From e7b915342839d29ef6ddeff07b9f6205c702fa12 Mon Sep 17 00:00:00 2001 From: Bobbi Webber-Manners Date: Sun, 3 Jun 2018 18:19:35 -0400 Subject: [PATCH] v0.76: implemented jump table to speed up VM --- bin/8ballvm20.prg | Bin 9432 -> 9444 bytes bin/8ballvm64.prg | Bin 9516 -> 9528 bytes bin/eightballvm | Bin 28108 -> 33964 bytes disk-images/eightball.d64 | Bin 174848 -> 174848 bytes disk-images/eightball.dsk | Bin 143360 -> 143360 bytes eightballvm.c | 1504 ++++++++++++++++++++++--------------- eightballvmzp_a2e.S | 3 +- 7 files changed, 909 insertions(+), 598 deletions(-) diff --git a/bin/8ballvm20.prg b/bin/8ballvm20.prg index da17974a94b29daa150ab1bc01f10e06092eb985..6a29e2bb8c9112a8736ab66dc561cc3bcbb0fce8 100644 GIT binary patch literal 9444 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 N&2pdhw%~K${{z9j{j~r9 literal 9432 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 Hb^HGTQj*JR diff --git a/bin/8ballvm64.prg b/bin/8ballvm64.prg index 3c7c96058596e62d954068376662f5e48ad7d464..b3a46f2a51d5d1be6e9eef5848f5a3100439cd7d 100644 GIT binary patch literal 9528 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 T$^^SrYtoXfaQMspx9I-^u+l8c diff --git a/bin/eightballvm b/bin/eightballvm index 62029dd61e0f24e6c1cf49adce5b0031159152d8..ea089da470776a19370035cf97becd8ce376ba9f 100755 GIT binary patch literal 33964 zcmeHwdtg+>+5Vifo3MnC1c-`4WznFZ5UvGOPy&RDT#Q@=#3h%_1(Ix<>~iUc6$}c9 zsqxlor7f*g{k8g)Rtr|Cf*-f~J`upoUI(g@v zdFGvW-npDP@0{h_l0SZwWm&>p9^nz>mb4OL0O*aksGI@9FItQ4;v&&iq#}uVCiqc+ z!HYBo55g4iCUgMLz&s?&0205}j1z((g(+Dof8#_UHr}MdVq1uVwk7LjK3K5@`CE|B za11;H^)fn?qaqVVBAvnH6?_mb*>RN+ChUVi29tk1@&RvlQ9h~{laTM$ZzSqsV0pH$ zcV$IU@5+*1l@-;Ig}HU1+;+hDt?gSuk8I>cX{^NU04LmWa~g%1~WU1Omki3j?JU z)rFN6-z7_tkW^S34pbFZREq_*72%*5J$~%)5rKZWeRKOe@p!Bcs-H3;P!g;SmQ~b+ zgSAs8jHnD%2d5MkRZ?bIRj69a3@B)eK(vlM?2%)^MqK^pk*Vx+OV3S?BVKh~Dq7PT za}j4+yNZgoEI(iKS(3NK67ak@pM0R3G(8qjymyYGeob>U?XGE0P5Wp%K-0mR4$*X& zrXw{Sqv?1}3pAag=?$9RsOcO{OEfLlv{KU=O~aZl)O4|?OEg`k=?YEn)U;94`!sz( z)76@;(R8h*k7@e2rt36)O4Fw`-Kgm%O}A*eP17Bk?$q=xO?PR!ThqOo?$b1?=>bg- zYI<1HW11eYmB*g-D zm=p`saZ-%LZJ@0zth1yZA$F2t5q*oal@Pl~F(7x7VkGY+O~YDD+D3>dX}S=T>ks&% z9Uy3FQ|1gIR@Dy{Lfp0~oDyA+Nc|SytR_%(#h&C!8he=IoLB5&2oU9rez-S=>tW86 za%O+HQ}SGO%bED$Cdqds&p#iolYD3Le)4N1&uDpf@{N+uA>W7m63H{GoEm;uBl(`> zhmoHndEPZk8)FX>Qrg(}qnlR#wSM2hf+>@tTyvK;^}IodhWah<#$p8x^(7?NPm4Xt zwK{qW1RP$~Ij5<#(fpUll{QBAQOFDbm<}O#EQZY*Zsp%AwuQg7>Q-tAyLFhl@`L&V z+1JN*)^Ew$-qhF-zC;{qYM?PibgeA^D9TTD3+SAaK>}9HrrfQi0$A{K*;=(kbgrFsIbX7Xl#NO`NWbDAg|4T&B_sijSareSR4 z`&Q&1Zm9n!wltaR#o+wI^RIyPhWdRpWOQmS$4gd2eU$kd@c$;{7DNNRWjf+>)1qYx zwEsk-tXfs#jou?G`93O%iyxAyrGFu%AMMq$bjvNhbxYE-qXVS$KCUJ_g2pQqpW)Kq zD~;bzsIbN$*yZiX{t_{9Gx& z+ezg2cFP~sviu?`|0c+n9WY7?d<(N7sRJ7B-N%-$_u853Rd3u8m)=kxki~x7yqN5_ zM^)9ToxfI~{U=P1?LE#G?w;c6v1OaWgQPkoQf|JHtH+Dc;0G#Q$(`;nBD&-ASj@;@ zBIPf3%Wo*K)aY1|6>Wk6;v-FFaMYEqOc;Ku_0|gw^^d^{%p+YT8tzppwa;AtM#HtS z%niudf}GNo*<)NnZ54;m#`-PZS+n(&@J9DR&!tU!Crj(kwW6;>S7~^sr40p8k1{hi zcndHSzM?8Kq^B>x9HMX%F z2v)QKEjc3_X0FeMP?x30#Mq53b)eJUM62bT9)z^%dwXIiKMn|-aEM;g;m0084Fpt@e# z-9||??e=5T?!^Mrt?Qw!drfkejEg&qLFjG(I?K%KmKy*-vj({An{X%c$p(0J1MKK$ z;G3Bj7SS~oBz33B@Qy*FR=%!g&x&+s#C|z*e)lNNIsZCi&N8D-3mtJb<}{movV2OtL8-mP&RJVvl_VHL}Oe7H}S4C@iW@`+6l(iSD|%hZR@XLm3{6o z^?7FeNvvx@y>HaIW^8|LEAK~#*q{%`DFfTlchSJJHt_$K)%Yr@@gS|S742>`{wmAI z84haKk}?Jz{q?QTrJu4Jimo-?Fd2<()(vO2LT^i0Y__Sz=BuyTTRx$No5q@%_#0>} zHT(w6ZbrMy>|g6je()gMbN~;M+^^Zu_t3^>R*$dbymcHf8*;ZwdM|;;M?4NRa9}t$ zQpVI4+*M)>N>I|tHt8o@+lNVghiHARXs;xF<$BI~@GvnSdGR{{^)g$Y)2P`(cP8$J zp8c3c+c4S~?J+3jHd;f0-WWiMPmq_W#1{$d8Q7}ecw&i!N#I!bv}${$+Cr;sMLz+b zsJ7PhjJAa9|3xGGc9b!~!_A~Qx7-8BOK3yEnHk}$ZGjtSgKr+KV7Z4C9GgbjO0fL_^~~ z2X39X3hYAx_YKD^#;QrDc?>?;4BK;ns=hl?scJ>PkDBEuiK~i|r&2YBwkD{mofTi@ z`EJ_e=qRbz@VH+6QH^`_vXi4$LpDYNJBD^Ki>KTwWW{xAsEIYKQZ48UQ)aHe){1ZF zqwS=jPgf$%DX>>ISC68Wx6v+BHw2H(x=Fem(4@NkG<9f%G4&iYF{w#Xpc={pFyu@h zVAZ%+wIB^GSow*g&h=-h4xEDC===YqLVJcAgo3zt2AJR_i z^QbNh$-9_tzq*g!U@WH%1|*Cg4M8uak|U2uPk~sE7~yZOe$*V+%CDE zrZcUFBeEb$OOHog%AYh8mQNayob~sr7G@7`;9MqCx-xxui_am6xAKGkp!@^Z82Rs^ zzEjJ`%sVsr7}obl>EGAV?dUDdrOQo;(w-As&mFm2!5C2)=}8$UtWV6{$CdTv)}Et( zXTuL&tr~7e_d(U9hM$#cJzm9Xq;HL9t=vqh+_boIqt8w`E>JFmjyaL}>$i<=bP1p7 zLY1&+KlcF*_smdZxL-lnlN-)kkmSrTLv_Hli5VwwVu4Y6^vFsqrD}kkwThjjis!{u z^nJ}Lel-Q<3c7F~tr*4;otoD{sNBqoC!GMXqyJ-c;21mYHZe`sma1#BqesCvt1V$$ z?H)F9HN0a=uXrKzhv*=8_K74v^_h;U_`=O~uKaJbN6A%YR89RV8s7U&X!z3m)bIto zOQP;@PeS9fw&6YBgoZg%Lw{Vuc3(xqAAA!U-uhSC@OxJn8-}3qS=;cwZ$iVpd#T}W z9JH%megztzwTAb96B=GEHM}ye;pL~)&|6T7)ADW!GuCmSsN7b+$9_TVPx(Dp;6$We z6R??ZZY8I^&n8UlyZ%Cht{P+vx)|!8+@MmS$c2eYIO~sW%r~m;-aWGa2P$=~=qpga znYxJzWhM{AFLQ8*O;VMtvO-sBM`yNFWqffy^G#CMuf7j?<2_pA)o+{5dmgGbv&LDd z*7~cfHb|=0KdxHN*Q8qCuc(^5yZ>l6?e+t_tD^4i%b{#DyTwP5Yi_B1@6p%4)ZM+O ztgXAQ&5oYmQf={G;<^3KgbC)j;MDQn<~QGmv)Fx)r{hp>`pT0a`bt>s!A;}2TV47{M0vK&(5kCl8( zlaH9CE7RhMnH%0{Sg{XlvGsaGBYj!SlRmBXnH$s z7v#isO?=35wPyc0E$%7f1>=t761JNIl?Ke;*t^$?xhA?;-A+M;!F+q<1Q@x&H7 zB%YU8;A=3;f5XIQXO^%msocEo-cNdwsna{`)ARTWojlZe8CH;e8h1vyUAQ{2MH4iy z%GFTL1E~4s*w(L04#`JgO^|3IM)KxVh<(O+D_KmHeTxq z@NQ{|OMrZ(OV)bpSE}`)Ke4Uy9YWdG6{oB9In~y#coEpG-5IwPyQoWLofq@vK3QkB zs&oJF_#{bgYeS9Iuu9$423#NSefd(M*5__-qCUwI5(+Kb6uB>6*J(9(Tq<%Es(6bQ z3*xQ87CUu+UnhAC9DHigqw8BOqi&^l6<* z7;`JsOY9hwRO?N=$!_D6ZsnUsXHe01WJOiFB0G9hQblf|@|8oJVkW%hc*6LTvajXs zbCtY({*iAMPm2C6sry{Ftus*V?KfzHH!fp4*wmLygG#pwfjj?NI$5`h*oNjV@VN8@ z+oLV3merTw87sDP|8Daha!6J)PgXC(yvT znX$;hXiW9?s{DgE)J5-RBeqo(EeZ#>4)Yd=N`fy9^KnKr)ITW8FE{1WS$a{NYp8!% z=9ifi9~L^M5H{;|+5Ic?57*y(SY$4%#Jkk{D(hsFpP4%sqdKl=r zR>Rc8ljd40o1zaUm8d_^F}i{UEEL$9e>m$>AzsS=l<&Svzw6P+;T8FZmfUXWIL!&@N$&2*JnIn}o+|L`-f?AWp6==&>oZjO5N7>PVW391wO zM8~RvjobOEF};0Xz)&gkp@V$){`iuckGG!R8nqp--!y%HD;4RZ(Z1+wM2`WQLn0^o zIjt! ziWcwS=1(Bn!mhM3v>>fu#87ueXud0b zL}6vi1zZ^k1*TTlMQUn7wc%iizoHty5sVavD?-(NA*-35H)-P7iKDOd2cbw!xYiH7 z(uQM6=6dWet*8w8yN{UUFAdfDOM<0^k;-t7tHt2nkH&RennY%csTT$ zHo-r?Pwt?BX=2u7*`yKW!Qy#!{_7^rP7~dWdkha16;<@~_v_PlaGDrZ8w~m z3TuP8X<~duaj?1=N=iHUM;DCGO-mF0k@%q@BeYj1&sBTzd#qWAdtZ*ljw8Mn)DL5R zg030>It^yN0rV-*#h{m9psfMD9drw*4~xxS&~nh@pk6F!e%yP%4>}Tb4A$Oq&@G^M zf-c1^ZyjhC-2C4H-3xjQv>G@6&M89VVkO` z#9}vst_58Jx&W@q$3RozVciM36!b7?F1*&AeOO09ad#Dc;AbxZeE@U?=rPd8L2tkr z#!k>fpvOQPamM3sEksWoM~wk}4YUTd2B&)ufbId^2)YEPqn)Cc-+&>GNp4xv8KR}P~-(8AA9AJaiaTOlSKiN$h2 zn?T2a-f|S>Kr@b^9Owejr$O8Q8|6S3fgS_h^&i+X1NomrPtgAYEdl*4=n7E&F6D91 z&~fx1D1ZKO0CXBwp!7`C2ig;KAXdl%&?%rbpihBr1kL6^$7OwYlCT#0tWN1(?+WZI z{7B<3^~5%eXVMJcsEqV$Guwo{3&k}TTyhs4~tTq`l*THN;-uHl+lZ?4R zVLBpxAHp-h+?s@89u`I6$DE#%l;;QE8F?khqaF$ExVI_qMKpw%VZiJL=8j~{t&WZ* zzzoNFA$JpQd;G?cL!0jcW^uBdup{SjVESO4`9m`1DM!vuV73GElVr>f965)98G-d_ zb28@l4yGg4y1l@BKN)kogBb$MwOH3SC1aj;Fmr(UJ20oxXBjZutG=2n=S8Poj{%d0 zHL@`ov%;xs2Qc%2c|94k&5?5un2WK-{x%u&OGi#N*6H5>^QUCYD-LEbFhy9Kf1Zr_ zk%PGr7_Q%MC1Z9tm?gk8Vr^fSjCst#tOces*8AI%F*iGyZNS_N%!XvluN}+*V6t$( zn3#+i8y{gnEeb9}gth=2y&H?5YU@F|0JYb5QF}VyF{yw=p8B^q79s|br z=jQ8_t=Bm}%I*MW+a)3D(`<_$D83W9Hr@>SL(;oY#Q^{!rrtvhGr+~@8e(TrCZGY5h`z~M}JPqbJ zFnli}k}RjnnG1gG%_6{@ZoG^EE_w#I8sKJO4|pnhe(3W6aIXS)s{Y*wOh@b=f03;J zj~zSg1?IuiV7%B*UV#1QtYkTpm7LBx?CZG=5Pqa_&w4xZPj!E)1m;s< zo^;FLnEjQbZzC{EvG?7RjCtF^JO#{E*bg5`#(d($DaAM(_lsd(-r&hlgZ(_Qw~fWFdN-6RFsm10N4$V^XUVQQAgjx4tC*o@>nbjt_~lq|q%P^Jr>L2w(A zmmhzZAuSVWcn>6@u8>kyj<3gnxd<4#)7<*#t+3py?*OI`Fss}c7>;9m+!imeX9Mtc=?{lACBjxDtCFiB0dNBJaiZG>)iRY`8?GS>cD5E zJ;2E44pT>g(qRnp8o`Lp9P@-otwd-5`}ZujP8WY?!m%^ADPi}WJaF} z8UE23*?CPFS$QvIq~~qT@a4Uj0prrveEvEJSvF<;-}QeM_&*Dr(gN#nubhLxC658q zN36vj3T_Co>`Ecd2j#zc)d`gA*98dtx34&_$$xet7UDB1wwPigCLM~39pJIdiq{aZ z{K$EE4k#}?j);x;H;FhuIrq6Hv_m)#;YJi@oX;%nL2Cf&01EZQg_?dIi-jQG2UkYu zao}Q#7jWH#?gS6lN$6T&&-CKIeP^z}qy8fZsn{c(i*O0TK!i~U(-2A#+}GNH4(FZY z#FJxh!59Nzh@A*CVc={Sw-I4N2HrA6csvu&Us$~UgYWRMMLD-7MFM@$4!gvP} zwwx4>c!aCf{P9W5ygDyv>yp2$UP8xxZc>`g>w;&JUUKs8;LP-~tN67ID@jSwf zUE!BQc<3VB(=LYZ3}JkZ5dT7G>;|9UCHOa{5O^rjtvlifV|&1_f^f@a7zdXNu>zr2 zPt=Fds~7x^2<>sBc@g2^-q?fnL3&@r5zfa=>@I|H{e^fJVZ;FZ8+{{2T1MF%z8X*%m)Ynu2$^SK; zCGci!yf^2WA=P;-|=cAy#3#}KnH>E#7UT;c8by(QGlw5GOM2Tk6mZX=d`R+ykn6b0dCO-a3ogo?twy zwI33_@(DFNZ3asTiy0l${=y7PGM&=~Gsl*UKW)5htYmW1{)rZNQzX+pZ6TRd$@EN% zv5e2EM#X*7enx3&Rv65HG!J!2x2W*oG(Na`vm`Sl?L}(b-dc*BVQK4_bFMWR%*eD8 ztn@sq5X`7FjBVlVXnhxQMyEZ^GM%kEz>G=TPNti6CjjHqwz5nw>xW>bq`gWeS28!G z{fSI($=sO6Lw|1{$;?Un8<~CZ2|APw{g8}1XS-l0fK^-@MU`;;wc+YJ$> z4g@1p*O=5xMaBcDG_wmeyvAaB<`Bk*srW|LlPBY;-bWy$)pkI#g7}lVoYiN22eqfJ zkWtJsk-Abw|AW+47f`2kPKGuR*$z*=AX$5u)rl$X?}Kz})_9;&JdYGwqC-uwux@1E zq zy#GW>s`nuNo}0c0e=QhQO3fGNWg~7~?fpa+^3TCMSWPJ%Q)nJ8;p``C_4ynG)~DY5 zZ{q-jQdd`?;00{*VK1Zh-IW&d>}V8*hP&&wrqqe{7qDJMK!NV$Rl zGm#n}_HcRCDa(oZr-zHKPN7fE+T-C;e4i?n&$?dqaDkSJtnTzV3;$Gw8A)=Fhqr@SDy1!JU*X|R;uk9A3D*8S4{seh zr595o9^O!@73Lk1c^=+ow8b7IrqIKik4{;@KAi61ElH<5$GRqZc%zCaIg^+&(!<-= zuT{z#w(Cj{Z)!T_WlHYj;jQlH3NxB5y~M*CpiXJSl+GUB7IjJ*<+S(kW~o!!6XWyn z7OGPQQSu3!H&&gppP0{V-fneE?`O(>n>XQ~soFO)<*znx%@3=TN7#yYY~HX}tCTL3 z{EGd&A4fkbWj3wRWal77TjLU9p0Rn$pQA85akPG8b0eTqIZbtNY_EDdyHn%8m zD$FG6Jl5vMni0o*8ZTyZJnAso$jE{D=cpIUR9W%6SK(T7Vsx3 zC6|&bEp7}qsgx%uxya&n@%t*JGgGEn+(d3xDcjf=<1B71wVZXV>l%w2&Oa#3yDT-( z;x=@#N}0z}ms#ALKBH3Jq&|L&Th=>N%5#)+j>V0v9*6wrL@lqy?d=?i`POwzIXVdm zx2gm`1%LQyYlFD3KNJ4E1PQeg@g!nhZjp)Ok$^>3d}|zYUbzT4H%W~DapphI9a~T) zbh(`5c~d}e@_EI(s9bOIa#PhN&+G;>VN1Qq)4Mm1-r1@Bm)Y61yrol{Kee-qZw#-5 z3Mm<=$G*s3hPcB`Yj^ zLE`e)4dOq&h}dclA%)4;vfAE2$Y@n!UR$0wSYuRPWm~>tYmHTTbA|5<8t3ZoL0Ug4 z?K4Wl{^V*Z!eNrZR~f89>|*?n`jnLhX)7V6oz*R)LmN*&D_ z&_@!+pdt)8<`m$P;>}Zw9ElY1`1tsJ`=KZ0_s%>?Yg32?cJ$1R=EyH z@F~r&IiCsHQZ(#!j; z7wGDMX7Nr=@i+|bfaKI4QslSdscl@?3*!~Fx%B*aI;-lE61OU=^0x?NU!S^XozC={ zUQBUYfwoT732|Gua&*1)d}A2d3SWzA$WZ`&bx%;=v_$pWXv3ij=BB&FxGIo?!_kJ& z3^z1xAvC-VI@uO4(*)M%8Ex^`!nB~{#_AoZtCjy~epzvG?}dX01_lmL|9F0{vg%0h zLA@)giz_1~K_PLP>0MM2u4|ssJG`hSn3#^0moH!y;RUSuRk_8e6aNx?3EtMq#f}(W z2^K&U>oETD_ll5;jv6~YA2HlF_|M8S5jUQ?MRkE-ZEYp~k#~i{l(V_Cd!Dx}U*sKM zS6>8cwY9xZm9Oh|Hy82!)XjGNAc6CBwYznQrwq_#U-qQ^1c^gu*nKST_t&lHObHN{lIAMGjUITgx0RU>NIZeP^F?$-f-m9A`kzl6ApZ3eL~?_d`g z^f=$pnZ7?8^|$-LYgvb6ExkI-fH7xKljTSmqNCKImomuVcMwycuD)@zVeyL~212Fw zyX@g;|8=|UJQ5bWL|3gMkU2rhq4ewGv5E26)Oc*Nic!V@BV&q8lO{R4CfutxgU_{L!xn2z+kB}#qW?tTKcvOK$l?-@^PJIC@} z{P%Ufu19|AyV}=Pt^hyn?dxE7%eH%TX!3P`XI+KwZr?@tuPevTOkejIGwd`he(zx! zvISS8mY2hmuX)aL7715W)~OXOQjJBa1gjEOG<@tLR1*#qhw$F0T-Ufvaj)SSXhDg0 z=K0Fd!p|ZT-YFYj=9>wn%gX+k=bKS>Po)3h?e?V|^#3^>@_aM5V`+lLJ#B~h=A+@B z>-fi$?t7ecJWY{WiobSas;~D4p7TmQS=(mVHX1d*Do_%s=_f$31>~<7DyphPpspOR z+7?Ah$VE@9cZRW+iRugRL1b|pZ5mP0}k*LD=B zsVJT&!ojMV1)9|)-Z3yrBhC{Wz(1=iV8CAlaXJM$8v6{MaHcacu_91azQ3-r4 z_MF{r zxb%`ktU9(6I_+JV=u&<(2A{WKpUR@W%R^Pc-bH*_ymtYHSO{OQ z={=HjC{$AwtPb}c`0YOZddJ^7SLTuZtVd``ZK#H+g&2&1z;`0BrtD;Nu9>IEtt^q& z4Ac~s^aTv0pCbJg8KB6wr6kM{(jvBB7MmaD*KY!$($c!16kdz*H8)aK6E2biN!wIw zRD-$a*p!n*t`m46UzV+@M2&Y zps+^P!rfhH8!cH>PD<2 z>{(^Oc-1te{t<(apEe3W8B89vLZWMnBel3^R7R?h<_u2EV~jrvA2rHd2EhQiz&bR3{sYJCR%pupG^=zzQl#up(3`0OvFEE1+zA88`Pd zfZu(nK;RFvW4PGIoA62snwD*U#StQSS4kxD|6<%Yl6#cz}GQeQiR z6EV)?IRF>mZ|24Cq49b=&f_@%*N!-k#~NHbKj!6;r^rI^JXi6pBz-*2(^sd?iAg>9 zsv0kzAM^6a(`R*#t#~|kqyJYl$&#CiA!aPj<`mq)g&3Sp`DK^}Aah|>&A-}su>JjiT;^MhDFOPs%lGhyh7d%`S zxP}!P9?yub%Og+eodi$9SH>t0URT%Uk*BIof=9rY>$*HRZP#5RQ@!Go7%j%%eDJdI zwKQ5NOLc?fyMmwN;^~s1zLaB$j$#z3X}<+u7hO{8T=+%cjlFR4Bpv{7F4q5uVL-_z z>$d^vtH&u24x(IWg?|w#rhdLv@HTjJ_HV)de*tgmXa1+)P5<)nECm&s{;|+Moxm@_ zc;Jw24{KZw-Z-4e_XlsBx#X_~Zw@`k=YuzgGUUgDf8MVg`s62rH_m(VGr=1tJbC`U zz#Nc}uLf@pl*lgtZ=7f3mx4ELSn~IQHy5q7*2Vk5Zvwvw{mq%$-p&wDaqi7Qz~#qy zd>i@Zn1J$ltY{8?$bSId9IBB22)sGoBHtNvk!OgsUptJCBgi*?W9DP~E8jJE2>IlB z24lRWvOIWmNJ9Q%@Hu{U{6YRQ@aAZW`~dLANl*S7@aE`&{I%eX)0KPycyqW!ekOQx zctJi0-W)=ZuL3_9?ctRL`|udnT(mDvJw=hLy|*LZIL=wV0lYbkAm0smv;MTl`oohV zb1=gEHQ>!L1o{64Z;l+ub1gN;9psz98}}`F9t#_HKl%5-n`1-re+O@z|KvXbZ;n{V z{~NqHA|sDQM*LpSXO5S1!J9)+=3fZj9OIC`1iZN}LS#62b40=X0`NRR=J@0I;P36m z=ct1i<_EwV*Eab|@aCY8d@Xq68YaIGyg3vhUk~0t2i{QFxgGjz6?k(@$^3i3^9t7At9N{wm7vRm&9(kT)n`1@tzXdNKpBKl&^We?VE%W&vgE?L$|0ePJ@`Jt)-W(J% z|3gj6tDSwGNQI%yF%a=Q^>%;f@nZ1iFq!#1!JCWnhJZK6b<7`~ls_Yh zpAX)g&=9{YDgS=(=E#!ytHGONPVx_fHwTa8e+8cZQr~RoLjGCs=7^d+-y$&w)Z}-7 zHwRec-vPe{{l&Wt$IBk@=3@I+V7xxgNr)>8`5zn}dDw zbHJN}Nb>W*^HmC^Pe)M)-W<&_e=&G-JWc*q@O-BOW{~!|4ZJxDX8xVv&Cw0{`@x$d zdGbF6Z%*yVKM9`ijL@RA_p{*5!6frv0&iZWApbIWz9M4ke+#^^7su~j@a6!S`2FC` zfjjw6!JEsENILEx=4Axtp99_;Nt6E_48!*rd9}w|h+Pmj$F0oo1>PJek{<%z9JP`c z#dtspM@mcK8gf2L8VFYf@X^z1c*g^Ql2D+mG6a`+paf5Db%DajLQx#5s;LZO_nteb z-(WuRwE*I$QY!+5wY7zdu%Qp*(WbPvuqp^oPgT_-6mf9@Aj1jJ_#R)n;p3dy@dpB< zCgn}Y59CiA8Q>#FLU}x>j+`+uZ^GCSi8**^s>M@D01lo&{unJ`%*aV1FnauT!}G=m zt{XLKa{iRSl)T}1&^7uHJ_ta&*w|;W+GoiMuV}=L4&pFf<}dV=yC4 zx7rm!1uGHUw)&3mtIaq~pysA35EbuKk@V#suw^GQJe~S!YMG z9B6s~sWv;l=F*x#`2zLvXQu$oR8&`|jjcQ(%?C`OoN#mjneL`=<$^@ScxO07^w3c5 zGU|&m(jP^)lq{X-;dNFA$Kz-mGg7p2ElGc+3k9-wNFiZ}`|Q{>hys)AbzG+e7_xrxES6RfQfxv)_%H*fgZUg5$r z&EeEGwo z;urIHU5r3C266OPG58TT7xz=V@CIcZM?V%rj?7Vi3~nS?{PPYW%AAvt`NsC z5rJMP;^_BcIEXm6D2Pf7y-L#%xYZ|)&u|Q{A#N^WdC`@`-#!pWKN-V?h?{zu&M*&w zzm;H|{xgPQh`Z|rE53_BFB)+NfMMY8FN{34fsc3f2*eFXpude_4C2JmYh`eEB2Had z5BFgV7b9*i;&?4bFgW_>7}hXDU$hCa_aGP?{dNq>3#Wk8je-6GgX8|4!S1gx{AmaK8r6Wa8*IV%SGUUj`>%!9yCe=r3eAsN9hf zX>eP?(Z_~vkbbF+7(gbEK*kx~M4)$)IQq9Xodie!7ECK~^m}aq?wC#kk+NvNA0V(D zvR?QjH(n>iNbu$|^+u6kaAFRa0_^8qcJU*L*S`=bm-6Tj9DF@rwReDir1Lt2z|=lu za1ocIqVg~E7>;Wy6Y=Lp;D#9n)JSfFh>0_MHE^FRH?TyTyz`Q9Kg0tl-}*O~!O?>n2mNLy2Y8dmvB9`$$IMc^KuN>vi+LuvsuBAtArJ3O`jOukfp+Ft6qV_9lZM_tAazKj(kygq+&$HIvd-j9~SUtbr z_lFDCUh7@!y{&g$_PWi^jb#-xHBA$i(}gYwRVE0LkMNsKDkop~#6U4lj25FrB9fSA zc^?Sq-AJR?;i~~#J{>SU^N=h(0^6lc7J?ok5mEWiOc&yr`N~&-=y~W!xy*MV*opj| z$frLBn4bBT4o#r3d@0iDt-Q*2L-qB!LRkKBUQ{99sb48%(UTs5 z$Zlz_&2Fim*wWk@UY*qu%*s=Fq-FlB`HS#Wc4ArRNSgsq+cAH6Rqj>)_lH;J^vpHR zeQ#^|V>6fJBoQ|So;;+je8PvQOnZ3lU$!ysbcGIJ2;#RnU?1Ys95C}|IN;HU|HJ|N z5I@@i6Msw}IHwO>)dzMOmGtNL$-k%%{DcGcA)X9>PPVeuVAcfeTu1vB2!Htke@Cdk zxz!);2-J(f>gJGW2(|@UMMEIiAQ~D2p*qnKYHvYGd!VLXG}N^OI|9P*uUlQ?Z)k3< zX=%QmAX$P_O?$|{vZlFJT-V+l3W!-1RyKE6u)OUK!{fvLckjgq1jsulZ4pM5S15Y=oMmN-4n{ZiTsBvTuE-Q9 zb<4I;LUaovk)58adJrmSJjR}3{Fr*v89xRCAqS=2w+y%+v*b<8?%gY4_M#>x_HL8# zaKe1_J}TjJ2>S@%FJVTT#u45q;Y`9ggx5-#SxwZiw@tzm2p18)R>Jv+Hf%J0Oq7O= zxgT89`F3Rgp~~v2DErV&Jy*{WqB~OhreRceNA~|2!R1#NkFoDXZv=xQUFT%>G;Fl~ z#X}7nqx;EZ$1pOvtpf4xoB5o&J9KW>&D0WhOJCIaZscIb<;LE~&a^!}8@odnio-qK zG^U6?h{sJk_LU2<$jM;*?#_1?Za?Pg?1>z7Z$EIp_UcQ=LK$6m6aoE~mqSUYqRPvS zm%*@W+3`I+okzQ$8H+3dQ46Dsq4!Na5%2`@+NbN85gywWp(&ux;K)I*@z`tt(LbFq z4Dg6f2F0!j5w(-}E$bz}u8hncGDkt8pMdJ7o(sUgtIV^Z>_~UyIW+#%En-U9kyTT{ zy*pC>CJY%(!Vm=Z-I3kQe-i(Xx!2Q+M2;%5%4r zc=2aQEOkn(=ue_My5pZT+K01P9#dAsrDE-MivNE|{;yxqe~I=hma0St6;gbO+|gRe z|6AY>wC>0*$*}WehTV7WWJ$NUU8!4CZCqw+-yL~Vl2x5d2BwwKtDSn(TY8|zu0Xp; zi@tfBMNF1OWQ*9vva;$Mp2du%JF*Uf5jCDv(bOl=GH8m1&bTHLui>$>)b$VggxLO; zt83lxW6)1~)p*Np6YI8x3T1)!OU=KFPAyxU*&?kn_NsJc!Jowd5ncYNVc6WdD>W70 zkQVKLLG6|+Gh|Wv(^cEi9oc|_IP&5NnAs(|?^Ie1N!{{t_Z&l(|3O*)jM=@r@VcdX zTJ&z1u}>MgE1?QeQ=fEKq8BL>ImMoVgnCHmx1^mA_%D=HiBx^&WQEKw|GDk3^*qZC z-Kd!}vP0^Y43}Ln)Oh!7gBF$sYv_b+mxHH`;H=|s%gXOpRWtDv#_n74ooMNw*#el^ zg>HwI9&4H>DZ2e!Rd`o)<3G-@@XkiyM3a7Sce^v|bUt1uU+Wr7D1a=fxwB_&p*a*ckIbg);Bf{)Kvr(y?FR3QG z!5eEjPMZ{(QnYBICFM)9$tjzOL*ZDL&p=63``Hj{K5|GfO>)~vtIsSs){jZz#*V$# z;LEqMwl}g(J4F*e<%pF5skVuoy=p3y_+sP987kRtjacnSnX=!pb}5!hYOEdq$rrHK zX~&(vjra@;4TISKRSTW6k)7FCG#SdPe&#;<1&s71j88wu@<3JB^&gv>^jq_0;wjp* z9J0Si<8t)R*{DIQt(|Vn>K$g;@)t+?vE`YKS-azU?rzm{PdAPQP03nxx+VF4(RQb7 zb`INpjlKHUiJBESUk$7>P7dNIX4^Hf=%}1I zCORfHZ+Ulb4HSTUpdPv+5;ysH{VK_haNy)JoA6XfozAdH(tNRsyrS~ zVV9C`7K@^{)Ko`{rk|vasR1Sn=h;es@X=>mq~Kptx_3Kv2jWzXH57Lx8@#z>Y40OC zbqhMRqkY9};^xa9l;bf)?-wD?1jUfA#=KW73Fca@yAm~GFIG%W&NfgA0()i0A&9E) zL?d$!fYx}S==*&)ZN*ls8tf`hQUQyTQ>n21P#+b{rQT^~#}&53kzmkg#vO@j-5ID8 zwi1@a>f!Pol4cjUyUpnCQo7}$@TptoX!iUn`gf_<=_rz71iK}HZRA+v`w{jfm2uks zdXlP+MN&T6wN-Iw3wJ8blAu}VM=>!qpC#sETg<>yiecL^#n3iN3XIZ^=I;+?%cc#w z?_394a-ncKi#Tog1Qa_fe`fo@_grPQIUrn))Q$ ztJ!GcP2}y9aYFkjW)z#oxfb|0TjabiN#yw7q0`tk(XY^fw$N7(oMfLfDJPqP!vM2S zq(1ToOQz!;?JVfsIBQYuw*Hhd-IaY-F;*q#&xy}CfsH@3woi_BqA#l|{0z}&+oF5_ z`&7mK{Gv}I_($00H^;yJ1lv8UZ?iEzdClUCzI2tz#TC7%KQ3{z181e!?A@~)rtV1n z4$S1tJ`uO+V&^&Q>}{`AXOH%t%5Z&~Lm$a^etyY~w&a2@BKeNbFZlx;t*CbTO!Nzs z`JT@&xxa-&LOiC~NBC;8Gn@_m*g(qw&%Spm14u#P^K2epvKn7E)zG3v{izY_RF~R!D$|+2%toE=z4D(P%ZzKkB#{G8Cvv(ia?qC~GWT>Me>*^xQj6ZZ zzaPWewd81Ps-1lDl4DfA#pL3OR`l1804Pw&q*e-T*<_zK=HX8Q7-&oYTt%qjSO9 zPubM` zo<*0#`X?==Bx!8<)IVj8q;$-AV%rm^Yg;2xlrP8r)++J~*`NXT{MT$SK~nb9yr;5J z%jW%^x6HO-uOpos7iMC=&Fy5ij*5se>HVI|>hVoD_U*G}AuC(0tK?xRl&XwI-JsxA z1iNpw(woHEa&8ABy{SxEg#5@CC|qCnN75zliMz8 zWO1r8#!|%`V&ae>`ib7hG3!!>jQlCykdA#fTR~@08lL5ysROG>?TVK5p>|@*^K@(# z$DPcduvUl}b5fstxw~s86w#jJm7A*QjVIL=-fe2QI*=F*qK-DkY{1(D$_8n@Y+BX@ znk|3iMTvKC?}B|0&$R;jc9tD7(Rp10x_3v?(Ag@ZJ!}Iz)1bieR3m&S`l&KqSJ@%# zY{OI;h&?N6*MtJk7P;$!^?_YQ9$KzDk}K&W7QL6$VH@g>Tq5)9tQ1doWI9ub_Q31X z=AC6nA~zfnsq0z{!#L0au15Gs^lp{8q3o}*!p2v4>XvzbwRhSqBv0y-+ncxDv=+BH zqG=7=qXRm3Y=6fyen;o-@q6*k3lCz2Wkr)LeWa|{UXzO8m3Xr${iiC$VJvlZsJkN5 zjk{gO*N@ZCmq!;s%bR+>ktv%|cce%bb`@I{jS2HClqvO&6po9PQQnNSa8}8bB1g)t zG9^o;M8}LRi z;nAx|@J$drTXrOEtPs1({>Ix*a+l+i@R1E=hu7Y4ScKe2*Vf+fHxU|&D^G_b+j3IP z(c)%QIm+Uo>0IRLDm(Jj3(r6Q{3q{p?%f{M&Gr%g2|1_=%!!sO!i{@aW+)oniyBS% zXta6T>iF6ljt^Wl5YmoEwk;AF+))G8dSn8TyJsPBX%tC*-Fsy|I( z@jBVIsFX*-_N#4 z+J3@y%hAx7TtnS^gnEmNQ04^b?|Pazk!LlOZ|aHgUm`obS6$;@*3-QT_ax2xs1YgS z5g&UOE}-gAM#Ih9vQ;%LKHLYcTj2}0;)ZWSOYpj+${CkBGlHue=`(6t`X_K?#1SlN z?FhHE1=~Y`dS7!Z?kI=rLe0TepO9h}7gx1ke z5N!9=2O4U^Eurz#MMba%SHv5AW5w7c(JsoG8=FEUsIM#L`Bvp*6&56ks}{# zvLY)fN%%@}0h|%GqmlY0k0QjurkI9uJ&*7WgohB0N7>vMj=qI(9KwSL`Fn?JP}Vkt zTM^!cun6US6yb7Qec@oY=kK^WjIik+pu;$PAHoWRFClD0c=e~4C?LEI;iCv=90wi3 zM-d)EcmaBQ1{!%G!hD3&5Y9%p8R1Jhgpix2sC97TIXXy>CW`eIEA$U!oH6Y|0*hH)R_qSUL2S!oHb zuqaK{!>be1bXWMBuG_XFxwxnJH#1-WAJA5VW(w+9{&vHX3%)_6wjj=C;LHV19^y{f zX7OeHYy%GOYIQkrTBJF|RmA%7?GIm@tlESK3bpFcWy8ToQ+($d5AgiY^5{tC3g zl}>tBv&{D)tqA$QKz@fapLM-L6@)s}17`r*t88nQj7p^g+s!)Ue+nKjxpcGf{4UZC zB5fH{Bu#OOcfDSml6I@RI3**JFh9lDoRV3bGOjdbLTO6QycFN8l#Jq@l(gbqDc<5| zQ#{4LNdZIh-w$2_@)>;PzOukq7Wm2nUs>QQ3w&jPuPpGD1^)lHz}iG1a^NwQm7W_2 zA`!NrOUY}=dHNyCb%Ux0Sp;G2qawY6Gia2_9%aEiysHc5KFNj z*n6<=5_|}FSP>HzxFs089WbV%LF#p;j=z1k+!he-g8u{jd+zjb9>Hm(WOaE^s z=u^PLt@Bs$3Ho_>ChDxr0s4c;_2_RRWuX2hXp{6kcqZ$+kmA)FK{ZHcm8R%35Kq;= z4XQMKF*py_!$=vT=i-^JkH<4Z_aXNz{a)k_)mPv-O#d^U!}Y6?J3_x4&$IOz;6GAd zhxj=<_ZH99F9Xhb`a6(vzP=tQK79&OM(Oteb2K~_;QBtKWa>Xae2o48;uq>q0duT= z1Ne;7XG7cZ`YhyLq^IKfHGLPJ6ZFx@ov0_{nWb~XAY0!C%pCm%xk#;^AVq{-v<5#dIZlx{o6>NqTdG&Q}qdmU#!o^^Ai1DU{2H5<9Vsx25!^!e}MmG zdL!aR`n`x3>wiFQiGCeYX6TRLS*m}8^fKXg4{#xpa0Sv_ud>?Q?u6F>B)SutTSLO_ zN%%b=x90h8$a1>|JPbx4`ln1xWUq0%5{@zO3^<0wgm&=I3qK{(0f6<}KVbB3Xsvfo z0Pz5~$GwP5w8X<88_0Olt%%*_{`hSK$>mhyDECN2@=`MXbOF(mhcSMfaZmDiru>s} zZ}M&!$9;nFwB!b+8;oaoUxP@u&?{vv>dOG+>*450OWgzlbctg!c)A5sX&?prg^`?oFQ5v(u%wd1cqt@ z0hD^v$$FSJ48Tk;m&ESjS`N}?c|Rb7bF?A=v%NQxW{g&XvGgdi5Zxy`!^WdR zi~oWq=4)5dS6|Fs&%OW&80>vU5#QcHP*P)CPg{Pfp zp`T6^Vx{E7PBai_4oFluEy6RBI87f;5Q5u++U8|8PSY4AO?amf=NguG8}OhQ@NTj3 zu2H-~!c$AUvdO^dk~pu}IAtcUL9A_UmZDfO=qy6BRbI=W8wr)Gyye344;p8>4sLmp z+sEXFzBrwVu$iRXM1n$AF}GH=&B{uJrj?K~SR0d)o~);gOc|^VNle3}&gIthlr%6Cts4RrK2v!2|eYUWK>|LNKT#(bkyrmq!FPU2#IDo8ufrwprA`LVAjA31%sq? za7|9OI3^FWsiy$jYk~>o=>!K^ywSNetvsDNq>cigY-FaTgLE2Zxr6f+4-j28f(b*+ z1jtnhJUbH^&Quq6z|TU0M`?c92qp}btYOPxS>m!0vQ*$ndlU`7rv!|LXK7Ztol2cX zn4Ex3K4&MH3Jpd*jI?)Zs}BII>mzlf~EerhaMD|)OV+*S=F zm(~)i$-l#rd-_#_`VNG?rWL7gQoQ=fF&i`2>ty2)Kt_XN+7LCx ziE3L21ux|IB;KG2v`6e$|JK{9GR_JnNDPka2h!QGFcP3r{=o)>{ZdcJzn{S3I zZ>VC-j4OsJX=W;TKc|ot8ygwmbFS*4ajE3KY>($@S6;g3>7{$9bslt6p&7NnrLM1~ zyDHOxJ{S3(eN;!qiTI*xbh>L|`Vtgt2}JC5O_SjsqB(1mE&wHX zcuKEwl?=VgRXlXr9@mAmihRsdCRm_?`6^hXf`ux`ha#?O6+d0DY!9nG(X$(YE}!lY zqKQ}Xk?4sqpji;QPLJifgrZFqlFfq>JbPT38J-F&39x6W1o!Oo z9HvFy#lu14NR{MsJr8>>^~?p|aY{;DknJiN?7HYIV0z|eyK)D6?u5ir&;7Yd-APME z>u+4|nWI0HfC_l;QO~HO_j#s!M#;``U$!URH73I~KE1~?Zr`KLo=u+7_%{mwMlbb@ zTe8HJgn{Bu=vOYmp4

@!8`;tm}tE%`F|O_lH~2f$PzO(fjd$*8bH$z|jdz469ogd=n{NKkOfUAJ7RIE* zjQXHyo>iz-eE}c3*Ygm=3OuyL20UFG6Fu4Q>cblJwB1WE!PB%W=J|_DOYzaQU_*mH zBmh=a^SQ9PYVm?9WYjhBvu@$or3+Cf5BquUZ{P4B#jNTwab2*z9+xge2R;r5ZvKuY z+|#HHH!#1lYIfO`j8s)GRPelov*d^9^8C5{7#+qpe(r679|Zo|8hmXI$nzFeFj!b! zT(SfL5S?36I%Bp{!nzm2o0am z0M#)6kHj|uH}u3?8-oUM-ZRp%PtM93bX{U5@m7tB|ud(yxYi%X2=^P#GEA?PDyz+>wxvh zH<`b!CEOt)`DH*qiDC`NS%GsFR#7k*frY9sB%uwl{j{(^LN+Jd8*x+^(5<>vW^2Kn z6*8%;f+5WU(4OS&Zwc0|Fl#DL_*YVK6cqI*H8k5HK8hGCEo;xbN+eaQnvW`xUr(%A z6|h@r<-*xkos|$n3WEit!B}Kfs$#St6}u8jlM5AMQ!uT?+&S}PO|xbIm4Sr0D{I9I*40QD*G&j2UZ8_!Xa5LW-7a|YUk+D=%MVHxIYEi;Z}YFGLIbQ zmt9^V{HsFz5Tm1MG8MU{iz+1+LM6`bljdk))*q}P#}1HGE~vB&13j#IK*qww#gfVV zvRRUK`NA2+9B$ab)M!+Yuf`+T!!l2(L3al2$Z)P{J=Calc4S5*t@+1$u&01QCS<~Jq z>YE$!Jy8Jouh`TF>IC{RKPM{Xf|N!P^+5@8`g*df<}4jfePI`Ow`>?QW;oujqT@Gs z>A0Our@jcP&L$L$6&f7REa-H3av{X+iVQG!OhIqMSdGFRv|;?v4vuFQbhGFg{ZAB>FP$5ouG?z?KmU4IFAz`+quO@1}%2KX)hPP&`S%w<$y;4=Ghe;^SLQOeaS}? z!^KR5R{1sT_Ha{Xtpk4zV9Q<_?Dbv1mZSWi02r>S8L<@cb37Xy@S}h~bihvlu9UYG z5dr>Fcpi1YzXm)V;UaPrHGFZ4&(uxbSdH}!rwaJPXU*yW`-C9!O)3V zb1Ro35&*Ar!2F58+YXrf!ELG;O8N}I_c-7YfDb$1^8j~P2ZxY%0pOz!m`68FX0xR} z69K1V&&kp!5AgL4xDfCQ4tN^iMRv1J5ygOaIpCRq2VvX7;x`xYLI=#P<1Poh2yl-B z=GjKU*)e)<3;)~!*8@J^?j|Xs8SuRhxD{|Z4+N!45gmY+IAGp$e8mCZ0C=9=ty09z zfS+~1JVYzzL8{5`cEC?N;7x!hpC8M=2k{|{h&R4o5zfLA%- zM*#Oa;Ku=HkB;HwsSXJTEhb|1x0Lm>9ed@Cy$3 z4Zx3F7|VYfu-s6WNh#tzz|CW0`3C?$>3|ObP8b)<=Z5L`959dm#Q0dg0eHFtcDt-R zjQbdGh;BK;XCdD^S*2+5MBK_%_!l7G8sB)dk`LHA&&IilxD>E8zA?WNu=W1HhNq}w zzB&GDVyIXHSY&f7#qKBiQzs(Ub}->P0b2(PgnvRr({WhX;(&dCUk1Dp<27G_LtH81 zJA8MV?-L*1FHz(d0VdgCjMoPcu}(6`{}aI0K0RTcPg&dagi`=}OnzzLcNY1Zj{1xR z%o8Jve*_Wh{W=8i*Nc#EZLpJH0pL#a{Xl&y09yw!%&!J)xzUKU0p@`d%SZiJ1GYB* ziGK@VYqOki7vO7w?=$i525i}b`aeL}bUuXt>3~_D?SOgDfNrpBnD`xF=eOMd)Cd2A zKCsaTJ_m|hXFk-Ahjx~uJf7j)pC!aH#F;-A@LDNfljW`IgP#riZs4E@mj-)$AM$wA zMo0QO;B!7hGJbo0c^~?30FKq?aIqe+b-+gY+W~(c`p~g{9sq0|q%i;IfO*n~K)W)p1>oYkI8%#@KMOe6h5ZnF)4?STt0|AX%Zi#m_&+6q?kmCNu-!WihNS! zlOmrK`J~7vMLsF=Ns&*Ad{X3-VlpWvlVUO{CX-?^DJGL*GASmLVlpWvlcInW1*9k- zMFA-aNKrtF0#X!^qJR_yq$ngsAt?$;fdfN4NKr_NLQ)ixqL37Yq?keqR0AHQm_mvv zq?kgADWsS}iYcU+LW-%Rm`aMNc_%NJ{Qj9$#q-LzsP|)!A-;C7OH{gKe(}8W8Syz- zhqiM`j3unUY_`c^b}9A`W>qXGDX#D@m^pJ{S+yTKWY}&2qWqH#bsb^ZP8`d;ezsk> zKT%X<{k4YE{apr}k7Qw;=Wna?hnm8zE3#@=3!HglW5N1CmfG5Jt}@lS&>yI;3DuZ? zL?R|ISKz$gxr+4rPm)o;+TP5F|Kk%5Hux(O*3M(x>Qb#O9b0mKs-gb01Pm4TcP98J zFk&oW3V(e^(BD+kTF<{pfz`F#5mSFIgMTB#iL3rlhBM`)KaAnbloerbeaTh3Guu&v z?7r6ioc!|~F+29W>(t-sh^15W+KvvhkZNz>WUJP!w%6fucY=FVxQihT#Xm1l)t=MnL zDlRFX7^-PBAsoeJ)rOn#7h;<0MHZo^nvN!sRllYc{8R}2We$E?*nwXI#sPlhwFg>= zuOe+NA(16*n}ujrV-R478&6prT7eUk%{42~WDcfH^iw$hO+YzU(l*2g#{RN0yj(BwI;Vr!Tktn^)Q4iXLxOc!?ctsFK&pgXfH~R0xTX>wC z(f^mdCW+Df$brW>GrheuN1mnMPfa}9g>yUlassBa@E!q7xy*9@%_tMi=JzWH9{0BB zkM+avS>RztCEEhmIQ&~umMrpQocG_C*kq zUycbAFVl=OU>^N(GejWWgd){WO;F-6o(yE-Tdt)@h#yc9(^+}L`rr*L#~y~GJ}kU3 zeefQii?s>bmgOwGTocbK$6l0~x1B9VJj*-8h$|Okt&hDlAM&q*r=8Q_+1F@0%Z;nW Xm7IR$avRHucWEOo>Qa#Dtmyv$U6gp6 diff --git a/disk-images/eightball.d64 b/disk-images/eightball.d64 index cd96f39ca6ecb3d6879dc70541e39ae8a372d87f..2ca0f91f6b0fc161559aea13ab3f9a4c65383eda 100644 GIT binary patch delta 16836 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 CiMr(g diff --git a/disk-images/eightball.dsk b/disk-images/eightball.dsk index bf69b707dce8f1bd6f103c660866a0699fb10f0d..d2e4a97e9f4670e97f710cc5dd9d98282a6dcfe0 100644 GIT binary patch delta 8659 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 b`M1`fd-?mHMQQ1qzVO8_?b;PwhkpJ4TWn^y delta 8742 zcmcIp4RjP$maf;GpQe+L1QOHv5nc#sNGGAwsfr*VAxMS*jeyFiXU5%TcH;(SbaWlv zUB|Os1S(bU#IRd*6NcefPd9{-S}uXz1^pll97Cwt!*YXE43-9h+11o#>N) zWf*#+V-_^jHZE(}asQUaEz26WtY=a_W)L%sv{r_h5L>$LfqNV8+`7JziTPkF_Ys|7%K#mWG4Ghn_%Z3^K3)b=rFnj|0kOP>ZiD%Eei0%! zlCN%3SR7dtkRe(Ym#IdaQKm9oyo@^G{{f!t45tk8q_^LoFn;`><@`qqD#3n z>5wvpoG`d0i_8IdB8wOSUdbXE09A8ICcyJ^NfyATbIDwQo!KNC;Pq^h1F$NG;yvj$D!l@MbQ_2l&oBatnZC9w`9mnMX_jhWVrr;KBK%DD2eRee+2%{Jb`w zlmJ-s$gQ+7k1PQA=RC3yU@VVdfQ|X26yQicSp-1xNg2TB`D8J`-`qmV0p7fYm;vew z$P$2)1!O5efr(TAJZK^o0AeDQ0Ck0=Dy+ZFeq0%U7I$;_Y%R_+DWq(x_S2kUj;B3{h=iX@6xH;?dYp*}xpXw=Ra?VJ0mF;U(HiIs9 zvUY%Vsi@ToAGo_cNp0e4YW0cpWU{5Zs=8Wb%s}bO<+EA;|2MuVaqT>_x@vZ1 zv_N<%9qIMxWUTO(wq>I7`7@Nz@xmPV*f}-U6Sv1C1<-moev&8(qYtBXZ}KjjSw4D% znCw9#O)IX2?zSF<*_u2`d^Zk?UHc|DJkhMUKx~Jbn!AN=S96chqe)BcS*T$*9Dous zC@!`Ix`jZXM+j191cdHDQ0P&0T34@bv?tIV?1|c$luzRm7lLrM2qbw@J5ost=Ar^; zVzP|JU82R4j=9dUtQ!txJ)?56D-!y3!>oI*du&M6PJhzNb5Xrhpr^m7laIO)<|yoI z6IM*+yXe_)`d*pT9c@dQy`TWsXj(>{v&9k0;#^NdSr)Wu z*=9PfPjh@C-Al)Gs1!J3Sci(MVHh{?AJ6Uobfer}Jx%w9WZenDC~Ys+URTs#E_5bt-}uT6ioJo>;9lHU z)8(S8=bE6WNv9+Xm%M`}g?3FdE4kKm(ziKrz47T@{f0A9LLyp;|F-(iOncJKzen=V zXqe(Qfnc+g7d3g3wIfvzJ}Tm_CS^td@ir!q%9+_{`MjCW2`z>Dv%ZV3+t zyhkcI|E5j&zn3UZ#?#I@ROT1UIQyMT-EK}juORzoPGvy0&%#CYuOA$8D2&YH@`887 zmCJ_$Ui+nTrS`%xHZtejx$u}ePhlKqe!{{P=8k*Kns>kphl7&ljNl;vIdgy?$>o#R z#Gx$;T}wz)&>ks-b$A=zB&tZx!HNxEEr-QSAxtEBF8|WU(K&m^O~@LQO8XGNBfS2!Hq^V7SwjTqI`% z{)VylQ#BPoYO$x4`T6fgie3>zwoy$LKj@{kC%km03X}~ zp7VIPKvzXhq*^hY*~uO40OyaX!%8|hAA1YQhOhye`AD|90UY1c*@U-Mx7bgV_jH2q zCGS0`sOB>kLaeuMjBRf3&wTAFyj47Zh4rRIQdB17IQ1FZ<~lXTw(URg8S5Tn?L(Em zAHIXLo~j&hxj$z`xL#v@&%a~JIY*y-!H&T7OV)m_QnKES)))nkE3&MugSzD1I#ih9 z>hz2R_S1{!@NLME3$949!zGno(%>RJb{l#;_Zlm>`aWlc{dN-^;RakQd~4pVHh#ed z_S3;%tdOdfqx$Tl6#=R;`tWFl^we@xo_>w~{+yLM?nRB8ps@pbI7R{kVug;z%I}s$ zQs6!%cApNT!y9ggnuA{|SI0wIFlCp+HqL+uNQZ@asXXMcSC#wz@j|8ZGdA4(+87&l zfZorjo-wxX3sw-bzGNfo`o3go-N~^oZdOl~NqX*`tGJ>bV z5XlPEp?Xwx_z(>v8q@d>R;lQAw5sv@7MRprV(2#-jlDDibtZ?J zzQUoAO#^-rj%5QPu|`()Jv$V>t*>SX0!)iD59jIN)K?X{r=@3aN3~7?UI}&beuumc z7A?+{6-aY%8aViBrx|_Y$ck@!Tvj;5iw1u6(~GMO^>az%5;j+mA6-#sRaz|v&}VFFiRI#qWop{ ztrn1Uw{t5)4jDXn``c{9NH?n~eA&LU#&6p7mcn|`hYt5MoJW*au0m_JLZH|mwaAPM z+%f{My;JbtRb3npr;~AbRl2k0g=e^Z;tL|T4`KwABNaF(AO_nVpd}PB;MQu;2?N#hVpkl zZB`ijgBJJ)4GIHIH zKn~IjB*hdk51+M3_B&9a6WA}KEa5r4+Dd^e2A8+3@L}NMWw zbfE^TR`|+bR2Xl@AP>pwX|ueOhYt^O4R9(LuUVijrsKn`!MPLOrN5*8b!L>|0~Tzw z#oe9Y_~_JV|3QA!BK#YxnvIJW)4p)l!B5(>-Nl5Bw51K+xZh_}pVnTy$3-HG)Pvds zDj~sL2ukcT_`bx^ELB)TOQ3fAlW8Wjf@7>@$h|eyj zxgTDpgd*?oTat_1Bz<78_Wg4ME$WIFYtn+u>#@@?dK}8gA;YKw7yKMJ24Zf=s(I&k zN-d7G&~hqmqC~RG84!rRm*33O!FItmR8T#o7E)|lb@7CmR(qOkm!DQp{@7z*@f(XE zqczdh7WNMELTd}`2H#z8*rX8~Dk*8M>AyR48mc7}X>!%1%IEA)*1%qG=Y#{o;d-=6 zmsT$ENVl*7@;q!($n^H+C6t1JCfphY2VBAZZZGHQ6WJ(b8Z8nj`JmjEV~_oI|Uweh<}^$_uQ+Qde5{43|~sL%Q=NIh-e# za~E(P6DOV?A9t5V0doh+IO(VzRp&pzc@A)NgmmCr<^Ys%XobV~*oRflD{NrTC4>7a z>yQmV(N?9-4h*dnzQ`Zl4JFAH_-6Hq{^&khoxH#d4co&7eLox`D4e6VC}#Ik&Qk%b zrwoNt0*?oOB=Bu}lx*#b7nZoHJ;U%%T`t!N&+U6&!^8U|m63lf{NP6wYnUC6JpP34 z(MJz&L1*>ft7d$|mkOP4vG1_&vd1|39~1j?zv}U(eBc>v6~n(5L`a?RsS+~8zggmU zuTI>Z0kWWNLx6%uD_`)NHjS+@EaG2ki>Qn2aMdiP%egj^55=$gD=j_tuUB6$jNYw+ z6f6HbEOO8l*zf7$+&<2C;NqeMM{3|4kyZ|iMZ 0) { + print("WARNING: evalptr "); + printdec(evalptr); + printchar('\n'); + } +#ifdef __GNUC__ + exit(0); +#else + for (tempword = 0; tempword < 25000; ++tempword); + exit(0); +#endif +} + +/* + * Pushes the following 16 bit word to the evaluation stack + */ +void vm_ldimm() { + ++evalptr; + CHECKOVERFLOW(); + wordptr = (unsigned short *)&MEM(++pc); + XREG = *wordptr; + pc += 2; +} + +/* + * Replaces X with 16 bit value pointed to by X + */ +void vm_ldaword() { + CHECKUNDERFLOW(1); + wordptr = (unsigned short *)&MEM(XREG); + XREG = *wordptr; + ++pc; +} + +/* + * Imm mode - push 16 bit value pointed to by addr after opcode + */ +void vm_ldawordimm() { + ++evalptr; + CHECKOVERFLOW(); + wordptr = (unsigned short *)&MEM(++pc); /* Pointer to operand */ + wordptr = (unsigned short *)&MEM(*wordptr); /* Pointer to variable */ + XREG = *wordptr; + pc += 2; +} + +/* + * Replaces X with 8 bit value pointed to by X + */ +void vm_ldabyte() { + CHECKUNDERFLOW(1); + XREG = MEM(XREG); + ++pc; +} + +/* + * Imm mode - push byte pointed to by addr after opcode + */ +void vm_ldabyteimm() { + ++evalptr; + CHECKOVERFLOW(); + wordptr = (unsigned short *)&MEM(++pc); /* Pointer to operand */ + byteptr = (unsigned char *)&MEM(*wordptr); /* Pointer to variable */ + XREG = *byteptr; + pc += 2; +} + +/* + * Stores 16 bit value Y in addr pointed to by X. Drops X and Y + */ +void vm_staword() { + CHECKUNDERFLOW(2); + wordptr = (unsigned short *)&MEM(XREG); + *wordptr = YREG; + evalptr -= 2; + ++pc; +} + +/* + * Imm mode - store 16 bit value X in addr after opcode. Drop X + */ +void vm_stawordimm() { + CHECKUNDERFLOW(1); + wordptr = (unsigned short *)&MEM(++pc); /* Pointer to operand */ + wordptr = (unsigned short *)&MEM(*wordptr); /* Pointer to variable */ + *wordptr = XREG; + --evalptr; + pc += 2; +} + +/* + * Stores 8 bit value Y in addr pointed to by X. Drops X and Y + */ +void vm_stabyte() { + CHECKUNDERFLOW(2); + MEM(XREG) = YREG; + evalptr -= 2; + ++pc; +} + +/* + * Imm mode - store 8 bit value X in addr after opcode. Drop X + */ +void vm_stabyteimm() { + CHECKUNDERFLOW(1); + wordptr = (unsigned short *)&MEM(++pc); /* Pointer to operand */ + byteptr = (unsigned char *)&MEM(*wordptr); /* Pointer to variable */ + *byteptr = XREG; + --evalptr; + pc += 2; +} + + +/* + * Replaces X with 16 bit value pointed to by X + */ +void vm_ldrword() { + CHECKUNDERFLOW(1); +#ifdef __GNUC__ + wordptr = (unsigned short *)&MEM((XREG + fp + 1) & 0xffff); +#else + tempword = XREG + fp + 1; + wordptr = (unsigned short *)&MEM(tempword); +#endif + XREG = *wordptr; + ++pc; +} + +/* + * Imm mode - push 16 bit value pointed to by addr after opcode + */ +void vm_ldrwordimm() { + ++evalptr; + CHECKOVERFLOW(); + wordptr = (unsigned short *)&MEM(++pc); /* Pointer to operand */ +#ifdef __GNUC__ + wordptr = (unsigned short *)&MEM((*wordptr + fp + 1) & 0xffff); /* Pointer to variable */ +#else + tempword = *wordptr + fp + 1; + wordptr = (unsigned short *)&MEM(tempword); /* Pointer to variable */ +#endif + XREG = *wordptr; + pc += 2; +} + +/* + * Replaces X with 8 bit value pointed to by X. + */ +void vm_ldrbyte() { + CHECKUNDERFLOW(1); +#ifdef __GNUC__ + XREG = MEM((XREG + fp + 1) & 0xffff); +#else + XREG = MEM(XREG + fp + 1); +#endif + ++pc; +} + +/* + * Imm mode - push byte pointed to by addr after opcode + */ +void vm_ldrbyteimm() { + ++evalptr; + CHECKOVERFLOW(); + wordptr = (unsigned short *)&MEM(++pc); /* Pointer to operand */ +#ifdef __GNUC__ + byteptr = (unsigned char *)&MEM((*wordptr + fp + 1) & 0xffff); /* Pointer to variable */ +#else + tempword = *wordptr + fp + 1; + byteptr = (unsigned char *)&MEM(tempword); /* Pointer to variable */ +#endif + XREG = *byteptr; + pc += 2; +} + +/* + * Stores 16 bit value Y in addr pointed to by X. Drops X and Y + */ +void vm_strword() { + CHECKUNDERFLOW(2); +#ifdef __GNUC__ + wordptr = (unsigned short *)&MEM((XREG + fp + 1) & 0xffff); +#else + tempword = XREG + fp + 1; + wordptr = (unsigned short *)&MEM(tempword); +#endif + *wordptr = YREG; + evalptr -= 2; + ++pc; +} + +/* + * Imm mode - store 16 bit value X in addr after opcode. Drop X + */ +void vm_strwordimm() { + CHECKUNDERFLOW(1); + wordptr = (unsigned short *)&MEM(++pc); /* Pointer to operand */ +#ifdef __GNUC__ + wordptr = (unsigned short *)&MEM((*wordptr + fp + 1) & 0xffff); /* Pointer to variable */ +#else + tempword = *wordptr + fp + 1; + wordptr = (unsigned short *)&MEM(tempword); /* Pointer to variable */ +#endif + *wordptr = XREG; + --evalptr; + pc += 2; +} + +/* + * Stores 8 bit value Y in addr pointed to by X. Drops X and Y + */ +void vm_strbyte() { + CHECKUNDERFLOW(2); +#ifdef __GNUC__ + MEM((XREG + fp + 1) & 0xffff) = YREG; +#else + tempword = XREG + fp + 1; + MEM(tempword) = YREG; +#endif + evalptr -= 2; + ++pc; +} + +/* + * Imm mode - store 8 bit value X in addr after opcode. Drop X + */ +void vm_strbyteimm() { + CHECKUNDERFLOW(1); + wordptr = (unsigned short *)&MEM(++pc); /* Pointer to operand */ +#ifdef __GNUC__ + byteptr = (unsigned char *)&MEM((*wordptr + fp + 1) & 0xffff); /* Pointer to variable */ +#else + tempword = *wordptr + fp + 1; + byteptr = (unsigned char *)&MEM(tempword); /* Pointer to variable */ +#endif + *byteptr = XREG; + --evalptr; + pc += 2; +} + +/* + * Swaps X and Y + */ +void vm_swap() { + CHECKUNDERFLOW(2); + tempword = XREG; + XREG = YREG; + YREG = tempword; + ++pc; +} + +/* + * Duplicates X -> X, Y + */ +void vm_dup() { + CHECKUNDERFLOW(1); + ++evalptr; + CHECKOVERFLOW(); + XREG = YREG; + ++pc; +} + +/* + * Duplicates X -> X,Z; Y -> Y,T + */ +void vm_dup2() { + CHECKUNDERFLOW(2); + evalptr += 2; + CHECKOVERFLOW(); + XREG = ZREG; + YREG = TREG; + ++pc; +} + +/* + * Drops X + */ +void vm_drop() { + CHECKUNDERFLOW(1); + --evalptr; + ++pc; +} + +/* + * Duplicates Y -> X,Z + */ +void vm_over() { + CHECKUNDERFLOW(2); + ++evalptr; + CHECKOVERFLOW(); + XREG = ZREG; + ++pc; +} + +/* + * Duplicates stack level specified in X+1 -> X + */ +void vm_pick() { + CHECKUNDERFLOW(XREG + 1); + XREG = evalstack[evalptr - (XREG + 1)]; + ++pc; +} + +/* + * Pop 16 bit value from call stack, push onto eval stack [X] + */ +void vm_popword() { + CHECKSTACKUNDERFLOW(2); + sp += 2; + ++evalptr; + CHECKOVERFLOW(); +#ifdef __GNUC__ + wordptr = (unsigned short *)&MEM(sp - 1); +#else + tempword = sp - 1; + wordptr = (unsigned short *)&MEM(tempword); +#endif + XREG = *wordptr; + ++pc; +} + +/* + * Pop 8 bit value from call stack, push onto eval stack [X] + */ +void vm_popbyte() { + CHECKSTACKUNDERFLOW(1); + ++sp; + ++evalptr; + CHECKOVERFLOW(); + XREG = MEM(sp); + ++pc; +} + +/* + * Push 16 bit value in X onto call stack. Drop X + */ +void vm_pshword() { + CHECKUNDERFLOW(1); + byteptr = (unsigned char *)&XREG; + MEM(sp--) = *(byteptr + 1); + CHECKSTACKOVERFLOW(); + MEM(sp--) = *byteptr; + CHECKSTACKOVERFLOW(); + --evalptr; + ++pc; +} + +/* + * Push 8 bit value in X onto call stack. Drop X + */ +void vm_pshbyte() { + CHECKUNDERFLOW(1); + MEM(sp--) = XREG & 0x00ff; + CHECKSTACKOVERFLOW(); + --evalptr; + ++pc; +} + +/* + * Discard X bytes from call stack. Drop X + */ +void vm_discard() { + CHECKUNDERFLOW(1); + sp += XREG; + --evalptr; + ++pc; +} + +/* + * Copy stack pointer to frame pointer. (Enter function scope) + */ +void vm_sptofp() { + /* Push old FP to stack */ + byteptr = (unsigned char *)&fp; + MEM(sp--) = *(byteptr + 1); + CHECKSTACKOVERFLOW(); + MEM(sp--) = *byteptr; + CHECKSTACKOVERFLOW(); + fp = sp; + ++pc; +} + +/* + * Copy frame pointer to stack pointer. (Release local vars) + */ +void vm_fptosp() { + sp = fp; + /* Pop old FP from stack -> FP */ + CHECKSTACKUNDERFLOW(2); + sp += 2; + CHECKOVERFLOW(); +#ifdef __GNUC__ + wordptr = (unsigned short *)&MEM(sp - 1); +#else + tempword = sp - 1; + wordptr = (unsigned short *)&MEM(tempword); +#endif + fp = *wordptr; + ++pc; +} + +/* + * Convert absolute address in X to relative address + */ +void vm_ator() { +#ifdef __GNUC__ + XREG = (XREG - fp - 1) & 0xffff; +#else + XREG = XREG - fp - 1; +#endif + ++pc; +} + +/* + * Convert relative address in X to absolute address + */ +void vm_rtoa() { +#ifdef __GNUC__ + XREG = (XREG + fp + 1) & 0xffff; +#else + XREG = XREG + fp + 1; +#endif + ++pc; +} + +/* + * X = X+1 + */ +void vm_inc() { + CHECKUNDERFLOW(1); + ++XREG; + ++pc; +} + +/* + * X = X-1 + */ +void vm_dec() { + CHECKUNDERFLOW(1); + --XREG; + ++pc; +} + +/* + * X = Y+X. Y is dropped + */ +void vm_add() { + CHECKUNDERFLOW(2); + YREG = YREG + XREG; + --evalptr; + ++pc; +} + +/* + * X = Y-X. Y is dropped + */ +void vm_sub() { + CHECKUNDERFLOW(2); + YREG = YREG - XREG; + --evalptr; + ++pc; +} + +/* + * X = Y*X. Y is dropped + */ +void vm_mul() { + CHECKUNDERFLOW(2); + YREG = YREG * XREG; + --evalptr; + ++pc; +} + +/* + * X = Y/X. Y is dropped + */ +void vm_div() { + CHECKUNDERFLOW(2); + YREG = YREG / XREG; + --evalptr; + ++pc; +} + +/* + * X = Y%X. Y is dropped + */ +void vm_mod() { + CHECKUNDERFLOW(2); + YREG = YREG % XREG; + --evalptr; + ++pc; +} + +/* + * X = -X + */ +void vm_neg() { + CHECKUNDERFLOW(1); + XREG = -XREG; + ++pc; +} + +/* + * X = Y>X. Y is dropped + */ +void vm_gt() { + CHECKUNDERFLOW(2); + YREG = YREG > XREG; + --evalptr; + ++pc; +} + +/* + * X = Y>=X. Y is dropped + */ +void vm_gte() { + CHECKUNDERFLOW(2); + YREG = YREG >= XREG; + --evalptr; + ++pc; +} + +/* + * X = Y>X. Y is dropped + */ +void vm_rsh() { + CHECKUNDERFLOW(2); + YREG = YREG >> XREG; + --evalptr; + ++pc; +} + +/* + * Jump to address X. Drop X + */ +void vm_jmp() { + CHECKUNDERFLOW(1); + pc = XREG; + --evalptr; +} + +/* + * Imm mode - jump to 16 bit word following opcode + */ +void vm_jmpimm() { + wordptr = (unsigned short *)&MEM(++pc); + pc = *wordptr; +} + +/* + * If Y!= 0, jump to address X. Drop X, Y + */ +void vm_brnch() { + CHECKUNDERFLOW(2); + if (YREG) { + pc = XREG; + } else { + ++pc; + } + evalptr -= 2; +} + +/* + * Imm mode - if X!=0 branch to 16 bit word following opcode + */ +void vm_brnchimm() { + wordptr = (unsigned short *)&MEM(++pc); + CHECKUNDERFLOW(1); + if (XREG) { + pc = *wordptr; + } else { + pc += 2; + } + --evalptr; +} + +/* + * Push PC to call stack. Jump to address X. Drop X + */ +void vm_jsr() { + CHECKUNDERFLOW(1); + byteptr = (unsigned char *) &pc; + MEM(sp) = *(byteptr + 1); + --sp; + CHECKSTACKOVERFLOW(); + MEM(sp) = *byteptr; + --sp; + CHECKSTACKOVERFLOW(); + pc = XREG; + --evalptr; +} + +/* + * Imm mode - push PC to call stack, jump to 16 bit word + */ +void vm_jsrimm() { + wordptr = (unsigned short *)&MEM(++pc); + ++pc; + byteptr = (unsigned char *) &pc; + MEM(sp) = *(byteptr + 1); + --sp; + CHECKSTACKOVERFLOW(); + MEM(sp) = *byteptr; + --sp; + CHECKSTACKOVERFLOW(); + pc = *wordptr; +} + +/* + * Pop call stack, jump to the address popped + */ +void vm_rts() { + CHECKSTACKUNDERFLOW(2); + ++sp; + wordptr = (unsigned short *)&MEM(sp); + pc = *wordptr; + ++sp; + ++pc; +} + +/* + * Print 16 bit decimal in X. Drop X + */ +void vm_prdec() { + CHECKUNDERFLOW(1); + printdec(XREG); + --evalptr; + ++pc; +} + +/* + * Print 16 bit hex in X. Drop X + */ +void vm_prhex() { + CHECKUNDERFLOW(1); + printhex(XREG); + --evalptr; + ++pc; +} + +/* + * Print character in X. Drop X + */ +void vm_prch() { + CHECKUNDERFLOW(1); + printchar((unsigned char) XREG); + --evalptr; + ++pc; +} + +/* + * Print null terminated string pointed to by X. Drop X + */ +void vm_prstr() { + CHECKUNDERFLOW(1); + while (MEM(XREG)) { + printchar(MEM(XREG++)); + } + --evalptr; + ++pc; +} + +/* + * Print literal string at PC (null terminated) + */ +void vm_prmsg() { + ++pc; + while (MEM(pc)) { + printchar(MEM(pc++)); + } + ++pc; +} + +/* + * Push character from keyboard onto eval stack + */ +void vm_kbdch() { + CHECKUNDERFLOW(1); + ++evalptr; + /* Loop until we get a keypress */ +#ifdef A2E + while (!(XREG = getkey())); +#elif defined(CBM) + while (!(*(char *) XREG = cbm_k_getin())); +#else + /* TODO: Unimplemented in Linux */ + XREG = 0; +#endif + ++pc; +} + +/* + * Obtain line from keyboard and write to memory pointed to by + * Y. X contains the max number of bytes in buf. Drop X, Y + */ +void vm_kbdln() { + CHECKUNDERFLOW(2); + getln((char *) &MEM(YREG), XREG); + evalptr -= 2; + ++pc; +} + +typedef void (*func)(void); + +/* + * Must be in same order as enum bytecode. + */ +func jumptbl[] = { +vm_end, +vm_ldimm, +vm_ldaword, +vm_ldawordimm, +vm_ldabyte, +vm_ldabyteimm, +vm_staword, +vm_stawordimm, +vm_stabyte, +vm_stabyteimm, +vm_ldrword, +vm_ldrwordimm, +vm_ldrbyte, +vm_ldrbyteimm, +vm_strword, +vm_strwordimm, +vm_strbyte, +vm_strbyteimm, +vm_swap, +vm_dup, +vm_dup2, +vm_drop, +vm_over, +vm_pick, +vm_popword, +vm_popbyte, +vm_pshword, +vm_pshbyte, +vm_discard, +vm_sptofp, +vm_fptosp, +vm_ator, +vm_rtoa, +vm_inc, +vm_dec, +vm_add, +vm_sub, +vm_mul, +vm_div, +vm_mod, +vm_neg, +vm_gt, +vm_gte, +vm_lt, +vm_lte, +vm_eql, +vm_neql, +vm_and, +vm_or, +vm_not, +vm_bitand, +vm_bitor, +vm_bitxor, +vm_bitnot, +vm_lsh, +vm_rsh, +vm_jmp, +vm_jmpimm, +vm_brnch, +vm_brnchimm, +vm_jsr, +vm_jsrimm, +vm_rts, +vm_prdec, +vm_prhex, +vm_prch, +vm_prstr, +vm_prmsg, +vm_kbdch, +vm_kbdln}; + /* * Fetch, decode and execute a VM instruction. * Advance program counter and loop until VM_END. */ void execute() { - unsigned short d; #ifdef DEBUGREGS unsigned short i; #endif @@ -270,8 +1171,6 @@ void execute() while (1) { -nextinstr: - //print("--->PC "); printhex(pc); print(" eval stk: "); printhex(evalptr); print("\n"); #ifdef DEBUGREGS print("\n"); @@ -356,597 +1255,8 @@ nextinstr: #endif #endif - switch (MEM(pc)) { - /* - * Miscellaneous - */ - case VM_END: /* Terminate execution */ - if (evalptr > 0) { - print("WARNING: evalptr "); - printdec(evalptr); - printchar('\n'); - } -#ifdef __GNUC__ - exit(0); -#else - for (d = 0; d < 25000; ++d); - exit(0); -#endif - break; + jumptbl[MEM(pc)](); - /* - * Load Immediate - */ - case VM_LDIMM: /* Pushes the following 16 bit word to the evaluation stack */ - ++evalptr; - CHECKOVERFLOW(); - wordptr = (unsigned short *)&MEM(++pc); - ++pc; - XREG = *wordptr; - break; - /* - * Absolute addressing: - * XREG points to absolute address within system memory. - */ - case VM_LDAWORD: /* Replaces X with 16 bit value pointed to by X. */ - CHECKUNDERFLOW(1); - -#ifdef DEBUGADDRESSING - print("\n XREG: "); - printhex(XREG); - printchar('\n'); -#endif - - wordptr = (unsigned short *)&MEM(XREG); - XREG = *wordptr; - break; - case VM_LDAWORDIMM: /* Imm mode - push 16 bit value pointed to by addr after opcode */ - ++evalptr; - CHECKOVERFLOW(); - wordptr = (unsigned short *)&MEM(++pc); /* Pointer to operand */ - wordptr = (unsigned short *)&MEM(*wordptr); /* Pointer to variable */ - ++pc; - XREG = *wordptr; - break; - case VM_LDABYTE: /* Replaces X with 8 bit value pointed to by X. */ - CHECKUNDERFLOW(1); - XREG = MEM(XREG); - break; - case VM_LDABYTEIMM: /* Imm mode - push byte pointed to by addr after opcode */ - ++evalptr; - CHECKOVERFLOW(); - wordptr = (unsigned short *)&MEM(++pc); /* Pointer to operand */ - byteptr = (unsigned char *)&MEM(*wordptr); /* Pointer to variable */ - ++pc; - XREG = *byteptr; - break; - case VM_STAWORD: /* Stores 16 bit value Y in addr pointed to by X. Drops X and Y.*/ - CHECKUNDERFLOW(2); - wordptr = (unsigned short *)&MEM(XREG); - *wordptr = YREG; - evalptr -= 2; - break; - case VM_STAWORDIMM: /* Imm mode - store 16 bit value X in addr after opcode. Drop X.*/ - CHECKUNDERFLOW(1); - wordptr = (unsigned short *)&MEM(++pc); /* Pointer to operand */ - wordptr = (unsigned short *)&MEM(*wordptr); /* Pointer to variable */ - ++pc; - *wordptr = XREG; - --evalptr; - break; - case VM_STABYTE: /* Stores 8 bit value Y in addr pointed to by X. Drops X and Y. */ - CHECKUNDERFLOW(2); - MEM(XREG) = YREG; - evalptr -= 2; - break; - case VM_STABYTEIMM: /* Imm mode - store 8 bit value X in addr after opcode. Drop X.*/ - CHECKUNDERFLOW(1); - wordptr = (unsigned short *)&MEM(++pc); /* Pointer to operand */ - byteptr = (unsigned char *)&MEM(*wordptr); /* Pointer to variable */ - ++pc; - *byteptr = XREG; - --evalptr; - break; - /* - * Relative to Frame Pointer addressing: - * XREG points to address in system memory relative to the frame pointer. - */ - case VM_LDRWORD: /* Replaces X with 16 bit value pointed to by X. */ - CHECKUNDERFLOW(1); - -#ifdef DEBUGADDRESSING - print("\n XREG: "); - printhex(XREG); - print(", FP: "); - printhex(fp); - print(" -> "); - printhex((XREG + fp + 1) & 0xffff); - printchar('\n'); -#endif - -#ifdef __GNUC__ - wordptr = (unsigned short *)&memory[(XREG + fp + 1) & 0xffff]; -#else - wordptr = (unsigned short *)&memory[XREG + fp + 1]; -#endif - XREG = *wordptr; - break; - case VM_LDRWORDIMM: /* Imm mode - push 16 bit value pointed to by addr after opcode */ - ++evalptr; - CHECKOVERFLOW(); - wordptr = (unsigned short *)&MEM(++pc); /* Pointer to operand */ -#ifdef __GNUC__ - wordptr = (unsigned short *)&memory[(*wordptr + fp + 1) & 0xffff]; /* Pointer to variable */ -#else - wordptr = (unsigned short *)&memory[*wordptr + fp + 1]; /* Pointer to variable */ -#endif - ++pc; - XREG = *wordptr; - break; - case VM_LDRBYTE: /* Replaces X with 8 bit value pointed to by X. */ - CHECKUNDERFLOW(1); - -#ifdef DEBUGADDRESSING - print("\n XREG: "); - printhex(XREG); - print(", FP: "); - printhex(fp); - print(" -> "); - printhex((XREG + fp + 1) & 0xffff); - printchar('\n'); -#endif - -#ifdef __GNUC__ - XREG = MEM((XREG + fp + 1) & 0xffff); -#else - XREG = MEM(XREG + fp + 1); -#endif - break; - case VM_LDRBYTEIMM: /* Imm mode - push byte pointed to by addr after opcode */ - ++evalptr; - CHECKOVERFLOW(); - wordptr = (unsigned short *)&MEM(++pc); /* Pointer to operand */ -#ifdef __GNUC__ - byteptr = (unsigned char *)&memory[(*wordptr + fp + 1) & 0xffff]; /* Pointer to variable */ -#else - byteptr = (unsigned char *)&memory[*wordptr + fp + 1]; /* Pointer to variable */ -#endif - ++pc; - XREG = *byteptr; - break; - case VM_STRWORD: /* Stores 16 bit value Y in addr pointed to by X. Drops X and Y. */ - CHECKUNDERFLOW(2); -#ifdef __GNUC__ - wordptr = (unsigned short *)&memory[(XREG + fp + 1) & 0xffff]; -#else - wordptr = (unsigned short *)&memory[XREG + fp + 1]; -#endif - *wordptr = YREG; - evalptr -= 2; - break; - case VM_STRWORDIMM: /* Imm mode - store 16 bit value X in addr after opcode. Drop X.*/ - CHECKUNDERFLOW(1); - wordptr = (unsigned short *)&MEM(++pc); /* Pointer to operand */ -#ifdef __GNUC__ - wordptr = (unsigned short *)&memory[(*wordptr + fp + 1) & 0xffff]; /* Pointer to variable */ -#else - wordptr = (unsigned short *)&memory[*wordptr + fp + 1]; /* Pointer to variable */ -#endif - ++pc; - *wordptr = XREG; - --evalptr; - break; - case VM_STRBYTE: /* Stores 8 bit value Y in addr pointed to by X. Drops X and Y. */ - CHECKUNDERFLOW(2); -#ifdef __GNUC__ - memory[(XREG + fp + 1) & 0xffff] = YREG; -#else - memory[XREG + fp + 1] = YREG; -#endif - evalptr -= 2; - break; - case VM_STRBYTEIMM: /* Imm mode - store 8 bit value X in addr after opcode. Drop X.*/ - CHECKUNDERFLOW(1); - wordptr = (unsigned short *)&MEM(++pc); /* Pointer to operand */ -#ifdef __GNUC__ - byteptr = (unsigned char *)&memory[(*wordptr + fp + 1) & 0xffff]; /* Pointer to variable */ -#else - byteptr = (unsigned char *)&memory[*wordptr + fp + 1]; /* Pointer to variable */ -#endif - ++pc; - *byteptr = XREG; - --evalptr; - break; - /* - * Manipulate evaluation stack - */ - case VM_SWAP: /* Swaps X and Y */ - CHECKUNDERFLOW(2); - d = XREG; - XREG = YREG; - YREG = d; - break; - case VM_DUP: /* Duplicates X -> X, Y */ - CHECKUNDERFLOW(1); - ++evalptr; - CHECKOVERFLOW(); - XREG = YREG; - break; - case VM_DUP2: /* Duplicates X -> X,Z; Y -> Y,T */ - CHECKUNDERFLOW(2); - evalptr += 2; - CHECKOVERFLOW(); - XREG = ZREG; - YREG = TREG; - break; - case VM_DROP: /* Drops X */ - CHECKUNDERFLOW(1); - --evalptr; - break; - case VM_OVER: /* Duplicates Y -> X,Z */ - CHECKUNDERFLOW(2); - ++evalptr; - CHECKOVERFLOW(); - XREG = ZREG; - break; - case VM_PICK: /* Duplicates stack level specified in X+1 -> X */ - CHECKUNDERFLOW(XREG + 1); - XREG = evalstack[evalptr - (XREG + 1)]; - break; - /* - * Manipulate call stack - */ - case VM_POPWORD: /* Pop 16 bit value from call stack, push onto eval stack [X] */ - CHECKSTACKUNDERFLOW(2); - sp += 2; - ++evalptr; - CHECKOVERFLOW(); - wordptr = (unsigned short *)&memory[sp - 1]; - XREG = *wordptr; - break; - case VM_POPBYTE: /* Pop 8 bit value from call stack, push onto eval stack [X] */ - CHECKSTACKUNDERFLOW(1); - ++sp; - ++evalptr; - CHECKOVERFLOW(); - XREG = MEM(sp); - break; - case VM_PSHWORD: /* Push 16 bit value in X onto call stack. Drop X. */ - CHECKUNDERFLOW(1); - -#ifdef DEBUGSTACK - print("\n Push word to "); - printhex(sp - 1); - printchar('\n'); -#endif - byteptr = (unsigned char *)&XREG; - MEM(sp--) = *(byteptr + 1); - CHECKSTACKOVERFLOW(); - MEM(sp--) = *byteptr; - CHECKSTACKOVERFLOW(); - --evalptr; - break; - case VM_PSHBYTE: /* Push 8 bit value in X onto call stack. Drop X. */ - CHECKUNDERFLOW(1); - -#ifdef DEBUGSTACK - print("\n Push byte to "); - printhex(sp); - printchar('\n'); -#endif - - MEM(sp--) = XREG & 0x00ff; - CHECKSTACKOVERFLOW(); - --evalptr; - break; - case VM_DISCARD: /* Discard X bytes from call stack. Drop X. */ - CHECKUNDERFLOW(1); - sp += XREG; - --evalptr; - break; - case VM_SPTOFP: /* Copy stack pointer to frame pointer. (Enter function scope) */ - -#ifdef DEBUGSTACK - print("\n SPTOFP FP before "); - printhex(fp); - print(" SP "); - printhex(sp); - printchar('\n'); -#endif - - /* Push old FP to stack */ - byteptr = (unsigned char *)&fp; - MEM(sp--) = *(byteptr + 1); - CHECKSTACKOVERFLOW(); - MEM(sp--) = *byteptr; - CHECKSTACKOVERFLOW(); - - fp = sp; - break; - case VM_FPTOSP: /* Copy frame pointer to stack pointer. (Release local vars) */ - -#ifdef DEBUGSTACK - print("\n FPTOSP SP before "); - printhex(sp); - print(" FP "); - printhex(fp); - printchar('\n'); -#endif - - sp = fp; - - /* Pop old FP from stack -> FP */ - CHECKSTACKUNDERFLOW(2); - sp += 2; - CHECKOVERFLOW(); - wordptr = (unsigned short *)&memory[sp - 1]; - fp = *wordptr; - -#ifdef DEBUGSTACK - print(" Recovered FP "); - printhex(fp); - print(" from stack\n"); -#endif - - break; - case VM_ATOR: /* Convert absolute address in X to relative address */ -#ifdef __GNUC__ - XREG = (XREG - fp - 1) & 0xffff; -#else - XREG = XREG - fp - 1; -#endif - break; - case VM_RTOA: /* Convert relative address in X to absolute address */ -#ifdef __GNUC__ - XREG = (XREG + fp + 1) & 0xffff; -#else - XREG = XREG + fp + 1; -#endif - break; - /* - * Integer math - */ - case VM_INC: /* X = X+1. */ - CHECKUNDERFLOW(1); - ++XREG; - break; - case VM_DEC: /* X = X-1. */ - CHECKUNDERFLOW(1); - --XREG; - break; - case VM_ADD: /* X = Y+X. Y is dropped. */ - CHECKUNDERFLOW(2); - YREG = YREG + XREG; - --evalptr; - break; - case VM_SUB: /* X = Y-X. Y is dropped. */ - CHECKUNDERFLOW(2); - YREG = YREG - XREG; - --evalptr; - break; - case VM_MUL: /* X = Y*X. Y is dropped. */ - CHECKUNDERFLOW(2); - YREG = YREG * XREG; - --evalptr; - break; - case VM_DIV: /* X = Y/X. Y is dropped. */ - CHECKUNDERFLOW(2); - YREG = YREG / XREG; - --evalptr; - break; - case VM_MOD: /* X = Y%X. Y is dropped . */ - CHECKUNDERFLOW(2); - YREG = YREG % XREG; - --evalptr; - break; - case VM_NEG: /* X = -X */ - CHECKUNDERFLOW(1); - XREG = -XREG; - break; - /* - * Comparisons - */ - case VM_GT: /* X = Y>X. Y is dropped. */ - CHECKUNDERFLOW(2); - YREG = YREG > XREG; - --evalptr; - break; - case VM_GTE: /* X = Y>=X. Y is dropped. */ - CHECKUNDERFLOW(2); - YREG = YREG >= XREG; - --evalptr; - break; - case VM_LT: /* X = Y>X. Y is dropped. */ - CHECKUNDERFLOW(2); - YREG = YREG >> XREG; - --evalptr; - break; - /* - * Flow control - */ - case VM_JMP: /* Jump to address X. Drop X. */ - CHECKUNDERFLOW(1); - pc = XREG; - --evalptr; - goto nextinstr; /* Do not advance program counter */ - case VM_JMPIMM: /* Imm mode - jump to 16 bit word following opcode */ - wordptr = (unsigned short *)&MEM(++pc); - ++pc; - pc = *wordptr; - goto nextinstr; /* Do not advance program counter */ - case VM_BRNCH: /* If Y!= 0, jump to address X. Drop X, Y. */ - CHECKUNDERFLOW(2); - if (YREG) { - pc = XREG; - } else { - ++pc; - } - evalptr -= 2; - goto nextinstr; /* Do not advance program counter */ - case VM_BRNCHIMM: /* Imm mode - if X!=0 branch to 16 bit word following opcode */ - wordptr = (unsigned short *)&MEM(++pc); - ++pc; - CHECKUNDERFLOW(1); - if (XREG) { - pc = *wordptr; - } else { - ++pc; - } - --evalptr; - goto nextinstr; /* Do not advance program counter */ - case VM_JSR: /* Push PC to call stack. Jump to address X. Drop X. */ - CHECKUNDERFLOW(1); - byteptr = (unsigned char *) &pc; - MEM(sp) = *(byteptr + 1); - --sp; - CHECKSTACKOVERFLOW(); - MEM(sp) = *byteptr; - --sp; - CHECKSTACKOVERFLOW(); - pc = XREG; - --evalptr; - goto nextinstr; /* Do not advance program counter */ - case VM_JSRIMM: /* Imm mode - push PC to calls stack, jump to 16 bit word */ - wordptr = (unsigned short *)&MEM(++pc); - ++pc; - byteptr = (unsigned char *) &pc; - MEM(sp) = *(byteptr + 1); - --sp; - CHECKSTACKOVERFLOW(); - MEM(sp) = *byteptr; - --sp; - CHECKSTACKOVERFLOW(); - pc = *wordptr; - goto nextinstr; /* Do not advance program counter */ - case VM_RTS: /* Pop call stack, jump to the address popped. */ - CHECKSTACKUNDERFLOW(2); - ++sp; - wordptr = (unsigned short *)&MEM(sp); - pc = *wordptr; - ++sp; - break; - /* - * Input / Output - */ - case VM_PRDEC: /* Print 16 bit decimal in X. Drop X */ - CHECKUNDERFLOW(1); - printdec(XREG); - --evalptr; - break; - case VM_PRHEX: /* Print 16 bit hex in X. Drop X */ - CHECKUNDERFLOW(1); - printhex(XREG); - --evalptr; - break; - case VM_PRCH: /* Print character in X. Drop X */ - CHECKUNDERFLOW(1); - printchar((unsigned char) XREG); - --evalptr; - break; - case VM_PRSTR: /* Print null terminated string pointed to by X. Drop X */ - CHECKUNDERFLOW(1); - while (MEM(XREG)) { - printchar(MEM(XREG++)); - } - --evalptr; - break; - case VM_PRMSG: /* Print literal string at PC (null terminated) */ - ++pc; - while (MEM(pc)) { - printchar(MEM(pc++)); - } - break; - case VM_KBDCH: /* Push character from keyboard onto eval stack */ - CHECKUNDERFLOW(1); - ++evalptr; - /* Loop until we get a keypress */ -#ifdef A2E - while (!(XREG = getkey())); -#elif defined(CBM) - while (!(*(char *) XREG = cbm_k_getin())); -#else - /* TODO: Unimplemented in Linux */ - XREG = 0; -#endif - break; - case VM_KBDLN: /* Obtain line from keyboard and write to memory pointed to by */ - /* Y. X contains the max number of bytes in buf. Drop X, Y. */ - CHECKUNDERFLOW(2); - getln((char *) &MEM(YREG), XREG); - evalptr -= 2; - break; - /* - * Unsupported instruction - */ - default: - UNSUPPORTED(); - break; - } - ++pc; } }; diff --git a/eightballvmzp_a2e.S b/eightballvmzp_a2e.S index 7b29ce2..ec2c94e 100644 --- a/eightballvmzp_a2e.S +++ b/eightballvmzp_a2e.S @@ -14,5 +14,6 @@ .exportzp _fp := $a5 .exportzp _wordptr := $a7 .exportzp _byteptr := $a9 -.exportzp _evalstack := $ab ; 32 bytes +.exportzp _tempword := $ab +.exportzp _evalstack := $ad ; 32 bytes