Added instructions: LdBU8, RLCA, LdU16Sp and AddHlBc

This commit is contained in:
2026-09-19 22:11:46 +02:00
parent 7fafc060f5
commit d0f6bb4e76
6 changed files with 435 additions and 9 deletions
+2 -1
View File
@@ -21,7 +21,8 @@
"inherits": "base", "inherits": "base",
"generator": "Ninja", "generator": "Ninja",
"cacheVariables": { "cacheVariables": {
"BUILD_TESTING": "ON" "BUILD_TESTING": "ON",
"CMAKE_BUILD_TYPE": "Debug"
} }
} }
], ],
@@ -28,6 +28,10 @@ std::uint8_t LdBcA(Processor &processor);
std::uint8_t IncBc(Processor &processor); std::uint8_t IncBc(Processor &processor);
std::uint8_t IncB(Processor &processor); std::uint8_t IncB(Processor &processor);
std::uint8_t DecB(Processor &processor); std::uint8_t DecB(Processor &processor);
std::uint8_t LdBU8(Processor &processor);
std::uint8_t RLCA(Processor &processor);
std::uint8_t LdU16Sp(Processor &processor);
std::uint8_t AddHlBc(Processor &processor);
} // namespace instructions } // namespace instructions
} // namespace juiceboy } // namespace juiceboy
+4
View File
@@ -29,17 +29,21 @@ public:
/// @return The current value of the stack pointer. /// @return The current value of the stack pointer.
[[nodiscard]] std::uint16_t GetStackPointer() const; [[nodiscard]] std::uint16_t GetStackPointer() const;
void SetStackPointer(std::uint16_t value);
[[nodiscard]] std::uint8_t GetA() const; [[nodiscard]] std::uint8_t GetA() const;
[[nodiscard]] std::uint8_t GetF() const; [[nodiscard]] std::uint8_t GetF() const;
[[nodiscard]] std::uint8_t GetB() const; [[nodiscard]] std::uint8_t GetB() const;
[[nodiscard]] std::uint16_t GetBC() const; [[nodiscard]] std::uint16_t GetBC() const;
[[nodiscard]] std::uint16_t GetHL() const;
void SetA(std::uint8_t value); void SetA(std::uint8_t value);
void SetF(std::uint8_t value); void SetF(std::uint8_t value);
void SetB(std::uint8_t value); void SetB(std::uint8_t value);
void SetBC(std::uint16_t value); void SetBC(std::uint16_t value);
void SetHL(std::uint16_t value);
/// @brief Get the current value of the given flag. /// @brief Get the current value of the given flag.
/// @return True if the given flag bit is set, false otherwise. /// @return True if the given flag bit is set, false otherwise.
+316 -8
View File
@@ -8,15 +8,277 @@
namespace juiceboy { namespace juiceboy {
Instructions::Instructions() { Instructions::Instructions() {
// For now, all not implemented instructions should throw. std::get<0x00>(m_instructions) = &instructions::Nop;
m_instructions.fill(&instructions::NotImplemented); std::get<0x01>(m_instructions) = &instructions::LdBcD16;
std::get<0x02>(m_instructions) = &instructions::LdBcA;
std::get<0x03>(m_instructions) = &instructions::IncBc;
std::get<0x04>(m_instructions) = &instructions::IncB;
std::get<0x05>(m_instructions) = &instructions::DecB;
std::get<0x06>(m_instructions) = &instructions::LdBU8;
std::get<0x07>(m_instructions) = &instructions::RLCA;
std::get<0x08>(m_instructions) = &instructions::LdU16Sp;
std::get<0x09>(m_instructions) = &instructions::AddHlBc;
std::get<0x0A>(m_instructions) = &instructions::NotImplemented;
std::get<0x0B>(m_instructions) = &instructions::NotImplemented;
std::get<0x0C>(m_instructions) = &instructions::NotImplemented;
std::get<0x0D>(m_instructions) = &instructions::NotImplemented;
std::get<0x0E>(m_instructions) = &instructions::NotImplemented;
std::get<0x0F>(m_instructions) = &instructions::NotImplemented;
std::get<0x0>(m_instructions) = &instructions::Nop; std::get<0x10>(m_instructions) = &instructions::NotImplemented;
std::get<0x1>(m_instructions) = &instructions::LdBcD16; std::get<0x11>(m_instructions) = &instructions::NotImplemented;
std::get<0x2>(m_instructions) = &instructions::LdBcA; std::get<0x12>(m_instructions) = &instructions::NotImplemented;
std::get<0x3>(m_instructions) = &instructions::IncBc; std::get<0x13>(m_instructions) = &instructions::NotImplemented;
std::get<0x4>(m_instructions) = &instructions::IncB; std::get<0x14>(m_instructions) = &instructions::NotImplemented;
std::get<0x5>(m_instructions) = &instructions::DecB; std::get<0x15>(m_instructions) = &instructions::NotImplemented;
std::get<0x16>(m_instructions) = &instructions::NotImplemented;
std::get<0x17>(m_instructions) = &instructions::NotImplemented;
std::get<0x18>(m_instructions) = &instructions::NotImplemented;
std::get<0x19>(m_instructions) = &instructions::NotImplemented;
std::get<0x1A>(m_instructions) = &instructions::NotImplemented;
std::get<0x1B>(m_instructions) = &instructions::NotImplemented;
std::get<0x1C>(m_instructions) = &instructions::NotImplemented;
std::get<0x1D>(m_instructions) = &instructions::NotImplemented;
std::get<0x1E>(m_instructions) = &instructions::NotImplemented;
std::get<0x1F>(m_instructions) = &instructions::NotImplemented;
std::get<0x20>(m_instructions) = &instructions::NotImplemented;
std::get<0x21>(m_instructions) = &instructions::NotImplemented;
std::get<0x22>(m_instructions) = &instructions::NotImplemented;
std::get<0x23>(m_instructions) = &instructions::NotImplemented;
std::get<0x24>(m_instructions) = &instructions::NotImplemented;
std::get<0x25>(m_instructions) = &instructions::NotImplemented;
std::get<0x26>(m_instructions) = &instructions::NotImplemented;
std::get<0x27>(m_instructions) = &instructions::NotImplemented;
std::get<0x28>(m_instructions) = &instructions::NotImplemented;
std::get<0x29>(m_instructions) = &instructions::NotImplemented;
std::get<0x2A>(m_instructions) = &instructions::NotImplemented;
std::get<0x2B>(m_instructions) = &instructions::NotImplemented;
std::get<0x2C>(m_instructions) = &instructions::NotImplemented;
std::get<0x2D>(m_instructions) = &instructions::NotImplemented;
std::get<0x2E>(m_instructions) = &instructions::NotImplemented;
std::get<0x2F>(m_instructions) = &instructions::NotImplemented;
std::get<0x30>(m_instructions) = &instructions::NotImplemented;
std::get<0x31>(m_instructions) = &instructions::NotImplemented;
std::get<0x32>(m_instructions) = &instructions::NotImplemented;
std::get<0x33>(m_instructions) = &instructions::NotImplemented;
std::get<0x34>(m_instructions) = &instructions::NotImplemented;
std::get<0x35>(m_instructions) = &instructions::NotImplemented;
std::get<0x36>(m_instructions) = &instructions::NotImplemented;
std::get<0x37>(m_instructions) = &instructions::NotImplemented;
std::get<0x38>(m_instructions) = &instructions::NotImplemented;
std::get<0x39>(m_instructions) = &instructions::NotImplemented;
std::get<0x3A>(m_instructions) = &instructions::NotImplemented;
std::get<0x3B>(m_instructions) = &instructions::NotImplemented;
std::get<0x3C>(m_instructions) = &instructions::NotImplemented;
std::get<0x3D>(m_instructions) = &instructions::NotImplemented;
std::get<0x3E>(m_instructions) = &instructions::NotImplemented;
std::get<0x3F>(m_instructions) = &instructions::NotImplemented;
std::get<0x40>(m_instructions) = &instructions::NotImplemented;
std::get<0x41>(m_instructions) = &instructions::NotImplemented;
std::get<0x42>(m_instructions) = &instructions::NotImplemented;
std::get<0x43>(m_instructions) = &instructions::NotImplemented;
std::get<0x44>(m_instructions) = &instructions::NotImplemented;
std::get<0x45>(m_instructions) = &instructions::NotImplemented;
std::get<0x46>(m_instructions) = &instructions::NotImplemented;
std::get<0x47>(m_instructions) = &instructions::NotImplemented;
std::get<0x48>(m_instructions) = &instructions::NotImplemented;
std::get<0x49>(m_instructions) = &instructions::NotImplemented;
std::get<0x4A>(m_instructions) = &instructions::NotImplemented;
std::get<0x4B>(m_instructions) = &instructions::NotImplemented;
std::get<0x4C>(m_instructions) = &instructions::NotImplemented;
std::get<0x4D>(m_instructions) = &instructions::NotImplemented;
std::get<0x4E>(m_instructions) = &instructions::NotImplemented;
std::get<0x4F>(m_instructions) = &instructions::NotImplemented;
std::get<0x50>(m_instructions) = &instructions::NotImplemented;
std::get<0x51>(m_instructions) = &instructions::NotImplemented;
std::get<0x52>(m_instructions) = &instructions::NotImplemented;
std::get<0x53>(m_instructions) = &instructions::NotImplemented;
std::get<0x54>(m_instructions) = &instructions::NotImplemented;
std::get<0x55>(m_instructions) = &instructions::NotImplemented;
std::get<0x56>(m_instructions) = &instructions::NotImplemented;
std::get<0x57>(m_instructions) = &instructions::NotImplemented;
std::get<0x58>(m_instructions) = &instructions::NotImplemented;
std::get<0x59>(m_instructions) = &instructions::NotImplemented;
std::get<0x5A>(m_instructions) = &instructions::NotImplemented;
std::get<0x5B>(m_instructions) = &instructions::NotImplemented;
std::get<0x5C>(m_instructions) = &instructions::NotImplemented;
std::get<0x5D>(m_instructions) = &instructions::NotImplemented;
std::get<0x5E>(m_instructions) = &instructions::NotImplemented;
std::get<0x5F>(m_instructions) = &instructions::NotImplemented;
std::get<0x60>(m_instructions) = &instructions::NotImplemented;
std::get<0x61>(m_instructions) = &instructions::NotImplemented;
std::get<0x62>(m_instructions) = &instructions::NotImplemented;
std::get<0x63>(m_instructions) = &instructions::NotImplemented;
std::get<0x64>(m_instructions) = &instructions::NotImplemented;
std::get<0x65>(m_instructions) = &instructions::NotImplemented;
std::get<0x66>(m_instructions) = &instructions::NotImplemented;
std::get<0x67>(m_instructions) = &instructions::NotImplemented;
std::get<0x68>(m_instructions) = &instructions::NotImplemented;
std::get<0x69>(m_instructions) = &instructions::NotImplemented;
std::get<0x6A>(m_instructions) = &instructions::NotImplemented;
std::get<0x6B>(m_instructions) = &instructions::NotImplemented;
std::get<0x6C>(m_instructions) = &instructions::NotImplemented;
std::get<0x6D>(m_instructions) = &instructions::NotImplemented;
std::get<0x6E>(m_instructions) = &instructions::NotImplemented;
std::get<0x6F>(m_instructions) = &instructions::NotImplemented;
std::get<0x70>(m_instructions) = &instructions::NotImplemented;
std::get<0x71>(m_instructions) = &instructions::NotImplemented;
std::get<0x72>(m_instructions) = &instructions::NotImplemented;
std::get<0x73>(m_instructions) = &instructions::NotImplemented;
std::get<0x74>(m_instructions) = &instructions::NotImplemented;
std::get<0x75>(m_instructions) = &instructions::NotImplemented;
std::get<0x76>(m_instructions) = &instructions::NotImplemented;
std::get<0x77>(m_instructions) = &instructions::NotImplemented;
std::get<0x78>(m_instructions) = &instructions::NotImplemented;
std::get<0x79>(m_instructions) = &instructions::NotImplemented;
std::get<0x7A>(m_instructions) = &instructions::NotImplemented;
std::get<0x7B>(m_instructions) = &instructions::NotImplemented;
std::get<0x7C>(m_instructions) = &instructions::NotImplemented;
std::get<0x7D>(m_instructions) = &instructions::NotImplemented;
std::get<0x7E>(m_instructions) = &instructions::NotImplemented;
std::get<0x7F>(m_instructions) = &instructions::NotImplemented;
std::get<0x80>(m_instructions) = &instructions::NotImplemented;
std::get<0x81>(m_instructions) = &instructions::NotImplemented;
std::get<0x82>(m_instructions) = &instructions::NotImplemented;
std::get<0x83>(m_instructions) = &instructions::NotImplemented;
std::get<0x84>(m_instructions) = &instructions::NotImplemented;
std::get<0x85>(m_instructions) = &instructions::NotImplemented;
std::get<0x86>(m_instructions) = &instructions::NotImplemented;
std::get<0x87>(m_instructions) = &instructions::NotImplemented;
std::get<0x88>(m_instructions) = &instructions::NotImplemented;
std::get<0x89>(m_instructions) = &instructions::NotImplemented;
std::get<0x8A>(m_instructions) = &instructions::NotImplemented;
std::get<0x8B>(m_instructions) = &instructions::NotImplemented;
std::get<0x8C>(m_instructions) = &instructions::NotImplemented;
std::get<0x8D>(m_instructions) = &instructions::NotImplemented;
std::get<0x8E>(m_instructions) = &instructions::NotImplemented;
std::get<0x8F>(m_instructions) = &instructions::NotImplemented;
std::get<0x90>(m_instructions) = &instructions::NotImplemented;
std::get<0x91>(m_instructions) = &instructions::NotImplemented;
std::get<0x92>(m_instructions) = &instructions::NotImplemented;
std::get<0x93>(m_instructions) = &instructions::NotImplemented;
std::get<0x94>(m_instructions) = &instructions::NotImplemented;
std::get<0x95>(m_instructions) = &instructions::NotImplemented;
std::get<0x96>(m_instructions) = &instructions::NotImplemented;
std::get<0x97>(m_instructions) = &instructions::NotImplemented;
std::get<0x98>(m_instructions) = &instructions::NotImplemented;
std::get<0x99>(m_instructions) = &instructions::NotImplemented;
std::get<0x9A>(m_instructions) = &instructions::NotImplemented;
std::get<0x9B>(m_instructions) = &instructions::NotImplemented;
std::get<0x9C>(m_instructions) = &instructions::NotImplemented;
std::get<0x9D>(m_instructions) = &instructions::NotImplemented;
std::get<0x9E>(m_instructions) = &instructions::NotImplemented;
std::get<0x9F>(m_instructions) = &instructions::NotImplemented;
std::get<0xA0>(m_instructions) = &instructions::NotImplemented;
std::get<0xA1>(m_instructions) = &instructions::NotImplemented;
std::get<0xA2>(m_instructions) = &instructions::NotImplemented;
std::get<0xA3>(m_instructions) = &instructions::NotImplemented;
std::get<0xA4>(m_instructions) = &instructions::NotImplemented;
std::get<0xA5>(m_instructions) = &instructions::NotImplemented;
std::get<0xA6>(m_instructions) = &instructions::NotImplemented;
std::get<0xA7>(m_instructions) = &instructions::NotImplemented;
std::get<0xA8>(m_instructions) = &instructions::NotImplemented;
std::get<0xA9>(m_instructions) = &instructions::NotImplemented;
std::get<0xAA>(m_instructions) = &instructions::NotImplemented;
std::get<0xAB>(m_instructions) = &instructions::NotImplemented;
std::get<0xAC>(m_instructions) = &instructions::NotImplemented;
std::get<0xAD>(m_instructions) = &instructions::NotImplemented;
std::get<0xAE>(m_instructions) = &instructions::NotImplemented;
std::get<0xAF>(m_instructions) = &instructions::NotImplemented;
std::get<0xB0>(m_instructions) = &instructions::NotImplemented;
std::get<0xB1>(m_instructions) = &instructions::NotImplemented;
std::get<0xB2>(m_instructions) = &instructions::NotImplemented;
std::get<0xB3>(m_instructions) = &instructions::NotImplemented;
std::get<0xB4>(m_instructions) = &instructions::NotImplemented;
std::get<0xB5>(m_instructions) = &instructions::NotImplemented;
std::get<0xB6>(m_instructions) = &instructions::NotImplemented;
std::get<0xB7>(m_instructions) = &instructions::NotImplemented;
std::get<0xB8>(m_instructions) = &instructions::NotImplemented;
std::get<0xB9>(m_instructions) = &instructions::NotImplemented;
std::get<0xBA>(m_instructions) = &instructions::NotImplemented;
std::get<0xBB>(m_instructions) = &instructions::NotImplemented;
std::get<0xBC>(m_instructions) = &instructions::NotImplemented;
std::get<0xBD>(m_instructions) = &instructions::NotImplemented;
std::get<0xBE>(m_instructions) = &instructions::NotImplemented;
std::get<0xBF>(m_instructions) = &instructions::NotImplemented;
std::get<0xC0>(m_instructions) = &instructions::NotImplemented;
std::get<0xC1>(m_instructions) = &instructions::NotImplemented;
std::get<0xC2>(m_instructions) = &instructions::NotImplemented;
std::get<0xC3>(m_instructions) = &instructions::NotImplemented;
std::get<0xC4>(m_instructions) = &instructions::NotImplemented;
std::get<0xC5>(m_instructions) = &instructions::NotImplemented;
std::get<0xC6>(m_instructions) = &instructions::NotImplemented;
std::get<0xC7>(m_instructions) = &instructions::NotImplemented;
std::get<0xC8>(m_instructions) = &instructions::NotImplemented;
std::get<0xC9>(m_instructions) = &instructions::NotImplemented;
std::get<0xCA>(m_instructions) = &instructions::NotImplemented;
std::get<0xCB>(m_instructions) = &instructions::NotImplemented;
std::get<0xCC>(m_instructions) = &instructions::NotImplemented;
std::get<0xCD>(m_instructions) = &instructions::NotImplemented;
std::get<0xCE>(m_instructions) = &instructions::NotImplemented;
std::get<0xCF>(m_instructions) = &instructions::NotImplemented;
std::get<0xD0>(m_instructions) = &instructions::NotImplemented;
std::get<0xD1>(m_instructions) = &instructions::NotImplemented;
std::get<0xD2>(m_instructions) = &instructions::NotImplemented;
std::get<0xD3>(m_instructions) = &instructions::NotImplemented;
std::get<0xD4>(m_instructions) = &instructions::NotImplemented;
std::get<0xD5>(m_instructions) = &instructions::NotImplemented;
std::get<0xD6>(m_instructions) = &instructions::NotImplemented;
std::get<0xD7>(m_instructions) = &instructions::NotImplemented;
std::get<0xD8>(m_instructions) = &instructions::NotImplemented;
std::get<0xD9>(m_instructions) = &instructions::NotImplemented;
std::get<0xDA>(m_instructions) = &instructions::NotImplemented;
std::get<0xDB>(m_instructions) = &instructions::NotImplemented;
std::get<0xDC>(m_instructions) = &instructions::NotImplemented;
std::get<0xDD>(m_instructions) = &instructions::NotImplemented;
std::get<0xDE>(m_instructions) = &instructions::NotImplemented;
std::get<0xDF>(m_instructions) = &instructions::NotImplemented;
std::get<0xE0>(m_instructions) = &instructions::NotImplemented;
std::get<0xE1>(m_instructions) = &instructions::NotImplemented;
std::get<0xE2>(m_instructions) = &instructions::NotImplemented;
std::get<0xE3>(m_instructions) = &instructions::NotImplemented;
std::get<0xE4>(m_instructions) = &instructions::NotImplemented;
std::get<0xE5>(m_instructions) = &instructions::NotImplemented;
std::get<0xE6>(m_instructions) = &instructions::NotImplemented;
std::get<0xE7>(m_instructions) = &instructions::NotImplemented;
std::get<0xE8>(m_instructions) = &instructions::NotImplemented;
std::get<0xE9>(m_instructions) = &instructions::NotImplemented;
std::get<0xEA>(m_instructions) = &instructions::NotImplemented;
std::get<0xEB>(m_instructions) = &instructions::NotImplemented;
std::get<0xEC>(m_instructions) = &instructions::NotImplemented;
std::get<0xED>(m_instructions) = &instructions::NotImplemented;
std::get<0xEE>(m_instructions) = &instructions::NotImplemented;
std::get<0xEF>(m_instructions) = &instructions::NotImplemented;
std::get<0xF0>(m_instructions) = &instructions::NotImplemented;
std::get<0xF1>(m_instructions) = &instructions::NotImplemented;
std::get<0xF2>(m_instructions) = &instructions::NotImplemented;
std::get<0xF3>(m_instructions) = &instructions::NotImplemented;
std::get<0xF4>(m_instructions) = &instructions::NotImplemented;
std::get<0xF5>(m_instructions) = &instructions::NotImplemented;
std::get<0xF6>(m_instructions) = &instructions::NotImplemented;
std::get<0xF7>(m_instructions) = &instructions::NotImplemented;
std::get<0xF8>(m_instructions) = &instructions::NotImplemented;
std::get<0xF9>(m_instructions) = &instructions::NotImplemented;
std::get<0xFA>(m_instructions) = &instructions::NotImplemented;
std::get<0xFB>(m_instructions) = &instructions::NotImplemented;
std::get<0xFC>(m_instructions) = &instructions::NotImplemented;
std::get<0xFD>(m_instructions) = &instructions::NotImplemented;
std::get<0xFE>(m_instructions) = &instructions::NotImplemented;
std::get<0xFF>(m_instructions) = &instructions::NotImplemented;
} }
std::uint8_t Instructions::ExecuteInstruction(const std::uint8_t opcode, std::uint8_t Instructions::ExecuteInstruction(const std::uint8_t opcode,
@@ -77,6 +339,52 @@ std::uint8_t DecB(Processor &processor) {
return 4; return 4;
} }
std::uint8_t LdBU8(Processor &processor) {
processor.GetRegisters().SetB(processor.FetchByte());
return 4;
}
std::uint8_t RLCA(Processor &processor) {
auto value = processor.GetRegisters().GetA();
const auto carry = (value & 0x80) != 0;
value = static_cast<std::uint8_t>(value << 1);
value |= carry ? 1 : 0;
processor.GetRegisters().SetA(value);
processor.GetRegisters().SetFlag(Registers::Flags::Zero, false);
processor.GetRegisters().SetFlag(Registers::Flags::Subtract, false);
processor.GetRegisters().SetFlag(Registers::Flags::HalfCarry, false);
processor.GetRegisters().SetFlag(Registers::Flags::Carry, carry);
return 4;
}
std::uint8_t LdU16Sp(Processor &processor) {
const auto address = processor.FetchWord();
const auto value = processor.GetRegisters().GetStackPointer();
processor.GetMemory().WriteByte(address + 0, value & 0xFF);
processor.GetMemory().WriteByte(address + 1, value >> 8);
return 20;
}
std::uint8_t AddHlBc(Processor &processor) {
const auto hl = processor.GetRegisters().GetHL();
const auto bc = processor.GetRegisters().GetBC();
const auto result = static_cast<std::uint16_t>(hl + bc);
processor.GetRegisters().SetHL(result);
processor.GetRegisters().SetFlag(Registers::Flags::Subtract, false);
processor.GetRegisters().SetFlag(Registers::Flags::HalfCarry,
((hl & 0x0FFF) + (bc & 0x0FFF)) > 0x0FFF);
processor.GetRegisters().SetFlag(Registers::Flags::Carry, hl + bc > 0xFFFF);
return 8;
}
} // namespace instructions } // namespace instructions
} // namespace juiceboy } // namespace juiceboy
+6
View File
@@ -27,11 +27,14 @@ void Registers::IncrementProgramCounter(const std::uint16_t value) {
std::uint16_t Registers::GetStackPointer() const { return m_sp; } std::uint16_t Registers::GetStackPointer() const { return m_sp; }
void Registers::SetStackPointer(const std::uint16_t value) { m_sp = value; }
std::uint8_t Registers::GetA() const { return m_regA; } std::uint8_t Registers::GetA() const { return m_regA; }
std::uint8_t Registers::GetF() const { return m_regF; } std::uint8_t Registers::GetF() const { return m_regF; }
std::uint8_t Registers::GetB() const { return m_regB; } std::uint8_t Registers::GetB() const { return m_regB; }
std::uint16_t Registers::GetBC() const { return BytesToWord(m_regB, m_regC); } std::uint16_t Registers::GetBC() const { return BytesToWord(m_regB, m_regC); }
std::uint16_t Registers::GetHL() const { return BytesToWord(m_regH, m_regL); }
void Registers::SetA(const std::uint8_t value) { m_regA = value; } void Registers::SetA(const std::uint8_t value) { m_regA = value; }
void Registers::SetF(const std::uint8_t value) { m_regF = value; } void Registers::SetF(const std::uint8_t value) { m_regF = value; }
@@ -40,6 +43,9 @@ void Registers::SetB(const std::uint8_t value) { m_regB = value; }
void Registers::SetBC(const std::uint16_t value) { void Registers::SetBC(const std::uint16_t value) {
std::tie(m_regB, m_regC) = WordToBytes(value); std::tie(m_regB, m_regC) = WordToBytes(value);
} }
void Registers::SetHL(const std::uint16_t value) {
std::tie(m_regH, m_regL) = WordToBytes(value);
}
bool Registers::GetFlag(Flags flag) const { bool Registers::GetFlag(Flags flag) const {
return (m_regF & static_cast<std::uint8_t>(flag)) != 0; return (m_regF & static_cast<std::uint8_t>(flag)) != 0;
+103
View File
@@ -146,4 +146,107 @@ TEST_F(InstructionsTest, DecBPreservesCarry) {
EXPECT_TRUE(GetRegisters().GetFlag(Registers::Flags::Carry)); EXPECT_TRUE(GetRegisters().GetFlag(Registers::Flags::Carry));
} }
TEST_F(InstructionsTest, LdBU8) {
GetMemory().WriteByte(0x8000, 0x1);
GetRegisters().SetProgramCounter(0x8000);
const auto cycles = instructions::LdBU8(GetProcessor());
EXPECT_EQ(cycles, 4);
EXPECT_EQ(GetRegisters().GetB(), 0x1);
EXPECT_EQ(GetRegisters().GetProgramCounter(), 0x8001);
}
TEST_F(InstructionsTest, RCLA) {
GetRegisters().SetA(0b11110000);
const auto cycles = instructions::RLCA(GetProcessor());
EXPECT_EQ(cycles, 4);
EXPECT_EQ(GetRegisters().GetA(), 0b11100001);
EXPECT_EQ(GetRegisters().GetProgramCounter(), 0);
EXPECT_TRUE(GetRegisters().GetFlag(Registers::Flags::Carry));
}
TEST_F(InstructionsTest, RCLAClearsFlags) {
GetRegisters().SetA(0b01111111);
GetRegisters().SetFlag(Registers::Flags::Zero, true);
GetRegisters().SetFlag(Registers::Flags::Subtract, true);
GetRegisters().SetFlag(Registers::Flags::HalfCarry, true);
(void)instructions::RLCA(GetProcessor());
EXPECT_EQ(GetRegisters().GetA(), 0b11111110);
EXPECT_FALSE(GetRegisters().GetFlag(Registers::Flags::Carry));
EXPECT_FALSE(GetRegisters().GetFlag(Registers::Flags::Zero));
EXPECT_FALSE(GetRegisters().GetFlag(Registers::Flags::Subtract));
EXPECT_FALSE(GetRegisters().GetFlag(Registers::Flags::HalfCarry));
}
TEST_F(InstructionsTest, LdU16Sp) {
GetRegisters().SetStackPointer(0x1234);
GetRegisters().SetProgramCounter(0x8000);
GetMemory().WriteByte(0x8000, 0x02);
GetMemory().WriteByte(0x8001, 0x80);
const auto cycles = instructions::LdU16Sp(GetProcessor());
EXPECT_EQ(cycles, 20);
EXPECT_EQ(GetMemory().ReadByte(0x8002), 0x34);
EXPECT_EQ(GetMemory().ReadByte(0x8003), 0x12);
EXPECT_EQ(GetRegisters().GetProgramCounter(), 0x8002);
}
TEST_F(InstructionsTest, AddHlBc) {
GetRegisters().SetBC(0x1234);
GetRegisters().SetHL(0x4321);
const auto cycles = instructions::AddHlBc(GetProcessor());
EXPECT_EQ(cycles, 8);
EXPECT_EQ(GetRegisters().GetBC(), 0x1234);
EXPECT_EQ(GetRegisters().GetHL(), 0x5555);
EXPECT_FALSE(GetRegisters().GetFlag(Registers::Flags::Subtract));
EXPECT_FALSE(GetRegisters().GetFlag(Registers::Flags::Zero));
EXPECT_FALSE(GetRegisters().GetFlag(Registers::Flags::Carry));
EXPECT_FALSE(GetRegisters().GetFlag(Registers::Flags::HalfCarry));
EXPECT_EQ(GetRegisters().GetProgramCounter(), 0);
}
TEST_F(InstructionsTest, AddHlBcSetsCarryFlag) {
GetRegisters().SetBC(0xFFFF);
GetRegisters().SetHL(0x1);
(void)instructions::AddHlBc(GetProcessor());
EXPECT_EQ(GetRegisters().GetHL(), 0x0);
EXPECT_TRUE(GetRegisters().GetFlag(Registers::Flags::Carry));
}
TEST_F(InstructionsTest, AddHlBcSetsHalfCarryFlag) {
GetRegisters().SetBC(0x0FFF);
GetRegisters().SetHL(0x1);
(void)instructions::AddHlBc(GetProcessor());
EXPECT_EQ(GetRegisters().GetHL(), 0x1000);
EXPECT_TRUE(GetRegisters().GetFlag(Registers::Flags::HalfCarry));
}
TEST_F(InstructionsTest, AddHlBcClearsSubtractFlag) {
GetRegisters().SetFlag(Registers::Flags::Subtract, true);
(void)instructions::AddHlBc(GetProcessor());
EXPECT_FALSE(GetRegisters().GetFlag(Registers::Flags::Subtract));
}
TEST_F(InstructionsTest, AddHlBcPreservesZeroFlag) {
GetRegisters().SetFlag(Registers::Flags::Zero, true);
(void)instructions::AddHlBc(GetProcessor());
EXPECT_TRUE(GetRegisters().GetFlag(Registers::Flags::Zero));
}
} // namespace juiceboy::test } // namespace juiceboy::test