/* Copyright (c) 2013-2016 Jeffrey Pfau * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include static inline uint16_t SM83ReadHL(struct SM83Core* cpu) { uint16_t hl; LOAD_16LE(hl, 0, &cpu->hl); return hl; } static inline void SM83WriteHL(struct SM83Core* cpu, uint16_t hl) { STORE_16LE(hl, 0, &cpu->hl); } static inline uint16_t SM83ReadBC(struct SM83Core* cpu) { uint16_t bc; LOAD_16LE(bc, 0, &cpu->bc); return bc; } static inline void SM83WriteBC(struct SM83Core* cpu, uint16_t bc) { STORE_16LE(bc, 0, &cpu->bc); } static inline uint16_t SM83ReadDE(struct SM83Core* cpu) { uint16_t de; LOAD_16LE(de, 0, &cpu->de); return de; } static inline void SM83WriteDE(struct SM83Core* cpu, uint16_t de) { STORE_16LE(de, 0, &cpu->de); } #define DEFINE_INSTRUCTION_SM83(NAME, BODY) \ static void _SM83Instruction ## NAME (struct SM83Core* cpu) { \ UNUSED(cpu); \ BODY; \ } DEFINE_INSTRUCTION_SM83(NOP,); #define DEFINE_CONDITIONAL_ONLY_INSTRUCTION_SM83(NAME) \ DEFINE_ ## NAME ## _INSTRUCTION_SM83(C, cpu->f.c) \ DEFINE_ ## NAME ## _INSTRUCTION_SM83(Z, cpu->f.z) \ DEFINE_ ## NAME ## _INSTRUCTION_SM83(NC, !cpu->f.c) \ DEFINE_ ## NAME ## _INSTRUCTION_SM83(NZ, !cpu->f.z) #define DEFINE_CONDITIONAL_INSTRUCTION_SM83(NAME) \ DEFINE_ ## NAME ## _INSTRUCTION_SM83(, true) \ DEFINE_CONDITIONAL_ONLY_INSTRUCTION_SM83(NAME) DEFINE_INSTRUCTION_SM83(JPFinish, if (cpu->condition) { cpu->pc = (cpu->bus << 8) | cpu->index; cpu->memory.setActiveRegion(cpu, cpu->pc); cpu->executionState = SM83_CORE_STALL; }) DEFINE_INSTRUCTION_SM83(JPDelay, cpu->executionState = SM83_CORE_READ_PC; cpu->instruction = _SM83InstructionJPFinish; cpu->index = cpu->bus;) #define DEFINE_JP_INSTRUCTION_SM83(CONDITION_NAME, CONDITION) \ DEFINE_INSTRUCTION_SM83(JP ## CONDITION_NAME, \ cpu->executionState = SM83_CORE_READ_PC; \ cpu->instruction = _SM83InstructionJPDelay; \ cpu->condition = CONDITION;) DEFINE_CONDITIONAL_INSTRUCTION_SM83(JP); DEFINE_INSTRUCTION_SM83(JPHL, cpu->pc = SM83ReadHL(cpu); cpu->memory.setActiveRegion(cpu, cpu->pc);) DEFINE_INSTRUCTION_SM83(JRFinish, if (cpu->condition) { cpu->pc += (int8_t) cpu->bus; cpu->memory.setActiveRegion(cpu, cpu->pc); cpu->executionState = SM83_CORE_STALL; }) #define DEFINE_JR_INSTRUCTION_SM83(CONDITION_NAME, CONDITION) \ DEFINE_INSTRUCTION_SM83(JR ## CONDITION_NAME, \ cpu->executionState = SM83_CORE_READ_PC; \ cpu->instruction = _SM83InstructionJRFinish; \ cpu->condition = CONDITION;) DEFINE_CONDITIONAL_INSTRUCTION_SM83(JR); DEFINE_INSTRUCTION_SM83(CALLUpdateSPL, --cpu->index; cpu->bus = cpu->sp; cpu->sp = cpu->index; cpu->executionState = SM83_CORE_MEMORY_STORE; cpu->instruction = _SM83InstructionNOP;) DEFINE_INSTRUCTION_SM83(CALLUpdateSPH, cpu->executionState = SM83_CORE_MEMORY_STORE; cpu->instruction = _SM83InstructionCALLUpdateSPL;) DEFINE_INSTRUCTION_SM83(CALLUpdatePCH, if (cpu->condition) { int newPc = (cpu->bus << 8) | cpu->index; cpu->bus = cpu->pc >> 8; cpu->index = cpu->sp - 1; cpu->sp = cpu->pc; // GROSS cpu->pc = newPc; cpu->memory.setActiveRegion(cpu, cpu->pc); cpu->executionState = SM83_CORE_OP2; cpu->instruction = _SM83InstructionCALLUpdateSPH; }) DEFINE_INSTRUCTION_SM83(CALLUpdatePCL, cpu->executionState = SM83_CORE_READ_PC; cpu->index = cpu->bus; cpu->instruction = _SM83InstructionCALLUpdatePCH) #define DEFINE_CALL_INSTRUCTION_SM83(CONDITION_NAME, CONDITION) \ DEFINE_INSTRUCTION_SM83(CALL ## CONDITION_NAME, \ cpu->condition = CONDITION; \ cpu->executionState = SM83_CORE_READ_PC; \ cpu->instruction = _SM83InstructionCALLUpdatePCL;) DEFINE_CONDITIONAL_INSTRUCTION_SM83(CALL) DEFINE_INSTRUCTION_SM83(RETFinish, cpu->sp += 2; /* TODO: Atomic incrementing? */ cpu->pc |= cpu->bus << 8; cpu->memory.setActiveRegion(cpu, cpu->pc); cpu->executionState = SM83_CORE_STALL;) DEFINE_INSTRUCTION_SM83(RETUpdateSPL, cpu->index = cpu->sp + 1; cpu->pc = cpu->bus; cpu->executionState = SM83_CORE_MEMORY_LOAD; cpu->instruction = _SM83InstructionRETFinish;) DEFINE_INSTRUCTION_SM83(RETUpdateSPH, if (cpu->condition) { cpu->index = cpu->sp; cpu->executionState = SM83_CORE_MEMORY_LOAD; cpu->instruction = _SM83InstructionRETUpdateSPL; }) #define DEFINE_RET_INSTRUCTION_SM83(CONDITION_NAME, CONDITION) \ DEFINE_INSTRUCTION_SM83(RET ## CONDITION_NAME, \ cpu->condition = CONDITION; \ cpu->executionState = SM83_CORE_OP2; \ cpu->instruction = _SM83InstructionRETUpdateSPH;) DEFINE_INSTRUCTION_SM83(RET, cpu->condition = true; _SM83InstructionRETUpdateSPH(cpu);) DEFINE_INSTRUCTION_SM83(RETI, cpu->condition = true; cpu->irqh.setInterrupts(cpu, true); _SM83InstructionRETUpdateSPH(cpu);) DEFINE_CONDITIONAL_ONLY_INSTRUCTION_SM83(RET) #define DEFINE_AND_INSTRUCTION_SM83(NAME, OPERAND) \ DEFINE_INSTRUCTION_SM83(AND ## NAME, \ cpu->a &= OPERAND; \ cpu->f.z = !cpu->a; \ cpu->f.n = 0; \ cpu->f.c = 0; \ cpu->f.h = 1;) #define DEFINE_XOR_INSTRUCTION_SM83(NAME, OPERAND) \ DEFINE_INSTRUCTION_SM83(XOR ## NAME, \ cpu->a ^= OPERAND; \ cpu->f.z = !cpu->a; \ cpu->f.n = 0; \ cpu->f.c = 0; \ cpu->f.h = 0;) #define DEFINE_OR_INSTRUCTION_SM83(NAME, OPERAND) \ DEFINE_INSTRUCTION_SM83(OR ## NAME, \ cpu->a |= OPERAND; \ cpu->f.z = !cpu->a; \ cpu->f.n = 0; \ cpu->f.c = 0; \ cpu->f.h = 0;) #define DEFINE_CP_INSTRUCTION_SM83(NAME, OPERAND) \ DEFINE_INSTRUCTION_SM83(CP ## NAME, \ int diff = cpu->a - OPERAND; \ cpu->f.n = 1; \ cpu->f.z = !(diff & 0xFF); \ cpu->f.h = (cpu->a & 0xF) - (OPERAND & 0xF) < 0; \ cpu->f.c = diff < 0;) #define DEFINE_LDB__INSTRUCTION_SM83(NAME, OPERAND) \ DEFINE_INSTRUCTION_SM83(LDB_ ## NAME, \ cpu->b = OPERAND;) #define DEFINE_LDC__INSTRUCTION_SM83(NAME, OPERAND) \ DEFINE_INSTRUCTION_SM83(LDC_ ## NAME, \ cpu->c = OPERAND;) #define DEFINE_LDD__INSTRUCTION_SM83(NAME, OPERAND) \ DEFINE_INSTRUCTION_SM83(LDD_ ## NAME, \ cpu->d = OPERAND;) #define DEFINE_LDE__INSTRUCTION_SM83(NAME, OPERAND) \ DEFINE_INSTRUCTION_SM83(LDE_ ## NAME, \ cpu->e = OPERAND;) #define DEFINE_LDH__INSTRUCTION_SM83(NAME, OPERAND) \ DEFINE_INSTRUCTION_SM83(LDH_ ## NAME, \ cpu->h = OPERAND;) #define DEFINE_LDL__INSTRUCTION_SM83(NAME, OPERAND) \ DEFINE_INSTRUCTION_SM83(LDL_ ## NAME, \ cpu->l = OPERAND;) #define DEFINE_LDHL__INSTRUCTION_SM83(NAME, OPERAND) \ DEFINE_INSTRUCTION_SM83(LDHL_ ## NAME, \ cpu->bus = OPERAND; \ cpu->index = SM83ReadHL(cpu); \ cpu->executionState = SM83_CORE_MEMORY_STORE; \ cpu->instruction = _SM83InstructionNOP;) #define DEFINE_LDA__INSTRUCTION_SM83(NAME, OPERAND) \ DEFINE_INSTRUCTION_SM83(LDA_ ## NAME, \ cpu->a = OPERAND;) #define DEFINE_ALU_INSTRUCTION_SM83_NOHL(NAME) \ DEFINE_ ## NAME ## _INSTRUCTION_SM83(A, cpu->a); \ DEFINE_ ## NAME ## _INSTRUCTION_SM83(B, cpu->b); \ DEFINE_ ## NAME ## _INSTRUCTION_SM83(C, cpu->c); \ DEFINE_ ## NAME ## _INSTRUCTION_SM83(D, cpu->d); \ DEFINE_ ## NAME ## _INSTRUCTION_SM83(E, cpu->e); \ DEFINE_ ## NAME ## _INSTRUCTION_SM83(H, cpu->h); \ DEFINE_ ## NAME ## _INSTRUCTION_SM83(L, cpu->l); DEFINE_INSTRUCTION_SM83(LDHL_Bus, \ cpu->index = SM83ReadHL(cpu); \ cpu->executionState = SM83_CORE_MEMORY_STORE; \ cpu->instruction = _SM83InstructionNOP;) DEFINE_INSTRUCTION_SM83(LDHL_, \ cpu->executionState = SM83_CORE_READ_PC; \ cpu->instruction = _SM83InstructionLDHL_Bus;) DEFINE_INSTRUCTION_SM83(LDHL_SPDelay, int diff = (int8_t) cpu->bus; int sum = cpu->sp + diff; SM83WriteHL(cpu, sum); cpu->executionState = SM83_CORE_STALL; cpu->f.z = 0; cpu->f.n = 0; cpu->f.c = (diff & 0xFF) + (cpu->sp & 0xFF) >= 0x100; cpu->f.h = (diff & 0xF) + (cpu->sp & 0xF) >= 0x10;) DEFINE_INSTRUCTION_SM83(LDHL_SP, cpu->executionState = SM83_CORE_READ_PC; cpu->instruction = _SM83InstructionLDHL_SPDelay;) DEFINE_INSTRUCTION_SM83(LDSP_HL, cpu->sp = SM83ReadHL(cpu); cpu->executionState = SM83_CORE_STALL;) #define DEFINE_ALU_INSTRUCTION_SM83_MEM(NAME, REG) \ DEFINE_INSTRUCTION_SM83(NAME ## REG, \ cpu->executionState = SM83_CORE_MEMORY_LOAD; \ cpu->index = SM83Read ## REG (cpu); \ cpu->instruction = _SM83Instruction ## NAME ## Bus;) #define DEFINE_ALU_INSTRUCTION_SM83(NAME) \ DEFINE_ ## NAME ## _INSTRUCTION_SM83(Bus, cpu->bus); \ DEFINE_ALU_INSTRUCTION_SM83_MEM(NAME, HL) \ DEFINE_INSTRUCTION_SM83(NAME, \ cpu->executionState = SM83_CORE_READ_PC; \ cpu->instruction = _SM83Instruction ## NAME ## Bus;) \ DEFINE_ALU_INSTRUCTION_SM83_NOHL(NAME) DEFINE_ALU_INSTRUCTION_SM83(AND); DEFINE_ALU_INSTRUCTION_SM83(XOR); DEFINE_ALU_INSTRUCTION_SM83(OR); DEFINE_ALU_INSTRUCTION_SM83(CP); static void _SM83InstructionLDB_Bus(struct SM83Core*); static void _SM83InstructionLDC_Bus(struct SM83Core*); static void _SM83InstructionLDD_Bus(struct SM83Core*); static void _SM83InstructionLDE_Bus(struct SM83Core*); static void _SM83InstructionLDH_Bus(struct SM83Core*); static void _SM83InstructionLDL_Bus(struct SM83Core*); static void _SM83InstructionLDHL_Bus(struct SM83Core*); static void _SM83InstructionLDA_Bus(struct SM83Core*); #define DEFINE_ADD_INSTRUCTION_SM83(NAME, OPERAND) \ DEFINE_INSTRUCTION_SM83(ADD ## NAME, \ int diff = cpu->a + OPERAND; \ cpu->f.n = 0; \ cpu->f.h = (cpu->a & 0xF) + (OPERAND & 0xF) >= 0x10; \ cpu->f.c = diff >= 0x100; \ cpu->a = diff; \ cpu->f.z = !cpu->a;) #define DEFINE_ADC_INSTRUCTION_SM83(NAME, OPERAND) \ DEFINE_INSTRUCTION_SM83(ADC ## NAME, \ int diff = cpu->a + OPERAND + cpu->f.c; \ cpu->f.n = 0; \ cpu->f.h = (cpu->a & 0xF) + (OPERAND & 0xF) + cpu->f.c >= 0x10; \ cpu->f.c = diff >= 0x100; \ cpu->a = diff; \ cpu->f.z = !cpu->a;) #define DEFINE_SUB_INSTRUCTION_SM83(NAME, OPERAND) \ DEFINE_INSTRUCTION_SM83(SUB ## NAME, \ int diff = cpu->a - OPERAND; \ cpu->f.n = 1; \ cpu->f.h = (cpu->a & 0xF) - (OPERAND & 0xF) < 0; \ cpu->f.c = diff < 0; \ cpu->a = diff; \ cpu->f.z = !cpu->a;) #define DEFINE_SBC_INSTRUCTION_SM83(NAME, OPERAND) \ DEFINE_INSTRUCTION_SM83(SBC ## NAME, \ int diff = cpu->a - OPERAND - cpu->f.c; \ cpu->f.n = 1; \ cpu->f.h = (cpu->a & 0xF) - (OPERAND & 0xF) - cpu->f.c < 0; \ cpu->f.c = diff < 0; \ cpu->a = diff; \ cpu->f.z = !cpu->a;) DEFINE_ALU_INSTRUCTION_SM83(LDB_); DEFINE_ALU_INSTRUCTION_SM83(LDC_); DEFINE_ALU_INSTRUCTION_SM83(LDD_); DEFINE_ALU_INSTRUCTION_SM83(LDE_); DEFINE_ALU_INSTRUCTION_SM83(LDH_); DEFINE_ALU_INSTRUCTION_SM83(LDL_); DEFINE_ALU_INSTRUCTION_SM83_NOHL(LDHL_); DEFINE_ALU_INSTRUCTION_SM83(LDA_); DEFINE_ALU_INSTRUCTION_SM83_MEM(LDA_, BC); DEFINE_ALU_INSTRUCTION_SM83_MEM(LDA_, DE); DEFINE_ALU_INSTRUCTION_SM83(ADD); DEFINE_ALU_INSTRUCTION_SM83(ADC); DEFINE_ALU_INSTRUCTION_SM83(SUB); DEFINE_ALU_INSTRUCTION_SM83(SBC); DEFINE_INSTRUCTION_SM83(ADDSPFinish, cpu->sp = cpu->index; cpu->executionState = SM83_CORE_STALL;) DEFINE_INSTRUCTION_SM83(ADDSPDelay, int diff = (int8_t) cpu->bus; int sum = cpu->sp + diff; cpu->index = sum; cpu->executionState = SM83_CORE_OP2; cpu->instruction = _SM83InstructionADDSPFinish; cpu->f.z = 0; cpu->f.n = 0; cpu->f.c = (diff & 0xFF) + (cpu->sp & 0xFF) >= 0x100; cpu->f.h = (diff & 0xF) + (cpu->sp & 0xF) >= 0x10;) DEFINE_INSTRUCTION_SM83(ADDSP, cpu->executionState = SM83_CORE_READ_PC; cpu->instruction = _SM83InstructionADDSPDelay;) DEFINE_INSTRUCTION_SM83(LDBCDelay, \ cpu->c = cpu->bus; \ cpu->executionState = SM83_CORE_READ_PC; \ cpu->instruction = _SM83InstructionLDB_Bus;) DEFINE_INSTRUCTION_SM83(LDBC, \ cpu->executionState = SM83_CORE_READ_PC; \ cpu->instruction = _SM83InstructionLDBCDelay;) DEFINE_INSTRUCTION_SM83(LDBC_A, \ cpu->index = SM83ReadBC(cpu); \ cpu->bus = cpu->a; \ cpu->executionState = SM83_CORE_MEMORY_STORE; \ cpu->instruction = _SM83InstructionNOP;) DEFINE_INSTRUCTION_SM83(LDDEDelay, \ cpu->e = cpu->bus; \ cpu->executionState = SM83_CORE_READ_PC; \ cpu->instruction = _SM83InstructionLDD_Bus;) DEFINE_INSTRUCTION_SM83(LDDE, \ cpu->executionState = SM83_CORE_READ_PC; \ cpu->instruction = _SM83InstructionLDDEDelay;) DEFINE_INSTRUCTION_SM83(LDDE_A, \ cpu->index = SM83ReadDE(cpu); \ cpu->bus = cpu->a; \ cpu->executionState = SM83_CORE_MEMORY_STORE; \ cpu->instruction = _SM83InstructionNOP;) DEFINE_INSTRUCTION_SM83(LDHLDelay, \ cpu->l = cpu->bus; \ cpu->executionState = SM83_CORE_READ_PC; \ cpu->instruction = _SM83InstructionLDH_Bus;) DEFINE_INSTRUCTION_SM83(LDHL, \ cpu->executionState = SM83_CORE_READ_PC; \ cpu->instruction = _SM83InstructionLDHLDelay;) DEFINE_INSTRUCTION_SM83(LDSPFinish, cpu->sp |= cpu->bus << 8;) DEFINE_INSTRUCTION_SM83(LDSPDelay, \ cpu->sp = cpu->bus; \ cpu->executionState = SM83_CORE_READ_PC; \ cpu->instruction = _SM83InstructionLDSPFinish;) DEFINE_INSTRUCTION_SM83(LDSP, \ cpu->executionState = SM83_CORE_READ_PC; \ cpu->instruction = _SM83InstructionLDSPDelay;) DEFINE_INSTRUCTION_SM83(LDIHLA, \ cpu->index = SM83ReadHL(cpu); \ SM83WriteHL(cpu, cpu->index + 1); \ cpu->bus = cpu->a; \ cpu->executionState = SM83_CORE_MEMORY_STORE; \ cpu->instruction = _SM83InstructionNOP;) DEFINE_INSTRUCTION_SM83(LDDHLA, \ cpu->index = SM83ReadHL(cpu); \ SM83WriteHL(cpu, cpu->index - 1); \ cpu->bus = cpu->a; \ cpu->executionState = SM83_CORE_MEMORY_STORE; \ cpu->instruction = _SM83InstructionNOP;) DEFINE_INSTRUCTION_SM83(LDA_IHL, \ cpu->index = SM83ReadHL(cpu); \ SM83WriteHL(cpu, cpu->index + 1); \ cpu->executionState = SM83_CORE_MEMORY_LOAD; \ cpu->instruction = _SM83InstructionLDA_Bus;) DEFINE_INSTRUCTION_SM83(LDA_DHL, \ cpu->index = SM83ReadHL(cpu); \ SM83WriteHL(cpu, cpu->index - 1); \ cpu->executionState = SM83_CORE_MEMORY_LOAD; \ cpu->instruction = _SM83InstructionLDA_Bus;) DEFINE_INSTRUCTION_SM83(LDIAFinish, \ cpu->index |= cpu->bus << 8; cpu->bus = cpu->a; \ cpu->executionState = SM83_CORE_MEMORY_STORE; \ cpu->instruction = _SM83InstructionNOP;) DEFINE_INSTRUCTION_SM83(LDIADelay, \ cpu->index = cpu->bus; cpu->executionState = SM83_CORE_READ_PC; \ cpu->instruction = _SM83InstructionLDIAFinish;) DEFINE_INSTRUCTION_SM83(LDIA, \ cpu->executionState = SM83_CORE_READ_PC; \ cpu->instruction = _SM83InstructionLDIADelay;) DEFINE_INSTRUCTION_SM83(LDAIFinish, \ cpu->index |= cpu->bus << 8; cpu->executionState = SM83_CORE_MEMORY_LOAD; \ cpu->instruction = _SM83InstructionLDA_Bus;) DEFINE_INSTRUCTION_SM83(LDAIDelay, \ cpu->index = cpu->bus; cpu->executionState = SM83_CORE_READ_PC; \ cpu->instruction = _SM83InstructionLDAIFinish;) DEFINE_INSTRUCTION_SM83(LDAI, \ cpu->executionState = SM83_CORE_READ_PC; \ cpu->instruction = _SM83InstructionLDAIDelay;) DEFINE_INSTRUCTION_SM83(LDAIOC, \ cpu->index = 0xFF00 | cpu->c; \ cpu->executionState = SM83_CORE_MEMORY_LOAD; \ cpu->instruction = _SM83InstructionLDA_Bus;) DEFINE_INSTRUCTION_SM83(LDIOCA, \ cpu->index = 0xFF00 | cpu->c; \ cpu->bus = cpu->a; \ cpu->executionState = SM83_CORE_MEMORY_STORE; \ cpu->instruction = _SM83InstructionNOP;) DEFINE_INSTRUCTION_SM83(LDAIODelay, \ cpu->index = 0xFF00 | cpu->bus; \ cpu->executionState = SM83_CORE_MEMORY_LOAD; \ cpu->instruction = _SM83InstructionLDA_Bus;) DEFINE_INSTRUCTION_SM83(LDAIO, \ cpu->executionState = SM83_CORE_READ_PC; \ cpu->instruction = _SM83InstructionLDAIODelay;) DEFINE_INSTRUCTION_SM83(LDIOADelay, \ cpu->index = 0xFF00 | cpu->bus; \ cpu->bus = cpu->a; \ cpu->executionState = SM83_CORE_MEMORY_STORE; \ cpu->instruction = _SM83InstructionNOP;) DEFINE_INSTRUCTION_SM83(LDIOA, \ cpu->executionState = SM83_CORE_READ_PC; \ cpu->instruction = _SM83InstructionLDIOADelay;) DEFINE_INSTRUCTION_SM83(LDISPStoreH, ++cpu->index; cpu->bus = cpu->sp >> 8; cpu->executionState = SM83_CORE_MEMORY_STORE; cpu->instruction = _SM83InstructionNOP;) DEFINE_INSTRUCTION_SM83(LDISPStoreL, cpu->index |= cpu->bus << 8; cpu->bus = cpu->sp; cpu->executionState = SM83_CORE_MEMORY_STORE; cpu->instruction = _SM83InstructionLDISPStoreH;) DEFINE_INSTRUCTION_SM83(LDISPReadAddr, cpu->index = cpu->bus; cpu->executionState = SM83_CORE_READ_PC; cpu->instruction = _SM83InstructionLDISPStoreL;) DEFINE_INSTRUCTION_SM83(LDISP, cpu->executionState = SM83_CORE_READ_PC; cpu->instruction = _SM83InstructionLDISPReadAddr;) #define DEFINE_INCDEC_WIDE_INSTRUCTION_SM83(REG) \ DEFINE_INSTRUCTION_SM83(INC ## REG, \ uint16_t reg = SM83Read ## REG (cpu); \ SM83Write ## REG (cpu, reg + 1); \ cpu->executionState = SM83_CORE_STALL;) \ DEFINE_INSTRUCTION_SM83(DEC ## REG, \ uint16_t reg = SM83Read ## REG (cpu); \ SM83Write ## REG (cpu, reg - 1); \ cpu->executionState = SM83_CORE_STALL;) DEFINE_INCDEC_WIDE_INSTRUCTION_SM83(BC); DEFINE_INCDEC_WIDE_INSTRUCTION_SM83(DE); DEFINE_INCDEC_WIDE_INSTRUCTION_SM83(HL); #define DEFINE_ADD_HL_INSTRUCTION_SM83(REG, L, H) \ DEFINE_INSTRUCTION_SM83(ADDHL_ ## REG ## Finish, \ int diff = H + cpu->h + cpu->f.c; \ cpu->f.n = 0; \ cpu->f.h = (H & 0xF) + (cpu->h & 0xF) + cpu->f.c >= 0x10; \ cpu->f.c = diff >= 0x100; \ cpu->h = diff;) \ DEFINE_INSTRUCTION_SM83(ADDHL_ ## REG, \ int diff = L + cpu->l; \ cpu->l = diff; \ cpu->f.c = diff >= 0x100; \ cpu->executionState = SM83_CORE_OP2; \ cpu->instruction = _SM83InstructionADDHL_ ## REG ## Finish;) DEFINE_ADD_HL_INSTRUCTION_SM83(BC, cpu->c, cpu->b); DEFINE_ADD_HL_INSTRUCTION_SM83(DE, cpu->e, cpu->d); DEFINE_ADD_HL_INSTRUCTION_SM83(HL, cpu->l, cpu->h); DEFINE_ADD_HL_INSTRUCTION_SM83(SP, (cpu->sp & 0xFF), (cpu->sp >> 8)); #define DEFINE_INC_INSTRUCTION_SM83(NAME, OPERAND) \ DEFINE_INSTRUCTION_SM83(INC ## NAME, \ int diff = OPERAND + 1; \ cpu->f.h = (OPERAND & 0xF) == 0xF; \ OPERAND = diff; \ cpu->f.n = 0; \ cpu->f.z = !OPERAND;) #define DEFINE_DEC_INSTRUCTION_SM83(NAME, OPERAND) \ DEFINE_INSTRUCTION_SM83(DEC ## NAME, \ int diff = OPERAND - 1; \ cpu->f.h = (OPERAND & 0xF) == 0x0; \ OPERAND = diff; \ cpu->f.n = 1; \ cpu->f.z = !OPERAND;) DEFINE_ALU_INSTRUCTION_SM83_NOHL(INC); DEFINE_ALU_INSTRUCTION_SM83_NOHL(DEC); DEFINE_INSTRUCTION_SM83(INC_HLDelay, int diff = cpu->bus + 1; cpu->f.n = 0; cpu->f.h = (cpu->bus & 0xF) == 0xF; cpu->bus = diff; cpu->f.z = !cpu->bus; cpu->instruction = _SM83InstructionNOP; cpu->executionState = SM83_CORE_MEMORY_STORE;) DEFINE_INSTRUCTION_SM83(INC_HL, cpu->index = SM83ReadHL(cpu); cpu->instruction = _SM83InstructionINC_HLDelay; cpu->executionState = SM83_CORE_MEMORY_LOAD;) DEFINE_INSTRUCTION_SM83(DEC_HLDelay, int diff = cpu->bus - 1; cpu->f.n = 1; cpu->f.h = (cpu->bus & 0xF) == 0; cpu->bus = diff; cpu->f.z = !cpu->bus; cpu->instruction = _SM83InstructionNOP; cpu->executionState = SM83_CORE_MEMORY_STORE;) DEFINE_INSTRUCTION_SM83(DEC_HL, cpu->index = SM83ReadHL(cpu); cpu->instruction = _SM83InstructionDEC_HLDelay; cpu->executionState = SM83_CORE_MEMORY_LOAD;) DEFINE_INSTRUCTION_SM83(INCSP, ++cpu->sp; cpu->executionState = SM83_CORE_STALL;) DEFINE_INSTRUCTION_SM83(DECSP, --cpu->sp; cpu->executionState = SM83_CORE_STALL;) DEFINE_INSTRUCTION_SM83(SCF, cpu->f.c = 1; cpu->f.h = 0; cpu->f.n = 0;) DEFINE_INSTRUCTION_SM83(CCF, cpu->f.c ^= 1; cpu->f.h = 0; cpu->f.n = 0;) DEFINE_INSTRUCTION_SM83(CPL_, cpu->a ^= 0xFF; cpu->f.h = 1; cpu->f.n = 1;) DEFINE_INSTRUCTION_SM83(DAA, if (cpu->f.n) { if (cpu->f.h) { cpu->a += 0xFA; } if (cpu->f.c) { cpu->a += 0xA0; } } else { int a = cpu->a; if ((cpu->a & 0xF) > 0x9 || cpu->f.h) { a += 0x6; } if ((a & 0x1F0) > 0x90 || cpu->f.c) { a += 0x60; cpu->f.c = 1; } else { cpu->f.c = 0; } cpu->a = a; } cpu->f.h = 0; cpu->f.z = !cpu->a;) #define DEFINE_POPPUSH_INSTRUCTION_SM83(REG, HH, H, L) \ DEFINE_INSTRUCTION_SM83(POP ## REG ## Delay, \ cpu-> L = cpu->bus; \ cpu->f.packed &= 0xF0; \ cpu->index = cpu->sp; \ ++cpu->sp; \ cpu->instruction = _SM83InstructionLD ## HH ## _Bus; \ cpu->executionState = SM83_CORE_MEMORY_LOAD;) \ DEFINE_INSTRUCTION_SM83(POP ## REG, \ cpu->index = cpu->sp; \ ++cpu->sp; \ cpu->instruction = _SM83InstructionPOP ## REG ## Delay; \ cpu->executionState = SM83_CORE_MEMORY_LOAD;) \ DEFINE_INSTRUCTION_SM83(PUSH ## REG ## Finish, \ cpu->executionState = SM83_CORE_STALL;) \ DEFINE_INSTRUCTION_SM83(PUSH ## REG ## Delay, \ --cpu->sp; \ cpu->index = cpu->sp; \ cpu->bus = cpu-> L; \ cpu->instruction = _SM83InstructionPUSH ## REG ## Finish; \ cpu->executionState = SM83_CORE_MEMORY_STORE;) \ DEFINE_INSTRUCTION_SM83(PUSH ## REG, \ --cpu->sp; \ cpu->index = cpu->sp; \ cpu->bus = cpu-> H; \ cpu->instruction = _SM83InstructionPUSH ## REG ## Delay; \ cpu->executionState = SM83_CORE_MEMORY_STORE;) DEFINE_POPPUSH_INSTRUCTION_SM83(BC, B, b, c); DEFINE_POPPUSH_INSTRUCTION_SM83(DE, D, d, e); DEFINE_POPPUSH_INSTRUCTION_SM83(HL, H, h, l); DEFINE_POPPUSH_INSTRUCTION_SM83(AF, A, a, f.packed); #define DEFINE_CB_2_INSTRUCTION_SM83(NAME, WB, BODY) \ DEFINE_INSTRUCTION_SM83(NAME ## B, uint8_t reg = cpu->b; BODY; cpu->b = reg) \ DEFINE_INSTRUCTION_SM83(NAME ## C, uint8_t reg = cpu->c; BODY; cpu->c = reg) \ DEFINE_INSTRUCTION_SM83(NAME ## D, uint8_t reg = cpu->d; BODY; cpu->d = reg) \ DEFINE_INSTRUCTION_SM83(NAME ## E, uint8_t reg = cpu->e; BODY; cpu->e = reg) \ DEFINE_INSTRUCTION_SM83(NAME ## H, uint8_t reg = cpu->h; BODY; cpu->h = reg) \ DEFINE_INSTRUCTION_SM83(NAME ## L, uint8_t reg = cpu->l; BODY; cpu->l = reg) \ DEFINE_INSTRUCTION_SM83(NAME ## HLDelay, \ uint8_t reg = cpu->bus; \ BODY; \ cpu->bus = reg; \ cpu->executionState = WB; \ cpu->instruction = _SM83InstructionNOP;) \ DEFINE_INSTRUCTION_SM83(NAME ## HL, \ cpu->index = SM83ReadHL(cpu); \ cpu->executionState = SM83_CORE_MEMORY_LOAD; \ cpu->instruction = _SM83Instruction ## NAME ## HLDelay;) \ DEFINE_INSTRUCTION_SM83(NAME ## A, uint8_t reg = cpu->a; BODY; cpu->a = reg) #define DEFINE_CB_INSTRUCTION_SM83(NAME, WB, BODY) \ DEFINE_CB_2_INSTRUCTION_SM83(NAME ## 0, WB, uint8_t bit = 1; BODY) \ DEFINE_CB_2_INSTRUCTION_SM83(NAME ## 1, WB, uint8_t bit = 2; BODY) \ DEFINE_CB_2_INSTRUCTION_SM83(NAME ## 2, WB, uint8_t bit = 4; BODY) \ DEFINE_CB_2_INSTRUCTION_SM83(NAME ## 3, WB, uint8_t bit = 8; BODY) \ DEFINE_CB_2_INSTRUCTION_SM83(NAME ## 4, WB, uint8_t bit = 16; BODY) \ DEFINE_CB_2_INSTRUCTION_SM83(NAME ## 5, WB, uint8_t bit = 32; BODY) \ DEFINE_CB_2_INSTRUCTION_SM83(NAME ## 6, WB, uint8_t bit = 64; BODY) \ DEFINE_CB_2_INSTRUCTION_SM83(NAME ## 7, WB, uint8_t bit = 128; BODY) DEFINE_CB_INSTRUCTION_SM83(BIT, SM83_CORE_FETCH, cpu->f.n = 0; cpu->f.h = 1; cpu->f.z = !(reg & bit)) DEFINE_CB_INSTRUCTION_SM83(RES, SM83_CORE_MEMORY_STORE, reg &= ~bit) DEFINE_CB_INSTRUCTION_SM83(SET, SM83_CORE_MEMORY_STORE, reg |= bit) #define DEFINE_CB_ALU_INSTRUCTION_SM83(NAME, BODY) \ DEFINE_CB_2_INSTRUCTION_SM83(NAME, SM83_CORE_MEMORY_STORE, \ BODY; \ cpu->f.n = 0; \ cpu->f.h = 0; \ cpu->f.z = !reg;) DEFINE_CB_ALU_INSTRUCTION_SM83(RL, int wide = (reg << 1) | cpu->f.c; reg = wide; cpu->f.c = wide >> 8) DEFINE_CB_ALU_INSTRUCTION_SM83(RLC, reg = (reg << 1) | (reg >> 7); cpu->f.c = reg & 1) DEFINE_CB_ALU_INSTRUCTION_SM83(RR, int low = reg & 1; reg = (reg >> 1) | (cpu->f.c << 7); cpu->f.c = low) DEFINE_CB_ALU_INSTRUCTION_SM83(RRC, int low = reg & 1; reg = (reg >> 1) | (low << 7); cpu->f.c = low) DEFINE_CB_ALU_INSTRUCTION_SM83(SLA, cpu->f.c = reg >> 7; reg <<= 1) DEFINE_CB_ALU_INSTRUCTION_SM83(SRA, cpu->f.c = reg & 1; reg = ((int8_t) reg) >> 1) DEFINE_CB_ALU_INSTRUCTION_SM83(SRL, cpu->f.c = reg & 1; reg >>= 1) DEFINE_CB_ALU_INSTRUCTION_SM83(SWAP, reg = (reg << 4) | (reg >> 4); cpu->f.c = 0) DEFINE_INSTRUCTION_SM83(RLA_, int wide = (cpu->a << 1) | cpu->f.c; cpu->a = wide; cpu->f.z = 0; cpu->f.h = 0; cpu->f.n = 0; cpu->f.c = wide >> 8;) DEFINE_INSTRUCTION_SM83(RLCA_, cpu->a = (cpu->a << 1) | (cpu->a >> 7); cpu->f.z = 0; cpu->f.h = 0; cpu->f.n = 0; cpu->f.c = cpu->a & 1;) DEFINE_INSTRUCTION_SM83(RRA_, int low = cpu->a & 1; cpu->a = (cpu->a >> 1) | (cpu->f.c << 7); cpu->f.z = 0; cpu->f.h = 0; cpu->f.n = 0; cpu->f.c = low;) DEFINE_INSTRUCTION_SM83(RRCA_, int low = cpu->a & 1; cpu->a = (cpu->a >> 1) | (low << 7); cpu->f.z = 0; cpu->f.h = 0; cpu->f.n = 0; cpu->f.c = low;) DEFINE_INSTRUCTION_SM83(DI, cpu->irqh.setInterrupts(cpu, false)); DEFINE_INSTRUCTION_SM83(EI, cpu->irqh.setInterrupts(cpu, true)); DEFINE_INSTRUCTION_SM83(HALT, cpu->irqh.halt(cpu)); #define DEFINE_RST_INSTRUCTION_SM83(VEC) \ DEFINE_INSTRUCTION_SM83(RST ## VEC ## UpdateSPL, \ --cpu->sp; \ cpu->index = cpu->sp; \ cpu->bus = cpu->pc; \ cpu->pc = 0x ## VEC; \ cpu->memory.setActiveRegion(cpu, cpu->pc); \ cpu->executionState = SM83_CORE_MEMORY_STORE; \ cpu->instruction = _SM83InstructionNOP;) \ DEFINE_INSTRUCTION_SM83(RST ## VEC ## UpdateSPH, \ --cpu->sp;\ cpu->index = cpu->sp; \ cpu->bus = cpu->pc >> 8; \ cpu->executionState = SM83_CORE_MEMORY_STORE; \ cpu->instruction = _SM83InstructionRST ## VEC ## UpdateSPL;) \ DEFINE_INSTRUCTION_SM83(RST ## VEC, \ cpu->executionState = SM83_CORE_OP2; \ cpu->instruction = _SM83InstructionRST ## VEC ## UpdateSPH;) DEFINE_RST_INSTRUCTION_SM83(00); DEFINE_RST_INSTRUCTION_SM83(08); DEFINE_RST_INSTRUCTION_SM83(10); DEFINE_RST_INSTRUCTION_SM83(18); DEFINE_RST_INSTRUCTION_SM83(20); DEFINE_RST_INSTRUCTION_SM83(28); DEFINE_RST_INSTRUCTION_SM83(30); DEFINE_RST_INSTRUCTION_SM83(38); DEFINE_INSTRUCTION_SM83(ILL, cpu->irqh.hitIllegal(cpu)); DEFINE_INSTRUCTION_SM83(STOP2, cpu->irqh.stop(cpu)); DEFINE_INSTRUCTION_SM83(STOP, \ cpu->executionState = SM83_CORE_READ_PC; \ cpu->instruction = _SM83InstructionSTOP2;) static const SM83Instruction _sm83CBInstructionTable[0x100] = { DECLARE_SM83_CB_EMITTER_BLOCK(_SM83Instruction) }; DEFINE_INSTRUCTION_SM83(CBDelegate, _sm83CBInstructionTable[cpu->bus](cpu)) DEFINE_INSTRUCTION_SM83(CB, \ cpu->executionState = SM83_CORE_READ_PC; \ cpu->instruction = _SM83InstructionCBDelegate;) const SM83Instruction _sm83InstructionTable[0x100] = { DECLARE_SM83_EMITTER_BLOCK(_SM83Instruction) };