From a041b401ea34fbf528a2ce9925ccbc4f89a8dc49 Mon Sep 17 00:00:00 2001 From: rajames Date: Tue, 6 Oct 2026 11:19:46 -0400 Subject: [PATCH] feat(v4.0.0): a node is sent text as a message and sends back what it prints MESH.md step 3. The ports are the transport; the message is what is transported: to, from, type, heat and TTL, ACL tag, sequence, length, then text four characters to a word. - quit.v4: a node with nothing to do is blocked reading "any port"; text for it is interpreted; (FINISH) sends what it printed and then how the text ended, and it waits again - core.v4: EMIT keeps what is printed, (FLUSH-OUT) and (HDR) send it to the sender on the port the message came on. EMIT still needs one free data cell and no more; it works on the return stack and in A and B - message.h/.c: the same format for whatever is on a port and is not a node - boot.c: the boot is the node's console on port 1 and its kernel on port 0 - the prompt tests are a console that speaks messages - gone: v4_line_begin, v4_line_done, v4_line_status; writing a node's input buffer and setting its P from outside; any use of CONSOLE-TX Verified: make -C v4 test (test_host_quit.c 1283 checks, the full-stack figures unchanged) and make -C v4 sanitize pass; hosted-check passes on three ISAs with POST 550 of 550; clean qemu with STARFORTH_V4=1 passes POST and answers lines typed at each prompt on amd64, aarch64 and riscv64 (logs/20261006-110551, -111621, -111341). -110837 is an aarch64 run ended by the test wrapper's limit while still in UEFI firmware; it shows nothing about v4. Not done: KEY, EXPECT and QUERY still read the console's input registers; a message not for this node is let go (step 4). Co-Authored-By: Claude Opus 5.5 --- capsules/BLOCK_MAP.md | 2 +- capsules/v4/nucleus-64.f18 | Bin 48536 -> 49456 bytes docs/v4.0.0/MESH.md | 23 +++ kernel/Makefile | 2 +- kernel/src/v4/sk_v4.c | 4 +- .../amd64/qemu-amd64-20261006-110551.log | 130 +++++++++++++ .../aarch64/qemu-aarch64-20261006-110837.log | 2 + .../riscv64/qemu-riscv64-20261006-111341.log | 174 ++++++++++++++++++ .../aarch64/qemu-aarch64-20261006-111621.log | 104 +++++++++++ v4/Makefile | 2 +- v4/README.md | 24 +-- v4/capsule/core.v4 | 64 ++++++- v4/capsule/quit.v4 | 92 ++++++--- v4/include/v4/boot.h | 6 +- v4/include/v4/image.h | 38 +--- v4/include/v4/message.h | 63 +++++++ v4/src/image.c | 33 ---- v4/src/message.c | 44 +++++ v4/system/boot.c | 72 ++++++-- v4/tests/host_map.h | 12 ++ v4/tests/test_host_input.c | 5 +- v4/tests/test_host_quit.c | 113 ++++++++---- v4/tools/hosted.c | 4 +- v4/tools/mkimage.c | 9 +- 24 files changed, 844 insertions(+), 178 deletions(-) create mode 100644 logs/20261006-110551/amd64/qemu-amd64-20261006-110551.log create mode 100644 logs/20261006-110837/aarch64/qemu-aarch64-20261006-110837.log create mode 100644 logs/20261006-111341/riscv64/qemu-riscv64-20261006-111341.log create mode 100644 logs/20261006-111621/aarch64/qemu-aarch64-20261006-111621.log create mode 100644 v4/include/v4/message.h create mode 100644 v4/src/message.c diff --git a/capsules/BLOCK_MAP.md b/capsules/BLOCK_MAP.md index 4fe58223..a141bddb 100644 --- a/capsules/BLOCK_MAP.md +++ b/capsules/BLOCK_MAP.md @@ -1,5 +1,5 @@ # Capsule Block Manifest — Auto-generated - + diff --git a/capsules/v4/nucleus-64.f18 b/capsules/v4/nucleus-64.f18 index 44bc82e55757b094bade293c78d28df79d43ccb8..72026e29e8e5f8cb92183d7fafdfd94347d76515 100644 GIT binary patch literal 49456 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 z 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 F{C|N0&SL-o literal 48536 zcmb__3w%|@wf@e@Ny0NgK(N(Y53N?f1}W;5myjnUB_tsU52Zd3(4auJAt)l1P_b4- zkQS|?VpR0{03Q`C3TQyCTEz&ytuJnk7Oi5GAU@$gv)1?RbN0Y7dhdV#^2<6ivtF}i z&6?RWv-kGj*)hs9S6BPbT$lAy=rM@4+4BZjIMmDBWZ@9V9qcU?eTI5b$v6BJW>z;@Ja4f=%Fie$6@5nKRtXdw^Y0Y= z7zjAhTe8ajoVxfNu@C8~zn|GBWY0)`4k#5AA(aPM)q2NP`!f~kvpsKs{dtDhN%S~? z>r^LQ)c1XnQ`Gm46&Bxxe))3AKVS>Zl?>l+%2hdv7T{GKt$axz)USMp$Yp*czc(lq zOhu{$(5>HPsNbbdeJ*m+TMwVI(Xudb$)RA$x_*lxf~pAgGk>-g_#yfR@bNrFA9mV~ zdo1381Ln_MtRLmBS$ww01-j?ARKrf%AXV%7h3ueQET7G{TfS-eW6CTXAMz&8yTWFg zt6G7#9R3?ywp;vj{|GHe@GIZutc2Z4yg!KlS9^`yZT{57Lqr1c2~EF#)|RWb2M!oH z+8;AjPPA}Lu`RE%{}Qen@mniz`}?&LpDq}x1*@TlvDYq}6)XhY zi9`b+`F#ca`^m3C`FxH1d%XJfmL!s20ZIiAASI1wem8jaIX0_<{b#PU%JN(b^BucC zVl&OPPC-ByLpm+LY@GdB>KH^C#pG`QUWwP(Xn*?G^!>;}+B;fxYPn52V!i*indaJ} zzjD-#0SJ(wQGgbAmThm-)F7T z=32AtRq?a>Q#Abr^w|^VFMg(_ww^j(q!&(9yXS`+t`&%%0DcqjQTzNXMeRF((Yqq| zL&*CG(BD6No+aJIbkl1gyzZdC$7>Wjn*JtD`~~cig>wJ#;i5PBn0_zqIBc=jm-+M~ z=2IWGZ%T@`Z;zC%(jKP%Pgwm7|2zwMkssyIuFPls8jAOPY-wm`<2S}casNphJ5F4= zBGjABya9@SWs%JlYgPF%WU&31mc}u7rdaCjw}kcG2m4ab-AI#<@&5)Z=LFgl?Owhv zY}cJI)ZhRw#qk$S$1F2*HS8NJ^*f-+pq&@O|MF6{eQk^Uri;Z@^I`wM?(hfNuP8<5 zA*MVecg?bQLVm;gmL|dXGZmk9*oc0?^ruPeMSp2QyPgI9*(vbPS?a&^15-Z0){k~1 zfBIo%O8s10J|A{wIpvqEJoijnPQT|sQw_Q2rD**2n>5bR&huM`OFy9>{u}l2*J*!a z{>1MrcNr(uZ(wiYUkd$W-wx1rMEg^}HOqEM`?-G9JpYo{lyADwoeDV@pncu?(ypxU zGSrWFv?uj8_BhS*Ctvo%82UTyNITOXOx%?I$9gyH?H2MQ@{jY?e&PB@z^`d=j@5(w zq7%wwAT6+&3D*r!U5DcVon{zyB}zt*=yW0Iq)dIoc--F^%u%7 zK^)n@e(w17qs(v8{vJVHeWYo3rfG@?Q18tt;d!^|&+9FYX;*0v(r$iC&b&Yc>PP|Ng#J?vZo|2w?2ctfI)2A{|%7Z?fhf$9az{?Bf zZyGPDFXKZz{gv?ZGrQ&`>f`=SFC90==H(TJ?^{M95E=dDIwGR=C=K-0IOAQR_d&c5 z1eur8N9kD4u_zb~xGJSF$71wVG&?_*xRvr-%^=-G;Ew~OzbrUK@uotbDvbLaPa0te zbAK)IDhF~n4ssqud?SCZpfq12^B>kH4Ri#t621S}3;*%zwZz1Mo9!>^JsbU}I->L6 z*y3MGKk;@dKJn&88gI2Z#Pgcfp5)K=j23AFg@Ui4y99RmEnv~&6{0`sxlUv1ca4>k zmRlnC(W4})*c`nUfxaFvmW0o@v}@DCdo88mXF`nUm4%{{=Pd=FE8|f5!HmerB^Ezu z?_b$e{JIYKe+DdHJxu0BZhgv6yg*DreQ4J^Bbk!_9rSeXTiKpQeukA=G)nIeqfo)$ z`N&`F&q#h)vAdzqO28SBbkU3LxDI|8dw++tGxcTrReSXfmM`la85rjOF!-(oHM%B zpMl>;fNaOq@-W^PDBlaXHG=h405QgZoE`+dZI<8HY8_E!Oo%+Kc^!`lVNnk@c&BQDI4k zfq!Q}pk>Wwm0LPY43Zi+)nnNxy-uH z77PCg{1VK|3Q{!=a-E?lRqtiQG)Gx1&OJt$S-45Tjx z{-D%gy=kS@lYT(F`iPcu-C-x{LH;Hl3V-Uw{Byv6%`zR|8JDQHzdt-5W7k6HbBoeTPvPCoTyJs7v?$4t{-TK0wG^RME1truC&{3;y^u-*U1 zY4^*VcE2J?yOWOXZq_;SST_rs!M736)ay)}|8QV;y`Q7K3C%oAIyA>$_RniU_aOA) z{Wa+r$LIHWPvRWyXXe54tX%5Lb~N*Okwbr?U(o(c-w(O&x=X;n=|ho6zCr&j)pl{^ z-j`bcpw)-p|n5h zLphPC_7{#HMi23~?N{pl4E04f_6nmq51>9Hp>HIr<1YEES*H8Pq&Mw%o7M9luKk>L zrC%7mWF9#J`uUlv59$4;x!$Q_Ch|5hn z{~&%PbFbbcaH}BM)x>P5djV$umG*dntDCgVEi6ElI&^n~1s(0pV_Oc7Xq z#H0a2!gOwa$qA zzvg_@+>9n8UbnNq1{_rIF67RVVjT0>%$79y#Nbsdy%sRjHXN#M7CChJL ztS5&GE6Qczzc9Rv=oO|Zmv7;J?mV08Vi&{jeuw+~8l>I+&GGV#G@es9PV}WcCxLDo z;;@k`{e3j;hy2H!d^4{QKGKPd$}_;HHTsmq8}{!Zu_-mSMoiE2r_V@CPs^?e_5T?c z+tT=b2>Wp|{l0^K7ePM91J?UObQNlH*}%3B4xn*b>% zWe5ZS+=24dfIO$L8F8HRF0SJ+9&SZ>41CN!xcKdG)GNTBrSlfzZ-l*$LBIJ7_`Gl8 ze2nuiV|S@9{UZhAJMFXydfyFb<}*1^NdWcW`f1AqT|eOXZ~Q{|cO0$zOr?b-*_M#^ z@#OUk_-~HOllpQVWBfbE;!cEq)Z=Ghz;q_khL6aN7ETPE?_|ARgPf+IUiCR370|wT z%ozKlu%KAlKRkMR-aDXs3y^mB2==Evxb928G3U!d>%L|mUgVS)>wJg${TqCn0o^!h z)=k7d`-1+VX)|BTv3i?$Cf7Fj0o%9zqbHA`%+JSM3`tUyfzoB2X zGtWxTuPC(qo#XLdZ!Dl5fZf>N(veSo?b6j=?Z)TI_*k5qr|n>wCS3hM_e;R<;U|7T zy;+aJu*b?sG&FuQezwE;kIJfCncq6Yv^NBD2RQOGkWQ%2A>|hZ@)@^v+%e~e%+j1( zLdSOExy!VIGO=$Z_Rr{-V<0yNusW*opcv`i@cW;D`Dy98?&B|=CHqDh$PeyQgY^&X zH}%dw%OtdWqILb;F9)#|w2Z$Ld30kU1GFYjMyzhRDjT|36h z8yjtt9Ay81zCOp6b6qHHoX(#$I>+@}3%ynWvR?EH(lh^Z%m>eO{FD8Jewmg#D%Z+) z?XdxJ{`v#uorC&NKI2TnupnxA{fIPod;eH)N= zvURi<;|=3pq-><*)BazAt`*R&2kBP8{=0$a+TZQ3)W0|Uf%xo4KQ zKnhC>>`zoLXxHwjz_&^2M|#%V?cYH@&X@kZt@w)dJ>oG=w^d)(hxRt-VWmE%*(L6> zy|RIDI3V?--;tjAY!~X|whQAC%kwh0f1~S&jNjx(KOK^x@tXbH_w^jPpSk8$+YaV= zAQ|6T|N4?WPfLE&LK%mf-*{M{8Shsk|80Sp^PW(s&t=i?3Q#fn5$j3260gX?qrW9< zSJsF0#h|BM-2Tb@r{M?FU@x;CEAyCh;&zdG&~9!!P=AikET_B@AdoNlFpf|U;=A=2 z!+JRW_zfELO13l3HM0HDO}z1#7tr26){cRE+{Y*ADdRl-CQ=}`Awhp#47~>i^>56v z{*aG!d^}Zqv)`myBy**XP=@R;D?qo@;ph4j>rH=h;|=|zEj`F5T2dwzlflO5MSbpo z9@jhi6e7*}y;R2hqo0++uhNby5x!+$Oui3*{vL<#D2MN8q+PzQT&}wW>jrpE$z3$1D%xGmbn-dH>S$*7VC7 z&`si#}+?yvJaFrVY%b2RS$I``lF-NW+8+d}TYnRPYXC+Rs~=I=(mpUlwv zG}eo0)}updnT!jC*}9HWp^ve69LHMFz7MnA@!SjLWc10;wfa=$7xlG}bYBAh3x|&F zlG$g1_+3Row#vsjkHP|B6Y$Z~37+?z!-wbDy2km8wDQX;MhV}lDm_rA+~Rt*gM#UR zCT`?dI-Yau*r!m|O^U0si)?;b+2~NcvOw3>p{Jil$BrwubnbocPl10p>2~YBOAF%u zh74`Tb=Wt0GNV4n^5K=1tLG!bPgQu{G2nL;;N0dgU+(K{$oRvXmKXW5{kguJJ9TQU zEoXY#?Afuzbj_T)aQd8B2!HadbEjE+SAY5)`Bv6Vo|4G-{8-I}iRo#z=Y-a|Yc8^- z{~Nw@LhIvG4P(oPddvXhw)Cx-RyQY+u69;zc4FF8=lsO9sgBrza!hq<63bDYHtqDI z<<6NkHBruwwIkyu`}KwGbYF_`g6(*HyKvmS-AS);(tmT(Tb%UsPWn|R{Vyl|rIXHR zAJ!+!N&knF{*{v+?4*mF^aLmE+T%4(*B?r!ojW&SHO`UxRN= zxZh2V%?k0EdG<8vhspgIeCEtN+sdO~POFWH229t~#KQe<*0~n_d;Bz+ep9L~9r;eK z4fpptRkuyP1=FX5^qXEYD`el=i({ewJZFZe-zMME$umR!Gd6R2s6Wr1t`%>~p7}M} zf~;q4&5T%Ly=T|ehT3UL-JDRooMr@v@MlgA)mN?9w*CLlddxn^55jR|ns3!?)2@}( z(?ji1=j>n3nHBcq|ND5N{#RaG6SCX1DRrUtof^9+6n|@_c5TIc@n(Ztb}tznD2K>_;(Um_)v@nsY*OYRy2KST2<{8EwhUn^EJAyCFU5 zjG#omF(W83t)qL}a!PArp*Um2hR4V0;d#Z`)24^z#KPm{FY02mL-f)JKftb~2gTAJ@$fJK0nfM)|<0Lb%{<~&1= zZ6BWJaL=XH;r_+q*o*5GbCA#bed1lxUe{^d=M#uu-r8r2<->U+<(f?mxTw9&^}K$ZPcNOa&8Df(pTXZ> z8h)P(%Nw9K_lI8PU4tiV(cpsh<6{U?n?zxKFpjUNN z;}_}9f!r;aPtd+*(Mzh_u1{{BtzTJ1)gkS12js5={434!E!O@ zp8@&4y0_k$(`56_`_=?Tv$Z}|Hq%_B?+Chfq{sV8$S0s5Q83QZQD6JpUfn_074WAW zxW27+WdDc`4AWEo5uiI9(Co*EzoiW<5L0p;j`+QS7Yp!pzdNl!_noSWR4@KN7I?oT zex^QO&2<3ZS$B91{=;!{NUS(C9$z?l#&pY@VWDs(;TlP#GDfR~&|@~B=~ug~vXP46 zqBHUSfbz@Zc+V(aP6+QRlrJV;<`9V!DaC@OMl?UKLHRNl?>Aw*Yf-)e@Y|)cHU4B? z_^HKAD=CzC$M+Lb-y4B{17PdY8l}VhB7Iz`*rN=AfONM3zX8zq_dIXqq~zHD@%VNZ z%KwXaP5PXAO7AeBF8Br>a!bo9|!n@|0wkwczg(N56VA}<6UDBl8-0a zr8sU3i4}y#kqf8K4y9{mh3^|Lj?D|*kLlfY^83$?%XFXkFKB49|Ma5O?|P)WcGNg) z=KG=c%<9D68O6B-ThDU<@1-=f2Ey=g3iwgKc8UY^?EBWwQ_iYg}jD!)L;AHNBJEa zH`|H50NwU4rCv^ZkL}p_p=IFuK@YqSiuc8=-+1uJ!~0TM zuZe5*yv_~uH;jLzJ0pqw$v;y5xq*Bg|ErU<2lZ%=^62sUe%z4pO})>Dy@~;6chqq` zr(@$TYnS#N>z}dEU#jl|v%l?S*a@pIF&{|L@Sug}|3%>E11>m-ufA`~&-`5c^&tM> zME2pMKyw`WiMNeN%JwTu?g* zegJ�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 "); len = sk_v4_readline(); how = v4_boot_line(&boot, sk_v4_text, len); - if (how == V4_LINE_COMPLETED) console_puts(" ok\n"); - else if (how == V4_LINE_ERROR) console_puts(" ERROR\n"); + if (how == V4_TEXT_COMPLETED) console_puts(" ok\n"); + else if (how == V4_TEXT_ERROR) console_puts(" ERROR\n"); else if (how == V4_BOOT_LINE_STOPPED) { console_println("StarForth v4: the node stopped on a fault"); for (;;) { } diff --git a/logs/20261006-110551/amd64/qemu-amd64-20261006-110551.log b/logs/20261006-110551/amd64/qemu-amd64-20261006-110551.log new file mode 100644 index 00000000..c7b982a9 --- /dev/null +++ b/logs/20261006-110551/amd64/qemu-amd64-20261006-110551.log @@ -0,0 +1,130 @@ +[=3hBdsDxe: loading Boot0002 "UEFI QEMU DVD-ROM QM00005 " from PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x2,0xFFFF,0x0) +BdsDxe: starting Boot0002 "UEFI QEMU DVD-ROM QM00005 " from PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x2,0xFFFF,0x0) +[=3hStarKernel UEFI Loader +Loading kernel from ESP... +[CKPT 001] Entered efi_main - ConOut live +RAW SERIAL UP +[CKPT 002] Serial (COM1) initialized +Monolithic build - kernel linked directly +Collecting boot information... +CmdLine: parsed OK +[CKPT 004] Command line parsed +[CKPT 005] Kernel stack allocation decided +[CKPT 006] Boot info collected (ACPI table located) +GOP: linear framebuffer found +[CKPT 007] GOP: linear framebuffer found +[CKPT 008] About to enter ExitBootServices retry loop +EBS... +EBS OK +Calling kernel_main (monolithic)... + + + _____ _ _ __ _ + / ____| | | |/ / | | + | (___ | |_ __ _ _ __| ' / ___ _ __ _ __ ___| | + \___ \| __/ _` | '__| < / _ \ '__| '_ \ / _ \ | + ____) | || (_| | | | . \ __/ | | | | | __/ | + |_____/ \__\__,_|_| |_|\_\___|_| |_| |_|\___|_| + +LithosAnanke v2.1.0 +Architecture: amd64 +Build: Oct 6 2026 11:05:25 + +UEFI BootServices: EXITED + +=== StarKernel Boot Information === +Memory map entries: 131 +Total memory: 1023 MB +Usable memory: 968 MB +=================================== + +PMM initialized. +PMM statistics: + Total pages: 249252 + Free pages : 247729 + Used pages : 1523 + Total MB : 973 + Free MB : 967 + Used MB : 5 + +VMM initialized (mapped RAM, CR3 switched) +VMM initialized (mapped RAM, CR3 switched) +VMM self-test: mapped OK at 0xffff800000000000 +VMM self-test complete. + +IDT installed. + +APIC: init... +APIC: IA32_APIC_BASE MSR=0x00000000fee00900 +APIC: stale-ISR drain: 0 EOI(s) issued +APIC: initialized (xAPIC MMIO, TPR=0, SIVR=0x1FF, EOI-clear) +APIC: init done + +I/O APIC: init... +I/O APIC: base=0xfec00000, gsi_base=0, overrides=5 + override: source=00 gsi=2 flags=0x0000 + override: source=05 gsi=5 flags=0x000d + override: source=09 gsi=9 flags=0x000d + override: source=0a gsi=10 flags=0x000d + override: source=0b gsi=11 flags=0x000d +i8042: keyboard ACKed enable-scanning +i8042: IRQ1 enabled in controller config byte +I/O APIC: keyboard IRQ1 routed (masked) + +Timer: init... +Timer: init start +Timer: PM_TMR_BLK discovered from FADT at port 1544 +Timer: VM mode detected (hypervisor present). +Timer: HPET calibration disabled (VM-exit MMIO would poison timing). +Timer: WARNING: invariant TSC not present under hypervisor. +Timer: continuing in RELATIVE mode (no determinism guarantees). +Timer: RDTSCP not present; using RDTSC (less serialized). +Timer: CPUID frequency unavailable; trying PM Timer... +Timer: trust=1 (0=NONE,1=REL,2=ABS), TSC=2101540994 Hz +Timer: init done + +Kernel heap initialized. +Heap statistics: + Total bytes: 536870872 + Free bytes: 536870872 + Used bytes: 0 + Peak bytes: 0 + Heap base addr: 24641536 + Heap end addr: 561512448 + +Heartbeat: init... +APIC Timer: calibrating... +APIC Timer: apic_hz=1006649045, tick_hz=100, initial_count=10066490 +APIC Timer: configured (masked, ready to start) +Heartbeat: init done +Kernel initialization complete. +Boot successful! + +StarForth v4: one host node, the F18-derived engine +V4: capsule v4:nucleus-64.f18 signature: missing (unsigned) +PARITY:V4_NUCLEUS name=v4:nucleus-64.f18 capsule_id=0x97a655081b2af559 capsule_hash=0x97a655081b2af559 words=298 +V4: capsule v4:forth79.4th signature: missing (unsigned) +PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x594818fc69677603 +V4: capsule v4:post79.4th signature: missing (unsigned) +PARITY:V4_POST tests=550 pass=550 fail=0 +PARITY:V4_CAPSULE name=v4:post79.4th capsule_id=0xb987dbb4388990bd capsule_hash=0xb987dbb4388990bd dict_hash=0x8768fb163c8529f4 +PARITY:OK +POST: PASSED +ok> : SQ DUP * ; + ok +ok> 7 SQ . 3 4 U* . . +49 0 12 ok +ok> COLD +FORTH-79 Cold Start +System initialized. + ok +ok> 3 4 U* . . +0 12 ok +ok> FORGET U* +Protected word + ERROR +ok> 9 KERNEL-WORD ASK9 ASK9 +Argument out of range + ERROR +ok> BYE +BYE: cold restart diff --git a/logs/20261006-110837/aarch64/qemu-aarch64-20261006-110837.log b/logs/20261006-110837/aarch64/qemu-aarch64-20261006-110837.log new file mode 100644 index 00000000..0623e00c --- /dev/null +++ b/logs/20261006-110837/aarch64/qemu-aarch64-20261006-110837.log @@ -0,0 +1,2 @@ +UEFI firmware (version 2025.11-3ubuntu7.3 built at 15:40:26 on Sep 23 2026) +[=3h \ No newline at end of file diff --git a/logs/20261006-111341/riscv64/qemu-riscv64-20261006-111341.log b/logs/20261006-111341/riscv64/qemu-riscv64-20261006-111341.log new file mode 100644 index 00000000..849ca7d4 --- /dev/null +++ b/logs/20261006-111341/riscv64/qemu-riscv64-20261006-111341.log @@ -0,0 +1,174 @@ + +OpenSBI v1.8 + ____ _____ ____ _____ + / __ \ / ____| _ \_ _| + | | | |_ __ ___ _ __ | (___ | |_) || | + | | | | '_ \ / _ \ '_ \ \___ \| _ < | | + | |__| | |_) | __/ | | |____) | |_) || |_ + \____/| .__/ \___|_| |_|_____/|____/_____| + | | + |_| + +Platform Name : riscv-virtio,qemu +Platform Features : medeleg +Platform HART Count : 1 +Platform HART Protection : pmp +Platform IPI Device : aclint-mswi +Platform Timer Device : aclint-mtimer @ 10000000Hz +Platform Console Device : uart8250 +Platform HSM Device : --- +Platform PMU Device : --- +Platform Reboot Device : syscon-reboot +Platform Shutdown Device : syscon-poweroff +Platform Suspend Device : --- +Platform CPPC Device : --- +Firmware Base : 0x80000000 +Firmware Size : 321 KB +Firmware RW Offset : 0x40000 +Firmware RW Size : 65 KB +Firmware Heap Offset : 0x47000 +Firmware Heap Size : 37 KB (total), 0 KB (reserved), 12 KB (used), 23 KB (free) +Firmware Scratch Size : 4096 B (total), 1464 B (used), 2632 B (free) +Runtime SBI Version : 3.0 +Standard SBI Extensions : ipi,pmu,srst,sse,hsm,rfnc,fwft,time,base,legacy,dbcn,dbtr +Experimental SBI Extensions : none + +Domain0 Name : root +Domain0 Boot HART : 0 +Domain0 HARTs : 0* +Domain0 Region00 : 0x0000000080040000-0x000000008005ffff M: (F,R,W) S/U: () +Domain0 Region01 : 0x0000000080000000-0x000000008003ffff M: (F,R,X) S/U: () +Domain0 Region02 : 0x0000000000100000-0x0000000000100fff M: (I,R,W) S/U: (R,W) +Domain0 Region03 : 0x0000000010000000-0x0000000010000fff M: (I,R,W) S/U: (R,W) +Domain0 Region04 : 0x0000000002000000-0x000000000200ffff M: (I,R,W) S/U: () +Domain0 Region05 : 0x000000000c400000-0x000000000c5fffff M: (I,R,W) S/U: (R,W) +Domain0 Region06 : 0x000000000c000000-0x000000000c3fffff M: (I,R,W) S/U: (R,W) +Domain0 Region07 : 0x0000000000000000-0xffffffffffffffff M: () S/U: (R,W,X) +Domain0 Next Address : 0x0000000020000000 +Domain0 Next Arg1 : 0x00000000bfe00000 +Domain0 Next Mode : S-mode +Domain0 SysReset : yes +Domain0 SysSuspend : yes + +Boot HART ID : 0 +Boot HART Domain : root +Boot HART Priv Version : v1.12 +Boot HART Base ISA : rv64imafdch +Boot HART ISA Extensions : sstc,zicntr,zihpm,zicboz,zicbom,sdtrig,svadu +Boot HART PMP Count : 16 +Boot HART PMP Granularity : 2 bits +Boot HART PMP Address Bits : 54 +Boot HART MHPM Info : 16 (0x0007fff8) +Boot HART Debug Triggers : 2 triggers +Boot HART MIDELEG : 0x0000000000001666 +Boot HART MEDELEG : 0x0000000000f4b509 +[=3hRISC-V EDK2 firmware version 2025.11-3ubuntu7.3 +Press ESCAPE within 5 seconds for boot options ERROR: C40000002:V03051002 I0 6D33944A-EC75-4855-A54D-809C75241F6C 83FFF850 +BdsDxe: failed to load Boot0001 "UEFI Misc Device" fr +om PciRoot(0x0)/Pci(0x1,0x0): Not Found +[=3hStarKernel UEFI Loader +Loading kernel from ESP... +[CKPT 001] Entered efi_main - ConOut live +Monolithic build - kernel linked directly +Collecting boot information... +CmdLine: parsed OK +[CKPT 004] Command line parsed +[CKPT 005] Kernel stack allocation decided +[CKPT 006] Boot info collected (ACPI table located) +GOP: linear framebuffer found +[CKPT 007] GOP: linear framebuffer found +[CKPT 008] About to enter ExitBootServices retry loop +Calling kernel_main (monolithic)... +riscv64 item 4.3.5a: satp state at kernel entry (before switch) + satp.MODE = 0x000000000000000a + satp.PPN = 0x00000000000bf868 + __kernel_start = 0x00000000bdea78f8 +riscv64: satp cleared -- Bare mode, explicit (item 4.3.5a) + + + _____ _ _ __ _ + / ____| | | |/ / | | + | (___ | |_ __ _ _ __| ' / ___ _ __ _ __ ___| | + \___ \| __/ _` | '__| < / _ \ '__| '_ \ / _ \ | + ____) | || (_| | | | . \ __/ | | | | | __/ | + |_____/ \__\__,_|_| |_|\_\___|_| |_| |_|\___|_| + +LithosAnanke v2.1.0 +Architecture: riscv64 +Build: Oct 6 2026 11:13:04 + +UEFI BootServices: EXITED + +=== StarKernel Boot Information === +Memory map entries: 100 +Total memory: 1020 MB +Usable memory: 977 MB +=================================== + +PMM initialized. +PMM statistics: + Total pages: 250782 + Free pages : 250130 + Used pages : 652 + Total MB : 979 + Free MB : 977 + Used MB : 2 + +VMM initialized (mapped RAM, CR3 switched) +VMM initialized (mapped RAM, CR3 switched) +VMM self-test: mapped OK at 0xffff800000000000 +VMM self-test complete. + +IDT installed. + +APIC: init... +PLIC: no DTB PLIC node -- using QEMU virt-machine default (base=0x0c000000) +PLIC: init (S-mode context 1, threshold=0) +APIC: init done + +Timer: init... +Timer: RISC-V time CSR @ 10000000 Hz (FALLBACK, no devicetree) +Timer: init done + +Kernel heap initialized. +Heap statistics: + Total bytes: 536870872 + Free bytes: 536870872 + Used bytes: 0 + Peak bytes: 0 + Heap base addr: 2214588416 + Heap end addr: 2751459328 + +Heartbeat: init... +Heartbeat: init done +Kernel initialization complete. +Boot successful! + +StarForth v4: one host node, the F18-derived engine +V4: capsule v4:nucleus-64.f18 signature: missing (unsigned) +PARITY:V4_NUCLEUS name=v4:nucleus-64.f18 capsule_id=0x97a655081b2af559 capsule_hash=0x97a655081b2af559 words=298 +V4: capsule v4:forth79.4th signature: missing (unsigned) +PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x594818fc69677603 +V4: capsule v4:post79.4th signature: missing (unsigned) +PARITY:V4_POST tests=550 pass=550 fail=0 +PARITY:V4_CAPSULE name=v4:post79.4th capsule_id=0xb987dbb4388990bd capsule_hash=0xb987dbb4388990bd dict_hash=0x8768fb163c8529f4 +PARITY:OK +POST: PASSED +ok> : SQ DUP * ; + ok +ok> 7 SQ . 3 4 U* . . +49 0 12 ok +ok> COLD +FORTH-79 Cold Start +System initialized. + ok +ok> 3 4 U* . . +0 12 ok +ok> FORGET U* +Protected word + ERROR +ok> 9 KERNEL-WORD ASK9 ASK9 +Argument out of range + ERROR +ok> BYE +BYE: cold restart diff --git a/logs/20261006-111621/aarch64/qemu-aarch64-20261006-111621.log b/logs/20261006-111621/aarch64/qemu-aarch64-20261006-111621.log new file mode 100644 index 00000000..2dc2b244 --- /dev/null +++ b/logs/20261006-111621/aarch64/qemu-aarch64-20261006-111621.log @@ -0,0 +1,104 @@ +UEFI firmware (version 2025.11-3ubuntu7.3 built at 15:40:26 on Sep 23 2026) +[=3hBdsDxe: failed to load Boot0002 "UEFI Misc Device" from PciRoot(0x0)/Pci(0x2,0x0): Not Found +BdsDxe: failed to load Boot0003 "UEFI QEMU QEMU USB HARDDRIVE 1-0000:00:04.0-1" from PciRoot(0x0)/Pci(0x4,0x0)/USB(0x0,0x0): Not Found +BdsDxe: loading Boot0004 "UEFI Misc Device 2" from PciRoot(0x0)/Pci(0x6,0x0) +BdsDxe: starting Boot0004 "UEFI Misc Device 2" from PciRoot(0x0)/Pci(0x6,0x0) +[=3hStarKernel UEFI Loader +Loading kernel from ESP... +[CKPT 001] Entered efi_main - ConOut live +Collecting boot information... +[CKPT 004] Command line parsed +[CKPT 005] Kernel stack allocation decided +[CKPT 006] Boot info collected (ACPI table located) +[CKPT 007] GOP: linear framebuffer found +[CKPT 008] About to enter ExitBootServices retry loop + + + _____ _ _ __ _ + / ____| | | |/ / | | + | (___ | |_ __ _ _ __| ' / ___ _ __ _ __ ___| | + \___ \| __/ _` | '__| < / _ \ '__| '_ \ / _ \ | + ____) | || (_| | | | . \ __/ | | | | | __/ | + |_____/ \__\__,_|_| |_|\_\___|_| |_| |_|\___|_| + +LithosAnanke v2.1.0 +Architecture: aarch64 +Build: Oct 6 2026 11:15:55 + +UEFI BootServices: EXITED + +=== StarKernel Boot Information === +Memory map entries: 108 +Total memory: 4093 MB +Usable memory: 4056 MB +=================================== + +PMM initialized. +PMM statistics: + Total pages: 1039866 + Free pages : 1038455 + Used pages : 1411 + Total MB : 4061 + Free MB : 4056 + Used MB : 5 + +VMM initialized (mapped RAM, CR3 switched) +VMM initialized (mapped RAM, CR3 switched) +VMM self-test: mapped OK at 0xffff800000000000 +VMM self-test complete. + +AArch64: running at EL1 +IDT installed. + +APIC: init... +PSCI: no DTB -- using HVC (QEMU virt-machine default) +GICv2: no DTB GIC node -- using QEMU virt-machine defaults +GICv2: distributor+CPU interface enabled, PPI 30 +APIC: init done + +Timer: init... +Timer: AArch64 generic timer initialised. +Timer: init done + +Kernel heap initialized. +Heap statistics: + Total bytes: 2147483608 + Free bytes: 2147483608 + Used bytes: 0 + Peak bytes: 0 + Heap base addr: 1207959552 + Heap end addr: 3355443200 + +Heartbeat: init... +Heartbeat: init done +Kernel initialization complete. +Boot successful! + +StarForth v4: one host node, the F18-derived engine +V4: capsule v4:nucleus-64.f18 signature: missing (unsigned) +PARITY:V4_NUCLEUS name=v4:nucleus-64.f18 capsule_id=0x97a655081b2af559 capsule_hash=0x97a655081b2af559 words=298 +V4: capsule v4:forth79.4th signature: missing (unsigned) +PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x594818fc69677603 +V4: capsule v4:post79.4th signature: missing (unsigned) +PARITY:V4_POST tests=550 pass=550 fail=0 +PARITY:V4_CAPSULE name=v4:post79.4th capsule_id=0xb987dbb4388990bd capsule_hash=0xb987dbb4388990bd dict_hash=0x8768fb163c8529f4 +PARITY:OK +POST: PASSED +ok> : SQ DUP * ; + ok +ok> 7 SQ . 3 4 U* . . +49 0 12 ok +ok> COLD +FORTH-79 Cold Start +System initialized. + ok +ok> 3 4 U* . . +0 12 ok +ok> FORGET U* +Protected word + ERROR +ok> 9 KERNEL-WORD ASK9 ASK9 +Argument out of range + ERROR +ok> BYE +BYE: cold restart diff --git a/v4/Makefile b/v4/Makefile index b8194cf6..fdcbb97b 100644 --- a/v4/Makefile +++ b/v4/Makefile @@ -69,7 +69,7 @@ ROOT := $(abspath $(HERE)/..) NUCLEUS_64 := $(ROOT)/capsules/v4/nucleus-64.f18 NUCLEUS_32 := $(BINDIR)/nucleus-32.f18 HOST_DEFS := -DV4_NODE_WORDS=$(HOST_WORDS) -DV4_DATA_RING=$(HOST_DATA_RING) -DV4_RET_RING=$(HOST_RET_RING) -ENGINE_SRCS := $(addprefix $(HERE)/src/,node.c exec.c stack.c iword.c heat.c guard.c image.c fabric.c capsule.c) +ENGINE_SRCS := $(addprefix $(HERE)/src/,node.c exec.c stack.c iword.c heat.c guard.c image.c fabric.c capsule.c message.c) define IMAGE_RULE $(BINDIR)/mkimage-$(1): $(HERE)/tools/mkimage.c $$(SRCS) $$(wildcard $(HERE)/include/v4/*.h) $(HERE)/tests/host_map.h $(HERE)/Makefile diff --git a/v4/README.md b/v4/README.md index 5b905187..c0c7ecd7 100644 --- a/v4/README.md +++ b/v4/README.md @@ -59,7 +59,7 @@ State, 2026-10-05, after `ENGINE.md` step 1: all six builds start the nucleus, load `v4:forth79.4th`, pass POST and reach `ok>`, with the same lines: ``` -PARITY:V4_NUCLEUS name=v4:nucleus-64.f18 capsule_id=... capsule_hash=0xbcc90cc5a638a299 words=298 +PARITY:V4_NUCLEUS name=v4:nucleus-64.f18 capsule_id=... capsule_hash=0x97a655081b2af559 words=298 PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=... dict_hash=... PARITY:V4_POST tests=550 pass=550 fail=0 PARITY:V4_CAPSULE name=v4:post79.4th capsule_id=... dict_hash=... @@ -68,23 +68,23 @@ POST: PASSED ok> ``` -Bare-metal logs: `logs/20261006-102421/amd64/`, `logs/20261006-102706/aarch64/`, -`logs/20261006-103048/riscv64/`. On each, seven lines were then typed at the +Bare-metal logs: `logs/20261006-110551/amd64/`, `logs/20261006-111621/aarch64/`, +`logs/20261006-111341/riscv64/`. On each, seven lines were then typed at the prompt through the serial port — a definition, its use with the capsule's `U*`, `COLD`, the capsule word again, a `FORGET` of it (refused), a kernel word no one serves, and `BYE` — and each was answered as the hosted binary answers it. The capsules were unsigned (no signing key on this machine). -**A node is handed a line** (`docs/v4.0.0/ENGINE.md` 3.1). It does not read -its own command line and prints no prompt. Its host puts the text in the -node's input buffer and starts it at `(LINE)`; the node interprets the text -and stops at `(IDLE)`, leaving in `(LINE-STATUS)` how it ended. The host says -` ok` or ` ERROR` and prompts, as the kernel's REPL does for a v3 VM. A line -may be 1024 characters, a block. `v4_line_begin`, `v4_line_done` and -`v4_line_status` (`v4/include/v4/image.h`) are that interface; -`v4_boot_line` (`v4/system/boot.c`) is the one loop the hosted binary, the -kernel and the capsule loader all run it with. +**A node is sent text as a message** (`docs/v4.0.0/MESH.md` section 6). It +does not read its own command line, prints no prompt and has no console of +its own. With nothing to do it is blocked reading its ports. A neighbour +writes it a message; text for it is interpreted; what it prints goes back +as messages to the sender, and then a message saying how the text ended. +Its console says ` ok` or ` ERROR` and prompts, as the kernel's REPL does +for a v3 VM. A message carries 1024 characters, a block. `v4/src/message.c` +is the format for a host; `v4_boot_line` (`v4/system/boot.c`) is the +console both products and the capsule loader use. **A node asks its kernel by writing to its port** (`ENGINE.md` 3.3). The write blocks the node until it has been served. A kernel word is a diff --git a/v4/capsule/core.v4 b/v4/capsule/core.v4 index 79af2840..02c2907c 100644 --- a/v4/capsule/core.v4 +++ b/v4/capsule/core.v4 @@ -5,7 +5,8 @@ \ written here as text for the text assembler (v4/include/v4/text.h). \ \ Constants the loader supplies: N-1 (cell bits - 1), NODE-ERROR, CONSOLE-TX, -\ CONSOLE-RX, CONSOLE-STATUS, BASE, (EMIT-HOOK). +\ CONSOLE-RX, CONSOLE-STATUS, BASE, (EMIT-HOOK), (MSG), (REPLY), (ME), (OUT), +\ (OUT^). \ \ ERRORS (D-18). A word that finds an error takes its arguments off the stack \ and stores a code in NODE-ERROR. On a node with a prompt that store is a @@ -91,16 +92,63 @@ header CMOVE DONE: drop drop drop ; \ ---- section 5.10: the console ------------------------------------------- -\ EMIT sends the character to the console, unless (EMIT-HOOK) holds the xt -\ of a word: then that word is given it instead ( c -- ), and returns to -\ EMIT's caller. Everything the node prints goes through EMIT, so a hook -\ sees all of it. The prompt takes the hook off at the end of every line -\ (quit.v4), so that nothing can leave the console silent. POST uses it -\ to compare what a case prints (docs/v4.0.0/NUCLEUS.md 6.3). +\ ---- what a node prints (docs/v4.0.0/MESH.md section 6) ------------------------ +\ A node has no console of its own. It does what a message asks, and what +\ it prints while doing it goes back, as a message, to whoever sent that one, +\ on the port it came on. A message is seven words and then its text, four +\ characters to a word: +\ to, from, type, heat and TTL, ACL tag, sequence, length in characters +\ The types: 1 text to be interpreted 2 what a node printed 3 how the +\ text ended (one word of text: 0 QUIT, 1 completed, 2 an error). +\ The header of the message being served is in the seven cells (MSG); (REPLY) +\ is the address of the port it came on; (ME) is this node's number. +\ +\ Characters are kept in (OUT), 256 of them, a character to a cell, and sent +\ when it is full and when the text has been done with (quit.v4). (OUT^) +\ is where the next goes. +\ +\ THE STACK. What prints may be run with the data stack all but full: EMIT +\ has always needed one free cell and no more, and still does -- it keeps +\ the character and A on the return stack while it works. Sending needs +\ two. + +\ ( type -- ) the first six words of a message to the sender of the one +\ being served; its length, and its text, are the caller's to send. Each +\ write waits for the neighbour to take it. B is left at the port. +: (HDR) + (REPLY) a! @ b! + (MSG)+1 a! @ !b \ to + (ME) a! @ !b \ from + !b \ type + 0 !b 0 !b 0 !b ; \ heat and TTL, ACL tag, sequence: carried, not used yet + +\ ( -- ) send what has been printed: its length, then its characters, four +\ to a word, the first lowest +: (FLUSH-OUT) + (OUT^) a! @ (OUT) xor if NONE drop + 2 (HDR) + (OUT^) a! @ (OUT) - dup !b + 3 + 2/ 2/ -1 + (OUT) a! + FOR @+ @+ 8* + @+ 8* 8* + @+ 8* 8* 8* + !b NEXT + (OUT) (OUT^) a! ! ; + NONE: drop ; + +\ EMIT puts the character with what has been printed, unless (EMIT-HOOK) +\ holds the xt of a word: then that word is given it instead ( c -- ), and +\ returns to EMIT's caller. Everything the node prints goes through EMIT, +\ so a hook sees all of it. The hook is taken off when the text being +\ interpreted ends (quit.v4), so that nothing can leave a node silent. +\ POST uses it to compare what a case prints (docs/v4.0.0/NUCLEUS.md 6.3). +\ A is kept: the words that print have always been free to use it across +\ an EMIT. As v3, only the low 8 bits of the character are printed. header EMIT : EMIT ( c -- ) (EMIT-HOOK) b! @b if NONE push ; - NONE: drop CONSOLE-TX b! !b ; + NONE: drop + 255 and a push push \ A, and then the character, to the return stack + (OUT^) b! @b a! pop !+ a !b \ the character goes where (OUT^) points, which moves on + a (OUT)+256 xor if FULL drop pop a! ; + FULL: drop (FLUSH-OUT) pop a! ; header KEY : KEY ( -- c ) L: CONSOLE-STATUS b! @b if WAIT drop CONSOLE-RX b! @b ; diff --git a/v4/capsule/quit.v4 b/v4/capsule/quit.v4 index fa89762d..3ae961d1 100644 --- a/v4/capsule/quit.v4 +++ b/v4/capsule/quit.v4 @@ -4,17 +4,17 @@ \ DECOMPOSITION.md 5.15 and 5.10: QUIT ABORT ABORT" (ABORT") ." (."). Part of \ the compiler capsule. Rests on all the files before it. \ -\ A NODE IS HANDED A LINE (docs/v4.0.0/ENGINE.md 3.1). It does not read its -\ own command line and prints no prompt: that is its host's, as it is the -\ kernel's REPL's for a v3 VM. The host puts the text in TIB and starts -\ (LINE); the node interprets it and stops at (IDLE), having left in the -\ variable (LINE-STATUS) how the line ended: -\ 1 it completed the host says " ok" +\ A NODE IS SENT TEXT (docs/v4.0.0/MESH.md section 6). It does not read its +\ own command line and prints no prompt. A node with nothing to do waits at +\ its ports; a neighbour writes it a message; if that is text for this node +\ it is interpreted; what it printed goes back as a message, and then a +\ message saying how the text ended: +\ 1 it completed a console says " ok" \ 2 it ended in an error the message is already printed; " ERROR" \ 0 QUIT nothing is said -\ What the console then shows is v3's: -\ ok> 65 EMIT the host's prompt, and the line -\ A ok what the line printed, then the host's " ok" +\ What a console then shows is v3's: +\ ok> 65 EMIT the console's prompt, and the line +\ A ok what the line printed, then " ok" \ ok> NOSUCH \ UNKNOWN WORD: 'NOSUCH' \ ERROR @@ -22,7 +22,8 @@ \ Address out of range an address fault (D-14), from any depth \ ERROR \ KEY, EXPECT and QUERY are FORTH-79 words that read characters, as before; -\ they are not how a line reaches the node. +\ they are not how text reaches the node. They still read the console's +\ registers, CONSOLE-RX and CONSOLE-STATUS, and not a message. \ \ THE STACKS are guarded (D-16): each counts what it holds, and a push onto \ a full one or a pop from an empty one is a fault. So QUIT and ABORT, which @@ -30,7 +31,10 @@ \ the data stack too. A store to RSTACK-DEPTH or DSTACK-DEPTH does that. \ \ Constants the loader supplies: -\ (LINE-STATUS) word address of the variable: how the last line ended +\ (LINE-STATUS) word address of the variable: how the last text ended +\ (MSG) (REPLY) (ME) (OUT) (OUT^) see core.v4, "what a node prints" +\ (PORT) word address of the node's port 0; (PORT)+8 is "any port" and +\ (PORT)+9 the port the last read from that came on \ (Q) word address of four cells of scratch, which system.v4 and \ blocks.v4 use too \ DSTACK-DEPTH RSTACK-DEPTH word addresses of the stack registers @@ -52,26 +56,62 @@ macro R-CLEAR RSTACK-DEPTH b! a !b endmacro \ (docs/v4.0.0/NUCLEUS.md 6.3). (EMIT-HOOK), core.v4, is set to 0 here at \ the end of every line, caught or not. \ -\ ( k -- ) the line is over. It is entered with how -- 0 QUIT, 1 completed, -\ anything else an error -- and never returns: it leaves that in -\ (LINE-STATUS) and stops at (IDLE), where the host finds the node. It is -\ always jumped to, never called, by something that has emptied the return -\ stack (or by a fault, which empties it). -: (IDLE) L: jump L +\ ( s -- ) the text is done with. What it printed is sent, then a message +\ saying how it ended -- 0 QUIT, 1 completed, 2 an error -- and the node waits +\ for the next. (DONE) is entered with the same number and decides whether +\ an error was one to catch; it is always jumped to, never called, by +\ something that has emptied the return stack (or by a fault, which empties +\ it). (LINE-STATUS) keeps how the last text ended. +: (FINISH) ( s -- ) + (LINE-STATUS) b! dup !b + (FLUSH-OUT) + 3 (HDR) 4 !b !b \ a message of type 3, four characters long: how it ended + jump (IDLE) : (DONE) - (EMIT-HOOK) b! 0 !b \ the console is the console again + (EMIT-HOOK) b! 0 !b \ what is printed is printed again if GO -1 + if OK drop (RESET) - (CATCH) b! @b if LOUD drop -1 !b 1 jump (DONE) \ caught: the line completed - LOUD: drop 2 (LINE-STATUS) b! !b jump (IDLE) - OK: drop 1 (LINE-STATUS) b! !b jump (IDLE) - GO: drop 0 (LINE-STATUS) b! !b jump (IDLE) + (CATCH) b! @b if LOUD drop -1 !b 1 jump (DONE) \ caught: the text completed + LOUD: drop 2 jump (FINISH) + OK: drop 1 jump (FINISH) + GO: drop 0 jump (FINISH) -\ ( -- ) THE LINE ENTRY. The host has put a line of text in TIB, a zero -\ after it, and its length in SPAN, has emptied the return stack and set P -\ here. The line is interpreted with one return entry under it, this -\ word's call of INTERPRET; whatever is on the data stack stays there. +\ ( -- ) WAITING. A node with nothing to do is blocked reading its ports +\ (docs/v4.0.0/MESH.md 4.1): it executes nothing until a neighbour writes. +\ What arrives is a message (core.v4). Its first word is taken from any +\ port and the rest from the port that came on. Its text goes into TIB, +\ which holds 1024 characters, the most a message carries; a longer one is +\ read to its end, so that what follows it is not taken for a message, and +\ is error 12. A message of type 1 for this node is text to interpret: it +\ is done as a line was, and (FINISH) reports how it ended. Any other is +\ let go: passing a message on is MESH.md step 4. +: (IDLE) + (PORT)+8 b! @b (MSG) a! !+ \ to, from any port + (PORT)+9 b! @b (PORT) + dup b! \ B: the port it came on + 5 FOR @b !+ UNEXT \ from, type, heat and TTL, ACL tag, sequence, length + (REPLY) a! ! + (MSG)+6 a! @ -if SIZED jump BAD \ a length below zero: no telling what follows + SIZED: dup -1025 + -if LONG drop jump FITS + LONG: drop 3 + 2/ 2/ -1 + FOR @b drop UNEXT 0 \ too long: read it and let it go + BAD: drop 0 (MSG)+6 a! ! 0 SPAN a! ! NODE-ERROR b! 12 !b + FITS: + 3 + 2/ 2/ if EMPTY + -1 + TIB 2/ 2/ a! FOR @b !+ UNEXT + jump READ + EMPTY: drop + READ: + 0 (MSG)+6 a! @ TIB + C! \ a zero after the text + (MSG)+6 a! @ SPAN a! ! + (MSG) a! @ (ME) a! @ xor if MINE drop jump (IDLE) + MINE: drop + (MSG)+2 a! @ -1 + if TEXT drop jump (IDLE) + TEXT: drop jump (LINE) + +\ ( -- ) THE TEXT, INTERPRETED. It is in TIB with a zero after it and its +\ length in SPAN, and the return stack is empty. It is interpreted with one +\ return entry under it, this word's call of INTERPRET; whatever is on the +\ data stack stays there. : (LINE) 0 BLK a! ! \ the terminal, whatever was being loaded TIB (SRC) a! ! 0 >IN a! ! diff --git a/v4/include/v4/boot.h b/v4/include/v4/boot.h index 7adabf14..bfe0d07c 100644 --- a/v4/include/v4/boot.h +++ b/v4/include/v4/boot.h @@ -33,6 +33,7 @@ #define V4_BOOT_H #include "v4/image.h" +#include "v4/message.h" typedef struct { v4_node *n; @@ -66,8 +67,9 @@ typedef struct { int v4_boot_run(const v4_boot *b, unsigned char *disk, unsigned blocks); /* Hand the node a line and run it to its end, sending what it prints to - * `out`. Returns how it ended -- V4_LINE_QUIT, V4_LINE_COMPLETED or - * V4_LINE_ERROR (image.h) -- or one of these: */ + * `out`. The line is sent to the node as a message and what it prints + * comes back as messages (message.h). Returns how it ended -- V4_TEXT_QUIT, + * V4_TEXT_COMPLETED or V4_TEXT_ERROR -- or one of these: */ #define V4_BOOT_LINE_TOO_LONG (-1) /* more than the node's input buffer holds; nothing was run */ #define V4_BOOT_LINE_STOPPED (-2) /* the node stopped on a fault, or never finished */ #define V4_BOOT_LINE_NO_INPUT (-3) /* the line read the keyboard and there is no more input */ diff --git a/v4/include/v4/image.h b/v4/include/v4/image.h index 6d58c524..7c145c8e 100644 --- a/v4/include/v4/image.h +++ b/v4/include/v4/image.h @@ -10,6 +10,10 @@ * (capsules/v4/nucleus-.f18). docs/v4.0.0/MESH.md section 5. * - this description of it, a C file: the addresses a host needs. * + * A node that has taken the nucleus in is sent text as messages and sends + * back what it prints (v4/include/v4/message.h); nothing here hands it a + * line. + * * A description is for one cell width, one node size and one pair of stack * sizes; v4_image_born refuses one the engine was not built for. */ @@ -22,16 +26,10 @@ typedef struct { /* what the image was built for */ unsigned cell_bits, node_words, data_ring, ret_ring; - /* The node is handed a line (docs/v4.0.0/ENGINE.md 3.1). Its host puts - * text in the input buffer and starts it at `line`; it stops at `idle`, - * with how the line ended in the cell `line_status`. At switch-on it - * is at `idle`. */ - v4_cell line; /* (LINE) */ - v4_cell idle; /* (IDLE) */ - v4_cell line_status; /* word address of the variable (LINE-STATUS) */ - v4_cell tib; /* byte address of the input buffer */ - unsigned tib_bytes; /* its size: a line may be one less */ - v4_cell span; /* word address of the variable SPAN */ + /* Where the nucleus waits for a message (v4/capsule/quit.v4, (IDLE)): + * the node's P is there, blocked reading its ports, when it has nothing + * to do. */ + v4_cell idle; v4_cell fault_table; /* (FAULTS): where a fault goes */ v4_cell port; /* word address of the node's port (node.h) */ @@ -67,11 +65,6 @@ extern const v4_image v4_capsule_image; * back to, and FORGET will not go below it. */ void v4_image_seal(v4_node *n, const v4_image *im); -/* How a line ended. */ -#define V4_LINE_QUIT 0 /* QUIT: nothing is to be said */ -#define V4_LINE_COMPLETED 1 /* the host says " ok" */ -#define V4_LINE_ERROR 2 /* the message is printed; the host says " ERROR" */ - /* A node newly born (node.h), with the registers the nucleus expects of the * node it runs on -- and `disk`, `blocks` blocks of 1024 bytes, as its block * storage, or none if `disk` is 0. Its memory is empty and it is blocked @@ -81,21 +74,6 @@ void v4_image_seal(v4_node *n, const v4_image *im); int v4_image_born(v4_node *n, v4_exec_state *es, v4_heat *h, const v4_image *im, unsigned char *disk, unsigned blocks); -/* Hand the node `len` characters of text to interpret. Returns 1, or 0 if - * the text is longer than the node's input buffer holds (nothing is then - * done). After it the host runs the node -- v4_exec_step_word again and - * again, taking what the node prints from n->console and setting - * n->console_len back to 0 -- until v4_line_done; if v4_image_waiting comes - * first, the line is reading the keyboard, and the host gives it characters - * with v4_node_console_feed. */ -int v4_line_begin(v4_node *n, const v4_image *im, const char *text, unsigned len); - -/* 1 when the node has finished the line it was handed and is idle again. */ -int v4_line_done(const v4_node *n, const v4_image *im); - -/* How the line just finished ended: V4_LINE_QUIT, _COMPLETED or _ERROR. */ -int v4_line_status(const v4_node *n, const v4_image *im); - /* 1 if the node is waiting for a character: it is inside KEY and none is * pending. */ int v4_image_waiting(const v4_node *n, const v4_image *im); diff --git a/v4/include/v4/message.h b/v4/include/v4/message.h new file mode 100644 index 00000000..02b3dd18 --- /dev/null +++ b/v4/include/v4/message.h @@ -0,0 +1,63 @@ +/* message.h -- a message, as it is written to a port and read from one. + * docs/v4.0.0/MESH.md section 6. + * + * The ports are the transport; the message is what is transported. It is + * v3's Hermes message with what it carries, a word at a time: + * + * word 0 to: the node it is for + * word 1 from: the node that sent it + * word 2 type + * word 3 heat and TTL + * word 4 ACL tag: the sender's identity fingerprint + * word 5 sequence + * word 6 how many characters of text follow, 0 to 1024 + * word 7.. the text, four characters to a word, the first lowest + * + * Words 3, 4 and 5 are carried and not yet used: checking them is the + * router's, and awaits rulings (MESH.md section 3). + * + * This is for whatever is on the other end of a node's port and is not a + * node -- a console, a host -- to speak what the nodes speak (v4/capsule/ + * core.v4 and quit.v4 are the same thing in the node). Nothing here uses + * the C library. + */ +#ifndef V4_MESSAGE_H +#define V4_MESSAGE_H + +#include "v4/cell.h" + +#define V4_MSG_HEADER 7u +#define V4_MSG_MAX_CHARS 1024u /* a block */ +#define V4_MSG_MAX_WORDS (V4_MSG_HEADER + V4_MSG_MAX_CHARS / 4u) + +#define V4_MSG_TEXT 1 /* text to be interpreted */ +#define V4_MSG_OUTPUT 2 /* what a node printed */ +#define V4_MSG_DONE 3 /* how the text ended: one word, V4_TEXT_* */ + +/* how text ended */ +#define V4_TEXT_QUIT 0 /* QUIT: nothing is to be said */ +#define V4_TEXT_COMPLETED 1 /* a console says " ok" */ +#define V4_TEXT_ERROR 2 /* the message is printed; a console says " ERROR" */ + +typedef struct { + v4_cell word[V4_MSG_MAX_WORDS]; + unsigned count; /* words in it */ +} v4_message; + +/* A message of `len` characters, at most V4_MSG_MAX_CHARS. Returns how many + * words it is, or 0 if `len` is too many. */ +unsigned v4_message_text(v4_message *m, v4_cell to, v4_cell from, v4_cell type, const char *chars, unsigned len); + +/* A message arriving a word at a time. Start with m->count = 0 and give + * each word as it comes: returns 1 when the message is whole, 0 if there is + * more to come. A length that is not 0 to V4_MSG_MAX_CHARS is taken as 0. */ +int v4_message_word(v4_message *m, v4_cell word); + +/* Its parts. */ +#define v4_message_to(m) ((m)->word[0]) +#define v4_message_from(m) ((m)->word[1]) +#define v4_message_type(m) ((m)->word[2]) +unsigned v4_message_length(const v4_message *m); /* characters of text */ +char v4_message_char(const v4_message *m, unsigned i); /* the i-th of them */ + +#endif /* V4_MESSAGE_H */ diff --git a/v4/src/image.c b/v4/src/image.c index 847b17ce..9b079d42 100644 --- a/v4/src/image.c +++ b/v4/src/image.c @@ -29,39 +29,6 @@ int v4_image_waiting(const v4_node *n, const v4_image *im) return n->input_pos == n->input_len && n->p >= im->key_start && n->p < im->key_end; } -/* One byte of the node's memory: four to a cell, the first lowest, at either - * cell width -- as C! stores them (v4/capsule/core.v4). */ -static void put_byte(v4_node *n, v4_cell baddr, unsigned c) -{ - v4_cell word = baddr / 4; - unsigned shift = 8u * (unsigned)(baddr % 4); - v4_ucell mask = (v4_ucell)0xFFu << shift; - n->mem[word] = (v4_cell)(((v4_ucell)n->mem[word] & ~mask) | ((v4_ucell)(c & 0xFFu) << shift)); -} - -int v4_line_begin(v4_node *n, const v4_image *im, const char *text, unsigned len) -{ - unsigned i; - - if (len + 1u > im->tib_bytes) return 0; - for (i = 0; i < len; i++) put_byte(n, im->tib + (v4_cell)i, (unsigned char)text[i]); - put_byte(n, im->tib + (v4_cell)len, 0); - n->mem[im->span] = (v4_cell)len; - v4_rstack_reset(&n->rs); - n->p = im->line; - return 1; -} - -int v4_line_done(const v4_node *n, const v4_image *im) -{ - return n->p == im->idle; -} - -int v4_line_status(const v4_node *n, const v4_image *im) -{ - return (int)n->mem[im->line_status]; -} - void v4_image_seal(v4_node *n, const v4_image *im) { n->mem[im->boot_cells] = n->mem[im->dp]; diff --git a/v4/src/message.c b/v4/src/message.c new file mode 100644 index 00000000..8581a4df --- /dev/null +++ b/v4/src/message.c @@ -0,0 +1,44 @@ +/* message.c -- a message, as it is written to a port and read from one. + * See message.h. Nothing here uses the C library. + */ +#include "v4/message.h" + +unsigned v4_message_text(v4_message *m, v4_cell to, v4_cell from, v4_cell type, const char *chars, unsigned len) +{ + unsigned i, words; + + if (len > V4_MSG_MAX_CHARS) return 0; + words = (len + 3u) / 4u; + m->word[0] = to; + m->word[1] = from; + m->word[2] = type; + m->word[3] = 0; + m->word[4] = 0; + m->word[5] = 0; + m->word[6] = (v4_cell)len; + for (i = 0; i < words; i++) m->word[V4_MSG_HEADER + i] = 0; + for (i = 0; i < len; i++) + m->word[V4_MSG_HEADER + i / 4u] = (v4_cell)((v4_ucell)m->word[V4_MSG_HEADER + i / 4u] + | ((v4_ucell)(unsigned char)chars[i] << (8u * (i % 4u)))); + m->count = V4_MSG_HEADER + words; + return m->count; +} + +unsigned v4_message_length(const v4_message *m) +{ + v4_cell len = m->word[6]; + return (len < 0 || len > (v4_cell)V4_MSG_MAX_CHARS) ? 0u : (unsigned)len; +} + +char v4_message_char(const v4_message *m, unsigned i) +{ + return (char)(((v4_ucell)m->word[V4_MSG_HEADER + i / 4u] >> (8u * (i % 4u))) & 0xFFu); +} + +int v4_message_word(v4_message *m, v4_cell word) +{ + if (m->count < V4_MSG_MAX_WORDS) m->word[m->count] = word; + m->count++; + if (m->count < V4_MSG_HEADER) return 0; + return m->count >= V4_MSG_HEADER + (v4_message_length(m) + 3u) / 4u; +} diff --git a/v4/system/boot.c b/v4/system/boot.c index 33449540..a7f89e70 100644 --- a/v4/system/boot.c +++ b/v4/system/boot.c @@ -5,6 +5,7 @@ * which only a whole system has. */ #include "v4/boot.h" +#include "v4/message.h" #include "starkernel/capsule.h" #include "starkernel/capsule_generated.h" #include "starkernel/capsule_sig.h" @@ -126,22 +127,29 @@ static void post_watch(char c) post_len = 0; } +/* The boot is the node's neighbour on two of its ports. On port 0 it is + * the kernel: the node writes the number of a request there (ENGINE.md + * 3.3). On port 1 it is the console: it writes the node a message of text + * and reads back messages of what the node printed and of how the text + * ended (message.h). */ +#define KERNEL_PORT 0u +#define CONSOLE_PORT 1u +#define CONSOLE_ID 1 /* the console's number as a sender; the node's is 0 until it is given one */ + int v4_boot_line(const v4_boot *b, const char *text, unsigned len) { + static v4_message out, in; /* one line at a time: the boot is not re-entered */ v4_node *n = b->n; uint64_t steps = 0; - unsigned i; + unsigned sent = 0, i; - if (!v4_line_begin(n, b->im, text, len)) return V4_BOOT_LINE_TOO_LONG; + if (!v4_message_text(&out, 0, CONSOLE_ID, V4_MSG_TEXT, text, len)) return V4_BOOT_LINE_TOO_LONG; + in.count = 0; for (;;) { (void)v4_exec_step_word(n, b->es, b->h); - if (n->console_len) { - for (i = 0; i < n->console_len; i++) post_watch((char)n->console[i]); - b->out((const char *)n->console, n->console_len); - n->console_len = 0; - } if (n->stopped) return V4_BOOT_LINE_STOPPED; - if (n->asking) { /* blocked at its port: the kernel's turn */ + + if (n->asking && n->ask_port == KERNEL_PORT) { /* a request: the kernel's turn */ if (b->serve && n->request >= 1 && n->request <= (v4_cell)b->word_count) { b->serve(n, (unsigned)n->request); v4_node_port_served(n); @@ -153,8 +161,34 @@ int v4_boot_line(const v4_boot *b, const char *text, unsigned len) } continue; } - if (v4_line_done(n, b->im)) return v4_line_status(n, b->im); - if (v4_image_waiting(n, b->im)) { /* the line is reading the keyboard */ + if (n->asking && n->ask_port == CONSOLE_PORT) { /* a word of a message from the node */ + v4_cell word = n->request; + v4_node_port_served(n); + if (v4_message_word(&in, word)) { + unsigned chars = v4_message_length(&in); + if (v4_message_type(&in) == V4_MSG_OUTPUT) { + for (i = 0; i < chars; i++) { + char c = v4_message_char(&in, i); + post_watch(c); + b->out(&c, 1); + } + } else if (v4_message_type(&in) == V4_MSG_DONE) { + return (int)in.word[V4_MSG_HEADER]; + } + in.count = 0; + } + continue; + } + if (n->asking) return V4_BOOT_LINE_STOPPED; /* a port with nothing on it */ + + if (n->reading && !n->given) { + if (sent < out.count && (n->read_port == CONSOLE_PORT || n->read_port == V4_PORT_ANY)) { + v4_node_port_give(n, CONSOLE_PORT, out.word[sent++]); /* a word of the message to the node */ + continue; + } + return V4_BOOT_LINE_STOPPED; /* waiting for what will not come */ + } + if (v4_image_waiting(n, b->im)) { /* the text is reading the keyboard */ int c = b->key ? b->key() : V4_BOOT_KEY_END; unsigned char ch = (unsigned char)c; if (c == V4_BOOT_KEY_END) return V4_BOOT_LINE_NO_INPUT; @@ -225,10 +259,10 @@ static int load_capsule(const v4_boot *b, const char *name) if (len) { for (i = 0; i < len; i++) text[i] = (char)p[i]; int how = v4_boot_line(b, text, len); - if (how != V4_LINE_COMPLETED) { + if (how != V4_TEXT_COMPLETED) { say_where(b, name, block, line); - say(b, how == V4_LINE_ERROR ? " ended in an error: " - : how == V4_LINE_QUIT ? " ended with QUIT: " + say(b, how == V4_TEXT_ERROR ? " ended in an error: " + : how == V4_TEXT_QUIT ? " ended with QUIT: " : how == V4_BOOT_LINE_NO_INPUT ? " reads the keyboard: " : " stopped the node: "); b->out(text, len); say(b, "\n"); @@ -289,7 +323,9 @@ static int load_nucleus(const v4_boot *b) if (!p || cap->length % CELL_BYTES != 0) { say(b, "V4: capsule " NUCLEUS_NAME " is not whole words\n"); return 0; } words = cap->length / CELL_BYTES; - while (at < words || !v4_line_done(n, b->im)) { + /* until it has taken every word and is waiting for a message: reading + * its ports again, but from its memory now and not from the port */ + while (at < words || !(n->reading && !n->given && n->p != b->im->port + (v4_cell)V4_PORT_ANY)) { (void)v4_exec_step_word(n, b->es, b->h); if (n->stopped || n->asking || ++steps > STEP_LIMIT) { say(b, "V4: the node did not take the nucleus in\n"); @@ -298,7 +334,11 @@ static int load_nucleus(const v4_boot *b) if (n->reading && !n->given) { v4_ucell word = 0; unsigned i; - if (at >= words) { say(b, "V4: the node wants more than the nucleus holds\n"); return 0; } + if (at >= words) { + if (n->p != b->im->port + (v4_cell)V4_PORT_ANY) break; /* it is waiting for a message */ + say(b, "V4: the node wants more than the nucleus holds\n"); + return 0; + } for (i = 0; i < CELL_BYTES; i++) word |= (v4_ucell)p[at * CELL_BYTES + i] << (8 * i); v4_node_port_give(n, 0, (v4_cell)word); at++; @@ -335,7 +375,7 @@ int v4_boot_run(const v4_boot *b, unsigned char *disk, unsigned blocks) for (; div; div /= 10) text[at++] = (char)('0' + num / div % 10); for (k = 0; " KERNEL-WORD "[k]; k++) text[at++] = " KERNEL-WORD "[k]; for (k = 0; b->words[i][k] && at < sizeof text; k++) text[at++] = b->words[i][k]; - if (b->words[i][k] || v4_boot_line(b, text, at) != V4_LINE_COMPLETED) { + if (b->words[i][k] || v4_boot_line(b, text, at) != V4_TEXT_COMPLETED) { say(b, "V4: kernel word "); say(b, b->words[i]); say(b, " could not be made\nPARITY:FAIL\nPOST: FAILED\n"); return 0; } diff --git a/v4/tests/host_map.h b/v4/tests/host_map.h index d1b6e34c..78f5354e 100644 --- a/v4/tests/host_map.h +++ b/v4/tests/host_map.h @@ -69,6 +69,12 @@ #define CATCH (BUF0_W - 8) /* non-zero: a line's error is recorded here, -1, and the line ends " ok" */ #define LINE_STATUS (BUF0_W - 9) /* how the last line ended: 0 QUIT, 1 completed, 2 an error */ #define PORT (BUF0_W - 32) /* the node's ports (node.h): V4_PORTS of them, then "any port" and "which port". Port 0 is where its requests go. */ +#define ME (BUF0_W - 13) /* this node's number: a message is for it when its first word is this */ +#define OUT_PTR (BUF0_W - 14) /* where the next character printed goes: a cell of the output buffer */ +#define REPLY (BUF0_W - 15) /* the address of the port the message being served came on */ +#define MSG (BUF0_W - 48) /* the header of the message being served, 7 cells */ +#define OUT_W (BUF0_W - 400) /* the output buffer: 256 cells, a character to a cell */ +#define OUT_CELLS 256 #define WORD_DEFINED (BUF0_W - 11) /* the xt of the word that is told of each new entry, or 0 */ #define WORD_FORGOTTEN (BUF0_W - 12) /* the xt of the word that is told when entries go, or 0 */ #define LOG_LEVEL (BUF0_W - 5) /* the level at or below which a message is printed */ @@ -108,6 +114,7 @@ static int host_load(v4_text *tx, v4_node *n, const char *const *files, unsigned unsigned i; v4_node_reset(n); + n->mem[OUT_PTR] = OUT_W; /* nothing has been printed: what is, is kept from here (core.v4) */ v4_text_begin(tx, n, 16); v4_text_constant(tx, "N-1", V4_CELL_BITS - 1); v4_text_constant(tx, "NODE-ERROR", NODE_ERROR); @@ -148,6 +155,11 @@ static int host_load(v4_text *tx, v4_node *n, const char *const *files, unsigned v4_text_constant(tx, "(CATCH)", CATCH); v4_text_constant(tx, "(LINE-STATUS)", LINE_STATUS); v4_text_constant(tx, "(PORT)", PORT); + v4_text_constant(tx, "(ME)", ME); + v4_text_constant(tx, "(OUT^)", OUT_PTR); + v4_text_constant(tx, "(REPLY)", REPLY); + v4_text_constant(tx, "(MSG)", MSG); + v4_text_constant(tx, "(OUT)", OUT_W); v4_text_constant(tx, "(WORD-DEFINED)", WORD_DEFINED); v4_text_constant(tx, "(WORD-FORGOTTEN)", WORD_FORGOTTEN); v4_text_constant(tx, "BLOCK-NUMBER", STORAGE_REG); diff --git a/v4/tests/test_host_input.c b/v4/tests/test_host_input.c index f2ac3b4e..c0c33250 100644 --- a/v4/tests/test_host_input.c +++ b/v4/tests/test_host_input.c @@ -263,7 +263,10 @@ int main(void) } n.mem[BASE] = 10; CHECK(v4_node_console_feed(&n, "Z", 1) == 1 && run("KEY", 0, 0, 0, 0) && pop() == 'Z' && clean(), "KEY"); - CHECK(run("EMIT", 1, 'q', 0, 0) && clean() && n.console_len == 1 && n.console[0] == 'q', "EMIT"); + /* a node has no console of its own: what it prints is kept to be sent (core.v4) */ + n.mem[OUT_PTR] = OUT_W; + CHECK(run("EMIT", 1, 'q', 0, 0) && clean() && n.mem[OUT_PTR] == OUT_W + 1 && n.mem[OUT_W] == 'q', "EMIT"); + CHECK(run("EMIT", 1, 0x141, 0, 0) && clean() && n.mem[OUT_PTR] == OUT_W + 2 && n.mem[OUT_W + 1] == 'A', "EMIT prints the low 8 bits"); } /* ---- the in-line names ---- */ diff --git a/v4/tests/test_host_quit.c b/v4/tests/test_host_quit.c index 6698386d..e06575bb 100644 --- a/v4/tests/test_host_quit.c +++ b/v4/tests/test_host_quit.c @@ -41,7 +41,7 @@ * 3 ROLL is ROT. v3's count from zero. */ #include "v4/text.h" -#include "v4/image.h" +#include "v4/message.h" #include "v4/testcode.h" #include #include @@ -59,7 +59,7 @@ static v4_exec_state es; static v4_heat h; static v4_text tx; static v4_cell w_key, w_key_end, w_fault, capsule_latest; -static v4_image img; /* where a line is handed to the node: v4/include/v4/image.h */ +static v4_cell w_idle; /* (IDLE): where the node waits for a message */ static char out[V4_CONSOLE_CAP + 1]; /* The storage device's blocks: zeros at every switch-on. */ @@ -73,16 +73,6 @@ static void put_block(unsigned num, const char *text) } static long last_steps; -/* THE HOST. A node is handed a line and prints no prompt (ENGINE.md 3.1); - * these tests are its host, and do what tools/hosted.c does: take what is - * typed a line at a time, hand each line over, and say " ok" or " ERROR" and - * the next prompt. What is typed after a line is there for a word in it - * that reads the keyboard, and what such a word does not take is the next - * line. */ -static char typed[8192]; /* typed and not yet taken */ -static unsigned typed_len; -static int line_open; /* a line has been handed over and has not ended */ - /* THE KERNEL. A node asks its kernel by writing to its port (node.h), and * these tests are that too. Request 1 is "an entry has been made" ( xt -- ) * and request 2 "the entries from here up have gone" ( w -- ): the kernel's @@ -149,7 +139,31 @@ static const char *node_name(v4_cell xt) return name; } -/* Run until the line ends, or until it has been inside KEY with nothing to +/* THE CONSOLE. A node is sent text as a message and sends back what it + * prints (MESH.md section 6); these tests are its console, on its port 1, + * and do what tools/hosted.c does: take what is typed a line at a time, + * send each line as a message, show what comes back, and say " ok" or + * " ERROR" and the next prompt. What is typed after a line is there for a + * word in it that reads the keyboard, and what such a word does not take is + * the next line. */ +#define CONSOLE_PORT 1u +static char typed[8192]; /* typed and not yet taken */ +static unsigned typed_len; +static int line_open; /* a line has been sent and has not ended */ +static v4_message to_node, from_node; /* the message going in, and the one coming out */ +static unsigned to_sent; /* how many words of to_node the node has taken */ +static char shown[V4_CONSOLE_CAP]; /* what the node has printed since the console last looked */ +static unsigned shown_len; +static int shown_dropped; +static int text_ended; /* how the text ended, when it has */ + +/* 1 if the node is where it waits for a message, with nothing given it. */ +static int node_idle(void) +{ + return n.reading && !n.given && n.read_port == V4_PORT_ANY && n.p > w_idle && n.p <= w_idle + 3; +} + +/* Run until the text ends, or until it has been inside KEY with nothing to * read for 64 instruction words; or until `max` words. 1: ended, 2: waiting * for a character, 0: neither. */ static int run_line(long max) @@ -157,14 +171,36 @@ static int run_line(long max) long steps = 0; unsigned idle = 0; while (steps < max && idle < 64) { - if (v4_line_done(&n, &img)) { last_steps = steps; return 1; } (void)v4_exec_step_word(&n, &es, &h); steps++; - if (n.asking) { kernel_serve(); v4_node_port_served(&n); } /* blocked at its port: the kernel's turn */ + if (n.asking && n.ask_port == 0) { kernel_serve(); v4_node_port_served(&n); continue; } /* a request */ + if (n.asking && n.ask_port == CONSOLE_PORT) { /* a word of a message from the node */ + v4_cell word = n.request; + v4_node_port_served(&n); + if (v4_message_word(&from_node, word)) { + unsigned i, chars = v4_message_length(&from_node); + if (v4_message_type(&from_node) == V4_MSG_OUTPUT) { + for (i = 0; i < chars; i++) { + if (shown_len < sizeof shown) shown[shown_len++] = v4_message_char(&from_node, i); + else shown_dropped = 1; + } + } else if (v4_message_type(&from_node) == V4_MSG_DONE) { + text_ended = (int)from_node.word[V4_MSG_HEADER]; + from_node.count = 0; + last_steps = steps; + return 1; + } + from_node.count = 0; + } + continue; + } + if (n.reading && !n.given && to_sent < to_node.count && (n.read_port == CONSOLE_PORT || n.read_port == V4_PORT_ANY)) { + v4_node_port_give(&n, CONSOLE_PORT, to_node.word[to_sent++]); /* a word of the message to the node */ + continue; + } if (n.input_pos == n.input_len && n.p >= w_key && n.p < w_key_end) idle++; else idle = 0; } last_steps = steps; - if (v4_line_done(&n, &img)) return 1; return idle >= 64 ? 2 : 0; } @@ -193,7 +229,6 @@ static void boot_with(unsigned depth) for (v4_cell k = BVARS; k < BVARS + 14; k++) if (k != SRC) n.mem[k] = 0; /* empty buffers, SCR and BLK 0, no hook */ memset(disk, 0, sizeof disk); v4_node_storage_attach(&n, STORAGE_REG, disk, DISK_BLOCKS); - v4_node_console_attach(&n, CONSOLE_TX); v4_node_console_input_attach(&n, CONSOLE_RX, CONSOLE_ST); v4_node_fault_attach(&n, w_fault); v4_node_error_attach(&n, NODE_ERROR); @@ -208,10 +243,16 @@ static void boot_with(unsigned depth) n.mem[WORD_FORGOTTEN] = 0; known_n = 0; last_request = 0; - n.mem[LINE_STATUS] = V4_LINE_COMPLETED; - n.p = img.idle; /* idle, waiting to be handed a line */ + n.mem[LINE_STATUS] = 1; + n.mem[ME] = 0; /* it has no number yet: a message to 0 is for it */ + n.mem[OUT_PTR] = OUT_W; + n.mem[REPLY] = PORT + CONSOLE_PORT; + n.p = w_idle; /* waiting for a message */ typed_len = 0; line_open = 0; + to_node.count = 0; to_sent = 0; from_node.count = 0; + shown_len = 0; shown_dropped = 0; + (void)v4_exec_step_word(&n, &es, &h); /* it reads its ports, and is blocked */ } static void boot(void) { boot_with(0); } /* The same with nothing at all on the data stack. */ @@ -252,27 +293,27 @@ static const char *say(const char *input) unsigned len; if (!nl) break; len = (unsigned)(nl - typed); - if (!v4_line_begin(&n, &img, typed, len)) return "(line too long)"; + if (!v4_message_text(&to_node, 0, 1, V4_MSG_TEXT, typed, len)) return "(line too long)"; + to_sent = 0; memmove(typed, nl + 1, typed_len - len - 1); typed_len -= len + 1; line_open = 1; } - v4_node_console_attach(&n, CONSOLE_TX); /* empties the capture */ - v4_node_console_input_attach(&n, CONSOLE_RX, CONSOLE_ST); /* and the keyboard */ + shown_len = 0; shown_dropped = 0; + v4_node_console_input_attach(&n, CONSOLE_RX, CONSOLE_ST); /* empties the keyboard */ if (v4_node_console_feed(&n, typed, typed_len) != typed_len) return "(input queue full)"; ended = run_line(40000000); took = n.input_pos; /* what a word in the line read */ memmove(typed, typed + took, typed_len - took); typed_len -= took; - if (n.console_dropped || olen + n.console_len + 16 > sizeof out) return "(too much output)"; - memcpy(out + olen, n.console, n.console_len); - olen += n.console_len; + if (shown_dropped || olen + shown_len + 16 > sizeof out) return "(too much output)"; + memcpy(out + olen, shown, shown_len); + olen += shown_len; out[olen] = 0; if (ended == 0) return "(still running)"; if (ended == 2) break; line_open = 0; - tail = v4_line_status(&n, &img) == V4_LINE_COMPLETED ? " ok\nok> " - : v4_line_status(&n, &img) == V4_LINE_ERROR ? " ERROR\nok> " : "ok> "; + tail = text_ended == V4_TEXT_COMPLETED ? " ok\nok> " : text_ended == V4_TEXT_ERROR ? " ERROR\nok> " : "ok> "; memcpy(out + olen, tail, strlen(tail) + 1); olen += (unsigned)strlen(tail); } @@ -739,12 +780,7 @@ int main(void) CHECK(v4_text_here(&tx) < DICT_W, "code stays below the dictionary space"); printf(" capsule: %ld words\n", (long)v4_text_here(&tx) - 16); if (failures) { printf(" %d checks, %d failures\n", checks, failures); return 1; } - img.line = v4_text_word(&tx, "(LINE)"); - img.idle = v4_text_word(&tx, "(IDLE)"); - img.line_status = LINE_STATUS; - img.tib = TIB; - img.tib_bytes = 1025u; - img.span = SPAN; + w_idle = v4_text_word(&tx, "(IDLE)"); w_key = v4_text_word(&tx, "KEY"); w_key_end = v4_text_word(&tx, "CR"); /* the word after KEY in core.v4 */ w_fault = v4_text_word(&tx, "(FAULTS)"); @@ -753,11 +789,12 @@ int main(void) /* ---- switch-on ---- */ boot(); - CHECK(v4_line_done(&n, &img) && n.console_len == 0, "the node is idle and has printed nothing: the prompt is its host's"); - CHECK(run_line(5000) == 1 && last_steps == 0, "and goes on waiting to be handed a line"); + CHECK(node_idle() && n.mem[OUT_PTR] == OUT_W, "the node is waiting at its ports and has printed nothing: the prompt is its console's"); + { v4_uheat_t clock = es.anticlock; + CHECK(run_line(5000) == 0 && es.anticlock == clock, "and goes on waiting, executing nothing"); } CHECK(canary_under_expect(), "with the data stack as it found it"); (void)v4_exec_step_word(&n, &es, &h); - CHECK(v4_line_done(&n, &img), "it stays idle however long it is run"); + CHECK(node_idle(), "it stays waiting however long it is run"); /* ---- the sessions ---- */ for (i = 0; i < NSCRIPT; i++) { @@ -883,7 +920,7 @@ int main(void) memcpy(line, "65 EMIT", 7); line[1025] = '\n'; line[1026] = 0; CHECK(is(say(line), "(line too long)"), "one of 1025 is not taken: the node's input buffer holds a block"); - CHECK(v4_line_done(&n, &img) && n.console_len == 0, "and nothing of it was run"); + CHECK(node_idle() && n.mem[OUT_PTR] == OUT_W, "and nothing of it was sent"); } /* ---- ABORT and QUIT from deep in a programme, again and again ---- */ @@ -1247,7 +1284,7 @@ int main(void) boot_bare(); CHECK(load_source("tools.fth"), "tools.fth compiles, every line of it"); CHECK(is(say(": SQ DUP * ; SEE SQ\n"), ": SQ\n dup call * \n ; \n ok\nok> "), "a definition: an in-line word, a call by name, the return"); - CHECK(is(say("SEE DUP\n"), ": DUP\n dup ; \n ok\nok> ") && is(say("SEE EMIT\n"), out) && strncmp(out, ": EMIT\n @p ", 12) == 0 && strstr(out, " b! !b ; \n"), + CHECK(is(say("SEE DUP\n"), ": DUP\n dup ; \n ok\nok> ") && is(say("SEE EMIT\n"), out) && strncmp(out, ": EMIT\n @p ", 12) == 0 && strstr(out, " b! @b \n if ") && strstr(out, " pop a! ; \n"), "the capsule's own words; a literal's value follows its @p"); CHECK(is(say("VARIABLE V 7 V ! SEE V\n"), ": V\n data: 7 \n ok\nok> ") && is(say("5 CONSTANT K SEE K\n"), ": K\n data: 5 \n ok\nok> "), "a variable and a constant show what they hold"); CHECK(is(say(": IM 1 ; IMMEDIATE SEE IM\n"), ": IM\n @p 1 ; \nIMMEDIATE\n ok\nok> "), "an immediate word says so"); diff --git a/v4/tools/hosted.c b/v4/tools/hosted.c index ab3cc20e..f3fb77b9 100644 --- a/v4/tools/hosted.c +++ b/v4/tools/hosted.c @@ -67,9 +67,9 @@ int main(void) len = strlen(line); if (len && line[len - 1] == '\n') len--; how = v4_boot_line(&boot, line, (unsigned)len); - if (how == V4_LINE_COMPLETED) fputs(" ok\n", stdout); + if (how == V4_TEXT_COMPLETED) fputs(" ok\n", stdout); if (leaving) { fflush(stdout); return 0; } - else if (how == V4_LINE_ERROR) fputs(" ERROR\n", stdout); + else if (how == V4_TEXT_ERROR) fputs(" ERROR\n", stdout); else if (how == V4_BOOT_LINE_TOO_LONG) fputs("Line too long\n ERROR\n", stdout); else if (how == V4_BOOT_LINE_NO_INPUT) { putchar('\n'); return 0; } else if (how == V4_BOOT_LINE_STOPPED) { fflush(stdout); fprintf(stderr, "starforth4: the node stopped on a fault\n"); return 1; } diff --git a/v4/tools/mkimage.c b/v4/tools/mkimage.c index 1a063081..3e333119 100644 --- a/v4/tools/mkimage.c +++ b/v4/tools/mkimage.c @@ -52,7 +52,7 @@ int main(int argc, char **argv) static const char *const files[] = { "core.v4", "input.v4", "dict.v4", "codegen.v4", "compile.v4", "quit.v4", "forth.v4", "numout.v4", "words.v4", "system.v4", "qmath.v4", "blocks.v4", "log.v4", "acl.v4" }; FILE *out; - v4_cell k, line, idle, faults, voc; + v4_cell k, idle, faults, voc; unsigned count = 0; if (argc != 3) die("usage: mkimage DESCRIPTION.c CAPSULE.f18", NULL); @@ -60,7 +60,6 @@ int main(int argc, char **argv) if (!host_load(&tx, &n, files, (unsigned)(sizeof files / sizeof files[0]))) die("the capsule does not assemble", NULL); if (!v4_text_finish(&tx)) die("not everything is defined", v4_text_error(&tx)); if (v4_text_here(&tx) >= DICT_W) die("the capsule's code runs into the dictionary space", NULL); - line = v4_text_word(&tx, "(LINE)"); idle = v4_text_word(&tx, "(IDLE)"); faults = v4_text_word(&tx, "(FAULTS)"); w_key = v4_text_word(&tx, "KEY"); @@ -99,7 +98,8 @@ int main(int argc, char **argv) for (voc = n.mem[VOC_LINK]; voc != 0; voc = n.mem[voc + 1]) clear_acl(n.mem[voc]); if (!v4_node_guards_intact(&n)) die("the node's guards are damaged", NULL); - n.mem[LINE_STATUS] = V4_LINE_COMPLETED; /* idle, with nothing to report */ + n.mem[LINE_STATUS] = 1; /* nothing has ended badly */ + n.mem[OUT_PTR] = OUT_W; /* nothing has been printed */ /* the nucleus as a capsule of F18 code: the words a neighbour writes to * an empty node's port, each in V4_CELL_BITS / 8 bytes, low byte first */ @@ -113,8 +113,7 @@ int main(int argc, char **argv) fprintf(out, "/* Generated by v4/tools/mkimage.c from v4/capsule -- do not edit. */\n#include \"v4/image.h\"\n\n"); fprintf(out, "const v4_image v4_capsule_image = {\n %uu, %uu, %uu, %uu,\n", (unsigned)V4_CELL_BITS, (unsigned)V4_NODE_WORDS, (unsigned)V4_DATA_RING, (unsigned)V4_RET_RING); - fprintf(out, " %ld, %ld, %ld,\n %ld, %uu, %ld,\n %ld, %ld,\n %ld, %ld,\n", (long)line, (long)idle, (long)LINE_STATUS, - (long)TIB, 1025u, (long)SPAN, (long)faults, (long)PORT, (long)w_key, (long)w_key_end); + fprintf(out, " %ld,\n %ld, %ld,\n %ld, %ld,\n", (long)idle, (long)faults, (long)PORT, (long)w_key, (long)w_key_end); fprintf(out, " %ld, %ld, %ld,\n %ld, %ld,\n %ld,\n %ld,\n %ld, %ld,\n %ld, %ld\n};\n", (long)CONSOLE_TX, (long)CONSOLE_RX, (long)CONSOLE_ST, (long)DSTACK_REG, (long)RSTACK_REG, (long)NODE_ERROR, (long)STORAGE_REG, (long)DP, (long)LATEST, (long)BOOT_CELLS, (long)FENCE);