From ec0d2bc7d745a3ff0e681d217275418a7a5ae21a Mon Sep 17 00:00:00 2001 From: Ross Thompson Date: Wed, 22 Sep 2021 10:50:29 -0500 Subject: [PATCH] Initial SD Card reader. --- wally-pipelined/proposed-sdc.txt | 55 + wally-pipelined/src/sdc/clkdivider.sv | 72 ++ wally-pipelined/src/sdc/counter.sv | 54 + wally-pipelined/src/sdc/crc16_sipo_np_ce.sv | 62 + wally-pipelined/src/sdc/crc7_pipo.sv | 66 ++ wally-pipelined/src/sdc/crc7_sipo_np_ce.sv | 61 + wally-pipelined/src/sdc/piso_generic_ce.sv | 51 + .../src/sdc/regfile_p2r1w1_nibo.sv | 45 + wally-pipelined/src/sdc/regfile_p2r1w1bwen.sv | 51 + wally-pipelined/src/sdc/sd_clk_fsm.sv | 94 ++ wally-pipelined/src/sdc/sd_cmd_fsm.sv | 554 +++++++++ wally-pipelined/src/sdc/sd_dat_fsm.sv | 233 ++++ wally-pipelined/src/sdc/sd_top.sv | 665 +++++++++++ wally-pipelined/src/sdc/simple_timer.sv | 55 + wally-pipelined/src/sdc/sipo_generic_ce.sv | 53 + wally-pipelined/src/sdc/tb/ramdisk2.hex | 384 ++++++ wally-pipelined/src/sdc/tb/run_tb.do | 17 + wally-pipelined/src/sdc/tb/sdModel.sv | 1052 +++++++++++++++++ wally-pipelined/src/sdc/tb/sd_crc_16.sv | 48 + wally-pipelined/src/sdc/tb/sd_crc_7.sv | 34 + wally-pipelined/src/sdc/tb/sd_defines.h | 89 ++ wally-pipelined/src/sdc/tb/sd_top_tb.sv | 115 ++ wally-pipelined/src/sdc/tb/wave.do | 127 ++ wally-pipelined/src/sdc/up_down_counter.sv | 55 + 24 files changed, 4092 insertions(+) create mode 100644 wally-pipelined/proposed-sdc.txt create mode 100644 wally-pipelined/src/sdc/clkdivider.sv create mode 100644 wally-pipelined/src/sdc/counter.sv create mode 100644 wally-pipelined/src/sdc/crc16_sipo_np_ce.sv create mode 100644 wally-pipelined/src/sdc/crc7_pipo.sv create mode 100644 wally-pipelined/src/sdc/crc7_sipo_np_ce.sv create mode 100644 wally-pipelined/src/sdc/piso_generic_ce.sv create mode 100644 wally-pipelined/src/sdc/regfile_p2r1w1_nibo.sv create mode 100644 wally-pipelined/src/sdc/regfile_p2r1w1bwen.sv create mode 100644 wally-pipelined/src/sdc/sd_clk_fsm.sv create mode 100644 wally-pipelined/src/sdc/sd_cmd_fsm.sv create mode 100644 wally-pipelined/src/sdc/sd_dat_fsm.sv create mode 100644 wally-pipelined/src/sdc/sd_top.sv create mode 100644 wally-pipelined/src/sdc/simple_timer.sv create mode 100644 wally-pipelined/src/sdc/sipo_generic_ce.sv create mode 100644 wally-pipelined/src/sdc/tb/ramdisk2.hex create mode 100644 wally-pipelined/src/sdc/tb/run_tb.do create mode 100644 wally-pipelined/src/sdc/tb/sdModel.sv create mode 100644 wally-pipelined/src/sdc/tb/sd_crc_16.sv create mode 100644 wally-pipelined/src/sdc/tb/sd_crc_7.sv create mode 100644 wally-pipelined/src/sdc/tb/sd_defines.h create mode 100644 wally-pipelined/src/sdc/tb/sd_top_tb.sv create mode 100644 wally-pipelined/src/sdc/tb/wave.do create mode 100644 wally-pipelined/src/sdc/up_down_counter.sv diff --git a/wally-pipelined/proposed-sdc.txt b/wally-pipelined/proposed-sdc.txt new file mode 100644 index 00000000..893143dd --- /dev/null +++ b/wally-pipelined/proposed-sdc.txt @@ -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 diff --git a/wally-pipelined/src/sdc/clkdivider.sv b/wally-pipelined/src/sdc/clkdivider.sv new file mode 100644 index 00000000..084d020a --- /dev/null +++ b/wally-pipelined/src/sdc/clkdivider.sv @@ -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 diff --git a/wally-pipelined/src/sdc/counter.sv b/wally-pipelined/src/sdc/counter.sv new file mode 100644 index 00000000..2a1f93bc --- /dev/null +++ b/wally-pipelined/src/sdc/counter.sv @@ -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 + + diff --git a/wally-pipelined/src/sdc/crc16_sipo_np_ce.sv b/wally-pipelined/src/sdc/crc16_sipo_np_ce.sv new file mode 100644 index 00000000..444555c7 --- /dev/null +++ b/wally-pipelined/src/sdc/crc16_sipo_np_ce.sv @@ -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 diff --git a/wally-pipelined/src/sdc/crc7_pipo.sv b/wally-pipelined/src/sdc/crc7_pipo.sv new file mode 100644 index 00000000..46ba0062 --- /dev/null +++ b/wally-pipelined/src/sdc/crc7_pipo.sv @@ -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 diff --git a/wally-pipelined/src/sdc/crc7_sipo_np_ce.sv b/wally-pipelined/src/sdc/crc7_sipo_np_ce.sv new file mode 100644 index 00000000..5721aa95 --- /dev/null +++ b/wally-pipelined/src/sdc/crc7_sipo_np_ce.sv @@ -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 + + diff --git a/wally-pipelined/src/sdc/piso_generic_ce.sv b/wally-pipelined/src/sdc/piso_generic_ce.sv new file mode 100644 index 00000000..ad1d6a17 --- /dev/null +++ b/wally-pipelined/src/sdc/piso_generic_ce.sv @@ -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 diff --git a/wally-pipelined/src/sdc/regfile_p2r1w1_nibo.sv b/wally-pipelined/src/sdc/regfile_p2r1w1_nibo.sv new file mode 100644 index 00000000..3bb1329e --- /dev/null +++ b/wally-pipelined/src/sdc/regfile_p2r1w1_nibo.sv @@ -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 diff --git a/wally-pipelined/src/sdc/regfile_p2r1w1bwen.sv b/wally-pipelined/src/sdc/regfile_p2r1w1bwen.sv new file mode 100644 index 00000000..4ace3749 --- /dev/null +++ b/wally-pipelined/src/sdc/regfile_p2r1w1bwen.sv @@ -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 diff --git a/wally-pipelined/src/sdc/sd_clk_fsm.sv b/wally-pipelined/src/sdc/sd_clk_fsm.sv new file mode 100644 index 00000000..337cb8c7 --- /dev/null +++ b/wally-pipelined/src/sdc/sd_clk_fsm.sv @@ -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 + diff --git a/wally-pipelined/src/sdc/sd_cmd_fsm.sv b/wally-pipelined/src/sdc/sd_cmd_fsm.sv new file mode 100644 index 00000000..c98448c7 --- /dev/null +++ b/wally-pipelined/src/sdc/sd_cmd_fsm.sv @@ -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 diff --git a/wally-pipelined/src/sdc/sd_dat_fsm.sv b/wally-pipelined/src/sdc/sd_dat_fsm.sv new file mode 100644 index 00000000..add3d6d3 --- /dev/null +++ b/wally-pipelined/src/sdc/sd_dat_fsm.sv @@ -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 diff --git a/wally-pipelined/src/sdc/sd_top.sv b/wally-pipelined/src/sdc/sd_top.sv new file mode 100644 index 00000000..cfa3ced6 --- /dev/null +++ b/wally-pipelined/src/sdc/sd_top.sv @@ -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 + diff --git a/wally-pipelined/src/sdc/simple_timer.sv b/wally-pipelined/src/sdc/simple_timer.sv new file mode 100644 index 00000000..8138cb8a --- /dev/null +++ b/wally-pipelined/src/sdc/simple_timer.sv @@ -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 + diff --git a/wally-pipelined/src/sdc/sipo_generic_ce.sv b/wally-pipelined/src/sdc/sipo_generic_ce.sv new file mode 100644 index 00000000..210767af --- /dev/null +++ b/wally-pipelined/src/sdc/sipo_generic_ce.sv @@ -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 diff --git a/wally-pipelined/src/sdc/tb/ramdisk2.hex b/wally-pipelined/src/sdc/tb/ramdisk2.hex new file mode 100644 index 00000000..bd568d9c --- /dev/null +++ b/wally-pipelined/src/sdc/tb/ramdisk2.hex @@ -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 diff --git a/wally-pipelined/src/sdc/tb/run_tb.do b/wally-pipelined/src/sdc/tb/run_tb.do new file mode 100644 index 00000000..a2d3ba38 --- /dev/null +++ b/wally-pipelined/src/sdc/tb/run_tb.do @@ -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 diff --git a/wally-pipelined/src/sdc/tb/sdModel.sv b/wally-pipelined/src/sdc/tb/sdModel.sv new file mode 100644 index 00000000..29f2336d --- /dev/null +++ b/wally-pipelined/src/sdc/tb/sdModel.sv @@ -0,0 +1,1052 @@ +//`include "timescale.v" +//`timescale 1ps / 1ps +`include "sd_defines.h" +`define tTLH 10 //Clock rise time +`define tHL 10 //Clock fall time +`define tISU 6 //Input setup time +`define tIH 0 //Input hold time +`define tODL 14 //Output delay +`define DLY_TO_OUTP 47 //47 + +`define BLOCKSIZE 512 +`define MEMSIZE 24643590 // 2mb block +`define BLOCK_BUFFER_SIZE 1 +`define TIME_BUSY 63 + +`define PRG 7 +`define RCV 6 +`define DATAS 5 +`define TRAN 4 + +module sdModel + ( + input sdClk, + inout tri1 cmd, + inout tri1 [3:0] dat + ); + parameter SD_FILE = "ramdisk2.hex"; + + reg oeCmd; + reg oeDat; + reg cmdOut; + reg [3:0] datOut; + reg [10:0] transf_cnt; + reg [10:0] BLOCK_WIDTH; + + reg [5:0] lastCMD; + reg cardIdentificationState; + reg CardTransferActive; + reg [2:0] BusWidth; + + assign cmd = oeCmd ? cmdOut : 1'bz; + assign dat = oeDat ? datOut : 4'bz; + + reg InbuffStatus; + reg [32:0] ByteAddr; + reg [7:0] Inbuff [0:511]; + reg [7:0] FLASHmem [logic[32:0]]; + reg [7:0] wide_data [0:63]; + + + + reg [46:0] inCmd; + reg [5:0] cmdRead; + reg [7:0] cmdWrite; + reg crcIn; + reg crcEn; + reg crcRst; + reg [31:0] CardStatus; + reg [15:0] RCA; + reg [31:0] OCR; + reg [120:0] CID; + reg [120:0] CSD; + reg Busy; //0 when busy + wire [6:0] crcOut; + reg [4:0] crc_c; + + reg [3:0] CurrentState; + reg [3:0] DataCurrentState; + +`define RCASTART 16'h2000 +`define OCRSTART 32'h40ff8000 // SDHC +`define STATUSSTART 32'h0 +`define CIDSTART 128'hffffffddddddddaaaaaaaa99999999 //Just some random data not really useful anyway +`define CSDSTART 128'hadaeeeddddddddaaaaaaaa12345678 + +`define outDelay 4 + reg [2:0] outDelayCnt; + reg [9:0] flash_write_cnt; + reg [8:0] flash_blockwrite_cnt; + + parameter SIZE = 10; + parameter CONTENT_SIZE = 40; + parameter + IDLE = 10'b0000_0000_01, + READ_CMD = 10'b0000_0000_10, + ANALYZE_CMD = 10'b0000_0001_00, + SEND_CMD = 10'b0000_0010_00; + reg [SIZE-1:0] state; + reg [SIZE-1:0] next_state; + + parameter + DATA_IDLE =10'b0000_0000_01, + READ_WAITS =10'b0000_0000_10, + READ_DATA =10'b0000_0001_00, + WRITE_FLASH =10'b0000_0010_00, + WRITE_DATA =10'b0000_0100_00; + parameter okcrctoken = 4'b0101; + parameter invalidcrctoken = 4'b1111; + reg [SIZE-1:0] dataState; + reg [SIZE-1:0] next_datastate; + + reg ValidCmd; + reg inValidCmd; + + reg [7:0] response_S; + reg [135:0] response_CMD; + integer responseType; + + reg [9:0] block_cnt; + reg wptr; + reg crc_ok; + reg [3:0] last_din; + + reg crcDat_rst; + reg mult_read; + reg mult_write; + reg crcDat_en; + reg [3:0] crcDat_in; + wire [15:0] crcDat_out [3:0]; + + genvar i; + generate + for(i=0; i<4; i=i+1) begin:CRC_16_gen + sd_crc_16 CRC_16_i (crcDat_in[i],crcDat_en, sdClk, crcDat_rst, crcDat_out[i]); + end + endgenerate + + sd_crc_7 crc_7 + ( + crcIn, + crcEn, + sdClk, + crcRst, + crcOut + ); + + reg stop; + + reg appendCrc; + reg [5:0] startUppCnt; + + reg q_start_bit; + + //Card initialization DAT contents + initial $readmemh(SD_FILE, FLASHmem); + + initial begin + wide_data[0] <= 00; + wide_data[1] <= 20; + wide_data[2] <= 80; + wide_data[3] <= 01; + wide_data[4] <= 80; + wide_data[5] <= 01; + wide_data[6] <= 80; + wide_data[7] <= 01; + wide_data[8] <= 80; + wide_data[9] <= 01; + wide_data[10] <= 80; + wide_data[11] <= 01; + wide_data[12] <= 80; + wide_data[13] <= 03; + wide_data[14] <= 00; + wide_data[15] <= 00; + wide_data[16] <= 01; + wide_data[17] <= 00; + wide_data[18] <= 00; + wide_data[19] <= 00; + wide_data[20] <= 00; + wide_data[21] <= 00; + wide_data[22] <= 00; + wide_data[23] <= 00; + wide_data[24] <= 00; + wide_data[25] <= 00; + wide_data[26] <= 00; + wide_data[27] <= 00; + wide_data[28] <= 00; + wide_data[29] <= 00; + wide_data[30] <= 00; + wide_data[31] <= 00; + wide_data[32] <= 00; + wide_data[33] <= 00; + wide_data[34] <= 00; + wide_data[35] <= 00; + wide_data[36] <= 00; + wide_data[37] <= 00; + wide_data[38] <= 00; + wide_data[39] <= 00; + wide_data[40] <= 00; + wide_data[41] <= 00; + wide_data[42] <= 00; + wide_data[43] <= 00; + wide_data[44] <= 00; + wide_data[45] <= 00; + wide_data[46] <= 00; + wide_data[47] <= 00; + wide_data[48] <= 00; + wide_data[49] <= 00; + wide_data[50] <= 00; + wide_data[51] <= 00; + wide_data[52] <= 00; + wide_data[53] <= 00; + wide_data[54] <= 00; + wide_data[55] <= 00; + wide_data[56] <= 00; + wide_data[57] <= 00; + wide_data[58] <= 00; + wide_data[59] <= 00; + wide_data[60] <= 00; + wide_data[61] <= 00; + wide_data[62] <= 00; + wide_data[63] <= 00; + end + + + + integer k; + + reg qCmd; + reg [2:0] crcCnt; + + reg add_wrong_cmd_crc; + reg add_wrong_cmd_indx; + reg add_wrong_data_crc; + + initial begin + add_wrong_data_crc<=0; + add_wrong_cmd_indx<=0; + add_wrong_cmd_crc<=0; + stop<=1; + cardIdentificationState<=1; + state<=IDLE; + dataState<=DATA_IDLE; + Busy<=0; + oeCmd<=0; + crcCnt<=0; + CardTransferActive<=0; + qCmd<=1; + oeDat<=0; + cmdOut<=0; + cmdWrite<=0; + InbuffStatus<=0; + datOut<=0; + inCmd<=0; + BusWidth<=1; + responseType=0; + mult_read=0; + mult_write=0; + crcIn<=0; + response_S<=0; + crcEn<=0; + crcRst<=0; + cmdRead<=0; + ValidCmd<=0; + inValidCmd=0; + appendCrc<=0; + RCA<= `RCASTART; + OCR<= `OCRSTART; + CardStatus <= `STATUSSTART; + CID<=`CIDSTART; + CSD<=`CSDSTART; + response_CMD<=0; + outDelayCnt<=0; + crcDat_rst<=1; + crcDat_en<=0; + crcDat_in<=0; + transf_cnt<=0; + ByteAddr<=0; + block_cnt <=0; + wptr<=0; + transf_cnt<=0; + crcDat_rst<=1; + crcDat_en<=0; + crcDat_in<=0; + flash_write_cnt<=0; + startUppCnt<=0; + flash_blockwrite_cnt<=0; + end + + //CARD logic + + always @ (state or cmd or cmdRead or ValidCmd or inValidCmd or cmdWrite or outDelayCnt) + begin : FSM_COMBO + next_state = 0; + case(state) + IDLE: begin + if (!cmd) + next_state = READ_CMD; + else + next_state = IDLE; + end + READ_CMD: begin + if (cmdRead>= 47) + next_state = ANALYZE_CMD; + else + next_state = READ_CMD; + end + ANALYZE_CMD: begin + if ((ValidCmd ) && (outDelayCnt >= `outDelay )) // outDelayCnt >= 4 (NCR) + next_state = SEND_CMD; + else if (inValidCmd) + next_state = IDLE; + else + next_state = ANALYZE_CMD; + end + SEND_CMD: begin + if (cmdWrite>= response_S) + next_state = IDLE; + else + next_state = SEND_CMD; + + end + + + endcase + end + + always @ (dataState or CardStatus or crc_c or flash_write_cnt or dat[0] ) + begin : FSM_COMBODAT + next_datastate = 0; + case(dataState) + DATA_IDLE: begin + if ((CardStatus[12:9]==`RCV) || (mult_write == 1'b1) ) + next_datastate = READ_WAITS; + else if ((CardStatus[12:9]==`DATAS )|| (mult_read == 1'b1) ) + next_datastate = WRITE_DATA; + else + next_datastate = DATA_IDLE; + end + + READ_WAITS: begin + if ( dat[0] == 1'b0 ) + next_datastate = READ_DATA; + else + next_datastate = READ_WAITS; + end + + READ_DATA : begin + if (crc_c==0 ) + next_datastate = WRITE_FLASH; + else begin + if (stop == 1'b0) + next_datastate = READ_DATA; + else + next_datastate = DATA_IDLE; + end + + end + WRITE_FLASH : begin + if (flash_write_cnt>265 ) + next_datastate = DATA_IDLE; + else + next_datastate = WRITE_FLASH; + + end + + WRITE_DATA : begin + if (transf_cnt >= BLOCK_WIDTH) // transf_cnt >= 1044 + next_datastate= DATA_IDLE; + else + begin + if (stop == 1'b0) + next_datastate=WRITE_DATA; + else + next_datastate = DATA_IDLE; + end + end + + endcase + end + + always @ (posedge sdClk ) + begin + + q_start_bit <= dat[0]; + end + + always @ (posedge sdClk ) + begin : FSM_SEQ + state <= next_state; + end + + always @ (posedge sdClk ) + begin : FSM_SEQDAT + dataState <= next_datastate; + end + + always @ (posedge sdClk) begin + if (CardTransferActive) begin + if (InbuffStatus==0) //empty + CardStatus[8]<=1; + else + CardStatus[8]<=0; + end + else + CardStatus[8]<=1; + startUppCnt<=startUppCnt+1; + OCR[31]<=Busy; // THERE IS NO TILDA "OCR[31]<=~BUSY", BUSY is OCR[31] + if (startUppCnt == `TIME_BUSY) // startUppCnt == 63 (counts until ACMD41 valid) + Busy <=1; + end // always @ (posedge sdClk) + + + always @ (posedge sdClk) begin + qCmd<=cmd; + end + + //read data and cmd on rising edge + always @ (posedge sdClk) begin + case(state) + IDLE: begin + mult_write <= 0; + mult_read <=0; + crcIn<=0; + crcEn<=0; + crcRst<=1; + oeCmd<=0; + stop<=0; + cmdRead<=0; + appendCrc<=0; + ValidCmd<=0; + inValidCmd=0; + cmdWrite<=0; + crcCnt<=0; + response_CMD<=0; + response_S<=0; + outDelayCnt<=0; + responseType=0; + end // case: IDLE + + READ_CMD: begin //read cmd + crcEn<=1; + crcRst<=0; + crcIn <= #`tIH qCmd; // tIH 0 + inCmd[47-cmdRead] <= #`tIH qCmd; // tIH 0 + cmdRead <= #1 cmdRead+1; + if (cmdRead >= 40) + crcEn<=0; + + if (cmdRead == 46) begin + oeCmd<=1; + cmdOut<=1; + end + end // case: READ_CMD + + + ANALYZE_CMD: begin//check for valid cmd + //Wrong CRC go idle + if (inCmd[46] == 0) //start + inValidCmd=1; + else if (inCmd[7:1] != crcOut) begin + inValidCmd=1; + $fdisplay(sdModel_file_desc, "**sd_Model Command Packet - CRC Error") ; + $display(sdModel_file_desc, "**sd_Model Command Packet - CRC Error") ; + end + else if (inCmd[0] != 1) begin//stop + inValidCmd=1; + $fdisplay(sdModel_file_desc, "**sd_Model Command Packet - No Stop Bit Error") ; + $display(sdModel_file_desc, "**sd_Model Command Packet - No Stop Bit Error") ; + end + else begin + if(outDelayCnt ==0 ) + CardStatus[3]<=0; // AKE_SEQ_ERROR = no error in sequence of authentication process, until I say otherwise + case(inCmd[45:40]) + 0 : response_S <= 0; // GO_IDLE_STATE + 2 : response_S <= 136; //ALL_SEND_CARD_ID (CID) + 3 : response_S <= 48; //SEND_RELATIVE_CARD_ADDRESS (RCA) + 7 : response_S <= 48; // SELECT_CARD + 8 : response_S <= 48; // SEND_INTERFACE_CONDITION (IC) + 9 : response_S <= 136; // SEND_CARD_SPECIFIC_DATA (CSD) + 14 : response_S <= 0; // reserved (why is this even here?) + 16 : response_S <= 48; // SET_BLOCK_LENGTH (Does nothing for SDHC/SDXC) + 17 : response_S <= 48; // READ_SINGLE_BLOCK of data from card + 18 : response_S <= 48; // READ_MULTIPLE_BLOCKS of data from card + 24 : response_S <= 48; // WRITE_BLOCK of data to card + 25 : response_S <= 48; // WRITE_MULTIPLE_BLOCKS of data to card + 33 : response_S <= 48; // ERASE_WR_BLK_END + 55 : response_S <= 48; // APP_CMD + 41 : response_S <= 48; // CMD41 - SD_SEND_OCR + endcase // case (inCmd[45:40]) + + case(inCmd[45:40]) + 0 : begin // GO_IDLE_STATE + response_CMD <= 0; + cardIdentificationState<=1; + ResetCard; + end + 2 : begin //ALL_SEND_CARD_ID (CID) + if (lastCMD != 41 && outDelayCnt==0) begin + $fdisplay(sdModel_file_desc, "**Error in sequence, ACMD 41 should precede 2 in Start-up state") ; + //$display(sdModel_file_desc, "**Error in sequence, ACMD 41 should precede 2 in Start-up state") ; + CardStatus[3]<=1; // AKE_SEQ_ERROR = ERROR in sequence of authentication process + end + response_CMD[127:8] <= CID; + appendCrc<=0; + CardStatus[12:9] <=2; + end + 3 : begin //SEND_RELATIVE_CARD_ADDRESS (RCA) + if (lastCMD != 2 && outDelayCnt==0 ) begin + $fdisplay(sdModel_file_desc, "**Error in sequence, CMD 2 should precede 3 in Start-up state") ; + //$display(sdModel_file_desc, "**Error in sequence, CMD 2 should precede 3 in Start-up state") ; + CardStatus[3]<=1; // AKE_SEQ_ERROR = ERROR in sequence of authentication process + end + response_CMD[127:112] <= RCA[15:0] ; + response_CMD[111:96] <= CardStatus[15:0] ; + appendCrc<=1; + CardStatus[12:9] <=3; + cardIdentificationState<=0; + end + 6 : begin + if (lastCMD == 55 && outDelayCnt==0) begin //ACMD6 - SET_BUS_WIDTH + if (inCmd[9:8] == 2'b10) begin + BusWidth <=4; + $display(sdModel_file_desc, "**BUS WIDTH 4 ") ; + end + else + BusWidth <=1; + + response_S<=48; + response_CMD[127:96] <= CardStatus; + end + else if (outDelayCnt==0) begin //CMD6 - SWITCH_CARD_FUNCTION (Clock speed) + if (CardStatus[12:9] == `TRAN) begin //If card is in transfer state + CardStatus[12:9] <=`DATAS;//Put card in data state + response_CMD[127:96] <= CardStatus ; + response_S<=48; + BLOCK_WIDTH <= 11'd148; + $fdisplay(sdModel_file_desc, "**Error Invalid CMD, %h",inCmd[45:40]); + $display(sdModel_file_desc, "**Error Invalid CMD, %h",inCmd[45:40]); + end + else begin + response_S <= 0; + response_CMD[127:96] <= 0; + $fdisplay(sdModel_file_desc, "**Error Invalid CMD, %h, card not in transfer state",inCmd[45:40]); + $display(sdModel_file_desc, "**Error Invalid CMD, %h, card not in transfer state",inCmd[45:40]); + end // else: !if(CardStatus[12:9] == `TRAN) + end // if (outDelayCnt==0) + end // case: 6 + + 7: begin // SELECT_CARD + if (outDelayCnt==0) begin + if (inCmd[39:24]== RCA[15:0]) begin + CardTransferActive <= 1; + response_CMD[127:96] <= CardStatus ; + CardStatus[12:9] <=`TRAN; + end + else begin + CardTransferActive <= 0; + response_CMD[127:96] <= CardStatus ; + CardStatus[12:9] <=3; + end + end + end // case: 7 + + + 8 : begin // SEND_INTERFACE_CONDITION (IC) + response_CMD[127:96] <= {20'h00000 , inCmd[19:8]}; //not supported by V1.0 card + response_S<=48; + + $fdisplay(sdModel_file_desc, "**Warning Unofficially Supported CMD, %h",inCmd[45:40]); + $display(sdModel_file_desc, "**Warning Unofficially Supported CMD, %h",inCmd[45:40]); + end + + 9 : begin // SEND_CARD_SPECIFIC_DATA (CSD) + if (lastCMD != 41 && outDelayCnt==0) begin + $fdisplay(sdModel_file_desc, "**Error in sequence, ACMD 41 should precede 9 in Start-up state") ; + //$display(sdModel_file_desc, "**Error in sequence, ACMD 41 should precede 9 in Start-up state") ; + CardStatus[3]<=1; // AKE_SEQ_ERROR = ERROR in sequence of authentication process + end + response_CMD[127:8] <= CSD; + appendCrc<=0; + CardStatus[12:9] <=2; + end + + 12: begin // STOP_TRANSMISSION + response_CMD[127:96] <= CardStatus ; + stop<=1; + mult_write <= 0; + mult_read <=0; + CardStatus[12:9] <= `TRAN; + end + + 16 : begin // SET_BLOCK_LENGTH (Does nothing for SDHC/SDXC) + response_CMD[127:96] <= CardStatus ; + end + + 17 : begin // READ_SINGLE_BLOCK of data from card + if (outDelayCnt==0) begin + if (CardStatus[12:9] == `TRAN) begin //If card is in transfer state + CardStatus[12:9] <=`DATAS;//Put card in data state + response_CMD[127:96] <= CardStatus ; + BLOCK_WIDTH <= 11'd1044; + + ByteAddr = inCmd[39:8] << 9; + if (ByteAddr%512 !=0) + $display("**Block Misalign Error"); + end + else begin + response_S <= 0; + response_CMD[127:96] <= 0; + end + end + end + + 18 : begin // READ_MULTIPLE_BLOCKS of data from card + if (outDelayCnt==0) begin + if (CardStatus[12:9] == `TRAN) begin //If card is in transfer state + CardStatus[12:9] <=`DATAS;//Put card in data state + response_CMD[127:96] <= CardStatus ; + mult_read <= 1; + ByteAddr = inCmd[39:8] << 9; + if (ByteAddr%512 !=0) + $display("**Block Misalign Error"); + end + else begin + response_S <= 0; + response_CMD[127:96] <= 0; + end + end + end + + 24 : begin // WRITE_BLOCK of data to card + if (outDelayCnt==0) begin + if (CardStatus[12:9] == `TRAN) begin //If card is in transfer state + if (CardStatus[8]) begin //If Free write buffer + CardStatus[12:9] <=`RCV;//Put card in Rcv state + response_CMD[127:96] <= CardStatus ; + ByteAddr = inCmd[39:8] << 9; + if (ByteAddr%512 !=0) + $display("**Block Misalign Error"); + end + else begin + response_CMD[127:96] <= CardStatus; + $fdisplay(sdModel_file_desc, "**Error Try to blockwrite when No Free Writebuffer") ; + $display("**Error Try to blockwrite when No Free Writebuffer") ; + end + end + else begin + response_S <= 0; + response_CMD[127:96] <= 0; + end + end + end // case: 24 + + 25 : begin // WRITE_MULTIPLE_BLOCKS of data to card + if (outDelayCnt==0) begin + if (CardStatus[12:9] == `TRAN) begin //If card is in transfer state + if (CardStatus[8]) begin //If Free write buffer + CardStatus[12:9] <=`RCV;//Put card in Rcv state + response_CMD[127:96] <= CardStatus ; + ByteAddr = inCmd[39:8] << 9; + mult_write <= 1; + if (ByteAddr%512 !=0) + $display("**Block Misalign Error"); + end + else begin + response_CMD[127:96] <= CardStatus; + $fdisplay(sdModel_file_desc, "**Error Try to blockwrite when No Free Writebuffer") ; + $display("**Error Try to blockwrite when No Free Writebuffer") ; + end // else: !if(CardStatus[8]) + end // if (CardStatus[12:9] == `TRAN) + else begin + response_S <= 0; + response_CMD[127:96] <= 0; + end // else: !if(CardStatus[12:9] == `TRAN) + end // if (outDelayCnt==0) + end // case: 25 + + 33 : response_CMD[127:96] <= 48; // ERASE_WR_BLK_END + + 55 : + begin // APP_CMD + response_CMD[127:96] <= CardStatus ; + CardStatus[5] <=1; //Next CMD is AP specific CMD + appendCrc<=1; + end + + 41 : // CMD41 - SD_SEND_OCR + begin + if (cardIdentificationState) begin + if (lastCMD != 55 && outDelayCnt==0) begin // CMD41 - Reserved/Invalid + $fdisplay(sdModel_file_desc, "**Error in sequence, CMD 55 should precede 41 in Start-up state") ; + $display( "**Error in sequence, CMD 55 should precede 41 in Start-up state") ; + CardStatus[3]<=1; // AKE_SEQ_ERROR = ERROR in sequence of authentication process + end + else begin // CMD41 - SD_SEND_OCR + responseType=3; + response_CMD[127:96] <= OCR; + appendCrc<=0; + CardStatus[5] <=0; // not expecting next command to be ACMD + if (Busy==1) + CardStatus[12:9] <=1; // READY + end // else: !if(lastCMD != 55 && outDelayCnt==0) + end // if (cardIdentificationState) + end // case: 41 + endcase // case (inCmd[45:40]) + + ValidCmd<=1; + crcIn<=0; + + outDelayCnt<=outDelayCnt+1; + if (outDelayCnt==`outDelay) // if (outDelayCnt == 4) + crcRst<=1; + + oeCmd<=1; + cmdOut<=1; + response_CMD[135:134] <=0; // Start bit = 0, tx bit = 0 (response from card) + + // for those who aren't keeping track, we are still in 'else: !if(inCmd[0] != 1)' + if (responseType != 3) + if (!add_wrong_cmd_indx) + response_CMD[133:128] <=inCmd[45:40]; + else + response_CMD[133:128] <=0; + + if (responseType == 3) + response_CMD[133:128] <=6'b111111; + + lastCMD <=inCmd[45:40]; + end // else: !if(inCmd[0] != 1) + end // case: ANALYZE_CMD + endcase // case (state) + end // always @ (posedge sdClk) + + always @ ( negedge sdClk) begin + case(state) + + SEND_CMD: begin + crcRst<=0; + crcEn<=1; + cmdWrite<=cmdWrite+1; + if (response_S!=0) + cmdOut<=0; + else + cmdOut<=1; + + if ((cmdWrite>0) && (cmdWrite < response_S-8)) begin + cmdOut<=response_CMD[135-cmdWrite]; + crcIn<=response_CMD[134-cmdWrite]; + if (cmdWrite >= response_S-9) + crcEn<=0; + end + else if (cmdWrite!=0) begin + crcEn<=0; + if (add_wrong_cmd_crc) begin + cmdOut<=0; + crcCnt<=crcCnt+1; + end + else begin + cmdOut<=crcOut[6-crcCnt]; + crcCnt<=crcCnt+1; + if (responseType == 3) + cmdOut<=1; + end + end // if (cmdWrite!=0) + if (cmdWrite == response_S-1) + cmdOut<=1; + end // case: SEND_CMD + endcase // case (state) + end // always @ ( negedge sdClk) + + integer outdly_cnt; + + always @ (posedge sdClk) begin // Read DATA from host on positive clock edge + + case (dataState) + DATA_IDLE: begin + + crcDat_rst<=1; + crcDat_en<=0; + crcDat_in<=0; + + end + + READ_WAITS: begin + oeDat<=0; + crcDat_rst<=0; + crcDat_en<=1; + crcDat_in<=0; + crc_c<=15;// + crc_ok<=1; + end + + READ_DATA: begin + + InbuffStatus<=1; + if (transf_cnt<`BIT_BLOCK_REC) begin + if (wptr) + Inbuff[block_cnt][3:0] <= dat; + else + Inbuff[block_cnt][7:4] <= dat; + + if (!add_wrong_data_crc) + crcDat_in<=dat; + else + crcDat_in<=4'b1010; + + crc_ok<=1; + transf_cnt<=transf_cnt+1; + if (wptr) + block_cnt<=block_cnt+1; + wptr<=~wptr; + end // if (transf_cnt<`BIT_BLOCK_REC) + + else if ( transf_cnt <= (`BIT_BLOCK_REC +`BIT_CRC_CYCLE-1)) begin + transf_cnt<=transf_cnt+1; + crcDat_en<=0; + last_din <=dat; + + if (transf_cnt> `BIT_BLOCK_REC) begin + crc_c<=crc_c-1; + + if (crcDat_out[0][crc_c] != last_din[0]) + crc_ok<=0; + if (crcDat_out[1][crc_c] != last_din[1]) + crc_ok<=0; + if (crcDat_out[2][crc_c] != last_din[2]) + crc_ok<=0; + if (crcDat_out[3][crc_c] != last_din[3]) + crc_ok<=0; + end // if (transf_cnt> `BIT_BLOCK_REC) + end // if ( transf_cnt <= (`BIT_BLOCK_REC +`BIT_CRC_CYCLE-1)) + end // case: READ_DATA + + WRITE_FLASH: begin + oeDat<=1; + block_cnt <=0; + wptr<=0; + transf_cnt<=0; + crcDat_rst<=1; + crcDat_en<=0; + crcDat_in<=0; + end + + endcase // case (dataState) + + end // always @ (posedge sdClk) + + reg data_send_index; + integer write_out_index; + always @ (negedge sdClk) begin // Write DATA to Host on negative clock edge + + case (dataState) + DATA_IDLE: begin + write_out_index<=0; + transf_cnt<=0; + data_send_index<=0; + outdly_cnt<=0; + flash_write_cnt<=0; + end + + WRITE_DATA: begin + oeDat<=1; + outdly_cnt<=outdly_cnt+1; + datOut <= 4'b1111; // listen... until I tell you otherwise, DAT bus is all high (thanks Ross) + + + if ( outdly_cnt > `DLY_TO_OUTP) begin // if (outdly_cnt > 47) NAC cycles elapsed + transf_cnt <= transf_cnt+1; // start counting bits transferred + crcDat_en<=1; // Enable CRC16 + crcDat_rst<=0; // Stop reset of CRC16 + oeDat<=1; // Enable output + end + + else begin // NAC cycles have not elapsed + crcDat_en<=0; // Disable CRC16 generation + crcDat_rst<=1; // Reset CRC16 generators + oeDat<=0; // Do NOT enable output (I REALLY DO AGREE WITH THIS!) + crc_c<=16; // point to bit 16 of CRC16 + end // else: !if( outdly_cnt > `DLY_TO_OUTP) + + if (transf_cnt==1) begin // first nibble + if (BLOCK_WIDTH == 11'd1044) begin + last_din <= FLASHmem[ByteAddr+(write_out_index)][7:4]; // LOAD register with upper nibble + crcDat_in<= FLASHmem[ByteAddr+(write_out_index)][7:4]; // LOAD CRC16 with upper nibble + end + else begin + // code for wide width data + last_din <= wide_data[write_out_index][7:4]; + crcDat_in <= wide_data[write_out_index][7:4]; + end + datOut<=0; // Send nothing yet + data_send_index<=1; // Next nibble is lower nibble + end + + else if ( (transf_cnt>=2) && (transf_cnt<=BLOCK_WIDTH -`CRC_OFF )) begin // if (2 <= transf_cnt <= 1025) + data_send_index<=~data_send_index; //toggle + if (!data_send_index) begin //upper nibble + if (BLOCK_WIDTH == 11'd1044) begin + last_din <= FLASHmem[ByteAddr+(write_out_index)][7:4]; // LOAD register with upper nibble + crcDat_in<= FLASHmem[ByteAddr+(write_out_index)][7:4]; // LOAD CRC16 with upper nibble + end + else begin + // code for wide width data + last_din <= wide_data[write_out_index][7:4]; + crcDat_in <= wide_data[write_out_index][7:4]; + end + end // if (!data_send_index) + else begin //lower nibble + if (BLOCK_WIDTH == 11'd1044) begin + last_din<=FLASHmem[ByteAddr+(write_out_index)][3:0]; + end + else begin + last_din <= wide_data[write_out_index][3:0]; + end + if (!add_wrong_data_crc) + if (BLOCK_WIDTH == 11'd1044) begin + crcDat_in<= FLASHmem[ByteAddr+(write_out_index)][3:0]; + end + else begin + crcDat_in <= wide_data[write_out_index][3:0]; + end + else // SNAFU + crcDat_in<=4'b1010; + write_out_index<=write_out_index+1; // Having sent the lower nibble, increment the byte counter + + end // else: !if(!data_send_index) + + datOut<= last_din; // output content of register + + + if ( transf_cnt >=BLOCK_WIDTH-`CRC_OFF ) begin // if (trans_cnt >= 1025) + crcDat_en<=0; // Disable CRC16 Generators + end + end // if ( (transf_cnt>=2) && (transf_cnt<=`BIT_BLOCK-`CRC_OFF )) + + else if (transf_cnt>BLOCK_WIDTH-`CRC_OFF & crc_c!=0) begin // if ((transf_cnt > 1025) and (crc_c /= 0)) + datOut<= last_din; // if sent all data bitsbut not crc16 bits yet + crcDat_en<=0; // Disable CRC16 generators + crc_c<=crc_c-1; // point to next bit of CRC16 to begin transmission of CRC16 + if (crc_c<= 16) begin // begin sending CRC16 (16 downto 1) + datOut[0]<=crcDat_out[0][crc_c-1]; + datOut[1]<=crcDat_out[1][crc_c-1]; + datOut[2]<=crcDat_out[2][crc_c-1]; + datOut[3]<=crcDat_out[3][crc_c-1]; + end + + end // if (transf_cnt>`BIT_BLOCK-`CRC_OFF & crc_c!=0) + else if (transf_cnt==BLOCK_WIDTH-2) begin // if (transf_cnt = 1042) Last CRC16 bit is 1041 + datOut<=4'b1111; // send end bits + end + else if ((transf_cnt !=0) && (crc_c == 0 ))begin // if sent data bits and crc_c points past last bit of CRC + oeDat<=0; // disable output on DAT bus + CardStatus[12:9] <= `TRAN; // put card in transfer state + end + + end // case: WRITE_DATA + + + WRITE_FLASH: begin + flash_write_cnt<=flash_write_cnt+1; + CardStatus[12:9] <= `PRG; + datOut[0]<=0; + datOut[1]<=1; + datOut[2]<=1; + datOut[3]<=1; + if (flash_write_cnt == 0) + datOut<=1; + else if(flash_write_cnt == 1) + datOut[0]<=1; + else if(flash_write_cnt == 2) + datOut[0]<=0; + + else if ((flash_write_cnt > 2) && (flash_write_cnt < 7)) begin + if (crc_ok) + datOut[0] <=okcrctoken[6-flash_write_cnt]; + else + datOut[0] <= invalidcrctoken[6-flash_write_cnt]; + + end + else if ((flash_write_cnt >= 7) && (flash_write_cnt < 264)) begin + datOut[0]<=0; + + flash_blockwrite_cnt<=flash_blockwrite_cnt+2; + FLASHmem[ByteAddr+(flash_blockwrite_cnt)]=Inbuff[flash_blockwrite_cnt]; + FLASHmem[ByteAddr+(flash_blockwrite_cnt+1)]=Inbuff[flash_blockwrite_cnt+1]; + end + + else begin + datOut<=1; + InbuffStatus<=0; + CardStatus[12:9] <= `TRAN; + end // else: !if((flash_write_cnt >= 7) && (flash_write_cnt < 264)) + end // case: WRITE_FLASH + endcase // case (dataState) + end // always @ (negedge sdClk) + + integer sdModel_file_desc; + + initial + begin + sdModel_file_desc = $fopen("sd_model.log"); + if (sdModel_file_desc < 2) + begin + $display("*E Could not open/create testbench log file in /log/ directory!"); + $finish; + end + end + + task ResetCard; // MAC registers + begin + add_wrong_data_crc<=0; + add_wrong_cmd_indx<=0; + add_wrong_cmd_crc<=0; + cardIdentificationState<=1; + state<=IDLE; + dataState<=DATA_IDLE; + Busy<=0; + oeCmd<=0; + crcCnt<=0; + CardTransferActive<=0; + qCmd<=1; + oeDat<=0; + cmdOut<=0; + cmdWrite<=0; + startUppCnt<=0; + InbuffStatus<=0; + datOut<=0; + inCmd<=0; + BusWidth<=1; + responseType=0; + crcIn<=0; + response_S<=0; + crcEn<=0; + crcRst<=0; + cmdRead<=0; + ValidCmd<=0; + inValidCmd=0; + appendCrc<=0; + RCA<= `RCASTART; + OCR<= `OCRSTART; + CardStatus <= `STATUSSTART; + CID<=`CIDSTART; + CSD<=`CSDSTART; + response_CMD<=0; + outDelayCnt<=0; + crcDat_rst<=1; + crcDat_en<=0; + crcDat_in<=0; + transf_cnt<=0; + ByteAddr<=0; + block_cnt <=0; + wptr<=0; + transf_cnt<=0; + crcDat_rst<=1; + crcDat_en<=0; + crcDat_in<=0; + flash_write_cnt<=0; + flash_blockwrite_cnt<=0; + end + endtask + +endmodule // sdModel diff --git a/wally-pipelined/src/sdc/tb/sd_crc_16.sv b/wally-pipelined/src/sdc/tb/sd_crc_16.sv new file mode 100644 index 00000000..c7a02bf3 --- /dev/null +++ b/wally-pipelined/src/sdc/tb/sd_crc_16.sv @@ -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 diff --git a/wally-pipelined/src/sdc/tb/sd_crc_7.sv b/wally-pipelined/src/sdc/tb/sd_crc_7.sv new file mode 100644 index 00000000..352e6af6 --- /dev/null +++ b/wally-pipelined/src/sdc/tb/sd_crc_7.sv @@ -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 + diff --git a/wally-pipelined/src/sdc/tb/sd_defines.h b/wally-pipelined/src/sdc/tb/sd_defines.h new file mode 100644 index 00000000..9421fa5c --- /dev/null +++ b/wally-pipelined/src/sdc/tb/sd_defines.h @@ -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 +//--------------------------- + + + + + + + + + diff --git a/wally-pipelined/src/sdc/tb/sd_top_tb.sv b/wally-pipelined/src/sdc/tb/sd_top_tb.sv new file mode 100644 index 00000000..53ec0296 --- /dev/null +++ b/wally-pipelined/src/sdc/tb/sd_top_tb.sv @@ -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 diff --git a/wally-pipelined/src/sdc/tb/wave.do b/wally-pipelined/src/sdc/tb/wave.do new file mode 100644 index 00000000..d8615882 --- /dev/null +++ b/wally-pipelined/src/sdc/tb/wave.do @@ -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} diff --git a/wally-pipelined/src/sdc/up_down_counter.sv b/wally-pipelined/src/sdc/up_down_counter.sv new file mode 100644 index 00000000..13c5676c --- /dev/null +++ b/wally-pipelined/src/sdc/up_down_counter.sv @@ -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 + +