diff --git a/src/opcode/handler/maths-opcode-handler-container.cpp b/src/opcode/handler/maths-opcode-handler-container.cpp index d3d2db7..7279cb1 100644 --- a/src/opcode/handler/maths-opcode-handler-container.cpp +++ b/src/opcode/handler/maths-opcode-handler-container.cpp @@ -12,6 +12,15 @@ namespace emu_6502 { 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); }}); + handlers.insert({Op::SBC_IMM, [this](Machine& machine) { sbc_imm(machine); }}); + handlers.insert({Op::SBC_ZPG, [this](Machine& machine) { sbc_zpg(machine); }}); + handlers.insert({Op::SBC_ZPG_X, [this](Machine& machine) { sbc_zpg_x(machine); }}); + handlers.insert({Op::SBC_ABS, [this](Machine& machine) { sbc_abs(machine); }}); + handlers.insert({Op::SBC_ABS_X, [this](Machine& machine) { sbc_abs_x(machine); }}); + handlers.insert({Op::SBC_ABS_Y, [this](Machine& machine) { sbc_abs_y(machine); }}); + handlers.insert({Op::SBC_IND_X, [this](Machine& machine) { sbc_ind_x(machine); }}); + handlers.insert({Op::SBC_IND_Y, [this](Machine& machine) { sbc_ind_y(machine); }}); + handlers.insert({Op::DEC_ZPG, [this](Machine& machine) { dec_zpg(machine); }}); handlers.insert({Op::DEC_ZPG_X, [this](Machine& machine) { dec_zpg_x(machine); }}); handlers.insert({Op::DEC_ABS, [this](Machine& machine) { dec_abs(machine); }}); @@ -85,6 +94,43 @@ namespace emu_6502 { adc(machine, machine.get_memory().get_at(get_ind_y_address(machine))); } + void MathsOpcodeHandlerContainer::sbc(Machine& machine, uint8_t value) { + // subtract is same as add negative value (i.e. add accumulator to the twos compliment of 'value') + adc(machine, (0xFF ^ value) + 1); + } + + void MathsOpcodeHandlerContainer::sbc_imm(Machine& machine) { + sbc(machine, machine.read_program_byte()); + } + + void MathsOpcodeHandlerContainer::sbc_zpg(Machine& machine) { + sbc(machine, machine.get_memory().get_at(get_zpg_address(machine))); + } + + void MathsOpcodeHandlerContainer::sbc_zpg_x(Machine& machine) { + sbc(machine, machine.get_memory().get_at(get_zpg_x_address(machine))); + } + + void MathsOpcodeHandlerContainer::sbc_abs(Machine& machine) { + sbc(machine, machine.get_memory().get_at(get_abs_address(machine))); + } + + void MathsOpcodeHandlerContainer::sbc_abs_x(Machine& machine) { + sbc(machine, machine.get_memory().get_at(get_abs_x_address(machine))); + } + + void MathsOpcodeHandlerContainer::sbc_abs_y(Machine& machine) { + sbc(machine, machine.get_memory().get_at(get_abs_y_address(machine))); + } + + void MathsOpcodeHandlerContainer::sbc_ind_x(Machine& machine) { + sbc(machine, machine.get_memory().get_at(get_ind_x_address(machine))); + } + + void MathsOpcodeHandlerContainer::sbc_ind_y(Machine& machine) { + sbc(machine, machine.get_memory().get_at(get_ind_y_address(machine))); + } + void MathsOpcodeHandlerContainer::dec(Machine& machine, uint16_t address) { uint8_t value = machine.get_memory().get_at(address) - 1; machine.get_memory().set_at(address, value); @@ -160,28 +206,4 @@ namespace emu_6502 { void MathsOpcodeHandlerContainer::iny(Machine& machine) { in(machine, machine.get_cpu().get_y()); } - - 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) { - } } diff --git a/src/opcode/handler/maths-opcode-handler-container.h b/src/opcode/handler/maths-opcode-handler-container.h index 7e047e4..2ecd64a 100644 --- a/src/opcode/handler/maths-opcode-handler-container.h +++ b/src/opcode/handler/maths-opcode-handler-container.h @@ -16,6 +16,15 @@ namespace emu_6502 { ADC_IND_X = 0x61, ADC_IND_Y = 0x71, + SBC_IMM = 0xE9, + SBC_ZPG = 0xE5, + SBC_ZPG_X = 0xF5, + SBC_ABS = 0xED, + SBC_ABS_X = 0xFD, + SBC_ABS_Y = 0xF9, + SBC_IND_X = 0xE1, + SBC_IND_Y = 0xF1, + DEC_ZPG = 0xC6, DEC_ZPG_X = 0xD6, DEC_ABS = 0xCE, @@ -29,16 +38,7 @@ namespace emu_6502 { 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 + INY = 0xC8 }; void set_zero_neg(StatusRegister& ps, uint8_t value); @@ -53,6 +53,16 @@ namespace emu_6502 { void adc_ind_x(Machine& machine); void adc_ind_y(Machine& machine); + void sbc(Machine& machine, uint8_t value); + 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); + void dec(Machine& machine, uint16_t address); void dec_zpg(Machine& machine); void dec_zpg_x(Machine& machine); @@ -73,15 +83,6 @@ namespace emu_6502 { 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; diff --git a/test/maths-opcode-handler-test.cpp b/test/maths-opcode-handler-test.cpp index a18b197..4b904c9 100644 --- a/test/maths-opcode-handler-test.cpp +++ b/test/maths-opcode-handler-test.cpp @@ -13,6 +13,15 @@ const uint8_t ADC_ABS_Y = 0x79; const uint8_t ADC_IND_X = 0x61; const uint8_t ADC_IND_Y = 0x71; +const uint8_t SBC_IMM = 0xE9; +const uint8_t SBC_ZPG = 0xE5; +const uint8_t SBC_ZPG_X = 0xF5; +const uint8_t SBC_ABS = 0xED; +const uint8_t SBC_ABS_X = 0xFD; +const uint8_t SBC_ABS_Y = 0xF9; +const uint8_t SBC_IND_X = 0xE1; +const uint8_t SBC_IND_Y = 0xF1; + const uint8_t DEC_ZPG = 0xC6; const uint8_t DEC_ZPG_X = 0xD6; const uint8_t DEC_ABS = 0xCE; @@ -191,6 +200,148 @@ TEST(MathsOpcodeHandlerContainer, ADC_IND_Y) { ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); } +TEST(MathsOpcodeHandlerContainer, SBC_IMM) { + auto machine = create_machine({SBC_IMM, 0x20}); + machine->get_cpu().get_a().set_value(0x50); + machine->execute(); + + ASSERT_EQ(0x30, machine->get_cpu().get_a().get_value()); + RegisterFlagSet flags{}; + flags.carry = true; // indicates no borrow + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(MathsOpcodeHandlerContainer, SBC_IMM_WithBorrow) { + auto machine = create_machine({SBC_IMM, 0xf0}); + machine->get_cpu().get_a().set_value(0xd0); + machine->execute(); + + ASSERT_EQ(0xe0, machine->get_cpu().get_a().get_value()); + RegisterFlagSet flags{}; + flags.carry = false; // indicates there was a borrow + flags.negative = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(MathsOpcodeHandlerContainer, SBC_IMM_WithOverflow) { + auto machine = create_machine({SBC_IMM, 0xb0}); + machine->get_cpu().get_a().set_value(0x50); + machine->execute(); + + ASSERT_EQ(0xa0, machine->get_cpu().get_a().get_value()); + RegisterFlagSet flags{}; + flags.carry = false; // was a borrow + flags.negative = true; + flags.overflow = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(MathsOpcodeHandlerContainer, SBC_IMM_ZeroFlag) { + auto machine = create_machine({SBC_IMM, 50}); + machine->get_cpu().get_a().set_value(50); + machine->execute(); + + ASSERT_EQ(0, machine->get_cpu().get_a().get_value()); + + RegisterFlagSet flags{}; + flags.zero = true; + flags.carry = true; // no borrow + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(MathsOpcodeHandlerContainer, SBC_ZPG) { + auto machine = create_machine({SBC_ZPG, 0xf1}); + machine->get_cpu().get_a().set_value(36); + machine->get_memory().set_at(0xf1, 20); + machine->execute(); + + ASSERT_EQ(16, machine->get_cpu().get_a().get_value()); + RegisterFlagSet flags{}; + flags.carry = true; // no borrow + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(MathsOpcodeHandlerContainer, SBC_ZPG_X) { + auto machine = create_machine({SBC_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(16, machine->get_cpu().get_a().get_value()); + RegisterFlagSet flags{}; + flags.carry = true; // no borrow + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(MathsOpcodeHandlerContainer, SBC_ABS) { + auto machine = create_machine({SBC_ABS, 0xf1, 0x36}); + machine->get_cpu().get_a().set_value(36); + machine->get_memory().set_at(0x36f1, 20); + machine->execute(); + + ASSERT_EQ(16, machine->get_cpu().get_a().get_value()); + RegisterFlagSet flags{}; + flags.carry = true; // no borrow + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(MathsOpcodeHandlerContainer, SBC_ABS_X) { + auto machine = create_machine({SBC_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(16, machine->get_cpu().get_a().get_value()); + RegisterFlagSet flags{}; + flags.carry = true; // no borrow + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(MathsOpcodeHandlerContainer, SBC_ABS_Y) { + auto machine = create_machine({SBC_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(16, machine->get_cpu().get_a().get_value()); + RegisterFlagSet flags{}; + flags.carry = true; // no borrow + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(MathsOpcodeHandlerContainer, SBC_IND_X) { + auto machine = create_machine({SBC_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(16, machine->get_cpu().get_a().get_value()); + RegisterFlagSet flags{}; + flags.carry = true; // no borrow + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(MathsOpcodeHandlerContainer, SBC_IND_Y) { + auto machine = create_machine({SBC_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(16, machine->get_cpu().get_a().get_value()); + RegisterFlagSet flags{}; + flags.carry = true; // no borrow + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + TEST(MathsOpcodeHandlerContainer, DEC_ZPG) { auto machine = create_machine({DEC_ZPG, 0xf1}); machine->get_memory().set_at(0xf1, 20);