diff --git a/capsules/BLOCK_MAP.md b/capsules/BLOCK_MAP.md index 4fe58223..a141bddb 100644 --- a/capsules/BLOCK_MAP.md +++ b/capsules/BLOCK_MAP.md @@ -1,5 +1,5 @@ # Capsule Block Manifest — Auto-generated - + diff --git a/capsules/v4/nucleus-64.f18 b/capsules/v4/nucleus-64.f18 index 44bc82e5..72026e29 100644 Binary files a/capsules/v4/nucleus-64.f18 and b/capsules/v4/nucleus-64.f18 differ diff --git a/docs/v4.0.0/MESH.md b/docs/v4.0.0/MESH.md index b6bc6fec..5cc75c07 100644 --- a/docs/v4.0.0/MESH.md +++ b/docs/v4.0.0/MESH.md @@ -287,6 +287,29 @@ Each is tested, committed and pushed before the next. 6). 3. **Messages (section 6):** a StarForth node that reads messages when idle; the console as a device; a line typed is a message. + **Done 2026-10-06, but for the keyboard.** A node with nothing to do is + blocked reading "any port" (`(IDLE)`, `v4/capsule/quit.v4`). What + arrives is a message; text for this node is interpreted; what it prints + is kept and sent back as messages to the sender, on the port the + message came on, and then a message saying how the text ended (`EMIT`, + `(FLUSH-OUT)`, `(HDR)` in `core.v4`; `(FINISH)` in `quit.v4`). + `v4/src/message.c` is the same format for whatever is on the other end + of a port and is not a node. The boot is that, on the node's port 1, as + the console (`v4_boot_line`); the prompt tests are too. Handing a node a + line by writing its input buffer and setting its `P` is gone + (`v4_line_begin` and the rest). Nothing reads the `CONSOLE-TX` register + any more. + `EMIT` still needs one free cell of the data stack and no more, as + before; it keeps its working values on the return stack. The full-stack + tests hold at the same figures as before. + All v4 tests pass at both widths and under ASan and UBSan; + `hosted-check` on three ISAs; bare metal `logs/20261006-110551` (amd64), + `-111621` (aarch64), `-111341` (riscv64). `-110837` is an aarch64 run + that was ended by the test wrapper's limit while still in UEFI firmware, + before the kernel had started; it shows nothing about v4. + **Not done:** `KEY`, `EXPECT` and `QUERY` still read the console's two + input registers, not a message. A message not for this node, or not + text, is let go: passing it on is step 4. 4. **Finding the way (section 7).** 5. **Birth and Hera's requests (section 9); the unit of five.** 6. **Storage (section 8).** diff --git a/kernel/Makefile b/kernel/Makefile index 978ba762..7be5d48d 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -613,7 +613,7 @@ V4_DEFS := -DSTARFORTH_V4=1 -Iv4/include \ KERNEL_CFLAGS += $(V4_DEFS) LOADER_CFLAGS += $(V4_DEFS) -V4_ENGINE_SRCS := $(addprefix v4/src/,node.c exec.c stack.c iword.c heat.c guard.c image.c fabric.c capsule.c) +V4_ENGINE_SRCS := $(addprefix v4/src/,node.c exec.c stack.c iword.c heat.c guard.c image.c fabric.c capsule.c message.c) V4_IMAGE_C := $(BUILD_DIR)/v4_image_64.c LOADER_EXTRA_SRCS += $(KERNEL_SRC)/v4/sk_v4.c diff --git a/kernel/src/v4/sk_v4.c b/kernel/src/v4/sk_v4.c index 980e8e0a..0321a81e 100644 --- a/kernel/src/v4/sk_v4.c +++ b/kernel/src/v4/sk_v4.c @@ -100,8 +100,8 @@ void sk_v4_run(void) console_puts("ok> "); len = sk_v4_readline(); how = v4_boot_line(&boot, sk_v4_text, len); - if (how == V4_LINE_COMPLETED) console_puts(" ok\n"); - else if (how == V4_LINE_ERROR) console_puts(" ERROR\n"); + if (how == V4_TEXT_COMPLETED) console_puts(" ok\n"); + else if (how == V4_TEXT_ERROR) console_puts(" ERROR\n"); else if (how == V4_BOOT_LINE_STOPPED) { console_println("StarForth v4: the node stopped on a fault"); for (;;) { } diff --git a/logs/20261006-110551/amd64/qemu-amd64-20261006-110551.log b/logs/20261006-110551/amd64/qemu-amd64-20261006-110551.log new file mode 100644 index 00000000..c7b982a9 --- /dev/null +++ b/logs/20261006-110551/amd64/qemu-amd64-20261006-110551.log @@ -0,0 +1,130 @@ +[=3hBdsDxe: loading Boot0002 "UEFI QEMU DVD-ROM QM00005 " from PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x2,0xFFFF,0x0) +BdsDxe: starting Boot0002 "UEFI QEMU DVD-ROM QM00005 " from PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x2,0xFFFF,0x0) +[=3hStarKernel UEFI Loader +Loading kernel from ESP... +[CKPT 001] Entered efi_main - ConOut live +RAW SERIAL UP +[CKPT 002] Serial (COM1) initialized +Monolithic build - kernel linked directly +Collecting boot information... +CmdLine: parsed OK +[CKPT 004] Command line parsed +[CKPT 005] Kernel stack allocation decided +[CKPT 006] Boot info collected (ACPI table located) +GOP: linear framebuffer found +[CKPT 007] GOP: linear framebuffer found +[CKPT 008] About to enter ExitBootServices retry loop +EBS... +EBS OK +Calling kernel_main (monolithic)... + + + _____ _ _ __ _ + / ____| | | |/ / | | + | (___ | |_ __ _ _ __| ' / ___ _ __ _ __ ___| | + \___ \| __/ _` | '__| < / _ \ '__| '_ \ / _ \ | + ____) | || (_| | | | . \ __/ | | | | | __/ | + |_____/ \__\__,_|_| |_|\_\___|_| |_| |_|\___|_| + +LithosAnanke v2.1.0 +Architecture: amd64 +Build: Oct 6 2026 11:05:25 + +UEFI BootServices: EXITED + +=== StarKernel Boot Information === +Memory map entries: 131 +Total memory: 1023 MB +Usable memory: 968 MB +=================================== + +PMM initialized. +PMM statistics: + Total pages: 249252 + Free pages : 247729 + Used pages : 1523 + Total MB : 973 + Free MB : 967 + Used MB : 5 + +VMM initialized (mapped RAM, CR3 switched) +VMM initialized (mapped RAM, CR3 switched) +VMM self-test: mapped OK at 0xffff800000000000 +VMM self-test complete. + +IDT installed. + +APIC: init... +APIC: IA32_APIC_BASE MSR=0x00000000fee00900 +APIC: stale-ISR drain: 0 EOI(s) issued +APIC: initialized (xAPIC MMIO, TPR=0, SIVR=0x1FF, EOI-clear) +APIC: init done + +I/O APIC: init... +I/O APIC: base=0xfec00000, gsi_base=0, overrides=5 + override: source=00 gsi=2 flags=0x0000 + override: source=05 gsi=5 flags=0x000d + override: source=09 gsi=9 flags=0x000d + override: source=0a gsi=10 flags=0x000d + override: source=0b gsi=11 flags=0x000d +i8042: keyboard ACKed enable-scanning +i8042: IRQ1 enabled in controller config byte +I/O APIC: keyboard IRQ1 routed (masked) + +Timer: init... +Timer: init start +Timer: PM_TMR_BLK discovered from FADT at port 1544 +Timer: VM mode detected (hypervisor present). +Timer: HPET calibration disabled (VM-exit MMIO would poison timing). +Timer: WARNING: invariant TSC not present under hypervisor. +Timer: continuing in RELATIVE mode (no determinism guarantees). +Timer: RDTSCP not present; using RDTSC (less serialized). +Timer: CPUID frequency unavailable; trying PM Timer... +Timer: trust=1 (0=NONE,1=REL,2=ABS), TSC=2101540994 Hz +Timer: init done + +Kernel heap initialized. +Heap statistics: + Total bytes: 536870872 + Free bytes: 536870872 + Used bytes: 0 + Peak bytes: 0 + Heap base addr: 24641536 + Heap end addr: 561512448 + +Heartbeat: init... +APIC Timer: calibrating... +APIC Timer: apic_hz=1006649045, tick_hz=100, initial_count=10066490 +APIC Timer: configured (masked, ready to start) +Heartbeat: init done +Kernel initialization complete. +Boot successful! + +StarForth v4: one host node, the F18-derived engine +V4: capsule v4:nucleus-64.f18 signature: missing (unsigned) +PARITY:V4_NUCLEUS name=v4:nucleus-64.f18 capsule_id=0x97a655081b2af559 capsule_hash=0x97a655081b2af559 words=298 +V4: capsule v4:forth79.4th signature: missing (unsigned) +PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x594818fc69677603 +V4: capsule v4:post79.4th signature: missing (unsigned) +PARITY:V4_POST tests=550 pass=550 fail=0 +PARITY:V4_CAPSULE name=v4:post79.4th capsule_id=0xb987dbb4388990bd capsule_hash=0xb987dbb4388990bd dict_hash=0x8768fb163c8529f4 +PARITY:OK +POST: PASSED +ok> : SQ DUP * ; + ok +ok> 7 SQ . 3 4 U* . . +49 0 12 ok +ok> COLD +FORTH-79 Cold Start +System initialized. + ok +ok> 3 4 U* . . +0 12 ok +ok> FORGET U* +Protected word + ERROR +ok> 9 KERNEL-WORD ASK9 ASK9 +Argument out of range + ERROR +ok> BYE +BYE: cold restart diff --git a/logs/20261006-110837/aarch64/qemu-aarch64-20261006-110837.log b/logs/20261006-110837/aarch64/qemu-aarch64-20261006-110837.log new file mode 100644 index 00000000..0623e00c --- /dev/null +++ b/logs/20261006-110837/aarch64/qemu-aarch64-20261006-110837.log @@ -0,0 +1,2 @@ +UEFI firmware (version 2025.11-3ubuntu7.3 built at 15:40:26 on Sep 23 2026) +[=3h \ No newline at end of file diff --git a/logs/20261006-111341/riscv64/qemu-riscv64-20261006-111341.log b/logs/20261006-111341/riscv64/qemu-riscv64-20261006-111341.log new file mode 100644 index 00000000..849ca7d4 --- /dev/null +++ b/logs/20261006-111341/riscv64/qemu-riscv64-20261006-111341.log @@ -0,0 +1,174 @@ + +OpenSBI v1.8 + ____ _____ ____ _____ + / __ \ / ____| _ \_ _| + | | | |_ __ ___ _ __ | (___ | |_) || | + | | | | '_ \ / _ \ '_ \ \___ \| _ < | | + | |__| | |_) | __/ | | |____) | |_) || |_ + \____/| .__/ \___|_| |_|_____/|____/_____| + | | + |_| + +Platform Name : riscv-virtio,qemu +Platform Features : medeleg +Platform HART Count : 1 +Platform HART Protection : pmp +Platform IPI Device : aclint-mswi +Platform Timer Device : aclint-mtimer @ 10000000Hz +Platform Console Device : uart8250 +Platform HSM Device : --- +Platform PMU Device : --- +Platform Reboot Device : syscon-reboot +Platform Shutdown Device : syscon-poweroff +Platform Suspend Device : --- +Platform CPPC Device : --- +Firmware Base : 0x80000000 +Firmware Size : 321 KB +Firmware RW Offset : 0x40000 +Firmware RW Size : 65 KB +Firmware Heap Offset : 0x47000 +Firmware Heap Size : 37 KB (total), 0 KB (reserved), 12 KB (used), 23 KB (free) +Firmware Scratch Size : 4096 B (total), 1464 B (used), 2632 B (free) +Runtime SBI Version : 3.0 +Standard SBI Extensions : ipi,pmu,srst,sse,hsm,rfnc,fwft,time,base,legacy,dbcn,dbtr +Experimental SBI Extensions : none + +Domain0 Name : root +Domain0 Boot HART : 0 +Domain0 HARTs : 0* +Domain0 Region00 : 0x0000000080040000-0x000000008005ffff M: (F,R,W) S/U: () +Domain0 Region01 : 0x0000000080000000-0x000000008003ffff M: (F,R,X) S/U: () +Domain0 Region02 : 0x0000000000100000-0x0000000000100fff M: (I,R,W) S/U: (R,W) +Domain0 Region03 : 0x0000000010000000-0x0000000010000fff M: (I,R,W) S/U: (R,W) +Domain0 Region04 : 0x0000000002000000-0x000000000200ffff M: (I,R,W) S/U: () +Domain0 Region05 : 0x000000000c400000-0x000000000c5fffff M: (I,R,W) S/U: (R,W) +Domain0 Region06 : 0x000000000c000000-0x000000000c3fffff M: (I,R,W) S/U: (R,W) +Domain0 Region07 : 0x0000000000000000-0xffffffffffffffff M: () S/U: (R,W,X) +Domain0 Next Address : 0x0000000020000000 +Domain0 Next Arg1 : 0x00000000bfe00000 +Domain0 Next Mode : S-mode +Domain0 SysReset : yes +Domain0 SysSuspend : yes + +Boot HART ID : 0 +Boot HART Domain : root +Boot HART Priv Version : v1.12 +Boot HART Base ISA : rv64imafdch +Boot HART ISA Extensions : sstc,zicntr,zihpm,zicboz,zicbom,sdtrig,svadu +Boot HART PMP Count : 16 +Boot HART PMP Granularity : 2 bits +Boot HART PMP Address Bits : 54 +Boot HART MHPM Info : 16 (0x0007fff8) +Boot HART Debug Triggers : 2 triggers +Boot HART MIDELEG : 0x0000000000001666 +Boot HART MEDELEG : 0x0000000000f4b509 +[=3hRISC-V EDK2 firmware version 2025.11-3ubuntu7.3 +Press ESCAPE within 5 seconds for boot options ERROR: C40000002:V03051002 I0 6D33944A-EC75-4855-A54D-809C75241F6C 83FFF850 +BdsDxe: failed to load Boot0001 "UEFI Misc Device" fr +om PciRoot(0x0)/Pci(0x1,0x0): Not Found +[=3hStarKernel UEFI Loader +Loading kernel from ESP... +[CKPT 001] Entered efi_main - ConOut live +Monolithic build - kernel linked directly +Collecting boot information... +CmdLine: parsed OK +[CKPT 004] Command line parsed +[CKPT 005] Kernel stack allocation decided +[CKPT 006] Boot info collected (ACPI table located) +GOP: linear framebuffer found +[CKPT 007] GOP: linear framebuffer found +[CKPT 008] About to enter ExitBootServices retry loop +Calling kernel_main (monolithic)... +riscv64 item 4.3.5a: satp state at kernel entry (before switch) + satp.MODE = 0x000000000000000a + satp.PPN = 0x00000000000bf868 + __kernel_start = 0x00000000bdea78f8 +riscv64: satp cleared -- Bare mode, explicit (item 4.3.5a) + + + _____ _ _ __ _ + / ____| | | |/ / | | + | (___ | |_ __ _ _ __| ' / ___ _ __ _ __ ___| | + \___ \| __/ _` | '__| < / _ \ '__| '_ \ / _ \ | + ____) | || (_| | | | . \ __/ | | | | | __/ | + |_____/ \__\__,_|_| |_|\_\___|_| |_| |_|\___|_| + +LithosAnanke v2.1.0 +Architecture: riscv64 +Build: Oct 6 2026 11:13:04 + +UEFI BootServices: EXITED + +=== StarKernel Boot Information === +Memory map entries: 100 +Total memory: 1020 MB +Usable memory: 977 MB +=================================== + +PMM initialized. +PMM statistics: + Total pages: 250782 + Free pages : 250130 + Used pages : 652 + Total MB : 979 + Free MB : 977 + Used MB : 2 + +VMM initialized (mapped RAM, CR3 switched) +VMM initialized (mapped RAM, CR3 switched) +VMM self-test: mapped OK at 0xffff800000000000 +VMM self-test complete. + +IDT installed. + +APIC: init... +PLIC: no DTB PLIC node -- using QEMU virt-machine default (base=0x0c000000) +PLIC: init (S-mode context 1, threshold=0) +APIC: init done + +Timer: init... +Timer: RISC-V time CSR @ 10000000 Hz (FALLBACK, no devicetree) +Timer: init done + +Kernel heap initialized. +Heap statistics: + Total bytes: 536870872 + Free bytes: 536870872 + Used bytes: 0 + Peak bytes: 0 + Heap base addr: 2214588416 + Heap end addr: 2751459328 + +Heartbeat: init... +Heartbeat: init done +Kernel initialization complete. +Boot successful! + +StarForth v4: one host node, the F18-derived engine +V4: capsule v4:nucleus-64.f18 signature: missing (unsigned) +PARITY:V4_NUCLEUS name=v4:nucleus-64.f18 capsule_id=0x97a655081b2af559 capsule_hash=0x97a655081b2af559 words=298 +V4: capsule v4:forth79.4th signature: missing (unsigned) +PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x594818fc69677603 +V4: capsule v4:post79.4th signature: missing (unsigned) +PARITY:V4_POST tests=550 pass=550 fail=0 +PARITY:V4_CAPSULE name=v4:post79.4th capsule_id=0xb987dbb4388990bd capsule_hash=0xb987dbb4388990bd dict_hash=0x8768fb163c8529f4 +PARITY:OK +POST: PASSED +ok> : SQ DUP * ; + ok +ok> 7 SQ . 3 4 U* . . +49 0 12 ok +ok> COLD +FORTH-79 Cold Start +System initialized. + ok +ok> 3 4 U* . . +0 12 ok +ok> FORGET U* +Protected word + ERROR +ok> 9 KERNEL-WORD ASK9 ASK9 +Argument out of range + ERROR +ok> BYE +BYE: cold restart diff --git a/logs/20261006-111621/aarch64/qemu-aarch64-20261006-111621.log b/logs/20261006-111621/aarch64/qemu-aarch64-20261006-111621.log new file mode 100644 index 00000000..2dc2b244 --- /dev/null +++ b/logs/20261006-111621/aarch64/qemu-aarch64-20261006-111621.log @@ -0,0 +1,104 @@ +UEFI firmware (version 2025.11-3ubuntu7.3 built at 15:40:26 on Sep 23 2026) +[=3hBdsDxe: failed to load Boot0002 "UEFI Misc Device" from PciRoot(0x0)/Pci(0x2,0x0): Not Found +BdsDxe: failed to load Boot0003 "UEFI QEMU QEMU USB HARDDRIVE 1-0000:00:04.0-1" from PciRoot(0x0)/Pci(0x4,0x0)/USB(0x0,0x0): Not Found +BdsDxe: loading Boot0004 "UEFI Misc Device 2" from PciRoot(0x0)/Pci(0x6,0x0) +BdsDxe: starting Boot0004 "UEFI Misc Device 2" from PciRoot(0x0)/Pci(0x6,0x0) +[=3hStarKernel UEFI Loader +Loading kernel from ESP... +[CKPT 001] Entered efi_main - ConOut live +Collecting boot information... +[CKPT 004] Command line parsed +[CKPT 005] Kernel stack allocation decided +[CKPT 006] Boot info collected (ACPI table located) +[CKPT 007] GOP: linear framebuffer found +[CKPT 008] About to enter ExitBootServices retry loop + + + _____ _ _ __ _ + / ____| | | |/ / | | + | (___ | |_ __ _ _ __| ' / ___ _ __ _ __ ___| | + \___ \| __/ _` | '__| < / _ \ '__| '_ \ / _ \ | + ____) | || (_| | | | . \ __/ | | | | | __/ | + |_____/ \__\__,_|_| |_|\_\___|_| |_| |_|\___|_| + +LithosAnanke v2.1.0 +Architecture: aarch64 +Build: Oct 6 2026 11:15:55 + +UEFI BootServices: EXITED + +=== StarKernel Boot Information === +Memory map entries: 108 +Total memory: 4093 MB +Usable memory: 4056 MB +=================================== + +PMM initialized. +PMM statistics: + Total pages: 1039866 + Free pages : 1038455 + Used pages : 1411 + Total MB : 4061 + Free MB : 4056 + Used MB : 5 + +VMM initialized (mapped RAM, CR3 switched) +VMM initialized (mapped RAM, CR3 switched) +VMM self-test: mapped OK at 0xffff800000000000 +VMM self-test complete. + +AArch64: running at EL1 +IDT installed. + +APIC: init... +PSCI: no DTB -- using HVC (QEMU virt-machine default) +GICv2: no DTB GIC node -- using QEMU virt-machine defaults +GICv2: distributor+CPU interface enabled, PPI 30 +APIC: init done + +Timer: init... +Timer: AArch64 generic timer initialised. +Timer: init done + +Kernel heap initialized. +Heap statistics: + Total bytes: 2147483608 + Free bytes: 2147483608 + Used bytes: 0 + Peak bytes: 0 + Heap base addr: 1207959552 + Heap end addr: 3355443200 + +Heartbeat: init... +Heartbeat: init done +Kernel initialization complete. +Boot successful! + +StarForth v4: one host node, the F18-derived engine +V4: capsule v4:nucleus-64.f18 signature: missing (unsigned) +PARITY:V4_NUCLEUS name=v4:nucleus-64.f18 capsule_id=0x97a655081b2af559 capsule_hash=0x97a655081b2af559 words=298 +V4: capsule v4:forth79.4th signature: missing (unsigned) +PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x594818fc69677603 +V4: capsule v4:post79.4th signature: missing (unsigned) +PARITY:V4_POST tests=550 pass=550 fail=0 +PARITY:V4_CAPSULE name=v4:post79.4th capsule_id=0xb987dbb4388990bd capsule_hash=0xb987dbb4388990bd dict_hash=0x8768fb163c8529f4 +PARITY:OK +POST: PASSED +ok> : SQ DUP * ; + ok +ok> 7 SQ . 3 4 U* . . +49 0 12 ok +ok> COLD +FORTH-79 Cold Start +System initialized. + ok +ok> 3 4 U* . . +0 12 ok +ok> FORGET U* +Protected word + ERROR +ok> 9 KERNEL-WORD ASK9 ASK9 +Argument out of range + ERROR +ok> BYE +BYE: cold restart diff --git a/v4/Makefile b/v4/Makefile index b8194cf6..fdcbb97b 100644 --- a/v4/Makefile +++ b/v4/Makefile @@ -69,7 +69,7 @@ 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 capsule.c) +ENGINE_SRCS := $(addprefix $(HERE)/src/,node.c exec.c stack.c iword.c heat.c guard.c image.c fabric.c capsule.c message.c) define IMAGE_RULE $(BINDIR)/mkimage-$(1): $(HERE)/tools/mkimage.c $$(SRCS) $$(wildcard $(HERE)/include/v4/*.h) $(HERE)/tests/host_map.h $(HERE)/Makefile diff --git a/v4/README.md b/v4/README.md index 5b905187..c0c7ecd7 100644 --- a/v4/README.md +++ b/v4/README.md @@ -59,7 +59,7 @@ State, 2026-10-05, after `ENGINE.md` step 1: all six builds start the nucleus, load `v4:forth79.4th`, pass POST and reach `ok>`, with the same lines: ``` -PARITY:V4_NUCLEUS name=v4:nucleus-64.f18 capsule_id=... capsule_hash=0xbcc90cc5a638a299 words=298 +PARITY:V4_NUCLEUS name=v4:nucleus-64.f18 capsule_id=... capsule_hash=0x97a655081b2af559 words=298 PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=... dict_hash=... PARITY:V4_POST tests=550 pass=550 fail=0 PARITY:V4_CAPSULE name=v4:post79.4th capsule_id=... dict_hash=... @@ -68,23 +68,23 @@ POST: PASSED ok> ``` -Bare-metal logs: `logs/20261006-102421/amd64/`, `logs/20261006-102706/aarch64/`, -`logs/20261006-103048/riscv64/`. On each, seven lines were then typed at the +Bare-metal logs: `logs/20261006-110551/amd64/`, `logs/20261006-111621/aarch64/`, +`logs/20261006-111341/riscv64/`. On each, seven lines were then typed at the prompt through the serial port — a definition, its use with the capsule's `U*`, `COLD`, the capsule word again, a `FORGET` of it (refused), a kernel word no one serves, and `BYE` — and each was answered as the hosted binary answers it. The capsules were unsigned (no signing key on this machine). -**A node is handed a line** (`docs/v4.0.0/ENGINE.md` 3.1). It does not read -its own command line and prints no prompt. Its host puts the text in the -node's input buffer and starts it at `(LINE)`; the node interprets the text -and stops at `(IDLE)`, leaving in `(LINE-STATUS)` how it ended. The host says -` ok` or ` ERROR` and prompts, as the kernel's REPL does for a v3 VM. A line -may be 1024 characters, a block. `v4_line_begin`, `v4_line_done` and -`v4_line_status` (`v4/include/v4/image.h`) are that interface; -`v4_boot_line` (`v4/system/boot.c`) is the one loop the hosted binary, the -kernel and the capsule loader all run it with. +**A node is sent text as a message** (`docs/v4.0.0/MESH.md` section 6). It +does not read its own command line, prints no prompt and has no console of +its own. With nothing to do it is blocked reading its ports. A neighbour +writes it a message; text for it is interpreted; what it prints goes back +as messages to the sender, and then a message saying how the text ended. +Its console says ` ok` or ` ERROR` and prompts, as the kernel's REPL does +for a v3 VM. A message carries 1024 characters, a block. `v4/src/message.c` +is the format for a host; `v4_boot_line` (`v4/system/boot.c`) is the +console both products and the capsule loader use. **A node asks its kernel by writing to its port** (`ENGINE.md` 3.3). The write blocks the node until it has been served. A kernel word is a diff --git a/v4/capsule/core.v4 b/v4/capsule/core.v4 index 79af2840..02c2907c 100644 --- a/v4/capsule/core.v4 +++ b/v4/capsule/core.v4 @@ -5,7 +5,8 @@ \ written here as text for the text assembler (v4/include/v4/text.h). \ \ Constants the loader supplies: N-1 (cell bits - 1), NODE-ERROR, CONSOLE-TX, -\ CONSOLE-RX, CONSOLE-STATUS, BASE, (EMIT-HOOK). +\ CONSOLE-RX, CONSOLE-STATUS, BASE, (EMIT-HOOK), (MSG), (REPLY), (ME), (OUT), +\ (OUT^). \ \ ERRORS (D-18). A word that finds an error takes its arguments off the stack \ and stores a code in NODE-ERROR. On a node with a prompt that store is a @@ -91,16 +92,63 @@ header CMOVE DONE: drop drop drop ; \ ---- section 5.10: the console ------------------------------------------- -\ EMIT sends the character to the console, unless (EMIT-HOOK) holds the xt -\ of a word: then that word is given it instead ( c -- ), and returns to -\ EMIT's caller. Everything the node prints goes through EMIT, so a hook -\ sees all of it. The prompt takes the hook off at the end of every line -\ (quit.v4), so that nothing can leave the console silent. POST uses it -\ to compare what a case prints (docs/v4.0.0/NUCLEUS.md 6.3). +\ ---- what a node prints (docs/v4.0.0/MESH.md section 6) ------------------------ +\ A node has no console of its own. It does what a message asks, and what +\ it prints while doing it goes back, as a message, to whoever sent that one, +\ on the port it came on. A message is seven words and then its text, four +\ characters to a word: +\ to, from, type, heat and TTL, ACL tag, sequence, length in characters +\ The types: 1 text to be interpreted 2 what a node printed 3 how the +\ text ended (one word of text: 0 QUIT, 1 completed, 2 an error). +\ The header of the message being served is in the seven cells (MSG); (REPLY) +\ is the address of the port it came on; (ME) is this node's number. +\ +\ Characters are kept in (OUT), 256 of them, a character to a cell, and sent +\ when it is full and when the text has been done with (quit.v4). (OUT^) +\ is where the next goes. +\ +\ THE STACK. What prints may be run with the data stack all but full: EMIT +\ has always needed one free cell and no more, and still does -- it keeps +\ the character and A on the return stack while it works. Sending needs +\ two. + +\ ( type -- ) the first six words of a message to the sender of the one +\ being served; its length, and its text, are the caller's to send. Each +\ write waits for the neighbour to take it. B is left at the port. +: (HDR) + (REPLY) a! @ b! + (MSG)+1 a! @ !b \ to + (ME) a! @ !b \ from + !b \ type + 0 !b 0 !b 0 !b ; \ heat and TTL, ACL tag, sequence: carried, not used yet + +\ ( -- ) send what has been printed: its length, then its characters, four +\ to a word, the first lowest +: (FLUSH-OUT) + (OUT^) a! @ (OUT) xor if NONE drop + 2 (HDR) + (OUT^) a! @ (OUT) - dup !b + 3 + 2/ 2/ -1 + (OUT) a! + FOR @+ @+ 8* + @+ 8* 8* + @+ 8* 8* 8* + !b NEXT + (OUT) (OUT^) a! ! ; + NONE: drop ; + +\ EMIT puts the character with what has been printed, unless (EMIT-HOOK) +\ holds the xt of a word: then that word is given it instead ( c -- ), and +\ returns to EMIT's caller. Everything the node prints goes through EMIT, +\ so a hook sees all of it. The hook is taken off when the text being +\ interpreted ends (quit.v4), so that nothing can leave a node silent. +\ POST uses it to compare what a case prints (docs/v4.0.0/NUCLEUS.md 6.3). +\ A is kept: the words that print have always been free to use it across +\ an EMIT. As v3, only the low 8 bits of the character are printed. header EMIT : EMIT ( c -- ) (EMIT-HOOK) b! @b if NONE push ; - NONE: drop CONSOLE-TX b! !b ; + NONE: drop + 255 and a push push \ A, and then the character, to the return stack + (OUT^) b! @b a! pop !+ a !b \ the character goes where (OUT^) points, which moves on + a (OUT)+256 xor if FULL drop pop a! ; + FULL: drop (FLUSH-OUT) pop a! ; header KEY : KEY ( -- c ) L: CONSOLE-STATUS b! @b if WAIT drop CONSOLE-RX b! @b ; diff --git a/v4/capsule/quit.v4 b/v4/capsule/quit.v4 index fa89762d..3ae961d1 100644 --- a/v4/capsule/quit.v4 +++ b/v4/capsule/quit.v4 @@ -4,17 +4,17 @@ \ DECOMPOSITION.md 5.15 and 5.10: QUIT ABORT ABORT" (ABORT") ." (."). Part of \ the compiler capsule. Rests on all the files before it. \ -\ A NODE IS HANDED A LINE (docs/v4.0.0/ENGINE.md 3.1). It does not read its -\ own command line and prints no prompt: that is its host's, as it is the -\ kernel's REPL's for a v3 VM. The host puts the text in TIB and starts -\ (LINE); the node interprets it and stops at (IDLE), having left in the -\ variable (LINE-STATUS) how the line ended: -\ 1 it completed the host says " ok" +\ A NODE IS SENT TEXT (docs/v4.0.0/MESH.md section 6). It does not read its +\ own command line and prints no prompt. A node with nothing to do waits at +\ its ports; a neighbour writes it a message; if that is text for this node +\ it is interpreted; what it printed goes back as a message, and then a +\ message saying how the text ended: +\ 1 it completed a console says " ok" \ 2 it ended in an error the message is already printed; " ERROR" \ 0 QUIT nothing is said -\ What the console then shows is v3's: -\ ok> 65 EMIT the host's prompt, and the line -\ A ok what the line printed, then the host's " ok" +\ What a console then shows is v3's: +\ ok> 65 EMIT the console's prompt, and the line +\ A ok what the line printed, then " ok" \ ok> NOSUCH \ UNKNOWN WORD: 'NOSUCH' \ ERROR @@ -22,7 +22,8 @@ \ Address out of range an address fault (D-14), from any depth \ ERROR \ KEY, EXPECT and QUERY are FORTH-79 words that read characters, as before; -\ they are not how a line reaches the node. +\ they are not how text reaches the node. They still read the console's +\ registers, CONSOLE-RX and CONSOLE-STATUS, and not a message. \ \ THE STACKS are guarded (D-16): each counts what it holds, and a push onto \ a full one or a pop from an empty one is a fault. So QUIT and ABORT, which @@ -30,7 +31,10 @@ \ the data stack too. A store to RSTACK-DEPTH or DSTACK-DEPTH does that. \ \ Constants the loader supplies: -\ (LINE-STATUS) word address of the variable: how the last line ended +\ (LINE-STATUS) word address of the variable: how the last text ended +\ (MSG) (REPLY) (ME) (OUT) (OUT^) see core.v4, "what a node prints" +\ (PORT) word address of the node's port 0; (PORT)+8 is "any port" and +\ (PORT)+9 the port the last read from that came on \ (Q) word address of four cells of scratch, which system.v4 and \ blocks.v4 use too \ DSTACK-DEPTH RSTACK-DEPTH word addresses of the stack registers @@ -52,26 +56,62 @@ macro R-CLEAR RSTACK-DEPTH b! a !b endmacro \ (docs/v4.0.0/NUCLEUS.md 6.3). (EMIT-HOOK), core.v4, is set to 0 here at \ the end of every line, caught or not. \ -\ ( k -- ) the line is over. It is entered with how -- 0 QUIT, 1 completed, -\ anything else an error -- and never returns: it leaves that in -\ (LINE-STATUS) and stops at (IDLE), where the host finds the node. It is -\ always jumped to, never called, by something that has emptied the return -\ stack (or by a fault, which empties it). -: (IDLE) L: jump L +\ ( s -- ) the text is done with. What it printed is sent, then a message +\ saying how it ended -- 0 QUIT, 1 completed, 2 an error -- and the node waits +\ for the next. (DONE) is entered with the same number and decides whether +\ an error was one to catch; it is always jumped to, never called, by +\ something that has emptied the return stack (or by a fault, which empties +\ it). (LINE-STATUS) keeps how the last text ended. +: (FINISH) ( s -- ) + (LINE-STATUS) b! dup !b + (FLUSH-OUT) + 3 (HDR) 4 !b !b \ a message of type 3, four characters long: how it ended + jump (IDLE) : (DONE) - (EMIT-HOOK) b! 0 !b \ the console is the console again + (EMIT-HOOK) b! 0 !b \ what is printed is printed again if GO -1 + if OK drop (RESET) - (CATCH) b! @b if LOUD drop -1 !b 1 jump (DONE) \ caught: the line completed - LOUD: drop 2 (LINE-STATUS) b! !b jump (IDLE) - OK: drop 1 (LINE-STATUS) b! !b jump (IDLE) - GO: drop 0 (LINE-STATUS) b! !b jump (IDLE) + (CATCH) b! @b if LOUD drop -1 !b 1 jump (DONE) \ caught: the text completed + LOUD: drop 2 jump (FINISH) + OK: drop 1 jump (FINISH) + GO: drop 0 jump (FINISH) -\ ( -- ) THE LINE ENTRY. The host has put a line of text in TIB, a zero -\ after it, and its length in SPAN, has emptied the return stack and set P -\ here. The line is interpreted with one return entry under it, this -\ word's call of INTERPRET; whatever is on the data stack stays there. +\ ( -- ) WAITING. A node with nothing to do is blocked reading its ports +\ (docs/v4.0.0/MESH.md 4.1): it executes nothing until a neighbour writes. +\ What arrives is a message (core.v4). Its first word is taken from any +\ port and the rest from the port that came on. Its text goes into TIB, +\ which holds 1024 characters, the most a message carries; a longer one is +\ read to its end, so that what follows it is not taken for a message, and +\ is error 12. A message of type 1 for this node is text to interpret: it +\ is done as a line was, and (FINISH) reports how it ended. Any other is +\ let go: passing a message on is MESH.md step 4. +: (IDLE) + (PORT)+8 b! @b (MSG) a! !+ \ to, from any port + (PORT)+9 b! @b (PORT) + dup b! \ B: the port it came on + 5 FOR @b !+ UNEXT \ from, type, heat and TTL, ACL tag, sequence, length + (REPLY) a! ! + (MSG)+6 a! @ -if SIZED jump BAD \ a length below zero: no telling what follows + SIZED: dup -1025 + -if LONG drop jump FITS + LONG: drop 3 + 2/ 2/ -1 + FOR @b drop UNEXT 0 \ too long: read it and let it go + BAD: drop 0 (MSG)+6 a! ! 0 SPAN a! ! NODE-ERROR b! 12 !b + FITS: + 3 + 2/ 2/ if EMPTY + -1 + TIB 2/ 2/ a! FOR @b !+ UNEXT + jump READ + EMPTY: drop + READ: + 0 (MSG)+6 a! @ TIB + C! \ a zero after the text + (MSG)+6 a! @ SPAN a! ! + (MSG) a! @ (ME) a! @ xor if MINE drop jump (IDLE) + MINE: drop + (MSG)+2 a! @ -1 + if TEXT drop jump (IDLE) + TEXT: drop jump (LINE) + +\ ( -- ) THE TEXT, INTERPRETED. It is in TIB with a zero after it and its +\ length in SPAN, and the return stack is empty. It is interpreted with one +\ return entry under it, this word's call of INTERPRET; whatever is on the +\ data stack stays there. : (LINE) 0 BLK a! ! \ the terminal, whatever was being loaded TIB (SRC) a! ! 0 >IN a! ! diff --git a/v4/include/v4/boot.h b/v4/include/v4/boot.h index 7adabf14..bfe0d07c 100644 --- a/v4/include/v4/boot.h +++ b/v4/include/v4/boot.h @@ -33,6 +33,7 @@ #define V4_BOOT_H #include "v4/image.h" +#include "v4/message.h" typedef struct { v4_node *n; @@ -66,8 +67,9 @@ typedef struct { int v4_boot_run(const v4_boot *b, unsigned char *disk, unsigned blocks); /* Hand the node a line and run it to its end, sending what it prints to - * `out`. Returns how it ended -- V4_LINE_QUIT, V4_LINE_COMPLETED or - * V4_LINE_ERROR (image.h) -- or one of these: */ + * `out`. The line is sent to the node as a message and what it prints + * comes back as messages (message.h). Returns how it ended -- V4_TEXT_QUIT, + * V4_TEXT_COMPLETED or V4_TEXT_ERROR -- or one of these: */ #define V4_BOOT_LINE_TOO_LONG (-1) /* more than the node's input buffer holds; nothing was run */ #define V4_BOOT_LINE_STOPPED (-2) /* the node stopped on a fault, or never finished */ #define V4_BOOT_LINE_NO_INPUT (-3) /* the line read the keyboard and there is no more input */ diff --git a/v4/include/v4/image.h b/v4/include/v4/image.h index 6d58c524..7c145c8e 100644 --- a/v4/include/v4/image.h +++ b/v4/include/v4/image.h @@ -10,6 +10,10 @@ * (capsules/v4/nucleus-.f18). docs/v4.0.0/MESH.md section 5. * - this description of it, a C file: the addresses a host needs. * + * A node that has taken the nucleus in is sent text as messages and sends + * back what it prints (v4/include/v4/message.h); nothing here hands it a + * line. + * * A description is for one cell width, one node size and one pair of stack * sizes; v4_image_born refuses one the engine was not built for. */ @@ -22,16 +26,10 @@ typedef struct { /* what the image was built for */ unsigned cell_bits, node_words, data_ring, ret_ring; - /* The node is handed a line (docs/v4.0.0/ENGINE.md 3.1). Its host puts - * text in the input buffer and starts it at `line`; it stops at `idle`, - * with how the line ended in the cell `line_status`. At switch-on it - * is at `idle`. */ - v4_cell line; /* (LINE) */ - v4_cell idle; /* (IDLE) */ - v4_cell line_status; /* word address of the variable (LINE-STATUS) */ - v4_cell tib; /* byte address of the input buffer */ - unsigned tib_bytes; /* its size: a line may be one less */ - v4_cell span; /* word address of the variable SPAN */ + /* Where the nucleus waits for a message (v4/capsule/quit.v4, (IDLE)): + * the node's P is there, blocked reading its ports, when it has nothing + * to do. */ + v4_cell idle; v4_cell fault_table; /* (FAULTS): where a fault goes */ v4_cell port; /* word address of the node's port (node.h) */ @@ -67,11 +65,6 @@ extern const v4_image v4_capsule_image; * back to, and FORGET will not go below it. */ void v4_image_seal(v4_node *n, const v4_image *im); -/* How a line ended. */ -#define V4_LINE_QUIT 0 /* QUIT: nothing is to be said */ -#define V4_LINE_COMPLETED 1 /* the host says " ok" */ -#define V4_LINE_ERROR 2 /* the message is printed; the host says " ERROR" */ - /* A node newly born (node.h), with the registers the nucleus expects of the * node it runs on -- and `disk`, `blocks` blocks of 1024 bytes, as its block * storage, or none if `disk` is 0. Its memory is empty and it is blocked @@ -81,21 +74,6 @@ void v4_image_seal(v4_node *n, const v4_image *im); int v4_image_born(v4_node *n, v4_exec_state *es, v4_heat *h, const v4_image *im, unsigned char *disk, unsigned blocks); -/* Hand the node `len` characters of text to interpret. Returns 1, or 0 if - * the text is longer than the node's input buffer holds (nothing is then - * done). After it the host runs the node -- v4_exec_step_word again and - * again, taking what the node prints from n->console and setting - * n->console_len back to 0 -- until v4_line_done; if v4_image_waiting comes - * first, the line is reading the keyboard, and the host gives it characters - * with v4_node_console_feed. */ -int v4_line_begin(v4_node *n, const v4_image *im, const char *text, unsigned len); - -/* 1 when the node has finished the line it was handed and is idle again. */ -int v4_line_done(const v4_node *n, const v4_image *im); - -/* How the line just finished ended: V4_LINE_QUIT, _COMPLETED or _ERROR. */ -int v4_line_status(const v4_node *n, const v4_image *im); - /* 1 if the node is waiting for a character: it is inside KEY and none is * pending. */ int v4_image_waiting(const v4_node *n, const v4_image *im); diff --git a/v4/include/v4/message.h b/v4/include/v4/message.h new file mode 100644 index 00000000..02b3dd18 --- /dev/null +++ b/v4/include/v4/message.h @@ -0,0 +1,63 @@ +/* message.h -- a message, as it is written to a port and read from one. + * docs/v4.0.0/MESH.md section 6. + * + * The ports are the transport; the message is what is transported. It is + * v3's Hermes message with what it carries, a word at a time: + * + * word 0 to: the node it is for + * word 1 from: the node that sent it + * word 2 type + * word 3 heat and TTL + * word 4 ACL tag: the sender's identity fingerprint + * word 5 sequence + * word 6 how many characters of text follow, 0 to 1024 + * word 7.. the text, four characters to a word, the first lowest + * + * Words 3, 4 and 5 are carried and not yet used: checking them is the + * router's, and awaits rulings (MESH.md section 3). + * + * This is for whatever is on the other end of a node's port and is not a + * node -- a console, a host -- to speak what the nodes speak (v4/capsule/ + * core.v4 and quit.v4 are the same thing in the node). Nothing here uses + * the C library. + */ +#ifndef V4_MESSAGE_H +#define V4_MESSAGE_H + +#include "v4/cell.h" + +#define V4_MSG_HEADER 7u +#define V4_MSG_MAX_CHARS 1024u /* a block */ +#define V4_MSG_MAX_WORDS (V4_MSG_HEADER + V4_MSG_MAX_CHARS / 4u) + +#define V4_MSG_TEXT 1 /* text to be interpreted */ +#define V4_MSG_OUTPUT 2 /* what a node printed */ +#define V4_MSG_DONE 3 /* how the text ended: one word, V4_TEXT_* */ + +/* how text ended */ +#define V4_TEXT_QUIT 0 /* QUIT: nothing is to be said */ +#define V4_TEXT_COMPLETED 1 /* a console says " ok" */ +#define V4_TEXT_ERROR 2 /* the message is printed; a console says " ERROR" */ + +typedef struct { + v4_cell word[V4_MSG_MAX_WORDS]; + unsigned count; /* words in it */ +} v4_message; + +/* A message of `len` characters, at most V4_MSG_MAX_CHARS. Returns how many + * words it is, or 0 if `len` is too many. */ +unsigned v4_message_text(v4_message *m, v4_cell to, v4_cell from, v4_cell type, const char *chars, unsigned len); + +/* A message arriving a word at a time. Start with m->count = 0 and give + * each word as it comes: returns 1 when the message is whole, 0 if there is + * more to come. A length that is not 0 to V4_MSG_MAX_CHARS is taken as 0. */ +int v4_message_word(v4_message *m, v4_cell word); + +/* Its parts. */ +#define v4_message_to(m) ((m)->word[0]) +#define v4_message_from(m) ((m)->word[1]) +#define v4_message_type(m) ((m)->word[2]) +unsigned v4_message_length(const v4_message *m); /* characters of text */ +char v4_message_char(const v4_message *m, unsigned i); /* the i-th of them */ + +#endif /* V4_MESSAGE_H */ diff --git a/v4/src/image.c b/v4/src/image.c index 847b17ce..9b079d42 100644 --- a/v4/src/image.c +++ b/v4/src/image.c @@ -29,39 +29,6 @@ int v4_image_waiting(const v4_node *n, const v4_image *im) return n->input_pos == n->input_len && n->p >= im->key_start && n->p < im->key_end; } -/* One byte of the node's memory: four to a cell, the first lowest, at either - * cell width -- as C! stores them (v4/capsule/core.v4). */ -static void put_byte(v4_node *n, v4_cell baddr, unsigned c) -{ - v4_cell word = baddr / 4; - unsigned shift = 8u * (unsigned)(baddr % 4); - v4_ucell mask = (v4_ucell)0xFFu << shift; - n->mem[word] = (v4_cell)(((v4_ucell)n->mem[word] & ~mask) | ((v4_ucell)(c & 0xFFu) << shift)); -} - -int v4_line_begin(v4_node *n, const v4_image *im, const char *text, unsigned len) -{ - unsigned i; - - if (len + 1u > im->tib_bytes) return 0; - for (i = 0; i < len; i++) put_byte(n, im->tib + (v4_cell)i, (unsigned char)text[i]); - put_byte(n, im->tib + (v4_cell)len, 0); - n->mem[im->span] = (v4_cell)len; - v4_rstack_reset(&n->rs); - n->p = im->line; - return 1; -} - -int v4_line_done(const v4_node *n, const v4_image *im) -{ - return n->p == im->idle; -} - -int v4_line_status(const v4_node *n, const v4_image *im) -{ - return (int)n->mem[im->line_status]; -} - void v4_image_seal(v4_node *n, const v4_image *im) { n->mem[im->boot_cells] = n->mem[im->dp]; diff --git a/v4/src/message.c b/v4/src/message.c new file mode 100644 index 00000000..8581a4df --- /dev/null +++ b/v4/src/message.c @@ -0,0 +1,44 @@ +/* message.c -- a message, as it is written to a port and read from one. + * See message.h. Nothing here uses the C library. + */ +#include "v4/message.h" + +unsigned v4_message_text(v4_message *m, v4_cell to, v4_cell from, v4_cell type, const char *chars, unsigned len) +{ + unsigned i, words; + + if (len > V4_MSG_MAX_CHARS) return 0; + words = (len + 3u) / 4u; + m->word[0] = to; + m->word[1] = from; + m->word[2] = type; + m->word[3] = 0; + m->word[4] = 0; + m->word[5] = 0; + m->word[6] = (v4_cell)len; + for (i = 0; i < words; i++) m->word[V4_MSG_HEADER + i] = 0; + for (i = 0; i < len; i++) + m->word[V4_MSG_HEADER + i / 4u] = (v4_cell)((v4_ucell)m->word[V4_MSG_HEADER + i / 4u] + | ((v4_ucell)(unsigned char)chars[i] << (8u * (i % 4u)))); + m->count = V4_MSG_HEADER + words; + return m->count; +} + +unsigned v4_message_length(const v4_message *m) +{ + v4_cell len = m->word[6]; + return (len < 0 || len > (v4_cell)V4_MSG_MAX_CHARS) ? 0u : (unsigned)len; +} + +char v4_message_char(const v4_message *m, unsigned i) +{ + return (char)(((v4_ucell)m->word[V4_MSG_HEADER + i / 4u] >> (8u * (i % 4u))) & 0xFFu); +} + +int v4_message_word(v4_message *m, v4_cell word) +{ + if (m->count < V4_MSG_MAX_WORDS) m->word[m->count] = word; + m->count++; + if (m->count < V4_MSG_HEADER) return 0; + return m->count >= V4_MSG_HEADER + (v4_message_length(m) + 3u) / 4u; +} diff --git a/v4/system/boot.c b/v4/system/boot.c index 33449540..a7f89e70 100644 --- a/v4/system/boot.c +++ b/v4/system/boot.c @@ -5,6 +5,7 @@ * which only a whole system has. */ #include "v4/boot.h" +#include "v4/message.h" #include "starkernel/capsule.h" #include "starkernel/capsule_generated.h" #include "starkernel/capsule_sig.h" @@ -126,22 +127,29 @@ static void post_watch(char c) post_len = 0; } +/* The boot is the node's neighbour on two of its ports. On port 0 it is + * the kernel: the node writes the number of a request there (ENGINE.md + * 3.3). On port 1 it is the console: it writes the node a message of text + * and reads back messages of what the node printed and of how the text + * ended (message.h). */ +#define KERNEL_PORT 0u +#define CONSOLE_PORT 1u +#define CONSOLE_ID 1 /* the console's number as a sender; the node's is 0 until it is given one */ + int v4_boot_line(const v4_boot *b, const char *text, unsigned len) { + static v4_message out, in; /* one line at a time: the boot is not re-entered */ v4_node *n = b->n; uint64_t steps = 0; - unsigned i; + unsigned sent = 0, i; - if (!v4_line_begin(n, b->im, text, len)) return V4_BOOT_LINE_TOO_LONG; + if (!v4_message_text(&out, 0, CONSOLE_ID, V4_MSG_TEXT, text, len)) return V4_BOOT_LINE_TOO_LONG; + in.count = 0; for (;;) { (void)v4_exec_step_word(n, b->es, b->h); - if (n->console_len) { - for (i = 0; i < n->console_len; i++) post_watch((char)n->console[i]); - b->out((const char *)n->console, n->console_len); - n->console_len = 0; - } if (n->stopped) return V4_BOOT_LINE_STOPPED; - if (n->asking) { /* blocked at its port: the kernel's turn */ + + if (n->asking && n->ask_port == KERNEL_PORT) { /* a request: the kernel's turn */ if (b->serve && n->request >= 1 && n->request <= (v4_cell)b->word_count) { b->serve(n, (unsigned)n->request); v4_node_port_served(n); @@ -153,8 +161,34 @@ int v4_boot_line(const v4_boot *b, const char *text, unsigned len) } continue; } - if (v4_line_done(n, b->im)) return v4_line_status(n, b->im); - if (v4_image_waiting(n, b->im)) { /* the line is reading the keyboard */ + if (n->asking && n->ask_port == CONSOLE_PORT) { /* a word of a message from the node */ + v4_cell word = n->request; + v4_node_port_served(n); + if (v4_message_word(&in, word)) { + unsigned chars = v4_message_length(&in); + if (v4_message_type(&in) == V4_MSG_OUTPUT) { + for (i = 0; i < chars; i++) { + char c = v4_message_char(&in, i); + post_watch(c); + b->out(&c, 1); + } + } else if (v4_message_type(&in) == V4_MSG_DONE) { + return (int)in.word[V4_MSG_HEADER]; + } + in.count = 0; + } + continue; + } + if (n->asking) return V4_BOOT_LINE_STOPPED; /* a port with nothing on it */ + + if (n->reading && !n->given) { + if (sent < out.count && (n->read_port == CONSOLE_PORT || n->read_port == V4_PORT_ANY)) { + v4_node_port_give(n, CONSOLE_PORT, out.word[sent++]); /* a word of the message to the node */ + continue; + } + return V4_BOOT_LINE_STOPPED; /* waiting for what will not come */ + } + if (v4_image_waiting(n, b->im)) { /* the text is reading the keyboard */ int c = b->key ? b->key() : V4_BOOT_KEY_END; unsigned char ch = (unsigned char)c; if (c == V4_BOOT_KEY_END) return V4_BOOT_LINE_NO_INPUT; @@ -225,10 +259,10 @@ static int load_capsule(const v4_boot *b, const char *name) if (len) { for (i = 0; i < len; i++) text[i] = (char)p[i]; int how = v4_boot_line(b, text, len); - if (how != V4_LINE_COMPLETED) { + if (how != V4_TEXT_COMPLETED) { say_where(b, name, block, line); - say(b, how == V4_LINE_ERROR ? " ended in an error: " - : how == V4_LINE_QUIT ? " ended with QUIT: " + say(b, how == V4_TEXT_ERROR ? " ended in an error: " + : how == V4_TEXT_QUIT ? " ended with QUIT: " : how == V4_BOOT_LINE_NO_INPUT ? " reads the keyboard: " : " stopped the node: "); b->out(text, len); say(b, "\n"); @@ -289,7 +323,9 @@ static int load_nucleus(const v4_boot *b) if (!p || cap->length % CELL_BYTES != 0) { say(b, "V4: capsule " NUCLEUS_NAME " is not whole words\n"); return 0; } words = cap->length / CELL_BYTES; - while (at < words || !v4_line_done(n, b->im)) { + /* until it has taken every word and is waiting for a message: reading + * its ports again, but from its memory now and not from the port */ + while (at < words || !(n->reading && !n->given && n->p != b->im->port + (v4_cell)V4_PORT_ANY)) { (void)v4_exec_step_word(n, b->es, b->h); if (n->stopped || n->asking || ++steps > STEP_LIMIT) { say(b, "V4: the node did not take the nucleus in\n"); @@ -298,7 +334,11 @@ static int load_nucleus(const v4_boot *b) if (n->reading && !n->given) { v4_ucell word = 0; unsigned i; - if (at >= words) { say(b, "V4: the node wants more than the nucleus holds\n"); return 0; } + if (at >= words) { + if (n->p != b->im->port + (v4_cell)V4_PORT_ANY) break; /* it is waiting for a message */ + say(b, "V4: the node wants more than the nucleus holds\n"); + return 0; + } for (i = 0; i < CELL_BYTES; i++) word |= (v4_ucell)p[at * CELL_BYTES + i] << (8 * i); v4_node_port_give(n, 0, (v4_cell)word); at++; @@ -335,7 +375,7 @@ int v4_boot_run(const v4_boot *b, unsigned char *disk, unsigned blocks) for (; div; div /= 10) text[at++] = (char)('0' + num / div % 10); for (k = 0; " KERNEL-WORD "[k]; k++) text[at++] = " KERNEL-WORD "[k]; for (k = 0; b->words[i][k] && at < sizeof text; k++) text[at++] = b->words[i][k]; - if (b->words[i][k] || v4_boot_line(b, text, at) != V4_LINE_COMPLETED) { + if (b->words[i][k] || v4_boot_line(b, text, at) != V4_TEXT_COMPLETED) { say(b, "V4: kernel word "); say(b, b->words[i]); say(b, " could not be made\nPARITY:FAIL\nPOST: FAILED\n"); return 0; } diff --git a/v4/tests/host_map.h b/v4/tests/host_map.h index d1b6e34c..78f5354e 100644 --- a/v4/tests/host_map.h +++ b/v4/tests/host_map.h @@ -69,6 +69,12 @@ #define CATCH (BUF0_W - 8) /* non-zero: a line's error is recorded here, -1, and the line ends " ok" */ #define LINE_STATUS (BUF0_W - 9) /* how the last line ended: 0 QUIT, 1 completed, 2 an error */ #define PORT (BUF0_W - 32) /* the node's ports (node.h): V4_PORTS of them, then "any port" and "which port". Port 0 is where its requests go. */ +#define ME (BUF0_W - 13) /* this node's number: a message is for it when its first word is this */ +#define OUT_PTR (BUF0_W - 14) /* where the next character printed goes: a cell of the output buffer */ +#define REPLY (BUF0_W - 15) /* the address of the port the message being served came on */ +#define MSG (BUF0_W - 48) /* the header of the message being served, 7 cells */ +#define OUT_W (BUF0_W - 400) /* the output buffer: 256 cells, a character to a cell */ +#define OUT_CELLS 256 #define WORD_DEFINED (BUF0_W - 11) /* the xt of the word that is told of each new entry, or 0 */ #define WORD_FORGOTTEN (BUF0_W - 12) /* the xt of the word that is told when entries go, or 0 */ #define LOG_LEVEL (BUF0_W - 5) /* the level at or below which a message is printed */ @@ -108,6 +114,7 @@ static int host_load(v4_text *tx, v4_node *n, const char *const *files, unsigned unsigned i; v4_node_reset(n); + n->mem[OUT_PTR] = OUT_W; /* nothing has been printed: what is, is kept from here (core.v4) */ v4_text_begin(tx, n, 16); v4_text_constant(tx, "N-1", V4_CELL_BITS - 1); v4_text_constant(tx, "NODE-ERROR", NODE_ERROR); @@ -148,6 +155,11 @@ static int host_load(v4_text *tx, v4_node *n, const char *const *files, unsigned v4_text_constant(tx, "(CATCH)", CATCH); v4_text_constant(tx, "(LINE-STATUS)", LINE_STATUS); v4_text_constant(tx, "(PORT)", PORT); + v4_text_constant(tx, "(ME)", ME); + v4_text_constant(tx, "(OUT^)", OUT_PTR); + v4_text_constant(tx, "(REPLY)", REPLY); + v4_text_constant(tx, "(MSG)", MSG); + v4_text_constant(tx, "(OUT)", OUT_W); v4_text_constant(tx, "(WORD-DEFINED)", WORD_DEFINED); v4_text_constant(tx, "(WORD-FORGOTTEN)", WORD_FORGOTTEN); v4_text_constant(tx, "BLOCK-NUMBER", STORAGE_REG); diff --git a/v4/tests/test_host_input.c b/v4/tests/test_host_input.c index f2ac3b4e..c0c33250 100644 --- a/v4/tests/test_host_input.c +++ b/v4/tests/test_host_input.c @@ -263,7 +263,10 @@ int main(void) } n.mem[BASE] = 10; CHECK(v4_node_console_feed(&n, "Z", 1) == 1 && run("KEY", 0, 0, 0, 0) && pop() == 'Z' && clean(), "KEY"); - CHECK(run("EMIT", 1, 'q', 0, 0) && clean() && n.console_len == 1 && n.console[0] == 'q', "EMIT"); + /* a node has no console of its own: what it prints is kept to be sent (core.v4) */ + n.mem[OUT_PTR] = OUT_W; + CHECK(run("EMIT", 1, 'q', 0, 0) && clean() && n.mem[OUT_PTR] == OUT_W + 1 && n.mem[OUT_W] == 'q', "EMIT"); + CHECK(run("EMIT", 1, 0x141, 0, 0) && clean() && n.mem[OUT_PTR] == OUT_W + 2 && n.mem[OUT_W + 1] == 'A', "EMIT prints the low 8 bits"); } /* ---- the in-line names ---- */ diff --git a/v4/tests/test_host_quit.c b/v4/tests/test_host_quit.c index 6698386d..e06575bb 100644 --- a/v4/tests/test_host_quit.c +++ b/v4/tests/test_host_quit.c @@ -41,7 +41,7 @@ * 3 ROLL is ROT. v3's count from zero. */ #include "v4/text.h" -#include "v4/image.h" +#include "v4/message.h" #include "v4/testcode.h" #include #include @@ -59,7 +59,7 @@ static v4_exec_state es; static v4_heat h; static v4_text tx; static v4_cell w_key, w_key_end, w_fault, capsule_latest; -static v4_image img; /* where a line is handed to the node: v4/include/v4/image.h */ +static v4_cell w_idle; /* (IDLE): where the node waits for a message */ static char out[V4_CONSOLE_CAP + 1]; /* The storage device's blocks: zeros at every switch-on. */ @@ -73,16 +73,6 @@ static void put_block(unsigned num, const char *text) } static long last_steps; -/* THE HOST. A node is handed a line and prints no prompt (ENGINE.md 3.1); - * these tests are its host, and do what tools/hosted.c does: take what is - * typed a line at a time, hand each line over, and say " ok" or " ERROR" and - * the next prompt. What is typed after a line is there for a word in it - * that reads the keyboard, and what such a word does not take is the next - * line. */ -static char typed[8192]; /* typed and not yet taken */ -static unsigned typed_len; -static int line_open; /* a line has been handed over and has not ended */ - /* THE KERNEL. A node asks its kernel by writing to its port (node.h), and * these tests are that too. Request 1 is "an entry has been made" ( xt -- ) * and request 2 "the entries from here up have gone" ( w -- ): the kernel's @@ -149,7 +139,31 @@ static const char *node_name(v4_cell xt) return name; } -/* Run until the line ends, or until it has been inside KEY with nothing to +/* THE CONSOLE. A node is sent text as a message and sends back what it + * prints (MESH.md section 6); these tests are its console, on its port 1, + * and do what tools/hosted.c does: take what is typed a line at a time, + * send each line as a message, show what comes back, and say " ok" or + * " ERROR" and the next prompt. What is typed after a line is there for a + * word in it that reads the keyboard, and what such a word does not take is + * the next line. */ +#define CONSOLE_PORT 1u +static char typed[8192]; /* typed and not yet taken */ +static unsigned typed_len; +static int line_open; /* a line has been sent and has not ended */ +static v4_message to_node, from_node; /* the message going in, and the one coming out */ +static unsigned to_sent; /* how many words of to_node the node has taken */ +static char shown[V4_CONSOLE_CAP]; /* what the node has printed since the console last looked */ +static unsigned shown_len; +static int shown_dropped; +static int text_ended; /* how the text ended, when it has */ + +/* 1 if the node is where it waits for a message, with nothing given it. */ +static int node_idle(void) +{ + return n.reading && !n.given && n.read_port == V4_PORT_ANY && n.p > w_idle && n.p <= w_idle + 3; +} + +/* Run until the text ends, or until it has been inside KEY with nothing to * read for 64 instruction words; or until `max` words. 1: ended, 2: waiting * for a character, 0: neither. */ static int run_line(long max) @@ -157,14 +171,36 @@ static int run_line(long max) long steps = 0; unsigned idle = 0; while (steps < max && idle < 64) { - if (v4_line_done(&n, &img)) { last_steps = steps; return 1; } (void)v4_exec_step_word(&n, &es, &h); steps++; - if (n.asking) { kernel_serve(); v4_node_port_served(&n); } /* blocked at its port: the kernel's turn */ + if (n.asking && n.ask_port == 0) { kernel_serve(); v4_node_port_served(&n); continue; } /* a request */ + if (n.asking && n.ask_port == CONSOLE_PORT) { /* a word of a message from the node */ + v4_cell word = n.request; + v4_node_port_served(&n); + if (v4_message_word(&from_node, word)) { + unsigned i, chars = v4_message_length(&from_node); + if (v4_message_type(&from_node) == V4_MSG_OUTPUT) { + for (i = 0; i < chars; i++) { + if (shown_len < sizeof shown) shown[shown_len++] = v4_message_char(&from_node, i); + else shown_dropped = 1; + } + } else if (v4_message_type(&from_node) == V4_MSG_DONE) { + text_ended = (int)from_node.word[V4_MSG_HEADER]; + from_node.count = 0; + last_steps = steps; + return 1; + } + from_node.count = 0; + } + continue; + } + if (n.reading && !n.given && to_sent < to_node.count && (n.read_port == CONSOLE_PORT || n.read_port == V4_PORT_ANY)) { + v4_node_port_give(&n, CONSOLE_PORT, to_node.word[to_sent++]); /* a word of the message to the node */ + continue; + } if (n.input_pos == n.input_len && n.p >= w_key && n.p < w_key_end) idle++; else idle = 0; } last_steps = steps; - if (v4_line_done(&n, &img)) return 1; return idle >= 64 ? 2 : 0; } @@ -193,7 +229,6 @@ static void boot_with(unsigned depth) for (v4_cell k = BVARS; k < BVARS + 14; k++) if (k != SRC) n.mem[k] = 0; /* empty buffers, SCR and BLK 0, no hook */ memset(disk, 0, sizeof disk); v4_node_storage_attach(&n, STORAGE_REG, disk, DISK_BLOCKS); - v4_node_console_attach(&n, CONSOLE_TX); v4_node_console_input_attach(&n, CONSOLE_RX, CONSOLE_ST); v4_node_fault_attach(&n, w_fault); v4_node_error_attach(&n, NODE_ERROR); @@ -208,10 +243,16 @@ static void boot_with(unsigned depth) n.mem[WORD_FORGOTTEN] = 0; known_n = 0; last_request = 0; - n.mem[LINE_STATUS] = V4_LINE_COMPLETED; - n.p = img.idle; /* idle, waiting to be handed a line */ + n.mem[LINE_STATUS] = 1; + n.mem[ME] = 0; /* it has no number yet: a message to 0 is for it */ + n.mem[OUT_PTR] = OUT_W; + n.mem[REPLY] = PORT + CONSOLE_PORT; + n.p = w_idle; /* waiting for a message */ typed_len = 0; line_open = 0; + to_node.count = 0; to_sent = 0; from_node.count = 0; + shown_len = 0; shown_dropped = 0; + (void)v4_exec_step_word(&n, &es, &h); /* it reads its ports, and is blocked */ } static void boot(void) { boot_with(0); } /* The same with nothing at all on the data stack. */ @@ -252,27 +293,27 @@ static const char *say(const char *input) unsigned len; if (!nl) break; len = (unsigned)(nl - typed); - if (!v4_line_begin(&n, &img, typed, len)) return "(line too long)"; + if (!v4_message_text(&to_node, 0, 1, V4_MSG_TEXT, typed, len)) return "(line too long)"; + to_sent = 0; memmove(typed, nl + 1, typed_len - len - 1); typed_len -= len + 1; line_open = 1; } - v4_node_console_attach(&n, CONSOLE_TX); /* empties the capture */ - v4_node_console_input_attach(&n, CONSOLE_RX, CONSOLE_ST); /* and the keyboard */ + shown_len = 0; shown_dropped = 0; + v4_node_console_input_attach(&n, CONSOLE_RX, CONSOLE_ST); /* empties the keyboard */ if (v4_node_console_feed(&n, typed, typed_len) != typed_len) return "(input queue full)"; ended = run_line(40000000); took = n.input_pos; /* what a word in the line read */ memmove(typed, typed + took, typed_len - took); typed_len -= took; - if (n.console_dropped || olen + n.console_len + 16 > sizeof out) return "(too much output)"; - memcpy(out + olen, n.console, n.console_len); - olen += n.console_len; + if (shown_dropped || olen + shown_len + 16 > sizeof out) return "(too much output)"; + memcpy(out + olen, shown, shown_len); + olen += shown_len; out[olen] = 0; if (ended == 0) return "(still running)"; if (ended == 2) break; line_open = 0; - tail = v4_line_status(&n, &img) == V4_LINE_COMPLETED ? " ok\nok> " - : v4_line_status(&n, &img) == V4_LINE_ERROR ? " ERROR\nok> " : "ok> "; + tail = text_ended == V4_TEXT_COMPLETED ? " ok\nok> " : text_ended == V4_TEXT_ERROR ? " ERROR\nok> " : "ok> "; memcpy(out + olen, tail, strlen(tail) + 1); olen += (unsigned)strlen(tail); } @@ -739,12 +780,7 @@ int main(void) CHECK(v4_text_here(&tx) < DICT_W, "code stays below the dictionary space"); printf(" capsule: %ld words\n", (long)v4_text_here(&tx) - 16); if (failures) { printf(" %d checks, %d failures\n", checks, failures); return 1; } - img.line = v4_text_word(&tx, "(LINE)"); - img.idle = v4_text_word(&tx, "(IDLE)"); - img.line_status = LINE_STATUS; - img.tib = TIB; - img.tib_bytes = 1025u; - img.span = SPAN; + w_idle = v4_text_word(&tx, "(IDLE)"); w_key = v4_text_word(&tx, "KEY"); w_key_end = v4_text_word(&tx, "CR"); /* the word after KEY in core.v4 */ w_fault = v4_text_word(&tx, "(FAULTS)"); @@ -753,11 +789,12 @@ int main(void) /* ---- switch-on ---- */ boot(); - CHECK(v4_line_done(&n, &img) && n.console_len == 0, "the node is idle and has printed nothing: the prompt is its host's"); - CHECK(run_line(5000) == 1 && last_steps == 0, "and goes on waiting to be handed a line"); + CHECK(node_idle() && n.mem[OUT_PTR] == OUT_W, "the node is waiting at its ports and has printed nothing: the prompt is its console's"); + { v4_uheat_t clock = es.anticlock; + CHECK(run_line(5000) == 0 && es.anticlock == clock, "and goes on waiting, executing nothing"); } CHECK(canary_under_expect(), "with the data stack as it found it"); (void)v4_exec_step_word(&n, &es, &h); - CHECK(v4_line_done(&n, &img), "it stays idle however long it is run"); + CHECK(node_idle(), "it stays waiting however long it is run"); /* ---- the sessions ---- */ for (i = 0; i < NSCRIPT; i++) { @@ -883,7 +920,7 @@ int main(void) memcpy(line, "65 EMIT", 7); line[1025] = '\n'; line[1026] = 0; CHECK(is(say(line), "(line too long)"), "one of 1025 is not taken: the node's input buffer holds a block"); - CHECK(v4_line_done(&n, &img) && n.console_len == 0, "and nothing of it was run"); + CHECK(node_idle() && n.mem[OUT_PTR] == OUT_W, "and nothing of it was sent"); } /* ---- ABORT and QUIT from deep in a programme, again and again ---- */ @@ -1247,7 +1284,7 @@ int main(void) boot_bare(); CHECK(load_source("tools.fth"), "tools.fth compiles, every line of it"); CHECK(is(say(": SQ DUP * ; SEE SQ\n"), ": SQ\n dup call * \n ; \n ok\nok> "), "a definition: an in-line word, a call by name, the return"); - CHECK(is(say("SEE DUP\n"), ": DUP\n dup ; \n ok\nok> ") && is(say("SEE EMIT\n"), out) && strncmp(out, ": EMIT\n @p ", 12) == 0 && strstr(out, " b! !b ; \n"), + CHECK(is(say("SEE DUP\n"), ": DUP\n dup ; \n ok\nok> ") && is(say("SEE EMIT\n"), out) && strncmp(out, ": EMIT\n @p ", 12) == 0 && strstr(out, " b! @b \n if ") && strstr(out, " pop a! ; \n"), "the capsule's own words; a literal's value follows its @p"); CHECK(is(say("VARIABLE V 7 V ! SEE V\n"), ": V\n data: 7 \n ok\nok> ") && is(say("5 CONSTANT K SEE K\n"), ": K\n data: 5 \n ok\nok> "), "a variable and a constant show what they hold"); CHECK(is(say(": IM 1 ; IMMEDIATE SEE IM\n"), ": IM\n @p 1 ; \nIMMEDIATE\n ok\nok> "), "an immediate word says so"); diff --git a/v4/tools/hosted.c b/v4/tools/hosted.c index ab3cc20e..f3fb77b9 100644 --- a/v4/tools/hosted.c +++ b/v4/tools/hosted.c @@ -67,9 +67,9 @@ int main(void) len = strlen(line); if (len && line[len - 1] == '\n') len--; how = v4_boot_line(&boot, line, (unsigned)len); - if (how == V4_LINE_COMPLETED) fputs(" ok\n", stdout); + if (how == V4_TEXT_COMPLETED) fputs(" ok\n", stdout); if (leaving) { fflush(stdout); return 0; } - else if (how == V4_LINE_ERROR) fputs(" ERROR\n", stdout); + else if (how == V4_TEXT_ERROR) fputs(" ERROR\n", stdout); else if (how == V4_BOOT_LINE_TOO_LONG) fputs("Line too long\n ERROR\n", stdout); else if (how == V4_BOOT_LINE_NO_INPUT) { putchar('\n'); return 0; } else if (how == V4_BOOT_LINE_STOPPED) { fflush(stdout); fprintf(stderr, "starforth4: the node stopped on a fault\n"); return 1; } diff --git a/v4/tools/mkimage.c b/v4/tools/mkimage.c index 1a063081..3e333119 100644 --- a/v4/tools/mkimage.c +++ b/v4/tools/mkimage.c @@ -52,7 +52,7 @@ int main(int argc, char **argv) static const char *const files[] = { "core.v4", "input.v4", "dict.v4", "codegen.v4", "compile.v4", "quit.v4", "forth.v4", "numout.v4", "words.v4", "system.v4", "qmath.v4", "blocks.v4", "log.v4", "acl.v4" }; FILE *out; - v4_cell k, line, idle, faults, voc; + v4_cell k, idle, faults, voc; unsigned count = 0; if (argc != 3) die("usage: mkimage DESCRIPTION.c CAPSULE.f18", NULL); @@ -60,7 +60,6 @@ int main(int argc, char **argv) if (!host_load(&tx, &n, files, (unsigned)(sizeof files / sizeof files[0]))) die("the capsule does not assemble", NULL); if (!v4_text_finish(&tx)) die("not everything is defined", v4_text_error(&tx)); if (v4_text_here(&tx) >= DICT_W) die("the capsule's code runs into the dictionary space", NULL); - line = v4_text_word(&tx, "(LINE)"); idle = v4_text_word(&tx, "(IDLE)"); faults = v4_text_word(&tx, "(FAULTS)"); w_key = v4_text_word(&tx, "KEY"); @@ -99,7 +98,8 @@ int main(int argc, char **argv) for (voc = n.mem[VOC_LINK]; voc != 0; voc = n.mem[voc + 1]) clear_acl(n.mem[voc]); if (!v4_node_guards_intact(&n)) die("the node's guards are damaged", NULL); - n.mem[LINE_STATUS] = V4_LINE_COMPLETED; /* idle, with nothing to report */ + n.mem[LINE_STATUS] = 1; /* nothing has ended badly */ + n.mem[OUT_PTR] = OUT_W; /* nothing has been printed */ /* the nucleus as a capsule of F18 code: the words a neighbour writes to * an empty node's port, each in V4_CELL_BITS / 8 bytes, low byte first */ @@ -113,8 +113,7 @@ int main(int argc, char **argv) fprintf(out, "/* Generated by v4/tools/mkimage.c from v4/capsule -- do not edit. */\n#include \"v4/image.h\"\n\n"); fprintf(out, "const v4_image v4_capsule_image = {\n %uu, %uu, %uu, %uu,\n", (unsigned)V4_CELL_BITS, (unsigned)V4_NODE_WORDS, (unsigned)V4_DATA_RING, (unsigned)V4_RET_RING); - fprintf(out, " %ld, %ld, %ld,\n %ld, %uu, %ld,\n %ld, %ld,\n %ld, %ld,\n", (long)line, (long)idle, (long)LINE_STATUS, - (long)TIB, 1025u, (long)SPAN, (long)faults, (long)PORT, (long)w_key, (long)w_key_end); + fprintf(out, " %ld,\n %ld, %ld,\n %ld, %ld,\n", (long)idle, (long)faults, (long)PORT, (long)w_key, (long)w_key_end); fprintf(out, " %ld, %ld, %ld,\n %ld, %ld,\n %ld,\n %ld,\n %ld, %ld,\n %ld, %ld\n};\n", (long)CONSOLE_TX, (long)CONSOLE_RX, (long)CONSOLE_ST, (long)DSTACK_REG, (long)RSTACK_REG, (long)NODE_ERROR, (long)STORAGE_REG, (long)DP, (long)LATEST, (long)BOOT_CELLS, (long)FENCE);