mirror of
https://github.com/zoriya/ComSquare.git
synced 2026-05-16 20:38:28 +00:00
Finishing to implements JSR/JLR and push
This commit is contained in:
+20
-7
@@ -281,6 +281,19 @@ namespace ComSquare::CPU
|
||||
|
||||
case Instructions::REP: this->REP(this->_getImmediateAddr()); 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::JSR_ABS: this->JSR(this->_getAbsoluteAddr()); return 6;
|
||||
case Instructions::JSR_ABSXi: this->JSR(this->_getAbsoluteIndirectIndexedByXAddr()); return 8;
|
||||
|
||||
case Instructions::JSL: this->JSR(this->_getAbsoluteLongAddr()); return 8;
|
||||
|
||||
default:
|
||||
throw InvalidOpcode("CPU", opcode);
|
||||
}
|
||||
@@ -293,18 +306,18 @@ namespace ComSquare::CPU
|
||||
|
||||
void CPU::_push(uint16_t data)
|
||||
{
|
||||
this->_bus->write(this->_registers.s--, data >> 8u);
|
||||
this->_bus->write(this->_registers.s--, data);
|
||||
this->_bus->write(this->_registers.s--, data << 8u);
|
||||
}
|
||||
|
||||
uint8_t CPU::_pop()
|
||||
{
|
||||
return this->_bus->read(this->_registers.s++);
|
||||
return this->_bus->read(++this->_registers.s);
|
||||
}
|
||||
|
||||
uint16_t CPU::_pop16()
|
||||
{
|
||||
return this->_bus->read(this->_registers.s++) + (this->_bus->read(this->_registers.s++) << 8u);
|
||||
return this->_bus->read(++this->_registers.s) + (this->_bus->read(++this->_registers.s) << 8u);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@@ -347,7 +360,7 @@ namespace ComSquare::CPU
|
||||
uint24_t base = this->_bus->read(dp);
|
||||
base += this->_bus->read(dp + 1) << 8u;
|
||||
base += this->_registers.dbr << 16u;
|
||||
if ((base & 0xF0000000u) == (((base + this->_registers.y) & 0xF0000000u)))
|
||||
if ((base & 0x80000000u) == (((base + this->_registers.y) & 0x80000000u)))
|
||||
this->_hasIndexCrossedPageBoundary = true;
|
||||
return base + this->_registers.y;
|
||||
}
|
||||
@@ -390,7 +403,7 @@ namespace ComSquare::CPU
|
||||
uint16_t abs = this->_bus->read(this->_registers.pac++);
|
||||
abs += this->_bus->read(this->_registers.pac++) << 8u;
|
||||
uint24_t effective = abs + (this->_registers.dbr << 16u);
|
||||
if ((effective & 0xF0000000u) == (((effective + this->_registers.x) & 0xF0000000u)))
|
||||
if ((effective & 0x80000000u) == (((effective + this->_registers.x) & 0x80000000u)))
|
||||
this->_hasIndexCrossedPageBoundary = true;
|
||||
return effective + this->_registers.x;
|
||||
}
|
||||
@@ -400,7 +413,7 @@ namespace ComSquare::CPU
|
||||
uint16_t abs = this->_bus->read(this->_registers.pac++);
|
||||
abs += this->_bus->read(this->_registers.pac++) << 8u;
|
||||
uint24_t effective = abs + (this->_registers.dbr << 16u);
|
||||
if ((effective & 0xF0000000u) == (((effective + this->_registers.y) & 0xF0000000u)))
|
||||
if ((effective & 0x80000000u) == (((effective + this->_registers.y) & 0x80000000u)))
|
||||
this->_hasIndexCrossedPageBoundary = true;
|
||||
return effective + this->_registers.y;
|
||||
}
|
||||
@@ -438,7 +451,7 @@ namespace ComSquare::CPU
|
||||
return effective;
|
||||
}
|
||||
|
||||
uint24_t CPU::_getAbsoluteIndexedIndirectAddr()
|
||||
uint24_t CPU::_getAbsoluteIndirectIndexedByXAddr()
|
||||
{
|
||||
uint24_t abs = this->_bus->read(this->_registers.pac++);
|
||||
abs += this->_bus->read(this->_registers.pac++) << 8u;
|
||||
|
||||
+48
-4
@@ -34,8 +34,6 @@ namespace ComSquare::CPU
|
||||
};
|
||||
union {
|
||||
struct {
|
||||
//! @brief The Program Bank Register;
|
||||
uint8_t pbr;
|
||||
//! @brief The Program Counter;
|
||||
union {
|
||||
struct {
|
||||
@@ -44,6 +42,8 @@ namespace ComSquare::CPU
|
||||
};
|
||||
uint16_t pc;
|
||||
};
|
||||
//! @brief The Program Bank Register;
|
||||
uint8_t pbr;
|
||||
};
|
||||
//! @brief The current Program Address Counter (does not exist in a snes but is useful here).
|
||||
uint24_t pac;
|
||||
@@ -262,7 +262,19 @@ namespace ComSquare::CPU
|
||||
|
||||
SEP = 0xE2,
|
||||
|
||||
REP = 0xC2
|
||||
REP = 0xC2,
|
||||
|
||||
PHA = 0x48,
|
||||
PHB = 0x8B,
|
||||
PHD = 0x0B,
|
||||
PHK = 0x4B,
|
||||
PHP = 0x08,
|
||||
PHX = 0xDA,
|
||||
PHY = 0x5A,
|
||||
|
||||
JSR_ABS = 0x20,
|
||||
JSR_ABSXi = 0xFC,
|
||||
JSL = 0x22
|
||||
};
|
||||
|
||||
//! @brief The main CPU
|
||||
@@ -313,7 +325,7 @@ namespace ComSquare::CPU
|
||||
//! @brief 2 bytes are pulled from the <abs exp> to form the effective address.
|
||||
uint24_t _getAbsoluteIndirectAddr();
|
||||
//! @brief The <abs exp> is added with X, then 2 bytes are pulled from that address to form the new location.
|
||||
uint24_t _getAbsoluteIndexedIndirectAddr();
|
||||
uint24_t _getAbsoluteIndirectIndexedByXAddr();
|
||||
//! @brief 2 bytes are pulled from the direct page address to form the 16-bit address. It is combined with DBR to form a 24-bit effective address.
|
||||
uint24_t _getDirectIndirectAddr();
|
||||
//! @brief 3 bytes are pulled from the direct page address to form an effective address.
|
||||
@@ -365,6 +377,38 @@ namespace ComSquare::CPU
|
||||
void SEP(uint24_t valueAddr);
|
||||
//! @brief Reset status bits.
|
||||
void REP(uint24_t valueAddr);
|
||||
//! @brief Jump to subroutine
|
||||
void JSR(uint24_t addr);
|
||||
//! @brief Jump to subroutine (long)
|
||||
void JSL(uint24_t addr);
|
||||
//! @brief Push the accumulator to the stack.
|
||||
void PHA();
|
||||
//! @brief Push the data bank register to the stack.
|
||||
void PHB();
|
||||
//! @brief Push the direct page register to the stack.
|
||||
void PHD();
|
||||
//! @brief Push the program bank register to the stack.
|
||||
void PHK();
|
||||
//! @brief Push the processor status register to the stack.
|
||||
void PHP();
|
||||
//! @brief Push the x index register to the stack.
|
||||
void PHX();
|
||||
//! @brief Push the y index register to the stack.
|
||||
void PHY();
|
||||
//! @brief Pull the accumulator to the stack.
|
||||
void PLA();
|
||||
//! @brief Pull the data bank register to the stack.
|
||||
void PLB();
|
||||
//! @brief Pull the direct page register to the stack.
|
||||
void PLD();
|
||||
//! @brief Pull the program bank register to the stack.
|
||||
void PLK();
|
||||
//! @brief Pull the processor status register to the stack.
|
||||
void PLP();
|
||||
//! @brief Pull the x index register to the stack.
|
||||
void PLX();
|
||||
//! @brief Pull the y index register to the stack.
|
||||
void PLY();
|
||||
public:
|
||||
explicit CPU(std::shared_ptr<Memory::MemoryBus> bus, Cartridge::Header &cartridgeHeader);
|
||||
CPU(const CPU &) = default;
|
||||
|
||||
@@ -19,4 +19,90 @@ namespace ComSquare::CPU
|
||||
this->_registers.p.m = true;
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::JSR(uint24_t valueAddr)
|
||||
{
|
||||
this->_push(--this->_registers.pc);
|
||||
this->_registers.pc = this->_bus->read(valueAddr) + (this->_bus->read(valueAddr + 1) << 8u);
|
||||
}
|
||||
|
||||
void CPU::JSL(uint24_t valueAddr)
|
||||
{
|
||||
this->_registers.pac--;
|
||||
this->_push(this->_registers.pbr);
|
||||
this->_push(this->_registers.pc);
|
||||
this->_registers.pc = this->_bus->read(valueAddr) + (this->_bus->read(valueAddr + 1) << 8u);
|
||||
}
|
||||
|
||||
void CPU::PHA()
|
||||
{
|
||||
this->_push(this->_registers.a);
|
||||
}
|
||||
|
||||
void CPU::PHB()
|
||||
{
|
||||
this->_push(this->_registers.dbr);
|
||||
}
|
||||
|
||||
void CPU::PHD()
|
||||
{
|
||||
this->_push(this->_registers.d);
|
||||
}
|
||||
|
||||
void CPU::PHK()
|
||||
{
|
||||
this->_push(this->_registers.pbr);
|
||||
}
|
||||
|
||||
void CPU::PHP()
|
||||
{
|
||||
this->_push(this->_registers.p.flags);
|
||||
}
|
||||
|
||||
void CPU::PHX()
|
||||
{
|
||||
this->_push(this->_registers.x);
|
||||
}
|
||||
|
||||
void CPU::PHY()
|
||||
{
|
||||
this->_push(this->_registers.y);
|
||||
}
|
||||
|
||||
void CPU::PLA()
|
||||
{
|
||||
this->_registers.a = this->_pop16();
|
||||
this->_registers.p.z = this->_registers.a == 0;
|
||||
this->_registers.p.n = this->_registers.a & 0x8000u;
|
||||
}
|
||||
|
||||
void CPU::PLB()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CPU::PLD()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CPU::PLK()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CPU::PLP()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CPU::PLX()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CPU::PLY()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -243,7 +243,7 @@ Test(AddrMode, AbsoluteIndexedIndirect)
|
||||
pair.second.cpu->_registers.x = 2;
|
||||
pair.second.wram->_data[0x01AD] = 0xEF;
|
||||
pair.second.wram->_data[0x01AE] = 0x01;
|
||||
auto addr = pair.second.cpu->_getAbsoluteIndexedIndirectAddr();
|
||||
auto addr = pair.second.cpu->_getAbsoluteIndirectIndexedByXAddr();
|
||||
cr_assert_eq(addr, 0x01EF, "Returned address was %x but was expecting 0x01EF.", addr);
|
||||
cr_assert_eq(pair.second.cpu->_registers.pac, 0x808002);
|
||||
}
|
||||
|
||||
@@ -69,4 +69,151 @@ Test(REP, resetsomeEmulation)
|
||||
pair.second.cpu->REP(0x0);
|
||||
auto data = pair.second.cpu->_registers.p.flags;
|
||||
cr_assert_eq(data, 0b00110100, "The flag should be 0b00110100 but it was %x", data);
|
||||
}
|
||||
|
||||
Test(JSR, jump)
|
||||
{
|
||||
auto pair = Init();
|
||||
pair.second.cpu->_registers.pc = 0xABCD;
|
||||
pair.second.cpu->_registers.s = 0x0123;
|
||||
pair.second.wram->_data[0] = 0xFF;
|
||||
pair.second.wram->_data[1] = 0xAB;
|
||||
pair.second.cpu->JSR(0x0);
|
||||
auto pc = pair.second.cpu->_registers.pc;
|
||||
cr_assert_eq(pc, 0xABFF, "The PC should be 0xABFF but it was %x", pc);
|
||||
cr_assert_eq(pair.second.cpu->_registers.s, 0x0121, "The stack pointer should be 0x0121 but it was %x", pair.second.cpu->_registers.s);
|
||||
auto pushed = pair.second.cpu->_pop16();
|
||||
cr_assert_eq(pushed, 0xABCC, "The value pushed to the stack should be 0xABCC but it was %x", pushed);
|
||||
}
|
||||
|
||||
Test(JSL, jump)
|
||||
{
|
||||
auto pair = Init();
|
||||
pair.second.cpu->_registers.pbr = 0xFF;
|
||||
pair.second.cpu->_registers.pc = 0xABCD;
|
||||
pair.second.cpu->_registers.s = 0x0123;
|
||||
pair.second.wram->_data[0] = 0xFF;
|
||||
pair.second.wram->_data[1] = 0xAB;
|
||||
pair.second.cpu->JSL(0x0);
|
||||
auto pc = pair.second.cpu->_registers.pc;
|
||||
cr_assert_eq(pc, 0xABFF, "The PC should be 0xABFF but it was %x", pc);
|
||||
cr_assert_eq(pair.second.cpu->_registers.s, 0x0120, "The stack pointer should be 0x0120 but it was %x", pair.second.cpu->_registers.s);
|
||||
auto pushed = pair.second.cpu->_pop16() + (pair.second.cpu->_pop() << 16u);
|
||||
cr_assert_eq(pushed, 0xFFABCC, "The value pushed to the stack should be 0xFFABCD but it was %x", pushed);
|
||||
}
|
||||
|
||||
Test(PHA, basic)
|
||||
{
|
||||
auto pair = Init();
|
||||
pair.second.cpu->_registers.a = 0xABCD;
|
||||
pair.second.cpu->_registers.s = 0x02;
|
||||
pair.second.cpu->PHA();
|
||||
cr_assert_eq(pair.second.wram->_data[1], 0xCD, "The second value pushed to the stack should be 0xCD but it was %x", pair.second.wram->_data[1]);
|
||||
cr_assert_eq(pair.second.wram->_data[2], 0xAB, "The first value pushed to the stack should be 0xAB but it was %x", pair.second.wram->_data[2]);
|
||||
cr_assert_eq(pair.second.cpu->_registers.s, 0x0, "The Stack pointer should be equal to 0x0 but it was %x", pair.second.cpu->_registers.s);
|
||||
}
|
||||
|
||||
Test(PHB, basic)
|
||||
{
|
||||
auto pair = Init();
|
||||
pair.second.cpu->_registers.dbr = 0xFF;
|
||||
pair.second.cpu->_registers.s = 0x02;
|
||||
pair.second.cpu->PHB();
|
||||
cr_assert_eq(pair.second.wram->_data[2], 0xFF, "The first value pushed to the stack should be 0xFF but it was %x", pair.second.wram->_data[2]);
|
||||
cr_assert_eq(pair.second.cpu->_registers.s, 0x1, "The Stack pointer should be equal to 0x1 but it was %x", pair.second.cpu->_registers.s);
|
||||
}
|
||||
|
||||
Test(PHD, basic)
|
||||
{
|
||||
auto pair = Init();
|
||||
pair.second.cpu->_registers.d = 0xABCD;
|
||||
pair.second.cpu->_registers.s = 0x02;
|
||||
pair.second.cpu->PHD();
|
||||
cr_assert_eq(pair.second.wram->_data[1], 0xCD, "The second value pushed to the stack should be 0xCD but it was %x", pair.second.wram->_data[1]);
|
||||
cr_assert_eq(pair.second.wram->_data[2], 0xAB, "The first value pushed to the stack should be 0xAB but it was %x", pair.second.wram->_data[2]);
|
||||
cr_assert_eq(pair.second.cpu->_registers.s, 0x0, "The Stack pointer should be equal to 0x0 but it was %x", pair.second.cpu->_registers.s);
|
||||
}
|
||||
|
||||
Test(PHK, basic)
|
||||
{
|
||||
auto pair = Init();
|
||||
pair.second.cpu->_registers.pbr = 0xFF;
|
||||
pair.second.cpu->_registers.s = 0x02;
|
||||
pair.second.cpu->PHK();
|
||||
cr_assert_eq(pair.second.wram->_data[2], 0xFF, "The first value pushed to the stack should be 0xFF but it was %x", pair.second.wram->_data[2]);
|
||||
cr_assert_eq(pair.second.cpu->_registers.s, 0x1, "The Stack pointer should be equal to 0x1 but it was %x", pair.second.cpu->_registers.s);
|
||||
}
|
||||
|
||||
Test(PHP, basic)
|
||||
{
|
||||
auto pair = Init();
|
||||
pair.second.cpu->_registers.p.flags = 0xFF;
|
||||
pair.second.cpu->_registers.s = 0x02;
|
||||
pair.second.cpu->PHP();
|
||||
cr_assert_eq(pair.second.wram->_data[2], 0xFF, "The first value pushed to the stack should be 0xFF but it was %x", pair.second.wram->_data[2]);
|
||||
cr_assert_eq(pair.second.cpu->_registers.s, 0x1, "The Stack pointer should be equal to 0x1 but it was %x", pair.second.cpu->_registers.s);
|
||||
}
|
||||
|
||||
Test(PHX, basic)
|
||||
{
|
||||
auto pair = Init();
|
||||
pair.second.cpu->_registers.x = 0xABCD;
|
||||
pair.second.cpu->_registers.s = 0x02;
|
||||
pair.second.cpu->PHX();
|
||||
cr_assert_eq(pair.second.wram->_data[1], 0xCD, "The second value pushed to the stack should be 0xCD but it was %x", pair.second.wram->_data[1]);
|
||||
cr_assert_eq(pair.second.wram->_data[2], 0xAB, "The first value pushed to the stack should be 0xAB but it was %x", pair.second.wram->_data[2]);
|
||||
cr_assert_eq(pair.second.cpu->_registers.s, 0x0, "The Stack pointer should be equal to 0x0 but it was %x", pair.second.cpu->_registers.s);
|
||||
}
|
||||
|
||||
Test(PHY, basic)
|
||||
{
|
||||
auto pair = Init();
|
||||
pair.second.cpu->_registers.y = 0xABCD;
|
||||
pair.second.cpu->_registers.s = 0x02;
|
||||
pair.second.cpu->PHY();
|
||||
cr_assert_eq(pair.second.wram->_data[1], 0xCD, "The second value pushed to the stack should be 0xCD but it was %x", pair.second.wram->_data[1]);
|
||||
cr_assert_eq(pair.second.wram->_data[2], 0xAB, "The first value pushed to the stack should be 0xAB but it was %x", pair.second.wram->_data[2]);
|
||||
cr_assert_eq(pair.second.cpu->_registers.s, 0x0, "The Stack pointer should be equal to 0x0 but it was %x", pair.second.cpu->_registers.s);
|
||||
}
|
||||
|
||||
Test(PLA, basic)
|
||||
{
|
||||
auto pair = Init();
|
||||
pair.second.wram->_data[1] = 0xCD;
|
||||
pair.second.wram->_data[2] = 0x7B;
|
||||
pair.second.cpu->_registers.s = 0x00;
|
||||
pair.second.cpu->PLA();
|
||||
auto data = pair.second.cpu->_registers.a;
|
||||
cr_assert_eq(data, 0x7BCD, "The accumulator should be 0x7BCD but it was %x", data);
|
||||
cr_assert_eq(pair.second.cpu->_registers.p.z, false, "The zero flag should not be set.", pair.second.cpu->_registers.p.z);
|
||||
cr_assert_eq(pair.second.cpu->_registers.p.n, false, "The negative flag should not be set.", pair.second.cpu->_registers.p.n);
|
||||
cr_assert_eq(pair.second.cpu->_registers.s, 0x2, "The Stack pointer should be equal to 0x2 but it was %x", pair.second.cpu->_registers.s);
|
||||
}
|
||||
|
||||
Test(PLA, zero)
|
||||
{
|
||||
auto pair = Init();
|
||||
pair.second.wram->_data[1] = 0x00;
|
||||
pair.second.wram->_data[2] = 0x00;
|
||||
pair.second.cpu->_registers.s = 0x00;
|
||||
pair.second.cpu->PLA();
|
||||
auto data = pair.second.cpu->_registers.a;
|
||||
cr_assert_eq(data, 0x0000, "The accumulator should be 0x0000 but it was %x", data);
|
||||
cr_assert_eq(pair.second.cpu->_registers.p.z, true, "The zero flag should be set.", pair.second.cpu->_registers.p.z);
|
||||
cr_assert_eq(pair.second.cpu->_registers.p.n, false, "The negative flag should not be set.", pair.second.cpu->_registers.p.n);
|
||||
cr_assert_eq(pair.second.cpu->_registers.s, 0x2, "The Stack pointer should be equal to 0x2 but it was %x", pair.second.cpu->_registers.s);
|
||||
}
|
||||
|
||||
Test(PLA, negative)
|
||||
{
|
||||
auto pair = Init();
|
||||
pair.second.wram->_data[1] = 0x00;
|
||||
pair.second.wram->_data[2] = 0xA0;
|
||||
pair.second.cpu->_registers.s = 0x00;
|
||||
pair.second.cpu->PLA();
|
||||
auto data = pair.second.cpu->_registers.a;
|
||||
cr_assert_eq(data, 0xA000, "The accumulator should be 0xA000 but it was %x", data);
|
||||
cr_assert_eq(pair.second.cpu->_registers.p.z, false, "The zero flag not should be set.", pair.second.cpu->_registers.p.z);
|
||||
cr_assert_eq(pair.second.cpu->_registers.p.n, true, "The negative flag should be set.", pair.second.cpu->_registers.p.n);
|
||||
cr_assert_eq(pair.second.cpu->_registers.s, 0x2, "The Stack pointer should be equal to 0x2 but it was %x", pair.second.cpu->_registers.s);
|
||||
}
|
||||
Reference in New Issue
Block a user