Added instructions: LdABc, DecBc, IncC, DecC, LdCU8
This commit is contained in:
@@ -32,6 +32,11 @@ std::uint8_t LdBU8(Processor &processor);
|
|||||||
std::uint8_t RLCA(Processor &processor);
|
std::uint8_t RLCA(Processor &processor);
|
||||||
std::uint8_t LdU16Sp(Processor &processor);
|
std::uint8_t LdU16Sp(Processor &processor);
|
||||||
std::uint8_t AddHlBc(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 instructions
|
||||||
|
|
||||||
} // namespace juiceboy
|
} // namespace juiceboy
|
||||||
@@ -34,6 +34,7 @@ public:
|
|||||||
[[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::uint8_t GetC() const;
|
||||||
|
|
||||||
[[nodiscard]] std::uint16_t GetBC() const;
|
[[nodiscard]] std::uint16_t GetBC() const;
|
||||||
[[nodiscard]] std::uint16_t GetHL() const;
|
[[nodiscard]] std::uint16_t GetHL() const;
|
||||||
@@ -41,6 +42,7 @@ public:
|
|||||||
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 SetC(std::uint8_t value);
|
||||||
|
|
||||||
void SetBC(std::uint16_t value);
|
void SetBC(std::uint16_t value);
|
||||||
void SetHL(std::uint16_t value);
|
void SetHL(std::uint16_t value);
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ Instructions::Instructions() {
|
|||||||
std::get<0x07>(m_instructions) = &instructions::RLCA;
|
std::get<0x07>(m_instructions) = &instructions::RLCA;
|
||||||
std::get<0x08>(m_instructions) = &instructions::LdU16Sp;
|
std::get<0x08>(m_instructions) = &instructions::LdU16Sp;
|
||||||
std::get<0x09>(m_instructions) = &instructions::AddHlBc;
|
std::get<0x09>(m_instructions) = &instructions::AddHlBc;
|
||||||
std::get<0x0A>(m_instructions) = &instructions::NotImplemented;
|
std::get<0x0A>(m_instructions) = &instructions::LdABc;
|
||||||
std::get<0x0B>(m_instructions) = &instructions::NotImplemented;
|
std::get<0x0B>(m_instructions) = &instructions::DecBc;
|
||||||
std::get<0x0C>(m_instructions) = &instructions::NotImplemented;
|
std::get<0x0C>(m_instructions) = &instructions::IncC;
|
||||||
std::get<0x0D>(m_instructions) = &instructions::NotImplemented;
|
std::get<0x0D>(m_instructions) = &instructions::DecC;
|
||||||
std::get<0x0E>(m_instructions) = &instructions::NotImplemented;
|
std::get<0x0E>(m_instructions) = &instructions::LdCU8;
|
||||||
std::get<0x0F>(m_instructions) = &instructions::NotImplemented;
|
std::get<0x0F>(m_instructions) = &instructions::NotImplemented;
|
||||||
|
|
||||||
std::get<0x10>(m_instructions) = &instructions::NotImplemented;
|
std::get<0x10>(m_instructions) = &instructions::NotImplemented;
|
||||||
@@ -385,6 +385,51 @@ std::uint8_t AddHlBc(Processor &processor) {
|
|||||||
return 8;
|
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 instructions
|
||||||
|
|
||||||
} // namespace juiceboy
|
} // namespace juiceboy
|
||||||
@@ -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::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::uint8_t Registers::GetC() const { return m_regC; }
|
||||||
|
|
||||||
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); }
|
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::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; }
|
||||||
void Registers::SetB(const std::uint8_t value) { m_regB = 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) {
|
void Registers::SetBC(const std::uint16_t value) {
|
||||||
std::tie(m_regB, m_regC) = WordToBytes(value);
|
std::tie(m_regB, m_regC) = WordToBytes(value);
|
||||||
|
|||||||
@@ -249,4 +249,114 @@ TEST_F(InstructionsTest, AddHlBcPreservesZeroFlag) {
|
|||||||
EXPECT_TRUE(GetRegisters().GetFlag(Registers::Flags::Zero));
|
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
|
} // namespace juiceboy::test
|
||||||
Reference in New Issue
Block a user