URL
https://opencores.org/ocsvn/sdspi/sdspi/trunk
Subversion Repositories sdspi
Compare Revisions
- This comparison shows the changes necessary to convert path
/sdspi
- from Rev 2 to Rev 3
- ↔ Reverse comparison
Rev 2 → Rev 3
/trunk/README.md
0,0 → 1,45
# SD-Card controller, using a shared SPI interface |
|
This Verilog core exports an SD card controller interface from internal to an |
FPGA to the rest of the FPGA core, while taking care of the lower level details |
internal to the interface. Unlike the [other OpenCores SD Card controller](http://www.opencores.org/project,sdcard_mass_storage_controller) which offers a full SD interface, this controller focuses on the SPI interface of the SD Card. |
While this is a slower interface, the SPI interface is |
necessary to access the card when using a [XuLA2 board](http://www.xess.com/shop/product/xula2-lx25/), or |
in general any time the full 9--bit, bi--directional interface to the SD card |
has not been implemented. |
Further, for those who are die--hard Verilog authors, this core is written in |
Verilog as opposed to the [XESS provided demonstration SD Card controller |
found on GitHub](https://github.com/xesscorp/VHDL\_Lib/SDCard.vhd), which was |
written |
in VHDL. For those who are not such die--hard Verilog authors, this controller |
provides a lower level interface to the card than these other controllers. |
Whereas the XESS controller will automatically start up the card and interact |
with it, this controller requires external software to be used when interacting |
with the card. This makes this SDSPI controller both more versatile, in the |
face of potential changes to the card interface, but also less turn-key. |
|
While this core was written for the purpose of being used with the [ZipCPU](https://github.com/ZipCPU/zipcpu), |
as enhanced by the Wishbone DMA controller used by the ZipCPU, nothing in this |
core prevents it from being used with any other architecture that supports |
the 32-bit Wishbone interface of this core. |
|
This core has been written as a wishbone slave, not a master. Using the core |
together with a separate master, such as a CPU or a DMA controller, only makes |
sense. This design choice, however, also restricts the core from being able to |
use the multiple block write or multiple block read commands, restricting us to |
single block read and write commands alone. |
|
For more information, please consult the specification document. |
|
# Next Steps |
|
Now that I have an initial SD Card controller working over the SPI port, I've |
kind of fallen in love with the simple interface it uses. I'm wondering if I |
can use the same control interface for the full SD protocol. To that end, I |
intend to build a version of this controller that works with the full SD |
protocol--even integrating a card detect bit into the control register. |
|
# Commercial Applications |
|
Should you find the GPLv3 license insufficient for your needs, other licenses |
can be purchased from Gisselquist Technology, LLC. |
/trunk/bench/cpp/sdspisim.cpp
1,6 → 1,5
/////////////////////////////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
// Filename: sdspisim.cpp |
// |
// Project: Wishbone Controlled SD-Card Controller over SPI port |
11,12 → 10,12
// This simulator is for testing use in a Verilator/C++ environment, where |
// it would be used in place of the actual hardware. |
// |
// Creator: Dan Gisselquist |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
/////////////////////////////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, Gisselquist Technology, LLC |
// Copyright (C) 2015-2017, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
29,7 → 28,7
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory, run make with no |
// with this program. (It's in the $(ROOT)/doc directory. Run make with no |
// target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
37,7 → 36,9
// http://www.gnu.org/licenses/gpl.html |
// |
// |
/////////////////////////////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
#include <stdio.h> |
#include <string.h> |
#include <assert.h> |
69,7 → 70,7
static const unsigned |
CCS = 1; // 0: SDSC card, 1: SDHC or SDXC card |
|
SDSPISIM::SDSPISIM(void) { |
SDSPISIM::SDSPISIM(const bool debug) { |
m_dev = NULL; |
m_last_sck = 1; |
m_block_address = (CCS==1); |
120,6 → 121,7
// |
m_reading_data = false; |
m_have_token = false; |
m_debug = debug; |
} |
|
void SDSPISIM::load(const char *fname) { |
133,7 → 135,7
|
m_devblocks = devln>>9; |
|
printf("SDCARD: NBLOCKS = %ld\n", m_devblocks); |
if (m_debug) printf("SDCARD: NBLOCKS = %ld\n", m_devblocks); |
} |
} |
|
181,7 → 183,7
// Only change our output on the falling edge |
|
m_last_sck = sck; |
printf("SDSPI: (%3d) [%d,%d,%d] ", m_delay, csn, sck, m_mosi); |
if (m_debug) printf("SDSPI: (%3d) [%d,%d,%d] ", m_delay, csn, sck, m_mosi); |
// assert(m_delay > 20); |
|
m_bitpos++; |
188,15 → 190,15
m_dat_in = (m_dat_in<<1)|m_mosi; |
|
|
printf("(bitpos=%d,dat_in=%02x)\n", m_bitpos&7, m_dat_in&0x0ff); |
if (m_debug) printf("(bitpos=%d,dat_in=%02x)\n", m_bitpos&7, m_dat_in&0x0ff); |
|
if ((m_bitpos&7)==0) { |
printf("SDSPI--RX BYTE %02x\n", m_dat_in&0x0ff); |
if (m_debug) printf("SDSPI--RX BYTE %02x\n", m_dat_in&0x0ff); |
m_dat_out = 0xff; |
if (m_reading_data) { |
if (m_have_token) { |
m_block_buf[m_rxloc++] = m_dat_in; |
printf("SDSPI: WR[%3d] = %02x\n", m_rxloc-1, |
if (m_debug) printf("SDSPI: WR[%3d] = %02x\n", m_rxloc-1, |
m_dat_in&0x0ff); |
if (m_rxloc >= 512+2) { |
unsigned crc, rxcrc; |
204,8 → 206,8
rxcrc = ((m_block_buf[512]&0x0ff)<<8) |
|(m_block_buf[513]&0x0ff); |
|
printf("LEN = %d\n", m_rxloc); |
printf("CHECKING CRC: (rx) %04x =? %04x (calc)\n", |
if (m_debug) printf("LEN = %d\n", m_rxloc); |
if (m_debug) printf("CHECKING CRC: (rx) %04x =? %04x (calc)\n", |
crc, rxcrc); |
m_reading_data = false; |
m_have_token = false; |
218,13 → 220,14
} |
} else { |
if ((m_dat_in&0x0ff) == 0x0fe) { |
printf("SDSPI: TOKEN!!\n"); |
if (m_debug) printf("SDSPI: TOKEN!!\n"); |
m_have_token = true; |
m_rxloc = 0; |
} else printf("SDSPI: waiting on token\n"); |
} else if (m_debug) |
printf("SDSPI: waiting on token\n"); |
} |
} else if (m_cmdidx < 6) { |
printf("SDSPI: CMDIDX = %d\n", m_cmdidx); |
if (m_debug) printf("SDSPI: CMDIDX = %d\n", m_cmdidx); |
// All commands *must* start with a 01... pair of bits. |
if (m_cmdidx == 0) |
assert((m_dat_in&0xc0)==0x40); |
236,10 → 239,12
m_rspidx = 0; |
m_blkdly = 0; |
m_blkidx = SDSPI_MAXBLKLEN; |
printf("SDSPI: CMDIDX = %d -- WE HAVE A COMMAND! [ ", m_cmdidx); |
for(int i=0; i<6; i++) |
printf("%02x ", m_cmdbuf[i] & 0xff); |
printf("]\n"); fflush(stdout); |
if (m_debug) { |
printf("SDSPI: CMDIDX = %d -- WE HAVE A COMMAND! [ ", m_cmdidx); |
for(int i=0; i<6; i++) |
printf("%02x ", m_cmdbuf[i] & 0xff); |
printf("]\n"); fflush(stdout); |
} |
|
unsigned arg; |
arg = ((((((m_cmdbuf[1]<<8)|(m_cmdbuf[2]&0x0ff))<<8) |
292,7 → 297,7
} else { |
m_altcmd_flag = false; |
memset(m_rspbuf, 0x0ff, SDSPI_RSPLEN); |
printf("SDSPI: Received a command 0x%02x (%d)\n", |
if (m_debug) printf("SDSPI: Received a command 0x%02x (%d)\n", |
m_cmdbuf[0], m_cmdbuf[0]&0x03f); |
switch(m_cmdbuf[0]&0x3f) { |
case 0: // CMD0 -- GO_IDLE_STATE |
367,7 → 372,7
m_rspbuf[0] = 0x00; |
memset(m_block_buf, 0x0ff, SDSPI_MAXBLKLEN); |
if (m_dev) { |
printf("Reading from block %08x of %08lx\n", arg, m_devblocks); |
if (m_debug) printf("Reading from block %08x of %08lx\n", arg, m_devblocks); |
if (m_block_address) { |
assert(arg < m_devblocks); |
fseek(m_dev, arg<<9, SEEK_SET); |
378,9 → 383,10
} m_block_buf[0] = 0x0fe; |
m_blklen = 512; // (1<<m_csd[5]); |
if (m_dev) |
fread(&m_block_buf[1], m_blklen, 1, m_dev); |
m_blklen = fread(&m_block_buf[1], m_blklen, 1, m_dev); |
else |
memset(&m_block_buf[1], 0, m_blklen); |
m_blklen = (m_blklen != 512) ? 512 : m_blklen; |
add_block_crc(m_blklen, m_block_buf); |
|
m_blkdly = 60; |
423,7 → 429,7
default: // Unimplemented command |
m_rspbuf[0] = 0x04; |
m_rspdly = 4; |
printf("SDSPI ERR: Command CMD%d not implemented!\n", m_cmdbuf[0]&0x03f); |
if (m_debug) printf("SDSPI ERR: Command CMD%d not implemented!\n", m_cmdbuf[0]&0x03f); |
fflush(stdout); |
assert(0 && "Not Implemented"); |
} |
478,7 → 484,7
|
bool SDSPISIM::check_cmdcrc(char *buf) const { |
unsigned fill = cmdcrc(5, buf); |
printf("SDSPI: CRC-CHECK, should have a CRC of %02x\n", fill); |
if (m_debug) printf("SDSPI: CRC-CHECK, should have a CRC of %02x\n", fill); |
return (fill == (buf[5]&0x0ff)); |
} |
|
/trunk/bench/cpp/sdspisim.h
15,7 → 15,7
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, Gisselquist Technology, LLC |
// Copyright (C) 2015-2017, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
28,7 → 28,7
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory, run make with no |
// with this program. (It's in the $(ROOT)/doc directory. Run make with no |
// target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
75,7 → 75,7
char m_csd[SDSPI_CSDLEN], m_cid[SDSPI_CIDLEN]; |
|
public: |
SDSPISIM(void); |
SDSPISIM(const bool debug = false); |
void load(const char *fname); |
void debug(const bool dbg) { m_debug = dbg; } |
bool debug(void) const { return m_debug; } |
/trunk/doc/Makefile
1,3 → 1,48
################################################################################ |
## |
## Filename: Makefile |
## |
## Project: SD-Card controller, using a shared SPI interface |
## |
## Purpose: To coordinate the build of documentation PDFs from their |
## LaTeX sources. |
## |
## Targets include: |
## all Builds all documents |
## gpl-3.0.pdf Builds the GPL license these files are released |
## under. |
## spec.pdf Builds the specification for the SDSPI |
## controller. |
## |
## Creator: Dan Gisselquist, Ph.D. |
## Gisselquist Technology, LLC |
## |
################################################################################ |
## |
## Copyright (C) 2016, Gisselquist Technology, LLC |
## |
## This program is free software (firmware): you can redistribute it and/or |
## modify it under the terms of the GNU General Public License as published |
## by the Free Software Foundation, either version 3 of the License, or (at |
## your option) any later version. |
## |
## This program is distributed in the hope that it will be useful, but WITHOUT |
## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
## for more details. |
## |
## You should have received a copy of the GNU General Public License along |
## with this program. (It's in the $(ROOT)/doc directory, run make with no |
## target there if the PDF file isn't present.) If not, see |
## <http://www.gnu.org/licenses/> for a copy. |
## |
## License: GPL, v3, as defined and found on www.gnu.org, |
## http://www.gnu.org/licenses/gpl.html |
## |
## |
################################################################################ |
## |
## |
all: gpl-3.0.pdf spec.pdf |
DSRC := src |
|
/trunk/doc/spec.pdf
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/doc/src/spec.tex
53,7 → 53,7
\project{SDSPI Controller} |
\title{Specification} |
\author{Dan Gisselquist, Ph.D.} |
\email{dgisselq (at) opencores.org} |
\email{dgisselq (at) ieee.org} |
\revision{Rev.~0.1} |
\begin{document} |
\pagestyle{gqtekspecplain} |
335,7 → 335,7
shouldn't be busy anyway), and we then clear any errors: |
\begin{tabbing} |
{\tt SD\_WAIT\_WHILE\_BUSY;} \\ |
{\tt CMD} \= {\tt SD\_CLEARERR}; |
{\tt CMD} \= {\tt = SD\_CLEARERR}; |
\end{tabbing} |
|
Now that the controller is idle (which it should've been from startup anyway), |
458,7 → 458,7
\begin{tabbing} |
{\tt int CSD[4];}\\ |
{\tt DATA} \= {\tt = 0;} \\ |
{\tt CMD} \> {\tt = (SD\_FIFO\_OP|SD\_CMD)+9;} |
{\tt CMD} \> {\tt = (SD\_FIFO\_OP|SD\_CMD)+9;} \\ |
{\tt SD\_WAIT\_WHILE\_BUSY;} \\ |
{\tt for(int i=0; i<4; i++) } \\ |
\> {\tt CSD[i] = FIFO[0];} |
/trunk/rtl/Makefile
1,12 → 1,53
################################################################################ |
## |
## Filename: Makefile |
## |
## Project: SD-Card controller, using a shared SPI interface |
## |
## Purpose: To build the Verilator library necessary for simulating (via |
## verilator) this code. |
## |
## Creator: Dan Gisselquist, Ph.D. |
## Gisselquist Technology, LLC |
## |
################################################################################ |
## |
## Copyright (C) 2016, Gisselquist Technology, LLC |
## |
## This program is free software (firmware): you can redistribute it and/or |
## modify it under the terms of the GNU General Public License as published |
## by the Free Software Foundation, either version 3 of the License, or (at |
## your option) any later version. |
## |
## This program is distributed in the hope that it will be useful, but WITHOUT |
## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
## for more details. |
## |
## You should have received a copy of the GNU General Public License along |
## with this program. (It's in the $(ROOT)/doc directory, run make with no |
## target there if the PDF file isn't present.) If not, see |
## <http://www.gnu.org/licenses/> for a copy. |
## |
## License: GPL, v3, as defined and found on www.gnu.org, |
## http://www.gnu.org/licenses/gpl.html |
## |
## |
################################################################################ |
## |
## |
|
all: rtl export.v |
VERILATOR:= verilator |
# VOB := $(HOME)/src/verilog/vopro |
VOB := cat |
VOBJ:= obj_dir |
VFLAGS := -MMD -Wall -trace -cc |
|
.PHONY: rtl |
rtl: $(VOBJ)/Vsdspi.h |
$(VOBJ)/Vsdspi.h: sdspi.v llsdspi.v |
verilator -cc sdspi.v |
$(VERILATOR) $(VFLAGS) sdspi.v |
|
export.v: sdspi.v llsdspi.v |
$(VOB) $^ > $@ |
/trunk/rtl/llsdspi.v
87,6 → 87,8
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
`default_nettype none |
// |
`define LLSDSPI_IDLE 4'h0 |
`define LLSDSPI_HOTIDLE 4'h1 |
`define LLSDSPI_WAIT 4'h2 |
97,22 → 99,22
o_stb, o_byte, o_idle, i_bus_grant); |
parameter SPDBITS = 7; |
// |
input i_clk; |
input wire i_clk; |
// Parameters/setup |
input [(SPDBITS-1):0] i_speed; |
input wire [(SPDBITS-1):0] i_speed; |
// The incoming interface |
input i_cs; |
input i_stb; |
input [7:0] i_byte; |
input wire i_cs; |
input wire i_stb; |
input wire [7:0] i_byte; |
// The actual SPI interface |
output reg o_cs_n, o_sclk, o_mosi; |
input i_miso; |
input wire i_miso; |
// The outgoing interface |
output reg o_stb; |
output reg [7:0] o_byte; |
output wire o_idle; |
// And whether or not we actually own the interface (yet) |
input i_bus_grant; |
input wire i_bus_grant; |
|
reg r_z_counter; |
reg [(SPDBITS-1):0] r_clk_counter; |
126,11 → 128,11
initial r_clk_counter = 7'h0; |
always @(posedge i_clk) |
begin |
if ((~i_cs)||(~i_bus_grant)) |
if ((!i_cs)||(!i_bus_grant)) |
r_clk_counter <= 0; |
else if (byte_accepted) |
r_clk_counter <= i_speed; |
else if (~r_z_counter) |
else if (!r_z_counter) |
r_clk_counter <= (r_clk_counter - {{(SPDBITS-1){1'b0}},1'b1}); |
else if ((r_state != `LLSDSPI_IDLE)&&(r_state != `LLSDSPI_HOTIDLE)) |
r_clk_counter <= (i_speed); |
141,11 → 143,11
initial r_z_counter = 1'b1; |
always @(posedge i_clk) |
begin |
if ((~i_cs)||(~i_bus_grant)) |
if ((!i_cs)||(!i_bus_grant)) |
r_z_counter <= 1'b1; |
else if (byte_accepted) |
r_z_counter <= 1'b0; |
else if (~r_z_counter) |
else if (!r_z_counter) |
r_z_counter <= (r_clk_counter == 1); |
else if ((r_state != `LLSDSPI_IDLE)&&(r_state != `LLSDSPI_HOTIDLE)) |
r_z_counter <= 1'b0; |
155,13 → 157,13
always @(posedge i_clk) |
begin |
o_stb <= 1'b0; |
o_cs_n <= ~i_cs; |
if (~i_cs) |
o_cs_n <= !i_cs; |
if (!i_cs) |
begin |
r_state <= `LLSDSPI_IDLE; |
r_idle <= 1'b0; |
o_sclk <= 1'b1; |
end else if (~r_z_counter) |
end else if (!r_z_counter) |
begin |
r_idle <= 1'b0; |
if (byte_accepted) |
/trunk/rtl/sdspi.v
11,7 → 11,7
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2016, Gisselquist Technology, LLC |
// Copyright (C) 2016-2017, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
24,7 → 24,7
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory, run make with no |
// with this program. (It's in the $(ROOT)/doc directory. Run make with no |
// target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
35,6 → 35,8
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
`default_nettype none |
// |
`define SDSPI_CMD_ADDRESS 2'h0 |
`define SDSPI_DAT_ADDRESS 2'h1 |
`define SDSPI_FIFO_A_ADDR 2'h2 |
74,21 → 76,21
// And some wires for debugging it all |
o_debug); |
parameter LGFIFOLN = 7; |
input i_clk; |
input wire i_clk; |
// |
input i_wb_cyc, i_wb_stb, i_wb_we; |
input [1:0] i_wb_addr; |
input [31:0] i_wb_data; |
input wire i_wb_cyc, i_wb_stb, i_wb_we; |
input wire [1:0] i_wb_addr; |
input wire [31:0] i_wb_data; |
output reg o_wb_ack; |
output wire o_wb_stall; |
output reg [31:0] o_wb_data; |
// |
output wire o_cs_n, o_sck, o_mosi; |
input i_miso; |
input wire i_miso; |
// The interrupt |
output reg o_int; |
// .. and whether or not we can use the SPI port |
input i_bus_grant; |
input wire i_bus_grant; |
// |
output wire [31:0] o_debug; |
|
96,14 → 98,51
// Some WB simplifications: |
// |
reg r_cmd_busy; |
|
wire wb_stb, write_stb, cmd_stb, new_data, new_cmd; |
wire [1:0] wb_addr; |
wire [31:0] wb_data; |
`ifdef WB_CLOCK |
wire wb_stb, write_stb, cmd_stb; // read_stb |
assign wb_stb = ((i_wb_cyc)&&(i_wb_stb)&&(~o_wb_stall)); |
assign wb_stb = ((i_wb_stb)&&(!o_wb_stall)); |
assign write_stb = ((wb_stb)&&( i_wb_we)); |
// assign read_stb = ((wb_stb)&&(~i_wb_we)); |
assign cmd_stb = (~r_cmd_busy)&&(write_stb) |
// assign read_stb = ((wb_stb)&&(!i_wb_we)); |
assign cmd_stb = (!r_cmd_busy)&&(write_stb) |
&&(i_wb_addr==`SDSPI_CMD_ADDRESS); |
assign wb_addr = i_wb_addr; |
assign wb_data = i_wb_data; |
assign new_cmd = cmd_stb; |
assign new_data = (i_wb_stb)&&(!o_wb_stall)&&(i_wb_we) |
&&(i_wb_addr == `SDSPI_DAT_ADDRESS); |
`else |
reg r_wb_stb, r_write_stb, r_cmd_stb, r_new_data; |
reg [1:0] r_wb_addr; |
reg [31:0] r_wb_data; |
always @(posedge i_clk) |
r_wb_stb <= ((i_wb_stb)&&(!o_wb_stall)); |
always @(posedge i_clk) |
r_write_stb <= ((i_wb_stb)&&(!o_wb_stall)&&(i_wb_we)); |
always @(posedge i_clk) |
r_cmd_stb <= (!r_cmd_busy)&&(i_wb_stb)&&(!o_wb_stall)&&(i_wb_we) |
&&(i_wb_addr == `SDSPI_CMD_ADDRESS); |
always @(posedge i_clk) |
r_new_data <= (i_wb_stb)&&(!o_wb_stall)&&(i_wb_we) |
&&(i_wb_addr == `SDSPI_DAT_ADDRESS); |
always @(posedge i_clk) |
r_wb_addr <= i_wb_addr; |
always @(posedge i_clk) |
r_wb_data <= i_wb_data; |
|
assign wb_stb = r_wb_stb; |
assign write_stb= r_write_stb; |
assign cmd_stb = r_cmd_stb; |
assign new_cmd = r_cmd_stb; |
assign new_data = r_new_data; |
assign wb_addr = r_wb_addr; |
assign wb_data = r_wb_data; |
`endif |
|
|
// |
// Access to our lower-level SDSPI driver, the one that actually |
// uses/sets the SPI ports |
130,7 → 169,10
r_fifo_id, |
ll_fifo_wr, ll_fifo_rd, |
r_have_data_response_token, |
r_have_start_token; |
r_have_start_token, |
r_err_token; |
reg [3:0] r_read_err_token; |
reg [1:0] r_data_response_token; |
reg [7:0] fifo_byte; |
reg [7:0] r_last_r_one; |
// |
145,11 → 187,15
// |
reg q_busy; |
// |
reg [7:0] fifo_a_mem[((1<<(LGFIFOLN+2))-1):0]; |
reg [7:0] fifo_b_mem[((1<<(LGFIFOLN+2))-1):0]; |
reg [7:0] fifo_a_mem_0[0:((1<<LGFIFOLN)-1)], |
fifo_a_mem_1[0:((1<<LGFIFOLN)-1)], |
fifo_a_mem_2[0:((1<<LGFIFOLN)-1)], |
fifo_a_mem_3[0:((1<<LGFIFOLN)-1)], |
fifo_b_mem_0[0:((1<<LGFIFOLN)-1)], |
fifo_b_mem_1[0:((1<<LGFIFOLN)-1)], |
fifo_b_mem_2[0:((1<<LGFIFOLN)-1)], |
fifo_b_mem_3[0:((1<<LGFIFOLN)-1)]; |
reg [(LGFIFOLN-1):0] fifo_wb_addr; |
reg [(LGFIFOLN+1):0] rd_fifo_sd_addr; |
reg [(LGFIFOLN+1):0] wr_fifo_sd_addr; |
// |
reg [(LGFIFOLN+1):0] ll_fifo_addr; |
// |
176,6 → 222,8
reg r_watchdog_err; |
reg pre_cmd_state; |
|
// Relieve some stress from the WB bus timing |
|
initial r_cmd_busy = 1'b0; |
initial r_data_reg = 32'h00; |
initial r_last_r_one = 8'hff; |
190,7 → 238,7
initial r_cmd_err = 1'b0; |
always @(posedge i_clk) |
begin |
if (~ll_cmd_stb) |
if (!ll_cmd_stb) |
begin |
r_have_resp <= 1'b0; |
ll_fifo_wr <= 1'b0; |
273,9 → 321,9
// are expecting. |
if (pre_rsp_state) |
begin |
if (r_rsp_state == `SDSPI_RSP_NONE) |
begin // Waiting on R1 |
if (~ll_out_dat[7]) |
case(r_rsp_state) |
`SDSPI_RSP_NONE: begin // Waiting on R1 |
if (!ll_out_dat[7]) |
begin |
r_last_r_one <= ll_out_dat; |
if (r_cmd_resp == `SDSPI_EXPECT_R1) |
283,28 → 331,30
r_have_resp <= 1'b1; |
ll_cmd_stb <= (r_use_fifo); |
r_data_reg <= 32'hffffffff; |
ll_fifo_wr<=(r_use_fifo)&&(~r_fifo_wr); |
ll_fifo_wr<=(r_use_fifo)&&(!r_fifo_wr); |
end else if (r_cmd_resp == `SDSPI_EXPECT_R1B) |
begin // Go wait on R1b |
r_data_reg <= 32'hffffffff; |
end // else wait on 32-bit rsp |
end |
end else if (r_rsp_state == `SDSPI_RSP_BSYWAIT) |
begin // Waiting on R1b, have R1 |
end end |
`SDSPI_RSP_BSYWAIT: begin |
// Waiting on R1b, have R1 |
if (nonzero_out) |
r_have_resp <= 1'b1; |
ll_cmd_stb <= (r_use_fifo); |
end else if (r_rsp_state == `SDSPI_RSP_GETWORD) |
begin // Have R1, waiting on all of R2/R3/R7 |
r_data_reg <= { r_data_reg[23:0], ll_out_dat }; |
end |
`SDSPI_RSP_GETWORD: begin |
// Have R1, waiting on all of R2/R3/R7 |
r_data_reg <= { r_data_reg[23:0], |
ll_out_dat }; |
r_data_fil <= r_data_fil+2'b01; |
if (r_data_fil == 2'b11) |
begin |
ll_cmd_stb <= (r_use_fifo); |
// r_rsp_state <= 3'h3; |
end |
end else if (r_rsp_state == `SDSPI_RSP_WAIT_WHILE_BUSY) |
begin // Wait while device is busy writing |
end end |
`SDSPI_RSP_WAIT_WHILE_BUSY: begin |
// Wait while device is busy writing |
// if (nonzero_out) |
// begin |
// r_data_reg[31:8] <= 24'h00; |
311,63 → 361,68
// r_data_reg[7:0] <= ll_out_dat; |
// // r_rsp_state <= 3'h6; |
// end |
; |
end else if (r_rsp_state == `SDSPI_RSP_RDCOMPLETE) |
begin // Block write command has completed |
end |
`SDSPI_RSP_RDCOMPLETE: begin |
// Block write command has completed |
ll_cmd_stb <= 1'b0; |
end else if (r_rsp_state == `SDSPI_RSP_WRITING) |
begin // We are reading from the device into |
end |
`SDSPI_RSP_WRITING: begin |
// We are reading from the device into |
// our FIFO |
if ((ll_fifo_wr_complete) |
// Or ... we receive an error |
||((~r_have_start_token) |
&&(~ll_out_dat[4]) |
&&(ll_out_dat[0]))) |
||(r_read_err_token[0])) |
begin |
ll_fifo_wr <= 1'b0; |
ll_cmd_stb <= 1'b0; |
end |
end |
end end |
// `SDSPI_RSP_GETTOKEN: |
default: begin end |
endcase |
end |
|
if ((r_use_fifo)&&(ll_out_stb)) |
r_data_reg <= { 26'h3ffffff, r_data_response_token, r_read_err_token }; |
|
if (r_watchdog_err) |
ll_cmd_stb <= 1'b0; |
r_cmd_err<= (r_cmd_err)|(fifo_crc_err)|(r_watchdog_err); |
r_cmd_err<= (r_cmd_err)|(fifo_crc_err)|(r_watchdog_err) |
|(r_err_token); |
end else if (r_cmd_busy) |
begin |
r_cmd_busy <= (ll_cmd_stb)||(~ll_idle); |
end else if (cmd_stb) |
r_cmd_busy <= (ll_cmd_stb)||(!ll_idle); |
end else if (new_cmd) |
begin // Command write |
// Clear the error on any write, whether a commanding |
// one or not. -- provided the user requests clearing |
// it (by setting the bit high) |
r_cmd_err <= (r_cmd_err)&&(~i_wb_data[15]); |
r_cmd_err <= (r_cmd_err)&&(!wb_data[15]); |
// In a similar fashion, we can switch fifos even if |
// not in the middle of a command |
r_fifo_id <= i_wb_data[12]; |
r_fifo_id <= wb_data[12]; |
// |
// Doesn't matter what this is set to as long as we |
// aren't busy, so we can set it irrelevantly here. |
ll_cmd_dat <= i_wb_data[7:0]; |
ll_cmd_dat <= wb_data[7:0]; |
// |
// Note that we only issue a write upon receiving a |
// valid command. Such a command is 8 bits, and must |
// start with its high order bits set to zero and one. |
// Hence ... we test for that here. |
if (i_wb_data[7:6] == 2'b01) |
if (wb_data[7:6] == 2'b01) |
begin // Issue a command |
// |
r_cmd_busy <= 1'b1; |
// |
ll_cmd_stb <= 1'b1; |
r_cmd_resp <= i_wb_data[9:8]; |
r_cmd_resp <= wb_data[9:8]; |
// |
r_cmd_crc_stb <= 1'b1; |
// |
r_fifo_wr <= i_wb_data[10]; |
r_use_fifo <= i_wb_data[11]; |
r_fifo_wr <= wb_data[10]; |
r_use_fifo <= wb_data[11]; |
// |
end else if (i_wb_data[7]) |
end else if (wb_data[7]) |
// If, on the other hand, the command was invalid, |
// then it must have been an attempt to read our |
// internal configuration. So we'll place that on |
375,10 → 430,8
r_data_reg <= { 8'h00, |
4'h0, max_lgblklen, |
4'h0, r_lgblklen, 1'b0, r_sdspi_clk }; |
end else if ((write_stb)&&(i_wb_addr == `SDSPI_DAT_ADDRESS)) |
begin // Data write |
r_data_reg <= i_wb_data; |
end |
end else if (new_data) // Data write |
r_data_reg <= wb_data; |
end |
|
always @(posedge i_clk) |
386,14 → 439,14
|
reg ready_for_response_token; |
always @(posedge i_clk) |
if (~r_cmd_busy) |
if (!r_cmd_busy) |
ready_for_response_token <= 1'b0; |
else if (ll_fifo_rd) |
ready_for_response_token <= 1'b1; |
always @(posedge i_clk) |
if (~r_cmd_busy) |
if (!r_cmd_busy) |
r_have_data_response_token <= 1'b0; |
else if ((ll_out_stb)&&(ready_for_response_token)&&(~ll_out_dat[4])) |
else if ((ll_out_stb)&&(ready_for_response_token)&&(!ll_out_dat[4])) |
r_have_data_response_token <= 1'b1; |
|
reg [2:0] second_rsp_state; |
417,11 → 470,11
// Each bit depends upon 8 bits of input |
initial r_rsp_state = 3'h0; |
always @(posedge i_clk) |
if (~r_cmd_sent) |
if (!r_cmd_sent) |
r_rsp_state <= 3'h0; |
else if (pre_rsp_state) |
begin |
if ((r_rsp_state == `SDSPI_RSP_NONE)&&(~ll_out_dat[7])) |
if ((r_rsp_state == `SDSPI_RSP_NONE)&&(!ll_out_dat[7])) |
begin |
r_rsp_state <= second_rsp_state; |
end else if (r_rsp_state == `SDSPI_RSP_BSYWAIT) |
462,7 → 515,7
// with the card. These include the speed of the interface, |
// and the size of the block length to expect as part of a FIFO |
// command. |
if ((cmd_stb)&&(i_wb_data[7:6]==2'b11)&&(~r_data_reg[7]) |
if ((new_cmd)&&(wb_data[7:6]==2'b11)&&(!r_data_reg[7]) |
&&(r_data_reg[15:12]==4'h00)) |
begin |
if (|r_data_reg[6:0]) |
475,10 → 528,10
|
assign need_reset = 1'b0; |
always @(posedge i_clk) |
case(i_wb_addr) |
case(wb_addr) |
`SDSPI_CMD_ADDRESS: |
o_wb_data <= { need_reset, 11'h00, |
3'h0, fifo_crc_err, |
2'h0, r_err_token, fifo_crc_err, |
r_cmd_err, r_cmd_busy, 1'b0, r_fifo_id, |
r_use_fifo, r_fifo_wr, r_cmd_resp, |
r_last_r_one }; |
497,7 → 550,7
always @(posedge i_clk) |
q_busy <= r_cmd_busy; |
always @(posedge i_clk) |
o_int <= (~r_cmd_busy)&&(q_busy); |
o_int <= (!r_cmd_busy)&&(q_busy); |
|
assign o_wb_stall = 1'b0; |
|
507,11 → 560,11
// |
always @(posedge i_clk) |
begin |
if ((write_stb)&&(i_wb_addr == `SDSPI_CMD_ADDRESS)) |
if ((write_stb)&&(wb_addr == `SDSPI_CMD_ADDRESS)) |
begin // Command write |
// Clear the read/write address |
fifo_wb_addr <= {(LGFIFOLN){1'b0}}; |
end else if ((wb_stb)&&(i_wb_addr[1])) |
end else if ((wb_stb)&&(wb_addr[1])) |
begin // On read or write, of either FIFO, |
// we increase our pointer |
fifo_wb_addr <= fifo_wb_addr + 1; |
525,15 → 578,15
always @(posedge i_clk) |
begin |
fifo_a_reg <= { |
fifo_a_mem[{ fifo_wb_addr, 2'b00 }], |
fifo_a_mem[{ fifo_wb_addr, 2'b01 }], |
fifo_a_mem[{ fifo_wb_addr, 2'b10 }], |
fifo_a_mem[{ fifo_wb_addr, 2'b11 }] }; |
fifo_a_mem_0[ fifo_wb_addr ], |
fifo_a_mem_1[ fifo_wb_addr ], |
fifo_a_mem_2[ fifo_wb_addr ], |
fifo_a_mem_3[ fifo_wb_addr ] }; |
fifo_b_reg <= { |
fifo_b_mem[{ fifo_wb_addr, 2'b00 }], |
fifo_b_mem[{ fifo_wb_addr, 2'b01 }], |
fifo_b_mem[{ fifo_wb_addr, 2'b10 }], |
fifo_b_mem[{ fifo_wb_addr, 2'b11 }] }; |
fifo_b_mem_0[ fifo_wb_addr ], |
fifo_b_mem_1[ fifo_wb_addr ], |
fifo_b_mem_2[ fifo_wb_addr ], |
fifo_b_mem_3[ fifo_wb_addr ] }; |
end |
|
// Okay, now ... writing our FIFO ... |
542,25 → 595,50
initial pre_fifo_addr_inc_rd = 1'b0; |
initial pre_fifo_addr_inc_wr = 1'b0; |
always @(posedge i_clk) |
pre_fifo_addr_inc_wr <= ((ll_fifo_wr)&&(ll_out_stb)&&(r_have_start_token)); |
pre_fifo_addr_inc_wr <= ((ll_fifo_wr)&&(ll_out_stb) |
&&(r_have_start_token)); |
always @(posedge i_clk) |
pre_fifo_addr_inc_rd <= ((ll_fifo_rd)&&(ll_cmd_stb)&&(ll_idle));//&&(ll_fifo_pkt_state[2:0]!=3'b000)); |
pre_fifo_addr_inc_rd <= ((ll_fifo_rd)&&(ll_cmd_stb)&&(ll_idle)); |
always @(posedge i_clk) |
begin |
// if ((write_stb)&&(i_wb_addr == `SDSPI_CMD_ADDRESS)&&(i_wb_data[11])) |
// ll_fifo_addr <= {(LGFIFOLN+2){1'b0}}; |
if (~r_cmd_busy) |
if (!r_cmd_busy) |
ll_fifo_addr <= {(LGFIFOLN+2){1'b0}}; |
else if ((pre_fifo_addr_inc_wr)||(pre_fifo_addr_inc_rd)) |
ll_fifo_addr <= ll_fifo_addr + 1; |
end |
|
// Look for that start token |
// |
// Look for that start token. This will be present when reading from |
// the device into the FIFO. |
// |
always @(posedge i_clk) |
if (~r_cmd_busy) |
if (!r_cmd_busy) |
r_have_start_token <= 1'b0; |
else if ((ll_fifo_wr)&&(ll_out_stb)&&(ll_out_dat==8'hfe)) |
r_have_start_token <= 1'b1; |
always @(posedge i_clk) |
if (!r_cmd_busy) |
r_read_err_token <= 4'h0; |
else if ((ll_fifo_wr)&&(ll_out_stb)&&(!r_have_start_token) |
&&(ll_out_dat[7:4]==4'h0)) |
r_read_err_token <= ll_out_dat[3:0]; |
always @(posedge i_clk) // Look for a response to our writing |
if (!r_cmd_busy) |
r_data_response_token <= 2'b00; |
else if ((ready_for_response_token) |
&&(!ll_out_dat[4])&&(ll_out_dat[0])) |
r_data_response_token <= ll_out_dat[3:2]; |
initial r_err_token = 1'b0; |
always @(posedge i_clk) |
if (ll_fifo_rd) |
r_err_token <= (r_err_token)|(r_read_err_token[0]); |
else if (ll_fifo_wr) |
r_err_token <= (r_err_token)| |
((|r_data_response_token)&&(r_data_response_token[1])); |
else if (cmd_stb) |
// Clear the error on any write with the bit high |
r_err_token <= (r_err_token)&&(!i_wb_data[16]) |
&&(!i_wb_data[15]); |
|
reg last_fifo_byte; |
initial last_fifo_byte = 1'b0; |
582,39 → 660,89
clear_fifo_crc; |
always @(posedge i_clk) |
begin |
pre_fifo_a_wr <= (ll_fifo_wr)&&(ll_out_stb)&&(~r_fifo_id)&&(ll_fifo_wr_state == 2'b00); |
pre_fifo_b_wr <= (ll_fifo_wr)&&(ll_out_stb)&&( r_fifo_id)&&(ll_fifo_wr_state == 2'b00); |
fifo_wr_crc_stb <= (ll_fifo_wr)&&(ll_out_stb)&&(ll_fifo_wr_state == 2'b00)&&(r_have_start_token); |
pre_fifo_crc_a<= (ll_fifo_wr)&&(ll_out_stb)&&(ll_fifo_wr_state == 2'b01); |
pre_fifo_crc_b<= (ll_fifo_wr)&&(ll_out_stb)&&(ll_fifo_wr_state == 2'b10); |
clear_fifo_crc <= (cmd_stb)&&(i_wb_data[15]); |
pre_fifo_a_wr <= (ll_fifo_wr)&&(ll_out_stb) |
&&(!r_fifo_id)&&(ll_fifo_wr_state == 2'b00); |
pre_fifo_b_wr <= (ll_fifo_wr)&&(ll_out_stb) |
&&( r_fifo_id)&&(ll_fifo_wr_state == 2'b00); |
fifo_wr_crc_stb <= (ll_fifo_wr)&&(ll_out_stb) |
&&(ll_fifo_wr_state == 2'b00)&&(r_have_start_token); |
pre_fifo_crc_a<= (ll_fifo_wr)&&(ll_out_stb) |
&&(ll_fifo_wr_state == 2'b01); |
pre_fifo_crc_b<= (ll_fifo_wr)&&(ll_out_stb) |
&&(ll_fifo_wr_state == 2'b10); |
clear_fifo_crc <= (new_cmd)&&(wb_data[15]); |
end |
|
reg fifo_a_wr, fifo_b_wr; |
reg [3:0] fifo_a_wr_mask, fifo_b_wr_mask; |
reg [(LGFIFOLN-1):0] fifo_a_wr_addr, fifo_b_wr_addr; |
reg [31:0] fifo_a_wr_data, fifo_b_wr_data; |
|
initial fifo_crc_err = 1'b0; |
always @(posedge i_clk) |
begin // One and only memory write allowed |
if ((write_stb)&&(i_wb_addr[1:0]==2'b10)) |
{fifo_a_mem[{ fifo_wb_addr, 2'b00 }], |
fifo_a_mem[{ fifo_wb_addr, 2'b01 }], |
fifo_a_mem[{ fifo_wb_addr, 2'b10 }], |
fifo_a_mem[{ fifo_wb_addr, 2'b11 }] } |
<= i_wb_data; |
else if (pre_fifo_a_wr) |
fifo_a_mem[{ ll_fifo_addr }] <= ll_out_dat; |
fifo_a_wr <= 1'b0; |
fifo_a_wr_data <= { ll_out_dat, ll_out_dat, ll_out_dat, ll_out_dat }; |
if ((write_stb)&&(wb_addr[1:0]==2'b10)) |
begin |
fifo_a_wr <= 1'b1; |
fifo_a_wr_mask <= 4'b1111; |
fifo_a_wr_addr <= fifo_wb_addr; |
fifo_a_wr_data <= wb_data; |
end else if (pre_fifo_a_wr) |
begin |
fifo_a_wr <= 1'b1; |
fifo_a_wr_addr <= ll_fifo_addr[(LGFIFOLN+1):2]; |
case(ll_fifo_addr[1:0]) |
2'b00: fifo_a_wr_mask <= 4'b0001; |
2'b01: fifo_a_wr_mask <= 4'b0010; |
2'b10: fifo_a_wr_mask <= 4'b0100; |
2'b11: fifo_a_wr_mask <= 4'b1000; |
endcase |
end |
|
if ((write_stb)&&(i_wb_addr[1:0]==2'b11)) |
{fifo_b_mem[{fifo_wb_addr, 2'b00 }], |
fifo_b_mem[{ fifo_wb_addr, 2'b01 }], |
fifo_b_mem[{ fifo_wb_addr, 2'b10 }], |
fifo_b_mem[{ fifo_wb_addr, 2'b11 }] } |
<= i_wb_data; |
else if (pre_fifo_b_wr) |
fifo_b_mem[{ ll_fifo_addr }] <= ll_out_dat; |
if ((fifo_a_wr)&&(fifo_a_wr_mask[0])) |
fifo_a_mem_0[fifo_a_wr_addr] <= fifo_a_wr_data[7:0]; |
if ((fifo_a_wr)&&(fifo_a_wr_mask[1])) |
fifo_a_mem_1[fifo_a_wr_addr] <= fifo_a_wr_data[15:8]; |
if ((fifo_a_wr)&&(fifo_a_wr_mask[2])) |
fifo_a_mem_2[fifo_a_wr_addr] <= fifo_a_wr_data[23:16]; |
if ((fifo_a_wr)&&(fifo_a_wr_mask[3])) |
fifo_a_mem_3[fifo_a_wr_addr] <= fifo_a_wr_data[31:24]; |
|
if (~r_cmd_busy) |
fifo_b_wr <= 1'b0; |
fifo_b_wr_data <= { ll_out_dat, ll_out_dat, ll_out_dat, ll_out_dat }; |
if ((write_stb)&&(wb_addr[1:0]==2'b11)) |
begin |
fifo_b_wr <= 1'b1; |
fifo_b_wr_mask <= 4'b1111; |
fifo_b_wr_addr <= fifo_wb_addr; |
fifo_b_wr_data <= wb_data; |
end else if (pre_fifo_b_wr) |
begin |
fifo_b_wr <= 1'b1; |
fifo_b_wr_addr <= ll_fifo_addr[(LGFIFOLN+1):2]; |
case(ll_fifo_addr[1:0]) |
2'b00: fifo_b_wr_mask <= 4'b0001; |
2'b01: fifo_b_wr_mask <= 4'b0010; |
2'b10: fifo_b_wr_mask <= 4'b0100; |
2'b11: fifo_b_wr_mask <= 4'b1000; |
endcase |
end |
|
if ((fifo_b_wr)&&(fifo_b_wr_mask[0])) |
fifo_b_mem_0[fifo_b_wr_addr] <= fifo_b_wr_data[7:0]; |
if ((fifo_b_wr)&&(fifo_b_wr_mask[1])) |
fifo_b_mem_1[fifo_b_wr_addr] <= fifo_b_wr_data[15:8]; |
if ((fifo_b_wr)&&(fifo_b_wr_mask[2])) |
fifo_b_mem_2[fifo_b_wr_addr] <= fifo_b_wr_data[23:16]; |
if ((fifo_b_wr)&&(fifo_b_wr_mask[3])) |
fifo_b_mem_3[fifo_b_wr_addr] <= fifo_b_wr_data[31:24]; |
|
if (!r_cmd_busy) |
ll_fifo_wr_complete <= 1'b0; |
|
if (~r_cmd_busy) |
if (!r_cmd_busy) |
ll_fifo_wr_state <= 2'b00; |
else if ((pre_fifo_a_wr)||(pre_fifo_b_wr)) |
ll_fifo_wr_state <= (last_fifo_byte)? 2'b01:2'b00; |
634,14 → 762,30
|
always @(posedge i_clk) |
begin // Second memory read, this time for the FIFO |
fifo_a_byte <= fifo_a_mem[ ll_fifo_addr ]; |
fifo_b_byte <= fifo_b_mem[ ll_fifo_addr ]; |
case(ll_fifo_addr[1:0]) |
2'b00: begin |
fifo_a_byte<=fifo_a_mem_0[ll_fifo_addr[(LGFIFOLN+1):2]]; |
fifo_b_byte<=fifo_b_mem_0[ll_fifo_addr[(LGFIFOLN+1):2]]; |
end |
2'b01: begin |
fifo_a_byte<=fifo_a_mem_1[ll_fifo_addr[(LGFIFOLN+1):2]]; |
fifo_b_byte<=fifo_b_mem_1[ll_fifo_addr[(LGFIFOLN+1):2]]; |
end |
2'b10: begin |
fifo_a_byte<=fifo_a_mem_2[ll_fifo_addr[(LGFIFOLN+1):2]]; |
fifo_b_byte<=fifo_b_mem_2[ll_fifo_addr[(LGFIFOLN+1):2]]; |
end |
2'b11: begin |
fifo_a_byte<=fifo_a_mem_3[ll_fifo_addr[(LGFIFOLN+1):2]]; |
fifo_b_byte<=fifo_b_mem_3[ll_fifo_addr[(LGFIFOLN+1):2]]; |
end |
endcase |
end |
|
reg [(LGFIFOLN-1):0] r_blklimit; |
wire [(LGFIFOLN+1):0] w_blklimit; |
always @(posedge i_clk) |
r_blklimit[(LGFIFOLN-1):0] = (1<<r_lgblklen)-1; |
r_blklimit[(LGFIFOLN-1):0] <= (1<<r_lgblklen)-1; |
assign w_blklimit = { r_blklimit, 2'b11 }; |
|
// Package the FIFO reads up into a packet |
695,11 → 839,11
ll_fifo_rd_complete <= 1'b1; |
fifo_byte <= 8'hff; |
end |
end else if ((write_stb)&&(i_wb_addr == `SDSPI_CMD_ADDRESS)) |
end else if ((write_stb)&&(wb_addr == `SDSPI_CMD_ADDRESS)) |
begin |
ll_fifo_pkt_state <= 3'h0; |
ll_fifo_rd_complete <= 1'b0; |
fifo_byte <= (i_wb_data[12]) ? fifo_b_byte : fifo_a_byte; |
fifo_byte <= (wb_data[12]) ? fifo_b_byte : fifo_a_byte; |
fifo_rd_crc_stb <= 1'b1; |
end else begin // Packet state is IDLE (clear the CRC registers) |
ll_fifo_pkt_state <= 3'b111; |
709,7 → 853,7
|
always @(posedge i_clk) |
begin |
if (~ll_fifo_wr) |
if (!ll_fifo_wr) |
fifo_wr_crc_reg <= 16'h00; |
else if (fifo_wr_crc_stb) |
begin |
728,7 → 872,7
|
always @(posedge i_clk) |
begin |
if (~r_cmd_busy) |
if (!r_cmd_busy) |
begin |
fifo_rd_crc_reg <= 16'h00; |
fifo_rd_crc_count <= 4'h0; |
753,12 → 897,12
initial r_cmd_crc_ff = 1'b0; |
always @(posedge i_clk) |
begin |
if (~r_cmd_busy) |
if (!r_cmd_busy) |
begin |
r_cmd_crc <= 8'h00; |
r_cmd_crc_cnt <= 4'hf; |
r_cmd_crc_ff <= 1'b0; |
end else if (~r_cmd_crc_cnt[3]) |
end else if (!r_cmd_crc_cnt[3]) |
begin |
r_cmd_crc_cnt <= r_cmd_crc_cnt - 4'h1; |
if (r_cmd_crc[7]) |
784,12 → 928,12
initial r_watchdog = 26'h3ffffff; |
initial r_watchdog_err = 1'b0; |
always @(posedge i_clk) |
if (~r_cmd_busy) |
if (!r_cmd_busy) |
r_watchdog_err <= 1'b0; |
else if (r_watchdog == 0) |
r_watchdog_err <= 1'b1; |
always @(posedge i_clk) |
if (~r_cmd_busy) |
if (!r_cmd_busy) |
r_watchdog <= 26'h3fffff; |
else if (|r_watchdog) |
r_watchdog <= r_watchdog - 26'h1; |
801,5 → 945,11
r_rsp_state, r_cmd_busy, // 4'h |
ll_cmd_dat, // 8'b |
ll_out_dat }; // 8'b |
|
// Make verilator happy |
// verilator lint_off UNUSED |
wire unused; |
assign unused = i_wb_cyc; |
// verilator lint_on UNUSED |
endmodule |
|