Files
DbNesEmulator/nescorelib/emu/cpu.cpp
2018-12-16 22:19:06 +01:00

1269 lines
31 KiB
C++

#include "cpu.h"
// Qt includes
#include <QDataStream>
// local includes
#include "nesemulator.h"
Cpu::Cpu(NesEmulator &emu) :
m_emu(emu)
{
}
quint8 Cpu::getRegisterP() const
{
return (m_flagN ? 0x80 : 0) |
(m_flagV ? 0x40 : 0) |
(m_flagD ? 0x08 : 0) |
(m_flagI ? 0x04 : 0) |
(m_flagZ ? 0x02 : 0) |
(m_flagC ? 0x01 : 0) | 0x20;
}
void Cpu::setRegisterP(const quint8 value)
{
m_flagN = value & 0x80;
m_flagV = value & 0x40;
m_flagD = value & 0x08;
m_flagI = value & 0x04;
m_flagZ = value & 0x02;
m_flagC = value & 0x01;
}
quint8 Cpu::getRegisterPb() const
{
return (m_flagN ? 0x80 : 0) |
(m_flagV ? 0x40 : 0) |
(m_flagD ? 0x08 : 0) |
(m_flagI ? 0x04 : 0) |
(m_flagZ ? 0x02 : 0) |
(m_flagC ? 0x01 : 0) | 0x30;
}
void Cpu::clock()
{
static constexpr std::array<void (Cpu::*)(), 256> cpuAddressings {
// 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7
// 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF
/*0x0*/&Cpu::imp____, &Cpu::indX_r_, &Cpu::imA____, &Cpu::indX_w_, &Cpu::zpg_r__, &Cpu::zpg_r__, &Cpu::zpg_rw_, &Cpu::zpg_w__,
&Cpu::imA____, &Cpu::imm____, &Cpu::imA____, &Cpu::imm____, &Cpu::abs_r__, &Cpu::abs_r__, &Cpu::abs_rw_, &Cpu::abs_w__, // 0x0
/*0x1*/&Cpu::imp____, &Cpu::indY_r_, &Cpu::imp____, &Cpu::indY_w_, &Cpu::zpgX_r_, &Cpu::zpgX_r_, &Cpu::zpgX_rw, &Cpu::zpgX_w_,
&Cpu::imA____, &Cpu::absY_r_, &Cpu::imA____, &Cpu::absY_w_, &Cpu::absX_r_, &Cpu::absX_r_, &Cpu::absX_rw, &Cpu::absX_w_, // 0x1
/*0x2*/&Cpu::imp____, &Cpu::indX_r_, &Cpu::imA____, &Cpu::indX_w_, &Cpu::zpg_r__, &Cpu::zpg_r__, &Cpu::zpg_rw_, &Cpu::zpg_w__,
&Cpu::imA____, &Cpu::imm____, &Cpu::imA____, &Cpu::imm____, &Cpu::abs_r__, &Cpu::abs_r__, &Cpu::abs_rw_, &Cpu::abs_w__, // 0x2
/*0x3*/&Cpu::imp____, &Cpu::indY_r_, &Cpu::imp____, &Cpu::indY_w_, &Cpu::zpgX_r_, &Cpu::zpgX_r_, &Cpu::zpgX_rw, &Cpu::zpgX_w_,
&Cpu::imA____, &Cpu::absY_r_, &Cpu::imA____, &Cpu::absY_w_, &Cpu::absX_r_, &Cpu::absX_r_, &Cpu::absX_rw, &Cpu::absX_w_, // 0x3
/*0x4*/&Cpu::imA____, &Cpu::indX_r_, &Cpu::imA____, &Cpu::indX_w_, &Cpu::zpg_r__, &Cpu::zpg_r__, &Cpu::zpg_rw_, &Cpu::zpg_w__,
&Cpu::imA____, &Cpu::imm____, &Cpu::imA____, &Cpu::imm____, &Cpu::abs_w__, &Cpu::abs_r__, &Cpu::abs_rw_, &Cpu::abs_w__, // 0x4
/*0x5*/&Cpu::imp____, &Cpu::indY_r_, &Cpu::imp____, &Cpu::indY_w_, &Cpu::zpgX_r_, &Cpu::zpgX_r_, &Cpu::zpgX_rw, &Cpu::zpgX_w_,
&Cpu::imA____, &Cpu::absY_r_, &Cpu::imA____, &Cpu::absY_w_, &Cpu::absX_r_, &Cpu::absX_r_, &Cpu::absX_rw, &Cpu::absX_w_, // 0x5
/*0x6*/&Cpu::imA____, &Cpu::indX_r_, &Cpu::imA____, &Cpu::indX_w_, &Cpu::zpg_r__, &Cpu::zpg_r__, &Cpu::zpg_rw_, &Cpu::zpg_w__,
&Cpu::imA____, &Cpu::imm____, &Cpu::imA____, &Cpu::imm____, &Cpu::imp____, &Cpu::abs_r__, &Cpu::abs_rw_, &Cpu::abs_w__, // 0x6
/*0x7*/&Cpu::imp____, &Cpu::indY_r_, &Cpu::imp____, &Cpu::indY_w_, &Cpu::zpgX_r_, &Cpu::zpgX_r_, &Cpu::zpgX_rw, &Cpu::zpgX_w_,
&Cpu::imA____, &Cpu::absY_r_, &Cpu::imA____, &Cpu::absY_w_, &Cpu::absX_r_, &Cpu::absX_r_, &Cpu::absX_rw, &Cpu::absX_w_, // 0x7
/*0x8*/&Cpu::imm____, &Cpu::indX_w_, &Cpu::imm____, &Cpu::indX_w_, &Cpu::zpg_w__, &Cpu::zpg_w__, &Cpu::zpg_w__, &Cpu::zpg_w__,
&Cpu::imA____, &Cpu::imm____, &Cpu::imA____, &Cpu::imm____, &Cpu::abs_w__, &Cpu::abs_w__, &Cpu::abs_w__, &Cpu::abs_w__, // 0x8
/*0x9*/&Cpu::imp____, &Cpu::indY_w_, &Cpu::imp____, &Cpu::indY_w_, &Cpu::zpgX_w_, &Cpu::zpgX_w_, &Cpu::zpgY_w_, &Cpu::zpgY_w_,
&Cpu::imA____, &Cpu::absY_w_, &Cpu::imA____, &Cpu::absY_w_, &Cpu::abs_w__, &Cpu::absX_w_, &Cpu::abs_w__, &Cpu::absY_w_, // 0x9
/*0xA*/&Cpu::imm____, &Cpu::indX_r_, &Cpu::imm____, &Cpu::indX_r_, &Cpu::zpg_r__, &Cpu::zpg_r__, &Cpu::zpg_r__, &Cpu::zpg_r__,
&Cpu::imA____, &Cpu::imm____, &Cpu::imA____, &Cpu::imm____, &Cpu::abs_r__, &Cpu::abs_r__, &Cpu::abs_r__, &Cpu::abs_r__, // 0xA
/*0xB*/&Cpu::imp____, &Cpu::indY_r_, &Cpu::imp____, &Cpu::indY_r_, &Cpu::zpgX_r_, &Cpu::zpgX_r_, &Cpu::zpgY_r_, &Cpu::zpgY_r_,
&Cpu::imA____, &Cpu::absY_r_, &Cpu::imA____, &Cpu::absY_r_, &Cpu::absX_r_, &Cpu::absX_r_, &Cpu::absY_r_, &Cpu::absY_r_, // 0xB
/*0xC*/&Cpu::imm____, &Cpu::indX_r_, &Cpu::imm____, &Cpu::indX_r_, &Cpu::zpg_r__, &Cpu::zpg_r__, &Cpu::zpg_rw_, &Cpu::zpg_r__,
&Cpu::imA____, &Cpu::imm____, &Cpu::imA____, &Cpu::imm____, &Cpu::abs_r__, &Cpu::abs_r__, &Cpu::abs_rw_, &Cpu::abs_r__, // 0xC
/*0xD*/&Cpu::imp____, &Cpu::indY_r_, &Cpu::imp____, &Cpu::indY_rw, &Cpu::zpgX_r_, &Cpu::zpgX_r_, &Cpu::zpgX_rw, &Cpu::zpgX_rw,
&Cpu::imA____, &Cpu::absY_r_, &Cpu::imA____, &Cpu::absY_rw, &Cpu::absX_r_, &Cpu::absX_r_, &Cpu::absX_rw, &Cpu::absX_rw, // 0xD
/*0xE*/&Cpu::imm____, &Cpu::indX_r_, &Cpu::imm____, &Cpu::indX_w_, &Cpu::zpg_r__, &Cpu::zpg_r__, &Cpu::zpg_rw_, &Cpu::zpg_w__,
&Cpu::imA____, &Cpu::imm____, &Cpu::imA____, &Cpu::imm____, &Cpu::abs_r__, &Cpu::abs_r__, &Cpu::abs_rw_, &Cpu::abs_w__, // 0xE
/*0xF*/&Cpu::imp____, &Cpu::indY_r_, &Cpu::imp____, &Cpu::indY_w_, &Cpu::zpgX_r_, &Cpu::zpgX_r_, &Cpu::zpgX_rw, &Cpu::zpgX_w_,
&Cpu::imA____, &Cpu::absY_r_, &Cpu::imA____, &Cpu::absY_w_, &Cpu::absX_r_, &Cpu::absX_r_, &Cpu::absX_rw, &Cpu::absX_w_, // 0xF
};
static constexpr std::array<void (Cpu::*)(), 256> cpuInstructions {
// 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7
// 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF
/*0x0*/&Cpu::brk__, &Cpu::ora__, &Cpu::nop__, &Cpu::slo__, &Cpu::nop__, &Cpu::ora__, &Cpu::asl_m, &Cpu::slo__,
&Cpu::php__, &Cpu::ora__, &Cpu::asl_a, &Cpu::anc__, &Cpu::nop__, &Cpu::ora__, &Cpu::asl_m, &Cpu::slo__, // 0x0
/*0x1*/&Cpu::bpl__, &Cpu::ora__, &Cpu::nop__, &Cpu::slo__, &Cpu::nop__, &Cpu::ora__, &Cpu::asl_m, &Cpu::slo__,
&Cpu::clc__, &Cpu::ora__, &Cpu::nop__, &Cpu::slo__, &Cpu::nop__, &Cpu::ora__, &Cpu::asl_m, &Cpu::slo__, // 0x1
/*0x2*/&Cpu::jsr__, &Cpu::and__, &Cpu::nop__, &Cpu::rla__, &Cpu::bit__, &Cpu::and__, &Cpu::rol_m, &Cpu::rla__,
&Cpu::plp__, &Cpu::and__, &Cpu::rol_a, &Cpu::anc__, &Cpu::bit__, &Cpu::and__, &Cpu::rol_m, &Cpu::rla__, // 0x2
/*0x3*/&Cpu::bmi__, &Cpu::and__, &Cpu::nop__, &Cpu::rla__, &Cpu::nop__, &Cpu::and__, &Cpu::rol_m, &Cpu::rla__,
&Cpu::sec__, &Cpu::and__, &Cpu::nop__, &Cpu::rla__, &Cpu::nop__, &Cpu::and__, &Cpu::rol_m, &Cpu::rla__, // 0x3
/*0x4*/&Cpu::rti__, &Cpu::eor__, &Cpu::nop__, &Cpu::sre__, &Cpu::nop__, &Cpu::eor__, &Cpu::lsr_m, &Cpu::sre__,
&Cpu::pha__, &Cpu::eor__, &Cpu::lsr_a, &Cpu::alr__, &Cpu::jmp__, &Cpu::eor__, &Cpu::lsr_m, &Cpu::sre__, // 0x4
/*0x5*/&Cpu::bvm__, &Cpu::eor__, &Cpu::nop__, &Cpu::sre__, &Cpu::nop__, &Cpu::eor__, &Cpu::lsr_m, &Cpu::sre__,
&Cpu::cli__, &Cpu::eor__, &Cpu::nop__, &Cpu::sre__, &Cpu::nop__, &Cpu::eor__, &Cpu::lsr_m, &Cpu::sre__, // 0x5
/*0x6*/&Cpu::rts__, &Cpu::adc__, &Cpu::nop__, &Cpu::rra__, &Cpu::nop__, &Cpu::adc__, &Cpu::ror_m, &Cpu::rra__,
&Cpu::pla__, &Cpu::adc__, &Cpu::ror_a, &Cpu::arr__, &Cpu::jmp_i, &Cpu::adc__, &Cpu::ror_m, &Cpu::rra__, // 0x6
/*0x7*/&Cpu::bvs__, &Cpu::adc__, &Cpu::nop__, &Cpu::rra__, &Cpu::nop__, &Cpu::adc__, &Cpu::ror_m, &Cpu::rra__,
&Cpu::sei__, &Cpu::adc__, &Cpu::nop__, &Cpu::rra__, &Cpu::nop__, &Cpu::adc__, &Cpu::ror_m, &Cpu::rra__, // 0x7
/*0x8*/&Cpu::nop__, &Cpu::sta__, &Cpu::nop__, &Cpu::sax__, &Cpu::sty__, &Cpu::sta__, &Cpu::stx__, &Cpu::sax__,
&Cpu::dey__, &Cpu::nop__, &Cpu::txa__, &Cpu::xaa__, &Cpu::sty__, &Cpu::sta__, &Cpu::stx__, &Cpu::sax__, // 0x8
/*0x9*/&Cpu::bcc__, &Cpu::sta__, &Cpu::nop__, &Cpu::ahc__, &Cpu::sty__, &Cpu::sta__, &Cpu::stx__, &Cpu::sax__,
&Cpu::tya__, &Cpu::sta__, &Cpu::txs__, &Cpu::xas__, &Cpu::shy__, &Cpu::sta__, &Cpu::shx__, &Cpu::ahc__, // 0x9
/*0xA*/&Cpu::ldy__, &Cpu::lda__, &Cpu::ldx__, &Cpu::lax__, &Cpu::ldy__, &Cpu::lda__, &Cpu::ldx__, &Cpu::lax__,
&Cpu::tay__, &Cpu::lda__, &Cpu::tax__, &Cpu::lax__, &Cpu::ldy__, &Cpu::lda__, &Cpu::ldx__, &Cpu::lax__, // 0xA
/*0xB*/&Cpu::bcs__, &Cpu::lda__, &Cpu::nop__, &Cpu::lax__, &Cpu::ldy__, &Cpu::lda__, &Cpu::ldx__, &Cpu::lax__,
&Cpu::clv__, &Cpu::lda__, &Cpu::tsx__, &Cpu::lar__, &Cpu::ldy__, &Cpu::lda__, &Cpu::ldx__, &Cpu::lax__, // 0xB
/*0xC*/&Cpu::cpy__, &Cpu::cmp__, &Cpu::nop__, &Cpu::dcp__, &Cpu::cpy__, &Cpu::cmp__, &Cpu::dec__, &Cpu::dcp__,
&Cpu::iny__, &Cpu::cmp__, &Cpu::dex__, &Cpu::axs__, &Cpu::cpy__, &Cpu::cmp__, &Cpu::dec__, &Cpu::dcp__, // 0xC
/*0xD*/&Cpu::bne__, &Cpu::cmp__, &Cpu::nop__, &Cpu::dcp__, &Cpu::nop__, &Cpu::cmp__, &Cpu::dec__, &Cpu::dcp__,
&Cpu::cld__, &Cpu::cmp__, &Cpu::nop__, &Cpu::dcp__, &Cpu::nop__, &Cpu::cmp__, &Cpu::dec__, &Cpu::dcp__, // 0xD
/*0xE*/&Cpu::cpx__, &Cpu::sdc__, &Cpu::nop__, &Cpu::isc__, &Cpu::cpx__, &Cpu::sdc__, &Cpu::inc__, &Cpu::isc__,
&Cpu::inx__, &Cpu::sdc__, &Cpu::nop__, &Cpu::sdc__, &Cpu::cpx__, &Cpu::sdc__, &Cpu::inc__, &Cpu::isc__, // 0xE
/*0xF*/&Cpu::beq__, &Cpu::sdc__, &Cpu::nop__, &Cpu::isc__, &Cpu::nop__, &Cpu::sdc__, &Cpu::inc__, &Cpu::isc__,
&Cpu::sed__, &Cpu::sdc__, &Cpu::nop__, &Cpu::isc__, &Cpu::nop__, &Cpu::sdc__, &Cpu::inc__, &Cpu::isc__, // 0xF
};
m_opcode = m_emu.memory().read(m_regPc.v);
m_regPc.v++;
(this->*cpuAddressings[m_opcode])();
(this->*cpuInstructions[m_opcode])();
//handle interrupts
if(m_irqPin || m_nmiPin)
{
m_emu.memory().read(m_regPc.v);
m_emu.memory().read(m_regPc.v);
interrupt();
}
}
void Cpu::hardReset()
{
m_regA = 0;
m_regX = 0;
m_regY = 0;
m_regSp.v = 0x01FD;
m_regPc.l = m_emu.memory().board()->readPrg(0xFFFC);
m_regPc.h = m_emu.memory().board()->readPrg(0xFFFD);
setRegisterP(0);
m_flagI = true;
m_regEa.v = 0;
m_opcode = 0;
//interrupts
m_irqPin = false;
m_nmiPin = false;
m_suspendNmi = false;
m_suspendIrq = false;
m_emu.interrupts().setFlags(0);
}
void Cpu::softReset()
{
m_flagI = true;
m_regSp.v -= 3;
m_regPc.l = m_emu.memory().board()->readPrg(0xFFFC);
m_regPc.h = m_emu.memory().board()->readPrg(0xFFFD);
}
void Cpu::interrupt()
{
push(m_regPc.h);
push(m_regPc.l);
push(m_opcode == 0 ? getRegisterPb() : getRegisterP());
// pins are detected during φ2 of previous cycle (before push about 2 ppu
// cycles)
const auto temp = m_emu.interrupts().vector();
// THEORY:
// Once the vector requested, the interrupts are suspended and cleared
// by setting the I flag and clearing the nmi detect flag. Also, the nmi
// detection get suspended for 2 cycles while pulling PC, irq still can
// be detected but will not be taken since I is set.
m_suspendNmi = true;
m_flagI = true;
m_nmiPin = false;
m_regPc.l = m_emu.memory().read(temp);
m_regPc.h = m_emu.memory().read(temp + 1);
m_suspendNmi = false;
}
void Cpu::branch(const bool condition)
{
const auto temp = m_emu.memory().read(m_regPc.v++);
if (condition) {
m_suspendIrq = true;
m_emu.memory().read(m_regPc.v);
m_regPc.l += temp;
m_suspendIrq = false;
if (temp >= 0x80) {
if (m_regPc.l >= temp) {
m_emu.memory().read(m_regPc.v);
m_regPc.h--;
}
} else {
if (m_regPc.l < temp) {
m_emu.memory().read(m_regPc.v);
m_regPc.h++;
}
}
}
}
void Cpu::push(const quint8 value)
{
m_emu.memory().write(m_regSp.v--, value);
}
quint8 Cpu::_pull()
{
return m_emu.memory().read(++m_regSp.v);
}
quint8 Cpu::pull()
{
auto result = _pull();
return result;
}
void Cpu::imp____()
{
// No addressing mode ...
}
void Cpu::indX_r_()
{
CpuRegister temp;
temp.h = 0;// the zero page boundary crossing is not handled.
temp.l = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// CLock 1
m_emu.memory().read(temp.v);// Clock 2
temp.l += m_regX;
m_regEa.l = m_emu.memory().read(temp.v);// Clock 3
temp.l++;
m_regEa.h = m_emu.memory().read(temp.v);// Clock 4
m_m = m_emu.memory().read(m_regEa.v);
}
void Cpu::indX_w_()
{
CpuRegister temp;
temp.h = 0;// the zero page boundary crossing is not handled.
temp.l = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// CLock 1
m_emu.memory().read(temp.v);// Clock 2
temp.l += m_regX;
m_regEa.l = m_emu.memory().read(temp.v);// Clock 3
temp.l++;
m_regEa.h = m_emu.memory().read(temp.v);// Clock 4
}
void Cpu::indX_rw()
{
CpuRegister temp;
temp.h = 0;// the zero page boundary crossing is not handled.
temp.l = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// CLock 1
m_emu.memory().read(temp.v);// Clock 2
temp.l += m_regX;
m_regEa.l = m_emu.memory().read(temp.v);// Clock 3
temp.l++;
m_regEa.h = m_emu.memory().read(temp.v);// Clock 4
m_m = m_emu.memory().read(m_regEa.v);
}
void Cpu::indY_r_()
{
CpuRegister temp;
temp.h = 0;// the zero page boundary crossing is not handled.
temp.l = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// CLock 1
m_regEa.l = m_emu.memory().read(temp.v);// Clock 3
temp.l++;// Clock 2
m_regEa.h = m_emu.memory().read(temp.v);// Clock 4
m_regEa.l += m_regY;
m_m = m_emu.memory().read(m_regEa.v);
if (m_regEa.l < m_regY)
{
m_regEa.h++;
m_m = m_emu.memory().read(m_regEa.v);
}
}
void Cpu::indY_w_()
{
CpuRegister temp;
temp.h = 0;// the zero page boundary crossing is not handled.
temp.l = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// CLock 1
m_regEa.l = m_emu.memory().read(temp.v);
temp.l++;// Clock 2
m_regEa.h = m_emu.memory().read(temp.v);// Clock 2
m_regEa.l += m_regY;
m_m = m_emu.memory().read(m_regEa.v);// Clock 3
if (m_regEa.l < m_regY)
m_regEa.h++;
}
void Cpu::indY_rw()
{
CpuRegister temp;
temp.h = 0;// the zero page boundary crossing is not handled.
temp.l = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// CLock 1
m_regEa.l = m_emu.memory().read(temp.v);
temp.l++;// Clock 2
m_regEa.h = m_emu.memory().read(temp.v);// Clock 2
m_regEa.l += m_regY;
m_emu.memory().read(m_regEa.v);// Clock 3
if (m_regEa.l < m_regY)
m_regEa.h++;
m_m = m_emu.memory().read(m_regEa.v);// Clock 3
}
void Cpu::zpg_r__()
{
m_regEa.h = 0;
m_regEa.l = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// Clock 1
m_m = m_emu.memory().read(m_regEa.v);// Clock 3
}
void Cpu::zpg_w__()
{
m_regEa.h = 0;
m_regEa.l = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// Clock 1
}
void Cpu::zpg_rw_()
{
m_regEa.h = 0;
m_regEa.l = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// Clock 1
m_m = m_emu.memory().read(m_regEa.v);// Clock 3
}
void Cpu::zpgX_r_()
{
m_regEa.h = 0;
m_regEa.l = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// Clock 1
m_emu.memory().read(m_regEa.v);// Clock 2
m_regEa.l += m_regX;
m_m = m_emu.memory().read(m_regEa.v);// Clock 3
}
void Cpu::zpgX_w_()
{
m_regEa.h = 0;
m_regEa.l = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// Clock 1
m_emu.memory().read(m_regEa.v);// Clock 2
m_regEa.l += m_regX;
}
void Cpu::zpgX_rw()
{
m_regEa.h = 0;
m_regEa.l = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// Clock 1
m_emu.memory().read(m_regEa.v);// Clock 2
m_regEa.l += m_regX;
m_m = m_emu.memory().read(m_regEa.v);// Clock 3
}
void Cpu::zpgY_r_()
{
m_regEa.h = 0;
m_regEa.l = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// Clock 1
m_emu.memory().read(m_regEa.v);// Clock 2
m_regEa.l += m_regY;
m_m = m_emu.memory().read(m_regEa.v);// Clock 3
}
void Cpu::zpgY_w_()
{
m_regEa.h = 0;
m_regEa.l = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// Clock 1
m_emu.memory().read(m_regEa.v);// Clock 2
m_regEa.l += m_regY;
}
void Cpu::zpgY_rw()
{
m_regEa.h = 0;
m_regEa.l = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// Clock 1
m_emu.memory().read(m_regEa.v);// Clock 2
m_regEa.l += m_regY;
m_m = m_emu.memory().read(m_regEa.v);// Clock 3
}
void Cpu::imm____()
{
m_m = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// Clock 1
}
void Cpu::imA____()
{
m_emu.memory().read(m_regPc.v);
}
void Cpu::abs_r__()
{
m_regEa.l = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// Clock 1
m_regEa.h = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// Clock 2
m_m = m_emu.memory().read(m_regEa.v);// Clock 3
}
void Cpu::abs_w__()
{
m_regEa.l = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// Clock 1
m_regEa.h = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// Clock 2
}
void Cpu::abs_rw_()
{
m_regEa.l = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// Clock 1
m_regEa.h = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// Clock 2
m_m = m_emu.memory().read(m_regEa.v);// Clock 3
}
void Cpu::absX_r_()
{
m_regEa.l = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// Clock 1
m_regEa.h = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// Clock 2
m_regEa.l += m_regX;
m_m = m_emu.memory().read(m_regEa.v);// Clock 3
if (m_regEa.l < m_regX)
{
m_regEa.h++;
m_m = m_emu.memory().read(m_regEa.v);// Clock 4
}
}
void Cpu::absX_w_()
{
m_regEa.l = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// Clock 1
m_regEa.h = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// Clock 2
m_regEa.l += m_regX;
m_m = m_emu.memory().read(m_regEa.v);// Clock 4
if (m_regEa.l < m_regX)
m_regEa.h++;
}
void Cpu::absX_rw()
{
m_regEa.l = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// Clock 1
m_regEa.h = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// Clock 2
m_regEa.l += m_regX;
m_emu.memory().read(m_regEa.v);// Clock 3
if (m_regEa.l < m_regX)
m_regEa.h++;
m_m = m_emu.memory().read(m_regEa.v);// Clock 4
}
void Cpu::absY_r_()
{
m_regEa.l = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// Clock 1
m_regEa.h = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// Clock 2
m_regEa.l += m_regY;
m_m = m_emu.memory().read(m_regEa.v);// Clock 4
if (m_regEa.l < m_regY)
{
m_regEa.h++;
m_m = m_emu.memory().read(m_regEa.v);// Clock 4
}
}
void Cpu::absY_w_()
{
m_regEa.l = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// Clock 1
m_regEa.h = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// Clock 2
m_regEa.l += m_regY;
m_m = m_emu.memory().read(m_regEa.v);// Clock 4
if (m_regEa.l < m_regY)
m_regEa.h++;
}
void Cpu::absY_rw()
{
m_regEa.l = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// Clock 1
m_regEa.h = m_emu.memory().read(m_regPc.v);
m_regPc.v++;// Clock 2
m_regEa.l += m_regY;
m_m = m_emu.memory().read(m_regEa.v);// Clock 4
if (m_regEa.l < m_regY)
m_regEa.h++;
m_m = m_emu.memory().read(m_regEa.v);// Clock 4
}
void Cpu::adc__()
{
const qint32 temp = m_regA + m_m + (m_flagC ? 1 : 0);
m_flagV = (temp ^ m_regA) & (temp ^ m_m) & 0x80;
m_flagN = temp & 0x80;
m_flagZ = (temp & 0xFF) == 0;
m_flagC = temp >> 0x8;
m_regA = temp;
}
void Cpu::ahc__()
{
m_emu.memory().write(m_regEa.v, m_regA & m_regX & 7);
}
void Cpu::alr__()
{
m_regA &= m_m;
m_flagC = m_regA & 0x01;
m_regA >>= 1;
m_flagN = m_regA & 0x80;
m_flagZ = m_regA == 0;
}
void Cpu::anc__()
{
m_regA &= m_m;
m_flagN = m_regA & 0x80;
m_flagZ = m_regA == 0;
m_flagC = m_regA & 0x80;
}
void Cpu::and__()
{
m_regA &= m_m;
m_flagN = (m_regA & 0x80) == 0x80;
m_flagZ = (m_regA == 0);
}
void Cpu::arr__()
{
m_regA = ((m_m & m_regA) >> 1) | (m_flagC ? 0x80 : 0x00);
m_flagZ = (m_regA & 0xFF) == 0;
m_flagN = m_regA & 0x80;
m_flagC = m_regA & 0x40;
m_flagV = (m_regA << 1 ^ m_regA) & 0x40;
}
void Cpu::axs__()
{
const qint32 temp = (m_regA & m_regX) - m_m;
m_flagN = temp & 0x80;
m_flagZ = (temp & 0xFF) == 0;
m_flagC = ~temp >> 8;
m_regX = temp;
}
void Cpu::asl_m()
{
m_flagC = (m_m & 0x80) == 0x80;
m_emu.memory().write(m_regEa.v, m_m);
m_m = (m_m << 1) & 0xFE;
m_emu.memory().write(m_regEa.v, m_m);
m_flagN = (m_m & 0x80) == 0x80;
m_flagZ = m_m == 0;
}
void Cpu::asl_a()
{
m_flagC = (m_regA & 0x80) == 0x80;
m_regA = (m_regA << 1) & 0xFE;
m_flagN = (m_regA & 0x80) == 0x80;
m_flagZ = m_regA == 0;
}
void Cpu::bcc__()
{
branch(!m_flagC);
}
void Cpu::bcs__()
{
branch(m_flagC);
}
void Cpu::beq__()
{
branch(m_flagZ);
}
void Cpu::bit__()
{
m_flagN = m_m & 0x80;
m_flagV = m_m & 0x40;
m_flagZ = (m_m & m_regA) == 0;
}
void Cpu::brk__()
{
m_emu.memory().read(m_regPc.v);
m_regPc.v++;
interrupt();
}
void Cpu::bpl__()
{
branch(!m_flagN);
}
void Cpu::bne__()
{
branch(!m_flagZ);
}
void Cpu::bmi__()
{
branch(m_flagN);
}
void Cpu::bvm__()
{
branch(!m_flagV);
}
void Cpu::bvs__()
{
branch(m_flagV);
}
void Cpu::sed__()
{
m_flagD = true;
}
void Cpu::clc__()
{
m_flagC = false;
}
void Cpu::cld__()
{
m_flagD = false;
}
void Cpu::clv__()
{
m_flagV = false;
}
void Cpu::cmp__()
{
const qint32 temp = m_regA - m_m;
m_flagN = (temp & 0x80) == 0x80;
m_flagC = m_regA >= m_m;
m_flagZ = temp == 0;
}
void Cpu::cpx__()
{
const qint32 temp = m_regX - m_m;
m_flagN = (temp & 0x80) == 0x80;
m_flagC = m_regX >= m_m;
m_flagZ = temp == 0;
}
void Cpu::cpy__()
{
const qint32 temp = m_regY - m_m;
m_flagN = (temp & 0x80) == 0x80;
m_flagC = m_regY >= m_m;
m_flagZ = temp == 0;
}
void Cpu::cli__()
{
m_flagI = false;
}
void Cpu::dcp__()
{
m_emu.memory().write(m_regEa.v, m_m--);
m_emu.memory().write(m_regEa.v, m_m);
const qint32 temp = m_regA - m_m;
m_flagN = temp & 0x80;
m_flagZ = temp == 0;
m_flagC = ~temp >> 8;
}
void Cpu::dec__()
{
m_emu.memory().write(m_regEa.v, m_m--);
m_emu.memory().write(m_regEa.v, m_m);
m_flagN = (m_m & 0x80) == 0x80;
m_flagZ = m_m == 0;
}
void Cpu::dey__()
{
m_flagZ = --m_regY == 0;
m_flagN = (m_regY & 0x80) == 0x80;
}
void Cpu::dex__()
{
m_flagZ = --m_regX == 0;
m_flagN = (m_regX & 0x80) == 0x80;
}
void Cpu::eor__()
{
m_regA ^= m_m;
m_flagN = (m_regA & 0x80) == 0x80;
m_flagZ = m_regA == 0;
}
void Cpu::inc__()
{
m_emu.memory().write(m_regEa.v, m_m++);
m_emu.memory().write(m_regEa.v, m_m);
m_flagN = (m_m & 0x80) == 0x80;
m_flagZ = m_m == 0;
}
void Cpu::inx__()
{
m_flagZ = ++m_regX == 0;
m_flagN = (m_regX & 0x80) == 0x80;
}
void Cpu::iny__()
{
m_flagN = (++m_regY & 0x80) == 0x80;
m_flagZ = m_regY == 0;
}
void Cpu::isc__()
{
quint8 temp0 = m_emu.memory().read(m_regEa.v);
m_emu.memory().write(m_regEa.v, temp0);
temp0++;
m_emu.memory().write(m_regEa.v, temp0);
const qint32 temp1 = temp0 ^ 0xFF;
const qint32 temp2 = (m_regA + temp1 + (m_flagC ? 1 : 0));
m_flagN = temp2 & 0x80;
m_flagV = (temp2 ^ m_regA) & (temp2 ^ temp1) & 0x80;
m_flagZ = (temp2 & 0xFF) == 0;
m_flagC = temp2 >> 0x8;
m_regA = temp2;
}
void Cpu::jmp__()
{
m_regPc.v = m_regEa.v;
}
void Cpu::jmp_i()
{
// Fetch pointer
m_regEa.l = m_emu.memory().read(m_regPc.v);
m_regPc.v++;
m_regEa.h = m_emu.memory().read(m_regPc.v);
m_regPc.l = m_emu.memory().read(m_regEa.v);
m_regEa.l++; // only increment the low byte, causing the "JMP ($nnnn)" bug
m_regPc.h = m_emu.memory().read(m_regEa.v);
}
void Cpu::jsr__()
{
m_regEa.l = m_emu.memory().read(m_regPc.v);
m_regPc.v++;
// Store EAL at SP, see http://users.telenet.be/kim1-6502/6502/proman.html (see the JSR part)
m_emu.memory().write(m_regSp.v, m_regEa.l);
push(m_regPc.h);
push(m_regPc.l);
m_regEa.h = m_emu.memory().read(m_regPc.v);
m_regPc.v = m_regEa.v;
}
void Cpu::lar__()
{
m_regSp.l &= m_m;
m_regA = m_regSp.l;
m_regX = m_regSp.l;
m_flagN = m_regSp.l & 0x80;
m_flagZ = (m_regSp.l & 0xFF) == 0;
}
void Cpu::lax__()
{
m_regX = m_regA = m_m;
m_flagN = m_regX & 0x80;
m_flagZ = (m_regX & 0xFF) == 0;
}
void Cpu::lda__()
{
m_regA = m_m;
m_flagN = (m_regA & 0x80) == 0x80;
m_flagZ = m_regA == 0;
}
void Cpu::ldx__()
{
m_regX = m_m;
m_flagN = (m_regX & 0x80) == 0x80;
m_flagZ = m_regX == 0;
}
void Cpu::ldy__()
{
m_regY = m_m;
m_flagN = (m_regY & 0x80) == 0x80;
m_flagZ = m_regY == 0;
}
void Cpu::lsr_a()
{
m_flagC = m_regA & 1;
m_regA >>= 1;
m_flagZ = m_regA == 0;
m_flagN = m_regA & 0x80;
}
void Cpu::lsr_m()
{
m_flagC = m_m & 1;
m_emu.memory().write(m_regEa.v, m_m);
m_m >>= 1;
m_emu.memory().write(m_regEa.v, m_m);
m_flagZ = m_m == 0;
m_flagN = m_m & 0x80;
}
void Cpu::nop__()
{
// Do nothing.
}
void Cpu::ora__()
{
m_regA |= m_m;
m_flagN = (m_regA & 0x80) == 0x80;
m_flagZ = m_regA == 0;
}
void Cpu::pha__()
{
push(m_regA);
}
void Cpu::php__()
{
push(getRegisterPb());
}
void Cpu::pla__()
{
m_emu.memory().read(m_regSp.v);
m_regA = pull();
m_flagN = (m_regA & 0x80) == 0x80;
m_flagZ = m_regA == 0;
}
void Cpu::plp__()
{
m_emu.memory().read(m_regSp.v);
setRegisterP(pull());
}
void Cpu::rla__()
{
const quint8 temp0 = m_emu.memory().read(m_regEa.v);
m_emu.memory().write(m_regEa.v, temp0);
const quint8 temp1 = (temp0 << 1) | (m_flagC ? 0x01 : 0x00);
m_emu.memory().write(m_regEa.v, temp1);
m_flagN = temp1 & 0x80;
m_flagZ = (temp1 & 0xFF) == 0;
m_flagC = temp0 & 0x80;
m_regA &= temp1;
m_flagN = m_regA & 0x80;
m_flagZ = (m_regA & 0xFF) == 0;
}
void Cpu::rol_a()
{
const quint8 temp = (m_regA << 1) | (m_flagC ? 0x01 : 0x00);
m_flagN = temp & 0x80;
m_flagZ = (temp & 0xFF) == 0;
m_flagC = m_regA & 0x80;
m_regA = temp;
}
void Cpu::rol_m()
{
m_emu.memory().write(m_regEa.v, m_m);
const quint8 temp = (m_m << 1) | (m_flagC ? 0x01 : 0x00);
m_emu.memory().write(m_regEa.v, temp);
m_flagN = temp & 0x80;
m_flagZ = (temp & 0xFF) == 0;
m_flagC = m_m & 0x80;
}
void Cpu::ror_a()
{
const quint8 temp = (m_regA >> 1) | (m_flagC ? 0x80 : 0x00);
m_flagN = temp & 0x80;
m_flagZ = (temp & 0xFF) == 0;
m_flagC = m_regA & 0x01;
m_regA = temp;
}
void Cpu::ror_m()
{
m_emu.memory().write(m_regEa.v, m_m);
const quint8 temp = (m_m >> 1) | (m_flagC ? 0x80 : 0x00);
m_emu.memory().write(m_regEa.v, temp);
m_flagN = temp & 0x80;
m_flagZ = (temp & 0xFF) == 0;
m_flagC = m_m & 0x01;
}
void Cpu::rra__()
{
const quint8 cpu_byte_temp = m_emu.memory().read(m_regEa.v);
m_emu.memory().write(m_regEa.v, cpu_byte_temp);
const quint8 cpu_dummy = (cpu_byte_temp >> 1) | (m_flagC ? 0x80 : 0x00);
m_emu.memory().write(m_regEa.v, cpu_dummy);
m_flagN = cpu_dummy & 0x80;
m_flagZ = (cpu_dummy & 0xFF) == 0;
m_flagC = cpu_byte_temp & 0x01;
int cpu_int_temp = (m_regA + cpu_dummy + (m_flagC ? 1 : 0));
m_flagN = cpu_int_temp & 0x80;
m_flagV = (cpu_int_temp ^ m_regA) & (cpu_int_temp ^ cpu_dummy) & 0x80;
m_flagZ = (cpu_int_temp & 0xFF) == 0;
m_flagC = cpu_int_temp >> 0x8;
m_regA = cpu_int_temp;
}
void Cpu::rti__()
{
m_emu.memory().read(m_regSp.v);
setRegisterP(pull());
m_regPc.l = pull();
m_regPc.h = pull();
}
void Cpu::rts__()
{
m_emu.memory().read(m_regSp.v);
m_regPc.l = pull();
m_regPc.h = pull();
m_regPc.v++;
m_emu.memory().read(m_regPc.v);
}
void Cpu::sax__()
{
m_emu.memory().write(m_regEa.v, m_regX & m_regA);
}
void Cpu::sdc__()
{
m_m ^= 0xFF;
const qint32 temp = (m_regA + m_m + (m_flagC ? 1 : 0));
m_flagN = temp & 0x80;
m_flagV = (temp ^ m_regA) & (temp ^ m_m) & 0x80;
m_flagZ = (temp & 0xFF) == 0;
m_flagC = temp >> 0x8;
m_regA = temp;
}
void Cpu::sec__()
{
m_flagC = true;
}
void Cpu::sei__()
{
m_flagI = true;
}
void Cpu::shx__()
{
const quint8 cpu_byte_temp = m_regX & (m_regEa.h + 1);
m_emu.memory().read(m_regEa.v);
m_regEa.l += m_regY;
if (m_regEa.l < m_regY)
m_regEa.h = cpu_byte_temp;
m_emu.memory().write(m_regEa.v, cpu_byte_temp);
}
void Cpu::shy__()
{
const quint8 temp = m_regY & (m_regEa.h + 1);
m_emu.memory().read(m_regEa.v);
m_regEa.l += m_regX;
if (m_regEa.l < m_regX)
m_regEa.h = temp;
m_emu.memory().write(m_regEa.v, temp);
}
void Cpu::slo__()
{
quint8 cpu_byte_temp = m_emu.memory().read(m_regEa.v);
m_flagC = cpu_byte_temp & 0x80;
m_emu.memory().write(m_regEa.v, cpu_byte_temp);
cpu_byte_temp <<= 1;
m_emu.memory().write(m_regEa.v, cpu_byte_temp);
m_flagN = cpu_byte_temp & 0x80;
m_flagZ = (cpu_byte_temp & 0xFF) == 0;
m_regA |= cpu_byte_temp;
m_flagN = m_regA & 0x80;
m_flagZ = (m_regA & 0xFF) == 0;
}
void Cpu::sre__()
{
quint8 cpu_byte_temp = m_emu.memory().read(m_regEa.v);
m_flagC = cpu_byte_temp & 0x01;
m_emu.memory().write(m_regEa.v, cpu_byte_temp);
cpu_byte_temp >>= 1;
m_emu.memory().write(m_regEa.v, cpu_byte_temp);
m_flagN = cpu_byte_temp & 0x80;
m_flagZ = (cpu_byte_temp & 0xFF) == 0;
m_regA ^= cpu_byte_temp;
m_flagN = m_regA & 0x80;
m_flagZ = (m_regA & 0xFF) == 0;
}
void Cpu::sta__()
{
m_emu.memory().write(m_regEa.v, m_regA);
}
void Cpu::stx__()
{
m_emu.memory().write(m_regEa.v, m_regX);
}
void Cpu::sty__()
{
m_emu.memory().write(m_regEa.v, m_regY);
}
void Cpu::tax__()
{
m_regX = m_regA;
m_flagN = (m_regX & 0x80) == 0x80;
m_flagZ = m_regX == 0;
}
void Cpu::tay__()
{
m_regY = m_regA;
m_flagN = (m_regY & 0x80) == 0x80;
m_flagZ = m_regY == 0;
}
void Cpu::tsx__()
{
m_regX = m_regSp.l;
m_flagN = m_regX & 0x80;
m_flagZ = m_regX == 0;
}
void Cpu::txa__()
{
m_regA = m_regX;
m_flagN = (m_regA & 0x80) == 0x80;
m_flagZ = m_regA == 0;
}
void Cpu::txs__()
{
m_regSp.l = m_regX;
}
void Cpu::tya__()
{
m_regA = m_regY;
m_flagN = (m_regA & 0x80) == 0x80;
m_flagZ = m_regA == 0;
}
void Cpu::xaa__()
{
m_regA = m_regX & m_m;
m_flagN = m_regA & 0x80;
m_flagZ = (m_regA & 0xFF) == 0;
}
void Cpu::xas__()
{
m_regSp.l = m_regA & m_regX /*& ((dummyVal >> 8) + 1) */;
m_emu.memory().write(m_regEa.v, m_regSp.l);
}
void Cpu::writeState(QDataStream &dataStream) const
{
dataStream << m_regPc.v << m_regSp.v << m_regEa.v << m_regA << m_regX << m_regY
<< m_flagN << m_flagV << m_flagD << m_flagI << m_flagZ << m_flagC
<< m_m << m_opcode << m_irqPin << m_nmiPin << m_suspendNmi << m_suspendIrq;
}
void Cpu::readState(QDataStream &dataStream)
{
dataStream >> m_regPc.v >> m_regSp.v >> m_regEa.v >> m_regA >> m_regX >> m_regY
>> m_flagN >> m_flagV >> m_flagD >> m_flagI >> m_flagZ >> m_flagC
>> m_m >> m_opcode >> m_irqPin >> m_nmiPin >> m_suspendNmi >> m_suspendIrq;
}
bool Cpu::suspendNmi() const
{
return m_suspendNmi;
}
bool Cpu::suspendIrq() const
{
return m_suspendIrq;
}
bool Cpu::flagI() const
{
return m_flagI;
}
bool Cpu::nmiPin() const
{
return m_nmiPin;
}
void Cpu::setNmiPin(bool nmiPin)
{
m_nmiPin = nmiPin;
}
bool Cpu::irqPin() const
{
return m_irqPin;
}
void Cpu::setIrqPin(bool irqPin)
{
m_irqPin = irqPin;
}