From 321f3d37aa041a0c9465f596489b6de43149cfbe Mon Sep 17 00:00:00 2001 From: Polprzewodnikowy Date: Thu, 8 Sep 2022 23:36:46 +0200 Subject: [PATCH] preliminary sd card support --- fw/project/lcmxo2/.gitignore | 1 + fw/project/lcmxo2/sc64.ldf | 8 +- fw/rtl/mcu/mcu_top.sv | 100 +++++++++-- fw/rtl/memory/memory_dma.sv | 1 + fw/rtl/n64/n64_cfg.sv | 3 +- fw/rtl/n64/n64_top.sv | 7 +- fw/rtl/sd/sd_cmd.sv | 218 ++++++++++++++++++++++- fw/rtl/sd/sd_crc_16.sv | 33 ++++ fw/rtl/sd/sd_dat.sv | 246 ++++++++++++++++++++++++++ fw/rtl/sd/sd_scb.sv | 74 +++++++- fw/rtl/sd/sd_top.sv | 16 +- fw/rtl/usb/usb_ft1248.sv | 18 +- fw/rtl/vendor/lcmxo2/fifo_8kb.sv | 18 +- sw/bootloader/src/fatfs/diskio.c | 60 +++++-- sw/bootloader/src/io.h | 1 + sw/bootloader/src/sc64.c | 20 +++ sw/bootloader/src/sc64.h | 2 + sw/bootloader/src/storage.c | 2 + sw/controller/app.mk | 1 + sw/controller/src/app.c | 2 +- sw/controller/src/button.c | 4 +- sw/controller/src/cfg.c | 30 +++- sw/controller/src/fpga.h | 43 ++++- sw/controller/src/gvr.c | 3 + sw/controller/src/sd.c | 285 +++++++++++++++++++++++++++++++ sw/controller/src/sd.h | 14 ++ sw/pc/.gitignore | 11 +- sw/pc/sc64.py | 12 ++ 28 files changed, 1161 insertions(+), 72 deletions(-) create mode 100644 fw/rtl/sd/sd_crc_16.sv create mode 100644 fw/rtl/sd/sd_dat.sv create mode 100644 sw/controller/src/sd.c create mode 100644 sw/controller/src/sd.h diff --git a/fw/project/lcmxo2/.gitignore b/fw/project/lcmxo2/.gitignore index c5bd274..aa4d819 100644 --- a/fw/project/lcmxo2/.gitignore +++ b/fw/project/lcmxo2/.gitignore @@ -1,6 +1,7 @@ .recovery *.dir/ *.ccl +*.dmp *.html *.ini *.rva diff --git a/fw/project/lcmxo2/sc64.ldf b/fw/project/lcmxo2/sc64.ldf index 9bdab48..d9473c2 100644 --- a/fw/project/lcmxo2/sc64.ldf +++ b/fw/project/lcmxo2/sc64.ldf @@ -66,7 +66,13 @@ - + + + + + + + diff --git a/fw/rtl/mcu/mcu_top.sv b/fw/rtl/mcu/mcu_top.sv index bf1b9a1..11ef5cc 100644 --- a/fw/rtl/mcu/mcu_top.sv +++ b/fw/rtl/mcu/mcu_top.sv @@ -322,7 +322,6 @@ module mcu_top ( // Register list typedef enum bit [7:0] { - REG_STATUS, REG_MEM_ADDRESS, REG_MEM_SCR, REG_USB_SCR, @@ -373,15 +372,6 @@ module mcu_top ( reg_rdata <= 32'd0; case (address) - REG_STATUS: begin - reg_rdata <= { - 29'd0, - n64_scb.cfg_pending, - ~sd_det_ff[2], - ~button_ff[2] - }; - end - REG_MEM_ADDRESS: begin reg_rdata <= mem_address; end @@ -396,7 +386,10 @@ module mcu_top ( REG_USB_SCR: begin reg_rdata <= { - 28'd0, + 4'd0, + usb_scb.tx_count, + usb_scb.rx_count, + 2'b00, usb_scb.reset_pending, ~fifo_bus.tx_full, ~fifo_bus.rx_empty, @@ -429,7 +422,8 @@ module mcu_top ( REG_CFG_SCR: begin reg_rdata <= { - 20'd0, + ~button_ff[2], + 19'd0, n64_scb.rom_extended_enabled, n64_scb.eeprom_16k_mode, n64_scb.eeprom_enabled, @@ -455,7 +449,8 @@ module mcu_top ( REG_CFG_CMD: begin reg_rdata <= { - 24'd0, + 23'd0, + n64_scb.cfg_pending, n64_scb.cfg_cmd }; end @@ -510,11 +505,57 @@ module mcu_top ( REG_SD_SCR: begin reg_rdata <= { - 30'd0, + 4'd0, + sd_scb.tx_count, + sd_scb.rx_count, + ~sd_det_ff[2], + sd_scb.card_busy, + sd_scb.cmd_error, + sd_scb.cmd_busy, sd_scb.clock_mode }; end + REG_SD_ARG: begin + reg_rdata <= sd_scb.cmd_arg; + end + + REG_SD_CMD: begin + reg_rdata <= { + 22'd0, + sd_scb.cmd_ignore_crc, + sd_scb.cmd_long_response, + sd_scb.cmd_reserved_response, + sd_scb.cmd_skip_response, + sd_scb.cmd_index + }; + end + + REG_SD_RSP_0: begin + reg_rdata <= sd_scb.cmd_rsp[31:0]; + end + + REG_SD_RSP_1: begin + reg_rdata <= sd_scb.cmd_rsp[63:32]; + end + + REG_SD_RSP_2: begin + reg_rdata <= sd_scb.cmd_rsp[95:64]; + end + + REG_SD_RSP_3: begin + reg_rdata <= sd_scb.cmd_rsp[127:96]; + end + + REG_SD_DAT: begin + reg_rdata <= { + 18'd0, + sd_scb.dat_error, + sd_scb.dat_busy, + 12'd0 + }; + end + REG_SD_DMA_ADDRESS: begin reg_rdata <= { 5'd0, @@ -604,6 +645,12 @@ module mcu_top ( usb_dma_scb.start <= 1'b0; usb_dma_scb.stop <= 1'b0; + sd_scb.cmd_start <= 1'b0; + sd_scb.dat_fifo_flush <= 1'b0; + sd_scb.dat_start_write <= 1'b0; + sd_scb.dat_start_read <= 1'b0; + sd_scb.dat_stop <= 1'b0; + sd_dma_scb.start <= 1'b0; sd_dma_scb.stop <= 1'b0; @@ -656,8 +703,6 @@ module mcu_top ( n64_scb.rtc_wdata_valid <= 1'b0; end else if (reg_write) begin case (address) - REG_STATUS: begin end - REG_MEM_ADDRESS: begin mem_address <= reg_wdata; end @@ -725,7 +770,7 @@ module mcu_top ( n64_scb.cfg_irq, n64_scb.cfg_error, n64_scb.cfg_done - } <= reg_wdata[2:0]; + } <= reg_wdata[11:9]; end REG_FLASHRAM_SCR: begin @@ -760,6 +805,27 @@ module mcu_top ( sd_scb.clock_mode <= reg_wdata[1:0]; end + REG_SD_ARG: begin + sd_scb.cmd_arg <= reg_wdata; + end + + REG_SD_CMD: begin + sd_scb.cmd_start <= 1'b1; + sd_scb.cmd_ignore_crc <= reg_wdata[9]; + sd_scb.cmd_long_response <= reg_wdata[8]; + sd_scb.cmd_reserved_response <= reg_wdata[7]; + sd_scb.cmd_skip_response <= reg_wdata[6]; + sd_scb.cmd_index <= reg_wdata[5:0]; + end + + REG_SD_DAT: begin + sd_scb.dat_blocks <= reg_wdata[11:4]; + sd_scb.dat_stop <= reg_wdata[3]; + sd_scb.dat_start_read <= reg_wdata[2]; + sd_scb.dat_start_write <= reg_wdata[1]; + sd_scb.dat_fifo_flush <= reg_wdata[0]; + end + REG_SD_DMA_ADDRESS: begin sd_dma_scb.starting_address <= reg_wdata[26:0]; end diff --git a/fw/rtl/memory/memory_dma.sv b/fw/rtl/memory/memory_dma.sv index 0d7761d..fcba0bd 100644 --- a/fw/rtl/memory/memory_dma.sv +++ b/fw/rtl/memory/memory_dma.sv @@ -76,6 +76,7 @@ module memory_dma ( always_ff @(posedge clk) begin rx_rdata_pop <= ( !rx_rdata_pop && + !fifo_bus.rx_read && trx_enabled && rx_buffer_counter < 2'd2 && !fifo_bus.rx_empty && diff --git a/fw/rtl/n64/n64_cfg.sv b/fw/rtl/n64/n64_cfg.sv index 70dd91f..0c687b2 100644 --- a/fw/rtl/n64/n64_cfg.sv +++ b/fw/rtl/n64/n64_cfg.sv @@ -31,7 +31,8 @@ module n64_cfg ( REG_STATUS: reg_bus.rdata = { n64_scb.cfg_pending, cfg_error, - 14'd0 + irq, + 13'd0 }; REG_COMMAND: reg_bus.rdata = {8'd0, n64_scb.cfg_cmd}; REG_DATA_0_H: reg_bus.rdata = n64_scb.cfg_wdata[0][31:16]; diff --git a/fw/rtl/n64/n64_top.sv b/fw/rtl/n64/n64_top.sv index c63eafc..0191115 100644 --- a/fw/rtl/n64/n64_top.sv +++ b/fw/rtl/n64/n64_top.sv @@ -23,8 +23,13 @@ module n64_top ( logic n64_dd_irq; logic n64_cfg_irq; + logic n64_irq_oe; - assign n64_irq = (n64_dd_irq || n64_cfg_irq) ? 1'b0 : 1'bZ; + always @(posedge clk) begin + n64_irq_oe <= (n64_dd_irq || n64_cfg_irq); + end + + assign n64_irq = n64_irq_oe ? 1'b0 : 1'bZ; n64_reg_bus reg_bus (); diff --git a/fw/rtl/sd/sd_cmd.sv b/fw/rtl/sd/sd_cmd.sv index 661102f..e668c5c 100644 --- a/fw/rtl/sd/sd_cmd.sv +++ b/fw/rtl/sd/sd_cmd.sv @@ -10,6 +10,222 @@ module sd_cmd ( inout sd_cmd ); - assign sd_cmd = 1'bZ; + // Input and output data sampling + + logic sd_cmd_oe; + logic sd_cmd_out; + logic sd_cmd_in; + logic sd_cmd_oe_data; + logic sd_cmd_data; + + assign sd_cmd = sd_cmd_oe ? sd_cmd_out : 1'bZ; + + always_ff @(posedge clk) begin + sd_cmd_oe <= sd_cmd_oe_data; + sd_cmd_out <= sd_cmd_data; + sd_cmd_in <= sd_cmd; + end + + + // CMD state + + typedef enum bit [1:0] { + STATE_IDLE, + STATE_TX, + STATE_WAIT, + STATE_RX + } e_state; + + e_state state; + e_state next_state; + + always_ff @(posedge clk) begin + if (reset) begin + state <= STATE_IDLE; + end else begin + state <= next_state; + end + end + + assign sd_scb.cmd_busy = (state != STATE_IDLE); + + logic [7:0] counter; + + always_comb begin + next_state = state; + + case (state) + STATE_IDLE: begin + if (sd_scb.cmd_start) begin + next_state = STATE_TX; + end + end + + STATE_TX: begin + if (sd_clk_falling) begin + if (counter == 8'd48) begin + if (sd_scb.cmd_skip_response) begin + next_state = STATE_IDLE; + end else begin + next_state = STATE_WAIT; + end + end + end + end + + STATE_WAIT: begin + if (sd_clk_rising) begin + if (counter == 8'd64) begin + next_state = STATE_IDLE; + end + if (!sd_cmd_in) begin + next_state = STATE_RX; + end + end + end + + STATE_RX: begin + if (sd_clk_rising) begin + if (sd_scb.cmd_long_response) begin + if (counter == 8'd136) begin + next_state = STATE_IDLE; + end + end else begin + if (counter == 8'd48) begin + next_state = STATE_IDLE; + end + end + end + end + + default: begin + next_state = STATE_IDLE; + end + endcase + end + + + // CRC7 unit + + logic crc_reset; + logic crc_enable; + logic crc_data; + logic [6:0] crc_result; + + sd_crc_7 sd_crc_7_inst ( + .clk(clk), + .reset(crc_reset), + .enable(crc_enable), + .data(crc_data), + .result(crc_result) + ); + + + // Data shifting + + logic [7:0] data_shift; + + assign crc_data = (state == STATE_RX) ? data_shift[0] : data_shift[7]; + + always_ff @(posedge clk) begin + crc_reset <= 1'b0; + crc_enable <= 1'b0; + + if (reset) begin + sd_cmd_oe_data <= 1'b0; + sd_cmd_data <= 1'b1; + end else begin + case (state) + STATE_IDLE: begin + if (sd_scb.cmd_start) begin + sd_scb.cmd_error <= 1'b0; + crc_reset <= 1'b1; + data_shift <= {2'b01, sd_scb.cmd_index}; + counter <= 8'd0; + end + end + + STATE_TX: begin + if (sd_clk_falling) begin + sd_cmd_oe_data <= 1'b1; + sd_cmd_data <= data_shift[7]; + counter <= counter + 1'd1; + crc_enable <= 1'b1; + data_shift <= {data_shift[6:0], 1'bX}; + if (counter == 8'd7) begin + data_shift <= sd_scb.cmd_arg[31:24]; + end + if (counter == 8'd15) begin + data_shift <= sd_scb.cmd_arg[23:16]; + end + if (counter == 8'd23) begin + data_shift <= sd_scb.cmd_arg[15:8]; + end + if (counter == 8'd31) begin + data_shift <= sd_scb.cmd_arg[7:0]; + end + if (counter == 8'd39) begin + data_shift <= {crc_result, 1'b1}; + end + if (counter == 8'd48) begin + sd_cmd_oe_data <= 1'b0; + counter <= 8'd0; + end + end + end + + STATE_WAIT: begin + if (sd_clk_rising) begin + counter <= counter + 1'd1; + if (counter == 8'd64) begin + sd_scb.cmd_error <= 1'b1; + end + if (!sd_cmd_in) begin + counter <= 8'd1; + crc_reset <= 1'b1; + data_shift <= 8'h00; + end + end + end + + STATE_RX: begin + if (sd_clk_rising) begin + counter <= counter + 1'd1; + data_shift <= {data_shift[6:0], sd_cmd_in}; + if (counter == 8'd8) begin + if (data_shift[6:0] != (sd_scb.cmd_reserved_response ? 7'h3F : {1'b0, sd_scb.cmd_index})) begin + sd_scb.cmd_error <= 1'b1; + end + end + if (sd_scb.cmd_long_response) begin + if (counter >= 8'd8 && counter < 8'd128) begin + crc_enable <= 1'b1; + end + if (counter[2:0] == 3'd0) begin + sd_scb.cmd_rsp <= {sd_scb.cmd_rsp[119:0], data_shift}; + end + if (!sd_scb.cmd_ignore_crc && counter == 8'd136) begin + if (data_shift[7:1] != crc_result) begin + sd_scb.cmd_error <= 1'b1; + end + end + end else begin + if (counter < 8'd40) begin + crc_enable <= 1'b1; + end + if (counter <= 8'd40 && counter[2:0] == 3'd0) begin + sd_scb.cmd_rsp <= {sd_scb.cmd_rsp[119:0], data_shift}; + end + if (!sd_scb.cmd_ignore_crc && counter == 8'd48) begin + if (data_shift[7:1] != crc_result) begin + sd_scb.cmd_error <= 1'b1; + end + end + end + end + end + endcase + end + end endmodule diff --git a/fw/rtl/sd/sd_crc_16.sv b/fw/rtl/sd/sd_crc_16.sv new file mode 100644 index 0000000..77fe8be --- /dev/null +++ b/fw/rtl/sd/sd_crc_16.sv @@ -0,0 +1,33 @@ +module sd_crc_16 ( + input clk, + input reset, + + input enable, + input shift, + input data, + + output logic [15:0] result +); + + logic crc_inv; + + assign crc_inv = result[15] ^ data; + + always_ff @(posedge clk) begin + if (reset) begin + result <= 16'd0; + end else if (enable) begin + result <= { + result[14:12], + result[11] ^ crc_inv, + result[10:5], + result[4] ^ crc_inv, + result[3:0], + crc_inv + }; + end else if (shift) begin + result <= {result[14:0], 1'b1}; + end + end + +endmodule diff --git a/fw/rtl/sd/sd_dat.sv b/fw/rtl/sd/sd_dat.sv new file mode 100644 index 0000000..26ace97 --- /dev/null +++ b/fw/rtl/sd/sd_dat.sv @@ -0,0 +1,246 @@ +module sd_dat ( + input clk, + input reset, + + sd_scb.dat sd_scb, + + fifo_bus.fifo fifo_bus, + + input sd_clk_rising, + input sd_clk_falling, + + inout [3:0] sd_dat +); + + // Input and output data sampling + + logic sd_dat_oe; + logic sd_dat_out; + logic [3:0] sd_dat_in; + logic sd_dat_oe_data; + logic [3:0] sd_dat_data; + + assign sd_dat = sd_dat_oe ? sd_dat_out : 4'hZ; + + always_ff @(posedge clk) begin + sd_dat_oe <= sd_dat_oe_data; + sd_dat_out <= sd_dat_data; + sd_dat_in <= sd_dat; + end + + always_ff @(posedge clk) begin + sd_scb.card_busy <= !sd_dat_in[0]; + end + + + // FIFO + + logic rx_full; + logic rx_almost_full; + logic rx_write; + logic [7:0] rx_wdata; + + logic tx_empty; + logic tx_almost_empty; + logic tx_read; + logic [7:0] tx_rdata; + + fifo_8kb fifo_8kb_rx_inst ( + .clk(clk), + .reset(reset || sd_scb.dat_fifo_flush), + + .empty(fifo_bus.rx_empty), + .almost_empty(fifo_bus.rx_almost_empty), + .read(fifo_bus.rx_read), + .rdata(fifo_bus.rx_rdata), + + .full(rx_full), + .almost_full(rx_almost_full), + .write(rx_write), + .wdata(rx_wdata), + + .count(sd_scb.rx_count) + ); + + fifo_8kb fifo_8kb_tx_inst ( + .clk(clk), + .reset(reset || sd_scb.dat_fifo_flush), + + .empty(tx_empty), + .almost_empty(tx_almost_empty), + .read(tx_read), + .rdata(tx_rdata), + + .full(fifo_bus.tx_full), + .almost_full(fifo_bus.tx_almost_full), + .write(fifo_bus.tx_write), + .wdata(fifo_bus.tx_wdata), + + .count(sd_scb.tx_count) + ); + + + // DAT state + + typedef enum bit [1:0] { + STATE_IDLE, + STATE_RX_WAIT, + STATE_RX + } e_state; + + e_state state; + e_state next_state; + + always_ff @(posedge clk) begin + if (reset || sd_scb.dat_stop) begin + state <= STATE_IDLE; + end else begin + state <= next_state; + end + end + + assign sd_scb.dat_busy = (state != STATE_IDLE); + + logic [10:0] counter; + logic [7:0] blocks_remaining; + + always_comb begin + next_state = state; + + case (state) + STATE_IDLE: begin + if (sd_scb.dat_start_read) begin + next_state = STATE_RX_WAIT; + end + if (sd_scb.dat_start_write) begin + end + end + + STATE_RX_WAIT: begin + if (sd_clk_rising) begin + if (!sd_dat_in[0]) begin + next_state = STATE_RX; + end + end + end + + STATE_RX: begin + if (sd_clk_rising) begin + if (counter == 11'd1041) begin + if (blocks_remaining == 8'd0) begin + next_state = STATE_IDLE; + end else begin + next_state = STATE_RX_WAIT; + end + end + end + end + endcase + end + + + // CRC16 units + + logic crc_reset; + logic crc_enable; + logic crc_shift; + logic [3:0] crc_data; + logic [15:0] crc_result [0:3]; + + sd_crc_16 sd_crc_16_inst_0 ( + .clk(clk), + .reset(crc_reset), + .enable(crc_enable), + .shift(crc_shift), + .data(crc_data[0]), + .result(crc_result[0]) + ); + + sd_crc_16 sd_crc_16_inst_1 ( + .clk(clk), + .reset(crc_reset), + .enable(crc_enable), + .shift(crc_shift), + .data(crc_data[1]), + .result(crc_result[1]) + ); + + sd_crc_16 sd_crc_16_inst_2 ( + .clk(clk), + .reset(crc_reset), + .enable(crc_enable), + .shift(crc_shift), + .data(crc_data[2]), + .result(crc_result[2]) + ); + + sd_crc_16 sd_crc_16_inst_3 ( + .clk(clk), + .reset(crc_reset), + .enable(crc_enable), + .shift(crc_shift), + .data(crc_data[3]), + .result(crc_result[3]) + ); + + + // Data shifting + + assign crc_data = rx_wdata[3:0]; + + always_ff @(posedge clk) begin + rx_write <= 1'b0; + crc_reset <= 1'b0; + crc_enable <= 1'b0; + crc_shift <= 1'b0; + + if (reset || sd_scb.dat_stop) begin + sd_dat_oe_data <= 1'b0; + sd_dat_data <= 4'hF; + end else begin + case (state) + STATE_IDLE: begin + if (sd_scb.dat_start_read || sd_scb.dat_start_write) begin + sd_scb.dat_error <= 1'b0; + blocks_remaining <= sd_scb.dat_blocks; + end + end + + STATE_RX_WAIT: begin + if (sd_clk_rising) begin + if (!sd_dat_in[0]) begin + counter <= 8'd1; + crc_reset <= 1'b1; + end + end + end + + STATE_RX: begin + if (sd_clk_rising) begin + counter <= counter + 1'd1; + rx_wdata <= {rx_wdata[3:0], sd_dat_in}; + if (counter <= 11'd1024) begin + crc_enable <= 1'b1; + if (!counter[0]) begin + if (rx_full) begin + sd_scb.dat_error <= 1'b1; + end else begin + rx_write <= 1'b1; + end + end + end else begin + crc_shift <= 1'b1; + if ({crc_result[3][15], crc_result[2][15], crc_result[1][15], crc_result[0][15]} != sd_dat_in) begin + sd_scb.dat_error <= 1'b1; + end + end + if (counter == 11'd1041) begin + blocks_remaining <= blocks_remaining - 1'd1; + end + end + end + endcase + end + end + +endmodule diff --git a/fw/rtl/sd/sd_scb.sv b/fw/rtl/sd/sd_scb.sv index 1a4d37a..3309cf9 100644 --- a/fw/rtl/sd/sd_scb.sv +++ b/fw/rtl/sd/sd_scb.sv @@ -2,12 +2,56 @@ interface sd_scb (); logic [1:0] clock_mode; - logic [5:0] index; + logic card_busy; + + logic [10:0] rx_count; + logic [10:0] tx_count; + + logic [5:0] cmd_index; + logic [31:0] cmd_arg; + logic [127:0] cmd_rsp; + logic cmd_start; + logic cmd_skip_response; + logic cmd_reserved_response; + logic cmd_long_response; + logic cmd_ignore_crc; + logic cmd_busy; + logic cmd_error; + + logic dat_fifo_flush; + logic dat_start_write; + logic dat_start_read; + logic dat_stop; + logic [7:0] dat_blocks; + logic dat_busy; + logic dat_error; modport controller ( output clock_mode, - output index + input card_busy, + + input rx_count, + input tx_count, + + output cmd_index, + output cmd_arg, + input cmd_rsp, + output cmd_start, + output cmd_skip_response, + output cmd_reserved_response, + output cmd_long_response, + output cmd_ignore_crc, + input cmd_busy, + input cmd_error, + + output dat_fifo_flush, + output dat_start_write, + output dat_start_read, + output dat_stop, + output dat_blocks, + input dat_busy, + input dat_error ); modport clk ( @@ -15,7 +59,31 @@ interface sd_scb (); ); modport cmd ( - input index + input cmd_index, + input cmd_arg, + output cmd_rsp, + input cmd_start, + input cmd_skip_response, + input cmd_reserved_response, + input cmd_long_response, + input cmd_ignore_crc, + output cmd_busy, + output cmd_error + ); + + modport dat ( + output card_busy, + + output rx_count, + output tx_count, + + input dat_fifo_flush, + input dat_start_write, + input dat_start_read, + input dat_stop, + input dat_blocks, + output dat_busy, + output dat_error ); endinterface diff --git a/fw/rtl/sd/sd_top.sv b/fw/rtl/sd/sd_top.sv index 42b2e46..a5bccde 100644 --- a/fw/rtl/sd/sd_top.sv +++ b/fw/rtl/sd/sd_top.sv @@ -11,8 +11,6 @@ module sd_top ( inout [3:0] sd_dat ); - assign sd_dat = 4'hZ; - logic sd_clk_rising; logic sd_clk_falling; @@ -40,4 +38,18 @@ module sd_top ( .sd_cmd(sd_cmd) ); + sd_dat sd_dat_inst ( + .clk(clk), + .reset(reset), + + .sd_scb(sd_scb), + + .fifo_bus(fifo_bus), + + .sd_clk_rising(sd_clk_rising), + .sd_clk_falling(sd_clk_falling), + + .sd_dat(sd_dat) + ); + endmodule diff --git a/fw/rtl/usb/usb_ft1248.sv b/fw/rtl/usb/usb_ft1248.sv index aad5b0f..5251c10 100644 --- a/fw/rtl/usb/usb_ft1248.sv +++ b/fw/rtl/usb/usb_ft1248.sv @@ -4,19 +4,25 @@ interface usb_scb (); logic reset_pending; logic reset_ack; logic write_buffer_flush; + logic [10:0] rx_count; + logic [10:0] tx_count; modport controller ( output fifo_flush, input reset_pending, output reset_ack, - output write_buffer_flush + output write_buffer_flush, + input rx_count, + input tx_count ); modport usb ( input fifo_flush, output reset_pending, input reset_ack, - input write_buffer_flush + input write_buffer_flush, + output rx_count, + output tx_count ); endinterface @@ -59,7 +65,9 @@ module usb_ft1248 ( .full(rx_full), .almost_full(rx_almost_full), .write(rx_write), - .wdata(rx_wdata) + .wdata(rx_wdata), + + .count(usb_scb.rx_count) ); fifo_8kb fifo_8kb_tx_inst ( @@ -74,7 +82,9 @@ module usb_ft1248 ( .full(fifo_bus.tx_full), .almost_full(fifo_bus.tx_almost_full), .write(fifo_bus.tx_write), - .wdata(fifo_bus.tx_wdata) + .wdata(fifo_bus.tx_wdata), + + .count(usb_scb.tx_count) ); logic [1:0] usb_pwrsav_ff; diff --git a/fw/rtl/vendor/lcmxo2/fifo_8kb.sv b/fw/rtl/vendor/lcmxo2/fifo_8kb.sv index a8ef3a7..db02ad2 100644 --- a/fw/rtl/vendor/lcmxo2/fifo_8kb.sv +++ b/fw/rtl/vendor/lcmxo2/fifo_8kb.sv @@ -10,7 +10,9 @@ module fifo_8kb ( output full, output almost_full, input write, - input [7:0] wdata + input [7:0] wdata, + + output logic [10:0] count ); fifo_8kb_lattice_generated fifo_8kb_lattice_generated_inst ( @@ -28,4 +30,18 @@ module fifo_8kb ( .AlmostFull(almost_full) ); + always_ff @(posedge clk) begin + if (reset) begin + count <= 11'd0; + end else begin + if (write && read) begin + count <= count; + end else if (write) begin + count <= count + 1'd1; + end else if (read) begin + count <= count - 1'd1; + end + end + end + endmodule diff --git a/sw/bootloader/src/fatfs/diskio.c b/sw/bootloader/src/fatfs/diskio.c index 2a442c1..9d61a65 100644 --- a/sw/bootloader/src/fatfs/diskio.c +++ b/sw/bootloader/src/fatfs/diskio.c @@ -1,36 +1,60 @@ #include "ff.h" #include "diskio.h" +#include "../io.h" #include "../sc64.h" +#include "../error.h" - -// DSTATUS status[__DRIVE_COUNT] = { STA_NOINIT, STA_NOINIT }; +DSTATUS status = STA_NOINIT; DSTATUS disk_status (BYTE pdrv) { - // if (pdrv >= __DRIVE_COUNT) { + if (pdrv > 0) { return STA_NODISK; - // } - // return status[pdrv]; + } + return status; } DSTATUS disk_initialize (BYTE pdrv) { - // if (pdrv >= __DRIVE_COUNT) { + if (pdrv > 0) { return STA_NODISK; - // } - // if (!sc64_storage_init((drive_id_t) (pdrv))) { - // status[pdrv] &= ~(STA_NOINIT); - // } - // return status[pdrv]; + } + if (!sc64_sd_card_initialize()) { + status &= ~(STA_NOINIT); + } + return status; } DRESULT disk_read (BYTE pdrv, BYTE *buff, LBA_t sector, UINT count) { - // if (pdrv >= __DRIVE_COUNT) { - // return RES_PARERR; - // } - // if (sc64_storage_read((drive_id_t) (pdrv), buff, sector, count)) { - return RES_ERROR; - // } - // return RES_OK; + if (pdrv > 0) { + return RES_PARERR; + } + uint32_t physical_address = ((uint32_t) (buff)) & 0x1FFFFFFF; + uint32_t block = 0; + while (count > 0) { + if (physical_address < (8 * 1024 * 1024)) { + block = ((count > 16) ? 16 : count); + if (sc64_sd_read_sectors(sector, 0x1FFE0000UL, block * 512)) { + return RES_ERROR; + } + for (uint32_t i = 0; i < (block * 512); i += 4) { + uint32_t data = pi_io_read((uint32_t *) (0x1FFE0000UL + i)); + uint8_t *ptr = (uint8_t *) (&data); + for (int j = 0; j < 4; j++) { + *buff++ = *ptr++; + } + } + } else { + block = ((count > 256) ? 256 : count); + if (sc64_sd_read_sectors(sector, physical_address, block * 512)) { + error_display("Kurwa 0x%08X, 0x%08X\n", physical_address, block); + return RES_ERROR; + } + physical_address += (block * 512); + } + count -= block; + sector += block; + } + return RES_OK; } #if !FF_FS_READONLY diff --git a/sw/bootloader/src/io.h b/sw/bootloader/src/io.h index b1435ad..542b924 100644 --- a/sw/bootloader/src/io.h +++ b/sw/bootloader/src/io.h @@ -246,6 +246,7 @@ typedef struct { #define SC64_REGS_BASE (0x1FFF0000UL) #define SC64_REGS ((sc64_regs_t *) SC64_REGS_BASE) +#define SC64_SR_IRQ_PENDING (1 << 29) #define SC64_SR_CMD_ERROR (1 << 30) #define SC64_SR_CPU_BUSY (1 << 31) diff --git a/sw/bootloader/src/sc64.c b/sw/bootloader/src/sc64.c index e601146..f1e674b 100644 --- a/sw/bootloader/src/sc64.c +++ b/sw/bootloader/src/sc64.c @@ -15,6 +15,10 @@ typedef enum { SC64_CMD_USB_WRITE = 'M', SC64_CMD_USB_READ_STATUS = 'u', SC64_CMD_USB_READ = 'm', + SC64_CMD_SD_CARD_INITIALIZE = 'i', + SC64_CMD_SD_SECTOR_SET = 'I', + SC64_CMD_SD_READ = 's', + SC64_CMD_SD_WRITE = 'S', } cmd_id_t; @@ -136,3 +140,19 @@ bool sc64_usb_read (uint32_t *address, uint32_t length) { } while(result[0] & (1 << 24)); return false; } + +bool sc64_sd_card_initialize (void) { + if (sc64_execute_cmd(SC64_CMD_SD_CARD_INITIALIZE, NULL, NULL)) { + return true; + } + return false; +} + +bool sc64_sd_read_sectors (uint32_t starting_sector, uint32_t address, uint32_t length) { + uint32_t sector_set_args[2] = { starting_sector, 0 }; + uint32_t read_args[2] = { address, length }; + if (sc64_execute_cmd(SC64_CMD_SD_SECTOR_SET, sector_set_args, NULL)) { + return true; + } + return sc64_execute_cmd(SC64_CMD_SD_READ, read_args, NULL); +} diff --git a/sw/bootloader/src/sc64.h b/sw/bootloader/src/sc64.h index 3d24b3b..199c6c2 100644 --- a/sw/bootloader/src/sc64.h +++ b/sw/bootloader/src/sc64.h @@ -104,6 +104,8 @@ bool sc64_usb_write_ready (void); bool sc64_usb_write (uint32_t *address, uint32_t length); bool sc64_usb_read_ready (uint8_t *type, uint32_t *length); bool sc64_usb_read (uint32_t *address, uint32_t length); +bool sc64_sd_card_initialize (void); +bool sc64_sd_read_sectors (uint32_t starting_sector, uint32_t address, uint32_t length); #endif diff --git a/sw/bootloader/src/storage.c b/sw/bootloader/src/storage.c index 1edd9da..7ed59c7 100644 --- a/sw/bootloader/src/storage.c +++ b/sw/bootloader/src/storage.c @@ -61,6 +61,8 @@ void storage_run_menu (storage_backend_t storage_backend) { FF_CHECK(f_mount(&fs, path, 1), "Couldn't mount drive"); FF_CHECK(f_chdrive(path), "Couldn't chdrive"); FF_CHECK(f_open(&fil, "sc64menu.n64", FA_READ), "Couldn't open menu file"); + FF_CHECK(f_lseek(&fil, 0), "debug 1"); + FF_CHECK(f_read(&fil, (void *) (0x10000000UL), f_size(&fil), &br), "debug 2"); FF_CHECK(f_lseek(&fil, ROM_ENTRY_OFFSET), "Couldn't seek to entry point offset"); FF_CHECK(f_read(&fil, &menu, sizeof(menu), &br), "Couldn't read entry point"); FF_CHECK(f_lseek(&fil, ROM_CODE_OFFSET), "Couldn't seek to code start offset"); diff --git a/sw/controller/app.mk b/sw/controller/app.mk index 5194466..8fd20ee 100644 --- a/sw/controller/app.mk +++ b/sw/controller/app.mk @@ -17,6 +17,7 @@ SRC_FILES = \ isv.c \ lcmxo2.c \ rtc.c \ + sd.c \ task.c \ update.c \ usb.c diff --git a/sw/controller/src/app.c b/sw/controller/src/app.c index f2b7020..5625af7 100644 --- a/sw/controller/src/app.c +++ b/sw/controller/src/app.c @@ -8,7 +8,7 @@ #define CIC_STACK_SIZE (256) #define RTC_STACK_SIZE (256) -#define GVR_STACK_SIZE (1536) +#define GVR_STACK_SIZE (2048) uint8_t cic_stack[CIC_STACK_SIZE] __attribute__((aligned(8))); diff --git a/sw/controller/src/button.c b/sw/controller/src/button.c index 770b2a9..e2fbaf1 100644 --- a/sw/controller/src/button.c +++ b/sw/controller/src/button.c @@ -39,9 +39,9 @@ void button_init (void) { void button_process (void) { usb_tx_info_t packet_info; - uint32_t status = fpga_reg_get(REG_STATUS); + uint32_t status = fpga_reg_get(REG_CFG_SCR); p.shift <<= 1; - if (status & STATUS_BUTTON) { + if (status & CFG_SCR_BUTTON_STATE) { p.shift |= (1 << 0); } if (!p.state && p.shift == 0xFFFFFFFFUL) { diff --git a/sw/controller/src/cfg.c b/sw/controller/src/cfg.c index bb1ff5b..b9d0db8 100644 --- a/sw/controller/src/cfg.c +++ b/sw/controller/src/cfg.c @@ -5,6 +5,7 @@ #include "fpga.h" #include "isv.h" #include "rtc.h" +#include "sd.h" #include "usb.h" @@ -66,6 +67,7 @@ typedef enum { CFG_ERROR_BAD_ADDRESS = 1, CFG_ERROR_BAD_CONFIG_ID = 2, CFG_ERROR_TIMEOUT = 3, + CFG_ERROR_SD = 4, CFG_ERROR_UNKNOWN_CMD = -1, } cfg_error_t; @@ -76,6 +78,7 @@ struct process { cic_seed_t cic_seed; tv_type_t tv_type; bool usb_output_ready; + uint32_t sd_card_sector; }; @@ -317,13 +320,16 @@ void cfg_init (void) { } void cfg_process (void) { + uint32_t reg; uint32_t args[2]; usb_tx_info_t packet_info; - if (fpga_reg_get(REG_STATUS) & STATUS_CFG_PENDING) { + reg = fpga_reg_get(REG_CFG_CMD); + + if (reg & CFG_CMD_PENDING) { args[0] = fpga_reg_get(REG_CFG_DATA_0); args[1] = fpga_reg_get(REG_CFG_DATA_1); - char cmd = (char) fpga_reg_get(REG_CFG_CMD); + char cmd = (char) ((reg & CFG_CMD_MASK) >> CFG_CMD_BIT); switch (cmd) { case 'v': @@ -386,6 +392,26 @@ void cfg_process (void) { args[0] = p.usb_output_ready ? 1 : 0; break; + case 'i': + if (sd_card_initialize()) { + cfg_set_error(CFG_ERROR_SD); + } + break; + + case 'I': + p.sd_card_sector = args[0]; + break; + + case 's': + if (cfg_translate_address(args)) { + cfg_set_error(CFG_ERROR_BAD_ADDRESS); + return; + } + if (sd_read_sectors(p.sd_card_sector, args[0], args[1])) { + cfg_set_error(CFG_ERROR_SD); + } + break; + default: cfg_set_error(CFG_ERROR_UNKNOWN_CMD); return; diff --git a/sw/controller/src/fpga.h b/sw/controller/src/fpga.h index d67f1ce..6b955bd 100644 --- a/sw/controller/src/fpga.h +++ b/sw/controller/src/fpga.h @@ -18,7 +18,6 @@ typedef enum { } fpga_cmd_t; typedef enum { - REG_STATUS, REG_MEM_ADDRESS, REG_MEM_SCR, REG_USB_SCR, @@ -69,16 +68,16 @@ typedef enum { #define MEM_SCR_BUSY (1 << 3) #define MEM_SCR_LENGTH_BIT (4) -#define STATUS_BUTTON (1 << 0) -#define STATUS_SD_INSERTED (1 << 1) -#define STATUS_CFG_PENDING (1 << 2) - #define USB_SCR_FIFO_FLUSH (1 << 0) #define USB_SCR_RXNE (1 << 1) #define USB_SCR_TXE (1 << 2) #define USB_SCR_RESET_PENDING (1 << 3) #define USB_SCR_RESET_ACK (1 << 4) #define USB_SCR_WRITE_FLUSH (1 << 5) +#define USB_SCR_RX_COUNT_BIT (6) +#define USB_SCR_RX_COUNT_MASK (0x7FF << USB_SCR_RX_COUNT_BIT) +#define USB_SCR_TX_COUNT_BIT (17) +#define USB_SCR_TX_COUNT_MASK (0x7FF << USB_SCR_TX_COUNT_BIT) #define DMA_SCR_START (1 << 0) #define DMA_SCR_STOP (1 << 1) @@ -97,10 +96,14 @@ typedef enum { #define CFG_SCR_EEPROM_ENABLED (1 << 9) #define CFG_SCR_EEPROM_16K (1 << 10) #define CFG_SCR_ROM_EXTENDED_ENABLED (1 << 11) +#define CFG_SCR_BUTTON_STATE (1 << 31) -#define CFG_CMD_DONE (1 << 0) -#define CFG_CMD_ERROR (1 << 1) -#define CFG_CMD_IRQ (1 << 2) +#define CFG_CMD_BIT (0) +#define CFG_CMD_MASK (0xFF << CFG_CMD_BIT) +#define CFG_CMD_PENDING (1 << 8) +#define CFG_CMD_DONE (1 << 9) +#define CFG_CMD_ERROR (1 << 10) +#define CFG_CMD_IRQ (1 << 11) #define FLASHRAM_SCR_DONE (1 << 0) #define FLASHRAM_SCR_PENDING (1 << 1) @@ -120,6 +123,30 @@ typedef enum { #define SD_SCR_CLOCK_MODE_400KHZ (1 << 0) #define SD_SCR_CLOCK_MODE_25MHZ (2 << 0) #define SD_SCR_CLOCK_MODE_50MHZ (3 << 0) +#define SD_SCR_CMD_BUSY (1 << 2) +#define SD_SCR_CMD_ERROR (1 << 3) +#define SD_SCR_CARD_BUSY (1 << 4) +#define SD_SCR_CARD_INSERTED (1 << 5) +#define SD_SCR_RX_COUNT_BIT (6) +#define SD_SCR_RX_COUNT_MASK (0x7FF << SD_SCR_RX_COUNT_BIT) +#define SD_SCR_TX_COUNT_BIT (17) +#define SD_SCR_TX_COUNT_MASK (0x7FF << SD_SCR_TX_COUNT_BIT) + +#define SD_CMD_INDEX_BIT (0) +#define SD_CMD_INDEX_MASK (0x3F) +#define SD_CMD_SKIP_RESPONSE (1 << 6) +#define SD_CMD_RESERVED_RESPONSE (1 << 7) +#define SD_CMD_LONG_RESPONSE (1 << 8) +#define SD_CMD_IGNORE_CRC (1 << 9) + +#define SD_DAT_FIFO_FLUSH (1 << 0) +#define SD_DAT_START_WRITE (1 << 1) +#define SD_DAT_START_READ (1 << 2) +#define SD_DAT_STOP (1 << 3) +#define SD_DAT_BLOCKS_BIT (4) +#define SD_DAT_BLOCKS_MASK (0xFF << SD_DAT_BLOCKS_BIT) +#define SD_DAT_BUSY (1 << 12) +#define SD_DAT_ERROR (1 << 13) #define DD_SCR_HARD_RESET (1 << 0) #define DD_SCR_HARD_RESET_CLEAR (1 << 1) diff --git a/sw/controller/src/gvr.c b/sw/controller/src/gvr.c index e14d99c..bdc836a 100644 --- a/sw/controller/src/gvr.c +++ b/sw/controller/src/gvr.c @@ -5,6 +5,7 @@ #include "fpga.h" #include "isv.h" #include "rtc.h" +#include "sd.h" #include "usb.h" @@ -16,6 +17,7 @@ void gvr_task (void) { dd_init(); flashram_init(); isv_init(); + sd_init(); usb_init(); while (1) { @@ -25,6 +27,7 @@ void gvr_task (void) { flashram_process(); isv_process(); rtc_process(); + sd_process(); usb_process(); } } diff --git a/sw/controller/src/sd.c b/sw/controller/src/sd.c new file mode 100644 index 0000000..0e541db --- /dev/null +++ b/sw/controller/src/sd.c @@ -0,0 +1,285 @@ +#include +#include +#include "sd.h" +#include "fpga.h" +#include "debug.h" +#include "hw.h" + + +#define CMD8_ARG_SUPPLY_VOLTAGE_27_36_V (1 << 8) +#define CMD8_ARG_CHECK_PATTERN (0xAA << 0) + +#define ACMD41_ARG_HCS (1 << 30) + +#define R3_CCS (1 << 30) +#define R3_BUSY (1 << 31) + +#define R7_SUPPLY_VOLTAGE_27_36_V (1 << 8) +#define R7_CHECK_PATTERN (0xAA << 0) + + +typedef enum { + CLOCK_STOP, + CLOCK_400KHZ, + CLOCK_25MHZ, + CLOCK_50MHZ, +} sd_clock_t; + +typedef enum { + RSP_NONE, + RSP_R1, + RSP_R1b, + RSP_R2, + RSP_R3, + RSP_R6, + RSP_R7, +} rsp_type_t; + + +static bool sd_card_initialized; +static bool sd_card_type_block; +static uint32_t sd_rca = 0; +static volatile bool timeout = false; + + +static void sd_trigger_timeout (void) { + timeout = true; +} + +static void sd_set_clock (sd_clock_t mode) { + fpga_reg_set(REG_SD_SCR, SD_SCR_CLOCK_MODE_OFF); + + switch (mode) { + case CLOCK_400KHZ: + fpga_reg_set(REG_SD_SCR, SD_SCR_CLOCK_MODE_400KHZ); + break; + case CLOCK_25MHZ: + fpga_reg_set(REG_SD_SCR, SD_SCR_CLOCK_MODE_25MHZ); + break; + case CLOCK_50MHZ: + fpga_reg_set(REG_SD_SCR, SD_SCR_CLOCK_MODE_50MHZ); + break; + default: + break; + } +} + +static bool sd_cmd (uint8_t cmd, uint32_t arg, rsp_type_t rsp_type, void *rsp) { + uint32_t scr; + uint32_t cmd_data; + + cmd_data = ((cmd << SD_CMD_INDEX_BIT) & SD_CMD_INDEX_MASK); + switch (rsp_type) { + case RSP_NONE: + cmd_data |= SD_CMD_SKIP_RESPONSE; + break; + case RSP_R2: + cmd_data |= (SD_CMD_LONG_RESPONSE | SD_CMD_RESERVED_RESPONSE); + break; + case RSP_R3: + cmd_data |= (SD_CMD_IGNORE_CRC | SD_CMD_RESERVED_RESPONSE); + break; + default: + break; + } + + fpga_reg_set(REG_SD_ARG, arg); + fpga_reg_set(REG_SD_CMD, cmd_data); + + do { + scr = fpga_reg_get(REG_SD_SCR); + } while (scr & SD_SCR_CMD_BUSY); + + if (rsp != NULL) { + fpga_reg_t rsp_regs[4] = { + REG_SD_RSP_3, + REG_SD_RSP_2, + REG_SD_RSP_1, + REG_SD_RSP_0 + }; + bool rsp_long = rsp_type & SD_CMD_LONG_RESPONSE; + fpga_reg_t rsp_reg = (rsp_long ? 0 : (sizeof(rsp_regs) - 1)); + uint8_t *rsp_8 = (uint8_t *) (rsp); + while (rsp_reg < sizeof(rsp_regs)) { + uint32_t rsp_data = fpga_reg_get(rsp_regs[rsp_reg++]); + uint8_t *rsp_data_8 = (uint8_t *) (&rsp_data); + for (int i = 0; i < 4; i++) { + *rsp_8++ = *rsp_data_8++; + } + }; + } + + if (rsp_type == RSP_R1b) { + do { + scr = fpga_reg_get(REG_SD_SCR); + } while (scr & SD_SCR_CARD_BUSY); + } + + return (scr & SD_SCR_CMD_ERROR); +} + +static bool sd_acmd (uint8_t acmd, uint32_t arg, rsp_type_t rsp_type, void *rsp) { + if (sd_cmd(55, sd_rca, RSP_R1, NULL)) { + return true; + } + if (sd_cmd(acmd, arg, rsp_type, rsp)) { + return true; + } + return false; +} + + +bool sd_read_sectors (uint32_t starting_sector, uint32_t address, uint32_t length) { + if (!sd_card_initialized) { + return true; + } + + if ((length == 0) || (length % 512 != 0) || (length > (256 * 512))) { + return true; + } + + do { + uint32_t blocks = (length / 512); + + timeout = false; + hw_tim_setup(TIM_ID_GVR, 5000, sd_trigger_timeout); + + if (!sd_card_type_block) { + starting_sector *= 512; + } + + // fpga_reg_set(REG_SD_DMA_SCR, DMA_SCR_STOP); + // fpga_reg_set(REG_SD_DAT, SD_DAT_STOP | SD_DAT_FIFO_FLUSH); + + fpga_reg_set(REG_SD_DMA_ADDRESS, address); + fpga_reg_set(REG_SD_DMA_LENGTH, length); + fpga_reg_set(REG_SD_DMA_SCR, DMA_SCR_DIRECTION | DMA_SCR_START); + + fpga_reg_set(REG_SD_DAT, (((blocks - 1) << SD_DAT_BLOCKS_BIT) | SD_DAT_START_READ | SD_DAT_FIFO_FLUSH)); + + if (sd_cmd(23, blocks, RSP_R1, NULL)) { + break; + } + + if (sd_cmd(18, starting_sector, RSP_R1, NULL)) { + break; + } + + bool error = false; + + while (!timeout) { + uint32_t sd_scr = fpga_reg_get(REG_SD_SCR); + if (!(sd_scr & SD_SCR_CARD_INSERTED)) { + error = true; + break; + } + uint32_t sd_dat = fpga_reg_get(REG_SD_DAT); + uint32_t sd_dma_scr = fpga_reg_get(REG_SD_DMA_SCR); + if (sd_dat & SD_DAT_ERROR) { + error = true; + break; + } + if ((!(sd_dma_scr & DMA_SCR_BUSY)) && (!(sd_dat & SD_DAT_BUSY))) { + break; + } + } + + if (timeout) { + break; + } + + hw_tim_stop(TIM_ID_GVR); + + if (error) { + break; + } + + return false; + } while (0); + + fpga_reg_set(REG_SD_DMA_SCR, DMA_SCR_STOP); + fpga_reg_set(REG_SD_DAT, SD_DAT_STOP | SD_DAT_FIFO_FLUSH); + + return true; +} + +bool sd_card_initialize (void) { + bool error; + uint32_t arg; + uint32_t rsp; + bool version_2_or_later = false; + + if (sd_card_initialized) { + return false; + } + + sd_set_clock(CLOCK_400KHZ); + + do { + sd_cmd(0, 0, RSP_NONE, NULL); + + arg = (CMD8_ARG_SUPPLY_VOLTAGE_27_36_V | CMD8_ARG_CHECK_PATTERN); + if (!sd_cmd(8, arg, RSP_R7, &rsp)) { + version_2_or_later = true; + if (rsp != (R7_SUPPLY_VOLTAGE_27_36_V | R7_CHECK_PATTERN)) { + break; + } + } + + arg = ((version_2_or_later ? ACMD41_ARG_HCS : 0) | 0x00FF8000); + for (int i = 0; i < 4000; i++) { + error = sd_acmd(41, arg, RSP_R3, &rsp); + if (error || (rsp & R3_BUSY)) { + break; + } + } + if (error || ((rsp & 0x00FF8000) == 0)) { + break; + } + sd_card_type_block = (rsp & R3_CCS); + + if (sd_cmd(2, 0, RSP_R2, NULL)) { + break; + } + + if (sd_cmd(3, 0, RSP_R6, &rsp)) { + break; + } + sd_rca = rsp & 0xFFFF0000; + + if (sd_cmd(7, sd_rca, RSP_R1b, NULL)) { + break; + } + + if (sd_acmd(6, 2, RSP_R1, NULL)) { + break; + } + + sd_set_clock(CLOCK_50MHZ); + + sd_card_initialized = true; + + return false; + } while (0); + + sd_rca = 0; + sd_cmd(0, 0, RSP_NONE, NULL); + sd_set_clock(CLOCK_STOP); + + return true; +} + +void sd_init (void) { + sd_card_initialized = false; + sd_set_clock(CLOCK_STOP); +} + +void sd_process (void) { + if (!(fpga_reg_get(REG_SD_SCR) & SD_SCR_CARD_INSERTED)) { + if (sd_card_initialized) { + sd_card_initialized = false; + sd_rca = 0; + sd_set_clock(CLOCK_STOP); + } + } +} diff --git a/sw/controller/src/sd.h b/sw/controller/src/sd.h new file mode 100644 index 0000000..90afd36 --- /dev/null +++ b/sw/controller/src/sd.h @@ -0,0 +1,14 @@ +#ifndef SD_H__ +#define SD_H__ + + +#include + + +bool sd_read_sectors (uint32_t starting_sector, uint32_t address, uint32_t length); +bool sd_card_initialize (void); +void sd_init (void); +void sd_process (void); + + +#endif diff --git a/sw/pc/.gitignore b/sw/pc/.gitignore index a6ea7e6..baaf232 100644 --- a/sw/pc/.gitignore +++ b/sw/pc/.gitignore @@ -1,18 +1,9 @@ **/__pycache__ -/backup -/roms -/saves -*.a -*.bak *.bin -*.dat -*.data -*.dll -*.dylib *.eep *.fla -*.img *.n64 *.srm +*.upd *.v64 *.z64 diff --git a/sw/pc/sc64.py b/sw/pc/sc64.py index 4c727c2..704fe4a 100755 --- a/sw/pc/sc64.py +++ b/sw/pc/sc64.py @@ -433,6 +433,11 @@ class SC64: address = self.__Address.EEPROM return self.__read_memory(address, length) + def upload_bootloader(self, data: bytes) -> None: + if (len(data) > self.__Length.BOOTLOADER): + raise ValueError('Bootloader size too big') + self.__program_flash(self.__Address.BOOTLOADER, data) + def set_rtc(self, t: datetime) -> None: to_bcd = lambda v: ((int((v / 10) % 10) << 4) | int(int(v) % 10)) data = bytes([ @@ -645,6 +650,7 @@ if __name__ == '__main__': parser.add_argument('--isv', action='store_true', help='enable IS-Viewer64 support') parser.add_argument('--debug', action='store_true', help='run debug loop (required for 64DD and IS-Viewer64)') parser.add_argument('--download-memory', help='download whole memory space and write it to specified file') + parser.add_argument('--bootloader', help='bootloader') if (len(sys.argv) <= 1): parser.print_help() @@ -667,6 +673,12 @@ if __name__ == '__main__': status_callback = lambda status: print(f'{status} ', end='', flush=True) sc64.update_firmware(f.read(), status_callback) print('done') + + if (args.bootloader): + with open(args.bootloader, 'rb+') as f: + print('Uploading Bootloader... ', end='', flush=True) + sc64.upload_bootloader(f.read()) + print('done') if (args.reset_state): sc64.reset_state()