void asm_S9xOpcode_IRQ(void) { #ifdef __debug_c_irq__ printf("irq\n"); #endif // S9xUnpackStatus(); // not needed if (!CheckEmulation()) { PushB (Registers.PB); PushW (CPU.PC - CPU.PCBase); // S9xPackStatus (); // not needed PushB (Registers.PL); ClearDecimal (); SetIRQ (); Registers.PB = 0; // ICPU.ShiftedPB = 0; // unused #ifdef USE_SA1 if (Settings.SA1 && (Memory.FillRAM [0x2209] & 0x40)) S9xSetPCBase (Memory.FillRAM [0x220e] | (Memory.FillRAM [0x220f] << 8)); else #endif S9xSetPCBase (S9xGetWord (0xFFEE)); #ifdef VAR_CYCLES CPU.Cycles += TWO_CYCLES; #else CPU.Cycles += 8; #endif } else { PushW (CPU.PC - CPU.PCBase); // S9xPackStatus (); // not needed PushB (Registers.PL); ClearDecimal (); SetIRQ (); Registers.PB = 0; // ICPU.ShiftedPB = 0; // unused #ifdef USE_SA1 if (Settings.SA1 && (Memory.FillRAM [0x2209] & 0x40)) S9xSetPCBase (Memory.FillRAM [0x220e] | (Memory.FillRAM [0x220f] << 8)); else #endif S9xSetPCBase (S9xGetWord (0xFFFE)); #ifdef VAR_CYCLES CPU.Cycles += ONE_CYCLE; #else CPU.Cycles += 6; #endif } // S9xPackStatus(); // not needed }
void NewCpu::Step() { if (_stealCycles > 0) { _stealCycles--; } else if (_dmaCycles > 0) { if (_dmaCycles % 2 == 0) { _value = loadb(_dmaAddr++); } else { storeb(0x2004, _value); } _dmaCycles--; if (_dmaCycles == 0) { _dmaAddr = 0; EndInstr(); } } else if (_cycle == 0) { if (_wantNmi) { _type = InstrType::NMI; _wantNmi = false; _cycle = 1; } else if (_wantIrq && !_regs.GetFlag(Flag::IRQ)) { _type = InstrType::IRQ; _wantIrq = false; _cycle = 1; } else { #if defined(TRACE) Trace(); #endif _op = LoadBBumpPC(); Decode(); _cycle = 1; } } else { switch (_type) { case InstrType::BRK: switch (_cycle) { case 1: LoadBBumpPC(); _cycle++; break; case 2: PushB(_regs.PC.B.H); _cycle++; break; case 3: PushB(_regs.PC.B.L); _cycle++; break; case 4: PushB(_regs.P | (u8)Flag::Break | (u8)Flag::Unused); _cycle++; break; case 5: _regs.PC.B.L = loadb(IRQ_VECTOR); _cycle++; break; case 6: _regs.PC.B.H = loadb(IRQ_VECTOR + 1); _regs.SetFlag(Flag::IRQ, true); EndInstr(); break; } break; case InstrType::NMI: switch (_cycle) { case 1: _cycle++; break; case 2: PushB(_regs.PC.B.H); _cycle++; break; case 3: PushB(_regs.PC.B.L); _cycle++; break; case 4: PushB(_regs.P); _cycle++; break; case 5: _regs.PC.B.L = loadb(NMI_VECTOR); _cycle++; break; case 6: _regs.PC.B.H = loadb(NMI_VECTOR + 1); EndInstr(); break; } break; case InstrType::IRQ: switch (_cycle) { case 1: _cycle++; break; case 2: PushB(_regs.PC.B.H); _cycle++; break; case 3: PushB(_regs.PC.B.L); _cycle++; break; case 4: PushB(_regs.P); _cycle++; break; case 5: _regs.PC.B.L = loadb(IRQ_VECTOR); _cycle++; break; case 6: _regs.PC.B.H = loadb(IRQ_VECTOR + 1); _regs.SetFlag(Flag::IRQ, true); EndInstr(); break; } break; case InstrType::RTI: switch (_cycle) { case 1: loadb(_regs.PC.W); _cycle++; break; case 2: _regs.SP++; _cycle++; break; case 3: _regs.P = loadb(0x100 | _regs.SP++); _cycle++; break; case 4: _regs.PC.B.L = loadb(0x100 | _regs.SP++); _cycle++; break; case 5: _regs.PC.B.H = loadb(0x100 | _regs.SP); EndInstr(); break; } break; case InstrType::RTS: switch (_cycle) { case 1: loadb(_regs.PC.W); _cycle++; break; case 2: _regs.SP++; _cycle++; break; case 3: _regs.PC.B.L = loadb(0x100 | _regs.SP++); _cycle++; break; case 4: _regs.PC.B.H = loadb(0x100 | _regs.SP); _cycle++; break; case 5: _regs.PC.W++; EndInstr(); break; } break; case InstrType::PHAorPHP: switch (_cycle) { case 1: loadb(_regs.PC.W); _cycle++; break; case 2: if (_pIdxReg == &_regs.P) { PushB(*_pIdxReg | (u8)Flag::Break | (u8)Flag::Unused); } else { PushB(*_pIdxReg); } EndInstr(); break; } break; case InstrType::PLAorPLP: switch (_cycle) { case 1: loadb(_regs.PC.W); _cycle++; break; case 2: _regs.SP++; _cycle++; break; case 3: *_pIdxReg = loadb(0x100 | _regs.SP); if (_pIdxReg == &_regs.A) { _regs.SetZN(_regs.A); } EndInstr(); break; } break; case InstrType::JSR: switch (_cycle) { case 1: _value = LoadBBumpPC(); _cycle++; break; case 2: _cycle++; break; case 3: PushB(_regs.PC.B.H); _cycle++; break; case 4: PushB(_regs.PC.B.L); _cycle++; break; case 5: _regs.PC.B.H = loadb(_regs.PC.W); _regs.PC.B.L = _value; EndInstr(); break; } break; case InstrType::Implied: loadb(_regs.PC.W); // throwaway read (*this.*_action)(); EndInstr(); break; case InstrType::Accumulator: loadb(_regs.PC.W); _value = _regs.A; (*this.*_action)(); _regs.A = _value; EndInstr(); break; case InstrType::Immediate: _value = LoadBBumpPC(); (*this.*_action)(); EndInstr(); break; case InstrType::AbsoluteJmp: switch (_cycle) { case 1: _value = LoadBBumpPC(); _cycle++; break; case 2: _regs.PC.B.H = LoadBBumpPC(); _regs.PC.B.L = _value; EndInstr(); break; } break; case InstrType::AbsoluteRead: switch (_cycle) { case 1: _addr.B.L = LoadBBumpPC(); _cycle++; break; case 2: _addr.B.H = LoadBBumpPC(); _cycle++; break; case 3: _value = loadb(_addr.W); (*this.*_action)(); EndInstr(); break; } break; case InstrType::AbsoluteRMW: switch (_cycle) { case 1: _addr.B.L = LoadBBumpPC(); _cycle++; break; case 2: _addr.B.H = LoadBBumpPC(); _cycle++; break; case 3: _value = loadb(_addr.W); _cycle++; break; case 4: storeb(_addr.W, _value); (*this.*_action)(); _cycle++; break; case 5: storeb(_addr.W, _value); EndInstr(); break; } break; case InstrType::AbsoluteWrite: switch (_cycle) { case 1: _addr.B.L = LoadBBumpPC(); _cycle++; break; case 2: _addr.B.H = LoadBBumpPC(); _cycle++; break; case 3: (*this.*_action)(); EndInstr(); break; } break; case InstrType::ZPRead: switch (_cycle) { case 1: _addr.W = (u16)LoadBBumpPC(); _cycle++; break; case 2: _value = loadb(_addr.W); (*this.*_action)(); EndInstr(); break; } break; case InstrType::ZPRMW: switch (_cycle) { case 1: _addr.W = (u16)LoadBBumpPC(); _cycle++; break; case 2: _value = loadb(_addr.W); _cycle++; break; case 3: storeb(_addr.W, _value); (*this.*_action)(); _cycle++; break; case 4: storeb(_addr.W, _value); EndInstr(); break; } break; case InstrType::ZPWRite: switch (_cycle) { case 1: _addr.W = (u16)LoadBBumpPC(); _cycle++; break; case 2: (*this.*_action)(); EndInstr(); break; } break; case InstrType::ZPIndexedRead: switch (_cycle) { case 1: _addr.W = (u16)LoadBBumpPC(); _cycle++; break; case 2: loadb(_addr.W); _addr.B.L = (u8)(_addr.B.L + *_pIdxReg); _cycle++; break; case 3: _value = loadb(_addr.W); (*this.*_action)(); EndInstr(); break; } break; case InstrType::ZPIndexedRMW: switch (_cycle) { case 1: _addr.W = (u16)LoadBBumpPC(); _cycle++; break; case 2: loadb(_addr.W); _addr.B.L = (u8)(_addr.B.L + _regs.X); _cycle++; break; case 3: _value = loadb(_addr.W); _cycle++; break; case 4: storeb(_addr.W, _value); (*this.*_action)(); _cycle++; break; case 5: storeb(_addr.W, _value); EndInstr(); break; } break; case InstrType::ZPIndexedWrite: switch (_cycle) { case 1: _addr.W = (u16)LoadBBumpPC(); _cycle++; break; case 2: loadb(_addr.W); _addr.B.L = (u8)(_addr.B.L + *_pIdxReg); _cycle++; break; case 3: (*this.*_action)(); EndInstr(); break; } break; case InstrType::AbsoluteIndexedRead: switch (_cycle) { case 1: _addr.B.L = LoadBBumpPC(); _cycle++; break; case 2: _addr.B.H = LoadBBumpPC(); Pair newAddr; newAddr.W = (u16)_addr.B.L + (u16)*_pIdxReg; _addr.B.L = newAddr.B.L; _pageCross = newAddr.B.H != 0; _cycle++; break; case 3: _value = loadb(_addr.W); if (_pageCross) { _addr.B.H++; _cycle++; } else { (*this.*_action)(); EndInstr(); } break; case 4: _value = loadb(_addr.W); (*this.*_action)(); EndInstr(); break; } break; case InstrType::AbsoluteIndexedRMW: switch (_cycle) { case 1: _addr.B.L = LoadBBumpPC(); _cycle++; break; case 2: _addr.B.H = LoadBBumpPC(); Pair newAddr; newAddr.W = (u16)_addr.B.L + (u16)_regs.X; _addr.B.L = newAddr.B.L; _pageCross = newAddr.B.H != 0; _cycle++; break; case 3: loadb(_addr.W); if (_pageCross) { _addr.B.H++; } _cycle++; break; case 4: _value = loadb(_addr.W); _cycle++; break; case 5: storeb(_addr.W, _value); (*this.*_action)(); _cycle++; break; case 6: storeb(_addr.W, _value); EndInstr(); break; } break; case InstrType::AbsoluteIndexedWrite: switch (_cycle) { case 1: _addr.B.L = LoadBBumpPC(); _cycle++; break; case 2: _addr.B.H = LoadBBumpPC(); Pair newAddr; newAddr.W = (u16)_addr.B.L + (u16)*_pIdxReg; _addr.B.L = newAddr.B.L; _pageCross = newAddr.B.H != 0; _cycle++; break; case 3: loadb(_addr.W); if (_pageCross) { _addr.B.H++; } _cycle++; break; case 4: (*this.*_action)(); EndInstr(); break; } break; case InstrType::Relative: switch (_cycle) { case 1: _value = LoadBBumpPC(); _cycle++; break; case 2: { u8 op = loadb(_regs.PC.W); (*this.*_action)(); if (_doBranch) { Pair newPC; newPC.W = (u16)((i32)(i16)_regs.PC.W + (i32)(i8)_value); _regs.PC.B.L = newPC.B.L; _pageCross = newPC.B.H != _regs.PC.B.H; _value = newPC.B.H; _cycle++; } else { EndInstr(); #if defined(TRACE) Trace(); #endif _op = op; _regs.PC.W++; Decode(); _cycle = 1; } } break; case 3: { u8 op = loadb(_regs.PC.W); if (_pageCross) { _regs.PC.B.H = _value; _cycle++; } else { EndInstr(); #if defined(TRACE) Trace(); #endif _op = op; _regs.PC.W++; Decode(); _cycle = 1; } } break; case 4: { #if defined(TRACE) Trace(); #endif _op = LoadBBumpPC(); Decode(); _cycle = 1; } break; } break; case InstrType::IndexedIndirectRead: switch (_cycle) { case 1: _value = LoadBBumpPC(); _cycle++; break; case 2: loadb(_value); _value += _regs.X; _cycle++; break; case 3: _addr.B.L = loadb(_value); _cycle++; break; case 4: _addr.B.H = loadb((u8)(_value + 1)); _cycle++; break; case 5: _value = loadb(_addr.W); (*this.*_action)(); EndInstr(); break; } break; case InstrType::IndexedIndirectRMW: switch (_cycle) { case 1: _value = LoadBBumpPC(); _cycle++; break; case 2: loadb(_value); _value += _regs.X; _cycle++; break; case 3: _addr.B.L = loadb(_value); _cycle++; break; case 4: _addr.B.H = loadb((u8)(_value + 1)); _cycle++; break; case 5: _value = loadb(_addr.W); _cycle++; break; case 6: storeb(_addr.W, _value); (*this.*_action)(); _cycle++; break; case 7: storeb(_addr.W, _value); EndInstr(); break; } break; case InstrType::IndexedIndirectWrite: switch (_cycle) { case 1: _value = LoadBBumpPC(); _cycle++; break; case 2: loadb(_value); _value += _regs.X; _cycle++; break; case 3: _addr.B.L = loadb(_value); _cycle++; break; case 4: _addr.B.H = loadb((u8)(_value + 1)); _cycle++; break; case 5: (*this.*_action)(); EndInstr(); break; } break; case InstrType::IndirectIndexedRead: switch (_cycle) { case 1: _value = LoadBBumpPC(); _cycle++; break; case 2: _addr.B.L = loadb(_value); _cycle++; break; case 3: _addr.B.H = loadb((u8)(_value + 1)); Pair newAddr; newAddr.W = (u16)_addr.B.L + (u16)_regs.Y; _addr.B.L = newAddr.B.L; _pageCross = newAddr.B.H != 0; _cycle++; break; case 4: _value = loadb(_addr.W); if (_pageCross) { _addr.B.H++; _cycle++; } else { (*this.*_action)(); EndInstr(); } break; case 5: _value = loadb(_addr.W); (*this.*_action)(); EndInstr(); break; } break; case InstrType::IndirectIndexedRMW: __debugbreak(); break; case InstrType::IndirectIndexedWrite: switch (_cycle) { case 1: _value = LoadBBumpPC(); _cycle++; break; case 2: _addr.B.L = loadb(_value); _cycle++; break; case 3: _addr.B.H = loadb((u8)(_value + 1)); Pair newAddr; newAddr.W = (u16)_addr.B.L + (u16)_regs.Y; _addr.B.L = newAddr.B.L; _pageCross = newAddr.B.H != 0; _cycle++; break; case 4: loadb(_addr.W); if (_pageCross) { _addr.B.H++; } _cycle++; break; case 5: (*this.*_action)(); EndInstr(); break; } break; case InstrType::AbsoluteIndirectJmp: switch (_cycle) { case 1: _addr.B.L = LoadBBumpPC(); _cycle++; break; case 2: _addr.B.H = LoadBBumpPC(); _cycle++; break; case 3: _value = loadb(_addr.W); _cycle++; break; case 4: _addr.B.L = u8(_addr.B.L + 1); _regs.PC.B.L = _value; _regs.PC.B.H = loadb(_addr.W); EndInstr(); break; } break; default: __debugbreak(); } } }