fix(v4.0.0): step 6e final review -- texts begun in order; a word no one will read lets its writer go; a cut wire wakes a wait for room; a full console wire is a refusal, not a fault
The final review of step 6e, by a fresh reviewer told to break it, and what was ruled: fix them all, test first. Each has a test that failed before the mend. - Two texts from one node could be begun in the wrong order when room for their answers came between the node's look at the first and at the second. Texts whose answers go by the same port are begun in the order they came: (D-MASK), quit.v4. 102 of 700 timings were wrong before. - A word written with PORT! to a node that speaks whole messages, or to a console's port, blocked its writer for ever and cut off every node beyond it. It is error 18 now, whether that node is asleep, running or stuck: fabric.c, node.c. - A node asleep for room on one wire is woken when another of its wires is cut. - A line there was no room for on the lone node's wire was reported as a fault and ended the hosted program. It is Message refused, and the prompt comes back: V4_BOOT_LINE_REFUSED. hosted-check has the case; no bare-metal boot has typed it. - Ruled: text behind held output for the same port is refused though it would fit. MESH.md 7d.4 said otherwise and is corrected. - The removal test also cuts and re-makes a wire, and has an exchange in which output is held at a full wire: 26,814 disturbances in all. - MESH.md and v4/README.md no longer say that a stuck node holds up no other node, that only printing waits, or that no node is left waiting on one that is gone; 7d.6 lists the limits and what the products do that they did not before. make -C v4 test and sanitize at both widths, hosted-check, lint. Three bare-metal boots: logs/20261013-194827 (amd64), -195131 (aarch64), -195518 (riscv64). POST 538 of 538, word_count=317, dict_hash=0xe5a57f3eb72ff94a on all six; 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. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
06da5700bc
commit
66b26f823c
Binary file not shown.
+175
-46
File diff suppressed because it is too large
Load Diff
@@ -127,6 +127,7 @@ void sk_v4_run(void (*chain)(void))
|
||||
}
|
||||
if (how == V4_TEXT_COMPLETED) console_puts(" ok\n");
|
||||
else if (how == V4_TEXT_ERROR) console_puts(" ERROR\n");
|
||||
else if (how == V4_BOOT_LINE_REFUSED) console_puts("Message refused\n ERROR\n"); /* the node's wire is full: error 19's words */
|
||||
else if (how == V4_BOOT_LINE_STOPPED) {
|
||||
console_println("StarForth v4: the node stopped on a fault");
|
||||
for (;;) { }
|
||||
|
||||
@@ -0,0 +1,217 @@
|
||||
[2J[001;001H[=3h[2J[001;001H[2J[001;001H[8;042;160t[2J[001;001H[2J[001;001H[8;056;240t[2J[001;001HBdsDxe: 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)
|
||||
[2J[001;001H[=3h[2J[001;001HStarKernel 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 19:47:59
|
||||
|
||||
UEFI BootServices: EXITED
|
||||
|
||||
=== StarKernel Boot Information ===
|
||||
Memory map entries: 131
|
||||
Total memory: 1023 MB
|
||||
Usable memory: 966 MB
|
||||
===================================
|
||||
|
||||
PMM initialized.
|
||||
PMM statistics:
|
||||
Total pages: 248734
|
||||
Free pages : 247211
|
||||
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=2093272242 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=1004031420, tick_hz=100, initial_count=10040314
|
||||
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=0x3b4a82485b10bfb7 capsule_hash=0x3b4a82485b10bfb7 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=0x6b56e15226ee3719
|
||||
PARITY:V4_POST tests=538 pass=538 fail=0
|
||||
PARITY:V4_SYSTEM word_count=317 dict_hash=0xe5a57f3eb72ff94a
|
||||
PARITY:OK
|
||||
POST: PASSED
|
||||
[32m[HADES][INFO ] [0m[KRELTSC: 0] blk: raw device LBN 2048..3071 (1024 blocks)
|
||||
PCI: init...
|
||||
PCI: ECAM mapped (amd64)
|
||||
virtio-blk: found device
|
||||
[32m[HADES][INFO ] [0m[KRELTSC: 77784357] 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
|
||||
@@ -0,0 +1,190 @@
|
||||
UEFI firmware (version 2025.11-3ubuntu7.3 built at 15:40:26 on Sep 23 2026)
|
||||
[2J[001;001H[=3h[2J[001;001H[2J[001;001H[8;031;100t[2J[001;001HBdsDxe: 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)
|
||||
[2J[001;001H[=3h[2J[001;001HStarKernel 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 19:51:04
|
||||
|
||||
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=0x3b4a82485b10bfb7 capsule_hash=0x3b4a82485b10bfb7 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=0x6b56e15226ee3719
|
||||
PARITY:V4_POST tests=538 pass=538 fail=0
|
||||
PARITY:V4_SYSTEM word_count=317 dict_hash=0xe5a57f3eb72ff94a
|
||||
PARITY:OK
|
||||
POST: PASSED
|
||||
[32m[HADES][INFO ] [0m[KRELTSC: 0] blk: raw device LBN 2048..3071 (1024 blocks)
|
||||
PCI: init...
|
||||
virtio-blk: found device
|
||||
[32m[HADES][INFO ] [0m[KRELTSC: 1840537] 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
|
||||
@@ -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
|
||||
[2J[004D[=3h[2J[009D[2J[004D[8;031;100t[2J[016DRISC-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
|
||||
[2J[001;001H[=3h[2J[009DStarKernel 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 = 0x00000000bdc95abe
|
||||
riscv64: satp cleared -- Bare mode, explicit (item 4.3.5a)
|
||||
|
||||
|
||||
_____ _ _ __ _
|
||||
/ ____| | | |/ / | |
|
||||
| (___ | |_ __ _ _ __| ' / ___ _ __ _ __ ___| |
|
||||
\___ \| __/ _` | '__| < / _ \ '__| '_ \ / _ \ |
|
||||
____) | || (_| | | | . \ __/ | | | | | __/ |
|
||||
|_____/ \__\__,_|_| |_|\_\___|_| |_| |_|\___|_|
|
||||
|
||||
LithosAnanke v2.1.0 riscv64
|
||||
Architecture: riscv64
|
||||
Build: Oct 13 2026 19:54: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=0x3b4a82485b10bfb7 capsule_hash=0x3b4a82485b10bfb7 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=0x6b56e15226ee3719
|
||||
PARITY:V4_POST tests=538 pass=538 fail=0
|
||||
PARITY:V4_SYSTEM word_count=317 dict_hash=0xe5a57f3eb72ff94a
|
||||
PARITY:OK
|
||||
POST: PASSED
|
||||
[32m[HADES][INFO ] [0m[KRELTSC: 0] blk: raw device LBN 2048..3071 (1024 blocks)
|
||||
PCI: init...
|
||||
virtio-blk: found device
|
||||
[32m[HADES][INFO ] [0m[KRELTSC: 30767037] 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
|
||||
@@ -210,6 +210,8 @@ hosted-check: $(foreach i,$(HOSTED_ISAS),$(BINDIR)/boot-$(i).txt) $(BINDIR)/star
|
||||
@test $$(grep -c '^ok> ERROR$$' $(BINDIR)/kport-amd64.txt) -eq 2 && grep -q '^ok> 3 ok$$' $(BINDIR)/kport-amd64.txt && grep -q '^ok> 0 ok$$' $(BINDIR)/kport-amd64.txt || { echo "hosted-check: with the way to the console set to the kernel's port, a line that prints did not end in an error at the prompt, or left something on the stack, or the node did not come back"; tail -6 $(BINDIR)/kport-amd64.txt; exit 1; }
|
||||
@printf ': S0 S" 1 DROP" 0 0 SEND-ON ; S0\n1 2 + .\n65 1 BLOCK C! 1 BLOCK C@ .\n' | timeout 120 $(BINDIR)/starforth4-amd64 > $(BINDIR)/ksend-amd64.txt 2>&1; true
|
||||
@grep -q '^ok> No one on that port$$' $(BINDIR)/ksend-amd64.txt && grep -q '^ok> 3 ok$$' $(BINDIR)/ksend-amd64.txt && grep -q '^ok> 65 ok$$' $(BINDIR)/ksend-amd64.txt || { echo "hosted-check: a message sent to the kernel's port was not refused with No one on that port, or the kernel's requests no longer work"; tail -6 $(BINDIR)/ksend-amd64.txt; exit 1; }
|
||||
@{ printf '5 (CONSOLE) !\n7 AWAIT\n'; i=0; while [ $$i -lt 200 ]; do echo '1 DROP 1 DROP 1 DROP 1 DROP 1 DROP 1 DROP 1 DROP 1 DROP'; i=$$((i+1)); done; } | timeout 120 $(BINDIR)/starforth4-amd64 > $(BINDIR)/fullwire-amd64.txt 2>&1; test $$? -eq 0 || { echo "hosted-check: lines typed to a node that takes none, until its wire was full, ended the program"; tail -3 $(BINDIR)/fullwire-amd64.txt; exit 1; }
|
||||
@grep -q '^ok> Message refused$$' $(BINDIR)/fullwire-amd64.txt && ! grep -q 'stopped on a fault' $(BINDIR)/fullwire-amd64.txt || { echo "hosted-check: a line there was no room for on the node's wire was not refused, and said so"; tail -3 $(BINDIR)/fullwire-amd64.txt; exit 1; }
|
||||
@python3 $(HERE)/tools/depthsweep.py $(BINDIR)/starforth4-amd64 $$(( $(HOST_DATA_RING) + 2 )) $$(( $(HOST_RET_RING) + 1 )) || { echo "hosted-check: at some depth of a stack a line was not answered, or the node did not come back"; exit 1; }
|
||||
@$(BINDIR)/starforth4-postfail < /dev/null > $(BINDIR)/postfail.txt; test $$? -ne 0 || { echo "hosted-check: a boot with a failing case did not fail"; exit 1; }
|
||||
@grep -q '^POST FAIL: fail.wrong out<5 5 $$' $(BINDIR)/postfail.txt || { echo "hosted-check: the failing case was not named"; cat $(BINDIR)/postfail.txt; exit 1; }
|
||||
|
||||
+17
-14
@@ -129,9 +129,9 @@ The two products are not yet this: they become the five nodes at steps 8
|
||||
and 9.
|
||||
A node she births is not POSTed: POST is the kernel's, once, on Hera.
|
||||
|
||||
**Refusals and waits** (`MESH.md` 7b, step 6c). A node is never left
|
||||
waiting on a node that is gone, and a wait on a node that is alive and
|
||||
stuck is ended by Hera's killing it, or from the console. A node with no
|
||||
**Refusals and waits** (`MESH.md` 7b, step 6c). A wait on a node that
|
||||
never answers -- stuck, or gone -- is ended by Hera's killing it, which
|
||||
tells the others it is gone, or from the console. A node with no
|
||||
room for a message, or no way to pass it on, or that would be the
|
||||
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:
|
||||
@@ -140,17 +140,20 @@ 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.
|
||||
|
||||
**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.
|
||||
no longer stops its neighbours passing on, taking text or being typed
|
||||
to. 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`, a NACK and a GONE go at once or are refused at once.
|
||||
What a text prints, and its word of how the text ended, wait for room, so
|
||||
that output is not lost. A node with nothing to do sleeps until a message
|
||||
comes. A node removed, or a wire cut, 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;
|
||||
text for a node that is stuck fills its wire and is refused from then on;
|
||||
and a text whose printing must go by a stuck node waits, and cannot be
|
||||
typed to, until that node is killed.
|
||||
|
||||
**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
|
||||
|
||||
+15
-2
@@ -105,6 +105,14 @@ macro R-CLEAR RSTACK-DEPTH b! a !b endmacro
|
||||
\ whose answers go different ways, and each is begun when
|
||||
\ its own has the room. That room is kept from then until
|
||||
\ the answer has gone.
|
||||
\ TEXTS WHOSE ANSWERS GO THE SAME WAY ARE BEGUN IN THE ORDER
|
||||
\ THEY CAME. Once one has been left for want of room, every
|
||||
\ text behind it on this pass whose answer goes by that port
|
||||
\ is left too, though the room has come since: (D-MASK) has
|
||||
\ a bit for each such port. (As first built only the room
|
||||
\ was asked, each time; room that came between the look at
|
||||
\ one text and at the next began the second first. Found
|
||||
\ by the final review of step 6e.)
|
||||
\ a NACK is taken and counted in (REFUSED)
|
||||
\ a GONE is taken, and believed if this node's centre sent it
|
||||
\ an answer no one is waiting for is dropped: a SEND that is not waited
|
||||
@@ -128,7 +136,7 @@ macro R-CLEAR RSTACK-DEPTH b! a !b endmacro
|
||||
\ for no one.
|
||||
: (IDLE)
|
||||
L: 1 (QUIET) a! ! \ nothing here is any text's doing: see (RAISED)
|
||||
-1 (KEEP) a! ! 0 (AWAIT-FROM) a! ! -1 (DEFER) a! !
|
||||
-1 (KEEP) a! ! 0 (AWAIT-FROM) a! ! -1 (DEFER) a! ! 0 (D-MASK) a! !
|
||||
(SERVE) (MINE0)
|
||||
M: (MINE) if REST
|
||||
drop (IN)+2 a! @ -1 + if TEXT -3 + if NACK -1 + if GONE
|
||||
@@ -145,10 +153,15 @@ macro R-CLEAR RSTACK-DEPTH b! a !b endmacro
|
||||
TEXT: drop
|
||||
(IN)+1 a! @ (WAY) -if T1 drop (S-WIRE) a! @ \ the way back; with none known, the wire it came on
|
||||
T1: (DONE-PORT) a! !
|
||||
(DONE-PORT) a! @ (WBIT) (D-MASK) a! @ and if FREE1 jump FULL \ text ahead of it waits for room on that wire
|
||||
FREE1: drop
|
||||
8 (DONE-PORT) a! @ (ROOM?) if START -1 + if FULL
|
||||
drop (S-WIRE) a! @ (DONE-PORT) a! ! \ no one is on that port: back by the wire it came on,
|
||||
(S-WIRE) a! @ (WBIT) (D-MASK) a! @ and if FREE2 jump FULL
|
||||
FREE2: drop
|
||||
8 (S-WIRE) a! @ (ROOM?) -1 + if FULL jump START \ if that has the room -- or has no one on it either
|
||||
FULL: drop (DEFER) a! @ -if LATER drop (DONE-PORT) a! @ (DEFER) a! ! (SKIP) jump M
|
||||
FULL: drop (DONE-PORT) a! @ (WBIT) dup inv (D-MASK) a! @ and + !
|
||||
(DEFER) a! @ -if LATER drop (DONE-PORT) a! @ (DEFER) a! ! (SKIP) jump M
|
||||
LATER: drop (SKIP) jump M
|
||||
REST: drop
|
||||
(DEFER) a! @ -if ROOM drop (SLEEP) jump L
|
||||
|
||||
@@ -78,6 +78,9 @@ int v4_boot_run(const v4_boot *b);
|
||||
#define V4_BOOT_LINE_STOPPED (-2) /* the node stopped on a fault, or never finished */
|
||||
#define V4_BOOT_LINE_NO_INPUT (-3) /* the line read the keyboard and there is no more input */
|
||||
#define V4_BOOT_LINE_WAITING (-4) /* the line is waiting for an answer (AWAIT) that no one here can send: see below */
|
||||
#define V4_BOOT_LINE_REFUSED (-5) /* the node's wire has no room for the line: it was not put, and nothing was run. The node
|
||||
* is taking nothing -- it waits for an answer and does not know these lines for its
|
||||
* console's -- and its wire has filled (MESH.md 7d.6). It has not stopped. */
|
||||
int v4_boot_line(const v4_boot *b, const char *text, unsigned len);
|
||||
|
||||
/* A LINE THAT WAITS (docs/v4.0.0/MESH.md 7b.6). V4_BOOT_LINE_WAITING means
|
||||
|
||||
+21
-6
@@ -3,9 +3,10 @@
|
||||
*
|
||||
* On the fabric every node runs at the same time and a node with nothing to
|
||||
* do is blocked at a port. Here that is: every node that is awake and not
|
||||
* blocked executes one instruction word, and then every write that has a
|
||||
* reader waiting on the other end of its wire is handed over. There is no
|
||||
* choice of whose turn it is.
|
||||
* blocked executes one instruction word; then every operation on a whole
|
||||
* message that a node asked for is done (WHOLE MESSAGES, below); and then
|
||||
* every word written that has a reader waiting on the other end of its wire
|
||||
* is handed over. There is no choice of whose turn it is.
|
||||
*
|
||||
* THE GEOMETRY IS DATA. Which port connects to what is a table, and it can
|
||||
* be changed while the nodes run; nodes can be added and removed while they
|
||||
@@ -50,6 +51,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
v4_fabric_node *node; /* 0: no node here */
|
||||
int asleep;
|
||||
int cut; /* not 0: a wire of this node's has been cut since it was last woken by that (operation 9) */
|
||||
v4_wire wire[V4_PORTS];
|
||||
} v4_place;
|
||||
|
||||
@@ -97,6 +99,19 @@ 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 WORD NO ONE WILL READ. The same error is raised on a node that can take
|
||||
* one and is blocked writing a word to a port whose other end will not read
|
||||
* it: a device that takes no words (its `take` is 0: it speaks whole
|
||||
* messages only), or a node that speaks whole messages -- one that has
|
||||
* asked for a whole-message operation (below) since it was born, whatever
|
||||
* it is doing now: asleep at its wires, running, stuck in a loop, or put to
|
||||
* sleep by the fabric. Such a node does not read words, and before this a
|
||||
* word written to one blocked its writer for ever (found by the final
|
||||
* review of step 6e). A node that has asked for none yet may still read:
|
||||
* the writer waits for it. That is a newborn node being sent its nucleus
|
||||
* a word at a time, which executes from its ports and has asked nothing of
|
||||
* a wire. */
|
||||
|
||||
/* 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);
|
||||
@@ -149,9 +164,9 @@ void v4_fabric_wake(v4_fabric *f, unsigned id);
|
||||
* and 1 at once if it can never have it. Otherwise the node sleeps until a
|
||||
* message has come, as for 8, or a message has come off ANY of the wires
|
||||
* that lead from it -- taken, moved on or dropped by whoever reads that wire
|
||||
* -- since it was last woken that way; then it is answered 0 if the wire it
|
||||
* named now has the room and 1 if not, and it asks which wire has what
|
||||
* (10). A node may be waiting to put on several wires at once and can name
|
||||
* -- since it was last woken that way, or one of its wires has been cut;
|
||||
* then it is answered 0 if the wire it named now has the room and 1 if not,
|
||||
* and it asks which wire has what (10). A node may be waiting to put on several wires at once and can name
|
||||
* only one. A wake-up that finds nothing to do is answered by asking
|
||||
* again.
|
||||
*
|
||||
|
||||
@@ -125,6 +125,8 @@ typedef struct {
|
||||
unsigned wire; /* the port that A, B and Do are about; V4_PORTS if what was stored is not a port */
|
||||
v4_cell wire_a, wire_b; /* A and B */
|
||||
int doing; /* non-zero: blocked, having stored `do_op` to Do */
|
||||
int spoke; /* non-zero: it has asked for a whole-message operation since it was born: it is a node that
|
||||
* speaks whole messages, and not one that words are written to (fabric.h) */
|
||||
v4_cell do_op; /* the operation */
|
||||
v4_cell how; /* how the last one went */
|
||||
unsigned have; /* which wires had a message waiting, as the fabric last said: bit k for port k */
|
||||
@@ -217,8 +219,9 @@ void v4_node_console_attach(v4_node *n, v4_cell addr);
|
||||
* Have fetch: which wires have a message
|
||||
* waiting, bit k for port k, as the fabric
|
||||
* last said (v4_node_have)
|
||||
* The two before them are how a node looks before it writes (MESH.md 7a), as the
|
||||
* F18's io register lets it. They are what whoever connects the ports last
|
||||
* The two before them let a node that writes a word at a time see whether a
|
||||
* neighbour is waiting (MESH.md 7a), as the F18's io register does; a node that
|
||||
* speaks whole messages has no use for them. They are what whoever connects the ports last
|
||||
* said, v4_node_port_status; fetching them waits for nothing and changes
|
||||
* nothing. Of the whole-message addresses How and Have are read only: a
|
||||
* store to either is an address fault, as to "any port".
|
||||
|
||||
+18
-3
@@ -9,6 +9,7 @@ static void clear_place(v4_place *p)
|
||||
unsigned k;
|
||||
p->node = 0;
|
||||
p->asleep = 0;
|
||||
p->cut = 0;
|
||||
for (k = 0; k < V4_PORTS; k++) {
|
||||
p->wire[k].kind = V4_WIRE_NONE; p->wire[k].node = 0; p->wire[k].port = 0; p->wire[k].device = 0;
|
||||
p->wire[k].rx = 0; p->wire[k].tx = 0;
|
||||
@@ -126,8 +127,10 @@ static void cut(v4_fabric *f, unsigned a, unsigned pa)
|
||||
if (other->kind == V4_WIRE_NODE && other->node == a && other->port == pa) {
|
||||
other->kind = V4_WIRE_NONE; other->device = 0;
|
||||
other->rx = 0; other->tx = 0; /* the same two queues as w's */
|
||||
f->place[w->node].cut = 1;
|
||||
}
|
||||
}
|
||||
if (w->kind != V4_WIRE_NONE) f->place[a].cut = 1; /* a node asleep for room on another wire is woken (operation 9) */
|
||||
if (f->queue) { give_queue(f, w->rx); give_queue(f, w->tx); }
|
||||
w->kind = V4_WIRE_NONE;
|
||||
w->device = 0;
|
||||
@@ -226,6 +229,16 @@ static int awake(const v4_fabric *f, unsigned id)
|
||||
return id < f->capacity && f->place[id].node && !f->place[id].asleep;
|
||||
}
|
||||
|
||||
/* 1 if a word written to this end of a wire will not be read: the other end
|
||||
* is a device that takes no words, or a node that speaks whole messages --
|
||||
* one that has asked for a whole-message operation since it was born. */
|
||||
static int no_reader(const v4_fabric *f, const v4_wire *w)
|
||||
{
|
||||
if (w->kind == V4_WIRE_DEVICE) return w->device->take == 0;
|
||||
if (w->kind == V4_WIRE_NODE && w->node < f->capacity && f->place[w->node].node) return f->place[w->node].node->n.spoke != 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* What node `a` wrote to one of its ports, handed to whatever is there. */
|
||||
static unsigned hand_over_write(v4_fabric *f, unsigned a)
|
||||
{
|
||||
@@ -386,7 +399,8 @@ static int operate(v4_fabric *f, unsigned id, v4_cell *how)
|
||||
if (!tx) { *how = V4_WIRE_NO_ONE; break; }
|
||||
if (a < 0 || a > (v4_cell)V4_WIRE_CELLS) { *how = V4_WIRE_NO_ROOM; break; } /* no waiting can make that room */
|
||||
if (v4_wire_room(tx, (unsigned)a) == V4_WIRE_DONE) { *how = V4_WIRE_DONE; break; }
|
||||
if (!arrived(f, id) && !freed(f, id)) return 0;
|
||||
if (!arrived(f, id) && !freed(f, id) && !f->place[id].cut) return 0;
|
||||
f->place[id].cut = 0;
|
||||
for (cells = 0; cells < V4_PORTS; cells++) /* woken: the room that has come on any of its wires is seen */
|
||||
if (f->place[id].wire[cells].tx) f->place[id].wire[cells].tx->freed = 0;
|
||||
*how = V4_WIRE_NO_ROOM;
|
||||
@@ -457,13 +471,14 @@ 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 at one port that nothing is wired to */
|
||||
/* a node blocked at one port that nothing is wired to; or blocked writing a
|
||||
* word to what will not read one (fabric.h, A WORD NO ONE WILL READ) */
|
||||
if (f->gone_error != 0)
|
||||
for (i = 0; i < f->capacity; i++) {
|
||||
v4_node *n;
|
||||
if (!awake(f, i)) continue;
|
||||
n = &f->place[i].node->n;
|
||||
if ((n->asking && f->place[i].wire[n->ask_port].kind == V4_WIRE_NONE)
|
||||
if ((n->asking && (f->place[i].wire[n->ask_port].kind == V4_WIRE_NONE || no_reader(f, &f->place[i].wire[n->ask_port])))
|
||||
|| (n->reading && !n->given && n->read_port != V4_PORT_ANY && f->place[i].wire[n->read_port].kind == V4_WIRE_NONE))
|
||||
done += (unsigned)v4_node_port_gone(n, f->gone_error);
|
||||
}
|
||||
|
||||
+2
-1
@@ -90,7 +90,7 @@ void v4_node_store(v4_node *n, v4_cell addr, v4_cell value)
|
||||
if (port == (int)V4_PORT_WIRE) { n->wire = (value >= 0 && value < (v4_cell)V4_PORTS) ? (unsigned)value : V4_PORTS; return; }
|
||||
if (port == (int)V4_PORT_A) { n->wire_a = value; return; }
|
||||
if (port == (int)V4_PORT_B) { n->wire_b = value; return; }
|
||||
if (port == (int)V4_PORT_DO) { n->do_op = value; n->doing = 1; return; }
|
||||
if (port == (int)V4_PORT_DO) { n->do_op = value; n->doing = 1; n->spoke = 1; return; }
|
||||
if (port >= 0 && port < (int)V4_PORTS) {
|
||||
n->request = value;
|
||||
n->ask_port = (unsigned)port;
|
||||
@@ -193,6 +193,7 @@ void v4_node_port_attach(v4_node *n, v4_cell base)
|
||||
n->wire_a = 0;
|
||||
n->wire_b = 0;
|
||||
n->doing = 0;
|
||||
n->spoke = 0;
|
||||
n->do_op = 0;
|
||||
n->how = 0;
|
||||
n->have = 0;
|
||||
|
||||
+1
-1
@@ -225,7 +225,7 @@ static int run_line(const v4_boot *b, const char *text, unsigned len, char *keep
|
||||
|
||||
if (text) { /* with none, the node has a line waiting on its wire (boot.h) */
|
||||
if (!v4_message_text(&out, 0, CONSOLE_ID, V4_MSG_TEXT, text, len)) return V4_BOOT_LINE_TOO_LONG;
|
||||
if (v4_wire_put(TO_NODE, out.word, out.word + V4_MSG_HEADER) != V4_WIRE_DONE) return V4_BOOT_LINE_STOPPED;
|
||||
if (v4_wire_put(TO_NODE, out.word, out.word + V4_MSG_HEADER) != V4_WIRE_DONE) return V4_BOOT_LINE_REFUSED; /* no room: refused at once, as any message is */
|
||||
}
|
||||
for (;;) {
|
||||
int awake = boot_step(b);
|
||||
|
||||
+3
-1
@@ -90,6 +90,7 @@
|
||||
#define S_ON (BUF0_W - 38) /* and whether its mark has been put at its first message */
|
||||
#define KEEP (BUF0_W - 40) /* the port the answer to the text being done goes by, on whose wire 8 cells are kept for it; -1: none */
|
||||
#define DEFER (BUF0_W - 41) /* a port whose wire had no room for the answer to text that waits to be begun; -1: none */
|
||||
#define D_MASK (BUF0_W - 8) /* and a bit for each such port: text whose answer goes by one is not begun on this pass */
|
||||
#define IN_HDR (BUF0_W - 56) /* the seven words of the message a wire's mark is at */
|
||||
#define ONE (BUF0_W - 49) /* the one word of text of a NACK, a GONE or an answer, coming or going */
|
||||
#define OUT_HDR (BUF0_W - 112) /* the seven words of a message this node is putting on a wire */
|
||||
@@ -104,7 +105,7 @@
|
||||
#define SEND_PTR (BUF0_W - 101) /* where the next word of a text being made ready to send goes */
|
||||
#define OUT_TEXT (OUT_W - 64) /* what was printed, four characters to a cell, as it goes on the wire: 64 cells */
|
||||
#define SEND_TEXT (OUT_W - 400) /* the text of a message SEND is putting, four characters to a cell: 256 cells */
|
||||
/* FREE, plain memory: BUF0_W - 8; - 32 .. - 21; - 122 .. - 113; BUF0_W - 144 .. - 141 (what a flush makes zero after
|
||||
/* FREE, plain memory: BUF0_W - 32 .. - 21; - 122 .. - 113; BUF0_W - 144 .. - 141 (what a flush makes zero after
|
||||
* a full output buffer); and OUT_W - 144 .. OUT_W - 65. They and
|
||||
* the cells above held the messages waiting, the refusals owed and what went with them (MESH.md 7a, 7b), which a
|
||||
* node no longer keeps. */
|
||||
@@ -227,6 +228,7 @@ static int host_load(v4_text *tx, v4_node *n, const char *const *files, unsigned
|
||||
v4_text_constant(tx, "(S-ON)", S_ON);
|
||||
v4_text_constant(tx, "(KEEP)", KEEP);
|
||||
v4_text_constant(tx, "(DEFER)", DEFER);
|
||||
v4_text_constant(tx, "(D-MASK)", D_MASK);
|
||||
v4_text_constant(tx, "(IN)", IN_HDR);
|
||||
v4_text_constant(tx, "(ONE)", ONE);
|
||||
v4_text_constant(tx, "(OUT-HDR)", OUT_HDR);
|
||||
|
||||
@@ -350,6 +350,98 @@ int main(void)
|
||||
"a node that can take an error is let go, and the error is raised on it: its P is its handler");
|
||||
CHECK(!v4_node_port_gone(&ND(c)->n, 18), "a node that is not blocked at a port is not touched");
|
||||
|
||||
/* ---- A WORD WRITTEN TO WHAT WILL NOT READ ONE (found by the final review of step 6e) ----
|
||||
* A node that writes a word to a port is blocked until it is taken. Two things will never take it: a
|
||||
* device that takes no words -- one that speaks whole messages only -- and a node that is asleep at its
|
||||
* wires, which executes nothing until a message comes. The writer is let go, as from a port with no one
|
||||
* on it. A neighbour that is doing something else, or that the fabric has put to sleep, may yet read:
|
||||
* the writer waits. */
|
||||
{
|
||||
static v4_wire_queue wq[4];
|
||||
static const v4_device mute = { 0, 0, 0 }; /* it takes and gives no words */
|
||||
static const v4_cell one[1] = { 5 };
|
||||
static stream s;
|
||||
static v4_device giver;
|
||||
v4_fabric_init(&f, places, 4);
|
||||
v4_fabric_queues(&f, wq, 4);
|
||||
a = loaded(0); /* writes a word to its port 0, and then counts in OUT */
|
||||
LIT(PB + 0); O(BANG_B); LIT(7); O(STORE_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_device(&f, a, 0, &mute), "a writer, wired to a device that takes no words");
|
||||
(void)settle(100);
|
||||
CHECK(ND(a)->n.asking && ND(a)->n.mem[OUT] == 0, "it is blocked writing");
|
||||
v4_fabric_gone_error(&f, 18);
|
||||
(void)settle(100);
|
||||
CHECK(ND(a)->n.asking && ND(a)->n.faults == 0, "a bare node, which cannot take an error, waits there");
|
||||
v4_node_error_attach(&ND(a)->n, OUT + 20);
|
||||
v4_node_fault_attach(&ND(a)->n, 900);
|
||||
(void)v4_fabric_step(&f);
|
||||
CHECK(!ND(a)->n.asking && ND(a)->n.fault_kind == V4_FAULT_RAISED && ND(a)->n.fault_addr == 18 && ND(a)->n.mem[OUT + 20] == 18,
|
||||
"a node that can take one is let go: no one on that port");
|
||||
|
||||
v4_fabric_init(&f, places, 4);
|
||||
v4_fabric_queues(&f, wq, 4);
|
||||
v4_fabric_gone_error(&f, 18);
|
||||
a = loaded(0);
|
||||
LIT(PB + 0); O(BANG_B); LIT(7); O(STORE_B);
|
||||
wait_for_ever();
|
||||
b = loaded(1); /* reads a word from its port 5, and then sleeps at its wires */
|
||||
LIT(PB + 5); O(BANG_B); O(FETCH_B); O(DROP);
|
||||
LIT(P_DO); O(BANG_B); LIT(8); O(STORE_B);
|
||||
wait_for_ever();
|
||||
CHECK(v4_asm_ok(&as) && v4_fabric_wire(&f, a, 0, b, 3), "a writer wired to a node that is waiting to read another port");
|
||||
v4_node_error_attach(&ND(a)->n, OUT + 20);
|
||||
v4_node_fault_attach(&ND(a)->n, 900);
|
||||
(void)settle(200);
|
||||
CHECK(ND(a)->n.asking && ND(a)->n.faults == 0 && ND(b)->n.reading, "the neighbour is not asleep at its wires and may yet read: the writer waits");
|
||||
v4_fabric_sleep(&f, b);
|
||||
memset(&s, 0, sizeof s); s.words = one; s.count = 1;
|
||||
giver.give = stream_give; giver.take = 0; giver.self = &s;
|
||||
CHECK(v4_fabric_wire_device(&f, b, 5, &giver), "the neighbour is put to sleep by the fabric, and a device with a word for it is wired to its port 5");
|
||||
(void)settle(200);
|
||||
CHECK(ND(a)->n.asking && ND(a)->n.faults == 0 && !v4_node_doing(&ND(b)->n), "a neighbour the fabric has put to sleep takes nothing and does nothing: the writer waits");
|
||||
v4_fabric_wake(&f, b);
|
||||
for (i = 0; i < 200 && ND(a)->n.asking; i++) (void)v4_fabric_step(&f);
|
||||
CHECK(v4_node_doing(&ND(b)->n) && ND(b)->n.do_op == 8, "woken, the neighbour takes its word and sleeps at its wires");
|
||||
CHECK(!ND(a)->n.asking && ND(a)->n.fault_kind == V4_FAULT_RAISED && ND(a)->n.fault_addr == 18, "and the writer is let go: no one on that port will read a word");
|
||||
|
||||
/* nor does it matter that such a node is awake and running: once a node has asked for a whole message
|
||||
* it is not one that words are written to. A stuck node does not hold whoever writes it a word. */
|
||||
v4_fabric_init(&f, places, 4);
|
||||
v4_fabric_queues(&f, wq, 4);
|
||||
v4_fabric_gone_error(&f, 18);
|
||||
a = loaded(0);
|
||||
LIT(PB + 0); O(BANG_B); LIT(7); O(STORE_B);
|
||||
wait_for_ever();
|
||||
b = loaded(1); /* reads a word from its port 5, asks whether its wire 3 has room, and then counts for ever */
|
||||
LIT(PB + 5); O(BANG_B); O(FETCH_B); O(DROP);
|
||||
LIT(P_WIRE); O(BANG_B); LIT(3); O(STORE_B);
|
||||
LIT(P_A); O(BANG_B); LIT(8); O(STORE_B);
|
||||
LIT(P_DO); O(BANG_B); LIT(10); O(STORE_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), "a writer wired to a node that has not yet asked anything of a wire");
|
||||
v4_node_error_attach(&ND(a)->n, OUT + 20);
|
||||
v4_node_fault_attach(&ND(a)->n, 900);
|
||||
(void)settle(200);
|
||||
CHECK(ND(a)->n.asking && ND(a)->n.faults == 0, "the writer waits");
|
||||
memset(&s, 0, sizeof s); s.words = one; s.count = 1;
|
||||
CHECK(v4_fabric_wire_device(&f, b, 5, &giver), "the neighbour is given its word");
|
||||
for (i = 0; i < 200 && ND(a)->n.asking; i++) (void)v4_fabric_step(&f);
|
||||
CHECK(!ND(a)->n.asking && ND(a)->n.fault_kind == V4_FAULT_RAISED && ND(a)->n.fault_addr == 18, "it asks for room, and the writer is let go");
|
||||
for (i = 0; i < 20; i++) (void)v4_fabric_step(&f);
|
||||
CHECK(!v4_node_doing(&ND(b)->n) && ND(b)->n.mem[OUT] > 0, "though that node is not asleep: it goes on counting");
|
||||
}
|
||||
|
||||
/* ---- asleep, awake, and removed, while looping; and a node born while others run ---- */
|
||||
v4_fabric_init(&f, places, 4);
|
||||
a = loaded(0); /* counts in OUT for ever */
|
||||
@@ -710,6 +802,40 @@ int main(void)
|
||||
(void)v4_fabric_step(&f);
|
||||
CHECK(!ND(a)->n.doing && ND(a)->n.how == 1 && f.place[a].wire[0].tx->used + 200 > V4_WIRE_CELLS, "it wakes, and how it went says 1: no room, but a message");
|
||||
|
||||
/* A node asleep for room on one wire is woken when another of its wires is cut, or the node on it
|
||||
* removed: it may be keeping something to put there, and must find out that it cannot (found by the
|
||||
* final review of step 6e: before, it slept on until something else happened). */
|
||||
v4_fabric_init(&f, more_places, 8);
|
||||
v4_fabric_queues(&f, qpool, 8);
|
||||
a = (unsigned)v4_fabric_add(&f, &pool[0], PB);
|
||||
b = (unsigned)v4_fabric_add(&f, &pool[1], PB);
|
||||
c = (unsigned)v4_fabric_add(&f, &pool[2], PB);
|
||||
CHECK(v4_fabric_wire(&f, a, 0, b, 3) && v4_fabric_wire(&f, a, 1, c, 2), "a node with two wires");
|
||||
fill(f.place[a].wire[0].tx, 0);
|
||||
fill(f.place[a].wire[1].tx, 0);
|
||||
(void)v4_node_fetch(&ND(a)->n, P_HAVE);
|
||||
(void)v4_fabric_step(&f);
|
||||
CHECK(ask(a, 0, 100, 0, 9) == -99, "both full: asleep for room on wire 0");
|
||||
CHECK(v4_fabric_unwire(&f, a, 1), "its wire 1 is cut");
|
||||
(void)v4_fabric_step(&f);
|
||||
CHECK(!ND(a)->n.doing && ND(a)->n.how == 1, "it wakes, told 1: the wire it named has no room, but something has changed");
|
||||
CHECK(ask(a, 1, 100, 0, 10) == 2, "it asks, and finds no one on port 1");
|
||||
CHECK(ask(a, 0, 100, 0, 9) == -99, "asleep for room on wire 0 again");
|
||||
for (i = 0; i < 100; i++) (void)v4_fabric_step(&f);
|
||||
CHECK(ND(a)->n.doing, "and it is not woken twice for the one cut");
|
||||
CHECK(v4_fabric_wire(&f, a, 1, c, 2), "the wire is made again");
|
||||
fill(f.place[a].wire[1].tx, 0);
|
||||
for (i = 0; i < 100; i++) (void)v4_fabric_step(&f);
|
||||
CHECK(ND(a)->n.doing, "a wire being made does not wake it");
|
||||
CHECK(v4_fabric_remove(&f, c) == &pool[2], "the node on wire 1 is removed");
|
||||
(void)v4_fabric_step(&f);
|
||||
CHECK(!ND(a)->n.doing && ND(a)->n.how == 1, "it wakes, told 1");
|
||||
ND(a)->n.doing = 0;
|
||||
v4_node_store(&ND(a)->n, P_DO, 8);
|
||||
CHECK(v4_fabric_wire(&f, a, 1, b, 4) && v4_fabric_unwire(&f, a, 1), "asleep for a message (8), with a wire made and cut");
|
||||
for (i = 0; i < 100; i++) (void)v4_fabric_step(&f);
|
||||
CHECK(ND(a)->n.doing, "a node asleep for a message is not woken by a cut: it keeps nothing");
|
||||
|
||||
/* SLEEP FOR ROOM IS WOKEN BY ROOM ON ANY OF THE NODE'S WIRES (MESH.md 7d.3): a node may be waiting to
|
||||
* put on more than one, and names only one */
|
||||
v4_fabric_init(&f, more_places, 8);
|
||||
|
||||
+149
-27
@@ -262,35 +262,76 @@ static int answers(v4_cell node, unsigned id)
|
||||
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. */
|
||||
/* AN EXCHANGE, DISTURBED AT EVERY STEP. The exchange that start() begins is played from the mesh as kept:
|
||||
* once whole, to see how many steps it takes, and then once for every one of those steps with the mesh
|
||||
* disturbed at that step --
|
||||
* 1 node 11 removed, and node 12 then wired to node 10, as whoever removed it would, so that it can be asked;
|
||||
* 2 node 12 removed;
|
||||
* 3 the wire between nodes 11 and 12 cut and made again at once: what waited on it is let go.
|
||||
* After each, every node left must come to rest, asleep and blocked at no port, and answer. With `moments`
|
||||
* only the steps at which something the fabric keeps had changed are tried -- what is on a wire, or what a
|
||||
* node asks of one: for an exchange too long to disturb at every step. A removal between two such steps
|
||||
* finds the mesh as the one before it did.
|
||||
* How many steps the exchange takes; how many disturbances were tried; how many went wrong, and the first. */
|
||||
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)
|
||||
static v4_cell start_node;
|
||||
static const char *start_text;
|
||||
static int start_plain(void) { return put_text(start_node, start_text); }
|
||||
static int hera_busy(void) { return pool[hera].n.mem[QUIET] == 0; }
|
||||
/* Text for node 12 that prints, with node 10 made busy and the wire from node 11 to node 10 full but for 7
|
||||
* cells: what node 12 prints, and how its text ended, are held by node 11, asleep for room (MESH.md 7d.4). */
|
||||
static int start_held(void)
|
||||
{
|
||||
unsigned long before;
|
||||
static v4_cell big[V4_WIRE_HEADER + V4_MSG_MAX_CHARS / 4u];
|
||||
v4_wire_queue *q = places[mid].wire[2].tx;
|
||||
unsigned k;
|
||||
int ok = put_text(12, "A") && put_text(10, "SLOW") && run_until(hera_busy, 5000); /* node 10 has passed the one on and begun the other */
|
||||
memset(big, 0, sizeof big);
|
||||
big[0] = CONSOLE_ID; big[1] = 12; big[2] = V4_MSG_OUTPUT; big[3] = 16; big[6] = 1024;
|
||||
for (k = 0; k < 3; k++) ok = ok && v4_wire_put(q, big, big + V4_WIRE_HEADER) == V4_WIRE_DONE;
|
||||
big[6] = 884;
|
||||
return ok && v4_wire_put(q, big, big + V4_WIRE_HEADER) == V4_WIRE_DONE && V4_WIRE_CELLS - q->used == 7;
|
||||
}
|
||||
/* what the fabric keeps, in a number: what every wire holds and what every node asks of one */
|
||||
static unsigned long fabric_mark(void)
|
||||
{
|
||||
unsigned long h = 1469598103UL;
|
||||
unsigned k;
|
||||
for (k = 0; k < 3; k++) if (v4_fabric_node_at(&f, k)) h = (h ^ (unsigned long)(pool[k].n.doing * 16 + (int)pool[k].n.do_op)) * 16777619UL;
|
||||
for (k = 0; k < QUEUES; k++) h = ((h ^ queues[k].used) * 16777619UL ^ queues[k].head) * 16777619UL;
|
||||
return h;
|
||||
}
|
||||
static unsigned disturbed_at_every_step(int (*start)(void), unsigned how, int moments, unsigned *tried, unsigned *wrong, unsigned *first_wrong)
|
||||
{
|
||||
unsigned long before, mark, last = 0;
|
||||
unsigned whole, s;
|
||||
*wrong = 0; *first_wrong = 0;
|
||||
*tried = 0; *wrong = 0; *first_wrong = 0;
|
||||
put_back();
|
||||
before = steps_run;
|
||||
if (!put_text(node, text) || !run()) { *wrong = 1; return 0; }
|
||||
saw_mid_hold = 0; watch = watch_mid_holds;
|
||||
if (!start() || !run()) { watch = 0; *wrong = 1; return 0; }
|
||||
watch = 0;
|
||||
whole = (unsigned)(steps_run - before);
|
||||
put_back();
|
||||
if (!put_text(node, text)) { *wrong = 1; return 0; }
|
||||
if (!start()) { *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;
|
||||
mark = fabric_mark();
|
||||
if (!moments || s == 0 || mark != last) {
|
||||
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 */
|
||||
if (how == 1) ok = v4_fabric_remove(&f, mid) == &pool[mid] && run() && at_rest(hera) && at_rest(far)
|
||||
&& v4_fabric_wire(&f, hera, 2, far, 2) && answers(12, far) && answers(10, hera);
|
||||
else if (how == 2) ok = v4_fabric_remove(&f, far) == &pool[far] && run() && at_rest(hera) && at_rest(mid) && answers(11, mid) && answers(10, hera);
|
||||
else ok = v4_fabric_unwire(&f, mid, 3) && v4_fabric_wire(&f, mid, 3, far, 2) && run() && at_rest(hera) && at_rest(mid) && at_rest(far)
|
||||
&& answers(12, far) && answers(11, mid) && answers(10, hera);
|
||||
(*tried)++;
|
||||
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;
|
||||
}
|
||||
last = mark;
|
||||
(void)v4_fabric_step(&f); (void)console_takes();
|
||||
}
|
||||
return whole;
|
||||
@@ -995,32 +1036,113 @@ int main(void)
|
||||
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.
|
||||
/* ---- A WORD WRITTEN TO A PORT, PORT!, HOLDS NO ONE (found by the final review of step 6e) ----
|
||||
* A node's neighbours speak whole messages and are asleep at their wires; so is its console. A word
|
||||
* written to one of them will never be read. The line that wrote it ends in an error and the node goes
|
||||
* on; before, it was blocked for ever, and every node beyond it was cut off. */
|
||||
CHECK(row(), "a row made afresh");
|
||||
step_cap = 2000000;
|
||||
CHECK(strstr(tell(10, "5 2 PORT! 65 EMIT"), "No one on that port") != NULL && strchr(printed, 'A') == NULL && ended == 1 && ended_how == V4_TEXT_ERROR && asleep(hera),
|
||||
"node 10 writes a word to node 11's port: its line ends No one on that port: \"%s\"", printed);
|
||||
CHECK(strcmp(tell(10, "1 2 + ."), "3 ") == 0 && strcmp(tell(11, "20 22 + ."), "42 ") == 0 && strcmp(tell(12, "7 8 * ."), "56 ") == 0, "and all three answer");
|
||||
CHECK(strstr(tell(10, "5 1 PORT!"), "No one on that port") != NULL && ended_how == V4_TEXT_ERROR && strcmp(tell(10, "1 2 + ."), "3 ") == 0,
|
||||
"the same for a word written to the console's port: \"%s\"", printed);
|
||||
CHECK(strstr(tell(11, "5 3 PORT!"), "No one on that port") != NULL && ended_from == 11 && strcmp(tell(12, "7 8 * ."), "56 ") == 0 && strcmp(tell(11, "20 22 + ."), "42 ") == 0,
|
||||
"and for node 11 writing to node 12's: node 12 is not cut off");
|
||||
stuck = 1u << mid;
|
||||
(void)tell(11, ": C BEGIN 0 UNTIL ; C");
|
||||
CHECK(ended == 0 && !asleep(mid), "node 11 is stuck in a loop: it does not sleep");
|
||||
CHECK(strstr(tell(10, "5 2 PORT!"), "No one on that port") != NULL && ended_how == V4_TEXT_ERROR && strcmp(tell(10, "1 2 + ."), "3 ") == 0,
|
||||
"a word node 10 writes to it is refused all the same, and node 10 can be typed to: \"%s\"", printed);
|
||||
stuck = 0;
|
||||
step_cap = 20000000;
|
||||
|
||||
/* ---- TWO TEXTS FROM ONE NODE ARE BEGUN IN THE ORDER THEY CAME (acceptance 8; found by the final review) ----
|
||||
* Node 12 has two texts from node 10 on its wire, and the wire their answers go by has 7 cells free:
|
||||
* neither can be begun. Node 11, which was not taking, then takes a message off that wire -- at every
|
||||
* step in turn, so that the room comes before node 12 looks at the first text, between its look at the
|
||||
* first and at the second, and after both. Whenever it comes, the first is begun first. */
|
||||
{
|
||||
static v4_cell big[V4_WIRE_HEADER + V4_MSG_MAX_CHARS / 4u], hd[V4_WIRE_HEADER];
|
||||
static v4_message m;
|
||||
unsigned k, wrong = 0, first_wrong = 0, undone = 0;
|
||||
v4_wire_queue *out, *in;
|
||||
CHECK(row() && told(12, ": X1 65 EMIT ; : X2 66 EMIT ;"), "a row made afresh; node 12 has two words that print");
|
||||
v4_fabric_sleep(&f, mid); /* node 11 takes nothing for now */
|
||||
out = places[far].wire[2].tx; in = places[far].wire[2].rx;
|
||||
memset(big, 0, sizeof big);
|
||||
big[0] = 1; big[1] = 12; big[2] = V4_MSG_OUTPUT; big[3] = 16;
|
||||
big[6] = 1024; for (i = 0; i < 3; i++) (void)v4_wire_put(out, big, big + V4_WIRE_HEADER);
|
||||
big[6] = 884; (void)v4_wire_put(out, big, big + V4_WIRE_HEADER);
|
||||
CHECK(V4_WIRE_CELLS - out->used == 7, "the wire from node 12 to node 11 has 7 cells free: %u", V4_WIRE_CELLS - out->used);
|
||||
CHECK(v4_message_text(&m, 12, 10, V4_MSG_TEXT, "X1", 2) && (m.word[3] = 16, m.word[5] = 1, v4_wire_put(in, m.word, m.word + V4_MSG_HEADER) == V4_WIRE_DONE)
|
||||
&& v4_message_text(&m, 12, 10, V4_MSG_TEXT, "X2", 2) && (m.word[3] = 16, m.word[5] = 2, v4_wire_put(in, m.word, m.word + V4_MSG_HEADER) == V4_WIRE_DONE),
|
||||
"two texts from node 10 are on the wire to node 12, numbered 1 and 2");
|
||||
keep();
|
||||
for (k = 0; k < 700; k++) {
|
||||
unsigned began = 0, seq[2] = { 0, 0 };
|
||||
put_back();
|
||||
for (i = 0; i < 100000 && began < 2; i++) {
|
||||
const v4_node *n = &pool[far].n;
|
||||
int kept = n->mem[KEEP] >= 0;
|
||||
if (i == k) { v4_wire_first(out); (void)v4_wire_look(out, hd); (void)v4_wire_drop(out); }
|
||||
(void)v4_fabric_step(&f); (void)console_takes();
|
||||
if (!kept && n->mem[KEEP] >= 0) seq[began++] = (unsigned)n->mem[MSG + 5];
|
||||
}
|
||||
if (began < 2) undone++;
|
||||
else if (seq[0] != 1 || seq[1] != 2) { if (!wrong) first_wrong = k; wrong++; }
|
||||
}
|
||||
CHECK(undone == 0 && wrong == 0, "whenever the room came, both texts were done, the first first: %u not done, %u in the wrong order, the first when it came at step %u", undone, wrong, first_wrong);
|
||||
}
|
||||
|
||||
/* ---- A NODE REMOVED, OR A WIRE CUT, 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, again with node 12 removed, and again with the wire between them cut and made again: the
|
||||
* nodes left come to rest, blocked at 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. */
|
||||
* mesh does nothing, and every one of them would be a removal played to the end.
|
||||
* WHAT "ANSWERS" MEANS HERE. A node that was waiting for an answer from a node now removed, or for one
|
||||
* that was on a wire now cut, is still waiting when the mesh comes to rest: removing a node tells no one
|
||||
* (Hera's KILL does: test_host_unit.c). Its wait is ended by the line it is then typed, "Interrupted",
|
||||
* and it answers. */
|
||||
{
|
||||
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;
|
||||
static const char *const how_name[4] = { "", "node 11 removed", "node 12 removed", "the wire between nodes 11 and 12 cut and made again" };
|
||||
unsigned e, g, whole, tried, wrong, first, all = 0;
|
||||
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);
|
||||
start_node = ex[e].node; start_text = ex[e].text;
|
||||
for (g = 1; g <= 3; g++) {
|
||||
whole = disturbed_at_every_step(start_plain, g, 0, &tried, &wrong, &first);
|
||||
all += tried;
|
||||
CHECK(whole > 0 && wrong == 0, "%s, in %u steps: with %s at each of them the rest come to rest and answer: %u did not, the first at step %u",
|
||||
ex[e].what, whole, how_name[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");
|
||||
|
||||
/* and with what node 12 prints held at node 11, which sleeps for room: at every step at which
|
||||
* anything on a wire, or what a node asks of one, has changed */
|
||||
CHECK(row() && told(12, ": A 7 8 * . ;") && told(10, ": SLOW 3000 0 DO LOOP ;") && told(10, ASK) && told(11, ASK) && told(12, ASK), "a row made afresh for output held at a full wire");
|
||||
step_cap = 2000000;
|
||||
keep();
|
||||
for (g = 1; g <= 3; g++) {
|
||||
whole = disturbed_at_every_step(start_held, g, 1, &tried, &wrong, &first);
|
||||
all += tried;
|
||||
CHECK(whole > 0 && saw_mid_hold > 0, "text for node 12 that prints, node 10 busy and the wire to it full: node 11 held what was printed, asleep for room, for %u of %u steps", saw_mid_hold, whole);
|
||||
CHECK(tried > 20 && wrong == 0, "with %s at each of the %u steps at which a wire or a node's asking changed, the rest come to rest and answer: %u did not, the first at step %u",
|
||||
how_name[g], tried, wrong, first);
|
||||
}
|
||||
printf(" a node removed or a wire cut: %u times in all\n", all);
|
||||
step_cap = 20000000;
|
||||
}
|
||||
|
||||
|
||||
@@ -94,6 +94,7 @@ int main(void)
|
||||
if (leaving) { fflush(stdout); return 0; }
|
||||
else if (how == V4_TEXT_ERROR) fputs(" ERROR\n", stdout);
|
||||
else if (how == V4_BOOT_LINE_TOO_LONG) fputs("Line too long\n ERROR\n", stdout);
|
||||
else if (how == V4_BOOT_LINE_REFUSED) fputs("Message refused\n ERROR\n", stdout); /* the node's wire is full: error 19's words */
|
||||
else if (how == V4_BOOT_LINE_NO_INPUT) { putchar('\n'); return 0; }
|
||||
else if (how == V4_BOOT_LINE_STOPPED) { fflush(stdout); fprintf(stderr, "starforth4: the node stopped on a fault\n"); return 1; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user