diff --git a/docs/02_usb_commands.md b/docs/02_usb_commands.md index 901fb53..90ea86e 100644 --- a/docs/02_usb_commands.md +++ b/docs/02_usb_commands.md @@ -13,12 +13,12 @@ | `C` | **CONFIG_SET** | config_id | new_value | --- | --- | Set config option | | `t` | **TIME_GET** | --- | --- | --- | time | Get current 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_WRITE** | address | length | --- | data | Write data to 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 | | `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 | | `f` | **FIRMWARE_BACKUP** | address | --- | --- | status/length | Backup firmware to 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 | | `?` | **DEBUG_GET** | --- | --- | --- | debug_data | Get internal FPGA debug info | diff --git a/docs/03_n64_commands.md b/docs/03_n64_commands.md index 8c902e5..02725e9 100644 --- a/docs/03_n64_commands.md +++ b/docs/03_n64_commands.md @@ -20,7 +20,8 @@ | `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 | | `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 | -| `p` | **FLASH_WAIT_BUSY** | --- | --- | erase_block_size | --- | Wait until flash ready / get block erase size | +| `W` | **WRITEBACK_SD_INFO** | pi_address | --- | --- | --- | Load writeback SD sector table and enable it | +| `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 | | `?` | **DEBUG_GET** | --- | --- | debug_data_0 | debug_data_1 | Get internal FPGA debug info | diff --git a/docs/04_config_options.md b/docs/04_config_options.md index 1ab88e6..89b5538 100644 --- a/docs/04_config_options.md +++ b/docs/04_config_options.md @@ -130,6 +130,7 @@ type: *enum* | default: `0` - `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. +Any successful write to this config will disable automatic save writeback to SD card when previously enabled. --- diff --git a/sw/bootloader/src/fatfs/diskio.c b/sw/bootloader/src/fatfs/diskio.c index 445496a..95cd235 100644 --- a/sw/bootloader/src/fatfs/diskio.c +++ b/sw/bootloader/src/fatfs/diskio.c @@ -11,13 +11,21 @@ #define FROM_BCD(x) ((((x >> 4) & 0x0F) * 10) + (x & 0x0F)) -static DSTATUS status = STA_NOINIT; - - DSTATUS disk_status (BYTE pdrv) { if (pdrv > 0) { 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; } @@ -25,10 +33,10 @@ DSTATUS disk_initialize (BYTE pdrv) { if (pdrv > 0) { return STA_NODISK; } - if (!sc64_sd_card_init()) { - status &= ~(STA_NOINIT); - } - return status; + + sc64_sd_card_init(); + + return disk_status(pdrv); } DRESULT disk_read (BYTE pdrv, BYTE *buff, LBA_t sector, UINT count) { diff --git a/sw/bootloader/src/sc64.c b/sw/bootloader/src/sc64.c index 6eb3b8b..ac069e2 100644 --- a/sw/bootloader/src/sc64.c +++ b/sw/bootloader/src/sc64.c @@ -39,6 +39,7 @@ typedef enum { SC64_CMD_SD_WRITE = 'S', SC64_CMD_DD_SD_INFO = 'D', SC64_CMD_WRITEBACK_SD_INFO = 'W', + SC64_CMD_FLASH_PROGRAM = 'K', SC64_CMD_FLASH_WAIT_BUSY = 'p', SC64_CMD_FLASH_ERASE_BLOCK = 'P', 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) { - 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)) { return true; } @@ -196,7 +197,7 @@ bool sc64_sd_card_init (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)) { return true; } @@ -204,7 +205,7 @@ bool sc64_sd_card_deinit (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]; if (sc64_execute_cmd(SC64_CMD_SD_CARD_OP, args, result)) { return false; @@ -246,24 +247,32 @@ bool sc64_dd_set_sd_info (void *address, uint32_t length) { return false; } -bool sc64_writeback_set_sd_info (void *address, bool enabled) { - uint32_t args[2] = { (uint32_t) (address), (uint32_t) (enabled) }; +bool sc64_writeback_enable (void *address) { + uint32_t args[2] = { (uint32_t) (address), 0 }; if (sc64_execute_cmd(SC64_CMD_WRITEBACK_SD_INFO, args, NULL)) { return true; } 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 args[2] = { false, 0 }; 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]; } bool sc64_flash_erase_block (void *address) { uint32_t args[2] = { (uint32_t) (address), 0 }; - if (sc64_execute_cmd(SC64_CMD_FLASH_ERASE_BLOCK, args, NULL)) { - return true; - } - return sc64_execute_cmd(SC64_CMD_FLASH_WAIT_BUSY, NULL, NULL); + return sc64_execute_cmd(SC64_CMD_FLASH_ERASE_BLOCK, args, NULL); } diff --git a/sw/bootloader/src/sc64.h b/sw/bootloader/src/sc64.h index 30b0465..6e5eda2 100644 --- a/sw/bootloader/src/sc64.h +++ b/sw/bootloader/src/sc64.h @@ -76,9 +76,10 @@ typedef enum { } button_mode_t; typedef enum { - SD_CARD_STATUS_INITIALIZED = (1 << 0), - SD_CARD_STATUS_TYPE_BLOCK = (1 << 1), - SD_CARD_STATUS_50MHZ_MODE = (1 << 2), + SD_CARD_STATUS_INSERTED = (1 << 0), + SD_CARD_STATUS_INITIALIZED = (1 << 1), + SD_CARD_STATUS_TYPE_BLOCK = (1 << 2), + SD_CARD_STATUS_50MHZ_MODE = (1 << 3), } sd_card_status_t; 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_read_sectors (void *address, uint32_t sector, uint32_t count); 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); bool sc64_flash_erase_block (void *address); diff --git a/sw/bootloader/src/test.c b/sw/bootloader/src/test.c index 508c58a..6fb4a67 100644 --- a/sw/bootloader/src/test.c +++ b/sw/bootloader/src/test.c @@ -20,6 +20,14 @@ void test_execute (void) { 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()) { display_printf("SD card init error!\n"); while (1); @@ -28,13 +36,13 @@ void test_execute (void) { card_status = sc64_sd_card_get_status(); 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) { - display_printf("SD card type block\n"); + display_printf("SD card type is block\n"); } 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))) { diff --git a/sw/controller/src/cfg.c b/sw/controller/src/cfg.c index e8f5004..25eb5a1 100644 --- a/sw/controller/src/cfg.c +++ b/sw/controller/src/cfg.c @@ -10,6 +10,10 @@ #include "writeback.h" +#define DATA_BUFFER_ADDRESS (0x05000000) +#define DATA_BUFFER_SIZE (8192) + + typedef enum { CFG_ID_BOOTLOADER_SWITCH, CFG_ID_ROM_WRITE_ENABLE, @@ -169,6 +173,8 @@ static bool cfg_set_save_type (save_type_t save_type) { return true; } + writeback_disable(); + uint32_t save_reset_mask = ( CFG_SCR_EEPROM_16K | CFG_SCR_EEPROM_ENABLED | @@ -494,7 +500,7 @@ void cfg_process (void) { args[1] = sd_card_get_status(); break; 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); return; } @@ -518,7 +524,7 @@ void cfg_process (void) { cfg_set_error(CFG_ERROR_BAD_ARGUMENT); 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); return; } @@ -526,6 +532,7 @@ void cfg_process (void) { cfg_set_error(CFG_ERROR_SD_CARD); return; } + p.sd_card_sector += args[1]; break; case 'S': @@ -533,7 +540,7 @@ void cfg_process (void) { cfg_set_error(CFG_ERROR_BAD_ARGUMENT); 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); return; } @@ -541,6 +548,7 @@ void cfg_process (void) { cfg_set_error(CFG_ERROR_SD_CARD); return; } + p.sd_card_sector += args[1]; break; case 'D': @@ -552,15 +560,33 @@ void cfg_process (void) { break; 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); 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; case 'p': - flash_wait_busy(); + if (args[0]) { + flash_wait_busy(); + } args[0] = FLASH_ERASE_BLOCK_SIZE; break; @@ -569,7 +595,10 @@ void cfg_process (void) { cfg_set_error(CFG_ERROR_BAD_ADDRESS); return; } - flash_erase_block(args[0]); + if (flash_erase_block(args[0])) { + cfg_set_error(CFG_ERROR_BAD_ARGUMENT); + return; + } break; case '?': diff --git a/sw/controller/src/cic.c b/sw/controller/src/cic.c index 19e9ead..ccf8dbe 100644 --- a/sw/controller/src/cic.c +++ b/sw/controller/src/cic.c @@ -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 #include "cic.h" diff --git a/sw/controller/src/flash.c b/sw/controller/src/flash.c index bca24aa..8d32ca3 100644 --- a/sw/controller/src/flash.c +++ b/sw/controller/src/flash.c @@ -3,19 +3,42 @@ #define FLASH_ADDRESS (0x04000000UL) +#define FLASH_SIZE (16 * 1024 * 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) { uint8_t dummy[2]; 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++) { fpga_reg_set(REG_FLASH_SCR, offset); while (fpga_reg_get(REG_FLASH_SCR) & FLASH_SCR_BUSY); offset += ERASE_BLOCK_SIZE; } flash_wait_busy(); + return false; } diff --git a/sw/controller/src/flash.h b/sw/controller/src/flash.h index a60d010..d2b2cb1 100644 --- a/sw/controller/src/flash.h +++ b/sw/controller/src/flash.h @@ -2,14 +2,16 @@ #define FLASH_H__ +#include #include #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_erase_block (uint32_t offset); +bool flash_erase_block (uint32_t offset); #endif diff --git a/sw/controller/src/sd.c b/sw/controller/src/sd.c index e6740bf..87682ac 100644 --- a/sw/controller/src/sd.c +++ b/sw/controller/src/sd.c @@ -33,6 +33,7 @@ #define SWITCH_FUNCTION_GROUP_1_HS (1 << 1) #define DAT_BLOCK_MAX_COUNT (256) +#define DAT_TIMEOUT_MS (1000) typedef enum { @@ -299,7 +300,7 @@ bool sd_card_init (void) { sd_card_deinit(); return true; } - sd_dat_wait(1000); + sd_dat_wait(DAT_TIMEOUT_MS); if (sd_did_timeout()) { sd_card_deinit(); return true; @@ -317,7 +318,7 @@ bool sd_card_init (void) { sd_card_deinit(); return true; } - sd_dat_wait(1000); + sd_dat_wait(DAT_TIMEOUT_MS); if (sd_did_timeout()) { sd_card_deinit(); 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 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 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 ( - (clock_mode_50mhz << 2) | - (card_type_block << 1) | - (initialized << 0) + (clock_mode_50mhz << 3) | + (card_type_block << 2) | + (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; } sd_dat_prepare(address, blocks, DAT_WRITE); - if (sd_dat_wait(1000)) { + if (sd_dat_wait(DAT_TIMEOUT_MS)) { sd_dat_abort(); sd_cmd(12, 0, RSP_R1b, NULL); return true; @@ -417,7 +424,7 @@ bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count) { sd_dat_abort(); return true; } - if (sd_dat_wait(1000)) { + if (sd_dat_wait(DAT_TIMEOUT_MS)) { if (sd_did_timeout()) { sd_cmd(12, 0, RSP_R1b, NULL); } @@ -465,7 +472,7 @@ void sd_init (void) { } void sd_process (void) { - if (!(fpga_reg_get(REG_SD_SCR) & SD_SCR_CARD_INSERTED)) { + if (!sd_card_is_inserted()) { sd_card_deinit(); } } diff --git a/sw/controller/src/sd.h b/sw/controller/src/sd.h index 3df2434..690905b 100644 --- a/sw/controller/src/sd.h +++ b/sw/controller/src/sd.h @@ -6,6 +6,7 @@ #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); @@ -13,6 +14,7 @@ typedef bool sd_process_sectors_t (uint32_t address, uint32_t sector, uint32_t c bool sd_card_init (void); void sd_card_deinit (void); +bool sd_card_is_inserted (void); uint32_t sd_card_get_status (void); bool sd_card_get_info (uint32_t address); bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count); diff --git a/sw/controller/src/update.c b/sw/controller/src/update.c index 52ab791..90aa404 100644 --- a/sw/controller/src/update.c +++ b/sw/controller/src/update.c @@ -162,15 +162,20 @@ static bool bootloader_update (uint32_t address, uint32_t length) { uint8_t update_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) { - 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)) { fpga_mem_read(address + offset, sizeof(update_buffer), update_buffer); fpga_mem_read(BOOTLOADER_ADDRESS + offset, sizeof(verify_buffer), verify_buffer); for (int i = 0; i < sizeof(verify_buffer); i++) { + if ((offset + i) >= length) { + break; + } if (update_buffer[i] != verify_buffer[i]) { return true; } diff --git a/sw/controller/src/usb.c b/sw/controller/src/usb.c index ca73e75..ab59986 100644 --- a/sw/controller/src/usb.c +++ b/sw/controller/src/usb.c @@ -272,7 +272,9 @@ static void usb_rx_process (void) { break; case 'p': - flash_wait_busy(); + if (p.rx_args[0]) { + flash_wait_busy(); + } p.rx_state = RX_STATE_IDLE; p.response_pending = true; p.response_info.data_length = 4; @@ -280,7 +282,7 @@ static void usb_rx_process (void) { break; 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.response_pending = true; break; diff --git a/sw/controller/src/writeback.c b/sw/controller/src/writeback.c index 5ea80b5..0fd9485 100644 --- a/sw/controller/src/writeback.c +++ b/sw/controller/src/writeback.c @@ -6,8 +6,8 @@ #define SAVE_MAX_SECTOR_COUNT (256) -#define SRAM_FLASHRAM_ADDRESS (0x03FE0000) #define EEPROM_ADDRESS (0x05002000) +#define SRAM_FLASHRAM_ADDRESS (0x03FE0000) #define EEPROM_4K_SECTOR_COUNT (1) #define EEPROM_16K_SECTOR_COUNT (4) #define SRAM_SECTOR_COUNT (64) @@ -53,30 +53,33 @@ static void writeback_save_to_sd (void) { count = SRAM_BANKED_SECTOR_COUNT; break; default: - p.enabled = false; + writeback_disable(); return; } 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) { - p.enabled = enabled; +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 (void) { + p.enabled = true; 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)); - for (int i = 0; i < SAVE_MAX_SECTOR_COUNT; 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_disable (void) { + p.enabled = false; + p.pending = false; + timer_set(TIMER_ID_WRITEBACK, 0); } void writeback_init (void) { @@ -88,22 +91,21 @@ void writeback_init (void) { } void writeback_process (void) { + if (p.enabled && !sd_card_is_inserted()) { + writeback_disable(); + } + if (p.enabled) { - if (fpga_reg_get(REG_SD_SCR) & SD_SCR_CARD_INSERTED) { - uint16_t save_count = fpga_reg_get(REG_SAVE_COUNT); - if (save_count != p.last_save_count) { - p.pending = true; - timer_set(TIMER_ID_WRITEBACK, WRITEBACK_DELAY_TICKS); - p.last_save_count = save_count; - } - } else { - writeback_init(); + 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) { - if (timer_get(TIMER_ID_WRITEBACK) == 0) { - p.pending = false; - writeback_save_to_sd(); - } + + if (p.pending && (timer_get(TIMER_ID_WRITEBACK) == 0)) { + p.pending = false; + writeback_save_to_sd(); } } diff --git a/sw/controller/src/writeback.h b/sw/controller/src/writeback.h index 3895121..41e038d 100644 --- a/sw/controller/src/writeback.h +++ b/sw/controller/src/writeback.h @@ -6,7 +6,12 @@ #include -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_process (void); diff --git a/sw/pc/sc64.py b/sw/pc/sc64.py index c8ad058..52160bc 100755 --- a/sw/pc/sc64.py +++ b/sw/pc/sc64.py @@ -352,8 +352,11 @@ class SC64: def __dd_set_block_ready(self, error: int) -> None: self.__link.execute_cmd(cmd=b'D', args=[error, 0]) - def __flash_wait_busy(self) -> int: - data = self.__link.execute_cmd(cmd=b'p') + def __flash_wait_busy(self) -> None: + 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]) 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') if ((address + length) > (self.__Address.FLASH + self.__Length.FLASH)): 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): raise ValueError('Flash erase address not aligned to block size') for offset in range(address, address + length, erase_block_size): self.__flash_erase_block(offset) - self.__flash_wait_busy() def __program_flash(self, address: int, data: bytes): program_chunk_size = (128 * 1024) @@ -377,6 +379,7 @@ class SC64: self.__erase_flash_region(address, len(data)) for offset in range(0, len(data), 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): raise ConnectionException('Flash memory program failure')