From 72e7e0e4782adda6213f91d683feb22bf5c61214 Mon Sep 17 00:00:00 2001 From: lynchaj <86925539+lynchaj@users.noreply.github.com> Date: Thu, 16 Sep 2021 19:26:53 -0400 Subject: [PATCH 1/2] Create Readme.txt --- Source/Apps/DMAmon/Readme.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 Source/Apps/DMAmon/Readme.txt diff --git a/Source/Apps/DMAmon/Readme.txt b/Source/Apps/DMAmon/Readme.txt new file mode 100644 index 00000000..1d6ab543 --- /dev/null +++ b/Source/Apps/DMAmon/Readme.txt @@ -0,0 +1 @@ +DMAmon is a program to verify operation of the Z80 MBC DMA board From f8e0fb3a6fb3f43106a4b7f9150cc248ea3c2195 Mon Sep 17 00:00:00 2001 From: Wayne Warthen Date: Mon, 20 Sep 2021 19:51:19 -0700 Subject: [PATCH 2/2] HDIAG Early Development - Initial framework. Just boots up and displays startup messages. --- Doc/ROM Applications.pdf | Bin 117558 -> 124019 bytes Doc/RomWBW Applications.pdf | Bin 142480 -> 142480 bytes Doc/RomWBW Architecture.pdf | Bin 440180 -> 440180 bytes Doc/RomWBW Disk Catalog.pdf | Bin 131009 -> 131009 bytes Doc/RomWBW Getting Started.pdf | Bin 181345 -> 181345 bytes Source/BuildShared.cmd | 1 + Source/Clean.cmd | 1 + Source/Doc/ROM_Applications.md | 2 +- Source/HDIAG/Build.cmd | 19 + Source/HDIAG/Clean.cmd | 7 + Source/HDIAG/Makefile | 20 + Source/HDIAG/acia.asm | 70 + Source/HDIAG/asci.asm | 89 ++ Source/HDIAG/hdiag.asm | 588 ++++++++ Source/HDIAG/hdiag_old.asm | 2543 ++++++++++++++++++++++++++++++++ Source/HDIAG/sio.asm | 108 ++ Source/HDIAG/uart.asm | 106 ++ Source/HDIAG/util.asm | 106 ++ Source/HDIAG/z180.inc | 71 + Source/HDIAG/z2u.asm | 49 + Source/Makefile | 3 +- Source/ver.inc | 2 +- Source/ver.lib | 2 +- Tools/Makefile.inc | 3 + 24 files changed, 3786 insertions(+), 4 deletions(-) create mode 100644 Source/HDIAG/Build.cmd create mode 100644 Source/HDIAG/Clean.cmd create mode 100644 Source/HDIAG/Makefile create mode 100644 Source/HDIAG/acia.asm create mode 100644 Source/HDIAG/asci.asm create mode 100644 Source/HDIAG/hdiag.asm create mode 100644 Source/HDIAG/hdiag_old.asm create mode 100644 Source/HDIAG/sio.asm create mode 100644 Source/HDIAG/uart.asm create mode 100644 Source/HDIAG/util.asm create mode 100644 Source/HDIAG/z180.inc create mode 100644 Source/HDIAG/z2u.asm diff --git a/Doc/ROM Applications.pdf b/Doc/ROM Applications.pdf index b63d58e98dd875d1d55ae2ea6c1e2eb96408f1a0..5ed0a9963eaf8d68169aea53e10389b3e41cc483 100644 GIT binary patch delta 69429 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

=$PKrd19=qz$1g(~WG(kx(S1Z5r+j zenr{`J0j8@iIGVU_e{GJnTRTBi0O;15VxPQI1}$&7Px5X-!s4Db)%g&Zn3y?7;Mu| z{W8zDo8>_GA-rSY4Dv!$g9HoIFt?*?aZ-#O6E3r2a+m051?k4c=4$wTB4vbT1CYc~ zvmV+Wk+51?NnMvombs>gkJQdq#@EJCFcUwO{wde{#2O7vuAbrQ}Gw8^i|C_$HWv=cW$I(8 zPk(&1sC5t#(x2!3cn!GB@+Un=!)wQQqv%_BU^-B?d)fUSH;K$HH(F6-dubN&HV{yc ztde%6{gYmZ{pDUp$~ zthnG?bDyXvaz_@74F=sNay(Qhk+yPdxF84^Ac9(qmr$@HCFIC(L8!sO5C}3sPVf&~ zorl{UWWF*n@_mJzvbPX$?TAoCf zC06=GLJ2(LpN|y}Ya>|dav8Uuw56V~eHgiyx>Iyi5-{H9fgL1DitrJsfkp7goMO8; z>-$cZ_9S9`jOXg)cGUCb>R4>@pyVfitFAvcm2rITHj_25O26gN<{II6z9-n0TMftV z@FI6@eK0B)J$BIDueomgBbz%^gyCq7)Zh>|kMH3-QS7T-8`Byesr>AkMY?^z7KYV9 z%N&aDy>z>tn}y?sg9vbgAIr!a>{_-TscDbL8ZHQx=DP|elbYIIH`+Qe=mcUKN8k@F zXm(&{N0r{miFQ+3JQ!_xIcSr%G?MWO>SUTnQ4$blE^DKvlHrJRPjG5WlR(f? zMOKu>`BnR{1SX)afY`(*sc$}VX}xaJ*lMa{;Ga&yok@R6b`#`iI{0+{Bh2RXX{)p$0o zF$R^gd@YN2U@b3vJ`eagZDz>Y;l3aBvf$R>*t=j*-+c9$DLzoLQYy};vg=|tLRe?u zXo3sPCF}7lq|9r1{~phBH%lRQflSYH%6-+Q)9tyH0nQYJat>QOXLfi7oE4>5yg^1}5bX$Dy zU`O>mgEb{y#4sxPmvcs~(??9;RqWQyZ5%H`h#hC(k#{>~cHDPK-P#pMF_n#sI|x-Y zNq+3v$&6DYko8}8Yiih|TJqBT1&=O!rfuy~( zBM0*3m^}n4r=I%d9{>VzC)gt~RZHz9)(lW#s-H3!*bZde1p!N&nF@<1Ov<`~1}ye- z1^d-+)hS(6Kn?eobS#sT0;RHq219ic^G0SN5tGj^Kfi)4t0&{#sg0S(Y3NXWe=%_Q zbcMvG5P@N+%jV^d|GnDR_dE(0inqCwNAlCP;1Qz|c5)h5v=61p_>I^%yfs5raHjS1 zj_Up`xZ0U)q&%xlhM@ zUE=5dOmm0v#CxJ@wyk2N229H4*4IUMG^K9Tc@UFd88+10tH+V{`a$-;gjLO3{f-}T zO-)?a*SiTy2`?(*k7I-Qz|^6hw8K|p`dJ<1yZ#8O>4y5gI*{|vq{K;f)>;pH5igS1 zmbWr4q12zc^9B`q&qwr5OREQ^9)^yrdeA(9du;yd{lt4S5Z*x;cpuwvGBSlKV+)rQ zDvfh0lvb`JjC>tWi6IO{DNO8C!ne!*zbQ;WVI(;P&z*lLOenqPc8!0Vg#YXJzmLI4 z0U31`2nr40FcCIXY6Jj=i?Tt5A*c`zV}rqgx326A86jaSPfHt5Hyck!dmr0C6dJhO zdU^>ty4u+K101|vod2#fp~m@-d?hS`@?}HVU{GNIL26_?hqn+->amg>-}{72R~*w1w^)3kxYYdYk@M*pQ!;n2^)hxF~QHKxLia zD0{mI8(0_$fT12aOc;cEthY*?eAbH$bP^ntss=>8!);SuB$)~YIuuE(&4*M~A*cSA zpW)wz38)C_S&1M|A5bBCRLE)ms0E`ER$!Ei{!)jP_OBlQPUKJycqH%+H6O}ujjH%B z#)lgF?=3+nG)KJ(avjv47Ub6D&iJnef4SWMYODYRiJ-jvK;$hrOKSfG&JfV8pF$9U zlFUMvYPXClxuVg?wo-HK6nxWoK9lNw*tHVK6Xf{loC!RIG2my5(dbKkz(QN#0^Lg+ClMxE?nx=Kf4y*kBcei z4~uOOHqW+mz5X=)<8$%XJGNafoL%x>Z#CYi7z?S}$6t$Q#J$-G|M?8r}Q-NB}~@?ChJ^w2^Yv8_*A z&bu@C)~;(ML7pa*S(Vvn8b@8u*yD4Hlatsl#nFQ#rMZh1-yaVbg^Dy!e&XhlZY6O_ zPCNFOYL%Y2Sx=mr;xz{dOR+5>30Z#Rh9ncVku+%-&;&fuAu{HX)gkj`W84 zzX)Siw4$_g|8j@I^=I{E)dAW?1}$lwbj*Z4$#=7Y$xua>NBjl?!7S~av!@6eGaEF3 z-h1ITe+TJ<*>{UzzuJjm|*9{8+%apiG6fQ7LvSI=RcNwzKyVZYN(lS~UF%9pUh ze^?P{oHiU<%bDh9t49uPO~n1Yb&)V-vFcL+OKUy~0-JA|F53xtJ_Cq{<$2@6@M*(U zw9B13j*X2dBAIO7f6D(}K9;RV!+ql^;WUF>TqMs5y&Oce(iOl^dpNjH~X~0BrW=$h9TS=RXi1hp1IExUM(4Bgs6O zqoUZ{Y0|ovv*^;A73|`C^Zq-y+T`!W0*0x z*%9H*{b~Lq8izT#`491HG)|+QS3MzT^KUE`*b14%eKKfc-xK6L#>=XhNi7Dvex6qq z;91Qlan+xsls=kzajfOlH1|Z%8Y9L{ch&hB3$blP`6lK|2cMGH zMF9yzLEuUyj?BSF_BZi8_gj>;?p30#j}v| zp@SLam>xBu$==iw2J(<|6FF=4>^ zgYr5PNqMFhvKOB6Z**_cBOGI!ThDwS3UB85i07Q`PDpW`@Lt@5TVEnTM7%U6`3xknWvh1|~tVAsv zP`j1Lb*KdYgv~$u0isqK!oa^WVaVGW*T~LVOcrZ|nOn8| zFSH;`3Ui%!JY)$jc-@Yc9^v}%rg%ww1)&5B2vtj1? zs!~8qC5N!!QT(NO z=lttU1ESA7_K^nB!&H%2xS<68YYZ5;#F5?ZI=g}w8OAOMue`6qOLtl;e*sA!mIEr5zG^LM@1H+l%>0?QcXMOO&@{rIl(wXCBjtr7Z&g1s|-iv>e&j7xJeY> zsM6b4%D&(?5BFO>^gbwBTYuv%{Cp<}ZM|y_*<$ngvnhfk6j4AuT&d;%jBa}vD2GF) zrw82%y09o^yrQC?^gTY32$nvqo+Y38kVdWJtG)1JQ~Qy}r|s9Vz!~0sp3RDJbdx1p zeEuJpEScLb%d~Isz;oAc4=#2CJOw<{OX|wHyUs_1C5e z1-nh!eEo{xw5a*4nANBwO~lE+zZzZ>%2;sYw8b={^cBJQK}*TSEfCk~%=$%Qn%9B= zR@!s~9#Y9O?}T@KJxgg=i^z_dAi-_QG5mR?Y;9-xx(IcNKWC5oCgu2_3$XL z;_?;wj?&c6Qvo_WzV#KpfPD2y{zOaiG(Wz?aKjZut0(M-rvfpi4)=RE{k{rm;DJt% zc!A**Te`3(U#U5zcph&_44B9Lk@gky_WJ}552}sRciX2X4?UGY(ItL-X;@D}+a<;a zkzRpVKd-cuH&e6RQ{Q09JcIWQ-*YFOn<^pwHfTmkukLE*hBuwTK_dr7w=cW8;%VXq zs{n4Waay|7f7~JilFyttYr_g12l<(tlm->dZsX|R00Q)X0|?Mx0HLM(e*l672onJS zQRh)s1(d~(4VC2qz)(JM@a_Ix6xTty6!`xKLfAOEIC^_JdZXM5Ufuy#mR^q5C}=>2 z8`9tIHU)xiVSw__eX=Mbg34s^BJs>9sQw84FcjqyMQ+JbA%o0rvBMu_1UxdMr1_&6 z6exmXW)LK!96Rd9|EPqBqF69;Tb7dV_nz7R#+pByf>9(E28AIF>{%Ip&-ah6z$iZh zN(x00tGnPoa&-R~79;`%KtQnHaDogpXZX$O{u~g5GE$Q0&>$CW$!Y#kha$kJ4bQh~ zE1BIttABgvMNwpu5~=dPs!@+b6h-b-C^1m4{r`U}?=1toup>s^eSwPw1f!fDzj009 z#SKLRZ#K-?EzE76*~y>EQ%ut+%`^=YG|BC__O=s0;})agQOz~WE!$7tO!Z4U8aEUZ z{6brpG+J_9=?dkodZlikv-xNNEsq&O2MJ(`aJz&`9vP;!{U4CiIMX`LgBbEQO$7{z= zeJJfCUtwus@o+u+L{t8eNjD;7lt?p2_vh+Feph=S5ty|Wz}h#yFfg@evsYoF3ZPOg zvQwpR#7g^ECe_pemYciVM)2#Ry(`!Q)SLZe-yG}vIzMNw$N3SD*^M8i&@lph>dqCI z=6}O?>3@@KYh0fD#6WhPD&njFV0_}p-#8p$`MQJ*t$xe0HO%O_}zKR?$QI2G?RCtr?`DkNQaEGr`{tix7tDU`OIE)}uwvmgoX)sky zvrN#+kf7lKYPFsg=6%=FUgRS}`YU}PN%iY8=APh6!P%wbU`=9UFk40*!xN~>%RI~Y z`I;B;qu-ES?QDrJD+P?rv(BN$f>Bi4*ef6xCv{X-@1kfoMIuAMyECk_Rqir?yn6a! zdTsYwGqs-8(HWfNd%YnZpNU~2^HK3t(*6sVR3=9khl52!hr!Bc*y;2LlAQ-sKLXpo z1}$rS1nj?lH<#+Y8`+wVg^ctO9wNB=_NXH^k*@cg%gjGdcL11tln7ah|Eeg@TNetS^^LNOSrks*3CT0-w8QqXeQ(9?a) zetwJ#-|SnwF%9Osqq;|Dj=-oh?XY7g%J6ksJs-Yv5L#E>CY1Y5m?@`0jh9ZN5&arM zunJ;T$O@ucX0dVfm*KH|I_23hs2n^v9p;v@j@j2iB)A9iL~jXtsM(p+pU=(AK@>kS zIvMkjxV&Xz8Ph?7Jx~4yR=7(}#y;e(LYm8;CH*z~mT|3%febiW_-7Um1rF+R>UHp^E;dSj%Dt6! zUJ*;N$;SrvY93-i?>)Jjh-w){xFR2RS27Qkt%mfagE5uq-<}n$x52U*Vy2LUEx*PinW9J2UgkWmE|nV( zIhiEsBYQlz9~1nZu;V5q+e1?fY}A{0DQ^KANrNd8r43-UD3lnD>fd z%-==|STirKh1$N<`FFKq-(wB+i6`1zSq%-0?(KP|G;_yY^jG)sh|XhH<0VD+fYjHF zkYB5!q2;7MH@DUJ&`GDWM+D{KO_)CB*B1W7X1saD_?yo`Kqx-PLG^o!)8Eh<^7}g* z-2d9e^&fW#5b`IHL3MGfJu15q|CSbQ`<}a=K|Lh{WO*aCe zVC1zc7xh1?P!Re%--v;F82>K}6GSTe5+SeUa4}F{7AdL_KrHA#aGMh*3*D?eDdCK@ z7jM};fkC3BPu@I^#8Mkwe33Yu*d&o{`yTytBc<>7dhRDYD%IAgNa15G`ux2u$6V1v)+dg&*Z>r6@0;@dkTF)` zM-BpVY*mh*!H;+*nUVD}S%B#i)&1=v$g^(U-6!E5Ii6w45*S|^t;sT?m3wjpu=qK?{imt=sn(6vWuy?;5dG&n#Crv>HASx`gpkCCASqL@s3F0 z=JF3JTG*k`6+*uSV7VK-vb^5*cD;PFjccuWwQ@zSu|UN!QAz}%;sC`dpo#eE^GKkQ z?=!vo6q;DbOhdtwetd~|8KZ10l96h7QWtAB?t+!qfpjVEY7&P>iGMmmOZnBM^>N!} zGz*%Bi@hy(47n;lQ(s@~-VT<-wp0buJo?=3Iz6TufcRM@zB+f;D8h$a=bv)-`(Mc;EH%+0xKgD|@^UOm;gQW)(a)TzfK5mrV ztQr)wiD+CY=%n@K+f#>~JC5WSaYx()76w1DN#Fv>d?-oca^+U@Pw~5aZBE0bmiRk( zp#E=eGe^I7YW{t#554^w49;J{1L^C_g8Hh*(S`l>KYh%Ypuhl12;>8U@u#-uj{oXrixP>{u-g^Zz64tHY{ly1qGd z=OLxLY6J1PR%|p`=5RZb4}f1QbEK8>FNgz75{o?{nYJd%Yij zaP4(wX3fmnd(YalX06{+lp}k*O+*|%pLBM#iLCZ2Hc7pomK!OeU8=$FM^F83;^ArF z51)@llJ%+~U%cbgI6e(_%yaMd=Y~CC{H(wDc^8h|`g?)zsMH5iBA=$H&Py|ZppTQ> zwlo***Cfe;TWzYd38dvQmeUObsds5SoZsAAPxL-_Ahr5}I8=v0q*H^p=@h0sVA{h2abLp&~=-n%o`}tP$$?Z;a+I((0GW%V||`eV)2r=GIuo- zZAyCQ_Q=yy+->lR<{KY+&CVie#M`ylxK^!GHUDvpv~|eg@>fC2JAZr_tpG$P@e6|i zLYvc-Z&oD^r!*V=71y44LO(nL{gc19ulL%wY|e>BTkh(wzf0My5Bl~UkQmN$xP-;R zDbW%X4d8|Q8Y#+kcKKUHUThuKk5cos6Y{>5lK3Lc-J2eATo!7wiDVCPNj zGf5y)S{ou+y0+}>j{dBfvWy8Uk3g&(FGXfS>h4`v%m?fN8y{V`H*84Sa5rC$zJ9&K zol;lYll6M>TZrtiPbejFfK*E+5yu-WgrT$B2QLY@@<)3COWHox!4j0_^Unfpe*4Sq zy>zd9%S3~@9#$^ttn}Z=3bx(E4c;37|kazBue^q7uam(Ix z<2&bymN-*w!ZXxiWQw~>1dz2cR@q@TV$Xd%*i1M#%kS;;zY^q&+m z25Si0!nbJNVt>4EGk(8ScKEwp|6I-B-25CWRx=|dPDvs8mK1+UU<5hErr16$_rnbq zfhDe|UQ@kuW04rgR+4SpuSQ^(#mM;9*t1z$-;-G~lq|k|?~P45ldVwbU?ltUtuO)! zcCJgGV=B{8OtdNxUc9L>ZMMV$OPYb*@zlN zZKzk|{a!JLTNW=~uj0R7JR!DyeN3)v8p`&SpxIsFv2n_ml8@3js~-*$-B3Rl2t^6N ziah#W%dQW8`MfFcRMMLA`FleDP)DOxNT4{@msa@wt*ATh{YBs1c;zs5^o|;76>+~n zStYodG%W>rBj)p8J8Hy!ne2JytK|~HQ%}*8STMc5S+Nn$22(YcyJ+M+*}H{qP1k5j z{N{zk<%nwl&x?n8#VNuaFMr0Cl{*X11M1i=6X5dmOShml;88$ArSja6bxVY@Mk9d7e_(Rze*g$ebFTWK6zfR(=`9JPT#EA*KlRv z#vLN^C*VO?_-fnE37@>$w8OVdGnFad8E&h^9Sl{j_2DT7w5?*h`)YBsUhUX9gnQwQ zOj}lJQ8Wa8L|yZ*K1EN{Y{jlHsAf$+Vi9^&^yu?(hGLs|xA5x^r(qQeO^=AT!`KYt zsG5m$vj;^^$O!H^nK-FcKcI4)8|>Izx8T^7ET)b+e~DQSZ;$1ozZC3`ptVKAKg5CT z7F4qctdmK;is%TztC#;}sXy$V<{^JiS+95fT`}f_iz%tcdF7Gs{wda5;ye1PY6-TK zocji`oh=TZ=v(Xv16bwVhO7NtY6w+~A8M-2KWRKVd&PjUN_RoURy^5XSX`}dx~D%b z#$1U#$^B5|(Q+p64$&NLN*$!=AbgQa>4+FwZ$VwDY2 z=!;&57IXXXCGvC9o)i?HuuXXHg_7fY7347rhJMCI`VnV$oAQtc_AztKXa`H@WIOrE z_|}*NKiSAO(V=7U6i;K=qIjb;GRJJbcWmt<*kcC zW&WG?M|=tI;UZ<7Y!Nj$-zuKvM%l+uDO~Vsl0H1iZFd3DAJ8=p(06g% zU#48@##gU?IAyD|)-4i6!0NQH1OxjTrl59x!fl)7kLxnw1NeTTF(lu-SH&EH))y1^ zqIBYKabXwUPEYq{&(t_JU=ui{BPfi`pfodqbM&ukx(CNpAOR#P*gi&R@vqYONrp&d z9)vkVhf1`yFTX!pABB8}1${m5X0-m*UE73gc+xB=YdfnUW!T54e%9{RYL!5;PF0(b zUDf~Wq1JP`V-m^i=DPTxx}Sn*sTeg)p0eZT=#-IsC4Lk?7cZps{8moh3^Fc93+#Jy z!s8sW@*>|?JaZ=d(jsGl-e-eb?Zy+B%K6w8eG%K^`8SLBM?ybWevYubtIe!2FqJ7u z7K^S6D@&nw{$=T0z~uakLrj35Pk~%hJjm@`pHxyIzha-SpA2&Rc*V;su?5o}`hmn- zciyT?ZUCNc&=)|Z1Wp6FQH}lBe8XzDN;dpZo}ESja#U8hiM1LN7UQ19gS}va`r-@AH@{{6YK1fcD6YwbVAsb0&%xIXcAw8-GWULvdNq76 zMCLA!Q%8H4ix)_qIe#dDG2ZOh$0mV(?`R{2899iYnqVY0s3nU5w&Wx|HHwHJ?N=gS zAfz%BDpf%wo3DEG8i0t2Og+bFl2#0x9 zeDuE*gU87Hpb?_PpY95&=HLF!q0*=VLRY?2R|modYSEw$Zdf+J>X?h$|E6tC&T zr(T6NaUQ`3h_x_X)|p!o&)N)$x{S3FY<{?spUd7hiH8e%i?`uyb8bsEPQ^2?wQt9fl?I0d>k}PQ+)EmTPtP|tGiX>Ng6SJuF15lt zS-Kx-X4>MWlXRQC0m|AeXjCo~Ybe*9C9?>(krv9Uf{AIP6r&u?h}3k5#nMaP(jQNJ z@HkiU@@qxp=i>8w^M)b?;0a>o?#nXQv?kO-wZ3=$B_;>1D#=wQf_GOa_3Z{1~0urD8tdJ;Mmx6Zg99uzE%l@pDif zt`j?3$mYiPOe12VzHGDSn`%pWQ0_qd=!W~lY%jFiswQcMm4uX}XskzzYF3G=$oN}q zyRDGJbi)qG%YY`AnkKX->v}VXD`vW@f~=_qzqgYEqeb*2nIgy1bX{{JE1*o;D-TdEuXnSg5D9`QBSVGj`3xR?& z9OM-40~2VFjrh~44x?DZQsulUT6(`QG`1~xGs;Ya^U?$Spvrh@-}N7le)?5R&S^OK z261!o4P;R$Ls24x#f+JP3T_V^Hj^#$YuQExG?oqOJydAdv&5n~4A5DU!YxhuN{ugdUaC8OnkfIc zs5q3?eoUjJ#McCk65Zeh?Icp1wE{dH^RjNFd40tDF*%}QM>b0y0$+SJy7XK{7aNZd z{h_Ebq;tN4F;z$7A|84zwc;^p8H3L*R&HWsoXh{s+gh`{=vz7FIOCgpIa?+15w zBVm?4MEhvn>AzZra;W8XFd7ktoy*0>K+;C7;+{$1Y|&0-d@9?kqwVvoETFz0gE7FC zo80`i1tBY@>yI6vk2T{C4d!rO*N6zp=e?<()o7kffX4^FWM^(JEETYiHG?NnPi<#cAA^YMcc@#%85 z*0+wK-L~~?)~lNq8bq&&WE-vHK04ca8L%~IR>!~pSQ=e)jG)Um9b%w|CjF^0itlCF zs;TMI;=u2qo5QLU9~G}!a@-WW%Iit`>P27v=P54KkIe|#Ci}wz*(1FT1d!j={AlFz z)?IuRWUO13`V%!nL9Nq|A2>~YRZbKLnAun}g@=<<;<9(FW5XG1Rm@va6j4=)+3ho| z0vJ&g(N$?>hR=nh?ss0Ah8#16%r%0sBR=n<pYFWA^?zV-UhT2O0PO)N ziU@dqeYL>HKj?}D7x>SoTo2-L^x`wIUaW!cGOvJI>S+BghHn9k3|PX(P~HP}({%K@ zW8J`#F(+|e>%4~e)n1GsUhmT=a!2!VJZ2uiFw(%FO0i$ z3P-XO-s5AZfJ5|SH#Wt#w9Q}DdR2yP>u!W$;UX{Lj;$yO;1kUR%ex(yR_AFKQQe|H zT0m=iPhy6|*{qf6KoPO0F_pOQeH_4AVqcMK>wEtFWvIHt#n{F3cIY>@hdO*wIqA6^ zW0@)EO6UhP&+@)uOp5T|vk>Vv7oc!cbnWG2+87@!ON`8i(M|9g*|!a;3W~pX+&78S z$V+|*Z`UThl~(qJb~s~Lcs}7}SLb);F~#H@-Mc-X==Ni_+;c+(9}w|hjzt7`d{bQU zp83+<84<_#G&lq{B>7fPV2_<*qD&<~&n%HqNkTqiK59rDziRvU1H2QxA4>IK));u{ zJO(#K7|oVte+=*BwRIVo=nJ9r&OG#~MZ+$0Hi5@sNxL?5Z;%*%ZEB#leajhlQBH(Z zM$B^GThK^CaLq31P`RS>f&KZmBKg;*{^^Mj{!cAI=O5|RTN1@joPCgJ&<>?Bw3|dz zU+uYs5}OWV#JEc0)Ow@iY7?Kl$w?%2!23pxiB8brMK?8{)p;v*-EKIED)T+P>~f2h z>uLs^Dzq5Wo%ntibFRAzC4s_gc)Y=cxuqT#%Snxl+@^ZlX3hy@tJC2 z0wvV?>RaDKWL?v36-3AcRc^B_`$YuDlo#}>!4;>veW_LSV~4z5enz_DWVcX~NBXvf z^s&Dk$Aw7BHa$%XQk4;IKr&J7TWsyprcolYl~zZNs*s3{&Q~Qr<_ECNX~?F3XxmQu z=uU+DK5rH<$EIe|RfdVg#q1UhkSy_jL>sxZ>v>2ViWHZgYS5#|7->lJ;DJf6P0)hd zM>r3?zIEd5Sdw)iMi~u^5kqouxL|fJu-cW;JuAQh*(T ze5q~zSynm!E&K46w6DaBoL2249tD(Is?~-mV!p$;yi7A0MW%@*4B9%E)QPQxVv2-n zQFq=a!?sbWf8#8kjz7k}=m|W(44T~%HG|hqIs?R^K_BekJnI_Vm%$yW& z!-72NS+h64Yq&j3b7Plh*NXA8NhqA1ly7#+QC=}#U?^v|w_NeF_<2Vd11t6IL~V}2 zt%@+eg1uR>nXZqvwWlw`SxM~Bk>~nvJ7I^Etc-a+VBo-Dw&xOAH`WUbrg5D~i7ke2 zaCGs|gcQ2uRi55S%ix4;Ra)v7n^K*2dr{*_2Z>R#_*3Z&Ezlef3g24b8-xM`68fvw z8oAw3_o$xkkt;^dVe!>^vL8HKQR_6oA>ZPK`ZJQWt);Nt3zM;^OBO_*dqwy4sFDA| z8D*ZJdTGLO?`t;ND2eZjv%X^(pD|se9& zEFzRi7a_+@O_N~>k?QFU@^>a8m2V4HG2Vn6`QYdrn>jMIt@+%pSZ`R~IUv3L^?h*N zme;Q>ZLfm8^ln9>7`)-_vu*S==_p=H9T+nAZ5Uj8L0(-{*3oVmbp& z0mlw*fR-By6GvHR)-o49B8d(|zykwNe6tp(UJqknOYT-s5K+`k3d=+12)%FgApK=k zA1aY;3EcNM4PS)0Zm)ZS?hc9*Z!O(NodIVag{c z3dY`QI(fA11maCFBhzwV^T1%H=s5W$veHuz^6MR%*cH|c1L=(m?|&p+0Czp0G4p>p z4F&-?|GB*ad0cJLz+?;m{{3IOC1GJOI`nF{^aq&WKlfcAk8DO(b};$E|A&cy02nL^ zrYF!QK|DzOgKPcoy%Fd#EA|JiQ&{W|oLalVcoe8W{k|KlLr@SbbRTFjk3) zoWrX_{}8p3dA#M9MVOA)`Qh7HEhGD3!+ga6DTfo6+^NPGZc3aCkW#V+f6khwN$U60?@z7fTfbGOC+HX|EW`B8!ycRC& zBUh@&;frExk6h!X*=KFu$(ZJoLdEOr6g^9t32!CMPikV237`*f-1*|W!0hZhDF|a+ue5Ryw{03 za{@h9fiXwT%!EP@2TEVWye5prLOz7Q9bm(J6@-*xPiXwIhTvr34$_gwX~wD{^mVs5 zA#dVqnwTee?1B9IHE2<UU%DS{F2aoA+TJg~*&_pLx0D zp|=RE98m5q_{)6fXncA=kj$rbPca;el!X1xo=fCSmI%$`en`^M0-0AZUY@mP zHXfb^=sXbAhuQGDcbHHWjYDlN4Bq1xVIGBiX*s$uQ`*-kxKhm(!}@0Hd71QHCD#We z@}tY4It-SgJ9I`CiUC3LjBa+JoNOP9)z$j_uu%0I#@*x?tAoZBU}2~^v~6os_C*kW zBpSkT5`LXhh1$nMQTA!r%iVFOjpt|K%wC}|iCTL@{mOz5;bsHNSU)oF9Kp@IFzWAV zL#phG?d^M>$5<5`sVA>ee1U#epr$RQ=$52PuZiRmv&?nP(M*LXO6B7!*}p!>GIw^O zQ6<9=sEX+2lyfvI|LNW^WN167kxtOYhP#X*f6LiE-IhVRLvV4Y>cn z8%*qS@L(k;UkxlPSrcILb$~nKH3#?8pY>+0gok7~>;04wr})LQ&|`fPDknfHmOuVf zojIp|)dLt+2>vdSkDV8kse?4&6O8S4%ZkF`*D9`rfH1DH#B1B=V`fQD9^)+y+c-+G z&uy`ZvesDri6Lc-DO>!MeQ+(_Qf39-dTw8H96xSH@BZk<;(3E^D| zgldjCdfg`JLk!MGcr8!34Ae}tQEiHYrDF&7W1~x?>%t9YC{=d~?#S)bVOO_D${Q}) z%xwnUHY>VIVX(b>aMq_Gl5x-9DM8=ketVgal>7O5MvC9|v|Sn#>Mb&QWk1bNbE+I~ zfAt{xpMLu($pqcQ*_5Dp0YV1l^_PxdO_lQPEWA2zspB=*y$Bv1xfTDDAJv(2X z*kf|r(4RK!8>6$j0R4N#eCPdMhE>_`>*%Lf0$8HPc@}4Twco`~v*bhEpu9jGsMSKwZFCukEv z#R2y&hlFRsf^&a=dMMUHU0=THWy^OjX`xwh54i7tiKn^weG+vjxB7)7otTu#;v6Jz zhwvgYT7<3AsMQx!(x|ukbN)(vugl84>9@K(Rx=l>{wBEj%sznu6%Tj>dR)B?A7|7B z_jL`amOW64id>!Rj7}kkqa4|LQ(vh`giQ(rAGqU4N(u(I{@ck}>Hqa6Z*t0j)u66dQUISjF}^4ej9K}c46qdxA9VZ=1INybE>n0?{%!3 zb@hM-^=%m;G9^?Dxfio0PLs8i#$u8xm=k)IxKr!D&EASaeH|i94I2Nr;eU!i_FEh;@ad+0vLDdFtYNaj@BimnhsT zUF760sT)dpPLQV)h>Q(O6AYiCwY8=!m&0OMsXnT4l)R(};fXdYUzXa)gC!>CKT_ps z99Qcq&EzH>2NM;GwhzUll`m^KIM(Ejq-1`_@Pw}L>5Jzk=E%=-znYHS zm8n&yhyoStebw2(pXIzw$Tcy%tMcyC5$QGrVEylI6T@+x_rU) zQn)K<6NMq>lV6SW(Mo>w>IY-l{TEDxjBhOOuI4`1R^(qi(P=p77i;IX*pwq6U^uLC z>-ph)0*9vofQtYC^lWShE=!KrjCxU$x>p$zioMz6@TZ`I{p%#{h^L1j`{B{M=G zs3MlA)%=*`#aPD0w@zIX`t@B5l#fqqN*w)7O{U?gNwRnnND_nSdB!xM=@xJ0-a6(H zb!MFK7RGycIDN1`(^;u1!E73g5 zRiBp~o+BfF7ZJ&e6={pIz4PlWg!mtS2=VK+=^v*&;#d9M1*Bg0kLh8P%aag!O~rYji#zoY%c|J71ZgdYrg z5dB|T{=N9p{K>8cj^@uoc@teP0HPg$QSVm~58zBeZ_)n-btZ>hV=UY(_v+S;w(fTH zB4A3i_grv2wP?^=v|+2{_m4MsL1f;K8;s$>ZSrGH0biO`CPWxtsm<}OH`=BO^I4U&9v3e*={ScL^T{Jw%^+(GL zbbdrpG^}+$QB{scNi4@9Jl0-^6D^-%AM^ciYs?}%O9#ps>_3*hb7wwzjD<7S)8Dmg zA{0f{qa!54@tat-NK+EdJ>|XgPUY#3+gOjs)nUJu4~*;Y)QXU#`kQEQFucrmH?kN( z@%tV4%I#L)XLg(-@oN4t&x05G+oZKd0m{}jkNlGB-aV$0Og=m}LANt0r=?C-ZbXf< z5#6iqg4brs@1Q+(H}Xv4FLSWAd$X9L)8~~W^b;B496W`Og+Y<=jG! zK6`fQ8+1ni>Er&qi*vKbJH|Eb*d@=AlmIwYDhzdH#{%!Xc)syY(7Q3bFBlEUL(V0WIZ(+&*KcTQ8IiOLe_xcS`4 zTsv42e+efPx1@?JnVfPAC3SN@rtGETN;r$z`@O>Nk3}bT{Me9 zh#UY9J+ zP#_|b9lVBtzta;4UT0DK3;q^Fo%kI?3Yt|P0ArqF43P!-{}leo_;@o`5cTz{bxaf*knrXS_TK?t4-s1w5E_6zwiEbR3y4lqV^ANF#10h4i;6NVz{ZI1hH(UfiE*Pcfi@-(} z6i1i<5O$yhAqj+6;&GaTUBCqYI-oZf05OMQ*MVl>lK@g8Aa%XyT_sy_sG_NmPUMCF z9M#YYc#;eRAg+N{3?z#{fD!P5CRGmtq}P%nN>CwOK-t?7An7A1kd`(AWY&=a5$V0a z{d#D{(+pAwp!W%i=s<&TS2Sl5LBQx#D3IRG4G?FK0*no$u{ry|dIPiqD_0%@^fW>% z%<=>vz>6kQATNIrxYJAuWV|~C_M4#beZT?k5@Ww0;G6JV*-Ie<}iA3_$_T&qqM@I3ipl5w?)^Tg?<8z zuWqZpNFl&wJ`L0QB??6TPS{f&AFc)K6R^euB6!-=H?g{&tB?9 z*CjA_SW&L0@>QdGoG#_=yH~dC*I7W*=XdY>9*z%Eobo?#SiyX@{J+ouvUL*R&9{%h zy$w>p^m_?Fvk9$W>=T6mG+U&A3;An5Zs0$icullK+M1};J8B$`2So3 zp6rrV_zyxr!S9h)#0^nGfXsdH0h{IqHiwr1!~q%bB8jVlY?K57lpT@*(qnBv+Yu>1 zF@6H-<&!J-At-`ZfPFhqK=s!;ViXtLHv7ND1k~3$5qX3lL4$=^!MV-|K?WC2@Q4$z z*r>a@WGEy71UAYL}hU zYhZ*WXhq;IEd)XR1~dkzRJy_TyKwy{v4W`7oOd}SxT>bU3t4FdkI4ZftE zhvxu&A+%!jhz5e7N&_o^aXb~+Ct_C>KtONc{^@UIK@lJmrSl(ZLh$eCtiRNRGZqB%+uuh7J1C!LN|g{tO6g0D^Sh5MW2*f3pK`(I1RYkew*l z>mRhYD+28G+6Z;k(bcyB2#@xM8+c1$;x~i4LS+Nd-u@~9W%_5Q1h#=+Jnw|hC0>M9U zIoA|8b%7g63V=co{DT>DT?S76280J}2hRQ)_2v(kt9<1*Llgk#4q~@m4eM(D*O~LK zQE&cK1-pmcj0H?@08%#+1;N=s>PDnj=se)U``7HQK;Q)bAO>9V1cxkm1NZ<^pulgk zmV*@7{Wau*4mSL%>eYL7BUteG4y0~GCIF6E5L^`gNJ#)3v*7g?^z}f&Aq)P`mnk?% z*tK)$pRy}i|IHJ85@6s9@)wt@J9P6JUadc1)jt8ESK|in3y327cUADo|NBk6vNFK_ zeigw@4M^S09tMgOcC*Zy!@$Q0_SXu_2U1sDZk{O^C@0vTgoI#!a2PlXF!9D;9l}5% zfq5uyC{QXeaMAcP?yE0t*iBrW`PElFO!($jTz&P!z-8mFn&5Om9EZQDtC}~@>eWDC zH|ev?VH6-k7`TvJHT<7|UJzlohK&p|2tgL+uel(HNFakQO9%-n2os8^fEdD@3POe= zEF=gpaI?XSysY(1#$$!?n|Vshgv@H#t3@MZSZ9wnWu z8H~Y=F0dgh;+Of$miauLoyflz=i4E6Hul!|m8GXIj!d2OkdPss9WpN%I&m=xW8-z> zV~9|+UUi)zhe3E=h}792iTmCWjFFO|$|0yMMbkmS<#9l=xqN`M$HRjw1CO^+y9|J{ znBnxHjTk}pW$DIWXq?D=Xf&=w;>w5=?;JXqr$H)5qZnN=8u8m}`bLaY-X~fidKA$V zI@!15BzIpVfsSa2u7QAGTG zDAD6Qd)bJt*wWHR+|+hNP#^Gl5Pm}aLIf@v_Nyc*^MXF}iJ86m5-vXyRf}Nf1NfL< z4yxAqmR{cF;j1&Jn4@XN-;Ih>mnpTE1wY^tZI{ElXC-}E2R1gax+OZ4-_bbezg=2K zkaHmLNr6k#!ea5xo@02}#juR^j5NiCCOxrd9i0PVDgQ}K;G48fEIoybR-i|}a&)INc-vhxVd9~3!GkGBm5M#V2ZAw0Mj@yDT( z@Ld}%J;IA)`PsF`sXVxHm)|?b{FSHsvg^{nj?C?Un?^M9qoVP=MJjezpMHSk&i#5? z3jY=p&I=%Z;2hq0C`vdWJuL0M@l-|wX+JuPGU65a;JCoEm6H z6`yg^fAAp@F|Thvx|#&7>@qCa)mhav75%n9v@YrObia;Er9$*)h=bB-5|ZS1R(H1i z&2O>~Py0_c*3t-q?lb7@ymEynuC*8Lp~q24WcN=Et!R1|1(H)_ZQm!mRU3ivn9nto zny=^k;r&k9lUKrT9yq-7Fk8|8_=U~Xf`D$5^E9K-z@NhFCJR}^%H{3AaXrI z8jLG|@s4r}$Fm(1u4n}hc)$aCD>Y1JdHBIw%IOTVMxOwD1e5%p)bwy@MQ!U;L`lWPD#S^#=c7Ab8**qv3#3nEE=}d4lb_ zCVJnCV#X5XcC7c768Y{uvmHc7OvFhpn85`}SQGE2zo}&%+@W$rQ+fvfu}uNHPky)8 zg#$U^x0am2v&5X?o*u%MvBx!YL(99{OU9qZj|wFSD^PKkhrL1n3J5NFGt&t~vA+1& zD506FAWZ(9lW=jz0t1rwDT=j*CE@p5Dq$LaEYtkXq;*y5pC?l z{Ug(k!jz_Z(t`^u9JK`CaktMn6=}9mMu-9lut~GWo6aTVA0?=S9jiQua36%8!U{P} z?GLqZlG}(g>4VrC%sRy2^ZZbJ!P*}>OS;BCE$#U@u|7Wja^56-zcE~iz8h10+sXEk z37vp1*SS}~1)?Zb^UGt3fT->Wmx=1yyh+-a@BBPXm>y&+Z`t$f;rq<*Yc!3kaHJk| z;$ASe-bNibR#$vR_8{#|?TllLy6n;0(%n1H)cK>W-X`Yt&d(F~o z@-{s`c5+*>>uEje{&FxQYxE{k;L}H>{nz=wlxh@6VsUr4I#}Yw^h69hi#;Y|+TJ}5 z^{o0Hx9Vz%lRVzXsC}Y^gYjj&l8;$E!T?cY=MnmhF~PsQDaNJ*?oIi&P&S^ZKz7;6 z)H`vy64nNSEb%Q^^a%ShS^9jN_CaYM;BWG}gs!I7DsmNgm3TluB|7b?CO(JUiKcP8 zc$sGPnSr?^R$T6wXWal>OUxK$k=hi3ZG<-l-_HLj45j`d@OYa|mEjz6>Ru1^c7Nbm z-SU{yoK886%=pI)9PX=v@jD^aX>!#PkxUhHk4d)ml~F~CEf5;OVW)wh!3t3zIn1Y zRQG6LRpj#P&&MlKUaDK#T~0Vp^0vnG*P zQxLm5JdcfstQZ(E>yJ&=?++Ug*QHOQf0gQ>#5d>OpZ*k(7a_g z9T6piu~XIDPsoJ}#x75U_-HYEeLpQ?7JktBq^LlnGI3DGc8ulhCBI)PGqGXNEh-%o z`z9CElPSuSrGzrMTp~>D=yw50T88QYQZa3T)1N+BDf}vSsINDzVxe_>*Ce9oeJMW_jqqb2&XKV1HLC28q)F*r0_6X zZy1nsGw8{6SG_;M49weGDW_(Inm3Mk(LO6L?Wk6xP_)SKOs~9O)Dl|Cav$H-zr+8z zDO3<$OsmFOQZA-dzTv1VRazregOBr@y*&xM@yZ#|4bGVfbT)JcKP)E1E#)OSy)<$Q zFM^|+nm*%U&LuKXeBeo%lhbsJF8a(_y&9{y8|?T!CfkuhT`F@#9NVgw>doH8EK`L< z){KNRu?;J+0-2;N6CKz13VnB;`}2M|#RiO}Ro`?8U1xaU+-L_)?`!wp-5Nz2sFvrb zVvTph7S`_lc)2QkYgowBC_AS0h&tN+Q1!@XKyT0~HiQQIkq%+*SLLB>Yi-HTj)Om` zByM}M^G~WjG6-7{IT@S8s1~h|dGRgWZ`{*LO%yOL?o8A|e)k^s7> z2|rWb!>T*dZ~>*F`?CCspU-Vjs5|7ctMdW;Ei?IK)zQ-Ktj;5%C%bG)9c?1L&cM4@ zHjcr#^6KQQ`i4I>u{!3MWEEZw{f1SqwlGQSwpIRKO7!ey+0buu-d_vqN{DFK?sS+* z`|!c=!CpdzFJSW%%aIVj@V9EE;cS##N{_0I=>a!VHatXU_cQ{G1yDqiOlgDa5!UX6 z(|yl4NTkXme-6-0@4Tx#$Zg(AA;WpdMh3TwX zBzISJt}?r4V`7((d7rOUkG(I-!Yy_^SV)e)Ts_RPMcuNf5qs!u?Cp-&+e%cs;=#-^ zNyhWY4Dk1L9|oNs1-kFk*Dkxug_v|8s`KXq+=$3hktZ2+z2_N+38F|pG$*Q799+0K z-NnxsowIpRfjhfz7TMj~>8xx*ScI)&q-A}vNtZ%0`%o+c#ehKvh)YA;j|hCT`nq`J zaHU|PJhz`t#{~BYG{Qn?f+QW|BLNGKC9~>1-Zgmji6dG9mBBFjJj2YXu!6zyJmM|B zoausD8k4W&Y*axJ& zBak=AXI^H1i1}QeLJj}ax1UInltt`SoFMlYoa5BuCeaS=lrK zCW|<@C#$z*R2hAgw^cEY<2+e}8pnGEUTP2DkK9aKgCYN@vHhCj85RW+Dz zcDWySw|&S$CY-(;U4KOgk#|<1(nJ0^3MCZ=pDlieGR7Uqg<^LCjbHsS`m8m^;9GI@48JfbGCF#4WA1x0lUq=C35bR^;lmnx!q+@Gj%9MR zE=0v$el_v(G_#PoP>QewyG$!D4fpttSqqi+0zM+ zZ^EMAvG}mP)M}w4-ITx2g~}eT9=0sx5oE%v8nU%x{fcJ=zU6pz2eQf)9WexsLYIBX z(nfSwpa`cI%>86qeohVhCm+8?>?1u&TrN1IUOq8%j$ps6AjypIJMcS6Gy2GEiN2`T zsl6|jS$~$j9#i=%QrKDfRy(@%TZ16qPZMw=9PHwhR{2QbRMf>34$beCG3=ygq*F?8 z8I+)vgR!DjlddUubH@*E7emIvZ_d#xFZT#WG_whuZSs7M5ZM$*k3X$XPJi58dZcmZ zhy7lacp-DSkG=}iVq~ZrV=nT0K7T%HvX+A)su5zgyRDaJ78z%~yh zbIPn7g+$)fQN|gcIpnyr#MpShBYDU)IUT?{MUYDuj$QO8}}* zR8=&4A1A--Pp?n_eL~Ln($;R0M$Mn2a#7{Ndck#A)sPgTH7MmuMm=4F1$q%T%%Shv?z4c6f zQn=YVv!NomT-3Fa@rZ9jL`5~^_qQLpVYR;GPN5Ge9V#|9?juK77d_8MmWNB!-Xo!= zT;_zU%9rG{$-Hh}!ST!MG)(t1;WdB+_>V7BvOXoWE#;YCHig72VRruLv@}m%`jpz5 zROz1*H!!-AHPCfm3;f84v^R2^o$_*aQmEouC|Un8J>=l#N7bxUu0HnElDEljZ#Mae z;dDJ=Wb#%ji?1g0>!}pXS1RxbMJx7H*9csblZGa~S_4_Wa{cp_+*tWv8KT^4o@36T z*gxPK#x3@W2R00xc3?6wJLhR*!S){7ma0Y^$;^Jz)wN{(@ySEN_5;8*)xNYHMi%|j zruKO`Wp#v-OQf$sh|v8PBqUfNdF<4->;?UI3(ZfSP9#RAchh@oaSg)X4V7(3>Q^KK zCqJ1!045geCc}$dn*LM{Nb>`6%m*o8cKh@w3&}TO{_@yey~$*)nBRy;y~LDDLm5Sy zr;P&@E<&~*i@HA`z_5iA9^Ao*FE(TrYw%v%e(_$`(ib7KK(-APmu9rkb#pXtLZd!7J8Swp|8qvjN8eH6WsZSEYBv!#M94z;`s37 z=J3I$(-5x@bp4`w#|i)4uA$)} z6@36qJq8mavG_;DB&!qjgXchqZAz2u9lN+r7VZ>TOGu~TK)h{nj&mu#-0hX!_50@f zqAAr)l5r}7Q080hKq5dn!K;6oFO5;79_^pV{iYqEAzz*LtXx*!%LjL?%vixMS?A>9~ESuMaC&r9>Rg zg@N|*9L8*V0}ixc_bz`IL%m;VO7-+ST!0FDa~RnQODL@xB&%QSZ_Ax|lm~3slAq%U zI{FD15-Y#L6-ncn$Sl6_5D4FD7RiWOdg56-dA1Yt>_cn4pz{jO;lp0xtTLw%0cFk< zN(e1U6kiQeXeY=mA)%7?%%~$9%n`FnB(pV^4F@}W(~n4=BuamPtW2?wyx}*xCF6MV z{adPS?GcCX?foyMg$(oHbv>kHB^fO6>0p)-DoqCEbp2&e6_o^4t4b z*GiJmO(xBlZtlyJzub<(Z`0I=?`PY}P}+iwbr`Y!l&i6@K4fs-J@~a( zGo#R*;b_IB+$r0D1r_%5li6693I|+VG0u?s1aGbnbCW-}0^|N`YQ6+~6%DcM97>qN z3Ig{?eQ;5LK%+@XP@q4!QhZ(w%u*AR%7xJLLb%h`I(UDZqkFMGKPjBnk!J9s-XDa| zP{(`5jh94zHFI>RNzdvJ2}HnKHf>F&lfyJ5j*`8NWOqFft%6^5cCG>6q09|fYc{*F7lzSu>W%WO)lwvvVBUDvrFzJ&}d&e$$h$58~Nm(mWPQjb13?AVgu}m(E@->7xnwtM8AnfQZ1f0r%|sU zs4suaeWdozJF^2aN&!{Lh2zjW3QWBfIu&W8tIg$6L^So7t-lKi$;S(NS3{fzNsvw* zQ4xg3+<~7^JmH6aOy}bfZCp%S!4linK5b4W94J0S05toQzhS z(uKX>opdS0IdF&lix2(9Z}3{R_{pQC^;LhFD+5-|aAhG%Vv>{JLiEEZ7!bWqx=rD&Zu8Kq2L;A7&SZGnQ=Xptx3epBvbtYt-+N6Ull9Ti8|ON-~_Dk<)!U zMnOIPR+`hw7)-~P>ExQdW0$RDryFq`*(u<-03>)O$D9a;@PyL0)(Yorg4W<@Ewy`^ z#y0on3DafqP11)|E2?S{6JCEx7=YPxB6qYy-e>73TkdQR(NhbXr+b78oQG~C6{qVc zjORlpd+A-dNR)Osj5oY`?cmQ;p>Kx_u0L1hje7d@=QE0arP@$(N38dl?-1^OrpU&& zdaYxfxdt;NteqQ0B?mjhiQ}C_tzC-WZvn0p#og1%Cc3|4hb$jvTbq9lt?V7}d7tj&Wgy+XqUJ-9^Ei?rQ@;k>2V-p7PpW;W@;pLOJCa|gQi;~ z6@jaJ70qcQd416%P~DzsjG!BvHjzz7{%lg?CK#TL0;#v@-Ab;>GWJWaUD9477!*oo z$CkJ6G|RfE((Y)tHfn!>VT}4T)`C5C%b{tKrs=U}fG(@P`{=G;_*ZCx2;{-0Ae*BK z1CL&kLdxASxBa|;a4%mk2^DSG81MA=R$puYACdg>G^L5g}jLk06m?nxEtN?%6C^T0{l9et>e=hGNm-4i&R50ki<2!fgHJg9E^gW%zQRmm+;8Aq1#dCVh ztJWLW(gYV)1ci6g4Vh)}z#--7q;8JyYaGG%^(hbcM(!h?gz-@t^Q+%!0{7F%C^&d0 zfM!?uR#(`%zGr=-b7N$D;ud8~yb9M6c?;9W#zhOvqX-T!4PN;d*s{!p=Qga=Z6V(m zv;>1Jb%TE{Z(iFm>v}q#O}X0JiGKE$4%DLC*CWWY~doezjgE!9tD5tV3SLZ&Gvd$oz<>IyjLr+6Wc+{~>7D*rY?%YYAC z)|)IgU8`!%BRUEyuV7*iTBz5b`77(akh*_d7)k@TWyz)>L^(BAnnf?Ibu^u16=NDW zgH{>8xD6!s>ViWZ;mQNI@6)nAK}XFI#Ic$*=9uwU^cnNDoUX~Cixu@h%7TU3-yUAr z>wJj@wk#tQ_Zrk=3Yd^>q?Q!ng%?6;Gc4_DV%(aq4sKczDVxr(i#my>*fSN{&+C5$ z$G9n`HS~DV&AYS#NWU8)af3MLiF%nXwm7ez4v;dHkvK*^HMeNQlyNCF1>^1uBsB>v z_{j9X^#$>#-JY+{ZeV9=Gv0Q_zVvP35vMPW&BUPvs5RhhzB(T(AIkVuR{H+uv-bv(Xtn6-<9Cf@&?^ zmR!n^Ml`pjc6k#fWGt*p4r(Szt?X$AT_ULJ*nPz@LWgfat%xf+^eaX&9?JS>aB zz3`#W6$~UaI`*6+Amlg*Q!#%=jqsPHl1}-lm}CZ|!jB$h=M$qK&Nk2D*L_w|Hct~a zpR*WuJ{cKqov24o-+9S|r1wwhp0k)$YG4O7EesIfZI5fF<%iE_+q4hIM+5={@`j90 z&ioX58XIxt>#NNMGpV&IuT186;vOE}NwxHupQ-0_q!?!XsdR_EU5S6ZYHhcgR~Vn5 z%?E=lY^XSmTdhEDbG$aSN2%hu++%Fc$E^fDT+67gUhka8(1I>VBIV?HkdW3grD(dJ zFNt=04c1O<4;7yZv*`%0?Ogcj`!ULVznWb4K#0<)-eB>)mcDrVdrf-RBp^xHKJdZqk4p)D+H`oNP-6f!X^+T_Z{yDd{OS}LTGhV&0d{3y}*BhOxgO80^ ztLcW`423&DEde0#DVps!=snEWl3c_T&LywCWo?4w<5fGqiB6>?Z!hv6S+j$0W!8WGhQVT@4rpr}FMGF(W3#?SFIV38>h#N~J&seU~`I zcXIf7?I~;BU1ZFM#oT|B7wX^y<{oZ^L(%@;=xN6)4fcQFUyhbDMPTzn>KmB3O&k?0 zvxOzIEH8OXTQ&07gP7ofOi!v{aw4F^rpQ6}?QofY1f@BIqX*>-bN+jLBmXBYzA{OK zN1M`Q(XDwbqZNu-P#^hH*@*wpi_G=`B#JASU6tMF&(huSU{CB8}@9*{uYn|ijaqh9XsM)3ud;XPw)u@Lt}JZ5op{ z7kk=`@`4fVYtzFV_P6Ek5Ezr_-607(cW_NbiDiGs$Yun7zLzcQkike@bSB{KdRy@8 zvDn3Rs$Nv{VhtaD%fdK`t`qlChR243n00`DyuTgn_Q) zzjCqlbOg0th4{r?tN16hSdsFR{UgJ*=`rH+6TnFHta`eCD$c*W;{8ee;W+fAz2qjU z4FrGnFcKr(S3^p6_NO|$pD{IVDbB%Mt$#qwE`B>WvG3Q+mB(VvZN_xcnWIrS3!Fp} zF@&(FU{aAGuL{!I*R~VhRoev2)KNQn0xIbZiTN2E_yeH^Cpq8Hr;Mi^h}*GbnXa&I z41%G;_tYRG($kp}zfag-eDNJuIILn8JgO1;xUEHr8 zCQjfSDVB7;m8W35rylXVpDqPLg3mwziXK_tB!)6iN1D1w8Se6@n@!7A{;S&$`9Gor;nORAEWTlSDYc^ZG+ zaBR!_@ZG-<@JtRUPsO8RIZ+ym1=gOC@1b4Nk&WOC-bej7R)zq#k0d?e9)WbjX)w@&)>osb1+L1PUI)uChjl!xx7cPIQkvJ@BMk8S4yV@hP79WnE;hVGlwuH%Few}vMC%780P#biRV zDibn*GHucJsb9BW8ddod8tz<3mk^V*XBax;Rk$G-pKhXWWk_c-qP~(hoDOF`#Kd4_sTr*1c-FUX9a7kZ#TJGz zy*>(hMxtpQXw$L0!pIJbeEet{1|&doN3QsENq)mCM@u}+PxO0o>WxFN%J{LF1lC&X z)?b*uqv4@;)N&BxXFq=)Zj1Pb`D*FscEfvxpicdHLI(EriNcK{A;UgvHMM5na1=A#)SH5S62Pg!V@4JNVf zS<=yADe(bpU*an`v4eMa7OsgV`5wU05jLBEaCS5vmKuNM#^1;hy}|McWlhh~ zsTo)03=t2%|D^Xq%7J*A$HV?`C-a}9)M?xd^WXKQ{J&w_$|Y-zso}=o~4^#BJP~v$->YN zYowu$F_ZF*d2)Z1S1E*nwb+>#^%!8Rl6%2`d7O#D$|EB4wBB0r#YFMV*S=~ zUCr)2D6uXe%Ps`|_|sietljDPu~E^J?OT{*>q^m8c~Zuit%()O;rBR3Qnkm z94^d1J}HODH(i^h*9q0WAamgAHQWsD#bExLqYfW=ghqef&sGcfg?g_7ljNY;Ho`*a z+jykiuDE0U%6ZQ(8a@>!W$sk?he^s4{HV%xi~3!Q<{mkLqXpT&@4C=#Xwunkv{-KI z(Cx}K+GVYx?eMmZgyMRm-=|s#-d4r4Hl6kvdOe{sY)s|A(l~@|n<1EN<^;(5z2FW( zYaLA0nxB7Uy&vQ*KXQ4CcUx0n<7;!$r7hF_aK0kJ?*av_=X}f)7&-r$@@WZGqOGNu z&v0N#2+t0!twW1LfcUcaKBGk7)*O-g$GC@=DtYjh4Fa|ZqB>>pvp3)4;!bj{k_#0$ z&j{aFSj$wp)_w_94>HY*;LZc)%%B9~GP$%frRjexDNF&+YWn!7c4Sp72itl1q$HX8 zPQ$CdF&lSf0)Pv1mEBHgHVsQ{7}y(~`_6K>Q5l==rD1qv@F?s9Gil|Q)NKa0R_RCI ze8p(5XQEw6ABo)H1W&VemV9s6T@y%JbDPNgh`Gl7JAos17s%Aa2TJFA8mKU|!v4J>dLv35yW+oBTFy z)F(P^ehDRr+`4w`xm6{sEXNyEyg;PFI0jbA3MIFP`o^l9j&pf7KSD*uhBct|627!x z`L+JYiuNSn;%v&X+a{hJ(x`OMYeq(U?dD=Flmve9OS5l6Je6p8WRyc}jXW@k8h3xz z@Wx%^lRbzP~ZWBy$sVaoia&Wtg)M2_{#a@y-o>eQsX4Odae1TM?DaYSZYOe@IW1)JA5 zfh1#{9^qBsi}I7Arv8Y{sZfxv${>H78|rxXQHiQFK67aMj1<50mhu$*IqL~pN_@R$ zw9;XZ-6((pe5T_&DOx99p&IP7ZAH+lck?%AX`_ji>s4LaBhI*3iLsHR1_qu-Tfz{H zC?BVrwStxD7w`}?Sdu@%3Ntk_ zm#>up6_@B@0Tu>SQ$$fsQ3Ntk` zx6()f{~4Fps{sv{x|IP6m*`>v)|cz60Uwv$V*wZgIW#$!VHyDz12-`^ml0$EFMsX? zciXtT1a}SY?rdNq8+U>`!JVMNgS!NGch}(Vgy6iK)33YV?Y{3@KUUQkv&NJfMNO`v z&Mao(U&p-!fet?QI$lk#lpaOISI@^K3 ze<(=@b2ob+*j3%l(a{bBv`_=OIJh~R16}w5mVYYy@2mg`2S+bwkd?J7fKF3Qo1T%8 z>E8%DA0HpU%FKoaNzvH}BW{w&;qb`FkzW%?r_0|Wz|{}gTUSFDPqsehCO$n~#w z0d&@`u8#bytd5qZz&{v^izN#f=*mj}r%)-dg@l9sUji;jf6Yu1j&Z#U1`gGP8f=0x)y%a{qD4A4NWH&i_XvSN8x`a_Rr$ofzB>}TnM21+pzS2|EZ+p;0iJa0_gs25(74Fwm<&(^JD*C&GSF_ z|J6eOnM2ym&hGF2>Hg6;;7{i+00qEbz1x{O|5v!FJ;=`Me>w1O$HdYQ%^nwD?&qt#S=-zeDtv86YpSw$HWT7gp!RUJY%UBRN_auLZF+zX6qwN_=2C7 zdo1BKD0@j>ey>X{EHQzp9_E1KPx7F5c;uuEM?_j)P>HB~v`Ei~`xJDcENkbd$`3a` z(kaPi6BM3?{C}ydY37mklOA%@*>9}M4os7U#eQ*AZvXi(86?-bD>EY9vXA_o6I~on z)*bSqosiv3MNxUQhqtWb$ZtPK80Jyn@RJfqHc&p`<4*;0E7%LHm?IEnE`00nn4ud% z;az4H1Dl+hReMlGZF-mGVH^vu)MW0{1P&R-QLpwn5ngB zkGC;vICkJJ(c3A%y*mz3Yd{L2O6>1YofPCQKAD$!CHzOMTHA)sXtN;Od zUm~DUzR@Z{6jmqUa~-}_3HSQ**p+K1Q^!U0BYy`65DA?#L`DyZ)Mnzy|8mEy;WYVl z=Ur-+E~GTB1g%9|oA|ob=~n;SUO3#5X#=HSJrFEf!eDieP}c)bV*Q=RPK4$jUt!F+ z0c{p;V=6T?13RG=&m_P~=tI=fDdsS1)rSwU@LqaGf#}uYVuUt%kqxEOufE+iC`iSS zhks(z2$4IH!gq%p6Jl=N;=26eRv)Vu)v%b_C{Azi7O~lzGsap(cv0Z>55(a4nvOKl-6sw+r3}{=WJx1`BC>;$=`pR zGg?i>VORbv^LhYSz!gjHiVCI?gB-=oZhvp@OHpR_=qr9RR8hsXI9|@|>|(}sYisdG z3Q%dqozFB_OL|1bV0LsNgI+E97Fa8^?d5DDk_NSHZTj9NlQ1q zxKd*}13EYOI~4YN^E6Q+YY*2ITrRqac)wJitaeO+EEJA1@eBUXp&k}xA+Ui4`Wnte z0^&i|&Lh5^(EWT)< za-O@maXr5HuJ05fSBx`cn|~kl^Wg`hAR^YZC*kl|HmJNhS_o2c>4;4$B8=Nx3J7uPeg~uMGMMxl(;6%x0Ex_uOD?}epBZtc4|*q ziVbZV)0D?`6R3V;No$H0bZ{12)-3el)eJIEy+i*bmq!s0k<_*owx>i?HX7qyrkVWe zNGn>f>N>~Y*~FxxUbDVZ+_lPm?Wkx}cL;Wf#ytRZ+nu<9oPUPmUaOSNzcPd}Yc`t3 z%qbzr63tEjROlBk54Nw6g@K0n#Tx0)>%wm&+PrCy{tfaYV_j*_$i0%FOHFjyr*(=< zR7frC9@Osrw#$hragDsU=HzPWr+J4v=J=;iScf=7Hg=r}*m)~))-P*ZDhhXM?M;XI zj#%lE*Q7r(>VMgk0frdyq^lS=!TVh5JDf^nY^|tGA9(j=PdyJH0Wq!#R($ zJ`loyTwPy(miH4GJV-oX3I;n8LeeRFmjXIx^H&C@7{XaS@>)eFoLBN$YlFHL(#tVR zuW&@EgIp&j-MmCJbj)qyvu;rid!ZD5e}_y1B)k}ks^ZqHcIW5>kEmjr|I7`MFw-^U zY-3Zg>wj88#>(bl=+V}2nlD36U3E5ndNw5-=z|NaE0(Hd8&5H=Gb|)O%t(%*il`4_ zY996*^*RJekr`L`C0n%Q$JbKtNseCIy#)g8uXQl>(P+jOG|j%8Q9N&+Y6oc8f+Jni z1%QPI_=OuH)B8izPV`n3#aR4znRg?uR(O==e1Fqc+w_YiZ58>;I)FdIpj#s<9I4`Q zc77gRQJ#dyF)x;n9EYdVNx=0oJWn-KIKOynpD6pX?MqA#yzpCbVPGDK!&p0oa!9O8 z{@$c7lA?(F6#jS0jvak!uITje7Ns6J#MRZ0n>+D$eAu$z`O#c!6Upoy&(G9IRR%+i zO@9V4i*n>h1M^3B59AMmObqre$XtF#`HMsk><42(OZp~5Q}6UcqXP2@%F}`5Q_e(m zv1F&*`;ZRuy4s1VM$9qItLo~)REoQ6#Q1h37lv+y7g@5d!N_FQQf66(6Qx{;tg1Zr z!cgDDquYWI7tky`=zc{#8|*$DiEK&@V1H&Yb1{`@5V~0z)m;~LQA?Bd+&dN^#uHnW zx0}A+R4%aKx$J!z@8#(m)e5+$z;ITZSz@ryhV>Q`aT!1zxWMNpf?&&@$8-FU)-F1Z zphiH3qlkg$ZSBKsQ4ntrD|WVs*J?*wAZ(etm~}pCdrbLJDiFmey$gbvUsPFGHh)w{ zSHFe~A{()7{%6&0pY!m29-G2`tXRPsHOyo>aQpTIIMRgb5040sQSo)5afKVTjNm6* zi*^HgMIHr*=7W(z6z`rSwS0Ab(u% zpdb3<8cQ4rq;^ZV{uz(VhNjGEw12g4I)buV`v5V_Swv|_@K43Sq}HWKcva@5jcB}O z=I?zD1kH@SP}&ujQBMU8CX z=-W2~IGTA2+N)-ms-lAOG1)`i71BwqviT^B?*2uVOuUvG$?;hwx0|24XMb(NPL$@I z@cUOKjAsjuQHNlhj1HgYUszd+q+TVbJ=L;x*6~MBZSOJ*cIx>sB@vwnc{V;DmDj%= z`L3S&hR&z}R8m90F<)^Kd`M?UqEfYgPjONcrA{g+hc7T=2r_c2`^CI3?dBBj;~;pB z?lYdm1Re1?2ht@L@&AxLpMONP6;SkK84Cu&>X%DVWRlAEP{RmHr~3x2W3aX*Jg|w2 zh7Y7p+fPGeu?I2U@!?<$HL=0~czMH{op!$_m1{Teico>2&O^J9astHi!}U-no6nxW zVkRzTEabawzg^mictrVc`r&Wj@QsnkCJvbx@qHBYK-fvE*jjhBA%F12BpHPe04)gB z)dC8`o?;*$1?PAY!SAn1MgD1Ey(JmJ0iE!j#>>ZE$am;E^u%xXCvVF$POkC~0pbtz zyCq@15W{tEt^(veI>Vc)%BZ^L1KuzrTJ&Zdf=HM!;@eX(Xyf)aht-T%soHzC^D5G2 zHW$+8Q8BVPQ|tUWbAQ+pwv0Bv$;<<9OFJ@zFAw>rV>$X-awFHcL(dIx-r3bXL~@mO6k)M#x8yh zk!Ooc{}LA$km3_@Z^b1;iXaj=CVE@{ z&d9-h_v4EiMt?x?BrA%TMw-Y7Xy<@~>3h(ID(AP=-aRA`jZt9FCUNypRkT9wW_uf; zF%G-!oC6ET%rt&bOTG*B^ut1wU7rVIl9)L8VWg>Qtn1!8zI0fHrrlM4F zCzK*B9V}h-y>cu2N&qLx7Q-%Cr|Kb!AgWf2dAgIivgBXMl0rs3YI51xskg$f5maSB+99>#~Sq+-&tRzQ6T%6U(oT=Zm-0qV#0pdhieBJG_gAMJ(AYk7s zg6y_!!_{_<93xi;*j(krX`oG0Z_MTe`qinvW>Au$D*{5PvGG{K;;Di_i0C!Qu(QGe zbeiH@L5MoeajYm`e=6Sk916A=wF-{WE&G!aYV0y8KEX?<8*{oHi1uHo9~Ih(1dRwY z+CRQQwW zgZSC|fnB+*Cn7t26dV4)U7)pr0u762i%*w+Xko{0jeuXK0^_>~;N|jMPcS>TL9#u$8N(eewV()>4u+AS zl!lJ<+>}bl4}t<#w#SZOJKYtq!V5t!H?38C4Zl3;JRmM)W#4%*>k`7e(eSYe!GDrW z1sgp+Fw!wPFKi7OJnMd+$XPZhF}X;5On)Dd@4MGeZXiW&4rz8nl^XB4P&cRP*3veH z{VO-N8V74Q1u}*zLp8; zZl2!=3;tUAebLHLK`M^}p*qj6X@5Wz^;XE;gp7lM1BgEclrU$qFAOYls@}WX6N>ld zUePyJCbCEqir)sH76!^Nu6FiiT|w;Eo&7M9%7$qU@j~U9gln?wmar{WFqB;F85#bF@3JAyh<&r1^e3I4`iL{hYE#IMDOvc{k}$ zc-eD}Q74dKNVIXl&wmDZP56$s>WIn! zaqg++SMjCHdOjDLkX|Z&ZvM(NMbcOFdUK;$WOWXl@lr|g!^z^68pg68HH8WS8$ln4 zt+z@LM)l-{aYfoNlM9y65iDmMoCX}*2cP*DBJS7?6V%ncD)u6NM0O6W=55z@=qiW? zM%ly0+=0@JoHSdE*nc0o2J?&?wAbhNuQc4rXL_LZ(wXoSR0PFQlgG}JuHQqJ@;*hO zUP*its*yDwam$iQ75v0Zflrl!-XsD!=a$0Wvq%{)YO?$c%16{@-1aX=U$TlJUE^bD zerR>;LPfH?$U13ct*y|lhMS;bMa^0iNYQMJ+TKtZ`5os{l7C9vrV5u;KU_jReH%~P zh-XwwaYckRph3LG@#RHd5V19;F93zAhx@Q*gmrYz|4@=VFLMG4lTM9q`(FYfbad> z!r4cO-#yNj_(g*$h|K;(x{C)uGOev(R~A*M@Z)QJb4>+Z-S%%3@#>gHL`-mK3RJOQ z#u~e%oo<~fb3-cR!=;u;7f#Icd+ncLyw34deAcB_6-$riF3ACC9uN8NNq*e}qe*X1_QJ!Flmf#h#Y4=U10`XSZbPdJM; z2VL8;M%|S3{Igfp-#@KOx9EorH&6@iHdMiAoeid^Tq>e%)%vUO)$Ir$XPwl#FkX$ zq+wHR_YnqESQOA{x+I@Zz0KALp8<59#-VpIuYXeUv<@AL{rnT0{k9-jbL|UzI&ipR zG=2PdXAw^~^W5-vWqFT%=V6B|K4`)#J`UU)CEbU?Z`VM)){UUse&+!W8zE2aeW&oG zdJ&aczFtmmIUNrbgug^D5HOCc#yu8dmwob<~q3Ln8cK7ju()A?sN+$o;E3#CZ4PuI&J0nF60j_J?5_7sy(rK7jN_t=5 zG{onx7nD&e+f=t7_Ua`)HK@;P))f*7&$4A8EF_5bAzZyOr-+LzinpEB-wcLGqkr+9 ziYZ`@Yy=R>FpCR)qj?C2Har@mSXokc3ZjdKQ;M<*iuVRO&ZNcSxNmV(cE#AsX7*hQ zB%Z0LtXV#O#<1KYrJN{XIL}K9a8fk7f;~Ty-CEl;9A$+C4oaY9q&TW2AGA<080#|8 zmV`m3(jJZ-$~uz%=J(WgcQnQ+l79?}Qelkt)oIRuC&tQTY6|X9DH|7{ErVJ7-GS!k zZx(|yzCg|tT{i@c2i*+O-PuXF-7jR69lWB=Qt9;`r1;QD_ISn17uH`PDhrP&k1%*v zl05UVx7lg!q@w0Lj$u<$`I8?PUpESOs!iee`Km@zT7n23@1$mHjk&R+%xzDkyM7sGZ#v_Sc!Gt{i%?|-Y5b8u+z3tktD z)kvJ=;aJdbI)yqS$A4tQW4`MO907}F5I`oeuIrN zjk48&P}HtF(kQ?-bp)`JV;`uKnlP2ciL<8J#BRNm#;)W7q_qu}72f!6U>Yy-=a*&R zoj2ESaCytUxkzoG`35S>G}ObyeXPTe>|Gg><(N7qmcZ|$VNaP5#1bGTG+k@B#=2ohW#axN^9uq1kB8$Pv9OKY!%HG(U5KR{yd&Lzg_ z;O^&{QU_yEdTg7%o-g%O0HN}Q3{%k5I|=%&eR~r{y~Q!=7u}GV`zM~#)lLk^D+qtz zFMl2P3N}xCd=ilXx%vdgZ6|SCuPu`u`8UWkyjzNH!^{#vy7@y;ee-@>@tK`tdN-`s zAGs;9yjg6tgqja}#I7dkV`r9bs@ArNs+4zLo!mX#&tcg>HA?5Z*rw?+>@?TNrNtFP z<;HMUU+PF63!WvBB0Yn4GzQ*vRv$Z>BYz}Pl8y?__mJ@WU*D2kG6hJAeoax1)qcLU++5xjLqF{%4rGjdM`C*J zkXj0Eg@YH7Y(5)CFfoBb+#mT)OdRIn&pWbB0XEm$Bf4m5lq1+LR=7>r?B6=FpMMaD zyH+l)?mU%b)?FA)S89rLhm$N-cd2-D3{M%7ie-ztK=w$>JWJ5SyT;o7@<~@g@<*Al zGuMy-nnR`HSw=3iQDw+1znnI>907L*qfh?%B3p@?Xwoy#j~U_#pc{`Kj`nxe&f{Jb~xwYl-9Br_3u6ckn3h=M;N2i zi_!~av{y_MA{eAS?HcXHnGAs_2_%T@N3&A_G}utD;8e2C8ey487`xN3a(}kC`XP2K zWlw~WgXijF_YZ1OdZ!753BcoCK(S|Zqfg<6)=e`cWdV;h@tR9Si}E`j;j zo-6~SWDC+nk>KJ|ECP9vcrh*yh;i?944%YCX&J+%F{&b*Y@rJ!so1GvQ(25S;%+nb z!iLtlZyw2}%`}Kfq%DFu3?E`)SwmXFk4+*k%y{$2&yYq^PY)KEiFk6^jh&& zt-9L_b=WS&?F1|%K* z=c>W!^fmfL@Zn)p7JmWN5zGlp#7XF3?;113y$>fCOOvf1P&vO5Z#X{|)s2W)Xe5Ha zE^2UpJt*zM<4DMmwf$Yn!Pkb8?&R^nbxQt;+m%;4`ee6-&Kxy8uT0ug#nzUaD;I(* z$ALKuW7?~16*Ij@yEtMmU^C|J40rQWxw3!oarf$(CaoJck$?HG4;jpy9^G%@fM*qA zPF$*dpIfc3xB``!zxQf-;rJM-mo(s$z|g%{9tNG%%L>-zPNM-GtAX~8Q<3iFyP16F zgJS`M9&U9I@Aeo`l}8bS#{?hZei;rMvZ260%{W-Ez13j!kVtIoiU?}j`Qb<;B1KSX zDLRz+-w)~b`hOGV6DIFH&g@q~M$r6D#H-4vYkLuKfafe+$YijS0v@y$=704s=>768 z^gZT6Yv`u<8@UyXX8x@a?C1FbiH2^qAh9WIvT7=L&kOIH?+hap+U_6v7~SSsX7 zkU+_##LnA9y%_2=G2hI4^F@*!5O&$@-(0aXZm6E_Zen7y(wfLd3z^mdE*v@R+eD-X z_nZ~u%cUKGNX~UsLuKW&C*r&x+8g@bU;7G2PEsVVoBVVb7QzOIKUwS@#7;^(Dtr(d zT#G-(rhm$WK6@F-gM}4A>EFr15A}L!zdE+p(g?gcJApEAnOCCR+PhU6#{Kkp=j?bC z{DF*uU#Y?crsdk<4fruX?M|>R=i{2s3t_g*U~u8;YJnJSzqYFbYnsgg6(mAU3YvFM;2zCK!_n2(>ua688Fsr zo0g*)h{2{Ahs4x?iwp|3Wh5C4$DyMpgpkk|hzq6!FeMx%gwR4T&5%ZiP{M_pKtc^2 z?#<4wv^xW*f51;OZ{EClb+o_zR))RyxZR@73x>WI|5>Q@vT%+sp3$O`e_y-MvfR#A zo1gysR+G}BZN3}*+>?E=+WR*DnOo=2oxQ|12$|yS-)C{Fe%F@v5aO%1Z1cv!PkLpH zk#@A}5xX*GW~V=PFaPQLwi8+oIPv@YRTkBpwxsL#2_aR!>Rr*dt!P|cf9w5YFUsuq zEgoKJ;qAsXj%2rQm9YQ9&83Oie;-b5ai!pyU&xypy|!NS?8z6zljpar?()2}=g7;6 zo0O7}Ezd`^cE-*fP$_b9<+$4`zH#xV8dbUcntR+2f1Qr(J!#k2JAJOi^u0c{Y*=#T zRrllA;@|q)Z$(8OKl7hIt{3cWwKk_)?+v%YI}Dk+WS=L0+^2007S3&!HE-I6ef8JP z-dU?()0pxeJNMZ0^y?CBy;vGdyZk8e!PJ-O&0+ilIycN)!_|3#nY3%0N9JtVB} zng#0*@%fu)=Jj}St!MdBTtdv02`g7WSaB}#bf5I>Yo(#>_FRj_4{kZ+JR?MupW???*&uok{G}s7p!gwZ(5-c~aub>hnz`}4O>tNE~f3F`9?}&C5Et`FDu-|d`>XF^;r`!&&GHFJ~2EVrdwBz|s z8(;4_Z~B0l59%%{JHU74>q9$c_WkSQ(G&0YeN^>?5OSs3S&w7x#A3PCr|yf)w2*6$ zM!y?VP@qWuML)|A-YdVcYFxV!6C2h@*>q-E;goIbZ*)s3{qUbfN6v)R3ri`pbIpj$ z?>q>plj|s`9hy7M-}v0QG4W61!^Y2ynRzqpcE9GOU!8t7!R9WLUsM#li#Ff2#l;^veV}x5l`k(3 z{dUfjPN~N}|NY$A^G{oKjeU~3vFn+?Ml2k;^4}N74`@GX#r(lP@Bb;m-*E7Df0_9O zmax&W`8mr&I<&548<=`%Vr=;1zEAg5x$4=!qHy`&ZHsO`xU_vnTt@px1Jdt|-tQin zup?&M_OMOYF5f)8^InhDLc0#1h%t{GQSrO(D1Yn~k*bNycZx?%scZ5_IBSGRr% zJ!+JeY`aoF^kVZ}RmYX^TXTyCoewYA-SDevE&KU@%IjBmblcP~m)f6>Iy>%E{o7+t zJ&UQ8{q5ev&udo*d2935lFwr!_jkXWbHSJL+Tu#ngcbeA_Zy$mW8{#FB|}QRnTwJK zhBq8FkBg|}ntoz(^E;*xp(#H6t|(? z;T=|2bzffB5MR=@klL=533qo+-BdR1+bv^m4moh^K>e>is;Nx;1h&^8X{DWMuweRB=o~y_DJ$W|yMcvT#QwPK}OdTVh+%xXu zPAjiZ5(}yqPvA;V*FEs@ch2VXFS@Qwy|8uVghtbkm4CNSm;9&!hn_$BsoKv8lQtF) zz5$hU+K;35e7SDwf&cPLm)*MDZF1*ZPd9crcde4Y;QH14u$p6g!wXbXFUI@sh4eW7 zcyaC3sVAKNweO7Wy5{1ZMmugF?wfUaylW}{sqJaTpOsQ3oJ|Uu*=66-F@HD65?y2K4N+O~XUp&0MC;jG0 zr&3h!hgs}~kGD$U{$2ZyNeRD<;d^!;9RA|ZzjOZ4Y1i~kS;8A%re!rLBiw5+Cv|0` zra$)?dSCc9ZSC3PGbZ0zQS1BXWsl~4oHT9ift7_%vWnvWIJ53W^amd`{mIi{>O{Xi zb#1d|cUF8jEWcps_CX7KO^QDDc6CYK%&9$_`1$mR##7cGsqo$1eo#X}`_*~tPCbjPF|X3Q(vLHXMpam9DazhGv1ZQlXM341w*Nlw zRQ!ei44P2cRd}1CQup?*ptf$}PHf_-0$=J)@PPGP(xiKg8->!Y@^1iqn<{5r_c-c)% z{TC^{!(%OtEa}VNdgJp`pC!lTX3np(y1G|taq>~^{@spVDs!su?x@3&);rewlfU*K zO{#a#nq0fx>pM&cGS{2_e$da9rBWYP5N}`*+=}L&QXzby0m%Nar~M?H+Sa# z+T!a2fC_=W?IW5jsypF&ROzF8U(AVFTy@q5DH{_S*PY?G z{i4j|OD@cWbnB9&^q$3BD4(1&R&Frn7mXeX-O!q~P z%yIji@Q24WY`9PPV>a`CHSOKz!IzTTIc^I;6SZPOqf-K0KAFo5swV~Jzl7QKxlG+T zAC<3&o^fxcKONt89upA)kIfIA$3!;MU(FuC%Yc=L7ox+9@6mn+hX}kM?f(3&HNSw z5xOBTR@)Zl{u0^I_at`>=>T!p01;j;x(;ihG7q(DfE4Z9&(5pSK~t-abpgC| zNQ_tT(m)e5LFd$2(4eEnLr2y?JTzs!f`=wJ<^k|VG4pHt4QH%_c_2obUS7dSvjB|| z7R_)bs-+QH(;-QKIp9oykz$`{rUnb`Of-IERO19$8JWj4d`~?~i#5*Y%xuj@T3C!< zq7m#s!009#0pRgiEk58WJR+zY(?$S39xHLm!qrSYB_yAz79!fvLRFQP`AmZ*I9gd# zlD)1}7>Kb(EY?(aMp{&g+wF_A@Pd+=&(y02I4vm7Skqh{XR0qM)t#A{oR#K##n=KSf{~T{0;X0iO}!(WV^ZA7p0p@u z>Tq|YMdX!Qg-m2`O;4HbQO>|-F+7b?788G~aj;n$PF0;h%jp~K_KeWZgvBT!7Hbxy zYS0?S>Cyg-0;{oO6dsG!o$d4_``jL+S`3f^v>ab{jxWmRj>-o0MOw4~Z_Q2~=2T5i zwN0b2SxrpK>m$vQ^2+Wark0iAL3~i-TWT0U5C5-~I z~J` z0ggFY-kfY?qs}zrD4f+{R8Ce@HkJ%_tj1f5)eFH1LJ2U#rDTB8q8tvVN~5Jr%gXxp zwcX1~qh(BeKb#~6@e0mr&4SJ_ewUF5Mu4%=j6^s%703*tq$WlSfGY-~7G;A(I6@2% zW;`OV61IXV56%OJWE^U;X33_C+7J#MV}}{X!pURQFpI)1V;Z+YfK_VH4zNRxXVz4U z)^=FX&MMEpU}}Sd7#D|c%!{*V@p@2Z0UKOu8J4#r<`_B4NJXBFYX~D1)PiBIj6~$% zx^D$V29a1?nrYfn-dw>{f}fR5qKbs5iUpmh9aN$xwIE02<+_UnsmRkYjGRFxkRI1B zMjG;X3@c}(BBfwRs=%o#6;?160sYD-DaR6$a#*PxQlFj`15$BF04**CiE3;l&z1xA z;rh!c6=)Baibf&`1c2DcHcXVXX0hs7fe0evlz3DQ_oqDyWi<;MLobnc6$jIA^1x;5IrAa0&E!p&Z&V0Q;>P;-i;~9voZLdMOy>e zrCzq-G00Uhl%P>o{2j8(n))!aa5%+;`Jm$)qt~$z&1*{U)lAI>Kvb1%UQ_3#+y*x7Ra@6RY2lzO zRBP|-Vy2v*C{5HHK=9QP5T{itkeN09*orx=AK-8sV3ZmcLZH{60TKbc1E(4kv7**L za9Z2I;o`xO)QvRU7ZE23~v?L?}}`b&|U#KTd*1d9{;ORUD-jUF1|v#W+=3 zu<&rV;!qZ>W;!%iTLpbe7pE6$d`^QU4fbg;`1xukB0|5b>7C}CRiUBLy^=GX zXr|I>4I?v-E#uZO#Y}myO_`TiUTM9KsT=&O&pKup<50G)W9*OxEjIMAWLZMh|JZCI zO1}inff^BlCZp(QrhyAV-A&L`3{Qf_qj(A*NR)wvp)7{#iWn%NfM%vC>^|uHO1@;O z`=O|%WsnhWp>YaplR0FOMw-nA0U1u!NP}@UQXfDQ(A}JI9LyDw1>5{U4a(1pD2$l~ zLZ6E=l!*oq@~Fi&(|8+7x@MZllN+%CP%0|U^l@l?5Ju+clK@~)lA#T-CaKc_^hkPl z0*WT+6WkoYT@u=|*?7N%vbuR7&(Ws{K(h2?0pY3=a|INLOf=XAx_C6vY`loI3i}UA zC<>_VFb@=MG>vzl3mjsc+N2RQJ9SJpQANQGjKlgDRdmw;5&g#|awy!Qk3m2lm1`u8 zJ~{_TO^$P@kjBJZ(T`9^%|wS9U`#X~;5n&<9XzTMP2+419#t*`O`seQ8eZW?h6||DGt$6x)Eg%w4P+N-ACN^)Lfah+I1~Eif&;$*tTWTke2Pk1U2*}i2nX-2~C!=c_bzQ$6-~r*9 zQY+9Y*UECcBv5GqiV@14 zpgyD$wjEqHz)q^JW8sW-^;@*O1w_&^ZICZ1!{nglCEXMB zLPa>x0=j=NX%LX;(dCJm=I7|r0~Vp`D(D0urW2C|x`W`L1194FEI|t`K&=b>kp2Uf z4o_jAe$_0YAgKw?G)|JKdI`lST0jR8ZlQjWz_){IVE^MJNK!$fDgn??J8l*R!Z&H@ z92hkrG`O7uT@aY(%EC)%eyS+4aSpYjA|^xGMls~58is>jjSOZSBwI3Kaxq_cMW8NlHsTXn+8E9ZKPnDH0jugW7Y%o~%AVgTyv0LUog@ z4XQwci=pwbhJ>zI(Z?`Xmi)x-Pzy%od>%>~vasOoxbQVGgm_D++QxHsDpv3u#9J&( zu>RxWHj*$9m@HHAo98(y+wpK?K+T0{OVJ=jnB5rk&kJC3q-vmqqb7r<&68m+Tn6&RDwFBmce=z&Pj6&yU(eF+Ycwnc|bl>>rIUtYo88quRe$Pi?@k``^y z5)+Dqd`@L$(I!#0E!v<)Am_pl(qsq{A-=L?$Pl68COr}!P^1@u%PV@EL|sOT99+7Q z!a&5Xjg6dY6y zBZ97}-9bk{9Ua)TzT?0eq72<3O4)|k0_6{NtqQ(JHPfObQHfQAqMkZ;hn=<=V@B6Q zhUfsZCe;eJGL%}uwrCpNCWx|3^|=ysL8Q(2AvKbh*H20>0ehr5bb2_2O4pYk6H}7NG436ImljBm6@<3puzooa3kvZ1CeTe zfkqi7&>ZBo5&VitT_phx?&yMxAQuN3)MymVZ%E(xwgm<{$RZbLGQB&v1tjbPx)Zo7 zAQyp}gQjV@1oj_Pzd#j5z)&z&>poAiE5qr5XUHwl@3_V~;a6lSG&&KUn}z?uj?n|a zaarkZ_zOf+|LS5H*tQEF3m23QTdd?@JK1b+vs@>*IEfKiG4^fYZLxD~d&~bBqYW8s efgicyxe$*p*W*kNW#KUfRtjy}^zGiUq5lIIW3Kc7 delta 64024 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 It5?=O2c~lY$p8QV diff --git a/Doc/RomWBW Applications.pdf b/Doc/RomWBW Applications.pdf index 4be462cf4a0e95cdd8cdf2c392a1815d3da1e7d5..cc4978a5037d986b181f0b4fbdaa460263903a63 100644 GIT binary patch delta 160 zcmbPmlVie7j)oS-Eldea+C~P3mL_JVmbwP!>IMetnq2z6`6(`mC8-J;E>=bcMurBK zFeTf&nV6PpCb(EwxR@F{nVC8|nVT59I+~lfnHxEoo4UEWn3_5nTG%Pr5L6PYU}wiw bT#{H+Qc;we#${-1XkloIMetnq2z6`6(`mC8-J;E>=bcMurBK zFeTf&nV6PpCRn%`7&)7nIGeb-nmd}gIk~u+SU4M4x>`7zJ31L#7~3h>5L6PYU}wiw aT#{H+Qc;we#s##&!q9?CRn^tsjSB$%{U|R0 diff --git a/Doc/RomWBW Architecture.pdf b/Doc/RomWBW Architecture.pdf index 5602cd8885ae4b47116ef280a7cec322292842e2..b8bf2c3c67a854455788c9be7dbc97f9f4ef099c 100644 GIT binary patch delta 176 zcmezJPU_1$sSWL^0*Q$xrpcCuW=7_g#%5{e2F=q`w@*)HOzp&wY3F&*2*gZ4%nZaV z+j-uzo@wVWGBC6>F*h)o{-BIa8qV9!T+Sxw;B0JWYXD5fBBM88qV9!^NKN4G{M!y!pOwg)!fC&+1S*= z+1$<9($v|+(a6Za$;rUd%*jr{hM%@me>W}w DN}(n7 delta 137 zcmX^3pZ(x}_J%Et4_|T^8XFp#7@1m3fBBM88qV9!^NKN4G{M-|%+=J<*vP`n#nsiw z(bdw}*u}-g$;HUc%+12w+{sSChM%@me>W}w DLNg`* diff --git a/Doc/RomWBW Getting Started.pdf b/Doc/RomWBW Getting Started.pdf index ffe2308039d09065f6265022db4ff5f3b635b7cb..a233805a60b457ad0cf3e0090bfe24ed8a7d1010 100644 GIT binary patch delta 139 zcmaFZ!TqpvmEGnreN=@T3G_$ZYGUifMb@g}S F0sv*@BmMvY delta 139 zcmaFZ!Tqp-vU5(5P-OMZ;4UCMOj2#W_6l@48iB+((<0>vmEGnreN=@T3G_$ZYGUifMb@g}S F0su>GBZvS1 diff --git a/Source/BuildShared.cmd b/Source/BuildShared.cmd index fd88b2c1..df961d93 100644 --- a/Source/BuildShared.cmd +++ b/Source/BuildShared.cmd @@ -1,6 +1,7 @@ @echo off setlocal +pushd HDIAG && call Build || exit /b & popd pushd CBIOS && call Build || exit /b & popd pushd CPM22 && call Build || exit /b & popd pushd ZCPR && call Build || exit /b & popd diff --git a/Source/Clean.cmd b/Source/Clean.cmd index a5e88c6c..6f2cf842 100644 --- a/Source/Clean.cmd +++ b/Source/Clean.cmd @@ -1,6 +1,7 @@ @echo off setlocal +pushd HDIAG && call Clean.cmd & popd pushd Apps && call Clean.cmd & popd pushd CPM22 && call Clean.cmd & popd pushd ZCPR && call Clean.cmd & popd diff --git a/Source/Doc/ROM_Applications.md b/Source/Doc/ROM_Applications.md index b6db42b1..ca8090db 100644 --- a/Source/Doc/ROM_Applications.md +++ b/Source/Doc/ROM_Applications.md @@ -355,7 +355,7 @@ ROMWBW contains two versions of ROM BASIC, a full implementation and a "tiny" BA The full implementation is a version of Microsoft BASIC from the NASCOM Computer. -A comprehensive instruction manual is available in the Doc\Contrib directory. +A comprehensive instruction manual is available in the Doc\\Contrib directory. ## ROMWBW specific features diff --git a/Source/HDIAG/Build.cmd b/Source/HDIAG/Build.cmd new file mode 100644 index 00000000..a3d35a56 --- /dev/null +++ b/Source/HDIAG/Build.cmd @@ -0,0 +1,19 @@ +@echo off +setlocal + +set TOOLS=../../Tools +set BIN=..\..\Binary + +set PATH=%TOOLS%\tasm32;%PATH% + +set TASMTABS=%TOOLS%\tasm32 + +set ZXBINDIR=%TOOLS%/cpm/bin/ +set ZXLIBDIR=%TOOLS%/cpm/lib/ +set ZXINCDIR=%TOOLS%/cpm/include/ + +tasm -t180 -g3 -fFF -DAPPBOOT hdiag.asm hdiag.com hdiag_com.lst || exit /b +tasm -t180 -g3 -fFF -DROMBOOT hdiag.asm hdiag.rom hdiag_rom.lst || exit /b + +copy hdiag.rom %BIN% || exit /b +copy hdiag.com %BIN% || exit /b diff --git a/Source/HDIAG/Clean.cmd b/Source/HDIAG/Clean.cmd new file mode 100644 index 00000000..c9c917a4 --- /dev/null +++ b/Source/HDIAG/Clean.cmd @@ -0,0 +1,7 @@ +@echo off +setlocal + +if exist *.bin del *.bin +if exist *.com del *.com +if exist *.lst del *.lst +if exist *.hex del *.hex \ No newline at end of file diff --git a/Source/HDIAG/Makefile b/Source/HDIAG/Makefile new file mode 100644 index 00000000..18895f67 --- /dev/null +++ b/Source/HDIAG/Makefile @@ -0,0 +1,20 @@ +OBJECTS = hdiag.com hdiag.rom +DEST = ../../Binary +TOOLS = ../../Tools +include $(TOOLS)/Makefile.inc + +TASMFLAGS=-t hd64180 + +hdiag.com: hdiag.asm + $(TASM) $(TASMFLAGS) -dAPPBOOT $< $@ $*.lst + + +hdiag.rom: hdiag.asm + $(TASM) $(TASMFLAGS) -dROMBOOT $< $@ $*.lst + +#cbios_wbw.bin: cbios.asm +# $(TASM) -dPLTWBW $< $@ cbios_wbw.lst +# +#cbios_una.bin: cbios.asm +# $(TASM) -dPLTUNA $< $@ cbios_una.lst + diff --git a/Source/HDIAG/acia.asm b/Source/HDIAG/acia.asm new file mode 100644 index 00000000..c69c5f6d --- /dev/null +++ b/Source/HDIAG/acia.asm @@ -0,0 +1,70 @@ +; +;======================================================================= +; HDIAG ACIA Driver +;======================================================================= +; +acia_cmd .equ $80 +acia_dat .equ $81 +; +; +; +acia_jptbl: + jp acia_cinit ; Initialize serial port + jp acia_cin ; Read byte + jp acia_cout ; Write byte + jp acia_cist ; Input status + jp acia_cost ; Output Status +; +; +; +acia_cinit: + ; Detect ACIA + ld a,$03 ; master reset + out (acia_cmd),a ; apply it + in a,(acia_cmd) ; get status + or a ; check for zero (expected) + ret nz ; abort if not + ld a,$02 ; clear master reset + out (acia_cmd),a ; apply it + in a,(acia_cmd) ; get status again + and %00001110 ; isolate reliable bits + cp %00000010 ; check for expected value + ret nz ; abort if not + ; Initialize ACIA + ld a,%00010110 ; default config + out (acia_cmd),a ; apply it + xor a ; signal success + ret +; +; +; +acia_cin: + call acia_cist ; check for char ready + jr z,acia_cin ; if not, loop + in a,(acia_dat) ; read byte + ret ; done +; +; +; +acia_cout: + push af ; save incoming +acia_cout1: + call acia_cost ; ready for char? + jr z,acia_cout1 ; loop if not + pop af ; restore incoming + out (acia_dat),a ; write byte + ret ; and done +; +; +; +acia_cist: + in a,(acia_cmd) ; get status + and $01 ; isolate rx ready + ret ; done +; +; +; +acia_cost: + in a,(acia_cmd) ; get status + and $02 ; isolate tx empty + ret ; done diff --git a/Source/HDIAG/asci.asm b/Source/HDIAG/asci.asm new file mode 100644 index 00000000..d5dc8bd0 --- /dev/null +++ b/Source/HDIAG/asci.asm @@ -0,0 +1,89 @@ +; +;======================================================================= +; HDIAG ASCI Driver +;======================================================================= +; +; ASCI0 is programmed with a fixed divisor of 480, resulting in a +; baud rate of 38400 at the standard cpu frequency of 18.432 MHz +; +; The Z180 may relocate it's internal I/O to begin at different +; starting port addresses. This driver relies upon an HDIAG global +; variable to dynamically adjust to the right port address. +; +; +asci_jptbl: + jp asci_cinit ; Initialize serial port + jp asci_cin ; Read byte + jp asci_cout ; Write byte + jp asci_cist ; Input status + jp asci_cost ; Output Status +; +; +; +asci_cinit: + ; Detect ASCI + ld a,(hd_cpu) ; get cpu type + cp 1 + jr c, asci_cinit1 ; less than Z180, abort + cp 4 + jr nc, asci_cinit1 ; greater than Z180, abort +; + ; Initialize ASCI + ld a,%01100100 ; rcv enable, xmit enable, no parity + out0 (z180_cntla0),a ; set cntla + ld a,%00100000 ; div 30, div 16, div 1 (38400 baud for 18.432mhz cpu) + out0 (z180_cntlb0),a ; set cntlb + ld a,%01100110 ; no cts, no dcd, no break detect + out0 (z180_asext0),a ; set asext + xor a ; no interrupts + out0 (z180_stat0),a ; set stat0 + xor a ; signal success + ret ; done +; +asci_cinit1: + or $FF ; signal error + ret ; done +; +; +; +asci_cin: + call asci_cist ; check for char ready + jr z,asci_cin ; if not, loop + in0 a,(z180_rdr0) ; get char + ret ; done +; +; +; +asci_cout: + push af ; save incoming +asci_cout1: + call asci_cost ; ready for char? + jr z,asci_cout1 ; loop if not + pop af ; restore incoming + out0 (z180_tdr0),a ; write byte + ret ; and done +; +; +; +asci_cist: + in0 a,(z180_stat0) ; get status + push af ; save status + and $70 ; line error? + jr z,asci_cist1 ; continue if no errors +; + ; clear line error(s) or nothing further can be received!!! + in0 a,(z180_cntla0) ; read cntla + res 3,a ; clear efr (error flag reset) + out0 (z180_cntla0),a ; update cntla +; +asci_cist1: + pop af ; recover original status + and $80 ; data ready? + ret +; +; +; +asci_cost: + in0 a,(z180_stat0) ; get status + and $02 ; isolate bit 5 + ret ; a != 0 if char ready, else 0 diff --git a/Source/HDIAG/hdiag.asm b/Source/HDIAG/hdiag.asm new file mode 100644 index 00000000..9d37a523 --- /dev/null +++ b/Source/HDIAG/hdiag.asm @@ -0,0 +1,588 @@ +; +; +;======================================================================= +; HDIAG Diagmostic ROM +;======================================================================= +; +; HDIAG is a framework for a diagnotic environment intended to be +; suitable for all systems supported by RomWBW. RomWBW expects hardware +; to be fully functional making it difficult to use it to initially +; check out a system. HDIAG is explicitly constructed to be as simple +; as possible. +; +; There is only a single variant of HDIAG that is built. HDIAG is +; designed to detect the environment it is operating under at startup +; and dynamically adapt to it. +; +; HDIAG can be assembled to boot in one of 2 modes (rom or application) +; as described below. When compiled, you must define exactly one of the +; following macros: +; +; - ROMBOOT: Boot from a rom bank +; +; When ROMBOOT is defined, the file is assembled to be imbedded at the +; start of a rom assuming that the cpu will start execution at address +; 0. +; +; - APPBOOT: Boot as a CP/M style application file +; +; When APPBOOT is defined, the file is assembled as a CP/M application +; assuming that it will be loaded at 100h by the cp/m (or compatible) +; OS. +; +#include "z180.inc" +; +;======================================================================= +; Page Zero Definition +;======================================================================= +; +; Generic page zero setup. Only applies to ROMBOOT startup mode. +; +#ifdef ROMBOOT +; + .org $0000 +; + jp hd_start ; rst $00: jump to boot code + .fill ($08-$) + ret ; rst $08 + .fill ($10-$) + ret ; rst $10 + .fill ($18-$) + ret ; rst $18 + .fill ($20-$) + ret ; rst $20 + .fill ($28-$) + ret ; rst $28 + .fill ($30-$) + ret ; rst $30 + .fill ($38-$) + reti ; h/w int return + .fill ($66-$) + retn ; h/w nmi return + .fill ($100-$) ; pad remainder of page zero +; +#else + .org $0100 +; +#endif +; +;======================================================================= +; Startup +;======================================================================= +; +; Before transitioning to RAM, we need to determine the memory +; manager to use because some platforms will not have any RAM mapped +; to the upper 32K of CPU address space until the memory manager +; is initialized. +; +hd_start: +; +; Discover CPU Type and Memory Manager +; +; Some of this code is derived from UNA by John Coffman +; +; CPU Type: +; 0: Z80 +; 1: Z80180 - ORIGINAL Z180 (EQUIVALENT TO HD64180) +; 2: Z8S180 - ORIGINAL S-CLASS, REV. K, AKA SL1960, NO ASCI BRG +; 3: Z8S180 - REVISED S-CLASS, REV. N, W/ ASCI BRG +; 4: Z8280 +; +; Memory Manager: +; 0: SBC/MBC/Zeta 1 +; 1: Zeta 2/RC2014 +; 2: Z180 +; 3: N8? +; 4: Z280 +; +; + di ; no interrupts allowed +; + ld a,$80 + out ($0D),a +; + ; Use H for memory manager, and L for CPU Type + ld hl,0 ; assume Z80 and SBC +; + ; Test for Z180 using mlt + ld de,$0506 ; 5 x 6 + mlt de ; de = 30 if Z180 + ld a,e ; check if multiply happened + cp 30 + jr nz,hd_tryZ280 ; if != 30, not a Z180, try Z280 + inc l ; Z80180 or better +; +#ifdef APPBOOT +; + ; Reset Z180 internal register base to zero + xor a + out0 ($7F),a + out0 ($BF),a + out0 ($FF),a +; +#endif +; + ; Test for older S-class (rev K) + in0 a,(z180_ccr) ; supposedly only on s-class + inc a ; FF -> 0 + jr z,hd_z180res ; if zero, pre-S, HD61480 or equiv + inc l ; Z8S180 rev K (SL1960) or better +; + ; Test for newer S-class (rev N) + ; On older S-class, asci time constant reg does not exist + ; and will always read back as $FF + out0 (z180_astc1l),d ; d = 0 at this point + in0 a,(z180_astc1l) ; asci time constant reg + inc a ; FF -> 0 + jr z,hd_z180res ; if zero, rev-K + inc l ; otherwise Z8S180 rev N w/ asci brg + jr hd_z180res ; go to Z180 reset +; +hd_tryZ280: + ; Test for Z280 per Zilog doc + ld a,$40 ; initialize the operand + .db $cb,$37 ; this instruction will set the s flag + ; on the Z80 cpu and clear the s flag + ; on the Z280 mpu. + jp m,hd_z80res ; if not Z280, we are Z80 + ld l,4 ; we are Z280 + jr hd_z280res ; handle Z280 initialization +; +hd_z80res: + ld a,$01 + out (0),a + ; Reset Z80 here (is there anything?) + jr hd_cpu1 +; +hd_z180res: +; + ; Reset z180 registers here + ; Set CPU speed to oscillator X 1 + xor a + out0 (z180_cmr),a + ld a,$80 + out0 (z180_ccr),a + ; Set default wait states + ld a,$%00000100 ; mem wait=0, i/o wait=+1 + out0 (z180_dcntl),a +; +#ifdef ROMBOOT + ; Setup Z180 MMU + ; Keep ROM page zero in lower 32K!!! + ld a,$80 ; Common Base @ 32K, Bank Base @ 0K + out0 (z180_cbar),a + xor a ; Physical address zero + out0 (z180_cbr),a ; ... for Common Base + out0 (z180_bbr),a ; ... and Bank Base +#else + xor a ; Physical address zero + out0 (z180_cbr),a ; ... for Common Base +#endif +; + jr hd_cpu1 +; +hd_z280res: + ; Reset Z280 registers here + ; Make sure memmgr is reset to defaults! + jr hd_cpu1 +; +hd_cpu1: + ld a,$02 + out ($0D),a +; + ; Reset Zeta 2 memory manager (in case it exists) +#ifdef ROMBOOT + xor a ; disable value + out ($7C),a ; write it + xor a ; 16K ROM page 0 + out ($78),a + inc a ; 16K ROM page 1 + out ($79),a +#endif + ld a,2 ; 16K ROM page 2 + out ($7A),a + inc a ; 16K ROM page 3 + out ($7B),a +; + ; Reset N8 supplemental memory manager + ; *** Need to implement this *** +; + ld a,$03 + out ($0D),a +; + ; If SBC memmgr, RAM is already in himem, otherwise ROM + ld ix,$FFFF ; point to himem + ld a,$A5 ; an unlikely bit pattern + ld (ix),a ; write the value + cp (ix+0) ; check value written + jr z,hd_cpu2 ; SBC memory manager, we are done! +; + ld a,$04 + out ($0D),a +; + ; Now test for Zeta 2 memory manager + ; Start by initializing and enabling the page registers + inc h ; assume Zeta 2 memory manager +#ifdef ROMBOOT + xor a ; ROM page 0 + out ($78),a + inc a ; ROM page 1 + out ($79),a +#endif + ld a,$20 ; first RAM page + out ($7A),a + inc a ; second RAM page + out ($7B),a + ld a,1 ; enable paging + out ($7C),a +; + ld a,$05 + out ($0D),a +; + ; Test himem RAM again + ld ix,$FFFF ; point to himem + ld a,$A5 ; an unlikely bit pattern + ld (ix),a ; write the value + cp (ix+0) ; check value written + jr z,hd_cpu2 ; Zeta 2 memory manager, we are done! +; + ld a,$06 + out ($0D),a +; + ; If neither SBC nor Zeta 2, then we assume the memory + ; manager is the native memory manager onboard the CPU + ld a,l ; get cpu type + cp 4 ; Z280? + jr z,hd_z280init ; handle it + or a ; Z80? + jr nz,hd_z180init ; if no, do handle Z180 +; + ; If we get here, we are stuck. We believe we are a Z80 + ; but both of the Z80 memory manager tests failed. +hd_halt: + + + ld a,$07 + out ($0D),a + + + ld hl,str_halt + call prtstr + halt ; give up +; +hd_z180init: + ; Initialize Z180 memory manager + ; Put first RAM page into himem (commmon) + ld a,$80 + out0 (z180_cbr),a +; + ld h,2 + jr hd_cpu2 + +hd_N8init: + ; Initialize N8 memory manager + ld h,3 + jr hd_cpu2 + +hd_z280init: + ; Initialize Z280 memory manager + ld h,4 + jr hd_cpu2 +; +hd_cpu2: + ld a,$08 + out ($0D),a +; + ld ($8000),hl ; stash cpu/memmgr at $8000 +; +; Transition to upper memory (omit page zero) +; + ld hl,$0000+$100 + ld de,$8000+$100 + ld bc,$8000-$100 + ldir + jp hd_start2 +; + .org $ + $8000 +; +; +;======================================================================= +; Post-relocation Startup +;======================================================================= +; +hd_start2: +; + ld a,$09 + out ($0D),a +; + ld sp,$FF00 ; Stack just below FF page +; +; Copy FF page image to real location. Use a decrementing copy +; just in case page image is within $100 bytes of $FF00. Very +; unlikely, but just to be safe. +; + ld hl,ffpgimg+$FF ; Start at end of image + ld de,$FFFF ; To top of RAM + ld bc,$100 ; Copy 1 page + lddr ; Execute +; +; Recover cpu/memmgr codes stashed at $8000 and +; save them in FFpg +; + ld hl,($8000) + ld (hd_cpu),hl +; +; Probe and initialize serial port console driver. We just go +; through the options stopping at the first one that works. The +; order of polling below is intended to find the most reasonable +; console port. +; +; + ld a,$0A + out ($0D),a +; + ; Z280 UART + ld ix,z2u_jptbl + call jpix + jr z,hd_start3 + ; ASCI + ld ix,asci_jptbl + call jpix + jr z,hd_start3 + ; UART + ld ix,uart_jptbl + call jpix + jr z,hd_start3 + ; ACIA + ld ix,acia_jptbl + call jpix + jr z,hd_start3 + ; SIO + ld ix,sio_jptbl + call jpix + jr z,hd_start3 +; + ; Ugh, nothing worked + ld a,$0C + out ($0D),a + halt +; +; +; +hd_start3: +; + ld a,$0D + out ($0D),a +; +; Copy selected console serial driver vector table into place +; + push ix + pop hl + ld de,hd_serjptbl + ld bc,5*3 + ldir +; +; +; + ; Map a RAM page to lower 32K +; + ; Setup zero page in lower 32K +; +; +; +hd_start4: +; + ld hl,str_banner + call prtstr +; + ld hl,str_cputag + call prtstr + ld a,($8000) ; cpu type + ;call prthex8 + rlca + ld hl,str_cpu + call addhla + ld a,(hl) + inc hl + ld h,(hl) + ld l,a + call prtstr +; +; + ld hl,str_mmtag + call prtstr + ld a,($8001) ; memory manager + ;call prthex8 + rlca + ld hl,str_mm + call addhla + ld a,(hl) + inc hl + ld h,(hl) + ld l,a + call prtstr +; + call cin + jp hd_start4 +; +; +; + jp hd_halt +; +;======================================================================= +; Helper functions +;======================================================================= +; +; +;======================================================================= +; Include various utility code modules +;======================================================================= +; +#include "util.asm" +; +;======================================================================= +; Console I/O +;======================================================================= +; +; Internal serial driver routing jump table. The console serial +; port is detected at startup and the following table is populated +; dynamically at that time. +; +hd_serjptbl: + jp 0 ; Console port initialization + jp 0 ; Console read byte + jp 0 ; Console write byte + jp 0 ; Console input status + jp 0 ; Console output status +; +; Wrapper functions for console I/O handles routing abstraction and +; ensures that no registers are modified other than AF for input +; functions. +; +hd_cinit: + push af + push bc + push de + push hl + call hd_serjptbl + 0 + pop hl + pop de + pop bc + pop af + ret +; +hd_cin: + push bc + push de + push hl + call hd_serjptbl + 3 + pop hl + pop de + pop bc + ret +; +hd_cout: + push af + push bc + push de + push hl + call hd_serjptbl + 6 + pop hl + pop de + pop bc + pop af + ret +; +hd_cist: + push bc + push de + push hl + call hd_serjptbl + 9 + pop hl + pop de + pop bc + ret +; +hd_cost: + push af + push bc + push de + push hl + call hd_serjptbl + 12 + pop hl + pop de + pop bc + pop af + ret +; +; Include all serial drivers +; +#include "uart.asm" +#include "asci.asm" +#include "acia.asm" +#include "sio.asm" +#include "z2u.asm" +; +;======================================================================= +; Working literals and internal variables +;======================================================================= +; +str_banner .db "\r\n\r\nHDIAG v0.90",0 +str_cputag .db "\r\nCPU Model: ",0 +str_mmtag .db "\r\nMemory Manager: ",0 +str_halt .db "\r\n\r\n*** System HALTed ***",0 +; +str_cpu: + .dw str_cpuz80 + .dw str_cpuz180 + .dw str_cpuz180K + .dw str_cpuz180N + .dw str_cpuz280 +; +str_cpuz80 .db "Z80",0 +str_cpuz180 .db "Z80180",0 +str_cpuz180K .db "Z8S180-K",0 +str_cpuz180N .db "Z8S180-N",0 +str_cpuz280 .db "Z80280",0 +; +str_mm: + .dw str_mmsbc + .dw str_mmz2 + .dw str_mmz180 + .dw str_mmn8 + .dw str_mmz280 +; +str_mmsbc .db "SBC/MBC",0 +str_mmz2 .db "Zeta2/RC2014",0 +str_mmz180 .db "Z180 Native",0 +str_mmn8 .db "Z180 Native (N8)",0 +str_mmz280 .db "Z280 Native",0 +; +;======================================================================= +; Top page of CPU RAM, global variables and function jump table +;======================================================================= +; +; This area is defined here, but copied to the top page of RAM at +; initialization! +; +; The top page (256 bytes) of CPU address space is used to maintain +; a jump table of functions available to all diagnostic modules. +; It also contains some global variables at fixed locations for use +; by diagnostic modules. +; +ffpgimg .equ $ + .org $FF00 ; Set code org +; +hd_jptbl: +cinit jp hd_cinit ; Console port initialization +cin jp hd_cin ; Console read byte +cout jp hd_cout ; Console write byte +cist jp hd_cist ; Console input status +cost jp hd_cost ; Console output status +; + .fill $FF80-$ +hd_cpu .db 0 ; CPU type +hd_mmgr .db 0 ; Memory manager type + .end + + diff --git a/Source/HDIAG/hdiag_old.asm b/Source/HDIAG/hdiag_old.asm new file mode 100644 index 00000000..46456513 --- /dev/null +++ b/Source/HDIAG/hdiag_old.asm @@ -0,0 +1,2543 @@ +; +;================================================================================================== +; HDIAG +;================================================================================================== +; +; THIS FILE CONTAINS A FRAMEWORK FOR A DIAGNOTIC ENVIRONMENT. IT IS ESSENTIALLY A STRIPPED DOWN +; VERSION OF HBIOS. IT DOES NO BANK SWITCHING, BUT THE INTERRUPT MANAGEMENT FRAMEWORK IS +; RETAINED. UPON STARTUP, IT RELOCATES TO UPPER (COMMON) RAM AS QUICKLY AS POSSIBLE. +; +; THERE IS NO HBIOS API. MINIMAL SERIAL PORT ACCESS IS PROVIDED BY INCLUDING THE PLATFORM +; APPROPRIATE MIN_XXX.ASM SERIAL DRIVER. SERIAL PORT SPEEDS ARE FIXED AND THERE IS NO +; FLOW CONTROL. NONE OF THE TYPICAL DRIVER MODULES (CHARACTER, DISK, VIDEO, ETC.) ARE INCLUDED +; AND THERE IS NO DISPATCHING MECHANISM. +; +; IN ORDER TO BUILD PLATFORM APPROPRIATE VERSIONS, THE FULL HBIOS INCLUDE FILE STRUCTURE +; IS USED SO THAT ALL OF THE HBIOS CONFIG SETTINGS CAN BE USED. +; +; THIS FILE CAN BE COMPILED TO BOOT IN ONE OF 2 MODES (ROM OR APPLICATION) AS DESCRIBED +; BELOW. WHEN COMPILED, YOU MUST DEFINE EXACTLY ONE OF THE FOLLOWING MACROS: +; +; - ROMBOOT: BOOT FROM A ROM BANK +; +; WHEN ROMBOOT IS DEFINED, THE FILE IS ASSEMBLED TO BE IMBEDDED AT THE START OF A ROM +; ASSUMING THAT THE CPU WILL START EXECUTION AT ADDRESS 0. +; +; - APPBOOT: BOOT FROM A CP/M STYLE APPLICATION FILE +; +; WHEN APPBOOT IS DEFINED, THE FILE IS ASSEMBLED AS A CP/M APPLICATION ASSUMING +; THAT IT WILL BE LOADED AT 100H BY THE CP/M (OR COMPATIBLE) OS. +; +; INCLUDE FILE NESTING: +; +; hdiag.asm +; - std.asm +; - ver.inc +; - hbios.inc +; - build.inc +; - config/_.asm +; - cfg_.asm +; - util.asm +; - min_[uart|asci|sio|acia].asm +; - dsky.asm ??? +; - diagnostic modules... +; +; INCLUDE GENERIC STUFF +; +#INCLUDE "std.asm" +; +#DEFINE HDIAG +; +; MAKE SURE EXACTLY ONE OF ROMBOOT, APPBOOT IS DEFINED. +; +MODCNT .EQU 0 +#IFDEF ROMBOOT +MODCNT .SET MODCNT + 1 +#ENDIF +#IFDEF APPBOOT +MODCNT .SET MODCNT + 1 +#ENDIF +#IF (MODCNT != 1) + .ECHO "*** ERROR: PLEASE DEFINE ONE AND ONLY ONE OF ROMBOOT, APPBOOT!!!\n" + !!! ; FORCE AN ASSEMBLY ERROR +#ENDIF +; +; +; +#IF (DIAGENABLE) +#DEFINE DIAG(N) PUSH AF + #DEFCONT \ LD A,N + #DEFCONT \ OUT (DIAGPORT),A + #DEFCONT \ POP AF +#ELSE +#DEFINE DIAG(N) \; +#ENDIF +; +#IF (LEDENABLE) + #IF (LEDMODE == LEDMODE_STD) +#DEFINE LED(N) PUSH AF + #DEFCONT \ LD A,~N + #DEFCONT \ OUT (LEDPORT),A + #DEFCONT \ POP AF + #ENDIF + #IF (LEDMODE == LEDMODE_RTC) +#DEFINE LED(N) PUSH AF + #DEFCONT \ LD A,(HB_RTCVAL) + #DEFCONT \ AND %11111100 + #DEFCONT \ OR (N & %00000011) + #DEFCONT \ LD (HB_RTCVAL),A + #DEFCONT \ OUT (LEDPORT),A + #DEFCONT \ POP AF + #ENDIF +#ELSE +#DEFINE LED(N) \; +#ENDIF +; +; +; +#IF (INTMODE == 0) +; NO INTERRUPT HANDLING +#DEFINE HB_DI ; +#DEFINE HB_EI ; +#ELSE + #IF (CPUFAM == CPU_Z280) + #IF (INTMODE == 3) +; Z280 MODE 3 INTERRUPT HANDLING (INTA, C/T 0, & UART RCVR ENABLED) +#DEFINE HB_DI DI +#DEFINE HB_EI .DB $ED,$7F,$0B + #ELSE +; Z280 MODE 1/2 INTERRUPT HANDLING +#DEFINE HB_DI DI +#DEFINE HB_EI EI + #ENDIF + #ELSE +#DEFINE HB_DI DI +#DEFINE HB_EI EI + #ENDIF +#ENDIF +; +#IF (INTMODE > 3) + .ECHO "*** ERROR: INVALID INTMODE SETTING!!!\n" + !!! ; FORCE AN ASSEMBLY ERROR +#ENDIF +; +#IF (INTMODE == 3) + #IF (CPUFAM != CPU_Z280) + .ECHO "*** ERROR: INTMODE 3 REQUIRES Z280 FAMILY CPU!!!\n" + !!! ; FORCE AN ASSEMBLY ERROR + #ENDIF + #IF (MEMMGR != MM_Z280) + .ECHO "*** ERROR: INTMODE 3 REQUIRES Z280 MEMORY MANAGER!!!\n" + !!! ; FORCE AN ASSEMBLY ERROR + #ENDIF +#ENDIF +; +#IF (MEMMGR == MM_Z280) + #IF (INTMODE != 3) + .ECHO "*** ERROR: Z280 MEMORY MANAGER REQUIRES INTMODE 3!!!\n" + !!! ; FORCE AN ASSEMBLY ERROR + #ENDIF + #IF (CPUFAM != CPU_Z280) + .ECHO "*** ERROR: Z280 MEMORY MANAGER REQUIRES Z280 FAMILY CPU!!!\n" + !!! ; FORCE AN ASSEMBLY ERROR + #ENDIF +#ENDIF +; +; +; +#IF (CTCENABLE) +CTCA .EQU CTCBASE + 0 ; CTC: CHANNEL A REGISTER ADR +CTCB .EQU CTCBASE + 1 ; CTC: CHANNEL B REGISTER ADR +CTCC .EQU CTCBASE + 2 ; CTC: CHANNEL C REGISTER ADR +CTCD .EQU CTCBASE + 3 ; CTC: CHANNEL D REGISTER ADR +#ENDIF +; +; THIS EQUATE IS UPDATED BY DRIVER INCLUDES THAT SHARE THE RTC LATCH. +; AS DRIVER IS INCLUDED, IT WILL USE .SET TO SET ANY BITS THEY OWN +; AND WANT TO SET AS DEFAULT. +; +RTCDEF .EQU 0 ; ALLOWS DRIVERS TO SET BITS +; +#IF (PLATFORM == PLT_SCZ180) +RTCDEF .SET RTCDEF | %00000001 ; SC128 I2C SCL BIT +#ENDIF +; +; +; +#IFNDEF APPBOOT +; + .ORG 0 +; +;================================================================================================== +; NORMAL PAGE ZERO SETUP, RET/RETI/RETN AS APPROPRIATE, LEAVE INTERRUPTS DISABLED +;================================================================================================== +; + .FILL (000H - $),0FFH ; RST 0 + JP HB_START + .DW ROM_SIG + .FILL (008H - $),0FFH ; RST 8 + RET + .FILL (010H - $),0FFH ; RST 10 + RET + .FILL (018H - $),0FFH ; RST 18 + RET + .FILL (020H - $),0FFH ; RST 20 + RET + .FILL (028H - $),0FFH ; RST 28 + RET + .FILL (030H - $),0FFH ; RST 30 + RET + .FILL (038H - $),0FFH ; RST 38 / IM1 INT + #IF (INTMODE == 1) + JP INT_IM1 ; JP TO INTERRUPT HANDLER IN HI MEM + #ELSE + RET ; RETURN W/ INTS DISABLED + #ENDIF + .FILL (066H - $),0FFH ; NMI + RETN +; + .FILL (070H - $),0FFH ; SIG STARTS AT $80 +; +ROM_SIG: + .DB $76, $B5 ; 2 SIGNATURE BYTES + .DB 1 ; STRUCTURE VERSION NUMBER + .DB 7 ; ROM SIZE (IN MULTIPLES OF 4KB, MINUS ONE) + .DW NAME ; POINTER TO HUMAN-READABLE ROM NAME + .DW AUTH ; POINTER TO AUTHOR INITIALS + .DW DESC ; POINTER TO LONGER DESCRIPTION OF ROM + .DB 0, 0, 0, 0, 0, 0 ; RESERVED FOR FUTURE USE; MUST BE ZERO +; +NAME .DB "ROMWBW v", BIOSVER, ", ", TIMESTAMP, 0 +AUTH .DB "WBW",0 +DESC .DB "ROMWBW v", BIOSVER, ", Copyright (C) 2020, Wayne Warthen, GNU GPL v3", 0 +; + .FILL ($100 - $),$FF ; PAD REMAINDER OF PAGE ZERO +; +#ENDIF +; +; +; + .ORG $100 + JP HB_START +; +;================================================================================================== +; HBIOS UPPER MEMORY PROXY (RELOCATED TO RUN IN TOP 2 PAGES OF CPU RAM) +;================================================================================================== +; +; THE FOLLOWING CODE IS RELOCATED TO THE TOP OF MEMORY TO HANDLE INVOCATION DISPATCHING +; + ;.FILL (HBX_IMG - $) ; FILL TO START OF PROXY IMAGE START +HBX_IMG .SET $ + .ORG HBX_LOC ; ADJUST FOR RELOCATION +; +; MEMORY LAYOUT: +; +; HBIOS PROXY CODE $FE00 (256 BYTES) +; INTERRUPT VECTORS $FF00 (32 BYTES, 16 ENTRIES) +; INTERRUPT HANDLER STUBS $FF20 (128 BYTES) +; HBIOS PROXY COPY BUFFER $FF80 (64 BYTES) +; HBIOS PROXY MGMT BLOCK $FFE0 (32 BYTES) +; +; DEFINITIONS +; +HBX_BUFSIZ .EQU $40 ; INTERBANK COPY BOUNCE BUFFER SIZE +; +; HBIOS IDENTIFICATION DATA BLOCK +; +HBX_IDENT: + .DB 'W',~'W' ; MARKER + .DB RMJ << 4 | RMN ; FIRST BYTE OF VERSION INFO + .DB RUP << 4 | RTP ; SECOND BYTE OF VERSION INFO +;;;; +;;;;================================================================================================== +;;;; HBIOS ENTRY FOR RST 08 PROCESSING +;;;;================================================================================================== +;;;; +;;;; NOTE: THE SIZE OF HBX_TMPSTK (TYPICALLY 20 BYTES) IS INSUFFICIENT FOR +;;;; FREERTOS IF AN INTERRUPT STRIKES WHILE THE TEMPORARY STACK IS ACTIVE. +;;;; BELOW, HBX_BUF HAS BEEN USURPED TO PROVIDE A LARGER TEMP STACK TO +;;;; ACCOMMODATE FREERTOS. HBX_BUF IS ONLY USED AS A BOUNCE BUFFER, SO IT'S +;;;; USE WILL NEVER OVERLAP WITH BELOW. +;;;; +;;;; WARNING: HBX_INVOKE IS *NOT* REENTRANT! +;;;; +;;;HBX_INVOKE: +;;;; +;;;#IF (HBIOS_MUTEX == TRUE) +;;; PUSH HL ; SAVE HL +;;; LD HL,HB_LOCK ; POINT TO LOCK +;;; SRA (HL) ; TEST/ACQUIRE MUTEX LOCK +;;; JR C,$-2 ; KEEP TRYING ON FAILURE +;;; POP HL ; RESTORE HL +;;;#ENDIF +;;;; +;;;#IF (MEMMGR == MM_Z280) +;;;; +;;; LD A,(HB_CURBNK) ; GET CURRENT BANK +;;; LD (HB_INVBNK),A ; SAVE INVOCATION BANK +;;;; +;;; LD A,BID_BIOS ; HBIOS BANK +;;; LD (HB_CURBNK),A ; SET AS CURRENT BANK +;;;; +;;; .DB $ED,$71 ; SC +;;; .DW HB_DISPATCH ; SC PARAMETER +;;;; +;;; PUSH AF +;;; LD A,(HB_INVBNK) +;;; LD (HB_CURBNK),A +;;; POP AF +;;;; +;;;#ELSE +;;;; +;;; LD (HBX_INVSP),SP ; SAVE ORIGINAL STACK FRAME +;;; LD SP,HBX_BUF_END ; BORROW HBX_BUF FOR TEMP STACK +;;;; +;;; LD A,(HB_CURBNK) ; GET CURRENT BANK +;;; LD (HB_INVBNK),A ; SAVE INVOCATION BANK +;;;; +;;; LD A,BID_BIOS ; HBIOS BANK +;;; CALL HBX_BNKSEL ; SELECT IT +;;; LD SP,HB_STACK ; NOW USE FULL HBIOS STACK IN HBIOS BANK +;;;; +;;; ;CALL HB_DISPATCH ; CALL HBIOS FUNCTION DISPATCHER +;;;; +;;; LD SP,HBX_BUF_END ; BORROW HBX_BUF FOR TEMP STACK +;;; PUSH AF ; SAVE AF (FUNCTION RETURN) +;;;; +;;; LD A,(HB_INVBNK) ; LOAD ORIGINAL BANK +;;; CALL HBX_BNKSEL ; SELECT IT +;;; POP AF ; RESTORE AF +;;; LD SP,0 ; RESTORE ORIGINAL STACK FRAME +;;;HBX_INVSP .EQU $ - 2 +;;;; +;;;#ENDIF +;;;; +;;;#IF (HBIOS_MUTEX == TRUE) +;;; PUSH HL ; SAVE HL +;;; LD HL,HB_LOCK ; POINT TO LOCK +;;; LD (HL),$FE ; RELEASE MUTEX LOCK +;;; POP HL ; RESTORE HL +;;;#ENDIF +;;;; +;;; RET ; RETURN TO CALLER +; +;;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +;; BNKSEL - Switch Memory Bank to Bank in A. +;; Preserve all Registers including Flags. +;;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +; +HBX_BNKSEL: + ; IF AN INTERRUPT OCCURS DURING THE BANK SWITCH CODE, + ; THE BANK WILL BE SET TO (CURBNK) AS THE INTERRUPT + ; RETURNS. SO, IT IS IMPORTANT THAT (HB_CURBNK) BE + ; SET AS THE FIRST STEP TO AVOID ISSUES IF AN INTERRUPT + ; OCCURS DURING PROCESSING. + LD (HB_CURBNK),A ; RECORD NEW CURRENT BANK +; +HBX_BNKSEL_INT: +; +#IF (MEMMGR == MM_SBC) + #IF (INTMODE == 1) + ; THIS BIT OF ABSURDITY HANDLES A RARE (BUT FATAL) SITUATION + ; WHERE AN IM1 INTERRUPT OCCURS BETWEEN SETTING THE RAM AND + ; ROM SELECTORS. BRACKETING THE INSTRUCTIONS WITH DI/EI + ; IS CONTRAINDICATED BECAUSE THIS ROUTINE IS CALLED BY + ; OTHER ROUTINES THAT MUST CONTROL INT ENABLE AT A HIGHER + ; LEVEL. THE FOLLOWING TECHNIQUE ENSURES THAT YOU ALWAYS + ; SWITCH DIRECTLY FROM THE PREVIOUS BANK TO THE TARGET BANK + ; WITHOUT AN "ERRANT" BANK BEING ACTIVE BETWEEN THE TWO + ; BANK SELECTION I/O INSTRUCTIONS. THE TECHNIQUE IS ONLY + ; NEEDED WHEN USING INT MODE 1 BECAUSE THAT MODE REQUIRES + ; PAGE ONE TO HAVE A VALID INT HANDLER WHENEVER INTS ARE + ; ENABLED. + ;BIT 7,A ; [8] TEST RAM BIT + ;JR Z,HBX_ROM ; [12/7] IF NOT SET, JUST DO ROM + OR A ; [4] SET FLAGS + JP P,HBX_ROM ; [10] BIT 7 INDICATES RAM + #ENDIF + OUT (MPCL_RAM),A ; SET RAM PAGE SELECTOR +HBX_ROM: + OUT (MPCL_ROM),A ; SET ROM PAGE SELECTOR + RET ; DONE +#ENDIF +; +#IF (MEMMGR == MM_Z2) + BIT 7,A ; BIT 7 SET REQUESTS RAM PAGE + JR Z,HBX_ROM ; NOT SET, SELECT ROM PAGE + RES 7,A ; RAM PAGE REQUESTED: CLEAR ROM BIT + ADD A,16 ; ADD 16 x 32K - RAM STARTS FROM 512K +; +HBX_ROM: + RLCA ; TIMES 2 - GET 16K PAGE INSTEAD OF 32K + OUT (MPGSEL_0),A ; BANK_0: 0K - 16K + INC A ; + OUT (MPGSEL_1),A ; BANK_1: 16K - 32K + #IF (CPUFAM == CPU_Z280) + PCACHE + #ENDIF + RET ; DONE +#ENDIF +; +#IF (MEMMGR == MM_N8) + BIT 7,A ; TEST BIT 7 FOR RAM VS. ROM + JR Z,HBX_ROM ; IF NOT SET, SELECT ROM PAGE +; +HBX_RAM: + RES 7,A ; CLEAR BIT 7 FROM ABOVE + RLCA ; SCALE SELECTOR TO + RLCA ; ... GO FROM Z180 4K PAGE SIZE + RLCA ; ... TO DESIRED 32K PAGE SIZE + OUT0 (Z180_BBR),A ; WRITE TO BANK BASE + LD A,N8_DEFACR | 80H ; SELECT RAM BY SETTING BIT 7 + OUT0 (N8_ACR),A ; ... IN N8 ACR REGISTER + RET ; DONE +; +HBX_ROM: + OUT0 (N8_RMAP),A ; BANK INDEX TO N8 RMAP REGISTER + XOR A ; ZERO ACCUM + OUT0 (Z180_BBR),A ; ZERO BANK BASE + LD A,N8_DEFACR ; SELECT ROM BY CLEARING BIT 7 + OUT0 (N8_ACR),A ; ... IN N8 ACR REGISTER + RET ; DONE +#ENDIF +; +#IF (MEMMGR == MM_Z180) + RLCA ; RAM FLAG TO CARRY FLAG AND BIT 0 + JR NC,HBX_BNKSEL1 ; IF NC, WANT ROM PAGE, SKIP AHEAD + XOR %00100001 ; SET BIT FOR HI 512K, CLR BIT 0 +HBX_BNKSEL1: + RLCA ; CONTINUE SHIFTING TO SCALE SELECTOR + RLCA ; FOR Z180 4K PAGE -> DESIRED 32K PAGE + OUT0 (Z180_BBR),A ; WRITE TO BANK BASE + RET ; DONE +#ENDIF +; +#IF (MEMMGR == MM_Z280) + PUSH BC ; SAVE BC + PUSH HL ; SAVE HL + LD B,$00 ; FIRST USER PDR + .DB $ED,$71 ; SC + .DW Z280_BNKSEL ; SC PARAMETER + POP HL ; RESTORE HL + POP BC ; RESTORE BC + RET ; DONE +#ENDIF +; +#IF (MEMMGR == MM_ZRC) + BIT 7,A ; BIT 7 SET REQUESTS RAM PAGE + JR Z,HBX_ROM ; NOT SET, SELECT ROM PAGE + RES 7,A ; RAM PAGE REQUESTED: CLEAR ROM BIT + ADD A,$10 ; ADD 16 x 32K - RAM STARTS FROM 512K +; +HBX_ROM: + OUT ($1F),A ; HCS WRITE TO THE BANK CONTROL REGISTER + RET ; DONE +#ENDIF +; +#IF (MEMMGR == MM_MBC) +; + #IF (INTMODE == 1) + LD (HBX_MMA),A ; SAVE ACCUM + LD A,I ; GET INT CTL REG + HB_DI ; DISABLE INTS + PUSH AF ; SAVE INT CTL REG + LD A,(HBX_MMA) ; RESTORE ACCUM + #ENDIF +; + OR A ; SET FLAGS + JP P,HBX_ROM ; BIT 7 INDICATES RAM + OUT (MPCL_ROM),A ; ENSURE ROM PAGE OUT OF MEMORY BEFORE SWITCH + +#IF (RAMSIZE == 256) + XOR %00000100 ; TOP 32K IS ALWAYS IN FIRST CHIP +#ENDIF + +#IF (RAMSIZE == 1024) + XOR %00010000 ; TOP 32K IS ALWAYS IN FIRST CHIP +#ENDIF + + OUT (MPCL_RAM),A ; SET RAM PAGE SELECTOR + JR HBX_RAMX +HBX_ROM: + OUT (MPCL_RAM),A ; ENSURE RAM PAGE OUT OF MEMORY BEFORE SWITCH + OUT (MPCL_ROM),A ; SET ROM PAGE SELECTOR + +HBX_RAMX: +; + #IF (INTMODE == 1) + POP AF ; RESTORE INT CTL REG + JP PO,$+4 ; WERE INTS DISABLED AT ENTRY? + EI ; *** DO NOT USE HB_EI HERE *** + LD A,(HBX_MMA) ; RESTORE INCOMING ACCUM + #ENDIF +; + RET +; +HBX_MMA .DB 0 ; TEMPORARY STORAGE FOR REG A +#ENDIF +; +;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +; Copy Data - Possibly between banks. This resembles CP/M 3, but +; usage of the HL and DE registers is reversed. +; Caller MUST preset HBX_SRCBNK and HBX_DSTBNK. +; IM1/IM2 interrupts are disabled during HBX_BNKCPY. +; Enter: +; HL = Source Address +; DE = Destination Address +; BC = Number of bytes to copy +; Exit : None +; Uses : AF,BC,DE,HL +; +;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +; +HBX_BNKCPY: +#IF (MEMMGR == MM_Z280) + .DB $ED,$71 ; SC + .DW Z280_BNKCPY ; SC PARAMETER + RET +#ELSE + #IF (CPUFAM == CPU_Z280) + PUSH HL + PUSH BC + LD C,Z280_MSR + LDCTL HL,(C) + POP BC + EX (SP),HL + HB_DI + #ELSE + LD A,I + HB_DI + PUSH AF + #ENDIF + LD (HBX_BC_SP),SP ; PUT STACK + LD SP,HBX_TMPSTK ; ... IN HI MEM + + LD A,(HB_CURBNK) ; GET CURRENT BANK + PUSH AF ; AND SAVE TO RESTORE LATER + PUSH BC ; CUR LEN -> (SP) +; +HBX_BC_LOOP: + EX (SP),HL ; HL := CUR LEN, (SP) := CUR SRC + LD BC,HBX_BUFSIZ ; SET BC TO BOUNCE BUFFER SIZE + OR A ; CLEAR CARRY FLAG + SBC HL,BC ; CUR LEN := CUR LEN - BBUF SIZE + JR C,HBX_BC_LAST ; END GAME, LESS THAN BBUF BYTES LEFT + EX (SP),HL ; HL := CUR SRC, (SP) := REM LEN + CALL HBX_BC_ITER ; DO A FULL BBUF SIZE CHUNK + JR HBX_BC_LOOP ; AND REPEAT TILL DONE +; +HBX_BC_LAST: + ; HL IS BETWEEN -(BBUF SIZE) AND -1, BC = BBUF SIZE + OR A ; CLEAR CARRY + ADC HL,BC ; HL := REM LEN (0 - 127) + EX (SP),HL ; HL := CUR SRC, (SP) := REM LEN + POP BC ; BC := REM LEN + CALL NZ,HBX_BC_ITER ; DO FINAL CHUNK, IFF > 0 BYTES + POP AF ; RECOVER ORIGINAL BANK + CALL HBX_BNKSEL ; SWITCH + + LD SP,$FFFF ; RESTORE STACK +HBX_BC_SP .EQU $ - 2 ; ... TO ORIGINAL VALUE + #IF (CPUFAM == CPU_Z280) + EX (SP),HL ; SAVE HL, RECOVER MSR + PUSH BC ; SAVE BC + LD C,Z280_MSR + LDCTL (C),HL + POP BC ; RECOVER BC + POP HL ; RECOVER HL + #ELSE + POP AF + JP PO,$+4 + EI ; *** DO NOT USE HB_EI HERE *** + #ENDIF + RET +; +HBX_BC_ITER: + ; HL = SRC ADR, DE = DEST ADR, BC = LEN + PUSH BC ; SAVE COPY LEN + PUSH DE ; FINAL DEST ON STACK + LD DE,HBX_BUF ; SET DEST TO BUF + LD A,(HB_SRCBNK) ; GET SOURCE BANK + CALL HBX_BNKSEL ; SWITCH TO SOURCE BANK + LDIR ; HL -> BUF (DE), BC BYTES, HL UPDATED SRC ADR + POP DE ; DE := FINAL DEST + POP BC ; GET LEN BACK IN BC + PUSH HL ; SAVE UPDATED SRC ADR + LD HL,HBX_BUF ; SET SRC ADR TO BUF + LD A,(HB_DSTBNK) ; GET DEST BANK + CALL HBX_BNKSEL ; SWITCH TO DEST BANK + LDIR ; BUF (HL) -> DE, BC BYTES, DE UPDATED DEST ADR + POP HL ; RECOVER UPDATED SRC ADR + ; HL = UPDATED SRC, DE = UPDATED DEST, BC = 0 + RET +#ENDIF +; +; CALL A ROUTINE IN ANOTHER BANK. +; CALLER MUST ENSURE STACK IS ALREADY IN HIGH MEMORY AND HAS ADEQUATE SPACE. +; IF IM1 INTERRUPTS ARE POSSIBLE, CALLER MUST EITHER DISABLE THEM PRIOR TO +; BNKCALL OR MAKE SURE THAT PAGE ZERO IN TARGET BANK IS PREPARED FOR THEM. +; ON INPUT A=TARGET BANK, IX=TARGET ADDRESS +; +HBX_BNKCALL: +; +#IF (MEMMGR == MM_Z280) + CP BID_BIOS ; CALLING HBIOS? + JR NZ,HBX_BNKCALL3 ; NOPE, DO NORMAL PROCESSING + .DB $ED,$71 ; SC + .DW HBX_BNKCALL2 ; CALL HERE IN SYSTEM MODE + RET ; THEN RETURN +; +HBX_BNKCALL2: + HB_EI ; INTS ARE OK + LD (HBX_BNKCALL_GO+1),IX ; SETUP DEST ADR + PCACHE ; CRITICAL!!! +HBX_BNKCALL_GO: + JP $FFFF ; DO THE REAL WORK AND RETURN +#ENDIF +; +HBX_BNKCALL3: + LD (HBX_BNKCALL_BNK+1),A ; STUFF TARGET BANK TO CALL INTO CODE BELOW + LD (HBX_BNKCALL_ADR+1),IX ; STUFF ADDRESS TO CALL INTO CODE BELOW + LD A,(HB_CURBNK) ; GET CURRENT BANK + PUSH AF ; SAVE FOR RETURN +HBX_BNKCALL_BNK: + LD A,$FF ; LOAD BANK TO CALL ($FF OVERLAID AT ENTRY) + CALL HBX_BNKSEL ; ACTIVATE THE NEW BANK +HBX_BNKCALL_ADR: + CALL $FFFF ; CALL ROUTINE ($FFFF IS OVERLAID ABOVE) + EX (SP),HL ; SAVE HL AND GET BANK TO RESTORE IN HL + PUSH AF ; SAVE AF + LD A,H ; BANK TO RESTORE TO A + CALL HBX_BNKSEL ; RESTORE IT + POP AF ; RECOVER AF + POP HL ; RECOVER HL + RET +; +; PEEK & POKE ROUTINES +; ADDRESS IN HL, BANK IN D, VALUE IN/OUT IN E, A IS TRASHED +; +; THESE ROUTINES ARE NOT INTENDED TO BE CALLED DIRECTLY -- THEY ARE +; HELPERS FOR THE HBIOS API AND ARE CALLED BY HBIOS BANK CODE. THE +; HBIOS BANK CODE BRACKETS THE USE OF THESE ROUTINES WITH DI/EI IF +; NECESSARY FOR THE CURRENT INTERRUPT MODE. +; +; NOTE: THE SIZE OF HBX_TMPSTK (TYPICALLY 20 BYTES) IS INSUFFICIENT FOR +; FREERTOS IF AN INTERRUPT STRIKES WHILE THE TEMPORARY STACK IS ACTIVE. +; BELOW, HBX_BUF HAS BEEN USURPED TO PROVIDE A LARGER TEMP STACK TO +; ACCOMMODATE FREERTOS. HBX_BUF IS ONLY USED AS A BOUNCE BUFFER, SO IT'S +; USE WILL NEVER OVERLAP WITH BELOW. +; +HBX_PEEK: + LD (HBX_PPSP),SP ; SAVE ORIGINAL STACK FRAME + LD SP,HBX_BUF_END ; BORROW HBX_BUF FOR TEMP STACK + LD A,(HB_CURBNK) + PUSH AF + LD A,D + CALL HBX_BNKSEL + LD E,(HL) + JR HBX_PPRET +; +HBX_POKE: + LD (HBX_PPSP),SP ; SAVE ORIGINAL STACK FRAME + LD SP,HBX_BUF_END ; BORROW HBX_BUF FOR TEMP STACK + LD A,(HB_CURBNK) + PUSH AF + LD A,D + CALL HBX_BNKSEL + LD (HL),E +; +HBX_PPRET: + POP AF +#IF (MEMMGR == MM_Z280) + LD A,(HB_INVBNK) ; SPECIAL CASE FOR Z280 MEM MGR +#ENDIF + CALL HBX_BNKSEL + LD SP,0 ; RESTORE ORIGINAL STACK FRAME +HBX_PPSP .EQU $ - 2 + RET +; +; SPECIAL ROUTINE IN HIGH MEMORY TO PERFORM A COLD START ON Z280 +; THIS REQUIRES US TO REMAP LOW MEMORY, THEN JUMP TO ZERO +; +#IF (MEMMGR == MM_Z280) +; +Z280_RESTART: + DI ; KILL INTERRUPTS + LD SP,HBX_LOC ; STACK IN HIGH MEMORY +; + ; COPY Z280 BANK SELECT ROUTINE TO HIGH MEMORY + LD HL,Z280_BNKSEL + LD DE,$8000 + LD BC,Z280_BNKSEL_LEN + LDIR +; + ; MAKE ROM BOOT BANK ACTIVE IN LOW SYS MEM + LD A,BID_BOOT + LD B,$10 ; FIRST SYS PDR + CALL $8000 ; DO IT +; + ; NOW JUST JUMP TO START OF ROM BOOT CODE + JP 0 +#ENDIF +; +; PRIVATE STACK AT END OF HBIOS CODE +; OCCUPIES SPACE BEFORE IVT +; +HBX_INTSTKSIZ .EQU $FF00 - $ + .ECHO "HBIOS INT STACK space: " + .ECHO HBX_INTSTKSIZ + .ECHO " bytes.\n" + .FILL HBX_INTSTKSIZ,$FF +HBX_INTSTK .EQU $ +; +;#IF (HBX_INTSTKSIZ < 24) +#IF (HBX_INTSTKSIZ < 22) + .ECHO "*** ERROR: INTERRUPT STACK IS TOO SMALL!!!\n" + !!! ; FORCE AN ASSEMBLY ERROR +#ENDIF +; +#IF ((INTMODE == 2) | (INTMODE == 3)) +; +; HBIOS INTERRUPT SLOT ASSIGNMENTS +; +; # Z80 Z180 +; --- -------------- -------------- +; 0 CTC0A INT1 -+ +; 1 CTC0B INT2 | +; 2 CTC0C TIM0 | +; 3 CTC0D TIM1 | +; 4 UART0 DMA0 +- Z180 INTERNAL +; 5 UART1 DMA1 | +; 6 CSIO | +; 7 SIO0 SER0 | +; 8 SIO1 SER1 -+ +; 9 PIO0A PIO0A +; 10 PIO0B PIO0B +; 11 PIO1A PIO1A +; 12 PIO1B PIO1B +; 13 SIO0 +; 14 SIO1 +; 15 +; +HBX_IVT: + .DW HBX_IV00 + .DW HBX_IV01 + .DW HBX_IV02 + .DW HBX_IV03 + .DW HBX_IV04 + .DW HBX_IV05 + .DW HBX_IV06 + .DW HBX_IV07 + .DW HBX_IV08 + .DW HBX_IV09 + .DW HBX_IV0A + .DW HBX_IV0B + .DW HBX_IV0C + .DW HBX_IV0D + .DW HBX_IV0E + .DW HBX_IV0F +; +HBX_IVTCNT .EQU ($ - HBX_IVT) / 2 +; +HBX_IV00: CALL HBX_INT \ .DB $00 << 2 +HBX_IV01: CALL HBX_INT \ .DB $01 << 2 +HBX_IV02: CALL HBX_INT \ .DB $02 << 2 +HBX_IV03: CALL HBX_INT \ .DB $03 << 2 +HBX_IV04: CALL HBX_INT \ .DB $04 << 2 +HBX_IV05: CALL HBX_INT \ .DB $05 << 2 +HBX_IV06: CALL HBX_INT \ .DB $06 << 2 +HBX_IV07: CALL HBX_INT \ .DB $07 << 2 +HBX_IV08: CALL HBX_INT \ .DB $08 << 2 +HBX_IV09: CALL HBX_INT \ .DB $09 << 2 +HBX_IV0A: CALL HBX_INT \ .DB $0A << 2 +HBX_IV0B: CALL HBX_INT \ .DB $0B << 2 +HBX_IV0C: CALL HBX_INT \ .DB $0C << 2 +HBX_IV0D: CALL HBX_INT \ .DB $0D << 2 +HBX_IV0E: CALL HBX_INT \ .DB $0E << 2 +HBX_IV0F: CALL HBX_INT \ .DB $0F << 2 +; +#ENDIF +; +INT_IM1: +#IF (INTMODE == 1) + CALL HBX_INT + .DB $00 +#ELSE + RETI ; UNEXPECTED INT, RET W/ INTS LEFT DISABLED +#ENDIF +; +#IF (INTMODE > 0) +; +HBX_INT: ; COMMON INTERRUPT ROUTING CODE +; + #IF (MEMMGR == MM_Z280) +; +; THIS CODE ASSUMES Z280 IM 3. IM 1 AND IM 2 ON Z280 +; DO NOT SAVE MSR AT INTERRUPT MAKING IT VIRTUALLY IMPOSSIBLE +; TO RETURN FROM THE INTERRUPT TO THE CORRECT MODE (SYSTEM +; OR USER). THIS IS BECAUSE THERE IS NO WAY TO KNOW WHETHER +; SYSTEM OR USER MODE WAS ACTIVE AT THE TIME OF THE INTERRUPT. +; + EX (SP),HL ; SAVE HL AND GET INT JP TABLE OFFSET + + ; SAVE STATE (HL SAVED PREVIOUSLY ON ORIGINAL STACK FRAME) + PUSH AF ; SAVE AF + PUSH BC ; SAVE BC + PUSH DE ; SAVE DE + PUSH IY ; SAVE IY +; + ; HANDLE INT VIA JP TABLE IN HBIOS + LD L,(HL) ; OFFSET INTO JP TABLE FOR THIS INT + LD H,HB_IVT >> 8 ; MSB OF HBIOS INT JP TABLE + CALL JPHL ; CALL HANDLER VIA INT JP TABLE +; + ; RESTORE STATE + POP IY ; RESTORE IY + POP DE ; RESTORE DE + POP BC ; RESTORE BC + POP AF ; RESTORE AF + POP HL ; RESTORE HL +; + ; BURN THE REASON CODE + EX (SP),HL ; HL TO STK, RC TO HL + POP HL ; RESTORE HL +; + CALL HBX_RETI ; RETI FOR Z80 PERIPHERALS + RETIL +; +HBX_RETI: + RETI +; + #ELSE +; +; COMMON INTERRUPT DISPATCHING CODE +; SETUP AND CALL HANDLER IN BIOS BANK +; + EX (SP),HL ; SAVE HL AND GET INT JP TABLE OFFSET +; + LD (HBX_INT_SP),SP ; SAVE ORIGINAL STACK FRAME + LD SP,HBX_INTSTK ; USE DEDICATED INT STACK FRAME IN HI MEM +; + ; SAVE STATE (HL SAVED PREVIOUSLY ON ORIGINAL STACK FRAME) + PUSH AF ; SAVE AF + PUSH BC ; SAVE BC + PUSH DE ; SAVE DE + PUSH IY ; SAVE IY +; + ;LD A,BID_BIOS ; HBIOS BANK + ;CALL HBX_BNKSEL_INT ; SELECT IT +; + LD L,(HL) ; OFFSET INTO JP TABLE FOR THIS INT + LD H,HB_IVT >> 8 ; MSB OF HBIOS INT JP TABLE +; + CALL JPHL ; CALL HANDLER VIA INT JP TABLE +; + ;LD A,(HB_CURBNK) ; GET PRE-INT BANK + ;CALL HBX_BNKSEL ; SELECT IT +; + ; RESTORE STATE + POP IY ; RESTORE IY + POP DE ; RESTORE DE + POP BC ; RESTORE BC + POP AF ; RESTORE AF +; + LD SP,$FFFF ; RESTORE ORIGINAL STACK FRAME +HBX_INT_SP .EQU $ - 2 +; + POP HL ; RESTORE HL +; + HB_EI ; ENABLE INTERRUPTS + RETI ; AND RETURN +; + #ENDIF + +#ENDIF +; +; SMALL TEMPORARY STACK FOR USE BY HBX_BNKCPY +; +HBX_TMPSTKSIZ .EQU (HBX_XFC - HBX_BUFSIZ - $) + .ECHO "HBIOS TEMP STACK space: " + .ECHO HBX_TMPSTKSIZ + .ECHO " bytes.\n" + .FILL HBX_TMPSTKSIZ,$CC +HBX_TMPSTK .EQU $ +; +; INTERBANK COPY BOUNCE BUFFER (64 BYTES) +; +; N.B., THIS BUFFER IS ALSO USED AS A TEMPORARY STACK BY INVOKE, PEEK, AND POKE. +; THEREFORE, THIS BUFFER *CANNOT* BE USED TO PASS DATA OUTSIDE OF +; HBIOS FUNCTION CALLS. +; +HBX_BUF .FILL HBX_BUFSIZ,0 +HBX_BUF_END .EQU $ +; +; HBIOS PROXY MGMT BLOCK (TOP 32 BYTES) +; +#IFDEF ROMBOOT + .DB BID_BOOT ; HB_CURBNK: CURRENTLY ACTIVE LOW MEMORY BANK ID +#ELSE + .DB BID_USR ; HB_CURBNK: CURRENTLY ACTIVE LOW MEMORY BANK ID +#ENDIF + .DB $FF ; HB_INVBNK: BANK ACTIVE AT TIME OF HBIOS CALL INVOCATION + .DW 0 ; HB_SRCADR: BNKCPY SOURCE ADDRESS + .DB BID_USR ; HB_SRCBNK: BNKCPY SOURCE BANK ID + .DW 0 ; HB_DSTADR: BNKCPY DESTINATION ADDRESS + .DB BID_USR ; HB_DSTBNK: BNKCPY DESTINATION BANK ID + .DW 0 ; HB_CPYLEN: BNKCPY LENGTH + .FILL 4,0 ; FILLER, RESERVED FOR FUTURE HBIOS USE + .DB RTCDEF ; SHADOW VALUE FOR RTC LATCH PORT + .DB $FE ; HB_LOCK: HBIOS MUTEX LOCK + JP 0 ; HB_INVOKE: FIXED ADR ENTRY FOR HBX_INVOKE (ALT FOR RST 08) + JP HBX_BNKSEL ; HB_BNKSEL: FIXED ADR ENTRY FOR HBX_BNKSEL + JP HBX_BNKCPY ; HB_BNKCPY: FIXED ADR ENTRY FOR HBX_BNKCPY + JP HBX_BNKCALL ; HB_BNKCALL: FIXED ADR ENTRY FOR HBX_BNKCALL + .DW HBX_IDENT ; ADDRESS OF HBIOS PROXY START (DEPRECATED) + .DW HBX_IDENT ; HB_IDENT: ADDRESS OF HBIOS IDENT INFO DATA BLOCK +; + .FILL MEMTOP - $ ; FILL TO END OF MEMORY (AS NEEDED) + .ORG HBX_IMG + HBX_SIZ ; RESET ORG +; +;================================================================================================== +; HDIAG CORE +;================================================================================================== +; +;================================================================================================== +; SYSTEM INITIALIZATION +;================================================================================================== +; +HB_START: +#IFDEF APPBOOT + #IF (MEMMGR == MM_Z280) + LD A,%00000001 + OUT (DIAGPORT),A + LD DE,Z280_BOOTERR + LD C,9 + LD A,%00000010 + OUT (DIAGPORT),A + CALL $0005 + LD A,%00001000 + OUT (DIAGPORT),A + RET +; +Z280_BOOTERR .TEXT "\r\n\r\n*** Application mode boot not supported under Z280 native memory management!!!\r\n\r\n$" + #ENDIF +#ENDIF + + DI ; NO INTERRUPTS + IM 1 ; INTERRUPT MODE 1 +; +#IF (DIAGENABLE) + LD A,%00000001 + OUT (DIAGPORT),A +#ENDIF +#IF (LEDENABLE) + #IF (LEDMODE == LEDMODE_STD) + XOR A ; LED IS INVERTED, TURN IT ON + #ENDIF + #IF (LEDMODE == LEDMODE_RTC) + LD A,%00000001 ; LED 0 + LD (HB_RTCVAL),A ; SAVE TO SHADOW REGISTER + #ENDIF + OUT (LEDPORT),A +#ENDIF +; + LD SP,HBX_LOC ; SETUP INITIAL STACK JUST BELOW HBIOS PROXY +; +#IF (CPUFAM == CPU_Z280) + ; SET MAXIMUM I/O WAIT STATES FOR NOW + LD C,Z280_BTCR ; BUS TIMING AND CONTROL REGISTER + LD HL,$0033 ; 3 I/O WAIT STATES ADDED + LDCTL (C),HL +; + ; START BY SELECTING I/O PAGE $FF + LD L,$FF ; MMU AND DMA PAGE I/O REG IS $FF + LD C,Z280_IOPR ; REG C POINTS TO I/O PAGE REGISTER + LDCTL (C),HL +; + #IF (MEMMGR == MM_Z280) +; + ; INITIALIZE ALL OF THE SYSTEM PAGE DESCRIPTORS WITH BLOCK MOVE + XOR A ; FIRST USER PDR + OUT (Z280_MMUPDRPTR),A ; SET THE PDR POINTER + LD HL,Z280_BOOTPDRTBL ; START OF PDR VALUES TABLE + LD C,Z280_MMUBLKMOV ; PDR BLOCK MOVE PORT + LD B,16 ; PROGRAM 16 PDRS + .DB $ED,$93 ; OTIRW +; + ; INITIALIZE ALL OF THE USER PAGE DESCRIPTORS WITH BLOCK MOVE + LD A,$10 ; FIRST SYSTEM PDR + OUT (Z280_MMUPDRPTR),A ; SET THE PDR POINTER + LD HL,Z280_BOOTPDRTBL ; START OF PDR VALUES TABLE + LD C,Z280_MMUBLKMOV ; PDR BLOCK MOVE PORT + LD B,16 ; PROGRAM 16 PDRS + .DB $ED,$93 ; OTIRW +; + ; ENABLE MMU (SYSTEM AND USER TRANSLATION) + LD C,Z280_MMUMCR ; MMU MASTER CONTROL REGISTER + LD HL,$BBFF ; ENABLE USER & SYSTEM TRANSLATE + OUTW (C),HL +; + ; DISABLE MEMORY REFRESH CYCLES + LD A,$08 ; DISABLED + OUT (Z280_RRR),A ; SET REFRESH RATE REGISTER +; + ; CONFIGURE Z280 INT/TRAP VECTOR TABLE POINTER REGISTER + ; WILL POINT TO ROM COPY FOR NOW, UPDATED TO RAM LATER ON + LD C,Z280_VPR + LD HL,Z280_IVT >> 8 ; TOP 16 BITS OF PHYSICAL ADR OF IVT + LDCTL (C),HL +; + JR Z280_INITZ ; JUMP TO CODE CONTINUATION +; + #IF (($ % 2) == 1) + ; WORD ALIGN THE TABLE + .DB 0 + #ENDIF +; +Z280_BOOTPDRTBL: + ; LOWER 32 K (BANKED) + .DW ($000 << 4) | $A + .DW ($001 << 4) | $A + .DW ($002 << 4) | $A + .DW ($003 << 4) | $A + .DW ($004 << 4) | $A + .DW ($005 << 4) | $A + .DW ($006 << 4) | $A + .DW ($007 << 4) | $A + ; UPPER 32 K (COMMON) + .DW (((((BID_COM & $7F) * 8) + 0) + (1 << (RAMLOC - 12))) << 4) | $A + .DW (((((BID_COM & $7F) * 8) + 1) + (1 << (RAMLOC - 12))) << 4) | $A + .DW (((((BID_COM & $7F) * 8) + 2) + (1 << (RAMLOC - 12))) << 4) | $A + .DW (((((BID_COM & $7F) * 8) + 3) + (1 << (RAMLOC - 12))) << 4) | $A + .DW (((((BID_COM & $7F) * 8) + 4) + (1 << (RAMLOC - 12))) << 4) | $A + .DW (((((BID_COM & $7F) * 8) + 5) + (1 << (RAMLOC - 12))) << 4) | $A + .DW (((((BID_COM & $7F) * 8) + 6) + (1 << (RAMLOC - 12))) << 4) | $A + .DW (((((BID_COM & $7F) * 8) + 7) + (1 << (RAMLOC - 12))) << 4) | $A +; +Z280_INITZ: +; + #ENDIF +; + ; RESTORE I/O PAGE TO $00 + LD L,$00 ; NORMAL I/O REG IS $00 + LD C,Z280_IOPR ; REG C POINTS TO I/O PAGE REGISTER + LDCTL (C),HL +; +#ENDIF +; +#IF (CPUFAM == CPU_Z180) + ; SET BASE FOR CPU IO REGISTERS + ; DO NOT USE Z180_ICR FROM Z180.INC BECAUSE THE ICR + ; IS NOT YET AT THE RUNNING LOCATION. AT RESET, THE Z180 + ; REGISTER BASE I/O ADDRESS IS ZERO, SO INITIALLY, ICR IS + ; AT $3F. + LD A,Z180_BASE + OUT0 ($3F),A ; AT RESET, ICR IS AT $3F + + DIAG(%00000010) + + ; DISABLE REFRESH + XOR A + OUT0 (Z180_RCR),A + + ; MASK OFF TIMER INTERRUPTS + XOR A + OUT0 (Z180_TCR),A + OUT0 (Z180_ITC),A + + ; SET DEFAULT CPU CLOCK MULTIPLIERS (XTAL / 2) + ; + ; IT HAS BEEN REPORTED THAT CMR NEEDS TO BE SET PRIOR TO CCR + ; WHEN USING AN INPUT FREQUENCY THAT IS XTAL / 2. + ; I NEVER EXPERIENCED A PROBLEM RELATED TO ORDER, BUT JUST + ; FOR GOOD MEASURE, CMR IS SET PRIOR TO CCR BELOW. + ; https://www.retrobrewcomputers.org/forum/index.php?t=msg&th=316&#msg_5045 + XOR A + OUT0 (Z180_CMR),A + OUT0 (Z180_CCR),A + + ; SET DEFAULT WAIT STATES + LD A,$F0 + OUT0 (Z180_DCNTL),A + + #IF ((MEMMGR == MM_Z180) | (MEMMGR == MM_N8)) + ; Z180 MMU SETUP + LD A,$80 + OUT0 (Z180_CBAR),A ; SETUP FOR 32K/32K BANK CONFIG +;#IFDEF ROMBOOT +; XOR A +; OUT0 (Z180_BBR),A ; BANK BASE = 0 +;#ENDIF + LD A,(RAMSIZE + RAMBIAS - 64) >> 2 + OUT0 (Z180_CBR),A ; COMMON BASE = LAST (TOP) BANK +; + ; SET DEFAULT CSIO SPEED (INTERNAL CLOCK, SLOW AS POSSIBLE) + LD A,Z180_CNTR_DEF ; DIV 1280, 14KHZ @ 18MHZ CLK + OUT0 (Z180_CNTR),A + #ENDIF +; +#ENDIF +; +#IF (EIPCENABLE) + LD A,(EIPC_WDT_CONST | EIPC_HALT_RUN | EIPC_WDT_P2_22) + OUT (EIPC_WDTMR),A ; CLEAR WDTE BIT (DISABLE WATCHDOG) + LD A,EIPC_DIS_WDT ; DISABLE WDT - SECOND KEY + OUT (EIPC_WDTCR),A + LD A,EIPC_WCR ; SET SYSTEM CONTROL REGISTER POINTER + ; (SCRP) TO POINT TO WAIT STATE + OUT (EIPC_SCRP),A ; CONTROL REGISTER (WCR) + LD A,(EIPC_IO_0WS | EIPC_MEM_OWS | EIPC_OCF_0WS | EIPC_INT_0WS | EIPC_CHAIN_0WS) + OUT (EIPC_SCDP),A ; NO WAIT STATES + LD A,EIPC_MCR ; SET SCRP TO POINT TO MISCELLANEOUS + OUT (EIPC_SCRP),A ; CONTROL REGISTER (MCR) + LD A,EIPC_CLKDIV1 ; DIVIDE CLOCK BY 1, /CS0 DISABLE + OUT (EIPC_SCDP),A ; SET SYSTEM CONTROL DATA PORT (SCDP) +#ENDIF +; +#IF ((MEMMGR == MM_SBC) | (MEMMGR == MM_MBC)) + ; SET PAGING REGISTERS + #IFDEF ROMBOOT + XOR A + OUT (MPCL_RAM),A ; REMOVE RAM FIRST! + OUT (MPCL_ROM),A ; SELECT ROM PAGE 0 + #ENDIF +#ENDIF +; +#IF (MEMMGR == MM_Z2) + ; SET PAGING REGISTERS + #IFDEF ROMBOOT + XOR A + OUT (MPGSEL_0),A + INC A + OUT (MPGSEL_1),A + #ENDIF + LD A,62 + OUT (MPGSEL_2),A + INC A + OUT (MPGSEL_3),A + ; ENABLE PAGING + LD A,1 + OUT (MPGENA),A +#ENDIF +; + DIAG(%00000011) +; +; CHECK BATTERY BACKUP STATUS BEFORE WE COPY PROXY TO UPPER MEMORY +; +; IF A DS1210 POWER CONTROLLER IS INSTALLED AND BATTERY BACKUP IS NOT INSTALLED +; OR IS LESS THAN 2V THEN THE DS1210 WILL BLOCK THE SECOND RAM ACCESS. +; FAILURE TO COMPLETE TWO RAM ACCESSES BEFORE INSTALLING PROXY WILL RESULT +; IN THE ROM ID BYTES NOT BEING COPIED CORRECTLY AND CP/M APPLICATIONS +; WILL NOT START CORRECTLY WHEN THEY CHECK THE ROM ID VERSION BYTES. +; THE BATTERY CONDITION VALUE IS TEMPORARILY STORED AT HBX_LOC - 1. +; IF THERE IS NO DS1210 IN THE SYSTEM, THE CODE BELOW DOES NO HARM. +; + DEC SP ; RESERVE A STACK BYTE + XOR A ; ZERO MEANS LOW BAT + LD (HBX_LOC - 1),A ; WRITE IT (SHOULD ALWAYS WORK) + INC A ; 1 MEANS BAT OK + LD (HBX_LOC - 1),A ; OVERWRITE IF NVC ALLOWS IT +; +; IF APPBOOT, SAVE CURRENT BANKID +; +; THIS IS NOT GOING TO WORK IF THE APP BOOT IMAGE IS LOADED +; USING THE UNA FAT32 LOADER. SHOULD PROBABLY CHECK THAT THERE +; IS A VALID ROMWBW PROXY IN MEMORY BEFORE DOING THIS. HOWEVER, +; THIS USE CASE IS PROBABLY NON-EXISTENT. THE IMG BOOT IMAGE +; SHOULD WORK FINE WITH THE UNA FAT32 LOADER. +; +#IFDEF APPBOOT + LD A,(HB_CURBNK) + DEC SP ; RESERVE A STACK BYTE + LD (HBX_LOC - 2),A ; SAVE BANK + PUSH AF ; ALSO ON STACK +#ENDIF +; +; INSTALL PROXY IN UPPER MEMORY +; + LD DE,HBX_LOC ; AS PER ABOVE + LD HL,HBX_IMG + LD BC,HBX_SIZ + LDIR +; +; IF APPBOOT, RESTORE CURRENT BANK ID +; +#IFDEF APPBOOT + POP AF + LD (HB_CURBNK),A +#ENDIF +; +; TRANSITION TO UPPER (COMMON) RAM +; + LD HL,0 ; FROM START OF CURRENT BANK + LD DE,$8000 ; TO START OF COMMON RAM + LD BC,$8000-$200-1 ; EVERYTHING BUT THE PROXY AND BATCOND + LDIR + JP HB_START1 +; +; EXECUTION RESUMES HERE AFTER SWITCH TO RAM BANK +; + .ORG $8000 + $ +; +HB_START1: ; BNKCALL ARRIVES HERE, BUT NOW RUNNING IN RAM BANK +; + DIAG(%00000111) + LED(%00000010) +; + LD A,(HBX_LOC - 1) ; RECALL BATTERY STATE AND SAVE + LD (HB_BATCOND),A ; FOR FUTURE REFERENCE +; + LD SP,HBX_LOC ; RESET STACK SINCE WE DO NOT RETURN +; +#IF (MEMMGR == MM_Z280) + ; NOW POINT TO RAM COPY OF Z280 INT/TRAP TABLE + ; HL IS TOP 16 BITS OF PHYSICAL ADDRESS OF IVT + ; IVT *MUST* BE ON A 4K BOUNDARY + LD C,Z280_VPR + LD HL,0 + ((((BID_BIOS & $7F) * 8) + (1 << (RAMLOC - 12))) << 4) + (Z280_IVT >> 8) + LDCTL (C),HL +#ENDIF +; +; IF APPBOOT, WE NEED TO FIX UP A FEW THINGS IN PAGE ZERO +; +#IFDEF APPBOOT +; + ; GET AND SAVE APP BOOT BANK ID + LD A,(HBX_LOC - 2) + LD (HB_APPBNK),A +;;;; +;;; ; MAKE SURE RST 08 VECTOR IS RIGHT +;;; LD A,$C3 +;;; LD ($0008),A +;;; LD HL,HB_INVOKE +;;; LD ($0009),HL +; + ; MAKE SURE IM1 INT VECTOR IS RIGHT + #IF (INTMODE == 1) + ; JP INT_IM1 IF INTERRUPT MODE ACTIVE + LD A,$C3 + LD ($0038),A + LD HL,INT_IM1 + LD ($0039),HL + #ELSE + ; RETI ($ED, $4D) IF NON-INTERRUPT MODE + LD HL,$0038 + LD (HL),$ED + INC HL + LD (HL),$4D + #ENDIF +; +#ENDIF +; + DIAG(%00001111) +; +#IF FALSE +; +; TEST DEBUG *************************************************************************************** +; + PRTS("DEBUG-IVT$") + LD DE,HB_IVT + CALL DUMP_BUFFER + CALL NEWLINE +; +; TEST DEBUG *************************************************************************************** +; +#ENDIF +; +; DISCOVER CPU TYPE +; +; SOME OF THIS CODE IS DERIVED FROM UNA BY JOHN COFFMAN +; +; 0: Z80 +; 1: Z80180 - ORIGINAL Z180 (EQUIVALENT TO HD64180) +; 2: Z8S180 - ORIGINAL S-CLASS, REV. K, AKA SL1960, NO ASCI BRG +; 3: Z8S180 - REVISED S-CLASS, REV. N, W/ ASCI BRG +; 4: Z8280 +; + LD HL,0 ; L = 0 MEANS Z80 +; +#IF (CPUFAM == CPU_Z180) +; + ; TEST FOR ORIGINAL Z180 USING MLT + LD DE,$0506 ; 5 X 6 + MLT DE ; DE = 30 IF Z180 + LD A,E ; CHECK IF MULTIPLY HAPPENED + CP 30 + JR NZ,HB_CPU1 ; IT IS A Z80 IF != 30 + INC L ; FLAG Z80180 OR BETTER +; + ; TEST FOR OLDER S-CLASS (REV K) + IN0 A,(Z180_CCR) ; SUPPOSEDLY ONLY ON S-CLASS + INC A ; FF -> 0 + JR Z,HB_CPU1 + INC L ; FLAG Z8S180 REV K (SL1960) OR BETTER +; + ; TEST FOR NEWER S-CLASS (REV N) + ; ON OLDER S-CLASS, ASCI TIME CONSTANT REG DOES NOT EXIST + ; AND WILL ALWYAS READ BACK AS $FF + OUT0 (Z180_ASTC1L),D ; D = 0 AT THIS POINT + IN0 A,(Z180_ASTC1L) ; ASCI TIME CONSTANT REG + INC A ; FF -> 0 + JR Z,HB_CPU1 + INC L ; FLAG Z8S180 REV N W/ ASCI BRG +; +#ENDIF +; +#IF (CPUFAM == CPU_Z280) +; + ; TEST FOR Z280 PER ZILOG DOC + LD A,$40 ; INITIALIZE THE OPERAND + .DB $CB,$37 ; THIS INSTRUCTION WILL SET THE S FLAG + ; ON THE Z80 CPU AND CLEAR THE S FLAG + ; ON THE Z280 MPU. + JP M,HB_CPU1 ; IF Z80, SKIP AHEAD + LD L,4 ; WE ARE Z280 +; +#ENDIF +; +HB_CPU1: + LD A,L + LD (HB_CPUTYPE),A +; +#IF (SKZENABLE) +; + ; SET THE SK Z80-512K UART CLK2 DIVIDER AS + ; CONFIGURED. NOTE THAT THIS IMPLICITLY + ; CLEARS THE WATCHDOG BIT. THE WATCHDOG + ; WILL BE ENABLED LATER IF CONFIGURED. + LD A,SKZDIV ; GET DIVIDER CODE + OUT ($6D),A ; IMPLEMENT IT +; +#ENDIF +; +#IF (CPUFAM == CPU_Z180) +; + ; AT BOOT, Z180 PHI IS OSC / 2 + LD C,(CPUOSC / 2) / 1000000 + LD DE,(CPUOSC / 2) / 1000 +; + #IF (Z180_CLKDIV >= 1) + LD A,(HB_CPUTYPE) ; GET CPU TYPE + CP 2 ; Z8S180 REV K OR BETTER? + JR C,HB_CPU2 ; IF NOT, NOT POSSIBLE! + ; SET CLOCK DIVIDE TO 1 RESULTING IN FULL XTAL SPEED + LD A,$80 + OUT0 (Z180_CCR),A + ; REFLECT SPEED CHANGE + LD C,CPUOSC / 1000000 + LD DE,CPUOSC / 1000 + #ENDIF + + #IF (Z180_CLKDIV >= 2) + LD A,(HB_CPUTYPE) ; GET CPU TYPE + CP 3 ; Z8S180 REV N OR BETTER? + JR C,HB_CPU2 ; IF NOT, NOT POSSIBLE! + ; SET CPU MULTIPLIER TO 1 RESULTING IN XTAL * 2 SPEED + ; ALSO SET CCR AGAIN BECAUSE OF REPORTS THAT CCR + ; *MUST* BE SET AFTER CMR. + LD A,$80 + OUT0 (Z180_CMR),A ; CPU MULTIPLIER + OUT0 (Z180_CCR),A ; CLOCK DIVIDE + ; REFLECT SPEED CHANGE + LD C,(CPUOSC * 2) / 1000000 + LD DE,(CPUOSC * 2) / 1000 + #ENDIF +; +HB_CPU2: + ; SAVE CPU SPEED + LD A,C + LD (CB_CPUMHZ),A + LD (CB_CPUKHZ),DE +; +#ENDIF +; + DIAG(%00011111) +; + LD A,(CPUMHZ) ; CPU SPEED TO ACCUM AND INIT + CALL DELAY_INIT ; .. SPEED COMPENSATED DELAY +; +#IF (CPUFAM == CPU_Z180) +; + ; SET FINAL DESIRED WAIT STATES + LD A,0 + (Z180_MEMWAIT << 6) | (Z180_IOWAIT << 4) + OUT0 (Z180_DCNTL),A +; +#ENDIF +; +#IF (CPUFAM == CPU_Z280) +; + LD C,Z280_BTCR ; BUS TIMING AND CONTROL REG + LDCTL HL,(C) + LD A,L ; PUT IN A + AND %00111100 ; CLEAR DC,HM, AND IO FIELDS + OR Z280_INTWAIT << 6 ; SET INT ACK WAIT STATE BITS (DC) + OR Z280_MEMHIWAIT << 2 ; SET HIGH 8MB WAIT STATE BITS (HM) + OR Z280_IOWAIT ; SET I/O WAIT STATE BITS + LD L,A ; BACK TO L + LDCTL (C),HL +; + LD C,Z280_BTIR ; BUS TIMING AND INIT REG + LDCTL HL,(C) + LD A,L ; PUT IN A + AND %11110011 ; CLEAR LM FIELD + OR Z280_MEMLOWAIT << 2 ; SET LOW 8MB WAIT STATE BITS + LD L,A ; BACK TO L + LDCTL (C),HL +; +#ENDIF +; +#IF (INTMODE == 2) + ; SETUP Z80 IVT AND INT MODE 2 + LD A,HBX_IVT >> 8 ; SETUP HI BYTE OF IVT ADDRESS + LD I,A ; ... AND PLACE IT IN I REGISTER + + #IF (CPUFAM == CPU_Z180) + ; SETUP Z180 IVT + XOR A ; SETUP LO BYTE OF IVT ADDRESS + OUT0 (Z180_IL),A ; ... AND PLACE IN Z180 IL REGISTER + #ENDIF + + IM 2 ; SWITCH TO INT MODE 2 +#ENDIF +; +#IF (INTMODE == 3) +; + ; SETUP Z280 INT A FOR VECTORED INTERRUPTS + LD HL,%0010000000000000 + LD C,Z280_ISR + LDCTL (C),HL +; + IM 3 +; +#ENDIF +; +#IF (CPUFAM == CPU_Z180) +; + #IF (INTMODE == 2) +; + ; MASK ALL EXTERNAL INTERRUPTS FOR NOW + LD A,$01 ; INT0 ENABLED, INT1-2 DISABLED + OUT0 (Z180_ITC),A ; WRITE TO INT/TRAP CONTROL REGISTER +; + #ENDIF +; +#ENDIF +; + DIAG(%00111111) +#IF FALSE +; +; TEST DEBUG *************************************************************************************** +; + CALL NEWLINE + CALL REGDMP +; +; TEST DEBUG *************************************************************************************** +; +#ENDIF +; +#IF (DSKYENABLE) + CALL DSKY_PREINIT +; + LD HL,MSG_HBVER + 5 + LD A,(DSKY_HEXMAP + RMJ) + OR $80 + LD (HL),A + INC HL + LD A,(DSKY_HEXMAP + RMN) + OR $80 + LD (HL),A + INC HL + LD A,(DSKY_HEXMAP + RUP) + LD (HL),A + LD HL,MSG_HBVER + CALL DSKY_SHOW +#ENDIF +; + ; INITIALIZE SERIAL PORT + CALL CINIT +; +#IF FALSE +; +; TEST DEBUG *************************************************************************************** +; + CALL NEWLINE + CALL REGDMP +; +; TEST DEBUG *************************************************************************************** +; +#ENDIF +; + DIAG(%01111111) + LED(%00000011) +; +#IF FALSE +; +; TEST DEBUG *************************************************************************************** +; + CALL NEWLINE2 + PRTS("DEBUG+IVT$") + LD DE,HB_IVT + CALL DUMP_BUFFER +; +; TEST DEBUG *************************************************************************************** +; +#ENDIF +; +; ANNOUNCE HBIOS +; + CALL NEWLINE2 + PRTX(STR_BANNER) +; + DIAG(%11111111) +; +; IO PORT SCAN +; +#IF FALSE +PSCN: + LD C,0 ; IO PORT NUMBER + LD B,0 ; LOOP COUNTER + CALL NEWLINE +PSCN1: + CALL NEWLINE + LD A,C + CALL PRTHEXBYTE + CALL PC_COLON + CALL PC_SPACE + CALL DELAY + LD A,C + LD (PSCNX),A +PSCNX .EQU $ + 1 + IN A,(0) + CALL PRTHEXBYTE + CALL PC_COMMA + PUSH BC + LD B,0 + IN A,(C) + POP BC + CALL PRTHEXBYTE + INC C + DJNZ PSCN1 +#ENDIF +; + HB_EI ; INTERRUPTS SHOULD BE OK NOW +; +; DISPLAY PLATFORM INFORMATION +; + CALL NEWLINE2 + PRTX(STR_PLATFORM) +; + LD A,(HB_CPUTYPE) ; GET CPU TYPE + LD DE,HB_CPU_STR ; DISPLAY IT + CALL PRTIDXDEA +; + PRTS(" @ $") + LD HL,(CB_CPUKHZ) + CALL PRTD3M ; PRINT AS DECIMAL WITH 3 DIGIT MANTISSA + PRTS("MHz$") +; +#IF (CPUFAM == CPU_Z180) + PRTS(" IO=0x$") + LD A,Z180_BASE + CALL PRTHEXBYTE +#ENDIF +; +#IF (CPUFAM == CPU_Z280) + CALL PRTSTRD + .TEXT ", BUS @ $" + LD C,Z280_BTIR ; BUS TIMING AND CTL REG + LDCTL HL,(C) + LD A,L ; MOVE TO A + AND %00000011 ; ISOLATE CS FIELD + LD HL,(CB_CPUKHZ) ; GET CPU SPEED + CP %00000001 ; BUS @ 1/1 + JR Z,HB_Z280BUS ; GOT IT, SHOW IT + SRL H ; DIVIDE + RR L ; ... BY 2 + CP %00000000 ; BUS @ 1/2 + JR Z,HB_Z280BUS ; GOT IT, SHOW IT + SRL H ; DIVIDE + RR L ; ... BY 2 + CP %00000010 ; BUS @ 1/4 + JR Z,HB_Z280BUS ; GOT IT, SHOW IT + PRTS("???$") ; INVALID VALUE + JR HB_Z280BUS1 ; CONTINUE +HB_Z280BUS: + CALL PRTD3M ; PRINT AS DECIMAL WITH 3 DIGIT MANTISSA +HB_Z280BUS1: + PRTS("MHz$") ; SUFFIX +#ENDIF +; +; DISPLAY CPU CONFIG +; + CALL NEWLINE + +#IF (CPUFAM == CPU_Z280) + LD A,Z280_MEMLOWAIT + CALL PRTDECB + LD A,'/' + CALL COUT + LD A,Z280_MEMHIWAIT + CALL PRTDECB + CALL PRTSTRD + .TEXT " MEM W/S, $" +#ELSE + XOR A + #IF (CPUFAM == CPU_Z180) + LD A,Z180_MEMWAIT + #ENDIF + CALL PRTDECB + CALL PRTSTRD + .TEXT " MEM W/S, $" +#ENDIF + LD A,1 +#IF (CPUFAM == CPU_Z180) + LD A,Z180_IOWAIT + 1 +#ENDIF +#IF (CPUFAM == CPU_Z280) + LD A,Z280_IOWAIT + 1 +#ENDIF + CALL PRTDECB + CALL PRTSTRD + .TEXT " I/O W/S$" +#IF (CPUFAM == CPU_Z280) + CALL PRTSTRD + .TEXT ", $" + LD A,Z280_INTWAIT + CALL PRTDECB + CALL PRTSTRD + .TEXT " INT W/S$" +#ENDIF +#IF (INTMODE > 0) + CALL PRTSTRD + .TEXT ", INT MODE $" + LD A,INTMODE + CALL PRTDECB +#ENDIF +; + CALL PRTSTRD + .TEXT ", $" + CALL PRTSTRD +#IF (MEMMGR == MM_NONE) + .TEXT "NONE$" +#ENDIF +#IF (MEMMGR == MM_SBC) + .TEXT "SBC$" +#ENDIF +#IF (MEMMGR == MM_Z2) + .TEXT "Z2$" +#ENDIF +#IF (MEMMGR == MM_N8) + .TEXT "N8$" +#ENDIF +#IF (MEMMGR == MM_Z180) + .TEXT "Z180$" +#ENDIF +#IF (MEMMGR == MM_Z280) + .TEXT "Z280$" +#ENDIF +#IF (MEMMGR == MM_ZRC) + .TEXT "ZRC$" +#ENDIF +#IF (MEMMGR == MM_MBC) + .TEXT "MBC$" +#ENDIF + CALL PRTSTRD + .TEXT " MMU$" +; +; DISPLAY MEMORY CONFIG +; + CALL NEWLINE + LD HL,ROMSIZE + CALL PRTDEC + CALL PRTSTRD + .TEXT "KB ROM, $" + LD HL,RAMSIZE + CALL PRTDEC + CALL PRTSTRD + .TEXT "KB RAM$" +; +#IF (CPUFAM == CPU_Z280) + CALL NEWLINE + PRTS("Z280: $") + PRTS("MSR=$") + LD C,Z280_MSR ; MASTER STATUS REGISTER + LDCTL HL,(C) + CALL PRTHEXWORDHL + CALL PC_SPACE + PRTS("BTCR=$") + LD C,Z280_BTCR ; BUS TIMING AND CONTROL REGISTER + LDCTL HL,(C) + CALL PRTHEXWORDHL + CALL PC_SPACE + PRTS("BTIR=$") + LD C,Z280_BTIR ; BUS TIMING AND CONTROL REGISTER + LDCTL HL,(C) + CALL PRTHEXWORDHL + CALL PC_SPACE + PRTS("CCR=$") + LD C,Z280_CCR ; CACHE CONTROL REGISTER + LDCTL HL,(C) + CALL PRTHEXWORDHL +#ENDIF +; +#IFDEF ROMBOOT +; +; ROM CHECKSUM VERIFICATION +; THE FIRST ROM BANK HAS A CHECKSUM INJECTED SUCH THAT +; A COMPUTED CHECKSUM ACROSS THE ENTIRE BANK SHOLD ALWAYS BE ZERO +; +HB_ROMCK: + CALL NEWLINE + PRTS("ROM VERIFY:$") +; + ; TEST FIRST 4 BANKS OF ROM + LD B,1 ; 1 BANK + LD C,0 ; STARTING AT BANK 0 +HB_ROMCK1: + PUSH BC ; SAVE LOOP CONTROL + CALL HB_CKBNK ; TEST THE BANK + CALL PC_SPACE ; FORMATTING + CALL PRTHEXBYTE ; PRINT RESULT + POP BC ; RESTORE LOOP CONTROL + OR A ; SET FLAGS + JR NZ,HB_ROMCK2 ; HANDLE FAILURE + INC C ; NEXT BANK + DJNZ HB_ROMCK1 ; LOOP FOR BANKS + PRTS(" PASS$") ; DISPLAY SUCCESS + JR HB_ROMCKZ ; CONTINUE BOOT +HB_ROMCK2: + PRTS(" FAIL$") ; DISPLAY ERROR + JR HB_ROMCKZ ; CONTINUE BOOT +; +; VERIFY ROM CHECKSUM BANK SPECIFIED IN REG C +; THIS MUST BE COPIED TO UPPER RAM TO RUN +; INTERRUPTS ARE DISABLED SINCE PAGE ZERO VECTOR WILL BE +; SWAPPED OUT. ASSUMES THAT INTERRUPTS ARE ENABLED AT ENTRY. +; +HB_CKBNK: + HB_DI ; SUPPRESS INTERRUPTS + LD HL,$7FFF ; START AT BANK END + LD BC,1 ; DECREMENT VALUE + XOR A ; ZERO ACCUM +HB_CKBNK1: + ADD A,(HL) ; ADD NEXT BYTE + OR A ; CLEAR CARRY + SBC HL,BC ; DECREMENT + JR NC,HB_CKBNK1 ; LOOP TILL DONE + HB_EI ; ALLOW INTERRUPTS AGAIN + RET ; AND DONE +; +HB_CKBNKSIZ .EQU $-HB_CKBNK ; SIZE OF ROUTINE +; +HB_ROMCKZ: +; +#ENDIF +; +; LOW BATTERY DIAGNOSTIC MESSAGE +; +#IF (BATCOND) + LD A,(HB_BATCOND) + OR A + LD DE,STR_LOWBAT + CALL Z,WRITESTR +#ENDIF +; + LD DE,STR_SYSHALT + CALL WRITESTR + JR $ + DI + HALT +; +;================================================================================================== +; INTERRUPT VECTOR TABLE (MUST START AT PAGE BOUNDARY!!!) +;================================================================================================== +; + .FILL $100 - ($ & $FF) +; +; +; IM1 INTERRUPTS ARRIVE HERE AFTER BANK SWITCH TO HBIOS BANK +; LIST OF IM1 INT CALLS IS BUILT DYNAMICALLY BELOW +; SEE HB_ADDIM1 ROUTINE +; EACH ENTRY WILL LOOK LIKE: +; CALL XXXX ; CALL INT HANDLER +; RET NZ ; RETURN IF HANDLED +; +; NOTE THAT THE LIST IS INITIALLY FILLED WITH CALLS TO HB_BADINT. +; AS THE TABLE IS POPULATED, THE ADDRESS OF HB_BADINT IS OVERLAID +; WITH THE ADDRESS OF A REAL INTERRUPT HANDLER. +; +; THERE IS ROOM FOR 8 ENTRIES PLUS A FINAL CALL TO HB_BADINT. +; +#IF (INTMODE < 2) +; +HB_IVT: + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ +; +#ENDIF +; +; IM2 INTERRUPTS ARRIVE HERE AFTER BANK SWITCH TO HBIOS BANK +; THE LIST OF JP TABLE ENTRIES MATCHES THE IM2 VECTORS ONE FOR +; ONE. ANY CALL TO THE PRIMARY IVT (HBX_IVT) WILL BE MAPPED TO +; THE CORRESPONDING JP TABLE ENTRY BELOW AFTER THE BANK SWITCH. +; +; NOTE THAT THE LIST IS INITIALLY FILLED WITH CALLS TO HB_BADINT. +; IT IS INTENDED THAT HARDWARE DRIVERS WILL DYNAMICALLY OVERLAY +; THE ADDRESS PORTION OF THE APPROPRIATE JP TO POINT TO THE +; DESIRED INTERRUPT HANDLER DURING THE DRIVERS INITIALIZATION. +; +; NOTE THAT EACH ENTRY HAS A FILLER BYTE OF VALUE ZERO. THIS BYTE +; HAS NO FUNCTION. IT IS JUST USED TO MAKE ENTRIES AN EVEN 4 BYTES. +; +#IF ((INTMODE == 2) | (INTMODE == 3)) +; +HB_IVT: +HB_IVT00: JP HB_BADINT \ .DB 0 +HB_IVT01: JP HB_BADINT \ .DB 0 +HB_IVT02: JP HB_BADINT \ .DB 0 +HB_IVT03: JP HB_BADINT \ .DB 0 +HB_IVT04: JP HB_BADINT \ .DB 0 +HB_IVT05: JP HB_BADINT \ .DB 0 +HB_IVT06: JP HB_BADINT \ .DB 0 +HB_IVT07: JP HB_BADINT \ .DB 0 +HB_IVT08: JP HB_BADINT \ .DB 0 +HB_IVT09: JP HB_BADINT \ .DB 0 +HB_IVT0A: JP HB_BADINT \ .DB 0 +HB_IVT0B: JP HB_BADINT \ .DB 0 +HB_IVT0C: JP HB_BADINT \ .DB 0 +HB_IVT0D: JP HB_BADINT \ .DB 0 +HB_IVT0E: JP HB_BADINT \ .DB 0 +HB_IVT0F: JP HB_BADINT \ .DB 0 +; +#ENDIF +; +#IF (INTMODE == 1) +; +; ROUTINE BELOW IS USED TO ADD A NEW VECTOR TO THE IM1 +; CALL LIST ABOVE. ENTER WITH HL=VECTOR ADDRESS IN HBIOS +; +HB_ADDIM1: + EX DE,HL ; VECTOR ADDRESS TO DE + LD HL,(HB_IM1PTR) ; GET PTR FOR NEXT ENTRY + INC HL ; BUMP PTR TO ADDRESS FIELD OF CALL OPCODE + LD (HL),E ; ADD VECTOR ADDRESS + INC HL ; ... + LD (HL),D ; ... + INC HL ; BUMP PTR + INC HL ; BUMP PTR + LD (HB_IM1PTR),HL ; SAVE UPDATED POINTER + LD HL,HB_IM1CNT ; POINT TO ENTRY COUNT + INC (HL) ; INCREMENT + RET ; DONE +; +HB_IM1CNT .DB 0 ; NUMBER OF ENTRIES IN CALL LIST +HB_IM1MAX .DB 8 ; MAX ENTRIES IN CALL LIST +HB_IM1PTR .DW HB_IVT ; POINTER FOR NEXT IM1 ENTRY +; +#ENDIF +; +; BAD INTERRUPT HANDLER +; +HB_BADINT: + +#IF FALSE ; *DEBUG* + LD HL,HB_BADINTCNT + INC (HL) + LD A,(HL) + OUT (DIAGPORT),A + OR $FF + RET +HB_BADINTCNT .DB 0 +#ENDIF ; *DEBUG* + + CALL NEWLINE2 + PRTS("+++ BAD INT $") + LD A,L + RRCA + RRCA + CALL PRTHEXBYTE + PRTS("H: $") + + CALL XREGDMP + ;CALL CONTINUE + OR $FF ; SIGNAL INTERRUPT HANDLED + RET +; +; Z280 BAD INT HANDLER +; +#IF (MEMMGR == MM_Z280) +; +Z280_BADINT: + ; SAVE REASON CODE FOR POSSIBLE RETURN VIA RETIL + EX (SP),HL ; GET MSR, SAVE HL + LD (HB_RCSAV),HL ; SAVE IT + POP HL ; RECOVER HL, POP STACK + ; SAVE MSR FOR POSSIBLE RETURN VIA RETIL + EX (SP),HL ; GET MSR, SAVE HL + LD (HB_MSRSAV),HL ; SAVE IT + POP HL ; RECOVER HL, POP STACK +; + PUSH DE + LD DE,Z280_BADINTSTR + CALL NEWLINE2 + PRTS("+++ $") + CALL WRITESTR + POP DE + CALL XREGDMP +; + ; RECOVER MSR, THEN RETURN VIA RETIL + PUSH HL ; SAVE HL + LD HL,(HB_RCSAV) ; GET SAVED REASON CODE + PRTS(" RC=$") + CALL PRTHEXWORDHL ; DUMP MSR + LD HL,(HB_MSRSAV) ; GET SAVED MSR + PRTS(" MSR=$") + CALL PRTHEXWORDHL ; DUMP MSR + EX (SP),HL ; MSR TO STK, RECOVER HL +; + .DB $ED,$55 ; RETIL +; +Z280_SSTEP: + ; SAVE HL AND MSR FOR POSSIBLE RETURN VIA RETIL + EX (SP),HL ; GET MSR, SAVE HL + LD (HB_MSRSAV),HL ; SAVE IT + POP HL ; RECOVER HL, POP STACK +; + PUSH DE + LD DE,Z280_SSTEPSTR + JP Z280_DIAG +; +Z280_BRKHLT: + ; SAVE HL AND MSR FOR POSSIBLE RETURN VIA RETIL + EX (SP),HL ; GET MSR, SAVE HL + LD (HB_MSRSAV),HL ; SAVE IT + POP HL ; RECOVER HL, POP STACK +; + PUSH DE + LD DE,Z280_BRKHLTSTR + JP Z280_DIAG +; +Z280_DIVEXC: + ; SAVE HL AND MSR FOR POSSIBLE RETURN VIA RETIL + EX (SP),HL ; GET MSR, SAVE HL + LD (HB_MSRSAV),HL ; SAVE IT + POP HL ; RECOVER HL, POP STACK +; + PUSH DE + LD DE,Z280_DIVEXCSTR + JP Z280_DIAG +; +Z280_STKOVR: + ; SAVE HL AND MSR FOR POSSIBLE RETURN VIA RETIL + EX (SP),HL ; GET MSR, SAVE HL + LD (HB_MSRSAV),HL ; SAVE IT + POP HL ; RECOVER HL, POP STACK +; + PUSH DE + LD DE,Z280_STKOVRSTR + JP Z280_DIAG +; +Z280_ACCVIO: + ; SAVE HL AND MSR FOR POSSIBLE RETURN VIA RETIL + EX (SP),HL ; GET MSR, SAVE HL + LD (HB_MSRSAV),HL ; SAVE IT + POP HL ; RECOVER HL, POP STACK +; + PUSH DE + LD DE,Z280_ACCVIOSTR + JP Z280_DIAG +; +Z280_DIAG: + CALL NEWLINE2 + PRTS("+++ $") + CALL WRITESTR + POP DE + CALL XREGDMP +; + ; RECOVER MSR, THEN RETURN VIA RETIL + PUSH HL ; SAVE HL + LD HL,(HB_MSRSAV) ; GET SAVED MSR + PRTS(" MSR=$") + CALL PRTHEXWORDHL ; DUMP MSR + EX (SP),HL ; MSR TO STK, RECOVER HL +; + ;RETIL + DI + HALT +; +Z280_BADINTSTR .TEXT "BAD INT $" +Z280_SSTEPSTR .TEXT "SINGLE STEP $" +Z280_BRKHLTSTR .TEXT "BREAK HALT $" +Z280_DIVEXCSTR .TEXT "DIVISION EXCEPTION $" +Z280_STKOVRSTR .TEXT "STACK OVERFLOW $" +Z280_ACCVIOSTR .TEXT "ACCESS VIOLATION $" +; +#ENDIF +; +; Z280 PRIVILEGED INSTRUCTION HANDLER +; +#IF (MEMMGR == MM_Z280) +; +Z280_PRIVINST: + ; SAVE HL AND MSR FOR POSSIBLE RETURN VIA RETIL + EX (SP),HL ; GET MSR, SAVE HL + LD (HB_MSRSAV),HL ; SAVE IT + POP HL ; RECOVER HL, POP STACK + EX (SP),HL ; GET ADR, SAVE HL +; + PUSH AF + PUSH BC + PUSH DE +; + .DB $ED,$96 ; LDUP A,(HL) +; + ; HANDLE DI + CP $F3 ; DI? + JR NZ,Z280_PRIVINST2 + HB_DI ; DO THE DI + INC HL ; BUMP PAST IT + JR Z280_PRIVINSTX +; +Z280_PRIVINST2: + ; HANDLE EI + CP $FB ; EI? + JR NZ,Z280_PRIVINST3 + HB_EI ; DO THE EI + INC HL ; BUMP PAST IT + JR Z280_PRIVINSTX +; +Z280_PRIVINST3: + ; SOMETHING ELSE, DIAGNOSE & HALT SYSTEM + LD DE,Z280_PRIVSTR + CALL WRITESTR + CALL PRTHEXWORDHL +; + ; DUMP 16 BYTES OF USER ADDRESS SPACE + CALL PC_SPACE + CALL PC_LBKT + LD B,$10 +Z280_PRIVINST4: + .DB $ED,$96 ; LDUP A,(HL) + CALL PRTHEXBYTE + INC HL + DJNZ Z280_PRIVINST4 + CALL PC_RBKT +; + ; GO NO FURTHER + DI + HALT +; +Z280_PRIVINSTX: + ; RESTORE REGISTERS + POP DE + POP BC + POP AF +; + ; RECOVER HL AND MSR, THEN RETURN VIA RETIL + EX (SP),HL ; RECOVER HL, ADR TO STK + PUSH HL ; SAVE HL + LD HL,(HB_MSRSAV) ; GET SAVED MSR + EX (SP),HL ; MSR TO STK, RECOVER HL + .DB $ED,$55 ; RETIL +; +HB_MSRSAV .DW 0 ; SAVED MSR +HB_RCSAV .DW 0 ; SAVED REASON CODE +; +Z280_PRIVSTR .TEXT "\r\n\r\n*** Privileged Instruction @$" +; +#ENDIF +; +;================================================================================================== +; Z280 INTERRUPT VECTOR TABLE +;================================================================================================== +; +#IF (MEMMGR == MM_Z280) +; + ; THE Z280 IVT MUST BE ON A 4K BOUNDARY. IT HAS BEEN LOCATED + ; HERE IN AN EFFORT TO MINIMIZE WASTED SPACE. THERE SHOULD BE + ; A LITTLE LESS THAN 4K OF CODE ABOVE. +; + .FILL $1000 - ($ & $FFF) ; MUST BE 4K ALIGNED! +; +Z280_IVT: + .DW 0, 0 ; RESERVED + .DW 0 ; NMI MSR + .DW 0 ; NMI VECTOR + .DW $0000 ; INT A MSR + .DW Z280_BADINT ; INT A VECTOR + .DW $0000 ; INT B MSR + .DW Z280_BADINT ; INT B VECTOR + .DW $0000 ; INT C MSR + .DW Z280_BADINT ; INT C VECTOR + .DW $0000 ; COUNTER/TIMER 0 MSR + .DW Z280_BADINT ; COUNTER/TIMER 0 VECTOR + .DW $0000 ; COUNTER/TIMER 1 MSR + .DW Z280_BADINT ; COUNTER/TIMER 1 VECTOR + .DW 0, 0 ; RESERVED + .DW $0000 ; COUNTER/TIMER 2 MSR + .DW Z280_BADINT ; COUNTER/TIMER 2 VECTOR + .DW $0000 ; DMA CHANNEL 0 MSR + .DW Z280_BADINT ; DMA CHANNEL 0 VECTOR + .DW $0000 ; DMA CHANNEL 1 MSR + .DW Z280_BADINT ; DMA CHANNEL 1 VECTOR + .DW $0000 ; DMA CHANNEL 2 MSR + .DW Z280_BADINT ; DMA CHANNEL 2 VECTOR + .DW $0000 ; DMA CHANNEL 3 MSR + .DW Z280_BADINT ; DMA CHANNEL 3 VECTOR + .DW $0000 ; UART RECEIVER MSR + .DW Z280_BADINT ; UART RECEIVER VECTOR + .DW $0000 ; UART TRANSMITTER MSR + .DW Z280_BADINT ; UART TRANSMITTER VECTOR + .DW $0000 ; SINGLE STEP TRAP MSR + .DW Z280_SSTEP ; SINGLE STEP TRAP VECTOR + .DW $0000 ; BREAK ON HALT TRAP MSR + .DW Z280_BRKHLT ; BREAK ON HALT TRAP VECTOR + .DW $0000 ; DIVISION EXCEPTION TRAP MSR + .DW Z280_DIVEXC ; DIVISION EXCEPTION TRAP VECTOR + .DW $0000 ; STACK OVERFLOW WARNING TRAP MSR + .DW Z280_STKOVR ; STACK OVERFLOW WARNING TRAP VECTOR + .DW $0000 ; ACCESS VIOLATION TRAP MSR + .DW Z280_ACCVIO ; ACCESS VIOLATION TRAP VECTOR + .DW $0000 ; SYSTEM CALL TRAP MSR + .DW Z280_SYSCALL ; SYSTEM CALL TRAP VECTOR + .DW $0000 ; PRIVILEGED INSTRUCTION TRAP MSR + .DW Z280_PRIVINST ; PRIVILEGED INSTRUCTION TRAP VECTOR + .DW $0000 ; EPU <- MEMORY EXTENDED INSTRUCTION TRAP MSR + .DW $0000 ; EPU <- MEMORY EXTENDED INSTRUCTION TRAP VECTOR + .DW $0000 ; MEMORY <- EPU EXTENDED INSTRUCTION TRAP MSR + .DW $0000 ; MEMORY <- EPU EXTENDED INSTRUCTION TRAP VECTOR + .DW $0000 ; A <- EPU EXTENDED INSTRUCTION TRAP MSR + .DW $0000 ; A <- EPU EXTENDED INSTRUCTION TRAP VECTOR + .DW $0000 ; EPU INTERNAL OPERATION EXTENDED INSTRUCTION TRAP MSR + .DW $0000 ; EPU INTERNAL OPERATION EXTENDED INSTRUCTION TRAP VECTOR + .DW 0, 0 ; RESERVED + .DW 0, 0 ; RESERVED + ; PROGRAM COUNTER VALUES FOR NMI/INTA (16) + .DW HBX_IV00 + .DW HBX_IV01 + .DW HBX_IV02 + .DW HBX_IV03 + .DW HBX_IV04 + .DW HBX_IV05 + .DW HBX_IV06 + .DW HBX_IV07 + .DW HBX_IV08 + .DW HBX_IV09 + .DW HBX_IV0A + .DW HBX_IV0B + .DW HBX_IV0C + .DW HBX_IV0D + .DW HBX_IV0E + .DW HBX_IV0F + ; THE REMAINDER OF THE Z280 IVT IS TRUNCATED HERE BECAUSE IT + ; TAKES A BUNCH OF SPACE AND IS NOT USED. WE SUPPORT ONLY + ; 16 VECTORED INTERRUPTS AND THEY MUST BE CONNECTED TO INTA. +; +#ENDIF +; +; Z280 BANK SELECTION (CALLED FROM PROXY) +; +#IF (MEMMGR == MM_Z280) +; +; REG A HAS BANK ID, REG B HAS INITIAL PDR TO PROGRAM +; REGISTERS AF, BC, HL DESTROYED +; +; THIS ROUTINE MAY BE RELOCATED TO RUN IN HIGH MEMORY IN CERTAIN CASES +; LIKE A SYSTEM RESTART. IT MUST BE KEPT ENTIRELY RELOCATABLE. +; +Z280_BNKSEL: + ;; *DEBUG* + ;CALL PC_LBKT + ;CALL PRTHEXBYTE + ;CALL PC_RBKT + + ; SELECT I/O PAGE $FE (SAVING PREVIOUS VALUE) + LD C,Z280_IOPR ; REG C POINTS TO I/O PAGE REGISTER + LDCTL HL,(C) ; GET CURRENT I/O PAGE + PUSH HL ; SAVE IT + LD L,$FF ; NEW I/O PAGE + LDCTL (C),HL +; + ; CONVERT BANK ID TO TOP 12 BITS OF PHYSICAL ADDRESS + ; WITH $0A IN THE LOW ORDER NIBBLE: + ; BANK ID: R000 BBBB + ; PDR: R000 0BBB B000 1010 (RC2014) + ; PDR: 0000 RBBB B000 1010 (ZZ80MB) +; + MULTU A,$80 ; HL=0R00 0BBB B000 0000 + BIT 6,H ; RAM BIT SET? + JR Z,Z280_BNKSEL2 ; IF NOT, ALL DONE + RES 6,H ; OTHERWISE, MOVE RAM BIT + SET RAMLOC-16,H ; HL=0000 RBBB B000 0000 +; +Z280_BNKSEL2: +; + ; SET LOW NIBBLE + LD A,$0A ; VALUE FOR LOW NIBBLE + .DB $ED,$6D ; ADD HL,A ; HL=0000 RBBB B000 1010 +; + ; POINT TO FIRST PDR TO PROGRAM + LD A,B ; INITIAL PDR TO PROG + OUT (Z280_MMUPDRPTR),A ; SET THE PDR POINTER +; + ; PROGRAM 8 PDRS + LD C,Z280_MMUBLKMOV ; PDR BLOCK MOVE PORT + ;LD B,8 ; PROGRAM 8 PDRS + LD A,$10 ; PDR VALUE INCREMENT +Z280_BNKSEL3: + ; PROGRAM 8 PDR VALUES + ; LOOP UNROLLED FOR SPEED + OUTW (C),HL ; WRITE VALUE + ADD HL,A ; BUMP VALUE + OUTW (C),HL ; WRITE VALUE + ADD HL,A ; BUMP VALUE + OUTW (C),HL ; WRITE VALUE + ADD HL,A ; BUMP VALUE + OUTW (C),HL ; WRITE VALUE + ADD HL,A ; BUMP VALUE + OUTW (C),HL ; WRITE VALUE + ADD HL,A ; BUMP VALUE + OUTW (C),HL ; WRITE VALUE + ADD HL,A ; BUMP VALUE + OUTW (C),HL ; WRITE VALUE + ADD HL,A ; BUMP VALUE + OUTW (C),HL ; WRITE VALUE + ADD HL,A ; BUMP VALUE + ;DJNZ Z280_BNKSEL3 ; DO ALL PDRS +; + ; RESTORE I/O PAGE + LD C,Z280_IOPR ; REG C POINTS TO I/O PAGE REGISTER + POP HL ; RECOVER ORIGINAL I/O PAGE + LDCTL (C),HL +; + RET +; +Z280_BNKSEL_LEN .EQU $ - Z280_BNKSEL +; +#ENDIF +; +; Z280 BANK COPY (CALLED FROM PROXY) +; +#IF (MEMMGR == MM_Z280) +; +Z280_BNKCPY: + ; Z280 MEMORY TO MEMORY DMA + ; USE FLOW THROUGH MODE + ; SINGLE BYTE TRANSFER + ; TRANSACTION DESCRIPTION REGISTER (TDR) + ; %0000 0000 0000 0000 + ; - AUTO INCREMENT MEMORY + ; - FLOWTHROUGH OPERATION + ; - SINGLE TRANSACTION (CAN WE USE CONTINUOUS???) + ; - 1 BYTE XFER SIZE +; + ; SAVE INCOMING REGISTERS + PUSH HL + PUSH DE + PUSH BC +; + PUSH BC ; SAVE COUNT + PUSH HL ; SAVE SOURCE ADDRESS +; + ; SELECT I/O PAGE $FF + LD C,Z280_IOPR ; I/O PAGE REGISTER + LDCTL HL,(C) ; GET CURRENT I/O PAGE + LD (IOPRVAL),HL ; SAVE IT + LD L,$FF ; I/O PAGE $FF + LDCTL (C),HL +; + LD C,Z280_DMA0_DSTL ; START WITH DEST REG LO +; + LD A,(HB_DSTBNK) ; DEST BANK TO ACCUM + CALL Z2DMAADR ; SETUP DEST ADR REGS +; + POP DE ; SRC ADR TO DE + LD A,(HB_SRCBNK) ; DEST BANK TO ACCUM + CALL Z2DMAADR ; SETUP SOURCE ADR REGS +; + POP HL ; COUNT TO HL + OUTW (C),HL + INC C ; BUMP TO TDR +; + LD HL,$8000 ; ENABLE DMA0 TO RUN! + OUTW (C),HL +; + ; WAIT FOR XFER TO COMPLETE +Z2DMALOOP: + .DB $ED,$B7 ; INW HL,(C) + BIT 7,H ; CHECK EN BIT OF TDR + JR NZ,Z2DMALOOP ; LOOP WHILE ACTIVE +; + ; RESTORE I/O PAGE + LD C,Z280_IOPR ; I/O PAGE REGISTER + LD HL,(IOPRVAL) ; RESTORE I/O PAGE + LDCTL (C),HL +; + ; SETUP RETURN VALUES + POP BC ; RECOVER ORIGINAL BC + POP DE ; RECOVER ORIGINAL DE + POP HL ; RECOVER ORIGINAL HL + ADD HL,BC ; INCREMENT SRC ADR BY COUNT + EX DE,HL ; SWAP + ADD HL,BC ; INCREMENT DST ADR BY COUNT + EX DE,HL ; SWAP BACK + LD BC,0 ; COUNT IS NOW ZERO +; + RET +; +Z2DMAADR: + ; SET ADDRESS REGISTERS, BANK IN A, ADDRESS IN DE + ; C POINTS TO FIRST DMA ADR PORT TO SET + ; A=R000 BBBB, DE=0AAA AAAA AAAA AAAA + ; RC: DMA HI=0000 RBBB BAAA 1111 LO=1111 AAAA AAAA AAAA + ; ZZ: DMA HI=R000 0BBB BAAA 1111 LO=1111 AAAA AAAA AAAA + BIT 7,D ; HIGH RAM? + JR Z,Z2DMAADR1 ; NO, SKIP + LD A,$8F ; SUBSTITUTE COMMON RAM BANK ID +; +Z2DMAADR1: + ; ADR HI FROM A:DE + LD L,D ; L=?AAA AAAA + LD H,A ; H=R000 BBBB + SLA L ; L=AAAA AAA0 ? + SRL H ; H=0R00 0BBB B + RR L ; L=BAAA AAAA 0 + LD A,$0F ; A=0000 1111 + OR L ; A=BAAA 1111 + LD L,A ; L=BAAA 1111 +; + ; MOVE THE RAM/ROM BIT. + ; RC2014 DMA HI=0000 RBBB BAAA 1111 LO=1111 AAAA AAAA AAAA + ; ZZ80MB DMA HI=R000 0BBB BAAA 1111 LO=1111 AAAA AAAA AAAA + BIT 6,H + JR Z,Z2DMAADR2 + RES 6,H + SET RAMLOC-16,H +; +Z2DMAADR2: + PUSH HL ; SAVE IT FOR NOW + + ; ADR LO FROM DE: + LD L,E ; L=AAAA AAAA + LD A,$F0 ; A=1111 0000 + OR D ; A=1111 AAAA + LD H,A ; HL=1111 AAAA AAAA AAAA +; + ; SET ADR LO REG + OUTW (C),HL + INC C ; BUMP TO ADR HI REG +; + ; SET ADR HI REG + POP HL ; RECOVER THE HI VAL + OUTW (C),HL + INC C ; BUMP TO NEXT REG +; + RET +#ENDIF +; +; Z280 SYSCALL VECTOR ENTRY POINT. TAKES STACK PARAMETER AS A BRANCH +; ADDRESS AND CALLS IT. ALLOWS ANY USER MODE CODE TO CALL INTO AN +; ARBITRARY LOCATION OF SYSTEM MODE CODE. +; +#IF (MEMMGR == MM_Z280) +Z280_SYSCALL: + EX (SP),HL + LD (Z280_SYSCALL_GO+1),HL + POP HL +Z280_SYSCALL_GO: + CALL $FFFF ; PARM SET ABOVE + .DB $ED,$55 ; RETIL +#ENDIF +; +#DEFINE USEDELAY +#INCLUDE "util.asm" +; +#IF (DSKYENABLE) +#DEFINE DSKY_KBD + #IF (DSKYMODE == DSKYMODE_V1) +#INCLUDE "dsky.asm" + #ENDIF + #IF (DSKYMODE == DSKYMODE_NG) +#INCLUDE "dskyng.asm" + #ENDIF +#ENDIF +; +; PANIC: DUMP MACHINE STATE AND HALT +; +PANIC: + PUSH DE + LD DE,STR_PANIC + CALL WRITESTR + POP DE + CALL XREGDMP ; DUMP REGISTERS + JR SYSHALT ; FULL STOP +; +; +; +CONTINUE: + PUSH AF +CONTINUE1: + PUSH DE + LD DE,STR_CONTINUE + CALL WRITESTR + POP DE + CALL CIN + RES 5,A ; FORCE UPPERCASE (IMPERFECTLY) + CALL COUT ; ECHO + CP 'Y' + JR Z,CONTINUE3 + CP 'N' + JR Z,SYSHALT + JR CONTINUE1 +CONTINUE3: + CALL NEWLINE + POP AF + RET +; +; +; +SYSHALT: + LD DE,STR_HALT + CALL WRITESTR + DI + HALT +; +; PRINT VALUE OF HL AS THOUSANDTHS, IE. 0.000 +; +PRTD3M: + PUSH BC + PUSH DE + PUSH HL + LD E,'0' + LD BC,-10000 + CALL PRTD3M1 + LD E,0 + LD BC,-1000 + CALL PRTD3M1 + CALL PC_PERIOD + LD BC,-100 + CALL PRTD3M1 + LD C,-10 + CALL PRTD3M1 + LD C,-1 + CALL PRTD3M1 + POP HL + POP DE + POP BC + RET +PRTD3M1: + LD A,'0' - 1 +PRTD3M2: + INC A + ADD HL,BC + JR C,PRTD3M2 + SBC HL,BC + CP E + JR Z,PRTD3M3 + LD E,0 + CALL COUT +PRTD3M3: + RET +; +HB_CPU_STR: .TEXT " Z80$" + .TEXT " Z80180$" + .TEXT " Z8S180-K$" + .TEXT " Z8S180-N$" + .TEXT " Z80280$" +; +;================================================================================================== +; CONSOLE CHARACTER I/O HELPER ROUTINES (REGISTERS PRESERVED) +;================================================================================================== +; +#IF (MINIO == MINIO_UART) + #INCLUDE "min_uart.asm" +#ENDIF +; +#IF (MINIO == MINIO_ASCI) + #INCLUDE "min_asci.asm" +#ENDIF +; +#IF (MINIO == MINIO_ACIA) + #INCLUDE "min_acia.asm" +#ENDIF +; +#IF (MINIO == MINIO_SIO) + #INCLUDE "min_sio.asm" +#ENDIF +; +#IF (MINIO == MINIO_Z2U) + #INCLUDE "min_z2u.asm" +#ENDIF +; +;================================================================================================== +; MISCELLANEOUS UTILITY FUNCTIONS +;================================================================================================== +; +; SET HL TO IY+A, A IS TRASHED +; +LDHLIYA: + PUSH IY ; COPY INSTANCE DATA PTR + POP HL ; ... TO HL + ;JP ADDHLA ; APPLY OFFSET TO HL AND RETURN + ADD A,L ; ADD OFFSET TO LSB + LD L,A ; ... PUT BACK IN L + RET NC ; DONE IF CF NOT SET + INC H ; IF CF SET, BUMP MSB + RET ; ... AND RETURN +; +;================================================================================================== +; HBIOS GLOBAL DATA +;================================================================================================== +; +HB_CPUTYPE .DB 0 ; 0=Z80, 1=80180, 2=SL1960, 3=ASCI BRG +; +CB_CPUMHZ .DB CPUMHZ +CB_CPUKHZ .DW CPUKHZ +; +IOPRVAL .DW 0 ; TEMP STORAGE FOR IOPR +; +HB_BATCOND .DB 0 ; BATTERY CONDITION (0=LOW, 1=OK) +; +STR_BANNER .DB "RomWBW HDIAG v", BIOSVER, ", ", TIMESTAMP, "$" +STR_PLATFORM .DB PLATFORM_NAME, "$" +STR_SWITCH .DB "*** Activating CRT Console ***$" +STR_BADINT .DB "\r\n*** BAD INT ***\r\n$" +STR_LOWBAT .DB "\r\n\r\n+++ LOW BATTERY +++$" +; +STR_PANIC .TEXT "\r\n>>> PANIC: $" +STR_SYSCHK .TEXT "\r\n>>> SYSCHK: $" +STR_CONTINUE .TEXT "\r\nContinue (Y/N)? $" +STR_SYSHALT .TEXT "\r\n\r\n*** SYSTEM HALTED ***$" +; +#IF (DSKYENABLE) ; 'H','B','I','O',' ',' ',' ',' ' + #IF (DSKYMODE == DSKYMODE_V1) +MSG_HBVER .DB $3E,$7F,$0A,$7B,$00,$00,$00,$00 ; "HBIO " + #ENDIF + #IF (DSKYMODE == DSKYMODE_NG) +MSG_HBVER .DB $76,$7F,$30,$3F,$00,$00,$00,$00 ; "HBIO " + #ENDIF +#ENDIF +; +HB_APPBNK .DB 0 ; START BANK WHEN RUN IN APP MODE +; +HB_BCDTMP .FILL 5,0 ; BCD NUMBER STORAGE (TEMP) +; +HB_END .EQU $ +; +SLACK .EQU HBX_LOC - $ + .ECHO "HDIAG space remaining: " + .ECHO SLACK + .ECHO " bytes.\n" +; +#IFDEF ROMBOOT + .FILL SLACK +#ENDIF +; + .END diff --git a/Source/HDIAG/sio.asm b/Source/HDIAG/sio.asm new file mode 100644 index 00000000..b38a4abe --- /dev/null +++ b/Source/HDIAG/sio.asm @@ -0,0 +1,108 @@ +; +;======================================================================= +; HDIAG SIO Driver +;======================================================================= +; +; Assumes the UART port conventions for RC2014. Command/status port +; at $80 and read/write data port at $81. +; Assuming a UART clock frequency of 1.8432 MHz, the baud rate +; will be 38400. +; +sio_cmd .equ $80 ; SIO command/status port +sio_dat .equ $81 ; SIO read/write port +; +sio_jptbl: + jp sio_cinit ; Initialize serial port + jp sio_cin ; Read byte + jp sio_cout ; Write byte + jp sio_cist ; Input status + jp sio_cost ; Output Status +; +; +; +sio_cinit: + ; Detect SIO here... + ; Zero the int vector register + ld a,2 ; select WR2 (int vector) + out (sio_cmd+2),a ; do it + xor a ; zero accum + out (sio_cmd+2),a ; write to WR2 + ; Read the int vector register and check for zero + ld a,2 ; select WR2 (int vector) + out (sio_cmd+2),a ; do it + in a,(sio_cmd+2) ; get int vector value + and $F0 ; only top nibble + ret nz ; abort if not zero + ; Set test value in int vector register + ld a,2 ; select WR2 (int vector) + out (sio_cmd+2),a ; do it + ld a,$FF ; test value + out (sio_cmd+2),a ; write to WR2 + ; Read the int vector register to confirm value written + ld a,2 ; select WR2 (int vector) + out (sio_cmd+2),a ; do it + in a,(sio_cmd+2) ; get int vector value + and $F0 ; only top nibble + cp $F0 ; compare + ret nz ; abort if miscompare +; + ; Program the SIO, just channel A + ld c,sio_cmd ; command port + ld hl,sio_initregs ; point to init values + ld b,sio_initlen ; count of bytes to write + otir ; write all values +; + xor a ; signal success + ret ; done +; +; +; +sio_cin: + call sio_cist ; check for char ready + jr z,sio_cin ; if not, loop + in a,(sio_dat) ; read byte + ret ; done +; +; +; +sio_cout: + push af ; save incoming +sio_cout1: + call sio_cost ; ready for char? + jr z,sio_cout1 ; loop if not + pop af ; restore incoming + out (sio_dat),a ; write byte + ret ; and done +; +; +; +sio_cist: + xor a ; select WR0 + out (sio_cmd),a ; do it + in a,(sio_cmd) ; get status + and $01 ; isolate rx ready + ret ; a != 0 if rx ready, else 0 +; +; +; +sio_cost: + xor a ; select WR0 + out (sio_cmd),a ; do it + in a,(sio_cmd) ; get status + and $04 ; isolate tx ready (empty) + ret ; a != 0 if tx ready, else 0 +; +; Table for chip register initialization. Simple setup for clock +; divided by 64. Assuming a system clock of 7.3728 MHz, this will +; result in a baud rate of 115200 which is standard for RC2014. +; +sio_initregs: + .db $00, $18 ; wr0: channel reset cmd + .db $04, $C4 ; wr4: clk baud parity stop bit + .db $01, $00 ; wr1: no interrupts + .db $02, $00 ; wr2: im2 vec offset + .db $03, $E1 ; wr3: 8 bit rcv, cts/dcd auto, rx enable + .db $05, $EA ; wr5: dtr, 8 bits send, tx enable, rts 1 11 0 1 0 1 0 (1=dtr,11=8bits,0=sendbreak,1=txenable,0=sdlc,1=rts,0=txcrc) +; +sio_initlen .equ $-sio_initregs + diff --git a/Source/HDIAG/uart.asm b/Source/HDIAG/uart.asm new file mode 100644 index 00000000..36a030c3 --- /dev/null +++ b/Source/HDIAG/uart.asm @@ -0,0 +1,106 @@ +; +;======================================================================= +; HDIAG UART Driver +;======================================================================= +; +; Assumes the UART conventions for SBC/MBC/Zeta, base port at $68. +; Assuming a UART clock frequency of 1.8432 MHz, the baud rate +; will be 38400. +; +uart_iob .equ $68 +uart_osc .equ 1843200 +uart_baudrate .equ 38400 +uart_divisor .equ uart_osc / uart_baudrate / 16 +; +uart_rbr .equ uart_iob + 0 ; dlab=0: rcvr buffer reg (read only) +uart_thr .equ uart_iob + 0 ; dlab=0: xmit holding reg (write only) +uart_ier .equ uart_iob + 1 ; dlab=0: int enable reg +uart_iir .equ uart_iob + 2 ; int ident register (read only) +uart_fcr .equ uart_iob + 2 ; fifo control reg (write only) +uart_lcr .equ uart_iob + 3 ; line control reg +uart_mcr .equ uart_iob + 4 ; modem control reg +uart_lsr .equ uart_iob + 5 ; line status reg +uart_msr .equ uart_iob + 6 ; modem status reg +uart_scr .equ uart_iob + 7 ; scratch register +uart_dll .equ uart_iob + 0 ; dlab=1: divisor latch (ls) +uart_dlm .equ uart_iob + 1 ; dlab=1: divisor latch (ms) +; +; +; +uart_jptbl: + jp uart_cinit ; Initialize serial port + jp uart_cin ; Read byte + jp uart_cout ; Write byte + jp uart_cist ; Input status + jp uart_cost ; Output Status +; +; +; +uart_cinit: + ; Test for existence + xor a ; zero accum + out (uart_ier),a ; ier := 0 + ld a,$80 ; dlab bit on + out (uart_lcr),a ; output to lcr (dlab regs now active) + ld a,$5A ; load test value + out (uart_dlm),a ; output to dlm + in a,(uart_dlm) ; read it back + cp $5A ; check for test value + ret nz ; nope, unknown uart or not present + xor a ; dlab bit off + out (uart_lcr),a ; output to lcr (dlab regs now inactive) + in a,(uart_ier) ; read ier + cp $5A ; check for test value + jr nz,uart_cinit1 ; if *not* $5A, good to go + or $FF ; signal error + ret ; done +; +uart_cinit1: + ld a,$80 ; lcr := dlab on + out (uart_lcr),a ; set lcr + ld a,uart_divisor & $ff ; low byte of divisor + out (uart_dll),a ; set divisor (lsb) + ld a,uart_divisor / $100 ; high byte of divisor + out (uart_dlm),a ; set divisor (msb) + xor a ; zero accum + out (uart_ier),a ; init ier (no ints) + ld a,$03 ; value for lcr and mcr + out (uart_lcr),a ; lcr := 3, dlab off, 8 data, 1 stop, no parity + out (uart_mcr),a ; mcr := 3, dtr on, rts on + ld a,$07 ; enable & reset fifo's + out (uart_fcr),a ; do it + xor a ; signal success + ret +; +; +; +uart_cin: + call uart_cist ; received char ready? + jr z,uart_cin ; loop if not + in a,(uart_rbr) ; read byte + ret ; and done +; +; +; +uart_cout: + push af ; save incoming +uart_cout1: + call uart_cost ; ready for char? + jr z,uart_cout1 ; loop if not + pop af ; restore incoming + out (uart_thr),a ; write byte + ret ; and done +; +; +; +uart_cist: + in a,(uart_lsr) ; get status + and $01 ; isolate bit 0 (receive data ready) + ret ; a != 0 if char ready, else 0 +; +; +; +uart_cost: + in a,(uart_lsr) ; get status + and $20 ; isolate bit 5 + ret ; a != 0 if char ready, else 0 diff --git a/Source/HDIAG/util.asm b/Source/HDIAG/util.asm new file mode 100644 index 00000000..b2a1cfb4 --- /dev/null +++ b/Source/HDIAG/util.asm @@ -0,0 +1,106 @@ +; +;======================================================================= +; HDIAG Utility Functions +;======================================================================= +; +; Print string at HL on console, null terminated. +; HL and AF are trashed. +; +prtstr: + ld a,(hl) ; get next character + or a ; set flags + inc hl ; bump pointer regardless + ret z ; done if null + call cout ; display character + jr prtstr ; loop till done +; +; Print the hex byte value in A +; +prthex8: + push af + push de + call hexascii + ld a,d + call cout + ld a,e + call cout + pop de + pop af + ret +; +; Print the hex word value in BC +; +prthex16: + push af + ld a,b + call prthex8 + ld a,c + call prthex8 + pop af + ret +; +; Print the hex dword value in DE:HL +; +prthex32: + push bc + push de + pop bc + call prthex16 + push hl + pop bc + call prthex16 + pop bc + ret +; +; Convert binary value in A to ASCII hex characters in DE +; +hexascii: + ld d,a + call hexconv + ld e,a + ld a,d + rlca + rlca + rlca + rlca + call hexconv + ld d,a + ret +; +; Convert low nibble of A to ASCII hex +; +hexconv: + and $0F ; low nibble only + add a,$90 + daa + adc a,$40 + daa + ret + +; +; Jump to address in HL/IX/IY +; +; No registers affected +; Typically used as "call jphl" to call a routine +; at address in HL register. +; +jphl: + jp (hl) +; +jpix: + jp (ix) +; +jpiy: + jp (iy) +; +; Add hl,a +; +; A register is destroyed! +; +addhla: + add a,l + ld l,a + ret nc + inc h + ret + diff --git a/Source/HDIAG/z180.inc b/Source/HDIAG/z180.inc new file mode 100644 index 00000000..3e0ff0f8 --- /dev/null +++ b/Source/HDIAG/z180.inc @@ -0,0 +1,71 @@ +; +;======================================================================= +; Z180 Internal I/O Ports +;======================================================================= +; +; These are offsets from the Z180 I/O base address. +; +z180_cntla0 .equ $00 ; asci0 control a +z180_cntla1 .equ $01 ; asci1 control a +z180_cntlb0 .equ $02 ; asci0 control b +z180_cntlb1 .equ $03 ; asci1 control b +z180_stat0 .equ $04 ; asci0 status +z180_stat1 .equ $05 ; asci1 status +z180_tdr0 .equ $06 ; asci0 transmit +z180_tdr1 .equ $07 ; asci1 transmit +z180_rdr0 .equ $08 ; asci0 receive +z180_rdr1 .equ $09 ; asci1 receive +z180_cntr .equ $0a ; csi/o control +z180_trdr .equ $0b ; csi/o transmit/receive +z180_tmdr0l .equ $0c ; timer 0 data lo +z180_tmdr0h .equ $0d ; timer 0 data hi +z180_rldr0l .equ $0e ; timer 0 reload lo +z180_rldr0h .equ $0f ; timer 0 reload hi +z180_tcr .equ $10 ; timer control +; +z180_asext0 .equ $12 ; asci0 extension control (z8s180) +z180_asext1 .equ $13 ; asci1 extension control (z8s180) +; +z180_tmdr1l .equ $14 ; timer 1 data lo +z180_tmdr1h .equ $15 ; timer 1 data hi +z180_rldr1l .equ $16 ; timer 1 reload lo +z180_rldr1h .equ $17 ; timer 1 reload hi +z180_frc .equ $18 ; free running counter +; +z180_astc0l .equ $1a ; asci0 time constant lo (z8s180) +z180_astc0h .equ $1b ; asci0 time constant hi (z8s180) +z180_astc1l .equ $1c ; asci1 time constant lo (z8s180) +z180_astc1h .equ $1d ; asci1 time constant hi (z8s180) +z180_cmr .equ $1e ; clock multiplier (latest z8s180) +z180_ccr .equ $1f ; cpu control (z8s180) +; +z180_sar0l .equ $20 ; dma0 source addr lo +z180_sar0h .equ $21 ; dma0 source addr hi +z180_sar0b .equ $22 ; dma0 source addr bank +z180_dar0l .equ $23 ; dma0 dest addr lo +z180_dar0h .equ $24 ; dma0 dest addr hi +z180_dar0b .equ $25 ; dma0 dest addr bank +z180_bcr0l .equ $26 ; dma0 byte count lo +z180_bcr0h .equ $27 ; dma0 byte count hi +z180_mar1l .equ $28 ; dma1 memory addr lo +z180_mar1h .equ $29 ; dma1 memory addr hi +z180_mar1b .equ $2a ; dma1 memory addr bank +z180_iar1l .equ $2b ; dma1 i/o addr lo +z180_iar1h .equ $2c ; dma1 i/o addr hi +z180_iar1b .equ $2d ; dma1 i/o addr bank (z8s180) +z180_bcr1l .equ $2e ; dma1 byte count lo +z180_bcr1h .equ $2f ; dma1 byte count hi +z180_dstat .equ $30 ; dma status +z180_dmode .equ $31 ; dma mode +z180_dcntl .equ $32 ; dma/wait control +z180_il .equ $33 ; interrupt vector load +z180_itc .equ $34 ; int/trap control +; +z180_rcr .equ $36 ; refresh control +; +z180_cbr .equ $38 ; mmu common base register +z180_bbr .equ $39 ; mmu bank base register +z180_cbar .equ $3a ; mmu common/bank area register +; +z180_omcr .equ $3e ; operation mode control +z180_icr .equ $3f ; i/o control register diff --git a/Source/HDIAG/z2u.asm b/Source/HDIAG/z2u.asm new file mode 100644 index 00000000..5e3dc109 --- /dev/null +++ b/Source/HDIAG/z2u.asm @@ -0,0 +1,49 @@ +; +;======================================================================= +; HDIAG Z180 UART Driver +;======================================================================= +; +z2u_jptbl: + jp z2u_cinit ; Initialize serial port + jp z2u_cin ; Read byte + jp z2u_cout ; Write byte + jp z2u_cist ; Input status + jp z2u_cost ; Output Status +; +; +; +z2u_cinit: + ; initialize port here + or $FF ; signal failure for now + ret +; +; +; +z2u_cin: + call z2u_cist ; check for char ready + jr z,z2u_cin ; if not, loop + ; read byte here + ret ; done +; +; +; +z2u_cout: + push af ; save incoming +z2u_cout1: + call z2u_cost ; ready for char? + jr z,z2u_cout1 ; loop if not + pop af ; restore incoming + ; write byte here + ret ; and done +; +; +; +z2u_cist: + ; check input status here + ret +; +; +; +z2u_cost: + ; check output status here + ret ; a != 0 if char ready, else 0 diff --git a/Source/Makefile b/Source/Makefile index cb096c4a..3887f8ae 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -1,7 +1,8 @@ # # order is actually important, because of build dependencies # -SUBDIRS = Prop +SUBDIRS = HDIAG +SUBDIRS += Prop SUBDIRS += Apps SUBDIRS += CBIOS SUBDIRS += Forth diff --git a/Source/ver.inc b/Source/ver.inc index 8874a42f..2311d3d0 100644 --- a/Source/ver.inc +++ b/Source/ver.inc @@ -2,4 +2,4 @@ #DEFINE RMN 1 #DEFINE RUP 1 #DEFINE RTP 0 -#DEFINE BIOSVER "3.1.1-pre.116" +#DEFINE BIOSVER "3.1.1-pre.117" diff --git a/Source/ver.lib b/Source/ver.lib index dca1306a..3fef82fa 100644 --- a/Source/ver.lib +++ b/Source/ver.lib @@ -3,5 +3,5 @@ rmn equ 1 rup equ 1 rtp equ 0 biosver macro - db "3.1.1-pre.116" + db "3.1.1-pre.117" endm diff --git a/Tools/Makefile.inc b/Tools/Makefile.inc index b5a8bf44..70820679 100644 --- a/Tools/Makefile.inc +++ b/Tools/Makefile.inc @@ -69,6 +69,9 @@ CPM=$(TOOLS)/cpm/bin rm -f $$($(CASEFN) $*.hex) ; \ fi +%.rom: %.asm + $(TASM) $(TASMFLAGS) $< $@ $*.lst + %.hex: %.asm $(ZXCC) $(CPM)/MAC -$< -$$PO