├── A-Hdrive.gz ├── MacProj.hqx ├── Makefile ├── README ├── bios.c ├── bye.mac ├── cpm.c ├── cpmdisc.h ├── defs.h ├── disassem.c ├── getunix.mac ├── main.c ├── makedisc.c ├── putunix.mac ├── z80.c └── z80.proj /A-Hdrive.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tjmerritt/z80/3aea43bf3390a5ae2ba1ef78ef54ee9f292ca059/A-Hdrive.gz -------------------------------------------------------------------------------- /MacProj.hqx: -------------------------------------------------------------------------------- 1 | (This file must be converted with BinHex 4.0) 2 | :#d&bBfKTGQ8ZFfPd!&0*9%46593K!*!%(5m!N!4(ie0*9#%!!`!!(5pb6'&e![m 3 | !N!-@rrm0$3aYGbmf1'ZP@MJ`,VN3h0J!$YIf!*!$J!#3"!%C!4)S9!#3&!@)!*! 4 | %rj!%68e38Ne03d-"!+`,@(1X3#P+!!!&[J!!#G3!!!(&!!!$2@G[-Ji!N!Dbp#0 5 | %$L*bIBqS#*@ma-Uf(k,5YUBP6944Zb&d6LJE@NY8Se,C[1Uf4bpiV5)p8,pSFGq 6 | GCbpZm2ejVC1Fe0NClZlX$!6JBcqpLhHr4ccV$5,hXd6&R`qfd$Jk(!b''A,B%@b 7 | 2GU"r+K,YRSlqKBj)i0[S$rP$3F%lhYVGdSVqV"a6&U"[36m#MTAYJ4$df2&bc"" 8 | p%(VJXl24)cqKRqX'1Ccq3+Ke*IUTR5fK0H"9`bIiKXJiG*NB"%e*TkC+-HhIa5B 9 | rRQUTh2&&jr")hrP`RX!6[R"b15LA+c"Y1BGi#!AC,EllEl6D'#UfTBQh8iUeF5Q 10 | 1e")@VrjM&YUm6r(j#lG5"RChm(5#"`bCT"T9G8#X#j!!9d41Ca61r*aRrZMENmR 11 | c"$-"fY%Y!Zp*l$Y5Y(Pa`rqI*EJ9K1C`@1c`Z[A[lX[rHXPiGR#)FalY,cT(3)P 12 | [iUB)&`L6GpPafj!!mkBh6IdP%"-p3ml-@Ui$kjh4H3+TKpPA"lRRQ&Hk[C@f'BT 13 | 0Y6$@`TCEQ-V#GPSBCf&l,)bhX'-@TV5`*JY6@pK&#p-)M,(pl4%B0ml#&"CQXL` 14 | e@AVj!M1%G@dMMjN-f9PP6AdI!*!$#`$VG8j#3q3BBB55#58VHh)VSC&M6eE#AX* 15 | @4KKK%RU%H5PK+h[#MXc`&*rdmH6@3@6e##A-b)!GH8D1N4%l-U#4!51--#1-8-) 16 | )mr!4pQ4##50()q`P6b2(b,%McmJcmS`-f*%T1c*Jj"KKj0N4'MN+9&d"4-Q[M$$ 17 | #b0VMQ4fH-%)Mk''%!4!mF)I9),bFcDBBBajmYc)@'X(h)ZlLq*EM'mA,6ZE&@qr 18 | p#IEPdh('I'(#a5jFkf"I$ci&)lb%JpNmhZ@EIeQFqTHMIcPPq*aL3GE$NV#F-Q) 19 | HIY0ik&LLYcfm@phHIMLb0hSddUF1rP$4C-hG*4hpNMi#0L4`0@XkQRrT#29,mN! 20 | LNLV4a5P`5cUU%ld$*dp[1'UH4QZq`@jLULVUm!qU@5dLrdPCS6&UM-R8'FbYaZ+ 21 | ZMjJ$aR[r1c*fjRRYBc)'plF`Yq&q(R23q2$J21D@r,lA1c%hj,ZZa#MGq9ME0"P 22 | J2-`q`jaKP(CrdCq+T+T*QUDNABr3![`8r#Mi80"Ie(ZEh5(+YcbN*6@cQ3IUhC8 23 | m9-([1FaeaYAj*f5FFDrq,ZC+[([Nj+6@Q&XL,DXqME'c4#rkj$XAlGbdLIP@F[& 24 | jeY52QH[(c(9MjVSaFpfBS61'c(H&hFBb&[3G(Z'1PjV#&hCl*4rV@,5TC5E96AZ 25 | qDq+b65fhY2l1E$kfCF'QqNbUQb$NBGDQqRNDTUU4KKj&5LSj$Ghl23e)Mdd0%(A 26 | rRS#Q*p9X"(YE+828$B)DY+MMBe*+FkM8'))D-UP"D%9Bel#mI`5e`Y)k*'IdP+1 27 | 9fNa3+`YDeH'-Y)lPh5HS9CC@*CI,1'RJ65USeFZqjY6-m"U@pkQJePKDCAem9(& 28 | mTIB@e&UL(QJ0R!$dCr+SX`@ecU3'Mi`T'AdGbcF$3DfR1l4A8KPbT&)26GZ0dQ" 29 | 53r*S'Q8TVi*Tbl+TMEbp*YfYdAMlUX+Q0R&IhlJlY,(39f06QlR@U,XajrhUM%e 30 | Y-Ahe`GH09XB@D90EcC6l09h5R3caA993fbbUVUDGDU!HQVHTPejFae+dMIifa2X 31 | dhAScK68%GlkkH(G+%f`2rY-`EcbK$0YrAI$'`qJ0UIS2!!d0$'eh,h"`Bk9D1$! 32 | ZZ4$Ff!!1erB!N!1!!*!%!4N"%RmZ!*!4&J!!#dB!N!6rN!4069"569"$3`%!V!Y 33 | BFk`pRA!!!!H(!!!+aJ!!!EN!!!19RXmjX3#3"Q@-)d31)LUjNDJBPEbflf$9jeF 34 | X)brkDV[hCRD[AbTkAAUJ2T1*hARfiJEIRpFkb8QGRH(ZcR!J!"rlDIJG($ae[NF 35 | mk`fLmVmN+YdTI2QAfrlk(,*l8ihG"kTfhlXXch["lN1Dl(j)Uph(*H`qTL52,m[ 36 | h,ADI0-rZKfqfqj'Rj[X$SSG!@#T#PiP"d*4dDUS8dpi,cI&iUU9baaHG`b0pjm0 37 | j!Nri`XRPS&bZ`,6P(1)K&'5hq1iAFdHSJBTYDH,YP'*YA)Tch3L(!hr-3T[h+5I 38 | $,Qe!rabj$[a4p4rIM4X-8p,0I`2!arpqc(JNkSRQU8CRAMd+X4KqiSR)kBc#QCr 39 | cc,r9-KbHB#C!Hh4TlK5SDM0Z0EMC2TD%8djS$SFlX(,KQ-&+QSM@lrmh%,*L9Z" 40 | *f'6k$[hDq3%"*Ek*Bc6mRF18FAJ1RZ3$BU,RbCPCbh9J[6-k6j!!Kdk04,ZR!hr 41 | XQ%&kHLPYVa5EDQ'XK5fh-*@&l4330ph#pPKBU)A41iUE+6$Q"NY2+6$f2JY6@pJ 42 | 2,8aMB6qfX$d#ilpQD3q`X*pE@*2P+9pJKV#ZEH3aNb&(UkbTl`-!!!X!kq@`XfQ 43 | %2@'%%NDHNT@`)dF**Fq1(#AXP"cY*%a#Mab9V8IBbYlV##2(b"SqU8PZ2BZX(PX 44 | *[FM69[+-2#-$CNHH4JDd)dabM$$###8-(k&(MK&+RK*QK*f4Tj%*)`0''"Q`N`c 45 | BN5'6$"JC-$+Q3!$A&9j#1b1822-Y$dmBSH3C33`M$)$JJ3UVVi4d1NN)XH"lN!! 46 | 3cf9mXjL&mEAKfi+EcF5+ZiZ0mq6Gjf1%f2d8ejBEEb3IK$i`r-Xid2mL158S`3K 47 | aNb%53q5d)rci6Tf0G$@d0iA$l8h*"#h#Ve2JGT!!cT`fm4022"IX#Cd'Zm'J[*m 48 | Kj-JRc'ECM5amLkZqfD5d5e,%6(p8%,ZhA405ZqVELNNE[YrQiILQ(LqYZ(ikpHq 49 | QEfF`UJcX@QDRa[#Y6f,NiE5,hilTXhhk[9E@#HVlHmrBT#c5&EV3bfUfiplaYfF 50 | GL0maK*Pp*HpehljJ6rZjDj+55)NlaZYd28*b1lkVNEeY2fCHGQ18h)AbV1d94em 51 | L,6F*IlB6E63pAR8LH5NF)LjebI%&f[2dEINVD"rQMk$GkYIC'p$eq4-IMd+AjJ0 52 | hfU$,mS&a&GUT[NK23NYNN!#ek%FHRPK#MXUbQ$)c`ECNKq@J,QRqSCPrD1BAQ[Q 53 | &IN)QDEerjTq+*U5pr![,Lq822jA)I3kk@VhhHKkkA*fZR)+Z`,fAd)9F@$pi2PA 54 | Uh,+YQ"2G$eKrDcRCVlFdlm@NEaQp&l43e$pG-03r0200Qj!!pei*8UI8YlBcfY$ 55 | a`!(cTD%Z4!jEM(5XG$2BrHBHb3IZAq68%SeUYMdI'"[P9*[ZGEHcD03c6V9V9,0 56 | "m$V&U3l@KJRc2D#qZ4hL9#HM2Li,4S91-4S6-c,)ke4dMP0GP(VbZ&0@BSPddm" 57 | '3Uc4"Y@Y8iHcdD4FT0+q'e524RA"+pUpL@9E`k"kGDq#-M`S&VeL0h*U+ChCr@j 58 | K-)@L#aYFqN,JE@!l'Lf2LIh&@'R,98leVH5D58Ma65lEJJDeA-qeAj!!P'3a9qa 59 | f6UdSH%h%THJ@PVi%1,95pbTQ-P+ajI4G`DP9P0TDlcb2iQfh(+m+6Uh@U+ic@9& 60 | 5YV$dlF+T0@alpCT[EhAQDT)hVeDMQRm+3)ecDKfMhM,I[HT#pMQReQZl`Bk0mRZ 61 | AiqeT8#eHC3cU%2fr%Zk@&Ih1!cM"elBBlNM+"YZ#2e2%'Sk)FIkI#AFXK0kKr[m 62 | $!!!0!!9D1$!ZZIm33)#D#J%3h0J!$YIf!*!$J!#3"!%C!4,EZ3#3%!@)!*!)rj! 63 | %8&*25NY"5%`"!+&T#HLX3#NX!!!ZC3#3"K&j!*!%8Fi!N!KcL!d!PIR*[-jZBC[ 64 | ZGE00&di"f-VGP+m0q*TmhC3IS3YVCEpqpRBCRPjq,lF"260mPk`eIkm$GR+hbc' 65 | jZDJ9@f3Aj5kH(Z%,EqA[0QDE,4+qF,*2`U1%2k(G0YD!m)8[E+'FFQplAFH2--, 66 | c**[`KCm,ApJq`U+F%LT3q+rRIVmBYq9BC"pCML"J)C00MT-K)`[!#R"!N`Ei'"- 67 | BBj@,'+[!V9RCl&hVqQ*(Rm3pU8K3LNEiZP!N)X@j*qT23)MPVUqa@AqLB4V@fYE 68 | 5Y0,PEBEq[H3"A!mFI-5V[eNQ6jrl3hNR&F3U$Am(JKF1*6%[Qm+D@+m[+F8r5)) 69 | 1LEYD@jYAi#aQ3LXE*GDF%qHFq0jN,-$ZZrcZrIFjrLSL8rjbKTeckY-%,PPqmM$ 70 | cV'I-PXZBTfeY@pHY,0cPq%KPQ$9K0"+B)D-HPDH-1R3@illX2ah5@$))9q1iDh! 71 | [%4JIPjRKVKY8MA"hTra12RNI@2ILlQ5kMC,UEb(6E(QB'DFGk@(U"R$fcA+fiHl 72 | FNX%Xm`[f5q%bS36B0pJVl"G#LF#"lCl&rQC@ipZ%E-N!BFc%lK"Za0h2(KI)Mj- 73 | p)Gb1N!#A`'ZR8%aXBC(`M2cZKq)$`MEK#0i2#VF6)M`0E&pf!T2,Ba!2*D-DqDF 74 | F!lYLkKhf+%20bBF8G1V0@*'`%4lTE"8+QC6BaeJL,H-(XQ'EcjGB2QGj@UX[dDr 75 | [m$D++hQYaZV23MP@[cqrrCCqAb3TqAPY438)XE-%,3MR',R@5$3TkIR6N@K%HNC 76 | MM4C`Dj6A4L-ET6J'6ideRUHiDj-fjeVMLEKrATZ8L+ELIJNUXC!!&-r@[Pc!5qi 77 | [h2,Z83"9jCH()[j`UPILMP8q[eIbp8Va4%A&m[)U@HHZjjmHF-V#RbLT1M&"YR9 78 | jVa3)455HM+FNVTbV#V+NJ#qF8&QfD9*FfU`+c5V"@*BfSb6(fi9i58PZ$@a[cQY 79 | XVakh!9MH'EEAq(1fGmi#YVGJ"qkRf0kjll+pmmTa0l1pAhjYZMKVrUlh@$),VMK 80 | 6FQVHDrV4R-'Ce[R"@A'QX0$!Y8l0"6lV9[Z[X!F(lja2C1CP-U-jRJE'rUQBXHS 81 | BB`9B"Pc3QZhN03FIBfbm&6Pd+ChlSYZDJcZJ&Ei%J(2&Le1+T2U"D%14hS'%&1i 82 | 04b0"`QHR$%`,ih`@E`CH(8Q&P3aDMLQY3ch62'%DqH!83R[*E2cSe122`ePf!b1 83 | 3!200U!E,FS$GXh9#2bAT-I5&B`#8ENeF@J@T$ZE$8@k6iP5GJh,NAiX'$@3"YN1 84 | jVe-pUq`Fq+8IBcGK%X-NT9d+c+,kS[V*a8p(hVpm"1J,'#1STG,4JU9MZQ1M-[[ 85 | `@EDF)bBQ2DB1**0!rH4[`+LK6"6N#P-G-c6db$96$ABTf%K)2MTSjY'-5!e35jX 86 | Uj-EZQClVD(Ba)NmM%`cSH&G[41j+&CVNR*ACje&KIXlA9%GChTm+1Ha+BEjQkf` 87 | pGX6lT3M+KK)MI#&e!D8rr+#A#B%Sm5pf#5TL5U82fTA+2#RFM4IQf`r(eGmGRl3 88 | akBXN-,Y-IL@@L&#RbGD"KVJ`+9b,SjP$Bah1E[LN@CRF8i'F2pPCqD#cp(eC!2C 89 | c,Hl'PRDUV*j30'(e8bJr12,V(fG[D*JS``95HiHR%@4p)YNELPS4UHDXMSBY8R8 90 | DepG48SR3CUNV58,R(H9-+h9id$%&!ab&3cfbdMP2fUc5ZPU[#qbm6IiqAe`aGFj 91 | 6EMDPfSlV-#d)HRrbPTMdXBjZaRXET3R[m9!NU+4dF0P1CrC'IeUNe%GYkbVU-AR 92 | q@(p[+1'A24edQSDc0fT5V542AEeF54MC%T!!XClhRMG65Di1Q0!PNMk+dRSqG@0 93 | @Tk0a&9@5,KRUTbMKjq$5PbZb0j[$LUB6XP,R4%)Si)Ye[fchY`!AUfNeYP00'4' 94 | U,j'3!%Mk8J5elrr[fMpIIe!k@eAD#e9&PASKhq&I,Gd*@(&BYFT9LbTM"NcV(A& 95 | I$&[Tl,VMGaha5cqEkBLVA)dL1HlhK5+SLX5P&DVLI%IdA`UJ)pEALY4Yp!&r*"R 96 | qV#-f0L"eH!m&)cjCk,b52ZZSVUf0P2452"k4FcqRBrLXahl5%6rZfQGl!AA%hr@ 97 | #$rh-8Ic-ra(XS1)%I3IXb%,RG2+9K1ErU'jYRCajh8BTNP3FRDZh!R4,@@ReQXC 98 | D+-eCR3VjEqk0qcCpl'TZ0[ID&K%T#ARqD#34$91HfC(l2hV@dkjrPMX2+Gqd4Qb 99 | N[D-Z&3N09&6mISBc23TBR3$SX`qD!$EMM6CqUBi*lV2*l)0ZS2Yd-V"GV$)hE6l 100 | 8+R1*lA$)G24'PFRIUa6NjC8(BK89I"Qr`RU&1TSEY$3#d#,18Zk2mFAJmL[+H'N 101 | TYi5iJhqel&SHUUJSJrDdH$)DMQk5iU3(jV8&HApH8%"N8'e!AI3HU+qr&Ua3J&X 102 | XJ9i`!Y'B&,%%3Q%TiZZA+VNjhP0K,L[MbjCaF8ec-aQ-5mP82%+bXJ9B+3rdaT* 103 | a8ZmPY#GmX`,,A#VGD4J4&&59FdmGMd9$k(-)LIYiE@[9+PjIklB@)0q@#(D4j,# 104 | 5ZcMk9K+j*lL0)b0I1-`hS6hL%3jAbZRaD,*2LQm+*54CR$j)mS@$dAJSfGI28`N 105 | *$N'"0h+D5%EM%Jp&!M$G%ddPC5ie1Nk"`d"j93&0`L%rhaJ0p4Eiia)q*U)1D%% 106 | lNhA,!C39I,dJMjU(,%YeFVhGGQ-P4fdKm*jENK*(c3&#`M`%RP)3!04D!,@qXEN 107 | 1JVdJ+G9$pB6#AXC,bHZ9brZPrZY4*KAmUKZTGV-9CP'%bmXXTHGNkMdYpIAYG4f 108 | bfR3&@LL#MmAFc5YRe@BUp)*FqrTC0@4"-@@MTpb`ID)f4"Aq5AZUQ@P2RhDR#qR 109 | r'AP@'Y5XXB)m91!(AC)drMH'5aPdb8fAB1Q5bTl2N!![lm6hA$r1pZ!VPMeGTpN 110 | HheYX6mrcE)pIKe[jQX8JEe,PShlISTa,L1rr'Er8l[jr[+E9de+,ZFb"Ze2Ze#h 111 | (j)PQCMD,pQcJB*QSRp0RS[*"4aQRU8RZUj[`95)e&m,*6b!HlFrUrmp%S-l-m)0 112 | K&2i8JbECpIrj8`FHHXa-Jc0(p[,C%@Dql6q$#1bSYG2CkCHaMF#,hd,CBGI`ArV 113 | NJ#E"crf6"Yere0INb0qRdMHVRrZRl-M$(r9cY26GVharlTqbSiRZFrr86dJE5ie 114 | XRm*-b&FiQ$"m+[GYjDh6U1mLp@eAhhhUHl[k2U#qRe2HH4lP2C[&qAIH@TSI,NC 115 | %FcTc$aLEr[B&FB6ei4kSG$5+RNja4#mf6'51P1l!kkR5E@!1LL-jMiSM"Kf`Gh% 116 | rLE[8(I31C$,H+00kehN(Q'"HQMNJMZ6H*2lBa(Jr#iZlKNq$XcGS!-Y,,$'eqSc 117 | aTKJ64l4(JVUQA8&0ZP&-m4VM3'"ZT@0pLeJRMZM'H(khVY6*+aL(IfrTS*LUG(K 118 | F(5j`(qA0jS%mV,c59U5d!AaEkEC+"qD9GV$[!9jFZJ0UEAA0`,IcCUi0jSXMQKp 119 | UUCIR"dk,%rTUF@hQ&GHC[%*c5ibRV6(Kk2cemmG'A40X35`hE9fc%iPUKVmMhL5 120 | Qj)q9@F1%rVHPMaP[j32'JEqIT+S*'X"jSh3r+kUU-3i'0*dla96R6ZqEQ62,UeJ 121 | 0CGaY['jRP@(iHl`NlE6T86h(JZ''LDP[P'lRKF(AcFkQZ`,@G&QkXG*4+fH9qbr 122 | "CY,1*XCHQ8jX4,F9#Gl+0dpjdb%d*(e!Qqj0Pi(cKMR+UQqmXkU4AG2mDNQQBfG 123 | 6MA"P8$1F%91aHF22GZlNU-hm9['p`&`E4`CY`C2TFZJ1@VmVTP!r`0KFUKXC,8B 124 | P,Y8A"KLcm`(03l(mSlXHINac)'"'lQqP[m*Ec9kcUG[S1XN-5@'EkHMKeFpQ6Zr 125 | DI[61J%C-Q9RD5MTF5#maYlDmNaRP,HlpE-&9)I5MS[3Ah0rhK[$KHF[`ZhB6%RK 126 | l5HG,KkT0CP0NHG$FjJSZ`&fkeS94l)G!X$-58hC,"YPV*PpXQmDHRmA'AMb3!*Q 127 | Lh$4$pM+@ha4LaJ$[F'mSE(-("Q,qi@Ia2N0k80Jp0XcQUYK"`[,GQFPJ6hmI0,6 128 | %Urf05I2NkX$cqEi9MX!4X(6'$Hb,Q5RliNkAHI2NdE'lKTTQ[IH0rEALAX@VXcJ 129 | `#rR,iYQhkZq8l1rAm*D6QE3[[S'm*FIZ'S2'8029VXa8pH2Leq!+&5+m9[FE%h[ 130 | Tjp@QS"e9XL3iYmd9@+Mi&8jfQe4NT(ZZLKcZ4Qm@6X$a%+U4("bMa2MQpkIid[H 131 | RQ[DMDeRX&QB*QTGBQ1NkGqfrXX)A6c,Y5pIC*eFih&pDF*)YXdm1ReVY#Vb&'RI 132 | +rFFC1#*l')'(NAJQb@3ILjkdX'@"KGI!MIHR`IcafarCcl55eQaKfPRPFHKqQlI 133 | '#SF'hlM6GZL0Ec,h),-GKTr@1,1EE#D0Fd[Qc6Y4'lakI[F#FaR6$Qfh(k)dl)I 134 | P**l*[09p$5p-Vq(1$aAc3q*l6"-d98-906$I'bYNT#UqChi9ZUIi8QENcS$'Ta2 135 | PcDE0NAlL`AUc`HEBrph[ecqb2DK$[krXj[Ne6#Y85B5DZaF!eDLSU9Z,ef@e%jR 136 | $jZeL+[f%Q$Tp"K@qQ@N-Sba(r$T$ed12Gp5fH1T@X1%dlfT&hqF'-@AC2$&NEVj 137 | lr&Hh[AcSaA%ChhaiNMR0e5B6X+eMZf91318BKNBQ0XL-$T941$Bbd5%ch#T$UlX 138 | 0)4C5KmNm-0h[82'CalUeH"fMVS2+kV+EUNd2Gkjl0M24j!j1LDIiT-UjCjBcSA, 139 | F%H-Z9lrZU00eLQPXKF6&L&V&Y&8ZTM9A-809&fDl0aeX#5X9[1kRIQTKjB+hlTQ 140 | IMAZmEVGlp0$4VFf[-SHj"-ir8Vd+8akl&r`G&rQhFZ%2#T9ri1I21'JDh&$FG0Z 141 | 'I-qJjcB`19iT$bCA9L3c8Z!DCDB1V*39ZpK-jT&"[mk-%9e-2Aa(6rlJ)Dr6cYa 142 | 1Ve0-2A*(cb+VM"(,fl#FH4ZqGFLQpcEBp@+++Z,%pK0h3ZA-i+(41q`jKdHY1Gk 143 | '&dDp$@0h5)DKV6eDmYcZl(lp,aK0K1J9ZK9kp)N5QR*+RF$R$(q[Y)62XH5d0Ec 144 | 6d0D`90pGG&CPHeZ$$[mXXQ9UcFiU0[b3!+d%depZi*I8CrkaEQp$S*MRT*e`m3$ 145 | r%kLY"c*NDHFVdf8a!I@L[ImbEJ$2EI&1Dec$9r+FEY0CPqDf"ZlNU)BY8e8'6(R 146 | 0,iqQVF-2V[k(c#YlRLTYPVfXE+V$e(NjqL$Uc1iB2P8lm9iK+ZPKB1m#HacB2Q$ 147 | r"ZbE`1i"pZr!pXh1c)AF`SU#4Vb+J`[&#CD%6J`kTk'6"0i,[&[&im!lN!"'&,A 148 | HKdf@!Iem)bC6apR*Y"++!8S$EcHjahXT*B+hR4,!Zj`Fi@hQA@,+*YaI[m3Eblr 149 | r-TZ3!'k`6BSriFrLp4jr6Z'DqjJKA@)6H'1k38aP&b8d&fG1"lAFkGie`rVp1II 150 | 2B+cPH*UhJ9+X+@,c[Djf,l!KfRIJIGp+,&h`2V#Z'IY2I2m!Q,ic28b6"DER&fM 151 | h!8G'fR,JA86E$Ec0lGHY)YaD+pBhB)TCUZahKBfd8F!FXpAMAY1!pd-HGcYYY*r 152 | cZ0H4hV(fCKNr8Eq1[U3@hTlHI,BFapFBp'mpHRahF4`IE"+@FaSBmL)XYaFBXL+ 153 | XT"JB[J!KE$'fXXFVQ8E'YQ&$H`mQA-*f!0[0Y$+f'pJ1*Q3b#pRLHi&KVdNmA41 154 | dXHFPV2bh`,"VPE%*B2MQ4XDQJ"@cI$N$D"q[DGT(Zd'G#+b`pKhmj`r6G3$,[rS 155 | irEH3!1j@B)B[P,%bB2Z!83*IKAB5Q%2*U8,$@PikTH48S8-HK8T1&8CJ(P9M,V! 156 | "9@-"X%j9S`KB-aZ8mqL'*bb,C@`VH1Kf-YB'hN+9&`22QGYrXkm[I1l2FFlqN8l 157 | f6hKQrLj(F2`rl4S!!!: 158 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # optional CFLAGS include: -O -g -Wall 2 | # -DNO_LARGE_SWITCH compiler cannot handle really big switch statements 3 | # so break them into smaller pieces 4 | # -DLITTLE_ENDIAN machine's byte-sex is like x86 instead of 68k 5 | # -DPOSIX_TTY use Posix termios instead of older termio (FreeBSD) 6 | # -DMEM_BREAK support memory-mapped I/O and breakpoints, 7 | # which will noticably slow down emulation 8 | 9 | CC = gcc 10 | CFLAGS = -O2 -pipe -Wall -DPOSIX_TTY -DLITTLE_ENDIAN -DMEM_BREAK 11 | LDFLAGS = 12 | 13 | FILES = README Makefile MacProj.hqx z80.proj A-Hdrive.gz \ 14 | cpmdisc.h defs.h \ 15 | cpm.c bios.c disassem.c main.c z80.c \ 16 | bye.mac getunix.mac putunix.mac \ 17 | makedisc.c 18 | 19 | OBJS = bios.o \ 20 | disassem.o \ 21 | main.o \ 22 | z80.o 23 | 24 | z80: $(OBJS) 25 | $(CC) $(CFLAGS) $(LDFLAGS) -o z80 $(OBJS) 26 | 27 | cpm: 28 | rm -f cpm 29 | ln -s z80 cpm 30 | 31 | bios.o: bios.c defs.h cpmdisc.h cpm.c 32 | z80.o: z80.c defs.h 33 | disassem.o: disassem.c defs.h 34 | main.o: main.c defs.h 35 | 36 | clean: 37 | rm -f z80 cpm *.o 38 | 39 | tags: $(FILES) 40 | cxxtags *.[hc] 41 | 42 | tar: 43 | tar -zcf z80.tgz $(FILES) p2dos zcpr1 zmac 44 | 45 | files: 46 | @echo $(FILES) 47 | 48 | difflist: 49 | @for f in $(FILES); do rcsdiff -q $$f >/dev/null || echo $$f; done 50 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This is a Z80 instruction-set simulator written entirely ANSI C. It can 2 | boot and run CP/M or CP/M clones. It's also got a builtin debugger 3 | which supports tracing, single-stepping, breakpoints, read or write 4 | protected memory, memory-mapped I/O, logging, and disassembly. This is 5 | not the fastest emulator around, but it's very portable. 6 | 7 | So far z80 has been tested under Linux, FreeBSD, DEC's UNIX on Alpha, 8 | and SunOS, the Macintosh using either Think C or CodeWarrior (PPC and 9 | 68k), MS-DOS using DJGPP, and the BeOS. It should be quite easy to port 10 | to other UNIX-line systems. 11 | 12 | The file "Makefile" will need tweaking for your system. The two key 13 | compilation flags are -DLITTLE_ENDIAN and -DPOSIX_TTY as described 14 | further in the Makefile. You'll almost certainly have to tweak the 15 | other make variables, such as CFLAGS and CC. Then just type "make". 16 | 17 | For the Macintosh, the file "MacProj.hqx" is a BinHex SIT archive with 18 | three project files for Think C, CodeWarrior 68k, and CW PowerPC. 19 | 20 | The file "main.c" contains UNIX routines for character-mode I/O, if 21 | these need to be ported to your flavor of UNIX. They're pretty generic 22 | and ought to work under just about anything. 23 | 24 | Once z80 is built, run it, and enter 'b' at the prompt to boot CP/M. 25 | Enter '?' to see a list of debugging commands it understands. The 26 | interrupt character, ^C, is wanted by CP/M for its own uses, so to force 27 | the z80 into its debugger, use ^_ (control-underscore). (You may have 28 | to type after the ^_ to wake it up.) 29 | 30 | If z80 is linked or renamed to "cpm", it will directly boot into CP/M 31 | without displaying the debugger prompt. If an "A-Hdrive" doesn't exist 32 | in the current working directory for CP/M, it will be created. 33 | 34 | The file "z80.c" contains the emulator proper. Most variables are 35 | accessed via macros defined in "defs.h". The file "bios.c" contains the 36 | mock-BIOS code that allows the emulator to boot and run CP/M or its 37 | clones. The file "cpm.c" contains an image of P2D0S 2.3 and ZCPR1, so 38 | it should be safe to distribute freely. (This allows the z80 to 39 | directly boot CP/M.) 40 | 41 | The z80 program will automatically create virtual CP/M "drives" as they 42 | are accessed, and will only allocate disk space for them when it is 43 | needed. The obsolete "makedisc.c" program is included to allocate all 44 | the space for a floppy at once and also allows placing a single Unix 45 | file within it. 46 | 47 | The "bios.c" code is built for two 5Mb virtual hard-drives (A-Hdrive, 48 | and B-Hdrive), and a bunch of floppy drives (C-drive, D-drive, and so 49 | on). It is possible to rebuild it for different numbers of hard-drives 50 | by changing the macro NUMHDISCS at the top. The hard disks emulated are 51 | the venerable ST-506 5Mb 5" 5Mb drives. The floppies are the 52 | traditional 8" 256k drives. The code names the virtual hard-drives as 53 | "?-Hdrive" and floppies as "?-drive" to help avoid accidentlally 54 | confusing one for the other. Their contents should be identical to the 55 | real thing, even down to the reserved tracks, assuming I did it right. 56 | 57 | There are several "*.mac" files which are Z80 macro-assembly sources for 58 | getting files from UNIX into CP/M (GETUNIX.MAC), putting files out from 59 | CP/M to UNIX (PUTUNIX.MAC), and quitting the emulator (BYE.MAC). All 60 | these files are also in "A-Hdrive", all assembled and ready to run. 61 | They do little useful error checking, but it should be pretty obvious 62 | from the code how they work. Any text files transfered into CP/M must 63 | have CR-LF as the line separator or it gets awfully confused. 64 | 65 | Usage: 66 | PUTUNIX 67 | GETUNIX 68 | BYE 69 | 70 | Additional utilities that come with the P2DOS23 distribution are also 71 | included to support the date/time functions of P2DOS. These are located 72 | within the "A-Hdrive" and within the P2DOS archive. These are date.com, 73 | ddir.com, initdir.com, public.com, set.com, and touch.com. 74 | 75 | I had picked up a Z80 assembler named "zmac" from the Internet quite 76 | some time ago. I've hacked it heavily to add a lot of support for 77 | different assembler formats but it's still kind of finicky. You'll need 78 | yacc of some flavor to compile it up. Sorry, but I don't have a 79 | Makefile for it any longer. The "*.z" files there are sample assembly 80 | sources. There's also a separate Z80 disassembler that came with zmac. 81 | Unfortunately the sources did not come with any copyright, but the file 82 | "zmac.y" does contain a somewhat cryptic list of folks who hacked it. I 83 | don't know if "zdis" is by the same authors or not - there are no 84 | comments in it. 85 | 86 | zmac assembled P2DOS 2.3 (off of the CP/M archives on oak.oakland.edu) 87 | without too much trouble. ZCPR1 (from the archives) needed to be 88 | converted from the .ASM format to .MAC, which I did using XLATE5 (also 89 | from the Oak archives). Then the resulting output had to be hacked 90 | somewhat so that zmac could assemble it. Z80DOS23 and Z80CCP from the 91 | archives also assembled up without much trouble. 92 | 93 | To play with different BDOS/CCP replacements, just rename the assembler 94 | output HEX file from wherever you built it into the files "bdos.hex" and 95 | "ccp.hex". If z80 sees these in the current directory, it will load 96 | them to boot CP/M instead of using its builtin versions of P2DOS/ZCPR1. 97 | 98 | There's a lot of stuff to do in this code, but it's functional enough to 99 | leave the rest as an exercise for the student. The Mac version needs a 100 | really cool interface, with separate windows for the out, setting 101 | registers, tracing, a virtual terminal, etc. The debug-level prompting 102 | code pretty much sucks and needs to be thrown out. 103 | 104 | This code has been designed so that the z80 emulator proper should be 105 | thread-safe and runs independently of CP/M. It should be possible to 106 | run multiple z80s within one program if desired. 107 | 108 | The CP/M layer may be built so that the fake BIOS is turned into real 109 | Z80 code with all I/O occurring through fake devices using either 110 | INPUT/OUTPUT or the memory-mapped I/O hooks. Conversely, it's also 111 | possible to turn then entire BDOS/CCP into C code much as the BIOS is 112 | currently coded with magic hooks that trigger the appropriate actions. 113 | 114 | Use this code as you wish, so long as it is properly attributed. That 115 | is, display our copyrights where you would display yours (manuals, 116 | boot-up, etc) and do not claim that this code is yours. If you do use 117 | it, please drop me a note. This code is "as-is" without any warrantee. 118 | Be warned that P2DOS23 and ZCPR1 only allow free redistribution for 119 | non-commercial use. (See their documentation for more details.) 120 | 121 | Copyright 1986-1988 by Parag Patel. All Rights Reserved. 122 | Copyright 1994-1995 by CodeGen, Inc. All Rights Reserved. 123 | 124 | 125 | -- Parag Patel 126 | 127 | 128 | Version history: 129 | 130 | 3.1 Added support for virtual 5Mb ST-506 drives in bios.c. 131 | Fixed a few bugs in emulator, fake BIOS, and console I/O. 132 | String search for "cpm" in argv[0] now uses strrchr() in main.c. 133 | Change all "(char)" casts to "(signed char)" for AIX and other 134 | systems that have "char" default to "unsigned". 135 | Making a start at adding support for printing. 136 | 137 | 3.0 First public release 1995. 138 | Use publicly available P2DOS23 and ZCPR1 instead of 139 | copyrighted CP/M 2.2. 140 | Added date/time support for P2DOS and its utilities. 141 | -------------------------------------------------------------------------------- /bios.c: -------------------------------------------------------------------------------- 1 | /*-----------------------------------------------------------------------*\ 2 | | bios.c -- CP/M emulator "front-end" for the Z80 emulator -- runs | 3 | | standard CP/M executables with no changes as long as they use CP/M | 4 | | system calls to do all their work. | 5 | | | 6 | | Originally by Kevin Kayes, but he refused any responsibility for it, | 7 | | then I later hacked it up, enhanced it, and debugged it. | 8 | | | 9 | | Copyright 1986-1988 by Parag Patel. All Rights Reserved. | 10 | | Copyright 1994-1995,2000 by CodeGen, Inc. All Rights Reserved. | 11 | \*-----------------------------------------------------------------------*/ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "cpmdisc.h" 20 | #include "defs.h" 21 | 22 | #ifdef macintosh 23 | #include 24 | #else 25 | #include 26 | #endif 27 | 28 | /* definition of: extern unsigned char cpm_array[]; */ 29 | #include "cpm.c" 30 | 31 | /* The BDOS/CCP had better be built with these values! */ 32 | #define CCP 0xD400 33 | #define BDOS 0xDC00 34 | #define CBIOS 0xEA00 35 | 36 | #define NENTRY 30 /* number of BIOS entries */ 37 | #define STACK 0xEF00 /* grows down from here */ 38 | 39 | /* The first NUMHDISCS drives may be specified as hard-drives. */ 40 | #define NUMHDISCS 2 41 | #define NUMDISCS (MAXDISCS - NUMHDISCS) 42 | 43 | #if NUMHDISCS > MAXDISCS 44 | # error Too many hard-discs specified here. 45 | #endif 46 | 47 | /* disk parameter block information */ 48 | #define DPBSIZE 15 49 | #define HDPBLOCK (CBIOS + NENTRY * 8) 50 | #define DPBLOCK (HDPBLOCK + DPBSIZE) 51 | #define DIRBUF (DPBLOCK + DPBSIZE) 52 | #define DPHSIZE 16 53 | 54 | /* hard disc parameter info */ 55 | #define HDPBASE (DIRBUF + SECTORSIZE) 56 | 57 | #define DPBASE (HDPBASE + DPHSIZE * NUMHDISCS) 58 | #define CVSIZE 0 59 | #define ALVSIZE 33 60 | #define CVBASE (DPBASE + DPHSIZE * NUMDISCS) 61 | #define ALVBASE (CVBASE + CVSIZE * NUMDISCS) 62 | 63 | /* ST-506 allocation vector size */ 64 | #define HALVBASE (ALVBASE + ALVSIZE * NUMDISCS) 65 | #define HALVSIZE 306 66 | 67 | /* buffer for where to return time/date info */ 68 | #define TIMEBUF (HALVBASE + HALVSIZE * NUMHDISCS) 69 | #define TIMEBUFSIZE 5 70 | 71 | /* just a marker for future expansion */ 72 | #define END_OF_BIOS (TIMEBUF + TIMEBUFSIZE) 73 | 74 | 75 | /* ST-506 HD sector info (floppy defs are in cpmdisc.h for makedisc.c) */ 76 | #define HDSECTORSPERTRACK 64 77 | #define HDTRACKSPERDISC 610 78 | 79 | /* offsets into FCB needed for reading/writing Unix files */ 80 | #define FDOFFSET 12 81 | #define BLKOFFSET 16 82 | #define SZOFFSET 20 83 | 84 | /* this batch of macros are not used at the moment */ 85 | #define CBUFF CCP+7 86 | #define CIBUFF CCP+8 87 | #define DEFAULTFCB 0x005C 88 | #define DEFAULTBUF 0x0080 89 | #define IOBYTE 0x0003 90 | #define DISK 0x0004 91 | #define DMA 0x0008 92 | #define USER 0x000A 93 | #define USERSTART 0x0100 94 | 95 | 96 | /* forward declarations: */ 97 | static void seldisc(z80info *z80); 98 | 99 | 100 | static void 101 | closeall(z80info *z80) 102 | { 103 | int i; 104 | 105 | for (i = 0; i < MAXDISCS; i++) 106 | { 107 | if (z80->drives[i] != NULL) 108 | { 109 | fclose(z80->drives[i]); 110 | z80->drives[i] = NULL; 111 | } 112 | } 113 | } 114 | 115 | static void 116 | warmboot(z80info *z80) 117 | { 118 | int i; 119 | 120 | closeall(z80); 121 | 122 | /* load CCP and BDOS into memory (max 0x1600 in size) */ 123 | for (i = 0; i < 0x1600 && i < sizeof cpm_array; i++) 124 | SETMEM(CCP + i, cpm_array[i]); 125 | 126 | /* try to load CCP/BDOS from disk, but ignore any errors */ 127 | loadfile(z80, "bdos.hex"); 128 | loadfile(z80, "ccp.hex"); 129 | 130 | /* CP/M system reset via "JP 00" - entry into BIOS warm-boot */ 131 | SETMEM(0x0000, 0xC3); /* JP CBIOS+3 */ 132 | SETMEM(0x0001, ((CBIOS + 3) & 0xFF)); 133 | SETMEM(0x0002, ((CBIOS + 3) >> 8)); 134 | 135 | /* 0x0003 is the IOBYTE, 0x0004 is the current DISK */ 136 | SETMEM(0x0003, 0x00); 137 | SETMEM(0x0004, z80->drive); 138 | 139 | /* CP/M syscall via "CALL 05" - entry into BDOS */ 140 | SETMEM(0x0005, 0xC3); /* JP BDOS+6 */ 141 | SETMEM(0x0006, ((BDOS+6) & 0xFF)); 142 | SETMEM(0x0007, ((BDOS+6) >> 8)); 143 | 144 | /* fake BIOS entry points */ 145 | for (i = 0; i < NENTRY; i++) 146 | { 147 | /* JP */ 148 | SETMEM(CBIOS + 3 * i, 0xC3); 149 | SETMEM(CBIOS + 3 * i + 1, (CBIOS + NENTRY * 3 + i * 5) & 0xFF); 150 | SETMEM(CBIOS + 3 * i + 2, (CBIOS + NENTRY * 3 + i * 5) >> 8); 151 | 152 | /* LD A, - start of bios-entry */ 153 | SETMEM(CBIOS + NENTRY * 3 + i * 5, 0x3E); 154 | SETMEM(CBIOS + NENTRY * 3 + i * 5 + 1, i); 155 | 156 | /* OUT A,0FFH - we use port 0xFF to fake the BIOS call */ 157 | SETMEM(CBIOS + NENTRY * 3 + i * 5 + 2, 0xD3); 158 | SETMEM(CBIOS + NENTRY * 3 + i * 5 + 3, 0xFF); 159 | 160 | /* RET - end of bios-entry */ 161 | SETMEM(CBIOS + NENTRY * 3 + i * 5 + 4, 0xC9); 162 | } 163 | 164 | /* disc parameter block - a 5Mb ST-506 hard disc */ 165 | SETMEM(HDPBLOCK, HDSECTORSPERTRACK & 0xFF);/* SPT - sectors per track */ 166 | SETMEM(HDPBLOCK + 1, HDSECTORSPERTRACK >> 8); 167 | SETMEM(HDPBLOCK + 2, 4); /* BSH - data block shift factor */ 168 | SETMEM(HDPBLOCK + 3, 15); /* BLM - data block mask */ 169 | SETMEM(HDPBLOCK + 4, 0); /* EXM - extent mask */ 170 | SETMEM(HDPBLOCK + 5, 2441 & 0xFF); /* DSM - total drive capacity */ 171 | SETMEM(HDPBLOCK + 6, 2441 >> 8); 172 | SETMEM(HDPBLOCK + 7, 1023 & 0xFF); /* DRM - total dir entries */ 173 | SETMEM(HDPBLOCK + 8, 1023 >> 8); 174 | SETMEM(HDPBLOCK + 9, 0xFF); /* AL0 - blocks for directory entries */ 175 | SETMEM(HDPBLOCK + 10, 0xFF); /* AL1 */ 176 | SETMEM(HDPBLOCK + 11, 0x00); /* CKS - directory check vector */ 177 | SETMEM(HDPBLOCK + 12, 0x00); 178 | SETMEM(HDPBLOCK + 13, RESERVEDTRACKS & 0xFF);/* OFF - reserved tracks */ 179 | SETMEM(HDPBLOCK + 14, RESERVEDTRACKS >> 8); 180 | 181 | /* disk parameter headers for hard disc */ 182 | for (i = 0; i < NUMHDISCS; i++) 183 | { 184 | SETMEM(HDPBASE + DPHSIZE * i, 0x00); /* XLT */ 185 | SETMEM(HDPBASE + DPHSIZE * i + 1, 0x00); 186 | SETMEM(HDPBASE + DPHSIZE * i + 2, 0x00); /* scratch 1 */ 187 | SETMEM(HDPBASE + DPHSIZE * i + 3, 0x00); 188 | SETMEM(HDPBASE + DPHSIZE * i + 4, 0x00); /* scratch 2 */ 189 | SETMEM(HDPBASE + DPHSIZE * i + 5, 0x00); 190 | SETMEM(HDPBASE + DPHSIZE * i + 6, 0x00); /* scratch 3 */ 191 | SETMEM(HDPBASE + DPHSIZE * i + 7, 0x00); 192 | SETMEM(HDPBASE + DPHSIZE * i + 8, DIRBUF & 0xFF); /* DIRBUF */ 193 | SETMEM(HDPBASE + DPHSIZE * i + 9, DIRBUF >> 8); 194 | SETMEM(HDPBASE + DPHSIZE * i + 10, HDPBLOCK & 0xFF); /* DPB */ 195 | SETMEM(HDPBASE + DPHSIZE * i + 11, HDPBLOCK >> 8); 196 | SETMEM(HDPBASE + DPHSIZE * i + 12, 0x00); 197 | SETMEM(HDPBASE + DPHSIZE * i + 13, 0x00); 198 | SETMEM(HDPBASE + DPHSIZE * i + 14, 199 | (HALVBASE + HALVSIZE * i) & 0xFF); 200 | SETMEM(HDPBASE + DPHSIZE * i + 15, 201 | (HALVBASE + HALVSIZE * i) >> 8); 202 | } 203 | 204 | /* disc parameter block - a single-sided single-density 8" 256k disc */ 205 | SETMEM(DPBLOCK, SECTORSPERTRACK & 0xFF); /* SPT - sectors per track */ 206 | SETMEM(DPBLOCK + 1, SECTORSPERTRACK >> 8); 207 | SETMEM(DPBLOCK + 2, 3); /* BSH - data block shift factor */ 208 | SETMEM(DPBLOCK + 3, 7); /* BLM - data block mask */ 209 | SETMEM(DPBLOCK + 4, 0); /* EXM - extent mask */ 210 | SETMEM(DPBLOCK + 5, 242); /* DSM - total capacity of drive */ 211 | SETMEM(DPBLOCK + 6, 0); 212 | SETMEM(DPBLOCK + 7, 63); /* DRM - total directory entries */ 213 | SETMEM(DPBLOCK + 8, 0); 214 | SETMEM(DPBLOCK + 9, 0xC0); /* AL0 - blocks for directory entries */ 215 | SETMEM(DPBLOCK + 10, 0x00); /* AL1 */ 216 | SETMEM(DPBLOCK + 11, 0x00); /* CKS - directory check vector */ 217 | SETMEM(DPBLOCK + 12, 0x00); 218 | SETMEM(DPBLOCK + 13, RESERVEDTRACKS & 0xFF); /* OFF - reserved tracks */ 219 | SETMEM(DPBLOCK + 14, RESERVEDTRACKS >> 8); 220 | 221 | /* disc parameter headers */ 222 | for (i = 0; i < NUMDISCS; i++) 223 | { 224 | SETMEM(DPBASE + DPHSIZE * i, 0x00); /* XLT */ 225 | SETMEM(DPBASE + DPHSIZE * i + 1, 0x00); 226 | SETMEM(DPBASE + DPHSIZE * i + 2, 0x00); /* scratch 1 */ 227 | SETMEM(DPBASE + DPHSIZE * i + 3, 0x00); 228 | SETMEM(DPBASE + DPHSIZE * i + 4, 0x00); /* scratch 2 */ 229 | SETMEM(DPBASE + DPHSIZE * i + 5, 0x00); 230 | SETMEM(DPBASE + DPHSIZE * i + 6, 0x00); /* scratch 3 */ 231 | SETMEM(DPBASE + DPHSIZE * i + 7, 0x00); 232 | SETMEM(DPBASE + DPHSIZE * i + 8, DIRBUF & 0xFF); /* DIRBUF */ 233 | SETMEM(DPBASE + DPHSIZE * i + 9, DIRBUF >> 8); 234 | SETMEM(DPBASE + DPHSIZE * i + 10, DPBLOCK & 0xFF); /* DPB */ 235 | SETMEM(DPBASE + DPHSIZE * i + 11, DPBLOCK >> 8); 236 | #if (CVSIZE == 0) 237 | SETMEM(DPBASE + DPHSIZE * i + 12, 0x00); 238 | SETMEM(DPBASE + DPHSIZE * i + 13, 0x00); 239 | #else 240 | SETMEM(DPBASE + DPHSIZE * i + 12, 241 | (CVBASE + CVSIZE * i) & 0xFF); 242 | SETMEM(DPBASE + DPHSIZE * i + 13, 243 | (CVBASE + CVSIZE * i) >> 8); 244 | #endif 245 | SETMEM(DPBASE + DPHSIZE * i + 14, 246 | (ALVBASE + ALVSIZE * i) & 0xFF); 247 | SETMEM(DPBASE + DPHSIZE * i + 15, 248 | (ALVBASE + ALVSIZE * i) >> 8); 249 | } 250 | 251 | /* set up the stack for an 8-level RET to do a system reset */ 252 | SP = STACK; 253 | 254 | for (i = 0; i < 8; i++) 255 | { 256 | /* push reboot entry (CBIOS + 3) onto stack */ 257 | --SP; 258 | SETMEM(SP, (CBIOS + 3) >> 8); 259 | --SP; 260 | SETMEM(SP, (CBIOS + 3) & 0xFF); 261 | } 262 | 263 | /* set up the default disk (A:) and dma address */ 264 | z80->dma = 0x0080; 265 | 266 | /* and all our default drive info */ 267 | z80->track = 0; 268 | z80->sector = 1; 269 | 270 | /* make sure the current file/disk is open */ 271 | B = 0; 272 | C = z80->drive; 273 | seldisc(z80); 274 | 275 | PC = CCP; 276 | } 277 | 278 | static void 279 | boot(z80info *z80) 280 | { 281 | z80->drive = 0; 282 | warmboot(z80); 283 | } 284 | 285 | void 286 | sysreset(z80info *z80) 287 | { 288 | boot(z80); 289 | } 290 | 291 | static void 292 | consstat(z80info *z80) 293 | { 294 | input(z80, 0x01, 0x01, &A); 295 | } 296 | 297 | static void 298 | consin(z80info *z80) 299 | { 300 | input(z80, 0x00, 0x00, &A); 301 | 302 | if (A == CNTL('S')) 303 | input(z80, 0x00, 0x00, &A); 304 | } 305 | 306 | static void 307 | consout(z80info *z80) 308 | { 309 | output(z80, 0x00, 0x00, C & 0x7F); 310 | } 311 | 312 | /* list character in C */ 313 | static void 314 | list(z80info *z80) 315 | { 316 | static FILE *fp = NULL; 317 | 318 | if (fp == NULL) 319 | { 320 | fp = fopen("list", "w"); 321 | 322 | if (fp == NULL) 323 | return; 324 | } 325 | 326 | /* close up on EOF */ 327 | if (C == CNTL('D') || C == '\0') 328 | { 329 | fclose(fp); 330 | fp = NULL; 331 | return; 332 | } 333 | 334 | putc(C, fp); 335 | } 336 | 337 | /* punch character in C */ 338 | static void 339 | punch(z80info *z80) 340 | { 341 | } 342 | 343 | /* return reader char in A, ^Z is EOF */ 344 | static void 345 | reader(z80info *z80) 346 | { 347 | A = CNTL('Z'); 348 | } 349 | 350 | static void 351 | home(z80info *z80) 352 | { 353 | z80->track = 0; 354 | z80->sector = 1; 355 | } 356 | 357 | static void 358 | seldisc(z80info *z80) 359 | { 360 | char hdrivebuf[] = "A-Hdrive"; 361 | char drivebuf[] = "A-drive"; 362 | char *drivestr = C < NUMHDISCS ? hdrivebuf : drivebuf; 363 | 364 | *drivestr += C; /* set the 1st letter to the drive name */ 365 | H = 0; 366 | L = 0; 367 | 368 | if (C >= MAXDISCS) 369 | { 370 | fprintf(stderr, "seldisc(): Attempt to open bogus drive %d\r\n", 371 | C); 372 | return; 373 | } 374 | 375 | if (z80->drives[C] == NULL) 376 | { 377 | struct stat statbuf; 378 | long secs; 379 | FILE *fp; 380 | 381 | fp = fopen(drivestr, "rb+"); 382 | 383 | if (fp == NULL) 384 | fp = fopen(drivestr, "wb+"); 385 | 386 | if (fp == NULL) 387 | { 388 | fprintf(stderr, "seldisc(): Cannot open file '%s'!\r\n", 389 | drivestr); 390 | return; 391 | } 392 | 393 | if (stat(drivestr, &statbuf) < 0) 394 | { 395 | fprintf(stderr, "seldisc(): Cannot stat file '%s'!\r\n", 396 | drivestr); 397 | fclose(fp); 398 | return; 399 | } 400 | 401 | secs = statbuf.st_size / SECTORSIZE; 402 | 403 | if (secs == 0) 404 | { 405 | char buf[SECTORSIZE]; 406 | memset(buf, 0xE5, SECTORSIZE); 407 | 408 | if (fwrite(buf, 1, SECTORSIZE, fp) != SECTORSIZE) 409 | { 410 | fprintf(stderr, "seldisc(): Cannot create file '%s'!\r\n", 411 | drivestr); 412 | 413 | fclose(fp); 414 | return; 415 | } 416 | 417 | secs = 1; 418 | } 419 | 420 | z80->drives[C] = fp; 421 | z80->drivelen[C] = secs * SECTORSIZE; 422 | } 423 | 424 | z80->drive = C; 425 | 426 | if (z80->drive < NUMHDISCS) 427 | { 428 | L = (HDPBASE + DPHSIZE * C) & 0xFF; 429 | H = (HDPBASE + DPHSIZE * C) >> 8; 430 | } 431 | else 432 | { 433 | L = (DPBASE + DPHSIZE * C) & 0xFF; 434 | H = (DPBASE + DPHSIZE * C) >> 8; 435 | } 436 | 437 | home(z80); 438 | } 439 | 440 | static void 441 | settrack(z80info *z80) 442 | { 443 | int tracks = (z80->drive < NUMHDISCS) ? 444 | HDTRACKSPERDISC : TRACKSPERDISC; 445 | 446 | z80->track = (B << 8) + C; 447 | 448 | if (z80->track < RESERVEDTRACKS || z80->track >= tracks) 449 | fprintf(stderr, "settrack(): bogus track %d!\r\n", 450 | z80->track); 451 | } 452 | 453 | static void 454 | setsector(z80info *z80) 455 | { 456 | int sectors = (z80->drive < NUMHDISCS) ? 457 | HDSECTORSPERTRACK : SECTORSPERTRACK; 458 | 459 | z80->sector = (B << 8) + C; 460 | 461 | if (z80->sector < SECTOROFFSET || z80->sector > sectors) 462 | fprintf(stderr, "setsector(): bogus sector %d!\r\n", 463 | z80->sector); 464 | } 465 | 466 | static void 467 | setdma(z80info *z80) 468 | { 469 | z80->dma = (B << 8) + C; 470 | } 471 | 472 | 473 | static void 474 | rdsector(z80info *z80) 475 | { 476 | int n; 477 | int drive = z80->drive; 478 | int sectors = (drive < NUMHDISCS) ? HDSECTORSPERTRACK : SECTORSPERTRACK; 479 | long offset = SECTORSIZE * ((long)z80->sector - SECTOROFFSET + 480 | sectors * ((long)z80->track - TRACKOFFSET)); 481 | FILE *fp = z80->drives[drive]; 482 | long len = z80->drivelen[drive]; 483 | 484 | if (fp == NULL) 485 | { 486 | fprintf(stderr, "rdsector(): file/drive %d not open!\r\n", 487 | drive); 488 | A = 1; 489 | return; 490 | } 491 | 492 | if (len && offset >= len) 493 | { 494 | memset(&(z80->mem[z80->dma]), 0xE5, SECTORSIZE); 495 | A = 0; 496 | return; 497 | } 498 | 499 | if (fseek(fp, offset, SEEK_SET) != 0) 500 | { 501 | fprintf(stderr, "rdsector(): fseek failure offset=0x%lX!\r\n", 502 | offset); 503 | A = 1; 504 | return; 505 | } 506 | 507 | n = fread(&(z80->mem[z80->dma]), 1, SECTORSIZE, fp); 508 | 509 | if (n != SECTORSIZE) 510 | { 511 | fprintf(stderr, "rdsector(): read failure %d!\r\n", n); 512 | A = 1; 513 | } 514 | else 515 | A = 0; 516 | } 517 | 518 | 519 | static void 520 | wrsector(z80info *z80) 521 | { 522 | int drive = z80->drive; 523 | int sectors = (drive < NUMHDISCS) ? HDSECTORSPERTRACK : SECTORSPERTRACK; 524 | long offset = SECTORSIZE * ((long)z80->sector - SECTOROFFSET + 525 | sectors * ((long)z80->track - TRACKOFFSET)); 526 | FILE *fp = z80->drives[drive]; 527 | long len = z80->drivelen[drive]; 528 | 529 | if (fp == NULL) 530 | { 531 | fprintf(stderr, "wrsector(): file/drive %d not open!\r\n", 532 | drive); 533 | A = 1; 534 | return; 535 | } 536 | 537 | if (len && offset > len) 538 | { 539 | char buf[SECTORSIZE]; 540 | 541 | if (fseek(fp, len, SEEK_SET) != 0) 542 | { 543 | fprintf(stderr, "wrsector(): fseek failure offset=0x%lX!\r\n", 544 | len); 545 | A = 1; 546 | return; 547 | } 548 | 549 | memset(buf, 0xE5, SECTORSIZE); 550 | 551 | while (offset > len) 552 | { 553 | if (fwrite(buf, 1, SECTORSIZE, fp) != SECTORSIZE) 554 | { 555 | fprintf(stderr, "wrsector(): write failure!\r\n"); 556 | A = 1; 557 | return; 558 | } 559 | 560 | len += SECTORSIZE; 561 | z80->drivelen[drive] = len; 562 | } 563 | } 564 | 565 | if (fseek(fp, offset, SEEK_SET) != 0) 566 | { 567 | fprintf(stderr, "wrsector(): fseek failure offset=0x%lX!\r\n", 568 | offset); 569 | A = 1; 570 | return; 571 | } 572 | 573 | if (fwrite(&(z80->mem[z80->dma]), 1, SECTORSIZE, fp) != SECTORSIZE) 574 | { 575 | fprintf(stderr, "wrsector(): write failure!\r\n"); 576 | A = 1; 577 | } 578 | else 579 | { 580 | A = 0; 581 | 582 | if (offset + SECTORSIZE > len) 583 | z80->drivelen[drive] = offset + SECTORSIZE; 584 | } 585 | } 586 | 587 | static void 588 | secttran(z80info *z80) 589 | { 590 | if (z80->drive < NUMHDISCS) 591 | { 592 | /* simple sector translation for hard disc */ 593 | HL = BC + 1; 594 | 595 | if (BC >= HDSECTORSPERTRACK) 596 | fprintf(stderr, "secttran(): bogus sector %d!\r\n", BC); 597 | } 598 | else 599 | { 600 | /* we do not need to use DE to find our translation table */ 601 | HL = sectorxlat[BC]; 602 | 603 | if (BC >= SECTORSPERTRACK) 604 | fprintf(stderr, "secttran(): bogus sector %d!\r\n", BC); 605 | } 606 | } 607 | 608 | static void 609 | liststat(z80info *z80) 610 | { 611 | A = 0xFF; 612 | } 613 | 614 | /* These two routines read and write ints at arbitrary aligned addrs. 615 | * The values are stored in the z80 in little-endian order regardless 616 | * of the byte-order on the host. 617 | */ 618 | static int 619 | addr2int(char *addr) 620 | { 621 | unsigned char *a = (unsigned char*)addr; 622 | unsigned int t; 623 | 624 | t = a[0] | (a[1] << 8) | (a[2] << 16) | (a[3] << 24); 625 | return (int)t; 626 | } 627 | 628 | static void 629 | int2addr(char *addr, int val) 630 | { 631 | unsigned char *a = (unsigned char*)addr; 632 | unsigned int t = (unsigned int)val; 633 | 634 | a[0] = t & 0xFF; 635 | a[1] = (t >> 8) & 0xFF; 636 | a[2] = (t >> 16) & 0xFF; 637 | a[3] = (t >> 24) & 0xFF; 638 | } 639 | 640 | /* DE points to a CP/M FCB. 641 | On return, A contains 0 if all went well, 0xFF otherwise. 642 | The algorithm uses the FCB to store info about the UNIX file. 643 | */ 644 | static void 645 | openunix(z80info *z80) 646 | { 647 | char filename[20], *fp; 648 | byte *cp; 649 | int i; 650 | FILE *fd; 651 | 652 | cp = &(z80->mem[DE + 1]); 653 | fp = filename; 654 | 655 | for (i = 0; (*cp != ' ') && (i < 8); i++) 656 | *fp++ = tolower(*cp++); 657 | 658 | cp = &(z80->mem[DE + 9]); 659 | 660 | if (*cp != ' ') 661 | { 662 | *fp++ = '.'; 663 | 664 | for (i = 0; (*cp != ' ') && (i < 3); i++) 665 | *fp++ = tolower(*cp++); 666 | } 667 | 668 | *fp = 0; 669 | A = 0xFF; 670 | 671 | /* if file is not readable, try opening it read-only */ 672 | if ((fd = fopen(filename, "rb+")) == NULL) 673 | if ((fd = fopen(filename, "rb")) == NULL) 674 | return; 675 | 676 | A = 0; 677 | 678 | int2addr(&z80->mem[DE + FDOFFSET], (int)fd); 679 | int2addr(&z80->mem[DE + BLKOFFSET], 0); 680 | int2addr(&z80->mem[DE + SZOFFSET], 0); 681 | } 682 | 683 | 684 | /* DE points to a CP/M FCB. 685 | On return, A contains 0 if all went well, 0xFF otherwise. 686 | The algorithm uses the FCB to store info about the UNIX file. 687 | */ 688 | static void 689 | createunix(z80info *z80) 690 | { 691 | char filename[20], *fp; 692 | byte *cp; 693 | int i; 694 | FILE *fd; 695 | 696 | cp = &(z80->mem[DE + 1]); 697 | fp = filename; 698 | 699 | for (i = 0; (*cp != ' ') && (i < 8); i++) 700 | *fp++ = tolower(*cp++); 701 | 702 | cp = &(z80->mem[DE + 9]); 703 | 704 | if (*cp != ' ') 705 | { 706 | *fp++ = '.'; 707 | 708 | for (i = 0; (*cp != ' ') && (i < 3); i++) 709 | *fp++ = tolower(*cp++); 710 | } 711 | 712 | *fp = 0; 713 | A = 0xFF; 714 | 715 | if ((fd = fopen(filename, "wb+")) == NULL) 716 | return; 717 | 718 | A = 0; 719 | 720 | int2addr(&z80->mem[DE + FDOFFSET], (int)fd); 721 | int2addr(&z80->mem[DE + BLKOFFSET], 0); 722 | int2addr(&z80->mem[DE + SZOFFSET], 0); 723 | } 724 | 725 | 726 | /* DE points to a CP/M FCB. 727 | On return, A contains 0 if all went well, 0xFF otherwise. 728 | The algorithm uses the FCB to store info about the UNIX file. 729 | */ 730 | static void 731 | rdunix(z80info *z80) 732 | { 733 | byte *cp; 734 | int i, blk, size; 735 | FILE *fd; 736 | 737 | cp = &(z80->mem[z80->dma]); 738 | fd = (FILE *)addr2int(&z80->mem[DE + FDOFFSET]); 739 | blk = addr2int(&z80->mem[DE + BLKOFFSET]); 740 | size = addr2int(&z80->mem[DE + SZOFFSET]); 741 | 742 | A = 0xFF; 743 | 744 | if (fseek(fd, (long)blk << 7, SEEK_SET) != 0) 745 | return; 746 | 747 | i = fread(cp, 1, SECTORSIZE, fd); 748 | size = i; 749 | 750 | if (i == 0) 751 | return; 752 | 753 | for (; i < SECTORSIZE; i++) 754 | cp[i] = CNTL('Z'); 755 | 756 | A = 0; 757 | blk += 1; 758 | 759 | int2addr(&z80->mem[DE + FDOFFSET], (int)fd); 760 | int2addr(&z80->mem[DE + BLKOFFSET], blk); 761 | int2addr(&z80->mem[DE + SZOFFSET], size); 762 | } 763 | 764 | 765 | /* DE points to a CP/M FCB. 766 | On return, A contains 0 if all went well, 0xFF otherwise. 767 | The algorithm uses the FCB to store info about the UNIX file. 768 | */ 769 | static void 770 | wrunix(z80info *z80) 771 | { 772 | byte *cp; 773 | int i, blk, size; 774 | FILE *fd; 775 | 776 | cp = &(z80->mem[z80->dma]); 777 | fd = (FILE *)addr2int(&z80->mem[DE + FDOFFSET]); 778 | blk = addr2int(&z80->mem[DE + BLKOFFSET]); 779 | size = addr2int(&z80->mem[DE + SZOFFSET]); 780 | 781 | A = 0xFF; 782 | 783 | if (fseek(fd, (long)blk << 7, SEEK_SET) != 0) 784 | return; 785 | 786 | i = fwrite(cp, 1, size = SECTORSIZE, fd); 787 | 788 | if (i != SECTORSIZE) 789 | return; 790 | 791 | A = 0; 792 | blk += 1; 793 | 794 | int2addr(&z80->mem[DE + FDOFFSET], (int)fd); 795 | int2addr(&z80->mem[DE + BLKOFFSET], blk); 796 | int2addr(&z80->mem[DE + SZOFFSET], size); 797 | } 798 | 799 | 800 | /* DE points to a CP/M FCB. 801 | On return, A contains 0 if all went well, 0xFF otherwise. 802 | */ 803 | static void 804 | closeunix(z80info *z80) 805 | { 806 | FILE *fd; 807 | 808 | fd = (FILE *)addr2int(&z80->mem[DE + FDOFFSET]); 809 | A = 0xFF; 810 | 811 | if (fclose(fd) != 0) 812 | return; 813 | 814 | A = 0; 815 | } 816 | 817 | /* clean up and quit - never returns */ 818 | static void 819 | finish(z80info *z80) 820 | { 821 | resetterm(); 822 | exit(0); 823 | } 824 | 825 | /* Get/set the time - although only the get-time part is implemented. 826 | If C==0, then get the time, else of C==0xFF, then set the time. 827 | HL returns a pointer to our time table: 828 | HL+0:DATE LSB SINCE 1,1,1978 829 | HL+1:DATE MSB 830 | HL+2:HOURS (BCD) 831 | HL+3:MINUTES (BCD) 832 | HL+4:SECONDS (BCD) 833 | */ 834 | static void 835 | dotime(z80info *z80) 836 | { 837 | time_t now; 838 | struct tm *t; 839 | word days; 840 | int y; 841 | 842 | if (C != 0) /* do not support setting the time yet */ 843 | return; 844 | 845 | time(&now); 846 | t = localtime(&now); 847 | 848 | /* days since Jan 1, 1978 + one since tm_yday starts at zero */ 849 | days = (t->tm_year - 78) * 365 + t->tm_yday + 1; 850 | 851 | /* add in the number of days for the leap years - dumb but accurate */ 852 | for (y = 78; y < t->tm_year; y++) 853 | if (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) 854 | days++; 855 | 856 | HL = TIMEBUF; 857 | SETMEM(HL + 0, days & 0xFF); 858 | SETMEM(HL + 1, days >> 8); 859 | SETMEM(HL + 2, ((t->tm_hour / 10) << 4) + (t->tm_hour % 10)); 860 | SETMEM(HL + 3, ((t->tm_min / 10) << 4) + (t->tm_min % 10)); 861 | SETMEM(HL + 4, ((t->tm_sec / 10) << 4) + (t->tm_sec % 10)); 862 | } 863 | 864 | void 865 | bios(z80info *z80, int fn) 866 | { 867 | static void (*bioscall[])(z80info *z80) = 868 | { 869 | boot, /* 0 */ 870 | warmboot, /* 1 */ 871 | consstat, /* 2 */ 872 | consin, /* 3 */ 873 | consout, /* 4 */ 874 | list, /* 5 */ 875 | punch, /* 6 */ 876 | reader, /* 7 */ 877 | home, /* 8 */ 878 | seldisc, /* 9 */ 879 | settrack, /* 10 */ 880 | setsector, /* 11 */ 881 | setdma, /* 12 */ 882 | rdsector, /* 13 */ 883 | wrsector, /* 14 */ 884 | liststat, /* 15 */ 885 | secttran, /* 16 */ 886 | openunix, /* 17 */ 887 | createunix, /* 18 */ 888 | rdunix, /* 19 */ 889 | wrunix, /* 20 */ 890 | closeunix, /* 21 */ 891 | finish, /* 22 */ 892 | dotime /* 23 */ 893 | }; 894 | 895 | if (fn < 0 || fn >= sizeof bioscall / sizeof *bioscall) 896 | { 897 | fprintf(stderr, "Illegal BIOS call %d\r\n", fn); 898 | return; 899 | } 900 | 901 | bioscall[fn](z80); 902 | /* let z80 handle return */ 903 | } 904 | -------------------------------------------------------------------------------- /bye.mac: -------------------------------------------------------------------------------- 1 | ; EXIT CP/M - return to Unix 2 | ; 3 | .Z80 4 | CBIOS EQU 0EA00H 5 | FINISH EQU CBIOS+42H 6 | 7 | CSEG 8 | ENTRY START 9 | START: 10 | CALL FINISH 11 | END 12 | -------------------------------------------------------------------------------- /cpm.c: -------------------------------------------------------------------------------- 1 | /* This is an image of P2DOS 2.3 + ZCPR1 and should be OK to redistribute. */ 2 | 3 | unsigned char cpm_array[] = { 4 | 0xC3, 0x5, 0xD5, 0xC3, 0x1, 0xD5, 0x50, 0x4, 0x44, 0x41, 5 | 0x54, 0x45, 0x0, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 6 | 0x20, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 7 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 8 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 9 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 10 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 11 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 12 | 0x0, 0x0, 0xC, 0xD4, 0xC, 0xD4, 0x0, 0x0, 0x0, 0x0, 0x0, 13 | 0x0, 0xB6, 0xD5, 0xEA, 0xD8, 0xE2, 0xD5, 0x14, 0x0, 0xB6, 0xD5, 14 | 0xB6, 0xD5, 0x59, 0xD6, 0x20, 0x0, 0xC6, 0xD6, 0x63, 0xD5, 0x43, 15 | 0x4F, 0x4D, 0x1, 0x24, 0x24, 0x24, 0x20, 0x20, 0x20, 0x20, 0x20, 16 | 0x53, 0x55, 0x42, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 17 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 18 | 0x0, 0x0, 0x0, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 19 | 0x20, 0x20, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x20, 0x20, 20 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0, 0x0, 0x0, 21 | 0x0, 0x0, 0x16, 0x0, 0x0, 0x44, 0x49, 0x52, 0x20, 0x82, 0xD8, 22 | 0x4C, 0x49, 0x53, 0x54, 0x5B, 0xD9, 0x54, 0x59, 0x50, 0x45, 0x5F, 23 | 0xD9, 0x55, 0x53, 0x45, 0x52, 0xBE, 0xDA, 0x44, 0x46, 0x55, 0x20, 24 | 0xC8, 0xDA, 0x47, 0x4F, 0x20, 0x20, 0xD5, 0xDA, 0x45, 0x52, 0x41, 25 | 0x20, 0x33, 0xD9, 0x53, 0x41, 0x56, 0x45, 0xF8, 0xD9, 0x52, 0x45, 26 | 0x4E, 0x20, 0x7A, 0xDA, 0x47, 0x45, 0x54, 0x20, 0x7F, 0xDB, 0x4A, 27 | 0x55, 0x4D, 0x50, 0xD0, 0xDA, 0xAF, 0x32, 0x7, 0xD4, 0x31, 0x77, 28 | 0xD4, 0xC5, 0x79, 0x1F, 0x1F, 0x1F, 0x1F, 0xE6, 0xF, 0x5F, 0xCD, 29 | 0x45, 0xD6, 0xCD, 0x8, 0xD6, 0x32, 0x2A, 0xD5, 0xC1, 0x79, 0xE6, 30 | 0xF, 0x32, 0x59, 0xD6, 0x28, 0x3, 0xCD, 0xD, 0xD6, 0x11, 0x7A, 31 | 0xD4, 0x3E, 0x0, 0xB7, 0x2F, 0xC4, 0x27, 0xD6, 0x2F, 0x32, 0x2A, 32 | 0xD5, 0x3A, 0x7, 0xD4, 0xB7, 0x20, 0x29, 0x31, 0x77, 0xD4, 0xCD, 33 | 0xA7, 0xD5, 0xCD, 0xFD, 0xD5, 0xC6, 0x41, 0xCD, 0xAE, 0xD5, 0xCD, 34 | 0x43, 0xD6, 0xB7, 0x28, 0x12, 0xFE, 0xA, 0x38, 0x9, 0xD6, 0xA, 35 | 0xF5, 0x3E, 0x31, 0xCD, 0xAE, 0xD5, 0xF1, 0xC6, 0x30, 0xCD, 0xAE, 36 | 0xD5, 0xCD, 0x67, 0xD6, 0xCD, 0x1, 0xD6, 0xCD, 0xFD, 0xD5, 0x32, 37 | 0x59, 0xD6, 0xCD, 0xE1, 0xD7, 0xC4, 0xF0, 0xD6, 0x11, 0x88, 0xD5, 38 | 0xD5, 0x3A, 0xD8, 0xD7, 0xB7, 0xC2, 0xDA, 0xDA, 0xCD, 0x60, 0xD8, 39 | 0xC2, 0xDA, 0xDA, 0x7E, 0x23, 0x66, 0x6F, 0xE9, 0xCD, 0xCD, 0xD7, 40 | 0xCD, 0xE1, 0xD7, 0x3A, 0x9C, 0xD4, 0xD6, 0x20, 0x21, 0xD8, 0xD7, 41 | 0xB6, 0xC2, 0xF0, 0xD6, 0x18, 0x9E, 0xCD, 0xE5, 0xD5, 0x4E, 0x6F, 42 | 0x20, 0x46, 0x69, 0x6C, 0xE5, 0xC9, 0x3E, 0xD, 0xCD, 0xAE, 0xD5, 43 | 0x3E, 0xA, 0xC5, 0xE, 0x2, 0x5F, 0xE5, 0xCD, 0x5, 0x0, 0xE1, 44 | 0xC1, 0xC9, 0xE, 0x1, 0xCD, 0xDE, 0xD5, 0xC3, 0x5E, 0xD6, 0xF5, 45 | 0x3E, 0x0, 0xB7, 0x28, 0x6, 0xF1, 0xC5, 0xE, 0x5, 0x18, 0xE4, 46 | 0xF1, 0xF5, 0xCD, 0xAE, 0xD5, 0xF1, 0xFE, 0xA, 0xCA, 0xDF, 0xD9, 47 | 0xC9, 0x11, 0x9B, 0xD4, 0xE, 0x14, 0xC5, 0xCD, 0x5, 0x0, 0xC1, 48 | 0xB7, 0xC9, 0xF5, 0xCD, 0xA7, 0xD5, 0xF1, 0xE3, 0xF5, 0xCD, 0xF2, 49 | 0xD5, 0xF1, 0xE3, 0xC9, 0x7E, 0xCD, 0xAE, 0xD5, 0x7E, 0x23, 0xB7, 50 | 0xC8, 0xF8, 0x18, 0xF5, 0xE, 0x19, 0x18, 0x9, 0x11, 0x80, 0x0, 51 | 0xE, 0x1A, 0x18, 0x2, 0xE, 0xD, 0xC3, 0x5, 0x0, 0x5F, 0xE, 52 | 0xE, 0x18, 0xF8, 0xAF, 0x32, 0xBB, 0xD4, 0x11, 0x9B, 0xD4, 0xE, 53 | 0xF, 0xCD, 0x5, 0x0, 0x3C, 0xC9, 0xE, 0x10, 0x18, 0xF7, 0x11, 54 | 0x9B, 0xD4, 0xE, 0x11, 0x18, 0xF0, 0xE, 0x12, 0x18, 0xEC, 0x21, 55 | 0x2A, 0xD5, 0x7E, 0xB7, 0xC8, 0x36, 0x0, 0x11, 0x7A, 0xD4, 0xE, 56 | 0x13, 0x18, 0xCC, 0x3E, 0x0, 0x5F, 0x18, 0x2, 0x1E, 0xFF, 0xE, 57 | 0x20, 0x18, 0xC1, 0xCD, 0x43, 0xD6, 0x87, 0x87, 0x87, 0x87, 0x21, 58 | 0x59, 0xD6, 0xB6, 0x32, 0x4, 0x0, 0xC9, 0x3E, 0x0, 0x32, 0x4, 59 | 0x0, 0xC9, 0xFE, 0x61, 0xD8, 0xFE, 0x7B, 0xD0, 0xE6, 0x5F, 0xC9, 60 | 0x3A, 0x2A, 0xD5, 0xB7, 0x28, 0x46, 0x11, 0x7A, 0xD4, 0xD5, 0xCD, 61 | 0x19, 0xD6, 0xD1, 0x28, 0x3C, 0x3A, 0x89, 0xD4, 0x3D, 0x32, 0x9A, 62 | 0xD4, 0xCD, 0xDC, 0xD5, 0x20, 0x30, 0x11, 0x7, 0xD4, 0x21, 0x80, 63 | 0x0, 0x1, 0x50, 0x0, 0xED, 0xB0, 0x21, 0x88, 0xD4, 0x36, 0x0, 64 | 0x23, 0x35, 0x11, 0x7A, 0xD4, 0xCD, 0x20, 0xD6, 0x28, 0x16, 0x3E, 65 | 0x24, 0xCD, 0xAE, 0xD5, 0x21, 0x8, 0xD4, 0xCD, 0xF2, 0xD5, 0xCD, 66 | 0xDF, 0xD6, 0x28, 0x1C, 0xCD, 0x2F, 0xD6, 0xC3, 0x3A, 0xD5, 0xCD, 67 | 0x2F, 0xD6, 0xCD, 0x49, 0xD6, 0x3E, 0x3E, 0xCD, 0xAE, 0xD5, 0xE, 68 | 0xA, 0x11, 0x6, 0xD4, 0xCD, 0x5, 0x0, 0xCD, 0x58, 0xD6, 0x21, 69 | 0x7, 0xD4, 0x46, 0x4, 0x23, 0x7E, 0xCD, 0x5E, 0xD6, 0x77, 0x10, 70 | 0xF8, 0x36, 0x0, 0x21, 0x8, 0xD4, 0x22, 0x59, 0xD4, 0xC9, 0xD5, 71 | 0xE, 0xB, 0xCD, 0xDE, 0xD5, 0xC4, 0xB9, 0xD5, 0xD1, 0xC9, 0xCD, 72 | 0x3C, 0xD7, 0xFE, 0x10, 0xD8, 0xCD, 0xA7, 0xD5, 0x2A, 0x5B, 0xD4, 73 | 0x7E, 0xFE, 0x21, 0x38, 0x8, 0xE5, 0xCD, 0xAE, 0xD5, 0xE1, 0x23, 74 | 0x18, 0xF3, 0xCD, 0xEA, 0xD5, 0xBF, 0xCD, 0x2F, 0xD6, 0xC3, 0x3A, 75 | 0xD5, 0x1A, 0xB7, 0xC8, 0xFE, 0x20, 0x38, 0xDC, 0xC8, 0xFE, 0x3D, 76 | 0xC8, 0xFE, 0x5F, 0xC8, 0xFE, 0x2E, 0xC8, 0xFE, 0x3A, 0xC8, 0xFE, 77 | 0x3B, 0xC8, 0xFE, 0x3C, 0xC8, 0xFE, 0x3E, 0xC9, 0xED, 0x5B, 0x59, 78 | 0xD4, 0x1A, 0xB7, 0xC8, 0xFE, 0x20, 0xC0, 0x13, 0x18, 0xF7, 0x85, 79 | 0x6F, 0xD0, 0x24, 0xC9, 0xCD, 0xE1, 0xD7, 0x21, 0xA6, 0xD4, 0x6, 80 | 0xB, 0x7E, 0x2B, 0xFE, 0x20, 0x20, 0x4, 0x10, 0xF8, 0x18, 0x4, 81 | 0xFE, 0x48, 0x28, 0x2B, 0x21, 0x9C, 0xD4, 0x1, 0x0, 0x11, 0x7E, 82 | 0xFE, 0x20, 0x28, 0x18, 0x23, 0xD6, 0x30, 0xFE, 0xA, 0x30, 0x13, 83 | 0x57, 0x79, 0x7, 0x7, 0x7, 0x81, 0x38, 0xB, 0x81, 0x38, 0x8, 84 | 0x82, 0x38, 0x5, 0x4F, 0x10, 0xE3, 0x79, 0xC9, 0xC3, 0xF0, 0xD6, 85 | 0xCD, 0xE1, 0xD7, 0x21, 0x9C, 0xD4, 0x11, 0x0, 0x0, 0x6, 0xB, 86 | 0x7E, 0xFE, 0x20, 0x28, 0x2D, 0xFE, 0x48, 0x28, 0x29, 0xD6, 0x30, 87 | 0x38, 0xE5, 0xFE, 0xA, 0x38, 0x6, 0xD6, 0x7, 0xFE, 0x10, 0x30, 88 | 0xDB, 0x23, 0x4F, 0x7A, 0x7, 0x7, 0x7, 0x7, 0xE6, 0xF0, 0x57, 89 | 0x7B, 0x7, 0x7, 0x7, 0x7, 0x5F, 0xE6, 0xF, 0xB2, 0x57, 0x7B, 90 | 0xE6, 0xF0, 0xB1, 0x5F, 0x10, 0xCE, 0xEB, 0x7D, 0xC9, 0x21, 0x80, 91 | 0x0, 0x81, 0xCD, 0x37, 0xD7, 0x7E, 0xC9, 0xAF, 0x32, 0x9B, 0xD4, 92 | 0xCD, 0xD7, 0xD7, 0xC8, 0x18, 0x7, 0xCD, 0xD7, 0xD7, 0xC8, 0x3A, 93 | 0x59, 0xD6, 0xC3, 0xD, 0xD6, 0x3E, 0x0, 0xB7, 0xC8, 0x3D, 0x21, 94 | 0x59, 0xD6, 0xBE, 0xC9, 0x21, 0x9B, 0xD4, 0xAF, 0x32, 0xD8, 0xD7, 95 | 0xCD, 0x2A, 0xD7, 0xED, 0x53, 0x5B, 0xD4, 0x1A, 0xB7, 0x28, 0xA, 96 | 0xDE, 0x40, 0x47, 0x13, 0x1A, 0xFE, 0x3A, 0x28, 0x7, 0x1B, 0x3A, 97 | 0x59, 0xD6, 0x77, 0x18, 0x6, 0x78, 0x32, 0xD8, 0xD7, 0x70, 0x13, 98 | 0xAF, 0x32, 0xBE, 0xD4, 0x6, 0x8, 0xCD, 0x31, 0xD8, 0x6, 0x3, 99 | 0xFE, 0x2E, 0x20, 0x6, 0x13, 0xCD, 0x31, 0xD8, 0x18, 0x3, 0xCD, 100 | 0x52, 0xD8, 0x6, 0x4, 0x23, 0x36, 0x0, 0x10, 0xFB, 0xED, 0x53, 101 | 0x59, 0xD4, 0x3A, 0xBE, 0xD4, 0xB7, 0xC9, 0xCD, 0xD, 0xD7, 0x28, 102 | 0x1C, 0x23, 0xFE, 0x2A, 0x20, 0x7, 0x36, 0x3F, 0xCD, 0x58, 0xD8, 103 | 0x18, 0x7, 0x77, 0x13, 0xFE, 0x3F, 0xCC, 0x58, 0xD8, 0x10, 0xE6, 104 | 0xCD, 0xD, 0xD7, 0xC8, 0x13, 0x18, 0xF9, 0x23, 0x36, 0x20, 0x10, 105 | 0xFB, 0xC9, 0x3A, 0xBE, 0xD4, 0x3C, 0x32, 0xBE, 0xD4, 0xC9, 0x21, 106 | 0xBF, 0xD4, 0xE, 0xB, 0x11, 0x9C, 0xD4, 0x6, 0x4, 0x1A, 0xBE, 107 | 0x20, 0xA, 0x13, 0x23, 0x10, 0xF8, 0x1A, 0xFE, 0x20, 0x20, 0x4, 108 | 0xC9, 0x23, 0x10, 0xFD, 0x23, 0x23, 0xD, 0x20, 0xE5, 0xC, 0xC9, 109 | 0x3E, 0x80, 0xF5, 0xCD, 0xE1, 0xD7, 0xCD, 0xC3, 0xD7, 0x21, 0x9C, 110 | 0xD4, 0x7E, 0xFE, 0x20, 0xCC, 0x2B, 0xD9, 0xCD, 0x2A, 0xD7, 0x6, 111 | 0x0, 0x28, 0x16, 0xFE, 0x41, 0x28, 0x6, 0xFE, 0x53, 0x20, 0xE, 112 | 0x6, 0x80, 0x13, 0xED, 0x53, 0x59, 0xD4, 0xFE, 0x53, 0x28, 0x3, 113 | 0xF1, 0xAF, 0xF5, 0xF1, 0x57, 0x1E, 0x0, 0xD5, 0x78, 0x32, 0xD2, 114 | 0xD8, 0xCD, 0x24, 0xD6, 0xCC, 0x9C, 0xD5, 0x28, 0x67, 0x3D, 0xF, 115 | 0xF, 0xF, 0xE6, 0x60, 0x4F, 0x3E, 0xA, 0xCD, 0xBA, 0xD7, 0xD1, 116 | 0xD5, 0xA2, 0xFE, 0x0, 0x20, 0x4A, 0xD1, 0x7B, 0x1C, 0xD5, 0xE6, 117 | 0x3, 0xF5, 0x20, 0x5, 0xCD, 0xA7, 0xD5, 0x18, 0x8, 0xCD, 0xEA, 118 | 0xD5, 0x20, 0x20, 0x7C, 0x20, 0xA0, 0x6, 0x1, 0x78, 0xCD, 0xBA, 119 | 0xD7, 0xE6, 0x7F, 0xFE, 0x20, 0x20, 0x13, 0xF1, 0xF5, 0xFE, 0x3, 120 | 0x20, 0xB, 0x3E, 0x9, 0xCD, 0xBA, 0xD7, 0xE6, 0x7F, 0xFE, 0x20, 121 | 0x28, 0x16, 0x3E, 0x20, 0xCD, 0xAE, 0xD5, 0x4, 0x78, 0xFE, 0xC, 122 | 0x30, 0xB, 0xFE, 0x9, 0x20, 0xD6, 0x3E, 0x2E, 0xCD, 0xAE, 0xD5, 123 | 0x18, 0xCF, 0xF1, 0xCD, 0xDF, 0xD6, 0x20, 0x5, 0xCD, 0x2B, 0xD6, 124 | 0x18, 0x97, 0xD1, 0xC9, 0x6, 0xB, 0x36, 0x3F, 0x23, 0x10, 0xFB, 125 | 0xC9, 0xCD, 0xE1, 0xD7, 0xFE, 0xB, 0x20, 0x12, 0xCD, 0xE5, 0xD5, 126 | 0x41, 0x6C, 0x6C, 0xBF, 0xCD, 0xB9, 0xD5, 0xFE, 0x59, 0xC2, 0x3A, 127 | 0xD5, 0xCD, 0xA7, 0xD5, 0xCD, 0xC3, 0xD7, 0xAF, 0x47, 0xCD, 0xB2, 128 | 0xD8, 0x11, 0x9B, 0xD4, 0xCD, 0x3A, 0xD6, 0xC9, 0x3E, 0xFF, 0x18, 129 | 0x1, 0xAF, 0x32, 0xC3, 0xD5, 0xCD, 0xE1, 0xD7, 0xC2, 0xF0, 0xD6, 130 | 0xCD, 0x2A, 0xD7, 0x32, 0xE9, 0xD9, 0x28, 0x5, 0x13, 0xEB, 0x22, 131 | 0x59, 0xD4, 0xCD, 0xC3, 0xD7, 0xCD, 0x12, 0xD6, 0xCA, 0xDC, 0xD9, 132 | 0xCD, 0xA7, 0xD5, 0x3E, 0x17, 0x32, 0xBC, 0xD4, 0x21, 0xBD, 0xD4, 133 | 0x36, 0xFF, 0x6, 0x0, 0x21, 0xBD, 0xD4, 0x7E, 0xFE, 0x80, 0x38, 134 | 0x9, 0xE5, 0xCD, 0xD9, 0xD5, 0xE1, 0x20, 0x3D, 0xAF, 0x77, 0x34, 135 | 0x21, 0x80, 0x0, 0xCD, 0x37, 0xD7, 0x7E, 0xE6, 0x7F, 0xFE, 0x1A, 136 | 0xC8, 0xFE, 0xD, 0x28, 0xE, 0xFE, 0xA, 0x28, 0xA, 0xFE, 0x9, 137 | 0x28, 0xD, 0xCD, 0xC1, 0xD5, 0x4, 0x18, 0x12, 0xCD, 0xC1, 0xD5, 138 | 0x6, 0x0, 0x18, 0xB, 0x3E, 0x20, 0xCD, 0xC1, 0xD5, 0x4, 0x78, 139 | 0xE6, 0x7, 0x20, 0xF5, 0xCD, 0xDF, 0xD6, 0x28, 0xB9, 0xFE, 0x3, 140 | 0xC8, 0x18, 0xB4, 0x3D, 0xC8, 0xC3, 0x79, 0xDB, 0xE5, 0x21, 0xBC, 141 | 0xD4, 0x35, 0x20, 0x10, 0x36, 0x16, 0x3E, 0x0, 0xFE, 0x50, 0x28, 142 | 0x8, 0xCD, 0xB9, 0xD5, 0xFE, 0x3, 0xCA, 0x88, 0xD5, 0xE1, 0xC9, 143 | 0xCD, 0x3C, 0xD7, 0x6F, 0x26, 0x0, 0xE5, 0xCD, 0x4B, 0xDA, 0xE, 144 | 0x16, 0xCD, 0x1B, 0xD6, 0xE1, 0x28, 0x3A, 0xAF, 0x32, 0xBB, 0xD4, 145 | 0xCD, 0x2A, 0xD7, 0x13, 0xFE, 0x53, 0x28, 0x2, 0x1B, 0x29, 0xED, 146 | 0x53, 0x59, 0xD4, 0x11, 0x0, 0x1, 0x7C, 0xB5, 0x28, 0x18, 0x2B, 147 | 0xE5, 0x21, 0x80, 0x0, 0x19, 0xE5, 0xCD, 0x4, 0xD6, 0x11, 0x9B, 148 | 0xD4, 0xE, 0x15, 0xCD, 0xDE, 0xD5, 0xD1, 0xE1, 0x20, 0xB, 0x18, 149 | 0xE4, 0x11, 0x9B, 0xD4, 0xCD, 0x20, 0xD6, 0x3C, 0x20, 0x3, 0xCD, 150 | 0xDF, 0xDB, 0xCD, 0x1, 0xD6, 0xC9, 0xCD, 0xE1, 0xD7, 0xC2, 0xF0, 151 | 0xD6, 0xCD, 0xC3, 0xD7, 0xCD, 0x24, 0xD6, 0x11, 0x9B, 0xD4, 0xC8, 152 | 0xD5, 0xCD, 0xE5, 0xD5, 0x44, 0x65, 0x6C, 0x65, 0x74, 0x65, 0x20, 153 | 0x46, 0x69, 0x6C, 0x65, 0xBF, 0xCD, 0xB9, 0xD5, 0xD1, 0xFE, 0x59, 154 | 0xC2, 0x88, 0xD5, 0xD5, 0xCD, 0x3A, 0xD6, 0xD1, 0xC9, 0xCD, 0x4B, 155 | 0xDA, 0x3A, 0xD8, 0xD7, 0xF5, 0x21, 0x9B, 0xD4, 0x11, 0xAB, 0xD4, 156 | 0x1, 0x10, 0x0, 0xED, 0xB0, 0xCD, 0x2A, 0xD7, 0xFE, 0x3D, 0x20, 157 | 0x28, 0xEB, 0x23, 0x22, 0x59, 0xD4, 0xCD, 0xE1, 0xD7, 0x20, 0x1E, 158 | 0xF1, 0x47, 0x21, 0xD8, 0xD7, 0x7E, 0xB7, 0x28, 0x4, 0xB8, 0x70, 159 | 0x20, 0x11, 0x70, 0xAF, 0x32, 0x9B, 0xD4, 0x11, 0x9B, 0xD4, 0xE, 160 | 0x17, 0xCD, 0x1B, 0xD6, 0xC0, 0xCD, 0x9C, 0xD5, 0xC3, 0x79, 0xDB, 161 | 0xCD, 0xEA, 0xD6, 0x5F, 0xCD, 0x45, 0xD6, 0xC3, 0x8B, 0xD5, 0xCD, 162 | 0xEA, 0xD6, 0x32, 0xA7, 0xDB, 0x18, 0xF5, 0xCD, 0x7A, 0xD7, 0x18, 163 | 0x3C, 0x21, 0x0, 0x1, 0x18, 0x37, 0x3A, 0x9C, 0xD4, 0xFE, 0x20, 164 | 0x20, 0x14, 0x3A, 0xD8, 0xD7, 0xB7, 0xCA, 0x8B, 0xD5, 0x3D, 0x32, 165 | 0x59, 0xD6, 0xCD, 0x58, 0xD6, 0xCD, 0xD, 0xD6, 0xC3, 0x8B, 0xD5, 166 | 0x3A, 0xA4, 0xD4, 0xFE, 0x20, 0xC2, 0xF0, 0xD6, 0x21, 0x77, 0xD4, 167 | 0x11, 0xA4, 0xD4, 0x1, 0x3, 0x0, 0xED, 0xB0, 0x21, 0x0, 0x1, 168 | 0xE5, 0xCD, 0x89, 0xDB, 0xE1, 0xC0, 0x22, 0x67, 0xDB, 0xCD, 0xCD, 169 | 0xD7, 0xCD, 0xE1, 0xD7, 0x21, 0xD8, 0xD7, 0xE5, 0x7E, 0x32, 0x9B, 170 | 0xD4, 0x21, 0xAB, 0xD4, 0xCD, 0xE4, 0xD7, 0xE1, 0x7E, 0x32, 0xAB, 171 | 0xD4, 0xAF, 0x32, 0xBB, 0xD4, 0x11, 0x5C, 0x0, 0x21, 0x9B, 0xD4, 172 | 0x1, 0x21, 0x0, 0xED, 0xB0, 0x21, 0x8, 0xD4, 0x7E, 0xB7, 0x28, 173 | 0x7, 0xFE, 0x20, 0x28, 0x3, 0x23, 0x18, 0xF5, 0x6, 0x0, 0x11, 174 | 0x81, 0x0, 0x7E, 0x12, 0xB7, 0x28, 0x5, 0x4, 0x23, 0x13, 0x18, 175 | 0xF6, 0x78, 0x32, 0x80, 0x0, 0xCD, 0xA7, 0xD5, 0xCD, 0x1, 0xD6, 176 | 0xCD, 0x49, 0xD6, 0xCD, 0x0, 0x1, 0xCD, 0x1, 0xD6, 0xCD, 0x58, 177 | 0xD6, 0xCD, 0xD, 0xD6, 0xC3, 0x3A, 0xD5, 0xE1, 0xCD, 0x3E, 0xD6, 178 | 0xCD, 0xCD, 0xD7, 0xC3, 0xF0, 0xD6, 0xCD, 0x7A, 0xD7, 0xE5, 0xCD, 179 | 0xE1, 0xD7, 0xE1, 0x20, 0xF3, 0xCD, 0x92, 0xDB, 0xF5, 0xCD, 0x3E, 180 | 0xD6, 0xF1, 0xC9, 0x22, 0xC2, 0xDB, 0xCD, 0x43, 0xD6, 0x32, 0x3F, 181 | 0xD6, 0x32, 0xA9, 0xDB, 0xCD, 0xC3, 0xD7, 0xCD, 0x12, 0xD6, 0x20, 182 | 0x1B, 0x3E, 0x0, 0xFE, 0x0, 0x28, 0x9, 0x32, 0xA9, 0xDB, 0x5F, 183 | 0xCD, 0x45, 0xD6, 0x18, 0xE9, 0x21, 0xD8, 0xD7, 0xAF, 0xB6, 0xC2, 184 | 0x75, 0xDB, 0x36, 0x1, 0x18, 0xDD, 0x21, 0x0, 0x1, 0x3E, 0xD3, 185 | 0xBC, 0x38, 0x16, 0xE5, 0xEB, 0xCD, 0x4, 0xD6, 0x11, 0x9B, 0xD4, 186 | 0xCD, 0xDC, 0xD5, 0xE1, 0x20, 0x6, 0x11, 0x80, 0x0, 0x19, 0x18, 187 | 0xE7, 0x3D, 0xC8, 0xCD, 0xE5, 0xD5, 0x46, 0x75, 0x6C, 0xEC, 0x3E, 188 | 0x1, 0xB7, 0xC9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 189 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 190 | 0x0, 0x0, 0x0, 0x50, 0x32, 0x44, 0x4F, 0x53, 0x23, 0xC3, 0x16, 191 | 0xDC, 0x92, 0xDF, 0x93, 0xDF, 0xAC, 0xDF, 0x98, 0xDF, 0x0, 0x0, 192 | 0x45, 0xEA, 0xFF, 0x79, 0x32, 0x79, 0xE9, 0x21, 0x0, 0x0, 0x22, 193 | 0x7A, 0xE9, 0xAF, 0x32, 0x7C, 0xE9, 0x32, 0x7D, 0xE9, 0xED, 0x73, 194 | 0x8F, 0xE9, 0x31, 0xCF, 0xE9, 0xDD, 0xE5, 0xD5, 0xDD, 0xE1, 0x21, 195 | 0x2A, 0xE9, 0xE5, 0x79, 0xFE, 0xC8, 0xCA, 0x14, 0xE9, 0xFE, 0xC9, 196 | 0xCA, 0x21, 0xE9, 0xFE, 0x29, 0xD0, 0x21, 0x51, 0xDC, 0x6, 0x0, 197 | 0x9, 0x9, 0x7E, 0x23, 0x66, 0x6F, 0xE9, 0x3, 0xEA, 0xA3, 0xDC, 198 | 0xB0, 0xDC, 0xB3, 0xDC, 0xB8, 0xDC, 0xBC, 0xDC, 0xC0, 0xDC, 0xD7, 199 | 0xDC, 0xDC, 0xDC, 0xBA, 0xDD, 0x17, 0xDE, 0xE1, 0xDC, 0xB7, 0xDE, 200 | 0xBB, 0xDE, 0x5, 0xE1, 0xA1, 0xE5, 0xD9, 0xE5, 0xD9, 0xDE, 0x0, 201 | 0xDF, 0xC, 0xDF, 0x24, 0xE7, 0x6F, 0xE7, 0x5B, 0xE6, 0x17, 0xDF, 202 | 0x1F, 0xDF, 0x26, 0xDF, 0xC, 0xE3, 0x2C, 0xDF, 0x6F, 0xE3, 0x31, 203 | 0xDF, 0x36, 0xDF, 0x3E, 0xDF, 0x43, 0xDF, 0x1A, 0xE7, 0x64, 0xE7, 204 | 0x51, 0xDF, 0x59, 0xDF, 0x69, 0xDF, 0xAF, 0xDC, 0xAF, 0xDC, 0x64, 205 | 0xE7, 0xCD, 0x5C, 0xDD, 0xCD, 0x9E, 0xDD, 0xD4, 0x1, 0xDD, 0x32, 206 | 0x7A, 0xE9, 0xC9, 0x7B, 0x18, 0x4E, 0xCD, 0x15, 0xEA, 0x18, 0xF4, 207 | 0x4B, 0xC3, 0x12, 0xEA, 0x4B, 0xC3, 0xF, 0xEA, 0x4B, 0x1C, 0x28, 208 | 0x9, 0x1C, 0xC2, 0xC, 0xEA, 0xCD, 0x6, 0xEA, 0x18, 0xDF, 0xCD, 209 | 0x6, 0xEA, 0xB7, 0xC8, 0xCD, 0x9, 0xEA, 0x18, 0xD5, 0x3A, 0x3, 210 | 0x0, 0x18, 0xD0, 0x7B, 0x32, 0x3, 0x0, 0xC9, 0xCD, 0x67, 0xDD, 211 | 0x18, 0xC6, 0xCD, 0x9E, 0xDD, 0x30, 0x16, 0xF5, 0x3E, 0x5E, 0xCD, 212 | 0x1, 0xDD, 0xF1, 0xF5, 0xC6, 0x40, 0xCD, 0x1, 0xDD, 0xF1, 0xC9, 213 | 0x3E, 0xD, 0xCD, 0x1, 0xDD, 0x3E, 0xA, 0xFE, 0x9, 0x20, 0xF, 214 | 0x3E, 0x20, 0xCD, 0x1, 0xDD, 0x3A, 0x4F, 0xE9, 0xE6, 0x7, 0x20, 215 | 0xF4, 0x3E, 0x9, 0xC9, 0xF5, 0xCD, 0x67, 0xDD, 0xF1, 0xF5, 0x4F, 216 | 0xCD, 0xC, 0xEA, 0xF1, 0xF5, 0x4F, 0x3A, 0x51, 0xE9, 0xB7, 0xC4, 217 | 0xF, 0xEA, 0x3A, 0x15, 0xDC, 0xCB, 0x4F, 0x28, 0x8, 0x21, 0x53, 218 | 0xE9, 0xAF, 0xB6, 0x28, 0x1, 0x35, 0xF1, 0x21, 0x4F, 0xE9, 0xFE, 219 | 0x7F, 0xC8, 0x34, 0xFE, 0x20, 0xD0, 0x35, 0xFE, 0x8, 0x20, 0x2, 220 | 0x35, 0xC9, 0xFE, 0xD, 0x20, 0x3, 0x36, 0x0, 0xC9, 0xFE, 0x9, 221 | 0xC0, 0xF5, 0x7E, 0xC6, 0x8, 0xE6, 0xF8, 0x77, 0xF1, 0xC9, 0x21, 222 | 0x52, 0xE9, 0x7E, 0x36, 0x0, 0xB7, 0xC0, 0xC3, 0x9, 0xEA, 0x3A, 223 | 0x53, 0xE9, 0xB7, 0x20, 0x6, 0xCD, 0x6, 0xEA, 0xB7, 0x20, 0xB, 224 | 0x3A, 0x52, 0xE9, 0xB7, 0x20, 0x22, 0xCD, 0x6, 0xEA, 0xB7, 0xC8, 225 | 0xCD, 0x9, 0xEA, 0xFE, 0x13, 0x20, 0xE, 0xCD, 0x9, 0xEA, 0xFE, 226 | 0x3, 0xCA, 0x0, 0x0, 0xFE, 0x11, 0x20, 0xF4, 0x18, 0xD4, 0x32, 227 | 0x52, 0xE9, 0x3E, 0xFF, 0x32, 0x53, 0xE9, 0x3E, 0x1, 0xC9, 0xFE, 228 | 0xD, 0xC8, 0xFE, 0xA, 0xC8, 0xFE, 0x9, 0xC8, 0xFE, 0x8, 0xC8, 229 | 0xFE, 0x20, 0xC9, 0xCD, 0xB5, 0xDD, 0xE, 0x20, 0xCD, 0xC, 0xEA, 230 | 0xE, 0x8, 0xC3, 0xC, 0xEA, 0x1A, 0xFE, 0x24, 0xC8, 0x13, 0xD5, 231 | 0xCD, 0x1, 0xDD, 0xD1, 0x18, 0xF4, 0x3E, 0x23, 0xCD, 0x1, 0xDD, 232 | 0xCD, 0xFA, 0xDC, 0x21, 0x4F, 0xE9, 0x3A, 0x50, 0xE9, 0xBE, 0xC8, 233 | 0x3E, 0x20, 0xCD, 0x1, 0xDD, 0x18, 0xF1, 0x5, 0x3A, 0x4F, 0xE9, 234 | 0xF5, 0xC5, 0x3A, 0x50, 0xE9, 0x32, 0x4F, 0xE9, 0x78, 0xB7, 0x28, 235 | 0x13, 0x5, 0x23, 0x7E, 0xE5, 0xCD, 0x9E, 0xDD, 0x30, 0x4, 0x1F, 236 | 0xCD, 0x38, 0xDD, 0xCD, 0x38, 0xDD, 0xE1, 0x18, 0xE9, 0xC1, 0xF1, 237 | 0xE5, 0xC5, 0x21, 0x4F, 0xE9, 0x96, 0x3D, 0xFE, 0x8, 0x30, 0x7, 238 | 0xF5, 0xCD, 0xAD, 0xDD, 0xF1, 0x18, 0xF4, 0xC1, 0xE1, 0xC9, 0x3A, 239 | 0x4F, 0xE9, 0x32, 0x50, 0xE9, 0xDD, 0xE5, 0xE1, 0x4E, 0x23, 0x6, 240 | 0x0, 0xE5, 0xE5, 0xC5, 0xCD, 0x5C, 0xDD, 0xC1, 0xE1, 0xE6, 0x7F, 241 | 0xFE, 0x5, 0x20, 0x7, 0xE5, 0xC5, 0xCD, 0xCB, 0xDD, 0x18, 0xEE, 242 | 0xFE, 0x8, 0x20, 0xB, 0x78, 0xB7, 0x28, 0xE4, 0xE1, 0xE5, 0xCD, 243 | 0xDD, 0xDD, 0x18, 0xDD, 0xFE, 0x10, 0x20, 0x9, 0x3A, 0x51, 0xE9, 244 | 0x2F, 0x32, 0x51, 0xE9, 0x18, 0xD0, 0xFE, 0x12, 0x20, 0x1B, 0xC5, 245 | 0xCD, 0xC6, 0xDD, 0xC1, 0xE1, 0xE5, 0xC5, 0x78, 0xB7, 0x28, 0xC, 246 | 0x23, 0x7E, 0x5, 0xE5, 0xC5, 0xCD, 0xE6, 0xDC, 0xC1, 0xE1, 0x18, 247 | 0xF0, 0xC1, 0x18, 0xDF, 0xFE, 0x15, 0x20, 0x6, 0xE1, 0xCD, 0xC6, 248 | 0xDD, 0x18, 0x99, 0xFE, 0x18, 0x20, 0xB, 0xE1, 0x78, 0xB7, 0x28, 249 | 0xF5, 0xE5, 0xCD, 0xDD, 0xDD, 0x18, 0xF5, 0xFE, 0x7F, 0x28, 0xAC, 250 | 0xFE, 0xD, 0x28, 0x1B, 0xFE, 0xA, 0x28, 0x17, 0x23, 0x77, 0x4, 251 | 0xE5, 0xC5, 0xCD, 0xE6, 0xDC, 0xC1, 0xE1, 0xFE, 0x3, 0x78, 0x20, 252 | 0x5, 0xFE, 0x1, 0xCA, 0x0, 0x0, 0xB9, 0x20, 0xC2, 0xE1, 0x70, 253 | 0x3E, 0xD, 0xC3, 0x1, 0xDD, 0x3E, 0x22, 0x18, 0x6E, 0x21, 0x0, 254 | 0x0, 0x22, 0x75, 0xE9, 0x22, 0x73, 0xE9, 0x21, 0x80, 0x0, 0x22, 255 | 0x77, 0xE9, 0xCD, 0x10, 0xE3, 0xAF, 0x32, 0x81, 0xE9, 0xCD, 0x6, 256 | 0xE1, 0x3A, 0x87, 0xE9, 0x18, 0x50, 0xCD, 0xD5, 0xE0, 0xDD, 0x7E, 257 | 0x0, 0xD6, 0x3F, 0x28, 0xD, 0xDD, 0x7E, 0xE, 0xFE, 0x3F, 0x28, 258 | 0x4, 0xDD, 0x36, 0xE, 0x0, 0x3E, 0xF, 0xCD, 0xE1, 0xE3, 0x2A, 259 | 0x5C, 0xE9, 0xED, 0x5B, 0x77, 0xE9, 0x1, 0x80, 0x0, 0xED, 0xB0, 260 | 0xC9, 0xDD, 0x2A, 0x88, 0xE9, 0xCD, 0xD5, 0xE0, 0xCD, 0xF7, 0xE3, 261 | 0x18, 0xE7, 0xCD, 0xD5, 0xE0, 0xCD, 0x9F, 0xE4, 0x3A, 0x8A, 0xE9, 262 | 0x18, 0x12, 0xCD, 0xD5, 0xE0, 0xCD, 0xC0, 0xE4, 0x18, 0xF3, 0x2A, 263 | 0x75, 0xE9, 0x22, 0x7A, 0xE9, 0xC9, 0x3A, 0x81, 0xE9, 0xC3, 0xAC, 264 | 0xDC, 0x2A, 0x62, 0xE9, 0x18, 0xF1, 0x2A, 0x73, 0xE9, 0x18, 0xEC, 265 | 0xCD, 0xD5, 0xE0, 0xCD, 0xDA, 0xE4, 0x18, 0xD4, 0x2A, 0x5E, 0xE9, 266 | 0x18, 0xDF, 0x7B, 0x3C, 0x3A, 0x7F, 0xE9, 0x28, 0xDF, 0x7B, 0xE6, 267 | 0x1F, 0x32, 0x7F, 0xE9, 0xC9, 0xCD, 0xD5, 0xE0, 0xCD, 0xF1, 0xE4, 268 | 0x18, 0xB9, 0x21, 0x20, 0x0, 0xCD, 0xCA, 0xE8, 0xDD, 0x72, 0x21, 269 | 0xDD, 0x71, 0x22, 0xDD, 0x70, 0x23, 0xC9, 0x7B, 0x2F, 0x5F, 0x7A, 270 | 0x2F, 0x57, 0x2A, 0x75, 0xE9, 0x7B, 0xA5, 0x6F, 0x7A, 0xA4, 0x67, 271 | 0x22, 0x75, 0xE9, 0xEB, 0x2A, 0x73, 0xE9, 0x7B, 0xA5, 0x6F, 0x7A, 272 | 0xA4, 0x67, 0x22, 0x73, 0xE9, 0x3A, 0x81, 0xE9, 0xCD, 0x6, 0xE1, 273 | 0xAF, 0xC3, 0xAC, 0xDC, 0xE9, 0x11, 0x71, 0xE0, 0x18, 0x10, 0x11, 274 | 0x84, 0xE0, 0x1, 0xFF, 0xFF, 0x18, 0x13, 0x11, 0xBE, 0xE0, 0x18, 275 | 0x3, 0x11, 0xC9, 0xE0, 0x6, 0x0, 0x18, 0x5, 0x11, 0x8C, 0xE0, 276 | 0x6, 0xFF, 0xE, 0x0, 0xC5, 0xD5, 0xCD, 0xFA, 0xDC, 0x3A, 0x81, 277 | 0xE9, 0xC6, 0x41, 0x32, 0xA4, 0xE0, 0x11, 0x96, 0xE0, 0xCD, 0xBA, 278 | 0xDD, 0xD1, 0xCD, 0xBA, 0xDD, 0xCD, 0xFA, 0xDC, 0x11, 0xA8, 0xE0, 279 | 0xCD, 0xBA, 0xDD, 0x3A, 0x79, 0xE9, 0xF5, 0x1, 0x64, 0x0, 0xCD, 280 | 0x4C, 0xE0, 0xE, 0xA, 0xCD, 0x4C, 0xE0, 0x1, 0x1, 0x1, 0xCD, 281 | 0x4C, 0xE0, 0xF1, 0xC1, 0xC5, 0xFE, 0xF, 0x38, 0x39, 0xFE, 0x18, 282 | 0x38, 0x10, 0xFE, 0x1E, 0x28, 0xC, 0xFE, 0x21, 0x38, 0x2D, 0xFE, 283 | 0x25, 0x38, 0x4, 0xFE, 0x28, 0x20, 0x25, 0xDD, 0xE5, 0xD6, 0x13, 284 | 0x20, 0x7, 0xB1, 0x28, 0x4, 0xCD, 0x5F, 0xE2, 0xE3, 0x11, 0xB4, 285 | 0xE0, 0xCD, 0xBA, 0xDD, 0xE1, 0x6, 0x8, 0xCD, 0x63, 0xE0, 0x3E, 286 | 0x2E, 0xE5, 0xCD, 0x1, 0xDD, 0xE1, 0x6, 0x3, 0xCD, 0x63, 0xE0, 287 | 0xCD, 0x67, 0xDD, 0xB7, 0x28, 0x5, 0xCD, 0x5C, 0xDD, 0x18, 0xF5, 288 | 0xCD, 0x5C, 0xDD, 0xC1, 0xFE, 0x3, 0x28, 0x8, 0xA0, 0x28, 0x5, 289 | 0x21, 0x15, 0xDC, 0xCB, 0x56, 0xCA, 0x0, 0x0, 0xFE, 0x18, 0xC8, 290 | 0xC5, 0x18, 0xE7, 0x16, 0xFF, 0x14, 0x91, 0x30, 0xFC, 0x81, 0xF5, 291 | 0x7A, 0xB0, 0x28, 0x9, 0x42, 0x7A, 0xC6, 0x30, 0xC5, 0xCD, 0x1, 292 | 0xDD, 0xC1, 0xF1, 0xC9, 0x23, 0x7E, 0xE6, 0x7F, 0xE5, 0xC5, 0xCD, 293 | 0x1, 0xDD, 0xC1, 0xE1, 0x10, 0xF3, 0xC9, 0x4E, 0x6F, 0x6E, 0x2D, 294 | 0x65, 0x78, 0x69, 0x73, 0x74, 0x65, 0x6E, 0x74, 0x20, 0x64, 0x72, 295 | 0x69, 0x76, 0x65, 0x24, 0x46, 0x69, 0x6C, 0x65, 0x20, 0x69, 0x73, 296 | 0x20, 0x52, 0x65, 0x61, 0x64, 0x2D, 0x4F, 0x6E, 0x6C, 0x79, 0x24, 297 | 0x44, 0x69, 0x73, 0x6B, 0x20, 0x65, 0x72, 0x72, 0x6F, 0x72, 0x20, 298 | 0x6F, 0x6E, 0x20, 0x0, 0x3A, 0x20, 0x24, 0x46, 0x75, 0x6E, 0x63, 299 | 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x3D, 0x20, 0x24, 0x3B, 0x20, 0x46, 300 | 0x69, 0x6C, 0x65, 0x20, 0x3D, 0x20, 0x24, 0x52, 0x65, 0x61, 0x64, 301 | 0x20, 0x65, 0x72, 0x72, 0x6F, 0x72, 0x24, 0x57, 0x72, 0x69, 0x74, 302 | 0x65, 0x20, 0x65, 0x72, 0x72, 0x6F, 0x72, 0x24, 0x3E, 0xFF, 0x32, 303 | 0x7C, 0xE9, 0x3A, 0x81, 0xE9, 0x32, 0x80, 0xE9, 0x5F, 0xDD, 0x7E, 304 | 0x0, 0x32, 0x7E, 0xE9, 0xFE, 0x3F, 0x28, 0x1A, 0xE6, 0x1F, 0x7B, 305 | 0x28, 0x4, 0xDD, 0x7E, 0x0, 0x3D, 0xCD, 0x6, 0xE1, 0xDD, 0x7E, 306 | 0x0, 0xE6, 0xE0, 0x47, 0x3A, 0x7F, 0xE9, 0xB0, 0xDD, 0x77, 0x0, 307 | 0xC9, 0x7B, 0xE6, 0xF, 0x47, 0xED, 0x5B, 0x75, 0xE9, 0xB7, 0x28, 308 | 0x6, 0xCB, 0x1A, 0xCB, 0x1B, 0x10, 0xFA, 0x21, 0x81, 0xE9, 0xCB, 309 | 0x43, 0x28, 0x2, 0xBE, 0xC8, 0x77, 0xD5, 0x4F, 0xCD, 0x1B, 0xEA, 310 | 0x7C, 0xB5, 0x20, 0x4, 0x2A, 0xB, 0xDC, 0xE9, 0x5E, 0x23, 0x56, 311 | 0x23, 0xED, 0x53, 0x54, 0xE9, 0x22, 0x56, 0xE9, 0x23, 0x23, 0x22, 312 | 0x58, 0xE9, 0x23, 0x23, 0x22, 0x5A, 0xE9, 0x23, 0x23, 0x11, 0x5C, 313 | 0xE9, 0x1, 0x8, 0x0, 0xED, 0xB0, 0x2A, 0x5E, 0xE9, 0xE, 0xF, 314 | 0xED, 0xB0, 0xD1, 0xCB, 0x43, 0xC0, 0x2A, 0x75, 0xE9, 0xCD, 0xBF, 315 | 0xE1, 0x22, 0x75, 0xE9, 0xED, 0x5B, 0x69, 0xE9, 0x3E, 0x3, 0xCB, 316 | 0x3A, 0xCB, 0x1B, 0x3D, 0x20, 0xF9, 0x2A, 0x62, 0xE9, 0xE5, 0x23, 317 | 0x36, 0x0, 0x1B, 0x7A, 0xB3, 0x20, 0xF8, 0xE1, 0xED, 0x5B, 0x6D, 318 | 0xE9, 0x73, 0x23, 0x72, 0x2A, 0x56, 0xE9, 0x77, 0x23, 0x77, 0x32, 319 | 0x87, 0xE9, 0x32, 0x8E, 0xE9, 0xCD, 0x6A, 0xE2, 0x3E, 0xFF, 0xCD, 320 | 0x8E, 0xE2, 0xCD, 0x71, 0xE2, 0xC8, 0xCD, 0x5F, 0xE2, 0x7E, 0xFE, 321 | 0xE5, 0x28, 0xEF, 0xFE, 0x21, 0x28, 0xEB, 0x3A, 0x7F, 0xE9, 0xBE, 322 | 0x20, 0xA, 0x23, 0x7E, 0xD6, 0x24, 0x20, 0x4, 0x3D, 0x32, 0x87, 323 | 0xE9, 0xE, 0x1, 0xCD, 0x46, 0xE3, 0xCD, 0x78, 0xE2, 0x18, 0xD1, 324 | 0xEB, 0x21, 0x1, 0x0, 0x3A, 0x81, 0xE9, 0xB7, 0x28, 0x4, 0x29, 325 | 0x3D, 0x20, 0xFC, 0x7A, 0xB4, 0x67, 0x7B, 0xB5, 0x6F, 0xC9, 0x2A, 326 | 0x84, 0xE9, 0xCB, 0x3C, 0xCB, 0x1D, 0xCB, 0x3C, 0xCB, 0x1D, 0x22, 327 | 0x82, 0xE9, 0xEB, 0x21, 0x0, 0x0, 0xED, 0x4B, 0x64, 0xE9, 0x3E, 328 | 0x11, 0xB7, 0xED, 0x42, 0x3F, 0x38, 0x2, 0x9, 0xB7, 0xCB, 0x13, 329 | 0xCB, 0x12, 0x3D, 0x28, 0x6, 0xCB, 0x15, 0xCB, 0x14, 0x18, 0xEB, 330 | 0xE5, 0x2A, 0x71, 0xE9, 0x19, 0x44, 0x4D, 0xCD, 0x1E, 0xEA, 0xC1, 331 | 0xED, 0x5B, 0x54, 0xE9, 0xCD, 0x30, 0xEA, 0x44, 0x4D, 0xC3, 0x21, 332 | 0xEA, 0xDD, 0x4E, 0x20, 0x3A, 0x66, 0xE9, 0x47, 0xCB, 0x39, 0x10, 333 | 0xFC, 0x2F, 0xC6, 0x9, 0x47, 0x3A, 0x68, 0xE9, 0xDD, 0xA6, 0xC, 334 | 0xF, 0x7, 0x10, 0xFD, 0x81, 0xDD, 0xE5, 0xE1, 0xE, 0x10, 0x9, 335 | 0x4F, 0x9, 0x3A, 0x6A, 0xE9, 0xB7, 0x5E, 0x57, 0xC8, 0x9, 0x5E, 336 | 0x23, 0x56, 0x2B, 0xC9, 0x21, 0x0, 0x0, 0x3A, 0x66, 0xE9, 0x47, 337 | 0xCB, 0x23, 0xCB, 0x12, 0xCB, 0x15, 0x10, 0xF8, 0x3A, 0x67, 0xE9, 338 | 0xDD, 0xA6, 0x20, 0xB3, 0x5F, 0xC9, 0x2A, 0x5C, 0xE9, 0x3A, 0x86, 339 | 0xE9, 0x85, 0x6F, 0xD0, 0x24, 0xC9, 0x21, 0xFF, 0xFF, 0x22, 0x84, 340 | 0xE9, 0xC9, 0x2A, 0x84, 0xE9, 0x7C, 0xA5, 0x3C, 0xC9, 0xCD, 0x81, 341 | 0xE2, 0xD8, 0x13, 0x72, 0x2B, 0x73, 0xC9, 0x2A, 0x56, 0xE9, 0xED, 342 | 0x5B, 0x84, 0xE9, 0x7B, 0x96, 0x23, 0x7A, 0x9E, 0xC9, 0x4F, 0x2A, 343 | 0x84, 0xE9, 0x23, 0x22, 0x84, 0xE9, 0xED, 0x5B, 0x6B, 0xE9, 0xB7, 344 | 0xED, 0x52, 0x19, 0x28, 0x2, 0x30, 0xC8, 0x7D, 0x87, 0x87, 0x87, 345 | 0x87, 0x87, 0xE6, 0x60, 0x32, 0x86, 0xE9, 0xC0, 0xC5, 0xCD, 0xD4, 346 | 0xE1, 0xCD, 0xF5, 0xE2, 0xC1, 0x2A, 0x6F, 0xE9, 0xED, 0x5B, 0x82, 347 | 0xE9, 0xB7, 0xED, 0x52, 0xC8, 0xD8, 0x2A, 0x5C, 0xE9, 0x6, 0x80, 348 | 0xAF, 0x86, 0x23, 0x10, 0xFC, 0x2A, 0x60, 0xE9, 0x19, 0xC, 0x28, 349 | 0xA, 0xBE, 0xC8, 0x3E, 0xFF, 0x32, 0x8E, 0xE9, 0xC3, 0x78, 0xE3, 350 | 0x77, 0xC9, 0xCD, 0x27, 0xEA, 0x21, 0xA0, 0xDF, 0x18, 0x6, 0xCD, 351 | 0x2A, 0xEA, 0x21, 0xA5, 0xDF, 0xB7, 0xC8, 0xE5, 0x2A, 0x9, 0xDC, 352 | 0xE3, 0xC9, 0xCD, 0x16, 0xE3, 0xCD, 0xDF, 0xE2, 0x18, 0x13, 0xE, 353 | 0xFF, 0xCD, 0xB6, 0xE2, 0xCD, 0x16, 0xE3, 0xE, 0x1, 0xCD, 0xE7, 354 | 0xE2, 0x18, 0x4, 0xED, 0x53, 0x77, 0xE9, 0xED, 0x4B, 0x77, 0xE9, 355 | 0x18, 0x4, 0xED, 0x4B, 0x5C, 0xE9, 0xC3, 0x24, 0xEA, 0x7B, 0xE6, 356 | 0x7, 0x3C, 0x47, 0x4F, 0xCB, 0x3A, 0xCB, 0x1B, 0xCB, 0x3A, 0xCB, 357 | 0x1B, 0xCB, 0x3A, 0xCB, 0x1B, 0x2A, 0x62, 0xE9, 0x19, 0x7E, 0x7, 358 | 0x10, 0xFD, 0x41, 0xC9, 0xC5, 0xCD, 0x1D, 0xE3, 0xE6, 0xFE, 0xD1, 359 | 0xB3, 0xF, 0x10, 0xFD, 0x77, 0xC9, 0xCD, 0x5F, 0xE2, 0x11, 0x10, 360 | 0x0, 0x19, 0x43, 0x5E, 0x23, 0x16, 0x0, 0x3A, 0x6A, 0xE9, 0xB7, 361 | 0x28, 0x3, 0x5, 0x56, 0x23, 0x7A, 0xB3, 0x28, 0xD, 0xE5, 0xC5, 362 | 0x2A, 0x69, 0xE9, 0xB7, 0xED, 0x52, 0xD4, 0x39, 0xE3, 0xC1, 0xE1, 363 | 0x10, 0xE0, 0xC9, 0x2A, 0x73, 0xE9, 0xCD, 0xBF, 0xE1, 0x22, 0x73, 364 | 0xE9, 0xED, 0x5B, 0x6B, 0xE9, 0x13, 0x2A, 0x56, 0xE9, 0x73, 0x23, 365 | 0x72, 0xC9, 0xCD, 0x5F, 0xE2, 0x11, 0x2, 0x0, 0x19, 0xCB, 0x7E, 366 | 0x20, 0xB, 0x1E, 0x7, 0x19, 0xCB, 0x7E, 0x20, 0x4, 0x23, 0xCB, 367 | 0x7E, 0xC8, 0x2A, 0xF, 0xDC, 0xE9, 0x2A, 0x73, 0xE9, 0xCD, 0xBF, 368 | 0xE1, 0xED, 0x52, 0xC0, 0x2A, 0xD, 0xDC, 0xE9, 0x62, 0x6B, 0x7A, 369 | 0xB3, 0x28, 0xB, 0x1B, 0xE5, 0xD5, 0xCD, 0x1D, 0xE3, 0x1F, 0x30, 370 | 0x1F, 0xD1, 0xE1, 0xED, 0x4B, 0x69, 0xE9, 0xB7, 0xED, 0x42, 0x9, 371 | 0x30, 0xE, 0x23, 0xD5, 0xE5, 0xEB, 0xCD, 0x1D, 0xE3, 0x1F, 0x30, 372 | 0x9, 0xE1, 0xD1, 0x18, 0xD9, 0x7A, 0xB3, 0x20, 0xD5, 0xC9, 0x37, 373 | 0x17, 0xCD, 0x41, 0xE3, 0xD1, 0xE1, 0xC9, 0x32, 0x8B, 0xE9, 0x3A, 374 | 0x8E, 0xE9, 0xA7, 0xC4, 0x60, 0xE1, 0x3E, 0xFF, 0x32, 0x8A, 0xE9, 375 | 0xDD, 0x22, 0x88, 0xE9, 0xCD, 0x6A, 0xE2, 0xAF, 0xCD, 0x8E, 0xE2, 376 | 0xCD, 0x71, 0xE2, 0x28, 0x7C, 0xED, 0x5B, 0x88, 0xE9, 0x1A, 0xFE, 377 | 0xE5, 0x28, 0x7, 0xD5, 0xCD, 0x81, 0xE2, 0xD1, 0x30, 0x6C, 0xCD, 378 | 0x5F, 0xE2, 0x7E, 0xFE, 0x21, 0x28, 0xDF, 0x3A, 0x8B, 0xE9, 0x47, 379 | 0xAF, 0x32, 0x8C, 0xE9, 0x32, 0x8D, 0xE9, 0x4F, 0x78, 0xB7, 0x28, 380 | 0x5D, 0x1A, 0xD6, 0x3F, 0x28, 0x3C, 0x79, 0xB7, 0x20, 0x23, 0x3A, 381 | 0x15, 0xDC, 0xCB, 0x47, 0x28, 0x1C, 0x23, 0x23, 0xCB, 0x7E, 0x2B, 382 | 0x2B, 0x28, 0x14, 0x1A, 0xFE, 0xE5, 0x28, 0xF, 0xAE, 0xE6, 0x7F, 383 | 0x28, 0x19, 0xE6, 0xE0, 0x20, 0x6, 0x3D, 0x32, 0x8D, 0xE9, 0x18, 384 | 0xF, 0x79, 0xFE, 0xD, 0x28, 0xA, 0xFE, 0xC, 0x1A, 0x28, 0x11, 385 | 0xAE, 0xE6, 0x7F, 0x20, 0x94, 0x13, 0x23, 0xC, 0x5, 0x18, 0xBB, 386 | 0x3D, 0x32, 0x8C, 0xE9, 0x18, 0xF4, 0xC5, 0xAE, 0x47, 0x3A, 0x68, 387 | 0xE9, 0x2F, 0xE6, 0x1F, 0xA0, 0xC1, 0x18, 0xE5, 0xCD, 0x6A, 0xE2, 388 | 0x3E, 0xFF, 0x32, 0x7A, 0xE9, 0xC9, 0x3A, 0x8C, 0xE9, 0x47, 0x3A, 389 | 0x8D, 0xE9, 0xA0, 0x20, 0xD2, 0xCD, 0x78, 0xE2, 0x3A, 0x84, 0xE9, 390 | 0xE6, 0x3, 0x32, 0x7A, 0xE9, 0xAF, 0x32, 0x8A, 0xE9, 0xC9, 0xCD, 391 | 0x9E, 0xE3, 0x3E, 0xC, 0xCD, 0xE1, 0xE3, 0xCD, 0x71, 0xE2, 0xC8, 392 | 0xCD, 0x84, 0xE3, 0xCD, 0x5F, 0xE2, 0x36, 0xE5, 0xE, 0x0, 0xCD, 393 | 0x46, 0xE3, 0xCD, 0x34, 0xE5, 0xCD, 0xF7, 0xE3, 0x18, 0xE7, 0xCD, 394 | 0x9E, 0xE3, 0x3E, 0xC, 0xCD, 0xE1, 0xE3, 0xCD, 0x71, 0xE2, 0xC8, 395 | 0xCD, 0x84, 0xE3, 0x1, 0x10, 0xC, 0xCD, 0x1F, 0xE5, 0xCD, 0xF7, 396 | 0xE3, 0x18, 0xEE, 0xCD, 0x9E, 0xE3, 0x3E, 0xC, 0xCD, 0xE1, 0xE3, 397 | 0xCD, 0x71, 0xE2, 0xC8, 0x1, 0x0, 0xC, 0xCD, 0x1F, 0xE5, 0xCD, 398 | 0xF7, 0xE3, 0x18, 0xF1, 0x1, 0x0, 0x0, 0x51, 0xCD, 0x5F, 0xDF, 399 | 0x3E, 0xC, 0xCD, 0xE1, 0xE3, 0xCD, 0x71, 0xE2, 0xC8, 0xCD, 0x5F, 400 | 0xE2, 0xEB, 0x21, 0xF, 0x0, 0xCD, 0xCA, 0xE8, 0x7A, 0xDD, 0x96, 401 | 0x21, 0x79, 0xDD, 0x9E, 0x22, 0x78, 0xDD, 0x9E, 0x23, 0xD4, 0x5F, 402 | 0xDF, 0xCD, 0xF7, 0xE3, 0x18, 0xDE, 0xCD, 0x5F, 0xE2, 0xE5, 0x7E, 403 | 0xEB, 0xDD, 0xE5, 0xE1, 0xC5, 0x6, 0x0, 0x9, 0xC1, 0x48, 0x6, 404 | 0x0, 0xED, 0xB0, 0xE1, 0x77, 0xCD, 0xD4, 0xE1, 0xC3, 0xFD, 0xE2, 405 | 0x3E, 0xF, 0xCD, 0xE1, 0xE3, 0xCD, 0x71, 0xE2, 0xC0, 0x3A, 0x7D, 406 | 0xE9, 0xB7, 0xC0, 0x3A, 0x8C, 0xE9, 0xB7, 0xC0, 0x2A, 0x11, 0xDC, 407 | 0x7C, 0xB5, 0xC8, 0x7E, 0x23, 0xB7, 0xCA, 0x7C, 0xE4, 0xE6, 0x7F, 408 | 0xFE, 0x24, 0x20, 0x4, 0x3A, 0x80, 0xE9, 0x3C, 0x3D, 0xE5, 0xCD, 409 | 0x6, 0xE1, 0xE1, 0x7E, 0x23, 0xE6, 0x7F, 0xFE, 0x24, 0x20, 0x3, 410 | 0x3A, 0x7F, 0xE9, 0xE6, 0x1F, 0x47, 0xDD, 0x7E, 0x0, 0xE6, 0xE0, 411 | 0xB0, 0xDD, 0x77, 0x0, 0xE5, 0x3E, 0xF, 0xCD, 0xE1, 0xE3, 0xCD, 412 | 0x71, 0xE2, 0xE1, 0x28, 0xC7, 0xE5, 0xCD, 0x5F, 0xE2, 0x11, 0xA, 413 | 0x0, 0x19, 0xCB, 0x7E, 0xE1, 0x28, 0xBA, 0x3A, 0x81, 0xE9, 0x3C, 414 | 0x32, 0x7E, 0xE9, 0xC9, 0xCD, 0xD5, 0xE0, 0xDD, 0x36, 0xE, 0x0, 415 | 0xCD, 0x3A, 0xE5, 0xCD, 0x71, 0xE2, 0xC8, 0xDD, 0x7E, 0xC, 0xF5, 416 | 0xCD, 0x5F, 0xE2, 0xDD, 0xE5, 0xD1, 0x1, 0x20, 0x0, 0xED, 0xB0, 417 | 0xDD, 0xCB, 0xE, 0xFE, 0xDD, 0x46, 0xC, 0xDD, 0x4E, 0xF, 0xF1, 418 | 0xDD, 0x77, 0xC, 0xB8, 0x28, 0x6, 0xE, 0x0, 0x30, 0x2, 0xE, 419 | 0x80, 0xDD, 0x71, 0xF, 0xC9, 0xCD, 0xD5, 0xE0, 0xDD, 0xCB, 0xE, 420 | 0x7E, 0xC0, 0xCD, 0x9E, 0xE3, 0x3E, 0xF, 0xCD, 0xE1, 0xE3, 0xCD, 421 | 0x71, 0xE2, 0xC8, 0xCD, 0x84, 0xE3, 0xCD, 0x5F, 0xE2, 0x1, 0x10, 422 | 0x0, 0x9, 0xEB, 0xDD, 0xE5, 0xE1, 0x9, 0x3A, 0x6A, 0xE9, 0xB7, 423 | 0x28, 0x1, 0x5, 0xCD, 0x39, 0xE6, 0xEB, 0xCD, 0x39, 0xE6, 0xEB, 424 | 0x20, 0x26, 0x23, 0x13, 0xCB, 0x40, 0x28, 0x3, 0x23, 0x13, 0xD, 425 | 0xD, 0x20, 0xEA, 0x21, 0xEC, 0xFF, 0x19, 0xDD, 0x7E, 0xC, 0xBE, 426 | 0x38, 0x8, 0x77, 0x23, 0x23, 0x23, 0xDD, 0x7E, 0xF, 0x77, 0x1E, 427 | 0x5, 0xCD, 0xEF, 0xE8, 0xC3, 0x34, 0xE5, 0x3E, 0xFF, 0x32, 0x7A, 428 | 0xE9, 0xC9, 0x7E, 0xCB, 0x40, 0x28, 0x3, 0x23, 0xB6, 0x2B, 0xB7, 429 | 0x20, 0xB, 0x1A, 0x77, 0xCB, 0x40, 0xC8, 0x23, 0x13, 0x1A, 0x77, 430 | 0x18, 0x7, 0x1A, 0x96, 0xC0, 0xB0, 0xC8, 0x23, 0x13, 0x1A, 0x96, 431 | 0x2B, 0x1B, 0xC9, 0xCD, 0xD5, 0xE0, 0xDD, 0x36, 0xE, 0x0, 0xCD, 432 | 0x9E, 0xE3, 0xDD, 0x7E, 0x0, 0xF5, 0xDD, 0x36, 0x0, 0xE5, 0x3E, 433 | 0x1, 0xCD, 0xE1, 0xE3, 0xF1, 0xDD, 0x77, 0x0, 0xCD, 0x71, 0xE2, 434 | 0xC8, 0xAF, 0xDD, 0x77, 0xD, 0xDD, 0xE5, 0xE1, 0x11, 0xF, 0x0, 435 | 0x19, 0x6, 0x11, 0x77, 0x23, 0x10, 0xFC, 0xCD, 0x5F, 0xE2, 0xDD, 436 | 0x7E, 0x0, 0x77, 0x1E, 0x1, 0xCD, 0xEF, 0xE8, 0x1E, 0x5, 0xCD, 437 | 0xEF, 0xE8, 0x1, 0x0, 0x20, 0xCD, 0x1F, 0xE5, 0xDD, 0xCB, 0xE, 438 | 0xFE, 0xC9, 0xDD, 0xCB, 0xE, 0x7E, 0x20, 0x2F, 0xCD, 0xDC, 0xE5, 439 | 0x3A, 0x7A, 0xE9, 0x3C, 0xC8, 0xCD, 0xF4, 0xE6, 0x38, 0x1A, 0x20, 440 | 0x30, 0x3E, 0xF, 0xCD, 0xE1, 0xE3, 0xCD, 0x71, 0xE2, 0x20, 0x26, 441 | 0x3A, 0x7D, 0xE9, 0xB7, 0x28, 0x8, 0xCD, 0x62, 0xE6, 0xCD, 0x71, 442 | 0xE2, 0x20, 0x1B, 0xDD, 0xCB, 0xE, 0xFE, 0x3E, 0xFF, 0x18, 0x14, 443 | 0xCD, 0xF4, 0xE6, 0x38, 0xF3, 0xDD, 0xCB, 0xA, 0x7E, 0x28, 0xD5, 444 | 0xCD, 0x3A, 0xE5, 0x18, 0xD5, 0xCD, 0xAF, 0xE5, 0xAF, 0x32, 0x7A, 445 | 0xE9, 0xC9, 0xDD, 0x46, 0xC, 0xDD, 0x4E, 0xE, 0xCB, 0x71, 0x37, 446 | 0xC0, 0x4, 0x78, 0xE6, 0x1F, 0x47, 0x20, 0xA, 0xC, 0x79, 0xE6, 447 | 0x3F, 0x4F, 0x37, 0xC8, 0xAF, 0x18, 0x4, 0x3A, 0x68, 0xE9, 0xA0, 448 | 0xDD, 0x70, 0xC, 0xDD, 0x71, 0xE, 0xC9, 0xCD, 0xD5, 0xE0, 0xAF, 449 | 0xCD, 0x2B, 0xE8, 0x28, 0x4, 0xC9, 0xCD, 0xD5, 0xE0, 0xAF, 0x32, 450 | 0x7D, 0xE9, 0xDD, 0x7E, 0x20, 0xFE, 0x80, 0x30, 0xB, 0xDD, 0xBE, 451 | 0xF, 0x38, 0x13, 0x3E, 0x1, 0x32, 0x7A, 0xE9, 0xC9, 0xCD, 0xA7, 452 | 0xE6, 0x3A, 0x7A, 0xE9, 0xB7, 0x20, 0xF1, 0xDD, 0x36, 0x20, 0x0, 453 | 0xCD, 0x18, 0xE2, 0x7A, 0xB3, 0x28, 0xE6, 0xCD, 0x47, 0xE2, 0xCD, 454 | 0xE6, 0xE1, 0xCD, 0xDF, 0xE2, 0x3A, 0x79, 0xE9, 0xFE, 0x14, 0xC0, 455 | 0xDD, 0x34, 0x20, 0xC9, 0xCD, 0xD5, 0xE0, 0x3E, 0xFF, 0xCD, 0x2B, 456 | 0xE8, 0x28, 0x4, 0xC9, 0xCD, 0xD5, 0xE0, 0x3E, 0xFF, 0x32, 0x7D, 457 | 0xE9, 0xCD, 0x9E, 0xE3, 0xDD, 0xE5, 0xE1, 0xCD, 0x87, 0xE3, 0xDD, 458 | 0x7E, 0x20, 0xFE, 0x80, 0x38, 0xE, 0xCD, 0xA7, 0xE6, 0x3A, 0x7A, 459 | 0xE9, 0xB7, 0xC2, 0x25, 0xE8, 0xDD, 0x36, 0x20, 0x0, 0xCD, 0x18, 460 | 0xE2, 0x7A, 0xB3, 0x20, 0x58, 0xE5, 0x79, 0xB7, 0x28, 0x4, 0x3D, 461 | 0xCD, 0x32, 0xE2, 0xCD, 0xAB, 0xE3, 0xE1, 0x7A, 0xB3, 0x28, 0x72, 462 | 0xDD, 0xCB, 0xE, 0xBE, 0x73, 0x3A, 0x6A, 0xE9, 0xB7, 0x28, 0x2, 463 | 0x23, 0x72, 0xE, 0x2, 0x3A, 0x79, 0xE9, 0xD6, 0x28, 0x20, 0x33, 464 | 0xD5, 0x21, 0x5C, 0xE9, 0x6, 0x80, 0x77, 0x23, 0x10, 0xFC, 0xCD, 465 | 0x47, 0xE2, 0x3A, 0x67, 0xE9, 0x47, 0x4, 0x2F, 0xA3, 0x5F, 0xE, 466 | 0x2, 0xE5, 0xD5, 0xC5, 0xCD, 0xE6, 0xE1, 0xCD, 0x16, 0xE3, 0xC1, 467 | 0xC5, 0xCD, 0xE7, 0xE2, 0xC1, 0xD1, 0xE1, 0xE, 0x0, 0x1C, 0x10, 468 | 0xEA, 0xCD, 0x10, 0xE3, 0xD1, 0xE, 0x0, 0xDD, 0xCB, 0xE, 0xBE, 469 | 0xC5, 0xCD, 0x47, 0xE2, 0xCD, 0xE6, 0xE1, 0xC1, 0xCD, 0xE7, 0xE2, 470 | 0xDD, 0x7E, 0x20, 0xDD, 0xBE, 0xF, 0x38, 0x8, 0x3C, 0xDD, 0x77, 471 | 0xF, 0xDD, 0xCB, 0xE, 0xBE, 0x3A, 0x79, 0xE9, 0xFE, 0x15, 0xC0, 472 | 0xDD, 0x34, 0x20, 0xC9, 0x3E, 0x2, 0x32, 0x7A, 0xE9, 0xC9, 0x3E, 473 | 0x1, 0x32, 0x7A, 0xE9, 0xC9, 0x32, 0x7D, 0xE9, 0xDD, 0x7E, 0x21, 474 | 0x57, 0xCB, 0xBA, 0x17, 0xDD, 0x7E, 0x22, 0x17, 0xF5, 0xE6, 0x1F, 475 | 0x4F, 0xF1, 0x17, 0x17, 0x17, 0x17, 0xE6, 0xF, 0x47, 0xDD, 0x7E, 476 | 0x23, 0x1E, 0x6, 0xFE, 0x4, 0x30, 0x72, 0x7, 0x7, 0x7, 0x7, 477 | 0x80, 0x47, 0xDD, 0x72, 0x20, 0xDD, 0x56, 0xE, 0xCB, 0x72, 0x20, 478 | 0xE, 0x79, 0xDD, 0xBE, 0xC, 0x20, 0x8, 0x78, 0xDD, 0xAE, 0xE, 479 | 0xE6, 0x3F, 0x28, 0x4B, 0xCB, 0x7A, 0x20, 0xF, 0xD5, 0xC5, 0xCD, 480 | 0xDC, 0xE5, 0xC1, 0xD1, 0x1E, 0x3, 0x3A, 0x7A, 0xE9, 0x3C, 0x28, 481 | 0x3D, 0xDD, 0x71, 0xC, 0xDD, 0x70, 0xE, 0xCB, 0x7A, 0x20, 0x7, 482 | 0x3E, 0xF, 0xCD, 0xE1, 0xE3, 0x18, 0x9, 0xDD, 0xCB, 0xA, 0x7E, 483 | 0x28, 0xF3, 0xCD, 0x3A, 0xE5, 0x3A, 0x7A, 0xE9, 0x3C, 0x20, 0x15, 484 | 0x3A, 0x7D, 0xE9, 0x1E, 0x4, 0x3C, 0x20, 0x15, 0xCD, 0x62, 0xE6, 485 | 0x1E, 0x5, 0x3A, 0x7A, 0xE9, 0x3C, 0x28, 0xA, 0x18, 0x3, 0xCD, 486 | 0xAF, 0xE5, 0xAF, 0x32, 0x7A, 0xE9, 0xC9, 0xDD, 0x36, 0xE, 0xC0, 487 | 0x7B, 0x32, 0x7A, 0xE9, 0xDD, 0xCB, 0xE, 0xFE, 0xB7, 0xC9, 0x19, 488 | 0x7E, 0x21, 0xC, 0x0, 0x19, 0x57, 0x7E, 0xE6, 0x1F, 0xCB, 0x12, 489 | 0xCE, 0x0, 0x1F, 0xCB, 0x1A, 0x4F, 0x23, 0x23, 0x7E, 0xF, 0xF, 490 | 0xF, 0xF, 0xF5, 0xE6, 0x3, 0x47, 0xF1, 0xE6, 0xF0, 0x81, 0x4F, 491 | 0xD0, 0x4, 0xC9, 0x2A, 0x5C, 0xE9, 0x1, 0x60, 0x0, 0x9, 0x7E, 492 | 0xD6, 0x21, 0xC0, 0x57, 0x19, 0x3A, 0x86, 0xE9, 0xF, 0xF, 0x5F, 493 | 0xF, 0xF, 0x83, 0x5F, 0x19, 0xE5, 0xE, 0x0, 0xCD, 0x24, 0xE9, 494 | 0xD1, 0x1, 0x4, 0x0, 0xED, 0xB0, 0xC9, 0xD5, 0xE, 0x0, 0xCD, 495 | 0x24, 0xE9, 0xD1, 0x1, 0x5, 0x0, 0xED, 0xB0, 0xC9, 0xEB, 0xE, 496 | 0xFF, 0xE5, 0x2A, 0x13, 0xDC, 0xE3, 0xC9, 0x3A, 0x7C, 0xE9, 0xB7, 497 | 0x28, 0xC, 0x3A, 0x7E, 0xE9, 0xDD, 0x77, 0x0, 0x3A, 0x80, 0xE9, 498 | 0xCD, 0x6, 0xE1, 0xDD, 0xE5, 0xD1, 0xDD, 0xE1, 0xED, 0x7B, 0x8F, 499 | 0xE9, 0x2A, 0x7A, 0xE9, 0x3A, 0x79, 0xE9, 0x4F, 0x7D, 0x44, 0xC9, 500 | 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xF0, 0x4, 0xF0, 501 | 0x6, 0xF0, 0x80, 0xEF, 0x70, 0xEF, 0x0, 0x0, 0x0, 0xF1, 0x1A, 502 | 0x0, 0x3, 0x7, 0x0, 0xF2, 0x0, 0x3F, 0x0, 0xC0, 0x0, 0x0, 503 | 0x0, 0x2, 0x0, 0x0, 0x0, 0x1, 0x0, 0x80, 0x0, 0xA, 0x0, 504 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x0, 0x22, 0x0, 505 | 0x40, 0x0, 0x9B, 0xD4, 0x0, 0xF, 0x0, 0x0, 0x0, 0x73, 0xD4, 506 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 507 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 508 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 509 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 510 | 0xE2, 0xE2, 0xFB, 0xE2, 0xB5, 0xE2, 0x2A, 0xDE, 0x50, 0x0, 0x7, 511 | 0xD4, 0x7, 0xD4, 0x2A, 0xE9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 512 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 513 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 514 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 515 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 516 | 0x0, 517 | }; 518 | -------------------------------------------------------------------------------- /cpmdisc.h: -------------------------------------------------------------------------------- 1 | /*-----------------------------------------------------------------------*\ 2 | | Originally by Kevin Kayes, but he refused any responsibility for it. | 3 | | | 4 | | Copyright 1986-1988 by Parag Patel. All Rights Reserved. | 5 | | Copyright 1994 by CodeGen, Inc. All Rights Reserved. | 6 | \*-----------------------------------------------------------------------*/ 7 | 8 | 9 | #define SECTORSIZE 128 10 | #define SECTORSPERTRACK 26 11 | #define TRACKSPERDISC 77 12 | #define SECTOROFFSET 1 13 | #define TRACKOFFSET 0 14 | #define RESERVEDTRACKS 2 15 | #define SECTORSPERBLOCK 8 16 | #define SECTORSPEREXTENT 128 17 | #define EXTENTSIZE 32 18 | #define TOTALEXTENTS 64 19 | 20 | #define EXTENTSPERSECTOR (SECTORSIZE / EXTENTSIZE) 21 | #define TRACKSIZE (long)(SECTORSIZE * SECTORSPERTRACK) 22 | #define DISCSIZE (long)(TRACKSIZE * TRACKSPERDISC) 23 | 24 | unsigned char sectorxlat[] = { 25 | 1, 7, 13, 19, 26 | 25, 5, 11, 17, 27 | 23, 3, 9, 15, 28 | 21, 2, 8, 14, 29 | 20, 26, 6, 12, 30 | 18, 24, 4, 10, 31 | 16, 22 32 | }; 33 | 34 | -------------------------------------------------------------------------------- /defs.h: -------------------------------------------------------------------------------- 1 | /*-----------------------------------------------------------------------*\ 2 | | defs.h -- main definitions for z80 emulator | 3 | | | 4 | | Copyright 1986-1988 by Parag Patel. All Rights Reserved. | 5 | | Copyright 1994-1995 by CodeGen, Inc. All Rights Reserved. | 6 | \*-----------------------------------------------------------------------*/ 7 | 8 | #ifndef __DEFS_H_ 9 | #define __DEFS_H_ 10 | 11 | #include 12 | 13 | /* the current version of the z80 emulator */ 14 | #define VERSION "3.1" 15 | 16 | 17 | /* system definitions */ 18 | #if defined THINK_C || defined applec || defined macintosh 19 | # ifndef macintosh 20 | # define macintosh 21 | # endif 22 | #elif defined __MWERKS__ 23 | # define BeBox 24 | #elif defined MSDOS && defined GO32 25 | # define DJGPP 26 | # ifndef LITTLE_ENDIAN 27 | # define LITTLE_ENDIAN 28 | # endif 29 | #else 30 | # define UNIX /* cannot use "unix" since DJGPP defines it as well */ 31 | #endif 32 | 33 | 34 | /* some headers define macros this way */ 35 | #ifdef BYTE_ORDER 36 | # if BYTE_ORDER == LITTLE_ENDIAN 37 | # undef BIG_ENDIAN 38 | # else 39 | # undef LITTLE_ENDIAN 40 | # endif 41 | #endif 42 | 43 | 44 | /* misc. handy defs */ 45 | 46 | #ifndef TRUE 47 | #define TRUE 1 48 | #endif 49 | 50 | #ifndef FALSE 51 | #define FALSE 0 52 | #endif 53 | 54 | typedef int boolean; 55 | 56 | 57 | #define CNTL(c) ((c) & 037) /* convert a char to its control equivalent */ 58 | 59 | 60 | /* handy typedefs for an 8-bit byte, 16-bit word, & 32-bit longword */ 61 | 62 | typedef unsigned char byte; 63 | typedef unsigned short word; 64 | typedef unsigned long longword; 65 | 66 | 67 | /* handy bit definitions - bit fields are not used as they are generally 68 | much slower than the equivalent logical masking operations */ 69 | 70 | #define BIT16 0x10000L 71 | #define BIT15 0x8000 72 | #define BIT14 0x4000 73 | #define BIT13 0x2000 74 | #define BIT12 0x1000 75 | #define BIT11 0x0800 76 | #define BIT10 0x0400 77 | #define BIT9 0x0200 78 | #define BIT8 0x0100 79 | #define BIT7 0x0080 80 | #define BIT6 0x0040 81 | #define BIT5 0x0020 82 | #define BIT4 0x0010 83 | #define BIT3 0x0008 84 | #define BIT2 0x0004 85 | #define BIT1 0x0002 86 | #define BIT0 0x0001 87 | 88 | /* handy masks to get a particular number of bits out */ 89 | 90 | #define MASK1 0x01 91 | #define MASK2 0x03 92 | #define MASK3 0x07 93 | #define MASK4 0x0F 94 | #define MASK5 0x1F 95 | #define MASK6 0x3F 96 | #define MASK7 0x7F 97 | #define MASK8 0xFF 98 | 99 | #define MASKU4 0xF0 100 | #define MASK16 0xFFFF 101 | 102 | 103 | /* z80 flag register definitions */ 104 | 105 | #define SIGN 0x80 106 | #define ZERO 0x40 107 | #define HALF 0x10 108 | #define PARITY 0x04 109 | #define OVERFLOW PARITY 110 | #define NEGATIVE 0x02 111 | #define CARRY 0x01 112 | 113 | 114 | /* z80 interrupt types - used to set the intr struct var */ 115 | 116 | #define INTRMASK 0xF00 117 | #define INT_FLAG 0x100 118 | #define NM_FLAG 0x200 119 | #define RESET_FLAG 0x400 120 | 121 | 122 | /* max number of the BIOS drive tables */ 123 | #define MAXDISCS 16 124 | 125 | 126 | typedef struct z80info 127 | { 128 | boolean event; 129 | byte regaf[2], regbc[2], regde[2], reghl[2]; 130 | word regaf2, regbc2, regde2, reghl2; 131 | word regsp, regpc, regix, regiy; 132 | byte regi, regr; 133 | byte iff, iff2, imode; 134 | byte reset, nmi, intr, halt; 135 | 136 | /* these point to the addresses of the above registers */ 137 | byte *reg[8]; 138 | word *regpairaf[4]; 139 | word *regpairsp[4]; 140 | word *regpairxy[4]; 141 | word *regixy[2]; 142 | byte *regir[2]; 143 | 144 | /* these are for the I/O, CP/M, and outside needs */ 145 | boolean trace; /* trace mode off/on */ 146 | boolean step; /* step-trace mode off/on */ 147 | int sig; /* caught a signal */ 148 | int syscall; /* CP/M syscall to be done */ 149 | int biosfn; /* BIOS function be done */ 150 | 151 | /* these are for the CP/M BIOS */ 152 | int drive; 153 | word dma; 154 | word track; 155 | word sector; 156 | FILE *drives[MAXDISCS]; 157 | long drivelen[MAXDISCS]; 158 | 159 | /* 64k bytes - may be allocated separately if desired */ 160 | byte mem[0x10000L]; 161 | 162 | #ifdef MEM_BREAK 163 | /* one for each byte of memory for breaks, memory-mapped I/O, etc */ 164 | byte membrk[0x10000L]; 165 | long numbrks; 166 | #endif 167 | } z80info; 168 | 169 | 170 | /* All the following macros assume that a variable named "z80" is 171 | available to access the above info. This is to allow multiple 172 | z80s to run without stepping on each other. 173 | */ 174 | 175 | 176 | /* These macros allow memory-mapped I/O if MEM_BREAK is defined. 177 | Because of this, these macros must be very carefully used, and 178 | there must not be ANY side-effects, such as increment/decerement 179 | in any of the macro args. Customizations go into read_mem() and 180 | write_mem(). 181 | */ 182 | 183 | #ifdef MEM_BREAK 184 | # define MEM(addr) \ 185 | (z80->membrk[(word)(addr)] ? \ 186 | read_mem(z80, addr) : \ 187 | z80->mem[(word)(addr)]) 188 | # define SETMEM(addr, val) \ 189 | (z80->membrk[(word)(addr)] ? \ 190 | write_mem(z80, addr, val) : \ 191 | (z80->mem[(word)(addr)] = (byte)(val))) 192 | 193 | /* various flags for "membrk" - others may be added */ 194 | # define M_BREAKPOINT 0x01 /* breakpoint */ 195 | # define M_READ_PROTECT 0x02 /* read-protected memory */ 196 | # define M_WRITE_PROTECT 0x04 /* write-protected memory */ 197 | # define M_MEM_MAPPED_IO 0x08 /* memory-mapped I/O addr */ 198 | 199 | #else 200 | # define MEM(addr) z80->mem[(word)(addr)] 201 | # define SETMEM(addr, val) (z80->mem[(word)(addr)] = (byte)(val)) 202 | #endif 203 | 204 | 205 | /* how to access the z80 registers & register pairs */ 206 | 207 | #ifdef LITTLE_ENDIAN 208 | # define A z80->regaf[1] 209 | # define F z80->regaf[0] 210 | # define B z80->regbc[1] 211 | # define C z80->regbc[0] 212 | # define D z80->regde[1] 213 | # define E z80->regde[0] 214 | # define H z80->reghl[1] 215 | # define L z80->reghl[0] 216 | #else 217 | # define A z80->regaf[0] 218 | # define F z80->regaf[1] 219 | # define B z80->regbc[0] 220 | # define C z80->regbc[1] 221 | # define D z80->regde[0] 222 | # define E z80->regde[1] 223 | # define H z80->reghl[0] 224 | # define L z80->reghl[1] 225 | #endif 226 | 227 | #define I z80->regi 228 | #define R z80->regr 229 | #define AF (*(word *)z80->regaf) 230 | #define BC (*(word *)z80->regbc) 231 | #define DE (*(word *)z80->regde) 232 | #define HL (*(word *)z80->reghl) 233 | #define AF2 z80->regaf2 234 | #define BC2 z80->regbc2 235 | #define DE2 z80->regde2 236 | #define HL2 z80->reghl2 237 | #define SP z80->regsp 238 | #define PC z80->regpc 239 | #define IX z80->regix 240 | #define IY z80->regiy 241 | #define IFF z80->iff 242 | #define IFF2 z80->iff2 243 | #define IMODE z80->imode 244 | #define RESET z80->reset 245 | #define NMI z80->nmi 246 | #define INTR z80->intr 247 | #define HALT z80->halt 248 | 249 | #define EVENT z80->event 250 | 251 | 252 | /* function externs: */ 253 | 254 | /* z80.c */ 255 | extern z80info *new_z80info(void); 256 | extern z80info *init_z80info(z80info *z80); 257 | extern z80info *destroy_z80info(z80info *z80); 258 | extern void delete_z80info(z80info *z80); 259 | 260 | extern boolean z80_emulator(z80info *z80, int count); 261 | 262 | /* main.c */ 263 | extern void resetterm(void); 264 | extern void setterm(void); 265 | extern boolean input(z80info *z80, byte haddr, byte laddr, byte *val); 266 | extern void output(z80info *z80, byte haddr, byte laddr, byte data); 267 | extern void haltcpu(z80info *z80); 268 | extern word read_mem(z80info *z80, word addr); 269 | extern word write_mem(z80info *z80, word addr, byte val); 270 | extern void undefinstr(z80info *z80, byte instr); 271 | extern boolean loadfile(z80info *z80, const char *fname); 272 | 273 | /* bios.c */ 274 | extern void bios(z80info *z80, int fn); 275 | extern void sysreset(z80info *z80); 276 | 277 | /* disassem.c */ 278 | extern int disassemlen(z80info *z80); 279 | extern int disassem(z80info *z80, word start, FILE *fp); 280 | 281 | #endif /* __DEFS_H_ */ 282 | -------------------------------------------------------------------------------- /disassem.c: -------------------------------------------------------------------------------- 1 | /*-----------------------------------------------------------------------*\ 2 | | disassem.c -- Z80 disassembler | 3 | | | 4 | | Originally by T.J. Merritt but modified and debugged to run in the | 5 | | Z80 emulator instead of being standalone. | 6 | | | 7 | | Copyright 1986-1988 by Parag Patel. All Rights Reserved. | 8 | | Copyright 1994-1995 by CodeGen, Inc. All Rights Reserved. | 9 | \*-----------------------------------------------------------------------*/ 10 | 11 | 12 | #include 13 | #include 14 | #include "defs.h" 15 | 16 | 17 | #define bits(l,r) (((z80->mem[loc]) >> (r)) & mask[(l) - (r)]) 18 | #define put_cc(cc) put_str(cc_names[cc]) 19 | 20 | #define OPC_LD "LD " 21 | #define OPC_INC "INC " 22 | #define OPC_DEC "DEC " 23 | #define OPC_ADD "ADD " 24 | #define OPC_RET "RET " 25 | #define OPC_POP "POP " 26 | #define OPC_EXX "EXX " 27 | #define OPC_JP "JP " 28 | #define OPC_OUT "OUT " 29 | #define OPC_IN "IN " 30 | #define OPC_EX "EX " 31 | #define OPC_DI "DI " 32 | #define OPC_EI "EI " 33 | #define OPC_CALL "CALL " 34 | #define OPC_PUSH "PUSH " 35 | #define OPC_ILLEGAL "***" 36 | #define OPC_RST "RST " 37 | 38 | static int 39 | mask[] = 40 | { 41 | 0x001, 42 | 0x003, 43 | 0x007, 44 | 0x00F, 45 | 0x01F, 46 | 0x03F, 47 | 0x07F, 48 | 0x0FF 49 | }; 50 | 51 | static char * 52 | rr_names[] = 53 | { 54 | "B", 55 | "C", 56 | "D", 57 | "E", 58 | "H", 59 | "L", 60 | "(HL)", 61 | "A" 62 | }; 63 | 64 | static char * 65 | dd_names[] = 66 | { 67 | "BC", 68 | "DE", 69 | "HL", 70 | "SP" 71 | }; 72 | 73 | static char * 74 | qq_names[] = 75 | { 76 | "BC", 77 | "DE", 78 | "HL", 79 | "AF" 80 | }; 81 | 82 | static char * 83 | cc_names[] = 84 | { 85 | "NZ", 86 | "Z", 87 | "NC", 88 | "C", 89 | "PO", 90 | "PE", 91 | "P", 92 | "M" 93 | }; 94 | 95 | static char * 96 | op_names[] = 97 | { 98 | "ADD A,", 99 | "ADC A,", 100 | "SUB ", 101 | "SBC A,", 102 | "AND ", 103 | "XOR ", 104 | "OR ", 105 | "CP ", 106 | }; 107 | 108 | static char * 109 | jr_op_names[] = 110 | { 111 | 0, 112 | 0, 113 | "DJNZ ", 114 | "JR ", 115 | "JR NZ,", 116 | "JR Z,", 117 | "JR NC,", 118 | "JR C," 119 | }; 120 | 121 | static char * 122 | log_op_names[] = 123 | { 124 | "RLCA", 125 | "RRCA", 126 | "RLA", 127 | "RRA", 128 | "DAA", 129 | "CPL", 130 | "SCF", 131 | "CCF" 132 | }; 133 | 134 | static char * 135 | shf_op_names[] = 136 | { 137 | "RLC ", 138 | "RRC ", 139 | "RL ", 140 | "RR ", 141 | "SLA ", 142 | "SRA ", 143 | "SLL? ", 144 | "SRL " 145 | }; 146 | 147 | static char * 148 | bit_op_names[] = 149 | { 150 | 0, 151 | "BIT ", 152 | "RES ", 153 | "SET ", 154 | }; 155 | 156 | static char * 157 | rep_op_names[] = 158 | { 159 | "LDI", 160 | "CPI", 161 | "INI", 162 | "OUTI", 163 | "LDD", 164 | "CPD", 165 | "IND", 166 | "OUTD", 167 | "LDIR", 168 | "CPIR", 169 | "INIR", 170 | "OTIR", 171 | "LDDR", 172 | "CPDR", 173 | "INDR", 174 | "OTDR" 175 | }; 176 | 177 | static char *index_reg; 178 | static int str_length; 179 | static FILE *fp; 180 | 181 | static void 182 | put_byte(byte b) 183 | { 184 | fprintf(fp, "%02X", b & 0x0FF); 185 | str_length += 2; 186 | } 187 | 188 | static void 189 | put_addr(z80info *z80, int loc) 190 | { 191 | put_byte(z80->mem[loc]); 192 | put_byte(z80->mem[(loc - 1) & 0x0FFFF]); 193 | } 194 | 195 | static void 196 | put_word(word w) 197 | { 198 | fprintf(fp, "%04X", w & 0x0FFFF); 199 | str_length += 4; 200 | } 201 | 202 | static void 203 | put_digit(byte digit) 204 | { 205 | fprintf(fp, "%01X", digit & 0x00F); 206 | str_length += 1; 207 | } 208 | 209 | static void 210 | put_char(char ch) 211 | { 212 | putc(ch, fp); 213 | str_length += 1; 214 | } 215 | 216 | static void 217 | put_str(char *str) 218 | { 219 | fprintf(fp, "%s", str); 220 | str_length += strlen(str); 221 | } 222 | 223 | static void 224 | put_reg(z80info *z80, int reg_num, int loc) 225 | { 226 | int d; 227 | 228 | if (index_reg && (reg_num == 6)) 229 | { 230 | put_str("("); 231 | put_str(index_reg); 232 | d = (signed char)z80->mem[loc + 1]; 233 | 234 | if (d < 0) 235 | { 236 | put_str("-"); 237 | put_byte(-d); 238 | } 239 | else 240 | { 241 | put_str("+"); 242 | put_byte(d); 243 | } 244 | 245 | put_str(")"); 246 | } 247 | else 248 | { 249 | put_str(rr_names[reg_num]); 250 | } 251 | } 252 | 253 | static void 254 | put_dd_reg(int reg_num) 255 | { 256 | if (index_reg) 257 | { 258 | if (reg_num == 2) 259 | put_str(index_reg); 260 | else if (reg_num == 3) 261 | put_str("SP"); 262 | else 263 | put_str(OPC_ILLEGAL); 264 | } 265 | else 266 | put_str(dd_names[reg_num]); 267 | } 268 | 269 | static void 270 | put_qq_reg(int reg_num) 271 | { 272 | if (index_reg) 273 | { 274 | if (reg_num == 2) 275 | put_str(index_reg); 276 | else 277 | put_str(OPC_ILLEGAL); 278 | } 279 | else 280 | put_str(qq_names[reg_num]); 281 | } 282 | 283 | int 284 | disassemlen(z80info *z80) 285 | { 286 | return str_length; 287 | } 288 | 289 | int 290 | disassem(z80info *z80, word start, FILE *file) 291 | { 292 | word loc; 293 | int byte_count; 294 | byte last_byte; 295 | 296 | loc = start; 297 | byte_count = 0; 298 | str_length = 0; 299 | 300 | if (file != NULL) 301 | { 302 | fp = file; 303 | index_reg = NULL; 304 | } 305 | 306 | switch (bits(7,6)) 307 | { 308 | case 0: 309 | switch (bits(3,0)) 310 | { 311 | case 0: 312 | case 8: 313 | if (bits(5,3) == 0) 314 | { 315 | put_str("NOP"); 316 | break; 317 | } 318 | 319 | if (bits(5,3) == 1) 320 | { 321 | put_str("EX AF,AF'"); 322 | break; 323 | } 324 | 325 | put_str(jr_op_names[bits(5,3)]); 326 | loc++; 327 | byte_count++; 328 | put_word((signed char)z80->mem[loc] + (int)loc + 1); 329 | break; 330 | 331 | case 1: 332 | put_str(OPC_LD); 333 | put_dd_reg(bits(5,4)); 334 | put_char(','); 335 | byte_count += 2; 336 | loc += 2; 337 | put_addr(z80, loc); 338 | break; 339 | 340 | case 2: 341 | last_byte = z80->mem[loc]; 342 | put_str(OPC_LD); 343 | 344 | switch (bits(5,4)) 345 | { 346 | case 0: 347 | put_str("(BC)"); 348 | break; 349 | 350 | case 1: 351 | put_str("(DE)"); 352 | break; 353 | 354 | case 2: 355 | case 3: 356 | put_char('('); 357 | byte_count += 2; 358 | loc += 2; 359 | put_addr(z80, loc); 360 | put_char(')'); 361 | break; 362 | } 363 | 364 | if ((last_byte & 0x030) == 0x020) 365 | { 366 | put_char(','); 367 | 368 | if (index_reg) 369 | put_str(index_reg); 370 | else 371 | put_str("HL"); 372 | } 373 | else 374 | { 375 | put_str(",A"); 376 | } 377 | 378 | break; 379 | 380 | case 3: 381 | put_str(OPC_INC); 382 | put_dd_reg(bits(5,4)); 383 | break; 384 | 385 | case 4: 386 | case 0x0C: 387 | put_str(OPC_INC); 388 | put_reg(z80, bits(5,3), loc); 389 | break; 390 | 391 | case 5: 392 | case 0x0D: 393 | put_str(OPC_DEC); 394 | put_reg(z80, bits(5,3), loc); 395 | break; 396 | 397 | case 6: 398 | case 0x0E: 399 | put_str(OPC_LD); 400 | put_reg(z80, bits(5,3), loc); 401 | put_char(','); 402 | 403 | if (index_reg && (bits(5,3) == 6)) 404 | { 405 | loc++; 406 | byte_count++; 407 | } 408 | 409 | loc++; 410 | byte_count++; 411 | put_byte(z80->mem[loc]); 412 | break; 413 | 414 | case 7: 415 | case 0x0F: 416 | put_str(log_op_names[bits(5,3)]); 417 | break; 418 | 419 | case 9: 420 | put_str(OPC_ADD); 421 | put_str("HL,"); 422 | put_dd_reg(bits(5,4)); 423 | break; 424 | 425 | case 0x0A: 426 | put_str(OPC_LD); 427 | 428 | if (bits(5,4) == 2) 429 | { 430 | if (index_reg) 431 | { 432 | put_str(index_reg); 433 | put_str(","); 434 | } 435 | else 436 | put_str("HL,"); 437 | } 438 | else 439 | { 440 | put_str("A,"); 441 | } 442 | 443 | switch (bits(5,4)) 444 | { 445 | case 0: 446 | put_str("(BC)"); 447 | break; 448 | 449 | case 1: 450 | put_str("(DE)"); 451 | break; 452 | 453 | case 2: 454 | case 3: 455 | put_char('('); 456 | byte_count += 2; 457 | loc += 2; 458 | put_addr(z80, loc); 459 | put_char(')'); 460 | break; 461 | } 462 | 463 | break; 464 | 465 | case 0x0B: 466 | put_str(OPC_DEC); 467 | put_dd_reg(bits(5,4)); 468 | break; 469 | } 470 | 471 | break; 472 | 473 | case 1: 474 | /* if ((bits(5,3) != 6) && (bits(2,0) != 6)) */ 475 | if (z80->mem[loc] == 0x76) 476 | { 477 | put_str("HALT"); 478 | } 479 | else 480 | { 481 | put_str(OPC_LD); 482 | put_reg(z80, bits(5,3), loc); 483 | put_char(','); 484 | put_reg(z80, bits(2,0), loc); 485 | } 486 | 487 | break; 488 | 489 | case 2: 490 | put_str(op_names[bits(5,3)]); 491 | put_reg(z80, bits(2,0), loc); 492 | break; 493 | 494 | case 3: 495 | if (z80->mem[loc] == 0xCB) 496 | { 497 | loc++; 498 | byte_count++; 499 | 500 | if (bits(7,6) == 0) 501 | { 502 | put_str(shf_op_names[bits(5,3)]); 503 | } 504 | else 505 | { 506 | put_str(bit_op_names[bits(7,6)]); 507 | put_digit(bits(5,3)); 508 | put_char(','); 509 | } 510 | 511 | put_reg(z80, bits(2,0), loc); 512 | break; 513 | } 514 | 515 | /*if ((z80->mem[loc] & 0x0DD) == 0x0DD)*/ 516 | if (z80->mem[loc] == 0xDD) 517 | { 518 | if (bits(5,5)) 519 | index_reg = "IY"; 520 | else 521 | index_reg = "IX"; 522 | 523 | byte_count = disassem(z80, loc + 1, NULL); 524 | loc += byte_count; 525 | 526 | break; 527 | } 528 | 529 | if (z80->mem[loc] == 0xED) 530 | { 531 | loc++; 532 | byte_count++; 533 | 534 | switch (bits(7,6)) 535 | { 536 | case 0: 537 | put_str(OPC_ILLEGAL); 538 | break; 539 | 540 | case 1: 541 | switch (bits(3,0)) 542 | { 543 | case 0: 544 | case 8: 545 | put_str("IN "); 546 | put_reg(z80, bits(5,3), loc); 547 | put_str(",[C]"); 548 | break; 549 | 550 | case 1: 551 | case 9: 552 | put_str("OUT [C],"); 553 | put_reg(z80, bits(5,3), loc); 554 | break; 555 | 556 | case 2: 557 | put_str("SBC HL,"); 558 | put_dd_reg(bits(5,4)); 559 | break; 560 | 561 | case 0xA: 562 | put_str("ADC HL,"); 563 | put_dd_reg(bits(5,4)); 564 | break; 565 | 566 | case 3: 567 | put_str(OPC_LD); 568 | put_char('('); 569 | put_addr(z80, loc + 2); 570 | put_str("),"); 571 | put_dd_reg(bits(5,4)); 572 | byte_count += 2; 573 | loc += 2; 574 | break; 575 | 576 | case 0xB: 577 | put_str(OPC_LD); 578 | put_dd_reg(bits(5,4)); 579 | put_str(",("); 580 | byte_count += 2; 581 | loc += 2; 582 | put_addr(z80, loc); 583 | put_char(')'); 584 | break; 585 | 586 | case 4: 587 | if (bits(5,4) == 0) 588 | put_str("NEG"); 589 | else 590 | put_str(OPC_ILLEGAL); 591 | 592 | break; 593 | 594 | case 0xC: 595 | put_str(OPC_ILLEGAL); 596 | break; 597 | 598 | case 5: 599 | if (bits(5,4) == 0) 600 | put_str("RETN"); 601 | else 602 | put_str(OPC_ILLEGAL); 603 | 604 | break; 605 | 606 | case 0xD: 607 | if (bits(5,4) == 0) 608 | put_str("RETI"); 609 | else 610 | put_str(OPC_ILLEGAL); 611 | 612 | break; 613 | 614 | case 6: 615 | if (bits(5,4) == 0) 616 | put_str("IM 0"); 617 | else if (bits(5,4) == 1) 618 | put_str("IM 1"); 619 | else 620 | put_str(OPC_ILLEGAL); 621 | 622 | break; 623 | 624 | case 0xE: 625 | if (bits(5,4) == 1) 626 | put_str("IM 2"); 627 | else 628 | put_str(OPC_ILLEGAL); 629 | break; 630 | 631 | case 7: 632 | if (bits(5,4) == 0) 633 | put_str("LD I,A"); 634 | else if (bits(5,4) == 1) 635 | put_str("LD A,I"); 636 | else if (bits(5,4) == 2) 637 | put_str("RRD"); 638 | else 639 | put_str(OPC_ILLEGAL); 640 | 641 | break; 642 | 643 | case 0xF: 644 | if (bits(5,4) == 0) 645 | put_str("LD R,A"); 646 | else if (bits(5,4) == 1) 647 | put_str("LD A,R"); 648 | else if (bits(5,4) == 2) 649 | put_str("RLD"); 650 | else 651 | put_str(OPC_ILLEGAL); 652 | 653 | break; 654 | } 655 | 656 | break; 657 | 658 | case 2: 659 | if (bits(5,5) == 0) 660 | { 661 | put_str(OPC_ILLEGAL); 662 | break; 663 | } 664 | 665 | if (bits(2,2) == 1) 666 | { 667 | put_str(OPC_ILLEGAL); 668 | break; 669 | } 670 | 671 | put_str(rep_op_names[ 672 | ((z80->mem[loc] >> 1) & 0xC) 673 | | (z80->mem[loc] & 3) 674 | ]); 675 | break; 676 | 677 | case 3: 678 | put_str(OPC_ILLEGAL); 679 | break; 680 | } 681 | 682 | break; 683 | } 684 | 685 | if ((z80->mem[loc] & 0x06) == 0x06) 686 | { 687 | put_str(op_names[bits(5,3)]); 688 | loc++; 689 | byte_count++; 690 | put_byte(z80->mem[loc]); 691 | break; 692 | } 693 | 694 | switch (bits(2,0)) 695 | { 696 | case 0: 697 | put_str(OPC_RET); 698 | put_cc(bits(5,3)); 699 | break; 700 | 701 | case 1: 702 | switch (bits(5,3)) 703 | { 704 | case 0: 705 | case 2: 706 | case 4: 707 | case 6: 708 | put_str(OPC_POP); 709 | put_qq_reg(bits(5,4)); 710 | break; 711 | 712 | case 1: 713 | put_str(OPC_RET); 714 | break; 715 | 716 | case 3: 717 | put_str(OPC_EXX); 718 | break; 719 | 720 | case 5: 721 | put_str(OPC_JP); 722 | 723 | if (index_reg) 724 | { 725 | put_str("("); 726 | put_str( index_reg); 727 | put_str(")"); 728 | } 729 | else 730 | put_str("(HL)"); 731 | 732 | break; 733 | 734 | case 7: 735 | put_str(OPC_LD); 736 | put_str("SP,"); 737 | 738 | if (index_reg) 739 | put_str(index_reg); 740 | else 741 | put_str("HL"); 742 | 743 | break; 744 | } 745 | 746 | break; 747 | 748 | case 2: 749 | put_str(OPC_JP); 750 | put_cc(bits(5,3)); 751 | put_char(','); 752 | byte_count += 2; 753 | loc += 2; 754 | put_addr(z80, loc); 755 | break; 756 | 757 | case 3: 758 | switch (bits(5,3)) 759 | { 760 | case 0: 761 | put_str(OPC_JP); 762 | byte_count += 2; 763 | loc += 2; 764 | put_addr(z80, loc); 765 | break; 766 | 767 | case 2: 768 | loc++; 769 | byte_count++; 770 | put_str(OPC_OUT); 771 | put_char('('); 772 | put_byte(z80->mem[loc]); 773 | put_str("),A"); 774 | break; 775 | 776 | case 3: 777 | loc++; 778 | byte_count++; 779 | put_str(OPC_IN); 780 | put_str("A,("); 781 | put_byte(z80->mem[loc]); 782 | put_char(')'); 783 | break; 784 | 785 | case 4: 786 | put_str(OPC_EX); 787 | put_str("(SP),"); 788 | 789 | if (index_reg) 790 | put_str(index_reg); 791 | else 792 | put_str("HL"); 793 | 794 | break; 795 | 796 | case 5: 797 | put_str(OPC_EX); 798 | put_str("HL,DE"); 799 | break; 800 | 801 | case 6: 802 | put_str(OPC_DI); 803 | break; 804 | 805 | case 7: 806 | put_str(OPC_EI); 807 | break; 808 | } 809 | 810 | break; 811 | 812 | case 4: 813 | put_str(OPC_CALL); 814 | put_cc(bits(5,3)); 815 | put_char(','); 816 | byte_count += 2; 817 | loc += 2; 818 | put_addr(z80, loc); 819 | break; 820 | 821 | case 5: 822 | if (bits(3,3)) 823 | { 824 | put_str(OPC_CALL); 825 | byte_count += 2; 826 | loc += 2; 827 | put_addr(z80, loc); 828 | } 829 | else 830 | { 831 | put_str(OPC_PUSH); 832 | put_qq_reg(bits(5,4)); 833 | } 834 | 835 | break; 836 | 837 | case 6: 838 | put_str(OPC_ILLEGAL); 839 | break; 840 | 841 | case 7: 842 | put_str(OPC_RST); 843 | put_byte(z80->mem[loc] & 0x038); 844 | break; 845 | } 846 | 847 | break; 848 | } 849 | 850 | loc++; 851 | byte_count++; 852 | return byte_count; 853 | } 854 | -------------------------------------------------------------------------------- /getunix.mac: -------------------------------------------------------------------------------- 1 | ; GET UNIX FILE INTO CP/M UTILITY 2 | ; getunix unixfilename.extension driveletter:cpmfilename.extension 3 | ; 4 | .Z80 5 | 6 | SRCFCB EQU 005CH 7 | SECFCB EQU 006CH 8 | 9 | CBIOS EQU 0EA00H 10 | OPNUNX EQU CBIOS+33H 11 | RDUNX EQU CBIOS+39H 12 | CLSUNX EQU CBIOS+3FH 13 | 14 | BDOS EQU 5 15 | CREATE EQU 22 16 | WRITE EQU 21 17 | CLOSE EQU 16 18 | SETDMA EQU 26 19 | PRINT EQU 9 20 | 21 | CSEG 22 | ENTRY START 23 | START: 24 | LD SP,STACK 25 | ;MOVE DESTINATION FCB 26 | LD HL,SECFCB 27 | LD DE,DSTFCB 28 | LD BC,10H 29 | LDIR 30 | LD HL,DSTFCB+16 31 | LD DE,DSTFCB+17 32 | LD (HL),0 33 | LD BC,20H 34 | LDIR 35 | ;OPEN SOURCE FILE 36 | LD DE,SRCFCB 37 | CALL OPNUNX 38 | AND A 39 | JP NZ,ERROR1 40 | ;CREATE DESTINATION FILE 41 | LD DE,DSTFCB 42 | LD C,CREATE 43 | CALL BDOS 44 | CP 0FFH 45 | JP Z,ERROR2 46 | ;SET DMA ADDRESS 47 | LD DE,0080H 48 | LD C,SETDMA 49 | CALL BDOS 50 | ;READ ONE, WRITE ONE 51 | LOOP: LD DE,SRCFCB 52 | CALL RDUNX 53 | AND A 54 | JP NZ,CLOSEM 55 | LD DE,DSTFCB 56 | LD C,WRITE 57 | CALL BDOS 58 | AND A 59 | JP NZ,ERROR4 60 | JP LOOP 61 | ;CLOSE UNIX FILE 62 | CLOSEM: LD DE,SRCFCB 63 | CALL CLSUNX 64 | AND A 65 | JP Z,CLSCPM 66 | 67 | CLSCPM: LD DE,DSTFCB 68 | LD C,CLOSE 69 | CALL BDOS 70 | JP 0 71 | 72 | ERROR1: LD DE,STR1 73 | JP ERROR 74 | STR1: DEFM "ERROR1" 75 | DEFB 13,10,'$' 76 | ERROR2: LD DE,STR2 77 | JP ERROR 78 | STR2: DEFM "ERROR2" 79 | DEFB 13,10,'$' 80 | ERROR3: LD DE,STR3 81 | JP ERROR 82 | STR3: DEFM "ERROR3" 83 | DEFB 13,10,'$' 84 | ERROR4: LD DE,STR4 85 | JP ERROR 86 | STR4: DEFM "ERROR4" 87 | DEFB 13,10,'$' 88 | 89 | ERROR: LD C,PRINT 90 | CALL BDOS 91 | JP 0 92 | 93 | DSTFCB: DEFS 200 94 | STACK: DEFS 1 95 | END 96 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /*-----------------------------------------------------------------------*\ 2 | | main.c -- main driver program for the z80 emulator -- all I/O | 3 | | to the Unix world is done from this file -- "z80.c" calls various | 4 | | functions within this file | 5 | | | 6 | | Copyright 1986-1988 by Parag Patel. All Rights Reserved. | 7 | | Copyright 1994-1995 by CodeGen, Inc. All Rights Reserved. | 8 | \*-----------------------------------------------------------------------*/ 9 | 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "defs.h" 20 | 21 | #if defined macintosh 22 | # include 23 | # include 24 | # ifdef THINK_C 25 | # include 26 | # endif 27 | #elif defined DJGPP 28 | # include 29 | #else /* UNIX */ 30 | # include 31 | # include 32 | # if defined POSIX_TTY 33 | # include 34 | # elif defined BeBox 35 | # include 36 | # else 37 | # include 38 | # endif 39 | #endif 40 | 41 | #define INTR_CHAR 31 /* control-underscore */ 42 | 43 | extern int errno; 44 | 45 | 46 | /* globally visible vars */ 47 | static FILE *logfile = NULL; 48 | 49 | 50 | #if defined UNIX || defined BeBox 51 | #ifdef POSIX_TTY 52 | # define termio termios 53 | # define TCSETAW TIOCSETAW 54 | # define TCGETA TIOCGETA 55 | #endif 56 | static struct termio rawterm, oldterm; /* for raw terminal I/O */ 57 | static int keybd = -1; /* to check keyboard for data */ 58 | #endif 59 | 60 | 61 | static void dumptrace(z80info *z80); 62 | 63 | 64 | 65 | /*-----------------------------------------------------------------------*\ 66 | | resetterm -- reset terminal characteristics to original settings 67 | \*-----------------------------------------------------------------------*/ 68 | 69 | void 70 | resetterm(void) 71 | { 72 | #ifdef TCSETAW 73 | ioctl(0, TCSETAW, &oldterm); 74 | #endif 75 | } 76 | 77 | 78 | 79 | /*-----------------------------------------------------------------------*\ 80 | | setterm -- set terminal characteristics to raw mode 81 | \*-----------------------------------------------------------------------*/ 82 | 83 | void 84 | setterm(void) 85 | { 86 | #ifdef TCSETAW 87 | ioctl(0, TCSETAW, &rawterm); 88 | #endif 89 | } 90 | 91 | 92 | 93 | /*-----------------------------------------------------------------------*\ 94 | | initterm -- initialize terminal stuff -- called once on startup 95 | | and then after returning from a sub-shell 96 | \*-----------------------------------------------------------------------*/ 97 | 98 | static void 99 | initterm(void) 100 | { 101 | #ifdef TCGETA 102 | /* try to setup the terminal into raw mode */ 103 | if (ioctl(0, TCGETA, &oldterm) < 0 104 | || ioctl(1, TCGETA, &oldterm) < 0) 105 | { 106 | fprintf(stderr, "Sorry. Must be using a terminal.\n"); 107 | exit(1); 108 | } 109 | 110 | rawterm = oldterm; 111 | /* rawterm.c_lflag &= ~(ISIG | ICANON | ECHO); */ 112 | rawterm.c_lflag &= ~(ICANON | ECHO); 113 | #ifdef IENQAK 114 | rawterm.c_iflag &= ~(IENQAK | IXON | IXOFF | INLCR | ICRNL); 115 | #else 116 | rawterm.c_iflag &= ~(IXON | IXOFF | INLCR | ICRNL); 117 | #endif 118 | rawterm.c_oflag &= ~OPOST; 119 | rawterm.c_cc[VINTR] = INTR_CHAR; 120 | rawterm.c_cc[VQUIT] = -1; 121 | rawterm.c_cc[VERASE] = -1; 122 | rawterm.c_cc[VKILL] = -1; 123 | rawterm.c_cc[VMIN] = 1; /* MIN number of chars */ 124 | rawterm.c_cc[VTIME] = 0; /* TIME timeout value */ 125 | #endif 126 | } 127 | 128 | 129 | 130 | 131 | /*-----------------------------------------------------------------------*\ 132 | | command -- called when user-level commands are needed by the z80 133 | | for some reason or another 134 | \*-----------------------------------------------------------------------*/ 135 | 136 | static void 137 | command(z80info *z80) 138 | { 139 | int i, j, t, e; 140 | char str[256], *s; 141 | FILE *fp; 142 | static word pe = 0; 143 | static word po = 0; 144 | 145 | resetterm(); 146 | printf("\n"); 147 | 148 | loop: /* "infinite" loop */ 149 | 150 | /* prompt for a command from the user & then do it */ 151 | printf("Cmd: "); 152 | fflush(stdout); 153 | *str = '\0'; 154 | fgets(str, sizeof str - 1, stdin); 155 | 156 | for (s = str; *s == ' ' || *s == '\t'; s++) 157 | ; 158 | 159 | switch (isupper(*s) ? tolower(*s) : *s) 160 | { 161 | case '?': /* help */ 162 | printf(" Q(uit) T(race on/off) S(tep trace) D(ump regs)\n"); 163 | printf(" E(xamine memory) P(oke memory) R(egister modify)\n"); 164 | printf(" L(oad binary) C(ontinue running - if Step)\n"); 165 | printf(" G(o) B(oot CP/M) Z(80 disassembled dump)\n"); 166 | printf(" W(write memory to file) X,Y(-set/clear breakpoint)\n"); 167 | printf(" O(output to \"logfile\")\n\n"); 168 | printf(" !(fork shell) ?(command list) V(ersion)\n\n"); 169 | break; 170 | 171 | case 'o': 172 | if (logfile != NULL) 173 | { 174 | fclose(logfile); 175 | logfile = NULL; 176 | printf(" Logging off.\n"); 177 | } 178 | else 179 | { 180 | printf(" Logfile name? "); 181 | gets(str); 182 | 183 | for (s = str; isspace(*s); s++) 184 | ; 185 | 186 | if (*s == '\0') 187 | break; 188 | 189 | logfile = fopen(s, "w"); 190 | 191 | if (logfile == NULL) 192 | printf("Cannot open logfile!\n"); 193 | else 194 | printf(" Logging on.\n"); 195 | } 196 | 197 | break; 198 | 199 | case '!': /* fork a shell */ 200 | system("exec ${SHELL:-/bin/sh}"); 201 | initterm(); 202 | printf("\n"); 203 | break; 204 | 205 | case 'q': /* quit */ 206 | if (logfile != NULL) 207 | fclose(logfile); 208 | 209 | exit(0); 210 | break; 211 | 212 | case 'v': /* version */ 213 | printf(" Version %s\n", VERSION); 214 | break; 215 | 216 | case 'b': /* boot cp/m */ 217 | setterm(); 218 | sysreset(z80); 219 | return; 220 | break; 221 | 222 | case 't': /* toggle trace mode */ 223 | z80->trace = !z80->trace; 224 | printf(" Trace %s\n", z80->trace ? "on" : "off"); 225 | break; 226 | 227 | case 's': /* toggle step-trace mode */ 228 | z80->step = !z80->step; 229 | printf(" Step-trace %s\n", z80->step ? "on" : "off"); 230 | printf(" Trace %s\n", z80->trace ? "on" : "off"); 231 | break; 232 | 233 | case 'd': /* dump registers */ 234 | dumptrace(z80); 235 | break; 236 | 237 | case 'e': /* examine memory */ 238 | printf(" Starting at loc? (%.4X) : ", pe); 239 | gets(str); 240 | t = pe; 241 | sscanf(str, "%x", &t); 242 | pe = t; 243 | 244 | for (i = 0; i <= 8; i++) 245 | { 246 | printf(" %.4X: ", pe); 247 | 248 | for (j = 0; j <= 0xF; j++) 249 | printf("%.2X ", z80->mem[pe++]); 250 | 251 | printf("\n"); 252 | } 253 | 254 | break; 255 | 256 | case 'w': /* write memory to file */ 257 | printf(" Starting at loc? "); 258 | gets(str); 259 | sscanf(str, "%x", &t); 260 | printf(" Ending at loc? "); 261 | gets(str); 262 | sscanf(str, "%x", &e); 263 | fp = fopen("mem", "w"); 264 | 265 | if (fp == NULL) 266 | printf("Cannot open file 'mem' for writing!\n"); 267 | else 268 | { 269 | j = 0; 270 | 271 | for (i = t; i < e; i++) 272 | { 273 | if (j++ > 9) 274 | { 275 | fprintf(fp, "\n"); 276 | j = 0; 277 | } 278 | 279 | fprintf(fp, "0x%X, ", z80->mem[i]); 280 | } 281 | 282 | fprintf(fp, "\n"); 283 | fclose(fp); 284 | } 285 | 286 | break; 287 | 288 | case 'x': /* set breakpoint */ 289 | #ifdef MEM_BREAK 290 | printf(" Set breakpoint at loc? (A for abort): "); 291 | gets(str); 292 | 293 | if (tolower(*str) == 'a' || *str == '\0') 294 | break; 295 | 296 | sscanf(str, "%x", &t); 297 | 298 | if (t < 0 || t >= sizeof z80->mem) 299 | { 300 | printf("Cannot set breakpoint at addr 0x%X\n", t); 301 | break; 302 | } 303 | 304 | if (!(z80->membrk[t] & M_BREAKPOINT)) 305 | { 306 | printf(" Breakpoint set at addr 0x%X\n", t); 307 | z80->membrk[t] |= M_BREAKPOINT; 308 | z80->numbrks++; 309 | } 310 | #else 311 | printf("Sorry, Z80 has not been compiled with MEM_BREAK.\n"); 312 | #endif /* MEM_BREAK */ 313 | break; 314 | 315 | case 'y': /* clear breakpoints */ 316 | #ifdef MEM_BREAK 317 | printf(" Clear breakpoint at loc? (A for all) : "); 318 | gets(str); 319 | 320 | if (tolower(*str) == 'a') 321 | { 322 | for (i = 0; i < sizeof z80->membrk; i++) 323 | z80->membrk[i] &= ~M_BREAKPOINT; 324 | 325 | z80->numbrks = 0; 326 | printf(" All breakpoints cleared\n"); 327 | break; 328 | } 329 | 330 | sscanf(str, "%x", &t); 331 | 332 | if (t < 0 || t >= sizeof z80->mem) 333 | { 334 | printf(" Cannot clear breakpoint at addr 0x%X\n", t); 335 | break; 336 | } 337 | 338 | if (z80->membrk[t] & M_BREAKPOINT) 339 | { 340 | printf("Breakpoint cleared at addr 0x%X\n", t); 341 | z80->membrk[t] &= ~M_BREAKPOINT; 342 | z80->numbrks--; 343 | } 344 | #else 345 | printf("Sorry, Z80 has not been compiled with MEM_BREAK.\n"); 346 | #endif /* MEM_BREAK */ 347 | break; 348 | 349 | case 'z': /* z80 disassembled memory dump */ 350 | printf(" Starting at loc? (%.4X) : ", pe); 351 | gets(str); 352 | t = pe; 353 | sscanf(str, "%x", &t); 354 | pe = t; 355 | 356 | for (i = 0; i < 0x10; i++) 357 | { 358 | printf(" %.4X: ", pe); 359 | j = pe; 360 | pe += disassem(z80, pe, stdout); 361 | t = disassemlen(z80); 362 | 363 | while (t++ < 15) 364 | putchar(' '); 365 | 366 | while (j < pe) 367 | printf(" %.2X", z80->mem[j++]); 368 | 369 | printf("\n"); 370 | } 371 | 372 | break; 373 | 374 | case 'p': /* poke memory */ 375 | printf(" Start at loc? (%.4X) : ", po); 376 | gets(str); 377 | sscanf(str, "%x", &i); 378 | po = i; 379 | 380 | for (;;) 381 | { 382 | printf(" Mem[%.4X] (%.2X) = ", po, z80->mem[po]); 383 | gets(str); 384 | 385 | for (s = str; *s == ' ' || *s == '\t'; s++) 386 | ; 387 | 388 | if (*s == '~') /* exit? */ 389 | { 390 | po = i; 391 | break; 392 | } 393 | 394 | if (*s == '\0') /* leave the value alone */ 395 | continue; 396 | 397 | j = 0; 398 | sscanf(str, "%x", &j); 399 | z80->mem[po] = j; 400 | po++; 401 | } 402 | break; 403 | 404 | case 'r': /* set a register */ 405 | printf(" Value? = "); 406 | gets(str); 407 | i = 0; 408 | sscanf(str, "%x", &i); 409 | printf(" Reg? (A,F,B,C,D,E,H,L,IX,IY,SP,PC) : "); 410 | gets(str); 411 | 412 | for (s = str; *s == ' ' || *s == '\t'; s++) 413 | ; 414 | 415 | switch (tolower(*s)) 416 | { 417 | case 'a': A = i; break; 418 | case 'f': F = i; break; 419 | case 'b': B = i; break; 420 | case 'c': C = i; break; 421 | case 'd': D = i; break; 422 | case 'e': E = i; break; 423 | case 'h': H = i; break; 424 | case 'l': L = i; break; 425 | case 'i': 426 | if (tolower(s[1]) == 'x') 427 | IX = i; 428 | else if (tolower(s[1]) == 'y') 429 | IY = i; 430 | 431 | break; 432 | 433 | case 'x': IX = i; break; 434 | case 'y': IY = i; break; 435 | case 's': SP = i; break; 436 | case 'p': PC = i; break; 437 | 438 | default: 439 | printf("No such register\n"); 440 | break; 441 | } 442 | 443 | break; 444 | 445 | case 'l': /* load a file into z80 memory */ 446 | printf(" File-name: "); 447 | gets(str); 448 | 449 | if (!loadfile(z80, str)) 450 | fprintf(stderr, "Cannot load file %s!\r\n", str); 451 | 452 | break; 453 | 454 | case '\0': /* carriage-return */ 455 | case '\r': 456 | case '\n': 457 | if (z80->trace && z80->step) 458 | goto cont; 459 | 460 | break; 461 | 462 | case 'c': /* continue z80 execution */ 463 | case 'g': 464 | cont: 465 | setterm(); 466 | 467 | if (z80->trace) 468 | { 469 | z80->event = TRUE; 470 | z80->halt = TRUE; 471 | } 472 | 473 | return; 474 | 475 | default: 476 | /*putchar('\007');*/ 477 | printf("\007Command \"%s\" not recognized\n", s); 478 | break; 479 | } 480 | 481 | goto loop; 482 | } 483 | 484 | 485 | 486 | 487 | /*-----------------------------------------------------------------------*\ 488 | | dumptrace -- dump the z80 registers in an easy-to-trace format 489 | | -- note that the dump takes exactly one line so that changes in 490 | | register values are easier to spot -- disassembles the z80 code 491 | \*-----------------------------------------------------------------------*/ 492 | 493 | static void 494 | dumptrace(z80info *z80) 495 | { 496 | printf("a%.2X f%.2X bc%.4X de%.4X hl%.4X ", 497 | A, F, BC, DE, HL); 498 | printf("ix%.4X iy%.4X sp%.4X pc%.4X:%.2X ", 499 | IX, IY, SP, PC, z80->mem[PC]); 500 | disassem(z80, PC, stdout); 501 | printf("\r\n"); 502 | 503 | if (logfile) 504 | { 505 | fprintf(logfile, "a%.2X f%.2X bc%.4X de%.4X hl%.4X ", 506 | A, F, BC, DE, HL); 507 | fprintf(logfile, "ix%.4X iy%.4X sp%.4X pc%.4X:%.2X ", 508 | IX, IY, SP, PC, z80->mem[PC]); 509 | disassem(z80, PC, logfile); 510 | fprintf(logfile, "\r\n"); 511 | } 512 | } 513 | 514 | 515 | 516 | #define HEXVAL(c) (('0' <= (c) && (c) <= '9') ? (c) - '0' :\ 517 | (('a' <= (c) && (c) <= 'f') ? (c) - 'a' + 10 :\ 518 | (('A' <= (c) && (c) <= 'F') ? (c) - 'A' + 10 :\ 519 | -1 ))) 520 | 521 | static int 522 | gethex(FILE *fp) 523 | { 524 | int i, j; 525 | 526 | i = getc(fp); 527 | j = getc(fp); 528 | 529 | if (i < 0 || j < 0) 530 | return -1; 531 | 532 | i = HEXVAL(i); 533 | j = HEXVAL(j); 534 | 535 | if (i < 0 || j < 0) 536 | return -1; 537 | 538 | return (i << 4) | j; 539 | } 540 | 541 | 542 | static int 543 | loadhex(z80info *z80, FILE *fp) 544 | { 545 | int start = TRUE; 546 | int len, line, i; 547 | word addr, check, t; 548 | 549 | for (line = 1; getc(fp) >= 0; line++) /* should be a ':' */ 550 | { 551 | if ((len = gethex(fp)) <= 0) 552 | break; 553 | 554 | check = len; 555 | 556 | if ((i = gethex(fp)) < 0) 557 | break; 558 | 559 | addr = (word)i; 560 | check += addr; 561 | 562 | if ((i = gethex(fp)) < 0) 563 | break; 564 | 565 | t = (word)i; 566 | check += t; 567 | addr = (addr << 8) | t; 568 | 569 | if (start) 570 | PC = addr, start = FALSE; 571 | 572 | if ((i = gethex(fp)) < 0) /* ??? */ 573 | break; 574 | 575 | check += (word)i; 576 | 577 | while (len-- > 0) 578 | { 579 | if ((i = gethex(fp)) < 0) 580 | break; 581 | 582 | t = (word)i; 583 | check += t; 584 | z80->mem[addr] = t; 585 | addr++; 586 | } 587 | 588 | if ((i = gethex(fp)) < 0) /* checksum */ 589 | break; 590 | 591 | t = (word)i; 592 | 593 | if ((t + check) & 0xFF) 594 | { 595 | fprintf(stderr, "%d: Checksum error: %.2X != 0!\r\n", 596 | line, (t + check) & 0xFF); 597 | return FALSE; 598 | } 599 | 600 | if (getc(fp) < 0) /* should be a '\n' */ 601 | break; 602 | } 603 | 604 | return TRUE; 605 | } 606 | 607 | 608 | 609 | /*-----------------------------------------------------------------------*\ 610 | | getword -- return a 16-bit word from the specified file 611 | \*-----------------------------------------------------------------------*/ 612 | 613 | static int 614 | getword(FILE *file) 615 | { 616 | int w; 617 | 618 | w = getc(file) << 8; 619 | w |= getc(file); 620 | return w; 621 | } 622 | 623 | 624 | 625 | /*-----------------------------------------------------------------------*\ 626 | | loadpisces -- load the specified file (assumed to be in Pisces+ 627 | | format) into the z80 memory for subsequent execution 628 | \*-----------------------------------------------------------------------*/ 629 | 630 | static int 631 | loadpisces(z80info *z80, FILE *file) 632 | { 633 | int numbytes, i; 634 | unsigned short loadaddr; 635 | 636 | /* ignore the 1st 12 words in the file - the 13th word is the starting 637 | PC value - the 14th is also ignored */ 638 | for (i = 0; i < 12; i++) 639 | getword(file); 640 | 641 | PC = getword(file); 642 | getword(file); 643 | 644 | /* read in each block of words into the z80 memory - each block 645 | specifies the number of bytes in the block and the address to load 646 | the data into */ 647 | while (getword(file) != EOF) 648 | { 649 | numbytes = getword(file); 650 | loadaddr = getword(file); 651 | getword(file); 652 | 653 | for (; numbytes > 0; numbytes -= 2) 654 | { 655 | z80->mem[loadaddr] = getc(file); 656 | loadaddr++; 657 | z80->mem[loadaddr] = getc(file); 658 | loadaddr++; 659 | } 660 | } 661 | 662 | return TRUE; 663 | } 664 | 665 | 666 | static void 667 | suffix(char *str, const char *suff) 668 | { 669 | while(*str != '\0' && *str != '.') 670 | str++; 671 | 672 | strcpy(str, suff); 673 | } 674 | 675 | 676 | boolean 677 | loadfile(z80info *z80, const char *fname) 678 | { 679 | char buf[200]; 680 | FILE *fp; 681 | int ret; 682 | 683 | if ((fp = fopen(fname, "r")) != NULL) 684 | { 685 | ret = loadhex(z80, fp); 686 | fclose(fp); 687 | return ret; 688 | } 689 | 690 | strcpy(buf, fname); 691 | suffix(buf, ".hex"); 692 | 693 | if ((fp = fopen(buf, "r")) != NULL) 694 | { 695 | ret = loadhex(z80, fp); 696 | fclose(fp); 697 | return ret; 698 | } 699 | 700 | strcpy(buf, fname); 701 | suffix(buf, ".X"); 702 | 703 | if ((fp = fopen(buf, "r")) != NULL) 704 | { 705 | ret = loadpisces(z80, fp); 706 | fclose(fp); 707 | return ret; 708 | } 709 | 710 | return FALSE; 711 | } 712 | 713 | 714 | 715 | /* input -- z80 input instruction -- this function is called whenever 716 | an input ports is referenced from the z80 to handle the real I/O -- 717 | it returns a byte to the z80 just like the real I/O instruction -- 718 | the arguments represent the data on the bus as it would be for a real 719 | z80 - this routine is restarted later if there is no input pending, 720 | and we must wait for some to occur */ 721 | 722 | boolean 723 | input(z80info *z80, byte haddr, byte laddr, byte *val) 724 | { 725 | static int last = 0; /* the last character read from the tty */ 726 | int data; 727 | 728 | /* just uses the lower 8-bits of the I/O address for now... */ 729 | switch (laddr) 730 | { 731 | 732 | /* return a character from the keyboard - wait for it if necessary -- 733 | return "last" if we have already read in something via 0x01 */ 734 | case 0x00: 735 | if (last) 736 | { 737 | data = last; 738 | last = 0; 739 | } 740 | else 741 | { 742 | #if defined macintosh 743 | EventRecord ev; 744 | 745 | again: 746 | fflush(stdout); 747 | 748 | while (!WaitNextEvent(keyDownMask | autoKeyMask, 749 | &ev, 20, nil)) 750 | ; 751 | 752 | data = ev.message & charCodeMask; 753 | 754 | if ((data == '.' && (ev.modifiers & cmdKey)) || 755 | data == INTR_CHAR) 756 | { 757 | command(z80); 758 | goto again; 759 | } 760 | else if (data == 'q' && (ev.modifiers & cmdKey)) 761 | exit(0); 762 | #elif defined DJGPP 763 | fflush(stdout); 764 | data = getkey(); 765 | 766 | while (data == INTR_CHAR) 767 | { 768 | command(z80); 769 | data = getkey(); 770 | } 771 | #else /* TCGETA */ 772 | fflush(stdout); 773 | data = getchar(); 774 | 775 | while ((data < 0 && errno == EINTR) || 776 | data == INTR_CHAR) 777 | { 778 | command(z80); 779 | data = getchar(); 780 | } 781 | #endif 782 | } 783 | 784 | *val = data & 0x7F; 785 | break; 786 | 787 | /* return 0xFF if we have a character waiting to be read - save the 788 | character in "last" for 0x00 above */ 789 | case 0x01: 790 | #if defined macintosh 791 | { 792 | EventRecord ev; 793 | *val = EventAvail(keyDownMask | autoKeyMask, &ev) ? 794 | 0xFF : 0; 795 | } 796 | #elif defined DJGPP 797 | *val = (kbhit()) ? 0xFF : 0; 798 | #else /* UNIX or BeBox */ 799 | /* "keybd" should already be opened for non-blocking read */ 800 | fflush(stdout); 801 | 802 | if (!last && keybd >= 0) 803 | read(keybd, &last, 1); 804 | 805 | *val = last ? 0xFF : 0; 806 | #endif 807 | break; 808 | 809 | /* default - prompt the user for an input byte */ 810 | default: 811 | resetterm(); 812 | printf("INPUT : addr = %X%X DATA = ", haddr, laddr); 813 | fflush(stdout); 814 | scanf("%x", &data); 815 | setterm(); 816 | *val = data; 817 | break; 818 | } 819 | 820 | return TRUE; 821 | } 822 | 823 | 824 | 825 | 826 | /*-----------------------------------------------------------------------*\ 827 | | output -- output the data at the specified I/O address 828 | \*-----------------------------------------------------------------------*/ 829 | 830 | void 831 | output(z80info *z80, byte haddr, byte laddr, byte data) 832 | { 833 | if (laddr == 0xFF) { 834 | /* BIOS call - interrupt the z80 before the next instruction 835 | since we may have to mess with the PC & other stuff - 836 | otherwise we would do it right here */ 837 | z80->event = TRUE; 838 | z80->halt = TRUE; 839 | z80->syscall = TRUE; 840 | z80->biosfn = data; 841 | 842 | if (z80->trace) 843 | { 844 | printf("BIOS call %d\r\n", z80->biosfn); 845 | 846 | if (logfile) 847 | fprintf(logfile, "BIOS call %d\r\n", 848 | z80->biosfn); 849 | } 850 | } else if (laddr == 0) { 851 | /* output a character to the screen */ 852 | putchar(data); 853 | 854 | if (logfile != NULL) 855 | putc(data, logfile); 856 | } else { 857 | /* dump the data for our user */ 858 | printf("OUTPUT: addr = %X%X DATA = %X\r\n", haddr, laddr,data); 859 | } 860 | } 861 | 862 | 863 | 864 | /*-----------------------------------------------------------------------*\ 865 | | haltcpu -- this is called after the z80 halts -- it is used for 866 | | tracing & such 867 | \*-----------------------------------------------------------------------*/ 868 | 869 | void 870 | haltcpu(z80info *z80) 871 | { 872 | z80->halt = FALSE; 873 | 874 | /* we were interrupted by a Unix signal */ 875 | if (z80->sig) 876 | { 877 | if (z80->sig != SIGINT) 878 | printf("\r\nCaught signal %d.\r\n", z80->sig); 879 | 880 | z80->sig = 0; 881 | command(z80); 882 | return; 883 | } 884 | 885 | /* we are tracing execution of the z80 */ 886 | if (z80->trace) 887 | { 888 | /* re-enable tracing */ 889 | z80->event = TRUE; 890 | z80->halt = TRUE; 891 | dumptrace(z80); 892 | 893 | if (z80->step) 894 | command(z80); 895 | } 896 | 897 | /* a CP/M syscall - done here so tracing still works */ 898 | if (z80->syscall) 899 | { 900 | z80->syscall = FALSE; 901 | bios(z80, z80->biosfn); 902 | } 903 | } 904 | 905 | word 906 | read_mem(z80info *z80, word addr) 907 | { 908 | #ifdef MEM_BREAK 909 | if (z80->membrk[addr] & M_BREAKPOINT) 910 | { 911 | fprintf(stderr, "\r\nBreak at 0x%X\r\n", addr); 912 | } 913 | else if (z80->membrk[addr] & M_READ_PROTECT) 914 | { 915 | fprintf(stderr, 916 | "\r\nAttempt to read protected memory at 0x%X\r\n", 917 | addr); 918 | } 919 | else if (z80->membrk[addr] & M_MEM_MAPPED_IO) 920 | { 921 | fprintf(stderr, 922 | "\r\nAttempt to perform mem-mapped input at 0x%X\r\n", 923 | addr); 924 | /* fake some sort of I/O here and return its value */ 925 | } 926 | 927 | dumptrace(z80); 928 | command(z80); 929 | #endif /* MEM_BREAK */ 930 | 931 | return z80->mem[addr]; 932 | } 933 | 934 | word 935 | write_mem(z80info *z80, word addr, byte val) 936 | { 937 | #ifdef MEM_BREAK 938 | if (z80->membrk[addr] & M_BREAKPOINT) 939 | { 940 | fprintf(stderr, "\r\nBreak at 0x%X\r\n", addr); 941 | } 942 | else if (z80->membrk[addr] & M_WRITE_PROTECT) 943 | { 944 | fprintf(stderr, 945 | "\r\nAttempt to write to protected memory at 0x%X\r\n", 946 | addr); 947 | } 948 | else if (z80->membrk[addr] & M_MEM_MAPPED_IO) 949 | { 950 | fprintf(stderr, 951 | "\r\nAttempt to perform mem-mapped output at 0x%X\r\n", 952 | addr); 953 | /* fake some sort of I/O here and set mem to its value, */ 954 | /* then return */ 955 | } 956 | 957 | dumptrace(z80); 958 | command(z80); 959 | #endif /* MEM_BREAK */ 960 | 961 | return z80->mem[addr] = val; 962 | } 963 | 964 | void 965 | undefinstr(z80info *z80, byte instr) 966 | { 967 | printf("\r\nIllegal instruction 0x%.2X at PC=0x%.4X\r\n", 968 | instr, PC - 1); 969 | command(z80); 970 | } 971 | 972 | 973 | 974 | /*-----------------------------------------------------------------------*\ 975 | | quit -- terminate this program after cleaning up -- this it is | 976 | | intended to catch unused signals & not leave the terminal hosed | 977 | \*-----------------------------------------------------------------------*/ 978 | 979 | static void 980 | quit(int sig) 981 | { 982 | printf("\r\nCaught signal %d.\r\n", sig); 983 | resetterm(); 984 | exit(2); 985 | } 986 | 987 | 988 | /* this is needed by both interrupt() and main() */ 989 | static z80info *z80 = NULL; 990 | 991 | 992 | /*-----------------------------------------------------------------------*\ 993 | | interrupt -- this is called when we get a usable signal from Unix 994 | \*-----------------------------------------------------------------------*/ 995 | 996 | static void 997 | interrupt(int s) 998 | { 999 | /* we tell the z80 to stop when convenient, then reset & continue */ 1000 | if (z80 != NULL) 1001 | { 1002 | z80->event = TRUE; 1003 | z80->halt = TRUE; 1004 | z80->sig = s; 1005 | } 1006 | 1007 | signal(s, interrupt); 1008 | } 1009 | 1010 | 1011 | /*-----------------------------------------------------------------------*\ 1012 | | main -- set up the global vars & run the z80 1013 | \*-----------------------------------------------------------------------*/ 1014 | 1015 | int 1016 | main(int argc, const char *argv[]) 1017 | { 1018 | const char *s; 1019 | 1020 | z80 = new_z80info(); 1021 | 1022 | if (z80 == NULL) 1023 | return -1; 1024 | 1025 | initterm(); 1026 | 1027 | #if defined BeBox_TurnedOff 1028 | /* try to open the keyboard for non-blocking read */ 1029 | keybd = dup(0); /* dup stdin */ 1030 | 1031 | if (keybd < 0) 1032 | { 1033 | fprintf(stderr, "Cannot dup stdin for I/O.\r\n"); 1034 | exit(1); 1035 | } 1036 | 1037 | if (fcntl(keybd, F_SETFL, O_NONBLOCK) < 0) 1038 | { 1039 | fprintf(stderr, "Cannot set fcntl for I/O.\r\n"); 1040 | exit(1); 1041 | } 1042 | #elif defined UNIX 1043 | /* try to open the keyboard for non-blocking read */ 1044 | #if defined O_NONBLOCK 1045 | keybd = open("/dev/tty", O_RDONLY | O_NONBLOCK); 1046 | #elif defined O_NDELAY 1047 | keybd = open("/dev/tty", O_RDONLY | O_NDELAY); 1048 | #else 1049 | #error Need to specify non-blocking I/O. 1050 | #endif 1051 | 1052 | if (keybd < 0) 1053 | { 1054 | fprintf(stderr, "Cannot open /dev/tty for I/O.\r\n"); 1055 | exit(1); 1056 | } 1057 | #endif 1058 | 1059 | /* set up the signals */ 1060 | #ifdef SIGQUIT 1061 | signal(SIGQUIT, quit); 1062 | #endif 1063 | #ifdef SIGHUP 1064 | signal(SIGHUP, quit); 1065 | #endif 1066 | #ifdef SIGTERM 1067 | signal(SIGTERM, quit); 1068 | #endif 1069 | #ifdef SIGINT 1070 | signal(SIGINT, interrupt); 1071 | #endif 1072 | 1073 | setterm(); 1074 | 1075 | /* if we had an argument on the command line, try to load that file & 1076 | immediately execute the z80 -- otherwise go to the command level */ 1077 | if (strcmp(argv[0], "cpm") == 0 || 1078 | ((s = strrchr(argv[0], '/')) != NULL && 1079 | strcmp(s + 1, "cpm") == 0)) 1080 | { 1081 | sysreset(z80); 1082 | } 1083 | else 1084 | { 1085 | if (argc <= 1) 1086 | command(z80); 1087 | 1088 | else if (!loadfile(z80, argv[1])) 1089 | { 1090 | /* cannot load it - exit */ 1091 | fprintf(stderr, "Cannot load file %s!\r\n", argv[1]); 1092 | resetterm(); 1093 | return -2; 1094 | } 1095 | } 1096 | 1097 | while (1) 1098 | { 1099 | #ifdef macintosh 1100 | EventRecord ev; 1101 | WaitNextEvent(0, &ev, 0, nil); 1102 | #endif 1103 | z80_emulator(z80, 100000); 1104 | } 1105 | } 1106 | -------------------------------------------------------------------------------- /makedisc.c: -------------------------------------------------------------------------------- 1 | /*-----------------------------------------------------------------------*\ 2 | | Originally by Kevin Kayes, but he refused any responsibility for it. | 3 | | | 4 | | Copyright 1986-1988 by Parag Patel. All Rights Reserved. | 5 | | Copyright 1994 by CodeGen, Inc. All Rights Reserved. | 6 | \*-----------------------------------------------------------------------*/ 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "cpmdisc.h" 15 | #include 16 | #include 17 | 18 | unsigned char disc[DISCSIZE]; 19 | unsigned char buf[128]; 20 | unsigned char *bufptr = buf; 21 | int sector, track; 22 | 23 | void 24 | usage(void) 25 | { 26 | printf("Usage: makedisc [-bc] discname [filename]\n"); 27 | printf(" -b = binary file (no conversion - default)\n"); 28 | printf(" -c = text file (convert newlines to CRLF)\n"); 29 | printf(" discname = A: B: etc.\n"); 30 | printf(" filename = file to be inserted into the disc (1 max)\n"); 31 | printf(" If an option (-b or -c) is given the optional filename must\n"); 32 | printf(" be supplied. The -b and -c options are mutually exclusive.\n"); 33 | 34 | exit(1); 35 | } 36 | 37 | void 38 | writesector(unsigned char *sectordata) 39 | { 40 | unsigned char *cp; 41 | int i; 42 | int physical; 43 | 44 | /* incoming sector is logical (0 -> (SECTORSPERTRACK - 1)) */ 45 | physical = sectorxlat[sector]; 46 | 47 | /* printf("Writesector: track = %d sector = %d physical = %d\n", track, sector, physical); */ 48 | 49 | cp = &disc[SECTORSIZE 50 | * (physical - SECTOROFFSET 51 | + (SECTORSPERTRACK 52 | * (track - TRACKOFFSET) 53 | ) 54 | ) 55 | ]; 56 | for (i = 0; i < SECTORSIZE; i++) *cp++ = *sectordata++; 57 | if (++sector == SECTORSPERTRACK) { 58 | sector = 0; 59 | track++; 60 | } 61 | } 62 | 63 | void 64 | writechar(int c) 65 | { 66 | if ((bufptr - buf) == SECTORSIZE) { 67 | writesector(buf); 68 | bufptr = buf; 69 | } 70 | *bufptr++ = c; 71 | } 72 | 73 | void 74 | flushsector(int c) 75 | { 76 | int i; 77 | 78 | for (i = (bufptr - buf); i < SECTORSIZE; i++) writechar(c); 79 | writesector(buf); 80 | bufptr = buf; 81 | } 82 | 83 | int 84 | main(int argc, const char **argv) 85 | { 86 | int i, n, size, ext, block; 87 | int drive, file, convert; 88 | int infile = 0, outfile = 0; 89 | const char *fp_out; 90 | const char *fp_in = NULL; 91 | const char *opts; 92 | char c, lastc, *cp; 93 | const char *f; 94 | char newname[128]; 95 | struct stat statbuf; 96 | unsigned char *dp; 97 | 98 | convert = file = drive = 0; 99 | 100 | if ((argc > 4) || (argc < 2)) usage(); 101 | for (i = 0; i < (argc - 1); i ++) { 102 | opts = *++argv; 103 | if (*opts == '-') { 104 | if (strlen(opts) != 2) usage(); 105 | if (drive || file) usage(); 106 | if (i != 0) usage(); 107 | convert = opts[1]; 108 | if ((convert != 'c') && (convert != 'b')) usage(); 109 | } else { 110 | if (!drive) { 111 | if ((strlen(opts) != 2) || (opts[1] != ':')) usage(); 112 | if (!isupper(*opts)) { 113 | printf("Disc filename must be single capital letter "); 114 | printf("followed by semicolon (A: B: etc.)\n"); 115 | return 1; 116 | } 117 | strcpy(newname, "?-drive"); 118 | newname[0] = opts[0]; 119 | fp_out = newname; 120 | drive = 1; 121 | if ((outfile = open(fp_out, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0) { 122 | printf("makecpm: cannot create \"%s\" : %d\n", fp_out, errno); 123 | return 1; 124 | } 125 | } else { 126 | fp_in = opts; 127 | file = 1; 128 | if ((infile = open(fp_in, O_RDONLY)) < 0) { 129 | printf("makecpm: cannot open \"%s\" for reading\n", fp_in); 130 | return 1; 131 | } 132 | } 133 | } 134 | } 135 | 136 | convert = (convert == 'c'); 137 | 138 | /* format disc */ 139 | dp = disc; 140 | for (i = 0; i < DISCSIZE; i++) *dp++ = 0xE5; 141 | 142 | c = size = 0; 143 | ext = 0; 144 | block = (TOTALEXTENTS / EXTENTSPERSECTOR) / SECTORSPERBLOCK; 145 | track = RESERVEDTRACKS + TRACKOFFSET; 146 | sector = 0; 147 | if (file) { 148 | /* find file size */ 149 | if (convert) { 150 | do { 151 | lastc = c; 152 | n = read(infile, &c, 1); 153 | if (n == 1) { 154 | if (convert && (lastc != 0xD) && (c == 0xA)) { 155 | size++; 156 | } 157 | size++; 158 | } 159 | } while (n == 1); 160 | } else { 161 | if (fstat(infile, &statbuf) < 0) { 162 | printf("makecpm: cannot get stats on input file\n"); 163 | return 1; 164 | } 165 | size = statbuf.st_size; 166 | } 167 | 168 | if (size > DISCSIZE) { 169 | printf("makecpm: file is to large.\n"); 170 | return 1; 171 | } 172 | 173 | /* build directory */ 174 | f = fp_in + strlen(fp_in); 175 | while ((f != fp_in) && (*f != '/')) f--; 176 | if (*f == '/') f++; 177 | strcpy(newname, f); 178 | for (cp = newname; *cp; cp++) *cp = toupper(*cp); 179 | printf("%s => %s, size = %d\n", fp_in, newname, size); 180 | while(size > 0) { 181 | c = 0x00; 182 | writechar(c); 183 | for (i = 0, cp = newname; 184 | (i < 8) && (*cp != 0) && (*cp != '.'); 185 | i++, cp++) { 186 | writechar(*cp); 187 | } 188 | while ((*cp != 0) && (*cp != '.')) cp++; 189 | c = ' '; 190 | while (i < 8) { writechar(c); i++; } 191 | if (*cp == '.') { 192 | cp++; 193 | while ((*cp != 0) && (i < 11)) { 194 | writechar(*cp++); 195 | i++; 196 | } 197 | } 198 | while (i < 11) { writechar(c); i++; } 199 | c = ext; 200 | writechar(c); 201 | c = 0x00; 202 | writechar(c); 203 | writechar(c); 204 | if (size >= SECTORSIZE * SECTORSPEREXTENT) 205 | c = SECTORSPEREXTENT; 206 | else 207 | c = (size / SECTORSIZE) + ((size % SECTORSIZE) ? 1 : 0); 208 | writechar(c); 209 | for (i = 0; 210 | (i < 16) && (size > 0); 211 | i++, size -= SECTORSIZE * SECTORSPERBLOCK 212 | ) { 213 | c = block++; 214 | writechar(c); 215 | } 216 | c = 0; 217 | for (; i < 16; i++) { 218 | writechar(c); 219 | } 220 | ext++; 221 | } 222 | flushsector(0xE5); 223 | 224 | /* copy file */ 225 | size = (TOTALEXTENTS + EXTENTSPERSECTOR - 1) / EXTENTSPERSECTOR; 226 | track = RESERVEDTRACKS + TRACKOFFSET + size / SECTORSPERTRACK; 227 | sector = size % SECTORSPERTRACK; 228 | 229 | close(infile); 230 | if ((infile = open(fp_in, O_RDONLY)) < 0) { 231 | printf("makecpm: cannot open \"%s\" for reading\n", fp_in); 232 | return 1; 233 | } 234 | if (convert) { 235 | do { 236 | lastc = c; 237 | n = read(infile, &c, 1); 238 | if (n == 1) { 239 | if ((lastc != 0xD) && (c == 0xA)) { 240 | lastc = 0xD; 241 | writechar(lastc); 242 | } 243 | writechar(c); 244 | } 245 | } while (n == 1); 246 | flushsector(0x1A); 247 | } else { 248 | do { 249 | n = read(infile, &c, 1); 250 | if (n == 1) 251 | writechar(c); 252 | } while (n == 1); 253 | flushsector(0x1A); 254 | } 255 | } 256 | 257 | /* finish writing disc file */ 258 | if (write(outfile, disc, DISCSIZE) != DISCSIZE) { 259 | printf("makecpm: trouble writing output file\n"); 260 | } 261 | close(outfile); 262 | printf("done\n"); 263 | return 0; 264 | } 265 | -------------------------------------------------------------------------------- /putunix.mac: -------------------------------------------------------------------------------- 1 | ; PUT CP/M FILE INTO UNIX UTILITY 2 | ; putunix driveletter:cpmfilename.extension unixfilename.extension 3 | ; 4 | .Z80 5 | 6 | SRCFCB EQU 005CH 7 | SECFCB EQU 006CH 8 | 9 | CBIOS EQU 0EA00H 10 | OPNUNX EQU CBIOS+33H 11 | CRTUNX EQU CBIOS+36H 12 | RDUNX EQU CBIOS+39H 13 | WRUNX EQU CBIOS+3CH 14 | CLSUNX EQU CBIOS+3FH 15 | 16 | BDOS EQU 5 17 | OPEN EQU 15 18 | CLOSE EQU 16 19 | READ EQU 20 20 | WRITE EQU 21 21 | CREATE EQU 22 22 | SETDMA EQU 26 23 | PRINT EQU 9 24 | 25 | CSEG 26 | ENTRY START 27 | START: 28 | LD SP,STACK 29 | ;MOVE DESTINATION FCB 30 | LD HL,SECFCB 31 | LD DE,DSTFCB 32 | LD BC,10H 33 | LDIR 34 | LD HL,DSTFCB+16 35 | LD DE,DSTFCB+17 36 | LD (HL),0 37 | LD BC,20H 38 | LDIR 39 | 40 | ;OPEN SOURCE FILE 41 | LD DE,SRCFCB 42 | LD C,OPEN 43 | CALL BDOS 44 | CP 0FFH 45 | JP Z,ERROR1 46 | ;CREATE DESTINATION FILE 47 | LD DE,DSTFCB 48 | CALL CRTUNX 49 | AND A 50 | JP NZ,ERROR2 51 | 52 | ;SET DMA ADDRESS 53 | LD DE,0080H 54 | LD C,SETDMA 55 | CALL BDOS 56 | 57 | ;READ ONE, WRITE ONE 58 | LOOP: LD DE,SRCFCB 59 | LD C,READ 60 | CALL BDOS 61 | AND A 62 | JP NZ,CLOSEM 63 | LD DE,DSTFCB 64 | CALL WRUNX 65 | AND A 66 | JP NZ,ERROR4 67 | JP LOOP 68 | 69 | ;CLOSE UNIX FILE 70 | CLOSEM: LD DE,DSTFCB 71 | CALL CLSUNX 72 | AND A 73 | JP Z,CLSCPM 74 | 75 | CLSCPM: LD DE,SRCFCB 76 | LD C,CLOSE 77 | CALL BDOS 78 | JP 0 79 | 80 | ERROR1: LD DE,STR1 81 | JP ERROR 82 | STR1: DEFM "ERROR1" 83 | DEFB 13,10,'$' 84 | ERROR2: LD DE,STR2 85 | JP ERROR 86 | STR2: DEFM "ERROR2" 87 | DEFB 13,10,'$' 88 | ERROR3: LD DE,STR3 89 | JP ERROR 90 | STR3: DEFM "ERROR3" 91 | DEFB 13,10,'$' 92 | ERROR4: LD DE,STR4 93 | JP ERROR 94 | STR4: DEFM "ERROR4" 95 | DEFB 13,10,'$' 96 | 97 | ERROR: LD C,PRINT 98 | CALL BDOS 99 | JP 0 100 | 101 | DSTFCB: DEFS 200 102 | STACK: DEFS 1 103 | END 104 | -------------------------------------------------------------------------------- /z80.c: -------------------------------------------------------------------------------- 1 | /*-----------------------------------------------------------------------*\ 2 | | z80.c -- z80 emulator | 3 | | | 4 | | Copyright 1986-1988 by Parag Patel. All Rights Reserved. | 5 | | Copyright 1994-1995 by CodeGen, Inc. All Rights Reserved. | 6 | \*-----------------------------------------------------------------------*/ 7 | 8 | #include 9 | #include 10 | #include 11 | #include "defs.h" 12 | 13 | 14 | /* All the following macros assume access to a parameter named "z80" */ 15 | 16 | 17 | /* entry in "REGPAIRXY[]" to get to the IX or IY registers */ 18 | #define XYPAIR 2 19 | 20 | #define REG z80->reg 21 | #define REGPAIRAF z80->regpairaf 22 | #define REGPAIRSP z80->regpairsp 23 | #define REGPAIRXY z80->regpairxy 24 | #define REGIXY z80->regixy 25 | #define REGIR z80->regir 26 | 27 | 28 | /* bit masks for jump/call/return group instructions */ 29 | static const byte flagmask[] = 30 | { 31 | ZERO, CARRY, PARITY, SIGN 32 | }; 33 | 34 | /* bit masks for bit-twiddling instructions */ 35 | static const byte bitmask[] = 36 | { 37 | BIT0, BIT1, BIT2, BIT3, 38 | BIT4, BIT5, BIT6, BIT7 39 | }; 40 | 41 | /* parity setting array - initialized in init_z80info() below */ 42 | static int parityarr[0x100]; 43 | static boolean parity_inited = FALSE; 44 | 45 | 46 | 47 | /* handy defines for playing with the F(lag) register */ 48 | 49 | #define flagon(flag) (F |= (flag)) 50 | #define flagoff(flag) (F &= ~(flag)) 51 | #define setflag(flag,val) ((val) ? flagon(flag) : flagoff(flag)) 52 | #define resetflag(flag,val) ((val) ? flagoff(flag) : flagon(flag)) 53 | 54 | #define setsign() setflag(SIGN, A & BIT7) 55 | #define setzero() setflag(ZERO, !A) 56 | 57 | 58 | 59 | /* The following macros are supposed to look just like function calls. 60 | To that effect they use a bunch of temporary vars that must be 61 | allocated somewhere. They're generally named "t*" or "r*". 62 | */ 63 | 64 | 65 | /* macros for swapping various popular entities */ 66 | 67 | #define swapw(reg1,reg2) (tt = reg1, reg1 = reg2, reg2 = tt) 68 | #define swapb(reg1,reg2) (t = reg1, reg1 = reg2, reg2 = t) 69 | 70 | 71 | 72 | /* set the parity flag based on the value specified */ 73 | 74 | #define setparity(val) setflag(PARITY, parityarr[val & 0xFF]) 75 | 76 | 77 | 78 | /* set the flags for most bit-twiddling instructions */ 79 | 80 | #define flags(val) \ 81 | {\ 82 | v = val;\ 83 | setflag(SIGN, v & BIT7);\ 84 | setflag(ZERO, !v);\ 85 | flagoff(HALF);\ 86 | flagoff(NEGATIVE);\ 87 | setparity(v);\ 88 | } 89 | 90 | 91 | 92 | /* for generic 8-bit arithmetic instructions */ 93 | 94 | #define arith8(val, carry, sub) \ 95 | {\ 96 | vv = val;\ 97 | s = sub;\ 98 | if (s)\ 99 | {\ 100 | flagon(NEGATIVE);\ 101 | setflag(HALF, ((A & MASK4) - (vv & MASK4)) & BIT4);\ 102 | tt = A - vv;\ 103 | if ((carry) && (F & CARRY)) tt -= 1;\ 104 | }\ 105 | else\ 106 | {\ 107 | flagoff(NEGATIVE);\ 108 | setflag(HALF, ((A & MASK4) + (vv & MASK4)) & BIT4);\ 109 | tt = A + vv;\ 110 | if ((carry) && (F & CARRY)) tt += 1;\ 111 | }\ 112 | setflag(SIGN, tt & BIT7);\ 113 | setflag(OVERFLOW, ((A & BIT7) == (vv & BIT7)) &&\ 114 | ((A & BIT7) != (tt & BIT7)));\ 115 | setflag(CARRY, tt & BIT8);\ 116 | v = tt;\ 117 | setflag(ZERO, !v);\ 118 | } 119 | 120 | 121 | 122 | /* set flags for most logical (AND, OR, ...) instructions */ 123 | 124 | #define logical(hval) \ 125 | {\ 126 | h = hval;\ 127 | setflag(SIGN, A & BIT7);\ 128 | setflag(ZERO, !A);\ 129 | setflag(HALF, h);\ 130 | setparity(A);\ 131 | flagoff(NEGATIVE);\ 132 | flagoff(CARRY);\ 133 | } 134 | 135 | 136 | 137 | /* for incrementing/decrementing of a register */ 138 | 139 | #define increment(reg, neg) \ 140 | {\ 141 | i = reg;\ 142 | n = neg;\ 143 | tt = i;\ 144 | if (n)\ 145 | {\ 146 | setflag(HALF, !(tt-- & MASK4));\ 147 | setflag(OVERFLOW, (i & BIT7) && !(tt & BIT7));\ 148 | }\ 149 | else\ 150 | {\ 151 | setflag(HALF, !(++tt & MASK4));\ 152 | setflag(OVERFLOW, !(i & BIT7) && (tt & BIT7));\ 153 | }\ 154 | setflag(SIGN, tt & BIT7);\ 155 | setflag(ZERO, !(tt & MASK8));\ 156 | setflag(NEGATIVE, n);\ 157 | } 158 | 159 | 160 | 161 | 162 | /*-----------------------------------------------------------------------*\ 163 | | z80 -- emulate a z80 -- labels & gotos are used here (if you 164 | | don't like 'em, tough!) 165 | \*-----------------------------------------------------------------------*/ 166 | 167 | boolean 168 | z80_emulator(z80info *z80, int count) 169 | { 170 | byte t = 0, t1, t2, cy, v, *r = NULL; 171 | word tt, tt2, vv, *rr; 172 | longword ttt; 173 | int i, j, h, n, s; 174 | 175 | /* main loop -- all "goto"s eventually end up here */ 176 | infloop: 177 | 178 | /* only execute "count" instructions at one whack */ 179 | if (count-- <= 0) 180 | return TRUE; 181 | 182 | /* see if the z80 is to be interrupted for any reason */ 183 | if (EVENT) 184 | { 185 | EVENT = FALSE; 186 | 187 | /* HALT execution if desired - this is for tracing & such */ 188 | if (HALT) 189 | haltcpu(z80); 190 | 191 | /* "i" is used to see if we need to get the next opcode or not*/ 192 | i = TRUE; 193 | 194 | /* get the interrupt type -- use a sequence of "if" statements 195 | instead of a "switch" since the order is important -- each 196 | interrupt resets itself only so that another one will run */ 197 | 198 | if (RESET) /* RESET "line" has been "pulled" */ 199 | { 200 | IFF = 0; 201 | IFF2 = 0; 202 | I = 0; 203 | R = 0; 204 | PC = 0; 205 | IMODE = 0; 206 | RESET = FALSE; 207 | if (NMI || INTR) /* catch these the next time */ 208 | EVENT = TRUE; 209 | } 210 | else if (NMI) /* non-maskable interrupt */ 211 | { 212 | --SP; 213 | SETMEM(SP, PC >> 8); 214 | --SP; 215 | SETMEM(SP, PC & MASK8); 216 | PC = 0x66; 217 | IFF = 0; 218 | NMI = FALSE; 219 | if (INTR) /* catch this the next time */ 220 | EVENT = TRUE; 221 | } 222 | else if (INTR && IFF) /* normal masked interrupt */ 223 | { 224 | /* we have three interrupt modes in the z80 */ 225 | switch (IMODE) 226 | { 227 | case 0: /* 8080-mode -- this is NOT correct */ 228 | /* get the next instruction from the interrupting 229 | device - this may be more than one byte but we 230 | cannot handle that yet */ 231 | i = FALSE; 232 | t = INTR; 233 | break; 234 | case 1: /* like a "rst" to 0x38 */ 235 | default: 236 | --SP; 237 | SETMEM(SP, PC >> 8); 238 | --SP; 239 | SETMEM(SP, PC & MASK8); 240 | PC = 0x38; 241 | break; 242 | case 2: /* most powerful/flexible mode */ 243 | --SP; 244 | SETMEM(SP, PC >> 8); 245 | --SP; 246 | SETMEM(SP, PC & MASK8); 247 | tt = (I << 8) | (INTR & 0xFF); 248 | PC = MEM(tt); 249 | tt++; 250 | PC |= MEM(tt) << 8; 251 | break; 252 | } 253 | IFF = IFF2 = 0; 254 | INTR = 0; 255 | } 256 | else if (INTR) /* try again the next time around */ 257 | EVENT = TRUE; 258 | 259 | /* get the next opcode to execute if we do not have it yet */ 260 | if (i) 261 | { 262 | t = MEM(PC); 263 | PC++; 264 | } 265 | } 266 | else 267 | { 268 | /* just get the next opcode */ 269 | t = MEM(PC); 270 | PC++; 271 | } 272 | 273 | 274 | /* main "switch" for initial opcode */ 275 | switch (t) 276 | { 277 | /* go to other switch statements for the multi-byte opcodes */ 278 | case 0xDD: 279 | case 0xFD: /* index-register instructions */ 280 | goto ireginstr; 281 | break; 282 | case 0xED: /* extended instructions */ 283 | goto extinstr; 284 | break; 285 | case 0xCB: /* bit-twiddling instructions */ 286 | goto bitinstr; 287 | break; 288 | 289 | 290 | /* 8-bit load group */ 291 | 292 | case 0x40: /* ld b,b */ 293 | case 0x41: /* ld b,c */ 294 | case 0x42: /* ld b,d */ 295 | case 0x43: /* ld b,e */ 296 | case 0x44: /* ld b,h */ 297 | case 0x45: /* ld b,l */ 298 | case 0x47: /* ld b,a */ 299 | case 0x48: /* ld c,b */ 300 | case 0x49: /* ld c,c */ 301 | case 0x4A: /* ld c,d */ 302 | case 0x4B: /* ld c,e */ 303 | case 0x4C: /* ld c,h */ 304 | case 0x4D: /* ld c,l */ 305 | case 0x4F: /* ld c,a */ 306 | case 0x50: /* ld d,b */ 307 | case 0x51: /* ld d,c */ 308 | case 0x52: /* ld d,d */ 309 | case 0x53: /* ld d,e */ 310 | case 0x54: /* ld d,h */ 311 | case 0x55: /* ld d,l */ 312 | case 0x57: /* ld d,a */ 313 | case 0x58: /* ld e,b */ 314 | case 0x59: /* ld e,c */ 315 | case 0x5A: /* ld e,d */ 316 | case 0x5B: /* ld e,e */ 317 | case 0x5C: /* ld e,h */ 318 | case 0x5D: /* ld e,l */ 319 | case 0x5F: /* ld e,a */ 320 | case 0x60: /* ld h,b */ 321 | case 0x61: /* ld h,c */ 322 | case 0x62: /* ld h,d */ 323 | case 0x63: /* ld h,e */ 324 | case 0x64: /* ld h,h */ 325 | case 0x65: /* ld h,l */ 326 | case 0x67: /* ld h,a */ 327 | case 0x68: /* ld l,b */ 328 | case 0x69: /* ld l,c */ 329 | case 0x6A: /* ld l,d */ 330 | case 0x6B: /* ld l,e */ 331 | case 0x6C: /* ld l,h */ 332 | case 0x6D: /* ld l,l */ 333 | case 0x6F: /* ld l,a */ 334 | case 0x78: /* ld a,b */ 335 | case 0x79: /* ld a,c */ 336 | case 0x7A: /* ld a,d */ 337 | case 0x7B: /* ld a,e */ 338 | case 0x7C: /* ld a,h */ 339 | case 0x7D: /* ld a,l */ 340 | case 0x7F: /* ld a,a */ 341 | *REG[(t >> 3) & MASK3] = *REG[t & MASK3]; 342 | break; 343 | 344 | case 0x46: /* ld b,(hl) */ 345 | case 0x4E: /* ld c,(hl) */ 346 | case 0x56: /* ld d,(hl) */ 347 | case 0x5E: /* ld e,(hl) */ 348 | case 0x66: /* ld h,(hl) */ 349 | case 0x6E: /* ld l,(hl) */ 350 | case 0x7E: /* ld a,(hl) */ 351 | *REG[(t >> 3) & MASK3] = MEM(HL); 352 | break; 353 | 354 | case 0x70: /* ld (hl),b */ 355 | case 0x71: /* ld (hl),c */ 356 | case 0x72: /* ld (hl),d */ 357 | case 0x73: /* ld (hl),e */ 358 | case 0x74: /* ld (hl),h */ 359 | case 0x75: /* ld (hl),l */ 360 | case 0x77: /* ld (hl),a */ 361 | SETMEM(HL, *REG[t & MASK3]); 362 | break; 363 | 364 | case 0x06: /* ld b,n */ 365 | case 0x0E: /* ld c,n */ 366 | case 0x16: /* ld d,n */ 367 | case 0x1E: /* ld e,n */ 368 | case 0x26: /* ld h,n */ 369 | case 0x2E: /* ld l,n */ 370 | case 0x3E: /* ld a,n */ 371 | *REG[(t >> 3) & MASK3] = MEM(PC); 372 | PC++; 373 | break; 374 | case 0x36: /* ld (hl),nn */ 375 | t1 = MEM(PC); 376 | PC++; 377 | SETMEM(HL, t1); 378 | break; 379 | 380 | case 0x0A: /* ld a,(bc) */ 381 | case 0x1A: /* ld a,(de) */ 382 | A = MEM(*REGPAIRAF[t >> 4]); 383 | break; 384 | 385 | case 0x02: /* ld (bc),a */ 386 | case 0x12: /* ld (de),a */ 387 | SETMEM(*REGPAIRAF[t >> 4], A); 388 | break; 389 | 390 | case 0x3A: /* ld a,(nn) */ 391 | t = MEM(PC); 392 | PC++; 393 | t1 = MEM(PC); 394 | A = MEM((t1 << 8) | t); 395 | PC++; 396 | break; 397 | case 0x32: /* ld (nn),a */ 398 | t = MEM(PC); 399 | PC++; 400 | t1 = MEM(PC); 401 | PC++; 402 | SETMEM((t1 << 8) | t, A); 403 | break; 404 | 405 | 406 | /* 16-bit load group */ 407 | 408 | case 0x01: /* ld bc,nn */ 409 | case 0x11: /* ld de,nn */ 410 | case 0x21: /* ld hl,nn */ 411 | case 0x31: /* ld sp,nn */ 412 | tt = MEM(PC); 413 | PC++; 414 | tt |= MEM(PC) << 8; 415 | PC++; 416 | *REGPAIRSP[(t >> 4) & MASK2] = tt; 417 | break; 418 | 419 | case 0x2A: /* ld hl,(nn) */ 420 | tt = MEM(PC); 421 | PC++; 422 | tt |= MEM(PC) << 8; 423 | PC++; 424 | L = MEM(tt); 425 | tt++; 426 | H = MEM(tt); 427 | break; 428 | 429 | case 0x22: /* ld (nn),hl */ 430 | tt = MEM(PC); 431 | PC++; 432 | tt |= MEM(PC) << 8; 433 | PC++; 434 | SETMEM(tt, L); 435 | tt++; 436 | SETMEM(tt, H); 437 | break; 438 | 439 | case 0xF9: /* ld sp,hl */ 440 | SP = HL; 441 | break; 442 | 443 | case 0xC5: /* push bc */ 444 | case 0xD5: /* push de */ 445 | case 0xE5: /* push hl */ 446 | case 0xF5: /* push af */ 447 | tt = *REGPAIRAF[(t >> 4) & MASK2]; 448 | --SP; 449 | SETMEM(SP, tt >> 8); 450 | --SP; 451 | SETMEM(SP, tt & MASK8); 452 | break; 453 | 454 | case 0xC1: /* pop bc */ 455 | case 0xD1: /* pop de */ 456 | case 0xE1: /* pop hl */ 457 | case 0xF1: /* pop af */ 458 | rr = REGPAIRAF[(t >> 4) & MASK2]; 459 | *rr = MEM(SP); 460 | SP++; 461 | *rr |= MEM(SP) << 8; 462 | SP++; 463 | break; 464 | 465 | 466 | /* exchange group and block transfer & search group */ 467 | 468 | case 0x08: /* ex af,af2 */ 469 | swapw(AF, AF2); 470 | break; 471 | case 0xEB: /* ex de,hl */ 472 | swapw(DE, HL); 473 | break; 474 | case 0xD9: /* exx */ 475 | swapw(BC, BC2); 476 | swapw(DE, DE2); 477 | swapw(HL, HL2); 478 | break; 479 | case 0xE3: /* ex (sp),hl */ 480 | t1 = L; 481 | L = MEM(SP); 482 | SETMEM(SP, t1); 483 | t1 = H; 484 | H = MEM((SP + 1) & MASK16); 485 | SETMEM((SP + 1) & MASK16, t1); 486 | break; 487 | 488 | 489 | /* 8-bit arithmetic & logical group */ 490 | 491 | case 0x80: /* add a,b */ 492 | case 0x81: /* add a,c */ 493 | case 0x82: /* add a,d */ 494 | case 0x83: /* add a,e */ 495 | case 0x84: /* add a,h */ 496 | case 0x85: /* add a,l */ 497 | case 0x87: /* add a,a */ 498 | case 0x88: /* adc a,b */ 499 | case 0x89: /* adc a,c */ 500 | case 0x8A: /* adc a,d */ 501 | case 0x8B: /* adc a,e */ 502 | case 0x8C: /* adc a,h */ 503 | case 0x8D: /* adc a,l */ 504 | case 0x8F: /* adc a,a */ 505 | case 0x90: /* sub b */ 506 | case 0x91: /* sub c */ 507 | case 0x92: /* sub d */ 508 | case 0x93: /* sub e */ 509 | case 0x94: /* sub h */ 510 | case 0x95: /* sub l */ 511 | case 0x97: /* sub a */ 512 | case 0x98: /* sbc a,b */ 513 | case 0x99: /* sbc a,c */ 514 | case 0x9A: /* sbc a,d */ 515 | case 0x9B: /* sbc a,e */ 516 | case 0x9C: /* sbc a,h */ 517 | case 0x9D: /* sbc a,l */ 518 | case 0x9F: /* sbc a,a */ 519 | arith8(*REG[t & MASK3], t & BIT3, t & BIT4); 520 | A = v; 521 | break; 522 | case 0x86: /* add a,(hl) */ 523 | case 0x8E: /* adc a,(hl) */ 524 | case 0x96: /* sub (hl) */ 525 | case 0x9E: /* sbc a,(hl) */ 526 | arith8(MEM(HL), t & BIT3, t & BIT4); 527 | A = v; 528 | break; 529 | case 0xC6: /* add a,n */ 530 | case 0xCE: /* adc a,n */ 531 | case 0xD6: /* sub n */ 532 | case 0xDE: /* sbc a,n */ 533 | arith8(MEM(PC), t & BIT3, t & BIT4); 534 | PC++; 535 | A = v; 536 | break; 537 | 538 | case 0xA0: /* and b */ 539 | case 0xA1: /* and c */ 540 | case 0xA2: /* and d */ 541 | case 0xA3: /* and e */ 542 | case 0xA4: /* and h */ 543 | case 0xA5: /* and l */ 544 | case 0xA7: /* and a */ 545 | A &= *REG[t & MASK3]; 546 | logical(1); 547 | break; 548 | case 0xA6: /* and (hl) */ 549 | A &= MEM(HL); 550 | logical(1); 551 | break; 552 | case 0xE6: /* and n */ 553 | A &= MEM(PC); 554 | PC++; 555 | logical(1); 556 | break; 557 | 558 | case 0xA8: /* xor b */ 559 | case 0xA9: /* xor c */ 560 | case 0xAA: /* xor d */ 561 | case 0xAB: /* xor e */ 562 | case 0xAC: /* xor h */ 563 | case 0xAD: /* xor l */ 564 | case 0xAF: /* xor a */ 565 | A ^= *REG[t & MASK3]; 566 | logical(0); 567 | break; 568 | case 0xAE: /* xor (hl) */ 569 | A ^= MEM(HL); 570 | logical(0); 571 | break; 572 | case 0xEE: /* xor n */ 573 | A ^= MEM(PC); 574 | PC++; 575 | logical(0); 576 | break; 577 | 578 | case 0xB0: /* or b */ 579 | case 0xB1: /* or c */ 580 | case 0xB2: /* or d */ 581 | case 0xB3: /* or e */ 582 | case 0xB4: /* or h */ 583 | case 0xB5: /* or l */ 584 | case 0xB7: /* or a */ 585 | A |= *REG[t & MASK3]; 586 | logical(0); 587 | break; 588 | case 0xB6: /* or (hl) */ 589 | A |= MEM(HL); 590 | logical(0); 591 | break; 592 | case 0xF6: /* or n */ 593 | A |= MEM(PC); 594 | PC++; 595 | logical(0); 596 | break; 597 | 598 | case 0xB8: /* cp b */ 599 | case 0xB9: /* cp c */ 600 | case 0xBA: /* cp d */ 601 | case 0xBB: /* cp e */ 602 | case 0xBC: /* cp h */ 603 | case 0xBD: /* cp l */ 604 | case 0xBF: /* cp a */ 605 | arith8(*REG[t & MASK3], 0, 1); 606 | break; 607 | case 0xBE: /* cp (hl) */ 608 | arith8(MEM(HL), 0, 1); 609 | break; 610 | case 0xFE: /* cp n */ 611 | arith8(MEM(PC), 0, 1); 612 | PC++; 613 | break; 614 | 615 | #ifdef NO_LARGE_SWITCH 616 | /* this is for compilers that cannot handle a large switch statement */ 617 | /* neat, eh? */ 618 | 619 | default: 620 | goto contsw; 621 | } 622 | 623 | goto infloop; 624 | 625 | contsw: 626 | switch (t) 627 | { 628 | #endif /* NO_LARGE_SWITCH */ 629 | 630 | /* still the 8-bit arithmetic & logical group */ 631 | 632 | case 0x04: /* inc b */ 633 | case 0x05: /* dec b */ 634 | case 0x0C: /* inc c */ 635 | case 0x0D: /* dec c */ 636 | case 0x14: /* inc d */ 637 | case 0x15: /* dec d */ 638 | case 0x1C: /* inc e */ 639 | case 0x1D: /* dec e */ 640 | case 0x24: /* inc h */ 641 | case 0x25: /* dec h */ 642 | case 0x2C: /* inc l */ 643 | case 0x2D: /* dec l */ 644 | case 0x3C: /* inc a */ 645 | case 0x3D: /* dec a */ 646 | r = REG[(t >> 3) & MASK3]; 647 | increment(*r, t & BIT0); 648 | *r = tt; 649 | break; 650 | case 0x34: /* inc (hl) */ 651 | case 0x35: /* dec (hl) */ 652 | increment(MEM(HL), t & BIT0); 653 | SETMEM(HL, tt); 654 | break; 655 | 656 | 657 | /* general purpose arithmetic & CPU control groups */ 658 | 659 | case 0x27: /* daa - this is REALLY messy */ 660 | t = 0x00; 661 | if (F & NEGATIVE) 662 | { 663 | if (F & CARRY) 664 | { 665 | if (F & HALF) 666 | { 667 | if ((A & MASKU4) >= 0x60 && (A & MASK4) >= 0x06) 668 | t = 0x9A; 669 | } 670 | else /* no HALF carry */ 671 | { 672 | if ((A & MASKU4) >= 0x70 && (A & MASK4) <= 0x09) 673 | t = 0xA0; 674 | } 675 | } 676 | else /* no CARRY */ 677 | { 678 | if (F & HALF) 679 | { 680 | if ((A & MASKU4) <= 0x80 && (A & MASK4) >= 0x06) 681 | t = 0xFA; 682 | } 683 | } 684 | } 685 | else /* not NEGATIVE */ 686 | { 687 | if (F & CARRY) 688 | { 689 | if (F & HALF) 690 | { 691 | if ((A & MASKU4) <= 0x30 && (A & MASK4) <= 0x03) 692 | t = 0x66; 693 | } 694 | else /* no HALF */ 695 | { 696 | if ((A & MASKU4) <= 0x20) 697 | if ((A & MASK4) <= 0x09) 698 | { 699 | t = 0x60; 700 | } 701 | else 702 | t = 0x66; 703 | } 704 | } 705 | else /* no CARRY */ 706 | { 707 | if (F & HALF) 708 | { 709 | if ((A & MASK4) <= 0x03) 710 | if ((A & MASKU4) <= 0x90) 711 | { 712 | t = 0x06; 713 | } 714 | else 715 | t = 0x66; 716 | } 717 | else /* no HALF */ 718 | { 719 | if ((A & MASK4) <= 0x09) 720 | { 721 | if ((A & MASKU4) >= 0xA0) 722 | t = 0x60; 723 | } 724 | else 725 | { 726 | if ((A & MASKU4) <= 0x80) 727 | { 728 | t = 0x06; 729 | } 730 | else 731 | t = 0x66; 732 | } 733 | } 734 | } 735 | } 736 | i = F & NEGATIVE; 737 | arith8(t, 0, 0); 738 | F |= i; 739 | A = v; 740 | setparity(A); 741 | break; 742 | 743 | case 0x2F: /* cpl */ 744 | A = ~A; 745 | flagon(HALF); 746 | flagon(NEGATIVE); 747 | break; 748 | 749 | case 0x3F: /* ccf */ 750 | setflag(CARRY, !(F & CARRY)); 751 | flagoff(NEGATIVE); 752 | break; 753 | case 0x37: /* scf */ 754 | flagon(CARRY); 755 | flagoff(HALF); 756 | flagoff(NEGATIVE); 757 | break; 758 | 759 | case 0x00: /* nop */ 760 | break; 761 | case 0x76: /* HALT */ 762 | /*while (!EVENT) 763 | sleep(1);*/ 764 | EVENT = HALT = TRUE; 765 | break; 766 | 767 | case 0xF3: /* di */ 768 | IFF = IFF2 = 0; 769 | break; 770 | case 0xFB: /* ei */ 771 | IFF = IFF2 = 1; 772 | break; 773 | 774 | 775 | /* 16-bit arithmetic group */ 776 | 777 | case 0x09: /* add hl,bc */ 778 | case 0x19: /* add hl,de */ 779 | case 0x29: /* add hl,hl */ 780 | case 0x39: /* add hl,sp */ 781 | ttt = HL + *REGPAIRSP[(t >> 4) & MASK2]; 782 | flagoff(NEGATIVE); 783 | setflag(CARRY, ttt & BIT16); 784 | HL = ttt; 785 | break; 786 | 787 | case 0x03: /* inc bc */ 788 | case 0x13: /* inc de */ 789 | case 0x23: /* inc hl */ 790 | case 0x33: /* inc sp */ 791 | case 0x0B: /* dec bc */ 792 | case 0x1B: /* dec de */ 793 | case 0x2B: /* dec hl */ 794 | case 0x3B: /* dec sp */ 795 | *REGPAIRSP[(t >> 4) & MASK2] += (t & BIT3) ? -1 : 1; 796 | break; 797 | 798 | 799 | /* rotate & shift group */ 800 | 801 | case 0x07: /* rlca */ 802 | case 0x17: /* rla */ 803 | case 0x0F: /* rrca */ 804 | case 0x1F: /* rra */ 805 | t1 = F & CARRY; 806 | if (t & BIT3) 807 | { 808 | setflag(CARRY, A & BIT0); 809 | A >>= 1; 810 | t2 = BIT7; 811 | } 812 | else 813 | { 814 | setflag(CARRY, A & BIT7); 815 | A <<= 1; 816 | t2 = BIT0; 817 | } 818 | if (t & BIT4) 819 | { 820 | if (t1) 821 | A |= t2; 822 | } 823 | else 824 | { 825 | if (F & CARRY) 826 | A |= t2; 827 | } 828 | flagoff(HALF); 829 | flagoff(NEGATIVE); 830 | break; 831 | 832 | 833 | /* jump group */ 834 | 835 | case 0xC3: /* jp nn */ 836 | tt = MEM(PC); 837 | PC++; 838 | tt |= MEM(PC) << 8; 839 | PC = tt; 840 | break; 841 | case 0xC2: /* jp nz,nn */ 842 | case 0xD2: /* jp nc,nn */ 843 | case 0xE2: /* jp po,nn */ 844 | case 0xF2: /* jp p,nn */ 845 | if (F & flagmask[(t >> 4) & MASK2]) 846 | PC += 2; 847 | else 848 | { 849 | tt = MEM(PC); 850 | PC++; 851 | tt |= MEM(PC) << 8; 852 | PC = tt; 853 | } 854 | break; 855 | case 0xCA: /* jp z,nn */ 856 | case 0xDA: /* jp c,nn */ 857 | case 0xEA: /* jp p,nn */ 858 | case 0xFA: /* jp m,nn */ 859 | if (F & flagmask[(t >> 4) & MASK2]) 860 | { 861 | tt = MEM(PC); 862 | PC++; 863 | tt |= MEM(PC) << 8; 864 | PC = tt; 865 | } 866 | else 867 | PC += 2; 868 | break; 869 | 870 | case 0x18: /* jr e */ 871 | PC += ((signed char)MEM(PC)) + 1; 872 | break; 873 | case 0x20: /* jr nz,e */ 874 | case 0x30: /* jr nc,e */ 875 | if (!(F & flagmask[(t >> 4) & MASK1])) 876 | PC += ((signed char)MEM(PC)) + 1; 877 | else 878 | PC += 1; 879 | break; 880 | case 0x28: /* jr z,e */ 881 | case 0x38: /* jr c,e */ 882 | if (F & flagmask[(t >> 4) & MASK1]) 883 | PC += ((signed char)MEM(PC)) + 1; 884 | else 885 | PC += 1; 886 | break; 887 | 888 | case 0xE9: /* jp (hl) */ 889 | PC = HL; 890 | break; 891 | case 0x10: /* djnz e */ 892 | if (--B) 893 | PC += ((signed char)MEM(PC)) + 1; 894 | else 895 | PC += 1; 896 | break; 897 | 898 | 899 | /* call & return group */ 900 | 901 | case 0xCD: /* call nn */ 902 | tt = MEM(PC); 903 | PC++; 904 | tt |= MEM(PC) << 8; 905 | PC++; 906 | --SP; 907 | SETMEM(SP, PC >> 8); 908 | --SP; 909 | SETMEM(SP, PC & MASK8); 910 | PC = tt; 911 | break; 912 | case 0xC4: /* call nz,nn */ 913 | case 0xD4: /* call nc,nn */ 914 | case 0xE4: /* call po,nn */ 915 | case 0xF4: /* call p,nn */ 916 | if (F & flagmask[(t >> 4) & MASK2]) 917 | PC += 2; 918 | else 919 | { 920 | tt = MEM(PC); 921 | PC++; 922 | tt |= MEM(PC) << 8; 923 | PC++; 924 | --SP; 925 | SETMEM(SP, PC >> 8); 926 | --SP; 927 | SETMEM(SP, PC & MASK8); 928 | PC = tt; 929 | } 930 | break; 931 | case 0xCC: /* call z,nn */ 932 | case 0xDC: /* call c,nn */ 933 | case 0xEC: /* call pe,nn */ 934 | case 0xFC: /* call m,nn */ 935 | if (F & flagmask[(t >> 4) & MASK2]) 936 | { 937 | tt = MEM(PC); 938 | PC++; 939 | tt |= MEM(PC) << 8; 940 | PC++; 941 | --SP; 942 | SETMEM(SP, PC >> 8); 943 | --SP; 944 | SETMEM(SP, PC & MASK8); 945 | PC = tt; 946 | } 947 | else 948 | PC += 2; 949 | break; 950 | 951 | case 0xC9: /* ret */ 952 | PC = MEM(SP); 953 | SP++; 954 | PC |= MEM(SP) << 8; 955 | SP++; 956 | break; 957 | case 0xC0: /* ret nz */ 958 | case 0xD0: /* ret nc */ 959 | case 0xE0: /* ret po */ 960 | case 0xF0: /* ret p */ 961 | if (!(F & flagmask[(t >> 4) & MASK2])) 962 | { 963 | PC = MEM(SP); 964 | SP++; 965 | PC |= MEM(SP) << 8; 966 | SP++; 967 | } 968 | break; 969 | case 0xC8: /* ret z */ 970 | case 0xD8: /* ret c */ 971 | case 0xE8: /* ret pe */ 972 | case 0xF8: /* ret m */ 973 | if (F & flagmask[(t >> 4) & MASK2]) 974 | { 975 | PC = MEM(SP); 976 | SP++; 977 | PC |= MEM(SP) << 8; 978 | SP++; 979 | } 980 | break; 981 | 982 | case 0xC7: /* rst 0 */ 983 | case 0xCF: /* rst 8 */ 984 | case 0xD7: /* rst 16 */ 985 | case 0xDF: /* rst 24 */ 986 | case 0xE7: /* rst 32 */ 987 | case 0xEF: /* rst 40 */ 988 | case 0xF7: /* rst 48 */ 989 | case 0xFF: /* rst 56 */ 990 | --SP; 991 | SETMEM(SP, PC >> 8); 992 | --SP; 993 | SETMEM(SP, PC & MASK8); 994 | PC = t & 0x38; 995 | break; 996 | 997 | 998 | /* input & output group */ 999 | 1000 | case 0xDB: /* in a,n */ 1001 | if (!input(z80, A, MEM(PC), &t1)) 1002 | return FALSE; 1003 | 1004 | A = t1; 1005 | PC++; 1006 | break; 1007 | case 0xD3: /* out a,n */ 1008 | output(z80, A, MEM(PC), A); 1009 | PC++; 1010 | break; 1011 | 1012 | 1013 | default: 1014 | undefinstr(z80, t); 1015 | break; 1016 | } /* end of main "switch" */ 1017 | 1018 | goto infloop; 1019 | 1020 | 1021 | 1022 | /* bit-twiddling instructions */ 1023 | bitinstr: 1024 | t = MEM(PC); 1025 | PC++; 1026 | 1027 | switch (t) 1028 | { 1029 | /* rotate & shift group */ 1030 | 1031 | case 0x00: /* rlc b */ 1032 | case 0x01: /* rlc c */ 1033 | case 0x02: /* rlc d */ 1034 | case 0x03: /* rlc e */ 1035 | case 0x04: /* rlc h */ 1036 | case 0x05: /* rlc l */ 1037 | case 0x07: /* rlc a */ 1038 | case 0x08: /* rrc b */ 1039 | case 0x09: /* rrc c */ 1040 | case 0x0A: /* rrc d */ 1041 | case 0x0B: /* rrc e */ 1042 | case 0x0C: /* rrc h */ 1043 | case 0x0D: /* rrc l */ 1044 | case 0x0F: /* rrc a */ 1045 | case 0x10: /* rl b */ 1046 | case 0x11: /* rl c */ 1047 | case 0x12: /* rl d */ 1048 | case 0x13: /* rl e */ 1049 | case 0x14: /* rl h */ 1050 | case 0x15: /* rl l */ 1051 | case 0x17: /* rl a */ 1052 | case 0x18: /* rr b */ 1053 | case 0x19: /* rr c */ 1054 | case 0x1A: /* rr d */ 1055 | case 0x1B: /* rr e */ 1056 | case 0x1C: /* rr h */ 1057 | case 0x1D: /* rr l */ 1058 | case 0x1F: /* rr a */ 1059 | case 0x20: /* sla b */ 1060 | case 0x21: /* sla c */ 1061 | case 0x22: /* sla d */ 1062 | case 0x23: /* sla e */ 1063 | case 0x24: /* sla h */ 1064 | case 0x25: /* sla l */ 1065 | case 0x27: /* sla a */ 1066 | case 0x28: /* sra b */ 1067 | case 0x29: /* sra c */ 1068 | case 0x2A: /* sra d */ 1069 | case 0x2B: /* sra e */ 1070 | case 0x2C: /* sra h */ 1071 | case 0x2D: /* sra l */ 1072 | case 0x2F: /* sra a */ 1073 | case 0x38: /* srl b */ 1074 | case 0x39: /* srl c */ 1075 | case 0x3A: /* srl d */ 1076 | case 0x3B: /* srl e */ 1077 | case 0x3C: /* srl h */ 1078 | case 0x3D: /* srl l */ 1079 | case 0x3F: /* srl a */ 1080 | r = REG[t & MASK3]; 1081 | cy = F & CARRY; 1082 | if (t & BIT3) 1083 | { 1084 | setflag(CARRY, *r & BIT0); 1085 | *r >>= 1; 1086 | t2 = BIT7; 1087 | } 1088 | else 1089 | { 1090 | setflag(CARRY, *r & BIT7); 1091 | *r <<= 1; 1092 | t2 = BIT0; 1093 | } 1094 | if (t & BIT5) 1095 | { 1096 | if (t2 == BIT7 && !(t & BIT4)) 1097 | if (*r & BIT6) 1098 | *r |= BIT7; 1099 | } 1100 | else 1101 | { 1102 | if (t & BIT4) 1103 | { 1104 | if (cy) 1105 | *r |= t2; 1106 | } 1107 | else 1108 | { 1109 | if (F & CARRY) 1110 | *r |= t2; 1111 | } 1112 | } 1113 | flags(*r); 1114 | break; 1115 | 1116 | case 0x06: /* rlc (hl) */ 1117 | case 0x0E: /* rrc (hl) */ 1118 | case 0x16: /* rl (hl) */ 1119 | case 0x1E: /* rr (hl) */ 1120 | case 0x26: /* sla (hl) */ 1121 | case 0x2E: /* sra (hl) */ 1122 | case 0x3E: /* srl (hl) */ 1123 | cy = F & CARRY; 1124 | t1 = MEM(HL); 1125 | if (t & BIT3) 1126 | { 1127 | setflag(CARRY, t1 & BIT0); 1128 | t1 >>= 1; 1129 | t2 = BIT7; 1130 | } 1131 | else 1132 | { 1133 | setflag(CARRY, t1 & BIT7); 1134 | t1 <<= 1; 1135 | t2 = BIT0; 1136 | } 1137 | if (t & BIT5) 1138 | { 1139 | if (t2 == BIT7 && !(t & BIT4)) 1140 | if (t1 & BIT6) 1141 | t1 |= BIT7; 1142 | } 1143 | else 1144 | { 1145 | if (t & BIT4) 1146 | { 1147 | if (cy) 1148 | t1 |= t2; 1149 | } 1150 | else 1151 | { 1152 | if (F & CARRY) 1153 | t1 |= t2; 1154 | } 1155 | } 1156 | SETMEM(HL, t1); 1157 | flags(t1); 1158 | break; 1159 | 1160 | 1161 | /* bit set, reset, and test group */ 1162 | 1163 | case 0x40: /* bit 0,b */ 1164 | case 0x41: /* bit 0,c */ 1165 | case 0x42: /* bit 0,d */ 1166 | case 0x43: /* bit 0,e */ 1167 | case 0x44: /* bit 0,h */ 1168 | case 0x45: /* bit 0,l */ 1169 | case 0x47: /* bit 0,a */ 1170 | case 0x48: /* bit 1,b */ 1171 | case 0x49: /* bit 1,c */ 1172 | case 0x4A: /* bit 1,d */ 1173 | case 0x4B: /* bit 1,e */ 1174 | case 0x4C: /* bit 1,h */ 1175 | case 0x4D: /* bit 1,l */ 1176 | case 0x4F: /* bit 1,a */ 1177 | case 0x50: /* bit 2,b */ 1178 | case 0x51: /* bit 2,c */ 1179 | case 0x52: /* bit 2,d */ 1180 | case 0x53: /* bit 2,e */ 1181 | case 0x54: /* bit 2,h */ 1182 | case 0x55: /* bit 2,l */ 1183 | case 0x57: /* bit 2,a */ 1184 | case 0x58: /* bit 3,b */ 1185 | case 0x59: /* bit 3,c */ 1186 | case 0x5A: /* bit 3,d */ 1187 | case 0x5B: /* bit 3,e */ 1188 | case 0x5C: /* bit 3,h */ 1189 | case 0x5D: /* bit 3,l */ 1190 | case 0x5F: /* bit 3,a */ 1191 | case 0x60: /* bit 4,b */ 1192 | case 0x61: /* bit 4,c */ 1193 | case 0x62: /* bit 4,d */ 1194 | case 0x63: /* bit 4,e */ 1195 | case 0x64: /* bit 4,h */ 1196 | case 0x65: /* bit 4,l */ 1197 | case 0x67: /* bit 4,a */ 1198 | case 0x68: /* bit 5,b */ 1199 | case 0x69: /* bit 5,c */ 1200 | case 0x6A: /* bit 5,d */ 1201 | case 0x6B: /* bit 5,e */ 1202 | case 0x6C: /* bit 5,h */ 1203 | case 0x6D: /* bit 5,l */ 1204 | case 0x6F: /* bit 5,a */ 1205 | case 0x70: /* bit 6,b */ 1206 | case 0x71: /* bit 6,c */ 1207 | case 0x72: /* bit 6,d */ 1208 | case 0x73: /* bit 6,e */ 1209 | case 0x74: /* bit 6,h */ 1210 | case 0x75: /* bit 6,l */ 1211 | case 0x77: /* bit 6,a */ 1212 | case 0x78: /* bit 7,b */ 1213 | case 0x79: /* bit 7,c */ 1214 | case 0x7A: /* bit 7,d */ 1215 | case 0x7B: /* bit 7,e */ 1216 | case 0x7C: /* bit 7,h */ 1217 | case 0x7D: /* bit 7,l */ 1218 | case 0x7F: /* bit 7,a */ 1219 | r = REG[t & MASK3]; 1220 | resetflag(ZERO, *r & bitmask[(t >> 3) & MASK3]); 1221 | flagon(HALF); 1222 | flagoff(NEGATIVE); 1223 | break; 1224 | case 0x46: /* bit 0,(hl) */ 1225 | case 0x4E: /* bit 1,(hl) */ 1226 | case 0x56: /* bit 2,(hl) */ 1227 | case 0x5E: /* bit 3,(hl) */ 1228 | case 0x66: /* bit 4,(hl) */ 1229 | case 0x6E: /* bit 5,(hl) */ 1230 | case 0x76: /* bit 6,(hl) */ 1231 | case 0x7E: /* bit 7,(hl) */ 1232 | resetflag(ZERO, MEM(HL) & bitmask[(t >> 3) & MASK3]); 1233 | flagon(HALF); 1234 | flagoff(NEGATIVE); 1235 | break; 1236 | 1237 | case 0x80: /* res 0,b */ 1238 | case 0x81: /* res 0,c */ 1239 | case 0x82: /* res 0,d */ 1240 | case 0x83: /* res 0,e */ 1241 | case 0x84: /* res 0,h */ 1242 | case 0x85: /* res 0,l */ 1243 | case 0x87: /* res 0,a */ 1244 | case 0x88: /* res 1,b */ 1245 | case 0x89: /* res 1,c */ 1246 | case 0x8A: /* res 1,d */ 1247 | case 0x8B: /* res 1,e */ 1248 | case 0x8C: /* res 1,h */ 1249 | case 0x8D: /* res 1,l */ 1250 | case 0x8F: /* res 1,a */ 1251 | case 0x90: /* res 2,b */ 1252 | case 0x91: /* res 2,c */ 1253 | case 0x92: /* res 2,d */ 1254 | case 0x93: /* res 2,e */ 1255 | case 0x94: /* res 2,h */ 1256 | case 0x95: /* res 2,l */ 1257 | case 0x97: /* res 2,a */ 1258 | case 0x98: /* res 3,b */ 1259 | case 0x99: /* res 3,c */ 1260 | case 0x9A: /* res 3,d */ 1261 | case 0x9B: /* res 3,e */ 1262 | case 0x9C: /* res 3,h */ 1263 | case 0x9D: /* res 3,l */ 1264 | case 0x9F: /* res 3,a */ 1265 | case 0xA0: /* res 4,b */ 1266 | case 0xA1: /* res 4,c */ 1267 | case 0xA2: /* res 4,d */ 1268 | case 0xA3: /* res 4,e */ 1269 | case 0xA4: /* res 4,h */ 1270 | case 0xA5: /* res 4,l */ 1271 | case 0xA7: /* res 4,a */ 1272 | case 0xA8: /* res 5,b */ 1273 | case 0xA9: /* res 5,c */ 1274 | case 0xAA: /* res 5,d */ 1275 | case 0xAB: /* res 5,e */ 1276 | case 0xAC: /* res 5,h */ 1277 | case 0xAD: /* res 5,l */ 1278 | case 0xAF: /* res 5,a */ 1279 | case 0xB0: /* res 6,b */ 1280 | case 0xB1: /* res 6,c */ 1281 | case 0xB2: /* res 6,d */ 1282 | case 0xB3: /* res 6,e */ 1283 | case 0xB4: /* res 6,h */ 1284 | case 0xB5: /* res 6,l */ 1285 | case 0xB7: /* res 6,a */ 1286 | case 0xB8: /* res 7,b */ 1287 | case 0xB9: /* res 7,c */ 1288 | case 0xBA: /* res 7,d */ 1289 | case 0xBB: /* res 7,e */ 1290 | case 0xBC: /* res 7,h */ 1291 | case 0xBD: /* res 7,l */ 1292 | case 0xBF: /* res 7,a */ 1293 | *REG[t & MASK3] &= ~bitmask[(t >> 3) & MASK3]; 1294 | break; 1295 | case 0x86: /* res 0,(hl) */ 1296 | case 0x8E: /* res 1,(hl) */ 1297 | case 0x96: /* res 2,(hl) */ 1298 | case 0x9E: /* res 3,(hl) */ 1299 | case 0xA6: /* res 4,(hl) */ 1300 | case 0xAE: /* res 5,(hl) */ 1301 | case 0xB6: /* res 6,(hl) */ 1302 | case 0xBE: /* res 7,(hl) */ 1303 | t1 = MEM(HL) & ~bitmask[(t >> 3) & MASK3]; 1304 | SETMEM(HL, t1); 1305 | break; 1306 | 1307 | 1308 | case 0xC0: /* set 0,b */ 1309 | case 0xC1: /* set 0,c */ 1310 | case 0xC2: /* set 0,d */ 1311 | case 0xC3: /* set 0,e */ 1312 | case 0xC4: /* set 0,h */ 1313 | case 0xC5: /* set 0,l */ 1314 | case 0xC7: /* set 0,a */ 1315 | case 0xC8: /* set 1,b */ 1316 | case 0xC9: /* set 1,c */ 1317 | case 0xCA: /* set 1,d */ 1318 | case 0xCB: /* set 1,e */ 1319 | case 0xCC: /* set 1,h */ 1320 | case 0xCD: /* set 1,l */ 1321 | case 0xCF: /* set 1,a */ 1322 | case 0xD0: /* set 2,b */ 1323 | case 0xD1: /* set 2,c */ 1324 | case 0xD2: /* set 2,d */ 1325 | case 0xD3: /* set 2,e */ 1326 | case 0xD4: /* set 2,h */ 1327 | case 0xD5: /* set 2,l */ 1328 | case 0xD7: /* set 2,a */ 1329 | case 0xD8: /* set 3,b */ 1330 | case 0xD9: /* set 3,c */ 1331 | case 0xDA: /* set 3,d */ 1332 | case 0xDB: /* set 3,e */ 1333 | case 0xDC: /* set 3,h */ 1334 | case 0xDD: /* set 3,l */ 1335 | case 0xDF: /* set 3,a */ 1336 | case 0xE0: /* set 4,b */ 1337 | case 0xE1: /* set 4,c */ 1338 | case 0xE2: /* set 4,d */ 1339 | case 0xE3: /* set 4,e */ 1340 | case 0xE4: /* set 4,h */ 1341 | case 0xE5: /* set 4,l */ 1342 | case 0xE7: /* set 4,a */ 1343 | case 0xE8: /* set 5,b */ 1344 | case 0xE9: /* set 5,c */ 1345 | case 0xEA: /* set 5,d */ 1346 | case 0xEB: /* set 5,e */ 1347 | case 0xEC: /* set 5,h */ 1348 | case 0xED: /* set 5,l */ 1349 | case 0xEF: /* set 5,a */ 1350 | case 0xF0: /* set 6,b */ 1351 | case 0xF1: /* set 6,c */ 1352 | case 0xF2: /* set 6,d */ 1353 | case 0xF3: /* set 6,e */ 1354 | case 0xF4: /* set 6,h */ 1355 | case 0xF5: /* set 6,l */ 1356 | case 0xF7: /* set 6,a */ 1357 | case 0xF8: /* set 7,b */ 1358 | case 0xF9: /* set 7,c */ 1359 | case 0xFA: /* set 7,d */ 1360 | case 0xFB: /* set 7,e */ 1361 | case 0xFC: /* set 7,h */ 1362 | case 0xFD: /* set 7,l */ 1363 | case 0xFF: /* set 7,a */ 1364 | *REG[t & MASK3] |= bitmask[(t >> 3) & MASK3]; 1365 | break; 1366 | 1367 | case 0xC6: /* set 0,(hl) */ 1368 | case 0xCE: /* set 1,(hl) */ 1369 | case 0xD6: /* set 2,(hl) */ 1370 | case 0xDE: /* set 3,(hl) */ 1371 | case 0xE6: /* set 4,(hl) */ 1372 | case 0xEE: /* set 5,(hl) */ 1373 | case 0xF6: /* set 6,(hl) */ 1374 | case 0xFE: /* set 7,(hl) */ 1375 | t1 = MEM(HL) | bitmask[(t >> 3) & MASK3]; 1376 | SETMEM(HL, t1); 1377 | break; 1378 | 1379 | default: 1380 | undefinstr(z80, t); 1381 | break; 1382 | } /* end of "bitinstr" "switch" */ 1383 | 1384 | goto infloop; 1385 | 1386 | 1387 | 1388 | /* index-register instructions */ 1389 | ireginstr: 1390 | 1391 | /* pointer to either the IX or the IY register */ 1392 | rr = REGIXY[(t >> 5) & MASK1]; 1393 | t = MEM(PC); 1394 | PC++; 1395 | 1396 | /* note: in comments below, "ir" is either "ix" or "iy" */ 1397 | switch (t) 1398 | { 1399 | case 0xCB: /* index-register bit-twiddling instructions */ 1400 | goto iregbitinstr; 1401 | break; 1402 | 1403 | 1404 | /* 8-bit load group */ 1405 | 1406 | case 0x46: /* ld b,(ir+d) */ 1407 | case 0x4E: /* ld c,(ir+d) */ 1408 | case 0x56: /* ld d,(ir+d) */ 1409 | case 0x5E: /* ld e,(ir+d) */ 1410 | case 0x66: /* ld h,(ir+d) */ 1411 | case 0x6E: /* ld l,(ir+d) */ 1412 | case 0x7E: /* ld a,(ir+d) */ 1413 | i = (t >> 3) & MASK3; 1414 | j = (int)((signed char)MEM(PC)); 1415 | PC++; 1416 | *REG[i] = MEM(((int)*rr + j) & MASK16); 1417 | break; 1418 | 1419 | case 0x70: /* ld (ir+d),b */ 1420 | case 0x71: /* ld (ir+d),c */ 1421 | case 0x72: /* ld (ir+d),d */ 1422 | case 0x73: /* ld (ir+d),e */ 1423 | case 0x74: /* ld (ir+d),h */ 1424 | case 0x75: /* ld (ir+d),l */ 1425 | case 0x77: /* ld (ir+d),a */ 1426 | t1 = MEM(PC); 1427 | PC++; 1428 | SETMEM(((int)*rr + ((signed char)t1)) & MASK16, *REG[t &MASK3]); 1429 | break; 1430 | 1431 | 1432 | /* 16-bit load group */ 1433 | 1434 | case 0x36: /* ld (ir+d),n */ 1435 | tt = (int)*rr + ((signed char)MEM(PC)); 1436 | PC++; 1437 | t1 = MEM(PC); 1438 | PC++; 1439 | SETMEM(tt, t1); 1440 | break; 1441 | 1442 | case 0x21: /* ld ir,nn */ 1443 | *rr = MEM(PC); 1444 | PC++; 1445 | *rr |= MEM(PC) << 8; 1446 | PC++; 1447 | break; 1448 | 1449 | case 0x2A: /* ld ir,(nn) */ 1450 | tt = MEM(PC); 1451 | PC++; 1452 | tt |= MEM(PC) << 8; 1453 | PC++; 1454 | *rr = MEM(tt); 1455 | tt++; 1456 | *rr |= MEM(tt) << 8; 1457 | break; 1458 | 1459 | case 0x22: /* ld (nn),ir */ 1460 | tt = MEM(PC); 1461 | PC++; 1462 | tt |= MEM(PC) << 8; 1463 | PC++; 1464 | SETMEM(tt, *rr & MASK8); 1465 | tt++; 1466 | SETMEM(tt, *rr >> 8); 1467 | break; 1468 | 1469 | case 0xF9: /* ld sp,ir */ 1470 | SP = *rr; 1471 | break; 1472 | 1473 | case 0xE5: /* push ir */ 1474 | --SP; 1475 | SETMEM(SP, *rr >> 8); 1476 | --SP; 1477 | SETMEM(SP, *rr & MASK8); 1478 | break; 1479 | 1480 | case 0xE1: /* pop ir */ 1481 | *rr = MEM(SP); 1482 | SP++; 1483 | *rr |= MEM(SP) << 8; 1484 | SP++; 1485 | break; 1486 | 1487 | 1488 | /* exchange group */ 1489 | 1490 | case 0xE3: /* ex sp,ir */ 1491 | tt = MEM(SP); 1492 | tt |= MEM(SP + 1) << 8; 1493 | SETMEM(SP, *rr & MASK8); 1494 | SETMEM(SP + 1, *rr >> 8); 1495 | *rr = tt; 1496 | break; 1497 | 1498 | 1499 | /* 8-bit arithmetic group */ 1500 | 1501 | case 0x86: /* add a,(ir+d) */ 1502 | case 0x8E: /* adc a,(ir+d) */ 1503 | case 0x96: /* sub (ir+d) */ 1504 | case 0x9E: /* sbc a,(ir+d) */ 1505 | tt = (int)*rr + ((signed char)MEM(PC)); 1506 | PC++; 1507 | arith8(MEM(tt), t & BIT3, t & BIT4); 1508 | A = v; 1509 | break; 1510 | 1511 | case 0x34: /* inc (ir+d) */ 1512 | case 0x35: /* dec (ir+d) */ 1513 | tt2 = (int)*rr + ((signed char)MEM(PC)); 1514 | PC++; 1515 | increment(MEM(tt2), t & BIT0); 1516 | SETMEM(tt2, tt); 1517 | break; 1518 | 1519 | case 0xA6: /* and (ir+d) */ 1520 | tt = (int)*rr + ((signed char)MEM(PC)); 1521 | PC++; 1522 | A &= MEM(tt); 1523 | logical(1); 1524 | break; 1525 | case 0xAE: /* xor (ir+d) */ 1526 | tt = (int)*rr + ((signed char)MEM(PC)); 1527 | PC++; 1528 | A ^= MEM(tt); 1529 | logical(0); 1530 | break; 1531 | case 0xB6: /* or (ir+d) */ 1532 | tt = (int)*rr + ((signed char)MEM(PC)); 1533 | PC++; 1534 | A |= MEM(tt); 1535 | logical(0); 1536 | break; 1537 | case 0xBE: /* cp (ir+d) */ 1538 | tt = (int)*rr + ((signed char)MEM(PC)); 1539 | PC++; 1540 | arith8(MEM(tt), 0, 1); 1541 | break; 1542 | 1543 | 1544 | /* 16-bit arithmetic group */ 1545 | 1546 | case 0x09: /* add ir,bc */ 1547 | case 0x19: /* add ir,de */ 1548 | case 0x29: /* add ir,rr */ 1549 | case 0x39: /* add ir,sp */ 1550 | REGPAIRXY[XYPAIR] = rr; 1551 | i = *rr; 1552 | j = *REGPAIRXY[(t >> 4) & MASK2]; 1553 | ttt = i + j; 1554 | flagoff(NEGATIVE); 1555 | setflag(CARRY, ttt & BIT16); 1556 | *rr = ttt; 1557 | break; 1558 | 1559 | case 0x23: /* inc ir */ 1560 | case 0x2B: /* dec ir */ 1561 | *rr += (t & BIT3) ? -1 : 1; 1562 | break; 1563 | 1564 | 1565 | /* jump group */ 1566 | 1567 | case 0xE9: /* jp (ir) */ 1568 | PC = *rr; 1569 | break; 1570 | 1571 | 1572 | default: 1573 | undefinstr(z80, t); 1574 | break; 1575 | } /* end of "ireginstr" "switch" */ 1576 | 1577 | goto infloop; 1578 | 1579 | 1580 | 1581 | /* extended instructions */ 1582 | extinstr: 1583 | t = MEM(PC); 1584 | PC++; 1585 | switch (t) 1586 | { 1587 | /* 8-bit load group */ 1588 | 1589 | case 0x57: /* ld a,i */ 1590 | case 0x5F: /* ld a,r */ 1591 | A = *REGIR[(t >> 3) & MASK1]; 1592 | setsign(); 1593 | setzero(); 1594 | flagoff(HALF); 1595 | setflag(PARITY, IFF2); 1596 | flagoff(NEGATIVE); 1597 | break; 1598 | 1599 | case 0x47: /* ld i,a */ 1600 | case 0x4F: /* ld r,a */ 1601 | *REGIR[(t >> 3) & MASK1] = A; 1602 | break; 1603 | 1604 | 1605 | /* 16-bit load group */ 1606 | 1607 | case 0x4B: /* ld bc,(nn) */ 1608 | case 0x5B: /* ld de,(nn) */ 1609 | case 0x6B: /* ld hl,(nn) */ 1610 | case 0x7B: /* ld sp,(nn) */ 1611 | tt = MEM(PC); 1612 | PC++; 1613 | tt |= MEM(PC) << 8; 1614 | PC++; 1615 | tt2 = MEM(tt); 1616 | tt++; 1617 | tt2 |= MEM(tt) << 8; 1618 | *REGPAIRSP[(t >> 4) & MASK2] = tt2; 1619 | break; 1620 | 1621 | case 0x43: /* ld (nn),bc */ 1622 | case 0x53: /* ld (nn),de */ 1623 | case 0x63: /* ld (nn),hl */ 1624 | case 0x73: /* ld (nn),sp */ 1625 | tt = MEM(PC); 1626 | PC++; 1627 | tt |= MEM(PC) << 8; 1628 | PC++; 1629 | tt2 = *REGPAIRSP[(t >> 4) & MASK2]; 1630 | SETMEM(tt, tt2 & MASK8); 1631 | tt++; 1632 | SETMEM(tt, tt2 >> 8); 1633 | break; 1634 | 1635 | 1636 | /* block transfer and search group */ 1637 | 1638 | case 0xA0: /* ldi */ 1639 | case 0xA8: /* ldd */ 1640 | case 0xB0: /* ldir */ 1641 | case 0xB8: /* lddr */ 1642 | if (t & BIT3) 1643 | { 1644 | t1 = MEM(HL); 1645 | HL--; 1646 | SETMEM(DE, t1); 1647 | DE--; 1648 | } 1649 | else 1650 | { 1651 | t1 = MEM(HL); 1652 | HL++; 1653 | SETMEM(DE, t1); 1654 | DE++; 1655 | } 1656 | 1657 | setflag(OVERFLOW, --BC); 1658 | 1659 | if ((t & BIT4) && BC) 1660 | PC -= 2; 1661 | 1662 | flagoff(HALF); 1663 | flagoff(NEGATIVE); 1664 | break; 1665 | 1666 | case 0xA1: /* cpi */ 1667 | case 0xA9: /* cpd */ 1668 | case 0xB1: /* cpir */ 1669 | case 0xB9: /* cpdr */ 1670 | t1 = MEM(HL); 1671 | 1672 | if (t & BIT3) 1673 | HL--; 1674 | else 1675 | HL++; 1676 | 1677 | t2 = A - t1; 1678 | setflag(SIGN, t2 & BIT7); 1679 | setflag(ZERO, !t2); 1680 | setflag(HALF, (A & MASK4) < (t1 & MASK4)); 1681 | setflag(OVERFLOW, --BC); 1682 | flagon(NEGATIVE); 1683 | if ((t & BIT4) && t2 && BC) 1684 | PC -= 2; 1685 | break; 1686 | 1687 | 1688 | /* general purpose arithmetic and cpu control groups */ 1689 | 1690 | case 0x44: /* neg */ 1691 | A = ~A; 1692 | arith8(1, 0, 0); 1693 | A = v; 1694 | /* flagon(HALF); */ 1695 | flagon(NEGATIVE); 1696 | break; 1697 | 1698 | case 0x46: /* im 0 */ 1699 | IMODE = 0; 1700 | break; 1701 | case 0x56: /* im 1 */ 1702 | IMODE = 1; 1703 | break; 1704 | case 0x5E: /* im 2 */ 1705 | IMODE = 2; 1706 | break; 1707 | 1708 | 1709 | /* 16-bit arithmetic group */ 1710 | 1711 | case 0x4A: /* adc hl,bc */ 1712 | case 0x5A: /* adc hl,de */ 1713 | case 0x6A: /* adc hl,hl */ 1714 | case 0x7A: /* adc hl,sp */ 1715 | case 0x42: /* sbc hl,bc */ 1716 | case 0x52: /* sbc hl,de */ 1717 | case 0x62: /* sbc hl,hl */ 1718 | case 0x72: /* sbc hl,sp */ 1719 | vv = *REGPAIRSP[(t >> 4) & MASK2]; 1720 | n = !(t & BIT3); 1721 | if (n) 1722 | { 1723 | ttt = (int)HL - (int)vv - ((F & CARRY) ? 1 : 0); 1724 | setflag(OVERFLOW, (HL & BIT15) != (vv & BIT15) && 1725 | (vv & BIT15) == (ttt & BIT15)); 1726 | } 1727 | else 1728 | { 1729 | ttt = (int)HL + (int)vv + ((F & CARRY) ? 1 : 0); 1730 | setflag(OVERFLOW, (HL & BIT15) == (vv & BIT15) && 1731 | (vv & BIT15) != (ttt & BIT15)); 1732 | } 1733 | setflag(SIGN, ttt & BIT15); 1734 | setflag(ZERO, !ttt); 1735 | setflag(NEGATIVE, n); 1736 | setflag(CARRY, ttt & BIT16); 1737 | HL = ttt; 1738 | break; 1739 | 1740 | 1741 | /* rotate & shift group */ 1742 | 1743 | case 0x67: /* rrd */ 1744 | case 0x6F: /* rld */ 1745 | t1 = MEM(HL); 1746 | if (t & BIT3) 1747 | { 1748 | SETMEM(HL, (t1 << 4) | (A & MASK4)); 1749 | A = (A & MASKU4) | (t1 >> 4); 1750 | } 1751 | else 1752 | { 1753 | SETMEM(HL, (t1 >> 4) | (A << 4)); 1754 | A = (A & MASKU4) | (t1 & MASK4); 1755 | } 1756 | flags(A); 1757 | break; 1758 | 1759 | 1760 | /* call & return group */ 1761 | 1762 | case 0x45: /* retn */ 1763 | IFF = IFF2; 1764 | PC = MEM(SP); 1765 | SP++; 1766 | PC |= MEM(SP) << 8; 1767 | SP++; 1768 | break; 1769 | case 0x4D: /* reti */ 1770 | PC = MEM(SP); 1771 | SP++; 1772 | PC |= MEM(SP) << 8; 1773 | SP++; 1774 | break; 1775 | 1776 | 1777 | /* input & output group */ 1778 | 1779 | case 0x40: /* in b,c */ 1780 | case 0x48: /* in c,c */ 1781 | case 0x50: /* in d,c */ 1782 | case 0x58: /* in e,c */ 1783 | case 0x60: /* in h,c */ 1784 | case 0x68: /* in l,c */ 1785 | case 0x70: /* in ?,c */ 1786 | case 0x78: /* in a,c */ 1787 | if (!input(z80, B, C, &t1)) 1788 | return FALSE; 1789 | 1790 | v = *REG[(t >> 3) & MASK3] = t1; 1791 | setflag(SIGN, v & BIT7); 1792 | resetflag(ZERO, v); 1793 | flagoff(HALF); 1794 | setparity(v); 1795 | flagoff(NEGATIVE); 1796 | break; 1797 | 1798 | case 0x49: /* out c,c */ 1799 | case 0x51: /* out d,c */ 1800 | case 0x59: /* out e,c */ 1801 | case 0x61: /* out h,c */ 1802 | case 0x69: /* out l,c */ 1803 | case 0x79: /* out a,c */ 1804 | case 0x41: /* out b,c */ 1805 | output(z80, B, C, *REG[(t >> 3) & MASK3]); 1806 | break; 1807 | 1808 | case 0xA2: /* ini */ 1809 | case 0xAA: /* ind */ 1810 | case 0xB2: /* inir */ 1811 | case 0xBA: /* indr */ 1812 | if (!input(z80, B, C, &t1)) 1813 | return FALSE; 1814 | 1815 | SETMEM(HL, t1); 1816 | 1817 | if (t & BIT3) 1818 | HL--; 1819 | else 1820 | HL++; 1821 | 1822 | resetflag(ZERO, --B); 1823 | flagon(NEGATIVE); 1824 | 1825 | if ((t & BIT4) && B) 1826 | PC -= 2; 1827 | 1828 | break; 1829 | 1830 | case 0xA3: /* outi */ 1831 | case 0xAB: /* outd */ 1832 | case 0xB3: /* otir */ 1833 | case 0xBB: /* otdr */ 1834 | resetflag(ZERO, --B); 1835 | output(z80, B, C, MEM(HL)); 1836 | 1837 | if (t & BIT3) 1838 | HL--; 1839 | else 1840 | HL++; 1841 | 1842 | flagon(NEGATIVE); 1843 | 1844 | if ((t & BIT4) && B) 1845 | PC -= 2; 1846 | 1847 | break; 1848 | 1849 | 1850 | default: 1851 | undefinstr(z80, t); 1852 | break; 1853 | } /* end of "extinstr" "switch" */ 1854 | 1855 | goto infloop; 1856 | 1857 | 1858 | /* index-register bit-twiddling instuctions */ 1859 | iregbitinstr: 1860 | 1861 | /* note: we have to look ahead 1 byte for the opcode -- the PC is 1862 | bumped later after the "switch" */ 1863 | switch (t = MEM((PC + 1) & 0xFFFF)) 1864 | { 1865 | 1866 | /* rotate & shift group */ 1867 | 1868 | case 0x06: /* rlc (ir+d) */ 1869 | case 0x0E: /* rrc (ir+d) */ 1870 | case 0x16: /* rl (ir+d) */ 1871 | case 0x1E: /* rr (ir+d) */ 1872 | case 0x26: /* sla (ir+d) */ 1873 | case 0x2E: /* sra (ir+d) */ 1874 | case 0x3E: /* srl (ir+d) */ 1875 | tt = (int)*rr + ((signed char)MEM(PC)); 1876 | PC++; 1877 | t1 = MEM(tt); 1878 | cy = F & CARRY; 1879 | if (t & BIT3) 1880 | { 1881 | setflag(CARRY, t1 & BIT0); 1882 | t1 >>= 1; 1883 | t2 = BIT7; 1884 | } 1885 | else 1886 | { 1887 | setflag(CARRY, t1 & BIT7); 1888 | t1 <<= 1; 1889 | t2 = BIT0; 1890 | } 1891 | if (t & BIT5) 1892 | { 1893 | if (t2 == BIT7 && !(t & BIT4)) 1894 | if (t1 & BIT6) 1895 | t1 |= BIT7; 1896 | } 1897 | else 1898 | { 1899 | if (t & BIT4) 1900 | { 1901 | if (cy) 1902 | t1 |= t2; 1903 | } 1904 | else 1905 | { 1906 | if (F & CARRY) 1907 | t1 |= t2; 1908 | } 1909 | } 1910 | SETMEM(tt, t1); 1911 | flags(t1); 1912 | break; 1913 | 1914 | 1915 | /* bit set, reset, & test group */ 1916 | 1917 | case 0x46: /* bit 0,(ir+d) */ 1918 | case 0x4E: /* bit 1,(ir+d) */ 1919 | case 0x56: /* bit 2,(ir+d) */ 1920 | case 0x5E: /* bit 3,(ir+d) */ 1921 | case 0x66: /* bit 4,(ir+d) */ 1922 | case 0x6E: /* bit 5,(ir+d) */ 1923 | case 0x76: /* bit 6,(ir+d) */ 1924 | case 0x7E: /* bit 7,(ir+d) */ 1925 | tt = (int)*rr + ((signed char)MEM(PC)); 1926 | PC++; 1927 | resetflag(ZERO, MEM(tt) & bitmask[(t >> 3) & MASK3]); 1928 | flagon(HALF); 1929 | flagoff(NEGATIVE); 1930 | break; 1931 | 1932 | case 0x86: /* res 0,(ir+d) */ 1933 | case 0x8E: /* res 1,(ir+d) */ 1934 | case 0x96: /* res 2,(ir+d) */ 1935 | case 0x9E: /* res 3,(ir+d) */ 1936 | case 0xA6: /* res 4,(ir+d) */ 1937 | case 0xAE: /* res 5,(ir+d) */ 1938 | case 0xB6: /* res 6,(ir+d) */ 1939 | case 0xBE: /* res 7,(ir+d) */ 1940 | tt = (int)*rr + ((signed char)MEM(PC)); 1941 | PC++; 1942 | t1 = MEM(tt) & ~bitmask[(t >> 3) & MASK3]; 1943 | SETMEM(tt, t1); 1944 | break; 1945 | 1946 | case 0xC6: /* set 0,(ir+d) */ 1947 | case 0xCE: /* set 1,(ir+d) */ 1948 | case 0xD6: /* set 2,(ir+d) */ 1949 | case 0xDE: /* set 3,(ir+d) */ 1950 | case 0xE6: /* set 4,(ir+d) */ 1951 | case 0xEE: /* set 5,(ir+d) */ 1952 | case 0xF6: /* set 6,(ir+d) */ 1953 | case 0xFE: /* set 7,(ir+d) */ 1954 | tt = (int)*rr + ((signed char)MEM(PC)); 1955 | PC++; 1956 | t1 = MEM(tt) | bitmask[(t >> 3) & MASK3]; 1957 | SETMEM(tt, t1); 1958 | break; 1959 | 1960 | 1961 | default: 1962 | undefinstr(z80, t); 1963 | break; 1964 | } /* end of "iregbitinstr" "switch" */ 1965 | 1966 | PC++; /* bump the PC here instead */ 1967 | goto infloop; 1968 | 1969 | } /* end of "z80_emulator()" */ 1970 | 1971 | 1972 | 1973 | /* initialize the z80 struct with sane stuff */ 1974 | z80info * 1975 | init_z80info(z80info *z80) 1976 | { 1977 | int i; 1978 | 1979 | /* clear it the easy way */ 1980 | memset(z80, 0, sizeof *z80); 1981 | 1982 | /* could allocate memory if need be here - check for NULL malloc */ 1983 | /* z80->mem = malloc(0x10000L); */ 1984 | 1985 | /* initialize the generic byte registers */ 1986 | REG[0] = &B; 1987 | REG[1] = &C; 1988 | REG[2] = &D; 1989 | REG[3] = &E; 1990 | REG[4] = &H; 1991 | REG[5] = &L; 1992 | /* REG[6] = NULL; */ 1993 | REG[7] = &A; 1994 | 1995 | /* initialize the register pairs with AF */ 1996 | REGPAIRAF[0] = &BC; 1997 | REGPAIRAF[1] = &DE; 1998 | REGPAIRAF[2] = &HL; 1999 | REGPAIRAF[3] = &AF; 2000 | 2001 | /* register pairs with SP instead of AF */ 2002 | REGPAIRSP[0] = &BC; 2003 | REGPAIRSP[1] = &DE; 2004 | REGPAIRSP[2] = &HL; 2005 | REGPAIRSP[3] = &SP; 2006 | 2007 | /* register pairs with IX/IY in place of HL - it is set to either the 2008 | address of IX or IY depending on the opcode during runtime */ 2009 | REGPAIRXY[0] = &BC; 2010 | REGPAIRXY[1] = &DE; 2011 | /* REGPAIRXY[2] = NULL; */ 2012 | REGPAIRXY[3] = &SP; 2013 | 2014 | /* index registers */ 2015 | REGIXY[0] = &IX; 2016 | REGIXY[1] = &IY; 2017 | 2018 | /* interrupt vector & memory refresh registers */ 2019 | REGIR[0] = &I; 2020 | REGIR[1] = &R; 2021 | 2022 | /* initialize the other misc stuff */ 2023 | z80->trace = FALSE; 2024 | z80->step = FALSE; 2025 | z80->sig = 0; 2026 | z80->syscall = FALSE; 2027 | 2028 | /* initialize the CP/M BIOS data */ 2029 | z80->drive = 0; 2030 | z80->dma = 0x80; 2031 | z80->track = 0; 2032 | z80->sector = 1; 2033 | 2034 | /* initialize the global parity array if necessary */ 2035 | if (!parity_inited) 2036 | { 2037 | for (i = 0; i <= 0xFF; i++) 2038 | { 2039 | word tt = 1; 2040 | byte t; 2041 | 2042 | for (t = 1; t; t <<= 1) 2043 | if (i & t) 2044 | tt++; 2045 | 2046 | parityarr[i] = tt & BIT0; 2047 | } 2048 | 2049 | parity_inited = TRUE; 2050 | } 2051 | 2052 | return z80; 2053 | } 2054 | 2055 | z80info * 2056 | destroy_z80info(z80info *z80) 2057 | { 2058 | /* free the mem array if allocated above */ 2059 | /* free(z80->mem); */ 2060 | return z80; 2061 | } 2062 | 2063 | z80info * 2064 | new_z80info(void) 2065 | { 2066 | z80info *z80 = (z80info*)malloc(sizeof *z80); 2067 | 2068 | if (z80 == NULL) 2069 | { 2070 | fprintf(stderr, "Cannot allocate memory for a z80 object\n"); 2071 | return NULL; 2072 | } 2073 | 2074 | return init_z80info(z80); 2075 | } 2076 | 2077 | void 2078 | delete_z80info(z80info *z80) 2079 | { 2080 | if (z80 == NULL) 2081 | return; 2082 | 2083 | destroy_z80info(z80); 2084 | free(z80); 2085 | } 2086 | -------------------------------------------------------------------------------- /z80.proj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tjmerritt/z80/3aea43bf3390a5ae2ba1ef78ef54ee9f292ca059/z80.proj --------------------------------------------------------------------------------