[SC64][SW] Implement FlashRAM timings emulation and add a fake variant of FlashRAM

This commit is contained in:
Mateusz Faderewski 2025-03-07 20:51:56 +01:00
parent 8393963650
commit f546e5d17d
11 changed files with 67 additions and 12 deletions

@ -133,9 +133,10 @@ type: *enum* | default: `0`
- `4` - FlashRAM 1 Mib save is enabled
- `5` - SRAM 768 kib save is enabled
- `6` - SRAM 1 Mib save is enabled
- `7` - FakeFlashRAM 1 Mib save is enabled (write/erase timings are not emulated and erase before write is not required)
Use this setting for selecting save type that will be emulated. Only one save type can be enabled.
Any successful write to this config will disable automatic save writeback to USB or SD card when previously enabled.
Any successful write to this config will disable automatic save writeback to the USB or SD card if previously enabled.
---

@ -104,7 +104,8 @@ typedef enum {
SAVE_TYPE_SRAM = 3,
SAVE_TYPE_FLASHRAM = 4,
SAVE_TYPE_SRAM_BANKED = 5,
SAVE_TYPE_SRAM_1M = 6
SAVE_TYPE_SRAM_1M = 6,
SAVE_TYPE_FLASHRAM_FAKE = 7,
} sc64_save_type_t;
typedef enum {

@ -278,6 +278,9 @@ static bool cfg_set_save_type (save_type_t save_type) {
case SAVE_TYPE_SRAM_1M:
cfg_change_scr_bits(CFG_SCR_SRAM_ENABLED, true);
break;
case SAVE_TYPE_FLASHRAM_FAKE:
cfg_change_scr_bits(CFG_SCR_FLASHRAM_ENABLED, true);
break;
default:
save_type = SAVE_TYPE_NONE;
break;

@ -14,6 +14,7 @@ typedef enum {
SAVE_TYPE_FLASHRAM = 4,
SAVE_TYPE_SRAM_BANKED = 5,
SAVE_TYPE_SRAM_1M = 6,
SAVE_TYPE_FLASHRAM_FAKE = 7,
__SAVE_TYPE_COUNT
} save_type_t;

@ -1,12 +1,18 @@
#include <stdint.h>
#include "cfg.h"
#include "fpga.h"
#include "hw.h"
#include "timer.h"
#define FLASHRAM_SIZE (128 * 1024)
#define FLASHRAM_SECTOR_SIZE (16 * 1024)
#define FLASHRAM_PAGE_SIZE (128)
#define FLASHRAM_ADDRESS (0x03FE0000UL)
#define FLASHRAM_BUFFER_ADDRESS (0x05002C00UL)
#define FLASHRAM_SIZE (128 * 1024)
#define FLASHRAM_SECTOR_SIZE (16 * 1024)
#define FLASHRAM_PAGE_SIZE (128)
#define FLASHRAM_ADDRESS (0x03FE0000UL)
#define FLASHRAM_BUFFER_ADDRESS (0x05002C00UL)
#define FLASHRAM_WRITE_TIMING_MS (3)
#define FLASHRAM_ERASE_TIMING_MS (200)
typedef enum {
@ -16,6 +22,13 @@ typedef enum {
OP_WRITE_PAGE
} flashram_op_t;
struct process {
bool pending;
};
static struct process p;
static flashram_op_t flashram_operation_type (uint32_t scr) {
if (!(scr & FLASHRAM_SCR_PENDING)) {
@ -38,6 +51,7 @@ void flashram_init (void) {
if (fpga_reg_get(REG_FLASHRAM_SCR) & FLASHRAM_SCR_PENDING) {
fpga_reg_set(REG_FLASHRAM_SCR, FLASHRAM_SCR_DONE);
}
p.pending = false;
}
@ -53,8 +67,15 @@ void flashram_process (void) {
uint8_t write_buffer[FLASHRAM_PAGE_SIZE];
uint32_t page = ((scr & FLASHRAM_SCR_PAGE_MASK) >> FLASHRAM_SCR_PAGE_BIT);
const bool full_emulation = (cfg_get_save_type() != SAVE_TYPE_FLASHRAM_FAKE);
if (op == OP_WRITE_PAGE) {
if (p.pending) {
if (timer_countdown_elapsed(TIMER_ID_FLASHRAM)) {
p.pending = false;
} else {
return;
}
} else if (op == OP_WRITE_PAGE) {
uint8_t page_buffer[FLASHRAM_PAGE_SIZE];
uint32_t address = (FLASHRAM_ADDRESS + (page * FLASHRAM_PAGE_SIZE));
@ -63,11 +84,24 @@ void flashram_process (void) {
fpga_mem_read(address, FLASHRAM_PAGE_SIZE, write_buffer);
for (int i = 0; i < FLASHRAM_PAGE_SIZE; i++) {
write_buffer[i] &= page_buffer[i];
if (full_emulation) {
write_buffer[i] &= page_buffer[i];
} else {
write_buffer[i] = page_buffer[i];
}
}
fpga_mem_write(address, FLASHRAM_PAGE_SIZE, write_buffer);
} else if ((op == OP_ERASE_SECTOR) || (op == OP_ERASE_ALL)) {
if (full_emulation) {
hw_delay_ms(FLASHRAM_WRITE_TIMING_MS);
}
} else if ((op == OP_ERASE_SECTOR) || (op == OP_ERASE_ALL)) {
if (full_emulation) {
p.pending = true;
timer_countdown_start(TIMER_ID_FLASHRAM, FLASHRAM_ERASE_TIMING_MS);
}
for (int i = 0; i < FLASHRAM_PAGE_SIZE; i++) {
write_buffer[i] = 0xFF;
}
@ -80,6 +114,10 @@ void flashram_process (void) {
for (uint32_t offset = 0; offset < erase_size; offset += FLASHRAM_PAGE_SIZE) {
fpga_mem_write(address + offset, FLASHRAM_PAGE_SIZE, write_buffer);
}
if (full_emulation) {
return;
}
}
fpga_reg_set(REG_FLASHRAM_SCR, FLASHRAM_SCR_DONE);

@ -176,13 +176,11 @@ static bool sd_acmd (uint8_t acmd, uint32_t arg, rsp_type_t rsp_type, void *rsp)
static void sd_dat_start_write (uint32_t count) {
uint32_t dat = (((count - 1) << SD_DAT_BLOCKS_BIT) | SD_DAT_START_WRITE | SD_DAT_FIFO_FLUSH);
fpga_reg_set(REG_SD_DAT, dat);
}
static void sd_dat_start_read (uint32_t count) {
uint32_t dat = (((count - 1) << SD_DAT_BLOCKS_BIT) | SD_DAT_START_READ | SD_DAT_FIFO_FLUSH);
fpga_reg_set(REG_SD_DAT, dat);
}
static dat_status_t sd_dat_status (void) {

@ -13,6 +13,7 @@ typedef enum {
TIMER_ID_SD,
TIMER_ID_USB,
TIMER_ID_WRITEBACK,
TIMER_ID_FLASHRAM,
__TIMER_ID_COUNT
} timer_id_t;

@ -62,6 +62,10 @@ static save_type_t writeback_get_address_length (uint32_t *address, uint32_t *le
*address = SRAM_FLASHRAM_ADDRESS;
*length = SRAM_1M_LENGTH;
break;
case SAVE_TYPE_FLASHRAM_FAKE:
*address = SRAM_FLASHRAM_ADDRESS;
*length = FLASHRAM_LENGTH;
break;
default:
*address = 0;
*length = 0;

@ -330,6 +330,7 @@ enum SaveType {
SramBanked,
Sram1m,
Flashram,
FlashramFake,
}
impl From<n64::SaveType> for SaveType {
@ -356,6 +357,7 @@ impl From<SaveType> for sc64::SaveType {
SaveType::SramBanked => Self::SramBanked,
SaveType::Sram1m => Self::Sram1m,
SaveType::Flashram => Self::Flashram,
SaveType::FlashramFake => Self::FlashramFake,
}
}
}

@ -445,6 +445,7 @@ impl SC64 {
SaveType::Flashram => (SAVE_ADDRESS, FLASHRAM_LENGTH),
SaveType::SramBanked => (SAVE_ADDRESS, SRAM_BANKED_LENGTH),
SaveType::Sram1m => (SAVE_ADDRESS, SRAM_1M_LENGTH),
SaveType::FlashramFake => (SAVE_ADDRESS, FLASHRAM_LENGTH),
};
if length != save_length {
@ -469,6 +470,7 @@ impl SC64 {
SaveType::Flashram => (SAVE_ADDRESS, FLASHRAM_LENGTH),
SaveType::SramBanked => (SAVE_ADDRESS, SRAM_BANKED_LENGTH),
SaveType::Sram1m => (SAVE_ADDRESS, SRAM_1M_LENGTH),
SaveType::FlashramFake => (SAVE_ADDRESS, FLASHRAM_LENGTH),
};
self.memory_read_chunked(writer, address, save_length)

@ -288,6 +288,7 @@ pub enum SaveType {
Flashram,
SramBanked,
Sram1m,
FlashramFake,
}
impl Display for SaveType {
@ -300,6 +301,7 @@ impl Display for SaveType {
Self::SramBanked => "SRAM 768k",
Self::Flashram => "FlashRAM 1M",
Self::Sram1m => "SRAM 1M",
Self::FlashramFake => "FakeFlashRAM 1M"
})
}
}
@ -315,6 +317,7 @@ impl TryFrom<u32> for SaveType {
4 => Self::Flashram,
5 => Self::SramBanked,
6 => Self::Sram1m,
7 => Self::FlashramFake,
_ => return Err(Error::new("Unknown save type code")),
})
}
@ -330,6 +333,7 @@ impl From<SaveType> for u32 {
SaveType::Flashram => 4,
SaveType::SramBanked => 5,
SaveType::Sram1m => 6,
SaveType::FlashramFake => 7,
}
}
}