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")
|
file(GLOB_RECURSE test_src "test/**.h" "test/**.cpp" "src/**.h" "src/**.cpp")
|
||||||
list(FILTER test_src EXCLUDE REGEX ".*/6502-emulator/src/main.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)
|
target_link_libraries(6502_emulator_test gtest_main)
|
||||||
add_test(NAME run_tests COMMAND 6502_emulator_test)
|
add_test(NAME run_tests COMMAND 6502_emulator_test)
|
||||||
|
|
||||||
file(GLOB_RECURSE emulator_src "src/**.h" "src/**.cpp")
|
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 "register/register-manager.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
using namespace std;
|
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() {
|
int main() {
|
||||||
auto reg = unique_ptr<Register<uint8_t>>(new Register<uint8_t>("PC"));
|
cout << "Only unit tests for now" << endl;
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
|
@ -1,8 +1,5 @@
|
||||||
#include "flag-opcode-handler.h"
|
#include "flag-opcode-handler.h"
|
||||||
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
const uint8_t FlagOpcodeHandler::CLC;
|
const uint8_t FlagOpcodeHandler::CLC;
|
||||||
const uint8_t FlagOpcodeHandler::SEC;
|
const uint8_t FlagOpcodeHandler::SEC;
|
||||||
const uint8_t FlagOpcodeHandler::CLI;
|
const uint8_t FlagOpcodeHandler::CLI;
|
||||||
|
@ -39,9 +36,7 @@ void FlagOpcodeHandler::execute() {
|
||||||
statusReg->set_decimal(true);
|
statusReg->set_decimal(true);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
stringstream stream;
|
throw_unexpected_opcode(opcode);
|
||||||
stream << "Unexpected opcode 0x" << hex << opcode;
|
|
||||||
throw runtime_error(stream.str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
move_program_counter(1);
|
move_program_counter(1);
|
||||||
|
|
|
@ -1,5 +1,94 @@
|
||||||
//
|
|
||||||
// Created by tony on 27/03/19.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "lda-opcode-handler.h"
|
#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
|
#ifndef INC_6502_EMULATOR_LDA_OPCODE_HANDLER_H
|
||||||
#define 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 "ldx-opcode-handler.h"
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
const uint8_t LdxOpcodeHandler::IMMEDIATE;
|
const uint8_t LdxOpcodeHandler::IMMEDIATE;
|
||||||
const uint8_t LdxOpcodeHandler::ZERO_PAGE;
|
const uint8_t LdxOpcodeHandler::ZERO_PAGE;
|
||||||
|
@ -25,7 +24,8 @@ void LdxOpcodeHandler::execute() {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ZERO_PAGE_Y: {
|
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));
|
x_reg->set_value(memory->get_byte_at(address));
|
||||||
move_program_counter(2);
|
move_program_counter(2);
|
||||||
|
@ -53,8 +53,6 @@ void LdxOpcodeHandler::execute() {
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
stringstream stream;
|
throw_unexpected_opcode(opcode);
|
||||||
stream << "Unexpected opcode 0x" << hex << opcode;
|
|
||||||
throw runtime_error(stream.str());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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 "register-opcode-handler.h"
|
||||||
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
const uint8_t RegisterOpcodeHandler::TAX;
|
const uint8_t RegisterOpcodeHandler::TAX;
|
||||||
const uint8_t RegisterOpcodeHandler::TXA;
|
const uint8_t RegisterOpcodeHandler::TXA;
|
||||||
const uint8_t RegisterOpcodeHandler::DEX;
|
const uint8_t RegisterOpcodeHandler::DEX;
|
||||||
|
@ -23,31 +20,37 @@ void RegisterOpcodeHandler::execute() {
|
||||||
case TAX:
|
case TAX:
|
||||||
x_index->set_value(accumulator->get_value());
|
x_index->set_value(accumulator->get_value());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TXA:
|
case TXA:
|
||||||
accumulator->set_value(x_index->get_value());
|
accumulator->set_value(x_index->get_value());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DEX:
|
case DEX:
|
||||||
x_index->set_value(x_index->get_value() - 1);
|
x_index->set_value(x_index->get_value() - 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INX:
|
case INX:
|
||||||
x_index->set_value(x_index->get_value() + 1);
|
x_index->set_value(x_index->get_value() + 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TAY:
|
case TAY:
|
||||||
y_index->set_value(accumulator->get_value());
|
y_index->set_value(accumulator->get_value());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TYA:
|
case TYA:
|
||||||
accumulator->set_value(y_index->get_value());
|
accumulator->set_value(y_index->get_value());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DEY:
|
case DEY:
|
||||||
y_index->set_value(y_index->get_value() - 1);
|
y_index->set_value(y_index->get_value() - 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INY:
|
case INY:
|
||||||
y_index->set_value(y_index->get_value() + 1);
|
y_index->set_value(y_index->get_value() + 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
stringstream stream;
|
throw_unexpected_opcode(opcode);
|
||||||
stream << "Unexpected opcode 0x" << hex << opcode;
|
|
||||||
throw runtime_error(stream.str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
move_program_counter(1);
|
move_program_counter(1);
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
#include "stack-opcode-handler.h"
|
#include "stack-opcode-handler.h"
|
||||||
#include <sstream>
|
|
||||||
#include <climits>
|
|
||||||
|
|
||||||
const uint8_t StackOpcodeHandler::PHA;
|
const uint8_t StackOpcodeHandler::PHA;
|
||||||
const uint8_t StackOpcodeHandler::PLA;
|
const uint8_t StackOpcodeHandler::PLA;
|
||||||
|
@ -34,9 +32,7 @@ void StackOpcodeHandler::execute() {
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
stringstream stream;
|
throw_unexpected_opcode(opcode);
|
||||||
stream << "Unexpected opcode 0x" << hex << opcode;
|
|
||||||
throw runtime_error(stream.str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
move_program_counter(1);
|
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 "opcode-handler-directory.h"
|
||||||
#include "handler/flag-opcode-handler.h"
|
#include "handler/flag-opcode-handler.h"
|
||||||
#include "handler/register-opcode-handler.h"
|
#include "handler/register-opcode-handler.h"
|
||||||
|
#include "handler/lda-opcode-handler.h"
|
||||||
#include "handler/ldx-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 "handler/stack-opcode-handler.h"
|
||||||
|
|
||||||
#include <sstream>
|
#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<FlagOpcodeHandler>(FlagOpcodeHandler(program, reg_man, memory)));
|
||||||
register_handler(make_shared<RegisterOpcodeHandler>(RegisterOpcodeHandler(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<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)));
|
register_handler(make_shared<StackOpcodeHandler>(StackOpcodeHandler(program, reg_man, memory)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
#include "opcode-handler.h"
|
#include "opcode-handler.h"
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
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) {
|
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) {
|
void OpcodeHandler::move_program_counter(uint8_t forward_by) {
|
||||||
auto pc = reg_man->get_program_counter();
|
auto pc = reg_man->get_program_counter();
|
||||||
pc->set_value(pc->get_value() + forward_by);
|
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:
|
public:
|
||||||
OpcodeHandler(shared_ptr<Program> program, shared_ptr<RegisterManager> reg_man, shared_ptr<Memory> memory);
|
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;
|
virtual void execute() = 0;
|
||||||
|
|
||||||
|
shared_ptr<vector<uint8_t>> get_handled_opcodes() { return handled_opcodes; }
|
||||||
|
void throw_unexpected_opcode(uint8_t opcode);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
shared_ptr<vector<uint8_t>> handled_opcodes = make_shared<vector<uint8_t>>();
|
shared_ptr<vector<uint8_t>> handled_opcodes = make_shared<vector<uint8_t>>();
|
||||||
shared_ptr<Program> program;
|
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) {
|
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 machine = ldxt_get_machine(code);
|
||||||
auto reg_man = machine->get_reg_man();
|
auto reg_man = machine->get_reg_man();
|
||||||
auto x_reg = reg_man->get_x_index();
|
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, x_reg->get_value());
|
||||||
ASSERT_EQ(0, y_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();
|
machine->execute();
|
||||||
ASSERT_EQ(255, x_reg->get_value());
|
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);
|
reg_man->get_program_counter()->set_value(0);
|
||||||
machine->execute();
|
machine->execute();
|
||||||
ASSERT_EQ(0, x_reg->get_value());
|
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);
|
reg_man->get_program_counter()->set_value(0);
|
||||||
machine->execute();
|
machine->execute();
|
||||||
ASSERT_EQ(233, x_reg->get_value());
|
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