Lay down flash support (doesn't work properly yet)
This commit is contained in:
@@ -54,6 +54,7 @@ add_subdirectory(frontend/imgui)
|
|||||||
add_subdirectory(backend)
|
add_subdirectory(backend)
|
||||||
add_subdirectory(backend/core)
|
add_subdirectory(backend/core)
|
||||||
add_subdirectory(backend/core/interpreter)
|
add_subdirectory(backend/core/interpreter)
|
||||||
|
add_subdirectory(backend/core/mem)
|
||||||
add_subdirectory(backend/core/mmio)
|
add_subdirectory(backend/core/mmio)
|
||||||
add_subdirectory(backend/core/registers)
|
add_subdirectory(backend/core/registers)
|
||||||
add_subdirectory(backend/core/rsp)
|
add_subdirectory(backend/core/rsp)
|
||||||
@@ -75,4 +76,4 @@ file(REMOVE
|
|||||||
${PROJECT_BINARY_DIR}/resources/shader.vert)
|
${PROJECT_BINARY_DIR}/resources/shader.vert)
|
||||||
|
|
||||||
target_link_libraries(kaizen PUBLIC frontend frontend-imgui
|
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)
|
||||||
|
|||||||
@@ -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.InitDevices(cpu.mem.saveType);
|
||||||
cpu.mem.mmio.si.pif.LoadMempak(rom_);
|
cpu.mem.mmio.si.pif.LoadMempak(rom_);
|
||||||
cpu.mem.mmio.si.pif.LoadEeprom(cpu.mem.saveType, 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);
|
cpu.mem.mmio.si.pif.ExecutePIF(cpu.mem, cpu.regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
namespace n64 {
|
namespace n64 {
|
||||||
void GameDB::match(Mem& mem) {
|
void GameDB::match(Mem& mem) {
|
||||||
ROM& rom = mem.rom;
|
ROM& rom = mem.rom;
|
||||||
|
bool found = false;
|
||||||
std::for_each(std::execution::par, std::begin(gamedb), std::end(gamedb), [&](const auto& i) {
|
std::for_each(std::execution::par, std::begin(gamedb), std::end(gamedb), [&](const auto& i) {
|
||||||
bool matches_code = i.code == rom.code;
|
bool matches_code = i.code == rom.code;
|
||||||
bool matches_region = false;
|
bool matches_region = false;
|
||||||
@@ -17,6 +18,7 @@ void GameDB::match(Mem& mem) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (matches_code) {
|
if (matches_code) {
|
||||||
|
found = true;
|
||||||
if (matches_region) {
|
if (matches_region) {
|
||||||
mem.saveType = i.saveType;
|
mem.saveType = i.saveType;
|
||||||
mem.rom.gameNameDB = i.name;
|
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]);
|
Util::debug("Did not match any Game DB entries. Code: {} Region: {}", mem.rom.code, mem.rom.header.countryCode[0]);
|
||||||
|
|
||||||
mem.rom.gameNameDB = "";
|
mem.rom.gameNameDB = "";
|
||||||
mem.saveType = SAVE_NONE;
|
mem.saveType = SAVE_NONE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <core/registers/Registers.hpp>
|
|
||||||
#include <Mem.hpp>
|
#include <Mem.hpp>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|||||||
@@ -194,12 +194,22 @@ u32 Mem::Read32(n64::Registers ®s, u32 paddr) {
|
|||||||
return mmio.Read(paddr);
|
return mmio.Read(paddr);
|
||||||
case CART_REGION_1_2:
|
case CART_REGION_1_2:
|
||||||
return Util::ReadAccess<u32>(rom.cart, paddr & rom.mask);
|
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:
|
case PIF_ROM_REGION:
|
||||||
return Util::ReadAccess<u32>(si.pif.bootrom, paddr - PIF_ROM_REGION_START);
|
return Util::ReadAccess<u32>(si.pif.bootrom, paddr - PIF_ROM_REGION_START);
|
||||||
case PIF_RAM_REGION:
|
case PIF_RAM_REGION:
|
||||||
return be32toh(Util::ReadAccess<u32>(si.pif.ram, paddr - PIF_RAM_REGION_START));
|
return be32toh(Util::ReadAccess<u32>(si.pif.ram, paddr - PIF_RAM_REGION_START));
|
||||||
case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF:
|
case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF:
|
||||||
case 0x04900000 ... 0x0FFFFFFF: case 0x1FC00800 ... 0xFFFFFFFF: return 0;
|
case 0x04900000 ... 0x07FFFFFF: case 0x1FC00800 ... 0xFFFFFFFF: return 0;
|
||||||
default:
|
default:
|
||||||
Util::panic("Unimplemented 32-bit read at address {:08X} (PC = {:016X})", paddr, (u64) regs.pc);
|
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));
|
Util::WriteAccess<u32>(si.pif.ram, paddr, htobe32(val));
|
||||||
si.pif.ProcessCommands(*this);
|
si.pif.ProcessCommands(*this);
|
||||||
break;
|
break;
|
||||||
case SRAM_REGION:
|
case CART_REGION_2_2:
|
||||||
Util::panic("SRAM Write8!");
|
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 0x00800000 ... 0x03FFFFFF:
|
||||||
case 0x04200000 ... 0x042FFFFF:
|
case 0x04200000 ... 0x042FFFFF:
|
||||||
case 0x04900000 ... 0x07FFFFFF:
|
case 0x04900000 ... 0x07FFFFFF:
|
||||||
@@ -284,7 +312,7 @@ void Mem::Write8(Registers& regs, u32 paddr, u32 val) {
|
|||||||
case 0x80000000 ... 0xFFFFFFFF:
|
case 0x80000000 ... 0xFFFFFFFF:
|
||||||
break;
|
break;
|
||||||
default:
|
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);
|
(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));
|
Util::WriteAccess<u32>(si.pif.ram, paddr - PIF_RAM_REGION_START, htobe32(val));
|
||||||
si.pif.ProcessCommands(*this);
|
si.pif.ProcessCommands(*this);
|
||||||
break;
|
break;
|
||||||
case SRAM_REGION:
|
case CART_REGION_2_2:
|
||||||
Util::panic("SRAM Write16!");
|
Util::panic("Backup Write16!");
|
||||||
case 0x00800000 ... 0x03FFFFFF:
|
case 0x00800000 ... 0x03FFFFFF:
|
||||||
case 0x04200000 ... 0x042FFFFF:
|
case 0x04200000 ... 0x042FFFFF:
|
||||||
case 0x04900000 ... 0x07FFFFFF:
|
case 0x04900000 ... 0x07FFFFFF:
|
||||||
@@ -333,7 +361,7 @@ void Mem::Write16(Registers& regs, u32 paddr, u32 val) {
|
|||||||
case 0x80000000 ... 0xFFFFFFFF:
|
case 0x80000000 ... 0xFFFFFFFF:
|
||||||
break;
|
break;
|
||||||
default:
|
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);
|
(u64) regs.pc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -384,8 +412,20 @@ void Mem::Write32(Registers& regs, u32 paddr, u32 val) {
|
|||||||
case PIF_ROM_REGION:
|
case PIF_ROM_REGION:
|
||||||
case 0x1FC00800 ... 0x7FFFFFFF:
|
case 0x1FC00800 ... 0x7FFFFFFF:
|
||||||
case 0x80000000 ... 0xFFFFFFFF: break;
|
case 0x80000000 ... 0xFFFFFFFF: break;
|
||||||
case 0x08000000 ... 0x0FFFFFFF:
|
case CART_REGION_2_2:
|
||||||
Util::panic("SRAM Write32!");
|
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);
|
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 0x1FC00000 ... 0x1FC007BF:
|
||||||
case 0x1FC00800 ... 0x7FFFFFFF:
|
case 0x1FC00800 ... 0x7FFFFFFF:
|
||||||
case 0x80000000 ... 0xFFFFFFFF: break;
|
case 0x80000000 ... 0xFFFFFFFF: break;
|
||||||
case 0x08000000 ... 0x0FFFFFFF:
|
case CART_REGION_2_2:
|
||||||
Util::panic("SRAM Write64!");
|
Util::panic("Backup Write64!");
|
||||||
default:
|
default:
|
||||||
Util::panic("Unimplemented 64-bit write at address {:08X} with value {:0X} (PC = {:016X})", paddr, val,
|
Util::panic("Unimplemented 64-bit write at address {:08X} with value {:0X} (PC = {:016X})", paddr, val,
|
||||||
(u64) regs.pc);
|
(u64) regs.pc);
|
||||||
|
|||||||
@@ -38,6 +38,83 @@ struct ROM {
|
|||||||
bool pal;
|
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 {
|
struct Mem {
|
||||||
~Mem() {
|
~Mem() {
|
||||||
free(sram);
|
free(sram);
|
||||||
@@ -91,7 +168,8 @@ struct Mem {
|
|||||||
}
|
}
|
||||||
uintptr_t writePages[PAGE_COUNT]{}, readPages[PAGE_COUNT]{};
|
uintptr_t writePages[PAGE_COUNT]{}, readPages[PAGE_COUNT]{};
|
||||||
ROM rom;
|
ROM rom;
|
||||||
SaveType saveType;
|
SaveType saveType = SAVE_NONE;
|
||||||
|
Flash flash;
|
||||||
private:
|
private:
|
||||||
friend struct SI;
|
friend struct SI;
|
||||||
friend struct PI;
|
friend struct PI;
|
||||||
|
|||||||
4
src/backend/core/mem/CMakeLists.txt
Normal file
4
src/backend/core/mem/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
file(GLOB SOURCES *.cpp)
|
||||||
|
file(GLOB HEADERS *.hpp)
|
||||||
|
|
||||||
|
add_library(mem ${SOURCES} ${HEADERS})
|
||||||
84
src/backend/core/mem/Flash.cpp
Normal file
84
src/backend/core/mem/Flash.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user