Implement more parts of decoder
This commit is contained in:
parent
93521e559c
commit
ad2334a6af
8 changed files with 469 additions and 265 deletions
11
Makeconf
11
Makeconf
|
@ -1,6 +1,9 @@
|
||||||
modules := test \
|
modules := memory/mem_device \
|
||||||
memory/bus \
|
memory/bus \
|
||||||
memory/ram \
|
memory/ram \
|
||||||
cpu/decoder
|
cpu/cpu \
|
||||||
|
cpu/decoder
|
||||||
|
|
||||||
|
modules += test
|
||||||
|
|
||||||
CXX_FLAGS := -I $(CURDIR)
|
CXX_FLAGS := -I $(CURDIR)
|
||||||
|
|
91
cpu/cpu.cpp
Normal file
91
cpu/cpu.cpp
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
#include "cpu.h"
|
||||||
|
|
||||||
|
void Cpu_state::setAF(u16 v)
|
||||||
|
{
|
||||||
|
A = (u8)(v >> 8);
|
||||||
|
zero = (v & 0x80 != 0);
|
||||||
|
subtract = (v & 0x40 != 0);
|
||||||
|
halfcarry = (v & 0x20 != 0);
|
||||||
|
carry = (v & 0x10 != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 Cpu_state::getAF()
|
||||||
|
{
|
||||||
|
return ((u16)A << 8) |
|
||||||
|
(zero ? 0x80 : 0) |
|
||||||
|
(subtract ? 0x40 : 0) |
|
||||||
|
(halfcarry ? 0x20 : 0) |
|
||||||
|
(carry ? 0x10 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::aluop8(AluOp op, u8 lhs, u8 rhs, u8& out, bool update_carry)
|
||||||
|
{
|
||||||
|
u16 rhs16 = rhs;
|
||||||
|
u16 res16;
|
||||||
|
u8 res;
|
||||||
|
|
||||||
|
if ((op == ADC || op == SBC) && state.carry)
|
||||||
|
rhs16++;
|
||||||
|
|
||||||
|
u16 lhs_lower = lhs & 0x0F;
|
||||||
|
u16 lhs_upper = lhs & 0xF0;
|
||||||
|
u16 rhs_lower = rhs16 & 0x0F;
|
||||||
|
u16 rhs_upper = rhs16 & 0x1F0;
|
||||||
|
|
||||||
|
switch(op)
|
||||||
|
{
|
||||||
|
case ADD:
|
||||||
|
case ADC:
|
||||||
|
res16 = lhs_lower + rhs_lower;
|
||||||
|
break;
|
||||||
|
case SUB:
|
||||||
|
case SBC:
|
||||||
|
case CP:
|
||||||
|
res16 = lhs_lower - rhs_lower;
|
||||||
|
break;
|
||||||
|
case AND:
|
||||||
|
res16 = lhs_lower & rhs_lower;
|
||||||
|
break;
|
||||||
|
case OR:
|
||||||
|
res16 = lhs_lower | rhs_lower;
|
||||||
|
break;
|
||||||
|
case XOR:
|
||||||
|
res16 = lhs_lower ^ rhs_lower;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.halfcarry = (res16 & 0x10 != 0) || op == AND;
|
||||||
|
state.subtract = (op == SUB) || (op == SBC) || (op == CP);
|
||||||
|
|
||||||
|
switch(op)
|
||||||
|
{
|
||||||
|
case ADD:
|
||||||
|
case ADC:
|
||||||
|
res16 += lhs_upper + rhs_upper;
|
||||||
|
break;
|
||||||
|
case SUB:
|
||||||
|
case SBC:
|
||||||
|
case CP:
|
||||||
|
res16 += lhs_upper - rhs_upper;
|
||||||
|
break;
|
||||||
|
case AND:
|
||||||
|
res16 |= lhs_upper & rhs_upper;
|
||||||
|
break;
|
||||||
|
case OR:
|
||||||
|
res16 |= lhs_upper | rhs_upper;
|
||||||
|
break;
|
||||||
|
case XOR:
|
||||||
|
res16 |= lhs_upper ^ rhs_upper;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = (u8)(res16 & 0xFF);
|
||||||
|
|
||||||
|
if(update_carry)
|
||||||
|
state.carry = (res16 & 0x100 != 0);
|
||||||
|
|
||||||
|
state.zero = (res == 0);
|
||||||
|
|
||||||
|
if (op != CP)
|
||||||
|
out = res;
|
||||||
|
}
|
43
cpu/cpu.h
43
cpu/cpu.h
|
@ -12,6 +12,26 @@ enum Flags {
|
||||||
F_CARRY = 0x1,
|
F_CARRY = 0x1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum AluOp : int {
|
||||||
|
ADD = 0,
|
||||||
|
ADC = 1,
|
||||||
|
SUB = 2,
|
||||||
|
SBC = 3,
|
||||||
|
AND = 4,
|
||||||
|
XOR = 5,
|
||||||
|
OR = 6,
|
||||||
|
CP = 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum CC
|
||||||
|
{
|
||||||
|
COND_NZ = 0,
|
||||||
|
COND_Z = 1,
|
||||||
|
COND_NC = 2,
|
||||||
|
COND_C = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct Cpu_state {
|
struct Cpu_state {
|
||||||
// Registers
|
// Registers
|
||||||
union {
|
union {
|
||||||
|
@ -35,6 +55,15 @@ struct Cpu_state {
|
||||||
bool subtract;
|
bool subtract;
|
||||||
bool halfcarry;
|
bool halfcarry;
|
||||||
bool carry;
|
bool carry;
|
||||||
|
|
||||||
|
bool IME; // interrupts enabled/disabled
|
||||||
|
bool IME_scheduled; // interrupts about to be enabled
|
||||||
|
|
||||||
|
|
||||||
|
bool bootRomEnabled; // Whether boot ROM is visible
|
||||||
|
|
||||||
|
void setAF(u16 v);
|
||||||
|
u16 getAF();
|
||||||
};
|
};
|
||||||
|
|
||||||
class Cpu {
|
class Cpu {
|
||||||
|
@ -53,6 +82,20 @@ private:
|
||||||
|
|
||||||
void pushStack16(u16 data);
|
void pushStack16(u16 data);
|
||||||
u16 popStack16();
|
u16 popStack16();
|
||||||
|
|
||||||
|
void aluop8(AluOp op, u8 lhs, u8 rhs, u8& out, bool update_carry = true);
|
||||||
|
|
||||||
|
inline
|
||||||
|
void aluop8(AluOp op, u8 rhs, bool update_carry = true)
|
||||||
|
{
|
||||||
|
aluop8(op, state.A, rhs, state.A, update_carry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void doCall(u16 target);
|
||||||
|
void doRet();
|
||||||
|
|
||||||
|
bool decodeCond(u8 cc);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Cpu();
|
Cpu();
|
||||||
|
|
||||||
|
|
556
cpu/decoder.cpp
556
cpu/decoder.cpp
|
@ -1,6 +1,11 @@
|
||||||
#include "cpu/cpu.h"
|
#include "cpu/cpu.h"
|
||||||
#include "memory/mem_device.h"
|
#include "memory/mem_device.h"
|
||||||
|
|
||||||
|
static inline u16 make_u16(u8 msb, u8 lsb)
|
||||||
|
{
|
||||||
|
return (((u16)msb << 8) | (u16)lsb);
|
||||||
|
}
|
||||||
|
|
||||||
u8 Cpu::readPC8()
|
u8 Cpu::readPC8()
|
||||||
{
|
{
|
||||||
u8 data = bus->read8(state.PC);
|
u8 data = bus->read8(state.PC);
|
||||||
|
@ -41,6 +46,30 @@ u16 Cpu::popStack16()
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Cpu::doCall(u16 target)
|
||||||
|
{
|
||||||
|
pushStack16(state.PC);
|
||||||
|
state.PC = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::doRet()
|
||||||
|
{
|
||||||
|
state.PC = popStack16();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Cpu::decodeCond(u8 cc)
|
||||||
|
{
|
||||||
|
switch(cc)
|
||||||
|
{
|
||||||
|
case COND_NZ: return !state.zero; break;
|
||||||
|
case COND_Z: return state.zero; break;
|
||||||
|
case COND_NC: return !state.carry; break;
|
||||||
|
case COND_C: return state.carry; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void Cpu::step()
|
void Cpu::step()
|
||||||
{
|
{
|
||||||
opcode_t op = readPC8();
|
opcode_t op = readPC8();
|
||||||
|
@ -85,7 +114,7 @@ void Cpu::step()
|
||||||
case 0x3: state.E = imm; break;
|
case 0x3: state.E = imm; break;
|
||||||
case 0x4: state.H = imm; break;
|
case 0x4: state.H = imm; break;
|
||||||
case 0x5: state.L = imm; break;
|
case 0x5: state.L = imm; break;
|
||||||
case 0x6: bus->write8(state.HL, tmp); break;
|
case 0x6: bus->write8(state.HL, imm); break;
|
||||||
case 0x7: state.A = imm; break;
|
case 0x7: state.A = imm; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,13 +124,13 @@ void Cpu::step()
|
||||||
|
|
||||||
switch((op >> 3) & 0x7)
|
switch((op >> 3) & 0x7)
|
||||||
{
|
{
|
||||||
case 0x0: state.B = imm; break;
|
case 0x0: state.B = data; break;
|
||||||
case 0x1: state.C = imm; break;
|
case 0x1: state.C = data; break;
|
||||||
case 0x2: state.D = imm; break;
|
case 0x2: state.D = data; break;
|
||||||
case 0x3: state.E = imm; break;
|
case 0x3: state.E = data; break;
|
||||||
case 0x4: state.H = imm; break;
|
case 0x4: state.H = data; break;
|
||||||
case 0x5: state.L = imm; break;
|
case 0x5: state.L = data; break;
|
||||||
case 0x7: state.A = imm; break;
|
case 0x7: state.A = data; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(op & 0xC8 == 0x70 && op != 0x76) // LD [HL], r
|
else if(op & 0xC8 == 0x70 && op != 0x76) // LD [HL], r
|
||||||
|
@ -120,272 +149,311 @@ void Cpu::step()
|
||||||
|
|
||||||
bus->write8(state.HL, data);
|
bus->write8(state.HL, data);
|
||||||
}
|
}
|
||||||
|
else if(op & 0xCF == 0x01) // LD rr, nn
|
||||||
|
{
|
||||||
|
u16 data = readPC16();
|
||||||
|
|
||||||
|
switch((op >> 4) & 0x3)
|
||||||
|
{
|
||||||
|
case 0x0: state.BC = data; break;
|
||||||
|
case 0x1: state.DE = data; break;
|
||||||
|
case 0x2: state.HL = data; break;
|
||||||
|
case 0x3: state.SP = data; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mcycles = 3;
|
||||||
|
}
|
||||||
|
else if(op & 0xCF == 0xC5) // PUSH rr
|
||||||
|
{
|
||||||
|
u16 data;
|
||||||
|
switch((op >> 4) & 0x3)
|
||||||
|
{
|
||||||
|
case 0x0: data = state.BC; break;
|
||||||
|
case 0x1: data = state.DE; break;
|
||||||
|
case 0x2: data = state.HL; break;
|
||||||
|
case 0x3: data = state.getAF(); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 0x0: state.BC = data; break;
|
||||||
|
case 0x1: state.DE = data; break;
|
||||||
|
case 0x2: state.HL = data; break;
|
||||||
|
case 0x3: state.setAF(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 0x0: rhs = state.B; break;
|
||||||
|
case 0x1: rhs = state.C; break;
|
||||||
|
case 0x2: rhs = state.D; break;
|
||||||
|
case 0x3: rhs = state.E; break;
|
||||||
|
case 0x4: rhs = state.H; break;
|
||||||
|
case 0x5: rhs = state.L; break;
|
||||||
|
case 0x6: rhs = bus->read8(state.HL); mcycles = 2; break;
|
||||||
|
case 0x7: rhs = state.A; 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 0x0: aluop8(aluop, state.B, 1, state.B, false); break;
|
||||||
|
case 0x1: aluop8(aluop, state.C, 1, state.C, false); break;
|
||||||
|
case 0x2: aluop8(aluop, state.D, 1, state.D, false); break;
|
||||||
|
case 0x3: aluop8(aluop, state.E, 1, state.E, false); break;
|
||||||
|
case 0x4: aluop8(aluop, state.H, 1, state.C, false); break;
|
||||||
|
case 0x5: aluop8(aluop, state.L, 1, state.L, false); break;
|
||||||
|
case 0x7: aluop8(aluop, state.A, 1, state.A, false); break;
|
||||||
|
|
||||||
|
case 0x6:
|
||||||
|
{
|
||||||
|
u8 tmp = bus->read8(state.HL);
|
||||||
|
aluop8(aluop, tmp, 1, tmp, false);
|
||||||
|
bus->write8(state.HL, tmp);
|
||||||
|
mcycles = 3;
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
u16 rst_addr;
|
||||||
|
switch((op >> 3) & 0x7)
|
||||||
|
{
|
||||||
|
case 0x0: rst_addr = 0x00; break;
|
||||||
|
case 0x1: rst_addr = 0x08; break;
|
||||||
|
case 0x2: rst_addr = 0x10; break;
|
||||||
|
case 0x3: rst_addr = 0x18; break;
|
||||||
|
case 0x4: rst_addr = 0x20; break;
|
||||||
|
case 0x5: rst_addr = 0x28; break;
|
||||||
|
case 0x6: rst_addr = 0x30; break;
|
||||||
|
case 0x7: rst_addr = 0x38; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
doCall(rst_addr);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
switch(op)
|
switch(op)
|
||||||
{
|
{
|
||||||
case 0x00: break; // NOP
|
case 0x00: break; // NOP
|
||||||
|
case 0x0A: // Load A, [BC]
|
||||||
case 0x01: // LD BC, n16
|
state.A = bus->read8(state.BC);
|
||||||
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;
|
mcycles = 2;
|
||||||
break;
|
break;
|
||||||
case 0x16: // LD D, n8
|
case 0x1A: // Load A, [DE]
|
||||||
state.D = readPC8();
|
state.A = bus->read8(state.DE);
|
||||||
mcycles = 2;
|
mcycles = 2;
|
||||||
break;
|
break;
|
||||||
case 0x26: // LD H, n8
|
case 0x02: // Load [BC], A
|
||||||
state.H = readPC8();
|
bus->write8(state.BC, state.A);
|
||||||
mcycles = 2;
|
mcycles = 2;
|
||||||
break;
|
break;
|
||||||
case 0x36: // LD [HL], n8
|
case 0x12: // Load [DE], A
|
||||||
bus->write8(state.HL, readPC8());
|
bus->write8(state.DE, state.A);
|
||||||
mcycles = 3;
|
mcycles = 2;
|
||||||
break;
|
break;
|
||||||
|
case 0xFA: // LD A, [nn]
|
||||||
case 0x07: // RLCA
|
|
||||||
case 0x17: // RLA
|
|
||||||
case 0x27: // DAA
|
|
||||||
case 0x37: // SCF
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x08: // LD [a16], SP
|
|
||||||
{
|
{
|
||||||
u16 addr = readPC16();
|
u16 addr = readPC16();
|
||||||
bus->write16(addr, state.SP);
|
state.A = bus->read8(addr);
|
||||||
mcycles = 5;
|
mcycles = 4;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x18: // JR e8
|
case 0xEA: // LD [nn], A
|
||||||
{
|
{
|
||||||
s8 rel = readPC8();
|
u16 addr = readPC16();
|
||||||
state.PC = state.PC + rel;
|
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]
|
||||||
|
{
|
||||||
|
u8 n = readPC8();
|
||||||
|
state.A = bus->read8(make_u16(0xFFu,n));
|
||||||
mcycles = 3;
|
mcycles = 3;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x28: // JR Z, e8
|
case 0xE0: // LD [0xFF : n], A
|
||||||
{
|
{
|
||||||
s8 rel = readPC8();
|
u8 n = readPC8();
|
||||||
if (state.zero)
|
bus->write8(make_u16(0xFFu,n), state.A);
|
||||||
{
|
mcycles = 3;
|
||||||
state.PC = state.PC + rel;
|
|
||||||
mcycles = 3;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mcycles = 2;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
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-]
|
case 0x3A: // LD A, [HL-]
|
||||||
state.A = bus->read8(state.HL);
|
state.A = bus->read8(state.HL); state.HL--; mcycles = 2; break;
|
||||||
state.HL--;
|
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;
|
break;
|
||||||
|
|
||||||
case 0x0B: // DEC BC
|
case 0x37: // SCF Set carry flag
|
||||||
state.BC--;
|
state.carry = true;
|
||||||
break;
|
state.subtract = false;
|
||||||
case 0x1B: // DEC DE
|
state.halfcarry = false;
|
||||||
state.DE--;
|
|
||||||
break;
|
|
||||||
case 0x2B: // DEC HL
|
|
||||||
state.HL--;
|
|
||||||
break;
|
|
||||||
case 0x3B: // DEC SP
|
|
||||||
state.SP--;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x0C: // INC C
|
case 0x27: // DAA
|
||||||
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
|
// TODO
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
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=true; mcycles = 4; break;
|
||||||
|
|
||||||
|
case 0xF3: // DI
|
||||||
|
state.IME = false;
|
||||||
|
state.IME_scheduled = false;
|
||||||
|
break;
|
||||||
|
case 0xFB: // EI
|
||||||
|
state.IME_scheduled = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
14
memory/mem_device.cpp
Normal file
14
memory/mem_device.cpp
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#include "memory/mem_device.h"
|
||||||
|
|
||||||
|
void Mem_device::write16(u16 addr, u16 data)
|
||||||
|
{
|
||||||
|
write8(addr, (u8)(data & 0xFF));
|
||||||
|
write8(addr+1, (u8)((data >> 8) & 0xFF));
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 Mem_device::read16(u16 addr)
|
||||||
|
{
|
||||||
|
u8 lsb = read8(addr);
|
||||||
|
u8 msb = read8(addr+1);
|
||||||
|
return ((u16)msb << 8) | (u16)lsb;
|
||||||
|
}
|
|
@ -7,6 +7,6 @@ public:
|
||||||
virtual void write8(u16 addr, u8 data) = 0;
|
virtual void write8(u16 addr, u8 data) = 0;
|
||||||
virtual u8 read8(u16 addr) = 0;
|
virtual u8 read8(u16 addr) = 0;
|
||||||
|
|
||||||
virtual void write16(u16 addr, u16 data) = 0;
|
virtual void write16(u16 addr, u16 data);
|
||||||
virtual u16 read16(u16 addr) = 0;
|
virtual u16 read16(u16 addr);
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,15 +17,3 @@ u8 RAM::read8(u16 addr) {
|
||||||
if (addr >= size) return 0xFFu;
|
if (addr >= size) return 0xFFu;
|
||||||
return memory[addr];
|
return memory[addr];
|
||||||
}
|
}
|
||||||
|
|
||||||
void RAM::write16(u16 addr, u16 data) {
|
|
||||||
if(addr >= size - 1 || readonly) return;
|
|
||||||
u16 *ptr = (u16*)&memory[addr];
|
|
||||||
*ptr = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
u16 RAM::read16(u16 addr) {
|
|
||||||
if(addr >= size - 1) return 0xFFFFu;
|
|
||||||
u16 *ptr = (u16*)&memory[addr];
|
|
||||||
return *ptr;
|
|
||||||
}
|
|
||||||
|
|
|
@ -14,7 +14,4 @@ public:
|
||||||
|
|
||||||
virtual void write8(u16 addr, u8 data);
|
virtual void write8(u16 addr, u8 data);
|
||||||
virtual u8 read8(u16 addr);
|
virtual u8 read8(u16 addr);
|
||||||
|
|
||||||
virtual void write16(u16 addr, u16 data);
|
|
||||||
virtual u16 read16(u16 addr);
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue