Skip to content

Commit

Permalink
Added save type selection and validation (#68)
Browse files Browse the repository at this point in the history
  • Loading branch information
Mr-Wiseguy authored Oct 27, 2024
1 parent 9ee0e73 commit ef6e84c
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 5 deletions.
16 changes: 15 additions & 1 deletion librecomp/include/librecomp/game.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,22 @@
#include <ultramodern/ultramodern.hpp>

namespace recomp {
enum class SaveType {
None,
Eep4k,
Eep16k,
Sram,
Flashram,
AllowAll, // Allows all save types to work and reports eeprom size as 16kbit.
};

struct GameEntry {
uint64_t rom_hash;
std::string internal_name;
std::u8string game_id;
std::string mod_game_id;
std::span<const char> cache_data;
SaveType save_type = SaveType::None;
bool is_enabled;

gpr entrypoint_address;
Expand Down Expand Up @@ -73,7 +83,6 @@ namespace recomp {
* It must be called only once and it must be called before `ultramodern::preinit`.
*/
void start(
uint32_t rdram_size,
const Version& project_version,
ultramodern::renderer::WindowHandle window_handle,
const recomp::rsp::callbacks_t& rsp_callbacks,
Expand All @@ -86,6 +95,11 @@ namespace recomp {
const ultramodern::threads::callbacks_t& threads_callbacks
);

SaveType get_save_type();
bool eeprom_allowed();
bool sram_allowed();
bool flashram_allowed();

void start_game(const std::u8string& game_id);
std::u8string current_game_id();
}
Expand Down
31 changes: 30 additions & 1 deletion librecomp/src/eep.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "librecomp/recomp.h"
#include "librecomp/game.hpp"

#include "ultramodern/ultra64.h"

Expand All @@ -12,10 +13,23 @@ constexpr int eep16_size = 16384;
constexpr int eep16_block_count = eep16_size / eeprom_block_size;

extern "C" void osEepromProbe_recomp(uint8_t* rdram, recomp_context* ctx) {
ctx->r2 = 0x02; // EEP16K
switch (recomp::get_save_type()) {
case recomp::SaveType::AllowAll:
case recomp::SaveType::Eep16k:
ctx->r2 = 0x02; // EEPROM_TYPE_16K
case recomp::SaveType::Eep4k:
ctx->r2 = 0x01; // EEPROM_TYPE_4K
default:
ctx->r2 = 0x00;
}
}

extern "C" void osEepromWrite_recomp(uint8_t* rdram, recomp_context* ctx) {
if (!recomp::eeprom_allowed()) {
ultramodern::error_handling::message_box("Attempted to use EEPROM saving with other save type");
ULTRAMODERN_QUICK_EXIT();
}

uint8_t eep_address = ctx->r5;
gpr buffer = ctx->r6;
int32_t nbytes = eeprom_block_size;
Expand All @@ -29,6 +43,11 @@ extern "C" void osEepromWrite_recomp(uint8_t* rdram, recomp_context* ctx) {
}

extern "C" void osEepromLongWrite_recomp(uint8_t* rdram, recomp_context* ctx) {
if (!recomp::eeprom_allowed()) {
ultramodern::error_handling::message_box("Attempted to use EEPROM saving with other save type");
ULTRAMODERN_QUICK_EXIT();
}

uint8_t eep_address = ctx->r5;
gpr buffer = ctx->r6;
int32_t nbytes = ctx->r7;
Expand All @@ -42,6 +61,11 @@ extern "C" void osEepromLongWrite_recomp(uint8_t* rdram, recomp_context* ctx) {
}

extern "C" void osEepromRead_recomp(uint8_t* rdram, recomp_context* ctx) {
if (!recomp::eeprom_allowed()) {
ultramodern::error_handling::message_box("Attempted to use EEPROM saving with other save type");
ULTRAMODERN_QUICK_EXIT();
}

uint8_t eep_address = ctx->r5;
gpr buffer = ctx->r6;
int32_t nbytes = eeprom_block_size;
Expand All @@ -55,6 +79,11 @@ extern "C" void osEepromRead_recomp(uint8_t* rdram, recomp_context* ctx) {
}

extern "C" void osEepromLongRead_recomp(uint8_t* rdram, recomp_context* ctx) {
if (!recomp::eeprom_allowed()) {
ultramodern::error_handling::message_box("Attempted to use EEPROM saving with other save type");
ULTRAMODERN_QUICK_EXIT();
}

uint8_t eep_address = ctx->r5;
gpr buffer = ctx->r6;
int32_t nbytes = ctx->r7;
Expand Down
66 changes: 66 additions & 0 deletions librecomp/src/flash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <ultramodern/ultramodern.hpp>
#include "librecomp/recomp.h"
#include "librecomp/addresses.hpp"
#include "librecomp/game.hpp"

// TODO move this out into ultramodern code

Expand All @@ -22,16 +23,31 @@ void save_clear(uint32_t start, uint32_t size, char value);
std::array<char, page_size> write_buffer;

extern "C" void osFlashInit_recomp(uint8_t * rdram, recomp_context * ctx) {
if (!recomp::flashram_allowed()) {
ultramodern::error_handling::message_box("Attempted to use FlashRAM saving with other save type");
ULTRAMODERN_QUICK_EXIT();
}

ctx->r2 = recomp::flash_handle;
}

extern "C" void osFlashReadStatus_recomp(uint8_t * rdram, recomp_context * ctx) {
if (!recomp::flashram_allowed()) {
ultramodern::error_handling::message_box("Attempted to use FlashRAM saving with other save type");
ULTRAMODERN_QUICK_EXIT();
}

PTR(u8) flash_status = ctx->r4;

MEM_B(0, flash_status) = 0;
}

extern "C" void osFlashReadId_recomp(uint8_t * rdram, recomp_context * ctx) {
if (!recomp::flashram_allowed()) {
ultramodern::error_handling::message_box("Attempted to use FlashRAM saving with other save type");
ULTRAMODERN_QUICK_EXIT();
}

PTR(u32) flash_type = ctx->r4;
PTR(u32) flash_maker = ctx->r5;

Expand All @@ -41,23 +57,43 @@ extern "C" void osFlashReadId_recomp(uint8_t * rdram, recomp_context * ctx) {
}

extern "C" void osFlashClearStatus_recomp(uint8_t * rdram, recomp_context * ctx) {
if (!recomp::flashram_allowed()) {
ultramodern::error_handling::message_box("Attempted to use FlashRAM saving with other save type");
ULTRAMODERN_QUICK_EXIT();
}

// Nothing to do here.
}

extern "C" void osFlashAllErase_recomp(uint8_t * rdram, recomp_context * ctx) {
if (!recomp::flashram_allowed()) {
ultramodern::error_handling::message_box("Attempted to use FlashRAM saving with other save type");
ULTRAMODERN_QUICK_EXIT();
}

save_clear(0, ultramodern::save_size, 0xFF);

ctx->r2 = 0;
}

extern "C" void osFlashAllEraseThrough_recomp(uint8_t * rdram, recomp_context * ctx) {
if (!recomp::flashram_allowed()) {
ultramodern::error_handling::message_box("Attempted to use FlashRAM saving with other save type");
ULTRAMODERN_QUICK_EXIT();
}

save_clear(0, ultramodern::save_size, 0xFF);

ctx->r2 = 0;
}

// This function is named sector but really means page.
extern "C" void osFlashSectorErase_recomp(uint8_t * rdram, recomp_context * ctx) {
if (!recomp::flashram_allowed()) {
ultramodern::error_handling::message_box("Attempted to use FlashRAM saving with other save type");
ULTRAMODERN_QUICK_EXIT();
}

uint32_t page_num = (uint32_t)ctx->r4;

// Prevent out of bounds erase
Expand All @@ -73,6 +109,11 @@ extern "C" void osFlashSectorErase_recomp(uint8_t * rdram, recomp_context * ctx)

// Same naming issue as above.
extern "C" void osFlashSectorEraseThrough_recomp(uint8_t * rdram, recomp_context * ctx) {
if (!recomp::flashram_allowed()) {
ultramodern::error_handling::message_box("Attempted to use FlashRAM saving with other save type");
ULTRAMODERN_QUICK_EXIT();
}

uint32_t page_num = (uint32_t)ctx->r4;

// Prevent out of bounds erase
Expand All @@ -87,11 +128,21 @@ extern "C" void osFlashSectorEraseThrough_recomp(uint8_t * rdram, recomp_context
}

extern "C" void osFlashCheckEraseEnd_recomp(uint8_t * rdram, recomp_context * ctx) {
if (!recomp::flashram_allowed()) {
ultramodern::error_handling::message_box("Attempted to use FlashRAM saving with other save type");
ULTRAMODERN_QUICK_EXIT();
}

// All erases are blocking in this implementation, so this should always return OK.
ctx->r2 = 0; // FLASH_STATUS_ERASE_OK
}

extern "C" void osFlashWriteBuffer_recomp(uint8_t * rdram, recomp_context * ctx) {
if (!recomp::flashram_allowed()) {
ultramodern::error_handling::message_box("Attempted to use FlashRAM saving with other save type");
ULTRAMODERN_QUICK_EXIT();
}

OSIoMesg* mb = TO_PTR(OSIoMesg, ctx->r4);
int32_t pri = ctx->r5;
PTR(void) dramAddr = ctx->r6;
Expand All @@ -109,6 +160,11 @@ extern "C" void osFlashWriteBuffer_recomp(uint8_t * rdram, recomp_context * ctx)
}

extern "C" void osFlashWriteArray_recomp(uint8_t * rdram, recomp_context * ctx) {
if (!recomp::flashram_allowed()) {
ultramodern::error_handling::message_box("Attempted to use FlashRAM saving with other save type");
ULTRAMODERN_QUICK_EXIT();
}

uint32_t page_num = ctx->r4;

// Copy the write buffer into the save file
Expand All @@ -118,6 +174,11 @@ extern "C" void osFlashWriteArray_recomp(uint8_t * rdram, recomp_context * ctx)
}

extern "C" void osFlashReadArray_recomp(uint8_t * rdram, recomp_context * ctx) {
if (!recomp::flashram_allowed()) {
ultramodern::error_handling::message_box("Attempted to use FlashRAM saving with other save type");
ULTRAMODERN_QUICK_EXIT();
}

OSIoMesg* mb = TO_PTR(OSIoMesg, ctx->r4);
int32_t pri = ctx->r5;
uint32_t page_num = ctx->r6;
Expand All @@ -138,5 +199,10 @@ extern "C" void osFlashReadArray_recomp(uint8_t * rdram, recomp_context * ctx) {
}

extern "C" void osFlashChange_recomp(uint8_t * rdram, recomp_context * ctx) {
if (!recomp::flashram_allowed()) {
ultramodern::error_handling::message_box("Attempted to use FlashRAM saving with other save type");
ULTRAMODERN_QUICK_EXIT();
}

assert(false);
}
39 changes: 37 additions & 2 deletions librecomp/src/pi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ void recomp::do_rom_pio(uint8_t* rdram, gpr ram_address, uint32_t physical_addr)
}

struct {
std::array<char, 0x20000> save_buffer;
std::vector<char> save_buffer;
std::thread saving_thread;
moodycamel::LightweightSemaphore write_sempahore;
std::mutex save_buffer_mutex;
Expand Down Expand Up @@ -143,6 +143,8 @@ void saving_thread_func(RDRAM_ARG1) {
}

void save_write_ptr(const void* in, uint32_t offset, uint32_t count) {
assert(offset + count <= save_context.save_buffer.size());

{
std::lock_guard lock { save_context.save_buffer_mutex };
memcpy(&save_context.save_buffer[offset], in, count);
Expand All @@ -152,6 +154,8 @@ void save_write_ptr(const void* in, uint32_t offset, uint32_t count) {
}

void save_write(RDRAM_ARG PTR(void) rdram_address, uint32_t offset, uint32_t count) {
assert(offset + count <= save_context.save_buffer.size());

{
std::lock_guard lock { save_context.save_buffer_mutex };
for (gpr i = 0; i < count; i++) {
Expand All @@ -163,13 +167,17 @@ void save_write(RDRAM_ARG PTR(void) rdram_address, uint32_t offset, uint32_t cou
}

void save_read(RDRAM_ARG PTR(void) rdram_address, uint32_t offset, uint32_t count) {
assert(offset + count <= save_context.save_buffer.size());

std::lock_guard lock { save_context.save_buffer_mutex };
for (gpr i = 0; i < count; i++) {
MEM_B(i, rdram_address) = save_context.save_buffer[offset + i];
}
}

void save_clear(uint32_t start, uint32_t size, char value) {
assert(start + size < save_context.save_buffer.size());

{
std::lock_guard lock { save_context.save_buffer_mutex };
std::fill_n(save_context.save_buffer.begin() + start, size, value);
Expand All @@ -178,20 +186,39 @@ void save_clear(uint32_t start, uint32_t size, char value) {
save_context.write_sempahore.signal();
}

size_t get_save_size(recomp::SaveType save_type) {
switch (save_type) {
case recomp::SaveType::AllowAll:
case recomp::SaveType::Flashram:
return 0x20000;
case recomp::SaveType::Sram:
return 0x8000;
case recomp::SaveType::Eep16k:
return 0x800;
case recomp::SaveType::Eep4k:
return 0x200;
case recomp::SaveType::None:
return 0;
}
return 0;
}

void ultramodern::init_saving(RDRAM_ARG1) {
std::filesystem::path save_file_path = get_save_file_path();

// Ensure the save file directory exists.
std::filesystem::create_directories(save_file_path.parent_path());

save_context.save_buffer.resize(get_save_size(recomp::get_save_type()));

// Read the save file if it exists.
std::ifstream save_file = recomp::open_input_file_with_backup(save_file_path, std::ios_base::binary);
if (save_file.good()) {
save_file.read(save_context.save_buffer.data(), save_context.save_buffer.size());
}
else {
// Otherwise clear the save file to all zeroes.
save_context.save_buffer.fill(0);
std::fill(save_context.save_buffer.begin(), save_context.save_buffer.end(), 0);
}

save_context.saving_thread = std::thread{saving_thread_func, PASS_RDRAM};
Expand All @@ -214,6 +241,10 @@ void do_dma(RDRAM_ARG PTR(OSMesgQueue) mq, gpr rdram_address, uint32_t physical_
// Send a message to the mq to indicate that the transfer completed
osSendMesg(rdram, mq, 0, OS_MESG_NOBLOCK);
} else if (physical_addr >= recomp::sram_base) {
if (!recomp::sram_allowed()) {
ultramodern::error_handling::message_box("Attempted to use SRAM saving with other save type");
ULTRAMODERN_QUICK_EXIT();
}
// read sram
save_read(rdram, rdram_address, physical_addr - recomp::sram_base, size);

Expand All @@ -227,6 +258,10 @@ void do_dma(RDRAM_ARG PTR(OSMesgQueue) mq, gpr rdram_address, uint32_t physical_
// write cart rom
throw std::runtime_error("ROM DMA write unimplemented");
} else if (physical_addr >= recomp::sram_base) {
if (!recomp::sram_allowed()) {
ultramodern::error_handling::message_box("Attempted to use SRAM saving with other save type");
ULTRAMODERN_QUICK_EXIT();
}
// write sram
save_write(rdram, rdram_address, physical_addr - recomp::sram_base, size);

Expand Down
Loading

0 comments on commit ef6e84c

Please sign in to comment.