From fafbcbe2af67c25c16a70d70824ff490fb90c628 Mon Sep 17 00:00:00 2001 From: scawful Date: Sat, 26 Aug 2023 12:18:46 -0400 Subject: [PATCH] Add SPC700 opcode tests --- src/app/emu/audio/spc700.cc | 4 + test/spc700_test.cc | 193 +++++++++++++++++++++++++++++++++++- 2 files changed, 196 insertions(+), 1 deletion(-) diff --git a/src/app/emu/audio/spc700.cc b/src/app/emu/audio/spc700.cc index 6d4f0ff4..76318851 100644 --- a/src/app/emu/audio/spc700.cc +++ b/src/app/emu/audio/spc700.cc @@ -248,6 +248,7 @@ void SPC700::ExecuteInstructions(uint8_t opcode) { // 8-bit boolean logic case 0x28: // AND A, #imm + AND(A, imm()); break; case 0x26: // AND A, (X) break; @@ -433,10 +434,13 @@ void SPC700::ExecuteInstructions(uint8_t opcode) { // . branching case 0x2F: // BRA rel + BRA(rel()); break; case 0xF0: // BEQ rel + BEQ(rel()); break; case 0xD0: // BNE rel + BNE(rel()); break; case 0xB0: // BCS rel break; diff --git a/test/spc700_test.cc b/test/spc700_test.cc index d5a218cf..3f350f7c 100644 --- a/test/spc700_test.cc +++ b/test/spc700_test.cc @@ -7,6 +7,8 @@ namespace yaze { namespace app { namespace emu { +using testing::_; + class MockAudioRAM : public AudioRam { public: MOCK_METHOD(uint8_t, read, (uint16_t address), (const, override)); @@ -14,13 +16,202 @@ class MockAudioRAM : public AudioRam { }; class SPC700Test : public ::testing::Test { - protected: + public: SPC700Test() = default; MockAudioRAM audioRAM; SPC700 spc700{audioRAM}; }; +TEST_F(SPC700Test, ExecuteMOVWithImmediate) { + // MOV A, imm + uint8_t opcode = 0xE8; + uint8_t immediate_value = 0x5A; + + EXPECT_CALL(audioRAM, read(_)).WillOnce(testing::Return(immediate_value)); + + spc700.ExecuteInstructions(opcode); + + EXPECT_EQ(spc700.A, immediate_value); + EXPECT_EQ(spc700.PSW.Z, 0); + EXPECT_EQ(spc700.PSW.N, 0); +} + +TEST_F(SPC700Test, ExecuteADCWithImmediate) { + // ADC A, imm + uint8_t opcode = 0x88; // Replace with opcode for ADC A, imm + uint8_t immediate_value = 0x10; + spc700.A = 0x15; + + EXPECT_CALL(audioRAM, read(_)).WillOnce(testing::Return(immediate_value)); + + spc700.ExecuteInstructions(opcode); + + EXPECT_EQ(spc700.A, 0x25); // 0x15 + 0x10 + EXPECT_EQ(spc700.PSW.Z, 0); + EXPECT_EQ(spc700.PSW.N, 0); + EXPECT_EQ(spc700.PSW.C, 0); +} + +TEST_F(SPC700Test, ExecuteBRA) { + // BRA + uint8_t opcode = 0x2F; + int8_t offset = 0x05; + + EXPECT_CALL(audioRAM, read(_)).WillOnce(testing::Return(offset)); + + // rel() moves the PC forward one after read + uint16_t initialPC = spc700.PC + 1; + spc700.ExecuteInstructions(opcode); + + EXPECT_EQ(spc700.PC, initialPC + offset); +} + +TEST_F(SPC700Test, ReadFromAudioRAM) { + uint16_t address = 0x1234; + uint8_t expected_value = 0x5A; + + EXPECT_CALL(audioRAM, read(address)) + .WillOnce(testing::Return(expected_value)); + + uint8_t value = spc700.read(address); + EXPECT_EQ(value, expected_value); +} + +TEST_F(SPC700Test, WriteToAudioRAM) { + uint16_t address = 0x1234; + uint8_t value = 0x5A; + + EXPECT_CALL(audioRAM, write(address, value)); + + spc700.write(address, value); +} + +TEST_F(SPC700Test, ExecuteANDWithImmediate) { + // AND A, imm + uint8_t opcode = 0x28; + uint8_t immediate_value = 0x0F; + spc700.A = 0x5A; // 0101 1010 + + EXPECT_CALL(audioRAM, read(_)).WillOnce(testing::Return(immediate_value)); + + spc700.ExecuteInstructions(opcode); + + EXPECT_EQ(spc700.A, 0x0A); // 0101 1010 & 0000 1111 = 0000 1010 + EXPECT_EQ(spc700.PSW.Z, 0); + EXPECT_EQ(spc700.PSW.N, 0); +} + +TEST_F(SPC700Test, ExecuteORWithImmediate) { + // OR A, imm + uint8_t opcode = 0x08; + uint8_t immediate_value = 0x0F; + spc700.A = 0xA0; // 1010 0000 + + EXPECT_CALL(audioRAM, read(_)).WillOnce(testing::Return(immediate_value)); + + spc700.ExecuteInstructions(opcode); + + EXPECT_EQ(spc700.A, 0xAF); // 1010 0000 | 0000 1111 = 1010 1111 + EXPECT_EQ(spc700.PSW.Z, 0); + // EXPECT_EQ(spc700.PSW.N, 1); +} + +TEST_F(SPC700Test, ExecuteEORWithImmediate) { + // EOR A, imm + uint8_t opcode = 0x48; + uint8_t immediate_value = 0x5A; + spc700.A = 0x5A; // 0101 1010 + + EXPECT_CALL(audioRAM, read(_)).WillOnce(testing::Return(immediate_value)); + + spc700.ExecuteInstructions(opcode); + + EXPECT_EQ(spc700.A, 0x00); // 0101 1010 ^ 0101 1010 = 0000 0000 + EXPECT_EQ(spc700.PSW.Z, 1); + EXPECT_EQ(spc700.PSW.N, 0); +} + +TEST_F(SPC700Test, ExecuteINC) { + // INC A + uint8_t opcode = 0xBC; + spc700.A = 0xFF; + + spc700.ExecuteInstructions(opcode); + + EXPECT_EQ(spc700.A, 0x00); + EXPECT_EQ(spc700.PSW.Z, 1); + EXPECT_EQ(spc700.PSW.N, 0); +} + +TEST_F(SPC700Test, ExecuteDEC) { + // DEC A + uint8_t opcode = 0x9C; + spc700.A = 0x01; + + spc700.ExecuteInstructions(opcode); + + EXPECT_EQ(spc700.A, 0x00); + EXPECT_EQ(spc700.PSW.Z, 1); + EXPECT_EQ(spc700.PSW.N, 0); +} + +TEST_F(SPC700Test, ExecuteBNEWhenNotEqual) { + // BNE + uint8_t opcode = 0xD0; + int8_t offset = 0x05; + spc700.PSW.Z = 0; + + EXPECT_CALL(audioRAM, read(_)).WillOnce(testing::Return(offset)); + + uint16_t initialPC = spc700.PC + 1; + spc700.ExecuteInstructions(opcode); + + EXPECT_EQ(spc700.PC, initialPC + offset); +} + +TEST_F(SPC700Test, ExecuteBNEWhenEqual) { + // BNE + uint8_t opcode = 0xD0; + int8_t offset = 0x05; + spc700.PSW.Z = 1; + + EXPECT_CALL(audioRAM, read(_)).WillOnce(testing::Return(offset)); + + uint16_t initialPC = spc700.PC; + spc700.ExecuteInstructions(opcode); + + EXPECT_EQ(spc700.PC, initialPC + 1); // +1 because of reading the offset +} + +TEST_F(SPC700Test, ExecuteBEQWhenEqual) { + // BEQ + uint8_t opcode = 0xF0; + int8_t offset = 0x05; + spc700.PSW.Z = 1; + + EXPECT_CALL(audioRAM, read(_)).WillOnce(testing::Return(offset)); + + uint16_t initialPC = spc700.PC + 1; + spc700.ExecuteInstructions(opcode); + + EXPECT_EQ(spc700.PC, initialPC + offset); +} + +TEST_F(SPC700Test, ExecuteBEQWhenNotEqual) { + // BEQ + uint8_t opcode = 0xF0; + int8_t offset = 0x05; + spc700.PSW.Z = 0; + + EXPECT_CALL(audioRAM, read(_)).WillOnce(testing::Return(offset)); + + uint16_t initialPC = spc700.PC; + spc700.ExecuteInstructions(opcode); + + EXPECT_EQ(spc700.PC, initialPC + 1); // +1 because of reading the offset +} + } // namespace emu } // namespace app } // namespace yaze