#include "cpu/cpu.h" #include "cpu/panic.h" #include "memory/mem_device.h" static inline u16 make_u16(u8 msb, u8 lsb) { return (((u16)msb << 8) | (u16)lsb); } void Cpu::executeInstruction() { u16 currentpc = state.PC; opcode_t op = readPC8(); int mcycles = 1; #if 0 printf("@0x%04x: opcode %02X\n",currentpc,op); #endif if ((op & 0xC0) == 0x40 && op != 0x76) // LD r, r' { u8 tmp; switch(op & 0x07) { case 0x6: tmp = bus->read8(state.HL); break; default: tmp = state.reg8(op & 0x07); break; }; switch((op >> 3) & 0x7) { case 0x6: bus->write8(state.HL, tmp); break; default: state.reg8((op >> 3) & 0x7) = tmp; break; } } else if((op & 0xC7) == 0x06) // LD r, n { u8 imm = readPC8(); switch((op >> 3) & 0x7) { case 0x6: bus->write8(state.HL, imm); break; default: state.reg8((op >> 3) & 0x7) = imm; break; } } else if((op & 0xC7) == 0x46 && op != 0x76) // LD r, [HL] { u8 data = bus->read8(state.HL); state.reg8((op >> 3) & 0x7) = data; } else if((op & 0xC8) == 0x70 && op != 0x76) // LD [HL], r { u8 data = state.reg8(op & 0x7); bus->write8(state.HL, data); } else if((op & 0xCF) == 0x01) // LD rr, nn { u16 data = readPC16(); state.reg16((op >> 4) & 0x3) = data; mcycles = 3; } else if((op & 0xCF) == 0xC5) // PUSH rr { u16 data; switch((op >> 4) & 0x3) { case 0x3: data = state.getAF(); break; default: data = state.reg16((op >> 4) & 0x3); } state.SP-=2; bus->write16(state.SP, data); mcycles = 4; } else if((op & 0xCF) == 0xC1) // POP rr { u16 data = bus->read16(state.SP); state.SP+=2; switch((op >> 4) & 0x3) { case 0x3: state.setAF(data); break; default: state.reg16((op >> 4) & 0x3) = data; break; } mcycles = 4; } else if((op & 0xC0) == 0x80) // ADD, ADC, SUB, ABC, CP, AND, OR, XOR { // SUB r: 0b10010xxx // CP r: 0b10111xxx // SBC r: 0b10011xxx AluOp aluop = (AluOp)((op >> 3) & 0x3); u8 rhs; switch(op & 0x7) { case 0x6: rhs = bus->read8(state.HL); mcycles = 2; break; default: rhs = state.reg8(op & 0x7); break; } aluop8(aluop, rhs); } else if((op & 0xC6) == 0x04) // INC r; INC [HL]; DEC r; DEC [HL]; { AluOp aluop = (op & 0x1) ? SUB : ADD; switch((op >> 3) & 0x7) { case 0x6: { u8 tmp = bus->read8(state.HL); aluop8(aluop, tmp, 1, tmp, false); bus->write8(state.HL, tmp); mcycles = 3; } break; default: { u8& reg = state.reg8((op >> 3) & 0x7); aluop8(aluop, reg, 1, reg, false); break; } break; } } else if((op & 0xE7) == 0xC2) // JP cc, nn: { u16 nn = readPC16(); if (decodeCond((op >> 3) && 0x3)) { state.PC = nn; mcycles = 4; } else { mcycles = 3; } } else if((op & 0xE7) == 0x20) // JR cc, e { s8 e = readPC8(); bool cond; if (decodeCond((op >> 3) & 0x3)) { state.PC += e; mcycles = 3; } else { mcycles = 2; } } else if((op & 0xE7) == 0xC4) // CALL cc, nn { u16 nn = readPC16(); if(decodeCond((op >> 3) & 0x3)) { doCall(nn); mcycles = 6; } else { mcycles = 3; } } else if((op & 0xE7) == 0xC0) // RET cc { if(decodeCond((op >> 3) & 0x3)) { doRet(); mcycles = 5; } else { mcycles = 2; } } else if((op & 0xC7) == 0xC7) // RST { u16 rst_addr = op & 0x38; doCall(rst_addr); } else { switch(op) { case 0x00: break; // NOP case 0x0A: // Load A, [BC] state.A = bus->read8(state.BC); mcycles = 2; break; case 0x1A: // Load A, [DE] state.A = bus->read8(state.DE); mcycles = 2; break; case 0x02: // Load [BC], A bus->write8(state.BC, state.A); mcycles = 2; break; case 0x12: // Load [DE], A bus->write8(state.DE, state.A); mcycles = 2; break; case 0xFA: // LD A, [nn] { u16 addr = readPC16(); state.A = bus->read8(addr); mcycles = 4; } break; case 0xEA: // LD [nn], A { u16 addr = readPC16(); bus->write8(addr, state.A); mcycles = 4; } break; case 0xF2: // LD A, [0xFF : C] state.A = bus->read8(make_u16(0xFFu,state.C)); mcycles = 2; break; case 0xE2: // LD [0xFF : C], A bus->write8(make_u16(0xFFu,state.C), state.A); mcycles = 2; break; case 0xF0: // LD A, [0xFF : n] state.A = bus->read8(make_u16(0xFFu,readPC8())); mcycles = 3; break; case 0xE0: // LD [0xFF : n], A bus->write8(make_u16(0xFFu,readPC8()), state.A); mcycles = 3; break; case 0x3A: // LD A, [HL-] state.A = bus->read8(state.HL); state.HL--; mcycles = 2; break; case 0x2A: // LD A, [HL+] state.A = bus->read8(state.HL); state.HL++; mcycles = 2; break; case 0x32: // LD [HL-], A bus->write8(state.HL, state.A); state.HL--; mcycles = 2; break; case 0x22: // LD [HL-], A bus->write8(state.HL, state.A); state.HL++; mcycles = 2; break; case 0x08: // LD [nn], SP bus->write16(readPC16(), state.SP); mcycles = 5; break; case 0xF9: // LD SP, HL state.SP = state.HL; mcycles = 2; break; case 0xC6: // ADD n aluop8(ADD, readPC8()); mcycles = 2; break; case 0xD6: // SUB n aluop8(SUB, readPC8()); mcycles = 2; break; case 0xE6: // AND n aluop8(AND, readPC8()); mcycles = 2; break; case 0xF6: // OR n aluop8(OR, readPC8()); mcycles = 2; break; case 0xCE: // ADC n aluop8(ADC, readPC8()); mcycles = 2; break; case 0xDE: // SBC n aluop8(SBC, readPC8()); mcycles = 2; break; case 0xEE: // XOR n aluop8(XOR, readPC8()); mcycles = 2; break; case 0xFE: // CP n aluop8(CP, readPC8()); mcycles = 2; break; case 0x3F: // CCF complement carry flag state.carry = !state.carry; state.subtract = false; state.halfcarry = false; break; case 0x37: // SCF Set carry flag state.carry = true; state.subtract = false; state.halfcarry = false; break; // TODO: case 0x27: break; // DAA case 0x2F: // CPL Complement accumulator state.A = ~state.A; state.subtract = true; state.halfcarry = true; case 0xC3: // JP nn { u16 nn = readPC16(); state.PC = nn; mcycles = 4; } break; case 0xE9: // JP HL state.PC = state.HL; break; case 0x18: // JR e { s8 e = readPC8(); state.PC += e; } case 0xCD: // CALL nn doCall(readPC16()); mcycles = 6; break; case 0xC9: // RET doRet(); mcycles = 4; break; case 0xD9: // RETI doRet(); state.IME = IME_ON; mcycles = 4; break; case 0xF3: // DI state.IME = IME_OFF; break; case 0xFB: // EI state.IME = IME_SCHEDULED; break; default: panic("Unknown opcode 0x%x\n",op); } } processed_mcycles += mcycles; }