feat(v4.0.0): the nucleus is a capsule, sent to a node born empty

MESH.md step 2.  A capsule of F18 code is the words a neighbour writes to a
node's port: for each stretch of memory, "@p a! @p push", the address and
count, "@p !+ unext" and the words; then a jump to the start.  A node born
empty executes that from its port, so it needs nothing in it beforehand.

- capsule.h/.c: v4_capsule_write, any node's memory as such a capsule
- mkimage writes the nucleus so, to capsules/v4/nucleus-64.f18, and the
  addresses a host needs as a C file; the memory image is no longer linked
  into either product
- mkcapsule is unchanged: the nucleus capsule is a built file kept under
  capsules/, as BLOCK_MAP.md is, and is baked, hashed and signed with the
  rest
- boot: the node is born empty (v4_image_born); the nucleus capsule is
  found, its hash and signature checked, and given to the node a word at a
  time as it reads its port; PARITY:V4_NUCLEUS carries its name and hash

Verified: test_fabric.c (59 checks, both widths, and under ASan and UBSan):
a memory with a programme and scattered words arrives word for word in an
empty node and runs.  The nucleus capsule rebuilds byte for byte.
hosted-check passes on three ISAs; clean qemu with STARFORTH_V4=1 on amd64,
aarch64 and riscv64 takes the nucleus in, passes POST (550 of 550) and
answers lines typed at each prompt (logs/20261006-102421, -102706,
-103048).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rajames
2026-10-06 10:33:15 -04:00
co-authored by Claude Opus 5.5
parent 9af442f793
commit 42610e844f
17 changed files with 718 additions and 88 deletions
+11 -4
View File
@@ -60,8 +60,16 @@ capsule_dir := -DV4_CAPSULE_DIR='"$(HERE)/capsule"'
# capsule/*.v4 -- and writes it as a C file, $(BINDIR)/v4_image_<width>.c.
# The hosted system below and the bare-metal kernel (kernel/Makefile,
# STARFORTH_V4=1) link the 64-bit one. docs/v4.0.0/NUCLEUS.md.
# The nucleus as a capsule of F18 code (include/v4/capsule.h). The 64-bit one
# is a product's: it goes into the capsule directory, ../capsules/v4, where
# the repository's mkcapsule finds it, hashes it and signs it with every
# other capsule. It is a built file kept in the tree, as
# ../capsules/BLOCK_MAP.md is, and is to be committed when it changes.
ROOT := $(abspath $(HERE)/..)
NUCLEUS_64 := $(ROOT)/capsules/v4/nucleus-64.f18
NUCLEUS_32 := $(BINDIR)/nucleus-32.f18
HOST_DEFS := -DV4_NODE_WORDS=$(HOST_WORDS) -DV4_DATA_RING=$(HOST_DATA_RING) -DV4_RET_RING=$(HOST_RET_RING)
ENGINE_SRCS := $(addprefix $(HERE)/src/,node.c exec.c stack.c iword.c heat.c guard.c image.c fabric.c)
ENGINE_SRCS := $(addprefix $(HERE)/src/,node.c exec.c stack.c iword.c heat.c guard.c image.c fabric.c capsule.c)
define IMAGE_RULE
$(BINDIR)/mkimage-$(1): $(HERE)/tools/mkimage.c $$(SRCS) $$(wildcard $(HERE)/include/v4/*.h) $(HERE)/tests/host_map.h $(HERE)/Makefile
@@ -69,7 +77,7 @@ $(BINDIR)/mkimage-$(1): $(HERE)/tools/mkimage.c $$(SRCS) $$(wildcard $(HERE)/inc
$$(CC) $$(CFLAGS) -I$(HERE)/include -DV4_CELL_BITS=$(1) $(HOST_DEFS) $(capsule_dir) $(HERE)/tools/mkimage.c $$(SRCS) -o $$@
$(BINDIR)/v4_image_$(1).c: $(BINDIR)/mkimage-$(1) $$(CAPSULES)
$(BINDIR)/mkimage-$(1) $$@
$(BINDIR)/mkimage-$(1) $$@ $$(NUCLEUS_$(1))
endef
$(foreach w,$(WIDTHS),$(eval $(call IMAGE_RULE,$(w))))
@@ -85,7 +93,6 @@ image: $(foreach w,$(WIDTHS),$(BINDIR)/v4_image_$(w).c)
# SIGN_KEY), and the code that reads it is the kernel's, compiled here as it
# is there. The binaries are static, so the two foreign ones run under
# user-mode QEMU with nothing else installed.
ROOT := $(abspath $(HERE)/..)
HOSTED_ISAS := amd64 aarch64 riscv64
CC_amd64 ?= cc
CC_aarch64 ?= aarch64-linux-gnu-gcc
@@ -114,7 +121,7 @@ $(BINDIR)/mkcapsule: $(MKCAPSULE_SRCS)
@mkdir -p $(BINDIR)
cc -std=c99 -Wall -Wextra -O2 -I$(ROOT)/v3/include -I$(ROOT)/kernel/include -I$(ROOT)/tools -o $@ $(MKCAPSULE_SRCS)
$(CAPSULE_DIR_C): $(BINDIR)/mkcapsule $(CAPSULE_FILES)
$(CAPSULE_DIR_C): $(BINDIR)/mkcapsule $(CAPSULE_FILES) $(BINDIR)/v4_image_64.c
$(BINDIR)/mkcapsule $(SIGN_KEY_ARGS) $(ROOT)/capsules $@
define HOSTED_RULE