Add "adc" instructions

This commit is contained in:
Tony Di Nucci 2019-04-18 01:09:44 +01:00
parent 534c5576f8
commit cab2cec9ff
10 changed files with 403 additions and 5 deletions

View File

@ -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();
}

View File

@ -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();

View File

@ -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;

View File

@ -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;

View 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) {
}
}

View 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

View File

@ -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();
}

View File

@ -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);

View File

@ -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);
}

View 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{}));
}