From 6015c87157c1bf25fb9f04c69eb59ac13977cc6d Mon Sep 17 00:00:00 2001 From: rajames Date: Thu, 8 Oct 2026 07:31:40 -0400 Subject: [PATCH] revert(v4.0.0): step 6d, the wait, is backed out -- two reviews found it unsound Ruled 2026-10-08. The engine, the nucleus and their tests are as they were at dfabfa46, before step 6d; the code of the wait and its tests are in history at 075385ab..2cf37aab. The limit of MESH.md 7b.7 stands: a node that is stuck can hold up its neighbours until Hera kills it. MESH.md 7c is kept as the record of the design as approved, and 7c.6 says what was built, what the two reviews found, the cause the findings share -- a node's message machinery runs on the stacks its text is using, and a fault abandons whatever was in progress -- and what a second attempt must settle before anything is built. Kept from it, in hosted-check: a line that leaves 29 values on the stack, and WORDS with 26 values on it. Both hung the products at some commit of the wait. make -C v4 test and sanitize at both widths, hosted-check, lint; three bare-metal boots typing both. POST 538 of 538, word_count=317, dict_hash=0xc0769523a47b7dc3 on all six: the hash of step 6c's code. Co-Authored-By: Claude Opus 5.5 --- capsules/v4/nucleus-64.f18 | Bin 59800 -> 56608 bytes docs/v4.0.0/MESH.md | 313 +++++++--------- .../amd64/qemu-amd64-20261008-072104.log | 204 ++++++++++ .../aarch64/qemu-aarch64-20261008-072354.log | 177 +++++++++ .../riscv64/qemu-riscv64-20261008-072743.log | 247 +++++++++++++ v4/Makefile | 2 + v4/README.md | 13 +- v4/capsule/core.v4 | 221 ++++------- v4/capsule/quit.v4 | 349 +++++------------- v4/include/v4/fabric.h | 15 + v4/include/v4/image.h | 5 + v4/include/v4/node.h | 58 +-- v4/src/fabric.c | 58 ++- v4/src/node.c | 84 +---- v4/system/boot.c | 1 - v4/tests/host_map.h | 20 +- v4/tests/test_fabric.c | 226 +++--------- v4/tests/test_host_mesh.c | 239 ++---------- v4/tests/test_host_quit.c | 20 +- v4/tests/test_host_unit.c | 59 ++- 20 files changed, 1108 insertions(+), 1203 deletions(-) create mode 100644 logs/20261008-072104/amd64/qemu-amd64-20261008-072104.log create mode 100644 logs/20261008-072354/aarch64/qemu-aarch64-20261008-072354.log create mode 100644 logs/20261008-072743/riscv64/qemu-riscv64-20261008-072743.log diff --git a/capsules/v4/nucleus-64.f18 b/capsules/v4/nucleus-64.f18 index 78a565975440bdf6a27f3b767f202f3283fd43f6..6f8189113aac25137fb5b6eab2a7dfb10642796a 100644 GIT binary patch literal 56608 zcmb__34B$>_5aPw0$~ZOEYjAeVg)RVs1*<~Aq$CyBqU)`tAY>(1#%5R5m94HT~cJJ z`vOKqEQ-{Hwy3C4siM_aP~55_t+Aq_rWmwPh5wv6-|v0z4!lPD``=GKId5jpHfPS9 zS?=6>{cT&uc;@OX|I9U`k3v6IlqAe*fTB$vOr3 z%|Dy_rTpBu;H0Yr9_BT^BhZiae?lPXqEN+;4Sz=RkMI_MA+WEP_Ow8gZ}H`~T>ZQ( zTkfB|%$AdnQQE5N;%_ZE?p2|icIYMf0*P<%+DJN*cZ`7G8iZfn0h``^Qsu=SdQ-Aa z^t@pLPx7*!5;y{KhkJ{yJ|}r;HsA19m^D2ncwW6i%5RfbV)Yr5Q)!{aG5=1+kD-7C z-l7%qb6Wj*);^@C{(e@!kUb;0*`QQVh}3An%9i^!%Fk4!&-J_^^7Cx3gVkd{uG5`# zVgHY;oWlP1-6;4j^vjmn{QXjBu4MRrEJx)iT7XyCSNW1Ys9)I@E0_6^+`~bsU>Z`z zfNuSMh5B9L)aMc>y|LHS4Z^~}MF)e$>ju>V-ca3D4Yq|n& z8T>c8L|8%c$v*b^!A7LdBpV0K{m!({_-M`<+(f*jF za{Sm^Htw81T(CUve(-PJ*G20I!d@u%W3!$Uyw$+-W7W3)cS{H`m$9GaC%@&Y+r7os z=RDBY-SN6jKOE4X6q56hmu*xOKI)G_J+jo!K{|G6NRA&n#_GlL_2i$m%gU>*f7JQ` z%h$mUJHOWYS38-;zXM(d@Lu=ojO%%x8K11* zn6%3GzqEc>eEa#pke$>e)e?NBV{la^} z!cF4^GM{oyd(4-7UePB;S-aDZMzj7UTlNYL+v7yo`NSmcaR>Zvc)UK=Pw9`Rqdv{M z$63Fm9qEts(;Ucm^Qo7cpPK|fFG+rWl6>07K@m0n9h&AWZUVSz-~J4V;o?AVSitJ>i6d&U5j>p6mi1;=vdoN*>9$U-%RkUMZ6b5$i$KQxo8b?BYO^*Ur4&>i?) z9l9t`(sN5~+%Itq)(7~#0gFBDzy8wxp9(3*fwaog?Reve^^OEx6mVcf=OM$IbUna$ zMLwqe>^OBi>|*3?7CFX#HV%~C7?w+aGkk5oH0@yLSHnTS7x9Mc;S(YY?K+r#QnpaX zn}5UZm^SRshMs=bX3LNE^-DBZ?L&jQ$I!9pE>KY_eY0sVcW=8LQyOk+Mt zyo*5JHbVc``Qq2Gi;r?2aff`&I@h)%=M&6l`!k<%*uLkWeQP2cZF`vdKO_1X{-Xu* zB0tKZU764NHDG+9osHl8M|jYG(#MUru3R4K&7OBT>^TuI+M@EKdsG9qAJevROp(F2 z^=8~sY|r}!_NAU*AWc5T{~H8%8SRO7=emyd+73hA65ypc{-WuqFf&)fH{)#m_G>a| z=d0j<4H2CmnfSd!Q0@-;7wisyp#4?_{uSO2~V(hCtvo%DCU*4BkfFoFmcoNKi0be z`wGHKF7l7_)qdgnN5C&OJX`3m0olld|2@2HmXQ%%$EOw$xusT!XS zOLg}*bUwv>4$}8Y)$x{eKLs7fPmZrH-4UQ`lV4)z=f$NJ)(@#ie@rO9h2qcFb{_<| zVTr~Sw)f|VQ}n-KuyYmVKCJ5t;*E%?{n=kGA>Ka4V}Blj{?;9S&HXY%ze)5=$hZ64 zYnJGJ8qyENzM@bA}Q$Y$)L z35{GkVV~4NoLNiGBN8mpONPoE!^PcCRPbJ2E zjwg*U1ow%vA&282=Rw3b^6mV=Yg%gex46zp2OUAQSl1uB;XhuTmY6uOTz*mSE$BZl zr0V=PTK`kK{`B5feB!;C+IY9*5YKDUbtU<;J<|%cfkMI8(7gk@JONl(f1}l(^vD+b zE)_ZHImLFJJ;p{A$lxO~Qx!xqj@b2Zhq`Ga<(FN<-1f^e^!FI1X(;csaGe zF6D#v{+Uq6uNL6{3$SeENINfb>r;08Mb;G5hjvX%)B70Q-*?xoY)>QKu3HPo==v}X zD)`&~c#Hgu!iwlno*`%U-i8iX(F9T^(t-wpiR z19IMH7PfW9YS-EN&nKg)S*EXCT5_DLV5{!nt7Xcxcwf<6jp z;)|tYeNu}Ha^l#YcMS0Q$6;qFPcJUAo_5-(L~L`j3wVPA{?A%_rjIJIe8*a8ahjh4 z?*zb&>ql9Pg!zkY&(xBzUZa42QXHyYB{??k^h~2nqq&j;Uo~yh@Z;03MNs{hPD(ehRX^v*B;_IIMB5UhlWlUhF5t&!`w{ z_pkECgeA=Z{|f<)|5^XP9Q=m0sYSG#gop%2yNxPGd?QZrtMzd}Lo4~gb(A4W3$?uk~;~d+I_9is*Fx#Oy zzOa9O1v_?1S3l(Xnskig3%Y-3#{t^U%!B8PTiAPyfsV&ENQxr3j!4%Zze2#_{5*>Ccfscb%-hG8oMr-ablbnpzJInLD3<4$`yMvmosZLwmYMl?5Irqj z4(wsZIXk`$fZvTp{%PsqeUl<59jvE1siYviUp+3K)&_{D_uF|0_nE2ZX0#L2Taezc zMEB8{{~GeS@BAYaypQ~iz0@zsZ$ZoSMS?- zGl_@$0hE76y0*)-bhWFQhdm*Ds1M_tiBF+;@*ec(J{{An@8#%M(GALv<*bLf?|ZMv zc^!Nxrv`eIqJ7za7$4sOKJ}(On7;`1T;#Mre;e(Obur~khW$By7(J}NZN5(L`%+)dNAFG7^$_)034JH0>$pokYnJGF zNzxnp-6MMb&9$G?uJj9|m+fcEp`V|n`jDRI{H(Hu?`YsP4A%McyO6VW@niNr?#MIF zKU?IpenDK0>HLHEk3ep+@<1Q#$5S8DJ(XUUEpj6A&sy@ z?`P2OHo;ylU+VoC_|pH$H_+$dea}mM*)F_Kn+(>~ue?$450ii9GW-883VaUsG2>il z9Dg49f+LrY_I?5R8?V)VMtXmr`t45mQ_l>YpK#xp=WseRANPZsP@x{kzY_g{=V>S} zuxCvBG2>%L(Cua1L7b%iyI|+-7>}9XygPipwQ|zr`V1^ z&Zt{0_SpsbFHjHoc@5SXN3!0yFUWQ?d~Mt&UvrMyUL)%V*!9H+u#Y`qZAwVD-O=aR zjAGk<0p32{&*sU&<4`X@_Ak31`I8JCKiqmnRlGM2^`hVQIrF&Vr04|92RNUY1$?F_ z=9Gu#BO{`U!16w44zVOm=j0ZT5DccH)2e1Cre{=5izcRzmV~*=p?|XZ%6mKiI7aaP z1%G{${S9&aAoCv^H{0Y-vUbcJAAWveJSO}{rwdox4m$*zeTi&=oJTdFof)sVZ!9=+ zasS=)xA~H$UvocN^5kNFfHc-LEORl0nQ(YM>^iOxHd!gCAiPadQ^+l_{-o^p7DZ>H|*adqEoBIE=Z|3-fuuY@87WATakY~#u?UYHTubbbk+CGAdc&PP|BIA z2krDW+QZP>i|YhU#pfj{XE8_N2f%;Np`)Ku&o;$Hy02WGV_Z7kKmG~24@r-4hIC&B z_0xXO@hb&^llnJ<{xiUl82?P#Heu?SM_bLiK>e?Q*W%!tans^wo~irSmHE1VS&Vv9 z-nXFJ3rIOBBOm}EwT=FW0P>u|vxwuIcX1zw@o*!`qu^uigImA76Z=*H{%oDM5dY9N zI#2l(`b{b9z;zSnW1N2(yW9HGKT=LofwWT}=-md;%xAKpk_FU*`=`wlb^n0lzwryp zzx`=?pQ$9jc%Tq+9Zz0A1^>h1@@#!Mk1_t8Ex0_dOFe!9225umZTMKZY59{v=RaAm z6CmejLA~m-L25x}(OBKb&nwE2jPU4bo`(V52teAQ5ca1%xbI89G3Uxc`@ZHryp>Z{ zr1Kr>R|LMJ0o^!h_D!sP#zP+MWaewxqOXZ(_8Ne=!1m2NGuQ6lk2L}XAs>ECxf3C; zq!qd6Lavcx?d-}i{dAM?H|w>(TIj6rUZ#I@9~S30=*LkZGS~O@`zxT2SvRd0I<|+~ z4&3)P`y;j;7^kQY*YSUbelIxltc=`pJD+kM2lcLmz0Lw;f18Fh`JD&9Y&#*xj*mq- zqqQAG>4fWA&@F78pY;Rk&3fDdd;B{!Ei`^JezwK=kBZ71JHK^?Y429ZUF^uOLOP*7 z2bI4nkk7cSj#$tSI{ z(5h&iBtg&jq2H^Ho?IWZUwsNcSl34HXOJ)TH+tCk@ge3Z|G(?w%1IxcKSoTXyVY^K ze}j7b1CZ@XeYt+2{cd;c>)J71-q?o5eJ`g{FD8Jewm&##*S~UJ$gf4XF&2zCT}C^Lp;Wr^ofOb{N-w%ets1A{-hQD zZ$p39kL~h(`y1nZMtOdj*g0R1Hw69d=a4@ji5{en*Gu;a=?BdJ-gd!$4(a3lQ2l`I zV$Q+Xb7*O~IR}jsW1;U!fV7j;Q7*-g)eGA7A|RZRq<*Al`?>u)$j7|orPksr_S=caINe%( zSs&WloQJjbG0kq{F8j-Gpzy^>>O=Zudb{nyctm|0+H!wW_YoPt$&Y?|Yg>)i?BBkx z=g9r6HTJz5=6N7HzO(*y#b3QB{%HK!j>Apw{J}yq-mgUd`xa)+e@3Cchk$-}59&)l zVm)bB;;nM<=x@o|mGvS0{h+5^-2Tb@7vTrb!(L`T*3M%##_eM3LA$Yk(9YDK<1@=C z?*ZsRzU0IBN-apiifqbmv6ZEv>JpCq; zXO|&Cf87DSmj?B3%ocyR8|nCXs`h5TNf#t@rJkY;*ZyiCpFWm>3!|!b1%|dFDRDh(a+YvuhNexwtP#$n0&Lqw=E#`z0cvh z8fllWE0_B&!M*{WuXOhf=HXli`}u6#7pMk&J>_cL&(Zyf3CMS!H!VUw$9Fz&>OQwS zJX7P&iJ2OwPRQ(F<0Io#?@X-wGV8L%hV(6r5<0U>93qR(22y!5Q zd?wa47|;3q?pT!jYxTS>pIAa;7^lm=e!OcH43I1tG@{5z?k4=(a;^cGReg^VcJ}*=E-?{J4 z_G3BIQM`wR_eXjEvjY%J{JBJaF6eudT^IBDJn}K`wKzk{>5so=dphq`2<%k9?JdEl z|I}sbdls&yf5h~>yt(f=TJU&L9_3F*J8^%I<*WzqPq6*?9RCfOy3XAMdAz^Mc4Pl| z81=Xl{f7H<4NgCz-;vKnXb0BMl+Tkou$+4Gy!3sLLp~3*(|-9N?TGzK`r8@@pLA;m zhui1mcIwCUYwm-S&mFMeAHeTVh!@18KheJ!kEWx38$kE8Lr4B5PCO^|=JWBC_dMwS z?9fpj=O29Dei!i&SJ;nU0iRe&i4?4=mS@ws2g3p5fdVih%ML#zE%f=x;cAe$J_F}u5ayvhw|G4iF zG56Qzi=AnA>Sx-~_DlNpcW7_&ch5!5M!O0xx%gZM&qYyRJ{RfI^E`!8dmiJ+>Wr(u zl02T*Wqx`)9hU}Uyy5u6H2Y6_xjqN(?kBftr;@s19OwBdzK5$BhVBhHYnJH!aK?Y) zt=reXUO4qa{Tp_V`-`MmPCd;0`(DX+-!GOBCw(c;EXgktIHpj~eUG=Jj^ya|W9Z!h z@Thi;&q_)Eb~;}7Z>Q&kcwVCJ8$BN|4EnVuzhhp0f$+;2Uu?H12PU!KK*&E5uny-x zXrJ>SuWd=Gz5ig?==~^Ro^YKA`r`pP-=_TvVgJ_NhgJkUz7H+8UGV;$^&-yL|0#hD zmw#m;`;lp{`z4?9m|xcYuvL=JcHME;#J!SUhjHKZD;t;Z@G`!T{L>+y^R1gx3hetU z{H!~3rJVa34R`4CVf14^>qon!oPLltMxPV3K|l&{odx@txNNVAc6HhEgY)rB*Uokq z!=l=M(?EAFpxggge^RjhxKA9fS4NHC(60-NmOU?N#;fatb_l;uh4-1we&uV4^ky^O z&X@SUk+PLD7D+k#vs+HQ>3E+BpBJQjmM4RL$+CNeKigwo5blPmD9hCJ)aO-_B$VV z4R}9JGCyNKV>>?r{rNt$fZxM<4tyB;v+?^jB9HVO&;Q8!vmEEBIj;B^|M;FN%f#?` z(JS~s`MvvBfltQUL**o)^JD+9TjWo|f1YdivZbefuLk;r{qRNLlkO!~9_~}{9H8hV zS32s?b%~ju*zqwVu#2v{m_D(+j!)|`AEUhrfd76wonL>@&beRYjQ?dT!+f!<^fur< z8stm;K1RKdZ?Eemo}Z!JIgj1hZqZp%FXC~2!1snR4t@iEUVB~t@qB+Lq=|Q!lP2Fs zS%1t!`M$Dm9XxP0vU;hZDubEG4m^ZowFryjJ^00-Z- z!^!O$8^sSuNBxI@&gf~!PwL4y>+1Oo)(bBHZbck2{n65wInSj~4(pW%c?FIi6*+15 zIpsq{d2{i(4YsF?*GkH~1Lw((T zI0^L`2LCm7u=DVKOZ2&3cYmSw^JDFhAH>}iUwtl;`QARRN8Ns0)n3=5_oKhl-`sxe zL!WuDC;Rc$j(u-*(&U@0AI}9};vItZ&an16KVg4P)_*TY|0O;3XPo3Z_m_^G-#PCA zV0$qBC*$)QhtJ!)m)Y@?^uI+p=`V8P!|ClcE(~k0ahv^?_^#f!Ir1K8ceRyw7xLNf z*k2ove|md8KTLRXJAEFL_|*5l0AKql^1FypmdeB9J}$pj!_UV7 zKHOf{73)B^u6=l2;e8yQceJ*y$mpl{S8|H`hXk*OytRPbkKuFISD&ot%;)n^*C4+T z`|iYNz0G;L-wNeFPf_}IC8c&Mmp@R?MU|@=JdUTEApa>q<44&-$vBbLPoHF__N3bk z{Fp<>aW=D`p8qMSC^b`Ab3YUeNdFe--f-wSugd7B`_L7YN=Uj7fd9TjR|S8~?5F2u z3dXD5^BlSV1YMIuPk+zqH?dUoEzcXMcEj^#`Cvpnz5xABhYz2t?HuQ0*OjH^V=Ujw zN}XT3_WTBXc02s|ylvXJ@kOGSdwwPb6YKq?`$EreH>3S~XKFv-^Js&yZ!Ns!O3%^t zcKGcqX1)%-8G!Se!hCr?ym#i+?+PFC<$QwYRCA_Hv+E|NtLDs!3O>`-b8Ext^P(aA zDYMV75`0&G#vk&jsGTxZ@R+_ZT5Z>%Ojp&MH#4!k+V0N&FMQ|DPUJJqFiuR*1mo89 zEw8Gbn@CqPJ31#ZZK`u&V%k*4+JW^k)u~P_M|E1Y(+`$AclNYIIX~2noF8zX?A#8z zKH&bk`#w$fpye$2;jkoByoo*7N7_ng|AP&-Ynog0ehRYq_Kf7X;x zebtJs+yDQp$D9NFAROna?6!2PcCDB`Bh((X&T|@bXNUdx|32QS|CQBLhwN50wKmkg z)1sGz#)lePyVmWRH{;@P`xpmIY_I6KmxkJVepQW?)0*Gp)SMski&<4+KZ+W|gydA8 z7m`zBCIX4&wz4LpHMyf_R=e|pkRG+s>QMVdji5w1I{Ro{PDyn%6laXs@c2C=JnuQT zYDQR2G(4V9nO0?6thM^(Rh<`V_nI1|WB)X65bA%^qO(JOQ5&5TqPLCkJ?vU?Kz#n+ z{H>xktlyOLtD=eaucwGYHH?&>RH>0oqKlBeY(DY zg8@eX76DEIG|$)D^|-koV(rZ54o!RIi=8;ntHnA_^5o*a(_G|pK1sZ_9d$nGzDI}n zWi9=l6F%fmxy9HI=lgW->4<$t>{lgwpUxj4&wZcH@8k4#-!HA-pd&;s*Lj^KVXi-Q zRM@41LVxkpSL7G(LcYwK5ro(tu^P(;-U?C=uw*Z|le zRolfXZS>)J2AzqD&R+u zGq3wpdw!Ga*l0x8nS9?0`=7C+mE-?N@o6Vxhm|6i?M^#n1nXU`Da${F{B7UU9^W|j zARX=TT}S=i$wBO5`@sSFW4}19U&TS~v=4fH3F!JwwEt>*E|&F~RzLs#gVjHx>;t>B z%MvVe9}}=OKj@LA{f&M=I@a4?tk3cC`Rd>OTlv#3*glKU|BAgd>mM#&YTo!Vq2zwc zVbCuN(6ncxl&9sDmkPAV1`@w7@Q#e*YribjFQSzTk-3OJ0C@f5_?x9XtwQ(5UH(IW zHyDu5^U%*y%k_0w0XVE_S+1aL#6IkDbsyQpkI;2D^tl1>chKum=w)C?uSZ5NckwMH}M`v`T98CCdJDR;XRG=r-+v|A|?naMHWqsXnsDA^5KLy?=#7DhSjtR?eM){XP3Uh$I=7R?Su@`cwP${(#yx^(CQr7jneV39afbd<3cBJ>ix&$X&r8uC z#&!zg{xe!WXQ#lkkYAC6uF|1<`+B9D1bLG?H9nrmr}&AZZ9G3SDChX4_xaBzzfqs8 zuzIWruY1OH(({b*`IVjvqJ5@=ulqgZ8RU!g9M_Gs^K8)h+2Qx-a9mBT7?mgb@T!LY z3;?{ilinvzcyFTZ3QUtO68?O)HxKl40NwV#ih4Qiy|7c`C&JV9gYKSwx4^C6b>K4^ z-vwp8COxFjXWT}A!}v$LEK4H)#vdsE_CUUl|92#559%=z zRh@KPpVO&vhv1Lwgzud$*6&tGo?M2VWpxbrrwrD7{(k`c?gf1G0KTwq)~?Tm#&`LH z5&5S=9{K+feAfa#os2){a}Iy9BmeXPgU1SQtrex1_tAm>6M!#4PCf0uP@i|CT@9O3 zp(fwRfWdKQ=GUv>^CIBZI6sXyv$ z{}S8TZ5Q^CBM-r+BY}6gi*H9sgFi~&JV5;Zz&qN(=kpk8 z_^x4ziVO4_4E%u(9iN{{8y$X*p7MSU{No)ueg`nMEXQ_D;-3t>lN@~Rlcbv$s)%ZQ zzJqkRz|V2$xQ}PP+iT~SoF`PG9mjP(_&lK;?PKg8nkSr#{7FgZPIu@yPdE$msygdD zfqXbmm>iUc=Lu8EFUdTixU)M?(DT}nkw>Bh6-Amt6p)X4BF)Ze8~6=ZWIqi0;1 z?k#*?@X{)Z?0k^^D|vEV1HEejmq1=^XI*dWtlY|3FZd~8^La}_w+PUDHz`~2c%9l= z=cDZ3+@Bf|DToP9vU0!Px8?kvDh6C8|LH_`t`A*7HB7yBk|1oj!Ey-s)Wdz?x4ePZY zd>#XQCaAB6{kY7c%^9`?Sf+&lPz^WA%M^@>{Nr;QJIH-?N9~yj~D@ z3iBr^h5mm9_%AthNCtH2rTPKTuvGJYYaniR=oz0V*WI`J0QLVn+JSa7`rG#6zCYJB>!_KX!~Sd9*UDSeS?7JGeQf$&`rTsP&m&*j&cp+Y zM|zje)#p3tV}g&RbLo@Gj|}3@wMvfQ0sXgW?=Li-Q7_u*W9XkUh$RZ!fj$G!Z&G^3 z6Vj84d{W1U73l{0Eb>XB$1e8M@nJ>!fUYO$ThW7jQuD%k^acH4jI^<}?w`LVucT(NeW47)L(cAMX&?jqq;+ePEkW1SnE;SA^Kqv>W}fhzu;llG9)x_phnv0p5zz7ZrmN6UzX$#!(ATBo zefRHMf1}?p(dRDk+nb{I%~@~WcVd5|-_c)v_!HZicHIcR#&0d^1zqZVk;C_Q(Er&V zO#iXv=|d|f3SLf`{EuHRp&$MNkn=U(m#lsNvY24+xKsD*n&Qs^+j(sI(9#J~u1^=p zFTJ*cUyOX$%>7bIOxo(5HZ**n6J*}Iz<(#8F92Ph)gyJN-f*#<&Jg_rc-tul_eIV9 zR7;mSRByZxe+TgX3CMc#{;R>y7F~${1@LwPwyd3N_2B%L@yV>itz|jS*$w<%fCg{7 z@J*{MxA$l5WX`0CzZZCW;`rHu&p47^pffFfsv%C7(p9hwoOBFpySxk!$Wx8P~H{L_|ZN=@UzbTi@?ahFn({~^#t6U zzvWxOi^mgv&OCL_vh9W5A=k>Nv)I5!#FG5*ZRA_xgdZFW}&=;e8e>#QYoD z8sD&5-f`gfvw*+ur$k0#Kmy}oC_fR<>~C0CGy6WaUqnWQ@kaq~B%s+Z3FD9FOhE41Lhu`fgd?ccSt?mPQg7p#!{jN*zyfkg#8xgjafn+y7j02ja>SHpgO$J617v9KS2fRm#AJcJ@{VkFg?%z)UZ#|&V&-QOaul*|z zH$Kshjlg>va8uWV@7uk^cH_QXR*k*Cmzswgq~P~5_-q8My>*KnH&JZj_pYbqcVsMX zgri^!@MD1HewNjHDC`*-8*aC^fcJ)j@3!BLHJ808B0lT7=naAXY<-X8hiI>+uHpUW zkCFdLSKYr#i2rtfO?b#<#v?m!n|9tL>6XR%o(liLxi-Eu)1MI^{{{OoKDMCz>sI8n ztkwBa?eaO+ZvIkj|43dqPVa#o-UZx-c5k}u%g;qW`eRz&*c?fRf}~`0lYgG~okO45 zO~=Eg%PzBVp7r&!^!|_GS0r>L@-N|P2Y%^*)Tb->k>2H-d5Z2pmm?0l`$65ouM?n; zb6tB7@G^4szRm>aL$*Hx{-JxbGYDfOg&r#kwj<2x0c zhf>9I=#?A5x@?vSOdnmGBhdX$^Xb5!=+H$4*<6_eE6WAu6zO*|O6;zN<-kw*t^=cyE%uyS@8JXp_@?tTgc`6npkhfBj(djm~Z^u##`nSy8eD0?ALFJ#v|6F z=^Z^c$@<)bdbsoY``C_X-#`w}p;hSlwenm$9g`~BYZcnzQoyxI?8|*7>OuY1CBct= zuI=#{+T+on9UuQn1i!LY%gK-5O?npmXorBVPS3rPpK5Q`Js&Nz;|cYN^Lu=k;A~CO zzOiolo{Sc}e=Au(UypYAzU}yD_JcZYNBT)xMQ)DhQzHKot~X)#2Lb)qWqLmYINOuh z_miMr>aYInlWd&Zf&7Nzadw=eA5f3&-E<$)_$S7}XI~XjX%(m0@vkgFH~IM~^m;dm zel1D#`!0!odyxNKH{JJ3re{l_r|OqppzjCB#RfrJ=(!JieHrMd_rv*~2NQ>^$t&|G z*#!vc(z`2zR6t{oY{}vGfZF8hoA%1{^?LxM>j3~SD9!@>+-I$}0Ztc4xCwJF*RIF?|#(bc_*H0B%Y}U#+!jQ zzSCZXkh7p(-@{1%CcPh<`U|O86!!`HMe?lY9ERF*AJa5frDVD1<{2ev$8>!6*xk=7 zfn5dy@_b`O)s!0L+n6nI>hx%JV!Fn>AR#e5A}T2}t}fPdd~DBA-E|!1KJ&Ehi)=k; zhf&>i|CH&f?!h>0`#1MfsaNjYnvh)cxT)P@XL;0WA>+I1L4TqihMyhh)6EB@1T`<@ zorVr}r~q`|o5ttUSU)4@9N}{_+SC2MTto`ZRoA_4wZI#?Yus2<+Qr6wws$mAut>_+ zEb&9_OnLske)mW@`=h&m&-Z;2zYz|#q`S_qDYq;3>-pYl;VBpC%=2MZKK*e%+JpCp z(kJMAt)f!t`2QBzYi=B3KBeap`P^RfZfzH)*T8O@AJ_NeQjhz)>-%|FU+xPT``Y;k z^&=mD-@d(~%UyB*vHdOs@obFqA;E{B=beDbzK`_<^fTXEw02>8F+P{&eQf1Y&qmnW z-LK*OdG^PR-)Q@@zJAN7deNWn{b7Gtj{ZY`W?XqIiQQt3-Cl#g(Qed}d|v3j@joJ$ z{FZlbY?L(pfcUS$u6*wm{XfvZeus@$#NP%x{2lW7zBSg1^n4E(`)RVniYPJQPrHu>nwER;b7Wj_0nYHjZ8!NEw+IL7;sq$mCrSSLl0F~_!od|!LBjWfjK zcc2gJjdi-Cx9PVb|82E>bE{_xZ`ys@|K7ec68X%YQ5#B|#}DTxmRC*F7Ixd$#G$_m z-j#>&K9)W&=Dx47lOUPPJU>|=(4C+C5`K^m$Z>lC(yh&BmqLEB@A&b3$OhVREK;Ns zBF5btAmr1^<wU0 zzJ4h`n=U`;DuIl*ZO09&lyvDpy)k7Il7Z_P@LvyDdt-Rtp8mq;#!|-(I#x)zzIzFD ze+D%BEOwlTTUrGfIy=sgZZq&-J%A310kj#X2c2?ritUg=`nN#0^#FQ$QXn^U!{Gzq zzXxc>4?Ax(`q}ZB(wk8JA)vXRV)4?)4ayOm@ZCz!`viD90L^_K;@fdspSB}+&-)U1 zUjQ1TQ4d5k#odka7C>{qhIpYH0eext2hi;26K_;ps<~f_@_m5j9EFX0#7{#zg_JN1 z(t9YER6yQWGWM`TX87)_=d}l3J3w{ z`_SF758J#(?^_(vL)Rn3JF18BW!m(UCldMd{*Jj{^H<6DSLk^Y@@-jr(yNls`!d^c zo@G#v#a~GNkREAzzsBKfp0C;=<>YJp&f1;(?(y>@`W!9gQO}`XMyUVSE}ski^uCbk zf0o~$4^cU+hpFEtk(=8iYoEaU9(sR^y~M45A?k5zD|kEK?*E4H^RsGJ34CwcZX5sV z;W!Ig&WK6=wMerb(S@5Yl>B7Z5)>G{zLcL$H)-4>pX?r5PqR+8_P7rG1eR>3ze^BlUjVg*_T?6TDl& zm;C!JX|eRIKhI0d0sk8CzXWub1M^mdcTVH-!W>&3gN|b zVDyg$KHm&Mte4>zx??l32cFYN;veq)MHAl#Q+I(4h#!3bd5(Vz{KoVzyB{=Zx%Mxf zgIxswS%Z3;xNZC0+8!m=Uzzq}7g_&*1pHn`d;4eW{=0d?+HNWQ!71Oqi1%Ahvh6kq zO8XCC zmaoBl%#2HRzA&jw8Swu$wD(G<-H-2ydGp7*PjUm=`IDeN+RpysrEe-Po}^Sw7|(s2 z(>SK5w!@Ak>+E>21pN5@6O(V_)b&ojAM0Z0`|+Nw(#W52b{XiRh_ew?@J8hOF}-iJ zVBKrB-%vi~_381#sY1f`Bb}KCT7Ne7v9R{LWwySg-*7Yf!_&%_dL+}2;{fTq^?b$3 z?cG!FD<0BQ+r4*Bjnln)>ONcy4SYEAjsMvG$aAyQm+{ZsU#*e)>;_#F_TSHb2l{!i z2lZw<59rxAPVLbJ^8s>}TzlS>cCqsk`ZMplk z=!z>7B{W@*`*2#ZE6sexghF#=+yB8o`tL1{|8ib`TN3}JeA2C?|H2QMPd|)0=Z|3T zD|c+D{=F#EeAB4c1d@(%oAlGsj?BLR_Nam1&V=9Az&|g7-}1S$mAEfW{>EP>i9GtT zYlnI0$3gwC(eEYFPv%4ZM98bVX_WQT1pe#6-$E1r?ER|J(5UHoSHN#Z0{$9))2WyC zKl(>jFZB=qWA+E(?s<2jeHQhsdsfm***~3e?N-K9^t)v3(SY_KUw_Q9UBZ{WpuQ*K zKE6xn^EpYJXkHFEcSDcpN8>gKJ^9goxAk0jujH5E+{5jt2Tw-NTZs27AwNTq&9yx6 zNBs`tyoGo#6Y^I84qMW%Mk!SDyGR#2Hx#kO4alFjQ18!^UTMwyolxGVM@BjG1V%p! zw*&bQhw*wc#xL@Xj!}K7598{_o{e`4?JKYwpCgU))q0rkJw2~7G_w8${o+x!JKC4e zlhCe|w>_9|>iHDvwG-{u1b*`thTk*8dXdjc#~!tq&(mJ7;CmlD7x8z-VP_r2c^v6J zr+=*sKkr7l)PwdN_JGdE51@w~IG(bey8=DJ&kOEGytoq%`X8qq=y&wry*(G%c37Rn z?$n2VpV15Rz{O#^);yv$;`-7r3BR`_vzPWavtG>>OyVTooqUd9{hj(9iTbfVeBP(= zUHwwZ&jLD~2cFV5)k;2w`B{4ZJdn%#?a2S-pZ3@$WBrnwo{KOy}sXjb<8+vH=y19 zsHt|g=Xt-vIN7Zi=Kqer&Za)ja|zL%>esXv>*23l_7#005t?dl)*?)y=tZFk(FqtlvUgZ?hk4S9ImhhWTx%*DnDXR~~>L--CJ@VHRWFLLHA* zqx^S(=J~f8QHA%L?nl1qS2n*L^kn(|{hDFkhw*^?;`;9m*+ zk9+BQzNwd<$K^Q+_kLJM8pipqSr_D+c3Uq$KO;Xp7r2e_D(hT3-^>_2zCiE_oEvI8 zq2GJd6Z1jp!|#>tVE-Mh-z(C$RSHMFc7y(34j=Xtmrus{vOJ;W`~ASi+Xwo+4j+DB zn|!uGpAHo{6NEN@;OOxJ3s6BPym)PTOR0H34j`Y$<@d*2zUc+UmY+UFq_pzCE9kT0 z(E3Zq{IRy*SDrr5#*6Vr5y3Ba6zK)Jp40>HW%&;bMLp7r^~Pg(Rqc64fX>_}wwJm8 z`JDW?c(|sG-K^!z`5Zg$GM|3hHS&VJ@67wc2Yxp|`D8fH;q!hj@3$&e!a1qMZ`zd{ z&zZ11S^QvsWWVG2i4h>=`8ZczaJ~uW*;p^udt)!X-%mXjPf&qqqnY08TUvRe~w!1Lit=b8u{}@1ka_N+gsy7 z0r>G;+GKqHjP-HpxyyF}=!XUL)JyHbxN{NkXfHo&n{Br`#3ja)wBphn(a&~L`GKnj zes?tBrLeMP8z=5NLFWccJ$h`!R=K#p(ZrWqv zPi#COo$!z=kdN<8yK=J>%{)(CXvZTPl#nN2CFI@~$k%av^Wv}U_`bHcb8gW8>M5Z! z^8vf>YxK79!uaFMl282}Kzn8u>kf_ite%yxr$po9++&ctIxat3`0#2=dYoS>K>^3f zCqehPLr*;d`l1p$ew8}(&x7t+ho1AbfW9){MqHNO$9tmZ4A=4l=?@Rle+at21MWnB+|^s}qY|0% zj^j*ofX6tYagTa4E>MrnySG?>VtUU3ex>(KQV*?rTx4b)s`DC-|Gk}bUnf1-Nsl;G z_2TzH`kZ;(vBH<*)+|Ywi)rJY)-{+e9}x|e_c?QjB^hz3#`6Te$0hP{`5L#iE=#^( z8_4}He24xwzQ&zH`u+gEC;T_Q#?7sZ{}1{e|KIo;_qU;ke8;q6Uykc$-k|d%_Jbgf z4AlN;ql!q@YviE{KY>5D^sdWBkp&&dhw)^f*4JU<<%3TyAo(z^1bi4*lJF@3eX+xb z@g?BH_>zRrM9`0S_%P0NWW9nob8!1i2L0I%ANE^*Pjt)?{jI&M@y)Lpz&{_*{jNq? z-=p3T0@^1U3C?MJA^AN2(b8MrPvS4udBY{crPRzz6?h%+9Ekf}m0ul-`@i`meR-`Q}#E5h-W^eq^tf;buYmukfNTnoPBfAOJpR-VX|D~R*-D^!T| zOF_RFkn}7M=;==m{jH$8*`bf9__%!fkwf1Ax)lyR{U@k@;6KWM`uz@cs~mdz&7*7| zJYN`f)|>Prs4Mr0+Q{$9b^06t*Js&4V0qh|Tzj8qU}33^cXp9%a5#QG34PWA8am5@ z=V3ERj~4{zQvl>V54vXoA3jv)Glh?b^(yRt-;F|I-hZR}m7ovwtE{woW+R{Aui*RA z_v9bQDO+acasQye}1Qz)Gnmh>L@zv0Mn?Hh$+p9Jj{e*TyH+#Gk?Q*N2=AeQ9k zox-{a{0#E`;mG|H?D(}KhkV(-Z5;mO{SEm2%i%jcnZGp8TrRW+wD;lUs4%6E!fzeE z)VF;f#2LK*WMi*mo)8LbgL!Lu>3Yy_o(@0I8o7Spi1j){ZW}=Q8RZ`8$o+92JvY#| zk2?=L<~gl_$~`im)A<+urEedsJ8|D;BlIS0I7I6~d_U_a4+-A`{VZIQ{?NZil6o8$ z=<}>yC;YsR&gbeTZn1X!01mKqwWgz58Pl(xeN27^{#H~{DCzuieeO|y%QYNw2Rrh4 zzKV8r{hkd-Jhz$|WQRJ5*J+6<=FPl-X!=%t$e9i~t`%jCv!+I(2 zMt?UCbV|B%V40nI6ph96ofCAOA!TxnM?Fsg?eNx%!Y9DP z^Jt9g=Q{cY{ijf$53kG?>i9JSdYt9hpK*hjK|Aufz=1`1EE8A*`sxGt=(yl-+hSKr zm6#t;Uq7bb-I?@ruiB}Cgj$g#19MZdx<1P7cUx0Yz6WyaZ#N+cL zb|HG}T}Bzt)SeB>9p-a60 literal 59800 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 : 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> 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 +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-INFFO-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 QQ.- 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/MODD +*/ */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> HERE . +8300 ok +ok> BYE +BYE: cold restart diff --git a/logs/20261008-072354/aarch64/qemu-aarch64-20261008-072354.log b/logs/20261008-072354/aarch64/qemu-aarch64-20261008-072354.log new file mode 100644 index 00000000..a8944360 --- /dev/null +++ b/logs/20261008-072354/aarch64/qemu-aarch64-20261008-072354.log @@ -0,0 +1,177 @@ +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 8 2026 07:23:27 + +UEFI BootServices: EXITED + +=== StarKernel Boot Information === +Memory map entries: 108 +Total memory: 4093 MB +Usable memory: 4054 MB +=================================== + +PMM initialized. +PMM statistics: + Total pages: 1039354 + Free pages : 1037943 + 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=0x5ff3672509f6c4e5 capsule_hash=0x5ff3672509f6c4e5 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=0xc07eb35ca84c4aa8 +PARITY:V4_POST tests=538 pass=538 fail=0 +PARITY:V4_SYSTEM word_count=317 dict_hash=0xc0769523a47b7dc3 +PARITY:OK +POST: PASSED +[HADES][INFO ] [KRELTSC: 0] blk: raw device LBN 2048..3071 (1024 blocks) +PCI: init... +virtio-blk: found device +[HADES][INFO ] [KRELTSC: 1411419] 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> 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 +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> HERE . +8300 ok +ok> BYE +BYE: cold restart diff --git a/logs/20261008-072743/riscv64/qemu-riscv64-20261008-072743.log b/logs/20261008-072743/riscv64/qemu-riscv64-20261008-072743.log new file mode 100644 index 00000000..ba6b2241 --- /dev/null +++ b/logs/20261008-072743/riscv64/qemu-riscv64-20261008-072743.log @@ -0,0 +1,247 @@ + +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 = 0x00000000bdc9caaa +riscv64: satp cleared -- Bare mode, explicit (item 4.3.5a) + + + _____ _ _ __ _ + / ____| | | |/ / | | + | (___ | |_ __ _ _ __| ' / ___ _ __ _ __ ___| | + \___ \| __/ _` | '__| < / _ \ '__| '_ \ / _ \ | + ____) | || (_| | | | . \ __/ | | | | | __/ | + |_____/ \__\__,_|_| |_|\_\___|_| |_| |_|\___|_| + +LithosAnanke v2.1.0 +Architecture: riscv64 +Build: Oct 8 2026 07:27:03 + +UEFI BootServices: EXITED + +=== StarKernel Boot Information === +Memory map entries: 100 +Total memory: 1020 MB +Usable memory: 975 MB +=================================== + +PMM initialized. +PMM statistics: + Total pages: 250269 + Free pages : 249617 + 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=0x5ff3672509f6c4e5 capsule_hash=0x5ff3672509f6c4e5 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=0xc07eb35ca84c4aa8 +PARITY:V4_POST tests=538 pass=538 fail=0 +PARITY:V4_SYSTEM word_count=317 dict_hash=0xc0769523a47b7dc3 +PARITY:OK +POST: PASSED +[HADES][INFO ] [KRELTSC: 0] blk: raw device LBN 2048..3071 (1024 blocks) +PCI: init... +virtio-blk: found device +[HADES][INFO ] [KRELTSC: 17911425] 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> 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 +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-INFFO-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 QQ.- 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* DD= 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-EERROR (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] ['] ' LLITERAL ] [ 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> HERE . +8300 ok +ok> BYE +BYE: cold restart diff --git a/v4/Makefile b/v4/Makefile index 3621a245..e8ae96ce 100644 --- a/v4/Makefile +++ b/v4/Makefile @@ -204,6 +204,8 @@ hosted-check: $(foreach i,$(HOSTED_ISAS),$(BINDIR)/boot-$(i).txt) $(BINDIR)/star @grep -q '^ok> Interrupted$$' $(BINDIR)/await-amd64.txt && grep -q '^ok> 3 ok$$' $(BINDIR)/await-amd64.txt && grep -q '^ok> 56 ok$$' $(BINDIR)/await-amd64.txt || { echo "hosted-check: a line typed while the node waited did not break the wait and then run"; tail -6 $(BINDIR)/await-amd64.txt; exit 1; } @printf '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\n1 2 + .\n' | $(BINDIR)/starforth4-amd64 > $(BINDIR)/deep-amd64.txt 2>&1; true @grep -q '^ok> Stack overflow$$' $(BINDIR)/deep-amd64.txt && grep -q '^ok> 3 ok$$' $(BINDIR)/deep-amd64.txt || { echo "hosted-check: a line that left 29 values on the stack was not an error the node came back from"; tail -4 $(BINDIR)/deep-amd64.txt; exit 1; } + @printf '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\nWORDS\nDEPTH .\n' | $(BINDIR)/starforth4-amd64 > $(BINDIR)/deepwords-amd64.txt 2>&1; true + @grep -q 'DUP' $(BINDIR)/deepwords-amd64.txt && grep -q '^ok> 26 ok$$' $(BINDIR)/deepwords-amd64.txt || { echo "hosted-check: WORDS with 26 values on the stack did not print and come back"; tail -4 $(BINDIR)/deepwords-amd64.txt | cut -c1-200; 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; } @grep -q '^POST FAIL: fail.many outplace = places; f->capacity = capacity; f->gone_error = 0; + f->interrupt_error = 0; for (i = 0; i < capacity; i++) clear_place(&places[i]); } @@ -26,6 +27,10 @@ void v4_fabric_gone_error(v4_fabric *f, v4_cell code) f->gone_error = code; } +void v4_fabric_interrupt_error(v4_fabric *f, v4_cell code) +{ + f->interrupt_error = code; +} void v4_fabric_grow(v4_fabric *f, v4_place *places, unsigned capacity) { @@ -147,15 +152,11 @@ static unsigned hand_over_write(v4_fabric *f, unsigned a) static unsigned hand_over_read(v4_fabric *f, unsigned a) { v4_node *n = &f->place[a].node->n; - unsigned first; - unsigned last; + unsigned first = n->read_port == V4_PORT_ANY ? 0 : n->read_port; + unsigned last = n->read_port == V4_PORT_ANY ? V4_PORTS - 1 : n->read_port; unsigned k; v4_cell value; - if (n->read_port > V4_PORT_ANY) return 0; /* the wait for an offer only: it reads no port */ - first = n->read_port == V4_PORT_ANY ? 0 : n->read_port; - last = n->read_port == V4_PORT_ANY ? V4_PORTS - 1 : n->read_port; - for (k = first; k <= last; k++) { const v4_wire *w = &f->place[a].wire[k]; if (w->kind == V4_WIRE_DEVICE && w->device->give && w->device->give(w->device->self, &value)) { @@ -208,35 +209,23 @@ 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); - /* THE WAIT (docs/v4.0.0/MESH.md 7c). A node in the wait that was given a - * word above is no longer in it: a word for a node comes before its own - * offer. Of the rest, each offer is taken by whoever is ready for it: a - * device that takes, or a node blocked reading that port or any -- which - * a node in the wait is, so of two that offer to each other the one at - * the lower place writes and the other's offers are withdrawn. */ - for (i = 0; i < f->capacity; i++) { - v4_node *n; - unsigned k; - if (!awake(f, i)) continue; - n = &f->place[i].node->n; - if (!v4_node_in_wait(n)) continue; - for (k = 0; k < V4_PORTS; k++) { - const v4_wire *w = &f->place[i].wire[k]; - if (!(n->offers & (1u << k))) continue; - if (w->kind == V4_WIRE_DEVICE) { - if (w->device->take && w->device->take(w->device->self, n->offer[k])) { (void)v4_node_offer_taken(n, k); done++; break; } - } else if (w->kind == V4_WIRE_NODE && awake(f, w->node)) { - v4_node *r = &f->place[w->node].node->n; - if (r->reading && !r->given && (r->read_port == w->port || r->read_port == V4_PORT_ANY)) { - v4_cell word = n->offer[k]; - (void)v4_node_offer_taken(n, k); - v4_node_port_give(r, w->port, word); - done++; + /* a node blocked on the first word of a message to a node that is not + * reading, while a device of its own has something for it */ + if (f->interrupt_error != 0) + for (i = 0; i < f->capacity; i++) { + v4_node *n; + unsigned k; + if (!awake(f, i)) continue; + n = &f->place[i].node->n; + if (!n->asking || f->place[i].wire[n->ask_port].kind != V4_WIRE_NODE || v4_node_words_since_look(n) != 0) continue; + for (k = 0; k < V4_PORTS; k++) { + const v4_wire *w = &f->place[i].wire[k]; + if (w->kind == V4_WIRE_DEVICE && w->device->pending && w->device->pending(w->device->self)) { + done += (unsigned)v4_node_port_gone(n, f->interrupt_error); break; } } } - } /* a node blocked at one port that nothing is wired to */ if (f->gone_error != 0) @@ -245,13 +234,8 @@ unsigned v4_fabric_step(v4_fabric *f) 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) - || (n->reading && !n->given && n->read_port < V4_PORTS && f->place[i].wire[n->read_port].kind == V4_WIRE_NONE)) + || (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); - else if (v4_node_in_wait(n)) { /* an offer on a port with nothing on it */ - unsigned k; - for (k = 0; k < V4_PORTS; k++) - if ((n->offers & (1u << k)) && f->place[i].wire[k].kind == V4_WIRE_NONE) { done += (unsigned)v4_node_offer_gone(n, k); break; } - } } return done; diff --git a/v4/src/node.c b/v4/src/node.c index 491d31ab..665310b6 100644 --- a/v4/src/node.c +++ b/v4/src/node.c @@ -93,14 +93,7 @@ void v4_node_store(v4_node *n, v4_cell addr, v4_cell value) n->asking = 1; return; } - if (port >= (int)V4_PORT_OFFER && port < (int)V4_PORT_WAIT) { /* an offer: remembered until the wait */ - unsigned k = (unsigned)port - V4_PORT_OFFER; - n->offer[k] = value; - n->offers |= 1u << k; - return; - } - if (port == (int)V4_PORT_WAIT) { n->offers = 0; return; } /* a store to the wait: every offer is withdrawn */ - if (port >= 0) { v4_node_fault(n, V4_FAULT_ADDRESS, addr); return; } /* "any", "which port" and the rest are not written to */ + if (port >= 0) { v4_node_fault(n, V4_FAULT_ADDRESS, addr); return; } /* "any" and "which port" are not written to */ } /* The stack registers: a store empties the stack. -1 when not attached. */ if (addr == n->dstack_reg) { v4_dstack_clear(&n->ds); return; } @@ -127,16 +120,8 @@ v4_cell v4_node_fetch(v4_node *n, v4_cell addr) { int port = v4_node_port_index(n, addr); if (port == (int)V4_PORTS + 1) return (v4_cell)n->last_from; - if (port == (int)V4_PORTS + 2) return (v4_cell)n->writers; - if (port == (int)V4_PORTS + 3) return (v4_cell)n->readers; - if (port == (int)V4_PORT_WAIT || port == (int)V4_PORT_WAIT1) { - /* the wait: the word that came, or 0 for an offer taken */ - if (!n->given) return 0; - n->given = 0; - n->last_from = n->given_port; - return n->given_value; - } - if (port >= (int)V4_PORT_OFFER) return 0; /* an offer is not read back */ + if (port == (int)V4_PORTS + 2) { n->since_look = 0; return (v4_cell)n->writers; } + if (port == (int)V4_PORTS + 3) { n->since_look = 0; return (v4_cell)n->readers; } if (port >= 0) { /* the word its neighbour wrote; v4_node_read_ready has said it is there */ if (!n->given) return 0; @@ -194,9 +179,7 @@ void v4_node_port_attach(v4_node *n, v4_cell base) n->last_from = 0; n->writers = 0; n->readers = 0; - n->offers = 0; - n->waiting = 0; - n->offer_asked = 0; + n->since_look = 0; } void v4_node_port_status(v4_node *n, unsigned writers, unsigned readers) @@ -207,19 +190,17 @@ void v4_node_port_status(v4_node *n, unsigned writers, unsigned readers) int v4_node_port_index(const v4_node *n, v4_cell addr) { - if (n->port < 0 || addr < n->port || addr > n->port + (v4_cell)V4_PORT_WAIT1) return -1; + if (n->port < 0 || addr < n->port || addr > n->port + (v4_cell)V4_PORTS + 3) return -1; return (int)(addr - n->port); } int v4_node_read_ready(v4_node *n, v4_cell addr) { int port = v4_node_port_index(n, addr); - if (port < 0 || (port > (int)V4_PORT_ANY && port != (int)V4_PORT_WAIT && port != (int)V4_PORT_WAIT1)) return 1; - if (n->given && (port >= (int)V4_PORT_ANY || (unsigned)port == n->given_port)) return 1; + if (port < 0 || port > (int)V4_PORT_ANY) return 1; + if (n->given && (port == (int)V4_PORT_ANY || (unsigned)port == n->given_port)) return 1; n->reading = 1; - n->waiting = port >= (int)V4_PORT_WAIT; /* the wait is a read of any port, with offers standing; */ - n->read_port = port == (int)V4_PORT_WAIT ? V4_PORT_ANY /* the wait for an offer only reads no port at all */ - : (unsigned)port; + n->read_port = (unsigned)port; return 0; } @@ -229,39 +210,6 @@ void v4_node_port_give(v4_node *n, unsigned port, v4_cell value) n->given_value = value; n->given_port = port; n->reading = 0; - if (n->waiting) { n->waiting = 0; n->offers = 0; } /* the wait is over: every offer is withdrawn */ -} - -int v4_node_in_wait(const v4_node *n) -{ - return n->waiting && n->reading && !n->given; -} - -int v4_node_offer_taken(v4_node *n, unsigned k) -{ - if (!v4_node_in_wait(n) || k >= V4_PORTS || !(n->offers & (1u << k))) return 0; - v4_node_port_give(n, V4_PORTS + k, 0); - return 1; -} - -int v4_node_offer_gone(v4_node *n, unsigned k) -{ - if (n->error_reg < 0 || n->fault_vector < 0 || n->stopped) return 0; - if (!v4_node_in_wait(n) || k >= V4_PORTS || !(n->offers & (1u << k))) return 0; - v4_node_port_give(n, 2u * V4_PORTS + k, 0); - return 1; -} - -int v4_node_offer_as_write(v4_node *n) -{ - unsigned k; - if (!v4_node_in_wait(n) || n->offers == 0 || n->asking) return 0; - for (k = 0; !(n->offers & (1u << k)); k++) { } - n->request = n->offer[k]; - n->ask_port = k; - n->asking = 1; - n->offer_asked = 1; - return 1; } void v4_node_born(v4_node *n, v4_cell base) @@ -274,23 +222,19 @@ void v4_node_born(v4_node *n, v4_cell base) void v4_node_port_served(v4_node *n) { n->asking = 0; - if (n->offer_asked) { /* what was served was an offer: the wait is over */ - n->offer_asked = 0; - v4_node_port_give(n, V4_PORTS + n->ask_port, 0); - } + n->since_look++; } +unsigned v4_node_words_since_look(const v4_node *n) +{ + return n->since_look; +} int v4_node_port_gone(v4_node *n, v4_cell code) { if (code == 0 || n->error_reg < 0 || n->fault_vector < 0 || n->stopped) return 0; - if (n->asking && n->offer_asked) { /* what it wrote was an offer: it is told, not faulted */ - n->asking = 0; n->offer_asked = 0; - v4_node_port_give(n, 2u * V4_PORTS + n->ask_port, 0); - return 1; - } if (n->asking) n->asking = 0; - else if (n->reading && !n->given && n->read_port < V4_PORTS) n->reading = 0; + else if (n->reading && !n->given && n->read_port != V4_PORT_ANY) n->reading = 0; else return 0; v4_node_store(n, n->error_reg, code); /* raises it: P is the node's handler now */ return 1; diff --git a/v4/system/boot.c b/v4/system/boot.c index 3e9b57b2..715a5bf6 100644 --- a/v4/system/boot.c +++ b/v4/system/boot.c @@ -107,7 +107,6 @@ static int run_line(const v4_boot *b, const char *text, unsigned len, char *keep for (;;) { (void)v4_exec_step_word(n, b->es, b->h); if (n->stopped) return V4_BOOT_LINE_STOPPED; - (void)v4_node_offer_as_write(n); /* in the wait (MESH.md 7c): what it offers is a write, here where whatever is on a port takes at once */ if (n->asking && n->ask_port == KERNEL_PORT) { /* a request: the kernel's turn */ if (v4_blocks_serve(&boot_blocks, n, n->request)) { /* a block, as for any node */ diff --git a/v4/tests/host_map.h b/v4/tests/host_map.h index 29c0c8bd..98e3cca2 100644 --- a/v4/tests/host_map.h +++ b/v4/tests/host_map.h @@ -73,7 +73,7 @@ #define OWED (BUF0_W - 112) /* those: for each, the node it is owed to and the node the refused message was for */ #define ACL_HOOK (BUF0_W - 6) /* the xt of the access control recheck word, or 0 */ #define LINE_STATUS (BUF0_W - 9) /* how the last line ended: 0 QUIT, 1 completed, 2 an error */ -#define PORT (BUF0_W - 144) /* the node's ports (node.h): V4_PORTS of them, then "any port", "which port", who writes, who reads, an offer for each port, and the two waits: 2 * V4_PORTS + 6 cells, between the output buffer and A_FOUND. Port 0 is where its requests go. */ +#define PORT (BUF0_W - 32) /* the node's ports (node.h): V4_PORTS of them, then "any port" and "which port". Port 0 is where its requests go. */ #define CONSOLE (BUF0_W - 16) /* the node what this one prints is sent to; 0: whoever sent the text being served */ #define ROUTE_COUNT (BUF0_W - 17) /* how many entries the table of ways holds */ #define ROUTE_DEFAULT (BUF0_W - 18) /* the port address for a node not in the table, or 0: there is none */ @@ -87,12 +87,6 @@ #define MQ_TAIL (BUF0_W - 36) /* where the next will go, */ #define MQ_COUNT (BUF0_W - 37) /* and how many cells they take */ #define AWAIT_FROM (BUF0_W - 39) /* the node whose word of how text ended is waited for */ -#define W_GONE (BUF0_W - 122) /* not 0: the port a message was being written to has nothing on it; its other words are let go */ -#define TAKING (BUF0_W - 121) /* not 0: a message is being taken in, and is only partly with the messages waiting; */ -#define T_TAIL (BUF0_W - 120) /* where they ended before it, */ -#define T_COUNT (BUF0_W - 119) /* and how many cells they took */ -#define GATE_WORD (BUF0_W - 32) /* the first word of a message that is being offered */ -#define PAY_K (BUF0_W - 31) /* for each port, which refusal owed is offered there, counted from 1; 0: none. V4_PORTS cells */ #define GATE_PORT (BUF0_W - 38) /* the port address a message is about to be begun on */ #define NEAR (BUF0_W - 64) /* for each port, the number of the node on the other end; 0: not told */ #define MQ_HDR (BUF0_W - 56) /* a message being taken in: its seven words and the port it came on */ @@ -130,8 +124,6 @@ typedef char host_map_ports_fit[(V4_PORTS <= 8u) ? 1 : -1]; #endif /* the messages waiting are above the dictionary */ typedef char host_map_queue_fits[(MQ_W >= DICT_END_W) ? 1 : -1]; -/* the ports, with the offers and the wait after them, end below the cells that follow */ -typedef char host_map_port_block_fits[(PORT + 2 * (v4_cell)V4_PORTS + 6 <= W_GONE && PAY_K + (v4_cell)V4_PORTS <= PRINT_TO) ? 1 : -1]; /* How many slots, from slot 0, a branch may sit in on a node this size: those * whose address field reaches every word of it. */ @@ -204,16 +196,6 @@ static int host_load(v4_text *tx, v4_node *n, const char *const *files, unsigned v4_text_constant(tx, "-PORTS", -(v4_cell)V4_PORTS); v4_text_constant(tx, "(NEAR)", NEAR); v4_text_constant(tx, "(GATE-PORT)", GATE_PORT); - v4_text_constant(tx, "(GATE-WORD)", GATE_WORD); - v4_text_constant(tx, "(PAY-K)", PAY_K); - v4_text_constant(tx, "PORTS-1", (v4_cell)V4_PORTS - 1); - v4_text_constant(tx, "(OFFER)", PORT + (v4_cell)V4_PORT_OFFER); - v4_text_constant(tx, "(WAIT)", PORT + (v4_cell)V4_PORT_WAIT); - v4_text_constant(tx, "(WAIT1)", PORT + (v4_cell)V4_PORT_WAIT1); - v4_text_constant(tx, "(W-GONE)", W_GONE); - v4_text_constant(tx, "(TAKING)", TAKING); - v4_text_constant(tx, "(T-TAIL)", T_TAIL); - v4_text_constant(tx, "(T-COUNT)", T_COUNT); v4_text_constant(tx, "(AWAIT-FROM)", AWAIT_FROM); v4_text_constant(tx, "(MQ)", MQ_W); v4_text_constant(tx, "(MQ-END)", MQ_W + MQ_CELLS); diff --git a/v4/tests/test_fabric.c b/v4/tests/test_fabric.c index 042ff1db..7af08fe6 100644 --- a/v4/tests/test_fabric.c +++ b/v4/tests/test_fabric.c @@ -15,7 +15,7 @@ static int failures = 0, checks = 0; #define CHECK(c,...) do{checks++; if(!(c)){failures++; printf("FAIL %s:%d: ",__FILE__,__LINE__); printf(__VA_ARGS__); printf("\n");}}while(0) /* The memory map is open (D-4); the test chooses where the ports are. */ -#define PB ((v4_cell)(V4_NODE_WORDS - 32u)) /* port 0: the ports and what follows them end below the top of memory */ +#define PB ((v4_cell)(V4_NODE_WORDS - 16u)) /* port 0 */ #define ANY (PB + (v4_cell)V4_PORT_ANY) #define ORG ((v4_cell)16) /* where a test's programme starts */ #define OUT ((v4_cell)900) /* where it leaves what it found */ @@ -45,36 +45,9 @@ static unsigned loaded(unsigned k) /* the programme ends by waiting at a port nothing is wired to */ static void wait_for_ever(void) { LIT(PB + 7); O(BANG_B); O(FETCH_B); (void)v4_asm_label(&as); } /* and the last word is written out */ -/* ---- the wait (MESH.md 7c) ---- */ -static void fresh(void) -{ - unsigned k; - v4_fabric_init(&f, places, 4); - for (k = 0; k < 4; k++) v4_node_reset(&pool[k].n); -} -/* offer `word` on port k */ -static void offer(unsigned k, v4_cell word) { LIT(word); LIT(PB + (v4_cell)V4_PORT_OFFER + (v4_cell)k); O(BANG_A); O(STORE_A); } -/* the wait: what it gives goes to `at`, and which port to `at + 1` */ -static void wait_into(v4_cell at) -{ - LIT(PB + (v4_cell)V4_PORT_WAIT); O(BANG_B); O(FETCH_B); LIT(at); O(BANG_A); O(STORE_A); - LIT(PB + (v4_cell)V4_PORTS + 1); O(BANG_B); O(FETCH_B); LIT(at + 1); O(BANG_A); O(STORE_A); -} -/* the wait for an offer only */ -static void wait1_into(v4_cell at) -{ - LIT(PB + (v4_cell)V4_PORT_WAIT1); O(BANG_B); O(FETCH_B); LIT(at); O(BANG_A); O(STORE_A); - LIT(PB + (v4_cell)V4_PORTS + 1); O(BANG_B); O(FETCH_B); LIT(at + 1); O(BANG_A); O(STORE_A); -} -static void done_mark(void) { LIT(1); LIT(OUT + 2); O(BANG_A); O(STORE_A); } -static void count_for_ever(void) -{ - v4_cell again; - LIT(OUT); O(BANG_A); - again = v4_asm_label(&as); - O(FETCH_A); LIT(1); O(ADD); O(STORE_A); - v4_asm_branch(&as, V4_OP_JUMP, again); -} +/* a device that says whether it has something pending */ +static int *dev_has; +static int device_has(void *self) { (void)self; return *dev_has; } /* Let time pass until nothing more can happen, or `max` steps. */ static unsigned settle(unsigned max) @@ -394,155 +367,60 @@ int main(void) CHECK(ND(a)->n.asking && ND(a)->n.request == 5 && ND(c)->n.reading && ND(c)->n.mem[OUT] == 0, "looking takes nothing and gives nothing: both wait as they did"); CHECK(!ND(b)->n.stopped && ND(b)->n.reading, "and the one that looked did not wait to look"); - /* ---- the wait (MESH.md 7c): a node offers a word and sleeps ---- */ + /* ---- a node blocked on the first word of a message, while a device of its own has something for it ---- */ { + static int has; /* what the device says it has pending */ static stream none; - static v4_device sink; - v4_uheat_t clock; - sink.take = stream_take; sink.give = 0; sink.self = &none; - - /* taken by a reader */ - fresh(); - a = loaded(0); offer(0, 7); wait_into(OUT); done_mark(); wait_for_ever(); - b = loaded(1); LIT(PB + 3); O(BANG_B); O(FETCH_B); LIT(OUT); O(BANG_A); O(STORE_A); wait_for_ever(); - CHECK(v4_asm_ok(&as) && v4_fabric_wire(&f, a, 0, b, 3), "a node that offers, wired to one that reads"); - (void)settle(300); - CHECK(ND(b)->n.mem[OUT] == 7, "the reader has the word offered: %ld", (long)ND(b)->n.mem[OUT]); - CHECK(ND(a)->n.mem[OUT] == 0 && ND(a)->n.mem[OUT + 1] == (v4_cell)V4_PORTS + 0 && ND(a)->n.mem[OUT + 2] == 1 && ND(a)->n.offers == 0, - "the one that offered is told its offer on port 0 was taken, and has none left: %ld from %ld", (long)ND(a)->n.mem[OUT], (long)ND(a)->n.mem[OUT + 1]); - - /* taken by a device */ - fresh(); none.took_n = 0; - a = loaded(0); offer(0, 7); wait_into(OUT); done_mark(); wait_for_ever(); - CHECK(v4_fabric_wire_device(&f, a, 0, &sink), "the same, wired to a device that takes what is written"); - (void)settle(300); - CHECK(none.took_n == 1 && none.took[0] == 7 && ND(a)->n.mem[OUT + 1] == (v4_cell)V4_PORTS + 0 && ND(a)->n.mem[OUT + 2] == 1, "the device has the word, and the node is told"); - - /* a neighbour that never reads */ - fresh(); - a = loaded(0); offer(0, 7); wait_into(OUT); done_mark(); wait_for_ever(); - b = loaded(1); count_for_ever(); - CHECK(v4_asm_ok(&as) && v4_fabric_wire(&f, a, 0, b, 3), "a node that offers, wired to one that never reads"); - for (i = 0; i < 200; i++) (void)v4_fabric_step(&f); - clock = ND(a)->es.anticlock; - for (i = 0; i < 100; i++) (void)v4_fabric_step(&f); - CHECK(v4_node_in_wait(&ND(a)->n) && ND(a)->es.anticlock == clock && ND(a)->n.mem[OUT + 2] == 0, "it is in the wait, and executes nothing there"); - CHECK((ND(b)->n.readers & (1u << 3)) != 0, "and shows to its neighbour as waiting to read"); - - /* withdrawn by a word that comes for it */ - c = loaded(2); LIT(PB + 0); O(BANG_B); LIT(9); O(STORE_B); wait_for_ever(); - CHECK(v4_asm_ok(&as) && v4_fabric_wire(&f, c, 0, a, 2), "a third node writes to it"); - for (i = 0; i < 100; i++) (void)v4_fabric_step(&f); - CHECK(ND(a)->n.mem[OUT] == 9 && ND(a)->n.mem[OUT + 1] == 2 && ND(a)->n.mem[OUT + 2] == 1 && ND(a)->n.offers == 0, - "it gets that word, from that port, and its offer is withdrawn: %ld from %ld", (long)ND(a)->n.mem[OUT], (long)ND(a)->n.mem[OUT + 1]); - CHECK(!ND(b)->n.given && !ND(c)->n.asking, "the node offered to was given nothing, and the writer was served"); - - /* an offer that could be taken in the step a word comes: the word comes first */ - fresh(); - a = loaded(0); offer(0, 7); wait_into(OUT); offer(0, 7); wait_into(OUT + 3); done_mark(); wait_for_ever(); - b = loaded(1); LIT(PB + 3); O(BANG_B); O(FETCH_B); LIT(OUT); O(BANG_A); O(STORE_A); wait_for_ever(); - c = loaded(2); LIT(PB + 0); O(BANG_B); LIT(9); O(STORE_B); wait_for_ever(); - CHECK(v4_asm_ok(&as) && v4_fabric_wire(&f, a, 0, b, 3) && v4_fabric_wire(&f, c, 0, a, 2), "one offers to a reader while a third writes to it"); - v4_fabric_sleep(&f, a); - for (i = 0; i < 50; i++) (void)v4_fabric_step(&f); - CHECK(ND(b)->n.reading && ND(c)->n.asking, "the reader and the writer are both blocked"); - v4_fabric_sleep(&f, b); v4_fabric_sleep(&f, c); v4_fabric_wake(&f, a); - for (i = 0; i < 50; i++) (void)v4_fabric_step(&f); - CHECK(v4_node_in_wait(&ND(a)->n), "and then the one that offers is in the wait"); - v4_fabric_wake(&f, b); v4_fabric_wake(&f, c); + static v4_device dev; + v4_fabric_init(&f, places, 4); + for (i = 0; i < 3; i++) v4_node_reset(&pool[i].n); + a = loaded(0); /* looks about, then writes two words to its port 0 */ + LIT(PB + (v4_cell)V4_PORTS + 3); O(BANG_B); O(FETCH_B); O(DROP); + LIT(PB + 0); O(BANG_B); LIT(1); O(STORE_B); LIT(2); O(STORE_B); wait_for_ever(); + b = loaded(1); /* never reads */ + LIT(OUT); O(BANG_A); + { + v4_cell again = v4_asm_label(&as); + O(FETCH_A); LIT(1); O(ADD); O(STORE_A); + v4_asm_branch(&as, V4_OP_JUMP, again); + } + CHECK(v4_asm_ok(&as) && v4_fabric_wire(&f, a, 0, b, 3), "a writer that looks first, wired to a node that never reads"); + dev.take = stream_take; dev.give = 0; dev.self = &none; dev.pending = device_has; has = 1; dev_has = &has; + CHECK(v4_fabric_wire_device(&f, a, 5, &dev), "and to a device, which has something for it"); + for (i = 0; i < 40; i++) (void)v4_fabric_step(&f); + CHECK(ND(a)->n.asking && ND(a)->n.request == 1 && v4_node_words_since_look(&ND(a)->n) == 0, "the writer is blocked on its first word, and waits: the fabric has no error for it"); + v4_fabric_interrupt_error(&f, 21); + for (i = 0; i < 40; i++) (void)v4_fabric_step(&f); + CHECK(ND(a)->n.asking && ND(a)->n.faults == 0, "nor is a bare node let go when it has: it cannot take an error"); + v4_node_error_attach(&ND(a)->n, OUT + 20); + v4_node_fault_attach(&ND(a)->n, 900); + has = 0; + for (i = 0; i < 40; i++) (void)v4_fabric_step(&f); + CHECK(ND(a)->n.asking && ND(a)->n.faults == 0, "a node that can take one waits all the same while the device has nothing for it"); + has = 1; (void)v4_fabric_step(&f); - CHECK(!v4_node_in_wait(&ND(a)->n) && !ND(c)->n.asking && ND(b)->n.reading && !ND(b)->n.given, "in one step: the word for it comes first, and the reader is given nothing"); - (void)settle(300); - CHECK(ND(a)->n.mem[OUT] == 9 && ND(a)->n.mem[OUT + 1] == 2 && ND(a)->n.mem[OUT + 3] == 0 && ND(a)->n.mem[OUT + 4] == (v4_cell)V4_PORTS + 0 && ND(b)->n.mem[OUT] == 7, - "it offers again, and the reader gets the word once"); + CHECK(!ND(a)->n.asking && ND(a)->n.fault_kind == V4_FAULT_RAISED && ND(a)->n.fault_addr == 21 && ND(a)->n.mem[OUT + 20] == 21, + "when it has, the writer is let go and the error raised on it"); - /* two nodes each offering to the other */ - fresh(); - a = loaded(0); offer(0, 5); wait_into(OUT); done_mark(); wait_for_ever(); - b = loaded(1); offer(3, 6); wait_into(OUT); done_mark(); wait_for_ever(); - CHECK(v4_asm_ok(&as) && v4_fabric_wire(&f, a, 0, b, 3), "two nodes each offer to the other"); - (void)settle(300); - CHECK(ND(a)->n.mem[OUT] == 0 && ND(a)->n.mem[OUT + 1] == (v4_cell)V4_PORTS + 0, "the one at the lower place has its offer taken"); - CHECK(ND(b)->n.mem[OUT] == 5 && ND(b)->n.mem[OUT + 1] == 3, "the other gets the word, from the port it came by"); - CHECK(ND(a)->n.offers == 0 && ND(b)->n.offers == 0 && ND(a)->n.mem[OUT + 2] == 1 && ND(b)->n.mem[OUT + 2] == 1, "and neither has an offer left"); - - /* three in a ring, each offering to the next */ - fresh(); - a = loaded(0); offer(0, 11); wait_into(OUT); done_mark(); wait_for_ever(); - b = loaded(1); offer(0, 12); wait_into(OUT); done_mark(); wait_for_ever(); - c = loaded(2); offer(0, 13); wait_into(OUT); done_mark(); wait_for_ever(); - CHECK(v4_asm_ok(&as) && v4_fabric_wire(&f, a, 0, b, 1) && v4_fabric_wire(&f, b, 0, c, 1) && v4_fabric_wire(&f, c, 0, a, 1), "three nodes in a ring, each offering to the next"); - CHECK(settle(1000) < 1000, "they come to rest"); - CHECK(ND(a)->n.mem[OUT + 1] == (v4_cell)V4_PORTS + 0 && ND(b)->n.mem[OUT] == 11 && ND(b)->n.mem[OUT + 1] == 1, "the first's offer was taken by the second"); - CHECK(v4_node_in_wait(&ND(c)->n) && ND(c)->n.offers == 1u && ND(c)->n.mem[OUT + 2] == 0 && !ND(a)->n.given, "the third still offers to the first, which is not reading: nothing was handed over twice"); - - /* a neighbour that is asleep */ - fresh(); - a = loaded(0); offer(0, 7); wait_into(OUT); done_mark(); wait_for_ever(); - b = loaded(1); LIT(PB + 3); O(BANG_B); O(FETCH_B); LIT(OUT); O(BANG_A); O(STORE_A); wait_for_ever(); - CHECK(v4_asm_ok(&as) && v4_fabric_wire(&f, a, 0, b, 3), "a node that offers, wired to a reader"); - v4_fabric_sleep(&f, a); - for (i = 0; i < 50; i++) (void)v4_fabric_step(&f); - v4_fabric_sleep(&f, b); v4_fabric_wake(&f, a); - for (i = 0; i < 100; i++) (void)v4_fabric_step(&f); - CHECK(v4_node_in_wait(&ND(a)->n) && ND(b)->n.reading && !ND(b)->n.given, "while the reader is asleep the offer stands"); - v4_fabric_wake(&f, b); - (void)settle(300); - CHECK(ND(b)->n.mem[OUT] == 7 && ND(a)->n.mem[OUT + 2] == 1, "woken, it takes it"); - - /* a port with nothing on it */ - fresh(); - a = loaded(0); offer(5, 7); wait_into(OUT); done_mark(); wait_for_ever(); - CHECK(v4_asm_ok(&as) && v4_fabric_wire_device(&f, a, 7, &sink), "a node that offers on a port nothing is wired to (the port it ends by reading has a device that gives nothing)"); - for (i = 0; i < 50; i++) (void)v4_fabric_step(&f); - v4_fabric_gone_error(&f, 18); - for (i = 0; i < 50; i++) (void)v4_fabric_step(&f); - CHECK(v4_node_in_wait(&ND(a)->n) && ND(a)->n.faults == 0, "a bare node waits, though the fabric has an error for it"); + /* once the first word has gone, it is not let go: the message must be finished */ + v4_fabric_init(&f, places, 4); + for (i = 0; i < 3; i++) v4_node_reset(&pool[i].n); + a = loaded(0); + LIT(PB + (v4_cell)V4_PORTS + 3); O(BANG_B); O(FETCH_B); O(DROP); + LIT(PB + 0); O(BANG_B); LIT(1); O(STORE_B); LIT(2); O(STORE_B); wait_for_ever(); + b = loaded(1); /* reads one word, and no more */ + LIT(PB + 3); O(BANG_B); O(FETCH_B); LIT(OUT); O(BANG_A); + { + v4_cell again = v4_asm_label(&as); + O(FETCH_A); LIT(1); O(ADD); O(STORE_A); + v4_asm_branch(&as, V4_OP_JUMP, again); + } + CHECK(v4_asm_ok(&as) && v4_fabric_wire(&f, a, 0, b, 3) && v4_fabric_wire_device(&f, a, 5, &dev), "the same, to a node that reads one word and no more"); v4_node_error_attach(&ND(a)->n, OUT + 20); v4_node_fault_attach(&ND(a)->n, 900); - for (i = 0; i < 100 && ND(a)->n.mem[OUT + 2] == 0; i++) (void)v4_fabric_step(&f); /* until it has noted what it was told */ - CHECK(!v4_node_in_wait(&ND(a)->n) && ND(a)->n.faults == 0 && ND(a)->n.offers == 0 && ND(a)->n.mem[OUT] == 0 && ND(a)->n.mem[OUT + 1] == 2 * (v4_cell)V4_PORTS + 5 && ND(a)->n.mem[OUT + 2] == 1, - "one that can take an error is woken and told there is nothing on port 5: no error is raised, and its offer is withdrawn: %ld", (long)ND(a)->n.mem[OUT + 1]); - - /* offers are withdrawn by a store to the wait (found by the review of step 6d) */ - fresh(); - a = loaded(0); offer(0, 7); LIT(0); LIT(PB + (v4_cell)V4_PORT_WAIT); O(BANG_A); O(STORE_A); done_mark(); wait_for_ever(); - for (i = 0; i < 50; i++) (void)v4_fabric_step(&f); - CHECK(v4_asm_ok(&as) && ND(a)->n.mem[OUT + 2] == 1 && ND(a)->n.offers == 0 && ND(a)->n.faults == 0, "a node that offers and then stores to the wait has no offer left"); - - /* the wait for an offer only: a word that comes for the node does not end it */ - fresh(); - a = loaded(0); offer(0, 7); wait1_into(OUT); done_mark(); wait_for_ever(); - b = loaded(1); count_for_ever(); - c = loaded(2); LIT(PB + 0); O(BANG_B); LIT(9); O(STORE_B); wait_for_ever(); - CHECK(v4_asm_ok(&as) && v4_fabric_wire(&f, a, 0, b, 3) && v4_fabric_wire(&f, c, 0, a, 2), "a node waits for its offer only, to a node that never reads, while a third writes to it"); - for (i = 0; i < 200; i++) (void)v4_fabric_step(&f); - CHECK(v4_node_in_wait(&ND(a)->n) && ND(a)->n.mem[OUT + 2] == 0 && ND(c)->n.asking && (ND(c)->n.readers & 1u) == 0, "it goes on waiting; the writer is not served, and does not see it as reading"); - CHECK(v4_fabric_remove(&f, b) != 0, "the node offered to is removed"); - v4_fabric_gone_error(&f, 18); - v4_node_error_attach(&ND(a)->n, OUT + 20); - v4_node_fault_attach(&ND(a)->n, 900); - CHECK(v4_fabric_wire_device(&f, a, 7, &sink), "(the port it ends by reading has a device that gives nothing)"); - for (i = 0; i < 100 && ND(a)->n.mem[OUT + 2] == 0; i++) (void)v4_fabric_step(&f); - CHECK(ND(a)->n.mem[OUT + 1] == 2 * (v4_cell)V4_PORTS + 0 && ND(a)->n.faults == 0 && ND(a)->n.offers == 0 && ND(c)->n.asking, "it is told there is nothing on that port; no error is raised; the writer still waits"); - fresh(); - a = loaded(0); offer(0, 7); wait1_into(OUT); done_mark(); wait_for_ever(); - b = loaded(1); LIT(PB + 3); O(BANG_B); O(FETCH_B); LIT(OUT); O(BANG_A); O(STORE_A); wait_for_ever(); - CHECK(v4_asm_ok(&as) && v4_fabric_wire(&f, a, 0, b, 3), "the same, to a node that reads"); - (void)settle(300); - CHECK(ND(b)->n.mem[OUT] == 7 && ND(a)->n.mem[OUT + 1] == (v4_cell)V4_PORTS + 0 && ND(a)->n.mem[OUT + 2] == 1, "its offer is taken, and it is told"); - - /* a host with one node, whose devices always take */ - fresh(); - a = loaded(0); offer(1, 21); offer(3, 23); wait_into(OUT); done_mark(); wait_for_ever(); - for (i = 0; i < 50; i++) (void)v4_fabric_step(&f); - CHECK(v4_node_in_wait(&ND(a)->n) && ND(a)->n.offers == ((1u << 1) | (1u << 3)), "a node offers on two ports and is in the wait"); - CHECK(v4_node_offer_as_write(&ND(a)->n) && ND(a)->n.asking && ND(a)->n.ask_port == 1 && ND(a)->n.request == 21, "its host turns that into a write of the lower port's word"); - v4_node_port_served(&ND(a)->n); - for (i = 0; i < 50; i++) (void)v4_fabric_step(&f); - CHECK(!ND(a)->n.asking && ND(a)->n.mem[OUT] == 0 && ND(a)->n.mem[OUT + 1] == (v4_cell)V4_PORTS + 1 && ND(a)->n.mem[OUT + 2] == 1 && ND(a)->n.offers == 0, - "and when it is served the node is told that offer was taken"); - CHECK(!v4_node_offer_as_write(&ND(a)->n), "a node that is not in the wait is left alone"); + v4_fabric_interrupt_error(&f, 21); + for (i = 0; i < 60; i++) (void)v4_fabric_step(&f); + CHECK(ND(a)->n.asking && ND(a)->n.request == 2 && ND(a)->n.faults == 0, "blocked on its second word with the device still pending, the writer waits"); } printf(" %d checks, %d failures\n", checks, failures); diff --git a/v4/tests/test_host_mesh.c b/v4/tests/test_host_mesh.c index bfc8082d..cde5eaa7 100644 --- a/v4/tests/test_host_mesh.c +++ b/v4/tests/test_host_mesh.c @@ -71,7 +71,8 @@ static int console_take(void *self, v4_cell value) } return 1; } -static const v4_device console = { console_take, console_give, 0 }; +static int console_pending(void *self) { (void)self; return going_at < going.count; } +static const v4_device console = { console_take, console_give, 0, console_pending }; static int is_empty(const char *s) { return s[0] == 0; } @@ -111,38 +112,12 @@ static unsigned starforth_node(unsigned k) return (unsigned)id; } -/* The same, answering with what has been printed: for when a node is - * spinning and the fabric never comes to rest. */ -static const char *said(v4_cell node, const char *text) { (void)tell(node, text); return printed; } - static int waiting(unsigned id) { const v4_node *n = &v4_fabric_node_at(&f, id)->n; return n->reading && !n->given && n->read_port == V4_PORT_ANY; } -/* Three nodes in a row once more, 10 at the console, 11, 12: a new fabric, each - * told who it is and the way to the others. For the scenes at the end. */ -static unsigned starforth_node(unsigned k); -static void row_again(unsigned *hera, unsigned *mid, unsigned *far) -{ - unsigned i; - v4_fabric_init(&f, places, 3); - v4_fabric_gone_error(&f, V4_ERROR_NO_ONE); - *hera = starforth_node(0); *mid = starforth_node(1); *far = starforth_node(2); - (void)v4_fabric_wire_device(&f, *hera, 1, &console); - (void)v4_fabric_wire(&f, *hera, 2, *mid, 2); (void)v4_fabric_wire(&f, *mid, 3, *far, 2); - going.count = 0; going_at = 0; - step_cap = 20000000; - for (i = 0; i < 20; i++) (void)v4_fabric_step(&f); - (void)tell(0, "10 (ME) ! 1 (CONSOLE) ! 1 1 ROUTE 0 2 ROUTE"); - (void)tell(0, "11 (ME) ! 1 (CONSOLE) ! 2 DEFAULT-ROUTE 0 3 ROUTE"); - (void)tell(0, "12 (ME) ! 1 (CONSOLE) ! 2 DEFAULT-ROUTE"); - (void)tell(10, "11 2 ROUTE 12 2 ROUTE 11 2 NEIGHBOUR"); - (void)tell(11, "12 3 ROUTE 10 2 NEIGHBOUR"); - (void)tell(12, "11 2 NEIGHBOUR"); -} - int main(void) { unsigned hera, mid, far, i; @@ -327,12 +302,12 @@ int main(void) /* no room: a node that is waiting keeps what it is sent, and has room for only so much */ { - v4_cell lost = pool[1].n.mem[LOST], refused = pool[0].n.mem[REFUSED], got, not_taken, told_of; + v4_cell lost = pool[1].n.mem[LOST], refused = pool[0].n.mem[REFUSED], got, not_taken; CHECK(is_empty(tell(11, "0 GOT !")) && is_empty(tell(11, "12 AWAIT .")) && ended == 0 && pool[1].n.mem[AWAIT_FROM] == 12, "node 11 waits for an answer from 12, which is not going to send one"); CHECK(is_empty(tell(10, ": F 49 0 DO S\" HIT\" 11 SEND LOOP ; F")) && ended == 1 && ended_from == 10, "node 10 sends it 49 messages meanwhile"); CHECK(pool[1].n.mem[MQ_COUNT] > 300 && pool[1].n.mem[MQ_COUNT] <= MQ_CELLS - 36, "node 11 has kept what it has room for, and left the room that is kept for refusals: %ld cells", (long)pool[1].n.mem[MQ_COUNT]); - CHECK(pool[1].n.mem[OWED_COUNT] == 0 && pool[0].n.mem[REFUSED] >= refused + 8, "it owed a refusal for each of the rest, as many as it could owe at once, and paid them while it waited: node 10 was told of %ld", - (long)(pool[0].n.mem[REFUSED] - refused)); + CHECK(pool[1].n.mem[OWED_COUNT] == 8, "it owes a refusal for each of the rest, as many as it can owe: %ld", (long)pool[1].n.mem[OWED_COUNT]); + CHECK(pool[0].n.mem[REFUSED] == refused, "and has sent none yet: it is still waiting"); /* one from its centre ends the wait */ CHECK(is_empty(tell(10, "12 NO-ROUTE")), "node 10 forgets the way to 12"); @@ -341,10 +316,9 @@ int main(void) got = strtol(tell(11, "GOT @ ."), NULL, 10); not_taken = 49 - got; CHECK(got >= 30 && not_taken > 8, "it then did every message it had kept: %ld of the 49", (long)got); - told_of = pool[0].n.mem[REFUSED] - refused; - CHECK(told_of >= 8 && told_of <= not_taken, "node 10 was told of %ld of them", (long)told_of); - CHECK(pool[1].n.mem[LOST] == lost + not_taken + (not_taken - told_of), "it counted each message it did not take, and each refusal it could not owe: %ld for %ld not taken, %ld told", - (long)(pool[1].n.mem[LOST] - lost), (long)not_taken, (long)told_of); + CHECK(pool[0].n.mem[REFUSED] == refused + 8, "and sent the eight refusals it owed: node 10 was told of %ld", (long)(pool[0].n.mem[REFUSED] - refused)); + CHECK(pool[1].n.mem[LOST] == lost + not_taken + (not_taken - 8), "it counted each message it did not take, and each refusal it could not owe: %ld for %ld not taken", + (long)(pool[1].n.mem[LOST] - lost), (long)not_taken); /* the way to 12 is forgotten: what is sent there now is refused */ refused = pool[1].n.mem[REFUSED]; CHECK(is_empty(tell(11, ": P12 S\" 1 DROP\" 12 SEND ; P12")) && pool[1].n.mem[REFUSED] == refused + 1, "having forgotten the way to 12, what node 11 sends there goes toward its centre, which has no way either, and is refused"); @@ -352,11 +326,11 @@ int main(void) } /* a line from the console breaks a wait (MESH.md 7b.6) */ CHECK(is_empty(tell(10, "12 AWAIT .")) && ended == 0 && pool[0].n.mem[AWAIT_FROM] == 12 && waiting(hera), "node 10 waits for an answer from 12, which is not going to send one"); - CHECK(strcmp(tell(11, "20 22 + ."), "42 ") == 0 && ended == 1 && pool[0].n.mem[AWAIT_FROM] == 12, "text from the console for node 11 comes to node 10 on its way: node 10 passes it on, and goes on waiting: \"%s\"", printed); + CHECK(is_empty(tell(11, "20 22 + .")) && ended == 0 && pool[0].n.mem[AWAIT_FROM] == 12, "text from the console for node 11 comes to node 10 on its way: node 10 keeps it, and goes on waiting"); { const char *r = tell(10, "65 EMIT"); CHECK(strstr(r, "Interrupted\n") != NULL && pool[0].n.mem[AWAIT_FROM] == 0, "text from the console for node 10 itself ends its wait, with an error that says so: \"%s\"", r); - CHECK(strstr(r, "A") != NULL && ended == 2, "the line is then done as usual: \"%s\", %d ended", r, ended); + CHECK(strstr(r, "A") != NULL && strstr(r, "42 ") != NULL && ended == 3, "the line is then done as usual, and so is what was kept for node 11: \"%s\", %d ended", r, ended); CHECK(strstr(r, "Interrupted\n") < strstr(r, "A"), "the wait ends before the line that ended it is done"); } CHECK(strcmp(tell(10, "1 2 + ."), "3 ") == 0 && waiting(hera) && waiting(mid) && waiting(far), "and all three go on as before"); @@ -390,10 +364,9 @@ int main(void) { CHECK(is_empty(tell(11, "0 GOT !")) && is_empty(tell(11, "12 AWAIT .")) && pool[1].n.mem[AWAIT_FROM] == 12, "node 11 waits on 12 again"); CHECK(is_empty(tell(10, ": F40 40 0 DO S\" HIT\" 11 SEND LOOP ; F40")) && pool[1].n.mem[OWED_COUNT] == 0, "node 10 sends it as many messages as it has room for"); - /* node 11 does what it has kept before it pays what it owes (7b.3): forty answers come first */ - (void)tell(10, ": ONE S\" HIT\" 11 SEND 12 NO-ROUTE 12 11 GONE 41 0 DO 11 AWAIT DROP LOOP ; ONE"); + (void)tell(10, ": ONE S\" HIT\" 11 SEND 12 NO-ROUTE 12 11 GONE 11 AWAIT . ; ONE"); CHECK(strstr(printed, "Message refused") != NULL && pool[0].n.mem[AWAIT_FROM] == 0, - "it sends one more, for which there is no room, ends node 11's wait, and waits for node 11's answers: after the forty, its wait ends, the message refused: \"%s\"", printed); + "it sends one more, for which there is no room, ends node 11's wait, and waits for node 11's answer: its own wait ends, the message refused: \"%s\"", printed); CHECK(strtol(tell(11, "GOT @ ."), NULL, 10) == 40 && is_empty(tell(10, "12 3 ROUTE")) && is_empty(tell(11, "12 3 ROUTE")), "node 11 did the forty it had kept; the ways are told again"); } @@ -420,180 +393,34 @@ int main(void) CHECK(is_empty(tell(10, "66 NO-ROUTE")) && waiting(hera) && waiting(mid) && waiting(far), "the way is forgotten, and all three are at rest"); } - /* ---- what a node passes on keeps its order, however long it must be kept (MESH.md 7c) ---- */ - CHECK(is_empty(tell(11, "12 2 ROUTE")), "node 11 is told the way to node 12 is by node 10"); - CHECK(is_empty(tell(12, ": SLOW 30000 0 DO LOOP ;")), "node 12 is given a word that takes a while"); - CHECK(strcmp(tell(11, ": TRIO S\" SLOW 68 EMIT\" 12 SEND S\" 69 EMIT\" 12 SEND S\" 70 EMIT\" 12 SEND ; TRIO"), "DEF") == 0, - "it sends node 12 three texts, the first slow to do: node 10 keeps the other two until node 12 reads again, and they are done in order: \"%s\"", printed); - CHECK(is_empty(tell(11, "12 3 ROUTE")) && waiting(hera) && waiting(mid) && waiting(far) && pool[0].n.mem[MQ_COUNT] == 0, "the way is told again; all three are at rest, keeping nothing"); - - /* ---- a node that is stuck holds up no one (MESH.md 7c) ------------------- */ - v4_fabric_gone_error(&f, V4_ERROR_NO_ONE); - - /* From here a node is spinning, so the fabric never comes to rest: said() - * is tell(), answering with what was printed by the time it gave up. */ - - /* a refusal owed to a stuck node whose number is the lower */ - CHECK(is_empty(said(12, "NO-ROUTES 1 3 ROUTE 10 3 ROUTE 11 2 ROUTE")) && is_empty(said(11, "55 3 ROUTE")), "node 12 has no way for 55; node 11 is told the way to 55 is by node 12"); - CHECK(strcmp(tell(11, ": C1 S\" 1 DROP\" 55 SEND S\" 1 DROP\" 12 SEND BEGIN 0 UNTIL ; C1"), "(still running)") == 0, "node 11 sends 55 a message, and node 12 text, and is then stuck in a loop"); + /* a node that owes a refusal to a node that is stuck is not stuck itself */ + CHECK(is_empty(tell(12, "NO-ROUTES 1 3 ROUTE 10 3 ROUTE 11 2 ROUTE")) && is_empty(tell(11, "55 3 ROUTE")), "node 12 has no way for 55; node 11 is told the way to 55 is by node 12"); + CHECK(strcmp(tell(11, ": C1 S\" 1 DROP\" 55 SEND BEGIN 0 UNTIL ; C1"), "(still running)") == 0, "node 11 sends 55 a message and is then stuck in a loop"); CHECK(pool[2].n.mem[OWED_COUNT] == 1, "node 12 owes node 11 a refusal, and cannot give it: node 11 is not reading"); - CHECK(strcmp(said(12, "7 8 * ."), "56 ") == 0 && printed_from == 12, "node 12 goes on doing what it is sent: \"%s\"", printed); - { - v4_uheat_t clock = pool[2].es.anticlock; - unsigned k; - for (k = 0; k < 1000; k++) (void)v4_fabric_step(&f); - CHECK(v4_node_in_wait(&pool[2].n) && pool[2].es.anticlock == clock && pool[2].n.mem[OWED_COUNT] == 1, "between times it sleeps in the wait, still owing, and executes nothing"); - } - CHECK(strcmp(said(10, ": X12 S\" 66 EMIT\" 12 SEND ; X12"), "B") == 0 && printed_from == 12, "another node writes to it and is answered: \"%s\"", printed); + (void)tell(12, "7 8 * ."); + CHECK(strcmp(printed, "56 ") == 0 && printed_from == 12, "node 12 goes on doing what it is sent: \"%s\"", printed); - /* two refusals owed: one to the stuck node, one to a node that waits for it */ - CHECK(is_empty(said(10, "77 3 ROUTE")), "node 10 is told the way to 77 is by node 12, which has none"); - CHECK(strstr(said(10, ": W77B S\" 1 DROP\" 77 SEND 77 AWAIT . ; W77B"), "Message refused") != NULL && pool[0].n.mem[AWAIT_FROM] == 0 && pool[2].n.mem[OWED_COUNT] == 1, - "node 10 sends 77 a message and waits: node 12, which still owes the stuck node, tells node 10 it was refused: \"%s\"", printed); - CHECK(is_empty(said(10, "77 NO-ROUTE")), "the way is forgotten"); - - /* a message passed on toward the stuck node waits with the node passing it on, which goes on serving */ - { - v4_cell kept = pool[0].n.mem[MQ_COUNT]; - CHECK(is_empty(said(11, "1 DROP")) && ended == 0 && pool[0].n.mem[MQ_COUNT] > kept && v4_node_in_wait(&pool[0].n), - "text from the console for the stuck node comes to node 10, which cannot hand it on: it keeps it, offered, and sleeps"); - CHECK(strcmp(said(10, "1 2 + ."), "3 ") == 0 && strcmp(said(12, "7 8 * ."), "56 ") == 0 && printed_from == 12, - "node 10 goes on doing what it is sent, and passing on what is for others: \"%s\"", printed); - CHECK(pool[0].n.mem[MQ_COUNT] > kept && v4_node_in_wait(&pool[0].n), "still keeping what is for the stuck node"); - } - /* the stuck node's own answer: node 12 did text node 11 sent before it stuck, and cannot give it the answer */ - CHECK(pool[2].n.mem[MQ_COUNT] > 0 && v4_node_in_wait(&pool[2].n), "node 12 keeps the answer it has for node 11, offered, and sleeps"); - - /* a line that must begin a message to the stuck node waits, and the node takes in what comes */ - CHECK(is_empty(said(10, ": TO11 S\" 1 DROP\" 11 SEND 65 EMIT ; TO11")) && ended == 0 && v4_node_in_wait(&pool[0].n) && !pool[0].n.asking, - "node 10 sends the stuck node a message: its line waits in the wait, not blocked writing"); - { - v4_cell kept = pool[0].n.mem[MQ_COUNT]; - CHECK(is_empty(said(12, "7 8 * .")) && ended == 0 && pool[0].n.mem[MQ_COUNT] > kept && v4_node_in_wait(&pool[0].n), - "text from the console for node 12 comes to node 10: it keeps it, and its line goes on waiting"); - } - { - const char *r = said(10, "66 EMIT"); - CHECK(strstr(r, "Interrupted\n") != NULL && strstr(r, "A") == NULL && strstr(r, "B") != NULL && strstr(r, "Interrupted\n") < strstr(r, "B"), - "text from the console for node 10 itself ends the line that waited, with an error that says so, and is then done: \"%s\"", r); - CHECK(strstr(r, "56 ") != NULL && ended == 3, "and what it kept for node 12 is passed on and done: \"%s\", %d ended", r, ended); - } - - /* the stuck node is removed while a line waits to begin a message to it */ - CHECK(is_empty(said(10, "TO11")) && ended == 0 && v4_node_in_wait(&pool[0].n), "node 10's line waits on the stuck node again"); + /* a node that is waiting to write to a node finds out when that node is removed */ + (void)tell(12, ": TO11 S\" 1 DROP\" 11 SEND 65 EMIT ; TO11"); + CHECK(ended == 0, "node 12 sends node 11 a message: node 11 is not reading, and node 12 waits to write to it"); CHECK(v4_fabric_remove(&f, mid) == &pool[1], "node 11 is removed"); - { - unsigned k; - for (k = 0; k < 200000 && ended == 0; k++) (void)v4_fabric_step(&f); - CHECK(strstr(printed, "No one on that port") != NULL && strstr(printed, "A") == NULL && ended == 1, "the line ends in an error that says no one is there: \"%s\"", printed); - } + (void)tell(10, "1 DROP"); + CHECK(strstr(printed, "No one on that port") != NULL && strstr(printed, "A") == NULL, "node 12's line ends in an error that says no one is there: \"%s\"", printed); step_cap = 20000000; - CHECK(strcmp(said(12, "7 8 * ."), "56 ") == 0 && pool[2].n.mem[OWED_COUNT] == 0 && pool[2].n.mem[MQ_COUNT] == 0 && pool[0].n.mem[MQ_COUNT] == 0 && waiting(far) && !v4_node_in_wait(&pool[2].n) && waiting(hera), - "node 12 goes on; what it owed node 11 and kept for it, and what node 10 kept for it, are let go: they owe and keep nothing, and are at rest"); + CHECK(strcmp(tell(12, "7 8 * ."), "56 ") == 0 && pool[2].n.mem[OWED_COUNT] == 0 && waiting(far) && waiting(hera), + "it goes on, the refusal it owed node 11 let go: it owes nothing and is at rest"); - /* a refusal owed to a stuck node whose number is the higher */ + /* THE LIMIT (MESH.md 7b.7): a refusal owed to a neighbour whose number is the higher is written + * without looking, as any message to it is, so a node that is stuck holds up a neighbour that owes + * it one -- until it is removed */ step_cap = 3000000; - CHECK(is_empty(said(12, "55 3 ROUTE")), "node 12 is told the way to 55 is by node 10, which has none"); - CHECK(strcmp(tell(12, ": C2 S\" 1 DROP\" 55 SEND BEGIN 0 UNTIL ; C2"), "(still running)") == 0 && pool[0].n.mem[OWED_COUNT] == 1 && !pool[0].n.asking, - "node 12 sends 55 a message and is then stuck in a loop: node 10 owes it a refusal, and is not blocked writing it"); - step_cap = 20000000; - CHECK(strcmp(said(10, "1 2 + ."), "3 ") == 0 && pool[0].n.mem[OWED_COUNT] == 1, "node 10 goes on doing what it is sent, still owing: \"%s\"", printed); - { - v4_uheat_t clock; - unsigned k; - for (k = 0; k < 1000; k++) (void)v4_fabric_step(&f); - clock = pool[0].es.anticlock; - for (k = 0; k < 1000; k++) (void)v4_fabric_step(&f); - CHECK(v4_node_in_wait(&pool[0].n) && pool[0].es.anticlock == clock, "and sleeps in the wait between times"); - } + CHECK(is_empty(tell(12, "55 3 ROUTE")), "node 12 is told the way to 55 is by node 10, which has none"); + CHECK(strcmp(tell(12, ": C2 S\" 1 DROP\" 55 SEND BEGIN 0 UNTIL ; C2"), "(still running)") == 0 && pool[0].n.asking && pool[0].n.mem[OWED_COUNT] == 1, + "node 12 sends 55 a message and is then stuck in a loop: node 10 owes it a refusal, writes it, and is blocked"); + v4_fabric_gone_error(&f, V4_ERROR_NO_ONE); CHECK(v4_fabric_remove(&f, far) == &pool[2], "node 12 is removed"); - CHECK(strcmp(said(10, "1 2 + ."), "3 ") == 0 && pool[0].n.mem[OWED_COUNT] == 0 && waiting(hera) && !v4_node_in_wait(&pool[0].n), "node 10 lets the refusal go and is at rest: \"%s\"", printed); - - /* ==== what the review of step 6d found: each scene on a row of three, begun again ==== */ - - /* a node is removed while a message is being passed on to it */ - { - static char line[240]; - unsigned steps = 0, k; - unsigned depth; - row_again(&hera, &mid, &far); - CHECK(strcmp(tell(12, "7 8 * ."), "56 ") == 0, "three nodes in a row again"); - depth = pool[1].n.ds.depth; - memset(line, ' ', 200); memcpy(line, "1 DROP", 6); line[200] = 0; - printed_len = 0; printed[0] = 0; ended = 0; - (void)v4_message_text(&going, 12, CONSOLE_ID, V4_MSG_TEXT, line, 200); going_at = 0; - while (steps < 2000000 && !(pool[1].n.mem[MQ_COUNT] > 0 && pool[1].n.mem[MQ_COUNT] < 40 && pool[2].n.reading && pool[2].n.read_port == 2)) { (void)v4_fabric_step(&f); steps++; } - CHECK(steps < 2000000, "long text for node 12 is on its way through node 11, part written: %ld cells of it still with node 11", (long)pool[1].n.mem[MQ_COUNT]); - CHECK(v4_fabric_remove(&f, far) == &pool[2], "node 12 is removed"); - for (k = 0; k < 3000000 && v4_fabric_step(&f) != 0; k++) { } - CHECK(k < 3000000 && pool[1].n.mem[MQ_COUNT] == 0 && waiting(mid) && pool[1].n.ds.depth == depth, "node 11 comes to rest: it has let the rest go, keeps nothing, and its stack is as it was (%ld cells kept)", (long)pool[1].n.mem[MQ_COUNT]); - CHECK(strcmp(tell(11, "20 22 + ."), "42 ") == 0 && strcmp(tell(10, "1 2 + ."), "3 ") == 0, "and it and node 10 go on"); - } - - /* a node is removed while it is writing a message to its neighbour: the half that came is not kept */ - { - static char line[240]; - unsigned steps = 0, k; - row_again(&hera, &mid, &far); - memset(line, ' ', 200); memcpy(line, "1 DROP", 6); line[200] = 0; - printed_len = 0; printed[0] = 0; ended = 0; - (void)v4_message_text(&going, 12, CONSOLE_ID, V4_MSG_TEXT, line, 200); going_at = 0; - while (steps < 2000000 && !(pool[2].n.mem[MQ_COUNT] > 8 && pool[2].n.reading && pool[2].n.read_port == 2)) { (void)v4_fabric_step(&f); steps++; } - CHECK(steps < 2000000, "node 12 has taken in part of a long text from node 11: %ld cells", (long)pool[2].n.mem[MQ_COUNT]); - CHECK(v4_fabric_remove(&f, mid) == &pool[1], "node 11 is removed"); - for (k = 0; k < 3000000 && v4_fabric_step(&f) != 0; k++) { } - CHECK(k < 3000000 && pool[2].n.mem[MQ_COUNT] == 0 && waiting(far), "node 12 comes to rest, and has not kept the half: %ld cells", (long)pool[2].n.mem[MQ_COUNT]); - CHECK(v4_fabric_wire(&f, hera, 3, far, 3) && is_empty(tell(10, "12 NO-ROUTE 12 3 ROUTE")), "node 12 is wired to node 10 instead"); - (void)tell(12, "NO-ROUTES 1 3 ROUTE 10 3 ROUTE"); - CHECK(strcmp(tell(12, "7 8 * ."), "56 ") == 0, "and does what it is sent"); - } - - /* what a finished text printed, with the way to the console through a stuck node */ - row_again(&hera, &mid, &far); - CHECK(v4_fabric_wire(&f, hera, 3, far, 3) && is_empty(tell(10, "NO-ROUTES 1 1 ROUTE 11 2 ROUTE 12 3 ROUTE")) && strcmp(tell(12, "3 4 + ."), "7 ") == 0, - "node 12 is reached straight from node 10; what it prints still goes back by node 11"); - step_cap = 400000; - CHECK(strcmp(tell(11, ": ST BEGIN 0 UNTIL ; ST"), "(still running)") == 0, "node 11 is stuck in a loop"); - (void)said(10, ": P S\" 65 EMIT\" 12 SEND ; P"); - CHECK(v4_node_in_wait(&pool[2].n) && pool[2].n.mem[MQ_COUNT] > 0, "node 10 sends node 12 text that prints: what it printed, and how it ended, wait with node 12, offered, and it sleeps"); - (void)said(10, ": Q S\" 9 (REFUSED) !\" 12 SEND ; Q"); - (void)said(12, "8 (REFUSED) !"); - CHECK(pool[2].n.mem[REFUSED] == 0 && v4_node_in_wait(&pool[2].n), - "the next text from node 10, and text typed at the console for it, are kept back: what it owes each from the last has not gone (MESH.md 7c.3). It sleeps in the wait"); - { v4_cell kept = pool[2].n.mem[MQ_COUNT]; - (void)said(10, ": R S\" 7 (REFUSED) !\" 12 SEND ; R"); - CHECK(pool[2].n.mem[MQ_COUNT] > kept && v4_node_in_wait(&pool[2].n), "it is not held: it takes in what it is sent, and sleeps again"); } - CHECK(v4_fabric_remove(&f, mid) == &pool[1], "node 11 is removed"); - { unsigned k; for (k = 0; k < 3000000 && v4_fabric_step(&f) != 0; k++) { } - CHECK(k < 3000000 && pool[2].n.mem[REFUSED] == 7 && pool[2].n.mem[MQ_COUNT] == 0 && waiting(far), "what could not go is let go, the texts kept back are done in the order they came, and node 12 is at rest: %ld", (long)pool[2].n.mem[REFUSED]); } - - /* offers left standing when a node goes round to begin text */ - row_again(&hera, &mid, &far); - CHECK(v4_fabric_wire(&f, hera, 3, far, 3) && v4_fabric_wire(&f, hera, 4, far, 4), "nodes 10 and 12 are wired to each other twice over"); - (void)tell(10, "NO-ROUTES 1 1 ROUTE 11 2 ROUTE 12 3 ROUTE 77 3 ROUTE"); - (void)tell(10, ": SLOW 400000 0 DO LOOP ; : Z S\" 1 DROP\" 77 SEND SLOW ;"); - (void)tell(12, ": FWD99 S\" 67 EMIT\" 99 SEND ;"); - (void)tell(12, "NO-ROUTES 10 3 ROUTE 11 2 ROUTE 1 4 ROUTE 99 4 ROUTE"); - CHECK(strcmp(tell(12, "3 4 + ."), "7 ") == 0, "node 12's way to the console, and to 99, is by its other wire to node 10"); - step_cap = 300000; - CHECK(strcmp(tell(11, ": C S\" 1 DROP\" 12 SEND S\" FWD99\" 12 SEND BEGIN 0 UNTIL ; C"), "(still running)") == 0, "node 11 sends node 12 two texts and is stuck"); - step_cap = 30000; - (void)said(10, "Z"); - CHECK(pool[2].n.mem[OWED_COUNT] == 1, "node 10 sends 77 a message by node 12, which has no way, and is then busy: node 12 owes it a refusal, offered on its first wire"); - CHECK(v4_fabric_remove(&f, mid) == &pool[1], "node 11 is removed: node 12 lets its answer go, and begins the text it kept back"); - printed_len = 0; printed[0] = 0; printed_from = -1; - { unsigned k; for (k = 0; k < 20000000 && v4_fabric_step(&f) != 0; k++) { } - CHECK(k < 20000000, "all come to rest"); } - CHECK(strchr(printed, 'C') == NULL, "the text node 12 sent to 99 was not done by node 10: \"%s\" from %ld", printed, (long)printed_from); - CHECK(pool[0].n.mem[REFUSED] == 1 && pool[2].n.mem[OWED_COUNT] == 0, "node 10 was told its message to 77 was refused: %ld", (long)pool[0].n.mem[REFUSED]); - - /* many of a node's own messages waiting for a stuck node */ - row_again(&hera, &mid, &far); - step_cap = 300000; - CHECK(strcmp(tell(11, ": ST BEGIN 0 UNTIL ; ST"), "(still running)") == 0, "node 11 is stuck in a loop"); - { int k, good = 0; - for (k = 1; k <= 12; k++) { (void)said(10, "12 11 GONE"); if (strcmp(said(10, "1 2 + ."), "3 ") == 0) good++; } - CHECK(good == 12 && pool[0].n.mem[MQ_COUNT] == 108, "node 10 is told twelve times to tell it a node is gone, and after each still does what is typed: %d of 12, %ld cells kept", good, (long)pool[0].n.mem[MQ_COUNT]); } + step_cap = 20000000; + CHECK(strcmp(tell(10, "1 2 + ."), "3 ") == 0 && pool[0].n.mem[OWED_COUNT] == 0 && waiting(hera), "node 10 is let go, lets the refusal go, and goes on: \"%s\"", printed); printf(" %d checks, %d failures\n", checks, failures); return failures != 0; diff --git a/v4/tests/test_host_quit.c b/v4/tests/test_host_quit.c index 98fce310..2c6c7fb0 100644 --- a/v4/tests/test_host_quit.c +++ b/v4/tests/test_host_quit.c @@ -63,7 +63,7 @@ static v4_heat h; static v4_text tx; static v4_cell w_key, w_key_end, w_fault, capsule_latest; static v4_cell w_idle; /* (IDLE): where the node waits for a message */ -static v4_cell w_idle_end; /* (LINE): the word after it */ +static v4_cell w_idle_end; /* (PASS-ON): the word after it */ static char out[V4_CONSOLE_CAP + 1]; /* STORAGE (MESH.md section 8). The node asks its kernel for its blocks, and @@ -213,7 +213,6 @@ static int run_line(long max) while (steps < max && idle < 64) { (void)v4_exec_step_word(&n, &es, &h); steps++; - (void)v4_node_offer_as_write(&n); /* in the wait: what it offers is a write, the kernel and the console taking at once */ 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; @@ -871,7 +870,7 @@ int main(void) printf(" capsule: %ld words\n", (long)v4_text_here(&tx) - 16); if (failures) { printf(" %d checks, %d failures\n", checks, failures); return 1; } w_idle = v4_text_word(&tx, "(IDLE)"); - w_idle_end = v4_text_word(&tx, "(LINE)"); /* the word after (IDLE) in quit.v4 */ + w_idle_end = v4_text_word(&tx, "(PASS-ON)"); /* the word after (IDLE) in quit.v4 */ 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)"); @@ -1134,21 +1133,6 @@ int main(void) } printf(" %u values may wait on the stack while the next line is typed and interpreted\n", most); CHECK(most + 4u >= V4_DATA_DEPTH, "the prompt and the interpreter take no more than four cells of the stack"); - /* one more than may wait: the line ends in an error that says so, and the node goes on (found by the review of step 6d) */ - { - char line[4 * V4_DATA_DEPTH + 16]; - size_t at = 0; - unsigned m; - const char *r; - boot_bare(); - for (m = 0; m < most + 1; m++) at += (size_t)snprintf(line + at, sizeof line - at, "1 "); - snprintf(line + at, sizeof line - at, "\n"); - r = say(line); - CHECK(strstr(r, "Stack overflow") != NULL && strstr(r, " ERROR\nok> ") != NULL, "a line that leaves one value more than may wait ends in an error that says so: \"%s\"", r); - CHECK(strcmp(say("1 2 + .\n"), "3 ok\nok> ") == 0, "and the next line is done as usual"); - for (m = 0; m < 2000 && !node_idle(); m++) (void)v4_exec_step_word(&n, &es, &h); /* it finishes what it was doing when its answer went */ - CHECK(n.mem[MQ_COUNT] == 0 && node_idle(), "with nothing left among the messages waiting, and the node at its ports"); - } } /* ---- how much of the data stack a line has ---- */ diff --git a/v4/tests/test_host_unit.c b/v4/tests/test_host_unit.c index 360a23bf..5167db89 100644 --- a/v4/tests/test_host_unit.c +++ b/v4/tests/test_host_unit.c @@ -140,7 +140,7 @@ static int host_born(void *self) v4_node_fault_attach(&pool[k].n, w_fault); v4_blocks_init(&node_blocks[k], BUF0_W); if (k != 0) { /* Hera's kernel is wired where she is made */ - node_kernel[k].take = node_kernel_take; node_kernel[k].give = 0; node_kernel[k].self = &pool[k]; + node_kernel[k].take = node_kernel_take; node_kernel[k].give = 0; node_kernel[k].self = &pool[k]; node_kernel[k].pending = 0; if (!v4_fabric_wire_device(&f, (unsigned)place, 0, &node_kernel[k])) return -1; } return place; @@ -194,7 +194,7 @@ static int kernel_take(void *self, v4_cell value) /* a request */ if (value < FIRST_REQUEST || !v4_manage_serve(&manage, hera_place, (unsigned)(value - FIRST_REQUEST))) refused++; return 1; } -static const v4_device kernel = { kernel_take, kernel_give, 0 }; +static const v4_device kernel = { kernel_take, kernel_give, 0, 0 }; /* ---- the console: a device on Hera's port 1 ---- */ #define CONSOLE_ID 1 @@ -237,7 +237,8 @@ static int console_take(void *self, v4_cell value) } return 1; } -static const v4_device console = { console_take, console_give, 0 }; +static int console_pending(void *self) { (void)self; return going_at < going.count; } +static const v4_device console = { console_take, console_give, 0, console_pending }; /* Is there a node that will execute at the next step? A step in which a * node only faulted counts nothing done (exec.h), and it goes on from its @@ -275,8 +276,6 @@ static const char *tell(v4_cell node, const char *text) if (steps >= step_limit) { stuck(); return "(still running)"; } return printed; } -/* The same, answering with what has been printed: for when a node is spinning and the fabric never rests. */ -static const char *said(v4_cell node, const char *text) { (void)tell(node, text); return printed; } static int told(v4_cell node, const char *text) { return tell(node, text)[0] == 0 && ended == 1 && ended_how == V4_TEXT_COMPLETED; } /* POST's host, for the node numbered 10 (v4/include/v4/post.h): a line is @@ -383,6 +382,7 @@ int main(void) /* ---- Hera is born empty, and takes in the nucleus ---- */ v4_fabric_init(&f, places, PLACES); v4_fabric_gone_error(&f, V4_ERROR_NO_ONE); + v4_fabric_interrupt_error(&f, V4_ERROR_INTERRUPTED); place = host_born(0); CHECK(place == 0, "a node is born"); hera_place = (unsigned)place; @@ -506,8 +506,8 @@ int main(void) /* a node is killed while its neighbour is writing to it */ step_limit = 3000000ul; CHECK(strcmp(tell(14, ": SPIN BEGIN 0 UNTIL ; SPIN"), "(still running)") == 0, "node 14 is stuck in a loop that never ends"); - CHECK(strcmp(tell(12, ": TO14 S\" 65 EMIT\" 14 SEND ; TO14"), "(still running)") == 0 && v4_node_in_wait(node_numbered(12)) && !node_numbered(12)->asking, - "node 12, beside it, sends it text: 14 never reads, and 12 waits to begin the message, in the wait"); + CHECK(strcmp(tell(12, ": TO14 S\" 65 EMIT\" 14 SEND ; TO14"), "(still running)") == 0 && node_numbered(12)->asking, + "node 12, beside it, sends it text: 14 never reads, and 12 is blocked writing to it"); { unsigned born = born_count; const char *r = tell(10, "14 KILL 65 EMIT"); @@ -525,34 +525,21 @@ int main(void) CHECK(strstr(tell(10, ": H14 S\" 1\" 14 SEND ; H14"), "Argument out of range") != NULL, "Hera herself has no way to it"); } - /* two nodes each send a third text and are then stuck: the third has an answer for each that it - * cannot give, and goes on doing what others send it (MESH.md 7c). While a node spins the fabric - * never rests: said() answers with what was printed. */ + /* a node waits on one that is stuck and is not its neighbour; Hera kills the stuck one */ step_limit = 3000000ul; - CHECK(strcmp(tell(12, ": S11 S\" 1 DROP\" 11 SEND BEGIN 0 UNTIL ; S11"), "(still running)") == 0 && - strcmp(tell(13, ": S11 S\" 1 DROP\" 11 SEND BEGIN 0 UNTIL ; S11"), "(still running)") == 0, "nodes 12 and 13, either side of node 11, each send it text and are then stuck in a loop"); - CHECK(node_numbered(11)->mem[MQ_COUNT] == 18 && v4_node_in_wait(node_numbered(11)), "node 11 keeps its answer to each, offered, and sleeps: %ld cells", (long)node_numbered(11)->mem[MQ_COUNT]); - CHECK(strcmp(said(11, "11 100 * ."), "1100 ") == 0 && ended == 1 && node_numbered(11)->mem[MQ_COUNT] == 18, "text typed for node 11 is done all the same: \"%s\"", printed); - - /* a node waits on one that is stuck; text for the stuck one waits with Hera, who goes on; Hera kills it */ - CHECK(said(11, ": W13 13 AWAIT . ; W13")[0] == 0 && ended == 0 && node_numbered(11)->mem[AWAIT_FROM] == 13 && waiting(11), "node 11 waits for node 13's answer"); - { - v4_cell kept = node_numbered(10)->mem[MQ_COUNT]; - (void)tell(13, "1 DROP"); - CHECK(ended == 0 && v4_node_in_wait(node_numbered(10)) && !node_numbered(10)->asking && node_numbered(10)->mem[MQ_COUNT] > kept, - "text typed for the stuck node waits with Hera, offered: she sleeps in the wait, not blocked writing"); - } - CHECK(strcmp(said(10, "1 2 + ."), "3 ") == 0 && ended == 1, "and text for Hera herself is done meanwhile: \"%s\"", printed); - (void)tell(10, "13 KILL 65 EMIT"); - CHECK(node_numbered(13) == NULL && strstr(printed, "Node gone") != NULL && node_numbered(11)->mem[AWAIT_FROM] == 0, - "Hera kills node 13: node 11's wait ends, with an error that says the node is gone: \"%s\"", printed); - CHECK(strstr(printed, "A") != NULL && ended == 2 && node_numbered(10)->mem[MQ_COUNT] == 9 && v4_node_in_wait(node_numbered(10)), - "her line is not held by node 12, which is stuck and has to be told too: that message waits with her, offered, and what she kept for node 13 is let go: %ld cells", - (long)node_numbered(10)->mem[MQ_COUNT]); - CHECK(strcmp(said(11, "11 100 * ."), "1100 ") == 0 && strcmp(said(10, "1 2 + ."), "3 ") == 0, "and the others go on"); + CHECK(strcmp(tell(13, ": SPIN BEGIN 0 UNTIL ; SPIN"), "(still running)") == 0, "node 13 is stuck in a loop"); + CHECK(strcmp(tell(12, ": W13 13 AWAIT . ; W13"), "(still running)") == 0 && node_numbered(12)->mem[AWAIT_FROM] == 13 && waiting(12), + "node 12, which is not wired to it, waits for its answer"); + (void)tell(10, "13 KILL"); + CHECK(node_numbered(13) == NULL && strstr(printed, "Node gone") != NULL && node_numbered(12)->mem[AWAIT_FROM] == 0 && waiting(12), + "Hera kills node 13: node 12's wait ends, with an error that says the node is gone: \"%s\"", printed); + step_limit = 30000000ul; + CHECK(strcmp(tell(12, "12 100 * ."), "1200 ") == 0 && strcmp(tell(11, "11 100 * ."), "1100 ") == 0, "and the others go on"); /* Hera's own wait, on a node that is stuck: a line from the console ends it */ - CHECK(said(10, "12 AWAIT .")[0] == 0 && ended == 0 && node_numbered(10)->mem[AWAIT_FROM] == 12 && waiting(10), "Hera waits for node 12's answer, which will not come"); + step_limit = 3000000ul; + CHECK(strcmp(tell(12, ": SPIN BEGIN 0 UNTIL ; SPIN"), "(still running)") == 0, "node 12 is stuck in a loop"); + CHECK(strcmp(tell(10, "12 AWAIT ."), "(still running)") == 0 && node_numbered(10)->mem[AWAIT_FROM] == 12 && waiting(10), "Hera waits for its answer, which will not come"); { const char *r = tell(10, "12 KILL 66 EMIT"); CHECK(strstr(r, "Interrupted\n") != NULL && strstr(r, "B") != NULL && strstr(r, "Interrupted\n") < strstr(r, "B") && ended == 2, @@ -560,14 +547,12 @@ int main(void) CHECK(node_numbered(12) == NULL && node_numbered(10)->mem[AWAIT_FROM] == 0, "the line killed the stuck node"); } step_limit = 30000000ul; - CHECK(strcmp(tell(11, "11 100 * ."), "1100 ") == 0 && strcmp(tell(10, "1 2 + ."), "3 ") == 0 && node_numbered(11)->mem[MQ_COUNT] == 0 && node_numbered(10)->mem[MQ_COUNT] == 0 && waiting(10) && waiting(11), - "the two that are left go on, and keep nothing for the nodes that are gone"); - /* Hera's line must begin a message to a node that is stuck: it waits, and a line from the console ends it (MESH.md 7c.3) */ + /* Hera blocked writing to a node that is stuck: a line from the console lets her go (MESH.md 7b.7) */ step_limit = 3000000ul; CHECK(strcmp(tell(11, ": SPIN BEGIN 0 UNTIL ; SPIN"), "(still running)") == 0, "node 11 is stuck in a loop"); - CHECK(strcmp(tell(10, ": T11 S\" 1 DROP\" 11 SEND 67 EMIT ; T11"), "(still running)") == 0 && v4_node_in_wait(node_numbered(10)) && !node_numbered(10)->asking, - "Hera sends it text: it never reads, and she waits to begin the message, in the wait"); + CHECK(strcmp(tell(10, ": T11 S\" 1 DROP\" 11 SEND 67 EMIT ; T11"), "(still running)") == 0 && node_numbered(10)->asking, + "Hera sends it text: its number is the higher, so she writes without looking, and is blocked"); { const char *r = tell(10, "11 KILL 68 EMIT"); CHECK(strstr(r, "Interrupted\n") != NULL && strstr(r, "D") != NULL && strstr(r, "C") == NULL && strstr(r, "Interrupted\n") < strstr(r, "D"),