diff --git a/cpu/cpu.h b/cpu/cpu.h index 8efd834..15f0b52 100644 --- a/cpu/cpu.h +++ b/cpu/cpu.h @@ -62,6 +62,31 @@ enum IME_state IME_ON, }; +struct opcode { + const opcode_t value; + + inline operator opcode_t() const + { return value; } + + inline u8 reg8idxlo() const + { return value & 0x7; } + + inline u8 reg8idxhi() const + { return (value >> 3) & 0x7; } + + inline u8 reg16idx() const + { return (value >> 4) & 0x3; } + + inline AluOp aluop() const + { return (AluOp)((value >> 3) & 0x7); } + + inline u8 cc() const + { return (value >> 3) & 0x3; } + + inline u16 rst_addr() const + { return (u16)(value & 0x38); } +}; + struct Cpu_state { // Registers union { diff --git a/cpu/decoder.cpp b/cpu/decoder.cpp index fb6c6ba..0d6d0f7 100644 --- a/cpu/decoder.cpp +++ b/cpu/decoder.cpp @@ -20,7 +20,8 @@ static inline void add16(Cpu& cpu, u16& out, u16 lhs, u16 rhs) void Cpu::executeInstruction() { u16 currentpc = state.PC; - opcode_t op = readPC8(); + opcode op{ readPC8() }; + int mcycles = 1; #if 0 @@ -30,41 +31,41 @@ void Cpu::executeInstruction() if ((op & 0xC0) == 0x40 && op != 0x76) // LD r, r'; LD r, [HL]; LD [HL], r { u8 tmp; - switch(op & 0x07) + switch(op.reg8idxlo()) { case 0x6: tmp = bus->read8(state.HL); break; - default: tmp = state.reg8(op & 0x07); break; + default: tmp = state.reg8(op.reg8idxlo()); break; }; - switch((op >> 3) & 0x7) + switch(op.reg8idxhi()) { case 0x6: bus->write8(state.HL, tmp); break; - default: state.reg8((op >> 3) & 0x7) = tmp; break; + default: state.reg8(op.reg8idxhi()) = tmp; break; } } else if((op & 0xC7) == 0x06) // LD r, n { u8 imm = readPC8(); - switch((op >> 3) & 0x7) + switch(op.reg8idxhi()) { case 0x6: bus->write8(state.HL, imm); break; - default: state.reg8((op >> 3) & 0x7) = imm; break; + default: state.reg8(op.reg8idxhi()) = imm; break; } } else if((op & 0xCF) == 0x01) // LD rr, nn { u16 data = readPC16(); - state.reg16((op >> 4) & 0x3) = data; + state.reg16(op.reg16idx()) = data; mcycles = 3; } else if((op & 0xCF) == 0xC5) // PUSH rr { u16 data; - switch((op >> 4) & 0x3) + switch(op.reg16idx()) { case 0x3: data = state.getAF(); break; - default: data = state.reg16((op >> 4) & 0x3); + default: data = state.reg16(op.reg16idx()); } pushStack16(data); @@ -75,39 +76,35 @@ void Cpu::executeInstruction() { u16 data = popStack16(); - switch((op >> 4) & 0x3) + switch(op.reg16idx()) { case 0x3: state.setAF(data); break; - default: state.reg16((op >> 4) & 0x3) = data; break; + default: state.reg16(op.reg16idx()) = data; break; } mcycles = 4; } else if((op & 0xC0) == 0x80) // ADD, ADC, SUB, SBC, CP, AND, OR, XOR { - AluOp aluop = (AluOp)((op >> 3) & 0x3); - u8 reg = op & 0x7; - u8 rhs; - switch(reg) + switch(op.reg8idxlo()) { case 0x6: rhs = bus->read8(state.HL); mcycles = 2; break; - default: rhs = state.reg8(reg); break; + default: rhs = state.reg8(op.reg8idxlo()); break; } - aluop8(aluop, rhs); + aluop8(op.aluop(), rhs); } else if((op & 0xC7) == 0xC6) // ADD n, ADC n, SUB n, SBC n, AND n, XOR n, OR n, CP n { - AluOp aluop = (AluOp)((op >> 3) & 0x3); - aluop8(aluop, readPC8()); + aluop8(op.aluop(), readPC8()); mcycles = 2; } else if((op & 0xC6) == 0x04) // INC r; INC [HL]; DEC r; DEC [HL]; { AluOp aluop = (op & 0x1) ? SUB : ADD; - switch((op >> 3) & 0x7) + switch(op.reg8idxhi()) { case 0x6: { @@ -119,7 +116,7 @@ void Cpu::executeInstruction() break; default: { - u8& reg = state.reg8((op >> 3) & 0x7); + u8& reg = state.reg8(op.reg8idxhi()); aluop8(aluop, reg, 1, reg, false); break; } break; @@ -127,14 +124,14 @@ void Cpu::executeInstruction() } else if((op & 0xC7) == 0x03) // INC rr; DEC rr { - state.reg16((op >> 4) & 0x3) += ((op & 0x08) ? -1 : 1); + state.reg16(op.reg16idx()) += ((op & 0x08) ? -1 : 1); mcycles = 2; } else if((op & 0xE7) == 0xC2) // JP cc, nn: { u16 nn = readPC16(); - if (decodeCond((op >> 3) && 0x3)) + if (decodeCond(op.cc())) { state.PC = nn; mcycles = 4; @@ -147,7 +144,7 @@ void Cpu::executeInstruction() s8 e = readPC8(); bool cond; - if (decodeCond((op >> 3) & 0x3)) + if (decodeCond(op.cc())) { state.PC += e; mcycles = 3; @@ -159,7 +156,7 @@ void Cpu::executeInstruction() { u16 nn = readPC16(); - if(decodeCond((op >> 3) & 0x3)) + if(decodeCond(op.cc())) { doCall(nn); mcycles = 6; @@ -169,12 +166,12 @@ void Cpu::executeInstruction() } else if((op & 0xCF) == 0x09) // ADD HL, rr { - add16(*this, state.HL, state.HL, state.reg16((op >> 4) & 0x3)); + add16(*this, state.HL, state.HL, state.reg16(op.reg16idx())); mcycles = 2; } else if((op & 0xE7) == 0xC0) // RET cc { - if(decodeCond((op >> 3) & 0x3)) + if(decodeCond(op.cc())) { doRet(); mcycles = 5; @@ -184,29 +181,26 @@ void Cpu::executeInstruction() } else if((op & 0xC7) == 0xC7) // RST { - u16 rst_addr = op & 0x38; - doCall(rst_addr); + doCall(op.rst_addr()); } else if(op == 0xCB) // PREFIX { currentpc = state.PC; - opcode_t prefix_op = readPC8(); + opcode prefix_op{ readPC8() }; #if 0 printf("@0x%04x: CB opcode %02X\n", currentpc, prefix_op); #endif - u8 reg = prefix_op & 0x7; - u8 data; - switch(reg) + switch(prefix_op.reg8idxlo()) { case 0x6: data = bus->read8(state.HL); mcycles = 3; break; - default: data = state.reg8(reg); mcycles = 2; break; + default: data = state.reg8(prefix_op.reg8idxlo()); mcycles = 2; break; } // For BIT, RES, SET - u8 bit = (prefix_op >> 3) & 0x7; + u8 bit = prefix_op.reg8idxhi(); switch(prefix_op & 0xC0) { @@ -278,10 +272,10 @@ void Cpu::executeInstruction() // All ops except for BIT write the data back to where it came from if ((prefix_op & 0xC0) != 0x40) { - switch(reg) + switch(prefix_op.reg8idxlo()) { case 0x6: bus->write8(state.HL, data); mcycles = 4; break; - default: state.reg8(reg) = data; break; + default: state.reg8(prefix_op.reg8idxlo()) = data; break; } } }