#include "cpu.h"
#include "memory.h"
#include "savestate.h"
namespace gambatte {
CPU::CPU()
: memory(Interrupter(SP, PC)),
cycleCounter_(0),
PC(0x100),
SP(0xFFFE),
HF1(0xF),
HF2(0xF),
ZF(0),
CF(0x100),
A(0x01),
B(0x00),
C(0x13),
D(0x00),
E(0xD8),
H(0x01),
L(0x4D),
skip(false),
tracecallback(0)
{
}
long CPU::runFor(const unsigned long cycles) {
process(cycles);
const long csb = memory.cyclesSinceBlit(cycleCounter_);
if (cycleCounter_ & 0x80000000)
cycleCounter_ = memory.resetCounters(cycleCounter_);
return csb;
}
static void calcHF(const unsigned HF1, unsigned& HF2) {
unsigned arg1 = HF1 & 0xF;
unsigned arg2 = (HF2 & 0xF) + (HF2 >> 8 & 1);
if (HF2 & 0x800) {
arg1 = arg2;
arg2 = 1;
}
if (HF2 & 0x400)
arg1 -= arg2;
else
arg1 = (arg1 + arg2) << 5;
HF2 |= arg1 & 0x200;
}
#define F() (((HF2 & 0x600) | (CF & 0x100)) >> 4 | ((ZF & 0xFF) ? 0 : 0x80))
#define FROM_F(f_in) do { \
unsigned from_f_var = f_in; \
\
ZF = ~from_f_var & 0x80; \
HF2 = from_f_var << 4 & 0x600; \
CF = from_f_var << 4 & 0x100; \
} while (0)
void CPU::setStatePtrs(SaveState &state) {
memory.setStatePtrs(state);
}
void CPU::loadState(const SaveState &state) {
memory.loadState(state);
cycleCounter_ = state.cpu.cycleCounter;
PC = state.cpu.PC & 0xFFFF;
SP = state.cpu.SP & 0xFFFF;
A = state.cpu.A & 0xFF;
B = state.cpu.B & 0xFF;
C = state.cpu.C & 0xFF;
D = state.cpu.D & 0xFF;
E = state.cpu.E & 0xFF;
FROM_F(state.cpu.F);
H = state.cpu.H & 0xFF;
L = state.cpu.L & 0xFF;
skip = state.cpu.skip;
}
#define BC() ( B << 8 | C )
#define DE() ( D << 8 | E )
#define HL() ( H << 8 | L )
#define READ(dest, addr) do { (dest) = memory.read(addr, cycleCounter); cycleCounter += 4; } while (0)
#define PC_READ(dest) do { (dest) = memory.read_excb(PC, cycleCounter, false); PC = (PC + 1) & 0xFFFF; cycleCounter += 4; } while (0)
#define PC_READ_FIRST(dest) do { (dest) = memory.read_excb(PC, cycleCounter, true); PC = (PC + 1) & 0xFFFF; cycleCounter += 4; } while (0)
#define FF_READ(dest, addr) do { (dest) = memory.ff_read(addr, cycleCounter); cycleCounter += 4; } while (0)
#define WRITE(addr, data) do { memory.write(addr, data, cycleCounter); cycleCounter += 4; } while (0)
#define FF_WRITE(addr, data) do { memory.ff_write(addr, data, cycleCounter); cycleCounter += 4; } while (0)
#define PC_MOD(data) do { PC = data; cycleCounter += 4; } while (0)
#define PUSH(r1, r2) do { \
SP = (SP - 1) & 0xFFFF; \
WRITE(SP, (r1)); \
SP = (SP - 1) & 0xFFFF; \
WRITE(SP, (r2)); \
} while (0)
#define swap_r(r) do { \
CF = HF2 = 0; \
ZF = (r); \
(r) = (ZF << 4 | ZF >> 4) & 0xFF; \
} while (0)
#define rlc_r(r) do { \
CF = (r) << 1; \
ZF = CF | CF >> 8; \
(r) = ZF & 0xFF; \
HF2 = 0; \
} while (0)
#define rl_r(r) do { \
const unsigned rl_r_var_oldcf = CF >> 8 & 1; \
CF = (r) << 1; \
ZF = CF | rl_r_var_oldcf; \
(r) = ZF & 0xFF; \
HF2 = 0; \
} while (0)
#define rrc_r(r) do { \
ZF = (r); \
CF = ZF << 8; \
(r) = (ZF | CF) >> 1 & 0xFF; \
HF2 = 0; \
} while (0)
#define rr_r(r) do { \
const unsigned rr_r_var_oldcf = CF & 0x100; \
CF = (r) << 8; \
(r) = ZF = ((r) | rr_r_var_oldcf) >> 1; \
HF2 = 0; \
} while (0)
#define sla_r(r) do { \
ZF = CF = (r) << 1; \
(r) = ZF & 0xFF; \
HF2 = 0; \
} while (0)
#define sra_r(r) do { \
CF = (r) << 8; \
ZF = (r) >> 1; \
(r) = ZF | ((r) & 0x80); \
HF2 = 0; \
} while (0)
#define srl_r(r) do { \
ZF = (r); \
CF = (r) << 8; \
ZF >>= 1; \
(r) = ZF; \
HF2 = 0; \
} while (0)
#define bitn_u8(bitmask, u8) do { \
ZF = (u8) & (bitmask); \
HF2 = 0x200; \
} while (0)
#define bit0_u8(u8) bitn_u8(1, (u8))
#define bit1_u8(u8) bitn_u8(2, (u8))
#define bit2_u8(u8) bitn_u8(4, (u8))
#define bit3_u8(u8) bitn_u8(8, (u8))
#define bit4_u8(u8) bitn_u8(0x10, (u8))
#define bit5_u8(u8) bitn_u8(0x20, (u8))
#define bit6_u8(u8) bitn_u8(0x40, (u8))
#define bit7_u8(u8) bitn_u8(0x80, (u8))
#define set0_r(r) ( (r) |= 0x1 )
#define set1_r(r) ( (r) |= 0x2 )
#define set2_r(r) ( (r) |= 0x4 )
#define set3_r(r) ( (r) |= 0x8 )
#define set4_r(r) ( (r) |= 0x10 )
#define set5_r(r) ( (r) |= 0x20 )
#define set6_r(r) ( (r) |= 0x40 )
#define set7_r(r) ( (r) |= 0x80 )
#define setn_mem_hl(n) do { \
const unsigned setn_mem_hl_var_addr = HL(); \
unsigned setn_mem_hl_var_tmp; \
\
READ(setn_mem_hl_var_tmp, setn_mem_hl_var_addr); \
setn_mem_hl_var_tmp |= 1 << (n); \
\
WRITE(setn_mem_hl_var_addr, setn_mem_hl_var_tmp); \
} while (0)
#define res0_r(r) ( (r) &= 0xFE )
#define res1_r(r) ( (r) &= 0xFD )
#define res2_r(r) ( (r) &= 0xFB )
#define res3_r(r) ( (r) &= 0xF7 )
#define res4_r(r) ( (r) &= 0xEF )
#define res5_r(r) ( (r) &= 0xDF )
#define res6_r(r) ( (r) &= 0xBF )
#define res7_r(r) ( (r) &= 0x7F )
#define resn_mem_hl(n) do { \
const unsigned resn_mem_hl_var_addr = HL(); \
unsigned resn_mem_hl_var_tmp; \
\
READ(resn_mem_hl_var_tmp, resn_mem_hl_var_addr); \
resn_mem_hl_var_tmp &= ~(1 << (n)); \
\
WRITE(resn_mem_hl_var_addr, resn_mem_hl_var_tmp); \
} while (0)
#define ld_rr_nn(r1, r2) do { \
PC_READ(r2); \
PC_READ(r1); \
} while (0)
#define push_rr(r1, r2) do { \
PUSH(r1, r2); \
cycleCounter += 4; \
} while (0)
#define pop_rr(r1, r2) do { \
READ(r2, SP); \
SP = (SP + 1) & 0xFFFF; \
READ(r1, SP); \
SP = (SP + 1) & 0xFFFF; \
} while (0)
#define add_a_u8(u8) do { \
HF1 = A; \
HF2 = u8; \
ZF = CF = A + HF2; \
A = ZF & 0xFF; \
} while (0)
#define adc_a_u8(u8) do { \
HF1 = A; \
HF2 = (CF & 0x100) | (u8); \
ZF = CF = (CF >> 8 & 1) + (u8) + A; \
A = ZF & 0xFF; \
} while (0)
#define sub_a_u8(u8) do { \
HF1 = A; \
HF2 = u8; \
ZF = CF = A - HF2; \
A = ZF & 0xFF; \
HF2 |= 0x400; \
} while (0)
#define sbc_a_u8(u8) do { \
HF1 = A; \
HF2 = 0x400 | (CF & 0x100) | (u8); \
ZF = CF = A - ((CF >> 8) & 1) - (u8); \
A = ZF & 0xFF; \
} while (0)
#define and_a_u8(u8) do { \
HF2 = 0x200; \
CF = 0; \
A &= (u8); \
ZF = A; \
} while (0)
#define or_a_u8(u8) do { \
CF = HF2 = 0; \
A |= (u8); \
ZF = A; \
} while (0)
#define xor_a_u8(u8) do { \
CF = HF2 = 0; \
A ^= (u8); \
ZF = A; \
} while (0)
#define cp_a_u8(u8) do { \
HF1 = A; \
HF2 = u8; \
ZF = CF = A - HF2; \
HF2 |= 0x400; \
} while (0)
#define inc_r(r) do { \
HF2 = (r) | 0x800; \
ZF = (r) + 1; \
(r) = ZF & 0xFF; \
} while (0)
#define dec_r(r) do { \
HF2 = (r) | 0xC00; \
ZF = (r) - 1; \
(r) = ZF & 0xFF; \
} while (0)
#define add_hl_rr(rh, rl) do { \
CF = L + (rl); \
L = CF & 0xFF; \
HF1 = H; \
HF2 = (CF & 0x100) | (rh); \
CF = H + (CF >> 8) + (rh); \
H = CF & 0xFF; \
cycleCounter += 4; \
} while (0)
#define inc_rr(rh, rl) do { \
const unsigned inc_rr_var_tmp = (rl) + 1; \
(rl) = inc_rr_var_tmp & 0xFF; \
(rh) = ((rh) + (inc_rr_var_tmp >> 8)) & 0xFF; \
cycleCounter += 4; \
} while (0)
#define dec_rr(rh, rl) do { \
const unsigned dec_rr_var_tmp = (rl) - 1; \
(rl) = dec_rr_var_tmp & 0xFF; \
(rh) = ((rh) - (dec_rr_var_tmp >> 8 & 1)) & 0xFF; \
cycleCounter += 4; \
} while (0)
#define sp_plus_n(sumout) do { \
unsigned sp_plus_n_var_n; \
PC_READ(sp_plus_n_var_n); \
sp_plus_n_var_n = (sp_plus_n_var_n ^ 0x80) - 0x80; \
\
const unsigned sp_plus_n_var_sum = SP + sp_plus_n_var_n; \
CF = SP ^ sp_plus_n_var_n ^ sp_plus_n_var_sum; \
HF2 = CF << 5 & 0x200; \
ZF = 1; \
cycleCounter += 4; \
(sumout) = sp_plus_n_var_sum & 0xFFFF; \
} while (0)
#define jp_nn() do { \
unsigned jp_nn_var_l, jp_nn_var_h; \
\
PC_READ(jp_nn_var_l); \
PC_READ(jp_nn_var_h); \
\
PC_MOD(jp_nn_var_h << 8 | jp_nn_var_l); \
} while (0)
#define jr_disp() do { \
unsigned jr_disp_var_tmp; \
\
PC_READ(jr_disp_var_tmp); \
jr_disp_var_tmp = (jr_disp_var_tmp ^ 0x80) - 0x80; \
\
PC_MOD((PC + jr_disp_var_tmp) & 0xFFFF); \
} while (0)
#define call_nn() do { \
unsigned const npc = (PC + 2) & 0xFFFF; \
jp_nn(); \
PUSH(npc >> 8, npc & 0xFF); \
} while (0)
#define rst_n(n) do { \
PUSH(PC >> 8, PC & 0xFF); \
PC_MOD(n); \
} while (0)
#define ret() do { \
unsigned ret_var_l, ret_var_h; \
\
pop_rr(ret_var_h, ret_var_l); \
\
PC_MOD(ret_var_h << 8 | ret_var_l); \
} while (0)
void CPU::process(const unsigned long cycles) {
memory.setEndtime(cycleCounter_, cycles);
memory.updateInput();
unsigned long cycleCounter = cycleCounter_;
while (memory.isActive()) {
if (memory.halted()) {
if (cycleCounter < memory.nextEventTime()) {
const unsigned long cycles = memory.nextEventTime() - cycleCounter;
cycleCounter += cycles + (-cycles & 3);
}
} else while (cycleCounter < memory.nextEventTime()) {
unsigned char opcode;
if (tracecallback) {
int result[14];
result[0] = cycleCounter;
result[1] = PC;
result[2] = SP;
result[3] = A;
result[4] = B;
result[5] = C;
result[6] = D;
result[7] = E;
result[8] = F();
result[9] = H;
result[10] = L;
result[11] = skip;
PC_READ_FIRST(opcode);
result[12] = opcode;
result[13] = memory.debugGetLY();
tracecallback((void *)result);
}
else {
PC_READ_FIRST(opcode);
}
if (skip) {
PC = (PC - 1) & 0xFFFF;
skip = false;
}
switch (opcode) {
case 0x00:
break;
case 0x01:
ld_rr_nn(B, C);
break;
case 0x02:
WRITE(BC(), A);
break;
case 0x03:
inc_rr(B, C);
break;
case 0x04:
inc_r(B);
break;
case 0x05:
dec_r(B);
break;
case 0x06:
PC_READ(B);
break;
case 0x07:
CF = A << 1;
A = (CF | CF >> 8) & 0xFF;
HF2 = 0;
ZF = 1;
break;
case 0x08:
{
unsigned l, h;
PC_READ(l);
PC_READ(h);
const unsigned addr = h << 8 | l;
WRITE(addr, SP & 0xFF);
WRITE((addr + 1) & 0xFFFF, SP >> 8);
}
break;
case 0x09:
add_hl_rr(B, C);
break;
case 0x0A:
READ(A, BC());
break;
case 0x0B:
dec_rr(B, C);
break;
case 0x0C:
inc_r(C);
break;
case 0x0D:
dec_r(C);
break;
case 0x0E:
PC_READ(C);
break;
case 0x0F:
CF = A << 8 | A;
A = CF >> 1 & 0xFF;
HF2 = 0;
ZF = 1;
break;
case 0x10:
PC = (PC + 1) & 0xFFFF;
cycleCounter = memory.stop(cycleCounter);
if (cycleCounter < memory.nextEventTime()) {
const unsigned long cycles = memory.nextEventTime() - cycleCounter;
cycleCounter += cycles + (-cycles & 3);
}
break;
case 0x11:
ld_rr_nn(D, E);
break;
case 0x12:
WRITE(DE(), A);
break;
case 0x13:
inc_rr(D, E);
break;
case 0x14:
inc_r(D);
break;
case 0x15:
dec_r(D);
break;
case 0x16:
PC_READ(D);
break;
case 0x17:
{
const unsigned oldcf = CF >> 8 & 1;
CF = A << 1;
A = (CF | oldcf) & 0xFF;
}
HF2 = 0;
ZF = 1;
break;
case 0x18:
jr_disp();
break;
case 0x19:
add_hl_rr(D, E);
break;
case 0x1A:
READ(A, DE());
break;
case 0x1B:
dec_rr(D, E);
break;
case 0x1C:
inc_r(E);
break;
case 0x1D:
dec_r(E);
break;
case 0x1E:
PC_READ(E);
break;
case 0x1F:
{
const unsigned oldcf = CF & 0x100;
CF = A << 8;
A = (A | oldcf) >> 1;
}
HF2 = 0;
ZF = 1;
break;
case 0x20:
if (ZF & 0xFF) {
jr_disp();
} else {
PC_MOD((PC + 1) & 0xFFFF);
}
break;
case 0x21:
ld_rr_nn(H, L);
break;
case 0x22:
{
unsigned addr = HL();
WRITE(addr, A);
addr = (addr + 1) & 0xFFFF;
L = addr;
H = addr >> 8;
}
break;
case 0x23:
inc_rr(H, L);
break;
case 0x24:
inc_r(H);
break;
case 0x25:
dec_r(H);
break;
case 0x26:
PC_READ(H);
break;
case 0x27:
calcHF(HF1, HF2);
{
unsigned correction = (CF & 0x100) ? 0x60 : 0x00;
if (HF2 & 0x200)
correction |= 0x06;
if (!(HF2 &= 0x400)) {
if ((A & 0x0F) > 0x09)
correction |= 0x06;
if (A > 0x99)
correction |= 0x60;
A += correction;
} else
A -= correction;
CF = correction << 2 & 0x100;
ZF = A;
A &= 0xFF;
}
break;
case 0x28:
if (ZF & 0xFF) {
PC_MOD((PC + 1) & 0xFFFF);
} else {
jr_disp();
}
break;
case 0x29:
add_hl_rr(H, L);
break;
case 0x2A:
{
unsigned addr = HL();
READ(A, addr);
addr = (addr + 1) & 0xFFFF;
L = addr;
H = addr >> 8;
}
break;
case 0x2B:
dec_rr(H, L);
break;
case 0x2C:
inc_r(L);
break;
case 0x2D:
dec_r(L);
break;
case 0x2E:
PC_READ(L);
break;
case 0x2F:
HF2 = 0x600;
A ^= 0xFF;
break;
case 0x30:
if (CF & 0x100) {
PC_MOD((PC + 1) & 0xFFFF);
} else {
jr_disp();
}
break;
case 0x31:
{
unsigned l, h;
PC_READ(l);
PC_READ(h);
SP = h << 8 | l;
}
break;
case 0x32:
{
unsigned addr = HL();
WRITE(addr, A);
addr = (addr - 1) & 0xFFFF;
L = addr;
H = addr >> 8;
}
break;
case 0x33:
SP = (SP + 1) & 0xFFFF;
cycleCounter += 4;
break;
case 0x34:
{
const unsigned addr = HL();
READ(HF2, addr);
ZF = HF2 + 1;
WRITE(addr, ZF & 0xFF);
HF2 |= 0x800;
}
break;
case 0x35:
{
const unsigned addr = HL();
READ(HF2, addr);
ZF = HF2 - 1;
WRITE(addr, ZF & 0xFF);
HF2 |= 0xC00;
}
break;
case 0x36:
{
unsigned tmp;
PC_READ(tmp);
WRITE(HL(), tmp);
}
break;
case 0x37:
CF = 0x100;
HF2 = 0;
break;
case 0x38:
if (CF & 0x100) {
jr_disp();
} else {
PC_MOD((PC + 1) & 0xFFFF);
}
break;
case 0x39:
CF = L + SP;
L = CF & 0xFF;
HF1 = H;
HF2 = ((CF ^ SP) & 0x100) | SP >> 8;
CF >>= 8;
CF += H;
H = CF & 0xFF;
cycleCounter += 4;
break;
case 0x3A:
{
unsigned addr = HL();
A = memory.read(addr, cycleCounter);
cycleCounter += 4;
addr = (addr - 1) & 0xFFFF;
L = addr;
H = addr >> 8;
}
break;
case 0x3B:
SP = (SP - 1) & 0xFFFF;
cycleCounter += 4;
break;
case 0x3C:
inc_r(A);
break;
case 0x3D:
dec_r(A);
break;
case 0x3E:
PC_READ(A);
break;
case 0x3F:
CF ^= 0x100;
HF2 = 0;
break;
case 0x40:
B = B;
break;
case 0x41:
B = C;
break;
case 0x42:
B = D;
break;
case 0x43:
B = E;
break;
case 0x44:
B = H;
break;
case 0x45:
B = L;
break;
case 0x46:
READ(B, HL());
break;
case 0x47:
B = A;
break;
case 0x48:
C = B;
break;
case 0x49:
C = C;
break;
case 0x4A:
C = D;
break;
case 0x4B:
C = E;
break;
case 0x4C:
C = H;
break;
case 0x4D:
C = L;
break;
case 0x4E:
READ(C, HL());
break;
case 0x4F:
C = A;
break;
case 0x50:
D = B;
break;
case 0x51:
D = C;
break;
case 0x52:
D = D;
break;
case 0x53:
D = E;
break;
case 0x54:
D = H;
break;
case 0x55:
D = L;
break;
case 0x56:
READ(D, HL());
break;
case 0x57:
D = A;
break;
case 0x58:
E = B;
break;
case 0x59:
E = C;
break;
case 0x5A:
E = D;
break;
case 0x5B:
E = E;
break;
case 0x5C:
E = H;
break;
case 0x5D:
E = L;
break;
case 0x5E:
READ(E, HL());
break;
case 0x5F:
E = A;
break;
case 0x60:
H = B;
break;
case 0x61:
H = C;
break;
case 0x62:
H = D;
break;
case 0x63:
H = E;
break;
case 0x64:
H = H;
break;
case 0x65:
H = L;
break;
case 0x66:
READ(H, HL());
break;
case 0x67:
H = A;
break;
case 0x68:
L = B;
break;
case 0x69:
L = C;
break;
case 0x6A:
L = D;
break;
case 0x6B:
L = E;
break;
case 0x6C:
L = H;
break;
case 0x6D:
L = L;
break;
case 0x6E:
READ(L, HL());
break;
case 0x6F:
L = A;
break;
case 0x70:
WRITE(HL(), B);
break;
case 0x71:
WRITE(HL(), C);
break;
case 0x72:
WRITE(HL(), D);
break;
case 0x73:
WRITE(HL(), E);
break;
case 0x74:
WRITE(HL(), H);
break;
case 0x75:
WRITE(HL(), L);
break;
case 0x76:
if (!memory.ime() && (memory.ff_read(0xFF0F, cycleCounter) & memory.ff_read(0xFFFF, cycleCounter) & 0x1F)) {
if (memory.isCgb())
cycleCounter += 4;
else
skip = true;
} else {
memory.halt();
if (cycleCounter < memory.nextEventTime()) {
const unsigned long cycles = memory.nextEventTime() - cycleCounter;
cycleCounter += cycles + (-cycles & 3);
}
}
break;
case 0x77:
WRITE(HL(), A);
break;
case 0x78:
A = B;
break;
case 0x79:
A = C;
break;
case 0x7A:
A = D;
break;
case 0x7B:
A = E;
break;
case 0x7C:
A = H;
break;
case 0x7D:
A = L;
break;
case 0x7E:
READ(A, HL());
break;
case 0x7F:
break;
case 0x80:
add_a_u8(B);
break;
case 0x81:
add_a_u8(C);
break;
case 0x82:
add_a_u8(D);
break;
case 0x83:
add_a_u8(E);
break;
case 0x84:
add_a_u8(H);
break;
case 0x85:
add_a_u8(L);
break;
case 0x86:
{
unsigned data;
READ(data, HL());
add_a_u8(data);
}
break;
case 0x87:
add_a_u8(A);
break;
case 0x88:
adc_a_u8(B);
break;
case 0x89:
adc_a_u8(C);
break;
case 0x8A:
adc_a_u8(D);
break;
case 0x8B:
adc_a_u8(E);
break;
case 0x8C:
adc_a_u8(H);
break;
case 0x8D:
adc_a_u8(L);
break;
case 0x8E:
{
unsigned data;
READ(data, HL());
adc_a_u8(data);
}
break;
case 0x8F:
adc_a_u8(A);
break;
case 0x90:
sub_a_u8(B);
break;
case 0x91:
sub_a_u8(C);
break;
case 0x92:
sub_a_u8(D);
break;
case 0x93:
sub_a_u8(E);
break;
case 0x94:
sub_a_u8(H);
break;
case 0x95:
sub_a_u8(L);
break;
case 0x96:
{
unsigned data;
READ(data, HL());
sub_a_u8(data);
}
break;
case 0x97:
HF2 = 0x400;
CF = ZF = A = 0;
break;
case 0x98:
sbc_a_u8(B);
break;
case 0x99:
sbc_a_u8(C);
break;
case 0x9A:
sbc_a_u8(D);
break;
case 0x9B:
sbc_a_u8(E);
break;
case 0x9C:
sbc_a_u8(H);
break;
case 0x9D:
sbc_a_u8(L);
break;
case 0x9E:
{
unsigned data;
READ(data, HL());
sbc_a_u8(data);
}
break;
case 0x9F:
sbc_a_u8(A);
break;
case 0xA0:
and_a_u8(B);
break;
case 0xA1:
and_a_u8(C);
break;
case 0xA2:
and_a_u8(D);
break;
case 0xA3:
and_a_u8(E);
break;
case 0xA4:
and_a_u8(H);
break;
case 0xA5:
and_a_u8(L);
break;
case 0xA6:
{
unsigned data;
READ(data, HL());
and_a_u8(data);
}
break;
case 0xA7:
ZF = A;
CF = 0;
HF2 = 0x200;
break;
case 0xA8:
xor_a_u8(B);
break;
case 0xA9:
xor_a_u8(C);
break;
case 0xAA:
xor_a_u8(D);
break;
case 0xAB:
xor_a_u8(E);
break;
case 0xAC:
xor_a_u8(H);
break;
case 0xAD:
xor_a_u8(L);
break;
case 0xAE:
{
unsigned data;
READ(data, HL());
xor_a_u8(data);
}
break;
case 0xAF:
CF = HF2 = ZF = A = 0;
break;
case 0xB0:
or_a_u8(B);
break;
case 0xB1:
or_a_u8(C);
break;
case 0xB2:
or_a_u8(D);
break;
case 0xB3:
or_a_u8(E);
break;
case 0xB4:
or_a_u8(H);
break;
case 0xB5:
or_a_u8(L);
break;
case 0xB6:
{
unsigned data;
READ(data, HL());
or_a_u8(data);
}
break;
case 0xB7:
ZF = A;
HF2 = CF = 0;
break;
case 0xB8:
cp_a_u8(B);
break;
case 0xB9:
cp_a_u8(C);
break;
case 0xBA:
cp_a_u8(D);
break;
case 0xBB:
cp_a_u8(E);
break;
case 0xBC:
cp_a_u8(H);
break;
case 0xBD:
cp_a_u8(L);
break;
case 0xBE:
{
unsigned data;
READ(data, HL());
cp_a_u8(data);
}
break;
case 0xBF:
CF = ZF = 0;
HF2 = 0x400;
break;
case 0xC0:
cycleCounter += 4;
if (ZF & 0xFF) {
ret();
}
break;
case 0xC1:
pop_rr(B, C);
break;
case 0xC2:
if (ZF & 0xFF) {
jp_nn();
} else {
PC_MOD((PC + 2) & 0xFFFF);
cycleCounter += 4;
}
break;
case 0xC3:
jp_nn();
break;
case 0xC4:
if (ZF & 0xFF) {
call_nn();
} else {
PC_MOD((PC + 2) & 0xFFFF);
cycleCounter += 4;
}
break;
case 0xC5:
push_rr(B, C);
break;
case 0xC6:
{
unsigned data;
PC_READ(data);
add_a_u8(data);
}
break;
case 0xC7:
rst_n(0x00);
break;
case 0xC8:
cycleCounter += 4;
if (!(ZF & 0xFF)) {
ret();
}
break;
case 0xC9:
ret();
break;
case 0xCA:
if (ZF & 0xFF) {
PC_MOD((PC + 2) & 0xFFFF);
cycleCounter += 4;
} else {
jp_nn();
}
break;
case 0xCB:
PC_READ(opcode);
switch (opcode) {
case 0x00:
rlc_r(B);
break;
case 0x01:
rlc_r(C);
break;
case 0x02:
rlc_r(D);
break;
case 0x03:
rlc_r(E);
break;
case 0x04:
rlc_r(H);
break;
case 0x05:
rlc_r(L);
break;
case 0x06:
{
const unsigned addr = HL();
READ(CF, addr);
CF <<= 1;
ZF = CF | (CF >> 8);
WRITE(addr, ZF & 0xFF);
HF2 = 0;
}
break;
case 0x07:
rlc_r(A);
break;
case 0x08:
rrc_r(B);
break;
case 0x09:
rrc_r(C);
break;
case 0x0A:
rrc_r(D);
break;
case 0x0B:
rrc_r(E);
break;
case 0x0C:
rrc_r(H);
break;
case 0x0D:
rrc_r(L);
break;
case 0x0E:
{
const unsigned addr = HL();
READ(ZF, addr);
CF = ZF << 8;
WRITE(addr, (ZF | CF) >> 1 & 0xFF);
HF2 = 0;
}
break;
case 0x0F:
rrc_r(A);
break;
case 0x10:
rl_r(B);
break;
case 0x11:
rl_r(C);
break;
case 0x12:
rl_r(D);
break;
case 0x13:
rl_r(E);
break;
case 0x14:
rl_r(H);
break;
case 0x15:
rl_r(L);
break;
case 0x16:
{
const unsigned addr = HL();
const unsigned oldcf = CF >> 8 & 1;
READ(CF, addr);
CF <<= 1;
ZF = CF | oldcf;
WRITE(addr, ZF & 0xFF);
HF2 = 0;
}
break;
case 0x17:
rl_r(A);
break;
case 0x18:
rr_r(B);
break;
case 0x19:
rr_r(C);
break;
case 0x1A:
rr_r(D);
break;
case 0x1B:
rr_r(E);
break;
case 0x1C:
rr_r(H);
break;
case 0x1D:
rr_r(L);
break;
case 0x1E:
{
const unsigned addr = HL();
READ(ZF, addr);
const unsigned oldcf = CF & 0x100;
CF = ZF << 8;
ZF = (ZF | oldcf) >> 1;
WRITE(addr, ZF);
HF2 = 0;
}
break;
case 0x1F:
rr_r(A);
break;
case 0x20:
sla_r(B);
break;
case 0x21:
sla_r(C);
break;
case 0x22:
sla_r(D);
break;
case 0x23:
sla_r(E);
break;
case 0x24:
sla_r(H);
break;
case 0x25:
sla_r(L);
break;
case 0x26:
{
const unsigned addr = HL();
READ(CF, addr);
CF <<= 1;
ZF = CF;
WRITE(addr, ZF & 0xFF);
HF2 = 0;
}
break;
case 0x27:
sla_r(A);
break;
case 0x28:
sra_r(B);
break;
case 0x29:
sra_r(C);
break;
case 0x2A:
sra_r(D);
break;
case 0x2B:
sra_r(E);
break;
case 0x2C:
sra_r(H);
break;
case 0x2D:
sra_r(L);
break;
case 0x2E:
{
const unsigned addr = HL();
READ(CF, addr);
ZF = CF >> 1;
WRITE(addr, ZF | (CF & 0x80));
CF <<= 8;
HF2 = 0;
}
break;
case 0x2F:
sra_r(A);
break;
case 0x30:
swap_r(B);
break;
case 0x31:
swap_r(C);
break;
case 0x32:
swap_r(D);
break;
case 0x33:
swap_r(E);
break;
case 0x34:
swap_r(H);
break;
case 0x35:
swap_r(L);
break;
case 0x36:
{
const unsigned addr = HL();
READ(ZF, addr);
WRITE(addr, (ZF << 4 | ZF >> 4) & 0xFF);
CF = HF2 = 0;
}
break;
case 0x37:
swap_r(A);
break;
case 0x38:
srl_r(B);
break;
case 0x39:
srl_r(C);
break;
case 0x3A:
srl_r(D);
break;
case 0x3B:
srl_r(E);
break;
case 0x3C:
srl_r(H);
break;
case 0x3D:
srl_r(L);
break;
case 0x3E:
{
const unsigned addr = HL();
READ(CF, addr);
ZF = CF >> 1;
WRITE(addr, ZF);
CF <<= 8;
HF2 = 0;
}
break;
case 0x3F:
srl_r(A);
break;
case 0x40:
bit0_u8(B);
break;
case 0x41:
bit0_u8(C);
break;
case 0x42:
bit0_u8(D);
break;
case 0x43:
bit0_u8(E);
break;
case 0x44:
bit0_u8(H);
break;
case 0x45:
bit0_u8(L);
break;
case 0x46:
{
unsigned data;
READ(data, HL());
bit0_u8(data);
}
break;
case 0x47:
bit0_u8(A);
break;
case 0x48:
bit1_u8(B);
break;
case 0x49:
bit1_u8(C);
break;
case 0x4A:
bit1_u8(D);
break;
case 0x4B:
bit1_u8(E);
break;
case 0x4C:
bit1_u8(H);
break;
case 0x4D:
bit1_u8(L);
break;
case 0x4E:
{
unsigned data;
READ(data, HL());
bit1_u8(data);
}
break;
case 0x4F:
bit1_u8(A);
break;
case 0x50:
bit2_u8(B);
break;
case 0x51:
bit2_u8(C);
break;
case 0x52:
bit2_u8(D);
break;
case 0x53:
bit2_u8(E);
break;
case 0x54:
bit2_u8(H);
break;
case 0x55:
bit2_u8(L);
break;
case 0x56:
{
unsigned data;
READ(data, HL());
bit2_u8(data);
}
break;
case 0x57:
bit2_u8(A);
break;
case 0x58:
bit3_u8(B);
break;
case 0x59:
bit3_u8(C);
break;
case 0x5A:
bit3_u8(D);
break;
case 0x5B:
bit3_u8(E);
break;
case 0x5C:
bit3_u8(H);
break;
case 0x5D:
bit3_u8(L);
break;
case 0x5E:
{
unsigned data;
READ(data, HL());
bit3_u8(data);
}
break;
case 0x5F:
bit3_u8(A);
break;
case 0x60:
bit4_u8(B);
break;
case 0x61:
bit4_u8(C);
break;
case 0x62:
bit4_u8(D);
break;
case 0x63:
bit4_u8(E);
break;
case 0x64:
bit4_u8(H);
break;
case 0x65:
bit4_u8(L);
break;
case 0x66:
{
unsigned data;
READ(data, HL());
bit4_u8(data);
}
break;
case 0x67:
bit4_u8(A);
break;
case 0x68:
bit5_u8(B);
break;
case 0x69:
bit5_u8(C);
break;
case 0x6A:
bit5_u8(D);
break;
case 0x6B:
bit5_u8(E);
break;
case 0x6C:
bit5_u8(H);
break;
case 0x6D:
bit5_u8(L);
break;
case 0x6E:
{
unsigned data;
READ(data, HL());
bit5_u8(data);
}
break;
case 0x6F:
bit5_u8(A);
break;
case 0x70:
bit6_u8(B);
break;
case 0x71:
bit6_u8(C);
break;
case 0x72:
bit6_u8(D);
break;
case 0x73:
bit6_u8(E);
break;
case 0x74:
bit6_u8(H);
break;
case 0x75:
bit6_u8(L);
break;
case 0x76:
{
unsigned data;
READ(data, HL());
bit6_u8(data);
}
break;
case 0x77:
bit6_u8(A);
break;
case 0x78:
bit7_u8(B);
break;
case 0x79:
bit7_u8(C);
break;
case 0x7A:
bit7_u8(D);
break;
case 0x7B:
bit7_u8(E);
break;
case 0x7C:
bit7_u8(H);
break;
case 0x7D:
bit7_u8(L);
break;
case 0x7E:
{
unsigned data;
READ(data, HL());
bit7_u8(data);
}
break;
case 0x7F:
bit7_u8(A);
break;
case 0x80:
res0_r(B);
break;
case 0x81:
res0_r(C);
break;
case 0x82:
res0_r(D);
break;
case 0x83:
res0_r(E);
break;
case 0x84:
res0_r(H);
break;
case 0x85:
res0_r(L);
break;
case 0x86:
resn_mem_hl(0);
break;
case 0x87:
res0_r(A);
break;
case 0x88:
res1_r(B);
break;
case 0x89:
res1_r(C);
break;
case 0x8A:
res1_r(D);
break;
case 0x8B:
res1_r(E);
break;
case 0x8C:
res1_r(H);
break;
case 0x8D:
res1_r(L);
break;
case 0x8E:
resn_mem_hl(1);
break;
case 0x8F:
res1_r(A);
break;
case 0x90:
res2_r(B);
break;
case 0x91:
res2_r(C);
break;
case 0x92:
res2_r(D);
break;
case 0x93:
res2_r(E);
break;
case 0x94:
res2_r(H);
break;
case 0x95:
res2_r(L);
break;
case 0x96:
resn_mem_hl(2);
break;
case 0x97:
res2_r(A);
break;
case 0x98:
res3_r(B);
break;
case 0x99:
res3_r(C);
break;
case 0x9A:
res3_r(D);
break;
case 0x9B:
res3_r(E);
break;
case 0x9C:
res3_r(H);
break;
case 0x9D:
res3_r(L);
break;
case 0x9E:
resn_mem_hl(3);
break;
case 0x9F:
res3_r(A);
break;
case 0xA0:
res4_r(B);
break;
case 0xA1:
res4_r(C);
break;
case 0xA2:
res4_r(D);
break;
case 0xA3:
res4_r(E);
break;
case 0xA4:
res4_r(H);
break;
case 0xA5:
res4_r(L);
break;
case 0xA6:
resn_mem_hl(4);
break;
case 0xA7:
res4_r(A);
break;
case 0xA8:
res5_r(B);
break;
case 0xA9:
res5_r(C);
break;
case 0xAA:
res5_r(D);
break;
case 0xAB:
res5_r(E);
break;
case 0xAC:
res5_r(H);
break;
case 0xAD:
res5_r(L);
break;
case 0xAE:
resn_mem_hl(5);
break;
case 0xAF:
res5_r(A);
break;
case 0xB0:
res6_r(B);
break;
case 0xB1:
res6_r(C);
break;
case 0xB2:
res6_r(D);
break;
case 0xB3:
res6_r(E);
break;
case 0xB4:
res6_r(H);
break;
case 0xB5:
res6_r(L);
break;
case 0xB6:
resn_mem_hl(6);
break;
case 0xB7:
res6_r(A);
break;
case 0xB8:
res7_r(B);
break;
case 0xB9:
res7_r(C);
break;
case 0xBA:
res7_r(D);
break;
case 0xBB:
res7_r(E);
break;
case 0xBC:
res7_r(H);
break;
case 0xBD:
res7_r(L);
break;
case 0xBE:
resn_mem_hl(7);
break;
case 0xBF:
res7_r(A);
break;
case 0xC0:
set0_r(B);
break;
case 0xC1:
set0_r(C);
break;
case 0xC2:
set0_r(D);
break;
case 0xC3:
set0_r(E);
break;
case 0xC4:
set0_r(H);
break;
case 0xC5:
set0_r(L);
break;
case 0xC6:
setn_mem_hl(0);
break;
case 0xC7:
set0_r(A);
break;
case 0xC8:
set1_r(B);
break;
case 0xC9:
set1_r(C);
break;
case 0xCA:
set1_r(D);
break;
case 0xCB:
set1_r(E);
break;
case 0xCC:
set1_r(H);
break;
case 0xCD:
set1_r(L);
break;
case 0xCE:
setn_mem_hl(1);
break;
case 0xCF:
set1_r(A);
break;
case 0xD0:
set2_r(B);
break;
case 0xD1:
set2_r(C);
break;
case 0xD2:
set2_r(D);
break;
case 0xD3:
set2_r(E);
break;
case 0xD4:
set2_r(H);
break;
case 0xD5:
set2_r(L);
break;
case 0xD6:
setn_mem_hl(2);
break;
case 0xD7:
set2_r(A);
break;
case 0xD8:
set3_r(B);
break;
case 0xD9:
set3_r(C);
break;
case 0xDA:
set3_r(D);
break;
case 0xDB:
set3_r(E);
break;
case 0xDC:
set3_r(H);
break;
case 0xDD:
set3_r(L);
break;
case 0xDE:
setn_mem_hl(3);
break;
case 0xDF:
set3_r(A);
break;
case 0xE0:
set4_r(B);
break;
case 0xE1:
set4_r(C);
break;
case 0xE2:
set4_r(D);
break;
case 0xE3:
set4_r(E);
break;
case 0xE4:
set4_r(H);
break;
case 0xE5:
set4_r(L);
break;
case 0xE6:
setn_mem_hl(4);
break;
case 0xE7:
set4_r(A);
break;
case 0xE8:
set5_r(B);
break;
case 0xE9:
set5_r(C);
break;
case 0xEA:
set5_r(D);
break;
case 0xEB:
set5_r(E);
break;
case 0xEC:
set5_r(H);
break;
case 0xED:
set5_r(L);
break;
case 0xEE:
setn_mem_hl(5);
break;
case 0xEF:
set5_r(A);
break;
case 0xF0:
set6_r(B);
break;
case 0xF1:
set6_r(C);
break;
case 0xF2:
set6_r(D);
break;
case 0xF3:
set6_r(E);
break;
case 0xF4:
set6_r(H);
break;
case 0xF5:
set6_r(L);
break;
case 0xF6:
setn_mem_hl(6);
break;
case 0xF7:
set6_r(A);
break;
case 0xF8:
set7_r(B);
break;
case 0xF9:
set7_r(C);
break;
case 0xFA:
set7_r(D);
break;
case 0xFB:
set7_r(E);
break;
case 0xFC:
set7_r(H);
break;
case 0xFD:
set7_r(L);
break;
case 0xFE:
setn_mem_hl(7);
break;
case 0xFF:
set7_r(A);
break;
}
break;
case 0xCC:
if (ZF & 0xFF) {
PC_MOD((PC + 2) & 0xFFFF);
cycleCounter += 4;
} else {
call_nn();
}
break;
case 0xCD:
call_nn();
break;
case 0xCE:
{
unsigned data;
PC_READ(data);
adc_a_u8(data);
}
break;
case 0xCF:
rst_n(0x08);
break;
case 0xD0:
cycleCounter += 4;
if (!(CF & 0x100)) {
ret();
}
break;
case 0xD1:
pop_rr(D, E);
break;
case 0xD2:
if (CF & 0x100) {
PC_MOD((PC + 2) & 0xFFFF);
cycleCounter += 4;
} else {
jp_nn();
}
break;
case 0xD3:
skip = true;
memory.di();
break;
case 0xD4:
if (CF & 0x100) {
PC_MOD((PC + 2) & 0xFFFF);
cycleCounter += 4;
} else {
call_nn();
}
break;
case 0xD5:
push_rr(D, E);
break;
case 0xD6:
{
unsigned data;
PC_READ(data);
sub_a_u8(data);
}
break;
case 0xD7:
rst_n(0x10);
break;
case 0xD8:
cycleCounter += 4;
if (CF & 0x100) {
ret();
}
break;
case 0xD9:
{
unsigned l, h;
pop_rr(h, l);
memory.ei(cycleCounter);
PC_MOD(h << 8 | l);
}
break;
case 0xDA:
if (CF & 0x100) {
jp_nn();
} else {
PC_MOD((PC + 2) & 0xFFFF);
cycleCounter += 4;
}
break;
case 0xDB:
skip = true;
memory.di();
break;
case 0xDC:
if (CF & 0x100) {
call_nn();
} else {
PC_MOD((PC + 2) & 0xFFFF);
cycleCounter += 4;
}
break;
case 0xDD:
skip = true;
memory.di();
break;
case 0xDE:
{
unsigned data;
PC_READ(data);
sbc_a_u8(data);
}
break;
case 0xDF:
rst_n(0x18);
break;
case 0xE0:
{
unsigned tmp;
PC_READ(tmp);
FF_WRITE(0xFF00 | tmp, A);
}
break;
case 0xE1:
pop_rr(H, L);
break;
case 0xE2:
FF_WRITE(0xFF00 | C, A);
break;
case 0xE3:
skip = true;
memory.di();
break;
case 0xE4:
skip = true;
memory.di();
break;
case 0xE5:
push_rr(H, L);
break;
case 0xE6:
{
unsigned data;
PC_READ(data);
and_a_u8(data);
}
break;
case 0xE7:
rst_n(0x20);
break;
case 0xE8:
sp_plus_n(SP);
cycleCounter += 4;
break;
case 0xE9:
PC = HL();
break;
case 0xEA:
{
unsigned l, h;
PC_READ(l);
PC_READ(h);
WRITE(h << 8 | l, A);
}
break;
case 0xEB:
skip = true;
memory.di();
break;
case 0xEC:
skip = true;
memory.di();
break;
case 0xED:
skip = true;
memory.di();
break;
case 0xEE:
{
unsigned data;
PC_READ(data);
xor_a_u8(data);
}
break;
case 0xEF:
rst_n(0x28);
break;
case 0xF0:
{
unsigned tmp;
PC_READ(tmp);
FF_READ(A, 0xFF00 | tmp);
}
break;
case 0xF1:
{
unsigned F;
pop_rr(A, F);
FROM_F(F);
}
break;
case 0xF2:
FF_READ(A, 0xFF00 | C);
break;
case 0xF3:
memory.di();
break;
case 0xF4:
skip = true;
memory.di();
break;
case 0xF5:
calcHF(HF1, HF2);
{
unsigned F = F();
push_rr(A, F);
}
break;
case 0xF6:
{
unsigned data;
PC_READ(data);
or_a_u8(data);
}
break;
case 0xF7:
rst_n(0x30);
break;
case 0xF8:
{
unsigned sum;
sp_plus_n(sum);
L = sum & 0xFF;
H = sum >> 8;
}
break;
case 0xF9:
SP = HL();
cycleCounter += 4;
break;
case 0xFA:
{
unsigned l, h;
PC_READ(l);
PC_READ(h);
READ(A, h << 8 | l);
}
break;
case 0xFB:
memory.ei(cycleCounter);
break;
case 0xFC:
skip = true;
memory.di();
break;
case 0xFD:
skip = true;
memory.di();
break;
case 0xFE:
{
unsigned data;
PC_READ(data);
cp_a_u8(data);
}
break;
case 0xFF:
rst_n(0x38);
break;
}
}
cycleCounter = memory.event(cycleCounter);
}
cycleCounter_ = cycleCounter;
}
void CPU::GetRegs(int *dest)
{
dest[0] = PC;
dest[1] = SP;
dest[2] = A;
dest[3] = B;
dest[4] = C;
dest[5] = D;
dest[6] = E;
dest[7] = F();
dest[8] = H;
dest[9] = L;
}
SYNCFUNC(CPU)
{
SSS(memory);
NSS(cycleCounter_);
NSS(PC);
NSS(SP);
NSS(HF1);
NSS(HF2);
NSS(ZF);
NSS(CF);
NSS(A);
NSS(B);
NSS(C);
NSS(D);
NSS(E);
NSS(H);
NSS(L);
NSS(skip);
}
}