4176 lines
139 KiB
C++
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
|