Initial SD Card reader.

This commit is contained in:
Ross Thompson 2021-09-22 10:50:29 -05:00
parent 221dbe92b2
commit ec0d2bc7d7
24 changed files with 4092 additions and 0 deletions

View File

@ -0,0 +1,55 @@
SD Flash interface
regsiter map:
1. clock divider
2. address
3. data register
4. command register
5. size register
Number of bytes to read or write.
6. status register
1. bits 11 to 0: bytes currently in the buffer
2. bits 12 to 29: reservered
3. bit 30: fault
4. bit 31: busy
5. bits XLEN-1 to 32: reservered
non dma read operation
1. write the address regsiter
2. write the command register to read
3. wait for interrupt or pool on status
4. Check status for fault and number of bytes.
5. read the data register for 512 bytes. (64 ld, or 128 lw)
non dma write operation
1. write address register
2. write data register for 512 bytes. (64 sd, or 128 sw)
3. write command register to write data to flash
4. wait for interrupt or pool on status
5. check status for fault and number of bytes written.
implement dma transfers later
interrupts
1. operation done
2. bus error (more of an exception)
Occurs if attempting to do an operation while the flash controller is busy.
ie. if status[31] is set generate an interrupt
This is tricky in a multiprocessor environment.
tasks
1. [-] Remove all AFRL identifiers
2. [X] get the existing sdc compiled on wally.
1. [X] use wally primatives over tcore's
3. build abhlite interface with the above registers and necessary fsm.
1. [ ] The sd card reader uses a 4 bit data interface. We can change this to be something
more pratical.
4. write test programs
5. [X] Convert VHDL to system verilog

View File

@ -0,0 +1,72 @@
///////////////////////////////////////////
// clock divider.sv
//
// Written: Ross Thompson September 18, 2021
// Modified:
//
// Purpose: clock divider for sd flash
//
// 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 clkdivider #(parameter integer g_COUNT_WIDTH)
(
input logic [g_COUNT_WIDTH-1:0] i_COUNT_IN_MAX, //((Divide by value)/2) - 1
input logic i_EN, //Enable frequency division of i_clk
input logic i_CLK, // 1.2 GHz Base clock
input logic i_RST, // at start: clears flip flop and loads counter,
// i_RST must NOT be a_RST, it needs to be synchronized with the 50 MHz Clock to load the
// counter's initial value
output logic o_CLK // frequency divided clock
);
logic [g_COUNT_WIDTH-1:0] r_count_out; // wider for sign
logic w_counter_overflowed;
logic r_fd_Q;
logic w_fd_D;
logic w_load;
assign w_load = i_RST | w_counter_overflowed; // reload when zero occurs or when set by outside
counter #(.WIDTH(g_COUNT_WIDTH)) // wider for sign, this way the (MSB /= '1') only for zero
my_counter (.clk(i_CLK),
.Load(w_load), // reload when zero occurs or when set by outside
.CountIn(i_COUNT_IN_MAX), // negative signed integer
.CountOut(r_count_out),
.Enable(1'b1), // ALWAYS COUNT
.reset(1'b0)); // no reset, only load
assign w_counter_overflowed = r_count_out[g_COUNT_WIDTH-1] == '0;
flopenr #(1) toggle_flip_flop
(.d(w_fd_D),
.q(r_fd_Q),
.clk(i_CLK),
.reset(i_RST), // reset when told by outside
.en(w_counter_overflowed)); // only update when counter overflows
assign w_fd_D = ~ r_fd_Q;
assign o_CLK = i_EN ? r_fd_Q : i_CLK;
endmodule

View File

@ -0,0 +1,54 @@
///////////////////////////////////////////
// counter.sv
//
// Written: Ross Thompson
// Modified:
//
// Purpose: basic up counter
//
// 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 counter #(parameter integer WIDTH=32)
(
input logic [WIDTH-1:0] CountIn,
output logic [WIDTH-1:0] CountOut,
input logic Load,
input logic Enable,
input logic clk,
input logic reset);
logic [WIDTH-1:0] NextCount;
logic [WIDTH-1:0] count_q;
logic [WIDTH-1:0] CountP1;
flopenr #(WIDTH) reg1(.clk,
.reset,
.en(Enable | Load),
.d(NextCount),
.q(CountOut));
assign CountP1 = CountOut + 1'b1;
// mux between load and P1
assign NextCount = Load ? CountIn : CountP1;
endmodule

View File

@ -0,0 +1,62 @@
///////////////////////////////////////////
// crc16 sipo np ce
//
// Written: Ross Thompson September 18, 2021
// Modified:
//
// Purpose: CRC16 generator SIPO using register_ce
// w/o appending any zero-bits to the message
//
// 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 crc16_sipo_np_ce
(input logic CLK, // sequential device
input logic RST, // initial calue of CRC register must be "0000_0000_0000_0000"
input logic i_enable, // input is valid
input logic i_message_bit,
output logic [15:0] o_crc16);
logic [15:0] w_crc16_d;
flopenr #(16) crc16reg(.clk(CLK),
.reset(RST),
.en(i_enable),
.d(w_crc16_d),
.q(o_crc16));
assign w_crc16_d[15] = o_crc16[14];
assign w_crc16_d[14] = o_crc16[13];
assign w_crc16_d[13] = o_crc16[12];
assign w_crc16_d[12] = o_crc16[11] ^ (i_message_bit ^ o_crc16[15]);
assign w_crc16_d[11] = o_crc16[10];
assign w_crc16_d[10] = o_crc16[9];
assign w_crc16_d[9] = o_crc16[8];
assign w_crc16_d[8] = o_crc16[7];
assign w_crc16_d[7] = o_crc16[6];
assign w_crc16_d[6] = o_crc16[5];
assign w_crc16_d[5] = o_crc16[4] ^ (i_message_bit ^ o_crc16[15]);
assign w_crc16_d[4] = o_crc16[3];
assign w_crc16_d[3] = o_crc16[2];
assign w_crc16_d[2] = o_crc16[1];
assign w_crc16_d[1] = o_crc16[0];
assign w_crc16_d[0] = i_message_bit ^ o_crc16[15];
endmodule

View File

@ -0,0 +1,66 @@
///////////////////////////////////////////
// crc7 sipo np ce
//
// Written: Ross Thompson September 18, 2021
// Modified:
//
// Purpose: takes 40 bits of input, generates 7 bit CRC after a single
// clock cycle!
// w/o appending any zero-bits to the message
//
// 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 crc7_pipo
(input logic [39:0] i_DATA,
input logic i_CRC_ENABLE,
input logic RST,
input logic CLK,
output logic [6:0] o_CRC);
logic [6:0] r_lfsr_q;
logic [6:0] w_lfsr_d;
assign o_CRC = r_lfsr_q;
assign w_lfsr_d[0] = r_lfsr_q[1] ^ r_lfsr_q[2] ^ r_lfsr_q[4] ^ r_lfsr_q[6] ^ i_DATA[0] ^ i_DATA[4] ^ i_DATA[7] ^ i_DATA[8] ^ i_DATA[12] ^ i_DATA[14] ^ i_DATA[15] ^ i_DATA[16] ^ i_DATA[18] ^ i_DATA[20] ^ i_DATA[21] ^ i_DATA[23] ^ i_DATA[24] ^ i_DATA[30] ^ i_DATA[31] ^ i_DATA[34] ^ i_DATA[35] ^ i_DATA[37] ^ i_DATA[39];
assign w_lfsr_d[1] = r_lfsr_q[2] ^ r_lfsr_q[3] ^ r_lfsr_q[5] ^ i_DATA[1] ^ i_DATA[5] ^ i_DATA[8] ^ i_DATA[9] ^ i_DATA[13] ^ i_DATA[15] ^ i_DATA[16] ^ i_DATA[17] ^ i_DATA[19] ^ i_DATA[21] ^ i_DATA[22] ^ i_DATA[24] ^ i_DATA[25] ^ i_DATA[31] ^ i_DATA[32] ^ i_DATA[35] ^ i_DATA[36] ^ i_DATA[38];
assign w_lfsr_d[2] = r_lfsr_q[0] ^ r_lfsr_q[3] ^ r_lfsr_q[4] ^ r_lfsr_q[6] ^ i_DATA[2] ^ i_DATA[6] ^ i_DATA[9] ^ i_DATA[10] ^ i_DATA[14] ^ i_DATA[16] ^ i_DATA[17] ^ i_DATA[18] ^ i_DATA[20] ^ i_DATA[22] ^ i_DATA[23] ^ i_DATA[25] ^ i_DATA[26] ^ i_DATA[32] ^ i_DATA[33] ^ i_DATA[36] ^ i_DATA[37] ^ i_DATA[39];
assign w_lfsr_d[3] = r_lfsr_q[0] ^ r_lfsr_q[2] ^ r_lfsr_q[5] ^ r_lfsr_q[6] ^ i_DATA[0] ^ i_DATA[3] ^ i_DATA[4] ^ i_DATA[8] ^ i_DATA[10] ^ i_DATA[11] ^ i_DATA[12] ^ i_DATA[14] ^ i_DATA[16] ^ i_DATA[17] ^ i_DATA[19] ^ i_DATA[20] ^ i_DATA[26] ^ i_DATA[27] ^ i_DATA[30] ^ i_DATA[31] ^ i_DATA[33] ^ i_DATA[35] ^ i_DATA[38] ^ i_DATA[39];
assign w_lfsr_d[4] = r_lfsr_q[1] ^ r_lfsr_q[3] ^ r_lfsr_q[6] ^ i_DATA[1] ^ i_DATA[4] ^ i_DATA[5] ^ i_DATA[9] ^ i_DATA[11] ^ i_DATA[12] ^ i_DATA[13] ^ i_DATA[15] ^ i_DATA[17] ^ i_DATA[18] ^ i_DATA[20] ^ i_DATA[21] ^ i_DATA[27] ^ i_DATA[28] ^ i_DATA[31] ^ i_DATA[32] ^ i_DATA[34] ^ i_DATA[36] ^ i_DATA[39];
assign w_lfsr_d[5] = r_lfsr_q[0] ^ r_lfsr_q[2] ^ r_lfsr_q[4] ^ i_DATA[2] ^ i_DATA[5] ^ i_DATA[6] ^ i_DATA[10] ^ i_DATA[12] ^ i_DATA[13] ^ i_DATA[14] ^ i_DATA[16] ^ i_DATA[18] ^ i_DATA[19] ^ i_DATA[21] ^ i_DATA[22] ^ i_DATA[28] ^ i_DATA[29] ^ i_DATA[32] ^ i_DATA[33] ^ i_DATA[35] ^ i_DATA[37];
assign w_lfsr_d[6] = r_lfsr_q[0] ^ r_lfsr_q[1] ^ r_lfsr_q[3] ^ r_lfsr_q[5] ^ i_DATA[3] ^ i_DATA[6] ^ i_DATA[7] ^ i_DATA[11] ^ i_DATA[13] ^ i_DATA[14] ^ i_DATA[15] ^ i_DATA[17] ^ i_DATA[19] ^ i_DATA[20] ^ i_DATA[22] ^ i_DATA[23] ^ i_DATA[29] ^ i_DATA[30] ^ i_DATA[33] ^ i_DATA[34] ^ i_DATA[36] ^ i_DATA[38];
flopenr #(7)
lfsrReg(.clk(CLK),
.reset(RST),
.en(i_CRC_ENABLE),
.d(w_lfsr_d),
.q(r_lfsr_q));
endmodule

View File

@ -0,0 +1,61 @@
///////////////////////////////////////////
// crc16 sipo np ce
//
// Written: Ross Thompson September 18, 2021
// Modified:
//
// Purpose: CRC7 generator SIPO using register_ce
// w/o appending any zero-bits othe message
//
// 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 crc7_sipo_np_ce
(
input logic clk,
input logic rst,// initial CRC value must be b"000_0000"
input logic i_enable,
input logic i_message_bit,
output logic [6:0] o_crc7);
logic [6:0] w_crc7_d;
logic [6:0] r_crc7_q;
flopenr #(7)
crc7Reg(.clk(clk),
.reset(rst),
.en(i_enable),
.d(w_crc7_d),
.q(r_crc7_q));
assign w_crc7_d[6] = r_crc7_q[5];
assign w_crc7_d[5] = r_crc7_q[4];
assign w_crc7_d[4] = r_crc7_q[3];
assign w_crc7_d[3] = r_crc7_q[2] ^ (i_message_bit ^ r_crc7_q[6]);
assign w_crc7_d[2] = r_crc7_q[1];
assign w_crc7_d[1] = r_crc7_q[0];
assign w_crc7_d[0] = i_message_bit ^ r_crc7_q[6];
assign o_crc7 = r_crc7_q;
endmodule

View File

@ -0,0 +1,51 @@
///////////////////////////////////////////
// piso generic ce
//
// Written: Ross Thompson September 18, 2021
// Modified:
//
//
// 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 piso_generic_ce #(parameter integer g_BUS_WIDTH)
(
input logic clk,
input logic i_load,
input logic [g_BUS_WIDTH-1:0] i_data,
input logic i_en,
output o_data);
logic [g_BUS_WIDTH-1:0] w_reg_d;
logic [g_BUS_WIDTH-1:0] r_reg_q;
flopenr #(g_BUS_WIDTH)
shiftReg(.clk(clk),
.reset(1'b0),
.en(1'b1),
.d(w_reg_d),
.q(r_reg_q));
assign o_data = i_en ? r_reg_q[g_BUS_WIDTH - 1] : 1'b1;
assign w_reg_d = i_load ? i_data :
i_en ? {r_reg_q[g_BUS_WIDTH - 2 : 0], 1'b1} :
r_reg_q[g_BUS_WIDTH - 1 : 0];
endmodule

View File

@ -0,0 +1,45 @@
///////////////////////////////////////////
// regfile_p2r1w1_nibo
//
// Written: Ross Thompson September 18, 2021
// Modified: 2 port register file with 1 read and 1 write
//
//
// 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 regfile_p2r1w1_nibo #(parameter integer DEPTH = 10, parameter integer WIDTH = 4)
(input logic clk,
input logic we1,
input logic [DEPTH-1:0] ra1,
output logic [WIDTH-1:0] rd1,
input logic [DEPTH-1:0] wa1,
input logic [WIDTH-1:0] wd1);
logic [WIDTH-1:0] regs [2**DEPTH-1:0];
always_ff @(posedge clk) begin
if(we1) begin
regs[wa1] <= wd1;
end
end
assign rd1 = regs[ra1];
endmodule

View File

@ -0,0 +1,51 @@
///////////////////////////////////////////
// regfile_p2r1w1bwen
//
// Written: Ross Thompson September 18, 2021
// Modified: 2 port register file with 1 read and 1 write
//
//
// 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 regfile_p2r1w1bwen #(parameter integer DEPTH = 10, parameter integer WIDTH = 4)
(input logic clk,
input logic we1,
input logic [WIDTH-1:0] we1bit,
input logic [DEPTH-1:0] ra1,
output logic [WIDTH-1:0] rd1,
input logic [DEPTH-1:0] wa1,
input logic [WIDTH-1:0] wd1);
logic [WIDTH-1:0] regs [2**DEPTH-1:0];
integer i;
always_ff @(posedge clk) begin
if(we1) begin
for (i=0; i < WIDTH; i++) begin
if(we1bit[i]) begin
regs[wa1][i] <= wd1[i];
end
end
end
end
assign rd1 = regs[ra1];
endmodule

View File

@ -0,0 +1,94 @@
///////////////////////////////////////////
// sd_clk_fsm.sv
//
// Written: Ross Thompson September 19, 2021
// Modified:
//
// Purpose: Controls clock dividers.
// Replaces s_disable_sd_clocks, s_select_hs_clk, s_enable_hs_clk
// in sd_cmd_fsm.vhd. Attempts to correct issues with oversampling and
// under-sampling of control signals (for counter_cmd), that were present in my
// previous design.
// This runs on 50 MHz.
// sd_cmd_fsm will run on SD_CLK_Gated (50 MHz or 400 KHz, selected by this)
// asynchronous reset is used for both sd_cmd_fsm and for this.
// It must be synchronized with 50 MHz and held for a minimum period of a full
// 400 KHz pulse width.
//
// 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_clk_fsm
(
input logic CLK,
input logic i_RST,
output logic o_DONE,
input logic i_START,
input logic i_FATAL_ERROR,
output logic o_HS_TO_INIT_CLK_DIVIDER_RST, // resets clock divider that is going from 50 MHz to 400 KHz
output logic o_SD_CLK_SELECTED, // which clock is selected ('0'=HS or '1'=init)
output logic o_G_CLK_SD_EN); // Turns gated clock (G_CLK_SD) off and on
logic [3:0] w_next_state;
logic [3:0] r_curr_state;
// clock selection
parameter c_sd_clk_init = 1'b1;
parameter c_sd_clk_hs = 1'b0;
// States
localparam s_reset = 4'b0000;
localparam s_enable_init_clk = 4'b0001; // enable 400 KHz
localparam s_disable_sd_clocks = 4'b0010;
localparam s_select_hs_clk = 4'b0011;
localparam s_enable_hs_clk = 4'b0100;
localparam s_done = 4'b0101;
localparam s_disable_sd_clocks_2 = 4'b0110; // if error occurs
localparam s_select_init_clk = 4'b0111; // if error occurs
localparam s_safe_state = 4'b1111; //always provide a safe state return if all states are not used
flopenr #(4) stateReg(.clk(CLK),
.reset(i_RST),
.en(1'b1),
.d(w_next_state),
.q(r_curr_state));
assign w_next_state = i_RST ? s_reset :
r_curr_state == s_reset | (r_curr_state == s_enable_init_clk & ~i_START) | (r_curr_state == s_select_init_clk) ? s_enable_init_clk :
r_curr_state == s_enable_init_clk & i_START ? s_disable_sd_clocks :
r_curr_state == s_disable_sd_clocks ? s_select_hs_clk :
r_curr_state == s_select_hs_clk ? s_enable_hs_clk :
r_curr_state == s_enable_hs_clk | (r_curr_state == s_done & ~i_FATAL_ERROR) ? s_done :
r_curr_state == s_done & i_FATAL_ERROR ? s_disable_sd_clocks_2 :
r_curr_state == s_disable_sd_clocks_2 ? s_select_init_clk :
s_safe_state;
assign o_HS_TO_INIT_CLK_DIVIDER_RST = r_curr_state == s_reset;
assign o_SD_CLK_SELECTED = (r_curr_state == s_select_hs_clk) | (r_curr_state == s_enable_hs_clk) | (r_curr_state == s_done) ? c_sd_clk_hs : c_sd_clk_init;
assign o_G_CLK_SD_EN = (r_curr_state == s_enable_init_clk) | (r_curr_state == s_enable_hs_clk) | (r_curr_state == s_done);
assign o_DONE = r_curr_state == s_done;
endmodule

View File

@ -0,0 +1,554 @@
///////////////////////////////////////////
// sd_clk_fsm.sv
//
// Written: Ross Thompson September 19, 2021
// Modified:
//
// Purpose: Finite state machine for the SD CMD bus
//
// 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_cmd_fsm
(
input logic CLK, // HS
//i_SLOWER_CLK : in std_logic;
input logic i_RST, // reset FSM,
// MUST COME OUT OF RESET
// SYNCHRONIZED TO THE 1.2 GHZ CLOCK!
output logic o_TIMER_LOAD, o_TIMER_EN, // Timer
output logic [18:0] o_TIMER_IN,
input logic [18:0] i_TIMER_OUT,
output logic o_COUNTER_LOAD, o_COUNTER_EN, // Counter
output logic [7:0] o_COUNTER_IN,
input logic [7:0] i_COUNTER_OUT,
output logic o_SD_CLK_EN, // Clock Gaters
input logic i_CLOCK_CHANGE_DONE, // Communication with CLK_FSM
output logic o_START_CLOCK_CHANGE, // Communication with CLK_FSM
output logic o_IC_RST, o_IC_EN, o_IC_UP_DOWN, // Instruction counter
input logic [3:0] i_IC_OUT, // stop when you get to 10 because that is CMD17
input logic [1:0] i_USES_DAT,
input logic [6:0] i_OPCODE,
input logic [2:0] i_R_TYPE,
// bit masks
input logic [31:0] i_NO_REDO_MASK,
input logic [31:0] i_NO_REDO_ANS,
input logic [31:0] i_NO_ERROR_MASK,
input logic [31:0] i_NO_ERROR_ANS,
output logic o_SD_CMD_OE, // Enable ouptut on tri-state SD_CMD line
// TX Components
output logic o_TX_PISO40_LOAD, o_TX_PISO40_EN, // Shift register for TX command head
output logic o_TX_PISO8_LOAD, o_TX_PISO8_EN, // Shift register for TX command tail
output logic o_TX_CRC7_PIPO_RST, o_TX_CRC7_PIPO_EN, // Parallel-to-Parallel CRC7 Generator
output logic [1:0] o_TX_SOURCE_SELECT, // What gets sent to CMD_TX
// TX Memory
output logic o_CMD_TX_IS_CMD55_RST,
output logic o_CMD_TX_IS_CMD55_EN, // '1' means that the command that was just sent has index
// 55, so the subsequent command is to be
// viewed as ACMD by the SD card.
// RX Components
input logic i_SD_CMD_RX, // serial response input on SD_CMD
output logic o_RX_SIPO48_RST, o_RX_SIPO48_EN, // Shift Register for all 48 bits of Response
input logic [39:8] i_RESPONSE_CONTENT, // last 32 bits of RX_SIPO_40_OUT
input logic [45:40] i_RESPONSE_INDEX, // 6 bits from RX_SIPO_40_OUT
output logic o_RX_CRC7_SIPO_RST, o_RX_CRC7_SIPO_EN, // Serial-to-parallel CRC7 Generator
input logic [6:0] i_RX_CRC7,
// RX Memory
output logic o_RCA_REGISTER_RST, o_RCA_REGISTER_EN, // Relative Card Address
// Communication to sd_dat_fsm
output logic o_CMD_TX_DONE, // begin waiting for DAT_RX to complete
input logic i_DAT_RX_DONE, // now go to next state since data block rx was completed
input logic i_ERROR_CRC16, // repeat last command
input logic i_ERROR_DAT_TIMES_OUT,
// Commnuication to core
output logic o_READY_FOR_READ, // tell core that I have completed initialization
output logic o_SD_RESTARTING, // inform core the need to restart
input logic i_READ_REQUEST, // core tells me to execute CMD17
// Communication to Host
output logic o_DAT_ERROR_FD_RST,
output logic [2:0] o_ERROR_CODE_Q, // Indicates what caused the fatal error
output logic o_FATAL_ERROR, // SD Card is damaged beyond recovery, restart entire initialization procedure of card
input logic LIMIT_SD_TIMERS
);
logic [4:0] w_next_state, r_curr_state;
logic w_resend_last_command, w_rx_crc7_check, w_rx_index_check, w_rx_bad_crc7, w_rx_bad_index, w_rx_bad_reply, w_bad_card;
logic [31:0] w_redo_result, w_error_result;
logic w_ACMD41_init_done;
logic w_fail_cnt_en, w_fail_count_rst;
logic [10:0] r_fail_count_out;
logic w_ACMD41_busy_timer_START, w_ACMD41_times_out_FLAG, w_ACMD41_busy_timer_RST; //give up after 1000 ms of ACMD41
logic [2:0] w_ERROR_CODE_D, r_ERROR_CODE_Q ; // Error Codes for fatal error on SD CMD FSM
logic w_error_code_rst, w_error_code_en;
logic [18:0] Timer_In;
localparam s_reset_clear_error_reg = 5'b00000;
localparam s_idle_supply_no_clk = 5'b00001;
localparam s_idle_supply_sd_clk = 5'b00010;
localparam s_ld_head = 5'b00011;
localparam s_tx_head = 5'b00100;
localparam s_ld_tail = 5'b00101;
localparam s_tx_tail = 5'b00110;
localparam s_setup_rx = 5'b00111;
localparam s_idle_ncc = 5'b01000;
localparam s_fetch_next_cmd = 5'b01001;
localparam s_rx_48 = 5'b01010;
localparam s_rx_136 = 5'b01011;
localparam s_error_no_response = 5'b01100;
localparam s_idle_for_dat = 5'b01101;
localparam s_error_bad_card = 5'b01110;
localparam s_idle_nrc = 5'b01111;
localparam s_count_attempt = 5'b10000;
localparam s_reset_from_error = 5'b10001;
//localparam s_enable_hs_clk = 5'b10010;
localparam s_idle_for_start_bit = 5'b10011;
localparam s_fetch_prev_cmd = 5'b10100; // use to resend previous cmd55 if acmd is resent
// localparam s_setup_rx_b = 5'b10110;
// localparam s_idle_for_start_bit_b= 5'b10111;
// localparam s_rx_48_b = 5'b11000;
// localparam s_rx_136_b = 5'b11001;
localparam s_error_dat_time_out = 5'b11010; // don't advance states if the dat fsm times out
localparam s_idle_for_clock_change = 5'b11011; // replaces s_disable_sd_clocks, s_select_hs_clk, s_enable_hs_clk
localparam s_study_response = 5'b11100; // Do error checking here
localparam s_idle_for_read_request = 5'b11101; // After power up and initialization sequence is completed
localparam s_Error_TX_Failed = 5'b11110; // when fail_cnt_out exceeds c_max_attempts
localparam c_MAX_ATTEMPTS = 3; // Give up sending a command after 3 failed attempts
// (except ACMD41) so the processor is not locked up forever
localparam c_response_type_R0_NONE = 0;
localparam c_response_type_R1_NORMAL = 1;
localparam c_response_type_R2_CID_CSD = 2;
localparam c_response_type_R3_OCR = 3;
localparam c_response_type_R6_RCA = 6;
localparam c_response_type_R7_CIC = 7;
localparam c_start_bit = 1'b0;
localparam c_DAT_none = 2'b00;
localparam c_DAT_busy = 2'b01;
localparam c_DAT_wide = 2'b10;
localparam c_DAT_block = 2'b11;
// Instructions mnemonics based on index (opcode(5 downto 0))
localparam logic [45:40] c_Go_Idle_State = 6'd0; //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
// clock selection
localparam c_sd_clk_init = 1'b1;
localparam c_sd_clk_hs = 1'b0;
//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;
// Error Codes for Error Register
localparam logic [2:0] c_NO_ERRORS = 3'b000; // no fatal errors occurred
// (default value when register is cleared during reset)
localparam [2:0] C_ERROR_NO_CMD_RESPONSE = 3'b100; // card timed out while waiting for a response on CMD, no start bit
// of response packet was ever received
// (possible causes: illegal command, card is disconnected,
// not meeting timing (you can fix timing by inverting the clock
// sent to card))
localparam logic [2:0] c_ERROR_NO_DAT_RESPONSE = 3'b101; // card timed out while waiting for a data block on DAT, no start bit
// of DAT packet was ever received
// (possible cause: card is disconnected)
localparam logic [2:0] C_ERROR_BAD_CARD_STATUS = 3'b110; // status bits of a response indicate a card is not supported
// or that the card is damaged internally
localparam logic [2:0] C_ERROR_EXCEED_MAX_ATTEMPTS = 3'b111; // if a command fails it may be resent,
// but after so many attempts you should just give up
//Alias for value of SD_CMD_Output_Enable
localparam c_TX_COMMAND = 1'b1; // Enable output on SD_CMD
localparam c_RX_RESPONSE = 1'b0; // Disable Output on SD_CMD
// load values in for timers and counters
localparam logic [7:0] c_NID_max = 8'd63; // counter_in: should be "4"
// downto 0 = 5 bits count
// but is not enough time for
// sdModel.v
localparam logic [7:0] c_NCR_max = 8'd63; // counter_in
localparam logic [7:0] c_NCC_min = 8'd7; // counter_in
localparam logic [7:0] c_NRC_min = 8'd8; // counter_in
localparam logic [18:0] c_1000ms = 18'd400000; // ACMD41 timeout
// command instruction type (opcode(6))
localparam c_CMD = 1'b0;
localparam c_ACMD = 1'b1;
// counter direction for up_down
localparam c_increment = 1'b1; // count <= count + 1
localparam c_decrement = 1'b0; // count <= count - 1
assign Timer_In = LIMIT_SD_TIMERS ? 19'b0000000000000000011 : 19'b0011000011010100000; // 250 ms
//Fail Counter, tracks how many failed attempts at command transmission
counter #(11) fail_counter
(.CountIn(11'b0),
.CountOut(r_fail_count_out),
.Load(1'b0),
.Enable(w_fail_cnt_en),
.clk(CLK),
.reset(w_fail_count_rst));
// Simple timer for ACMD41 busy
simple_timer #(19) ACMD41_busy_timer
(.VALUE(c_1000ms),
.START(w_ACMD41_busy_timer_START),
.FLAG(w_ACMD41_times_out_FLAG),
.RST(w_ACMD41_busy_timer_RST),
.CLK(CLK));
// State Register, instantiate register_ce. 32 state state machine
flopenr #(5) state_reg
(.d(w_next_state),
.q(r_curr_state),
.en(1'b1),
.reset(i_RST),
.clk(CLK));
// Error register : indicates what type of fatal error occured for interrupt
flopenr #(3) error_reg
(.d(w_ERROR_CODE_D),
.q(r_ERROR_CODE_Q),
.en(w_ERROR_CODE_EN),
.reset(w_ERROR_CODE_RST),
.clk(CLK));
assign o_ERROR_CODE_Q = r_ERROR_CODE_Q;
assign w_next_state = i_RST ? s_reset_clear_error_reg :
((r_curr_state == s_reset_clear_error_reg) |
(r_curr_state == s_Error_TX_Failed) |
(r_curr_state == s_error_no_response) |
(r_curr_state == s_error_bad_card) |
(r_curr_state == s_error_dat_time_out)) ? s_reset_from_error :
((r_curr_state == s_reset_from_error) |
((r_curr_state == s_idle_supply_no_clk) & (i_TIMER_OUT > 0))) ? s_idle_supply_no_clk :
(((r_curr_state == s_idle_supply_no_clk) & (i_TIMER_OUT == 0)) |
((r_curr_state == s_idle_supply_sd_clk) & (i_COUNTER_OUT > 0))) ? s_idle_supply_sd_clk :
(r_curr_state == s_ld_head) ? s_count_attempt :
(((r_curr_state == s_count_attempt) & (r_fail_count_out <= (c_MAX_ATTEMPTS-1))) |
((r_curr_state == s_count_attempt) &
(((i_IC_OUT == 2) & (i_OPCODE[5:0] == c_App_Command)) |
((i_IC_OUT == 3) & (i_OPCODE == ({c_ACMD, c_SD_Send_OCR})))) // to work CMD55, ACMD41 MUST be lines 2, 3 of instruction fetch mux of sd_top.vhd
& (w_ACMD41_times_out_FLAG)
& (r_fail_count_out > (c_MAX_ATTEMPTS-1)))) ? s_tx_head :
((r_curr_state == s_count_attempt) & (r_fail_count_out > (c_MAX_ATTEMPTS-1))) ? s_Error_TX_Failed :
((r_curr_state == s_tx_head) | ((r_curr_state == s_ld_tail) & (i_COUNTER_OUT > 8))) ? s_ld_tail :
(((r_curr_state == s_ld_tail) & (i_COUNTER_OUT == 8)) |
((r_curr_state == s_tx_tail) & (i_COUNTER_OUT > 0))) ? s_tx_tail :
(r_curr_state == s_tx_tail) & (i_COUNTER_OUT == 0) ? s_setup_rx :
(((r_curr_state == s_setup_rx) & (i_R_TYPE == c_response_type_R0_NONE)) |
((r_curr_state == s_idle_ncc) & (i_COUNTER_OUT > 0))) ? s_idle_ncc :
(((r_curr_state == s_setup_rx) & (i_R_TYPE != c_response_type_R0_NONE)) |
((r_curr_state == s_idle_for_start_bit) & (i_SD_CMD_RX != c_start_bit) &
(i_COUNTER_OUT > 0))) ? s_idle_for_start_bit :
((r_curr_state == s_idle_for_start_bit) & (i_SD_CMD_RX != c_start_bit) &
(i_COUNTER_OUT == 0)) ? s_error_no_response :
(((r_curr_state == s_idle_for_start_bit) & (i_SD_CMD_RX == c_start_bit) &
(i_COUNTER_OUT >= 0) & (i_R_TYPE == c_response_type_R2_CID_CSD)) |
((r_curr_state == s_rx_136) & (i_COUNTER_OUT > 0))) ? s_rx_136 :
(((r_curr_state == s_idle_for_start_bit) & (i_SD_CMD_RX == c_start_bit) &
(i_COUNTER_OUT >= 0) & (i_R_TYPE != c_response_type_R2_CID_CSD)) |
((r_curr_state == s_rx_48) & (i_COUNTER_OUT > 0))) ? s_rx_48 :
(((r_curr_state == s_rx_136) & (i_COUNTER_OUT == 0)) |
((r_curr_state == s_rx_48) & (i_COUNTER_OUT) == 0)) ? s_study_response :
(r_curr_state == s_study_response) & w_bad_card ? s_error_bad_card :
(((r_curr_state == s_study_response) & (~w_bad_card) & (i_USES_DAT != c_DAT_none)) |
((r_curr_state == s_idle_for_dat) & (~i_DAT_RX_DONE))) ? s_idle_for_dat :
((r_curr_state == s_idle_for_dat) & (i_DAT_RX_DONE) & (i_ERROR_DAT_TIMES_OUT)) ? s_error_dat_time_out :
(((r_curr_state == s_idle_for_dat) & (i_DAT_RX_DONE) &
(~i_ERROR_DAT_TIMES_OUT)) |
((r_curr_state == s_study_response) & (~w_bad_card) &
(i_USES_DAT == c_DAT_none)) |
((r_curr_state == s_idle_nrc) & (i_COUNTER_OUT > 0))) ? s_idle_nrc :
((r_curr_state == s_idle_nrc) & (i_COUNTER_OUT == 0) &
(w_resend_last_command) & ((i_OPCODE[6] == c_ACMD) &
((i_OPCODE[5:0]) != c_App_Command))) ? s_fetch_prev_cmd :
((r_curr_state == s_fetch_prev_cmd) |
((r_curr_state == s_idle_supply_sd_clk) & (i_COUNTER_OUT == 0)) |
((r_curr_state == s_fetch_next_cmd) & // before CMD17
(i_IC_OUT < 9)) | // blindly load head of next command
((r_curr_state == s_idle_for_read_request) & (i_READ_REQUEST)) | // got the request, load head
((r_curr_state == s_idle_nrc) & (i_COUNTER_OUT == 0) &
(w_resend_last_command) & ((i_OPCODE[6] == c_CMD) |
((i_OPCODE[5:0]) == c_App_Command)))) ? s_ld_head :
(((r_curr_state == s_idle_nrc) & (i_COUNTER_OUT == 0) &
(~w_resend_last_command) & ((i_OPCODE) == ({c_CMD, c_Switch_Function}))) |
((r_curr_state == s_idle_for_clock_change) & (~i_CLOCK_CHANGE_DONE))) ? s_idle_for_clock_change :
(((r_curr_state == s_idle_ncc) & (i_COUNTER_OUT == 0)) |
((r_curr_state == s_idle_nrc) & (i_COUNTER_OUT == 0) &
(~w_resend_last_command) & ((i_OPCODE) != ({c_CMD, c_Switch_Function}))) |
((r_curr_state == s_idle_for_clock_change) & (i_CLOCK_CHANGE_DONE))) ? s_fetch_next_cmd :
(((r_curr_state == s_fetch_next_cmd) &
(i_IC_OUT >= 9)) | // During and after CMD17, wait for request to send CMD17 from core
// waiting for request
(r_curr_state == s_idle_for_read_request)) ? s_idle_for_read_request :
s_reset_clear_error_reg;
// state outputs
assign w_ACMD41_busy_timer_START = ((r_curr_state == s_count_attempt) & (i_OPCODE == {c_ACMD, c_SD_Send_OCR}) & (r_fail_count_out == 1));
assign w_ACMD41_busy_timer_RST = ((r_curr_state == s_reset_from_error) | (w_ACMD41_init_done));
// Error Register
assign w_ERROR_CODE_RST = (r_curr_state == s_reset_clear_error_reg);
assign w_ERROR_CODE_EN = (r_curr_state == s_error_bad_card) | (r_curr_state == s_error_no_response) | (r_curr_state == s_Error_TX_Failed) | (r_curr_state == s_error_dat_time_out);
assign w_ERROR_CODE_D = (r_curr_state == s_Error_TX_Failed) ? C_ERROR_EXCEED_MAX_ATTEMPTS : // give up
(r_curr_state == s_error_bad_card) ? C_ERROR_BAD_CARD_STATUS : // card is damaged or unsupported
(r_curr_state == s_error_no_response) ? C_ERROR_NO_CMD_RESPONSE : // no response was received on CMD line
(r_curr_state == s_error_dat_time_out) ? c_ERROR_NO_DAT_RESPONSE : // no data packet was received on DAT bus
c_NO_ERRORS; // all is well
// Failure counter
assign w_fail_count_rst = ((r_curr_state == s_reset_from_error) | (r_curr_state == s_fetch_next_cmd & i_OPCODE[5:0] != c_App_Command));
assign w_fail_cnt_en = ((r_curr_state == s_count_attempt) & (i_OPCODE[6] != c_ACMD | i_OPCODE[5:0] == c_App_Command));
// & (i_OPCODE != ({c_ACMD, c_SD_Send_OCR})) else // NOT ACMD41, it can take up to 1 second
// Timer module
assign o_TIMER_EN = (r_curr_state == s_idle_supply_no_clk);
assign o_TIMER_LOAD = (r_curr_state == s_reset_from_error);
assign o_TIMER_IN = (r_curr_state == s_reset_from_error) ? Timer_In : '0;
// Clock selection/gater module(s) ...
assign o_SD_CLK_EN = ~((r_curr_state == s_reset_from_error) | (r_curr_state == s_idle_supply_no_clk) | (r_curr_state == s_idle_for_clock_change));
assign o_START_CLOCK_CHANGE = (r_curr_state == s_idle_for_clock_change);
// RCA register module
assign o_RCA_REGISTER_RST = (r_curr_state == s_reset_from_error);
assign o_RCA_REGISTER_EN = ((r_curr_state == s_idle_nrc) & (i_R_TYPE == c_response_type_R6_RCA));
// Instruction counter module
assign o_IC_RST = (r_curr_state == s_reset_from_error);
//assign o_IC_EN = (r_curr_state == s_fetch_next_cmd) | (r_curr_state == s_fetch_prev_cmd);
assign o_IC_EN = (((r_curr_state == s_fetch_next_cmd) & (i_IC_OUT < 10)) | (r_curr_state == s_fetch_prev_cmd));
assign o_IC_UP_DOWN = (r_curr_state == s_fetch_prev_cmd) ? c_decrement : c_increment;
// "Previous Command sent was CMD55, so the command I'm now sending is ACMD" module
assign o_CMD_TX_IS_CMD55_RST = (r_curr_state == s_reset_from_error);
assign o_CMD_TX_IS_CMD55_EN = (r_curr_state == s_ld_head);
// Output signals to DAT FSM
//o_CMD_TX_DONE = '0' when (r_curr_state == s_reset) else // reset
// '0' when (r_curr_state == s_idle_supply_no_clk) | (r_curr_state == s_idle_supply_sd_clk) else // power up
// '0' when ((r_curr_state == s_ld_head)
// | (r_curr_state == s_tx_head)
// | (r_curr_state == s_ld_tail)
// | (r_curr_state == s_tx_tail)) else // tx
// '1';
assign o_CMD_TX_DONE = (r_curr_state == s_setup_rx);
// Counter Module
assign o_COUNTER_LOAD = (r_curr_state == s_idle_supply_no_clk) |
(r_curr_state == s_ld_head) |
(r_curr_state == s_setup_rx) |
(r_curr_state == s_idle_for_start_bit) & (i_SD_CMD_RX == c_start_bit) |
(r_curr_state == s_rx_48) & (i_COUNTER_OUT == 0) |
(r_curr_state == s_rx_136) & (i_COUNTER_OUT == 0);
assign o_COUNTER_IN = (r_curr_state == s_idle_supply_no_clk) ? 8'd73 :
// | is it 73 downto 0 == 74 bits
(r_curr_state == s_ld_head) ? 8'd47 : // or is it 48
((r_curr_state == s_setup_rx) & (i_R_TYPE == c_response_type_R0_NONE)) ? c_NCC_min :
((r_curr_state == s_setup_rx)
& (i_R_TYPE != c_response_type_R0_NONE)
& (((i_OPCODE) == ({c_CMD, c_All_Send_CID})) |
((i_OPCODE) == ({c_ACMD, c_SD_Send_OCR})))) ? c_NID_max :
(r_curr_state == s_setup_rx) ? c_NCR_max :
((r_curr_state == s_idle_for_start_bit) & (i_R_TYPE == c_response_type_R2_CID_CSD)) ? 8'd135 : // | is it 136
(r_curr_state == s_idle_for_start_bit) ? 8'd46 : // | is it not48
(r_curr_state == s_rx_48) | (r_curr_state == s_rx_136) ? c_NRC_min : // | is it 8
8'd0;
assign o_COUNTER_EN = (r_curr_state == s_idle_supply_sd_clk) ? 1'b1 :
((r_curr_state == s_tx_head) | (r_curr_state == s_ld_tail) | (r_curr_state == s_tx_tail)) ? 1'b1 :
(r_curr_state == s_idle_for_start_bit) & (i_SD_CMD_RX == c_start_bit) ? 1'b0 :
(r_curr_state == s_idle_for_start_bit) ? 1'b1 :
(r_curr_state == s_rx_48) & (i_COUNTER_OUT == 0) ? 1'b0 :
(r_curr_state == s_rx_48) ? 1'b1 :
(r_curr_state == s_idle_nrc) ? 1'b1 :
(r_curr_state == s_rx_136) & (i_COUNTER_OUT == 0) ? 1'b0 :
(r_curr_state == s_rx_136) ? 1'b1 :
(r_curr_state == s_idle_ncc) ? 1'b1 :
1'b0;
// SD_CMD Tri-state Buffer Module
assign o_SD_CMD_OE = (r_curr_state == s_idle_supply_sd_clk) ? c_TX_COMMAND :
((r_curr_state == s_tx_head)
| (r_curr_state == s_ld_tail)
| (r_curr_state == s_tx_tail)) ? c_TX_COMMAND :
c_RX_RESPONSE;
// Shift Registers
// TX_PISO40 Transmit Command Head
assign o_TX_PISO40_LOAD = (r_curr_state == s_ld_head);
assign o_TX_PISO40_EN = (r_curr_state == s_tx_head) | (r_curr_state == s_ld_tail);
// TX_CRC7_PIPO Generate Tail
assign o_TX_CRC7_PIPO_RST = (r_curr_state == s_ld_head);
assign o_TX_CRC7_PIPO_EN = (r_curr_state == s_tx_head);
// TX_PISO8 Transmit Command Tail
assign o_TX_PISO8_LOAD = (r_curr_state == s_ld_tail);
assign o_TX_PISO8_EN = (r_curr_state == s_tx_tail);
// RX_CRC7_SIPO Calculate the CRC7 of the first 47-bits of reply (should be zero)
assign o_RX_CRC7_SIPO_RST = (r_curr_state == s_setup_rx);
assign o_RX_CRC7_SIPO_EN = (r_curr_state == s_rx_48) & (i_COUNTER_OUT > 0); // or (r_curr_state == s_rx_48_b)
// RX_SIPO40 Content bits of response
assign o_RX_SIPO48_RST = (r_curr_state == s_setup_rx);
assign o_RX_SIPO48_EN = (r_curr_state == s_rx_48 | r_curr_state == s_rx_48);
// Fatal Error Signal Wire
assign o_FATAL_ERROR = (r_curr_state == s_error_bad_card) | (r_curr_state == s_error_no_response) |
(r_curr_state == s_Error_TX_Failed) | (r_curr_state == s_error_dat_time_out);
assign o_DAT_ERROR_FD_RST = (r_curr_state == s_ld_head);
// I'm debating the merit of creating yet another state for sd_cmd_fsm.vhd to go into when and if sd_dat_fsm.vhd
// times out while waiting for start bit on the DAT bus resulting in Error_Time_Out going high in
// sd_Dat_fsm.vhd while sd_cmd_fsm.vhd is still in s_idle_for_dat
// TX source selection bits for mux
assign o_TX_SOURCE_SELECT = (r_curr_state == s_idle_supply_sd_clk) ? c_tx_high :
((r_curr_state == s_ld_head)
| (r_curr_state == s_tx_head)
| (r_curr_state == s_ld_tail)) ? c_tx_head :
(r_curr_state == s_tx_tail) ? c_tx_tail :
c_tx_high; // This occurs when not transmitting anything
// Study Response
assign w_rx_crc7_check = (r_curr_state == s_idle_nrc) &
((i_R_TYPE != c_response_type_R0_NONE) &
(i_R_TYPE != c_response_type_R3_OCR) &
(i_R_TYPE != c_response_type_R2_CID_CSD));
assign w_rx_index_check = (r_curr_state == s_idle_nrc) &
((i_R_TYPE != c_response_type_R0_NONE) &
(i_R_TYPE != c_response_type_R3_OCR) &
(i_R_TYPE != c_response_type_R2_CID_CSD));
assign w_redo_result = i_RESPONSE_CONTENT & i_NO_REDO_MASK;
assign w_rx_bad_reply = ((r_curr_state == s_idle_nrc | r_curr_state == s_study_response) & (w_redo_result != i_NO_REDO_ANS));
assign w_rx_bad_crc7 = ((r_curr_state == s_idle_nrc | r_curr_state == s_study_response) & ((w_rx_crc7_check) & (i_RX_CRC7 != 7'b0)));
assign w_rx_bad_index = ((r_curr_state == s_idle_nrc | r_curr_state == s_study_response)
& ((w_rx_index_check) & (i_RESPONSE_INDEX != i_OPCODE[5:0])));
assign w_resend_last_command = ((r_curr_state == s_idle_nrc | r_curr_state == s_study_response) &
((w_rx_bad_reply) | (w_rx_bad_index) | (w_rx_bad_crc7))) |
((r_curr_state == s_idle_nrc) &
((i_ERROR_CRC16) &
((i_USES_DAT == c_DAT_block) | (i_USES_DAT == c_DAT_wide))));
assign w_error_result = i_RESPONSE_CONTENT & i_NO_ERROR_MASK;
// Make assignment based on what was read from the OCR Register.
// Bit 31, Card power up status bit: '1' == SD Flash Card power up procedure is finished.
// '0' == SD Flash Card power up procedure is not finished.
// Bit 30, Card capacity status bit: '1' == Extended capacity card is in use (64 GB in size or greater).
// '0' == Extended capacity card is not in use.
assign w_ACMD41_init_done = ((i_IC_OUT == 3) & (i_OPCODE == ({c_ACMD, c_SD_Send_OCR}))) &
(~w_rx_bad_reply) & (r_curr_state == s_study_response);
assign w_bad_card = ((r_curr_state == s_study_response) & (w_error_result != i_NO_ERROR_ANS) &
((~w_ACMD41_times_out_FLAG) | (w_ACMD41_init_done)));
// Communication with core
assign o_READY_FOR_READ = (r_curr_state == s_idle_for_read_request);
assign o_SD_RESTARTING = (r_curr_state == s_Error_TX_Failed) |
(r_curr_state == s_error_dat_time_out) |
(r_curr_state == s_error_bad_card) |
(r_curr_state == s_error_no_response);
endmodule

View File

@ -0,0 +1,233 @@
///////////////////////////////////////////
// sd_dat_fsm.sv
//
// Written: Ross Thompson September 19, 2021
// Modified:
//
// Purpose: Runs in parallel with sd_cmd_fsm to control activity on the DAT
// bus of the SD card.
// 14 State Mealy FSM + Safe state = 15 State Mealy FSM
//
// 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_dat_fsm
(
input logic CLK, // HS Clock (48 MHz)
input logic i_RST,
// Timer module control
input logic i_SD_CLK_SELECTED, // Which frequency I'm in determines what count in to load for a 100ms timer
output logic o_TIMER_LOAD, o_TIMER_EN, // Timer Control signals
output logic [22:0] o_TIMER_IN, // Need Enough bits for 100 milliseconds at 48MHz
input logic [22:0] i_TIMER_OUT, // (ceiling(log((clk freq)(delay desired)-1)/log(2))-1) downto 0
// Nibble counter module control
output logic o_COUNTER_RST, o_COUNTER_EN, // nibble counter
input logic [10:0] i_COUNTER_OUT, // max nibbles is 1024 + crc16 bits = 1040 bits
// CRC16 Generation control
output logic o_CRC16_EN, o_CRC16_RST, // shared signals for all 4 CRC16_SIPO (one for each of 4 DAT lines)
input logic i_DATA_CRC16_GOOD, // indicates that no errors in transmission when CRC16 are all zero
// For R1b
output logic o_BUSY_RST, o_BUSY_EN, // busy signal for R1b
input logic i_DAT0_Q,
// Storage Buffers for DAT bits read
output logic o_NIBO_EN, // 512 bytes block data (Nibble In Block Out)
// From LUT
input logic [1:0] i_USES_DAT, // current command needs use of DAT bus
// For communicating with core
output logic o_DATA_VALID, // indicates that DATA being send over o_DATA to core is valid
output logic o_LAST_NIBBLE, // indicates that the last nibble has been sent
// For communication with sd_cmd_fsm
input logic i_CMD_TX_DONE, // command transmission completed, begin waiting for DATA
output logic o_DAT_RX_DONE, // tell SD_CMD_FSM that DAT communication is completed, send next instruction to sd card
output logic o_ERROR_DAT_TIMES_OUT, // error flag for when DAT times out (so don't fetch more instructions)
output logic o_DAT_ERROR_FD_RST,
output logic o_DAT_ERROR_FD_EN, // tell SD_CMD_FSM to resend command due to error in transmission
input logic LIMIT_SD_TIMERS
);
logic [3:0] w_next_state, r_curr_state;
logic w_error_crc16_fd_en, w_error_crc16_fd_rst, w_error_crc16_fd_d; // Save ERROR_CRC16 so CMD FSM sees it in IDLE_NRC (not just in IDLE_DAT)
logic r_error_crc16_fd_Q;
logic [22:0] Identify_Timer_In;
logic [22:0] Data_TX_Timer_In;
localparam logic [3:0] s_reset = 4'b0000;
localparam logic [3:0] s_idle = 4'b0001;
localparam logic [3:0] s_idle_for_start_bit = 4'b0010;
localparam logic [3:0] s_read_r1b = 4'b0011;
localparam logic [3:0] s_notify_r1b_completed = 4'b0100;
localparam logic [3:0] s_error_time_out = 4'b0101;
localparam logic [3:0] s_rx_wide_data = 4'b0110;
localparam logic [3:0] s_rx_block_data = 4'b0111;
localparam logic [3:0] s_rx_crc16 = 4'b1000;
localparam logic [3:0] s_error_crc16_fail = 4'b1001;
localparam logic [3:0] s_publish_block_data = 4'b1010;
localparam logic [3:0] s_publish_wide_data = 4'b1011;
localparam logic [3:0] s_reset_wide_data = 4'b1100;
localparam logic [3:0] s_reset_block_data = 4'b1101;
localparam logic [3:0] s_reset_nibble_counter = 4'b1110; // Before publishing CMD17 Block Data
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;
localparam logic c_start_bit = 0;
localparam logic c_busy_bit = 0;
// load values in for timers and counters
localparam logic c_slow_clock = 1'b1; // use during initialization (card identification mode)
localparam logic c_HS_clock = 1'b0; // use after CMD6 switches clock frequency (CMD17)
assign Identify_Timer_In = LIMIT_SD_TIMERS ? 23'b00000000000000001100011 : 23'b00000001001110001000000; // 40,000 unsigned.
assign Data_TX_Timer_In = LIMIT_SD_TIMERS ? 23'b00000000000000001100011 : 23'b11110100001001000000000; // 8,000,000 unsigned.
flopenr #(4) stateReg(.clk(CLK),
.reset(i_RST),
.en(1'b1),
.d(w_next_state),
.q(r_curr_state));
assign w_next_state = ((i_RST) |
(r_curr_state == s_error_time_out) | // noticed this change is needed during emulation
(r_curr_state == s_notify_r1b_completed) |
(r_curr_state == s_error_crc16_fail) |
(r_curr_state == s_publish_wide_data) |
((r_curr_state == s_publish_block_data) & (i_COUNTER_OUT == 1023))) ? s_reset :
((r_curr_state == s_reset) |
((r_curr_state == s_idle) & ((i_USES_DAT == c_DAT_none) | ((i_USES_DAT != c_DAT_none) & (~i_CMD_TX_DONE))))) ? s_idle :
((r_curr_state == s_idle) & (i_USES_DAT == c_DAT_wide) & (i_CMD_TX_DONE)) ? s_reset_wide_data :
((r_curr_state == s_idle) & (i_USES_DAT == c_DAT_block) & (i_CMD_TX_DONE)) ? s_reset_block_data :
((r_curr_state == s_reset_wide_data) |
((r_curr_state == s_idle) & (i_USES_DAT == c_DAT_busy) & (i_CMD_TX_DONE)) |
(r_curr_state == s_reset_block_data) |
((r_curr_state == s_idle_for_start_bit) & (i_TIMER_OUT > 0) & (i_DAT0_Q != c_start_bit))) ? s_idle_for_start_bit :
((r_curr_state == s_idle_for_start_bit) & // Apparently R1b's busy signal is optional,
(i_TIMER_OUT == 0) & // Even if it never shows up,
(i_USES_DAT == c_DAT_busy)) ? s_notify_r1b_completed : // pretend it did, & move on
(((r_curr_state == s_idle_for_start_bit) & (i_TIMER_OUT > 0) &
(i_DAT0_Q == c_start_bit) & (i_USES_DAT == c_DAT_busy)) |
((r_curr_state == s_read_r1b) & (i_TIMER_OUT > 0) & (i_DAT0_Q == c_busy_bit))) ? s_read_r1b :
(((r_curr_state == s_read_r1b) & (i_TIMER_OUT == 0)) |
((r_curr_state == s_idle_for_start_bit) & (i_TIMER_OUT == 0) &
(i_USES_DAT != c_DAT_busy))) ? s_error_time_out :
((r_curr_state == s_read_r1b) & (i_DAT0_Q != c_busy_bit)) ? s_notify_r1b_completed :
(((r_curr_state == s_idle_for_start_bit) & (i_TIMER_OUT > 0) & (i_DAT0_Q == c_start_bit) &
(i_USES_DAT == c_DAT_wide)) |
((r_curr_state == s_rx_wide_data) & (i_COUNTER_OUT < 128))) ? s_rx_wide_data :
(((r_curr_state == s_idle_for_start_bit) & (i_TIMER_OUT > 0) &
(i_DAT0_Q == c_start_bit) & (i_USES_DAT == c_DAT_block)) |
((r_curr_state == s_rx_block_data) & (i_COUNTER_OUT < 1023))) ? s_rx_block_data :
(((r_curr_state == s_rx_wide_data) & (i_COUNTER_OUT == 128)) |
((r_curr_state == s_rx_block_data) & (i_COUNTER_OUT == 1023)) |
((r_curr_state == s_rx_crc16) &
(((i_USES_DAT == c_DAT_wide) & (i_COUNTER_OUT < 144)) |
((i_USES_DAT == c_DAT_block) & (i_COUNTER_OUT < 1040))))) ? s_rx_crc16 :
((r_curr_state == s_rx_crc16) &
(((i_USES_DAT == c_DAT_wide) & (i_COUNTER_OUT == 144)) |
((i_USES_DAT == c_DAT_block) & (i_COUNTER_OUT == 1040))) &
(~i_DATA_CRC16_GOOD)) ? s_error_crc16_fail :
((r_curr_state == s_rx_crc16) & (i_USES_DAT == c_DAT_wide) & (i_COUNTER_OUT == 144) &
(i_DATA_CRC16_GOOD)) ? s_publish_wide_data :
((r_curr_state == s_rx_crc16) &
(i_USES_DAT == c_DAT_block) & (i_COUNTER_OUT == 1040) & (i_DATA_CRC16_GOOD)) ? s_reset_nibble_counter :
((r_curr_state == s_reset_nibble_counter) |
((r_curr_state == s_publish_block_data) & (i_COUNTER_OUT < 1023))) ? s_publish_block_data :
s_reset;
assign o_TIMER_IN = (r_curr_state == s_reset) & (i_SD_CLK_SELECTED == c_slow_clock) ? Identify_Timer_In : Data_TX_Timer_In;
assign o_TIMER_LOAD = ((r_curr_state == s_reset) |
(r_curr_state == s_reset_block_data));
assign o_TIMER_EN = ((r_curr_state == s_idle_for_start_bit) |
(r_curr_state == s_read_r1b));
// Nibble Counter module
assign o_COUNTER_RST = (r_curr_state == s_reset) | (r_curr_state == s_reset_nibble_counter);
assign o_COUNTER_EN = ((r_curr_state == s_rx_block_data) |
(r_curr_state == s_rx_wide_data) |
(r_curr_state == s_rx_crc16)) | (r_curr_state == s_publish_block_data);
// CRC16 Generation module
assign o_CRC16_RST = (r_curr_state == s_reset);
assign o_CRC16_EN = ((r_curr_state == s_rx_block_data) |
(r_curr_state == s_rx_wide_data) |
(r_curr_state == s_rx_crc16));
// Flip Flop Module (for R1b)
assign o_BUSY_RST = (r_curr_state == s_reset);
//o_BUSY_EN = '1' when ((r_curr_state == s_idle_for_start_bit) |
// (r_curr_state == s_read_r1b)) else
// '0';
assign o_BUSY_EN = 1'b1; // Always sample data
// DAT Storage Modules
assign o_NIBO_EN = (r_curr_state == s_rx_block_data);
// To sd_cmd_fsm
assign o_DAT_RX_DONE = ((r_curr_state == s_error_time_out) |
(r_curr_state == s_notify_r1b_completed) |
(r_curr_state == s_error_crc16_fail) |
(r_curr_state == s_publish_wide_data) |
(r_curr_state == s_publish_block_data));
assign o_ERROR_DAT_TIMES_OUT = (r_curr_state == s_error_time_out);
// o_RESEND_READ_WIDE (Error! This is not defined. Indicates switch command must be re-rent),
// should be a function of block busy logic
// For Communication with core
assign o_DATA_VALID = (r_curr_state == s_publish_block_data);
assign o_LAST_NIBBLE = ((r_curr_state == s_publish_block_data)
& (i_COUNTER_OUT == 1023)) | (r_curr_state == s_error_time_out); // notify done if errors occur
// o_ERROR_CRC16 (note: saved to flip flop because otherwise is only 1 clock cycle, not what I want)
assign o_DAT_ERROR_FD_RST = (r_curr_state == s_reset_block_data) | (r_curr_state == s_reset_wide_data);
assign o_DAT_ERROR_FD_EN = (r_curr_state == s_rx_crc16);
endmodule

View File

@ -0,0 +1,665 @@
///////////////////////////////////////////
// sd_top.sv
//
// Written: Ross Thompson September 19, 2021
// Modified:
//
// 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
input logic i_SD_CMD, // CMD Response from card
output logic o_SD_CMD, // CMD Command from host
output logic o_SD_CMD_OE, // Direction of SD_CMD
input logic [3:0] i_SD_DAT, // SD DAT Bus
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
// 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; // SD_Send_OCR
localparam logic [127:96] c_ACMD41_ans_dont_redo = 32'h80000000;
localparam logic [127:96] c_ACMD41_mask_check_error_bits = 32'h41FF8000;
localparam logic [127:96] c_ACMD41_ans_error_free = 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;
logic w_IC_RST, w_IC_EN, w_IC_UP_DOWN;
//logic w_USES_DAT : std_logic_vector(1 downto 0);
//logic w_OPCODE_Q : std_logic_vector(6 downto 0);
//logic w_R_TYPE : std_logic_vector(2 downto 0);
//logic w_NO_REDO_MASK : std_logic_vector(31 downto 0);
//logic w_NO_REDO_ANS : std_logic_vector(31 downto 0);
//logic w_NO_ERROR_MASK : std_logic_vector(31 downto 0);
//logic w_NO_ERROR_ANS : std_logic_vector(31 downto 0);
logic w_SD_CMD_OE;
//logic w_SD_CMD_IE : std_logic; // tri-state buffer - input enable (for simulation only)
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;
logic [39:8] r_RESPONSE_CONTENT;
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;
logic r_DAT_ERROR_Q; // CRC16 error or time out
logic w_NOT_DAT_ERROR_Q; // '0'=no error, '1'=tx error on DAT bus
logic w_ERROR_DAT_TIMES_OUT;
logic w_FATAL_ERROR;
logic [2:0] r_ERROR_CODE_Q; // indicates which fatal error occured
// Communication with core
logic w_READY_FOR_READ;
logic w_READ_REQUEST;
logic [3:0] r_DATA_TO_CORE;
logic w_DATA_VALID;
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;
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 ;
logic [6:0] w_OPCODE_Q ;
// TOP_LEVEL Connections
logic [40:9] w_BLOCK_ADDR ;
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
counter #(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
.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));
// 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_RST(w_HS_TO_INIT_CLK_DIVIDER_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),
.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;
assign r_G_CLK_SD_n = ~r_G_CLK_SD;
flopenr #(1) sd_cmd_out_reg
(.d(w_SD_CMD_TX_Q),
.q(o_SD_CMD),
.en(1'b1),
.clk(r_G_CLK_SD_n),
.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_n),
.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

View File

@ -0,0 +1,55 @@
///////////////////////////////////////////
// simple_timer.sv
//
// Written: Ross Thompson September 20, 2021
// Modified:
//
// 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 simple_timer #(parameter BUS_WIDTH = 4)
(
input logic [BUS_WIDTH-1:0] VALUE,
input logic START,
output logic FLAG,
input logic RST,
input logic CLK);
logic [0:2**BUS_WIDTH-1] count;
logic timer_en;
assign timer_en = count != 0;
always_ff @(posedge CLK, posedge RST) begin
if (RST) begin
count <= '0;
end else if (START) begin
count <= VALUE - 1'b1;
end else if(timer_en) begin
count <= count - 1'b1;
end
end
assign FLAG = count != 0;
endmodule

View File

@ -0,0 +1,53 @@
///////////////////////////////////////////
// sipo_generic_ce
//
// Written: Ross Thompson September 20, 2021
// Modified:
//
// Purpose: serial to n-bit parallel shift register using register_ce.
// When given a n-bit word as input transmit the message serially MSB (leftmost)
// bit first.
//
// 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 sipo_generic_ce #(g_BUS_WIDTH)
(input logic clk,
input logic rst,
input logic i_enable, // data valid, write to register
input logic i_message_bit, // serial data
output logic [g_BUS_WIDTH-1:0] o_data // message received, parallel data
);
logic [g_BUS_WIDTH-1:0] w_reg_d;
logic [g_BUS_WIDTH-1:0] r_reg_q;
flopenr #(g_BUS_WIDTH) shiftReg
(.d(w_reg_d),
.q(r_reg_q),
.en(i_enable),
.reset(rst),
.clk(clk));
assign w_reg_d = {r_reg_q[g_BUS_WIDTH-2:0], i_message_bit};
assign o_data = r_reg_q;
endmodule

View File

@ -0,0 +1,384 @@
@20000000 10 32 54 76
@20000004 00 01 02 03
@20000008 04 05 06 07
@2000000C 08 09 0A 0B
@20000010 0C 0D 0E 0F
@20000014 0F 0E 0D 0C
@20000018 0B 0A 09 08
@2000001C 07 06 05 04
@20000020 03 02 01 00
@20000024 10 32 54 76
@20000028 10 32 54 76
@2000002C 10 32 54 76
@20000030 10 32 54 76
@20000034 10 32 54 76
@20000038 10 32 54 76
@2000003C 10 32 54 76
@20000040 10 32 54 76
@20000044 10 32 54 76
@20000048 10 32 54 76
@2000004C 10 32 54 76
@20000050 10 32 54 76
@20000054 10 32 54 76
@20000058 10 32 54 76
@2000005C 10 32 54 76
@20000060 10 32 54 76
@20000064 10 32 54 76
@20000068 10 32 54 76
@2000006C 10 32 54 76
@20000070 10 32 54 76
@20000074 10 32 54 76
@20000078 10 32 54 76
@2000007C 10 32 54 76
@20000080 10 32 54 76
@20000084 10 32 54 76
@20000088 10 32 54 76
@2000008C 10 32 54 76
@20000090 10 32 54 76
@20000094 10 32 54 76
@20000098 10 32 54 76
@2000009C 10 32 54 76
@200000A0 10 32 54 76
@200000A4 10 32 54 76
@200000A8 10 32 54 76
@200000AC 10 32 54 76
@200000B0 10 32 54 76
@200000B4 10 32 54 76
@200000B8 10 32 54 76
@200000BC 10 32 54 76
@200000C0 10 32 54 76
@200000C4 10 32 54 76
@200000C8 10 32 54 76
@200000CC 10 32 54 76
@200000D0 10 32 54 76
@200000D4 10 32 54 76
@200000D8 10 32 54 76
@200000DC 10 32 54 76
@200000E0 10 32 54 76
@200000E4 10 32 54 76
@200000E8 10 32 54 76
@200000EC 10 32 54 76
@200000F0 10 32 54 76
@200000F4 10 32 54 76
@200000F8 10 32 54 76
@200000FC 10 32 54 76
@20000100 10 32 54 76
@20000104 10 32 54 76
@20000108 10 32 54 76
@2000010C 10 32 54 76
@20000110 10 32 54 76
@20000114 10 32 54 76
@20000118 10 32 54 76
@2000011C 10 32 54 76
@20000120 10 32 54 76
@20000124 10 32 54 76
@20000128 10 32 54 76
@2000012C 10 32 54 76
@20000130 10 32 54 76
@20000134 10 32 54 76
@20000138 10 32 54 76
@2000013C 10 32 54 76
@20000140 10 32 54 76
@20000144 10 32 54 76
@20000148 10 32 54 76
@2000014C 10 32 54 76
@20000150 10 32 54 76
@20000154 10 32 54 76
@20000158 10 32 54 76
@2000015C 10 32 54 76
@20000160 10 32 54 76
@20000164 10 32 54 76
@20000168 10 32 54 76
@2000016C 10 32 54 76
@20000170 10 32 54 76
@20000174 10 32 54 76
@20000178 10 32 54 76
@2000017C 10 32 54 76
@20000180 10 32 54 76
@20000184 10 32 54 76
@20000188 10 32 54 76
@2000018C 10 32 54 76
@20000190 10 32 54 76
@20000194 10 32 54 76
@20000198 10 32 54 76
@2000019C 10 32 54 76
@200001A0 10 32 54 76
@200001A4 10 32 54 76
@200001A8 10 32 54 76
@200001AC 10 32 54 76
@200001B0 10 32 54 76
@200001B4 10 32 54 76
@200001B8 10 32 54 76
@200001BC 10 32 54 76
@200001C0 10 32 54 76
@200001C4 10 32 54 76
@200001C8 10 32 54 76
@200001CC 10 32 54 76
@200001D0 10 32 54 76
@200001D4 10 32 54 76
@200001D8 10 32 54 76
@200001DC 10 32 54 76
@200001E0 10 32 54 76
@200001E4 10 32 54 76
@200001E8 10 32 54 76
@200001EC 10 32 54 76
@200001F0 10 32 54 76
@200001F4 10 32 54 76
@200001F8 10 32 54 76
@200001FC 10 32 54 76
@1ffff0000 00 00 00 00
@1ffff0004 00 00 00 00
@1ffff0008 00 00 00 00
@1ffff000c 00 00 00 00
@1ffff0010 00 00 00 00
@1ffff0014 00 00 00 00
@1ffff0018 00 00 00 00
@1ffff001c 00 00 00 00
@1ffff0020 00 00 00 00
@1ffff0024 00 00 00 00
@1ffff0028 00 00 00 00
@1ffff002c 00 00 00 00
@1ffff0030 00 00 00 00
@1ffff0034 00 00 00 00
@1ffff0038 00 00 00 00
@1ffff003c 00 00 00 00
@1ffff0040 00 00 00 00
@1ffff0044 00 00 00 00
@1ffff0048 00 00 00 00
@1ffff004c 00 00 00 00
@1ffff0050 00 00 00 00
@1ffff0054 00 00 00 00
@1ffff0058 00 00 00 00
@1ffff005c 00 00 00 00
@1ffff0060 00 00 00 00
@1ffff0064 00 00 00 00
@1ffff0068 00 00 00 00
@1ffff006C 00 00 00 00
@1ffff0070 00 00 00 00
@1ffff0074 00 00 00 00
@1ffff0078 00 00 00 00
@1ffff007c 00 00 00 00
@1ffff0080 00 00 00 00
@1ffff0084 00 00 00 00
@1ffff0088 00 00 00 00
@1ffff008c 00 00 00 00
@1ffff0090 00 00 00 00
@1ffff0094 00 00 00 00
@1ffff0098 00 00 00 00
@1ffff009c 00 00 00 00
@1ffff00a0 00 00 00 00
@1ffff00a4 00 00 00 00
@1ffff00a8 00 00 00 00
@1ffff00ac 00 00 00 00
@1ffff00b0 00 00 00 00
@1ffff00b4 00 00 00 00
@1ffff00b8 00 00 00 00
@1ffff00bc 00 00 00 00
@1ffff00c0 00 00 00 00
@1ffff00c4 00 00 00 00
@1ffff00c8 00 00 00 00
@1ffff00cc 00 00 00 00
@1ffff00d0 00 00 00 00
@1ffff00d4 00 00 00 00
@1ffff00d8 00 00 00 00
@1ffff00dc 00 00 00 00
@1ffff00e0 00 00 00 00
@1ffff00e4 00 00 00 00
@1ffff00e8 00 00 00 00
@1ffff00ec 00 00 00 00
@1ffff00f0 00 00 00 00
@1ffff00f4 00 00 00 00
@1ffff00f8 00 00 00 00
@1ffff00fc 00 00 00 00
@1ffff0100 00 00 00 00
@1ffff0104 00 00 00 00
@1ffff0108 00 00 00 00
@1ffff010c 00 00 00 00
@1ffff0110 00 00 00 00
@1ffff0114 00 00 00 00
@1ffff0118 00 00 00 00
@1ffff011c 00 00 00 00
@1ffff0120 00 00 00 00
@1ffff0124 00 00 00 00
@1ffff0128 00 00 00 00
@1ffff012c 00 00 00 00
@1ffff0130 00 00 00 00
@1ffff0134 00 00 00 00
@1ffff0138 00 00 00 00
@1ffff013c 00 00 00 00
@1ffff0140 00 00 00 00
@1ffff0144 00 00 00 00
@1ffff0148 00 00 00 00
@1ffff014c 00 00 00 00
@1ffff0150 00 00 00 00
@1ffff0154 00 00 00 00
@1ffff0158 00 00 00 00
@1ffff015c 00 00 00 00
@1ffff0160 00 00 00 00
@1ffff0164 00 00 00 00
@1ffff0168 00 00 00 00
@1ffff016C 00 00 00 00
@1ffff0170 00 00 00 00
@1ffff0174 00 00 00 00
@1ffff0178 00 00 00 00
@1ffff017c 00 00 00 00
@1ffff0180 00 00 00 00
@1ffff0184 00 00 00 00
@1ffff0188 00 00 00 00
@1ffff018c 00 00 00 00
@1ffff0190 00 00 00 00
@1ffff0194 00 00 00 00
@1ffff0198 00 00 00 00
@1ffff019c 00 00 00 00
@1ffff01a0 00 00 00 00
@1ffff01a4 00 00 00 00
@1ffff01a8 00 00 00 00
@1ffff01ac 00 00 00 00
@1ffff01b0 00 00 00 00
@1ffff01b4 00 00 00 00
@1ffff01b8 00 00 00 00
@1ffff01bc 00 00 00 00
@1ffff01c0 00 00 00 00
@1ffff01c4 00 00 00 00
@1ffff01c8 00 00 00 00
@1ffff01cc 00 00 00 00
@1ffff01d0 00 00 00 00
@1ffff01d4 00 00 00 00
@1ffff01d8 00 00 00 00
@1ffff01dc 00 00 00 00
@1ffff01e0 00 00 00 00
@1ffff01e4 00 00 00 00
@1ffff01e8 00 00 00 00
@1ffff01ec 00 00 00 00
@1ffff01f0 00 00 00 00
@1ffff01f4 00 00 00 00
@1ffff01f8 00 00 00 00
@1ffff01fc 00 00 00 00
@0ffff0000 00 00 00 00
@0ffff0004 00 00 00 00
@0ffff0008 00 00 00 00
@0ffff000c 00 00 00 00
@0ffff0010 00 00 00 00
@0ffff0014 00 00 00 00
@0ffff0018 00 00 00 00
@0ffff001c 00 00 00 00
@0ffff0020 00 00 00 00
@0ffff0024 00 00 00 00
@0ffff0028 00 00 00 00
@0ffff002c 00 00 00 00
@0ffff0030 00 00 00 00
@0ffff0034 00 00 00 00
@0ffff0038 00 00 00 00
@0ffff003c 00 00 00 00
@0ffff0040 00 00 00 00
@0ffff0044 00 00 00 00
@0ffff0048 00 00 00 00
@0ffff004c 00 00 00 00
@0ffff0050 00 00 00 00
@0ffff0054 00 00 00 00
@0ffff0058 00 00 00 00
@0ffff005c 00 00 00 00
@0ffff0060 00 00 00 00
@0ffff0064 00 00 00 00
@0ffff0068 00 00 00 00
@0ffff006C 00 00 00 00
@0ffff0070 00 00 00 00
@0ffff0074 00 00 00 00
@0ffff0078 00 00 00 00
@0ffff007c 00 00 00 00
@0ffff0080 00 00 00 00
@0ffff0084 00 00 00 00
@0ffff0088 00 00 00 00
@0ffff008c 00 00 00 00
@0ffff0090 00 00 00 00
@0ffff0094 00 00 00 00
@0ffff0098 00 00 00 00
@0ffff009c 00 00 00 00
@0ffff00a0 00 00 00 00
@0ffff00a4 00 00 00 00
@0ffff00a8 00 00 00 00
@0ffff00ac 00 00 00 00
@0ffff00b0 00 00 00 00
@0ffff00b4 00 00 00 00
@0ffff00b8 00 00 00 00
@0ffff00bc 00 00 00 00
@0ffff00c0 00 00 00 00
@0ffff00c4 00 00 00 00
@0ffff00c8 00 00 00 00
@0ffff00cc 00 00 00 00
@0ffff00d0 00 00 00 00
@0ffff00d4 00 00 00 00
@0ffff00d8 00 00 00 00
@0ffff00dc 00 00 00 00
@0ffff00e0 00 00 00 00
@0ffff00e4 00 00 00 00
@0ffff00e8 00 00 00 00
@0ffff00ec 00 00 00 00
@0ffff00f0 00 00 00 00
@0ffff00f4 00 00 00 00
@0ffff00f8 00 00 00 00
@0ffff00fc 00 00 00 00
@0ffff0100 00 00 00 00
@0ffff0104 00 00 00 00
@0ffff0108 00 00 00 00
@0ffff010c 00 00 00 00
@0ffff0110 00 00 00 00
@0ffff0114 00 00 00 00
@0ffff0118 00 00 00 00
@0ffff011c 00 00 00 00
@0ffff0120 00 00 00 00
@0ffff0124 00 00 00 00
@0ffff0128 00 00 00 00
@0ffff012c 00 00 00 00
@0ffff0130 00 00 00 00
@0ffff0134 00 00 00 00
@0ffff0138 00 00 00 00
@0ffff013c 00 00 00 00
@0ffff0140 00 00 00 00
@0ffff0144 00 00 00 00
@0ffff0148 00 00 00 00
@0ffff014c 00 00 00 00
@0ffff0150 00 00 00 00
@0ffff0154 00 00 00 00
@0ffff0158 00 00 00 00
@0ffff015c 00 00 00 00
@0ffff0160 00 00 00 00
@0ffff0164 00 00 00 00
@0ffff0168 00 00 00 00
@0ffff016C 00 00 00 00
@0ffff0170 00 00 00 00
@0ffff0174 00 00 00 00
@0ffff0178 00 00 00 00
@0ffff017c 00 00 00 00
@0ffff0180 00 00 00 00
@0ffff0184 00 00 00 00
@0ffff0188 00 00 00 00
@0ffff018c 00 00 00 00
@0ffff0190 00 00 00 00
@0ffff0194 00 00 00 00
@0ffff0198 00 00 00 00
@0ffff019c 00 00 00 00
@0ffff01a0 00 00 00 00
@0ffff01a4 00 00 00 00
@0ffff01a8 00 00 00 00
@0ffff01ac 00 00 00 00
@0ffff01b0 00 00 00 00
@0ffff01b4 00 00 00 00
@0ffff01b8 00 00 00 00
@0ffff01bc 00 00 00 00
@0ffff01c0 00 00 00 00
@0ffff01c4 00 00 00 00
@0ffff01c8 00 00 00 00
@0ffff01cc 00 00 00 00
@0ffff01d0 00 00 00 00
@0ffff01d4 00 00 00 00
@0ffff01d8 00 00 00 00
@0ffff01dc 00 00 00 00
@0ffff01e0 00 00 00 00
@0ffff01e4 00 00 00 00
@0ffff01e8 00 00 00 00
@0ffff01ec 00 00 00 00
@0ffff01f0 00 00 00 00
@0ffff01f4 00 00 00 00
@0ffff01f8 00 00 00 00
@0ffff01fc 00 00 00 00

View File

@ -0,0 +1,17 @@
onbreak {resume}
# create library
if [file exists work] {
vdel -all
}
vlib work
vlog +incdir+../../../config/rv64ic +incdir+../../../config/shared ../../../testbench/common/*.sv ../../*/*.sv sd_top_tb.sv sdModel.sv sd_crc_7.sv sd_crc_16.sv -suppress 2583
vopt -fsmdebug +acc -gDEBUG=1 work.sd_top_tb -o workopt
vsim workopt -fsmdebug
do wave.do
add log -r /*
run 3000 us

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,48 @@
// ==========================================================================
// CRC Generation Unit - Linear Feedback Shift Register implementation
// (c) Kay Gorontzi, GHSi.de, distributed under the terms of LGPL
// https://www.ghsi.de/CRC/index.php?
// https://www.ghsi.de/CRC/index.php?
// =========================================================================
module sd_crc_16(BITVAL, Enable, CLK, RST, CRC);
input BITVAL;// Next input bit
input Enable;
input CLK; // Current bit valid (Clock)
input RST; // Init CRC value
output reg [15:0] CRC; // Current output CRC value
// We need output registers
wire inv;
assign inv = BITVAL ^ CRC[15]; // XOR required?
always @(posedge CLK or posedge RST) begin
if (RST) begin
CRC = 0;
end
else begin
if (Enable==1) begin
CRC[15] = CRC[14];
CRC[14] = CRC[13];
CRC[13] = CRC[12];
CRC[12] = CRC[11] ^ inv;
CRC[11] = CRC[10];
CRC[10] = CRC[9];
CRC[9] = CRC[8];
CRC[8] = CRC[7];
CRC[7] = CRC[6];
CRC[6] = CRC[5];
CRC[5] = CRC[4] ^ inv;
CRC[4] = CRC[3];
CRC[3] = CRC[2];
CRC[2] = CRC[1];
CRC[1] = CRC[0];
CRC[0] = inv;
end
end
end
endmodule

View File

@ -0,0 +1,34 @@
module sd_crc_7(BITVAL, Enable, CLK, RST, CRC);
input BITVAL;// Next input bit
input Enable;
input CLK; // Current bit valid (Clock)
input RST; // Init CRC value
output [6:0] CRC; // Current output CRC value
reg [6:0] CRC;
// We need output registers
wire inv;
assign inv = BITVAL ^ CRC[6]; // XOR required?
always @(posedge CLK or posedge RST) begin
if (RST) begin
CRC = 0;
end
else begin
if (Enable==1) begin
CRC[6] = CRC[5];
CRC[5] = CRC[4];
CRC[4] = CRC[3];
CRC[3] = CRC[2] ^ inv;
CRC[2] = CRC[1];
CRC[1] = CRC[0];
CRC[0] = inv;
end
end
end
endmodule

View File

@ -0,0 +1,89 @@
//Read the documentation before changing values
`define BIG_ENDIAN
//`define LITLE_ENDIAN
`define SIM
//`define SYN
`define SDC_IRQ_ENABLE
`define ACTEL
//`define CUSTOM
//`define ALTERA
//`define XLINX
//`define SIMULATOR
`define RESEND_MAX_CNT 3
//MAX 255 BD
//BD size/4
`ifdef ACTEL
`define BD_WIDTH 5
`define BD_SIZE 32
`define RAM_MEM_WIDTH_16
`define RAM_MEM_WIDTH 16
`endif
//`ifdef CUSTOM
// `define NR_O_BD_4
// `define BD_WIDTH 5
// `define BD_SIZE 32
// `define RAM_MEM_WIDTH_32
// `define RAM_MEM_WIDTH 32
//`endif
`ifdef SYN
`define RESET_CLK_DIV 0
`define MEM_OFFSET 4
`endif
`ifdef SIM
`define RESET_CLK_DIV 0
`define MEM_OFFSET 4
`endif
//SD-Clock Defines ---------
//Use bus clock or a seperate clock
`define SDC_CLK_BUS_CLK
//`define SDC_CLK_SEP
// Use of internal clock divider
//`define SDC_CLK_STATIC
`define SDC_CLK_DYNAMIC
//SD DATA-transfer defines---
`define BLOCK_SIZE 512
`define SD_BUS_WIDTH_4
`define SD_BUS_W 4
//at 512 bytes per block, equal 1024 4 bytes writings with a bus width of 4, add 2 for startbit and Z bit.
//Add 18 for crc, endbit and z.
`define BIT_BLOCK 1044
`define CRC_OFF 19
`define BIT_BLOCK_REC 1024
`define BIT_CRC_CYCLE 16
//FIFO defines---------------
`define FIFO_RX_MEM_DEPTH 8
`define FIFO_RX_MEM_ADR_SIZE 4
`define FIFO_TX_MEM_DEPTH 8
`define FIFO_TX_MEM_ADR_SIZE 4
//---------------------------

View File

@ -0,0 +1,115 @@
///////////////////////////////////////////
// sd_top_tb.sv
//
// Written: Ross Thompson September 20, 2021
// Modified:
//
// 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_tb();
localparam integer g_COUNT_WIDTH = 8;
logic a_RST;
logic i_SD_CMD;
logic o_SD_CMD;
logic o_SD_CMD_OE;
wire [3:0] i_SD_DAT;
logic o_SD_CLK;
logic [32:9] i_BLOCK_ADDR;
logic [g_COUNT_WIDTH-1:0] i_COUNT_IN_MAX;
logic o_READY_FOR_READ;
logic i_READ_REQUEST;
logic [3:0] o_DATA_TO_CORE;
logic o_DATA_VALID;
logic o_LAST_NIBBLE;
// Driver
wire PAD;
logic r_CLK;
// clock
sd_top #(g_COUNT_WIDTH) DUT
(.CLK(r_CLK),
.a_RST(a_RST),
.i_SD_CMD(i_SD_CMD),
.o_SD_CMD(o_SD_CMD),
.o_SD_CMD_OE(o_SD_CMD_OE),
.i_SD_DAT(i_SD_DAT),
.o_SD_CLK(o_SD_CLK),
.i_BLOCK_ADDR(i_BLOCK_ADDR),
.o_READY_FOR_READ(o_READY_FOR_READ),
.i_READ_REQUEST(i_READ_REQUEST),
.o_DATA_TO_CORE(o_DATA_TO_CORE),
.o_DATA_VALID(o_DATA_VALID),
.o_LAST_NIBBLE(o_LAST_NIBBLE),
.i_COUNT_IN_MAX(i_COUNT_IN_MAX),
.LIMIT_SD_TIMERS(1'b1));
sdModel sdcard
(.sdClk(o_SD_CLK),
.cmd(PAD),
.dat(i_SD_DAT));
// tri state pad
// replace with I/O standard cell or FPGA gate.
assign PAD = o_SD_CMD_OE ? o_SD_CMD : 1'bz;
assign i_SD_CMD = PAD;
always
begin
r_CLK = 1; # 5; r_CLK = 0; # 5;
end
initial begin
a_RST = 1'b0;
i_BLOCK_ADDR = 24'h100000;
i_COUNT_IN_MAX = '0;
i_READ_REQUEST = 1'b0;
# 5;
i_COUNT_IN_MAX = -62;
# 10;
a_RST = 1'b1;
# 4800;
a_RST = 1'b0;
# 2000000;
i_READ_REQUEST = 1'b0;
# 10000;
i_READ_REQUEST = 1'b1;
# 10000;
i_READ_REQUEST = 1'b0;
end
endmodule

View File

@ -0,0 +1,127 @@
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate /sd_top_tb/DUT/a_RST
add wave -noupdate /sd_top_tb/DUT/CLK
add wave -noupdate /sd_top_tb/DUT/i_BLOCK_ADDR
add wave -noupdate /sd_top_tb/DUT/i_READ_REQUEST
add wave -noupdate /sd_top_tb/DUT/i_COUNT_IN_MAX
add wave -noupdate /sd_top_tb/DUT/LIMIT_SD_TIMERS
add wave -noupdate /sd_top_tb/DUT/o_READY_FOR_READ
add wave -noupdate /sd_top_tb/DUT/o_SD_RESTARTING
add wave -noupdate /sd_top_tb/DUT/o_DATA_TO_CORE
add wave -noupdate /sd_top_tb/DUT/o_DATA_VALID
add wave -noupdate /sd_top_tb/DUT/o_LAST_NIBBLE
add wave -noupdate /sd_top_tb/DUT/o_ERROR_CODE_Q
add wave -noupdate /sd_top_tb/DUT/o_FATAL_ERROR
add wave -noupdate -expand -group interface /sd_top_tb/DUT/o_SD_CLK
add wave -noupdate -expand -group interface /sd_top_tb/DUT/o_SD_CMD
add wave -noupdate -expand -group interface /sd_top_tb/DUT/o_SD_CMD_OE
add wave -noupdate -expand -group interface /sd_top_tb/DUT/i_SD_CMD
add wave -noupdate -expand -group interface /sd_top_tb/DUT/i_SD_DAT
add wave -noupdate -label {cmd fsm} /sd_top_tb/DUT/my_sd_cmd_fsm/r_curr_state
add wave -noupdate -label {dat fsm} /sd_top_tb/DUT/my_sd_dat_fsm/r_curr_state
add wave -noupdate -label {clk fsm} /sd_top_tb/DUT/my_clk_fsm/r_curr_state
add wave -noupdate -group old /sd_top_tb/DUT/my_sd_cmd_fsm/i_RST
add wave -noupdate -group old /sd_top_tb/DUT/my_sd_cmd_fsm/i_TIMER_OUT
add wave -noupdate -group old /sd_top_tb/DUT/my_sd_cmd_fsm/i_COUNTER_OUT
add wave -noupdate -group old /sd_top_tb/DUT/my_sd_cmd_fsm/i_CLOCK_CHANGE_DONE
add wave -noupdate -group old /sd_top_tb/DUT/my_sd_cmd_fsm/i_IC_OUT
add wave -noupdate -group old /sd_top_tb/DUT/my_sd_cmd_fsm/i_USES_DAT
add wave -noupdate -group old /sd_top_tb/DUT/my_sd_cmd_fsm/i_OPCODE
add wave -noupdate -group old /sd_top_tb/DUT/my_sd_cmd_fsm/i_R_TYPE
add wave -noupdate -group old /sd_top_tb/DUT/my_sd_cmd_fsm/i_NO_REDO_MASK
add wave -noupdate -group old /sd_top_tb/DUT/my_sd_cmd_fsm/i_NO_REDO_ANS
add wave -noupdate -group old /sd_top_tb/DUT/my_sd_cmd_fsm/i_NO_ERROR_MASK
add wave -noupdate -group old /sd_top_tb/DUT/my_sd_cmd_fsm/i_NO_ERROR_ANS
add wave -noupdate -group old /sd_top_tb/DUT/my_sd_cmd_fsm/i_SD_CMD_RX
add wave -noupdate -group old /sd_top_tb/DUT/my_sd_cmd_fsm/i_RESPONSE_CONTENT
add wave -noupdate -group old /sd_top_tb/DUT/my_sd_cmd_fsm/i_RESPONSE_INDEX
add wave -noupdate -group old /sd_top_tb/DUT/my_sd_cmd_fsm/i_RX_CRC7
add wave -noupdate -group old /sd_top_tb/DUT/my_sd_cmd_fsm/i_DAT_RX_DONE
add wave -noupdate -group old /sd_top_tb/DUT/my_sd_cmd_fsm/i_ERROR_CRC16
add wave -noupdate -group old /sd_top_tb/DUT/my_sd_cmd_fsm/i_ERROR_DAT_TIMES_OUT
add wave -noupdate -group old /sd_top_tb/DUT/my_sd_cmd_fsm/i_READ_REQUEST
add wave -noupdate -group old /sd_top_tb/DUT/my_sd_cmd_fsm/LIMIT_SD_TIMERS
add wave -noupdate -group old /sd_top_tb/DUT/my_clk_fsm/i_START
add wave -noupdate -group old /sd_top_tb/DUT/my_clk_fsm/i_FATAL_ERROR
add wave -noupdate -group old /sd_top_tb/DUT/my_clk_fsm/i_RST
add wave -noupdate -group old /sd_top_tb/DUT/my_clk_fsm/o_DONE
add wave -noupdate -group old /sd_top_tb/DUT/my_clk_fsm/o_G_CLK_SD_EN
add wave -noupdate -group old /sd_top_tb/DUT/my_clk_fsm/o_HS_TO_INIT_CLK_DIVIDER_RST
add wave -noupdate -group old /sd_top_tb/DUT/my_clk_fsm/o_SD_CLK_SELECTED
add wave -noupdate -group old -expand /sd_top_tb/DUT/w_OPCODE_Q
add wave -noupdate -group old /sd_top_tb/DUT/c_CMD
add wave -noupdate -group old /sd_top_tb/DUT/c_ACMD
add wave -noupdate -group old /sd_top_tb/DUT/c_Go_Idle_State
add wave -noupdate -group old /sd_top_tb/DUT/c_response_type_R0_NONE
add wave -noupdate -group old /sd_top_tb/DUT/c_response_type_R0_NONE
add wave -noupdate -group old /sd_top_tb/DUT/c_response_type_R1_NORMAL
add wave -noupdate -group old /sd_top_tb/DUT/c_response_type_R2_CID_CSD
add wave -noupdate -group old /sd_top_tb/DUT/c_response_type_R3_OCR
add wave -noupdate -group old /sd_top_tb/DUT/c_response_type_R6_RCA
add wave -noupdate -group old /sd_top_tb/DUT/c_response_type_R7_CIC
add wave -noupdate -group old /sd_top_tb/DUT/w_instruction_control_bits
add wave -noupdate -group old /sd_top_tb/DUT/w_command_index
add wave -noupdate -group old /sd_top_tb/DUT/r_IC_OUT
add wave -noupdate -group old /sd_top_tb/DUT/w_BLOCK_ADDR
add wave -noupdate /sd_top_tb/DUT/w_TX_SOURCE_SELECT
add wave -noupdate /sd_top_tb/DUT/w_tx_tail_Q
add wave -noupdate /sd_top_tb/DUT/w_TX_PISO8_LOAD
add wave -noupdate /sd_top_tb/DUT/w_TX_PISO8_EN
add wave -noupdate /sd_top_tb/DUT/r_command_tail
add wave -noupdate /sd_top_tb/DUT/r_TX_CRC7
add wave -noupdate /sd_top_tb/DUT/w_TX_CRC7_PIPO_RST
add wave -noupdate /sd_top_tb/DUT/w_TX_CRC7_PIPO_EN
add wave -noupdate /sd_top_tb/DUT/w_command_head
add wave -noupdate /sd_top_tb/DUT/my_sd_dat_fsm/i_DAT0_Q
add wave -noupdate /sd_top_tb/sdcard/oeDat
add wave -noupdate /sd_top_tb/sdcard/datOut
add wave -noupdate /sd_top_tb/sdcard/dat
add wave -noupdate /sd_top_tb/DUT/my_sd_cmd_fsm/w_resend_last_command
add wave -noupdate /sd_top_tb/DUT/my_sd_cmd_fsm/i_ERROR_CRC16
add wave -noupdate /sd_top_tb/DUT/r_DAT3_CRC16
add wave -noupdate /sd_top_tb/DUT/r_DAT2_CRC16
add wave -noupdate /sd_top_tb/DUT/r_DAT1_CRC16
add wave -noupdate /sd_top_tb/DUT/r_DAT0_CRC16
add wave -noupdate -radix decimal /sd_top_tb/DUT/my_sd_cmd_fsm/i_COUNTER_OUT
add wave -noupdate /sd_top_tb/DUT/CLK
add wave -noupdate /sd_top_tb/DUT/r_CLK_SD
add wave -noupdate -expand -group {clock divider} /sd_top_tb/DUT/slow_clk_divider/i_COUNT_IN_MAX
add wave -noupdate -expand -group {clock divider} /sd_top_tb/DUT/slow_clk_divider/i_EN
add wave -noupdate -expand -group {clock divider} /sd_top_tb/DUT/slow_clk_divider/i_CLK
add wave -noupdate -expand -group {clock divider} /sd_top_tb/DUT/slow_clk_divider/i_RST
add wave -noupdate -expand -group {clock divider} /sd_top_tb/DUT/slow_clk_divider/g_COUNT_WIDTH
add wave -noupdate -expand -group {clock divider} /sd_top_tb/DUT/slow_clk_divider/r_count_out
add wave -noupdate -expand -group {clock divider} /sd_top_tb/DUT/slow_clk_divider/w_counter_overflowed
add wave -noupdate -expand -group {clock divider} /sd_top_tb/DUT/slow_clk_divider/r_fd_Q
add wave -noupdate -expand -group {clock divider} /sd_top_tb/DUT/slow_clk_divider/w_fd_D
add wave -noupdate -expand -group {clock divider} /sd_top_tb/DUT/slow_clk_divider/w_load
add wave -noupdate -expand -group {clock divider} /sd_top_tb/DUT/slow_clk_divider/o_CLK
add wave -noupdate /sd_top_tb/sdcard/ByteAddr
add wave -noupdate /sd_top_tb/sdcard/write_out_index
add wave -noupdate /sd_top_tb/sdcard/inCmd
add wave -noupdate /sd_top_tb/DUT/w_TX_SOURCE_SELECT
add wave -noupdate /sd_top_tb/DUT/w_command_head
add wave -noupdate /sd_top_tb/DUT/r_IC_OUT
add wave -noupdate /sd_top_tb/DUT/w_BLOCK_ADDR
add wave -noupdate /sd_top_tb/DUT/i_BLOCK_ADDR
add wave -noupdate /sd_top_tb/DUT/regfile_cmd17_data_block/regs
add wave -noupdate /sd_top_tb/DUT/regfile_cmd17_data_block/ra1
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {2028326 ns} 0} {{Cursor 2} {4831 ns} 0}
quietly wave cursor active 1
configure wave -namecolwidth 245
configure wave -valuecolwidth 180
configure wave -justifyvalue left
configure wave -signalnamewidth 1
configure wave -snapdistance 10
configure wave -datasetprefix 0
configure wave -rowmargin 4
configure wave -childrowmargin 2
configure wave -gridoffset 0
configure wave -gridperiod 1
configure wave -griddelta 40
configure wave -timeline 0
configure wave -timelineunits ns
update
WaveRestoreZoom {2013966 ns} {2038576 ns}

View File

@ -0,0 +1,55 @@
///////////////////////////////////////////
// counter.sv
//
// Written: Ross Thompson
// Modified:
//
// Purpose: basic up counter
//
// 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 up_down_counter #(parameter integer WIDTH=32)
(
input logic [WIDTH-1:0] CountIn,
output logic [WIDTH-1:0] CountOut,
input logic Load,
input logic Enable,
input logic UpDown,
input logic clk,
input logic reset);
logic [WIDTH-1:0] NextCount;
logic [WIDTH-1:0] count_q;
logic [WIDTH-1:0] CountP1;
flopenr #(WIDTH) reg1(.clk,
.reset,
.en(Enable | Load),
.d(NextCount),
.q(CountOut));
assign CountP1 = UpDown ? CountOut + 1'b1 : CountOut - 1'b1;
// mux between load and P1
assign NextCount = Load ? CountIn : CountP1;
endmodule