#include "z80.h" #include "z80debug.h" #include namespace z80 { static uint8_t *memory = nullptr; static uint32_t t = 0; int (*in_ports[256])(); void (*out_ports[256])(int); #define _rM16(a) (uint16_t*)&memory[a] #define rM16(a) *_rM16(a) #define fC 0b00000001 #define fN 0b00000010 #define fP 0b00000100 #define fV 0b00000100 #define fX 0b00001000 #define fH 0b00010000 #define fY 0b00100000 #define fZ 0b01000000 #define fS 0b10000000 #define cNO 255 #define cNZ 0 #define cZ 1 #define cNC 2 #define cC 3 #define cPO 4 #define cPE 5 #define cP 6 #define cM 7 uint8_t regs[28]; uint8_t *_rF = ®s[0]; uint8_t *_rA = ®s[1]; uint8_t *_rC = ®s[2]; uint8_t *_rB = ®s[3]; uint8_t *_rE = ®s[4]; uint8_t *_rD = ®s[5]; uint8_t *_rL = ®s[6]; uint8_t *_rH = ®s[7]; uint16_t *_rAF = (uint16_t*)®s[0]; uint16_t *_rBC = (uint16_t*)®s[2]; uint16_t *_rDE = (uint16_t*)®s[4]; uint16_t *_rHL = (uint16_t*)®s[6]; uint8_t *_rF2 = ®s[8]; uint8_t *_rA2 = ®s[9]; uint8_t *_rC2 = ®s[10]; uint8_t *_rB2 = ®s[11]; uint8_t *_rE2 = ®s[12]; uint8_t *_rD2 = ®s[13]; uint8_t *_rL2 = ®s[14]; uint8_t *_rH2 = ®s[15]; uint16_t *_rAF2 = (uint16_t*)®s[8]; uint16_t *_rBC2 = (uint16_t*)®s[10]; uint16_t *_rDE2 = (uint16_t*)®s[12]; uint16_t *_rHL2 = (uint16_t*)®s[14]; uint8_t *_rIXL = ®s[16]; uint8_t *_rIXH = ®s[17]; uint8_t *_rIYL = ®s[18]; uint8_t *_rIYH = ®s[19]; uint16_t *_rIX = (uint16_t*)®s[16]; uint16_t *_rIY = (uint16_t*)®s[18]; uint16_t *_rSP = (uint16_t*)®s[20]; uint8_t *_rI = ®s[22]; uint8_t *_rR = ®s[23]; uint16_t *_rPC = (uint16_t*)®s[24]; uint16_t *_rWZ = (uint16_t*)®s[26]; uint8_t *_rZ = (uint8_t*)®s[26]; uint8_t *_rW = (uint8_t*)®s[27]; uint8_t iff1, iff2, im; #define rA (*_rA) #define rF (*_rF) #define rB (*_rB) #define rC (*_rC) #define rD (*_rD) #define rE (*_rE) #define rH (*_rH) #define rL (*_rL) #define rW (*_rW) #define rZ (*_rZ) #define rAF (*_rAF) #define rBC (*_rBC) #define rDE (*_rDE) #define rHL (*_rHL) #define rWZ (*_rWZ) #define rA2 (*_rA2) #define rF2 (*_rF2) #define rB2 (*_rB2) #define rC2 (*_rC2) #define rD2 (*_rD2) #define rE2 (*_rE2) #define rH2 (*_rH2) #define rL2 (*_rL2) #define rAF2 (*_rAF2) #define rBC2 (*_rBC2) #define rDE2 (*_rDE2) #define rHL2 (*_rHL2) #define rIXH (*_rIXH) #define rIXL (*_rIXL) #define rIYH (*_rIYH) #define rIYL (*_rIYL) #define rIX (*_rIX) #define rIY (*_rIY) #define rSP (*_rSP) #define rI (*_rI) #define rR (*_rR) #define rPC (*_rPC) #define SWAP(a,b) {auto temp=a;a=b;b=temp;} uint8_t READ_MEM_8(const uint16_t addr) { if (z80debug::isbreak(addr, 2)) z80debug::stop(); t+=3; return memory[addr]; } uint8_t READ_MEM_8() { return READ_MEM_8(rPC++); } uint8_t READ_M1() { t+=1; return READ_MEM_8(); } uint16_t READ_MEM_16() { const uint8_t L = READ_MEM_8(); const uint8_t H = READ_MEM_8(); return (H << 8) + L; } uint16_t READ_MEM_16(const uint16_t addr) { return READ_MEM_8(addr) + (READ_MEM_8(addr+1) << 8); } const uint8_t WRITE_MEM_8(const uint16_t addr, const uint8_t value) { t+=3; if (addr>=0x4000) memory[addr] = value; if (z80debug::isbreak(addr, 4)) z80debug::stop(); return value; } void WRITE_MEM_16(const uint16_t addr, const uint16_t value) { WRITE_MEM_8(addr, value & 0xff); WRITE_MEM_8(addr+1, (value>>8) & 0xff); } void PUSH(uint16_t b) { rSP-=2; WRITE_MEM_16(rSP, b); t+=1; } void POP(uint16_t *a) { *a = READ_MEM_16(rSP); rSP+=2; } inline void KEEP_FLAGS(const uint8_t flags) { rF &= flags; } inline void SET_FLAGS(const uint8_t flags) { rF |= flags; } inline void FLAGS_SZXY(const uint8_t value) { rF |= value ? value & fS : fZ; rF |= (value & (fY | fX)); } inline void SET_PARITY_FLAG() { uint8_t count=0; uint8_t f = rF; while (f>0) { count+=(f&1); f=f>>1; } if (!(count&1)) rF |= fP; } void INC16(uint16_t *reg) { t+=2; (*reg)++; } void DEC16(uint16_t *reg) { t+=2; (*reg)--; } void ADD16(uint16_t* a, uint16_t b) { t++; const uint32_t res = *a + b; KEEP_FLAGS(fS | fZ | fV); SET_FLAGS(((*a ^ res ^ b) >> 8) & fH); SET_FLAGS((res >> 16) & fC); SET_FLAGS((res >> 8) & (fY | fX)); *a = (uint16_t)res; } void ADC16(uint16_t* a, uint16_t b) { t++; const uint32_t res = *a + b + (rF & fC); rF=0; SET_FLAGS(((*a ^ res ^ b) >> 8) & fH); SET_FLAGS((res >> 16) & fC); SET_FLAGS((res >> 8) & (fS | fY | fX)); SET_FLAGS((res & 0xffff) ? 0 : fZ); SET_FLAGS(((b ^ *a ^ 0x8000) & (b ^ res) & 0x8000) >> 13); *a = (uint16_t)res; } void SBC16(uint16_t* a, uint16_t b) { t++; const uint32_t res = *a - b - (rF & fC); rF = 0; SET_FLAGS(((*a ^ res ^ b) >> 8) & fH); SET_FLAGS(fN); SET_FLAGS((res >> 16) & fC); SET_FLAGS((res >> 8) & (fS | fY | fX)); SET_FLAGS((res & 0xffff) ? 0 : fZ); SET_FLAGS(((b ^ *a) & (*a ^ res) & 0x8000) >> 13); *a = (uint16_t)res; } void INC8(uint8_t *reg) { uint8_t value = *reg + 1; KEEP_FLAGS(fC); FLAGS_SZXY(value); if (value == 0x80) SET_FLAGS(fV); if ( (value & 0x0f) == 0x00 ) SET_FLAGS(fH); *reg = value; } void DEC8(uint8_t *reg) { uint8_t value = *reg - 1; KEEP_FLAGS(fC); FLAGS_SZXY(value); SET_FLAGS(fN); if (value == 0x7f) SET_FLAGS(fV); if ( (value & 0x0f) == 0x0f ) SET_FLAGS(fH); *reg = value; } void INCMEM8(const uint16_t addr) { t++; uint8_t value = READ_MEM_8(addr); value++; KEEP_FLAGS(fC); FLAGS_SZXY(value); if (value == 0x80) SET_FLAGS(fV); if ( (value & 0x0f) == 0x00 ) SET_FLAGS(fH); WRITE_MEM_8(addr, value); } void DECMEM8(const uint16_t addr) { t+=1; uint8_t value = READ_MEM_8(addr); value--; KEEP_FLAGS(fC); FLAGS_SZXY(value); SET_FLAGS(fN); if (value == 0x7f) SET_FLAGS(fV); if ( (value & 0x0f) == 0x0f ) SET_FLAGS(fH); WRITE_MEM_8(addr, value); } void ADD8(uint8_t b) { const uint8_t res = rA + b; rF=0; FLAGS_SZXY(res); if ( (res & 0x0f) < (rA & 0x0f) ) SET_FLAGS(fH); if ( res < rA ) SET_FLAGS(fC); if ( (b^rA^0x80) & (b^res) & 0x80 ) SET_FLAGS(fV); rA = (uint8_t)res; } void ADC8(uint8_t b) { if (!(rF & fC)) ADD8(b); else { uint16_t res = rA + b + 1; rF=0; FLAGS_SZXY(res); if ( (res & 0x0f) <= (rA & 0x0f) ) SET_FLAGS(fH); if ( res <= rA ) SET_FLAGS(fC); if ( (b^rA^0x80) & (b^res) & 0x80 ) SET_FLAGS(fV); rA = (uint8_t)res; } } void SUB8(uint8_t b, const bool update=true) { const uint8_t res = rA - b; rF=0; FLAGS_SZXY(res); SET_FLAGS(fN); if ( (res & 0x0f) > (rA & 0x0f) ) SET_FLAGS(fH); if ( res > rA ) SET_FLAGS(fC); if ( (b^rA) & (rA^res) & 0x80 ) SET_FLAGS(fV); if (update) rA = (uint8_t)res; } void SBC8(uint8_t b) { if (!(rF & fC)) SUB8(b); else { const uint8_t res = rA - b - 1; rF=0; FLAGS_SZXY(res); SET_FLAGS(fN); if ( (res & 0x0f) >= (rA & 0x0f) ) SET_FLAGS(fH); if ( res >= rA ) SET_FLAGS(fC); if ( (b^rA) & (rA^res) & 0x80 ) SET_FLAGS(fV); rA = (uint8_t)res; } } void NEG() { uint8_t val = rA; rA = 0; SUB8(val); } void AND(uint8_t b) { rA = rA & b; rF=0; FLAGS_SZXY(rA); SET_PARITY_FLAG(); SET_FLAGS(fH); } void XOR(uint8_t b) { rA = rA ^ b; rF=0; FLAGS_SZXY(rA); SET_PARITY_FLAG(); } void OR(uint8_t b) { rA = rA | b; rF=0; FLAGS_SZXY(rA); SET_PARITY_FLAG(); } void CP(uint8_t b) { SUB8(b, false); } void RLCA() { rA = (rA>>7) | (rA<<1); KEEP_FLAGS(fS | fZ | fP); SET_FLAGS(rA & (fX | fY | fC)); } void RRCA() { rA = (rA<<7) | (rA>>1); KEEP_FLAGS(fS | fZ | fP); SET_FLAGS(rA & (fX | fY | fC)); } void RLA() { rA = (rA<<1) | (rF&fC); KEEP_FLAGS(fS | fZ | fP); SET_FLAGS(rA & (fX | fY | fC)); } void RRA() { rA = ((rF&fC)<<7) | (rA>>1); KEEP_FLAGS(fS | fZ | fP); SET_FLAGS(rA & (fX | fY | fC)); } void RRD() { uint8_t a = rA; uint8_t hl = READ_MEM_8(rHL); rA = (rA & 0xF0) | (hl >> 4); hl = (hl<<4) | (a & 0X0F); WRITE_MEM_8(rHL, hl); KEEP_FLAGS(fC); FLAGS_SZXY(rA); SET_PARITY_FLAG(); t+=4; } void RLD() { uint8_t a = rA; uint8_t hl = READ_MEM_8(rHL); rA = (rA & 0xF0) | (hl & 0x0F); hl = (hl >> 4) | (a << 4); WRITE_MEM_8(rHL, hl); KEEP_FLAGS(fC); FLAGS_SZXY(rA); SET_PARITY_FLAG(); t+=4; } void DAA() { bool carry_set = false; uint8_t old = rA; if ( (rA & 0x0F)>9 || (rF & fH) ) rA += 0x06; if ( (rA >> 4)>9 || (rF & fC) ) { rA += 0x60; carry_set = true; } KEEP_FLAGS(fN); FLAGS_SZXY(rA); if ( (rA & 0x0F) < (old & 0x0F) ) SET_FLAGS(fH); if (carry_set) SET_FLAGS(fC); SET_PARITY_FLAG(); } void CPL() { rA = ~rA; KEEP_FLAGS(fS | fZ | fP | fC); SET_FLAGS(fH | fN); SET_FLAGS(rA & (fX | fY)); } void SCF() { KEEP_FLAGS( fS | fZ | fP ); SET_FLAGS(fC); SET_FLAGS(rA & (fX | fY)); } void CCF() { const bool carry = (rF & fC); KEEP_FLAGS( fS | fZ | fP ); SET_FLAGS(carry ? fH : fC); SET_FLAGS(rA & (fX | fY)); } void DJNZ() { const int8_t d = (int8_t)READ_MEM_8(); rB--; if (rB==0) { rPC = rPC + d; t+=5; } } void JR(uint8_t cond = cNO) { const int8_t d = (int8_t)READ_MEM_8(); if ( cond == cNO || ( (cond == cNZ) && !(rF & fZ) ) || ( (cond == cZ) && (rF & fZ) ) || ( (cond == cNC) && !(rF & fC) ) || ( (cond == cC) && (rF & fC) ) ) { rPC = rPC + d; t+=5; } } void JP(uint8_t cond, uint16_t addr) { if ( cond == cNO || ( (cond == cNZ) && !(rF & fZ) ) || ( (cond == cZ) && (rF & fZ) ) || ( (cond == cNC) && !(rF & fC) ) || ( (cond == cC) && (rF & fC) ) || ( (cond == cPO) && !(rF & fV) ) || ( (cond == cPE) && (rF & fV) ) || ( (cond == cM) && (rF & fS) ) || ( (cond == cP) && !(rF & fS) ) ) rPC = addr; } void CALL(uint8_t cond, uint16_t addr) { if ( cond == cNO || ( (cond == cNZ) && !(rF & fZ) ) || ( (cond == cZ) && (rF & fZ) ) || ( (cond == cNC) && !(rF & fC) ) || ( (cond == cC) && (rF & fC) ) || ( (cond == cPO) && !(rF & fV) ) || ( (cond == cPE) && (rF & fV) ) || ( (cond == cM) && (rF & fS) ) || ( (cond == cP) && !(rF & fS) ) ) { PUSH(rPC); rPC = addr; } } void RET(uint8_t cond) { if ( cond == cNO || ( (cond == cNZ) && !(rF & fZ) ) || ( (cond == cZ) && (rF & fZ) ) || ( (cond == cNC) && !(rF & fC) ) || ( (cond == cC) && (rF & fC) ) || ( (cond == cPO) && !(rF & fV) ) || ( (cond == cPE) && (rF & fV) ) || ( (cond == cM) && (rF & fS) ) || ( (cond == cP) && !(rF & fS) ) ) { POP(_rPC); if (cond != cNO) t++; } else { t++; } } void RETN() { POP(_rPC); iff1 = iff2; } void RETI() { RETN(); } void interrupt() { if (!iff1) return; PUSH(rPC); rPC = 0x38; } void RST(uint8_t vec) { PUSH(rPC); rPC = vec; } void IM(uint8_t mode) { im = mode; } void EX_MEM(uint16_t *reg, uint16_t addr) { auto temp = *reg; *reg = READ_MEM_16(addr); WRITE_MEM_16(addr, temp); t+=3; } void DI() { iff1 = iff2 = 0; } void EI() { iff1 = iff2 = 1; } void HALT() { printf("HALT\n"); rPC--; } static inline const uint8_t RLC(const uint8_t v) { const uint8_t res = (v>>7) | (v<<1); rF=0; FLAGS_SZXY(res); if (res&1) SET_FLAGS(fC); SET_PARITY_FLAG(); return res; } static inline const uint8_t RRC(const uint8_t v) { const uint8_t res = (v<<7) | (v>>1); rF=0; FLAGS_SZXY(res); if (res&0x80) SET_FLAGS(fC); SET_PARITY_FLAG(); return res; } static inline const uint8_t RL(const uint8_t v) { const uint8_t res = (v<<1) | (rF&fC); rF=0; FLAGS_SZXY(res); if (v&0x80) SET_FLAGS(fC); SET_PARITY_FLAG(); return res; } static inline const uint8_t RR(const uint8_t v) { const uint8_t res = ((rF&fC)<<7) | (v>>1); rF=0; FLAGS_SZXY(res); if (v&1) SET_FLAGS(fC); SET_PARITY_FLAG(); return res; } static inline const uint8_t SLA(const uint8_t v) { const uint8_t res = (v<<1); rF=0; FLAGS_SZXY(res); if (v&0x80) SET_FLAGS(fC); SET_PARITY_FLAG(); return res; } static inline const uint8_t SRA(const uint8_t v) { const uint8_t res = (v&0x80) | (v>>1); rF=0; FLAGS_SZXY(res); if (v&1) SET_FLAGS(fC); SET_PARITY_FLAG(); return res; } static inline const uint8_t SLL(const uint8_t v) { const uint8_t res = (v<<1) & 1; rF=0; FLAGS_SZXY(res); if (v&0x80) SET_FLAGS(fC); SET_PARITY_FLAG(); return res; } static inline const uint8_t SRL(const uint8_t v) { const uint8_t res = (v>>1); rF=0; FLAGS_SZXY(res); if (v&1) SET_FLAGS(fC); SET_PARITY_FLAG(); return res; } void BIT(uint8_t pos, uint8_t v) { const uint8_t res = v & 1<