mirror of
https://github.com/openhwgroup/cvw
synced 2025-02-11 06:05:49 +00:00
660 lines
28 KiB
Systemverilog
660 lines
28 KiB
Systemverilog
///////////////////////////////////////////
|
|
// 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
|
|
|