mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-21 21:49:15 +01:00
[SC64][FW][SW] Fixed unreliable CIC boot
This commit is contained in:
parent
0150060f1e
commit
e93cecfae3
@ -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
|
||||
|
120
sw/cic/cic.c
120
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -785,7 +785,7 @@ impl TryFrom<u32> 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<u8> 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,
|
||||
|
Loading…
Reference in New Issue
Block a user