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
}
Exemple #2
0
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();
        }
    }
}