Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
0d3d45c
test(https_e2e): add P-384 cert profile to test listener (Phase 4c)
JC-000 May 15, 2026
98b328f
chore(submodules): bump libs/nistcurves to 90830c9 (post-PR #23 + #24)
JC-000 May 15, 2026
9a2765a
build(p384-overlay): wire SHA-384 + ecdsa_verify_with_message_384 wra…
JC-000 May 15, 2026
45a2013
build(p384-overlay): split overlay into sha384 + curve halves to fit …
JC-000 May 16, 2026
338bf02
feat(tls): negotiate ecdsa_secp384r1_sha384 (0x0503) in addition to P…
JC-000 May 16, 2026
ed6f239
feat(crypto): activate dual-overlay swap dispatcher (P-384 SHA + curv…
JC-000 May 16, 2026
dc9a09c
feat(crypto): TLS-side P-384 verify dispatcher (dual-overlay swap + s…
JC-000 May 16, 2026
b82f5ce
test(p384): KAT smoke test for ecdsa_verify_384 dual-overlay flow
JC-000 May 16, 2026
bf1f27c
fix(p384): shrink CertificateVerify signed blob 146 -> 130 B (Phase 5…
JC-000 May 16, 2026
5ae5703
fix(p384): separate 48 B P-384 pubkey BSS slots (Phase 5 Fix B)
JC-000 May 16, 2026
76ba6eb
build(p384): generate overlay-resident equates from labels at build t…
JC-000 May 16, 2026
2f5face
build(p384): order-only labels.txt dep on overlay-bin + script harden…
JC-000 May 16, 2026
7b589b5
test(p384): tools/uci/test_https_local_p384.py + CLAUDE.md update (Ph…
JC-000 May 16, 2026
c895dcc
fix(uci): bounded uci_wait_not_busy (TOD-budgeted, mirrors uci_wait_i…
JC-000 May 16, 2026
5d6c4bb
refactor(tools/uci): factor P-384 arbiter monkey-patch into shared he…
JC-000 May 16, 2026
29c7038
test(uci): adopt new c64-test-harness lock/health pattern in test_htt…
JC-000 May 16, 2026
dbd2ae2
test(uci): bump SENTINEL_POLL_TIMEOUT to 5400s for P-384 e2e
JC-000 May 16, 2026
4f4d654
fix(uci): bound uci_drain_resp + uci_drain_status (TOD, mirrors uci_w…
JC-000 May 16, 2026
865c5e9
build(make): emit cc65 debug info (-g + --dbgfile) for PRG + overlays
JC-000 May 16, 2026
3cf6b92
docs(CLAUDE.md): note cc65 .dbg sidecars in Build section
JC-000 May 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,7 +6,8 @@ ip65-build/*.bin
ip65-build/*.map
.claude/*
!.claude/settings.json
tools/https_e2e/certs/
tools/https_e2e/certs/*
!tools/https_e2e/certs/README
tools/diag_4de0_*.py
tools/diag_read_live.py
.serena/
118 changes: 103 additions & 15 deletions CLAUDE.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,7 +20,7 @@ Targets:
`build/labels.txt` (VICE label format), and
`build/c64-https.dbg` (cc65 debug info,
consumable by VICE's monitor + diagnostic
agents; P-384 overlay gets a `.dbg` sidecar too)
agents; P-384 overlays get `.dbg` sidecars too)
- `make clean` — remove build artifacts
- `make run` — autostart the PRG in VICE
- `make ip65-libs` — rebuild ip65 object libraries from the submodule
Expand DownExpand Up@@ -146,18 +146,32 @@ is **$C9**. See `src/net/uci/uci_regs.inc` for the full equate list
### UCI command primitives

`src/net/uci/uci_cmd.s` provides shared subroutines used by `net.s`:
`uci_wait_idle`, `uci_begin_cmd`, `uci_push_wait`, `uci_end_cmd`,
`uci_read_data`, etc. No zero-page usage — all absolute addressing
and self-modifying code.

`uci_wait_idle` is wall-clock-bounded (5 s budget via CIA1 TOD) per
the design note below. On timeout it returns C=1 with `net_last_error
= UCI_ERR_WAIT_TIMEOUT`. The four callers (`net_dhcp_acquire`,
`net_tcp_connect`, `net_tcp_send`, `net_tcp_close`) all `bcs` out to
surface the failure rather than letting the C64 hang indefinitely on
a wedged FPGA. `uci_push_wait` and `uci_end_cmd` are still unbounded
and should be converted to the same TOD pattern if a wedge there is
ever observed.
`uci_wait_idle`, `uci_wait_not_busy`, `uci_begin_cmd`, `uci_push_wait`,
`uci_read_resp_bytes`, etc. No zero-page usage — all absolute
addressing and self-modifying code.

`uci_wait_idle`, `uci_wait_not_busy`, `uci_drain_resp`, and
`uci_drain_status` are all wall-clock-bounded (5 s budget via CIA1
TOD) per the design note below. On timeout they return C=1 with
`net_last_error = UCI_ERR_WAIT_TIMEOUT`. All `uci_wait_idle` callers
(`net_dhcp_acquire`, `net_tcp_connect`, `net_tcp_send`,
`net_tcp_close`) and all `uci_wait_not_busy` / `uci_push_wait`
callers (`net_poll`, `net_dhcp_acquire`, `net_tcp_connect`,
`net_tcp_send`, `net_tcp_close`) `bcs` out to surface the failure
rather than letting the C64 hang indefinitely on a wedged FPGA. All
13 `uci_drain_resp` / `uci_drain_status` call sites in `net.s` also
`bcs` out — on timeout the routine skips its companion drain + ack,
forces the appropriate `net_tcp_state` (ERROR for poll paths,
CONNECT_FAIL for connect, CLOSED for close, untouched for DHCP/send
which use C=1 as their fail sentinel), and returns. `uci_push_wait`
inherits the bound via its tail-call to `uci_wait_not_busy`. The
`uci_wait_not_busy` conversion was driven by a Phase 5 wedge observed
in CertVerify recv on real U64E hardware that converted a wedge into
a 1843 s test sentinel timeout; the drain conversion (Phase 5j)
closed the secondary risk that `net_tcp_send` / `net_poll` /
`net_tcp_close` could still wedge in `uci_drain_resp` /
`uci_drain_status` post-SOCKET_WRITE if firmware ever left DATA_AV /
STAT_AV asserted.

### UCI error codes

Expand DownExpand Up@@ -275,6 +289,28 @@ backends:
- `http_status = 200`, `http_resp_buf = "HELLO FROM TLS SERVER"`,
`http_resp_len = 21`

**ECDSA P-384 also wired end-to-end (Phase 5).** The TLS dispatcher
now negotiates `ecdsa_secp384r1_sha384` (0x0503) alongside the existing
P-256/SHA-256 path; on a 0x0503 CertificateVerify it routes through
`src/crypto/ecdsa_verify_384.s`, which composes the dual-overlay swap
(SHA-384 overlay → ECDSA-P384 curve overlay) plus the sibling's
`ecdsa_verify_384` to verify the server's signature. The
`tls_handle_certificate` cert handler dispatches on `ecdsa_curve_id`
and writes the 48 B P-384 pubkey into the dedicated
`ecdsa_pubkey_x_384` / `_y_384` slots in CRYPTO_BSS (Phase 5 Fix B).
The CertificateVerify signed-content blob is 130 B (RFC 8446 §4.4.3:
64-space pad + 33 B context + 1 B sep + 32 B SHA-256 transcript;
the transcript-hash function stays SHA-256 because c64-https
negotiates only TLS_AES_128_GCM_SHA256 — Phase 5 Fix A). The
end-to-end test is `tools/uci/test_https_local_p384.py` (mirrors
`test_https_local.py` with P-384 cert profile via swapping CERT_PATH
/ KEY_PATH to `tools/https_e2e/certs/server-p384.{pem,key}`); see the
"ECDSA P-384 verify wall-clock" subsection for the wall-clock
expectation. Negotiation plumbing test
`tools/test_tls_p384_negotiation.py` confirms ClientHello advertises
both 0x0403 + 0x0503 and the dispatcher reaches the P-384 path on
0x0503 CertificateVerify (2/2 PASS as of Phase 5).

### Summary of recent fixes (post-PR23 branch)

Five latent bugs and three new ones were cleared to get here:
Expand DownExpand Up@@ -434,10 +470,42 @@ budget, ample headroom). Further speedups live in the sibling
here as a submodule bump without
touching TLS call sites.

### ECDSA P-384 verify wall-clock

Not yet measured end-to-end. The U64E test host was unreachable from
the dev machine when Phase 5's e2e wiring landed (DeviceLock
unavailable; ping/TCP both unreachable to the default
192.168.1.81). Run `tools/uci/test_https_local_p384.py` from a host
with U64E LAN access to capture the number; the script defaults to a
30 minute wall-clock budget (`SENTINEL_POLL_TIMEOUT=1800` /
`ACCEPT_TIMEOUT=1800`) — expect 4-7 minutes per handshake at 48 MHz
turbo, dominated by:

- one ECDSA-P384 verify (sibling `libs/nistcurves`
`ecdsa_verify_384`); P-256 measures 81.9 s, the P-384 cost is
~5x because the field is 1.5x wider and the scalar mul does
proportionally more `fp_mul` / `fp_sqr` calls — extrapolate
~400 s = ~7 min ceiling
- one SHA-384 hash over the 130 B signed-content blob (negligible
vs the verify)
- the dual-overlay swap dance (sha384 overlay swap-in →
sha384_init/update/final → curve overlay swap-in → verify); each
swap is 2 REU DMAs at ~16 ms wallclock — also negligible
- X25519 + Finished HMACs + state-machine overhead (~6-7 s
across the rest of the handshake, per the P-256 baseline)

Once measured, drop the wall-clock here. Phase 4 cert-profile flag
in the local listener (`HTTPS_LISTENER_CERT_PROFILE=p384` or the
`cert_profile="p384"` kwarg to `start_https_listener`) is the
upstream selector; `tools/uci/test_https_local_p384.py` inlines its
own listener (matching `test_https_local.py`'s pattern) and points it
at `tools/https_e2e/certs/server-p384.{pem,key}`.

### Design note — bounded timeouts must use wall-clock time

Robustness work on the UCI adapter's spin-wait helpers (`uci_wait_idle`,
`uci_push_wait`, etc.) MUST use a wall-clock time source — CIA timer
`uci_wait_not_busy`, `uci_drain_resp`, `uci_drain_status`, etc.) MUST
use a wall-clock time source — CIA timer
on stock C64, TOD clock on U64E — rather than a cycle-counted iteration
budget. The fences around every UCI register access make per-iteration
cost scale with CPU speed: a budget that is ample at 1 MHz collapses
Expand All@@ -447,14 +515,34 @@ FPGA's wire-level operation durations. A prior attempt on branch
budgets and broke DHCP at turbo for exactly this reason; the branch
was abandoned.

`uci_wait_idle` is the first helper to follow this pattern (issue #37).
`uci_wait_idle` was the first helper to follow this pattern (issue #37).
At entry it samples CIA1 TOD ($DC08-$DC0B) — read order is HOUR
(latch) → MIN → SEC → TENTHS (unlatch) — and on each spin pass re-reads
TENTHS, bailing with C=1 + `net_last_error = UCI_ERR_WAIT_TIMEOUT`
after 50 transitions (~5 s wall-clock, independent of CPU turbo). State
lives in two SMC bytes inside the routine to match the file's no-ZP
convention. Use this as the template for any future bounded helper.

`uci_wait_not_busy` was converted to the same pattern after a Phase 5
wedge in CertVerify recv on real U64E hardware — the unbounded spin
turned an FPGA wedge into a 1843 s test sentinel timeout. Same 5 s
budget, same error code, same SMC-byte state convention. All six
caller sites (`net_poll`, `net_dhcp_acquire`, `net_tcp_connect`,
`net_tcp_send`, `net_tcp_close` direct + via `uci_push_wait`) `bcs`
out on C=1 to surface the timeout. `uci_push_wait` inherits the bound
via its tail-`jmp` into `uci_wait_not_busy` and needs no separate
conversion.

`uci_drain_resp` and `uci_drain_status` followed in Phase 5j to close
the symmetric risk on the response-drain side: `net_tcp_send` /
`net_poll` / `net_tcp_close` all call drains after their respective
SOCKET_WRITE / POLL_DATA / SOCKET_CLOSE responses, and if firmware
ever leaves DATA_AV / STAT_AV asserted post-response the old
unbounded `jmp <self>` loops would wedge the C64 with no wall-clock
escape. Same 5 s budget, same error code, same SMC-byte state
convention. All 13 call sites in `net.s` `bcs` out on C=1 to skip
the companion drain + ack and force the appropriate exit state.

## Memory layout

Defined in `cfg/c64-https-ip65.cfg`. Physically contiguous file-backed
Expand Down
120 changes: 106 additions & 14 deletions Makefile
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,7 +34,7 @@ IP65_DIR := ip65
IP65_BUILD := ip65-build
IP65_BIN := $(IP65_BUILD)/ip65-c64.bin

CA65FLAGS := -I src -I src/inc -I src/crypto/shared -I src/net/$(BACKEND) --debug-info
CA65FLAGS := -I src -I src/inc -I src/crypto/shared -I src/net/$(BACKEND) -I build --debug-info
LD65FLAGS := -C $(CFG) -Ln build/labels.txt -m build/c64-https.map --dbgfile build/c64-https.dbg

# Source inventory.
Expand DownExpand Up@@ -90,6 +90,22 @@ CRYPTO_SRCS := $(CRYPTO_SRCS_EFFECTIVE)
else ifeq ($(BACKEND),uci)
NET_SRCS := $(UCI_SRCS)
CRYPTO_SRCS := $(CRYPTO_SRCS_EFFECTIVE)
# Phase 3: embed the two P-384 split overlay blobs in the PRG so boot
# can populate REU banks 6/7 at startup. Gated to UCI (ip65 has no
# room for the SHA blob in main RAM) and to !USE_X25519_SIBLING (the
# sibling rodata occupies CRYPTO_OVERLAY at PRG load time, displacing
# the SHA blob). Adds a build-order dep on the .bin files; a missing
# .bin causes the .incbin to fail, so we extend PRG_DEPS below.
ifneq ($(USE_X25519_SIBLING),1)
# Phase 5 Fix D: respect a command-line USE_OVERLAY_P384_EMBED=0 so the
# bootstrap rule below can do a no-overlay-embed prelim link to break
# the overlay-bin <-> labels.txt cycle on a clean tree. Default is
# still 1 unless the operator explicitly disables it.
USE_OVERLAY_P384_EMBED ?= 1
ifeq ($(USE_OVERLAY_P384_EMBED),1)
CA65FLAGS += -D USE_OVERLAY_P384_EMBED=1
endif
endif
# Phase C.3: add c64-nist-curves P-384 primitives as a REU overlay.
# Variable-base P-384 point ops (double/add/jacobian-to-affine) only —
# see tools/integration/build_nistcurves_p384.sh for the scope rationale.
Expand All@@ -107,7 +123,12 @@ CRYPTO_SRCS := $(CRYPTO_SRCS_EFFECTIVE)
# integration can be re-enabled by uncommenting the two lines below once
# the cfg is extended.
#CA65FLAGS += -D USE_NISTCURVES_P384=1
#SIBLING_LIB_ARCHIVES += build/lib/nistcurves-p384.a
# Phase 1.5 split the monolithic nistcurves-p384.a into two halves
# (nistcurves-p384-sha384.a + nistcurves-p384-curve.a) since the
# combined image overflowed the live 7.5 KB CRYPTO_OVERLAY slot.
# Either-of approach for the production wire-up will be Phase 4a.
#SIBLING_LIB_ARCHIVES += build/lib/nistcurves-p384-sha384.a
#SIBLING_LIB_ARCHIVES += build/lib/nistcurves-p384-curve.a
else
$(error Unknown BACKEND=$(BACKEND); expected ip65 or uci)
endif
Expand All@@ -134,24 +155,51 @@ else
PRG_DEPS := $(ALL_OBJS)
endif

# Phase 3: when USE_OVERLAY_P384_EMBED is on, add the two .bin files
# to PRG_DEPS so make builds them before the .incbin in
# src/crypto/shared/p384_overlay_blobs.s tries to read them.
ifeq ($(USE_OVERLAY_P384_EMBED),1)
PRG_DEPS += build/lib/overlay-p384-sha384.bin build/lib/overlay-p384-curve.bin
PRG_DEPS += build/p384_overlay_equates.inc
build/crypto/shared/p384_overlay_blobs.o: build/lib/overlay-p384-sha384.bin build/lib/overlay-p384-curve.bin
endif

$(PRG): $(PRG_DEPS)
@mkdir -p build
$(LD65) $(LD65FLAGS) -o $@ $(ALL_OBJS) $(SIBLING_LIB_ARCHIVES)
# Rewrite ca65 label format `al XXXXXX .name` -> VICE format `al C:XXXX .name`
# so the c64-test-harness Labels.from_file() reader can parse it.
sed -i '' 's/^al 00\([0-9a-fA-F]\{4\}\) /al C:\1 /' $(LABELS)

# Phase 5 Fix D: $(LABELS) is normally a side-effect of the $(PRG)
# link recipe; we don't add an explicit rule. The overlay-bin rule
# below has an order-only dep on $(LABELS) so its lookup_label()
# resolves the main PRG's runtime mul_dma_lo / mul_dma_hi /
# mul_cached_a / reu_fetch_mul_row to real addresses (was: silent
# $0000 fallback that produced a curve overlay whose fp_mul_384
# read/wrote $0000 and silently corrupted downstream state).
#
# Bootstrap workflow (clean tree under USE_OVERLAY_P384_EMBED=1):
# make BACKEND=uci USE_OVERLAY_P384_EMBED=0 # produce labels.txt
# make BACKEND=uci # real link with overlays
# After this two-step bootstrap, plain `make BACKEND=uci` rebuilds
# incrementally without intervention. The script
# tools/integration/build_nistcurves_p384_bin.sh prints a clear error
# pointing at this two-step procedure if it runs without labels.txt
# (vs the old silent $0000 stub fallback).


link: $(PRG)

build/%.o: src/%.s
@mkdir -p $(dir $@)
$(CA65) $(CA65FLAGS) -o $@ $<

# Phase C.3: c64-nist-curves sibling archive (libs/nistcurves/ submodule).
# Same gating as x25519: only linked under BACKEND=uci; ip65 continues
# without P-384 entirely. Exports only the variable-base primitives
# (see the build script for the excluded symbols and why).
build/lib/nistcurves-p384.a:
# Phase 1.5 split: produces TWO archives, one per overlay half. The
# script writes both with a single invocation; the second target is a
# pseudo-rule that piggybacks on the first.
build/lib/nistcurves-p384-sha384.a build/lib/nistcurves-p384-curve.a:
@mkdir -p build/lib
bash tools/integration/build_nistcurves_p384.sh

Expand All@@ -176,18 +224,62 @@ build/lib/x25519.a:
@mkdir -p build/lib
bash tools/integration/build_x25519.sh

# Phase C.3b: P-384 overlay IMAGE + labels for harness-time use only.
# The production PRG does NOT link nistcurves-p384.a — this is smoke-test
# infrastructure. tools/test_p384_symbols.py loads overlay-p384.bin into
# REU at test time via a trampoline, then calls crypto_swap_to_p384 to
# page it into the live slot. Keeps the main PRG size unchanged.
# Phase C.3b / Phase 1.5 split: P-384 overlay IMAGES + labels for
# harness-time use only. The production PRG does NOT link
# nistcurves-p384-{sha384,curve}.a — these are smoke-test infrastructure.
# A future Phase 3 / Phase 4a harness will load both .bins into REU at
# test time, then DMA them into the live slot via two new swap entry
# points (crypto_swap_to_p384_sha384 / crypto_swap_to_p384_curve);
# the existing crypto_swap_to_p384 entry point is now stale -- see the
# comment block at the top of src/crypto/shared/crypto_swap.s.
#
# All four outputs (two .bins + two labels files) are produced by a
# single script invocation; the rule lists all four targets so make
# only runs the script once even when several are stale.
#
# Both outputs live below build/; depend on the archive being built first.
build/lib/overlay-p384.bin build/labels-p384.txt: build/lib/nistcurves-p384.a cfg/p384-overlay.cfg tools/integration/build_nistcurves_p384_bin.sh
# Phase 5 Fix D: build/labels.txt is an ORDER-ONLY dependency. The
# overlay-bin script's lookup_label() reads build/labels.txt to resolve
# mul_dma_lo / mul_dma_hi / mul_cached_a / reu_fetch_mul_row to the
# main PRG's runtime addresses (so the curve overlay's fp_mul_384
# reads/writes the right $BA00 / $BB00 / etc. cells). On a clean
# build, build/labels.txt doesn't exist yet when this rule runs and the
# script falls back to $0000 stubs - silently producing an overlay
# image whose fp_mul_384 reads from $0000. Order-only ('|') ensures
# labels.txt exists before the script runs but doesn't trigger an
# overlay rebuild on every main-PRG link.
build/lib/overlay-p384-sha384.bin build/lib/overlay-p384-curve.bin build/labels-p384-sha384.txt build/labels-p384-curve.txt: \
build/lib/nistcurves-p384-sha384.a build/lib/nistcurves-p384-curve.a \
cfg/p384-overlay-sha384.cfg cfg/p384-overlay-curve.cfg \
tools/integration/build_nistcurves_p384_bin.sh \
| build/labels.txt
bash tools/integration/build_nistcurves_p384_bin.sh

.PHONY: p384-overlay
p384-overlay: build/lib/overlay-p384.bin build/labels-p384.txt
p384-overlay: build/lib/overlay-p384-sha384.bin build/lib/overlay-p384-curve.bin \
build/labels-p384-sha384.txt build/labels-p384-curve.txt

# Phase 5 Fix C: regenerate the P-384 overlay-resident symbol equates
# (build/p384_overlay_equates.inc) from the overlay labels files so the
# TLS-side dispatcher (src/crypto/ecdsa_verify_384.s) picks up address
# changes via .include, with .assert pins catching drift. Whenever
# either labels file is rebuilt, the .inc regenerates and the
# dispatcher .o is forced to rebuild.
build/p384_overlay_equates.inc: build/labels-p384-sha384.txt build/labels-p384-curve.txt \
tools/integration/gen_p384_overlay_equates.sh
bash tools/integration/gen_p384_overlay_equates.sh \
build/labels-p384-sha384.txt build/labels-p384-curve.txt $@

# The dispatcher .o now depends on the generated equates file (via
# .include) AND on the overlay .bin files (PRG_DEPS already lists those
# under USE_OVERLAY_P384_EMBED). Phase 5 Fix D: gate the .inc dep on
# USE_OVERLAY_P384_EMBED so the bootstrap rule for $(LABELS) (which
# sub-makes with USE_OVERLAY_P384_EMBED=0) can skip rebuilding the .inc
# from labels-p384-* (those depend on overlay-bins which depend on
# $(LABELS) -- cycle). The bootstrap pre-creates a placeholder .inc
# before sub-making.
ifeq ($(USE_OVERLAY_P384_EMBED),1)
build/crypto/ecdsa_verify_384.o: build/p384_overlay_equates.inc
endif

# Build ip65 object libraries from the submodule. Only needed if the ip65
# submodule changes; the prebuilt blob is committed to ip65-build/.
Expand Down
22 changes: 20 additions & 2 deletions cfg/c64-https-ip65.cfg
Original file line numberDiff line numberDiff line change
Expand Up@@ -44,10 +44,19 @@ MEMORY {

# CRYPTO_OVERLAY is not used under ip65 (no REU-overlay swapping).
# A zero-size rw alias is declared here only to satisfy
# `crypto_swap.s`'s `.import __CRYPTO_OVERLAY_START__` ip65 never
# actually issues the DMA, so the address value is unused.
# `crypto_swap.s`'s `.import __CRYPTO_OVERLAY_START__` -- ip65
# never actually issues the DMA, so the address value is unused.
CRYPTO_OVERLAY: start = $6000, size = $0000, type = rw, define = yes;

# Phase 3: ip65 backend does NOT embed the P-384 split overlay
# blobs (no room in main RAM after the existing layout, and ip65
# is the production X25519-only path that never calls into P-384).
# The OVERLAY_BLOB_SHA384 / OVERLAY_BLOB_CURVE segments below are
# `optional = yes` and stay empty under ip65; their MEMORY anchors
# are zero-size aliases just to give ld65 valid load addresses
# for the segment names referenced from src/crypto/shared/.
OVERLAY_BLOB_CURVE_RAM: start = $E000, size = $0000, type = rw, define = yes;

TCP_BUF: start = $C000, size = $1000, type = rw, define = yes;
}

Expand DownExpand Up@@ -115,5 +124,14 @@ SEGMENTS {
CRYPTO_BSS: load = CRYPTO_RESIDENT, type = bss;
TABLES_BSS: load = CRYPTO_RESIDENT, type = bss, align = $100;

# Phase 3: ip65 backend stays at the historical 47 KB PRG size --
# USE_OVERLAY_P384_EMBED is gated off in the Makefile under ip65,
# so src/crypto/shared/p384_overlay_blobs.s emits no bytes and
# both segments below stay empty. The segment declarations are
# kept (`optional = yes`) so the cfg parses identically across
# backends and the ip65/UCI link line stays uniform.
OVERLAY_BLOB_SHA384: load = CRYPTO_OVERLAY, type = ro, optional = yes;
OVERLAY_BLOB_CURVE: load = OVERLAY_BLOB_CURVE_RAM, type = ro, optional = yes;

TCP_RECV_BUF: load = TCP_BUF, type = bss, optional = yes;
}
Loading