IME(1),
HALT(0),
cycle_count(0),
+ cycles_until_video_update(0),
+ cycles_until_next_instruction(0),
breakpoints(),
last_breakpoint_id(0)
{
void GameBoy::reset()
{
logger.info("GameBoy reset");
+ IME = 1;
+ HALT = 0;
+ cycle_count = 0;
+ cycles_until_video_update = 0;
+ cycles_until_next_instruction = 0;
+
regs.PC = 0x0100;
regs.AF = 0x01B0;
regs.BC = 0x0013;
regs.HL = 0x014D;
regs.SP = 0xFFFE;
+ for (int i=0; i<0xFFFF; i++)
+ {
+ memory.write(i, 0);
+ }
+
memory.write(0xFF05, 0x00); // TIMA
memory.write(0xFF06, 0x00); // TMA
memory.write(0xFF07, 0x00); // TAC
GameBoy::run_status GameBoy::run_cycle()
{
- int opcode;
- opcode = memory.read(regs.PC++);
-
- switch(opcode)
- {
- // LD n, nn
- for_each_register(0x3E, 0x06, 0x0E, 0x16, 0x1E, 0x26, 0x2E, LD_reg_nn)
+ cycle_count += CYCLE_STEP;
- // LD r1,r2
- for_each_register(0x7F, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, LD_A_reg)
- for_each_register(0x47, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, LD_B_reg)
- for_each_register(0x4F, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, LD_C_reg)
- for_each_register(0x57, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, LD_D_reg)
- for_each_register(0x5F, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, LD_E_reg)
- for_each_register(0x67, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, LD_H_reg)
- for_each_register(0x6F, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, LD_L_reg)
-
- // LD reg, (HL)
- for_each_register(0x7E, 0x46, 0x4E, 0x56, 0x5E, 0x66, 0x6E, LD_reg__HL_)
-
- // LD (HL), reg
- for_each_register(0x77, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, LD__HL__reg)
-
- case 0x36: // LD (HL), n
- memory.write(regs.HL, memory.read(regs.PC++));
- break;
-
- // LD A, mem
- case 0x0A: // LD A, (BC)
- regs.A = memory.read(regs.BC);
- break;
- case 0x1A: // LD A, (DE)
- regs.A = memory.read(regs.DE);
- break;
- case 0xFA: // LD A, (nn)
- regs.A = memory.read(memory.read16(regs.PC));
- regs.PC+=2;
- break;
+ if (cycles_until_next_instruction > 0)
+ {
+ if (cycles_until_video_update <= 0)
+ cycles_until_video_update = video.update();
- // LD mem, A
- case 0x02: // LD (BC), A
- memory.write(regs.BC, regs.A);
- break;
- case 0x12: // LD (DE), A
- memory.write(regs.DE, regs.A);
- break;
- case 0xEA: // LD (nn), A
- memory.write(memory.read16(regs.PC), regs.A);
- regs.PC+=2;
- break;
-
- // LD A, (C)
- case 0xF2:
- regs.A = memory.read(0xFF00 + regs.C);
- break;
- // LD (C), A
- case 0xE2:
- memory.write(0xFF00 + regs.C, regs.A);
- break;
-
- // LD A, (HLD); LD A, (HL-); LDD A,(HL);
- case 0x3A:
- regs.A = memory.read(regs.HL);
- --regs.HL;
- break;
- // LD (HLD), A; LD (HL-), A; LDD (HL), A;
- case 0x32:
- memory.write(regs.HL, regs.A);
- --regs.HL;
- break;
- // LD A, (HLI); LD A, (HL+); LDI A, (HL);
- case 0x2A:
- regs.A = memory.read(regs.HL);
- ++regs.HL;
- break;
- // LD (HLI), A; LD (HL+), A; LDI (HL), A;
- case 0x22:
- memory.write(regs.HL, regs.A);
- ++regs.HL;
- break;
-
- // LDH (n), A
- case 0xE0: {
- memory.high[memory.read(regs.PC++)] = regs.A;
- break;
- }
- // LDH A, (n)
- case 0xF0:
- regs.A = memory.high[memory.read(regs.PC++)];
- break;
-
- // LD n, nn
- case 0x01: // LD BC, nn
- regs.BC = memory.read16(regs.PC);
- regs.PC +=2;
- break;
- case 0x11: // LD DE, nn
- regs.DE = memory.read16(regs.PC);
- regs.PC +=2;
- break;
- case 0x21: // LD HL, nn
- regs.HL = memory.read16(regs.PC);
- regs.PC +=2;
- break;
- case 0x31: // LD SP, nn
- regs.SP = memory.read16(regs.PC);
- regs.PC +=2;
- break;
+ cycles_until_video_update -= CYCLE_STEP;
+ cycles_until_next_instruction -= CYCLE_STEP;
- // LD SP, HL
- case 0xF9:
- regs.SP = regs.HL;
- break;
-
- // LD HL, SP+n
- // LDHL SP, n
- case 0xF8: {
- s8 offset = memory.read(regs.PC++);
- int res = regs.SP + offset;
-
- // TODO: Verificar si los flags van asi
- set_flag_if (res > 0xFFFF, CARRY_FLAG);
-
- // TODO: hacer lo apropiado con el half-carry flag
- reset_flag(ADD_SUB_FLAG);
- reset_flag(ZERO_FLAG);
+ if (cycles_until_next_instruction > 0) return WAIT;
+ else return NORMAL;
+ }
- regs.HL = static_cast<u16>(res & 0xFFFF);
- break;
+ // Check for interrupts before opcode fetching
+ u8 IE=memory.high[GBMemory::I_IE];
+ //logger.trace("IME=", int(IME), " IE=", int(IE));
+ if (IME && IE)
+ {
+ u8 IF = memory.high[GBMemory::I_IF];
+ //logger.trace("Dispatching interrupts: IE=", int(IE), " IF=", int(IF));
+ if (IF)
+ {
+ if ((IF & IRQ_VBLANK) && (IE & IRQ_VBLANK))
+ {
+ IME = 0;
+ IF &= (~IRQ_VBLANK);
+ do_call(0x40);
+ logger.trace("VBLANK IRQ");
}
-
- // LD (nn), SP
- case 0x08: {
- int addr = memory.read16(regs.PC);
- regs.PC += 2;
- memory.write(addr, regs.SP);
- break;
+ else if ((IF & IRQ_LCD_STAT) && (IE & IRQ_LCD_STAT))
+ {
+ IME = 0;
+ IF &= (~IRQ_LCD_STAT);
+ do_call(0x48);
+ logger.trace("LCD STAT IRQ");
+ }
+ else if ((IF & IRQ_TIMER) && (IE & IRQ_TIMER))
+ {
+ IME = 0;
+ IF &= (~IRQ_TIMER);
+ do_call(0x50);
+ logger.trace("TIMER IRQ");
+ }
+ else if ((IF & IRQ_SERIAL) && (IE & IRQ_SERIAL))
+ {
+ IME = 0;
+ IF &= (~IRQ_SERIAL);
+ do_call(0x58);
+ logger.trace("SERIAL IRQ");
+ }
+ else if ((IF & IRQ_JOYPAD) && (IE & IRQ_JOYPAD))
+ {
+ IME = 0;
+ IF &= (~IRQ_JOYPAD);
+ do_call(0x60);
+ logger.trace("JOYPAD IRQ");
}
+ }
+ memory.high[GBMemory::I_IF] = IF;
+ }
- // PUSH nn
- PUSH(0xF5, A, flags)
- PUSH(0xC5, B, C)
- PUSH(0xD5, D, E)
- PUSH(0xE5, H, L)
+ /*
+ for(BreakpointMap::iterator i=breakpoints.begin();
+ i != breakpoints.end();
+ i++)
+ {
+ if (i->second.addr == regs.PC && i->second.enabled)
+ return BREAKPOINT;
+ }
+ */
+
+ int opcode;
+ opcode = memory.read(regs.PC++);
- // POP nn
- POP(0xF1, A, flags)
- POP(0xC1, B, C)
- POP(0xD1, D, E)
- POP(0xE1, H, L)
+ switch(opcode & 0x80)
+ {
+ case 0x00:
+ switch(opcode)
+ {
+ // LD n, nn
+ for_each_register(0x3E, 0x06, 0x0E, 0x16, 0x1E, 0x26, 0x2E, LD_reg_nn)
+
+ // LD r1,r2
+ for_each_register(0x7F, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, LD_A_reg)
+ for_each_register(0x47, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, LD_B_reg)
+ for_each_register(0x4F, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, LD_C_reg)
+ for_each_register(0x57, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, LD_D_reg)
+ for_each_register(0x5F, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, LD_E_reg)
+ for_each_register(0x67, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, LD_H_reg)
+ for_each_register(0x6F, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, LD_L_reg)
+
+ // LD reg, (HL)
+ for_each_register(0x7E, 0x46, 0x4E, 0x56, 0x5E, 0x66, 0x6E, LD_reg__HL_)
- // 8-bit ALU
- // ADD A,reg
- for_each_register(0x87, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, ADD_A_reg)
-
- case 0x86: {// ADD A, (HL)
- int res = regs.A + memory.read(regs.HL);
- int half_res = (regs.A & 0x0F) + (memory.read(regs.HL) & 0x0F);
- regs.A = static_cast<u8>(res);
+ // LD (HL), reg
+ for_each_register(0x77, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, LD__HL__reg)
- reset_flag(ADD_SUB_FLAG);
- set_flag_if (res > 0xFF, CARRY_FLAG);
- set_flag_if (regs.A == 0, ZERO_FLAG);
- set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG);
- break;
- }
- case 0xC6: {//ADD A, #
- int inm = memory.read(regs.PC++);
- int res = regs.A + inm;
- int half_res = (regs.A & 0x0F) + (inm & 0x0F);
- regs.A = static_cast<u8>(res);
+ case 0x36: // LD (HL), n
+ memory.write(regs.HL, memory.read(regs.PC++));
+ cycles_until_next_instruction = 12;
+ break;
- reset_flag(ADD_SUB_FLAG);
- set_flag_if (res > 0xFF, CARRY_FLAG);
- set_flag_if (regs.A == 0, ZERO_FLAG);
- set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG);
- break;
- }
-
- // ADC A, n
- for_each_register(0x8F, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, ADC_A_reg)
-
- case 0x8E: {// ADC A, (HL)
- int carry = (check_flag(CARRY_FLAG)? 1 : 0);
- int res = regs.A + memory.read(regs.HL) + carry;
- int half_res = (regs.A & 0x0F) + (memory.read(regs.HL) & 0x0F) + carry;
- regs.A = static_cast<u8>(res);
+ // LD A, mem
+ case 0x0A: // LD A, (BC)
+ regs.A = memory.read(regs.BC);
+ cycles_until_next_instruction = 8;
+ break;
+ case 0x1A: // LD A, (DE)
+ regs.A = memory.read(regs.DE);
+ cycles_until_next_instruction = 8;
+ break;
- reset_flag(ADD_SUB_FLAG);
- set_flag_if (res > 0xFF, CARRY_FLAG);
- set_flag_if (regs.A == 0, ZERO_FLAG);
- set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG);
- break;
- }
- case 0xCE: {//ADC A, #
- int carry = (check_flag(CARRY_FLAG)? 1 : 0);
- int inm = memory.read(regs.PC++);
- int res = regs.A + inm + carry;
- int half_res = (regs.A & 0x0F) + (inm & 0x0F) + carry;
- regs.A = static_cast<u8>(res);
+ // LD mem, A
+ case 0x02: // LD (BC), A
+ memory.write(regs.BC, regs.A);
+ cycles_until_next_instruction = 8;
+ break;
+ case 0x12: // LD (DE), A
+ memory.write(regs.DE, regs.A);
+ cycles_until_next_instruction = 8;
+ break;
+
+ // LD A, (HLD); LD A, (HL-); LDD A,(HL);
+ case 0x3A:
+ regs.A = memory.read(regs.HL);
+ --regs.HL;
+ cycles_until_next_instruction = 8;
+ break;
+ // LD (HLD), A; LD (HL-), A; LDD (HL), A;
+ case 0x32:
+ memory.write(regs.HL, regs.A);
+ --regs.HL;
+ cycles_until_next_instruction = 8;
+ break;
+ // LD A, (HLI); LD A, (HL+); LDI A, (HL);
+ case 0x2A:
+ regs.A = memory.read(regs.HL);
+ ++regs.HL;
+ cycles_until_next_instruction = 8;
+ break;
+ // LD (HLI), A; LD (HL+), A; LDI (HL), A;
+ case 0x22:
+ memory.write(regs.HL, regs.A);
+ ++regs.HL;
+ cycles_until_next_instruction = 8;
+ break;
+
+ // LD n, nn
+ case 0x01: // LD BC, nn
+ regs.BC = memory.read16(regs.PC);
+ regs.PC +=2;
+ cycles_until_next_instruction = 12;
+ break;
+ case 0x11: // LD DE, nn
+ regs.DE = memory.read16(regs.PC);
+ regs.PC +=2;
+ cycles_until_next_instruction = 12;
+ break;
+ case 0x21: // LD HL, nn
+ regs.HL = memory.read16(regs.PC);
+ regs.PC +=2;
+ cycles_until_next_instruction = 12;
+ break;
+ case 0x31: // LD SP, nn
+ regs.SP = memory.read16(regs.PC);
+ regs.PC +=2;
+ cycles_until_next_instruction = 12;
+ break;
- reset_flag(ADD_SUB_FLAG);
- set_flag_if (res > 0xFF, CARRY_FLAG);
- set_flag_if (regs.A == 0, ZERO_FLAG);
- set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG);
- break;
- }
- // SUB n
- for_each_register(0x97, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, SUB_reg)
+ // LD (nn), SP
+ case 0x08: {
+ int addr = memory.read16(regs.PC);
+ regs.PC += 2;
+ memory.write(addr, regs.SP);
+ cycles_until_next_instruction = 20;
+ break;
+ }
- case 0x96: {//SUB (HL)
- int res = regs.A - memory.read(regs.HL);
- int half_res = (regs.A & 0x0F) - (memory.read(regs.HL) & 0x0F);
- regs.A = static_cast<u8>(res);
+ // INC n
+ for_each_register(0x3C, 0x04, 0x0C, 0x14, 0x1C, 0x24, 0x2C, INC_reg)
+
+ case 0x34: {//INC (HL)
+ int half_res = (memory.read(regs.HL) & 0x0F) + 1;
+ memory.write(regs.HL, memory.read(regs.HL) - 1);
+ reset_flag(ADD_SUB_FLAG);
+ set_flag_if (memory.read(regs.HL) == 0, ZERO_FLAG);
+ set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG);
+ cycles_until_next_instruction = 12;
+ break;
+ }
+
+ // DEC n
+ for_each_register(0x3D, 0x05, 0x0D, 0x15, 0x1D, 0x25, 0x2D, DEC_reg)
+
+ case 0x35: {//DEC (HL)
+ int half_res = (memory.read(regs.HL) & 0x0F) - 1;
+ memory.write(regs.HL, memory.read(regs.HL) - 1);
+ set_flag(ADD_SUB_FLAG);
+ set_flag_if (memory.read(regs.HL) == 0, ZERO_FLAG);
+ set_flag_if (half_res < 0, HALF_CARRY_FLAG);
+ cycles_until_next_instruction = 12;
+ break;
+ }
- set_flag(ADD_SUB_FLAG);
- set_flag_if (res < 0, CARRY_FLAG);
- set_flag_if (res == 0, ZERO_FLAG);
- set_flag_if (half_res < 0, HALF_CARRY_FLAG);
- break;
- }
-
- case 0xD6: {//SUB #
- int inm = memory.read(regs.PC++);
- int res = regs.A - inm;
- int half_res = (regs.A & 0x0F) - (inm & 0x0F);
- regs.A = static_cast<u8>(res);
-
- set_flag(ADD_SUB_FLAG);
- set_flag_if (res < 0, CARRY_FLAG);
- set_flag_if (res == 0, ZERO_FLAG);
- set_flag_if (half_res < 0, HALF_CARRY_FLAG);
- break;
- }
+ // 16-bit ALU
+ // ADD HL, n
+ for_each_register16(0x09, 0x19, 0x29, 0x39, ADD_HL_reg16)
- // SBC n
- for_each_register(0x9F, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, SBC_reg)
-
- case 0x9E: {//SBC (HL)
- int carry = (check_flag(CARRY_FLAG)? 1 : 0);
- int res = regs.A - memory.read(regs.HL) - carry;
- int half_res = (regs.A & 0x0F) - (memory.read(regs.HL) & 0x0F) - carry;
- regs.A = static_cast<u8>(res);
-
- set_flag(ADD_SUB_FLAG);
- set_flag_if (res < 0, CARRY_FLAG);
- set_flag_if (res == 0, ZERO_FLAG);
- set_flag_if (half_res < 0, HALF_CARRY_FLAG);
- break;
- }
+ // INC nn
+ for_each_register16(0x03, 0x13, 0x23, 0x33, INC_reg16)
- // There is no SBC inm
+ // DEC nn
+ for_each_register16(0x0B, 0x1B, 0x2B, 0x3B, DEC_reg16)
- // AND n
- for_each_register(0xA7, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, AND_reg)
-
- case 0xA6: //AND (HL)
- regs.A &= memory.read(regs.HL);
- if (regs.A == 0) set_flag(ZERO_FLAG);
- reset_flag(ADD_SUB_FLAG);
- set_flag(HALF_CARRY_FLAG);
- reset_flag(CARRY_FLAG);
- break;
- case 0xE6: //AND inm
- regs.A &= memory.read(regs.PC++);
- if (regs.A == 0) set_flag(ZERO_FLAG);
- reset_flag(ADD_SUB_FLAG);
- set_flag(HALF_CARRY_FLAG);
- reset_flag(CARRY_FLAG);
- break;
+ // DAA http://www.worldofspectrum.org/faq/reference/z80reference.htm#DAA
+ case 0x27: {
+ u8 corr_factor = 0;
+ if (regs.A > 0x99 || check_flag(CARRY_FLAG)) {
+ corr_factor = 0x60;
+ set_flag(CARRY_FLAG);
+ } else {
+ reset_flag(CARRY_FLAG);
+ }
- // OR n
- for_each_register(0xB7, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, OR_reg)
-
- case 0xB6: //OR (HL)
- regs.A |= memory.read(regs.HL);
- if (regs.A == 0) set_flag(ZERO_FLAG);
- reset_flag(ADD_SUB_FLAG);
- reset_flag(HALF_CARRY_FLAG);
- reset_flag(CARRY_FLAG);
- break;
+ if (regs.A & 0x0F > 9 || check_flag(HALF_CARRY_FLAG)) {
+ corr_factor |= 0x06;
+ }
- case 0xF6: //OR inm
- regs.A |= memory.read(regs.PC++);
- if (regs.A == 0) set_flag(ZERO_FLAG);
- reset_flag(ADD_SUB_FLAG);
- reset_flag(HALF_CARRY_FLAG);
- reset_flag(CARRY_FLAG);
- break;
+ if (!check_flag(ADD_SUB_FLAG)) {
+ regs.A += corr_factor;
+ } else {
+ regs.A -= corr_factor;
+ }
- // XOR n
- for_each_register(0xAF, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, XOR_reg)
-
- case 0xAE: //XOR (HL)
- regs.A ^= memory.read(regs.HL);
- if (regs.A == 0) set_flag(ZERO_FLAG);
- reset_flag(ADD_SUB_FLAG);
- reset_flag(HALF_CARRY_FLAG);
- reset_flag(CARRY_FLAG);
- break;
+ set_flag_if(regs.A==0, ZERO_FLAG);
+ reset_flag(HALF_CARRY_FLAG); // GBCPUman.pdf contradicts previous reference :P
+ cycles_until_next_instruction = 4;
+ break;
+ }
- case 0xEE: //XOR inm
- regs.A ^= memory.read(regs.PC++);
- if (regs.A == 0) set_flag(ZERO_FLAG);
- reset_flag(ADD_SUB_FLAG);
- reset_flag(HALF_CARRY_FLAG);
- reset_flag(CARRY_FLAG);
- break;
-
- // CP n
- for_each_register(0xBF, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, CP_reg)
+ // CPL
+ case 0x2F:
+ regs.A = ~regs.A;
+ set_flag(HALF_CARRY_FLAG);
+ set_flag(ADD_SUB_FLAG);
+ cycles_until_next_instruction = 4;
+ break;
+
+ // CCF
+ case 0x3F:
+ if (check_flag(CARRY_FLAG))
+ reset_flag(CARRY_FLAG);
+ else
+ set_flag(CARRY_FLAG);
- case 0xBE: {//CP (HL)
- int res = regs.A - memory.read(regs.HL);
- int half_res = (regs.A & 0x0F) - (memory.read(regs.HL) & 0x0F);
+ reset_flag(HALF_CARRY_FLAG);
+ reset_flag(ADD_SUB_FLAG);
+ cycles_until_next_instruction = 4;
+ break;
- set_flag(ADD_SUB_FLAG);
- set_flag_if (res < 0, CARRY_FLAG);
- set_flag_if (res == 0, ZERO_FLAG);
- set_flag_if (half_res < 0, HALF_CARRY_FLAG);
- break;
+ // SCF
+ case 0x37:
+ set_flag(CARRY_FLAG);
+ reset_flag(HALF_CARRY_FLAG);
+ reset_flag(ADD_SUB_FLAG);
+ cycles_until_next_instruction = 4;
+ break;
+
+ // NOP
+ case 0x00:
+ cycles_until_next_instruction = 4;
+ break;
+
+ // HALT
+ case 0x76:
+ HALT = true;
+ cycles_until_next_instruction = 4;
+ break;
+
+ // STOP
+ case 0x10: {
+ int sub_opcode = memory.read(regs.PC++);
+ if (sub_opcode == 0x00) {
+ HALT = true;
+ } else {
+ logger.critical("Unknown sub-opcode after 0x10");
+ }
+ cycles_until_next_instruction = 4;
+ break;
}
-
- case 0xFE: {//CP #
- int inm = memory.read(regs.PC++);
- int res = regs.A - inm;
- int half_res = (regs.A & 0x0F) - (inm & 0x0F);
-
- set_flag(ADD_SUB_FLAG);
- set_flag_if (res < 0, CARRY_FLAG);
- set_flag_if (res == 0, ZERO_FLAG);
- set_flag_if (half_res < 0, HALF_CARRY_FLAG);
- break;
+
+ // Rotates and shifts
+ // RLCA
+ case 0x07: {
+ u8 bit7 = regs.A >>7;
+ regs.A = (regs.A << 1) | bit7;
+ set_flag_if(regs.A == 0, ZERO_FLAG);
+ reset_flag(ADD_SUB_FLAG);
+ reset_flag(HALF_CARRY_FLAG);
+ // TODO: Check which of GBCPUman.pdf or
+ // worldofspectrum z80 reference is correct
+ //
+ //set_flag_if(bit7, CARRY_FLAG);
+ cycles_until_next_instruction = 4;
+ break;
}
- // INC n
- for_each_register(0x3C, 0x04, 0x0C, 0x14, 0x1C, 0x24, 0x2C, INC_reg)
-
- case 0x34: {//INC (HL)
- int half_res = (memory.read(regs.HL) & 0x0F) + 1;
- memory.write(regs.HL, memory.read(regs.HL) - 1);
- reset_flag(ADD_SUB_FLAG);
- set_flag_if (memory.read(regs.HL) == 0, ZERO_FLAG);
- set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG);
- break;
- }
+ // RLA (through carry)
+ case 0x17: {
+ u8 bit7 = regs.A >> 7;
+ regs.A = (regs.A << 1) | check_flag(CARRY_FLAG);
+ set_flag_if(bit7, CARRY_FLAG);
+ set_flag_if(regs.A == 0, ZERO_FLAG);
+ reset_flag(ADD_SUB_FLAG);
+ reset_flag(HALF_CARRY_FLAG);
+ cycles_until_next_instruction = 4;
+ break;
+ }
+
+ // RRCA
+ case 0x0F: {
+ u8 bit0 = regs.A & 1;
+ regs.A = (regs.A >> 1) | (bit0 << 7);
+ set_flag_if(regs.A == 0, ZERO_FLAG);
+ reset_flag(ADD_SUB_FLAG);
+ reset_flag(HALF_CARRY_FLAG);
+ // TODO: Check which of GBCPUman.pdf or
+ // worldofspectrum z80 reference is correct
+ //
+ //set_flag_if(bit0, CARRY_FLAG);
+ cycles_until_next_instruction = 4;
+ break;
+ }
- // DEC n
- for_each_register(0x3D, 0x05, 0x0D, 0x15, 0x1D, 0x25, 0x2D, DEC_reg)
-
- case 0x35: {//DEC (HL)
- int half_res = (memory.read(regs.HL) & 0x0F) - 1;
- memory.write(regs.HL, memory.read(regs.HL) - 1);
- set_flag(ADD_SUB_FLAG);
- set_flag_if (memory.read(regs.HL) == 0, ZERO_FLAG);
- set_flag_if (half_res < 0, HALF_CARRY_FLAG);
- break;
+ // RRA (through carry)
+ case 0x1F: {
+ u8 bit0 = regs.A & 1;
+ regs.A = (regs.A >> 1) | (check_flag(CARRY_FLAG) << 7);
+ set_flag_if(bit0, CARRY_FLAG);
+ set_flag_if(regs.A == 0, ZERO_FLAG);
+ reset_flag(ADD_SUB_FLAG);
+ reset_flag(HALF_CARRY_FLAG);
+ cycles_until_next_instruction = 4;
+ break;
}
- // 16-bit ALU
- // ADD HL, n
- for_each_register16(0x09, 0x19, 0x29, 0x39, ADD_HL_reg16)
+
+ // JR n
+ case 0x18:
+ // -1 because PC is now pointing past the opcode
+ regs.PC += static_cast<s8>(memory.read(regs.PC++));
+ cycles_until_next_instruction = 8;
+ break;
+
+ // JR cc, n
+ case 0x20: { // JR NZ, n
+ s8 offset = static_cast<s8>(memory.read(regs.PC++));
+ if (!check_flag(ZERO_FLAG))
+ regs.PC += offset;
+ cycles_until_next_instruction = 8;
+ break;
+ }
- // ADD SP, #
- case 0xE8: {
- // FIXME: No se que hacer con el half carry, en 4 o en 11?
- int n = static_cast<s8>(memory.read(regs.PC++));
- int res = regs.SP + n;
- regs.SP = static_cast<u8>(res);
- reset_flag(ZERO_FLAG);
- reset_flag(ADD_SUB_FLAG);
- set_flag_if(res > 0xFFFF, CARRY_FLAG);
- break;
- }
+ case 0x28: { // JR Z, n
+ s8 offset = static_cast<s8>(memory.read(regs.PC++));
+ if (check_flag(ZERO_FLAG))
+ regs.PC += offset;
+ cycles_until_next_instruction = 8;
+ break;
+ }
- // INC nn
- for_each_register16(0x03, 0x13, 0x23, 0x33, INC_reg16)
+ case 0x30: { // JR NC, n
+ s8 offset = static_cast<s8>(memory.read(regs.PC++));
+ if (!check_flag(CARRY_FLAG))
+ regs.PC += offset;
+ cycles_until_next_instruction = 8;
+ break;
+ }
- // DEC nn
- for_each_register16(0x0B, 0x1B, 0x2B, 0x3B, DEC_reg16)
+ case 0x38: { // JR C, n
+ s8 offset = static_cast<s8>(memory.read(regs.PC++));
+ if (check_flag(CARRY_FLAG))
+ regs.PC += offset;
+ cycles_until_next_instruction = 8;
+ break;
+ }
- // Miscellaneous instructions
- case 0xCB: {
- int sub_opcode = memory.read(regs.PC++);
- switch(sub_opcode)
- {
- // SWAP n
- for_each_register(0x37, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, SWAP_reg)
- // SWAP (HL)
- case 0x36: {
- u8 tmp = memory.read(regs.HL);
- tmp = ((tmp & 0x0F) << 4) | ((tmp & 0xF0)>>4);
- memory.write(regs.HL, tmp);
- set_flag_if(tmp==0, ZERO_FLAG);
- reset_flag(CARRY_FLAG);
- reset_flag(HALF_CARRY_FLAG);
- reset_flag(ADD_SUB_FLAG);
- break;
- }
+ default:
+ std::ostringstream errmsg;
+ errmsg << "Unknown opcode 0x";
+ errmsg << std::hex << std::setw(2) << std::setfill('0') << opcode;
+ errmsg << " at 0x" << std::hex << std::setw(4) << regs.PC-1;
+ errmsg << " (cycle count = " << std::dec << cycle_count << ")";
+ logger.critical(errmsg.str());
+ break;
+
+ } // end switch
+ break;
+ case 0x80:
+ switch(opcode)
+ {
+ case 0xFA: // LD A, (nn)
+ regs.A = memory.read(memory.read16(regs.PC));
+ regs.PC+=2;
+ cycles_until_next_instruction = 16;
+ break;
+ case 0xEA: // LD (nn), A
+ memory.write(memory.read16(regs.PC), regs.A);
+ regs.PC+=2;
+ cycles_until_next_instruction = 16;
+ break;
+
+ // LD A, (C)
+ case 0xF2:
+ regs.A = memory.read(0xFF00 + regs.C);
+ cycles_until_next_instruction = 8;
+ break;
+ // LD (C), A
+ case 0xE2:
+ memory.write(0xFF00 + regs.C, regs.A);
+ cycles_until_next_instruction = 8;
+ break;
+ // LDH (n), A
+ case 0xE0: {
+ memory.high[memory.read(regs.PC++)] = regs.A;
+ cycles_until_next_instruction = 12;
+ break;
+ }
+ // LDH A, (n)
+ case 0xF0:
+ regs.A = memory.high[memory.read(regs.PC++)];
+ cycles_until_next_instruction = 12;
+ break;
+
+ // LD SP, HL
+ case 0xF9:
+ regs.SP = regs.HL;
+ cycles_until_next_instruction = 8;
+ break;
+
+ // LD HL, SP+n
+ // LDHL SP, n
+ case 0xF8: {
+ s8 offset = memory.read(regs.PC++);
+ int res = regs.SP + offset;
+
+ // TODO: Verificar si los flags van asi
+ set_flag_if (res > 0xFFFF, CARRY_FLAG);
- // RLC n
- for_each_register(0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, RLC_reg)
+ // TODO: hacer lo apropiado con el half-carry flag
+ reset_flag(ADD_SUB_FLAG);
+ reset_flag(ZERO_FLAG);
- // RLC (HL)
- case 0x06: {
- u8 value = memory.read(regs.HL);
- u8 bit7 = value >> 7;
- value = (value << 1) | bit7;
- memory.write(regs.HL, value);
- set_flag_if(value == 0, ZERO_FLAG);
- reset_flag(ADD_SUB_FLAG);
- reset_flag(HALF_CARRY_FLAG);
- break;
+ regs.HL = static_cast<u16>(res & 0xFFFF);
+ cycles_until_next_instruction = 12;
+ break;
}
- // RL n (through carry)
- for_each_register(0x17, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, RL_reg)
-
- // RL (HL) (through carry)
- case 0x16: {
- u8 value = memory.read(regs.HL);
- u8 bit7 = value >> 7;
- value = (value << 1) | check_flag(CARRY_FLAG);
- memory.write(regs.HL, value);
- set_flag_if(bit7, CARRY_FLAG);
- set_flag_if(value == 0, ZERO_FLAG);
- reset_flag(ADD_SUB_FLAG);
- reset_flag(HALF_CARRY_FLAG);
- break;
+ // PUSH nn
+ PUSH(0xF5, A, flags)
+ PUSH(0xC5, B, C)
+ PUSH(0xD5, D, E)
+ PUSH(0xE5, H, L)
+
+ // POP nn
+ POP(0xF1, A, flags)
+ POP(0xC1, B, C)
+ POP(0xD1, D, E)
+ POP(0xE1, H, L)
+
+ // 8-bit ALU
+ // ADD A,reg
+ for_each_register(0x87, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, ADD_A_reg)
+
+ case 0x86: {// ADD A, (HL)
+ int res = regs.A + memory.read(regs.HL);
+ int half_res = (regs.A & 0x0F) + (memory.read(regs.HL) & 0x0F);
+ regs.A = static_cast<u8>(res);
+
+ reset_flag(ADD_SUB_FLAG);
+ set_flag_if (res > 0xFF, CARRY_FLAG);
+ set_flag_if (regs.A == 0, ZERO_FLAG);
+ set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG);
+ cycles_until_next_instruction = 8;
+ break;
}
-
- // RRC n
- for_each_register(0x0F, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, RRC_reg)
-
- // RRC (HL)
- case 0x0E: {
- u8 value = memory.read(regs.HL);
- u8 bit0 = value & 1;
- value = (value >> 1) | (bit0 << 7);
- memory.write(regs.HL, value);
- set_flag_if(value == 0, ZERO_FLAG);
- reset_flag(ADD_SUB_FLAG);
- reset_flag(HALF_CARRY_FLAG);
- break;
+ case 0xC6: {//ADD A, #
+ int inm = memory.read(regs.PC++);
+ int res = regs.A + inm;
+ int half_res = (regs.A & 0x0F) + (inm & 0x0F);
+ regs.A = static_cast<u8>(res);
+
+ reset_flag(ADD_SUB_FLAG);
+ set_flag_if (res > 0xFF, CARRY_FLAG);
+ set_flag_if (regs.A == 0, ZERO_FLAG);
+ set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG);
+ cycles_until_next_instruction = 8;
+ break;
}
- // RR n (through carry)
- for_each_register(0x1F, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, RR_reg)
+ // ADC A, n
+ for_each_register(0x8F, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, ADC_A_reg)
- // RR (HL) (through carry)
- case 0x1E: {
- u8 value = memory.read(regs.HL);
- u8 bit0 = value & 1;
- value = (value >> 1) | (check_flag(CARRY_FLAG) << 7);
- memory.write(regs.HL, value);
- set_flag_if(bit0, CARRY_FLAG);
- set_flag_if(value == 0, ZERO_FLAG);
- reset_flag(ADD_SUB_FLAG);
- reset_flag(HALF_CARRY_FLAG);
- break;
- }
+ case 0x8E: {// ADC A, (HL)
+ int carry = (check_flag(CARRY_FLAG)? 1 : 0);
+ int res = regs.A + memory.read(regs.HL) + carry;
+ int half_res = (regs.A & 0x0F) + (memory.read(regs.HL) & 0x0F) + carry;
+ regs.A = static_cast<u8>(res);
- // SLA n
- for_each_register(0x27, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, SLA_reg)
-
- // SLA (HL)
- case 0x26: {
- u8 value = memory.read(regs.HL);
- bool carry = (value & 0x80) != 0;
- value <<= 1;
- memory.write(regs.HL, value);
- set_flag_if(value == 0, ZERO_FLAG);
- reset_flag(ADD_SUB_FLAG);
- reset_flag(HALF_CARRY_FLAG);
- set_flag_if(carry, CARRY_FLAG);
- break;
+ reset_flag(ADD_SUB_FLAG);
+ set_flag_if (res > 0xFF, CARRY_FLAG);
+ set_flag_if (regs.A == 0, ZERO_FLAG);
+ set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG);
+ cycles_until_next_instruction = 8;
+ break;
}
+ case 0xCE: {//ADC A, #
+ int carry = (check_flag(CARRY_FLAG)? 1 : 0);
+ int inm = memory.read(regs.PC++);
+ int res = regs.A + inm + carry;
+ int half_res = (regs.A & 0x0F) + (inm & 0x0F) + carry;
+ regs.A = static_cast<u8>(res);
- // SRA n
- for_each_register(0x2F, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, SRA_reg)
-
- // SRA (HL)
- case 0x2E: {
- u8 value = memory.read(regs.HL);
- bool carry = (value & 0x01) != 0;
- u8 MSB = value & 0x80;
- value = (value >> 1) | MSB;
- memory.write(regs.HL, value);
- set_flag_if(value == 0, ZERO_FLAG);
- reset_flag(ADD_SUB_FLAG);
- reset_flag(HALF_CARRY_FLAG);
- set_flag_if(carry, CARRY_FLAG);
- break;
+ reset_flag(ADD_SUB_FLAG);
+ set_flag_if (res > 0xFF, CARRY_FLAG);
+ set_flag_if (regs.A == 0, ZERO_FLAG);
+ set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG);
+ cycles_until_next_instruction = 8;
+ break;
}
- // SRL n
- for_each_register(0x3F, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, SRL_reg)
+ // SUB n
+ for_each_register(0x97, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, SUB_reg)
- // SRL (HL)
- case 0x3E: {
- u8 value = memory.read(regs.HL);
- bool carry = (value & 0x01) != 0;
- value >>= 1;
- memory.write(regs.HL, value);
- set_flag_if(value == 0, ZERO_FLAG);
- reset_flag(ADD_SUB_FLAG);
- reset_flag(HALF_CARRY_FLAG);
- set_flag_if(carry, CARRY_FLAG);
- break;
- }
+ case 0x96: {//SUB (HL)
+ int res = regs.A - memory.read(regs.HL);
+ int half_res = (regs.A & 0x0F) - (memory.read(regs.HL) & 0x0F);
+ regs.A = static_cast<u8>(res);
- default: {
- int bit_op = sub_opcode >> 6;
- int reg = sub_opcode & 7;
- int b = (sub_opcode >> 3) & 7;
- bool res;
- switch (bit_op)
- {
- case 1: // BIT
- switch(reg)
- {
- case 0:
- res = check_bit(regs.B, b);
- set_flag_if(res == false, ZERO_FLAG);
- reset_flag(ADD_SUB_FLAG);
- set_flag(HALF_CARRY_FLAG);
- break;
- case 1:
- res = check_bit(regs.C, b);
- set_flag_if(res == false, ZERO_FLAG);
- reset_flag(ADD_SUB_FLAG);
- set_flag(HALF_CARRY_FLAG);
- break;
- case 2:
- res = check_bit(regs.D, b);
- set_flag_if(res == false, ZERO_FLAG);
- reset_flag(ADD_SUB_FLAG);
- set_flag(HALF_CARRY_FLAG);
- break;
- case 3:
- res = check_bit(regs.E, b);
- set_flag_if(res == false, ZERO_FLAG);
- reset_flag(ADD_SUB_FLAG);
- set_flag(HALF_CARRY_FLAG);
- break;
- case 4:
- res = check_bit(regs.H, b);
- set_flag_if(res == false, ZERO_FLAG);
- reset_flag(ADD_SUB_FLAG);
- set_flag(HALF_CARRY_FLAG);
- break;
- case 5:
- res = check_bit(regs.L, b);
- set_flag_if(res == false, ZERO_FLAG);
- reset_flag(ADD_SUB_FLAG);
- set_flag(HALF_CARRY_FLAG);
- break;
- case 6:
- res = check_bit(memory.read(regs.HL), b);
- set_flag_if(res == false, ZERO_FLAG);
- reset_flag(ADD_SUB_FLAG);
- set_flag(HALF_CARRY_FLAG);
- break;
- case 7:
- res = check_bit(regs.A, b);
- set_flag_if(res == false, ZERO_FLAG);
- reset_flag(ADD_SUB_FLAG);
- set_flag(HALF_CARRY_FLAG);
- break;
- }
- break;
-
- case 2: // RES
- switch(reg)
- {
- case 0:
- regs.B = reset_bit(regs.B, b);
- break;
- case 1:
- regs.C = reset_bit(regs.C, b);
- break;
- case 2:
- regs.D = reset_bit(regs.D, b);
- break;
- case 3:
- regs.E = reset_bit(regs.E, b);
- break;
- case 4:
- regs.H = reset_bit(regs.H, b);
- break;
- case 5:
- regs.L = reset_bit(regs.L, b);
- break;
- case 6:
- memory.write(regs.HL, reset_bit(memory.read(regs.HL), b));
- break;
- case 7:
- regs.A = reset_bit(regs.A, b);
- break;
- }
- break;
-
- case 3: // SET
- switch(reg)
- {
- case 0:
- regs.B = set_bit(regs.B, b);
- break;
- case 1:
- regs.C = set_bit(regs.C, b);
- break;
- case 2:
- regs.D = set_bit(regs.D, b);
- break;
- case 3:
- regs.E = set_bit(regs.E, b);
- break;
- case 4:
- regs.H = set_bit(regs.H, b);
- break;
- case 5:
- regs.L = set_bit(regs.L, b);
- break;
- case 6:
- memory.write(regs.HL, set_bit(memory.read(regs.HL), b));
- break;
- case 7:
- regs.A = set_bit(regs.A, b);
- break;
- }
- break;
-
- default:
- logger.critical("Unknown sub-opcode after 0xCB");
- break;
- }
+ set_flag(ADD_SUB_FLAG);
+ set_flag_if (res < 0, CARRY_FLAG);
+ set_flag_if (res == 0, ZERO_FLAG);
+ set_flag_if (half_res < 0, HALF_CARRY_FLAG);
+ cycles_until_next_instruction = 8;
+ break;
+ }
+
+ case 0xD6: {//SUB #
+ int inm = memory.read(regs.PC++);
+ int res = regs.A - inm;
+ int half_res = (regs.A & 0x0F) - (inm & 0x0F);
+ regs.A = static_cast<u8>(res);
+
+ set_flag(ADD_SUB_FLAG);
+ set_flag_if (res < 0, CARRY_FLAG);
+ set_flag_if (res == 0, ZERO_FLAG);
+ set_flag_if (half_res < 0, HALF_CARRY_FLAG);
+ cycles_until_next_instruction = 8;
+ break;
}
-
- }
- break;
- }
-
- // DAA http://www.worldofspectrum.org/faq/reference/z80reference.htm#DAA
- case 0x27: {
- u8 corr_factor = 0;
- if (regs.A > 0x99 || check_flag(CARRY_FLAG)) {
- corr_factor = 0x60;
- set_flag(CARRY_FLAG);
- } else {
- reset_flag(CARRY_FLAG);
- }
-
- if (regs.A & 0x0F > 9 || check_flag(HALF_CARRY_FLAG)) {
- corr_factor |= 0x06;
- }
- if (!check_flag(ADD_SUB_FLAG)) {
- regs.A += corr_factor;
- } else {
- regs.A -= corr_factor;
- }
+ // SBC n
+ for_each_register(0x9F, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, SBC_reg)
+
+ case 0x9E: {//SBC (HL)
+ int carry = (check_flag(CARRY_FLAG)? 1 : 0);
+ int res = regs.A - memory.read(regs.HL) - carry;
+ int half_res = (regs.A & 0x0F) - (memory.read(regs.HL) & 0x0F) - carry;
+ regs.A = static_cast<u8>(res);
+
+ set_flag(ADD_SUB_FLAG);
+ set_flag_if (res < 0, CARRY_FLAG);
+ set_flag_if (res == 0, ZERO_FLAG);
+ set_flag_if (half_res < 0, HALF_CARRY_FLAG);
+ cycles_until_next_instruction = 8;
+ break;
+ }
- set_flag_if(regs.A==0, ZERO_FLAG);
- reset_flag(HALF_CARRY_FLAG); // GBCPUman.pdf contradicts previous reference :P
- break;
- }
+ // There is no SBC inm
- // CPL
- case 0x2F:
- regs.A = ~regs.A;
- set_flag(HALF_CARRY_FLAG);
- set_flag(ADD_SUB_FLAG);
- break;
+ // AND n
+ for_each_register(0xA7, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, AND_reg)
- // CCF
- case 0x3F:
- if (check_flag(CARRY_FLAG))
+ case 0xA6: //AND (HL)
+ regs.A &= memory.read(regs.HL);
+ if (regs.A == 0) set_flag(ZERO_FLAG);
+ reset_flag(ADD_SUB_FLAG);
+ set_flag(HALF_CARRY_FLAG);
reset_flag(CARRY_FLAG);
- else
- set_flag(CARRY_FLAG);
+ cycles_until_next_instruction = 8;
+ break;
+
+ case 0xE6: //AND inm
+ regs.A &= memory.read(regs.PC++);
+ if (regs.A == 0) set_flag(ZERO_FLAG);
+ reset_flag(ADD_SUB_FLAG);
+ set_flag(HALF_CARRY_FLAG);
+ reset_flag(CARRY_FLAG);
+ cycles_until_next_instruction = 8;
+ break;
- reset_flag(HALF_CARRY_FLAG);
- reset_flag(ADD_SUB_FLAG);
- break;
+ // OR n
+ for_each_register(0xB7, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, OR_reg)
- // SCF
- case 0x37:
- set_flag(CARRY_FLAG);
- reset_flag(HALF_CARRY_FLAG);
- reset_flag(ADD_SUB_FLAG);
- break;
+ case 0xB6: //OR (HL)
+ regs.A |= memory.read(regs.HL);
+ if (regs.A == 0) set_flag(ZERO_FLAG);
+ reset_flag(ADD_SUB_FLAG);
+ reset_flag(HALF_CARRY_FLAG);
+ reset_flag(CARRY_FLAG);
+ cycles_until_next_instruction = 8;
+ break;
+
+ case 0xF6: //OR inm
+ regs.A |= memory.read(regs.PC++);
+ if (regs.A == 0) set_flag(ZERO_FLAG);
+ reset_flag(ADD_SUB_FLAG);
+ reset_flag(HALF_CARRY_FLAG);
+ reset_flag(CARRY_FLAG);
+ cycles_until_next_instruction = 8;
+ break;
- // NOP
- case 0x00:
- break;
+ // XOR n
+ for_each_register(0xAF, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, XOR_reg)
- // HALT
- case 0x76:
- HALT = true;
- break;
+ case 0xAE: //XOR (HL)
+ regs.A ^= memory.read(regs.HL);
+ if (regs.A == 0) set_flag(ZERO_FLAG);
+ reset_flag(ADD_SUB_FLAG);
+ reset_flag(HALF_CARRY_FLAG);
+ reset_flag(CARRY_FLAG);
+ cycles_until_next_instruction = 8;
+ break;
+
+ case 0xEE: //XOR inm
+ regs.A ^= memory.read(regs.PC++);
+ if (regs.A == 0) set_flag(ZERO_FLAG);
+ reset_flag(ADD_SUB_FLAG);
+ reset_flag(HALF_CARRY_FLAG);
+ reset_flag(CARRY_FLAG);
+ cycles_until_next_instruction = 8;
+ break;
+
+ // CP n
+ for_each_register(0xBF, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, CP_reg)
+
+ case 0xBE: {//CP (HL)
+ int res = regs.A - memory.read(regs.HL);
+ int half_res = (regs.A & 0x0F) - (memory.read(regs.HL) & 0x0F);
+
+ set_flag(ADD_SUB_FLAG);
+ set_flag_if (res < 0, CARRY_FLAG);
+ set_flag_if (res == 0, ZERO_FLAG);
+ set_flag_if (half_res < 0, HALF_CARRY_FLAG);
+ cycles_until_next_instruction = 8;
+ break;
+ }
+
+ case 0xFE: {//CP #
+ int inm = memory.read(regs.PC++);
+ int res = regs.A - inm;
+ int half_res = (regs.A & 0x0F) - (inm & 0x0F);
+
+ set_flag(ADD_SUB_FLAG);
+ set_flag_if (res < 0, CARRY_FLAG);
+ set_flag_if (res == 0, ZERO_FLAG);
+ set_flag_if (half_res < 0, HALF_CARRY_FLAG);
+ cycles_until_next_instruction = 8;
+ break;
+ }
- // STOP
- case 0x10: {
- int sub_opcode = memory.read(regs.PC++);
- if (sub_opcode == 0x00) {
- HALT = true;
- } else {
- logger.critical("Unknown sub-opcode after 0x10");
+ // ADD SP, #
+ case 0xE8: {
+ // FIXME: No se que hacer con el half carry, en 4 o en 11?
+ int n = static_cast<s8>(memory.read(regs.PC++));
+ int res = regs.SP + n;
+ regs.SP = static_cast<u8>(res);
+ reset_flag(ZERO_FLAG);
+ reset_flag(ADD_SUB_FLAG);
+ set_flag_if(res > 0xFFFF, CARRY_FLAG);
+ cycles_until_next_instruction = 16;
+ break;
}
- break;
- }
-
- // DI
- case 0xF3:
- IME = 0;
- break;
-
- // EI
- case 0xFB:
- IME = 1;
- break;
-
- // Rotates and shifts
- // RLCA
- case 0x07: {
- u8 bit7 = regs.A >>7;
- regs.A = (regs.A << 1) | bit7;
- set_flag_if(regs.A == 0, ZERO_FLAG);
- reset_flag(ADD_SUB_FLAG);
- reset_flag(HALF_CARRY_FLAG);
- // TODO: Check which of GBCPUman.pdf or
- // worldofspectrum z80 reference is correct
- //
- //set_flag_if(bit7, CARRY_FLAG);
- break;
- }
- // RLA (through carry)
- case 0x17: {
- u8 bit7 = regs.A >> 7;
- regs.A = (regs.A << 1) | check_flag(CARRY_FLAG);
- set_flag_if(bit7, CARRY_FLAG);
- set_flag_if(regs.A == 0, ZERO_FLAG);
- reset_flag(ADD_SUB_FLAG);
- reset_flag(HALF_CARRY_FLAG);
- break;
- }
-
- // RRCA
- case 0x0F: {
- u8 bit0 = regs.A & 1;
- regs.A = (regs.A >> 1) | (bit0 << 7);
- set_flag_if(regs.A == 0, ZERO_FLAG);
- reset_flag(ADD_SUB_FLAG);
- reset_flag(HALF_CARRY_FLAG);
- // TODO: Check which of GBCPUman.pdf or
- // worldofspectrum z80 reference is correct
- //
- //set_flag_if(bit0, CARRY_FLAG);
- break;
- }
-
- // RRA (through carry)
- case 0x1F: {
- u8 bit0 = regs.A & 1;
- regs.A = (regs.A >> 1) | (check_flag(CARRY_FLAG) << 7);
- set_flag_if(bit0, CARRY_FLAG);
- set_flag_if(regs.A == 0, ZERO_FLAG);
- reset_flag(ADD_SUB_FLAG);
- reset_flag(HALF_CARRY_FLAG);
- break;
- }
-
-
- // Jumps
- // JP nn
- case 0xC3:
- regs.PC = memory.read16(regs.PC);
- break;
-
- // JP cc, nn
- case 0xC2: { // JP NZ, nn
- u16 dst = memory.read16(regs.PC);
- if (!check_flag(ZERO_FLAG))
- regs.PC = dst;
- else
- regs.PC += 2; // if !cc, skip 2 dst bytes
- break;
- }
+ // Miscellaneous instructions
+ case 0xCB: {
+ int sub_opcode = memory.read(regs.PC++);
+ switch(sub_opcode)
+ {
+ // SWAP n
+ for_each_register(0x37, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, SWAP_reg)
+
+ // SWAP (HL)
+ case 0x36: {
+ u8 tmp = memory.read(regs.HL);
+ tmp = ((tmp & 0x0F) << 4) | ((tmp & 0xF0)>>4);
+ memory.write(regs.HL, tmp);
+
+ set_flag_if(tmp==0, ZERO_FLAG);
+ reset_flag(CARRY_FLAG);
+ reset_flag(HALF_CARRY_FLAG);
+ reset_flag(ADD_SUB_FLAG);
+ cycles_until_next_instruction = 16;
+ break;
+ }
- case 0xCA: { // JP Z, nn
- u16 dst = memory.read16(regs.PC);
- if (check_flag(ZERO_FLAG))
- regs.PC = dst;
- else
- regs.PC += 2; // if !cc, skip 2 dst bytes
- break;
- }
+ // RLC n
+ for_each_register(0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, RLC_reg)
+
+ // RLC (HL)
+ case 0x06: {
+ u8 value = memory.read(regs.HL);
+ u8 bit7 = value >> 7;
+ value = (value << 1) | bit7;
+ memory.write(regs.HL, value);
+ set_flag_if(value == 0, ZERO_FLAG);
+ reset_flag(ADD_SUB_FLAG);
+ reset_flag(HALF_CARRY_FLAG);
+ cycles_until_next_instruction = 16;
+ break;
+ }
- case 0xD2: { // JP NC, nn
- u16 dst = memory.read16(regs.PC);
- if (!check_flag(CARRY_FLAG))
- regs.PC = dst;
- else
- regs.PC += 2; // if !cc, skip 2 dst bytes
- break;
- }
+ // RL n (through carry)
+ for_each_register(0x17, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, RL_reg)
+
+ // RL (HL) (through carry)
+ case 0x16: {
+ u8 value = memory.read(regs.HL);
+ u8 bit7 = value >> 7;
+ value = (value << 1) | check_flag(CARRY_FLAG);
+ memory.write(regs.HL, value);
+ set_flag_if(bit7, CARRY_FLAG);
+ set_flag_if(value == 0, ZERO_FLAG);
+ reset_flag(ADD_SUB_FLAG);
+ reset_flag(HALF_CARRY_FLAG);
+ cycles_until_next_instruction = 16;
+ break;
+ }
- case 0xDA: { // JP C, nn
- u16 dst = memory.read16(regs.PC);
- if (check_flag(CARRY_FLAG))
- regs.PC = dst;
- else
- regs.PC += 2; // if !cc, skip 2 dst bytes
- break;
- }
+ // RRC n
+ for_each_register(0x0F, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, RRC_reg)
+
+ // RRC (HL)
+ case 0x0E: {
+ u8 value = memory.read(regs.HL);
+ u8 bit0 = value & 1;
+ value = (value >> 1) | (bit0 << 7);
+ memory.write(regs.HL, value);
+ set_flag_if(value == 0, ZERO_FLAG);
+ reset_flag(ADD_SUB_FLAG);
+ reset_flag(HALF_CARRY_FLAG);
+ cycles_until_next_instruction = 16;
+ break;
+ }
- // JP (HL)
- case 0xE9:
- regs.PC = regs.HL;
- break;
+ // RR n (through carry)
+ for_each_register(0x1F, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, RR_reg)
+
+ // RR (HL) (through carry)
+ case 0x1E: {
+ u8 value = memory.read(regs.HL);
+ u8 bit0 = value & 1;
+ value = (value >> 1) | (check_flag(CARRY_FLAG) << 7);
+ memory.write(regs.HL, value);
+ set_flag_if(bit0, CARRY_FLAG);
+ set_flag_if(value == 0, ZERO_FLAG);
+ reset_flag(ADD_SUB_FLAG);
+ reset_flag(HALF_CARRY_FLAG);
+ cycles_until_next_instruction = 16;
+ break;
+ }
+
+ // SLA n
+ for_each_register(0x27, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, SLA_reg)
+
+ // SLA (HL)
+ case 0x26: {
+ u8 value = memory.read(regs.HL);
+ bool carry = (value & 0x80) != 0;
+ value <<= 1;
+ memory.write(regs.HL, value);
+ set_flag_if(value == 0, ZERO_FLAG);
+ reset_flag(ADD_SUB_FLAG);
+ reset_flag(HALF_CARRY_FLAG);
+ set_flag_if(carry, CARRY_FLAG);
+ cycles_until_next_instruction = 16;
+ break;
+ }
+
+ // SRA n
+ for_each_register(0x2F, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, SRA_reg)
+
+ // SRA (HL)
+ case 0x2E: {
+ u8 value = memory.read(regs.HL);
+ bool carry = (value & 0x01) != 0;
+ u8 MSB = value & 0x80;
+ value = (value >> 1) | MSB;
+ memory.write(regs.HL, value);
+ set_flag_if(value == 0, ZERO_FLAG);
+ reset_flag(ADD_SUB_FLAG);
+ reset_flag(HALF_CARRY_FLAG);
+ set_flag_if(carry, CARRY_FLAG);
+ cycles_until_next_instruction = 16;
+ break;
+ }
- // JR n
- case 0x18:
- // -1 because PC is now pointing past the opcode
- regs.PC += static_cast<s8>(memory.read(regs.PC++));
- break;
+ // SRL n
+ for_each_register(0x3F, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, SRL_reg)
+
+ // SRL (HL)
+ case 0x3E: {
+ u8 value = memory.read(regs.HL);
+ bool carry = (value & 0x01) != 0;
+ value >>= 1;
+ memory.write(regs.HL, value);
+ set_flag_if(value == 0, ZERO_FLAG);
+ reset_flag(ADD_SUB_FLAG);
+ reset_flag(HALF_CARRY_FLAG);
+ set_flag_if(carry, CARRY_FLAG);
+ cycles_until_next_instruction = 16;
+ break;
+ }
- // JR cc, n
- case 0x20: { // JR NZ, n
- s8 offset = static_cast<s8>(memory.read(regs.PC++));
- if (!check_flag(ZERO_FLAG))
- regs.PC += offset;
- break;
- }
+ default: {
+ int bit_op = sub_opcode >> 6;
+ int reg = sub_opcode & 7;
+ int b = (sub_opcode >> 3) & 7;
+ bool res;
+ switch (bit_op)
+ {
+ case 1: // BIT
+ switch(reg)
+ {
+ case 0:
+ res = check_bit(regs.B, b);
+ set_flag_if(res == false, ZERO_FLAG);
+ reset_flag(ADD_SUB_FLAG);
+ set_flag(HALF_CARRY_FLAG);
+ cycles_until_next_instruction = 8;
+ break;
+ case 1:
+ res = check_bit(regs.C, b);
+ set_flag_if(res == false, ZERO_FLAG);
+ reset_flag(ADD_SUB_FLAG);
+ set_flag(HALF_CARRY_FLAG);
+ cycles_until_next_instruction = 8;
+ break;
+ case 2:
+ res = check_bit(regs.D, b);
+ set_flag_if(res == false, ZERO_FLAG);
+ reset_flag(ADD_SUB_FLAG);
+ set_flag(HALF_CARRY_FLAG);
+ cycles_until_next_instruction = 8;
+ break;
+ case 3:
+ res = check_bit(regs.E, b);
+ set_flag_if(res == false, ZERO_FLAG);
+ reset_flag(ADD_SUB_FLAG);
+ set_flag(HALF_CARRY_FLAG);
+ cycles_until_next_instruction = 8;
+ break;
+ case 4:
+ res = check_bit(regs.H, b);
+ set_flag_if(res == false, ZERO_FLAG);
+ reset_flag(ADD_SUB_FLAG);
+ set_flag(HALF_CARRY_FLAG);
+ cycles_until_next_instruction = 8;
+ break;
+ case 5:
+ res = check_bit(regs.L, b);
+ set_flag_if(res == false, ZERO_FLAG);
+ reset_flag(ADD_SUB_FLAG);
+ set_flag(HALF_CARRY_FLAG);
+ cycles_until_next_instruction = 8;
+ break;
+ case 6:
+ res = check_bit(memory.read(regs.HL), b);
+ set_flag_if(res == false, ZERO_FLAG);
+ reset_flag(ADD_SUB_FLAG);
+ set_flag(HALF_CARRY_FLAG);
+ cycles_until_next_instruction = 16;
+ break;
+ case 7:
+ res = check_bit(regs.A, b);
+ set_flag_if(res == false, ZERO_FLAG);
+ reset_flag(ADD_SUB_FLAG);
+ set_flag(HALF_CARRY_FLAG);
+ cycles_until_next_instruction = 8;
+ break;
+ }
+ break;
+
+ case 2: // RES
+ switch(reg)
+ {
+ case 0:
+ regs.B = reset_bit(regs.B, b);
+ cycles_until_next_instruction = 8;
+ break;
+ case 1:
+ regs.C = reset_bit(regs.C, b);
+ cycles_until_next_instruction = 8;
+ break;
+ case 2:
+ regs.D = reset_bit(regs.D, b);
+ cycles_until_next_instruction = 8;
+ break;
+ case 3:
+ regs.E = reset_bit(regs.E, b);
+ cycles_until_next_instruction = 8;
+ break;
+ case 4:
+ regs.H = reset_bit(regs.H, b);
+ cycles_until_next_instruction = 8;
+ break;
+ case 5:
+ regs.L = reset_bit(regs.L, b);
+ cycles_until_next_instruction = 8;
+ break;
+ case 6:
+ memory.write(regs.HL, reset_bit(memory.read(regs.HL), b));
+ cycles_until_next_instruction = 16;
+ break;
+ case 7:
+ regs.A = reset_bit(regs.A, b);
+ cycles_until_next_instruction = 8;
+ break;
+ }
+ break;
+
+ case 3: // SET
+ switch(reg)
+ {
+ case 0:
+ regs.B = set_bit(regs.B, b);
+ cycles_until_next_instruction = 8;
+ break;
+ case 1:
+ regs.C = set_bit(regs.C, b);
+ cycles_until_next_instruction = 8;
+ break;
+ case 2:
+ regs.D = set_bit(regs.D, b);
+ cycles_until_next_instruction = 8;
+ break;
+ case 3:
+ regs.E = set_bit(regs.E, b);
+ cycles_until_next_instruction = 8;
+ break;
+ case 4:
+ regs.H = set_bit(regs.H, b);
+ cycles_until_next_instruction = 8;
+ break;
+ case 5:
+ regs.L = set_bit(regs.L, b);
+ cycles_until_next_instruction = 8;
+ break;
+ case 6:
+ memory.write(regs.HL, set_bit(memory.read(regs.HL), b));
+ cycles_until_next_instruction = 16;
+ break;
+ case 7:
+ regs.A = set_bit(regs.A, b);
+ cycles_until_next_instruction = 8;
+ break;
+ }
+ break;
+
+ default:
+ logger.critical("Unknown sub-opcode after 0xCB");
+ break;
+ }
+ }
+
+ }
+ break;
+ }
+ // DI
+ case 0xF3:
+ IME = 0;
+ cycles_until_next_instruction = 4;
+ break;
+
+ // EI
+ case 0xFB:
+ IME = 1;
+ cycles_until_next_instruction = 4;
+ break;
+
+ // Jumps
+ // JP nn
+ case 0xC3:
+ regs.PC = memory.read16(regs.PC);
+ cycles_until_next_instruction = 12;
+ break;
+
+ // JP cc, nn
+ case 0xC2: { // JP NZ, nn
+ u16 dst = memory.read16(regs.PC);
+ if (!check_flag(ZERO_FLAG))
+ regs.PC = dst;
+ else
+ regs.PC += 2; // if !cc, skip 2 dst bytes
+ cycles_until_next_instruction = 12;
+ break;
+ }
- case 0x28: { // JR Z, n
- s8 offset = static_cast<s8>(memory.read(regs.PC++));
- if (check_flag(ZERO_FLAG))
- regs.PC += offset;
- break;
- }
+ case 0xCA: { // JP Z, nn
+ u16 dst = memory.read16(regs.PC);
+ if (check_flag(ZERO_FLAG))
+ regs.PC = dst;
+ else
+ regs.PC += 2; // if !cc, skip 2 dst bytes
+ cycles_until_next_instruction = 12;
+ break;
+ }
- case 0x30: { // JR NC, n
- s8 offset = static_cast<s8>(memory.read(regs.PC++));
- if (!check_flag(CARRY_FLAG))
- regs.PC += offset;
- break;
- }
+ case 0xD2: { // JP NC, nn
+ u16 dst = memory.read16(regs.PC);
+ if (!check_flag(CARRY_FLAG))
+ regs.PC = dst;
+ else
+ regs.PC += 2; // if !cc, skip 2 dst bytes
+ cycles_until_next_instruction = 12;
+ break;
+ }
- case 0x38: { // JR C, n
- s8 offset = static_cast<s8>(memory.read(regs.PC++));
- if (check_flag(CARRY_FLAG))
- regs.PC += offset;
- break;
- }
+ case 0xDA: { // JP C, nn
+ u16 dst = memory.read16(regs.PC);
+ if (check_flag(CARRY_FLAG))
+ regs.PC = dst;
+ else
+ regs.PC += 2; // if !cc, skip 2 dst bytes
+ cycles_until_next_instruction = 12;
+ break;
+ }
- // Calls
- // CALL nn
- case 0xCD: {
- u16 addr = memory.read16(regs.PC);
- regs.PC += 2;
- do_call(addr);
- break;
- }
+ // JP (HL)
+ case 0xE9:
+ regs.PC = regs.HL;
+ cycles_until_next_instruction = 4;
+ break;
- // CALL cc, nn
- case 0xC4: { // CALL NZ, nn
- if (!check_flag(ZERO_FLAG)) {
+ // Calls
+ // CALL nn
+ case 0xCD: {
u16 addr = memory.read16(regs.PC);
regs.PC += 2;
do_call(addr);
- } else {
- regs.PC += 2; // if !cc, skip 2 (nn) bytes
+ cycles_until_next_instruction = 12;
+ break;
}
- break;
- }
- case 0xCC: { // CALL Z, nn
- if (check_flag(ZERO_FLAG)) {
- u16 addr = memory.read16(regs.PC);
- regs.PC += 2;
- do_call(addr);
- } else {
- regs.PC += 2; // if !cc, skip 2 (nn) bytes
+ // CALL cc, nn
+ case 0xC4: { // CALL NZ, nn
+ if (!check_flag(ZERO_FLAG)) {
+ u16 addr = memory.read16(regs.PC);
+ regs.PC += 2;
+ do_call(addr);
+ } else {
+ regs.PC += 2; // if !cc, skip 2 (nn) bytes
+ }
+ cycles_until_next_instruction = 12;
+ break;
}
- break;
- }
- case 0xD4: { // CALL NC, nn
- if (!check_flag(CARRY_FLAG)) {
- u16 addr = memory.read16(regs.PC);
- regs.PC += 2;
- do_call(addr);
- } else {
- regs.PC += 2; // if !cc, skip 2 (nn) bytes
+ case 0xCC: { // CALL Z, nn
+ if (check_flag(ZERO_FLAG)) {
+ u16 addr = memory.read16(regs.PC);
+ regs.PC += 2;
+ do_call(addr);
+ } else {
+ regs.PC += 2; // if !cc, skip 2 (nn) bytes
+ }
+ cycles_until_next_instruction = 12;
+ break;
}
- break;
- }
- case 0xDC: { // CALL C, nn
- if (check_flag(CARRY_FLAG)) {
- u16 addr = memory.read16(regs.PC);
- regs.PC += 2;
- do_call(addr);
- } else {
- regs.PC += 2; // if !cc, skip 2 (nn) bytes
+ case 0xD4: { // CALL NC, nn
+ if (!check_flag(CARRY_FLAG)) {
+ u16 addr = memory.read16(regs.PC);
+ regs.PC += 2;
+ do_call(addr);
+ } else {
+ regs.PC += 2; // if !cc, skip 2 (nn) bytes
+ }
+ cycles_until_next_instruction = 12;
+ break;
}
- break;
- }
-
- // Restarts
- RST(0xC7, 0x00)
- RST(0xCF, 0x08)
- RST(0xD7, 0x10)
- RST(0xDF, 0x18)
- RST(0xE7, 0x20)
- RST(0xEF, 0x28)
- RST(0xF7, 0x30)
- RST(0xFF, 0x38)
-
- // Returns
- // RET
- case 0xC9: {
- u16 retaddr = memory.read16(regs.SP);
- regs.SP += 2;
- regs.PC = retaddr;
- break;
- }
- // RET cc
- case 0xC0: // RET NZ
- if (!check_flag(ZERO_FLAG)) {
- u16 retaddr = memory.read16(regs.SP);
- regs.SP += 2;
- regs.PC = retaddr;
+ case 0xDC: { // CALL C, nn
+ if (check_flag(CARRY_FLAG)) {
+ u16 addr = memory.read16(regs.PC);
+ regs.PC += 2;
+ do_call(addr);
+ } else {
+ regs.PC += 2; // if !cc, skip 2 (nn) bytes
+ }
+ cycles_until_next_instruction = 12;
+ break;
}
- break;
- case 0xC8: // RET Z
- if (check_flag(ZERO_FLAG)) {
+ // Restarts
+ RST(0xC7, 0x00)
+ RST(0xCF, 0x08)
+ RST(0xD7, 0x10)
+ RST(0xDF, 0x18)
+ RST(0xE7, 0x20)
+ RST(0xEF, 0x28)
+ RST(0xF7, 0x30)
+ RST(0xFF, 0x38)
+
+ // Returns
+ // RET
+ case 0xC9: {
u16 retaddr = memory.read16(regs.SP);
regs.SP += 2;
regs.PC = retaddr;
+ cycles_until_next_instruction = 8;
+ break;
}
- break;
- case 0xD0: // RET NC
- if (!check_flag(CARRY_FLAG)) {
- u16 retaddr = memory.read16(regs.SP);
- regs.SP += 2;
- regs.PC = retaddr;
- }
- break;
+ // RET cc
+ case 0xC0: // RET NZ
+ if (!check_flag(ZERO_FLAG)) {
+ u16 retaddr = memory.read16(regs.SP);
+ regs.SP += 2;
+ regs.PC = retaddr;
+ }
+ cycles_until_next_instruction = 8;
+ break;
+
+ case 0xC8: // RET Z
+ if (check_flag(ZERO_FLAG)) {
+ u16 retaddr = memory.read16(regs.SP);
+ regs.SP += 2;
+ regs.PC = retaddr;
+ }
+ cycles_until_next_instruction = 8;
+ break;
+
+ case 0xD0: // RET NC
+ if (!check_flag(CARRY_FLAG)) {
+ u16 retaddr = memory.read16(regs.SP);
+ regs.SP += 2;
+ regs.PC = retaddr;
+ }
+ cycles_until_next_instruction = 8;
+ break;
+
+ case 0xD8: // RET C
+ if (check_flag(CARRY_FLAG)) {
+ u16 retaddr = memory.read16(regs.SP);
+ regs.SP += 2;
+ regs.PC = retaddr;
+ }
+ cycles_until_next_instruction = 8;
+ break;
- case 0xD8: // RET C
- if (check_flag(CARRY_FLAG)) {
+ // RETI
+ case 0xD9: {
+ // RET && EI
u16 retaddr = memory.read16(regs.SP);
regs.SP += 2;
regs.PC = retaddr;
+ IME=1;
+ cycles_until_next_instruction = 8;
+ break;
}
- break;
-
- // RETI
- case 0xD9: {
- // RET && EI
- u16 retaddr = memory.read16(regs.SP);
- regs.SP += 2;
- regs.PC = retaddr;
- IME=1;
- break;
+
+ default:
+ std::ostringstream errmsg;
+ errmsg << "Unknown opcode 0x";
+ errmsg << std::hex << std::setw(2) << std::setfill('0') << opcode;
+ errmsg << " at 0x" << std::hex << std::setw(4) << regs.PC-1;
+ errmsg << " (cycle count = " << std::dec << cycle_count << ")";
+ logger.critical(errmsg.str());
+ break;
}
+ break;
+ }
- default:
- std::ostringstream errmsg;
- errmsg << "Unknown opcode 0x";
- errmsg << std::hex << std::setw(2) << std::setfill('0') << opcode;
- errmsg << " at 0x" << std::hex << std::setw(4) << regs.PC-1;
- errmsg << " (cycle count = " << std::dec << cycle_count << ")";
- logger.critical(errmsg.str());
- break;
-
- } // end switch
-
- ++cycle_count;
+ if (cycles_until_video_update <= 0)
+ cycles_until_video_update = video.update();
- video.update();
-
- // Check for interrupts before opcode fetching
- u8 IE=memory.high[GBMemory::I_IE];
- //logger.trace("IME=", int(IME), " IE=", int(IE));
- if (IME && IE)
- {
- u8 IF = memory.high[GBMemory::I_IF];
- //logger.trace("Dispatching interrupts: IE=", int(IE), " IF=", int(IF));
- if (IF)
- {
- if ((IF & IRQ_VBLANK) && (IE & IRQ_VBLANK))
- {
- IME = 0;
- IF &= (~IRQ_VBLANK);
- do_call(0x40);
- logger.trace("VBLANK IRQ");
- }
- else if ((IF & IRQ_LCD_STAT) && (IE & IRQ_LCD_STAT))
- {
- IME = 0;
- IF &= (~IRQ_LCD_STAT);
- do_call(0x48);
- logger.trace("LCD STAT IRQ");
- }
- else if ((IF & IRQ_TIMER) && (IE & IRQ_TIMER))
- {
- IME = 0;
- IF &= (~IRQ_TIMER);
- do_call(0x50);
- logger.trace("TIMER IRQ");
- }
- else if ((IF & IRQ_SERIAL) && (IE & IRQ_SERIAL))
- {
- IME = 0;
- IF &= (~IRQ_SERIAL);
- do_call(0x58);
- logger.trace("SERIAL IRQ");
- }
- else if ((IF & IRQ_JOYPAD) && (IE & IRQ_JOYPAD))
- {
- IME = 0;
- IF &= (~IRQ_JOYPAD);
- do_call(0x60);
- logger.trace("JOYPAD IRQ");
- }
- }
- memory.high[GBMemory::I_IF] = IF;
- }
-
- /*
- for(BreakpointMap::iterator i=breakpoints.begin();
- i != breakpoints.end();
- i++)
- {
- if (i->second.addr == regs.PC && i->second.enabled)
- return BREAKPOINT;
- }
- */
+ cycles_until_video_update -= CYCLE_STEP;
+ cycles_until_next_instruction -= CYCLE_STEP;
- return NORMAL;
+ if (cycles_until_next_instruction > 0) return WAIT;
+ else return NORMAL;
}
GameBoy::run_status GameBoy::run()
{
+ static const int CYCLES_PER_INPUT_CHECK = 40000;
+ static int c=0;
SDL_Event ev;
run_status status=NORMAL;
- while (status == NORMAL)
+ while (status == NORMAL || status == WAIT)
{
- while (video.poll_event(&ev))
+ ++c;
+ if (c==CYCLES_PER_INPUT_CHECK)
{
- switch(ev.type)
+ c=0;
+ while (video.poll_event(&ev))
{
- case SDL_KEYDOWN:
- switch(ev.key.keysym.sym)
- {
- case SDLK_ESCAPE:
- return PAUSED;
- case SDLK_q:
- return QUIT;
- default:
- break;
- }
- break;
- case SDL_QUIT:
- return QUIT;
+ switch(ev.type)
+ {
+ case SDL_KEYDOWN:
+ switch(ev.key.keysym.sym)
+ {
+ case SDLK_ESCAPE:
+ return PAUSED;
+ case SDLK_q:
+ return QUIT;
+ default:
+ break;
+ }
+ break;
+ case SDL_QUIT:
+ return QUIT;
+ }
}
}
status = run_cycle();