Lay down flash support (doesn't work properly yet)

This commit is contained in:
SimoneN64
2023-06-09 16:06:03 +02:00
parent c132900c57
commit 7e9cfa1f53
8 changed files with 228 additions and 17 deletions

View File

@@ -54,6 +54,7 @@ add_subdirectory(frontend/imgui)
add_subdirectory(backend)
add_subdirectory(backend/core)
add_subdirectory(backend/core/interpreter)
add_subdirectory(backend/core/mem)
add_subdirectory(backend/core/mmio)
add_subdirectory(backend/core/registers)
add_subdirectory(backend/core/rsp)
@@ -75,4 +76,4 @@ file(REMOVE
${PROJECT_BINARY_DIR}/resources/shader.vert)
target_link_libraries(kaizen PUBLIC frontend frontend-imgui
discord-rpc imgui nfd parallel-rdp backend fmt::fmt nlohmann_json::nlohmann_json core registers interpreter mmio rsp SDL2::SDL2main SDL2::SDL2)
discord-rpc imgui nfd parallel-rdp backend fmt::fmt nlohmann_json::nlohmann_json core registers interpreter mem mmio rsp SDL2::SDL2main SDL2::SDL2)

View File

@@ -27,6 +27,7 @@ void Core::LoadROM(const std::string& rom_) {
cpu.mem.mmio.si.pif.InitDevices(cpu.mem.saveType);
cpu.mem.mmio.si.pif.LoadMempak(rom_);
cpu.mem.mmio.si.pif.LoadEeprom(cpu.mem.saveType, rom_);
cpu.mem.flash.Load(cpu.mem.saveType, rom_);
cpu.mem.mmio.si.pif.ExecutePIF(cpu.mem, cpu.regs);
}

View File

@@ -6,6 +6,7 @@
namespace n64 {
void GameDB::match(Mem& mem) {
ROM& rom = mem.rom;
bool found = false;
std::for_each(std::execution::par, std::begin(gamedb), std::end(gamedb), [&](const auto& i) {
bool matches_code = i.code == rom.code;
bool matches_region = false;
@@ -17,6 +18,7 @@ void GameDB::match(Mem& mem) {
}
if (matches_code) {
found = true;
if (matches_region) {
mem.saveType = i.saveType;
mem.rom.gameNameDB = i.name;
@@ -31,9 +33,11 @@ void GameDB::match(Mem& mem) {
}
});
if(!found) {
Util::debug("Did not match any Game DB entries. Code: {} Region: {}", mem.rom.code, mem.rom.header.countryCode[0]);
mem.rom.gameNameDB = "";
mem.saveType = SAVE_NONE;
}
}
}

View File

@@ -1,5 +1,4 @@
#pragma once
#include <core/registers/Registers.hpp>
#include <Mem.hpp>
#include <vector>

View File

@@ -194,12 +194,22 @@ u32 Mem::Read32(n64::Registers &regs, u32 paddr) {
return mmio.Read(paddr);
case CART_REGION_1_2:
return Util::ReadAccess<u32>(rom.cart, paddr & rom.mask);
case CART_REGION_2_2:
if(saveType == SAVE_NONE) {
return 0;
} else if (saveType == SAVE_SRAM_256k) {
return 0xffff'ffff;
} else if (saveType == SAVE_FLASH_1m) {
return flash.Read(paddr - CART_REGION_START_2_2);
} else {
Util::panic("Cartridge backup Read32 with unknown save type!");;
}
case PIF_ROM_REGION:
return Util::ReadAccess<u32>(si.pif.bootrom, paddr - PIF_ROM_REGION_START);
case PIF_RAM_REGION:
return be32toh(Util::ReadAccess<u32>(si.pif.ram, paddr - PIF_RAM_REGION_START));
case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF:
case 0x04900000 ... 0x0FFFFFFF: case 0x1FC00800 ... 0xFFFFFFFF: return 0;
case 0x04900000 ... 0x07FFFFFF: case 0x1FC00800 ... 0xFFFFFFFF: return 0;
default:
Util::panic("Unimplemented 32-bit read at address {:08X} (PC = {:016X})", paddr, (u64) regs.pc);
}
@@ -274,8 +284,26 @@ void Mem::Write8(Registers& regs, u32 paddr, u32 val) {
Util::WriteAccess<u32>(si.pif.ram, paddr, htobe32(val));
si.pif.ProcessCommands(*this);
break;
case SRAM_REGION:
Util::panic("SRAM Write8!");
case CART_REGION_2_2:
if(flash.saveData) {
switch (saveType) {
case SAVE_NONE:
Util::panic("Accessing cartridge backup with save type SAVE_NONE");
break;
case SAVE_EEPROM_4k:
case SAVE_EEPROM_16k:
Util::panic("Accessing cartridge backup with save type SAVE_EEPROM");
break;
case SAVE_FLASH_1m:
flash.Write8(paddr - CART_REGION_START_2_2, val);
break;
case SAVE_SRAM_256k:
flash.saveData[paddr - CART_REGION_START_2_2] = val;
flash.saveDataDirty = true;
break;
}
}
break;
case 0x00800000 ... 0x03FFFFFF:
case 0x04200000 ... 0x042FFFFF:
case 0x04900000 ... 0x07FFFFFF:
@@ -284,7 +312,7 @@ void Mem::Write8(Registers& regs, u32 paddr, u32 val) {
case 0x80000000 ... 0xFFFFFFFF:
break;
default:
Util::panic("Unimplemented 8-bit write at address {:08X} with value {:0X} (PC = {:016X})", paddr, val,
Util::panic("Unimplemented 8-bit write at address {:08X} with value {:02X} (PC = {:016X})", paddr, val,
(u64) regs.pc);
}
}
@@ -323,8 +351,8 @@ void Mem::Write16(Registers& regs, u32 paddr, u32 val) {
Util::WriteAccess<u32>(si.pif.ram, paddr - PIF_RAM_REGION_START, htobe32(val));
si.pif.ProcessCommands(*this);
break;
case SRAM_REGION:
Util::panic("SRAM Write16!");
case CART_REGION_2_2:
Util::panic("Backup Write16!");
case 0x00800000 ... 0x03FFFFFF:
case 0x04200000 ... 0x042FFFFF:
case 0x04900000 ... 0x07FFFFFF:
@@ -333,7 +361,7 @@ void Mem::Write16(Registers& regs, u32 paddr, u32 val) {
case 0x80000000 ... 0xFFFFFFFF:
break;
default:
Util::panic("Unimplemented 16-bit write at address {:08X} with value {:0X} (PC = {:016X})", paddr, val,
Util::panic("Unimplemented 16-bit write at address {:08X} with value {:04X} (PC = {:016X})", paddr, val,
(u64) regs.pc);
}
}
@@ -384,8 +412,20 @@ void Mem::Write32(Registers& regs, u32 paddr, u32 val) {
case PIF_ROM_REGION:
case 0x1FC00800 ... 0x7FFFFFFF:
case 0x80000000 ... 0xFFFFFFFF: break;
case 0x08000000 ... 0x0FFFFFFF:
Util::panic("SRAM Write32!");
case CART_REGION_2_2:
if(flash.saveData) {
if (saveType == SAVE_FLASH_1m) {
flash.Write32(paddr - CART_REGION_START_2_2, val);
} else if (saveType == SAVE_SRAM_256k) {
break;
} else {
Util::panic("Invalid cartridge backup Write32 with save type {} (addr {:08X})", static_cast<int>(saveType),
paddr);
}
} else {
Util::panic("Invalid write to cartridge backup if save data is not initialized!");
}
break;
default: Util::panic("Unimplemented 32-bit write at address {:08X} with value {:0X} (PC = {:016X})", paddr, val, (u64)regs.pc);
}
}
@@ -426,8 +466,8 @@ void Mem::Write64(Registers& regs, u32 paddr, u64 val) {
case 0x1FC00000 ... 0x1FC007BF:
case 0x1FC00800 ... 0x7FFFFFFF:
case 0x80000000 ... 0xFFFFFFFF: break;
case 0x08000000 ... 0x0FFFFFFF:
Util::panic("SRAM Write64!");
case CART_REGION_2_2:
Util::panic("Backup Write64!");
default:
Util::panic("Unimplemented 64-bit write at address {:08X} with value {:0X} (PC = {:016X})", paddr, val,
(u64) regs.pc);

View File

@@ -38,6 +38,83 @@ struct ROM {
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<u8>(state));
}
}
FORCE_INLINE u32 Read(u32 index) const {
return status >> 32;
}
};
struct Mem {
~Mem() {
free(sram);
@@ -91,7 +168,8 @@ struct Mem {
}
uintptr_t writePages[PAGE_COUNT]{}, readPages[PAGE_COUNT]{};
ROM rom;
SaveType saveType;
SaveType saveType = SAVE_NONE;
Flash flash;
private:
friend struct SI;
friend struct PI;

View File

@@ -0,0 +1,4 @@
file(GLOB SOURCES *.cpp)
file(GLOB HEADERS *.hpp)
add_library(mem ${SOURCES} ${HEADERS})

View File

@@ -0,0 +1,84 @@
#include <Mem.hpp>
namespace n64 {
void Flash::Load(SaveType saveType, fs::path path) {
if(saveType == SAVE_FLASH_1m) {
if(saveData) {
memset(saveData, 0xff, 1_mb);
} else {
saveData = (u8 *) calloc(1_mb, 1);
}
saveDataPath = path.replace_extension(".flash").string();
FILE *f = fopen(saveDataPath.c_str(), "rb");
if (!f) {
f = fopen(saveDataPath.c_str(), "wb");
fwrite(saveData, 1, 1_mb, f);
fclose(f);
f = fopen(saveDataPath.c_str(), "rb");
}
fseek(f, 0, SEEK_END);
size_t actualSize = ftell(f);
fseek(f, 0, SEEK_SET);
if (actualSize != 1_mb) {
Util::panic("Corrupt flash!");
}
fread(saveData, 1, 1_mb, f);
fclose(f);
}
}
void Flash::CommandExecute() {
Util::debug("Flash::CommandExecute");
switch (state) {
case FlashState::Idle:
break;
case FlashState::Erase:
for (int i = 0; i < 128; i++) {
saveData[eraseOffs + i] = 0xFF;
}
saveDataDirty = true;
break;
case FlashState::Write:
for (int i = 0; i < 128; i++) {
saveData[writeOffs + i] = writeBuf[i];
}
saveDataDirty = true;
break;
case FlashState::Read:
Util::panic("Execute command when flash in read state");
break;
case FlashState::Status:
break;
}
}
void Flash::CommandStatus() {
state = FlashState::Status;
status = 0x1111800100C20000;
}
void Flash::CommandSetEraseOffs(u32 val) {
eraseOffs = (val & 0xffff) << 7;
}
void Flash::CommandErase() {
state = FlashState::Erase;
status = 0x11118004F0000000;
}
void Flash::CommandSetWriteOffs(u32 val) {
writeOffs = (val & 0xffff) << 7;
}
void Flash::CommandWrite() {
state = FlashState::Write;
status = 0x1111800400C20000LL;
}
void Flash::CommandRead() {
state = FlashState::Read;
status = 0x11118004F0000000;
}
}