Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added save type selection and validation #68

Merged
merged 2 commits into from
Oct 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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