mirror of
https://github.com/tdinucci/6502-emulator.git
synced 2025-02-17 08:30:39 +00:00
More opcodes
This commit is contained in:
parent
2bcafa836d
commit
b2baba888f
@ -25,9 +25,9 @@ add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src
|
||||
|
||||
file(GLOB_RECURSE test_src "test/**.h" "test/**.cpp" "src/**.h" "src/**.cpp")
|
||||
list(FILTER test_src EXCLUDE REGEX ".*/6502-emulator/src/main.cpp$")
|
||||
add_executable(6502_emulator_test ${test_src})
|
||||
add_executable(6502_emulator_test ${test_src} test/stack-opcode-handler-test.cpp test/ldx-opcode-handler-test.cpp)
|
||||
target_link_libraries(6502_emulator_test gtest_main)
|
||||
add_test(NAME run_tests COMMAND 6502_emulator_test)
|
||||
|
||||
file(GLOB_RECURSE emulator_src "src/**.h" "src/**.cpp")
|
||||
add_executable(6502_emulator ${emulator_src})
|
||||
add_executable(6502_emulator ${emulator_src} src/opcode/handler/stack-opcode-handler.cpp src/opcode/handler/stack-opcode-handler.h src/stack.cpp src/stack.h src/opcode/handler/lda-opcode-handler.cpp src/opcode/handler/lda-opcode-handler.h)
|
||||
|
@ -6,7 +6,7 @@ Machine::Machine(shared_ptr<Program> program) {
|
||||
this->program = program;
|
||||
memory = make_shared<Memory>(Memory());
|
||||
reg_man = make_shared<RegisterManager>(RegisterManager());
|
||||
opcode_handler_dir = make_shared<OpcodeHandlerDirectory>(OpcodeHandlerDirectory(program, reg_man));
|
||||
opcode_handler_dir = make_shared<OpcodeHandlerDirectory>(OpcodeHandlerDirectory(program, reg_man, memory));
|
||||
instruction_executor =
|
||||
make_unique<InstructionExecutor>(InstructionExecutor(program, reg_man, opcode_handler_dir));
|
||||
}
|
||||
|
@ -2,13 +2,22 @@
|
||||
#include <stdexcept>
|
||||
|
||||
Memory::Memory() {
|
||||
bytes = make_shared<vector<uint8_t>>(vector<uint8_t>((1024 * 64) - 1));
|
||||
bytes = make_unique<vector<uint8_t>>(vector<uint8_t>(0xFFFF));
|
||||
stack = make_unique<Stack>(Stack());
|
||||
}
|
||||
|
||||
void Memory::set_byte_at(uint16_t index, uint8_t value) {
|
||||
bytes->at(index) = value;
|
||||
}
|
||||
|
||||
uint8_t Memory::get_byte_at(uint16_t index) {
|
||||
auto size = bytes->size();
|
||||
if (size == 0 || bytes->size() - 1 < index)
|
||||
throw runtime_error("Attempted to read past end of memory");
|
||||
|
||||
return bytes->at(index);
|
||||
}
|
||||
|
||||
void Memory::stack_push(uint8_t data) {
|
||||
stack->push(data);
|
||||
}
|
||||
|
||||
uint8_t Memory::stack_pop() {
|
||||
return stack->pop();
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
#ifndef INC_6502_EMULATOR_MEMORY_H
|
||||
#define INC_6502_EMULATOR_MEMORY_H
|
||||
|
||||
|
||||
#include "stack.h"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
@ -11,10 +11,14 @@ class Memory {
|
||||
public:
|
||||
explicit Memory();
|
||||
|
||||
void set_byte_at(uint16_t index, uint8_t value);
|
||||
uint8_t get_byte_at(uint16_t index);
|
||||
|
||||
void stack_push(uint8_t data);
|
||||
uint8_t stack_pop();
|
||||
private:
|
||||
shared_ptr<vector<uint8_t>> bytes;
|
||||
unique_ptr<vector<uint8_t>> bytes;
|
||||
unique_ptr<Stack> stack;
|
||||
};
|
||||
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
#ifndef INC_6502_EMULATOR_FLAG_OPCODE_HANDLER_H
|
||||
#define INC_6502_EMULATOR_FLAG_OPCODE_HANDLER_H
|
||||
|
||||
#include "../../program.h"
|
||||
#include "../opcode-handler.h"
|
||||
|
||||
class FlagOpcodeHandler : public OpcodeHandler {
|
||||
@ -14,8 +13,9 @@ public:
|
||||
static const uint8_t CLD = 0xD8;
|
||||
static const uint8_t SED = 0xF8;
|
||||
|
||||
explicit FlagOpcodeHandler(shared_ptr<Program> program, shared_ptr<RegisterManager> reg_man) :
|
||||
OpcodeHandler(program, reg_man) {
|
||||
explicit FlagOpcodeHandler(shared_ptr<Program> program, shared_ptr<RegisterManager> reg_man,
|
||||
shared_ptr<Memory> memory) :
|
||||
OpcodeHandler(program, reg_man, memory) {
|
||||
handled_opcodes->push_back(CLC);
|
||||
handled_opcodes->push_back(SEC);
|
||||
handled_opcodes->push_back(CLI);
|
||||
|
5
src/opcode/handler/lda-opcode-handler.cpp
Normal file
5
src/opcode/handler/lda-opcode-handler.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
//
|
||||
// Created by tony on 27/03/19.
|
||||
//
|
||||
|
||||
#include "lda-opcode-handler.h"
|
14
src/opcode/handler/lda-opcode-handler.h
Normal file
14
src/opcode/handler/lda-opcode-handler.h
Normal file
@ -0,0 +1,14 @@
|
||||
//
|
||||
// Created by tony on 27/03/19.
|
||||
//
|
||||
|
||||
#ifndef INC_6502_EMULATOR_LDA_OPCODE_HANDLER_H
|
||||
#define INC_6502_EMULATOR_LDA_OPCODE_HANDLER_H
|
||||
|
||||
|
||||
class LdaOpcodeHandler {
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //INC_6502_EMULATOR_LDA_OPCODE_HANDLER_H
|
@ -3,25 +3,55 @@
|
||||
|
||||
const uint8_t LdxOpcodeHandler::IMMEDIATE;
|
||||
const uint8_t LdxOpcodeHandler::ZERO_PAGE;
|
||||
const uint8_t LdxOpcodeHandler::ZERO_PAGE_X;
|
||||
const uint8_t LdxOpcodeHandler::ZERO_PAGE_Y;
|
||||
const uint8_t LdxOpcodeHandler::ABSOLUTE;
|
||||
const uint8_t LdxOpcodeHandler::ABSOLUTE_X;
|
||||
const uint8_t LdxOpcodeHandler::ABSOLUTE_Y;
|
||||
const uint8_t LdxOpcodeHandler::INDIRECT_X;
|
||||
const uint8_t LdxOpcodeHandler::INDIRECT_Y;
|
||||
|
||||
void LdxOpcodeHandler::execute() {
|
||||
auto instructionIndex = reg_man->get_program_counter()->get_value();
|
||||
auto opcode = program->get_byte_at(instructionIndex);
|
||||
auto byte2 = program->get_byte_at(instructionIndex + 1);
|
||||
auto accumulator = reg_man->get_accumulator();
|
||||
auto x_reg = reg_man->get_x_index();
|
||||
|
||||
switch (opcode) {
|
||||
case IMMEDIATE:
|
||||
accumulator->set_value(byte2);
|
||||
x_reg->set_value(byte2);
|
||||
move_program_counter(2);
|
||||
break;
|
||||
|
||||
case ZERO_PAGE:
|
||||
x_reg->set_value(memory->get_byte_at(byte2));
|
||||
move_program_counter(2);
|
||||
break;
|
||||
|
||||
case ZERO_PAGE_Y: {
|
||||
uint16_t address = byte2 + reg_man->get_y_index()->get_value();
|
||||
|
||||
x_reg->set_value(memory->get_byte_at(address));
|
||||
move_program_counter(2);
|
||||
break;
|
||||
}
|
||||
|
||||
case ABSOLUTE: {
|
||||
auto low = byte2;
|
||||
auto high = program->get_byte_at(instructionIndex + 2);
|
||||
uint16_t address = (high << 8) + low;
|
||||
|
||||
x_reg->set_value(memory->get_byte_at(address));
|
||||
move_program_counter(3);
|
||||
break;
|
||||
}
|
||||
|
||||
case ABSOLUTE_Y: {
|
||||
auto low = byte2;
|
||||
auto high = program->get_byte_at(instructionIndex + 2);
|
||||
uint16_t address = (high << 8) + low + reg_man->get_y_index()->get_value();
|
||||
|
||||
x_reg->set_value(memory->get_byte_at(address));
|
||||
move_program_counter(3);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
stringstream stream;
|
||||
stream << "Unexpected opcode 0x" << hex << opcode;
|
||||
|
@ -6,25 +6,20 @@
|
||||
|
||||
class LdxOpcodeHandler : public OpcodeHandler {
|
||||
public:
|
||||
static const uint8_t IMMEDIATE = 0xA9;
|
||||
static const uint8_t ZERO_PAGE = 0xA5;
|
||||
static const uint8_t ZERO_PAGE_X = 0xB5;
|
||||
static const uint8_t ABSOLUTE = 0xAD;
|
||||
static const uint8_t ABSOLUTE_X = 0xBD;
|
||||
static const uint8_t ABSOLUTE_Y = 0xB9;
|
||||
static const uint8_t INDIRECT_X = 0xA1;
|
||||
static const uint8_t INDIRECT_Y = 0xB1;
|
||||
static const uint8_t IMMEDIATE = 0xA2;
|
||||
static const uint8_t ZERO_PAGE = 0xA6;
|
||||
static const uint8_t ZERO_PAGE_Y = 0xB6;
|
||||
static const uint8_t ABSOLUTE = 0xAE;
|
||||
static const uint8_t ABSOLUTE_Y = 0xBE;
|
||||
|
||||
explicit LdxOpcodeHandler(shared_ptr<Program> program, shared_ptr<RegisterManager> reg_man) :
|
||||
OpcodeHandler(program, reg_man) {
|
||||
explicit LdxOpcodeHandler(shared_ptr<Program> program, shared_ptr<RegisterManager> reg_man,
|
||||
shared_ptr<Memory> memory) :
|
||||
OpcodeHandler(program, reg_man, memory) {
|
||||
handled_opcodes->push_back(IMMEDIATE);
|
||||
handled_opcodes->push_back(ZERO_PAGE);
|
||||
handled_opcodes->push_back(ZERO_PAGE_X);
|
||||
handled_opcodes->push_back(ZERO_PAGE_Y);
|
||||
handled_opcodes->push_back(ABSOLUTE);
|
||||
handled_opcodes->push_back(ABSOLUTE_X);
|
||||
handled_opcodes->push_back(ABSOLUTE_Y);
|
||||
handled_opcodes->push_back(INDIRECT_X);
|
||||
handled_opcodes->push_back(INDIRECT_Y);
|
||||
}
|
||||
|
||||
virtual void execute() override;
|
||||
|
@ -15,8 +15,9 @@ public:
|
||||
static const uint8_t DEY = 0x88;
|
||||
static const uint8_t INY = 0xC8;
|
||||
|
||||
explicit RegisterOpcodeHandler(shared_ptr<Program> program, shared_ptr<RegisterManager> reg_man) :
|
||||
OpcodeHandler(program, reg_man) {
|
||||
explicit RegisterOpcodeHandler(shared_ptr<Program> program, shared_ptr<RegisterManager> reg_man,
|
||||
shared_ptr<Memory> memory) :
|
||||
OpcodeHandler(program, reg_man, memory) {
|
||||
handled_opcodes->push_back(TAX);
|
||||
handled_opcodes->push_back(TXA);
|
||||
handled_opcodes->push_back(DEX);
|
||||
|
43
src/opcode/handler/stack-opcode-handler.cpp
Normal file
43
src/opcode/handler/stack-opcode-handler.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
#include "stack-opcode-handler.h"
|
||||
#include <sstream>
|
||||
#include <climits>
|
||||
|
||||
const uint8_t StackOpcodeHandler::PHA;
|
||||
const uint8_t StackOpcodeHandler::PLA;
|
||||
const uint8_t StackOpcodeHandler::PHP;
|
||||
const uint8_t StackOpcodeHandler::PLP;
|
||||
|
||||
void StackOpcodeHandler::execute() {
|
||||
auto instructionIndex = reg_man->get_program_counter()->get_value();
|
||||
auto opcode = program->get_byte_at(instructionIndex);
|
||||
|
||||
switch (opcode) {
|
||||
case PHA:
|
||||
memory->stack_push(reg_man->get_accumulator()->get_value());
|
||||
break;
|
||||
|
||||
case PLA:
|
||||
reg_man->get_accumulator()->set_value(memory->stack_pop());
|
||||
break;
|
||||
|
||||
case PHP: {
|
||||
ulong long_data = reg_man->get_status_register()->get_value().to_ulong();
|
||||
auto data = static_cast<uint8_t>(long_data);
|
||||
memory->stack_push(data);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLP: {
|
||||
auto data = memory->stack_pop();
|
||||
reg_man->get_status_register()->set_value(bitset<8>(data));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
stringstream stream;
|
||||
stream << "Unexpected opcode 0x" << hex << opcode;
|
||||
throw runtime_error(stream.str());
|
||||
}
|
||||
|
||||
move_program_counter(1);
|
||||
}
|
27
src/opcode/handler/stack-opcode-handler.h
Normal file
27
src/opcode/handler/stack-opcode-handler.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef INC_6502_EMULATOR_STACK_OPCODE_HANDLER_H
|
||||
#define INC_6502_EMULATOR_STACK_OPCODE_HANDLER_H
|
||||
|
||||
#include "../../program.h"
|
||||
#include "../opcode-handler.h"
|
||||
|
||||
class StackOpcodeHandler : public OpcodeHandler {
|
||||
public:
|
||||
static const uint8_t PHA = 0x48;
|
||||
static const uint8_t PLA = 0x68;
|
||||
static const uint8_t PHP = 0x08;
|
||||
static const uint8_t PLP = 0x28;
|
||||
|
||||
explicit StackOpcodeHandler(shared_ptr<Program> program, shared_ptr<RegisterManager> reg_man,
|
||||
shared_ptr<Memory> memory) :
|
||||
OpcodeHandler(program, reg_man, memory) {
|
||||
handled_opcodes->push_back(PHA);
|
||||
handled_opcodes->push_back(PLA);
|
||||
handled_opcodes->push_back(PHP);
|
||||
handled_opcodes->push_back(PLP);
|
||||
}
|
||||
|
||||
virtual void execute() override;
|
||||
};
|
||||
|
||||
|
||||
#endif //INC_6502_EMULATOR_STACK_OPCODE_HANDLER_H
|
@ -2,16 +2,18 @@
|
||||
#include "handler/flag-opcode-handler.h"
|
||||
#include "handler/register-opcode-handler.h"
|
||||
#include "handler/ldx-opcode-handler.h"
|
||||
#include "handler/stack-opcode-handler.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
OpcodeHandlerDirectory::OpcodeHandlerDirectory(shared_ptr<Program> program, shared_ptr<RegisterManager> reg_man) {
|
||||
OpcodeHandlerDirectory::OpcodeHandlerDirectory(shared_ptr<Program> program, shared_ptr<RegisterManager> reg_man, shared_ptr<Memory> memory) {
|
||||
handlers = make_unique<unordered_map<uint8_t, shared_ptr<OpcodeHandler>>>();
|
||||
|
||||
register_handler(make_shared<FlagOpcodeHandler>(program, reg_man));
|
||||
register_handler(make_shared<RegisterOpcodeHandler>(program, reg_man));
|
||||
register_handler(make_shared<LdxOpcodeHandler>(program, reg_man));
|
||||
register_handler(make_shared<FlagOpcodeHandler>(FlagOpcodeHandler(program, reg_man, memory)));
|
||||
register_handler(make_shared<RegisterOpcodeHandler>(RegisterOpcodeHandler(program, reg_man, memory)));
|
||||
register_handler(make_shared<LdxOpcodeHandler>(LdxOpcodeHandler(program, reg_man, memory)));
|
||||
register_handler(make_shared<StackOpcodeHandler>(StackOpcodeHandler(program, reg_man, memory)));
|
||||
}
|
||||
|
||||
void OpcodeHandlerDirectory::register_handler(shared_ptr<OpcodeHandler> handler) {
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define INC_6502_EMULATOR_OPCODE_HANDLER_DIRECTORY_H
|
||||
|
||||
#include "../program.h"
|
||||
#include "../memory.h"
|
||||
#include "opcode-handler.h"
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
@ -11,7 +12,7 @@ using namespace std;
|
||||
|
||||
class OpcodeHandlerDirectory {
|
||||
public:
|
||||
explicit OpcodeHandlerDirectory(shared_ptr<Program> program, shared_ptr<RegisterManager> reg_man);
|
||||
explicit OpcodeHandlerDirectory(shared_ptr<Program> program, shared_ptr<RegisterManager> reg_man, shared_ptr<Memory> memory);
|
||||
|
||||
shared_ptr<OpcodeHandler> get_handler(uint8_t opcode);
|
||||
private:
|
||||
|
@ -1,9 +1,10 @@
|
||||
#include "../program.h"
|
||||
#include "opcode-handler.h"
|
||||
|
||||
OpcodeHandler::OpcodeHandler(shared_ptr<Program> program, shared_ptr<RegisterManager> reg_man) {
|
||||
OpcodeHandler::OpcodeHandler(shared_ptr<Program> program, shared_ptr<RegisterManager> reg_man,
|
||||
shared_ptr<Memory> memory) {
|
||||
this->program = program;
|
||||
this->reg_man = reg_man;
|
||||
this->memory = memory;
|
||||
}
|
||||
|
||||
void OpcodeHandler::move_program_counter(uint8_t forward_by) {
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define INC_6502_EMULATOR_OPCODE_HANDLER_H
|
||||
|
||||
#include "../program.h"
|
||||
#include "../memory.h"
|
||||
#include "../register/register-manager.h"
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
@ -10,7 +11,7 @@ using namespace std;
|
||||
|
||||
class OpcodeHandler {
|
||||
public:
|
||||
OpcodeHandler(shared_ptr<Program> program, shared_ptr<RegisterManager> reg_man);
|
||||
OpcodeHandler(shared_ptr<Program> program, shared_ptr<RegisterManager> reg_man, shared_ptr<Memory> memory);
|
||||
|
||||
shared_ptr<vector<uint8_t>> get_handled_opcodes() { return handled_opcodes; }
|
||||
|
||||
@ -19,6 +20,7 @@ public:
|
||||
protected:
|
||||
shared_ptr<vector<uint8_t>> handled_opcodes = make_shared<vector<uint8_t>>();
|
||||
shared_ptr<Program> program;
|
||||
shared_ptr<Memory> memory;
|
||||
shared_ptr<RegisterManager> reg_man;
|
||||
|
||||
void move_program_counter(uint8_t forward_by);
|
||||
|
26
src/stack.cpp
Normal file
26
src/stack.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
#include "stack.h"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
const uint8_t Stack::MAX_SIZE;
|
||||
|
||||
Stack::Stack() {
|
||||
data = make_unique<stack<uint8_t>>(stack<uint8_t>());
|
||||
}
|
||||
|
||||
void Stack::push(uint8_t byte) {
|
||||
if (data->size() >= MAX_SIZE)
|
||||
throw runtime_error("Stack overflow");
|
||||
|
||||
data->push(byte);
|
||||
}
|
||||
|
||||
uint8_t Stack::pop() {
|
||||
if (data->empty())
|
||||
throw runtime_error("Stack is empty");
|
||||
|
||||
auto result = data->top();
|
||||
data->pop();
|
||||
|
||||
return result;
|
||||
}
|
22
src/stack.h
Normal file
22
src/stack.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef INC_6502_EMULATOR_STACK_H
|
||||
#define INC_6502_EMULATOR_STACK_H
|
||||
|
||||
#include <memory>
|
||||
#include <stack>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class Stack {
|
||||
public:
|
||||
explicit Stack();
|
||||
|
||||
void push(uint8_t byte);
|
||||
uint8_t pop();
|
||||
|
||||
private:
|
||||
static const uint8_t MAX_SIZE = 0xFF;
|
||||
unique_ptr<stack<uint8_t>> data;
|
||||
};
|
||||
|
||||
|
||||
#endif //INC_6502_EMULATOR_STACK_H
|
@ -22,7 +22,8 @@ TEST(InstructionExecutor, Execute) {
|
||||
CLC
|
||||
});
|
||||
auto program = make_shared<Program>(Program(code));
|
||||
auto opcode_handler_dir = make_shared<OpcodeHandlerDirectory>(OpcodeHandlerDirectory(program, reg_man));
|
||||
auto memory = make_shared<Memory>(Memory());
|
||||
auto opcode_handler_dir = make_shared<OpcodeHandlerDirectory>(OpcodeHandlerDirectory(program, reg_man, memory));
|
||||
auto executor = make_unique<InstructionExecutor>(InstructionExecutor(program, reg_man, opcode_handler_dir));
|
||||
|
||||
executor->execute();
|
||||
|
106
test/ldx-opcode-handler-test.cpp
Normal file
106
test/ldx-opcode-handler-test.cpp
Normal file
@ -0,0 +1,106 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "../src/machine.h"
|
||||
#include "../src/program.h"
|
||||
#include "../src/opcode/handler/stack-opcode-handler.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
const uint8_t IMMEDIATE = 0xA2;
|
||||
const uint8_t ZERO_PAGE = 0xA6;
|
||||
const uint8_t ZERO_PAGE_Y = 0xB6;
|
||||
const uint8_t ABSOLUTE = 0xAE;
|
||||
const uint8_t ABSOLUTE_Y = 0xBE;
|
||||
|
||||
unique_ptr<Machine> ldxt_get_machine(shared_ptr<vector<uint8_t>> code) {
|
||||
auto program = make_shared<Program>(Program(code));
|
||||
auto machine = make_unique<Machine>(Machine(program));
|
||||
return machine;
|
||||
}
|
||||
|
||||
TEST(LdxOpcodeHandler, Immediate) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{IMMEDIATE, 36});
|
||||
auto machine = ldxt_get_machine(code);
|
||||
auto reg_man = machine->get_reg_man();
|
||||
auto x_reg = reg_man->get_x_index();
|
||||
|
||||
ASSERT_EQ(0, x_reg->get_value());
|
||||
|
||||
machine->execute();
|
||||
|
||||
ASSERT_EQ(36, x_reg->get_value());
|
||||
}
|
||||
|
||||
TEST(LdxOpcodeHandler, ZeroPage) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{ZERO_PAGE, 123});
|
||||
auto machine = ldxt_get_machine(code);
|
||||
auto reg_man = machine->get_reg_man();
|
||||
auto x_reg = reg_man->get_x_index();
|
||||
|
||||
ASSERT_EQ(0, x_reg->get_value());
|
||||
|
||||
machine->get_memory()->set_byte_at(123, 78);
|
||||
machine->execute();
|
||||
|
||||
ASSERT_EQ(78, x_reg->get_value());
|
||||
}
|
||||
|
||||
TEST(LdxOpcodeHandler, ZeroPageY) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{ZERO_PAGE_Y, 250});
|
||||
auto machine = ldxt_get_machine(code);
|
||||
auto reg_man = machine->get_reg_man();
|
||||
auto x_reg = reg_man->get_x_index();
|
||||
auto y_reg = reg_man->get_y_index();
|
||||
|
||||
ASSERT_EQ(0, x_reg->get_value());
|
||||
ASSERT_EQ(0, y_reg->get_value());
|
||||
machine->get_memory()->set_byte_at(250, 255);
|
||||
machine->execute();
|
||||
ASSERT_EQ(255, x_reg->get_value());
|
||||
|
||||
reg_man->get_y_index()->set_value(100);
|
||||
reg_man->get_program_counter()->set_value(0);
|
||||
machine->execute();
|
||||
ASSERT_EQ(0, x_reg->get_value());
|
||||
|
||||
machine->get_memory()->set_byte_at(350, 233);
|
||||
reg_man->get_program_counter()->set_value(0);
|
||||
machine->execute();
|
||||
ASSERT_EQ(233, x_reg->get_value());
|
||||
}
|
||||
|
||||
TEST(LdxOpcodeHandler, Absolute) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{ABSOLUTE, 0xe5, 0xff});
|
||||
auto machine = ldxt_get_machine(code);
|
||||
auto reg_man = machine->get_reg_man();
|
||||
auto x_reg = reg_man->get_x_index();
|
||||
|
||||
ASSERT_EQ(0, x_reg->get_value());
|
||||
|
||||
machine->get_memory()->set_byte_at(0xffe5, 0xde);
|
||||
machine->execute();
|
||||
|
||||
ASSERT_EQ(0xde, x_reg->get_value());
|
||||
}
|
||||
|
||||
TEST(LdxOpcodeHandler, AbsoluteY) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{ABSOLUTE_Y, 0x33, 0xc2});
|
||||
auto machine = ldxt_get_machine(code);
|
||||
auto reg_man = machine->get_reg_man();
|
||||
auto x_reg = reg_man->get_x_index();
|
||||
auto y_reg = reg_man->get_y_index();
|
||||
|
||||
ASSERT_EQ(0, x_reg->get_value());
|
||||
ASSERT_EQ(0, y_reg->get_value());
|
||||
machine->get_memory()->set_byte_at(0xc233, 0xc8);
|
||||
machine->execute();
|
||||
ASSERT_EQ(0xc8, x_reg->get_value());
|
||||
|
||||
y_reg->set_value(0x55);
|
||||
machine->get_memory()->set_byte_at(0xc233 + 0x55, 0xab);
|
||||
reg_man->get_program_counter()->set_value(0);
|
||||
machine->execute();
|
||||
ASSERT_EQ(0xab, x_reg->get_value());
|
||||
}
|
112
test/stack-opcode-handler-test.cpp
Normal file
112
test/stack-opcode-handler-test.cpp
Normal file
@ -0,0 +1,112 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "../src/machine.h"
|
||||
#include "../src/program.h"
|
||||
#include "../src/opcode/handler/stack-opcode-handler.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
const uint8_t PHA = 0x48;
|
||||
const uint8_t PLA = 0x68;
|
||||
const uint8_t PHP = 0x08;
|
||||
const uint8_t PLP = 0x28;
|
||||
|
||||
unique_ptr<Machine> st_get_machine(shared_ptr<vector<uint8_t>> code) {
|
||||
auto program = make_shared<Program>(Program(code));
|
||||
auto machine = make_unique<Machine>(Machine(program));
|
||||
return machine;
|
||||
}
|
||||
|
||||
TEST(StackOpcodeHandler, PushAccumulator) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{PHA});
|
||||
auto machine = st_get_machine(code);
|
||||
auto reg_man = machine->get_reg_man();
|
||||
|
||||
reg_man->get_accumulator()->set_value(0x8b);
|
||||
ASSERT_EQ(0x8b, reg_man->get_accumulator()->get_value());
|
||||
|
||||
// stack is empty
|
||||
ASSERT_THROW(machine->get_memory()->stack_pop(), runtime_error);
|
||||
|
||||
machine->execute();
|
||||
|
||||
ASSERT_EQ(0x8b, reg_man->get_accumulator()->get_value());
|
||||
auto stack_value = machine->get_memory()->stack_pop();
|
||||
|
||||
ASSERT_EQ(0x8b, stack_value);
|
||||
|
||||
// stack is empty again
|
||||
ASSERT_THROW(machine->get_memory()->stack_pop(), runtime_error);
|
||||
}
|
||||
|
||||
TEST(StackOpcodeHandler, PullAccumulator) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{PLA});
|
||||
auto machine = st_get_machine(code);
|
||||
auto reg_man = machine->get_reg_man();
|
||||
|
||||
machine->get_memory()->stack_push(1);
|
||||
machine->get_memory()->stack_push(2);
|
||||
machine->get_memory()->stack_push(3);
|
||||
|
||||
machine->execute();
|
||||
ASSERT_EQ(3, reg_man->get_accumulator()->get_value());
|
||||
|
||||
reg_man->get_program_counter()->set_value(0);
|
||||
machine->execute();
|
||||
ASSERT_EQ(2, reg_man->get_accumulator()->get_value());
|
||||
|
||||
reg_man->get_program_counter()->set_value(0);
|
||||
machine->execute();
|
||||
ASSERT_EQ(1, reg_man->get_accumulator()->get_value());
|
||||
|
||||
// stack is empty
|
||||
ASSERT_THROW(machine->get_memory()->stack_pop(), runtime_error);
|
||||
}
|
||||
|
||||
TEST(StackOpcodeHandler, PushStatus) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{PHP});
|
||||
auto machine = st_get_machine(code);
|
||||
auto reg_man = machine->get_reg_man();
|
||||
|
||||
reg_man->get_status_register()->set_value(255);
|
||||
ASSERT_EQ(255, reg_man->get_status_register()->get_value().to_ulong());
|
||||
|
||||
// stack is empty
|
||||
ASSERT_THROW(machine->get_memory()->stack_pop(), runtime_error);
|
||||
|
||||
machine->execute();
|
||||
|
||||
ASSERT_EQ(255, reg_man->get_status_register()->get_value().to_ulong());
|
||||
auto stack_value = machine->get_memory()->stack_pop();
|
||||
|
||||
ASSERT_EQ(255, stack_value);
|
||||
|
||||
// stack is empty again
|
||||
ASSERT_THROW(machine->get_memory()->stack_pop(), runtime_error);
|
||||
}
|
||||
|
||||
TEST(StackOpcodeHandler, PullStatus) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{PLP});
|
||||
auto machine = st_get_machine(code);
|
||||
auto reg_man = machine->get_reg_man();
|
||||
|
||||
machine->get_memory()->stack_push(8);
|
||||
machine->get_memory()->stack_push(16);
|
||||
machine->get_memory()->stack_push(32);
|
||||
|
||||
machine->execute();
|
||||
ASSERT_EQ(32, reg_man->get_status_register()->get_value().to_ulong());
|
||||
|
||||
reg_man->get_program_counter()->set_value(0);
|
||||
machine->execute();
|
||||
ASSERT_EQ(16, reg_man->get_status_register()->get_value().to_ulong());
|
||||
|
||||
reg_man->get_program_counter()->set_value(0);
|
||||
machine->execute();
|
||||
ASSERT_EQ(8, reg_man->get_status_register()->get_value().to_ulong());
|
||||
|
||||
// stack is empty
|
||||
ASSERT_THROW(machine->get_memory()->stack_pop(), runtime_error);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user