More opcodes
This commit is contained in:
parent
b2baba888f
commit
ad1015759e
|
@ -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} test/stack-opcode-handler-test.cpp test/ldx-opcode-handler-test.cpp)
|
||||
add_executable(6502_emulator_test ${test_src})
|
||||
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} 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)
|
||||
add_executable(6502_emulator ${emulator_src})
|
||||
|
|
34
src/main.cpp
34
src/main.cpp
|
@ -1,42 +1,10 @@
|
|||
#include "register/register-manager.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
using namespace std;
|
||||
|
||||
void stack_test(string astring) {
|
||||
astring.push_back('x');
|
||||
}
|
||||
|
||||
void heap_test(shared_ptr<string> astring){
|
||||
astring->push_back('y');
|
||||
}
|
||||
|
||||
int main() {
|
||||
auto reg = unique_ptr<Register<uint8_t>>(new Register<uint8_t>("PC"));
|
||||
|
||||
cout << "Register: " << reg->get_name() << " " << to_string(56) << endl;
|
||||
|
||||
string astr = "hello";
|
||||
shared_ptr<string> bstr = make_shared<string>("there");
|
||||
|
||||
cout << astr << " - " << bstr->c_str() << endl;
|
||||
|
||||
stack_test(astr);
|
||||
heap_test(bstr);
|
||||
|
||||
cout << astr << " - " << bstr->c_str() << endl;
|
||||
|
||||
auto reg_man = new RegisterManager();
|
||||
auto accum = reg_man->get_accumulator();
|
||||
|
||||
cout << "****** " << accum->get_name() << " ******" << endl;
|
||||
cout << "****** " << reg_man->get_x_index()->get_name() << " ******" << endl;
|
||||
cout << "****** " << reg_man->get_y_index()->get_name() << " ******" << endl;
|
||||
cout << "****** " << reg_man->get_stack_pointer()->get_name() << " ******" << endl;
|
||||
cout << "****** " << reg_man->get_status_register()->get_name() << " ******" << endl;
|
||||
cout << "****** " << reg_man->get_program_counter()->get_name() << " ******" << endl;
|
||||
cout << "Only unit tests for now" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,8 +1,5 @@
|
|||
#include "flag-opcode-handler.h"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
|
||||
const uint8_t FlagOpcodeHandler::CLC;
|
||||
const uint8_t FlagOpcodeHandler::SEC;
|
||||
const uint8_t FlagOpcodeHandler::CLI;
|
||||
|
@ -39,9 +36,7 @@ void FlagOpcodeHandler::execute() {
|
|||
statusReg->set_decimal(true);
|
||||
break;
|
||||
default:
|
||||
stringstream stream;
|
||||
stream << "Unexpected opcode 0x" << hex << opcode;
|
||||
throw runtime_error(stream.str());
|
||||
throw_unexpected_opcode(opcode);
|
||||
}
|
||||
|
||||
move_program_counter(1);
|
||||
|
|
|
@ -1,5 +1,94 @@
|
|||
//
|
||||
// Created by tony on 27/03/19.
|
||||
//
|
||||
|
||||
#include "lda-opcode-handler.h"
|
||||
|
||||
const uint8_t LdaOpcodeHandler::IMMEDIATE;
|
||||
const uint8_t LdaOpcodeHandler::ZERO_PAGE;
|
||||
const uint8_t LdaOpcodeHandler::ZERO_PAGE_X;
|
||||
const uint8_t LdaOpcodeHandler::ABSOLUTE;
|
||||
const uint8_t LdaOpcodeHandler::ABSOLUTE_X;
|
||||
const uint8_t LdaOpcodeHandler::ABSOLUTE_Y;
|
||||
const uint8_t LdaOpcodeHandler::INDIRECT_X;
|
||||
const uint8_t LdaOpcodeHandler::INDIRECT_Y;
|
||||
|
||||
void LdaOpcodeHandler::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();
|
||||
|
||||
switch (opcode) {
|
||||
case IMMEDIATE:
|
||||
accumulator->set_value(byte2);
|
||||
move_program_counter(2);
|
||||
break;
|
||||
|
||||
case ZERO_PAGE:
|
||||
accumulator->set_value(memory->get_byte_at(byte2));
|
||||
move_program_counter(2);
|
||||
break;
|
||||
|
||||
case ZERO_PAGE_X: {
|
||||
// expect wrap around
|
||||
uint8_t address = byte2 + reg_man->get_x_index()->get_value();
|
||||
|
||||
accumulator->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;
|
||||
|
||||
accumulator->set_value(memory->get_byte_at(address));
|
||||
move_program_counter(3);
|
||||
break;
|
||||
}
|
||||
|
||||
case ABSOLUTE_X: {
|
||||
auto low = byte2;
|
||||
auto high = program->get_byte_at(instructionIndex + 2);
|
||||
uint16_t address = (high << 8) + low + reg_man->get_x_index()->get_value();
|
||||
|
||||
accumulator->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();
|
||||
|
||||
accumulator->set_value(memory->get_byte_at(address));
|
||||
move_program_counter(3);
|
||||
break;
|
||||
}
|
||||
|
||||
case INDIRECT_X: {
|
||||
auto paddress = reg_man->get_x_index()->get_value() + byte2;
|
||||
auto low = memory->get_byte_at(paddress);
|
||||
auto high = memory->get_byte_at(paddress + 1);
|
||||
uint16_t address = (high << 8) + low;
|
||||
|
||||
accumulator->set_value(memory->get_byte_at(address));
|
||||
move_program_counter(2);
|
||||
break;
|
||||
}
|
||||
|
||||
case INDIRECT_Y : {
|
||||
auto initial = byte2;
|
||||
auto low = memory->get_byte_at(initial);
|
||||
auto high = memory->get_byte_at(initial + 1);
|
||||
auto y = reg_man->get_y_index()->get_value();
|
||||
uint16_t address = (high << 8) + low + y;
|
||||
|
||||
accumulator->set_value(memory->get_byte_at(address));
|
||||
move_program_counter(2);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw_unexpected_opcode(opcode);
|
||||
}
|
||||
}
|
|
@ -1,13 +1,33 @@
|
|||
//
|
||||
// Created by tony on 27/03/19.
|
||||
//
|
||||
|
||||
#ifndef INC_6502_EMULATOR_LDA_OPCODE_HANDLER_H
|
||||
#define INC_6502_EMULATOR_LDA_OPCODE_HANDLER_H
|
||||
|
||||
#include "../opcode-handler.h"
|
||||
|
||||
class LdaOpcodeHandler {
|
||||
class LdaOpcodeHandler : 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;
|
||||
|
||||
explicit LdaOpcodeHandler(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(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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include "ldx-opcode-handler.h"
|
||||
#include <sstream>
|
||||
|
||||
const uint8_t LdxOpcodeHandler::IMMEDIATE;
|
||||
const uint8_t LdxOpcodeHandler::ZERO_PAGE;
|
||||
|
@ -25,7 +24,8 @@ void LdxOpcodeHandler::execute() {
|
|||
break;
|
||||
|
||||
case ZERO_PAGE_Y: {
|
||||
uint16_t address = byte2 + reg_man->get_y_index()->get_value();
|
||||
// expect wrap around
|
||||
uint8_t address = byte2 + reg_man->get_y_index()->get_value();
|
||||
|
||||
x_reg->set_value(memory->get_byte_at(address));
|
||||
move_program_counter(2);
|
||||
|
@ -53,8 +53,6 @@ void LdxOpcodeHandler::execute() {
|
|||
}
|
||||
|
||||
default:
|
||||
stringstream stream;
|
||||
stream << "Unexpected opcode 0x" << hex << opcode;
|
||||
throw runtime_error(stream.str());
|
||||
throw_unexpected_opcode(opcode);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#include "nop-opcode-handler.h"
|
||||
|
||||
const uint8_t NopOpcodeHandler::IMPLIED;
|
||||
|
||||
void NopOpcodeHandler::execute() {
|
||||
auto instructionIndex = reg_man->get_program_counter()->get_value();
|
||||
auto opcode = program->get_byte_at(instructionIndex);
|
||||
|
||||
switch (opcode) {
|
||||
case IMPLIED:
|
||||
move_program_counter(1);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw_unexpected_opcode(opcode);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef INC_6502_EMULATOR_NOP_OPCODE_HANDLER_H
|
||||
#define INC_6502_EMULATOR_NOP_OPCODE_HANDLER_H
|
||||
|
||||
#include "../opcode-handler.h"
|
||||
|
||||
class NopOpcodeHandler : public OpcodeHandler {
|
||||
public:
|
||||
static const uint8_t IMPLIED = 0xEA;
|
||||
|
||||
explicit NopOpcodeHandler(shared_ptr<Program> program, shared_ptr<RegisterManager> reg_man,
|
||||
shared_ptr<Memory> memory) :
|
||||
OpcodeHandler(program, reg_man, memory) {
|
||||
handled_opcodes->push_back(IMPLIED);
|
||||
}
|
||||
|
||||
virtual void execute() override;
|
||||
};
|
||||
|
||||
|
||||
#endif //INC_6502_EMULATOR_NOP_OPCODE_HANDLER_H
|
|
@ -1,8 +1,5 @@
|
|||
#include "register-opcode-handler.h"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
|
||||
const uint8_t RegisterOpcodeHandler::TAX;
|
||||
const uint8_t RegisterOpcodeHandler::TXA;
|
||||
const uint8_t RegisterOpcodeHandler::DEX;
|
||||
|
@ -23,31 +20,37 @@ void RegisterOpcodeHandler::execute() {
|
|||
case TAX:
|
||||
x_index->set_value(accumulator->get_value());
|
||||
break;
|
||||
|
||||
case TXA:
|
||||
accumulator->set_value(x_index->get_value());
|
||||
break;
|
||||
|
||||
case DEX:
|
||||
x_index->set_value(x_index->get_value() - 1);
|
||||
break;
|
||||
|
||||
case INX:
|
||||
x_index->set_value(x_index->get_value() + 1);
|
||||
break;
|
||||
|
||||
case TAY:
|
||||
y_index->set_value(accumulator->get_value());
|
||||
break;
|
||||
|
||||
case TYA:
|
||||
accumulator->set_value(y_index->get_value());
|
||||
break;
|
||||
|
||||
case DEY:
|
||||
y_index->set_value(y_index->get_value() - 1);
|
||||
break;
|
||||
|
||||
case INY:
|
||||
y_index->set_value(y_index->get_value() + 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
stringstream stream;
|
||||
stream << "Unexpected opcode 0x" << hex << opcode;
|
||||
throw runtime_error(stream.str());
|
||||
throw_unexpected_opcode(opcode);
|
||||
}
|
||||
|
||||
move_program_counter(1);
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#include "stack-opcode-handler.h"
|
||||
#include <sstream>
|
||||
#include <climits>
|
||||
|
||||
const uint8_t StackOpcodeHandler::PHA;
|
||||
const uint8_t StackOpcodeHandler::PLA;
|
||||
|
@ -34,9 +32,7 @@ void StackOpcodeHandler::execute() {
|
|||
}
|
||||
|
||||
default:
|
||||
stringstream stream;
|
||||
stream << "Unexpected opcode 0x" << hex << opcode;
|
||||
throw runtime_error(stream.str());
|
||||
throw_unexpected_opcode(opcode);
|
||||
}
|
||||
|
||||
move_program_counter(1);
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
#include "stx-opcode-handler.h"
|
||||
|
||||
const uint8_t StxOpcodeHandler::ZERO_PAGE;
|
||||
const uint8_t StxOpcodeHandler::ZERO_PAGE_Y;
|
||||
const uint8_t StxOpcodeHandler::ABSOLUTE;
|
||||
|
||||
void StxOpcodeHandler::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 x_reg = reg_man->get_x_index();
|
||||
|
||||
switch (opcode) {
|
||||
case ZERO_PAGE:
|
||||
memory->set_byte_at(byte2, x_reg->get_value());
|
||||
move_program_counter(2);
|
||||
break;
|
||||
|
||||
case ZERO_PAGE_Y: {
|
||||
// expect wrap around
|
||||
uint8_t address = reg_man->get_y_index()->get_value() + byte2;
|
||||
memory->set_byte_at(address, x_reg->get_value());
|
||||
move_program_counter(2);
|
||||
break;
|
||||
}
|
||||
|
||||
case ABSOLUTE: {
|
||||
auto low = byte2;
|
||||
auto high = program->get_byte_at(instructionIndex + 2);
|
||||
uint16_t address = (high << 8) + low;
|
||||
memory->set_byte_at(address, x_reg->get_value());
|
||||
move_program_counter(3);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw_unexpected_opcode(opcode);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef INC_6502_EMULATOR_STX_OPCODE_HANDLER_H
|
||||
#define INC_6502_EMULATOR_STX_OPCODE_HANDLER_H
|
||||
|
||||
#include "../opcode-handler.h"
|
||||
|
||||
class StxOpcodeHandler : public OpcodeHandler {
|
||||
public:
|
||||
static const uint8_t ZERO_PAGE = 0x86;
|
||||
static const uint8_t ZERO_PAGE_Y = 0x96;
|
||||
static const uint8_t ABSOLUTE = 0x8E;
|
||||
|
||||
explicit StxOpcodeHandler(shared_ptr<Program> program, shared_ptr<RegisterManager> reg_man,
|
||||
shared_ptr<Memory> memory) :
|
||||
OpcodeHandler(program, reg_man, memory) {
|
||||
handled_opcodes->push_back(ZERO_PAGE);
|
||||
handled_opcodes->push_back(ZERO_PAGE_Y);
|
||||
handled_opcodes->push_back(ABSOLUTE);
|
||||
}
|
||||
|
||||
virtual void execute() override;
|
||||
};
|
||||
|
||||
|
||||
#endif //INC_6502_EMULATOR_STX_OPCODE_HANDLER_H
|
|
@ -0,0 +1,39 @@
|
|||
#include "sty-opcode-handler.h"
|
||||
|
||||
const uint8_t StyOpcodeHandler::ZERO_PAGE;
|
||||
const uint8_t StyOpcodeHandler::ZERO_PAGE_X;
|
||||
const uint8_t StyOpcodeHandler::ABSOLUTE;
|
||||
|
||||
void StyOpcodeHandler::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 y_reg = reg_man->get_y_index();
|
||||
|
||||
switch (opcode) {
|
||||
case ZERO_PAGE:
|
||||
memory->set_byte_at(byte2, y_reg->get_value());
|
||||
move_program_counter(2);
|
||||
break;
|
||||
|
||||
case ZERO_PAGE_X: {
|
||||
// expect wrap around
|
||||
uint8_t address = reg_man->get_x_index()->get_value() + byte2;
|
||||
memory->set_byte_at(address, y_reg->get_value());
|
||||
move_program_counter(2);
|
||||
break;
|
||||
}
|
||||
|
||||
case ABSOLUTE: {
|
||||
auto low = byte2;
|
||||
auto high = program->get_byte_at(instructionIndex + 2);
|
||||
uint16_t address = (high << 8) + low;
|
||||
memory->set_byte_at(address, y_reg->get_value());
|
||||
move_program_counter(3);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw_unexpected_opcode(opcode);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef INC_6502_EMULATOR_STY_OPCODE_HANDLER_H
|
||||
#define INC_6502_EMULATOR_STY_OPCODE_HANDLER_H
|
||||
|
||||
#include "../opcode-handler.h"
|
||||
|
||||
class StyOpcodeHandler : public OpcodeHandler {
|
||||
public:
|
||||
static const uint8_t ZERO_PAGE = 0x84;
|
||||
static const uint8_t ZERO_PAGE_X = 0x94;
|
||||
static const uint8_t ABSOLUTE = 0x8C;
|
||||
|
||||
explicit StyOpcodeHandler(shared_ptr<Program> program, shared_ptr<RegisterManager> reg_man,
|
||||
shared_ptr<Memory> memory) :
|
||||
OpcodeHandler(program, reg_man, memory) {
|
||||
handled_opcodes->push_back(ZERO_PAGE);
|
||||
handled_opcodes->push_back(ZERO_PAGE_X);
|
||||
handled_opcodes->push_back(ABSOLUTE);
|
||||
}
|
||||
|
||||
virtual void execute() override;
|
||||
};
|
||||
|
||||
|
||||
#endif //INC_6502_EMULATOR_STY_OPCODE_HANDLER_H
|
|
@ -1,7 +1,10 @@
|
|||
#include "opcode-handler-directory.h"
|
||||
#include "handler/flag-opcode-handler.h"
|
||||
#include "handler/register-opcode-handler.h"
|
||||
#include "handler/lda-opcode-handler.h"
|
||||
#include "handler/ldx-opcode-handler.h"
|
||||
#include "handler/stx-opcode-handler.h"
|
||||
#include "handler/sty-opcode-handler.h"
|
||||
#include "handler/stack-opcode-handler.h"
|
||||
|
||||
#include <sstream>
|
||||
|
@ -12,7 +15,10 @@ OpcodeHandlerDirectory::OpcodeHandlerDirectory(shared_ptr<Program> program, shar
|
|||
|
||||
register_handler(make_shared<FlagOpcodeHandler>(FlagOpcodeHandler(program, reg_man, memory)));
|
||||
register_handler(make_shared<RegisterOpcodeHandler>(RegisterOpcodeHandler(program, reg_man, memory)));
|
||||
register_handler(make_shared<LdaOpcodeHandler>(LdaOpcodeHandler(program, reg_man, memory)));
|
||||
register_handler(make_shared<LdxOpcodeHandler>(LdxOpcodeHandler(program, reg_man, memory)));
|
||||
register_handler(make_shared<StxOpcodeHandler>(StxOpcodeHandler(program, reg_man, memory)));
|
||||
register_handler(make_shared<StyOpcodeHandler>(StyOpcodeHandler(program, reg_man, memory)));
|
||||
register_handler(make_shared<StackOpcodeHandler>(StackOpcodeHandler(program, reg_man, memory)));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#include "opcode-handler.h"
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
OpcodeHandler::OpcodeHandler(shared_ptr<Program> program, shared_ptr<RegisterManager> reg_man,
|
||||
shared_ptr<Memory> memory) {
|
||||
|
@ -10,4 +12,10 @@ OpcodeHandler::OpcodeHandler(shared_ptr<Program> program, shared_ptr<RegisterMan
|
|||
void OpcodeHandler::move_program_counter(uint8_t forward_by) {
|
||||
auto pc = reg_man->get_program_counter();
|
||||
pc->set_value(pc->get_value() + forward_by);
|
||||
}
|
||||
|
||||
void OpcodeHandler::throw_unexpected_opcode(uint8_t opcode) {
|
||||
stringstream stream;
|
||||
stream << "Unexpected opcode 0x" << hex << opcode;
|
||||
throw runtime_error(stream.str());
|
||||
}
|
|
@ -13,10 +13,11 @@ class OpcodeHandler {
|
|||
public:
|
||||
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; }
|
||||
|
||||
virtual void execute() = 0;
|
||||
|
||||
shared_ptr<vector<uint8_t>> get_handled_opcodes() { return handled_opcodes; }
|
||||
void throw_unexpected_opcode(uint8_t opcode);
|
||||
|
||||
protected:
|
||||
shared_ptr<vector<uint8_t>> handled_opcodes = make_shared<vector<uint8_t>>();
|
||||
shared_ptr<Program> program;
|
||||
|
|
|
@ -0,0 +1,199 @@
|
|||
#include "gtest/gtest.h"
|
||||
#include "../src/machine.h"
|
||||
#include "../src/program.h"
|
||||
#include "../src/opcode/handler/lda-opcode-handler.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
const uint8_t IMMEDIATE = 0xA9;
|
||||
const uint8_t ZERO_PAGE = 0xA5;
|
||||
const uint8_t ZERO_PAGE_X = 0xB5;
|
||||
const uint8_t ABSOLUTE = 0xAD;
|
||||
const uint8_t ABSOLUTE_X = 0xBD;
|
||||
const uint8_t ABSOLUTE_Y = 0xB9;
|
||||
const uint8_t INDIRECT_X = 0xA1;
|
||||
const uint8_t INDIRECT_Y = 0xB1;
|
||||
|
||||
unique_ptr<Machine> ldat_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(LdaOpcodeHandler, Immediate) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{IMMEDIATE, 36});
|
||||
auto machine = ldat_get_machine(code);
|
||||
auto reg_man = machine->get_reg_man();
|
||||
auto accumulator = reg_man->get_accumulator();
|
||||
|
||||
ASSERT_EQ(0, accumulator->get_value());
|
||||
|
||||
machine->execute();
|
||||
|
||||
ASSERT_EQ(36, accumulator->get_value());
|
||||
}
|
||||
|
||||
TEST(LdaOpcodeHandler, ZeroPage) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{ZERO_PAGE, 123});
|
||||
auto machine = ldat_get_machine(code);
|
||||
auto reg_man = machine->get_reg_man();
|
||||
auto accumulator = reg_man->get_accumulator();
|
||||
|
||||
ASSERT_EQ(0, accumulator->get_value());
|
||||
|
||||
machine->get_memory()->set_byte_at(123, 78);
|
||||
machine->execute();
|
||||
|
||||
ASSERT_EQ(78, accumulator->get_value());
|
||||
}
|
||||
|
||||
TEST(LdaOpcodeHandler, ZeroPageX) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{ZERO_PAGE_X, 0x50});
|
||||
auto machine = ldat_get_machine(code);
|
||||
auto reg_man = machine->get_reg_man();
|
||||
auto accumulator = reg_man->get_accumulator();
|
||||
auto x_reg = reg_man->get_x_index();
|
||||
|
||||
ASSERT_EQ(0, accumulator->get_value());
|
||||
ASSERT_EQ(0, x_reg->get_value());
|
||||
machine->get_memory()->set_byte_at(0x50, 0xff);
|
||||
machine->execute();
|
||||
ASSERT_EQ(0xff, accumulator->get_value());
|
||||
|
||||
x_reg->set_value(0x15);
|
||||
reg_man->get_program_counter()->set_value(0);
|
||||
machine->execute();
|
||||
ASSERT_EQ(0, accumulator->get_value());
|
||||
|
||||
machine->get_memory()->set_byte_at(0x65, 233);
|
||||
reg_man->get_program_counter()->set_value(0);
|
||||
machine->execute();
|
||||
ASSERT_EQ(233, accumulator->get_value());
|
||||
}
|
||||
|
||||
TEST(LdaOpcodeHandler, ZeroPageXWrap) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{ZERO_PAGE_X, 0x80});
|
||||
auto machine = ldat_get_machine(code);
|
||||
auto reg_man = machine->get_reg_man();
|
||||
auto accumulator = reg_man->get_accumulator();
|
||||
auto x_reg = reg_man->get_x_index();
|
||||
|
||||
ASSERT_EQ(0, accumulator->get_value());
|
||||
ASSERT_EQ(0, x_reg->get_value());
|
||||
|
||||
x_reg->set_value(0xff);
|
||||
machine->get_memory()->set_byte_at(0x7f, 0x12);
|
||||
machine->execute();
|
||||
ASSERT_EQ(0x12, accumulator->get_value());
|
||||
}
|
||||
|
||||
TEST(LdaOpcodeHandler, Absolute) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{ABSOLUTE, 0xe5, 0xff});
|
||||
auto machine = ldat_get_machine(code);
|
||||
auto reg_man = machine->get_reg_man();
|
||||
auto accumulator = reg_man->get_accumulator();
|
||||
|
||||
ASSERT_EQ(0, accumulator->get_value());
|
||||
|
||||
machine->get_memory()->set_byte_at(0xffe5, 0xde);
|
||||
machine->execute();
|
||||
|
||||
ASSERT_EQ(0xde, accumulator->get_value());
|
||||
}
|
||||
|
||||
TEST(LdaOpcodeHandler, AbsoluteX) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{ABSOLUTE_X, 0x33, 0xc2});
|
||||
auto machine = ldat_get_machine(code);
|
||||
auto reg_man = machine->get_reg_man();
|
||||
auto accumulator = reg_man->get_accumulator();
|
||||
auto x_reg = reg_man->get_x_index();
|
||||
|
||||
ASSERT_EQ(0, accumulator->get_value());
|
||||
ASSERT_EQ(0, x_reg->get_value());
|
||||
machine->get_memory()->set_byte_at(0xc233, 0xc8);
|
||||
machine->execute();
|
||||
ASSERT_EQ(0xc8, accumulator->get_value());
|
||||
|
||||
x_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, accumulator->get_value());
|
||||
}
|
||||
|
||||
TEST(LdaOpcodeHandler, AbsoluteY) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{ABSOLUTE_Y, 0x33, 0xc2});
|
||||
auto machine = ldat_get_machine(code);
|
||||
auto reg_man = machine->get_reg_man();
|
||||
auto accumulator = reg_man->get_accumulator();
|
||||
auto y_reg = reg_man->get_y_index();
|
||||
|
||||
ASSERT_EQ(0, accumulator->get_value());
|
||||
ASSERT_EQ(0, y_reg->get_value());
|
||||
machine->get_memory()->set_byte_at(0xc233, 0xc8);
|
||||
machine->execute();
|
||||
ASSERT_EQ(0xc8, accumulator->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, accumulator->get_value());
|
||||
}
|
||||
|
||||
TEST(LdaOpcodeHandler, IndirectX) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{INDIRECT_X, 0x00});
|
||||
auto machine = ldat_get_machine(code);
|
||||
auto reg_man = machine->get_reg_man();
|
||||
auto accumulator = reg_man->get_accumulator();
|
||||
auto x_reg = reg_man->get_x_index();
|
||||
|
||||
ASSERT_EQ(0, accumulator->get_value());
|
||||
|
||||
x_reg->set_value(0x01);
|
||||
machine->get_memory()->set_byte_at(0x01, 0x05);
|
||||
machine->get_memory()->set_byte_at(0x02, 0x07);
|
||||
machine->get_memory()->set_byte_at(0x0705, 0xc6);
|
||||
machine->execute();
|
||||
ASSERT_EQ(0xc6, accumulator->get_value());
|
||||
|
||||
code->at(1) = 0x15;
|
||||
reg_man->get_program_counter()->set_value(0);
|
||||
|
||||
x_reg->set_value(0x20);
|
||||
machine->get_memory()->set_byte_at(0x35, 0xef);
|
||||
machine->get_memory()->set_byte_at(0x36, 0xa8);
|
||||
machine->get_memory()->set_byte_at(0xa8ef, 0x9d);
|
||||
machine->execute();
|
||||
ASSERT_EQ(0x9d, accumulator->get_value());
|
||||
}
|
||||
|
||||
TEST(LdaOpcodeHandler, IndirectY) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{INDIRECT_Y, 0x00});
|
||||
auto machine = ldat_get_machine(code);
|
||||
auto reg_man = machine->get_reg_man();
|
||||
auto accumulator = reg_man->get_accumulator();
|
||||
auto y_reg = reg_man->get_y_index();
|
||||
|
||||
ASSERT_EQ(0, accumulator->get_value());
|
||||
|
||||
y_reg->set_value(0x00);
|
||||
machine->get_memory()->set_byte_at(0x00, 0x25);
|
||||
machine->get_memory()->set_byte_at(0x01, 0x3e);
|
||||
machine->get_memory()->set_byte_at(0x3e25, 0xf0);
|
||||
machine->execute();
|
||||
ASSERT_EQ(0xf0, accumulator->get_value());
|
||||
|
||||
code->at(1) = 0x15;
|
||||
reg_man->get_program_counter()->set_value(0);
|
||||
|
||||
y_reg->set_value(0x25);
|
||||
machine->get_memory()->set_byte_at(0x15, 0x20);
|
||||
machine->get_memory()->set_byte_at(0x16, 0x07);
|
||||
machine->get_memory()->set_byte_at(0x0745, 0x89);
|
||||
machine->execute();
|
||||
ASSERT_EQ(0x89, accumulator->get_value());
|
||||
}
|
|
@ -48,7 +48,7 @@ TEST(LdxOpcodeHandler, ZeroPage) {
|
|||
}
|
||||
|
||||
TEST(LdxOpcodeHandler, ZeroPageY) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{ZERO_PAGE_Y, 250});
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{ZERO_PAGE_Y, 0x50});
|
||||
auto machine = ldxt_get_machine(code);
|
||||
auto reg_man = machine->get_reg_man();
|
||||
auto x_reg = reg_man->get_x_index();
|
||||
|
@ -56,16 +56,16 @@ TEST(LdxOpcodeHandler, ZeroPageY) {
|
|||
|
||||
ASSERT_EQ(0, x_reg->get_value());
|
||||
ASSERT_EQ(0, y_reg->get_value());
|
||||
machine->get_memory()->set_byte_at(250, 255);
|
||||
machine->get_memory()->set_byte_at(0x50, 255);
|
||||
machine->execute();
|
||||
ASSERT_EQ(255, x_reg->get_value());
|
||||
|
||||
reg_man->get_y_index()->set_value(100);
|
||||
reg_man->get_y_index()->set_value(0x17);
|
||||
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);
|
||||
machine->get_memory()->set_byte_at(0x67, 233);
|
||||
reg_man->get_program_counter()->set_value(0);
|
||||
machine->execute();
|
||||
ASSERT_EQ(233, x_reg->get_value());
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
#include "gtest/gtest.h"
|
||||
#include "../src/machine.h"
|
||||
#include "../src/program.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
const uint8_t ZERO_PAGE = 0x86;
|
||||
const uint8_t ZERO_PAGE_Y = 0x96;
|
||||
const uint8_t ABSOLUTE = 0x8E;
|
||||
|
||||
unique_ptr<Machine> stxt_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(StxOpcodeHandler, ZeroPage) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{ZERO_PAGE, 50});
|
||||
auto machine = stxt_get_machine(code);
|
||||
auto memory = machine->get_memory();
|
||||
auto reg_man = machine->get_reg_man();
|
||||
auto x_reg = reg_man->get_x_index();
|
||||
|
||||
ASSERT_EQ(0, x_reg->get_value());
|
||||
ASSERT_EQ(0, memory->get_byte_at(50));
|
||||
|
||||
x_reg->set_value(0x8a);
|
||||
machine->execute();
|
||||
|
||||
ASSERT_EQ(0x8a, memory->get_byte_at(50));
|
||||
}
|
||||
|
||||
TEST(StxOpcodeHandler, ZeroPageY) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{ZERO_PAGE_Y, 0x45});
|
||||
auto machine = stxt_get_machine(code);
|
||||
auto memory = machine->get_memory();
|
||||
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());
|
||||
ASSERT_EQ(0, memory->get_byte_at(0x4a));
|
||||
|
||||
x_reg->set_value(0x8b);
|
||||
y_reg->set_value(0x5);
|
||||
machine->execute();
|
||||
|
||||
ASSERT_EQ(0x8b, memory->get_byte_at(0x4a));
|
||||
}
|
||||
|
||||
TEST(StxOpcodeHandler, Absolute) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{ABSOLUTE, 0x33, 0x44});
|
||||
auto machine = stxt_get_machine(code);
|
||||
auto memory = machine->get_memory();
|
||||
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());
|
||||
ASSERT_EQ(0, memory->get_byte_at(0x4433));
|
||||
|
||||
x_reg->set_value(0x9f);
|
||||
machine->execute();
|
||||
|
||||
ASSERT_EQ(0x9f, memory->get_byte_at(0x4433));
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
#include "gtest/gtest.h"
|
||||
#include "../src/machine.h"
|
||||
#include "../src/program.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
const uint8_t ZERO_PAGE = 0x84;
|
||||
const uint8_t ZERO_PAGE_X = 0x94;
|
||||
const uint8_t ABSOLUTE = 0x8C;
|
||||
|
||||
unique_ptr<Machine> styt_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(StyOpcodeHandler, ZeroPage) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{ZERO_PAGE, 50});
|
||||
auto machine = styt_get_machine(code);
|
||||
auto memory = machine->get_memory();
|
||||
auto reg_man = machine->get_reg_man();
|
||||
auto y_reg = reg_man->get_y_index();
|
||||
|
||||
ASSERT_EQ(0, y_reg->get_value());
|
||||
ASSERT_EQ(0, memory->get_byte_at(50));
|
||||
|
||||
y_reg->set_value(0x8a);
|
||||
machine->execute();
|
||||
|
||||
ASSERT_EQ(0x8a, memory->get_byte_at(50));
|
||||
}
|
||||
|
||||
TEST(StyOpcodeHandler, ZeroPageX) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{ZERO_PAGE_X, 0x45});
|
||||
auto machine = styt_get_machine(code);
|
||||
auto memory = machine->get_memory();
|
||||
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());
|
||||
ASSERT_EQ(0, memory->get_byte_at(0x5b));
|
||||
|
||||
x_reg->set_value(0x16);
|
||||
y_reg->set_value(0xe1);
|
||||
machine->execute();
|
||||
|
||||
ASSERT_EQ(0xe1, memory->get_byte_at(0x5b));
|
||||
}
|
||||
|
||||
TEST(StyOpcodeHandler, Absolute) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{ABSOLUTE, 0x33, 0x44});
|
||||
auto machine = styt_get_machine(code);
|
||||
auto memory = machine->get_memory();
|
||||
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());
|
||||
ASSERT_EQ(0, memory->get_byte_at(0x4433));
|
||||
|
||||
y_reg->set_value(0x9f);
|
||||
machine->execute();
|
||||
|
||||
ASSERT_EQ(0x9f, memory->get_byte_at(0x4433));
|
||||
}
|
Loading…
Reference in New Issue