mirror of
https://github.com/tdinucci/6502-emulator.git
synced 2024-11-27 02:49:50 +00:00
Clear out initial draft
This commit is contained in:
parent
ad1015759e
commit
99c0834f0d
@ -1,33 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(6502_emulator)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
|
||||
configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt)
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
|
||||
RESULT_VARIABLE result
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download )
|
||||
if(result)
|
||||
message(FATAL_ERROR "CMake step for googletest failed: ${result}")
|
||||
endif()
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} --build .
|
||||
RESULT_VARIABLE result
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download )
|
||||
if(result)
|
||||
message(FATAL_ERROR "Build step for googletest failed: ${result}")
|
||||
endif()
|
||||
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
|
||||
add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src
|
||||
${CMAKE_CURRENT_BINARY_DIR}/googletest-build
|
||||
EXCLUDE_FROM_ALL)
|
||||
|
||||
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})
|
||||
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})
|
@ -1,15 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
project(googletest-download NONE)
|
||||
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(googletest
|
||||
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||
GIT_TAG master
|
||||
SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src"
|
||||
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
)
|
@ -1,38 +0,0 @@
|
||||
#include "instruction-executor.h"
|
||||
#include <stdexcept>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
void dump_cpu_state(shared_ptr<RegisterManager> reg_man) {
|
||||
cout << "--------------" << endl;
|
||||
cout << "A=0x" << hex << (int) reg_man->get_accumulator()->get_value() <<
|
||||
" X=0x" << hex << (int) reg_man->get_x_index()->get_value() <<
|
||||
" Y=0x" << hex << (int) reg_man->get_y_index()->get_value() << endl;
|
||||
|
||||
cout << "SP=0x" << hex << (int) reg_man->get_stack_pointer()->get_value() <<
|
||||
" PC=0x" << hex << (int) reg_man->get_program_counter()->get_value() << endl;
|
||||
|
||||
cout << "NV-BDIZC" << endl <<
|
||||
reg_man->get_status_register()->get_value() << endl;
|
||||
}
|
||||
|
||||
InstructionExecutor::InstructionExecutor(shared_ptr<Program> program, shared_ptr<RegisterManager> reg_man,
|
||||
shared_ptr<OpcodeHandlerDirectory> opcode_handler_dir) {
|
||||
this->program = program;
|
||||
this->reg_man = reg_man;
|
||||
this->opcode_handler_dir = opcode_handler_dir;
|
||||
}
|
||||
|
||||
void InstructionExecutor::execute() {
|
||||
auto pc = reg_man->get_program_counter();
|
||||
|
||||
do {
|
||||
auto opcode = program->get_byte_at(pc->get_value());
|
||||
auto handler = opcode_handler_dir->get_handler(opcode);
|
||||
|
||||
handler->execute();
|
||||
|
||||
dump_cpu_state(reg_man);
|
||||
|
||||
} while (pc->get_value() < program->get_size());
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
#ifndef INC_6502_EMULATOR_INSTRUCTION_EXECUTOR_H
|
||||
#define INC_6502_EMULATOR_INSTRUCTION_EXECUTOR_H
|
||||
|
||||
#include "../program.h"
|
||||
#include "../register/register-manager.h"
|
||||
#include "../opcode/opcode-handler-directory.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class InstructionExecutor {
|
||||
public:
|
||||
explicit InstructionExecutor(shared_ptr<Program> program, shared_ptr<RegisterManager> reg_man,
|
||||
shared_ptr<OpcodeHandlerDirectory> opcode_handler_dir);
|
||||
|
||||
void execute();
|
||||
|
||||
private:
|
||||
shared_ptr<Program> program;
|
||||
shared_ptr<RegisterManager> reg_man;
|
||||
shared_ptr<OpcodeHandlerDirectory> opcode_handler_dir;
|
||||
};
|
||||
|
||||
|
||||
#endif //INC_6502_EMULATOR_INSTRUCTION_EXECUTOR_H
|
@ -1,24 +0,0 @@
|
||||
#include "machine.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
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, memory));
|
||||
instruction_executor =
|
||||
make_unique<InstructionExecutor>(InstructionExecutor(program, reg_man, opcode_handler_dir));
|
||||
}
|
||||
|
||||
shared_ptr<Memory> Machine::get_memory() {
|
||||
return memory;
|
||||
}
|
||||
|
||||
shared_ptr<RegisterManager> Machine::get_reg_man() {
|
||||
return reg_man;
|
||||
}
|
||||
|
||||
void Machine::execute() {
|
||||
instruction_executor->execute();
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
#ifndef INC_6502_EMULATOR_MACHINE_H
|
||||
#define INC_6502_EMULATOR_MACHINE_H
|
||||
|
||||
#include "program.h"
|
||||
#include "memory.h"
|
||||
#include "register/register-manager.h"
|
||||
#include "opcode/opcode-handler-directory.h"
|
||||
#include "instruction/instruction-executor.h"
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class Machine {
|
||||
public:
|
||||
explicit Machine(shared_ptr<Program> program);
|
||||
|
||||
shared_ptr<RegisterManager> get_reg_man();
|
||||
shared_ptr<Memory> get_memory();
|
||||
|
||||
void execute();
|
||||
|
||||
private:
|
||||
shared_ptr<Program> program;
|
||||
shared_ptr<Memory> memory;
|
||||
shared_ptr<RegisterManager> reg_man;
|
||||
shared_ptr<OpcodeHandlerDirectory> opcode_handler_dir;
|
||||
shared_ptr<InstructionExecutor> instruction_executor;
|
||||
};
|
||||
|
||||
|
||||
#endif //INC_6502_EMULATOR_MACHINE_H
|
10
src/main.cpp
10
src/main.cpp
@ -1,10 +0,0 @@
|
||||
#include "register/register-manager.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
cout << "Only unit tests for now" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
#include "memory.h"
|
||||
#include <stdexcept>
|
||||
|
||||
Memory::Memory() {
|
||||
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) {
|
||||
return bytes->at(index);
|
||||
}
|
||||
|
||||
void Memory::stack_push(uint8_t data) {
|
||||
stack->push(data);
|
||||
}
|
||||
|
||||
uint8_t Memory::stack_pop() {
|
||||
return stack->pop();
|
||||
}
|
25
src/memory.h
25
src/memory.h
@ -1,25 +0,0 @@
|
||||
#ifndef INC_6502_EMULATOR_MEMORY_H
|
||||
#define INC_6502_EMULATOR_MEMORY_H
|
||||
|
||||
#include "stack.h"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
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:
|
||||
unique_ptr<vector<uint8_t>> bytes;
|
||||
unique_ptr<Stack> stack;
|
||||
};
|
||||
|
||||
|
||||
#endif //INC_6502_EMULATOR_MEMORY_H
|
@ -1,43 +0,0 @@
|
||||
#include "flag-opcode-handler.h"
|
||||
|
||||
const uint8_t FlagOpcodeHandler::CLC;
|
||||
const uint8_t FlagOpcodeHandler::SEC;
|
||||
const uint8_t FlagOpcodeHandler::CLI;
|
||||
const uint8_t FlagOpcodeHandler::SEI;
|
||||
const uint8_t FlagOpcodeHandler::CLV;
|
||||
const uint8_t FlagOpcodeHandler::CLD;
|
||||
const uint8_t FlagOpcodeHandler::SED;
|
||||
|
||||
void FlagOpcodeHandler::execute() {
|
||||
auto instructionIndex = reg_man->get_program_counter()->get_value();
|
||||
auto opcode = program->get_byte_at(instructionIndex);
|
||||
auto statusReg = reg_man->get_status_register();
|
||||
|
||||
switch (opcode) {
|
||||
case CLC:
|
||||
statusReg->set_carry(false);
|
||||
break;
|
||||
case SEC:
|
||||
statusReg->set_carry(true);
|
||||
break;
|
||||
case CLI:
|
||||
statusReg->set_interupt_disable(false);
|
||||
break;
|
||||
case SEI:
|
||||
statusReg->set_interupt_disable(true);
|
||||
break;
|
||||
case CLV:
|
||||
statusReg->set_overflow(false);
|
||||
break;
|
||||
case CLD:
|
||||
statusReg->set_decimal(false);
|
||||
break;
|
||||
case SED:
|
||||
statusReg->set_decimal(true);
|
||||
break;
|
||||
default:
|
||||
throw_unexpected_opcode(opcode);
|
||||
}
|
||||
|
||||
move_program_counter(1);
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
#ifndef INC_6502_EMULATOR_FLAG_OPCODE_HANDLER_H
|
||||
#define INC_6502_EMULATOR_FLAG_OPCODE_HANDLER_H
|
||||
|
||||
#include "../opcode-handler.h"
|
||||
|
||||
class FlagOpcodeHandler : public OpcodeHandler {
|
||||
public:
|
||||
static const uint8_t CLC = 0x18;
|
||||
static const uint8_t SEC = 0x38;
|
||||
static const uint8_t CLI = 0x58;
|
||||
static const uint8_t SEI = 0x78;
|
||||
static const uint8_t CLV = 0xB8;
|
||||
static const uint8_t CLD = 0xD8;
|
||||
static const uint8_t SED = 0xF8;
|
||||
|
||||
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);
|
||||
handled_opcodes->push_back(SEI);
|
||||
handled_opcodes->push_back(CLV);
|
||||
handled_opcodes->push_back(CLD);
|
||||
handled_opcodes->push_back(SED);
|
||||
}
|
||||
|
||||
virtual void execute() override;
|
||||
};
|
||||
|
||||
#endif //INC_6502_EMULATOR_FLAG_OPCODE_HANDLER_H
|
@ -1,94 +0,0 @@
|
||||
#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,34 +0,0 @@
|
||||
#ifndef INC_6502_EMULATOR_LDA_OPCODE_HANDLER_H
|
||||
#define INC_6502_EMULATOR_LDA_OPCODE_HANDLER_H
|
||||
|
||||
#include "../opcode-handler.h"
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
#endif //INC_6502_EMULATOR_LDA_OPCODE_HANDLER_H
|
@ -1,58 +0,0 @@
|
||||
#include "ldx-opcode-handler.h"
|
||||
|
||||
const uint8_t LdxOpcodeHandler::IMMEDIATE;
|
||||
const uint8_t LdxOpcodeHandler::ZERO_PAGE;
|
||||
const uint8_t LdxOpcodeHandler::ZERO_PAGE_Y;
|
||||
const uint8_t LdxOpcodeHandler::ABSOLUTE;
|
||||
const uint8_t LdxOpcodeHandler::ABSOLUTE_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 x_reg = reg_man->get_x_index();
|
||||
|
||||
switch (opcode) {
|
||||
case IMMEDIATE:
|
||||
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: {
|
||||
// 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);
|
||||
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:
|
||||
throw_unexpected_opcode(opcode);
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
#ifndef INC_6502_EMULATOR_LDX_OPCODE_HANDLER_H
|
||||
#define INC_6502_EMULATOR_LDX_OPCODE_HANDLER_H
|
||||
|
||||
#include "../../program.h"
|
||||
#include "../opcode-handler.h"
|
||||
|
||||
class LdxOpcodeHandler : public OpcodeHandler {
|
||||
public:
|
||||
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,
|
||||
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_Y);
|
||||
handled_opcodes->push_back(ABSOLUTE);
|
||||
handled_opcodes->push_back(ABSOLUTE_Y);
|
||||
}
|
||||
|
||||
virtual void execute() override;
|
||||
};
|
||||
|
||||
#endif //INC_6502_EMULATOR_LDX_OPCODE_HANDLER_H
|
@ -1,17 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
#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,57 +0,0 @@
|
||||
#include "register-opcode-handler.h"
|
||||
|
||||
const uint8_t RegisterOpcodeHandler::TAX;
|
||||
const uint8_t RegisterOpcodeHandler::TXA;
|
||||
const uint8_t RegisterOpcodeHandler::DEX;
|
||||
const uint8_t RegisterOpcodeHandler::INX;
|
||||
const uint8_t RegisterOpcodeHandler::TAY;
|
||||
const uint8_t RegisterOpcodeHandler::TYA;
|
||||
const uint8_t RegisterOpcodeHandler::DEY;
|
||||
const uint8_t RegisterOpcodeHandler::INY;
|
||||
|
||||
void RegisterOpcodeHandler::execute() {
|
||||
auto instructionIndex = reg_man->get_program_counter()->get_value();
|
||||
auto opcode = program->get_byte_at(instructionIndex);
|
||||
auto accumulator = reg_man->get_accumulator();
|
||||
auto x_index = reg_man->get_x_index();
|
||||
auto y_index = reg_man->get_y_index();
|
||||
|
||||
switch (opcode) {
|
||||
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:
|
||||
throw_unexpected_opcode(opcode);
|
||||
}
|
||||
|
||||
move_program_counter(1);
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
#ifndef INC_6502_EMULATOR_REGISTER_OPCODE_HANDLER_H
|
||||
#define INC_6502_EMULATOR_REGISTER_OPCODE_HANDLER_H
|
||||
|
||||
#include "../../program.h"
|
||||
#include "../opcode-handler.h"
|
||||
|
||||
class RegisterOpcodeHandler : public OpcodeHandler {
|
||||
public:
|
||||
static const uint8_t TAX = 0xAA;
|
||||
static const uint8_t TXA = 0x8A;
|
||||
static const uint8_t DEX = 0xCA;
|
||||
static const uint8_t INX = 0xE8;
|
||||
static const uint8_t TAY = 0xA8;
|
||||
static const uint8_t TYA = 0x98;
|
||||
static const uint8_t DEY = 0x88;
|
||||
static const uint8_t INY = 0xC8;
|
||||
|
||||
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);
|
||||
handled_opcodes->push_back(INX);
|
||||
handled_opcodes->push_back(TAY);
|
||||
handled_opcodes->push_back(TYA);
|
||||
handled_opcodes->push_back(DEY);
|
||||
handled_opcodes->push_back(INY);
|
||||
}
|
||||
|
||||
virtual void execute() override;
|
||||
};
|
||||
|
||||
|
||||
#endif //INC_6502_EMULATOR_REGISTER_OPCODE_HANDLER_H
|
@ -1,39 +0,0 @@
|
||||
#include "stack-opcode-handler.h"
|
||||
|
||||
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:
|
||||
throw_unexpected_opcode(opcode);
|
||||
}
|
||||
|
||||
move_program_counter(1);
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
#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
|
@ -1,39 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
#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
|
@ -1,39 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
#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,39 +0,0 @@
|
||||
#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>
|
||||
#include <stdexcept>
|
||||
|
||||
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>(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)));
|
||||
}
|
||||
|
||||
void OpcodeHandlerDirectory::register_handler(shared_ptr<OpcodeHandler> handler) {
|
||||
for (auto opcode: *handler->get_handled_opcodes()) {
|
||||
handlers->insert({opcode, handler});
|
||||
}
|
||||
}
|
||||
|
||||
shared_ptr<OpcodeHandler> OpcodeHandlerDirectory::get_handler(uint8_t opcode) {
|
||||
if (handlers->find(opcode) == handlers->end()) {
|
||||
stringstream stream;
|
||||
stream << "No handler registered for opcode 0x" << hex << opcode;
|
||||
throw runtime_error(stream.str());
|
||||
}
|
||||
|
||||
return handlers->at(opcode);
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
#ifndef INC_6502_EMULATOR_OPCODE_HANDLER_DIRECTORY_H
|
||||
#define INC_6502_EMULATOR_OPCODE_HANDLER_DIRECTORY_H
|
||||
|
||||
#include "../program.h"
|
||||
#include "../memory.h"
|
||||
#include "opcode-handler.h"
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class OpcodeHandlerDirectory {
|
||||
public:
|
||||
explicit OpcodeHandlerDirectory(shared_ptr<Program> program, shared_ptr<RegisterManager> reg_man, shared_ptr<Memory> memory);
|
||||
|
||||
shared_ptr<OpcodeHandler> get_handler(uint8_t opcode);
|
||||
private:
|
||||
unique_ptr<unordered_map<uint8_t, shared_ptr<OpcodeHandler>>> handlers;
|
||||
|
||||
void register_handler(shared_ptr<OpcodeHandler> handler);
|
||||
};
|
||||
|
||||
|
||||
#endif //INC_6502_EMULATOR_OPCODE_HANDLER_DIRECTORY_H
|
@ -1,21 +0,0 @@
|
||||
#include "opcode-handler.h"
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
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) {
|
||||
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());
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
#ifndef INC_6502_EMULATOR_OPCODE_HANDLER_H
|
||||
#define INC_6502_EMULATOR_OPCODE_HANDLER_H
|
||||
|
||||
#include "../program.h"
|
||||
#include "../memory.h"
|
||||
#include "../register/register-manager.h"
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class OpcodeHandler {
|
||||
public:
|
||||
OpcodeHandler(shared_ptr<Program> program, shared_ptr<RegisterManager> reg_man, shared_ptr<Memory> memory);
|
||||
|
||||
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;
|
||||
shared_ptr<Memory> memory;
|
||||
shared_ptr<RegisterManager> reg_man;
|
||||
|
||||
void move_program_counter(uint8_t forward_by);
|
||||
};
|
||||
|
||||
|
||||
#endif //INC_6502_EMULATOR_OPCODE_HANDLER_H
|
@ -1,19 +0,0 @@
|
||||
#include "program.h"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
Program::Program(shared_ptr<vector<uint8_t>> bytes) {
|
||||
this->bytes = bytes;
|
||||
}
|
||||
|
||||
uint16_t Program::get_size() {
|
||||
return bytes->size();
|
||||
}
|
||||
|
||||
uint8_t Program::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 program");
|
||||
|
||||
return bytes->at(index);
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
#ifndef INC_6502_EMULATOR_PROGRAM_H
|
||||
#define INC_6502_EMULATOR_PROGRAM_H
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class Program {
|
||||
public:
|
||||
explicit Program(shared_ptr<vector<uint8_t>> bytes);
|
||||
|
||||
uint8_t get_byte_at(uint16_t index);
|
||||
uint16_t get_size();
|
||||
|
||||
private:
|
||||
shared_ptr<vector<uint8_t>> bytes;
|
||||
};
|
||||
|
||||
|
||||
#endif //INC_6502_EMULATOR_PROGRAM_H
|
@ -1,39 +0,0 @@
|
||||
#include "register-manager.h"
|
||||
#include "register.h"
|
||||
#include <memory>
|
||||
#include <cstring>
|
||||
|
||||
using namespace std;
|
||||
|
||||
RegisterManager::RegisterManager() {
|
||||
accumulator = std::make_shared<Register<uint8_t>>(Register<uint8_t>("A"));
|
||||
x_index = make_shared<Register<uint8_t>>(Register<uint8_t>("X"));
|
||||
y_index = make_shared<Register<uint8_t>>(Register<uint8_t>("Y"));
|
||||
stack_pointer = make_shared<Register<uint8_t>>(Register<uint8_t>("SP"));
|
||||
status_register = make_shared<StatusRegister>(StatusRegister());
|
||||
program_counter = make_shared<Register<uint16_t>>(Register<uint16_t>("PC"));
|
||||
}
|
||||
|
||||
shared_ptr<Register<uint8_t>> RegisterManager::get_accumulator() {
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
shared_ptr<Register<uint8_t>> RegisterManager::get_x_index() {
|
||||
return x_index;
|
||||
}
|
||||
|
||||
shared_ptr<Register<uint8_t>> RegisterManager::get_y_index() {
|
||||
return y_index;
|
||||
}
|
||||
|
||||
shared_ptr<Register<uint8_t>> RegisterManager::get_stack_pointer() {
|
||||
return stack_pointer;
|
||||
}
|
||||
|
||||
shared_ptr<StatusRegister> RegisterManager::get_status_register() {
|
||||
return status_register;
|
||||
}
|
||||
|
||||
shared_ptr<Register<uint16_t>> RegisterManager::get_program_counter() {
|
||||
return program_counter;
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
#ifndef INC_6502_EMULATOR_REGISTER_MANAGER_H
|
||||
#define INC_6502_EMULATOR_REGISTER_MANAGER_H
|
||||
|
||||
#include "register.h"
|
||||
#include "status-register.h"
|
||||
#include <memory>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class RegisterManager {
|
||||
public:
|
||||
explicit RegisterManager();
|
||||
|
||||
shared_ptr<Register<uint8_t>> get_accumulator();
|
||||
|
||||
shared_ptr<Register<uint8_t>> get_x_index();
|
||||
|
||||
shared_ptr<Register<uint8_t>> get_y_index();
|
||||
|
||||
shared_ptr<Register<uint8_t>> get_stack_pointer();
|
||||
|
||||
shared_ptr<StatusRegister> get_status_register();
|
||||
|
||||
shared_ptr<Register<uint16_t>> get_program_counter();
|
||||
|
||||
private:
|
||||
shared_ptr<Register<uint8_t>> accumulator;
|
||||
shared_ptr<Register<uint8_t>> x_index;
|
||||
shared_ptr<Register<uint8_t>> y_index;
|
||||
shared_ptr<Register<uint8_t>> stack_pointer;
|
||||
shared_ptr<StatusRegister> status_register;
|
||||
shared_ptr<Register<uint16_t>> program_counter;
|
||||
};
|
||||
|
||||
|
||||
#endif //INC_6502_EMULATOR_REGISTER_MANAGER_H
|
@ -1,30 +0,0 @@
|
||||
#include "register.h"
|
||||
#include <stdexcept>
|
||||
#include <bitset>
|
||||
|
||||
using namespace std;
|
||||
|
||||
template<class T>
|
||||
Register<T>::Register(string name) {
|
||||
this->name = name;
|
||||
this->value = 0;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
string Register<T>::get_name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T Register<T>::get_value() {
|
||||
return value;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void Register<T>::set_value(T value) {
|
||||
this->value = value;
|
||||
}
|
||||
|
||||
template class Register<uint8_t>;
|
||||
template class Register<uint16_t>;
|
||||
template class Register<bitset<8>>;
|
@ -1,28 +0,0 @@
|
||||
#ifndef INC_6502_EMULATOR_REGISTER_H
|
||||
#define INC_6502_EMULATOR_REGISTER_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
template <class T>
|
||||
class Register
|
||||
{
|
||||
public:
|
||||
explicit Register<T>(string name);
|
||||
|
||||
string get_name();
|
||||
|
||||
T get_value();
|
||||
void set_value(T value);
|
||||
|
||||
protected:
|
||||
T value;
|
||||
|
||||
private:
|
||||
string name;
|
||||
};
|
||||
|
||||
|
||||
#endif //INC_6502_EMULATOR_REGISTER_H
|
@ -1,65 +0,0 @@
|
||||
#include "status-register.h"
|
||||
|
||||
const uint8_t CARRY_FLAG = 0;
|
||||
const uint8_t ZERO_FLAG = 1;
|
||||
const uint8_t INTERUPT_DISABLE_FLAG = 2;
|
||||
const uint8_t DECIMAL_FLAG = 3;
|
||||
const uint8_t BREAK_FLAG = 4;
|
||||
const uint8_t OVERFLOW_FLAG = 6;
|
||||
const uint8_t NEGATIVE_FLAG = 7;
|
||||
|
||||
bool StatusRegister::is_carry_set() {
|
||||
return this->value[CARRY_FLAG];
|
||||
}
|
||||
|
||||
bool StatusRegister::is_zero_set() {
|
||||
return this->value[ZERO_FLAG];
|
||||
}
|
||||
|
||||
bool StatusRegister::is_interupt_disable_set() {
|
||||
return this->value[INTERUPT_DISABLE_FLAG];
|
||||
}
|
||||
|
||||
bool StatusRegister::is_decimal_set() {
|
||||
return this->value[DECIMAL_FLAG];
|
||||
}
|
||||
|
||||
bool StatusRegister::is_break_set() {
|
||||
return this->value[BREAK_FLAG];
|
||||
}
|
||||
|
||||
bool StatusRegister::is_overflow_set() {
|
||||
return this->value[OVERFLOW_FLAG];
|
||||
}
|
||||
|
||||
bool StatusRegister::is_negative_set() {
|
||||
return this->value[NEGATIVE_FLAG];
|
||||
}
|
||||
|
||||
void StatusRegister::set_carry(bool state) {
|
||||
this->value[CARRY_FLAG] = state;
|
||||
}
|
||||
|
||||
void StatusRegister::set_zero(bool state) {
|
||||
this->value[ZERO_FLAG] = state;
|
||||
}
|
||||
|
||||
void StatusRegister::set_interupt_disable(bool state) {
|
||||
this->value[INTERUPT_DISABLE_FLAG] = state;
|
||||
}
|
||||
|
||||
void StatusRegister::set_decimal(bool state) {
|
||||
this->value[DECIMAL_FLAG] = state;
|
||||
}
|
||||
|
||||
void StatusRegister::set_break(bool state) {
|
||||
this->value[BREAK_FLAG] = state;
|
||||
}
|
||||
|
||||
void StatusRegister::set_overflow(bool state) {
|
||||
this->value[OVERFLOW_FLAG] = state;
|
||||
}
|
||||
|
||||
void StatusRegister::set_negative(bool state) {
|
||||
this->value[NEGATIVE_FLAG] = state;
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
#ifndef INC_6502_EMULATOR_STATUS_REGISTER_H
|
||||
#define INC_6502_EMULATOR_STATUS_REGISTER_H
|
||||
|
||||
#include "register.h"
|
||||
#include <bitset>
|
||||
|
||||
class StatusRegister : public Register<bitset<8>> {
|
||||
public:
|
||||
explicit StatusRegister() : Register<bitset<8>>("P") {}
|
||||
|
||||
bool is_carry_set();
|
||||
bool is_zero_set();
|
||||
bool is_interupt_disable_set();
|
||||
bool is_decimal_set();
|
||||
bool is_break_set();
|
||||
bool is_overflow_set();
|
||||
bool is_negative_set();
|
||||
|
||||
void set_carry(bool state);
|
||||
void set_zero(bool state);
|
||||
void set_interupt_disable(bool state);
|
||||
void set_decimal(bool state);
|
||||
void set_break(bool state);
|
||||
void set_overflow(bool state);
|
||||
void set_negative(bool state);
|
||||
};
|
||||
|
||||
|
||||
#endif //INC_6502_EMULATOR_STATUS_REGISTER_H
|
@ -1,26 +0,0 @@
|
||||
#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
22
src/stack.h
@ -1,22 +0,0 @@
|
||||
#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
|
@ -1,112 +0,0 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "../src/machine.h"
|
||||
#include "../src/program.h"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
const uint8_t CLC = 0x18;
|
||||
const uint8_t SEC = 0x38;
|
||||
const uint8_t CLI = 0x58;
|
||||
const uint8_t SEI = 0x78;
|
||||
const uint8_t CLV = 0xB8;
|
||||
const uint8_t CLD = 0xD8;
|
||||
const uint8_t SED = 0xF8;
|
||||
|
||||
unique_ptr<Machine> ft_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(FlagOpcodeHandlerTest, ClearCarry) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{CLC});
|
||||
auto machine = ft_get_machine(code);
|
||||
auto status = machine->get_reg_man()->get_status_register();
|
||||
|
||||
ASSERT_EQ(0, status->is_carry_set());
|
||||
|
||||
status->set_carry(true);
|
||||
ASSERT_EQ(1, status->is_carry_set());
|
||||
|
||||
machine->execute();
|
||||
ASSERT_EQ(0, status->is_carry_set());
|
||||
}
|
||||
|
||||
TEST(FlagOpcodeHandlerTest, SetCarry) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{SEC});
|
||||
auto machine = ft_get_machine(code);
|
||||
auto status = machine->get_reg_man()->get_status_register();
|
||||
|
||||
ASSERT_EQ(0, status->is_carry_set());
|
||||
|
||||
machine->execute();
|
||||
ASSERT_EQ(1, status->is_carry_set());
|
||||
}
|
||||
|
||||
TEST(FlagOpcodeHandlerTest, ClearInteruptDisable) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{CLI});
|
||||
auto machine = ft_get_machine(code);
|
||||
auto status = machine->get_reg_man()->get_status_register();
|
||||
|
||||
ASSERT_EQ(0, status->is_interupt_disable_set());
|
||||
|
||||
status->set_interupt_disable(true);
|
||||
ASSERT_EQ(1, status->is_interupt_disable_set());
|
||||
|
||||
machine->execute();
|
||||
ASSERT_EQ(0, status->is_interupt_disable_set());
|
||||
}
|
||||
|
||||
TEST(FlagOpcodeHandlerTest, SetInteruptDisable) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{SEI});
|
||||
auto machine = ft_get_machine(code);
|
||||
auto status = machine->get_reg_man()->get_status_register();
|
||||
|
||||
ASSERT_EQ(0, status->is_interupt_disable_set());
|
||||
|
||||
machine->execute();
|
||||
ASSERT_EQ(1, status->is_interupt_disable_set());
|
||||
}
|
||||
|
||||
TEST(FlagOpcodeHandlerTest, ClearOverflow) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{CLV});
|
||||
auto machine = ft_get_machine(code);
|
||||
auto status = machine->get_reg_man()->get_status_register();
|
||||
|
||||
ASSERT_EQ(0, status->is_overflow_set());
|
||||
|
||||
status->set_overflow(true);
|
||||
ASSERT_EQ(1, status->is_overflow_set());
|
||||
|
||||
machine->execute();
|
||||
ASSERT_EQ(0, status->is_overflow_set());
|
||||
}
|
||||
|
||||
TEST(FlagOpcodeHandlerTest, ClearDecimal) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{CLD});
|
||||
auto machine = ft_get_machine(code);
|
||||
auto status = machine->get_reg_man()->get_status_register();
|
||||
|
||||
ASSERT_EQ(0, status->is_decimal_set());
|
||||
|
||||
status->set_decimal(true);
|
||||
ASSERT_EQ(1, status->is_decimal_set());
|
||||
|
||||
machine->execute();
|
||||
ASSERT_EQ(0, status->is_decimal_set());
|
||||
}
|
||||
|
||||
TEST(FlagOpcodeHandlerTest, SetDecimal) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{SED});
|
||||
auto machine = ft_get_machine(code);
|
||||
auto status = machine->get_reg_man()->get_status_register();
|
||||
|
||||
ASSERT_EQ(0, status->is_decimal_set());
|
||||
|
||||
machine->execute();
|
||||
ASSERT_EQ(1, status->is_decimal_set());
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "../src/program.h"
|
||||
#include "../src/instruction/instruction-executor.h"
|
||||
#include "../src/register/register-manager.h"
|
||||
#include "../src/opcode/opcode-handler-directory.h"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
const uint8_t CLC = 0x18;
|
||||
const uint8_t SEC = 0x38;
|
||||
|
||||
const uint8_t LDX_IMMEDIATE = 0xA9;
|
||||
|
||||
TEST(InstructionExecutor, Execute) {
|
||||
auto reg_man = make_shared<RegisterManager>(RegisterManager());
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>
|
||||
{SEC,
|
||||
CLC
|
||||
});
|
||||
auto program = make_shared<Program>(Program(code));
|
||||
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();
|
||||
}
|
@ -1,199 +0,0 @@
|
||||
#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());
|
||||
}
|
@ -1,106 +0,0 @@
|
||||
#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, 0x50});
|
||||
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(0x50, 255);
|
||||
machine->execute();
|
||||
ASSERT_EQ(255, x_reg->get_value());
|
||||
|
||||
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(0x67, 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());
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "../src/machine.h"
|
||||
#include "../src/program.h"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
const uint8_t CLC = 0x18;
|
||||
const uint8_t SEC = 0x38;
|
||||
const uint8_t CLI = 0x58;
|
||||
const uint8_t SEI = 0x78;
|
||||
const uint8_t CLV = 0xB8;
|
||||
const uint8_t CLD = 0xD8;
|
||||
const uint8_t SED = 0xF8;
|
||||
|
||||
const uint8_t LDX_IMMEDIATE = 0xA9;
|
||||
|
||||
TEST(Machine, Execute) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{SEC, SEI, SED, CLI, CLV, CLD, CLC, LDX_IMMEDIATE, 0x6B});
|
||||
auto program = make_shared<Program>(Program(code));
|
||||
auto machine = make_unique<Machine>(Machine(program));
|
||||
|
||||
machine->execute();
|
||||
}
|
@ -1,219 +0,0 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "../src/machine.h"
|
||||
#include "../src/program.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
const uint8_t TAX = 0xAA;
|
||||
const uint8_t TXA = 0x8A;
|
||||
const uint8_t DEX = 0xCA;
|
||||
const uint8_t INX = 0xE8;
|
||||
const uint8_t TAY = 0xA8;
|
||||
const uint8_t TYA = 0x98;
|
||||
const uint8_t DEY = 0x88;
|
||||
const uint8_t INY = 0xC8;
|
||||
|
||||
unique_ptr<Machine> rt_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(RegisterOpcodeHandler, TransferAtoX) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{TAX});
|
||||
auto machine = rt_get_machine(code);
|
||||
auto reg_man = machine->get_reg_man();
|
||||
|
||||
auto aval = reg_man->get_accumulator()->get_value();
|
||||
auto xval = reg_man->get_x_index()->get_value();
|
||||
ASSERT_EQ(0, aval);
|
||||
ASSERT_EQ(0, xval);
|
||||
|
||||
machine->execute();
|
||||
aval = reg_man->get_accumulator()->get_value();
|
||||
xval = reg_man->get_x_index()->get_value();
|
||||
ASSERT_EQ(0, aval);
|
||||
ASSERT_EQ(0, xval);
|
||||
|
||||
reg_man->get_program_counter()->set_value(0);
|
||||
reg_man->get_accumulator()->set_value(0x3e);
|
||||
machine->execute();
|
||||
aval = reg_man->get_accumulator()->get_value();
|
||||
xval = reg_man->get_x_index()->get_value();
|
||||
ASSERT_EQ(0x3e, aval);
|
||||
ASSERT_EQ(0x3e, xval);
|
||||
}
|
||||
|
||||
TEST(RegisterOpcodeHandler, TransferXtoA) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{TXA});
|
||||
auto machine = rt_get_machine(code);
|
||||
auto reg_man = machine->get_reg_man();
|
||||
|
||||
auto aval = reg_man->get_accumulator()->get_value();
|
||||
auto xval = reg_man->get_x_index()->get_value();
|
||||
ASSERT_EQ(0, aval);
|
||||
ASSERT_EQ(0, xval);
|
||||
|
||||
machine->execute();
|
||||
aval = reg_man->get_accumulator()->get_value();
|
||||
xval = reg_man->get_x_index()->get_value();
|
||||
ASSERT_EQ(0, aval);
|
||||
ASSERT_EQ(0, xval);
|
||||
|
||||
reg_man->get_program_counter()->set_value(0);
|
||||
reg_man->get_x_index()->set_value(0x4f);
|
||||
machine->execute();
|
||||
aval = reg_man->get_accumulator()->get_value();
|
||||
xval = reg_man->get_x_index()->get_value();
|
||||
ASSERT_EQ(0x4f, aval);
|
||||
ASSERT_EQ(0x4f, xval);
|
||||
}
|
||||
|
||||
TEST(RegisterOpcodeHandler, DecrementX) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{DEX});
|
||||
auto machine = rt_get_machine(code);
|
||||
auto reg_man = machine->get_reg_man();
|
||||
|
||||
auto xval = reg_man->get_x_index()->get_value();
|
||||
ASSERT_EQ(0, xval);
|
||||
|
||||
machine->execute();
|
||||
xval = reg_man->get_x_index()->get_value();
|
||||
ASSERT_EQ(0xff, xval);
|
||||
|
||||
reg_man->get_program_counter()->set_value(0);
|
||||
machine->execute();
|
||||
xval = reg_man->get_x_index()->get_value();
|
||||
ASSERT_EQ(0xfe, xval);
|
||||
|
||||
reg_man->get_program_counter()->set_value(0);
|
||||
reg_man->get_x_index()->set_value(0x45);
|
||||
machine->execute();
|
||||
xval = reg_man->get_x_index()->get_value();
|
||||
ASSERT_EQ(0x44, xval);
|
||||
}
|
||||
|
||||
TEST(RegisterOpcodeHandler, IncrementX) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{INX});
|
||||
auto machine = rt_get_machine(code);
|
||||
auto reg_man = machine->get_reg_man();
|
||||
|
||||
auto xval = reg_man->get_x_index()->get_value();
|
||||
ASSERT_EQ(0, xval);
|
||||
|
||||
machine->execute();
|
||||
xval = reg_man->get_x_index()->get_value();
|
||||
ASSERT_EQ(0x01, xval);
|
||||
|
||||
reg_man->get_program_counter()->set_value(0);
|
||||
machine->execute();
|
||||
xval = reg_man->get_x_index()->get_value();
|
||||
ASSERT_EQ(0x02, xval);
|
||||
|
||||
reg_man->get_program_counter()->set_value(0);
|
||||
reg_man->get_x_index()->set_value(0x45);
|
||||
machine->execute();
|
||||
xval = reg_man->get_x_index()->get_value();
|
||||
ASSERT_EQ(0x46, xval);
|
||||
}
|
||||
|
||||
TEST(RegisterOpcodeHandler, TransferAtoY) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{TAY});
|
||||
auto machine = rt_get_machine(code);
|
||||
auto reg_man = machine->get_reg_man();
|
||||
|
||||
auto aval = reg_man->get_accumulator()->get_value();
|
||||
auto yval = reg_man->get_y_index()->get_value();
|
||||
ASSERT_EQ(0, aval);
|
||||
ASSERT_EQ(0, yval);
|
||||
|
||||
machine->execute();
|
||||
aval = reg_man->get_accumulator()->get_value();
|
||||
yval = reg_man->get_y_index()->get_value();
|
||||
ASSERT_EQ(0, aval);
|
||||
ASSERT_EQ(0, yval);
|
||||
|
||||
reg_man->get_program_counter()->set_value(0);
|
||||
reg_man->get_accumulator()->set_value(0xaf);
|
||||
machine->execute();
|
||||
aval = reg_man->get_accumulator()->get_value();
|
||||
yval = reg_man->get_y_index()->get_value();
|
||||
ASSERT_EQ(0xaf, aval);
|
||||
ASSERT_EQ(0xaf, yval);
|
||||
}
|
||||
|
||||
TEST(RegisterOpcodeHandler, TransferYtoA) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{TYA});
|
||||
auto machine = rt_get_machine(code);
|
||||
auto reg_man = machine->get_reg_man();
|
||||
|
||||
auto aval = reg_man->get_accumulator()->get_value();
|
||||
auto yval = reg_man->get_y_index()->get_value();
|
||||
ASSERT_EQ(0, aval);
|
||||
ASSERT_EQ(0, yval);
|
||||
|
||||
machine->execute();
|
||||
aval = reg_man->get_accumulator()->get_value();
|
||||
yval = reg_man->get_y_index()->get_value();
|
||||
ASSERT_EQ(0, aval);
|
||||
ASSERT_EQ(0, yval);
|
||||
|
||||
reg_man->get_program_counter()->set_value(0);
|
||||
reg_man->get_y_index()->set_value(0xff);
|
||||
machine->execute();
|
||||
aval = reg_man->get_accumulator()->get_value();
|
||||
yval = reg_man->get_y_index()->get_value();
|
||||
ASSERT_EQ(0xff, aval);
|
||||
ASSERT_EQ(0xff, yval);
|
||||
}
|
||||
|
||||
TEST(RegisterOpcodeHandler, DecrementY) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{DEY});
|
||||
auto machine = rt_get_machine(code);
|
||||
auto reg_man = machine->get_reg_man();
|
||||
|
||||
auto yval = reg_man->get_y_index()->get_value();
|
||||
ASSERT_EQ(0, yval);
|
||||
|
||||
machine->execute();
|
||||
yval = reg_man->get_y_index()->get_value();
|
||||
ASSERT_EQ(0xff, yval);
|
||||
|
||||
reg_man->get_program_counter()->set_value(0);
|
||||
machine->execute();
|
||||
yval = reg_man->get_y_index()->get_value();
|
||||
ASSERT_EQ(0xfe, yval);
|
||||
|
||||
reg_man->get_program_counter()->set_value(0);
|
||||
reg_man->get_y_index()->set_value(0x3b);
|
||||
machine->execute();
|
||||
yval = reg_man->get_y_index()->get_value();
|
||||
ASSERT_EQ(0x3a, yval);
|
||||
}
|
||||
|
||||
TEST(RegisterOpcodeHandler, IncrementY) {
|
||||
auto code = make_shared<vector<uint8_t>>(vector<uint8_t>{INY});
|
||||
auto machine = rt_get_machine(code);
|
||||
auto reg_man = machine->get_reg_man();
|
||||
|
||||
auto yval = reg_man->get_y_index()->get_value();
|
||||
ASSERT_EQ(0, yval);
|
||||
|
||||
machine->execute();
|
||||
yval = reg_man->get_y_index()->get_value();
|
||||
ASSERT_EQ(0x01, yval);
|
||||
|
||||
reg_man->get_program_counter()->set_value(0);
|
||||
machine->execute();
|
||||
yval = reg_man->get_y_index()->get_value();
|
||||
ASSERT_EQ(0x02, yval);
|
||||
|
||||
reg_man->get_program_counter()->set_value(0);
|
||||
reg_man->get_y_index()->set_value(0x3b);
|
||||
machine->execute();
|
||||
yval = reg_man->get_y_index()->get_value();
|
||||
ASSERT_EQ(0x3c, yval);
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "../src/register/register.h"
|
||||
|
||||
TEST(Construct, Equals) {
|
||||
auto reg = new Register<uint16_t>("PC");
|
||||
|
||||
EXPECT_EQ("PC", reg->get_name());
|
||||
}
|
@ -1,112 +0,0 @@
|
||||
#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);
|
||||
}
|
@ -1,170 +0,0 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "../src/register/status-register.h"
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
string get_bit_pattern(StatusRegister* reg) {
|
||||
stringstream stream;
|
||||
stream << reg->get_value();
|
||||
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
TEST(StatusRegister, Construct) {
|
||||
auto reg = make_unique<StatusRegister>(StatusRegister());
|
||||
auto bit_pattern = get_bit_pattern(reg.get());
|
||||
|
||||
EXPECT_EQ("P", reg->get_name());
|
||||
|
||||
EXPECT_EQ("00000000", bit_pattern);
|
||||
|
||||
EXPECT_EQ(false, reg->is_carry_set());
|
||||
EXPECT_EQ(false, reg->is_zero_set());
|
||||
EXPECT_EQ(false, reg->is_interupt_disable_set());
|
||||
EXPECT_EQ(false, reg->is_decimal_set());
|
||||
EXPECT_EQ(false, reg->is_break_set());
|
||||
EXPECT_EQ(false, reg->is_overflow_set());
|
||||
EXPECT_EQ(false, reg->is_negative_set());
|
||||
}
|
||||
|
||||
TEST(StatusRegister, CarryFlag) {
|
||||
auto reg = make_unique<StatusRegister>(StatusRegister());
|
||||
EXPECT_EQ(false, reg->is_carry_set());
|
||||
|
||||
reg->set_carry(true);
|
||||
EXPECT_EQ(true, reg->is_carry_set());
|
||||
|
||||
auto bit_pattern = get_bit_pattern(reg.get());
|
||||
EXPECT_EQ("00000001", bit_pattern);
|
||||
|
||||
reg->set_carry(false);
|
||||
EXPECT_EQ(false, reg->is_carry_set());
|
||||
bit_pattern = get_bit_pattern(reg.get());
|
||||
EXPECT_EQ("00000000", bit_pattern);
|
||||
}
|
||||
|
||||
TEST(StatusRegister, ZeroFlag) {
|
||||
auto reg = make_unique<StatusRegister>(StatusRegister());
|
||||
EXPECT_EQ(false, reg->is_zero_set());
|
||||
|
||||
reg->set_zero(true);
|
||||
EXPECT_EQ(true, reg->is_zero_set());
|
||||
|
||||
auto bit_pattern = get_bit_pattern(reg.get());
|
||||
EXPECT_EQ("00000010", bit_pattern);
|
||||
|
||||
reg->set_zero(false);
|
||||
EXPECT_EQ(false, reg->is_zero_set());
|
||||
bit_pattern = get_bit_pattern(reg.get());
|
||||
EXPECT_EQ("00000000", bit_pattern);
|
||||
}
|
||||
|
||||
TEST(StatusRegister, InteruptDisableFlag) {
|
||||
auto reg = make_unique<StatusRegister>(StatusRegister());
|
||||
EXPECT_EQ(false, reg->is_interupt_disable_set());
|
||||
|
||||
reg->set_interupt_disable(true);
|
||||
EXPECT_EQ(true, reg->is_interupt_disable_set());
|
||||
|
||||
auto bit_pattern = get_bit_pattern(reg.get());
|
||||
EXPECT_EQ("00000100", bit_pattern);
|
||||
|
||||
reg->set_interupt_disable(false);
|
||||
EXPECT_EQ(false, reg->is_interupt_disable_set());
|
||||
bit_pattern = get_bit_pattern(reg.get());
|
||||
EXPECT_EQ("00000000", bit_pattern);
|
||||
}
|
||||
|
||||
TEST(StatusRegister, DecimalFlag) {
|
||||
auto reg = make_unique<StatusRegister>(StatusRegister());
|
||||
EXPECT_EQ(false, reg->is_decimal_set());
|
||||
|
||||
reg->set_decimal(true);
|
||||
EXPECT_EQ(true, reg->is_decimal_set());
|
||||
|
||||
auto bit_pattern = get_bit_pattern(reg.get());
|
||||
EXPECT_EQ("00001000", bit_pattern);
|
||||
|
||||
reg->set_decimal(false);
|
||||
EXPECT_EQ(false, reg->is_decimal_set());
|
||||
bit_pattern = get_bit_pattern(reg.get());
|
||||
EXPECT_EQ("00000000", bit_pattern);
|
||||
}
|
||||
|
||||
TEST(StatusRegister, BreakFlag) {
|
||||
auto reg = make_unique<StatusRegister>(StatusRegister());
|
||||
EXPECT_EQ(false, reg->is_break_set());
|
||||
|
||||
reg->set_break(true);
|
||||
EXPECT_EQ(true, reg->is_break_set());
|
||||
|
||||
auto bit_pattern = get_bit_pattern(reg.get());
|
||||
EXPECT_EQ("00010000", bit_pattern);
|
||||
|
||||
reg->set_break(false);
|
||||
EXPECT_EQ(false, reg->is_break_set());
|
||||
bit_pattern = get_bit_pattern(reg.get());
|
||||
EXPECT_EQ("00000000", bit_pattern);
|
||||
}
|
||||
|
||||
TEST(StatusRegister, OverflowFlag) {
|
||||
auto reg = make_unique<StatusRegister>(StatusRegister());
|
||||
EXPECT_EQ(false, reg->is_overflow_set());
|
||||
|
||||
reg->set_overflow(true);
|
||||
EXPECT_EQ(true, reg->is_overflow_set());
|
||||
|
||||
auto bit_pattern = get_bit_pattern(reg.get());
|
||||
EXPECT_EQ("01000000", bit_pattern);
|
||||
|
||||
reg->set_overflow(false);
|
||||
EXPECT_EQ(false, reg->is_overflow_set());
|
||||
bit_pattern = get_bit_pattern(reg.get());
|
||||
EXPECT_EQ("00000000", bit_pattern);
|
||||
}
|
||||
|
||||
TEST(StatusRegister, NegativeFlag) {
|
||||
auto reg = make_unique<StatusRegister>(StatusRegister());
|
||||
EXPECT_EQ(false, reg->is_negative_set());
|
||||
|
||||
reg->set_negative(true);
|
||||
EXPECT_EQ(true, reg->is_negative_set());
|
||||
|
||||
auto bit_pattern = get_bit_pattern(reg.get());
|
||||
EXPECT_EQ("10000000", bit_pattern);
|
||||
|
||||
reg->set_negative(false);
|
||||
EXPECT_EQ(false, reg->is_negative_set());
|
||||
bit_pattern = get_bit_pattern(reg.get());
|
||||
EXPECT_EQ("00000000", bit_pattern);
|
||||
}
|
||||
|
||||
TEST(StatusRegister, AllFlags) {
|
||||
auto reg = make_unique<StatusRegister>(StatusRegister());
|
||||
EXPECT_EQ(false, reg->is_negative_set());
|
||||
|
||||
reg->set_carry(true);
|
||||
reg->set_zero(true);
|
||||
reg->set_interupt_disable(true);
|
||||
reg->set_decimal(true);
|
||||
reg->set_break(true);
|
||||
reg->set_overflow(true);
|
||||
reg->set_negative(true);
|
||||
|
||||
auto bit_pattern = get_bit_pattern(reg.get());
|
||||
EXPECT_EQ("11011111", bit_pattern);
|
||||
|
||||
reg->set_carry(false);
|
||||
reg->set_zero(false);
|
||||
reg->set_interupt_disable(false);
|
||||
reg->set_decimal(false);
|
||||
reg->set_break(false);
|
||||
reg->set_overflow(false);
|
||||
reg->set_negative(false);
|
||||
|
||||
bit_pattern = get_bit_pattern(reg.get());
|
||||
EXPECT_EQ("00000000", bit_pattern);
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
#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));
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
#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
Block a user