From 630d03fa4e47b02a391fa1fb9dd2010b74269fda Mon Sep 17 00:00:00 2001 From: rajames Date: Tue, 6 Oct 2026 12:01:32 -0400 Subject: [PATCH] feat(v4.0.0): a node finds the way -- routes, passing on, SEND; one fault stands MESH.md step 4. Each node has a table of destinations and the port toward each, and a port for everything else (ROUTE, DEFAULT-ROUTE, NO-ROUTES). A message not for this node is passed on whole; one with nowhere to go is dropped and counted. What text prints and how it ended go back to the node it came from by the same table. SEND sends text to another node. test_host_mesh.c: three StarForth nodes in a row behind a console, 28 checks at both widths and under ASan+UBSan. hosted-check on three ISAs. Bare metal: logs/20261006-115225 (amd64), -115501 (aarch64), -115849 (riscv64). NOT DONE. Two neighbours that write to each other at once wait for ever: a write blocks until the neighbour reads, and a node that is writing is not reading. The last check in test_host_mesh.c shows it (KNOWN FAULT). MESH.md section 7a sets out the ways out; none is chosen. Co-Authored-By: Claude Opus 5.5 --- capsules/BLOCK_MAP.md | 2 +- capsules/v4/nucleus-64.f18 | Bin 49456 -> 50832 bytes docs/v4.0.0/MESH.md | 71 ++++++ .../amd64/qemu-amd64-20261006-115225.log | 130 +++++++++++ .../aarch64/qemu-aarch64-20261006-115501.log | 104 +++++++++ .../riscv64/qemu-riscv64-20261006-115849.log | 174 ++++++++++++++ v4/README.md | 9 + v4/capsule/core.v4 | 39 +++- v4/capsule/quit.v4 | 73 +++++- v4/tests/host_map.h | 17 ++ v4/tests/test_host_mesh.c | 218 ++++++++++++++++++ 11 files changed, 820 insertions(+), 17 deletions(-) create mode 100644 logs/20261006-115225/amd64/qemu-amd64-20261006-115225.log create mode 100644 logs/20261006-115501/aarch64/qemu-aarch64-20261006-115501.log create mode 100644 logs/20261006-115849/riscv64/qemu-riscv64-20261006-115849.log create mode 100644 v4/tests/test_host_mesh.c diff --git a/capsules/BLOCK_MAP.md b/capsules/BLOCK_MAP.md index a141bddb..a8037619 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 72026e29e8e5f8cb92183d7fafdfd94347d76515..229ddeac8eb49b077076f1e97f8a971cf2b03c6f 100644 GIT binary patch literal 50832 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 literal 49456 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 z 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 F{C|N0&SL-o diff --git a/docs/v4.0.0/MESH.md b/docs/v4.0.0/MESH.md index 5cc75c07..44b417bd 100644 --- a/docs/v4.0.0/MESH.md +++ b/docs/v4.0.0/MESH.md @@ -213,6 +213,39 @@ outer nodes, and for each other unit the port toward that unit's centre. A different geometry is a different way of filling in the wiring table and these tables. Nothing else changes. +## 7a. Two neighbours writing to each other (open; awaits a ruling) + +The fault is in section 10, step 4. Three ways out, none built: + +**A. A node writes only to a neighbour that is already reading.** The +engine gives a node two more things to fetch, as the F18's `io` register +does: which ports have a neighbour writing, and which have a neighbour +reading. A node with a message to send looks first. If the neighbour is +reading, it writes, and the write does not wait. If the neighbour is +writing to it instead, it takes that message in first, and deals with it, +and looks again. A node therefore holds messages waiting to go, in its own +memory, and what it does when that room is full has to be decided (the +message is lost and counted, as one with nowhere to go is now). Writes +still block, as ruled; a node simply does not start one it cannot finish. +This is how it is done on the chip. It is all in the nucleus but for the +two fetches. + +**B. Passing on is not the node's programme's work.** `DECOMPOSITION.md` +6.1 says "the router in each node forwards packets". Read as a thing apart +from the programme -- logic beside the F18 on the FPGA, a part of the +fabric in the model -- it takes in and sends on whatever the programme is +doing, and holds what is for the programme until it reads. The programme's +own writes then never wait on a neighbour's programme. This is more +hardware per node and takes passing-on out of F18 code, and out of what a +capsule can change. + +**C. No answer to a `SEND`.** It removes the case found and leaves the +fault: any two messages crossing still stop both nodes. Not offered as a +way out; listed so that it is seen to have been weighed. + +Recommended: A. It keeps every ruling as it stands, keeps a node an F18 +and nothing more, and what it adds to the engine the chip already has. + ## 8. Storage **Proposal.** A disk is a device on a port. Asking for a block is a @@ -311,6 +344,44 @@ Each is tested, committed and pushed before the next. 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).** + **Built 2026-10-06; NOT done: one fault stands, below, and it needs a + ruling.** Each node has a table of up to 16 destinations and the port + toward each, and one port for everything else (`ROUTE ( node port -- )`, + `DEFAULT-ROUTE ( port -- )`, `NO-ROUTES`; `(PORT-FOR)` in + `v4/capsule/core.v4`). A message not for this node is written, whole, + to the port its destination's entry names (`(PASS-ON)`, + `v4/capsule/quit.v4`); with no entry and no port for everything else it + is dropped and counted (`(LOST)`). What text prints, and how it ended, + go back to the node the text came from by the same table, so an answer + crosses as many nodes as the text did. `SEND ( baddr u node -- )` sends + text to another node; `(ME)` is a node's own number; `(CONSOLE)`, when + set, is where a node's printing goes instead of to the sender. + `v4/tests/test_host_mesh.c`, 28 checks at both widths and under ASan + and UBSan: three StarForth nodes in a row behind a console; text for + the far one passes through the other two and its answer comes back; + each node keeps its own dictionary; output longer than one message; a + 1024-character message passed on whole; a message with nowhere to go + counted; a table changed while running. The single-node products are + unchanged: `hosted-check` on three ISAs; bare metal + `logs/20261006-115225` (amd64), `-115501` (aarch64), `-115849` + (riscv64). + **THE FAULT: two neighbours that write to each other at once wait for + ever.** A write blocks until the neighbour reads (ruling, section 4.1), + and a node that is blocked writing is not reading. Passing a message on + is done here by the node's own programme, so a node cannot pass + anything on, or take anything in, while it waits to write. Found so: the + far node `SEND`s text to the middle one and then goes to send word of + how its own text ended, which goes by the middle one; the middle one has + done the text and goes to answer the far one. Each is writing the first + word of a message to the other. It is not peculiar to `SEND`: any two + messages going opposite ways on one wire at the same moment do it, and + so would a ring of nodes each writing to the next. The last check in + `test_host_mesh.c` shows it and is named KNOWN FAULT; it is there so the + fault is on record and is seen to go. + It is not a slip in the code. It is what blocking writes and a + programme that does one thing at a time give. Section 7 said nothing + about it and should have. What is to be done about it is not decided: + the choices are in section 7a. 5. **Birth and Hera's requests (section 9); the unit of five.** 6. **Storage (section 8).** 7. **A second unit; scaling while running; sleep, wake and kill by diff --git a/logs/20261006-115225/amd64/qemu-amd64-20261006-115225.log b/logs/20261006-115225/amd64/qemu-amd64-20261006-115225.log new file mode 100644 index 00000000..c20d5dcb --- /dev/null +++ b/logs/20261006-115225/amd64/qemu-amd64-20261006-115225.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:51:59 + +UEFI BootServices: EXITED + +=== StarKernel Boot Information === +Memory map entries: 131 +Total memory: 1023 MB +Usable memory: 968 MB +=================================== + +PMM initialized. +PMM statistics: + Total pages: 249253 + Free pages : 247730 + 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=2118830204 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=1019349401, tick_hz=100, initial_count=10193494 +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=0x9653e727bf5cf8bd capsule_hash=0x9653e727bf5cf8bd words=305 +V4: capsule v4:forth79.4th signature: missing (unsigned) +PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x14a9ea7be071593b +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=0x721a93a6abb945f9 +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-115501/aarch64/qemu-aarch64-20261006-115501.log b/logs/20261006-115501/aarch64/qemu-aarch64-20261006-115501.log new file mode 100644 index 00000000..389775e9 --- /dev/null +++ b/logs/20261006-115501/aarch64/qemu-aarch64-20261006-115501.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:54:35 + +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=0x9653e727bf5cf8bd capsule_hash=0x9653e727bf5cf8bd words=305 +V4: capsule v4:forth79.4th signature: missing (unsigned) +PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x14a9ea7be071593b +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=0x721a93a6abb945f9 +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-115849/riscv64/qemu-riscv64-20261006-115849.log b/logs/20261006-115849/riscv64/qemu-riscv64-20261006-115849.log new file mode 100644 index 00000000..a359a5d9 --- /dev/null +++ b/logs/20261006-115849/riscv64/qemu-riscv64-20261006-115849.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:58:12 + +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=0x9653e727bf5cf8bd capsule_hash=0x9653e727bf5cf8bd words=305 +V4: capsule v4:forth79.4th signature: missing (unsigned) +PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x14a9ea7be071593b +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=0x721a93a6abb945f9 +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/README.md b/v4/README.md index c0c7ecd7..2d143acf 100644 --- a/v4/README.md +++ b/v4/README.md @@ -112,6 +112,15 @@ their ports are wired, both of which change while they run. The products below are still one node each; they become the five nodes at `MESH.md` steps 8 and 9. +**Finding the way** (`MESH.md` step 4) is built: a node has a table of +which port leads toward which node (`ROUTE`, `DEFAULT-ROUTE`, `NO-ROUTES`), +passes on a message that is not for it, and `SEND`s text to another node; +`v4/tests/test_host_mesh.c` runs three StarForth nodes in a row. **It has +a fault that stands:** two neighbours that write to each other at the same +moment wait for ever, because a write blocks until the neighbour reads and +a node that is writing is not reading. The test shows it, named KNOWN +FAULT. The ways out are in `MESH.md` section 7a and none is chosen yet. + **This is still the lone node.** On bare metal `kernel_main.c` starts it before the fleet tables, beside the kernel's own system and not in the VM's place. `ENGINE.md` sets out the steps from here; step 1 is done and step 2 is diff --git a/v4/capsule/core.v4 b/v4/capsule/core.v4 index 02c2907c..ab369018 100644 --- a/v4/capsule/core.v4 +++ b/v4/capsule/core.v4 @@ -6,7 +6,8 @@ \ \ Constants the loader supplies: N-1 (cell bits - 1), NODE-ERROR, CONSOLE-TX, \ CONSOLE-RX, CONSOLE-STATUS, BASE, (EMIT-HOOK), (MSG), (REPLY), (ME), (OUT), -\ (OUT^). +\ (OUT^), (CONSOLE), (ROUTES), (ROUTE#), (ROUTE-DEFAULT), (PRINT-TO), +\ (PRINT-PORT). \ \ 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 @@ -94,8 +95,9 @@ header CMOVE \ ---- section 5.10: the console ------------------------------------------- \ ---- 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 +\ it prints while doing it is sent as a message: to the node in (CONSOLE), or +\ if that is 0 to whoever sent the text; by the port that leads there, or if +\ this node knows of none, by the port the text 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 @@ -112,20 +114,35 @@ header CMOVE \ 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. +\ FINDING THE WAY (MESH.md section 7). A node knows its ports and nothing of +\ the shape they are wired in. Whoever wires it tells it, for a node, which +\ port leads toward that node: the table (ROUTES), (ROUTE#) entries of a +\ node's number and a port's address; and (ROUTE-DEFAULT), the port for any +\ node that is not in the table, or 0. + +\ ( node -- port | 0 ) the address of the port that leads toward the node +: (PORT-FOR) + (ROUTE#) a! @ if NONE -1 + (ROUTES) a! + FOR dup @+ xor if HIT drop @+ drop NEXT + 0 + NONE: drop drop (ROUTE-DEFAULT) a! @ ; + HIT: drop drop @+ pop drop ; + +\ ( type -- ) words 1 to 5 of a message this node sends: from, type, and +\ the three that are carried and not used yet. Its caller has put B at the +\ port and sent word 0, whom it is to, and sends the length and the text. +\ Each write waits for the neighbour to take it. : (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 + 0 !b 0 !b 0 !b ; \ heat and TTL, ACL tag, sequence -\ ( -- ) send what has been printed: its length, then its characters, four -\ to a word, the first lowest +\ ( -- ) send what has been printed, to where (PRINT-TO) says, by the port +\ (PRINT-PORT): its length, then its characters, four to a word, the first +\ lowest. quit.v4 sets those two when text for this node arrives. : (FLUSH-OUT) (OUT^) a! @ (OUT) xor if NONE drop + (PRINT-PORT) a! @ b! (PRINT-TO) a! @ !b 2 (HDR) (OUT^) a! @ (OUT) - dup !b 3 + 2/ 2/ -1 + (OUT) a! diff --git a/v4/capsule/quit.v4 b/v4/capsule/quit.v4 index 3ae961d1..c835f0b8 100644 --- a/v4/capsule/quit.v4 +++ b/v4/capsule/quit.v4 @@ -65,6 +65,7 @@ macro R-CLEAR RSTACK-DEPTH b! a !b endmacro : (FINISH) ( s -- ) (LINE-STATUS) b! dup !b (FLUSH-OUT) + (DONE-PORT) a! @ b! (MSG)+1 a! @ !b \ to whoever sent the text 3 (HDR) 4 !b !b \ a message of type 3, four characters long: how it ended jump (IDLE) @@ -84,8 +85,8 @@ macro R-CLEAR RSTACK-DEPTH b! a !b endmacro \ 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. +\ is done as a line was, and (FINISH) reports how it ended. A message for +\ another node is passed on, (PASS-ON). : (IDLE) (PORT)+8 b! @b (MSG) a! !+ \ to, from any port (PORT)+9 b! @b (PORT) + dup b! \ B: the port it came on @@ -103,10 +104,32 @@ macro R-CLEAR RSTACK-DEPTH b! a !b endmacro 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) + (MSG) a! @ (ME) a! @ xor if MINE drop jump (PASS-ON) MINE: drop - (MSG)+2 a! @ -1 + if TEXT drop jump (IDLE) - TEXT: drop jump (LINE) + (MSG)+2 a! @ -1 + if TEXT drop jump (IDLE) \ for this node and not text: let go + TEXT: drop + (MSG)+1 a! @ (PORT-FOR) if D0 jump D1 \ the way back to whoever sent it: + D0: drop (REPLY) a! @ \ the port it came on, if no other is known + D1: (DONE-PORT) a! ! + (CONSOLE) a! @ if P0 jump P1 \ where what it prints goes: the console, + P0: drop (MSG)+1 a! @ \ or whoever sent it + P1: dup (PRINT-TO) a! ! + (PORT-FOR) if Q0 jump Q1 + Q0: drop (REPLY) a! @ + Q1: (PRINT-PORT) a! ! + jump (LINE) + +\ ( -- ) A MESSAGE FOR ANOTHER NODE is passed on (MESH.md section 7): all +\ of it, as it came, to the port that leads toward that node. With no way +\ known it is let go, and (LOST) counts it. +: (PASS-ON) + (MSG) a! @ (PORT-FOR) if NOWAY + b! (MSG) a! 6 FOR @+ !b UNEXT \ its seven words + (MSG)+6 a! @ 3 + 2/ 2/ if SENT + -1 + TIB 2/ 2/ a! FOR @+ !b UNEXT \ and its text + jump (IDLE) + SENT: drop jump (IDLE) + NOWAY: drop (LOST) a! @ 1 + ! jump (IDLE) \ ( -- ) 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 @@ -121,6 +144,43 @@ macro R-CLEAR RSTACK-DEPTH b! a !b endmacro drop 2 jump (DONE) GOOD: drop 1 jump (DONE) +\ ---- the node among others (MESH.md sections 6 and 7) --------------------------- +\ Not FORTH-79 and not in v3: v3's VMs are sent to through the kernel. + +\ ( node port -- ) the port, by its number, leads toward that node +header ROUTE +: ROUTE + (ROUTE#) a! @ -16 + if FULL drop + (PORT) + (ROUTE#) a! @ 2* (ROUTES) + a! + push !+ pop !+ + (ROUTE#) a! @ 1 + ! ; + FULL: drop drop drop NODE-ERROR b! 12 !b ; + +\ ( port -- ) the port, by its number, leads toward every node not told of +header DEFAULT-ROUTE +: DEFAULT-ROUTE (PORT) + (ROUTE-DEFAULT) a! ! ; + +\ ( -- ) forget every way: for when the wiring has changed +header NO-ROUTES +: NO-ROUTES 0 (ROUTE#) a! ! 0 (ROUTE-DEFAULT) a! ! ; + +\ ( baddr u node -- ) send the node u characters of text to interpret. It +\ is on its way when SEND returns; what it prints there goes to that node's +\ console. With no way to the node it is error 12. The write waits for the +\ neighbour to read: a neighbour that is itself waiting to write to this +\ node will wait for ever, and so will this one. +header SEND +: SEND + dup (PORT-FOR) if NOWAY + b! !b \ to + 1 (HDR) + dup !b \ length + 3 + 2/ 2/ if NONE -1 + + FOR dup C@ over 1 + C@ 8* + over 2 + C@ 8* 8* + over 3 + C@ 8* 8* 8* + !b 4 + NEXT + drop ; + NONE: drop drop ; + NOWAY: drop drop drop drop NODE-ERROR b! 12 !b ; + \ FORTH-79: clear the return stack, set execution mode, return control to \ the terminal; no message is given. The data stack is left as it is. \ NODE-ERROR, by name: how a definition written in FORTH raises an error. @@ -129,6 +189,9 @@ macro R-CLEAR RSTACK-DEPTH b! a !b endmacro \ its own) and the line ends with ERROR. The codes are listed in core.v4. header NODE-ERROR inline : NODE-ERROR' NODE-ERROR ; header (CATCH) inline : (CATCH)' (CATCH) ; +header (ME) inline : (ME)' (ME) ; +header (CONSOLE) inline : (CONSOLE)' (CONSOLE) ; +header (LOST) inline : (LOST)' (LOST) ; header (WORD-DEFINED) inline : (WORD-DEFINED)' (WORD-DEFINED) ; header (WORD-FORGOTTEN) inline : (WORD-FORGOTTEN)' (WORD-FORGOTTEN) ; header (EMIT-HOOK) inline : (EMIT-HOOK)' (EMIT-HOOK) ; diff --git a/v4/tests/host_map.h b/v4/tests/host_map.h index 78f5354e..1629c02c 100644 --- a/v4/tests/host_map.h +++ b/v4/tests/host_map.h @@ -69,6 +69,15 @@ #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 CONSOLE (BUF0_W - 16) /* the node what this one prints is sent to; 0: whoever sent the text being served */ +#define ROUTE_COUNT (BUF0_W - 17) /* how many entries the table of ways holds */ +#define ROUTE_DEFAULT (BUF0_W - 18) /* the port address for a node not in the table, or 0: there is none */ +#define LOST (BUF0_W - 19) /* how many messages have been let go for want of a way */ +#define PRINT_TO (BUF0_W - 20) /* where what the text being served prints is to go: the node, */ +#define PRINT_PORT (BUF0_W - 21) /* and the port address that leads there */ +#define DONE_PORT (BUF0_W - 22) /* the port address that leads back to whoever sent the text being served */ +#define ROUTES (BUF0_W - 96) /* the table of ways: 16 entries of a node and the port address that leads to it */ +#define ROUTE_MAX 16 #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 */ @@ -156,6 +165,14 @@ static int host_load(v4_text *tx, v4_node *n, const char *const *files, unsigned v4_text_constant(tx, "(LINE-STATUS)", LINE_STATUS); v4_text_constant(tx, "(PORT)", PORT); v4_text_constant(tx, "(ME)", ME); + v4_text_constant(tx, "(CONSOLE)", CONSOLE); + v4_text_constant(tx, "(ROUTE#)", ROUTE_COUNT); + v4_text_constant(tx, "(ROUTE-DEFAULT)", ROUTE_DEFAULT); + v4_text_constant(tx, "(LOST)", LOST); + v4_text_constant(tx, "(PRINT-TO)", PRINT_TO); + v4_text_constant(tx, "(PRINT-PORT)", PRINT_PORT); + v4_text_constant(tx, "(DONE-PORT)", DONE_PORT); + v4_text_constant(tx, "(ROUTES)", ROUTES); v4_text_constant(tx, "(OUT^)", OUT_PTR); v4_text_constant(tx, "(REPLY)", REPLY); v4_text_constant(tx, "(MSG)", MSG); diff --git a/v4/tests/test_host_mesh.c b/v4/tests/test_host_mesh.c new file mode 100644 index 00000000..e0e53a0b --- /dev/null +++ b/v4/tests/test_host_mesh.c @@ -0,0 +1,218 @@ +/* test_host_mesh.c -- StarForth nodes that talk: a console wired to one + * node, and two more in a row behind it. docs/v4.0.0/MESH.md sections 6 + * and 7, steps 3 and 4. + * + * console --1 [10] 2--2 [11] 3--2 [12] + * + * Each node is the nucleus (v4/capsule/ *.v4) and nothing else. They start + * alike, numbered 0 and knowing no way anywhere; everything they come to + * know they are told by text sent from the console, as whoever wires a node + * tells it. The console is a device on a port and speaks messages + * (v4/include/v4/message.h). + */ +#include "v4/fabric.h" +#include "v4/message.h" +#include "v4/text.h" +#include +#include + +#include "host_map.h" + +static int failures = 0, checks = 0; +#define CHECK(c,...) do{checks++; if(!(c)){failures++; printf("FAIL %s:%d: ",__FILE__,__LINE__); printf(__VA_ARGS__); printf("\n");}}while(0) + +static v4_text tx; +static v4_node nucleus; /* one node with the nucleus in it: what every node here starts as */ +static v4_cell w_idle, w_fault; +static v4_fabric_node pool[3]; +static v4_place places[3]; +static v4_fabric f; + +/* ---- the console: a device on a port ---- */ +#define CONSOLE_ID 1 +static v4_message going, coming; +static unsigned going_at; +static char printed[8192]; /* what has come back since the console last sent */ +static unsigned printed_len; +static v4_cell printed_from; /* which node the last of it came from */ +static int ended; /* how many messages of how text ended have come, */ +static v4_cell ended_from, ended_how; /* and the last of them */ + +static int console_give(void *self, v4_cell *value) +{ + (void)self; + if (going_at >= going.count) return 0; + *value = going.word[going_at++]; + return 1; +} +static int console_take(void *self, v4_cell value) +{ + (void)self; + if (v4_message_word(&coming, value)) { + if (v4_message_type(&coming) == V4_MSG_OUTPUT) { + unsigned i, chars = v4_message_length(&coming); + for (i = 0; i < chars && printed_len + 1 < sizeof printed; i++) printed[printed_len++] = v4_message_char(&coming, i); + printed[printed_len] = 0; + printed_from = v4_message_from(&coming); + } else if (v4_message_type(&coming) == V4_MSG_DONE) { + ended++; + ended_from = v4_message_from(&coming); + ended_how = coming.word[V4_MSG_HEADER]; + } + coming.count = 0; + } + return 1; +} +static const v4_device console = { console_take, console_give, 0 }; + +static int is_empty(const char *s) { return s[0] == 0; } + +/* Send text to a node and let everything that follows from it happen. */ +static const char *tell(v4_cell node, const char *text) +{ + unsigned steps = 0; + printed_len = 0; printed[0] = 0; printed_from = -1; + ended = 0; ended_from = -1; ended_how = -1; + if (!v4_message_text(&going, node, CONSOLE_ID, V4_MSG_TEXT, text, (unsigned)strlen(text))) return "(too long)"; + going_at = 0; + while (steps < 20000000 && v4_fabric_step(&f) != 0) steps++; + if (steps >= 20000000) return "(still running)"; + return printed; +} + +/* A StarForth node in the fabric: born, then given the nucleus and the + * registers the nucleus expects, waiting for a message. */ +static unsigned starforth_node(unsigned k) +{ + int id = v4_fabric_add(&f, &pool[k], PORT); + v4_node *n = &pool[k].n; + memcpy(n->mem, nucleus.mem, sizeof n->mem); + v4_node_stack_regs_attach(n, DSTACK_REG, RSTACK_REG); + v4_node_error_attach(n, NODE_ERROR); + v4_node_fault_attach(n, w_fault); + n->p = w_idle; + return (unsigned)id; +} + +static int waiting(unsigned id) +{ + const v4_node *n = &v4_fabric_node_at(&f, id)->n; + return n->reading && !n->given && n->read_port == V4_PORT_ANY; +} + +int main(void) +{ + unsigned hera, mid, far, i; + + printf("v4 mesh tests: V4_CELL_BITS=%d, V4_NODE_WORDS=%u\n", V4_CELL_BITS, (unsigned)V4_NODE_WORDS); + { + 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" }; + CHECK(host_load(&tx, &nucleus, files, 14), "the nucleus assembles"); + } + CHECK(v4_text_finish(&tx), "everything is defined: %s", v4_text_error(&tx)); + if (failures) { printf(" %d checks, %d failures\n", checks, failures); return 1; } + w_idle = v4_text_word(&tx, "(IDLE)"); + w_fault = v4_text_word(&tx, "(FAULTS)"); + nucleus.mem[DP] = DICT_W * 4; /* the variables, as at switch-on (tools/mkimage.c) */ + nucleus.mem[LATEST] = v4_text_latest(&tx); + nucleus.mem[CFP] = CFS_W; + nucleus.mem[BASE] = 10; + nucleus.mem[FENCE] = DICT_W; + nucleus.mem[BOOT_CELLS] = nucleus.mem[DP]; + nucleus.mem[BOOT_CELLS + 1] = nucleus.mem[LATEST]; + nucleus.mem[LOG_LEVEL] = 2; + nucleus.mem[CONTEXT] = LATEST; + nucleus.mem[CURRENT] = LATEST; + nucleus.mem[SRC] = TIB; + nucleus.mem[LINE_STATUS] = 1; + nucleus.mem[OUT_PTR] = OUT_W; + + v4_fabric_init(&f, places, 3); + hera = starforth_node(0); + mid = starforth_node(1); + far = starforth_node(2); + CHECK(v4_fabric_wire_device(&f, hera, 1, &console), "the console is wired to one node's port 1"); + CHECK(v4_fabric_wire(&f, hera, 2, mid, 2) && v4_fabric_wire(&f, mid, 3, far, 2), "and the three nodes in a row"); + going.count = 0; going_at = 0; + for (i = 0; i < 20; i++) (void)v4_fabric_step(&f); + CHECK(waiting(hera) && waiting(mid) && waiting(far), "all three wait at their ports"); + + /* ---- they are told who they are and the way to each other, by text ---- */ + CHECK(is_empty(tell(0, "10 (ME) ! 1 (CONSOLE) ! 1 1 ROUTE 0 2 ROUTE")) && ended == 1 && ended_how == V4_TEXT_COMPLETED && ended_from == 10, + "the node at the console takes text sent to 0, and is 10 from then on: %ld", (long)ended_from); + CHECK(is_empty(tell(0, "11 (ME) ! 1 (CONSOLE) ! 2 DEFAULT-ROUTE 0 3 ROUTE")) && ended == 1 && ended_from == 11 && ended_how == V4_TEXT_COMPLETED, + "text sent to 0 now passes through 10 to the next, which is 11 from then on: %ld", (long)ended_from); + CHECK(is_empty(tell(0, "12 (ME) ! 1 (CONSOLE) ! 2 DEFAULT-ROUTE")) && ended == 1 && ended_from == 12 && ended_how == V4_TEXT_COMPLETED, + "and then through both to the last, 12: %ld", (long)ended_from); + CHECK(is_empty(tell(10, "11 2 ROUTE 12 2 ROUTE")) && ended_from == 10 && is_empty(tell(11, "12 3 ROUTE")) && ended_from == 11, + "each is told the way to the others"); + + /* ---- they talk ---- */ + CHECK(strcmp(tell(10, "1 2 + ."), "3 ") == 0 && printed_from == 10 && ended_how == V4_TEXT_COMPLETED, "text for the node at the console is done there"); + CHECK(strcmp(tell(11, "20 22 + ."), "42 ") == 0 && printed_from == 11 && ended_from == 11, "text for the next node is done there, and what it prints comes back"); + CHECK(strcmp(tell(12, "7 8 * ."), "56 ") == 0 && printed_from == 12 && ended_from == 12 && ended_how == V4_TEXT_COMPLETED, + "text for the last passes through two nodes, and what it prints comes back through two: \"%s\" from %ld", printed, (long)printed_from); + CHECK(strcmp(tell(12, "NOSUCH"), "UNKNOWN WORD: 'NOSUCH'\n") == 0 && ended_from == 12 && ended_how == V4_TEXT_ERROR, "an error there is reported from there"); + CHECK(strcmp(tell(12, ": SQ DUP * ;"), "") == 0 && strcmp(tell(12, "9 SQ ."), "81 ") == 0 && strstr(tell(11, "9 SQ ."), "UNKNOWN WORD") != NULL, + "each node has its own dictionary: a word defined on one is not on another"); + { + const char *all = tell(12, "WORDS"); + CHECK(strlen(all) > 1000 && printed_from == 12 && ended == 1, "more than a message holds comes back in several: %u characters", (unsigned)strlen(all)); + } + { + static char line[1100]; + memset(line, ' ', 1024); + memcpy(line, "66 EMIT", 7); + memcpy(line + 1017, "67 EMIT", 7); + line[1024] = 0; + CHECK(strcmp(tell(12, line), "BC") == 0, "a message as long as a message may be is passed on whole: 1024 characters"); + } + + /* ---- one node sends to another ---- */ + CHECK(strcmp(tell(10, ": TELL S\" 65 EMIT 12 . \" 12 SEND ; TELL"), "A12 ") == 0 && printed_from == 12, + "text one node SENDs another is done there, and what that prints goes to its console: \"%s\" from %ld", printed, (long)printed_from); + CHECK(strstr(tell(10, ": NOWAY S\" 1\" 99 SEND ; NOWAY"), "Argument out of range") != NULL && ended_how == V4_TEXT_ERROR, + "SEND to a node there is no way to is an error"); + + /* ---- no way ---- */ + CHECK(is_empty(tell(99, "1 2 + .")) && ended == 0, "text for a node there is no way to: nothing comes back"); + CHECK(strcmp(tell(10, "(LOST) @ ."), "1 ") == 0, "and the node that could not pass it on has counted it"); + CHECK(strcmp(tell(11, "(LOST) @ ."), "0 ") == 0 && strcmp(tell(12, "(LOST) @ ."), "0 ") == 0, "the others have lost nothing"); + + /* ---- waiting ---- */ + { + v4_uheat_t c0 = pool[0].es.anticlock, c1 = pool[1].es.anticlock, c2 = pool[2].es.anticlock; + for (i = 0; i < 100; i++) (void)v4_fabric_step(&f); + CHECK(waiting(hera) && waiting(mid) && waiting(far), "with nothing to do, all three wait at their ports"); + CHECK(pool[0].es.anticlock == c0 && pool[1].es.anticlock == c1 && pool[2].es.anticlock == c2, "and execute nothing"); + } + + /* ---- the ways are forgotten and told again: the wiring has changed ---- */ + CHECK(v4_fabric_wire(&f, hera, 3, far, 3), "the far node is wired straight to the one at the console as well"); + CHECK(is_empty(tell(10, "NO-ROUTES 1 1 ROUTE 11 2 ROUTE 12 3 ROUTE")) && is_empty(tell(12, "NO-ROUTES 3 DEFAULT-ROUTE")), "and both are told"); + { + v4_uheat_t before = pool[1].es.anticlock; + CHECK(strcmp(tell(12, "5 5 + ."), "10 ") == 0 && pool[1].es.anticlock == before, "text for it no longer passes through the middle node, which executes nothing"); + } + + /* ---- WHAT DOES NOT WORK: two neighbours that write to each other at once ---- + * A write blocks until the neighbour reads, and a node that is writing + * is not reading. Here the far node sends text to the middle one and + * then goes to send word of how its own text ended, which goes by the + * middle one; the middle one does the text and goes to answer the far + * one. Each waits for the other to read, for ever. It is the same + * whenever messages go both ways on a wire at once, and it is because + * passing a message on is done here by the node's own programme + * (v4/capsule/quit.v4, (PASS-ON)), which cannot pass anything on while + * it waits to write. docs/v4.0.0/MESH.md, step 4. This check is here + * so that the fault is on record and is seen to go when it is put + * right. */ + CHECK(is_empty(tell(10, "NO-ROUTES 1 1 ROUTE 11 2 ROUTE 12 2 ROUTE")) && is_empty(tell(12, "NO-ROUTES 2 DEFAULT-ROUTE")), "the row of three again"); + (void)tell(12, ": HI S\" 72 EMIT\" 11 SEND ; HI"); + CHECK(pool[1].n.asking && pool[1].n.ask_port == 3 && pool[2].n.asking && pool[2].n.ask_port == 2, + "KNOWN FAULT: two neighbours each writing to the other wait for ever"); + + printf(" %d checks, %d failures\n", checks, failures); + return failures != 0; +}