From e93cecfae380cee3caae78d505b7f903a42e6d39 Mon Sep 17 00:00:00 2001 From: Mateusz Faderewski Date: Thu, 11 Apr 2024 01:34:36 +0200 Subject: [PATCH] [SC64][FW][SW] Fixed unreliable CIC boot --- fw/rtl/n64/n64_cic.sv | 38 +++++++---- sw/cic/cic.c | 120 ++++++++++++++++------------------ sw/deployer/src/sc64/types.rs | 6 +- 3 files changed, 85 insertions(+), 79 deletions(-) diff --git a/fw/rtl/n64/n64_cic.sv b/fw/rtl/n64/n64_cic.sv index 356eca0..8452553 100644 --- a/fw/rtl/n64/n64_cic.sv +++ b/fw/rtl/n64/n64_cic.sv @@ -57,18 +57,34 @@ module n64_cic ( logic [7:0] timer_divider; logic [11:0] timer_counter; - logic timer_reset; + logic timer_start; + logic timer_clear; + logic timer_elapsed; + + const bit [11:0] TIMEOUT_500MS = 12'd3815; // (62_500_000 / 32 / 256 / 2) = ~500 ms always_ff @(posedge clk) begin if (si_clk_rising_edge) begin timer_divider <= timer_divider + 1'd1; - if (&timer_divider) begin - timer_counter <= timer_counter + 1'd1; + end + + if (si_clk_rising_edge && (&timer_divider) && (timer_counter > 12'd0)) begin + timer_counter <= timer_counter - 1'd1; + if (timer_counter == 12'd1) begin + timer_elapsed <= 1'b1; end end - if (timer_reset) begin + + if (timer_start) begin + timer_divider <= 8'd0; + timer_counter <= TIMEOUT_500MS; + timer_elapsed <= 1'b0; + end + + if (timer_clear) begin timer_divider <= 8'd0; timer_counter <= 12'd0; + timer_elapsed <= 1'b0; end end @@ -135,7 +151,6 @@ module n64_cic ( always_ff @(posedge clk) begin ram_output <= ram[ram_addr]; - ibus_ack <= ibus_cycle && !ibus_ack; end @@ -147,7 +162,8 @@ module n64_cic ( // Bus controller always_ff @(posedge clk) begin - timer_reset <= 1'b0; + timer_start <= 1'b0; + timer_clear <= 1'b0; n64_scb.cic_invalid_region <= 1'b0; dbus_ack <= dbus_cycle && !dbus_ack; @@ -164,8 +180,9 @@ module n64_cic ( 2'b11: begin case (dbus_addr[3:2]) 2'b10: begin - timer_reset <= dbus_wdata[4]; - n64_scb.cic_invalid_region <= dbus_wdata[3]; + n64_scb.cic_invalid_region <= dbus_wdata[6]; + timer_clear <= dbus_wdata[5]; + timer_start <= dbus_wdata[4]; cic_dq_out <= dbus_wdata[0]; end @@ -207,9 +224,8 @@ module n64_cic ( 2'b01: dbus_rdata = n64_scb.cic_checksum[31:0]; 2'b10: dbus_rdata = { - 4'd0, - timer_counter, - 13'd0, + 28'd0, + timer_elapsed, cic_reset, cic_clk, cic_dq diff --git a/sw/cic/cic.c b/sw/cic/cic.c index 47e1915..69ac53c 100644 --- a/sw/cic/cic.c +++ b/sw/cic/cic.c @@ -36,33 +36,32 @@ typedef struct { #define EXT ((ext_regs_t *) (0xC0000000UL)) -#define CIC_DQ (1 << 0) -#define CIC_CLK (1 << 1) -#define CIC_RESET (1 << 2) -#define CIC_INVALID_REGION (1 << 3) -#define CIC_TIMER_RESET (1 << 4) -#define CIC_TIMER_BIT (16) -#define CIC_TIMER_MASK (0xFFF) +#define CIC_DQ (1 << 0) // IO +#define CIC_CLK (1 << 1) // I +#define CIC_RESET (1 << 2) // I +#define CIC_TIMER_ELAPSED (1 << 3) // I +#define CIC_TIMER_START (1 << 4) // O +#define CIC_TIMER_CLEAR (1 << 5) // O +#define CIC_INVALID_REGION (1 << 6) // O +#define CIC_INIT() { EXT->IO = (CIC_TIMER_CLEAR | CIC_DQ); } #define CIC_IS_RUNNING() (EXT->IO & CIC_RESET) -#define CIC_CLK_WAIT_LOW() { while ((EXT->IO & (CIC_RESET | CIC_CLK)) == (CIC_RESET | CIC_CLK)); } -#define CIC_CLK_WAIT_HIGH() { while ((EXT->IO & (CIC_RESET | CIC_CLK)) == CIC_RESET); } +#define CIC_CLK_WAIT_LOW() { while ((EXT->IO & (CIC_TIMER_ELAPSED | CIC_RESET | CIC_CLK)) == (CIC_RESET | CIC_CLK)); } +#define CIC_CLK_WAIT_HIGH() { while ((EXT->IO & (CIC_TIMER_ELAPSED | CIC_RESET | CIC_CLK)) == CIC_RESET); } +#define CIC_CLK_IS_LOW() ((EXT->IO & (CIC_RESET | CIC_CLK)) == CIC_RESET) #define CIC_DQ_GET() (EXT->IO & CIC_DQ) #define CIC_DQ_SET(v) { EXT->IO = ((v) ? CIC_DQ : 0); } -#define CIC_CLK_GET() (EXT->IO & (CIC_RESET | CIC_CLK)) #define CIC_NOTIFY_INVALID_REGION() { EXT->IO = (CIC_INVALID_REGION | CIC_DQ); } -#define CIC_TIMEOUT_START() { EXT->IO = (CIC_TIMER_RESET | CIC_DQ); } -#define CIC_TIMEOUT_GET() ((EXT->IO >> CIC_TIMER_BIT) & CIC_TIMER_MASK) +#define CIC_TIMEOUT_START() { EXT->IO = (CIC_TIMER_START | CIC_DQ); } +#define CIC_TIMEOUT_STOP() { EXT->IO = (CIC_TIMER_CLEAR | CIC_DQ); } +#define CIC_TIMEOUT_ELAPSED() (EXT->IO & CIC_TIMER_ELAPSED) +#define CIC_SET_STEP(v) { EXT->DEBUG = (v); } -#define CIC_TIMER_MS_TO_TICKS(ms) ((((62500000 / 32) / 256) * (ms)) / 1000) - -#define CIC_TIMEOUT_INVALID_REGION CIC_TIMER_MS_TO_TICKS(100) -#define CIC_TIMEOUT_SOFT_RESET CIC_TIMER_MS_TO_TICKS(500) typedef enum { CIC_STEP_UNAVAILABLE = 0, CIC_STEP_POWER_OFF = 1, - CIC_STEP_INIT = 2, + CIC_STEP_CONFIG_LOAD = 2, CIC_STEP_ID = 3, CIC_STEP_SEED = 4, CIC_STEP_CHECKSUM = 5, @@ -77,7 +76,6 @@ typedef enum { CIC_STEP_DIE_COMMAND = 14, } cic_step_t; - typedef struct { bool cic_disabled; bool cic_64dd_mode; @@ -88,8 +86,6 @@ typedef struct { static cic_config_t config; -static uint16_t timeout; - static uint8_t cic_ram[32]; static uint8_t cic_x105_ram[30]; @@ -100,30 +96,16 @@ static const uint8_t cic_ram_init[2][16] = {{ }}; -static void cic_set_step (cic_step_t step) { - EXT->DEBUG = step; -} - -static void cic_timeout_start (uint16_t timeout_ticks) { - CIC_TIMEOUT_START(); - timeout = timeout_ticks; -} - -static bool cic_timeout_elapsed (void) { - return (CIC_TIMEOUT_GET() >= timeout); -} - -static void cic_die (cic_step_t reason) { - cic_set_step(reason); +static void cic_die (void) { while (CIC_IS_RUNNING()); } static void cic_wait_power_on (void) { - CIC_DQ_SET(1); + CIC_INIT(); while (!CIC_IS_RUNNING()); } -static void cic_init (void) { +static void cic_load_config (void) { uint32_t cic_config[2]; cic_config[0] = EXT->CIC_CONFIG[0]; @@ -141,7 +123,8 @@ static void cic_init (void) { config.cic_checksum[5] = (cic_config[1] & 0xFF); if (config.cic_disabled) { - cic_die(CIC_STEP_DIE_DISABLED); + CIC_SET_STEP(CIC_STEP_DIE_DISABLED); + cic_die(); } } @@ -192,9 +175,10 @@ static void cic_encode_round (uint8_t index) { static void cic_write_id (void) { if (config.cic_64dd_mode) { CIC_CLK_WAIT_LOW(); - while (CIC_CLK_GET() == CIC_RESET) { + while (CIC_CLK_IS_LOW()) { if (!CIC_DQ_GET()) { - cic_die(CIC_STEP_DIE_64DD); + CIC_SET_STEP(CIC_STEP_DIE_64DD); + cic_die(); } } } else { @@ -215,16 +199,17 @@ static void cic_write_seed (void) { cic_encode_round(0x0A); cic_encode_round(0x0A); - cic_timeout_start(CIC_TIMEOUT_INVALID_REGION); - - while (CIC_CLK_GET() == (CIC_RESET | CIC_CLK)) { - if (cic_timeout_elapsed()) { - CIC_NOTIFY_INVALID_REGION(); - cic_die(CIC_STEP_DIE_INVALID_REGION); - } - } + CIC_TIMEOUT_START(); cic_write_ram_nibbles(0x0A); + + if (CIC_TIMEOUT_ELAPSED()) { + CIC_NOTIFY_INVALID_REGION(); + CIC_SET_STEP(CIC_STEP_DIE_INVALID_REGION); + cic_die(); + } + + CIC_TIMEOUT_STOP(); } static void cic_write_checksum (void) { @@ -232,14 +217,15 @@ static void cic_write_checksum (void) { cic_ram[i] = 0x00; } for (int i = 0; i < 6; i++) { - cic_ram[(i * 2) + 4] = ((config.cic_checksum[i] >> 4) & 0x0F); - cic_ram[(i * 2) + 5] = (config.cic_checksum[i] & 0x0F); + uint8_t value = config.cic_checksum[i]; + cic_ram[(i * 2) + 4] = ((value >> 4) & 0x0F); + cic_ram[(i * 2) + 5] = (value & 0x0F); } cic_encode_round(0x00); cic_encode_round(0x00); cic_encode_round(0x00); cic_encode_round(0x00); - cic_write(0); + cic_read(); cic_write_ram_nibbles(0x00); } @@ -374,49 +360,53 @@ static void cic_x105_mode (void) { static void cic_soft_reset (void) { CIC_CLK_WAIT_LOW(); - cic_timeout_start(CIC_TIMEOUT_SOFT_RESET); - while ((!cic_timeout_elapsed()) && CIC_IS_RUNNING()); + + CIC_TIMEOUT_START(); + while ((!CIC_TIMEOUT_ELAPSED()) && CIC_IS_RUNNING()); + CIC_TIMEOUT_STOP(); + cic_write(0); } __attribute__((naked)) void cic_main (void) { while (true) { - cic_set_step(CIC_STEP_POWER_OFF); + CIC_SET_STEP(CIC_STEP_POWER_OFF); cic_wait_power_on(); - cic_set_step(CIC_STEP_INIT); - cic_init(); + CIC_SET_STEP(CIC_STEP_CONFIG_LOAD); + cic_load_config(); - cic_set_step(CIC_STEP_ID); + CIC_SET_STEP(CIC_STEP_ID); cic_write_id(); - cic_set_step(CIC_STEP_SEED); + CIC_SET_STEP(CIC_STEP_SEED); cic_write_seed(); - cic_set_step(CIC_STEP_CHECKSUM); + CIC_SET_STEP(CIC_STEP_CHECKSUM); cic_write_checksum(); - cic_set_step(CIC_STEP_INIT_RAM); + CIC_SET_STEP(CIC_STEP_INIT_RAM); cic_init_ram(); while (CIC_IS_RUNNING()) { - cic_set_step(CIC_STEP_COMMAND); + CIC_SET_STEP(CIC_STEP_COMMAND); uint8_t cmd = 0; cmd |= (cic_read() << 1); cmd |= cic_read(); if (cmd == 0) { - cic_set_step(CIC_STEP_COMPARE); + CIC_SET_STEP(CIC_STEP_COMPARE); cic_compare_mode(); } else if (cmd == 2) { - cic_set_step(CIC_STEP_X105); + CIC_SET_STEP(CIC_STEP_X105); cic_x105_mode(); } else if (cmd == 3) { - cic_set_step(CIC_STEP_RESET_BUTTON); + CIC_SET_STEP(CIC_STEP_RESET_BUTTON); cic_soft_reset(); } else { - cic_die(CIC_STEP_DIE_COMMAND); + CIC_SET_STEP(CIC_STEP_DIE_COMMAND); + cic_die(); } } } diff --git a/sw/deployer/src/sc64/types.rs b/sw/deployer/src/sc64/types.rs index 46cf00d..331df85 100644 --- a/sw/deployer/src/sc64/types.rs +++ b/sw/deployer/src/sc64/types.rs @@ -785,7 +785,7 @@ impl TryFrom for UpdateStatus { pub enum CicStep { Unavailable, PowerOff, - Init, + ConfigLoad, Id, Seed, Checksum, @@ -806,7 +806,7 @@ impl Display for CicStep { f.write_str(match self { Self::Unavailable => "Unavailable", Self::PowerOff => "Power off", - Self::Init => "Initialize", + Self::ConfigLoad => "Load config", Self::Id => "ID", Self::Seed => "Seed", Self::Checksum => "Checksum", @@ -830,7 +830,7 @@ impl TryFrom for CicStep { Ok(match value { 0 => Self::Unavailable, 1 => Self::PowerOff, - 2 => Self::Init, + 2 => Self::ConfigLoad, 3 => Self::Id, 4 => Self::Seed, 5 => Self::Checksum,