From 4e9415dff1a314f88e9bed2d02763002dabab402 Mon Sep 17 00:00:00 2001 From: Raimon Zamora Date: Tue, 26 Mar 2024 14:32:29 +0100 Subject: [PATCH] =?UTF-8?q?-=20Avan=C3=A7os?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- z80.cpp | 1860 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 1342 insertions(+), 518 deletions(-) diff --git a/z80.cpp b/z80.cpp index 9e73702..c0d97c4 100644 --- a/z80.cpp +++ b/z80.cpp @@ -3,7 +3,7 @@ namespace z80 { static uint8_t *memory = nullptr; - static uint32_t t_states = 0; + static uint32_t t = 0; #define _rM16(a) (uint16_t*)&memory[a] #define rM16(a) *_rM16(a) @@ -76,6 +76,8 @@ namespace z80 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) @@ -122,213 +124,449 @@ namespace z80 #define SWAP(a,b) {auto temp=a;a=b;b=temp;} - uint16_t LD16() + uint8_t READ_MEM_8(const uint16_t addr) { - return memory[rPC++] + memory[rPC++] << 8; + 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() + { + return READ_MEM_8() + READ_MEM_8() << 8; + } + + uint16_t READ_MEM_16(const uint16_t addr) + { + return READ_MEM_8(addr) + READ_MEM_8(addr+1) << 8; + } + + void WRITE_MEM_8(const uint16_t addr, const uint8_t value) + { + t+=3; + memory[addr] = 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) { - memory[rSP-2] = b & 0xff; - memory[rSP-1] = (b >> 8) & 0xff; rSP-=2; + WRITE_MEM_16(rSP, b); + t+=1; } void POP(uint16_t *a) { - *a = memory[rSP] + (memory[rSP+1] << 8); + *a = READ_MEM_16(rSP); rSP+=2; } - uint16_t LD8() + inline void KEEP_FLAGS(const uint8_t flags) { - return memory[rPC++]; + 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>>1; } + if (!(count&1)) rF |= fP; } void INC16(uint16_t *reg) { - reg++; + t+=2; + *reg++; } void DEC16(uint16_t *reg) { - reg--; + t+=2; + *reg--; } void ADD16(uint16_t* a, uint16_t b) { - // [TODO] operadors mes grans, per a no perdre el carry_out - *a = *a + 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) { - // [TODO] operadors mes grans, per a no perdre el carry_out - *a = *a + b; - if (rF & fC) *a++; + 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) { - // [TODO] operadors mes grans, per a no perdre el carry_out - *a = *a + b; - if (rF & fC) *a--; + 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) { - reg++; + uint8_t value = *reg + 1; + + KEEP_FLAGS(fC); + FLAGS_SZXY(*reg); + if (*reg == 0x80) SET_FLAGS(fV); + if ( (*reg & 0x0f) == 0x00 ) SET_FLAGS(fH); + + *reg = value; } void DEC8(uint8_t *reg) { - reg--; + uint8_t value = *reg - 1; + + KEEP_FLAGS(fC); + FLAGS_SZXY(*reg); + SET_FLAGS(fN); + if (*reg == 0x7f) SET_FLAGS(fV); + if ( (*reg & 0x0f) == 0x0f ) SET_FLAGS(fH); + + *reg = value; } - void ADD8(uint8_t* a, uint8_t b) + void INCMEM8(const uint16_t addr) { - // [TODO] operadors mes grans, per a no perdre el carry_out - *a = *a + b; + t++; + uint8_t value = READ_MEM_8(addr); + value++; + WRITE_MEM_8(addr, value); } - void ADC8(uint8_t* a, uint8_t b) + void DECMEM8(const uint16_t addr) { - // [TODO] operadors mes grans, per a no perdre el carry_out - *a = *a + b; - if (rF & fC) *a++; + t+=1; + uint8_t value = READ_MEM_8(addr); + value--; + WRITE_MEM_8(addr, value); } - void SUB8(uint8_t b) + void ADD8(uint8_t b) { - // [TODO] operadors mes grans, per a no perdre el carry_out - rA = rA - 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 SBC8(uint8_t* a, uint8_t b) + void ADC8(uint8_t b) { - // [TODO] operadors mes grans, per a no perdre el carry_out - *a = *a - b; - if (rF & fC) *a--; + 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() { - rA = ~rA; + 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) { - rA = rA ^ b; + SUB8(b, false); } void RLCA() { - // [TODO] + rA = (rA>>7) | (rA<<1); + KEEP_FLAGS(fS | fZ | fP); + SET_FLAGS(rA & (fX | fY | fC)); } void RRCA() { - // [TODO] + rA = (rA<<7) | (rA>>1); + KEEP_FLAGS(fS | fZ | fP); + SET_FLAGS(rA & (fX | fY | fC)); } void RLA() { - // [TODO] + rA = (rA<<1) | (rF&fC); + KEEP_FLAGS(fS | fZ | fP); + SET_FLAGS(rA & (fX | fY | fC)); } void RRA() { - // [TODO] + rA = ((rF&fC)<<7) | (rA>>1); + KEEP_FLAGS(fS | fZ | fP); + SET_FLAGS(rA & (fX | fY | fC)); } void RRD() { - // [TODO] + 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() { - // [TODO] + 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() { - // [TODO] + 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() { - // [TODO] + rA = ~rA; + KEEP_FLAGS(fS | fZ | fP | fC); + SET_FLAGS(fH | fN); + SET_FLAGS(rA & (fX | fY)); } void SCF() { - // [TODO] + KEEP_FLAGS( fS | fZ | fP ); + SET_FLAGS(fC); + SET_FLAGS(rA & (fX | fY)); } void CCF() { - // [TODO] + const bool carry = (rF & fC); + KEEP_FLAGS( fS | fZ | fP ); + SET_FLAGS(carry ? fH : fC); + SET_FLAGS(rA & (fX | fY)); } void DJNZ() { - // [TODO] + const int8_t d = (int8_t)READ_MEM_8(); + rB--; + if (rB==0) + { + rPC = rPC + d; + t+=5; + } } - void JR(uint8_t cond, int8_t disp) + void JR(uint8_t cond = cNO) { - // [TODO] + 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, int8_t disp) + void JP(uint8_t cond, uint16_t addr) { - // [TODO] + 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, int8_t disp) + void CALL(uint8_t cond, uint16_t addr) { - // [TODO] + 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) { - // [TODO] + 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() { - // [TODO] + POP(_rPC); + iff1 = iff2; } void RETI() { - // [TODO] + RETN(); } void RST(uint8_t vec) { - // [TODO] + PUSH(rPC); + rPC = vec; } void IM(uint8_t mode) { - // [TODO] + im = mode; } void IN(uint8_t *reg, uint8_t dir) @@ -341,76 +579,147 @@ namespace z80 // [TODO] } + 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() { - // [TODO] + iff1 = iff2 = 0; } void EI() { - // [TODO] + iff1 = iff2 = 1; } void HALT() { - // [TODO] + rPC--; } - void RLC(uint8_t *v, uint8_t *r=nullptr) + static inline const uint8_t RLC(const uint8_t v) { - // [TODO] + const uint8_t res = (v>>7) | (v<<1); + rF=0; + FLAGS_SZXY(res); + if (res&1) SET_FLAGS(fC); + SET_PARITY_FLAG(); + return res; } - void RRC(uint8_t *v, uint8_t *r=nullptr) + static inline const uint8_t RRC(const uint8_t v) { - // [TODO] + const uint8_t res = (v<<7) | (v>>1); + rF=0; + FLAGS_SZXY(res); + if (res&0x80) SET_FLAGS(fC); + SET_PARITY_FLAG(); + return res; } - void RL(uint8_t *v, uint8_t *r=nullptr) + static inline const uint8_t RL(const uint8_t v) { - // [TODO] + const uint8_t res = (v<<1) | (rF&fC); + rF=0; + FLAGS_SZXY(res); + if (v&0x80) SET_FLAGS(fC); + SET_PARITY_FLAG(); + return res; } - void RR(uint8_t *v, uint8_t *r=nullptr) + static inline const uint8_t RR(const uint8_t v) { - // [TODO] + 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; } - void SLA(uint8_t *v, uint8_t *r=nullptr) + static inline const uint8_t SLA(const uint8_t v) { - // [TODO] + const uint8_t res = (v<<1); + rF=0; + FLAGS_SZXY(res); + if (v&0x80) SET_FLAGS(fC); + SET_PARITY_FLAG(); + return res; } - void SRA(uint8_t *v, uint8_t *r=nullptr) + static inline const uint8_t SRA(const uint8_t v) { - // [TODO] + const uint8_t res = (v&0x80) | (v>>1); + rF=0; + FLAGS_SZXY(res); + if (v&1) SET_FLAGS(fC); + SET_PARITY_FLAG(); + return res; } - void SLL(uint8_t *v, uint8_t *r=nullptr) + static inline const uint8_t SLL(const uint8_t v) { - // [TODO] + const uint8_t res = (v<<1) & 1; + rF=0; + FLAGS_SZXY(res); + if (v&0x80) SET_FLAGS(fC); + SET_PARITY_FLAG(); + return res; } - void SRL(uint8_t *v, uint8_t *r=nullptr) + static inline const uint8_t SRL(const uint8_t v) { - // [TODO] + 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) { - // [TODO] + const uint8_t res = v & 1<>pos) & 1) SET_FLAGS(fZ | fP); + if (res&0x80) SET_FLAGS(fS); + if (res&0x20) SET_FLAGS(fY); + if (res&0x08) SET_FLAGS(fX); } - void SET(uint8_t pos, uint8_t *v, uint8_t *r=nullptr) + static inline const uint8_t SET(uint8_t pos, const uint8_t v) { - // [TODO] + return v | (1<