cpu/decoder - define opcode class with methods
Instead of doing the same bit operations on the opcode everywhere, and possibly botching it in the process, we create a datatype which has methods return often used values extracted from the opcode.
This commit is contained in:
parent
ef9bda4a30
commit
175a24c77d
2 changed files with 57 additions and 38 deletions
25
cpu/cpu.h
25
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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue