Added instructions: LdABc, DecBc, IncC, DecC, LdCU8

This commit is contained in:
2026-09-20 22:12:38 +02:00
parent d0f6bb4e76
commit 90de24a6ba
5 changed files with 169 additions and 5 deletions
@@ -32,6 +32,11 @@ std::uint8_t LdBU8(Processor &processor);
std::uint8_t RLCA(Processor &processor);
std::uint8_t LdU16Sp(Processor &processor);
std::uint8_t AddHlBc(Processor &processor);
std::uint8_t LdABc(Processor &processor);
std::uint8_t DecBc(Processor &processor);
std::uint8_t IncC(Processor &processor);
std::uint8_t DecC(Processor &processor);
std::uint8_t LdCU8(Processor &processor);
} // namespace instructions
} // namespace juiceboy
+2
View File
@@ -34,6 +34,7 @@ public:
[[nodiscard]] std::uint8_t GetA() const;
[[nodiscard]] std::uint8_t GetF() const;
[[nodiscard]] std::uint8_t GetB() const;
[[nodiscard]] std::uint8_t GetC() const;
[[nodiscard]] std::uint16_t GetBC() const;
[[nodiscard]] std::uint16_t GetHL() const;
@@ -41,6 +42,7 @@ public:
void SetA(std::uint8_t value);
void SetF(std::uint8_t value);
void SetB(std::uint8_t value);
void SetC(std::uint8_t value);
void SetBC(std::uint16_t value);
void SetHL(std::uint16_t value);
+50 -5
View File
@@ -18,11 +18,11 @@ Instructions::Instructions() {
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<0x0A>(m_instructions) = &instructions::LdABc;
std::get<0x0B>(m_instructions) = &instructions::DecBc;
std::get<0x0C>(m_instructions) = &instructions::IncC;
std::get<0x0D>(m_instructions) = &instructions::DecC;
std::get<0x0E>(m_instructions) = &instructions::LdCU8;
std::get<0x0F>(m_instructions) = &instructions::NotImplemented;
std::get<0x10>(m_instructions) = &instructions::NotImplemented;
@@ -385,6 +385,51 @@ std::uint8_t AddHlBc(Processor &processor) {
return 8;
}
std::uint8_t LdABc(Processor &processor) {
const auto address = processor.GetRegisters().GetBC();
const auto value = processor.GetMemory().ReadByte(address);
processor.GetRegisters().SetA(value);
return 8;
}
std::uint8_t DecBc(Processor &processor) {
processor.GetRegisters().SetBC(processor.GetRegisters().GetBC() - 1);
return 8;
}
std::uint8_t IncC(Processor &processor) {
const auto value = processor.GetRegisters().GetC();
const std::uint8_t result = value + 1;
processor.GetRegisters().SetC(result);
processor.GetRegisters().SetFlag(Registers::Flags::Zero, result == 0);
processor.GetRegisters().SetFlag(Registers::Flags::Subtract, false);
processor.GetRegisters().SetFlag(Registers::Flags::HalfCarry,
(value & 0x0F) == 0x0F);
return 4;
}
std::uint8_t DecC(Processor &processor) {
const auto value = processor.GetRegisters().GetC();
const std::uint8_t result = value - 1;
processor.GetRegisters().SetC(result);
processor.GetRegisters().SetFlag(Registers::Flags::Zero, result == 0);
processor.GetRegisters().SetFlag(Registers::Flags::Subtract, true);
processor.GetRegisters().SetFlag(Registers::Flags::HalfCarry,
(value & 0x0F) == 0x0);
return 4;
}
std::uint8_t LdCU8(Processor &processor) {
processor.GetRegisters().SetC(processor.FetchByte());
return 8;
}
} // namespace instructions
} // namespace juiceboy
+2
View File
@@ -32,6 +32,7 @@ void Registers::SetStackPointer(const std::uint16_t value) { m_sp = value; }
std::uint8_t Registers::GetA() const { return m_regA; }
std::uint8_t Registers::GetF() const { return m_regF; }
std::uint8_t Registers::GetB() const { return m_regB; }
std::uint8_t Registers::GetC() const { return 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); }
@@ -39,6 +40,7 @@ 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::SetF(const std::uint8_t value) { m_regF = value; }
void Registers::SetB(const std::uint8_t value) { m_regB = value; }
void Registers::SetC(const std::uint8_t value) { m_regC = value; }
void Registers::SetBC(const std::uint16_t value) {
std::tie(m_regB, m_regC) = WordToBytes(value);
+110
View File
@@ -249,4 +249,114 @@ TEST_F(InstructionsTest, AddHlBcPreservesZeroFlag) {
EXPECT_TRUE(GetRegisters().GetFlag(Registers::Flags::Zero));
}
TEST_F(InstructionsTest, LdABc) {
GetMemory().WriteByte(0x8000, 0x12);
GetRegisters().SetBC(0x8000);
const auto cycles = instructions::LdABc(GetProcessor());
EXPECT_EQ(cycles, 8);
EXPECT_EQ(GetRegisters().GetA(), 0x12);
EXPECT_EQ(GetRegisters().GetProgramCounter(), 0);
}
TEST_F(InstructionsTest, DecBC) {
GetRegisters().SetBC(0x2);
const auto cycles = instructions::DecBc(GetProcessor());
EXPECT_EQ(cycles, 8);
EXPECT_EQ(GetRegisters().GetBC(), 0x1);
EXPECT_EQ(GetRegisters().GetProgramCounter(), 0);
}
TEST_F(InstructionsTest, IncC) {
GetRegisters().SetC(0x1);
const auto cycles = instructions::IncC(GetProcessor());
EXPECT_EQ(cycles, 4);
EXPECT_EQ(GetRegisters().GetC(), 0x2);
EXPECT_EQ(GetRegisters().GetProgramCounter(), 0);
EXPECT_FALSE(GetRegisters().GetFlag(Registers::Flags::Zero));
EXPECT_FALSE(GetRegisters().GetFlag(Registers::Flags::Subtract));
EXPECT_FALSE(GetRegisters().GetFlag(Registers::Flags::HalfCarry));
}
TEST_F(InstructionsTest, IncCSetsZeroFlag) {
GetRegisters().SetC(0xFF);
(void)instructions::IncC(GetProcessor());
EXPECT_EQ(GetRegisters().GetC(), 0x00);
EXPECT_TRUE(GetRegisters().GetFlag(Registers::Flags::Zero));
}
TEST_F(InstructionsTest, IncCSetsHalfCarryFlag) {
GetRegisters().SetC(0x0F);
(void)instructions::IncC(GetProcessor());
EXPECT_EQ(GetRegisters().GetC(), 0x10);
EXPECT_TRUE(GetRegisters().GetFlag(Registers::Flags::HalfCarry));
}
TEST_F(InstructionsTest, IncCPreservesCarry) {
GetRegisters().SetFlag(Registers::Flags::Carry, true);
(void)instructions::IncC(GetProcessor());
EXPECT_TRUE(GetRegisters().GetFlag(Registers::Flags::Carry));
}
TEST_F(InstructionsTest, DecC) {
GetRegisters().SetC(0x2);
const auto cycles = instructions::DecC(GetProcessor());
EXPECT_EQ(cycles, 4);
EXPECT_EQ(GetRegisters().GetC(), 0x1);
EXPECT_EQ(GetRegisters().GetProgramCounter(), 0);
EXPECT_FALSE(GetRegisters().GetFlag(Registers::Flags::Zero));
EXPECT_TRUE(GetRegisters().GetFlag(Registers::Flags::Subtract));
EXPECT_FALSE(GetRegisters().GetFlag(Registers::Flags::HalfCarry));
}
TEST_F(InstructionsTest, DecCSetsZeroFlag) {
GetRegisters().SetC(0x1);
(void)instructions::DecC(GetProcessor());
EXPECT_EQ(GetRegisters().GetC(), 0x00);
EXPECT_TRUE(GetRegisters().GetFlag(Registers::Flags::Zero));
}
TEST_F(InstructionsTest, DecCSetsHalfCarryFlag) {
GetRegisters().SetC(0x10);
(void)instructions::DecC(GetProcessor());
EXPECT_EQ(GetRegisters().GetC(), 0x0F);
EXPECT_TRUE(GetRegisters().GetFlag(Registers::Flags::HalfCarry));
}
TEST_F(InstructionsTest, DecCPreservesCarry) {
GetRegisters().SetFlag(Registers::Flags::Carry, true);
(void)instructions::IncC(GetProcessor());
EXPECT_TRUE(GetRegisters().GetFlag(Registers::Flags::Carry));
}
TEST_F(InstructionsTest, LdCU8) {
GetMemory().WriteByte(0x8000, 0x12);
GetRegisters().SetProgramCounter(0x8000);
const auto cycles = instructions::LdCU8(GetProcessor());
EXPECT_EQ(cycles, 8);
EXPECT_EQ(GetRegisters().GetC(), 0x12);
EXPECT_EQ(GetRegisters().GetProgramCounter(), 0x8001);
}
} // namespace juiceboy::test