Add "transfer" instructions
This commit is contained in:
parent
d987a4849e
commit
534c5576f8
|
@ -13,12 +13,12 @@ namespace emu_6502 {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
const T Register<T>::get_value() {
|
T Register<T>::get_value() const {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
const string& Register<T>::get_name() {
|
const string& Register<T>::get_name() const {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,9 @@ namespace emu_6502 {
|
||||||
Register<T>(const Register<T>&) = delete;
|
Register<T>(const Register<T>&) = delete;
|
||||||
Register<T>& operator=(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);
|
void set_value(T value);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,8 @@ namespace emu_6502 {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LoadOpcodeHandlerContainer();
|
LoadOpcodeHandlerContainer();
|
||||||
LoadOpcodeHandlerContainer(const LoadOpcodeHandlerContainer& other) = delete;
|
LoadOpcodeHandlerContainer(const LoadOpcodeHandlerContainer&) = delete;
|
||||||
|
LoadOpcodeHandlerContainer& operator=(const LoadOpcodeHandlerContainer&) = delete;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ namespace emu_6502 {
|
||||||
public:
|
public:
|
||||||
OpcodeHandlerContainer();
|
OpcodeHandlerContainer();
|
||||||
OpcodeHandlerContainer(const OpcodeHandlerContainer& other) = delete;
|
OpcodeHandlerContainer(const OpcodeHandlerContainer& other) = delete;
|
||||||
|
OpcodeHandlerContainer operator=(const OpcodeHandlerContainer& other) = delete;
|
||||||
|
|
||||||
virtual ~OpcodeHandlerContainer() {};
|
virtual ~OpcodeHandlerContainer() {};
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ namespace emu_6502 {
|
||||||
public:
|
public:
|
||||||
StoreOpcodeHandlerContainer();
|
StoreOpcodeHandlerContainer();
|
||||||
StoreOpcodeHandlerContainer(const StoreOpcodeHandlerContainer& other) = delete;
|
StoreOpcodeHandlerContainer(const StoreOpcodeHandlerContainer& other) = delete;
|
||||||
|
StoreOpcodeHandlerContainer operator=(const StoreOpcodeHandlerContainer& other) = delete;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -1,6 +1,7 @@
|
||||||
#include "opcode-handler-directory.h"
|
#include "opcode-handler-directory.h"
|
||||||
#include "handler/load-opcode-handler-container.h"
|
#include "handler/load-opcode-handler-container.h"
|
||||||
#include "handler/store-opcode-handler-container.h"
|
#include "handler/store-opcode-handler-container.h"
|
||||||
|
#include "handler/transfer-opcode-handler-container.h"
|
||||||
#include "../utils.h"
|
#include "../utils.h"
|
||||||
|
|
||||||
namespace emu_6502 {
|
namespace emu_6502 {
|
||||||
|
@ -8,6 +9,7 @@ namespace emu_6502 {
|
||||||
OpcodeHandlerDirectory::OpcodeHandlerDirectory() : handler_containers{}, handlers{} {
|
OpcodeHandlerDirectory::OpcodeHandlerDirectory() : handler_containers{}, handlers{} {
|
||||||
handler_containers.push_back(make_unique<LoadOpcodeHandlerContainer>());
|
handler_containers.push_back(make_unique<LoadOpcodeHandlerContainer>());
|
||||||
handler_containers.push_back(make_unique<StoreOpcodeHandlerContainer>());
|
handler_containers.push_back(make_unique<StoreOpcodeHandlerContainer>());
|
||||||
|
handler_containers.push_back(make_unique<TransferOpcodeHandlerContainer>());
|
||||||
|
|
||||||
init_handlers();
|
init_handlers();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "test-utils.h"
|
#include "test-utils.h"
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace emu_6502;
|
using namespace emu_6502;
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "test-utils.h"
|
#include "test-utils.h"
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace emu_6502;
|
using namespace emu_6502;
|
||||||
|
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
Loading…
Reference in New Issue