Add "transfer" instructions

This commit is contained in:
Tony Di Nucci 2019-04-17 22:03:06 +01:00
parent d987a4849e
commit 534c5576f8
11 changed files with 289 additions and 11 deletions

View File

@ -13,12 +13,12 @@ namespace emu_6502 {
}
template<typename T>
const T Register<T>::get_value() {
T Register<T>::get_value() const {
return value;
}
template<typename T>
const string& Register<T>::get_name() {
const string& Register<T>::get_name() const {
return name;
}
}

View File

@ -20,9 +20,9 @@ namespace emu_6502 {
Register<T>(const Register<T>&) = delete;
Register<T>& operator=(const Register<T>&) = delete;
const string& get_name();
const string& get_name() const;
const T get_value();
T get_value() const;
void set_value(T value);
};
}

View File

@ -51,7 +51,8 @@ namespace emu_6502 {
public:
LoadOpcodeHandlerContainer();
LoadOpcodeHandlerContainer(const LoadOpcodeHandlerContainer& other) = delete;
LoadOpcodeHandlerContainer(const LoadOpcodeHandlerContainer&) = delete;
LoadOpcodeHandlerContainer& operator=(const LoadOpcodeHandlerContainer&) = delete;
};
}

View File

@ -15,6 +15,7 @@ namespace emu_6502 {
public:
OpcodeHandlerContainer();
OpcodeHandlerContainer(const OpcodeHandlerContainer& other) = delete;
OpcodeHandlerContainer operator=(const OpcodeHandlerContainer& other) = delete;
virtual ~OpcodeHandlerContainer() {};

View File

@ -45,6 +45,7 @@ namespace emu_6502 {
public:
StoreOpcodeHandlerContainer();
StoreOpcodeHandlerContainer(const StoreOpcodeHandlerContainer& other) = delete;
StoreOpcodeHandlerContainer operator=(const StoreOpcodeHandlerContainer& other) = delete;
};
}

View File

@ -0,0 +1,42 @@
#include "transfer-opcode-handler-container.h"
namespace emu_6502 {
TransferOpcodeHandlerContainer::TransferOpcodeHandlerContainer() : OpcodeHandlerContainer() {
handlers.insert({Op::TAX, [this](Machine& machine) {
transfer(machine, machine.get_cpu().get_a(), machine.get_cpu().get_x());
}});
handlers.insert({Op::TAY, [this](Machine& machine) {
transfer(machine, machine.get_cpu().get_a(), machine.get_cpu().get_y());
}});
handlers.insert({Op::TSX, [this](Machine& machine) {
transfer(machine, machine.get_cpu().get_sp(), machine.get_cpu().get_x());
}});
handlers.insert({Op::TXA, [this](Machine& machine) {
transfer(machine, machine.get_cpu().get_x(), machine.get_cpu().get_a());
}});
handlers.insert({Op::TXS, [this](Machine& machine) {
transfer(machine, machine.get_cpu().get_x(), machine.get_cpu().get_sp(), true);
}});
handlers.insert({Op::TYA, [this](Machine& machine) {
transfer(machine, machine.get_cpu().get_y(), machine.get_cpu().get_a());
}});
}
void TransferOpcodeHandlerContainer::transfer(Machine& machine, const Register<uint8_t>& source,
Register<uint8_t>& dest, bool ignoreFlags) {
auto value = source.get_value();
dest.set_value(value);
if (!ignoreFlags) {
auto& ps = machine.get_cpu().get_ps();
ps.set_zero(value == 0);
ps.set_negative((value & 0x80) == 0x80);
}
}
}

View File

@ -0,0 +1,30 @@
#ifndef INC_6502_EMULATOR_TRANSFER_OPCODE_HANDLER_CONTAINER_H
#define INC_6502_EMULATOR_TRANSFER_OPCODE_HANDLER_CONTAINER_H
#include "opcode-handler-container.h"
#include "../../machine/register.h"
namespace emu_6502 {
class TransferOpcodeHandlerContainer : public OpcodeHandlerContainer {
private:
enum Op {
TAX = 0xAA,
TAY = 0xA8,
TSX = 0xBA,
TXA = 0x8A,
TXS = 0x9A,
TYA = 0x98
};
void transfer(Machine& machine, const Register<uint8_t>& source, Register<uint8_t>& dest,
bool ignoreFlags = false);
public:
TransferOpcodeHandlerContainer();
TransferOpcodeHandlerContainer(const TransferOpcodeHandlerContainer&) = delete;
TransferOpcodeHandlerContainer operator=(const TransferOpcodeHandlerContainer&) = delete;
};
}
#endif //INC_6502_EMULATOR_TRANSFER_OPCODE_HANDLER_CONTAINER_H

View File

@ -1,6 +1,7 @@
#include "opcode-handler-directory.h"
#include "handler/load-opcode-handler-container.h"
#include "handler/store-opcode-handler-container.h"
#include "handler/transfer-opcode-handler-container.h"
#include "../utils.h"
namespace emu_6502 {
@ -8,6 +9,7 @@ namespace emu_6502 {
OpcodeHandlerDirectory::OpcodeHandlerDirectory() : handler_containers{}, handlers{} {
handler_containers.push_back(make_unique<LoadOpcodeHandlerContainer>());
handler_containers.push_back(make_unique<StoreOpcodeHandlerContainer>());
handler_containers.push_back(make_unique<TransferOpcodeHandlerContainer>());
init_handlers();
}

View File

@ -1,9 +1,6 @@
#include "gtest/gtest.h"
#include "test-utils.h"
#include <memory>
#include <vector>
using namespace std;
using namespace emu_6502;

View File

@ -1,9 +1,6 @@
#include "gtest/gtest.h"
#include "test-utils.h"
#include <memory>
#include <vector>
using namespace std;
using namespace emu_6502;

View File

@ -0,0 +1,207 @@
#include "gtest/gtest.h"
#include "test-utils.h"
using namespace std;
using namespace emu_6502;
const uint8_t TAX = 0xAA;
const uint8_t TAY = 0xA8;
const uint8_t TSX = 0xBA;
const uint8_t TXA = 0x8A;
const uint8_t TXS = 0x9A;
const uint8_t TYA = 0x98;
TEST(TransferOpcodeHandlerContainer, TAX) {
auto machine = create_machine({TAX});
machine->get_cpu().get_a().set_value(0x11);
machine->execute();
ASSERT_EQ(0x11, machine->get_cpu().get_x().get_value());
ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{}));
}
TEST(TransferOpcodeHandlerContainer, TAX_ZeroFlag) {
auto machine = create_machine({TAX});
machine->get_cpu().get_a().set_value(0);
machine->execute();
ASSERT_EQ(0, machine->get_cpu().get_x().get_value());
RegisterFlagSet flags{};
flags.zero = true;
ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags));
}
TEST(TransferOpcodeHandlerContainer, TAX_NegativeFlag) {
auto machine = create_machine({TAX});
machine->get_cpu().get_a().set_value(0xf0);
machine->execute();
ASSERT_EQ(0xf0, machine->get_cpu().get_x().get_value());
RegisterFlagSet flags{};
flags.negative = true;
ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags));
}
TEST(TransferOpcodeHandlerContainer, TAY) {
auto machine = create_machine({TAY});
machine->get_cpu().get_a().set_value(0x11);
machine->execute();
ASSERT_EQ(0x11, machine->get_cpu().get_y().get_value());
ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{}));
}
TEST(TransferOpcodeHandlerContainer, TAY_ZeroFlag) {
auto machine = create_machine({TAY});
machine->get_cpu().get_a().set_value(0);
machine->execute();
ASSERT_EQ(0, machine->get_cpu().get_y().get_value());
RegisterFlagSet flags{};
flags.zero = true;
ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags));
}
TEST(TransferOpcodeHandlerContainer, TAY_NegativeFlag) {
auto machine = create_machine({TAY});
machine->get_cpu().get_a().set_value(0xf0);
machine->execute();
ASSERT_EQ(0xf0, machine->get_cpu().get_y().get_value());
RegisterFlagSet flags{};
flags.negative = true;
ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags));
}
TEST(TransferOpcodeHandlerContainer, TSX) {
auto machine = create_machine({TSX});
machine->get_cpu().get_sp().set_value(0x11);
machine->execute();
ASSERT_EQ(0x11, machine->get_cpu().get_x().get_value());
ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{}));
}
TEST(TransferOpcodeHandlerContainer, TSX_ZeroFlag) {
auto machine = create_machine({TSX});
machine->get_cpu().get_sp().set_value(0);
machine->execute();
ASSERT_EQ(0, machine->get_cpu().get_x().get_value());
RegisterFlagSet flags{};
flags.zero = true;
ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags));
}
TEST(TransferOpcodeHandlerContainer, TSX_NegativeFlag) {
auto machine = create_machine({TSX});
machine->get_cpu().get_sp().set_value(0xf0);
machine->execute();
ASSERT_EQ(0xf0, machine->get_cpu().get_x().get_value());
RegisterFlagSet flags{};
flags.negative = true;
ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags));
}
TEST(TransferOpcodeHandlerContainer, TXA) {
auto machine = create_machine({TXA});
machine->get_cpu().get_x().set_value(0x11);
machine->execute();
ASSERT_EQ(0x11, machine->get_cpu().get_a().get_value());
ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{}));
}
TEST(TransferOpcodeHandlerContainer, TXA_ZeroFlag) {
auto machine = create_machine({TXA});
machine->get_cpu().get_x().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(TransferOpcodeHandlerContainer, TXA_NegativeFlag) {
auto machine = create_machine({TXA});
machine->get_cpu().get_x().set_value(0xf0);
machine->execute();
ASSERT_EQ(0xf0, machine->get_cpu().get_a().get_value());
RegisterFlagSet flags{};
flags.negative = true;
ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags));
}
TEST(TransferOpcodeHandlerContainer, TXS) {
auto machine = create_machine({TXS});
machine->get_cpu().get_x().set_value(0x11);
machine->execute();
ASSERT_EQ(0x11, machine->get_cpu().get_sp().get_value());
ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{}));
}
TEST(TransferOpcodeHandlerContainer, TXS_ZeroFlag) {
auto machine = create_machine({TXS});
machine->get_cpu().get_x().set_value(0);
machine->execute();
ASSERT_EQ(0, machine->get_cpu().get_sp().get_value());
// flags not affected with this op
ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{}));
}
TEST(TransferOpcodeHandlerContainer, TXS_NegativeFlag) {
auto machine = create_machine({TXS});
machine->get_cpu().get_x().set_value(0xf0);
machine->execute();
ASSERT_EQ(0xf0, machine->get_cpu().get_sp().get_value());
// flags not affected with this op
ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{}));
}
TEST(TransferOpcodeHandlerContainer, TYA) {
auto machine = create_machine({TYA});
machine->get_cpu().get_y().set_value(0x11);
machine->execute();
ASSERT_EQ(0x11, machine->get_cpu().get_a().get_value());
ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{}));
}
TEST(TransferOpcodeHandlerContainer, TYA_ZeroFlag) {
auto machine = create_machine({TYA});
machine->get_cpu().get_y().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(TransferOpcodeHandlerContainer, TYA_NegativeFlag) {
auto machine = create_machine({TYA});
machine->get_cpu().get_y().set_value(0xf0);
machine->execute();
ASSERT_EQ(0xf0, machine->get_cpu().get_a().get_value());
RegisterFlagSet flags{};
flags.negative = true;
ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags));
}