mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2025-01-14 13:39:14 +01:00
c4f6a0d555
And other bug fixes related to DMA write mask
171 lines
4.4 KiB
C
171 lines
4.4 KiB
C
#include "cfg.h"
|
|
#include "fpga.h"
|
|
#include "sd.h"
|
|
#include "timer.h"
|
|
#include "usb.h"
|
|
#include "writeback.h"
|
|
|
|
|
|
#define SAVE_MAX_SECTOR_COUNT (256)
|
|
#define EEPROM_ADDRESS (0x05002000)
|
|
#define SRAM_FLASHRAM_ADDRESS (0x03FE0000)
|
|
#define EEPROM_4K_LENGTH (512)
|
|
#define EEPROM_16K_LENGTH (2048)
|
|
#define SRAM_LENGTH (32 * 1024)
|
|
#define FLASHRAM_LENGTH (128 * 1024)
|
|
#define SRAM_BANKED_LENGTH (3 * 32 * 1024)
|
|
#define SRAM_1M_LENGTH (128 * 1024)
|
|
#define WRITEBACK_DELAY_TICKS (100)
|
|
|
|
|
|
struct process {
|
|
bool enabled;
|
|
bool pending;
|
|
writeback_mode_t mode;
|
|
uint16_t last_save_count;
|
|
uint32_t sectors[SAVE_MAX_SECTOR_COUNT];
|
|
};
|
|
|
|
|
|
static struct process p;
|
|
|
|
|
|
static save_type_t writeback_get_address_length (uint32_t *address, uint32_t *length) {
|
|
save_type_t save = cfg_get_save_type();
|
|
|
|
switch (save) {
|
|
case SAVE_TYPE_EEPROM_4K:
|
|
*address = EEPROM_ADDRESS;
|
|
*length = EEPROM_4K_LENGTH;
|
|
break;
|
|
case SAVE_TYPE_EEPROM_16K:
|
|
*address = EEPROM_ADDRESS;
|
|
*length = EEPROM_16K_LENGTH;
|
|
break;
|
|
case SAVE_TYPE_SRAM:
|
|
*address = SRAM_FLASHRAM_ADDRESS;
|
|
*length = SRAM_LENGTH;
|
|
break;
|
|
case SAVE_TYPE_FLASHRAM:
|
|
*address = SRAM_FLASHRAM_ADDRESS;
|
|
*length = FLASHRAM_LENGTH;
|
|
break;
|
|
case SAVE_TYPE_SRAM_BANKED:
|
|
*address = SRAM_FLASHRAM_ADDRESS;
|
|
*length = SRAM_BANKED_LENGTH;
|
|
break;
|
|
case SAVE_TYPE_SRAM_1M:
|
|
*address = SRAM_FLASHRAM_ADDRESS;
|
|
*length = SRAM_1M_LENGTH;
|
|
break;
|
|
default:
|
|
*address = 0;
|
|
*length = 0;
|
|
break;
|
|
}
|
|
|
|
return save;
|
|
}
|
|
|
|
static void writeback_save_to_sd (void) {
|
|
save_type_t save;
|
|
uint32_t address;
|
|
uint32_t length;
|
|
|
|
save = writeback_get_address_length(&address, &length);
|
|
if (save == SAVE_TYPE_NONE) {
|
|
writeback_disable();
|
|
return;
|
|
}
|
|
|
|
if(sd_optimize_sectors(address, p.sectors, length / SD_SECTOR_SIZE, sd_write_sectors)) {
|
|
writeback_disable();
|
|
}
|
|
}
|
|
|
|
static bool writeback_save_to_usb (void) {
|
|
save_type_t save;
|
|
uint32_t address;
|
|
uint32_t length;
|
|
|
|
save = writeback_get_address_length(&address, &length);
|
|
if (save == SAVE_TYPE_NONE) {
|
|
writeback_disable();
|
|
return true;
|
|
}
|
|
|
|
usb_tx_info_t packet_info;
|
|
usb_create_packet(&packet_info, PACKET_CMD_SAVE_WRITEBACK);
|
|
packet_info.data_length = 4;
|
|
packet_info.data[0] = save;
|
|
packet_info.dma_length = length;
|
|
packet_info.dma_address = address;
|
|
return usb_enqueue_packet(&packet_info);
|
|
}
|
|
|
|
|
|
void writeback_load_sector_table (uint32_t address) {
|
|
fpga_mem_read(address, sizeof(p.sectors), (uint8_t *) (p.sectors));
|
|
for (int i = 0; i < SAVE_MAX_SECTOR_COUNT; i++) {
|
|
p.sectors[i] = SWAP32(p.sectors[i]);
|
|
}
|
|
}
|
|
|
|
void writeback_enable (writeback_mode_t mode) {
|
|
p.enabled = true;
|
|
p.pending = false;
|
|
p.mode = mode;
|
|
p.last_save_count = fpga_reg_get(REG_SAVE_COUNT);
|
|
}
|
|
|
|
void writeback_disable (void) {
|
|
p.enabled = false;
|
|
p.pending = false;
|
|
timer_set(TIMER_ID_WRITEBACK, 0);
|
|
}
|
|
|
|
bool writeback_pending (void) {
|
|
return p.enabled && p.pending;
|
|
}
|
|
|
|
void writeback_init (void) {
|
|
p.enabled = false;
|
|
p.pending = false;
|
|
p.mode = WRITEBACK_SD;
|
|
for (int i = 0; i < SAVE_MAX_SECTOR_COUNT; i++) {
|
|
p.sectors[i] = 0;
|
|
}
|
|
}
|
|
|
|
void writeback_process (void) {
|
|
if (p.enabled && (p.mode == WRITEBACK_SD) && !sd_card_is_inserted()) {
|
|
writeback_disable();
|
|
}
|
|
|
|
if (p.enabled) {
|
|
uint16_t save_count = fpga_reg_get(REG_SAVE_COUNT);
|
|
if (save_count != p.last_save_count) {
|
|
p.pending = true;
|
|
p.last_save_count = save_count;
|
|
timer_set(TIMER_ID_WRITEBACK, WRITEBACK_DELAY_TICKS);
|
|
}
|
|
}
|
|
|
|
if (p.pending && (timer_get(TIMER_ID_WRITEBACK) == 0)) {
|
|
switch (p.mode) {
|
|
case WRITEBACK_SD:
|
|
writeback_save_to_sd();
|
|
p.pending = false;
|
|
break;
|
|
case WRITEBACK_USB:
|
|
if (writeback_save_to_usb()) {
|
|
p.pending = false;
|
|
}
|
|
break;
|
|
default:
|
|
writeback_disable();
|
|
break;
|
|
}
|
|
}
|
|
}
|