mirror of
https://github.com/openhwgroup/cvw
synced 2025-02-02 09:45:18 +00:00
Removed SDC from repo due to copy right issue.
Modified fpga build flow to reference it outside the repo.
This commit is contained in:
parent
b1f3bd566c
commit
5b740fbf60
2
.gitignore
vendored
2
.gitignore
vendored
@ -126,3 +126,5 @@ tests/custom/*/*/*.map
|
||||
tests/custom/*/*/*.memfile
|
||||
tests/custom/crt0/*.a
|
||||
/pipelined/regression/sd_model.log
|
||||
fpga/src/sdc/*
|
||||
fpga/src/sdc.tar.gz
|
||||
|
@ -1,18 +1,19 @@
|
||||
dst := IP
|
||||
sdc_src := ~/repos/sdc.tar.gz
|
||||
# vcu118
|
||||
export XILINX_PART := xcvu9p-flga2104-2L-e
|
||||
export XILINX_BOARD := xilinx.com:vcu118:part0:2.4
|
||||
export board := vcu118
|
||||
#export XILINX_PART := xcvu9p-flga2104-2L-e
|
||||
#export XILINX_BOARD := xilinx.com:vcu118:part0:2.4
|
||||
#export board := vcu118
|
||||
|
||||
# vcu108
|
||||
#export XILINX_PART := xcvu095-ffva2104-2-e
|
||||
#export XILINX_BOARD := xilinx.com:vcu108:part0:1.2
|
||||
#export board := vcu108
|
||||
export XILINX_PART := xcvu095-ffva2104-2-e
|
||||
export XILINX_BOARD := xilinx.com:vcu108:part0:1.2
|
||||
export board := vcu108
|
||||
|
||||
|
||||
all: FPGA
|
||||
|
||||
FPGA: IP
|
||||
FPGA: IP SDC
|
||||
vivado -mode tcl -source wally.tcl 2>&1 | tee wally.log
|
||||
|
||||
IP: $(dst)/xlnx_proc_sys_reset.log \
|
||||
@ -20,6 +21,10 @@ IP: $(dst)/xlnx_proc_sys_reset.log \
|
||||
$(dst)/xlnx_axi_clock_converter.log \
|
||||
$(dst)/xlnx_ahblite_axi_bridge.log
|
||||
|
||||
SDC:
|
||||
cp $(sdc_src) ../src/
|
||||
tar xzf ../src/sdc.tar.gz -C ../src
|
||||
|
||||
$(dst)/%.log: %.tcl
|
||||
mkdir -p IP
|
||||
cd IP;\
|
||||
|
@ -17,6 +17,7 @@ read_ip IP/xlnx_ddr4.srcs/sources_1/ip/xlnx_ddr4/xlnx_ddr4.xci
|
||||
|
||||
read_verilog -sv [glob -type f ../../pipelined/src/*/*.sv ../../pipelined/src/*/*/*.sv]
|
||||
read_verilog {../src/fpgaTop.v}
|
||||
read_verilog -sv [glob -type f ../src/sdc/*.sv]
|
||||
|
||||
set_property include_dirs {../../pipelined/config/fpga ../../pipelined/config/shared} [current_fileset]
|
||||
|
||||
|
@ -1,362 +0,0 @@
|
||||
///////////////////////////////////////////
|
||||
// SDC.sv
|
||||
//
|
||||
// Written: Ross Thompson September 22, 2021
|
||||
// Modified:
|
||||
//
|
||||
// Purpose: SDC interface to AHBLite BUS.
|
||||
//
|
||||
// A component of the CORE-V-WALLY configurable RISC-V project.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
||||
//
|
||||
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
|
||||
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
|
||||
// may obtain a copy of the License at
|
||||
//
|
||||
// https://solderpad.org/licenses/SHL-2.1/
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, any work distributed under the
|
||||
// License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
`include "wally-config.vh"
|
||||
|
||||
`define SDCCLKDIV -8'd3
|
||||
|
||||
module SDC (
|
||||
input logic HCLK,
|
||||
input logic HRESETn,
|
||||
input logic HSELSDC,
|
||||
input logic [4:0] HADDR,
|
||||
input logic HWRITE,
|
||||
input logic HREADY,
|
||||
input logic [1:0] HTRANS,
|
||||
input logic [`XLEN-1:0] HWDATA,
|
||||
output logic [`XLEN-1:0] HREADSDC,
|
||||
output logic HRESPSDC,
|
||||
output logic HREADYSDC,
|
||||
|
||||
//sd card interface
|
||||
// place the tristate drivers at the top. this level
|
||||
// will use dedicated 1 direction ports.
|
||||
output logic SDCCmdOut,
|
||||
input logic SDCCmdIn,
|
||||
output logic SDCCmdOE,
|
||||
input logic [3:0] SDCDatIn,
|
||||
output logic SDCCLK,
|
||||
// interrupt to PLIC
|
||||
output logic SDCIntM
|
||||
);
|
||||
|
||||
logic InitTrans;
|
||||
logic RegRead;
|
||||
logic RegWrite;
|
||||
logic [4:0] HADDRDelay;
|
||||
|
||||
|
||||
// Register outputs
|
||||
logic signed [7:0] CLKDiv;
|
||||
logic [2:0] Command;
|
||||
logic [63:9] Address;
|
||||
|
||||
|
||||
logic SDCDone;
|
||||
|
||||
logic [2:0] ErrorCode;
|
||||
logic InvalidCommand;
|
||||
logic SDCBusy;
|
||||
|
||||
logic StartCLKDivUpdate;
|
||||
logic CLKDivUpdateEn;
|
||||
logic SDCCLKEN;
|
||||
logic CLKGate;
|
||||
logic SDCCLKIn;
|
||||
|
||||
|
||||
logic SDCDataValid;
|
||||
logic [`XLEN-1:0] SDCReadData;
|
||||
logic [`XLEN-1:0] SDCReadDataPreNibbleSwap;
|
||||
logic [`XLEN-1:0] SDCWriteData;
|
||||
logic FatalError;
|
||||
|
||||
logic [4095:0] ReadData512Byte;
|
||||
logic [`XLEN-1:0] ReadData512ByteWords [4096/`XLEN-1:0] ;
|
||||
logic SDCInitialized;
|
||||
logic SDCRestarting;
|
||||
logic SDCLast;
|
||||
|
||||
logic [$clog2(4096/`XLEN)-1:0] WordCount;
|
||||
logic WordCountRst;
|
||||
logic [5:0] Status;
|
||||
logic CommandCompleted;
|
||||
logic ReadDone;
|
||||
|
||||
|
||||
|
||||
genvar index;
|
||||
|
||||
assign HRESPSDC = 1'b0;
|
||||
|
||||
// registers
|
||||
//| Offset | Name | Size | Purpose |
|
||||
//|--------+---------+--------+------------------------------------------------|
|
||||
//| 0x0 | CLKDiv | 4 | Divide HCLK to produce SDCLK |
|
||||
//| 0x4 | Status | 4 | Provide status to software |
|
||||
//| 0x8 | Control | 4 | Send commands to SDC |
|
||||
//| 0xC | Size | 4 | Size of data command (only 512 byte supported) |
|
||||
//| 0x10 | address | 8 | address of operation |
|
||||
//| 0x18 | data | XLEN/8 | Data Bus interface |
|
||||
|
||||
// Status contains
|
||||
// Status[0] initialized
|
||||
// Status[1] Busy on read
|
||||
// Status[2] invalid command
|
||||
// Status[5:3] error code
|
||||
|
||||
// control contains 3 bit command
|
||||
// control[2:0]
|
||||
// 000 nop op
|
||||
// xx1 initialize
|
||||
// 010 Write no implemented
|
||||
// 100 Read
|
||||
// 110 Atomic read/write not implemented
|
||||
|
||||
// size is fixed to 512. Read only
|
||||
|
||||
|
||||
// Currently using a mailbox style interface. Data is passed through the Data register (0x10)
|
||||
// The card will support 3 operations
|
||||
// 1. initialize
|
||||
// 2. read
|
||||
// 3. write
|
||||
// all read and write operations will occur on 512 bytes (4096 bits) of data
|
||||
// starting at the 512 byte aligned address in the address register This register
|
||||
// is the byte address.
|
||||
|
||||
// currently does not support writes
|
||||
|
||||
assign InitTrans = HREADY & HSELSDC & HTRANS[1];
|
||||
//assign RegRead = InitTrans & ~HWRITE;
|
||||
// register resolve combo loop
|
||||
flopr #(1) RegReadReg(HCLK, ~HRESETn, InitTrans & ~HWRITE, RegRead);
|
||||
// AHBLite Spec has write data 1 cycle after write command
|
||||
flopr #(1) RegWriteReg(HCLK, ~HRESETn, InitTrans & HWRITE, RegWrite);
|
||||
|
||||
flopenr #(5) HADDRReg(HCLK, ~HRESETn, InitTrans, HADDR, HADDRDelay);
|
||||
|
||||
assign StartCLKDivUpdate = HADDRDelay == '0 & RegWrite;
|
||||
|
||||
flopenl #(8) CLKDivReg(HCLK, ~HRESETn, CLKDivUpdateEn, HWDATA[7:0], `SDCCLKDIV, CLKDiv);
|
||||
|
||||
// Control reg
|
||||
flopenl #(3) CommandReg(HCLK, ~HRESETn, (HADDRDelay == 'h8 & RegWrite) | (CommandCompleted),
|
||||
CommandCompleted ? '0 : HWDATA[2:0], '0, Command);
|
||||
|
||||
if (`XLEN == 64) begin
|
||||
flopenr #(64-9) AddressReg(HCLK, ~HRESETn, (HADDRDelay == 'h10 & RegWrite),
|
||||
HWDATA[`XLEN-1:9], Address);
|
||||
end else begin
|
||||
flopenr #(32-9) AddressLowReg(HCLK, ~HRESETn, (HADDRDelay == 'h10 & RegWrite),
|
||||
HWDATA[`XLEN-1:9], Address[31:9]);
|
||||
flopenr #(32) AddressHighReg(HCLK, ~HRESETn, (HADDRDelay == 'h14 & RegWrite),
|
||||
HWDATA, Address[63:32]);
|
||||
end
|
||||
|
||||
flopen #(`XLEN) DataReg(HCLK, (HADDRDelay == 'h18 & RegWrite),
|
||||
HWDATA, SDCWriteData);
|
||||
|
||||
assign InvalidCommand = (Command[2] | Command[1]) & Command[0];
|
||||
|
||||
assign Status = {ErrorCode, InvalidCommand, SDCBusy, SDCInitialized};
|
||||
|
||||
if(`XLEN == 64) begin
|
||||
always_comb
|
||||
case(HADDRDelay[4:0])
|
||||
'h0: HREADSDC = {24'b0, CLKDiv, 26'b0, Status};
|
||||
'h4: HREADSDC = {26'b0, Status, 29'b0, Command};
|
||||
'h8: HREADSDC = {29'b0, Command, 32'h200};
|
||||
'hC: HREADSDC = {32'h200, Address[31:9], 9'b0};
|
||||
'h10: HREADSDC = {Address, 9'b0};
|
||||
'h18: HREADSDC = SDCReadData;
|
||||
default: HREADSDC = {24'b0, CLKDiv, 26'b0, Status};
|
||||
endcase // case (HADDRDelay[4:0])
|
||||
end else begin
|
||||
always_comb
|
||||
case(HADDRDelay[4:0])
|
||||
'h0: HREADSDC = {24'b0, CLKDiv};
|
||||
'h4: HREADSDC = {26'b0, Status};
|
||||
'h8: HREADSDC = {29'b0, Command};
|
||||
'hC: HREADSDC = 'h200;
|
||||
'h10: HREADSDC = {Address[31:9], 9'b0};
|
||||
'h14: HREADSDC = Address[63:32];
|
||||
'h18: HREADSDC = SDCReadData[31:0];
|
||||
default: HREADSDC = {24'b0, CLKDiv};
|
||||
endcase
|
||||
end
|
||||
|
||||
|
||||
for(index = 0; index < 4096/`XLEN; index++) begin
|
||||
assign ReadData512ByteWords[index] = ReadData512Byte[(index+1)*`XLEN-1:index*`XLEN];
|
||||
end
|
||||
|
||||
assign SDCReadDataPreNibbleSwap = ReadData512ByteWords[WordCount];
|
||||
if(`XLEN == 64) begin
|
||||
assign SDCReadData = {SDCReadDataPreNibbleSwap[59:56], SDCReadDataPreNibbleSwap[63:60],
|
||||
SDCReadDataPreNibbleSwap[51:48], SDCReadDataPreNibbleSwap[55:52],
|
||||
SDCReadDataPreNibbleSwap[43:40], SDCReadDataPreNibbleSwap[47:44],
|
||||
SDCReadDataPreNibbleSwap[35:32], SDCReadDataPreNibbleSwap[39:36],
|
||||
SDCReadDataPreNibbleSwap[27:24], SDCReadDataPreNibbleSwap[31:28],
|
||||
SDCReadDataPreNibbleSwap[19:16], SDCReadDataPreNibbleSwap[23:20],
|
||||
SDCReadDataPreNibbleSwap[11:8], SDCReadDataPreNibbleSwap[15:12],
|
||||
SDCReadDataPreNibbleSwap[3:0], SDCReadDataPreNibbleSwap[7:4]};
|
||||
end else begin
|
||||
assign SDCReadData = {SDCReadDataPreNibbleSwap[27:24], SDCReadDataPreNibbleSwap[31:28],
|
||||
SDCReadDataPreNibbleSwap[19:16], SDCReadDataPreNibbleSwap[23:20],
|
||||
SDCReadDataPreNibbleSwap[11:8], SDCReadDataPreNibbleSwap[15:12],
|
||||
SDCReadDataPreNibbleSwap[3:0], SDCReadDataPreNibbleSwap[7:4]};
|
||||
end
|
||||
|
||||
flopenr #($clog2(4096/`XLEN)) WordCountReg
|
||||
(.clk(HCLK),
|
||||
.reset(~HRESETn | WordCountRst),
|
||||
.en(HADDRDelay[4:0] == 'h18 & ReadDone),
|
||||
.d(WordCount + 1'b1),
|
||||
.q(WordCount));
|
||||
|
||||
|
||||
|
||||
typedef enum {STATE_READY,
|
||||
|
||||
// clock update states
|
||||
STATE_CLK_DIV1,
|
||||
STATE_CLK_DIV2,
|
||||
STATE_CLK_DIV3,
|
||||
STATE_CLK_DIV4,
|
||||
|
||||
// restart SDC
|
||||
STATE_RESTART,
|
||||
|
||||
// SDC operation
|
||||
STATE_PROCESS_CMD,
|
||||
|
||||
STATE_READ
|
||||
} statetype;
|
||||
|
||||
|
||||
statetype CurrState, NextState;
|
||||
|
||||
always_ff @(posedge HCLK, negedge HRESETn)
|
||||
if (~HRESETn) CurrState <= STATE_READY;
|
||||
else CurrState <= NextState;
|
||||
|
||||
always_comb begin
|
||||
CLKDivUpdateEn = 1'b0;
|
||||
HREADYSDC = 1'b0;
|
||||
SDCCLKEN = 1'b1;
|
||||
WordCountRst = 1'b0;
|
||||
SDCBusy = 1'b0;
|
||||
CommandCompleted = 1'b0;
|
||||
ReadDone = 1'b0;
|
||||
|
||||
case (CurrState)
|
||||
STATE_READY : begin
|
||||
if (StartCLKDivUpdate)begin
|
||||
NextState = STATE_CLK_DIV1;
|
||||
HREADYSDC = 1'b0;
|
||||
end else if (Command[2] | Command[1]) begin
|
||||
NextState = STATE_PROCESS_CMD;
|
||||
HREADYSDC = 1'b0;
|
||||
end else if(HADDRDelay[4:0] == 'h18 & RegRead) begin
|
||||
NextState = STATE_READ;
|
||||
HREADYSDC = 1'b0;
|
||||
end else begin
|
||||
NextState = STATE_READY;
|
||||
HREADYSDC = 1'b1;
|
||||
end
|
||||
end
|
||||
STATE_CLK_DIV1: begin
|
||||
NextState = STATE_CLK_DIV2;
|
||||
SDCCLKEN = 1'b0;
|
||||
end
|
||||
STATE_CLK_DIV2: begin
|
||||
NextState = STATE_CLK_DIV3;
|
||||
CLKDivUpdateEn = 1'b1;
|
||||
SDCCLKEN = 1'b0;
|
||||
end
|
||||
STATE_CLK_DIV3: begin
|
||||
NextState = STATE_CLK_DIV4;
|
||||
SDCCLKEN = 1'b0;
|
||||
end
|
||||
STATE_CLK_DIV4: begin
|
||||
NextState = STATE_READY;
|
||||
end
|
||||
STATE_PROCESS_CMD: begin
|
||||
HREADYSDC = 1'b1;
|
||||
WordCountRst = 1'b1;
|
||||
SDCBusy = 1'b1;
|
||||
if(SDCDataValid) begin
|
||||
NextState = STATE_READY;
|
||||
CommandCompleted = 1'b1;
|
||||
end else begin
|
||||
NextState = STATE_PROCESS_CMD;
|
||||
CommandCompleted = 1'b0;
|
||||
end
|
||||
end
|
||||
STATE_READ: begin
|
||||
NextState = STATE_READY;
|
||||
HREADYSDC = 1'b1;
|
||||
ReadDone = 1'b1;
|
||||
end
|
||||
default: begin
|
||||
NextState = STATE_READY;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
// clock generation divider
|
||||
|
||||
clockgater clockgater(.E(SDCCLKEN),
|
||||
.SE(1'b0),
|
||||
.CLK(HCLK),
|
||||
.ECLK(CLKGate));
|
||||
|
||||
|
||||
clkdivider #(8) clkdivider(.i_COUNT_IN_MAX(CLKDiv),
|
||||
.i_EN(CLKDiv <= 0), // enable if < 0 (msb is 1)
|
||||
.i_CLK(CLKGate),
|
||||
.i_RST(~HRESETn | CLKDivUpdateEn),
|
||||
.o_CLK(SDCCLKIn));
|
||||
|
||||
// assign SDCCLKIn = CLKGate;
|
||||
|
||||
|
||||
// should always be 0 for real implementation, but for simulation set to 1.
|
||||
logic LimitTimers;
|
||||
assign LimitTimers = '0;
|
||||
|
||||
sd_top sd_top(.CLK(SDCCLKIn),
|
||||
.a_RST(~HRESETn),
|
||||
.i_SD_CMD(SDCCmdIn),
|
||||
.o_SD_CMD(SDCCmdOut),
|
||||
.o_SD_CMD_OE(SDCCmdOE),
|
||||
.i_SD_DAT(SDCDatIn),
|
||||
.o_SD_CLK(SDCCLK),
|
||||
.i_BLOCK_ADDR(Address[32:9]),
|
||||
.o_READY_FOR_READ(SDCInitialized),
|
||||
.o_SD_RESTARTING(SDCRestarting),
|
||||
.i_READ_REQUEST(Command[2]),
|
||||
.o_DATA_TO_CORE(),
|
||||
.ReadData(ReadData512Byte),
|
||||
.o_DATA_VALID(SDCDataValid),
|
||||
.o_LAST_NIBBLE(SDCLast),
|
||||
.o_ERROR_CODE_Q(ErrorCode),
|
||||
.o_FATAL_ERROR(FatalError),
|
||||
.i_COUNT_IN_MAX(-8'd62),
|
||||
.LIMIT_SD_TIMERS(LimitTimers)); // *** must change this to 0 for real hardware.
|
||||
|
||||
|
||||
endmodule
|
||||
|
@ -1,43 +0,0 @@
|
||||
///////////////////////////////////////////
|
||||
// counter.sv
|
||||
//
|
||||
// Written: Richard Davis
|
||||
// Modified: Ross Thompson
|
||||
// Converted to SystemVerilog.
|
||||
//
|
||||
// Purpose: basic up counter
|
||||
//
|
||||
// A component of the CORE-V-WALLY configurable RISC-V project.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
||||
//
|
||||
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
|
||||
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
|
||||
// may obtain a copy of the License at
|
||||
//
|
||||
// https://solderpad.org/licenses/SHL-2.1/
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, any work distributed under the
|
||||
// License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
`include "wally-config.vh"
|
||||
|
||||
module SDCcounter #(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;
|
||||
|
||||
assign NextCount = Load ? CountIn : (CountOut + 1'b1);
|
||||
flopenr #(WIDTH) reg1(clk, reset, Enable | Load, NextCount, CountOut);
|
||||
endmodule
|
||||
|
||||
|
@ -1,105 +0,0 @@
|
||||
///////////////////////////////////////////
|
||||
// clock divider.sv
|
||||
//
|
||||
// Written: Richard Davis
|
||||
// Modified: Ross Thompson September 18, 2021
|
||||
// Converted to system verilog.
|
||||
//
|
||||
// Purpose: clock divider for sd flash
|
||||
//
|
||||
// A component of the CORE-V-WALLY configurable RISC-V project.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
||||
//
|
||||
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
|
||||
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
|
||||
// may obtain a copy of the License at
|
||||
//
|
||||
// https://solderpad.org/licenses/SHL-2.1/
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, any work distributed under the
|
||||
// License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
`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;
|
||||
|
||||
logic resetD, resetDD, resetPulse;
|
||||
logic rstdd2, rstddn;
|
||||
|
||||
assign w_load = resetPulse | w_counter_overflowed; // reload when zero occurs or when set by outside
|
||||
|
||||
SDCcounter #(.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;
|
||||
|
||||
// to ensure the clock keeps running we need to make the reset last 1 cycle
|
||||
// rather than until the reset is released. Alternatively we could do
|
||||
// two resets. The first which resets this and the clk_fsm and the second
|
||||
// which resets the rest of the design.
|
||||
// Or we can make this clock divider not depend on reset.
|
||||
|
||||
flop #(1) pulseReset
|
||||
(.d(i_RST),
|
||||
.q(resetD),
|
||||
.clk(i_CLK));
|
||||
|
||||
flop #(1) pulseReset2
|
||||
(.d(resetD),
|
||||
.q(resetDD),
|
||||
.clk(i_CLK));
|
||||
|
||||
//assign resetPulse = i_RST & ~resetDD;
|
||||
assign resetPulse = ~i_RST & resetDD;
|
||||
|
||||
assign rstdd2 = i_RST | resetDD;
|
||||
|
||||
flop #(1) fallingEdge
|
||||
(.d(rstdd2),
|
||||
.q(rstddn),
|
||||
.clk(~i_CLK));
|
||||
|
||||
flopenr #(1) toggle_flip_flop
|
||||
(.d(w_fd_D),
|
||||
.q(r_fd_Q),
|
||||
.clk(i_CLK),
|
||||
.reset(resetPulse),
|
||||
.en(w_counter_overflowed)); // only update when counter overflows
|
||||
|
||||
assign w_fd_D = ~ r_fd_Q;
|
||||
|
||||
/* -----\/----- EXCLUDED -----\/-----
|
||||
if(`FPGA) BUFGMUX clkMux(.I1(r_fd_Q), .I0(i_CLK), .S(i_EN), .O(o_CLK));
|
||||
else assign o_CLK = i_EN ? r_fd_Q : i_CLK;
|
||||
-----/\----- EXCLUDED -----/\----- */
|
||||
|
||||
if(`FPGA) BUFGMUX clkMux(.I1(r_fd_Q), .I0(i_CLK), .S(i_EN & ~rstddn), .O(o_CLK));
|
||||
else assign o_CLK = i_EN & ~rstddn ? r_fd_Q : i_CLK;
|
||||
endmodule
|
@ -1,63 +0,0 @@
|
||||
///////////////////////////////////////////
|
||||
// crc16 sipo np ce
|
||||
//
|
||||
// Written: Richard Davis
|
||||
// Modified: Ross Thompson September 18, 2021
|
||||
// Converted to system verilog.
|
||||
//
|
||||
// Purpose: CRC16 generator SIPO using register_ce
|
||||
// w/o appending any zero-bits to the message
|
||||
//
|
||||
// A component of the CORE-V-WALLY configurable RISC-V project.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
||||
//
|
||||
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
|
||||
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
|
||||
// may obtain a copy of the License at
|
||||
//
|
||||
// https://solderpad.org/licenses/SHL-2.1/
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, any work distributed under the
|
||||
// License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
`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
|
@ -1,67 +0,0 @@
|
||||
///////////////////////////////////////////
|
||||
// crc7 sipo np ce
|
||||
//
|
||||
// Written: Richard Davis
|
||||
// Modified: Ross Thompson September 18, 2021
|
||||
// Converted to system verilog.
|
||||
//
|
||||
// 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 CORE-V-WALLY configurable RISC-V project.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
||||
//
|
||||
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
|
||||
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
|
||||
// may obtain a copy of the License at
|
||||
//
|
||||
// https://solderpad.org/licenses/SHL-2.1/
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, any work distributed under the
|
||||
// License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
`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
|
@ -1,60 +0,0 @@
|
||||
///////////////////////////////////////////
|
||||
// crc16 sipo np ce
|
||||
//
|
||||
// Written: Richard Davis
|
||||
// Modified: Ross Thompson September 18, 2021
|
||||
//
|
||||
// Purpose: CRC7 generator SIPO using register_ce
|
||||
// w/o appending any zero-bits othe message
|
||||
//
|
||||
// A component of the CORE-V-WALLY configurable RISC-V project.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
||||
//
|
||||
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
|
||||
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
|
||||
// may obtain a copy of the License at
|
||||
//
|
||||
// https://solderpad.org/licenses/SHL-2.1/
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, any work distributed under the
|
||||
// License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
`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
|
||||
|
||||
|
@ -1,49 +0,0 @@
|
||||
///////////////////////////////////////////
|
||||
// piso generic ce
|
||||
//
|
||||
// Written: Richard Davis
|
||||
// Modified: Ross Thompson September 18, 2021
|
||||
//
|
||||
//
|
||||
// A component of the CORE-V-WALLY configurable RISC-V project.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
||||
//
|
||||
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
|
||||
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
|
||||
// may obtain a copy of the License at
|
||||
//
|
||||
// https://solderpad.org/licenses/SHL-2.1/
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, any work distributed under the
|
||||
// License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
`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
|
@ -1,49 +0,0 @@
|
||||
///////////////////////////////////////////
|
||||
// regfile_p2r1w1_nibo
|
||||
//
|
||||
// Written: Ross Thompson September 18, 2021
|
||||
// Modified: 2 port register file with 1 read and 1 write
|
||||
//
|
||||
//
|
||||
// A component of the CORE-V-WALLY configurable RISC-V project.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
||||
//
|
||||
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
|
||||
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
|
||||
// may obtain a copy of the License at
|
||||
//
|
||||
// https://solderpad.org/licenses/SHL-2.1/
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, any work distributed under the
|
||||
// License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
`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,
|
||||
output logic [(2**DEPTH)*WIDTH-1:0] Rd1All,
|
||||
input logic [DEPTH-1:0] wa1,
|
||||
input logic [WIDTH-1:0] wd1
|
||||
);
|
||||
|
||||
logic [WIDTH-1:0] regs [2**DEPTH-1:0];
|
||||
genvar index;
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
if(we1) begin
|
||||
regs[wa1] <= wd1;
|
||||
end
|
||||
end
|
||||
|
||||
assign rd1 = regs[ra1];
|
||||
for(index = 0; index < 2**DEPTH; index++)
|
||||
assign Rd1All[index*WIDTH+WIDTH-1:index*WIDTH] = regs[index];
|
||||
|
||||
endmodule
|
@ -1,44 +0,0 @@
|
||||
///////////////////////////////////////////
|
||||
// regfile_p2r1w1bwen
|
||||
//
|
||||
// Written: Ross Thompson September 18, 2021
|
||||
// Modified: 2 port register file with 1 read and 1 write
|
||||
//
|
||||
//
|
||||
// A component of the CORE-V-WALLY configurable RISC-V project.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
||||
//
|
||||
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
|
||||
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
|
||||
// may obtain a copy of the License at
|
||||
//
|
||||
// https://solderpad.org/licenses/SHL-2.1/
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, any work distributed under the
|
||||
// License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
`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)
|
||||
if (we1) // global write enable
|
||||
regs[wa1] = wd1 & we1bit | regs[wa1] & ~we1bit; // bit write enable
|
||||
|
||||
assign rd1 = regs[ra1];
|
||||
endmodule
|
@ -1,93 +0,0 @@
|
||||
///////////////////////////////////////////
|
||||
// sd_clk_fsm.sv
|
||||
//
|
||||
// Written: Richard Davis
|
||||
// Modified: Ross Thompson September 19, 2021
|
||||
//
|
||||
// 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 CORE-V-WALLY configurable RISC-V project.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
||||
//
|
||||
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
|
||||
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
|
||||
// may obtain a copy of the License at
|
||||
//
|
||||
// https://solderpad.org/licenses/SHL-2.1/
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, any work distributed under the
|
||||
// License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
`include "wally-config.vh"
|
||||
|
||||
module sd_clk_fsm (
|
||||
input logic CLK,
|
||||
input logic i_RST,
|
||||
(* mark_debug = "true" *)output logic o_DONE,
|
||||
(* mark_debug = "true" *)input logic i_START,
|
||||
(* mark_debug = "true" *)input logic i_FATAL_ERROR,
|
||||
(* mark_debug = "true" *)output logic o_HS_TO_INIT_CLK_DIVIDER_RST, // resets clock divider that is going from 50 MHz to 400 KHz
|
||||
(* mark_debug = "true" *)output logic o_SD_CLK_SELECTED, // which clock is selected ('0'=HS or '1'=init)
|
||||
(* mark_debug = "true" *)output logic o_G_CLK_SD_EN // Turns gated clock (G_CLK_SD) off and on
|
||||
);
|
||||
|
||||
|
||||
logic [3:0] w_next_state;
|
||||
(* mark_debug = "true" *) 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
|
||||
|
@ -1,586 +0,0 @@
|
||||
///////////////////////////////////////////
|
||||
// sd_clk_fsm.sv
|
||||
//
|
||||
// Written: Richard Davis
|
||||
// Modified: Ross Thompson September 19, 2021
|
||||
//
|
||||
// Purpose: Finite state machine for the SD CMD bus
|
||||
//
|
||||
// A component of the CORE-V-WALLY configurable RISC-V project.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
||||
//
|
||||
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
|
||||
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
|
||||
// may obtain a copy of the License at
|
||||
//
|
||||
// https://solderpad.org/licenses/SHL-2.1/
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, any work distributed under the
|
||||
// License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
`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,
|
||||
(* mark_debug = "true" *) 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
|
||||
(* mark_debug = "true" *) input logic i_ERROR_CRC16, // repeat last command
|
||||
(* mark_debug = "true" *) 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;
|
||||
(* mark_debug = "true" *) logic [4:0] 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 = 1500; // 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 = 19'd400000; // ACMD41 timeout
|
||||
//*** BUG this value is too bit to fit into 19 bits.
|
||||
localparam logic [18:0] c_1000ms = 19'd40000; // 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
|
||||
|
||||
|
||||
logic COUNTER_OUT_GT_ZERO;
|
||||
logic COUNTER_OUT_GE_ZERO;
|
||||
logic COUNTER_OUT_GT_8;
|
||||
logic COUNTER_OUT_EQ_8;
|
||||
logic COUNTER_OUT_EQ_ZERO;
|
||||
logic TIMER_OUT_GT_ZERO;
|
||||
logic TIMER_OUT_EQ_ZERO;
|
||||
logic fail_count_out_le_max_attempts;
|
||||
logic fail_count_out_lt_max_attempts;
|
||||
logic fail_count_out_gt_max_attempts;
|
||||
logic IC_OUT_EQ_2;
|
||||
logic IC_OUT_EQ_3;
|
||||
logic IC_OUT_LT_9;
|
||||
logic IC_OUT_GE_9;
|
||||
|
||||
|
||||
assign Timer_In = LIMIT_SD_TIMERS ? 19'b0000000000000000011 : 19'b0011000011010100000; // 250 ms
|
||||
|
||||
//Fail Counter, tracks how many failed attempts at command transmission
|
||||
SDCcounter #(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 COUNTER_OUT_GT_ZERO = i_COUNTER_OUT > 0;
|
||||
assign COUNTER_OUT_GE_ZERO = $signed(i_COUNTER_OUT) >= $signed(8'b0);
|
||||
assign COUNTER_OUT_GT_8 = i_COUNTER_OUT > 8;
|
||||
assign COUNTER_OUT_EQ_8 = i_COUNTER_OUT == 8;
|
||||
assign COUNTER_OUT_EQ_ZERO = i_COUNTER_OUT == 0;
|
||||
assign TIMER_OUT_GT_ZERO = i_TIMER_OUT > 0;
|
||||
assign TIMER_OUT_EQ_ZERO = i_TIMER_OUT == 0;
|
||||
assign fail_count_out_le_max_attempts = r_fail_count_out <= (c_MAX_ATTEMPTS-1);
|
||||
assign fail_count_out_lt_max_attempts = r_fail_count_out < (c_MAX_ATTEMPTS-1);
|
||||
assign fail_count_out_gt_max_attempts = r_fail_count_out > (c_MAX_ATTEMPTS-1);
|
||||
assign IC_OUT_EQ_2 = i_IC_OUT == 2;
|
||||
assign IC_OUT_EQ_3 = i_IC_OUT == 3;
|
||||
assign IC_OUT_LT_9 = i_IC_OUT < 9;
|
||||
assign IC_OUT_GE_9 = i_IC_OUT >= 9;
|
||||
|
||||
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) & (TIMER_OUT_GT_ZERO))) ? s_idle_supply_no_clk :
|
||||
|
||||
(((r_curr_state == s_idle_supply_no_clk) & (TIMER_OUT_EQ_ZERO)) |
|
||||
((r_curr_state == s_idle_supply_sd_clk) & (COUNTER_OUT_GT_ZERO))) ? s_idle_supply_sd_clk :
|
||||
|
||||
(r_curr_state == s_ld_head) ? s_count_attempt :
|
||||
|
||||
(((r_curr_state == s_count_attempt) & (fail_count_out_le_max_attempts)) |
|
||||
((r_curr_state == s_count_attempt) &
|
||||
(((IC_OUT_EQ_2) & (i_OPCODE[5:0] == c_App_Command)) |
|
||||
((IC_OUT_EQ_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)
|
||||
& (fail_count_out_gt_max_attempts))) ? s_tx_head :
|
||||
|
||||
((r_curr_state == s_count_attempt) & (fail_count_out_gt_max_attempts)) ? s_Error_TX_Failed :
|
||||
|
||||
((r_curr_state == s_tx_head) | ((r_curr_state == s_ld_tail) & (COUNTER_OUT_GT_8))) ? s_ld_tail :
|
||||
|
||||
(((r_curr_state == s_ld_tail) & (COUNTER_OUT_EQ_8)) |
|
||||
((r_curr_state == s_tx_tail) & (COUNTER_OUT_GT_ZERO))) ? s_tx_tail :
|
||||
|
||||
(r_curr_state == s_tx_tail) & (COUNTER_OUT_EQ_ZERO) ? s_setup_rx :
|
||||
|
||||
(((r_curr_state == s_setup_rx) & (i_R_TYPE == c_response_type_R0_NONE)) |
|
||||
((r_curr_state == s_idle_ncc) & (COUNTER_OUT_GT_ZERO))) ? 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) &
|
||||
(COUNTER_OUT_GT_ZERO))) ? s_idle_for_start_bit :
|
||||
|
||||
((r_curr_state == s_idle_for_start_bit) & (i_SD_CMD_RX != c_start_bit) &
|
||||
(COUNTER_OUT_EQ_ZERO)) ? s_error_no_response :
|
||||
|
||||
(((r_curr_state == s_idle_for_start_bit) & (i_SD_CMD_RX == c_start_bit) &
|
||||
/* verilator lint_off UNSIGNED */
|
||||
(COUNTER_OUT_GE_ZERO) & (i_R_TYPE == c_response_type_R2_CID_CSD)) |
|
||||
/* verilator lint_on UNSIGNED */
|
||||
((r_curr_state == s_rx_136) & (COUNTER_OUT_GT_ZERO))) ? s_rx_136 :
|
||||
|
||||
(((r_curr_state == s_idle_for_start_bit) & (i_SD_CMD_RX == c_start_bit) &
|
||||
/* verilator lint_off UNSIGNED */
|
||||
(COUNTER_OUT_GE_ZERO) & (i_R_TYPE != c_response_type_R2_CID_CSD)) |
|
||||
/* verilator lint_on UNSIGNED */
|
||||
((r_curr_state == s_rx_48) & (COUNTER_OUT_GT_ZERO))) ? s_rx_48 :
|
||||
|
||||
(((r_curr_state == s_rx_136) & (COUNTER_OUT_EQ_ZERO)) |
|
||||
((r_curr_state == s_rx_48) & COUNTER_OUT_EQ_ZERO)) ? 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) & (COUNTER_OUT_GT_ZERO))) ? s_idle_nrc :
|
||||
|
||||
((r_curr_state == s_idle_nrc) & (COUNTER_OUT_EQ_ZERO) &
|
||||
(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) & (COUNTER_OUT_EQ_ZERO)) |
|
||||
((r_curr_state == s_fetch_next_cmd) & // before CMD17
|
||||
(IC_OUT_LT_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) & (COUNTER_OUT_EQ_ZERO) &
|
||||
(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) & (COUNTER_OUT_EQ_ZERO) &
|
||||
(~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) & (COUNTER_OUT_EQ_ZERO)) |
|
||||
((r_curr_state == s_idle_nrc) & (COUNTER_OUT_EQ_ZERO) &
|
||||
(~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) &
|
||||
(IC_OUT_GE_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
|
@ -1,253 +0,0 @@
|
||||
///////////////////////////////////////////
|
||||
// sd_dat_fsm.sv
|
||||
//
|
||||
// Written: Richard Davis
|
||||
// Modified: Ross Thompson September 19, 2021
|
||||
//
|
||||
// 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 CORE-V-WALLY configurable RISC-V project.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
||||
//
|
||||
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
|
||||
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
|
||||
// may obtain a copy of the License at
|
||||
//
|
||||
// https://solderpad.org/licenses/SHL-2.1/
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, any work distributed under the
|
||||
// License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
`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
|
||||
(* mark_debug = "true" *)output logic o_CRC16_EN, o_CRC16_RST, // shared signals for all 4 CRC16_SIPO (one for each of 4 DAT lines)
|
||||
(* mark_debug = "true" *)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
|
||||
(* mark_debug = "true" *)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
|
||||
(* mark_debug = "true" *)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
|
||||
(* mark_debug = "true" *)input logic i_CMD_TX_DONE, // command transmission completed, begin waiting for DATA
|
||||
(* mark_debug = "true" *)output logic o_DAT_RX_DONE, // tell SD_CMD_FSM that DAT communication is completed, send next instruction to sd card
|
||||
(* mark_debug = "true" *)output logic o_ERROR_DAT_TIMES_OUT, // error flag for when DAT times out (so don't fetch more instructions)
|
||||
(* mark_debug = "true" *)output logic o_DAT_ERROR_FD_RST,
|
||||
(* mark_debug = "true" *)output logic o_DAT_ERROR_FD_EN, // tell SD_CMD_FSM to resend command due to error in transmission
|
||||
input logic LIMIT_SD_TIMERS
|
||||
);
|
||||
|
||||
(* mark_debug = "true" *) logic [3:0] r_curr_state;
|
||||
logic [3:0] w_next_state;
|
||||
|
||||
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)
|
||||
|
||||
|
||||
logic TIMER_OUT_GT_0;
|
||||
logic TIMER_OUT_EQ_0;
|
||||
logic COUNTER_OUT_EQ_1023;
|
||||
logic COUNTER_OUT_LT_1023;
|
||||
logic COUNTER_OUT_LT_128;
|
||||
logic COUNTER_OUT_EQ_128;
|
||||
logic COUNTER_OUT_LT_144;
|
||||
logic COUNTER_OUT_EQ_144;
|
||||
logic COUNTER_OUT_LT_1040;
|
||||
logic COUNTER_OUT_EQ_1040;
|
||||
|
||||
|
||||
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 TIMER_OUT_GT_0 = i_TIMER_OUT > 0;
|
||||
assign TIMER_OUT_EQ_0 = i_TIMER_OUT == 0;
|
||||
assign COUNTER_OUT_EQ_1023 = i_COUNTER_OUT == 1023;
|
||||
assign COUNTER_OUT_LT_1023 = i_COUNTER_OUT < 1023;
|
||||
assign COUNTER_OUT_LT_128 = i_COUNTER_OUT < 128;
|
||||
assign COUNTER_OUT_EQ_128 = i_COUNTER_OUT == 128;
|
||||
assign COUNTER_OUT_LT_144 = i_COUNTER_OUT < 144;
|
||||
assign COUNTER_OUT_EQ_144 = i_COUNTER_OUT == 144;
|
||||
assign COUNTER_OUT_LT_1040 = i_COUNTER_OUT < 1040;
|
||||
assign COUNTER_OUT_EQ_1040 = i_COUNTER_OUT == 1040;
|
||||
|
||||
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) & (COUNTER_OUT_EQ_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) & (TIMER_OUT_GT_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,
|
||||
(TIMER_OUT_EQ_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) & (TIMER_OUT_GT_0) &
|
||||
(i_DAT0_Q == c_start_bit) & (i_USES_DAT == c_DAT_busy)) |
|
||||
((r_curr_state == s_read_r1b) & (TIMER_OUT_GT_0) & (i_DAT0_Q == c_busy_bit))) ? s_read_r1b :
|
||||
|
||||
(((r_curr_state == s_read_r1b) & (TIMER_OUT_EQ_0)) |
|
||||
((r_curr_state == s_idle_for_start_bit) & (TIMER_OUT_EQ_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) & (TIMER_OUT_GT_0) & (i_DAT0_Q == c_start_bit) &
|
||||
(i_USES_DAT == c_DAT_wide)) |
|
||||
((r_curr_state == s_rx_wide_data) & (COUNTER_OUT_LT_128))) ? s_rx_wide_data :
|
||||
|
||||
(((r_curr_state == s_idle_for_start_bit) & (TIMER_OUT_GT_0) &
|
||||
(i_DAT0_Q == c_start_bit) & (i_USES_DAT == c_DAT_block)) |
|
||||
((r_curr_state == s_rx_block_data) & (COUNTER_OUT_LT_1023))) ? s_rx_block_data :
|
||||
|
||||
(((r_curr_state == s_rx_wide_data) & (COUNTER_OUT_EQ_128)) |
|
||||
((r_curr_state == s_rx_block_data) & (COUNTER_OUT_EQ_1023)) |
|
||||
((r_curr_state == s_rx_crc16) &
|
||||
(((i_USES_DAT == c_DAT_wide) & (COUNTER_OUT_LT_144)) |
|
||||
((i_USES_DAT == c_DAT_block) & (COUNTER_OUT_LT_1040))))) ? s_rx_crc16 :
|
||||
|
||||
((r_curr_state == s_rx_crc16) &
|
||||
(((i_USES_DAT == c_DAT_wide) & (COUNTER_OUT_EQ_144)) |
|
||||
((i_USES_DAT == c_DAT_block) & (COUNTER_OUT_EQ_1040))) &
|
||||
(~i_DATA_CRC16_GOOD)) ? s_error_crc16_fail :
|
||||
|
||||
((r_curr_state == s_rx_crc16) & (i_USES_DAT == c_DAT_wide) & (COUNTER_OUT_EQ_144) &
|
||||
(i_DATA_CRC16_GOOD)) ? s_publish_wide_data :
|
||||
|
||||
((r_curr_state == s_rx_crc16) &
|
||||
(i_USES_DAT == c_DAT_block) & (COUNTER_OUT_EQ_1040) & (i_DATA_CRC16_GOOD)) ? s_reset_nibble_counter :
|
||||
|
||||
((r_curr_state == s_reset_nibble_counter)) ? 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)
|
||||
& (COUNTER_OUT_EQ_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
|
@ -1,652 +0,0 @@
|
||||
///////////////////////////////////////////
|
||||
// sd_top.sv
|
||||
//
|
||||
// Written: Richard Davis
|
||||
// Modified: Ross Thompson September 19, 2021
|
||||
//
|
||||
// Purpose: SD card controller
|
||||
//
|
||||
// A component of the CORE-V-WALLY configurable RISC-V project.
|
||||
//
|
||||
/// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
||||
//
|
||||
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
|
||||
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
|
||||
// may obtain a copy of the License at
|
||||
//
|
||||
// https://solderpad.org/licenses/SHL-2.1/
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, any work distributed under the
|
||||
// License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
`include "wally-config.vh"
|
||||
|
||||
module sd_top #(parameter g_COUNT_WIDTH = 8) (
|
||||
input logic CLK, // 1.2 GHz (1.0 GHz typical)
|
||||
input logic a_RST, // Reset signal (Must be held for minimum of 24 clock cycles)
|
||||
// a_RST MUST COME OUT OF RESET SYNCHRONIZED TO THE 1.2 GHZ CLOCK!
|
||||
// io_SD_CMD_z : inout std_logic; // SD CMD Bus
|
||||
(* mark_debug = "true" *)input logic i_SD_CMD, // CMD Response from card
|
||||
(* mark_debug = "true" *)output logic o_SD_CMD, // CMD Command from host
|
||||
(* mark_debug = "true" *)output logic o_SD_CMD_OE, // Direction of SD_CMD
|
||||
(* mark_debug = "true" *)input logic [3:0] i_SD_DAT, // SD DAT Bus
|
||||
(* mark_debug = "true" *)output logic o_SD_CLK, // SD CLK Bus
|
||||
// For communication with core cpu
|
||||
input logic [32:9] i_BLOCK_ADDR, // see "Addressing" in parts.fods (only 8GB total capacity is used)
|
||||
output logic o_READY_FOR_READ, // tells core that initialization sequence is completed and
|
||||
// sd card is ready to read a 512 byte block to the core.
|
||||
// Held high during idle until i_READ_REQUEST is received
|
||||
output logic o_SD_RESTARTING, // inform core the need to restart
|
||||
|
||||
input logic i_READ_REQUEST, // After Ready for read is sent to the core, the core will
|
||||
// pulse this bit high to indicate it wants the block at this address
|
||||
output logic [3:0] o_DATA_TO_CORE, // nibble being sent to core when DATA block is
|
||||
output logic [4095:0] ReadData, // full 512 bytes to Bus
|
||||
// being published
|
||||
output logic o_DATA_VALID, // held high while data being read to core to indicate that it is valid
|
||||
output logic o_LAST_NIBBLE, // pulse when last nibble is sent
|
||||
output logic [2:0] o_ERROR_CODE_Q, // indicates which error occured
|
||||
output logic o_FATAL_ERROR, // indicates that the FATAL ERROR register has updated
|
||||
// For tuning
|
||||
input logic [g_COUNT_WIDTH-1:0] i_COUNT_IN_MAX,
|
||||
input logic LIMIT_SD_TIMERS
|
||||
);
|
||||
|
||||
localparam logic c_CMD = 1'b0;
|
||||
localparam logic c_ACMD = 1'b1;
|
||||
|
||||
// packet bit names
|
||||
localparam logic c_start_bit = 1'b0; // bit 47
|
||||
localparam logic c_stop_bit = 1'b1; // bit 0, AKA "end bit"
|
||||
// transmitter bit, bit 46
|
||||
localparam logic c_tx_host_command = 1'b1;
|
||||
localparam logic c_tx_card_response = 1'b0;
|
||||
|
||||
// response types
|
||||
localparam logic [2:0] c_response_type_R0_NONE = 3'd0;
|
||||
localparam logic [2:0] c_response_type_R1_NORMAL = 3'd1;
|
||||
localparam logic [2:0] c_response_type_R2_CID_CSD = 3'd2;
|
||||
localparam logic [2:0] c_response_type_R3_OCR = 3'd3;
|
||||
localparam logic [2:0] c_response_type_R6_RCA = 3'd6;
|
||||
localparam logic [2:0] c_response_type_R7_CIC = 3'd7;
|
||||
|
||||
// uses dat
|
||||
localparam logic [1:0] c_DAT_none = 2'b00;
|
||||
localparam logic [1:0] c_DAT_busy = 2'b01;
|
||||
localparam logic [1:0] c_DAT_wide = 2'b10;
|
||||
localparam logic [1:0] c_DAT_block = 2'b11;
|
||||
|
||||
// tx source selection
|
||||
localparam logic [1:0] c_tx_low = 2'b00;
|
||||
localparam logic [1:0] c_tx_high = 2'b01;
|
||||
localparam logic [1:0] c_tx_head = 2'b10;
|
||||
localparam logic [1:0] c_tx_tail = 2'b11;
|
||||
|
||||
// command indexes
|
||||
localparam logic [45:40] c_Go_Idle_State = 6'd00; // CMD0
|
||||
localparam logic [45:40] c_All_Send_CID = 6'd02; // CMD2
|
||||
localparam logic [45:40] c_SD_Send_RCA = 6'd03; // CMD3
|
||||
localparam logic [45:40] c_Switch_Function = 6'd06; // CMD6
|
||||
localparam logic [45:40] c_Set_Bus_Width = 6'd06; // ACMD6
|
||||
localparam logic [45:40] c_Select_Card = 6'd07; // CMD7
|
||||
localparam logic [45:40] c_Send_IF_State = 6'd08; // CMD8
|
||||
localparam logic [45:40] c_Read_Single_Block = 6'd17; // CMD17
|
||||
localparam logic [45:40] c_SD_Send_OCR = 6'd41; // ACMD41
|
||||
localparam logic [45:40] c_App_Command = 6'd55; // CMD55
|
||||
|
||||
// bitmasks
|
||||
localparam logic [127:96] c_CMD0_mask_check_redo_bits = 32'h00000000; // Go_Idle_State
|
||||
localparam logic [127:96] c_CMD0_ans_dont_redo = 32'h00000000;
|
||||
localparam logic [127:96] c_CMD0_mask_check_error_bits = 32'h00000000;
|
||||
localparam logic [127:96] c_CMD0_ans_error_free = 32'h00000000;
|
||||
|
||||
localparam logic [127:96] c_CMD2_mask_check_redo_bits = 32'h00000000; // All_Send_CID
|
||||
localparam logic [127:96] c_CMD2_ans_dont_redo = 32'h00000000;
|
||||
localparam logic [127:96] c_CMD2_mask_check_error_bits = 32'h00000000;
|
||||
localparam logic [127:96] c_CMD2_ans_error_free = 32'h00000000;
|
||||
|
||||
localparam logic [127:96] c_CMD3_mask_check_redo_bits = 32'h00000000; // SD_Send_RCA
|
||||
localparam logic [127:96] c_CMD3_ans_dont_redo = 32'h00000000;
|
||||
localparam logic [127:96] c_CMD3_mask_check_error_bits = 32'h00002000;
|
||||
localparam logic [127:96] c_CMD3_ans_error_free = 32'h00000000;
|
||||
|
||||
localparam logic [127:96] c_CMD6_mask_check_redo_bits = 32'h00000000; // Switch_Function
|
||||
localparam logic [127:96] c_CMD6_ans_dont_redo = 32'h00000000;
|
||||
localparam logic [127:96] c_CMD6_mask_check_error_bits = 32'h82380000;
|
||||
localparam logic [127:96] c_CMD6_ans_error_free = 32'h00000000;
|
||||
|
||||
localparam logic [127:96] c_ACMD6_mask_check_redo_bits = 32'h00000000; // Set_Bus_Width
|
||||
localparam logic [127:96] c_ACMD6_ans_dont_redo = 32'h00000000;
|
||||
localparam logic [127:96] c_ACMD6_mask_check_error_bits = 32'h8F398020;
|
||||
localparam logic [127:96] c_ACMD6_ans_error_free = 32'h00000020;
|
||||
|
||||
localparam logic [127:96] c_CMD7_mask_check_redo_bits = 32'h00000000; // Select_Card
|
||||
localparam logic [127:96] c_CMD7_ans_dont_redo = 32'h00000000;
|
||||
localparam logic [127:96] c_CMD7_mask_check_error_bits = 32'h0F398000;
|
||||
localparam logic [127:96] c_CMD7_ans_error_free = 32'h00000000;
|
||||
|
||||
localparam logic [127:96] c_CMD8_mask_check_redo_bits = 32'h00000000; // Send_IF_State
|
||||
localparam logic [127:96] c_CMD8_ans_dont_redo = 32'h00000000;
|
||||
localparam logic [127:96] c_CMD8_mask_check_error_bits = 32'h00000FFF;
|
||||
localparam logic [127:96] c_CMD8_ans_error_free = 32'h000001FF;
|
||||
|
||||
localparam logic [127:96] c_CMD17_mask_check_redo_bits = 32'h00000000; // Read_Single_Block
|
||||
localparam logic [127:96] c_CMD17_ans_dont_redo = 32'h00000000;
|
||||
localparam logic [127:96] c_CMD17_mask_check_error_bits = 32'hCF398000;
|
||||
localparam logic [127:96] c_CMD17_ans_error_free = 32'h00000000;
|
||||
|
||||
localparam logic [127:96] c_ACMD41_mask_check_redo_bits = 32'h80000000; //32'h80000000; // SD_Send_OCR
|
||||
localparam logic [127:96] c_ACMD41_ans_dont_redo = 32'h80000000; //32'h80000000;
|
||||
localparam logic [127:96] c_ACMD41_mask_check_error_bits = 32'h41FF8000; // 32'h41FF8000;
|
||||
localparam logic [127:96] c_ACMD41_ans_error_free = 32'h40FF8000; // 32'h40FF8000
|
||||
|
||||
localparam logic [127:96] c_CMD55_mask_check_redo_bits = 32'h00000000; // App_Command
|
||||
localparam logic [127:96] c_CMD55_ans_dont_redo = 32'h00000000;
|
||||
localparam logic [127:96] c_CMD55_mask_check_error_bits = 32'h0F398000;
|
||||
localparam logic [127:96] c_CMD55_ans_error_free = 32'h00000000;
|
||||
|
||||
localparam logic [127:96] c_ACMD55_mask_check_redo_bits = 32'h00000000; // App_Command
|
||||
localparam logic [127:96] c_ACMD55_ans_dont_redo = 32'h00000000;
|
||||
localparam logic [127:96] c_ACMD55_mask_check_error_bits = 32'h0F398000;
|
||||
localparam logic [127:96] c_ACMD55_ans_error_free = 32'h00000000;
|
||||
|
||||
// SD_CMD_FSM Connections
|
||||
logic w_TIMER_LOAD, w_TIMER_EN;
|
||||
logic [18:0] w_TIMER_IN;
|
||||
logic [18:0] r_TIMER_OUT;
|
||||
logic w_COUNTER_LOAD, w_COUNTER_EN;
|
||||
logic [7:0] w_COUNTER_IN;
|
||||
logic [7:0] r_COUNTER_OUT;
|
||||
logic w_SD_CLK_EN;
|
||||
logic w_CLOCK_CHANGE_DONE, w_START_CLOCK_CHANGE; // to clk fsm
|
||||
logic w_HS_TO_INIT_CLK_DIVIDER_RST;
|
||||
(* mark_debug = "true" *)logic w_IC_RST, w_IC_EN, w_IC_UP_DOWN;
|
||||
(* mark_debug = "true" *)logic w_SD_CMD_OE;
|
||||
logic w_TX_PISO40_LOAD, w_TX_PISO40_EN;
|
||||
logic w_TX_PISO8_LOAD, w_TX_PISO8_EN;
|
||||
logic w_TX_CRC7_PIPO_RST, w_TX_CRC7_PIPO_EN;
|
||||
logic [1:0] w_TX_SOURCE_SELECT;
|
||||
logic w_CMD_TX_IS_CMD55_RST;
|
||||
logic w_CMD_TX_IS_CMD55_EN;
|
||||
logic w_RX_SIPO48_RST, w_RX_SIPO48_EN;
|
||||
(* mark_debug = "true" *)logic [39:8] r_RESPONSE_CONTENT;
|
||||
(* mark_debug = "true" *)logic [45:40] r_RESPONSE_INDEX;
|
||||
logic w_RX_CRC7_SIPO_RST, w_RX_CRC7_SIPO_EN;
|
||||
logic [6:0] r_RX_CRC7_Q;
|
||||
logic w_RCA_REGISTER_RST, w_RCA_REGISTER_EN;
|
||||
logic w_CMD_TX_DONE;
|
||||
logic w_DAT_RX_DONE;
|
||||
logic w_DAT_ERROR_FD_RST_DAT, w_DAT_ERROR_FD_RST_CMD, w_DAT_ERROR_FD_RST, w_DAT_ERROR_FD_EN;
|
||||
(* mark_debug = "true" *)logic r_DAT_ERROR_Q; // CRC16 error or time out
|
||||
(* mark_debug = "true" *)logic w_NOT_DAT_ERROR_Q; // '0'=no error, '1'=tx error on DAT bus
|
||||
(* mark_debug = "true" *)logic w_ERROR_DAT_TIMES_OUT;
|
||||
(* mark_debug = "true" *)logic w_FATAL_ERROR;
|
||||
(* mark_debug = "true" *)logic [2:0] r_ERROR_CODE_Q; // indicates which fatal error occured
|
||||
|
||||
// Communication with core
|
||||
(* mark_debug = "true" *)logic w_READY_FOR_READ;
|
||||
(* mark_debug = "true" *)logic w_READ_REQUEST;
|
||||
(* mark_debug = "true" *)logic [3:0] r_DATA_TO_CORE;
|
||||
(* mark_debug = "true" *)logic w_DATA_VALID;
|
||||
(* mark_debug = "true" *)logic w_LAST_NIBBLE;
|
||||
|
||||
//SD_DAT_FSM Connections
|
||||
logic w_DAT_TIMER_LOAD, w_DAT_TIMER_EN;
|
||||
logic w_DAT_COUNTER_RST, w_DAT_COUNTER_EN;
|
||||
logic w_CRC16_EN, w_CRC16_RST;
|
||||
logic w_BUSY_RST, w_BUSY_EN;
|
||||
logic w_NIBO_EN;
|
||||
logic w_DATA_CRC16_GOOD;
|
||||
logic [22:0] w_DAT_TIMER_IN;
|
||||
logic [22:0] r_DAT_TIMER_OUT;
|
||||
logic [10:0] r_DAT_COUNTER_OUT;
|
||||
(* mark_debug = "true" *)logic [3:0] r_DAT_Q;
|
||||
|
||||
// RCA Register
|
||||
logic [15:0] w_RCA_D_Q;
|
||||
logic [15:0] r_RCA_Q2;
|
||||
|
||||
// Multiplexer Logics
|
||||
logic [132:0] w_instruction_control_bits;
|
||||
logic [132:130] w_R_TYPE ;
|
||||
logic [129:128] w_USES_DAT ;
|
||||
logic [127:96] w_NO_REDO_MASK ;
|
||||
logic [95:64] w_NO_REDO_ANS ;
|
||||
logic [63:32] w_NO_ERROR_MASK ;
|
||||
logic [31:0] w_NO_ERROR_ANS ;
|
||||
logic [45:40] w_command_index ;
|
||||
logic [39:8] w_command_arguments ;
|
||||
logic [47:8] w_command_head ;
|
||||
(* mark_debug = "true" *)logic [6:0] w_OPCODE_Q ;
|
||||
|
||||
// TOP_LEVEL Connections
|
||||
logic [40:9] w_BLOCK_ADDR ;
|
||||
(* mark_debug = "true" *)logic [3:0] r_IC_OUT ;
|
||||
logic [2:0] r_command_index_is_55_history ; // [0] is live index, [1] is currently saved index, [2] is index of previous command
|
||||
logic r_previous_command_index_was_55_q; // is index of previous command 55, wired to r_command_index_is_55_history[2]
|
||||
logic r_ACMD_Q; // if the previous command sent to the SD card successfully had index 55, then the SD card thinks the current command is ACMD
|
||||
|
||||
// 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;
|
||||
|
||||
// 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 [15:0] r_CLK_FSM_RST ; // a_rst logic delayed by one 1.2 GHz period
|
||||
logic w_SD_CLK_SELECTED;
|
||||
|
||||
//DAT FSM Connections
|
||||
logic [15:0] r_DAT3_CRC16, r_DAT2_CRC16, r_DAT1_CRC16;
|
||||
logic [15:0] r_DAT0_CRC16;
|
||||
|
||||
assign w_BLOCK_ADDR = {8'h00, i_BLOCK_ADDR}; // (40 downto 36 are zero since card is 64 GB)
|
||||
// (35 downto 32 are zero since memeory is only 8GB total)
|
||||
|
||||
assign o_READY_FOR_READ = w_READY_FOR_READ;
|
||||
assign w_READ_REQUEST = i_READ_REQUEST;
|
||||
assign o_DATA_TO_CORE = r_DATA_TO_CORE;
|
||||
assign o_DATA_VALID = w_DATA_VALID;
|
||||
assign o_LAST_NIBBLE = (w_LAST_NIBBLE | w_FATAL_ERROR); // indicate done if (last nibble OR Fatal Error go high)
|
||||
assign o_FATAL_ERROR = w_FATAL_ERROR;
|
||||
|
||||
sd_cmd_fsm my_sd_cmd_fsm
|
||||
(
|
||||
.CLK(r_G_CLK_SD),
|
||||
.i_RST(a_RST),
|
||||
.o_TIMER_LOAD(w_TIMER_LOAD),
|
||||
.o_TIMER_EN(w_TIMER_EN),
|
||||
.o_TIMER_IN(w_TIMER_IN),
|
||||
.i_TIMER_OUT(r_TIMER_OUT),
|
||||
.o_COUNTER_LOAD(w_COUNTER_LOAD),
|
||||
.o_COUNTER_EN(w_COUNTER_EN),
|
||||
.o_COUNTER_IN(w_COUNTER_IN),
|
||||
.i_COUNTER_OUT(r_COUNTER_OUT),
|
||||
.o_SD_CLK_EN(w_SD_CLK_EN),
|
||||
.i_CLOCK_CHANGE_DONE(w_CLOCK_CHANGE_DONE),
|
||||
.o_START_CLOCK_CHANGE(w_START_CLOCK_CHANGE),
|
||||
.o_IC_RST(w_IC_RST),
|
||||
.o_IC_EN(w_IC_EN),
|
||||
.o_IC_UP_DOWN(w_IC_UP_DOWN),
|
||||
.i_IC_OUT(r_IC_OUT),
|
||||
.i_USES_DAT(w_USES_DAT),
|
||||
.i_OPCODE(w_OPCODE_Q),
|
||||
.i_R_TYPE(w_R_TYPE),
|
||||
.i_NO_REDO_MASK(w_NO_REDO_MASK),
|
||||
.i_NO_REDO_ANS(w_NO_REDO_ANS),
|
||||
.i_NO_ERROR_MASK(w_NO_ERROR_MASK),
|
||||
.i_NO_ERROR_ANS(w_NO_ERROR_ANS),
|
||||
.o_SD_CMD_OE(w_SD_CMD_OE),
|
||||
.o_TX_PISO40_LOAD(w_TX_PISO40_LOAD),
|
||||
.o_TX_PISO40_EN(w_TX_PISO40_EN),
|
||||
.o_TX_PISO8_LOAD(w_TX_PISO8_LOAD),
|
||||
.o_TX_PISO8_EN(w_TX_PISO8_EN),
|
||||
.o_TX_CRC7_PIPO_RST(w_TX_CRC7_PIPO_RST),
|
||||
.o_TX_CRC7_PIPO_EN(w_TX_CRC7_PIPO_EN),
|
||||
.o_TX_SOURCE_SELECT(w_TX_SOURCE_SELECT),
|
||||
.o_CMD_TX_IS_CMD55_RST(w_CMD_TX_IS_CMD55_RST),
|
||||
.o_CMD_TX_IS_CMD55_EN(w_CMD_TX_IS_CMD55_EN),
|
||||
.i_SD_CMD_RX(w_SD_CMD_RX),
|
||||
.o_RX_SIPO48_RST(w_RX_SIPO48_RST),
|
||||
.o_RX_SIPO48_EN(w_RX_SIPO48_EN),
|
||||
.i_RESPONSE_CONTENT(r_RESPONSE_CONTENT),
|
||||
.i_RESPONSE_INDEX(r_RESPONSE_INDEX),
|
||||
.o_RX_CRC7_SIPO_RST(w_RX_CRC7_SIPO_RST),
|
||||
.o_RX_CRC7_SIPO_EN(w_RX_CRC7_SIPO_EN),
|
||||
.i_RX_CRC7(r_RX_CRC7_Q),
|
||||
.o_RCA_REGISTER_RST(w_RCA_REGISTER_RST),
|
||||
.o_RCA_REGISTER_EN(w_RCA_REGISTER_EN),
|
||||
.o_CMD_TX_DONE(w_CMD_TX_DONE),
|
||||
.i_DAT_RX_DONE(w_DAT_RX_DONE),
|
||||
.i_ERROR_CRC16(w_NOT_DAT_ERROR_Q),
|
||||
.i_ERROR_DAT_TIMES_OUT(w_ERROR_DAT_TIMES_OUT),
|
||||
.i_READ_REQUEST(w_READ_REQUEST),
|
||||
.o_READY_FOR_READ(w_READY_FOR_READ),
|
||||
.o_SD_RESTARTING(o_SD_RESTARTING),
|
||||
.o_DAT_ERROR_FD_RST(w_DAT_ERROR_FD_RST_CMD),
|
||||
.o_ERROR_CODE_Q(r_ERROR_CODE_Q),
|
||||
.o_FATAL_ERROR(w_FATAL_ERROR),
|
||||
.LIMIT_SD_TIMERS(LIMIT_SD_TIMERS));
|
||||
|
||||
assign o_ERROR_CODE_Q = r_ERROR_CODE_Q;
|
||||
|
||||
sd_dat_fsm my_sd_dat_fsm
|
||||
(.CLK(r_G_CLK_SD),
|
||||
.i_RST(a_RST),
|
||||
.o_TIMER_LOAD(w_DAT_TIMER_LOAD),
|
||||
.o_TIMER_EN(w_DAT_TIMER_EN),
|
||||
.o_TIMER_IN(w_DAT_TIMER_IN),
|
||||
.i_TIMER_OUT(r_DAT_TIMER_OUT),
|
||||
.i_SD_CLK_SELECTED(w_SD_CLK_SELECTED),
|
||||
.o_COUNTER_RST(w_DAT_COUNTER_RST),
|
||||
.o_COUNTER_EN(w_DAT_COUNTER_EN),
|
||||
.i_COUNTER_OUT(r_DAT_COUNTER_OUT),
|
||||
.o_CRC16_EN(w_CRC16_EN),
|
||||
.o_CRC16_RST(w_CRC16_RST),
|
||||
.i_DATA_CRC16_GOOD(w_DATA_CRC16_GOOD),
|
||||
.o_BUSY_RST(w_BUSY_RST),
|
||||
.o_BUSY_EN(w_BUSY_EN),
|
||||
.i_DAT0_Q(r_DAT_Q[0]),
|
||||
.o_NIBO_EN(w_NIBO_EN),
|
||||
.i_USES_DAT(w_USES_DAT),
|
||||
.i_CMD_TX_DONE(w_CMD_TX_DONE),
|
||||
.o_DAT_RX_DONE(w_DAT_RX_DONE),
|
||||
.o_ERROR_DAT_TIMES_OUT(w_ERROR_DAT_TIMES_OUT),
|
||||
.o_DATA_VALID(w_DATA_VALID),
|
||||
.o_LAST_NIBBLE(w_LAST_NIBBLE),
|
||||
.o_DAT_ERROR_FD_RST(w_DAT_ERROR_FD_RST_DAT),
|
||||
.o_DAT_ERROR_FD_EN(w_DAT_ERROR_FD_EN),
|
||||
.LIMIT_SD_TIMERS(LIMIT_SD_TIMERS));
|
||||
|
||||
assign w_DAT_ERROR_FD_RST = w_DAT_ERROR_FD_RST_CMD | w_DAT_ERROR_FD_RST_DAT;
|
||||
|
||||
flopenr #(1) dat_error_fd
|
||||
(.clk(r_G_CLK_SD),
|
||||
.d(w_DATA_CRC16_GOOD),
|
||||
.q(r_DAT_ERROR_Q),
|
||||
.en(w_DAT_ERROR_FD_EN),
|
||||
.reset((w_DAT_ERROR_FD_RST)));
|
||||
|
||||
assign w_NOT_DAT_ERROR_Q = ~r_DAT_ERROR_Q;
|
||||
|
||||
up_down_counter #(23) dat_fsm_timer
|
||||
(
|
||||
.CountIn(w_DAT_TIMER_IN),
|
||||
.CountOut(r_DAT_TIMER_OUT),
|
||||
.Load(w_DAT_TIMER_LOAD),
|
||||
.Enable(w_DAT_TIMER_EN),
|
||||
.UpDown(1'b0), // Count DOWN only
|
||||
.clk(r_G_CLK_SD),
|
||||
.reset(1'b0)); // No Reset, Just Load
|
||||
|
||||
SDCcounter #(11) dat_nibble_counter
|
||||
(
|
||||
.CountIn('0),
|
||||
.CountOut(r_DAT_COUNTER_OUT),
|
||||
.Load(1'b0),
|
||||
.Enable(w_DAT_COUNTER_EN),
|
||||
.clk(r_G_CLK_SD),
|
||||
.reset(w_DAT_COUNTER_RST));
|
||||
|
||||
regfile_p2r1w1_nibo #(.DEPTH(10), .WIDTH(4) ) regfile_cmd17_data_block // Nibble In - Nibble Out (NINO)
|
||||
(.clk(r_G_CLK_SD),
|
||||
.we1(w_NIBO_EN),
|
||||
.ra1(r_DAT_COUNTER_OUT[9:0]), // Nibble Read (to core) Address
|
||||
.rd1(r_DATA_TO_CORE), // output nibble to core
|
||||
.Rd1All(ReadData),
|
||||
.wa1(r_DAT_COUNTER_OUT[9:0]), // Nibble Write (to host) Address
|
||||
.wd1(r_DAT_Q)); // input nibble from card
|
||||
|
||||
crc16_sipo_np_ce crc16_sipo_np_ce_DAT3
|
||||
(.CLK(r_G_CLK_SD),
|
||||
.RST(w_CRC16_RST),
|
||||
.i_enable(w_CRC16_EN),
|
||||
.i_message_bit(r_DAT_Q[3]),
|
||||
.o_crc16(r_DAT3_CRC16));
|
||||
|
||||
crc16_sipo_np_ce crc16_sipo_np_ce_DAT2
|
||||
(.CLK(r_G_CLK_SD),
|
||||
.RST(w_CRC16_RST),
|
||||
.i_enable(w_CRC16_EN),
|
||||
.i_message_bit(r_DAT_Q[2]),
|
||||
.o_crc16(r_DAT2_CRC16));
|
||||
|
||||
crc16_sipo_np_ce crc16_sipo_np_ce_DAT1
|
||||
(.CLK(r_G_CLK_SD),
|
||||
.RST(w_CRC16_RST),
|
||||
.i_enable(w_CRC16_EN),
|
||||
.i_message_bit(r_DAT_Q[1]),
|
||||
.o_crc16(r_DAT1_CRC16));
|
||||
|
||||
crc16_sipo_np_ce crc16_sipo_np_ce_DAT0
|
||||
(.CLK(r_G_CLK_SD),
|
||||
.RST(w_CRC16_RST),
|
||||
.i_enable(w_CRC16_EN),
|
||||
.i_message_bit(r_DAT_Q[0]),
|
||||
.o_crc16(r_DAT0_CRC16));
|
||||
|
||||
|
||||
assign w_DATA_CRC16_GOOD = ({r_DAT3_CRC16, r_DAT2_CRC16, r_DAT1_CRC16, r_DAT0_CRC16}) == 64'h0000000000000000;
|
||||
|
||||
flopenr #(4) busy_bit_fd
|
||||
(.en(w_BUSY_EN),
|
||||
.clk(r_G_CLK_SD),
|
||||
.d(i_SD_DAT),
|
||||
.q(r_DAT_Q),
|
||||
.reset(w_BUSY_RST));
|
||||
|
||||
sd_clk_fsm my_clk_fsm
|
||||
(.CLK(CLK),
|
||||
.i_RST(a_RST),
|
||||
.o_DONE(w_CLOCK_CHANGE_DONE),
|
||||
.i_START(w_START_CLOCK_CHANGE),
|
||||
.o_HS_TO_INIT_CLK_DIVIDER_RST(w_HS_TO_INIT_CLK_DIVIDER_RST),
|
||||
.o_SD_CLK_SELECTED(w_SD_CLK_SELECTED),
|
||||
.i_FATAL_ERROR(w_FATAL_ERROR),
|
||||
.o_G_CLK_SD_EN(w_G_CLK_SD_EN));
|
||||
|
||||
up_down_counter #(19) cmd_fsm_timer
|
||||
(.CountIn(w_TIMER_IN),
|
||||
.CountOut(r_TIMER_OUT),
|
||||
.Load(w_TIMER_LOAD),
|
||||
.Enable(w_TIMER_EN),
|
||||
.UpDown(1'b0), // Count DOWN only
|
||||
.clk(r_G_CLK_SD),
|
||||
.reset(1'b0)); // No Reset, Just Load
|
||||
|
||||
up_down_counter #(8) cmd_fsm_counter
|
||||
(.CountIn(w_COUNTER_IN),
|
||||
.CountOut(r_COUNTER_OUT),
|
||||
.Load(w_COUNTER_LOAD),
|
||||
.Enable(w_COUNTER_EN),
|
||||
.UpDown(1'b0), // Count DOWN only
|
||||
.clk(r_G_CLK_SD),
|
||||
.reset(1'b0)); // No RESET, only LOAD
|
||||
|
||||
up_down_counter #(4) instruction_counter
|
||||
(.CountIn('0), // No CountIn, only RESET
|
||||
.CountOut(r_IC_OUT),
|
||||
.Load(1'b0), // No LOAD, only RESET
|
||||
.Enable(w_IC_EN),
|
||||
.UpDown(w_IC_UP_DOWN),
|
||||
.clk(r_G_CLK_SD),
|
||||
.reset(w_IC_RST | a_RST));
|
||||
|
||||
// Clock selection
|
||||
clkdivider #(g_COUNT_WIDTH) slow_clk_divider // Divide 50 MHz to <400 KHz (Initial clock)
|
||||
(.i_COUNT_IN_MAX(i_COUNT_IN_MAX),
|
||||
.i_EN(w_SD_CLK_SELECTED),
|
||||
//.i_EN(1'b1),
|
||||
//.i_RST(w_HS_TO_INIT_CLK_DIVIDER_RST),
|
||||
.i_RST(a_RST),
|
||||
.i_CLK(CLK),
|
||||
.o_CLK(r_CLK_SD));
|
||||
|
||||
clockgater sd_clk_gater // Select which clock goes to components
|
||||
(.CLK(r_CLK_SD),
|
||||
.E(w_G_CLK_SD_EN | a_RST),
|
||||
.SE(1'b0),
|
||||
.ECLK(r_G_CLK_SD));
|
||||
|
||||
clockgater to_sd_clk_gater // Enable activity on the SD_CLK line
|
||||
(.CLK(r_G_CLK_SD),
|
||||
.E(w_SD_CLK_EN),
|
||||
.SE(1'b0),
|
||||
.ECLK(r_TO_SD_CLK));
|
||||
|
||||
flopenr #(16) RCA_register_CE
|
||||
(.clk(r_G_CLK_SD),
|
||||
.en(w_RCA_REGISTER_EN),
|
||||
.d(w_RCA_D_Q),
|
||||
.q(r_RCA_Q2),
|
||||
.reset(w_RCA_REGISTER_RST));
|
||||
|
||||
// ACMD_Detector
|
||||
flopenr #(1) index_history_fd_2to1
|
||||
(.clk(r_G_CLK_SD),
|
||||
.reset(w_CMD_TX_IS_CMD55_RST),
|
||||
.en(w_CMD_TX_IS_CMD55_EN),
|
||||
.d(r_command_index_is_55_history[2]),
|
||||
.q(r_command_index_is_55_history[1]));
|
||||
|
||||
flopenr #(1) index_history_fd_1to0
|
||||
(.clk(r_G_CLK_SD),
|
||||
.reset(w_CMD_TX_IS_CMD55_RST),
|
||||
.en(w_CMD_TX_IS_CMD55_EN),
|
||||
.d(r_command_index_is_55_history[1]),
|
||||
.q(r_command_index_is_55_history[0]));
|
||||
|
||||
|
||||
|
||||
assign r_command_index_is_55_history[2] = (w_command_index == 55);
|
||||
|
||||
|
||||
assign r_previous_command_index_was_55_q = r_command_index_is_55_history[0];
|
||||
assign r_ACMD_Q = r_previous_command_index_was_55_q; // if the previous command WAS 55, the current command is ACMD
|
||||
|
||||
assign o_SD_CLK = r_TO_SD_CLK;
|
||||
|
||||
|
||||
|
||||
// Multiplexers
|
||||
//Fetch index and argument of command
|
||||
assign w_command_content = (r_IC_OUT == 0) ? ({c_Go_Idle_State, 32'h00000000}) : // CMD0
|
||||
(r_IC_OUT == 1) ? ({c_Send_IF_State, 32'h000001FF}) : // CMD8
|
||||
(r_IC_OUT == 2) ? ({c_App_Command, 32'h00000000}) : // CMD55
|
||||
(r_IC_OUT == 3) ? ({c_SD_Send_OCR, 32'h40FF8000}) : // ACMD41
|
||||
(r_IC_OUT == 4) ? ({c_All_Send_CID, 32'h00000000}) : // CMD2
|
||||
(r_IC_OUT == 5) ? ({c_SD_Send_RCA, 32'h00000000}) : // CMD3
|
||||
(r_IC_OUT == 6) ? ({c_Select_Card, r_RCA_Q2[15:0], 16'h0000}) : // CMD7
|
||||
(r_IC_OUT == 7) ? ({c_App_Command, r_RCA_Q2[15:0], 16'h0000}) : // CMD55
|
||||
(r_IC_OUT == 8) ? ({c_Set_Bus_Width, 32'h00000002}) : // ACMD6
|
||||
(r_IC_OUT == 9) ? ({c_Switch_Function, 32'h80FFFFF1}) : // CMD6
|
||||
(r_IC_OUT == 10) ? ({c_Read_Single_Block, w_BLOCK_ADDR}) : // CMD17
|
||||
({c_Read_Single_Block, w_BLOCK_ADDR}); // when in doubt just send CMD17
|
||||
|
||||
assign w_command_index = w_command_content[45:40];
|
||||
assign w_command_arguments = w_command_content[39:8];
|
||||
assign w_command_head = {c_start_bit, c_tx_host_command, w_command_content};
|
||||
|
||||
assign w_OPCODE_Q = {r_ACMD_Q, w_command_index};
|
||||
|
||||
// TX
|
||||
|
||||
crc7_pipo tx_crc7_pipo
|
||||
(.CLK(r_G_CLK_SD),
|
||||
.i_DATA(w_command_head),
|
||||
.i_CRC_ENABLE(w_TX_CRC7_PIPO_EN),
|
||||
.RST(w_TX_CRC7_PIPO_RST),
|
||||
.o_CRC(r_TX_CRC7));
|
||||
|
||||
assign r_command_tail = {r_TX_CRC7, c_stop_bit};
|
||||
|
||||
piso_generic_ce #(40) tx_piso40_command_head
|
||||
(.clk(r_G_CLK_SD),
|
||||
.i_load(w_TX_PISO40_LOAD),
|
||||
.i_data(w_command_head),
|
||||
.i_en(w_TX_PISO40_EN),
|
||||
.o_data(w_tx_head_Q));
|
||||
|
||||
piso_generic_ce #(8) tx_piso8_command_tail
|
||||
(.clk(r_G_CLK_SD),
|
||||
.i_load(w_TX_PISO8_LOAD),
|
||||
.i_data(r_command_tail),
|
||||
.i_en(w_TX_PISO8_EN),
|
||||
.o_data(w_tx_tail_Q));
|
||||
|
||||
assign w_SD_CMD_TX_Q = (w_TX_SOURCE_SELECT == c_tx_low) ? 1'b0 :
|
||||
(w_TX_SOURCE_SELECT == c_tx_high) ? 1'b1 :
|
||||
(w_TX_SOURCE_SELECT == c_tx_head) ? w_tx_head_Q :
|
||||
(w_TX_SOURCE_SELECT == c_tx_tail) ? w_tx_tail_Q :
|
||||
1'b0;
|
||||
|
||||
assign w_SD_CMD_RX = i_SD_CMD;
|
||||
|
||||
flopenr #(1) sd_cmd_out_reg
|
||||
(.d(w_SD_CMD_TX_Q),
|
||||
.q(o_SD_CMD),
|
||||
.en(1'b1),
|
||||
.clk(~r_G_CLK_SD),
|
||||
.reset(a_RST));
|
||||
|
||||
flopenr #(1) sd_cmd_out_oe_reg
|
||||
(.d(w_SD_CMD_OE),
|
||||
.q(o_SD_CMD_OE),
|
||||
.en(1'b1),
|
||||
.clk(~r_G_CLK_SD),
|
||||
.reset(a_RST));
|
||||
|
||||
// RX
|
||||
sipo_generic_ce #(48) rx_sipo48_response_content
|
||||
(.clk(r_G_CLK_SD),
|
||||
.rst(w_RX_SIPO48_RST),
|
||||
.i_enable(w_RX_SIPO48_EN),
|
||||
.i_message_bit(w_SD_CMD_RX),
|
||||
.o_data(r_RX_RESPONSE));
|
||||
|
||||
assign r_RESPONSE_CONTENT = r_RX_RESPONSE[39:8];
|
||||
assign r_RESPONSE_INDEX = r_RX_RESPONSE[45:40];
|
||||
assign w_RCA_D_Q = r_RESPONSE_CONTENT[39:24];
|
||||
|
||||
crc7_sipo_np_ce rx_crc7_sipo
|
||||
(.clk(r_G_CLK_SD),
|
||||
.rst(w_RX_CRC7_SIPO_RST),
|
||||
.i_enable(w_RX_CRC7_SIPO_EN),
|
||||
.i_message_bit(w_SD_CMD_RX),
|
||||
.o_crc7(r_RX_CRC7_Q));
|
||||
|
||||
// Fetch control bits using r_opcode
|
||||
assign w_instruction_control_bits = (w_OPCODE_Q == ({c_CMD, c_Go_Idle_State})) ? ({c_response_type_R0_NONE, c_DAT_none, c_CMD0_mask_check_redo_bits, c_CMD0_ans_dont_redo, c_CMD0_mask_check_error_bits, c_CMD0_ans_error_free}) : // CMD0
|
||||
|
||||
(w_OPCODE_Q == ({c_CMD, c_All_Send_CID})) ? ({c_response_type_R2_CID_CSD, c_DAT_none, c_CMD2_mask_check_redo_bits, c_CMD2_ans_dont_redo, c_CMD2_mask_check_error_bits, c_CMD2_ans_error_free}): // CMD2
|
||||
|
||||
(w_OPCODE_Q == ({c_CMD, c_SD_Send_RCA})) ? ({c_response_type_R6_RCA, c_DAT_none, c_CMD3_mask_check_redo_bits, c_CMD3_ans_dont_redo, c_CMD3_mask_check_error_bits, c_CMD3_ans_error_free}) : // CMD3
|
||||
|
||||
(w_OPCODE_Q == ({c_CMD, c_Switch_Function})) ? ({c_response_type_R1_NORMAL, c_DAT_wide, c_CMD6_mask_check_redo_bits, c_CMD6_ans_dont_redo, c_CMD6_mask_check_error_bits, c_CMD6_ans_error_free}): // CMD6
|
||||
|
||||
(w_OPCODE_Q == ({c_ACMD, c_Set_Bus_Width})) ? ({c_response_type_R1_NORMAL, c_DAT_none, c_ACMD6_mask_check_redo_bits, c_ACMD6_ans_dont_redo, c_ACMD6_mask_check_error_bits, c_ACMD6_ans_error_free}): //ACMD6
|
||||
|
||||
(w_OPCODE_Q == ({c_CMD, c_Select_Card})) ? ({c_response_type_R1_NORMAL, c_DAT_busy, c_CMD7_mask_check_redo_bits, c_CMD7_ans_dont_redo, c_CMD7_mask_check_error_bits, c_CMD7_ans_error_free}): // CMD7
|
||||
|
||||
(w_OPCODE_Q == ({c_CMD, c_Send_IF_State})) ? ({c_response_type_R7_CIC, c_DAT_none, c_CMD8_mask_check_redo_bits, c_CMD8_ans_dont_redo, c_CMD8_mask_check_error_bits, c_CMD8_ans_error_free}): // CMD8
|
||||
|
||||
(w_OPCODE_Q == ({c_CMD, c_Read_Single_Block})) ? ({c_response_type_R1_NORMAL, c_DAT_block, c_CMD17_mask_check_redo_bits, c_CMD17_ans_dont_redo, c_CMD17_mask_check_error_bits, c_CMD17_ans_error_free}): // CMD17
|
||||
|
||||
(w_OPCODE_Q == ({c_ACMD, c_SD_Send_OCR})) ? ({c_response_type_R3_OCR, c_DAT_none, c_ACMD41_mask_check_redo_bits, c_ACMD41_ans_dont_redo, c_ACMD41_mask_check_error_bits, c_ACMD41_ans_error_free}) : //ACMD41
|
||||
|
||||
(w_OPCODE_Q == ({c_CMD, c_App_Command})) ? ({c_response_type_R1_NORMAL, c_DAT_none, c_CMD55_mask_check_redo_bits, c_CMD55_ans_dont_redo, c_CMD55_mask_check_error_bits, c_CMD55_ans_error_free}) : // CMD55
|
||||
|
||||
(w_OPCODE_Q == ({c_ACMD, c_App_Command})) ? ({c_response_type_R1_NORMAL, c_DAT_none, c_ACMD55_mask_check_redo_bits, c_ACMD55_ans_dont_redo, c_ACMD55_mask_check_error_bits, c_ACMD55_ans_error_free}) : //ACMD55
|
||||
|
||||
({c_response_type_R1_NORMAL, c_DAT_none, c_ACMD55_mask_check_redo_bits, c_ACMD55_ans_dont_redo, c_ACMD55_mask_check_error_bits, c_ACMD55_ans_error_free}); // when in doubt just send ACMD55
|
||||
|
||||
assign w_R_TYPE = w_instruction_control_bits[132:130];
|
||||
assign w_USES_DAT = w_instruction_control_bits[129:128];
|
||||
assign w_NO_REDO_MASK = w_instruction_control_bits[127:96];
|
||||
assign w_NO_REDO_ANS = w_instruction_control_bits[95:64];
|
||||
assign w_NO_ERROR_MASK = w_instruction_control_bits[63:32];
|
||||
assign w_NO_ERROR_ANS = w_instruction_control_bits[31:0];
|
||||
|
||||
|
||||
endmodule
|
||||
|
@ -1,98 +0,0 @@
|
||||
|
||||
///////////////////////////////////////////
|
||||
// sd_top_wrapper.sv
|
||||
//
|
||||
// Written: Richard Davis
|
||||
// Modified: Ross Thompson September 19, 2021
|
||||
//
|
||||
// Purpose: SD card controller wrapper
|
||||
//
|
||||
// A component of the CORE-V-WALLY configurable RISC-V project.
|
||||
//
|
||||
/// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
||||
//
|
||||
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
|
||||
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
|
||||
// may obtain a copy of the License at
|
||||
//
|
||||
// https://solderpad.org/licenses/SHL-2.1/
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, any work distributed under the
|
||||
// License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
module sd_top_wrapper #(parameter g_COUNT_WIDTH = 8) (
|
||||
input logic clk_in1_p,
|
||||
input logic clk_in1_n,
|
||||
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
|
||||
inout SD_CMD, // CMD Response from card
|
||||
input logic [3:0] i_SD_DAT, // SD DAT Bus
|
||||
output logic o_SD_CLK, // SD CLK Bus
|
||||
// For communication with core cpu
|
||||
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
|
||||
);
|
||||
|
||||
wire CLK;
|
||||
wire LIMIT_SD_TIMERS;
|
||||
wire [g_COUNT_WIDTH-1:0] i_COUNT_IN_MAX;
|
||||
wire [4095:0] ReadData; // full 512 bytes to Bus
|
||||
wire [32:9] i_BLOCK_ADDR; // see "Addressing" in parts.fods (only 8GB total capacity is used)
|
||||
wire o_SD_CMD; // CMD Command from host
|
||||
wire i_SD_CMD; // CMD Command from host
|
||||
wire o_SD_CMD_OE; // Direction of SD_CMD
|
||||
wire [2:0] o_ERROR_CODE_Q; // indicates which error occured
|
||||
wire o_FATAL_ERROR; // indicates that the FATAL ERROR register has updated
|
||||
wire o_LAST_NIBBLE; // pulse when last nibble is sent
|
||||
|
||||
assign LIMIT_SD_TIMERS = 1'b0;
|
||||
assign i_COUNT_IN_MAX = -8'd62;
|
||||
assign i_BLOCK_ADDR = 23'h0;
|
||||
|
||||
clk_wiz_0 clk_wiz_0(.clk_in1_p(clk_in1_p),
|
||||
.clk_in1_n(clk_in1_n),
|
||||
.reset(1'b0),
|
||||
.clk_out1(CLK),
|
||||
.locked(locked));
|
||||
|
||||
IOBUF SDCMDIODriver(.T(~o_SD_CMD_OE),
|
||||
.I(o_SD_CMD),
|
||||
.O(i_SD_CMD),
|
||||
.IO(SD_CMD));
|
||||
|
||||
|
||||
sd_top #(g_COUNT_WIDTH)
|
||||
sd_top(.CLK(CLK),
|
||||
.a_RST(a_RST),
|
||||
.i_SD_CMD(i_SD_CMD), // CMD Response from card
|
||||
.o_SD_CMD(o_SD_CMD), // CMD Command from host
|
||||
.o_SD_CMD_OE(o_SD_CMD_OE), // Direction of SD_CMD
|
||||
.i_SD_DAT(i_SD_DAT), // SD DAT Bus
|
||||
.o_SD_CLK(o_SD_CLK), // SD CLK Bus
|
||||
.i_BLOCK_ADDR(i_BLOCK_ADDR), // see "Addressing" in parts.fods (only 8GB total capacity is used)
|
||||
.o_READY_FOR_READ(o_READY_FOR_READ), // tells core that initialization sequence is completed and
|
||||
.o_SD_RESTARTING(o_SD_RESTARTING), // inform core the need to restart
|
||||
.i_READ_REQUEST(i_READ_REQUEST), // After Ready for read is sent to the core, the core will
|
||||
.o_DATA_TO_CORE(o_DATA_TO_CORE), // nibble being sent to core when DATA block is
|
||||
.ReadData(ReadData), // full 512 bytes to Bus
|
||||
.o_DATA_VALID(o_DATA_VALID), // held high while data being read to core to indicate that it is valid
|
||||
.o_LAST_NIBBLE(o_LAST_NIBBLE), // pulse when last nibble is sent
|
||||
.o_ERROR_CODE_Q(o_ERROR_CODE_Q), // indicates which error occured
|
||||
.o_FATAL_ERROR(o_FATAL_ERROR), // indicates that the FATAL ERROR register has updated
|
||||
.i_COUNT_IN_MAX(i_COUNT_IN_MAX),
|
||||
.LIMIT_SD_TIMERS(LIMIT_SD_TIMERS)
|
||||
);
|
||||
|
||||
endmodule
|
@ -1,54 +0,0 @@
|
||||
///////////////////////////////////////////
|
||||
// simple_timer.sv
|
||||
//
|
||||
// Written: Ross Thompson September 20, 2021
|
||||
// Modified:
|
||||
//
|
||||
// Purpose: SD card controller
|
||||
//
|
||||
// A component of the CORE-V-WALLY configurable RISC-V project.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
||||
//
|
||||
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
|
||||
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
|
||||
// may obtain a copy of the License at
|
||||
//
|
||||
// https://solderpad.org/licenses/SHL-2.1/
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, any work distributed under the
|
||||
// License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
`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 [BUS_WIDTH-1:0] 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
|
||||
|
@ -1,51 +0,0 @@
|
||||
///////////////////////////////////////////
|
||||
// sipo_generic_ce
|
||||
//
|
||||
// Written: Richard Davis
|
||||
// Modified: Ross Thompson September 20, 2021
|
||||
//
|
||||
// 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 CORE-V-WALLY configurable RISC-V project.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
||||
//
|
||||
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
|
||||
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
|
||||
// may obtain a copy of the License at
|
||||
//
|
||||
// https://solderpad.org/licenses/SHL-2.1/
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, any work distributed under the
|
||||
// License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
`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
|
@ -1,45 +0,0 @@
|
||||
///////////////////////////////////////////
|
||||
// counter.sv
|
||||
//
|
||||
// Written: Ross Thompson
|
||||
// Modified:
|
||||
//
|
||||
// Purpose: basic up counter
|
||||
//
|
||||
// A component of the CORE-V-WALLY configurable RISC-V project.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
||||
//
|
||||
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
|
||||
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
|
||||
// may obtain a copy of the License at
|
||||
//
|
||||
// https://solderpad.org/licenses/SHL-2.1/
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, any work distributed under the
|
||||
// License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
`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] CountP1;
|
||||
|
||||
assign CountP1 = UpDown ? CountOut + 1'b1 : CountOut - 1'b1;
|
||||
assign NextCount = Load ? CountIn : CountP1;
|
||||
flopenr #(WIDTH) reg1(clk, reset, Enable | Load, NextCount, CountOut);
|
||||
endmodule
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user