mirror of
https://github.com/tdinucci/6502-emulator.git
synced 2025-04-09 17:37:58 +00:00
Add "adc" instructions
This commit is contained in:
parent
534c5576f8
commit
cab2cec9ff
@ -92,7 +92,7 @@ namespace emu_6502 {
|
||||
pimpl->load(program, load_at);
|
||||
}
|
||||
|
||||
bool Machine::is_eop() {
|
||||
bool Machine::is_eop() const {
|
||||
return pimpl->is_eop();
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ namespace emu_6502 {
|
||||
Memory& get_memory();
|
||||
Stack& get_stack();
|
||||
|
||||
bool is_eop();
|
||||
bool is_eop() const;
|
||||
uint8_t read_program_byte();
|
||||
void load(const vector<uint8_t>& program, uint16_t load_at);
|
||||
void execute();
|
||||
|
@ -16,9 +16,9 @@ namespace emu_6502 {
|
||||
T value;
|
||||
|
||||
public:
|
||||
Register<T>(string name);
|
||||
explicit Register<T>(string name);
|
||||
Register<T>(const Register<T>&) = delete;
|
||||
Register<T>& operator=(const Register<T>&) = delete;
|
||||
virtual Register<T>& operator=(const Register<T>&) = delete;
|
||||
|
||||
const string& get_name() const;
|
||||
|
||||
|
@ -24,7 +24,7 @@ namespace emu_6502 {
|
||||
StatusRegister() : Register<bitset<8>>("PS") {}
|
||||
|
||||
StatusRegister(const StatusRegister&) = delete;
|
||||
StatusRegister& operator=(const StatusRegister&) = delete;
|
||||
virtual StatusRegister& operator=(const StatusRegister&) = delete;
|
||||
|
||||
bool is_carry_set() const;
|
||||
bool is_zero_set() const;
|
||||
|
124
src/opcode/handler/maths-opcode-handler-container.cpp
Normal file
124
src/opcode/handler/maths-opcode-handler-container.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
#include "maths-opcode-handler-container.h"
|
||||
#include "../../utils.h"
|
||||
|
||||
namespace emu_6502 {
|
||||
MathsOpcodeHandlerContainer::MathsOpcodeHandlerContainer() : OpcodeHandlerContainer() {
|
||||
handlers.insert({Op::ADC_IMM, [this](Machine& machine) { adc_imm(machine); }});
|
||||
handlers.insert({Op::ADC_ZPG, [this](Machine& machine) { adc_zpg(machine); }});
|
||||
handlers.insert({Op::ADC_ZPG_X, [this](Machine& machine) { adc_zpg_x(machine); }});
|
||||
handlers.insert({Op::ADC_ABS, [this](Machine& machine) { adc_abs(machine); }});
|
||||
handlers.insert({Op::ADC_ABS_X, [this](Machine& machine) { adc_abs_x(machine); }});
|
||||
handlers.insert({Op::ADC_ABS_Y, [this](Machine& machine) { adc_abs_y(machine); }});
|
||||
handlers.insert({Op::ADC_IND_X, [this](Machine& machine) { adc_ind_x(machine); }});
|
||||
handlers.insert({Op::ADC_IND_Y, [this](Machine& machine) { adc_ind_y(machine); }});
|
||||
}
|
||||
|
||||
void MathsOpcodeHandlerContainer::adc(Machine& machine, uint8_t value){
|
||||
auto& cpu = machine.get_cpu();
|
||||
auto init_a = cpu.get_a().get_value();
|
||||
|
||||
uint16_t result = value + init_a;
|
||||
if (cpu.get_ps().is_carry_set())
|
||||
result += 1;
|
||||
|
||||
cpu.get_a().set_value(result); // will chop off bit 8 if set
|
||||
auto a = cpu.get_a().get_value();
|
||||
|
||||
// 'a' may be 0 if the result wasn't 0, i.e. the cary bit is set
|
||||
cpu.get_ps().set_zero(a == 0);
|
||||
cpu.get_ps().set_negative((a & 0x80) == 0x80);
|
||||
cpu.get_ps().set_carry(result > 0xFF);
|
||||
cpu.get_ps().set_overflow(
|
||||
(value < 0x7F && init_a < 0x7F && a > 0x7F) ||
|
||||
(value > 0x7F && init_a > 0x7F && a < 0x7F));
|
||||
}
|
||||
|
||||
void MathsOpcodeHandlerContainer::adc_imm(Machine& machine) {
|
||||
adc(machine, machine.read_program_byte());
|
||||
}
|
||||
|
||||
void MathsOpcodeHandlerContainer::adc_zpg(Machine& machine) {
|
||||
auto addr = get_zpg_address(machine.read_program_byte());
|
||||
adc(machine, machine.get_memory().get_at(addr));
|
||||
}
|
||||
|
||||
void MathsOpcodeHandlerContainer::adc_zpg_x(Machine& machine) {
|
||||
auto addr = get_zpg_x_address(machine.read_program_byte(), machine.get_cpu());
|
||||
adc(machine, machine.get_memory().get_at(addr));
|
||||
}
|
||||
|
||||
void MathsOpcodeHandlerContainer::adc_abs(Machine& machine) {
|
||||
auto low = machine.read_program_byte();
|
||||
auto high = machine.read_program_byte();
|
||||
auto addr = get_abs_address(low, high);
|
||||
adc(machine, machine.get_memory().get_at(addr));
|
||||
}
|
||||
|
||||
void MathsOpcodeHandlerContainer::adc_abs_x(Machine& machine) {
|
||||
auto addr = get_abs_x_address(machine, machine.get_cpu());
|
||||
adc(machine, machine.get_memory().get_at(addr));
|
||||
}
|
||||
|
||||
void MathsOpcodeHandlerContainer::adc_abs_y(Machine& machine) {
|
||||
auto addr = get_abs_y_address(machine, machine.get_cpu());
|
||||
adc(machine, machine.get_memory().get_at(addr));
|
||||
}
|
||||
|
||||
void MathsOpcodeHandlerContainer::adc_ind_x(Machine& machine) {
|
||||
auto addr = get_ind_x_address(machine.read_program_byte(), machine);
|
||||
adc(machine, machine.get_memory().get_at(addr));
|
||||
}
|
||||
|
||||
void MathsOpcodeHandlerContainer::adc_ind_y(Machine& machine) {
|
||||
auto addr = get_ind_y_address(machine.read_program_byte(), machine);
|
||||
adc(machine, machine.get_memory().get_at(addr));
|
||||
}
|
||||
|
||||
void MathsOpcodeHandlerContainer::dec_zpg(Machine& machine) {
|
||||
}
|
||||
|
||||
void MathsOpcodeHandlerContainer::dec_zpg_x(Machine& machine) {
|
||||
}
|
||||
|
||||
void MathsOpcodeHandlerContainer::dec_abs(Machine& machine) {
|
||||
}
|
||||
|
||||
void MathsOpcodeHandlerContainer::dec_abs_x(Machine& machine) {
|
||||
}
|
||||
|
||||
void MathsOpcodeHandlerContainer::dex(Machine& machine) {
|
||||
}
|
||||
|
||||
void MathsOpcodeHandlerContainer::dey(Machine& machine) {
|
||||
}
|
||||
|
||||
void MathsOpcodeHandlerContainer::inx(Machine& machine) {
|
||||
}
|
||||
|
||||
void MathsOpcodeHandlerContainer::iny(Machine& machine) {
|
||||
}
|
||||
|
||||
void MathsOpcodeHandlerContainer::sbc_imm(Machine& machine) {
|
||||
}
|
||||
|
||||
void MathsOpcodeHandlerContainer::sbc_zpg(Machine& machine) {
|
||||
}
|
||||
|
||||
void MathsOpcodeHandlerContainer::sbc_zpg_x(Machine& machine) {
|
||||
}
|
||||
|
||||
void MathsOpcodeHandlerContainer::sbc_abs(Machine& machine) {
|
||||
}
|
||||
|
||||
void MathsOpcodeHandlerContainer::sbc_abs_x(Machine& machine) {
|
||||
}
|
||||
|
||||
void MathsOpcodeHandlerContainer::sbc_abs_y(Machine& machine) {
|
||||
}
|
||||
|
||||
void MathsOpcodeHandlerContainer::sbc_ind_x(Machine& machine) {
|
||||
}
|
||||
|
||||
void MathsOpcodeHandlerContainer::sbc_ind_y(Machine& machine) {
|
||||
}
|
||||
}
|
81
src/opcode/handler/maths-opcode-handler-container.h
Normal file
81
src/opcode/handler/maths-opcode-handler-container.h
Normal file
@ -0,0 +1,81 @@
|
||||
#ifndef INC_6502_EMULATOR_MATHS_OPCODE_HANDLER_CONTAINER_H
|
||||
#define INC_6502_EMULATOR_MATHS_OPCODE_HANDLER_CONTAINER_H
|
||||
|
||||
#include "opcode-handler-container.h"
|
||||
|
||||
namespace emu_6502 {
|
||||
class MathsOpcodeHandlerContainer : public OpcodeHandlerContainer {
|
||||
private:
|
||||
enum Op {
|
||||
ADC_IMM = 0x69,
|
||||
ADC_ZPG = 0x65,
|
||||
ADC_ZPG_X = 0x75,
|
||||
ADC_ABS = 0x6D,
|
||||
ADC_ABS_X = 0x7D,
|
||||
ADC_ABS_Y = 0x79,
|
||||
ADC_IND_X = 0x61,
|
||||
ADC_IND_Y = 0x71,
|
||||
|
||||
DEC_ZPG = 0xC6,
|
||||
DEC_ZPG_X = 0xD6,
|
||||
DEC_ABS = 0xCE,
|
||||
DEC_ABS_X = 0xDE,
|
||||
|
||||
INC_ZPG = 0xE6,
|
||||
INC_ZPG_X = 0xF6,
|
||||
INC_ABS = 0xEE,
|
||||
INC_ABS_X = 0xFE,
|
||||
|
||||
DEX = 0xCA,
|
||||
DEY = 0x88,
|
||||
INX = 0xE8,
|
||||
INY = 0xC8,
|
||||
|
||||
SBC_IMM = 0x0,
|
||||
SBC_ZPG = 0x0,
|
||||
SBC_ZPG_X = 0x0,
|
||||
SBC_ABS = 0x0,
|
||||
SBC_ABS_X = 0x0,
|
||||
SBC_ABS_Y = 0x0,
|
||||
SBC_IND_X = 0x0,
|
||||
SBC_IND_Y = 0x0
|
||||
};
|
||||
|
||||
void adc(Machine& machine, uint8_t value);
|
||||
void adc_imm(Machine& machine);
|
||||
void adc_zpg(Machine& machine);
|
||||
void adc_zpg_x(Machine& machine);
|
||||
void adc_abs(Machine& machine);
|
||||
void adc_abs_x(Machine& machine);
|
||||
void adc_abs_y(Machine& machine);
|
||||
void adc_ind_x(Machine& machine);
|
||||
void adc_ind_y(Machine& machine);
|
||||
|
||||
void dec_zpg(Machine& machine);
|
||||
void dec_zpg_x(Machine& machine);
|
||||
void dec_abs(Machine& machine);
|
||||
void dec_abs_x(Machine& machine);
|
||||
|
||||
void dex(Machine& machine);
|
||||
void dey(Machine& machine);
|
||||
void inx(Machine& machine);
|
||||
void iny(Machine& machine);
|
||||
|
||||
void sbc_imm(Machine& machine);
|
||||
void sbc_zpg(Machine& machine);
|
||||
void sbc_zpg_x(Machine& machine);
|
||||
void sbc_abs(Machine& machine);
|
||||
void sbc_abs_x(Machine& machine);
|
||||
void sbc_abs_y(Machine& machine);
|
||||
void sbc_ind_x(Machine& machine);
|
||||
void sbc_ind_y(Machine& machine);
|
||||
|
||||
public:
|
||||
MathsOpcodeHandlerContainer();
|
||||
MathsOpcodeHandlerContainer(const MathsOpcodeHandlerContainer&) = delete;
|
||||
MathsOpcodeHandlerContainer& operator=(const MathsOpcodeHandlerContainer&) = delete;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif //INC_6502_EMULATOR_MATHS_OPCODE_HANDLER_CONTAINER_H
|
@ -2,6 +2,7 @@
|
||||
#include "handler/load-opcode-handler-container.h"
|
||||
#include "handler/store-opcode-handler-container.h"
|
||||
#include "handler/transfer-opcode-handler-container.h"
|
||||
#include "handler/maths-opcode-handler-container.h"
|
||||
#include "../utils.h"
|
||||
|
||||
namespace emu_6502 {
|
||||
@ -10,6 +11,7 @@ namespace emu_6502 {
|
||||
handler_containers.push_back(make_unique<LoadOpcodeHandlerContainer>());
|
||||
handler_containers.push_back(make_unique<StoreOpcodeHandlerContainer>());
|
||||
handler_containers.push_back(make_unique<TransferOpcodeHandlerContainer>());
|
||||
handler_containers.push_back(make_unique<MathsOpcodeHandlerContainer>());
|
||||
|
||||
init_handlers();
|
||||
}
|
||||
|
@ -37,6 +37,18 @@ namespace emu_6502 {
|
||||
return address;
|
||||
}
|
||||
|
||||
uint16_t get_abs_x_address(Machine& machine, Cpu& cpu) {
|
||||
auto low = machine.read_program_byte();
|
||||
auto high = machine.read_program_byte();
|
||||
return get_abs_x_address(low, high, machine.get_cpu());
|
||||
}
|
||||
|
||||
uint16_t get_abs_y_address(Machine& machine, Cpu& cpu) {
|
||||
auto low = machine.read_program_byte();
|
||||
auto high = machine.read_program_byte();
|
||||
return get_abs_y_address(low, high, machine.get_cpu());
|
||||
}
|
||||
|
||||
uint16_t get_ind_x_address(uint8_t offset, Machine& machine) {
|
||||
uint8_t paddress = machine.get_cpu().get_x().get_value() + offset;
|
||||
auto low = machine.get_memory().get_at(paddress);
|
||||
|
@ -15,6 +15,8 @@ namespace emu_6502 {
|
||||
uint16_t get_abs_address(uint8_t low_byte, uint8_t high_byte);
|
||||
uint16_t get_abs_x_address(uint8_t low_byte, uint8_t high_byte, Cpu& cpu);
|
||||
uint16_t get_abs_y_address(uint8_t low_byte, uint8_t high_byte, Cpu& cpu);
|
||||
uint16_t get_abs_x_address(Machine& machine, Cpu& cpu);
|
||||
uint16_t get_abs_y_address(Machine& machine, Cpu& cpu);
|
||||
uint16_t get_ind_x_address(uint8_t offset, Machine& machine);
|
||||
uint16_t get_ind_y_address(uint8_t offset, Machine& machine);
|
||||
}
|
||||
|
177
test/maths-opcode-handler-test.cpp
Normal file
177
test/maths-opcode-handler-test.cpp
Normal file
@ -0,0 +1,177 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "test-utils.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace emu_6502;
|
||||
|
||||
const uint8_t ADC_IMM = 0x69;
|
||||
const uint8_t ADC_ZPG = 0x65;
|
||||
const uint8_t ADC_ZPG_X = 0x75;
|
||||
const uint8_t ADC_ABS = 0x6D;
|
||||
const uint8_t ADC_ABS_X = 0x7D;
|
||||
const uint8_t ADC_ABS_Y = 0x79;
|
||||
const uint8_t ADC_IND_X = 0x61;
|
||||
const uint8_t ADC_IND_Y = 0x71;
|
||||
|
||||
TEST(MathsOpcodeHandlerContainer, ADC_IMM) {
|
||||
auto machine = create_machine({ADC_IMM, 36});
|
||||
machine->get_cpu().get_a().set_value(36);
|
||||
machine->execute();
|
||||
|
||||
ASSERT_EQ(72, machine->get_cpu().get_a().get_value());
|
||||
ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{}));
|
||||
}
|
||||
|
||||
TEST(MathsOpcodeHandlerContainer, ADC_IMM_ZeroFlag) {
|
||||
auto machine = create_machine({ADC_IMM, 0});
|
||||
machine->get_cpu().get_a().set_value(0);
|
||||
machine->execute();
|
||||
|
||||
ASSERT_EQ(0, machine->get_cpu().get_a().get_value());
|
||||
|
||||
RegisterFlagSet flags{};
|
||||
flags.zero = true;
|
||||
ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags));
|
||||
}
|
||||
|
||||
TEST(MathsOpcodeHandlerContainer, ADC_IMM_CarryFlag) {
|
||||
auto machine = create_machine({ADC_IMM, 200});
|
||||
machine->get_cpu().get_a().set_value(72);
|
||||
machine->execute();
|
||||
|
||||
ASSERT_EQ(16, machine->get_cpu().get_a().get_value());
|
||||
|
||||
RegisterFlagSet flags{};
|
||||
flags.carry = true;
|
||||
ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags));
|
||||
}
|
||||
|
||||
TEST(MathsOpcodeHandlerContainer, ADC_IMM_ZeroAndCarryFlags) {
|
||||
auto machine = create_machine({ADC_IMM, 0xFF});
|
||||
machine->get_cpu().get_a().set_value(1);
|
||||
machine->execute();
|
||||
|
||||
ASSERT_EQ(0, machine->get_cpu().get_a().get_value());
|
||||
|
||||
RegisterFlagSet flags{};
|
||||
flags.zero = true;
|
||||
flags.carry = true;
|
||||
ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags));
|
||||
}
|
||||
|
||||
TEST(MathsOpcodeHandlerContainer, ADC_IMM_NegativeFlag) {
|
||||
auto machine = create_machine({ADC_IMM, 200});
|
||||
machine->get_cpu().get_a().set_value(32);
|
||||
machine->execute();
|
||||
|
||||
ASSERT_EQ(232, machine->get_cpu().get_a().get_value());
|
||||
|
||||
RegisterFlagSet flags{};
|
||||
flags.negative = true;
|
||||
ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags));
|
||||
}
|
||||
|
||||
TEST(MathsOpcodeHandlerContainer, ADC_IMM_OverflowFlag_Postive) {
|
||||
auto machine = create_machine({ADC_IMM, 120});
|
||||
machine->get_cpu().get_a().set_value(32);
|
||||
machine->execute();
|
||||
|
||||
ASSERT_EQ(152, machine->get_cpu().get_a().get_value());
|
||||
|
||||
RegisterFlagSet flags{};
|
||||
flags.negative = true;
|
||||
flags.overflow = true;
|
||||
ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags));
|
||||
}
|
||||
|
||||
TEST(MathsOpcodeHandlerContainer, ADC_IMM_OverflowFlag_Negative) {
|
||||
auto machine = create_machine({ADC_IMM, 208});
|
||||
machine->get_cpu().get_a().set_value(144);
|
||||
machine->execute();
|
||||
|
||||
ASSERT_EQ(96, machine->get_cpu().get_a().get_value());
|
||||
|
||||
RegisterFlagSet flags{};
|
||||
flags.carry = true;
|
||||
flags.overflow = true;
|
||||
ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags));
|
||||
}
|
||||
|
||||
TEST(MathsOpcodeHandlerContainer, ADC_ZPG) {
|
||||
auto machine = create_machine({ADC_ZPG, 0xf1});
|
||||
machine->get_cpu().get_a().set_value(36);
|
||||
machine->get_memory().set_at(0xf1, 20);
|
||||
machine->execute();
|
||||
|
||||
ASSERT_EQ(56, machine->get_cpu().get_a().get_value());
|
||||
ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{}));
|
||||
}
|
||||
|
||||
TEST(MathsOpcodeHandlerContainer, ADC_ZPG_X) {
|
||||
auto machine = create_machine({ADC_ZPG_X, 0xf1});
|
||||
machine->get_cpu().get_a().set_value(36);
|
||||
machine->get_cpu().get_x().set_value(5);
|
||||
machine->get_memory().set_at(0xf6, 20);
|
||||
machine->execute();
|
||||
|
||||
ASSERT_EQ(56, machine->get_cpu().get_a().get_value());
|
||||
ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{}));
|
||||
}
|
||||
|
||||
TEST(MathsOpcodeHandlerContainer, ADC_ABS) {
|
||||
auto machine = create_machine({ADC_ABS, 0xf1, 0x36});
|
||||
machine->get_cpu().get_a().set_value(36);
|
||||
machine->get_memory().set_at(0x36f1, 20);
|
||||
machine->execute();
|
||||
|
||||
ASSERT_EQ(56, machine->get_cpu().get_a().get_value());
|
||||
ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{}));
|
||||
}
|
||||
|
||||
TEST(MathsOpcodeHandlerContainer, ADC_ABS_X) {
|
||||
auto machine = create_machine({ADC_ABS_X, 0xf1, 0x36});
|
||||
machine->get_cpu().get_a().set_value(36);
|
||||
machine->get_cpu().get_x().set_value(8);
|
||||
machine->get_memory().set_at(0x36f9, 20);
|
||||
machine->execute();
|
||||
|
||||
ASSERT_EQ(56, machine->get_cpu().get_a().get_value());
|
||||
ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{}));
|
||||
}
|
||||
|
||||
TEST(MathsOpcodeHandlerContainer, ADC_ABS_Y) {
|
||||
auto machine = create_machine({ADC_ABS_Y, 0xf1, 0x36});
|
||||
machine->get_cpu().get_a().set_value(36);
|
||||
machine->get_cpu().get_y().set_value(8);
|
||||
machine->get_memory().set_at(0x36f9, 20);
|
||||
machine->execute();
|
||||
|
||||
ASSERT_EQ(56, machine->get_cpu().get_a().get_value());
|
||||
ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{}));
|
||||
}
|
||||
|
||||
TEST(MathsOpcodeHandlerContainer, ADC_IND_X) {
|
||||
auto machine = create_machine({ADC_IND_X, 0x41});
|
||||
machine->get_cpu().get_x().set_value(0x22);
|
||||
machine->get_cpu().get_a().set_value(36);
|
||||
machine->get_memory().set_at(0x63, 0x34);
|
||||
machine->get_memory().set_at(0x64, 0x12);
|
||||
machine->get_memory().set_at(0x1234, 20);
|
||||
machine->execute();
|
||||
|
||||
ASSERT_EQ(56, machine->get_cpu().get_a().get_value());
|
||||
ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{}));
|
||||
}
|
||||
|
||||
TEST(MathsOpcodeHandlerContainer, ADC_IND_Y) {
|
||||
auto machine = create_machine({ADC_IND_Y, 0x41});
|
||||
machine->get_cpu().get_y().set_value(0x22);
|
||||
machine->get_cpu().get_a().set_value(36);
|
||||
machine->get_memory().set_at(0x41, 0x34);
|
||||
machine->get_memory().set_at(0x42, 0x12);
|
||||
machine->get_memory().set_at(0x1256, 20);
|
||||
machine->execute();
|
||||
|
||||
ASSERT_EQ(56, machine->get_cpu().get_a().get_value());
|
||||
ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{}));
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user