#include "z80.h" #include #include #include template struct RegBit { T data; enum { mask = (1u << nbits) - 1u }; template RegBit& operator=(T2 val) { data = (data & ~(mask << bitno)) | ((nbits > 1 ? val : !!val) << bitno); return *this; } operator unsigned() const { return (data >> bitno) & mask; } unsigned operator &(unsigned val) const { return (unsigned)*this & val; } RegBit& operator &=(unsigned val) { data &= (val & mask) << bitno; return *this; } RegBit& operator++ () { return *this = *this + 1; } unsigned operator++ (int) { unsigned r = *this; ++*this; return r; } }; namespace Z80Bus { void Wr(u16 addr, u8 value); u8 Rd(u16 addr); void Out(u16 addr, u8 value); u8 In(u16 addr); u8 IRQVector(); void exc_unimplemented(u8 op); } namespace Z80 { using namespace std; using namespace Z80Bus; typedef union Reg_ { u16 W; struct { u8 L,H; }; RegBit<0> CF; RegBit<1> NF; RegBit<2> VF; RegBit<2> PF; RegBit<3> XF; RegBit<4> HF; RegBit<5> YF; RegBit<6> ZF; RegBit<7> SF; operator u16() { return W; } Reg_& operator=(u16 val) { W=val; return *this; } Reg_& operator++() { return *this = *this+1; } u16 operator++(int) { u16 r = *this; ++*this; return r; } Reg_& operator--() { return *this = *this-1; } u16 operator--(int) { u16 r = *this; --*this; return r; } } Reg; #define LEVEL_TRIGGERED 0 #define UP_EDGE_TRIGGERED 1 #define DOWN_EDGE_TRIGGERED 2 template struct Line { bool status; bool triggered; Line& operator=(bool v) { if (trigger != LEVEL_TRIGGERED && (status^v)) triggered=true; status=v; return *this; } operator bool() { bool ret=(trigger == LEVEL_TRIGGERED ? status : triggered); triggered = false; return ret; } }; Line line_irq, line_busreq, line_reset; Line line_nmi; u64 CLK; bool ei_delay, halted; Reg AF, BC, DE, HL, IX, IY, SP, PC, AF1, BC1, DE1, HL1; u8 R, I, IFF1, IFF2, IM; auto &A = AF.H; auto &F = AF.L; auto &B = BC.H; auto &C = BC.L; auto &D = DE.H; auto &E = DE.L; auto &H = HL.H; auto &L = HL.L; u8* const regop[8] = {&B,&C,&D,&E,&H,&L,nullptr,&A}; Reg* const ppairop[4] = { &BC, &DE, &HL, &SP }; Reg* const qpairop[4] = { &BC, &DE, &HL, &AF }; u8 const flagmask[4] = { (1<<6), (1<<0), (1<<2), (1<<7) }; #define ft256(t) ft256a(t,0) ft256a(t,1) ft256a(t,2) ft256a(t,3) #define ft256a(t,n) ft256b(t,(n)*4+0) ft256b(t,(n)*4+1) ft256b(t,(n)*4+2) ft256b(t,(n)*4+3) #define ft256b(t,n) ft256c(t,(n)*4+0) ft256c(t,(n)*4+1) ft256c(t,(n)*4+2) ft256c(t,(n)*4+3) #define ft256c(t,n) ft256d(t,(n)*4+0) ft256d(t,(n)*4+1) ft256d(t,(n)*4+2) ft256d(t,(n)*4+3) #define ft256d(t,n) t(n) template u8 CalcZS() { Reg ret = {0}; ret.ZF=(val?0:1); ret.SF=val>>7; ret.YF=val>>5; ret.XF=val>>3; return ret; } template u8 CalcPZS() { Reg ret = { CalcZS() }; ret.PF = !__builtin_parity(val); return ret; } #define tzs(n) CalcZS(), const u8 ZSTable[256] = { ft256(tzs) }; #define tpzs(n) CalcPZS(), const u8 PZSTable[256] = { ft256(tpzs) }; #if 0 #define xxx(xs,idx) \ if (xs[idx] == '0' && (op>>7)) match=false; \ if (xs[idx] == '1' && !(op>>7)) match=false; \ if (xs[idx] == 'r') r_ = (r_<<1) | (op>>7); \ if (xs[idx] == 's') s_ = (s_<<1) | (op>>7); \ if (xs[idx] == 'p') p_ = (p_<<1) | (op>>7); \ if (xs[idx] == 'q') q_ = (q_<<1) | (op>>7); \ if (xs[idx] == 'f') f = (f<<1) | (op>>7); \ if (xs[idx] == 'g') g = (g<<1) | (op>>7); \ if (xs[idx] == 'm') m = (m<<1) | (op>>7); \ op<<=1; #define xa(ch) \ if (ch == 'n') n=op; \ if (ch == 'N') n=(op<<8)|n; \ if (ch == 'd') d=op; #define xx(xs,n) \ xxx(xs,n+0) xxx(xs,n+1) xxx(xs,n+2) xxx(xs,n+3) \ xxx(xs,n+4) xxx(xs,n+5) xxx(xs,n+6) xxx(xs,n+7) #define xflag(xsf) \ if (xsf == '@') F=PZSTable[A]; \ if (xsf == 'n') AF.NF = 0; \ if (xsf == 'N') AF.NF = 1; \ if (xsf == 'h') AF.HF = 0; \ if (xsf == 'H') AF.HF = 1; #define xend(xs) \ if (match) { xflag(xsstring[0]); xflag(xsstring[1]); xflag(xsstring[2]); return; } #define xstart() \ u8 op,r_,s_,p_,q_,d,f,g,m,_; u16 n; bool match=false; const char* xsstring; #define x(xs, cyc) \ xend(xs) \ r_=s_=p_=q_=d=n=f=g=m=_=0; xsstring=xs; match=true; op=op_; \ xx(xsstring, 0) \ if (match && xsstring[ 8] == '.') { op=Rd(PC.W++); xa(xsstring[9]) } \ if (match && xsstring[ 8] == ':' && prefix) { op=Rd(PC.W++); xa(xsstring[9]) } \ if (match && xsstring[10] == '.') { op=Rd(PC.W++); xa(xsstring[11]) } \ if (match && xsstring[10] == ':' && prefix) { op=Rd(PC.W++); xa(xsstring[11]) } \ if (match) CLK+=cyc,xsstring+=13; \ if (match) #define fallback() \ if (m) return; \ if (1) #define r (*regop[r_]) #define s (*regop[s_]) #define p (*ppairop[p_]) #define q (*qpairop[q_]) #else #define INLINE __attribute__((always_inline)) #define xxx(xs,idx) \ if (xs[idx] == '0') { if (op>>7) { match=false; return; } } \ else if (xs[idx] == '1') { if (!(op>>7)) { match=false; return; } } \ else if (xs[idx] == 'r') r_ = (r_<<1) | (op>>7); \ else if (xs[idx] == 's') s_ = (s_<<1) | (op>>7); \ else if (xs[idx] == 'p') p_ = (p_<<1) | (op>>7); \ else if (xs[idx] == 'q') q_ = (q_<<1) | (op>>7); \ else if (xs[idx] == 'f') f = (f<<1) | (op>>7); \ else if (xs[idx] == 'g') g = (g<<1) | (op>>7); \ else if (xs[idx] == 'm') m = (m<<1) | (op>>7); \ op<<=1; #define xa(ch) \ if (ch == 'n') n=op; \ else if (ch == 'N') n=(op<<8)|n; \ else if (ch == 'd') d=op; #define xflag(xsf) \ if (xsf == '@') F=PZSTable[A]; \ else if (xsf == 'k') AF.CF = cf; \ else if (xsf == 'w') AF.VF = vf; \ else if (xsf == 'n') AF.NF = 0; \ else if (xsf == 'N') AF.NF = 1; \ else if (xsf == 'h') AF.HF = 0; \ else if (xsf == 'H') AF.HF = 1; #define NextOp() (CLK+=1, Rd(PC.W++)) struct XDecoder { u8 r_,s_,p_,q_,d,f,g,m,_; bool match; u16 n; const char *xsflag; bool cf, vf; XDecoder() { match=false; } XDecoder(u8 prefix, u8 op, const char* xs, int cyc) INLINE { r_=s_=p_=q_=d=n=f=g=m=_=0; match=true; xxx(xs, 0) xxx(xs, 1) xxx(xs, 2) xxx(xs, 3) xxx(xs, 4) xxx(xs, 5) xxx(xs, 6) xxx(xs, 7) if (xs[ 8] == '.') { op=NextOp(); xa(xs[ 9]) } if (xs[ 8] == ':' && prefix) { op=NextOp(); xa(xs[ 9]) } if (xs[10] == '.') { op=NextOp(); xa(xs[11]) } if (xs[10] == ':' && prefix) { op=NextOp(); xa(xs[11]) } CLK+=cyc; cf=AF.CF; vf=AF.VF; xsflag = xs+13; match=true; } ~XDecoder() INLINE { if (!match) return; if (xsflag[0] != ' ') { xflag(xsflag[0]); xflag(xsflag[1]); xflag(xsflag[2]); } } operator bool() INLINE { return match; } }; #define xstart() if (0); #define x(xs, cyc) else if (XDecoder x = XDecoder(prefix, op_, xs, cyc)) #define fallback() else #define _ x._ #define f x.f #define g x.g #define d x.d #define m x.m #define n x.n #define r (*regop[x.r_]) #define s (*regop[x.s_]) #define p (*ppairop[x.p_]) #define q (*qpairop[x.q_]) #endif inline void Io8(bool read, u16 addr, u8 &val) { if (read) val = In(addr); else Out(addr, val); } inline void Mem8(bool read, u16 addr, u8 &val) { if (read) val = Rd(addr); else Wr(addr, val); } inline void Mem16(bool read, u16 addr, u16 &val) { if (read) { val = Rd(addr); val |= Rd(addr+1)<<8; } else { Wr(addr, val&0xFF); Wr(addr+1, val>>8); } } template