mirror of
https://github.com/zoriya/ComSquare.git
synced 2025-12-23 15:45:26 +00:00
Marge master into PPU
This commit is contained in:
@@ -93,6 +93,8 @@ add_executable(unit_tests
|
|||||||
tests/CPU/TransferRegisters.cpp
|
tests/CPU/TransferRegisters.cpp
|
||||||
sources/CPU/AddressingModes.cpp
|
sources/CPU/AddressingModes.cpp
|
||||||
sources/Models/Components.hpp
|
sources/Models/Components.hpp
|
||||||
|
sources/CPU/Instruction.hpp
|
||||||
|
sources/Exceptions/DebuggableError.hpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# include criterion & coverage
|
# include criterion & coverage
|
||||||
@@ -200,7 +202,13 @@ add_executable(ComSquare
|
|||||||
sources/Debugger/MemoryBusDebug.cpp
|
sources/Debugger/MemoryBusDebug.cpp
|
||||||
sources/Debugger/MemoryBusDebug.hpp
|
sources/Debugger/MemoryBusDebug.hpp
|
||||||
sources/Debugger/ClosableWindow.hpp
|
sources/Debugger/ClosableWindow.hpp
|
||||||
sources/Models/Components.hpp sources/Debugger/CGramDebug.cpp sources/Debugger/CGramDebug.hpp)
|
sources/Models/Components.hpp
|
||||||
|
sources/CPU/Instruction.hpp
|
||||||
|
sources/Exceptions/DebuggableError.hpp
|
||||||
|
sources/Models/Components.hpp
|
||||||
|
sources/Debugger/CGramDebug.cpp
|
||||||
|
sources/Debugger/CGramDebug.hpp
|
||||||
|
)
|
||||||
|
|
||||||
target_compile_definitions(ComSquare PUBLIC DEBUGGER_ENABLED)
|
target_compile_definitions(ComSquare PUBLIC DEBUGGER_ENABLED)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<RCC>
|
<RCC>
|
||||||
<qresource prefix="resources">
|
<qresource prefix="resources">
|
||||||
|
<file>icons/continue.svg</file>
|
||||||
<file>icons/step.svg</file>
|
<file>icons/step.svg</file>
|
||||||
<file>Logo.png</file>
|
<file>Logo.png</file>
|
||||||
<file>icons/play.svg</file>
|
<file>icons/play.svg</file>
|
||||||
|
|||||||
1
resources/icons/continue.svg
Normal file
1
resources/icons/continue.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="level-down-alt" class="svg-inline--fa fa-level-down-alt fa-w-10" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path fill="currentColor" d="M313.553 392.331L209.587 504.334c-9.485 10.214-25.676 10.229-35.174 0L70.438 392.331C56.232 377.031 67.062 352 88.025 352H152V80H68.024a11.996 11.996 0 0 1-8.485-3.515l-56-56C-4.021 12.926 1.333 0 12.024 0H208c13.255 0 24 10.745 24 24v328h63.966c20.878 0 31.851 24.969 17.587 40.331z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 531 B |
@@ -7,47 +7,56 @@
|
|||||||
|
|
||||||
namespace ComSquare::CPU
|
namespace ComSquare::CPU
|
||||||
{
|
{
|
||||||
|
uint24_t CPU::_getImmediateAddr8Bits()
|
||||||
|
{
|
||||||
|
uint24_t ret = this->_registers.pac;
|
||||||
|
this->_registers.pc++;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
uint24_t CPU::_getImmediateAddrForA()
|
uint24_t CPU::_getImmediateAddrForA()
|
||||||
{
|
{
|
||||||
uint24_t effective = this->_registers.pac++;
|
uint24_t effective = this->_registers.pac;
|
||||||
|
this->_registers.pc++;
|
||||||
if (!this->_registers.p.m)
|
if (!this->_registers.p.m)
|
||||||
this->_registers.pac++;
|
this->_registers.pc++;
|
||||||
return effective;
|
return effective;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint24_t CPU::_getImmediateAddrForX()
|
uint24_t CPU::_getImmediateAddrForX()
|
||||||
{
|
{
|
||||||
uint24_t effective = this->_registers.pac++;
|
uint24_t effective = this->_registers.pac;
|
||||||
|
this->_registers.pc++;
|
||||||
if (!this->_registers.p.x_b)
|
if (!this->_registers.p.x_b)
|
||||||
this->_registers.pac++;
|
this->_registers.pc++;
|
||||||
return effective;
|
return effective;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint24_t CPU::_getDirectAddr()
|
uint24_t CPU::_getDirectAddr()
|
||||||
{
|
{
|
||||||
uint8_t addr = this->_bus->read(this->_registers.pac++);
|
uint8_t addr = this->readPC();
|
||||||
return this->_registers.d + addr;
|
return this->_registers.d + addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint24_t CPU::_getAbsoluteAddr()
|
uint24_t CPU::_getAbsoluteAddr()
|
||||||
{
|
{
|
||||||
uint24_t addr = this->_registers.dbr << 16u;
|
uint24_t addr = this->_registers.dbr << 16u;
|
||||||
addr += this->_bus->read(this->_registers.pac++);
|
addr += this->readPC();
|
||||||
addr += this->_bus->read(this->_registers.pac++) << 8u;
|
addr += this->readPC() << 8u;
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint24_t CPU::_getAbsoluteLongAddr()
|
uint24_t CPU::_getAbsoluteLongAddr()
|
||||||
{
|
{
|
||||||
uint24_t addr = this->_bus->read(this->_registers.pac++);
|
uint24_t addr = this->readPC();
|
||||||
addr += this->_bus->read(this->_registers.pac++) << 8u;
|
addr += this->readPC() << 8u;
|
||||||
addr += this->_bus->read(this->_registers.pac++) << 16u;
|
addr += this->readPC() << 16u;
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint24_t CPU::_getDirectIndirectIndexedYAddr()
|
uint24_t CPU::_getDirectIndirectIndexedYAddr()
|
||||||
{
|
{
|
||||||
uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d;
|
uint16_t dp = this->readPC() + this->_registers.d;
|
||||||
uint24_t base = this->_bus->read(dp);
|
uint24_t base = this->_bus->read(dp);
|
||||||
base += this->_bus->read(dp + 1) << 8u;
|
base += this->_bus->read(dp + 1) << 8u;
|
||||||
base += this->_registers.dbr << 16u;
|
base += this->_registers.dbr << 16u;
|
||||||
@@ -58,7 +67,7 @@ namespace ComSquare::CPU
|
|||||||
|
|
||||||
uint24_t CPU::_getDirectIndirectIndexedYLongAddr()
|
uint24_t CPU::_getDirectIndirectIndexedYLongAddr()
|
||||||
{
|
{
|
||||||
uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d;
|
uint16_t dp = this->readPC() + this->_registers.d;
|
||||||
uint24_t base = this->_bus->read(dp);
|
uint24_t base = this->_bus->read(dp);
|
||||||
base += this->_bus->read(dp + 1) << 8u;
|
base += this->_bus->read(dp + 1) << 8u;
|
||||||
base += this->_bus->read(dp + 2) << 16u;
|
base += this->_bus->read(dp + 2) << 16u;
|
||||||
@@ -67,7 +76,7 @@ namespace ComSquare::CPU
|
|||||||
|
|
||||||
uint24_t CPU::_getDirectIndirectIndexedXAddr()
|
uint24_t CPU::_getDirectIndirectIndexedXAddr()
|
||||||
{
|
{
|
||||||
uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d;
|
uint16_t dp = this->readPC() + this->_registers.d;
|
||||||
dp += this->_registers.x;
|
dp += this->_registers.x;
|
||||||
uint24_t base = this->_bus->read(dp);
|
uint24_t base = this->_bus->read(dp);
|
||||||
base += this->_bus->read(dp + 1) << 8u;
|
base += this->_bus->read(dp + 1) << 8u;
|
||||||
@@ -77,22 +86,22 @@ namespace ComSquare::CPU
|
|||||||
|
|
||||||
uint24_t CPU::_getDirectIndexedByXAddr()
|
uint24_t CPU::_getDirectIndexedByXAddr()
|
||||||
{
|
{
|
||||||
uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d;
|
uint16_t dp = this->readPC() + this->_registers.d;
|
||||||
dp += this->_registers.x;
|
dp += this->_registers.x;
|
||||||
return dp;
|
return dp;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint24_t CPU::_getDirectIndexedByYAddr()
|
uint24_t CPU::_getDirectIndexedByYAddr()
|
||||||
{
|
{
|
||||||
uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d;
|
uint16_t dp = this->readPC() + this->_registers.d;
|
||||||
dp += this->_registers.y;
|
dp += this->_registers.y;
|
||||||
return dp;
|
return dp;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint24_t CPU::_getAbsoluteIndexedByXAddr()
|
uint24_t CPU::_getAbsoluteIndexedByXAddr()
|
||||||
{
|
{
|
||||||
uint16_t abs = this->_bus->read(this->_registers.pac++);
|
uint16_t abs = this->readPC();
|
||||||
abs += this->_bus->read(this->_registers.pac++) << 8u;
|
abs += this->readPC() << 8u;
|
||||||
uint24_t effective = abs + (this->_registers.dbr << 16u);
|
uint24_t effective = abs + (this->_registers.dbr << 16u);
|
||||||
if ((effective & 0x80000000u) == (((effective + this->_registers.x) & 0x80000000u)))
|
if ((effective & 0x80000000u) == (((effective + this->_registers.x) & 0x80000000u)))
|
||||||
this->_hasIndexCrossedPageBoundary = true;
|
this->_hasIndexCrossedPageBoundary = true;
|
||||||
@@ -101,8 +110,8 @@ namespace ComSquare::CPU
|
|||||||
|
|
||||||
uint24_t CPU::_getAbsoluteIndexedByYAddr()
|
uint24_t CPU::_getAbsoluteIndexedByYAddr()
|
||||||
{
|
{
|
||||||
uint16_t abs = this->_bus->read(this->_registers.pac++);
|
uint16_t abs = this->readPC();
|
||||||
abs += this->_bus->read(this->_registers.pac++) << 8u;
|
abs += this->readPC() << 8u;
|
||||||
uint24_t effective = abs + (this->_registers.dbr << 16u);
|
uint24_t effective = abs + (this->_registers.dbr << 16u);
|
||||||
if ((effective & 0x80000000u) == (((effective + this->_registers.y) & 0x80000000u)))
|
if ((effective & 0x80000000u) == (((effective + this->_registers.y) & 0x80000000u)))
|
||||||
this->_hasIndexCrossedPageBoundary = true;
|
this->_hasIndexCrossedPageBoundary = true;
|
||||||
@@ -111,32 +120,32 @@ namespace ComSquare::CPU
|
|||||||
|
|
||||||
uint24_t CPU::_getAbsoluteIndexedByXLongAddr()
|
uint24_t CPU::_getAbsoluteIndexedByXLongAddr()
|
||||||
{
|
{
|
||||||
uint24_t lng = this->_bus->read(this->_registers.pac++);
|
uint24_t lng = this->readPC();
|
||||||
lng += this->_bus->read(this->_registers.pac++) << 8u;
|
lng += this->readPC() << 8u;
|
||||||
lng += this->_bus->read(this->_registers.pac++) << 16u;
|
lng += this->readPC() << 16u;
|
||||||
return lng + this->_registers.x;
|
return lng + this->_registers.x;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint24_t CPU::_getProgramCounterRelativeAddr()
|
uint24_t CPU::_getProgramCounterRelativeAddr()
|
||||||
{
|
{
|
||||||
uint24_t pc = this->_registers.pac;
|
uint24_t pc = this->_registers.pac;
|
||||||
int8_t mod = this->_bus->read(this->_registers.pac++);
|
int8_t mod = this->readPC();
|
||||||
return pc + mod;
|
return pc + mod;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint24_t CPU::_getProgramCounterRelativeLongAddr()
|
uint24_t CPU::_getProgramCounterRelativeLongAddr()
|
||||||
{
|
{
|
||||||
uint24_t pc = this->_registers.pac;
|
uint24_t pc = this->_registers.pac;
|
||||||
uint8_t val1 = this->_bus->read(this->_registers.pac++);
|
uint8_t val1 = this->readPC();
|
||||||
uint8_t val2 = this->_bus->read(this->_registers.pac++);
|
uint8_t val2 = this->readPC();
|
||||||
int16_t mod = val2 > 0x7F ? (static_cast<char>(val2) * 256 - val1) : (val1 | val2 << 8u);
|
int16_t mod = val2 > 0x7F ? (static_cast<char>(val2) * 256 - val1) : (val1 | val2 << 8u);
|
||||||
return pc + mod;
|
return pc + mod;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint24_t CPU::_getAbsoluteIndirectAddr()
|
uint24_t CPU::_getAbsoluteIndirectAddr()
|
||||||
{
|
{
|
||||||
uint16_t abs = this->_bus->read(this->_registers.pac++);
|
uint16_t abs = this->readPC();
|
||||||
abs += this->_bus->read(this->_registers.pac++) << 8u;
|
abs += this->readPC() << 8u;
|
||||||
uint24_t effective = this->_bus->read(abs);
|
uint24_t effective = this->_bus->read(abs);
|
||||||
effective += this->_bus->read(abs + 1) << 8u;
|
effective += this->_bus->read(abs + 1) << 8u;
|
||||||
return effective;
|
return effective;
|
||||||
@@ -144,8 +153,8 @@ namespace ComSquare::CPU
|
|||||||
|
|
||||||
uint24_t CPU::_getAbsoluteIndirectIndexedByXAddr()
|
uint24_t CPU::_getAbsoluteIndirectIndexedByXAddr()
|
||||||
{
|
{
|
||||||
uint24_t abs = this->_bus->read(this->_registers.pac++);
|
uint24_t abs = this->readPC();
|
||||||
abs += this->_bus->read(this->_registers.pac++) << 8u;
|
abs += this->readPC() << 8u;
|
||||||
abs += this->_registers.x;
|
abs += this->_registers.x;
|
||||||
uint24_t effective = this->_bus->read(abs);
|
uint24_t effective = this->_bus->read(abs);
|
||||||
effective += this->_bus->read(abs + 1) << 8u;
|
effective += this->_bus->read(abs + 1) << 8u;
|
||||||
@@ -154,7 +163,7 @@ namespace ComSquare::CPU
|
|||||||
|
|
||||||
uint24_t CPU::_getDirectIndirectAddr()
|
uint24_t CPU::_getDirectIndirectAddr()
|
||||||
{
|
{
|
||||||
uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d;
|
uint16_t dp = this->readPC() + this->_registers.d;
|
||||||
uint24_t effective = this->_bus->read(dp);
|
uint24_t effective = this->_bus->read(dp);
|
||||||
effective += this->_bus->read(dp + 1) << 8u;
|
effective += this->_bus->read(dp + 1) << 8u;
|
||||||
effective += this->_registers.dbr << 16u;
|
effective += this->_registers.dbr << 16u;
|
||||||
@@ -163,7 +172,7 @@ namespace ComSquare::CPU
|
|||||||
|
|
||||||
uint24_t CPU::_getDirectIndirectLongAddr()
|
uint24_t CPU::_getDirectIndirectLongAddr()
|
||||||
{
|
{
|
||||||
uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d;
|
uint16_t dp = this->readPC() + this->_registers.d;
|
||||||
uint24_t effective = this->_bus->read(dp);
|
uint24_t effective = this->_bus->read(dp);
|
||||||
effective += this->_bus->read(++dp) << 8u;
|
effective += this->_bus->read(++dp) << 8u;
|
||||||
effective += this->_bus->read(++dp) << 16u;
|
effective += this->_bus->read(++dp) << 16u;
|
||||||
@@ -172,12 +181,12 @@ namespace ComSquare::CPU
|
|||||||
|
|
||||||
uint24_t CPU::_getStackRelativeAddr()
|
uint24_t CPU::_getStackRelativeAddr()
|
||||||
{
|
{
|
||||||
return this->_bus->read(this->_registers.pac++) + this->_registers.s;
|
return this->readPC() + this->_registers.s;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint24_t CPU::_getStackRelativeIndirectIndexedYAddr()
|
uint24_t CPU::_getStackRelativeIndirectIndexedYAddr()
|
||||||
{
|
{
|
||||||
uint24_t base = this->_bus->read(this->_registers.pac++) + this->_registers.s;
|
uint24_t base = this->readPC() + this->_registers.s;
|
||||||
base += this->_registers.dbr << 16u;
|
base += this->_registers.dbr << 16u;
|
||||||
return base + this->_registers.y;
|
return base + this->_registers.y;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -195,202 +195,114 @@ namespace ComSquare::CPU
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t CPU::readPC()
|
||||||
|
{
|
||||||
|
uint8_t ret = this->_bus->read(this->_registers.pac);
|
||||||
|
this->_registers.pc++;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned CPU::update()
|
unsigned CPU::update()
|
||||||
{
|
{
|
||||||
unsigned cycles = 0;
|
unsigned cycles = 0;
|
||||||
|
|
||||||
for (int i = 0; i < 0xFF; i++)
|
for (int i = 0; i < 0xFF; i++)
|
||||||
cycles += this->_executeInstruction(this->_bus->read(this->_registers.pac++));
|
cycles += this->_executeInstruction(this->readPC());
|
||||||
return cycles;
|
return cycles;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned CPU::_executeInstruction(uint8_t opcode)
|
unsigned CPU::_executeInstruction(uint8_t opcode)
|
||||||
{
|
{
|
||||||
|
Instruction instruction = this->_instructions[opcode];
|
||||||
|
uint24_t valueAddr = 0;
|
||||||
|
|
||||||
this->_hasIndexCrossedPageBoundary = false;
|
this->_hasIndexCrossedPageBoundary = false;
|
||||||
uint24_t addr;
|
|
||||||
|
|
||||||
switch (opcode) {
|
switch (instruction.addressingMode) {
|
||||||
case Instructions::BRK: this->BRK(); return 7 + !this->_isEmulationMode;
|
case Implied:
|
||||||
|
break;
|
||||||
|
case Immediate8bits:
|
||||||
|
valueAddr = this->_getImmediateAddr8Bits();
|
||||||
|
break;
|
||||||
|
case ImmediateForA:
|
||||||
|
valueAddr = this->_getImmediateAddrForA();
|
||||||
|
break;
|
||||||
|
case ImmediateForX:
|
||||||
|
valueAddr = this->_getImmediateAddrForX();
|
||||||
|
break;
|
||||||
|
|
||||||
case Instructions::COP: this->COP(); return 7 + !this->_isEmulationMode;
|
// TODO implement the relative addressing mode
|
||||||
|
// TODO implement the relative long addressing mode
|
||||||
|
|
||||||
case Instructions::RTI: this->RTI(); return 6 + !this->_isEmulationMode;
|
case Absolute:
|
||||||
|
valueAddr = this->_getAbsoluteAddr();
|
||||||
|
break;
|
||||||
|
case AbsoluteLong:
|
||||||
|
valueAddr = this->_getAbsoluteLongAddr();
|
||||||
|
break;
|
||||||
|
case AbsoluteIndirect:
|
||||||
|
valueAddr = this->_getAbsoluteIndirectAddr();
|
||||||
|
break;
|
||||||
|
|
||||||
case Instructions::ADC_IM: this->ADC(this->_getImmediateAddrForA()); return 2 + !this->_registers.p.m;
|
//TODO implement absolute indirect long addressing mode
|
||||||
case Instructions::ADC_ABS: this->ADC(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m;
|
|
||||||
case Instructions::ADC_ABSl: this->ADC(this->_getAbsoluteLongAddr()); return 5 + !this->_registers.p.m;
|
|
||||||
case Instructions::ADC_DP: this->ADC(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
case Instructions::ADC_DPi: this->ADC(this->_getDirectIndirectAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
case Instructions::ADC_DPil: this->ADC(this->_getDirectIndirectLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
case Instructions::ADC_ABSX: this->ADC(this->_getAbsoluteIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary;
|
|
||||||
case Instructions::ADC_ABSXl:this->ADC(this->_getAbsoluteIndexedByXLongAddr()); return 5 + !this->_registers.p.m;
|
|
||||||
case Instructions::ADC_ABSY: this->ADC(this->_getAbsoluteIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary;
|
|
||||||
case Instructions::ADC_DPX: this->ADC(this->_getDirectIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
case Instructions::ADC_DPXi: this->ADC(this->_getDirectIndirectIndexedXAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
case Instructions::ADC_DPYi: this->ADC(this->_getDirectIndirectIndexedYAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0 + this->_hasIndexCrossedPageBoundary;
|
|
||||||
case Instructions::ADC_DPYil:this->ADC(this->_getDirectIndirectIndexedYLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
case Instructions::ADC_SR: this->ADC(this->_getStackRelativeAddr()); return 4 + !this->_registers.p.m;
|
|
||||||
case Instructions::ADC_SRYi: this->ADC(this->_getStackRelativeIndirectIndexedYAddr()); return 7 + !this->_registers.p.m;
|
|
||||||
|
|
||||||
case Instructions::STA_ABS: this->STA(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m;
|
case DirectPage:
|
||||||
case Instructions::STA_ABSl: this->STA(this->_getAbsoluteLongAddr()); return 5 + !this->_registers.p.m;
|
valueAddr = this->_getDirectAddr();
|
||||||
case Instructions::STA_DP: this->STA(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0;
|
break;
|
||||||
case Instructions::STA_DPi: this->STA(this->_getDirectIndirectAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0;
|
case DirectPageIndirect:
|
||||||
case Instructions::STA_DPil: this->STA(this->_getDirectIndirectLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0;
|
valueAddr = this->_getDirectIndirectAddr();
|
||||||
case Instructions::STA_ABSX: this->STA(this->_getAbsoluteIndexedByXAddr()); return 5 + !this->_registers.p.m;
|
break;
|
||||||
case Instructions::STA_ABSXl:this->STA(this->_getAbsoluteIndexedByXLongAddr()); return 5 + !this->_registers.p.m;
|
case DirectPageIndirectLong:
|
||||||
case Instructions::STA_ABSY: this->STA(this->_getAbsoluteIndexedByYAddr()); return 5 + !this->_registers.p.m;
|
valueAddr = this->_getDirectIndirectLongAddr();
|
||||||
case Instructions::STA_DPX: this->STA(this->_getDirectIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0;
|
break;
|
||||||
case Instructions::STA_DPXi: this->STA(this->_getDirectIndirectIndexedXAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
case Instructions::STA_DPYi: this->STA(this->_getDirectIndirectIndexedYAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
case Instructions::STA_DPYil:this->STA(this->_getDirectIndirectIndexedYLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
case Instructions::STA_SR: this->STA(this->_getStackRelativeAddr()); return 4 + !this->_registers.p.m;
|
|
||||||
case Instructions::STA_SRYi: this->STA(this->_getStackRelativeIndirectIndexedYAddr()); return 7 + !this->_registers.p.m;
|
|
||||||
|
|
||||||
case Instructions::STX_ABS: this->STX(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m;
|
case DirectPageIndexedByX:
|
||||||
case Instructions::STX_DP: this->STX(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0;
|
valueAddr = this->_getDirectIndexedByXAddr();
|
||||||
case Instructions::STX_DPY: this->STX(this->_getDirectIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0;
|
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 Instructions::STY_ABS: this->STX(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m;
|
case AbsoluteIndexedByX:
|
||||||
case Instructions::STY_DP: this->STX(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0;
|
valueAddr = this->_getAbsoluteIndexedByXAddr();
|
||||||
case Instructions::STY_DPX: this->STX(this->_getDirectIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0;
|
break;
|
||||||
|
case AbsoluteIndexedByXLong:
|
||||||
|
valueAddr = this->_getAbsoluteIndexedByXLongAddr();
|
||||||
|
break;
|
||||||
|
case AbsoluteIndexedByY:
|
||||||
|
valueAddr = this->_getAbsoluteIndexedByYAddr();
|
||||||
|
break;
|
||||||
|
|
||||||
case Instructions::STZ_ABS: this->STZ(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m;
|
case StackRelative:
|
||||||
case Instructions::STZ_DP: this->STZ(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0;
|
valueAddr = this->_getStackRelativeAddr();
|
||||||
case Instructions::STZ_ABSX: this->STZ(this->_getAbsoluteIndexedByXAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0;
|
break;
|
||||||
case Instructions::STZ_DPX: this->STZ(this->_getDirectIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0;
|
case StackRelativeIndirectIndexedByY:
|
||||||
|
valueAddr = this->_getStackRelativeIndirectIndexedYAddr();
|
||||||
case Instructions::LDA_IM: this->LDA(this->_getImmediateAddrForA()); return 2 + !this->_registers.p.m;
|
break;
|
||||||
case Instructions::LDA_ABS: this->LDA(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m;
|
|
||||||
case Instructions::LDA_ABSl: this->LDA(this->_getAbsoluteLongAddr()); return 5 + !this->_registers.p.m;
|
|
||||||
case Instructions::LDA_DP: this->LDA(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
case Instructions::LDA_DPi: this->LDA(this->_getDirectIndirectAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
case Instructions::LDA_DPil: this->LDA(this->_getDirectIndirectLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
case Instructions::LDA_ABSX: this->LDA(this->_getAbsoluteIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary;
|
|
||||||
case Instructions::LDA_ABSXl:this->LDA(this->_getAbsoluteIndexedByXLongAddr()); return 5 + !this->_registers.p.m;
|
|
||||||
case Instructions::LDA_ABSY: this->LDA(this->_getAbsoluteIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary;
|
|
||||||
case Instructions::LDA_DPX: this->LDA(this->_getDirectIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
case Instructions::LDA_DPXi: this->LDA(this->_getDirectIndirectIndexedXAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
case Instructions::LDA_DPYi: this->LDA(this->_getDirectIndirectIndexedYAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0 + this->_hasIndexCrossedPageBoundary;
|
|
||||||
case Instructions::LDA_DPYil:this->LDA(this->_getDirectIndirectIndexedYLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
case Instructions::LDA_SR: this->LDA(this->_getStackRelativeAddr()); return 4 + !this->_registers.p.m;
|
|
||||||
case Instructions::LDA_SRYi: this->LDA(this->_getStackRelativeIndirectIndexedYAddr()); return 7 + !this->_registers.p.m;
|
|
||||||
|
|
||||||
case Instructions::LDX_IM: this->LDX(this->_getImmediateAddrForX()); return 2 + !this->_registers.p.m;
|
|
||||||
case Instructions::LDX_ABS: this->LDX(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m;
|
|
||||||
case Instructions::LDX_DP: this->LDX(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
case Instructions::LDX_ABSY: this->LDX(this->_getAbsoluteIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary;
|
|
||||||
case Instructions::LDX_DPY: this->LDX(this->_getDirectIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
|
|
||||||
case Instructions::LDY_IM: this->LDY(this->_getImmediateAddrForX()); return 2 + !this->_registers.p.m;
|
|
||||||
case Instructions::LDY_ABS: this->LDY(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m;
|
|
||||||
case Instructions::LDY_DP: this->LDY(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
case Instructions::LDY_ABSY: this->LDY(this->_getAbsoluteIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary;
|
|
||||||
case Instructions::LDY_DPY: this->LDY(this->_getDirectIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
|
|
||||||
case Instructions::SEP: this->SEP(this->_bus->read(this->_registers.pc++)); return 3;
|
|
||||||
|
|
||||||
case Instructions::REP: this->REP(this->_bus->read(this->_registers.pc++)); return 3;
|
|
||||||
|
|
||||||
case Instructions::PHA: this->PHA(); return 3 + !this->_registers.p.m;
|
|
||||||
case Instructions::PHB: this->PHB(); return 3;
|
|
||||||
case Instructions::PHD: this->PHD(); return 4;
|
|
||||||
case Instructions::PHK: this->PHK(); return 3;
|
|
||||||
case Instructions::PHP: this->PHP(); return 3;
|
|
||||||
case Instructions::PHX: this->PHX(); return 3 + !this->_registers.p.x_b;
|
|
||||||
case Instructions::PHY: this->PHY(); return 3 + !this->_registers.p.x_b;
|
|
||||||
|
|
||||||
case Instructions::PLA: this->PLA(); return 4 + !this->_registers.p.m;
|
|
||||||
case Instructions::PLB: this->PLB(); return 4;
|
|
||||||
case Instructions::PLD: this->PLD(); return 5;
|
|
||||||
case Instructions::PLP: this->PLP(); return 4;
|
|
||||||
case Instructions::PLX: this->PLX(); return 4 + !this->_registers.p.x_b;
|
|
||||||
case Instructions::PLY: this->PLY(); return 4 + !this->_registers.p.x_b;
|
|
||||||
|
|
||||||
case Instructions::JSR_ABS: this->JSR(this->_getAbsoluteAddr()); return 6;
|
|
||||||
case Instructions::JSR_ABSXi: this->JSR(this->_getAbsoluteIndirectIndexedByXAddr()); return 8;
|
|
||||||
|
|
||||||
case Instructions::JSL: this->JSL(this->_getAbsoluteLongAddr()); return 8;
|
|
||||||
|
|
||||||
case Instructions::CLC: this->CLC(); return 2;
|
|
||||||
case Instructions::CLI: this->CLI(); return 2;
|
|
||||||
case Instructions::CLD: this->CLD(); return 2;
|
|
||||||
case Instructions::CLV: this->CLV(); return 2;
|
|
||||||
|
|
||||||
case Instructions::SEC: this->SEC(); return 2;
|
|
||||||
case Instructions::SED: this->SED(); return 2;
|
|
||||||
case Instructions::SEI: this->SEI(); return 2;
|
|
||||||
|
|
||||||
case Instructions::AND_IM: this->AND(this->_getImmediateAddrForA()); return 2 + !this->_registers.p.m;
|
|
||||||
case Instructions::AND_ABS: this->AND(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m;
|
|
||||||
case Instructions::AND_ABSl: this->AND(this->_getAbsoluteLongAddr()); return 5 + !this->_registers.p.m;
|
|
||||||
case Instructions::AND_DP: this->AND(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
case Instructions::AND_DPi: this->AND(this->_getDirectIndirectAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
case Instructions::AND_DPil: this->AND(this->_getDirectIndirectLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
case Instructions::AND_ABSX: this->AND(this->_getAbsoluteIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary;
|
|
||||||
case Instructions::AND_ABSXl:this->AND(this->_getAbsoluteIndexedByXLongAddr()); return 5 + !this->_registers.p.m;
|
|
||||||
case Instructions::AND_ABSY: this->AND(this->_getAbsoluteIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary;
|
|
||||||
case Instructions::AND_DPX: this->AND(this->_getDirectIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
case Instructions::AND_DPXi: this->AND(this->_getDirectIndirectIndexedXAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
case Instructions::AND_DPYi: this->AND(this->_getDirectIndirectIndexedYAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0 + this->_hasIndexCrossedPageBoundary;
|
|
||||||
case Instructions::AND_DPYil:this->AND(this->_getDirectIndirectIndexedYLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
case Instructions::AND_SR: this->AND(this->_getStackRelativeAddr()); return 4 + !this->_registers.p.m;
|
|
||||||
case Instructions::AND_SRYi: this->AND(this->_getStackRelativeIndirectIndexedYAddr()); return 7 + !this->_registers.p.m;
|
|
||||||
|
|
||||||
case Instructions::XCE: this->XCE(); return 2;
|
|
||||||
|
|
||||||
case Instructions::SBC_IM: this->SBC(this->_getImmediateAddrForA()); return 2 + !this->_registers.p.m;
|
|
||||||
case Instructions::SBC_ABS: this->SBC(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m;
|
|
||||||
case Instructions::SBC_ABSl: this->SBC(this->_getAbsoluteLongAddr()); return 5 + !this->_registers.p.m;
|
|
||||||
case Instructions::SBC_DP: this->SBC(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
case Instructions::SBC_DPi: this->SBC(this->_getDirectIndirectAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
case Instructions::SBC_DPil: this->SBC(this->_getDirectIndirectLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
case Instructions::SBC_ABSX: this->SBC(this->_getAbsoluteIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary;
|
|
||||||
case Instructions::SBC_ABSXl:this->SBC(this->_getAbsoluteIndexedByXLongAddr()); return 5 + !this->_registers.p.m;
|
|
||||||
case Instructions::SBC_ABSY: this->SBC(this->_getAbsoluteIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary;
|
|
||||||
case Instructions::SBC_DPX: this->SBC(this->_getDirectIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
case Instructions::SBC_DPXi: this->SBC(this->_getDirectIndirectIndexedXAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
case Instructions::SBC_DPYi: this->SBC(this->_getDirectIndirectIndexedYAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0 + this->_hasIndexCrossedPageBoundary;
|
|
||||||
case Instructions::SBC_DPYil:this->SBC(this->_getDirectIndirectIndexedYLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
case Instructions::SBC_SR: this->SBC(this->_getStackRelativeAddr()); return 4 + !this->_registers.p.m;
|
|
||||||
case Instructions::SBC_SRYi: this->SBC(this->_getStackRelativeIndirectIndexedYAddr()); return 7 + !this->_registers.p.m;
|
|
||||||
|
|
||||||
case Instructions::TAX: this->TAX(); return 2;
|
|
||||||
case Instructions::TAY: this->TAY(); return 2;
|
|
||||||
case Instructions::TXS: this->TXS(); return 2;
|
|
||||||
|
|
||||||
case Instructions::INX: this->INX(); return 2;
|
|
||||||
case Instructions::INY: this->INY(); return 2;
|
|
||||||
|
|
||||||
case Instructions::CPX_IM: this->CPX(this->_getImmediateAddrForX()); return 2 + !this->_registers.p.m;
|
|
||||||
case Instructions::CPX_ABS: this->CPX(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m;
|
|
||||||
case Instructions::CPX_DP: this->CPX(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
|
|
||||||
case Instructions::CPY_IM: this->CPY(this->_getImmediateAddrForX()); return 2 + !this->_registers.p.m;
|
|
||||||
case Instructions::CPY_ABS: this->CPY(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m;
|
|
||||||
case Instructions::CPY_DP: this->CPY(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0;
|
|
||||||
|
|
||||||
case Instructions::BCC: return this->BCC(this->_registers.pc++) + 2 + this->_isEmulationMode;
|
|
||||||
case Instructions::BCS: return this->BCS(this->_registers.pc++) + 2 + this->_isEmulationMode;
|
|
||||||
case Instructions::BEQ: return this->BEQ(this->_registers.pc++) + 2 + this->_isEmulationMode;
|
|
||||||
case Instructions::BNE: return this->BNE(this->_registers.pc++) + 2 + this->_isEmulationMode;
|
|
||||||
case Instructions::BMI: return this->BMI(this->_registers.pc++) + 2 + this->_isEmulationMode;
|
|
||||||
case Instructions::BPL: return this->BPL(this->_registers.pc++) + 2 + this->_isEmulationMode;
|
|
||||||
case Instructions::BVC: return this->BVC(this->_registers.pc++) + 2 + this->_isEmulationMode;
|
|
||||||
case Instructions::BVS: return this->BVS(this->_registers.pc++) + 2 + this->_isEmulationMode;
|
|
||||||
case Instructions::BRA: this->BRA(this->_registers.pc++); return 3 + this->_isEmulationMode;
|
|
||||||
case Instructions::BRL: this->BRL(this->_registers.pc); this->_registers.pc += 2; return 4;
|
|
||||||
|
|
||||||
case Instructions::JMP_ABS: addr = this->_getAbsoluteAddr(); this->JMP(addr); return 3;
|
|
||||||
case Instructions::JMP_ABSi: addr = this->_getAbsoluteIndirectAddr(); this->JMP(addr); return 3;
|
|
||||||
case Instructions::JMP_ABSXi: addr = this->_getAbsoluteIndexedByXAddr(); this->JMP(addr); return 3;
|
|
||||||
|
|
||||||
case Instructions::JML_ABSl: addr = this->_getAbsoluteLongAddr(); this->JML(addr); return 3;
|
|
||||||
//case Instructions::JML_ABSil: this->JML(this->_getAbsoluteLong()); return 3;
|
|
||||||
|
|
||||||
|
case ProgramCounterRelative:
|
||||||
|
valueAddr = this->_getProgramCounterRelativeAddr();
|
||||||
|
break;
|
||||||
|
case ProgramCounterRelativeLong:
|
||||||
|
valueAddr = this->_getProgramCounterRelativeLongAddr();
|
||||||
|
break;
|
||||||
|
case AbsoluteIndirectIndexedByX:
|
||||||
|
valueAddr = this->_getAbsoluteIndirectIndexedByXAddr();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw InvalidOpcode("CPU", opcode);
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return instruction.cycleCount + (this->*instruction.call)(valueAddr, instruction.addressingMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::_push(uint8_t data)
|
void CPU::_push(uint8_t data)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "../Models/Int24.hpp"
|
#include "../Models/Int24.hpp"
|
||||||
#include "../Cartridge/Cartridge.hpp"
|
#include "../Cartridge/Cartridge.hpp"
|
||||||
#include "../Memory/AMemory.hpp"
|
#include "../Memory/AMemory.hpp"
|
||||||
|
#include "Instruction.hpp"
|
||||||
|
|
||||||
namespace ComSquare::CPU
|
namespace ComSquare::CPU
|
||||||
{
|
{
|
||||||
@@ -180,189 +181,6 @@ namespace ComSquare::CPU
|
|||||||
uint8_t joy4h;
|
uint8_t joy4h;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! @brief All the instructions opcode of the main CPU.
|
|
||||||
//! @info The name of the instruction followed by their parameters (after an underscore) if any.
|
|
||||||
//! @info Addr mode with an i at the end means indirect.
|
|
||||||
//! @info Addr mode with an l at the end means long.
|
|
||||||
enum Instructions
|
|
||||||
{
|
|
||||||
BRK = 0x00,
|
|
||||||
COP = 0x02,
|
|
||||||
RTI = 0x40,
|
|
||||||
|
|
||||||
ADC_DPXi = 0x61,
|
|
||||||
ADC_SR = 0x63,
|
|
||||||
ADC_DP = 0x65,
|
|
||||||
ADC_DPil = 0x67,
|
|
||||||
ADC_IM = 0x69,
|
|
||||||
ADC_ABS = 0x6D,
|
|
||||||
ADC_ABSl = 0x6F,
|
|
||||||
ADC_DPYi = 0x71,
|
|
||||||
ADC_DPi = 0x72,
|
|
||||||
ADC_SRYi = 0x73,
|
|
||||||
ADC_DPX = 0x75,
|
|
||||||
ADC_DPYil = 0x77,
|
|
||||||
ADC_ABSY = 0x79,
|
|
||||||
ADC_ABSX = 0x7D,
|
|
||||||
ADC_ABSXl = 0x7F,
|
|
||||||
|
|
||||||
STA_ABS = 0x8D,
|
|
||||||
STA_ABSl = 0x8F,
|
|
||||||
STA_DP = 0x85,
|
|
||||||
STA_DPi = 0x92,
|
|
||||||
STA_DPil = 0x87,
|
|
||||||
STA_ABSX = 0x9D,
|
|
||||||
STA_ABSXl = 0x9F,
|
|
||||||
STA_ABSY = 0x99,
|
|
||||||
STA_DPX = 0x95,
|
|
||||||
STA_DPXi = 0x81,
|
|
||||||
STA_DPYi = 0x91,
|
|
||||||
STA_DPYil = 0x97,
|
|
||||||
STA_SR = 0x83,
|
|
||||||
STA_SRYi = 0x93,
|
|
||||||
|
|
||||||
STX_ABS = 0x8E,
|
|
||||||
STX_DP = 0x86,
|
|
||||||
STX_DPY = 0x96,
|
|
||||||
|
|
||||||
STY_ABS = 0x8C,
|
|
||||||
STY_DP = 0x84,
|
|
||||||
STY_DPX = 0x94,
|
|
||||||
|
|
||||||
STZ_ABS = 0x9C,
|
|
||||||
STZ_DP = 0x64,
|
|
||||||
STZ_ABSX = 0x9E,
|
|
||||||
STZ_DPX = 0x74,
|
|
||||||
|
|
||||||
LDA_IM = 0xA9,
|
|
||||||
LDA_ABS = 0xAD,
|
|
||||||
LDA_ABSl = 0xAF,
|
|
||||||
LDA_DP = 0xA5,
|
|
||||||
LDA_DPi = 0xB2,
|
|
||||||
LDA_DPil = 0xA7,
|
|
||||||
LDA_ABSX = 0xBD,
|
|
||||||
LDA_ABSXl = 0xBF,
|
|
||||||
LDA_ABSY = 0xB9,
|
|
||||||
LDA_DPX = 0xB5,
|
|
||||||
LDA_DPXi = 0xA1,
|
|
||||||
LDA_DPYi = 0xB1,
|
|
||||||
LDA_DPYil = 0xB7,
|
|
||||||
LDA_SR = 0xA3,
|
|
||||||
LDA_SRYi = 0xB3,
|
|
||||||
|
|
||||||
LDX_IM = 0xA2,
|
|
||||||
LDX_ABS = 0xAE,
|
|
||||||
LDX_DP = 0xA6,
|
|
||||||
LDX_ABSY = 0xBE,
|
|
||||||
LDX_DPY = 0xB6,
|
|
||||||
|
|
||||||
LDY_IM = 0xA0,
|
|
||||||
LDY_ABS = 0xAC,
|
|
||||||
LDY_DP = 0xA4,
|
|
||||||
LDY_ABSY = 0xBC,
|
|
||||||
LDY_DPY = 0xB4,
|
|
||||||
|
|
||||||
SEP = 0xE2,
|
|
||||||
|
|
||||||
REP = 0xC2,
|
|
||||||
|
|
||||||
PHA = 0x48,
|
|
||||||
PHB = 0x8B,
|
|
||||||
PHD = 0x0B,
|
|
||||||
PHK = 0x4B,
|
|
||||||
PHP = 0x08,
|
|
||||||
PHX = 0xDA,
|
|
||||||
PHY = 0x5A,
|
|
||||||
|
|
||||||
PLA = 0x68,
|
|
||||||
PLB = 0xAB,
|
|
||||||
PLD = 0x2B,
|
|
||||||
PLP = 0x28,
|
|
||||||
PLX = 0xFA,
|
|
||||||
PLY = 0x7A,
|
|
||||||
|
|
||||||
JSR_ABS = 0x20,
|
|
||||||
JSR_ABSXi = 0xFC,
|
|
||||||
|
|
||||||
JSL = 0x22,
|
|
||||||
|
|
||||||
CLC = 0x18,
|
|
||||||
CLI = 0x58,
|
|
||||||
CLD = 0xD8,
|
|
||||||
CLV = 0xB8,
|
|
||||||
|
|
||||||
SEC = 0x38,
|
|
||||||
SEI = 0x78,
|
|
||||||
SED = 0xF8,
|
|
||||||
|
|
||||||
AND_IM = 0x29,
|
|
||||||
AND_ABS = 0x2D,
|
|
||||||
AND_ABSl = 0x2F,
|
|
||||||
AND_DP = 0x25,
|
|
||||||
AND_DPi = 0x32,
|
|
||||||
AND_DPil = 0x27,
|
|
||||||
AND_ABSX = 0x3D,
|
|
||||||
AND_ABSXl = 0x3F,
|
|
||||||
AND_ABSY = 0x39,
|
|
||||||
AND_DPX = 0x35,
|
|
||||||
AND_DPXi = 0x21,
|
|
||||||
AND_DPYi = 0x31,
|
|
||||||
AND_DPYil = 0x37,
|
|
||||||
AND_SR = 0x23,
|
|
||||||
AND_SRYi = 0x33,
|
|
||||||
|
|
||||||
XCE = 0xFB,
|
|
||||||
|
|
||||||
SBC_IM = 0xE9,
|
|
||||||
SBC_ABS = 0xED,
|
|
||||||
SBC_ABSl = 0xEF,
|
|
||||||
SBC_DP = 0xE5,
|
|
||||||
SBC_DPi = 0xF2,
|
|
||||||
SBC_DPil = 0xE7,
|
|
||||||
SBC_ABSX = 0xFD,
|
|
||||||
SBC_ABSXl = 0xFF,
|
|
||||||
SBC_ABSY = 0xF9,
|
|
||||||
SBC_DPX = 0xF5,
|
|
||||||
SBC_DPXi = 0xE1,
|
|
||||||
SBC_DPYi = 0xF1,
|
|
||||||
SBC_DPYil = 0xF7,
|
|
||||||
SBC_SR = 0xE3,
|
|
||||||
SBC_SRYi = 0xF3,
|
|
||||||
|
|
||||||
TAX = 0xAA,
|
|
||||||
TAY = 0xA8,
|
|
||||||
TXS = 0x9A,
|
|
||||||
|
|
||||||
INX = 0xE8,
|
|
||||||
INY = 0xC8,
|
|
||||||
|
|
||||||
CPX_IM = 0xE0,
|
|
||||||
CPX_ABS = 0xEC,
|
|
||||||
CPX_DP = 0xE4,
|
|
||||||
|
|
||||||
CPY_IM = 0xC0,
|
|
||||||
CPY_ABS = 0xCC,
|
|
||||||
CPY_DP = 0xC4,
|
|
||||||
|
|
||||||
BCC = 0x90,
|
|
||||||
BCS = 0xB0,
|
|
||||||
BEQ = 0xF0,
|
|
||||||
BNE = 0xD0,
|
|
||||||
BMI = 0x30,
|
|
||||||
BPL = 0x10,
|
|
||||||
BVC = 0x50,
|
|
||||||
BVS = 0x70,
|
|
||||||
BRA = 0x80,
|
|
||||||
BRL = 0x82,
|
|
||||||
|
|
||||||
JMP_ABS = 0x4C,
|
|
||||||
JMP_ABSi = 0x6C,
|
|
||||||
JMP_ABSXi = 0x7C,
|
|
||||||
|
|
||||||
JML_ABSl = 0x5C,
|
|
||||||
JML_ABSil = 0xDC
|
|
||||||
};
|
|
||||||
|
|
||||||
//! @brief The main CPU
|
//! @brief The main CPU
|
||||||
class CPU : public Memory::AMemory {
|
class CPU : public Memory::AMemory {
|
||||||
protected:
|
protected:
|
||||||
@@ -380,6 +198,8 @@ namespace ComSquare::CPU
|
|||||||
//! @brief True if an addressing mode with an iterator (x, y) has crossed the page. (Used because crossing the page boundary take one more cycle to run certain instructions).
|
//! @brief True if an addressing mode with an iterator (x, y) has crossed the page. (Used because crossing the page boundary take one more cycle to run certain instructions).
|
||||||
bool _hasIndexCrossedPageBoundary = false;
|
bool _hasIndexCrossedPageBoundary = false;
|
||||||
|
|
||||||
|
//! @brief Immediate address mode is specified with a value in 8. (This functions returns the 24bit space address of the value).
|
||||||
|
uint24_t _getImmediateAddr8Bits();
|
||||||
//! @brief Immediate address mode is specified with a value in 8 or 16 bits. The value is 16 bits if the m flag is unset. (This functions returns the 24bit space address of the value).
|
//! @brief Immediate address mode is specified with a value in 8 or 16 bits. The value is 16 bits if the m flag is unset. (This functions returns the 24bit space address of the value).
|
||||||
uint24_t _getImmediateAddrForA();
|
uint24_t _getImmediateAddrForA();
|
||||||
//! @brief Immediate address mode is specified with a value in 8 or 16 bits. The value is 16 bits if the x flag is unset. (This functions returns the 24bit space address of the value).
|
//! @brief Immediate address mode is specified with a value in 8 or 16 bits. The value is 16 bits if the x flag is unset. (This functions returns the 24bit space address of the value).
|
||||||
@@ -433,125 +253,390 @@ namespace ComSquare::CPU
|
|||||||
//! @brief Pop 16 bits of data from the stack.
|
//! @brief Pop 16 bits of data from the stack.
|
||||||
uint16_t _pop16();
|
uint16_t _pop16();
|
||||||
|
|
||||||
|
//! @brief Return the data at the program bank concatenated with the program counter. It also increment the program counter (the program bank is not incremented on overflows).
|
||||||
|
uint8_t readPC();
|
||||||
|
|
||||||
//! @brief Execute a single instruction.
|
//! @brief Execute a single instruction.
|
||||||
//! @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 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.
|
||||||
void BRK();
|
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.
|
||||||
void COP();
|
int COP(uint24_t, AddressingMode);
|
||||||
//! @brief Return from Interrupt - Used to return from a interrupt handler.
|
//! @brief Return from Interrupt - Used to return from a interrupt handler.
|
||||||
void RTI();
|
int RTI(uint24_t, AddressingMode);
|
||||||
//! @brief Add with carry - Adds operand to the Accumulator; adds an additional 1 if carry is set.
|
//! @brief Add with carry - Adds operand to the Accumulator; adds an additional 1 if carry is set.
|
||||||
void ADC(uint24_t valueAddr);
|
int ADC(uint24_t valueAddr, AddressingMode);
|
||||||
//! @brief Store the accumulator to memory.
|
//! @brief Store the accumulator to memory.
|
||||||
void STA(uint24_t addr);
|
int STA(uint24_t addr, AddressingMode);
|
||||||
//! @brief Store the index register X to memory.
|
//! @brief Store the index register X to memory.
|
||||||
void STX(uint24_t addr);
|
int STX(uint24_t addr, AddressingMode);
|
||||||
//! @brief Store the index register Y to memory.
|
//! @brief Store the index register Y to memory.
|
||||||
void STY(uint24_t addr);
|
int STY(uint24_t addr, AddressingMode);
|
||||||
//! @brief Store zero to the memory.
|
//! @brief Store zero to the memory.
|
||||||
void STZ(uint24_t addr);
|
int STZ(uint24_t addr, AddressingMode);
|
||||||
//! @brief Load the accumulator from memory.
|
//! @brief Load the accumulator from memory.
|
||||||
void LDA(uint24_t addr);
|
int LDA(uint24_t addr, AddressingMode);
|
||||||
//! @brief Load the X index register from memory.
|
//! @brief Load the X index register from memory.
|
||||||
void LDX(uint24_t addr);
|
int LDX(uint24_t addr, AddressingMode);
|
||||||
//! @brief Load the Y index register from memory.
|
//! @brief Load the Y index register from memory.
|
||||||
void LDY(uint24_t addr);
|
int LDY(uint24_t addr, AddressingMode);
|
||||||
//! @brief Set status bits.
|
//! @brief Set status bits.
|
||||||
void SEP(uint24_t valueAddr);
|
int SEP(uint24_t valueAddr, AddressingMode);
|
||||||
//! @brief Reset status bits.
|
//! @brief Reset status bits.
|
||||||
void REP(uint24_t valueAddr);
|
int REP(uint24_t valueAddr, AddressingMode);
|
||||||
//! @brief Jump to subroutine
|
//! @brief Jump to subroutine
|
||||||
void JSR(uint24_t addr);
|
int JSR(uint24_t addr, AddressingMode);
|
||||||
//! @brief Jump to subroutine (long)
|
//! @brief Jump to subroutine (long)
|
||||||
void JSL(uint24_t addr);
|
int JSL(uint24_t addr, AddressingMode);
|
||||||
//! @brief Push the accumulator to the stack.
|
//! @brief Push the accumulator to the stack.
|
||||||
void PHA();
|
int PHA(uint24_t, AddressingMode);
|
||||||
//! @brief Push the data bank register to the stack.
|
//! @brief Push the data bank register to the stack.
|
||||||
void PHB();
|
int PHB(uint24_t, AddressingMode);
|
||||||
//! @brief Push the direct page register to the stack.
|
//! @brief Push the direct page register to the stack.
|
||||||
void PHD();
|
int PHD(uint24_t, AddressingMode);
|
||||||
//! @brief Push the program bank register to the stack.
|
//! @brief Push the program bank register to the stack.
|
||||||
void PHK();
|
int PHK(uint24_t, AddressingMode);
|
||||||
//! @brief Push the processor status register to the stack.
|
//! @brief Push the processor status register to the stack.
|
||||||
void PHP();
|
int PHP(uint24_t, AddressingMode);
|
||||||
//! @brief Push the x index register to the stack.
|
//! @brief Push the x index register to the stack.
|
||||||
void PHX();
|
int PHX(uint24_t, AddressingMode);
|
||||||
//! @brief Push the y index register to the stack.
|
//! @brief Push the y index register to the stack.
|
||||||
void PHY();
|
int PHY(uint24_t, AddressingMode);
|
||||||
//! @brief Pull the accumulator to the stack.
|
//! @brief Pull the accumulator to the stack.
|
||||||
void PLA();
|
int PLA(uint24_t, AddressingMode);
|
||||||
//! @brief Pull the data bank register to the stack.
|
//! @brief Pull the data bank register to the stack.
|
||||||
void PLB();
|
int PLB(uint24_t, AddressingMode);
|
||||||
//! @brief Pull the direct page register to the stack.
|
//! @brief Pull the direct page register to the stack.
|
||||||
void PLD();
|
int PLD(uint24_t, AddressingMode);
|
||||||
//! @brief Pull the processor status register to the stack.
|
//! @brief Pull the processor status register to the stack.
|
||||||
void PLP();
|
int PLP(uint24_t, AddressingMode);
|
||||||
//! @brief Pull the x index register to the stack.
|
//! @brief Pull the x index register to the stack.
|
||||||
void PLX();
|
int PLX(uint24_t, AddressingMode);
|
||||||
//! @brief Pull the y index register to the stack.
|
//! @brief Pull the y index register to the stack.
|
||||||
void PLY();
|
int PLY(uint24_t, AddressingMode);
|
||||||
//! @brief Clear the carry flag.
|
//! @brief Clear the carry flag.
|
||||||
void CLC();
|
int CLC(uint24_t, AddressingMode);
|
||||||
//! @brief Clear the Interrupt Disable flag.
|
//! @brief Clear the Interrupt Disable flag.
|
||||||
void CLI();
|
int CLI(uint24_t, AddressingMode);
|
||||||
//! @brief Clear the decimal flag.
|
//! @brief Clear the decimal flag.
|
||||||
void CLD();
|
int CLD(uint24_t, AddressingMode);
|
||||||
//! @brief Clear the overflow flag.
|
//! @brief Clear the overflow flag.
|
||||||
void CLV();
|
int CLV(uint24_t, AddressingMode);
|
||||||
//! @brief Set the carry Flag.
|
//! @brief Set the carry Flag.
|
||||||
void SEC();
|
int SEC(uint24_t, AddressingMode);
|
||||||
//! @brief Set the decimal flag.
|
//! @brief Set the decimal flag.
|
||||||
void SED();
|
int SED(uint24_t, AddressingMode);
|
||||||
//! @brief Set the Interrupt Disable flag.
|
//! @brief Set the Interrupt Disable flag.
|
||||||
void SEI();
|
int SEI(uint24_t, AddressingMode);
|
||||||
//! @brief Exchange Carry and Emulation Flags
|
//! @brief Exchange Carry and Emulation Flags
|
||||||
void XCE();
|
int XCE(uint24_t, AddressingMode);
|
||||||
//! @brief And accumulator with memory.
|
//! @brief And accumulator with memory.
|
||||||
void AND(uint24_t valueAddr);
|
int AND(uint24_t valueAddr, AddressingMode);
|
||||||
//! @brief Subtract with Borrow from Accumulator.
|
//! @brief Subtract with Borrow from Accumulator.
|
||||||
void SBC(uint24_t valueAddr);
|
int SBC(uint24_t valueAddr, AddressingMode);
|
||||||
//! @brief Transfer A to X
|
//! @brief Transfer A to X
|
||||||
void TAX();
|
int TAX(uint24_t, AddressingMode);
|
||||||
//! @brief Transfer A to Y
|
//! @brief Transfer A to Y
|
||||||
void TAY();
|
int TAY(uint24_t, AddressingMode);
|
||||||
//! @brief Transfer X to SP
|
//! @brief Transfer X to SP
|
||||||
void TXS();
|
int TXS(uint24_t, AddressingMode);
|
||||||
//! @brief Increment the X register
|
//! @brief Increment the X register
|
||||||
void INX();
|
int INX(uint24_t, AddressingMode);
|
||||||
//! @brief Increment the Y register
|
//! @brief Increment the Y register
|
||||||
void INY();
|
int INY(uint24_t, AddressingMode);
|
||||||
//! @brief Compare the X register with the memory
|
//! @brief Compare the X register with the memory
|
||||||
void CPX(uint24_t valueAddr);
|
int CPX(uint24_t valueAddr, AddressingMode);
|
||||||
//! @brief Compare the Y register with the memory
|
//! @brief Compare the Y register with the memory
|
||||||
void CPY(uint24_t valueAddr);
|
int CPY(uint24_t valueAddr, AddressingMode);
|
||||||
//! @brief Branch if carry clear
|
//! @brief Branch if carry clear
|
||||||
bool BCC(uint24_t valueAddr);
|
int BCC(uint24_t valueAddr, AddressingMode);
|
||||||
//! @brief Branch if carry set
|
//! @brief Branch if carry set
|
||||||
bool BCS(uint24_t valueAddr);
|
int BCS(uint24_t valueAddr, AddressingMode);
|
||||||
//! @brief Branch if equal
|
//! @brief Branch if equal
|
||||||
bool BEQ(uint24_t valueAddr);
|
int BEQ(uint24_t valueAddr, AddressingMode);
|
||||||
//! @brief Branch if not equal
|
//! @brief Branch if not equal
|
||||||
bool BNE(uint24_t valueAddr);
|
int BNE(uint24_t valueAddr, AddressingMode);
|
||||||
//! @brief Branch if minus
|
//! @brief Branch if minus
|
||||||
bool BMI(uint24_t valueAddr);
|
int BMI(uint24_t valueAddr, AddressingMode);
|
||||||
//! @brief Branch if plus
|
//! @brief Branch if plus
|
||||||
bool BPL(uint24_t valueAddr);
|
int BPL(uint24_t valueAddr, AddressingMode);
|
||||||
//! @brief Branch if Overflow Clear
|
//! @brief Branch if Overflow Clear
|
||||||
bool BVC(uint24_t valueAddr);
|
int BVC(uint24_t valueAddr, AddressingMode);
|
||||||
//! @brief Branch if Overflow Set
|
//! @brief Branch if Overflow Set
|
||||||
bool BVS(uint24_t valueAddr);
|
int BVS(uint24_t valueAddr, AddressingMode);
|
||||||
//! @brief Branch always
|
//! @brief Branch always
|
||||||
bool BRA(uint24_t valueAddr);
|
int BRA(uint24_t valueAddr, AddressingMode);
|
||||||
//! @brief Branch always long
|
//! @brief Branch always long
|
||||||
bool BRL(uint24_t valueAddr);
|
int BRL(uint24_t valueAddr, AddressingMode);
|
||||||
//! @brief Jump.
|
//! @brief Jump.
|
||||||
void JMP(uint24_t valueAddr);
|
int JMP(uint24_t valueAddr, AddressingMode);
|
||||||
//! @brief Long jump.
|
//! @brief Long jump.
|
||||||
void JML(uint24_t valueAddr);
|
int JML(uint24_t valueAddr, AddressingMode);
|
||||||
|
//! @brief No OP.
|
||||||
|
int NOP(uint24_t, AddressingMode);
|
||||||
|
|
||||||
|
//! @brief All the instructions of the CPU.
|
||||||
|
//! @info Instructions are indexed by their opcode
|
||||||
|
Instruction _instructions[0x100] = {
|
||||||
|
{&CPU::BRK, 7, "brk", AddressingMode::Implied, 2}, // 00
|
||||||
|
{&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 01
|
||||||
|
{&CPU::COP, 7, "cop", AddressingMode::Implied, 2}, // 02
|
||||||
|
{&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 03
|
||||||
|
{&CPU::BRK, 7, "tsb #-#", AddressingMode::Implied, 2}, // 04
|
||||||
|
{&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 05
|
||||||
|
{&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 06
|
||||||
|
{&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 07
|
||||||
|
{&CPU::PHP, 3, "php", AddressingMode::Implied, 3}, // 08
|
||||||
|
{&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 09
|
||||||
|
{&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 0A
|
||||||
|
{&CPU::PHD, 4, "phd", AddressingMode::Implied, 1}, // 0B
|
||||||
|
{&CPU::BRK, 7, "tsb #-#", AddressingMode::Implied, 2}, // 0C
|
||||||
|
{&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 0D
|
||||||
|
{&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 0E
|
||||||
|
{&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 0F
|
||||||
|
{&CPU::BPL, 7, "bpl", AddressingMode::Implied, 2}, // 10
|
||||||
|
{&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 11
|
||||||
|
{&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 12
|
||||||
|
{&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 13
|
||||||
|
{&CPU::BRK, 7, "trb #-#", AddressingMode::Implied, 2}, // 14
|
||||||
|
{&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 15
|
||||||
|
{&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 16
|
||||||
|
{&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 17
|
||||||
|
{&CPU::CLC, 2, "clc", AddressingMode::Implied, 1}, // 18
|
||||||
|
{&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 19
|
||||||
|
{&CPU::BRK, 7, "inc #-#", AddressingMode::Implied, 2}, // 1A
|
||||||
|
{&CPU::BRK, 7, "tcs #-#", AddressingMode::Implied, 2}, // 1B
|
||||||
|
{&CPU::BRK, 7, "trb #-#", AddressingMode::Implied, 2}, // 1C
|
||||||
|
{&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 1D
|
||||||
|
{&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 1E
|
||||||
|
{&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 1F
|
||||||
|
{&CPU::JSR, 6, "jsr", AddressingMode::Absolute, 3}, // 20
|
||||||
|
{&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 21
|
||||||
|
{&CPU::JSL, 8, "jsl", AddressingMode::AbsoluteLong, 4}, // 22
|
||||||
|
{&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 23
|
||||||
|
{&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 24
|
||||||
|
{&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 25
|
||||||
|
{&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 26
|
||||||
|
{&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 27
|
||||||
|
{&CPU::PLP, 4, "plp", AddressingMode::Implied, 1}, // 28
|
||||||
|
{&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 29
|
||||||
|
{&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 2A
|
||||||
|
{&CPU::PLD, 5, "pld", AddressingMode::Implied, 1}, // 2B
|
||||||
|
{&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 2C
|
||||||
|
{&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 2D
|
||||||
|
{&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 2E
|
||||||
|
{&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 2F
|
||||||
|
{&CPU::BMI, 2, "bmi", AddressingMode::Implied, 2}, // 30
|
||||||
|
{&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 31
|
||||||
|
{&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 32
|
||||||
|
{&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 33
|
||||||
|
{&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 34
|
||||||
|
{&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 35
|
||||||
|
{&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 36
|
||||||
|
{&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 37
|
||||||
|
{&CPU::SEC, 2, "sec", AddressingMode::Implied, 1}, // 38
|
||||||
|
{&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 39
|
||||||
|
{&CPU::BRK, 7, "dec #-#", AddressingMode::Implied, 2}, // 3A
|
||||||
|
{&CPU::BRK, 7, "tsc #-#", AddressingMode::Implied, 2}, // 3B
|
||||||
|
{&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 3C
|
||||||
|
{&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 3D
|
||||||
|
{&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 3E
|
||||||
|
{&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 3F
|
||||||
|
{&CPU::RTI, 6, "rti", AddressingMode::Implied, 1}, // 40
|
||||||
|
{&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 41
|
||||||
|
{&CPU::BRK, 7, "wdm #-#", AddressingMode::Implied, 2}, // 42
|
||||||
|
{&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 43
|
||||||
|
{&CPU::BRK, 7, "mvp #-#", AddressingMode::Implied, 2}, // 44
|
||||||
|
{&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 45
|
||||||
|
{&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 46
|
||||||
|
{&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 47
|
||||||
|
{&CPU::PHA, 3, "pha", AddressingMode::Implied, 1}, // 48
|
||||||
|
{&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 49
|
||||||
|
{&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 4A
|
||||||
|
{&CPU::PHK, 3, "phk", AddressingMode::Implied, 1}, // 4B
|
||||||
|
{&CPU::JMP, 3, "jmp", AddressingMode::Absolute, 3}, // 4C
|
||||||
|
{&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 4D
|
||||||
|
{&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 4E
|
||||||
|
{&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 4F
|
||||||
|
{&CPU::BVC, 2, "bvc", AddressingMode::Implied, 2}, // 50
|
||||||
|
{&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 51
|
||||||
|
{&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 52
|
||||||
|
{&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 53
|
||||||
|
{&CPU::BRK, 7, "mvn #-#", AddressingMode::Implied, 2}, // 54
|
||||||
|
{&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 55
|
||||||
|
{&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 56
|
||||||
|
{&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 57
|
||||||
|
{&CPU::CLI, 2, "cli", AddressingMode::Implied, 1}, // 58
|
||||||
|
{&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 59
|
||||||
|
{&CPU::PHY, 3, "phy", AddressingMode::Implied, 1}, // 5A
|
||||||
|
{&CPU::BRK, 7, "tcd #-#", AddressingMode::Implied, 2}, // 5B
|
||||||
|
{&CPU::JML, 4, "jml", AddressingMode::Implied, 4}, // 5C
|
||||||
|
{&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 5D
|
||||||
|
{&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 5E
|
||||||
|
{&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 5F
|
||||||
|
{&CPU::BRK, 7, "rtl #-#", AddressingMode::Implied, 2}, // 60
|
||||||
|
{&CPU::ADC, 6, "adc", AddressingMode::DirectPageIndirectIndexedByX, 2}, // 61
|
||||||
|
{&CPU::BRK, 7, "per #-#", AddressingMode::Implied, 2}, // 62
|
||||||
|
{&CPU::ADC, 4, "adc", AddressingMode::StackRelative, 2}, // 63
|
||||||
|
{&CPU::STZ, 3, "stz", AddressingMode::DirectPage, 2}, // 64
|
||||||
|
{&CPU::ADC, 3, "adc", AddressingMode::DirectPage, 2}, // 65
|
||||||
|
{&CPU::BRK, 7, "ror #-#", AddressingMode::Implied, 2}, // 66
|
||||||
|
{&CPU::ADC, 6, "adc", AddressingMode::DirectPageIndirectLong, 2}, // 67
|
||||||
|
{&CPU::PLA, 4, "pla", AddressingMode::Implied, 1}, // 68
|
||||||
|
{&CPU::ADC, 2, "adc", AddressingMode::ImmediateForA, 2}, // 69
|
||||||
|
{&CPU::BRK, 7, "ror #-#", AddressingMode::Implied, 2}, // 6A
|
||||||
|
{&CPU::BRK, 7, "rts #-#", AddressingMode::Implied, 2}, // 6B
|
||||||
|
{&CPU::JMP, 5, "jmp", AddressingMode::AbsoluteIndirect, 3}, // 6C
|
||||||
|
{&CPU::ADC, 4, "adc", AddressingMode::Absolute, 3}, // 6D
|
||||||
|
{&CPU::BRK, 7, "ror #-#", AddressingMode::Implied, 2}, // 6E
|
||||||
|
{&CPU::ADC, 5, "adc", AddressingMode::AbsoluteLong, 4}, // 6F
|
||||||
|
{&CPU::BVS, 2, "bvs", AddressingMode::Implied, 2}, // 70
|
||||||
|
{&CPU::ADC, 5, "adc", AddressingMode::DirectPageIndirectIndexedByY, 2}, // 71
|
||||||
|
{&CPU::ADC, 5, "adc", AddressingMode::DirectPageIndirect, 2}, // 72
|
||||||
|
{&CPU::ADC, 7, "adc", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // 73
|
||||||
|
{&CPU::STZ, 4, "stz", AddressingMode::DirectPageIndexedByX, 2}, // 74
|
||||||
|
{&CPU::ADC, 4, "adc", AddressingMode::DirectPageIndexedByX, 2}, // 75
|
||||||
|
{&CPU::BRK, 7, "ror #-#", AddressingMode::Implied, 2}, // 76
|
||||||
|
{&CPU::ADC, 6, "adc", AddressingMode::DirectPageIndirectIndexedByY, 2}, // 77
|
||||||
|
{&CPU::SEI, 2, "sei", AddressingMode::Implied, 1}, // 78
|
||||||
|
{&CPU::ADC, 4, "adc", AddressingMode::AbsoluteIndexedByY, 2}, // 79
|
||||||
|
{&CPU::PLY, 4, "ply", AddressingMode::Implied, 1}, // 7A
|
||||||
|
{&CPU::BRK, 7, "tdc #-#", AddressingMode::Implied, 2}, // 7B
|
||||||
|
{&CPU::JMP, 6, "jmp", AddressingMode::AbsoluteIndirectIndexedByX, 3}, // 7C
|
||||||
|
{&CPU::ADC, 4, "adc", AddressingMode::AbsoluteIndexedByX, 3}, // 7D
|
||||||
|
{&CPU::BRK, 7, "ror #-#", AddressingMode::Implied, 2}, // 7E
|
||||||
|
{&CPU::ADC, 5, "adc", AddressingMode::AbsoluteIndexedByXLong, 4}, // 7F
|
||||||
|
{&CPU::BRA, 3, "bra", AddressingMode::Implied, 2}, // 80
|
||||||
|
{&CPU::STA, 6, "sta", AddressingMode::DirectPageIndexedByX, 2}, // 81
|
||||||
|
{&CPU::BRL, 4, "brl", AddressingMode::Implied, 3}, // 82
|
||||||
|
{&CPU::STA, 4, "sta", AddressingMode::StackRelative, 2}, // 83
|
||||||
|
{&CPU::STY, 3, "sty", AddressingMode::DirectPage, 2}, // 84
|
||||||
|
{&CPU::STA, 3, "sta", AddressingMode::DirectPage, 2}, // 85
|
||||||
|
{&CPU::STX, 3, "stx", AddressingMode::DirectPage, 2}, // 86
|
||||||
|
{&CPU::STA, 6, "sta", AddressingMode::DirectPageIndirectLong, 2}, // 87
|
||||||
|
{&CPU::BRK, 7, "dey #-#", AddressingMode::Implied, 2}, // 88
|
||||||
|
{&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 89
|
||||||
|
{&CPU::BRK, 7, "txa #-#", AddressingMode::Implied, 2}, // 8A
|
||||||
|
{&CPU::PHB, 3, "phb", AddressingMode::Implied, 1}, // 8B
|
||||||
|
{&CPU::STY, 4, "sty", AddressingMode::Absolute, 3}, // 8C
|
||||||
|
{&CPU::STA, 4, "sta", AddressingMode::Absolute, 3}, // 8D
|
||||||
|
{&CPU::STX, 4, "stx", AddressingMode::Absolute, 3}, // 8E
|
||||||
|
{&CPU::STA, 5, "sta", AddressingMode::AbsoluteLong, 4}, // 8F
|
||||||
|
{&CPU::BCC, 2, "bcc", AddressingMode::Implied, 2}, // 90
|
||||||
|
{&CPU::STA, 6, "sta", AddressingMode::DirectPageIndirectIndexedByY, 2}, // 91
|
||||||
|
{&CPU::STA, 5, "sta", AddressingMode::DirectPageIndirect, 2}, // 92
|
||||||
|
{&CPU::STA, 7, "sta", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // 93
|
||||||
|
{&CPU::STY, 4, "sty", AddressingMode::DirectPageIndirectIndexedByX, 2}, // 94
|
||||||
|
{&CPU::STA, 4, "sta", AddressingMode::DirectPageIndexedByX, 2}, // 95
|
||||||
|
{&CPU::STX, 4, "stx", AddressingMode::DirectPageIndexedByY, 2}, // 96
|
||||||
|
{&CPU::STA, 6, "sta", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // 97
|
||||||
|
{&CPU::BRK, 7, "tya #-#", AddressingMode::Implied, 2}, // 98
|
||||||
|
{&CPU::STA, 5, "sta", AddressingMode::AbsoluteIndexedByY, 3}, // 99
|
||||||
|
{&CPU::TXS, 2, "txs", AddressingMode::Implied, 1}, // 9A
|
||||||
|
{&CPU::BRK, 7, "txy #-#", AddressingMode::Implied, 2}, // 9B
|
||||||
|
{&CPU::STZ, 4, "stz", AddressingMode::Absolute, 3}, // 9C
|
||||||
|
{&CPU::STA, 5, "sta", AddressingMode::AbsoluteIndexedByX, 3}, // 9D
|
||||||
|
{&CPU::STZ, 5, "stz", AddressingMode::AbsoluteIndexedByX, 3}, // 9E
|
||||||
|
{&CPU::STA, 5, "sta", AddressingMode::AbsoluteIndexedByXLong, 4}, // 9F
|
||||||
|
{&CPU::LDY, 2, "ldy", AddressingMode::ImmediateForX, 2}, // A0
|
||||||
|
{&CPU::LDA, 6, "lda", AddressingMode::DirectPageIndirectIndexedByX, 2}, // A1
|
||||||
|
{&CPU::LDX, 2, "ldx", AddressingMode::ImmediateForX, 2}, // A2
|
||||||
|
{&CPU::LDA, 4, "lda", AddressingMode::StackRelative, 2}, // A3
|
||||||
|
{&CPU::LDY, 3, "ldy", AddressingMode::DirectPage, 2}, // A4
|
||||||
|
{&CPU::LDA, 3, "lda", AddressingMode::DirectPage, 2}, // A5
|
||||||
|
{&CPU::LDX, 3, "ldx", AddressingMode::DirectPage, 2}, // A6
|
||||||
|
{&CPU::LDA, 6, "lda", AddressingMode::DirectPageIndirectLong, 2}, // A7
|
||||||
|
{&CPU::TAY, 2, "tay", AddressingMode::Implied, 1}, // A8
|
||||||
|
{&CPU::LDA, 2, "lda", AddressingMode::ImmediateForA, 2}, // A9
|
||||||
|
{&CPU::TAX, 2, "tax", AddressingMode::Implied, 1}, // AA
|
||||||
|
{&CPU::BRK, 7, "trb #-#", AddressingMode::Implied, 2}, // AB
|
||||||
|
{&CPU::LDY, 4, "ldy", AddressingMode::Absolute, 4}, // AC
|
||||||
|
{&CPU::LDA, 4, "lda", AddressingMode::Absolute, 3}, // AD
|
||||||
|
{&CPU::LDX, 4, "ldx", AddressingMode::Absolute, 3}, // AE
|
||||||
|
{&CPU::LDA, 5, "lda", AddressingMode::AbsoluteLong, 4}, // AF
|
||||||
|
{&CPU::BCS, 2, "bcs", AddressingMode::Implied, 2}, // B0
|
||||||
|
{&CPU::LDA, 5, "lda", AddressingMode::DirectPageIndirectIndexedByY, 2}, // B1
|
||||||
|
{&CPU::LDA, 5, "lda", AddressingMode::DirectPageIndirect, 2}, // B2
|
||||||
|
{&CPU::LDA, 7, "lda", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // B3
|
||||||
|
{&CPU::LDY, 4, "ldy", AddressingMode::DirectPageIndexedByX, 2}, // B4
|
||||||
|
{&CPU::LDA, 4, "lda", AddressingMode::DirectPageIndexedByX, 2}, // B5
|
||||||
|
{&CPU::LDX, 4, "ldx", AddressingMode::DirectPageIndexedByY, 2}, // B6
|
||||||
|
{&CPU::LDA, 6, "lda", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // B7
|
||||||
|
{&CPU::CLV, 7, "clv", AddressingMode::Implied, 1}, // B8
|
||||||
|
{&CPU::LDA, 4, "lda", AddressingMode::AbsoluteIndexedByY, 3}, // B9
|
||||||
|
{&CPU::BRK, 7, "mvn #-#", AddressingMode::Implied, 2}, // BA
|
||||||
|
{&CPU::BRK, 7, "tyx #-#", AddressingMode::Implied, 2}, // BB
|
||||||
|
{&CPU::LDY, 4, "ldy", AddressingMode::AbsoluteIndexedByX, 3}, // BC
|
||||||
|
{&CPU::LDA, 4, "lda", AddressingMode::AbsoluteIndexedByX, 3}, // BD
|
||||||
|
{&CPU::LDX, 4, "ldx", AddressingMode::AbsoluteIndexedByY, 3}, // BE
|
||||||
|
{&CPU::LDA, 5, "lda", AddressingMode::AbsoluteIndexedByXLong, 4}, // BF
|
||||||
|
{&CPU::BRK, 7, "cpy #-#", AddressingMode::Implied, 2}, // C0
|
||||||
|
{&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // C1
|
||||||
|
{&CPU::REP, 3, "rep", AddressingMode::Immediate8bits, 2}, // C2
|
||||||
|
{&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // C3
|
||||||
|
{&CPU::BRK, 7, "cpy #-#", AddressingMode::Implied, 2}, // C4
|
||||||
|
{&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // C5
|
||||||
|
{&CPU::BRK, 7, "dec #-#", AddressingMode::Implied, 2}, // C6
|
||||||
|
{&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // C7
|
||||||
|
{&CPU::INY, 2, "iny", AddressingMode::Implied, 1}, // C8
|
||||||
|
{&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // C9
|
||||||
|
{&CPU::BRK, 7, "dex #-#", AddressingMode::Implied, 2}, // CA
|
||||||
|
{&CPU::BRK, 7, "wai #-#", AddressingMode::Implied, 2}, // CB
|
||||||
|
{&CPU::BRK, 7, "cpy #-#", AddressingMode::Implied, 2}, // CC
|
||||||
|
{&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // CD
|
||||||
|
{&CPU::BRK, 7, "dec #-#", AddressingMode::Implied, 2}, // CE
|
||||||
|
{&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // CF
|
||||||
|
{&CPU::BNE, 2, "bne", AddressingMode::Implied, 2}, // D0
|
||||||
|
{&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // D1
|
||||||
|
{&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // D2
|
||||||
|
{&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // D3
|
||||||
|
{&CPU::BRK, 7, "pei #-#", AddressingMode::Implied, 2}, // D4
|
||||||
|
{&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // D5
|
||||||
|
{&CPU::BRK, 7, "dec #-#", AddressingMode::Implied, 2}, // D6
|
||||||
|
{&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // D7
|
||||||
|
{&CPU::CLD, 27, "cld", AddressingMode::Implied, 2}, // D8
|
||||||
|
{&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // D9
|
||||||
|
{&CPU::PHX, 3, "phx", AddressingMode::Implied, 1}, // DA
|
||||||
|
{&CPU::BRK, 7, "stp #-#", AddressingMode::Implied, 2}, // DB
|
||||||
|
{&CPU::JML, 7, "jml", AddressingMode::AbsoluteIndirectLong, 2}, // DC
|
||||||
|
{&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // DD
|
||||||
|
{&CPU::BRK, 7, "dec #-#", AddressingMode::Implied, 2}, // DE
|
||||||
|
{&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // DF
|
||||||
|
{&CPU::BRK, 7, "cpx #-#", AddressingMode::Implied, 2}, // E0
|
||||||
|
{&CPU::SBC, 6, "sbc", AddressingMode::DirectPageIndirectIndexedByX, 2}, // E1
|
||||||
|
{&CPU::SEP, 3, "sep", AddressingMode::Immediate8bits, 2}, // E2
|
||||||
|
{&CPU::SBC, 4, "sbc", AddressingMode::StackRelative, 2}, // E3
|
||||||
|
{&CPU::BRK, 7, "cpx #-#", AddressingMode::Implied, 2}, // E4
|
||||||
|
{&CPU::SBC, 3, "sbc", AddressingMode::DirectPage, 2}, // E5
|
||||||
|
{&CPU::BRK, 7, "inc #-#", AddressingMode::Implied, 2}, // E6
|
||||||
|
{&CPU::SBC, 6, "sbc", AddressingMode::DirectPageIndirectLong, 2}, // E7
|
||||||
|
{&CPU::INX, 2, "inx", AddressingMode::Implied, 1}, // E8
|
||||||
|
{&CPU::SBC, 2, "sbc", AddressingMode::ImmediateForA, 2}, // E9
|
||||||
|
{&CPU::NOP, 2, "nop", AddressingMode::Implied, 1}, // EA
|
||||||
|
{&CPU::BRK, 7, "xba #-#", AddressingMode::Implied, 2}, // EB
|
||||||
|
{&CPU::BRK, 7, "cpx #-#", AddressingMode::Implied, 2}, // EC
|
||||||
|
{&CPU::SBC, 4, "sbc", AddressingMode::Absolute, 3}, // ED
|
||||||
|
{&CPU::BRK, 7, "inc #-#", AddressingMode::Implied, 2}, // EE
|
||||||
|
{&CPU::SBC, 5, "sbc", AddressingMode::AbsoluteLong, 4}, // EF
|
||||||
|
{&CPU::BEQ, 2, "beq", AddressingMode::Implied, 2}, // F0
|
||||||
|
{&CPU::SBC, 5, "sbc", AddressingMode::DirectPageIndirectIndexedByY, 2}, // F1
|
||||||
|
{&CPU::SBC, 5, "sbc", AddressingMode::DirectPageIndirect, 2}, // F2
|
||||||
|
{&CPU::SBC, 7, "sbc", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // F3
|
||||||
|
{&CPU::BRK, 7, "pea #-#", AddressingMode::Implied, 2}, // F4
|
||||||
|
{&CPU::SBC, 4, "sbc", AddressingMode::DirectPageIndexedByX, 2}, // F5
|
||||||
|
{&CPU::BRK, 7, "inc #-#", AddressingMode::Implied, 2}, // F6
|
||||||
|
{&CPU::SBC, 6, "sbc", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // F7
|
||||||
|
{&CPU::SED, 2, "sed", AddressingMode::Implied, 1}, // F8
|
||||||
|
{&CPU::SBC, 4, "sbc", AddressingMode::AbsoluteIndexedByY, 3}, // F9
|
||||||
|
{&CPU::PLX, 4, "plx", AddressingMode::Implied, 1}, // FA
|
||||||
|
{&CPU::XCE, 2, "xce", AddressingMode::Implied, 1}, // FB
|
||||||
|
{&CPU::JSR, 8, "jsr", AddressingMode::AbsoluteIndirectIndexedByX, 3}, // FC
|
||||||
|
{&CPU::SBC, 4, "sbc", AddressingMode::AbsoluteIndexedByX, 3}, // FD
|
||||||
|
{&CPU::BRK, 7, "inc #-#", AddressingMode::Implied, 2}, // FE
|
||||||
|
{&CPU::SBC, 5, "sbc", AddressingMode::AbsoluteIndexedByXLong, 4}, // FF
|
||||||
|
};
|
||||||
public:
|
public:
|
||||||
explicit CPU(std::shared_ptr<Memory::MemoryBus> bus, Cartridge::Header &cartridgeHeader);
|
explicit CPU(std::shared_ptr<Memory::MemoryBus> bus, Cartridge::Header &cartridgeHeader);
|
||||||
CPU(const CPU &) = default;
|
CPU(const CPU &) = default;
|
||||||
@@ -578,7 +663,7 @@ namespace ComSquare::CPU
|
|||||||
Component getComponent() override;
|
Component getComponent() override;
|
||||||
|
|
||||||
//! @brief Reset interrupt - Called on boot and when the reset button is pressed.
|
//! @brief Reset interrupt - Called on boot and when the reset button is pressed.
|
||||||
virtual void RESB();
|
virtual int RESB();
|
||||||
|
|
||||||
//! @brief Return true if the CPU is overloaded with debugging features.
|
//! @brief Return true if the CPU is overloaded with debugging features.
|
||||||
virtual bool isDebugger();
|
virtual bool isDebugger();
|
||||||
|
|||||||
67
sources/CPU/Instruction.hpp
Normal file
67
sources/CPU/Instruction.hpp
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
//
|
||||||
|
// Created by anonymus-raccoon on 3/25/20.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COMSQUARE_INSTRUCTION_HPP
|
||||||
|
#define COMSQUARE_INSTRUCTION_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "../Models/Int24.hpp"
|
||||||
|
|
||||||
|
namespace ComSquare::CPU
|
||||||
|
{
|
||||||
|
class CPU;
|
||||||
|
|
||||||
|
//! @brief Different addressing modes that instructions can use for the main CPU.
|
||||||
|
enum AddressingMode {
|
||||||
|
Implied,
|
||||||
|
|
||||||
|
Immediate8bits,
|
||||||
|
ImmediateForA,
|
||||||
|
ImmediateForX,
|
||||||
|
|
||||||
|
Absolute,
|
||||||
|
AbsoluteLong,
|
||||||
|
|
||||||
|
DirectPage,
|
||||||
|
DirectPageIndirect,
|
||||||
|
DirectPageIndirectLong,
|
||||||
|
|
||||||
|
AbsoluteIndexedByX,
|
||||||
|
AbsoluteIndexedByXLong,
|
||||||
|
AbsoluteIndexedByY,
|
||||||
|
|
||||||
|
DirectPageIndexedByX,
|
||||||
|
DirectPageIndexedByY,
|
||||||
|
DirectPageIndirectIndexedByX,
|
||||||
|
DirectPageIndirectIndexedByY,
|
||||||
|
DirectPageIndirectIndexedByYLong,
|
||||||
|
|
||||||
|
StackRelative,
|
||||||
|
StackRelativeIndirectIndexedByY,
|
||||||
|
|
||||||
|
|
||||||
|
ProgramCounterRelative,
|
||||||
|
ProgramCounterRelativeLong,
|
||||||
|
|
||||||
|
AbsoluteIndirect,
|
||||||
|
AbsoluteIndirectIndexedByX,
|
||||||
|
|
||||||
|
AbsoluteIndirectLong
|
||||||
|
};
|
||||||
|
|
||||||
|
//! @brief Struct containing basic information about instructions.
|
||||||
|
struct Instruction {
|
||||||
|
int (CPU::*call)(uint24_t valueAddr, AddressingMode mode) = nullptr;
|
||||||
|
int cycleCount = 0;
|
||||||
|
std::string name = "";
|
||||||
|
AddressingMode addressingMode = Implied;
|
||||||
|
int size = 0;
|
||||||
|
|
||||||
|
Instruction() = default;
|
||||||
|
Instruction(const Instruction &) = default;
|
||||||
|
Instruction &operator=(const Instruction &) = default;
|
||||||
|
~Instruction() = default;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif //COMSQUARE_INSTRUCTION_HPP
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
namespace ComSquare::CPU
|
namespace ComSquare::CPU
|
||||||
{
|
{
|
||||||
void CPU::AND(uint24_t valueAddr)
|
int CPU::AND(uint24_t valueAddr, AddressingMode mode)
|
||||||
{
|
{
|
||||||
unsigned negativeMask = this->_isEmulationMode ? 0x80u : 0x8000u;
|
unsigned negativeMask = this->_isEmulationMode ? 0x80u : 0x8000u;
|
||||||
unsigned value = this->_bus->read(valueAddr);
|
unsigned value = this->_bus->read(valueAddr);
|
||||||
@@ -17,5 +17,27 @@ namespace ComSquare::CPU
|
|||||||
this->_registers.a &= value;
|
this->_registers.a &= value;
|
||||||
this->_registers.p.n = this->_registers.a & negativeMask;
|
this->_registers.p.n = this->_registers.a & negativeMask;
|
||||||
this->_registers.p.z = this->_registers.a == 0;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,152 +6,185 @@
|
|||||||
|
|
||||||
namespace ComSquare::CPU
|
namespace ComSquare::CPU
|
||||||
{
|
{
|
||||||
void CPU::SEC()
|
int CPU::SEC(uint24_t, AddressingMode)
|
||||||
{
|
{
|
||||||
this->_registers.p.c = true;
|
this->_registers.p.c = true;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::SED()
|
int CPU::SED(uint24_t, AddressingMode)
|
||||||
{
|
{
|
||||||
this->_registers.p.d = true;
|
this->_registers.p.d = true;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::SEI()
|
int CPU::SEI(uint24_t, AddressingMode)
|
||||||
{
|
{
|
||||||
this->_registers.p.i = true;
|
this->_registers.p.i = true;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::CLC()
|
int CPU::CLC(uint24_t, AddressingMode)
|
||||||
{
|
{
|
||||||
this->_registers.p.c = false;
|
this->_registers.p.c = false;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::CLI()
|
int CPU::CLI(uint24_t, AddressingMode)
|
||||||
{
|
{
|
||||||
this->_registers.p.i = false;
|
this->_registers.p.i = false;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::CLD()
|
int CPU::CLD(uint24_t, AddressingMode)
|
||||||
{
|
{
|
||||||
this->_registers.p.d = false;
|
this->_registers.p.d = false;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::CLV()
|
int CPU::CLV(uint24_t, AddressingMode)
|
||||||
{
|
{
|
||||||
this->_registers.p.v = false;
|
this->_registers.p.v = false;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::SEP(uint24_t value)
|
int CPU::SEP(uint24_t valueAddr, AddressingMode)
|
||||||
{
|
{
|
||||||
this->_registers.p.flags |= value;
|
this->_registers.p.flags |= this->_bus->read(valueAddr);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::REP(uint24_t value)
|
int CPU::REP(uint24_t valueAddr, AddressingMode)
|
||||||
{
|
{
|
||||||
this->_registers.p.flags &= ~value;
|
this->_registers.p.flags &= ~this->_bus->read(valueAddr);
|
||||||
if (this->_isEmulationMode) {
|
if (this->_isEmulationMode) {
|
||||||
this->_registers.p.x_b = true;
|
this->_registers.p.x_b = true;
|
||||||
this->_registers.p.m = true;
|
this->_registers.p.m = true;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::JSR(uint24_t value)
|
int CPU::JSR(uint24_t valueAddr, AddressingMode)
|
||||||
{
|
{
|
||||||
this->_push(--this->_registers.pc);
|
this->_push(--this->_registers.pc);
|
||||||
this->_registers.pc = value;
|
this->_registers.pc = valueAddr;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::JSL(uint24_t value)
|
int CPU::JSL(uint24_t valueAddr, AddressingMode)
|
||||||
{
|
{
|
||||||
this->_registers.pac--;
|
this->_registers.pac--;
|
||||||
this->_push(this->_registers.pbr);
|
this->_push(this->_registers.pbr);
|
||||||
this->_push(this->_registers.pc);
|
this->_push(this->_registers.pc);
|
||||||
this->_registers.pac = value;
|
this->_registers.pac = valueAddr;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::PHA()
|
int CPU::PHA(uint24_t, AddressingMode)
|
||||||
{
|
{
|
||||||
this->_push(this->_registers.a);
|
this->_push(this->_registers.a);
|
||||||
|
return !this->_registers.p.m;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::PHB()
|
int CPU::PHB(uint24_t, AddressingMode)
|
||||||
{
|
{
|
||||||
this->_push(this->_registers.dbr);
|
this->_push(this->_registers.dbr);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::PHD()
|
int CPU::PHD(uint24_t, AddressingMode)
|
||||||
{
|
{
|
||||||
this->_push(this->_registers.d);
|
this->_push(this->_registers.d);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::PHK()
|
int CPU::PHK(uint24_t, AddressingMode)
|
||||||
{
|
{
|
||||||
this->_push(this->_registers.pbr);
|
this->_push(this->_registers.pbr);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::PHP()
|
int CPU::PHP(uint24_t, AddressingMode)
|
||||||
{
|
{
|
||||||
this->_push(this->_registers.p.flags);
|
this->_push(this->_registers.p.flags);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::PHX()
|
int CPU::PHX(uint24_t, AddressingMode)
|
||||||
{
|
{
|
||||||
this->_push(this->_registers.x);
|
this->_push(this->_registers.x);
|
||||||
|
return !this->_registers.p.x_b;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::PHY()
|
int CPU::PHY(uint24_t, AddressingMode)
|
||||||
{
|
{
|
||||||
this->_push(this->_registers.y);
|
this->_push(this->_registers.y);
|
||||||
|
return !this->_registers.p.x_b;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::PLA()
|
int CPU::PLA(uint24_t, AddressingMode)
|
||||||
{
|
{
|
||||||
// TODO this register should be poped by 8 if the m flag is 1
|
if (this->_registers.p.m) {
|
||||||
|
this->_registers.a = this->_pop();
|
||||||
|
this->_registers.ah = 0;
|
||||||
|
} else
|
||||||
this->_registers.a = this->_pop16();
|
this->_registers.a = this->_pop16();
|
||||||
this->_registers.p.z = this->_registers.a == 0;
|
this->_registers.p.z = this->_registers.a == 0;
|
||||||
this->_registers.p.n = this->_registers.a & 0x8000u;
|
this->_registers.p.n = this->_registers.a & 0x8000u;
|
||||||
|
return !this->_registers.p.m;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::PLB()
|
int CPU::PLB(uint24_t, AddressingMode)
|
||||||
{
|
{
|
||||||
this->_registers.dbr = this->_pop();
|
this->_registers.dbr = this->_pop();
|
||||||
this->_registers.p.z = this->_registers.dbr == 0;
|
this->_registers.p.z = this->_registers.dbr == 0;
|
||||||
this->_registers.p.n = this->_registers.dbr & 0x80u;
|
this->_registers.p.n = this->_registers.dbr & 0x80u;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::PLD()
|
int CPU::PLD(uint24_t, AddressingMode)
|
||||||
{
|
{
|
||||||
this->_registers.d = this->_pop16();
|
this->_registers.d = this->_pop16();
|
||||||
this->_registers.p.z = this->_registers.d == 0;
|
this->_registers.p.z = this->_registers.d == 0;
|
||||||
this->_registers.p.n = this->_registers.d & 0x8000u;
|
this->_registers.p.n = this->_registers.d & 0x8000u;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::PLP()
|
int CPU::PLP(uint24_t, AddressingMode)
|
||||||
{
|
{
|
||||||
this->_registers.p.flags = this->_pop();
|
this->_registers.p.flags = this->_pop();
|
||||||
if (this->_isEmulationMode) {
|
if (this->_isEmulationMode) {
|
||||||
this->_registers.p.m = true;
|
this->_registers.p.m = true;
|
||||||
this->_registers.p.x_b = true;
|
this->_registers.p.x_b = true;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::PLX()
|
int CPU::PLX(uint24_t, AddressingMode)
|
||||||
{
|
{
|
||||||
// TODO this register should be poped by 8 if the x_b is 1
|
if (this->_registers.p.x_b) {
|
||||||
|
this->_registers.x = this->_pop();
|
||||||
|
this->_registers.xh = 0;
|
||||||
|
} else
|
||||||
this->_registers.x = this->_pop16();
|
this->_registers.x = this->_pop16();
|
||||||
this->_registers.p.z = this->_registers.x == 0;
|
this->_registers.p.z = this->_registers.x == 0;
|
||||||
this->_registers.p.n = this->_registers.x & 0x8000u;
|
this->_registers.p.n = this->_registers.x & 0x8000u;
|
||||||
|
return !this->_registers.p.x_b;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::PLY()
|
int CPU::PLY(uint24_t, AddressingMode)
|
||||||
{
|
{
|
||||||
// TODO this register should be poped by 8 if the x_b is 1
|
if (this->_registers.p.x_b) {
|
||||||
|
this->_registers.y = this->_pop();
|
||||||
|
this->_registers.yh = 0;
|
||||||
|
} else
|
||||||
this->_registers.y = this->_pop16();
|
this->_registers.y = this->_pop16();
|
||||||
this->_registers.p.z = this->_registers.y == 0;
|
this->_registers.p.z = this->_registers.y == 0;
|
||||||
this->_registers.p.n = this->_registers.y & 0x8000u;
|
this->_registers.p.n = this->_registers.y & 0x8000u;
|
||||||
|
return !this->_registers.p.x_b;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::XCE()
|
int CPU::XCE(uint24_t, AddressingMode)
|
||||||
{
|
{
|
||||||
bool oldCarry = this->_registers.p.c;
|
bool oldCarry = this->_registers.p.c;
|
||||||
this->_registers.p.c = this->_isEmulationMode;
|
this->_registers.p.c = this->_isEmulationMode;
|
||||||
@@ -163,9 +196,10 @@ namespace ComSquare::CPU
|
|||||||
this->_registers.xh = 0;
|
this->_registers.xh = 0;
|
||||||
this->_registers.yh = 0;
|
this->_registers.yh = 0;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::INX()
|
int CPU::INX(uint24_t, AddressingMode)
|
||||||
{
|
{
|
||||||
this->_registers.x++;
|
this->_registers.x++;
|
||||||
|
|
||||||
@@ -175,9 +209,10 @@ namespace ComSquare::CPU
|
|||||||
unsigned negativeFlag = this->_registers.p.x_b ? 0x80u : 0x8000u;
|
unsigned negativeFlag = this->_registers.p.x_b ? 0x80u : 0x8000u;
|
||||||
this->_registers.p.z = this->_registers.x == 0;
|
this->_registers.p.z = this->_registers.x == 0;
|
||||||
this->_registers.p.n = this->_registers.x & negativeFlag;
|
this->_registers.p.n = this->_registers.x & negativeFlag;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::INY()
|
int CPU::INY(uint24_t, AddressingMode)
|
||||||
{
|
{
|
||||||
this->_registers.y++;
|
this->_registers.y++;
|
||||||
|
|
||||||
@@ -187,9 +222,10 @@ namespace ComSquare::CPU
|
|||||||
unsigned negativeFlag = this->_registers.p.x_b ? 0x80u : 0x8000u;
|
unsigned negativeFlag = this->_registers.p.x_b ? 0x80u : 0x8000u;
|
||||||
this->_registers.p.z = this->_registers.y == 0;
|
this->_registers.p.z = this->_registers.y == 0;
|
||||||
this->_registers.p.n = this->_registers.y & negativeFlag;
|
this->_registers.p.n = this->_registers.y & negativeFlag;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::CPX(uint24_t valueAddr)
|
int CPU::CPX(uint24_t valueAddr, AddressingMode mode)
|
||||||
{
|
{
|
||||||
unsigned value = this->_bus->read(valueAddr++);
|
unsigned value = this->_bus->read(valueAddr++);
|
||||||
|
|
||||||
@@ -206,9 +242,10 @@ namespace ComSquare::CPU
|
|||||||
this->_registers.p.n = x & 0x8000u;
|
this->_registers.p.n = x & 0x8000u;
|
||||||
}
|
}
|
||||||
this->_registers.p.c = this->_registers.x >= value;
|
this->_registers.p.c = this->_registers.x >= value;
|
||||||
|
return !this->_registers.p.x_b + (mode == DirectPage && this->_registers.dl != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::CPY(uint24_t valueAddr)
|
int CPU::CPY(uint24_t valueAddr, AddressingMode mode)
|
||||||
{
|
{
|
||||||
unsigned value = this->_bus->read(valueAddr++);
|
unsigned value = this->_bus->read(valueAddr++);
|
||||||
|
|
||||||
@@ -225,86 +262,94 @@ namespace ComSquare::CPU
|
|||||||
this->_registers.p.z = y == 0;
|
this->_registers.p.z = y == 0;
|
||||||
this->_registers.p.n = y & 0x8000u;
|
this->_registers.p.n = y & 0x8000u;
|
||||||
}
|
}
|
||||||
|
return !this->_registers.p.x_b + (mode == DirectPage && this->_registers.dl != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CPU::BCC(uint24_t valueAddr)
|
int CPU::BCC(uint24_t valueAddr, AddressingMode)
|
||||||
{
|
{
|
||||||
if (!this->_registers.p.c)
|
if (!this->_registers.p.c)
|
||||||
this->_registers.pac += static_cast<int8_t>(this->_bus->read(valueAddr));
|
this->_registers.pc += static_cast<int8_t>(this->_bus->read(valueAddr));
|
||||||
return !this->_registers.p.c;
|
return !this->_registers.p.c + this->_isEmulationMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CPU::BCS(uint24_t valueAddr)
|
int CPU::BCS(uint24_t valueAddr, AddressingMode)
|
||||||
{
|
{
|
||||||
if (this->_registers.p.c)
|
if (this->_registers.p.c)
|
||||||
this->_registers.pac += static_cast<int8_t>(this->_bus->read(valueAddr));
|
this->_registers.pc += static_cast<int8_t>(this->_bus->read(valueAddr));
|
||||||
return this->_registers.p.c;
|
return this->_registers.p.c + this->_isEmulationMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CPU::BEQ(uint24_t valueAddr)
|
int CPU::BEQ(uint24_t valueAddr, AddressingMode)
|
||||||
{
|
{
|
||||||
if (this->_registers.p.z)
|
if (this->_registers.p.z)
|
||||||
this->_registers.pac += static_cast<int8_t>(this->_bus->read(valueAddr));
|
this->_registers.pc += static_cast<int8_t>(this->_bus->read(valueAddr));
|
||||||
return this->_registers.p.z;
|
return this->_registers.p.z + this->_isEmulationMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CPU::BNE(uint24_t valueAddr)
|
int CPU::BNE(uint24_t valueAddr, AddressingMode)
|
||||||
{
|
{
|
||||||
if (!this->_registers.p.z)
|
if (!this->_registers.p.z)
|
||||||
this->_registers.pac += static_cast<int8_t>(this->_bus->read(valueAddr));
|
this->_registers.pc += static_cast<int8_t>(this->_bus->read(valueAddr));
|
||||||
return !this->_registers.p.z;
|
return !this->_registers.p.z + this->_isEmulationMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CPU::BMI(uint24_t valueAddr)
|
int CPU::BMI(uint24_t valueAddr, AddressingMode)
|
||||||
{
|
{
|
||||||
if (this->_registers.p.n)
|
if (this->_registers.p.n)
|
||||||
this->_registers.pac += static_cast<int8_t>(this->_bus->read(valueAddr));
|
this->_registers.pc += static_cast<int8_t>(this->_bus->read(valueAddr));
|
||||||
return this->_registers.p.n;
|
return this->_registers.p.n + this->_isEmulationMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CPU::BPL(uint24_t valueAddr)
|
int CPU::BPL(uint24_t valueAddr, AddressingMode)
|
||||||
{
|
{
|
||||||
if (!this->_registers.p.n)
|
if (!this->_registers.p.n)
|
||||||
this->_registers.pac += static_cast<int8_t>(this->_bus->read(valueAddr));
|
this->_registers.pc += static_cast<int8_t>(this->_bus->read(valueAddr));
|
||||||
return !this->_registers.p.n;
|
return !this->_registers.p.n + this->_isEmulationMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CPU::BRA(uint24_t valueAddr)
|
int CPU::BRA(uint24_t valueAddr, AddressingMode)
|
||||||
{
|
{
|
||||||
this->_registers.pac += static_cast<int8_t>(this->_bus->read(valueAddr));
|
this->_registers.pc += static_cast<int8_t>(this->_bus->read(valueAddr));
|
||||||
return true;
|
return this->_isEmulationMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CPU::BRL(uint24_t valueAddr)
|
int CPU::BRL(uint24_t valueAddr, AddressingMode)
|
||||||
{
|
{
|
||||||
unsigned value = this->_bus->read(valueAddr);
|
unsigned value = this->_bus->read(valueAddr);
|
||||||
value += this->_bus->read(valueAddr + 1) << 8u;
|
value += this->_bus->read(valueAddr + 1) << 8u;
|
||||||
|
|
||||||
this->_registers.pac += static_cast<int16_t>(value);
|
this->_registers.pc += static_cast<int16_t>(value);
|
||||||
return true;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CPU::BVC(uint24_t valueAddr)
|
int CPU::BVC(uint24_t valueAddr, AddressingMode)
|
||||||
{
|
{
|
||||||
if (!this->_registers.p.v)
|
if (!this->_registers.p.v)
|
||||||
this->_registers.pac += static_cast<int8_t>(this->_bus->read(valueAddr));
|
this->_registers.pc += static_cast<int8_t>(this->_bus->read(valueAddr));
|
||||||
return !this->_registers.p.v;
|
return !this->_registers.p.v + this->_isEmulationMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CPU::BVS(uint24_t valueAddr)
|
int CPU::BVS(uint24_t valueAddr, AddressingMode)
|
||||||
{
|
{
|
||||||
if (this->_registers.p.v)
|
if (this->_registers.p.v)
|
||||||
this->_registers.pac += static_cast<int8_t>(this->_bus->read(valueAddr));
|
this->_registers.pc += static_cast<int8_t>(this->_bus->read(valueAddr));
|
||||||
return this->_registers.p.v;
|
return this->_registers.p.v + this->_isEmulationMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::JMP(uint24_t value)
|
int CPU::JMP(uint24_t value, AddressingMode)
|
||||||
{
|
{
|
||||||
this->_registers.pc = value;
|
this->_registers.pc = value;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::JML(uint24_t value)
|
int CPU::JML(uint24_t value, AddressingMode)
|
||||||
{
|
{
|
||||||
this->_registers.pac = value;
|
this->_registers.pac = value;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CPU::NOP(uint24_t, AddressingMode)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
namespace ComSquare::CPU
|
namespace ComSquare::CPU
|
||||||
{
|
{
|
||||||
void CPU::RESB()
|
int CPU::RESB()
|
||||||
{
|
{
|
||||||
this->_registers.p.i = true;
|
this->_registers.p.i = true;
|
||||||
this->_registers.p.d = false;
|
this->_registers.p.d = false;
|
||||||
@@ -18,9 +18,10 @@ namespace ComSquare::CPU
|
|||||||
this->_registers.d = 0x0000;
|
this->_registers.d = 0x0000;
|
||||||
this->_registers.sh = 0x01; // the low bit of the stack pointer is undefined on reset.
|
this->_registers.sh = 0x01; // the low bit of the stack pointer is undefined on reset.
|
||||||
this->_registers.pc = this->_cartridgeHeader.emulationInterrupts.reset;
|
this->_registers.pc = this->_cartridgeHeader.emulationInterrupts.reset;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::BRK()
|
int CPU::BRK(uint24_t, AddressingMode)
|
||||||
{
|
{
|
||||||
if (this->_isEmulationMode) {
|
if (this->_isEmulationMode) {
|
||||||
this->_registers.pc += 2;
|
this->_registers.pc += 2;
|
||||||
@@ -30,7 +31,6 @@ namespace ComSquare::CPU
|
|||||||
this->_registers.p.i = true;
|
this->_registers.p.i = true;
|
||||||
this->_registers.p.d = false;
|
this->_registers.p.d = false;
|
||||||
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->_registers.pc += 2;
|
||||||
@@ -41,9 +41,10 @@ namespace ComSquare::CPU
|
|||||||
this->_registers.pbr = 0x0;
|
this->_registers.pbr = 0x0;
|
||||||
this->_registers.pc = this->_cartridgeHeader.nativeInterrupts.brk;
|
this->_registers.pc = this->_cartridgeHeader.nativeInterrupts.brk;
|
||||||
}
|
}
|
||||||
|
return !this->_isEmulationMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::COP()
|
int CPU::COP(uint24_t, AddressingMode)
|
||||||
{
|
{
|
||||||
if (this->_isEmulationMode) {
|
if (this->_isEmulationMode) {
|
||||||
this->_registers.pc += 2;
|
this->_registers.pc += 2;
|
||||||
@@ -63,14 +64,16 @@ namespace ComSquare::CPU
|
|||||||
this->_registers.pbr = 0x0;
|
this->_registers.pbr = 0x0;
|
||||||
this->_registers.pc = this->_cartridgeHeader.nativeInterrupts.cop;
|
this->_registers.pc = this->_cartridgeHeader.nativeInterrupts.cop;
|
||||||
}
|
}
|
||||||
|
return !this->_isEmulationMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::RTI()
|
int CPU::RTI(uint24_t, AddressingMode)
|
||||||
{
|
{
|
||||||
this->_registers.p.flags = this->_pop();
|
this->_registers.p.flags = this->_pop();
|
||||||
this->_registers.pc = this->_pop16();
|
this->_registers.pc = this->_pop16();
|
||||||
|
|
||||||
if (!this->_isEmulationMode)
|
if (!this->_isEmulationMode)
|
||||||
this->_registers.pbr = this->_pop16();
|
this->_registers.pbr = this->_pop16();
|
||||||
|
return !this->_isEmulationMode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
namespace ComSquare::CPU
|
namespace ComSquare::CPU
|
||||||
{
|
{
|
||||||
void CPU::ADC(uint24_t valueAddr)
|
int CPU::ADC(uint24_t valueAddr, AddressingMode mode)
|
||||||
{
|
{
|
||||||
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)
|
||||||
@@ -25,9 +25,31 @@ namespace ComSquare::CPU
|
|||||||
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;
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::SBC(uint24_t valueAddr)
|
int CPU::SBC(uint24_t valueAddr, AddressingMode mode)
|
||||||
{
|
{
|
||||||
unsigned negativeMask = this->_isEmulationMode ? 0x80u : 0x8000u;
|
unsigned negativeMask = this->_isEmulationMode ? 0x80u : 0x8000u;
|
||||||
unsigned value = this->_bus->read(valueAddr);
|
unsigned value = this->_bus->read(valueAddr);
|
||||||
@@ -45,5 +67,27 @@ namespace ComSquare::CPU
|
|||||||
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;
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
namespace ComSquare::CPU
|
namespace ComSquare::CPU
|
||||||
{
|
{
|
||||||
void CPU::STA(uint24_t addr)
|
int CPU::STA(uint24_t addr, AddressingMode mode)
|
||||||
{
|
{
|
||||||
if (this->_registers.p.m)
|
if (this->_registers.p.m)
|
||||||
this->_bus->write(addr, this->_registers.al);
|
this->_bus->write(addr, this->_registers.al);
|
||||||
@@ -14,9 +14,24 @@ namespace ComSquare::CPU
|
|||||||
this->_bus->write(addr, this->_registers.al);
|
this->_bus->write(addr, this->_registers.al);
|
||||||
this->_bus->write(addr + 1, this->_registers.ah);
|
this->_bus->write(addr + 1, this->_registers.ah);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int cycles = !this->_registers.p.m;
|
||||||
|
switch (mode) {
|
||||||
|
case DirectPage:
|
||||||
|
case DirectPageIndirect:
|
||||||
|
case DirectPageIndirectLong:
|
||||||
|
case DirectPageIndexedByX:
|
||||||
|
case DirectPageIndirectIndexedByX:
|
||||||
|
case DirectPageIndirectIndexedByY:
|
||||||
|
case DirectPageIndirectIndexedByYLong:
|
||||||
|
cycles += this->_registers.dl != 0;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return cycles;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::STX(uint24_t addr)
|
int CPU::STX(uint24_t addr, AddressingMode mode)
|
||||||
{
|
{
|
||||||
if (this->_registers.p.x_b)
|
if (this->_registers.p.x_b)
|
||||||
this->_bus->write(addr, this->_registers.xl);
|
this->_bus->write(addr, this->_registers.xl);
|
||||||
@@ -24,9 +39,10 @@ namespace ComSquare::CPU
|
|||||||
this->_bus->write(addr, this->_registers.xl);
|
this->_bus->write(addr, this->_registers.xl);
|
||||||
this->_bus->write(addr + 1, this->_registers.xh);
|
this->_bus->write(addr + 1, this->_registers.xh);
|
||||||
}
|
}
|
||||||
|
return !this->_registers.p.x_b + (mode != Absolute && this->_registers.dl != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::STY(uint24_t addr)
|
int CPU::STY(uint24_t addr, AddressingMode mode)
|
||||||
{
|
{
|
||||||
if (this->_registers.p.x_b)
|
if (this->_registers.p.x_b)
|
||||||
this->_bus->write(addr, this->_registers.yl);
|
this->_bus->write(addr, this->_registers.yl);
|
||||||
@@ -34,16 +50,20 @@ namespace ComSquare::CPU
|
|||||||
this->_bus->write(addr, this->_registers.yl);
|
this->_bus->write(addr, this->_registers.yl);
|
||||||
this->_bus->write(addr + 1, this->_registers.yh);
|
this->_bus->write(addr + 1, this->_registers.yh);
|
||||||
}
|
}
|
||||||
|
return !this->_registers.p.x_b + (mode != Absolute && this->_registers.dl != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::STZ(uint24_t addr)
|
int CPU::STZ(uint24_t addr, AddressingMode mode)
|
||||||
{
|
{
|
||||||
this->_bus->write(addr, 0x00);
|
this->_bus->write(addr, 0x00);
|
||||||
if (!this->_registers.p.m)
|
if (!this->_registers.p.m)
|
||||||
this->_bus->write(addr + 1, 0x00);
|
this->_bus->write(addr + 1, 0x00);
|
||||||
|
if (mode == Absolute || mode == AbsoluteIndexedByX)
|
||||||
|
return !this->_registers.p.m;
|
||||||
|
return !this->_registers.p.m + this->_registers.dl != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::LDA(uint24_t addr)
|
int CPU::LDA(uint24_t addr, AddressingMode mode)
|
||||||
{
|
{
|
||||||
if (this->_registers.p.m) {
|
if (this->_registers.p.m) {
|
||||||
this->_registers.a = this->_bus->read(addr);
|
this->_registers.a = this->_bus->read(addr);
|
||||||
@@ -54,9 +74,31 @@ namespace ComSquare::CPU
|
|||||||
this->_registers.p.n = this->_registers.a & 0xF000u;
|
this->_registers.p.n = this->_registers.a & 0xF000u;
|
||||||
}
|
}
|
||||||
this->_registers.p.z = this->_registers.a == 0x0;
|
this->_registers.p.z = this->_registers.a == 0x0;
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::LDX(uint24_t addr)
|
int CPU::LDX(uint24_t addr, AddressingMode mode)
|
||||||
{
|
{
|
||||||
if (this->_registers.p.x_b) {
|
if (this->_registers.p.x_b) {
|
||||||
this->_registers.x = this->_bus->read(addr);
|
this->_registers.x = this->_bus->read(addr);
|
||||||
@@ -67,9 +109,23 @@ namespace ComSquare::CPU
|
|||||||
this->_registers.p.n = this->_registers.x & 0xF000u;
|
this->_registers.p.n = this->_registers.x & 0xF000u;
|
||||||
}
|
}
|
||||||
this->_registers.p.z = this->_registers.x == 0x0;
|
this->_registers.p.z = this->_registers.x == 0x0;
|
||||||
|
|
||||||
|
int cycles = !this->_registers.p.x_b;
|
||||||
|
switch (mode) {
|
||||||
|
case DirectPage:
|
||||||
|
case DirectPageIndexedByY:
|
||||||
|
cycles += this->_registers.dl != 0;
|
||||||
|
break;
|
||||||
|
case AbsoluteIndexedByY:
|
||||||
|
cycles += this->_hasIndexCrossedPageBoundary;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return cycles;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::LDY(uint24_t addr)
|
int CPU::LDY(uint24_t addr, AddressingMode mode)
|
||||||
{
|
{
|
||||||
if (this->_registers.p.x_b) {
|
if (this->_registers.p.x_b) {
|
||||||
this->_registers.y = this->_bus->read(addr);
|
this->_registers.y = this->_bus->read(addr);
|
||||||
@@ -80,5 +136,19 @@ namespace ComSquare::CPU
|
|||||||
this->_registers.p.n = this->_registers.y & 0xF000u;
|
this->_registers.p.n = this->_registers.y & 0xF000u;
|
||||||
}
|
}
|
||||||
this->_registers.p.z = this->_registers.y == 0x0;
|
this->_registers.p.z = this->_registers.y == 0x0;
|
||||||
|
|
||||||
|
int cycles = !this->_registers.p.x_b;
|
||||||
|
switch (mode) {
|
||||||
|
case DirectPage:
|
||||||
|
case DirectPageIndexedByY:
|
||||||
|
cycles += this->_registers.dl != 0;
|
||||||
|
break;
|
||||||
|
case AbsoluteIndexedByY:
|
||||||
|
cycles += this->_hasIndexCrossedPageBoundary;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return cycles;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
namespace ComSquare::CPU
|
namespace ComSquare::CPU
|
||||||
{
|
{
|
||||||
void CPU::TAX()
|
int CPU::TAX(uint24_t, AddressingMode)
|
||||||
{
|
{
|
||||||
if (this->_registers.p.x_b) {
|
if (this->_registers.p.x_b) {
|
||||||
this->_registers.xl = this->_registers.al;
|
this->_registers.xl = this->_registers.al;
|
||||||
@@ -17,9 +17,10 @@ namespace ComSquare::CPU
|
|||||||
this->_registers.p.z = this->_registers.x == 0;
|
this->_registers.p.z = this->_registers.x == 0;
|
||||||
this->_registers.p.n = this->_registers.x & 0x8000u;
|
this->_registers.p.n = this->_registers.x & 0x8000u;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::TAY()
|
int CPU::TAY(uint24_t, AddressingMode)
|
||||||
{
|
{
|
||||||
if (this->_registers.p.x_b) {
|
if (this->_registers.p.x_b) {
|
||||||
this->_registers.yl = this->_registers.al;
|
this->_registers.yl = this->_registers.al;
|
||||||
@@ -30,9 +31,10 @@ namespace ComSquare::CPU
|
|||||||
this->_registers.p.z = this->_registers.y == 0;
|
this->_registers.p.z = this->_registers.y == 0;
|
||||||
this->_registers.p.n = this->_registers.y & 0x8000u;
|
this->_registers.p.n = this->_registers.y & 0x8000u;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::TXS()
|
int CPU::TXS(uint24_t, AddressingMode)
|
||||||
{
|
{
|
||||||
if (this->_registers.p.x_b) {
|
if (this->_registers.p.x_b) {
|
||||||
this->_registers.sh = 0;
|
this->_registers.sh = 0;
|
||||||
@@ -44,5 +46,6 @@ namespace ComSquare::CPU
|
|||||||
this->_registers.p.z = this->_registers.s == 0;
|
this->_registers.p.z = this->_registers.s == 0;
|
||||||
this->_registers.p.n = this->_registers.s & 0x8000u;
|
this->_registers.p.n = this->_registers.s & 0x8000u;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -15,7 +15,6 @@ namespace ComSquare::Cartridge
|
|||||||
Cartridge::Cartridge(const std::string &romPath)
|
Cartridge::Cartridge(const std::string &romPath)
|
||||||
: Ram::Ram(0, Rom, "Cartridge")
|
: Ram::Ram(0, Rom, "Cartridge")
|
||||||
{
|
{
|
||||||
try {
|
|
||||||
if (romPath.empty())
|
if (romPath.empty())
|
||||||
throw InvalidRomException("Path is empty.");
|
throw InvalidRomException("Path is empty.");
|
||||||
size_t size = Cartridge::getRomSize(romPath);
|
size_t size = Cartridge::getRomSize(romPath);
|
||||||
@@ -28,9 +27,6 @@ namespace ComSquare::Cartridge
|
|||||||
std::memset(this->_data, 0, size);
|
std::memset(this->_data, 0, size);
|
||||||
fread(this->_data, 1, size, rom);
|
fread(this->_data, 1, size, rom);
|
||||||
this->_loadHeader();
|
this->_loadHeader();
|
||||||
} catch (InvalidRomException &ex) {
|
|
||||||
std::cerr << "Invalid Rom Error: " << ex.what() << std::endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Cartridge::getRomSize(const std::string &romPath)
|
size_t Cartridge::getRomSize(const std::string &romPath)
|
||||||
|
|||||||
@@ -5,8 +5,6 @@
|
|||||||
#include "CGramDebug.hpp"
|
#include "CGramDebug.hpp"
|
||||||
#include "../SNES.hpp"
|
#include "../SNES.hpp"
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include <iostream>
|
|
||||||
#include <bitset>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "../Utility/Utility.hpp"
|
#include "../Utility/Utility.hpp"
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,11 @@
|
|||||||
#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 <QtEvents>
|
#include <QtEvents>
|
||||||
|
#include <QPainter>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
using namespace ComSquare::CPU;
|
using namespace ComSquare::CPU;
|
||||||
|
|
||||||
@@ -16,6 +19,8 @@ namespace ComSquare::Debugger
|
|||||||
: CPU(basicCPU),
|
: CPU(basicCPU),
|
||||||
_window(new ClosableWindow<CPUDebug>(*this, &CPUDebug::disableDebugger)),
|
_window(new ClosableWindow<CPUDebug>(*this, &CPUDebug::disableDebugger)),
|
||||||
_ui(),
|
_ui(),
|
||||||
|
_model(*this),
|
||||||
|
_painter(*this),
|
||||||
_snes(snes)
|
_snes(snes)
|
||||||
{
|
{
|
||||||
this->_window->setContextMenuPolicy(Qt::NoContextMenu);
|
this->_window->setContextMenuPolicy(Qt::NoContextMenu);
|
||||||
@@ -23,9 +28,20 @@ namespace ComSquare::Debugger
|
|||||||
this->_window->setAttribute(Qt::WA_DeleteOnClose);
|
this->_window->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
|
||||||
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->_ui.disassembly->setModel(&this->_model);
|
||||||
|
this->_ui.disassembly->horizontalHeader()->setStretchLastSection(true);
|
||||||
|
this->_ui.disassembly->resizeColumnsToContents();
|
||||||
|
this->_ui.disassembly->verticalHeader()->setSectionResizeMode (QHeaderView::Fixed);
|
||||||
|
this->_ui.disassembly->verticalHeader()->setHighlightSections(false);
|
||||||
|
this->_ui.disassembly->setItemDelegate(&this->_painter);
|
||||||
|
|
||||||
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.clear, &QPushButton::released, this, &CPUDebug::clearHistory);
|
QMainWindow::connect(this->_ui.clear, &QPushButton::released, this, &CPUDebug::clearHistory);
|
||||||
|
QMainWindow::connect(this->_ui.disassembly->verticalHeader(), &QHeaderView::sectionClicked, this, &CPUDebug::toggleBreakpoint);
|
||||||
this->_window->show();
|
this->_window->show();
|
||||||
this->_updateRegistersPanel();
|
this->_updateRegistersPanel();
|
||||||
}
|
}
|
||||||
@@ -43,25 +59,50 @@ namespace ComSquare::Debugger
|
|||||||
unsigned CPUDebug::update()
|
unsigned CPUDebug::update()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
unsigned cycles = 0;
|
||||||
|
|
||||||
if (this->_isPaused)
|
if (this->_isPaused)
|
||||||
return 0xFF;
|
return 0xFF;
|
||||||
if (this->_isStepping)
|
if (this->_isStepping) {
|
||||||
return this->_executeInstruction(this->_bus->read(this->_registers.pac++));
|
cycles = this->_executeInstruction(this->readPC());
|
||||||
return CPU::update();
|
this->_updateDisassembly();
|
||||||
|
return cycles;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 0xFF; i++) {
|
||||||
|
auto breakpoint = std::find_if(this->breakpoints.begin(), this->breakpoints.end(), [this](Breakpoint &brk) {
|
||||||
|
return brk.address == this->_registers.pac;
|
||||||
|
});
|
||||||
|
if (i != 0 && breakpoint != this->breakpoints.end()) {
|
||||||
|
if (breakpoint->oneTime)
|
||||||
|
this->breakpoints.erase(breakpoint);
|
||||||
|
this->_isPaused = false;
|
||||||
|
this->pause();
|
||||||
|
return cycles;
|
||||||
|
}
|
||||||
|
cycles += this->_executeInstruction(this->readPC());
|
||||||
|
}
|
||||||
|
return cycles;
|
||||||
} catch (InvalidOpcode &e) {
|
} catch (InvalidOpcode &e) {
|
||||||
if (!this->_isPaused)
|
if (!this->_isPaused)
|
||||||
this->pause();
|
this->pause();
|
||||||
|
std::cout << "Invalid Opcode: " << e.what() << std::endl;
|
||||||
return 0xFF;
|
return 0xFF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned CPUDebug::_executeInstruction(uint8_t opcode)
|
unsigned CPUDebug::_executeInstruction(uint8_t opcode)
|
||||||
{
|
{
|
||||||
|
if (this->_isPaused)
|
||||||
|
return 0;
|
||||||
if (this->_isStepping) {
|
if (this->_isStepping) {
|
||||||
this->_isStepping = false;
|
this->_isStepping = false;
|
||||||
this->_isPaused = true;
|
this->_isPaused = true;
|
||||||
}
|
}
|
||||||
this->_ui.logger->append((CPUDebug::_getInstructionString(this->_registers.pac - 1) + " - " + Utility::to_hex(opcode)).c_str());
|
uint24_t pc = (this->_registers.pbr << 16u) | (this->_registers.pc - 1u);
|
||||||
|
DisassemblyContext ctx = this->_getDisassemblyContext();
|
||||||
|
DisassembledInstruction instruction = this->_parseInstruction(pc, ctx);
|
||||||
|
this->_ui.logger->append((instruction.toString() + " - " + Utility::to_hex(opcode)).c_str());
|
||||||
unsigned ret = CPU::_executeInstruction(opcode);
|
unsigned ret = CPU::_executeInstruction(opcode);
|
||||||
this->_updateRegistersPanel();
|
this->_updateRegistersPanel();
|
||||||
return ret;
|
return ret;
|
||||||
@@ -74,6 +115,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();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPUDebug::step()
|
void CPUDebug::step()
|
||||||
@@ -82,6 +124,28 @@ namespace ComSquare::Debugger
|
|||||||
this->_isPaused = false;
|
this->_isPaused = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CPUDebug::next()
|
||||||
|
{
|
||||||
|
auto next = std::find_if(this->disassembledInstructions.begin(), this->disassembledInstructions.end(), [this](DisassembledInstruction &i) {
|
||||||
|
return i.address > this->_registers.pac;
|
||||||
|
});
|
||||||
|
this->breakpoints.push_back({next->address, true});
|
||||||
|
this->_isPaused = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPUDebug::toggleBreakpoint(int logicalIndex)
|
||||||
|
{
|
||||||
|
DisassembledInstruction instruction = this->disassembledInstructions[logicalIndex];
|
||||||
|
auto existing = std::find_if(this->breakpoints.begin(), this->breakpoints.end(), [instruction](Breakpoint &i) {
|
||||||
|
return i.address == instruction.address;
|
||||||
|
});
|
||||||
|
if (existing == this->breakpoints.end())
|
||||||
|
this->breakpoints.push_back({instruction.address, false});
|
||||||
|
else
|
||||||
|
this->breakpoints.erase(existing);
|
||||||
|
this->_ui.disassembly->viewport()->repaint();
|
||||||
|
}
|
||||||
|
|
||||||
void CPUDebug::_updateRegistersPanel()
|
void CPUDebug::_updateRegistersPanel()
|
||||||
{
|
{
|
||||||
if (!this->_registers.p.m)
|
if (!this->_registers.p.m)
|
||||||
@@ -126,49 +190,130 @@ namespace ComSquare::Debugger
|
|||||||
this->_ui.logger->clear();
|
this->_ui.logger->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CPUDebug::_getImmediateValueForA(uint24_t pc)
|
void CPUDebug::_updateDisassembly(uint24_t refreshSize)
|
||||||
|
{
|
||||||
|
auto first = std::find_if(this->disassembledInstructions.begin(), this->disassembledInstructions.end(), [this](DisassembledInstruction &i) {
|
||||||
|
return i.address >= this->_registers.pac;
|
||||||
|
});
|
||||||
|
auto end = std::find_if(this->disassembledInstructions.begin(), this->disassembledInstructions.end(),[this, refreshSize](DisassembledInstruction &i) {
|
||||||
|
return i.address >= this->_registers.pac + refreshSize;
|
||||||
|
});
|
||||||
|
this->disassembledInstructions.erase(first, end);
|
||||||
|
|
||||||
|
auto next = std::find_if(this->disassembledInstructions.begin(), this->disassembledInstructions.end(), [this](DisassembledInstruction &i) {
|
||||||
|
return i.address >= this->_registers.pac;
|
||||||
|
});
|
||||||
|
int row = next - this->disassembledInstructions.begin();
|
||||||
|
DisassemblyContext ctx = this->_getDisassemblyContext();
|
||||||
|
std::vector<DisassembledInstruction> nextInstructions = this->_disassemble(this->_registers.pac, refreshSize, ctx);
|
||||||
|
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);
|
||||||
|
this->_ui.disassembly->viewport()->repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
DisassemblyContext CPUDebug::_getDisassemblyContext()
|
||||||
|
{
|
||||||
|
return {this->_registers.p.m, this->_registers.p.x_b, false};
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
unsigned value = this->_bus->read(pc, true);
|
||||||
|
|
||||||
if (!this->_registers.p.m)
|
if (dual)
|
||||||
value += this->_bus->read(pc + 1, true) << 8u;
|
value += this->_bus->read(pc + 1, true) << 8u;
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "#$" << std::hex << value;
|
ss << "#$" << std::hex << value;
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CPUDebug::_getImmediateValueForX(uint24_t pc)
|
|
||||||
{
|
|
||||||
unsigned value = this->_bus->read(pc, true);
|
|
||||||
|
|
||||||
if (!this->_registers.p.x_b)
|
|
||||||
value += this->_bus->read(pc + 1, true) << 8u;
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << "#$" << std::hex << value;
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string CPUDebug::_getImmediateValue8Bits(uint24_t pc)
|
|
||||||
{
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << "#$" << std::hex << static_cast<int>(this->_bus->read(pc), true);
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string CPUDebug::_getImmediateValue16Bits(uint24_t pc)
|
|
||||||
{
|
|
||||||
unsigned value = this->_bus->read(pc, true);
|
|
||||||
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::string CPUDebug::_getDirectValue(uint24_t pc)
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "$" << std::hex << static_cast<int>(this->_bus->read(pc), true);
|
ss << "$" << std::hex << static_cast<int>(this->_bus->read(pc, true));
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,201 +344,101 @@ namespace ComSquare::Debugger
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CPUDebug::_getInstructionString(uint24_t pc)
|
int CPUDebug::RESB()
|
||||||
{
|
|
||||||
uint8_t opcode = this->_bus->read(pc++, true);
|
|
||||||
|
|
||||||
switch (opcode) {
|
|
||||||
case Instructions::BRK: return "BRK";
|
|
||||||
|
|
||||||
case Instructions::COP: return "COP";
|
|
||||||
|
|
||||||
case Instructions::RTI: return "RTI";
|
|
||||||
|
|
||||||
case Instructions::ADC_IM: return "ADC " + this->_getImmediateValueForA(pc);
|
|
||||||
case Instructions::ADC_ABS: return "ADC " + this->_getAbsoluteValue(pc);
|
|
||||||
case Instructions::ADC_ABSl: return "ADC " + this->_getAbsoluteLongValue(pc);
|
|
||||||
case Instructions::ADC_DP: return "ADC " + this->_getDirectValue(pc);
|
|
||||||
case Instructions::ADC_DPi: return "ADC";
|
|
||||||
case Instructions::ADC_DPil: return "ADC";
|
|
||||||
case Instructions::ADC_ABSX: return "ADC";
|
|
||||||
case Instructions::ADC_ABSXl:return "ADC";
|
|
||||||
case Instructions::ADC_ABSY: return "ADC";
|
|
||||||
case Instructions::ADC_DPX: return "ADC " + this->_getDirectIndexedByXValue(pc);
|
|
||||||
case Instructions::ADC_DPXi: return "ADC";
|
|
||||||
case Instructions::ADC_DPYi: return "ADC";
|
|
||||||
case Instructions::ADC_DPYil:return "ADC";
|
|
||||||
case Instructions::ADC_SR: return "ADC";
|
|
||||||
case Instructions::ADC_SRYi: return "ADC";
|
|
||||||
|
|
||||||
case Instructions::STA_ABS: return "STA " + this->_getAbsoluteValue(pc);
|
|
||||||
case Instructions::STA_ABSl: return "STA " + this->_getAbsoluteLongValue(pc);
|
|
||||||
case Instructions::STA_DP: return "STA " + this->_getDirectValue(pc);
|
|
||||||
case Instructions::STA_DPi: return "STA";
|
|
||||||
case Instructions::STA_DPil: return "STA";
|
|
||||||
case Instructions::STA_ABSX: return "STA";
|
|
||||||
case Instructions::STA_ABSXl:return "STA";
|
|
||||||
case Instructions::STA_ABSY: return "STA";
|
|
||||||
case Instructions::STA_DPX: return "STA " + this->_getDirectIndexedByXValue(pc);
|
|
||||||
case Instructions::STA_DPXi: return "STA";
|
|
||||||
case Instructions::STA_DPYi: return "STA";
|
|
||||||
case Instructions::STA_DPYil:return "STA";
|
|
||||||
case Instructions::STA_SR: return "STA";
|
|
||||||
case Instructions::STA_SRYi: return "STA";
|
|
||||||
|
|
||||||
case Instructions::STX_ABS: return "STX " + this->_getAbsoluteValue(pc);
|
|
||||||
case Instructions::STX_DP: return "STX " + this->_getDirectValue(pc);
|
|
||||||
case Instructions::STX_DPY: return "STX";
|
|
||||||
|
|
||||||
case Instructions::STY_ABS: return "STY " + this->_getAbsoluteValue(pc);
|
|
||||||
case Instructions::STY_DP: return "STY " + this->_getDirectValue(pc);
|
|
||||||
case Instructions::STY_DPX: return "STY " + this->_getDirectIndexedByXValue(pc);
|
|
||||||
|
|
||||||
case Instructions::STZ_ABS: return "STZ " + this->_getAbsoluteValue(pc);
|
|
||||||
case Instructions::STZ_DP: return "STZ " + this->_getDirectValue(pc);
|
|
||||||
case Instructions::STZ_ABSX: return "STZ";
|
|
||||||
case Instructions::STZ_DPX: return "STZ " + this->_getDirectIndexedByXValue(pc);
|
|
||||||
|
|
||||||
case Instructions::LDA_IM: return "LDA " + this->_getImmediateValueForA(pc);
|
|
||||||
case Instructions::LDA_ABS: return "LDA " + this->_getAbsoluteValue(pc);
|
|
||||||
case Instructions::LDA_ABSl: return "LDA " + this->_getAbsoluteLongValue(pc);
|
|
||||||
case Instructions::LDA_DP: return "LDA " + this->_getDirectValue(pc);
|
|
||||||
case Instructions::LDA_DPi: return "LDA";
|
|
||||||
case Instructions::LDA_DPil: return "LDA";
|
|
||||||
case Instructions::LDA_ABSX: return "LDA";
|
|
||||||
case Instructions::LDA_ABSXl:return "LDA";
|
|
||||||
case Instructions::LDA_ABSY: return "LDA";
|
|
||||||
case Instructions::LDA_DPX: return "LDA " + this->_getDirectIndexedByXValue(pc);
|
|
||||||
case Instructions::LDA_DPXi: return "LDA";
|
|
||||||
case Instructions::LDA_DPYi: return "LDA";
|
|
||||||
case Instructions::LDA_DPYil:return "LDA";
|
|
||||||
case Instructions::LDA_SR: return "LDA";
|
|
||||||
case Instructions::LDA_SRYi: return "LDA";
|
|
||||||
|
|
||||||
case Instructions::LDX_IM: return "LDX " + this->_getImmediateValueForX(pc);
|
|
||||||
case Instructions::LDX_ABS: return "LDX " + this->_getAbsoluteValue(pc);
|
|
||||||
case Instructions::LDX_DP: return "LDX " + this->_getDirectValue(pc);
|
|
||||||
case Instructions::LDX_ABSY: return "LDX";
|
|
||||||
case Instructions::LDX_DPY: return "LDX";
|
|
||||||
|
|
||||||
case Instructions::LDY_IM: return "LDY " + this->_getImmediateValueForX(pc);
|
|
||||||
case Instructions::LDY_ABS: return "LDY " + this->_getAbsoluteValue(pc);
|
|
||||||
case Instructions::LDY_DP: return "LDY " + this->_getDirectValue(pc);
|
|
||||||
case Instructions::LDY_ABSY: return "LDY";
|
|
||||||
case Instructions::LDY_DPY: return "LDY";
|
|
||||||
|
|
||||||
case Instructions::SEP: return "SEP " + this->_getImmediateValue8Bits(pc);
|
|
||||||
|
|
||||||
case Instructions::REP: return "REP " + this->_getImmediateValue8Bits(pc);
|
|
||||||
|
|
||||||
case Instructions::PHA: return "PHA";
|
|
||||||
case Instructions::PHB: return "PHB";
|
|
||||||
case Instructions::PHD: return "PHD";
|
|
||||||
case Instructions::PHK: return "PHK";
|
|
||||||
case Instructions::PHP: return "PHP";
|
|
||||||
case Instructions::PHX: return "PHX";
|
|
||||||
case Instructions::PHY: return "PHY";
|
|
||||||
|
|
||||||
case Instructions::PLA: return "PLA";
|
|
||||||
case Instructions::PLB: return "PLB";
|
|
||||||
case Instructions::PLD: return "PLD";
|
|
||||||
case Instructions::PLP: return "PLP";
|
|
||||||
case Instructions::PLX: return "PLX";
|
|
||||||
case Instructions::PLY: return "PLY";
|
|
||||||
|
|
||||||
case Instructions::JSR_ABS: return "JSR " + this->_getAbsoluteValue(pc);
|
|
||||||
case Instructions::JSR_ABSXi: return "JSR";
|
|
||||||
|
|
||||||
case Instructions::JSL: return "JSL " + this->_getAbsoluteLongValue(pc);
|
|
||||||
|
|
||||||
case Instructions::CLC: return "CLC";
|
|
||||||
case Instructions::CLI: return "CLI";
|
|
||||||
case Instructions::CLD: return "CLD";
|
|
||||||
case Instructions::CLV: return "CLV";
|
|
||||||
|
|
||||||
case Instructions::SEC: return "SEC";
|
|
||||||
case Instructions::SED: return "SED";
|
|
||||||
case Instructions::SEI: return "SEI";
|
|
||||||
|
|
||||||
case Instructions::AND_IM: return "AND " + this->_getImmediateValueForA(pc);
|
|
||||||
case Instructions::AND_ABS: return "AND " + this->_getAbsoluteValue(pc);
|
|
||||||
case Instructions::AND_ABSl: return "AND " + this->_getAbsoluteLongValue(pc);
|
|
||||||
case Instructions::AND_DP: return "AND " + this->_getDirectValue(pc);
|
|
||||||
case Instructions::AND_DPi: return "AND";
|
|
||||||
case Instructions::AND_DPil: return "AND";
|
|
||||||
case Instructions::AND_ABSX: return "AND";
|
|
||||||
case Instructions::AND_ABSXl:return "AND";
|
|
||||||
case Instructions::AND_ABSY: return "AND";
|
|
||||||
case Instructions::AND_DPX: return "AND " + this->_getDirectIndexedByXValue(pc);
|
|
||||||
case Instructions::AND_DPXi: return "AND";
|
|
||||||
case Instructions::AND_DPYi: return "AND";
|
|
||||||
case Instructions::AND_DPYil:return "AND";
|
|
||||||
case Instructions::AND_SR: return "AND";
|
|
||||||
case Instructions::AND_SRYi: return "AND";
|
|
||||||
|
|
||||||
case Instructions::XCE: return "XCE";
|
|
||||||
|
|
||||||
case Instructions::SBC_IM: return "SBC " + this->_getImmediateValueForA(pc);
|
|
||||||
case Instructions::SBC_ABS: return "SBC " + this->_getAbsoluteValue(pc);
|
|
||||||
case Instructions::SBC_ABSl: return "SBC " + this->_getAbsoluteLongValue(pc);
|
|
||||||
case Instructions::SBC_DP: return "SBC " + this->_getDirectValue(pc);
|
|
||||||
case Instructions::SBC_DPi: return "SBC";
|
|
||||||
case Instructions::SBC_DPil: return "SBC";
|
|
||||||
case Instructions::SBC_ABSX: return "SBC";
|
|
||||||
case Instructions::SBC_ABSXl:return "SBC";
|
|
||||||
case Instructions::SBC_ABSY: return "SBC";
|
|
||||||
case Instructions::SBC_DPX: return "SBC " + this->_getDirectIndexedByXValue(pc);
|
|
||||||
case Instructions::SBC_DPXi: return "SBC";
|
|
||||||
case Instructions::SBC_DPYi: return "SBC";
|
|
||||||
case Instructions::SBC_DPYil:return "SBC";
|
|
||||||
case Instructions::SBC_SR: return "SBC";
|
|
||||||
case Instructions::SBC_SRYi: return "SBC";
|
|
||||||
|
|
||||||
case Instructions::TAX: return "TAX";
|
|
||||||
case Instructions::TAY: return "TAY";
|
|
||||||
case Instructions::TXS: return "TXS";
|
|
||||||
|
|
||||||
case Instructions::INX: return "INX";
|
|
||||||
case Instructions::INY: return "INY";
|
|
||||||
|
|
||||||
case Instructions::CPX_IM: return "CPX " + this->_getImmediateValueForX(pc);
|
|
||||||
case Instructions::CPX_ABS: return "CPX " + this->_getAbsoluteValue(pc);
|
|
||||||
case Instructions::CPX_DP: return "CPX";
|
|
||||||
|
|
||||||
case Instructions::CPY_IM: return "CPY " + this->_getImmediateValueForX(pc);
|
|
||||||
case Instructions::CPY_ABS: return "CPY " + this->_getAbsoluteValue(pc);
|
|
||||||
case Instructions::CPY_DP: return "CPY";
|
|
||||||
|
|
||||||
case Instructions::BCC: return "BCC " + this->_getImmediateValue8Bits(pc);
|
|
||||||
case Instructions::BCS: return "BCS " + this->_getImmediateValue8Bits(pc);
|
|
||||||
case Instructions::BEQ: return "BEQ " + this->_getImmediateValue8Bits(pc);
|
|
||||||
case Instructions::BNE: return "BNE " + this->_getImmediateValue8Bits(pc);
|
|
||||||
case Instructions::BMI: return "BMI " + this->_getImmediateValue8Bits(pc);
|
|
||||||
case Instructions::BPL: return "BPL " + this->_getImmediateValue8Bits(pc);
|
|
||||||
case Instructions::BVC: return "BVC " + this->_getImmediateValue8Bits(pc);
|
|
||||||
case Instructions::BVS: return "BVS " + this->_getImmediateValue8Bits(pc);
|
|
||||||
case Instructions::BRA: return "BRA " + this->_getImmediateValue8Bits(pc);
|
|
||||||
case Instructions::BRL: return "BRL " + this->_getImmediateValue16Bits(pc);
|
|
||||||
|
|
||||||
case Instructions::JMP_ABS: return "JMP " + this->_getAbsoluteValue(pc);
|
|
||||||
case Instructions::JMP_ABSi: return "JMP "; //+ this->_getAbsoluteIndire(pc);
|
|
||||||
case Instructions::JMP_ABSXi: return "JMP "; //+ this->_getAbsoluteValue(pc);
|
|
||||||
|
|
||||||
case Instructions::JML_ABSl: return "JML";
|
|
||||||
case Instructions::JML_ABSil: return "JML";
|
|
||||||
|
|
||||||
default: return "Unknown";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CPUDebug::RESB()
|
|
||||||
{
|
{
|
||||||
CPU::RESB();
|
CPU::RESB();
|
||||||
this->_updateRegistersPanel();
|
this->_updateRegistersPanel();
|
||||||
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPUDebug::focus()
|
void CPUDebug::focus()
|
||||||
{
|
{
|
||||||
this->_window->activateWindow();
|
this->_window->activateWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint24_t CPUDebug::getPC()
|
||||||
|
{
|
||||||
|
return this->_registers.pac;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {}
|
||||||
|
|
||||||
|
std::string DisassembledInstruction::toString()
|
||||||
|
{
|
||||||
|
return this->name + " " + this->argument;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DisassemblyModel::DisassemblyModel(ComSquare::Debugger::CPUDebug &cpu) : QAbstractTableModel(), _cpu(cpu){ }
|
||||||
|
|
||||||
|
int DisassemblyModel::columnCount(const QModelIndex &) const
|
||||||
|
{
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DisassemblyModel::rowCount(const QModelIndex &) const
|
||||||
|
{
|
||||||
|
return this->_cpu.disassembledInstructions.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
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()];
|
||||||
|
if (role == Qt::DecorationRole) {
|
||||||
|
if (index.column() == 3 && instruction.level == ComSquare::Debugger::TrustLevel::Unsafe)
|
||||||
|
return QColor(Qt::yellow);
|
||||||
|
if (index.column() == 3 && instruction.level == ComSquare::Debugger::TrustLevel::Compromised)
|
||||||
|
return QColor(Qt::red);
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
switch (index.column()) {
|
||||||
|
case 0:
|
||||||
|
return QString(instruction.name.c_str());
|
||||||
|
case 1:
|
||||||
|
return QString(instruction.argument.c_str());
|
||||||
|
default:
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant DisassemblyModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
|
{
|
||||||
|
if (orientation == Qt::Horizontal)
|
||||||
|
return QVariant();
|
||||||
|
if (role != Qt::DisplayRole)
|
||||||
|
return QVariant();
|
||||||
|
ComSquare::Debugger::DisassembledInstruction instruction = this->_cpu.disassembledInstructions[section];
|
||||||
|
return QString(ComSquare::Utility::to_hex(instruction.address, ComSquare::Utility::HexString::NoPrefix).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
RowPainter::RowPainter(ComSquare::Debugger::CPUDebug &cpu, QObject *parent) : QStyledItemDelegate(parent), _cpu(cpu) { }
|
||||||
|
|
||||||
|
void RowPainter::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
ComSquare::Debugger::DisassembledInstruction instruction = this->_cpu.disassembledInstructions[index.row()];
|
||||||
|
bool isBreakpoint = false;
|
||||||
|
|
||||||
|
auto breakpoint = std::find_if(this->_cpu.breakpoints.begin(), this->_cpu.breakpoints.end(), [instruction](ComSquare::Debugger::Breakpoint brk) {
|
||||||
|
return brk.address == instruction.address;
|
||||||
|
});
|
||||||
|
if (breakpoint != this->_cpu.breakpoints.end())
|
||||||
|
isBreakpoint = true;
|
||||||
|
|
||||||
|
QStyleOptionViewItem style = option;
|
||||||
|
if (instruction.address == this->_cpu.getPC()) {
|
||||||
|
painter->fillRect(option.rect, QColor(Qt::darkGreen));
|
||||||
|
style.state &= ~QStyle::State_Selected;
|
||||||
|
} else if (isBreakpoint && !breakpoint->oneTime) {
|
||||||
|
painter->fillRect(option.rect,QColor(Qt::darkRed));
|
||||||
|
style.state &= ~QStyle::State_Selected;
|
||||||
|
}
|
||||||
|
QStyledItemDelegate::paint(painter, style, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize RowPainter::sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const
|
||||||
|
{
|
||||||
|
return QSize();
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
#ifndef COMSQUARE_CPUDEBUG_HPP
|
#ifndef COMSQUARE_CPUDEBUG_HPP
|
||||||
#define COMSQUARE_CPUDEBUG_HPP
|
#define COMSQUARE_CPUDEBUG_HPP
|
||||||
|
|
||||||
|
#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"
|
||||||
@@ -13,6 +14,95 @@
|
|||||||
|
|
||||||
namespace ComSquare::Debugger
|
namespace ComSquare::Debugger
|
||||||
{
|
{
|
||||||
|
class CPUDebug;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! @brief The qt model that show the disassembly.
|
||||||
|
class DisassemblyModel : public QAbstractTableModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
ComSquare::Debugger::CPUDebug &_cpu;
|
||||||
|
public:
|
||||||
|
explicit DisassemblyModel(ComSquare::Debugger::CPUDebug &cpu);
|
||||||
|
DisassemblyModel(const DisassemblyModel &) = delete;
|
||||||
|
const DisassemblyModel &operator=(const DisassemblyModel &) = delete;
|
||||||
|
~DisassemblyModel() 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 class that highlight breakpoints and the PC's position
|
||||||
|
class RowPainter : public QStyledItemDelegate {
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
//! @brief The CPU to get PC and breakpoints from.
|
||||||
|
ComSquare::Debugger::CPUDebug &_cpu;
|
||||||
|
public:
|
||||||
|
explicit RowPainter(ComSquare::Debugger::CPUDebug &cpu, QObject *parent = nullptr);
|
||||||
|
RowPainter &operator=(const RowPainter &) = delete;
|
||||||
|
~RowPainter() override = default;
|
||||||
|
protected:
|
||||||
|
QSize sizeHint(const QStyleOptionViewItem &options, const QModelIndex &index) const override;
|
||||||
|
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace ComSquare::Debugger
|
||||||
|
{
|
||||||
|
enum TrustLevel {
|
||||||
|
Safe,
|
||||||
|
Unsafe,
|
||||||
|
Compromised
|
||||||
|
};
|
||||||
|
|
||||||
|
//! @brief Struct used to emulate the state of the processor during the disassembly since instructions take a different amount of space depending on some flags.
|
||||||
|
struct DisassemblyContext {
|
||||||
|
//! @brief The accumulator and Memory width flag (in native mode only) - 0 = 16 bits mode, 1 = 8 bits mode.
|
||||||
|
//! @info If this flag is set to false, instructions that have the ImmediateByA addressing mode take 1 more bit of space.
|
||||||
|
bool mFlag = true;
|
||||||
|
//! @brief The indeX register width flag (in native mode only) - 0 = 16 bits mode, 1 = 8 bits mode OR the Break flag (in emulation mode only)
|
||||||
|
//! @info If this flag is set to false, instructions that have the ImmediateByX addressing mode take 1 more bit of space.
|
||||||
|
bool xFlag = true;
|
||||||
|
//! @brief Is the CPU emulating a 6502? If yes, some instructions don't change flags the same way.
|
||||||
|
bool isEmulationMode = true;
|
||||||
|
//! @brief Sometimes, the flags can't be tracked correctly after an instruction so the next instructions may not be correctly disassembled.
|
||||||
|
TrustLevel level = Safe;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! @brief Struct representing an instruction in an human readable way (created by disassembling the rom).
|
||||||
|
struct DisassembledInstruction : public CPU::Instruction {
|
||||||
|
//! @brief The address of the instruction
|
||||||
|
uint24_t address;
|
||||||
|
//! @brief A string representing the argument with the right addressing mode.
|
||||||
|
std::string argument;
|
||||||
|
//! @brief The opcode of the instruction
|
||||||
|
uint8_t opcode;
|
||||||
|
//! @brief Are we sure that this instruction has been correctly disassembled?
|
||||||
|
TrustLevel level;
|
||||||
|
|
||||||
|
DisassembledInstruction(const CPU::Instruction &instruction, uint24_t address, std::string argument, uint8_t opcode);
|
||||||
|
DisassembledInstruction(const DisassembledInstruction &) = default;
|
||||||
|
DisassembledInstruction &operator=(const DisassembledInstruction &) = default;
|
||||||
|
~DisassembledInstruction() = default;
|
||||||
|
|
||||||
|
std::string toString();
|
||||||
|
};
|
||||||
|
|
||||||
|
//! @brief Struct representing a breakpoint set by the user or by the app
|
||||||
|
struct Breakpoint {
|
||||||
|
//! @brief The address of the breakpoint
|
||||||
|
uint24_t address;
|
||||||
|
//! @brief If this is true, the breakpoint will be deleted on first hit and won't be shown on the disassembly view.
|
||||||
|
bool oneTime;
|
||||||
|
};
|
||||||
|
|
||||||
//! @brief A custom CPU with a window that show it's registers and the disassembly.
|
//! @brief A custom CPU with a window that show it's registers and the disassembly.
|
||||||
class CPUDebug : public CPU::CPU, public QObject {
|
class CPUDebug : public CPU::CPU, public QObject {
|
||||||
private:
|
private:
|
||||||
@@ -20,6 +110,10 @@ namespace ComSquare::Debugger
|
|||||||
ClosableWindow<CPUDebug> *_window;
|
ClosableWindow<CPUDebug> *_window;
|
||||||
//! @brief A widget that contain the whole UI.
|
//! @brief A widget that contain the whole UI.
|
||||||
Ui::CPUView _ui;
|
Ui::CPUView _ui;
|
||||||
|
//! @brief The disassembly viewer's model.
|
||||||
|
DisassemblyModel _model;
|
||||||
|
//! @brief A custom painter that highlight breakpoints and the PC's position.
|
||||||
|
RowPainter _painter;
|
||||||
//! @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.
|
||||||
@@ -28,21 +122,25 @@ namespace ComSquare::Debugger
|
|||||||
SNES &_snes;
|
SNES &_snes;
|
||||||
//! @brief Reimplement the basic instruction execution method to log instructions inside the logger view.
|
//! @brief Reimplement the basic instruction execution method to log instructions inside the logger view.
|
||||||
unsigned _executeInstruction(uint8_t opcode) override;
|
unsigned _executeInstruction(uint8_t opcode) override;
|
||||||
//! @brief Get a printable string representing an instruction at the program counter given as parameter.
|
//! @brief Return a disassembly context representing the current state of the processor.
|
||||||
std::string _getInstructionString(uint24_t pc);
|
DisassemblyContext _getDisassemblyContext();
|
||||||
|
//! @brief Disassemble part of the memory (using the bus) and parse it to a map of address and disassembled instruction.
|
||||||
|
//! @param ctx The initial context of the processor before the disassembly begin.
|
||||||
|
std::vector<DisassembledInstruction> _disassemble(uint24_t startAddr, uint24_t size, DisassemblyContext &ctx);
|
||||||
|
//! @brief Update disassembly with the new state of the processor.
|
||||||
|
void _updateDisassembly(uint24_t refreshSize = 0xFF);
|
||||||
|
//! @brief Parse the instruction at the program counter given to have human readable information.
|
||||||
|
DisassembledInstruction _parseInstruction(uint24_t pc, DisassemblyContext &ctx);
|
||||||
|
//! @brief Get the parameter of the instruction as an hexadecimal string.
|
||||||
|
std::string _getInstructionParameter(ComSquare::CPU::Instruction &instruction, uint24_t pc, DisassemblyContext &ctx);
|
||||||
//! @brief Get a printable string representing the flags.
|
//! @brief Get a printable string representing the flags.
|
||||||
std::string _getFlagsString();
|
std::string _getFlagsString();
|
||||||
//! @brief Update the register's panel (accumulator, stack pointer...)
|
//! @brief Update the register's panel (accumulator, stack pointer...)
|
||||||
void _updateRegistersPanel();
|
void _updateRegistersPanel();
|
||||||
|
|
||||||
//! @brief Return a printable string corresponding to the value of an immediate addressing mode for a.
|
//! @brief Return a printable string corresponding to the value of a 8 or 16 bits immediate addressing mode.
|
||||||
std::string _getImmediateValueForA(uint24_t pc);
|
//! @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).
|
||||||
//! @brief Return a printable string corresponding to the value of an immediate addressing mode for x.
|
std::string _getImmediateValue(uint24_t pc, bool dual);
|
||||||
std::string _getImmediateValueForX(uint24_t pc);
|
|
||||||
//! @brief Return a printable string corresponding to the value of a 8bits immediate addressing mode (used only with SEP and REP).
|
|
||||||
std::string _getImmediateValue8Bits(uint24_t pc);
|
|
||||||
//! @brief Return a printable string corresponding to the value of a 16bits immediate addressing mode.
|
|
||||||
std::string _getImmediateValue16Bits(uint24_t pc);
|
|
||||||
//! @brief Return a printable string corresponding to the value of a direct addressing mode.
|
//! @brief Return a printable string corresponding to the value of a direct addressing mode.
|
||||||
std::string _getDirectValue(uint24_t pc);
|
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.
|
||||||
@@ -52,18 +150,27 @@ namespace ComSquare::Debugger
|
|||||||
//! @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);
|
||||||
|
|
||||||
public slots:
|
public:
|
||||||
//! @brief Pause/Resume the CPU.
|
//! @brief Pause/Resume the CPU.
|
||||||
void pause();
|
void pause();
|
||||||
//! @brief Step - Execute a single instruction.
|
//! @brief Step - Execute a single instruction.
|
||||||
void step();
|
void step();
|
||||||
|
//! @brief Next - Continue running instructions until the next line is reached.
|
||||||
|
void next();
|
||||||
//! @brief Clear the history panel.
|
//! @brief Clear the history panel.
|
||||||
void clearHistory();
|
void clearHistory();
|
||||||
|
//! @brief Called when the user clicks on a section header. It enable/disable a breakpoint for this address.
|
||||||
|
void toggleBreakpoint(int logicalIndex);
|
||||||
//! @brief Called when the window is closed. Turn off the debugger and revert to a basic CPU.
|
//! @brief Called when the window is closed. Turn off the debugger and revert to a basic CPU.
|
||||||
void disableDebugger();
|
void disableDebugger();
|
||||||
public:
|
//! @brief The list of disassembled instructions to show on the debugger.
|
||||||
//! @brief Update the UI when reseting the CPU.
|
std::vector<DisassembledInstruction> disassembledInstructions;
|
||||||
void RESB() override;
|
//! @brief The list of breakpoints the user has set.
|
||||||
|
std::vector<Breakpoint> breakpoints;
|
||||||
|
//! @brief Return the current program counter of this CPU.
|
||||||
|
uint24_t getPC();
|
||||||
|
//! @brief Update the UI when resetting the CPU.
|
||||||
|
int RESB() override;
|
||||||
//! @brief Convert a basic CPU to a debugging CPU.
|
//! @brief Convert a basic CPU to a debugging CPU.
|
||||||
explicit CPUDebug(ComSquare::CPU::CPU &cpu, SNES &snes);
|
explicit CPUDebug(ComSquare::CPU::CPU &cpu, SNES &snes);
|
||||||
CPUDebug(const CPUDebug &) = delete;
|
CPUDebug(const CPUDebug &) = delete;
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ namespace ComSquare::Debugger
|
|||||||
this->_ui.setupUi(this->_window);
|
this->_ui.setupUi(this->_window);
|
||||||
this->_proxy.setSourceModel(&this->_model);
|
this->_proxy.setSourceModel(&this->_model);
|
||||||
this->_ui.log->setModel(&this->_proxy);
|
this->_ui.log->setModel(&this->_proxy);
|
||||||
|
this->_ui.log->setAlternatingRowColors(true);
|
||||||
|
this->_ui.log->verticalHeader()->hide();
|
||||||
this->_ui.log->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
|
this->_ui.log->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
|
||||||
this->_ui.log->horizontalHeader()->setStretchLastSection(true);
|
this->_ui.log->horizontalHeader()->setStretchLastSection(true);
|
||||||
this->_ui.log->horizontalHeader()->setSectionsMovable(true);
|
this->_ui.log->horizontalHeader()->setSectionsMovable(true);
|
||||||
|
|||||||
15
sources/Exceptions/DebuggableError.hpp
Normal file
15
sources/Exceptions/DebuggableError.hpp
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
//
|
||||||
|
// Created by anonymus-raccoon on 3/26/20.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COMSQUARE_DEBUGGABLEERROR_HPP
|
||||||
|
#define COMSQUARE_DEBUGGABLEERROR_HPP
|
||||||
|
|
||||||
|
#include <bits/exception.h>
|
||||||
|
|
||||||
|
namespace ComSquare
|
||||||
|
{
|
||||||
|
class DebuggableError : public std::exception {};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //COMSQUARE_DEBUGGABLEERROR_HPP
|
||||||
@@ -7,11 +7,12 @@
|
|||||||
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include "DebuggableError.hpp"
|
||||||
|
|
||||||
namespace ComSquare
|
namespace ComSquare
|
||||||
{
|
{
|
||||||
//! @brief Exception thrown when someone tries to load an invalid rom.
|
//! @brief Exception thrown when someone tries to load an invalid rom.
|
||||||
class InvalidAction : public std::exception {
|
class InvalidAction : public DebuggableError {
|
||||||
private:
|
private:
|
||||||
std::string _msg;
|
std::string _msg;
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -9,11 +9,12 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <ios>
|
#include <ios>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include "DebuggableError.hpp"
|
||||||
|
|
||||||
namespace ComSquare
|
namespace ComSquare
|
||||||
{
|
{
|
||||||
//! @brief Exception thrown when trying to read/write to an invalid address.
|
//! @brief Exception thrown when trying to read/write to an invalid address.
|
||||||
class InvalidAddress : public std::exception {
|
class InvalidAddress : public DebuggableError {
|
||||||
private:
|
private:
|
||||||
std::string _msg;
|
std::string _msg;
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -8,11 +8,12 @@
|
|||||||
#include <exception>
|
#include <exception>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include "DebuggableError.hpp"
|
||||||
|
|
||||||
namespace ComSquare
|
namespace ComSquare
|
||||||
{
|
{
|
||||||
//! @brief Exception thrown when someone tries to load an invalid rom.
|
//! @brief Exception thrown when someone tries to load an invalid rom.
|
||||||
class InvalidOpcode : public std::exception {
|
class InvalidOpcode : public DebuggableError {
|
||||||
private:
|
private:
|
||||||
std::string _msg;
|
std::string _msg;
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -7,11 +7,12 @@
|
|||||||
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include "DebuggableError.hpp"
|
||||||
|
|
||||||
namespace ComSquare
|
namespace ComSquare
|
||||||
{
|
{
|
||||||
//! @brief Exception thrown when someone tries to load an invalid rom.
|
//! @brief Exception thrown when someone tries to load an invalid rom.
|
||||||
class InvalidRomException : public std::exception {
|
class InvalidRomException : public DebuggableError {
|
||||||
private:
|
private:
|
||||||
std::string _msg;
|
std::string _msg;
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -8,6 +8,9 @@
|
|||||||
#include <QMenuBar>
|
#include <QMenuBar>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "QtSFML.hpp"
|
#include "QtSFML.hpp"
|
||||||
|
#include "../../Exceptions/InvalidOpcode.hpp"
|
||||||
|
#include "../../Exceptions/InvalidAddress.hpp"
|
||||||
|
#include "../../Exceptions/InvalidAction.hpp"
|
||||||
|
|
||||||
#ifdef Q_WS_X11
|
#ifdef Q_WS_X11
|
||||||
#include <Qt/qx11info_x11.h>
|
#include <Qt/qx11info_x11.h>
|
||||||
@@ -88,6 +91,9 @@ namespace ComSquare::Renderer
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
this->_snes.update();
|
this->_snes.update();
|
||||||
|
} catch (DebuggableError &e) {
|
||||||
|
std::cout << "Invalid rom's instruction: " << e.what() << std::endl;
|
||||||
|
this->_snes.enableCPUDebugging(true);
|
||||||
} catch (std::exception &e) {
|
} catch (std::exception &e) {
|
||||||
std::cerr << "An error occurred: " << e.what() << std::endl;
|
std::cerr << "An error occurred: " << e.what() << std::endl;
|
||||||
QApplication::quit();
|
QApplication::quit();
|
||||||
|
|||||||
@@ -35,15 +35,19 @@ namespace ComSquare
|
|||||||
this->apu->update(cycleCount);
|
this->apu->update(cycleCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SNES::enableCPUDebugging()
|
void SNES::enableCPUDebugging(bool pause)
|
||||||
{
|
{
|
||||||
#ifdef DEBUGGER_ENABLED
|
#ifdef DEBUGGER_ENABLED
|
||||||
if (this->cpu->isDebugger())
|
if (this->cpu->isDebugger()) {
|
||||||
std::static_pointer_cast<Debugger::CPUDebug>(this->cpu)->focus();
|
auto cpuDebug = std::static_pointer_cast<Debugger::CPUDebug>(this->cpu);
|
||||||
else
|
cpuDebug->focus();
|
||||||
|
if (pause)
|
||||||
|
cpuDebug->pause();
|
||||||
|
} else
|
||||||
this->cpu = std::make_shared<Debugger::CPUDebug>(*this->cpu, *this);
|
this->cpu = std::make_shared<Debugger::CPUDebug>(*this->cpu, *this);
|
||||||
#else
|
#else
|
||||||
std::cerr << "Debugging features are not enabled. You can't enable the debugger." << std::endl;
|
std::cerr << "Debugging features are not enabled. You can't enable the debugger." << std::endl;
|
||||||
|
(void)pause;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ namespace ComSquare
|
|||||||
//! @brief Disable the CPU's debugging window.
|
//! @brief Disable the CPU's debugging window.
|
||||||
void disableCPUDebugging();
|
void disableCPUDebugging();
|
||||||
//! @brief Enable the CPU's debugging window.
|
//! @brief Enable the CPU's debugging window.
|
||||||
void enableCPUDebugging();
|
void enableCPUDebugging(bool pause = false);
|
||||||
//! @brief Disable the Ram's debugging window.
|
//! @brief Disable the Ram's debugging window.
|
||||||
void disableRamViewer();
|
void disableRamViewer();
|
||||||
//! @brief Enable the Ram's debugging window.
|
//! @brief Enable the Ram's debugging window.
|
||||||
|
|||||||
@@ -3,29 +3,42 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <bitset>
|
#include <bitset>
|
||||||
|
#include <iomanip>
|
||||||
#include "Utility.hpp"
|
#include "Utility.hpp"
|
||||||
|
|
||||||
namespace ComSquare::Utility
|
namespace ComSquare::Utility
|
||||||
{
|
{
|
||||||
std::string to_hex(uint8_t i)
|
std::string to_hex(uint8_t i, HexString prefix)
|
||||||
{
|
{
|
||||||
char buf[5];
|
std::stringstream ss;
|
||||||
sprintf(buf, "0x%02X", i);
|
if (prefix == AsmPrefix)
|
||||||
return buf;
|
ss << "$";
|
||||||
|
else if (prefix == StandardPrefix)
|
||||||
|
ss << "0x";
|
||||||
|
ss << std::hex << std::setfill('0') << std::setw(2) << static_cast<unsigned>(i);
|
||||||
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_hex(uint16_t i)
|
std::string to_hex(uint16_t i, HexString prefix)
|
||||||
{
|
{
|
||||||
char buf[7];
|
std::stringstream ss;
|
||||||
sprintf(buf, "0x%04X", i);
|
if (prefix == AsmPrefix)
|
||||||
return buf;
|
ss << "$";
|
||||||
|
else if (prefix == StandardPrefix)
|
||||||
|
ss << "0x";
|
||||||
|
ss << std::hex << std::setfill('0') << std::setw(4) << i;
|
||||||
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_hex(uint24_t i)
|
std::string to_hex(uint24_t i, HexString prefix)
|
||||||
{
|
{
|
||||||
char buf[9];
|
std::stringstream ss;
|
||||||
sprintf(buf, "0x%06X", i);
|
if (prefix == AsmPrefix)
|
||||||
return buf;
|
ss << "$";
|
||||||
|
else if (prefix == StandardPrefix)
|
||||||
|
ss << "0x";
|
||||||
|
ss << std::hex << std::setfill('0') << std::setw(6) << i;
|
||||||
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_binary(uint8_t i)
|
std::string to_binary(uint8_t i)
|
||||||
|
|||||||
@@ -12,11 +12,17 @@
|
|||||||
|
|
||||||
namespace ComSquare::Utility
|
namespace ComSquare::Utility
|
||||||
{
|
{
|
||||||
std::string to_hex(uint8_t i);
|
enum HexString {
|
||||||
|
NoPrefix,
|
||||||
|
AsmPrefix,
|
||||||
|
StandardPrefix
|
||||||
|
};
|
||||||
|
|
||||||
std::string to_hex(uint16_t i);
|
std::string to_hex(uint8_t i, HexString prefix = StandardPrefix);
|
||||||
|
|
||||||
std::string to_hex(uint24_t i);
|
std::string to_hex(uint16_t i, HexString prefix = StandardPrefix);
|
||||||
|
|
||||||
|
std::string to_hex(uint24_t i, HexString prefix = StandardPrefix);
|
||||||
|
|
||||||
std::string to_binary(uint8_t i);
|
std::string to_binary(uint8_t i);
|
||||||
|
|
||||||
|
|||||||
@@ -77,8 +77,14 @@ int main(int argc, char **argv)
|
|||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
QApplication::setAttribute(Qt::AA_DisableWindowContextHelpButton);
|
QApplication::setAttribute(Qt::AA_DisableWindowContextHelpButton);
|
||||||
Renderer::QtSFML renderer(600, 800);
|
Renderer::QtSFML renderer(600, 800);
|
||||||
|
try {
|
||||||
SNES snes(argv[1], renderer);
|
SNES snes(argv[1], renderer);
|
||||||
renderer.createWindow(snes, 60);
|
renderer.createWindow(snes, 60);
|
||||||
parseArguments(argc, argv, snes);
|
parseArguments(argc, argv, snes);
|
||||||
return QApplication::exec();
|
return QApplication::exec();
|
||||||
|
}
|
||||||
|
catch(std::exception &ex) {
|
||||||
|
std::cerr << ex.what() << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -14,7 +14,7 @@ Test(ADC, addingOne)
|
|||||||
snes.cpu->_isEmulationMode = false;
|
snes.cpu->_isEmulationMode = false;
|
||||||
snes.cpu->_registers.a = 0;
|
snes.cpu->_registers.a = 0;
|
||||||
snes.wram->_data[0] = 0x1;
|
snes.wram->_data[0] = 0x1;
|
||||||
snes.cpu->ADC(0x0);
|
snes.cpu->ADC(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.a, 1, "The accumulator's value should be 0x1 but it was 0x%x.", snes.cpu->_registers.a);
|
cr_assert_eq(snes.cpu->_registers.a, 1, "The accumulator's value should be 0x1 but it was 0x%x.", snes.cpu->_registers.a);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flags should not be set.");
|
cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flags should not be set.");
|
||||||
cr_assert_eq(snes.cpu->_registers.p.v, false, "The overflow flags should not be set.");
|
cr_assert_eq(snes.cpu->_registers.p.v, false, "The overflow flags should not be set.");
|
||||||
@@ -28,7 +28,7 @@ Test(ADC, addingOneEmulation)
|
|||||||
snes.cpu->_isEmulationMode = true;
|
snes.cpu->_isEmulationMode = true;
|
||||||
snes.cpu->_registers.a = 0;
|
snes.cpu->_registers.a = 0;
|
||||||
snes.wram->_data[0] = 0x1;
|
snes.wram->_data[0] = 0x1;
|
||||||
snes.cpu->ADC(0x0);
|
snes.cpu->ADC(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.a, 1, "The accumulator's value should be 0x1 but it was 0x%x.", snes.cpu->_registers.a);
|
cr_assert_eq(snes.cpu->_registers.a, 1, "The accumulator's value should be 0x1 but it was 0x%x.", snes.cpu->_registers.a);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flags should not be set.");
|
cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flags should not be set.");
|
||||||
cr_assert_eq(snes.cpu->_registers.p.v, false, "The overflow flags should not be set.");
|
cr_assert_eq(snes.cpu->_registers.p.v, false, "The overflow flags should not be set.");
|
||||||
@@ -42,7 +42,7 @@ Test(ADC, overflow)
|
|||||||
snes.cpu->_isEmulationMode = false;
|
snes.cpu->_isEmulationMode = false;
|
||||||
snes.cpu->_registers.a = 0xFFFF;
|
snes.cpu->_registers.a = 0xFFFF;
|
||||||
snes.wram->_data[0] = 0x1;
|
snes.wram->_data[0] = 0x1;
|
||||||
snes.cpu->ADC(0x0);
|
snes.cpu->ADC(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.a, 0, "The accumulator's value should be 0x0 but it was 0x%x.", snes.cpu->_registers.a);
|
cr_assert_eq(snes.cpu->_registers.a, 0, "The accumulator's value should be 0x0 but it was 0x%x.", snes.cpu->_registers.a);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.c, true, "The carry flags should be set.");
|
cr_assert_eq(snes.cpu->_registers.p.c, true, "The carry flags should be set.");
|
||||||
cr_assert_eq(snes.cpu->_registers.p.v, false, "The overflow flags should not be set.");
|
cr_assert_eq(snes.cpu->_registers.p.v, false, "The overflow flags should not be set.");
|
||||||
@@ -56,7 +56,7 @@ Test(ADC, overflowEmulation)
|
|||||||
snes.cpu->_isEmulationMode = true;
|
snes.cpu->_isEmulationMode = true;
|
||||||
snes.cpu->_registers.a = 0xFF;
|
snes.cpu->_registers.a = 0xFF;
|
||||||
snes.wram->_data[0] = 0x1;
|
snes.wram->_data[0] = 0x1;
|
||||||
snes.cpu->ADC(0x0);
|
snes.cpu->ADC(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.a, 0, "The accumulator's value should be 0x0 but it was 0x%x.", snes.cpu->_registers.a);
|
cr_assert_eq(snes.cpu->_registers.a, 0, "The accumulator's value should be 0x0 but it was 0x%x.", snes.cpu->_registers.a);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.c, true, "The carry flags should be set.");
|
cr_assert_eq(snes.cpu->_registers.p.c, true, "The carry flags should be set.");
|
||||||
cr_assert_eq(snes.cpu->_registers.p.v, false, "The overflow flags should not be set.");
|
cr_assert_eq(snes.cpu->_registers.p.v, false, "The overflow flags should not be set.");
|
||||||
@@ -70,7 +70,7 @@ Test(ADC, signedOverflow)
|
|||||||
snes.cpu->_isEmulationMode = false;
|
snes.cpu->_isEmulationMode = 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);
|
snes.cpu->ADC(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.a, 0x8000, "The accumulator's value should be 0x8000 but it was 0x%x.", snes.cpu->_registers.a);
|
cr_assert_eq(snes.cpu->_registers.a, 0x8000, "The accumulator's value should be 0x8000 but it was 0x%x.", snes.cpu->_registers.a);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flags should not be set.");
|
cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flags should not be set.");
|
||||||
cr_assert_eq(snes.cpu->_registers.p.v, true, "The overflow flags should be set.");
|
cr_assert_eq(snes.cpu->_registers.p.v, true, "The overflow flags should be set.");
|
||||||
@@ -84,7 +84,7 @@ Test(ADC, signedOverflowEmulated)
|
|||||||
snes.cpu->_isEmulationMode = true;
|
snes.cpu->_isEmulationMode = 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);
|
snes.cpu->ADC(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.a, 0x0080, "The accumulator's value should be 0x0080 but it was 0x%x.", snes.cpu->_registers.a);
|
cr_assert_eq(snes.cpu->_registers.a, 0x0080, "The accumulator's value should be 0x0080 but it was 0x%x.", snes.cpu->_registers.a);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flags should not be set.");
|
cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flags should not be set.");
|
||||||
cr_assert_eq(snes.cpu->_registers.p.v, true, "The overflow flags should be set.");
|
cr_assert_eq(snes.cpu->_registers.p.v, true, "The overflow flags should be set.");
|
||||||
@@ -98,7 +98,7 @@ Test(ADC, negative)
|
|||||||
snes.cpu->_isEmulationMode = false;
|
snes.cpu->_isEmulationMode = 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);
|
snes.cpu->ADC(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.a, 0x9000, "The accumulator's value should be 0x9000 but it was 0x%x.", snes.cpu->_registers.a);
|
cr_assert_eq(snes.cpu->_registers.a, 0x9000, "The accumulator's value should be 0x9000 but it was 0x%x.", snes.cpu->_registers.a);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flags should not be set.");
|
cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flags should not be set.");
|
||||||
cr_assert_eq(snes.cpu->_registers.p.v, false, "The overflow flags should be set.");
|
cr_assert_eq(snes.cpu->_registers.p.v, false, "The overflow flags should be set.");
|
||||||
@@ -114,7 +114,7 @@ Test(ADC, memoryTwoBytes)
|
|||||||
snes.cpu->_registers.a = 0x000F;
|
snes.cpu->_registers.a = 0x000F;
|
||||||
snes.wram->_data[0] = 0x01;
|
snes.wram->_data[0] = 0x01;
|
||||||
snes.wram->_data[1] = 0x04;
|
snes.wram->_data[1] = 0x04;
|
||||||
snes.cpu->ADC(0x0);
|
snes.cpu->ADC(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.a, 0x0410, "The accumulator's value should be 0x0410 but it was 0x%x.", snes.cpu->_registers.a);
|
cr_assert_eq(snes.cpu->_registers.a, 0x0410, "The accumulator's value should be 0x0410 but it was 0x%x.", snes.cpu->_registers.a);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flags should not be set.");
|
cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flags should not be set.");
|
||||||
cr_assert_eq(snes.cpu->_registers.p.v, false, "The overflow flags should not be set.");
|
cr_assert_eq(snes.cpu->_registers.p.v, false, "The overflow flags should not be set.");
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ Test(SBC, removingOne)
|
|||||||
snes.cpu->_registers.p.c = true;
|
snes.cpu->_registers.p.c = true;
|
||||||
snes.cpu->_registers.a = 0x1;
|
snes.cpu->_registers.a = 0x1;
|
||||||
snes.wram->_data[0] = 0x1;
|
snes.wram->_data[0] = 0x1;
|
||||||
snes.cpu->SBC(0x0);
|
snes.cpu->SBC(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.a, 0, "The accumulator's value should be 0x0 but it was 0x%x.", snes.cpu->_registers.a);
|
cr_assert_eq(snes.cpu->_registers.a, 0, "The accumulator's value should be 0x0 but it was 0x%x.", snes.cpu->_registers.a);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.c, true, "The carry flags should be set.");
|
cr_assert_eq(snes.cpu->_registers.p.c, true, "The carry flags should be set.");
|
||||||
cr_assert_eq(snes.cpu->_registers.p.v, false, "The overflow flags should not be set.");
|
cr_assert_eq(snes.cpu->_registers.p.v, false, "The overflow flags should not be set.");
|
||||||
@@ -32,7 +32,7 @@ Test(SBC, legitOverflowWithCarry)
|
|||||||
snes.cpu->_registers.p.c = true;
|
snes.cpu->_registers.p.c = true;
|
||||||
snes.wram->_data[0] = 0x03;
|
snes.wram->_data[0] = 0x03;
|
||||||
snes.wram->_data[1] = 0x20;
|
snes.wram->_data[1] = 0x20;
|
||||||
snes.cpu->SBC(0x0);
|
snes.cpu->SBC(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.a, 0xDFFE, "The accumulator's value should be 0xDFFE but it was 0x%x.", snes.cpu->_registers.a);
|
cr_assert_eq(snes.cpu->_registers.a, 0xDFFE, "The accumulator's value should be 0xDFFE but it was 0x%x.", snes.cpu->_registers.a);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flags should not be set.");
|
cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flags should not be set.");
|
||||||
cr_assert_eq(snes.cpu->_registers.p.v, false, "The overflow flags should not be set.");
|
cr_assert_eq(snes.cpu->_registers.p.v, false, "The overflow flags should not be set.");
|
||||||
@@ -49,7 +49,7 @@ Test(SBC, overflowWithCarry)
|
|||||||
snes.cpu->_registers.p.c = true;
|
snes.cpu->_registers.p.c = true;
|
||||||
snes.wram->_data[0] = 0x03;
|
snes.wram->_data[0] = 0x03;
|
||||||
snes.wram->_data[1] = 0x20;
|
snes.wram->_data[1] = 0x20;
|
||||||
snes.cpu->SBC(0x0);
|
snes.cpu->SBC(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.a, 0xDFFE, "The accumulator's value should be 0xDFFE but it was 0x%x.", snes.cpu->_registers.a);
|
cr_assert_eq(snes.cpu->_registers.a, 0xDFFE, "The accumulator's value should be 0xDFFE but it was 0x%x.", snes.cpu->_registers.a);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flags should not be set.");
|
cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flags should not be set.");
|
||||||
cr_assert_eq(snes.cpu->_registers.p.v, false, "The overflow flags should be not set.");
|
cr_assert_eq(snes.cpu->_registers.p.v, false, "The overflow flags should be not set.");
|
||||||
@@ -65,7 +65,7 @@ Test(SBC, overflowEmulation)
|
|||||||
snes.cpu->_registers.p.m = false;
|
snes.cpu->_registers.p.m = false;
|
||||||
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);
|
snes.cpu->SBC(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.a, 0xFE, "The accumulator's value should be 0xFE but it was 0x%x.", snes.cpu->_registers.a);
|
cr_assert_eq(snes.cpu->_registers.a, 0xFE, "The accumulator's value should be 0xFE but it was 0x%x.", snes.cpu->_registers.a);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flags should not be set.");
|
cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flags should not be set.");
|
||||||
cr_assert_eq(snes.cpu->_registers.p.v, false, "The overflow flags should not be set.");
|
cr_assert_eq(snes.cpu->_registers.p.v, false, "The overflow flags should not be set.");
|
||||||
@@ -83,7 +83,7 @@ Test(SBC, overflowEmulation)
|
|||||||
// snes.cpu->_registers.p.m = false;
|
// snes.cpu->_registers.p.m = false;
|
||||||
// snes.wram->_data[0] = 0x03;
|
// snes.wram->_data[0] = 0x03;
|
||||||
// snes.wram->_data[1] = 0x20;
|
// snes.wram->_data[1] = 0x20;
|
||||||
// snes.cpu->SBC(0x0);
|
// snes.cpu->SBC(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
// cr_assert_eq(snes.cpu->_registers.a, 0x7998, "The accumulator's value should be 0x7998 but it was 0x%x.", snes.cpu->_registers.a);
|
// cr_assert_eq(snes.cpu->_registers.a, 0x7998, "The accumulator's value should be 0x7998 but it was 0x%x.", snes.cpu->_registers.a);
|
||||||
// cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flags should not be set.");
|
// cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flags should not be set.");
|
||||||
// cr_assert_eq(snes.cpu->_registers.p.v, false, "The overflow flags should not be set.");
|
// cr_assert_eq(snes.cpu->_registers.p.v, false, "The overflow flags should not be set.");
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ Test(TAX, 16bitsTo16Bits)
|
|||||||
snes.cpu->_registers.p.m = false;
|
snes.cpu->_registers.p.m = false;
|
||||||
snes.cpu->_registers.x = 0xABCD;
|
snes.cpu->_registers.x = 0xABCD;
|
||||||
snes.cpu->_registers.a = 0xFEDC;
|
snes.cpu->_registers.a = 0xFEDC;
|
||||||
snes.cpu->TAX();
|
snes.cpu->TAX(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.x, 0xFEDC, "The flags should be 0xFEDC but it was %x", snes.cpu->_registers.x);
|
cr_assert_eq(snes.cpu->_registers.x, 0xFEDC, "The flags should be 0xFEDC 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.n, true, "The negative flag should be set.");
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.");
|
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.");
|
||||||
@@ -31,7 +31,7 @@ Test(TAX, 16bitsTo8Bits)
|
|||||||
snes.cpu->_registers.p.m = false;
|
snes.cpu->_registers.p.m = false;
|
||||||
snes.cpu->_registers.x = 0xFEDC;
|
snes.cpu->_registers.x = 0xFEDC;
|
||||||
snes.cpu->_registers.a = 0xAB00;
|
snes.cpu->_registers.a = 0xAB00;
|
||||||
snes.cpu->TAX();
|
snes.cpu->TAX(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.x, 0xFE00, "The flags should be 0xFE00 but it was %x", snes.cpu->_registers.x);
|
cr_assert_eq(snes.cpu->_registers.x, 0xFE00, "The flags should be 0xFE00 but it was %x", snes.cpu->_registers.x);
|
||||||
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.");
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.");
|
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.");
|
||||||
@@ -45,7 +45,7 @@ Test(TAX, 8bitsTo16Bits)
|
|||||||
snes.cpu->_registers.p.m = true;
|
snes.cpu->_registers.p.m = true;
|
||||||
snes.cpu->_registers.x = 0xFEDC;
|
snes.cpu->_registers.x = 0xFEDC;
|
||||||
snes.cpu->_registers.a = 0xAB;
|
snes.cpu->_registers.a = 0xAB;
|
||||||
snes.cpu->TAX();
|
snes.cpu->TAX(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.x, 0x00AB, "The flags should be 0x00AB but it was %x", snes.cpu->_registers.x);
|
cr_assert_eq(snes.cpu->_registers.x, 0x00AB, "The flags should be 0x00AB but it was %x", snes.cpu->_registers.x);
|
||||||
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.");
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.");
|
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.");
|
||||||
@@ -59,7 +59,7 @@ Test(TAX, 8bitsTo8Bits)
|
|||||||
snes.cpu->_registers.p.m = true;
|
snes.cpu->_registers.p.m = true;
|
||||||
snes.cpu->_registers.x = 0xFE;
|
snes.cpu->_registers.x = 0xFE;
|
||||||
snes.cpu->_registers.a = 0xAB;
|
snes.cpu->_registers.a = 0xAB;
|
||||||
snes.cpu->TAX();
|
snes.cpu->TAX(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.x, 0xAB, "The flags should be 0xAB but it was %x", snes.cpu->_registers.x);
|
cr_assert_eq(snes.cpu->_registers.x, 0xAB, "The flags should be 0xAB 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.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.");
|
||||||
@@ -74,7 +74,7 @@ Test(TAY, 16bitsTo16Bits)
|
|||||||
snes.cpu->_registers.p.m = false;
|
snes.cpu->_registers.p.m = false;
|
||||||
snes.cpu->_registers.y = 0xABCD;
|
snes.cpu->_registers.y = 0xABCD;
|
||||||
snes.cpu->_registers.a = 0xFEDC;
|
snes.cpu->_registers.a = 0xFEDC;
|
||||||
snes.cpu->TAY();
|
snes.cpu->TAY(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.y, 0xFEDC, "The y register should be 0xFEDC but it was %x", snes.cpu->_registers.y);
|
cr_assert_eq(snes.cpu->_registers.y, 0xFEDC, "The y register should be 0xFEDC 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.n, true, "The negative flag should be set.");
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.");
|
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.");
|
||||||
@@ -88,7 +88,7 @@ Test(TAY, 16bitsTo8Bits)
|
|||||||
snes.cpu->_registers.p.m = false;
|
snes.cpu->_registers.p.m = false;
|
||||||
snes.cpu->_registers.y = 0xFEDC;
|
snes.cpu->_registers.y = 0xFEDC;
|
||||||
snes.cpu->_registers.a = 0xAB00;
|
snes.cpu->_registers.a = 0xAB00;
|
||||||
snes.cpu->TAY();
|
snes.cpu->TAY(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.y, 0xFE00, "The y register should be 0xFE00 but it was %x", snes.cpu->_registers.y);
|
cr_assert_eq(snes.cpu->_registers.y, 0xFE00, "The y register should be 0xFE00 but it was %x", snes.cpu->_registers.y);
|
||||||
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.");
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.");
|
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.");
|
||||||
@@ -102,7 +102,7 @@ Test(TAY, 8bitsTo16Bits)
|
|||||||
snes.cpu->_registers.p.m = true;
|
snes.cpu->_registers.p.m = true;
|
||||||
snes.cpu->_registers.y = 0xFEDC;
|
snes.cpu->_registers.y = 0xFEDC;
|
||||||
snes.cpu->_registers.a = 0xAB;
|
snes.cpu->_registers.a = 0xAB;
|
||||||
snes.cpu->TAY();
|
snes.cpu->TAY(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.y, 0x00AB, "The y register should be 0x00AB but it was %x", snes.cpu->_registers.y);
|
cr_assert_eq(snes.cpu->_registers.y, 0x00AB, "The y register should be 0x00AB but it was %x", snes.cpu->_registers.y);
|
||||||
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.");
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.");
|
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.");
|
||||||
@@ -116,7 +116,7 @@ Test(TAY, 8bitsTo8Bits)
|
|||||||
snes.cpu->_registers.p.m = true;
|
snes.cpu->_registers.p.m = true;
|
||||||
snes.cpu->_registers.y = 0xFE;
|
snes.cpu->_registers.y = 0xFE;
|
||||||
snes.cpu->_registers.a = 0xAB;
|
snes.cpu->_registers.a = 0xAB;
|
||||||
snes.cpu->TAY();
|
snes.cpu->TAY(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.y, 0xAB, "The y register should be 0xAB but it was %x", snes.cpu->_registers.y);
|
cr_assert_eq(snes.cpu->_registers.y, 0xAB, "The y register should be 0xAB 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.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.");
|
||||||
@@ -128,7 +128,7 @@ Test(TXS, 16bitsIndex)
|
|||||||
snes.cpu->_isEmulationMode = false;
|
snes.cpu->_isEmulationMode = false;
|
||||||
snes.cpu->_registers.p.x_b = false;
|
snes.cpu->_registers.p.x_b = false;
|
||||||
snes.cpu->_registers.x = 0xABCD;
|
snes.cpu->_registers.x = 0xABCD;
|
||||||
snes.cpu->TXS();
|
snes.cpu->TXS(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);
|
cr_assert_eq(snes.cpu->_registers.s, 0xABCD, "The stack pointer should be 0xABCD but it was %x", snes.cpu->_registers.s);
|
||||||
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.");
|
||||||
@@ -140,7 +140,7 @@ Test(TXS, 8bitsIndex)
|
|||||||
snes.cpu->_isEmulationMode = false;
|
snes.cpu->_isEmulationMode = false;
|
||||||
snes.cpu->_registers.p.x_b = true;
|
snes.cpu->_registers.p.x_b = true;
|
||||||
snes.cpu->_registers.x = 0xABCD;
|
snes.cpu->_registers.x = 0xABCD;
|
||||||
snes.cpu->TXS();
|
snes.cpu->TXS(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.s, 0x00CD, "The stack pointer should be 0x00CD but it was %x", snes.cpu->_registers.s);
|
cr_assert_eq(snes.cpu->_registers.s, 0x00CD, "The stack pointer should be 0x00CD but it was %x", snes.cpu->_registers.s);
|
||||||
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.");
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ Test(AddrMode, ImmediateBankChange)
|
|||||||
snes.cpu->_registers.pac = 0x00FFFF;
|
snes.cpu->_registers.pac = 0x00FFFF;
|
||||||
snes.cpu->_registers.p.m = true;
|
snes.cpu->_registers.p.m = true;
|
||||||
cr_assert_eq(snes.cpu->_getImmediateAddrForA(), 0x00FFFF);
|
cr_assert_eq(snes.cpu->_getImmediateAddrForA(), 0x00FFFF);
|
||||||
cr_assert_eq(snes.cpu->_registers.pac, 0x010000);
|
cr_assert_eq(snes.cpu->_registers.pac, 0x000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
Test(AddrMode, Direct)
|
Test(AddrMode, Direct)
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ Test(AND, emulation)
|
|||||||
snes.wram->_data[0] = 0x00;
|
snes.wram->_data[0] = 0x00;
|
||||||
snes.cpu->_registers.a = 0xFF;
|
snes.cpu->_registers.a = 0xFF;
|
||||||
snes.cpu->_isEmulationMode = true;
|
snes.cpu->_isEmulationMode = true;
|
||||||
snes.cpu->AND(0x0);
|
snes.cpu->AND(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.a, 0x00, "The flags should be 0x00 but it was %x", snes.cpu->_registers.a);
|
cr_assert_eq(snes.cpu->_registers.a, 0x00, "The flags should be 0x00 but it was %x", snes.cpu->_registers.a);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.");
|
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.");
|
||||||
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.");
|
||||||
@@ -29,7 +29,7 @@ Test(AND, nativeNegative)
|
|||||||
snes.cpu->_registers.p.m = false;
|
snes.cpu->_registers.p.m = false;
|
||||||
snes.cpu->_registers.a = 0xFF00;
|
snes.cpu->_registers.a = 0xFF00;
|
||||||
snes.cpu->_isEmulationMode = false;
|
snes.cpu->_isEmulationMode = false;
|
||||||
snes.cpu->AND(0x0);
|
snes.cpu->AND(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.a, 0xF000, "The flags should be 0xF000 but it was %x", snes.cpu->_registers.a);
|
cr_assert_eq(snes.cpu->_registers.a, 0xF000, "The flags should be 0xF000 but it was %x", snes.cpu->_registers.a);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.");
|
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.");
|
||||||
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.");
|
||||||
@@ -42,7 +42,7 @@ Test(AND, emulationTest)
|
|||||||
snes.wram->_data[0] = 0b00110011;
|
snes.wram->_data[0] = 0b00110011;
|
||||||
snes.cpu->_registers.a = 0b00110111;
|
snes.cpu->_registers.a = 0b00110111;
|
||||||
snes.cpu->_isEmulationMode = true;
|
snes.cpu->_isEmulationMode = true;
|
||||||
snes.cpu->AND(0x0);
|
snes.cpu->AND(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.a, 0b00110011, "The flags should be 0b00110011 but it was %x", snes.cpu->_registers.a);
|
cr_assert_eq(snes.cpu->_registers.a, 0b00110011, "The flags should be 0b00110011 but it was %x", snes.cpu->_registers.a);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.");
|
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.");
|
||||||
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.");
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ using namespace ComSquare;
|
|||||||
Test(SEP, setall)
|
Test(SEP, setall)
|
||||||
{
|
{
|
||||||
Init()
|
Init()
|
||||||
snes.cpu->SEP(0xFF);
|
snes.wram->_data[0] = 0xFF;
|
||||||
|
snes.cpu->SEP(0x00, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.cpu->_registers.p.flags;
|
auto data = snes.cpu->_registers.p.flags;
|
||||||
cr_assert_eq(data, 0xFF, "The flag should be 0xFF but it was %x", data);
|
cr_assert_eq(data, 0xFF, "The flag should be 0xFF but it was %x", data);
|
||||||
}
|
}
|
||||||
@@ -24,7 +25,8 @@ Test(SEP, setsome)
|
|||||||
{
|
{
|
||||||
Init()
|
Init()
|
||||||
snes.cpu->_registers.p.flags = 0b01000000;
|
snes.cpu->_registers.p.flags = 0b01000000;
|
||||||
snes.cpu->SEP(0b10110101);
|
snes.wram->_data[0] = 0b10110101;
|
||||||
|
snes.cpu->SEP(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.cpu->_registers.p.flags;
|
auto data = snes.cpu->_registers.p.flags;
|
||||||
cr_assert_eq(data, 0b11110101, "The flag should be 245 but it was %i", data);
|
cr_assert_eq(data, 0b11110101, "The flag should be 245 but it was %i", data);
|
||||||
}
|
}
|
||||||
@@ -33,7 +35,8 @@ Test(REP, resetall)
|
|||||||
{
|
{
|
||||||
Init()
|
Init()
|
||||||
snes.cpu->_isEmulationMode = false;
|
snes.cpu->_isEmulationMode = false;
|
||||||
snes.cpu->REP(0xFF);
|
snes.wram->_data[0] = 0xFF;
|
||||||
|
snes.cpu->REP(0x00, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.cpu->_registers.p.flags;
|
auto data = snes.cpu->_registers.p.flags;
|
||||||
cr_assert_eq(data, 0x00, "The flag should be 0x00 but it was %x", data);
|
cr_assert_eq(data, 0x00, "The flag should be 0x00 but it was %x", data);
|
||||||
}
|
}
|
||||||
@@ -43,7 +46,8 @@ Test(REP, resetsome)
|
|||||||
Init()
|
Init()
|
||||||
snes.cpu->_isEmulationMode = false;
|
snes.cpu->_isEmulationMode = false;
|
||||||
snes.cpu->_registers.p.flags = 0b01000000;
|
snes.cpu->_registers.p.flags = 0b01000000;
|
||||||
snes.cpu->REP(0b01000000);
|
snes.wram->_data[0] = 0b01000000;
|
||||||
|
snes.cpu->REP(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.cpu->_registers.p.flags;
|
auto data = snes.cpu->_registers.p.flags;
|
||||||
cr_assert_eq(data, 0x0, "The flag should be 0 but it was %x", data);
|
cr_assert_eq(data, 0x0, "The flag should be 0 but it was %x", data);
|
||||||
}
|
}
|
||||||
@@ -52,7 +56,8 @@ Test(REP, resetallEmulation)
|
|||||||
{
|
{
|
||||||
Init()
|
Init()
|
||||||
snes.cpu->_isEmulationMode = true;
|
snes.cpu->_isEmulationMode = true;
|
||||||
snes.cpu->REP(0xFF);
|
snes.wram->_data[0] = 0xFF;
|
||||||
|
snes.cpu->REP(0x00, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.cpu->_registers.p.flags;
|
auto data = snes.cpu->_registers.p.flags;
|
||||||
cr_assert_eq(data, 0b00110000, "The flag should be 0b00110000 but it was %x", data);
|
cr_assert_eq(data, 0b00110000, "The flag should be 0b00110000 but it was %x", data);
|
||||||
}
|
}
|
||||||
@@ -62,7 +67,8 @@ Test(REP, resetsomeEmulation)
|
|||||||
Init()
|
Init()
|
||||||
snes.cpu->_isEmulationMode = true;
|
snes.cpu->_isEmulationMode = true;
|
||||||
snes.cpu->_registers.p.flags = 0b01000101;
|
snes.cpu->_registers.p.flags = 0b01000101;
|
||||||
snes.cpu->REP(0b01000001);
|
snes.wram->_data[0] = 0b01000001;
|
||||||
|
snes.cpu->REP(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.cpu->_registers.p.flags;
|
auto data = snes.cpu->_registers.p.flags;
|
||||||
cr_assert_eq(data, 0b00110100, "The flag should be 0b00110100 but it was %x", data);
|
cr_assert_eq(data, 0b00110100, "The flag should be 0b00110100 but it was %x", data);
|
||||||
}
|
}
|
||||||
@@ -72,7 +78,7 @@ Test(JSR, jump)
|
|||||||
Init()
|
Init()
|
||||||
snes.cpu->_registers.pc = 0xABCD;
|
snes.cpu->_registers.pc = 0xABCD;
|
||||||
snes.cpu->_registers.s = 0x0123;
|
snes.cpu->_registers.s = 0x0123;
|
||||||
snes.cpu->JSR(0xABFF);
|
snes.cpu->JSR(0xABFF, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto pc = snes.cpu->_registers.pc;
|
auto pc = snes.cpu->_registers.pc;
|
||||||
cr_assert_eq(pc, 0xABFF, "The PC should be 0xABFF but it was %x", pc);
|
cr_assert_eq(pc, 0xABFF, "The PC should be 0xABFF but it was %x", pc);
|
||||||
cr_assert_eq(snes.cpu->_registers.s, 0x0121, "The stack pointer should be 0x0121 but it was %x", snes.cpu->_registers.s);
|
cr_assert_eq(snes.cpu->_registers.s, 0x0121, "The stack pointer should be 0x0121 but it was %x", snes.cpu->_registers.s);
|
||||||
@@ -86,7 +92,7 @@ Test(JSL, jump)
|
|||||||
snes.cpu->_registers.pbr = 0xFF;
|
snes.cpu->_registers.pbr = 0xFF;
|
||||||
snes.cpu->_registers.pc = 0xABCD;
|
snes.cpu->_registers.pc = 0xABCD;
|
||||||
snes.cpu->_registers.s = 0x0123;
|
snes.cpu->_registers.s = 0x0123;
|
||||||
snes.cpu->JSL(0xCDABFF);
|
snes.cpu->JSL(0xCDABFF, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto pac = snes.cpu->_registers.pac;
|
auto pac = snes.cpu->_registers.pac;
|
||||||
cr_assert_eq(pac, 0xCDABFF, "The PC should be 0xCDABFF but it was %x", pac);
|
cr_assert_eq(pac, 0xCDABFF, "The PC should be 0xCDABFF but it was %x", pac);
|
||||||
cr_assert_eq(snes.cpu->_registers.s, 0x0120, "The stack pointer should be 0x0120 but it was %x", snes.cpu->_registers.s);
|
cr_assert_eq(snes.cpu->_registers.s, 0x0120, "The stack pointer should be 0x0120 but it was %x", snes.cpu->_registers.s);
|
||||||
@@ -99,7 +105,7 @@ Test(PHA, basic)
|
|||||||
Init()
|
Init()
|
||||||
snes.cpu->_registers.a = 0xABCD;
|
snes.cpu->_registers.a = 0xABCD;
|
||||||
snes.cpu->_registers.s = 0x02;
|
snes.cpu->_registers.s = 0x02;
|
||||||
snes.cpu->PHA();
|
snes.cpu->PHA(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.wram->_data[1], 0xCD, "The second value pushed to the stack should be 0xCD but it was %x", snes.wram->_data[1]);
|
cr_assert_eq(snes.wram->_data[1], 0xCD, "The second value pushed to the stack should be 0xCD but it was %x", snes.wram->_data[1]);
|
||||||
cr_assert_eq(snes.wram->_data[2], 0xAB, "The first value pushed to the stack should be 0xAB but it was %x", snes.wram->_data[2]);
|
cr_assert_eq(snes.wram->_data[2], 0xAB, "The first value pushed to the stack should be 0xAB but it was %x", snes.wram->_data[2]);
|
||||||
cr_assert_eq(snes.cpu->_registers.s, 0x0, "The Stack pointer should be equal to 0x0 but it was %x", snes.cpu->_registers.s);
|
cr_assert_eq(snes.cpu->_registers.s, 0x0, "The Stack pointer should be equal to 0x0 but it was %x", snes.cpu->_registers.s);
|
||||||
@@ -110,7 +116,7 @@ Test(PHB, basic)
|
|||||||
Init()
|
Init()
|
||||||
snes.cpu->_registers.dbr = 0xFF;
|
snes.cpu->_registers.dbr = 0xFF;
|
||||||
snes.cpu->_registers.s = 0x02;
|
snes.cpu->_registers.s = 0x02;
|
||||||
snes.cpu->PHB();
|
snes.cpu->PHB(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.wram->_data[2], 0xFF, "The first value pushed to the stack should be 0xFF but it was %x", snes.wram->_data[2]);
|
cr_assert_eq(snes.wram->_data[2], 0xFF, "The first value pushed to the stack should be 0xFF but it was %x", snes.wram->_data[2]);
|
||||||
cr_assert_eq(snes.cpu->_registers.s, 0x1, "The Stack pointer should be equal to 0x1 but it was %x", snes.cpu->_registers.s);
|
cr_assert_eq(snes.cpu->_registers.s, 0x1, "The Stack pointer should be equal to 0x1 but it was %x", snes.cpu->_registers.s);
|
||||||
}
|
}
|
||||||
@@ -120,7 +126,7 @@ Test(PHD, basic)
|
|||||||
Init()
|
Init()
|
||||||
snes.cpu->_registers.d = 0xABCD;
|
snes.cpu->_registers.d = 0xABCD;
|
||||||
snes.cpu->_registers.s = 0x02;
|
snes.cpu->_registers.s = 0x02;
|
||||||
snes.cpu->PHD();
|
snes.cpu->PHD(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.wram->_data[1], 0xCD, "The second value pushed to the stack should be 0xCD but it was %x", snes.wram->_data[1]);
|
cr_assert_eq(snes.wram->_data[1], 0xCD, "The second value pushed to the stack should be 0xCD but it was %x", snes.wram->_data[1]);
|
||||||
cr_assert_eq(snes.wram->_data[2], 0xAB, "The first value pushed to the stack should be 0xAB but it was %x", snes.wram->_data[2]);
|
cr_assert_eq(snes.wram->_data[2], 0xAB, "The first value pushed to the stack should be 0xAB but it was %x", snes.wram->_data[2]);
|
||||||
cr_assert_eq(snes.cpu->_registers.s, 0x0, "The Stack pointer should be equal to 0x0 but it was %x", snes.cpu->_registers.s);
|
cr_assert_eq(snes.cpu->_registers.s, 0x0, "The Stack pointer should be equal to 0x0 but it was %x", snes.cpu->_registers.s);
|
||||||
@@ -131,7 +137,7 @@ Test(PHK, basic)
|
|||||||
Init()
|
Init()
|
||||||
snes.cpu->_registers.pbr = 0xFF;
|
snes.cpu->_registers.pbr = 0xFF;
|
||||||
snes.cpu->_registers.s = 0x02;
|
snes.cpu->_registers.s = 0x02;
|
||||||
snes.cpu->PHK();
|
snes.cpu->PHK(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.wram->_data[2], 0xFF, "The first value pushed to the stack should be 0xFF but it was %x", snes.wram->_data[2]);
|
cr_assert_eq(snes.wram->_data[2], 0xFF, "The first value pushed to the stack should be 0xFF but it was %x", snes.wram->_data[2]);
|
||||||
cr_assert_eq(snes.cpu->_registers.s, 0x1, "The Stack pointer should be equal to 0x1 but it was %x", snes.cpu->_registers.s);
|
cr_assert_eq(snes.cpu->_registers.s, 0x1, "The Stack pointer should be equal to 0x1 but it was %x", snes.cpu->_registers.s);
|
||||||
}
|
}
|
||||||
@@ -141,7 +147,7 @@ Test(PHP, basic)
|
|||||||
Init()
|
Init()
|
||||||
snes.cpu->_registers.p.flags = 0xFF;
|
snes.cpu->_registers.p.flags = 0xFF;
|
||||||
snes.cpu->_registers.s = 0x02;
|
snes.cpu->_registers.s = 0x02;
|
||||||
snes.cpu->PHP();
|
snes.cpu->PHP(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.wram->_data[2], 0xFF, "The first value pushed to the stack should be 0xFF but it was %x", snes.wram->_data[2]);
|
cr_assert_eq(snes.wram->_data[2], 0xFF, "The first value pushed to the stack should be 0xFF but it was %x", snes.wram->_data[2]);
|
||||||
cr_assert_eq(snes.cpu->_registers.s, 0x1, "The Stack pointer should be equal to 0x1 but it was %x", snes.cpu->_registers.s);
|
cr_assert_eq(snes.cpu->_registers.s, 0x1, "The Stack pointer should be equal to 0x1 but it was %x", snes.cpu->_registers.s);
|
||||||
}
|
}
|
||||||
@@ -151,7 +157,7 @@ Test(PHX, basic)
|
|||||||
Init()
|
Init()
|
||||||
snes.cpu->_registers.x = 0xABCD;
|
snes.cpu->_registers.x = 0xABCD;
|
||||||
snes.cpu->_registers.s = 0x02;
|
snes.cpu->_registers.s = 0x02;
|
||||||
snes.cpu->PHX();
|
snes.cpu->PHX(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.wram->_data[1], 0xCD, "The second value pushed to the stack should be 0xCD but it was %x", snes.wram->_data[1]);
|
cr_assert_eq(snes.wram->_data[1], 0xCD, "The second value pushed to the stack should be 0xCD but it was %x", snes.wram->_data[1]);
|
||||||
cr_assert_eq(snes.wram->_data[2], 0xAB, "The first value pushed to the stack should be 0xAB but it was %x", snes.wram->_data[2]);
|
cr_assert_eq(snes.wram->_data[2], 0xAB, "The first value pushed to the stack should be 0xAB but it was %x", snes.wram->_data[2]);
|
||||||
cr_assert_eq(snes.cpu->_registers.s, 0x0, "The Stack pointer should be equal to 0x0 but it was %x", snes.cpu->_registers.s);
|
cr_assert_eq(snes.cpu->_registers.s, 0x0, "The Stack pointer should be equal to 0x0 but it was %x", snes.cpu->_registers.s);
|
||||||
@@ -162,7 +168,7 @@ Test(PHY, basic)
|
|||||||
Init()
|
Init()
|
||||||
snes.cpu->_registers.y = 0xABCD;
|
snes.cpu->_registers.y = 0xABCD;
|
||||||
snes.cpu->_registers.s = 0x02;
|
snes.cpu->_registers.s = 0x02;
|
||||||
snes.cpu->PHY();
|
snes.cpu->PHY(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.wram->_data[1], 0xCD, "The second value pushed to the stack should be 0xCD but it was %x", snes.wram->_data[1]);
|
cr_assert_eq(snes.wram->_data[1], 0xCD, "The second value pushed to the stack should be 0xCD but it was %x", snes.wram->_data[1]);
|
||||||
cr_assert_eq(snes.wram->_data[2], 0xAB, "The first value pushed to the stack should be 0xAB but it was %x", snes.wram->_data[2]);
|
cr_assert_eq(snes.wram->_data[2], 0xAB, "The first value pushed to the stack should be 0xAB but it was %x", snes.wram->_data[2]);
|
||||||
cr_assert_eq(snes.cpu->_registers.s, 0x0, "The Stack pointer should be equal to 0x0 but it was %x", snes.cpu->_registers.s);
|
cr_assert_eq(snes.cpu->_registers.s, 0x0, "The Stack pointer should be equal to 0x0 but it was %x", snes.cpu->_registers.s);
|
||||||
@@ -174,7 +180,8 @@ Test(PLA, basic)
|
|||||||
snes.wram->_data[1] = 0xCD;
|
snes.wram->_data[1] = 0xCD;
|
||||||
snes.wram->_data[2] = 0x7B;
|
snes.wram->_data[2] = 0x7B;
|
||||||
snes.cpu->_registers.s = 0x00;
|
snes.cpu->_registers.s = 0x00;
|
||||||
snes.cpu->PLA();
|
snes.cpu->_registers.p.m = false;
|
||||||
|
snes.cpu->PLA(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.cpu->_registers.a;
|
auto data = snes.cpu->_registers.a;
|
||||||
cr_assert_eq(data, 0x7BCD, "The accumulator should be 0x7BCD but it was %x", data);
|
cr_assert_eq(data, 0x7BCD, "The accumulator should be 0x7BCD but it was %x", data);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.", snes.cpu->_registers.p.z);
|
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.", snes.cpu->_registers.p.z);
|
||||||
@@ -188,7 +195,8 @@ Test(PLA, zero)
|
|||||||
snes.wram->_data[1] = 0x00;
|
snes.wram->_data[1] = 0x00;
|
||||||
snes.wram->_data[2] = 0x00;
|
snes.wram->_data[2] = 0x00;
|
||||||
snes.cpu->_registers.s = 0x00;
|
snes.cpu->_registers.s = 0x00;
|
||||||
snes.cpu->PLA();
|
snes.cpu->_registers.p.m = false;
|
||||||
|
snes.cpu->PLA(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.cpu->_registers.a;
|
auto data = snes.cpu->_registers.a;
|
||||||
cr_assert_eq(data, 0x0000, "The accumulator should be 0x0000 but it was %x", data);
|
cr_assert_eq(data, 0x0000, "The accumulator should be 0x0000 but it was %x", data);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.", snes.cpu->_registers.p.z);
|
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.", snes.cpu->_registers.p.z);
|
||||||
@@ -202,7 +210,8 @@ Test(PLA, negative)
|
|||||||
snes.wram->_data[1] = 0x00;
|
snes.wram->_data[1] = 0x00;
|
||||||
snes.wram->_data[2] = 0xA0;
|
snes.wram->_data[2] = 0xA0;
|
||||||
snes.cpu->_registers.s = 0x00;
|
snes.cpu->_registers.s = 0x00;
|
||||||
snes.cpu->PLA();
|
snes.cpu->_registers.p.m = false;
|
||||||
|
snes.cpu->PLA(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.cpu->_registers.a;
|
auto data = snes.cpu->_registers.a;
|
||||||
cr_assert_eq(data, 0xA000, "The accumulator should be 0xA000 but it was %x", data);
|
cr_assert_eq(data, 0xA000, "The accumulator should be 0xA000 but it was %x", data);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag not should be set.", snes.cpu->_registers.p.z);
|
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag not should be set.", snes.cpu->_registers.p.z);
|
||||||
@@ -216,7 +225,8 @@ Test(PLX, basic)
|
|||||||
snes.wram->_data[1] = 0xCD;
|
snes.wram->_data[1] = 0xCD;
|
||||||
snes.wram->_data[2] = 0x7B;
|
snes.wram->_data[2] = 0x7B;
|
||||||
snes.cpu->_registers.s = 0x00;
|
snes.cpu->_registers.s = 0x00;
|
||||||
snes.cpu->PLX();
|
snes.cpu->_registers.p.x_b = false;
|
||||||
|
snes.cpu->PLX(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.cpu->_registers.x;
|
auto data = snes.cpu->_registers.x;
|
||||||
cr_assert_eq(data, 0x7BCD, "The X register should be 0x7BCD but it was %x", data);
|
cr_assert_eq(data, 0x7BCD, "The X register should be 0x7BCD but it was %x", data);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.", snes.cpu->_registers.p.z);
|
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.", snes.cpu->_registers.p.z);
|
||||||
@@ -230,7 +240,8 @@ Test(PLX, zero)
|
|||||||
snes.wram->_data[1] = 0x00;
|
snes.wram->_data[1] = 0x00;
|
||||||
snes.wram->_data[2] = 0x00;
|
snes.wram->_data[2] = 0x00;
|
||||||
snes.cpu->_registers.s = 0x00;
|
snes.cpu->_registers.s = 0x00;
|
||||||
snes.cpu->PLX();
|
snes.cpu->_registers.p.x_b = false;
|
||||||
|
snes.cpu->PLX(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.cpu->_registers.x;
|
auto data = snes.cpu->_registers.x;
|
||||||
cr_assert_eq(data, 0x0000, "The x register should be 0x0000 but it was %x", data);
|
cr_assert_eq(data, 0x0000, "The x register should be 0x0000 but it was %x", data);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.", snes.cpu->_registers.p.z);
|
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.", snes.cpu->_registers.p.z);
|
||||||
@@ -244,7 +255,8 @@ Test(PLX, negative)
|
|||||||
snes.wram->_data[1] = 0x00;
|
snes.wram->_data[1] = 0x00;
|
||||||
snes.wram->_data[2] = 0xA0;
|
snes.wram->_data[2] = 0xA0;
|
||||||
snes.cpu->_registers.s = 0x00;
|
snes.cpu->_registers.s = 0x00;
|
||||||
snes.cpu->PLX();
|
snes.cpu->_registers.p.x_b = false;
|
||||||
|
snes.cpu->PLX(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.cpu->_registers.x;
|
auto data = snes.cpu->_registers.x;
|
||||||
cr_assert_eq(data, 0xA000, "The x register should be 0xA000 but it was %x", data);
|
cr_assert_eq(data, 0xA000, "The x register should be 0xA000 but it was %x", data);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag not should be set.", snes.cpu->_registers.p.z);
|
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag not should be set.", snes.cpu->_registers.p.z);
|
||||||
@@ -258,7 +270,8 @@ Test(PLY, basic)
|
|||||||
snes.wram->_data[1] = 0xCD;
|
snes.wram->_data[1] = 0xCD;
|
||||||
snes.wram->_data[2] = 0x7B;
|
snes.wram->_data[2] = 0x7B;
|
||||||
snes.cpu->_registers.s = 0x00;
|
snes.cpu->_registers.s = 0x00;
|
||||||
snes.cpu->PLY();
|
snes.cpu->_registers.p.x_b = false;
|
||||||
|
snes.cpu->PLY(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.cpu->_registers.y;
|
auto data = snes.cpu->_registers.y;
|
||||||
cr_assert_eq(data, 0x7BCD, "The Y register should be 0x7BCD but it was %x", data);
|
cr_assert_eq(data, 0x7BCD, "The Y register should be 0x7BCD but it was %x", data);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.", snes.cpu->_registers.p.z);
|
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.", snes.cpu->_registers.p.z);
|
||||||
@@ -272,7 +285,8 @@ Test(PLY, zero)
|
|||||||
snes.wram->_data[1] = 0x00;
|
snes.wram->_data[1] = 0x00;
|
||||||
snes.wram->_data[2] = 0x00;
|
snes.wram->_data[2] = 0x00;
|
||||||
snes.cpu->_registers.s = 0x00;
|
snes.cpu->_registers.s = 0x00;
|
||||||
snes.cpu->PLY();
|
snes.cpu->_registers.p.x_b = false;
|
||||||
|
snes.cpu->PLY(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.cpu->_registers.y;
|
auto data = snes.cpu->_registers.y;
|
||||||
cr_assert_eq(data, 0x0000, "The y register should be 0x0000 but it was %x", data);
|
cr_assert_eq(data, 0x0000, "The y register should be 0x0000 but it was %x", data);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.", snes.cpu->_registers.p.z);
|
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.", snes.cpu->_registers.p.z);
|
||||||
@@ -286,7 +300,8 @@ Test(PLY, negative)
|
|||||||
snes.wram->_data[1] = 0x00;
|
snes.wram->_data[1] = 0x00;
|
||||||
snes.wram->_data[2] = 0xA0;
|
snes.wram->_data[2] = 0xA0;
|
||||||
snes.cpu->_registers.s = 0x00;
|
snes.cpu->_registers.s = 0x00;
|
||||||
snes.cpu->PLY();
|
snes.cpu->_registers.p.x_b = false;
|
||||||
|
snes.cpu->PLY(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.cpu->_registers.y;
|
auto data = snes.cpu->_registers.y;
|
||||||
cr_assert_eq(data, 0xA000, "The y register should be 0xA000 but it was %x", data);
|
cr_assert_eq(data, 0xA000, "The y register should be 0xA000 but it was %x", data);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag not should be set.", snes.cpu->_registers.p.z);
|
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag not should be set.", snes.cpu->_registers.p.z);
|
||||||
@@ -300,7 +315,7 @@ Test(PLD, basic)
|
|||||||
snes.wram->_data[1] = 0xCD;
|
snes.wram->_data[1] = 0xCD;
|
||||||
snes.wram->_data[2] = 0x7B;
|
snes.wram->_data[2] = 0x7B;
|
||||||
snes.cpu->_registers.s = 0x00;
|
snes.cpu->_registers.s = 0x00;
|
||||||
snes.cpu->PLD();
|
snes.cpu->PLD(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.cpu->_registers.d;
|
auto data = snes.cpu->_registers.d;
|
||||||
cr_assert_eq(data, 0x7BCD, "The D register should be 0x7BCD but it was %x", data);
|
cr_assert_eq(data, 0x7BCD, "The D register should be 0x7BCD but it was %x", data);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.", snes.cpu->_registers.p.z);
|
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.", snes.cpu->_registers.p.z);
|
||||||
@@ -314,7 +329,7 @@ Test(PLD, zero)
|
|||||||
snes.wram->_data[1] = 0x00;
|
snes.wram->_data[1] = 0x00;
|
||||||
snes.wram->_data[2] = 0x00;
|
snes.wram->_data[2] = 0x00;
|
||||||
snes.cpu->_registers.s = 0x00;
|
snes.cpu->_registers.s = 0x00;
|
||||||
snes.cpu->PLD();
|
snes.cpu->PLD(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.cpu->_registers.d;
|
auto data = snes.cpu->_registers.d;
|
||||||
cr_assert_eq(data, 0x0000, "The d register should be 0x0000 but it was %x", data);
|
cr_assert_eq(data, 0x0000, "The d register should be 0x0000 but it was %x", data);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.", snes.cpu->_registers.p.z);
|
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.", snes.cpu->_registers.p.z);
|
||||||
@@ -328,7 +343,7 @@ Test(PLD, negative)
|
|||||||
snes.wram->_data[1] = 0x00;
|
snes.wram->_data[1] = 0x00;
|
||||||
snes.wram->_data[2] = 0xA0;
|
snes.wram->_data[2] = 0xA0;
|
||||||
snes.cpu->_registers.s = 0x00;
|
snes.cpu->_registers.s = 0x00;
|
||||||
snes.cpu->PLD();
|
snes.cpu->PLD(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.cpu->_registers.d;
|
auto data = snes.cpu->_registers.d;
|
||||||
cr_assert_eq(data, 0xA000, "The D register should be 0xA000 but it was %x", data);
|
cr_assert_eq(data, 0xA000, "The D register should be 0xA000 but it was %x", data);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag not should be set.", snes.cpu->_registers.p.z);
|
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag not should be set.", snes.cpu->_registers.p.z);
|
||||||
@@ -341,7 +356,7 @@ Test(PLB, basic)
|
|||||||
Init()
|
Init()
|
||||||
snes.wram->_data[1] = 0x7D;
|
snes.wram->_data[1] = 0x7D;
|
||||||
snes.cpu->_registers.s = 0x00;
|
snes.cpu->_registers.s = 0x00;
|
||||||
snes.cpu->PLB();
|
snes.cpu->PLB(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.cpu->_registers.dbr;
|
auto data = snes.cpu->_registers.dbr;
|
||||||
cr_assert_eq(data, 0x7D, "The DBR should be 0x7D but it was %x", data);
|
cr_assert_eq(data, 0x7D, "The DBR should be 0x7D but it was %x", data);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.", snes.cpu->_registers.p.z);
|
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.", snes.cpu->_registers.p.z);
|
||||||
@@ -354,7 +369,7 @@ Test(PLB, zero)
|
|||||||
Init()
|
Init()
|
||||||
snes.wram->_data[1] = 0x00;
|
snes.wram->_data[1] = 0x00;
|
||||||
snes.cpu->_registers.s = 0x00;
|
snes.cpu->_registers.s = 0x00;
|
||||||
snes.cpu->PLB();
|
snes.cpu->PLB(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.cpu->_registers.dbr;
|
auto data = snes.cpu->_registers.dbr;
|
||||||
cr_assert_eq(data, 0x00, "The dbr should be 0x00 but it was %x", data);
|
cr_assert_eq(data, 0x00, "The dbr should be 0x00 but it was %x", data);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.", snes.cpu->_registers.p.z);
|
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.", snes.cpu->_registers.p.z);
|
||||||
@@ -367,7 +382,7 @@ Test(PLB, negative)
|
|||||||
Init()
|
Init()
|
||||||
snes.wram->_data[1] = 0xA0;
|
snes.wram->_data[1] = 0xA0;
|
||||||
snes.cpu->_registers.s = 0x00;
|
snes.cpu->_registers.s = 0x00;
|
||||||
snes.cpu->PLB();
|
snes.cpu->PLB(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.cpu->_registers.dbr;
|
auto data = snes.cpu->_registers.dbr;
|
||||||
cr_assert_eq(data, 0xA0, "The D register should be 0xA0 but it was %x", data);
|
cr_assert_eq(data, 0xA0, "The D register should be 0xA0 but it was %x", data);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag not should be set.", snes.cpu->_registers.p.z);
|
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag not should be set.", snes.cpu->_registers.p.z);
|
||||||
@@ -381,7 +396,7 @@ Test(PLP, basic)
|
|||||||
snes.wram->_data[1] = 0x7D;
|
snes.wram->_data[1] = 0x7D;
|
||||||
snes.cpu->_registers.s = 0x00;
|
snes.cpu->_registers.s = 0x00;
|
||||||
snes.cpu->_isEmulationMode = false;
|
snes.cpu->_isEmulationMode = false;
|
||||||
snes.cpu->PLP();
|
snes.cpu->PLP(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.cpu->_registers.p.flags;
|
auto data = snes.cpu->_registers.p.flags;
|
||||||
cr_assert_eq(data, 0x7D, "The flags should be 0x7D but it was %x", data);
|
cr_assert_eq(data, 0x7D, "The flags should be 0x7D but it was %x", data);
|
||||||
cr_assert_eq(snes.cpu->_registers.s, 0x1, "The Stack pointer should be equal to 0x1 but it was %x", snes.cpu->_registers.s);
|
cr_assert_eq(snes.cpu->_registers.s, 0x1, "The Stack pointer should be equal to 0x1 but it was %x", snes.cpu->_registers.s);
|
||||||
@@ -393,7 +408,7 @@ Test(PLP, emulation)
|
|||||||
snes.wram->_data[1] = 0x00;
|
snes.wram->_data[1] = 0x00;
|
||||||
snes.cpu->_registers.s = 0x00;
|
snes.cpu->_registers.s = 0x00;
|
||||||
snes.cpu->_isEmulationMode = true;
|
snes.cpu->_isEmulationMode = true;
|
||||||
snes.cpu->PLP();
|
snes.cpu->PLP(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.cpu->_registers.p.flags;
|
auto data = snes.cpu->_registers.p.flags;
|
||||||
cr_assert_eq(data, 0b00110000, "The flags should be 0b00110000 but it was %x", data);
|
cr_assert_eq(data, 0b00110000, "The flags should be 0b00110000 but it was %x", data);
|
||||||
cr_assert_eq(snes.cpu->_registers.s, 0x1, "The Stack pointer should be equal to 0x1 but it was %x", snes.cpu->_registers.s);
|
cr_assert_eq(snes.cpu->_registers.s, 0x1, "The Stack pointer should be equal to 0x1 but it was %x", snes.cpu->_registers.s);
|
||||||
@@ -403,7 +418,7 @@ Test(CLC, clear)
|
|||||||
{
|
{
|
||||||
Init()
|
Init()
|
||||||
snes.cpu->_registers.p.flags = 0xFF;
|
snes.cpu->_registers.p.flags = 0xFF;
|
||||||
snes.cpu->CLC();
|
snes.cpu->CLC(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flag should not be set");
|
cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flag should not be set");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -411,7 +426,7 @@ Test(CLI, clear)
|
|||||||
{
|
{
|
||||||
Init()
|
Init()
|
||||||
snes.cpu->_registers.p.flags = 0xFF;
|
snes.cpu->_registers.p.flags = 0xFF;
|
||||||
snes.cpu->CLI();
|
snes.cpu->CLI(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.i, false, "The interrupt flag should not be set");
|
cr_assert_eq(snes.cpu->_registers.p.i, false, "The interrupt flag should not be set");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,7 +434,7 @@ Test(CLD, clear)
|
|||||||
{
|
{
|
||||||
Init()
|
Init()
|
||||||
snes.cpu->_registers.p.flags = 0xFF;
|
snes.cpu->_registers.p.flags = 0xFF;
|
||||||
snes.cpu->CLD();
|
snes.cpu->CLD(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -427,7 +442,7 @@ Test(CLV, clear)
|
|||||||
{
|
{
|
||||||
Init()
|
Init()
|
||||||
snes.cpu->_registers.p.flags = 0xFF;
|
snes.cpu->_registers.p.flags = 0xFF;
|
||||||
snes.cpu->CLV();
|
snes.cpu->CLV(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.v, false, "The overflow flag should not be set");
|
cr_assert_eq(snes.cpu->_registers.p.v, false, "The overflow flag should not be set");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -435,7 +450,7 @@ Test(SEC, set)
|
|||||||
{
|
{
|
||||||
Init()
|
Init()
|
||||||
snes.cpu->_registers.p.flags = 0x00;
|
snes.cpu->_registers.p.flags = 0x00;
|
||||||
snes.cpu->SEC();
|
snes.cpu->SEC(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.c, true, "The carry flag should be set");
|
cr_assert_eq(snes.cpu->_registers.p.c, true, "The carry flag should be set");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -443,7 +458,7 @@ Test(SEI, set)
|
|||||||
{
|
{
|
||||||
Init()
|
Init()
|
||||||
snes.cpu->_registers.p.flags = 0x00;
|
snes.cpu->_registers.p.flags = 0x00;
|
||||||
snes.cpu->SEI();
|
snes.cpu->SEI(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.i, true, "The interrupt disabled flag should be set");
|
cr_assert_eq(snes.cpu->_registers.p.i, true, "The interrupt disabled flag should be set");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -451,7 +466,7 @@ Test(SED, set)
|
|||||||
{
|
{
|
||||||
Init()
|
Init()
|
||||||
snes.cpu->_registers.p.flags = 0x00;
|
snes.cpu->_registers.p.flags = 0x00;
|
||||||
snes.cpu->SED();
|
snes.cpu->SED(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.d, true, "The decimal flag should be set");
|
cr_assert_eq(snes.cpu->_registers.p.d, true, "The decimal flag should be set");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -463,7 +478,7 @@ Test(XCE, enableEmulation)
|
|||||||
snes.cpu->_registers.p.c = true;
|
snes.cpu->_registers.p.c = true;
|
||||||
snes.cpu->_registers.xh = 0xFF;
|
snes.cpu->_registers.xh = 0xFF;
|
||||||
snes.cpu->_registers.yh = 0xFF;
|
snes.cpu->_registers.yh = 0xFF;
|
||||||
snes.cpu->XCE();
|
snes.cpu->XCE(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_isEmulationMode, true, "The e flag should be set");
|
cr_assert_eq(snes.cpu->_isEmulationMode, true, "The e flag should be set");
|
||||||
cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flag should not be set");
|
cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flag should not be set");
|
||||||
cr_assert_eq(snes.cpu->_registers.p.m, false, "The memory width flag should be untouched (unset)");
|
cr_assert_eq(snes.cpu->_registers.p.m, false, "The memory width flag should be untouched (unset)");
|
||||||
@@ -479,7 +494,7 @@ Test(XCE, enableNative)
|
|||||||
snes.cpu->_registers.p.flags = 0;
|
snes.cpu->_registers.p.flags = 0;
|
||||||
snes.cpu->_registers.xh = 0xFF;
|
snes.cpu->_registers.xh = 0xFF;
|
||||||
snes.cpu->_registers.yh = 0xFF;
|
snes.cpu->_registers.yh = 0xFF;
|
||||||
snes.cpu->XCE();
|
snes.cpu->XCE(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_isEmulationMode, false, "The e flag should be not set");
|
cr_assert_eq(snes.cpu->_isEmulationMode, false, "The e flag should be not set");
|
||||||
cr_assert_eq(snes.cpu->_registers.p.c, true, "The carry flag should be set");
|
cr_assert_eq(snes.cpu->_registers.p.c, true, "The carry flag should be set");
|
||||||
cr_assert_eq(snes.cpu->_registers.p.m, true, "The memory width flag should be set");
|
cr_assert_eq(snes.cpu->_registers.p.m, true, "The memory width flag should be set");
|
||||||
@@ -495,7 +510,7 @@ Test(INX, basic)
|
|||||||
snes.cpu->_registers.p.flags = 0;
|
snes.cpu->_registers.p.flags = 0;
|
||||||
snes.cpu->_registers.p.x_b = false;
|
snes.cpu->_registers.p.x_b = false;
|
||||||
snes.cpu->_registers.x = 0xFF;
|
snes.cpu->_registers.x = 0xFF;
|
||||||
snes.cpu->INX();
|
snes.cpu->INX(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.x, 0x0100, "The x register should be equal to 0x0100 but it was 0x%x.", snes.cpu->_registers.x);
|
cr_assert_eq(snes.cpu->_registers.x, 0x0100, "The x register should be equal to 0x0100 but it was 0x%x.", snes.cpu->_registers.x);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set");
|
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set");
|
||||||
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");
|
||||||
@@ -508,7 +523,7 @@ Test(INX, 8bits)
|
|||||||
snes.cpu->_registers.p.flags = 0;
|
snes.cpu->_registers.p.flags = 0;
|
||||||
snes.cpu->_registers.p.x_b = true;
|
snes.cpu->_registers.p.x_b = true;
|
||||||
snes.cpu->_registers.x = 0xFF;
|
snes.cpu->_registers.x = 0xFF;
|
||||||
snes.cpu->INX();
|
snes.cpu->INX(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.x, 0x00, "The x register should be equal to 0x00 but it was 0x%x.", snes.cpu->_registers.x);
|
cr_assert_eq(snes.cpu->_registers.x, 0x00, "The x register should be equal to 0x00 but it was 0x%x.", snes.cpu->_registers.x);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set");
|
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set");
|
||||||
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");
|
||||||
@@ -521,7 +536,7 @@ Test(INY, basic)
|
|||||||
snes.cpu->_registers.p.flags = 0;
|
snes.cpu->_registers.p.flags = 0;
|
||||||
snes.cpu->_registers.p.x_b = false;
|
snes.cpu->_registers.p.x_b = false;
|
||||||
snes.cpu->_registers.y = 0xFF;
|
snes.cpu->_registers.y = 0xFF;
|
||||||
snes.cpu->INY();
|
snes.cpu->INY(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.y, 0x0100, "The y register should be equal to 0x0100 but it was 0x%x.", snes.cpu->_registers.y);
|
cr_assert_eq(snes.cpu->_registers.y, 0x0100, "The y register should be equal to 0x0100 but it was 0x%x.", snes.cpu->_registers.y);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set");
|
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set");
|
||||||
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");
|
||||||
@@ -534,7 +549,7 @@ Test(INY, 8bits)
|
|||||||
snes.cpu->_registers.p.flags = 0;
|
snes.cpu->_registers.p.flags = 0;
|
||||||
snes.cpu->_registers.p.x_b = true;
|
snes.cpu->_registers.p.x_b = true;
|
||||||
snes.cpu->_registers.y = 0xFF;
|
snes.cpu->_registers.y = 0xFF;
|
||||||
snes.cpu->INY();
|
snes.cpu->INY(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.y, 0x00, "The y register should be equal to 0x00 but it was 0x%x.", snes.cpu->_registers.y);
|
cr_assert_eq(snes.cpu->_registers.y, 0x00, "The y register should be equal to 0x00 but it was 0x%x.", snes.cpu->_registers.y);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set");
|
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set");
|
||||||
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");
|
||||||
@@ -547,7 +562,7 @@ Test(CPX, basic)
|
|||||||
snes.cpu->_registers.p.flags = 0;
|
snes.cpu->_registers.p.flags = 0;
|
||||||
snes.cpu->_registers.x = 0xFF;
|
snes.cpu->_registers.x = 0xFF;
|
||||||
snes.wram->_data[0] = 0xFF;
|
snes.wram->_data[0] = 0xFF;
|
||||||
snes.cpu->CPX(0x0);
|
snes.cpu->CPX(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set");
|
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set");
|
||||||
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");
|
||||||
cr_assert_eq(snes.cpu->_registers.p.c, true, "The carry flag should be set");
|
cr_assert_eq(snes.cpu->_registers.p.c, true, "The carry flag should be set");
|
||||||
@@ -560,7 +575,7 @@ Test(CPX, negative)
|
|||||||
snes.cpu->_registers.p.flags = 0;
|
snes.cpu->_registers.p.flags = 0;
|
||||||
snes.cpu->_registers.x = 0x80;
|
snes.cpu->_registers.x = 0x80;
|
||||||
snes.wram->_data[0] = 0xFF;
|
snes.wram->_data[0] = 0xFF;
|
||||||
snes.cpu->CPX(0x0);
|
snes.cpu->CPX(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set");
|
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set");
|
||||||
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.c, false, "The carry flag should not be set");
|
cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flag should not be set");
|
||||||
@@ -574,7 +589,7 @@ Test(CPX, 16bits)
|
|||||||
snes.cpu->_registers.x = 0x8888;
|
snes.cpu->_registers.x = 0x8888;
|
||||||
snes.wram->_data[0] = 0x88;
|
snes.wram->_data[0] = 0x88;
|
||||||
snes.wram->_data[1] = 0x98;
|
snes.wram->_data[1] = 0x98;
|
||||||
snes.cpu->CPX(0x0);
|
snes.cpu->CPX(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set");
|
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set");
|
||||||
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.c, false, "The carry flag should not be set");
|
cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flag should not be set");
|
||||||
@@ -587,7 +602,7 @@ Test(CPY, basic)
|
|||||||
snes.cpu->_registers.p.flags = 0;
|
snes.cpu->_registers.p.flags = 0;
|
||||||
snes.cpu->_registers.y = 0xFF;
|
snes.cpu->_registers.y = 0xFF;
|
||||||
snes.wram->_data[0] = 0xFF;
|
snes.wram->_data[0] = 0xFF;
|
||||||
snes.cpu->CPY(0x0);
|
snes.cpu->CPY(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set");
|
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set");
|
||||||
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");
|
||||||
cr_assert_eq(snes.cpu->_registers.p.c, true, "The carry flag should be set");
|
cr_assert_eq(snes.cpu->_registers.p.c, true, "The carry flag should be set");
|
||||||
@@ -600,7 +615,7 @@ Test(CPY, negative)
|
|||||||
snes.cpu->_registers.p.flags = 0;
|
snes.cpu->_registers.p.flags = 0;
|
||||||
snes.cpu->_registers.y = 0x80;
|
snes.cpu->_registers.y = 0x80;
|
||||||
snes.wram->_data[0] = 0xFF;
|
snes.wram->_data[0] = 0xFF;
|
||||||
snes.cpu->CPY(0x0);
|
snes.cpu->CPY(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set");
|
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set");
|
||||||
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.c, false, "The carry flag should not be set");
|
cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flag should not be set");
|
||||||
@@ -612,7 +627,7 @@ Test(BCC, basic)
|
|||||||
snes.cpu->_registers.p.c = false;
|
snes.cpu->_registers.p.c = false;
|
||||||
snes.cpu->_registers.pc = 0x80;
|
snes.cpu->_registers.pc = 0x80;
|
||||||
snes.wram->_data[0] = 0x50;
|
snes.wram->_data[0] = 0x50;
|
||||||
snes.cpu->BCC(0x0);
|
snes.cpu->BCC(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", snes.cpu->_registers.pc);
|
cr_assert_eq(snes.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", snes.cpu->_registers.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -622,7 +637,7 @@ Test(BCC, negativeJump)
|
|||||||
snes.cpu->_registers.p.c = false;
|
snes.cpu->_registers.p.c = false;
|
||||||
snes.cpu->_registers.pc = 0x80;
|
snes.cpu->_registers.pc = 0x80;
|
||||||
snes.wram->_data[0] = 0xF0;
|
snes.wram->_data[0] = 0xF0;
|
||||||
snes.cpu->BCC(0x0);
|
snes.cpu->BCC(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", snes.cpu->_registers.pc);
|
cr_assert_eq(snes.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", snes.cpu->_registers.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -632,7 +647,7 @@ Test(BCC, noJump)
|
|||||||
snes.cpu->_registers.p.c = true;
|
snes.cpu->_registers.p.c = true;
|
||||||
snes.cpu->_registers.pc = 0x80;
|
snes.cpu->_registers.pc = 0x80;
|
||||||
snes.wram->_data[0] = 0x90;
|
snes.wram->_data[0] = 0x90;
|
||||||
snes.cpu->BCC(0x0);
|
snes.cpu->BCC(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", snes.cpu->_registers.pc);
|
cr_assert_eq(snes.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", snes.cpu->_registers.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -642,7 +657,7 @@ Test(BCS, basic)
|
|||||||
snes.cpu->_registers.p.c = true;
|
snes.cpu->_registers.p.c = true;
|
||||||
snes.cpu->_registers.pc = 0x80;
|
snes.cpu->_registers.pc = 0x80;
|
||||||
snes.wram->_data[0] = 0x50;
|
snes.wram->_data[0] = 0x50;
|
||||||
snes.cpu->BCS(0x0);
|
snes.cpu->BCS(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", snes.cpu->_registers.pc);
|
cr_assert_eq(snes.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", snes.cpu->_registers.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -652,7 +667,7 @@ Test(BCS, negativeJump)
|
|||||||
snes.cpu->_registers.p.c = true;
|
snes.cpu->_registers.p.c = true;
|
||||||
snes.cpu->_registers.pc = 0x80;
|
snes.cpu->_registers.pc = 0x80;
|
||||||
snes.wram->_data[0] = 0xF0;
|
snes.wram->_data[0] = 0xF0;
|
||||||
snes.cpu->BCS(0x0);
|
snes.cpu->BCS(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", snes.cpu->_registers.pc);
|
cr_assert_eq(snes.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", snes.cpu->_registers.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -662,7 +677,7 @@ Test(BCS, noJump)
|
|||||||
snes.cpu->_registers.p.c = false;
|
snes.cpu->_registers.p.c = false;
|
||||||
snes.cpu->_registers.pc = 0x80;
|
snes.cpu->_registers.pc = 0x80;
|
||||||
snes.wram->_data[0] = 0x90;
|
snes.wram->_data[0] = 0x90;
|
||||||
snes.cpu->BCS(0x0);
|
snes.cpu->BCS(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", snes.cpu->_registers.pc);
|
cr_assert_eq(snes.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", snes.cpu->_registers.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -672,7 +687,7 @@ Test(BEQ, basic)
|
|||||||
snes.cpu->_registers.p.z = true;
|
snes.cpu->_registers.p.z = true;
|
||||||
snes.cpu->_registers.pc = 0x80;
|
snes.cpu->_registers.pc = 0x80;
|
||||||
snes.wram->_data[0] = 0x50;
|
snes.wram->_data[0] = 0x50;
|
||||||
snes.cpu->BEQ(0x0);
|
snes.cpu->BEQ(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", snes.cpu->_registers.pc);
|
cr_assert_eq(snes.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", snes.cpu->_registers.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -682,7 +697,7 @@ Test(BEQ, negativeJump)
|
|||||||
snes.cpu->_registers.p.z = true;
|
snes.cpu->_registers.p.z = true;
|
||||||
snes.cpu->_registers.pc = 0x80;
|
snes.cpu->_registers.pc = 0x80;
|
||||||
snes.wram->_data[0] = 0xF0;
|
snes.wram->_data[0] = 0xF0;
|
||||||
snes.cpu->BEQ(0x0);
|
snes.cpu->BEQ(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", snes.cpu->_registers.pc);
|
cr_assert_eq(snes.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", snes.cpu->_registers.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -692,7 +707,7 @@ Test(BEQ, noJump)
|
|||||||
snes.cpu->_registers.p.z = false;
|
snes.cpu->_registers.p.z = false;
|
||||||
snes.cpu->_registers.pc = 0x80;
|
snes.cpu->_registers.pc = 0x80;
|
||||||
snes.wram->_data[0] = 0x90;
|
snes.wram->_data[0] = 0x90;
|
||||||
snes.cpu->BEQ(0x0);
|
snes.cpu->BEQ(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", snes.cpu->_registers.pc);
|
cr_assert_eq(snes.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", snes.cpu->_registers.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -702,7 +717,7 @@ Test(BNE, basic)
|
|||||||
snes.cpu->_registers.p.z = false;
|
snes.cpu->_registers.p.z = false;
|
||||||
snes.cpu->_registers.pc = 0x80;
|
snes.cpu->_registers.pc = 0x80;
|
||||||
snes.wram->_data[0] = 0x50;
|
snes.wram->_data[0] = 0x50;
|
||||||
snes.cpu->BNE(0x0);
|
snes.cpu->BNE(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", snes.cpu->_registers.pc);
|
cr_assert_eq(snes.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", snes.cpu->_registers.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -712,7 +727,7 @@ Test(BNE, negativeJump)
|
|||||||
snes.cpu->_registers.p.z = false;
|
snes.cpu->_registers.p.z = false;
|
||||||
snes.cpu->_registers.pc = 0x80;
|
snes.cpu->_registers.pc = 0x80;
|
||||||
snes.wram->_data[0] = 0xF0;
|
snes.wram->_data[0] = 0xF0;
|
||||||
snes.cpu->BNE(0x0);
|
snes.cpu->BNE(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", snes.cpu->_registers.pc);
|
cr_assert_eq(snes.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", snes.cpu->_registers.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -722,7 +737,7 @@ Test(BNE, noJump)
|
|||||||
snes.cpu->_registers.p.z = true;
|
snes.cpu->_registers.p.z = true;
|
||||||
snes.cpu->_registers.pc = 0x80;
|
snes.cpu->_registers.pc = 0x80;
|
||||||
snes.wram->_data[0] = 0x90;
|
snes.wram->_data[0] = 0x90;
|
||||||
snes.cpu->BNE(0x0);
|
snes.cpu->BNE(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", snes.cpu->_registers.pc);
|
cr_assert_eq(snes.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", snes.cpu->_registers.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -732,7 +747,7 @@ Test(BMI, basic)
|
|||||||
snes.cpu->_registers.p.n = true;
|
snes.cpu->_registers.p.n = true;
|
||||||
snes.cpu->_registers.pc = 0x80;
|
snes.cpu->_registers.pc = 0x80;
|
||||||
snes.wram->_data[0] = 0x50;
|
snes.wram->_data[0] = 0x50;
|
||||||
snes.cpu->BMI(0x0);
|
snes.cpu->BMI(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", snes.cpu->_registers.pc);
|
cr_assert_eq(snes.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", snes.cpu->_registers.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -742,7 +757,7 @@ Test(BMI, negativeJump)
|
|||||||
snes.cpu->_registers.p.n = true;
|
snes.cpu->_registers.p.n = true;
|
||||||
snes.cpu->_registers.pc = 0x80;
|
snes.cpu->_registers.pc = 0x80;
|
||||||
snes.wram->_data[0] = 0xF0;
|
snes.wram->_data[0] = 0xF0;
|
||||||
snes.cpu->BMI(0x0);
|
snes.cpu->BMI(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", snes.cpu->_registers.pc);
|
cr_assert_eq(snes.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", snes.cpu->_registers.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -752,7 +767,7 @@ Test(BMI, noJump)
|
|||||||
snes.cpu->_registers.p.n = false;
|
snes.cpu->_registers.p.n = false;
|
||||||
snes.cpu->_registers.pc = 0x80;
|
snes.cpu->_registers.pc = 0x80;
|
||||||
snes.wram->_data[0] = 0x90;
|
snes.wram->_data[0] = 0x90;
|
||||||
snes.cpu->BMI(0x0);
|
snes.cpu->BMI(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", snes.cpu->_registers.pc);
|
cr_assert_eq(snes.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", snes.cpu->_registers.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -762,7 +777,7 @@ Test(BPL, basic)
|
|||||||
snes.cpu->_registers.p.n = false;
|
snes.cpu->_registers.p.n = false;
|
||||||
snes.cpu->_registers.pc = 0x80;
|
snes.cpu->_registers.pc = 0x80;
|
||||||
snes.wram->_data[0] = 0x50;
|
snes.wram->_data[0] = 0x50;
|
||||||
snes.cpu->BPL(0x0);
|
snes.cpu->BPL(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", snes.cpu->_registers.pc);
|
cr_assert_eq(snes.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", snes.cpu->_registers.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -772,7 +787,7 @@ Test(BPL, negativeJump)
|
|||||||
snes.cpu->_registers.p.n = false;
|
snes.cpu->_registers.p.n = false;
|
||||||
snes.cpu->_registers.pc = 0x80;
|
snes.cpu->_registers.pc = 0x80;
|
||||||
snes.wram->_data[0] = 0xF0;
|
snes.wram->_data[0] = 0xF0;
|
||||||
snes.cpu->BPL(0x0);
|
snes.cpu->BPL(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", snes.cpu->_registers.pc);
|
cr_assert_eq(snes.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", snes.cpu->_registers.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -782,7 +797,7 @@ Test(BPL, noJump)
|
|||||||
snes.cpu->_registers.p.n = true;
|
snes.cpu->_registers.p.n = true;
|
||||||
snes.cpu->_registers.pc = 0x80;
|
snes.cpu->_registers.pc = 0x80;
|
||||||
snes.wram->_data[0] = 0x90;
|
snes.wram->_data[0] = 0x90;
|
||||||
snes.cpu->BPL(0x0);
|
snes.cpu->BPL(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", snes.cpu->_registers.pc);
|
cr_assert_eq(snes.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", snes.cpu->_registers.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -791,7 +806,7 @@ Test(BRA, basic)
|
|||||||
Init()
|
Init()
|
||||||
snes.cpu->_registers.pc = 0x80;
|
snes.cpu->_registers.pc = 0x80;
|
||||||
snes.wram->_data[0] = 0x50;
|
snes.wram->_data[0] = 0x50;
|
||||||
snes.cpu->BRA(0x0);
|
snes.cpu->BRA(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", snes.cpu->_registers.pc);
|
cr_assert_eq(snes.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", snes.cpu->_registers.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -800,7 +815,7 @@ Test(BRA, negativeJump)
|
|||||||
Init()
|
Init()
|
||||||
snes.cpu->_registers.pc = 0x80;
|
snes.cpu->_registers.pc = 0x80;
|
||||||
snes.wram->_data[0] = 0xF0;
|
snes.wram->_data[0] = 0xF0;
|
||||||
snes.cpu->BRA(0x0);
|
snes.cpu->BRA(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", snes.cpu->_registers.pc);
|
cr_assert_eq(snes.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", snes.cpu->_registers.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -810,7 +825,7 @@ Test(BRL, basic)
|
|||||||
snes.cpu->_registers.pc = 0x8080;
|
snes.cpu->_registers.pc = 0x8080;
|
||||||
snes.wram->_data[0] = 0x00;
|
snes.wram->_data[0] = 0x00;
|
||||||
snes.wram->_data[1] = 0x10;
|
snes.wram->_data[1] = 0x10;
|
||||||
snes.cpu->BRL(0x0);
|
snes.cpu->BRL(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.pc, 0x9080, "The program counter should be equal to 0x9080 but it was 0x%x.", snes.cpu->_registers.pc);
|
cr_assert_eq(snes.cpu->_registers.pc, 0x9080, "The program counter should be equal to 0x9080 but it was 0x%x.", snes.cpu->_registers.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -820,7 +835,7 @@ Test(BRL, negativeJump)
|
|||||||
snes.cpu->_registers.pc = 0x8080;
|
snes.cpu->_registers.pc = 0x8080;
|
||||||
snes.wram->_data[0] = 0x00;
|
snes.wram->_data[0] = 0x00;
|
||||||
snes.wram->_data[1] = 0xF0;
|
snes.wram->_data[1] = 0xF0;
|
||||||
snes.cpu->BRL(0x0);
|
snes.cpu->BRL(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.pc, 0x7080, "The program counter should be equal to 0x7080 but it was 0x%x.", snes.cpu->_registers.pc);
|
cr_assert_eq(snes.cpu->_registers.pc, 0x7080, "The program counter should be equal to 0x7080 but it was 0x%x.", snes.cpu->_registers.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -830,7 +845,7 @@ Test(BVC, basic)
|
|||||||
snes.cpu->_registers.p.v = false;
|
snes.cpu->_registers.p.v = false;
|
||||||
snes.cpu->_registers.pc = 0x80;
|
snes.cpu->_registers.pc = 0x80;
|
||||||
snes.wram->_data[0] = 0x50;
|
snes.wram->_data[0] = 0x50;
|
||||||
snes.cpu->BVC(0x0);
|
snes.cpu->BVC(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", snes.cpu->_registers.pc);
|
cr_assert_eq(snes.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", snes.cpu->_registers.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -840,7 +855,7 @@ Test(BVC, negativeJump)
|
|||||||
snes.cpu->_registers.p.v = false;
|
snes.cpu->_registers.p.v = false;
|
||||||
snes.cpu->_registers.pc = 0x80;
|
snes.cpu->_registers.pc = 0x80;
|
||||||
snes.wram->_data[0] = 0xF0;
|
snes.wram->_data[0] = 0xF0;
|
||||||
snes.cpu->BVC(0x0);
|
snes.cpu->BVC(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", snes.cpu->_registers.pc);
|
cr_assert_eq(snes.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", snes.cpu->_registers.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -850,7 +865,7 @@ Test(BVC, noJump)
|
|||||||
snes.cpu->_registers.p.v = true;
|
snes.cpu->_registers.p.v = true;
|
||||||
snes.cpu->_registers.pc = 0x80;
|
snes.cpu->_registers.pc = 0x80;
|
||||||
snes.wram->_data[0] = 0x90;
|
snes.wram->_data[0] = 0x90;
|
||||||
snes.cpu->BVC(0x0);
|
snes.cpu->BVC(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", snes.cpu->_registers.pc);
|
cr_assert_eq(snes.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", snes.cpu->_registers.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -861,7 +876,7 @@ Test(BVS, basic)
|
|||||||
snes.cpu->_registers.p.v = true;
|
snes.cpu->_registers.p.v = true;
|
||||||
snes.cpu->_registers.pc = 0x80;
|
snes.cpu->_registers.pc = 0x80;
|
||||||
snes.wram->_data[0] = 0x50;
|
snes.wram->_data[0] = 0x50;
|
||||||
snes.cpu->BVS(0x0);
|
snes.cpu->BVS(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", snes.cpu->_registers.pc);
|
cr_assert_eq(snes.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", snes.cpu->_registers.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -871,7 +886,7 @@ Test(BVS, negativeJump)
|
|||||||
snes.cpu->_registers.p.v = true;
|
snes.cpu->_registers.p.v = true;
|
||||||
snes.cpu->_registers.pc = 0x80;
|
snes.cpu->_registers.pc = 0x80;
|
||||||
snes.wram->_data[0] = 0xF0;
|
snes.wram->_data[0] = 0xF0;
|
||||||
snes.cpu->BVS(0x0);
|
snes.cpu->BVS(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", snes.cpu->_registers.pc);
|
cr_assert_eq(snes.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", snes.cpu->_registers.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -881,7 +896,7 @@ Test(BVS, noJump)
|
|||||||
snes.cpu->_registers.p.v = false;
|
snes.cpu->_registers.p.v = false;
|
||||||
snes.cpu->_registers.pc = 0x80;
|
snes.cpu->_registers.pc = 0x80;
|
||||||
snes.wram->_data[0] = 0x90;
|
snes.wram->_data[0] = 0x90;
|
||||||
snes.cpu->BVS(0x0);
|
snes.cpu->BVS(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", snes.cpu->_registers.pc);
|
cr_assert_eq(snes.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", snes.cpu->_registers.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -889,7 +904,7 @@ Test(JMP, simpleJump)
|
|||||||
{
|
{
|
||||||
Init()
|
Init()
|
||||||
snes.cpu->_registers.pc = 0x8000;
|
snes.cpu->_registers.pc = 0x8000;
|
||||||
snes.cpu->JMP(0x1000);
|
snes.cpu->JMP(0x1000, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.pc, 0x1000, "The program counter should be equal to 0x9000 but it was 0x%x.", snes.cpu->_registers.pc);
|
cr_assert_eq(snes.cpu->_registers.pc, 0x1000, "The program counter should be equal to 0x9000 but it was 0x%x.", snes.cpu->_registers.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -897,6 +912,6 @@ Test(JML, simpleJump)
|
|||||||
{
|
{
|
||||||
Init()
|
Init()
|
||||||
snes.cpu->_registers.pc = 0x8000;
|
snes.cpu->_registers.pc = 0x8000;
|
||||||
snes.cpu->JML(0x10AB00);
|
snes.cpu->JML(0x10AB00, ComSquare::CPU::AddressingMode::Implied);
|
||||||
cr_assert_eq(snes.cpu->_registers.pac, 0x10AB00, "The program counter should be equal to 0x10AB00 but it was 0x%x.", snes.cpu->_registers.pac);
|
cr_assert_eq(snes.cpu->_registers.pac, 0x10AB00, "The program counter should be equal to 0x10AB00 but it was 0x%x.", snes.cpu->_registers.pac);
|
||||||
}
|
}
|
||||||
@@ -18,7 +18,7 @@ Test(CPU_emulated, BRK)
|
|||||||
snes.cpu->_registers.p.flags = 0xF1;
|
snes.cpu->_registers.p.flags = 0xF1;
|
||||||
snes.cpu->_registers.pc = 0x156u;
|
snes.cpu->_registers.pc = 0x156u;
|
||||||
snes.cpu->_registers.pbr = 0x15;
|
snes.cpu->_registers.pbr = 0x15;
|
||||||
snes.cpu->BRK();
|
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, 0x15, "The PBR should be 0x15 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.");
|
||||||
@@ -38,7 +38,7 @@ Test(CPU_native, BRK)
|
|||||||
snes.cpu->_registers.p.flags = 0xF1;
|
snes.cpu->_registers.p.flags = 0xF1;
|
||||||
snes.cpu->_registers.pc = 0x156u;
|
snes.cpu->_registers.pc = 0x156u;
|
||||||
snes.cpu->_registers.pbr = 0x15;
|
snes.cpu->_registers.pbr = 0x15;
|
||||||
snes.cpu->BRK();
|
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, 0x0, "The PBR should be 0x0 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.");
|
||||||
@@ -59,7 +59,7 @@ Test(CPU_emulated, COP)
|
|||||||
snes.cpu->_registers.p.flags = 0x0F;
|
snes.cpu->_registers.p.flags = 0x0F;
|
||||||
snes.cpu->_registers.pc = 0x156u;
|
snes.cpu->_registers.pc = 0x156u;
|
||||||
snes.cpu->_registers.pbr = 0x15;
|
snes.cpu->_registers.pbr = 0x15;
|
||||||
snes.cpu->COP();
|
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, 0x15, "The PBR should be 0x15 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.");
|
||||||
@@ -79,7 +79,7 @@ Test(CPU_native, COP)
|
|||||||
snes.cpu->_registers.p.flags = 0xF1;
|
snes.cpu->_registers.p.flags = 0xF1;
|
||||||
snes.cpu->_registers.pc = 0x156u;
|
snes.cpu->_registers.pc = 0x156u;
|
||||||
snes.cpu->_registers.pbr = 0x15;
|
snes.cpu->_registers.pbr = 0x15;
|
||||||
snes.cpu->COP();
|
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, 0x0, "The PBR should be 0x0 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.");
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ Test(STA, 8bits)
|
|||||||
Init()
|
Init()
|
||||||
snes.cpu->_registers.p.m = true;
|
snes.cpu->_registers.p.m = true;
|
||||||
snes.cpu->_registers.a = 0x11;
|
snes.cpu->_registers.a = 0x11;
|
||||||
snes.cpu->STA(0x0);
|
snes.cpu->STA(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.wram->_data[0];
|
auto data = snes.wram->_data[0];
|
||||||
cr_assert_eq(data, 0x11, "The stored value should be 0x11 but it was 0x%x.", data);
|
cr_assert_eq(data, 0x11, "The stored value should be 0x11 but it was 0x%x.", data);
|
||||||
}
|
}
|
||||||
@@ -24,7 +24,7 @@ Test(STA, 16bits)
|
|||||||
Init()
|
Init()
|
||||||
snes.cpu->_registers.p.m = false;
|
snes.cpu->_registers.p.m = false;
|
||||||
snes.cpu->_registers.a = 0x11AB;
|
snes.cpu->_registers.a = 0x11AB;
|
||||||
snes.cpu->STA(0x0);
|
snes.cpu->STA(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.wram->_data[0] + (snes.wram->_data[1] << 8u);
|
auto data = snes.wram->_data[0] + (snes.wram->_data[1] << 8u);
|
||||||
cr_assert_eq(data, 0x11AB, "The stored value should be 0x11AB but it was 0x%x.", data);
|
cr_assert_eq(data, 0x11AB, "The stored value should be 0x11AB but it was 0x%x.", data);
|
||||||
}
|
}
|
||||||
@@ -34,7 +34,7 @@ Test(STX, 8bits)
|
|||||||
Init()
|
Init()
|
||||||
snes.cpu->_registers.p.x_b = true;
|
snes.cpu->_registers.p.x_b = true;
|
||||||
snes.cpu->_registers.x = 0x11;
|
snes.cpu->_registers.x = 0x11;
|
||||||
snes.cpu->STX(0x0);
|
snes.cpu->STX(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.wram->_data[0];
|
auto data = snes.wram->_data[0];
|
||||||
cr_assert_eq(data, 0x11, "The stored value should be 0x11 but it was 0x%x.", data);
|
cr_assert_eq(data, 0x11, "The stored value should be 0x11 but it was 0x%x.", data);
|
||||||
}
|
}
|
||||||
@@ -44,7 +44,7 @@ Test(STX, 16bits)
|
|||||||
Init()
|
Init()
|
||||||
snes.cpu->_registers.p.x_b = false;
|
snes.cpu->_registers.p.x_b = false;
|
||||||
snes.cpu->_registers.x = 0x11AB;
|
snes.cpu->_registers.x = 0x11AB;
|
||||||
snes.cpu->STX(0x0);
|
snes.cpu->STX(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.wram->_data[0] + (snes.wram->_data[1] << 8u);
|
auto data = snes.wram->_data[0] + (snes.wram->_data[1] << 8u);
|
||||||
cr_assert_eq(data, 0x11AB, "The stored value should be 0x11AB but it was 0x%x.", data);
|
cr_assert_eq(data, 0x11AB, "The stored value should be 0x11AB but it was 0x%x.", data);
|
||||||
}
|
}
|
||||||
@@ -54,7 +54,7 @@ Test(STY, 8bits)
|
|||||||
Init()
|
Init()
|
||||||
snes.cpu->_registers.p.x_b = true;
|
snes.cpu->_registers.p.x_b = true;
|
||||||
snes.cpu->_registers.y = 0x11;
|
snes.cpu->_registers.y = 0x11;
|
||||||
snes.cpu->STY(0x0);
|
snes.cpu->STY(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.wram->_data[0];
|
auto data = snes.wram->_data[0];
|
||||||
cr_assert_eq(data, 0x11, "The stored value should be 0x11 but it was 0x%x.", data);
|
cr_assert_eq(data, 0x11, "The stored value should be 0x11 but it was 0x%x.", data);
|
||||||
}
|
}
|
||||||
@@ -64,7 +64,7 @@ Test(STY, 16bits)
|
|||||||
Init()
|
Init()
|
||||||
snes.cpu->_registers.p.x_b = false;
|
snes.cpu->_registers.p.x_b = false;
|
||||||
snes.cpu->_registers.y = 0x11AB;
|
snes.cpu->_registers.y = 0x11AB;
|
||||||
snes.cpu->STY(0x0);
|
snes.cpu->STY(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.wram->_data[0] + (snes.wram->_data[1] << 8u);
|
auto data = snes.wram->_data[0] + (snes.wram->_data[1] << 8u);
|
||||||
cr_assert_eq(data, 0x11AB, "The stored value should be 0x11AB but it was 0x%x.", data);
|
cr_assert_eq(data, 0x11AB, "The stored value should be 0x11AB but it was 0x%x.", data);
|
||||||
}
|
}
|
||||||
@@ -74,7 +74,7 @@ Test(STZ, 8bits)
|
|||||||
Init()
|
Init()
|
||||||
snes.cpu->_registers.p.m = true;
|
snes.cpu->_registers.p.m = true;
|
||||||
snes.wram->_data[0] = 0x11;
|
snes.wram->_data[0] = 0x11;
|
||||||
snes.cpu->STZ(0x0);
|
snes.cpu->STZ(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.wram->_data[0];
|
auto data = snes.wram->_data[0];
|
||||||
cr_assert_eq(data, 0x00, "The stored value should be 0x00 but it was 0x%x.", data);
|
cr_assert_eq(data, 0x00, "The stored value should be 0x00 but it was 0x%x.", data);
|
||||||
}
|
}
|
||||||
@@ -85,7 +85,7 @@ Test(STZ, 16bits)
|
|||||||
snes.cpu->_registers.p.m = false;
|
snes.cpu->_registers.p.m = false;
|
||||||
snes.wram->_data[0] = 0x11;
|
snes.wram->_data[0] = 0x11;
|
||||||
snes.wram->_data[1] = 0x11;
|
snes.wram->_data[1] = 0x11;
|
||||||
snes.cpu->STZ(0x0);
|
snes.cpu->STZ(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.wram->_data[0] + (snes.wram->_data[1] << 8u);
|
auto data = snes.wram->_data[0] + (snes.wram->_data[1] << 8u);
|
||||||
cr_assert_eq(data, 0x00, "The stored value should be 0x00 but it was 0x%x.", data);
|
cr_assert_eq(data, 0x00, "The stored value should be 0x00 but it was 0x%x.", data);
|
||||||
}
|
}
|
||||||
@@ -95,7 +95,7 @@ Test(LDX, 8bits)
|
|||||||
Init()
|
Init()
|
||||||
snes.cpu->_registers.p.x_b = true;
|
snes.cpu->_registers.p.x_b = true;
|
||||||
snes.wram->_data[0] = 0x01;
|
snes.wram->_data[0] = 0x01;
|
||||||
snes.cpu->LDX(0x0);
|
snes.cpu->LDX(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.cpu->_registers.x;
|
auto data = snes.cpu->_registers.x;
|
||||||
cr_assert_eq(data, 0x01, "The stored value should be 0x01 but it was 0x%x.", data);
|
cr_assert_eq(data, 0x01, "The stored value should be 0x01 but it was 0x%x.", data);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag register should not be set.");
|
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag register should not be set.");
|
||||||
@@ -107,7 +107,7 @@ Test(LDX, 8bitsNegative)
|
|||||||
Init()
|
Init()
|
||||||
snes.cpu->_registers.p.x_b = true;
|
snes.cpu->_registers.p.x_b = true;
|
||||||
snes.wram->_data[0] = 0x11;
|
snes.wram->_data[0] = 0x11;
|
||||||
snes.cpu->LDX(0x0);
|
snes.cpu->LDX(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.cpu->_registers.x;
|
auto data = snes.cpu->_registers.x;
|
||||||
cr_assert_eq(data, 0x11, "The stored value should be 0x11 but it was 0x%x.", data);
|
cr_assert_eq(data, 0x11, "The stored value should be 0x11 but it was 0x%x.", data);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag register should not be set.");
|
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag register should not be set.");
|
||||||
@@ -120,7 +120,7 @@ Test(LDX, 8bitsZero)
|
|||||||
snes.cpu->_registers.p.x_b = true;
|
snes.cpu->_registers.p.x_b = true;
|
||||||
snes.wram->_data[0] = 0x00;
|
snes.wram->_data[0] = 0x00;
|
||||||
snes.wram->_data[1] = 0x11;
|
snes.wram->_data[1] = 0x11;
|
||||||
snes.cpu->LDX(0x0);
|
snes.cpu->LDX(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.cpu->_registers.x;
|
auto data = snes.cpu->_registers.x;
|
||||||
cr_assert_eq(data, 0x00, "The stored value should be 0x00 but it was 0x%x.", data);
|
cr_assert_eq(data, 0x00, "The stored value should be 0x00 but it was 0x%x.", data);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag register should be set.");
|
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag register should be set.");
|
||||||
@@ -133,7 +133,7 @@ Test(LDX, 16bits)
|
|||||||
snes.cpu->_registers.p.x_b = false;
|
snes.cpu->_registers.p.x_b = false;
|
||||||
snes.wram->_data[0] = 0xAB;
|
snes.wram->_data[0] = 0xAB;
|
||||||
snes.wram->_data[1] = 001;
|
snes.wram->_data[1] = 001;
|
||||||
snes.cpu->LDX(0x0);
|
snes.cpu->LDX(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.cpu->_registers.x;
|
auto data = snes.cpu->_registers.x;
|
||||||
cr_assert_eq(data, 0x01AB, "The stored value should be 0x01AB but it was 0x%x.", data);
|
cr_assert_eq(data, 0x01AB, "The stored value should be 0x01AB but it was 0x%x.", data);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag register should not be set.");
|
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag register should not be set.");
|
||||||
@@ -146,7 +146,7 @@ Test(LDX, 16bitsNegative)
|
|||||||
snes.cpu->_registers.p.x_b = false;
|
snes.cpu->_registers.p.x_b = false;
|
||||||
snes.wram->_data[0] = 0xAB;
|
snes.wram->_data[0] = 0xAB;
|
||||||
snes.wram->_data[1] = 0x11;
|
snes.wram->_data[1] = 0x11;
|
||||||
snes.cpu->LDX(0x0);
|
snes.cpu->LDX(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.cpu->_registers.x;
|
auto data = snes.cpu->_registers.x;
|
||||||
cr_assert_eq(data, 0x11AB, "The stored value should be 0x11AB but it was 0x%x.", data);
|
cr_assert_eq(data, 0x11AB, "The stored value should be 0x11AB but it was 0x%x.", data);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag register should not be set.");
|
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag register should not be set.");
|
||||||
@@ -159,7 +159,7 @@ Test(LDX, 16bitsZero)
|
|||||||
snes.cpu->_registers.p.x_b = false;
|
snes.cpu->_registers.p.x_b = false;
|
||||||
snes.wram->_data[0] = 0x00;
|
snes.wram->_data[0] = 0x00;
|
||||||
snes.wram->_data[1] = 0x00;
|
snes.wram->_data[1] = 0x00;
|
||||||
snes.cpu->LDX(0x0);
|
snes.cpu->LDX(0x0, ComSquare::CPU::AddressingMode::Implied);
|
||||||
auto data = snes.cpu->_registers.x;
|
auto data = snes.cpu->_registers.x;
|
||||||
cr_assert_eq(data, 0x0000, "The stored value should be 0x0000 but it was 0x%x.", data);
|
cr_assert_eq(data, 0x0000, "The stored value should be 0x0000 but it was 0x%x.", data);
|
||||||
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag register should be set.");
|
cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag register should be set.");
|
||||||
|
|||||||
104
ui/cpu.ui
104
ui/cpu.ui
@@ -6,8 +6,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>420</width>
|
<width>971</width>
|
||||||
<height>438</height>
|
<height>709</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
@@ -21,28 +21,39 @@
|
|||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="centralwidget">
|
<widget class="QWidget" name="centralwidget">
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
<item row="0" column="0" rowspan="2">
|
||||||
|
<widget class="QTableView" name="disassembly">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>1</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||||
|
</property>
|
||||||
|
<property name="selectionBehavior">
|
||||||
|
<enum>QAbstractItemView::SelectRows</enum>
|
||||||
|
</property>
|
||||||
|
<property name="showGrid">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="gridStyle">
|
||||||
|
<enum>Qt::NoPen</enum>
|
||||||
|
</property>
|
||||||
|
<attribute name="horizontalHeaderVisible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="horizontalHeaderHighlightSections">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="QLabel" name="loggerLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>Instructions History</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignCenter</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QTextBrowser" name="logger"/>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="1">
|
|
||||||
<widget class="QPushButton" name="clear">
|
|
||||||
<property name="text">
|
|
||||||
<string>Clear History</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="0" rowspan="3">
|
|
||||||
<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">
|
||||||
@@ -150,10 +161,37 @@
|
|||||||
<property name="layoutDirection">
|
<property name="layoutDirection">
|
||||||
<enum>Qt::RightToLeft</enum>
|
<enum>Qt::RightToLeft</enum>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<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">
|
||||||
|
<widget class="QLabel" name="loggerLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Instructions History</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QTextBrowser" name="logger"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QToolBar" name="toolBar">
|
<widget class="QToolBar" name="toolBar">
|
||||||
@@ -182,6 +220,7 @@
|
|||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</attribute>
|
</attribute>
|
||||||
<addaction name="actionPause"/>
|
<addaction name="actionPause"/>
|
||||||
|
<addaction name="actionNext"/>
|
||||||
<addaction name="actionStep"/>
|
<addaction name="actionStep"/>
|
||||||
</widget>
|
</widget>
|
||||||
<action name="actionPause">
|
<action name="actionPause">
|
||||||
@@ -190,13 +229,13 @@
|
|||||||
<normaloff>:/resources/icons/play.svg</normaloff>:/resources/icons/play.svg</iconset>
|
<normaloff>:/resources/icons/play.svg</normaloff>:/resources/icons/play.svg</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Resume</string>
|
<string>Continue</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Pause or Resume instruction execution.</string>
|
<string>Pause or Resume instruction execution.</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="shortcut">
|
<property name="shortcut">
|
||||||
<string>P</string>
|
<string>C</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionStep">
|
<action name="actionStep">
|
||||||
@@ -214,6 +253,21 @@
|
|||||||
<string>S</string>
|
<string>S</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionNext">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../resources/appResources.qrc">
|
||||||
|
<normaloff>:/resources/icons/continue.svg</normaloff>:/resources/icons/continue.svg</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Next</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Continue execution to the next line.</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>N</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="../resources/appResources.qrc"/>
|
<include location="../resources/appResources.qrc"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user