From 06da5700bc35a617e51af410a537b1ff6eae8fee Mon Sep 17 00:00:00 2001 From: rajames Date: Tue, 13 Oct 2026 17:47:05 -0400 Subject: [PATCH] feat(v4.0.0): step 6e -- a node removed at any step leaves the rest at rest; written up test_host_mesh.c, 220 checks: three exchanges on the row of three -- text from the console for node 12 with what it prints and how it ended; node 11 SENDing node 12 text and waiting for its answer; a message node 12 has no way for and its NACK to node 10 -- are each played once for every engine step they take with node 11 removed at that step, and again with node 12: 17,642 removals at 64 bits. Every node left comes to rest asleep, blocked at no port and in no operation, and answers. What is typed is a word defined beforehand, so that the steps are the exchange's and not the dictionary being searched. Removed from the engine, nothing using them: v4_fabric_interrupt_error, a device's pending hook, v4_node_words_since_look, V4_ERROR_INTERRUPTED. MESH.md: 4.1's table has the addresses after the ports; 7a and 7b say what of them still holds; 7b.7's limit is closed; step 6e is written up. v4/README.md likewise. make -C v4 test and sanitize at both widths, hosted-check, lint. Three bare-metal boots with the typed session and a loop printing 400 numbers: logs/20261013-165124 (amd64), -165428 (aarch64), -165818 (riscv64). POST 538 of 538, word_count=317, dict_hash=0x0951d7e02e251554 on all six, and the three sessions are the same character for character. The boots were built with the working tree's uncommitted change to kernel/Makefile that adds the ISA to the kernel's version line; nothing else differs from this commit. The plan's final review is not done yet. Co-Authored-By: Claude Opus 5.5 --- docs/v4.0.0/MESH.md | 123 ++++++++- .../runs/doe-aarch64-20261013-165428.csv | 0 .../runs/doe-amd64-20261013-165124.csv | 0 .../runs/doe-riscv64-20261013-165818.csv | 0 .../amd64/qemu-amd64-20261013-165124.log | 217 +++++++++++++++ .../aarch64/qemu-aarch64-20261013-165428.log | 190 +++++++++++++ .../riscv64/qemu-riscv64-20261013-165818.log | 260 ++++++++++++++++++ v4/README.md | 26 +- v4/include/v4/fabric.h | 15 - v4/include/v4/image.h | 5 - v4/include/v4/node.h | 8 - v4/src/fabric.c | 24 -- v4/src/node.c | 11 +- v4/tests/test_fabric.c | 64 +---- v4/tests/test_host_depth.c | 2 +- v4/tests/test_host_mesh.c | 84 +++++- v4/tests/test_host_unit.c | 6 +- 17 files changed, 893 insertions(+), 142 deletions(-) create mode 100644 experiments/bare_metal/runs/doe-aarch64-20261013-165428.csv create mode 100644 experiments/bare_metal/runs/doe-amd64-20261013-165124.csv create mode 100644 experiments/bare_metal/runs/doe-riscv64-20261013-165818.csv create mode 100644 logs/20261013-165124/amd64/qemu-amd64-20261013-165124.log create mode 100644 logs/20261013-165428/aarch64/qemu-aarch64-20261013-165428.log create mode 100644 logs/20261013-165818/riscv64/qemu-riscv64-20261013-165818.log diff --git a/docs/v4.0.0/MESH.md b/docs/v4.0.0/MESH.md index 9f0745a9..ef71ba54 100644 --- a/docs/v4.0.0/MESH.md +++ b/docs/v4.0.0/MESH.md @@ -104,6 +104,19 @@ word address `base`: | `base` … `base + V4_PORTS − 1` | Port 0 … port `V4_PORTS − 1` | | `base + V4_PORTS` | Any port: a read here takes from whichever port has a neighbour writing | | `base + V4_PORTS + 1` | Which port the last read from "any" came from. Read only. | +| `base + V4_PORTS + 2` | Which ports have a neighbour waiting to write to this node, a bit to a port. Read only. (Section 7a.) | +| `base + V4_PORTS + 3` | Which have one waiting to read from it; and, in the bits above those, which have anything on them at all. Read only. (Section 7a.) | +| `base + V4_PORTS + 4` | Wire: the port that a whole-message operation is about (section 7d.3) | +| `base + V4_PORTS + 5` | A: a value the operation needs | +| `base + V4_PORTS + 6` | B: a second | +| `base + V4_PORTS + 7` | Do: the number of the operation; storing it does the operation | +| `base + V4_PORTS + 8` | How it went. Read only. | +| `base + V4_PORTS + 9` | Which wires have a message waiting, a bit to a port. Read only. | + +The first two rows after "which port" are for words written and read one at +a time; the six after them are for whole messages, which is how nodes talk +to each other since step 6e (section 7d). Words one at a time are still +how a newborn node is sent its nucleus and how a node asks its kernel. - **A write to a port blocks the node until the neighbour has read it.** Built 2026-10-05 for one port; the opcode after the write runs when the @@ -159,6 +172,12 @@ time passing for all of them at once. a word when the node reads, each able to say "not yet". The console, a disk, and the kernel that serves a node's requests (`ENGINE.md` 3.3) are devices. +- **The wires' queues** (step 6e, section 7d.2). Each wire between two + nodes, or a node and a device that speaks whole messages, has a queue of + messages each way, in memory the fabric's owner gives it + (`v4_fabric_queues`). A device puts and takes whole messages through the + fabric (`v4_fabric_device_put`, `v4_fabric_device_take`). The kernel's + port has none (7d.5). - **A step.** Every node that is awake and not blocked executes one instruction word. Then every write that has a reader waiting on the other end of its wire is handed over, and both nodes are unblocked. That @@ -240,9 +259,17 @@ and these tables. Nothing else changes. ## 7a. Two neighbours writing to each other (ruled 2026-10-06) -*(The wait of section 7c was to replace the lower-number rule and the -looking again of this section. It was backed out on 2026-10-08; this -section is what the code does.)* +*(**A record since step 6e, 2026-10-13.** Messages now wait on the wires +(section 7d) and a node writes none a word at a time, so two neighbours +can no longer block each other and nothing below is needed to prevent it. +What does not hold any more: looking before writing and `(GATE)`; the +lower-number rule; the ring of messages waiting, `(MQ)`. What still +holds: the two status addresses are in the engine and tested there +(`v4/tests/test_fabric.c`), though the nucleus does not use them; +`NEIGHBOUR` stays, because it is how a node knows who its centre is and +so whose GONE to believe (7b.4); and `(LOST)` still counts what a node +lets go. The cost at the end of this section is now 7d.6's: a message for +a full wire is refused at once and its sender told.)* The fault is in section 10, step 4. **Ruled: a node writes only to a neighbour that is already reading; a node keeps the messages it takes in @@ -299,6 +326,20 @@ kernel-Hermes's work in v3 and is not decided for the mesh. ## 7b. Refusals and waits (ruled 2026-10-07) +*(**What of this section holds since step 6e, 2026-10-13.** It holds: the +two messages, NACK and GONE (7b.2); that a message is passed on by at +most 16 nodes, and that there is no NACK for a NACK (7b.3); what a node +does when it is sent a NACK or a GONE, and the endings of `AWAIT` in +errors 19, 20 and 21 (7b.4); Hera's table and `KILL` (7b.5); and a line +from the console ending an `AWAIT` (7b.6). It does not hold: a node no +longer notes a NACK it owes and pays it later, because it keeps nothing: +the NACK is put on the wire at once or counted in `(LOST)` (7d.4); no +room is kept in a node for NACK and GONE, there being no queue in a node; +what ends a wait is looked for on the wires, not among messages a node +has taken in; and the blocked write of 7b.6 cannot happen. The limit of +7b.7, that a stuck node holds up its neighbours, is closed: 7d.6 says +what the limits are now.)* + **The rule of this section (reworded 2026-10-07, after the review of step 6c): a node is never left waiting, or going round, on a node that is gone; and a wait on a node that is alive and stuck is ended by Hera's @@ -430,6 +471,11 @@ Two types, beside text (1), output (2) and done (3): it: it gives that message up and goes on to read the line. Only on the first word, so that half a message is never left on a wire (`v4_fabric_interrupt_error`, `v4/include/v4/fabric.h`). + *(Removed at step 6e, 2026-10-13: no node writes a message a word at a + time, so none is blocked writing one. `v4_fabric_interrupt_error`, a + device's `pending` and `v4_node_words_since_look` are gone from the + engine. Hera can be typed to whatever any node is doing: + `v4/tests/test_host_unit.c`.)* - **A node waiting to write to a neighbour that has been removed** is told: the word that says which neighbours are reading also says which ports have anything on them at all, and with nothing there the wait ends in @@ -437,6 +483,12 @@ Two types, beside text (1), output (2) and done (3): ### 7b.7 Limits +*(**Closed at step 6e, 2026-10-13**, but for the last of these, which +stands. A node that is stuck holds up no other node, and neither does +one that is asleep: what is for it waits on its wire. A node that waits +for an answer passes on what is for other nodes while it waits. What a +stuck node costs now is in section 7d.6.)* + - The room kept for NACK and GONE is finite, and so is the list of NACKs a node owes. Past them one is dropped and counted in `(LOST)`. A sender left waiting by that is ended as any stuck wait is: by Hera, or from the @@ -1612,7 +1664,70 @@ Each is tested, committed and pushed before the next. and `-06*` are of the wait as built and are kept as its record. **6e. Messages on the wire (section 7d).** Ruled 2026-10-08: the - second attempt at 6d. Not built. + second attempt at 6d. **Built and verified 2026-10-13; its final + review is still to come** (last item below). + - *The wire* (`v4/include/v4/wire.h`, `v4/src/wire.c`, `d5cd6460`, + `83694b18`): a queue of whole messages, one way; put, look, take, + move and drop, each all or nothing. `v4/tests/test_wire.c`, 112 + checks. + - *The engine* (`v4/src/node.c`, `v4/src/fabric.c`): the six addresses + of 7d.3 and the ten operations; the wires' queues given by the + fabric's owner; a device that puts and takes whole messages; the + kernel's port, which has no queue. `v4/tests/test_fabric.c`, 306 + checks. + - *The nucleus* (`v4/capsule/core.v4`, `quit.v4`, `b1d09af0`): `(DO)`, + `(WAY)`, `(ROOM?)`, `(SERVE)`, `(REFUSE)`; `(IDLE)`, `SEND`, `AWAIT`, + printing and how text ended, all on the wires. `(MQ)`, `(GATE)`, `(OWE)` and + `(PAY)` are gone. + - *The hosts* (`v4/system/boot.c`, which both products' lone node is + run by, and the tests' consoles) speak whole messages. + - *Two reviews of the nucleus, each mended* (`6a7d0aa2`, `f1419e73`): + 7d.3 and 7d.4 carry what they changed, marked "fix round". + - *A node removed at every step* (acceptance 6): + `v4/tests/test_host_mesh.c`, 220 checks. Three exchanges on the row + of three -- text from the console for node 12, what it prints and how + it ended; node 11 `SEND`ing node 12 text and waiting for its answer; + a message node 12 has no way for, and its NACK to node 10 -- are each + played whole, and then once for every engine step they take (3,579, + 4,214 and 1,025 at 64 bits) with node 11 removed at that step, and + again with node 12: 17,642 removals. After each, every node left came + to rest asleep, blocked at no port and in no operation, and answered + `1 2 + .`; with node 11 gone, node 12 is wired to node 10 first, as + whoever removed it would, so that it can be asked. None failed. The + test was shown to fail, in 4,376 of them, with the engine changed so + that a wait for room on a cut wire never ends. + *What is typed in that test is a word defined beforehand, not a line + of several words:* a line is mostly the dictionary being searched, + tens of thousands of steps in which no message moves, and each would + be a removal played to its end. The first exchange as the line + `7 8 * .` takes 38,234 steps; removal was tried at its first 300 and + none failed, and it is not in the suite. + - *Removed from the engine, nothing using them:* + `v4_fabric_interrupt_error`, a device's `pending`, + `v4_node_words_since_look`, and `V4_ERROR_INTERRUPTED` (the nucleus + raises error 21 itself). A device's `take` and `give`, and the two + status addresses of 7a, stay: the kernel's port and the engine's own + tests use them. + - *Other tests.* `v4/tests/test_host_unit.c`, 81 checks (Hera and + four); `v4/tests/test_host_depth.c`, 397 checks (acceptance 7 on the + mesh); `v4/tools/depthsweep.py`, 230 runs on the hosted product. + - *Verified.* `make -C v4 test` and `sanitize` at both widths, + `hosted-check`, and `mkcapsule --lint capsules/`: no failures. Three + bare-metal boots, `logs/20261013-165124` (amd64), `-165428` + (aarch64), `-165818` (riscv64), each typing the session of step 6d's + last boots and a loop that prints 400 numbers: 29 values on a line + ("Stack overflow"); `WORDS` with 26 on the stack; `AWAIT` with 27, + and `5 AWAIT` ended by the next line ("Interrupted"); all 400 + numbers, in order. On all six systems: POST 538 of 538, + `word_count=317`, `dict_hash=0x0951d7e02e251554`; and what the three + boots answered at the prompt is the same, character for character. + - *Seen in the older logs, and not a fault of the node.* In the boots + of 2026-10-08 `WORDS` shows a character twice here and there on + amd64 and riscv64 (`LOG-INFFO-STR`, `QQ.-`). The script that typed + those sessions read QEMU's serial socket only between lines; with + the socket read as it comes, as these three were, there is none. + - **Not done:** the final review of the whole step by a fresh + reviewer (the plan's last step). 7. **A second unit; scaling while running; sleep, wake and kill by command.** diff --git a/experiments/bare_metal/runs/doe-aarch64-20261013-165428.csv b/experiments/bare_metal/runs/doe-aarch64-20261013-165428.csv new file mode 100644 index 00000000..e69de29b diff --git a/experiments/bare_metal/runs/doe-amd64-20261013-165124.csv b/experiments/bare_metal/runs/doe-amd64-20261013-165124.csv new file mode 100644 index 00000000..e69de29b diff --git a/experiments/bare_metal/runs/doe-riscv64-20261013-165818.csv b/experiments/bare_metal/runs/doe-riscv64-20261013-165818.csv new file mode 100644 index 00000000..e69de29b diff --git a/logs/20261013-165124/amd64/qemu-amd64-20261013-165124.log b/logs/20261013-165124/amd64/qemu-amd64-20261013-165124.log new file mode 100644 index 00000000..195d2616 --- /dev/null +++ b/logs/20261013-165124/amd64/qemu-amd64-20261013-165124.log @@ -0,0 +1,217 @@ +[=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 amd64 +Architecture: amd64 +Build: Oct 13 2026 16:50:56 + +UEFI BootServices: EXITED + +=== StarKernel Boot Information === +Memory map entries: 135 +Total memory: 1023 MB +Usable memory: 966 MB +=================================== + +PMM initialized. +PMM statistics: + Total pages: 248737 + Free pages : 247214 + Used pages : 1523 + Total MB : 971 + Free MB : 965 + 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=2116499919 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=1017498109, tick_hz=100, initial_count=10174981 +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=0x4b56120b672e75bc capsule_hash=0x4b56120b672e75bc words=311 +V4: capsule v4:forth79.4th signature: missing (unsigned) +PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x65daab1b670a4383 +PARITY:V4_POST tests=538 pass=538 fail=0 +PARITY:V4_SYSTEM word_count=317 dict_hash=0x0951d7e02e251554 +PARITY:OK +POST: PASSED +[HADES][INFO ] [KRELTSC: 0] blk: raw device LBN 2048..3071 (1024 blocks) +PCI: init... +PCI: ECAM mapped (amd64) +virtio-blk: found device +[HADES][INFO ] [KRELTSC: 88227636] blk: disk 'StarForth Volume' v2 LBN 3072..789009 (785938 user b +Artemis: virtio-blk attached +ok> : SQ DUP * ; + ok +ok> 7 SQ . 3 4 U* . . +49 0 12 ok +ok> T{ +UNKNOWN WORD: 'T{' + ERROR +ok> RS1 +UNKNOWN WORD: 'RS1' + ERROR +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> 1 BLOCK C@ . 2047 BLOCK C@ . +0 0 ok +ok> 2100 BLOCK 1024 BLANK 65 2100 BLOCK C! UPDATE SAVE-BUFFERS EMPTY-BUFFERS 2100 BLOCK C@ . +65 ok +ok> 3072 BLOCK C@ . +0 ok +ok> 3072 BLOCK DROP UPDATE SAVE-BUFFERS +Storage refused + ERROR +ok> 9999999 BLOCK +Block out of range + ERROR +ok> 5 7 PORT! +No one on that port + ERROR +ok> 1 2 + . +3 ok +ok> 5 AWAIT +7 8 * . +Interrupted + ERROR +ok> 56 ok +ok> : N4 400 0 DO I . LOOP ; + ok +ok> N4 +0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 ok +ok> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 +Stack overflow + ERROR +ok> 3 4 + . +7 ok +ok> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 + ok +ok> WORDS +N4 ASK9 U/MOD U* (UD) (NB) (BITS) BYE ACL-WORD-ID ACL-HEAT@ ACL-INIT-PRIMITIVES +ACL-INHERIT ACL-ALLOW! ACL-TTL! ACL-MODE! ACL-PIN ACL-PINNED? ACL-ALLOW@ +ACL-TTL@ ACL-MODE@ ACL-HOOK LOG-DEBUG" LOG-TEST" LOG-INFO" LOG-WARN" +LOG-ERROR" (LOG") LOG-DEBUG-STR LOG-TEST-STR LOG-INFO-STR LOG-WARN-STR +LOG-ERROR-STR LOG-LEVEL! LOG-LEVEL@ LOG-DEBUG LOG-TEST LOG-INFO +LOG-WARN LOG-ERROR THRU --> LOAD LIST EMPTY-BUFFERS FLUSH SAVE-BUFFERS +UPDATE BLOCK BUFFER BLK SCR Q.PRINT Q.COS Q.SIN Q.LOG Q.SQRT Q.EXP +Q./ Q.* Q.MIN Q.MAX Q.0= Q.> Q.< Q.= Q.NEG Q.ABS Q.- Q.+ Q.SCALE +Q.0 Q.1 Q.TO-INT Q.FROM-INT DEFER@ IS DEFER COLD WARM PAGE VERSION +79-STANDARD FORGET VLIST WORDS ORDER VOCABULARY DEFINITIONS FORTH +CURRENT CONTEXT FENCE SKIP SCAN SEARCH COMPARE -TRAILING BLANK ERASE +FILL MOVE CMOVE> ?TERMINAL DMIN DMAX D< M- M+ D2/ D2* D= D0< D0= +DABS D- RSHIFT LSHIFT WITHIN MIN MAX ABS U> U< >= <= <> 0> 0<> -! +2! 2@ INVERT FALSE TRUE NOP 2R@ 2R> 2>R 2ROT 2OVER 2SWAP DUMP .S +? D. D.R U. U.R . .R OCTAL HEX DECIMAL SPACES #> #S # SIGN HOLD +<# STATE PAD BASE SPAN >IN TIB BL > < = NOT 0< 0= OR XOR AND M/MOD +*/ */MOD MOD / /MOD M* S>D 2/ 2* 2- 2+ 1- 1+ NEGATE * - + CELLS ++! ! @ UNLOOP LEAVE J I R@ R> >R ROLL PICK DEPTH 2DROP 2DUP ?DUP +-ROT ROT SWAP OVER DROP DUP S" (S") ABORT" (ABORT") ." (.") ABORT +QUIT (WORD-FORGOTTEN) (WORD-DEFINED) (REFUSED) (LOST) (CONSOLE) +(ME) NODE-ERROR (SEAL) PORT! AWAIT SEND-ON SEND NO-ROUTES GONE NO-ROUTE +DEFAULT-ROUTE NEIGHBOUR ROUTE +LOOP LOOP ?DO DO ENDCASE ENDOF OF +CASE REPEAT WHILE AGAIN UNTIL BEGIN THEN ELSE IF DOES> CONSTANT +VARIABLE CREATE [COMPILE] COMPILE IMMEDIATE EXIT KERNEL-WORD ; : +[LITERAL] ['] ' LITERAL ] [ INTERPRET EXECUTE FIND HIDDEN SMUDGE +TRAVERSE >BODY PFA CFA NAME> NFA >NAME LINK> LFA >LINK LATEST 2, +C, , ALLOT ALIGN HERE \ ( NUMBER CONVERT ENCLOSE WORD QUERY EXPECT +SOURCE TYPE COUNT SPACE CR KEY EMIT CMOVE C! C@ DNEGATE D+ UM* + ok +ok> DEPTH . +26 ok +ok> : AW 5 AWAIT ; + ok +ok> 1 + ok +ok> AW +Stack overflow + ERROR +ok> 4321 . +4321 ok +ok> HERE . +8326 ok +ok> BYE +BYE: cold restart diff --git a/logs/20261013-165428/aarch64/qemu-aarch64-20261013-165428.log b/logs/20261013-165428/aarch64/qemu-aarch64-20261013-165428.log new file mode 100644 index 00000000..6c873953 --- /dev/null +++ b/logs/20261013-165428/aarch64/qemu-aarch64-20261013-165428.log @@ -0,0 +1,190 @@ +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 aarch64 +Architecture: aarch64 +Build: Oct 13 2026 16:54:01 + +UEFI BootServices: EXITED + +=== StarKernel Boot Information === +Memory map entries: 108 +Total memory: 4093 MB +Usable memory: 4054 MB +=================================== + +PMM initialized. +PMM statistics: + Total pages: 1039347 + Free pages : 1037936 + Used pages : 1411 + Total MB : 4059 + Free MB : 4054 + 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=0x4b56120b672e75bc capsule_hash=0x4b56120b672e75bc words=311 +V4: capsule v4:forth79.4th signature: missing (unsigned) +PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x65daab1b670a4383 +PARITY:V4_POST tests=538 pass=538 fail=0 +PARITY:V4_SYSTEM word_count=317 dict_hash=0x0951d7e02e251554 +PARITY:OK +POST: PASSED +[HADES][INFO ] [KRELTSC: 0] blk: raw device LBN 2048..3071 (1024 blocks) +PCI: init... +virtio-blk: found device +[HADES][INFO ] [KRELTSC: 1502483] blk: disk 'StarForth Volume' v2 LBN 3072..789009 (785938 user b +Artemis: virtio-blk attached +ok> : SQ DUP * ; + ok +ok> 7 SQ . 3 4 U* . . +49 0 12 ok +ok> T{ +UNKNOWN WORD: 'T{' + ERROR +ok> RS1 +UNKNOWN WORD: 'RS1' + ERROR +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> 1 BLOCK C@ . 2047 BLOCK C@ . +0 0 ok +ok> 2100 BLOCK 1024 BLANK 65 2100 BLOCK C! UPDATE SAVE-BUFFERS EMPTY-BUFFERS 2100 BLOCK C@ . +65 ok +ok> 3072 BLOCK C@ . +0 ok +ok> 3072 BLOCK DROP UPDATE SAVE-BUFFERS +Storage refused + ERROR +ok> 9999999 BLOCK +Block out of range + ERROR +ok> 5 7 PORT! +No one on that port + ERROR +ok> 1 2 + . +3 ok +ok> 5 AWAIT +7 8 * . +Interrupted + ERROR +ok> 56 ok +ok> : N4 400 0 DO I . LOOP ; + ok +ok> N4 +0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 ok +ok> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 +Stack overflow + ERROR +ok> 3 4 + . +7 ok +ok> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 + ok +ok> WORDS +N4 ASK9 U/MOD U* (UD) (NB) (BITS) BYE ACL-WORD-ID ACL-HEAT@ ACL-INIT-PRIMITIVES +ACL-INHERIT ACL-ALLOW! ACL-TTL! ACL-MODE! ACL-PIN ACL-PINNED? ACL-ALLOW@ +ACL-TTL@ ACL-MODE@ ACL-HOOK LOG-DEBUG" LOG-TEST" LOG-INFO" LOG-WARN" +LOG-ERROR" (LOG") LOG-DEBUG-STR LOG-TEST-STR LOG-INFO-STR LOG-WARN-STR +LOG-ERROR-STR LOG-LEVEL! LOG-LEVEL@ LOG-DEBUG LOG-TEST LOG-INFO +LOG-WARN LOG-ERROR THRU --> LOAD LIST EMPTY-BUFFERS FLUSH SAVE-BUFFERS +UPDATE BLOCK BUFFER BLK SCR Q.PRINT Q.COS Q.SIN Q.LOG Q.SQRT Q.EXP +Q./ Q.* Q.MIN Q.MAX Q.0= Q.> Q.< Q.= Q.NEG Q.ABS Q.- Q.+ Q.SCALE +Q.0 Q.1 Q.TO-INT Q.FROM-INT DEFER@ IS DEFER COLD WARM PAGE VERSION +79-STANDARD FORGET VLIST WORDS ORDER VOCABULARY DEFINITIONS FORTH +CURRENT CONTEXT FENCE SKIP SCAN SEARCH COMPARE -TRAILING BLANK ERASE +FILL MOVE CMOVE> ?TERMINAL DMIN DMAX D< M- M+ D2/ D2* D= D0< D0= +DABS D- RSHIFT LSHIFT WITHIN MIN MAX ABS U> U< >= <= <> 0> 0<> -! +2! 2@ INVERT FALSE TRUE NOP 2R@ 2R> 2>R 2ROT 2OVER 2SWAP DUMP .S +? D. D.R U. U.R . .R OCTAL HEX DECIMAL SPACES #> #S # SIGN HOLD +<# STATE PAD BASE SPAN >IN TIB BL > < = NOT 0< 0= OR XOR AND M/MOD +*/ */MOD MOD / /MOD M* S>D 2/ 2* 2- 2+ 1- 1+ NEGATE * - + CELLS ++! ! @ UNLOOP LEAVE J I R@ R> >R ROLL PICK DEPTH 2DROP 2DUP ?DUP +-ROT ROT SWAP OVER DROP DUP S" (S") ABORT" (ABORT") ." (.") ABORT +QUIT (WORD-FORGOTTEN) (WORD-DEFINED) (REFUSED) (LOST) (CONSOLE) +(ME) NODE-ERROR (SEAL) PORT! AWAIT SEND-ON SEND NO-ROUTES GONE NO-ROUTE +DEFAULT-ROUTE NEIGHBOUR ROUTE +LOOP LOOP ?DO DO ENDCASE ENDOF OF +CASE REPEAT WHILE AGAIN UNTIL BEGIN THEN ELSE IF DOES> CONSTANT +VARIABLE CREATE [COMPILE] COMPILE IMMEDIATE EXIT KERNEL-WORD ; : +[LITERAL] ['] ' LITERAL ] [ INTERPRET EXECUTE FIND HIDDEN SMUDGE +TRAVERSE >BODY PFA CFA NAME> NFA >NAME LINK> LFA >LINK LATEST 2, +C, , ALLOT ALIGN HERE \ ( NUMBER CONVERT ENCLOSE WORD QUERY EXPECT +SOURCE TYPE COUNT SPACE CR KEY EMIT CMOVE C! C@ DNEGATE D+ UM* + ok +ok> DEPTH . +26 ok +ok> : AW 5 AWAIT ; + ok +ok> 1 + ok +ok> AW +Stack overflow + ERROR +ok> 4321 . +4321 ok +ok> HERE . +8326 ok +ok> BYE +BYE: cold restart diff --git a/logs/20261013-165818/riscv64/qemu-riscv64-20261013-165818.log b/logs/20261013-165818/riscv64/qemu-riscv64-20261013-165818.log new file mode 100644 index 00000000..c35a22a2 --- /dev/null +++ b/logs/20261013-165818/riscv64/qemu-riscv64-20261013-165818.log @@ -0,0 +1,260 @@ + +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 = 0x00000000bdc95aaa +riscv64: satp cleared -- Bare mode, explicit (item 4.3.5a) + + + _____ _ _ __ _ + / ____| | | |/ / | | + | (___ | |_ __ _ _ __| ' / ___ _ __ _ __ ___| | + \___ \| __/ _` | '__| < / _ \ '__| '_ \ / _ \ | + ____) | || (_| | | | . \ __/ | | | | | __/ | + |_____/ \__\__,_|_| |_|\_\___|_| |_| |_|\___|_| + +LithosAnanke v2.1.0 riscv64 +Architecture: riscv64 +Build: Oct 13 2026 16:57:38 + +UEFI BootServices: EXITED + +=== StarKernel Boot Information === +Memory map entries: 100 +Total memory: 1020 MB +Usable memory: 975 MB +=================================== + +PMM initialized. +PMM statistics: + Total pages: 250264 + Free pages : 249612 + Used pages : 652 + Total MB : 977 + Free MB : 975 + 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=0x4b56120b672e75bc capsule_hash=0x4b56120b672e75bc words=311 +V4: capsule v4:forth79.4th signature: missing (unsigned) +PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x65daab1b670a4383 +PARITY:V4_POST tests=538 pass=538 fail=0 +PARITY:V4_SYSTEM word_count=317 dict_hash=0x0951d7e02e251554 +PARITY:OK +POST: PASSED +[HADES][INFO ] [KRELTSC: 0] blk: raw device LBN 2048..3071 (1024 blocks) +PCI: init... +virtio-blk: found device +[HADES][INFO ] [KRELTSC: 30083718] blk: disk 'StarForth Volume' v2 LBN 3072..789009 (785938 user b +Artemis: virtio-blk attached +ok> : SQ DUP * ; + ok +ok> 7 SQ . 3 4 U* . . +49 0 12 ok +ok> T{ +UNKNOWN WORD: 'T{' + ERROR +ok> RS1 +UNKNOWN WORD: 'RS1' + ERROR +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> 1 BLOCK C@ . 2047 BLOCK C@ . +0 0 ok +ok> 2100 BLOCK 1024 BLANK 65 2100 BLOCK C! UPDATE SAVE-BUFFERS EMPTY-BUFFERS 2100 BLOCK C@ . +65 ok +ok> 3072 BLOCK C@ . +0 ok +ok> 3072 BLOCK DROP UPDATE SAVE-BUFFERS +Storage refused + ERROR +ok> 9999999 BLOCK +Block out of range + ERROR +ok> 5 7 PORT! +No one on that port + ERROR +ok> 1 2 + . +3 ok +ok> 5 AWAIT +7 8 * . +Interrupted + ERROR +ok> 56 ok +ok> : N4 400 0 DO I . LOOP ; + ok +ok> N4 +0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 ok +ok> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 +Stack overflow + ERROR +ok> 3 4 + . +7 ok +ok> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 + ok +ok> WORDS +N4 ASK9 U/MOD U* (UD) (NB) (BITS) BYE ACL-WORD-ID ACL-HEAT@ ACL-INIT-PRIMITIVES +ACL-INHERIT ACL-ALLOW! ACL-TTL! ACL-MODE! ACL-PIN ACL-PINNED? ACL-ALLOW@ +ACL-TTL@ ACL-MODE@ ACL-HOOK LOG-DEBUG" LOG-TEST" LOG-INFO" LOG-WARN" +LOG-ERROR" (LOG") LOG-DEBUG-STR LOG-TEST-STR LOG-INFO-STR LOG-WARN-STR +LOG-ERROR-STR LOG-LEVEL! LOG-LEVEL@ LOG-DEBUG LOG-TEST LOG-INFO +LOG-WARN LOG-ERROR THRU --> LOAD LIST EMPTY-BUFFERS FLUSH SAVE-BUFFERS +UPDATE BLOCK BUFFER BLK SCR Q.PRINT Q.COS Q.SIN Q.LOG Q.SQRT Q.EXP +Q./ Q.* Q.MIN Q.MAX Q.0= Q.> Q.< Q.= Q.NEG Q.ABS Q.- Q.+ Q.SCALE +Q.0 Q.1 Q.TO-INT Q.FROM-INT DEFER@ IS DEFER COLD WARM PAGE VERSION +79-STANDARD FORGET VLIST WORDS ORDER VOCABULARY DEFINITIONS FORTH +CURRENT CONTEXT FENCE SKIP SCAN SEARCH COMPARE -TRAILING BLANK ERASE +FILL MOVE CMOVE> ?TERMINAL DMIN DMAX D< M- M+ D2/ D2* D= D0< D0= +DABS D- RSHIFT LSHIFT WITHIN MIN MAX ABS U> U< >= <= <> 0> 0<> -! +2! 2@ INVERT FALSE TRUE NOP 2R@ 2R> 2>R 2ROT 2OVER 2SWAP DUMP .S +? D. D.R U. U.R . .R OCTAL HEX DECIMAL SPACES #> #S # SIGN HOLD +<# STATE PAD BASE SPAN >IN TIB BL > < = NOT 0< 0= OR XOR AND M/MOD +*/ */MOD MOD / /MOD M* S>D 2/ 2* 2- 2+ 1- 1+ NEGATE * - + CELLS ++! ! @ UNLOOP LEAVE J I R@ R> >R ROLL PICK DEPTH 2DROP 2DUP ?DUP +-ROT ROT SWAP OVER DROP DUP S" (S") ABORT" (ABORT") ." (.") ABORT +QUIT (WORD-FORGOTTEN) (WORD-DEFINED) (REFUSED) (LOST) (CONSOLE) +(ME) NODE-ERROR (SEAL) PORT! AWAIT SEND-ON SEND NO-ROUTES GONE NO-ROUTE +DEFAULT-ROUTE NEIGHBOUR ROUTE +LOOP LOOP ?DO DO ENDCASE ENDOF OF +CASE REPEAT WHILE AGAIN UNTIL BEGIN THEN ELSE IF DOES> CONSTANT +VARIABLE CREATE [COMPILE] COMPILE IMMEDIATE EXIT KERNEL-WORD ; : +[LITERAL] ['] ' LITERAL ] [ INTERPRET EXECUTE FIND HIDDEN SMUDGE +TRAVERSE >BODY PFA CFA NAME> NFA >NAME LINK> LFA >LINK LATEST 2, +C, , ALLOT ALIGN HERE \ ( NUMBER CONVERT ENCLOSE WORD QUERY EXPECT +SOURCE TYPE COUNT SPACE CR KEY EMIT CMOVE C! C@ DNEGATE D+ UM* + ok +ok> DEPTH . +26 ok +ok> : AW 5 AWAIT ; + ok +ok> 1 + ok +ok> AW +Stack overflow + ERROR +ok> 4321 . +4321 ok +ok> HERE . +8326 ok +ok> BYE +BYE: cold restart diff --git a/v4/README.md b/v4/README.md index d1ed0257..b5181199 100644 --- a/v4/README.md +++ b/v4/README.md @@ -115,13 +115,9 @@ 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. A node -looks before it begins a message (`MESH.md` section 7a): it takes in what -its neighbours are waiting to write to it, keeps those messages until it -has nothing else to do, and writes only to a neighbour that is waiting to -read -- or, of two neighbours, the one with the lower number may wait. -`NEIGHBOUR ( node port -- )` tells a node who is on each port. A node with -no room for one more message lets it go and counts it in `(LOST)`. +`v4/tests/test_host_mesh.c` runs three StarForth nodes in a row. +`NEIGHBOUR ( node port -- )` tells a node who is on each port. What a node +cannot take or pass on it lets go and counts in `(LOST)`. **Five nodes from nothing** (`MESH.md` step 5) is built and proven in the fabric under test: Hera asks whoever holds the fabric for a node @@ -141,8 +137,20 @@ sixteenth to pass it on, sends a NACK to whoever waits on it; `(REFUSED)` counts them. `AWAIT` ends in an error if the answer is not going to come: "Message refused", "Node gone", or "Interrupted" when a line is typed at the console. `n KILL` on Hera removes node n and tells every other node it -is gone; a node believes that only from its centre. A stuck node can hold -up its neighbours until it is killed: `MESH.md` 7b.7 says how. +is gone; a node believes that only from its centre. + +**Messages on the wire** (`MESH.md` 7d, step 6e). A node that is stuck +holds up no other node. The fabric keeps a queue of whole messages each +way on every wire (`v4/src/wire.c`, 1,024 cells), and a node asks it, +through six addresses after its ports, to look at, take, move, drop or +put a whole message: each is one engine step, all of it or none. A node +holds nothing in transit. `SEND`, an answer, a NACK and a GONE go at once +or are refused at once; only what a text prints waits for room, so that +output is not lost. A node with nothing to do sleeps until a message +comes. A node removed at any step of an exchange leaves the others at +rest and answering (`v4/tests/test_host_mesh.c`). What it costs is in +`MESH.md` 7d.6: a burst beyond what a wire holds is refused, and text for +a node that is stuck fills its wire and is refused from then on. **Blocks** (`MESH.md` step 6). The block words are the kernel's, as they are for a v3 VM: `BLOCK`, `BUFFER`, `UPDATE`, `SAVE-BUFFERS` and diff --git a/v4/include/v4/fabric.h b/v4/include/v4/fabric.h index 3d2f16d0..42d54c47 100644 --- a/v4/include/v4/fabric.h +++ b/v4/include/v4/fabric.h @@ -27,7 +27,6 @@ typedef struct { int (*take)(void *self, v4_cell value); /* the node wrote `value`: 1 if it is taken, 0 if not yet */ int (*give)(void *self, v4_cell *value); /* the node is reading: 1 with a word in *value, 0 if not yet */ void *self; - int (*pending)(void *self); /* 1 if it has a word to give that has not been asked for; may be 0: it never says */ } v4_device; /* One end of a wire. */ @@ -61,7 +60,6 @@ typedef struct { unsigned queue_count, queue_free; /* how many, and how many are not on a wire */ unsigned queue_first; /* the first that is not, and the index plus one; 0: none. Each links to the next by its `head`. */ v4_cell gone_error; /* see v4_fabric_gone_error; 0: none */ - v4_cell interrupt_error; /* see v4_fabric_interrupt_error; 0: none */ } v4_fabric; /* An empty fabric with room for `capacity` nodes, in `places`. */ @@ -99,19 +97,6 @@ int v4_fabric_device_take(v4_fabric *f, unsigned node, unsigned port, v4_cell *h * is how a fabric begins, nothing is raised. */ void v4_fabric_gone_error(v4_fabric *f, v4_cell code); -/* A NODE BLOCKED WRITING TO A NODE THAT DOES NOT READ. Of two neighbours - * one may write to the other without looking (docs/v4.0.0/MESH.md 7a), and - * is then blocked until the other reads; if the other never does, it is - * blocked for ever, and if it is the node the console is on, nothing can be - * typed to it again. So: when a node that can take an error is blocked - * writing to another node, on the first word of a message (node.h, - * v4_node_words_since_look: nothing of the message has gone), and a device - * on one of its own ports says it has something pending for it, the error - * `code` is raised on the node: it gives up that message and goes on, to - * read what the device has. Only a device with a `pending` function can - * do this. With `code` 0, which is how a fabric begins, it never happens. */ -void v4_fabric_interrupt_error(v4_fabric *f, v4_cell code); - /* More room: `places`, of `capacity` no less than before, takes over; every * node keeps its number and its wiring. */ void v4_fabric_grow(v4_fabric *f, v4_place *places, unsigned capacity); diff --git a/v4/include/v4/image.h b/v4/include/v4/image.h index 9171b38a..80adffd2 100644 --- a/v4/include/v4/image.h +++ b/v4/include/v4/image.h @@ -65,11 +65,6 @@ typedef struct { * port". */ #define V4_ERROR_NO_ONE 18 -/* The nucleus's error for a node let go of a message it was blocked on the - * first word of, because its console has a line for it (fabric.h, - * v4_fabric_interrupt_error): "Interrupted". */ -#define V4_ERROR_INTERRUPTED 21 - /* The description of the nucleus built from v4/capsule (the generated file * defines it). */ extern const v4_image v4_capsule_image; diff --git a/v4/include/v4/node.h b/v4/include/v4/node.h index 4d17d6ac..760490b4 100644 --- a/v4/include/v4/node.h +++ b/v4/include/v4/node.h @@ -120,7 +120,6 @@ typedef struct { unsigned last_from; /* the port the last read from "any" took its word from */ unsigned writers; /* bit k: the neighbour on port k is blocked writing to this node */ unsigned readers; /* bit k: the neighbour on port k is blocked reading from this node */ - unsigned since_look; /* words taken from this node since it last fetched either of those */ /* Whole messages on the wires (MESH.md 7d.3). See v4_node_port_attach. */ unsigned wire; /* the port that A, B and Do are about; V4_PORTS if what was stored is not a port */ @@ -262,13 +261,6 @@ int v4_node_doing(const v4_node *n); void v4_node_done(v4_node *n, v4_cell how); void v4_node_have(v4_node *n, unsigned mask); -/* How many words the node has had taken since it last looked at its - * neighbours (a fetch of either of the two status addresses). A node that - * looks before it begins a message (MESH.md 7a) and is blocked writing with - * this at 0 is blocked on the first word of the message: nothing of it has - * gone. */ -unsigned v4_node_words_since_look(const v4_node *n); - /* THERE IS NO ONE ON THE PORT the node is blocked at -- writing to it, or * reading from that one port -- and there will not be. A node that can * take an error (it has an error register and a fault table: node.h, diff --git a/v4/src/fabric.c b/v4/src/fabric.c index 218fac0f..8a8fa124 100644 --- a/v4/src/fabric.c +++ b/v4/src/fabric.c @@ -25,7 +25,6 @@ void v4_fabric_init(v4_fabric *f, v4_place *places, unsigned capacity) f->queue_free = 0; f->queue_first = 0; f->gone_error = 0; - f->interrupt_error = 0; for (i = 0; i < capacity; i++) clear_place(&places[i]); } @@ -34,11 +33,6 @@ void v4_fabric_gone_error(v4_fabric *f, v4_cell code) f->gone_error = code; } -void v4_fabric_interrupt_error(v4_fabric *f, v4_cell code) -{ - f->interrupt_error = code; -} - void v4_fabric_grow(v4_fabric *f, v4_place *places, unsigned capacity) { unsigned i; @@ -463,24 +457,6 @@ unsigned v4_fabric_step(v4_fabric *f) for (i = 0; i < f->capacity; i++) if (awake(f, i) && f->place[i].node->n.reading && !f->place[i].node->n.given) done += hand_over_read(f, i); - /* a node blocked on the first word of a message to a node that is not - * reading, while a device of its own has something for it */ - if (f->interrupt_error != 0) - for (i = 0; i < f->capacity; i++) { - v4_node *n; - unsigned k; - if (!awake(f, i)) continue; - n = &f->place[i].node->n; - if (!n->asking || f->place[i].wire[n->ask_port].kind != V4_WIRE_NODE || v4_node_words_since_look(n) != 0) continue; - for (k = 0; k < V4_PORTS; k++) { - const v4_wire *w = &f->place[i].wire[k]; - if (w->kind == V4_WIRE_DEVICE && w->device->pending && w->device->pending(w->device->self)) { - done += (unsigned)v4_node_port_gone(n, f->interrupt_error); - break; - } - } - } - /* a node blocked at one port that nothing is wired to */ if (f->gone_error != 0) for (i = 0; i < f->capacity; i++) { diff --git a/v4/src/node.c b/v4/src/node.c index 99354623..e645c68f 100644 --- a/v4/src/node.c +++ b/v4/src/node.c @@ -124,8 +124,8 @@ v4_cell v4_node_fetch(v4_node *n, v4_cell addr) { int port = v4_node_port_index(n, addr); if (port == (int)V4_PORTS + 1) return (v4_cell)n->last_from; - if (port == (int)V4_PORTS + 2) { n->since_look = 0; return (v4_cell)n->writers; } - if (port == (int)V4_PORTS + 3) { n->since_look = 0; return (v4_cell)n->readers; } + if (port == (int)V4_PORTS + 2) return (v4_cell)n->writers; + if (port == (int)V4_PORTS + 3) return (v4_cell)n->readers; if (port == (int)V4_PORT_WIRE) return (v4_cell)n->wire; if (port == (int)V4_PORT_A) return n->wire_a; if (port == (int)V4_PORT_B) return n->wire_b; @@ -189,7 +189,6 @@ void v4_node_port_attach(v4_node *n, v4_cell base) n->last_from = 0; n->writers = 0; n->readers = 0; - n->since_look = 0; n->wire = 0; n->wire_a = 0; n->wire_b = 0; @@ -240,7 +239,6 @@ void v4_node_born(v4_node *n, v4_cell base) void v4_node_port_served(v4_node *n) { n->asking = 0; - n->since_look++; } int v4_node_doing(const v4_node *n) @@ -259,11 +257,6 @@ void v4_node_have(v4_node *n, unsigned mask) n->have = mask; } -unsigned v4_node_words_since_look(const v4_node *n) -{ - return n->since_look; -} - int v4_node_port_gone(v4_node *n, v4_cell code) { if (code == 0 || n->error_reg < 0 || n->fault_vector < 0 || n->stopped) return 0; diff --git a/v4/tests/test_fabric.c b/v4/tests/test_fabric.c index 68fdd2b2..38878df8 100644 --- a/v4/tests/test_fabric.c +++ b/v4/tests/test_fabric.c @@ -51,10 +51,6 @@ static unsigned loaded(unsigned k) /* the programme ends by waiting at a port nothing is wired to */ static void wait_for_ever(void) { LIT(PB + 7); O(BANG_B); O(FETCH_B); (void)v4_asm_label(&as); } /* and the last word is written out */ -/* a device that says whether it has something pending */ -static int *dev_has; -static int device_has(void *self) { (void)self; return *dev_has; } - /* Let time pass until nothing more can happen, or `max` steps. */ static unsigned settle(unsigned max) { @@ -435,62 +431,6 @@ int main(void) CHECK(ND(a)->n.asking && ND(a)->n.request == 5 && ND(c)->n.reading && ND(c)->n.mem[OUT] == 0, "looking takes nothing and gives nothing: both wait as they did"); CHECK(!ND(b)->n.stopped && ND(b)->n.reading, "and the one that looked did not wait to look"); - /* ---- a node blocked on the first word of a message, while a device of its own has something for it ---- */ - { - static int has; /* what the device says it has pending */ - static stream none; - static v4_device dev; - v4_fabric_init(&f, places, 4); - for (i = 0; i < 3; i++) v4_node_reset(&pool[i].n); - a = loaded(0); /* looks about, then writes two words to its port 0 */ - LIT(PB + (v4_cell)V4_PORTS + 3); O(BANG_B); O(FETCH_B); O(DROP); - LIT(PB + 0); O(BANG_B); LIT(1); O(STORE_B); LIT(2); O(STORE_B); wait_for_ever(); - b = loaded(1); /* never reads */ - LIT(OUT); O(BANG_A); - { - v4_cell again = v4_asm_label(&as); - O(FETCH_A); LIT(1); O(ADD); O(STORE_A); - v4_asm_branch(&as, V4_OP_JUMP, again); - } - CHECK(v4_asm_ok(&as) && v4_fabric_wire(&f, a, 0, b, 3), "a writer that looks first, wired to a node that never reads"); - dev.take = stream_take; dev.give = 0; dev.self = &none; dev.pending = device_has; has = 1; dev_has = &has; - CHECK(v4_fabric_wire_device(&f, a, 5, &dev), "and to a device, which has something for it"); - for (i = 0; i < 40; i++) (void)v4_fabric_step(&f); - CHECK(ND(a)->n.asking && ND(a)->n.request == 1 && v4_node_words_since_look(&ND(a)->n) == 0, "the writer is blocked on its first word, and waits: the fabric has no error for it"); - v4_fabric_interrupt_error(&f, 21); - for (i = 0; i < 40; i++) (void)v4_fabric_step(&f); - CHECK(ND(a)->n.asking && ND(a)->n.faults == 0, "nor is a bare node let go when it has: it cannot take an error"); - v4_node_error_attach(&ND(a)->n, OUT + 20); - v4_node_fault_attach(&ND(a)->n, 900); - has = 0; - for (i = 0; i < 40; i++) (void)v4_fabric_step(&f); - CHECK(ND(a)->n.asking && ND(a)->n.faults == 0, "a node that can take one waits all the same while the device has nothing for it"); - has = 1; - (void)v4_fabric_step(&f); - CHECK(!ND(a)->n.asking && ND(a)->n.fault_kind == V4_FAULT_RAISED && ND(a)->n.fault_addr == 21 && ND(a)->n.mem[OUT + 20] == 21, - "when it has, the writer is let go and the error raised on it"); - - /* once the first word has gone, it is not let go: the message must be finished */ - v4_fabric_init(&f, places, 4); - for (i = 0; i < 3; i++) v4_node_reset(&pool[i].n); - a = loaded(0); - LIT(PB + (v4_cell)V4_PORTS + 3); O(BANG_B); O(FETCH_B); O(DROP); - LIT(PB + 0); O(BANG_B); LIT(1); O(STORE_B); LIT(2); O(STORE_B); wait_for_ever(); - b = loaded(1); /* reads one word, and no more */ - LIT(PB + 3); O(BANG_B); O(FETCH_B); LIT(OUT); O(BANG_A); - { - v4_cell again = v4_asm_label(&as); - O(FETCH_A); LIT(1); O(ADD); O(STORE_A); - v4_asm_branch(&as, V4_OP_JUMP, again); - } - CHECK(v4_asm_ok(&as) && v4_fabric_wire(&f, a, 0, b, 3) && v4_fabric_wire_device(&f, a, 5, &dev), "the same, to a node that reads one word and no more"); - v4_node_error_attach(&ND(a)->n, OUT + 20); - v4_node_fault_attach(&ND(a)->n, 900); - v4_fabric_interrupt_error(&f, 21); - for (i = 0; i < 60; i++) (void)v4_fabric_step(&f); - CHECK(ND(a)->n.asking && ND(a)->n.request == 2 && ND(a)->n.faults == 0, "blocked on its second word with the device still pending, the writer waits"); - } - /* ---- messages on the wire (MESH.md 7d): the engine only ---- */ { static v4_wire_queue qpool[8]; @@ -800,7 +740,7 @@ int main(void) CHECK(!ND(c)->n.doing && !ND(a)->n.doing && ND(a)->n.how == 1, "room that comes in the step the node goes to sleep wakes it: no wake-up is lost"); /* a device's take is a take */ { - static const v4_device dev = { 0, 0, 0, 0 }; + static const v4_device dev = { 0, 0, 0 }; v4_cell hh[7], tt[V4_WIRE_CELLS / 4]; CHECK(v4_fabric_wire_device(&f, a, 4, &dev), "a device on a third wire"); fill(f.place[a].wire[4].tx, 0); @@ -855,7 +795,7 @@ int main(void) static stream ks; static v4_device kern; unsigned free_before = f.queue_free; - ks.took_n = 0; kern.take = stream_take; kern.give = 0; kern.self = &ks; kern.pending = 0; + ks.took_n = 0; kern.take = stream_take; kern.give = 0; kern.self = &ks; CHECK(v4_fabric_wire_kernel(&f, a, 5, &kern) && f.queue_free == free_before && !f.place[a].wire[5].rx && !f.place[a].wire[5].tx, "a kernel is wired to a port, and is given no queues"); put_msg(&ND(a)->n, 100, 110, 4, 7); CHECK(ask(a, 5, 100, 110, 5) == 2 && ask(a, 5, 8, 0, 10) == 2 && ask(a, 5, 8, 0, 9) == 2 && ask(a, 5, 200, 220, 1) == 2 && ask(a, 5, 0, 0, 6) == 2 && !ND(a)->n.doing, diff --git a/v4/tests/test_host_depth.c b/v4/tests/test_host_depth.c index 22723d66..b8ec1a13 100644 --- a/v4/tests/test_host_depth.c +++ b/v4/tests/test_host_depth.c @@ -45,7 +45,7 @@ static v4_wire_queue queues[QUEUES]; /* ---- the console: a device on a port ---- */ #define CONSOLE_ID 1 -static const v4_device console = { 0, 0, 0, 0 }; /* it takes and gives no words: only whole messages */ +static const v4_device console = { 0, 0, 0 }; /* it takes and gives no words: only whole messages */ static unsigned hera, mid, far; /* where the three nodes are: 10, 11, 12 */ static char printed[32768]; /* what has come back since the console last sent */ static unsigned printed_len; diff --git a/v4/tests/test_host_mesh.c b/v4/tests/test_host_mesh.c index dbc58db2..e0ece12e 100644 --- a/v4/tests/test_host_mesh.c +++ b/v4/tests/test_host_mesh.c @@ -38,11 +38,11 @@ static v4_wire_queue queues[QUEUES]; /* ---- the console: a device on a port ---- */ #define CONSOLE_ID 1 -static const v4_device console = { 0, 0, 0, 0 }; /* it takes and gives no words: only whole messages */ +static const v4_device console = { 0, 0, 0 }; /* it takes and gives no words: only whole messages */ /* a kernel on a node's port 0: it takes the words written to it, and no messages (MESH.md 7d.5) */ static unsigned kernel_words; static int kernel_take(void *self, v4_cell value) { (void)self; (void)value; kernel_words++; return 1; } -static const v4_device kernel_dev = { kernel_take, 0, 0, 0 }; +static const v4_device kernel_dev = { kernel_take, 0, 0 }; static unsigned hera, mid, far; /* where the three nodes are: 10, 11, 12 */ static char printed[32768]; /* what has come back since the console last sent */ static unsigned printed_len; @@ -246,6 +246,56 @@ static void watch_far_waits(void) if (waits_for_room(far)) { saw_room_wait++; if (going_from(far, 3) && going_from(far, 3)->used == V4_WIRE_CELLS - 8u) saw_full++; } } +/* ---- a node removed at every step of an exchange (MESH.md 7d.7, acceptance 6) ---- */ +/* 1 if the node is doing nothing and waits for nothing but a message: asleep, and blocked at no port. */ +static int at_rest(unsigned id) +{ + const v4_fabric_node *x = v4_fabric_node_at(&f, id); + return x && asleep(id) && !x->n.asking && !x->n.reading && !x->n.stopped; +} +/* 1 if what came back ends with the answer to `1 2 + .`, asked by the word Q that each node was given; a wait + * the removal left is first ended by the line, and says so. */ +#define ASK ": Q 1 2 + . ;" +static int answers(v4_cell node, unsigned id) +{ + const char *got = tell(node, "Q"); + size_t len = strlen(got); + return len >= 2 && strcmp(got + len - 2, "3 ") == 0 && ended >= 1 && ended_from == node && at_rest(id); +} +/* The exchange that `text`, sent to `node`, begins is played from the mesh as kept, once for every step it + * takes, with the node at place `gone` removed at that step. Every node left must come to rest, blocked in + * nothing, and answer. With the middle node gone the far one is wired to the first, as whoever removed it + * would, so that it can be asked. How many steps the exchange takes; how many removals went wrong, and + * the first of them. */ +static v4_fabric_node now_pool[3]; +static v4_place now_places[3]; +static v4_wire_queue now_queues[QUEUES]; +static v4_fabric now_f; +static unsigned removed_at_every_step(v4_cell node, const char *text, unsigned gone, unsigned *wrong, unsigned *first_wrong) +{ + unsigned long before; + unsigned whole, s; + *wrong = 0; *first_wrong = 0; + put_back(); + before = steps_run; + if (!put_text(node, text) || !run()) { *wrong = 1; return 0; } + whole = (unsigned)(steps_run - before); + put_back(); + if (!put_text(node, text)) { *wrong = 1; return 0; } + for (s = 0; s <= whole; s++) { + int ok; + memcpy(now_pool, pool, sizeof pool); memcpy(now_places, places, sizeof places); memcpy(now_queues, queues, sizeof queues); now_f = f; /* the exchange, s steps on */ + ok = v4_fabric_remove(&f, gone) == &pool[gone] && run(); + ok = ok && at_rest(hera) && (gone == mid ? at_rest(far) : at_rest(mid)); + if (ok && gone == mid) ok = v4_fabric_wire(&f, hera, 2, far, 2) && answers(12, far) && answers(10, hera); + else if (ok) ok = answers(11, mid) && answers(10, hera); + if (!ok) { if (!*wrong) *first_wrong = s; (*wrong)++; } + memcpy(pool, now_pool, sizeof pool); memcpy(places, now_places, sizeof places); memcpy(queues, now_queues, sizeof queues); f = now_f; + (void)v4_fabric_step(&f); (void)console_takes(); + } + return whole; +} + int main(void) { unsigned i; @@ -944,6 +994,36 @@ int main(void) printf(" between texts the nucleus used at most %u cells of the data stack and %u entries of the return stack\n", between_data, between_ret); CHECK(between_data <= 4 && between_ret <= 7, "between texts: four cells of the data stack, and seven return entries"); + + /* ---- A NODE REMOVED AT EVERY STEP (MESH.md 7d.7, acceptance 6) ---- + * Three exchanges, each played once whole and then once for every step it takes, with node 11 removed + * at that step, and again with node 12: the nodes left come to rest, blocked in nothing, and answer. + * What is typed is a word defined beforehand, and so is what a node left is asked (Q, which is + * `1 2 + .`): a line of several words is mostly the dictionary searched, thousands of steps in which the + * mesh does nothing, and every one of them would be a removal played to the end. */ + { + static const struct { const char *what, *set10, *set11, *set12; v4_cell node; const char *text; } ex[3] = { + { "text from the console for node 12, what it prints and how it ended", "1 DROP", "1 DROP", ": A 7 8 * . ;", 12, "A" }, + { "node 11 SENDs node 12 text and waits for its answer", "1 DROP", ": T S\" Q\" 12 SEND 12 AWAIT . ;", "1 DROP", 11, "T" }, + { "a message node 12 has no way for, and its NACK to node 10", "55 2 ROUTE : N S\" 1 DROP\" 55 SEND ;", "55 3 ROUTE", "NO-ROUTES 1 2 ROUTE 10 2 ROUTE 11 2 ROUTE", 10, "N" } + }; + unsigned e, g, whole, wrong, first; + step_cap = 2000000; + for (e = 0; e < 3; e++) { + CHECK(row() && told(10, ex[e].set10) && told(11, ex[e].set11) && told(12, ex[e].set12) && told(10, ASK) && told(11, ASK) && told(12, ASK), "a row made afresh for: %s", ex[e].what); + step_cap = 2000000; + keep(); + for (g = 1; g <= 2; g++) { + whole = removed_at_every_step(ex[e].node, ex[e].text, g == 1 ? mid : far, &wrong, &first); + CHECK(whole > 0 && wrong == 0, "%s, in %u steps: with node %u removed at each of them the rest come to rest and answer: %u did not, the first at step %u", + ex[e].what, whole, 10u + g, wrong, first); + } + } + put_back(); + CHECK(is_empty(tell(10, "N")) && pool[hera].n.mem[REFUSED] == 1 && pool[far].n.mem[LOST] == 1, "the last of them, whole: node 12 let the message go and node 10 was told it was refused"); + step_cap = 20000000; + } + printf(" %d checks, %d failures\n", checks, failures); return failures != 0; } diff --git a/v4/tests/test_host_unit.c b/v4/tests/test_host_unit.c index 0c0224de..d51a49cd 100644 --- a/v4/tests/test_host_unit.c +++ b/v4/tests/test_host_unit.c @@ -142,7 +142,7 @@ static int host_born(void *self) v4_node_fault_attach(&pool[k].n, w_fault); v4_blocks_init(&node_blocks[k], BUF0_W); if (k != 0) { /* Hera's kernel is wired where she is made */ - node_kernel[k].take = node_kernel_take; node_kernel[k].give = 0; node_kernel[k].self = &pool[k]; node_kernel[k].pending = 0; + node_kernel[k].take = node_kernel_take; node_kernel[k].give = 0; node_kernel[k].self = &pool[k]; if (!v4_fabric_wire_kernel(&f, (unsigned)place, 0, &node_kernel[k])) return -1; /* it takes words, and no messages */ } return place; @@ -196,7 +196,7 @@ static int kernel_take(void *self, v4_cell value) /* a request */ if (value < FIRST_REQUEST || !v4_manage_serve(&manage, hera_place, (unsigned)(value - FIRST_REQUEST))) refused++; return 1; } -static const v4_device kernel = { kernel_take, kernel_give, 0, 0 }; +static const v4_device kernel = { kernel_take, kernel_give, 0 }; /* ---- the console: a device on Hera's port 1 ---- * It speaks whole messages: it puts them on the wire to Hera and takes them @@ -209,7 +209,7 @@ static int ended; static v4_cell ended_from, ended_how; static unsigned post_passed[32]; /* by node number: POST tallies with no failures seen from it */ static unsigned post_other; /* tallies with failures */ -static const v4_device console = { 0, 0, 0, 0 }; +static const v4_device console = { 0, 0, 0 }; static unsigned console_takes(void) {