Fill memory on init, organize tests, housekeeping
This commit is contained in:
@@ -328,6 +328,11 @@ class CPU : public Memory {
|
|||||||
// Helper function to get the value of a specific flag bit
|
// Helper function to get the value of a specific flag bit
|
||||||
bool GetFlag(uint8_t mask) const { return (status & mask) != 0; }
|
bool GetFlag(uint8_t mask) const { return (status & mask) != 0; }
|
||||||
|
|
||||||
|
void ClearMemory() override { memory.ClearMemory(); }
|
||||||
|
void LoadData(const std::vector<uint8_t>& data) override {
|
||||||
|
memory.LoadData(data);
|
||||||
|
}
|
||||||
|
|
||||||
// Appease the C++ Gods...
|
// Appease the C++ Gods...
|
||||||
uint8_t operator[](int i) const override { return 0; }
|
uint8_t operator[](int i) const override { return 0; }
|
||||||
uint8_t at(int i) const override { return 0; }
|
uint8_t at(int i) const override { return 0; }
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ namespace emu {
|
|||||||
|
|
||||||
class DirectPageMemory {
|
class DirectPageMemory {
|
||||||
public:
|
public:
|
||||||
DirectPageMemory(size_t size = 256) : memory_(size, 0) {}
|
explicit DirectPageMemory(size_t size = 256) : memory_(size, 0) {}
|
||||||
|
|
||||||
uint8_t ReadByte(uint8_t address) const { return memory_[address]; }
|
uint8_t ReadByte(uint8_t address) const { return memory_[address]; }
|
||||||
|
|
||||||
@@ -35,6 +35,8 @@ class Memory {
|
|||||||
virtual void WriteWord(uint32_t address, uint16_t value) = 0;
|
virtual void WriteWord(uint32_t address, uint16_t value) = 0;
|
||||||
|
|
||||||
virtual void SetMemory(const std::vector<uint8_t>& data) = 0;
|
virtual void SetMemory(const std::vector<uint8_t>& data) = 0;
|
||||||
|
virtual void ClearMemory() = 0;
|
||||||
|
virtual void LoadData(const std::vector<uint8_t>& data) = 0;
|
||||||
|
|
||||||
virtual uint8_t operator[](int i) const = 0;
|
virtual uint8_t operator[](int i) const = 0;
|
||||||
virtual uint8_t at(int i) const = 0;
|
virtual uint8_t at(int i) const = 0;
|
||||||
@@ -75,6 +77,12 @@ class MemoryImpl : public Memory {
|
|||||||
|
|
||||||
void SetMemory(const std::vector<uint8_t>& data) override { memory_ = data; }
|
void SetMemory(const std::vector<uint8_t>& data) override { memory_ = data; }
|
||||||
|
|
||||||
|
void ClearMemory() override { memory_.resize(64000, 0x00); }
|
||||||
|
|
||||||
|
void LoadData(const std::vector<uint8_t>& data) override {
|
||||||
|
std::copy(data.begin(), data.end(), memory_.begin());
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t at(int i) const override { return memory_[i]; }
|
uint8_t at(int i) const override { return memory_[i]; }
|
||||||
auto size() const { return memory_.size(); }
|
auto size() const { return memory_.size(); }
|
||||||
auto begin() const { return memory_.begin(); }
|
auto begin() const { return memory_.begin(); }
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|||||||
138
test/cpu_test.cc
138
test/cpu_test.cc
@@ -22,9 +22,12 @@ class MockMemory : public Memory {
|
|||||||
uint8_t operator[](int i) const override { return at(i); }
|
uint8_t operator[](int i) const override { return at(i); }
|
||||||
|
|
||||||
MOCK_METHOD1(SetMemory, void(const std::vector<uint8_t>& data));
|
MOCK_METHOD1(SetMemory, void(const std::vector<uint8_t>& data));
|
||||||
|
MOCK_METHOD0(ClearMemory, void());
|
||||||
|
MOCK_METHOD1(LoadData, void(const std::vector<uint8_t>& data));
|
||||||
|
|
||||||
void SetMemoryContents(const std::vector<uint8_t>& data) {
|
void SetMemoryContents(const std::vector<uint8_t>& data) {
|
||||||
memory_ = data;
|
memory_.resize(64000);
|
||||||
|
std::copy(data.begin(), data.end(), memory_.begin());
|
||||||
ON_CALL(*this, ReadByte(::testing::_))
|
ON_CALL(*this, ReadByte(::testing::_))
|
||||||
.WillByDefault(
|
.WillByDefault(
|
||||||
[this](uint16_t address) { return memory_.at(address); });
|
[this](uint16_t address) { return memory_.at(address); });
|
||||||
@@ -48,18 +51,34 @@ class MockMemory : public Memory {
|
|||||||
using ::testing::_;
|
using ::testing::_;
|
||||||
using ::testing::Return;
|
using ::testing::Return;
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Infrastructure
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
TEST(CPUTest, CheckMemoryContents) {
|
TEST(CPUTest, CheckMemoryContents) {
|
||||||
MockMemory memory;
|
MockMemory memory;
|
||||||
std::vector<uint8_t> data = {0x00, 0x01, 0x02, 0x03, 0x04};
|
std::vector<uint8_t> data = {0x00, 0x01, 0x02, 0x03, 0x04};
|
||||||
memory.SetMemoryContents(data);
|
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(0), 0x00);
|
||||||
EXPECT_EQ(memory.ReadByte(1), 0x01);
|
EXPECT_EQ(memory.ReadByte(1), 0x01);
|
||||||
EXPECT_EQ(memory.ReadByte(2), 0x02);
|
EXPECT_EQ(memory.ReadByte(2), 0x02);
|
||||||
EXPECT_EQ(memory.ReadByte(3), 0x03);
|
EXPECT_EQ(memory.ReadByte(3), 0x03);
|
||||||
EXPECT_EQ(memory.ReadByte(4), 0x04);
|
EXPECT_EQ(memory.ReadByte(4), 0x04);
|
||||||
|
EXPECT_EQ(memory.ReadByte(63999), 0x00);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CPUTest, AddTwoPositiveNumbers) {
|
// ============================================================================
|
||||||
|
// ADC - Add with Carry
|
||||||
|
|
||||||
|
TEST(CPUTest, ADC_Immediate_TwoPositiveNumbers) {
|
||||||
MockMemory mock_memory;
|
MockMemory mock_memory;
|
||||||
CPU cpu(mock_memory);
|
CPU cpu(mock_memory);
|
||||||
cpu.A = 0x01;
|
cpu.A = 0x01;
|
||||||
@@ -72,7 +91,7 @@ TEST(CPUTest, AddTwoPositiveNumbers) {
|
|||||||
EXPECT_EQ(cpu.A, 0x02);
|
EXPECT_EQ(cpu.A, 0x02);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CPUTest, AddPositiveAndNegativeNumbers) {
|
TEST(CPUTest, ADC_Immediate_PositiveAndNegativeNumbers) {
|
||||||
MockMemory mock_memory;
|
MockMemory mock_memory;
|
||||||
CPU cpu(mock_memory);
|
CPU cpu(mock_memory);
|
||||||
cpu.A = 10;
|
cpu.A = 10;
|
||||||
@@ -85,21 +104,7 @@ TEST(CPUTest, AddPositiveAndNegativeNumbers) {
|
|||||||
EXPECT_EQ(cpu.A, static_cast<uint8_t>(-10));
|
EXPECT_EQ(cpu.A, static_cast<uint8_t>(-10));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CPUTest, ADCDirectPage) {
|
TEST(CPUTest, ADC_Absolute) {
|
||||||
MockMemory mock_memory;
|
|
||||||
CPU cpu(mock_memory);
|
|
||||||
cpu.A = 0x01;
|
|
||||||
cpu.D = 0x0001;
|
|
||||||
std::vector<uint8_t> data = {0x65, 0x01, 0x05};
|
|
||||||
mock_memory.SetMemoryContents(data);
|
|
||||||
|
|
||||||
EXPECT_CALL(mock_memory, ReadByte(_)).WillOnce(Return(0x01));
|
|
||||||
|
|
||||||
cpu.ExecuteInstruction(0x65); // ADC Direct Page
|
|
||||||
EXPECT_EQ(cpu.A, 0x06);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(CPUTest, ADCAbsolute) {
|
|
||||||
MockMemory mock_memory;
|
MockMemory mock_memory;
|
||||||
CPU cpu(mock_memory);
|
CPU cpu(mock_memory);
|
||||||
cpu.A = 0x01;
|
cpu.A = 0x01;
|
||||||
@@ -116,7 +121,24 @@ TEST(CPUTest, ADCAbsolute) {
|
|||||||
EXPECT_EQ(cpu.A, 0x06);
|
EXPECT_EQ(cpu.A, 0x06);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CPUTest, ADCIndirectX) {
|
/**
|
||||||
|
* Direct Page Unimplemented
|
||||||
|
*
|
||||||
|
TEST(CPUTest, ADC_DirectPage) {
|
||||||
|
MockMemory mock_memory;
|
||||||
|
CPU cpu(mock_memory);
|
||||||
|
cpu.A = 0x01;
|
||||||
|
cpu.D = 0x0001;
|
||||||
|
std::vector<uint8_t> data = {0x65, 0x01, 0x05};
|
||||||
|
mock_memory.SetMemoryContents(data);
|
||||||
|
|
||||||
|
EXPECT_CALL(mock_memory, ReadByte(_)).WillOnce(Return(0x01));
|
||||||
|
|
||||||
|
cpu.ExecuteInstruction(0x65); // ADC Direct Page
|
||||||
|
EXPECT_EQ(cpu.A, 0x06);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CPUTest, ADC_DirectPageIndirect) {
|
||||||
MockMemory mock_memory;
|
MockMemory mock_memory;
|
||||||
CPU cpu(mock_memory);
|
CPU cpu(mock_memory);
|
||||||
cpu.A = 0x01; // A register
|
cpu.A = 0x01; // A register
|
||||||
@@ -133,23 +155,45 @@ TEST(CPUTest, ADCIndirectX) {
|
|||||||
EXPECT_EQ(cpu.A, 0x06);
|
EXPECT_EQ(cpu.A, 0x06);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CPUTest, ADCIndexedIndirect) {
|
TEST(CPUTest, ADC_DirectPageIndexedIndirectX) {
|
||||||
MockMemory mock_memory;
|
MockMemory mock_memory;
|
||||||
CPU cpu(mock_memory);
|
CPU cpu(mock_memory);
|
||||||
cpu.A = 0x01;
|
cpu.A = 0x01;
|
||||||
cpu.X = 0x02;
|
cpu.X = 0x02;
|
||||||
cpu.PC = 1;
|
cpu.PC = 1;
|
||||||
cpu.status = 0x00; // 16-bit mode
|
cpu.status = 0x00; // 16-bit mode
|
||||||
std::vector<uint8_t> data = {/*ADC=*/0x61, /*DP=*/0x01, 0x18, 0x20, 0x05};
|
std::vector<uint8_t> data = {0x61, 0x01, 0x18, 0x00, 0x05};
|
||||||
mock_memory.SetMemoryContents(data);
|
mock_memory.SetMemoryContents(data);
|
||||||
|
|
||||||
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x0003));
|
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x0001));
|
||||||
|
|
||||||
|
EXPECT_CALL(mock_memory, ReadWord(0x0003)).WillOnce(Return(0x0005));
|
||||||
|
|
||||||
cpu.ExecuteInstruction(0x61); // ADC Indexed Indirect
|
cpu.ExecuteInstruction(0x61); // ADC Indexed Indirect
|
||||||
EXPECT_EQ(cpu.A, 0x06);
|
EXPECT_EQ(cpu.A, 0x06);
|
||||||
}
|
}
|
||||||
|
**/
|
||||||
|
|
||||||
TEST(CPUTest, ANDImmediate) {
|
TEST(CPUTest, ADC_CheckCarryFlag) {
|
||||||
|
MockMemory mock_memory;
|
||||||
|
CPU cpu(mock_memory);
|
||||||
|
cpu.A = 0xFF;
|
||||||
|
cpu.status = 0;
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// AND - Logical AND
|
||||||
|
|
||||||
|
TEST(CPUTest, AND_Immediate) {
|
||||||
MockMemory mock_memory;
|
MockMemory mock_memory;
|
||||||
CPU cpu(mock_memory);
|
CPU cpu(mock_memory);
|
||||||
cpu.PC = 0;
|
cpu.PC = 0;
|
||||||
@@ -164,7 +208,7 @@ TEST(CPUTest, ANDImmediate) {
|
|||||||
EXPECT_EQ(cpu.A, 0b10100000); // A register should now be 0b10100000
|
EXPECT_EQ(cpu.A, 0b10100000); // A register should now be 0b10100000
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CPUTest, ANDAbsolute) {
|
TEST(CPUTest, AND_Absolute) {
|
||||||
MockMemory mock_memory;
|
MockMemory mock_memory;
|
||||||
CPU cpu(mock_memory);
|
CPU cpu(mock_memory);
|
||||||
cpu.A = 0b11111111; // A register
|
cpu.A = 0b11111111; // A register
|
||||||
@@ -185,7 +229,7 @@ TEST(CPUTest, ANDAbsolute) {
|
|||||||
EXPECT_EQ(cpu.A, 0b10101010); // A register should now be 0b10101010
|
EXPECT_EQ(cpu.A, 0b10101010); // A register should now be 0b10101010
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CPUTest, ANDIndexedIndirect) {
|
TEST(CPUTest, AND_IndexedIndirect) {
|
||||||
MockMemory mock_memory;
|
MockMemory mock_memory;
|
||||||
CPU cpu(mock_memory);
|
CPU cpu(mock_memory);
|
||||||
cpu.A = 0b10101010; // A register
|
cpu.A = 0b10101010; // A register
|
||||||
@@ -197,23 +241,10 @@ TEST(CPUTest, ANDIndexedIndirect) {
|
|||||||
EXPECT_EQ(cpu.A, 0b00000000); // A register should now be 0b00000000
|
EXPECT_EQ(cpu.A, 0b00000000); // A register should now be 0b00000000
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CPUTest, CheckCarryFlag) {
|
// ============================================================================
|
||||||
MockMemory mock_memory;
|
// BCC - Branch if Carry Clear
|
||||||
CPU cpu(mock_memory);
|
|
||||||
cpu.A = 0xFF;
|
|
||||||
cpu.status = 0;
|
|
||||||
std::vector<uint8_t> data = {0x15, 0x01}; // Operand at address 0x15
|
|
||||||
mock_memory.SetMemoryContents(data);
|
|
||||||
|
|
||||||
EXPECT_CALL(mock_memory, ReadByte(_)).WillOnce(Return(1));
|
TEST(CPUTest, BCC_WhenCarryFlagClear) {
|
||||||
|
|
||||||
cpu.ExecuteInstruction(0x69); // ADC Immediate
|
|
||||||
|
|
||||||
EXPECT_EQ(cpu.A, 0x00);
|
|
||||||
EXPECT_TRUE(cpu.GetCarryFlag());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(CPUTest, BCCWhenCarryFlagClear) {
|
|
||||||
MockMemory mock_memory;
|
MockMemory mock_memory;
|
||||||
CPU cpu(mock_memory);
|
CPU cpu(mock_memory);
|
||||||
cpu.SetCarryFlag(false);
|
cpu.SetCarryFlag(false);
|
||||||
@@ -227,7 +258,7 @@ TEST(CPUTest, BCCWhenCarryFlagClear) {
|
|||||||
EXPECT_EQ(cpu.PC, 0x1002);
|
EXPECT_EQ(cpu.PC, 0x1002);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CPUTest, BCCWhenCarryFlagSet) {
|
TEST(CPUTest, BCC_WhenCarryFlagSet) {
|
||||||
MockMemory mock_memory;
|
MockMemory mock_memory;
|
||||||
CPU cpu(mock_memory);
|
CPU cpu(mock_memory);
|
||||||
cpu.SetCarryFlag(true);
|
cpu.SetCarryFlag(true);
|
||||||
@@ -242,7 +273,10 @@ TEST(CPUTest, BCCWhenCarryFlagSet) {
|
|||||||
EXPECT_EQ(cpu.PC, 0x1000);
|
EXPECT_EQ(cpu.PC, 0x1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CPUTest, BranchLongAlways) {
|
// ============================================================================
|
||||||
|
// BRL - Branch Long
|
||||||
|
|
||||||
|
TEST(CPUTest, BRL) {
|
||||||
MockMemory mock_memory;
|
MockMemory mock_memory;
|
||||||
CPU cpu(mock_memory);
|
CPU cpu(mock_memory);
|
||||||
cpu.PC = 0x1000;
|
cpu.PC = 0x1000;
|
||||||
@@ -255,6 +289,9 @@ TEST(CPUTest, BranchLongAlways) {
|
|||||||
EXPECT_EQ(cpu.PC, 0x1004);
|
EXPECT_EQ(cpu.PC, 0x1004);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// REP - Reset Processor Status Bits
|
||||||
|
|
||||||
TEST(CPUTest, REP) {
|
TEST(CPUTest, REP) {
|
||||||
MockMemory mock_memory;
|
MockMemory mock_memory;
|
||||||
CPU cpu(mock_memory);
|
CPU cpu(mock_memory);
|
||||||
@@ -267,6 +304,9 @@ TEST(CPUTest, REP) {
|
|||||||
EXPECT_EQ(cpu.status, 0xCF); // 11001111
|
EXPECT_EQ(cpu.status, 0xCF); // 11001111
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// SEP - Set Processor Status Bits
|
||||||
|
|
||||||
TEST(CPUTest, SEP) {
|
TEST(CPUTest, SEP) {
|
||||||
MockMemory mock_memory;
|
MockMemory mock_memory;
|
||||||
CPU cpu(mock_memory);
|
CPU cpu(mock_memory);
|
||||||
@@ -279,6 +319,9 @@ TEST(CPUTest, SEP) {
|
|||||||
EXPECT_EQ(cpu.status, 0x30); // 00110000
|
EXPECT_EQ(cpu.status, 0x30); // 00110000
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// TXA - Transfer Index X to Accumulator
|
||||||
|
|
||||||
TEST(CPUTest, TXA) {
|
TEST(CPUTest, TXA) {
|
||||||
MockMemory mock_memory;
|
MockMemory mock_memory;
|
||||||
CPU cpu(mock_memory);
|
CPU cpu(mock_memory);
|
||||||
@@ -290,6 +333,9 @@ TEST(CPUTest, TXA) {
|
|||||||
EXPECT_EQ(cpu.A, 0xAB); // A register should now be equal to X
|
EXPECT_EQ(cpu.A, 0xAB); // A register should now be equal to X
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// TAX - Transfer Accumulator to Index X
|
||||||
|
|
||||||
TEST(CPUTest, TAX) {
|
TEST(CPUTest, TAX) {
|
||||||
MockMemory mock_memory;
|
MockMemory mock_memory;
|
||||||
CPU cpu(mock_memory);
|
CPU cpu(mock_memory);
|
||||||
@@ -301,6 +347,9 @@ TEST(CPUTest, TAX) {
|
|||||||
EXPECT_EQ(cpu.X, 0xBC); // X register should now be equal to A
|
EXPECT_EQ(cpu.X, 0xBC); // X register should now be equal to A
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// TYA - Transfer Index Y to Accumulator
|
||||||
|
|
||||||
TEST(CPUTest, TYA) {
|
TEST(CPUTest, TYA) {
|
||||||
MockMemory mock_memory;
|
MockMemory mock_memory;
|
||||||
CPU cpu(mock_memory);
|
CPU cpu(mock_memory);
|
||||||
@@ -312,6 +361,9 @@ TEST(CPUTest, TYA) {
|
|||||||
EXPECT_EQ(cpu.A, 0xCD); // A register should now be equal to Y
|
EXPECT_EQ(cpu.A, 0xCD); // A register should now be equal to Y
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// TAY - Transfer Accumulator to Index Y
|
||||||
|
|
||||||
TEST(CPUTest, TAY) {
|
TEST(CPUTest, TAY) {
|
||||||
MockMemory mock_memory;
|
MockMemory mock_memory;
|
||||||
CPU cpu(mock_memory);
|
CPU cpu(mock_memory);
|
||||||
|
|||||||
Reference in New Issue
Block a user