From f6b94aec97ba948dac7ff30a51811ecb9936040a Mon Sep 17 00:00:00 2001 From: Mateusz Faderewski Date: Wed, 10 Apr 2024 12:56:05 +0200 Subject: [PATCH] [SC64][FW][SW] Added CIC diagnostic, changed software timeout timer to hardware (derived from PIF clock) --- fw/rtl/mcu/mcu_top.sv | 3 +- fw/rtl/n64/n64_cic.sv | 60 ++++++++++++++++- fw/rtl/n64/n64_scb.sv | 5 +- fw/rtl/n64/n64_top.sv | 3 +- sw/cic/cic.c | 122 ++++++++++++++++++++++++++-------- sw/deployer/src/sc64/types.rs | 70 +++++++++++++++++++ 6 files changed, 229 insertions(+), 34 deletions(-) diff --git a/fw/rtl/mcu/mcu_top.sv b/fw/rtl/mcu/mcu_top.sv index 683b252..139fa62 100644 --- a/fw/rtl/mcu/mcu_top.sv +++ b/fw/rtl/mcu/mcu_top.sv @@ -649,7 +649,8 @@ module mcu_top ( REG_DEBUG_1: begin reg_rdata <= { - 28'd0, + 24'd0, + n64_scb.cic_debug, n64_scb.pi_debug[35:32] }; end diff --git a/fw/rtl/n64/n64_cic.sv b/fw/rtl/n64/n64_cic.sv index e76ff6c..356eca0 100644 --- a/fw/rtl/n64/n64_cic.sv +++ b/fw/rtl/n64/n64_cic.sv @@ -6,7 +6,8 @@ module n64_cic ( input n64_reset, input n64_cic_clk, - inout n64_cic_dq + inout n64_cic_dq, + input n64_si_clk ); // Input/output synchronization @@ -14,21 +15,25 @@ module n64_cic ( logic [1:0] n64_reset_ff; logic [1:0] n64_cic_clk_ff; logic [1:0] n64_cic_dq_ff; + logic [1:0] n64_si_clk_ff; always_ff @(posedge clk) begin n64_reset_ff <= {n64_reset_ff[0], n64_reset}; n64_cic_clk_ff <= {n64_cic_clk_ff[0], n64_cic_clk}; n64_cic_dq_ff <= {n64_cic_dq_ff[0], n64_cic_dq}; + n64_si_clk_ff <= {n64_si_clk_ff[0], n64_si_clk}; end logic cic_reset; logic cic_clk; logic cic_dq; + logic si_clk; always_comb begin cic_reset = n64_reset_ff[1]; cic_clk = n64_cic_clk_ff[1]; cic_dq = n64_cic_dq_ff[1]; + si_clk = n64_si_clk_ff[1]; end logic cic_dq_out; @@ -36,6 +41,38 @@ module n64_cic ( assign n64_cic_dq = cic_dq_out ? 1'bZ : 1'b0; + // Timer (divider and counter) + + logic last_si_clk; + + always_ff @(posedge clk) begin + last_si_clk <= si_clk; + end + + logic si_clk_rising_edge; + + always_comb begin + si_clk_rising_edge = cic_reset && !last_si_clk && si_clk; + end + + logic [7:0] timer_divider; + logic [11:0] timer_counter; + logic timer_reset; + + 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 + end + if (timer_reset) begin + timer_divider <= 8'd0; + timer_counter <= 12'd0; + end + end + + // SERV RISC-V CPU logic [31:0] ibus_addr; @@ -110,6 +147,7 @@ module n64_cic ( // Bus controller always_ff @(posedge clk) begin + timer_reset <= 1'b0; n64_scb.cic_invalid_region <= 1'b0; dbus_ack <= dbus_cycle && !dbus_ack; @@ -126,14 +164,23 @@ 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]; cic_dq_out <= dbus_wdata[0]; end + + 2'b11: begin + n64_scb.cic_debug <= dbus_wdata[3:0]; + end endcase end endcase end + if (reset) begin + n64_scb.cic_debug <= 3'd0; + end + if (reset || !cic_reset) begin cic_dq_out <= 1'b1; end @@ -159,7 +206,16 @@ module n64_cic ( 2'b01: dbus_rdata = n64_scb.cic_checksum[31:0]; - 2'b10: dbus_rdata = {29'd0, cic_reset, cic_clk, cic_dq}; + 2'b10: dbus_rdata = { + 4'd0, + timer_counter, + 13'd0, + cic_reset, + cic_clk, + cic_dq + }; + + 2'b11: dbus_rdata = {28'd0, n64_scb.cic_debug}; endcase end endcase diff --git a/fw/rtl/n64/n64_scb.sv b/fw/rtl/n64/n64_scb.sv index f1afa4a..1fecb12 100644 --- a/fw/rtl/n64/n64_scb.sv +++ b/fw/rtl/n64/n64_scb.sv @@ -61,6 +61,7 @@ interface n64_scb (); logic cic_region; logic [7:0] cic_seed; logic [47:0] cic_checksum; + logic [3:0] cic_debug; logic pi_sdram_active; logic pi_flash_active; @@ -111,6 +112,7 @@ interface n64_scb (); output cic_region, output cic_seed, output cic_checksum, + input cic_debug, input pi_debug ); @@ -225,7 +227,8 @@ interface n64_scb (); input cic_64dd_mode, input cic_region, input cic_seed, - input cic_checksum + input cic_checksum, + output cic_debug ); modport arbiter ( diff --git a/fw/rtl/n64/n64_top.sv b/fw/rtl/n64/n64_top.sv index 42b4eae..e0e75e9 100644 --- a/fw/rtl/n64/n64_top.sv +++ b/fw/rtl/n64/n64_top.sv @@ -112,7 +112,8 @@ module n64_top ( .n64_reset(n64_reset), .n64_cic_clk(n64_cic_clk), - .n64_cic_dq(n64_cic_dq) + .n64_cic_dq(n64_cic_dq), + .n64_si_clk(n64_si_clk) ); endmodule diff --git a/sw/cic/cic.c b/sw/cic/cic.c index 3ae6d19..44a9143 100644 --- a/sw/cic/cic.c +++ b/sw/cic/cic.c @@ -3,7 +3,7 @@ // MIT License // Copyright (c) 2019 Jan Goldacker -// Copyright (c) 2022-2023 Mateusz Faderewski +// Copyright (c) 2022-2024 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 @@ -30,7 +30,8 @@ typedef struct { volatile uint32_t CIC_CONFIG[2]; - volatile uint32_t GPIO; + volatile uint32_t IO; + volatile uint32_t DEBUG; } ext_regs_t; #define EXT ((ext_regs_t *) (0xC0000000UL)) @@ -39,14 +40,42 @@ typedef struct { #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_IS_RUNNING() (EXT->GPIO & CIC_RESET) -#define CIC_CLK_WAIT_LOW() { while ((EXT->GPIO & (CIC_RESET | CIC_CLK)) == (CIC_RESET | CIC_CLK)); } -#define CIC_CLK_WAIT_HIGH() { while ((EXT->GPIO & (CIC_RESET | CIC_CLK)) == CIC_RESET); } -#define CIC_DQ_GET() (EXT->GPIO & CIC_DQ) -#define CIC_DQ_SET(v) { EXT->GPIO = ((v) ? CIC_DQ : 0); } -#define CIC_CLK_GET() (EXT->GPIO & (CIC_RESET | CIC_CLK)) -#define CIC_NOTIFY_INVALID_REGION() { EXT->GPIO = (CIC_INVALID_REGION | 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_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_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_UNINITIALIZED = 0, + CIC_STEP_POWER_OFF = 1, + CIC_STEP_INIT = 2, + CIC_STEP_ID = 3, + CIC_STEP_SEED = 4, + CIC_STEP_CHECKSUM = 5, + CIC_STEP_INIT_RAM = 6, + CIC_STEP_COMMAND = 7, + CIC_STEP_COMPARE = 8, + CIC_STEP_X105 = 9, + CIC_STEP_RESET_BUTTON = 10, + CIC_STEP_DIE_DISABLED = 11, + CIC_STEP_DIE_64DD = 12, + CIC_STEP_DIE_INVALID_REGION = 13, + CIC_STEP_DIE_COMMAND = 14, +} cic_step_t; typedef struct { @@ -59,27 +88,44 @@ typedef struct { static cic_config_t config; +static uint16_t timeout; + static uint8_t cic_ram[32]; static uint8_t cic_x105_ram[30]; -static const uint8_t cic_ram_init[2][32] = {{ - 0xE, 0x0, 0x9, 0xA, 0x1, 0x8, 0x5, 0xA, 0x1, 0x3, 0xE, 0x1, 0x0, 0xD, 0xE, 0xC, - 0x0, 0xB, 0x1, 0x4, 0xF, 0x8, 0xB, 0x5, 0x7, 0xC, 0xD, 0x6, 0x1, 0xE, 0x9, 0x8 +static const uint8_t cic_ram_init[2][16] = {{ + 0xE0, 0x9A, 0x18, 0x5A, 0x13, 0xE1, 0x0D, 0xEC, + 0x0B, 0x14, 0xF8, 0xB5, 0x7C, 0xD6, 0x1E, 0x98 }, { - 0xE, 0x0, 0x4, 0xF, 0x5, 0x1, 0x2, 0x1, 0x7, 0x1, 0x9, 0x8, 0x5, 0x7, 0x5, 0xA, - 0x0, 0xB, 0x1, 0x2, 0x3, 0xF, 0x8, 0x2, 0x7, 0x1, 0x9, 0x8, 0x1, 0x1, 0x5, 0xC + 0xE0, 0x4F, 0x51, 0x21, 0x71, 0x98, 0x57, 0x5A, + 0x0B, 0x12, 0x3F, 0x82, 0x71, 0x98, 0x11, 0x5C }}; -static void cic_die (void) { +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); while (CIC_IS_RUNNING()); } -static void cic_init (void) { +static void cic_wait_power_on (void) { CIC_DQ_SET(1); - while (!CIC_IS_RUNNING()); +} +static void cic_init (void) { uint32_t cic_config[2]; cic_config[0] = EXT->CIC_CONFIG[0]; @@ -97,7 +143,7 @@ static void cic_init (void) { config.cic_checksum[5] = (cic_config[1] & 0xFF); if (config.cic_disabled) { - cic_die(); + cic_die(CIC_STEP_DIE_DISABLED); } } @@ -150,7 +196,7 @@ static void cic_write_id (void) { CIC_CLK_WAIT_LOW(); while (CIC_CLK_GET() == CIC_RESET) { if (!CIC_DQ_GET()) { - cic_die(); + cic_die(CIC_STEP_DIE_64DD); } } } else { @@ -171,13 +217,14 @@ static void cic_write_seed (void) { cic_encode_round(0x0A); cic_encode_round(0x0A); - uint32_t timeout = 10000; - do { - if (timeout == 0) { + 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_die(CIC_STEP_DIE_INVALID_REGION); } - } while (timeout-- && (CIC_CLK_GET() == (CIC_RESET | CIC_CLK))); + } cic_write_ram_nibbles(0x0A); } @@ -199,8 +246,10 @@ static void cic_write_checksum (void) { } static void cic_init_ram (void) { - for (int i = 0; i < 32; i++) { - cic_ram[i] = cic_ram_init[config.cic_region ? 1 : 0][i]; + for (int i = 0; i < 32; i += 2) { + uint8_t value = cic_ram_init[config.cic_region ? 1 : 0][i / 2]; + cic_ram[i] = ((value >> 4) & 0x0F); + cic_ram[i + 1] = (value & 0x0F); } cic_ram[0x01] = cic_read_nibble(); cic_ram[0x11] = cic_read_nibble(); @@ -326,35 +375,50 @@ static void cic_x105_mode (void) { } static void cic_soft_reset (void) { - volatile uint32_t timeout = 119050; // ~500 ms delay, measured on real hardware CIC_CLK_WAIT_LOW(); - while ((timeout--) && CIC_IS_RUNNING()); + cic_timeout_start(CIC_TIMEOUT_SOFT_RESET); + while ((!cic_timeout_elapsed()) && CIC_IS_RUNNING()); cic_write(0); } __attribute__((naked)) void cic_main (void) { while (true) { + cic_set_step(CIC_STEP_POWER_OFF); + cic_wait_power_on(); + + cic_set_step(CIC_STEP_INIT); cic_init(); + cic_set_step(CIC_STEP_ID); cic_write_id(); + + cic_set_step(CIC_STEP_SEED); cic_write_seed(); + + cic_set_step(CIC_STEP_CHECKSUM); cic_write_checksum(); + + cic_set_step(CIC_STEP_INIT_RAM); cic_init_ram(); while (CIC_IS_RUNNING()) { + 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_compare_mode(); } else if (cmd == 2) { + cic_set_step(CIC_STEP_X105); cic_x105_mode(); } else if (cmd == 3) { + cic_set_step(CIC_STEP_RESET_BUTTON); cic_soft_reset(); } else { - cic_die(); + cic_die(CIC_STEP_DIE_COMMAND); } } } diff --git a/sw/deployer/src/sc64/types.rs b/sw/deployer/src/sc64/types.rs index 58ffc59..7f4bd59 100644 --- a/sw/deployer/src/sc64/types.rs +++ b/sw/deployer/src/sc64/types.rs @@ -782,12 +782,79 @@ impl TryFrom for UpdateStatus { } } +pub enum CicStep { + Uninitialized, + PowerOff, + Init, + Id, + Seed, + Checksum, + InitRam, + Command, + Compare, + X105, + ResetButton, + DieDisabled, + Die64DD, + DieInvalidRegion, + DieCommand, + Unknown, +} + +impl Display for CicStep { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(match self { + Self::Uninitialized => "Uninitialized", + Self::PowerOff => "Power off", + Self::Init => "Initialize", + Self::Id => "ID", + Self::Seed => "Seed", + Self::Checksum => "Checksum", + Self::InitRam => "RAM init", + Self::Command => "Command wait", + Self::Compare => "Compare algorithm", + Self::X105 => "X105 algorithm", + Self::ResetButton => "Reset button pressed", + Self::DieDisabled => "Die (disabled)", + Self::Die64DD => "Die (found another CIC in 64DD mode)", + Self::DieInvalidRegion => "Die (invalid region)", + Self::DieCommand => "Die (triggered by command)", + Self::Unknown => "Unknown", + }) + } +} + +impl TryFrom for CicStep { + type Error = Error; + fn try_from(value: u8) -> Result { + Ok(match value { + 0 => Self::Uninitialized, + 1 => Self::PowerOff, + 2 => Self::Init, + 3 => Self::Id, + 4 => Self::Seed, + 5 => Self::Checksum, + 6 => Self::InitRam, + 7 => Self::Command, + 8 => Self::Compare, + 9 => Self::X105, + 10 => Self::ResetButton, + 11 => Self::DieDisabled, + 12 => Self::Die64DD, + 13 => Self::DieInvalidRegion, + 14 => Self::DieCommand, + _ => Self::Unknown + }) + } +} + pub struct FpgaDebugData { pub last_pi_address: u32, pub read_fifo_wait: bool, pub read_fifo_failure: bool, pub write_fifo_wait: bool, pub write_fifo_failure: bool, + pub cic_step: CicStep, } impl TryFrom> for FpgaDebugData { @@ -802,6 +869,7 @@ impl TryFrom> for FpgaDebugData { read_fifo_failure: (value[7] & (1 << 1)) != 0, write_fifo_wait: (value[7] & (1 << 2)) != 0, write_fifo_failure: (value[7] & (1 << 3)) != 0, + cic_step: ((value[7] >> 4) & 0xF).try_into().unwrap(), }) } } @@ -824,6 +892,8 @@ impl Display for FpgaDebugData { if self.write_fifo_failure { f.write_str(" WF")?; } + f.write_str(" / ")?; + f.write_fmt(format_args!("CIC step: {}", self.cic_step))?; Ok(()) } }