/////////////////////////////////////////// // sd_top.sv // // Written: Richard Davis // Modified: Ross Thompson September 19, 2021 // // Purpose: SD card controller // // A component of the Wally configurable RISC-V project. // // Copyright (C) 2021 Harvey Mudd College & Oklahoma State University // // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, // modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT // OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /////////////////////////////////////////// `include "wally-config.vh" module sd_top #(parameter g_COUNT_WIDTH = 8) ( input logic CLK, // 1.2 GHz (1.0 GHz typical) input logic a_RST, // Reset signal (Must be held for minimum of 24 clock cycles) // a_RST MUST COME OUT OF RESET SYNCHRONIZED TO THE 1.2 GHZ CLOCK! // io_SD_CMD_z : inout std_logic; // SD CMD Bus (* mark_debug = "true" *)input logic i_SD_CMD, // CMD Response from card (* mark_debug = "true" *)output logic o_SD_CMD, // CMD Command from host (* mark_debug = "true" *)output logic o_SD_CMD_OE, // Direction of SD_CMD (* mark_debug = "true" *)input logic [3:0] i_SD_DAT, // SD DAT Bus (* mark_debug = "true" *)output logic o_SD_CLK, // SD CLK Bus // For communication with core cpu input logic [32:9] i_BLOCK_ADDR, // see "Addressing" in parts.fods (only 8GB total capacity is used) output logic o_READY_FOR_READ, // tells core that initialization sequence is completed and // sd card is ready to read a 512 byte block to the core. // Held high during idle until i_READ_REQUEST is received output logic o_SD_RESTARTING, // inform core the need to restart input logic i_READ_REQUEST, // After Ready for read is sent to the core, the core will // pulse this bit high to indicate it wants the block at this address output logic [3:0] o_DATA_TO_CORE, // nibble being sent to core when DATA block is output logic [4095:0] ReadData, // full 512 bytes to Bus // being published output logic o_DATA_VALID, // held high while data being read to core to indicate that it is valid output logic o_LAST_NIBBLE, // pulse when last nibble is sent output logic [2:0] o_ERROR_CODE_Q, // indicates which error occured output logic o_FATAL_ERROR, // indicates that the FATAL ERROR register has updated // For tuning input logic [g_COUNT_WIDTH-1:0] i_COUNT_IN_MAX, input logic LIMIT_SD_TIMERS ); localparam logic c_CMD = 1'b0; localparam logic c_ACMD = 1'b1; // packet bit names localparam logic c_start_bit = 1'b0; // bit 47 localparam logic c_stop_bit = 1'b1; // bit 0, AKA "end bit" // transmitter bit, bit 46 localparam logic c_tx_host_command = 1'b1; localparam logic c_tx_card_response = 1'b0; // response types localparam logic [2:0] c_response_type_R0_NONE = 3'd0; localparam logic [2:0] c_response_type_R1_NORMAL = 3'd1; localparam logic [2:0] c_response_type_R2_CID_CSD = 3'd2; localparam logic [2:0] c_response_type_R3_OCR = 3'd3; localparam logic [2:0] c_response_type_R6_RCA = 3'd6; localparam logic [2:0] c_response_type_R7_CIC = 3'd7; // uses dat localparam logic [1:0] c_DAT_none = 2'b00; localparam logic [1:0] c_DAT_busy = 2'b01; localparam logic [1:0] c_DAT_wide = 2'b10; localparam logic [1:0] c_DAT_block = 2'b11; // tx source selection localparam logic [1:0] c_tx_low = 2'b00; localparam logic [1:0] c_tx_high = 2'b01; localparam logic [1:0] c_tx_head = 2'b10; localparam logic [1:0] c_tx_tail = 2'b11; // command indexes localparam logic [45:40] c_Go_Idle_State = 6'd00; // CMD0 localparam logic [45:40] c_All_Send_CID = 6'd02; // CMD2 localparam logic [45:40] c_SD_Send_RCA = 6'd03; // CMD3 localparam logic [45:40] c_Switch_Function = 6'd06; // CMD6 localparam logic [45:40] c_Set_Bus_Width = 6'd06; // ACMD6 localparam logic [45:40] c_Select_Card = 6'd07; // CMD7 localparam logic [45:40] c_Send_IF_State = 6'd08; // CMD8 localparam logic [45:40] c_Read_Single_Block = 6'd17; // CMD17 localparam logic [45:40] c_SD_Send_OCR = 6'd41; // ACMD41 localparam logic [45:40] c_App_Command = 6'd55; // CMD55 // bitmasks localparam logic [127:96] c_CMD0_mask_check_redo_bits = 32'h00000000; // Go_Idle_State localparam logic [127:96] c_CMD0_ans_dont_redo = 32'h00000000; localparam logic [127:96] c_CMD0_mask_check_error_bits = 32'h00000000; localparam logic [127:96] c_CMD0_ans_error_free = 32'h00000000; localparam logic [127:96] c_CMD2_mask_check_redo_bits = 32'h00000000; // All_Send_CID localparam logic [127:96] c_CMD2_ans_dont_redo = 32'h00000000; localparam logic [127:96] c_CMD2_mask_check_error_bits = 32'h00000000; localparam logic [127:96] c_CMD2_ans_error_free = 32'h00000000; localparam logic [127:96] c_CMD3_mask_check_redo_bits = 32'h00000000; // SD_Send_RCA localparam logic [127:96] c_CMD3_ans_dont_redo = 32'h00000000; localparam logic [127:96] c_CMD3_mask_check_error_bits = 32'h00002000; localparam logic [127:96] c_CMD3_ans_error_free = 32'h00000000; localparam logic [127:96] c_CMD6_mask_check_redo_bits = 32'h00000000; // Switch_Function localparam logic [127:96] c_CMD6_ans_dont_redo = 32'h00000000; localparam logic [127:96] c_CMD6_mask_check_error_bits = 32'h82380000; localparam logic [127:96] c_CMD6_ans_error_free = 32'h00000000; localparam logic [127:96] c_ACMD6_mask_check_redo_bits = 32'h00000000; // Set_Bus_Width localparam logic [127:96] c_ACMD6_ans_dont_redo = 32'h00000000; localparam logic [127:96] c_ACMD6_mask_check_error_bits = 32'h8F398020; localparam logic [127:96] c_ACMD6_ans_error_free = 32'h00000020; localparam logic [127:96] c_CMD7_mask_check_redo_bits = 32'h00000000; // Select_Card localparam logic [127:96] c_CMD7_ans_dont_redo = 32'h00000000; localparam logic [127:96] c_CMD7_mask_check_error_bits = 32'h0F398000; localparam logic [127:96] c_CMD7_ans_error_free = 32'h00000000; localparam logic [127:96] c_CMD8_mask_check_redo_bits = 32'h00000000; // Send_IF_State localparam logic [127:96] c_CMD8_ans_dont_redo = 32'h00000000; localparam logic [127:96] c_CMD8_mask_check_error_bits = 32'h00000FFF; localparam logic [127:96] c_CMD8_ans_error_free = 32'h000001FF; localparam logic [127:96] c_CMD17_mask_check_redo_bits = 32'h00000000; // Read_Single_Block localparam logic [127:96] c_CMD17_ans_dont_redo = 32'h00000000; localparam logic [127:96] c_CMD17_mask_check_error_bits = 32'hCF398000; localparam logic [127:96] c_CMD17_ans_error_free = 32'h00000000; localparam logic [127:96] c_ACMD41_mask_check_redo_bits = 32'h80000000; //32'h80000000; // SD_Send_OCR localparam logic [127:96] c_ACMD41_ans_dont_redo = 32'h80000000; //32'h80000000; localparam logic [127:96] c_ACMD41_mask_check_error_bits = 32'h41FF8000; // 32'h41FF8000; localparam logic [127:96] c_ACMD41_ans_error_free = 32'h40FF8000; // 32'h40FF8000 localparam logic [127:96] c_CMD55_mask_check_redo_bits = 32'h00000000; // App_Command localparam logic [127:96] c_CMD55_ans_dont_redo = 32'h00000000; localparam logic [127:96] c_CMD55_mask_check_error_bits = 32'h0F398000; localparam logic [127:96] c_CMD55_ans_error_free = 32'h00000000; localparam logic [127:96] c_ACMD55_mask_check_redo_bits = 32'h00000000; // App_Command localparam logic [127:96] c_ACMD55_ans_dont_redo = 32'h00000000; localparam logic [127:96] c_ACMD55_mask_check_error_bits = 32'h0F398000; localparam logic [127:96] c_ACMD55_ans_error_free = 32'h00000000; // SD_CMD_FSM Connections logic w_TIMER_LOAD, w_TIMER_EN; logic [18:0] w_TIMER_IN; logic [18:0] r_TIMER_OUT; logic w_COUNTER_LOAD, w_COUNTER_EN; logic [7:0] w_COUNTER_IN; logic [7:0] r_COUNTER_OUT; logic w_SD_CLK_EN; logic w_CLOCK_CHANGE_DONE, w_START_CLOCK_CHANGE; // to clk fsm logic w_HS_TO_INIT_CLK_DIVIDER_RST; (* mark_debug = "true" *)logic w_IC_RST, w_IC_EN, w_IC_UP_DOWN; (* mark_debug = "true" *)logic w_SD_CMD_OE; logic w_TX_PISO40_LOAD, w_TX_PISO40_EN; logic w_TX_PISO8_LOAD, w_TX_PISO8_EN; logic w_TX_CRC7_PIPO_RST, w_TX_CRC7_PIPO_EN; logic [1:0] w_TX_SOURCE_SELECT; logic w_CMD_TX_IS_CMD55_RST; logic w_CMD_TX_IS_CMD55_EN; //logic w_CMD_RX; logic w_RX_SIPO48_RST, w_RX_SIPO48_EN; (* mark_debug = "true" *)logic [39:8] r_RESPONSE_CONTENT; (* mark_debug = "true" *)logic [45:40] r_RESPONSE_INDEX; logic w_RX_CRC7_SIPO_RST, w_RX_CRC7_SIPO_EN; logic [6:0] r_RX_CRC7_Q; logic w_RCA_REGISTER_RST, w_RCA_REGISTER_EN; logic w_CMD_TX_DONE; logic w_DAT_RX_DONE; logic w_DAT_ERROR_FD_RST_DAT, w_DAT_ERROR_FD_RST_CMD, w_DAT_ERROR_FD_RST, w_DAT_ERROR_FD_EN; (* mark_debug = "true" *)logic r_DAT_ERROR_Q; // CRC16 error or time out (* mark_debug = "true" *)logic w_NOT_DAT_ERROR_Q; // '0'=no error, '1'=tx error on DAT bus (* mark_debug = "true" *)logic w_ERROR_DAT_TIMES_OUT; (* mark_debug = "true" *)logic w_FATAL_ERROR; (* mark_debug = "true" *)logic [2:0] r_ERROR_CODE_Q; // indicates which fatal error occured // Communication with core (* mark_debug = "true" *)logic w_READY_FOR_READ; (* mark_debug = "true" *)logic w_READ_REQUEST; (* mark_debug = "true" *)logic [3:0] r_DATA_TO_CORE; (* mark_debug = "true" *)logic w_DATA_VALID; (* mark_debug = "true" *)logic w_LAST_NIBBLE; //SD_DAT_FSM Connections logic w_DAT_TIMER_LOAD, w_DAT_TIMER_EN; logic w_DAT_COUNTER_RST, w_DAT_COUNTER_EN; logic w_CRC16_EN, w_CRC16_RST; logic w_BUSY_RST, w_BUSY_EN; logic w_NIBO_EN; logic w_DATA_CRC16_GOOD; logic w_VALID_BLOCK_D, w_VALID_BLOCK_EN, w_VALID_WIDE_D, w_VALID_WIDE_EN; logic [22:0] w_DAT_TIMER_IN; logic [22:0] r_DAT_TIMER_OUT; logic [10:0] r_DAT_COUNTER_OUT; (* mark_debug = "true" *)logic [3:0] r_DAT_Q; // RCA Register logic [15:0] w_RCA_D_Q; logic [15:0] r_RCA_Q2; // Multiplexer Logics logic [132:0] w_instruction_control_bits; logic [132:130] w_R_TYPE ; logic [129:128] w_USES_DAT ; logic [127:96] w_NO_REDO_MASK ; logic [95:64] w_NO_REDO_ANS ; logic [63:32] w_NO_ERROR_MASK ; logic [31:0] w_NO_ERROR_ANS ; logic [45:40] w_command_index ; logic [39:8] w_command_arguments ; logic [47:8] w_command_head ; (* mark_debug = "true" *)logic [6:0] w_OPCODE_Q ; // TOP_LEVEL Connections logic [40:9] w_BLOCK_ADDR ; (* mark_debug = "true" *)logic [3:0] r_IC_OUT ; logic [2:0] r_command_index_is_55_history ; // [0] is live index, [1] is currently saved index, [2] is index of previous command logic r_previous_command_index_was_55_q; // is index of previous command 55, wired to r_command_index_is_55_history[2] logic r_ACMD_Q; // if the previous command sent to the SD card successfully had index 55, then the SD card thinks the current command is ACMD logic [4095:0] r_block_data ; // data block from CMD17 // TX logic [45:8] w_command_content; // first 40 bits of command packet logic w_tx_head_Q; // transmission of first part of command packet logic w_tx_tail_Q; // transmission of last part of command packet logic [7:0] r_command_tail; // last 8 bits of command packet logic [6:0] r_TX_CRC7; //logic w_TX_Q:= '0'; // actual transmission when tx is enabled // RX logic [47:0] r_RX_RESPONSE; // Tri state IO Driver BC18MIMS logic w_SD_CMD_TX_Q; // Write Data logic w_SD_CMD_RX; // Read Data // CLOCKS //logic r_CLK_HS := '0'; // 50 MHz Divided Clock [static] //logic r_SD_CLK_ungated := '0'; // Selected clock before it is clock gated //logic r_SD_CLK := '0'; // GATED CLOCKS logic r_TO_SD_CLK; // What is actually sent to the SD card logic w_G_CLK_SD_EN; logic r_CLK_SD, r_G_CLK_SD; // clocks logic r_G_CLK_SD_n; logic [15:0] r_CLK_FSM_RST ; // a_rst logic delayed by one 1.2 GHz period logic w_SD_CLK_SELECTED; //DAT FSM Connections logic [15:0] r_DAT3_CRC16, r_DAT2_CRC16, r_DAT1_CRC16; logic [15:0] r_DAT0_CRC16; assign w_BLOCK_ADDR = {8'h00, i_BLOCK_ADDR}; // (40 downto 36 are zero since card is 64 GB) // (35 downto 32 are zero since memeory is only 8GB total) assign o_READY_FOR_READ = w_READY_FOR_READ; assign w_READ_REQUEST = i_READ_REQUEST; assign o_DATA_TO_CORE = r_DATA_TO_CORE; assign o_DATA_VALID = w_DATA_VALID; assign o_LAST_NIBBLE = (w_LAST_NIBBLE | w_FATAL_ERROR); // indicate done if (last nibble OR Fatal Error go high) assign o_FATAL_ERROR = w_FATAL_ERROR; sd_cmd_fsm my_sd_cmd_fsm ( .CLK(r_G_CLK_SD), .i_RST(a_RST), .o_TIMER_LOAD(w_TIMER_LOAD), .o_TIMER_EN(w_TIMER_EN), .o_TIMER_IN(w_TIMER_IN), .i_TIMER_OUT(r_TIMER_OUT), .o_COUNTER_LOAD(w_COUNTER_LOAD), .o_COUNTER_EN(w_COUNTER_EN), .o_COUNTER_IN(w_COUNTER_IN), .i_COUNTER_OUT(r_COUNTER_OUT), .o_SD_CLK_EN(w_SD_CLK_EN), .i_CLOCK_CHANGE_DONE(w_CLOCK_CHANGE_DONE), .o_START_CLOCK_CHANGE(w_START_CLOCK_CHANGE), .o_IC_RST(w_IC_RST), .o_IC_EN(w_IC_EN), .o_IC_UP_DOWN(w_IC_UP_DOWN), .i_IC_OUT(r_IC_OUT), .i_USES_DAT(w_USES_DAT), .i_OPCODE(w_OPCODE_Q), .i_R_TYPE(w_R_TYPE), .i_NO_REDO_MASK(w_NO_REDO_MASK), .i_NO_REDO_ANS(w_NO_REDO_ANS), .i_NO_ERROR_MASK(w_NO_ERROR_MASK), .i_NO_ERROR_ANS(w_NO_ERROR_ANS), .o_SD_CMD_OE(w_SD_CMD_OE), .o_TX_PISO40_LOAD(w_TX_PISO40_LOAD), .o_TX_PISO40_EN(w_TX_PISO40_EN), .o_TX_PISO8_LOAD(w_TX_PISO8_LOAD), .o_TX_PISO8_EN(w_TX_PISO8_EN), .o_TX_CRC7_PIPO_RST(w_TX_CRC7_PIPO_RST), .o_TX_CRC7_PIPO_EN(w_TX_CRC7_PIPO_EN), .o_TX_SOURCE_SELECT(w_TX_SOURCE_SELECT), .o_CMD_TX_IS_CMD55_RST(w_CMD_TX_IS_CMD55_RST), .o_CMD_TX_IS_CMD55_EN(w_CMD_TX_IS_CMD55_EN), .i_SD_CMD_RX(w_SD_CMD_RX), .o_RX_SIPO48_RST(w_RX_SIPO48_RST), .o_RX_SIPO48_EN(w_RX_SIPO48_EN), .i_RESPONSE_CONTENT(r_RESPONSE_CONTENT), .i_RESPONSE_INDEX(r_RESPONSE_INDEX), .o_RX_CRC7_SIPO_RST(w_RX_CRC7_SIPO_RST), .o_RX_CRC7_SIPO_EN(w_RX_CRC7_SIPO_EN), .i_RX_CRC7(r_RX_CRC7_Q), .o_RCA_REGISTER_RST(w_RCA_REGISTER_RST), .o_RCA_REGISTER_EN(w_RCA_REGISTER_EN), .o_CMD_TX_DONE(w_CMD_TX_DONE), .i_DAT_RX_DONE(w_DAT_RX_DONE), .i_ERROR_CRC16(w_NOT_DAT_ERROR_Q), .i_ERROR_DAT_TIMES_OUT(w_ERROR_DAT_TIMES_OUT), .i_READ_REQUEST(w_READ_REQUEST), .o_READY_FOR_READ(w_READY_FOR_READ), .o_SD_RESTARTING(o_SD_RESTARTING), .o_DAT_ERROR_FD_RST(w_DAT_ERROR_FD_RST_CMD), .o_ERROR_CODE_Q(r_ERROR_CODE_Q), .o_FATAL_ERROR(w_FATAL_ERROR), .LIMIT_SD_TIMERS(LIMIT_SD_TIMERS)); assign o_ERROR_CODE_Q = r_ERROR_CODE_Q; sd_dat_fsm my_sd_dat_fsm (.CLK(r_G_CLK_SD), .i_RST(a_RST), .o_TIMER_LOAD(w_DAT_TIMER_LOAD), .o_TIMER_EN(w_DAT_TIMER_EN), .o_TIMER_IN(w_DAT_TIMER_IN), .i_TIMER_OUT(r_DAT_TIMER_OUT), .i_SD_CLK_SELECTED(w_SD_CLK_SELECTED), .o_COUNTER_RST(w_DAT_COUNTER_RST), .o_COUNTER_EN(w_DAT_COUNTER_EN), .i_COUNTER_OUT(r_DAT_COUNTER_OUT), .o_CRC16_EN(w_CRC16_EN), .o_CRC16_RST(w_CRC16_RST), .i_DATA_CRC16_GOOD(w_DATA_CRC16_GOOD), .o_BUSY_RST(w_BUSY_RST), .o_BUSY_EN(w_BUSY_EN), .i_DAT0_Q(r_DAT_Q[0]), .o_NIBO_EN(w_NIBO_EN), .i_USES_DAT(w_USES_DAT), .i_CMD_TX_DONE(w_CMD_TX_DONE), .o_DAT_RX_DONE(w_DAT_RX_DONE), .o_ERROR_DAT_TIMES_OUT(w_ERROR_DAT_TIMES_OUT), .o_DATA_VALID(w_DATA_VALID), .o_LAST_NIBBLE(w_LAST_NIBBLE), .o_DAT_ERROR_FD_RST(w_DAT_ERROR_FD_RST_DAT), .o_DAT_ERROR_FD_EN(w_DAT_ERROR_FD_EN), .LIMIT_SD_TIMERS(LIMIT_SD_TIMERS)); assign w_DAT_ERROR_FD_RST = w_DAT_ERROR_FD_RST_CMD | w_DAT_ERROR_FD_RST_DAT; flopenr #(1) dat_error_fd (.clk(r_G_CLK_SD), .d(w_DATA_CRC16_GOOD), .q(r_DAT_ERROR_Q), .en(w_DAT_ERROR_FD_EN), .reset((w_DAT_ERROR_FD_RST))); assign w_NOT_DAT_ERROR_Q = ~r_DAT_ERROR_Q; up_down_counter #(23) dat_fsm_timer ( .CountIn(w_DAT_TIMER_IN), .CountOut(r_DAT_TIMER_OUT), .Load(w_DAT_TIMER_LOAD), .Enable(w_DAT_TIMER_EN), .UpDown(1'b0), // Count DOWN only .clk(r_G_CLK_SD), .reset(1'b0)); // No Reset, Just Load SDCcounter #(11) dat_nibble_counter ( .CountIn('0), .CountOut(r_DAT_COUNTER_OUT), .Load(1'b0), .Enable(w_DAT_COUNTER_EN), .clk(r_G_CLK_SD), .reset(w_DAT_COUNTER_RST)); regfile_p2r1w1_nibo #(.DEPTH(10), .WIDTH(4) ) regfile_cmd17_data_block // Nibble In - Nibble Out (NINO) (.clk(r_G_CLK_SD), .we1(w_NIBO_EN), .ra1(r_DAT_COUNTER_OUT[9:0]), // Nibble Read (to core) Address .rd1(r_DATA_TO_CORE), // output nibble to core .Rd1All(ReadData), .wa1(r_DAT_COUNTER_OUT[9:0]), // Nibble Write (to host) Address .wd1(r_DAT_Q)); // input nibble from card crc16_sipo_np_ce crc16_sipo_np_ce_DAT3 (.CLK(r_G_CLK_SD), .RST(w_CRC16_RST), .i_enable(w_CRC16_EN), .i_message_bit(r_DAT_Q[3]), .o_crc16(r_DAT3_CRC16)); crc16_sipo_np_ce crc16_sipo_np_ce_DAT2 (.CLK(r_G_CLK_SD), .RST(w_CRC16_RST), .i_enable(w_CRC16_EN), .i_message_bit(r_DAT_Q[2]), .o_crc16(r_DAT2_CRC16)); crc16_sipo_np_ce crc16_sipo_np_ce_DAT1 (.CLK(r_G_CLK_SD), .RST(w_CRC16_RST), .i_enable(w_CRC16_EN), .i_message_bit(r_DAT_Q[1]), .o_crc16(r_DAT1_CRC16)); crc16_sipo_np_ce crc16_sipo_np_ce_DAT0 (.CLK(r_G_CLK_SD), .RST(w_CRC16_RST), .i_enable(w_CRC16_EN), .i_message_bit(r_DAT_Q[0]), .o_crc16(r_DAT0_CRC16)); assign w_DATA_CRC16_GOOD = ({r_DAT3_CRC16, r_DAT2_CRC16, r_DAT1_CRC16, r_DAT0_CRC16}) == 64'h0000000000000000; flopenr #(4) busy_bit_fd (.en(w_BUSY_EN), .clk(r_G_CLK_SD), .d(i_SD_DAT), .q(r_DAT_Q), .reset(w_BUSY_RST)); sd_clk_fsm my_clk_fsm (.CLK(CLK), .i_RST(a_RST), .o_DONE(w_CLOCK_CHANGE_DONE), .i_START(w_START_CLOCK_CHANGE), .o_HS_TO_INIT_CLK_DIVIDER_RST(w_HS_TO_INIT_CLK_DIVIDER_RST), .o_SD_CLK_SELECTED(w_SD_CLK_SELECTED), .i_FATAL_ERROR(w_FATAL_ERROR), .o_G_CLK_SD_EN(w_G_CLK_SD_EN)); up_down_counter #(19) cmd_fsm_timer (.CountIn(w_TIMER_IN), .CountOut(r_TIMER_OUT), .Load(w_TIMER_LOAD), .Enable(w_TIMER_EN), .UpDown(1'b0), // Count DOWN only .clk(r_G_CLK_SD), .reset(1'b0)); // No Reset, Just Load up_down_counter #(8) cmd_fsm_counter (.CountIn(w_COUNTER_IN), .CountOut(r_COUNTER_OUT), .Load(w_COUNTER_LOAD), .Enable(w_COUNTER_EN), .UpDown(1'b0), // Count DOWN only .clk(r_G_CLK_SD), .reset(1'b0)); // No RESET, only LOAD up_down_counter #(4) instruction_counter (.CountIn('0), // No CountIn, only RESET .CountOut(r_IC_OUT), .Load(1'b0), // No LOAD, only RESET .Enable(w_IC_EN), .UpDown(w_IC_UP_DOWN), .clk(r_G_CLK_SD), .reset(w_IC_RST | a_RST)); // Clock selection clkdivider #(g_COUNT_WIDTH) slow_clk_divider // Divide 50 MHz to <400 KHz (Initial clock) (.i_COUNT_IN_MAX(i_COUNT_IN_MAX), .i_EN(w_SD_CLK_SELECTED), //.i_EN(1'b1), //.i_RST(w_HS_TO_INIT_CLK_DIVIDER_RST), .i_RST(a_RST), .i_CLK(CLK), .o_CLK(r_CLK_SD)); clockgater sd_clk_gater // Select which clock goes to components (.CLK(r_CLK_SD), .E(w_G_CLK_SD_EN | a_RST), .SE(1'b0), .ECLK(r_G_CLK_SD)); clockgater to_sd_clk_gater // Enable activity on the SD_CLK line (.CLK(r_G_CLK_SD), .E(w_SD_CLK_EN), .SE(1'b0), .ECLK(r_TO_SD_CLK)); flopenr #(16) RCA_register_CE (.clk(r_G_CLK_SD), .en(w_RCA_REGISTER_EN), .d(w_RCA_D_Q), .q(r_RCA_Q2), .reset(w_RCA_REGISTER_RST)); // ACMD_Detector flopenr #(1) index_history_fd_2to1 (.clk(r_G_CLK_SD), .reset(w_CMD_TX_IS_CMD55_RST), .en(w_CMD_TX_IS_CMD55_EN), .d(r_command_index_is_55_history[2]), .q(r_command_index_is_55_history[1])); flopenr #(1) index_history_fd_1to0 (.clk(r_G_CLK_SD), .reset(w_CMD_TX_IS_CMD55_RST), .en(w_CMD_TX_IS_CMD55_EN), .d(r_command_index_is_55_history[1]), .q(r_command_index_is_55_history[0])); assign r_command_index_is_55_history[2] = (w_command_index == 55); assign r_previous_command_index_was_55_q = r_command_index_is_55_history[0]; assign r_ACMD_Q = r_previous_command_index_was_55_q; // if the previous command WAS 55, the current command is ACMD assign o_SD_CLK = r_TO_SD_CLK; // Multiplexers //Fetch index and argument of command assign w_command_content = (r_IC_OUT == 0) ? ({c_Go_Idle_State, 32'h00000000}) : // CMD0 (r_IC_OUT == 1) ? ({c_Send_IF_State, 32'h000001FF}) : // CMD8 (r_IC_OUT == 2) ? ({c_App_Command, 32'h00000000}) : // CMD55 (r_IC_OUT == 3) ? ({c_SD_Send_OCR, 32'h40FF8000}) : // ACMD41 (r_IC_OUT == 4) ? ({c_All_Send_CID, 32'h00000000}) : // CMD2 (r_IC_OUT == 5) ? ({c_SD_Send_RCA, 32'h00000000}) : // CMD3 (r_IC_OUT == 6) ? ({c_Select_Card, r_RCA_Q2[15:0], 16'h0000}) : // CMD7 (r_IC_OUT == 7) ? ({c_App_Command, r_RCA_Q2[15:0], 16'h0000}) : // CMD55 (r_IC_OUT == 8) ? ({c_Set_Bus_Width, 32'h00000002}) : // ACMD6 (r_IC_OUT == 9) ? ({c_Switch_Function, 32'h80FFFFF1}) : // CMD6 (r_IC_OUT == 10) ? ({c_Read_Single_Block, w_BLOCK_ADDR}) : // CMD17 ({c_Read_Single_Block, w_BLOCK_ADDR}); // when in doubt just send CMD17 assign w_command_index = w_command_content[45:40]; assign w_command_arguments = w_command_content[39:8]; assign w_command_head = {c_start_bit, c_tx_host_command, w_command_content}; assign w_OPCODE_Q = {r_ACMD_Q, w_command_index}; // TX crc7_pipo tx_crc7_pipo (.CLK(r_G_CLK_SD), .i_DATA(w_command_head), .i_CRC_ENABLE(w_TX_CRC7_PIPO_EN), .RST(w_TX_CRC7_PIPO_RST), .o_CRC(r_TX_CRC7)); assign r_command_tail = {r_TX_CRC7, c_stop_bit}; piso_generic_ce #(40) tx_piso40_command_head (.clk(r_G_CLK_SD), .i_load(w_TX_PISO40_LOAD), .i_data(w_command_head), .i_en(w_TX_PISO40_EN), .o_data(w_tx_head_Q)); piso_generic_ce #(8) tx_piso8_command_tail (.clk(r_G_CLK_SD), .i_load(w_TX_PISO8_LOAD), .i_data(r_command_tail), .i_en(w_TX_PISO8_EN), .o_data(w_tx_tail_Q)); assign w_SD_CMD_TX_Q = (w_TX_SOURCE_SELECT == c_tx_low) ? 1'b0 : (w_TX_SOURCE_SELECT == c_tx_high) ? 1'b1 : (w_TX_SOURCE_SELECT == c_tx_head) ? w_tx_head_Q : (w_TX_SOURCE_SELECT == c_tx_tail) ? w_tx_tail_Q : 1'b0; assign w_SD_CMD_RX = i_SD_CMD; flopenr #(1) sd_cmd_out_reg (.d(w_SD_CMD_TX_Q), .q(o_SD_CMD), .en(1'b1), .clk(~r_G_CLK_SD), .reset(a_RST)); flopenr #(1) sd_cmd_out_oe_reg (.d(w_SD_CMD_OE), .q(o_SD_CMD_OE), .en(1'b1), .clk(~r_G_CLK_SD), .reset(a_RST)); // RX sipo_generic_ce #(48) rx_sipo48_response_content (.clk(r_G_CLK_SD), .rst(w_RX_SIPO48_RST), .i_enable(w_RX_SIPO48_EN), .i_message_bit(w_SD_CMD_RX), .o_data(r_RX_RESPONSE)); assign r_RESPONSE_CONTENT = r_RX_RESPONSE[39:8]; assign r_RESPONSE_INDEX = r_RX_RESPONSE[45:40]; assign w_RCA_D_Q = r_RESPONSE_CONTENT[39:24]; crc7_sipo_np_ce rx_crc7_sipo (.clk(r_G_CLK_SD), .rst(w_RX_CRC7_SIPO_RST), .i_enable(w_RX_CRC7_SIPO_EN), .i_message_bit(w_SD_CMD_RX), .o_crc7(r_RX_CRC7_Q)); // Fetch control bits using r_opcode assign w_instruction_control_bits = (w_OPCODE_Q == ({c_CMD, c_Go_Idle_State})) ? ({c_response_type_R0_NONE, c_DAT_none, c_CMD0_mask_check_redo_bits, c_CMD0_ans_dont_redo, c_CMD0_mask_check_error_bits, c_CMD0_ans_error_free}) : // CMD0 (w_OPCODE_Q == ({c_CMD, c_All_Send_CID})) ? ({c_response_type_R2_CID_CSD, c_DAT_none, c_CMD2_mask_check_redo_bits, c_CMD2_ans_dont_redo, c_CMD2_mask_check_error_bits, c_CMD2_ans_error_free}): // CMD2 (w_OPCODE_Q == ({c_CMD, c_SD_Send_RCA})) ? ({c_response_type_R6_RCA, c_DAT_none, c_CMD3_mask_check_redo_bits, c_CMD3_ans_dont_redo, c_CMD3_mask_check_error_bits, c_CMD3_ans_error_free}) : // CMD3 (w_OPCODE_Q == ({c_CMD, c_Switch_Function})) ? ({c_response_type_R1_NORMAL, c_DAT_wide, c_CMD6_mask_check_redo_bits, c_CMD6_ans_dont_redo, c_CMD6_mask_check_error_bits, c_CMD6_ans_error_free}): // CMD6 (w_OPCODE_Q == ({c_ACMD, c_Set_Bus_Width})) ? ({c_response_type_R1_NORMAL, c_DAT_none, c_ACMD6_mask_check_redo_bits, c_ACMD6_ans_dont_redo, c_ACMD6_mask_check_error_bits, c_ACMD6_ans_error_free}): //ACMD6 (w_OPCODE_Q == ({c_CMD, c_Select_Card})) ? ({c_response_type_R1_NORMAL, c_DAT_busy, c_CMD7_mask_check_redo_bits, c_CMD7_ans_dont_redo, c_CMD7_mask_check_error_bits, c_CMD7_ans_error_free}): // CMD7 (w_OPCODE_Q == ({c_CMD, c_Send_IF_State})) ? ({c_response_type_R7_CIC, c_DAT_none, c_CMD8_mask_check_redo_bits, c_CMD8_ans_dont_redo, c_CMD8_mask_check_error_bits, c_CMD8_ans_error_free}): // CMD8 (w_OPCODE_Q == ({c_CMD, c_Read_Single_Block})) ? ({c_response_type_R1_NORMAL, c_DAT_block, c_CMD17_mask_check_redo_bits, c_CMD17_ans_dont_redo, c_CMD17_mask_check_error_bits, c_CMD17_ans_error_free}): // CMD17 (w_OPCODE_Q == ({c_ACMD, c_SD_Send_OCR})) ? ({c_response_type_R3_OCR, c_DAT_none, c_ACMD41_mask_check_redo_bits, c_ACMD41_ans_dont_redo, c_ACMD41_mask_check_error_bits, c_ACMD41_ans_error_free}) : //ACMD41 (w_OPCODE_Q == ({c_CMD, c_App_Command})) ? ({c_response_type_R1_NORMAL, c_DAT_none, c_CMD55_mask_check_redo_bits, c_CMD55_ans_dont_redo, c_CMD55_mask_check_error_bits, c_CMD55_ans_error_free}) : // CMD55 (w_OPCODE_Q == ({c_ACMD, c_App_Command})) ? ({c_response_type_R1_NORMAL, c_DAT_none, c_ACMD55_mask_check_redo_bits, c_ACMD55_ans_dont_redo, c_ACMD55_mask_check_error_bits, c_ACMD55_ans_error_free}) : //ACMD55 ({c_response_type_R1_NORMAL, c_DAT_none, c_ACMD55_mask_check_redo_bits, c_ACMD55_ans_dont_redo, c_ACMD55_mask_check_error_bits, c_ACMD55_ans_error_free}); // when in doubt just send ACMD55 assign w_R_TYPE = w_instruction_control_bits[132:130]; assign w_USES_DAT = w_instruction_control_bits[129:128]; assign w_NO_REDO_MASK = w_instruction_control_bits[127:96]; assign w_NO_REDO_ANS = w_instruction_control_bits[95:64]; assign w_NO_ERROR_MASK = w_instruction_control_bits[63:32]; assign w_NO_ERROR_ANS = w_instruction_control_bits[31:0]; endmodule