[SC64][SW] Changed firmware version reporting

This commit is contained in:
Mateusz Faderewski 2023-02-20 18:17:09 +01:00
parent 56cdd3a709
commit 409ba28359
14 changed files with 142 additions and 152 deletions

View File

@ -5,7 +5,7 @@
- [SC64 registers](#sc64-registers) - [SC64 registers](#sc64-registers)
- [`0x1FFF_0000`: **STATUS/COMMAND**](#0x1fff_0000-statuscommand) - [`0x1FFF_0000`: **STATUS/COMMAND**](#0x1fff_0000-statuscommand)
- [`0x1FFF_0004`: **DATA0** and `0x1FFF_0008`: **DATA1**](#0x1fff_0004-data0-and-0x1fff_0008-data1) - [`0x1FFF_0004`: **DATA0** and `0x1FFF_0008`: **DATA1**](#0x1fff_0004-data0-and-0x1fff_0008-data1)
- [`0x1FFF_000C`: **VERSION**](#0x1fff_000c-version) - [`0x1FFF_000C`: **IDENTIFIER**](#0x1fff_000c-identifier)
- [`0x1FFF_0010`: **KEY**](#0x1fff_0010-key) - [`0x1FFF_0010`: **KEY**](#0x1fff_0010-key)
- [Command execution flow](#command-execution-flow) - [Command execution flow](#command-execution-flow)
@ -87,13 +87,13 @@ SC64 contains small register region used for communication between N64 and contr
Protocol is command based with support for up to 256 diferrent commands and two 32-bit argument/result values per operation. Protocol is command based with support for up to 256 diferrent commands and two 32-bit argument/result values per operation.
Support for interrupts is provided but currently no command relies on it, 64DD IRQ is handled separately. Support for interrupts is provided but currently no command relies on it, 64DD IRQ is handled separately.
| name | address | size | access | usage | | name | address | size | access | usage |
| ------------------ | ------------- | ------- | ------ | -------------------------------- | | ------------------ | ------------- | ------- | ------ | ---------------------------------- |
| **STATUS/COMMAND** | `0x1FFF_0000` | 4 bytes | RW | Command execution and status | | **STATUS/COMMAND** | `0x1FFF_0000` | 4 bytes | RW | Command execution and status |
| **DATA0** | `0x1FFF_0004` | 4 bytes | RW | Command argument/result 0 | | **DATA0** | `0x1FFF_0004` | 4 bytes | RW | Command argument/result 0 |
| **DATA1** | `0x1FFF_0008` | 4 bytes | RW | Command argument/result 1 | | **DATA1** | `0x1FFF_0008` | 4 bytes | RW | Command argument/result 1 |
| **VERSION** | `0x1FFF_000C` | 4 bytes | RW | Hardware version and IRQ clear | | **IDENTIFIER** | `0x1FFF_000C` | 4 bytes | RW | Flashcart identifier and IRQ clear |
| **KEY** | `0x1FFF_0010` | 4 bytes | W | SC64 register access lock/unlock | | **KEY** | `0x1FFF_0010` | 4 bytes | W | SC64 register access lock/unlock |
--- ---
@ -121,11 +121,11 @@ Note: Result is valid only when command has executed and `CMD_BUSY` bit is reset
--- ---
#### `0x1FFF_000C`: **VERSION** #### `0x1FFF_000C`: **IDENTIFIER**
| name | bits | access | meaning | | name | bits | access | meaning |
| --------- | ------ | ------ | --------------------------------------------- | | ------------ | ------ | ------ | ------------------------------------------------- |
| `VERSION` | [31:0] | RW | Hardware version (ASCII `SCv2`) and IRQ clear | | `IDENTIFIER` | [31:0] | RW | Flashcart identifier (ASCII `SCv2`) and IRQ clear |
Note: Writing any value to this register will clear pending flashcart interrupt. Note: Writing any value to this register will clear pending flashcart interrupt.

View File

@ -4,25 +4,25 @@
## USB commands ## USB commands
| id | name | arg0 | arg1 | data | response | description | | id | name | arg0 | arg1 | data | response | description |
| --- | ---------------------- | ------------ | ------------ | ---- | ---------------- | --------------------------------------------------- | | --- | ---------------------- | ------------ | ------------ | ---- | ---------------- | ------------------------------------------------------------- |
| `v` | **HW_VERSION_GET** | --- | --- | --- | hw_version | Get HW version | | `v` | **IDENTIFIER_GET** | --- | --- | --- | identifier | Get flashcart identifier `SCv2` |
| `V` | **API_VERSION_GET** | --- | --- | --- | api_version | Get USB command API version | | `V` | **VERSION_GET** | --- | --- | --- | version | Get flashcart firmware version |
| `R` | **STATE_RESET** | --- | --- | --- | --- | Reset entire flashcart state | | `R` | **STATE_RESET** | --- | --- | --- | --- | Reset flashcart state (CIC params and config options) |
| `B` | **CIC_PARAMS_SET** | cic_params_0 | cic_params_1 | --- | --- | Set CIC disable/mode/seed/checksum | | `B` | **CIC_PARAMS_SET** | cic_params_0 | cic_params_1 | --- | --- | Set CIC emulation parameters (disable/seed/checksum) |
| `c` | **CONFIG_GET** | config_id | --- | --- | current_value | Get config option | | `c` | **CONFIG_GET** | config_id | --- | --- | current_value | Get config option |
| `C` | **CONFIG_SET** | config_id | new_value | --- | --- | Set config option | | `C` | **CONFIG_SET** | config_id | new_value | --- | --- | Set config option |
| `a` | **SETTING_GET** | setting_id | --- | --- | current_value | Get persistent setting | | `a` | **SETTING_GET** | setting_id | --- | --- | current_value | Get persistent setting option |
| `A` | **SETTING_SET** | setting_id | new_value | --- | --- | Set persistent setting | | `A` | **SETTING_SET** | setting_id | new_value | --- | --- | Set persistent setting 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 new 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 | | `U` | **USB_WRITE** | type | length | data | N/A | Send data to be received by app running on N64 (no response!) |
| `U` | **USB_WRITE** | type | length | data | N/A | Send data to be received by app running on N64 | | `D` | **DD_SET_BLOCK_READY** | success | --- | --- | --- | Notify flashcart about 64DD block readiness |
| `f` | **FIRMWARE_BACKUP** | address | --- | --- | status/length | Backup firmware to specified memory address | | `p` | **FLASH_WAIT_BUSY** | wait | --- | --- | erase_block_size | Wait until flash ready / Get flash block erase size |
| `F` | **FIRMWARE_UPDATE** | address | length | --- | status | Update firmware from specified memory address | | `P` | **FLASH_ERASE_BLOCK** | address | --- | --- | --- | Start flash block erase |
| `p` | **FLASH_WAIT_BUSY** | wait | --- | --- | erase_block_size | Wait until flash ready / get flash block erase size | | `f` | **FIRMWARE_BACKUP** | address | --- | --- | status/length | Backup firmware to specified memory address |
| `P` | **FLASH_ERASE_BLOCK** | address | --- | --- | --- | Start flash block erase | | `F` | **FIRMWARE_UPDATE** | address | length | --- | status | Update firmware from specified memory address |
| `?` | **DEBUG_GET** | --- | --- | --- | debug_data | Get internal FPGA debug info | | `?` | **DEBUG_GET** | --- | --- | --- | debug_data | Get internal FPGA debug info |
| `%` | **STACK_USAGE_GET** | --- | --- | --- | stack_usage | Get per task stack usage | | `%` | **STACK_USAGE_GET** | --- | --- | --- | stack_usage | Get per task stack usage |

View File

@ -6,14 +6,14 @@
| id | name | arg0 | arg1 | rsp0 | rsp1 | description | | id | name | arg0 | arg1 | rsp0 | rsp1 | description |
| --- | --------------------- | ---------- | ------------ | ---------------- | -------------- | -------------------------------------------------- | | --- | --------------------- | ---------- | ------------ | ---------------- | -------------- | -------------------------------------------------- |
| `v` | **HW_VERSION_GET** | --- | --- | hw_version | --- | Get HW version | | `v` | **IDENTIFIER_GET** | --- | --- | identifier | --- | Get flashcart identifier `SCv2` |
| `V` | **API_VERSION_GET** | --- | --- | api_version | --- | Get N64 command API version | | `V` | **VERSION_GET** | --- | --- | version | --- | Get flashcart firmware version |
| `c` | **CONFIG_GET** | config_id | --- | --- | current_value | Get config option | | `c` | **CONFIG_GET** | config_id | --- | --- | current_value | Get config option |
| `C` | **CONFIG_SET** | config_id | new_value | --- | previous_value | Set config option and get previous value | | `C` | **CONFIG_SET** | config_id | new_value | --- | previous_value | Set config option and get previous value |
| `c` | **SETTING_GET** | setting_id | --- | --- | current_value | Get persistent setting option | | `c` | **SETTING_GET** | setting_id | --- | --- | current_value | Get persistent setting option |
| `C` | **SETTING_SET** | setting_id | new_value | --- | --- | Set persistent setting option | | `C` | **SETTING_SET** | setting_id | new_value | --- | --- | Set persistent setting option |
| `t` | **TIME_GET** | --- | --- | time_0 | time_1 | Get current RTC value | | `t` | **TIME_GET** | --- | --- | time_0 | time_1 | Get current RTC value |
| `T` | **TIME_SET** | time_0 | time_1 | --- | --- | Set RTC value | | `T` | **TIME_SET** | time_0 | time_1 | --- | --- | Set new RTC value |
| `m` | **USB_READ** | pi_address | length | --- | --- | Receive data from USB to flashcart | | `m` | **USB_READ** | pi_address | length | --- | --- | Receive data from USB to flashcart |
| `M` | **USB_WRITE** | pi_address | length/type | --- | --- | Send data from from flashcart to USB | | `M` | **USB_WRITE** | pi_address | length/type | --- | --- | Send data from from flashcart to USB |
| `u` | **USB_READ_STATUS** | --- | --- | read_status/type | length | Get USB read status and type/length | | `u` | **USB_READ_STATUS** | --- | --- | read_status/type | length | Get USB read status and type/length |
@ -27,4 +27,3 @@
| `K` | **FLASH_PROGRAM** | pi_address | length | --- | --- | Program flash with bytes loaded into data buffer | | `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_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 |

View File

@ -332,7 +332,7 @@ module mcu_top (
REG_CFG_DATA_0, REG_CFG_DATA_0,
REG_CFG_DATA_1, REG_CFG_DATA_1,
REG_CFG_CMD, REG_CFG_CMD,
REG_CFG_VERSION, REG_CFG_IDENTIFIER,
REG_FLASHRAM_SCR, REG_FLASHRAM_SCR,
REG_FLASH_SCR, REG_FLASH_SCR,
REG_RTC_SCR, REG_RTC_SCR,
@ -363,7 +363,7 @@ module mcu_top (
logic bootloader_skip; logic bootloader_skip;
assign n64_scb.cfg_version = 32'h53437632; assign n64_scb.cfg_identifier = 32'h53437632;
logic dd_bm_ack; logic dd_bm_ack;
@ -460,8 +460,8 @@ module mcu_top (
}; };
end end
REG_CFG_VERSION: begin REG_CFG_IDENTIFIER: begin
reg_rdata <= n64_scb.cfg_version; reg_rdata <= n64_scb.cfg_identifier;
end end
REG_FLASHRAM_SCR: begin REG_FLASHRAM_SCR: begin

View File

@ -16,8 +16,8 @@ module n64_cfg (
REG_DATA_0_L, REG_DATA_0_L,
REG_DATA_1_H, REG_DATA_1_H,
REG_DATA_1_L, REG_DATA_1_L,
REG_VERSION_H, REG_IDENTIFIER_H,
REG_VERSION_L, REG_IDENTIFIER_L,
REG_KEY_H, REG_KEY_H,
REG_KEY_L REG_KEY_L
} e_reg; } e_reg;
@ -39,8 +39,8 @@ module n64_cfg (
REG_DATA_0_L: reg_bus.rdata = n64_scb.cfg_wdata[0][15:0]; REG_DATA_0_L: reg_bus.rdata = n64_scb.cfg_wdata[0][15:0];
REG_DATA_1_H: reg_bus.rdata = n64_scb.cfg_wdata[1][31:16]; REG_DATA_1_H: reg_bus.rdata = n64_scb.cfg_wdata[1][31:16];
REG_DATA_1_L: reg_bus.rdata = n64_scb.cfg_wdata[1][15:0]; REG_DATA_1_L: reg_bus.rdata = n64_scb.cfg_wdata[1][15:0];
REG_VERSION_H: reg_bus.rdata = n64_scb.cfg_version[31:16]; REG_IDENTIFIER_H: reg_bus.rdata = n64_scb.cfg_identifier[31:16];
REG_VERSION_L: reg_bus.rdata = n64_scb.cfg_version[15:0]; REG_IDENTIFIER_L: reg_bus.rdata = n64_scb.cfg_identifier[15:0];
REG_KEY_H: reg_bus.rdata = 16'd0; REG_KEY_H: reg_bus.rdata = 16'd0;
REG_KEY_L: reg_bus.rdata = 16'd0; REG_KEY_L: reg_bus.rdata = 16'd0;
endcase endcase
@ -83,7 +83,7 @@ module n64_cfg (
REG_DATA_0_L: n64_scb.cfg_rdata[0][15:0] <= reg_bus.wdata; REG_DATA_0_L: n64_scb.cfg_rdata[0][15:0] <= reg_bus.wdata;
REG_DATA_1_H: n64_scb.cfg_rdata[1][31:16] <= reg_bus.wdata; REG_DATA_1_H: n64_scb.cfg_rdata[1][31:16] <= reg_bus.wdata;
REG_DATA_1_L: n64_scb.cfg_rdata[1][15:0] <= reg_bus.wdata; REG_DATA_1_L: n64_scb.cfg_rdata[1][15:0] <= reg_bus.wdata;
REG_VERSION_H: irq <= 1'b0; REG_IDENTIFIER_H: irq <= 1'b0;
REG_KEY_H, REG_KEY_L: begin REG_KEY_H, REG_KEY_L: begin
lock_sequence_counter <= lock_sequence_counter + 1'd1; lock_sequence_counter <= lock_sequence_counter + 1'd1;
if (reg_bus.wdata != 16'hFFFF) begin if (reg_bus.wdata != 16'hFFFF) begin

View File

@ -51,7 +51,7 @@ interface n64_scb ();
logic [7:0] cfg_cmd; logic [7:0] cfg_cmd;
logic [31:0] cfg_rdata [0:1]; logic [31:0] cfg_rdata [0:1];
logic [31:0] cfg_wdata [0:1]; logic [31:0] cfg_wdata [0:1];
logic [31:0] cfg_version; logic [31:0] cfg_identifier;
logic [15:0] save_count; logic [15:0] save_count;
@ -94,7 +94,7 @@ interface n64_scb ();
input cfg_cmd, input cfg_cmd,
input cfg_rdata, input cfg_rdata,
output cfg_wdata, output cfg_wdata,
output cfg_version, output cfg_identifier,
input save_count, input save_count,
@ -194,7 +194,7 @@ interface n64_scb ();
output cfg_cmd, output cfg_cmd,
output cfg_rdata, output cfg_rdata,
input cfg_wdata, input cfg_wdata,
input cfg_version input cfg_identifier
); );
modport save_counter ( modport save_counter (

View File

@ -5,7 +5,7 @@
typedef struct { typedef struct {
io32_t SR_CMD; io32_t SR_CMD;
io32_t DATA[2]; io32_t DATA[2];
io32_t VERSION; io32_t IDENTIFIER;
io32_t KEY; io32_t KEY;
} sc64_regs_t; } sc64_regs_t;
@ -16,7 +16,7 @@ typedef struct {
#define SC64_SR_CMD_ERROR (1 << 30) #define SC64_SR_CMD_ERROR (1 << 30)
#define SC64_SR_CPU_BUSY (1 << 31) #define SC64_SR_CPU_BUSY (1 << 31)
#define SC64_VERSION_2 (0x53437632) #define SC64_V2_IDENTIFIER (0x53437632)
#define SC64_KEY_RESET (0x00000000UL) #define SC64_KEY_RESET (0x00000000UL)
#define SC64_KEY_UNLOCK_1 (0x5F554E4CUL) #define SC64_KEY_UNLOCK_1 (0x5F554E4CUL)
@ -24,8 +24,8 @@ typedef struct {
#define SC64_KEY_LOCK (0xFFFFFFFFUL) #define SC64_KEY_LOCK (0xFFFFFFFFUL)
typedef enum { typedef enum {
SC64_CMD_HW_VERSION_GET = 'v', SC64_CMD_IDENTIFIER_GET = 'v',
SC64_CMD_API_VERSION_GET = 'V', SC64_CMD_VERSION_GET = 'V',
SC64_CMD_CONFIG_GET = 'c', SC64_CMD_CONFIG_GET = 'c',
SC64_CMD_CONFIG_SET = 'C', SC64_CMD_CONFIG_SET = 'C',
SC64_CMD_SETTING_GET = 'a', SC64_CMD_SETTING_GET = 'a',
@ -45,7 +45,6 @@ typedef enum {
SC64_CMD_FLASH_PROGRAM = 'K', 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 = '?',
} cmd_id_t; } cmd_id_t;
typedef enum { typedef enum {
@ -98,8 +97,8 @@ void sc64_lock (void) {
} }
bool sc64_check_presence (void) { bool sc64_check_presence (void) {
uint32_t version = pi_io_read(&SC64_REGS->VERSION); uint32_t identifier = pi_io_read(&SC64_REGS->IDENTIFIER);
if (version == SC64_VERSION_2) { if (identifier == SC64_V2_IDENTIFIER) {
sc64_wait_cpu_busy(); sc64_wait_cpu_busy();
return true; return true;
} }
@ -114,7 +113,7 @@ bool sc64_irq_pending (void) {
} }
void sc64_irq_clear (void) { void sc64_irq_clear (void) {
pi_io_write(&SC64_REGS->VERSION, 0); pi_io_write(&SC64_REGS->IDENTIFIER, 0);
} }
uint32_t sc64_get_config (sc64_cfg_id_t id) { uint32_t sc64_get_config (sc64_cfg_id_t id) {

View File

@ -221,8 +221,8 @@ static bool cfg_set_save_type (save_type_t save_type) {
} }
uint32_t cfg_get_version (void) { uint32_t cfg_get_identifier (void) {
return fpga_reg_get(REG_CFG_VERSION); return fpga_reg_get(REG_CFG_IDENTIFIER);
} }
bool cfg_query (uint32_t *args) { bool cfg_query (uint32_t *args) {
@ -468,11 +468,11 @@ void cfg_process (void) {
switch (cmd) { switch (cmd) {
case 'v': case 'v':
args[0] = cfg_get_version(); args[0] = cfg_get_identifier();
break; break;
case 'V': case 'V':
args[0] = version_api(API_N64); args[0] = version_firmware();
break; break;
case 'c': case 'c':
@ -666,11 +666,6 @@ void cfg_process (void) {
} }
break; break;
case '?':
args[0] = fpga_reg_get(REG_DEBUG_0);
args[1] = fpga_reg_get(REG_DEBUG_1);
break;
default: default:
cfg_set_error(CFG_ERROR_UNKNOWN_CMD); cfg_set_error(CFG_ERROR_UNKNOWN_CMD);
return; return;

View File

@ -16,7 +16,7 @@ typedef enum {
} save_type_t; } save_type_t;
uint32_t cfg_get_version (void); uint32_t cfg_get_identifier (void);
bool cfg_query (uint32_t *args); bool cfg_query (uint32_t *args);
bool cfg_update (uint32_t *args); bool cfg_update (uint32_t *args);
bool cfg_query_setting (uint32_t *args); bool cfg_query_setting (uint32_t *args);

View File

@ -28,7 +28,7 @@ typedef enum {
REG_CFG_DATA_0, REG_CFG_DATA_0,
REG_CFG_DATA_1, REG_CFG_DATA_1,
REG_CFG_CMD, REG_CFG_CMD,
REG_CFG_VERSION, REG_CFG_IDENTIFIER,
REG_FLASHRAM_SCR, REG_FLASHRAM_SCR,
REG_FLASH_SCR, REG_FLASH_SCR,
REG_RTC_SCR, REG_RTC_SCR,

View File

@ -160,14 +160,14 @@ static void usb_rx_process (void) {
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;
p.response_info.data[0] = cfg_get_version(); p.response_info.data[0] = cfg_get_identifier();
break; break;
case 'V': case 'V':
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;
p.response_info.data[0] = version_api(API_USB); p.response_info.data[0] = version_firmware();
break; break;
case 'R': case 'R':
@ -247,12 +247,6 @@ static void usb_rx_process (void) {
} }
break; break;
case 'D':
dd_set_block_ready(p.rx_args[0] == 0);
p.rx_state = RX_STATE_IDLE;
p.response_pending = true;
break;
case 'U': case 'U':
if ((p.read_length > 0) && usb_dma_ready()) { if ((p.read_length > 0) && usb_dma_ready()) {
uint32_t length = (p.read_length > p.rx_args[1]) ? p.rx_args[1] : p.read_length; uint32_t length = (p.read_length > p.rx_args[1]) ? p.rx_args[1] : p.read_length;
@ -274,6 +268,28 @@ static void usb_rx_process (void) {
} }
break; break;
case 'D':
dd_set_block_ready(p.rx_args[0] == 0);
p.rx_state = RX_STATE_IDLE;
p.response_pending = true;
break;
case 'p':
if (p.rx_args[0]) {
flash_wait_busy();
}
p.rx_state = RX_STATE_IDLE;
p.response_pending = true;
p.response_info.data_length = 4;
p.response_info.data[0] = FLASH_ERASE_BLOCK_SIZE;
break;
case 'P':
p.response_error = flash_erase_block(p.rx_args[0]);
p.rx_state = RX_STATE_IDLE;
p.response_pending = true;
break;
case 'f': { case 'f': {
bool rom_write_enable_restore = cfg_set_rom_write_enable(false); bool rom_write_enable_restore = cfg_set_rom_write_enable(false);
p.response_info.data[0] = update_backup(p.rx_args[0], &p.response_info.data[1]); p.response_info.data[0] = update_backup(p.rx_args[0], &p.response_info.data[1]);
@ -300,22 +316,6 @@ static void usb_rx_process (void) {
break; break;
} }
case 'p':
if (p.rx_args[0]) {
flash_wait_busy();
}
p.rx_state = RX_STATE_IDLE;
p.response_pending = true;
p.response_info.data_length = 4;
p.response_info.data[0] = FLASH_ERASE_BLOCK_SIZE;
break;
case 'P':
p.response_error = flash_erase_block(p.rx_args[0]);
p.rx_state = RX_STATE_IDLE;
p.response_pending = true;
break;
case '?': case '?':
p.rx_state = RX_STATE_IDLE; p.rx_state = RX_STATE_IDLE;
p.response_pending = true; p.response_pending = true;

View File

@ -1,17 +1,10 @@
#include "version.h" #include "version.h"
#define VERSION_API_USB (2) #define VERSION_MAJOR (2)
#define VERSION_API_N64 (2) #define VERSION_MINOR (12)
uint32_t version_api (version_api_type_t type) { uint32_t version_firmware (void) {
switch (type) { return ((VERSION_MAJOR << 16) | (VERSION_MINOR));
case API_USB:
return VERSION_API_USB;
case API_N64:
return VERSION_API_N64;
default:
return 0;
}
} }

View File

@ -5,13 +5,7 @@
#include <stdint.h> #include <stdint.h>
typedef enum { uint32_t version_firmware (void);
API_USB,
API_N64,
} version_api_type_t;
uint32_t version_api (version_api_type_t type);
#endif #endif

View File

@ -200,6 +200,7 @@ class SC64:
FLASH = 0x0400_0000 FLASH = 0x0400_0000
BUFFER = 0x0500_0000 BUFFER = 0x0500_0000
EEPROM = 0x0500_2000 EEPROM = 0x0500_2000
END = 0x0500_297F
FIRMWARE = 0x0200_0000 FIRMWARE = 0x0200_0000
DDIPL = 0x03BC_0000 DDIPL = 0x03BC_0000
SAVE = 0x03FE_0000 SAVE = 0x03FE_0000
@ -321,7 +322,8 @@ class SC64:
SCREENSHOT = 4 SCREENSHOT = 4
GDB = 0xDB GDB = 0xDB
__MIN_SUPPORTED_API_VERSION = 2 __SUPPORTED_MAJOR_VERSION = 2
__SUPPORTED_MINOR_VERSION = 12
__isv_line_buffer: bytes = b'' __isv_line_buffer: bytes = b''
__debug_header: Optional[bytes] = None __debug_header: Optional[bytes] = None
@ -329,21 +331,24 @@ class SC64:
def __init__(self) -> None: def __init__(self) -> None:
self.__link = SC64Serial() self.__link = SC64Serial()
version = self.__link.execute_cmd(cmd=b'v') identifier = self.__link.execute_cmd(cmd=b'v')
if (version != b'SCv2'): if (identifier != b'SCv2'):
raise ConnectionException('Unknown SC64 HW version') raise ConnectionException('Unknown SC64 v2 identifier')
def __get_int(self, data: bytes) -> int: def __get_int(self, data: bytes) -> int:
return int.from_bytes(data[:4], byteorder='big') return int.from_bytes(data[:4], byteorder='big')
def check_api_version(self) -> None: def check_firmware_version(self) -> None:
try: try:
data = self.__link.execute_cmd(cmd=b'V') version = self.__link.execute_cmd(cmd=b'V')
major = self.__get_int(version[0:2])
minor = self.__get_int(version[2:4])
if (major != self.__SUPPORTED_MAJOR_VERSION):
raise ConnectionException()
if (minor < self.__SUPPORTED_MINOR_VERSION):
raise ConnectionException()
except ConnectionException: except ConnectionException:
raise ConnectionException('Outdated SC64 API, please update firmware') raise ConnectionException(f'Unsupported SC64 version ({major}.{minor}), please update firmware')
version = self.__get_int(data)
if (version < self.__MIN_SUPPORTED_API_VERSION):
raise ConnectionException('Unsupported SC64 API version, please update firmware')
def __set_config(self, config: __CfgId, value: int) -> None: def __set_config(self, config: __CfgId, value: int) -> None:
try: try:
@ -461,8 +466,10 @@ class SC64:
raise ValueError('Debug data size too big') raise ValueError('Debug data size too big')
self.__link.execute_cmd(cmd=b'U', args=[datatype, len(data)], data=data, response=False) self.__link.execute_cmd(cmd=b'U', args=[datatype, len(data)], data=data, response=False)
def download_memory(self) -> bytes: def download_memory(self, address: int, length: int) -> bytes:
return self.__read_memory(self.__Address.MEMORY, self.__Length.MEMORY) if ((address < 0) or (length < 0) or ((address + length) > self.__Address.END)):
raise ValueError('Invalid address or length')
return self.__read_memory(address, length)
def upload_rom(self, data: bytes, use_shadow: bool=True) -> None: def upload_rom(self, data: bytes, use_shadow: bool=True) -> None:
rom_length = len(data) rom_length = len(data)
@ -582,7 +589,7 @@ class SC64:
raise ConnectionException('Error while getting firmware backup') raise ConnectionException('Error while getting firmware backup')
return self.__read_memory(address, length) return self.__read_memory(address, length)
def set_cic_parameters(self, seed: Optional[int]=None, disabled=False) -> tuple[int, int, bool]: def update_cic_parameters(self, seed: Optional[int]=None, disabled=False) -> tuple[int, int, bool]:
if ((seed != None) and (seed < 0 or seed > 0xFF)): if ((seed != None) and (seed < 0 or seed > 0xFF)):
raise ValueError('CIC seed outside of allowed values') raise ValueError('CIC seed outside of allowed values')
boot_mode = self.__get_config(self.__CfgId.BOOT_MODE) boot_mode = self.__get_config(self.__CfgId.BOOT_MODE)
@ -884,7 +891,7 @@ class SC64:
current_image = 0 current_image = 0
next_image = 0 next_image = 0
self.__set_config(self.__CfgId.ROM_WRITE_ENABLE, isv) self.__set_config(self.__CfgId.ROM_WRITE_ENABLE, 1 if (isv != 0) else 0)
self.__set_config(self.__CfgId.ISV_ADDRESS, isv) self.__set_config(self.__CfgId.ISV_ADDRESS, isv)
if (isv != 0): if (isv != 0):
print(f'IS-Viewer64 support set to [ENABLED] at ROM offset [0x{(isv):08X}]') print(f'IS-Viewer64 support set to [ENABLED] at ROM offset [0x{(isv):08X}]')
@ -992,16 +999,24 @@ if __name__ == '__main__':
disabled = bool(int(params[1])) if len(params) >= 2 else None disabled = bool(int(params[1])) if len(params) >= 2 else None
return (seed, disabled) return (seed, disabled)
def download_memory_type(argument: str):
params = argument.split(',')
if (len(params) < 2 or len(params) > 3):
raise argparse.ArgumentError()
address = int(params[0], 0)
length = int(params[1], 0)
file = params[2] if len(params) >= 3 else 'sc64dump.bin'
return (address, length, file)
parser = argparse.ArgumentParser(description='SC64 control software') parser = argparse.ArgumentParser(description='SC64 control software')
parser.add_argument('--backup-firmware', metavar='file', help='backup SC64 firmware and write it to specified file') parser.add_argument('--backup-firmware', metavar='file', help='backup SC64 firmware and write it to specified file')
parser.add_argument('--update-firmware', metavar='file', help='update SC64 firmware from specified file') parser.add_argument('--update-firmware', metavar='file', help='update SC64 firmware from specified file')
parser.add_argument('--update-bootloader', metavar='file', help='update SC64 bootloader (not recommended, use --update-firmware instead)')
parser.add_argument('--reset-state', action='store_true', help='reset SC64 internal state') parser.add_argument('--reset-state', action='store_true', help='reset SC64 internal state')
parser.add_argument('--print-state', action='store_true', help='print SC64 internal state') parser.add_argument('--print-state', action='store_true', help='print SC64 internal state')
parser.add_argument('--led-enabled', metavar='{true,false}', help='disable or enable LED I/O activity blinking') parser.add_argument('--led-blink', metavar='{yes,no}', help='disable or enable LED I/O activity blinking')
parser.add_argument('--boot', type=SC64.BootMode, action=EnumAction, help='set boot mode') parser.add_argument('--boot', type=SC64.BootMode, action=EnumAction, help='set boot mode')
parser.add_argument('--tv', type=SC64.TVType, action=EnumAction, help='force TV type to set value') parser.add_argument('--tv', type=SC64.TVType, action=EnumAction, help='force TV type to set value, not used when direct boot mode is enabled')
parser.add_argument('--cic', type=SC64.CICSeed, action=EnumAction, help='force CIC seed to set value') parser.add_argument('--cic', type=SC64.CICSeed, action=EnumAction, help='force CIC seed to set value, not used when direct boot mode is enabled')
parser.add_argument('--cic-params', metavar='seed,[disabled]', type=cic_params_type, help='set CIC emulation parameters') parser.add_argument('--cic-params', metavar='seed,[disabled]', type=cic_params_type, help='set CIC emulation parameters')
parser.add_argument('--rtc', action='store_true', help='update clock in SC64 to system time') parser.add_argument('--rtc', action='store_true', help='update clock in SC64 to system time')
parser.add_argument('--no-shadow', action='store_false', help='do not put last 128 kB of ROM inside flash memory (can corrupt non EEPROM saves)') parser.add_argument('--no-shadow', action='store_false', help='do not put last 128 kB of ROM inside flash memory (can corrupt non EEPROM saves)')
@ -1014,7 +1029,7 @@ if __name__ == '__main__':
parser.add_argument('--isv', type=lambda x: int(x, 0), default=0, help='enable IS-Viewer64 support at provided ROM offset') parser.add_argument('--isv', type=lambda x: int(x, 0), default=0, help='enable IS-Viewer64 support at provided ROM offset')
parser.add_argument('--gdb', metavar='port', type=int, help='expose socket port for GDB debugging') parser.add_argument('--gdb', metavar='port', type=int, help='expose socket port for GDB debugging')
parser.add_argument('--debug', action='store_true', help='run debug loop') parser.add_argument('--debug', action='store_true', help='run debug loop')
parser.add_argument('--download-memory', metavar='file', help='download whole memory space and write it to specified file') parser.add_argument('--download-memory', metavar='address,length,[file]', type=download_memory_type, help='download specified memory region and write it to file')
if (len(sys.argv) <= 1): if (len(sys.argv) <= 1):
parser.print_help() parser.print_help()
@ -1039,13 +1054,7 @@ if __name__ == '__main__':
sc64.update_firmware(f.read(), status_callback) sc64.update_firmware(f.read(), status_callback)
print('done') print('done')
sc64.check_api_version() sc64.check_firmware_version()
if (args.update_bootloader):
with open(args.update_bootloader, 'rb') as f:
print('Uploading Bootloader... ', end='', flush=True)
sc64.upload_bootloader(f.read())
print('done')
if (args.reset_state): if (args.reset_state):
sc64.reset_state() sc64.reset_state()
@ -1059,10 +1068,10 @@ if __name__ == '__main__':
value = getattr(value, 'name') value = getattr(value, 'name')
print(f' {key}: {value}') print(f' {key}: {value}')
if (args.led_enabled != None): if (args.led_blink):
value = (args.led_enabled == 'true') blink = (args.led_blink == 'yes')
sc64.set_led_enable(value) sc64.set_led_enable(blink)
print(f'LED blinking set to [{"ENABLED" if value else "DISABLED"}]') print(f'LED blinking set to [{"ENABLED" if blink else "DISABLED"}]')
if (args.tv != None): if (args.tv != None):
sc64.set_tv_type(args.tv) sc64.set_tv_type(args.tv)
@ -1085,6 +1094,12 @@ if __name__ == '__main__':
autodetected_save_type = sc64.autodetect_save_type(rom_data) autodetected_save_type = sc64.autodetect_save_type(rom_data)
print('done') print('done')
if (args.ddipl):
with open(args.ddipl, 'rb') as f:
print('Uploading 64DD IPL... ', end='', flush=True)
sc64.upload_ddipl(f.read())
print('done')
if (args.save_type != None or autodetected_save_type != None): if (args.save_type != None or autodetected_save_type != None):
save_type = args.save_type if args.save_type != None else autodetected_save_type save_type = args.save_type if args.save_type != None else autodetected_save_type
sc64.set_save_type(save_type) sc64.set_save_type(save_type)
@ -1096,26 +1111,20 @@ if __name__ == '__main__':
sc64.upload_save(f.read()) sc64.upload_save(f.read())
print('done') print('done')
if (args.ddipl):
with open(args.ddipl, 'rb') as f:
print('Uploading 64DD IPL... ', end='', flush=True)
sc64.upload_ddipl(f.read())
print('done')
if (args.boot != None): if (args.boot != None):
sc64.set_boot_mode(args.boot) sc64.set_boot_mode(args.boot)
print(f'Boot mode set to [{args.boot.name}]') print(f'Boot mode set to [{args.boot.name}]')
if (args.cic_params != None): if (args.cic_params != None):
(seed, disabled) = args.cic_params (seed, disabled) = args.cic_params
(seed, checksum, dd_mode) = sc64.set_cic_parameters(seed, disabled) (seed, checksum, dd_mode) = sc64.update_cic_parameters(seed, disabled)
print('CIC parameters set to [', end='') print('CIC parameters set to [', end='')
print(f'{"DISABLED" if disabled else "ENABLED"}, ', end='') print(f'{"DISABLED" if disabled else "ENABLED"}, ', end='')
print(f'{"DDIPL" if dd_mode else "ROM"}, ', end='') print(f'{"DDIPL" if dd_mode else "ROM"}, ', end='')
print(f'seed: 0x{seed:02X}, checksum: 0x{checksum:012X}', end='') print(f'seed: 0x{seed:02X}, checksum: 0x{checksum:012X}', end='')
print(']') print(']')
else: else:
sc64.set_cic_parameters() sc64.update_cic_parameters()
if (args.debug or args.isv or args.disk or args.gdb): if (args.debug or args.isv or args.disk or args.gdb):
sc64.debug_loop(isv=args.isv, disks=args.disk, gdb_port=args.gdb) sc64.debug_loop(isv=args.isv, disks=args.disk, gdb_port=args.gdb)
@ -1126,10 +1135,11 @@ if __name__ == '__main__':
f.write(sc64.download_save()) f.write(sc64.download_save())
print('done') print('done')
if (args.download_memory): if (args.download_memory != None):
with open(args.download_memory, 'wb') as f: (address, length, file) = args.download_memory
with open(file, 'wb') as f:
print('Downloading memory... ', end='', flush=True) print('Downloading memory... ', end='', flush=True)
f.write(sc64.download_memory()) f.write(sc64.download_memory(address, length))
print('done') print('done')
except ValueError as e: except ValueError as e:
print(f'\nValue error: {e}') print(f'\nValue error: {e}')