#pragma once #include #include #include #include "instruction.h" #define MEMORY_SIZE 0x00040000 // 256 kibibytes, or 262144 #define PROGRAM_ROM_START 0x00001000 #define GENERAL_PURPOSE_START 0x00010000 #define PC_REG_OFFSET 7 #define IHP_REG_OFFSET 8 #define SP_REG_OFFSET 9 #define FLAGS_REG_OFFSET 10 #define PC registers[PC_REG_OFFSET] #define IHP registers[PC_REG_OFFSET] #define SP registers[PC_REG_OFFSET] #define FLAGS registers[PC_REG_OFFSET] #define FLAGS_CARRY (1 << 0) #define FLAGS_ZERO (1 << 1) #define FLAGS_NEGATIVE (1 << 2) /* * All-purpose memory used by the emulator * 4kb for call stack (0x00000000 -> 0x00000FFF) * 65kb for program ROM (0x00001000 -> 0x0000FFFF) * Rest for general purpose (0x00010000 -> MEMORY_SIZE) */ struct Memory { size_t instructions = 0; size_t calls = 0; uint8_t memory[MEMORY_SIZE]{}; void addInstruction(const Instruction& inst); void addCall(const uint16_t address); uint8_t* operator[](const size_t& offset); Memory() = default; Memory(const std::vector& instructions) { for (const auto& instruction : instructions) { addInstruction(instruction.asBytecodeInstruction()); } } }; using Program = std::vector; class Emulator { private: std::array registers = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; Memory memory = {}; bool halted = false; Instruction fetchNextInst(); void updateFlags(int32_t opResult); public: void start(); Emulator() = delete; Emulator(const Memory& memory) : memory(std::move(memory)) {} };