Branch opcodes
This commit is contained in:
parent
248be24ef8
commit
f407339fc3
|
@ -4,4 +4,8 @@ namespace emu_6502 {
|
||||||
void ProgramCounter::inc() {
|
void ProgramCounter::inc() {
|
||||||
value += 1;
|
value += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProgramCounter::add(int8_t offset) {
|
||||||
|
value += offset;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -12,6 +12,7 @@ namespace emu_6502 {
|
||||||
ProgramCounter& operator=(const ProgramCounter&) = delete;
|
ProgramCounter& operator=(const ProgramCounter&) = delete;
|
||||||
|
|
||||||
void inc();
|
void inc();
|
||||||
|
void add(int8_t offset);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
#include "branch-opcode-handler-container.h"
|
||||||
|
|
||||||
|
namespace emu_6502 {
|
||||||
|
BranchOpcodeHandlerContainer::BranchOpcodeHandlerContainer() {
|
||||||
|
handlers.insert({Op::BCS, [this](Machine& machine) { bcs(machine); }});
|
||||||
|
handlers.insert({Op::BCC, [this](Machine& machine) { bcc(machine); }});
|
||||||
|
|
||||||
|
handlers.insert({Op::BEQ, [this](Machine& machine) { beq(machine); }});
|
||||||
|
handlers.insert({Op::BNE, [this](Machine& machine) { bne(machine); }});
|
||||||
|
|
||||||
|
handlers.insert({Op::BPL, [this](Machine& machine) { bpl(machine); }});
|
||||||
|
handlers.insert({Op::BMI, [this](Machine& machine) { bmi(machine); }});
|
||||||
|
|
||||||
|
handlers.insert({Op::BVS, [this](Machine& machine) { bvs(machine); }});
|
||||||
|
handlers.insert({Op::BVC, [this](Machine& machine) { bvc(machine); }});
|
||||||
|
}
|
||||||
|
|
||||||
|
void BranchOpcodeHandlerContainer::bcs(Machine& machine) {
|
||||||
|
auto jump = machine.read_program_byte();
|
||||||
|
if (machine.get_cpu().get_ps().is_carry_set())
|
||||||
|
machine.get_cpu().get_pc().add(jump);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BranchOpcodeHandlerContainer::bcc(Machine& machine) {
|
||||||
|
auto jump = machine.read_program_byte();
|
||||||
|
if (!machine.get_cpu().get_ps().is_carry_set())
|
||||||
|
machine.get_cpu().get_pc().add(jump);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BranchOpcodeHandlerContainer::beq(Machine& machine) {
|
||||||
|
auto jump = machine.read_program_byte();
|
||||||
|
if (machine.get_cpu().get_ps().is_zero_set())
|
||||||
|
machine.get_cpu().get_pc().add(jump);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BranchOpcodeHandlerContainer::bne(Machine& machine) {
|
||||||
|
auto jump = machine.read_program_byte();
|
||||||
|
if (!machine.get_cpu().get_ps().is_zero_set())
|
||||||
|
machine.get_cpu().get_pc().add(jump);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BranchOpcodeHandlerContainer::bpl(Machine& machine) {
|
||||||
|
auto jump = machine.read_program_byte();
|
||||||
|
if (!machine.get_cpu().get_ps().is_negative_set())
|
||||||
|
machine.get_cpu().get_pc().add(jump);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BranchOpcodeHandlerContainer::bmi(Machine& machine) {
|
||||||
|
auto jump = machine.read_program_byte();
|
||||||
|
if (machine.get_cpu().get_ps().is_negative_set())
|
||||||
|
machine.get_cpu().get_pc().add(jump);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BranchOpcodeHandlerContainer::bvs(Machine& machine) {
|
||||||
|
auto jump = machine.read_program_byte();
|
||||||
|
if (machine.get_cpu().get_ps().is_overflow_set())
|
||||||
|
machine.get_cpu().get_pc().add(jump);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BranchOpcodeHandlerContainer::bvc(Machine& machine) {
|
||||||
|
auto jump = machine.read_program_byte();
|
||||||
|
if (!machine.get_cpu().get_ps().is_overflow_set())
|
||||||
|
machine.get_cpu().get_pc().add(jump);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
#ifndef INC_6502_EMULATOR_BRANCH_OPCODE_HANDLER_CONTAINER_H
|
||||||
|
#define INC_6502_EMULATOR_BRANCH_OPCODE_HANDLER_CONTAINER_H
|
||||||
|
|
||||||
|
#include "opcode-handler-container.h"
|
||||||
|
|
||||||
|
namespace emu_6502 {
|
||||||
|
class BranchOpcodeHandlerContainer : public OpcodeHandlerContainer {
|
||||||
|
private:
|
||||||
|
enum Op {
|
||||||
|
BCS = 0xB0,
|
||||||
|
BCC = 0x90,
|
||||||
|
|
||||||
|
BEQ = 0xF0,
|
||||||
|
BNE = 0xD0,
|
||||||
|
|
||||||
|
BPL = 0x10,
|
||||||
|
BMI = 0x30,
|
||||||
|
|
||||||
|
BVS = 0x70,
|
||||||
|
BVC = 0x50
|
||||||
|
};
|
||||||
|
|
||||||
|
void bcs(Machine& machine);
|
||||||
|
void bcc(Machine& machine);
|
||||||
|
|
||||||
|
void beq(Machine& machine);
|
||||||
|
void bne(Machine& machine);
|
||||||
|
|
||||||
|
void bpl(Machine& machine);
|
||||||
|
void bmi(Machine& machine);
|
||||||
|
|
||||||
|
void bvs(Machine& machine);
|
||||||
|
void bvc(Machine& machine);
|
||||||
|
|
||||||
|
public:
|
||||||
|
BranchOpcodeHandlerContainer();
|
||||||
|
BranchOpcodeHandlerContainer(const BranchOpcodeHandlerContainer&) = delete;
|
||||||
|
BranchOpcodeHandlerContainer& operator=(BranchOpcodeHandlerContainer&) = delete;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //INC_6502_EMULATOR_BRANCH_OPCODE_HANDLER_CONTAINER_H
|
|
@ -7,6 +7,7 @@
|
||||||
#include "handler/status-opcode-handler-container.h"
|
#include "handler/status-opcode-handler-container.h"
|
||||||
#include "handler/compare-opcode-handler-container.h"
|
#include "handler/compare-opcode-handler-container.h"
|
||||||
#include "handler/stack-opcode-handler-container.h"
|
#include "handler/stack-opcode-handler-container.h"
|
||||||
|
#include "handler/branch-opcode-handler-container.h"
|
||||||
#include "../utils.h"
|
#include "../utils.h"
|
||||||
|
|
||||||
namespace emu_6502 {
|
namespace emu_6502 {
|
||||||
|
@ -20,6 +21,7 @@ namespace emu_6502 {
|
||||||
handler_containers.push_back(make_unique<StatusOpcodeHandlerContainer>());
|
handler_containers.push_back(make_unique<StatusOpcodeHandlerContainer>());
|
||||||
handler_containers.push_back(make_unique<CompareOpcodeHandlerContainer>());
|
handler_containers.push_back(make_unique<CompareOpcodeHandlerContainer>());
|
||||||
handler_containers.push_back(make_unique<StackOpcodeHandlerContainer>());
|
handler_containers.push_back(make_unique<StackOpcodeHandlerContainer>());
|
||||||
|
handler_containers.push_back(make_unique<BranchOpcodeHandlerContainer>());
|
||||||
|
|
||||||
init_handlers();
|
init_handlers();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,273 @@
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "test-utils.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace emu_6502;
|
||||||
|
|
||||||
|
const uint8_t BCS = 0xB0;
|
||||||
|
const uint8_t BCC = 0x90;
|
||||||
|
|
||||||
|
const uint8_t BEQ = 0xF0;
|
||||||
|
const uint8_t BNE = 0xD0;
|
||||||
|
|
||||||
|
const uint8_t BPL = 0x10;
|
||||||
|
const uint8_t BMI = 0x30;
|
||||||
|
|
||||||
|
const uint8_t BVS = 0x70;
|
||||||
|
const uint8_t BVC = 0x50;
|
||||||
|
|
||||||
|
TEST(BranchOpcodeHandlerContainer, BCS_Take_Forward) {
|
||||||
|
auto machine = create_machine({BCS, 0x23});
|
||||||
|
machine->get_cpu().get_ps().set_carry(true);
|
||||||
|
machine->execute();
|
||||||
|
|
||||||
|
// + 2 to account for op bytes
|
||||||
|
ASSERT_EQ(CODE_LOAD_ADDR + 2 + 0x23, machine->get_cpu().get_pc().get_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BranchOpcodeHandlerContainer, BCS_Take_Backward) {
|
||||||
|
auto machine = create_machine({BCS, 0xF0});
|
||||||
|
machine->get_cpu().get_ps().set_carry(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
machine->execute();
|
||||||
|
}
|
||||||
|
catch (exception) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// + 2 to account for op bytes
|
||||||
|
ASSERT_EQ(CODE_LOAD_ADDR + 2 - 0xf, machine->get_cpu().get_pc().get_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BranchOpcodeHandlerContainer, BCS_NotTake) {
|
||||||
|
auto machine = create_machine({BCS, 0x23});
|
||||||
|
machine->get_cpu().get_ps().set_carry(false);
|
||||||
|
machine->execute();
|
||||||
|
|
||||||
|
// + 2 to account for op bytes
|
||||||
|
ASSERT_EQ(CODE_LOAD_ADDR + 2, machine->get_cpu().get_pc().get_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BranchOpcodeHandlerContainer, BCC_Take_Forward) {
|
||||||
|
auto machine = create_machine({BCC, 0x23});
|
||||||
|
machine->get_cpu().get_ps().set_carry(false);
|
||||||
|
machine->execute();
|
||||||
|
|
||||||
|
// + 2 to account for op bytes
|
||||||
|
ASSERT_EQ(CODE_LOAD_ADDR + 2 + 0x23, machine->get_cpu().get_pc().get_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BranchOpcodeHandlerContainer, BCC_Take_Backward) {
|
||||||
|
auto machine = create_machine({BCC, 0xF0});
|
||||||
|
machine->get_cpu().get_ps().set_carry(false);
|
||||||
|
|
||||||
|
try {
|
||||||
|
machine->execute();
|
||||||
|
}
|
||||||
|
catch (exception) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// + 2 to account for op bytes
|
||||||
|
ASSERT_EQ(CODE_LOAD_ADDR + 2 - 0xf, machine->get_cpu().get_pc().get_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BranchOpcodeHandlerContainer, BCC_NotTake) {
|
||||||
|
auto machine = create_machine({BCC, 0x23});
|
||||||
|
machine->get_cpu().get_ps().set_carry(true);
|
||||||
|
machine->execute();
|
||||||
|
|
||||||
|
// + 2 to account for op bytes
|
||||||
|
ASSERT_EQ(CODE_LOAD_ADDR + 2, machine->get_cpu().get_pc().get_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BranchOpcodeHandlerContainer, BEQ_Take_Forward) {
|
||||||
|
auto machine = create_machine({BEQ, 0x23});
|
||||||
|
machine->get_cpu().get_ps().set_zero(true);
|
||||||
|
machine->execute();
|
||||||
|
|
||||||
|
// + 2 to account for op bytes
|
||||||
|
ASSERT_EQ(CODE_LOAD_ADDR + 2 + 0x23, machine->get_cpu().get_pc().get_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BranchOpcodeHandlerContainer, BEQ_Take_Backward) {
|
||||||
|
auto machine = create_machine({BEQ, 0xF0});
|
||||||
|
machine->get_cpu().get_ps().set_zero(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
machine->execute();
|
||||||
|
}
|
||||||
|
catch (exception) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// + 2 to account for op bytes
|
||||||
|
ASSERT_EQ(CODE_LOAD_ADDR + 2 - 0xf, machine->get_cpu().get_pc().get_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BranchOpcodeHandlerContainer, BEQ_NotTake) {
|
||||||
|
auto machine = create_machine({BEQ, 0x23});
|
||||||
|
machine->get_cpu().get_ps().set_zero(false);
|
||||||
|
machine->execute();
|
||||||
|
|
||||||
|
// + 2 to account for op bytes
|
||||||
|
ASSERT_EQ(CODE_LOAD_ADDR + 2, machine->get_cpu().get_pc().get_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BranchOpcodeHandlerContainer, BNE_Take_Forward) {
|
||||||
|
auto machine = create_machine({BNE, 0x23});
|
||||||
|
machine->get_cpu().get_ps().set_zero(false);
|
||||||
|
machine->execute();
|
||||||
|
|
||||||
|
// + 2 to account for op bytes
|
||||||
|
ASSERT_EQ(CODE_LOAD_ADDR + 2 + 0x23, machine->get_cpu().get_pc().get_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BranchOpcodeHandlerContainer, BNE_Take_Backward) {
|
||||||
|
auto machine = create_machine({BNE, 0xF0});
|
||||||
|
machine->get_cpu().get_ps().set_zero(false);
|
||||||
|
|
||||||
|
try {
|
||||||
|
machine->execute();
|
||||||
|
}
|
||||||
|
catch (exception) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// + 2 to account for op bytes
|
||||||
|
ASSERT_EQ(CODE_LOAD_ADDR + 2 - 0xf, machine->get_cpu().get_pc().get_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BranchOpcodeHandlerContainer, BNE_NotTake) {
|
||||||
|
auto machine = create_machine({BNE, 0x23});
|
||||||
|
machine->get_cpu().get_ps().set_zero(true);
|
||||||
|
machine->execute();
|
||||||
|
|
||||||
|
// + 2 to account for op bytes
|
||||||
|
ASSERT_EQ(CODE_LOAD_ADDR + 2, machine->get_cpu().get_pc().get_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BranchOpcodeHandlerContainer, BPL_Take_Forward) {
|
||||||
|
auto machine = create_machine({BPL, 0x23});
|
||||||
|
machine->get_cpu().get_ps().set_negative(false);
|
||||||
|
machine->execute();
|
||||||
|
|
||||||
|
// + 2 to account for op bytes
|
||||||
|
ASSERT_EQ(CODE_LOAD_ADDR + 2 + 0x23, machine->get_cpu().get_pc().get_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BranchOpcodeHandlerContainer, BPL_Take_Backward) {
|
||||||
|
auto machine = create_machine({BPL, 0xF0});
|
||||||
|
machine->get_cpu().get_ps().set_negative(false);
|
||||||
|
|
||||||
|
try {
|
||||||
|
machine->execute();
|
||||||
|
}
|
||||||
|
catch (exception) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// + 2 to account for op bytes
|
||||||
|
ASSERT_EQ(CODE_LOAD_ADDR + 2 - 0xf, machine->get_cpu().get_pc().get_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BranchOpcodeHandlerContainer, BPL_NotTake) {
|
||||||
|
auto machine = create_machine({BPL, 0x23});
|
||||||
|
machine->get_cpu().get_ps().set_negative(true);
|
||||||
|
machine->execute();
|
||||||
|
|
||||||
|
// + 2 to account for op bytes
|
||||||
|
ASSERT_EQ(CODE_LOAD_ADDR + 2, machine->get_cpu().get_pc().get_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BranchOpcodeHandlerContainer, BMI_Take_Forward) {
|
||||||
|
auto machine = create_machine({BMI, 0x23});
|
||||||
|
machine->get_cpu().get_ps().set_negative(true);
|
||||||
|
machine->execute();
|
||||||
|
|
||||||
|
// + 2 to account for op bytes
|
||||||
|
ASSERT_EQ(CODE_LOAD_ADDR + 2 + 0x23, machine->get_cpu().get_pc().get_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BranchOpcodeHandlerContainer, BMI_Take_Backward) {
|
||||||
|
auto machine = create_machine({BMI, 0xF0});
|
||||||
|
machine->get_cpu().get_ps().set_negative(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
machine->execute();
|
||||||
|
}
|
||||||
|
catch (exception) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// + 2 to account for op bytes
|
||||||
|
ASSERT_EQ(CODE_LOAD_ADDR + 2 - 0xf, machine->get_cpu().get_pc().get_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BranchOpcodeHandlerContainer, BMI_NotTake) {
|
||||||
|
auto machine = create_machine({BMI, 0x23});
|
||||||
|
machine->get_cpu().get_ps().set_negative(false);
|
||||||
|
machine->execute();
|
||||||
|
|
||||||
|
// + 2 to account for op bytes
|
||||||
|
ASSERT_EQ(CODE_LOAD_ADDR + 2, machine->get_cpu().get_pc().get_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BranchOpcodeHandlerContainer, BVS_Take_Forward) {
|
||||||
|
auto machine = create_machine({BVS, 0x23});
|
||||||
|
machine->get_cpu().get_ps().set_overflow(true);
|
||||||
|
machine->execute();
|
||||||
|
|
||||||
|
// + 2 to account for op bytes
|
||||||
|
ASSERT_EQ(CODE_LOAD_ADDR + 2 + 0x23, machine->get_cpu().get_pc().get_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BranchOpcodeHandlerContainer, BVS_Take_Backward) {
|
||||||
|
auto machine = create_machine({BVS, 0xF0});
|
||||||
|
machine->get_cpu().get_ps().set_overflow(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
machine->execute();
|
||||||
|
}
|
||||||
|
catch (exception) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// + 2 to account for op bytes
|
||||||
|
ASSERT_EQ(CODE_LOAD_ADDR + 2 - 0xf, machine->get_cpu().get_pc().get_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BranchOpcodeHandlerContainer, BVS_NotTake) {
|
||||||
|
auto machine = create_machine({BVS, 0x23});
|
||||||
|
machine->get_cpu().get_ps().set_overflow(false);
|
||||||
|
machine->execute();
|
||||||
|
|
||||||
|
// + 2 to account for op bytes
|
||||||
|
ASSERT_EQ(CODE_LOAD_ADDR + 2, machine->get_cpu().get_pc().get_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BranchOpcodeHandlerContainer, BVC_Take_Forward) {
|
||||||
|
auto machine = create_machine({BVC, 0x23});
|
||||||
|
machine->get_cpu().get_ps().set_overflow(false);
|
||||||
|
machine->execute();
|
||||||
|
|
||||||
|
// + 2 to account for op bytes
|
||||||
|
ASSERT_EQ(CODE_LOAD_ADDR + 2 + 0x23, machine->get_cpu().get_pc().get_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BranchOpcodeHandlerContainer, BVC_Take_Backward) {
|
||||||
|
auto machine = create_machine({BVC, 0xF0});
|
||||||
|
machine->get_cpu().get_ps().set_overflow(false);
|
||||||
|
|
||||||
|
try {
|
||||||
|
machine->execute();
|
||||||
|
}
|
||||||
|
catch (exception) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// + 2 to account for op bytes
|
||||||
|
ASSERT_EQ(CODE_LOAD_ADDR + 2 - 0xf, machine->get_cpu().get_pc().get_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BranchOpcodeHandlerContainer, BVC_NotTake) {
|
||||||
|
auto machine = create_machine({BVC, 0x23});
|
||||||
|
machine->get_cpu().get_ps().set_overflow(true);
|
||||||
|
machine->execute();
|
||||||
|
|
||||||
|
// + 2 to account for op bytes
|
||||||
|
ASSERT_EQ(CODE_LOAD_ADDR + 2, machine->get_cpu().get_pc().get_value());
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
unique_ptr<Machine> create_machine(vector<uint8_t> code) {
|
unique_ptr<Machine> create_machine(vector<uint8_t> code) {
|
||||||
auto machine = make_unique<Machine>();
|
auto machine = make_unique<Machine>();
|
||||||
machine->load(code, 0x600);
|
machine->load(code, CODE_LOAD_ADDR);
|
||||||
|
|
||||||
return machine;
|
return machine;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace emu_6502;
|
using namespace emu_6502;
|
||||||
|
|
||||||
|
const uint16_t CODE_LOAD_ADDR = 0x600;
|
||||||
|
|
||||||
struct RegisterFlagSet {
|
struct RegisterFlagSet {
|
||||||
bool carry;
|
bool carry;
|
||||||
bool zero;
|
bool zero;
|
||||||
|
|
Loading…
Reference in New Issue