Adding branch instructions

This commit is contained in:
AnonymusRaccoon
2020-02-28 19:20:59 +01:00
parent 68b82c9cda
commit d1561f1be3
6 changed files with 417 additions and 2 deletions

View File

@@ -359,6 +359,17 @@ namespace ComSquare::CPU
case Instructions::CPY_ABS: this->CPY(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; case Instructions::CPY_ABS: this->CPY(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m;
case Instructions::CPY_DP: this->CPY(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; case Instructions::CPY_DP: this->CPY(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0;
case Instructions::BCC: return this->BCC(this->_registers.pc++) + 2 + this->_isEmulationMode;
case Instructions::BCS: return this->BCS(this->_registers.pc++) + 2 + this->_isEmulationMode;
case Instructions::BEQ: return this->BEQ(this->_registers.pc++) + 2 + this->_isEmulationMode;
case Instructions::BNE: return this->BNE(this->_registers.pc++) + 2 + this->_isEmulationMode;
case Instructions::BMI: return this->BMI(this->_registers.pc++) + 2 + this->_isEmulationMode;
case Instructions::BPL: return this->BPL(this->_registers.pc++) + 2 + this->_isEmulationMode;
case Instructions::BVC: return this->BVC(this->_registers.pc++) + 2 + this->_isEmulationMode;
case Instructions::BVS: return this->BVS(this->_registers.pc++) + 2 + this->_isEmulationMode;
case Instructions::BRA: this->BRA(this->_registers.pc++); return 3 + this->_isEmulationMode;
case Instructions::BRL: this->BRL(this->_registers.pc); this->_registers.pc += 2; return 4;
default: default:
throw InvalidOpcode("CPU", opcode); throw InvalidOpcode("CPU", opcode);
} }

View File

@@ -341,7 +341,18 @@ namespace ComSquare::CPU
CPY_IM = 0xC0, CPY_IM = 0xC0,
CPY_ABS = 0xCC, CPY_ABS = 0xCC,
CPY_DP = 0xC4 CPY_DP = 0xC4,
BCC = 0x90,
BCS = 0xB0,
BEQ = 0xF0,
BNE = 0xD0,
BMI = 0x30,
BPL = 0x10,
BVC = 0x50,
BVS = 0x70,
BRA = 0x80,
BRL = 0x82
}; };
//! @brief The main CPU //! @brief The main CPU
@@ -509,6 +520,26 @@ namespace ComSquare::CPU
void CPX(uint24_t valueAddr); void CPX(uint24_t valueAddr);
//! @brief Compare the Y register with the memory //! @brief Compare the Y register with the memory
void CPY(uint24_t valueAddr); void CPY(uint24_t valueAddr);
//! @brief Branch if carry clear
bool BCC(uint24_t valueAddr);
//! @brief Branch if carry set
bool BCS(uint24_t valueAddr);
//! @brief Branch if equal
bool BEQ(uint24_t valueAddr);
//! @brief Branch if not equal
bool BNE(uint24_t valueAddr);
//! @brief Branch if minus
bool BMI(uint24_t valueAddr);
//! @brief Branch if plus
bool BPL(uint24_t valueAddr);
//! @brief Branch if Overflow Clear
bool BVC(uint24_t valueAddr);
//! @brief Branch if Overflow Set
bool BVS(uint24_t valueAddr);
//! @brief Branch always
bool BRA(uint24_t valueAddr);
//! @brief Branch always long
bool BRL(uint24_t valueAddr);
public: public:
explicit CPU(std::shared_ptr<Memory::MemoryBus> bus, Cartridge::Header &cartridgeHeader); explicit CPU(std::shared_ptr<Memory::MemoryBus> bus, Cartridge::Header &cartridgeHeader);
CPU(const CPU &) = default; CPU(const CPU &) = default;

View File

@@ -226,4 +226,75 @@ namespace ComSquare::CPU
this->_registers.p.n = y & 0x8000u; this->_registers.p.n = y & 0x8000u;
} }
} }
bool CPU::BCC(uint24_t valueAddr)
{
if (!this->_registers.p.c)
this->_registers.pac += static_cast<int8_t>(this->_bus->read(valueAddr));
return !this->_registers.p.c;
}
bool CPU::BCS(uint24_t valueAddr)
{
if (this->_registers.p.c)
this->_registers.pac += static_cast<int8_t>(this->_bus->read(valueAddr));
return this->_registers.p.c;
}
bool CPU::BEQ(uint24_t valueAddr)
{
if (this->_registers.p.z)
this->_registers.pac += static_cast<int8_t>(this->_bus->read(valueAddr));
return this->_registers.p.z;
}
bool CPU::BNE(uint24_t valueAddr)
{
if (!this->_registers.p.z)
this->_registers.pac += static_cast<int8_t>(this->_bus->read(valueAddr));
return !this->_registers.p.z;
}
bool CPU::BMI(uint24_t valueAddr)
{
if (this->_registers.p.n)
this->_registers.pac += static_cast<int8_t>(this->_bus->read(valueAddr));
return this->_registers.p.n;
}
bool CPU::BPL(uint24_t valueAddr)
{
if (!this->_registers.p.n)
this->_registers.pac += static_cast<int8_t>(this->_bus->read(valueAddr));
return !this->_registers.p.n;
}
bool CPU::BRA(uint24_t valueAddr)
{
this->_registers.pac += static_cast<int8_t>(this->_bus->read(valueAddr));
return true;
}
bool CPU::BRL(uint24_t valueAddr)
{
unsigned value = this->_bus->read(valueAddr);
value += this->_bus->read(valueAddr + 1) << 8u;
this->_registers.pac += static_cast<int16_t>(value);
return true;
}
bool CPU::BVC(uint24_t valueAddr)
{
if (!this->_registers.p.v)
this->_registers.pac += static_cast<int8_t>(this->_bus->read(valueAddr));
return !this->_registers.p.v;
}
bool CPU::BVS(uint24_t valueAddr)
{
if (this->_registers.p.v)
this->_registers.pac += static_cast<int8_t>(this->_bus->read(valueAddr));
return this->_registers.p.v;
}
} }

View File

@@ -146,6 +146,16 @@ namespace ComSquare::Debugger
return ss.str(); return ss.str();
} }
std::string CPUDebug::_getImmediateValue16Bits(uint24_t pc)
{
unsigned value = this->_bus->read(pc);
value += this->_bus->read(pc + 1) << 8u;
std::stringstream ss;
ss << "#$" << std::hex << value;
return ss.str();
}
std::string CPUDebug::_getDirectValue(uint24_t pc) std::string CPUDebug::_getDirectValue(uint24_t pc)
{ {
std::stringstream ss; std::stringstream ss;
@@ -345,6 +355,17 @@ namespace ComSquare::Debugger
case Instructions::CPY_ABS: return "CPY " + this->_getAbsoluteValue(pc); case Instructions::CPY_ABS: return "CPY " + this->_getAbsoluteValue(pc);
case Instructions::CPY_DP: return "CPY"; case Instructions::CPY_DP: return "CPY";
case Instructions::BCC: return "BCC " + this->_getImmediateValue8Bits(pc);
case Instructions::BCS: return "BCS " + this->_getImmediateValue8Bits(pc);
case Instructions::BEQ: return "BEQ " + this->_getImmediateValue8Bits(pc);
case Instructions::BNE: return "BNE " + this->_getImmediateValue8Bits(pc);
case Instructions::BMI: return "BMI " + this->_getImmediateValue8Bits(pc);
case Instructions::BPL: return "BPL " + this->_getImmediateValue8Bits(pc);
case Instructions::BVC: return "BVC " + this->_getImmediateValue8Bits(pc);
case Instructions::BVS: return "BVS " + this->_getImmediateValue8Bits(pc);
case Instructions::BRA: return "BRA " + this->_getImmediateValue8Bits(pc);
case Instructions::BRL: return "BRL " + this->_getImmediateValue16Bits(pc);
default: return "Unknown"; default: return "Unknown";
} }
} }

View File

@@ -38,6 +38,8 @@ namespace ComSquare::Debugger
std::string _getImmediateValueForX(uint24_t pc); std::string _getImmediateValueForX(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a 8bits immediate addressing mode (used only with SEP and REP). //! @brief Return a printable string corresponding to the value of a 8bits immediate addressing mode (used only with SEP and REP).
std::string _getImmediateValue8Bits(uint24_t pc); std::string _getImmediateValue8Bits(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a 16bits immediate addressing mode.
std::string _getImmediateValue16Bits(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a direct addressing mode. //! @brief Return a printable string corresponding to the value of a direct addressing mode.
std::string _getDirectValue(uint24_t pc); std::string _getDirectValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of an absolute addressing mode. //! @brief Return a printable string corresponding to the value of an absolute addressing mode.

View File

@@ -605,3 +605,282 @@ Test(CPY, negative)
cr_assert_eq(pair.second.cpu->_registers.p.n, true, "The negative flag should be set"); cr_assert_eq(pair.second.cpu->_registers.p.n, true, "The negative flag should be set");
cr_assert_eq(pair.second.cpu->_registers.p.c, false, "The carry flag should not be set"); cr_assert_eq(pair.second.cpu->_registers.p.c, false, "The carry flag should not be set");
} }
Test(BCC, basic)
{
auto pair = Init();
pair.second.cpu->_registers.p.c = false;
pair.second.cpu->_registers.pc = 0x80;
pair.second.wram->_data[0] = 0x50;
pair.second.cpu->BCC(0x0);
cr_assert_eq(pair.second.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", pair.second.cpu->_registers.pc);
}
Test(BCC, negativeJump)
{
auto pair = Init();
pair.second.cpu->_registers.p.c = false;
pair.second.cpu->_registers.pc = 0x80;
pair.second.wram->_data[0] = 0xF0;
pair.second.cpu->BCC(0x0);
cr_assert_eq(pair.second.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", pair.second.cpu->_registers.pc);
}
Test(BCC, noJump)
{
auto pair = Init();
pair.second.cpu->_registers.p.c = true;
pair.second.cpu->_registers.pc = 0x80;
pair.second.wram->_data[0] = 0x90;
pair.second.cpu->BCC(0x0);
cr_assert_eq(pair.second.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", pair.second.cpu->_registers.pc);
}
Test(BCS, basic)
{
auto pair = Init();
pair.second.cpu->_registers.p.c = true;
pair.second.cpu->_registers.pc = 0x80;
pair.second.wram->_data[0] = 0x50;
pair.second.cpu->BCS(0x0);
cr_assert_eq(pair.second.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", pair.second.cpu->_registers.pc);
}
Test(BCS, negativeJump)
{
auto pair = Init();
pair.second.cpu->_registers.p.c = true;
pair.second.cpu->_registers.pc = 0x80;
pair.second.wram->_data[0] = 0xF0;
pair.second.cpu->BCS(0x0);
cr_assert_eq(pair.second.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", pair.second.cpu->_registers.pc);
}
Test(BCS, noJump)
{
auto pair = Init();
pair.second.cpu->_registers.p.c = false;
pair.second.cpu->_registers.pc = 0x80;
pair.second.wram->_data[0] = 0x90;
pair.second.cpu->BCS(0x0);
cr_assert_eq(pair.second.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", pair.second.cpu->_registers.pc);
}
Test(BEQ, basic)
{
auto pair = Init();
pair.second.cpu->_registers.p.z = true;
pair.second.cpu->_registers.pc = 0x80;
pair.second.wram->_data[0] = 0x50;
pair.second.cpu->BEQ(0x0);
cr_assert_eq(pair.second.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", pair.second.cpu->_registers.pc);
}
Test(BEQ, negativeJump)
{
auto pair = Init();
pair.second.cpu->_registers.p.z = true;
pair.second.cpu->_registers.pc = 0x80;
pair.second.wram->_data[0] = 0xF0;
pair.second.cpu->BEQ(0x0);
cr_assert_eq(pair.second.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", pair.second.cpu->_registers.pc);
}
Test(BEQ, noJump)
{
auto pair = Init();
pair.second.cpu->_registers.p.z = false;
pair.second.cpu->_registers.pc = 0x80;
pair.second.wram->_data[0] = 0x90;
pair.second.cpu->BEQ(0x0);
cr_assert_eq(pair.second.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", pair.second.cpu->_registers.pc);
}
Test(BNE, basic)
{
auto pair = Init();
pair.second.cpu->_registers.p.z = false;
pair.second.cpu->_registers.pc = 0x80;
pair.second.wram->_data[0] = 0x50;
pair.second.cpu->BNE(0x0);
cr_assert_eq(pair.second.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", pair.second.cpu->_registers.pc);
}
Test(BNE, negativeJump)
{
auto pair = Init();
pair.second.cpu->_registers.p.z = false;
pair.second.cpu->_registers.pc = 0x80;
pair.second.wram->_data[0] = 0xF0;
pair.second.cpu->BNE(0x0);
cr_assert_eq(pair.second.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", pair.second.cpu->_registers.pc);
}
Test(BNE, noJump)
{
auto pair = Init();
pair.second.cpu->_registers.p.z = true;
pair.second.cpu->_registers.pc = 0x80;
pair.second.wram->_data[0] = 0x90;
pair.second.cpu->BNE(0x0);
cr_assert_eq(pair.second.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", pair.second.cpu->_registers.pc);
}
Test(BMI, basic)
{
auto pair = Init();
pair.second.cpu->_registers.p.n = true;
pair.second.cpu->_registers.pc = 0x80;
pair.second.wram->_data[0] = 0x50;
pair.second.cpu->BMI(0x0);
cr_assert_eq(pair.second.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", pair.second.cpu->_registers.pc);
}
Test(BMI, negativeJump)
{
auto pair = Init();
pair.second.cpu->_registers.p.n = true;
pair.second.cpu->_registers.pc = 0x80;
pair.second.wram->_data[0] = 0xF0;
pair.second.cpu->BMI(0x0);
cr_assert_eq(pair.second.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", pair.second.cpu->_registers.pc);
}
Test(BMI, noJump)
{
auto pair = Init();
pair.second.cpu->_registers.p.n = false;
pair.second.cpu->_registers.pc = 0x80;
pair.second.wram->_data[0] = 0x90;
pair.second.cpu->BMI(0x0);
cr_assert_eq(pair.second.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", pair.second.cpu->_registers.pc);
}
Test(BPL, basic)
{
auto pair = Init();
pair.second.cpu->_registers.p.n = false;
pair.second.cpu->_registers.pc = 0x80;
pair.second.wram->_data[0] = 0x50;
pair.second.cpu->BPL(0x0);
cr_assert_eq(pair.second.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", pair.second.cpu->_registers.pc);
}
Test(BPL, negativeJump)
{
auto pair = Init();
pair.second.cpu->_registers.p.n = false;
pair.second.cpu->_registers.pc = 0x80;
pair.second.wram->_data[0] = 0xF0;
pair.second.cpu->BPL(0x0);
cr_assert_eq(pair.second.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", pair.second.cpu->_registers.pc);
}
Test(BPL, noJump)
{
auto pair = Init();
pair.second.cpu->_registers.p.n = true;
pair.second.cpu->_registers.pc = 0x80;
pair.second.wram->_data[0] = 0x90;
pair.second.cpu->BPL(0x0);
cr_assert_eq(pair.second.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", pair.second.cpu->_registers.pc);
}
Test(BRA, basic)
{
auto pair = Init();
pair.second.cpu->_registers.pc = 0x80;
pair.second.wram->_data[0] = 0x50;
pair.second.cpu->BRA(0x0);
cr_assert_eq(pair.second.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", pair.second.cpu->_registers.pc);
}
Test(BRA, negativeJump)
{
auto pair = Init();
pair.second.cpu->_registers.pc = 0x80;
pair.second.wram->_data[0] = 0xF0;
pair.second.cpu->BRA(0x0);
cr_assert_eq(pair.second.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", pair.second.cpu->_registers.pc);
}
Test(BRL, basic)
{
auto pair = Init();
pair.second.cpu->_registers.pc = 0x8080;
pair.second.wram->_data[0] = 0x00;
pair.second.wram->_data[1] = 0x10;
pair.second.cpu->BRL(0x0);
cr_assert_eq(pair.second.cpu->_registers.pc, 0x9080, "The program counter should be equal to 0x9080 but it was 0x%x.", pair.second.cpu->_registers.pc);
}
Test(BRL, negativeJump)
{
auto pair = Init();
pair.second.cpu->_registers.pc = 0x8080;
pair.second.wram->_data[0] = 0x00;
pair.second.wram->_data[1] = 0xF0;
pair.second.cpu->BRL(0x0);
cr_assert_eq(pair.second.cpu->_registers.pc, 0x7080, "The program counter should be equal to 0x7080 but it was 0x%x.", pair.second.cpu->_registers.pc);
}
Test(BVC, basic)
{
auto pair = Init();
pair.second.cpu->_registers.p.v = false;
pair.second.cpu->_registers.pc = 0x80;
pair.second.wram->_data[0] = 0x50;
pair.second.cpu->BVC(0x0);
cr_assert_eq(pair.second.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", pair.second.cpu->_registers.pc);
}
Test(BVC, negativeJump)
{
auto pair = Init();
pair.second.cpu->_registers.p.v = false;
pair.second.cpu->_registers.pc = 0x80;
pair.second.wram->_data[0] = 0xF0;
pair.second.cpu->BVC(0x0);
cr_assert_eq(pair.second.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", pair.second.cpu->_registers.pc);
}
Test(BVC, noJump)
{
auto pair = Init();
pair.second.cpu->_registers.p.v = true;
pair.second.cpu->_registers.pc = 0x80;
pair.second.wram->_data[0] = 0x90;
pair.second.cpu->BVC(0x0);
cr_assert_eq(pair.second.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", pair.second.cpu->_registers.pc);
}
Test(BVS, basic)
{
auto pair = Init();
pair.second.cpu->_registers.p.v = true;
pair.second.cpu->_registers.pc = 0x80;
pair.second.wram->_data[0] = 0x50;
pair.second.cpu->BVS(0x0);
cr_assert_eq(pair.second.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", pair.second.cpu->_registers.pc);
}
Test(BVS, negativeJump)
{
auto pair = Init();
pair.second.cpu->_registers.p.v = true;
pair.second.cpu->_registers.pc = 0x80;
pair.second.wram->_data[0] = 0xF0;
pair.second.cpu->BVS(0x0);
cr_assert_eq(pair.second.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", pair.second.cpu->_registers.pc);
}
Test(BVS, noJump)
{
auto pair = Init();
pair.second.cpu->_registers.p.v = false;
pair.second.cpu->_registers.pc = 0x80;
pair.second.wram->_data[0] = 0x90;
pair.second.cpu->BVS(0x0);
cr_assert_eq(pair.second.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", pair.second.cpu->_registers.pc);
}