Files
yaze/test/emu/cpu_test.cc

4176 lines
139 KiB
C++

#include "app/emu/cpu/cpu.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "app/emu/cpu/clock.h"
#include "app/emu/cpu/internal/opcodes.h"
#include "app/emu/debug/asm_parser.h"
#include "app/emu/memory/memory.h"
#include "app/emu/memory/mock_memory.h"
namespace yaze_test {
namespace emu_test {
using yaze::app::emu::AsmParser;
using yaze::app::emu::Cpu;
using yaze::app::emu::memory::MockClock;
using yaze::app::emu::memory::MockMemory;
/**
* \test Test fixture for CPU unit tests
*/
class CpuTest : public ::testing::Test {
public:
void SetUp() override {
mock_memory.Init();
EXPECT_CALL(mock_memory, ClearMemory()).Times(::testing::AtLeast(1));
mock_memory.ClearMemory();
asm_parser.CreateInternalOpcodeMap();
}
AsmParser asm_parser;
MockMemory mock_memory;
MockClock mock_clock;
Cpu cpu{mock_memory, mock_clock};
};
using ::testing::_;
using ::testing::Return;
// ============================================================================
// Infrastructure
// ============================================================================
TEST_F(CpuTest, CheckMemoryContents) {
MockMemory memory;
std::vector<uint8_t> data = {0x00, 0x01, 0x02, 0x03, 0x04};
memory.SetMemoryContents(data);
EXPECT_CALL(memory, ReadByte(0)).WillOnce(Return(0x00));
EXPECT_CALL(memory, ReadByte(1)).WillOnce(Return(0x01));
EXPECT_CALL(memory, ReadByte(2)).WillOnce(Return(0x02));
EXPECT_CALL(memory, ReadByte(3)).WillOnce(Return(0x03));
EXPECT_CALL(memory, ReadByte(4)).WillOnce(Return(0x04));
EXPECT_CALL(memory, ReadByte(63999)).WillOnce(Return(0x00));
EXPECT_EQ(memory.ReadByte(0), 0x00);
EXPECT_EQ(memory.ReadByte(1), 0x01);
EXPECT_EQ(memory.ReadByte(2), 0x02);
EXPECT_EQ(memory.ReadByte(3), 0x03);
EXPECT_EQ(memory.ReadByte(4), 0x04);
EXPECT_EQ(memory.ReadByte(63999), 0x00);
}
// ============================================================================
// ADC - Add with Carry
TEST_F(CpuTest, ADC_CheckCarryFlag) {
cpu.A = 0xFF;
cpu.SetAccumulatorSize(true);
std::vector<uint8_t> data = {0x15, 0x01}; // Operand at address 0x15
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadByte(_)).WillOnce(Return(1));
cpu.ExecuteInstruction(0x69); // ADC Immediate
EXPECT_EQ(cpu.A, 0x00);
EXPECT_TRUE(cpu.GetCarryFlag());
}
TEST_F(CpuTest, ADC_DirectPageIndexedIndirectX) {
cpu.A = 0x03;
cpu.D = 0x2000; // Setting Direct Page register to 0x2000
std::vector<uint8_t> data = {0x61, 0x10}; // ADC (dp, X)
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x2012, {0x00, 0x30}); // [0x2012] = 0x3000
mock_memory.InsertMemory(0x3000, {0x06}); // [0x3000] = 0x06
cpu.X = 0x02; // X register
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x10));
EXPECT_CALL(mock_memory, ReadWord(0x2012)).WillOnce(Return(0x3000));
EXPECT_CALL(mock_memory, ReadByte(0x3000)).WillOnce(Return(0x06));
cpu.ExecuteInstruction(0x61); // ADC (dp, X)
EXPECT_EQ(cpu.A, 0x09); // 0x03 + 0x06 = 0x09
}
TEST_F(CpuTest, ADC_StackRelative) {
cpu.A = 0x03;
std::vector<uint8_t> data = {0x63, 0x02}; // ADC sr
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0201, {0x06}); // [0x0201] = 0x06
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x02)); // Operand
EXPECT_CALL(mock_memory, ReadByte(0x0201))
.WillOnce(Return(0x06)); // Memory value
cpu.ExecuteInstruction(0x63); // ADC Stack Relative
EXPECT_EQ(cpu.A, 0x09); // 0x03 + 0x06 = 0x09
}
TEST_F(CpuTest, ADC_DirectPage) {
cpu.A = 0x01;
cpu.D = 0x2000; // Setting Direct Page register to 0x2000
std::vector<uint8_t> data = {0x65, 0x10}; // ADC dp
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x2010, {0x05}); // [0x2010] = 0x05
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x10));
EXPECT_CALL(mock_memory, ReadByte(0x2010)).WillOnce(Return(0x05));
cpu.ExecuteInstruction(0x65); // ADC Direct Page
EXPECT_EQ(cpu.A, 0x06);
}
TEST_F(CpuTest, ADC_DirectPageIndirectLong) {
cpu.A = 0x03;
cpu.D = 0x2000;
std::vector<uint8_t> data = {0x67, 0x10};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x2010, {0x05, 0x00, 0x30});
mock_memory.InsertMemory(0x030005, {0x06});
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x10));
EXPECT_CALL(mock_memory, ReadWordLong(0x2010)).WillOnce(Return(0x300005));
EXPECT_CALL(mock_memory, ReadWord(0x300005)).WillOnce(Return(0x06));
cpu.ExecuteInstruction(0x67); // ADC Direct Page Indirect Long
EXPECT_EQ(cpu.A, 0x09);
}
TEST_F(CpuTest, ADC_Immediate_TwoPositiveNumbers) {
cpu.A = 0x01;
cpu.SetAccumulatorSize(true);
std::vector<uint8_t> data = {0x01};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadByte(_)).WillOnce(Return(0x01));
cpu.ExecuteInstruction(0x69); // ADC Immediate
EXPECT_EQ(cpu.A, 0x02);
}
TEST_F(CpuTest, ADC_Immediate_PositiveAndNegativeNumbers) {
cpu.A = 10;
cpu.SetAccumulatorSize(true);
std::vector<uint8_t> data = {0x69, static_cast<uint8_t>(-20)};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadByte(_)).WillOnce(Return(-20));
cpu.ExecuteInstruction(0x69); // ADC Immediate
EXPECT_EQ(cpu.A, static_cast<uint8_t>(-10));
}
TEST_F(CpuTest, ADC_Absolute) {
cpu.A = 0x01;
cpu.status = 0x00; // 16-bit mode
std::vector<uint8_t> data = {0x6D, 0x03, 0x00, 0x05, 0x00};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x0003));
EXPECT_CALL(mock_memory, ReadWord(0x0003)).WillOnce(Return(0x0005));
cpu.ExecuteInstruction(0x6D); // ADC Absolute
EXPECT_EQ(cpu.A, 0x06);
}
TEST_F(CpuTest, ADC_AbsoluteLong) {
cpu.A = 0x01;
cpu.SetAccumulatorSize(false); // 16-bit mode
cpu.SetCarryFlag(false);
std::vector<uint8_t> data = {0x6F, 0x04, 0x00, 0x00, 0x05, 0x00};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadWordLong(0x0001)).WillOnce(Return(0x0004));
EXPECT_CALL(mock_memory, ReadWord(0x0004)).WillOnce(Return(0x0005));
cpu.ExecuteInstruction(0x6F); // ADC Absolute Long
EXPECT_EQ(cpu.A, 0x06);
}
TEST_F(CpuTest, ADC_DirectPageIndirectIndexedY) {
cpu.A = 0x03;
cpu.Y = 0x02;
cpu.D = 0x2000;
std::vector<uint8_t> data = {0x71, 0x10};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x2010, {0x00, 0x30}); // [0x2010] = 0x3000
mock_memory.InsertMemory(0x3002, {0x06}); // [0x3002] = 0x06
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x10));
EXPECT_CALL(mock_memory, ReadWord(0x2010)).WillOnce(Return(0x3000));
EXPECT_CALL(mock_memory, ReadByte(0x3002)).WillOnce(Return(0x06));
cpu.ExecuteInstruction(0x71); // ADC Direct Page Indirect Indexed, Y
EXPECT_EQ(cpu.A, 0x09); // 0x03 + 0x06 = 0x09
}
TEST_F(CpuTest, ADC_DirectPageIndirect) {
cpu.A = 0x02;
cpu.D = 0x2000; // Setting Direct Page register to 0x2000
std::vector<uint8_t> data = {0x72, 0x10}; // ADC (dp)
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x2010, {0x00, 0x30}); // [0x2010] = 0x3000
mock_memory.InsertMemory(0x3000, {0x05}); // [0x3000] = 0x05
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x10));
EXPECT_CALL(mock_memory, ReadWord(0x2010)).WillOnce(Return(0x3000));
EXPECT_CALL(mock_memory, ReadByte(0x3000)).WillOnce(Return(0x05));
cpu.ExecuteInstruction(0x72); // ADC (dp)
EXPECT_EQ(cpu.A, 0x07); // 0x02 + 0x05 = 0x07
}
TEST_F(CpuTest, ADC_StackRelativeIndirectIndexedY) {
cpu.A = 0x03; // A register
cpu.Y = 0x02; // Y register
cpu.DB = 0x10; // Setting Data Bank register to 0x20
std::vector<uint8_t> data = {0x73, 0x02}; // ADC sr, Y
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0201, {0x00, 0x30}); // [0x0201] = 0x3000
mock_memory.InsertMemory(0x103002, {0x06}); // [0x3002] = 0x06
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x02));
EXPECT_CALL(mock_memory, ReadWord(0x0201)).WillOnce(Return(0x3000));
EXPECT_CALL(mock_memory, ReadByte(0x103002)).WillOnce(Return(0x06));
cpu.ExecuteInstruction(0x73); // ADC Stack Relative Indexed Y
EXPECT_EQ(cpu.A, 0x09); // 0x03 + 0x06 = 0x09
}
TEST_F(CpuTest, ADC_DirectPageIndexedX) {
cpu.A = 0x03;
cpu.X = 0x02;
cpu.D = 0x2000;
std::vector<uint8_t> data = {0x75, 0x10};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x2012, {0x06}); // [0x2012] = 0x3000
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x10));
EXPECT_CALL(mock_memory, ReadByte(0x2012)).WillOnce(Return(0x06));
cpu.ExecuteInstruction(0x75); // ADC Direct Page Indexed, X
EXPECT_EQ(cpu.A, 0x09); // 0x03 + 0x06 = 0x09
}
TEST_F(CpuTest, ADC_DirectPageIndirectLongIndexedY) {
cpu.A = 0x03;
cpu.Y = 0x02;
cpu.D = 0x2000;
cpu.status = 0x00;
std::vector<uint8_t> data = {0x77, 0x10};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x2010, {0x05, 0x00, 0x01});
mock_memory.InsertMemory(0x010007, {0x06});
EXPECT_CALL(mock_memory, ReadWordLong(0x2010)).WillOnce(Return(0x010005));
EXPECT_CALL(mock_memory, ReadWord(0x010007)).WillOnce(Return(0x06));
cpu.ExecuteInstruction(0x77); // ADC DP Indirect Long Indexed, Y
EXPECT_EQ(cpu.A, 0x09);
}
TEST_F(CpuTest, ADC_AbsoluteIndexedY) {
cpu.A = 0x03;
cpu.Y = 0x02; // Y register
cpu.DB = 0x20; // Setting Data Bank register to 0x20
std::vector<uint8_t> data = {0x79, 0x03, 0x00, 0x00, 0x05, 0x00};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x0003));
EXPECT_CALL(mock_memory, ReadWord(0x200005)).WillOnce(Return(0x0005));
mock_memory.InsertMemory(0x200005, {0x05});
cpu.ExecuteInstruction(0x79); // ADC Absolute Indexed Y
EXPECT_EQ(cpu.A, 0x08);
}
TEST_F(CpuTest, ADC_AbsoluteIndexedX) {
cpu.A = 0x03;
cpu.X = 0x02; // X register
cpu.DB = 0x20; // Setting Data Bank register to 0x20
cpu.SetCarryFlag(false);
cpu.SetAccumulatorSize(false); // 16-bit mode
std::vector<uint8_t> data = {0x7D, 0x03, 0x00};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x0003));
EXPECT_CALL(mock_memory, ReadWord(0x200005)).WillOnce(Return(0x0005));
mock_memory.InsertMemory(0x200005, {0x05}); // Inserting memory at 0x2005
cpu.ExecuteInstruction(0x7D); // ADC Absolute Indexed X
EXPECT_EQ(cpu.A, 0x08);
}
TEST_F(CpuTest, ADC_AbsoluteLongIndexedX) {
cpu.A = 0x03;
cpu.X = 0x02; // X register
cpu.SetCarryFlag(false);
cpu.SetAccumulatorSize(false); // 16-bit mode
std::vector<uint8_t> data = {0x7F, 0x00, 0x00, 0x01};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x010000, {0x03, 0x05});
EXPECT_CALL(mock_memory, ReadWordLong(0x0001)).WillOnce(Return(0x010000));
EXPECT_CALL(mock_memory, ReadWord(0x010002)).WillOnce(Return(0x0005));
cpu.ExecuteInstruction(0x7F); // ADC Absolute Long Indexed X
EXPECT_EQ(cpu.A, 0x08);
}
// ============================================================================
// AND - Logical AND
TEST_F(CpuTest, AND_DirectPageIndexedIndirectX) {
cpu.A = 0b11110000; // A register
cpu.D = 0x2000; // Setting Direct Page register to 0x2000
cpu.X = 0x02; // X register
cpu.status = 0xFF; // 8-bit mode
std::vector<uint8_t> data = {0x21, 0x10};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x2012, {0x00, 0x30}); // [0x2012] = 0x3000
mock_memory.InsertMemory(0x3000, {0b10101010}); // [0x3000] = 0b10101010
// Get the operand
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x10));
// Get the value at the operand
EXPECT_CALL(mock_memory, ReadWord(0x2012)).WillOnce(Return(0x3000));
// Get the value at the operand
EXPECT_CALL(mock_memory, ReadByte(0x3000)).WillOnce(Return(0b10101010));
cpu.ExecuteInstruction(0x21); // AND Direct Page Indexed Indirect X
EXPECT_EQ(cpu.A, 0b10100000); // A register should now be 0b10100000
}
TEST_F(CpuTest, AND_StackRelative) {
cpu.A = 0b11110000; // A register
cpu.status = 0xFF; // 8-bit mode
std::vector<uint8_t> data = {0x23, 0x02};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0201, {0b10101010}); // [0x0201] = 0b10101010
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x02));
// Get the value at the operand
EXPECT_CALL(mock_memory, ReadByte(0x0201)).WillOnce(Return(0b10101010));
cpu.ExecuteInstruction(0x23); // AND Stack Relative
EXPECT_EQ(cpu.A, 0b10100000); // A register should now be 0b10100000
}
TEST_F(CpuTest, AND_DirectPage) {
cpu.A = 0b11110000; // A register
cpu.D = 0x2000; // Setting Direct Page register to 0x2000
std::vector<uint8_t> data = {0x25, 0x10};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x2010, {0b10101010}); // [0x2010] = 0b10101010
// Get the operand
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x10));
// Get the value at the operand
EXPECT_CALL(mock_memory, ReadByte(0x2010)).WillOnce(Return(0b10101010));
cpu.ExecuteInstruction(0x25); // AND Direct Page
EXPECT_EQ(cpu.A, 0b10100000); // A register should now be 0b10100000
}
TEST_F(CpuTest, AND_DirectPageIndirectLong) {
cpu.A = 0b11110000; // A register
cpu.D = 0x2000; // Setting Direct Page register to 0x2000
cpu.status = 0xFF; // 8-bit mode
std::vector<uint8_t> data = {0x27, 0x10};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x2010, {0x05, 0x00, 0x30});
mock_memory.InsertMemory(0x300005, {0b10101010});
// Get the operand
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x10));
// Get the value at the operand
EXPECT_CALL(mock_memory, ReadWordLong(0x2010)).WillOnce(Return(0x300005));
// Get the value at the operand
EXPECT_CALL(mock_memory, ReadByte(0x300005)).WillOnce(Return(0b10101010));
cpu.ExecuteInstruction(0x27); // AND Direct Page Indirect Long
EXPECT_EQ(cpu.A, 0b10100000); // A register should now be 0b10100000
}
TEST_F(CpuTest, AND_Immediate) {
cpu.A = 0b11110000; // A register
std::vector<uint8_t> data = {0x29, 0b10101010}; // AND #0b10101010
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0x29); // AND Immediate
EXPECT_EQ(cpu.A, 0b10100000); // A register should now be 0b10100000
}
TEST_F(CpuTest, AND_Absolute_16BitMode) {
cpu.A = 0b11111111; // A register
cpu.E = 0; // 16-bit mode
cpu.status = 0x00; // Clear status flags
std::vector<uint8_t> data = {0x2D, 0x03, 0x00, 0b10101010, 0x01, 0x02};
mock_memory.SetMemoryContents(data);
// Get the absolute address
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x0003));
// Get the value at the absolute address
EXPECT_CALL(mock_memory, ReadWord(0x0003)).WillOnce(Return(0b10101010));
cpu.ExecuteInstruction(0x2D); // AND Absolute
EXPECT_THAT(cpu.PC, testing::Eq(0x03));
EXPECT_EQ(cpu.A, 0b10101010); // A register should now be 0b10101010
}
TEST_F(CpuTest, AND_AbsoluteLong) {
cpu.A = 0x01;
cpu.status = 0x00; // 16-bit mode
std::vector<uint8_t> data = {0x2F, 0x04, 0x00, 0x00, 0x05, 0x00};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadWordLong(0x0001)).WillOnce(Return(0x000004));
EXPECT_CALL(mock_memory, ReadWordLong(0x0004)).WillOnce(Return(0x000005));
cpu.ExecuteInstruction(0x2F); // ADC Absolute Long
EXPECT_EQ(cpu.A, 0x01);
}
TEST_F(CpuTest, AND_DirectPageIndirectIndexedY) {
cpu.A = 0b11110000; // A register
cpu.D = 0x2000; // Setting Direct Page register to 0x2000
cpu.Y = 0x02; // Y register
std::vector<uint8_t> data = {0x31, 0x10};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x2010, {0x00, 0x30}); // [0x2010] = 0x3000
mock_memory.InsertMemory(0x3002, {0b10101010}); // [0x3002] = 0b10101010
// Get the value at the operand
EXPECT_CALL(mock_memory, ReadWord(0x2010)).WillOnce(Return(0x3000));
cpu.ExecuteInstruction(0x31); // AND Direct Page Indirect Indexed Y
EXPECT_EQ(cpu.A, 0b10100000); // A register should now be 0b10100000
}
TEST_F(CpuTest, AND_DirectPageIndirect) {
cpu.A = 0b11110000; // A register
cpu.D = 0x2000; // Setting Direct Page register to 0x2000
std::vector<uint8_t> data = {0x32, 0x10};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x2010, {0x00, 0x30}); // [0x2010] = 0x3000
mock_memory.InsertMemory(0x3000, {0b10101010}); // [0x3000] = 0b10101010
// Get the value at the operand
EXPECT_CALL(mock_memory, ReadWord(0x2010)).WillOnce(Return(0x3000));
cpu.ExecuteInstruction(0x32); // AND Direct Page Indirect
EXPECT_EQ(cpu.A, 0b10100000); // A register should now be 0b10100000
}
TEST_F(CpuTest, AND_StackRelativeIndirectIndexedY) {
cpu.A = 0b11110000; // A register
cpu.Y = 0x02; // Y register
cpu.DB = 0x10; // Setting Data Bank register to 0x20
cpu.SetSP(0x01FF); // Setting Stack Pointer to 0x01FF
std::vector<uint8_t> data = {0x33, 0x02};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0201, {0x00, 0x30}); // [0x0201] = 0x3000
mock_memory.InsertMemory(0x103002, {0b10101010}); // [0x3002] = 0b10101010
EXPECT_CALL(mock_memory, SP()).WillRepeatedly(Return(0x01FF));
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x02));
EXPECT_CALL(mock_memory, ReadWord(0x0201)).WillOnce(Return(0x3000));
EXPECT_CALL(mock_memory, ReadByte(0x103002)).WillOnce(Return(0b10101010));
cpu.ExecuteInstruction(0x33); // AND Stack Relative Indirect Indexed Y
EXPECT_EQ(cpu.A, 0b10100000); // A register should now be 0b10100000
}
TEST_F(CpuTest, AND_DirectPageIndexedX) {
cpu.A = 0b11110000; // A register
cpu.D = 0x2000; // Setting Direct Page register to 0x2000
cpu.X = 0x02; // X register
std::vector<uint8_t> data = {0x35, 0x10};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x2012, {0b10101010}); // [0x2012] = 0b10101010
// Get the value at the operand
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x10));
EXPECT_CALL(mock_memory, ReadByte(0x2012)).WillOnce(Return(0b10101010));
cpu.ExecuteInstruction(0x35); // AND Direct Page Indexed X
EXPECT_EQ(cpu.A, 0b10100000); // A register should now be 0b10100000
}
TEST_F(CpuTest, AND_DirectPageIndirectLongIndexedY) {
cpu.A = 0b11110000; // A register
cpu.D = 0x2000; // Setting Direct Page register to 0x2000
cpu.Y = 0x02; // Y register
std::vector<uint8_t> data = {0x37, 0x10};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x2010, {0x05, 0x00, 0x30});
mock_memory.InsertMemory(0x300005, {0b10101010});
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x10));
EXPECT_CALL(mock_memory, ReadWordLong(0x2010)).WillOnce(Return(0x300005));
EXPECT_CALL(mock_memory, ReadByte(0x300007)).WillOnce(Return(0b10101010));
cpu.ExecuteInstruction(0x37); // AND Direct Page Indirect Long Indexed Y
EXPECT_EQ(cpu.A, 0b10100000); // A register should now be 0b10100000
}
TEST_F(CpuTest, AND_AbsoluteIndexedY) {
cpu.A = 0b11110000; // A register
cpu.Y = 0x02; // Y register
std::vector<uint8_t> data = {0x39, 0x03, 0x00,
0b00000000, 0b10101010, 0b01010101};
mock_memory.SetMemoryContents(data);
// Get the absolute address
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x0003));
// Add the offset from the Y register to the absolute address
uint16_t address = 0x0003 + cpu.Y;
// Get the value at the absolute address + Y
EXPECT_CALL(mock_memory, ReadByte(address)).WillOnce(Return(0b10101010));
cpu.ExecuteInstruction(0x39); // AND Absolute, Y
EXPECT_THAT(cpu.PC, testing::Eq(0x03));
EXPECT_EQ(cpu.A, 0b10100000); // A register should now be 0b10100000
}
TEST_F(CpuTest, AND_AbsoluteIndexedX) {
cpu.A = 0b11110000; // A register
cpu.X = 0x02; // X register
std::vector<uint8_t> data = {0x3D, 0x03, 0x00,
0b00000000, 0b10101010, 0b01010101};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x200005, {0b10101010});
// Get the absolute address
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x0003));
// Add the offset from the X register to the absolute address
uint16_t address = 0x0003 + static_cast<uint16_t>(cpu.X & 0xFF);
// Get the value at the absolute address + X
EXPECT_CALL(mock_memory, ReadByte(address)).WillOnce(Return(0b10101010));
cpu.ExecuteInstruction(0x3D); // AND Absolute, X
// EXPECT_THAT(cpu.PC, testing::Eq(0x03));
EXPECT_EQ(cpu.A, 0b10100000); // A register should now be 0b10100000
}
TEST_F(CpuTest, AND_AbsoluteLongIndexedX) {
cpu.A = 0b11110000; // A register
cpu.X = 0x02; // X register
cpu.status = 0xFF; // 8-bit mode
std::vector<uint8_t> data = {0x3F, 0x03, 0x00, 0x00,
0b00000000, 0b10101010, 0b01010101};
mock_memory.SetMemoryContents(data);
// Get the absolute address
EXPECT_CALL(mock_memory, ReadWordLong(0x0001)).WillOnce(Return(0x0003));
// Add the offset from the X register to the absolute address
uint16_t address = 0x0003 + static_cast<uint16_t>(cpu.X & 0xFF);
// Get the value at the absolute address + X
EXPECT_CALL(mock_memory, ReadByte(address)).WillOnce(Return(0b10101010));
cpu.ExecuteInstruction(0x3F); // AND Absolute Long, X
EXPECT_THAT(cpu.PC, testing::Eq(0x04));
EXPECT_EQ(cpu.A, 0b10100000); // A register should now be 0b10100000
}
// ============================================================================
// ASL - Arithmetic Shift Left
TEST_F(CpuTest, ASL_DirectPage) {
cpu.D = 0x1000; // Setting Direct Page register to 0x1000
cpu.PC = 0x1000;
std::vector<uint8_t> data = {0x06, 0x10}; // ASL dp
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x1010, {0x40}); // [0x1010] = 0x40
cpu.ExecuteInstruction(0x06); // ASL Direct Page
EXPECT_TRUE(cpu.GetCarryFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
EXPECT_TRUE(cpu.GetNegativeFlag());
}
TEST_F(CpuTest, ASL_Accumulator) {
cpu.status = 0xFF; // 8-bit mode
cpu.A = 0x40;
std::vector<uint8_t> data = {0x0A}; // ASL A
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0x0A); // ASL Accumulator
EXPECT_EQ(cpu.A, 0x80);
EXPECT_TRUE(cpu.GetCarryFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
EXPECT_TRUE(cpu.GetNegativeFlag());
}
TEST_F(CpuTest, ASL_Absolute) {
std::vector<uint8_t> data = {0x0E, 0x10, 0x20}; // ASL abs
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x2010, {0x40}); // [0x2010] = 0x40
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x2010));
EXPECT_CALL(mock_memory, ReadByte(0x2010)).WillOnce(Return(0x40));
cpu.ExecuteInstruction(0x0E); // ASL Absolute
EXPECT_TRUE(cpu.GetCarryFlag());
EXPECT_TRUE(cpu.GetZeroFlag());
EXPECT_FALSE(cpu.GetNegativeFlag());
}
TEST_F(CpuTest, ASL_DirectPageIndexedX) {
cpu.D = 0x1000; // Setting Direct Page register to 0x1000
cpu.X = 0x02; // Setting X register to 0x02
std::vector<uint8_t> data = {0x16, 0x10}; // ASL dp,X
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x1012, {0x40}); // [0x1012] = 0x40
cpu.ExecuteInstruction(0x16); // ASL DP Indexed, X
EXPECT_TRUE(cpu.GetCarryFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
EXPECT_TRUE(cpu.GetNegativeFlag());
}
TEST_F(CpuTest, ASL_AbsoluteIndexedX) {
cpu.X = 0x02; // Setting X register to 0x02
std::vector<uint8_t> data = {0x1E, 0x10, 0x20}; // ASL abs,X
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x2012, {0x40}); // [0x2012] = 0x40
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x2010));
EXPECT_CALL(mock_memory, ReadByte(0x2012)).WillOnce(Return(0x40));
cpu.ExecuteInstruction(0x1E); // ASL Absolute, X
EXPECT_TRUE(cpu.GetCarryFlag());
EXPECT_TRUE(cpu.GetZeroFlag());
EXPECT_FALSE(cpu.GetNegativeFlag());
}
// ============================================================================
// BCC - Branch if Carry Clear
TEST_F(CpuTest, BCC_WhenCarryFlagClear) {
cpu.SetCarryFlag(false);
std::vector<uint8_t> data = {0x90, 0x05, 0x01}; // Operand at address 0x1001
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadByte(_)).WillOnce(Return(5));
cpu.ExecuteInstruction(0x90); // BCC
EXPECT_EQ(cpu.PC, 0x05);
}
TEST_F(CpuTest, BCC_WhenCarryFlagSet) {
cpu.SetCarryFlag(true);
std::vector<uint8_t> data = {0x90, 0x02, 0x01};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadByte(_)).WillOnce(Return(2));
cpu.ExecuteInstruction(0x90); // BCC
EXPECT_EQ(cpu.PC, 2);
}
// ============================================================================
// BCS - Branch if Carry Set
TEST_F(CpuTest, BCS_WhenCarryFlagSet) {
cpu.SetCarryFlag(true);
std::vector<uint8_t> data = {0xB0, 0x07, 0x02}; // Operand at address 0x1001
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadByte(_)).WillOnce(Return(0x07));
cpu.ExecuteInstruction(0xB0); // BCS
EXPECT_EQ(cpu.PC, 0x07);
}
TEST_F(CpuTest, BCS_WhenCarryFlagClear) {
cpu.SetCarryFlag(false);
std::vector<uint8_t> data = {0x10, 0x02, 0x01};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadByte(_)).WillOnce(Return(2));
cpu.ExecuteInstruction(0xB0); // BCS
EXPECT_EQ(cpu.PC, 2);
}
// ============================================================================
// BEQ - Branch if Equal
TEST_F(CpuTest, BEQ_Immediate_ZeroFlagSet) {
cpu.PB = 0x00;
cpu.SetZeroFlag(true);
std::vector<uint8_t> data = {0xF0, 0x09}; // Operand at address 0x1001
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xF0); // BEQ
EXPECT_EQ(cpu.PC, 0x09);
}
TEST_F(CpuTest, BEQ_Immediate_ZeroFlagClear) {
cpu.SetZeroFlag(false);
std::vector<uint8_t> data = {0xF0, 0x03}; // Operand at address 0x1001
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadByte(_)).WillOnce(Return(0x03));
cpu.ExecuteInstruction(0xF0); // BEQ
EXPECT_EQ(cpu.PC, 0x02);
}
TEST_F(CpuTest, BEQ_Immediate_ZeroFlagSet_OverflowFlagSet) {
cpu.SetZeroFlag(true);
cpu.SetOverflowFlag(true);
std::vector<uint8_t> data = {0xF0, 0x03}; // Operand at address 0x1001
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadByte(_)).WillOnce(Return(0x03));
cpu.ExecuteInstruction(0xF0); // BEQ
EXPECT_EQ(cpu.PC, 0x03);
}
TEST_F(CpuTest, BEQ_Immediate_ZeroFlagClear_OverflowFlagSet) {
cpu.SetZeroFlag(false);
cpu.SetOverflowFlag(true);
std::vector<uint8_t> data = {0xF0, 0x03, 0x02}; // Operand at address 0x1001
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadByte(_)).WillOnce(Return(0x03));
cpu.ExecuteInstruction(0xF0); // BEQ
EXPECT_EQ(cpu.PC, 0x02);
}
// ============================================================================
// BIT - Bit Test
TEST_F(CpuTest, BIT_DirectPage) {
cpu.A = 0x01;
cpu.D = 0x1000; // Setting Direct Page register to 0x1000
cpu.status = 0xFF;
std::vector<uint8_t> data = {0x24, 0x10}; // BIT
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x1010, {0x81}); // [0x1010] = 0x81
// Read the operand
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x10));
// Read the value at the address of the operand
EXPECT_CALL(mock_memory, ReadByte(0x1010)).WillOnce(Return(0x81));
cpu.ExecuteInstruction(0x24); // BIT
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetOverflowFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, BIT_Absolute) {
cpu.A = 0x01;
cpu.status = 0xFF;
std::vector<uint8_t> data = {0x00, 0x10}; // BIT
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0010, {0x81}); // [0x0010] = 0x81
// Read the operand
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x10));
// Read the value at the address of the operand
EXPECT_CALL(mock_memory, ReadByte(0x0010)).WillOnce(Return(0x81));
cpu.ExecuteInstruction(0x24); // BIT
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetOverflowFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, BIT_DirectPageIndexedX) {
cpu.A = 0x01;
cpu.X = 0x02;
cpu.D = 0x1000; // Setting Direct Page register to 0x1000
cpu.status = 0xFF;
std::vector<uint8_t> data = {0x34, 0x10}; // BIT
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x1012, {0x81}); // [0x1010] = 0x81
// Read the operand
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x10));
// Read the value at the address of the operand
EXPECT_CALL(mock_memory, ReadByte(0x1012)).WillOnce(Return(0x81));
cpu.ExecuteInstruction(0x34); // BIT
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetOverflowFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, BIT_AbsoluteIndexedX) {
cpu.A = 0x01;
cpu.X = 0x02;
cpu.status = 0xFF;
std::vector<uint8_t> data = {0x00, 0x10}; // BIT
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0012, {0x81}); // [0x0010] = 0x81
// Read the operand
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x10));
// Read the value at the address of the operand
EXPECT_CALL(mock_memory, ReadByte(0x0012)).WillOnce(Return(0x81));
cpu.ExecuteInstruction(0x3C); // BIT
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetOverflowFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, BIT_Immediate) {
cpu.A = 0x01;
cpu.status = 0xFF;
std::vector<uint8_t> data = {0x24, 0x00, 0x10}; // BIT
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0010, {0x81}); // [0x0010] = 0x81
// Read the operand
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x10));
// Read the value at the address of the operand
EXPECT_CALL(mock_memory, ReadByte(0x0010)).WillOnce(Return(0x81));
cpu.ExecuteInstruction(0x24); // BIT
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetOverflowFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
// ============================================================================
// BMI - Branch if Minus
TEST_F(CpuTest, BMI_BranchTaken) {
cpu.SetNegativeFlag(true);
std::vector<uint8_t> data = {0x30, 0x05}; // BMI
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0x30); // BMI
EXPECT_EQ(cpu.PC, 0x0005);
}
TEST_F(CpuTest, BMI_BranchNotTaken) {
cpu.SetNegativeFlag(false);
std::vector<uint8_t> data = {0x30, 0x02}; // BMI
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0x30); // BMI
EXPECT_EQ(cpu.PC, 0x0002);
}
// ============================================================================
// BNE - Branch if Not Equal
TEST_F(CpuTest, BNE_BranchTaken) {
cpu.SetZeroFlag(false);
std::vector<uint8_t> data = {0xD0, 0x05}; // BNE
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xD0); // BNE
EXPECT_EQ(cpu.PC, 0x0007);
}
TEST_F(CpuTest, BNE_BranchNotTaken) {
cpu.SetZeroFlag(true);
std::vector<uint8_t> data = {0xD0, 0x05}; // BNE
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xD0); // BNE
EXPECT_EQ(cpu.PC, 0x0002);
}
// ============================================================================
// BPL - Branch if Positive
TEST_F(CpuTest, BPL_BranchTaken) {
cpu.SetNegativeFlag(false);
std::vector<uint8_t> data = {0x10, 0x07}; // BPL
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0x10); // BPL
EXPECT_EQ(cpu.PC, 0x0007);
}
TEST_F(CpuTest, BPL_BranchNotTaken) {
cpu.SetNegativeFlag(true);
std::vector<uint8_t> data = {0x10, 0x02}; // BPL
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0x10); // BPL
EXPECT_EQ(cpu.PC, 0x0002);
}
// ============================================================================
// BRA - Branch Always
TEST_F(CpuTest, BRA) {
std::vector<uint8_t> data = {0x80, 0x02}; // BRA
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0x80); // BRA
EXPECT_EQ(cpu.PC, 0x0004);
}
// ============================================================================
TEST_F(CpuTest, BRK) {
std::vector<uint8_t> data = {0x00}; // BRK
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0xFFFE, {0x10, 0x20}); // [0xFFFE] = 0x2010
EXPECT_CALL(mock_memory, ReadWord(0xFFFE)).WillOnce(Return(0x2010));
cpu.ExecuteInstruction(0x00); // BRK
EXPECT_EQ(cpu.PC, 0x2010);
EXPECT_TRUE(cpu.GetInterruptFlag());
}
// ============================================================================
// BRL - Branch Long
TEST_F(CpuTest, BRL) {
std::vector<uint8_t> data = {0x82, 0x10, 0x20}; // BRL
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x2010));
cpu.ExecuteInstruction(0x82); // BRL
EXPECT_EQ(cpu.PC, 0x2010);
}
// ============================================================================
// BVC - Branch if Overflow Clear
TEST_F(CpuTest, BVC_BranchTaken) {
cpu.SetOverflowFlag(false);
std::vector<uint8_t> data = {0x50, 0x02}; // BVC
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0x50); // BVC
EXPECT_EQ(cpu.PC, 0x0002);
}
// ============================================================================
// BVS - Branch if Overflow Set
TEST_F(CpuTest, BVS_BranchTaken) {
cpu.SetOverflowFlag(true);
std::vector<uint8_t> data = {0x70, 0x02}; // BVS
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0x70); // BVS
EXPECT_EQ(cpu.PC, 0x0002);
}
// ============================================================================
// CLC - Clear Carry Flag
TEST_F(CpuTest, CLC) {
cpu.SetCarryFlag(true);
cpu.PC = 0x0000;
std::vector<uint8_t> data = {0x18}; // CLC
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0x18); // CLC
EXPECT_FALSE(cpu.GetCarryFlag());
}
// ============================================================================
// CLD - Clear Decimal Mode Flag
TEST_F(CpuTest, CLD) {
cpu.SetDecimalFlag(true);
cpu.PC = 0x0000;
std::vector<uint8_t> data = {0xD8}; // CLD
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xD8); // CLD
EXPECT_FALSE(cpu.GetDecimalFlag());
}
// ============================================================================
// CLI - Clear Interrupt Disable Flag
TEST_F(CpuTest, CLI) {
cpu.SetInterruptFlag(true);
cpu.PC = 0x0000;
std::vector<uint8_t> data = {0x58}; // CLI
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0x58); // CLI
EXPECT_FALSE(cpu.GetInterruptFlag());
}
// ============================================================================
// CLV - Clear Overflow Flag
TEST_F(CpuTest, CLV) {
cpu.SetOverflowFlag(true);
cpu.PC = 0x0000;
std::vector<uint8_t> data = {0xB8}; // CLV
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xB8); // CLV
EXPECT_FALSE(cpu.GetOverflowFlag());
}
// ============================================================================
// CMP - Compare Accumulator
TEST_F(CpuTest, CMP_DirectPageIndexedIndirectX) {
cpu.status = 0x00;
cpu.SetAccumulatorSize(true);
cpu.A = 0x80;
cpu.X = 0x02;
cpu.D = 0x1000;
cpu.DB = 0x01;
std::vector<uint8_t> data = {0xC1, 0x10};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x1012, {0x00, 0x30}); // [0x1012] = 0x3000
mock_memory.InsertMemory(0x013000, {0x40}); // [0x3000] = 0x40
cpu.ExecuteInstruction(0xC1);
EXPECT_TRUE(cpu.GetCarryFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
EXPECT_TRUE(cpu.GetNegativeFlag());
}
TEST_F(CpuTest, CMP_StackRelative) {
cpu.A = 0x80;
cpu.SetSP(0x01FF);
std::vector<uint8_t> data = {0xC3, 0x02};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0201, {0x40, 0x9F});
EXPECT_CALL(mock_memory, SP()).WillRepeatedly(Return(0x01FF));
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x02));
EXPECT_CALL(mock_memory, ReadByte(0x0201)).WillOnce(Return(0x30));
// Execute the CMP Stack Relative instruction
cpu.ExecuteInstruction(0xC3);
EXPECT_TRUE(cpu.GetCarryFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
EXPECT_FALSE(cpu.GetNegativeFlag());
mock_memory.InsertMemory(0x0002, {0xC3, 0x03});
EXPECT_CALL(mock_memory, SP()).WillRepeatedly(Return(0x01FF));
EXPECT_CALL(mock_memory, ReadByte(0x0003)).WillOnce(Return(0x03));
EXPECT_CALL(mock_memory, ReadByte(0x0202)).WillOnce(Return(0x9F));
cpu.status = 0b00110000;
cpu.ExecuteInstruction(0xC3);
EXPECT_TRUE(cpu.GetCarryFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
EXPECT_TRUE(cpu.GetNegativeFlag());
}
TEST_F(CpuTest, CMP_DirectPage) {
// Set the accumulator to 8-bit mode
cpu.status = 0x00;
cpu.SetAccumulatorSize(true);
cpu.A = 0x80; // Set the accumulator to 0x80
mock_memory.InsertMemory(0x0000, {0xC5});
// Execute the CMP Direct Page instruction
cpu.ExecuteInstruction(0xC5);
// Check the status flags
EXPECT_TRUE(cpu.GetCarryFlag()); // Carry flag should be set
EXPECT_FALSE(cpu.GetZeroFlag()); // Zero flag should not be set
EXPECT_TRUE(cpu.GetNegativeFlag()); // Negative flag should be set
}
TEST_F(CpuTest, CMP_DirectPageIndirectLong) {
// Set the accumulator to 8-bit mode
cpu.status = 0x00;
cpu.SetAccumulatorSize(true);
cpu.A = 0x80; // Set the accumulator to 0x80
// Set up the instruction and operand
mock_memory.InsertMemory(0x0000, {0xC7, 0x02});
cpu.D = 0x1000; // Set the Direct Page register to 0x1000
mock_memory.InsertMemory(0x1002, {0x00, 0x00, 0x01});
mock_memory.InsertMemory(0x010000, {0x40}); // [0x010000] = 0x40
// Execute the CMP Direct Page Indirect Long instruction
cpu.ExecuteInstruction(0xC7);
// Check the status flags
EXPECT_TRUE(cpu.GetCarryFlag()); // Carry flag should be set
EXPECT_FALSE(cpu.GetZeroFlag()); // Zero flag should not be set
EXPECT_FALSE(cpu.GetNegativeFlag()); // Negative flag should be set
}
TEST_F(CpuTest, CMP_Immediate_8Bit) {
// Set the accumulator to 8-bit mode
cpu.status = 0x00;
cpu.SetAccumulatorSize(true);
cpu.A = 0x80; // Set the accumulator to 0x80
mock_memory.InsertMemory(0x0000, {0x40});
// Set up the memory to return 0x40 when the Immediate addressing mode is used
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(::testing::Return(0x40));
// Execute the CMP Immediate instruction
cpu.ExecuteInstruction(0xC9);
// Check the status flags
EXPECT_TRUE(cpu.GetCarryFlag()); // Carry flag should be set
EXPECT_FALSE(cpu.GetZeroFlag()); // Zero flag should not be set
EXPECT_FALSE(cpu.GetNegativeFlag()); // Negative flag should be set
}
TEST_F(CpuTest, CMP_Absolute_16Bit) {
// Set the accumulator to 16-bit mode
cpu.SetAccumulatorSize(false);
cpu.A = 0x8000; // Set the accumulator to 0x8000
mock_memory.InsertMemory(0x0000, {0x34, 0x12});
// Execute the CMP Absolute instruction
cpu.ExecuteInstruction(0xCD);
// Check the status flags
EXPECT_TRUE(cpu.GetCarryFlag()); // Carry flag should be set
EXPECT_FALSE(cpu.GetZeroFlag()); // Zero flag should not be set
EXPECT_TRUE(cpu.GetNegativeFlag()); // Negative flag should be set
}
TEST_F(CpuTest, CMP_AbsoluteLong) {
cpu.A = 0x01;
cpu.status = 0b00000001; // 16-bit mode
std::vector<uint8_t> data = {0xCF, 0x04, 0x00, 0x00, 0x05, 0x00};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadWordLong(0x0001)).WillOnce(Return(0x000004));
EXPECT_CALL(mock_memory, ReadWord(0x0004)).WillOnce(Return(0x000005));
cpu.ExecuteInstruction(0xCF); // ADC Absolute Long
EXPECT_FALSE(cpu.GetCarryFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
EXPECT_TRUE(cpu.GetNegativeFlag());
}
TEST_F(CpuTest, CMP_DirectPageIndirect) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.D = 0x0200;
std::vector<uint8_t> data = {0xD1, 0x3C};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x00023C, {0x00, 0x10});
EXPECT_CALL(mock_memory, ReadByte(0x000001)).WillOnce(Return(0x3C));
EXPECT_CALL(mock_memory, ReadWord(0x00023C)).WillOnce(Return(0x1000));
EXPECT_CALL(mock_memory, ReadByte(0x1000)).WillOnce(Return(0x7F));
// Execute the CMP Direct Page Indirect instruction
cpu.ExecuteInstruction(0xD1);
// Check the status flags
EXPECT_TRUE(cpu.GetCarryFlag()); // Carry flag should be set
EXPECT_FALSE(cpu.GetZeroFlag()); // Zero flag should not be set
EXPECT_TRUE(cpu.GetNegativeFlag()); // Negative flag should be set
}
TEST_F(CpuTest, CMP_StackRelativeIndirectIndexedY) {
cpu.A = 0x03; // A register
cpu.Y = 0x02; // Y register
cpu.DB = 0x10; // Setting Data Bank register to 0x20
cpu.SetSP(0x01FF); // Setting Stack Pointer to 0x01FF
std::vector<uint8_t> data = {0xD3, 0x02}; // ADC sr, Y
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0201, {0x00, 0x30}); // [0x0201] = 0x3000
mock_memory.InsertMemory(0x103002, {0x06}); // [0x3002] = 0x06
EXPECT_CALL(mock_memory, SP()).WillRepeatedly(Return(0x01FF));
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x02));
EXPECT_CALL(mock_memory, ReadWord(0x0201)).WillOnce(Return(0x3000));
EXPECT_CALL(mock_memory, ReadByte(0x103002)).WillOnce(Return(0x06));
// Execute the CMP Stack Relative Indirect Indexed Y instruction
cpu.ExecuteInstruction(0xD3);
// Check the status flags
EXPECT_TRUE(cpu.GetCarryFlag()); // Carry flag should be set
EXPECT_FALSE(cpu.GetZeroFlag()); // Zero flag should not be set
EXPECT_TRUE(cpu.GetNegativeFlag()); // Negative flag should be set
}
TEST_F(CpuTest, CMP_DirectPageIndexedX) {
// Set the accumulator to 8-bit mode
cpu.status = 0x00;
cpu.SetAccumulatorSize(true);
cpu.A = 0x80; // Set the accumulator to 0x80
cpu.X = 0x02; // Set the X register to 0x02
mock_memory.InsertMemory(0x0000, {0xD5});
// Set up the memory to return 0x40 when the Direct Page Indexed X addressing
// mode is used
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(::testing::Return(0x40));
EXPECT_CALL(mock_memory, ReadByte(0x0042)).WillOnce(::testing::Return(0x40));
// Execute the CMP Direct Page Indexed X instruction
cpu.ExecuteInstruction(0xD5);
// Check the status flags
EXPECT_TRUE(cpu.GetCarryFlag()); // Carry flag should be set
EXPECT_FALSE(cpu.GetZeroFlag()); // Zero flag should not be set
EXPECT_FALSE(cpu.GetNegativeFlag()); // Negative flag should be set
}
TEST_F(CpuTest, CMP_DirectPageIndirectLongIndexedY) {
cpu.A = 0b11110000; // A register
cpu.D = 0x2000; // Setting Direct Page register to 0x2000
cpu.Y = 0x02; // Y register
std::vector<uint8_t> data = {0xD7, 0x10};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x2010, {0x05, 0x00, 0x30});
mock_memory.InsertMemory(0x300005, {0b10101010});
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x10));
EXPECT_CALL(mock_memory, ReadWordLong(0x2010)).WillOnce(Return(0x300005));
EXPECT_CALL(mock_memory, ReadByte(0x300007)).WillOnce(Return(0b10101010));
// Execute the CMP Direct Page Indirect Long Indexed Y instruction
cpu.ExecuteInstruction(0xD7);
// Check the status flags
EXPECT_TRUE(cpu.GetCarryFlag()); // Carry flag should be set
EXPECT_FALSE(cpu.GetZeroFlag()); // Zero flag should not be set
EXPECT_FALSE(cpu.GetNegativeFlag()); // Negative flag should be set
}
TEST_F(CpuTest, CMP_AbsoluteIndexedY) {
// Set the accumulator to 16-bit mode
cpu.SetAccumulatorSize(false);
cpu.A = 0x8000; // Set the accumulator to 0x8000
cpu.Y = 0x02; // Set the Y register to 0x02
mock_memory.InsertMemory(0x0000, {0xD9});
// Execute the CMP Absolute Indexed Y instruction
cpu.ExecuteInstruction(0xD9);
// Check the status flags
EXPECT_TRUE(cpu.GetCarryFlag()); // Carry flag should be set
EXPECT_FALSE(cpu.GetZeroFlag()); // Zero flag should not be set
EXPECT_TRUE(cpu.GetNegativeFlag()); // Negative flag should be set
}
TEST_F(CpuTest, CMP_AbsoluteIndexedX) {
// Set the accumulator to 16-bit mode
cpu.SetAccumulatorSize(false);
cpu.A = 0x8000; // Set the accumulator to 0x8000
cpu.X = 0x02; // Set the X register to 0x02
mock_memory.InsertMemory(0x0000, {0xDD});
// Execute the CMP Absolute Indexed X instruction
cpu.ExecuteInstruction(0xDD);
// Check the status flags
EXPECT_TRUE(cpu.GetCarryFlag()); // Carry flag should be set
EXPECT_FALSE(cpu.GetZeroFlag()); // Zero flag should not be set
EXPECT_TRUE(cpu.GetNegativeFlag()); // Negative flag should be set
}
TEST_F(CpuTest, CMP_AbsoluteLongIndexedX) {
// Set the accumulator to 16-bit mode
cpu.SetAccumulatorSize(false);
cpu.A = 0x8000; // Set the accumulator to 0x8000
cpu.X = 0x02; // Set the X register to 0x02
mock_memory.InsertMemory(0x0000, {0xDF});
// Execute the CMP Absolute Long Indexed X instruction
cpu.ExecuteInstruction(0xDF);
// Check the status flags
EXPECT_TRUE(cpu.GetCarryFlag()); // Carry flag should be set
EXPECT_FALSE(cpu.GetZeroFlag()); // Zero flag should not be set
EXPECT_TRUE(cpu.GetNegativeFlag()); // Negative flag should be set
}
// ============================================================================
// TODO: FIX COP TEST
TEST_F(CpuTest, COP) {
// mock_memory.SetSP(0x01FF);
// std::vector<uint8_t> data = {0x02}; // COP
// mock_memory.SetMemoryContents(data);
// mock_memory.InsertMemory(0xFFF4, {0x10, 0x20}); // [0xFFFE] = 0x2010
// ON_CALL(mock_memory, SetSP(_)).WillByDefault(::testing::Return());
// EXPECT_CALL(mock_memory, PushWord(0x0002));
// EXPECT_CALL(mock_memory, PushByte(0x30));
// EXPECT_CALL(mock_memory, ReadWord(0xFFF4)).WillOnce(Return(0x2010));
// cpu.ExecuteInstruction(0x02); // COP
// EXPECT_TRUE(cpu.GetInterruptFlag());
// EXPECT_FALSE(cpu.GetDecimalFlag());
}
// ============================================================================
// Test for CPX instruction
TEST_F(CpuTest, CPX_Immediate_ZeroFlagSet) {
cpu.SetIndexSize(false); // Set X register to 16-bit mode
cpu.SetAccumulatorSize(false);
cpu.X = 0x1234;
std::vector<uint8_t> data = {0xE0, 0x34, 0x12}; // CPX #0x1234
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xE0); // Immediate CPX
ASSERT_TRUE(cpu.GetZeroFlag()); // Zero flag should be set
}
TEST_F(CpuTest, CPX_Immediate_NegativeFlagSet) {
cpu.SetIndexSize(false); // Set X register to 16-bit mode
cpu.PC = 0;
cpu.X = 0x9000;
std::vector<uint8_t> data = {0xE0, 0xFF, 0xFF}; // CPX #0x8001
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xE0); // Immediate CPX
ASSERT_TRUE(cpu.GetNegativeFlag()); // Negative flag should be set
}
// Test for CPX instruction
TEST_F(CpuTest, CPX_DirectPage) {
cpu.SetIndexSize(false); // Set Y register to 16-bit mode
cpu.PC = 0;
cpu.X = 0x1234;
std::vector<uint8_t> data = {0xE4, 0x34, 0x12}; // CPY #0x1234
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xE4); // Immediate CPY
ASSERT_TRUE(cpu.GetCarryFlag()); // Carry flag should be set
}
TEST_F(CpuTest, CPX_Absolute) {
cpu.SetIndexSize(false); // Set Y register to 16-bit mode
cpu.PC = 0;
cpu.X = 0x1234;
std::vector<uint8_t> data = {0xEC, 0x34, 0x12}; // CPY #0x1234
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xEC); // Immediate CPY
ASSERT_TRUE(cpu.GetCarryFlag()); // Carry flag should be set
}
TEST_F(CpuTest, CPY_Immediate_ZeroFlagSet) {
cpu.SetIndexSize(false); // Set Y register to 16-bit mode
cpu.SetAccumulatorSize(false);
cpu.Y = 0x5678;
std::vector<uint8_t> data = {0xC0, 0x78, 0x56}; // CPY #0x5678
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xC0); // Immediate CPY
ASSERT_TRUE(cpu.GetZeroFlag()); // Zero flag should be set
}
TEST_F(CpuTest, CPY_Immediate_NegativeFlagSet) {
cpu.SetIndexSize(false); // Set Y register to 16-bit mode
cpu.PC = 0;
cpu.Y = 0x9000;
std::vector<uint8_t> data = {0xC0, 0x01, 0x80}; // CPY #0x8001
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xC0); // Immediate CPY
ASSERT_TRUE(cpu.GetNegativeFlag()); // Negative flag should be set
}
// Test for CPY instruction
TEST_F(CpuTest, CPY_DirectPage) {
cpu.SetIndexSize(false); // Set Y register to 16-bit mode
cpu.PC = 0;
cpu.Y = 0x1234;
std::vector<uint8_t> data = {0xC4, 0x34, 0x12}; // CPY #0x1234
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xC4); // Immediate CPY
ASSERT_TRUE(cpu.GetCarryFlag()); // Carry flag should be set
}
TEST_F(CpuTest, CPY_Absolute) {
cpu.SetIndexSize(false); // Set Y register to 16-bit mode
cpu.PC = 0;
cpu.Y = 0x1234;
std::vector<uint8_t> data = {0xCC, 0x34, 0x12}; // CPY #0x1234
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xCC); // Immediate CPY
ASSERT_TRUE(cpu.GetCarryFlag()); // Carry flag should be set
}
// ============================================================================
// DEC - Decrement Memory
TEST_F(CpuTest, DEC_Accumulator) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.A = 0x02; // Set A register to 2
cpu.ExecuteInstruction(0x3A); // Execute DEC instruction
EXPECT_EQ(0x01, cpu.A); // Expected value of A register after decrementing
cpu.A = 0x00; // Set A register to 0
cpu.ExecuteInstruction(0x3A); // Execute DEC instruction
EXPECT_EQ(0xFF, cpu.A); // Expected value of A register after decrementing
cpu.A = 0x80; // Set A register to 128
cpu.ExecuteInstruction(0x3A); // Execute DEC instruction
EXPECT_EQ(0x7F, cpu.A); // Expected value of A register after decrementing
}
TEST_F(CpuTest, DEC_DirectPage) {
cpu.status = 0xFF; // Set A register to 8-bit mode
cpu.D = 0x1000; // Set Direct Page register to 0x1000
std::vector<uint8_t> data = {0xC6, 0x7F};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x107F, {0x02}); // [0x107F] = 0x02
cpu.ExecuteInstruction(0xC6); // Execute DEC instruction
EXPECT_EQ(0x01, mock_memory.ReadByte(0x107F)); // Expected value of memory
// location after decrementing
}
TEST_F(CpuTest, DEC_Absolute) {
cpu.status = 0xFF; // Set A register to 8-bit mode
std::vector<uint8_t> data = {0xCE, 0x00, 0x10};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x1000, {0x02}); // [0x1000] = 0x02
cpu.ExecuteInstruction(0xCE); // Execute DEC instruction
EXPECT_EQ(0x01, mock_memory.ReadByte(0x1000)); // Expected value of memory
// location after decrementing
}
TEST_F(CpuTest, DEC_DirectPageIndexedX) {
cpu.status = 0xFF; // Set A register to 8-bit mode
cpu.D = 0x1000; // Set Direct Page register to 0x1000
cpu.X = 0x02; // Set X register to 0x02
std::vector<uint8_t> data = {0xD6, 0x7F};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x1081, {0x02}); // [0x1081] = 0x02
cpu.ExecuteInstruction(0xD6); // Execute DEC instruction
EXPECT_EQ(0x01, mock_memory.ReadByte(0x1081)); // Expected value of memory
// location after decrementing
}
TEST_F(CpuTest, DEC_AbsoluteIndexedX) {
cpu.status = 0xFF; // Set A register to 8-bit mode
cpu.X = 0x02; // Set X register to 0x02
std::vector<uint8_t> data = {0xDE, 0x00, 0x10};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x1002, {0x02}); // [0x1002] = 0x02
cpu.ExecuteInstruction(0xDE); // Execute DEC instruction
EXPECT_EQ(0x01, mock_memory.ReadByte(0x1002)); // Expected value of memory
// location after decrementing
}
// ============================================================================
// Test for DEX instruction
TEST_F(CpuTest, DEX) {
cpu.SetIndexSize(true); // Set X register to 8-bit mode
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.SetIndexSize(true); // Set Y register to 8-bit mode
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
}
// ============================================================================
// EOR
TEST_F(CpuTest, EOR_DirectPageIndexedIndirectX) {
cpu.A = 0b10101010; // A register
cpu.X = 0x02; // X register
cpu.status = 0xFF; // 8-bit mode
std::vector<uint8_t> data = {0x41, 0x7E};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0080, {0x00, 0x10}); // [0x0080] = 0x1000
mock_memory.InsertMemory(0x1000, {0b01010101}); // [0x1000] = 0b01010101
cpu.ExecuteInstruction(0x41); // EOR DP Indexed Indirect, X
EXPECT_EQ(cpu.A, 0b11111111); // A register should now be 0b11111111
}
TEST_F(CpuTest, EOR_StackRelative) {
cpu.A = 0b10101010; // A register
cpu.status = 0xFF; // 8-bit mode
cpu.SetSP(0x01FF); // Set Stack Pointer to 0x01FF
std::vector<uint8_t> data = {0x43, 0x02};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0201, {0b01010101}); // [0x0201] = 0b01010101
EXPECT_CALL(mock_memory, SP()).WillRepeatedly(Return(0x01FF));
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x02));
EXPECT_CALL(mock_memory, ReadByte(0x0201)).WillOnce(Return(0b01010101));
cpu.ExecuteInstruction(0x43); // EOR Stack Relative
EXPECT_EQ(cpu.A, 0b11111111); // A register should now be 0b11111111
}
TEST_F(CpuTest, EOR_DirectPage) {
cpu.A = 0b10101010; // A register
cpu.status = 0xFF; // 8-bit mode
std::vector<uint8_t> data = {0x45, 0x7F};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x007F, {0b01010101}); // [0x007F] = 0b01010101
cpu.ExecuteInstruction(0x45); // EOR Direct Page
EXPECT_EQ(cpu.A, 0b11111111); // A register should now be 0b11111111
}
TEST_F(CpuTest, EOR_DirectPageIndirectLong) {
cpu.A = 0b10101010; // A register
cpu.status = 0xFF; // 8-bit mode
std::vector<uint8_t> data = {0x47, 0x7F};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x007F, {0x00, 0x10, 0x00}); // [0x007F] = 0x1000
mock_memory.InsertMemory(0x1000, {0b01010101}); // [0x1000] = 0b01010101
cpu.ExecuteInstruction(0x47); // EOR Direct Page Indirect Long
EXPECT_EQ(cpu.A, 0b11111111); // A register should now be 0b11111111
}
TEST_F(CpuTest, EOR_Immediate_8bit) {
cpu.A = 0b10101010; // A register
cpu.status = 0xFF; // 8-bit mode
std::vector<uint8_t> data = {0x49, 0b01010101};
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0x49); // EOR Immediate
EXPECT_EQ(cpu.A, 0b11111111); // A register should now be 0b11111111
}
TEST_F(CpuTest, EOR_Absolute) {
cpu.A = 0b10101010; // A register
cpu.status = 0xFF; // 8-bit mode
std::vector<uint8_t> data = {0x4D, 0x00, 0x10};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x1000, {0b01010101}); // [0x1000] = 0b01010101
cpu.ExecuteInstruction(0x4D); // EOR Absolute
EXPECT_EQ(cpu.A, 0b11111111); // A register should now be 0b11111111
}
TEST_F(CpuTest, EOR_AbsoluteLong) {
cpu.A = 0b10101010; // A register
cpu.status = 0xFF; // 8-bit mode
std::vector<uint8_t> data = {0x4F, 0x00, 0x10, 0x00};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x1000, {0b01010101}); // [0x1000] = 0b01010101
cpu.ExecuteInstruction(0x4F); // EOR Absolute Long
EXPECT_EQ(cpu.A, 0b11111111); // A register should now be 0b11111111
}
TEST_F(CpuTest, EOR_DirectPageIndirectIndexedY) {
cpu.A = 0b10101010; // A register
cpu.Y = 0x02; // Y register
cpu.status = 0xFF; // 8-bit mode
std::vector<uint8_t> data = {0x51, 0x7E};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x007E, {0x00, 0x10}); // [0x007E] = 0x1000
mock_memory.InsertMemory(0x1002, {0b01010101}); // [0x1002] = 0b01010101
cpu.ExecuteInstruction(0x51); // EOR DP Indirect Indexed, Y
EXPECT_EQ(cpu.A, 0b11111111); // A register should now be 0b11111111
}
TEST_F(CpuTest, EOR_DirectPageIndirect) {
cpu.A = 0b10101010; // A register
cpu.status = 0xFF; // 8-bit mode
std::vector<uint8_t> data = {0x52, 0x7E};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x007E, {0x00, 0x10}); // [0x007E] = 0x1000
mock_memory.InsertMemory(0x1000, {0b01010101}); // [0x1000] = 0b01010101
cpu.ExecuteInstruction(0x52); // EOR DP Indirect
EXPECT_EQ(cpu.A, 0b11111111); // A register should now be 0b11111111
}
TEST_F(CpuTest, EOR_StackRelativeIndirectIndexedY) {
cpu.A = 0b10101010; // A register
cpu.Y = 0x02; // Y register
cpu.status = 0xFF; // 8-bit mode
std::vector<uint8_t> data = {0x53, 0x02};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0201, {0x00, 0x10}); // [0x0201] = 0x1000
mock_memory.InsertMemory(0x1002, {0b01010101}); // [0x1002] = 0b01010101
EXPECT_CALL(mock_memory, SP()).WillRepeatedly(Return(0x01FF));
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x02));
EXPECT_CALL(mock_memory, ReadWord(0x0201)).WillOnce(Return(0x1000));
EXPECT_CALL(mock_memory, ReadByte(0x1002)).WillOnce(Return(0b01010101));
cpu.ExecuteInstruction(0x53); // EOR Stack Relative Indirect Indexed, Y
EXPECT_EQ(cpu.A, 0b11111111); // A register should now be 0b11111111
}
TEST_F(CpuTest, EOR_DirectPageIndexedX) {
cpu.A = 0b10101010; // A register
cpu.X = 0x02; // X register
cpu.status = 0xFF; // 8-bit mode
std::vector<uint8_t> data = {0x55, 0x7E};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0080, {0b01010101}); // [0x0080] = 0b01010101
cpu.ExecuteInstruction(0x55); // EOR DP Indexed, X
EXPECT_EQ(cpu.A, 0b11111111); // A register should now be 0b11111111
}
TEST_F(CpuTest, EOR_DirectPageIndirectLongIndexedY) {
cpu.A = 0b10101010; // A register
cpu.Y = 0x02; // Y register
cpu.status = 0xFF; // 8-bit mode
std::vector<uint8_t> data = {0x51, 0x7E};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x007E, {0x00, 0x10, 0x00}); // [0x007E] = 0x1000
mock_memory.InsertMemory(0x1002, {0b01010101}); // [0x1002] = 0b01010101
cpu.ExecuteInstruction(0x51); // EOR DP Indirect Long Indexed, Y
EXPECT_EQ(cpu.A, 0b11111111); // A register should now be 0b11111111
}
TEST_F(CpuTest, EOR_AbsoluteIndexedY) {
cpu.A = 0b10101010; // A register
cpu.Y = 0x02; // Y register
cpu.status = 0xFF; // 8-bit mode
// PC register
std::vector<uint8_t> data = {0x59, 0x7C, 0x00};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x007E, {0b01010101}); // [0x007E] = 0b01010101
cpu.ExecuteInstruction(0x59); // EOR Absolute Indexed, Y
EXPECT_EQ(cpu.A, 0b11111111); // A register should now be 0b11111111
}
TEST_F(CpuTest, EOR_AbsoluteIndexedX) {
cpu.A = 0b10101010; // A register
cpu.X = 0x02; // X register
cpu.status = 0xFF; // 8-bit mode
// PC register
std::vector<uint8_t> data = {0x5D, 0x7C, 0x00};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x007E, {0b01010101}); // [0x007E] = 0b01010101
cpu.ExecuteInstruction(0x5D); // EOR Absolute Indexed, X
EXPECT_EQ(cpu.A, 0b11111111); // A register should now be 0b11111111
}
TEST_F(CpuTest, EOR_AbsoluteLongIndexedX) {
cpu.A = 0b10101010; // A register
cpu.X = 0x02; // X register
cpu.status = 0xFF; // 8-bit mode
// PC register
std::vector<uint8_t> data = {0x5F, 0x7C, 0x00, 0x00};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x007E, {0b01010101}); // [0x007E] = 0b01010101
cpu.ExecuteInstruction(0x5F); // EOR Absolute Long Indexed, X
EXPECT_EQ(cpu.A, 0b11111111); // A register should now be 0b11111111
}
// ============================================================================
// INC - Increment Memory
TEST_F(CpuTest, INC_Accumulator) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.A = 0x02; // Set A register to 2
cpu.ExecuteInstruction(0x1A); // Execute INC instruction
EXPECT_EQ(0x03, cpu.A); // Expected value of A register after incrementing
cpu.A = 0xFF; // Set A register to 0xFF
cpu.ExecuteInstruction(0x1A); // Execute INC instruction
EXPECT_EQ(0x00, cpu.A); // Expected value of A register after incrementing
cpu.A = 0x7F; // Set A register to 127
cpu.ExecuteInstruction(0x1A); // Execute INC instruction
EXPECT_EQ(0x80, cpu.A); // Expected value of A register after incrementing
}
TEST_F(CpuTest, INC_DirectPage_8bit) {
cpu.SetAccumulatorSize(true);
cpu.D = 0x0200; // Setting Direct Page register to 0x0200
std::vector<uint8_t> data = {0xE6, 0x20};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0220, {0x40}); // [0x0220] = 0x40
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x20));
EXPECT_CALL(mock_memory, ReadByte(0x0220)).WillOnce(Return(0x40));
cpu.ExecuteInstruction(0xE6); // INC Direct Page
EXPECT_EQ(mock_memory[0x0220], 0x41);
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, INC_Absolute_16bit) {
std::vector<uint8_t> data = {0xEE, 0x00, 0x10};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x1000, {0x40}); // [0x1000] = 0x40
cpu.SetAccumulatorSize(false);
cpu.ExecuteInstruction(0xEE); // INC Absolute
EXPECT_EQ(mock_memory[0x1000], 0x41);
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, INC_DirectPage_ZeroResult_8bit) {
cpu.D = 0x0200; // Setting Direct Page register to 0x0200
std::vector<uint8_t> data = {0xE6, 0x20};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0220, {0xFF}); // [0x0220] = 0xFF
cpu.SetAccumulatorSize(true);
cpu.ExecuteInstruction(0xE6); // INC Direct Page
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_TRUE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, INC_Absolute_ZeroResult_16bit) {
std::vector<uint8_t> data = {0xEE, 0x00, 0x10};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x1000, {0xFF}); // [0x1000] = 0xFF
cpu.SetAccumulatorSize(false);
cpu.ExecuteInstruction(0xEE); // INC Absolute
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, INC_DirectPage_8bit_Overflow) {
std::vector<uint8_t> data = {0xE6, 0x80};
mock_memory.SetMemoryContents(data);
cpu.SetAccumulatorSize(true);
cpu.ExecuteInstruction(0xE6); // INC Direct Page
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, INC_DirectPageIndexedX_8bit) {
cpu.X = 0x01;
cpu.D = 0x0200; // Setting Direct Page register to 0x0200
std::vector<uint8_t> data = {0xF6, 0x20};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0221, {0x40}); // [0x0221] = 0x40
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x20));
EXPECT_CALL(mock_memory, ReadByte(0x0221)).WillOnce(Return(0x40));
cpu.ExecuteInstruction(0xF6); // INC Direct Page Indexed, X
EXPECT_EQ(mock_memory[0x0221], 0x41);
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, INC_AbsoluteIndexedX_16bit) {
cpu.X = 0x01;
std::vector<uint8_t> data = {0xFE, 0x00, 0x10};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x1001, {0x40}); // [0x1001] = 0x40
cpu.SetAccumulatorSize(false);
cpu.ExecuteInstruction(0xFE); // INC Absolute Indexed, X
EXPECT_EQ(mock_memory[0x1001], 0x41);
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, INX) {
cpu.SetIndexSize(true); // Set X register to 8-bit mode
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.SetIndexSize(true); // Set Y register to 8-bit mode
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());
}
// ============================================================================
// JMP - Jump to new location
TEST_F(CpuTest, JMP_Absolute) {
std::vector<uint8_t> data = {0x4C, 0x05, 0x20}; // JMP $2005
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x2005));
cpu.ExecuteInstruction(0x4C); // JMP Absolute
cpu.ExecuteInstruction(0xEA); // NOP
EXPECT_EQ(cpu.PC, 0x2006);
}
TEST_F(CpuTest, JMP_Indirect) {
std::vector<uint8_t> data = {0x6C, 0x03, 0x20, 0x05, 0x30}; // JMP ($2003)
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x2003));
EXPECT_CALL(mock_memory, ReadWord(0x2003)).WillOnce(Return(0x3005));
cpu.ExecuteInstruction(0x6C); // JMP Indirect
EXPECT_EQ(cpu.PC, 0x3005);
}
// ============================================================================
// JML - Jump Long
TEST_F(CpuTest, JML_AbsoluteLong) {
cpu.E = 0;
std::vector<uint8_t> data = {0x5C, 0x05, 0x00, 0x03}; // JML $030005
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x030005, {0x00, 0x20, 0x00});
EXPECT_CALL(mock_memory, ReadWordLong(0x0001)).WillOnce(Return(0x030005));
cpu.ExecuteInstruction(0x5C); // JML Absolute Long
EXPECT_EQ(cpu.PC, 0x0005);
EXPECT_EQ(cpu.PB, 0x03); // The PBR should be updated to 0x03
}
TEST_F(CpuTest, JMP_AbsoluteIndexedIndirectX) {
cpu.X = 0x02;
std::vector<uint8_t> data = {0x7C, 0x05, 0x20, 0x00}; // JMP ($2005, X)
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x2007, {0x30, 0x05}); // [0x2007] = 0x0530
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x2005));
EXPECT_CALL(mock_memory, ReadWord(0x2007)).WillOnce(Return(0x3005));
cpu.ExecuteInstruction(0x7C); // JMP Absolute Indexed Indirect
EXPECT_EQ(cpu.PC, 0x3005);
}
TEST_F(CpuTest, JMP_AbsoluteIndirectLong) {
std::vector<uint8_t> data = {0xDC, 0x05, 0x20, 0x00}; // JMP [$2005]
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x2005, {0x01, 0x30, 0x05}); // [0x2005] = 0x0530
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x2005));
EXPECT_CALL(mock_memory, ReadWordLong(0x2005)).WillOnce(Return(0x013005));
cpu.ExecuteInstruction(0xDC); // JMP Absolute Indirect Long
EXPECT_EQ(cpu.PC, 0x3005);
EXPECT_EQ(cpu.PB, 0x01);
}
// ============================================================================
// JSR - Jump to Subroutine
TEST_F(CpuTest, JSR_Absolute) {
std::vector<uint8_t> data = {0x20, 0x05, 0x20}; // JSR $2005
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x2005));
EXPECT_CALL(mock_memory, PushWord(0x0000)).Times(1);
cpu.ExecuteInstruction(0x20); // JSR Absolute
EXPECT_EQ(cpu.PC, 0x2005);
// Continue executing some code
cpu.ExecuteInstruction(0x60); // RTS
EXPECT_EQ(cpu.PC, 0x0003);
}
// ============================================================================
// JSL - Jump to Subroutine Long
TEST_F(CpuTest, JSL_AbsoluteLong) {
std::vector<uint8_t> data = {0x22, 0x05, 0x20, 0x00}; // JSL $002005
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadWordLong(0x0001)).WillOnce(Return(0x002005));
EXPECT_CALL(mock_memory, PushLong(0x0000)).Times(1);
cpu.ExecuteInstruction(0x22); // JSL Absolute Long
EXPECT_EQ(cpu.PC, 0x002005);
}
TEST_F(CpuTest, JSL_AbsoluteIndexedIndirect) {
cpu.X = 0x02;
std::vector<uint8_t> data = {0xFC, 0x05, 0x20, 0x00}; // JSL $002005
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x2007, {0x00, 0x20, 0x00});
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x2005));
EXPECT_CALL(mock_memory, ReadWord(0x2007)).WillOnce(Return(0x002000));
cpu.ExecuteInstruction(0xFC); // JSL Absolute Long
EXPECT_EQ(cpu.PC, 0x2000);
}
// ============================================================================
// LDA - Load Accumulator
TEST_F(CpuTest, LDA_DirectPageIndexedIndirectX) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.X = 0x02; // Set X register to 0x02
cpu.D = 0x0200; // Set Direct Page register to 0x0200
std::vector<uint8_t> data = {0xA1, 0x3C};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x00023E, {0x00, 0x10});
EXPECT_CALL(mock_memory, ReadByte(0x000001)).WillOnce(Return(0x3C));
EXPECT_CALL(mock_memory, ReadWord(0x00023E)).WillOnce(Return(0x1000));
EXPECT_CALL(mock_memory, ReadByte(0x1000)).WillOnce(Return(0x80));
cpu.ExecuteInstruction(0xA1); // LDA Direct Page Indexed Indirect, X
EXPECT_EQ(cpu.A, 0x80);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, LDA_StackRelative) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.status = 0xFF; // 8-bit mode
cpu.SetSP(0x01FF); // Set Stack Pointer to 0x01FF
std::vector<uint8_t> data = {0xA3, 0x02};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0201, {0x7F});
EXPECT_CALL(mock_memory, SP()).WillRepeatedly(Return(0x01FF));
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x02));
EXPECT_CALL(mock_memory, ReadByte(0x0201)).WillOnce(Return(0x7F));
cpu.ExecuteInstruction(0xA3); // LDA Stack Relative
EXPECT_EQ(cpu.A, 0x7F);
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, LDA_DirectPage) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.D = 0x0200;
std::vector<uint8_t> data = {0xA5, 0x3C, 0x00};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x00023C, {0x80});
EXPECT_CALL(mock_memory, ReadByte(0x000001)).WillOnce(Return(0x3C));
EXPECT_CALL(mock_memory, ReadByte(0x00023C)).WillOnce(Return(0x80));
cpu.ExecuteInstruction(0xA5); // LDA Direct Page
EXPECT_EQ(cpu.A, 0x80);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, LDA_DirectPageIndirectLong) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.D = 0x0200;
std::vector<uint8_t> data = {0xA7, 0x3C, 0x00};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x00023C, {0x00, 0x10, 0x00});
EXPECT_CALL(mock_memory, ReadByte(0x000001)).WillOnce(Return(0x3C));
EXPECT_CALL(mock_memory, ReadWordLong(0x00023C)).WillOnce(Return(0x1000));
EXPECT_CALL(mock_memory, ReadByte(0x1000)).WillOnce(Return(0x80));
cpu.ExecuteInstruction(0xA7); // LDA Direct Page Indirect Long
EXPECT_EQ(cpu.A, 0x80);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, LDA_Immediate_8bit) {
cpu.SetAccumulatorSize(true);
std::vector<uint8_t> data = {0xA9, 0xFF};
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xA9); // LDA Immediate
EXPECT_EQ(cpu.A, 0xFF);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, LDA_Immediate_16bit) {
std::vector<uint8_t> data = {0xA9, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
cpu.SetAccumulatorSize(false);
cpu.ExecuteInstruction(0xA9); // LDA Immediate
EXPECT_EQ(cpu.A, 0xFF7F);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, LDA_Absolute) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
std::vector<uint8_t> data = {0xAD, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x7FFF, {0x7F});
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x7FFF));
EXPECT_CALL(mock_memory, ReadByte(0x7FFF)).WillOnce(Return(0x7F));
cpu.SetAccumulatorSize(true);
cpu.ExecuteInstruction(0xAD); // LDA Absolute
EXPECT_EQ(cpu.A, 0x7F);
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, LDA_AbsoluteLong) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
std::vector<uint8_t> data = {0xAF, 0x7F, 0xFF, 0x00};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x7FFF, {0x7F});
EXPECT_CALL(mock_memory, ReadWordLong(0x0001)).WillOnce(Return(0x7FFF));
EXPECT_CALL(mock_memory, ReadByte(0x7FFF)).WillOnce(Return(0x7F));
cpu.SetAccumulatorSize(true);
cpu.ExecuteInstruction(0xAF); // LDA Absolute Long
EXPECT_EQ(cpu.A, 0x7F);
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, LDA_DirectPageIndirectIndexedY) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.Y = 0x02; // Set Y register to 0x02
cpu.D = 0x0200; // Set Direct Page register to 0x0200
std::vector<uint8_t> data = {0xB1, 0x3C};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x00023C, {0x00, 0x10});
mock_memory.InsertMemory(0x1002, {0x80});
EXPECT_CALL(mock_memory, ReadByte(0x000001)).WillOnce(Return(0x3C));
EXPECT_CALL(mock_memory, ReadWord(0x00023C)).WillOnce(Return(0x1000));
EXPECT_CALL(mock_memory, ReadByte(0x1002)).WillOnce(Return(0x80));
cpu.ExecuteInstruction(0xB1); // LDA Direct Page Indirect Indexed, Y
EXPECT_EQ(cpu.A, 0x80);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, LDA_DirectPageIndirect) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.D = 0x0200;
std::vector<uint8_t> data = {0xA1, 0x3C};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x00023C, {0x00, 0x10});
EXPECT_CALL(mock_memory, ReadByte(0x000001)).WillOnce(Return(0x3C));
EXPECT_CALL(mock_memory, ReadWord(0x00023C)).WillOnce(Return(0x1000));
EXPECT_CALL(mock_memory, ReadByte(0x1000)).WillOnce(Return(0x7F));
cpu.ExecuteInstruction(0xB2); // LDA Direct Page Indirect
EXPECT_EQ(cpu.A, 0x7F);
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, LDA_StackRelativeIndirectIndexedY) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.Y = 0x02; // Set Y register to 0x02
cpu.status = 0xFF; // 8-bit mode
std::vector<uint8_t> data = {0xB3, 0x02};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0201, {0x00, 0x10});
EXPECT_CALL(mock_memory, SP()).WillRepeatedly(Return(0x01FF));
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x02));
EXPECT_CALL(mock_memory, ReadWord(0x0201)).WillOnce(Return(0x1000));
EXPECT_CALL(mock_memory, ReadByte(0x1002)).WillOnce(Return(0x80));
cpu.ExecuteInstruction(0xB3); // LDA Stack Relative Indirect Indexed, Y
EXPECT_EQ(cpu.A, 0x80);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, LDA_DirectPageIndexedX) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.X = 0x02; // Set X register to 0x02
cpu.D = 0x0200; // Set Direct Page register to 0x0200
std::vector<uint8_t> data = {0xB5, 0x3C};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x00023E, {0x7F});
EXPECT_CALL(mock_memory, ReadByte(0x000001)).WillOnce(Return(0x3C));
EXPECT_CALL(mock_memory, ReadByte(0x00023E)).WillOnce(Return(0x80));
cpu.ExecuteInstruction(0xB5); // LDA Direct Page Indexed, X
EXPECT_EQ(cpu.A, 0x80);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, LDA_DirectPageIndirectLongIndexedY) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.Y = 0x02; // Set Y register to 0x02
cpu.D = 0x0200; // Set Direct Page register to 0x0200
std::vector<uint8_t> data = {0xB7, 0x3C};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x00023C, {0x00, 0x10, 0x00});
EXPECT_CALL(mock_memory, ReadByte(0x000001)).WillOnce(Return(0x3C));
EXPECT_CALL(mock_memory, ReadWordLong(0x00023C)).WillOnce(Return(0x1000));
EXPECT_CALL(mock_memory, ReadByte(0x1002)).WillOnce(Return(0x80));
cpu.ExecuteInstruction(0xB7); // LDA Direct Page Indirect Long Indexed, Y
EXPECT_EQ(cpu.A, 0x80);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, LDA_AbsoluteIndexedY) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.Y = 0x02; // Set Y register to 0x02
std::vector<uint8_t> data = {0xB9, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x8001, {0x80});
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x7FFF));
EXPECT_CALL(mock_memory, ReadByte(0x8001)).WillOnce(Return(0x80));
cpu.ExecuteInstruction(0xB9); // LDA Absolute Indexed, Y
EXPECT_EQ(cpu.A, 0x80);
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, LDA_AbsoluteIndexedX) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.X = 0x02; // Set X register to 0x02
std::vector<uint8_t> data = {0xBD, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x8001, {0x80});
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x7FFF));
EXPECT_CALL(mock_memory, ReadByte(0x8001)).WillOnce(Return(0x80));
cpu.ExecuteInstruction(0xBD); // LDA Absolute Indexed, X
EXPECT_EQ(cpu.A, 0x80);
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, LDA_AbsoluteLongIndexedX) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.X = 0x02; // Set X register to 0x02
std::vector<uint8_t> data = {0xBF, 0x7F, 0xFF, 0x00};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x8001, {0x80});
EXPECT_CALL(mock_memory, ReadWordLong(0x0001)).WillOnce(Return(0x7FFF));
EXPECT_CALL(mock_memory, ReadByte(0x8001)).WillOnce(Return(0x80));
cpu.ExecuteInstruction(0xBF); // LDA Absolute Long Indexed, X
EXPECT_EQ(cpu.A, 0x80);
EXPECT_FALSE(cpu.GetZeroFlag());
}
// ============================================================================
TEST_F(CpuTest, LDX_Immediate) {
cpu.SetIndexSize(true); // Set X register to 8-bit mode
std::vector<uint8_t> data = {0xA2, 0x42};
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xA2); // LDX Immediate
EXPECT_EQ(cpu.X, 0x42);
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, LDX_DirectPage) {
cpu.SetIndexSize(true); // Set X register to 8-bit mode
std::vector<uint8_t> data = {0xA6, 0x80};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0080, {0x42});
cpu.ExecuteInstruction(0xA6); // LDX Direct Page
EXPECT_EQ(cpu.X, 0x42);
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, LDX_Absolute) {
cpu.SetIndexSize(true); // Set X register to 8-bit mode
std::vector<uint8_t> data = {0xAE, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x7FFF, {0x42});
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x7FFF));
cpu.ExecuteInstruction(0xAE); // LDX Absolute
EXPECT_EQ(cpu.X, 0x42);
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, LDX_DirectPageIndexedY) {
cpu.SetIndexSize(true); // Set X register to 8-bit mode
cpu.Y = 0x02; // Set Y register to 0x02
std::vector<uint8_t> data = {0xB6, 0x80};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0082, {0x42});
cpu.ExecuteInstruction(0xB6); // LDX Direct Page Indexed, Y
EXPECT_EQ(cpu.X, 0x42);
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, LDX_AbsoluteIndexedY) {
cpu.SetIndexSize(true); // Set X register to 8-bit mode
cpu.Y = 0x02; // Set Y register to 0x02
std::vector<uint8_t> data = {0xBE, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x8001, {0x42});
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x7FFF));
cpu.ExecuteInstruction(0xBE); // LDX Absolute Indexed, Y
EXPECT_EQ(cpu.X, 0x42);
EXPECT_FALSE(cpu.GetZeroFlag());
}
// ============================================================================
TEST_F(CpuTest, LDY_Immediate) {
cpu.SetIndexSize(true); // Set Y register to 8-bit mode
std::vector<uint8_t> data = {0xA0, 0x42};
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xA0); // LDY Immediate
EXPECT_EQ(cpu.Y, 0x42);
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, LDY_DirectPage) {
cpu.SetIndexSize(true); // Set Y register to 8-bit mode
std::vector<uint8_t> data = {0xA4, 0x80};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0080, {0x42});
cpu.ExecuteInstruction(0xA4); // LDY Direct Page
EXPECT_EQ(cpu.Y, 0x42);
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, LDY_Absolute) {
cpu.SetIndexSize(true); // Set Y register to 8-bit mode
std::vector<uint8_t> data = {0xAC, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x7FFF, {0x42});
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x7FFF));
cpu.ExecuteInstruction(0xAC); // LDY Absolute
EXPECT_EQ(cpu.Y, 0x42);
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, LDY_DirectPageIndexedX) {
cpu.SetIndexSize(true); // Set Y register to 8-bit mode
cpu.X = 0x02; // Set X register to 0x02
std::vector<uint8_t> data = {0xB4, 0x80};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0082, {0x42});
cpu.ExecuteInstruction(0xB4); // LDY Direct Page Indexed, X
EXPECT_EQ(cpu.Y, 0x42);
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, LDY_AbsoluteIndexedX) {
cpu.SetIndexSize(true); // Set Y register to 8-bit mode
cpu.X = 0x02; // Set X register to 0x02
std::vector<uint8_t> data = {0xBC, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x8001, {0x42});
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x7FFF));
cpu.ExecuteInstruction(0xBC); // LDY Absolute Indexed, X
EXPECT_EQ(cpu.Y, 0x42);
EXPECT_FALSE(cpu.GetZeroFlag());
}
// ============================================================================
TEST_F(CpuTest, LSR_DirectPage) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
std::vector<uint8_t> data = {0x46, 0x80};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0080, {0x42});
cpu.ExecuteInstruction(0x46); // LSR Direct Page
EXPECT_EQ(mock_memory[0x0080], 0x21);
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, LSR_Accumulator) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.A = 0x42;
cpu.ExecuteInstruction(0x4A); // LSR Accumulator
EXPECT_EQ(cpu.A, 0x21);
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, LSR_Absolute) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
std::vector<uint8_t> data = {0x4E, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x7FFF, {0x42});
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x7FFF));
cpu.ExecuteInstruction(0x4E); // LSR Absolute
EXPECT_EQ(mock_memory[0x7FFF], 0x21);
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, LSR_DirectPageIndexedX) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.X = 0x02; // Set X register to 0x02
std::vector<uint8_t> data = {0x56, 0x80};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0082, {0x42});
cpu.ExecuteInstruction(0x56); // LSR Direct Page Indexed, X
EXPECT_EQ(mock_memory[0x0082], 0x21);
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, LSR_AbsoluteIndexedX) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.X = 0x02; // Set X register to 0x02
std::vector<uint8_t> data = {0x5E, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x8001, {0x42});
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x7FFF));
cpu.ExecuteInstruction(0x5E); // LSR Absolute Indexed, X
EXPECT_EQ(mock_memory[0x8001], 0x21);
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
// ============================================================================
// Stack Tests
TEST_F(CpuTest, ORA_DirectPageIndexedIndirectX) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.X = 0x02; // Set X register to 0x02
cpu.D = 0x0200; // Set Direct Page register to 0x0200
std::vector<uint8_t> data = {0x01, 0x3C};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x00023E, {0x00, 0x10});
EXPECT_CALL(mock_memory, ReadByte(0x000001)).WillOnce(Return(0x3C));
EXPECT_CALL(mock_memory, ReadWord(0x00023E)).WillOnce(Return(0x1000));
EXPECT_CALL(mock_memory, ReadByte(0x1000)).WillOnce(Return(0x80));
cpu.ExecuteInstruction(0x01); // ORA Direct Page Indexed Indirect, X
EXPECT_EQ(cpu.A, 0x80);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, ORA_StackRelative) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.status = 0xFF; // 8-bit mode
cpu.SetSP(0x01FF); // Set Stack Pointer to 0x01FF
std::vector<uint8_t> data = {0x03, 0x02};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0201, {0x7F});
EXPECT_CALL(mock_memory, SP()).WillRepeatedly(Return(0x01FF));
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x02));
EXPECT_CALL(mock_memory, ReadByte(0x0201)).WillOnce(Return(0x7F));
cpu.ExecuteInstruction(0x03); // ORA Stack Relative
EXPECT_EQ(cpu.A, 0x7F);
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, ORA_DirectPage) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.D = 0x0200;
std::vector<uint8_t> data = {0x05, 0x3C, 0x00};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x00023C, {0x80});
EXPECT_CALL(mock_memory, ReadByte(0x000001)).WillOnce(Return(0x3C));
EXPECT_CALL(mock_memory, ReadByte(0x00023C)).WillOnce(Return(0x80));
cpu.ExecuteInstruction(0x05); // ORA Direct Page
EXPECT_EQ(cpu.A, 0x80);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, ORA_DirectPageIndirectLong) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.D = 0x0200;
std::vector<uint8_t> data = {0x07, 0x3C, 0x00};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x00023C, {0x00, 0x10, 0x00});
EXPECT_CALL(mock_memory, ReadByte(0x000001)).WillOnce(Return(0x3C));
EXPECT_CALL(mock_memory, ReadWordLong(0x00023C)).WillOnce(Return(0x1000));
EXPECT_CALL(mock_memory, ReadByte(0x1000)).WillOnce(Return(0x80));
cpu.ExecuteInstruction(0x07); // ORA Direct Page Indirect Long
EXPECT_EQ(cpu.A, 0x80);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, ORA_Immediate) {
cpu.SetAccumulatorSize(true);
std::vector<uint8_t> data = {0x09, 0xFF};
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0x09); // ORA Immediate
EXPECT_EQ(cpu.A, 0xFF);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, ORA_Absolute) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
std::vector<uint8_t> data = {0x0D, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x7FFF, {0x7F});
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x7FFF));
EXPECT_CALL(mock_memory, ReadByte(0x7FFF)).WillOnce(Return(0x7F));
cpu.SetAccumulatorSize(true);
cpu.ExecuteInstruction(0x0D); // ORA Absolute
EXPECT_EQ(cpu.A, 0x7F);
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, ORA_AbsoluteLong) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
std::vector<uint8_t> data = {0x0F, 0x7F, 0xFF, 0x00};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x7FFF, {0x7F});
EXPECT_CALL(mock_memory, ReadWordLong(0x0001)).WillOnce(Return(0x7FFF));
EXPECT_CALL(mock_memory, ReadByte(0x7FFF)).WillOnce(Return(0x7F));
cpu.SetAccumulatorSize(true);
cpu.ExecuteInstruction(0x0F); // ORA Absolute Long
EXPECT_EQ(cpu.A, 0x7F);
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, ORA_DirectPageIndirectIndexedY) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.Y = 0x02; // Set Y register to 0x02
cpu.D = 0x0200; // Set Direct Page register to 0x0200
std::vector<uint8_t> data = {0x11, 0x3C};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x00023C, {0x00, 0x10});
mock_memory.InsertMemory(0x1002, {0x80});
EXPECT_CALL(mock_memory, ReadByte(0x000001)).WillOnce(Return(0x3C));
EXPECT_CALL(mock_memory, ReadWord(0x00023C)).WillOnce(Return(0x1000));
EXPECT_CALL(mock_memory, ReadByte(0x1002)).WillOnce(Return(0x80));
cpu.ExecuteInstruction(0x11); // ORA Direct Page Indirect Indexed, Y
EXPECT_EQ(cpu.A, 0x80);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, ORA_DirectPageIndirect) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.D = 0x0200;
std::vector<uint8_t> data = {0x12, 0x3C};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x00023C, {0x00, 0x10});
EXPECT_CALL(mock_memory, ReadByte(0x000001)).WillOnce(Return(0x3C));
EXPECT_CALL(mock_memory, ReadWord(0x00023C)).WillOnce(Return(0x1000));
EXPECT_CALL(mock_memory, ReadByte(0x1000)).WillOnce(Return(0x7F));
cpu.ExecuteInstruction(0x12); // ORA Direct Page Indirect
EXPECT_EQ(cpu.A, 0x7F);
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, ORA_StackRelativeIndirectIndexedY) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.Y = 0x02; // Set Y register to 0x02
cpu.status = 0xFF; // 8-bit mode
std::vector<uint8_t> data = {0x13, 0x02};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0201, {0x00, 0x10});
EXPECT_CALL(mock_memory, SP()).WillRepeatedly(Return(0x01FF));
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x02));
EXPECT_CALL(mock_memory, ReadWord(0x0201)).WillOnce(Return(0x1000));
EXPECT_CALL(mock_memory, ReadByte(0x1002)).WillOnce(Return(0x80));
cpu.ExecuteInstruction(0x13); // ORA Stack Relative Indirect Indexed, Y
EXPECT_EQ(cpu.A, 0x80);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, ORA_DirectPageIndexedX) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.X = 0x02; // Set X register to 0x02
cpu.D = 0x0200; // Set Direct Page register to 0x0200
std::vector<uint8_t> data = {0x15, 0x3C};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x00023E, {0x80});
EXPECT_CALL(mock_memory, ReadByte(0x000001)).WillOnce(Return(0x3C));
EXPECT_CALL(mock_memory, ReadByte(0x00023E)).WillOnce(Return(0x80));
cpu.ExecuteInstruction(0x15); // ORA Direct Page Indexed, X
EXPECT_EQ(cpu.A, 0x80);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, ORA_DirectPageIndirectLongIndexedY) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.Y = 0x02; // Set Y register to 0x02
cpu.D = 0x0200; // Set Direct Page register to 0x0200
std::vector<uint8_t> data = {0x17, 0x3C};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x00023C, {0x00, 0x10, 0x00});
EXPECT_CALL(mock_memory, ReadByte(0x000001)).WillOnce(Return(0x3C));
EXPECT_CALL(mock_memory, ReadWordLong(0x00023C)).WillOnce(Return(0x1000));
EXPECT_CALL(mock_memory, ReadByte(0x1002)).WillOnce(Return(0x80));
cpu.ExecuteInstruction(0x17); // ORA Direct Page Indirect Long Indexed, Y
EXPECT_EQ(cpu.A, 0x80);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, ORA_AbsoluteIndexedY) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.Y = 0x02; // Set Y register to 0x02
std::vector<uint8_t> data = {0x19, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x8001, {0x7F});
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x7FFF));
EXPECT_CALL(mock_memory, ReadByte(0x8001)).WillOnce(Return(0x7F));
cpu.ExecuteInstruction(0x19); // ORA Absolute Indexed, Y
EXPECT_EQ(cpu.A, 0x7F);
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, ORA_AbsoluteIndexedX) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.X = 0x02; // Set X register to 0x02
std::vector<uint8_t> data = {0x1D, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x8001, {0x7F});
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x7FFF));
EXPECT_CALL(mock_memory, ReadByte(0x8001)).WillOnce(Return(0x7F));
cpu.ExecuteInstruction(0x1D); // ORA Absolute Indexed, X
EXPECT_EQ(cpu.A, 0x7F);
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, ORA_AbsoluteLongIndexedX) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.X = 0x02; // Set X register to 0x02
std::vector<uint8_t> data = {0x1F, 0x7F, 0xFF, 0x00};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x8001, {0x7F});
EXPECT_CALL(mock_memory, ReadWordLong(0x0001)).WillOnce(Return(0x7FFF));
EXPECT_CALL(mock_memory, ReadByte(0x8001)).WillOnce(Return(0x7F));
cpu.ExecuteInstruction(0x1F); // ORA Absolute Long Indexed, X
EXPECT_EQ(cpu.A, 0x7F);
EXPECT_FALSE(cpu.GetZeroFlag());
}
// ============================================================================
TEST_F(CpuTest, PEA) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
std::vector<uint8_t> data = {0xF4, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x7FFF));
EXPECT_CALL(mock_memory, PushWord(0x7FFF));
cpu.ExecuteInstruction(0xF4); // PEA
}
TEST_F(CpuTest, PEI) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
std::vector<uint8_t> data = {0xD4, 0x3C, 0x00};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x00003C, {0x00, 0x10});
EXPECT_CALL(mock_memory, ReadWord(0x000001)).WillOnce(Return(0x3C));
EXPECT_CALL(mock_memory, ReadWord(0x00003C)).WillOnce(Return(0x1000));
EXPECT_CALL(mock_memory, PushWord(0x1000));
cpu.ExecuteInstruction(0xD4); // PEI
}
TEST_F(CpuTest, PER) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
std::vector<uint8_t> data = {0x62, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x7FFF));
EXPECT_CALL(mock_memory, PushWord(0x7FFF));
cpu.ExecuteInstruction(0x62); // PER
}
TEST_F(CpuTest, PHD) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.D = 0x7FFF;
std::vector<uint8_t> data = {0x0B};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, PushWord(0x7FFF));
cpu.ExecuteInstruction(0x0B); // PHD
}
TEST_F(CpuTest, PHK) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.PB = 0x7F;
std::vector<uint8_t> data = {0x4B};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, PushByte(0x7F));
cpu.ExecuteInstruction(0x4B); // PHK
}
TEST_F(CpuTest, PHP) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.status = 0x7F;
std::vector<uint8_t> data = {0x08};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, PushByte(0x7F));
cpu.ExecuteInstruction(0x08); // PHP
}
TEST_F(CpuTest, PHX) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.X = 0x7F;
std::vector<uint8_t> data = {0xDA};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, PushByte(0x7F));
cpu.ExecuteInstruction(0xDA); // PHX
}
TEST_F(CpuTest, PHY) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.Y = 0x7F;
std::vector<uint8_t> data = {0x5A};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, PushByte(0x7F));
cpu.ExecuteInstruction(0x5A); // PHY
}
TEST_F(CpuTest, PHB) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.DB = 0x7F;
std::vector<uint8_t> data = {0x8B};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, PushByte(0x7F));
cpu.ExecuteInstruction(0x8B); // PHB
}
TEST_F(CpuTest, PHA) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.A = 0x7F;
std::vector<uint8_t> data = {0x48};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, PushByte(0x7F));
cpu.ExecuteInstruction(0x48); // PHA
}
TEST_F(CpuTest, PHA_16Bit) {
cpu.SetAccumulatorSize(false); // Set A register to 16-bit mode
cpu.A = 0x7FFF;
std::vector<uint8_t> data = {0x48};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, PushWord(0x7FFF));
cpu.ExecuteInstruction(0x48); // PHA
}
TEST_F(CpuTest, PLA) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.A = 0x00;
std::vector<uint8_t> data = {0x68};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0001, {0x7F});
EXPECT_CALL(mock_memory, PopByte()).WillOnce(Return(0x7F));
cpu.ExecuteInstruction(0x68); // PLA
EXPECT_EQ(cpu.A, 0x7F);
}
TEST_F(CpuTest, PLA_16Bit) {
cpu.SetAccumulatorSize(false); // Set A register to 16-bit mode
cpu.A = 0x0000;
std::vector<uint8_t> data = {0x68};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0001, {0x7F, 0xFF});
EXPECT_CALL(mock_memory, PopWord()).WillOnce(Return(0x7FFF));
cpu.ExecuteInstruction(0x68); // PLA
EXPECT_EQ(cpu.A, 0x7FFF);
}
TEST_F(CpuTest, PLB) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.DB = 0x00;
std::vector<uint8_t> data = {0xAB};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0001, {0x7F});
EXPECT_CALL(mock_memory, PopByte()).WillOnce(Return(0x7F));
cpu.ExecuteInstruction(0xAB); // PLB
EXPECT_EQ(cpu.DB, 0x7F);
}
TEST_F(CpuTest, PLD) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.D = 0x0000;
std::vector<uint8_t> data = {0x2B};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0001, {0x7F, 0xFF});
EXPECT_CALL(mock_memory, PopWord()).WillOnce(Return(0x7FFF));
cpu.ExecuteInstruction(0x2B); // PLD
EXPECT_EQ(cpu.D, 0x7FFF);
}
TEST_F(CpuTest, PLP) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.status = 0x00;
std::vector<uint8_t> data = {0x28};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0001, {0x7F});
EXPECT_CALL(mock_memory, PopByte()).WillOnce(Return(0x7F));
cpu.ExecuteInstruction(0x28); // PLP
EXPECT_EQ(cpu.status, 0x7F);
}
TEST_F(CpuTest, PLX) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.X = 0x00;
std::vector<uint8_t> data = {0xFA};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0001, {0x7F});
EXPECT_CALL(mock_memory, PopByte()).WillOnce(Return(0x7F));
cpu.ExecuteInstruction(0xFA); // PLX
EXPECT_EQ(cpu.X, 0x7F);
}
TEST_F(CpuTest, PLX_16Bit) {
cpu.SetIndexSize(false); // Set A register to 16-bit mode
cpu.X = 0x0000;
std::vector<uint8_t> data = {0xFA};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x01FF, {0x7F, 0xFF});
EXPECT_CALL(mock_memory, PopWord()).WillOnce(Return(0x7FFF));
cpu.ExecuteInstruction(0xFA); // PLX
EXPECT_EQ(cpu.X, 0x7FFF);
}
TEST_F(CpuTest, PLY) {
cpu.SetIndexSize(true); // Set A register to 8-bit mode
cpu.Y = 0x00;
std::vector<uint8_t> data = {0x7A};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0001, {0x7F});
EXPECT_CALL(mock_memory, PopByte()).WillOnce(Return(0x7F));
cpu.ExecuteInstruction(0x7A); // PLY
EXPECT_EQ(cpu.Y, 0x7F);
}
TEST_F(CpuTest, PLY_16Bit) {
cpu.SetIndexSize(false); // Set A register to 16-bit mode
cpu.Y = 0x0000;
std::vector<uint8_t> data = {0x7A};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0001, {0x7F, 0xFF});
EXPECT_CALL(mock_memory, PopWord()).WillOnce(Return(0x7FFF));
cpu.ExecuteInstruction(0x7A); // PLY
EXPECT_EQ(cpu.Y, 0x7FFF);
}
// ============================================================================
// REP - Reset Processor Status Bits
TEST_F(CpuTest, REP) {
cpu.status = 0xFF;
std::vector<uint8_t> data = {0xC2, 0x30};
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xC2); // REP
EXPECT_EQ(cpu.status, 0xCF); // 11001111
}
TEST_F(CpuTest, REP_16Bit) {
cpu.status = 0xFF;
std::vector<uint8_t> data = {0xC2, 0x30};
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xC2); // REP
EXPECT_EQ(cpu.status, 0xCF); // 00111111
}
TEST_F(CpuTest, PHA_PLA_Ok) {
cpu.A = 0x42;
EXPECT_CALL(mock_memory, PushByte(0x42)).WillOnce(Return());
cpu.PHA();
cpu.A = 0x00;
EXPECT_CALL(mock_memory, PopByte()).WillOnce(Return(0x42));
cpu.PLA();
EXPECT_EQ(cpu.A, 0x42);
}
TEST_F(CpuTest, PHP_PLP_Ok) {
// Set some status flags
cpu.status = 0;
cpu.SetNegativeFlag(true);
cpu.SetZeroFlag(false);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
EXPECT_CALL(mock_memory, PushByte(0x80)).WillOnce(Return());
cpu.PHP();
// Clear status flags
cpu.SetNegativeFlag(false);
cpu.SetZeroFlag(true);
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_TRUE(cpu.GetZeroFlag());
EXPECT_CALL(mock_memory, PopByte()).WillOnce(Return(0x80));
cpu.PLP();
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
// ============================================================================
// PHA, PHP, PHX, PHY, PHB, PHD, PHK
// ============================================================================
TEST_F(CpuTest, PHA_PushAccumulator) {
cpu.A = 0x12;
EXPECT_CALL(mock_memory, PushByte(0x12));
cpu.ExecuteInstruction(0x48); // PHA
}
TEST_F(CpuTest, PHP_PushProcessorStatusRegister) {
cpu.status = 0x34;
EXPECT_CALL(mock_memory, PushByte(0x34));
cpu.ExecuteInstruction(0x08); // PHP
}
TEST_F(CpuTest, PHX_PushXRegister) {
cpu.X = 0x56;
EXPECT_CALL(mock_memory, PushByte(0x56));
cpu.ExecuteInstruction(0xDA); // PHX
}
TEST_F(CpuTest, PHY_PushYRegister) {
cpu.Y = 0x78;
EXPECT_CALL(mock_memory, PushByte(0x78));
cpu.ExecuteInstruction(0x5A); // PHY
}
TEST_F(CpuTest, PHB_PushDataBankRegister) {
cpu.DB = 0x9A;
EXPECT_CALL(mock_memory, PushByte(0x9A));
cpu.ExecuteInstruction(0x8B); // PHB
}
TEST_F(CpuTest, PHD_PushDirectPageRegister) {
cpu.D = 0xBC;
EXPECT_CALL(mock_memory, PushWord(0xBC));
cpu.ExecuteInstruction(0x0B); // PHD
}
TEST_F(CpuTest, PHK_PushProgramBankRegister) {
cpu.PB = 0xDE;
EXPECT_CALL(mock_memory, PushByte(0xDE));
cpu.ExecuteInstruction(0x4B); // PHK
}
// ============================================================================
// PLA, PLP, PLX, PLY, PLB, PLD
// ============================================================================
TEST_F(CpuTest, PLA_PullAccumulator) {
EXPECT_CALL(mock_memory, PopByte()).WillOnce(Return(0x12));
cpu.ExecuteInstruction(0x68); // PLA
EXPECT_EQ(cpu.A, 0x12);
}
TEST_F(CpuTest, PLP_PullProcessorStatusRegister) {
EXPECT_CALL(mock_memory, PopByte()).WillOnce(Return(0x34));
cpu.ExecuteInstruction(0x28); // PLP
EXPECT_EQ(cpu.status, 0x34);
}
TEST_F(CpuTest, PLX_PullXRegister) {
EXPECT_CALL(mock_memory, PopByte()).WillOnce(Return(0x56));
cpu.ExecuteInstruction(0xFA); // PLX
EXPECT_EQ(cpu.X, 0x56);
}
TEST_F(CpuTest, PLY_PullYRegister) {
EXPECT_CALL(mock_memory, PopByte()).WillOnce(Return(0x78));
cpu.ExecuteInstruction(0x7A); // PLY
EXPECT_EQ(cpu.Y, 0x78);
}
TEST_F(CpuTest, PLB_PullDataBankRegister) {
EXPECT_CALL(mock_memory, PopByte()).WillOnce(Return(0x9A));
cpu.ExecuteInstruction(0xAB); // PLB
EXPECT_EQ(cpu.DB, 0x9A);
}
TEST_F(CpuTest, PLD_PullDirectPageRegister) {
EXPECT_CALL(mock_memory, PopWord()).WillOnce(Return(0xBC));
cpu.ExecuteInstruction(0x2B); // PLD
EXPECT_EQ(cpu.D, 0xBC);
}
// ============================================================================
// SEP - Set Processor Status Bits
TEST_F(CpuTest, SEP) {
cpu.status = 0x00; // All flags cleared
std::vector<uint8_t> data = {0xE2, 0x30,
0x00}; // SEP #0x30 (set N & Z flags)
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xE2); // SEP
EXPECT_EQ(cpu.status, 0x30); // 00110000
}
// ============================================================================
TEST_F(CpuTest, ROL_DirectPage) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
std::vector<uint8_t> data = {0x26, 0x80};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0080, {0x42});
cpu.ExecuteInstruction(0x26); // ROL Direct Page
EXPECT_EQ(mock_memory[0x0080], 0x84);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, ROL_Accumulator) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.A = 0x42;
cpu.ExecuteInstruction(0x2A); // ROL Accumulator
EXPECT_EQ(cpu.A, 0x84);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, ROL_Absolute) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
std::vector<uint8_t> data = {0x2E, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x7FFF, {0x42});
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x7FFF));
cpu.ExecuteInstruction(0x2E); // ROL Absolute
EXPECT_EQ(mock_memory[0x7FFF], 0x84);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, ROL_DirectPageIndexedX) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.X = 0x02; // Set X register to 0x02
std::vector<uint8_t> data = {0x36, 0x80};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0082, {0x42});
cpu.ExecuteInstruction(0x36); // ROL Direct Page Indexed, X
EXPECT_EQ(mock_memory[0x0082], 0x84);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, ROL_AbsoluteIndexedX) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.X = 0x02; // Set X register to 0x02
std::vector<uint8_t> data = {0x3E, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x8001, {0x42});
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x7FFF));
cpu.ExecuteInstruction(0x3E); // ROL Absolute Indexed, X
EXPECT_EQ(mock_memory[0x8001], 0x84);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
// ============================================================================
TEST_F(CpuTest, ROR_DirectPage) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
std::vector<uint8_t> data = {0x66, 0x80};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0080, {0x42});
cpu.ExecuteInstruction(0x66); // ROR Direct Page
EXPECT_EQ(mock_memory[0x0080], 0x21);
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, ROR_Accumulator) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.A = 0x42;
cpu.ExecuteInstruction(0x6A); // ROR Accumulator
EXPECT_EQ(cpu.A, 0x21);
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, ROR_Absolute) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
std::vector<uint8_t> data = {0x6E, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x7FFF, {0x42});
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x7FFF));
cpu.ExecuteInstruction(0x6E); // ROR Absolute
EXPECT_EQ(mock_memory[0x7FFF], 0x21);
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, ROR_DirectPageIndexedX) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.X = 0x02; // Set X register to 0x02
std::vector<uint8_t> data = {0x76, 0x80};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0082, {0x42});
cpu.ExecuteInstruction(0x76); // ROR Direct Page Indexed, X
EXPECT_EQ(mock_memory[0x0082], 0x21);
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, ROR_AbsoluteIndexedX) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.X = 0x02; // Set X register to 0x02
std::vector<uint8_t> data = {0x7E, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x8001, {0x42});
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x7FFF));
cpu.ExecuteInstruction(0x7E); // ROR Absolute Indexed, X
EXPECT_EQ(mock_memory[0x8001], 0x21);
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
// ============================================================================
TEST_F(CpuTest, RTI) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.status = 0x00;
std::vector<uint8_t> data = {0x40};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0001, {0x7F});
EXPECT_CALL(mock_memory, PopByte()).WillOnce(Return(0x7F));
cpu.ExecuteInstruction(0x40); // RTI
EXPECT_EQ(cpu.status, 0x7F);
}
// ============================================================================
TEST_F(CpuTest, RTL) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.PC = 0x0000;
std::vector<uint8_t> data = {0x6B};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0001, {0x7F, 0xFF});
EXPECT_CALL(mock_memory, PopWord()).WillOnce(Return(0x7FFF));
cpu.ExecuteInstruction(0x6B); // RTL
EXPECT_EQ(cpu.PC, 0x7FFF);
}
// ============================================================================
TEST_F(CpuTest, RTS) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.PC = 0x0000;
std::vector<uint8_t> data = {0x60};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0001, {0x7F, 0xFF});
EXPECT_CALL(mock_memory, PopWord()).WillOnce(Return(0x7FFF));
cpu.ExecuteInstruction(0x60); // RTS
EXPECT_EQ(cpu.PC, 0x7FFF + 3);
}
// ============================================================================
TEST_F(CpuTest, SBC_DirectPageIndexedIndirectX) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.X = 0x02; // Set X register to 0x02
cpu.D = 0x0200; // Set Direct Page register to 0x0200
cpu.A = 0x10; // Set A register to 0x80
cpu.status = 0xFF; // 8-bit mode
std::vector<uint8_t> data = {0xE1, 0x3C};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x00023E, {0x80});
mock_memory.InsertMemory(0x0080, {0x80});
EXPECT_CALL(mock_memory, ReadByte(0x000001)).WillOnce(Return(0x3C));
EXPECT_CALL(mock_memory, ReadWord(0x00023E)).WillOnce(Return(0x80));
EXPECT_CALL(mock_memory, ReadByte(0x0080)).WillOnce(Return(0x80));
cpu.ExecuteInstruction(0xE1); // SBC Direct Page Indexed Indirect, X
EXPECT_EQ(cpu.A, 0x90);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, SBC_StackRelative) {
std::vector<uint8_t> data = {0xE3, 0x3C};
mock_memory.SetMemoryContents(data);
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.status = 0xFF; // 8-bit mode
cpu.SetSP(0x01FF); // Set Stack Pointer to 0x01FF
mock_memory.InsertMemory(0x00003E, {0x02});
mock_memory.InsertMemory(0x2002, {0x80});
EXPECT_CALL(mock_memory, SP()).WillRepeatedly(Return(0x01FF));
// EXPECT_CALL(mock_memory, ReadByte(_)).WillOnce(Return(0x3C));
cpu.ExecuteInstruction(0xE3); // SBC Stack Relative
EXPECT_EQ(cpu.A, 0x00);
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_TRUE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, SBC_DirectPage) {
std::vector<uint8_t> data = {0xE5, 0x80};
mock_memory.SetMemoryContents(data);
cpu.D = 0x0100; // Set Direct Page register to 0x0100
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.status = 0xFF; // 8-bit mode
cpu.A = 0x42; // Set A register to 0x42
mock_memory.InsertMemory(0x0180, {0x01});
cpu.ExecuteInstruction(0xE5); // SBC Direct Page
EXPECT_EQ(cpu.A, 0x41);
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, SBC_DirectPageIndirectLong) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.status = 0xFF; // 8-bit mode
cpu.A = 0x80; // Set A register to 0x80
std::vector<uint8_t> data = {0xE7, 0x3C};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x00003C, {0x00, 0x10, 0x00});
mock_memory.InsertMemory(0x1000, {0x8F});
EXPECT_CALL(mock_memory, ReadByte(0x000001)).WillOnce(Return(0x3C));
EXPECT_CALL(mock_memory, ReadWordLong(0x00003C)).WillOnce(Return(0x1000));
EXPECT_CALL(mock_memory, ReadByte(0x1000)).WillOnce(Return(0x8F));
cpu.ExecuteInstruction(0xE7); // SBC Direct Page Indirect Long
EXPECT_EQ(cpu.A, 0xF1);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, SBC_Immediate) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.status = 0xFF; // 8-bit mode
cpu.A = 0x80; // Set A register to 0x80
std::vector<uint8_t> data = {0xE9, 0x80};
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xE9); // SBC Immediate
EXPECT_EQ(cpu.A, 0x00);
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_TRUE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, SBC_Absolute) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.status = 0xFF; // 8-bit mode
cpu.A = 0xFF; // Set A register to 0x80
std::vector<uint8_t> data = {0xED, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x7FFF, {0x80});
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x7FFF));
cpu.ExecuteInstruction(0xED); // SBC Absolute
EXPECT_EQ(cpu.A, 0x7F);
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, SBC_AbsoluteLong) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.status = 0xFF; // 8-bit mode
cpu.A = 0xFF; // Set A register to 0x80
std::vector<uint8_t> data = {0xEF, 0x7F, 0xFF, 0xFF, 0xFF};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x7FFFFF, {0x80});
EXPECT_CALL(mock_memory, ReadWordLong(0x0001)).WillOnce(Return(0x7FFFFF));
cpu.ExecuteInstruction(0xEF); // SBC Absolute Long
EXPECT_EQ(cpu.A, 0x7F);
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, SBC_DirectPageIndirectIndexedY) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.Y = 0x02; // Set Y register to 0x02
cpu.A = 0xFF; // Set A register to 0x80
cpu.status = 0xFF; // 8-bit mode
std::vector<uint8_t> data = {0xF1, 0x3C};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x00003E, {0x00, 0x10});
EXPECT_CALL(mock_memory, ReadByte(0x000001)).WillOnce(Return(0x3C));
EXPECT_CALL(mock_memory, ReadWord(0x00003C)).WillOnce(Return(0x1000));
EXPECT_CALL(mock_memory, ReadByte(0x1002)).WillOnce(Return(0x80));
cpu.ExecuteInstruction(0xF1); // SBC Direct Page Indirect Indexed, Y
EXPECT_EQ(cpu.A, 0x7F);
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, SBC_DirectPageIndirect) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.status = 0xFF; // 8-bit mode
cpu.D = 0x0200; // Set Direct Page register to 0x0200
cpu.A = 0x10; // Set A register to 0x80
std::vector<uint8_t> data = {0xF2, 0x3C};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x00023C, {0x00, 0x10});
mock_memory.InsertMemory(0x1000, {0x80});
EXPECT_CALL(mock_memory, ReadByte(0x000001)).WillOnce(Return(0x3C));
EXPECT_CALL(mock_memory, ReadWord(0x00023C)).WillOnce(Return(0x1000));
EXPECT_CALL(mock_memory, ReadByte(0x1000)).WillOnce(Return(0x80));
cpu.ExecuteInstruction(0xF2); // SBC Direct Page Indirect
EXPECT_EQ(cpu.A, 0x90);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, SBC_StackRelativeIndirectIndexedY) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.Y = 0x02; // Set Y register to 0x02
cpu.A = 0xFF; // Set A register to 0x80
cpu.status = 0xFF; // 8-bit mode
cpu.SetSP(0x01FF); // Set Stack Pointer to 0x01FF
std::vector<uint8_t> data = {0xF3, 0x02};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0201, {0x00, 0x30});
mock_memory.InsertMemory(0x3002, {0x80});
EXPECT_CALL(mock_memory, SP()).WillRepeatedly(Return(0x01FF));
EXPECT_CALL(mock_memory, ReadByte(0x000001)).WillOnce(Return(0x02));
EXPECT_CALL(mock_memory, ReadWord(0x0201)).WillOnce(Return(0x3000));
EXPECT_CALL(mock_memory, ReadByte(0x3002)).WillOnce(Return(0x80));
cpu.ExecuteInstruction(0xF3); // SBC Stack Relative Indirect Indexed, Y
EXPECT_EQ(cpu.A, 0x7F);
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, SBC_DirectPageIndexedX) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.X = 0x02; // Set X register to 0x02
cpu.A = 0x01;
std::vector<uint8_t> data = {0xF5, 0x80};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0082, {0x01});
cpu.ExecuteInstruction(0xF5); // SBC Direct Page Indexed, X
EXPECT_EQ(cpu.A, 0xFF);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, SBC_DirectPageIndirectLongIndexedY) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.Y = 0x02; // Set Y register to 0x02
cpu.status = 0xFF; // 8-bit mode
cpu.A = 0xFF;
std::vector<uint8_t> data = {0xF7, 0x3C};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x00003C, {0x00, 0x10, 0x00});
EXPECT_CALL(mock_memory, ReadByte(0x000001)).WillOnce(Return(0x3C));
EXPECT_CALL(mock_memory, ReadWordLong(0x00003C)).WillOnce(Return(0x1000));
EXPECT_CALL(mock_memory, ReadByte(0x1002)).WillOnce(Return(0x80));
cpu.ExecuteInstruction(0xF7); // SBC Direct Page Indirect Long Indexed, Y
EXPECT_EQ(cpu.A, 0x7F);
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, SBC_AbsoluteIndexedY) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.Y = 0x02; // Set Y register to 0x02
cpu.status = 0xFF; // 8-bit mode
cpu.A = 0xFF;
std::vector<uint8_t> data = {0xF9, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x8001, {0x80});
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x7FFF));
cpu.ExecuteInstruction(0xF9); // SBC Absolute Indexed, Y
EXPECT_EQ(cpu.A, 0x7F);
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, SBC_AbsoluteIndexedX) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.X = 0x02; // Set X register to 0x02
cpu.status = 0xFF; // 8-bit mode
cpu.A = 0xFF;
std::vector<uint8_t> data = {0xFD, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x8001, {0x80});
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x7FFF));
cpu.ExecuteInstruction(0xFD); // SBC Absolute Indexed, X
EXPECT_EQ(cpu.A, 0x7F);
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CpuTest, SBC_AbsoluteLongIndexedX) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.X = 0x02; // Set X register to 0x02
cpu.A = 0xFF;
cpu.status = 0xFF; // 8-bit mode
std::vector<uint8_t> data = {0xFF, 0x7F, 0xFF, 0xFF, 0xFF};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x800001, {0x80});
EXPECT_CALL(mock_memory, ReadWordLong(0x0001)).WillOnce(Return(0x7FFFFF));
cpu.ExecuteInstruction(0xFF); // SBC Absolute Long Indexed, X
EXPECT_EQ(cpu.A, 0x7F);
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
// ============================================================================
TEST_F(CpuTest, SEC) {
cpu.ExecuteInstruction(0x38); // SEC
EXPECT_TRUE(cpu.GetCarryFlag());
}
// ============================================================================
TEST_F(CpuTest, SED) {
cpu.ExecuteInstruction(0xF8); // SED
EXPECT_TRUE(cpu.GetDecimalFlag());
}
// ============================================================================
// SEI - Set Interrupt Disable Status Flag
TEST_F(CpuTest, SEI) {
cpu.ExecuteInstruction(0x78); // SEI
// EXPECT_TRUE(cpu.GetInterruptDisableFlag());
}
// ============================================================================
TEST_F(CpuTest, SEP_8Bit) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.status = 0x00;
std::vector<uint8_t> data = {0xE2, 0x30};
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xE2); // SEP
EXPECT_EQ(cpu.status, 0x30); // 00110000
}
TEST_F(CpuTest, SEP_16Bit) {
cpu.SetAccumulatorSize(false); // Set A register to 16-bit mode
cpu.status = 0x00;
std::vector<uint8_t> data = {0xE2, 0x30};
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xE2); // SEP
EXPECT_EQ(cpu.status, 0x30); // 00110000
}
// ============================================================================
TEST_F(CpuTest, STA_DirectPageIndexedIndirectX) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.A = 0x42;
cpu.X = 0x02; // Set X register to 0x02
std::vector<uint8_t> data = {0x81, 0x3C};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x00003E, {0x00, 0x10});
EXPECT_CALL(mock_memory, ReadByte(0x000001)).WillOnce(Return(0x3C));
EXPECT_CALL(mock_memory, ReadWord(0x00003E)).WillOnce(Return(0x1000));
EXPECT_CALL(mock_memory, WriteByte(0x1000, 0x42));
cpu.ExecuteInstruction(0x81); // STA Direct Page Indexed Indirect, X
EXPECT_EQ(cpu.A, 0x42);
}
TEST_F(CpuTest, STA_StackRelative) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.A = 0x42;
cpu.SetSP(0x01FF); // Set Stack Pointer to 0x01FF
std::vector<uint8_t> data = {0x83, 0x3C};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadByte(0x000001)).WillOnce(Return(0x3C));
EXPECT_CALL(mock_memory, WriteByte(0x023B, 0x42));
cpu.ExecuteInstruction(0x83); // STA Stack Relative
}
TEST_F(CpuTest, STA_DirectPage) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.A = 0x42;
std::vector<uint8_t> data = {0x85, 0x80};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, WriteByte(0x0080, 0x42));
cpu.ExecuteInstruction(0x85); // STA Direct Page
}
TEST_F(CpuTest, STA_DirectPageIndirectLong) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.A = 0x42;
std::vector<uint8_t> data = {0x87, 0x3C};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x00003C, {0x00, 0x10, 0x00});
EXPECT_CALL(mock_memory, ReadByte(0x000001)).WillOnce(Return(0x3C));
EXPECT_CALL(mock_memory, ReadWordLong(0x00003C)).WillOnce(Return(0x1000));
EXPECT_CALL(mock_memory, WriteByte(0x1000, 0x42));
cpu.ExecuteInstruction(0x87); // STA Direct Page Indirect Long
}
TEST_F(CpuTest, STA_Absolute) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.A = 0x42;
std::vector<uint8_t> data = {0x8D, 0xFF, 0x7F};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, WriteByte(0x7FFF, 0x42));
cpu.ExecuteInstruction(0x8D); // STA Absolute
}
TEST_F(CpuTest, STA_AbsoluteLong) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.A = 0x42;
std::vector<uint8_t> data = {0x8F, 0xFF, 0x7F};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, WriteByte(0x7FFF, 0x42));
cpu.ExecuteInstruction(0x8F); // STA Absolute Long
}
TEST_F(CpuTest, STA_DirectPageIndirectIndexedY) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.A = 0x42;
cpu.Y = 0x02; // Set Y register to 0x02
std::vector<uint8_t> data = {0x91, 0x3C};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x00003E, {0x00, 0x10});
EXPECT_CALL(mock_memory, ReadByte(0x000001)).WillOnce(Return(0x3C));
EXPECT_CALL(mock_memory, ReadWord(0x00003C)).WillOnce(Return(0x1000));
EXPECT_CALL(mock_memory, WriteByte(0x1002, 0x42));
cpu.ExecuteInstruction(0x91); // STA Direct Page Indirect Indexed, Y
}
TEST_F(CpuTest, STA_DirectPageIndirect) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.A = 0x42;
cpu.Y = 0x02; // Set Y register to 0x02
std::vector<uint8_t> data = {0x92, 0x3C};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x00003C, {0x00, 0x10});
EXPECT_CALL(mock_memory, ReadByte(0x000001)).WillOnce(Return(0x3C));
EXPECT_CALL(mock_memory, ReadWord(0x00003C)).WillOnce(Return(0x1000));
EXPECT_CALL(mock_memory, WriteByte(0x1000, 0x42));
cpu.ExecuteInstruction(0x92); // STA Direct Page Indirect
}
TEST_F(CpuTest, STA_StackRelativeIndirectIndexedY) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.A = 0x42;
cpu.Y = 0x02; // Set Y register to 0x02
cpu.SetSP(0x01FF); // Set Stack Pointer to 0x01FF
std::vector<uint8_t> data = {0x93, 0x3C};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x00023B, {0x00, 0x10});
EXPECT_CALL(mock_memory, ReadByte(0x000001)).WillOnce(Return(0x3C));
EXPECT_CALL(mock_memory, ReadWord(0x00023B)).WillOnce(Return(0x1000));
EXPECT_CALL(mock_memory, WriteByte(0x1002, 0x42));
cpu.ExecuteInstruction(0x93); // STA Stack Relative Indirect Indexed, Y
}
TEST_F(CpuTest, STA_DirectPageIndexedX) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.A = 0x42;
cpu.X = 0x02; // Set X register to 0x02
std::vector<uint8_t> data = {0x95, 0x80};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, WriteByte(0x0082, 0x42));
cpu.ExecuteInstruction(0x95); // STA Direct Page Indexed, X
}
TEST_F(CpuTest, STA_DirectPageIndirectLongIndexedY) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.A = 0x42;
cpu.Y = 0x02; // Set Y register to 0x02
std::vector<uint8_t> data = {0x97, 0x3C};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x00003C, {0x00, 0x10, 0x00});
EXPECT_CALL(mock_memory, ReadByte(0x000001)).WillOnce(Return(0x3C));
EXPECT_CALL(mock_memory, ReadWordLong(0x00003C)).WillOnce(Return(0x1000));
EXPECT_CALL(mock_memory, WriteByte(0x1002, 0x42));
cpu.ExecuteInstruction(0x97); // STA Direct Page Indirect Long Indexed, Y
}
TEST_F(CpuTest, STA_AbsoluteIndexedY) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.A = 0x42;
cpu.Y = 0x02; // Set Y register to 0x02
std::vector<uint8_t> data = {0x99, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x7FFF));
EXPECT_CALL(mock_memory, WriteByte(0x8001, 0x42));
cpu.ExecuteInstruction(0x99); // STA Absolute Indexed, Y
}
TEST_F(CpuTest, STA_AbsoluteIndexedX) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.A = 0x42;
cpu.X = 0x02; // Set X register to 0x02
std::vector<uint8_t> data = {0x9D, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x7FFF));
EXPECT_CALL(mock_memory, WriteByte(0x8001, 0x42));
cpu.ExecuteInstruction(0x9D); // STA Absolute Indexed, X
}
TEST_F(CpuTest, STA_AbsoluteLongIndexedX) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.A = 0x42;
cpu.X = 0x02; // Set X register to 0x02
std::vector<uint8_t> data = {0x9F, 0xFF, 0xFF, 0x7F};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadWordLong(0x0001)).WillOnce(Return(0x7FFFFF));
EXPECT_CALL(mock_memory, WriteByte(0x800001, 0x42));
cpu.ExecuteInstruction(0x9F); // STA Absolute Long Indexed, X
}
// ============================================================================
TEST_F(CpuTest, STP) {
cpu.ExecuteInstruction(0xDB); // STP
// EXPECT_TRUE(cpu.GetStoppedFlag());
}
// ============================================================================
TEST_F(CpuTest, STX_DirectPage) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.X = 0x42;
std::vector<uint8_t> data = {0x86, 0x80};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, WriteByte(0x0080, 0x42));
cpu.ExecuteInstruction(0x86); // STX Direct Page
}
TEST_F(CpuTest, STX_Absolute) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.X = 0x42;
std::vector<uint8_t> data = {0x8E, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x7FFF));
EXPECT_CALL(mock_memory, WriteByte(0x7FFF, 0x42));
cpu.ExecuteInstruction(0x8E); // STX Absolute
}
TEST_F(CpuTest, STX_DirectPageIndexedY) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.X = 0x42;
cpu.Y = 0x02; // Set Y register to 0x02
std::vector<uint8_t> data = {0x96, 0x80};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, WriteByte(0x0082, 0x42));
cpu.ExecuteInstruction(0x96); // STX Direct Page Indexed, Y
}
// ============================================================================
TEST_F(CpuTest, STY_DirectPage) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.Y = 0x42;
std::vector<uint8_t> data = {0x84, 0x80};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, WriteByte(0x0080, 0x42));
cpu.ExecuteInstruction(0x84); // STY Direct Page
}
TEST_F(CpuTest, STY_Absolute) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.Y = 0x42;
std::vector<uint8_t> data = {0x8C, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x7FFF));
EXPECT_CALL(mock_memory, WriteByte(0x7FFF, 0x42));
cpu.ExecuteInstruction(0x8C); // STY Absolute
}
TEST_F(CpuTest, STY_DirectPageIndexedX) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.Y = 0x42;
cpu.X = 0x02; // Set X register to 0x02
std::vector<uint8_t> data = {0x94, 0x80};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, WriteByte(0x0082, 0x42));
cpu.ExecuteInstruction(0x94); // STY Direct Page Indexed, X
}
// ============================================================================
TEST_F(CpuTest, STZ_DirectPage) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
std::vector<uint8_t> data = {0x64, 0x80};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, WriteByte(0x0080, 0x00));
cpu.ExecuteInstruction(0x64); // STZ Direct Page
}
TEST_F(CpuTest, STZ_DirectPageIndexedX) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.X = 0x02; // Set X register to 0x02
std::vector<uint8_t> data = {0x74, 0x80};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, WriteByte(0x0082, 0x00));
cpu.ExecuteInstruction(0x74); // STZ Direct Page Indexed, X
}
TEST_F(CpuTest, STZ_Absolute) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
std::vector<uint8_t> data = {0x9C, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x7FFF));
EXPECT_CALL(mock_memory, WriteByte(0x7FFF, 0x00));
cpu.ExecuteInstruction(0x9C); // STZ Absolute
}
// ============================================================================
// TAX - Transfer Accumulator to Index X
TEST_F(CpuTest, TAX) {
cpu.A = 0xBC; // A register
std::vector<uint8_t> data = {0xAA}; // TAX
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xAA); // TAX
EXPECT_EQ(cpu.X, 0xBC); // X register should now be equal to A
}
// ============================================================================
// TAY - Transfer Accumulator to Index Y
TEST_F(CpuTest, TAY) {
cpu.A = 0xDE; // A register
std::vector<uint8_t> data = {0xA8}; // TAY
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xA8); // TAY
EXPECT_EQ(cpu.Y, 0xDE); // Y register should now be equal to A
}
// ============================================================================
TEST_F(CpuTest, TCD) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.A = 0x42;
std::vector<uint8_t> data = {0x5B};
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0x5B); // TCD
EXPECT_EQ(cpu.D, 0x42);
}
// ============================================================================
TEST_F(CpuTest, TCS) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.A = 0x42;
std::vector<uint8_t> data = {0x1B};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, SetSP(0x42));
cpu.ExecuteInstruction(0x1B); // TCS
EXPECT_EQ(mock_memory.SP(), 0x42);
}
// ============================================================================
TEST_F(CpuTest, TDC) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.D = 0x42;
std::vector<uint8_t> data = {0x7B};
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0x7B); // TDC
EXPECT_EQ(cpu.A, 0x42);
}
// ============================================================================
TEST_F(CpuTest, TRB_DirectPage) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.A = 0x42;
std::vector<uint8_t> data = {0x14, 0x80};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0080, {0x00});
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x0080));
EXPECT_CALL(mock_memory, ReadByte(0x0080)).WillOnce(Return(0x00));
EXPECT_CALL(mock_memory, WriteByte(0x0080, 0x00));
cpu.ExecuteInstruction(0x14); // TRB Direct Page
}
TEST_F(CpuTest, TRB_Absolute) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.A = 0x42;
std::vector<uint8_t> data = {0x1C, 0xFF, 0x7F};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x7FFF, {0x00});
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x7FFF));
EXPECT_CALL(mock_memory, ReadByte(0x7FFF)).WillOnce(Return(0x00));
EXPECT_CALL(mock_memory, WriteByte(0x7FFF, 0x00));
cpu.ExecuteInstruction(0x1C); // TRB Absolute
}
// ============================================================================
TEST_F(CpuTest, TSB_DirectPage) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.A = 0x00;
std::vector<uint8_t> data = {0x04, 0x80};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0080, {0x42});
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x0080));
EXPECT_CALL(mock_memory, ReadByte(0x0080)).WillOnce(Return(0x42));
EXPECT_CALL(mock_memory, WriteByte(0x0080, 0x42));
cpu.ExecuteInstruction(0x04); // TSB Direct Page
}
TEST_F(CpuTest, TSB_Absolute) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.A = 0x00;
std::vector<uint8_t> data = {0x0C, 0xFF, 0x7F};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x7FFF, {0x42});
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x7FFF));
EXPECT_CALL(mock_memory, ReadByte(0x7FFF)).WillOnce(Return(0x42));
EXPECT_CALL(mock_memory, WriteByte(0x7FFF, 0x42));
cpu.ExecuteInstruction(0x0C); // TSB Absolute
}
// ============================================================================
TEST_F(CpuTest, TSC) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.SetSP(0x42);
std::vector<uint8_t> data = {0x3B};
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0x3B); // TSC
EXPECT_EQ(cpu.A, 0x42);
}
// ============================================================================
TEST_F(CpuTest, TSX) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.SetSP(0x42);
std::vector<uint8_t> data = {0xBA};
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xBA); // TSX
EXPECT_EQ(cpu.X, 0x42);
}
// ============================================================================
// TXA - Transfer Index X to Accumulator
TEST_F(CpuTest, TXA) {
cpu.X = 0xAB; // X register
std::vector<uint8_t> data = {0x8A}; // TXA
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0x8A); // TXA
EXPECT_EQ(cpu.A, 0xAB); // A register should now be equal to X
}
// ============================================================================
TEST_F(CpuTest, TXS) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.X = 0x42;
std::vector<uint8_t> data = {0x9A};
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0x9A); // TXS
EXPECT_EQ(cpu.SP(), 0x42);
}
// ============================================================================
TEST_F(CpuTest, TXY) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.X = 0x42;
std::vector<uint8_t> data = {0x9B};
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0x9B); // TXY
EXPECT_EQ(cpu.Y, 0x42);
}
// ============================================================================
// TYA - Transfer Index Y to Accumulator
TEST_F(CpuTest, TYA) {
cpu.Y = 0xCD; // Y register
std::vector<uint8_t> data = {0x98}; // TYA
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0x98); // TYA
EXPECT_EQ(cpu.A, 0xCD); // A register should now be equal to Y
}
// ============================================================================
// TYX - Transfer Index Y to Index X
TEST_F(CpuTest, TYX) {
cpu.Y = 0xCD; // Y register
std::vector<uint8_t> data = {0xBB}; // TYX
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xBB); // TYX
EXPECT_EQ(cpu.X, 0xCD); // X register should now be equal to Y
}
// ============================================================================
TEST_F(CpuTest, WAI) {
cpu.ExecuteInstruction(0xCB); // WAI
// EXPECT_TRUE(cpu.GetWaitingFlag());
}
// ============================================================================
TEST_F(CpuTest, WDM) {
std::vector<uint8_t> data = {0x42};
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0x42); // WDM
}
// ============================================================================
TEST_F(CpuTest, XBA) {
cpu.SetAccumulatorSize(true); // Set A register to 8-bit mode
cpu.A = 0x4002;
std::vector<uint8_t> data = {0xEB};
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xEB); // XBA
EXPECT_EQ(cpu.A, 0x0240);
}
// ============================================================================
// 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_test
} // namespace yaze_test