Merge branch 'master' of github.com:AnonymusRaccoon/ComSquare into Debugger

This commit is contained in:
Anonymus Raccoon
2020-04-28 21:28:46 +02:00
31 changed files with 2819 additions and 583 deletions

View File

@@ -95,7 +95,9 @@ add_executable(unit_tests
sources/Models/Components.hpp sources/Models/Components.hpp
sources/CPU/Instruction.hpp sources/CPU/Instruction.hpp
sources/Exceptions/DebuggableError.hpp sources/Exceptions/DebuggableError.hpp
) tests/CPU/Math/testOthersMath.cpp
tests/testRectangleMemory.cpp
tests/CPU/Math/testCMP.cpp)
# include criterion & coverage # include criterion & coverage
target_link_libraries(unit_tests criterion -lgcov) target_link_libraries(unit_tests criterion -lgcov)
@@ -159,8 +161,8 @@ add_executable(ComSquare
sources/CPU/Instructions/InternalInstruction.cpp sources/CPU/Instructions/InternalInstruction.cpp
sources/Ram/ExtendedRam.cpp sources/Ram/ExtendedRam.cpp
sources/Ram/ExtendedRam.hpp sources/Ram/ExtendedRam.hpp
sources/Debugger/CPUDebug.cpp sources/Debugger/CPU/CPUDebug.cpp
sources/Debugger/CPUDebug.hpp sources/Debugger/CPU/CPUDebug.hpp
sources/Renderer/QtRenderer/QtSFML.cpp sources/Renderer/QtRenderer/QtSFML.cpp
sources/Renderer/QtRenderer/QtSFML.hpp sources/Renderer/QtRenderer/QtSFML.hpp
sources/Renderer/QtRenderer/QtWidgetSFML.cpp sources/Renderer/QtRenderer/QtWidgetSFML.cpp
@@ -205,7 +207,7 @@ add_executable(ComSquare
sources/Models/Components.hpp sources/Models/Components.hpp
sources/CPU/Instruction.hpp sources/CPU/Instruction.hpp
sources/Exceptions/DebuggableError.hpp sources/Exceptions/DebuggableError.hpp
) sources/Debugger/CPU/Disassembly.cpp)
target_compile_definitions(ComSquare PUBLIC DEBUGGER_ENABLED) target_compile_definitions(ComSquare PUBLIC DEBUGGER_ENABLED)

View File

@@ -126,22 +126,6 @@ namespace ComSquare::CPU
return lng + this->_registers.x; return lng + this->_registers.x;
} }
uint24_t CPU::_getProgramCounterRelativeAddr()
{
uint24_t pc = this->_registers.pac;
int8_t mod = this->readPC();
return pc + mod;
}
uint24_t CPU::_getProgramCounterRelativeLongAddr()
{
uint24_t pc = this->_registers.pac;
uint8_t val1 = this->readPC();
uint8_t val2 = this->readPC();
int16_t mod = val2 > 0x7F ? (static_cast<char>(val2) * 256 - val1) : (val1 | val2 << 8u);
return pc + mod;
}
uint24_t CPU::_getAbsoluteIndirectAddr() uint24_t CPU::_getAbsoluteIndirectAddr()
{ {
uint16_t abs = this->readPC(); uint16_t abs = this->readPC();
@@ -151,6 +135,16 @@ namespace ComSquare::CPU
return effective; return effective;
} }
uint24_t CPU::_getAbsoluteIndirectLongAddr()
{
uint16_t abs = this->readPC();
abs += this->readPC() << 8u;
uint24_t effective = this->_bus->read(abs);
effective += this->_bus->read(abs + 1) << 8u;
effective += this->_bus->read(abs + 2) << 16u;
return effective;
}
uint24_t CPU::_getAbsoluteIndirectIndexedByXAddr() uint24_t CPU::_getAbsoluteIndirectIndexedByXAddr()
{ {
uint24_t abs = this->readPC(); uint24_t abs = this->readPC();

View File

@@ -211,96 +211,69 @@ namespace ComSquare::CPU
return cycles; return cycles;
} }
uint24_t CPU::_getValueAddr(Instruction &instruction)
{
switch (instruction.addressingMode) {
case Implied:
return 0;
case Immediate8bits:
return this->_getImmediateAddr8Bits();
case ImmediateForA:
return this->_getImmediateAddrForA();
case ImmediateForX:
return this->_getImmediateAddrForX();
case Absolute:
return this->_getAbsoluteAddr();
case AbsoluteLong:
return this->_getAbsoluteLongAddr();
case AbsoluteIndirect:
return this->_getAbsoluteIndirectAddr();
case AbsoluteIndirectLong:
return this->_getAbsoluteIndirectLongAddr();
case DirectPage:
return this->_getDirectAddr();
case DirectPageIndirect:
return this->_getDirectIndirectAddr();
case DirectPageIndirectLong:
return this->_getDirectIndirectLongAddr();
case DirectPageIndexedByX:
return this->_getDirectIndexedByXAddr();
case DirectPageIndexedByY:
return this->_getDirectIndexedByYAddr();
case DirectPageIndirectIndexedByX:
return this->_getDirectIndirectIndexedXAddr();
case DirectPageIndirectIndexedByY:
return this->_getDirectIndirectIndexedYAddr();
case DirectPageIndirectIndexedByYLong:
return this->_getDirectIndirectIndexedYLongAddr();
case AbsoluteIndexedByX:
return this->_getAbsoluteIndexedByXAddr();
case AbsoluteIndexedByXLong:
return this->_getAbsoluteIndexedByXLongAddr();
case AbsoluteIndexedByY:
return this->_getAbsoluteIndexedByYAddr();
case StackRelative:
return this->_getStackRelativeAddr();
case StackRelativeIndirectIndexedByY:
return this->_getStackRelativeIndirectIndexedYAddr();
case AbsoluteIndirectIndexedByX:
return this->_getAbsoluteIndirectIndexedByXAddr();
default:
return 0;
}
}
unsigned CPU::_executeInstruction(uint8_t opcode) unsigned CPU::_executeInstruction(uint8_t opcode)
{ {
Instruction instruction = this->_instructions[opcode]; Instruction instruction = this->_instructions[opcode];
uint24_t valueAddr = 0;
this->_hasIndexCrossedPageBoundary = false; this->_hasIndexCrossedPageBoundary = false;
uint24_t valueAddr = this->_getValueAddr(instruction);
switch (instruction.addressingMode) {
case Implied:
break;
case Immediate8bits:
valueAddr = this->_getImmediateAddr8Bits();
break;
case ImmediateForA:
valueAddr = this->_getImmediateAddrForA();
break;
case ImmediateForX:
valueAddr = this->_getImmediateAddrForX();
break;
// TODO implement the relative addressing mode
// TODO implement the relative long addressing mode
case Absolute:
valueAddr = this->_getAbsoluteAddr();
break;
case AbsoluteLong:
valueAddr = this->_getAbsoluteLongAddr();
break;
case AbsoluteIndirect:
valueAddr = this->_getAbsoluteIndirectAddr();
break;
//TODO implement absolute indirect long addressing mode
case DirectPage:
valueAddr = this->_getDirectAddr();
break;
case DirectPageIndirect:
valueAddr = this->_getDirectIndirectAddr();
break;
case DirectPageIndirectLong:
valueAddr = this->_getDirectIndirectLongAddr();
break;
case DirectPageIndexedByX:
valueAddr = this->_getDirectIndexedByXAddr();
break;
case DirectPageIndexedByY:
valueAddr = this->_getDirectIndexedByYAddr();
break;
case DirectPageIndirectIndexedByX:
valueAddr = this->_getDirectIndirectIndexedXAddr();
break;
case DirectPageIndirectIndexedByY:
valueAddr = this->_getDirectIndirectIndexedYAddr();
break;
case DirectPageIndirectIndexedByYLong:
valueAddr = this->_getDirectIndirectIndexedYLongAddr();
break;
case AbsoluteIndexedByX:
valueAddr = this->_getAbsoluteIndexedByXAddr();
break;
case AbsoluteIndexedByXLong:
valueAddr = this->_getAbsoluteIndexedByXLongAddr();
break;
case AbsoluteIndexedByY:
valueAddr = this->_getAbsoluteIndexedByYAddr();
break;
case StackRelative:
valueAddr = this->_getStackRelativeAddr();
break;
case StackRelativeIndirectIndexedByY:
valueAddr = this->_getStackRelativeIndirectIndexedYAddr();
break;
case ProgramCounterRelative:
valueAddr = this->_getProgramCounterRelativeAddr();
break;
case ProgramCounterRelativeLong:
valueAddr = this->_getProgramCounterRelativeLongAddr();
break;
case AbsoluteIndirectIndexedByX:
valueAddr = this->_getAbsoluteIndirectIndexedByXAddr();
break;
default:
break;
}
return instruction.cycleCount + (this->*instruction.call)(valueAddr, instruction.addressingMode); return instruction.cycleCount + (this->*instruction.call)(valueAddr, instruction.addressingMode);
} }

View File

@@ -226,12 +226,10 @@ namespace ComSquare::CPU
uint24_t _getAbsoluteIndexedByYAddr(); uint24_t _getAbsoluteIndexedByYAddr();
//! @brief The effective address is formed by adding the <long exp> with X. //! @brief The effective address is formed by adding the <long exp> with X.
uint24_t _getAbsoluteIndexedByXLongAddr(); uint24_t _getAbsoluteIndexedByXLongAddr();
//! @brief The <8-bit signed exp> is added to PC (program counter) to form the new location.
uint24_t _getProgramCounterRelativeAddr();
//! @brief The <16-bit signed exp> is added to PC (program counter) to form the new location.
uint24_t _getProgramCounterRelativeLongAddr();
//! @brief 2 bytes are pulled from the <abs exp> to form the effective address. //! @brief 2 bytes are pulled from the <abs exp> to form the effective address.
uint24_t _getAbsoluteIndirectAddr(); uint24_t _getAbsoluteIndirectAddr();
//! @brief 3 bytes are pulled from the <abs exp> to form the effective address.
uint24_t _getAbsoluteIndirectLongAddr();
//! @brief The <abs exp> is added with X, then 2 bytes are pulled from that address to form the new location. //! @brief The <abs exp> is added with X, then 2 bytes are pulled from that address to form the new location.
uint24_t _getAbsoluteIndirectIndexedByXAddr(); uint24_t _getAbsoluteIndirectIndexedByXAddr();
//! @brief 2 bytes are pulled from the direct page address to form the 16-bit address. It is combined with DBR to form a 24-bit effective address. //! @brief 2 bytes are pulled from the direct page address to form the 16-bit address. It is combined with DBR to form a 24-bit effective address.
@@ -260,6 +258,11 @@ namespace ComSquare::CPU
//! @return The number of CPU cycles that the instruction took. //! @return The number of CPU cycles that the instruction took.
virtual unsigned _executeInstruction(uint8_t opcode); virtual unsigned _executeInstruction(uint8_t opcode);
//! @brief Get the parameter address of an instruction from it's addressing mode.
//! @info The current program counter should point to the instruction's opcode + 1.
//! @return The address of the data to read on the instruction.
uint24_t _getValueAddr(Instruction &instruction);
//! @brief Break instruction - Causes a software break. The PC is loaded from a vector table. //! @brief Break instruction - Causes a software break. The PC is loaded from a vector table.
int BRK(uint24_t, AddressingMode); int BRK(uint24_t, AddressingMode);
//! @brief Co-Processor Enable instruction - Causes a software break. The PC is loaded from a vector table. //! @brief Co-Processor Enable instruction - Causes a software break. The PC is loaded from a vector table.
@@ -376,107 +379,147 @@ namespace ComSquare::CPU
int JML(uint24_t valueAddr, AddressingMode); int JML(uint24_t valueAddr, AddressingMode);
//! @brief No OP. //! @brief No OP.
int NOP(uint24_t, AddressingMode); int NOP(uint24_t, AddressingMode);
//! @brief Decrement the X register.
int DEX(uint24_t, AddressingMode);
//! @brief Decrement the Y register.
int DEY(uint24_t, AddressingMode);
//! @brief Or accumulator with memory.
int ORA(uint24_t valueAddr, AddressingMode mode);
//! @brief Return from subroutine.
int RTS(uint24_t, AddressingMode);
//! @brief Return from subroutine long.
int RTL(uint24_t, AddressingMode);
//! @brief Compare Accumulator with Memory.
int CMP(uint24_t, AddressingMode);
//! @brief Increment
int INC(uint24_t, AddressingMode);
//! @brief Decrement
int DEC(uint24_t, AddressingMode);
//! @brief XOR, Exclusive OR accumulator with memory.
int EOR(uint24_t, AddressingMode);
//! @brief Transfer 16 bit A to DP
int TCD(uint24_t, AddressingMode);
//! @brief Transfer 16 bit A to SP
int TCS(uint24_t, AddressingMode);
//! @brief Transfer DP to 16 bit A
int TDC(uint24_t, AddressingMode);
//! @brief Transfer DP to 16 bit A
int TSC(uint24_t, AddressingMode);
//! @brief Transfer SP to X
int TSX(uint24_t, AddressingMode);
//! @brief Transfer X to A
int TXA(uint24_t, AddressingMode);
//! @brief Transfer Y to A
int TYA(uint24_t, AddressingMode);
//! @brief Transfer X to Y
int TXY(uint24_t, AddressingMode);
//! @brief Transfer Y to X
int TYX(uint24_t, AddressingMode);
//! @brief Test and Set Memory Bits Against Accumulator
int TSB(uint24_t, AddressingMode);
//! @brief Exchange the B and A Accumulators
int XBA(uint24_t, AddressingMode);
//! @brief All the instructions of the CPU. //! @brief All the instructions of the CPU.
//! @info Instructions are indexed by their opcode //! @info Instructions are indexed by their opcode
Instruction _instructions[0x100] = { Instruction _instructions[0x100] = {
{&CPU::BRK, 7, "brk", AddressingMode::Implied, 2}, // 00 {&CPU::BRK, 7, "brk", AddressingMode::Immediate8bits, 2}, // 00
{&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 01 {&CPU::ORA, 6, "ora", AddressingMode::DirectPageIndirectIndexedByX, 2}, // 01
{&CPU::COP, 7, "cop", AddressingMode::Implied, 2}, // 02 {&CPU::COP, 7, "cop", AddressingMode::Immediate8bits, 2}, // 02
{&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 03 {&CPU::ORA, 4, "ora", AddressingMode::StackRelative, 2}, // 03
{&CPU::BRK, 7, "tsb #-#", AddressingMode::Implied, 2}, // 04 {&CPU::TSB, 5, "tsb", AddressingMode::DirectPage, 2}, // 04
{&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 05 {&CPU::ORA, 3, "ora", AddressingMode::DirectPage, 2}, // 05
{&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 06 {&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 06
{&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 07 {&CPU::ORA, 6, "ora", AddressingMode::DirectPageIndirectLong, 2}, // 07
{&CPU::PHP, 3, "php", AddressingMode::Implied, 3}, // 08 {&CPU::PHP, 3, "php", AddressingMode::Implied, 3}, // 08
{&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 09 {&CPU::ORA, 2, "ora", AddressingMode::ImmediateForA, 2}, // 09
{&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 0A {&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 0A
{&CPU::PHD, 4, "phd", AddressingMode::Implied, 1}, // 0B {&CPU::PHD, 4, "phd", AddressingMode::Implied, 1}, // 0B
{&CPU::BRK, 7, "tsb #-#", AddressingMode::Implied, 2}, // 0C {&CPU::TSB, 6, "tsb", AddressingMode::Absolute, 3}, // 0C
{&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 0D {&CPU::ORA, 3, "ora", AddressingMode::Absolute, 4}, // 0D
{&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 0E {&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 0E
{&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 0F {&CPU::ORA, 5, "ora", AddressingMode::AbsoluteLong, 5}, // 0F
{&CPU::BPL, 7, "bpl", AddressingMode::Implied, 2}, // 10 {&CPU::BPL, 7, "bpl", AddressingMode::Immediate8bits, 2}, // 10
{&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 11 {&CPU::ORA, 5, "ora", AddressingMode::DirectPageIndirectIndexedByY, 2}, // 11
{&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 12 {&CPU::ORA, 5, "ora", AddressingMode::DirectPageIndirect, 2}, // 12
{&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 13 {&CPU::ORA, 7, "ora", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // 13
{&CPU::BRK, 7, "trb #-#", AddressingMode::Implied, 2}, // 14 {&CPU::BRK, 7, "trb #-#", AddressingMode::Implied, 2}, // 14
{&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 15 {&CPU::ORA, 4, "ora", AddressingMode::DirectPageIndexedByX, 2}, // 15
{&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 16 {&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 16
{&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 17 {&CPU::ORA, 6, "ora", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // 17
{&CPU::CLC, 2, "clc", AddressingMode::Implied, 1}, // 18 {&CPU::CLC, 2, "clc", AddressingMode::Implied, 1}, // 18
{&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 19 {&CPU::ORA, 4, "ora", AddressingMode::AbsoluteIndexedByY, 3}, // 19
{&CPU::BRK, 7, "inc #-#", AddressingMode::Implied, 2}, // 1A {&CPU::INC, 2, "inc", AddressingMode::Implied, 1}, // 1A
{&CPU::BRK, 7, "tcs #-#", AddressingMode::Implied, 2}, // 1B {&CPU::TCS, 2, "tcs", AddressingMode::Implied, 1}, // 1B
{&CPU::BRK, 7, "trb #-#", AddressingMode::Implied, 2}, // 1C {&CPU::BRK, 7, "trb #-#", AddressingMode::Implied, 2}, // 1C
{&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 1D {&CPU::ORA, 4, "ora", AddressingMode::AbsoluteIndexedByX, 3}, // 1D
{&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 1E {&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 1E
{&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 1F {&CPU::ORA, 5, "ora", AddressingMode::AbsoluteIndexedByXLong, 4}, // 1F
{&CPU::JSR, 6, "jsr", AddressingMode::Absolute, 3}, // 20 {&CPU::JSR, 6, "jsr", AddressingMode::Absolute, 3}, // 20
{&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 21 {&CPU::AND, 6, "and", AddressingMode::DirectPageIndirectIndexedByX, 2}, // 21
{&CPU::JSL, 8, "jsl", AddressingMode::AbsoluteLong, 4}, // 22 {&CPU::JSL, 8, "jsl", AddressingMode::AbsoluteLong, 4}, // 22
{&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 23 {&CPU::AND, 4, "and", AddressingMode::StackRelative, 2}, // 23
{&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 24 {&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 24
{&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 25 {&CPU::AND, 3, "and", AddressingMode::DirectPage, 2}, // 25
{&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 26 {&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 26
{&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 27 {&CPU::AND, 6, "and", AddressingMode::DirectPageIndirectLong, 2}, // 27
{&CPU::PLP, 4, "plp", AddressingMode::Implied, 1}, // 28 {&CPU::PLP, 4, "plp", AddressingMode::Implied, 1}, // 28
{&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 29 {&CPU::AND, 2, "and", AddressingMode::ImmediateForA, 2}, // 29
{&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 2A {&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 2A
{&CPU::PLD, 5, "pld", AddressingMode::Implied, 1}, // 2B {&CPU::PLD, 5, "pld", AddressingMode::Implied, 1}, // 2B
{&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 2C {&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 2C
{&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 2D {&CPU::AND, 4, "and", AddressingMode::Absolute, 3}, // 2D
{&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 2E {&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 2E
{&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 2F {&CPU::AND, 5, "and", AddressingMode::AbsoluteLong, 4}, // 2F
{&CPU::BMI, 2, "bmi", AddressingMode::Implied, 2}, // 30 {&CPU::BMI, 2, "bmi", AddressingMode::Immediate8bits, 2}, // 30
{&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 31 {&CPU::AND, 5, "and", AddressingMode::DirectPageIndirectIndexedByY, 2}, // 31
{&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 32 {&CPU::AND, 5, "and", AddressingMode::DirectPageIndirect, 2}, // 32
{&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 33 {&CPU::AND, 7, "and", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // 33
{&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 34 {&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 34
{&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 35 {&CPU::AND, 4, "and", AddressingMode::DirectPageIndexedByX, 2}, // 35
{&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 36 {&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 36
{&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 37 {&CPU::AND, 6, "and", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // 37
{&CPU::SEC, 2, "sec", AddressingMode::Implied, 1}, // 38 {&CPU::SEC, 2, "sec", AddressingMode::Implied, 1}, // 38
{&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 39 {&CPU::AND, 4, "and", AddressingMode::AbsoluteIndexedByY, 3}, // 39
{&CPU::BRK, 7, "dec #-#", AddressingMode::Implied, 2}, // 3A {&CPU::DEC, 2, "dec", AddressingMode::Implied, 1}, // 3A
{&CPU::BRK, 7, "tsc #-#", AddressingMode::Implied, 2}, // 3B {&CPU::TSC, 2, "tsc", AddressingMode::Implied, 1}, // 3B
{&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 3C {&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 3C
{&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 3D {&CPU::AND, 4, "and", AddressingMode::AbsoluteIndexedByX, 3}, // 3D
{&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 3E {&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 3E
{&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 3F {&CPU::AND, 5, "and", AddressingMode::AbsoluteIndexedByXLong, 4}, // 3F
{&CPU::RTI, 6, "rti", AddressingMode::Implied, 1}, // 40 {&CPU::RTI, 6, "rti", AddressingMode::Implied, 1}, // 40
{&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 41 {&CPU::EOR, 6, "eor", AddressingMode::DirectPageIndirectIndexedByX, 2}, // 41
{&CPU::BRK, 7, "wdm #-#", AddressingMode::Implied, 2}, // 42 {&CPU::BRK, 7, "wdm #-#", AddressingMode::Implied, 2}, // 42
{&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 43 {&CPU::EOR, 4, "eor", AddressingMode::StackRelative, 2}, // 43
{&CPU::BRK, 7, "mvp #-#", AddressingMode::Implied, 2}, // 44 {&CPU::BRK, 7, "mvp #-#", AddressingMode::Implied, 2}, // 44
{&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 45 {&CPU::EOR, 3, "eor", AddressingMode::DirectPage, 2}, // 45
{&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 46 {&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 46
{&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 47 {&CPU::EOR, 6, "eor", AddressingMode::DirectPageIndirectLong, 2}, // 47
{&CPU::PHA, 3, "pha", AddressingMode::Implied, 1}, // 48 {&CPU::PHA, 3, "pha", AddressingMode::Implied, 1}, // 48
{&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 49 {&CPU::EOR, 2, "eor", AddressingMode::ImmediateForA, 2}, // 49
{&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 4A {&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 4A
{&CPU::PHK, 3, "phk", AddressingMode::Implied, 1}, // 4B {&CPU::PHK, 3, "phk", AddressingMode::Implied, 1}, // 4B
{&CPU::JMP, 3, "jmp", AddressingMode::Absolute, 3}, // 4C {&CPU::JMP, 3, "jmp", AddressingMode::Absolute, 3}, // 4C
{&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 4D {&CPU::EOR, 4, "eor", AddressingMode::Absolute, 3}, // 4D
{&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 4E {&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 4E
{&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 4F {&CPU::EOR, 5, "eor", AddressingMode::AbsoluteLong, 4}, // 4F
{&CPU::BVC, 2, "bvc", AddressingMode::Implied, 2}, // 50 {&CPU::BVC, 2, "bvc", AddressingMode::Immediate8bits, 2}, // 50
{&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 51 {&CPU::EOR, 5, "eor", AddressingMode::DirectPageIndirectIndexedByY, 2}, // 51
{&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 52 {&CPU::EOR, 5, "eor", AddressingMode::DirectPageIndirect, 2}, // 52
{&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 53 {&CPU::EOR, 4, "eor", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // 53
{&CPU::BRK, 7, "mvn #-#", AddressingMode::Implied, 2}, // 54 {&CPU::BRK, 7, "mvn #-#", AddressingMode::Implied, 2}, // 54
{&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 55 {&CPU::EOR, 4, "eor", AddressingMode::DirectPageIndexedByX, 2}, // 55
{&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 56 {&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 56
{&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 57 {&CPU::EOR, 6, "eor", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // 57
{&CPU::CLI, 2, "cli", AddressingMode::Implied, 1}, // 58 {&CPU::CLI, 2, "cli", AddressingMode::Implied, 1}, // 58
{&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 59 {&CPU::EOR, 4, "eor", AddressingMode::AbsoluteIndexedByY, 3}, // 59
{&CPU::PHY, 3, "phy", AddressingMode::Implied, 1}, // 5A {&CPU::PHY, 3, "phy", AddressingMode::Implied, 1}, // 5A
{&CPU::BRK, 7, "tcd #-#", AddressingMode::Implied, 2}, // 5B {&CPU::TCD, 2, "tcd", AddressingMode::Implied, 1}, // 5B
{&CPU::JML, 4, "jml", AddressingMode::Implied, 4}, // 5C {&CPU::JML, 4, "jml", AddressingMode::Implied, 4}, // 5C
{&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 5D {&CPU::EOR, 4, "eor", AddressingMode::AbsoluteIndexedByX, 3}, // 5D
{&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 5E {&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 5E
{&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 5F {&CPU::EOR, 5, "eor", AddressingMode::AbsoluteIndexedByXLong, 4}, // 5F
{&CPU::BRK, 7, "rtl #-#", AddressingMode::Implied, 2}, // 60 {&CPU::RTL, 6, "rtl", AddressingMode::Implied, 1}, // 60
{&CPU::ADC, 6, "adc", AddressingMode::DirectPageIndirectIndexedByX, 2}, // 61 {&CPU::ADC, 6, "adc", AddressingMode::DirectPageIndirectIndexedByX, 2}, // 61
{&CPU::BRK, 7, "per #-#", AddressingMode::Implied, 2}, // 62 {&CPU::BRK, 7, "per #-#", AddressingMode::Implied, 2}, // 62
{&CPU::ADC, 4, "adc", AddressingMode::StackRelative, 2}, // 63 {&CPU::ADC, 4, "adc", AddressingMode::StackRelative, 2}, // 63
@@ -487,12 +530,12 @@ namespace ComSquare::CPU
{&CPU::PLA, 4, "pla", AddressingMode::Implied, 1}, // 68 {&CPU::PLA, 4, "pla", AddressingMode::Implied, 1}, // 68
{&CPU::ADC, 2, "adc", AddressingMode::ImmediateForA, 2}, // 69 {&CPU::ADC, 2, "adc", AddressingMode::ImmediateForA, 2}, // 69
{&CPU::BRK, 7, "ror #-#", AddressingMode::Implied, 2}, // 6A {&CPU::BRK, 7, "ror #-#", AddressingMode::Implied, 2}, // 6A
{&CPU::BRK, 7, "rts #-#", AddressingMode::Implied, 2}, // 6B {&CPU::RTS, 6, "rts", AddressingMode::Implied, 1}, // 6B
{&CPU::JMP, 5, "jmp", AddressingMode::AbsoluteIndirect, 3}, // 6C {&CPU::JMP, 5, "jmp", AddressingMode::AbsoluteIndirect, 3}, // 6C
{&CPU::ADC, 4, "adc", AddressingMode::Absolute, 3}, // 6D {&CPU::ADC, 4, "adc", AddressingMode::Absolute, 3}, // 6D
{&CPU::BRK, 7, "ror #-#", AddressingMode::Implied, 2}, // 6E {&CPU::BRK, 7, "ror #-#", AddressingMode::Implied, 2}, // 6E
{&CPU::ADC, 5, "adc", AddressingMode::AbsoluteLong, 4}, // 6F {&CPU::ADC, 5, "adc", AddressingMode::AbsoluteLong, 4}, // 6F
{&CPU::BVS, 2, "bvs", AddressingMode::Implied, 2}, // 70 {&CPU::BVS, 2, "bvs", AddressingMode::Immediate8bits, 2}, // 70
{&CPU::ADC, 5, "adc", AddressingMode::DirectPageIndirectIndexedByY, 2}, // 71 {&CPU::ADC, 5, "adc", AddressingMode::DirectPageIndirectIndexedByY, 2}, // 71
{&CPU::ADC, 5, "adc", AddressingMode::DirectPageIndirect, 2}, // 72 {&CPU::ADC, 5, "adc", AddressingMode::DirectPageIndirect, 2}, // 72
{&CPU::ADC, 7, "adc", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // 73 {&CPU::ADC, 7, "adc", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // 73
@@ -503,28 +546,28 @@ namespace ComSquare::CPU
{&CPU::SEI, 2, "sei", AddressingMode::Implied, 1}, // 78 {&CPU::SEI, 2, "sei", AddressingMode::Implied, 1}, // 78
{&CPU::ADC, 4, "adc", AddressingMode::AbsoluteIndexedByY, 2}, // 79 {&CPU::ADC, 4, "adc", AddressingMode::AbsoluteIndexedByY, 2}, // 79
{&CPU::PLY, 4, "ply", AddressingMode::Implied, 1}, // 7A {&CPU::PLY, 4, "ply", AddressingMode::Implied, 1}, // 7A
{&CPU::BRK, 7, "tdc #-#", AddressingMode::Implied, 2}, // 7B {&CPU::TDC, 2, "tdc", AddressingMode::Implied, 1}, // 7B
{&CPU::JMP, 6, "jmp", AddressingMode::AbsoluteIndirectIndexedByX, 3}, // 7C {&CPU::JMP, 6, "jmp", AddressingMode::AbsoluteIndirectIndexedByX, 3}, // 7C
{&CPU::ADC, 4, "adc", AddressingMode::AbsoluteIndexedByX, 3}, // 7D {&CPU::ADC, 4, "adc", AddressingMode::AbsoluteIndexedByX, 3}, // 7D
{&CPU::BRK, 7, "ror #-#", AddressingMode::Implied, 2}, // 7E {&CPU::BRK, 7, "ror #-#", AddressingMode::Implied, 2}, // 7E
{&CPU::ADC, 5, "adc", AddressingMode::AbsoluteIndexedByXLong, 4}, // 7F {&CPU::ADC, 5, "adc", AddressingMode::AbsoluteIndexedByXLong, 4}, // 7F
{&CPU::BRA, 3, "bra", AddressingMode::Implied, 2}, // 80 {&CPU::BRA, 3, "bra", AddressingMode::Immediate8bits, 2}, // 80
{&CPU::STA, 6, "sta", AddressingMode::DirectPageIndexedByX, 2}, // 81 {&CPU::STA, 6, "sta", AddressingMode::DirectPageIndexedByX, 2}, // 81
{&CPU::BRL, 4, "brl", AddressingMode::Implied, 3}, // 82 {&CPU::BRL, 4, "brl", AddressingMode::Absolute, 3}, // 82
{&CPU::STA, 4, "sta", AddressingMode::StackRelative, 2}, // 83 {&CPU::STA, 4, "sta", AddressingMode::StackRelative, 2}, // 83
{&CPU::STY, 3, "sty", AddressingMode::DirectPage, 2}, // 84 {&CPU::STY, 3, "sty", AddressingMode::DirectPage, 2}, // 84
{&CPU::STA, 3, "sta", AddressingMode::DirectPage, 2}, // 85 {&CPU::STA, 3, "sta", AddressingMode::DirectPage, 2}, // 85
{&CPU::STX, 3, "stx", AddressingMode::DirectPage, 2}, // 86 {&CPU::STX, 3, "stx", AddressingMode::DirectPage, 2}, // 86
{&CPU::STA, 6, "sta", AddressingMode::DirectPageIndirectLong, 2}, // 87 {&CPU::STA, 6, "sta", AddressingMode::DirectPageIndirectLong, 2}, // 87
{&CPU::BRK, 7, "dey #-#", AddressingMode::Implied, 2}, // 88 {&CPU::DEY, 2, "dey", AddressingMode::Implied, 1}, // 88
{&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 89 {&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 89
{&CPU::BRK, 7, "txa #-#", AddressingMode::Implied, 2}, // 8A {&CPU::TXA, 2, "txa", AddressingMode::Implied, 2}, // 8A
{&CPU::PHB, 3, "phb", AddressingMode::Implied, 1}, // 8B {&CPU::PHB, 3, "phb", AddressingMode::Implied, 1}, // 8B
{&CPU::STY, 4, "sty", AddressingMode::Absolute, 3}, // 8C {&CPU::STY, 4, "sty", AddressingMode::Absolute, 3}, // 8C
{&CPU::STA, 4, "sta", AddressingMode::Absolute, 3}, // 8D {&CPU::STA, 4, "sta", AddressingMode::Absolute, 3}, // 8D
{&CPU::STX, 4, "stx", AddressingMode::Absolute, 3}, // 8E {&CPU::STX, 4, "stx", AddressingMode::Absolute, 3}, // 8E
{&CPU::STA, 5, "sta", AddressingMode::AbsoluteLong, 4}, // 8F {&CPU::STA, 5, "sta", AddressingMode::AbsoluteLong, 4}, // 8F
{&CPU::BCC, 2, "bcc", AddressingMode::Implied, 2}, // 90 {&CPU::BCC, 2, "bcc", AddressingMode::Immediate8bits, 2}, // 90
{&CPU::STA, 6, "sta", AddressingMode::DirectPageIndirectIndexedByY, 2}, // 91 {&CPU::STA, 6, "sta", AddressingMode::DirectPageIndirectIndexedByY, 2}, // 91
{&CPU::STA, 5, "sta", AddressingMode::DirectPageIndirect, 2}, // 92 {&CPU::STA, 5, "sta", AddressingMode::DirectPageIndirect, 2}, // 92
{&CPU::STA, 7, "sta", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // 93 {&CPU::STA, 7, "sta", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // 93
@@ -532,10 +575,10 @@ namespace ComSquare::CPU
{&CPU::STA, 4, "sta", AddressingMode::DirectPageIndexedByX, 2}, // 95 {&CPU::STA, 4, "sta", AddressingMode::DirectPageIndexedByX, 2}, // 95
{&CPU::STX, 4, "stx", AddressingMode::DirectPageIndexedByY, 2}, // 96 {&CPU::STX, 4, "stx", AddressingMode::DirectPageIndexedByY, 2}, // 96
{&CPU::STA, 6, "sta", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // 97 {&CPU::STA, 6, "sta", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // 97
{&CPU::BRK, 7, "tya #-#", AddressingMode::Implied, 2}, // 98 {&CPU::TYA, 2, "tya", AddressingMode::Implied, 1}, // 98
{&CPU::STA, 5, "sta", AddressingMode::AbsoluteIndexedByY, 3}, // 99 {&CPU::STA, 5, "sta", AddressingMode::AbsoluteIndexedByY, 3}, // 99
{&CPU::TXS, 2, "txs", AddressingMode::Implied, 1}, // 9A {&CPU::TXS, 2, "txs", AddressingMode::Implied, 1}, // 9A
{&CPU::BRK, 7, "txy #-#", AddressingMode::Implied, 2}, // 9B {&CPU::TXY, 2, "txy", AddressingMode::Implied, 1}, // 9B
{&CPU::STZ, 4, "stz", AddressingMode::Absolute, 3}, // 9C {&CPU::STZ, 4, "stz", AddressingMode::Absolute, 3}, // 9C
{&CPU::STA, 5, "sta", AddressingMode::AbsoluteIndexedByX, 3}, // 9D {&CPU::STA, 5, "sta", AddressingMode::AbsoluteIndexedByX, 3}, // 9D
{&CPU::STZ, 5, "stz", AddressingMode::AbsoluteIndexedByX, 3}, // 9E {&CPU::STZ, 5, "stz", AddressingMode::AbsoluteIndexedByX, 3}, // 9E
@@ -556,7 +599,7 @@ namespace ComSquare::CPU
{&CPU::LDA, 4, "lda", AddressingMode::Absolute, 3}, // AD {&CPU::LDA, 4, "lda", AddressingMode::Absolute, 3}, // AD
{&CPU::LDX, 4, "ldx", AddressingMode::Absolute, 3}, // AE {&CPU::LDX, 4, "ldx", AddressingMode::Absolute, 3}, // AE
{&CPU::LDA, 5, "lda", AddressingMode::AbsoluteLong, 4}, // AF {&CPU::LDA, 5, "lda", AddressingMode::AbsoluteLong, 4}, // AF
{&CPU::BCS, 2, "bcs", AddressingMode::Implied, 2}, // B0 {&CPU::BCS, 2, "bcs", AddressingMode::Immediate8bits, 2}, // B0
{&CPU::LDA, 5, "lda", AddressingMode::DirectPageIndirectIndexedByY, 2}, // B1 {&CPU::LDA, 5, "lda", AddressingMode::DirectPageIndirectIndexedByY, 2}, // B1
{&CPU::LDA, 5, "lda", AddressingMode::DirectPageIndirect, 2}, // B2 {&CPU::LDA, 5, "lda", AddressingMode::DirectPageIndirect, 2}, // B2
{&CPU::LDA, 7, "lda", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // B3 {&CPU::LDA, 7, "lda", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // B3
@@ -566,67 +609,67 @@ namespace ComSquare::CPU
{&CPU::LDA, 6, "lda", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // B7 {&CPU::LDA, 6, "lda", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // B7
{&CPU::CLV, 7, "clv", AddressingMode::Implied, 1}, // B8 {&CPU::CLV, 7, "clv", AddressingMode::Implied, 1}, // B8
{&CPU::LDA, 4, "lda", AddressingMode::AbsoluteIndexedByY, 3}, // B9 {&CPU::LDA, 4, "lda", AddressingMode::AbsoluteIndexedByY, 3}, // B9
{&CPU::BRK, 7, "mvn #-#", AddressingMode::Implied, 2}, // BA {&CPU::TSX, 2, "tsx", AddressingMode::Implied, 1}, // BA
{&CPU::BRK, 7, "tyx #-#", AddressingMode::Implied, 2}, // BB {&CPU::TYX, 2, "tyx", AddressingMode::Implied, 1}, // BB
{&CPU::LDY, 4, "ldy", AddressingMode::AbsoluteIndexedByX, 3}, // BC {&CPU::LDY, 4, "ldy", AddressingMode::AbsoluteIndexedByX, 3}, // BC
{&CPU::LDA, 4, "lda", AddressingMode::AbsoluteIndexedByX, 3}, // BD {&CPU::LDA, 4, "lda", AddressingMode::AbsoluteIndexedByX, 3}, // BD
{&CPU::LDX, 4, "ldx", AddressingMode::AbsoluteIndexedByY, 3}, // BE {&CPU::LDX, 4, "ldx", AddressingMode::AbsoluteIndexedByY, 3}, // BE
{&CPU::LDA, 5, "lda", AddressingMode::AbsoluteIndexedByXLong, 4}, // BF {&CPU::LDA, 5, "lda", AddressingMode::AbsoluteIndexedByXLong, 4}, // BF
{&CPU::BRK, 7, "cpy #-#", AddressingMode::Implied, 2}, // C0 {&CPU::CPY, 2, "cpy", AddressingMode::ImmediateForX, 2}, // C0
{&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // C1 {&CPU::CMP, 6, "cmp", AddressingMode::DirectPageIndirectIndexedByX, 2}, // C1
{&CPU::REP, 3, "rep", AddressingMode::Immediate8bits, 2}, // C2 {&CPU::REP, 3, "rep", AddressingMode::Immediate8bits, 2}, // C2
{&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // C3 {&CPU::CMP, 4, "cmp", AddressingMode::StackRelative, 2}, // C3
{&CPU::BRK, 7, "cpy #-#", AddressingMode::Implied, 2}, // C4 {&CPU::CPY, 3, "cpy", AddressingMode::DirectPage, 2}, // C4
{&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // C5 {&CPU::CMP, 3, "cmp", AddressingMode::DirectPage, 2}, // C5
{&CPU::BRK, 7, "dec #-#", AddressingMode::Implied, 2}, // C6 {&CPU::DEC, 5, "dec", AddressingMode::DirectPage, 2}, // C6
{&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // C7 {&CPU::CMP, 6, "cmp", AddressingMode::DirectPageIndirectLong, 2}, // C7
{&CPU::INY, 2, "iny", AddressingMode::Implied, 1}, // C8 {&CPU::INY, 2, "iny", AddressingMode::Implied, 1}, // C8
{&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // C9 {&CPU::CMP, 2, "cmp", AddressingMode::ImmediateForA, 2}, // C9
{&CPU::BRK, 7, "dex #-#", AddressingMode::Implied, 2}, // CA {&CPU::DEX, 2, "dex", AddressingMode::Implied, 1}, // CA
{&CPU::BRK, 7, "wai #-#", AddressingMode::Implied, 2}, // CB {&CPU::BRK, 7, "wai #-#", AddressingMode::Implied, 2}, // CB
{&CPU::BRK, 7, "cpy #-#", AddressingMode::Implied, 2}, // CC {&CPU::CPY, 4, "cpy", AddressingMode::Absolute, 3}, // CC
{&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // CD {&CPU::CMP, 4, "cmp", AddressingMode::Absolute, 3}, // CD
{&CPU::BRK, 7, "dec #-#", AddressingMode::Implied, 2}, // CE {&CPU::DEC, 6, "dec", AddressingMode::Absolute, 3}, // CE
{&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // CF {&CPU::CMP, 6, "cmp", AddressingMode::AbsoluteLong, 4}, // CF
{&CPU::BNE, 2, "bne", AddressingMode::Implied, 2}, // D0 {&CPU::BNE, 2, "bne", AddressingMode::Immediate8bits, 2}, // D0
{&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // D1 {&CPU::CMP, 5, "cmp", AddressingMode::DirectPageIndirectIndexedByY, 2}, // D1
{&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // D2 {&CPU::CMP, 5, "cmp", AddressingMode::DirectPageIndirect, 2}, // D2
{&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // D3 {&CPU::CMP, 7, "cmp", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // D3
{&CPU::BRK, 7, "pei #-#", AddressingMode::Implied, 2}, // D4 {&CPU::BRK, 7, "pei #-#", AddressingMode::Implied, 2}, // D4
{&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // D5 {&CPU::CMP, 4, "cmp", AddressingMode::DirectPageIndexedByX, 2}, // D5
{&CPU::BRK, 7, "dec #-#", AddressingMode::Implied, 2}, // D6 {&CPU::DEC, 6, "dec", AddressingMode::DirectPageIndexedByX, 2}, // D6
{&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // D7 {&CPU::CMP, 6, "cmp", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // D7
{&CPU::CLD, 27, "cld", AddressingMode::Implied, 2}, // D8 {&CPU::CLD, 2, "cld", AddressingMode::Implied, 2}, // D8
{&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // D9 {&CPU::CMP, 4, "cmp", AddressingMode::AbsoluteIndexedByY, 3}, // D9
{&CPU::PHX, 3, "phx", AddressingMode::Implied, 1}, // DA {&CPU::PHX, 3, "phx", AddressingMode::Implied, 1}, // DA
{&CPU::BRK, 7, "stp #-#", AddressingMode::Implied, 2}, // DB {&CPU::BRK, 7, "stp #-#", AddressingMode::Implied, 2}, // DB
{&CPU::JML, 7, "jml", AddressingMode::AbsoluteIndirectLong, 2}, // DC {&CPU::JML, 7, "jml", AddressingMode::AbsoluteIndirectLong, 2}, // DC
{&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // DD {&CPU::CMP, 4, "cmp", AddressingMode::AbsoluteIndexedByX, 3}, // DD
{&CPU::BRK, 7, "dec #-#", AddressingMode::Implied, 2}, // DE {&CPU::DEC, 7, "dec", AddressingMode::AbsoluteIndexedByX, 3}, // DE
{&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // DF {&CPU::CMP, 5, "cmp", AddressingMode::AbsoluteIndexedByXLong, 4}, // DF
{&CPU::BRK, 7, "cpx #-#", AddressingMode::Implied, 2}, // E0 {&CPU::CPX, 2, "cpx", AddressingMode::ImmediateForX, 2}, // E0
{&CPU::SBC, 6, "sbc", AddressingMode::DirectPageIndirectIndexedByX, 2}, // E1 {&CPU::SBC, 6, "sbc", AddressingMode::DirectPageIndirectIndexedByX, 2}, // E1
{&CPU::SEP, 3, "sep", AddressingMode::Immediate8bits, 2}, // E2 {&CPU::SEP, 3, "sep", AddressingMode::Immediate8bits, 2}, // E2
{&CPU::SBC, 4, "sbc", AddressingMode::StackRelative, 2}, // E3 {&CPU::SBC, 4, "sbc", AddressingMode::StackRelative, 2}, // E3
{&CPU::BRK, 7, "cpx #-#", AddressingMode::Implied, 2}, // E4 {&CPU::CPX, 3, "cpx", AddressingMode::DirectPage, 2}, // E4
{&CPU::SBC, 3, "sbc", AddressingMode::DirectPage, 2}, // E5 {&CPU::SBC, 3, "sbc", AddressingMode::DirectPage, 2}, // E5
{&CPU::BRK, 7, "inc #-#", AddressingMode::Implied, 2}, // E6 {&CPU::INC, 5, "inc", AddressingMode::DirectPage, 2}, // E6
{&CPU::SBC, 6, "sbc", AddressingMode::DirectPageIndirectLong, 2}, // E7 {&CPU::SBC, 6, "sbc", AddressingMode::DirectPageIndirectLong, 2}, // E7
{&CPU::INX, 2, "inx", AddressingMode::Implied, 1}, // E8 {&CPU::INX, 2, "inx", AddressingMode::Implied, 1}, // E8
{&CPU::SBC, 2, "sbc", AddressingMode::ImmediateForA, 2}, // E9 {&CPU::SBC, 2, "sbc", AddressingMode::ImmediateForA, 2}, // E9
{&CPU::NOP, 2, "nop", AddressingMode::Implied, 1}, // EA {&CPU::NOP, 2, "nop", AddressingMode::Implied, 1}, // EA
{&CPU::BRK, 7, "xba #-#", AddressingMode::Implied, 2}, // EB {&CPU::XBA, 3, "xba", AddressingMode::Implied, 1}, // EB
{&CPU::BRK, 7, "cpx #-#", AddressingMode::Implied, 2}, // EC {&CPU::CPX, 4, "cpx", AddressingMode::Absolute, 3}, // EC
{&CPU::SBC, 4, "sbc", AddressingMode::Absolute, 3}, // ED {&CPU::SBC, 4, "sbc", AddressingMode::Absolute, 3}, // ED
{&CPU::BRK, 7, "inc #-#", AddressingMode::Implied, 2}, // EE {&CPU::INC, 6, "inc", AddressingMode::Absolute, 3}, // EE
{&CPU::SBC, 5, "sbc", AddressingMode::AbsoluteLong, 4}, // EF {&CPU::SBC, 5, "sbc", AddressingMode::AbsoluteLong, 4}, // EF
{&CPU::BEQ, 2, "beq", AddressingMode::Implied, 2}, // F0 {&CPU::BEQ, 2, "beq", AddressingMode::Immediate8bits, 2}, // F0
{&CPU::SBC, 5, "sbc", AddressingMode::DirectPageIndirectIndexedByY, 2}, // F1 {&CPU::SBC, 5, "sbc", AddressingMode::DirectPageIndirectIndexedByY, 2}, // F1
{&CPU::SBC, 5, "sbc", AddressingMode::DirectPageIndirect, 2}, // F2 {&CPU::SBC, 5, "sbc", AddressingMode::DirectPageIndirect, 2}, // F2
{&CPU::SBC, 7, "sbc", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // F3 {&CPU::SBC, 7, "sbc", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // F3
{&CPU::BRK, 7, "pea #-#", AddressingMode::Implied, 2}, // F4 {&CPU::BRK, 7, "pea #-#", AddressingMode::Implied, 2}, // F4
{&CPU::SBC, 4, "sbc", AddressingMode::DirectPageIndexedByX, 2}, // F5 {&CPU::SBC, 4, "sbc", AddressingMode::DirectPageIndexedByX, 2}, // F5
{&CPU::BRK, 7, "inc #-#", AddressingMode::Implied, 2}, // F6 {&CPU::INC, 6, "inc", AddressingMode::DirectPageIndexedByX, 2}, // F6
{&CPU::SBC, 6, "sbc", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // F7 {&CPU::SBC, 6, "sbc", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // F7
{&CPU::SED, 2, "sed", AddressingMode::Implied, 1}, // F8 {&CPU::SED, 2, "sed", AddressingMode::Implied, 1}, // F8
{&CPU::SBC, 4, "sbc", AddressingMode::AbsoluteIndexedByY, 3}, // F9 {&CPU::SBC, 4, "sbc", AddressingMode::AbsoluteIndexedByY, 3}, // F9
@@ -634,7 +677,7 @@ namespace ComSquare::CPU
{&CPU::XCE, 2, "xce", AddressingMode::Implied, 1}, // FB {&CPU::XCE, 2, "xce", AddressingMode::Implied, 1}, // FB
{&CPU::JSR, 8, "jsr", AddressingMode::AbsoluteIndirectIndexedByX, 3}, // FC {&CPU::JSR, 8, "jsr", AddressingMode::AbsoluteIndirectIndexedByX, 3}, // FC
{&CPU::SBC, 4, "sbc", AddressingMode::AbsoluteIndexedByX, 3}, // FD {&CPU::SBC, 4, "sbc", AddressingMode::AbsoluteIndexedByX, 3}, // FD
{&CPU::BRK, 7, "inc #-#", AddressingMode::Implied, 2}, // FE {&CPU::INC, 7, "inc", AddressingMode::AbsoluteIndexedByX, 3}, // FE
{&CPU::SBC, 5, "sbc", AddressingMode::AbsoluteIndexedByXLong, 4}, // FF {&CPU::SBC, 5, "sbc", AddressingMode::AbsoluteIndexedByXLong, 4}, // FF
}; };
public: public:

View File

@@ -41,9 +41,6 @@ namespace ComSquare::CPU
StackRelativeIndirectIndexedByY, StackRelativeIndirectIndexedByY,
ProgramCounterRelative,
ProgramCounterRelativeLong,
AbsoluteIndirect, AbsoluteIndirect,
AbsoluteIndirectIndexedByX, AbsoluteIndirectIndexedByX,

View File

@@ -2,42 +2,29 @@
// Created by anonymus-raccoon on 2/20/20. // Created by anonymus-raccoon on 2/20/20.
// //
#include <iostream>
#include "../../Models/Int24.hpp" #include "../../Models/Int24.hpp"
#include "../CPU.hpp" #include "../CPU.hpp"
namespace ComSquare::CPU namespace ComSquare::CPU
{ {
int CPU::AND(uint24_t valueAddr, AddressingMode mode) int CPU::TSB(uint24_t valueAddr, AddressingMode mode)
{ {
unsigned negativeMask = this->_isEmulationMode ? 0x80u : 0x8000u; uint16_t value = this->_bus->read(valueAddr);
unsigned value = this->_bus->read(valueAddr);
if (!this->_registers.p.m) if (!this->_registers.p.m)
value += this->_bus->read(valueAddr + 1) << 8u; value += this->_bus->read(valueAddr + 1) << 8u;
value |= this->_registers.a;
this->_bus->write(valueAddr, value);
if (!this->_registers.p.m)
this->_bus->write(valueAddr + 1, value >> 8u);
this->_registers.a &= value; this->_registers.p.z = value == 0;
this->_registers.p.n = this->_registers.a & negativeMask;
this->_registers.p.z = this->_registers.a == 0;
int cycles = !this->_registers.p.m; int cycles = 0;
switch (mode) { if (!this->_registers.p.m)
case DirectPage: cycles += 2;
case DirectPageIndirect: if (mode == DirectPage)
case DirectPageIndirectLong:
case DirectPageIndexedByX:
case DirectPageIndirectIndexedByX:
case DirectPageIndirectIndexedByYLong:
cycles += this->_registers.dl != 0; cycles += this->_registers.dl != 0;
break;
case AbsoluteIndexedByX:
case AbsoluteIndexedByY:
cycles += this->_hasIndexCrossedPageBoundary;
break;
case DirectPageIndirectIndexedByY:
cycles += this->_registers.dl != 0 + this->_hasIndexCrossedPageBoundary;
break;
default:
break;
}
return cycles; return cycles;
} }
} }

View File

@@ -199,72 +199,6 @@ namespace ComSquare::CPU
return 0; return 0;
} }
int CPU::INX(uint24_t, AddressingMode)
{
this->_registers.x++;
if (this->_registers.p.x_b)
this->_registers.x %= 0x100;
unsigned negativeFlag = this->_registers.p.x_b ? 0x80u : 0x8000u;
this->_registers.p.z = this->_registers.x == 0;
this->_registers.p.n = this->_registers.x & negativeFlag;
return 0;
}
int CPU::INY(uint24_t, AddressingMode)
{
this->_registers.y++;
if (this->_registers.p.x_b)
this->_registers.y %= 0x100;
unsigned negativeFlag = this->_registers.p.x_b ? 0x80u : 0x8000u;
this->_registers.p.z = this->_registers.y == 0;
this->_registers.p.n = this->_registers.y & negativeFlag;
return 0;
}
int CPU::CPX(uint24_t valueAddr, AddressingMode mode)
{
unsigned value = this->_bus->read(valueAddr++);
if (this->_registers.p.x_b) {
uint8_t x = this->_registers.x;
x -= value;
this->_registers.p.z = x == 0;
this->_registers.p.n = x & 0x80u;
} else {
value += this->_bus->read(valueAddr) << 8u;
uint16_t x = this->_registers.x;
x -= value;
this->_registers.p.z = x == 0;
this->_registers.p.n = x & 0x8000u;
}
this->_registers.p.c = this->_registers.x >= value;
return !this->_registers.p.x_b + (mode == DirectPage && this->_registers.dl != 0);
}
int CPU::CPY(uint24_t valueAddr, AddressingMode mode)
{
unsigned value = this->_bus->read(valueAddr++);
this->_registers.p.c = this->_registers.y >= value;
if (this->_registers.p.x_b) {
uint8_t y = this->_registers.y;
y -= value;
this->_registers.p.z = y == 0;
this->_registers.p.n = y & 0x80u;
} else {
value += this->_bus->read(valueAddr) << 8u;
uint16_t y = this->_registers.y;
y -= value;
this->_registers.p.z = y == 0;
this->_registers.p.n = y & 0x8000u;
}
return !this->_registers.p.x_b + (mode == DirectPage && this->_registers.dl != 0);
}
int CPU::BCC(uint24_t valueAddr, AddressingMode) int CPU::BCC(uint24_t valueAddr, AddressingMode)
{ {
if (!this->_registers.p.c) if (!this->_registers.p.c)
@@ -352,4 +286,17 @@ namespace ComSquare::CPU
{ {
return 0; return 0;
} }
int CPU::RTS(uint24_t, AddressingMode)
{
this->_registers.pc = this->_pop16() + 1;
return 0;
}
int CPU::RTL(uint24_t, AddressingMode)
{
this->_registers.pc = this->_pop16() + 1;
this->_registers.dbr = this->_pop();
return 0;
}
} }

View File

@@ -24,16 +24,14 @@ namespace ComSquare::CPU
int CPU::BRK(uint24_t, AddressingMode) int CPU::BRK(uint24_t, AddressingMode)
{ {
if (this->_isEmulationMode) { if (this->_isEmulationMode) {
this->_registers.pc += 2;
this->_push(this->_registers.pc); this->_push(this->_registers.pc);
this->_registers.p.x_b = true;
this->_push(this->_registers.p.flags); this->_push(this->_registers.p.flags);
this->_registers.p.i = true; this->_registers.p.i = true;
this->_registers.p.d = false; this->_registers.p.d = false;
this->_registers.pbr = 0x0;
this->_registers.pc = this->_cartridgeHeader.emulationInterrupts.brk; this->_registers.pc = this->_cartridgeHeader.emulationInterrupts.brk;
} else { } else {
this->_push(this->_registers.pbr); this->_push(this->_registers.pbr);
this->_registers.pc += 2;
this->_push(this->_registers.pc); this->_push(this->_registers.pc);
this->_push(this->_registers.p.flags); this->_push(this->_registers.p.flags);
this->_registers.p.i = true; this->_registers.p.i = true;
@@ -47,16 +45,14 @@ namespace ComSquare::CPU
int CPU::COP(uint24_t, AddressingMode) int CPU::COP(uint24_t, AddressingMode)
{ {
if (this->_isEmulationMode) { if (this->_isEmulationMode) {
this->_registers.pc += 2;
this->_push(this->_registers.pc); this->_push(this->_registers.pc);
this->_push(this->_registers.p.flags); this->_push(this->_registers.p.flags);
this->_registers.p.i = true; this->_registers.p.i = true;
this->_registers.p.d = false; this->_registers.p.d = false;
this->_registers.pbr = 0x0;
this->_registers.pc = this->_cartridgeHeader.emulationInterrupts.cop; this->_registers.pc = this->_cartridgeHeader.emulationInterrupts.cop;
} else { } else {
this->_push(this->_registers.pbr); this->_push(this->_registers.pbr);
this->_registers.pc += 2;
this->_push(this->_registers.pc); this->_push(this->_registers.pc);
this->_push(this->_registers.p.flags); this->_push(this->_registers.p.flags);
this->_registers.p.i = true; this->_registers.p.i = true;

View File

@@ -12,8 +12,8 @@ namespace ComSquare::CPU
unsigned value = this->_bus->read(valueAddr) + this->_registers.p.c; unsigned value = this->_bus->read(valueAddr) + this->_registers.p.c;
if (!this->_registers.p.m) if (!this->_registers.p.m)
value += this->_bus->read(valueAddr + 1) << 8u; value += this->_bus->read(valueAddr + 1) << 8u;
unsigned negativeMask = this->_isEmulationMode ? 0x80u : 0x8000u; unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u;
unsigned maxValue = this->_isEmulationMode ? UINT8_MAX : UINT16_MAX; unsigned maxValue = this->_registers.p.m ? UINT8_MAX : UINT16_MAX;
this->_registers.p.c = static_cast<unsigned>(this->_registers.a) + value > maxValue; this->_registers.p.c = static_cast<unsigned>(this->_registers.a) + value > maxValue;
if ((this->_registers.a & negativeMask) == (value & negativeMask)) if ((this->_registers.a & negativeMask) == (value & negativeMask))
@@ -21,7 +21,7 @@ namespace ComSquare::CPU
else else
this->_registers.p.v = false; this->_registers.p.v = false;
this->_registers.a += value; this->_registers.a += value;
if (this->_isEmulationMode) if (this->_registers.p.m)
this->_registers.a %= 0x100; this->_registers.a %= 0x100;
this->_registers.p.z = this->_registers.a == 0; this->_registers.p.z = this->_registers.a == 0;
this->_registers.p.n = this->_registers.a & negativeMask; this->_registers.p.n = this->_registers.a & negativeMask;
@@ -51,7 +51,7 @@ namespace ComSquare::CPU
int CPU::SBC(uint24_t valueAddr, AddressingMode mode) int CPU::SBC(uint24_t valueAddr, AddressingMode mode)
{ {
unsigned negativeMask = this->_isEmulationMode ? 0x80u : 0x8000u; unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u;
unsigned value = this->_bus->read(valueAddr); unsigned value = this->_bus->read(valueAddr);
if (!this->_registers.p.m) if (!this->_registers.p.m)
value += this->_bus->read(valueAddr + 1) << 8u; value += this->_bus->read(valueAddr + 1) << 8u;
@@ -63,7 +63,7 @@ namespace ComSquare::CPU
else else
this->_registers.p.v = false; this->_registers.p.v = false;
this->_registers.a += ~value + oldCarry; this->_registers.a += ~value + oldCarry;
if (this->_isEmulationMode) if (this->_registers.p.m)
this->_registers.a %= 0x100; this->_registers.a %= 0x100;
this->_registers.p.z = this->_registers.a == 0; this->_registers.p.z = this->_registers.a == 0;
this->_registers.p.n = this->_registers.a & negativeMask; this->_registers.p.n = this->_registers.a & negativeMask;
@@ -90,4 +90,322 @@ namespace ComSquare::CPU
} }
return cycles; return cycles;
} }
int CPU::ORA(uint24_t valueAddr, AddressingMode mode)
{
unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u;
unsigned value = this->_bus->read(valueAddr);
if (!this->_registers.p.m)
value += this->_bus->read(valueAddr + 1) << 8u;
this->_registers.a |= value;
this->_registers.p.z = this->_registers.a == 0;
this->_registers.p.n = this->_registers.a & negativeMask;
int cycles = !this->_registers.p.m;
switch (mode) {
case DirectPage:
case DirectPageIndirect:
case DirectPageIndirectLong:
case DirectPageIndexedByX:
case DirectPageIndirectIndexedByX:
case DirectPageIndirectIndexedByYLong:
cycles += this->_registers.dl != 0;
break;
case AbsoluteIndexedByX:
case AbsoluteIndexedByY:
cycles += this->_hasIndexCrossedPageBoundary;
break;
case DirectPageIndirectIndexedByY:
cycles += this->_registers.dl != 0 + this->_hasIndexCrossedPageBoundary;
break;
default:
break;
}
return cycles;
}
int CPU::DEX(uint24_t, AddressingMode)
{
unsigned negativeMask = this->_registers.p.x_b ? 0x80 : 0x8000;
this->_registers.x--;
if (this->_registers.p.x_b)
this->_registers.xh = 0;
this->_registers.p.z = this->_registers.x == 0;
this->_registers.p.n = this->_registers.x & negativeMask;
return 0;
}
int CPU::DEY(uint24_t, AddressingMode)
{
unsigned negativeMask = this->_registers.p.x_b ? 0x80 : 0x8000;
this->_registers.y--;
if (this->_registers.p.x_b)
this->_registers.yh = 0;
this->_registers.p.z = this->_registers.y == 0;
this->_registers.p.n = this->_registers.y & negativeMask;
return 0;
}
int CPU::CMP(uint24_t valueAddr, AddressingMode mode)
{
unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u;
unsigned value = this->_bus->read(valueAddr);
if (!this->_registers.p.m)
value += this->_bus->read(valueAddr + 1) << 8u;
unsigned result = this->_registers.a - value;
if (this->_registers.p.m)
result %= 0x100;
this->_registers.p.n = result & negativeMask;
this->_registers.p.z = result == 0;
this->_registers.p.c = this->_registers.a >= result;
int cycles = !this->_registers.p.m;
switch (mode) {
case DirectPage:
case DirectPageIndirect:
case DirectPageIndirectLong:
case DirectPageIndexedByX:
case DirectPageIndirectIndexedByX:
case DirectPageIndirectIndexedByYLong:
cycles += this->_registers.dl != 0;
break;
case AbsoluteIndexedByX:
case AbsoluteIndexedByY:
cycles += this->_hasIndexCrossedPageBoundary;
break;
case DirectPageIndirectIndexedByY:
cycles += this->_registers.dl != 0 + this->_hasIndexCrossedPageBoundary;
break;
default:
break;
}
return cycles;
}
int CPU::INX(uint24_t, AddressingMode)
{
this->_registers.x++;
if (this->_registers.p.x_b)
this->_registers.x %= 0x100;
unsigned negativeFlag = this->_registers.p.x_b ? 0x80u : 0x8000u;
this->_registers.p.z = this->_registers.x == 0;
this->_registers.p.n = this->_registers.x & negativeFlag;
return 0;
}
int CPU::INY(uint24_t, AddressingMode)
{
this->_registers.y++;
if (this->_registers.p.x_b)
this->_registers.y %= 0x100;
unsigned negativeFlag = this->_registers.p.x_b ? 0x80u : 0x8000u;
this->_registers.p.z = this->_registers.y == 0;
this->_registers.p.n = this->_registers.y & negativeFlag;
return 0;
}
int CPU::CPX(uint24_t valueAddr, AddressingMode mode)
{
unsigned value = this->_bus->read(valueAddr++);
if (this->_registers.p.x_b) {
uint8_t x = this->_registers.x;
x -= value;
this->_registers.p.z = x == 0;
this->_registers.p.n = x & 0x80u;
} else {
value += this->_bus->read(valueAddr) << 8u;
uint16_t x = this->_registers.x;
x -= value;
this->_registers.p.z = x == 0;
this->_registers.p.n = x & 0x8000u;
}
this->_registers.p.c = this->_registers.x >= value;
return !this->_registers.p.x_b + (mode == DirectPage && this->_registers.dl != 0);
}
int CPU::CPY(uint24_t valueAddr, AddressingMode mode)
{
unsigned value = this->_bus->read(valueAddr++);
this->_registers.p.c = this->_registers.y >= value;
if (this->_registers.p.x_b) {
uint8_t y = this->_registers.y;
y -= value;
this->_registers.p.z = y == 0;
this->_registers.p.n = y & 0x80u;
} else {
value += this->_bus->read(valueAddr) << 8u;
uint16_t y = this->_registers.y;
y -= value;
this->_registers.p.z = y == 0;
this->_registers.p.n = y & 0x8000u;
}
return !this->_registers.p.x_b + (mode == DirectPage && this->_registers.dl != 0);
}
int CPU::AND(uint24_t valueAddr, AddressingMode mode)
{
unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u;
unsigned value = this->_bus->read(valueAddr);
if (!this->_registers.p.m)
value += this->_bus->read(valueAddr + 1) << 8u;
this->_registers.a &= value;
this->_registers.p.n = this->_registers.a & negativeMask;
this->_registers.p.z = this->_registers.a == 0;
int cycles = !this->_registers.p.m;
switch (mode) {
case DirectPage:
case DirectPageIndirect:
case DirectPageIndirectLong:
case DirectPageIndexedByX:
case DirectPageIndirectIndexedByX:
case DirectPageIndirectIndexedByYLong:
cycles += this->_registers.dl != 0;
break;
case AbsoluteIndexedByX:
case AbsoluteIndexedByY:
cycles += this->_hasIndexCrossedPageBoundary;
break;
case DirectPageIndirectIndexedByY:
cycles += this->_registers.dl != 0 + this->_hasIndexCrossedPageBoundary;
break;
default:
break;
}
return cycles;
}
int CPU::INC(uint24_t valueAddr, AddressingMode mode)
{
unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u;
unsigned result;
if (mode == Implied) {
this->_registers.a++;
if (this->_registers.p.m)
this->_registers.ah = 0;
result = this->_registers.a;
} else if (!this->_registers.p.m) {
result = this->_bus->read(valueAddr);
result += this->_bus->read(valueAddr + 1) << 8u;
result = (uint16_t)(result + 1);
this->_bus->write(valueAddr, result);
this->_bus->write(valueAddr + 1, result << 8u);
} else {
result = this->_bus->read(valueAddr);
result = (uint8_t)(result + 1);
this->_bus->write(valueAddr, result);
}
this->_registers.p.z = result == 0;
this->_registers.p.n = result & negativeMask;
switch (mode) {
case Implied:
return 0;
case Absolute:
return this->_registers.p.m == 0 ? 2 : 0;
case DirectPage:
case DirectPageIndexedByX:
return (this->_registers.p.m == 0 ? 2 : 0) + this->_registers.dl != 0 ;
case AbsoluteIndexedByX:
return (this->_registers.p.m == 0 ? 2 : 0) + this->_hasIndexCrossedPageBoundary;
default:
return 0;
}
}
int CPU::DEC(uint24_t valueAddr, AddressingMode mode)
{
unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u;
unsigned result;
if (mode == Implied) {
this->_registers.a--;
if (this->_registers.p.m)
this->_registers.ah = 0;
result = this->_registers.a;
} else if (!this->_registers.p.m) {
result = this->_bus->read(valueAddr);
result += this->_bus->read(valueAddr + 1) << 8u;
result = (uint16_t)(result - 1);
this->_bus->write(valueAddr, result);
this->_bus->write(valueAddr + 1, result << 8u);
} else {
result = this->_bus->read(valueAddr);
result = (uint8_t)(result - 1);
this->_bus->write(valueAddr, result);
}
this->_registers.p.z = result == 0;
this->_registers.p.n = result & negativeMask;
switch (mode) {
case Implied:
return 0;
case Absolute:
return this->_registers.p.m == 0 ? 2 : 0;
case DirectPage:
case DirectPageIndexedByX:
return (this->_registers.p.m == 0 ? 2 : 0) + this->_registers.dl != 0 ;
case AbsoluteIndexedByX:
return (this->_registers.p.m == 0 ? 2 : 0) + this->_hasIndexCrossedPageBoundary;
default:
return 0;
}
}
int CPU::EOR(uint24_t valueAddr, AddressingMode mode)
{
unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u;
unsigned value = this->_bus->read(valueAddr);
if (!this->_registers.p.m)
value += this->_bus->read(valueAddr + 1) << 8u;
this->_registers.a ^= value;
this->_registers.p.z = this->_registers.a == 0;
this->_registers.p.n = this->_registers.a & negativeMask;
int cycles = !this->_registers.p.m;
switch (mode) {
case DirectPage:
case DirectPageIndirect:
case DirectPageIndirectLong:
case DirectPageIndexedByX:
case DirectPageIndirectIndexedByX:
case DirectPageIndirectIndexedByYLong:
cycles += this->_registers.dl != 0;
break;
case AbsoluteIndexedByX:
case AbsoluteIndexedByY:
cycles += this->_hasIndexCrossedPageBoundary;
break;
case DirectPageIndirectIndexedByY:
cycles += this->_registers.dl != 0 + this->_hasIndexCrossedPageBoundary;
break;
default:
break;
}
return cycles;
}
int CPU::XBA(uint24_t, AddressingMode)
{
int tmp = this->_registers.ah;
this->_registers.ah = this->_registers.al;
this->_registers.al = tmp;
this->_registers.p.n = this->_registers.al & 0x80u;
this->_registers.p.z = this->_registers.al == 0;
return 0;
}
} }

View File

@@ -48,4 +48,106 @@ namespace ComSquare::CPU
} }
return 0; return 0;
} }
int CPU::TCD(uint24_t, AddressingMode)
{
this->_registers.d = this->_registers.a;
this->_registers.p.n = this->_registers.d & 0x8000u;
this->_registers.p.z = this->_registers.d == 0;
return 0;
}
int CPU::TCS(uint24_t, AddressingMode)
{
this->_registers.s = this->_registers.a;
if (this->_isEmulationMode)
this->_registers.sh = 1;
return 0;
}
int CPU::TDC(uint24_t, AddressingMode)
{
this->_registers.a = this->_registers.d;
this->_registers.p.n = this->_registers.a & 0x8000u;
this->_registers.p.z = this->_registers.a == 0;
return 0;
}
int CPU::TSC(uint24_t, AddressingMode)
{
this->_registers.a = this->_registers.s;
this->_registers.p.n = this->_registers.a & 0x8000u;
this->_registers.p.z = this->_registers.a == 0;
return 0;
}
int CPU::TSX(uint24_t, AddressingMode)
{
unsigned negativeFlag = this->_registers.p.x_b ? 0x80u : 0x8000u;
this->_registers.x = this->_registers.s;
if (this->_registers.p.x_b)
this->_registers.xh = 0;
this->_registers.p.n = this->_registers.x & negativeFlag;
this->_registers.p.z = this->_registers.x == 0;
return 0;
}
int CPU::TXA(uint24_t, AddressingMode)
{
unsigned negativeFlag = this->_registers.p.m ? 0x80u : 0x8000u;
if (this->_registers.p.m)
this->_registers.al = this->_registers.xl;
else {
this->_registers.a = this->_registers.x;
if (this->_registers.p.x_b)
this->_registers.ah = 0;
}
this->_registers.p.n = this->_registers.a & negativeFlag;
this->_registers.p.z = this->_registers.a == 0;
return 0;
}
int CPU::TYA(uint24_t, AddressingMode)
{
unsigned negativeFlag = this->_registers.p.m ? 0x80u : 0x8000u;
if (this->_registers.p.m)
this->_registers.al = this->_registers.yl;
else {
this->_registers.a = this->_registers.y;
if (this->_registers.p.x_b)
this->_registers.ah = 0;
}
this->_registers.p.n = this->_registers.a & negativeFlag;
this->_registers.p.z = this->_registers.a == 0;
return 0;
}
int CPU::TXY(uint24_t, AddressingMode)
{
unsigned negativeFlag = this->_registers.p.x_b ? 0x80u : 0x8000u;
if (this->_registers.p.x_b)
this->_registers.yl = this->_registers.xl;
else
this->_registers.y = this->_registers.x;
this->_registers.p.n = this->_registers.y & negativeFlag;
this->_registers.p.z = this->_registers.y == 0;
return 0;
}
int CPU::TYX(uint24_t, AddressingMode)
{
unsigned negativeFlag = this->_registers.p.x_b ? 0x80u : 0x8000u;
if (this->_registers.p.x_b)
this->_registers.xl = this->_registers.yl;
else
this->_registers.x = this->_registers.y;
this->_registers.p.n = this->_registers.y & negativeFlag;
this->_registers.p.z = this->_registers.y == 0;
return 0;
}
} }

View File

@@ -3,9 +3,9 @@
// //
#include "CPUDebug.hpp" #include "CPUDebug.hpp"
#include "../Utility/Utility.hpp" #include "../../Utility/Utility.hpp"
#include "../Exceptions/InvalidOpcode.hpp" #include "../../Exceptions/InvalidOpcode.hpp"
#include "../CPU/CPU.hpp" #include "../../CPU/CPU.hpp"
#include <QtEvents> #include <QtEvents>
#include <QPainter> #include <QPainter>
#include <iostream> #include <iostream>
@@ -21,6 +21,7 @@ namespace ComSquare::Debugger
_ui(), _ui(),
_model(*this), _model(*this),
_painter(*this), _painter(*this),
_stackModel(*this->_bus, *this),
_snes(snes) _snes(snes)
{ {
this->_window->setContextMenuPolicy(Qt::NoContextMenu); this->_window->setContextMenuPolicy(Qt::NoContextMenu);
@@ -29,14 +30,26 @@ namespace ComSquare::Debugger
this->_ui.setupUi(this->_window); this->_ui.setupUi(this->_window);
this->_updateDisassembly(0xFFFF - this->_registers.pc); //Parse the first page of the ROM (the code can't reach the second page without a jump). this->_updateDisassembly(this->_cartridgeHeader.emulationInterrupts.reset, 0xFFFF - this->_cartridgeHeader.emulationInterrupts.reset); //Parse the first page of the ROM (the code can't reach the second page without a jump).
this->_ui.disassembly->setModel(&this->_model); this->_ui.disassembly->setModel(&this->_model);
this->_ui.disassembly->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
this->_ui.disassembly->horizontalHeader()->setStretchLastSection(true); this->_ui.disassembly->horizontalHeader()->setStretchLastSection(true);
this->_ui.disassembly->resizeColumnsToContents();
this->_ui.disassembly->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed); this->_ui.disassembly->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);
this->_ui.disassembly->verticalHeader()->setHighlightSections(false); this->_ui.disassembly->verticalHeader()->setHighlightSections(false);
this->_ui.disassembly->setItemDelegate(&this->_painter); this->_ui.disassembly->setItemDelegate(&this->_painter);
this->_ui.stackView->setModel(&this->_stackModel);
this->_ui.stackView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
this->_ui.stackView->verticalHeader()->setSectionResizeMode (QHeaderView::Fixed);
this->_ui.stackView->verticalHeader()->setHighlightSections(false);
this->_ui.history->setModel(&this->_historyModel);
this->_ui.history->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
this->_ui.history->horizontalHeader()->setStretchLastSection(true);
this->_ui.history->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);
this->_ui.history->verticalHeader()->hide();
QMainWindow::connect(this->_ui.actionPause, &QAction::triggered, this, &CPUDebug::pause); QMainWindow::connect(this->_ui.actionPause, &QAction::triggered, this, &CPUDebug::pause);
QMainWindow::connect(this->_ui.actionStep, &QAction::triggered, this, &CPUDebug::step); QMainWindow::connect(this->_ui.actionStep, &QAction::triggered, this, &CPUDebug::step);
QMainWindow::connect(this->_ui.actionNext, &QAction::triggered, this, &CPUDebug::next); QMainWindow::connect(this->_ui.actionNext, &QAction::triggered, this, &CPUDebug::next);
@@ -44,6 +57,7 @@ namespace ComSquare::Debugger
QMainWindow::connect(this->_ui.disassembly->verticalHeader(), &QHeaderView::sectionClicked, this, &CPUDebug::toggleBreakpoint); QMainWindow::connect(this->_ui.disassembly->verticalHeader(), &QHeaderView::sectionClicked, this, &CPUDebug::toggleBreakpoint);
this->_window->show(); this->_window->show();
this->_updateRegistersPanel(); this->_updateRegistersPanel();
this->_updateDisassembly(this->_registers.pac, 0);
} }
bool CPUDebug::isDebugger() bool CPUDebug::isDebugger()
@@ -65,7 +79,7 @@ namespace ComSquare::Debugger
return 0xFF; return 0xFF;
if (this->_isStepping) { if (this->_isStepping) {
cycles = this->_executeInstruction(this->readPC()); cycles = this->_executeInstruction(this->readPC());
this->_updateDisassembly(); this->_updateDisassembly(this->_registers.pac);
return cycles; return cycles;
} }
@@ -102,7 +116,10 @@ namespace ComSquare::Debugger
uint24_t pc = (this->_registers.pbr << 16u) | (this->_registers.pc - 1u); uint24_t pc = (this->_registers.pbr << 16u) | (this->_registers.pc - 1u);
DisassemblyContext ctx = this->_getDisassemblyContext(); DisassemblyContext ctx = this->_getDisassemblyContext();
DisassembledInstruction instruction = this->_parseInstruction(pc, ctx); DisassembledInstruction instruction = this->_parseInstruction(pc, ctx);
this->_ui.logger->append((instruction.toString() + " - " + Utility::to_hex(opcode)).c_str()); this->_registers.pc--;
this->_historyModel.log({opcode, instruction.name, instruction.argument, this->getProceededParameters()});
this->_ui.history->scrollToBottom();
this->_registers.pc++;
unsigned ret = CPU::_executeInstruction(opcode); unsigned ret = CPU::_executeInstruction(opcode);
this->_updateRegistersPanel(); this->_updateRegistersPanel();
return ret; return ret;
@@ -115,7 +132,7 @@ namespace ComSquare::Debugger
this->_ui.actionPause->setText("Resume"); this->_ui.actionPause->setText("Resume");
else else
this->_ui.actionPause->setText("Pause"); this->_ui.actionPause->setText("Pause");
this->_updateDisassembly(); this->_updateDisassembly(this->_registers.pac);
} }
void CPUDebug::step() void CPUDebug::step()
@@ -164,8 +181,20 @@ namespace ComSquare::Debugger
this->_ui.xIndexLineEdit->setText(Utility::to_hex(this->_registers.xl).c_str()); this->_ui.xIndexLineEdit->setText(Utility::to_hex(this->_registers.xl).c_str());
this->_ui.yIndexLineEdit->setText(Utility::to_hex(this->_registers.yl).c_str()); this->_ui.yIndexLineEdit->setText(Utility::to_hex(this->_registers.yl).c_str());
} }
this->_ui.flagsLineEdit->setText(this->_getFlagsString().c_str());
this->_ui.emulationModeCheckBox->setCheckState(this->_isEmulationMode ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); this->_ui.emulationModeCheckBox->setCheckState(this->_isEmulationMode ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
this->_ui.mCheckbox->setCheckState(this->_registers.p.m ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
this->_ui.xCheckbox->setCheckState(this->_registers.p.x_b ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
this->_ui.bCheckbox->setCheckState(this->_registers.p.x_b ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
this->_ui.iCheckbox->setCheckState(this->_registers.p.i ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
this->_ui.vCheckbox->setCheckState(this->_registers.p.v ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
this->_ui.dCheckbox->setCheckState(this->_registers.p.d ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
this->_ui.cCheckbox->setCheckState(this->_registers.p.c ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
this->_ui.zCheckbox->setCheckState(this->_registers.p.z ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
this->_ui.nCheckbox->setCheckState(this->_registers.p.n ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
auto index = this->_stackModel.index(this->_registers.s / 2, 0);
this->_ui.stackView->scrollTo(index, QAbstractItemView::PositionAtCenter);
} }
std::string CPUDebug::_getFlagsString() std::string CPUDebug::_getFlagsString()
@@ -187,166 +216,44 @@ namespace ComSquare::Debugger
void CPUDebug::clearHistory() void CPUDebug::clearHistory()
{ {
this->_ui.logger->clear(); this->_historyModel.clear();
} }
void CPUDebug::_updateDisassembly(uint24_t refreshSize) void CPUDebug::_updateDisassembly(uint24_t start, uint24_t refreshSize)
{ {
auto first = std::find_if(this->disassembledInstructions.begin(), this->disassembledInstructions.end(), [this](DisassembledInstruction &i) { auto first = std::find_if(this->disassembledInstructions.begin(), this->disassembledInstructions.end(), [start](DisassembledInstruction &i) {
return i.address >= this->_registers.pac; return i.address >= start;
}); });
auto end = std::find_if(this->disassembledInstructions.begin(), this->disassembledInstructions.end(),[this, refreshSize](DisassembledInstruction &i) { auto end = std::find_if(this->disassembledInstructions.begin(), this->disassembledInstructions.end(),[start, refreshSize](DisassembledInstruction &i) {
return i.address >= this->_registers.pac + refreshSize; return i.address >= start + refreshSize;
}); });
this->disassembledInstructions.erase(first, end); this->disassembledInstructions.erase(first, end);
auto next = std::find_if(this->disassembledInstructions.begin(), this->disassembledInstructions.end(), [this](DisassembledInstruction &i) { auto next = std::find_if(this->disassembledInstructions.begin(), this->disassembledInstructions.end(), [start](DisassembledInstruction &i) {
return i.address >= this->_registers.pac; return i.address >= start;
}); });
int row = next - this->disassembledInstructions.begin();
DisassemblyContext ctx = this->_getDisassemblyContext(); DisassemblyContext ctx = this->_getDisassemblyContext();
std::vector<DisassembledInstruction> nextInstructions = this->_disassemble(this->_registers.pac, refreshSize, ctx); std::vector<DisassembledInstruction> nextInstructions = this->_disassemble(start, refreshSize, ctx);
this->disassembledInstructions.insert(next, nextInstructions.begin(), nextInstructions.end()); this->disassembledInstructions.insert(next, nextInstructions.begin(), nextInstructions.end());
if (this->_ui.disassembly->rowAt(0) > row || this->_ui.disassembly->rowAt(this->_ui.disassembly->height()) < row)
this->_ui.disassembly->scrollTo(this->_model.index(row, 0), QAbstractItemView::PositionAtCenter); int row = next - this->disassembledInstructions.begin();
if (this->_ui.disassembly->rowAt(0) > row || this->_ui.disassembly->rowAt(this->_ui.disassembly->height()) < row) {
auto index = this->_model.index(row, 0);
this->_ui.disassembly->scrollTo(index, QAbstractItemView::PositionAtCenter);
}
this->_ui.disassembly->viewport()->repaint(); this->_ui.disassembly->viewport()->repaint();
} }
DisassemblyContext CPUDebug::_getDisassemblyContext() DisassemblyContext CPUDebug::_getDisassemblyContext()
{ {
return {this->_registers.p.m, this->_registers.p.x_b, false}; return {this->_registers.p.m, this->_registers.p.x_b, this->_isEmulationMode};
}
std::vector<DisassembledInstruction> CPUDebug::_disassemble(uint24_t pc, uint24_t length, DisassemblyContext &ctx)
{
std::vector<DisassembledInstruction> map;
uint24_t endAddr = pc + length;
while (pc < endAddr) {
DisassembledInstruction instruction = this->_parseInstruction(pc, ctx);
instruction.level = ctx.level;
map.push_back(instruction);
pc += instruction.size;
if (instruction.addressingMode == ImmediateForA && !ctx.mFlag)
pc++;
if (instruction.addressingMode == ImmediateForX && !ctx.xFlag)
pc++;
if (instruction.opcode == 0x40 && ctx.isEmulationMode) { // RTI
ctx.mFlag = true;
ctx.xFlag = true;
}
if (instruction.opcode == 0xC2) { // REP
if (ctx.isEmulationMode) {
ctx.mFlag = true;
ctx.xFlag = true;
} else {
uint8_t m = this->_bus->read(pc - 1);
ctx.mFlag &= ~m & 0b00100000u;
ctx.xFlag &= ~m & 0b00010000u;
}
}
if (instruction.opcode == 0xE2) { // SEP
uint8_t m = this->_bus->read(pc - 1);
ctx.mFlag |= m & 0b00100000u;
ctx.xFlag |= m & 0b00010000u;
}
if (instruction.opcode == 0x28) { // PLP
if (ctx.isEmulationMode) {
ctx.mFlag = true;
ctx.xFlag = true;
} else
ctx.level = Compromised;
}
if (instruction.opcode == 0xFB) {// XCE
ctx.level = Unsafe;
ctx.isEmulationMode = false; // The most common use of the XCE is to enable native mode at the start of the ROM so we guess that it has done that.
}
}
return map;
}
DisassembledInstruction CPUDebug::_parseInstruction(uint24_t pc, DisassemblyContext &ctx)
{
uint24_t opcode = this->_bus->read(pc, true);
Instruction instruction = this->_instructions[opcode];
std::string argument = this->_getInstructionParameter(instruction, pc + 1, ctx);
return DisassembledInstruction(instruction, pc, argument, opcode);
}
std::string CPUDebug::_getInstructionParameter(Instruction &instruction, uint24_t pc, DisassemblyContext &ctx)
{
switch (instruction.addressingMode) {
case Implied:
return "";
case ImmediateForA:
return this->_getImmediateValue(pc, !ctx.mFlag);
case ImmediateForX:
return this->_getImmediateValue(pc, !ctx.xFlag);
case Immediate8bits:
return this->_getImmediateValue(pc, false);
case Absolute:
return this->_getAbsoluteValue(pc);
case AbsoluteLong:
return this->_getAbsoluteLongValue(pc);
case DirectPage:
return this->_getDirectValue(pc);
case DirectPageIndexedByX:
return this->_getDirectIndexedByXValue(pc);
default:
return "???";
}
}
std::string CPUDebug::_getImmediateValue(uint24_t pc, bool dual)
{
unsigned value = this->_bus->read(pc, true);
if (dual)
value += this->_bus->read(pc + 1, true) << 8u;
std::stringstream ss;
ss << "#$" << std::hex << value;
return ss.str();
}
std::string CPUDebug::_getDirectValue(uint24_t pc)
{
std::stringstream ss;
ss << "$" << std::hex << static_cast<int>(this->_bus->read(pc, true));
return ss.str();
}
std::string CPUDebug::_getAbsoluteValue(uint24_t pc)
{
std::stringstream ss;
ss << "$" << std::hex << (this->_bus->read(pc) + (this->_bus->read(pc + 1, true) << 8u));
return ss.str();
}
std::string CPUDebug::_getAbsoluteLongValue(uint24_t pc)
{
unsigned value = this->_bus->read(pc++, true);
value += this->_bus->read(pc++, true) << 8u;
value += this->_bus->read(pc, true) << 16u;
std::stringstream ss;
ss << "$" << std::hex << value;
return ss.str();
}
std::string CPUDebug::_getDirectIndexedByXValue(uint24_t pc)
{
unsigned value = this->_bus->read(pc, true);
std::stringstream ss;
ss << "$" << std::hex << value << ", x";
return ss.str();
} }
int CPUDebug::RESB() int CPUDebug::RESB()
{ {
CPU::RESB(); CPU::RESB();
this->disassembledInstructions.clear();
this->_updateDisassembly(0xFFFF - this->_cartridgeHeader.emulationInterrupts.reset);
this->_updateRegistersPanel(); this->_updateRegistersPanel();
return (0); return (0);
} }
@@ -361,12 +268,22 @@ namespace ComSquare::Debugger
return this->_registers.pac; return this->_registers.pac;
} }
DisassembledInstruction::DisassembledInstruction(const CPU::Instruction &instruction, uint24_t addr, std::string arg, uint8_t op) uint16_t CPUDebug::getStackPointer()
: CPU::Instruction(instruction), address(addr), argument(std::move(arg)), opcode(op) {}
std::string DisassembledInstruction::toString()
{ {
return this->name + " " + this->argument; return this->_registers.s;
}
std::string CPUDebug::getProceededParameters()
{
uint24_t pac = this->_registers.pac;
this->_bus->forceSilence = true;
Instruction instruction = this->_instructions[this->readPC()];
uint24_t valueAddr = this->_getValueAddr(instruction);
this->_registers.pac = pac;
this->_bus->forceSilence = false;
if (instruction.size == 1)
return "";
return "[" + Utility::to_hex(valueAddr, Utility::AsmPrefix) + "]";
} }
} }
@@ -384,21 +301,28 @@ int DisassemblyModel::rowCount(const QModelIndex &) const
QVariant DisassemblyModel::data(const QModelIndex &index, int role) const QVariant DisassemblyModel::data(const QModelIndex &index, int role) const
{ {
if (role != Qt::DisplayRole && role != Qt::DecorationRole)
return QVariant();
ComSquare::Debugger::DisassembledInstruction instruction = this->_cpu.disassembledInstructions[index.row()]; ComSquare::Debugger::DisassembledInstruction instruction = this->_cpu.disassembledInstructions[index.row()];
if (role == Qt::DecorationRole) {
if (index.column() == 3 && instruction.level == ComSquare::Debugger::TrustLevel::Unsafe) switch (role) {
case Qt::DecorationRole:
if (index.column() == 2 && instruction.level == ComSquare::Debugger::TrustLevel::Unsafe)
return QColor(Qt::yellow); return QColor(Qt::yellow);
if (index.column() == 3 && instruction.level == ComSquare::Debugger::TrustLevel::Compromised) if (index.column() == 2 && instruction.level == ComSquare::Debugger::TrustLevel::Compromised)
return QColor(Qt::red); return QColor(Qt::red);
return QVariant(); return QVariant();
} case Qt::DisplayRole:
switch (index.column()) { switch (index.column()) {
case 0: case 0:
return QString(instruction.name.c_str()); return QString(instruction.name.c_str());
case 1: case 1:
return QString(instruction.argument.c_str()); return QString(instruction.argument.c_str());
case 3:
if (instruction.address != this->_cpu.getPC())
return QVariant();
return QString(this->_cpu.getProceededParameters().c_str());
default:
return QVariant();
}
default: default:
return QVariant(); return QVariant();
} }
@@ -406,8 +330,20 @@ QVariant DisassemblyModel::data(const QModelIndex &index, int role) const
QVariant DisassemblyModel::headerData(int section, Qt::Orientation orientation, int role) const QVariant DisassemblyModel::headerData(int section, Qt::Orientation orientation, int role) const
{ {
if (orientation == Qt::Horizontal) if (orientation == Qt::Horizontal) {
switch (section) {
case 0:
return QString("INST");
case 1:
return QString("Parameter");
case 2:
return QString("Thrust");
case 3:
return QString("Data Address");
default:
return QVariant(); return QVariant();
}
}
if (role != Qt::DisplayRole) if (role != Qt::DisplayRole)
return QVariant(); return QVariant();
ComSquare::Debugger::DisassembledInstruction instruction = this->_cpu.disassembledInstructions[section]; ComSquare::Debugger::DisassembledInstruction instruction = this->_cpu.disassembledInstructions[section];
@@ -442,3 +378,114 @@ QSize RowPainter::sizeHint(const QStyleOptionViewItem &, const QModelIndex &) co
{ {
return QSize(); return QSize();
} }
StackModel::StackModel(ComSquare::Memory::MemoryBus &bus, ComSquare::Debugger::CPUDebug &cpu) : _bus(bus), _cpu(cpu) { }
int StackModel::rowCount(const QModelIndex &) const
{
return 0x10000 / 2;
}
int StackModel::columnCount(const QModelIndex &) const
{
return 2;
}
QVariant StackModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::BackgroundRole) {
if (index.row() * 2 + index.column() == this->_cpu.getStackPointer())
return QColor(Qt::darkBlue);
if (index.row() * 2 + index.column() == this->_cpu.initialStackPointer)
return QColor(Qt::darkCyan);
}
if (role == Qt::TextAlignmentRole)
return Qt::AlignCenter;
if (role != Qt::DisplayRole)
return QVariant();
uint16_t addr = index.row() * 2 + index.column();
try {
uint8_t value = this->_bus.read(addr);
return (ComSquare::Utility::to_hex(value, ComSquare::Utility::NoPrefix).c_str());
} catch (std::exception &) {
return "??";
}
}
QVariant StackModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal)
return QVariant();
if (role != Qt::DisplayRole)
return QVariant();
uint16_t addr = section * 2;
return QString(ComSquare::Utility::to_hex(addr, ComSquare::Utility::HexString::NoPrefix).c_str());
}
HistoryModel::HistoryModel() = default;
int HistoryModel::rowCount(const QModelIndex &) const
{
return this->_instructions.size();
}
int HistoryModel::columnCount(const QModelIndex &) const
{
return 4;
}
QVariant HistoryModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::TextAlignmentRole)
return Qt::AlignCenter;
if (role != Qt::DisplayRole)
return QVariant();
ComSquare::Debugger::ExecutedInstruction instruction = this->_instructions[index.row()];
switch (index.column()) {
case 0:
return QString(ComSquare::Utility::to_hex(instruction.opcode, ComSquare::Utility::NoPrefix).c_str());
case 1:
return QString(instruction.name.c_str());
case 2:
return QString(instruction.params.c_str());
case 3:
return QString(instruction.proceededParams.c_str());
default:
return QVariant();
}
}
QVariant HistoryModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Vertical || role != Qt::DisplayRole)
return QVariant();
switch (section) {
case 0:
return QString("op");
case 1:
return QString("ins");
case 2:
return QString("Parameter");
case 3:
return QString("Pointer");
default:
return QVariant();
}
}
void HistoryModel::log(const ComSquare::Debugger::ExecutedInstruction& instruction)
{
int row = this->_instructions.size();
this->beginInsertRows(QModelIndex(), row, row);
this->_instructions.push_back(instruction);
this->insertRow(row);
this->endInsertRows();
}
void HistoryModel::clear()
{
this->beginResetModel();
this->_instructions.clear();
this->endResetModel();
}

View File

@@ -6,17 +6,79 @@
#define COMSQUARE_CPUDEBUG_HPP #define COMSQUARE_CPUDEBUG_HPP
#include <QtWidgets/QStyledItemDelegate> #include <QtWidgets/QStyledItemDelegate>
#include "../CPU/CPU.hpp" #include "../../CPU/CPU.hpp"
#include "../Renderer/SFRenderer.hpp" #include "../../Renderer/SFRenderer.hpp"
#include "../SNES.hpp" #include "../../SNES.hpp"
#include "../../ui/ui_cpu.h" #include "../../../ui/ui_cpu.h"
#include "ClosableWindow.hpp" #include "../ClosableWindow.hpp"
namespace ComSquare::Debugger namespace ComSquare::Debugger
{ {
class CPUDebug; class CPUDebug;
//! @brief An instruction that has already been executed. Used for the history viewer
struct ExecutedInstruction {
//! @brief Opcode of the instruction
uint8_t opcode;
//! @brief The name of the instruction
std::string name;
//! @brief Readable parameters (disassembly style)
std::string params;
//! @brief The address to read from after processing the parameter.
std::string proceededParams;
};
} }
//! @brief The qt model that show the stack.
class StackModel : public QAbstractTableModel
{
Q_OBJECT
private:
ComSquare::Memory::MemoryBus &_bus;
ComSquare::Debugger::CPUDebug &_cpu;
public:
explicit StackModel(ComSquare::Memory::MemoryBus &bus, ComSquare::Debugger::CPUDebug &cpu);
StackModel(const StackModel &) = delete;
const StackModel &operator=(const StackModel &) = delete;
~StackModel() override = default;
//! @brief The number of row the table has.
int rowCount(const QModelIndex &parent) const override;
//! @brief The number of column the table has.
int columnCount(const QModelIndex &parent) const override;
//! @brief Return a data representing the table cell.
QVariant data(const QModelIndex &index, int role) const override;
//! @brief Override the headers to use hex values.
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
};
//! @brief The qt model that show the history.
class HistoryModel : public QAbstractTableModel
{
Q_OBJECT
private:
std::vector<ComSquare::Debugger::ExecutedInstruction> _instructions = {};
public:
HistoryModel();
HistoryModel(const HistoryModel &) = delete;
const HistoryModel &operator=(const HistoryModel &) = delete;
~HistoryModel() override = default;
//! @brief Log a new instruction
void log(const ComSquare::Debugger::ExecutedInstruction &);
//! @brief Remove every instructions of the history.
void clear();
//! @brief The number of row the table has.
int rowCount(const QModelIndex &parent) const override;
//! @brief The number of column the table has.
int columnCount(const QModelIndex &parent) const override;
//! @brief Return a data representing the table cell.
QVariant data(const QModelIndex &index, int role) const override;
//! @brief Override the headers to use hex values.
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
};
//! @brief The qt model that show the disassembly. //! @brief The qt model that show the disassembly.
class DisassemblyModel : public QAbstractTableModel class DisassemblyModel : public QAbstractTableModel
{ {
@@ -114,6 +176,10 @@ namespace ComSquare::Debugger
DisassemblyModel _model; DisassemblyModel _model;
//! @brief A custom painter that highlight breakpoints and the PC's position. //! @brief A custom painter that highlight breakpoints and the PC's position.
RowPainter _painter; RowPainter _painter;
//! @brief The stack viewer's model.
StackModel _stackModel;
//! @brief The history model.
HistoryModel _historyModel;
//! @brief If this is set to true, the execution of the CPU will be paused. //! @brief If this is set to true, the execution of the CPU will be paused.
bool _isPaused = true; bool _isPaused = true;
//! @brief If this is set to true, the CPU will execute one instruction and pause itself. //! @brief If this is set to true, the CPU will execute one instruction and pause itself.
@@ -128,7 +194,7 @@ namespace ComSquare::Debugger
//! @param ctx The initial context of the processor before the disassembly begin. //! @param ctx The initial context of the processor before the disassembly begin.
std::vector<DisassembledInstruction> _disassemble(uint24_t startAddr, uint24_t size, DisassemblyContext &ctx); std::vector<DisassembledInstruction> _disassemble(uint24_t startAddr, uint24_t size, DisassemblyContext &ctx);
//! @brief Update disassembly with the new state of the processor. //! @brief Update disassembly with the new state of the processor.
void _updateDisassembly(uint24_t refreshSize = 0xFF); void _updateDisassembly(uint24_t start, uint24_t refreshSize = 0xFF);
//! @brief Parse the instruction at the program counter given to have human readable information. //! @brief Parse the instruction at the program counter given to have human readable information.
DisassembledInstruction _parseInstruction(uint24_t pc, DisassemblyContext &ctx); DisassembledInstruction _parseInstruction(uint24_t pc, DisassemblyContext &ctx);
//! @brief Get the parameter of the instruction as an hexadecimal string. //! @brief Get the parameter of the instruction as an hexadecimal string.
@@ -141,14 +207,42 @@ namespace ComSquare::Debugger
//! @brief Return a printable string corresponding to the value of a 8 or 16 bits immediate addressing mode. //! @brief Return a printable string corresponding to the value of a 8 or 16 bits immediate addressing mode.
//! @param dual Set this to true if the instruction take 16bits and not 8. (used for the immediate by a when the flag m is not set or the immediate by x if the flag x is not set). //! @param dual Set this to true if the instruction take 16bits and not 8. (used for the immediate by a when the flag m is not set or the immediate by x if the flag x is not set).
std::string _getImmediateValue(uint24_t pc, bool dual); std::string _getImmediateValue(uint24_t pc, bool dual);
//! @brief Return a printable string corresponding to the value of a direct addressing mode.
std::string _getDirectValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of an absolute addressing mode. //! @brief Return a printable string corresponding to the value of an absolute addressing mode.
std::string _getAbsoluteValue(uint24_t pc); std::string _getAbsoluteValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of an absolute long addressing mode. //! @brief Return a printable string corresponding to the value of an absolute long addressing mode.
std::string _getAbsoluteLongValue(uint24_t pc); std::string _getAbsoluteLongValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a direct addressing mode.
std::string _getDirectValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a direct indirect addressing mode.
std::string _getDirectIndirectValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a direct indirect long addressing mode.
std::string _getDirectIndirectLongValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a absolute indexed by x addressing mode.
std::string _getAbsoluteIndexByXValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a absolute indexed by x long addressing mode.
std::string _getAbsoluteIndexByXLongValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a absolute indexed by y addressing mode.
std::string _getAbsoluteIndexByYValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a direct index by x addressing mode. //! @brief Return a printable string corresponding to the value of a direct index by x addressing mode.
std::string _getDirectIndexedByXValue(uint24_t pc); std::string _getDirectIndexedByXValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a direct index by y addressing mode.
std::string _getDirectIndexedByYValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a direct indirect index by x addressing mode.
std::string _getDirectIndexedByXIndirectValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a direct indirect index by y addressing mode.
std::string _getDirectIndirectIndexedByYValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a direct indirect index by y long addressing mode.
std::string _getDirectIndirectIndexedByYLongValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a stack relative addressing mode.
std::string _getStackRelativeValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a stack relative indirect indexed by y addressing mode.
std::string _getStackRelativeIndiretIndexdeByYValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a absolute indirect addressing mode.
std::string _getAbsoluteIndirectValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a absolute indirect indexed by x addressing mode.
std::string _getAbsoluteIndirectIndexedByXValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a absolute indirect long addressing mode.
std::string _getAbsoluteIndirectLongValue(uint24_t pc);
public: public:
//! @brief Pause/Resume the CPU. //! @brief Pause/Resume the CPU.
@@ -167,8 +261,14 @@ namespace ComSquare::Debugger
std::vector<DisassembledInstruction> disassembledInstructions; std::vector<DisassembledInstruction> disassembledInstructions;
//! @brief The list of breakpoints the user has set. //! @brief The list of breakpoints the user has set.
std::vector<Breakpoint> breakpoints; std::vector<Breakpoint> breakpoints;
//! @brief Get a string representing the actual value of the arguments of the next instruction to execute.
std::string getProceededParameters();
//! @brief Return the current program counter of this CPU. //! @brief Return the current program counter of this CPU.
uint24_t getPC(); uint24_t getPC();
//! @brief Return the current stack pointer.
uint16_t getStackPointer();
//! @brief The stack pointer before the execution of any instructions.
uint16_t initialStackPointer = this->_registers.s;
//! @brief Update the UI when resetting the CPU. //! @brief Update the UI when resetting the CPU.
int RESB() override; int RESB() override;
//! @brief Convert a basic CPU to a debugging CPU. //! @brief Convert a basic CPU to a debugging CPU.

View File

@@ -0,0 +1,272 @@
//
// Created by anonymus-raccoon on 4/3/20.
//
#include <sstream>
#include "CPUDebug.hpp"
#include "../../Utility/Utility.hpp"
using namespace ComSquare::CPU;
namespace ComSquare::Debugger
{
DisassembledInstruction::DisassembledInstruction(const CPU::Instruction &instruction, uint24_t addr, std::string arg, uint8_t op)
: CPU::Instruction(instruction), address(addr), argument(std::move(arg)), opcode(op), level(Safe) {}
std::string DisassembledInstruction::toString()
{
return this->name + " " + this->argument;
}
std::vector<DisassembledInstruction> CPUDebug::_disassemble(uint24_t pc, uint24_t length, DisassemblyContext &ctx)
{
std::vector<DisassembledInstruction> map;
uint24_t endAddr = pc + length;
while (pc < endAddr) {
DisassembledInstruction instruction = this->_parseInstruction(pc, ctx);
instruction.level = ctx.level;
map.push_back(instruction);
pc += instruction.size;
if (instruction.addressingMode == ImmediateForA && !ctx.mFlag)
pc++;
if (instruction.addressingMode == ImmediateForX && !ctx.xFlag)
pc++;
if (instruction.opcode == 0x40 && ctx.isEmulationMode) { // RTI
ctx.mFlag = true;
ctx.xFlag = true;
}
if (instruction.opcode == 0xC2) { // REP
if (ctx.isEmulationMode) {
ctx.mFlag = true;
ctx.xFlag = true;
} else {
uint8_t m = this->_bus->read(pc - 1);
ctx.mFlag &= ~m & 0b00100000u;
ctx.xFlag &= ~m & 0b00010000u;
}
}
if (instruction.opcode == 0xE2) { // SEP
uint8_t m = this->_bus->read(pc - 1);
ctx.mFlag |= m & 0b00100000u;
ctx.xFlag |= m & 0b00010000u;
}
if (instruction.opcode == 0x28) { // PLP
if (ctx.isEmulationMode) {
ctx.mFlag = true;
ctx.xFlag = true;
} else
ctx.level = Compromised;
}
if (instruction.opcode == 0xFB) {// XCE
ctx.level = Unsafe;
ctx.isEmulationMode = false; // The most common use of the XCE is to enable native mode at the start of the ROM so we guess that it has done that.
}
}
return map;
}
DisassembledInstruction CPUDebug::_parseInstruction(uint24_t pc, DisassemblyContext &ctx)
{
uint24_t opcode = this->_bus->read(pc, true);
Instruction instruction = this->_instructions[opcode];
std::string argument = this->_getInstructionParameter(instruction, pc + 1, ctx);
return DisassembledInstruction(instruction, pc, argument, opcode);
}
std::string CPUDebug::_getInstructionParameter(Instruction &instruction, uint24_t pc, DisassemblyContext &ctx)
{
switch (instruction.addressingMode) {
case Implied:
return "";
case Immediate8bits:
return this->_getImmediateValue(pc, false);
case ImmediateForA:
return this->_getImmediateValue(pc, !ctx.mFlag);
case ImmediateForX:
return this->_getImmediateValue(pc, !ctx.xFlag);
case Absolute:
return this->_getAbsoluteValue(pc);
case AbsoluteLong:
return this->_getAbsoluteLongValue(pc);
case DirectPage:
return this->_getDirectValue(pc);
case DirectPageIndexedByX:
return this->_getDirectIndexedByXValue(pc);
case DirectPageIndirect:
return this->_getDirectIndirectValue(pc);
case DirectPageIndirectLong:
return this->_getDirectIndirectLongValue(pc);
case AbsoluteIndexedByX:
return this->_getAbsoluteIndexByXValue(pc);
case AbsoluteIndexedByXLong:
return this->_getAbsoluteIndexByXLongValue(pc);
case AbsoluteIndexedByY:
return this->_getAbsoluteIndexByYValue(pc);
case DirectPageIndexedByY:
return this->_getDirectIndexedByYValue(pc);
case DirectPageIndirectIndexedByX:
return this->_getDirectIndexedByXIndirectValue(pc);
case DirectPageIndirectIndexedByY:
return this->_getDirectIndirectIndexedByYValue(pc);
case DirectPageIndirectIndexedByYLong:
return this->_getDirectIndirectIndexedByYLongValue(pc);
case StackRelative:
return this->_getStackRelativeValue(pc);
case StackRelativeIndirectIndexedByY:
return this->_getStackRelativeIndiretIndexdeByYValue(pc);
case AbsoluteIndirect:
return this->_getAbsoluteIndirectValue(pc);
case AbsoluteIndirectIndexedByX:
return this->_getAbsoluteIndirectIndexedByXValue(pc);
case AbsoluteIndirectLong:
return this->_getAbsoluteIndirectLongValue(pc);
default:
return "???";
}
}
std::string CPUDebug::_getImmediateValue(uint24_t pc, bool dual)
{
unsigned value = this->_bus->read(pc, true);
if (dual)
value += this->_bus->read(pc + 1, true) << 8u;
std::stringstream ss;
ss << "#$" << std::hex << value;
return ss.str();
}
std::string CPUDebug::_getDirectValue(uint24_t pc)
{
return Utility::to_hex(this->_bus->read(pc, true), Utility::HexString::AsmPrefix);
}
std::string CPUDebug::_getAbsoluteValue(uint24_t pc)
{
uint24_t value = this->_bus->read(pc) + (this->_bus->read(pc + 1, true) << 8u);
return Utility::to_hex(value, Utility::HexString::AsmPrefix);
}
std::string CPUDebug::_getAbsoluteLongValue(uint24_t pc)
{
unsigned value = this->_bus->read(pc++, true);
value += this->_bus->read(pc++, true) << 8u;
value += this->_bus->read(pc, true) << 16u;
return Utility::to_hex(value, Utility::HexString::AsmPrefix);
}
std::string CPUDebug::_getDirectIndexedByXValue(uint24_t pc)
{
unsigned value = this->_bus->read(pc, true);
std::stringstream ss;
ss << "$" << std::hex << value << ", x";
return ss.str();
}
std::string CPUDebug::_getDirectIndexedByYValue(uint24_t pc)
{
unsigned value = this->_bus->read(pc, true);
std::stringstream ss;
ss << "$" << std::hex << value << ", y";
return ss.str();
}
std::string CPUDebug::_getDirectIndirectValue(uint24_t pc)
{
return "(" + Utility::to_hex(this->_bus->read(pc, true), Utility::AsmPrefix) + ")";
}
std::string CPUDebug::_getDirectIndirectLongValue(uint24_t pc)
{
return "[" + Utility::to_hex(this->_bus->read(pc, true), Utility::AsmPrefix) + "]";
}
std::string CPUDebug::_getAbsoluteIndexByXValue(uint24_t pc)
{
uint24_t value = this->_bus->read(pc) + (this->_bus->read(pc + 1, true) << 8u);
return Utility::to_hex(value, Utility::HexString::AsmPrefix) + ", x";
}
std::string CPUDebug::_getAbsoluteIndexByYValue(uint24_t pc)
{
uint24_t value = this->_bus->read(pc) + (this->_bus->read(pc + 1, true) << 8u);
return Utility::to_hex(value, Utility::HexString::AsmPrefix) + ", y";
}
std::string CPUDebug::_getAbsoluteIndexByXLongValue(uint24_t pc)
{
unsigned value = this->_bus->read(pc++, true);
value += this->_bus->read(pc++, true) << 8u;
value += this->_bus->read(pc, true) << 16u;
return Utility::to_hex(value, Utility::HexString::AsmPrefix) + ", x";
}
std::string CPUDebug::_getDirectIndexedByXIndirectValue(uint24_t pc)
{
unsigned value = this->_bus->read(pc, true);
std::stringstream ss;
ss << "($" << std::hex << value << ", x)";
return ss.str();
}
std::string CPUDebug::_getDirectIndirectIndexedByYValue(uint24_t pc)
{
unsigned value = this->_bus->read(pc, true);
std::stringstream ss;
ss << "($" << std::hex << value << "), y";
return ss.str();
}
std::string CPUDebug::_getDirectIndirectIndexedByYLongValue(uint24_t pc)
{
unsigned value = this->_bus->read(pc, true);
std::stringstream ss;
ss << "[$" << std::hex << value << "], y";
return ss.str();
}
std::string CPUDebug::_getStackRelativeValue(uint24_t pc)
{
return Utility::to_hex(this->_bus->read(pc, true), Utility::AsmPrefix) + ", s";
}
std::string CPUDebug::_getStackRelativeIndiretIndexdeByYValue(uint24_t pc)
{
return "(" + Utility::to_hex(this->_bus->read(pc, true), Utility::AsmPrefix) + ", s), y";
}
std::string CPUDebug::_getAbsoluteIndirectValue(uint24_t pc)
{
uint24_t value = this->_bus->read(pc) + (this->_bus->read(pc + 1, true) << 8u);
return "(" + Utility::to_hex(value, Utility::HexString::AsmPrefix) + ")";
}
std::string CPUDebug::_getAbsoluteIndirectLongValue(uint24_t pc)
{
unsigned value = this->_bus->read(pc++, true);
value += this->_bus->read(pc++, true) << 8u;
value += this->_bus->read(pc, true) << 16u;
return "(" + Utility::to_hex(value, Utility::HexString::AsmPrefix) + ")";
}
std::string CPUDebug::_getAbsoluteIndirectIndexedByXValue(uint24_t pc)
{
uint24_t value = this->_bus->read(pc) + (this->_bus->read(pc + 1, true) << 8u);
return "(" + Utility::to_hex(value, Utility::HexString::AsmPrefix) + ", x)";
}
}

View File

@@ -150,11 +150,15 @@ namespace ComSquare::Debugger
uint8_t MemoryBusDebug::read(uint24_t addr, bool silence) uint8_t MemoryBusDebug::read(uint24_t addr, bool silence)
{ {
if (!silence) { if (!silence && !forceSilence) {
auto accessor = this->getAccessor(addr); auto accessor = this->getAccessor(addr);
if (!accessor) {
this->_model.log(BusLog(true, addr, accessor, this->_openBus, this->_openBus));
} else {
uint8_t value = accessor->read(addr - accessor->getStart()); uint8_t value = accessor->read(addr - accessor->getStart());
this->_model.log(BusLog(false, addr, accessor, value, value)); this->_model.log(BusLog(false, addr, accessor, value, value));
} }
}
return MemoryBus::read(addr); return MemoryBus::read(addr);
} }
@@ -167,6 +171,7 @@ namespace ComSquare::Debugger
} catch (InvalidAddress &) { } catch (InvalidAddress &) {
value = 0; value = 0;
} }
if (!forceSilence)
this->_model.log(BusLog(true, addr, accessor, value, data)); this->_model.log(BusLog(true, addr, accessor, value, data));
MemoryBus::write(addr, data); MemoryBus::write(addr, data);
} }

View File

@@ -5,6 +5,7 @@
#include <iostream> #include <iostream>
#include "ARectangleMemory.hpp" #include "ARectangleMemory.hpp"
#include "../Exceptions/InvalidAddress.hpp" #include "../Exceptions/InvalidAddress.hpp"
#include "../Utility/Utility.hpp"
namespace ComSquare::Memory namespace ComSquare::Memory
{ {

View File

@@ -12,7 +12,7 @@ namespace ComSquare::Memory
{ {
//! @brief Superset of the AMemory to map non continuous rectangle to the memory. (A rectangle that spam across more than one bank but that does not start at 0000 or end at FFFF). //! @brief Superset of the AMemory to map non continuous rectangle to the memory. (A rectangle that spam across more than one bank but that does not start at 0000 or end at FFFF).
class ARectangleMemory : public AMemory { class ARectangleMemory : public AMemory {
private: protected:
//! @brief The first bank to map to. //! @brief The first bank to map to.
uint8_t _startBank = 0; uint8_t _startBank = 0;
//! @brief The last bank to map to. //! @brief The last bank to map to.

View File

@@ -22,20 +22,22 @@ namespace ComSquare
//! @brief The list of components registered inside the bus. Every components that can read/write to a public address should be in this vector. //! @brief The list of components registered inside the bus. Every components that can read/write to a public address should be in this vector.
std::vector<std::shared_ptr<AMemory>> _memoryAccessors; std::vector<std::shared_ptr<AMemory>> _memoryAccessors;
//! @brief The last value read via the memory bus.
uint8_t _openBus = 0;
//! @brief WRam, CPU, PPU & APU registers are mirrored to all banks of Q1 & Q3. This function is used for the mirroring. //! @brief WRam, CPU, PPU & APU registers are mirrored to all banks of Q1 & Q3. This function is used for the mirroring.
//! @param console All the components. //! @param console All the components.
//! @param i Base address for the mirrors. //! @param i Base address for the mirrors.
void _mirrorComponents(SNES &console, unsigned i); void _mirrorComponents(SNES &console, unsigned i);
protected:
//! @brief The last value read via the memory bus.
uint8_t _openBus = 0;
public: public:
MemoryBus() = default; MemoryBus() = default;
MemoryBus(const MemoryBus &) = default; MemoryBus(const MemoryBus &) = default;
MemoryBus &operator=(const MemoryBus &) = default; MemoryBus &operator=(const MemoryBus &) = default;
~MemoryBus() = default; ~MemoryBus() = default;
//! @brief Force silencing read to the bus.
bool forceSilence = false;
//! @brief Read data at a global address. //! @brief Read data at a global address.
//! @param addr The address to read from. //! @param addr The address to read from.
//! @param silence Disable login to the memory bus's debugger (if enabled). Should only be used by other debuggers. //! @param silence Disable login to the memory bus's debugger (if enabled). Should only be used by other debuggers.

View File

@@ -3,6 +3,7 @@
// //
#include "RectangleShadow.hpp" #include "RectangleShadow.hpp"
#include "../Utility/Utility.hpp"
#include <utility> #include <utility>
#include <iostream> #include <iostream>
@@ -17,13 +18,13 @@ namespace ComSquare::Memory
uint8_t RectangleShadow::read_internal(uint24_t addr) uint8_t RectangleShadow::read_internal(uint24_t addr)
{ {
addr += this->_bankOffset << 16u; addr += this->_bankOffset * (this->_endPage - this->_startPage);
return this->_initial->read_internal(addr); return this->_initial->read_internal(addr);
} }
void RectangleShadow::write_internal(uint24_t addr, uint8_t data) void RectangleShadow::write_internal(uint24_t addr, uint8_t data)
{ {
addr += this->_bankOffset << 16u; addr += this->_bankOffset * (this->_endPage - this->_startPage);
this->_initial->write_internal(addr, data); this->_initial->write_internal(addr, data);
} }

View File

@@ -22,7 +22,7 @@ namespace ComSquare::Memory
explicit RectangleShadow(std::shared_ptr<ARectangleMemory> initial, uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage); explicit RectangleShadow(std::shared_ptr<ARectangleMemory> initial, uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage);
RectangleShadow(const RectangleShadow &) = default; RectangleShadow(const RectangleShadow &) = default;
RectangleShadow &operator=(const RectangleShadow &) = default; RectangleShadow &operator=(const RectangleShadow &) = default;
~RectangleShadow() = default; ~RectangleShadow() override = default;
//! @brief Internal component read. Implement this as you would implement a basic AMemory's read. //! @brief Internal component read. Implement this as you would implement a basic AMemory's read.
//! @param addr The local address to read from. 0x0 refer to the first byte of your data and the address is in the component's space. That means that you can consider this address as continuous //! @param addr The local address to read from. 0x0 refer to the first byte of your data and the address is in the component's space. That means that you can consider this address as continuous

View File

@@ -6,7 +6,7 @@
#include <iostream> #include <iostream>
#include "SNES.hpp" #include "SNES.hpp"
#ifdef DEBUGGER_ENABLED #ifdef DEBUGGER_ENABLED
#include "Debugger/CPUDebug.hpp" #include "Debugger/CPU/CPUDebug.hpp"
#include "Debugger/APUDebug.hpp" #include "Debugger/APUDebug.hpp"
#include "Debugger/MemoryBusDebug.hpp" #include "Debugger/MemoryBusDebug.hpp"

View File

@@ -67,7 +67,7 @@ Test(ADC, overflowEmulation)
Test(ADC, signedOverflow) Test(ADC, signedOverflow)
{ {
Init() Init()
snes.cpu->_isEmulationMode = false; snes.cpu->_registers.p.m = false;
snes.cpu->_registers.a = 0x7FFF; snes.cpu->_registers.a = 0x7FFF;
snes.wram->_data[0] = 0x1; snes.wram->_data[0] = 0x1;
snes.cpu->ADC(0x0, ComSquare::CPU::AddressingMode::Implied); snes.cpu->ADC(0x0, ComSquare::CPU::AddressingMode::Implied);
@@ -81,7 +81,7 @@ Test(ADC, signedOverflow)
Test(ADC, signedOverflowEmulated) Test(ADC, signedOverflowEmulated)
{ {
Init() Init()
snes.cpu->_isEmulationMode = true; snes.cpu->_registers.p.m = true;
snes.cpu->_registers.a = 0x007F; snes.cpu->_registers.a = 0x007F;
snes.wram->_data[0] = 0x1; snes.wram->_data[0] = 0x1;
snes.cpu->ADC(0x0, ComSquare::CPU::AddressingMode::Implied); snes.cpu->ADC(0x0, ComSquare::CPU::AddressingMode::Implied);
@@ -95,7 +95,7 @@ Test(ADC, signedOverflowEmulated)
Test(ADC, negative) Test(ADC, negative)
{ {
Init() Init()
snes.cpu->_isEmulationMode = false; snes.cpu->_registers.p.m = false;
snes.cpu->_registers.a = 0x8FFF; snes.cpu->_registers.a = 0x8FFF;
snes.wram->_data[0] = 0x1; snes.wram->_data[0] = 0x1;
snes.cpu->ADC(0x0, ComSquare::CPU::AddressingMode::Implied); snes.cpu->ADC(0x0, ComSquare::CPU::AddressingMode::Implied);

View File

@@ -0,0 +1,73 @@
//
// Created by anonymus-raccoon on 4/6/20.
//
#include <criterion/criterion.h>
#include <bitset>
#include "../../tests.hpp"
#include "../../../sources/SNES.hpp"
using namespace ComSquare;
Test(CMP, underflow)
{
Init()
snes.cpu->_registers.p.m = true;
snes.cpu->_registers.a = 0;
snes.wram->_data[0] = 0x1;
snes.cpu->CMP(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flags should not be set.");
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set.");
}
Test(CMP, zero)
{
Init()
snes.cpu->_registers.p.m = true;
snes.cpu->_registers.a = 0x5;
snes.wram->_data[0] = 0x5;
snes.cpu->CMP(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.p.c, true, "The carry flags should be set.");
cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set.");
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flags should be set.");
}
Test(CMP, nativeModeZero)
{
Init()
snes.cpu->_registers.p.m = false;
snes.cpu->_registers.a = 0x5000;
snes.wram->_data[0] = 0x00;
snes.wram->_data[1] = 0x50;
snes.cpu->CMP(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.p.c, true, "The carry flags should be set.");
cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set.");
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flags should be set.");
}
Test(CMP, nativeModeNothing)
{
Init()
snes.cpu->_registers.p.m = false;
snes.cpu->_registers.a = 0x8000;
snes.wram->_data[0] = 0x00;
snes.wram->_data[1] = 0x50;
snes.cpu->CMP(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.p.c, true, "The carry flags should be set.");
cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set.");
}
Test(CMP, negative)
{
Init()
snes.cpu->_registers.p.m = false;
snes.cpu->_registers.a = 0xB000;
snes.wram->_data[0] = 0x00;
snes.wram->_data[1] = 0x10;
snes.cpu->CMP(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.p.c, true, "The carry flags should be set.");
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set.");
}

View File

@@ -0,0 +1,343 @@
//
// Created by anonymus-raccoon on 4/3/20.
//
#include <criterion/criterion.h>
#include <bitset>
#include "../../tests.hpp"
#include "../../../sources/SNES.hpp"
using namespace ComSquare;
Test(DEX, simple)
{
Init()
snes.cpu->_registers.p.x_b = true;
snes.cpu->_registers.x = 0x57;
snes.cpu->DEX(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.x, 0x56, "The x index value should be 0x56 but it was 0x%x.", snes.cpu->_registers.x);
cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set.");
}
Test(DEX, overflowEmul)
{
Init()
snes.cpu->_registers.p.x_b = true;
snes.cpu->_registers.x = 0;
snes.cpu->DEX(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.x, 0xFF, "The x index value should be 0xFF but it was 0x%x.", snes.cpu->_registers.x);
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set.");
}
Test(DEX, fakeOverflowNonEmul)
{
Init()
snes.cpu->_registers.p.x_b = false;
snes.cpu->_registers.x = 0xFF00;
snes.cpu->DEX(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.x, 0xFEFF, "The x index value should be 0xFEFF but it was 0x%x.", snes.cpu->_registers.x);
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set.");
}
Test(DEX, nonNegative)
{
Init()
snes.cpu->_registers.p.x_b = true;
snes.cpu->_registers.x = 0x80;
snes.cpu->DEX(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.x, 0x7F, "The x index value should be 0x7F but it was 0x%x.", snes.cpu->_registers.x);
cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set.");
}
Test(DEX, zero)
{
Init()
snes.cpu->_registers.p.x_b = true;
snes.cpu->_registers.x = 1;
snes.cpu->DEX(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.x, 0, "The x index value should be 0 but it was 0x%x.", snes.cpu->_registers.x);
cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set.");
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flags should be set.");
}
Test(DEY, simple)
{
Init()
snes.cpu->_registers.p.x_b = true;
snes.cpu->_registers.y = 0x57;
snes.cpu->DEY(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.y, 0x56, "The x index value should be 0x56 but it was 0x%x.", snes.cpu->_registers.y);
cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set.");
}
Test(DEY, overflowEmul)
{
Init()
snes.cpu->_registers.p.x_b = true;
snes.cpu->_registers.y = 0;
snes.cpu->DEY(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.y, 0xFF, "The x index value should be 0xFF but it was 0x%x.", snes.cpu->_registers.y);
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set.");
}
Test(DEY, fakeOverflowNonEmul)
{
Init()
snes.cpu->_registers.p.x_b = false;
snes.cpu->_registers.y = 0xFF00;
snes.cpu->DEY(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.y, 0xFEFF, "The x index value should be 0xFEFF but it was 0x%x.", snes.cpu->_registers.y);
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set.");
}
Test(DEY, nonNegative)
{
Init()
snes.cpu->_registers.p.x_b = true;
snes.cpu->_registers.y = 0x80;
snes.cpu->DEY(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.y, 0x7F, "The x index value should be 0x7F but it was 0x%x.", snes.cpu->_registers.y);
cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set.");
}
Test(DEY, zero)
{
Init()
snes.cpu->_registers.p.x_b = true;
snes.cpu->_registers.y = 1;
snes.cpu->DEY(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.y, 0, "The x index value should be 0 but it was 0x%x.", snes.cpu->_registers.y);
cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set.");
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flags should be set.");
}
Test(ORA, simple)
{
Init()
snes.cpu->_registers.p.m = true;
snes.cpu->_registers.a = 0x80;
snes.wram->_data[0] = 0x0F;
snes.cpu->ORA(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.a, 0x8F, "The accumulator's value should be 0x8F but it was 0x%x.", snes.cpu->_registers.a);
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set.");
}
Test(ORA, simple2)
{
Init()
snes.cpu->_registers.p.m = true;
snes.cpu->_registers.a = 0x80;
snes.wram->_data[0] = 0xF0;
snes.cpu->ORA(0x00, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.a, 0xF0, "The accumulator's value should be 0xF0 but it was 0x%x.", snes.cpu->_registers.a);
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set.");
}
Test(ORA, zero)
{
Init()
snes.cpu->_registers.p.m = true;
snes.cpu->_registers.a = 0x00;
snes.wram->_data[0] = 0x00;
snes.cpu->ORA(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.a, 0x00, "The accumulator's value should be 0x00 but it was 0x%x.", snes.cpu->_registers.a);
cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set.");
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flags should be set.");
}
Test(INC, simple)
{
Init()
snes.cpu->_registers.p.m = true;
snes.wram->_data[0] = 0x56;
snes.cpu->INC(0x0, ComSquare::CPU::AddressingMode::Absolute);
cr_assert_eq(snes.wram->_data[0], 0x57, "The incremented value should be 0x57 but it was 0x%x.", snes.wram->_data[0]);
cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set.");
}
Test(INC, negative)
{
Init()
snes.cpu->_registers.p.m = true;
snes.wram->_data[0] = 0x7F;
snes.cpu->INC(0x0, ComSquare::CPU::AddressingMode::Absolute);
cr_assert_eq(snes.wram->_data[0], 0x80, "The incremented value should be 0x80 but it was 0x%x.", snes.wram->_data[0]);
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set.");
}
Test(INC, accumulator)
{
Init()
snes.cpu->_registers.p.m = true;
snes.cpu->_registers.a = 0x56;
snes.cpu->INC(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.a, 0x57, "The incremented value should be 0x57 but it was 0x%x.", snes.cpu->_registers.a);
cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set.");
}
Test(INC, negativeAccumulator)
{
Init()
snes.cpu->_registers.p.m = true;
snes.cpu->_registers.a = 0x7F;
snes.cpu->INC(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.a, 0x80, "The incremented value should be 0x80 but it was 0x%x.", snes.cpu->_registers.a);
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set.");
}
Test(INC, nativeAccumulator)
{
Init()
snes.cpu->_registers.p.m = false;
snes.cpu->_registers.a = 0x5600;
snes.cpu->INC(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.a, 0x5601, "The incremented value should be 0x5601 but it was 0x%x.", snes.cpu->_registers.a);
cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set.");
}
Test(INC, negativeNativeAccumulator)
{
Init()
snes.cpu->_registers.p.m = false;
snes.cpu->_registers.a = 0x8FFF;
snes.cpu->INC(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.a, 0x9000, "The incremented value should be 0x9000 but it was 0x%x.", snes.cpu->_registers.a);
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set.");
}
Test(DEC, simple)
{
Init()
snes.cpu->_registers.p.m = true;
snes.wram->_data[0] = 0x58;
snes.cpu->DEC(0x0, ComSquare::CPU::AddressingMode::Absolute);
cr_assert_eq(snes.wram->_data[0], 0x57, "The incremented value should be 0x57 but it was 0x%x.", snes.wram->_data[0]);
cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set.");
}
Test(DEC, negative)
{
Init()
snes.cpu->_registers.p.m = true;
snes.wram->_data[0] = 0x81;
snes.cpu->DEC(0x0, ComSquare::CPU::AddressingMode::Absolute);
cr_assert_eq(snes.wram->_data[0], 0x80, "The incremented value should be 0x80 but it was 0x%x.", snes.wram->_data[0]);
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set.");
}
Test(DEC, accumulator)
{
Init()
snes.cpu->_registers.p.m = true;
snes.cpu->_registers.a = 0x58;
snes.cpu->DEC(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.a, 0x57, "The incremented value should be 0x57 but it was 0x%x.", snes.cpu->_registers.a);
cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set.");
}
Test(DEC, negativeAccumulator)
{
Init()
snes.cpu->_registers.p.m = true;
snes.cpu->_registers.a = 0x81;
snes.cpu->DEC(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.a, 0x80, "The incremented value should be 0x80 but it was 0x%x.", snes.cpu->_registers.a);
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set.");
}
Test(DEC, nativeAccumulator)
{
Init()
snes.cpu->_registers.p.m = false;
snes.cpu->_registers.a = 0x5602;
snes.cpu->DEC(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.a, 0x5601, "The incremented value should be 0x5601 but it was 0x%x.", snes.cpu->_registers.a);
cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set.");
}
Test(DEC, negativeNativeAccumulator)
{
Init()
snes.cpu->_registers.p.m = false;
snes.cpu->_registers.a = 0x9001;
snes.cpu->DEC(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.a, 0x9000, "The incremented value should be 0x9000 but it was 0x%x.", snes.cpu->_registers.a);
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set.");
}
Test(EOR, simple)
{
Init()
snes.cpu->_registers.p.m = true;
snes.cpu->_registers.a = 0x80;
snes.wram->_data[0] = 0x0F;
snes.cpu->EOR(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.a, 0x8F, "The accumulator's value should be 0x8F but it was 0x%x.", snes.cpu->_registers.a);
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set.");
}
Test(EOR, simple2)
{
Init()
snes.cpu->_registers.p.m = true;
snes.cpu->_registers.a = 0x80;
snes.wram->_data[0] = 0xF0;
snes.cpu->EOR(0x00, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.a, 0x70, "The accumulator's value should be 0x70 but it was 0x%x.", snes.cpu->_registers.a);
cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set.");
}
Test(EOR, zero)
{
Init()
snes.cpu->_registers.p.m = true;
snes.cpu->_registers.a = 0x00;
snes.wram->_data[0] = 0x00;
snes.cpu->EOR(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.a, 0x00, "The accumulator's value should be 0x00 but it was 0x%x.", snes.cpu->_registers.a);
cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set.");
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flags should be set.");
}
Test(XBA, zero)
{
Init()
snes.cpu->_registers.a = 0x0001;
snes.cpu->XBA(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.a, 0x0100, "The accumulator's value should be 0x0100 but it was 0x%x.", snes.cpu->_registers.a);
cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set.");
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flags should be set.");
}
Test(XBA, negative)
{
Init()
snes.cpu->_registers.a = 0x8001;
snes.cpu->XBA(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.a, 0x0180, "The accumulator's value should be 0x0180 but it was 0x%x.", snes.cpu->_registers.a);
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should be not set.");
}

View File

@@ -62,7 +62,7 @@ Test(SBC, overflowEmulation)
Init() Init()
snes.cpu->_isEmulationMode = true; snes.cpu->_isEmulationMode = true;
snes.cpu->_registers.a = 0x1; snes.cpu->_registers.a = 0x1;
snes.cpu->_registers.p.m = false; snes.cpu->_registers.p.m = true;
snes.cpu->_registers.p.c = false; snes.cpu->_registers.p.c = false;
snes.wram->_data[0] = 0x02; snes.wram->_data[0] = 0x02;
snes.cpu->SBC(0x0, ComSquare::CPU::AddressingMode::Implied); snes.cpu->SBC(0x0, ComSquare::CPU::AddressingMode::Implied);

View File

@@ -145,3 +145,294 @@ Test(TXS, 8bitsIndex)
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set."); cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
} }
Test(TCD, emulationMode)
{
Init()
snes.cpu->_isEmulationMode = true;
snes.cpu->_registers.p.m = true;
snes.cpu->_registers.d = 0x5656;
snes.cpu->_registers.a = 0xABCD;
snes.cpu->TCD(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.d, 0xABCD, "The direct page should be 0xABCD but it was %x", snes.cpu->_registers.d);
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
}
Test(TCD, zero)
{
Init()
snes.cpu->_isEmulationMode = true;
snes.cpu->_registers.p.m = true;
snes.cpu->_registers.d = 0x5656;
snes.cpu->_registers.a = 0x0;
snes.cpu->TCD(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.d, 0, "The direct page should be 0x0 but it was %x", snes.cpu->_registers.d);
cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set.");
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.");
}
Test(TCS, emulationMode)
{
Init()
snes.cpu->_isEmulationMode = true;
snes.cpu->_registers.p.m = false;
snes.cpu->_registers.s = 0x0156;
snes.cpu->_registers.a = 0xABCD;
snes.cpu->TCS(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.s, 0x01CD, "The stack pointer should be 0x01CD but it was %x", snes.cpu->_registers.s);
}
Test(TCS, native)
{
Init()
snes.cpu->_isEmulationMode = false;
snes.cpu->_registers.p.m = true;
snes.cpu->_registers.s = 0x0156;
snes.cpu->_registers.a = 0xABCD;
snes.cpu->TCS(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.s, 0xABCD, "The stack pointer should be 0xABCD but it was %x", snes.cpu->_registers.s);
}
Test(TDC, emulationMode)
{
Init()
snes.cpu->_isEmulationMode = true;
snes.cpu->_registers.p.m = true;
snes.cpu->_registers.d = 0xABCD;
snes.cpu->_registers.a = 0x5656;
snes.cpu->TDC(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.a, 0xABCD, "The accumulator should be 0xABCD but it was %x", snes.cpu->_registers.a);
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
}
Test(TDC, zero)
{
Init()
snes.cpu->_isEmulationMode = true;
snes.cpu->_registers.p.m = true;
snes.cpu->_registers.d = 0x0;
snes.cpu->_registers.a = 0x5656;
snes.cpu->TDC(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.a, 0, "The accumulator should be 0x0 but it was %x", snes.cpu->_registers.a);
cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set.");
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.");
}
Test(TSC, emulationMode)
{
Init()
snes.cpu->_isEmulationMode = true;
snes.cpu->_registers.p.m = true;
snes.cpu->_registers.s = 0xABCD;
snes.cpu->_registers.a = 0x5656;
snes.cpu->TSC(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.a, 0xABCD, "The accumulator should be 0xABCD but it was %x", snes.cpu->_registers.a);
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
}
Test(TSC, zero)
{
Init()
snes.cpu->_isEmulationMode = true;
snes.cpu->_registers.p.m = true;
snes.cpu->_registers.s = 0x0;
snes.cpu->_registers.a = 0x5656;
snes.cpu->TSC(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.a, 0, "The accumulator should be 0x0 but it was %x", snes.cpu->_registers.a);
cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set.");
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.");
}
Test(TSX, emulationMode)
{
Init()
snes.cpu->_isEmulationMode = true;
snes.cpu->_registers.p.x_b = true;
snes.cpu->_registers.s = 0xABCD;
snes.cpu->_registers.x = 0x5656;
snes.cpu->TSX(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.x, 0x00CD, "The x index should be 0x00CD but it was %x", snes.cpu->_registers.x);
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
}
Test(TSX, native)
{
Init()
snes.cpu->_isEmulationMode = false;
snes.cpu->_registers.p.x_b = false;
snes.cpu->_registers.s = 0x8F00;
snes.cpu->_registers.x = 0x5656;
snes.cpu->TSX(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.x, 0x8F00, "The x index should be 0x8F00 but it was %x", snes.cpu->_registers.x);
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
}
Test(TXA, double8bits)
{
Init()
snes.cpu->_isEmulationMode = true;
snes.cpu->_registers.p.m = true;
snes.cpu->_registers.p.x_b = true;
snes.cpu->_registers.x = 0xABCD;
snes.cpu->_registers.a = 0x5656;
snes.cpu->TXA(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.a, 0x56CD, "The accumulator should be 0x56CD but it was %x", snes.cpu->_registers.a);
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
}
Test(TXA, index8bits)
{
Init()
snes.cpu->_isEmulationMode = false;
snes.cpu->_registers.p.m = false;
snes.cpu->_registers.p.x_b = true;
snes.cpu->_registers.x = 0x0BCD;
snes.cpu->_registers.a = 0x5656;
snes.cpu->TXA(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.a, 0x00CD, "The accumulator should be 0x00CD but it was %x", snes.cpu->_registers.a);
cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
}
Test(TXA, accumulator8bits)
{
Init()
snes.cpu->_isEmulationMode = false;
snes.cpu->_registers.p.m = true;
snes.cpu->_registers.p.x_b = false;
snes.cpu->_registers.x = 0x0BCD;
snes.cpu->_registers.a = 0x5656;
snes.cpu->TXA(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.a, 0x56CD, "The accumulator should be 0x56CD but it was %x", snes.cpu->_registers.a);
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
}
Test(TXA, double16bits)
{
Init()
snes.cpu->_isEmulationMode = false;
snes.cpu->_registers.p.m = false;
snes.cpu->_registers.p.x_b = false;
snes.cpu->_registers.x = 0xAB0D;
snes.cpu->_registers.a = 0x5656;
snes.cpu->TXA(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.a, 0xAB0D, "The accumulator should be 0xAB0D but it was %x", snes.cpu->_registers.a);
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
}
Test(TYA, double8bits)
{
Init()
snes.cpu->_isEmulationMode = true;
snes.cpu->_registers.p.m = true;
snes.cpu->_registers.p.x_b = true;
snes.cpu->_registers.y = 0xABCD;
snes.cpu->_registers.a = 0x5656;
snes.cpu->TYA(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.a, 0x56CD, "The accumulator should be 0x56CD but it was %x", snes.cpu->_registers.a);
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
}
Test(TYA, index8bits)
{
Init()
snes.cpu->_isEmulationMode = false;
snes.cpu->_registers.p.m = false;
snes.cpu->_registers.p.x_b = true;
snes.cpu->_registers.y = 0x0BCD;
snes.cpu->_registers.a = 0x5656;
snes.cpu->TYA(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.a, 0x00CD, "The accumulator should be 0x00CD but it was %x", snes.cpu->_registers.a);
cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
}
Test(TYA, accumulator8bits)
{
Init()
snes.cpu->_isEmulationMode = false;
snes.cpu->_registers.p.m = true;
snes.cpu->_registers.p.x_b = false;
snes.cpu->_registers.y = 0x0BCD;
snes.cpu->_registers.a = 0x5656;
snes.cpu->TYA(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.a, 0x56CD, "The accumulator should be 0x56CD but it was %x", snes.cpu->_registers.a);
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
}
Test(TYA, double16bits)
{
Init()
snes.cpu->_isEmulationMode = false;
snes.cpu->_registers.p.m = false;
snes.cpu->_registers.p.x_b = false;
snes.cpu->_registers.y = 0xAB0D;
snes.cpu->_registers.a = 0x5656;
snes.cpu->TYA(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.a, 0xAB0D, "The accumulator should be 0xAB0D but it was %x", snes.cpu->_registers.a);
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
}
Test(TXY, emulationMode)
{
Init()
snes.cpu->_isEmulationMode = true;
snes.cpu->_registers.p.x_b = true;
snes.cpu->_registers.x = 0x0BCD;
snes.cpu->_registers.y = 0x5656;
snes.cpu->TXY(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.y, 0x56CD, "The y index should be 0x56CD but it was %x", snes.cpu->_registers.y);
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
}
Test(TXY, nativeMode)
{
Init()
snes.cpu->_isEmulationMode = false;
snes.cpu->_registers.p.x_b = false;
snes.cpu->_registers.x = 0xAB0D;
snes.cpu->_registers.y = 0x5656;
snes.cpu->TXY(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.y, 0xAB0D, "The y index should be 0xAB0D but it was %x", snes.cpu->_registers.y);
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
}
Test(TYX, emulationMode)
{
Init()
snes.cpu->_isEmulationMode = true;
snes.cpu->_registers.p.x_b = true;
snes.cpu->_registers.y = 0x0BCD;
snes.cpu->_registers.x = 0x5656;
snes.cpu->TYX(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.x, 0x56CD, "The x index should be 0x56CD but it was %x", snes.cpu->_registers.x);
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
}
Test(TYX, nativeMode)
{
Init()
snes.cpu->_isEmulationMode = false;
snes.cpu->_registers.p.x_b = false;
snes.cpu->_registers.y = 0xAB0D;
snes.cpu->_registers.x = 0x5656;
snes.cpu->TYX(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.x, 0xAB0D, "The x index should be 0xAB0D but it was %x", snes.cpu->_registers.x);
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
}

View File

@@ -181,45 +181,45 @@ Test(AddrMode, AbsoluteLongIndexByX)
cr_assert_eq(snes.cpu->_registers.pac, 0x808003); cr_assert_eq(snes.cpu->_registers.pac, 0x808003);
} }
Test(AddrMode, ProgramCounterRelativePositive) //Test(AddrMode, ProgramCounterRelativePositive)
{ //{
Init() // Init()
snes.cpu->_registers.pac = 0x808010; // snes.cpu->_registers.pac = 0x808010;
snes.cartridge->_data[0x10] = 0x15; // snes.cartridge->_data[0x10] = 0x15;
cr_assert_eq(snes.cpu->_getProgramCounterRelativeAddr(), 0x808025, "Returned address was %x but was expecting 0x808025.", snes.cpu->_getProgramCounterRelativeAddr()); // cr_assert_eq(snes.cpu->_getProgramCounterRelativeAddr(), 0x808025, "Returned address was %x but was expecting 0x808025.", snes.cpu->_getProgramCounterRelativeAddr());
cr_assert_eq(snes.cpu->_registers.pac, 0x808011); // cr_assert_eq(snes.cpu->_registers.pac, 0x808011);
} //}
//
Test(AddrMode, ProgramCounterRelativeNegative) //Test(AddrMode, ProgramCounterRelativeNegative)
{ //{
Init() // Init()
snes.cpu->_registers.pac = 0x808010; // snes.cpu->_registers.pac = 0x808010;
snes.cartridge->_data[0x10] = -0x15; // snes.cartridge->_data[0x10] = -0x15;
cr_assert_eq(snes.cpu->_getProgramCounterRelativeAddr(), 0x807FFB, "Returned address was %x but was expecting 0x807FFB.", snes.cpu->_getProgramCounterRelativeAddr()); // cr_assert_eq(snes.cpu->_getProgramCounterRelativeAddr(), 0x807FFB, "Returned address was %x but was expecting 0x807FFB.", snes.cpu->_getProgramCounterRelativeAddr());
cr_assert_eq(snes.cpu->_registers.pac, 0x808011); // cr_assert_eq(snes.cpu->_registers.pac, 0x808011);
} //}
//
Test(AddrMode, ProgramCounterRelativeLongPositive) //Test(AddrMode, ProgramCounterRelativeLongPositive)
{ //{
Init() // Init()
snes.cpu->_registers.pac = 0x808010; // snes.cpu->_registers.pac = 0x808010;
snes.cartridge->_data[0x10] = 0x15; // snes.cartridge->_data[0x10] = 0x15;
snes.cartridge->_data[0x11] = 0x10; // snes.cartridge->_data[0x11] = 0x10;
auto addr = snes.cpu->_getProgramCounterRelativeLongAddr(); // auto addr = snes.cpu->_getProgramCounterRelativeLongAddr();
cr_assert_eq(addr, 0x809025, "Returned address was %x but was expecting 0x809025.", addr); // cr_assert_eq(addr, 0x809025, "Returned address was %x but was expecting 0x809025.", addr);
cr_assert_eq(snes.cpu->_registers.pac, 0x808012); // cr_assert_eq(snes.cpu->_registers.pac, 0x808012);
} //}
//
Test(AddrMode, ProgramCounterRelativeLongNegative) //Test(AddrMode, ProgramCounterRelativeLongNegative)
{ //{
Init() // Init()
snes.cpu->_registers.pac = 0x808010; // snes.cpu->_registers.pac = 0x808010;
snes.cartridge->_data[0x10] = 0x10; // snes.cartridge->_data[0x10] = 0x10;
snes.cartridge->_data[0x11] = -0x15; // snes.cartridge->_data[0x11] = -0x15;
auto addr = snes.cpu->_getProgramCounterRelativeLongAddr(); // auto addr = snes.cpu->_getProgramCounterRelativeLongAddr();
cr_assert_eq(addr, 0x806B00, "Returned address was %x but was expecting 0x806B00.", addr); // cr_assert_eq(addr, 0x806B00, "Returned address was %x but was expecting 0x806B00.", addr);
cr_assert_eq(snes.cpu->_registers.pac, 0x808012); // cr_assert_eq(snes.cpu->_registers.pac, 0x808012);
} //}
Test(AddrMode, AbsoluteIndirect) Test(AddrMode, AbsoluteIndirect)
{ {

View File

@@ -35,7 +35,6 @@ Test(AND, nativeNegative)
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.");
} }
Test(AND, emulationTest) Test(AND, emulationTest)
{ {
Init() Init()
@@ -48,3 +47,27 @@ Test(AND, emulationTest)
cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set."); cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set.");
} }
Test(TSB, emulationTest)
{
Init()
snes.wram->_data[0] = 0b00110011;
snes.cpu->_registers.a = 0b00110111;
snes.cpu->_registers.p.m = true;
snes.cpu->TSB(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.wram->_data[0], 0b00110111, "The data in ram should be 0b00110111 but it was %x", snes.wram->_data[0]);
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.");
}
Test(TSB, nativeTest)
{
Init()
snes.wram->_data[0] = 0xF0;
snes.wram->_data[1] = 0x0F;
snes.cpu->_registers.a = 0x8008;
snes.cpu->_registers.p.m = false;
snes.cpu->TSB(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.wram->_data[0], 0xF8, "The first data in ram should be 0xF8 but it was %x", snes.wram->_data[0]);
cr_assert_eq(snes.wram->_data[1], 0x8F, "The second data in ram should be 0x8F but it was %x", snes.wram->_data[1]);
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.");
}

View File

@@ -20,14 +20,14 @@ Test(CPU_emulated, BRK)
snes.cpu->_registers.pbr = 0x15; snes.cpu->_registers.pbr = 0x15;
snes.cpu->BRK(0x0, ComSquare::CPU::AddressingMode::Implied); snes.cpu->BRK(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.pc, 0x123u, "The program counter should be 0x123u but it was 0x%X", snes.cpu->_registers.pc); cr_assert_eq(snes.cpu->_registers.pc, 0x123u, "The program counter should be 0x123u but it was 0x%X", snes.cpu->_registers.pc);
cr_assert_eq(snes.cpu->_registers.pbr, 0x15, "The PBR should be 0x15 but it was 0x%X", snes.cpu->_registers.pbr); cr_assert_eq(snes.cpu->_registers.pbr, 0x0, "The PBR should be 0x0 but it was 0x%X", snes.cpu->_registers.pbr);
cr_assert_eq(snes.cpu->_registers.p.d, false, "The decimal flag should not be set."); cr_assert_eq(snes.cpu->_registers.p.d, false, "The decimal flag should not be set.");
cr_assert_eq(snes.cpu->_registers.p.i, true, "The Interrupt disable flag should be set."); cr_assert_eq(snes.cpu->_registers.p.i, true, "The Interrupt disable flag should be set.");
cr_assert_eq(snes.cpu->_registers.p.x_b, true, "The break flag should be set."); cr_assert_eq(snes.cpu->_registers.p.x_b, true, "The break flag should be set.");
int data = snes.cpu->_pop(); int data = snes.cpu->_pop();
cr_assert_eq(data, 0xF1, "The Status Registers should be pushed into the stack with the value 0xF1 but it was 0x%X (expected 0xF1).", data); cr_assert_eq(data, 0xF1, "The Status Registers should be pushed into the stack with the value 0xF1 but it was 0x%X (expected 0xF1).", data);
data = snes.cpu->_pop16(); data = snes.cpu->_pop16();
cr_assert_eq(data, 0x158u, "The program counter should be incremented by two and pushed on the stack but it was 0x%X (expected 0x158).", data); cr_assert_eq(data, 0x156u, "The program counter should be incremented by two and pushed on the stack but it was 0x%X (expected 0x158).", data);
} }
Test(CPU_native, BRK) Test(CPU_native, BRK)
@@ -46,7 +46,7 @@ Test(CPU_native, BRK)
int data = snes.cpu->_pop(); int data = snes.cpu->_pop();
cr_assert_eq(data, 0xF1, "The Status Registers should be pushed into the stack with the value 0xF1 but it was 0x%X (expected 0xF1).", data); cr_assert_eq(data, 0xF1, "The Status Registers should be pushed into the stack with the value 0xF1 but it was 0x%X (expected 0xF1).", data);
data = snes.cpu->_pop16(); data = snes.cpu->_pop16();
cr_assert_eq(data, 0x158u, "The program counter should be incremented by two and pushed on the stack but it was 0x%X (expected 0x158).", data); cr_assert_eq(data, 0x156u, "The program counter should be incremented by two and pushed on the stack but it was 0x%X (expected 0x156).", data);
data = snes.cpu->_pop(); data = snes.cpu->_pop();
cr_assert_eq(data, 0x15, "The program bank register should be pushed on the stack but it was 0x%X (expected 0x15).", data); cr_assert_eq(data, 0x15, "The program bank register should be pushed on the stack but it was 0x%X (expected 0x15).", data);
} }
@@ -61,14 +61,14 @@ Test(CPU_emulated, COP)
snes.cpu->_registers.pbr = 0x15; snes.cpu->_registers.pbr = 0x15;
snes.cpu->COP(0x0, ComSquare::CPU::AddressingMode::Implied); snes.cpu->COP(0x0, ComSquare::CPU::AddressingMode::Implied);
cr_assert_eq(snes.cpu->_registers.pc, 0x123u, "The program counter should be 0x123u but it was 0x%X", snes.cpu->_registers.pc); cr_assert_eq(snes.cpu->_registers.pc, 0x123u, "The program counter should be 0x123u but it was 0x%X", snes.cpu->_registers.pc);
cr_assert_eq(snes.cpu->_registers.pbr, 0x15, "The PBR should be 0x15 but it was 0x%X", snes.cpu->_registers.pbr); cr_assert_eq(snes.cpu->_registers.pbr, 0x0, "The PBR should be 0x0 but it was 0x%X", snes.cpu->_registers.pbr);
cr_assert_eq(snes.cpu->_registers.p.d, false, "The decimal flag should not be set."); cr_assert_eq(snes.cpu->_registers.p.d, false, "The decimal flag should not be set.");
cr_assert_eq(snes.cpu->_registers.p.i, true, "The Interrupt disable flag should be set."); cr_assert_eq(snes.cpu->_registers.p.i, true, "The Interrupt disable flag should be set.");
cr_assert_eq(snes.cpu->_registers.p.x_b, false, "The break flag should not be set."); cr_assert_eq(snes.cpu->_registers.p.x_b, false, "The break flag should not be set.");
int data = snes.cpu->_pop(); int data = snes.cpu->_pop();
cr_assert_eq(data, 0x0F, "The Status Registers should be pushed into the stack with the value 0x0F but it was 0x%X (expected 0xF1).", data); cr_assert_eq(data, 0x0F, "The Status Registers should be pushed into the stack with the value 0x0F but it was 0x%X (expected 0xF1).", data);
data = snes.cpu->_pop16(); data = snes.cpu->_pop16();
cr_assert_eq(data, 0x158u, "The program counter should be incremented by two and pushed on the stack but it was 0x%X (expected 0x158).", data); cr_assert_eq(data, 0x156u, "The program counter should be incremented by two and pushed on the stack but it was 0x%X (expected 0x158).", data);
} }
Test(CPU_native, COP) Test(CPU_native, COP)
@@ -87,7 +87,7 @@ Test(CPU_native, COP)
int data = snes.cpu->_pop(); int data = snes.cpu->_pop();
cr_assert_eq(data, 0xF1, "The Status Registers should be pushed into the stack with the value 0xF1 but it was 0x%X (expected 0xF1).", data); cr_assert_eq(data, 0xF1, "The Status Registers should be pushed into the stack with the value 0xF1 but it was 0x%X (expected 0xF1).", data);
data = snes.cpu->_pop16(); data = snes.cpu->_pop16();
cr_assert_eq(data, 0x158u, "The program counter should be incremented by two and pushed on the stack but it was 0x%X (expected 0x158).", data); cr_assert_eq(data, 0x156u, "The program counter should be incremented by two and pushed on the stack but it was 0x%X (expected 0x156).", data);
data = snes.cpu->_pop(); data = snes.cpu->_pop();
cr_assert_eq(data, 0x15, "The program bank register should be pushed on the stack but it was 0x%X (expected 0x15).", data); cr_assert_eq(data, 0x15, "The program bank register should be pushed on the stack but it was 0x%X (expected 0x15).", data);
} }

View File

@@ -0,0 +1,89 @@
//
// Created by anonymus-raccoon on 4/6/20.
//
#include <criterion/criterion.h>
#include <criterion/redirect.h>
#include "tests.hpp"
#include "../sources/SNES.hpp"
#include "../sources/Renderer/NoRenderer.hpp"
#include "../sources/PPU/PPU.hpp"
#include "../sources/Memory/RectangleShadow.hpp"
#include "../sources/Utility/Utility.hpp"
using namespace ComSquare;
Test(RectangleMemory, HorizontalRamRead)
{
Ram::Ram ram(0xFF, Component::Rom, "Rom");
ram.setMemoryRegion(0x00, 0xFF, 0x0000, 0x0001);
for (int i = 0x00; i < 0xFF; i++)
ram._data[i] = i;
for (uint24_t i = 0x000000; i < 0xFF0000; i += 0x010000)
cr_assert_eq(ram.read(i), i >> 16u, "The ram's read returned 0x%x but the internal ram value was: 0x%x (addr: 0x%06x)", ram.read(i), i >> 16, i);
}
Test(RectangleMemory, HorizontalRamWrite)
{
Ram::Ram ram(0xFF, Component::Rom, "Rom");
ram.setMemoryRegion(0x00, 0xFF, 0x0000, 0x0001);
for (uint24_t i = 0x000000; i < 0xFF0000; i += 0x010000)
ram.write(i, i >> 16u);
for (int i = 0x00; i < 0xFF; i++)
cr_assert_eq(ram._data[i], i, "The ram's write put 0x%x but it should had put: 0x%x (addr: 0x%06x)", ram._data[i], i, i << 16u);
}
Test(RectangleMemory, DualLineRamRead)
{
Ram::Ram ram(0xFF * 2, Component::Rom, "Rom");
ram.setMemoryRegion(0x00, 0xFF, 0x0000, 0x0002);
for (int i = 0x00; i < 0xFF * 2; i++)
ram._data[i] = i;
for (uint24_t i = 0x000000, v = 0; v < 0xFF * 2; i += 0x010000, v += 2) {
cr_assert_eq(ram.read(i), (uint8_t)(v), "The ram's read returned 0x%x but the internal ram value was: 0x%x (addr: 0x%06x)", ram.read(i), (uint8_t)(v), i);
cr_assert_eq(ram.read(i + 1), (uint8_t)(v + 1), "The ram's read returned 0x%x but the internal ram value was: 0x%x (addr: 0x%06x)", ram.read(i + 1), (uint8_t)(v + 1), i + 1);
}
}
Test(RectangleMemory, HorizontalRamShadowRead)
{
std::shared_ptr<Ram::Ram> ram = std::make_shared<Ram::Ram>(0xFF, Component::Rom, "Rom");
ram->setMemoryRegion(0x00, 0xFF, 0x0000, 0x0001);
Memory::RectangleShadow shadow(ram, 0x00, 0xFF, 0x8000, 0x8001);
for (int i = 0x00; i < 0xFF; i++)
ram->_data[i] = i;
for (uint24_t i = 0x008000; i < 0xFF8000; i += 0x010000) {
uint8_t v = shadow.read(i - shadow.getStart());
cr_assert_eq(v, i >> 16u, "The ram's read returned 0x%x but the internal ram value was: 0x%x (addr: 0x%06x)", v, i >> 16, i);
}}
Test(RectangleMemory, HorizontalRamShadowReadWithBankOffset)
{
std::shared_ptr<Ram::Ram> ram = std::make_shared<Ram::Ram>(0xFF, Component::Rom, "Rom");
ram->setMemoryRegion(0x00, 0xFF, 0x0000, 0x0001);
Memory::RectangleShadow shadow(ram, 0x80, 0xFF, 0x8000, 0x8001);
for (int i = 0x00; i < 0xFF; i++)
ram->_data[i] = i;
shadow.setBankOffset(0x80);
for (uint24_t i = 0x808000; i < 0xFF8000; i += 0x010000) {
uint8_t v = shadow.read(i - shadow.getStart());
cr_assert_eq(v, i >> 16u, "The ram's read returned 0x%x but the internal ram value was: 0x%x (addr: 0x%06x)", v, i >> 16, i);
}
}
Test(RectangleMemory, ShadowOffsetCartridge)
{
std::shared_ptr<Ram::Ram> ram = std::make_shared<Ram::Ram>(0x3fff80, Component::Rom, "Rom");
ram->setMemoryRegion(0x80, 0xFF, 0x8000, 0xFFFF);
Memory::RectangleShadow shadow(ram, 0xC0, 0xEF, 0x0000, 0x7FFF);
for (int i = 0x00; i < 0x3fff80; i++)
ram->_data[i] = i;
shadow.setBankOffset(0x40);
for (uint24_t i = 0xC00000; i < 0xEF7FFF; i += 0x1) {
if ((uint16_t)i > 0x7FFFu)
i += 0x010000 - 0x8000;
uint8_t v = shadow.read(i - shadow.getStart());
uint8_t r = ram->read(i + 0x8000 - ram->getStart());
cr_assert_eq(v, r, "The ram's read returned 0x%x but the internal ram value was: 0x%x (addr: 0x%06x)", v, r, i);
}
}

221
ui/cpu.ui
View File

@@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>971</width> <width>1058</width>
<height>709</height> <height>673</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@@ -21,8 +21,8 @@
<bool>false</bool> <bool>false</bool>
</property> </property>
<widget class="QWidget" name="centralwidget"> <widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0" rowspan="2"> <item row="0" column="0" rowspan="3">
<widget class="QTableView" name="disassembly"> <widget class="QTableView" name="disassembly">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding"> <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
@@ -54,6 +54,27 @@
</widget> </widget>
</item> </item>
<item row="0" column="1"> <item row="0" column="1">
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="0">
<widget class="QTableView" name="stackView">
<attribute name="horizontalHeaderVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Stack Viewer</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="2" rowspan="2">
<layout class="QFormLayout" name="formLayout"> <layout class="QFormLayout" name="formLayout">
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="accumulatorLabel"> <widget class="QLabel" name="accumulatorLabel">
@@ -140,23 +161,13 @@
<widget class="QLineEdit" name="yIndexLineEdit"/> <widget class="QLineEdit" name="yIndexLineEdit"/>
</item> </item>
<item row="8" column="0"> <item row="8" column="0">
<widget class="QLabel" name="flagsLabel">
<property name="text">
<string>Flags</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLineEdit" name="flagsLineEdit"/>
</item>
<item row="9" column="0">
<widget class="QLabel" name="emulationModeLabel"> <widget class="QLabel" name="emulationModeLabel">
<property name="text"> <property name="text">
<string>Emulation mode</string> <string>Emulation mode</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="9" column="1"> <item row="8" column="1">
<widget class="QCheckBox" name="emulationModeCheckBox"> <widget class="QCheckBox" name="emulationModeCheckBox">
<property name="layoutDirection"> <property name="layoutDirection">
<enum>Qt::RightToLeft</enum> <enum>Qt::RightToLeft</enum>
@@ -168,15 +179,8 @@
</item> </item>
</layout> </layout>
</item> </item>
<item row="1" column="1"> <item row="1" column="1" rowspan="2">
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="2" column="0">
<widget class="QPushButton" name="clear">
<property name="text">
<string>Clear History</string>
</property>
</widget>
</item>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="loggerLabel"> <widget class="QLabel" name="loggerLabel">
<property name="text"> <property name="text">
@@ -187,11 +191,180 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0">
<widget class="QPushButton" name="clear">
<property name="text">
<string>Clear History</string>
</property>
</widget>
</item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QTextBrowser" name="logger"/> <widget class="QTableView" name="history"/>
</item> </item>
</layout> </layout>
</item> </item>
<item row="2" column="2">
<widget class="QGroupBox" name="formGroupBox">
<property name="title">
<string>Flags</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="flat">
<bool>false</bool>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<layout class="QFormLayout" name="formLayout_2">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<property name="labelAlignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="formAlignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="leftMargin">
<number>26</number>
</property>
<property name="topMargin">
<number>7</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="negativeLabel">
<property name="text">
<string>Memory Select (M)</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="mCheckbox">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="zeroLabel">
<property name="text">
<string>Index Select (X)</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="xCheckbox">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="carryLabel">
<property name="text">
<string>Interupt Request Disable (I)</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="iCheckbox">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="Overflow">
<property name="text">
<string>Overflow (V)</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QCheckBox" name="vCheckbox">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="decimalLabel">
<property name="text">
<string>Decimal (D)</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QCheckBox" name="dCheckbox">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="memoryAccumulatorSelectLabel">
<property name="text">
<string>Carry (C)</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QCheckBox" name="cCheckbox">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="indeXSelectLabel">
<property name="text">
<string>Zero (Z)</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="irqDisableLabel">
<property name="text">
<string>Negative (N)</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QCheckBox" name="nCheckbox">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QCheckBox" name="zCheckbox">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="breakBLabel">
<property name="text">
<string>Break (B)</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="bCheckbox">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<widget class="QToolBar" name="toolBar"> <widget class="QToolBar" name="toolBar">

457
ui/ui_cpu.h Normal file
View File

@@ -0,0 +1,457 @@
/********************************************************************************
** Form generated from reading UI file 'cpu.ui'
**
** Created by: Qt User Interface Compiler version 5.14.1
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/
#ifndef UI_CPU_H
#define UI_CPU_H
#include <QtCore/QVariant>
#include <QtGui/QIcon>
#include <QtWidgets/QAction>
#include <QtWidgets/QApplication>
#include <QtWidgets/QCheckBox>
#include <QtWidgets/QFormLayout>
#include <QtWidgets/QGridLayout>
#include <QtWidgets/QGroupBox>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QLabel>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QTableView>
#include <QtWidgets/QToolBar>
#include <QtWidgets/QWidget>
QT_BEGIN_NAMESPACE
class Ui_CPUView
{
public:
QAction *actionPause;
QAction *actionStep;
QAction *actionNext;
QWidget *centralwidget;
QGridLayout *gridLayout_3;
QTableView *disassembly;
QGridLayout *gridLayout_2;
QTableView *stackView;
QLabel *label;
QFormLayout *formLayout;
QLabel *accumulatorLabel;
QLineEdit *accumulatorLineEdit;
QLabel *programBankRegisterLabel;
QLineEdit *programBankRegisterLineEdit;
QLabel *programCounterLabel;
QLineEdit *programCounterLineEdit;
QLabel *directBankLabel;
QLineEdit *directBankLineEdit;
QLabel *directPageLabel;
QLineEdit *directPageLineEdit;
QLabel *stackPointerLabel;
QLineEdit *stackPointerLineEdit;
QLabel *xIndexLabel;
QLineEdit *xIndexLineEdit;
QLabel *yIndexLabel;
QLineEdit *yIndexLineEdit;
QLabel *emulationModeLabel;
QCheckBox *emulationModeCheckBox;
QGridLayout *gridLayout;
QLabel *loggerLabel;
QPushButton *clear;
QTableView *history;
QGroupBox *formGroupBox;
QFormLayout *formLayout_2;
QLabel *negativeLabel;
QCheckBox *mCheckbox;
QLabel *zeroLabel;
QCheckBox *xCheckbox;
QLabel *carryLabel;
QCheckBox *iCheckbox;
QLabel *Overflow;
QCheckBox *vCheckbox;
QLabel *decimalLabel;
QCheckBox *dCheckbox;
QLabel *memoryAccumulatorSelectLabel;
QCheckBox *cCheckbox;
QLabel *indeXSelectLabel;
QLabel *irqDisableLabel;
QCheckBox *nCheckbox;
QCheckBox *zCheckbox;
QLabel *breakBLabel;
QCheckBox *bCheckbox;
QToolBar *toolBar;
void setupUi(QMainWindow *CPUView)
{
if (CPUView->objectName().isEmpty())
CPUView->setObjectName(QString::fromUtf8("CPUView"));
CPUView->resize(1058, 673);
QIcon icon;
icon.addFile(QString::fromUtf8(":/resources/Logo.png"), QSize(), QIcon::Normal, QIcon::Off);
CPUView->setWindowIcon(icon);
CPUView->setAutoFillBackground(false);
actionPause = new QAction(CPUView);
actionPause->setObjectName(QString::fromUtf8("actionPause"));
QIcon icon1;
icon1.addFile(QString::fromUtf8(":/resources/icons/play.svg"), QSize(), QIcon::Normal, QIcon::Off);
actionPause->setIcon(icon1);
actionStep = new QAction(CPUView);
actionStep->setObjectName(QString::fromUtf8("actionStep"));
QIcon icon2;
icon2.addFile(QString::fromUtf8(":/resources/icons/step.svg"), QSize(), QIcon::Normal, QIcon::Off);
actionStep->setIcon(icon2);
actionNext = new QAction(CPUView);
actionNext->setObjectName(QString::fromUtf8("actionNext"));
QIcon icon3;
icon3.addFile(QString::fromUtf8(":/resources/icons/continue.svg"), QSize(), QIcon::Normal, QIcon::Off);
actionNext->setIcon(icon3);
centralwidget = new QWidget(CPUView);
centralwidget->setObjectName(QString::fromUtf8("centralwidget"));
gridLayout_3 = new QGridLayout(centralwidget);
gridLayout_3->setObjectName(QString::fromUtf8("gridLayout_3"));
disassembly = new QTableView(centralwidget);
disassembly->setObjectName(QString::fromUtf8("disassembly"));
QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
sizePolicy.setHorizontalStretch(1);
sizePolicy.setVerticalStretch(0);
sizePolicy.setHeightForWidth(disassembly->sizePolicy().hasHeightForWidth());
disassembly->setSizePolicy(sizePolicy);
disassembly->setStyleSheet(QString::fromUtf8(""));
disassembly->setSelectionMode(QAbstractItemView::ExtendedSelection);
disassembly->setSelectionBehavior(QAbstractItemView::SelectRows);
disassembly->setShowGrid(false);
disassembly->setGridStyle(Qt::NoPen);
disassembly->horizontalHeader()->setVisible(false);
disassembly->horizontalHeader()->setHighlightSections(false);
gridLayout_3->addWidget(disassembly, 0, 0, 3, 1);
gridLayout_2 = new QGridLayout();
gridLayout_2->setObjectName(QString::fromUtf8("gridLayout_2"));
stackView = new QTableView(centralwidget);
stackView->setObjectName(QString::fromUtf8("stackView"));
stackView->horizontalHeader()->setVisible(false);
gridLayout_2->addWidget(stackView, 1, 0, 1, 1);
label = new QLabel(centralwidget);
label->setObjectName(QString::fromUtf8("label"));
label->setAlignment(Qt::AlignCenter);
gridLayout_2->addWidget(label, 0, 0, 1, 1);
gridLayout_3->addLayout(gridLayout_2, 0, 1, 1, 1);
formLayout = new QFormLayout();
formLayout->setObjectName(QString::fromUtf8("formLayout"));
accumulatorLabel = new QLabel(centralwidget);
accumulatorLabel->setObjectName(QString::fromUtf8("accumulatorLabel"));
formLayout->setWidget(0, QFormLayout::LabelRole, accumulatorLabel);
accumulatorLineEdit = new QLineEdit(centralwidget);
accumulatorLineEdit->setObjectName(QString::fromUtf8("accumulatorLineEdit"));
formLayout->setWidget(0, QFormLayout::FieldRole, accumulatorLineEdit);
programBankRegisterLabel = new QLabel(centralwidget);
programBankRegisterLabel->setObjectName(QString::fromUtf8("programBankRegisterLabel"));
formLayout->setWidget(1, QFormLayout::LabelRole, programBankRegisterLabel);
programBankRegisterLineEdit = new QLineEdit(centralwidget);
programBankRegisterLineEdit->setObjectName(QString::fromUtf8("programBankRegisterLineEdit"));
formLayout->setWidget(1, QFormLayout::FieldRole, programBankRegisterLineEdit);
programCounterLabel = new QLabel(centralwidget);
programCounterLabel->setObjectName(QString::fromUtf8("programCounterLabel"));
formLayout->setWidget(2, QFormLayout::LabelRole, programCounterLabel);
programCounterLineEdit = new QLineEdit(centralwidget);
programCounterLineEdit->setObjectName(QString::fromUtf8("programCounterLineEdit"));
formLayout->setWidget(2, QFormLayout::FieldRole, programCounterLineEdit);
directBankLabel = new QLabel(centralwidget);
directBankLabel->setObjectName(QString::fromUtf8("directBankLabel"));
formLayout->setWidget(3, QFormLayout::LabelRole, directBankLabel);
directBankLineEdit = new QLineEdit(centralwidget);
directBankLineEdit->setObjectName(QString::fromUtf8("directBankLineEdit"));
formLayout->setWidget(3, QFormLayout::FieldRole, directBankLineEdit);
directPageLabel = new QLabel(centralwidget);
directPageLabel->setObjectName(QString::fromUtf8("directPageLabel"));
formLayout->setWidget(4, QFormLayout::LabelRole, directPageLabel);
directPageLineEdit = new QLineEdit(centralwidget);
directPageLineEdit->setObjectName(QString::fromUtf8("directPageLineEdit"));
formLayout->setWidget(4, QFormLayout::FieldRole, directPageLineEdit);
stackPointerLabel = new QLabel(centralwidget);
stackPointerLabel->setObjectName(QString::fromUtf8("stackPointerLabel"));
formLayout->setWidget(5, QFormLayout::LabelRole, stackPointerLabel);
stackPointerLineEdit = new QLineEdit(centralwidget);
stackPointerLineEdit->setObjectName(QString::fromUtf8("stackPointerLineEdit"));
formLayout->setWidget(5, QFormLayout::FieldRole, stackPointerLineEdit);
xIndexLabel = new QLabel(centralwidget);
xIndexLabel->setObjectName(QString::fromUtf8("xIndexLabel"));
formLayout->setWidget(6, QFormLayout::LabelRole, xIndexLabel);
xIndexLineEdit = new QLineEdit(centralwidget);
xIndexLineEdit->setObjectName(QString::fromUtf8("xIndexLineEdit"));
formLayout->setWidget(6, QFormLayout::FieldRole, xIndexLineEdit);
yIndexLabel = new QLabel(centralwidget);
yIndexLabel->setObjectName(QString::fromUtf8("yIndexLabel"));
formLayout->setWidget(7, QFormLayout::LabelRole, yIndexLabel);
yIndexLineEdit = new QLineEdit(centralwidget);
yIndexLineEdit->setObjectName(QString::fromUtf8("yIndexLineEdit"));
formLayout->setWidget(7, QFormLayout::FieldRole, yIndexLineEdit);
emulationModeLabel = new QLabel(centralwidget);
emulationModeLabel->setObjectName(QString::fromUtf8("emulationModeLabel"));
formLayout->setWidget(8, QFormLayout::LabelRole, emulationModeLabel);
emulationModeCheckBox = new QCheckBox(centralwidget);
emulationModeCheckBox->setObjectName(QString::fromUtf8("emulationModeCheckBox"));
emulationModeCheckBox->setLayoutDirection(Qt::RightToLeft);
emulationModeCheckBox->setCheckable(true);
formLayout->setWidget(8, QFormLayout::FieldRole, emulationModeCheckBox);
gridLayout_3->addLayout(formLayout, 0, 2, 2, 1);
gridLayout = new QGridLayout();
gridLayout->setObjectName(QString::fromUtf8("gridLayout"));
loggerLabel = new QLabel(centralwidget);
loggerLabel->setObjectName(QString::fromUtf8("loggerLabel"));
loggerLabel->setAlignment(Qt::AlignCenter);
gridLayout->addWidget(loggerLabel, 0, 0, 1, 1);
clear = new QPushButton(centralwidget);
clear->setObjectName(QString::fromUtf8("clear"));
gridLayout->addWidget(clear, 2, 0, 1, 1);
history = new QTableView(centralwidget);
history->setObjectName(QString::fromUtf8("history"));
gridLayout->addWidget(history, 1, 0, 1, 1);
gridLayout_3->addLayout(gridLayout, 1, 1, 2, 1);
formGroupBox = new QGroupBox(centralwidget);
formGroupBox->setObjectName(QString::fromUtf8("formGroupBox"));
formGroupBox->setAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter);
formGroupBox->setFlat(false);
formGroupBox->setCheckable(false);
formLayout_2 = new QFormLayout(formGroupBox);
formLayout_2->setObjectName(QString::fromUtf8("formLayout_2"));
formLayout_2->setSizeConstraint(QLayout::SetDefaultConstraint);
formLayout_2->setLabelAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter);
formLayout_2->setFormAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop);
formLayout_2->setContentsMargins(26, 7, 0, -1);
negativeLabel = new QLabel(formGroupBox);
negativeLabel->setObjectName(QString::fromUtf8("negativeLabel"));
formLayout_2->setWidget(0, QFormLayout::LabelRole, negativeLabel);
mCheckbox = new QCheckBox(formGroupBox);
mCheckbox->setObjectName(QString::fromUtf8("mCheckbox"));
mCheckbox->setLayoutDirection(Qt::RightToLeft);
formLayout_2->setWidget(0, QFormLayout::FieldRole, mCheckbox);
zeroLabel = new QLabel(formGroupBox);
zeroLabel->setObjectName(QString::fromUtf8("zeroLabel"));
formLayout_2->setWidget(1, QFormLayout::LabelRole, zeroLabel);
xCheckbox = new QCheckBox(formGroupBox);
xCheckbox->setObjectName(QString::fromUtf8("xCheckbox"));
xCheckbox->setLayoutDirection(Qt::RightToLeft);
formLayout_2->setWidget(1, QFormLayout::FieldRole, xCheckbox);
carryLabel = new QLabel(formGroupBox);
carryLabel->setObjectName(QString::fromUtf8("carryLabel"));
formLayout_2->setWidget(3, QFormLayout::LabelRole, carryLabel);
iCheckbox = new QCheckBox(formGroupBox);
iCheckbox->setObjectName(QString::fromUtf8("iCheckbox"));
iCheckbox->setLayoutDirection(Qt::RightToLeft);
formLayout_2->setWidget(3, QFormLayout::FieldRole, iCheckbox);
Overflow = new QLabel(formGroupBox);
Overflow->setObjectName(QString::fromUtf8("Overflow"));
formLayout_2->setWidget(4, QFormLayout::LabelRole, Overflow);
vCheckbox = new QCheckBox(formGroupBox);
vCheckbox->setObjectName(QString::fromUtf8("vCheckbox"));
vCheckbox->setLayoutDirection(Qt::RightToLeft);
formLayout_2->setWidget(4, QFormLayout::FieldRole, vCheckbox);
decimalLabel = new QLabel(formGroupBox);
decimalLabel->setObjectName(QString::fromUtf8("decimalLabel"));
formLayout_2->setWidget(5, QFormLayout::LabelRole, decimalLabel);
dCheckbox = new QCheckBox(formGroupBox);
dCheckbox->setObjectName(QString::fromUtf8("dCheckbox"));
dCheckbox->setLayoutDirection(Qt::RightToLeft);
formLayout_2->setWidget(5, QFormLayout::FieldRole, dCheckbox);
memoryAccumulatorSelectLabel = new QLabel(formGroupBox);
memoryAccumulatorSelectLabel->setObjectName(QString::fromUtf8("memoryAccumulatorSelectLabel"));
formLayout_2->setWidget(6, QFormLayout::LabelRole, memoryAccumulatorSelectLabel);
cCheckbox = new QCheckBox(formGroupBox);
cCheckbox->setObjectName(QString::fromUtf8("cCheckbox"));
cCheckbox->setLayoutDirection(Qt::RightToLeft);
formLayout_2->setWidget(6, QFormLayout::FieldRole, cCheckbox);
indeXSelectLabel = new QLabel(formGroupBox);
indeXSelectLabel->setObjectName(QString::fromUtf8("indeXSelectLabel"));
formLayout_2->setWidget(7, QFormLayout::LabelRole, indeXSelectLabel);
irqDisableLabel = new QLabel(formGroupBox);
irqDisableLabel->setObjectName(QString::fromUtf8("irqDisableLabel"));
formLayout_2->setWidget(8, QFormLayout::LabelRole, irqDisableLabel);
nCheckbox = new QCheckBox(formGroupBox);
nCheckbox->setObjectName(QString::fromUtf8("nCheckbox"));
nCheckbox->setLayoutDirection(Qt::RightToLeft);
formLayout_2->setWidget(8, QFormLayout::FieldRole, nCheckbox);
zCheckbox = new QCheckBox(formGroupBox);
zCheckbox->setObjectName(QString::fromUtf8("zCheckbox"));
zCheckbox->setLayoutDirection(Qt::RightToLeft);
formLayout_2->setWidget(7, QFormLayout::FieldRole, zCheckbox);
breakBLabel = new QLabel(formGroupBox);
breakBLabel->setObjectName(QString::fromUtf8("breakBLabel"));
formLayout_2->setWidget(2, QFormLayout::LabelRole, breakBLabel);
bCheckbox = new QCheckBox(formGroupBox);
bCheckbox->setObjectName(QString::fromUtf8("bCheckbox"));
bCheckbox->setLayoutDirection(Qt::RightToLeft);
formLayout_2->setWidget(2, QFormLayout::FieldRole, bCheckbox);
gridLayout_3->addWidget(formGroupBox, 2, 2, 1, 1);
CPUView->setCentralWidget(centralwidget);
toolBar = new QToolBar(CPUView);
toolBar->setObjectName(QString::fromUtf8("toolBar"));
toolBar->setMinimumSize(QSize(0, 0));
toolBar->setMovable(false);
toolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
toolBar->setFloatable(true);
CPUView->addToolBar(Qt::TopToolBarArea, toolBar);
toolBar->addAction(actionPause);
toolBar->addAction(actionNext);
toolBar->addAction(actionStep);
retranslateUi(CPUView);
QMetaObject::connectSlotsByName(CPUView);
} // setupUi
void retranslateUi(QMainWindow *CPUView)
{
CPUView->setWindowTitle(QCoreApplication::translate("CPUView", "CPU's Debugger", nullptr));
actionPause->setText(QCoreApplication::translate("CPUView", "Continue", nullptr));
#if QT_CONFIG(tooltip)
actionPause->setToolTip(QCoreApplication::translate("CPUView", "Pause or Resume instruction execution.", nullptr));
#endif // QT_CONFIG(tooltip)
#if QT_CONFIG(shortcut)
actionPause->setShortcut(QCoreApplication::translate("CPUView", "C", nullptr));
#endif // QT_CONFIG(shortcut)
actionStep->setText(QCoreApplication::translate("CPUView", "Step", nullptr));
#if QT_CONFIG(tooltip)
actionStep->setToolTip(QCoreApplication::translate("CPUView", "Execute a single instruction", nullptr));
#endif // QT_CONFIG(tooltip)
#if QT_CONFIG(shortcut)
actionStep->setShortcut(QCoreApplication::translate("CPUView", "S", nullptr));
#endif // QT_CONFIG(shortcut)
actionNext->setText(QCoreApplication::translate("CPUView", "Next", nullptr));
#if QT_CONFIG(tooltip)
actionNext->setToolTip(QCoreApplication::translate("CPUView", "Continue execution to the next line.", nullptr));
#endif // QT_CONFIG(tooltip)
#if QT_CONFIG(shortcut)
actionNext->setShortcut(QCoreApplication::translate("CPUView", "N", nullptr));
#endif // QT_CONFIG(shortcut)
label->setText(QCoreApplication::translate("CPUView", "Stack Viewer", nullptr));
accumulatorLabel->setText(QCoreApplication::translate("CPUView", "Accumulator", nullptr));
accumulatorLineEdit->setText(QString());
programBankRegisterLabel->setText(QCoreApplication::translate("CPUView", "Program Bank", nullptr));
programCounterLabel->setText(QCoreApplication::translate("CPUView", "Program Counter", nullptr));
directBankLabel->setText(QCoreApplication::translate("CPUView", "Direct Bank", nullptr));
directPageLabel->setText(QCoreApplication::translate("CPUView", "Direct Page", nullptr));
stackPointerLabel->setText(QCoreApplication::translate("CPUView", "Stack Pointer", nullptr));
xIndexLabel->setText(QCoreApplication::translate("CPUView", "X Index", nullptr));
yIndexLabel->setText(QCoreApplication::translate("CPUView", "Y Index", nullptr));
emulationModeLabel->setText(QCoreApplication::translate("CPUView", "Emulation mode", nullptr));
loggerLabel->setText(QCoreApplication::translate("CPUView", "Instructions History", nullptr));
clear->setText(QCoreApplication::translate("CPUView", "Clear History", nullptr));
formGroupBox->setTitle(QCoreApplication::translate("CPUView", "Flags", nullptr));
negativeLabel->setText(QCoreApplication::translate("CPUView", "Memory Select (M)", nullptr));
zeroLabel->setText(QCoreApplication::translate("CPUView", "Index Select (X)", nullptr));
carryLabel->setText(QCoreApplication::translate("CPUView", "Interupt Request Disable (I)", nullptr));
Overflow->setText(QCoreApplication::translate("CPUView", "Overflow (V)", nullptr));
decimalLabel->setText(QCoreApplication::translate("CPUView", "Decimal (D)", nullptr));
memoryAccumulatorSelectLabel->setText(QCoreApplication::translate("CPUView", "Carry (C)", nullptr));
indeXSelectLabel->setText(QCoreApplication::translate("CPUView", "Zero (Z)", nullptr));
irqDisableLabel->setText(QCoreApplication::translate("CPUView", "Negative (N)", nullptr));
breakBLabel->setText(QCoreApplication::translate("CPUView", "Break (B)", nullptr));
toolBar->setWindowTitle(QCoreApplication::translate("CPUView", "toolBar", nullptr));
} // retranslateUi
};
namespace Ui {
class CPUView: public Ui_CPUView {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_CPU_H