Add CPX, CPY, DEX, DEY, XCE, Emulation Mode
This commit is contained in:
@@ -334,23 +334,23 @@ void CPU::ExecuteInstruction(uint8_t opcode) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xE0: // CPX Immediate
|
case 0xE0: // CPX Immediate
|
||||||
// CPX();
|
CPX(Immediate());
|
||||||
break;
|
break;
|
||||||
case 0xE4: // CPX Direct Page
|
case 0xE4: // CPX Direct Page
|
||||||
// CPX();
|
// CPX();
|
||||||
break;
|
break;
|
||||||
case 0xEC: // CPX Absolute
|
case 0xEC: // CPX Absolute
|
||||||
// CPX();
|
CPX(Absolute());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xC0: // CPY Immediate
|
case 0xC0: // CPY Immediate
|
||||||
// CPY();
|
CPY(Immediate());
|
||||||
break;
|
break;
|
||||||
case 0xC4: // CPY Direct Page
|
case 0xC4: // CPY Direct Page
|
||||||
// CPY();
|
// CPY();
|
||||||
break;
|
break;
|
||||||
case 0xCC: // CPY Absolute
|
case 0xCC: // CPY Absolute
|
||||||
// CPY();
|
CPY(Absolute());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x3A: // DEC Accumulator
|
case 0x3A: // DEC Accumulator
|
||||||
@@ -370,11 +370,11 @@ void CPU::ExecuteInstruction(uint8_t opcode) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xCA: // DEX Decrement X register
|
case 0xCA: // DEX Decrement X register
|
||||||
// DEX();
|
DEX();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x88: // DEY Decrement Y register
|
case 0x88: // DEY Decrement Y register
|
||||||
// DEY();
|
DEY();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x41: // EOR DP Indexed Indirect, X
|
case 0x41: // EOR DP Indexed Indirect, X
|
||||||
@@ -951,7 +951,7 @@ void CPU::ExecuteInstruction(uint8_t opcode) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xFB: // XCE
|
case 0xFB: // XCE
|
||||||
// XCE();
|
XCE();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
std::cerr << "Unknown instruction: " << std::hex
|
std::cerr << "Unknown instruction: " << std::hex
|
||||||
@@ -962,7 +962,7 @@ void CPU::ExecuteInstruction(uint8_t opcode) {
|
|||||||
|
|
||||||
void CPU::ADC(uint8_t operand) {
|
void CPU::ADC(uint8_t operand) {
|
||||||
auto C = GetCarryFlag();
|
auto C = GetCarryFlag();
|
||||||
if (GetAccumulatorSize()) { // 8-bit mode
|
if (!E) { // 8-bit mode
|
||||||
uint16_t result = (A & 0xFF) + (operand & 0xFF); // + (C ? 1 : 0);
|
uint16_t result = (A & 0xFF) + (operand & 0xFF); // + (C ? 1 : 0);
|
||||||
SetCarryFlag(!(result > 0xFF)); // Update the carry flag
|
SetCarryFlag(!(result > 0xFF)); // Update the carry flag
|
||||||
|
|
||||||
@@ -997,7 +997,7 @@ void CPU::ADC(uint8_t operand) {
|
|||||||
|
|
||||||
void CPU::AND(uint16_t address) {
|
void CPU::AND(uint16_t address) {
|
||||||
uint8_t operand;
|
uint8_t operand;
|
||||||
if (GetAccumulatorSize() == 0) { // 16-bit mode
|
if (E == 0) { // 16-bit mode
|
||||||
uint16_t operand16 = memory.ReadWord(address);
|
uint16_t operand16 = memory.ReadWord(address);
|
||||||
A &= operand16;
|
A &= operand16;
|
||||||
SetZeroFlag(A == 0);
|
SetZeroFlag(A == 0);
|
||||||
|
|||||||
@@ -242,14 +242,14 @@ class CPU : public Memory {
|
|||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
// Registers
|
// Registers
|
||||||
|
|
||||||
uint8_t A = 0; // Accumulator
|
uint8_t A = 0; // Accumulator
|
||||||
uint8_t X = 0; // X index register
|
uint8_t X = 0; // X index register
|
||||||
uint8_t Y = 0; // Y index register
|
uint8_t Y = 0; // Y index register
|
||||||
// uint8_t SP = 0; // Stack Pointer
|
|
||||||
uint16_t DB = 0; // Data Bank register
|
|
||||||
uint16_t D = 0; // Direct Page register
|
uint16_t D = 0; // Direct Page register
|
||||||
|
uint16_t DB = 0; // Data Bank register
|
||||||
uint16_t PB = 0; // Program Bank register
|
uint16_t PB = 0; // Program Bank register
|
||||||
uint16_t PC = 0; // Program Counter
|
uint16_t PC = 0; // Program Counter
|
||||||
|
uint8_t E = 1; // Emulation mode flag
|
||||||
uint8_t status; // Processor Status (P)
|
uint8_t status; // Processor Status (P)
|
||||||
|
|
||||||
// Mnemonic Value Binary Description
|
// Mnemonic Value Binary Description
|
||||||
@@ -312,12 +312,7 @@ class CPU : public Memory {
|
|||||||
// CPX: Compare X register
|
// CPX: Compare X register
|
||||||
// CPY: Compare Y register
|
// CPY: Compare Y register
|
||||||
// DEC: Decrement
|
// DEC: Decrement
|
||||||
// DEX: Decrement X register
|
|
||||||
// DEY: Decrement Y register
|
|
||||||
// EOR: Exclusive OR
|
// EOR: Exclusive OR
|
||||||
// INC: Increment
|
|
||||||
// INX: Increment X register
|
|
||||||
// INY: Increment Y register
|
|
||||||
// JMP: Jump
|
// JMP: Jump
|
||||||
// JML: Jump long
|
// JML: Jump long
|
||||||
// JSR: Jump to subroutine
|
// JSR: Jump to subroutine
|
||||||
@@ -333,19 +328,6 @@ class CPU : public Memory {
|
|||||||
// PEA: Push effective address
|
// PEA: Push effective address
|
||||||
// PEI: Push effective indirect address
|
// PEI: Push effective indirect address
|
||||||
// PER: Push effective PC-relative address
|
// PER: Push effective PC-relative address
|
||||||
// PHA: Push accumulator
|
|
||||||
// PHB: Push data bank register
|
|
||||||
// PHD: Push direct page register
|
|
||||||
// PHK: Push program bank register
|
|
||||||
// PHP: Push processor status register
|
|
||||||
// PHX: Push X register
|
|
||||||
// PHY: Push Y register
|
|
||||||
// PLA: Pull accumulator
|
|
||||||
// PLB: Pull data bank register
|
|
||||||
// PLD: Pull direct page register
|
|
||||||
// PLP: Pull processor status register
|
|
||||||
// PLX: Pull X register
|
|
||||||
// PLY: Pull Y register
|
|
||||||
// ROL: Rotate left
|
// ROL: Rotate left
|
||||||
// ROR: Rotate right
|
// ROR: Rotate right
|
||||||
// RTI: Return from interrupt
|
// RTI: Return from interrupt
|
||||||
@@ -390,16 +372,86 @@ class CPU : public Memory {
|
|||||||
PC++;
|
PC++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SEC: Set carry flag
|
||||||
void SEC() { status |= 0x01; }
|
void SEC() { status |= 0x01; }
|
||||||
|
|
||||||
|
// CLC: Clear carry flag
|
||||||
void CLC() { status &= ~0x01; }
|
void CLC() { status &= ~0x01; }
|
||||||
|
|
||||||
|
// CLD: Clear decimal mode
|
||||||
void CLD() { status &= ~0x08; }
|
void CLD() { status &= ~0x08; }
|
||||||
|
|
||||||
|
// CLI: Clear interrupt disable flag
|
||||||
void CLI() { status &= ~0x04; }
|
void CLI() { status &= ~0x04; }
|
||||||
|
|
||||||
|
// CLV: Clear overflow flag
|
||||||
void CLV() { status &= ~0x40; }
|
void CLV() { status &= ~0x40; }
|
||||||
|
|
||||||
|
bool emulation_mode = false;
|
||||||
|
|
||||||
|
void CPX(uint16_t address) {
|
||||||
|
uint16_t memory_value =
|
||||||
|
E ? memory.ReadByte(address) : memory.ReadWord(address);
|
||||||
|
compare(X, memory_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPY(uint16_t address) {
|
||||||
|
uint16_t memory_value =
|
||||||
|
E ? memory.ReadByte(address) : memory.ReadWord(address);
|
||||||
|
compare(Y, memory_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEX: Decrement X register
|
||||||
|
void DEX() {
|
||||||
|
X--;
|
||||||
|
SetZeroFlag(X == 0);
|
||||||
|
SetNegativeFlag(X & 0x80);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEY: Decrement Y register
|
||||||
|
void DEY() {
|
||||||
|
Y--;
|
||||||
|
SetZeroFlag(Y == 0);
|
||||||
|
SetNegativeFlag(Y & 0x80);
|
||||||
|
}
|
||||||
|
|
||||||
|
// INX: Increment X register
|
||||||
|
void INX() {
|
||||||
|
X++;
|
||||||
|
SetNegativeFlag(X & 0x80);
|
||||||
|
SetZeroFlag(X == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// INY: Increment Y register
|
||||||
|
void INY() {
|
||||||
|
Y++;
|
||||||
|
SetNegativeFlag(Y & 0x80);
|
||||||
|
SetZeroFlag(Y == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// INC: Increment memory
|
||||||
|
void INC(uint16_t address) {
|
||||||
|
if (GetAccumulatorSize()) {
|
||||||
|
uint8_t value = ReadByte(address);
|
||||||
|
value++;
|
||||||
|
if (value == static_cast<uint8_t>(0x100)) {
|
||||||
|
value = 0x00; // Wrap around in 8-bit mode
|
||||||
|
}
|
||||||
|
WriteByte(address, value);
|
||||||
|
SetNegativeFlag(value & 0x80);
|
||||||
|
SetZeroFlag(value == 0);
|
||||||
|
} else {
|
||||||
|
uint16_t value = ReadWord(address);
|
||||||
|
value++;
|
||||||
|
if (value == static_cast<uint16_t>(0x10000)) {
|
||||||
|
value = 0x0000; // Wrap around in 16-bit mode
|
||||||
|
}
|
||||||
|
WriteByte(address, value);
|
||||||
|
SetNegativeFlag(value & 0x80);
|
||||||
|
SetZeroFlag(value == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Push Accumulator on Stack
|
// Push Accumulator on Stack
|
||||||
void PHA() { memory.PushByte(A); }
|
void PHA() { memory.PushByte(A); }
|
||||||
|
|
||||||
@@ -535,19 +587,22 @@ class CPU : public Memory {
|
|||||||
SetNegativeFlag(A & 0x80);
|
SetNegativeFlag(A & 0x80);
|
||||||
}
|
}
|
||||||
|
|
||||||
void INX() {
|
// XCE: Exchange Carry and Emulation Flags
|
||||||
X++;
|
void XCE() {
|
||||||
SetZeroFlag(X == 0);
|
uint8_t carry = status & 0x01;
|
||||||
SetNegativeFlag(X & 0x80);
|
status &= ~0x01;
|
||||||
}
|
status |= E;
|
||||||
|
E = carry;
|
||||||
void INY() {
|
|
||||||
Y++;
|
|
||||||
SetZeroFlag(Y == 0);
|
|
||||||
SetNegativeFlag(Y & 0x80);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void compare(uint16_t register_value, uint16_t memory_value) {
|
||||||
|
uint16_t result = register_value - memory_value;
|
||||||
|
SetNegativeFlag(result & (E ? 0x8000 : 0x80)); // Negative flag
|
||||||
|
SetZeroFlag(result == 0); // Zero flag
|
||||||
|
SetCarryFlag(register_value >= 0); // Carry flag
|
||||||
|
}
|
||||||
|
|
||||||
// Helper function to set or clear a specific flag bit
|
// Helper function to set or clear a specific flag bit
|
||||||
void SetFlag(uint8_t mask, bool set) {
|
void SetFlag(uint8_t mask, bool set) {
|
||||||
if (set) {
|
if (set) {
|
||||||
|
|||||||
@@ -74,8 +74,8 @@ class MemoryImpl : public Memory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WriteByte(uint32_t address, uint8_t value) override {
|
void WriteByte(uint32_t address, uint8_t value) override {
|
||||||
uint32_t mapped_address = GetMappedAddress(address);
|
// uint32_t mapped_address = GetMappedAddress(address);
|
||||||
memory_.at(mapped_address) = value;
|
memory_[address] = value;
|
||||||
}
|
}
|
||||||
void WriteWord(uint32_t address, uint16_t value) override {
|
void WriteWord(uint32_t address, uint16_t value) override {
|
||||||
uint32_t mapped_address = GetMappedAddress(address);
|
uint32_t mapped_address = GetMappedAddress(address);
|
||||||
|
|||||||
190
test/cpu_test.cc
190
test/cpu_test.cc
@@ -36,6 +36,9 @@ class MockMemory : public Memory {
|
|||||||
void SetMemoryContents(const std::vector<uint8_t>& data) {
|
void SetMemoryContents(const std::vector<uint8_t>& data) {
|
||||||
memory_.resize(64000);
|
memory_.resize(64000);
|
||||||
std::copy(data.begin(), data.end(), memory_.begin());
|
std::copy(data.begin(), data.end(), memory_.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Init() {
|
||||||
ON_CALL(*this, ReadByte(::testing::_))
|
ON_CALL(*this, ReadByte(::testing::_))
|
||||||
.WillByDefault(
|
.WillByDefault(
|
||||||
[this](uint16_t address) { return memory_.at(address); });
|
[this](uint16_t address) { return memory_.at(address); });
|
||||||
@@ -50,6 +53,15 @@ class MockMemory : public Memory {
|
|||||||
(static_cast<uint32_t>(memory_.at(address + 1)) << 8) |
|
(static_cast<uint32_t>(memory_.at(address + 1)) << 8) |
|
||||||
(static_cast<uint32_t>(memory_.at(address + 2)) << 16);
|
(static_cast<uint32_t>(memory_.at(address + 2)) << 16);
|
||||||
});
|
});
|
||||||
|
ON_CALL(*this, WriteByte(::testing::_, ::testing::_))
|
||||||
|
.WillByDefault([this](uint32_t address, uint8_t value) {
|
||||||
|
memory_[address] = value;
|
||||||
|
});
|
||||||
|
ON_CALL(*this, WriteWord(::testing::_, ::testing::_))
|
||||||
|
.WillByDefault([this](uint32_t address, uint16_t value) {
|
||||||
|
memory_[address] = value & 0xFF;
|
||||||
|
memory_[address + 1] = (value >> 8) & 0xFF;
|
||||||
|
});
|
||||||
ON_CALL(*this, PushByte(::testing::_)).WillByDefault([this](uint8_t value) {
|
ON_CALL(*this, PushByte(::testing::_)).WillByDefault([this](uint8_t value) {
|
||||||
memory_.at(SP_) = value;
|
memory_.at(SP_) = value;
|
||||||
});
|
});
|
||||||
@@ -69,6 +81,9 @@ class MockMemory : public Memory {
|
|||||||
this->SetSP(SP_ + 2);
|
this->SetSP(SP_ + 2);
|
||||||
return value;
|
return value;
|
||||||
});
|
});
|
||||||
|
ON_CALL(*this, ClearMemory()).WillByDefault([this]() {
|
||||||
|
memory_.resize(64000, 0x00);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -78,6 +93,11 @@ class MockMemory : public Memory {
|
|||||||
|
|
||||||
class CPUTest : public ::testing::Test {
|
class CPUTest : public ::testing::Test {
|
||||||
public:
|
public:
|
||||||
|
void SetUp() override {
|
||||||
|
mock_memory.Init();
|
||||||
|
mock_memory.ClearMemory();
|
||||||
|
}
|
||||||
|
|
||||||
MockMemory mock_memory;
|
MockMemory mock_memory;
|
||||||
CPU cpu{mock_memory};
|
CPU cpu{mock_memory};
|
||||||
};
|
};
|
||||||
@@ -239,9 +259,10 @@ TEST_F(CPUTest, AND_Immediate) {
|
|||||||
EXPECT_EQ(cpu.A, 0b10100000); // A register should now be 0b10100000
|
EXPECT_EQ(cpu.A, 0b10100000); // A register should now be 0b10100000
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CPUTest, AND_Absolute) {
|
TEST_F(CPUTest, AND_Absolute_16BitMode) {
|
||||||
cpu.A = 0b11111111; // A register
|
cpu.A = 0b11111111; // A register
|
||||||
cpu.status = 0x00; // 16-bit mode
|
cpu.E = 0; // 16-bit mode
|
||||||
|
cpu.status = 0x00; // Clear status flags
|
||||||
cpu.PC = 1; // PC register
|
cpu.PC = 1; // PC register
|
||||||
std::vector<uint8_t> data = {0x2D, 0x03, 0x00, 0b10101010, 0x01, 0x02};
|
std::vector<uint8_t> data = {0x2D, 0x03, 0x00, 0b10101010, 0x01, 0x02};
|
||||||
mock_memory.SetMemoryContents(data);
|
mock_memory.SetMemoryContents(data);
|
||||||
@@ -310,6 +331,142 @@ TEST_F(CPUTest, BRL) {
|
|||||||
EXPECT_EQ(cpu.PC, 0x1004);
|
EXPECT_EQ(cpu.PC, 0x1004);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
// Test for CPX instruction
|
||||||
|
TEST_F(CPUTest, CPX_CarryFlagSet) {
|
||||||
|
cpu.X = 0x1000;
|
||||||
|
cpu.CPX(0x0F00);
|
||||||
|
ASSERT_TRUE(cpu.GetCarryFlag()); // Carry flag should be set
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CPUTest, CPX_ZeroFlagSet) {
|
||||||
|
cpu.X = 0x0F00;
|
||||||
|
cpu.ExecuteInstruction(0xE0); // Immediate CPX
|
||||||
|
ASSERT_TRUE(cpu.GetZeroFlag()); // Zero flag should be set
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CPUTest, CPX_NegativeFlagSet) {
|
||||||
|
cpu.PC = 1;
|
||||||
|
cpu.X = 0x8000;
|
||||||
|
std::vector<uint8_t> data = {0xE0, 0xFF, 0xFF};
|
||||||
|
mock_memory.SetMemoryContents(data);
|
||||||
|
|
||||||
|
cpu.ExecuteInstruction(0xE0); // Immediate CPX (0xFFFF)
|
||||||
|
|
||||||
|
ASSERT_TRUE(cpu.GetNegativeFlag()); // Negative flag should be set
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for CPY instruction
|
||||||
|
TEST_F(CPUTest, CPY_CarryFlagSet) {
|
||||||
|
cpu.Y = 0x1000;
|
||||||
|
cpu.CPY(0x0F00);
|
||||||
|
ASSERT_TRUE(cpu.GetCarryFlag()); // Carry flag should be set
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CPUTest, CPY_ZeroFlagSet) {
|
||||||
|
cpu.Y = 0x0F00;
|
||||||
|
cpu.CPY(0x0F00);
|
||||||
|
ASSERT_TRUE(cpu.GetZeroFlag()); // Zero flag should be set
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CPUTest, CPY_NegativeFlagSet) {
|
||||||
|
cpu.PC = 1;
|
||||||
|
cpu.Y = 0x8000;
|
||||||
|
std::vector<uint8_t> data = {0xC0, 0xFF, 0xFF};
|
||||||
|
mock_memory.SetMemoryContents(data);
|
||||||
|
cpu.ExecuteInstruction(0xC0); // Immediate CPY (0xFFFF)
|
||||||
|
ASSERT_TRUE(cpu.GetNegativeFlag()); // Negative flag should be set
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// DEC - Decrement Memory
|
||||||
|
|
||||||
|
// Test for DEX instruction
|
||||||
|
TEST_F(CPUTest, DEX) {
|
||||||
|
cpu.X = 0x02; // Set X register to 2
|
||||||
|
cpu.ExecuteInstruction(0xCA); // Execute DEX instruction
|
||||||
|
EXPECT_EQ(0x01, cpu.X); // Expected value of X register after decrementing
|
||||||
|
|
||||||
|
cpu.X = 0x00; // Set X register to 0
|
||||||
|
cpu.ExecuteInstruction(0xCA); // Execute DEX instruction
|
||||||
|
EXPECT_EQ(0xFF, cpu.X); // Expected value of X register after decrementing
|
||||||
|
|
||||||
|
cpu.X = 0x80; // Set X register to 128
|
||||||
|
cpu.ExecuteInstruction(0xCA); // Execute DEX instruction
|
||||||
|
EXPECT_EQ(0x7F, cpu.X); // Expected value of X register after decrementing
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for DEY instruction
|
||||||
|
TEST_F(CPUTest, DEY) {
|
||||||
|
cpu.Y = 0x02; // Set Y register to 2
|
||||||
|
cpu.ExecuteInstruction(0x88); // Execute DEY instruction
|
||||||
|
EXPECT_EQ(0x01, cpu.Y); // Expected value of Y register after decrementing
|
||||||
|
|
||||||
|
cpu.Y = 0x00; // Set Y register to 0
|
||||||
|
cpu.ExecuteInstruction(0x88); // Execute DEY instruction
|
||||||
|
EXPECT_EQ(0xFF, cpu.Y); // Expected value of Y register after decrementing
|
||||||
|
|
||||||
|
cpu.Y = 0x80; // Set Y register to 128
|
||||||
|
cpu.ExecuteInstruction(0x88); // Execute DEY instruction
|
||||||
|
EXPECT_EQ(0x7F, cpu.Y); // Expected value of Y register after decrementing
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// INC - Increment Memory
|
||||||
|
|
||||||
|
/**
|
||||||
|
TEST_F(CPUTest, INC) {
|
||||||
|
cpu.status &= 0x20;
|
||||||
|
|
||||||
|
EXPECT_CALL(mock_memory, WriteByte(0x1000, 0x7F)).WillOnce(Return());
|
||||||
|
EXPECT_CALL(mock_memory, ReadByte(_)).WillOnce(Return(0x7F));
|
||||||
|
EXPECT_CALL(mock_memory, WriteByte(0x1000, 0x80)).WillOnce(Return());
|
||||||
|
|
||||||
|
cpu.WriteByte(0x1000, 0x7F);
|
||||||
|
cpu.INC(0x1000);
|
||||||
|
EXPECT_EQ(cpu.ReadByte(0x1000), 0x80);
|
||||||
|
EXPECT_TRUE(cpu.GetNegativeFlag());
|
||||||
|
EXPECT_FALSE(cpu.GetZeroFlag());
|
||||||
|
|
||||||
|
EXPECT_CALL(mock_memory, WriteByte(0x1000, 0xFF)).WillOnce(Return());
|
||||||
|
cpu.WriteByte(0x1000, 0xFF);
|
||||||
|
cpu.INC(0x1000);
|
||||||
|
EXPECT_CALL(mock_memory, ReadByte(_)).WillOnce(Return(0x00));
|
||||||
|
EXPECT_EQ(cpu.ReadByte(0x1000), 0x00);
|
||||||
|
EXPECT_FALSE(cpu.GetNegativeFlag());
|
||||||
|
EXPECT_TRUE(cpu.GetZeroFlag());
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
TEST_F(CPUTest, INX) {
|
||||||
|
cpu.X = 0x7F;
|
||||||
|
cpu.INX();
|
||||||
|
EXPECT_EQ(cpu.X, 0x80);
|
||||||
|
EXPECT_TRUE(cpu.GetNegativeFlag());
|
||||||
|
EXPECT_FALSE(cpu.GetZeroFlag());
|
||||||
|
|
||||||
|
cpu.X = 0xFF;
|
||||||
|
cpu.INX();
|
||||||
|
EXPECT_EQ(cpu.X, 0x00);
|
||||||
|
EXPECT_FALSE(cpu.GetNegativeFlag());
|
||||||
|
EXPECT_TRUE(cpu.GetZeroFlag());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CPUTest, INY) {
|
||||||
|
cpu.Y = 0x7F;
|
||||||
|
cpu.INY();
|
||||||
|
EXPECT_EQ(cpu.Y, 0x80);
|
||||||
|
EXPECT_TRUE(cpu.GetNegativeFlag());
|
||||||
|
EXPECT_FALSE(cpu.GetZeroFlag());
|
||||||
|
|
||||||
|
cpu.Y = 0xFF;
|
||||||
|
cpu.INY();
|
||||||
|
EXPECT_EQ(cpu.Y, 0x00);
|
||||||
|
EXPECT_FALSE(cpu.GetNegativeFlag());
|
||||||
|
EXPECT_TRUE(cpu.GetZeroFlag());
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Stack Tests
|
// Stack Tests
|
||||||
|
|
||||||
@@ -507,6 +664,35 @@ TEST_F(CPUTest, TAY) {
|
|||||||
EXPECT_EQ(cpu.Y, 0xDE); // Y register should now be equal to A
|
EXPECT_EQ(cpu.Y, 0xDE); // Y register should now be equal to A
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// XCE - Exchange Carry and Emulation Flags
|
||||||
|
|
||||||
|
TEST_F(CPUTest, XCESwitchToNativeMode) {
|
||||||
|
cpu.ExecuteInstruction(0x18); // Clear carry flag
|
||||||
|
cpu.ExecuteInstruction(0xFB); // Switch to native mode
|
||||||
|
EXPECT_FALSE(cpu.E); // Emulation mode flag should be cleared
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CPUTest, XCESwitchToEmulationMode) {
|
||||||
|
cpu.ExecuteInstruction(0x38); // Set carry flag
|
||||||
|
cpu.ExecuteInstruction(0xFB); // Switch to emulation mode
|
||||||
|
EXPECT_TRUE(cpu.E); // Emulation mode flag should be set
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CPUTest, XCESwitchBackAndForth) {
|
||||||
|
cpu.ExecuteInstruction(0x18); // Clear carry flag
|
||||||
|
cpu.ExecuteInstruction(0xFB); // Switch to native mode
|
||||||
|
EXPECT_FALSE(cpu.E); // Emulation mode flag should be cleared
|
||||||
|
|
||||||
|
cpu.ExecuteInstruction(0x38); // Set carry flag
|
||||||
|
cpu.ExecuteInstruction(0xFB); // Switch to emulation mode
|
||||||
|
EXPECT_TRUE(cpu.E); // Emulation mode flag should be set
|
||||||
|
|
||||||
|
cpu.ExecuteInstruction(0x18); // Clear carry flag
|
||||||
|
cpu.ExecuteInstruction(0xFB); // Switch to native mode
|
||||||
|
EXPECT_FALSE(cpu.E); // Emulation mode flag should be cleared
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace emu
|
} // namespace emu
|
||||||
} // namespace app
|
} // namespace app
|
||||||
} // namespace yaze
|
} // namespace yaze
|
||||||
|
|||||||
Reference in New Issue
Block a user