Skip to content

Commit ef6e84c

Browse files
authored
Added save type selection and validation (#68)
1 parent 9ee0e73 commit ef6e84c

File tree

5 files changed

+174
-5
lines changed

5 files changed

+174
-5
lines changed

librecomp/include/librecomp/game.hpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,22 @@
99
#include <ultramodern/ultramodern.hpp>
1010

1111
namespace recomp {
12+
enum class SaveType {
13+
None,
14+
Eep4k,
15+
Eep16k,
16+
Sram,
17+
Flashram,
18+
AllowAll, // Allows all save types to work and reports eeprom size as 16kbit.
19+
};
20+
1221
struct GameEntry {
1322
uint64_t rom_hash;
1423
std::string internal_name;
1524
std::u8string game_id;
1625
std::string mod_game_id;
1726
std::span<const char> cache_data;
27+
SaveType save_type = SaveType::None;
1828
bool is_enabled;
1929

2030
gpr entrypoint_address;
@@ -73,7 +83,6 @@ namespace recomp {
7383
* It must be called only once and it must be called before `ultramodern::preinit`.
7484
*/
7585
void start(
76-
uint32_t rdram_size,
7786
const Version& project_version,
7887
ultramodern::renderer::WindowHandle window_handle,
7988
const recomp::rsp::callbacks_t& rsp_callbacks,
@@ -86,6 +95,11 @@ namespace recomp {
8695
const ultramodern::threads::callbacks_t& threads_callbacks
8796
);
8897

98+
SaveType get_save_type();
99+
bool eeprom_allowed();
100+
bool sram_allowed();
101+
bool flashram_allowed();
102+
89103
void start_game(const std::u8string& game_id);
90104
std::u8string current_game_id();
91105
}

librecomp/src/eep.cpp

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "librecomp/recomp.h"
2+
#include "librecomp/game.hpp"
23

34
#include "ultramodern/ultra64.h"
45

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

1415
extern "C" void osEepromProbe_recomp(uint8_t* rdram, recomp_context* ctx) {
15-
ctx->r2 = 0x02; // EEP16K
16+
switch (recomp::get_save_type()) {
17+
case recomp::SaveType::AllowAll:
18+
case recomp::SaveType::Eep16k:
19+
ctx->r2 = 0x02; // EEPROM_TYPE_16K
20+
case recomp::SaveType::Eep4k:
21+
ctx->r2 = 0x01; // EEPROM_TYPE_4K
22+
default:
23+
ctx->r2 = 0x00;
24+
}
1625
}
1726

1827
extern "C" void osEepromWrite_recomp(uint8_t* rdram, recomp_context* ctx) {
28+
if (!recomp::eeprom_allowed()) {
29+
ultramodern::error_handling::message_box("Attempted to use EEPROM saving with other save type");
30+
ULTRAMODERN_QUICK_EXIT();
31+
}
32+
1933
uint8_t eep_address = ctx->r5;
2034
gpr buffer = ctx->r6;
2135
int32_t nbytes = eeprom_block_size;
@@ -29,6 +43,11 @@ extern "C" void osEepromWrite_recomp(uint8_t* rdram, recomp_context* ctx) {
2943
}
3044

3145
extern "C" void osEepromLongWrite_recomp(uint8_t* rdram, recomp_context* ctx) {
46+
if (!recomp::eeprom_allowed()) {
47+
ultramodern::error_handling::message_box("Attempted to use EEPROM saving with other save type");
48+
ULTRAMODERN_QUICK_EXIT();
49+
}
50+
3251
uint8_t eep_address = ctx->r5;
3352
gpr buffer = ctx->r6;
3453
int32_t nbytes = ctx->r7;
@@ -42,6 +61,11 @@ extern "C" void osEepromLongWrite_recomp(uint8_t* rdram, recomp_context* ctx) {
4261
}
4362

4463
extern "C" void osEepromRead_recomp(uint8_t* rdram, recomp_context* ctx) {
64+
if (!recomp::eeprom_allowed()) {
65+
ultramodern::error_handling::message_box("Attempted to use EEPROM saving with other save type");
66+
ULTRAMODERN_QUICK_EXIT();
67+
}
68+
4569
uint8_t eep_address = ctx->r5;
4670
gpr buffer = ctx->r6;
4771
int32_t nbytes = eeprom_block_size;
@@ -55,6 +79,11 @@ extern "C" void osEepromRead_recomp(uint8_t* rdram, recomp_context* ctx) {
5579
}
5680

5781
extern "C" void osEepromLongRead_recomp(uint8_t* rdram, recomp_context* ctx) {
82+
if (!recomp::eeprom_allowed()) {
83+
ultramodern::error_handling::message_box("Attempted to use EEPROM saving with other save type");
84+
ULTRAMODERN_QUICK_EXIT();
85+
}
86+
5887
uint8_t eep_address = ctx->r5;
5988
gpr buffer = ctx->r6;
6089
int32_t nbytes = ctx->r7;

librecomp/src/flash.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <ultramodern/ultramodern.hpp>
55
#include "librecomp/recomp.h"
66
#include "librecomp/addresses.hpp"
7+
#include "librecomp/game.hpp"
78

89
// TODO move this out into ultramodern code
910

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

2425
extern "C" void osFlashInit_recomp(uint8_t * rdram, recomp_context * ctx) {
26+
if (!recomp::flashram_allowed()) {
27+
ultramodern::error_handling::message_box("Attempted to use FlashRAM saving with other save type");
28+
ULTRAMODERN_QUICK_EXIT();
29+
}
30+
2531
ctx->r2 = recomp::flash_handle;
2632
}
2733

2834
extern "C" void osFlashReadStatus_recomp(uint8_t * rdram, recomp_context * ctx) {
35+
if (!recomp::flashram_allowed()) {
36+
ultramodern::error_handling::message_box("Attempted to use FlashRAM saving with other save type");
37+
ULTRAMODERN_QUICK_EXIT();
38+
}
39+
2940
PTR(u8) flash_status = ctx->r4;
3041

3142
MEM_B(0, flash_status) = 0;
3243
}
3344

3445
extern "C" void osFlashReadId_recomp(uint8_t * rdram, recomp_context * ctx) {
46+
if (!recomp::flashram_allowed()) {
47+
ultramodern::error_handling::message_box("Attempted to use FlashRAM saving with other save type");
48+
ULTRAMODERN_QUICK_EXIT();
49+
}
50+
3551
PTR(u32) flash_type = ctx->r4;
3652
PTR(u32) flash_maker = ctx->r5;
3753

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

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

65+
// Nothing to do here.
4566
}
4667

4768
extern "C" void osFlashAllErase_recomp(uint8_t * rdram, recomp_context * ctx) {
69+
if (!recomp::flashram_allowed()) {
70+
ultramodern::error_handling::message_box("Attempted to use FlashRAM saving with other save type");
71+
ULTRAMODERN_QUICK_EXIT();
72+
}
73+
4874
save_clear(0, ultramodern::save_size, 0xFF);
4975

5076
ctx->r2 = 0;
5177
}
5278

5379
extern "C" void osFlashAllEraseThrough_recomp(uint8_t * rdram, recomp_context * ctx) {
80+
if (!recomp::flashram_allowed()) {
81+
ultramodern::error_handling::message_box("Attempted to use FlashRAM saving with other save type");
82+
ULTRAMODERN_QUICK_EXIT();
83+
}
84+
5485
save_clear(0, ultramodern::save_size, 0xFF);
5586

5687
ctx->r2 = 0;
5788
}
5889

5990
// This function is named sector but really means page.
6091
extern "C" void osFlashSectorErase_recomp(uint8_t * rdram, recomp_context * ctx) {
92+
if (!recomp::flashram_allowed()) {
93+
ultramodern::error_handling::message_box("Attempted to use FlashRAM saving with other save type");
94+
ULTRAMODERN_QUICK_EXIT();
95+
}
96+
6197
uint32_t page_num = (uint32_t)ctx->r4;
6298

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

74110
// Same naming issue as above.
75111
extern "C" void osFlashSectorEraseThrough_recomp(uint8_t * rdram, recomp_context * ctx) {
112+
if (!recomp::flashram_allowed()) {
113+
ultramodern::error_handling::message_box("Attempted to use FlashRAM saving with other save type");
114+
ULTRAMODERN_QUICK_EXIT();
115+
}
116+
76117
uint32_t page_num = (uint32_t)ctx->r4;
77118

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

89130
extern "C" void osFlashCheckEraseEnd_recomp(uint8_t * rdram, recomp_context * ctx) {
131+
if (!recomp::flashram_allowed()) {
132+
ultramodern::error_handling::message_box("Attempted to use FlashRAM saving with other save type");
133+
ULTRAMODERN_QUICK_EXIT();
134+
}
135+
90136
// All erases are blocking in this implementation, so this should always return OK.
91137
ctx->r2 = 0; // FLASH_STATUS_ERASE_OK
92138
}
93139

94140
extern "C" void osFlashWriteBuffer_recomp(uint8_t * rdram, recomp_context * ctx) {
141+
if (!recomp::flashram_allowed()) {
142+
ultramodern::error_handling::message_box("Attempted to use FlashRAM saving with other save type");
143+
ULTRAMODERN_QUICK_EXIT();
144+
}
145+
95146
OSIoMesg* mb = TO_PTR(OSIoMesg, ctx->r4);
96147
int32_t pri = ctx->r5;
97148
PTR(void) dramAddr = ctx->r6;
@@ -109,6 +160,11 @@ extern "C" void osFlashWriteBuffer_recomp(uint8_t * rdram, recomp_context * ctx)
109160
}
110161

111162
extern "C" void osFlashWriteArray_recomp(uint8_t * rdram, recomp_context * ctx) {
163+
if (!recomp::flashram_allowed()) {
164+
ultramodern::error_handling::message_box("Attempted to use FlashRAM saving with other save type");
165+
ULTRAMODERN_QUICK_EXIT();
166+
}
167+
112168
uint32_t page_num = ctx->r4;
113169

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

120176
extern "C" void osFlashReadArray_recomp(uint8_t * rdram, recomp_context * ctx) {
177+
if (!recomp::flashram_allowed()) {
178+
ultramodern::error_handling::message_box("Attempted to use FlashRAM saving with other save type");
179+
ULTRAMODERN_QUICK_EXIT();
180+
}
181+
121182
OSIoMesg* mb = TO_PTR(OSIoMesg, ctx->r4);
122183
int32_t pri = ctx->r5;
123184
uint32_t page_num = ctx->r6;
@@ -138,5 +199,10 @@ extern "C" void osFlashReadArray_recomp(uint8_t * rdram, recomp_context * ctx) {
138199
}
139200

140201
extern "C" void osFlashChange_recomp(uint8_t * rdram, recomp_context * ctx) {
202+
if (!recomp::flashram_allowed()) {
203+
ultramodern::error_handling::message_box("Attempted to use FlashRAM saving with other save type");
204+
ULTRAMODERN_QUICK_EXIT();
205+
}
206+
141207
assert(false);
142208
}

librecomp/src/pi.cpp

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ void recomp::do_rom_pio(uint8_t* rdram, gpr ram_address, uint32_t physical_addr)
8282
}
8383

8484
struct {
85-
std::array<char, 0x20000> save_buffer;
85+
std::vector<char> save_buffer;
8686
std::thread saving_thread;
8787
moodycamel::LightweightSemaphore write_sempahore;
8888
std::mutex save_buffer_mutex;
@@ -143,6 +143,8 @@ void saving_thread_func(RDRAM_ARG1) {
143143
}
144144

145145
void save_write_ptr(const void* in, uint32_t offset, uint32_t count) {
146+
assert(offset + count <= save_context.save_buffer.size());
147+
146148
{
147149
std::lock_guard lock { save_context.save_buffer_mutex };
148150
memcpy(&save_context.save_buffer[offset], in, count);
@@ -152,6 +154,8 @@ void save_write_ptr(const void* in, uint32_t offset, uint32_t count) {
152154
}
153155

154156
void save_write(RDRAM_ARG PTR(void) rdram_address, uint32_t offset, uint32_t count) {
157+
assert(offset + count <= save_context.save_buffer.size());
158+
155159
{
156160
std::lock_guard lock { save_context.save_buffer_mutex };
157161
for (gpr i = 0; i < count; i++) {
@@ -163,13 +167,17 @@ void save_write(RDRAM_ARG PTR(void) rdram_address, uint32_t offset, uint32_t cou
163167
}
164168

165169
void save_read(RDRAM_ARG PTR(void) rdram_address, uint32_t offset, uint32_t count) {
170+
assert(offset + count <= save_context.save_buffer.size());
171+
166172
std::lock_guard lock { save_context.save_buffer_mutex };
167173
for (gpr i = 0; i < count; i++) {
168174
MEM_B(i, rdram_address) = save_context.save_buffer[offset + i];
169175
}
170176
}
171177

172178
void save_clear(uint32_t start, uint32_t size, char value) {
179+
assert(start + size < save_context.save_buffer.size());
180+
173181
{
174182
std::lock_guard lock { save_context.save_buffer_mutex };
175183
std::fill_n(save_context.save_buffer.begin() + start, size, value);
@@ -178,20 +186,39 @@ void save_clear(uint32_t start, uint32_t size, char value) {
178186
save_context.write_sempahore.signal();
179187
}
180188

189+
size_t get_save_size(recomp::SaveType save_type) {
190+
switch (save_type) {
191+
case recomp::SaveType::AllowAll:
192+
case recomp::SaveType::Flashram:
193+
return 0x20000;
194+
case recomp::SaveType::Sram:
195+
return 0x8000;
196+
case recomp::SaveType::Eep16k:
197+
return 0x800;
198+
case recomp::SaveType::Eep4k:
199+
return 0x200;
200+
case recomp::SaveType::None:
201+
return 0;
202+
}
203+
return 0;
204+
}
205+
181206
void ultramodern::init_saving(RDRAM_ARG1) {
182207
std::filesystem::path save_file_path = get_save_file_path();
183208

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

212+
save_context.save_buffer.resize(get_save_size(recomp::get_save_type()));
213+
187214
// Read the save file if it exists.
188215
std::ifstream save_file = recomp::open_input_file_with_backup(save_file_path, std::ios_base::binary);
189216
if (save_file.good()) {
190217
save_file.read(save_context.save_buffer.data(), save_context.save_buffer.size());
191218
}
192219
else {
193220
// Otherwise clear the save file to all zeroes.
194-
save_context.save_buffer.fill(0);
221+
std::fill(save_context.save_buffer.begin(), save_context.save_buffer.end(), 0);
195222
}
196223

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

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

0 commit comments

Comments
 (0)