#include "sm83.h" #include "mem.h" //#include "z80debug.h" //#include "z80mem.h" #include namespace sm83 { static uint32_t clock = 4194304; static uint32_t t = 0; static uint16_t current_opcode_address = 0; bool options[SM83_NUM_OPTIONS] = { true, false }; #define f0 0b00000001 #define f1 0b00000010 #define f2 0b00000100 #define f3 0b00001000 #define fC 0b00010000 #define fH 0b00100000 #define fN 0b01000000 #define fZ 0b10000000 #define cUnconditional 255 #define cNZ 0 #define cZ 1 #define cNC 2 #define cC 3 uint8_t regs[13]; 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]; uint16_t *_rSP = (uint16_t*)®s[8]; uint16_t *_rPC = (uint16_t*)®s[10]; uint8_t *_rIME = ®s[12]; bool exit_from_halt = false; int pending_ei = 0; #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 rAF (*_rAF) #define rBC (*_rBC) #define rDE (*_rDE) #define rHL (*_rHL) #define rSP (*_rSP) #define rPC (*_rPC) #define ime (*_rIME) #define EX(a,b) {auto temp=a;a=b;b=temp;} bool reading_m1 = false; uint8_t READ_MEM_8(const uint16_t addr, const bool code=false) { //if (z80debug::isbreak(addr, 2)) z80debug::stop(); t+=4; /* const uint8_t tag = z80mem::get()->getTag(addr); if ( !(tag&MEMTAG_IGNORE) ) { if (!code) { if ( tag & MEMTAG_INST ) { } else { z80mem::get()->setTag(addr, tag | MEMTAG_DATA); } } else { if ( (reading_m1) && ( tag & MEMTAG_DATA ) ) { } } } */ reading_m1 = false; return mem::readMem(addr); } uint8_t READ_MEM_8() { const uint8_t data = READ_MEM_8(rPC, true); //const uint8_t tag = z80mem::get()->getTag(rPC); //if ( !(tag & MEMTAG_IGNORE) ) z80mem::get()->setTag(rPC, tag | MEMTAG_CODE); rPC++; return data; } uint8_t READ_M1() { reading_m1 = true; 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+=4; mem::writeMem(addr, value); /* if (z80debug::isbreak(addr, 4)) z80debug::stop(); z80debug::setmemmodified(addr); const uint8_t tag = z80mem::get()->getTag(addr); if ( !(tag & MEMTAG_IGNORE) ) { if ( tag & MEMTAG_INST ) { //printf("WARNING! WRITING DATA OVER CODE!!! $%4X\n", addr); //z80debug::stop(); } else { z80mem::get()->setTag(addr, tag | MEMTAG_DATA | MEMTAG_TDATA); } } */ 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+=4; } 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; } void INC16(uint16_t *reg) { t+=4; (*reg)++; } void DEC16(uint16_t *reg) { t+=4; (*reg)--; } void ADD16(uint16_t* a, uint16_t b) { t+=4; const uint32_t res = *a + b; KEEP_FLAGS(fZ); if ( ((*a&0xfff)+(b&0xfff))&0x1000 ) SET_FLAGS(fH); if ( res > 0xffff ) SET_FLAGS(fC); *a = (uint16_t)res; } void INC8(uint8_t *reg) { uint8_t value = *reg + 1; KEEP_FLAGS(fC); if (value==0) SET_FLAGS(fZ); if ( (value & 0x0f) == 0x00 ) SET_FLAGS(fH); *reg = value; } void DEC8(uint8_t *reg) { uint8_t value = *reg - 1; KEEP_FLAGS(fC); SET_FLAGS(fN); if (value==0) SET_FLAGS(fZ); if ( (value & 0x0f) == 0x0f ) SET_FLAGS(fH); *reg = value; } void INCMEM8(const uint16_t addr) { uint8_t value = READ_MEM_8(addr); value++; KEEP_FLAGS(fC); if (value==0) SET_FLAGS(fZ); if ( (value & 0x0f) == 0x00 ) SET_FLAGS(fH); WRITE_MEM_8(addr, value); } void DECMEM8(const uint16_t addr) { uint8_t value = READ_MEM_8(addr); value--; KEEP_FLAGS(fC); SET_FLAGS(fN); if (value==0) SET_FLAGS(fZ); 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; if (res==0) SET_FLAGS(fZ); if ( (res & 0x0f) < (rA & 0x0f) ) SET_FLAGS(fH); if ( res < rA ) SET_FLAGS(fC); rA = (uint8_t)res; } void ADC8(uint8_t b) { if (!(rF & fC)) ADD8(b); else { uint16_t res = rA + b + 1; rF=0; if (res==0) SET_FLAGS(fZ); if ( (res & 0x0f) <= (rA & 0x0f) ) SET_FLAGS(fH); if ( res > 255 ) SET_FLAGS(fC); rA = (uint8_t)res; } } void SUB8(uint8_t b, const bool update=true) { const uint8_t res = rA - b; rF=0; if (res==0) SET_FLAGS(fZ); SET_FLAGS(fN); if ( (res & 0x0f) > (rA & 0x0f) ) SET_FLAGS(fH); if ( res > rA ) SET_FLAGS(fC); 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; if (res==0) SET_FLAGS(fZ); SET_FLAGS(fN); if ( (res & 0x0f) >= (rA & 0x0f) ) SET_FLAGS(fH); if ( res >= rA ) SET_FLAGS(fC); rA = (uint8_t)res; } } void AND(uint8_t b) { rA = rA & b; rF=fH; if (rA==0) SET_FLAGS(fZ); } void XOR(uint8_t b) { rA = rA ^ b; rF=0; if (rA==0) SET_FLAGS(fZ); } void OR(uint8_t b) { rA = rA | b; rF=0; if (rA==0) SET_FLAGS(fZ); } void CP(uint8_t b) { SUB8(b, false); } void RLCA() { const bool should_carry = rA & 0x80; rA = (rA>>7) | (rA<<1); rF = 0; if (should_carry) SET_FLAGS(fC); } void RRCA() { const bool should_carry = rA & 0x01; rA = (rA<<7) | (rA>>1); rF = 0; if (should_carry) SET_FLAGS(fC); } void RLA() { const bool should_carry = rA & 0x80; rA = (rA<<1) | (rF&fC); rF = 0; if (should_carry) SET_FLAGS(fC); } void RRA() { const bool should_carry = rA & 0x01; rA = ((rF&fC)<<7) | (rA>>1); rF = 0; if (should_carry) SET_FLAGS(fC); } /* void new_DAA() { uint8_t cf = rA > 0x99; uint8_t diff = ((rF & fH) || (rA & 0xF) > 9) ? 6 : 0; if ((rF & fC) || cf) diff |= 0x60; diff = (rF & fN) ? rA - diff : rA + diff; KEEP_FLAGS(fN | fC); FLAGS_SZXY(diff); SET_FLAGS(!(diff) << 6); SET_FLAGS((rA ^ diff) & fH); SET_PARITY_FLAG(diff); SET_FLAGS(cf); rA = diff; 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); if (rA==0) SET_FLAGS(fZ); if ( (rA & 0x0F) < (old & 0x0F) ) SET_FLAGS(fH); if (carry_set) SET_FLAGS(fC); } void CPL() { rA = ~rA; KEEP_FLAGS(fZ | fC); SET_FLAGS(fH | fN); } void SCF() { KEEP_FLAGS( fZ ); SET_FLAGS(fC); } void CCF() { const bool carry = (rF & fC); KEEP_FLAGS( fZ ); SET_FLAGS(carry ? fH : fC); } void JR(uint8_t cond = cUnconditional) { const int8_t d = (int8_t)READ_MEM_8(); if ( cond == cUnconditional || ( (cond == cNZ) && !(rF & fZ) ) || ( (cond == cZ) && (rF & fZ) ) || ( (cond == cNC) && !(rF & fC) ) || ( (cond == cC) && (rF & fC) ) ) { rPC = rPC + d; t+=4; } } void JP(uint8_t cond, uint16_t addr, const bool fast = false) { if ( cond == cUnconditional || ( (cond == cNZ) && !(rF & fZ) ) || ( (cond == cZ) && (rF & fZ) ) || ( (cond == cNC) && !(rF & fC) ) || ( (cond == cC) && (rF & fC) ) ) rPC = addr; if (!fast) t+=4; } void CALL(uint8_t cond, uint16_t addr) { if ( cond == cUnconditional || ( (cond == cNZ) && !(rF & fZ) ) || ( (cond == cZ) && (rF & fZ) ) || ( (cond == cNC) && !(rF & fC) ) || ( (cond == cC) && (rF & fC) ) ) { PUSH(rPC); rPC = addr; /*if (options[Z80_OPTION_BREAK_ON_RET]) { calls_stacked++; printf("CALL: calls stacked: %i", calls_stacked); }*/ } } void RET(uint8_t cond) { t+=4; if ( cond == cUnconditional || ( (cond == cNZ) && !(rF & fZ) ) || ( (cond == cZ) && (rF & fZ) ) || ( (cond == cNC) && !(rF & fC) ) || ( (cond == cC) && (rF & fC) ) ) { POP(_rPC); if (cond != cUnconditional) t += 4; /*if (options[Z80_OPTION_BREAK_ON_RET]) { if (calls_stacked>0) { calls_stacked--; printf("RET: calls still stacked: %i\n", calls_stacked); } else { printf("RET: BREAK\n"); options[Z80_OPTION_BREAK_ON_RET] = false; z80debug::setcursor(rPC); z80debug::history::store(); z80debug::stop(); } }*/ } } void DI(); void processInterrupts() { const uint8_t IF = mem::readMem(0xff0f); if ( (IF & 0x1f) == 0) return; DI(); PUSH(rPC); t+=20; if (IF & INTERRUPT_VBLANK) { rPC = 0x40; mem::writeMem(0xff0f, IF & ~INTERRUPT_VBLANK); } else if (IF & INTERRUPT_LCD) { rPC = 0x40; mem::writeMem(0xff0f, IF & ~INTERRUPT_LCD); } else if (IF & INTERRUPT_TIMER) { rPC = 0x40; mem::writeMem(0xff0f, IF & ~INTERRUPT_TIMER); } else if (IF & INTERRUPT_SERIAL) { rPC = 0x40; mem::writeMem(0xff0f, IF & ~INTERRUPT_SERIAL); } else if (IF & INTERRUPT_JOYPAD) { rPC = 0x40; mem::writeMem(0xff0f, IF & ~INTERRUPT_JOYPAD); } /*if (options[Z80_OPTION_BREAK_ON_INTERRUPT]) { printf("Break on interrupt! 0x%2x, PC: 0x%2x\n", address, rPC); z80debug::setcursor(rPC); z80debug::history::store(); z80debug::stop(); }*/ } void RETI() { RET(cUnconditional); *_rIME = 1; processInterrupts(); } void RST(uint8_t vec) { t-=4; // PUSH i RST duren el mateix en la gameboy, per tant llevem els 4 t que duiem de llegir el opcode PUSH(rPC); rPC = vec; } void DI() { pending_ei = 0; // If interrupts are disabled right after enabling them, they keep disabled *_rIME = 0; } void EI() { pending_ei = 1; // Enabling interrupts is delayed by one instruction } void actualEI() { *_rIME = 1; processInterrupts(); } void HALT() { if (exit_from_halt) { exit_from_halt = false; } else { //printf("HALT\n"); rPC--; } } void STOP() { HALT(); } void interrupt(uint8_t type) { exit_from_halt = true; const uint8_t IE = mem::readMem(0xffff); const uint8_t IF = mem::readMem(0xff0f); mem::writeMem(0xff0f, IF || (IE & type)); processInterrupts(); } static inline const uint8_t RLC(const uint8_t v) { const uint8_t res = (v>>7) | (v<<1); rF=0; if (res==0) SET_FLAGS(fZ); if (res&1) SET_FLAGS(fC); return res; } static inline const uint8_t RRC(const uint8_t v) { const uint8_t res = (v<<7) | (v>>1); rF=0; if (res==0) SET_FLAGS(fZ); if (res&0x80) SET_FLAGS(fC); return res; } static inline const uint8_t RL(const uint8_t v) { const uint8_t res = (v<<1) | (rF&fC); rF=0; if (res==0) SET_FLAGS(fZ); if (v&0x80) SET_FLAGS(fC); return res; } static inline const uint8_t RR(const uint8_t v) { const uint8_t res = ((rF&fC)<<7) | (v>>1); rF=0; if (res==0) SET_FLAGS(fZ); if (v&1) SET_FLAGS(fC); return res; } static inline const uint8_t SLA(const uint8_t v) { const uint8_t res = (v<<1); rF=0; if (res==0) SET_FLAGS(fZ); if (v&0x80) SET_FLAGS(fC); return res; } static inline const uint8_t SRA(const uint8_t v) { const uint8_t res = (v&0x80) | (v>>1); rF=0; if (res==0) SET_FLAGS(fZ); if (v&1) SET_FLAGS(fC); return res; } static inline const uint8_t SWAP(const uint8_t v) { const uint8_t res = (v<<4) | (v>>4); rF=0; if (res==0) SET_FLAGS(fZ); //if (v&0x80) SET_FLAGS(fC); // [TODO] fC reset o calculat? return res; } static inline const uint8_t SRL(const uint8_t v) { const uint8_t res = (v>>1); rF=0; if (res==0) SET_FLAGS(fZ); if (v&1) SET_FLAGS(fC); return res; } void BIT(uint8_t pos, uint8_t v) { const uint8_t res = v & 1<getTag(current_opcode_address); if ( !(tag & MEMTAG_IGNORE) ) tag = tag | MEMTAG_INST; z80mem::get()->setTag(current_opcode_address, tag | (!(tag&MEMTAG_TOUCHED) ? MEMTAG_TREPEAT : MEMTAG_TINST) );*/ uint16_t tmp; //if (opcode!=0xED && opcode!=0xCB && opcode!=0xDD && opcode!=0xFD ) z80debug::useOpcode(opcode, 0); switch (opcode) { case 0x00: /* NOP */ break; case 0x01: rBC = READ_MEM_16(); break; case 0x02: WRITE_MEM_8(rBC, rA); break; case 0x03: INC16(_rBC); break; case 0x04: INC8(_rB); break; case 0x05: DEC8(_rB); break; case 0x06: rB = READ_MEM_8(); break; case 0x07: RLCA(); break; case 0x08: WRITE_MEM_16(READ_MEM_16(), rSP);break; case 0x09: ADD16(_rHL, rBC); break; case 0x0A: rA = READ_MEM_8(rBC); break; case 0x0B: DEC16(_rBC); break; case 0x0C: INC8(_rC); break; case 0x0D: DEC8(_rC); break; case 0x0E: rC = READ_MEM_8(); break; case 0x0F: RRCA(); break; case 0x10: STOP(); break; case 0x11: rDE = READ_MEM_16(); break; case 0x12: WRITE_MEM_8(rDE, rA); break; case 0x13: INC16(_rDE); break; case 0x14: INC8(_rD); break; case 0x15: DEC8(_rD); break; case 0x16: rD = READ_MEM_8(); break; case 0x17: RLA(); break; case 0x18: JR(); break; case 0x19: ADD16(_rHL, rDE); break; case 0x1A: rA = READ_MEM_8(rDE); break; case 0x1B: DEC16(_rDE); break; case 0x1C: INC8(_rE); break; case 0x1D: DEC8(_rE); break; case 0x1E: rE = READ_MEM_8(); break; case 0x1F: RRA(); break; case 0x20: JR(cNZ); break; case 0x21: rHL = READ_MEM_16(); break; case 0x22: LDI_HL_A(); break; case 0x23: INC16(_rHL); break; case 0x24: INC8(_rH); break; case 0x25: DEC8(_rH); break; case 0x26: rH = READ_MEM_8(); break; case 0x27: DAA(); break; case 0x28: JR(cZ); break; case 0x29: ADD16(_rHL, rHL); break; case 0x2A: LDI_A_HL(); break; case 0x2B: DEC16(_rHL); break; case 0x2C: INC8(_rL); break; case 0x2D: DEC8(_rL); break; case 0x2E: rL = READ_MEM_8(); break; case 0x2F: CPL(); break; case 0x30: JR(cNC); break; case 0x31: rSP = READ_MEM_16(); break; case 0x32: LDD_HL_A(); break; case 0x33: INC16(_rSP); break; case 0x34: INCMEM8(rHL); break; case 0x35: DECMEM8(rHL); break; case 0x36: WRITE_MEM_8(rHL, READ_MEM_8()); break; case 0x37: SCF(); break; case 0x38: JR(cC); break; case 0x39: ADD16(_rHL, rSP); break; case 0x3A: LDD_A_HL(); break; case 0x3B: DEC16(_rSP); break; case 0x3C: INC8(_rA); break; case 0x3D: DEC8(_rA); break; case 0x3E: rA = READ_MEM_8(); break; case 0x3F: CCF(); break; case 0x40: rB = rB; break; case 0x41: rB = rC; break; case 0x42: rB = rD; break; case 0x43: rB = rE; break; case 0x44: rB = rH; break; case 0x45: rB = rL; break; case 0x46: rB = READ_MEM_8(rHL); break; case 0x47: rB = rA; break; case 0x48: rC = rB; break; case 0x49: rC = rC; break; case 0x4A: rC = rD; break; case 0x4B: rC = rE; break; case 0x4C: rC = rH; break; case 0x4D: rC = rL; break; case 0x4E: rC = READ_MEM_8(rHL); break; case 0x4F: rC = rA; break; case 0x50: rD = rB; break; case 0x51: rD = rC; break; case 0x52: rD = rD; break; case 0x53: rD = rE; break; case 0x54: rD = rH; break; case 0x55: rD = rL; break; case 0x56: rD = READ_MEM_8(rHL); break; case 0x57: rD = rA; break; case 0x58: rE = rB; break; case 0x59: rE = rC; break; case 0x5A: rE = rD; break; case 0x5B: rE = rE; break; case 0x5C: rE = rH; break; case 0x5D: rE = rL; break; case 0x5E: rE = READ_MEM_8(rHL); break; case 0x5F: rE = rA; break; case 0x60: rH = rB; break; case 0x61: rH = rC; break; case 0x62: rH = rD; break; case 0x63: rH = rE; break; case 0x64: rH = rH; break; case 0x65: rH = rL; break; case 0x66: rH = READ_MEM_8(rHL); break; case 0x67: rH = rA; break; case 0x68: rL = rB; break; case 0x69: rL = rC; break; case 0x6A: rL = rD; break; case 0x6B: rL = rE; break; case 0x6C: rL = rH; break; case 0x6D: rL = rL; break; case 0x6E: rL = READ_MEM_8(rHL); break; case 0x6F: rL = rA; break; case 0x70: WRITE_MEM_8(rHL, rB); break; case 0x71: WRITE_MEM_8(rHL, rC); break; case 0x72: WRITE_MEM_8(rHL, rD); break; case 0x73: WRITE_MEM_8(rHL, rE); break; case 0x74: WRITE_MEM_8(rHL, rH); break; case 0x75: WRITE_MEM_8(rHL, rL); break; case 0x76: HALT(); break; case 0x77: WRITE_MEM_8(rHL, rA); break; case 0x78: rA = rB; break; case 0x79: rA = rC; break; case 0x7A: rA = rD; break; case 0x7B: rA = rE; break; case 0x7C: rA = rH; break; case 0x7D: rA = rL; break; case 0x7E: rA = READ_MEM_8(rHL); break; case 0x7F: rA = rA; break; case 0x80: ADD8(rB); break; case 0x81: ADD8(rC); break; case 0x82: ADD8(rD); break; case 0x83: ADD8(rE); break; case 0x84: ADD8(rH); break; case 0x85: ADD8(rL); break; case 0x86: ADD8(READ_MEM_8(rHL)); break; case 0x87: ADD8(rA); break; case 0x88: ADC8(rB); break; case 0x89: ADC8(rC); break; case 0x8A: ADC8(rD); break; case 0x8B: ADC8(rE); break; case 0x8C: ADC8(rH); break; case 0x8D: ADC8(rL); break; case 0x8E: ADC8(READ_MEM_8(rHL)); break; case 0x8F: ADC8(rA); break; case 0x90: SUB8(rB); break; case 0x91: SUB8(rC); break; case 0x92: SUB8(rD); break; case 0x93: SUB8(rE); break; case 0x94: SUB8(rH); break; case 0x95: SUB8(rL); break; case 0x96: SUB8(READ_MEM_8(rHL)); break; case 0x97: SUB8(rA); break; case 0x98: SBC8(rB); break; case 0x99: SBC8(rC); break; case 0x9A: SBC8(rD); break; case 0x9B: SBC8(rE); break; case 0x9C: SBC8(rH); break; case 0x9D: SBC8(rL); break; case 0x9E: SBC8(READ_MEM_8(rHL)); break; case 0x9F: SBC8(rA); break; case 0xA0: AND(rB); break; case 0xA1: AND(rC); break; case 0xA2: AND(rD); break; case 0xA3: AND(rE); break; case 0xA4: AND(rH); break; case 0xA5: AND(rL); break; case 0xA6: AND(READ_MEM_8(rHL)); break; case 0xA7: AND(rA); break; case 0xA8: XOR(rB); break; case 0xA9: XOR(rC); break; case 0xAA: XOR(rD); break; case 0xAB: XOR(rE); break; case 0xAC: XOR(rH); break; case 0xAD: XOR(rL); break; case 0xAE: XOR(READ_MEM_8(rHL)); break; case 0xAF: XOR(rA); break; case 0xB0: OR(rB); break; case 0xB1: OR(rC); break; case 0xB2: OR(rD); break; case 0xB3: OR(rE); break; case 0xB4: OR(rH); break; case 0xB5: OR(rL); break; case 0xB6: OR(READ_MEM_8(rHL)); break; case 0xB7: OR(rA); break; case 0xB8: CP(rB); break; case 0xB9: CP(rC); break; case 0xBA: CP(rD); break; case 0xBB: CP(rE); break; case 0xBC: CP(rH); break; case 0xBD: CP(rL); break; case 0xBE: CP(READ_MEM_8(rHL)); break; case 0xBF: CP(rA); break; case 0xC0: RET(cNZ); break; case 0xC1: POP(_rBC); break; case 0xC2: JP(cNZ, READ_MEM_16()); break; case 0xC3: JP(cUnconditional, READ_MEM_16());break; case 0xC4: CALL(cNZ, READ_MEM_16()); break; case 0xC5: PUSH(rBC); break; case 0xC6: ADD8(READ_MEM_8()); break; case 0xC7: RST(0x00); break; case 0xC8: RET(cZ); break; case 0xC9: RET(cUnconditional); break; case 0xCA: JP(cZ, READ_MEM_16()); break; case 0xCB: BIT_INSTRUCTIONS(); break; case 0xCC: CALL(cZ, READ_MEM_16()); break; case 0xCD: CALL(cUnconditional, READ_MEM_16());break; case 0xCE: ADC8(READ_MEM_8()); break; case 0xCF: RST(0x08); break; case 0xD0: RET(cNC); break; case 0xD1: POP(_rDE); break; case 0xD2: JP(cNC, READ_MEM_16()); break; case 0xD3: IgnoreOpcode(); break; case 0xD4: CALL(cNC, READ_MEM_16()); break; case 0xD5: PUSH(rDE); break; case 0xD6: SUB8(READ_MEM_8()); break; case 0xD7: RST(0x10); break; case 0xD8: RET(cC); break; case 0xD9: RETI(); break; case 0xDA: JP(cC, READ_MEM_16()); break; case 0xDB: IgnoreOpcode(); break; case 0xDC: CALL(cC, READ_MEM_16()); break; case 0xDD: IgnoreOpcode(); break; case 0xDE: SBC8(READ_MEM_8()); break; case 0xDF: RST(0x18); break; case 0xE0: WRITE_MEM_8(READ_MEM_8()|0xff00, rA);break; case 0xE1: POP(_rHL); break; case 0xE2: WRITE_MEM_8(rC|0xff00, rA); break; case 0xE3: IgnoreOpcode(); break; case 0xE4: IgnoreOpcode(); break; case 0xE5: PUSH(rHL); break; case 0xE6: AND(READ_MEM_8()); break; case 0xE7: RST(0x20); break; case 0xE8: ADD16(_rSP, (int8_t)READ_MEM_8());break; /*[TODO] es correcte? ha de ser signed*/ case 0xE9: JP(cUnconditional, rHL, true); break; case 0xEA: WRITE_MEM_8(READ_MEM_16(), rA); break; case 0xEB: IgnoreOpcode(); break; case 0xEC: IgnoreOpcode(); break; case 0xED: IgnoreOpcode(); break; case 0xEE: XOR(READ_MEM_8()); break; case 0xEF: RST(0x28); break; case 0xF0: rA = READ_MEM_8(READ_MEM_8()|0xff00);break; case 0xF1: POP(_rAF); break; case 0xF2: rA = READ_MEM_8(rC|0xff00); break; case 0xF3: DI(); break; case 0xF4: IgnoreOpcode(); break; case 0xF5: PUSH(rAF); break; case 0xF6: OR(READ_MEM_8()); break; case 0xF7: RST(0x30); break; case 0xF8: rHL = rSP + (int8_t)READ_MEM_8();break; /*[TODO] es correcte? ha de ser signed*/ case 0xF9: rSP = rHL; t+=2; break; case 0xFA: rA = READ_MEM_8(READ_MEM_16()); break; case 0xFB: EI(); break; case 0xFC: IgnoreOpcode(); break; case 0xFD: IgnoreOpcode(); break; case 0xFE: CP(READ_MEM_8()); break; case 0xFF: RST(0x38); break; } } while (opcode_ignored); if (pending_ei==2) { pending_ei=0; actualEI(); } if (pending_ei==1) pending_ei=2; /*z80debug::setcursor(rPC); z80debug::history::store();*/ return t; } void BIT_INSTRUCTIONS() { const uint8_t opcode = READ_M1(); //z80debug::useOpcode(opcode, 2); switch (opcode) { case 0x00: rB = RLC(rB); break; case 0x01: rC = RLC(rC); break; case 0x02: rD = RLC(rD); break; case 0x03: rE = RLC(rE); break; case 0x04: rH = RLC(rH); break; case 0x05: rL = RLC(rL); break; case 0x06: WRITE_MEM_8(rHL, RLC(READ_MEM_8(rHL))); break; case 0x07: rA = RLC(rA); break; case 0x08: rB = RRC(rB); break; case 0x09: rC = RRC(rC); break; case 0x0A: rD = RRC(rD); break; case 0x0B: rE = RRC(rE); break; case 0x0C: rH = RRC(rH); break; case 0x0D: rL = RRC(rL); break; case 0x0E: WRITE_MEM_8(rHL, RRC(READ_MEM_8(rHL))); break; case 0x0F: rA = RRC(rA); break; case 0x10: rB = RL(rB); break; case 0x11: rC = RL(rC); break; case 0x12: rD = RL(rD); break; case 0x13: rE = RL(rE); break; case 0x14: rH = RL(rH); break; case 0x15: rL = RL(rL); break; case 0x16: WRITE_MEM_8(rHL, RL(READ_MEM_8(rHL))); break; case 0x17: rA = RL(rA); break; case 0x18: rB = RR(rB); break; case 0x19: rC = RR(rC); break; case 0x1A: rD = RR(rD); break; case 0x1B: rE = RR(rE); break; case 0x1C: rH = RR(rH); break; case 0x1D: rL = RR(rL); break; case 0x1E: WRITE_MEM_8(rHL, RR(READ_MEM_8(rHL))); break; case 0x1F: rA = RR(rA); break; case 0x20: rB = SLA(rB); break; case 0x21: rC = SLA(rC); break; case 0x22: rD = SLA(rD); break; case 0x23: rE = SLA(rE); break; case 0x24: rH = SLA(rH); break; case 0x25: rL = SLA(rL); break; case 0x26: WRITE_MEM_8(rHL, SLA(READ_MEM_8(rHL))); break; case 0x27: rA = SLA(rA); break; case 0x28: rB = SRA(rB); break; case 0x29: rC = SRA(rC); break; case 0x2A: rD = SRA(rD); break; case 0x2B: rE = SRA(rE); break; case 0x2C: rH = SRA(rH); break; case 0x2D: rL = SRA(rL); break; case 0x2E: WRITE_MEM_8(rHL, SRA(READ_MEM_8(rHL))); break; case 0x2F: rA = SRA(rA); break; case 0x30: rB = SWAP(rB); break; case 0x31: rC = SWAP(rC); break; case 0x32: rD = SWAP(rD); break; case 0x33: rE = SWAP(rE); break; case 0x34: rH = SWAP(rH); break; case 0x35: rL = SWAP(rL); break; case 0x36: WRITE_MEM_8(rHL, SWAP(READ_MEM_8(rHL))); break; case 0x37: rA = SWAP(rA); break; case 0x38: rB = SRL(rB); break; case 0x39: rC = SRL(rC); break; case 0x3A: rD = SRL(rD); break; case 0x3B: rE = SRL(rE); break; case 0x3C: rH = SRL(rH); break; case 0x3D: rL = SRL(rL); break; case 0x3E: WRITE_MEM_8(rHL, SRL(READ_MEM_8(rHL))); break; case 0x3F: rA = SRL(rA); break; case 0x40: BIT(0, rB); break; case 0x41: BIT(0, rC); break; case 0x42: BIT(0, rD); break; case 0x43: BIT(0, rE); break; case 0x44: BIT(0, rH); break; case 0x45: BIT(0, rL); break; case 0x46: BIT(0, READ_MEM_8(rHL)); break; case 0x47: BIT(0, rA); break; case 0x48: BIT(1, rB); break; case 0x49: BIT(1, rC); break; case 0x4A: BIT(1, rD); break; case 0x4B: BIT(1, rE); break; case 0x4C: BIT(1, rH); break; case 0x4D: BIT(1, rL); break; case 0x4E: BIT(1, READ_MEM_8(rHL)); break; case 0x4F: BIT(1, rA); break; case 0x50: BIT(2, rB); break; case 0x51: BIT(2, rC); break; case 0x52: BIT(2, rD); break; case 0x53: BIT(2, rE); break; case 0x54: BIT(2, rH); break; case 0x55: BIT(2, rL); break; case 0x56: BIT(2, READ_MEM_8(rHL)); break; case 0x57: BIT(2, rA); break; case 0x58: BIT(3, rB); break; case 0x59: BIT(3, rC); break; case 0x5A: BIT(3, rD); break; case 0x5B: BIT(3, rE); break; case 0x5C: BIT(3, rH); break; case 0x5D: BIT(3, rL); break; case 0x5E: BIT(3, READ_MEM_8(rHL)); break; case 0x5F: BIT(3, rA); break; case 0x60: BIT(4, rB); break; case 0x61: BIT(4, rC); break; case 0x62: BIT(4, rD); break; case 0x63: BIT(4, rE); break; case 0x64: BIT(4, rH); break; case 0x65: BIT(4, rL); break; case 0x66: BIT(4, READ_MEM_8(rHL)); break; case 0x67: BIT(4, rA); break; case 0x68: BIT(5, rB); break; case 0x69: BIT(5, rC); break; case 0x6A: BIT(5, rD); break; case 0x6B: BIT(5, rE); break; case 0x6C: BIT(5, rH); break; case 0x6D: BIT(5, rL); break; case 0x6E: BIT(5, READ_MEM_8(rHL)); break; case 0x6F: BIT(5, rA); break; case 0x70: BIT(6, rB); break; case 0x71: BIT(6, rC); break; case 0x72: BIT(6, rD); break; case 0x73: BIT(6, rE); break; case 0x74: BIT(6, rH); break; case 0x75: BIT(6, rL); break; case 0x76: BIT(6, READ_MEM_8(rHL)); break; case 0x77: BIT(6, rA); break; case 0x78: BIT(7, rB); break; case 0x79: BIT(7, rC); break; case 0x7A: BIT(7, rD); break; case 0x7B: BIT(7, rE); break; case 0x7C: BIT(7, rH); break; case 0x7D: BIT(7, rL); break; case 0x7E: BIT(7, READ_MEM_8(rHL)); break; case 0x7F: BIT(7, rA); break; case 0x80: rB = RES(0, rB); break; case 0x81: rC = RES(0, rC); break; case 0x82: rD = RES(0, rD); break; case 0x83: rE = RES(0, rE); break; case 0x84: rH = RES(0, rH); break; case 0x85: rL = RES(0, rL); break; case 0x86: WRITE_MEM_8(rHL, RES(0, READ_MEM_8(rHL)));break; case 0x87: rA = RES(0, rA); break; case 0x88: rB = RES(1, rB); break; case 0x89: rC = RES(1, rC); break; case 0x8A: rD = RES(1, rD); break; case 0x8B: rE = RES(1, rE); break; case 0x8C: rH = RES(1, rH); break; case 0x8D: rL = RES(1, rL); break; case 0x8E: WRITE_MEM_8(rHL, RES(1, READ_MEM_8(rHL)));break; case 0x8F: rA = RES(1, rA); break; case 0x90: rB = RES(2, rB); break; case 0x91: rC = RES(2, rC); break; case 0x92: rD = RES(2, rD); break; case 0x93: rE = RES(2, rE); break; case 0x94: rH = RES(2, rH); break; case 0x95: rL = RES(2, rL); break; case 0x96: WRITE_MEM_8(rHL, RES(2, READ_MEM_8(rHL)));break; case 0x97: rA = RES(2, rA); break; case 0x98: rB = RES(3, rB); break; case 0x99: rC = RES(3, rC); break; case 0x9A: rD = RES(3, rD); break; case 0x9B: rE = RES(3, rE); break; case 0x9C: rH = RES(3, rH); break; case 0x9D: rL = RES(3, rL); break; case 0x9E: WRITE_MEM_8(rHL, RES(3, READ_MEM_8(rHL)));break; case 0x9F: rA = RES(3, rA); break; case 0xA0: rB = RES(4, rB); break; case 0xA1: rC = RES(4, rC); break; case 0xA2: rD = RES(4, rD); break; case 0xA3: rE = RES(4, rE); break; case 0xA4: rH = RES(4, rH); break; case 0xA5: rL = RES(4, rL); break; case 0xA6: WRITE_MEM_8(rHL, RES(4, READ_MEM_8(rHL)));break; case 0xA7: rA = RES(4, rA); break; case 0xA8: rB = RES(5, rB); break; case 0xA9: rC = RES(5, rC); break; case 0xAA: rD = RES(5, rD); break; case 0xAB: rE = RES(5, rE); break; case 0xAC: rH = RES(5, rH); break; case 0xAD: rL = RES(5, rL); break; case 0xAE: WRITE_MEM_8(rHL, RES(5, READ_MEM_8(rHL)));break; case 0xAF: rA = RES(5, rA); break; case 0xB0: rB = RES(6, rB); break; case 0xB1: rC = RES(6, rC); break; case 0xB2: rD = RES(6, rD); break; case 0xB3: rE = RES(6, rE); break; case 0xB4: rH = RES(6, rH); break; case 0xB5: rL = RES(6, rL); break; case 0xB6: WRITE_MEM_8(rHL, RES(6, READ_MEM_8(rHL)));break; case 0xB7: rA = RES(6, rA); break; case 0xB8: rB = RES(7, rB); break; case 0xB9: rC = RES(7, rC); break; case 0xBA: rD = RES(7, rD); break; case 0xBB: rE = RES(7, rE); break; case 0xBC: rH = RES(7, rH); break; case 0xBD: rL = RES(7, rL); break; case 0xBE: WRITE_MEM_8(rHL, RES(7, READ_MEM_8(rHL)));break; case 0xBF: rA = RES(7, rA); break; case 0xC0: rB = SET(0, rB); break; case 0xC1: rC = SET(0, rC); break; case 0xC2: rD = SET(0, rD); break; case 0xC3: rE = SET(0, rE); break; case 0xC4: rH = SET(0, rH); break; case 0xC5: rL = SET(0, rL); break; case 0xC6: WRITE_MEM_8(rHL, SET(0, READ_MEM_8(rHL)));break; case 0xC7: rA = SET(0, rA); break; case 0xC8: rB = SET(1, rB); break; case 0xC9: rC = SET(1, rC); break; case 0xCA: rD = SET(1, rD); break; case 0xCB: rE = SET(1, rE); break; case 0xCC: rH = SET(1, rH); break; case 0xCD: rL = SET(1, rL); break; case 0xCE: WRITE_MEM_8(rHL, SET(1, READ_MEM_8(rHL)));break; case 0xCF: rA = SET(1, rA); break; case 0xD0: rB = SET(2, rB); break; case 0xD1: rC = SET(2, rC); break; case 0xD2: rD = SET(2, rD); break; case 0xD3: rE = SET(2, rE); break; case 0xD4: rH = SET(2, rH); break; case 0xD5: rL = SET(2, rL); break; case 0xD6: WRITE_MEM_8(rHL, SET(2, READ_MEM_8(rHL)));break; case 0xD7: rA = SET(2, rA); break; case 0xD8: rB = SET(3, rB); break; case 0xD9: rC = SET(3, rC); break; case 0xDA: rD = SET(3, rD); break; case 0xDB: rE = SET(3, rE); break; case 0xDC: rH = SET(3, rH); break; case 0xDD: rL = SET(3, rL); break; case 0xDE: WRITE_MEM_8(rHL, SET(3, READ_MEM_8(rHL)));break; case 0xDF: rA = SET(3, rA); break; case 0xE0: rB = SET(4, rB); break; case 0xE1: rC = SET(4, rC); break; case 0xE2: rD = SET(4, rD); break; case 0xE3: rE = SET(4, rE); break; case 0xE4: rH = SET(4, rH); break; case 0xE5: rL = SET(4, rL); break; case 0xE6: WRITE_MEM_8(rHL, SET(4, READ_MEM_8(rHL)));break; case 0xE7: rA = SET(4, rA); break; case 0xE8: rB = SET(5, rB); break; case 0xE9: rC = SET(5, rC); break; case 0xEA: rD = SET(5, rD); break; case 0xEB: rE = SET(5, rE); break; case 0xEC: rH = SET(5, rH); break; case 0xED: rL = SET(5, rL); break; case 0xEE: WRITE_MEM_8(rHL, SET(5, READ_MEM_8(rHL)));break; case 0xEF: rA = SET(5, rA); break; case 0xF0: rB = SET(6, rB); break; case 0xF1: rC = SET(6, rC); break; case 0xF2: rD = SET(6, rD); break; case 0xF3: rE = SET(6, rE); break; case 0xF4: rH = SET(6, rH); break; case 0xF5: rL = SET(6, rL); break; case 0xF6: WRITE_MEM_8(rHL, SET(6, READ_MEM_8(rHL)));break; case 0xF7: rA = SET(6, rA); break; case 0xF8: rB = SET(7, rB); break; case 0xF9: rC = SET(7, rC); break; case 0xFA: rD = SET(7, rD); break; case 0xFB: rE = SET(7, rE); break; case 0xFC: rH = SET(7, rH); break; case 0xFD: rL = SET(7, rL); break; case 0xFE: WRITE_MEM_8(rHL, SET(7, READ_MEM_8(rHL)));break; case 0xFF: rA = SET(7, rA); break; } } //uint8_t *getMem() { return memory; } uint8_t *getRegs() { return regs; } uint16_t getAF() { return rAF; } uint16_t getBC() { return rBC; } uint16_t getDE() { return rDE; } uint16_t getHL() { return rHL; } uint16_t getSP() { return rSP; } uint16_t getPC() { return rPC; } void setPC(const uint16_t addr) { rPC = addr; } /* uint8_t getMemTag(const uint16_t addr) { return memtag[addr]; } void setMemTag(const uint16_t addr, const uint8_t value) { memtag[addr] = value; } void clearMemTag() { for (int i=0; i<65536; ++i) memtag[i] = MEMTAG_NONE; } uint8_t getMemTouched(const uint16_t addr) { return memtouched[addr]; } void clearMemTouched() { for (int i=0; i<65536; ++i) memtouched[i] = MEMTAG_NONE; } void fixMemTouched() { for (int i=0; i<65536; ++i) if ( (memtouched[i]==MEMTAG_INST) || (memtouched[i]==MEMTAG_REPEAT) ) memtouched[i] = MEMTAG_DATA; //else if (memtouched[i]==MEMTAG_DATA) // memtouched[i] = MEMTAG_REPEAT; } */ const bool getOption(const int option) { return options[option]; } void setOption(const int option, const bool value) { options[option] = value; } void toggleOption(const int option) { options[option] = !options[option]; } }