#include "cpu.h" void Cpu_state::setAF(u16 v) { A = (u8)(v >> 8); zero = (v & 0x80 != 0); subtract = (v & 0x40 != 0); halfcarry = (v & 0x20 != 0); carry = (v & 0x10 != 0); } u16 Cpu_state::getAF() { return ((u16)A << 8) | (zero ? 0x80 : 0) | (subtract ? 0x40 : 0) | (halfcarry ? 0x20 : 0) | (carry ? 0x10 : 0); } Cpu::Cpu(Mem_device* bus) : bus(bus) { reset(); } void Cpu::step() { handleInterrupts(); executeInstruction(); } void Cpu::reset() { state.BC = 0; state.DE = 0; state.HL = 0; state.A = 0; state.SP = 0; state.PC = 0; state.zero = false; state.subtract = false; state.halfcarry = false; state.carry = false; state.IME = IME_OFF; state.IE = 0; state.IF = 0; } u8 Cpu::readPC8() { u8 data = bus->read8(state.PC); state.PC++; return data; } u16 Cpu::readPC16() { u16 data = bus->read16(state.PC); state.PC+=2; return data; } void Cpu::pushStack8(u8 data) { bus->write8(state.SP, data); state.SP--; } u8 Cpu::popStack8() { u8 data = bus->read8(state.SP); state.SP++; return data; } void Cpu::pushStack16(u16 data) { bus->write16(state.SP,data); state.SP-=2; } u16 Cpu::popStack16() { u16 data = bus->read16(state.SP); state.SP+=2; return data; } void Cpu::doCall(u16 target) { pushStack16(state.PC); state.PC = target; } void Cpu::doRet() { state.PC = popStack16(); } bool Cpu::decodeCond(u8 cc) { switch(cc) { case COND_NZ: return !state.zero; break; case COND_Z: return state.zero; break; case COND_NC: return !state.carry; break; case COND_C: return state.carry; break; } return false; } void Cpu::aluop8(AluOp op, u8 lhs, u8 rhs, u8& out, bool update_carry) { u16 rhs16 = rhs; u16 res16; u8 res; if ((op == ADC || op == SBC) && state.carry) rhs16++; u16 lhs_lower = lhs & 0x0F; u16 lhs_upper = lhs & 0xF0; u16 rhs_lower = rhs16 & 0x0F; u16 rhs_upper = rhs16 & 0x1F0; switch(op) { case ADD: case ADC: res16 = lhs_lower + rhs_lower; break; case SUB: case SBC: case CP: res16 = lhs_lower - rhs_lower; break; case AND: res16 = lhs_lower & rhs_lower; break; case OR: res16 = lhs_lower | rhs_lower; break; case XOR: res16 = lhs_lower ^ rhs_lower; break; } state.halfcarry = (res16 & 0x10 != 0) || op == AND; state.subtract = (op == SUB) || (op == SBC) || (op == CP); switch(op) { case ADD: case ADC: res16 += lhs_upper + rhs_upper; break; case SUB: case SBC: case CP: res16 += lhs_upper - rhs_upper; break; case AND: res16 |= lhs_upper & rhs_upper; break; case OR: res16 |= lhs_upper | rhs_upper; break; case XOR: res16 |= lhs_upper ^ rhs_upper; break; } res = (u8)(res16 & 0xFF); if(update_carry) state.carry = (res16 & 0x100 != 0); state.zero = (res == 0); if (op != CP) out = res; } void Cpu::handleInterrupts() { // servicable interrupts (assuming IME is on) u8 si = state.IE & state.IF & INT_MASK; if (state.IME == IME_SCHEDULED) state.IME = IME_DELAYED; else if (state.IME == IME_DELAYED) state.IME = IME_ON; else if (state.IME == IME_ON && si != 0) { u16 isr; InterruptType it; if (si & INT_VBlank) { it = INT_VBlank; isr = 0x40; } else if (si & INT_LCDSTAT) { it = INT_LCDSTAT; isr = 0x48; } else if (si & INT_Timer) { it = INT_Timer; isr = 0x50; } else if (si & INT_Serial) { it = INT_Serial; isr = 0x58; } else if (si & INT_Joypad) { it = INT_Joypad; isr = 0x60; } state.IME = IME_OFF; // Disable IME state.IF &= ~it; // clear interrupt in IF doCall(isr); // Call interrupt service routine processed_mcycles += 5; } }