mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-21 21:49:15 +01:00
[SC64][DOCS][SW] SD card and flash related improvements
This commit is contained in:
parent
6c90e2f123
commit
677e0a7172
@ -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 |
|
||||
|
@ -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 |
|
||||
|
@ -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.
|
||||
|
||||
---
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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))) {
|
||||
|
@ -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 '?':
|
||||
|
@ -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 "cic.h"
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -2,14 +2,16 @@
|
||||
#define FLASH_H__
|
||||
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
#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
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,12 @@
|
||||
#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_process (void);
|
||||
|
||||
|
@ -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')
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user