From ceed43c324f65a4ae891ec24bb43c783395d8576 Mon Sep 17 00:00:00 2001 From: Polprzewodnikowy Date: Tue, 13 Sep 2022 02:19:26 +0200 Subject: [PATCH] sd card writing is working --- fw/rtl/sd/sd_dat.sv | 130 +++++++++++++++++++++++++++++-- sw/bootloader/src/fatfs/diskio.c | 29 ++++++- sw/bootloader/src/fatfs/ffconf.h | 2 +- sw/bootloader/src/menu.c | 6 +- sw/bootloader/src/sc64.c | 11 ++- sw/bootloader/src/sc64.h | 1 + sw/controller/src/cfg.c | 10 +++ sw/controller/src/sd.c | 33 ++++++++ sw/controller/src/sd.h | 1 + 9 files changed, 211 insertions(+), 12 deletions(-) diff --git a/fw/rtl/sd/sd_dat.sv b/fw/rtl/sd/sd_dat.sv index 26ace97..b24e478 100644 --- a/fw/rtl/sd/sd_dat.sv +++ b/fw/rtl/sd/sd_dat.sv @@ -15,7 +15,7 @@ module sd_dat ( // Input and output data sampling logic sd_dat_oe; - logic sd_dat_out; + logic [3:0] sd_dat_out; logic [3:0] sd_dat_in; logic sd_dat_oe_data; logic [3:0] sd_dat_data; @@ -82,10 +82,14 @@ module sd_dat ( // DAT state - typedef enum bit [1:0] { + typedef enum bit [2:0] { STATE_IDLE, STATE_RX_WAIT, - STATE_RX + STATE_RX, + STATE_TX_WAIT, + STATE_TX, + STATE_TX_STATUS_WAIT, + STATE_TX_STATUS } e_state; e_state state; @@ -113,6 +117,7 @@ module sd_dat ( next_state = STATE_RX_WAIT; end if (sd_scb.dat_start_write) begin + next_state = STATE_TX_WAIT; end end @@ -135,6 +140,46 @@ module sd_dat ( end end end + + STATE_TX_WAIT: begin + if (sd_clk_falling) begin + if (sd_scb.tx_count >= 11'd512) begin + next_state = STATE_TX; + end + end + end + + STATE_TX: begin + if (sd_clk_falling) begin + if (counter == 11'd1042) begin + next_state = STATE_TX_STATUS_WAIT; + end + end + end + + STATE_TX_STATUS_WAIT: begin + if (sd_clk_rising) begin + if (counter == 11'd8) begin + next_state = STATE_IDLE; + end else if (!sd_dat_in[0]) begin + next_state = STATE_TX_STATUS; + end + end + end + + STATE_TX_STATUS: begin + if (sd_clk_rising) begin + if (counter == 11'd5) begin + if (sd_dat_in[0]) begin + if (blocks_remaining == 8'd0) begin + next_state = STATE_IDLE; + end else begin + next_state = STATE_TX_WAIT; + end + end + end + end + end endcase end @@ -186,10 +231,18 @@ module sd_dat ( // Data shifting - assign crc_data = rx_wdata[3:0]; + logic [7:0] data_shift; + logic tx_rdata_valid; + + assign crc_data = (state == STATE_RX) ? rx_wdata[3:0] : sd_dat_data; + + always_comb begin + tx_read = (state == STATE_TX) && sd_clk_falling && (counter < 11'd1024) && (!counter[0]); + end always_ff @(posedge clk) begin rx_write <= 1'b0; + tx_rdata_valid <= tx_read; crc_reset <= 1'b0; crc_enable <= 1'b0; crc_shift <= 1'b0; @@ -209,7 +262,7 @@ module sd_dat ( STATE_RX_WAIT: begin if (sd_clk_rising) begin if (!sd_dat_in[0]) begin - counter <= 8'd1; + counter <= 11'd1; crc_reset <= 1'b1; end end @@ -239,8 +292,75 @@ module sd_dat ( end end end + + STATE_TX_WAIT: begin + if (sd_clk_falling) begin + if (sd_scb.tx_count >= 11'd512) begin + counter <= 11'd0; + end + end + end + + STATE_TX: begin + if (sd_clk_falling) begin + counter <= counter + 1'd1; + if (counter == 11'd0) begin + crc_reset <= 1'b1; + sd_dat_oe_data <= 1'b1; + sd_dat_data <= 4'h0; + end else if (counter <= 11'd1024) begin + crc_enable <= 1'b1; + {sd_dat_data, data_shift} <= {data_shift, 4'h0}; + end else begin + crc_shift <= 1'b1; + sd_dat_data <= {crc_result[3][15], crc_result[2][15], crc_result[1][15], crc_result[0][15]}; + end + if (counter == 11'd1042) begin + sd_dat_oe_data <= 1'b0; + counter <= 11'd0; + end + end + end + + STATE_TX_STATUS_WAIT: begin + if (sd_clk_rising) begin + counter <= counter + 1'd1; + if (counter == 11'd8) begin + sd_scb.dat_error <= 1'b1; + end else if (!sd_dat_in[0]) begin + counter <= 11'd1; + end + end + end + + STATE_TX_STATUS: begin + if (sd_clk_rising) begin + if (counter < 11'd5) begin + counter <= counter + 1'd1; + end + if ((counter == 11'd1) && (sd_dat_in[0] != 1'b0)) begin + sd_scb.dat_error <= 1'b1; + end + if ((counter == 11'd2) && (sd_dat_in[0] != 1'b1)) begin + sd_scb.dat_error <= 1'b1; + end + if ((counter == 11'd3) && (sd_dat_in[0] != 1'b0)) begin + sd_scb.dat_error <= 1'b1; + end + if ((counter == 11'd4) && (sd_dat_in[0] != 1'b1)) begin + sd_scb.dat_error <= 1'b1; + end + if ((counter == 11'd5) && (sd_dat_in[0] == 1'b1)) begin + blocks_remaining <= blocks_remaining - 1'd1; + end + end + end endcase end + + if (tx_rdata_valid) begin + data_shift <= tx_rdata; + end end endmodule diff --git a/sw/bootloader/src/fatfs/diskio.c b/sw/bootloader/src/fatfs/diskio.c index c5b2205..861d86a 100644 --- a/sw/bootloader/src/fatfs/diskio.c +++ b/sw/bootloader/src/fatfs/diskio.c @@ -69,8 +69,33 @@ DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count) { if (pdrv > 0) { return RES_PARERR; } - // TODO: write - return RES_ERROR; + uint32_t *physical_address = (uint32_t *) (PHYSICAL(buff)); + if (physical_address < (uint32_t *) (N64_RAM_SIZE)) { + uint8_t aligned_buffer[BUFFER_BLOCKS_MAX * SD_BLOCK_SIZE] __attribute__((aligned(8))); + while (count > 0) { + uint32_t blocks = ((count > BUFFER_BLOCKS_MAX) ? BUFFER_BLOCKS_MAX : count); + size_t length = (blocks * SD_BLOCK_SIZE); + if (((uint32_t) (buff) % 8) == 0) { + cache_data_hit_writeback((void *) (buff), length); + pi_dma_write((io32_t *) (SC64_BUFFERS->BUFFER), (void *) (buff), length); + } else { + memcpy(aligned_buffer, buff, length); + cache_data_hit_writeback(aligned_buffer, length); + pi_dma_write((io32_t *) (SC64_BUFFERS->BUFFER), aligned_buffer, length); + } + if (sc64_sd_write_sectors((uint32_t *) (SC64_BUFFERS->BUFFER), sector, blocks)) { + return RES_ERROR; + } + buff += length; + sector += blocks; + count -= blocks; + } + } else { + if (sc64_sd_write_sectors(physical_address, sector, count)) { + return RES_ERROR; + } + } + return RES_OK; } #endif diff --git a/sw/bootloader/src/fatfs/ffconf.h b/sw/bootloader/src/fatfs/ffconf.h index 0e48a24..6fde966 100644 --- a/sw/bootloader/src/fatfs/ffconf.h +++ b/sw/bootloader/src/fatfs/ffconf.h @@ -166,7 +166,7 @@ / Drive/Volume Configurations /---------------------------------------------------------------------------*/ -#define FF_VOLUMES 2 +#define FF_VOLUMES 1 /* Number of volumes (logical drives) to be used. (1-10) */ diff --git a/sw/bootloader/src/menu.c b/sw/bootloader/src/menu.c index a9c43d5..f3723df 100644 --- a/sw/bootloader/src/menu.c +++ b/sw/bootloader/src/menu.c @@ -60,9 +60,9 @@ void menu_load_and_run (void) { } FF_CHECK(f_read(&fil, menu, size, &br), "Couldn't read menu file"); FF_CHECK(br != size, "Read size is different than expected"); - // TODO: delete this - FF_CHECK(f_lseek(&fil, 0), "Couldn't seek to the beginning of file"); - FF_CHECK(f_read(&fil, (void *) (0xB0000000UL), f_size(&fil), &br), "Couldn't read file contents to SDRAM"); + // TODO: delete this, do not touch SDRAM when loading menu + FF_CHECK(f_lseek(&fil, 0), "Couldn't seek to the beginning of file"); + FF_CHECK(f_read(&fil, (void *) (0xB0000000UL), f_size(&fil), &br), "Couldn't read file contents to SDRAM"); // TODO: ^ FF_CHECK(f_close(&fil), "Couldn't close menu file"); FF_CHECK(f_unmount(""), "Couldn't unmount drive"); diff --git a/sw/bootloader/src/sc64.c b/sw/bootloader/src/sc64.c index 440fe84..36e65ae 100644 --- a/sw/bootloader/src/sc64.c +++ b/sw/bootloader/src/sc64.c @@ -17,8 +17,8 @@ typedef enum { SC64_CMD_USB_READ = 'm', SC64_CMD_SD_CARD_INIT = 'i', SC64_CMD_SD_SECTOR_SET = 'I', - SC64_CMD_SD_READ = 's', SC64_CMD_SD_WRITE = 'S', + SC64_CMD_SD_READ = 's', } cmd_id_t; @@ -157,6 +157,15 @@ bool sc64_sd_card_deinit (void) { return false; } +bool sc64_sd_write_sectors (uint32_t *address, uint32_t sector, uint32_t count) { + uint32_t sector_set_args[2] = { sector, 0 }; + uint32_t write_args[2] = { (uint32_t) (address), count }; + if (sc64_execute_cmd(SC64_CMD_SD_SECTOR_SET, sector_set_args, NULL)) { + return true; + } + return sc64_execute_cmd(SC64_CMD_SD_WRITE, write_args, NULL); +} + bool sc64_sd_read_sectors (uint32_t *address, uint32_t sector, uint32_t count) { uint32_t sector_set_args[2] = { sector, 0 }; uint32_t read_args[2] = { (uint32_t) (address), count }; diff --git a/sw/bootloader/src/sc64.h b/sw/bootloader/src/sc64.h index 985c9e8..1d5ad63 100644 --- a/sw/bootloader/src/sc64.h +++ b/sw/bootloader/src/sc64.h @@ -105,6 +105,7 @@ 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_init (void); bool sc64_sd_card_deinit (void); +bool sc64_sd_write_sectors (uint32_t *address, uint32_t sector, uint32_t count); bool sc64_sd_read_sectors (uint32_t *address, uint32_t sector, uint32_t count); diff --git a/sw/controller/src/cfg.c b/sw/controller/src/cfg.c index a046ee2..0e60bf2 100644 --- a/sw/controller/src/cfg.c +++ b/sw/controller/src/cfg.c @@ -415,6 +415,16 @@ void cfg_process (void) { } break; + case 'S': + if (cfg_translate_address(args)) { + cfg_set_error(CFG_ERROR_BAD_ADDRESS); + return; + } + if (sd_write_sectors(args[0], p.sd_card_sector, args[1])) { + cfg_set_error(CFG_ERROR_SD); + } + break; + default: cfg_set_error(CFG_ERROR_UNKNOWN_CMD); return; diff --git a/sw/controller/src/sd.c b/sw/controller/src/sd.c index 77cf815..1cde4dd 100644 --- a/sw/controller/src/sd.c +++ b/sw/controller/src/sd.c @@ -235,6 +235,39 @@ bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count) { return false; } +bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count) { + if (!p.card_initialized || (count == 0)) { + return true; + } + + if (!p.card_type_block) { + sector *= SD_BLOCK_SIZE; + } + + while (count > 0) { + uint32_t blocks = ((count > DAT_BLOCK_MAX_COUNT) ? DAT_BLOCK_MAX_COUNT : count); + led_blink_act(); + if (sd_cmd(23, blocks, RSP_R1, NULL)) { + return true; + } + if (sd_cmd(25, sector, RSP_R1, NULL)) { + return true; + } + sd_dat_prepare(address, blocks, DAT_WRITE); + bool error = sd_dat_wait(1000); + sd_cmd(12, 0, RSP_R1b, NULL); + if (error) { + sd_dat_abort(); + return true; + } + address += (blocks * SD_BLOCK_SIZE); + sector += (blocks * (p.card_type_block ? 1 : SD_BLOCK_SIZE)); + count -= blocks; + } + + return false; +} + bool sd_card_init (void) { uint32_t arg; uint32_t rsp; diff --git a/sw/controller/src/sd.h b/sw/controller/src/sd.h index 5a68e36..c7f34ed 100644 --- a/sw/controller/src/sd.h +++ b/sw/controller/src/sd.h @@ -6,6 +6,7 @@ bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count); +bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count); bool sd_card_init (void); void sd_card_deinit (void); void sd_init (void);