#pragma once #include #include "cpu/cpu.h" #include "device/cache_control.h" #include "device/cdrom/cdrom.h" #include "device/controller/controller.h" #include "device/dma/dma.h" #include "device/expansion2.h" #include "device/gpu/gpu.h" #include "device/interrupt.h" #include "device/mdec/mdec.h" #include "device/memory_control.h" #include "device/ram_control.h" #include "device/serial.h" #include "device/spu/spu.h" #include "device/timer.h" #include "utils/macros.h" #include "utils/timing.h" #include #include /** * NOTE: * Build flags are configured with Premake5 build system */ /** * #define ENABLE_IO_LOG * Switch --enable-io-log * Default: false * * Enables IO access buffer log */ /** * #define ENABLE_BIOS_HOOKS * Switch --enable-bios-hooks * Default: false * * Enables BIOS syscall hooking/logging */ namespace bios { struct Function; } struct System { enum class State { halted, // Cannot be run until reset stop, // after reset pause, // if debugger attach run // normal state }; static const int BIOS_BASE = 0x1fc00000; static const int RAM_BASE = 0x00000000; static const int SCRATCHPAD_BASE = 0x1f800000; static const int EXPANSION_BASE = 0x1f000000; static const int IO_BASE = 0x1f801000; static const int BIOS_SIZE = 512 * 1024; static const int RAM_SIZE_2MB = 2 * 1024 * 1024; static const int RAM_SIZE_8MB = 8 * 1024 * 1024; static const int SCRATCHPAD_SIZE = 1024; static const int EXPANSION_SIZE = 1 * 1024 * 1024; static const int IO_SIZE = 0x2000; State state = State::stop; std::array bios; std::vector ram; std::array scratchpad; std::array expansion; bool debugOutput = true; // Print BIOS logs bool biosLoaded = false; uint64_t cycles; // Devices std::unique_ptr cpu; std::unique_ptr cdrom; std::unique_ptr controller; std::unique_ptr dma; std::unique_ptr expansion2; std::unique_ptr gpu; std::unique_ptr interrupt; std::unique_ptr mdec; std::unique_ptr memoryControl; std::unique_ptr ramControl; std::unique_ptr cacheControl; std::unique_ptr spu; std::unique_ptr serial; std::array, 3> timer; template INLINE T readMemory(uint32_t address); template INLINE void writeMemory(uint32_t address, T data); void singleStep(); void handleBiosFunction(); void handleSyscallFunction(); System(); uint8_t readMemory8(uint32_t address); uint16_t readMemory16(uint32_t address); uint32_t readMemory32(uint32_t address); void writeMemory8(uint32_t address, uint8_t data); void writeMemory16(uint32_t address, uint16_t data); void writeMemory32(uint32_t address, uint32_t data); void printFunctionInfo(const char* functionNum, const bios::Function& f); void emulateFrame(); void softReset(); bool isSystemReady(); // Helpers std::string biosPath; int biosLog = 0; bool printStackTrace = false; bool loadBios(const std::string& name); bool loadExpansion(const std::vector& _exe); bool loadExeFile(const std::vector& _exe); void dumpRam(); #ifdef ENABLE_IO_LOG struct IO_LOG_ENTRY { enum class MODE { READ, WRITE } mode; uint32_t size; uint32_t addr; uint32_t data; uint32_t pc; }; std::vector ioLogList; #endif template void serialize(Archive& ar) { ar(*cpu); ar(*gpu); ar(*spu); ar(*interrupt); ar(*dma); ar(*cdrom); ar(*memoryControl); ar(*cacheControl); ar(*serial); ar(*mdec); ar(*controller); for (auto i : {0, 1, 2}) ar(*timer[i]); ar(ram); ar(scratchpad); } };