|
|
|
|
@@ -4,6 +4,8 @@
|
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
|
|
|
|
|
|
#include "app/emu/clock.h"
|
|
|
|
|
#include "app/emu/internal/asm_parser.h"
|
|
|
|
|
#include "app/emu/internal/opcodes.h"
|
|
|
|
|
#include "app/emu/memory/memory.h"
|
|
|
|
|
#include "app/emu/memory/mock_memory.h"
|
|
|
|
|
|
|
|
|
|
@@ -17,11 +19,13 @@ class CPUTest : public ::testing::Test {
|
|
|
|
|
mock_memory.Init();
|
|
|
|
|
EXPECT_CALL(mock_memory, ClearMemory()).Times(::testing::AtLeast(1));
|
|
|
|
|
mock_memory.ClearMemory();
|
|
|
|
|
asm_parser.CreateInternalOpcodeMap();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MockMemory mock_memory;
|
|
|
|
|
MockClock mock_clock;
|
|
|
|
|
CPU cpu{mock_memory, mock_clock};
|
|
|
|
|
AsmParser asm_parser;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
using ::testing::_;
|
|
|
|
|
@@ -80,7 +84,6 @@ TEST_F(CPUTest, ADC_Immediate_PositiveAndNegativeNumbers) {
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, ADC_Absolute) {
|
|
|
|
|
cpu.A = 0x01;
|
|
|
|
|
cpu.PC = 1; // PC register
|
|
|
|
|
cpu.status = 0x00; // 16-bit mode
|
|
|
|
|
std::vector<uint8_t> data = {0x6D, 0x03, 0x00, 0x05, 0x00};
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
@@ -95,32 +98,18 @@ TEST_F(CPUTest, ADC_Absolute) {
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, ADC_AbsoluteLong) {
|
|
|
|
|
cpu.A = 0x01;
|
|
|
|
|
cpu.PC = 1; // PC register
|
|
|
|
|
cpu.status = 0x00; // 16-bit mode
|
|
|
|
|
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_DirectPage) {
|
|
|
|
|
cpu.A = 0x01;
|
|
|
|
|
cpu.D = 0x0001;
|
|
|
|
|
std::vector<uint8_t> data = {0x65, 0x01, 0x00};
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
mock_memory.InsertMemory(0x100, {0x05, 0x05, 0x05});
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadByte(0x100)).WillOnce(Return(0x05));
|
|
|
|
|
|
|
|
|
|
cpu.ExecuteInstruction(0x65); // ADC Direct Page
|
|
|
|
|
EXPECT_EQ(cpu.A, 0x06);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ADC Direct Page Indirect
|
|
|
|
|
TEST_F(CPUTest, ADC_DirectPageIndirect) {
|
|
|
|
|
cpu.A = 0x02;
|
|
|
|
|
@@ -130,7 +119,7 @@ TEST_F(CPUTest, ADC_DirectPageIndirect) {
|
|
|
|
|
mock_memory.InsertMemory(0x2010, {0x00, 0x30}); // [0x2010] = 0x3000
|
|
|
|
|
mock_memory.InsertMemory(0x3000, {0x05}); // [0x3000] = 0x05
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadByte(0x0000)).WillOnce(Return(0x10));
|
|
|
|
|
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));
|
|
|
|
|
|
|
|
|
|
@@ -148,7 +137,7 @@ TEST_F(CPUTest, ADC_DirectPageIndexedIndirectX) {
|
|
|
|
|
mock_memory.InsertMemory(0x3000, {0x06}); // [0x3000] = 0x06
|
|
|
|
|
|
|
|
|
|
cpu.X = 0x02; // X register
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadByte(0x0000)).WillOnce(Return(0x10));
|
|
|
|
|
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));
|
|
|
|
|
|
|
|
|
|
@@ -173,7 +162,6 @@ TEST_F(CPUTest, ADC_CheckCarryFlag) {
|
|
|
|
|
TEST_F(CPUTest, ADC_AbsoluteIndexedX) {
|
|
|
|
|
cpu.A = 0x03;
|
|
|
|
|
cpu.X = 0x02; // X register
|
|
|
|
|
cpu.PC = 0x0001;
|
|
|
|
|
cpu.SetCarryFlag(false);
|
|
|
|
|
cpu.SetAccumulatorSize(false); // 16-bit mode
|
|
|
|
|
std::vector<uint8_t> data = {0x7D, 0x03, 0x00, 0x00, 0x05, 0x00};
|
|
|
|
|
@@ -189,7 +177,6 @@ TEST_F(CPUTest, ADC_AbsoluteIndexedX) {
|
|
|
|
|
TEST_F(CPUTest, ADC_AbsoluteIndexedY) {
|
|
|
|
|
cpu.A = 0x03;
|
|
|
|
|
cpu.Y = 0x02; // Y register
|
|
|
|
|
cpu.PC = 0x0001;
|
|
|
|
|
std::vector<uint8_t> data = {0x79, 0x03, 0x00, 0x00, 0x05, 0x00};
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
|
|
|
|
|
@@ -208,7 +195,7 @@ TEST_F(CPUTest, ADC_DirectPageIndexedY) {
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
mock_memory.InsertMemory(0x2012, {0x06});
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadByte(0x0000)).WillOnce(Return(0x10));
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x10));
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadWordLong(0x2012)).WillOnce(Return(0x06));
|
|
|
|
|
|
|
|
|
|
cpu.ExecuteInstruction(0x77); // ADC Direct Page Indexed Y
|
|
|
|
|
@@ -236,7 +223,6 @@ TEST_F(CPUTest, ADC_DirectPageIndirectLong) {
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, ADC_StackRelative) {
|
|
|
|
|
cpu.A = 0x03;
|
|
|
|
|
cpu.PC = 0x0001;
|
|
|
|
|
cpu.SetSP(0x01FF); // Setting Stack Pointer to 0x01FF
|
|
|
|
|
std::vector<uint8_t> data = {0x63, 0x02}; // ADC sr
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
@@ -256,10 +242,8 @@ TEST_F(CPUTest, ADC_StackRelative) {
|
|
|
|
|
// AND - Logical AND
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, AND_Immediate) {
|
|
|
|
|
cpu.PC = 0;
|
|
|
|
|
cpu.status = 0xFF; // 8-bit mode
|
|
|
|
|
cpu.A = 0b11110000; // A register
|
|
|
|
|
std::vector<uint8_t> data = {0b10101010}; // AND #0b10101010
|
|
|
|
|
cpu.A = 0b11110000; // A register
|
|
|
|
|
std::vector<uint8_t> data = {0x29, 0b10101010}; // AND #0b10101010
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
|
|
|
|
|
cpu.ExecuteInstruction(0x29); // AND Immediate
|
|
|
|
|
@@ -270,7 +254,6 @@ TEST_F(CPUTest, AND_Absolute_16BitMode) {
|
|
|
|
|
cpu.A = 0b11111111; // A register
|
|
|
|
|
cpu.E = 0; // 16-bit mode
|
|
|
|
|
cpu.status = 0x00; // Clear status flags
|
|
|
|
|
cpu.PC = 1; // PC register
|
|
|
|
|
std::vector<uint8_t> data = {0x2D, 0x03, 0x00, 0b10101010, 0x01, 0x02};
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
|
|
|
|
|
@@ -288,14 +271,14 @@ TEST_F(CPUTest, AND_Absolute_16BitMode) {
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, AND_AbsoluteLong) {
|
|
|
|
|
cpu.A = 0x01;
|
|
|
|
|
cpu.PC = 1; // PC register
|
|
|
|
|
// PC register
|
|
|
|
|
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(0x0004));
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadWordLong(0x0001)).WillOnce(Return(0x000004));
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadWordLong(0x0004)).WillOnce(Return(0x0005));
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadWordLong(0x0004)).WillOnce(Return(0x000005));
|
|
|
|
|
|
|
|
|
|
cpu.ExecuteInstruction(0x2F); // ADC Absolute Long
|
|
|
|
|
EXPECT_EQ(cpu.A, 0x01);
|
|
|
|
|
@@ -314,8 +297,6 @@ TEST_F(CPUTest, AND_IndexedIndirect) {
|
|
|
|
|
TEST_F(CPUTest, AND_AbsoluteIndexedX) {
|
|
|
|
|
cpu.A = 0b11110000; // A register
|
|
|
|
|
cpu.X = 0x02; // X register
|
|
|
|
|
cpu.status = 0xFF; // 8-bit mode
|
|
|
|
|
cpu.PC = 1; // PC register
|
|
|
|
|
std::vector<uint8_t> data = {0x3D, 0x03, 0x00,
|
|
|
|
|
0b00000000, 0b10101010, 0b01010101};
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
@@ -338,8 +319,6 @@ TEST_F(CPUTest, AND_AbsoluteIndexedX) {
|
|
|
|
|
TEST_F(CPUTest, AND_AbsoluteIndexedY) {
|
|
|
|
|
cpu.A = 0b11110000; // A register
|
|
|
|
|
cpu.Y = 0x02; // Y register
|
|
|
|
|
cpu.status = 0xFF; // 8-bit mode
|
|
|
|
|
cpu.PC = 1; // PC register
|
|
|
|
|
std::vector<uint8_t> data = {0x39, 0x03, 0x00,
|
|
|
|
|
0b00000000, 0b10101010, 0b01010101};
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
@@ -363,7 +342,6 @@ TEST_F(CPUTest, AND_AbsoluteLongIndexedX) {
|
|
|
|
|
cpu.A = 0b11110000; // A register
|
|
|
|
|
cpu.X = 0x02; // X register
|
|
|
|
|
cpu.status = 0xFF; // 8-bit mode
|
|
|
|
|
cpu.PC = 1; // PC register
|
|
|
|
|
std::vector<uint8_t> data = {0x3F, 0x03, 0x00, 0x00,
|
|
|
|
|
0b00000000, 0b10101010, 0b01010101};
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
@@ -417,10 +395,13 @@ TEST_F(CPUTest, ASL_Absolute) {
|
|
|
|
|
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_FALSE(cpu.GetZeroFlag());
|
|
|
|
|
EXPECT_TRUE(cpu.GetNegativeFlag());
|
|
|
|
|
EXPECT_TRUE(cpu.GetZeroFlag());
|
|
|
|
|
EXPECT_FALSE(cpu.GetNegativeFlag());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, ASL_DP_Indexed_X) {
|
|
|
|
|
@@ -442,10 +423,13 @@ TEST_F(CPUTest, ASL_Absolute_Indexed_X) {
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
mock_memory.InsertMemory(0x2012, {0x40}); // [0x2012] = 0x40
|
|
|
|
|
|
|
|
|
|
cpu.ExecuteInstruction(0x1E); // ASL Absolute Indexed, X
|
|
|
|
|
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_FALSE(cpu.GetZeroFlag());
|
|
|
|
|
EXPECT_TRUE(cpu.GetNegativeFlag());
|
|
|
|
|
EXPECT_TRUE(cpu.GetZeroFlag());
|
|
|
|
|
EXPECT_FALSE(cpu.GetNegativeFlag());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
@@ -465,15 +449,14 @@ TEST_F(CPUTest, BCC_WhenCarryFlagClear) {
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, BCC_WhenCarryFlagSet) {
|
|
|
|
|
cpu.SetCarryFlag(true);
|
|
|
|
|
cpu.PC = 0x1000;
|
|
|
|
|
std::vector<uint8_t> data(0x1001, 2); // Operand at address 0x1001
|
|
|
|
|
std::vector<uint8_t> data = {0x90, 0x02, 0x01};
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadByte(_)).WillOnce(Return(2));
|
|
|
|
|
|
|
|
|
|
cpu.ExecuteInstruction(0x90); // BCC
|
|
|
|
|
cpu.BCC(2);
|
|
|
|
|
EXPECT_EQ(cpu.PC, 0x1000);
|
|
|
|
|
|
|
|
|
|
EXPECT_EQ(cpu.PC, 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
@@ -493,30 +476,63 @@ TEST_F(CPUTest, BCS_WhenCarryFlagSet) {
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, BCS_WhenCarryFlagClear) {
|
|
|
|
|
cpu.SetCarryFlag(false);
|
|
|
|
|
cpu.PC = 0x1000;
|
|
|
|
|
std::vector<uint8_t> data = {0x10, 0x02, 0x01}; // Operand at address 0x1001
|
|
|
|
|
std::vector<uint8_t> data = {0x10, 0x02, 0x01};
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadByte(_)).WillOnce(Return(2));
|
|
|
|
|
|
|
|
|
|
cpu.ExecuteInstruction(0xB0); // BCS
|
|
|
|
|
cpu.BCS(2);
|
|
|
|
|
EXPECT_EQ(cpu.PC, 0x1000);
|
|
|
|
|
EXPECT_EQ(cpu.PC, 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
// BEQ - Branch if Equal
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, BEQ) {
|
|
|
|
|
TEST_F(CPUTest, BEQ_Immediate_ZeroFlagSet) {
|
|
|
|
|
cpu.PB = 0x00;
|
|
|
|
|
cpu.SetZeroFlag(true);
|
|
|
|
|
cpu.PC = 0x1000;
|
|
|
|
|
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, 0x1003);
|
|
|
|
|
|
|
|
|
|
EXPECT_EQ(cpu.PC, 0x02);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
@@ -524,19 +540,25 @@ TEST_F(CPUTest, BEQ) {
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, BIT_Immediate) {
|
|
|
|
|
cpu.A = 0x01;
|
|
|
|
|
cpu.PC = 0x0001;
|
|
|
|
|
cpu.status = 0xFF;
|
|
|
|
|
std::vector<uint8_t> data = {0x00, 0x10}; // BIT
|
|
|
|
|
std::vector<uint8_t> data = {0x24, 0x00, 0x10}; // BIT
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
mock_memory.InsertMemory(0x0010, {0x81}); // [0x0010] = 0x81
|
|
|
|
|
|
|
|
|
|
cpu.ExecuteInstruction(0x89); // BIT
|
|
|
|
|
// 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_Absolute) {
|
|
|
|
|
cpu.A = 0x01;
|
|
|
|
|
cpu.PC = 0x0001;
|
|
|
|
|
cpu.status = 0xFF;
|
|
|
|
|
std::vector<uint8_t> data = {0x00, 0x10}; // BIT
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
@@ -557,7 +579,6 @@ TEST_F(CPUTest, BIT_Absolute) {
|
|
|
|
|
TEST_F(CPUTest, BIT_AbsoluteIndexedX) {
|
|
|
|
|
cpu.A = 0x01;
|
|
|
|
|
cpu.X = 0x02;
|
|
|
|
|
cpu.PC = 0x0001;
|
|
|
|
|
cpu.status = 0xFF;
|
|
|
|
|
std::vector<uint8_t> data = {0x00, 0x10}; // BIT
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
@@ -579,32 +600,29 @@ TEST_F(CPUTest, BIT_AbsoluteIndexedX) {
|
|
|
|
|
// BMI - Branch if Minus
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, BMI_BranchTaken) {
|
|
|
|
|
cpu.PC = 0x0000;
|
|
|
|
|
cpu.SetNegativeFlag(true);
|
|
|
|
|
std::vector<uint8_t> data = {0x02}; // BMI
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, BMI_BranchNotTaken) {
|
|
|
|
|
cpu.PC = 0x0000;
|
|
|
|
|
cpu.SetNegativeFlag(false);
|
|
|
|
|
std::vector<uint8_t> data = {0x30, 0x02}; // BMI
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
|
|
|
|
|
cpu.ExecuteInstruction(0x30); // BMI
|
|
|
|
|
EXPECT_EQ(cpu.PC, 0x0000);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
// BNE - Branch if Not Equal
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, BNE_BranchTaken) {
|
|
|
|
|
cpu.PC = 0x0000;
|
|
|
|
|
cpu.SetZeroFlag(false);
|
|
|
|
|
std::vector<uint8_t> data = {0x02}; // BNE
|
|
|
|
|
std::vector<uint8_t> data = {0xD0, 0x02}; // BNE
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
|
|
|
|
|
cpu.ExecuteInstruction(0xD0); // BNE
|
|
|
|
|
@@ -612,44 +630,40 @@ TEST_F(CPUTest, BNE_BranchTaken) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, BNE_BranchNotTaken) {
|
|
|
|
|
cpu.PC = 0x0000;
|
|
|
|
|
cpu.SetZeroFlag(true);
|
|
|
|
|
std::vector<uint8_t> data = {0xD0, 0x02}; // BNE
|
|
|
|
|
std::vector<uint8_t> data = {0xD0, 0x05}; // BNE
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
|
|
|
|
|
cpu.ExecuteInstruction(0xD0); // BNE
|
|
|
|
|
EXPECT_EQ(cpu.PC, 0x0000);
|
|
|
|
|
EXPECT_EQ(cpu.PC, 0x0002);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
// BPL - Branch if Positive
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, BPL_BranchTaken) {
|
|
|
|
|
cpu.PC = 0x0000;
|
|
|
|
|
cpu.SetNegativeFlag(false);
|
|
|
|
|
std::vector<uint8_t> data = {0x02}; // BPL
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, BPL_BranchNotTaken) {
|
|
|
|
|
cpu.PC = 0x0000;
|
|
|
|
|
cpu.SetNegativeFlag(true);
|
|
|
|
|
std::vector<uint8_t> data = {0x10, 0x02}; // BPL
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
|
|
|
|
|
cpu.ExecuteInstruction(0x10); // BPL
|
|
|
|
|
EXPECT_EQ(cpu.PC, 0x0000);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
// BRA - Branch Always
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, BRA) {
|
|
|
|
|
cpu.PC = 0x0000;
|
|
|
|
|
std::vector<uint8_t> data = {0x02}; // BRA
|
|
|
|
|
std::vector<uint8_t> data = {0x80, 0x02}; // BRA
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
|
|
|
|
|
cpu.ExecuteInstruction(0x80); // BRA
|
|
|
|
|
@@ -657,7 +671,6 @@ TEST_F(CPUTest, BRA) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, BRK) {
|
|
|
|
|
cpu.PC = 0x0000;
|
|
|
|
|
std::vector<uint8_t> data = {0x00}; // BRK
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
mock_memory.InsertMemory(0xFFFE, {0x10, 0x20}); // [0xFFFE] = 0x2010
|
|
|
|
|
@@ -673,23 +686,21 @@ TEST_F(CPUTest, BRK) {
|
|
|
|
|
// BRL - Branch Long
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, BRL) {
|
|
|
|
|
cpu.PC = 0x1000;
|
|
|
|
|
std::vector<uint8_t> data(0x1001, 2); // Operand at address 0x1001
|
|
|
|
|
std::vector<uint8_t> data = {0x82, 0x10, 0x20}; // BRL
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadWord(_)).WillOnce(Return(2));
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x2010));
|
|
|
|
|
|
|
|
|
|
cpu.ExecuteInstruction(0x82); // BRL
|
|
|
|
|
EXPECT_EQ(cpu.PC, 0x1004);
|
|
|
|
|
EXPECT_EQ(cpu.PC, 0x2010);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
// BVC - Branch if Overflow Clear
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, BVC_BranchTaken) {
|
|
|
|
|
cpu.PC = 0x0000;
|
|
|
|
|
cpu.SetOverflowFlag(false);
|
|
|
|
|
std::vector<uint8_t> data = {0x02}; // BVC
|
|
|
|
|
std::vector<uint8_t> data = {0x50, 0x02}; // BVC
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
|
|
|
|
|
cpu.ExecuteInstruction(0x50); // BVC
|
|
|
|
|
@@ -700,9 +711,8 @@ TEST_F(CPUTest, BVC_BranchTaken) {
|
|
|
|
|
// BVS - Branch if Overflow Set
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, BVS_BranchTaken) {
|
|
|
|
|
cpu.PC = 0x0000;
|
|
|
|
|
cpu.SetOverflowFlag(true);
|
|
|
|
|
std::vector<uint8_t> data = {0x02}; // BVS
|
|
|
|
|
std::vector<uint8_t> data = {0x70, 0x02}; // BVS
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
|
|
|
|
|
cpu.ExecuteInstruction(0x70); // BVS
|
|
|
|
|
@@ -772,7 +782,7 @@ TEST_F(CPUTest, CMP_Immediate_8Bit) {
|
|
|
|
|
mock_memory.InsertMemory(0x0000, {0x40});
|
|
|
|
|
|
|
|
|
|
// Set up the memory to return 0x40 when the Immediate addressing mode is used
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadByte(0x00)).WillOnce(::testing::Return(0x40));
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(::testing::Return(0x40));
|
|
|
|
|
|
|
|
|
|
// Execute the CMP Immediate instruction
|
|
|
|
|
cpu.ExecuteInstruction(0xC9);
|
|
|
|
|
@@ -811,7 +821,7 @@ TEST_F(CPUTest, CPX_ZeroFlagSet) {
|
|
|
|
|
cpu.SetIndexSize(false); // Set X register to 16-bit mode
|
|
|
|
|
cpu.SetAccumulatorSize(false);
|
|
|
|
|
cpu.X = 0x1234;
|
|
|
|
|
std::vector<uint8_t> data = {0x34, 0x12}; // CPX #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
|
|
|
|
|
@@ -838,7 +848,7 @@ TEST_F(CPUTest, CPY_ZeroFlagSet) {
|
|
|
|
|
cpu.SetIndexSize(false); // Set Y register to 16-bit mode
|
|
|
|
|
cpu.SetAccumulatorSize(false);
|
|
|
|
|
cpu.Y = 0x5678;
|
|
|
|
|
std::vector<uint8_t> data = {0x78, 0x56}; // CPY #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
|
|
|
|
|
@@ -894,7 +904,6 @@ TEST_F(CPUTest, DEY) {
|
|
|
|
|
TEST_F(CPUTest, EOR_Immediate_8bit) {
|
|
|
|
|
cpu.A = 0b10101010; // A register
|
|
|
|
|
cpu.status = 0xFF; // 8-bit mode
|
|
|
|
|
cpu.PC = 1; // PC register
|
|
|
|
|
std::vector<uint8_t> data = {0x49, 0b01010101};
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
|
|
|
|
|
@@ -906,7 +915,6 @@ TEST_F(CPUTest, EOR_DirectPageIndexedIndirectX) {
|
|
|
|
|
cpu.A = 0b10101010; // A register
|
|
|
|
|
cpu.X = 0x02; // X register
|
|
|
|
|
cpu.status = 0xFF; // 8-bit mode
|
|
|
|
|
cpu.PC = 1; // PC register
|
|
|
|
|
std::vector<uint8_t> data = {0x41, 0x7E};
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
mock_memory.InsertMemory(0x0080, {0x00, 0x10}); // [0x0080] = 0x1000
|
|
|
|
|
@@ -919,7 +927,6 @@ TEST_F(CPUTest, EOR_DirectPageIndexedIndirectX) {
|
|
|
|
|
TEST_F(CPUTest, EOR_DirectPage) {
|
|
|
|
|
cpu.A = 0b10101010; // A register
|
|
|
|
|
cpu.status = 0xFF; // 8-bit mode
|
|
|
|
|
cpu.PC = 1; // PC register
|
|
|
|
|
std::vector<uint8_t> data = {0x45, 0x7F};
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
mock_memory.InsertMemory(0x007F, {0b01010101}); // [0x007F] = 0b01010101
|
|
|
|
|
@@ -931,7 +938,6 @@ TEST_F(CPUTest, EOR_DirectPage) {
|
|
|
|
|
TEST_F(CPUTest, EOR_DirectPageIndirectLong) {
|
|
|
|
|
cpu.A = 0b10101010; // A register
|
|
|
|
|
cpu.status = 0xFF; // 8-bit mode
|
|
|
|
|
cpu.PC = 1; // PC register
|
|
|
|
|
std::vector<uint8_t> data = {0x47, 0x7F};
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
mock_memory.InsertMemory(0x007F, {0x00, 0x10, 0x00}); // [0x007F] = 0x1000
|
|
|
|
|
@@ -944,7 +950,6 @@ TEST_F(CPUTest, EOR_DirectPageIndirectLong) {
|
|
|
|
|
TEST_F(CPUTest, EOR_Absolute) {
|
|
|
|
|
cpu.A = 0b10101010; // A register
|
|
|
|
|
cpu.status = 0xFF; // 8-bit mode
|
|
|
|
|
cpu.PC = 1; // PC register
|
|
|
|
|
std::vector<uint8_t> data = {0x4D, 0x00, 0x10};
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
mock_memory.InsertMemory(0x1000, {0b01010101}); // [0x1000] = 0b01010101
|
|
|
|
|
@@ -956,7 +961,6 @@ TEST_F(CPUTest, EOR_Absolute) {
|
|
|
|
|
TEST_F(CPUTest, EOR_AbsoluteLong) {
|
|
|
|
|
cpu.A = 0b10101010; // A register
|
|
|
|
|
cpu.status = 0xFF; // 8-bit mode
|
|
|
|
|
cpu.PC = 1; // PC register
|
|
|
|
|
std::vector<uint8_t> data = {0x4F, 0x00, 0x10, 0x00};
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
mock_memory.InsertMemory(0x1000, {0b01010101}); // [0x1000] = 0b01010101
|
|
|
|
|
@@ -969,7 +973,6 @@ TEST_F(CPUTest, EOR_DirectPageIndirectLongIndexedY) {
|
|
|
|
|
cpu.A = 0b10101010; // A register
|
|
|
|
|
cpu.Y = 0x02; // Y register
|
|
|
|
|
cpu.status = 0xFF; // 8-bit mode
|
|
|
|
|
cpu.PC = 1; // PC register
|
|
|
|
|
std::vector<uint8_t> data = {0x51, 0x7E};
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
mock_memory.InsertMemory(0x007E, {0x00, 0x10, 0x00}); // [0x007E] = 0x1000
|
|
|
|
|
@@ -983,7 +986,6 @@ TEST_F(CPUTest, EOR_DirectPageIndirectIndexedY) {
|
|
|
|
|
cpu.A = 0b10101010; // A register
|
|
|
|
|
cpu.Y = 0x02; // Y register
|
|
|
|
|
cpu.status = 0xFF; // 8-bit mode
|
|
|
|
|
cpu.PC = 1; // PC register
|
|
|
|
|
std::vector<uint8_t> data = {0x51, 0x7E};
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
mock_memory.InsertMemory(0x007E, {0x00, 0x10}); // [0x007E] = 0x1000
|
|
|
|
|
@@ -997,7 +999,7 @@ TEST_F(CPUTest, EOR_DirectPageIndirectIndexedY) {
|
|
|
|
|
// cpu.A = 0b10101010; // A register
|
|
|
|
|
// cpu.Y = 0x02; // Y register
|
|
|
|
|
// cpu.status = 0xFF; // 8-bit mode
|
|
|
|
|
// cpu.PC = 1; // PC register
|
|
|
|
|
// // PC register
|
|
|
|
|
// std::vector<uint8_t> data = {0x57, 0x7C};
|
|
|
|
|
// mock_memory.SetMemoryContents(data);
|
|
|
|
|
// mock_memory.InsertMemory(0x007E, {0x00, 0x10, 0x00}); // [0x007E] = 0x1000
|
|
|
|
|
@@ -1012,7 +1014,7 @@ TEST_F(CPUTest, EOR_AbsoluteIndexedX) {
|
|
|
|
|
cpu.A = 0b10101010; // A register
|
|
|
|
|
cpu.X = 0x02; // X register
|
|
|
|
|
cpu.status = 0xFF; // 8-bit mode
|
|
|
|
|
cpu.PC = 1; // PC register
|
|
|
|
|
// PC register
|
|
|
|
|
std::vector<uint8_t> data = {0x5D, 0x7C, 0x00};
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
mock_memory.InsertMemory(0x007E, {0b01010101}); // [0x007E] = 0b01010101
|
|
|
|
|
@@ -1025,7 +1027,7 @@ TEST_F(CPUTest, EOR_AbsoluteIndexedY) {
|
|
|
|
|
cpu.A = 0b10101010; // A register
|
|
|
|
|
cpu.Y = 0x02; // Y register
|
|
|
|
|
cpu.status = 0xFF; // 8-bit mode
|
|
|
|
|
cpu.PC = 1; // PC register
|
|
|
|
|
// PC register
|
|
|
|
|
std::vector<uint8_t> data = {0x59, 0x7C, 0x00};
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
mock_memory.InsertMemory(0x007E, {0b01010101}); // [0x007E] = 0b01010101
|
|
|
|
|
@@ -1038,7 +1040,7 @@ TEST_F(CPUTest, EOR_AbsoluteLongIndexedX) {
|
|
|
|
|
cpu.A = 0b10101010; // A register
|
|
|
|
|
cpu.X = 0x02; // X register
|
|
|
|
|
cpu.status = 0xFF; // 8-bit mode
|
|
|
|
|
cpu.PC = 1; // PC register
|
|
|
|
|
// PC register
|
|
|
|
|
std::vector<uint8_t> data = {0x5F, 0x7C, 0x00, 0x00};
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
mock_memory.InsertMemory(0x007E, {0b01010101}); // [0x007E] = 0b01010101
|
|
|
|
|
@@ -1050,42 +1052,39 @@ TEST_F(CPUTest, EOR_AbsoluteLongIndexedX) {
|
|
|
|
|
// ============================================================================
|
|
|
|
|
// INC - Increment Memory
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
TEST_F(CPUTest, INC_DirectPage_8bit) {
|
|
|
|
|
cpu.PC = 0x1001;
|
|
|
|
|
std::vector<uint8_t> data = {0xE6, 0x7F, 0x7F};
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadByte(0x7F)).WillOnce(Return(0x7F));
|
|
|
|
|
EXPECT_CALL(mock_memory, WriteByte(0, 0x80)).Times(1);
|
|
|
|
|
|
|
|
|
|
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_TRUE(cpu.GetNegativeFlag());
|
|
|
|
|
EXPECT_EQ(mock_memory[0x0220], 0x41);
|
|
|
|
|
EXPECT_FALSE(cpu.GetNegativeFlag());
|
|
|
|
|
EXPECT_FALSE(cpu.GetZeroFlag());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, INC_Absolute_16bit) {
|
|
|
|
|
cpu.PC = 0x1001;
|
|
|
|
|
std::vector<uint8_t> data = {0xEE, 0x7F, 0xFF};
|
|
|
|
|
std::vector<uint8_t> data = {0xEE, 0x00, 0x10};
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadWord(0xFF7F)).WillOnce(Return(0x7FFF));
|
|
|
|
|
EXPECT_CALL(mock_memory, WriteWord(0xFF7F, 0x8000)).Times(1);
|
|
|
|
|
mock_memory.InsertMemory(0x1000, {0x40}); // [0x1000] = 0x40
|
|
|
|
|
|
|
|
|
|
cpu.SetAccumulatorSize(false);
|
|
|
|
|
cpu.ExecuteInstruction(0xEE); // INC Absolute
|
|
|
|
|
EXPECT_TRUE(cpu.GetNegativeFlag());
|
|
|
|
|
EXPECT_EQ(mock_memory[0x1000], 0x41);
|
|
|
|
|
EXPECT_FALSE(cpu.GetNegativeFlag());
|
|
|
|
|
EXPECT_FALSE(cpu.GetZeroFlag());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, INC_DirectPage_ZeroResult_8bit) {
|
|
|
|
|
cpu.PC = 0x1001;
|
|
|
|
|
std::vector<uint8_t> data = {0xE6, 0xFF};
|
|
|
|
|
cpu.D = 0x0200; // Setting Direct Page register to 0x0200
|
|
|
|
|
std::vector<uint8_t> data = {0xE6, 0x20};
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadByte(0xFF)).WillOnce(Return(0xFF));
|
|
|
|
|
EXPECT_CALL(mock_memory, WriteByte(0xFF, 0x00)).Times(1);
|
|
|
|
|
mock_memory.InsertMemory(0x0220, {0xFF}); // [0x0220] = 0xFF
|
|
|
|
|
|
|
|
|
|
cpu.SetAccumulatorSize(true);
|
|
|
|
|
cpu.ExecuteInstruction(0xE6); // INC Direct Page
|
|
|
|
|
@@ -1094,63 +1093,54 @@ TEST_F(CPUTest, INC_DirectPage_ZeroResult_8bit) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, INC_Absolute_ZeroResult_16bit) {
|
|
|
|
|
cpu.PC = 0x1001;
|
|
|
|
|
std::vector<uint8_t> data = {0xEE, 0xFF, 0xFF};
|
|
|
|
|
std::vector<uint8_t> data = {0xEE, 0x00, 0x10};
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadWord(0xFFFF)).WillOnce(Return(0xFFFF));
|
|
|
|
|
EXPECT_CALL(mock_memory, WriteWord(0xFFFF, 0x0000)).Times(1);
|
|
|
|
|
mock_memory.InsertMemory(0x1000, {0xFF}); // [0x1000] = 0xFF
|
|
|
|
|
|
|
|
|
|
cpu.SetAccumulatorSize(false);
|
|
|
|
|
cpu.ExecuteInstruction(0xEE); // INC Absolute
|
|
|
|
|
EXPECT_FALSE(cpu.GetNegativeFlag());
|
|
|
|
|
EXPECT_TRUE(cpu.GetZeroFlag());
|
|
|
|
|
EXPECT_FALSE(cpu.GetZeroFlag());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, INC_DirectPage_8bit_Overflow) {
|
|
|
|
|
cpu.PC = 0x1001;
|
|
|
|
|
std::vector<uint8_t> data = {0xE6, 0x80};
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadByte(0x80)).WillOnce(Return(0xFF));
|
|
|
|
|
EXPECT_CALL(mock_memory, WriteByte(0x80, 0x00)).Times(1);
|
|
|
|
|
|
|
|
|
|
cpu.SetAccumulatorSize(true);
|
|
|
|
|
cpu.ExecuteInstruction(0xE6); // INC Direct Page
|
|
|
|
|
EXPECT_FALSE(cpu.GetNegativeFlag());
|
|
|
|
|
EXPECT_TRUE(cpu.GetZeroFlag());
|
|
|
|
|
EXPECT_FALSE(cpu.GetZeroFlag());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, INC_DirectPageIndexedX_8bit) {
|
|
|
|
|
cpu.PC = 0x1001;
|
|
|
|
|
cpu.X = 0x01;
|
|
|
|
|
std::vector<uint8_t> data = {0xF6, 0x7E};
|
|
|
|
|
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(0x7F)).WillOnce(Return(0x7F));
|
|
|
|
|
EXPECT_CALL(mock_memory, WriteByte(0x7F, 0x80)).Times(1);
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x20));
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadByte(0x0221)).WillOnce(Return(0x40));
|
|
|
|
|
|
|
|
|
|
cpu.SetAccumulatorSize(true);
|
|
|
|
|
cpu.ExecuteInstruction(0xF6); // INC DP Indexed, X
|
|
|
|
|
EXPECT_TRUE(cpu.GetNegativeFlag());
|
|
|
|
|
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.PC = 0x1001;
|
|
|
|
|
cpu.X = 0x01;
|
|
|
|
|
std::vector<uint8_t> data = {0xFE, 0x7F, 0xFF};
|
|
|
|
|
std::vector<uint8_t> data = {0xFE, 0x00, 0x10};
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadWord(0xFF80)).WillOnce(Return(0x7FFF));
|
|
|
|
|
EXPECT_CALL(mock_memory, WriteWord(0xFF80, 0x8000)).Times(1);
|
|
|
|
|
mock_memory.InsertMemory(0x1001, {0x40}); // [0x1001] = 0x40
|
|
|
|
|
|
|
|
|
|
cpu.SetAccumulatorSize(false);
|
|
|
|
|
cpu.ExecuteInstruction(0xFE); // INC Absolute Indexed, X
|
|
|
|
|
EXPECT_TRUE(cpu.GetNegativeFlag());
|
|
|
|
|
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
|
|
|
|
|
@@ -1187,22 +1177,22 @@ TEST_F(CPUTest, INY) {
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, JMP_Absolute) {
|
|
|
|
|
cpu.PC = 0x1001;
|
|
|
|
|
std::vector<uint8_t> data = {0x4C, 0x05, 0x20}; // JMP $2005
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadWord(0x1001)).WillOnce(Return(0x2005));
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x2005));
|
|
|
|
|
|
|
|
|
|
cpu.ExecuteInstruction(0x4C); // JMP Absolute
|
|
|
|
|
EXPECT_EQ(cpu.PC, 0x2005);
|
|
|
|
|
cpu.ExecuteInstruction(0xEA); // NOP
|
|
|
|
|
|
|
|
|
|
EXPECT_EQ(cpu.PC, 0x2006);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, JMP_Indirect) {
|
|
|
|
|
cpu.PC = 0x1001;
|
|
|
|
|
std::vector<uint8_t> data = {0x6C, 0x03, 0x20, 0x05, 0x30}; // JMP ($2003)
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadWord(0x1001)).WillOnce(Return(0x2003));
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x2003));
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadWord(0x2003)).WillOnce(Return(0x3005));
|
|
|
|
|
|
|
|
|
|
cpu.ExecuteInstruction(0x6C); // JMP Indirect
|
|
|
|
|
@@ -1215,16 +1205,12 @@ TEST_F(CPUTest, JMP_Indirect) {
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, JML_AbsoluteLong) {
|
|
|
|
|
cpu.E = 0;
|
|
|
|
|
cpu.PC = 0x1001;
|
|
|
|
|
cpu.PB = 0x02; // Set the program bank register to 0x02
|
|
|
|
|
|
|
|
|
|
std::vector<uint8_t> data = {0x5C, 0x05, 0x00, 0x03}; // JML $030005
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
mock_memory.InsertMemory(0x030005, {0x00, 0x20, 0x00});
|
|
|
|
|
|
|
|
|
|
// NOP to set PB to 0x02
|
|
|
|
|
cpu.ExecuteInstruction(0xEA);
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadWordLong(0x1001)).WillOnce(Return(0x030005));
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadWordLong(0x0001)).WillOnce(Return(0x030005));
|
|
|
|
|
|
|
|
|
|
cpu.ExecuteInstruction(0x5C); // JML Absolute Long
|
|
|
|
|
EXPECT_EQ(cpu.PC, 0x0005);
|
|
|
|
|
@@ -1236,15 +1222,18 @@ TEST_F(CPUTest, JML_AbsoluteLong) {
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, JSR_Absolute) {
|
|
|
|
|
cpu.PC = 0x1001;
|
|
|
|
|
std::vector<uint8_t> data = {0x20, 0x05, 0x20}; // JSR $2005
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadWord(0x1001)).WillOnce(Return(0x2005));
|
|
|
|
|
EXPECT_CALL(mock_memory, PushWord(0x1002)).Times(1);
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
@@ -1252,12 +1241,11 @@ TEST_F(CPUTest, JSR_Absolute) {
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, JSL_AbsoluteLong) {
|
|
|
|
|
cpu.PC = 0x1001;
|
|
|
|
|
std::vector<uint8_t> data = {0x22, 0x05, 0x20, 0x00}; // JSL $002005
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadWordLong(0x1001)).WillOnce(Return(0x002005));
|
|
|
|
|
EXPECT_CALL(mock_memory, PushLong(0x1003)).Times(1);
|
|
|
|
|
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);
|
|
|
|
|
@@ -1266,23 +1254,18 @@ TEST_F(CPUTest, JSL_AbsoluteLong) {
|
|
|
|
|
// ============================================================================
|
|
|
|
|
// LDA - Load Accumulator
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
TEST_F(CPUTest, LDA_Immediate_8bit) {
|
|
|
|
|
cpu.PC = 0x1001;
|
|
|
|
|
cpu.SetAccumulatorSize(true);
|
|
|
|
|
cpu.A = 0x00;
|
|
|
|
|
std::vector<uint8_t> data = {0xA9, 0x7F, 0x7F};
|
|
|
|
|
std::vector<uint8_t> data = {0xA9, 0xFF};
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
mock_memory.InsertMemory(0x7F, {0xAA});
|
|
|
|
|
|
|
|
|
|
cpu.ExecuteInstruction(0xA9); // LDA Immediate
|
|
|
|
|
EXPECT_EQ(cpu.A, 0x7F);
|
|
|
|
|
EXPECT_EQ(cpu.A, 0xFF);
|
|
|
|
|
EXPECT_TRUE(cpu.GetNegativeFlag());
|
|
|
|
|
EXPECT_FALSE(cpu.GetZeroFlag());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, LDA_Immediate_16bit) {
|
|
|
|
|
cpu.PC = 0x1001;
|
|
|
|
|
std::vector<uint8_t> data = {0xA9, 0x7F, 0xFF};
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
|
|
|
|
|
@@ -1294,13 +1277,15 @@ TEST_F(CPUTest, LDA_Immediate_16bit) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, LDA_DirectPage) {
|
|
|
|
|
cpu.PC = 0x1001;
|
|
|
|
|
std::vector<uint8_t> data = {0xA5, 0x7F};
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadByte(0x7F)).WillOnce(Return(0x80));
|
|
|
|
|
|
|
|
|
|
cpu.SetAccumulatorSize(true);
|
|
|
|
|
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());
|
|
|
|
|
@@ -1308,22 +1293,20 @@ TEST_F(CPUTest, LDA_DirectPage) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, LDA_Absolute) {
|
|
|
|
|
cpu.PC = 0x1001;
|
|
|
|
|
cpu.SetAccumulatorSize(true);
|
|
|
|
|
std::vector<uint8_t> data = {0xAD, 0x7F, 0xFF};
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
mock_memory.InsertMemory(0x7FFF, {0x7F});
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(mock_memory, ReadWord(0x1001)).WillOnce(Return(0x7FFF));
|
|
|
|
|
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_TRUE(cpu.GetNegativeFlag());
|
|
|
|
|
EXPECT_FALSE(cpu.GetZeroFlag());
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
// Stack Tests
|
|
|
|
|
@@ -1452,8 +1435,9 @@ TEST_F(CPUTest, PLD_PullDirectPageRegister) {
|
|
|
|
|
// REP - Reset Processor Status Bits
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, REP) {
|
|
|
|
|
cpu.status = 0xFF; // All flags set
|
|
|
|
|
std::vector<uint8_t> data = {0x30, 0x00}; // REP #0x30 (clear N & Z flags)
|
|
|
|
|
cpu.status = 0xFF; // All flags set
|
|
|
|
|
std::vector<uint8_t> data = {0xC2, 0x30,
|
|
|
|
|
0x00}; // REP #0x30 (clear N & Z flags)
|
|
|
|
|
mock_memory.SetMemoryContents(data);
|
|
|
|
|
|
|
|
|
|
cpu.ExecuteInstruction(0xC2); // REP
|
|
|
|
|
@@ -1464,8 +1448,9 @@ TEST_F(CPUTest, REP) {
|
|
|
|
|
// SEP - Set Processor Status Bits
|
|
|
|
|
|
|
|
|
|
TEST_F(CPUTest, SEP) {
|
|
|
|
|
cpu.status = 0x00; // All flags cleared
|
|
|
|
|
std::vector<uint8_t> data = {0x30, 0x00}; // SEP #0x30 (set N & Z flags)
|
|
|
|
|
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
|
|
|
|
|
|