#pragma once #include #include #include #include #include #include #include #include #include namespace n64 { struct ROMHeader { u8 initialValues[4]; u32 clockRate; u32 programCounter; u32 release; u32 crc1; u32 crc2; u64 unknown; char imageName[20]; u32 unknown2; u32 manufacturerId; u16 cartridgeId; char countryCode[2]; u8 bootCode[4032]; }; struct ROM { u8* cart; size_t size; size_t mask; ROMHeader header; CICType cicType; char gameNameCart[20]; std::string gameNameDB; char code[4]; bool pal; }; enum FlashState : u8 { Idle, Erase, Write, Read, Status }; struct Flash { Flash() = default; ~Flash() { FILE* f = fopen(saveDataPath.c_str(), "wb"); if(f) { fwrite(saveData, 1, 1_mb, f); fclose(f); } } void Load(SaveType, fs::path); FlashState state{}; u64 status{}; size_t eraseOffs{}; size_t writeOffs{}; u8 writeBuf[128]{}; u8* saveData = nullptr; bool saveDataDirty = false; std::string saveDataPath{}; enum FlashCommands : u8 { FLASH_COMMAND_EXECUTE = 0xD2, FLASH_COMMAND_STATUS = 0xE1, FLASH_COMMAND_SET_ERASE_OFFSET = 0x4B, FLASH_COMMAND_ERASE = 0x78, FLASH_COMMAND_SET_WRITE_OFFSET = 0xA5, FLASH_COMMAND_WRITE = 0xB4, FLASH_COMMAND_READ = 0xF0, }; void CommandExecute(); void CommandStatus(); void CommandSetEraseOffs(u32); void CommandErase(); void CommandSetWriteOffs(u32); void CommandWrite(); void CommandRead(); FORCE_INLINE void Write32(u32 index, u32 val) { if(index > 0) { u8 cmd = val >> 24; switch(cmd) { case FLASH_COMMAND_EXECUTE: CommandExecute(); break; case FLASH_COMMAND_STATUS: CommandStatus(); break; case FLASH_COMMAND_SET_ERASE_OFFSET: CommandSetEraseOffs(val); break; case FLASH_COMMAND_ERASE: CommandErase(); break; case FLASH_COMMAND_SET_WRITE_OFFSET: CommandSetWriteOffs(val); break; case FLASH_COMMAND_WRITE: CommandWrite(); break; case FLASH_COMMAND_READ: CommandRead(); break; default: Util::warn("Invalid flash command: {:02X}", cmd); } } else { Util::warn("Ignoring write of {:08X} to flash status register", val); } } FORCE_INLINE void Write8(u32 index, u8 val) { switch(state) { case FlashState::Idle: Util::panic("Invalid FlashState::Idle with Write8"); case FlashState::Status: Util::panic("Invalid FlashState::Status with Write8"); case FlashState::Erase: Util::panic("Invalid FlashState::Erase with Write8"); case FlashState::Write: writeBuf[index] = val; break; case FlashState::Read: Util::panic("Invalid FlashState::Read with Write8"); default: Util::warn("Invalid flash state on Write8: {:02X}", static_cast(state)); } } FORCE_INLINE u32 Read(u32 index) const { return status >> 32; } }; struct Mem { ~Mem() { free(sram); } Mem(); void Reset(); void LoadROM(const std::string&); [[nodiscard]] auto GetRDRAM() const -> u8* { return mmio.rdp.rdram; } u8 Read8(Registers&, u32); u16 Read16(Registers&, u32); u32 Read32(Registers&, u32); u64 Read64(Registers&, u32); void Write8(Registers&, u32, u32); void Write16(Registers&, u32, u32); void Write32(Registers&, u32, u32); void Write64(Registers&, u32, u64); MMIO mmio; FORCE_INLINE void DumpRDRAM() const { FILE *fp = fopen("rdram.dump", "wb"); u8 *temp = (u8*)calloc(RDRAM_SIZE, 1); memcpy(temp, mmio.rdp.rdram, RDRAM_SIZE); Util::SwapBuffer32(RDRAM_SIZE, temp); fwrite(temp, 1, RDRAM_SIZE, fp); free(temp); fclose(fp); } FORCE_INLINE void DumpIMEM() const { FILE *fp = fopen("imem.bin", "wb"); u8 *temp = (u8*)calloc(IMEM_SIZE, 1); memcpy(temp, mmio.rsp.imem, IMEM_SIZE); Util::SwapBuffer32(IMEM_SIZE, temp); fwrite(temp, 1, IMEM_SIZE, fp); free(temp); fclose(fp); } FORCE_INLINE void DumpDMEM() const { FILE *fp = fopen("dmem.dump", "wb"); u8 *temp = (u8*)calloc(DMEM_SIZE, 1); memcpy(temp, mmio.rsp.dmem, DMEM_SIZE); Util::SwapBuffer32(DMEM_SIZE, temp); fwrite(temp, 1, DMEM_SIZE, fp); free(temp); fclose(fp); } uintptr_t writePages[PAGE_COUNT]{}, readPages[PAGE_COUNT]{}; ROM rom; SaveType saveType = SAVE_NONE; Flash flash; private: friend struct SI; friend struct PI; friend struct AI; friend struct RSP; friend struct Core; u8* sram; u8 isviewer[ISVIEWER_SIZE]{}; FORCE_INLINE bool IsROMPAL() { static const char pal_codes[] = {'D', 'F', 'I', 'P', 'S', 'U', 'X', 'Y'}; return std::any_of(std::begin(pal_codes), std::end(pal_codes), [this](char a) { return rom.cart[0x3d] == a; }); } }; }