#include "machine.h" #include "terminal.h" #include "keyboard.h" #include "../opcode/opcode-handler-directory.h" #include namespace emu_6502 { class MachineImpl { private: uint16_t code_loaded_at; uint16_t code_size; uint32_t instruction_iteration; unique_ptr cpu; unique_ptr memory; unique_ptr stack; unique_ptr terminal; unique_ptr keyboard; unique_ptr opcode_handler_dir; public: MachineImpl(bool init_terminal) { cpu = make_unique(); memory = make_unique(); stack = make_unique(*memory, cpu->get_sp()); keyboard = make_unique(*memory); if (init_terminal) terminal = make_unique(*memory); opcode_handler_dir = make_unique(); } MachineImpl(const MachineImpl&) = delete; MachineImpl& operator=(const MachineImpl&) = delete; Cpu& get_cpu() { return *cpu; } Memory& get_memory() { return *memory; } Stack& get_stack() { return *stack; } void load(const vector& program, uint16_t load_at) { code_loaded_at = load_at; code_size = program.size(); uint32_t code_end = load_at + code_size; if (code_end > 0xFE00) // need space for graphics, interupts, etc. throw runtime_error("Program does not fit into memory"); for (auto i = 0; i < program.size(); i++) memory->set_at(load_at + i, program.at(i)); cpu->get_pc().set_value(load_at); } bool is_eop() { return cpu->get_pc().get_value() >= code_loaded_at + code_size; } uint8_t read_program_byte() { if (is_eop()) throw runtime_error("Passed end of program"); auto byte = memory->get_at(cpu->get_pc().get_value()); cpu->get_pc().inc(); return byte; } void execute(Machine& machine) { while (!is_eop()) { auto byte = read_program_byte(); opcode_handler_dir->execute(byte, machine); if (instruction_iteration++ >= 100) { keyboard->read(); instruction_iteration = 0; } } } }; Machine::Machine(bool init_terminal) : pimpl(make_unique(init_terminal)) { } Machine::~Machine() = default; Cpu& Machine::get_cpu() { return pimpl->get_cpu(); } Memory& Machine::get_memory() { return pimpl->get_memory(); } Stack& Machine::get_stack() { return pimpl->get_stack(); } void Machine::load(const vector& program, uint16_t load_at) { pimpl->load(program, load_at); } bool Machine::is_eop() const { return pimpl->is_eop(); } uint8_t Machine::read_program_byte() { return pimpl->read_program_byte(); } void Machine::execute() { pimpl->execute(*this); } }