mirror of
https://github.com/zoriya/ComSquare.git
synced 2026-06-02 02:05:26 +00:00
Implementing instructions cycles
This commit is contained in:
+50
-18
@@ -194,28 +194,30 @@ namespace ComSquare::CPU
|
||||
return cycles;
|
||||
}
|
||||
|
||||
int CPU::executeInstruction()
|
||||
unsigned CPU::executeInstruction()
|
||||
{
|
||||
uint8_t opcode = this->_bus->read(this->_registers.pc);
|
||||
|
||||
switch (opcode) {
|
||||
case Instructions::BRK: return this->BRK();
|
||||
this->_extraMemoryCycles = 0;
|
||||
|
||||
case Instructions::ADC_DPXi: return this->ADC(this->_getDirectIndirectIndexedXAddr());
|
||||
case Instructions::ADC_SR: return this->ADC(this->_getStackRelativeAddr());
|
||||
case Instructions::ADC_DP: return this->ADC(this->_getDirectAddr());
|
||||
case Instructions::ADC_DPil: return this->ADC(this->_getDirectIndirectLongAddr());
|
||||
case Instructions::ADC_IM: return this->ADC(this->_getImmediateAddr());
|
||||
case Instructions::ADC_ABS: return this->ADC(this->_getAbsoluteAddr());
|
||||
case Instructions::ADC_ABSl: return this->ADC(this->_getAbsoluteLongAddr());
|
||||
case Instructions::ADC_DPYi: return this->ADC(this->_getDirectIndirectIndexedYAddr());
|
||||
case Instructions::ADC_DPi: return this->ADC(this->_getDirectIndirectAddr());
|
||||
case Instructions::ADC_SRYi: return this->ADC(this->_getStackRelativeIndirectIndexedYAddr());
|
||||
case Instructions::ADC_DPX: return this->ADC(this->_getDirectIndexedByXAddr());
|
||||
case Instructions::ADC_DPYil:return this->ADC(this->_getDirectIndirectIndexedYLongAddr());
|
||||
case Instructions::ADC_ABSY: return this->ADC(this->_getAbsoluteIndexedByYAddr());
|
||||
case Instructions::ADC_ABSX: return this->ADC(this->_getAbsoluteIndexedByXAddr());
|
||||
case Instructions::ADC_ABSXl:return this->ADC(this->_getAbsoluteIndexedByXLongAddr());
|
||||
switch (opcode) {
|
||||
case Instructions::BRK: return 7 + this->BRK();
|
||||
|
||||
case Instructions::ADC_IM: return 2 + this->ADC(this->_getImmediateAddr());
|
||||
case Instructions::ADC_ABS: return 4 + this->ADC(this->_getAbsoluteAddr());
|
||||
case Instructions::ADC_ABSl: return 5 + this->ADC(this->_getAbsoluteLongAddr());
|
||||
case Instructions::ADC_DP: return 3 + this->ADC(this->_getDirectAddr());
|
||||
case Instructions::ADC_DPi: return 5 + this->ADC(this->_getDirectIndirectAddr());
|
||||
case Instructions::ADC_DPil: return 6 + this->ADC(this->_getDirectIndirectLongAddr());
|
||||
case Instructions::ADC_ABSX: return 4 + this->ADC(this->_getAbsoluteIndexedByXAddr());
|
||||
case Instructions::ADC_ABSXl:return 5 + this->ADC(this->_getAbsoluteIndexedByXLongAddr());
|
||||
case Instructions::ADC_ABSY: return 4 + this->ADC(this->_getAbsoluteIndexedByYAddr());
|
||||
case Instructions::ADC_DPX: return 4 + this->ADC(this->_getDirectIndexedByXAddr());
|
||||
case Instructions::ADC_DPXi: return 6 + this->ADC(this->_getDirectIndirectIndexedXAddr());
|
||||
case Instructions::ADC_DPYi: return 5 + this->ADC(this->_getDirectIndirectIndexedYAddr());
|
||||
case Instructions::ADC_DPYil:return 6 + this->ADC(this->_getDirectIndirectIndexedYLongAddr());
|
||||
case Instructions::ADC_SR: return 4 + this->ADC(this->_getStackRelativeAddr());
|
||||
case Instructions::ADC_SRYi: return 7 + this->ADC(this->_getStackRelativeIndirectIndexedYAddr());
|
||||
|
||||
default:
|
||||
return 0;
|
||||
@@ -237,6 +239,9 @@ namespace ComSquare::CPU
|
||||
|
||||
uint24_t CPU::_getDirectAddr()
|
||||
{
|
||||
if (this->_registers.dl != 0)
|
||||
this->_extraMemoryCycles++;
|
||||
|
||||
uint8_t addr = this->_bus->read(this->_registers.pac++);
|
||||
return this->_registers.d + addr;
|
||||
}
|
||||
@@ -259,15 +264,23 @@ namespace ComSquare::CPU
|
||||
|
||||
uint24_t CPU::_getDirectIndirectIndexedYAddr()
|
||||
{
|
||||
if (this->_registers.dl != 0)
|
||||
this->_extraMemoryCycles++;
|
||||
|
||||
uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d;
|
||||
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)))
|
||||
this->_extraMemoryCycles++;
|
||||
return base + this->_registers.y;
|
||||
}
|
||||
|
||||
uint24_t CPU::_getDirectIndirectIndexedYLongAddr()
|
||||
{
|
||||
if (this->_registers.dl != 0)
|
||||
this->_extraMemoryCycles++;
|
||||
|
||||
uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d;
|
||||
uint24_t base = this->_bus->read(dp);
|
||||
base += this->_bus->read(dp + 1) << 8u;
|
||||
@@ -277,6 +290,9 @@ namespace ComSquare::CPU
|
||||
|
||||
uint24_t CPU::_getDirectIndirectIndexedXAddr()
|
||||
{
|
||||
if (this->_registers.dl != 0)
|
||||
this->_extraMemoryCycles++;
|
||||
|
||||
uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d;
|
||||
dp += this->_registers.x;
|
||||
uint24_t base = this->_bus->read(dp);
|
||||
@@ -287,6 +303,9 @@ namespace ComSquare::CPU
|
||||
|
||||
uint24_t CPU::_getDirectIndexedByXAddr()
|
||||
{
|
||||
if (this->_registers.dl != 0)
|
||||
this->_extraMemoryCycles++;
|
||||
|
||||
uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d;
|
||||
dp += this->_registers.x;
|
||||
return dp;
|
||||
@@ -294,6 +313,9 @@ namespace ComSquare::CPU
|
||||
|
||||
uint24_t CPU::_getDirectIndexedByYAddr()
|
||||
{
|
||||
if (this->_registers.dl != 0)
|
||||
this->_extraMemoryCycles++;
|
||||
|
||||
uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d;
|
||||
dp += this->_registers.y;
|
||||
return dp;
|
||||
@@ -304,6 +326,8 @@ 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)))
|
||||
this->_extraMemoryCycles++;
|
||||
return effective + this->_registers.x;
|
||||
}
|
||||
|
||||
@@ -312,6 +336,8 @@ 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)))
|
||||
this->_extraMemoryCycles++;
|
||||
return effective + this->_registers.y;
|
||||
}
|
||||
|
||||
@@ -360,6 +386,9 @@ namespace ComSquare::CPU
|
||||
|
||||
uint24_t CPU::_getDirectIndirectAddr()
|
||||
{
|
||||
if (this->_registers.dl != 0)
|
||||
this->_extraMemoryCycles++;
|
||||
|
||||
uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d;
|
||||
uint24_t effective = this->_bus->read(dp);
|
||||
effective += this->_bus->read(dp + 1) << 8u;
|
||||
@@ -369,6 +398,9 @@ namespace ComSquare::CPU
|
||||
|
||||
uint24_t CPU::_getDirectIndirectLongAddr()
|
||||
{
|
||||
if (this->_registers.dl != 0)
|
||||
this->_extraMemoryCycles++;
|
||||
|
||||
uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d;
|
||||
uint24_t effective = this->_bus->read(dp);
|
||||
effective += this->_bus->read(++dp) << 8u;
|
||||
|
||||
+9
-5
@@ -25,7 +25,7 @@ namespace ComSquare::CPU
|
||||
};
|
||||
//! @brief The Data Bank Register;
|
||||
uint8_t dbr;
|
||||
//! @brief The Direct register;
|
||||
//! @brief The Direct Page register;
|
||||
union {
|
||||
struct {
|
||||
uint8_t dh;
|
||||
@@ -202,7 +202,7 @@ namespace ComSquare::CPU
|
||||
ADC_DPYil = 0x77,
|
||||
ADC_ABSY = 0x79,
|
||||
ADC_ABSX = 0x7D,
|
||||
ADC_ABSXl = 0x7F,
|
||||
ADC_ABSXl = 0x7F
|
||||
};
|
||||
|
||||
//! @brief The main CPU
|
||||
@@ -219,6 +219,9 @@ namespace ComSquare::CPU
|
||||
//! @brief The cartridge header (stored for interrupt vectors..
|
||||
Cartridge::Header &_cartridgeHeader;
|
||||
|
||||
//! @brief An additional number of cycles that the current running instruction took to run. (Used for address modes that take longer to run than others).
|
||||
unsigned _extraMemoryCycles = 0;
|
||||
|
||||
//! @brief Immediate address mode is specified with a value. (This functions returns the 24bit space address of the value).
|
||||
uint24_t _getImmediateAddr();
|
||||
//! @brief The destination is formed by adding the direct page register with the 8-bit address to form an effective address. (This functions returns the 24bit space address of the value).
|
||||
@@ -263,12 +266,13 @@ namespace ComSquare::CPU
|
||||
|
||||
//! @brief Execute a single instruction.
|
||||
//! @return The number of CPU cycles that the instruction took.
|
||||
int executeInstruction();
|
||||
unsigned executeInstruction();
|
||||
|
||||
//! @brief Break instruction - Causes a software break. The PC is loaded from a vector table.
|
||||
int BRK();
|
||||
unsigned BRK();
|
||||
//! @brief Add with carry - Adds operand to the Accumulator; adds an additional 1 if carry is set.
|
||||
int ADC(uint24_t valueAddr);
|
||||
//! @return The number of extra cycles that this operation took.
|
||||
unsigned ADC(uint24_t valueAddr);
|
||||
public:
|
||||
explicit CPU(std::shared_ptr<Memory::MemoryBus> bus, Cartridge::Header &cartridgeHeader);
|
||||
//! @brief This function continue to execute the Cartridge code.
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
namespace ComSquare::CPU
|
||||
{
|
||||
int CPU::BRK()
|
||||
unsigned CPU::BRK()
|
||||
{
|
||||
this->_registers.pc += 2;
|
||||
|
||||
@@ -16,6 +16,6 @@ namespace ComSquare::CPU
|
||||
else
|
||||
this->_registers.pc = this->_cartridgeHeader.nativeInterrupts.brk;
|
||||
this->_registers.p.d = false;
|
||||
return 7 + !this->_isEmulationMode;
|
||||
return !this->_isEmulationMode;
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
namespace ComSquare::CPU
|
||||
{
|
||||
int CPU::ADC(uint24_t valueAddr)
|
||||
unsigned CPU::ADC(uint24_t valueAddr)
|
||||
{
|
||||
unsigned value = this->_bus->read(valueAddr) + this->_registers.p.c;
|
||||
if (this->_registers.p.m)
|
||||
@@ -25,6 +25,6 @@ namespace ComSquare::CPU
|
||||
this->_registers.a %= 0x100;
|
||||
this->_registers.p.z = this->_registers.a == 0;
|
||||
this->_registers.p.n = this->_registers.a & negativeMask;
|
||||
return (0);
|
||||
return this->_extraMemoryCycles + !this->_registers.p.m;
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ Test(CPU_emulated, BRK)
|
||||
pair.second.cartridge->header.emulationInterrupts.brk = 0x123u;
|
||||
pair.second.cpu->_registers.p.d = true;
|
||||
pair.second.cpu->_registers.pc = 0x156u;
|
||||
cr_assert_eq(pair.second.cpu->BRK(), 7);
|
||||
cr_assert_eq(pair.second.cpu->BRK(), 0);
|
||||
cr_assert_eq(pair.second.cpu->_registers.pc, 0x123u);
|
||||
cr_assert_eq(pair.second.cpu->_registers.p.i, 1, "pair.second.cpu->_registers.p.i mmust be equal to 1 but it was %d", pair.second.cpu->_registers.p.i);
|
||||
cr_assert_eq(pair.second.cpu->_registers.p.d, false);
|
||||
@@ -28,7 +28,7 @@ Test(CPU_native, BRK)
|
||||
pair.second.cpu->_isEmulationMode = false;
|
||||
pair.second.cartridge->header.nativeInterrupts.brk = 0x123u;
|
||||
pair.second.cpu->_registers.pc = 0x156u;
|
||||
cr_assert_eq(pair.second.cpu->BRK(), 8);
|
||||
cr_assert_eq(pair.second.cpu->BRK(), 1);
|
||||
cr_assert_eq(pair.second.cpu->_registers.pc, 0x123u);
|
||||
cr_assert_eq(pair.second.cpu->_registers.p.i, true);
|
||||
cr_assert_eq(pair.second.cpu->_registers.p.d, false);
|
||||
|
||||
Reference in New Issue
Block a user