[SC64][DOCS][SW] SD card and flash related improvements

This commit is contained in:
Mateusz Faderewski 2023-01-06 23:47:00 +01:00
parent 6c90e2f123
commit 677e0a7172
18 changed files with 221 additions and 87 deletions

View File

@ -13,12 +13,12 @@
| `C` | **CONFIG_SET** | config_id | new_value | --- | --- | Set config option | | `C` | **CONFIG_SET** | config_id | new_value | --- | --- | Set config option |
| `t` | **TIME_GET** | --- | --- | --- | time | Get current RTC value | | `t` | **TIME_GET** | --- | --- | --- | time | Get current RTC value |
| `T` | **TIME_SET** | time_0 | time_1 | --- | --- | Set RTC value | | `T` | **TIME_SET** | time_0 | time_1 | --- | --- | Set RTC value |
| `m` | **MEMORY_READ** | address | length | data | --- | Read data from specified memory address | | `m` | **MEMORY_READ** | address | length | --- | data | Read data from specified memory address |
| `M` | **MEMORY_WRITE** | address | length | --- | data | Write data to specified memory address | | `M` | **MEMORY_WRITE** | address | length | data | --- | Write data to specified memory address |
| `D` | **DD_SET_BLOCK_READY** | success | --- | --- | --- | Notify flashcart about 64DD block readiness | | `D` | **DD_SET_BLOCK_READY** | success | --- | --- | --- | Notify flashcart about 64DD block readiness |
| `U` | **USB_WRITE** | type | length | data | N/A | Send data to be received by app running on N64 | | `U` | **USB_WRITE** | type | length | data | N/A | Send data to be received by app running on N64 |
| `f` | **FIRMWARE_BACKUP** | address | --- | --- | status/length | Backup firmware to specified memory address | | `f` | **FIRMWARE_BACKUP** | address | --- | --- | status/length | Backup firmware to specified memory address |
| `F` | **FIRMWARE_UPDATE** | address | length | --- | status | Update firmware from specified memory address | | `F` | **FIRMWARE_UPDATE** | address | length | --- | status | Update firmware from specified memory address |
| `p` | **FLASH_WAIT_BUSY** | --- | --- | --- | erase_block_size | Wait until flash ready / get flash block erase size | | `p` | **FLASH_WAIT_BUSY** | wait | --- | --- | erase_block_size | Wait until flash ready / get flash block erase size |
| `P` | **FLASH_ERASE_BLOCK** | address | --- | --- | --- | Start flash block erase | | `P` | **FLASH_ERASE_BLOCK** | address | --- | --- | --- | Start flash block erase |
| `?` | **DEBUG_GET** | --- | --- | --- | debug_data | Get internal FPGA debug info | | `?` | **DEBUG_GET** | --- | --- | --- | debug_data | Get internal FPGA debug info |

View File

@ -20,7 +20,8 @@
| `s` | **SD_READ** | pi_address | sector_count | --- | --- | Read sectors from SD card to flashcart | | `s` | **SD_READ** | pi_address | sector_count | --- | --- | Read sectors from SD card to flashcart |
| `S` | **SD_WRITE** | pi_address | sector_count | --- | --- | Write sectors from flashcart to SD card | | `S` | **SD_WRITE** | pi_address | sector_count | --- | --- | Write sectors from flashcart to SD card |
| `D` | **DD_SD_INFO** | pi_address | table_size | --- | --- | Set 64DD disk SD sector info | | `D` | **DD_SD_INFO** | pi_address | table_size | --- | --- | Set 64DD disk SD sector info |
| `W` | **WRITEBACK_SD_INFO** | pi_address | enabled | --- | --- | Set save writeback SD sector info | | `W` | **WRITEBACK_SD_INFO** | pi_address | --- | --- | --- | Load writeback SD sector table and enable it |
| `p` | **FLASH_WAIT_BUSY** | --- | --- | erase_block_size | --- | Wait until flash ready / get block erase size | | `K` | **FLASH_PROGRAM** | pi_address | length | --- | --- | Program flash with bytes loaded into data buffer |
| `p` | **FLASH_WAIT_BUSY** | wait | --- | erase_block_size | --- | Wait until flash ready / get block erase size |
| `P` | **FLASH_ERASE_BLOCK** | pi_address | --- | --- | --- | Start flash block erase | | `P` | **FLASH_ERASE_BLOCK** | pi_address | --- | --- | --- | Start flash block erase |
| `?` | **DEBUG_GET** | --- | --- | debug_data_0 | debug_data_1 | Get internal FPGA debug info | | `?` | **DEBUG_GET** | --- | --- | debug_data_0 | debug_data_1 | Get internal FPGA debug info |

View File

@ -130,6 +130,7 @@ type: *enum* | default: `0`
- `5` - SRAM 768 kib save is enabled - `5` - SRAM 768 kib save is enabled
Use this setting for selecting save type that will be emulated. Only one save type can be enabled. 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 SD card when previously enabled.
--- ---

View File

@ -11,13 +11,21 @@
#define FROM_BCD(x) ((((x >> 4) & 0x0F) * 10) + (x & 0x0F)) #define FROM_BCD(x) ((((x >> 4) & 0x0F) * 10) + (x & 0x0F))
static DSTATUS status = STA_NOINIT;
DSTATUS disk_status (BYTE pdrv) { DSTATUS disk_status (BYTE pdrv) {
if (pdrv > 0) { if (pdrv > 0) {
return STA_NODISK; return STA_NODISK;
} }
DSTATUS status = 0;
sd_card_status_t sd_card_status = sc64_sd_card_get_status();
if (!(sd_card_status & SD_CARD_STATUS_INSERTED)) {
status |= STA_NODISK;
}
if (!(sd_card_status & SD_CARD_STATUS_INITIALIZED)) {
status |= STA_NOINIT;
}
return status; return status;
} }
@ -25,10 +33,10 @@ DSTATUS disk_initialize (BYTE pdrv) {
if (pdrv > 0) { if (pdrv > 0) {
return STA_NODISK; return STA_NODISK;
} }
if (!sc64_sd_card_init()) {
status &= ~(STA_NOINIT); sc64_sd_card_init();
}
return status; return disk_status(pdrv);
} }
DRESULT disk_read (BYTE pdrv, BYTE *buff, LBA_t sector, UINT count) { DRESULT disk_read (BYTE pdrv, BYTE *buff, LBA_t sector, UINT count) {

View File

@ -39,6 +39,7 @@ typedef enum {
SC64_CMD_SD_WRITE = 'S', SC64_CMD_SD_WRITE = 'S',
SC64_CMD_DD_SD_INFO = 'D', SC64_CMD_DD_SD_INFO = 'D',
SC64_CMD_WRITEBACK_SD_INFO = 'W', SC64_CMD_WRITEBACK_SD_INFO = 'W',
SC64_CMD_FLASH_PROGRAM = 'K',
SC64_CMD_FLASH_WAIT_BUSY = 'p', SC64_CMD_FLASH_WAIT_BUSY = 'p',
SC64_CMD_FLASH_ERASE_BLOCK = 'P', SC64_CMD_FLASH_ERASE_BLOCK = 'P',
SC64_CMD_DEBUG_GET = '?', SC64_CMD_DEBUG_GET = '?',
@ -188,7 +189,7 @@ bool sc64_usb_write (void *address, uint8_t type, uint32_t length) {
} }
bool sc64_sd_card_init (void) { bool sc64_sd_card_init (void) {
uint32_t args[2] = { 0, SD_CARD_OP_INIT }; uint32_t args[2] = { (uint32_t) (NULL), SD_CARD_OP_INIT };
if (sc64_execute_cmd(SC64_CMD_SD_CARD_OP, args, NULL)) { if (sc64_execute_cmd(SC64_CMD_SD_CARD_OP, args, NULL)) {
return true; return true;
} }
@ -196,7 +197,7 @@ bool sc64_sd_card_init (void) {
} }
bool sc64_sd_card_deinit (void) { bool sc64_sd_card_deinit (void) {
uint32_t args[2] = { 0, SD_CARD_OP_DEINIT }; uint32_t args[2] = { (uint32_t) (NULL), SD_CARD_OP_DEINIT };
if (sc64_execute_cmd(SC64_CMD_SD_CARD_OP, args, NULL)) { if (sc64_execute_cmd(SC64_CMD_SD_CARD_OP, args, NULL)) {
return true; return true;
} }
@ -204,7 +205,7 @@ bool sc64_sd_card_deinit (void) {
} }
sd_card_status_t sc64_sd_card_get_status (void) { sd_card_status_t sc64_sd_card_get_status (void) {
uint32_t args[2] = { 0, SD_CARD_OP_GET_STATUS }; uint32_t args[2] = { (uint32_t) (NULL), SD_CARD_OP_GET_STATUS };
uint32_t result[2]; uint32_t result[2];
if (sc64_execute_cmd(SC64_CMD_SD_CARD_OP, args, result)) { if (sc64_execute_cmd(SC64_CMD_SD_CARD_OP, args, result)) {
return false; return false;
@ -246,24 +247,32 @@ bool sc64_dd_set_sd_info (void *address, uint32_t length) {
return false; return false;
} }
bool sc64_writeback_set_sd_info (void *address, bool enabled) { bool sc64_writeback_enable (void *address) {
uint32_t args[2] = { (uint32_t) (address), (uint32_t) (enabled) }; uint32_t args[2] = { (uint32_t) (address), 0 };
if (sc64_execute_cmd(SC64_CMD_WRITEBACK_SD_INFO, args, NULL)) { if (sc64_execute_cmd(SC64_CMD_WRITEBACK_SD_INFO, args, NULL)) {
return true; return true;
} }
return false; return false;
} }
bool sc64_flash_program (void *address, uint32_t length) {
uint32_t args[2] = { (uint32_t) (address), length };
return sc64_execute_cmd(SC64_CMD_FLASH_PROGRAM, args, NULL);
}
void sc64_flash_wait_busy (void) {
uint32_t args[2] = { true, 0 };
sc64_execute_cmd(SC64_CMD_FLASH_WAIT_BUSY, args, NULL);
}
uint32_t sc64_flash_get_erase_block_size (void) { uint32_t sc64_flash_get_erase_block_size (void) {
uint32_t args[2] = { false, 0 };
uint32_t result[2]; uint32_t result[2];
sc64_execute_cmd(SC64_CMD_FLASH_WAIT_BUSY, NULL, result); sc64_execute_cmd(SC64_CMD_FLASH_WAIT_BUSY, args, result);
return result[0]; return result[0];
} }
bool sc64_flash_erase_block (void *address) { bool sc64_flash_erase_block (void *address) {
uint32_t args[2] = { (uint32_t) (address), 0 }; uint32_t args[2] = { (uint32_t) (address), 0 };
if (sc64_execute_cmd(SC64_CMD_FLASH_ERASE_BLOCK, args, NULL)) { return sc64_execute_cmd(SC64_CMD_FLASH_ERASE_BLOCK, args, NULL);
return true;
}
return sc64_execute_cmd(SC64_CMD_FLASH_WAIT_BUSY, NULL, NULL);
} }

View File

@ -76,9 +76,10 @@ typedef enum {
} button_mode_t; } button_mode_t;
typedef enum { typedef enum {
SD_CARD_STATUS_INITIALIZED = (1 << 0), SD_CARD_STATUS_INSERTED = (1 << 0),
SD_CARD_STATUS_TYPE_BLOCK = (1 << 1), SD_CARD_STATUS_INITIALIZED = (1 << 1),
SD_CARD_STATUS_50MHZ_MODE = (1 << 2), SD_CARD_STATUS_TYPE_BLOCK = (1 << 2),
SD_CARD_STATUS_50MHZ_MODE = (1 << 3),
} sd_card_status_t; } sd_card_status_t;
typedef struct { typedef struct {
@ -137,8 +138,10 @@ bool sc64_sd_card_get_info (void *address);
bool sc64_sd_write_sectors (void *address, uint32_t sector, uint32_t count); bool sc64_sd_write_sectors (void *address, uint32_t sector, uint32_t count);
bool sc64_sd_read_sectors (void *address, uint32_t sector, uint32_t count); bool sc64_sd_read_sectors (void *address, uint32_t sector, uint32_t count);
bool sc64_dd_set_sd_disk_info (void *address, uint32_t length); bool sc64_dd_set_sd_disk_info (void *address, uint32_t length);
bool sc64_writeback_set_sd_info (void *address, bool enabled); bool sc64_writeback_enable (void *address);
bool sc64_flash_program (void *address, uint32_t length);
void sc64_flash_wait_busy (void);
uint32_t sc64_flash_get_erase_block_size (void); uint32_t sc64_flash_get_erase_block_size (void);
bool sc64_flash_erase_block (void *address); bool sc64_flash_erase_block (void *address);

View File

@ -20,6 +20,14 @@ void test_execute (void) {
display_printf("SC64 Test suite\n\n"); display_printf("SC64 Test suite\n\n");
card_status = sc64_sd_card_get_status();
if (card_status & SD_CARD_STATUS_INSERTED) {
display_printf("SD card is inserted\n");
} else {
display_printf("SD card is not inserted\n");
}
if (sc64_sd_card_init()) { if (sc64_sd_card_init()) {
display_printf("SD card init error!\n"); display_printf("SD card init error!\n");
while (1); while (1);
@ -28,13 +36,13 @@ void test_execute (void) {
card_status = sc64_sd_card_get_status(); card_status = sc64_sd_card_get_status();
if (card_status & SD_CARD_STATUS_INITIALIZED) { if (card_status & SD_CARD_STATUS_INITIALIZED) {
display_printf("SD card initialized\n"); display_printf("SD card is initialized\n");
} }
if (card_status & SD_CARD_STATUS_TYPE_BLOCK) { if (card_status & SD_CARD_STATUS_TYPE_BLOCK) {
display_printf("SD card type block\n"); display_printf("SD card type is block\n");
} }
if (card_status & SD_CARD_STATUS_50MHZ_MODE) { if (card_status & SD_CARD_STATUS_50MHZ_MODE) {
display_printf("SD card 50 MHz clock mode\n"); display_printf("SD card runs at 50 MHz clock speed\n");
} }
if (sc64_sd_card_get_info((uint32_t *) (SC64_BUFFERS->BUFFER))) { if (sc64_sd_card_get_info((uint32_t *) (SC64_BUFFERS->BUFFER))) {

View File

@ -10,6 +10,10 @@
#include "writeback.h" #include "writeback.h"
#define DATA_BUFFER_ADDRESS (0x05000000)
#define DATA_BUFFER_SIZE (8192)
typedef enum { typedef enum {
CFG_ID_BOOTLOADER_SWITCH, CFG_ID_BOOTLOADER_SWITCH,
CFG_ID_ROM_WRITE_ENABLE, CFG_ID_ROM_WRITE_ENABLE,
@ -169,6 +173,8 @@ static bool cfg_set_save_type (save_type_t save_type) {
return true; return true;
} }
writeback_disable();
uint32_t save_reset_mask = ( uint32_t save_reset_mask = (
CFG_SCR_EEPROM_16K | CFG_SCR_EEPROM_16K |
CFG_SCR_EEPROM_ENABLED | CFG_SCR_EEPROM_ENABLED |
@ -494,7 +500,7 @@ void cfg_process (void) {
args[1] = sd_card_get_status(); args[1] = sd_card_get_status();
break; break;
case SD_CARD_OP_GET_INFO: case SD_CARD_OP_GET_INFO:
if (cfg_translate_address(&args[0], 32, (SDRAM | BRAM))) { if (cfg_translate_address(&args[0], SD_CARD_INFO_SIZE, (SDRAM | BRAM))) {
cfg_set_error(CFG_ERROR_BAD_ADDRESS); cfg_set_error(CFG_ERROR_BAD_ADDRESS);
return; return;
} }
@ -518,7 +524,7 @@ void cfg_process (void) {
cfg_set_error(CFG_ERROR_BAD_ARGUMENT); cfg_set_error(CFG_ERROR_BAD_ARGUMENT);
return; return;
} }
if (cfg_translate_address(&args[0], args[1] * SD_SECTOR_SIZE, (SDRAM | BRAM | FLASH))) { if (cfg_translate_address(&args[0], args[1] * SD_SECTOR_SIZE, (SDRAM | FLASH | BRAM))) {
cfg_set_error(CFG_ERROR_BAD_ADDRESS); cfg_set_error(CFG_ERROR_BAD_ADDRESS);
return; return;
} }
@ -526,6 +532,7 @@ void cfg_process (void) {
cfg_set_error(CFG_ERROR_SD_CARD); cfg_set_error(CFG_ERROR_SD_CARD);
return; return;
} }
p.sd_card_sector += args[1];
break; break;
case 'S': case 'S':
@ -533,7 +540,7 @@ void cfg_process (void) {
cfg_set_error(CFG_ERROR_BAD_ARGUMENT); cfg_set_error(CFG_ERROR_BAD_ARGUMENT);
return; return;
} }
if (cfg_translate_address(&args[0], args[1] * SD_SECTOR_SIZE, (SDRAM | BRAM | FLASH))) { if (cfg_translate_address(&args[0], args[1] * SD_SECTOR_SIZE, (SDRAM | FLASH | BRAM))) {
cfg_set_error(CFG_ERROR_BAD_ADDRESS); cfg_set_error(CFG_ERROR_BAD_ADDRESS);
return; return;
} }
@ -541,6 +548,7 @@ void cfg_process (void) {
cfg_set_error(CFG_ERROR_SD_CARD); cfg_set_error(CFG_ERROR_SD_CARD);
return; return;
} }
p.sd_card_sector += args[1];
break; break;
case 'D': case 'D':
@ -552,15 +560,33 @@ void cfg_process (void) {
break; break;
case 'W': case 'W':
if (cfg_translate_address(&args[0], 1024, (SDRAM | BRAM))) { if (cfg_translate_address(&args[0], WRITEBACK_SECTOR_TABLE_SIZE, (SDRAM | BRAM))) {
cfg_set_error(CFG_ERROR_BAD_ADDRESS); cfg_set_error(CFG_ERROR_BAD_ADDRESS);
return; return;
} }
writeback_set_sd_info(args[0], args[1]); writeback_load_sector_table(args[0]);
writeback_enable();
break;
case 'K':
if (args[1] >= DATA_BUFFER_SIZE) {
cfg_set_error(CFG_ERROR_BAD_ARGUMENT);
return;
}
if (cfg_translate_address(&args[0], args[1], FLASH)) {
cfg_set_error(CFG_ERROR_BAD_ADDRESS);
return;
}
if (flash_program(DATA_BUFFER_ADDRESS, args[0], args[1])) {
cfg_set_error(CFG_ERROR_BAD_ARGUMENT);
return;
}
break; break;
case 'p': case 'p':
if (args[0]) {
flash_wait_busy(); flash_wait_busy();
}
args[0] = FLASH_ERASE_BLOCK_SIZE; args[0] = FLASH_ERASE_BLOCK_SIZE;
break; break;
@ -569,7 +595,10 @@ void cfg_process (void) {
cfg_set_error(CFG_ERROR_BAD_ADDRESS); cfg_set_error(CFG_ERROR_BAD_ADDRESS);
return; return;
} }
flash_erase_block(args[0]); if (flash_erase_block(args[0])) {
cfg_set_error(CFG_ERROR_BAD_ARGUMENT);
return;
}
break; break;
case '?': case '?':

View File

@ -1,4 +1,28 @@
// Original code from https://github.com/jago85/UltraCIC_C licensed under the MIT License // Original code sourced from https://github.com/jago85/UltraCIC_C
// MIT License
// Copyright (c) 2019 Jan Goldacker
// Copyright (c) 2022 Mateusz Faderewski
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <stdbool.h> #include <stdbool.h>
#include "cic.h" #include "cic.h"

View File

@ -3,19 +3,42 @@
#define FLASH_ADDRESS (0x04000000UL) #define FLASH_ADDRESS (0x04000000UL)
#define FLASH_SIZE (16 * 1024 * 1024)
#define ERASE_BLOCK_SIZE (64 * 1024) #define ERASE_BLOCK_SIZE (64 * 1024)
bool flash_program (uint32_t src, uint32_t dst, uint32_t length) {
if (((src + length) >= FLASH_ADDRESS) && (src < (FLASH_ADDRESS + FLASH_SIZE))) {
return true;
}
if ((dst < FLASH_ADDRESS) || ((dst + length) >= (FLASH_ADDRESS + FLASH_SIZE))) {
return true;
}
while (length > 0) {
uint32_t block = (length > FPGA_MAX_MEM_TRANSFER) ? FPGA_MAX_MEM_TRANSFER : length;
fpga_mem_copy(src, dst, block);
src += block;
dst += block;
length -= block;
}
return false;
}
void flash_wait_busy (void) { void flash_wait_busy (void) {
uint8_t dummy[2]; uint8_t dummy[2];
fpga_mem_read(FLASH_ADDRESS, 2, dummy); fpga_mem_read(FLASH_ADDRESS, 2, dummy);
} }
void flash_erase_block (uint32_t offset) { bool flash_erase_block (uint32_t offset) {
if ((offset % FLASH_ERASE_BLOCK_SIZE) != 0) {
return true;
}
offset &= (FLASH_SIZE - 1);
for (int i = 0; i < (FLASH_ERASE_BLOCK_SIZE / ERASE_BLOCK_SIZE); i++) { for (int i = 0; i < (FLASH_ERASE_BLOCK_SIZE / ERASE_BLOCK_SIZE); i++) {
fpga_reg_set(REG_FLASH_SCR, offset); fpga_reg_set(REG_FLASH_SCR, offset);
while (fpga_reg_get(REG_FLASH_SCR) & FLASH_SCR_BUSY); while (fpga_reg_get(REG_FLASH_SCR) & FLASH_SCR_BUSY);
offset += ERASE_BLOCK_SIZE; offset += ERASE_BLOCK_SIZE;
} }
flash_wait_busy(); flash_wait_busy();
return false;
} }

View File

@ -2,14 +2,16 @@
#define FLASH_H__ #define FLASH_H__
#include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#define FLASH_ERASE_BLOCK_SIZE (128 * 1024) #define FLASH_ERASE_BLOCK_SIZE (128 * 1024)
bool flash_program (uint32_t src, uint32_t dst, uint32_t length);
void flash_wait_busy (void); void flash_wait_busy (void);
void flash_erase_block (uint32_t offset); bool flash_erase_block (uint32_t offset);
#endif #endif

View File

@ -33,6 +33,7 @@
#define SWITCH_FUNCTION_GROUP_1_HS (1 << 1) #define SWITCH_FUNCTION_GROUP_1_HS (1 << 1)
#define DAT_BLOCK_MAX_COUNT (256) #define DAT_BLOCK_MAX_COUNT (256)
#define DAT_TIMEOUT_MS (1000)
typedef enum { typedef enum {
@ -299,7 +300,7 @@ bool sd_card_init (void) {
sd_card_deinit(); sd_card_deinit();
return true; return true;
} }
sd_dat_wait(1000); sd_dat_wait(DAT_TIMEOUT_MS);
if (sd_did_timeout()) { if (sd_did_timeout()) {
sd_card_deinit(); sd_card_deinit();
return true; return true;
@ -317,7 +318,7 @@ bool sd_card_init (void) {
sd_card_deinit(); sd_card_deinit();
return true; return true;
} }
sd_dat_wait(1000); sd_dat_wait(DAT_TIMEOUT_MS);
if (sd_did_timeout()) { if (sd_did_timeout()) {
sd_card_deinit(); sd_card_deinit();
return true; return true;
@ -340,15 +341,21 @@ void sd_card_deinit (void) {
} }
} }
bool sd_card_is_inserted (void) {
return (fpga_reg_get(REG_SD_SCR) & SD_SCR_CARD_INSERTED);
}
uint32_t sd_card_get_status (void) { uint32_t sd_card_get_status (void) {
uint32_t scr = fpga_reg_get(REG_SD_SCR); uint32_t scr = fpga_reg_get(REG_SD_SCR);
uint32_t clock_mode_50mhz = ((scr & SD_SCR_CLOCK_MODE_MASK) == SD_SCR_CLOCK_MODE_50MHZ) ? 1 : 0; uint32_t clock_mode_50mhz = ((scr & SD_SCR_CLOCK_MODE_MASK) == SD_SCR_CLOCK_MODE_50MHZ) ? 1 : 0;
uint32_t card_type_block = p.card_type_block ? 1 : 0; uint32_t card_type_block = p.card_type_block ? 1 : 0;
uint32_t initialized = p.card_initialized ? 1 : 0; uint32_t card_initialized = p.card_initialized ? 1 : 0;
uint32_t card_inserted = (scr & SD_SCR_CARD_INSERTED) ? 1 : 0;
return ( return (
(clock_mode_50mhz << 2) | (clock_mode_50mhz << 3) |
(card_type_block << 1) | (card_type_block << 2) |
(initialized << 0) (card_initialized << 1) |
(card_inserted << 0)
); );
} }
@ -382,7 +389,7 @@ bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count) {
return true; return true;
} }
sd_dat_prepare(address, blocks, DAT_WRITE); sd_dat_prepare(address, blocks, DAT_WRITE);
if (sd_dat_wait(1000)) { if (sd_dat_wait(DAT_TIMEOUT_MS)) {
sd_dat_abort(); sd_dat_abort();
sd_cmd(12, 0, RSP_R1b, NULL); sd_cmd(12, 0, RSP_R1b, NULL);
return true; return true;
@ -417,7 +424,7 @@ bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count) {
sd_dat_abort(); sd_dat_abort();
return true; return true;
} }
if (sd_dat_wait(1000)) { if (sd_dat_wait(DAT_TIMEOUT_MS)) {
if (sd_did_timeout()) { if (sd_did_timeout()) {
sd_cmd(12, 0, RSP_R1b, NULL); sd_cmd(12, 0, RSP_R1b, NULL);
} }
@ -465,7 +472,7 @@ void sd_init (void) {
} }
void sd_process (void) { void sd_process (void) {
if (!(fpga_reg_get(REG_SD_SCR) & SD_SCR_CARD_INSERTED)) { if (!sd_card_is_inserted()) {
sd_card_deinit(); sd_card_deinit();
} }
} }

View File

@ -6,6 +6,7 @@
#define SD_SECTOR_SIZE (512) #define SD_SECTOR_SIZE (512)
#define SD_CARD_INFO_SIZE (32)
typedef bool sd_process_sectors_t (uint32_t address, uint32_t sector, uint32_t count); typedef bool sd_process_sectors_t (uint32_t address, uint32_t sector, uint32_t count);
@ -13,6 +14,7 @@ typedef bool sd_process_sectors_t (uint32_t address, uint32_t sector, uint32_t c
bool sd_card_init (void); bool sd_card_init (void);
void sd_card_deinit (void); void sd_card_deinit (void);
bool sd_card_is_inserted (void);
uint32_t sd_card_get_status (void); uint32_t sd_card_get_status (void);
bool sd_card_get_info (uint32_t address); bool sd_card_get_info (uint32_t address);
bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count); bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count);

View File

@ -162,15 +162,20 @@ static bool bootloader_update (uint32_t address, uint32_t length) {
uint8_t update_buffer[FPGA_MAX_MEM_TRANSFER]; uint8_t update_buffer[FPGA_MAX_MEM_TRANSFER];
uint8_t verify_buffer[FPGA_MAX_MEM_TRANSFER]; uint8_t verify_buffer[FPGA_MAX_MEM_TRANSFER];
for (uint32_t offset = 0; offset < BOOTLOADER_LENGTH; offset += FLASH_ERASE_BLOCK_SIZE) { for (uint32_t offset = 0; offset < BOOTLOADER_LENGTH; offset += FLASH_ERASE_BLOCK_SIZE) {
flash_erase_block(BOOTLOADER_ADDRESS + offset); if (flash_erase_block(BOOTLOADER_ADDRESS + offset)) {
return true;
} }
for (uint32_t offset = 0; offset < length; offset += FPGA_MAX_MEM_TRANSFER) { }
fpga_mem_copy(address + offset, BOOTLOADER_ADDRESS + offset, FPGA_MAX_MEM_TRANSFER); if (flash_program(address, BOOTLOADER_ADDRESS, length)) {
return true;
} }
for (uint32_t offset = 0; offset < length; offset += sizeof(verify_buffer)) { for (uint32_t offset = 0; offset < length; offset += sizeof(verify_buffer)) {
fpga_mem_read(address + offset, sizeof(update_buffer), update_buffer); fpga_mem_read(address + offset, sizeof(update_buffer), update_buffer);
fpga_mem_read(BOOTLOADER_ADDRESS + offset, sizeof(verify_buffer), verify_buffer); fpga_mem_read(BOOTLOADER_ADDRESS + offset, sizeof(verify_buffer), verify_buffer);
for (int i = 0; i < sizeof(verify_buffer); i++) { for (int i = 0; i < sizeof(verify_buffer); i++) {
if ((offset + i) >= length) {
break;
}
if (update_buffer[i] != verify_buffer[i]) { if (update_buffer[i] != verify_buffer[i]) {
return true; return true;
} }

View File

@ -272,7 +272,9 @@ static void usb_rx_process (void) {
break; break;
case 'p': case 'p':
if (p.rx_args[0]) {
flash_wait_busy(); flash_wait_busy();
}
p.rx_state = RX_STATE_IDLE; p.rx_state = RX_STATE_IDLE;
p.response_pending = true; p.response_pending = true;
p.response_info.data_length = 4; p.response_info.data_length = 4;
@ -280,7 +282,7 @@ static void usb_rx_process (void) {
break; break;
case 'P': case 'P':
flash_erase_block(p.rx_args[0]); p.response_error = flash_erase_block(p.rx_args[0]);
p.rx_state = RX_STATE_IDLE; p.rx_state = RX_STATE_IDLE;
p.response_pending = true; p.response_pending = true;
break; break;

View File

@ -6,8 +6,8 @@
#define SAVE_MAX_SECTOR_COUNT (256) #define SAVE_MAX_SECTOR_COUNT (256)
#define SRAM_FLASHRAM_ADDRESS (0x03FE0000)
#define EEPROM_ADDRESS (0x05002000) #define EEPROM_ADDRESS (0x05002000)
#define SRAM_FLASHRAM_ADDRESS (0x03FE0000)
#define EEPROM_4K_SECTOR_COUNT (1) #define EEPROM_4K_SECTOR_COUNT (1)
#define EEPROM_16K_SECTOR_COUNT (4) #define EEPROM_16K_SECTOR_COUNT (4)
#define SRAM_SECTOR_COUNT (64) #define SRAM_SECTOR_COUNT (64)
@ -53,30 +53,33 @@ static void writeback_save_to_sd (void) {
count = SRAM_BANKED_SECTOR_COUNT; count = SRAM_BANKED_SECTOR_COUNT;
break; break;
default: default:
p.enabled = false; writeback_disable();
return; return;
} }
if(sd_optimize_sectors(address, p.sectors, count, sd_write_sectors)) { if(sd_optimize_sectors(address, p.sectors, count, sd_write_sectors)) {
p.enabled = false; writeback_disable();
} }
} }
void writeback_set_sd_info (uint32_t address, bool enabled) { void writeback_load_sector_table (uint32_t address) {
p.enabled = enabled;
p.pending = false;
p.last_save_count = fpga_reg_get(REG_SAVE_COUNT);
if (p.enabled) {
fpga_mem_read(address, sizeof(p.sectors), (uint8_t *) (p.sectors)); fpga_mem_read(address, sizeof(p.sectors), (uint8_t *) (p.sectors));
for (int i = 0; i < SAVE_MAX_SECTOR_COUNT; i++) { for (int i = 0; i < SAVE_MAX_SECTOR_COUNT; i++) {
p.sectors[i] = SWAP32(p.sectors[i]); p.sectors[i] = SWAP32(p.sectors[i]);
} }
} else { }
for (int i = 0; i < SAVE_MAX_SECTOR_COUNT; i++) {
p.sectors[i] = 0; void writeback_enable (void) {
} p.enabled = true;
} p.pending = false;
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);
} }
void writeback_init (void) { void writeback_init (void) {
@ -88,22 +91,21 @@ void writeback_init (void) {
} }
void writeback_process (void) { void writeback_process (void) {
if (p.enabled && !sd_card_is_inserted()) {
writeback_disable();
}
if (p.enabled) { if (p.enabled) {
if (fpga_reg_get(REG_SD_SCR) & SD_SCR_CARD_INSERTED) {
uint16_t save_count = fpga_reg_get(REG_SAVE_COUNT); uint16_t save_count = fpga_reg_get(REG_SAVE_COUNT);
if (save_count != p.last_save_count) { if (save_count != p.last_save_count) {
p.pending = true; p.pending = true;
timer_set(TIMER_ID_WRITEBACK, WRITEBACK_DELAY_TICKS);
p.last_save_count = save_count; p.last_save_count = save_count;
} timer_set(TIMER_ID_WRITEBACK, WRITEBACK_DELAY_TICKS);
} else {
writeback_init();
} }
} }
if (p.pending) {
if (timer_get(TIMER_ID_WRITEBACK) == 0) { if (p.pending && (timer_get(TIMER_ID_WRITEBACK) == 0)) {
p.pending = false; p.pending = false;
writeback_save_to_sd(); writeback_save_to_sd();
} }
}
} }

View File

@ -6,7 +6,12 @@
#include <stdint.h> #include <stdint.h>
void writeback_set_sd_info (uint32_t address, bool enabled); #define WRITEBACK_SECTOR_TABLE_SIZE (1024)
void writeback_load_sector_table (uint32_t address);
void writeback_enable (void);
void writeback_disable (void);
void writeback_init (void); void writeback_init (void);
void writeback_process (void); void writeback_process (void);

View File

@ -352,8 +352,11 @@ class SC64:
def __dd_set_block_ready(self, error: int) -> None: def __dd_set_block_ready(self, error: int) -> None:
self.__link.execute_cmd(cmd=b'D', args=[error, 0]) self.__link.execute_cmd(cmd=b'D', args=[error, 0])
def __flash_wait_busy(self) -> int: def __flash_wait_busy(self) -> None:
data = self.__link.execute_cmd(cmd=b'p') self.__link.execute_cmd(cmd=b'p', args=[True, 0])
def __flash_get_erase_block_size(self) -> int:
data = self.__link.execute_cmd(cmd=b'p', args=[False, 0])
return self.__get_int(data[0:4]) return self.__get_int(data[0:4])
def __flash_erase_block(self, address: int) -> None: def __flash_erase_block(self, address: int) -> None:
@ -364,12 +367,11 @@ class SC64:
raise ValueError('Flash erase address or length outside of possible range') raise ValueError('Flash erase address or length outside of possible range')
if ((address + length) > (self.__Address.FLASH + self.__Length.FLASH)): if ((address + length) > (self.__Address.FLASH + self.__Length.FLASH)):
raise ValueError('Flash erase address or length outside of possible range') raise ValueError('Flash erase address or length outside of possible range')
erase_block_size = self.__flash_wait_busy() erase_block_size = self.__flash_get_erase_block_size()
if (address % erase_block_size != 0): if (address % erase_block_size != 0):
raise ValueError('Flash erase address not aligned to block size') raise ValueError('Flash erase address not aligned to block size')
for offset in range(address, address + length, erase_block_size): for offset in range(address, address + length, erase_block_size):
self.__flash_erase_block(offset) self.__flash_erase_block(offset)
self.__flash_wait_busy()
def __program_flash(self, address: int, data: bytes): def __program_flash(self, address: int, data: bytes):
program_chunk_size = (128 * 1024) program_chunk_size = (128 * 1024)
@ -377,6 +379,7 @@ class SC64:
self.__erase_flash_region(address, len(data)) self.__erase_flash_region(address, len(data))
for offset in range(0, len(data), program_chunk_size): for offset in range(0, len(data), program_chunk_size):
self.__write_memory(address + offset, data[offset:offset + program_chunk_size]) self.__write_memory(address + offset, data[offset:offset + program_chunk_size])
self.__flash_wait_busy()
if (self.__read_memory(address, len(data)) != data): if (self.__read_memory(address, len(data)) != data):
raise ConnectionException('Flash memory program failure') raise ConnectionException('Flash memory program failure')