2023-08-26 19:04:02 +02:00
|
|
|
#include "cpu/cpu.h"
|
2023-08-26 21:17:47 +02:00
|
|
|
#include "memory/mem_device.h"
|
2023-08-26 19:04:02 +02:00
|
|
|
|
|
|
|
u8 Cpu::readPC8()
|
|
|
|
{
|
|
|
|
u8 data = bus->read8(state.PC);
|
|
|
|
state.PC++;
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
u16 Cpu::readPC16()
|
|
|
|
{
|
|
|
|
u16 data = bus->read16(state.PC);
|
|
|
|
state.PC+=2;
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2023-08-26 21:17:47 +02:00
|
|
|
void Cpu::pushStack8(u8 data)
|
2023-08-26 19:04:02 +02:00
|
|
|
{
|
|
|
|
bus->write8(state.SP, data);
|
|
|
|
state.SP--;
|
|
|
|
}
|
|
|
|
|
2023-08-26 21:17:47 +02:00
|
|
|
u8 Cpu::popStack8()
|
2023-08-26 19:04:02 +02:00
|
|
|
{
|
|
|
|
u8 data = bus->read8(state.SP);
|
|
|
|
state.SP++;
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2023-08-26 21:17:47 +02:00
|
|
|
void Cpu::pushStack16(u16 data)
|
2023-08-26 19:04:02 +02:00
|
|
|
{
|
|
|
|
bus->write16(state.SP,data);
|
|
|
|
state.SP-=2;
|
|
|
|
}
|
|
|
|
|
2023-08-26 21:17:47 +02:00
|
|
|
u16 Cpu::popStack16()
|
2023-08-26 19:04:02 +02:00
|
|
|
{
|
|
|
|
u16 data = bus->read16(state.SP);
|
|
|
|
state.SP+=2;
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Cpu::step()
|
|
|
|
{
|
2023-08-26 21:17:47 +02:00
|
|
|
opcode_t op = readPC8();
|
2023-08-26 19:04:02 +02:00
|
|
|
int mcycles = 1;
|
2023-08-26 21:17:47 +02:00
|
|
|
|
2023-08-27 00:15:12 +02:00
|
|
|
if ((op & 0xC0 == 0x40) && op != 0x76) // LD r, r'
|
2023-08-26 21:17:47 +02:00
|
|
|
{
|
2023-08-27 00:15:12 +02:00
|
|
|
u8 tmp;
|
2023-08-26 23:51:51 +02:00
|
|
|
switch(op & 0x07)
|
|
|
|
{
|
|
|
|
case 0x0: tmp = state.B; break;
|
|
|
|
case 0x1: tmp = state.C; break;
|
|
|
|
case 0x2: tmp = state.D; break;
|
|
|
|
case 0x3: tmp = state.E; break;
|
|
|
|
case 0x4: tmp = state.H; break;
|
|
|
|
case 0x5: tmp = state.L; break;
|
|
|
|
case 0x6: tmp = bus->read8(state.HL); break;
|
|
|
|
case 0x7: tmp = state.A; break;
|
|
|
|
};
|
|
|
|
|
2023-08-27 00:15:12 +02:00
|
|
|
switch((op >> 3) & 0x7)
|
2023-08-26 23:51:51 +02:00
|
|
|
{
|
2023-08-27 00:15:12 +02:00
|
|
|
case 0x0: state.B = tmp; break;
|
|
|
|
case 0x1: state.C = tmp; break;
|
|
|
|
case 0x2: state.D = tmp; break;
|
|
|
|
case 0x3: state.E = tmp; break;
|
|
|
|
case 0x4: state.H = tmp; break;
|
|
|
|
case 0x5: state.L = tmp; break;
|
|
|
|
case 0x6: bus->write8(state.HL, tmp); break;
|
|
|
|
case 0x7: state.A = tmp; break;
|
2023-08-26 23:51:51 +02:00
|
|
|
}
|
2023-08-26 21:17:47 +02:00
|
|
|
}
|
2023-08-27 00:15:12 +02:00
|
|
|
else if(op & 0xC7 == 0x06) // LD r, n
|
2023-08-26 21:17:47 +02:00
|
|
|
{
|
2023-08-27 00:15:12 +02:00
|
|
|
u8 imm = readPC8();
|
2023-08-26 23:51:51 +02:00
|
|
|
|
2023-08-27 00:15:12 +02:00
|
|
|
switch((op >> 3) & 0x7)
|
|
|
|
{
|
|
|
|
case 0x0: state.B = imm; break;
|
|
|
|
case 0x1: state.C = imm; break;
|
|
|
|
case 0x2: state.D = imm; break;
|
|
|
|
case 0x3: state.E = imm; break;
|
|
|
|
case 0x4: state.H = imm; break;
|
|
|
|
case 0x5: state.L = imm; break;
|
|
|
|
case 0x6: bus->write8(state.HL, tmp); break;
|
|
|
|
case 0x7: state.A = imm; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(op & 0xC7 == 0x46 && op != 0x76) // LD r, [HL]
|
|
|
|
{
|
|
|
|
u8 data = bus->read8(state.HL);
|
|
|
|
|
|
|
|
switch((op >> 3) & 0x7)
|
|
|
|
{
|
|
|
|
case 0x0: state.B = imm; break;
|
|
|
|
case 0x1: state.C = imm; break;
|
|
|
|
case 0x2: state.D = imm; break;
|
|
|
|
case 0x3: state.E = imm; break;
|
|
|
|
case 0x4: state.H = imm; break;
|
|
|
|
case 0x5: state.L = imm; break;
|
|
|
|
case 0x7: state.A = imm; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(op & 0xC8 == 0x70 && op != 0x76) // LD [HL], r
|
|
|
|
{
|
|
|
|
u8 data;
|
|
|
|
switch(op & 0x7)
|
|
|
|
{
|
|
|
|
case 0x0: data = state.B; break;
|
|
|
|
case 0x1: data = state.C; break;
|
|
|
|
case 0x2: data = state.D; break;
|
|
|
|
case 0x3: data = state.E; break;
|
|
|
|
case 0x4: data = state.H; break;
|
|
|
|
case 0x5: data = state.L; break;
|
|
|
|
case 0x7: data = state.A; break;
|
|
|
|
}
|
|
|
|
|
|
|
|
bus->write8(state.HL, data);
|
2023-08-26 23:51:51 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch(op)
|
|
|
|
{
|
|
|
|
case 0x00: break; // NOP
|
|
|
|
|
|
|
|
case 0x01: // LD BC, n16
|
|
|
|
state.BC = readPC16(); mcycles = 12; break;
|
|
|
|
case 0x11: // LD DE, n16
|
|
|
|
state.DE = readPC16(); mcycles = 12; break;
|
|
|
|
case 0x21: // LD HL, n16
|
|
|
|
state.HL = readPC16(); mcycles = 12; break;
|
|
|
|
case 0x31: // LD SP, n16
|
|
|
|
state.SP = readPC16(); mcycles = 12; break;
|
|
|
|
|
|
|
|
case 0x02: // LD [BC], A
|
|
|
|
bus->write8(state.BC, state.A); mcycles = 8; break;
|
|
|
|
case 0x12: // LD [DE], A
|
|
|
|
bus->write8(state.DE, state.A); mcycles = 8; break;
|
|
|
|
case 0x22: // LD [HL+], A
|
|
|
|
bus->write8(state.HL, state.A); state.HL++; mcycles = 8; break;
|
|
|
|
case 0x32: // LD [HL-], A
|
|
|
|
bus->write8(state.HL, state.A); state.HL--; mcycles = 8; break;
|
|
|
|
|
|
|
|
case 0x03: // INC BC
|
|
|
|
state.BC++; mcycles = 2; break;
|
|
|
|
case 0x13: // INC DE
|
|
|
|
state.DE++; mcycles = 2; break;
|
|
|
|
case 0x23: // INC HL
|
|
|
|
state.HL++; mcycles = 2; break;
|
|
|
|
case 0x33: // INC SP
|
|
|
|
state.SP++; mcycles = 2; break;
|
|
|
|
|
|
|
|
case 0x04: // INC B
|
|
|
|
state.B++;
|
|
|
|
state.zero = (state.B == 0);
|
|
|
|
state.subtract = false;
|
|
|
|
state.halfcarry = (state.B & 0x0F == 0);
|
|
|
|
break;
|
|
|
|
case 0x14: // INC D
|
|
|
|
state.D++;
|
|
|
|
state.zero = (state.D == 0);
|
|
|
|
state.subtract = false;
|
|
|
|
state.halfcarry = (state.D & 0x0F == 0);
|
|
|
|
break;
|
|
|
|
case 0x24: // INC H
|
|
|
|
state.H++;
|
|
|
|
state.zero = (state.H == 0);
|
|
|
|
state.subtract = false;
|
|
|
|
state.halfcarry = (state.H & 0x0F == 0);
|
|
|
|
break;
|
|
|
|
case 0x34: // INC [HL]
|
|
|
|
{
|
|
|
|
u8 data = bus->read8(state.HL);
|
|
|
|
data++;
|
|
|
|
bus->write8(state.HL, data);
|
|
|
|
state.zero = (data == 0);
|
|
|
|
state.subtract = false;
|
|
|
|
state.halfcarry = (data & 0x0F == 0);
|
|
|
|
mcycles = 3;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x05: // INC B
|
|
|
|
state.B--;
|
|
|
|
state.zero = (state.B == 0);
|
|
|
|
state.subtract = true;
|
|
|
|
state.halfcarry = (state.B & 0x0F == 0x0F);
|
|
|
|
break;
|
|
|
|
case 0x15: // INC D
|
|
|
|
state.D--;
|
|
|
|
state.zero = (state.D == 0);
|
|
|
|
state.subtract = true;
|
|
|
|
state.halfcarry = (state.D & 0x0F == 0x0F);
|
|
|
|
break;
|
|
|
|
case 0x25: // INC H
|
|
|
|
state.H--;
|
|
|
|
state.zero = (state.H == 0);
|
|
|
|
state.subtract = true;
|
|
|
|
state.halfcarry = (state.H & 0x0F == 0x0F);
|
|
|
|
break;
|
|
|
|
case 0x35: // INC [HL]
|
|
|
|
{
|
|
|
|
u8 data = bus->read8(state.HL);
|
|
|
|
data--;
|
|
|
|
bus->write8(state.HL, data);
|
|
|
|
state.zero = (data == 0);
|
|
|
|
state.subtract = true;
|
|
|
|
state.halfcarry = (data & 0x0F == 0x0F);
|
|
|
|
mcycles = 3;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x06: // LD B, n8
|
|
|
|
state.B = readPC8();
|
|
|
|
mcycles = 2;
|
|
|
|
break;
|
|
|
|
case 0x16: // LD D, n8
|
|
|
|
state.D = readPC8();
|
|
|
|
mcycles = 2;
|
|
|
|
break;
|
|
|
|
case 0x26: // LD H, n8
|
|
|
|
state.H = readPC8();
|
|
|
|
mcycles = 2;
|
|
|
|
break;
|
|
|
|
case 0x36: // LD [HL], n8
|
|
|
|
bus->write8(state.HL, readPC8());
|
|
|
|
mcycles = 3;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x07: // RLCA
|
|
|
|
case 0x17: // RLA
|
|
|
|
case 0x27: // DAA
|
|
|
|
case 0x37: // SCF
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x08: // LD [a16], SP
|
|
|
|
{
|
|
|
|
u16 addr = readPC16();
|
|
|
|
bus->write16(addr, state.SP);
|
|
|
|
mcycles = 5;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 0x18: // JR e8
|
|
|
|
{
|
|
|
|
s8 rel = readPC8();
|
|
|
|
state.PC = state.PC + rel;
|
|
|
|
mcycles = 3;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 0x28: // JR Z, e8
|
|
|
|
{
|
|
|
|
s8 rel = readPC8();
|
|
|
|
if (state.zero)
|
|
|
|
{
|
|
|
|
state.PC = state.PC + rel;
|
|
|
|
mcycles = 3;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mcycles = 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 0x38: // JR C, e8
|
|
|
|
{
|
|
|
|
s8 rel = readPC8();
|
|
|
|
if (state.carry)
|
|
|
|
{
|
|
|
|
state.PC = state.PC + rel;
|
|
|
|
mcycles = 3;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mcycles = 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x09: // ADD HL, BC
|
|
|
|
case 0x19: // ADD HL, DE
|
|
|
|
case 0x29: // ADD HL, HL
|
|
|
|
case 0x39: // ADD HL, SP
|
|
|
|
// TODO
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x0A: // LD A, [BC]
|
|
|
|
state.A = bus->read8(state.BC);
|
|
|
|
break;
|
|
|
|
case 0x1A: // LD A, [DE]
|
|
|
|
state.A = bus->read8(state.DE);
|
|
|
|
break;
|
|
|
|
case 0x2A: // LD A, [HL+]
|
|
|
|
state.A = bus->read8(state.HL);
|
|
|
|
state.HL++;
|
|
|
|
break;
|
|
|
|
case 0x3A: // LD A, [HL-]
|
|
|
|
state.A = bus->read8(state.HL);
|
|
|
|
state.HL--;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x0B: // DEC BC
|
|
|
|
state.BC--;
|
|
|
|
break;
|
|
|
|
case 0x1B: // DEC DE
|
|
|
|
state.DE--;
|
|
|
|
break;
|
|
|
|
case 0x2B: // DEC HL
|
|
|
|
state.HL--;
|
|
|
|
break;
|
|
|
|
case 0x3B: // DEC SP
|
|
|
|
state.SP--;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x0C: // INC C
|
|
|
|
state.C++;
|
|
|
|
state.zero = (state.C == 0);
|
|
|
|
state.subtract = false;
|
|
|
|
state.halfcarry = (state.C & 0x0F == 0);
|
|
|
|
break;
|
|
|
|
case 0x1C: // INC E
|
|
|
|
state.E++;
|
|
|
|
state.zero = (state.E == 0);
|
|
|
|
state.subtract = false;
|
|
|
|
state.halfcarry = (state.E & 0x0F == 0);
|
|
|
|
break;
|
|
|
|
case 0x2C: // INC L
|
|
|
|
state.L++;
|
|
|
|
state.zero = (state.L == 0);
|
|
|
|
state.subtract = false;
|
|
|
|
state.halfcarry = (state.L & 0x0F == 0);
|
|
|
|
break;
|
|
|
|
case 0x3C: // INC A
|
|
|
|
state.A++;
|
|
|
|
state.zero = (state.A == 0);
|
|
|
|
state.subtract = false;
|
|
|
|
state.halfcarry = (state.A & 0x0F == 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x0D: // DEC C
|
|
|
|
state.C--;
|
|
|
|
state.zero = (state.C == 0);
|
|
|
|
state.subtract = true;
|
|
|
|
state.halfcarry = (state.C & 0x0F == 0x0F);
|
|
|
|
break;
|
|
|
|
case 0x1D: // DEC E
|
|
|
|
state.E--;
|
|
|
|
state.zero = (state.E == 0);
|
|
|
|
state.subtract = true;
|
|
|
|
state.halfcarry = (state.E & 0x0F == 0x0F);
|
|
|
|
break;
|
|
|
|
case 0x2D: // DEC L
|
|
|
|
state.L--;
|
|
|
|
state.zero = (state.L == 0);
|
|
|
|
state.subtract = true;
|
|
|
|
state.halfcarry = (state.L & 0x0F == 0x0F);
|
|
|
|
break;
|
|
|
|
case 0x3D: // DEC A
|
|
|
|
state.A--;
|
|
|
|
state.zero = (state.A == 0);
|
|
|
|
state.subtract = true;
|
|
|
|
state.halfcarry = (state.A & 0x0F == 0x0F);
|
|
|
|
break;
|
|
|
|
case 0x0E: // LD C, n8
|
|
|
|
state.C = readPC8();
|
|
|
|
mcycles = 2;
|
|
|
|
break;
|
|
|
|
case 0x1E: // LD E, n8
|
|
|
|
state.E = readPC8();
|
|
|
|
mcycles = 2;
|
|
|
|
break;
|
|
|
|
case 0x2E: // LD L, n8
|
|
|
|
state.L = readPC8();
|
|
|
|
mcycles = 2;
|
|
|
|
break;
|
|
|
|
case 0x3E: // LD A, n8
|
|
|
|
state.A = readPC8();
|
|
|
|
mcycles = 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x0F: // RRCA
|
|
|
|
case 0x1F: // RRA
|
|
|
|
case 0x2F: // CPL
|
|
|
|
case 0x3F: // CCF
|
|
|
|
// TODO
|
|
|
|
break;
|
|
|
|
}
|
2023-08-26 21:17:47 +02:00
|
|
|
}
|
2023-08-26 19:04:02 +02:00
|
|
|
}
|