├── .gitignore ├── Makefile ├── README.md ├── autodata ├── sdio.txt └── sdspi.txt ├── bench ├── cpp │ ├── .gitignore │ ├── Makefile │ ├── sdiosim.cpp │ ├── sdiosim.h │ ├── sdspisim.cpp │ ├── sdspisim.h │ ├── tb_sdspi.cpp │ ├── testb.h │ ├── trace.gtkw │ └── wb_tb.h ├── formal │ ├── .gitignore │ ├── Makefile │ ├── faxil_register.v │ ├── faxil_slave.v │ ├── fclk.v │ ├── fwb_register.v │ ├── fwb_slave.v │ ├── genreport.pl │ ├── llsdspi.gtkw │ ├── llsdspi.sby │ ├── report.html │ ├── sdaxil.sby │ ├── sdckgen.gtkw │ ├── sdckgen.sby │ ├── sdcmd.gtkw │ ├── sdcmd.sby │ ├── sdrxframe.gtkw │ ├── sdrxframe.sby │ ├── sdspi.gtkw │ ├── sdspi.sby │ ├── sdtxframe.gtkw │ ├── sdtxframe.sby │ ├── sdwb.gtkw │ ├── sdwb.sby │ ├── spicmd.gtkw │ ├── spicmd.sby │ ├── spirxdata.gtkw │ ├── spirxdata.sby │ ├── spitxdata.gtkw │ └── spitxdata.sby ├── testscript │ ├── emmclib.v │ ├── emmcstart.v │ ├── sddmachk.v │ ├── sdiolib.v │ ├── sdiostart.v │ └── sdstream.v └── verilog │ ├── .gitignore │ ├── IOBUF.v │ ├── Makefile │ ├── axil_bfm.v │ ├── cpu_files.txt │ ├── dev_files.txt │ ├── dev_testcases.txt │ ├── gen_report.pl │ ├── iscachable.v │ ├── mdl_emmc.v │ ├── mdl_sdcmd.v │ ├── mdl_sdio.v │ ├── mdl_sdrx.v │ ├── mdl_sdtx.v │ ├── report.html │ ├── sim_run.pl │ ├── streamchk.v │ ├── tb_axi.v │ ├── tb_cpu.v │ ├── tb_sdckgen.v │ ├── tb_txframe.v │ ├── tb_wb.v │ ├── wb2axip │ ├── addrdecode.v │ ├── axi2axilite.v │ ├── axi2axilsub.v │ ├── axi_addr.v │ ├── axiempty.v │ ├── axilgpio.v │ ├── axilite2axi.v │ ├── axilupsz.v │ ├── axiram.v │ ├── axixbar.v │ ├── memdev.v │ ├── sfifo.v │ ├── skidbuffer.v │ ├── wbdown.v │ ├── wbgpio.v │ ├── wbupsz.v │ └── wbxbar.v │ └── wb_bfm.v ├── doc ├── 20240214-1-originaltb.dia ├── 20240214-1-originaltb.png ├── 20240214-2-simpletb.dia ├── 20240214-2-simpletb.png ├── 20240214-3-kitchensink.dia ├── 20240214-3-kitchensink.png ├── 20240214-4-dotmem.dia ├── 20240214-4-dotmem.png ├── 20240214-5-dblaxi.dia ├── 20240214-5-dblaxi.png ├── 20240221-1-trace.dia ├── 20240221-1-trace.png ├── 20240221-2-steps.dia ├── 20240221-2-steps.png ├── 20240221-3-cmd.dia ├── 20240221-3-cmd.png ├── 20240221-4-buffer.dia ├── 20240221-4-buffer.png ├── 20240221-5-axis.dia ├── 20240221-5-axis.png ├── 20240221-6-dmablk.dia ├── 20240221-6-dmablk.png ├── 20240221-6-dmaparts.dia ├── 20240221-7-blkdiag.dia ├── 20240221-7-blkdiag.png ├── 20240221-sddma.png ├── 20240315-sim-benchmark.png ├── 20241125-usage-comparison.dia ├── 20241125-usage-comparison.png ├── 20241125-usage.png ├── 20241130-1p8vprogress.dia ├── 20241130-1p8vprogress.png ├── 20241230-cmd19-annotated.dia ├── 20241230-cmd19-annotated.png ├── 20241230-cmd19.png ├── 20241230-cmd19z-annotated.dia ├── 20241230-cmd19z-annotated.png ├── 20241230-cmd19z.png ├── Makefile ├── devprogress.dia ├── devstat.dia ├── devstat.png ├── gpl-3.0.pdf ├── hwteststat.dia ├── hwteststat.png ├── sdio.pdf ├── sdspi.pdf ├── src │ ├── .gitignore │ ├── GT.eps │ ├── gfx │ │ ├── cputb.dia │ │ ├── cputb.eps │ │ ├── dmablocks.dia │ │ ├── dmablocks.eps │ │ ├── dmablocks.png │ │ ├── mdlsdio.dia │ │ ├── mdlsdio.eps │ │ ├── sdioblocks.dia │ │ ├── sdioblocks.eps │ │ ├── sdiocmdflow.dia │ │ ├── sdiocmdflow.eps │ │ ├── sdiotxflow.dia │ │ ├── sdiotxflow.eps │ │ ├── swlayers.dia │ │ ├── swlayers.eps │ │ ├── vlogtb.dia │ │ └── vlogtb.eps │ ├── gpl-3.0.tex │ ├── gqtekspec.cls │ ├── sdio.tex │ ├── sdspi.tex │ └── zshell.sty ├── wbsdstart.dia └── wbsdstart.png ├── rtl ├── .gitignore ├── Makefile ├── README.md ├── afifo.v ├── exportspi.v ├── llsdspi.v ├── sdax_mm2s.v ├── sdax_s2mm.v ├── sdaxil.v ├── sdckgen.v ├── sdcmd.v ├── sddma.v ├── sddma_mm2s.v ├── sddma_rxgears.v ├── sddma_s2mm.v ├── sddma_txgears.v ├── sdfifo.v ├── sdfrontend.v ├── sdio.v ├── sdio_top.v ├── sdrxframe.v ├── sdskid.v ├── sdspi-diff.txt ├── sdspi.v ├── sdtxframe.v ├── sdwb.v ├── spicmd.v ├── spirxdata.v ├── spitxdata.v ├── usage.pl ├── usage.txt ├── xsdddr.v └── xsdserdes8x.v ├── sdspi.core └── sw ├── .gitignore ├── diskio.c ├── diskiodrvr.h ├── emmcdrv.c ├── emmcdrv.h ├── sdiodrv.c ├── sdiodrv.h ├── sdspidrv.c └── sdspidrv.h /.gitignore: -------------------------------------------------------------------------------- 1 | legal.txt 2 | .svn 3 | xilinx 4 | obj_dir 5 | obj-pc 6 | obj-zip 7 | *.o 8 | *.a 9 | *.vcd 10 | *.fst 11 | *.log 12 | .*.swp 13 | .*.swo 14 | *.autosave 15 | .swp 16 | .swo 17 | svn-commit* 18 | *_tb 19 | *_tb.dbl 20 | *dbg.txt 21 | *dump.txt 22 | tags 23 | cpudefs.h 24 | /*.pdf 25 | /refs/ 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | ## 3 | ## Filename: Makefile 4 | ## {{{ 5 | ## Project: SD-Card controller 6 | ## 7 | ## Purpose: Coordinate building the specification for this core, the 8 | ## Verilator Verilog check, and any bench software. 9 | ## 10 | ## Creator: Dan Gisselquist, Ph.D. 11 | ## Gisselquist Technology, LLC 12 | ## 13 | ################################################################################ 14 | ## }}} 15 | ## Copyright (C) 2016-2025, Gisselquist Technology, LLC 16 | ## {{{ 17 | ## This program is free software (firmware): you can redistribute it and/or 18 | ## modify it under the terms of the GNU General Public License as published 19 | ## by the Free Software Foundation, either version 3 of the License, or (at 20 | ## your option) any later version. 21 | ## 22 | ## This program is distributed in the hope that it will be useful, but WITHOUT 23 | ## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 24 | ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 25 | ## for more details. 26 | ## 27 | ## You should have received a copy of the GNU General Public License along 28 | ## with this program. (It's in the $(ROOT)/doc directory. Run make with no 29 | ## target there if the PDF file isn't present.) If not, see 30 | ## for a copy. 31 | ## }}} 32 | ## License: GPL, v3, as defined and found on www.gnu.org, 33 | ## {{{ 34 | ## http://www.gnu.org/licenses/gpl.html 35 | ## 36 | ################################################################################ 37 | ## 38 | ## }}} 39 | .PHONY: all 40 | all: verilated test 41 | ## Some definitions 42 | ## {{{ 43 | BENCH := `find bench -name Makefile` `find bench -name "*.cpp"` `find bench -name "*.h"` 44 | RTL := `find rtl -name "*.v"` `find rtl -name Makefile` 45 | NOTES := # `find . -name "*.txt"` `find . -name "*.html"` 46 | SW= 47 | #SW := `find sw -name "*.cpp"` `find sw -name "*.h"` \ 48 | # `find sw -name "*.sh"` `find sw -name "*.py"` \ 49 | # `find sw -name "*.pl"` `find sw -name Makefile` 50 | DEVSW= 51 | YYMMDD:=`date +%Y%m%d` 52 | SUBMAKE := $(MAKE) --no-print-directory -C 53 | ## }}} 54 | 55 | .PHONY: archive 56 | ## {{{ 57 | archive: 58 | tar --transform s,^,$(YYMMDD)-sdspi/, -chjf $(YYMMDD)-sdspi.tjz $(BENCH) $(SW) $(RTL) $(NOTES) 59 | ## }}} 60 | 61 | .PHONY: verilated rtl 62 | ## {{{ 63 | rtl: verilated 64 | verilated: 65 | $(SUBMAKE) rtl 66 | ## }}} 67 | 68 | .PHONY: doc 69 | ## {{{ 70 | # The documents target does not get, nor should it be, made automatically. 71 | # This is because the project is intended to be shipped with the documents 72 | # automatically built, and I don't necessarily expect all those who download 73 | # this "core" to have LaTeX distribution necessary to rebuild the specification 74 | # and GPL LaTeX documents into their PDF results. 75 | doc: 76 | $(SUBMAKE) doc 77 | ## }}} 78 | 79 | .PHONY: formal 80 | ## {{{ 81 | formal: 82 | +$(SUBMAKE) bench/formal 83 | ## }}} 84 | 85 | .PHONY: bench 86 | ## {{{ 87 | bench: rtl 88 | $(SUBMAKE) bench/cpp 89 | ## }}} 90 | 91 | .PHONY: test 92 | ## {{{ 93 | test: formal rtl 94 | $(SUBMAKE) bench/verilog test 95 | $(SUBMAKE) bench/cpp test 96 | ## }}} 97 | #.PHONY: sw 98 | # sw: 99 | # cd sw ; $(MAKE) --no-print-directory 100 | 101 | .PHONY: clean 102 | ## {{{ 103 | clean: 104 | $(SUBMAKE) rtl clean 105 | $(SUBMAKE) doc clean 106 | $(SUBMAKE) bench/formal clean 107 | $(SUBMAKE) bench/cpp clean 108 | ## }}} 109 | -------------------------------------------------------------------------------- /autodata/sdio.txt: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | ## 3 | ## Filename: autodata/sdio.txt 4 | ## {{{ 5 | ## Project: SD-Card controller 6 | ## 7 | ## Purpose: Describes how to connect an SDIO peripheral to a wishbone 8 | ## bus, as used by autofpga. 9 | ## 10 | ## Creator: Dan Gisselquist, Ph.D. 11 | ## Gisselquist Technology, LLC 12 | ## 13 | ################################################################################ 14 | ## }}} 15 | ## Copyright (C) 2016-2025, Gisselquist Technology, LLC 16 | ## {{{ 17 | ## This program is free software (firmware): you can redistribute it and/or 18 | ## modify it under the terms of the GNU General Public License as published 19 | ## by the Free Software Foundation, either version 3 of the License, or (at 20 | ## your option) any later version. 21 | ## 22 | ## This program is distributed in the hope that it will be useful, but WITHOUT 23 | ## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 24 | ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 25 | ## for more details. 26 | ## 27 | ## You should have received a copy of the GNU General Public License along 28 | ## with this program. (It's in the $(ROOT)/doc directory. Run make with no 29 | ## target there if the PDF file isn't present.) If not, see 30 | ## for a copy. 31 | ## }}} 32 | ## License: GPL, v3, as defined and found on www.gnu.org, 33 | ## {{{ 34 | ## http://www.gnu.org/licenses/gpl.html 35 | ## 36 | ################################################################################ 37 | ## 38 | ## }}} 39 | @PREFIX=sdcard 40 | @DEVID=SDIO 41 | @NAME=SDIO SD Card 42 | @NADDR=8 43 | @CRCTOKEN=1 44 | @$NUMIO=4 45 | @ACCESS=SDIO_ACCESS 46 | @SLAVE.TYPE=OTHER 47 | @SLAVE.BUS=wb 48 | @MASTER.TYPE=DMA 49 | @MASTER.BUS=wbwide 50 | @MASTER.ANSPREFIX=dma_ 51 | ## @SCOPE.TRIGGER=@$(PREFIX)_debug[31] 52 | ## @SCOPE.DATA=@$(PREFIX)_debug 53 | @INT.SDCARD.WIRE= @$(PREFIX)_int 54 | @INT.SDCARD.PIC= syspic 55 | @CARD_DETECT=1'b1 56 | @OPT_SERDES=1'b0 57 | @OPT_DDR=1'b1 58 | @OPT_EMMC=1'b0 59 | @OPT_DMA=1'b1 60 | @OPT_HWRESET=@$(OPT_EMMC) 61 | @TOP.PORTLIST= 62 | // @$(NAME) 63 | o_@$(PREFIX)_clk, io_@$(PREFIX)_cmd, io_@$(PREFIX)_dat, i_@$(PREFIX)_cd_n 64 | @TOP.IODECL= 65 | // @$(NAME) 66 | // {{{ 67 | output wire o_@$(PREFIX)_clk; 68 | inout wire io_@$(PREFIX)_cmd; 69 | inout wire [@$(NUMIO)-1:0] io_@$(PREFIX)_dat; 70 | input wire i_@$(PREFIX)_cd_n; 71 | // }}} 72 | @TOP.DEFNS= 73 | // @$(NAME) definitions 74 | // {{{ 75 | wire i_@$(PREFIX)_ds; 76 | // }}} 77 | @TOP.MAIN= 78 | // @$(NAME) 79 | o_@$(PREFIX)_clk, i_@$(PREFIX)_ds, 80 | io_@$(PREFIX)_cmd, io_@$(PREFIX)_dat, 81 | !i_@$(PREFIX)_cd_n 82 | @TOP.INSERT= 83 | assign i_@$(PREFIX)_ds = 1'b0; 84 | @MAIN.PORTLIST= 85 | // @$(NAME) 86 | o_@$(PREFIX)_clk, i_@$(PREFIX)_ds, 87 | `ifdef VERILATOR 88 | io_@$(PREFIX)_cmd_tristate, 89 | o_@$(PREFIX)_cmd, i_@$(PREFIX)_cmd, 90 | io_@$(PREFIX)_dat_tristate, 91 | o_@$(PREFIX)_dat, i_@$(PREFIX)_dat, 92 | `else 93 | io_@$(PREFIX)_cmd, io_@$(PREFIX)_dat, 94 | `endif 95 | i_@$(PREFIX)_detect 96 | @MAIN.IODECL= 97 | // @$(NAME) declarations 98 | // {{{ 99 | output wire o_@$(PREFIX)_clk; 100 | input wire i_@$(PREFIX)_ds; 101 | `ifdef VERILATOR 102 | output wire io_@$(PREFIX)_cmd_tristate; 103 | output wire o_@$(PREFIX)_cmd; 104 | input wire i_@$(PREFIX)_cmd; 105 | output wire [@$(NUMIO)-1:0] io_@$(PREFIX)_dat_tristate; 106 | output wire [@$(NUMIO)-1:0] o_@$(PREFIX)_dat; 107 | input wire [@$(NUMIO)-1:0] i_@$(PREFIX)_dat; 108 | `else 109 | inout wire io_@$(PREFIX)_cmd; 110 | inout wire [@$(NUMIO)-1:0] io_@$(PREFIX)_dat; 111 | `endif 112 | input wire i_@$(PREFIX)_detect; 113 | // }}} 114 | @MAIN.DEFNS= 115 | // @$(NAME) definitions 116 | // Verilator lint_off UNUSED 117 | wire w_@$(PREFIX)_1p8v, s_@$(PREFIX)_ready, 118 | m_@$(PREFIX)_valid, m_@$(PREFIX)_last; 119 | wire [31:0] @$(PREFIX)_debug, m_@$(PREFIX)_data; 120 | // Verilator lint_on UNUSED 121 | @MAIN.INSERT= 122 | //////////////////////////////////////////////////////////////////////// 123 | // 124 | // @$(NAME) handling 125 | // {{{ 126 | //////////////////////////////////////////////////////////////////////// 127 | // 128 | // 129 | 130 | sdio_top #( 131 | // {{{ 132 | .LGFIFO(10), .NUMIO(@$(NUMIO)), 133 | .MW(@$(SLAVE.BUS.WIDTH)), 134 | .ADDRESS_WIDTH(@$(MASTER.BUS.AWID)+$clog2(@$(MASTER.BUS.WIDTH)/8)), 135 | .DMA_DW(@$(MASTER.BUS.WIDTH)), 136 | .OPT_SERDES(@$(OPT_SERDES)), 137 | .OPT_EMMC(@$(OPT_EMMC)), 138 | .OPT_DMA(@$(OPT_DMA)), 139 | .OPT_DDR(@$(OPT_DDR)), 140 | .OPT_HWRESET(@$(OPT_HWRESET)), 141 | .OPT_CARD_DETECT(@$(CARD_DETECT)), 142 | .OPT_CRCTOKEN(@$(CRCTOKEN)), 143 | .LGTIMEOUT(26), 144 | .OPT_ISTREAM(1'b0), 145 | .OPT_OSTREAM(1'b0) 146 | // }}} 147 | ) u_@$(PREFIX)( 148 | // {{{ 149 | .i_clk(@$(SLAVE.BUS.CLOCK.WIRE)), 150 | .i_reset(@$(SLAVE.BUS.CLOCK.RESET)), 151 | .i_hsclk(1'b0), 152 | @$(SLAVE.ANSIPORTLIST), 153 | @$(MASTER.ANSIPORTLIST), 154 | .o_ck(o_@$(PREFIX)_clk), 155 | .i_ds(i_@$(PREFIX)_ds), 156 | // (Unused) DMA Stream assignments 157 | // {{{ 158 | .s_valid(1'b0), 159 | .s_ready(s_@$(PREFIX)_ready), 160 | .s_data(32'h0), 161 | // 162 | .m_valid(m_@$(PREFIX)_valid), 163 | .m_ready(1'b1), 164 | .m_data(m_@$(PREFIX)_data), 165 | .m_last(m_@$(PREFIX)_last), 166 | // }}} 167 | `ifdef VERILATOR 168 | .io_cmd_tristate(io_@$(PREFIX)_cmd_tristate), 169 | .o_cmd(o_@$(PREFIX)_cmd), 170 | .i_cmd(i_@$(PREFIX)_cmd), 171 | .io_dat_tristate(io_@$(PREFIX)_dat_tristate), 172 | .o_dat(o_@$(PREFIX)_dat), 173 | .i_dat(i_@$(PREFIX)_dat), 174 | `else 175 | .io_cmd(io_@$(PREFIX)_cmd), 176 | .io_dat(io_@$(PREFIX)_dat), 177 | `endif 178 | .i_card_detect(i_@$(PREFIX)_detect), 179 | .o_1p8v(w_@$(PREFIX)_1p8v), 180 | .o_int(@$(PREFIX)_int), 181 | .o_debug(@$(PREFIX)_debug) 182 | // }}} 183 | ); 184 | 185 | // }}} 186 | @MAIN.ALT= 187 | assign o_@$(PREFIX)_clk = 1'b1; 188 | `ifdef VERILATOR 189 | assign io_@$(PREFIX)_cmd_tristate = 1'b1; 190 | assign o_@$(PREFIX)_cmd = 1'b1; 191 | assign io_@$(PREFIX)_data_tristate = -1; 192 | assign o_@$(PREFIX)_data = -1; 193 | `else // VERILATOR 194 | assign io_@$(PREFIX)_cmd = 1'b1; 195 | assign io_@$(PREFIX)_dat = -1; 196 | `endif // VERILATOR 197 | @REGS.N=5 198 | @REGS.NOTE= // @$(NAME) addresses 199 | @REGS.0= 0 R_@$(DEVID)_CTRL SDCARD 200 | @REGS.1= 1 R_@$(DEVID)_DATA SDDATA 201 | @REGS.2= 2 R_@$(DEVID)_FIFOA SDFIFOA, SDFIF0, SDFIFA 202 | @REGS.3= 3 R_@$(DEVID)_FIFOB SDFIFOB, SDFIF1, SDFIFB 203 | @REGS.4= 4 R_@$(DEVID)_PHY SDPHY 204 | @BDEF.DEFN= 205 | //////////////////////////////////////////////////////////////////////////////// 206 | // 207 | // @$(NAME) constants 208 | // {{{ 209 | //////////////////////////////////////////////////////////////////////////////// 210 | // 211 | // 212 | 213 | // These will be defined in sdiodrv.h for the SDIO controller 214 | struct @$(DEVID)_S; 215 | // }}} 216 | @BDEF.IONAME=_@$(PREFIX) 217 | @BDEF.IOTYPE=struct @$(DEVID)_S 218 | @BDEF.OSDEF=_BOARD_HAS_@$(DEVID) 219 | @BDEF.OSVAL=static volatile @$(BDEF.IOTYPE) *const @$(BDEF.IONAME) = ((@$(BDEF.IOTYPE) *)@$[0x%08x](REGBASE)); 220 | @SIM.CLOCK=clk 221 | @SIM.INCLUDE= 222 | // #include "sdiosim.h" 223 | @RTL.MAKE.GROUP= SDIO 224 | @RTL.MAKE.SUBD=sdspi 225 | @RTL.MAKE.FILES= sdio_top.v sdio.v sdfrontend.v sdckgen.v sdwb.v sdtxframe.v sdrxframe.v sdcmd.v sddma.v sddma_mm2s.v sddma_rxgears.v sdfifo.v sddma_txgears.v sddma_s2mm.v xsdddr.v xsdserdes8x.v 226 | @XDC.SERDES= 227 | set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/u_sdcmd/cmd_tristate*}] -to [get_cells -hier -filter {NAME=~ u_@$(PREFIX)_frontend/GEN_WIDE_IO.cmd_serdes/u_oserdes*}] 4.0 228 | set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/u_txframe/r_tristate*}] -to [get_cells -hier -filter {NAME=~ u_@$(PREFIX)_frontend/GEN_WIDE_IO.GEN_WIDE_DATIO*.io_serdes/u_oserdes*}] 4.0 229 | 230 | -------------------------------------------------------------------------------- /autodata/sdspi.txt: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | ## 3 | ## Filename: autodata/sdspi.txt 4 | ## {{{ 5 | ## Project: SD-Card controller 6 | ## 7 | ## Purpose: Describes how to connect an SD-SPI peripheral to a wishbone 8 | ## bus, as used by autofpga. Note how the description requires 9 | ## both a description of what needs to take place in a top level file, as 10 | ## well as in the main 11 | ## 12 | ## An interesting consequence of this description is that upgrading to a 13 | ## proper SDIO device would involve no more than swapping this file for an 14 | ## sdio.c peripheral description file. 15 | ## 16 | ## Creator: Dan Gisselquist, Ph.D. 17 | ## Gisselquist Technology, LLC 18 | ## 19 | ################################################################################ 20 | ## }}} 21 | ## Copyright (C) 2016-2025, Gisselquist Technology, LLC 22 | ## {{{ 23 | ## This program is free software (firmware): you can redistribute it and/or 24 | ## modify it under the terms of the GNU General Public License as published 25 | ## by the Free Software Foundation, either version 3 of the License, or (at 26 | ## your option) any later version. 27 | ## 28 | ## This program is distributed in the hope that it will be useful, but WITHOUT 29 | ## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 30 | ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 31 | ## for more details. 32 | ## 33 | ## You should have received a copy of the GNU General Public License along 34 | ## with this program. (It's in the $(ROOT)/doc directory. Run make with no 35 | ## target there if the PDF file isn't present.) If not, see 36 | ## for a copy. 37 | ## }}} 38 | ## License: GPL, v3, as defined and found on www.gnu.org, 39 | ## {{{ 40 | ## http://www.gnu.org/licenses/gpl.html 41 | ## 42 | ################################################################################ 43 | ## 44 | ## }}} 45 | @PREFIX=sdcard 46 | @DEVID=SDSPI 47 | @NADDR=4 48 | @ACCESS=SDSPI_ACCESS 49 | @SLAVE.TYPE=OTHER 50 | @SLAVE.BUS=wb 51 | @BUS.NAME=wb 52 | ## @SCOPE.TRIGGER=@$(PREFIX)_debug[31] 53 | ## @SCOPE.DATA=@$(PREFIX)_debug 54 | @INT.SDCARD.WIRE= @$(PREFIX)_int 55 | @INT.SDCARD.PIC= syspic 56 | @IOPREFIX=@$(PREFIX) 57 | @TOP.PORTLIST= 58 | // SD Card 59 | o_@$(IOPREFIX)_sck, io_@$(IOPREFIX)_cmd, io_@$(IOPREFIX), i_@$(IOPREFIX)_cd 60 | @TOP.IODECL= 61 | // SD Card 62 | // {{{ 63 | output wire o_@$(IOPREFIX)_sck; 64 | inout wire io_@$(IOPREFIX)_cmd; 65 | inout wire [3:0] io_@$(IOPREFIX); 66 | input wire i_@$(IOPREFIX)_cd; 67 | // }}} 68 | @TOP.DEFNS= 69 | // SD Card definitions 70 | // {{{ 71 | wire w_@$(PREFIX)_cmd; 72 | wire [3:0] w_@$(PREFIX)_data; 73 | 74 | wire i_@$(IOPREFIX)_cmd; 75 | wire [3:0] i_@$(IOPREFIX); 76 | // }}} 77 | @TOP.MAIN= 78 | // SD Card 79 | o_@$(IOPREFIX)_sck, w_@$(IOPREFIX)_cmd, w_@$(IOPREFIX)_data, 80 | io_@$(IOPREFIX)_cmd, io_@$(IOPREFIX), i_@$(IOPREFIX)_cd 81 | @TOP.INSERT= 82 | ////////////////////////////////////////////////////////////////////// 83 | // 84 | // SD Card SPI Controller 85 | // {{{ 86 | ////////////////////////////////////////////////////////////////////// 87 | // 88 | // 89 | 90 | // Wires for setting up the SD Card Controller 91 | // {{{ 92 | // This is how we'd set up for SDIO 93 | // assign io_@$(PREFIX)_cmd = w_@$(PREFIX)_cmd ? 1'bz:1'b0; // MOSI 94 | // assign io_@$(PREFIX)[0] = w_@$(PREFIX)_data[0]? 1'bz:1'b0; // MISO 95 | // assign io_@$(PREFIX)[1] = w_@$(PREFIX)_data[1]? 1'bz:1'b0; 96 | // assign io_@$(PREFIX)[2] = w_@$(PREFIX)_data[2]? 1'bz:1'b0; 97 | // assign io_@$(PREFIX)[3] = w_@$(PREFIX)_data[3]? 1'bz:1'b0; // CS_n 98 | // }}} 99 | IOBUF @$(PREFIX)_cmd_bf(.T(1'b0),.O(i_@$(IOPREFIX)_cmd),.I(w_@$(PREFIX)_cmd),.IO(io_@$(IOPREFIX)_cmd));// MISO 100 | IOBUF @$(PREFIX)_dat0_bf(.T(1'b1),.O(i_@$(IOPREFIX)[0]),.I(1'b1),.IO(io_@$(IOPREFIX)[0]));// MISO 101 | IOBUF @$(PREFIX)_dat1_bf(.T(1'b1),.O(i_@$(IOPREFIX)[1]),.I(1'b1),.IO(io_@$(IOPREFIX)[1])); 102 | IOBUF @$(PREFIX)_dat2_bf(.T(1'b1),.O(i_@$(IOPREFIX)[2]),.I(1'b1),.IO(io_@$(IOPREFIX)[2])); 103 | 104 | // Implement an open-drain output 105 | IOBUF @$(PREFIX)_dat3_bf(.T(w_@$(PREFIX)_data[3]),.O(i_@$(IOPREFIX)[3]),.I(1'b0),.IO(io_@$(IOPREFIX)[3])); 106 | // }}} 107 | @MAIN.PORTLIST= 108 | // The SD-Card wires 109 | o_@$(PREFIX)_sck, o_@$(PREFIX)_cmd, o_@$(PREFIX)_data, i_@$(PREFIX)_cmd, i_@$(PREFIX)_data, i_@$(PREFIX)_detect 110 | @MAIN.IODECL= 111 | // SD-Card declarations 112 | // {{{ 113 | output wire o_@$(PREFIX)_sck, o_@$(PREFIX)_cmd; 114 | output wire [3:0] o_@$(PREFIX)_data; 115 | // verilator lint_off UNUSED 116 | // The SDSPI controller doesn't use all of the data pins 117 | input wire i_@$(PREFIX)_cmd; 118 | input wire [3:0] i_@$(PREFIX)_data; 119 | // verilator lint_on UNUSED 120 | input wire i_@$(PREFIX)_detect; 121 | // }}} 122 | @MAIN.DEFNS= 123 | // SD SPI definitions 124 | // Verilator lint_off UNUSED 125 | wire [31:0] @$(PREFIX)_debug; 126 | // Verilator lint_on UNUSED 127 | wire w_@$(PREFIX)_cs_n, w_@$(PREFIX)_mosi, w_@$(PREFIX)_miso; 128 | @MAIN.INSERT= 129 | //////////////////////////////////////////////////////////////////////// 130 | // 131 | // SD Card SPI handling 132 | // {{{ 133 | //////////////////////////////////////////////////////////////////////// 134 | // 135 | // 136 | 137 | sdspi 138 | u_@$(PREFIX)( 139 | // {{{ 140 | .i_clk(@$(SLAVE.BUS.CLOCK.WIRE)), 141 | .i_sd_reset(@$(SLAVE.BUS.CLOCK.RESET)), 142 | @$(SLAVE.ANSIPORTLIST), 143 | .o_cs_n(w_@$(PREFIX)_cs_n), 144 | .o_sck(o_@$(PREFIX)_sck), 145 | .o_mosi(w_@$(PREFIX)_mosi), 146 | .i_miso(w_@$(PREFIX)_miso), 147 | .i_card_detect(i_@$(PREFIX)_detect), 148 | .o_int(@$(PREFIX)_int), 149 | .i_bus_grant(1'b1), 150 | .o_debug(@$(PREFIX)_debug) 151 | // }}} 152 | ); 153 | 154 | assign w_@$(PREFIX)_miso = i_@$(PREFIX)_data[0]; 155 | assign o_@$(PREFIX)_data = { w_@$(PREFIX)_cs_n, 3'b111 }; 156 | assign o_@$(PREFIX)_cmd = w_@$(PREFIX)_mosi; 157 | // }}} 158 | @MAIN.ALT= 159 | assign o_@$(PREFIX)_sck = 1'b1; 160 | assign o_@$(PREFIX)_cmd = 1'b1; 161 | assign o_@$(PREFIX)_data = 4'hf; 162 | @REGS.N=4 163 | @REGS.NOTE= // SD-SPI addresses 164 | @REGS.0= 0 R_@$(DEVID)_CTRL SDCARD 165 | @REGS.1= 1 R_@$(DEVID)_DATA SDDATA 166 | @REGS.2= 2 R_@$(DEVID)_FIFOA SDFIFOA, SDFIF0, SDFIFA 167 | @REGS.3= 3 R_@$(DEVID)_FIFOB SDFIFOB, SDFIF1, SDFIFB 168 | @BDEF.DEFN= 169 | //////////////////////////////////////////////////////////////////////////////// 170 | // 171 | // SD SPI constants 172 | // {{{ 173 | //////////////////////////////////////////////////////////////////////////////// 174 | // 175 | // 176 | 177 | #ifndef @$(DEVID)_H 178 | #define @$(DEVID)_H 179 | 180 | struct @$(DEVID)_S; 181 | 182 | #endif // @$(DEVID)_H 183 | // }}} 184 | @BDEF.IONAME=_@$(PREFIX) 185 | @BDEF.IOTYPE=struct @$(DEVID)_S 186 | @BDEF.OSDEF=_BOARD_HAS_@$(DEVID) 187 | @BDEF.OSVAL=static volatile @$(BDEF.IOTYPE) *const @$(BDEF.IONAME) = ((@$(BDEF.IOTYPE) *)@$[0x%08x](REGBASE)); 188 | @SIM.CLOCK=clk 189 | @SIM.INCLUDE= 190 | #include "sdspisim.h" 191 | @SIM.DEFNS= 192 | #ifdef SDSPI_ACCESS 193 | SDSPISIM m_@$(PREFIX); 194 | #endif // @$(ACCESS) 195 | @SIM.INIT= 196 | #ifdef @$(ACCESS) 197 | m_@$(PREFIX).debug(false); 198 | #endif // @$(ACCESS) 199 | @SIM.METHODS= 200 | #ifdef @$(ACCESS) 201 | void setsdcard(const char *fn) { 202 | m_@$(PREFIX).load(fn); 203 | } 204 | #endif // @$(ACCESS) 205 | @SIM.TICK= 206 | // SD Card simulation 207 | // {{{ 208 | #ifdef @$(ACCESS) 209 | m_core->i_@$(PREFIX)_data = m_@$(PREFIX)( 210 | (m_core->o_@$(PREFIX)_data&8)?1:0, 211 | m_core->o_@$(PREFIX)_sck, 212 | m_core->o_@$(PREFIX)_cmd); 213 | m_core->i_@$(PREFIX)_data &= 1; 214 | m_core->i_@$(PREFIX)_data |= (m_core->o_@$(PREFIX)_data&0x0e); 215 | m_core->i_@$(PREFIX)_detect = 1; 216 | #endif // @$(ACCESS) 217 | // }}} 218 | @RTL.MAKE.GROUP= SDSPI 219 | @RTL.MAKE.SUBD=sdspi 220 | @RTL.MAKE.FILES= sdspi.v llsdspi.v spicmd.v spirxdata.v spitxdata.v 221 | -------------------------------------------------------------------------------- /bench/cpp/.gitignore: -------------------------------------------------------------------------------- 1 | *.vcd 2 | /sdcard.img 3 | /tb_sdspi 4 | -------------------------------------------------------------------------------- /bench/cpp/Makefile: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | ## 3 | ## Filename: bench/cpp/Makefile 4 | ## {{{ 5 | ## Project: SD-Card controller 6 | ## 7 | ## Purpose: Nothing currently. Eventually, if I create a proper bench 8 | ## test, rather than just running this on real hardware as part of 9 | ## another project (XuLA2-LX25 SoC), this Makefile will coordinate the 10 | ## building of that bench test software. 11 | ## 12 | ## Creator: Dan Gisselquist, Ph.D. 13 | ## Gisselquist Technology, LLC 14 | ## 15 | ################################################################################ 16 | ## }}} 17 | ## Copyright (C) 2016-2025, Gisselquist Technology, LLC 18 | ## {{{ 19 | ## This program is free software (firmware): you can redistribute it and/or 20 | ## modify it under the terms of the GNU General Public License as published 21 | ## by the Free Software Foundation, either version 3 of the License, or (at 22 | ## your option) any later version. 23 | ## 24 | ## This program is distributed in the hope that it will be useful, but WITHOUT 25 | ## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 26 | ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 27 | ## for more details. 28 | ## 29 | ## You should have received a copy of the GNU General Public License along 30 | ## with this program. (It's in the $(ROOT)/doc directory. Run make with no 31 | ## target there if the PDF file isn't present.) If not, see 32 | ## for a copy. 33 | ## }}} 34 | ## License: GPL, v3, as defined and found on www.gnu.org, 35 | ## {{{ 36 | ## http://www.gnu.org/licenses/gpl.html 37 | ## 38 | ################################################################################ 39 | ## 40 | ## }}} 41 | .PHONY: all 42 | all: 43 | CXX:= g++ 44 | OBJDIR := obj-pc 45 | RTLD := ../../rtl 46 | ifeq ($(VERILATOR_ROOT),) 47 | VERILATOR := verilator 48 | VERILATOR_ROOT ?= $(shell bash -c '$(VERILATOR) -V|grep VERILATOR_ROOT | head -1 | sed -e " s/^.*=\s*//"') 49 | else 50 | VERILATOR := $(VERILATOR_ROOT)/bin/verilator 51 | endif 52 | export $(VERILATOR) 53 | VROOT := $(VERILATOR_ROOT) 54 | VINCD := $(VERILATOR_ROOT)/include 55 | INCS := -I $(VINCD) -I $(VINCD)/vlstd -I $(RTLD)/obj_dir 56 | CFLAGS := -O3 57 | PROGRAMS := tb_sdspi 58 | all: $(PROGRAMS) 59 | 60 | SOURCES := tb_sdspi.cpp sdspisim.cpp 61 | HEADERS := sdspisim.h wb_tb.h testb.h 62 | OBJECTS := $(addprefix $(OBJDIR)/,$(subst .cpp,.o,$(SOURCES))) 63 | VLSRCS := verilated.cpp verilated_vcd_c.cpp verilated_threads.cpp 64 | VLOBJS := $(addprefix $(OBJDIR)/,$(subst .cpp,.o,$(VLSRCS))) 65 | VLIBS := $(RTLD)/obj_dir/Vsdspi__ALL.a 66 | 67 | ## Build patterns: .cpp to .o 68 | ## {{{ 69 | $(OBJDIR)/%.o: %.cpp 70 | $(mk-objdir) 71 | $(CXX) $(CFLAGS) $(INCS) -c $< -o $@ 72 | 73 | $(OBJDIR)/%.o: $(VROOT)/include/%.cpp 74 | $(mk-objdir) 75 | $(CXX) $(CFLAGS) $(INCS) -c $< -o $@ 76 | ## }}} 77 | 78 | ## tb_sdspi 79 | ## {{{ 80 | tb_sdspi: $(OBJECTS) $(VLIBS) $(VLOBJS) 81 | $(CXX) $(CFLAGS) $(OBJECTS) $(VLIBS) $(VLOBJS) -lpthread -o $@ 82 | ## }}} 83 | 84 | sdcard.img: 85 | dd if=/dev/zero of=sdcard.img bs=512 count=131072 86 | mkfs.fat -F 16 sdcard.img 87 | 88 | ## test 89 | ## {{{ 90 | test: tb_sdspi sdcard.img 91 | ./tb_sdspi 92 | ## }}} 93 | 94 | define mk-objdir 95 | @bash -c "if [ ! -e $(OBJDIR) ]; then mkdir -p $(OBJDIR)/; fi" 96 | endef 97 | 98 | tags: $(SOURCES) $(HEADERS) 99 | @ctags $(SOURCES) 100 | 101 | .PHONY: clean 102 | ## {{{ 103 | clean: 104 | rm -rf $(OBJDIR)/ $(PROGRAMS) 105 | rm -f *.vcd 106 | ## }}} 107 | 108 | ## Dependency handling 109 | ## {{{ 110 | define build-depends 111 | @echo "Building dependencies" 112 | $(mk-objdir) 113 | @$(CXX) $(CPPFLAGS) $(INCS) -MM zipcpu_tb.cpp $(VLIB) $(SOURCES) > $(OBJDIR)/xdepends.txt 114 | @sed -e 's/^.*.o: /$(OBJDIR)\/&/' < $(OBJDIR)/xdepends.txt > $(OBJDIR)/depeends.txt 115 | @rm $(OBJDIR)/xdepends.txt 116 | endef 117 | 118 | .PHONY: depends 119 | depends: tags $(OBJDIR)/ 120 | $(build-depends) 121 | 122 | -include $(OBJDIR)/depends.txt 123 | ## }}} 124 | -------------------------------------------------------------------------------- /bench/cpp/sdiosim.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: bench/cpp/sdiosim.h 4 | // {{{ 5 | // Project: SD-Card controller 6 | // 7 | // Purpose: 8 | // 9 | // Creator: Dan Gisselquist, Ph.D. 10 | // Gisselquist Technology, LLC 11 | // 12 | //////////////////////////////////////////////////////////////////////////////// 13 | // }}} 14 | // Copyright (C) 2016-2025, Gisselquist Technology, LLC 15 | // {{{ 16 | // This program is free software (firmware): you can redistribute it and/or 17 | // modify it under the terms of the GNU General Public License as published 18 | // by the Free Software Foundation, either version 3 of the License, or (at 19 | // your option) any later version. 20 | // 21 | // This program is distributed in the hope that it will be useful, but WITHOUT 22 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 23 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 24 | // for more details. 25 | // 26 | // You should have received a copy of the GNU General Public License along 27 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no 28 | // target there if the PDF file isn't present.) If not, see 29 | // for a copy. 30 | // }}} 31 | // License: GPL, v3, as defined and found on www.gnu.org, 32 | // {{{ 33 | // http://www.gnu.org/licenses/gpl.html 34 | // 35 | //////////////////////////////////////////////////////////////////////////////// 36 | // 37 | // }}} 38 | #ifndef SDIOSIM_H 39 | #define SDIOSIM_H 40 | 41 | #include 42 | #include 43 | 44 | class SDIOSIM { 45 | static constexpr int DBUFLN = 512+2+32; 46 | bool HCS; 47 | 48 | FILE *m_fp; 49 | uint32_t m_buf[512/sizeof(uint32_t)]; 50 | bool m_readonly, m_reply_active, m_open_drain, m_ddr, 51 | m_cmd_started, m_reply_started; 52 | bool m_data_started, m_multiblock; 53 | uint32_t m_sector, m_data_posn; 54 | 55 | uint32_t m_last_dat, m_last_cmd, m_lastck, m_app_cmd, 56 | m_selected, m_RCA, m_width, m_drive, m_data_count, 57 | m_crctoken; 58 | char m_cmd_buf[8], m_cid[16], m_reply_buf[20], 59 | m_dbuf[DBUFLN], m_csd[16], m_scr[8]; 60 | uint32_t m_cmd_pos, m_reply_posn, m_reply_count, m_R1, 61 | m_reply_delay, m_data_delay, m_busy_cycles; 62 | bool m_debug; 63 | protected: 64 | void init(void); 65 | unsigned cmdbit(unsigned); 66 | unsigned datp(unsigned); 67 | unsigned datn(unsigned); 68 | void accept_command(void); 69 | void load_reply(int cmd, unsigned arg); 70 | void appendcrc(unsigned len_bytes); 71 | uint8_t cmdcrc(int ln, char *buf); 72 | unsigned blockcrc(unsigned fill, unsigned bit); 73 | void CID(void); 74 | void CSD(void); 75 | void SCR(void); 76 | public: 77 | // SDIOSIM(const unsigned lglen); 78 | SDIOSIM(const char *fname); 79 | void load(const unsigned addr, const char *fname); 80 | void load(const char *fname) { load(0, fname); } 81 | bool card_busy(void) const { return m_busy_cycles > 0; }; 82 | unsigned crctoken(void) const { return m_crctoken; }; 83 | void apply(unsigned sdclk, unsigned ddr, 84 | unsigned cmd_en, unsigned cmd_data, 85 | unsigned data_en, unsigned rx_en, unsigned tx_data, 86 | unsigned &o_sync, unsigned &async_sync, 87 | unsigned &async_data); 88 | }; 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /bench/cpp/sdspisim.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: bench/cpp/sdspisim.h 4 | // {{{ 5 | // Project: SD-Card controller 6 | // 7 | // Purpose: This library simulates the operation of a SPI commanded SD-Card, 8 | // such as might be found on a XuLA2-LX25 board made by xess.com. 9 | // 10 | // This simulator is for testing use in a Verilator/C++ environment, where 11 | // it would be used in place of the actual hardware. 12 | // 13 | // Creator: Dan Gisselquist, Ph.D. 14 | // Gisselquist Technology, LLC 15 | // 16 | //////////////////////////////////////////////////////////////////////////////// 17 | // }}} 18 | // Copyright (C) 2015-2025, Gisselquist Technology, LLC 19 | // {{{ 20 | // This program is free software (firmware): you can redistribute it and/or 21 | // modify it under the terms of the GNU General Public License as published 22 | // by the Free Software Foundation, either version 3 of the License, or (at 23 | // your option) any later version. 24 | // 25 | // This program is distributed in the hope that it will be useful, but WITHOUT 26 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 27 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 28 | // for more details. 29 | // 30 | // You should have received a copy of the GNU General Public License along 31 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no 32 | // target there if the PDF file isn't present.) If not, see 33 | // for a copy. 34 | // }}} 35 | // License: GPL, v3, as defined and found on www.gnu.org, 36 | // {{{ 37 | // http://www.gnu.org/licenses/gpl.html 38 | // 39 | //////////////////////////////////////////////////////////////////////////////// 40 | // 41 | // }}} 42 | #ifndef SDSPISIM_H 43 | #define SDSPISIM_H 44 | 45 | #include 46 | 47 | typedef enum eRESET_STATES { 48 | SDSPI_POWERUP_RESET, 49 | SDSPI_CMD0_IDLE, 50 | SDSPI_RCVD_CMD8, 51 | SDSPI_RCVD_ACMD41, 52 | SDSPI_RESET_COMPLETE, 53 | SDSPI_IN_OPERATION 54 | } RESET_STATES; 55 | 56 | #define SDSPI_RSPLEN 8 57 | #define SDSPI_MAXBLKLEN (1+2048+2) 58 | #define SDSPI_CSDLEN (16) 59 | #define SDSPI_CIDLEN (16) 60 | class SDSPISIM { 61 | FILE *m_dev; 62 | unsigned long m_devblocks; 63 | 64 | int m_last_sck, m_delay, m_mosi; 65 | bool m_busy, m_debug, m_block_address, m_altcmd_flag, 66 | m_syncd, m_host_supports_high_capacity, m_reading_data, 67 | m_have_token; 68 | 69 | RESET_STATES m_reset_state; 70 | 71 | int m_cmdidx, m_bitpos, m_rspidx, m_rspdly, m_blkdly, 72 | m_blklen, m_blkidx, m_last_miso, m_powerup_busy; 73 | unsigned m_rxloc; 74 | char m_cmdbuf[8], m_dat_out, m_dat_in; 75 | char m_rspbuf[SDSPI_RSPLEN]; 76 | char m_block_buf[SDSPI_MAXBLKLEN]; 77 | uint8_t m_csd[SDSPI_CSDLEN], m_cid[SDSPI_CIDLEN]; 78 | 79 | void CID(void); 80 | void CSD(void); 81 | unsigned read_bitfield(int, int, int, const uint8_t *); 82 | public: 83 | SDSPISIM(const bool debug = false); 84 | void load(const char *fname); 85 | void debug(const bool dbg) { m_debug = dbg; } 86 | bool debug(void) const { return m_debug; } 87 | int operator()(const int csn, const int sck, const int dat); 88 | unsigned cmdcrc(int ln, char *buf) const; 89 | bool check_cmdcrc(char *buf) const; 90 | unsigned blockcrc(int ln, char *buf) const; 91 | void add_block_crc(int ln, char *buf) const; 92 | 93 | unsigned OCR(void); 94 | uint8_t CSD(int index); 95 | uint8_t CID(int index); 96 | }; 97 | 98 | #endif 99 | -------------------------------------------------------------------------------- /bench/cpp/testb.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: bench/cpp/testb.h 4 | // {{{ 5 | // Project: SD-Card controller 6 | // 7 | // Purpose: A wrapper for a common interface to a clocked FPGA core 8 | // begin exercised in Verilator. 9 | // 10 | // Creator: Dan Gisselquist, Ph.D. 11 | // Gisselquist Technology, LLC 12 | // 13 | //////////////////////////////////////////////////////////////////////////////// 14 | // }}} 15 | // Copyright (C) 2016-2025, Gisselquist Technology, LLC 16 | // {{{ 17 | // This program is free software (firmware): you can redistribute it and/or 18 | // modify it under the terms of the GNU General Public License as published 19 | // by the Free Software Foundation, either version 3 of the License, or (at 20 | // your option) any later version. 21 | // 22 | // This program is distributed in the hope that it will be useful, but WITHOUT 23 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 24 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 25 | // for more details. 26 | // 27 | // You should have received a copy of the GNU General Public License along 28 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no 29 | // target there if the PDF file isn't present.) If not, see 30 | // for a copy. 31 | // }}} 32 | // License: GPL, v3, as defined and found on www.gnu.org, 33 | // {{{ 34 | // http://www.gnu.org/licenses/gpl.html 35 | // 36 | //////////////////////////////////////////////////////////////////////////////// 37 | // 38 | // }}} 39 | #ifndef TESTB_H 40 | #define TESTB_H 41 | 42 | #include 43 | #include 44 | #include 45 | 46 | #define TBASSERT(TB,A) do { if (!(A)) { (TB).closetrace(); } assert(A); } while(0); 47 | 48 | template class TESTB { 49 | public: 50 | VA *m_core; 51 | VerilatedVcdC* m_trace; 52 | uint64_t m_tickcount; 53 | 54 | TESTB(void) : m_trace(NULL), m_tickcount(0l) { 55 | // {{{ 56 | m_core = new VA; 57 | Verilated::traceEverOn(true); 58 | m_core->i_clk = 0; 59 | eval(); // Get our initial values set properly. 60 | } 61 | // }}} 62 | 63 | virtual ~TESTB(void) { 64 | // {{{ 65 | closetrace(); 66 | delete m_core; 67 | m_core = NULL; 68 | } 69 | // }}} 70 | 71 | virtual void opentrace(const char *vcdname) { 72 | // {{{ 73 | if (!m_trace) { 74 | m_trace = new VerilatedVcdC; 75 | m_core->trace(m_trace, 99); 76 | m_trace->open(vcdname); 77 | } 78 | } 79 | // }}} 80 | 81 | virtual void closetrace(void) { 82 | // {{{ 83 | if (m_trace) { 84 | m_trace->close(); 85 | delete m_trace; 86 | m_trace = NULL; 87 | } 88 | } 89 | // }}} 90 | 91 | virtual void eval(void) { 92 | // {{{ 93 | m_core->eval(); 94 | } 95 | // }}} 96 | 97 | virtual void tick(void) { 98 | // {{{ 99 | m_tickcount++; 100 | 101 | // Make sure we have our evaluations straight before the top 102 | // of the clock. This is necessary since some of the 103 | // connection modules may have made changes, for which some 104 | // logic depends. This forces that logic to be recalculated 105 | // before the top of the clock. 106 | eval(); 107 | if (m_trace) m_trace->dump((vluint64_t)(10*m_tickcount-2)); 108 | m_core->i_clk = 1; 109 | eval(); 110 | if (m_trace) m_trace->dump((vluint64_t)(10*m_tickcount)); 111 | m_core->i_clk = 0; 112 | eval(); 113 | if (m_trace) { 114 | m_trace->dump((vluint64_t)(10*m_tickcount+5)); 115 | m_trace->flush(); 116 | } 117 | } 118 | // }}} 119 | 120 | /* 121 | virtual void reset(void) { 122 | // {{{ 123 | m_core->i_reset = 1; 124 | tick(); 125 | m_core->i_reset = 0; 126 | // printf("RESET\n"); 127 | } 128 | // }}} 129 | */ 130 | 131 | unsigned long tickcount(void) { 132 | // {{{ 133 | return m_tickcount; 134 | } 135 | // }}} 136 | }; 137 | 138 | #endif 139 | -------------------------------------------------------------------------------- /bench/cpp/trace.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.66 (w)1999-2015 BSI 3 | [*] Tue Nov 12 20:01:32 2019 4 | [*] 5 | [timestart] 4385000 6 | [size] 1920 1054 7 | [pos] -1 -1 8 | *-17.791178 5726460 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 9 | [treeopen] TOP. 10 | [treeopen] TOP.sdspi. 11 | [treeopen] TOP.sdspi.lowlevel. 12 | [sst_width] 196 13 | [signals_width] 182 14 | [sst_expanded] 1 15 | [sst_vpaned_height] 315 16 | @28 17 | TOP.i_bus_grant 18 | TOP.i_sd_reset 19 | TOP.i_card_detect 20 | TOP.i_clk 21 | @200 22 | - 23 | @28 24 | [color] 2 25 | TOP.o_cs_n 26 | [color] 2 27 | TOP.o_sck 28 | [color] 2 29 | TOP.o_mosi 30 | [color] 3 31 | TOP.i_miso 32 | @200 33 | - 34 | @28 35 | TOP.sdspi.r_cmd_busy 36 | TOP.sdspi.ll_out_stb 37 | @22 38 | TOP.sdspi.ll_out_dat[7:0] 39 | @200 40 | - 41 | @28 42 | [color] 3 43 | TOP.i_wb_cyc 44 | [color] 3 45 | TOP.i_wb_stb 46 | [color] 3 47 | TOP.i_wb_we 48 | [color] 3 49 | TOP.i_wb_addr[1:0] 50 | @22 51 | [color] 3 52 | TOP.i_wb_data[31:0] 53 | [color] 3 54 | TOP.i_wb_sel[3:0] 55 | @28 56 | [color] 2 57 | TOP.o_wb_stall 58 | [color] 2 59 | TOP.o_wb_ack 60 | @22 61 | [color] 2 62 | TOP.o_wb_data[31:0] 63 | TOP.sdspi.r_data_reg[31:0] 64 | TOP.sdspi.spicmdi.o_response[39:0] 65 | TOP.sdspi.r_lgblklen[3:0] 66 | @200 67 | - 68 | @28 69 | TOP.o_int 70 | @200 71 | - 72 | @28 73 | TOP.sdspi.dbg_trigger 74 | @22 75 | TOP.o_debug[31:0] 76 | @201 77 | - 78 | @28 79 | TOP.sdspi.lowlevel.powerup_hold 80 | TOP.sdspi.lowlevel.startup_hold 81 | TOP.sdspi.card_removed 82 | @22 83 | TOP.sdspi.card_status[31:0] 84 | @28 85 | TOP.sdspi.card_present 86 | TOP.sdspi.card_removed 87 | @200 88 | - 89 | @28 90 | TOP.sdspi.r_cmd_err 91 | TOP.sdspi.spicmdi.i_reset 92 | TOP.sdspi.spicmdi.i_cmd_stb 93 | TOP.sdspi.cmd_busy 94 | TOP.sdspi.cmd_valid 95 | @22 96 | TOP.sdspi.cmd_response[39:0] 97 | @28 98 | TOP.sdspi.spicmdi.rx_r1_byte 99 | TOP.sdspi.spicmdi.rxvalid 100 | TOP.sdspi.rx_busy 101 | TOP.sdspi.tx_busy 102 | @22 103 | TOP.sdspi.spi_write_addr[7:0] 104 | TOP.sdspi.spi_read_addr[7:0] 105 | TOP.sdspi.spi_read_data[31:0] 106 | @28 107 | TOP.sdspi.spi_read_from_fifo 108 | TOP.sdspi.tx_stb 109 | [pattern_trace] 1 110 | [pattern_trace] 0 111 | -------------------------------------------------------------------------------- /bench/formal/.gitignore: -------------------------------------------------------------------------------- 1 | llsdcmd*/ 2 | llsdspi*/ 3 | spitxdata*/ 4 | spirxdata*/ 5 | spicmd*/ 6 | sdspi*/ 7 | # 8 | sdaxil*/ 9 | sdwb*/ 10 | sdckgen*/ 11 | sdcmd*/ 12 | sdrxframe*/ 13 | sdtxframe*/ 14 | -------------------------------------------------------------------------------- /bench/formal/faxil_register.v: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: bench/formal/faxil_register.v 4 | // {{{ 5 | // Project: SD-Card controller(s) 6 | // 7 | // Purpose: While it may be fairly easy to verify that a core follows the 8 | // bus protocol, it's another thing to prove that the answers it 9 | // returns are the right ones. 10 | // 11 | // This core is meant to be a complement to the fwb_slave logic, for slaves 12 | // that consist of a series of registers. This core will test whether a 13 | // register can be written to using Wishbone, and/or read back properly 14 | // later. It assumes a register having a single clock latency. 15 | // 16 | // Creator: Dan Gisselquist, Ph.D. 17 | // Gisselquist Technology, LLC 18 | // 19 | //////////////////////////////////////////////////////////////////////////////// 20 | // }}} 21 | // Copyright (C) 2020-2024, Gisselquist Technology, LLC 22 | // {{{ 23 | // This program is free software (firmware): you can redistribute it and/or 24 | // modify it under the terms of the GNU General Public License as published 25 | // by the Free Software Foundation, either version 3 of the License, or (at 26 | // your option) any later version. 27 | // 28 | // This program is distributed in the hope that it will be useful, but WITHOUT 29 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 30 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 31 | // for more details. 32 | // 33 | // You should have received a copy of the GNU General Public License along 34 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no 35 | // target there if the PDF file isn't present.) If not, see 36 | // for a copy. 37 | // }}} 38 | // License: GPL, v3, as defined and found on www.gnu.org, 39 | // {{{ 40 | // http://www.gnu.org/licenses/gpl.html 41 | // 42 | //////////////////////////////////////////////////////////////////////////////// 43 | // 44 | `default_nettype none 45 | // }}} 46 | module faxil_register #( 47 | // {{{ 48 | parameter AW = 4, 49 | parameter DW = 32, 50 | parameter [AW-1:0] ADDR = 0, 51 | parameter [DW-1:0] MASK = -1, 52 | parameter [DW-1:0] FIXED_BIT_MASK = 0, 53 | localparam AXILLSB = $clog2(DW/8), 54 | parameter [0:0] OPT_ASYNC_RESET = 1'b0, 55 | parameter [0:0] OPT_INITIAL = 1'b0 56 | // }}} 57 | ) ( 58 | // {{{ 59 | input wire S_AXI_ACLK, S_AXI_ARESETN, 60 | // 61 | input wire S_AXIL_AWW, 62 | input wire [AW-1:0] S_AXIL_AWADDR, 63 | input wire [DW-1:0] S_AXIL_WDATA, 64 | input wire [DW/8-1:0] S_AXIL_WSTRB, 65 | input wire S_AXIL_BVALID, 66 | // 67 | input wire S_AXIL_AR, 68 | input wire [AW-1:0] S_AXIL_ARADDR, 69 | input wire S_AXIL_RVALID, 70 | input wire [DW-1:0] S_AXIL_RDATA, 71 | input wire [DW-1:0] i_register 72 | // }}} 73 | ); 74 | 75 | // Local register, reset assumption 76 | // {{{ 77 | reg f_past_valid; 78 | reg [DW-1:0] f_reg; 79 | integer ik; 80 | reg [DW-1:0] non_ro_write; 81 | wire [31:0] error_mask; 82 | 83 | 84 | initial f_past_valid = 0; 85 | always @(posedge S_AXI_ACLK) 86 | f_past_valid <= 1; 87 | 88 | always @(*) 89 | if (!f_past_valid) 90 | assume(!S_AXI_ARESETN); 91 | 92 | always @(*) 93 | assert((MASK & FIXED_BIT_MASK) == 0); 94 | // }}} 95 | 96 | // f_reg -- A formal copy of the register of interest 97 | // {{{ 98 | always @(*) 99 | begin 100 | non_ro_write = f_reg; 101 | for(ik=0; ik < DW/8; ik=ik+1) 102 | if (S_AXIL_WSTRB[ik]) 103 | non_ro_write[ik*8 +: 8] = S_AXIL_WDATA[ik*8 +: 8]; 104 | 105 | non_ro_write = (non_ro_write & ~FIXED_BIT_MASK) 106 | | (f_reg & FIXED_BIT_MASK); 107 | end 108 | 109 | generate if (OPT_ASYNC_RESET) 110 | begin : OPT_ASYNC 111 | always @(posedge S_AXI_ACLK or negedge S_AXI_ARESETN) 112 | if (!S_AXI_ARESETN) 113 | f_reg <= i_register; 114 | else if (S_AXIL_AWW 115 | && S_AXIL_AWADDR[AW-1:AXILLSB] == ADDR[AW-1:AXILLSB]) 116 | begin 117 | f_reg <= non_ro_write; 118 | end 119 | end else begin : SYNC_RESET 120 | reg last_reset; 121 | 122 | initial last_reset = 1'b1; 123 | always @(posedge S_AXI_ACLK) 124 | last_reset <= !S_AXI_ARESETN; 125 | 126 | always @(posedge S_AXI_ACLK) 127 | if (last_reset) 128 | f_reg <= i_register; 129 | else if (S_AXIL_AWW 130 | && S_AXIL_AWADDR[AW-1:AXILLSB] == ADDR[AW-1:AXILLSB]) 131 | begin 132 | f_reg <= non_ro_write; 133 | end 134 | 135 | end endgenerate 136 | // }}} 137 | 138 | // Comparing f_reg against i_register 139 | // {{{ 140 | assign error_mask = (f_reg ^ i_register) & MASK; 141 | 142 | always @(posedge S_AXI_ACLK) 143 | if (S_AXI_ARESETN && $past(S_AXI_ARESETN)) 144 | assert(error_mask == 0); 145 | // }}} 146 | 147 | // Verifying S_AXIL_BVALID && S_AXIL_RVALID 148 | // {{{ 149 | // This is a challenge if for no other reason than that we don't 150 | // have access to the full protocol here. Therefore, we're only 151 | // going to verify that these flags are high--not that they fall 152 | // properly. 153 | always @(posedge S_AXI_ACLK) 154 | if (!f_past_valid || !$past(S_AXI_ARESETN) 155 | || (OPT_ASYNC_RESET && !S_AXI_ARESETN)) 156 | assert(!S_AXIL_BVALID || (!f_past_valid && !OPT_INITIAL)); 157 | else if ($past(S_AXIL_AWW 158 | && S_AXIL_AWADDR[AW-1:AXILLSB] == ADDR[AW-1:AXILLSB])) 159 | assert(S_AXIL_BVALID); 160 | 161 | always @(posedge S_AXI_ACLK) 162 | if (!f_past_valid || !$past(S_AXI_ARESETN) 163 | || (OPT_ASYNC_RESET && !S_AXI_ARESETN)) 164 | assert(!S_AXIL_RVALID || (!f_past_valid && !OPT_INITIAL)); 165 | else if ($past(S_AXIL_AR 166 | && S_AXIL_ARADDR[AW-1:AXILLSB] == ADDR[AW-1:AXILLSB])) 167 | assert(S_AXIL_RVALID); 168 | // }}} 169 | 170 | // Verifying S_AXIL_RDATA 171 | // {{{ 172 | always @(posedge S_AXI_ACLK) 173 | if (S_AXI_ARESETN && $past(S_AXI_ARESETN && S_AXIL_AR 174 | && S_AXIL_ARADDR[AW-1:AXILLSB] == ADDR[AW-1:AXILLSB])) 175 | assert(S_AXIL_RDATA == $past(i_register)); 176 | // }}} 177 | 178 | endmodule 179 | -------------------------------------------------------------------------------- /bench/formal/fclk.v: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: fclk.v 4 | // {{{ 5 | // Project: SD-Card controller 6 | // 7 | // Purpose: 8 | // 9 | // Creator: Dan Gisselquist, Ph.D. 10 | // Gisselquist Technology, LLC 11 | // 12 | //////////////////////////////////////////////////////////////////////////////// 13 | // }}} 14 | // Copyright (C) 2024, Gisselquist Technology, LLC 15 | // {{{ 16 | // This program is free software (firmware): you can redistribute it and/or 17 | // modify it under the terms of the GNU General Public License as published 18 | // by the Free Software Foundation, either version 3 of the License, or (at 19 | // your option) any later version. 20 | // 21 | // This program is distributed in the hope that it will be useful, but WITHOUT 22 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 23 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 24 | // for more details. 25 | // 26 | // You should have received a copy of the GNU General Public License along 27 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no 28 | // target there if the PDF file isn't present.) If not, see 29 | // for a copy. 30 | // }}} 31 | // License: GPL, v3, as defined and found on www.gnu.org, 32 | // {{{ 33 | // http://www.gnu.org/licenses/gpl.html 34 | // 35 | //////////////////////////////////////////////////////////////////////////////// 36 | // 37 | `default_nettype none 38 | // }}} 39 | module fclk #( 40 | parameter [0:0] OPT_SERDES = 1'b0, 41 | OPT_DDR = 1'b0 42 | ) ( 43 | // {{{ 44 | input wire i_clk, i_reset, 45 | // 46 | input wire i_en, 47 | input wire [7:0] i_ckspd, 48 | input wire i_clk90, 49 | // 50 | input wire i_ckstb, i_hlfck, 51 | input wire [7:0] i_ckwide, 52 | // 53 | output reg f_pending_reset, 54 | output reg f_pending_half 55 | // }}} 56 | ); 57 | 58 | `ifdef CKGEN 59 | `define SLAVE_ASSUME assert 60 | `else 61 | `define SLAVE_ASSUME assume 62 | `endif 63 | 64 | reg f_past_tick, f_past_valid; 65 | reg last_reset, last_en, last_pending; 66 | reg [7:0] last_ckspd; 67 | 68 | initial f_past_valid = 0; 69 | always @(posedge i_clk) 70 | f_past_valid <= 1; 71 | 72 | initial f_pending_reset = 1'b0; 73 | always @(posedge i_clk) 74 | if (i_reset) 75 | f_pending_reset <= 1'b1; 76 | else if (i_ckstb || i_hlfck) 77 | f_pending_reset <= 1'b0; 78 | 79 | initial f_pending_half = 1'b0; 80 | always @(posedge i_clk) 81 | if (i_reset) 82 | f_pending_half <= 1'b0; 83 | else if (i_ckstb) 84 | f_pending_half <= !i_hlfck; 85 | else if (i_hlfck) 86 | f_pending_half <= 1'b0; 87 | 88 | initial f_past_tick = 0; 89 | always @(posedge i_clk) 90 | f_past_tick <= i_ckstb || i_hlfck; 91 | 92 | // always @(*) 93 | // if (!i_reset && !f_pending_reset && i_en && i_ckspd == 2) 94 | // `SLAVE_ASSUME({ i_ckstb, i_hlfck } == (f_pending_half ? 2'b01:2'b10)); 95 | 96 | always @(posedge i_clk) 97 | if (!i_reset && !f_pending_reset) 98 | begin 99 | if (f_pending_half) 100 | `SLAVE_ASSUME(!i_ckstb); 101 | else if (i_hlfck) 102 | `SLAVE_ASSUME(i_ckstb); 103 | end 104 | 105 | always @(posedge i_clk) 106 | if (!i_reset) 107 | case(i_ckspd) 108 | 0: begin 109 | // {{{ 110 | `SLAVE_ASSUME(OPT_SERDES); 111 | `SLAVE_ASSUME(f_pending_reset || !f_pending_half); 112 | if (i_ckwide == 0) 113 | begin 114 | `SLAVE_ASSUME(f_pending_reset || (!i_ckstb && !i_hlfck)); 115 | end else begin 116 | `SLAVE_ASSUME(i_ckstb && i_hlfck); 117 | end 118 | 119 | if (i_clk90) 120 | begin 121 | `SLAVE_ASSUME(i_ckwide == 0 || i_ckwide == 8'h66); 122 | end else begin 123 | `SLAVE_ASSUME(i_ckwide == 0 || i_ckwide == 8'h33); 124 | end end 125 | // }}} 126 | 1: begin 127 | // {{{ 128 | if (i_ckwide == 0) 129 | begin 130 | `SLAVE_ASSUME(f_pending_reset || (!i_ckstb && !i_hlfck)); 131 | end else begin 132 | `SLAVE_ASSUME(i_ckstb && i_hlfck); 133 | end 134 | 135 | if (!f_pending_reset) 136 | `SLAVE_ASSUME(!f_pending_half); 137 | 138 | if (i_clk90) 139 | begin 140 | `SLAVE_ASSUME(i_ckwide == 0 || i_ckwide == 8'h3c); 141 | `SLAVE_ASSUME(OPT_SERDES); 142 | end else begin 143 | `SLAVE_ASSUME(i_ckwide == 0 || i_ckwide == 8'h0f); 144 | `SLAVE_ASSUME(OPT_SERDES || OPT_DDR); 145 | end end 146 | // }}} 147 | 2: begin 148 | // {{{ 149 | if (i_clk90) 150 | begin 151 | `SLAVE_ASSUME(i_ckwide == 0 || i_ckwide == 8'h0f || i_ckwide == 8'hf0); 152 | if (i_en) 153 | begin 154 | `SLAVE_ASSUME(i_ckwide != 0); 155 | end 156 | `SLAVE_ASSUME(OPT_SERDES || OPT_DDR); 157 | if (!f_pending_reset && f_pending_half) 158 | begin 159 | `SLAVE_ASSUME(i_ckwide == 8'hf0); 160 | end 161 | if (i_ckwide == 8'h00) 162 | begin 163 | `SLAVE_ASSUME(!i_ckstb && !i_hlfck); 164 | end else if (i_ckwide == 8'h0f) 165 | begin 166 | `SLAVE_ASSUME(i_ckstb); 167 | end else begin 168 | `SLAVE_ASSUME(i_hlfck); 169 | end 170 | end else begin 171 | `SLAVE_ASSUME(i_ckwide == 0 || i_ckwide == 8'hff); 172 | if (!f_pending_reset) 173 | begin 174 | if (i_ckstb) 175 | begin 176 | `SLAVE_ASSUME(1 || i_ckwide == 8'h00); 177 | end else if (i_hlfck) 178 | begin 179 | `SLAVE_ASSUME(1 || i_ckwide == 8'hff); 180 | end else if (f_pending_half) 181 | begin 182 | `SLAVE_ASSUME(1 || i_ckwide == 8'h00); 183 | end else // if (!f_pending_half) 184 | `SLAVE_ASSUME(1 || i_ckwide == 8'hff); 185 | end 186 | if (i_ckwide == 8'hff) 187 | `SLAVE_ASSUME(i_hlfck); 188 | end end 189 | // }}} 190 | default: begin 191 | `SLAVE_ASSUME(i_ckwide == 0 || i_ckwide == 8'hff); 192 | // if (f_past_tick && !f_pending_reset) 193 | // `SLAVE_ASSUME(!i_ckstb && !i_hlfck); 194 | if (!f_pending_reset && !i_clk90 && last_en && i_en) 195 | begin 196 | if (i_ckstb) 197 | begin 198 | `SLAVE_ASSUME(i_ckwide == 8'h00); 199 | end else if (i_hlfck) 200 | begin 201 | `SLAVE_ASSUME(i_ckwide == 8'hff); 202 | end else if (f_pending_half) 203 | begin 204 | `SLAVE_ASSUME(i_ckwide == 8'h00); 205 | end else // if (!f_pending_half) 206 | `SLAVE_ASSUME(i_ckwide == 8'hff); 207 | end 208 | end 209 | endcase 210 | 211 | always @(posedge i_clk) 212 | if (!OPT_SERDES && !OPT_DDR) 213 | assert(!i_ckstb || !i_hlfck); 214 | 215 | always @(posedge i_clk) 216 | if (f_past_valid && !last_reset && (last_en || i_ckstb || i_hlfck)) 217 | begin 218 | case(i_ckspd) 219 | 0: `SLAVE_ASSUME(!i_en || (i_ckstb && i_hlfck)); 220 | 1: `SLAVE_ASSUME(!i_en || (i_ckstb && i_hlfck)); 221 | default: 222 | `SLAVE_ASSUME(!i_ckstb || !i_hlfck); 223 | endcase 224 | end 225 | 226 | always @(posedge i_clk) 227 | last_reset <= i_reset; 228 | 229 | always @(posedge i_clk) 230 | last_en <= i_en; 231 | 232 | always @(posedge i_clk) 233 | last_ckspd <= i_ckspd; 234 | 235 | always @(posedge i_clk) 236 | last_pending <= f_pending_reset; 237 | 238 | always @(posedge i_clk) 239 | if (!i_reset && f_past_valid && !last_reset && last_en && i_en 240 | && i_ckspd == last_ckspd) 241 | begin 242 | if (i_ckspd <= 1) 243 | assert(i_ckstb && i_hlfck); 244 | end 245 | 246 | always @(posedge i_clk) 247 | if (!i_reset && f_past_valid && f_past_tick && !last_pending 248 | && last_ckspd == i_ckspd && i_ckspd >= 3) 249 | begin 250 | if (f_past_tick && !f_pending_reset) 251 | `SLAVE_ASSUME(!i_ckstb && !i_hlfck); 252 | end 253 | endmodule 254 | -------------------------------------------------------------------------------- /bench/formal/fwb_register.v: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: fwb_register.v 4 | // {{{ 5 | // Project: SD-Card controller, using a shared SPI interface 6 | // 7 | // Purpose: While it may be fairly easy to verify that a core follows the 8 | // bus protocol, it's another thing to prove that the answers it 9 | // returns are the right ones. 10 | // 11 | // This core is meant to be a complement to the fwb_slave logic, for slaves 12 | // that consist of a series of registers. This core will test whether a 13 | // register can be written to using Wishbone, and/or read back properly 14 | // later. It assumes a register having a single clock latency. 15 | // 16 | // Creator: Dan Gisselquist, Ph.D. 17 | // Gisselquist Technology, LLC 18 | // 19 | //////////////////////////////////////////////////////////////////////////////// 20 | // }}} 21 | // Copyright (C) 2023-2024, Gisselquist Technology, LLC 22 | // {{{ 23 | // This program is free software (firmware): you can redistribute it and/or 24 | // modify it under the terms of the GNU General Public License as published 25 | // by the Free Software Foundation, either version 3 of the License, or (at 26 | // your option) any later version. 27 | // 28 | // This program is distributed in the hope that it will be useful, but WITHOUT 29 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 30 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 31 | // for more details. 32 | // 33 | // You should have received a copy of the GNU General Public License along 34 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no 35 | // target there if the PDF file isn't present.) If not, see 36 | // for a copy. 37 | // }}} 38 | // License: GPL, v3, as defined and found on www.gnu.org, 39 | // {{{ 40 | // http://www.gnu.org/licenses/gpl.html 41 | // 42 | //////////////////////////////////////////////////////////////////////////////// 43 | // 44 | // 45 | `default_nettype none 46 | // }}} 47 | module fwb_register #( 48 | // {{{ 49 | parameter AW = 4, 50 | parameter DW = 32, 51 | parameter [AW-1:0] ADDR = 0, 52 | parameter [DW-1:0] MASK = -1, 53 | parameter [DW-1:0] FIXED_BIT_MASK = 0 54 | // }}} 55 | ) ( 56 | // {{{ 57 | input wire i_clk, i_reset, 58 | // 59 | input wire i_wb_stb, i_wb_we, 60 | input wire [AW-1:0] i_wb_addr, 61 | input wire [DW-1:0] i_wb_data, 62 | input wire [DW/8-1:0] i_wb_sel, 63 | input wire i_wb_ack, 64 | input wire [DW-1:0] i_wb_return, 65 | input wire [DW-1:0] i_register 66 | // }}} 67 | ); 68 | 69 | // Local register, reset assumption 70 | // {{{ 71 | integer ik; 72 | reg f_past_valid, past_reset; 73 | reg [DW-1:0] freg, non_ro_write, mask_write; 74 | wire [DW-1:0] error_mask; 75 | 76 | initial f_past_valid = 0; 77 | always @(posedge i_clk) 78 | f_past_valid <= 1; 79 | 80 | always @(*) 81 | if (!f_past_valid) 82 | assume(i_reset); 83 | 84 | always @(*) 85 | assert((MASK & FIXED_BIT_MASK) == 0); 86 | // }}} 87 | 88 | // freg 89 | // {{{ 90 | always @(*) 91 | begin 92 | mask_write = (i_reset || past_reset) ? i_register : freg; 93 | for(ik=0; ikFormal Verification Report 2 | 3 |

SD Controller Formal Verification Report

4 |

20250423

5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 |
StatusComponentProofComponent description
7 Cover pointsllsdspi_cvrLow-Level SPI handler
7 Cover pointsllsdspi_cvra
Passllsdspi_prfc
Passllsdspi_prfa
Passllsdspi_prf
Passsdaxil_prfdsSDIO AXI-Lite Bus handler
Passsdaxil_prf
Passsdaxil_prfdma
18 Cover pointssdaxil_cvr
Passsdaxil_prfdr
Passsdckgen_prfSDIO Divided clock generator
12 Cover pointssdckgen_cvrd
9 Cover pointssdckgen_cvr
Passsdckgen_prf8
Passsdckgen_prfd
14 Cover pointssdckgen_cvr8
8 Cover pointssdcmd_cvrSDIO CMD wire controller
Passsdcmd_prfds
Passsdcmd_prf
Passsdrxframe_prfSDIO receive data handler
Passsdrxframe_prfs4
Passsdrxframe_prfs
25 Cover pointssdrxframe_cvr
Passsdrxframe_prf4
Passsdspi_prfSDSPI Top level controller
Passsdtxframe_prfsSDIO transmit data controller
Passsdtxframe_prf4
12 Cover pointssdtxframe_cvr
Passsdtxframe_prfs4
43 Cover pointssdtxframe_cvrs
Passsdtxframe_prf
19 Cover pointssdwb_cvrSDIO Wishbone Bus handler
Passsdwb_prfds
Passsdwb_prf
Passsdwb_prfdma
Passsdwb_prfdr
Passspicmd_prfSPI Command processor
11 Cover pointsspicmd_cvr
Passspirxdata_prfSPI Data receive handler
Passspirxdata_prfle
16 Cover pointsspirxdata_cvr
Passspitxdata_prfleSPI Data transmit handler
Passspitxdata_prf
13 Cover pointsspitxdata_cvr
63 | 64 | -------------------------------------------------------------------------------- /bench/formal/sdaxil.sby: -------------------------------------------------------------------------------- 1 | [tasks] 2 | prf 3 | prfds prf opt_serdes opt_emmc opt_dma 4 | prfdr prf opt_ddr opt_dma 5 | prfdma prf opt_dma 6 | cvr opt_serdes opt_dma 7 | 8 | [options] 9 | prf: mode prove 10 | cvr: mode cover 11 | prf: depth 10 12 | cvr: depth 45 # Actually takes 43 steps, and about 4 hrs 13 | 14 | [engines] 15 | smtbmc 16 | 17 | [script] 18 | read -formal sdaxil.v 19 | read -formal sdskid.v 20 | read -formal faxil_slave.v 21 | read -formal faxil_register.v 22 | --pycode-begin-- 23 | cmd = "hierarchy -top sdaxil" 24 | cmd += " -chparam OPT_SERDES %d" % (1 if "opt_serdes" in tags else 0) 25 | cmd += " -chparam OPT_DDR %d" % (1 if "opt_ddr" in tags else 0) 26 | cmd += " -chparam OPT_DMA %d" % (1 if "opt_dma" in tags else 0) 27 | cmd += " -chparam OPT_EMMC %d" % (1 if "opt_emmc" in tags else 0) 28 | cmd += " -chparam NUMIO %d" % (8 if "opt_emmc" in tags else 4) 29 | output(cmd) 30 | --pycode-end-- 31 | proc -norom 32 | prep -top sdaxil 33 | 34 | [files] 35 | ../../rtl/sdaxil.v 36 | ../../rtl/sdskid.v 37 | faxil_slave.v 38 | faxil_register.v 39 | -------------------------------------------------------------------------------- /bench/formal/sdckgen.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.104 (w)1999-2020 BSI 3 | [*] Tue Aug 20 16:43:24 2024 4 | [*] 5 | [dumpfile] "(null)" 6 | [timestart] 0 7 | [size] 1574 990 8 | [pos] -1 -1 9 | *-5.795382 15 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 10 | [treeopen] sdckgen. 11 | [sst_width] 270 12 | [signals_width] 158 13 | [sst_expanded] 1 14 | [sst_vpaned_height] 276 15 | @28 16 | sdckgen.i_clk 17 | sdckgen.i_reset 18 | @200 19 | - 20 | @28 21 | sdckgen.f_past_valid 22 | @29 23 | sdckgen.f_pending_half 24 | @28 25 | sdckgen.f_pending_reset 26 | @200 27 | - 28 | @28 29 | sdckgen.i_cfg_shutdown 30 | sdckgen.i_cfg_clk90 31 | @22 32 | sdckgen.i_cfg_ckspd[7:0] 33 | @200 34 | - 35 | @28 36 | sdckgen.o_ckstb 37 | sdckgen.o_hlfck 38 | @22 39 | sdckgen.o_ckwide[7:0] 40 | sdckgen.o_ckspd[7:0] 41 | @200 42 | - 43 | @28 44 | sdckgen.f_en 45 | sdckgen.clk90 46 | @22 47 | sdckgen.ckspd[7:0] 48 | sdckgen.counter[9:0] 49 | @200 50 | - 51 | @28 52 | sdckgen.nxt_clk 53 | @22 54 | sdckgen.new_ckspd[7:0] 55 | @200 56 | - 57 | @22 58 | sdckgen.nxt_counter[9:0] 59 | @28 60 | sdckgen.nxt_stb 61 | @22 62 | sdckgen.w_ckspd[7:0] 63 | @28 64 | sdckgen.w_clk90 65 | @800200 66 | -FCLK 67 | @28 68 | sdckgen.u_ckprop.i_clk 69 | sdckgen.u_ckprop.i_reset 70 | @200 71 | - 72 | @28 73 | sdckgen.u_ckprop.i_en 74 | sdckgen.u_ckprop.i_clk90 75 | @22 76 | sdckgen.u_ckprop.i_ckspd[7:0] 77 | @200 78 | - 79 | @28 80 | sdckgen.u_ckprop.i_ckstb 81 | sdckgen.u_ckprop.i_hlfck 82 | @22 83 | sdckgen.u_ckprop.i_ckwide[7:0] 84 | @1000200 85 | -FCLK 86 | [pattern_trace] 1 87 | [pattern_trace] 0 88 | -------------------------------------------------------------------------------- /bench/formal/sdckgen.sby: -------------------------------------------------------------------------------- 1 | [tasks] 2 | prf 3 | prfd prf ddr 4 | prf8 prf serdes 5 | cvr 6 | cvrd cvr ddr 7 | cvr8 cvr serdes 8 | 9 | [options] 10 | prf: mode prove 11 | prf: depth 5 12 | cvr: mode cover 13 | cvr: depth 54 14 | 15 | [engines] 16 | smtbmc 17 | 18 | [script] 19 | read -define CKGEN 20 | read -formal sdckgen.v 21 | read -formal fclk.v 22 | --pycode-begin-- 23 | cmd = "hierarchy -top sdckgen" 24 | cmd += " -chparam OPT_SERDES %d" % (1 if "serdes" in tags else 0) 25 | cmd += " -chparam OPT_DDR %d" % (1 if "ddr" in tags else 0) 26 | output(cmd) 27 | --pycode-end-- 28 | prep -top sdckgen 29 | 30 | [files] 31 | ../../rtl/sdckgen.v 32 | fclk.v 33 | -------------------------------------------------------------------------------- /bench/formal/sdcmd.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.4.0 (w)1999-2022 BSI 3 | [*] Fri Jul 7 18:46:12 2023 4 | [*] 5 | [dumpfile] "(null)" 6 | [timestart] 0 7 | [size] 1454 600 8 | [pos] -1 -1 9 | *-6.348147 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 10 | [sst_width] 362 11 | [signals_width] 182 12 | [sst_expanded] 1 13 | [sst_vpaned_height] 156 14 | @28 15 | sdcmd.i_clk 16 | sdcmd.i_reset 17 | sdcmd.i_cfg_dbl 18 | sdcmd.i_cfg_ds 19 | sdcmd.i_ckstb 20 | @200 21 | - 22 | @800200 23 | -CMD 24 | @28 25 | sdcmd.i_cmd_request 26 | sdcmd.o_busy 27 | @22 28 | sdcmd.i_cmd[5:0] 29 | @28 30 | sdcmd.i_cmd_type[1:0] 31 | @22 32 | sdcmd.i_arg[31:0] 33 | @1000200 34 | -CMD 35 | @c00200 36 | -REPLY 37 | @28 38 | sdcmd.o_cmd_response 39 | @22 40 | sdcmd.o_resp[5:0] 41 | sdcmd.o_arg[31:0] 42 | @28 43 | sdcmd.o_err 44 | sdcmd.o_ercode[1:0] 45 | @1401200 46 | -REPLY 47 | @c00200 48 | -MEM 49 | @28 50 | sdcmd.o_mem_valid 51 | @22 52 | sdcmd.o_mem_addr[8:0] 53 | sdcmd.o_mem_data[31:0] 54 | sdcmd.o_mem_strb[3:0] 55 | @1401200 56 | -MEM 57 | @c00200 58 | -IO 59 | @28 60 | sdcmd.o_cmd_en 61 | sdcmd.o_cmd_data[1:0] 62 | sdcmd.i_cmd_data[1:0] 63 | sdcmd.i_cmd_strb[1:0] 64 | @1401200 65 | -IO 66 | @28 67 | sdcmd.r_busy 68 | sdcmd.o_done 69 | @200 70 | - 71 | @28 72 | sdcmd.waiting_on_response 73 | sdcmd.active 74 | @22 75 | sdcmd.srcount[5:0] 76 | @28 77 | sdcmd.w_no_response 78 | sdcmd.rx_timeout 79 | [pattern_trace] 1 80 | [pattern_trace] 0 81 | -------------------------------------------------------------------------------- /bench/formal/sdcmd.sby: -------------------------------------------------------------------------------- 1 | [tasks] 2 | prf 3 | prfds prf opt_ds 4 | cvr 5 | 6 | [options] 7 | prf: mode prove 8 | cvr: mode cover 9 | prf: depth 8 10 | cvr: depth 60 11 | 12 | [engines] 13 | smtbmc 14 | 15 | [script] 16 | read -formal sdcmd.v 17 | --pycode-begin-- 18 | cmd = "hierarchy -top sdcmd" 19 | cmd += " -chparam OPT_EMMC 1" 20 | cmd += " -chparam OPT_DS %d" % ( 1 if "opt_ds" in tags else 0) 21 | output(cmd) 22 | --pycode-end-- 23 | proc -norom 24 | prep -top sdcmd 25 | 26 | [files] 27 | ../../rtl/sdcmd.v 28 | -------------------------------------------------------------------------------- /bench/formal/sdrxframe.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.4.0 (w)1999-2022 BSI 3 | [*] Fri Jul 14 20:27:46 2023 4 | [*] 5 | [dumpfile] "(null)" 6 | [timestart] 0 7 | [size] 2043 712 8 | [pos] 223 -122 9 | *-4.786479 40 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 10 | [sst_width] 362 11 | [signals_width] 174 12 | [sst_expanded] 1 13 | [sst_vpaned_height] 196 14 | @28 15 | sdrxframe.i_clk 16 | sdrxframe.i_reset 17 | sdrxframe.i_rx_en 18 | @800200 19 | -CONFIG 20 | @28 21 | sdrxframe.i_cfg_ddr 22 | sdrxframe.i_cfg_ds 23 | sdrxframe.i_cfg_width[1:0] 24 | sdrxframe.i_crc_en 25 | @22 26 | sdrxframe.i_length[15:0] 27 | @1000200 28 | -CONFIG 29 | @28 30 | sdrxframe.i_rx_strb[1:0] 31 | @22 32 | sdrxframe.i_rx_data[15:0] 33 | @200 34 | - 35 | @28 36 | sdrxframe.S_ASYNC_VALID 37 | @22 38 | sdrxframe.S_ASYNC_DATA[31:0] 39 | @c00200 40 | -STATE 41 | @28 42 | sdrxframe.busy 43 | sdrxframe.o_done 44 | sdrxframe.o_err 45 | sdrxframe.w_done 46 | @200 47 | - 48 | @28 49 | sdrxframe.last_strb 50 | sdrxframe.r_watchdog 51 | sdrxframe.data_phase 52 | sdrxframe.load_crc 53 | @1401200 54 | -STATE 55 | @c00200 56 | -PCHAIN 57 | @22 58 | sdrxframe.sync_fill[4:0] 59 | sdrxframe.sync_sreg[19:0] 60 | @200 61 | - 62 | @28 63 | sdrxframe.s2_valid 64 | sdrxframe.s2_fill[1:0] 65 | @22 66 | sdrxframe.s2_data[15:0] 67 | @1401200 68 | -PCHAIN 69 | @28 70 | sdrxframe.f_state 71 | @800201 72 | -MEM 73 | @29 74 | sdrxframe.o_mem_valid 75 | @23 76 | sdrxframe.o_mem_addr[12:0] 77 | sdrxframe.o_mem_data[31:0] 78 | sdrxframe.o_mem_strb[3:0] 79 | @29 80 | sdrxframe.subaddr[1:0] 81 | sdrxframe.mem_full 82 | sdrxframe.next_subaddr[1:0] 83 | @1000201 84 | -MEM 85 | @22 86 | sdrxframe.fc_posn[15:0] 87 | sdrxframe.fc_data[7:0] 88 | @200 89 | - 90 | @22 91 | sdrxframe.f_count[18:0] 92 | sdrxframe.f_recount[15:0] 93 | sdrxframe.fmem_count[15:0] 94 | sdrxframe.rail_count[18:0] 95 | @200 96 | - 97 | [pattern_trace] 1 98 | [pattern_trace] 0 99 | -------------------------------------------------------------------------------- /bench/formal/sdrxframe.sby: -------------------------------------------------------------------------------- 1 | [tasks] 2 | prf opt_ds 3 | prf4 prf opt_ds 4 | prfs prf 5 | prfs4 prf prf4 6 | cvr opt_ds 7 | 8 | [options] 9 | prf: mode prove 10 | depth 8 11 | cvr: mode cover 12 | cvr: depth 30 13 | 14 | [engines] 15 | smtbmc 16 | 17 | [script] 18 | read -formal sdrxframe.v 19 | --pycode-begin-- 20 | cmd = "hierarchy -top sdrxframe" 21 | cmd += " -chparam OPT_DS %d" % (1 if "opt_ds" in tags else 0) 22 | cmd += " -chparam NUMIO %d" % (4 if "prf4" in tags else 8) 23 | output(cmd) 24 | --pycode-end-- 25 | proc -norom 26 | prep -top sdrxframe 27 | 28 | [files] 29 | ../../rtl/sdrxframe.v 30 | -------------------------------------------------------------------------------- /bench/formal/sdspi.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.66 (w)1999-2015 BSI 3 | [*] Thu Nov 7 20:00:51 2019 4 | [*] 5 | [dumpfile_mtime] "Thu Nov 7 19:56:31 2019" 6 | [dumpfile_size] 20245 7 | [timestart] 0 8 | [size] 1563 803 9 | [pos] 1919 249 10 | *-3.628906 30 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 11 | [treeopen] sdspi. 12 | [sst_width] 196 13 | [signals_width] 238 14 | [sst_expanded] 1 15 | [sst_vpaned_height] 227 16 | @28 17 | sdspi.i_clk 18 | sdspi.i_sd_reset 19 | sdspi.i_card_detect 20 | @22 21 | sdspi.r_sdspi_clk[6:0] 22 | @c00200 23 | -Wishbone 24 | @28 25 | sdspi.i_wb_cyc 26 | sdspi.i_wb_stb 27 | sdspi.i_wb_we 28 | sdspi.i_wb_addr[1:0] 29 | @22 30 | sdspi.i_wb_data[31:0] 31 | sdspi.i_wb_sel[3:0] 32 | @28 33 | sdspi.o_wb_stall 34 | sdspi.o_wb_ack 35 | @22 36 | sdspi.o_wb_data[31:0] 37 | @1401200 38 | -Wishbone 39 | @c00200 40 | -SPI 41 | @28 42 | sdspi.o_cs_n 43 | sdspi.o_sck 44 | sdspi.o_mosi 45 | sdspi.i_miso 46 | @1401200 47 | -SPI 48 | @28 49 | sdspi.o_int 50 | @22 51 | sdspi.o_debug[31:0] 52 | @200 53 | - 54 | @28 55 | sdspi.card_present 56 | sdspi.card_removed 57 | @200 58 | - 59 | @28 60 | sdspi.wb_stb 61 | sdspi.write_stb 62 | sdspi.cmd_stb 63 | sdspi.new_data 64 | sdspi.wb_addr[1:0] 65 | @22 66 | sdspi.wb_data[31:0] 67 | @200 68 | - 69 | @22 70 | sdspi.card_status[21:0] 71 | @200 72 | - 73 | @28 74 | sdspi.r_cmd_busy 75 | sdspi.ll_cmd_stb 76 | @22 77 | sdspi.ll_cmd_dat[7:0] 78 | @28 79 | sdspi.ll_idle 80 | sdspi.ll_out_stb 81 | @22 82 | sdspi.ll_out_dat[7:0] 83 | @200 84 | - 85 | @22 86 | sdspi.r1_seq[4:0] 87 | @201 88 | - 89 | @22 90 | sdspi.cmd_crc[7:0] 91 | @28 92 | sdspi.r_cmd_crc_stb 93 | @22 94 | sdspi.r_cmd_crc[7:0] 95 | sdspi.r_cmd_crc_cnt[3:0] 96 | @28 97 | sdspi.r_cmd_crc_ff 98 | sdspi.r_cmd_err 99 | sdspi.r_cmd_resp[1:0] 100 | sdspi.r_cmd_sent 101 | sdspi.r_cmd_state[2:0] 102 | @200 103 | - 104 | @28 105 | sdspi.clear_fifo_crc 106 | sdspi.dly_stb 107 | sdspi.f_nacks[2:0] 108 | sdspi.f_nreqs[2:0] 109 | sdspi.f_outstanding[2:0] 110 | sdspi.f_past_valid 111 | @22 112 | sdspi.fifo_a_byte[7:0] 113 | sdspi.fifo_a_mem_0<00>[7:0] 114 | sdspi.fifo_a_mem_1<00>[7:0] 115 | sdspi.fifo_a_mem_2<00>[7:0] 116 | sdspi.fifo_a_mem_3<00>[7:0] 117 | sdspi.fifo_a_reg[31:0] 118 | @28 119 | sdspi.fifo_a_wr 120 | @22 121 | sdspi.fifo_a_wr_addr[6:0] 122 | sdspi.fifo_a_wr_data[31:0] 123 | sdspi.fifo_a_wr_mask[3:0] 124 | sdspi.fifo_b_byte[7:0] 125 | sdspi.fifo_b_mem_0<00>[7:0] 126 | sdspi.fifo_b_mem_1<00>[7:0] 127 | sdspi.fifo_b_mem_2<00>[7:0] 128 | sdspi.fifo_b_mem_3<00>[7:0] 129 | sdspi.fifo_b_reg[31:0] 130 | @28 131 | sdspi.fifo_b_wr 132 | @22 133 | sdspi.fifo_b_wr_addr[6:0] 134 | sdspi.fifo_b_wr_data[31:0] 135 | sdspi.fifo_b_wr_mask[3:0] 136 | sdspi.fifo_byte[7:0] 137 | @28 138 | sdspi.fifo_crc_err 139 | @22 140 | sdspi.fifo_rd_crc_count[3:0] 141 | sdspi.fifo_rd_crc_reg[15:0] 142 | @28 143 | sdspi.fifo_rd_crc_stb 144 | @22 145 | sdspi.fifo_wb_addr[6:0] 146 | sdspi.fifo_wr_crc_count[3:0] 147 | sdspi.fifo_wr_crc_reg[15:0] 148 | @28 149 | sdspi.fifo_wr_crc_stb 150 | sdspi.last_fifo_byte 151 | @22 152 | sdspi.ll_fifo_addr[8:0] 153 | @28 154 | sdspi.ll_fifo_pkt_state[2:0] 155 | sdspi.ll_fifo_rd 156 | sdspi.ll_fifo_rd_complete 157 | sdspi.ll_fifo_wr 158 | sdspi.ll_fifo_wr_complete 159 | sdspi.ll_fifo_wr_state[1:0] 160 | @22 161 | sdspi.max_lgblklen[3:0] 162 | @28 163 | sdspi.need_reset 164 | sdspi.nonzero_out 165 | sdspi.pipe_addr[1:0] 166 | sdspi.pre_cmd_state 167 | sdspi.pre_fifo_a_wr 168 | sdspi.pre_fifo_addr_inc_rd 169 | sdspi.pre_fifo_addr_inc_wr 170 | sdspi.pre_fifo_b_wr 171 | sdspi.pre_fifo_crc_a 172 | sdspi.pre_fifo_crc_b 173 | sdspi.pre_rsp_state 174 | sdspi.q_busy 175 | @22 176 | sdspi.r_blklimit[6:0] 177 | @28 178 | sdspi.r_data_fil[1:0] 179 | @22 180 | sdspi.r_data_reg[31:0] 181 | @28 182 | sdspi.r_data_response_token[1:0] 183 | sdspi.r_err_token 184 | sdspi.r_fifo_id 185 | sdspi.r_fifo_wr 186 | sdspi.r_have_data_response_token 187 | sdspi.r_have_resp 188 | sdspi.r_have_start_token 189 | @22 190 | sdspi.r_last_r_one[7:0] 191 | sdspi.r_lgblklen[3:0] 192 | sdspi.r_read_err_token[3:0] 193 | @28 194 | sdspi.r_rsp_state[2:0] 195 | @22 196 | sdspi.r_sdspi_clk[6:0] 197 | @28 198 | sdspi.r_use_fifo 199 | @22 200 | sdspi.r_watchdog[25:0] 201 | @28 202 | sdspi.r_watchdog_err 203 | sdspi.ready_for_response_token 204 | sdspi.second_rsp_state[2:0] 205 | sdspi.unused 206 | @22 207 | sdspi.w_blklimit[8:0] 208 | [pattern_trace] 1 209 | [pattern_trace] 0 210 | -------------------------------------------------------------------------------- /bench/formal/sdspi.sby: -------------------------------------------------------------------------------- 1 | [tasks] 2 | prf 3 | cvr 4 | 5 | [options] 6 | prf: mode prove 7 | prf: depth 20 8 | cvr: mode cover 9 | cvr: depth 900 10 | 11 | [engines] 12 | smtbmc boolector 13 | 14 | [script] 15 | read -formal fwb_slave.v 16 | read -formal llsdspi.v 17 | read -formal spicmd.v 18 | read -formal spirxdata.v 19 | read -formal spitxdata.v 20 | read -formal sdspi.v 21 | hierarchy -top sdspi -chparam POWERUP_IDLE 3 -chparam INITIAL_CLKDIV 1 22 | # -chparam STARTUP_CLOCKS 2 23 | # hierarchy -top sdspi -chparam STARTUP_CLOCKS 2 -chparam POWERUP_IDLE 3 -chparam INITIAL_CLKDIV 1 24 | prep -top sdspi 25 | 26 | [files] 27 | fwb_slave.v 28 | ../../rtl/llsdspi.v 29 | ../../rtl/spicmd.v 30 | ../../rtl/spirxdata.v 31 | ../../rtl/spitxdata.v 32 | ../../rtl/sdspi.v 33 | -------------------------------------------------------------------------------- /bench/formal/sdtxframe.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.4.0 (w)1999-2022 BSI 3 | [*] Mon Jul 3 23:06:36 2023 4 | [*] 5 | [dumpfile_mtime] "Mon Jul 3 23:05:56 2023" 6 | [dumpfile_size] 173733 7 | [timestart] 0 8 | [size] 1406 891 9 | [pos] -1 -1 10 | *-5.748147 190 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 11 | [sst_width] 362 12 | [signals_width] 158 13 | [sst_expanded] 1 14 | [sst_vpaned_height] 258 15 | @28 16 | sdtxframe.i_clk 17 | sdtxframe.i_reset 18 | sdtxframe.i_en 19 | sdtxframe.i_cfg_ddr 20 | @22 21 | sdtxframe.i_cfg_spd[7:0] 22 | @28 23 | sdtxframe.i_cfg_width[1:0] 24 | @200 25 | - 26 | @28 27 | sdtxframe.i_ckstb 28 | sdtxframe.i_hlfck 29 | @200 30 | - 31 | @28 32 | sdtxframe.S_VALID 33 | sdtxframe.S_READY 34 | @22 35 | sdtxframe.S_DATA[31:0] 36 | @28 37 | sdtxframe.S_LAST 38 | @200 39 | - 40 | @28 41 | sdtxframe.tx_valid 42 | @22 43 | sdtxframe.tx_data[31:0] 44 | @200 45 | - 46 | @28 47 | sdtxframe.pstate[1:0] 48 | @22 49 | sdtxframe.ck_counts[4:0] 50 | @200 51 | - 52 | @22 53 | sdtxframe.fb_count[14:0] 54 | sdtxframe.fd_count[14:0] 55 | sdtxframe.fd_offset[5:0] 56 | sdtxframe.fd_count[14:0] 57 | sdtxframe.fs_count[9:0] 58 | @29 59 | sdtxframe.fs_last 60 | [pattern_trace] 1 61 | [pattern_trace] 0 62 | -------------------------------------------------------------------------------- /bench/formal/sdtxframe.sby: -------------------------------------------------------------------------------- 1 | [tasks] 2 | prf 3 | prf4 prf 4 | prfs prf serdes 5 | prfs4 prf prf4 serdes 6 | cvr 7 | cvrs cvr serdes 8 | 9 | [options] 10 | prf: mode prove 11 | prf: depth 5 12 | cvr: mode cover 13 | cvr: depth 96 14 | 15 | [engines] 16 | smtbmc 17 | 18 | [script] 19 | read -formal sdtxframe.v 20 | read -formal fclk.v 21 | --pycode-begin-- 22 | cmd = "hierarchy -top sdtxframe" 23 | cmd += " -chparam OPT_SERDES %d" % (1 if "serdes" in tags else 0) 24 | cmd += " -chparam NUMIO %d" % (4 if "prf4" in tags else 8) 25 | output(cmd) 26 | --pycode-end-- 27 | proc -norom 28 | prep -top sdtxframe 29 | 30 | [files] 31 | ../../rtl/sdtxframe.v 32 | fclk.v 33 | -------------------------------------------------------------------------------- /bench/formal/sdwb.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.104 (w)1999-2020 BSI 3 | [*] Mon Feb 19 15:27:43 2024 4 | [*] 5 | [dumpfile_mtime] "Mon Feb 19 15:25:52 2024" 6 | [dumpfile_size] 223025 7 | [timestart] 3 8 | [size] 1918 600 9 | [pos] -1 -1 10 | *-4.641469 180 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 11 | [treeopen] sdwb. 12 | [sst_width] 270 13 | [signals_width] 203 14 | [sst_expanded] 1 15 | [sst_vpaned_height] 143 16 | @28 17 | sdwb.i_clk 18 | sdwb.i_reset 19 | @c00200 20 | -REQUEST 21 | @28 22 | sdwb.new_cmd_request 23 | sdwb.new_data_request 24 | sdwb.new_dma_request 25 | sdwb.new_r2_request 26 | sdwb.new_tx_request 27 | @1401200 28 | -REQUEST 29 | @c00200 30 | >25 31 | -BUS 32 | @28 33 | >0 34 | sdwb.bus_write 35 | sdwb.bus_wraddr[2:0] 36 | @22 37 | sdwb.bus_wdata[31:0] 38 | sdwb.bus_wstrb[3:0] 39 | @28 40 | sdwb.dma_write 41 | @1401200 42 | >25 43 | -BUS 44 | @28 45 | >0 46 | sdwb.r_mem_busy 47 | @22 48 | sdwb.fif_rdaddr[12:0] 49 | sdwb.fif_wraddr[12:0] 50 | @23 51 | sdwb.GEN_DMA_COMMANDS.f_dma_rdaddr[12:0] 52 | @28 53 | sdwb.r_fifo 54 | @c00200 55 | -DMA 56 | @28 57 | sdwb.dma_zero_len 58 | sdwb.dma_busy 59 | sdwb.GEN_DMA_COMMANDS.dma_stopped 60 | sdwb.GEN_DMA_COMMANDS.r_tx 61 | @22 62 | sdwb.GEN_DMA_COMMANDS.f_rx_blocks[31:0] 63 | sdwb.GEN_DMA_COMMANDS.f_tx_blocks[31:0] 64 | sdwb.GEN_DMA_COMMANDS.r_block_count[31:0] 65 | @28 66 | sdwb.GEN_DMA_COMMANDS.r_dma_loaded[1:0] 67 | sdwb.i_dma_busy 68 | [color] 1 69 | sdwb.i_dma_err 70 | sdwb.dma_error 71 | sdwb.o_dma_abort 72 | @200 73 | - 74 | @28 75 | sdwb.o_dma_s2sd 76 | sdwb.i_s2sd_valid 77 | sdwb.o_s2sd_ready 78 | @22 79 | sdwb.i_s2sd_data[31:0] 80 | @200 81 | - 82 | @28 83 | sdwb.o_dma_sd2s 84 | sdwb.o_sd2s_valid 85 | sdwb.i_sd2s_ready 86 | sdwb.GEN_DMA_COMMANDS.pre_dma_valid 87 | @22 88 | sdwb.o_sd2s_data[31:0] 89 | @28 90 | sdwb.o_sd2s_last 91 | @200 92 | - 93 | @22 94 | sdwb.dma_addr_return[63:0] 95 | @28 96 | sdwb.dma_fifo 97 | sdwb.dma_last 98 | @22 99 | sdwb.dma_len_return[31:0] 100 | @28 101 | sdwb.dma_read_fifo 102 | sdwb.dma_write 103 | @22 104 | sdwb.o_dma_addr[29:0] 105 | sdwb.o_dma_len[15:0] 106 | @1401200 107 | -DMA 108 | @28 109 | sdwb.cmd_busy 110 | @c00200 111 | -TX 112 | @28 113 | sdwb.r_tx_request 114 | sdwb.o_tx_en 115 | sdwb.o_tx_mem_valid 116 | sdwb.i_tx_mem_ready 117 | @22 118 | sdwb.o_tx_mem_data[31:0] 119 | @28 120 | sdwb.o_tx_mem_last 121 | @1401200 122 | -TX 123 | @c00200 124 | -RX 125 | @28 126 | sdwb.r_rx_request 127 | sdwb.o_rx_en 128 | sdwb.i_rx_done 129 | sdwb.i_rx_mem_valid 130 | @22 131 | sdwb.i_rx_mem_strb[3:0] 132 | sdwb.i_rx_mem_addr[12:0] 133 | sdwb.i_rx_mem_data[31:0] 134 | @28 135 | sdwb.r_rx_ecode 136 | sdwb.r_rx_err 137 | @1401200 138 | -RX 139 | [pattern_trace] 1 140 | [pattern_trace] 0 141 | -------------------------------------------------------------------------------- /bench/formal/sdwb.sby: -------------------------------------------------------------------------------- 1 | [tasks] 2 | prf 3 | prfds prf opt_serdes opt_emmc opt_dma 4 | prfdr prf opt_ddr opt_dma 5 | prfdma prf opt_dma 6 | cvr opt_serdes opt_dma 7 | 8 | [options] 9 | prf: mode prove 10 | cvr: mode cover 11 | prf: depth 10 12 | cvr: depth 45 # Actually takes 42 steps, and about 4hrs 13 | 14 | [engines] 15 | smtbmc 16 | 17 | [script] 18 | read -formal sdwb.v 19 | read -formal fwb_slave.v 20 | read -formal fwb_register.v 21 | --pycode-begin-- 22 | cmd = "hierarchy -top sdwb" 23 | cmd += " -chparam OPT_SERDES %d" % (1 if "opt_serdes" in tags else 0) 24 | cmd += " -chparam OPT_DDR %d" % (1 if "opt_ddr" in tags else 0) 25 | cmd += " -chparam OPT_DMA %d" % (1 if "opt_dma" in tags else 0) 26 | cmd += " -chparam OPT_EMMC %d" % (1 if "opt_emmc" in tags else 0) 27 | cmd += " -chparam OPT_CRCTOKEN 1" 28 | cmd += " -chparam NUMIO %d" % (8 if "opt_emmc" in tags else 4) 29 | output(cmd) 30 | --pycode-end-- 31 | proc -norom 32 | prep -top sdwb 33 | 34 | [files] 35 | ../../rtl/sdwb.v 36 | fwb_slave.v 37 | fwb_register.v 38 | -------------------------------------------------------------------------------- /bench/formal/spicmd.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.86 (w)1999-2017 BSI 3 | [*] Fri Nov 8 03:34:23 2019 4 | [*] 5 | [dumpfile] "(null)" 6 | [timestart] 422 7 | [size] 1920 1021 8 | [pos] -1 -1 9 | *-3.795382 470 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 10 | [sst_width] 270 11 | [signals_width] 230 12 | [sst_expanded] 1 13 | [sst_vpaned_height] 291 14 | @28 15 | spicmd.i_reset 16 | spicmd.i_clk 17 | @200 18 | - 19 | @28 20 | spicmd.i_cmd_stb 21 | @22 22 | spicmd.i_cmd[5:0] 23 | spicmd.i_cmd_data[31:0] 24 | @28 25 | spicmd.i_cmd_type[1:0] 26 | @200 27 | - 28 | @28 29 | spicmd.i_ll_busy 30 | spicmd.i_ll_stb 31 | @22 32 | spicmd.i_ll_byte[7:0] 33 | @200 34 | - 35 | @28 36 | spicmd.o_busy 37 | spicmd.o_ll_stb 38 | @22 39 | spicmd.o_ll_byte[7:0] 40 | @200 41 | - 42 | @28 43 | spicmd.o_cmd_sent 44 | spicmd.o_rxvalid 45 | @22 46 | spicmd.o_response[39:0] 47 | @200 48 | - 49 | @28 50 | spicmd.f_send_seq[2:0] 51 | @22 52 | spicmd.f_rcv_seq[3:0] 53 | @200 54 | - 55 | @22 56 | spicmd.shift_data[39:0] 57 | spicmd.crc_valid_sreg[4:0] 58 | @29 59 | spicmd.almost_sent 60 | @200 61 | - 62 | @28 63 | spicmd.rx_check_busy 64 | spicmd.rx_counter[2:0] 65 | spicmd.rx_r1_byte 66 | spicmd.rxvalid 67 | @200 68 | - 69 | @22 70 | spicmd.crc_bit_counter[5:0] 71 | @28 72 | spicmd.crc_busy 73 | @22 74 | spicmd.crc_byte[7:0] 75 | spicmd.f_cmd[5:0] 76 | spicmd.f_data[31:0] 77 | @28 78 | spicmd.f_past_valid 79 | spicmd.f_type[1:0] 80 | [pattern_trace] 1 81 | [pattern_trace] 0 82 | -------------------------------------------------------------------------------- /bench/formal/spicmd.sby: -------------------------------------------------------------------------------- 1 | [tasks] 2 | prf 3 | cvr 4 | 5 | [options] 6 | prf: mode prove 7 | prf: depth 4 8 | cvr: mode cover 9 | cvr: depth 60 10 | 11 | [engines] 12 | smtbmc boolector 13 | 14 | [script] 15 | read -formal -D SPICMD spicmd.v 16 | prep -top spicmd 17 | 18 | [files] 19 | ../../rtl/spicmd.v 20 | -------------------------------------------------------------------------------- /bench/formal/spirxdata.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.66 (w)1999-2015 BSI 3 | [*] Fri Nov 8 19:31:52 2019 4 | [*] 5 | [dumpfile] "(null)" 6 | [timestart] 0 7 | [size] 1920 1029 8 | [pos] -1 -1 9 | *-6.031004 500 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 10 | [sst_width] 196 11 | [signals_width] 166 12 | [sst_expanded] 1 13 | [sst_vpaned_height] 306 14 | @28 15 | spirxdata.f_past_valid 16 | spirxdata.i_reset 17 | spirxdata.i_clk 18 | @200 19 | - 20 | @28 21 | spirxdata.i_start 22 | spirxdata.i_fifo 23 | @22 24 | spirxdata.i_lgblksz[3:0] 25 | @200 26 | - 27 | @28 28 | spirxdata.i_ll_stb 29 | @22 30 | spirxdata.i_ll_byte[7:0] 31 | @200 32 | - 33 | @28 34 | spirxdata.o_busy 35 | @200 36 | - 37 | @28 38 | [color] 2 39 | spirxdata.o_write 40 | @22 41 | [color] 2 42 | spirxdata.o_addr[7:0] 43 | [color] 2 44 | spirxdata.o_data[31:0] 45 | @200 46 | - 47 | @22 48 | spirxdata.o_response[7:0] 49 | @28 50 | spirxdata.o_rxvalid 51 | @200 52 | - 53 | @28 54 | spirxdata.token 55 | spirxdata.error_token 56 | spirxdata.start_token 57 | spirxdata.received_token 58 | @200 59 | - 60 | @29 61 | [color] 3 62 | spirxdata.fill[2:0] 63 | @23 64 | [color] 3 65 | spirxdata.gearbox[23:0] 66 | @200 67 | - 68 | @28 69 | spirxdata.lastaddr 70 | spirxdata.all_mem_written 71 | spirxdata.crc_byte[1:0] 72 | @200 73 | - 74 | @28 75 | [color] 2 76 | spirxdata.new_data_byte 77 | [color] 2 78 | spirxdata.crc_active 79 | @22 80 | [color] 2 81 | spirxdata.crc_data[15:0] 82 | @28 83 | [color] 2 84 | spirxdata.crc_err 85 | @22 86 | [color] 2 87 | spirxdata.crc_fill[3:0] 88 | [color] 2 89 | spirxdata.crc_gearbox[7:0] 90 | @28 91 | [color] 2 92 | spirxdata.done 93 | @200 94 | - 95 | @28 96 | spirxdata.f_fifo 97 | @22 98 | spirxdata.f_lgblksz[3:0] 99 | @28 100 | spirxdata.r_lgblksz_m4[2:0] 101 | spirxdata.f_lgblksz_m4[2:0] 102 | @22 103 | spirxdata.f_last_read[6:0] 104 | [pattern_trace] 1 105 | [pattern_trace] 0 106 | -------------------------------------------------------------------------------- /bench/formal/spirxdata.sby: -------------------------------------------------------------------------------- 1 | [tasks] 2 | prf 3 | prfle prf opt_little_endian 4 | cvr 5 | 6 | [options] 7 | prf: mode prove 8 | prf: depth 7 9 | cvr: mode cover 10 | cvr: depth 180 11 | 12 | [engines] 13 | smtbmc boolector 14 | 15 | [script] 16 | read -formal -D SPIRXDATA spirxdata.v 17 | --pycode-begin-- 18 | cmd = "hierarchy -top spirxdata" 19 | cmd += " -chparam OPT_LITTLE_ENDIAN %d" % (1 if "opt_little_endian" in tags else 0) 20 | output(cmd) 21 | --pycode-end-- 22 | proc -norom 23 | prep 24 | 25 | [files] 26 | ../../rtl/spirxdata.v 27 | -------------------------------------------------------------------------------- /bench/formal/spitxdata.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.66 (w)1999-2015 BSI 3 | [*] Fri Nov 8 17:00:17 2019 4 | [*] 5 | [dumpfile_mtime] "Fri Nov 8 16:43:56 2019" 6 | [dumpfile_size] 81860 7 | [timestart] 586 8 | [size] 1920 1029 9 | [pos] -1 -1 10 | *-7.190785 1440 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 11 | [sst_width] 196 12 | [signals_width] 166 13 | [sst_expanded] 1 14 | [sst_vpaned_height] 306 15 | @28 16 | spitxdata.f_past_valid 17 | spitxdata.i_reset 18 | spitxdata.i_clk 19 | spitxdata.i_start 20 | spitxdata.o_busy 21 | @22 22 | spitxdata.i_lgblksz[3:0] 23 | @200 24 | - 25 | @28 26 | spitxdata.i_fifo 27 | @22 28 | spitxdata.i_data[31:0] 29 | @200 30 | - 31 | @28 32 | spitxdata.o_read 33 | @22 34 | spitxdata.o_addr[7:0] 35 | @200 36 | - 37 | @28 38 | spitxdata.o_ll_stb 39 | @22 40 | spitxdata.o_ll_byte[7:0] 41 | @28 42 | spitxdata.i_ll_busy 43 | @200 44 | - 45 | @28 46 | spitxdata.i_ll_stb 47 | @22 48 | spitxdata.i_ll_byte[7:0] 49 | @200 50 | - 51 | @28 52 | spitxdata.o_rxvalid 53 | @22 54 | spitxdata.o_response[7:0] 55 | @200 56 | - 57 | @22 58 | spitxdata.fill[4:0] 59 | @200 60 | - 61 | @28 62 | spitxdata.crc_active 63 | @22 64 | spitxdata.crc_data[15:0] 65 | spitxdata.crc_fill[4:0] 66 | @200 67 | - 68 | @28 69 | spitxdata.lastaddr 70 | spitxdata.all_mem_read 71 | spitxdata.crc_flag 72 | spitxdata.data_read 73 | spitxdata.crc_stb 74 | @29 75 | spitxdata.data_sent 76 | @200 77 | - 78 | @28 79 | spitxdata.r_lgblksz_m4[2:0] 80 | spitxdata.rdvalid[2:0] 81 | [pattern_trace] 1 82 | [pattern_trace] 0 83 | -------------------------------------------------------------------------------- /bench/formal/spitxdata.sby: -------------------------------------------------------------------------------- 1 | [tasks] 2 | prf 3 | prfle prf opt_little_endian 4 | cvr 5 | 6 | [options] 7 | prf: mode prove 8 | prf: depth 8 9 | cvr: mode cover 10 | cvr: depth 160 11 | 12 | [engines] 13 | smtbmc boolector 14 | 15 | [script] 16 | read -formal -D SPITXDATA spitxdata.v 17 | --pycode-begin-- 18 | cmd = "hierarchy -top spitxdata" 19 | cmd += " -chparam OPT_LITTLE_ENDIAN %d" % (1 if "opt_little_endian" in tags else 0) 20 | output(cmd) 21 | --pycode-end-- 22 | proc -norom 23 | prep 24 | 25 | [files] 26 | ../../rtl/spitxdata.v 27 | -------------------------------------------------------------------------------- /bench/testscript/sddmachk.v: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: bench/testscript/sddmachk.v 4 | // {{{ 5 | // Project: SD-Card controller 6 | // 7 | // Purpose: Drive and demonstrate the DMA controller. 8 | // 9 | // Creator: Dan Gisselquist, Ph.D. 10 | // Gisselquist Technology, LLC 11 | // 12 | //////////////////////////////////////////////////////////////////////////////// 13 | // }}} 14 | // Copyright (C) 2016-2025, Gisselquist Technology, LLC 15 | // {{{ 16 | // This program is free software (firmware): you can redistribute it and/or 17 | // modify it under the terms of the GNU General Public License as published 18 | // by the Free Software Foundation, either version 3 of the License, or (at 19 | // your option) any later version. 20 | // 21 | // This program is distributed in the hope that it will be useful, but WITHOUT 22 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 23 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 24 | // for more details. 25 | // 26 | // You should have received a copy of the GNU General Public License along 27 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no 28 | // target there if the PDF file isn't present.) If not, see 29 | // for a copy. 30 | // }}} 31 | // License: GPL, v3, as defined and found on www.gnu.org, 32 | // {{{ 33 | // http://www.gnu.org/licenses/gpl.html 34 | // 35 | //////////////////////////////////////////////////////////////////////////////// 36 | // 37 | `include "../testscript/sdiolib.v" 38 | // }}} 39 | 40 | reg expect_dma_err = 1'b0; 41 | 42 | always @(posedge clk) 43 | if (!reset && !expect_dma_err && (u_sdio.u_sdio.dma_err 44 | || (u_sdio.u_sdio.s2sd_valid 45 | && (u_sdio.u_sdio.s2sd_data != u_sdio.u_sdio.s2sd_data)) 46 | || (u_sdio.u_sdio.sd2s_valid 47 | && (u_sdio.u_sdio.sd2s_data != u_sdio.u_sdio.sd2s_data)))) 48 | begin 49 | $display("ERROR: Unexpected DMA ERR detected"); 50 | error_flag <= 1'b1; 51 | end 52 | 53 | always @(posedge clk) 54 | if (!reset && !expect_dma_err && u_sdcard.rx_err && !error_flag) 55 | begin 56 | $display("ERROR: SDCard (Model) RX ERR (bad CRC) detected"); 57 | error_flag <= 1'b1; 58 | end 59 | 60 | 61 | task testscript; 62 | reg [31:0] read_data, ocr_reg, if_cond, op_cond, r6; 63 | reg [15:0] rca; 64 | reg [127:0] CID; 65 | reg [31:0] sample_shift; 66 | begin 67 | @(posedge clk); 68 | while(reset !== 1'b0) 69 | @(posedge clk); 70 | @(posedge clk); 71 | 72 | sdcard_discover; 73 | 74 | // Set clock speed = 25MHz 75 | // {{{ 76 | // We can immediately start at 25MHz b/c our own simulation model 77 | // allows us to. We might not do this with real hardware. 78 | sample_shift = { 11'h0, 5'h08, 16'h0 }; 79 | u_bfm.write_f(ADDR_SDPHY, SECTOR_16B | SPEED_25MHZ | SDPHY_W1 | { 11'h0, 5'h1f, 16'h0 }); 80 | u_bfm.readio(ADDR_SDPHY, read_data); 81 | if (3'h0 == read_data[18:16]) 82 | // OPT_"RAW" (Neither SERDES nor DDR) 83 | sample_shift = { 11'h0, 5'h08, 16'h0 }; 84 | else if (2'b00 == read_data[17:16]) 85 | // OPT_DDR 86 | sample_shift = { 11'h0, 5'h0c, 16'h0 }; 87 | else 88 | // OPT_SERDES 89 | sample_shift = { 11'h0, 5'h03, 16'h0 }; 90 | u_bfm.write_f(ADDR_SDPHY, SECTOR_16B | SPEED_25MHZ | SDPHY_W1 | sample_shift); 91 | do begin 92 | u_bfm.readio(ADDR_SDPHY, read_data); 93 | end while(read_data[7:0] != SPEED_25MHZ[7:0]); 94 | u_bfm.readio(ADDR_SDCARD, read_data); 95 | // }}} 96 | 97 | $display("CMD0: GO-IDLE"); 98 | sdcard_go_idle; 99 | 100 | // IF condition and OP-Cond 101 | // {{{ 102 | if_cond = 32'h01a5; 103 | sdcard_send_if_cond(if_cond); 104 | u_bfm.readio(ADDR_SDCARD, read_data); 105 | $display("IF-COND: %08x", read_data); 106 | if (read_data[15] && read_data[17:16] == 2'b00) 107 | begin 108 | // No response from card 109 | do begin 110 | op_cond = 32'h0ff_8000; 111 | sdcard_send_op_cond(op_cond); 112 | end while(1'b0 === op_cond[31]); 113 | end else begin 114 | assert(if_cond[7:0] == 8'ha5); 115 | 116 | op_cond = 32'h4000_0000; 117 | op_cond[24] = OPT_1P8V; 118 | sdcard_send_op_cond(op_cond); 119 | 120 | do begin 121 | op_cond = 32'h40ff_8000; 122 | op_cond[24] = OPT_1P8V; 123 | sdcard_send_op_cond(op_cond); 124 | end while(1'b0 === op_cond[31]); 125 | end 126 | $display("OP-COND: %08x", op_cond); 127 | // }}} 128 | 129 | if (OPT_1P8V && op_cond[24]) 130 | begin 131 | sdcard_send_voltage_switch; // CMD11 132 | end 133 | // else max_spd = SPEED_50MHZ; 134 | 135 | // Assign RCAs 136 | // {{{ 137 | // CMD2 // All send CID 138 | sdcard_all_send_cid; 139 | u_bfm.readio(ADDR_FIFOA, CID[127:96]); 140 | u_bfm.readio(ADDR_FIFOA, CID[ 95:64]); 141 | u_bfm.readio(ADDR_FIFOA, CID[ 63:32]); 142 | u_bfm.readio(ADDR_FIFOA, CID[ 31: 0]); 143 | $display("READ-CID: %08x:%08x:%08x:%08x", 144 | CID[127:96], CID[95:64], CID[63:32], CID[31:0]); 145 | assert(CID[127:8] == u_sdcard.CID); 146 | 147 | // CMD3 SEND_RELATIVE_ADDR 148 | sdcard_send_relative_addr(r6); 149 | rca = r6[31:16]; 150 | $display("ASSIGNED-RCA: %04x", rca); 151 | // }}} 152 | 153 | // CMD7 SELECT/DESELCT Card 154 | sdcard_select_card(rca); 155 | 156 | // Set up for 1b @ 25MHz 157 | // {{{ 158 | u_bfm.write_f(ADDR_SDPHY, SECTOR_16B | SPEED_DS | SDPHY_W1 | sample_shift); 159 | do begin 160 | u_bfm.readio(ADDR_SDPHY, read_data); 161 | end while(read_data[7:0] != SPEED_DS[7:0]); 162 | // }}} 163 | 164 | $display("Set bus width to 4b"); 165 | sdcard_set_bus_width(2'b10); 166 | 167 | // Test at SPEED_DS=25MHZ SDR = 12.5MB/s, or 32b / 32 clocks 168 | // {{{ 169 | $display("Set speed to DS, i.e. 25MHz"); 170 | u_bfm.write_f(ADDR_SDPHY, SECTOR_512B | SPEED_DS | SDPHY_W4 | sample_shift); 171 | 172 | if (OPT_1P8V && op_cond[24]) 173 | sdcard_send_tuning_block; 174 | sdcard_write_dma(5, 32'h3, MEM_ADDR); 175 | 176 | sdcard_read_dma(4, 32'h4, MEM_ADDR + ((5+3)<<9)); 177 | sdcard_read_dma(1, 32'h3, MEM_ADDR + ((5+3+4)<<9)); 178 | // }}} 179 | 180 | // Test at SPEED_100=50MHZ SDR = 100MB/s, or 32b / 8 clocks 181 | // {{{ 182 | if (OPT_SERDES || OPT_DDR) 183 | begin 184 | $display("Set speed to SDR50, i.e. 100MHz"); 185 | u_bfm.write_f(ADDR_SDPHY, SECTOR_512B | SPEED_SDR100 | SDPHY_W4 | sample_shift); 186 | u_bfm.readio(ADDR_SDPHY, read_data); 187 | while(read_data[7:0] != SPEED_SDR100[7:0]) 188 | begin 189 | u_bfm.readio(ADDR_SDPHY, read_data); 190 | end 191 | 192 | if (OPT_1P8V && op_cond[24]) 193 | sdcard_send_tuning_block; 194 | 195 | sdcard_write_dma(6, 32'h3, MEM_ADDR); 196 | sdcard_read_dma(5, 32'h4, MEM_ADDR + ((6+4)<<9)); 197 | end 198 | 199 | // }}} 200 | 201 | // Test at SPEED_200=200MHZ SDR = 100MB/s, or 32b / 4 clocks 202 | // {{{ 203 | if (OPT_SERDES) 204 | begin 205 | $display("Set speed to SDR104, i.e. 200MHz"); 206 | u_bfm.write_f(ADDR_SDPHY, SECTOR_512B | SPEED_SDR200 | SDPHY_W4 | sample_shift); 207 | u_bfm.readio(ADDR_SDPHY, read_data); 208 | while(read_data[7:0] != SPEED_SDR200[7:0]) 209 | begin 210 | u_bfm.readio(ADDR_SDPHY, read_data); 211 | end 212 | 213 | if (OPT_1P8V && op_cond[24]) 214 | sdcard_send_tuning_block; 215 | 216 | sdcard_write_dma(6, 32'h4, MEM_ADDR); 217 | sdcard_read_dma(4, 32'h5, MEM_ADDR + ((6+4)<<9)); 218 | end 219 | // }}} 220 | 221 | // 1 block, sector 0, going right up to the end of memory 222 | u_bfm.readio(ADDR_SDCARD, read_data); 223 | sdcard_read_dma(1, 32'h9, MEM_ADDR + (1< for a copy. 30 | // }}} 31 | // License: GPL, v3, as defined and found on www.gnu.org, 32 | // {{{ 33 | // http://www.gnu.org/licenses/gpl.html 34 | // 35 | //////////////////////////////////////////////////////////////////////////////// 36 | // 37 | `include "../testscript/sdiolib.v" 38 | // }}} 39 | 40 | task testscript; 41 | reg [31:0] read_data, ocr_reg, if_cond, op_cond, r6, sample_shift; 42 | reg [15:0] rca; 43 | reg [127:0] CID; 44 | integer numio; 45 | reg [7:0] max_spd; 46 | begin 47 | @(posedge clk); 48 | while(reset !== 1'b0) 49 | @(posedge clk); 50 | @(posedge clk); 51 | 52 | sdcard_discover; 53 | 54 | $display("Starting with CMD=0x%08x, PHY=0x%08x", 55 | u_sdio.u_sdio.u_control.w_cmd_word, 56 | u_sdio.u_sdio.u_control.w_phy_ctrl); 57 | 58 | // Read our capabilities back from the controller 59 | // {{{ 60 | u_bfm.write_f(ADDR_SDPHY, SECTOR_16B | SPEED_200MHZ 61 | | SDPHY_WTEST | SPEED_CLKOFF 62 | | SDPHY_DDR | SDPHY_SHFTMSK); 63 | repeat(5) @(posedge clk); 64 | $display("Post write, CMD=0x%08x, PHY=0x%08x", 65 | u_sdio.u_sdio.u_control.w_cmd_word, 66 | u_sdio.u_sdio.u_control.w_phy_ctrl); 67 | 68 | do begin 69 | u_bfm.readio(ADDR_SDPHY, read_data); 70 | end while(read_data[7:0] > 8'h3); 71 | $display("Done waiting on initial clock change"); 72 | 73 | case(read_data[11:10]) 74 | 2'b00: numio = 1; 75 | default: numio = 4; 76 | endcase 77 | 78 | max_spd = read_data[7:0]; 79 | if (3'h0 == read_data[18:16]) 80 | // OPT_"RAW" (Neither SERDES nor DDR) 81 | sample_shift = { 11'h0, 5'h08, 16'h0 }; 82 | else if (2'b00 == read_data[17:16]) 83 | // OPT_DDR 84 | sample_shift = { 11'h0, 5'h0c, 16'h0 }; 85 | else 86 | // OPT_SERDES 87 | sample_shift = { 11'h0, 5'h03, 16'h0 }; 88 | // }}} 89 | 90 | // Now set up for the capabilities we will be using 91 | // {{{ 92 | u_bfm.write_f(ADDR_SDPHY, SECTOR_16B | SPEED_1MHZ | SDPHY_W1 | sample_shift); 93 | do begin 94 | u_bfm.readio(ADDR_SDPHY, read_data); 95 | end while(read_data[7:0] != SPEED_1MHZ[7:0]); 96 | // }}} 97 | 98 | u_bfm.readio(ADDR_SDCARD, read_data); 99 | sdcard_go_idle; 100 | 101 | // IF condition and OP-Cond 102 | // {{{ 103 | if_cond = 32'h01a5; 104 | sdcard_send_if_cond(if_cond); 105 | u_bfm.readio(ADDR_SDCARD, read_data); 106 | $display("IF-COND: %08x", read_data); 107 | if (read_data[15] && read_data[17:16] == 2'b00) 108 | begin 109 | // No response from card 110 | do begin 111 | op_cond = 32'h0ff_8000; 112 | sdcard_send_op_cond(op_cond); 113 | end while(1'b0 === op_cond[31]); 114 | end else begin 115 | assert(if_cond[7:0] == 8'ha5); 116 | 117 | op_cond = 32'h4000_0000; 118 | op_cond[24] = OPT_1P8V; 119 | sdcard_send_op_cond(op_cond); 120 | 121 | do begin 122 | op_cond = 32'h40ff_8000; 123 | op_cond[24] = OPT_1P8V; 124 | sdcard_send_op_cond(op_cond); 125 | end while(1'b0 === op_cond[31]); 126 | end 127 | $display("OP-COND: %08x", op_cond); 128 | // }}} 129 | 130 | if (OPT_1P8V && op_cond[24]) 131 | begin 132 | sdcard_send_voltage_switch; // CMD11 133 | end else 134 | max_spd = SPEED_50MHZ; 135 | 136 | // Assign RCAs 137 | // {{{ 138 | // CMD2 // All send CID 139 | sdcard_all_send_cid; 140 | u_bfm.readio(ADDR_FIFOA, CID[127:96]); 141 | u_bfm.readio(ADDR_FIFOA, CID[ 95:64]); 142 | u_bfm.readio(ADDR_FIFOA, CID[ 63:32]); 143 | u_bfm.readio(ADDR_FIFOA, CID[ 31: 0]); 144 | $display("READ-CID: %08x:%08x:%08x:%08x", 145 | CID[127:96], CID[95:64], CID[63:32], CID[31:0]); 146 | assert(CID[127:8] == u_sdcard.CID); 147 | 148 | // CMD3 SEND_RELATIVE_ADDR 149 | sdcard_send_relative_addr(r6); 150 | rca = r6[31:16]; 151 | $display("ASSIGNED-RCA: %04x", rca); 152 | // }}} 153 | 154 | // CMD7 SELECT/DESELCT Card 155 | sdcard_select_card(rca); 156 | 157 | u_bfm.write_f(ADDR_SDPHY, SECTOR_16B | SPEED_DS | SDPHY_W1 | sample_shift); 158 | do begin 159 | u_bfm.readio(ADDR_SDPHY, read_data); 160 | end while(read_data[7:0] != SPEED_DS[7:0]); 161 | 162 | // ACMD51 SEND_SCR -- can be used to determine what bus widths 163 | // are supported 164 | 165 | // CMD42 // LOCK_UNLOCK, sets/resets the password of the card 166 | 167 | // ACMD6 SET_BUS_WIDTH, allowable data bus widths are in SCR reg 168 | sdcard_send_random_block(32'h00); 169 | sdcard_send_random_block(32'h03); 170 | sdcard_send_random_block(32'h01); 171 | sdcard_send_random_block(32'h02); 172 | 173 | sdcard_read_block(32'h00); 174 | 175 | sdcard_set_bus_width(2'b10); 176 | 177 | // Test at SPEED_DS=25MHZ SDR 178 | // {{{ 179 | if (numio >= 4) 180 | begin 181 | u_bfm.write_f(ADDR_SDPHY, SECTOR_16B | SPEED_DS | SDPHY_W4 | sample_shift); 182 | 183 | // CMD6 // Select drive strength ?? 184 | // CMD19 // Tuning block to determine sampling point 185 | // sdcard_read_ocr(ocr_reg); 186 | 187 | sdcard_send_random_block(32'h04); 188 | sdcard_send_random_block(32'h06); 189 | sdcard_send_random_block(32'h05); 190 | sdcard_send_random_block(32'h07); 191 | 192 | sdcard_read_block(32'h05); 193 | end 194 | // }}} 195 | 196 | // Test at SPEED_HSSDR=50MHZ SDR 197 | // {{{ 198 | if (numio >= 4 && SPEED_HSSDR[7:0] >= max_spd) 199 | begin 200 | u_bfm.write_f(ADDR_SDPHY, SECTOR_16B | SPEED_HSSDR | SDPHY_W4 | sample_shift); 201 | 202 | sdcard_send_random_block(32'h0b); 203 | sdcard_send_random_block(32'h09); 204 | sdcard_send_random_block(32'h0a); 205 | sdcard_send_random_block(32'h08); 206 | 207 | sdcard_read_block(32'h0a); 208 | sdcard_read_block(32'h0b); 209 | end 210 | // }}} 211 | 212 | // Test at SPEED_SDR100=100MHZ SDR 213 | // {{{ 214 | if (numio >= 4 && SPEED_HSSDR[7:0] >= max_spd) 215 | begin 216 | u_bfm.write_f(ADDR_SDPHY, SECTOR_16B | SPEED_SDR100 | SDPHY_W4 | sample_shift); 217 | 218 | if (OPT_1P8V && op_cond[24]) 219 | sdcard_send_tuning_block; 220 | 221 | sdcard_send_random_block(32'h0c); 222 | sdcard_send_random_block(32'h0d); 223 | sdcard_send_random_block(32'h0e); 224 | sdcard_send_random_block(32'h0f); 225 | 226 | sdcard_read_block(32'h0d); 227 | sdcard_read_block(32'h0c); 228 | end 229 | // }}} 230 | 231 | // Test at fastest SDR speed=200MHz SDR 232 | // {{{ 233 | if (numio >= 4 && SPEED_HSSDR[7:0] >= max_spd) 234 | begin 235 | u_bfm.write_f(ADDR_SDPHY, SECTOR_16B | SPEED_SDR200 | SDPHY_W4 | sample_shift); 236 | 237 | if (OPT_1P8V && op_cond[24]) 238 | sdcard_send_tuning_block; 239 | 240 | sdcard_send_random_block(32'h10); 241 | sdcard_send_random_block(32'h11); 242 | sdcard_send_random_block(32'h12); 243 | sdcard_send_random_block(32'h13); 244 | 245 | sdcard_read_block(32'h10); 246 | sdcard_read_block(32'h11); 247 | end 248 | // }}} 249 | 250 | repeat(512) 251 | @(posedge clk); 252 | end endtask 253 | -------------------------------------------------------------------------------- /bench/verilog/.gitignore: -------------------------------------------------------------------------------- 1 | a.out 2 | devsim 3 | tb_sdckgen 4 | tb_txframe 5 | report.txt 6 | sdiosim 7 | test/ 8 | /cpu/ 9 | /testscript.v 10 | -------------------------------------------------------------------------------- /bench/verilog/IOBUF.v: -------------------------------------------------------------------------------- 1 | module IOBUF (input wire T, input wire I, inout wire IO, output wire O); 2 | assign IO = (T) ? 1'bz : I; 3 | assign O = (IO !== 1'b0); 4 | endmodule 5 | -------------------------------------------------------------------------------- /bench/verilog/Makefile: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | ## 3 | ## Filename: bench/verilog/Makefile 4 | ## {{{ 5 | ## Project: SD-Card controller 6 | ## 7 | ## Purpose: 8 | ## 9 | ## Creator: Dan Gisselquist, Ph.D. 10 | ## Gisselquist Technology, LLC 11 | ## 12 | ################################################################################ 13 | ## }}} 14 | ## Copyright (C) 2016-2025, Gisselquist Technology, LLC 15 | ## {{{ 16 | ## This program is free software (firmware): you can redistribute it and/or 17 | ## modify it under the terms of the GNU General Public License as published 18 | ## by the Free Software Foundation, either version 3 of the License, or (at 19 | ## your option) any later version. 20 | ## 21 | ## This program is distributed in the hope that it will be useful, but WITHOUT 22 | ## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 23 | ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 24 | ## for more details. 25 | ## 26 | ## You should have received a copy of the GNU General Public License along 27 | ## with this program. (It's in the $(ROOT)/doc directory. Run make with no 28 | ## target there if the PDF file isn't present.) If not, see 29 | ## for a copy. 30 | ## }}} 31 | ## License: GPL, v3, as defined and found on www.gnu.org, 32 | ## {{{ 33 | ## http://www.gnu.org/licenses/gpl.html 34 | ## 35 | ################################################################################ 36 | ## 37 | ## }}} 38 | RTL := ../../rtl 39 | CPU := $(HOME)/work/rnd/zipcpu/trunk 40 | 41 | tb_sdckgen: $(RTL)/sdckgen.v tb_sdckgen.v 42 | iverilog -g2012 $^ -o $@ 43 | 44 | tb_txframe: $(RTL)/sdckgen.v $(RTL)/sdtxframe.v tb_txframe.v 45 | iverilog -g2012 $^ -o $@ 46 | 47 | obj_dir/Vtb_cpu.h: 48 | verilator -Wall -Wno-TIMESCALEMOD -y $(RTL) -y . -y $(CPU)/rtl -y $(CPU)/rtl/core -y $(CPU)/rtl/peripherals -y $(CPU)/rtl/zipdma -y $(CPU)/rtl/ex -y $(CPU)/sim/rtl -cc tb_cpu.v 49 | 50 | .PHONY: test_ckgen 51 | test_ckgen: tb_sdckgen 52 | ./tb_sdckgen 53 | 54 | .PHONY: test_txframe 55 | test_txframe: tb_txframe 56 | ./tb_txframe 57 | 58 | .PHONY: test 59 | test: test_txframe test_ckgen 60 | perl sim_run.pl all 61 | -------------------------------------------------------------------------------- /bench/verilog/cpu_files.txt: -------------------------------------------------------------------------------- 1 | axidcache.v 2 | axiicache.v 3 | axilcon.v 4 | axilfetch.v 5 | axilops.v 6 | axilperiphs.v 7 | axilpipe.v 8 | axiops.v 9 | axipipe.v 10 | busdelay.v 11 | cpuops.v 12 | dblfetch.v 13 | dcache.v 14 | div.v 15 | icontrol.v 16 | idecode.v 17 | memops.v 18 | mpyop.v 19 | pfcache.v 20 | pffifo.v 21 | pipefetch.v 22 | pipemem.v 23 | prefetch.v 24 | slowmpy.v 25 | wbarbiter.v 26 | wbdblpriarb.v 27 | wbdmac.v 28 | wbpriarbiter.v 29 | wbscope.v 30 | wbwatchdog.v 31 | zipaxil.v 32 | zipaxi.v 33 | zipbones.v 34 | zipcore.v 35 | zipcounter.v 36 | zipdma_ctrl.v 37 | zipdma_fsm.v 38 | zipdma_mm2s.v 39 | zipdma_rxgears.v 40 | zipdma_s2mm.v 41 | zipdma_txgears.v 42 | zipdma.v 43 | zipjiffies.v 44 | zipmmu.v 45 | zipsystem.v 46 | ziptimer.v 47 | zipwb.v 48 | -------------------------------------------------------------------------------- /bench/verilog/dev_files.txt: -------------------------------------------------------------------------------- 1 | tb_wb.v 2 | tb_axi.v 3 | IOBUF.v 4 | wb_bfm.v 5 | axil_bfm.v 6 | streamchk.v 7 | mdl_sdio.v 8 | mdl_emmc.v 9 | mdl_sdcmd.v 10 | mdl_sdrx.v 11 | mdl_sdtx.v 12 | wb2axip/addrdecode.v 13 | wb2axip/axi_addr.v 14 | wb2axip/axi2axilite.v 15 | wb2axip/axi2axilsub.v 16 | wb2axip/axiempty.v 17 | wb2axip/axilgpio.v 18 | wb2axip/axilite2axi.v 19 | wb2axip/axilupsz.v 20 | wb2axip/axiram.v 21 | wb2axip/axixbar.v 22 | wb2axip/memdev.v 23 | wb2axip/sfifo.v 24 | wb2axip/skidbuffer.v 25 | wb2axip/wbdown.v 26 | wb2axip/wbgpio.v 27 | wb2axip/wbupsz.v 28 | wb2axip/wbxbar.v 29 | ../../rtl/sdio_top.v 30 | ../../rtl/sdfrontend.v 31 | ../../rtl/afifo.v 32 | ../../rtl/xsdddr.v 33 | ../../rtl/xsdserdes8x.v 34 | ../../rtl/sdio.v 35 | ../../rtl/sdckgen.v 36 | ../../rtl/sdwb.v 37 | ../../rtl/sdskid.v 38 | ../../rtl/sdaxil.v 39 | ../../rtl/sdcmd.v 40 | ../../rtl/sddma_mm2s.v 41 | ../../rtl/sddma_rxgears.v 42 | ../../rtl/sddma_s2mm.v 43 | ../../rtl/sddma_txgears.v 44 | ../../rtl/sdax_mm2s.v 45 | ../../rtl/sdax_s2mm.v 46 | ../../rtl/sdfifo.v 47 | ../../rtl/sddma.v 48 | ../../rtl/sdtxframe.v 49 | ../../rtl/sdrxframe.v 50 | ../formal/fclk.v 51 | -------------------------------------------------------------------------------- /bench/verilog/dev_testcases.txt: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | ## 3 | ## Filename: bench/verilog/dev_testcases.txt 4 | ## {{{ 5 | ## Project: SD-Card controller 6 | ## 7 | ## Purpose: Defines a set of tests to be applied to the SDIO (not the eMMC) 8 | ## controller and simulation model. 9 | ## 10 | ## Creator: Dan Gisselquist, Ph.D. 11 | ## Gisselquist Technology, LLC 12 | ## 13 | ################################################################################ 14 | ## }}} 15 | ## Copyright (C) 2016-2025, Gisselquist Technology, LLC 16 | ## {{{ 17 | ## This program is free software (firmware): you can redistribute it and/or 18 | ## modify it under the terms of the GNU General Public License as published 19 | ## by the Free Software Foundation, either version 3 of the License, or (at 20 | ## your option) any later version. 21 | ## 22 | ## This program is distributed in the hope that it will be useful, but WITHOUT 23 | ## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 24 | ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 25 | ## for more details. 26 | ## 27 | ## You should have received a copy of the GNU General Public License along 28 | ## with this program. (It's in the $(ROOT)/doc directory. Run make with no 29 | ## target there if the PDF file isn't present.) If not, see 30 | ## for a copy. 31 | ## }}} 32 | ## License: GPL, v3, as defined and found on www.gnu.org, 33 | ## {{{ 34 | ## http://www.gnu.org/licenses/gpl.html 35 | ## 36 | ################################################################################ 37 | ## }}} 38 | ## Format: 39 | ## Test name | Test configuration | Test script (or S/W load) | (PARAM=X)* 40 | ## {{{ 41 | ## 42 | ## Test configurations are one of: 43 | ## WB Uses tb_wb.v as the top level. 44 | ## This is an all-Verilog TB. The test script is a Verilog file 45 | ## containing instructions for the Wishbone bus-functional model 46 | ## (BFM). 47 | ## AXI Uses tb_axi.v as the top level. 48 | ## Also an all-Verilog TB, with a Verilog test script just like 49 | ## the SDIO configuration. 50 | ## CPU (Note yet built ...) Would use tb_cpu.v as the top level. This 51 | ## top level (will eventually) contain a ZipCPU, and it's test 52 | ## script would be a hex file specifying the software load for 53 | ## the test. 54 | ## }}} 55 | sdioio WB sdiostart OPT_SERDES=0 OPT_DDR=0 56 | sdioddr WB sdiostart OPT_SERDES=0 OPT_DDR=1 57 | sdio8x WB sdiostart OPT_SERDES=1 OPT_DDR=1 58 | sddmachk WB sddmachk OPT_SERDES=1 OPT_DDR=1 OPT_DMA=1 59 | sdstream WB sdstream OPT_SERDES=1 OPT_DDR=1 OPT_DMA=1 OPT_STREAM=1 60 | axsdioio AXI sdiostart OPT_SERDES=0 OPT_DDR=0 61 | axsdioddr AXI sdiostart OPT_SERDES=0 OPT_DDR=1 62 | axsdio8x AXI sdiostart OPT_SERDES=1 OPT_DDR=1 63 | axsdstream AXI sdstream OPT_SERDES=1 OPT_DDR=1 OPT_DMA=1 OPT_STREAM=1 64 | axdmachk AXI sddmachk OPT_SERDES=1 OPT_DDR=1 OPT_DMA=1 65 | emmcio WB emmcstart OPT_SERDES=0 OPT_DDR=0 66 | emmcddr WB emmcstart OPT_SERDES=0 OPT_DDR=1 67 | emmc8x WB emmcstart OPT_SERDES=1 OPT_DDR=1 68 | axemmcio AXI emmcstart OPT_SERDES=0 OPT_DDR=0 69 | axemmcddr AXI emmcstart OPT_SERDES=0 OPT_DDR=1 70 | axemmc8x AXI emmcstart OPT_SERDES=1 OPT_DDR=1 71 | # 72 | # The SDSPI tests aren't yet fully implemented in all Verilog yet 73 | # They currently exist as part of an integrated C++/Verilog test bench, 74 | # run from the bench/cpp directory under Verilator. 75 | # 76 | # The CPU tests aren't yet fully implemented ... 77 | # cpusdio WBCPU sdcheck.hex OPT_SERDES=0 OPT_DDR=0 78 | # cpusdddr WBCPU sdcheck.hex OPT_SERDES=0 OPT_DDR=1 79 | # cpusd8x WBCPU sdcheck.hex OPT_SERDES=1 OPT_DDR=1 80 | # cpuemio WBCPU emcheck.hex OPT_SERDES=0 OPT_DDR=0 81 | # cpuemddr WBCPU emcheck.hex OPT_SERDES=0 OPT_DDR=1 82 | # cpuem8x WBCPU emcheck.hex OPT_SERDES=1 OPT_DDR=1 83 | # 84 | # caxsdio AXCPU sdcheck.hex OPT_SERDES=0 OPT_DDR=0 85 | # caxsdddr AXCPU sdcheck.hex OPT_SERDES=0 OPT_DDR=1 86 | # caxsd8x AXCPU sdcheck.hex OPT_SERDES=1 OPT_DDR=1 87 | # caxemio AXCPU emcheck.hex OPT_SERDES=0 OPT_DDR=0 88 | # caxemddr AXCPU emcheck.hex OPT_SERDES=0 OPT_DDR=1 89 | # caxem8x AXCPU emcheck.hex OPT_SERDES=1 OPT_DDR=1 90 | -------------------------------------------------------------------------------- /bench/verilog/gen_report.pl: -------------------------------------------------------------------------------- 1 | #!/bin/perl 2 | ################################################################################ 3 | ## 4 | ## Filename: bench/verilog/gen_report.pl 5 | ## {{{ 6 | ## Project: SD-Card controller 7 | ## 8 | ## Purpose: Generate an HTML report file, containing the status of the 9 | ## last simulation run. 10 | ## 11 | ## Creator: Dan Gisselquist, Ph.D. 12 | ## Gisselquist Technology, LLC 13 | ## 14 | ################################################################################ 15 | ## }}} 16 | ## Copyright (C) 2025, Gisselquist Technology, LLC 17 | ## {{{ 18 | ## This program is free software (firmware): you can redistribute it and/or 19 | ## modify it under the terms of the GNU General Public License as published 20 | ## by the Free Software Foundation, either version 3 of the License, or (at 21 | ## your option) any later version. 22 | ## 23 | ## This program is distributed in the hope that it will be useful, but WITHOUT 24 | ## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 25 | ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 26 | ## for more details. 27 | ## 28 | ## You should have received a copy of the GNU General Public License along 29 | ## with this program. (It's in the $(ROOT)/doc directory. Run make with no 30 | ## target there if the PDF file isn't present.) If not, see 31 | ## for a copy. 32 | ## }}} 33 | ## License: GPL, v3, as defined and found on www.gnu.org, 34 | ## {{{ 35 | ## http://www.gnu.org/licenses/gpl.html 36 | ## 37 | ################################################################################ 38 | ## 39 | ## }}} 40 | $filelist = "dev_files.txt"; 41 | $rawreport= "report.txt"; 42 | $htmlfil= "report.html"; 43 | my $last_mtime = 0; 44 | my $last_tstamp = ""; 45 | 46 | ################################################################################ 47 | ## 48 | ## Get the last file modified time 49 | ## {{{ 50 | open(FLIST, $filelist); 51 | while($line = ) { 52 | if ($line =~ /\s*(\S+)\s*$/) { 53 | $fname = $1; 54 | } else { 55 | next; 56 | } 57 | 58 | my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, 59 | $atime, $mtime, $ctime, $blksize, $blocks) = stat($fname); 60 | 61 | if ($mtime > $last_mtime) { 62 | $last_mtime = $mtime; 63 | } 64 | } 65 | close FLIST; 66 | 67 | my $sc, $mn, $hr, $dy, $mo, $yr, $wd, $yd, $isdst; 68 | ($sc, $mn, $hr, $dy, $mo, $yr, $wd, $yd, $isdst) = localtime($last_mtime); 69 | $yr = $yr+1900; $mo=$mo+1; 70 | $last_tstamp = sprintf("%04d/%02d/%02d %02d:%02d:%02d", 71 | $yr,$mo,$dy,$hr,$mn,$sc); 72 | ## }}} 73 | ################################################################################ 74 | ## 75 | ## Get the latest test result 76 | ## {{{ 77 | my $n=0; 78 | my %STAT; 79 | 80 | open(REPORT, $rawreport); 81 | while($line = ) { 82 | next if ($line =~ /^-/); 83 | if ($line =~ /(\S+)\s+(\d\d\d\d.\d\d.\d\d.\d\d:\d\d:\d\d)\s+(\S+)\s+..\s+(\S+)\s*$/) { 84 | $status = $1; 85 | $tstamp = $2; 86 | $tool = $3; 87 | $test = $4; 88 | 89 | if ("$tstamp" lt "$last_tstamp") { 90 | $STAT{$test} = "Out-of-date"; 91 | $TOOL{$test} = $tool; 92 | $TSTAMP{$test} = $tstamp; 93 | next; 94 | } 95 | if (exists $STAT{$test}) { 96 | my $last_tool, $last_stat; 97 | 98 | $last_tool = $TOOL{$test}; 99 | $last_stat = $STAT{$test}; 100 | 101 | if ($last_tool =~ /$tool/) { 102 | } else { 103 | $TOOL{$test} = "$last_tool, $tool"; 104 | } 105 | 106 | if ($last_stat =~ /fail/i) { 107 | } elsif ($last_stat =~ /error/i) { 108 | } elsif ($last_stat =~ /warn/i) { 109 | if ($stat =~ /fail/i) { 110 | $STAT{$test} = $status; 111 | } elsif ($stat =~ /error/i) { 112 | $STAT{$test} = $status; 113 | } 114 | } else { 115 | $STAT{$test} = $status; 116 | } 117 | } else { 118 | $STAT{$test} = $status; 119 | $TOOL{$test} = $tool; 120 | } 121 | 122 | $TSTAMP{$test} = $tstamp; 123 | } 124 | } 125 | 126 | printf("Last timestamp: $last_tstamp\n"); 127 | 128 | close REPORT; 129 | 130 | foreach $key (sort (keys %STAT)) { 131 | printf("%-12s %12s $TSTAMP{$key} -- $TOOL{$key}\n", $key, $STAT{$key}); 132 | } 133 | 134 | open(HTML, "> $htmlfil"); 135 | print HTML "Simulation report\n"; 136 | print HTML "

SD Controller Simulation Report

\n"; 137 | print HTML "\n"; 138 | print HTML "\n"; 139 | foreach $key (sort (keys %STAT)) { 140 | my $lin, $st; 141 | 142 | $st = $STAT{$key}; 143 | $clr="white"; 144 | if ($st =~ /fail/i) { 145 | $clr="#ffa4a"; 146 | } elsif ($st =~ /err/i) { 147 | $clr="#ffa4a"; 148 | } elsif ($st =~ /warn/i) { 149 | $clr="#ffffca"; 150 | } elsif ($st =~ /out-of-date/i) { 151 | $clr="#ffffca"; 152 | } elsif ($st =~ /pass/i) { 153 | $clr="#caeec8"; 154 | } 155 | $lin = sprintf("\n", $key, $st); 156 | print HTML $lin; 157 | } 158 | print HTML "
TestStatusSim TimestampTool
%s%s$TSTAMP{$key}$TOOL{$key}
\n"; 159 | close HTML; 160 | -------------------------------------------------------------------------------- /bench/verilog/iscachable.v: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: bench/verilog/iscachable.v 4 | // {{{ 5 | // Project: SD-Card controller 6 | // 7 | // Purpose: A helper function to both dcache and its formal properties, 8 | // used to determine when a particular address is cachable. This 9 | // module must be built of entirely combinatorial logic and nothing more. 10 | // 11 | // Creator: Dan Gisselquist, Ph.D. 12 | // Gisselquist Technology, LLC 13 | // 14 | //////////////////////////////////////////////////////////////////////////////// 15 | // }}} 16 | // Copyright (C) 2016-2025, Gisselquist Technology, LLC 17 | // {{{ 18 | // This program is free software (firmware): you can redistribute it and/or 19 | // modify it under the terms of the GNU General Public License as published 20 | // by the Free Software Foundation, either version 3 of the License, or (at 21 | // your option) any later version. 22 | // 23 | // This program is distributed in the hope that it will be useful, but WITHOUT 24 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 25 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 26 | // for more details. 27 | // 28 | // You should have received a copy of the GNU General Public License along 29 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no 30 | // target there if the PDF file isn't present.) If not, see 31 | // for a copy. 32 | // }}} 33 | // License: GPL, v3, as defined and found on www.gnu.org, 34 | // {{{ 35 | // http://www.gnu.org/licenses/gpl.html 36 | // 37 | //////////////////////////////////////////////////////////////////////////////// 38 | // 39 | `default_nettype none 40 | // }}} 41 | module iscachable #( 42 | // {{{ 43 | parameter ADDRESS_WIDTH=28, 44 | localparam AW = ADDRESS_WIDTH, // Just for ease of notation below 45 | parameter [AW-1:0] 46 | MEM_ADDR = { 2'b01, {(ADDRESS_WIDTH-2){1'b0}} }, 47 | MEM_MASK = { 2'b11, {(ADDRESS_WIDTH-2){1'b0}} } 48 | // }}} 49 | ) ( 50 | // {{{ 51 | input wire [AW-1:0] i_addr, 52 | output reg o_cachable 53 | // }}} 54 | ); 55 | 56 | always @(*) 57 | begin 58 | o_cachable = 1'b0; 59 | if ((MEM_ADDR !=0)&&((i_addr & MEM_MASK)== MEM_ADDR)) 60 | o_cachable = 1'b1; 61 | end 62 | 63 | endmodule 64 | -------------------------------------------------------------------------------- /bench/verilog/report.html: -------------------------------------------------------------------------------- 1 | Simulation report 2 |

SD Controller Simulation Report

3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
TestStatusSim TimestampTool
axdmachkPass2025/04/21 18:04:51IVerilog
axemmc8xPass2025/04/21 18:11:05IVerilog
axemmcddrPass2025/04/21 18:09:03IVerilog
axemmcioPass2025/04/21 18:08:35IVerilog
axsdio8xPass2025/04/21 18:07:20IVerilog
axsdioddrPass2025/04/21 18:06:01IVerilog
axsdioioPass2025/04/21 18:05:47IVerilog
axsdstreamPass2025/04/21 18:04:37IVerilog
emmc8xPass2025/04/21 18:07:56IVerilog
emmcddrPass2025/04/21 18:04:37IVerilog
emmcioPass2025/04/21 18:03:55IVerilog
sddmachkPass2025/04/21 18:02:20IVerilog
sdio8xPass2025/04/21 18:04:46IVerilog
sdioddrPass2025/04/21 18:02:42IVerilog
sdioioPass2025/04/21 18:02:44IVerilog
sdstreamPass2025/04/21 18:02:27IVerilog
22 | -------------------------------------------------------------------------------- /bench/verilog/tb_sdckgen.v: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: bench/verilog/tb_sdckgen.v 4 | // {{{ 5 | // Project: SD-Card controller 6 | // 7 | // Purpose: An ad-hoc test of the clock generator. Pass-fail is judged 8 | // by looking at the trace and not automatically. 9 | // 10 | // Creator: Dan Gisselquist, Ph.D. 11 | // Gisselquist Technology, LLC 12 | // 13 | //////////////////////////////////////////////////////////////////////////////// 14 | // }}} 15 | // Copyright (C) 2016-2025, Gisselquist Technology, LLC 16 | // {{{ 17 | // This program is free software (firmware): you can redistribute it and/or 18 | // modify it under the terms of the GNU General Public License as published 19 | // by the Free Software Foundation, either version 3 of the License, or (at 20 | // your option) any later version. 21 | // 22 | // This program is distributed in the hope that it will be useful, but WITHOUT 23 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 24 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 25 | // for more details. 26 | // 27 | // You should have received a copy of the GNU General Public License along 28 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no 29 | // target there if the PDF file isn't present.) If not, see 30 | // for a copy. 31 | // }}} 32 | // License: GPL, v3, as defined and found on www.gnu.org, 33 | // {{{ 34 | // http://www.gnu.org/licenses/gpl.html 35 | // 36 | //////////////////////////////////////////////////////////////////////////////// 37 | // 38 | `timescale 1ns/1ns 39 | // }}} 40 | module tb_sdckgen; 41 | // Local declarations 42 | // {{{ 43 | reg clk, reset; 44 | 45 | reg cfg_clk90, cfg_shutdown; 46 | reg [7:0] cfg_ckspd; 47 | wire w_ckstb, w_halfck; 48 | wire [7:0] w_ckwide; 49 | // }}} 50 | //////////////////////////////////////////////////////////////////////// 51 | // 52 | // Clock and reset generation 53 | // {{{ 54 | initial begin 55 | $dumpfile("tb_sdckgen.vcd"); 56 | $dumpvars(0,tb_sdckgen); 57 | reset = 1'b1; 58 | clk = 0; 59 | forever 60 | #5 clk = !clk; 61 | end 62 | // }}} 63 | //////////////////////////////////////////////////////////////////////// 64 | // 65 | // Test script 66 | // {{{ 67 | task capture_beats; 68 | begin 69 | repeat(5) 70 | begin 71 | wait(w_ckstb); 72 | @(posedge clk); 73 | end 74 | end endtask 75 | 76 | initial begin 77 | { cfg_shutdown, cfg_clk90, cfg_ckspd } = 10'h0fc; 78 | repeat (5) 79 | @(posedge clk) 80 | @(posedge clk) 81 | reset <= 0; 82 | 83 | // 100kHz (10us) 84 | capture_beats; 85 | 86 | // 200 kHz (5us) 87 | @(posedge clk) 88 | { cfg_shutdown, cfg_clk90, cfg_ckspd } = 10'h07f; 89 | capture_beats; 90 | 91 | // 400 kHz (2.52us) 92 | @(posedge clk) 93 | { cfg_shutdown, cfg_clk90, cfg_ckspd } = 10'h041; 94 | capture_beats; 95 | 96 | // 1MHz (1us) 97 | @(posedge clk) 98 | { cfg_shutdown, cfg_clk90, cfg_ckspd } = 10'h01b; 99 | capture_beats; 100 | 101 | // 5MHz (200ns) 102 | @(posedge clk) 103 | { cfg_shutdown, cfg_clk90, cfg_ckspd } = 10'h007; 104 | capture_beats; 105 | 106 | // 12MHz (80ns) 107 | @(posedge clk) 108 | { cfg_shutdown, cfg_clk90, cfg_ckspd } = 10'h004; 109 | capture_beats; 110 | 111 | // 25MHz (40ns) 112 | @(posedge clk) 113 | { cfg_shutdown, cfg_clk90, cfg_ckspd } = 10'h003; 114 | capture_beats; 115 | 116 | // 50MHz (20ns) 117 | @(posedge clk) 118 | { cfg_shutdown, cfg_clk90, cfg_ckspd } = 10'h002; 119 | capture_beats; 120 | 121 | // 100MHz 122 | @(posedge clk) 123 | { cfg_shutdown, cfg_clk90, cfg_ckspd } = 10'h001; 124 | capture_beats; 125 | 126 | // 200MHz 127 | @(posedge clk) 128 | { cfg_shutdown, cfg_clk90, cfg_ckspd } = 10'h000; 129 | capture_beats; 130 | 131 | 132 | // 25MHz, CLK90 133 | @(posedge clk) 134 | { cfg_shutdown, cfg_clk90, cfg_ckspd } = 10'h103; 135 | capture_beats; 136 | 137 | // 25MHz, CLK90 138 | @(posedge clk) 139 | { cfg_shutdown, cfg_clk90, cfg_ckspd } = 10'h102; 140 | capture_beats; 141 | 142 | // 100MHz, CLK90 143 | @(posedge clk) 144 | { cfg_shutdown, cfg_clk90, cfg_ckspd } = 10'h101; 145 | capture_beats; 146 | 147 | // 200MHz, CLK90 148 | @(posedge clk) 149 | { cfg_shutdown, cfg_clk90, cfg_ckspd } = 10'h100; 150 | capture_beats; 151 | 152 | $finish; 153 | end 154 | // }}} 155 | //////////////////////////////////////////////////////////////////////// 156 | // 157 | // Module under test 158 | // {{{ 159 | 160 | sdckgen 161 | u_ckgen ( 162 | // {{{ 163 | .i_clk(clk), .i_reset(reset), 164 | // 165 | .i_cfg_clk90(cfg_clk90), 166 | .i_cfg_ckspd(cfg_ckspd), 167 | .i_cfg_shutdown(cfg_shutdown), 168 | // 169 | .o_ckstb(w_ckstb), 170 | .o_hlfck(w_halfck), 171 | .o_ckwide(w_ckwide) 172 | // }}} 173 | ); 174 | // }}} 175 | endmodule 176 | -------------------------------------------------------------------------------- /bench/verilog/wb2axip/wbgpio.v: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: bench/verilog/wb2axip/wbgpio.v 4 | // {{{ 5 | // Project: SD-Card controller 6 | // 7 | // Purpose: This extremely simple GPIO controller, although minimally 8 | // featured, is designed to control up to sixteen general purpose 9 | // input and sixteen general purpose output lines of a module from a 10 | // single address on a 32-bit wishbone bus. 11 | // 12 | // Input GPIO values are contained in the top 16-bits. Any change in 13 | // input values will generate an interrupt. 14 | // 15 | // Output GPIO values are contained in the bottom 16-bits. To change an 16 | // output GPIO value, writes to this port must also set a bit in the 17 | // upper sixteen bits. Hence, to set GPIO output zero, one would write 18 | // a 0x010001 to the port, whereas a 0x010000 would clear the bit. This 19 | // interface makes it possible to change only the bit of interest, without 20 | // needing to capture and maintain the prior bit values--something that 21 | // might be difficult from a interrupt context within a CPU. 22 | // 23 | // Unlike other controllers, this controller offers no capability to 24 | // change input/output direction, or to implement pull-up or pull-down 25 | // resistors. It simply changes and adjusts the values going out the 26 | // output pins, while allowing a user to read the values on the input 27 | // pins. 28 | // 29 | // Any change of an input pin value will result in the generation of an 30 | // interrupt signal. 31 | // 32 | // Creator: Dan Gisselquist, Ph.D. 33 | // Gisselquist Technology, LLC 34 | // 35 | //////////////////////////////////////////////////////////////////////////////// 36 | // }}} 37 | // Copyright (C) 2016-2025, Gisselquist Technology, LLC 38 | // {{{ 39 | // This program is free software (firmware): you can redistribute it and/or 40 | // modify it under the terms of the GNU General Public License as published 41 | // by the Free Software Foundation, either version 3 of the License, or (at 42 | // your option) any later version. 43 | // 44 | // This program is distributed in the hope that it will be useful, but WITHOUT 45 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 46 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 47 | // for more details. 48 | // 49 | // You should have received a copy of the GNU General Public License along 50 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no 51 | // target there if the PDF file isn't present.) If not, see 52 | // for a copy. 53 | // }}} 54 | // License: GPL, v3, as defined and found on www.gnu.org, 55 | // {{{ 56 | // http://www.gnu.org/licenses/gpl.html 57 | // 58 | //////////////////////////////////////////////////////////////////////////////// 59 | // 60 | `timescale 1ns/1ps 61 | `default_nettype none 62 | // }}} 63 | module wbgpio #( 64 | // {{{ 65 | parameter NIN=16, NOUT=16, 66 | parameter [(NOUT-1):0] DEFAULT=0 67 | // }}} 68 | ) ( 69 | // {{{ 70 | input wire i_clk, 71 | // 72 | input wire i_wb_cyc, i_wb_stb, i_wb_we, 73 | input wire [31:0] i_wb_data, 74 | input wire [32/8-1:0] i_wb_sel, 75 | // 76 | output wire o_wb_stall, 77 | output wire o_wb_ack, 78 | output wire [31:0] o_wb_data, 79 | // 80 | input wire [(NIN-1):0] i_gpio, 81 | output reg [(NOUT-1):0] o_gpio, 82 | // 83 | output reg o_int 84 | // }}} 85 | ); 86 | 87 | // Local declarations 88 | // {{{ 89 | reg [(NIN-1):0] r_gpio; 90 | (* ASYNC_REG *) reg [(NIN-1):0] x_gpio, q_gpio; 91 | wire [15:0] hi_bits, low_bits; 92 | // }}} 93 | 94 | assign o_wb_ack = i_wb_stb; 95 | assign o_wb_stall = 1'b0; 96 | 97 | // o_gpio 98 | // {{{ 99 | // 9LUT's, 16 FF's 100 | initial o_gpio = DEFAULT; 101 | always @(posedge i_clk) 102 | if (i_wb_stb && i_wb_we && (&i_wb_sel)) 103 | o_gpio <= ((o_gpio)&(~i_wb_data[(NOUT+16-1):16])) 104 | |((i_wb_data[(NOUT-1):0])&(i_wb_data[(NOUT+16-1):16])); 105 | // }}} 106 | 107 | // 3 LUTs, 33 FF's 108 | // {{{ 109 | always @(posedge i_clk) 110 | begin 111 | { r_gpio, q_gpio, x_gpio } <= { q_gpio, x_gpio, i_gpio }; 112 | o_int <= (q_gpio != r_gpio); 113 | end 114 | // }}} 115 | 116 | // o_wb_data 117 | // {{{ 118 | assign hi_bits[ (NIN -1):0] = r_gpio; 119 | assign low_bits[(NOUT-1):0] = o_gpio; 120 | 121 | generate 122 | if (NIN < 16) 123 | begin : GEN_HIBITS 124 | assign hi_bits[ 15: NIN] = 0; 125 | end 126 | if (NOUT < 16) 127 | begin : GEN_LOBITS 128 | assign low_bits[15:NOUT] = 0; 129 | end endgenerate 130 | 131 | assign o_wb_data = { hi_bits, low_bits }; 132 | // }}} 133 | 134 | // Make Verilator happy 135 | // {{{ 136 | // verilator lint_off UNUSED 137 | wire unused; 138 | assign unused = &{ 1'b0, i_wb_cyc, i_wb_data[31:0], i_wb_sel }; 139 | // verilator lint_on UNUSED 140 | // }}} 141 | endmodule 142 | -------------------------------------------------------------------------------- /bench/verilog/wb2axip/wbupsz.v: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: bench/verilog/wb2axip/wbupsz.v 4 | // {{{ 5 | // Project: SD-Card controller 6 | // 7 | // Purpose: Bridge a Wishbone bus from a smaller data width to a wider one. 8 | // 9 | // Creator: Dan Gisselquist, Ph.D. 10 | // Gisselquist Technology, LLC 11 | // 12 | //////////////////////////////////////////////////////////////////////////////// 13 | // }}} 14 | // Copyright (C) 2016-2025, Gisselquist Technology, LLC 15 | // {{{ 16 | // This program is free software (firmware): you can redistribute it and/or 17 | // modify it under the terms of the GNU General Public License as published 18 | // by the Free Software Foundation, either version 3 of the License, or (at 19 | // your option) any later version. 20 | // 21 | // This program is distributed in the hope that it will be useful, but WITHOUT 22 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 23 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 24 | // for more details. 25 | // 26 | // You should have received a copy of the GNU General Public License along 27 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no 28 | // target there if the PDF file isn't present.) If not, see 29 | // for a copy. 30 | // }}} 31 | // License: GPL, v3, as defined and found on www.gnu.org, 32 | // {{{ 33 | // http://www.gnu.org/licenses/gpl.html 34 | // 35 | //////////////////////////////////////////////////////////////////////////////// 36 | // 37 | `default_nettype none 38 | // }}} 39 | module wbupsz #( 40 | // {{{ 41 | parameter ADDRESS_WIDTH = 28, // Byte address width 42 | parameter WIDE_DW = 512, 43 | parameter SMALL_DW = 32, 44 | parameter [0:0] OPT_LITTLE_ENDIAN = 1'b0, 45 | parameter [0:0] OPT_LOWPOWER = 1'b0 46 | // }}} 47 | ) ( 48 | // {{{ 49 | input wire i_clk, i_reset, 50 | // Incoming small port 51 | // {{{ 52 | input wire i_scyc, i_sstb, i_swe, 53 | input wire [ADDRESS_WIDTH-$clog2(SMALL_DW/8)-1:0] i_saddr, 54 | input wire [SMALL_DW-1:0] i_sdata, 55 | input wire [SMALL_DW/8-1:0] i_ssel, 56 | output wire o_sstall, 57 | output wire o_sack, 58 | output wire [SMALL_DW-1:0] o_sdata, 59 | output wire o_serr, 60 | // }}} 61 | // Outgoing, small bus size, port 62 | // {{{ 63 | output wire o_wcyc, o_wstb, o_wwe, 64 | output wire [ADDRESS_WIDTH-$clog2(WIDE_DW/8)-1:0] o_waddr, 65 | output wire [WIDE_DW-1:0] o_wdata, 66 | output wire [WIDE_DW/8-1:0] o_wsel, 67 | input wire i_wstall, 68 | input wire i_wack, 69 | input wire [WIDE_DW-1:0] i_wdata, 70 | input wire i_werr 71 | // }}} 72 | // }}} 73 | ); 74 | 75 | generate if (WIDE_DW == SMALL_DW) 76 | begin : NO_ADJUSTMENT 77 | // {{{ 78 | assign o_wcyc = i_scyc; 79 | assign o_wstb = i_sstb; 80 | assign o_wwe = i_swe; 81 | assign o_waddr = i_saddr; 82 | assign o_wdata = i_sdata; 83 | assign o_wsel = i_ssel; 84 | 85 | assign o_sstall = i_wstall; 86 | assign o_sack = i_wack; 87 | assign o_sdata = i_wdata; 88 | assign o_serr = i_werr; 89 | 90 | // Keep Verilator happy 91 | // {{{ 92 | // Verilator lint_off UNUSED 93 | wire unused; 94 | assign unused = &{ 1'b0, i_clk, i_reset }; 95 | // Verilator lint_on UNUSED 96 | // }}} 97 | // }}} 98 | end else begin : UPSIZE 99 | localparam LGFIFO = 5; 100 | reg r_cyc, r_stb, r_we, r_ack, r_err; 101 | reg [ADDRESS_WIDTH-$clog2(WIDE_DW/8)-1:0] r_addr; 102 | reg [WIDE_DW-1:0] r_data, rtn_data; 103 | reg [WIDE_DW/8-1:0] r_sel; 104 | reg [$clog2(WIDE_DW/SMALL_DW)-1:0] r_shift; 105 | wire fifo_full, ign_fifo_empty; 106 | wire [LGFIFO:0] ign_fifo_fill; 107 | 108 | wire [$clog2(WIDE_DW/SMALL_DW)-1:0] w_shift, fifo_shift; 109 | wire [WIDE_DW-1:0] w_data; 110 | wire [WIDE_DW/8-1:0] w_sel; 111 | 112 | if (OPT_LITTLE_ENDIAN) 113 | begin : GEN_LILEND 114 | assign w_data= {{(WIDE_DW-SMALL_DW){1'b0}}, i_sdata }; 115 | assign w_sel ={{((WIDE_DW-SMALL_DW)/8){1'b0}},i_ssel }; 116 | end else begin : GEN_BIGEND 117 | assign w_data= {i_sdata, {(WIDE_DW-SMALL_DW){1'b0}} }; 118 | assign w_sel ={i_ssel,{((WIDE_DW-SMALL_DW)/8){1'b0}} }; 119 | end 120 | 121 | assign w_shift = i_saddr[$clog2(WIDE_DW/SMALL_DW)-1:0]; 122 | 123 | initial r_cyc = 1'b0; 124 | always @(posedge i_clk) 125 | if (i_reset || !i_scyc ||(o_wcyc && i_werr) || o_serr) 126 | r_cyc <= 1'b0; 127 | else if (i_scyc && i_sstb) 128 | r_cyc <= 1'b1; 129 | 130 | initial r_stb = 1'b0; 131 | initial r_we = 1'b0; 132 | initial r_addr = 0; 133 | initial r_data = 0; 134 | initial r_sel = 0; 135 | always @(posedge i_clk) 136 | if (i_reset || !i_scyc || o_serr || (o_wcyc && i_werr)) 137 | begin 138 | // {{{ 139 | r_stb <= 1'b0; 140 | r_we <= 1'b0; 141 | r_addr <= 0; 142 | r_data <= 0; 143 | r_sel <= 0; 144 | r_shift <= 0; 145 | // }}} 146 | end else if (i_sstb && !o_sstall) // New request 147 | begin 148 | // {{{ 149 | r_stb <= 1'b1; 150 | r_we <= i_swe; 151 | r_addr <= i_saddr[ADDRESS_WIDTH-$clog2(SMALL_DW/8)-1:$clog2(WIDE_DW/SMALL_DW)]; 152 | if (OPT_LITTLE_ENDIAN) 153 | begin 154 | r_data <= w_data << (SMALL_DW * w_shift); 155 | r_sel <= w_sel << ((SMALL_DW/8) * w_shift); 156 | end else begin 157 | r_data <= w_data >> (SMALL_DW * w_shift); 158 | r_sel <= w_sel >> ((SMALL_DW/8) * w_shift); 159 | end 160 | r_shift <= w_shift; 161 | // }}} 162 | end else if (o_wstb && !i_wstall) 163 | r_stb <= 1'b0; 164 | 165 | assign o_wcyc = r_cyc; 166 | assign o_wstb = r_stb && !fifo_full; 167 | assign o_wwe = r_we; 168 | assign o_waddr = r_addr; 169 | assign o_wdata = r_data; 170 | assign o_wsel = r_sel; 171 | 172 | sfifo #( 173 | .BW($clog2(WIDE_DW/SMALL_DW)), .LGFLEN(LGFIFO) 174 | ) u_fifo ( 175 | // {{{ 176 | .i_clk(i_clk), .i_reset(i_reset || !i_scyc), 177 | .i_wr(o_wstb && !i_wstall), 178 | .i_data(r_shift), 179 | .o_full(fifo_full), .o_fill(ign_fifo_fill), 180 | .i_rd(i_wack), .o_data(fifo_shift), 181 | .o_empty(ign_fifo_empty) 182 | // }}} 183 | ); 184 | 185 | // o_sdata&rtn_data, the return (shifted) data in the WIDE space 186 | // {{{ 187 | initial r_data = 0; 188 | always @(posedge i_clk) 189 | if (OPT_LOWPOWER && (!i_scyc || !o_wcyc || i_werr)) 190 | rtn_data <= 0; 191 | else if (i_wack) 192 | begin 193 | if (OPT_LITTLE_ENDIAN) 194 | rtn_data <= i_wdata >> (SMALL_DW * fifo_shift); 195 | else 196 | rtn_data <= i_wdata << (SMALL_DW * fifo_shift); 197 | end 198 | 199 | if (OPT_LITTLE_ENDIAN) 200 | begin : GEN_LILDATA 201 | assign o_sdata = rtn_data[SMALL_DW-1:0]; 202 | end else begin : GEN_BIGDATA 203 | assign o_sdata = rtn_data[WIDE_DW-1:WIDE_DW-SMALL_DW]; 204 | end 205 | // }}} 206 | 207 | // o_sack, r_ack 208 | // {{{ 209 | initial r_ack = 0; 210 | always @(posedge i_clk) 211 | r_ack <= !i_reset && i_scyc && o_wcyc && i_wack; 212 | 213 | assign o_sack = r_ack; 214 | // }}} 215 | 216 | // o_serr, r_err 217 | // {{{ 218 | initial r_err = 0; 219 | always @(posedge i_clk) 220 | r_err <= !i_reset && i_scyc && o_wcyc && i_werr; 221 | 222 | assign o_serr = r_err; 223 | // }}} 224 | 225 | assign o_sstall= r_stb && (fifo_full || i_wstall); 226 | 227 | // Keep Verilator happy 228 | // {{{ 229 | // Verilator lint_off UNUSED 230 | wire unused; 231 | assign unused = &{ 1'b0, ign_fifo_fill, ign_fifo_empty, 232 | rtn_data }; 233 | // Verilator lint_on UNUSED 234 | // }}} 235 | end endgenerate 236 | 237 | endmodule 238 | -------------------------------------------------------------------------------- /bench/verilog/wb_bfm.v: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: bench/verilog/wb_bfm.v 4 | // {{{ 5 | // Project: SD-Card controller 6 | // 7 | // Purpose: Drive a Wishbone bus via commands from a test script. 8 | // 9 | // Creator: Dan Gisselquist, Ph.D. 10 | // Gisselquist Technology, LLC 11 | // 12 | //////////////////////////////////////////////////////////////////////////////// 13 | // }}} 14 | // Copyright (C) 2016-2025, Gisselquist Technology, LLC 15 | // {{{ 16 | // This program is free software (firmware): you can redistribute it and/or 17 | // modify it under the terms of the GNU General Public License as published 18 | // by the Free Software Foundation, either version 3 of the License, or (at 19 | // your option) any later version. 20 | // 21 | // This program is distributed in the hope that it will be useful, but WITHOUT 22 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 23 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 24 | // for more details. 25 | // 26 | // You should have received a copy of the GNU General Public License along 27 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no 28 | // target there if the PDF file isn't present.) If not, see 29 | // for a copy. 30 | // }}} 31 | // License: GPL, v3, as defined and found on www.gnu.org, 32 | // {{{ 33 | // http://www.gnu.org/licenses/gpl.html 34 | // 35 | //////////////////////////////////////////////////////////////////////////////// 36 | // 37 | `default_nettype none 38 | // }}} 39 | module wb_bfm #( 40 | parameter AW = 5, 41 | parameter DW = 32, 42 | parameter LGFIFO = 4, 43 | parameter [0:0] OPT_DEBUG = 1'b0 44 | ) ( 45 | // {{{ 46 | input wire i_clk, i_reset, 47 | // 48 | output reg o_wb_cyc, o_wb_stb, o_wb_we, 49 | output reg [AW-1:0] o_wb_addr, 50 | output reg [DW-1:0] o_wb_data, 51 | output reg [DW/8-1:0] o_wb_sel, 52 | input wire i_wb_stall, 53 | input wire i_wb_ack, 54 | input wire [DW-1:0] i_wb_data, 55 | input wire i_wb_err 56 | // }}} 57 | ); 58 | 59 | // Local declarations 60 | // {{{ 61 | localparam WBLSB = $clog2(DW/8); 62 | localparam ADDR_WIDTH = AW + WBLSB; 63 | 64 | reg [31:0] bus_outstanding, req_outstanding; 65 | wire [31:0] bus_committed; 66 | reg [LGFIFO:0] fifo_fill, fifo_rdaddr, fifo_wraddr; 67 | reg [1+(DW/8)+AW+DW-1:0] fifo [0:((1< %08x", addr, dat); 167 | end endtask 168 | // }}} 169 | 170 | // }}} 171 | //////////////////////////////////////////////////////////////////////// 172 | // 173 | // Issue requests 174 | // {{{ 175 | assign bus_committed = bus_outstanding + (o_wb_stb ? 1:0); 176 | assign bus_full = (&bus_committed); 177 | 178 | always @(posedge i_clk) 179 | if (i_reset || !o_wb_cyc || i_wb_err) 180 | bus_outstanding <= 0; 181 | else case({ (o_wb_stb && !i_wb_stall), i_wb_ack }) 182 | 2'b10: bus_outstanding <= bus_outstanding + 1; 183 | 2'b01: bus_outstanding <= (bus_outstanding > 0) 184 | ? (bus_outstanding - 1) : 0; 185 | default: begin end 186 | endcase 187 | 188 | always @(*) 189 | { next_we, next_sel, next_addr, next_dat } = fifo[fifo_rdaddr[LGFIFO-1:0]]; 190 | always @(*) 191 | fifo_fill = fifo_wraddr - fifo_rdaddr; 192 | 193 | always @(*) 194 | req_outstanding = fifo_fill + bus_outstanding; 195 | 196 | always @(posedge i_clk) 197 | if (i_reset) 198 | begin 199 | // {{{ 200 | fifo_rdaddr <= 0; 201 | o_wb_cyc <= 0; 202 | o_wb_stb <= 0; 203 | o_wb_we <= 0; 204 | o_wb_addr <= 0; 205 | o_wb_data <= 0; 206 | o_wb_sel <= 0; 207 | // }}} 208 | end else if (o_wb_cyc && i_wb_err) 209 | begin 210 | // {{{ 211 | fifo_rdaddr <= fifo_wraddr; 212 | o_wb_cyc <= 0; 213 | o_wb_stb <= 0; 214 | o_wb_we <= 0; 215 | o_wb_addr <= 0; 216 | o_wb_data <= 0; 217 | o_wb_sel <= 0; 218 | // }}} 219 | end else if ((!o_wb_stb || !i_wb_stall) && (fifo_rdaddr != fifo_wraddr) 220 | && (!o_wb_cyc || (o_wb_we == next_we))) 221 | begin 222 | // {{{ 223 | o_wb_cyc <= 1'b1; 224 | o_wb_we <= next_we; 225 | o_wb_addr <= next_addr; 226 | o_wb_data <= next_dat; 227 | o_wb_sel <= next_sel; 228 | 229 | if (!bus_full) 230 | begin 231 | o_wb_stb <= 1'b1; 232 | fifo_rdaddr <= fifo_rdaddr + 1; 233 | end else begin 234 | o_wb_stb <= 1'b0; 235 | end 236 | // }}} 237 | end else begin 238 | // {{{ 239 | if (!i_wb_stall) 240 | o_wb_stb <= 1'b0; 241 | 242 | if (o_wb_cyc && i_wb_ack) 243 | begin 244 | 245 | if (bus_outstanding == 1 && !o_wb_stb) 246 | o_wb_cyc <= 1'b0; 247 | else if (bus_outstanding == 0 && o_wb_stb && !i_wb_stall) 248 | o_wb_cyc <= 1'b0; 249 | end 250 | 251 | if (bus_outstanding == 0 && !o_wb_stb) 252 | begin 253 | o_wb_cyc <= 1'b0; 254 | o_wb_stb <= 1'b0; 255 | o_wb_we <= 1'b0; 256 | o_wb_addr <= 0; 257 | o_wb_data <= 0; 258 | o_wb_sel <= 0; 259 | end 260 | // }}} 261 | end 262 | // }}} 263 | endmodule 264 | 265 | -------------------------------------------------------------------------------- /doc/20240214-1-originaltb.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20240214-1-originaltb.dia -------------------------------------------------------------------------------- /doc/20240214-1-originaltb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20240214-1-originaltb.png -------------------------------------------------------------------------------- /doc/20240214-2-simpletb.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20240214-2-simpletb.dia -------------------------------------------------------------------------------- /doc/20240214-2-simpletb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20240214-2-simpletb.png -------------------------------------------------------------------------------- /doc/20240214-3-kitchensink.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20240214-3-kitchensink.dia -------------------------------------------------------------------------------- /doc/20240214-3-kitchensink.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20240214-3-kitchensink.png -------------------------------------------------------------------------------- /doc/20240214-4-dotmem.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20240214-4-dotmem.dia -------------------------------------------------------------------------------- /doc/20240214-4-dotmem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20240214-4-dotmem.png -------------------------------------------------------------------------------- /doc/20240214-5-dblaxi.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20240214-5-dblaxi.dia -------------------------------------------------------------------------------- /doc/20240214-5-dblaxi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20240214-5-dblaxi.png -------------------------------------------------------------------------------- /doc/20240221-1-trace.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20240221-1-trace.dia -------------------------------------------------------------------------------- /doc/20240221-1-trace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20240221-1-trace.png -------------------------------------------------------------------------------- /doc/20240221-2-steps.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20240221-2-steps.dia -------------------------------------------------------------------------------- /doc/20240221-2-steps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20240221-2-steps.png -------------------------------------------------------------------------------- /doc/20240221-3-cmd.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20240221-3-cmd.dia -------------------------------------------------------------------------------- /doc/20240221-3-cmd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20240221-3-cmd.png -------------------------------------------------------------------------------- /doc/20240221-4-buffer.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20240221-4-buffer.dia -------------------------------------------------------------------------------- /doc/20240221-4-buffer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20240221-4-buffer.png -------------------------------------------------------------------------------- /doc/20240221-5-axis.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20240221-5-axis.dia -------------------------------------------------------------------------------- /doc/20240221-5-axis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20240221-5-axis.png -------------------------------------------------------------------------------- /doc/20240221-6-dmablk.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20240221-6-dmablk.dia -------------------------------------------------------------------------------- /doc/20240221-6-dmablk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20240221-6-dmablk.png -------------------------------------------------------------------------------- /doc/20240221-6-dmaparts.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20240221-6-dmaparts.dia -------------------------------------------------------------------------------- /doc/20240221-7-blkdiag.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20240221-7-blkdiag.dia -------------------------------------------------------------------------------- /doc/20240221-7-blkdiag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20240221-7-blkdiag.png -------------------------------------------------------------------------------- /doc/20240221-sddma.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20240221-sddma.png -------------------------------------------------------------------------------- /doc/20240315-sim-benchmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20240315-sim-benchmark.png -------------------------------------------------------------------------------- /doc/20241125-usage-comparison.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20241125-usage-comparison.dia -------------------------------------------------------------------------------- /doc/20241125-usage-comparison.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20241125-usage-comparison.png -------------------------------------------------------------------------------- /doc/20241125-usage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20241125-usage.png -------------------------------------------------------------------------------- /doc/20241130-1p8vprogress.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20241130-1p8vprogress.dia -------------------------------------------------------------------------------- /doc/20241130-1p8vprogress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20241130-1p8vprogress.png -------------------------------------------------------------------------------- /doc/20241230-cmd19-annotated.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20241230-cmd19-annotated.dia -------------------------------------------------------------------------------- /doc/20241230-cmd19-annotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20241230-cmd19-annotated.png -------------------------------------------------------------------------------- /doc/20241230-cmd19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20241230-cmd19.png -------------------------------------------------------------------------------- /doc/20241230-cmd19z-annotated.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20241230-cmd19z-annotated.dia -------------------------------------------------------------------------------- /doc/20241230-cmd19z-annotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20241230-cmd19z-annotated.png -------------------------------------------------------------------------------- /doc/20241230-cmd19z.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/20241230-cmd19z.png -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | ## 3 | ## Filename: doc/Makefile 4 | ## {{{ 5 | ## Project: SD-Card controller 6 | ## 7 | ## Purpose: To coordinate the build of documentation PDFs from their 8 | ## LaTeX sources. 9 | ## 10 | ## Targets include: 11 | ## all Builds all documents 12 | ## gpl-3.0.pdf Builds the GPL license these files are released 13 | ## under. 14 | ## spec.pdf Builds the specification for the SDSPI 15 | ## controller. 16 | ## 17 | ## Creator: Dan Gisselquist, Ph.D. 18 | ## Gisselquist Technology, LLC 19 | ## 20 | ################################################################################ 21 | ## }}} 22 | ## Copyright (C) 2016-2025, Gisselquist Technology, LLC 23 | ## {{{ 24 | ## This program is free software (firmware): you can redistribute it and/or 25 | ## modify it under the terms of the GNU General Public License as published 26 | ## by the Free Software Foundation, either version 3 of the License, or (at 27 | ## your option) any later version. 28 | ## 29 | ## This program is distributed in the hope that it will be useful, but WITHOUT 30 | ## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 31 | ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 32 | ## for more details. 33 | ## 34 | ## You should have received a copy of the GNU General Public License along 35 | ## with this program. (It's in the $(ROOT)/doc directory. Run make with no 36 | ## target there if the PDF file isn't present.) If not, see 37 | ## for a copy. 38 | ## }}} 39 | ## License: GPL, v3, as defined and found on www.gnu.org, 40 | ## {{{ 41 | ## http://www.gnu.org/licenses/gpl.html 42 | ## 43 | ################################################################################ 44 | ## 45 | ## }}} 46 | all: gpl-3.0.pdf sdspi.pdf sdio.pdf 47 | DSRC := src 48 | 49 | .PHONY: gpl 50 | gpl: gpl-3.0.pdf 51 | ## {{{ 52 | gpl-3.0.pdf: $(DSRC)/gpl-3.0.tex 53 | latex $(DSRC)/gpl-3.0.tex 54 | latex $(DSRC)/gpl-3.0.tex 55 | dvips -q -z -t letter -P pdf -o gpl-3.0.ps gpl-3.0.dvi 56 | ps2pdf -dAutoRotatePages=/All gpl-3.0.ps gpl-3.0.pdf 57 | rm gpl-3.0.dvi gpl-3.0.log gpl-3.0.aux gpl-3.0.ps 58 | ## }}} 59 | 60 | .PHONY: spec 61 | spec: sdspi sdio 62 | 63 | .PHONY: sdspi 64 | ## {{{ 65 | sdspi: sdspi.pdf 66 | sdspi.pdf: $(DSRC)/sdspi.tex $(DSRC)/gqtekspec.cls $(DSRC)/GT.eps 67 | cd $(DSRC)/; latex sdspi.tex 68 | cd $(DSRC)/; latex sdspi.tex 69 | cd $(DSRC)/; dvips -q -z -t letter -P pdf -o ../sdspi.ps sdspi.dvi 70 | ps2pdf -dAutoRotatePages=/All sdspi.ps sdspi.pdf 71 | -grep -i warning $(DSRC)/sdspi.log 72 | @rm -f $(DSRC)/sdspi.dvi $(DSRC)/sdspi.log 73 | @rm -f $(DSRC)/sdspi.aux $(DSRC)/sdspi.toc 74 | @rm -f $(DSRC)/sdspi.lot $(DSRC)/sdspi.lof 75 | @rm -f $(DSRC)/sdspi.out sdspi.ps 76 | ## }}} 77 | 78 | .PHONY: sdio 79 | ## {{{ 80 | sdio: sdio.pdf 81 | sdio.pdf: $(DSRC)/sdio.tex $(DSRC)/gqtekspec.cls $(DSRC)/GT.eps 82 | cd $(DSRC)/; latex sdio.tex 83 | cd $(DSRC)/; latex sdio.tex 84 | cd $(DSRC)/; dvips -q -z -t letter -P pdf -o ../sdio.ps sdio.dvi 85 | ps2pdf -dAutoRotatePages=/All sdio.ps sdio.pdf 86 | -grep -i warning $(DSRC)/sdio.log 87 | @rm -f $(DSRC)/sdio.dvi $(DSRC)/sdio.log 88 | @rm -f $(DSRC)/sdio.aux $(DSRC)/sdio.toc 89 | @rm -f $(DSRC)/sdio.lot $(DSRC)/sdio.lof 90 | @rm -f $(DSRC)/sdio.out sdio.ps 91 | ## }}} 92 | 93 | .PHONY: clean 94 | ## {{{ 95 | clean: 96 | rm -f $(DSRC)/sdspi.dvi $(DSRC)/sdspi.log 97 | rm -f $(DSRC)/sdspi.aux $(DSRC)/sdspi.toc 98 | rm -f $(DSRC)/sdspi.lot $(DSRC)/sdspi.lof 99 | rm -f $(DSRC)/sdspi.out sdspi.ps sdspi.pdf 100 | # 101 | rm -f $(DSRC)/sdio.dvi $(DSRC)/sdio.log 102 | rm -f $(DSRC)/sdio.aux $(DSRC)/sdio.toc 103 | rm -f $(DSRC)/sdio.lot $(DSRC)/sdio.lof 104 | rm -f $(DSRC)/sdio.out sdio.ps sdio.pdf 105 | rm -f gpl-3.0.pdf 106 | ## }}} 107 | -------------------------------------------------------------------------------- /doc/devprogress.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/devprogress.dia -------------------------------------------------------------------------------- /doc/devstat.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/devstat.dia -------------------------------------------------------------------------------- /doc/devstat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/devstat.png -------------------------------------------------------------------------------- /doc/gpl-3.0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/gpl-3.0.pdf -------------------------------------------------------------------------------- /doc/hwteststat.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/hwteststat.dia -------------------------------------------------------------------------------- /doc/hwteststat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/hwteststat.png -------------------------------------------------------------------------------- /doc/sdio.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/sdio.pdf -------------------------------------------------------------------------------- /doc/sdspi.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/sdspi.pdf -------------------------------------------------------------------------------- /doc/src/.gitignore: -------------------------------------------------------------------------------- 1 | *.aux 2 | *.out 3 | *.lof 4 | *.lot 5 | *.toc 6 | *.ps 7 | *.dvi 8 | /*.pdf 9 | -------------------------------------------------------------------------------- /doc/src/GT.eps: -------------------------------------------------------------------------------- 1 | %!PS-Adobe-3.0 EPSF-3.0 2 | %%BoundingBox: 0 0 504 288 3 | %%Creator: Gisselquist Technology LLC 4 | %%Title: Gisselquist Technology Logo 5 | %%CreationDate: 11 Mar 2014 6 | %%EndComments 7 | %%BeginProlog 8 | /black { 0 setgray } def 9 | /white { 1 setgray } def 10 | /height { 288 } def 11 | /lw { height 8 div } def 12 | %%EndProlog 13 | % %%Page: 1 14 | 15 | false { % A bounding box 16 | 0 setlinewidth 17 | newpath 18 | 0 0 moveto 19 | 0 height lineto 20 | 1.625 height mul lw add 0 rlineto 21 | 0 height neg rlineto 22 | closepath stroke 23 | } if 24 | 25 | true { % The "G" 26 | newpath 27 | height 2 div 1.25 mul height moveto 28 | height 2 div height 4 div sub height lineto 29 | 0 height 3 4 div mul lineto 30 | 0 height 4 div lineto 31 | height 4 div 0 lineto 32 | height 3 4 div mul 0 lineto 33 | height height 4 div lineto 34 | height height 2 div lineto 35 | % 36 | height lw sub height 2 div lineto 37 | height lw sub height 4 div lw 2 div add lineto 38 | height 3 4 div mul lw 2 div sub lw lineto 39 | height 4 div lw 2 div add lw lineto 40 | lw height 4 div lw 2 div add lineto 41 | lw height 3 4 div mul lw 2 div sub lineto 42 | height 4 div lw 2 div add height lw sub lineto 43 | height 2 div 1.25 mul height lw sub lineto 44 | closepath fill 45 | newpath 46 | height 2 div height 2 div moveto 47 | height 2 div 0 rlineto 48 | 0 height 2 div neg rlineto 49 | lw neg 0 rlineto 50 | 0 height 2 div lw sub rlineto 51 | height 2 div height 2 div lw sub lineto 52 | closepath fill 53 | } if 54 | 55 | height 2 div 1.25 mul lw add 0 translate 56 | false { 57 | newpath 58 | 0 height moveto 59 | height 0 rlineto 60 | 0 lw neg rlineto 61 | height lw sub 2 div neg 0 rlineto 62 | 0 height lw sub neg rlineto 63 | lw neg 0 rlineto 64 | 0 height lw sub rlineto 65 | height lw sub 2 div neg 0 rlineto 66 | 0 lw rlineto 67 | closepath fill 68 | } if 69 | 70 | true { % The "T" of "GT". 71 | newpath 72 | 0 height moveto 73 | height lw add 2 div 0 rlineto 74 | 0 height neg rlineto 75 | lw neg 0 rlineto 76 | 0 height lw sub rlineto 77 | height lw sub 2 div neg 0 rlineto 78 | closepath fill 79 | 80 | % The right half of the top of the "T" 81 | newpath 82 | % (height + lw)/2 + lw 83 | height lw add 2 div lw add height moveto 84 | % height - (above) = height - height/2 - 3/2 lw = height/2-3/2lw 85 | height 3 lw mul sub 2 div 0 rlineto 86 | 0 lw neg rlineto 87 | height 3 lw mul sub 2 div neg 0 rlineto 88 | closepath fill 89 | } if 90 | 91 | 92 | grestore 93 | showpage 94 | %%EOF 95 | -------------------------------------------------------------------------------- /doc/src/gfx/cputb.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/src/gfx/cputb.dia -------------------------------------------------------------------------------- /doc/src/gfx/dmablocks.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/src/gfx/dmablocks.dia -------------------------------------------------------------------------------- /doc/src/gfx/dmablocks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/src/gfx/dmablocks.png -------------------------------------------------------------------------------- /doc/src/gfx/mdlsdio.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/src/gfx/mdlsdio.dia -------------------------------------------------------------------------------- /doc/src/gfx/sdioblocks.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/src/gfx/sdioblocks.dia -------------------------------------------------------------------------------- /doc/src/gfx/sdiocmdflow.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/src/gfx/sdiocmdflow.dia -------------------------------------------------------------------------------- /doc/src/gfx/sdiotxflow.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/src/gfx/sdiotxflow.dia -------------------------------------------------------------------------------- /doc/src/gfx/swlayers.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/src/gfx/swlayers.dia -------------------------------------------------------------------------------- /doc/src/gfx/vlogtb.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/src/gfx/vlogtb.dia -------------------------------------------------------------------------------- /doc/src/zshell.sty: -------------------------------------------------------------------------------- 1 | \ProvidesFile{zshell.sty} 2 | [2018/01/25 0.9 SVA+Verilog language file] 3 | %% 4 | \usepackage{lstlang1} 5 | \usepackage{lstlang2} 6 | % \usepackage{lstlang1.sty} 7 | % 8 | \lst@definelanguage{Constraint}% 9 | {morekeywords={NET,set_io,IOSTANDARD,LOC,set_property,-dict,get_ports},% 10 | morecomment=[l]\#,% 11 | morestring=[b]" 12 | }[keywords,comments]% 13 | % 14 | \definecolor{bcomment}{rgb}{0.7,0.7,0.7} % Comments 15 | \definecolor{brword}{rgb}{0.0,0.2,0.2} % Reserved words 16 | \newcommand\blist{[language=bash]} 17 | \newcommand\bset{\lstset{language=bash,% 18 | basicstyle={\ttfamily\small},% 19 | keywordstyle={\ttfamily\bf \color{brword}},% 20 | commentstyle=\em\color{bcomment},% 21 | tabsize=8,% 22 | mathescape=false, 23 | numberstyle={\tiny \color{black}},% 24 | identifierstyle=\ttfamily\color{black}}} 25 | \newcommand\binline{\bset\lstinline} 26 | \lstnewenvironment{zbash}{% 27 | \bset\lstset{frame=tRBl,% escapeinside=`', 28 | backgroundcolor=\color{gray!05}}}{} 29 | % 30 | \lstnewenvironment{zconstraint}{% 31 | \lstset{language=sh,frame=tRBl,% escapeinside=`, 32 | basicstyle={\ttfamily\small},% 33 | mathescape=false, 34 | backgroundcolor=\color{blue!05}}}{} 35 | % 36 | \lstnewenvironment{zVCD}{% 37 | \bset\lstset{frame=tRBl,% escapeinside=`', 38 | backgroundcolor=\color{gray!05}}}{} 39 | % 40 | \newcommand\cplist{[language=C++]} 41 | \definecolor{cpcomment}{rgb}{0.4,0.4,0.4} % Comments 42 | \definecolor{cprword}{rgb}{0.0,0.2,0.2} % Reserved words 43 | \newcommand\cpset{\lstset{language=C++,% 44 | basicstyle={\ttfamily\small},% 45 | keywordstyle={\ttfamily\bf \color{cprword}},% 46 | commentstyle=\em\color{cpcomment},% 47 | tabsize=8,% 48 | mathescape=false, 49 | numberstyle={\tiny \color{black}},% 50 | identifierstyle=\ttfamily\small\bf\color{black}}} 51 | \lstnewenvironment{zCpp}{% 52 | \cpset\lstset{frame=tRBl,% escapeinside=`', 53 | backgroundcolor=\color{red!10}}}{} 54 | \newcommand\cppinline{\cpset\lstinline} 55 | % 56 | \newcommand\gmklist{[language=make]} 57 | \definecolor{gmkbackground}{rgb}{0.95,1.0,0.95} % Background 58 | \definecolor{gmkcomment}{rgb}{0.4,0.4,0.4} % Comments 59 | \definecolor{gmkword}{rgb}{0.0,0.2,0.2} % Reserved words 60 | \newcommand\gmkset{\lstset{language=make,% 61 | basicstyle={\ttfamily\small},% 62 | keywordstyle={\ttfamily\bf \color{gmkword}},% 63 | commentstyle=\em\color{gmkcomment},% 64 | tabsize=8,% 65 | mathescape=false, 66 | numberstyle={\tiny \color{black}},% 67 | identifierstyle=\ttfamily\small\bf\color{black}}} 68 | \lstnewenvironment{zmake}{% 69 | \gmkset\lstset{frame=tRBl,% escapeinside=`', 70 | backgroundcolor=\color{gmkbackground}}}{} 71 | \newcommand\gmkinline{\gmkset\lstinline} 72 | % 73 | \endinput 74 | %% 75 | -------------------------------------------------------------------------------- /doc/wbsdstart.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/wbsdstart.dia -------------------------------------------------------------------------------- /doc/wbsdstart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/sdspi/a1d912367ce71389ef25ced4b83d34d23b05b391/doc/wbsdstart.png -------------------------------------------------------------------------------- /rtl/.gitignore: -------------------------------------------------------------------------------- 1 | usage.ys 2 | -------------------------------------------------------------------------------- /rtl/Makefile: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | ## 3 | ## Filename: rtl/Makefile 4 | ## {{{ 5 | ## Project: SD-Card controller 6 | ## 7 | ## Purpose: To build the Verilator library necessary for simulating (via 8 | ## verilator) this code. 9 | ## 10 | ## Creator: Dan Gisselquist, Ph.D. 11 | ## Gisselquist Technology, LLC 12 | ## 13 | ################################################################################ 14 | ## }}} 15 | ## Copyright (C) 2016-2025, Gisselquist Technology, LLC 16 | ## {{{ 17 | ## This program is free software (firmware): you can redistribute it and/or 18 | ## modify it under the terms of the GNU General Public License as published 19 | ## by the Free Software Foundation, either version 3 of the License, or (at 20 | ## your option) any later version. 21 | ## 22 | ## This program is distributed in the hope that it will be useful, but WITHOUT 23 | ## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 24 | ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 25 | ## for more details. 26 | ## 27 | ## You should have received a copy of the GNU General Public License along 28 | ## with this program. (It's in the $(ROOT)/doc directory. Run make with no 29 | ## target there if the PDF file isn't present.) If not, see 30 | ## for a copy. 31 | ## }}} 32 | ## License: GPL, v3, as defined and found on www.gnu.org, 33 | ## {{{ 34 | ## http://www.gnu.org/licenses/gpl.html 35 | ## 36 | ################################################################################ 37 | ## 38 | ## }}} 39 | .PHONY: all 40 | all: 41 | VERILATOR:= verilator 42 | # VOB := $(HOME)/src/verilog/vopro ## Verilog scrambler 43 | VOB := cat 44 | VOBJ:= obj_dir 45 | VFLAGS := -MMD -Wall -trace -cc 46 | SUBMAKE:= $(MAKE) --no-print-directory -C 47 | SDSPI_FILES := sdspi.v spicmd.v spitxdata.v spirxdata.v llsdspi.v 48 | SDDMA_FILES := sddma_mm2s.v sddma_rxgears.v sddma_txgears.v sddma_s2mm.v sddma.v sdfifo.v sdskid.v 49 | SDIO_FILES := sdio.v sdwb.v sdckgen.v sdcmd.v sdrxframe.v sdtxframe.v $(SDDMA_FILES) 50 | all: rtl export $(VOBJ)/Vsdspi__ALL.so usage 51 | 52 | .DELETE_ON_ERROR: 53 | 54 | .PHONY: rtl 55 | ## {{{ 56 | rtl: $(VOBJ)/Vsdspi.h $(VOBJ)/Vsdio.h $(VOBJ)/Vsdaxil.h 57 | $(VOBJ)/Vsdspi.h: sdspi.v llsdspi.v 58 | $(VERILATOR) $(VFLAGS) sdspi.v 59 | $(VOBJ)/Vsdio.h: sdio.v sdwb.v sdcmd.v sdckgen.v sdrxframe.v sdtxframe.v 60 | $(VERILATOR) $(VFLAGS) sdio.v 61 | $(VOBJ)/Vsdaxil.h: sdio.v sdaxil.v sdskid.v sdcmd.v sdckgen.v sdrxframe.v sdtxframe.v 62 | $(VERILATOR) -DSDIO_AXI --prefix Vsdaxi $(VFLAGS) sdio.v 63 | ## }}} 64 | 65 | $(VOBJ)/Vsdspi__ALL.so: $(VOBJ)/Vsdspi.h 66 | $(SUBMAKE) $(VOBJ) -f Vsdspi.mk 67 | 68 | # 69 | # Create a single file to encapsulate the SDSPI core 70 | .PHONY: export 71 | export: exportspi.v exportsd.v 72 | exportspi.v: $(SDSPI_FILES) 73 | $(VOB) $^ > $@ 74 | 75 | # 76 | # Create a single file to encapsulate the SDSPI core 77 | exportsd.v: $(SDIO_FILES) 78 | $(VOB) $^ > $@ 79 | 80 | .PHONY: usage 81 | usage: usage.txt 82 | usage.txt: usage.pl $(SDSPI_FILES) $(SDIO_FILES) 83 | perl usage.pl 84 | 85 | .PHONY: clean 86 | ## {{{ 87 | clean: 88 | rm -rf exportspi.v exportsd.v $(VOBJ) 89 | ## }}} 90 | 91 | ## Including dependencies 92 | ## {{{ 93 | DEPS := $(wildcard $(VOBJ)/*.d) 94 | 95 | ifneq ($(MAKECMDGOALS),clean) 96 | ifneq ($(DEPS),) 97 | include $(DEPS) 98 | endif 99 | endif 100 | ## }}} 101 | 102 | -------------------------------------------------------------------------------- /rtl/README.md: -------------------------------------------------------------------------------- 1 | # RTL directory 2 | 3 | This directory contains the Verilog components for both the [SDSPI](sdspi.v) 4 | controller as well as the [SDIO](sdio.v) controller. 5 | 6 | ## SDSPI 7 | 8 | - [SDSPI](sdspi.v) is the top level of the SDSPI controller. It contains 9 | all of the Wishbone processing logic, as well as references to all of the 10 | components within. 11 | 12 | - [LLSDSPI](llsdspi.v) is the low level SPI driver. It turns "higher-level" 13 | commands into actual transactions taking place across the wires, and 14 | returns bytes read from the MISO line for processing by the 15 | [SDRXDATA](sdrxdata.v) module. 16 | 17 | - [SDCMD](spicmd.v) controls both the issuing of commands over the SPI 18 | interface, as well as any return responses. 19 | 20 | - [SPIRXDATA](spirxdata.v) captures data returned from the MISO interface, 21 | and formats this data for writing to a local FIFO maintained at the 22 | [SDSPI](sdspi.v) level. Note that [SPIRXDATA](spirxdata.v) is used for 23 | *data* from the device, not command replies. 24 | 25 | - [SPITXDATA](spitxdata.v) transforms data from the local FIFO to data 26 | blocks to be sent via the [low-level interface](llsdspi.v). 27 | 28 | This particular design is somewhat optimized for low area. 29 | 30 | ## SDIO 31 | 32 | - [SDIO-TOP](sdio_top.v) is a top level, existing as a wrapper for both the 33 | [front end PHY](sdfrontend.v) as well as the [host controller](sdio.v). 34 | My anticipation is that I will typically break these components up in my 35 | designs, so that the [host controller](sdio.v) will exist within the main 36 | body of any design, whereas the [front end PHY](sdfrontend.v) will only 37 | exist within the top level--since it contains _vendor dependent_ IO macro 38 | components which may not be simulable within an open source environment. 39 | 40 | - [SDFRONTEND](sdfrontend.v) is the front end to this IP. It contains three 41 | separate implementations: 1) one for direct IO support, going up to 50MHz 42 | SDR or 25MHz DDR, 2) one that can go a touch faster if DDR IO elements 43 | are available, and 3) a third which, using 8:1 and 1:8 IO SERDES components, 44 | will support IOs all the way up to 200MHz DDR with a return data strobe. 45 | Actual IO buffers for the various SDIO signal wires are also instantiated 46 | at this level. 47 | 48 | - [XSDDDR](xsdddr.v), contains the low-level DDR IO controllers. It's 49 | been designed specifically for Xilinx components, but also supports a 50 | non-Xilinx simulation model. 51 | 52 | - [XSDSERDES8X](xsdserdes8x.v), contains the setup necessary to instantiate 53 | both low-level 8:1 and 1:8 SERDES IO controllers. This has also been 54 | designed for Xilinx components, and no non-Xilinx simulation model 55 | (currently) exists for this component. 56 | 57 | - [SDIO](sdio.v) is the top level of the host controller. It contains all 58 | of the logic of this IP, save the PHY front end itself. 59 | 60 | - [SDWB](sdwb.v) is the Wishbone command and control module. 61 | 62 | - [SDAXIL](sdaxil.v) is an alternative command and control module, for use when using the AXI-Lite slave interface. 63 | 64 | - [SDSKID](sdskid.v) is a basic skidbuffer, required by AXI-Lite interface to maintain solid throughput. 65 | 66 | - [SDCKGEN](sdckgen.v) is the clock divider driving IO actions throughout. 67 | 68 | - [SDCMD](sdcmd.v) controls interaction via the command pin. 69 | 70 | - [SDRXFRAME](sdrxframe.v) transforms data returned by the IO controller 71 | into commands to write into the data FIFOs within [SDWB](sdwb.v). Data 72 | may be returned by either the asynchronous interface (if the data strobe 73 | is in use) at up to 32-bits per clock cycle, or at slower rates of up 74 | to 16-bits per clock cycle. 75 | 76 | - [SDTXFRAME](sdtxframe.v) transforms a 32-bit AXI stream into an outgoing 77 | transmit sequence. Three data widths are supported: 1b, 4b, and 8b. 78 | (SDIO tops out at 4b, whereas eMMC can use an 8b interface.) Three 79 | clock types are supported: 1) one data word per clock, for supporting 80 | 100MHz/SDR or 50MHz/DDR clock frequencies and below, 2) two data words 81 | per clock, for supporting 200MHz/SDR or 100MHz/DDR, and 3) four data 82 | words per clock, for 200MHz DDR. 83 | 84 | - [SDDMA](sddma.v) is top level of the DMA memory handling module. It depends heavily on the command/control interface to activate. This module primarily converts memory to an AXI stream to be fed to the command/control module, and again AXI stream to memory. An option exists for skipping memory and writing directly from an AXI stream, or likewise reading directly from one. 85 | 86 | - [SDDMA_MM2S](sddma_mm2s.v) reads data from memory, to feed the gearboxes and then write to the SD card. This forms the beginning of the S2SD (write) path. 87 | 88 | - [SDDMA_RXGEARS](sddma_rxgears.v) massages incoming data to the size of a full bus word, in preparation for (bus-word sized) the FIFO. 89 | 90 | - [SDFIFO](sdfifo.v), a basic synchronous data FIFO. 91 | 92 | - [SDDMA_TXGEARS](sddma_txgears.v) takes data from the FIFO and massages it to either the size of a full bus word for writing to memory, or to 32b for writing to the SD controller. 93 | 94 | - [SDDMA_S2MM](sddma_s2mm.v) writes data from SD card, having gone through the gearboxes, finally to memory. This forms the conclusion of the SD2S (read) path. 95 | 96 | 97 | The [SDIO controller](sdio_top.v) has been optimized for speed, rather than 98 | either area or lowpower. The [DMA component](sddma.v), in particular, may 99 | double the size of the core while achieving even greater throughput. As with 100 | many of my IP's, there is an `OPT_LOWPOWER` parameter which can be used to 101 | adjust this optimization for lowpower at the (potential) expense of area. 102 | 103 | ## Logic Usage 104 | 105 | A [perl script](usage.pl) is also available to measure the logic usage of these 106 | two IP components via Yosys. Measurement results are kept [here](usage.txt). 107 | As of this writing, the [SDSPI](sdspi.v) controller requires only 548 Xilinx 108 | 6-LUTs, whereas the [SDIO](sdio.v) controller requires 1438 Xilinx 6-LUTs 109 | without the DMA, and 2708 6-LUTs with the DMA. 110 | 111 | -------------------------------------------------------------------------------- /rtl/sdspi-diff.txt: -------------------------------------------------------------------------------- 1 | Index: sdspi.v 2 | =================================================================== 3 | --- sdspi.v (revision 2) 4 | +++ sdspi.v (working copy) 5 | @@ -130,7 +130,10 @@ 6 | r_fifo_id, 7 | ll_fifo_wr, ll_fifo_rd, 8 | r_have_data_response_token, 9 | - r_have_start_token; 10 | + r_have_start_token, 11 | + r_err_token; 12 | + reg [3:0] r_read_err_token; 13 | + reg [1:0] r_data_response_token; 14 | reg [7:0] fifo_byte; 15 | reg [7:0] r_last_r_one; 16 | // 17 | @@ -242,9 +245,9 @@ 18 | if (r_have_resp) 19 | begin 20 | if (r_use_fifo) 21 | - r_cmd_state <= r_cmd_state + 3'h1; 22 | + r_cmd_state <= r_cmd_state+3'h1; 23 | else 24 | - r_cmd_state <= r_cmd_state + 3'h2; 25 | + r_cmd_state <= r_cmd_state+3'h2; 26 | ll_fifo_rd <= (r_use_fifo)&&(r_fifo_wr); 27 | if ((r_use_fifo)&&(r_fifo_wr)) 28 | ll_cmd_dat <= 8'hfe; 29 | @@ -273,8 +276,8 @@ 30 | // are expecting. 31 | if (pre_rsp_state) 32 | begin 33 | - if (r_rsp_state == `SDSPI_RSP_NONE) 34 | - begin // Waiting on R1 35 | + case(r_rsp_state) 36 | + `SDSPI_RSP_NONE: begin // Waiting on R1 37 | if (~ll_out_dat[7]) 38 | begin 39 | r_last_r_one <= ll_out_dat; 40 | @@ -288,51 +291,58 @@ 41 | begin // Go wait on R1b 42 | r_data_reg <= 32'hffffffff; 43 | end // else wait on 32-bit rsp 44 | - end 45 | - end else if (r_rsp_state == `SDSPI_RSP_BSYWAIT) 46 | - begin // Waiting on R1b, have R1 47 | + end end 48 | + `SDSPI_RSP_BSYWAIT: begin 49 | + // Waiting on R1b, have R1 50 | if (nonzero_out) 51 | r_have_resp <= 1'b1; 52 | ll_cmd_stb <= (r_use_fifo); 53 | - end else if (r_rsp_state == `SDSPI_RSP_GETWORD) 54 | - begin // Have R1, waiting on all of R2/R3/R7 55 | - r_data_reg <= { r_data_reg[23:0], ll_out_dat }; 56 | + end 57 | + `SDSPI_RSP_GETWORD: begin 58 | + // Have R1, waiting on all of R2/R3/R7 59 | + r_data_reg <= { r_data_reg[23:0], 60 | + ll_out_dat }; 61 | r_data_fil <= r_data_fil+2'b01; 62 | if (r_data_fil == 2'b11) 63 | begin 64 | ll_cmd_stb <= (r_use_fifo); 65 | // r_rsp_state <= 3'h3; 66 | - end 67 | - end else if (r_rsp_state == `SDSPI_RSP_WAIT_WHILE_BUSY) 68 | - begin // Wait while device is busy writing 69 | + end end 70 | + `SDSPI_RSP_WAIT_WHILE_BUSY: begin 71 | + // Wait while device is busy writing 72 | // if (nonzero_out) 73 | // begin 74 | // r_data_reg[31:8] <= 24'h00; 75 | - // r_data_reg[7:0] <= ll_out_dat; 76 | + // r_data_reg[7:0]<= ll_out_dat; 77 | // // r_rsp_state <= 3'h6; 78 | // end 79 | - ; 80 | - end else if (r_rsp_state == `SDSPI_RSP_RDCOMPLETE) 81 | - begin // Block write command has completed 82 | + end 83 | + `SDSPI_RSP_RDCOMPLETE: begin 84 | + // Block write command has completed 85 | ll_cmd_stb <= 1'b0; 86 | - end else if (r_rsp_state == `SDSPI_RSP_WRITING) 87 | - begin // We are reading from the device into 88 | + end 89 | + `SDSPI_RSP_WRITING: begin 90 | + // We are reading from the device into 91 | // our FIFO 92 | if ((ll_fifo_wr_complete) 93 | // Or ... we receive an error 94 | - ||((~r_have_start_token) 95 | - &&(~ll_out_dat[4]) 96 | - &&(ll_out_dat[0]))) 97 | + ||(r_read_err_token[0])) 98 | begin 99 | ll_fifo_wr <= 1'b0; 100 | ll_cmd_stb <= 1'b0; 101 | - end 102 | - end 103 | + end end 104 | + // `SDSPI_RSP_GETTOKEN: 105 | + default: begin end 106 | + endcase 107 | end 108 | 109 | + if (r_use_fifo) 110 | + r_data_reg <= { 26'h3ffffff, r_data_response_token, r_read_err_token }; 111 | + 112 | if (r_watchdog_err) 113 | ll_cmd_stb <= 1'b0; 114 | - r_cmd_err<= (r_cmd_err)|(fifo_crc_err)|(r_watchdog_err); 115 | + r_cmd_err<= (r_cmd_err)|(fifo_crc_err)|(r_watchdog_err) 116 | + |(r_err_token); 117 | end else if (r_cmd_busy) 118 | begin 119 | r_cmd_busy <= (ll_cmd_stb)||(~ll_idle); 120 | @@ -478,7 +488,7 @@ 121 | case(i_wb_addr) 122 | `SDSPI_CMD_ADDRESS: 123 | o_wb_data <= { need_reset, 11'h00, 124 | - 3'h0, fifo_crc_err, 125 | + 2'h0, r_err_token, fifo_crc_err, 126 | r_cmd_err, r_cmd_busy, 1'b0, r_fifo_id, 127 | r_use_fifo, r_fifo_wr, r_cmd_resp, 128 | r_last_r_one }; 129 | @@ -542,13 +552,12 @@ 130 | initial pre_fifo_addr_inc_rd = 1'b0; 131 | initial pre_fifo_addr_inc_wr = 1'b0; 132 | always @(posedge i_clk) 133 | - pre_fifo_addr_inc_wr <= ((ll_fifo_wr)&&(ll_out_stb)&&(r_have_start_token)); 134 | + pre_fifo_addr_inc_wr <= ((ll_fifo_wr)&&(ll_out_stb) 135 | + &&(r_have_start_token)); 136 | always @(posedge i_clk) 137 | - pre_fifo_addr_inc_rd <= ((ll_fifo_rd)&&(ll_cmd_stb)&&(ll_idle));//&&(ll_fifo_pkt_state[2:0]!=3'b000)); 138 | + pre_fifo_addr_inc_rd <= ((ll_fifo_rd)&&(ll_cmd_stb)&&(ll_idle)); 139 | always @(posedge i_clk) 140 | begin 141 | - // if ((write_stb)&&(i_wb_addr == `SDSPI_CMD_ADDRESS)&&(i_wb_data[11])) 142 | - // ll_fifo_addr <= {(LGFIFOLN+2){1'b0}}; 143 | if (~r_cmd_busy) 144 | ll_fifo_addr <= {(LGFIFOLN+2){1'b0}}; 145 | else if ((pre_fifo_addr_inc_wr)||(pre_fifo_addr_inc_rd)) 146 | @@ -555,12 +564,38 @@ 147 | ll_fifo_addr <= ll_fifo_addr + 1; 148 | end 149 | 150 | - // Look for that start token 151 | + // 152 | + // Look for that start token. This will be present when reading from 153 | + // the device into the FIFO. 154 | + // 155 | always @(posedge i_clk) 156 | if (~r_cmd_busy) 157 | r_have_start_token <= 1'b0; 158 | else if ((ll_fifo_wr)&&(ll_out_stb)&&(ll_out_dat==8'hfe)) 159 | r_have_start_token <= 1'b1; 160 | + always @(posedge i_clk) 161 | + if (~r_cmd_busy) 162 | + r_read_err_token <= 4'h0; 163 | + else if ((ll_fifo_wr)&&(ll_out_stb)&&(~r_have_start_token) 164 | + &&(ll_out_dat[7:4]==4'h0)) 165 | + r_read_err_token <= ll_out_dat[3:0]; 166 | + always @(posedge i_clk) // Look for a response to our writing 167 | + if (~r_cmd_busy) 168 | + r_data_response_token <= 2'b00; 169 | + else if ((ready_for_response_token) 170 | + &&(!ll_out_dat[4])&&(ll_out_dat[0])) 171 | + r_data_response_token <= ll_out_dat[3:2]; 172 | + initial r_err_token = 1'b0; 173 | + always @(posedge i_clk) 174 | + if (ll_fifo_rd) 175 | + r_err_token <= (r_err_token)|(r_read_err_token[0]); 176 | + else if (ll_fifo_wr) 177 | + r_err_token <= (r_err_token)| 178 | + ((|r_data_response_token)&&(r_data_response_token[1])); 179 | + else if (cmd_stb) 180 | + // Clear the error on any write with the bit high 181 | + r_err_token <= (r_err_token)&&(~i_wb_data[16]) 182 | + &&(~i_wb_data[15]); 183 | 184 | reg last_fifo_byte; 185 | initial last_fifo_byte = 1'b0; 186 | @@ -582,11 +617,16 @@ 187 | clear_fifo_crc; 188 | always @(posedge i_clk) 189 | begin 190 | - pre_fifo_a_wr <= (ll_fifo_wr)&&(ll_out_stb)&&(~r_fifo_id)&&(ll_fifo_wr_state == 2'b00); 191 | - pre_fifo_b_wr <= (ll_fifo_wr)&&(ll_out_stb)&&( r_fifo_id)&&(ll_fifo_wr_state == 2'b00); 192 | - fifo_wr_crc_stb <= (ll_fifo_wr)&&(ll_out_stb)&&(ll_fifo_wr_state == 2'b00)&&(r_have_start_token); 193 | - pre_fifo_crc_a<= (ll_fifo_wr)&&(ll_out_stb)&&(ll_fifo_wr_state == 2'b01); 194 | - pre_fifo_crc_b<= (ll_fifo_wr)&&(ll_out_stb)&&(ll_fifo_wr_state == 2'b10); 195 | + pre_fifo_a_wr <= (ll_fifo_wr)&&(ll_out_stb) 196 | + &&(~r_fifo_id)&&(ll_fifo_wr_state == 2'b00); 197 | + pre_fifo_b_wr <= (ll_fifo_wr)&&(ll_out_stb) 198 | + &&( r_fifo_id)&&(ll_fifo_wr_state == 2'b00); 199 | + fifo_wr_crc_stb <= (ll_fifo_wr)&&(ll_out_stb) 200 | + &&(ll_fifo_wr_state == 2'b00)&&(r_have_start_token); 201 | + pre_fifo_crc_a<= (ll_fifo_wr)&&(ll_out_stb) 202 | + &&(ll_fifo_wr_state == 2'b01); 203 | + pre_fifo_crc_b<= (ll_fifo_wr)&&(ll_out_stb) 204 | + &&(ll_fifo_wr_state == 2'b10); 205 | clear_fifo_crc <= (cmd_stb)&&(i_wb_data[15]); 206 | end 207 | 208 | -------------------------------------------------------------------------------- /rtl/usage.pl: -------------------------------------------------------------------------------- 1 | #!/bin/perl 2 | 3 | ## Configuration definitions 4 | ## {{{ 5 | my $sdspi = ""; 6 | my $sdio_nodma = " -chparam OPT_DMA 1\'b0 -chparam NUMIO 4 -chparam OPT_EMMC 1\'b0"; 7 | my $emmc_nodma = " -chparam OPT_DMA 1\'b0 -chparam NUMIO 8 -chparam OPT_EMMC 1\'b1"; 8 | my $sdio_dma = " -chparam OPT_DMA 1\'b1 -chparam OPT_EMMC 1\'b0 -chparam NUMIO 4 -chparam OPT_ISTREAM 1\'b1 -chparam OPT_OSTREAM 1\'b1 -chparam DMA_DW 64"; 9 | my $emmc_dma = " -chparam OPT_DMA 1\'b1 -chparam OPT_EMMC 1\'b1 -chparam NUMIO 8 -chparam OPT_ISTREAM 1\'b1 -chparam OPT_OSTREAM 1\'b1 -chparam DMA_DW 64"; 10 | ## }}} 11 | 12 | ## Files 13 | ## {{{ 14 | my @files = ( 15 | "sdio.v", "sdwb.v", "sdckgen.v", 16 | "sdaxil.v", "sdskid.v", 17 | "sdcmd.v", "sdrxframe.v", "sdtxframe.v", 18 | "sdspi.v", "spicmd.v", "spirxdata.v", "spitxdata.v", 19 | "llsdspi.v", 20 | "sddma.v", "sdfifo.v", 21 | "sddma_mm2s.v", "sddma_s2mm.v", 22 | "sdax_mm2s.v", "sdax_s2mm.v", 23 | "sddma_rxgears.v", "sddma_txgears.v", 24 | "sdfrontend.v", "xsdserdes8x.v" ); 25 | ## }}} 26 | 27 | my $logfile = "yosys.log"; 28 | my $scriptf = "usage.ys"; 29 | my $ice40synth = "synth_ice40"; 30 | my $xilinxsynth = "synth_xilinx"; 31 | my $asicsynth = "synth"; 32 | my $asicpost = "abc -g cmos2"; 33 | 34 | sub calcusage($$$$$) { 35 | ## {{{ 36 | my($synth,$toplvl,$bus,$config,$postsynth)=@_; 37 | 38 | ## Build the script 39 | ## {{{ 40 | unlink($scriptf); 41 | open(SCRIPT, "> $scriptf"); 42 | if ($bus =~ "axil") { 43 | print SCRIPT "read -define SDIO_AXI\n"; 44 | } foreach $key (@files) { 45 | print SCRIPT "read -sv $key\n"; 46 | } 47 | 48 | print SCRIPT "hierarchy -top $toplvl $config\n"; 49 | print SCRIPT "$synth -flatten -top $toplvl\n"; 50 | if ($postsynth ne "") { 51 | print SCRIPT "$postsynth\n"; 52 | } 53 | print SCRIPT "stat\n"; 54 | close(SCRIPT); 55 | ## }}} 56 | 57 | system("yosys -l $logfile -s $scriptf"); 58 | 59 | ## Read the log, looking for the usage statistics 60 | ## {{{ 61 | $usage = 0; 62 | open(LOG, "< $logfile"); 63 | while($line = ) { 64 | if ($line =~ /Estimated number of LCs:\s*(\d+)\s*$/) { 65 | $usage = $1; 66 | } elsif ($line =~ /^\s*SB_LUT4\s*(\d+)\s*$/) { 67 | $usage = $1; 68 | } elsif ($line =~ /^\s*\$_NAND_\s*(\d+)\s*$/) { 69 | $usage = $1; 70 | } 71 | } close(LOG); 72 | ## }}} 73 | 74 | $usage 75 | } 76 | ## }}} 77 | 78 | sub topusage() { 79 | ## {{{ 80 | my $result = ""; 81 | 82 | $result = sprintf("SDIO(AXIL): %5d %5d %7d\n", 83 | ## Synth, top, bus, config, postsynth 84 | calcusage($ice40synth, "sdio", "axil", $sdio_nodma,""), 85 | calcusage($xilinxsynth,"sdio", "axil", $sdio_nodma,""), 86 | calcusage($asicsynth, "sdio", "axil", $sdio_nodma,$asicpost)); 87 | 88 | $result = $result . sprintf("SDIO(WB): %5d %5d %7d\n", 89 | calcusage($ice40synth, "sdio", "wb", $sdio_nodma,""), 90 | calcusage($xilinxsynth,"sdio", "wb", $sdio_nodma,""), 91 | calcusage($asicsynth, "sdio", "wb", $sdio_nodma,$asicpost)); 92 | 93 | $result = $result . sprintf("EMMC(AXIL): %5d %5d %7d\n", 94 | calcusage($ice40synth, "sdio", "axil", $emmc_nodma,""), 95 | calcusage($xilinxsynth,"sdio", "axil", $emmc_nodma,""), 96 | calcusage($asicsynth, "sdio", "axil", $emmc_nodma,$asicpost)); 97 | 98 | $result = $result . sprintf("EMMC(WB): %5d %5d %7d\n", 99 | calcusage($ice40synth, "sdio", "wb", $emmc_nodma,""), 100 | calcusage($xilinxsynth,"sdio", "wb", $emmc_nodma,""), 101 | calcusage($asicsynth, "sdio", "wb", $emmc_nodma,$asicpost)); 102 | 103 | $result = $result . sprintf("SDIO w/DMA: %5d %5d %7d\n", 104 | calcusage($ice40synth, "sdio", "wb", $sdio_dma,""), 105 | calcusage($xilinxsynth,"sdio", "wb", $sdio_dma,""), 106 | calcusage($asicsynth, "sdio", "wb", $sdio_dma,$asicpost)); 107 | 108 | $result = $result . sprintf("EMMC w/DMA: %5d %5d %7d\n", 109 | calcusage($ice40synth, "sdio", "wb", $emmc_dma,""), 110 | calcusage($xilinxsynth,"sdio", "wb", $emmc_dma,""), 111 | calcusage($asicsynth, "sdio", "wb", $emmc_dma,$asicpost)); 112 | 113 | $result = $result . sprintf("SDAXI w/DMA: %5d %5d %7d\n", 114 | calcusage($ice40synth, "sdio", "axil", $sdio_dma,""), 115 | calcusage($xilinxsynth,"sdio", "axil", $sdio_dma,""), 116 | calcusage($asicsynth, "sdio", "axil", $sdio_dma,$asicpost)); 117 | 118 | $result = $result . sprintf("EMAXI w/DMA: %5d %5d %7d\n", 119 | calcusage($ice40synth, "sdio", "axil", $emmc_dma,""), 120 | calcusage($xilinxsynth,"sdio", "axil", $emmc_dma,""), 121 | calcusage($asicsynth, "sdio", "axil", $emmc_dma,$asicpost)); 122 | 123 | $result = $result . sprintf("SDSPI: %5d %5d %7d\n", 124 | calcusage($ice40synth, "sdspi", "wb", "",""), 125 | calcusage($xilinxsynth,"sdspi", "wb", "",""), 126 | calcusage($asicsynth, "sdspi", "wb", "",$asicpost)); 127 | 128 | $result 129 | } 130 | ## }}} 131 | 132 | $result = ""; 133 | $result = topusage(); 134 | 135 | ## Add a header 136 | $result = " iCE40 X7-s RAW\n" 137 | . "Controller 4LUT 6LUT NANDs\n" 138 | . "-----------------------------------\n" . $result; 139 | print $result; 140 | 141 | open(USAGE, "> usage.txt"); 142 | 143 | print USAGE $result; 144 | 145 | close(USAGE); 146 | -------------------------------------------------------------------------------- /rtl/usage.txt: -------------------------------------------------------------------------------- 1 | iCE40 X7-s RAW 2 | Controller 4LUT 6LUT NANDs 3 | ----------------------------------- 4 | SDIO(AXIL): 2999 1478 732363 5 | SDIO(WB): 2937 1420 731900 6 | EMMC(AXIL): 3812 2132 729782 7 | EMMC(WB): 3731 2085 733185 8 | SDIO w/DMA: 5408 2869 970077 9 | EMMC w/DMA: 6227 3491 997149 10 | SDAXI w/DMA: 6621 3569 802136 11 | EMAXI w/DMA: 7442 4254 807292 12 | SDSPI: 1000 544 12719 13 | -------------------------------------------------------------------------------- /rtl/xsdddr.v: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: rtl/xsdddr.v 4 | // {{{ 5 | // Project: SD-Card controller 6 | // 7 | // Purpose: An 2:1 OSERDES followed by an (optional) 1:2 ISERDES implemented 8 | // via the Xilinx ODDR and IDDR elements. That simple, nothing 9 | // more. This implementation is specific to Xilinx FPGAs. It's designed, 10 | // however, so that there may be a minimum number of components that 11 | // need replacing when switching hardware platforms. 12 | // 13 | // Creator: Dan Gisselquist, Ph.D. 14 | // Gisselquist Technology, LLC 15 | // 16 | //////////////////////////////////////////////////////////////////////////////// 17 | // }}} 18 | // Copyright (C) 2016-2025, Gisselquist Technology, LLC 19 | // {{{ 20 | // This program is free software (firmware): you can redistribute it and/or 21 | // modify it under the terms of the GNU General Public License as published 22 | // by the Free Software Foundation, either version 3 of the License, or (at 23 | // your option) any later version. 24 | // 25 | // This program is distributed in the hope that it will be useful, but WITHOUT 26 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 27 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 28 | // for more details. 29 | // 30 | // You should have received a copy of the GNU General Public License along 31 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no 32 | // target there if the PDF file isn't present.) If not, see 33 | // for a copy. 34 | // }}} 35 | // License: GPL, v3, as defined and found on www.gnu.org, 36 | // {{{ 37 | // http://www.gnu.org/licenses/gpl.html 38 | // 39 | //////////////////////////////////////////////////////////////////////////////// 40 | // 41 | `timescale 1ns/1ps 42 | `default_nettype none 43 | `ifdef VERILATOR 44 | `define OPENSIM 45 | `endif 46 | `ifdef IVERILOG 47 | `define OPENSIM 48 | `endif 49 | // }}} 50 | module xsdddr #( 51 | parameter [0:0] OPT_BIDIR = 1'b1 52 | ) ( 53 | // {{{ 54 | input wire i_clk, 55 | // 56 | input wire i_en, 57 | input wire [1:0] i_data, 58 | output wire io_pin_tristate, 59 | input wire i_pin, 60 | output wire [1:0] o_mine, 61 | output wire o_pin, 62 | output wire [1:0] o_wide 63 | // }}} 64 | ); 65 | 66 | wire w_in, w_out; 67 | reg high_z; 68 | reg [1:0] r_mine; 69 | 70 | initial high_z = OPT_BIDIR; 71 | always @(posedge i_clk) 72 | high_z <= !i_en && OPT_BIDIR; 73 | 74 | `ifdef OPENSIM 75 | // {{{ 76 | reg r_out; 77 | // Verilator lint_off MULTIDRIVEN 78 | reg r_pin; 79 | // Verilator lint_on MULTIDRIVEN 80 | 81 | always @(posedge i_clk) 82 | r_out <= i_data[0]; 83 | 84 | always @(posedge i_clk) 85 | r_pin <= i_data[1]; 86 | always @(negedge i_clk) 87 | r_pin <= r_out; 88 | 89 | // assign w_out = (i_clk) ? r_out[1] : r_out[0]; 90 | assign w_out = r_pin; 91 | assign io_pin_tristate = high_z; 92 | assign o_pin = w_out; 93 | 94 | assign w_in = (high_z) ? i_pin : w_out; 95 | // }}} 96 | `else 97 | ODDR #( 98 | // {{{ 99 | .DDR_CLK_EDGE("SAME_EDGE"), 100 | .INIT(1'b1), 101 | .SRTYPE("SYNC") 102 | // }}} 103 | ) u_oddr ( 104 | // {{{ 105 | .CE(1'b1), .R(1'b0), .S(1'b0), 106 | // 107 | .C(i_clk), 108 | .Q(w_out), .D1(i_data[1]), .D2(i_data[0]) 109 | // }}} 110 | ); 111 | 112 | assign io_pin_tristate = high_z; 113 | assign o_pin = w_out; 114 | assign w_in = i_pin; 115 | `endif 116 | 117 | generate if (OPT_BIDIR) 118 | begin : GEN_BIDIRECTIONAL 119 | // {{{ 120 | reg [2:0] r_last; 121 | 122 | always @(posedge i_clk) 123 | if (!i_en) 124 | r_last <= 3'h0; 125 | else 126 | r_last <= { r_last[0], i_data[1], i_data[0] }; 127 | always @(posedge i_clk) 128 | r_mine <= r_last[2:1]; 129 | 130 | assign o_mine = r_mine; 131 | `ifdef OPENSIM 132 | reg r_p, r_n; 133 | reg [1:0] r_in; 134 | 135 | always @(posedge i_clk) 136 | r_p <= w_in; 137 | always @(negedge i_clk) 138 | r_n <= w_in; 139 | always @(posedge i_clk) 140 | r_in <= { r_p, r_n }; 141 | 142 | assign o_wide = r_in; 143 | `else 144 | IDDR #( 145 | .DDR_CLK_EDGE("SAME_EDGE_PIPELINED"), 146 | .INIT_Q1(1'b1), 147 | .INIT_Q2(1'b1), 148 | .SRTYPE("SYNC") 149 | ) u_iddr ( 150 | .Q1(o_wide[1]), .Q2(o_wide[0]), 151 | .C(i_clk), .CE(1'b1), .D(i_pin), 152 | .R(1'b0), .S(1'b0) 153 | ); 154 | `endif 155 | // }}} 156 | end else begin : GEN_OUTPUT 157 | 158 | assign o_wide = 2'b11; 159 | always @(posedge i_clk) 160 | r_mine <= i_data; 161 | assign o_mine = r_mine; 162 | 163 | // Keep Verilator happy 164 | // {{{ 165 | // Verilator coverage_off 166 | // Verilator lint_off UNUSED 167 | wire unused; 168 | assign unused = &{ 1'b0, 169 | `ifdef VERILATOR 170 | i_pin, 171 | `endif 172 | w_in }; 173 | // Verilator lint_on UNUSED 174 | // Verilator coverage_on 175 | // }}} 176 | end endgenerate 177 | endmodule 178 | -------------------------------------------------------------------------------- /rtl/xsdserdes8x.v: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: rtl/xsdserdes8x.v 4 | // {{{ 5 | // Project: SD-Card controller 6 | // 7 | // Purpose: An 8:1 OSERDES followed by an (optional) 1:8 ISERDES. That 8 | // simple, nothing more. This implementation is specific to 9 | // Xilinx FPGAs. It's designed, however, so that it may be the only 10 | // component needing replacing when switching hardware platforms. 11 | // 12 | // Creator: Dan Gisselquist, Ph.D. 13 | // Gisselquist Technology, LLC 14 | // 15 | //////////////////////////////////////////////////////////////////////////////// 16 | // }}} 17 | // Copyright (C) 2016-2025, Gisselquist Technology, LLC 18 | // {{{ 19 | // This program is free software (firmware): you can redistribute it and/or 20 | // modify it under the terms of the GNU General Public License as published 21 | // by the Free Software Foundation, either version 3 of the License, or (at 22 | // your option) any later version. 23 | // 24 | // This program is distributed in the hope that it will be useful, but WITHOUT 25 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 26 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 27 | // for more details. 28 | // 29 | // You should have received a copy of the GNU General Public License along 30 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no 31 | // target there if the PDF file isn't present.) If not, see 32 | // for a copy. 33 | // }}} 34 | // License: GPL, v3, as defined and found on www.gnu.org, 35 | // {{{ 36 | // http://www.gnu.org/licenses/gpl.html 37 | // 38 | //////////////////////////////////////////////////////////////////////////////// 39 | // 40 | `timescale 1ns/1ps 41 | `default_nettype none 42 | `ifdef VERILATOR 43 | `define OPENSIM 44 | `endif 45 | `ifdef IVERILOG 46 | `define OPENSIM 47 | `endif 48 | // }}} 49 | module xsdserdes8x #( 50 | // Verilator lint_off UNUSED 51 | parameter [0:0] OPT_BIDIR = 1'b1 52 | // Verilator lint_on UNUSED 53 | ) ( 54 | // {{{ 55 | input wire i_clk, 56 | i_hsclk, 57 | input wire i_reset, 58 | // 59 | input wire i_en, 60 | input wire [7:0] i_data, 61 | // 62 | output wire io_tristate, 63 | output wire o_pin, 64 | input wire i_pin, 65 | // 66 | output wire o_raw, 67 | output wire [7:0] o_mine, 68 | output wire [7:0] o_wide 69 | // }}} 70 | ); 71 | 72 | reg [8:0] r_last; 73 | reg [7:0] r_mine; 74 | 75 | always @(posedge i_clk) 76 | if (!i_en) 77 | r_last <= 0; 78 | else 79 | r_last <= { r_last[0], i_data }; 80 | 81 | always @(posedge i_clk) 82 | r_mine <= r_last[8:1]; 83 | 84 | assign o_mine = r_mine; 85 | 86 | `ifdef OPENSIM 87 | // {{{ 88 | reg last_ck; 89 | reg [7:0] ir_wide, rx_wide; 90 | reg [14:0] or_wide; // Output register 91 | 92 | always @(posedge i_hsclk or negedge i_hsclk) 93 | last_ck <= i_clk; 94 | 95 | always @(posedge i_hsclk or negedge i_hsclk) 96 | if (i_clk && !last_ck) 97 | or_wide <= { or_wide[13:7], i_data }; 98 | else 99 | or_wide <= { or_wide[13:0], 1'b0 }; 100 | 101 | always @(posedge i_hsclk or negedge i_hsclk) 102 | ir_wide <= { ir_wide[6:0], i_pin !== 1'b0 }; 103 | 104 | always @(posedge i_clk) 105 | rx_wide <= ir_wide; 106 | 107 | assign io_tristate = !i_en; 108 | assign o_pin = or_wide[14]; 109 | assign o_wide = rx_wide; 110 | assign o_raw = i_pin; 111 | 112 | // Keep Verilator happy 113 | // {{{ 114 | // Verilator lint_off UNUSED 115 | wire unused; 116 | assign unused = &{ 1'b0, i_reset }; 117 | // Verilator lint_on UNUSED 118 | // }}} 119 | // }}} 120 | `else 121 | wire w_pin, w_in, w_reset, high_z, fabric_return; 122 | assign w_reset = i_reset; // Active high reset 123 | 124 | OSERDESE2 #( 125 | // {{{ 126 | .DATA_RATE_OQ("DDR"), 127 | .DATA_RATE_TQ("SDR"), 128 | .DATA_WIDTH(8), 129 | .SERDES_MODE("MASTER"), 130 | .TRISTATE_WIDTH(1) 131 | // }}} 132 | ) u_oserdes ( 133 | // {{{ 134 | // Verilator lint_off PINCONNECTEMPTY 135 | .OCE(1'b1), .TCE(1'b1), .TFB(), .TQ(high_z), 136 | .CLK(i_hsclk), .CLKDIV(i_clk), .OQ(w_pin), .OFB(fabric_return), 137 | .D1(i_data[7]), .D2(i_data[6]), 138 | .D3(i_data[5]), .D4(i_data[4]), 139 | .D5(i_data[3]), .D6(i_data[2]), 140 | .D7(i_data[1]), .D8(i_data[0]), 141 | .RST(w_reset), .TBYTEIN(1'b0), // .TBYTEOUT(), 142 | .T1(!i_en && OPT_BIDIR), .T2(1'b0), .T3(1'b0), .T4(1'b0) 143 | // .SHIFTIN1(), .SHIFTIN2(), .SHIFTOUT1(), .SHIFTOUT2() 144 | // Verilator lint_on PINCONNECTEMPTY 145 | // }}} 146 | ); 147 | 148 | // Actual buffers are held externally 149 | assign io_tristate = high_z; 150 | assign o_pin = w_pin; 151 | assign w_in = i_pin; 152 | 153 | generate if (OPT_BIDIR) 154 | begin : GEN_BIDIRECTIONAL 155 | 156 | ISERDESE2 #( 157 | // {{{ 158 | .SERDES_MODE("MASTER"), 159 | .DATA_RATE("DDR"), 160 | .DATA_WIDTH(8), 161 | .INTERFACE_TYPE("NETWORKING"), 162 | .NUM_CE(1), 163 | .INIT_Q1(1'b0), .INIT_Q2(1'b0), 164 | .INIT_Q3(1'b0), .INIT_Q4(1'b0), 165 | .SRVAL_Q1(1'b0), .SRVAL_Q2(1'b0), 166 | .SRVAL_Q3(1'b0), .SRVAL_Q4(1'b0), 167 | // .SYN_CLKDIV_INV_EN("FALSE"), 168 | .DYN_CLK_INV_EN("FALSE"), 169 | .OFB_USED("FALSE") 170 | // }}} 171 | ) u_iserdes ( 172 | // {{{ 173 | .BITSLIP(1'b0), .CE1(1'b1), // .CE2(), 174 | .CLK(i_hsclk), .CLKB(!i_hsclk), .CLKDIV(i_clk), .CLKDIVP(1'b0), 175 | .D(w_in), .DYNCLKDIVSEL(1'b0), .DYNCLKSEL(1'b0), // .DDLY() 176 | .OCLK(1'b0), .OCLKB(1'b0), .O(o_raw), // .OFB(), 177 | .Q1(o_wide[0]), .Q2(o_wide[1]), 178 | .Q3(o_wide[2]), .Q4(o_wide[3]), 179 | .Q5(o_wide[4]), .Q6(o_wide[5]), 180 | .Q7(o_wide[6]), .Q8(o_wide[7]), 181 | .RST(w_reset) 182 | // .SHIFTIN1(), .SHIFTIN2(), .SHIFTOUT1(), .SHIFTOUT2() 183 | // }}} 184 | ); 185 | end else begin : GEN_OUTPUT 186 | 187 | assign o_wide = 8'h0; 188 | assign o_raw = fabric_return; 189 | 190 | // Keep Verilator happy 191 | // {{{ 192 | // Verilator lint_off UNUSED 193 | wire unused; 194 | assign unused = &{ 1'b0, w_in }; 195 | // Verilator lint_on UNUSED 196 | // }}} 197 | end endgenerate 198 | `endif // OPENSIM 199 | endmodule 200 | -------------------------------------------------------------------------------- /sdspi.core: -------------------------------------------------------------------------------- 1 | CAPI=1 2 | [main] 3 | 4 | description = SD-Card controller, using a shared SPI interface 5 | simulators = verilator 6 | 7 | [fileset rtl] 8 | files = rtl/llsdspi.v rtl/sdspi.v 9 | file_type = verilogSource 10 | 11 | [verilator] 12 | verilator_options = -Wno-fatal --trace 13 | include_files = bench/cpp/sdspisim.h 14 | tb_toplevel = bench/cpp/sdspisim.cpp 15 | top_module = sdspi 16 | -------------------------------------------------------------------------------- /sw/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | diskio.h 3 | ff.h 4 | ffconf.h 5 | -------------------------------------------------------------------------------- /sw/diskio.c: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: sw/diskio.c 4 | // {{{ 5 | // Project: SD-Card controller 6 | // 7 | // Purpose: This file contains the low-level SD-Card I/O wrappers for use 8 | // with the FAT-FS file-system library. This low-level wrappers 9 | // are specific to systems having either an SDSPI or an SDIO device within 10 | // them. 11 | // 12 | // Creator: Dan Gisselquist, Ph.D. 13 | // Gisselquist Technology, LLC 14 | // 15 | //////////////////////////////////////////////////////////////////////////////// 16 | // }}} 17 | // Copyright (C) 2016-2025, Gisselquist Technology, LLC 18 | // {{{ 19 | // This program is free software (firmware): you can redistribute it and/or 20 | // modify it under the terms of the GNU General Public License as published 21 | // by the Free Software Foundation, either version 3 of the License, or (at 22 | // your option) any later version. 23 | // 24 | // This program is distributed in the hope that it will be useful, but WITHOUT 25 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 26 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 27 | // for more details. 28 | // 29 | // You should have received a copy of the GNU General Public License along 30 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no 31 | // target there if the PDF file isn't present.) If not, see 32 | // for a copy. 33 | // }}} 34 | // License: GPL, v3, as defined and found on www.gnu.org, 35 | // {{{ 36 | // http://www.gnu.org/licenses/gpl.html 37 | // 38 | //////////////////////////////////////////////////////////////////////////////// 39 | // 40 | // }}} 41 | #include "ff.h" // From FATFS 42 | #include "diskio.h" // From FATFS as well 43 | #include "board.h" // Defines associated with the driver 44 | #include "sdspidrv.h" 45 | #include "sdiodrv.h" 46 | #include "emmcdrv.h" 47 | #include "diskiodrvr.h" 48 | 49 | // #define STDIO_DEBUG 50 | #include "zipcpu.h" 51 | 52 | #ifdef STDIO_DEBUG 53 | #include 54 | #define DBGPRINTF printf 55 | #else 56 | #define DBGPRINTF null 57 | #endif 58 | 59 | static inline void null(char *s,...) {} 60 | 61 | DSTATUS disk_status( 62 | BYTE pdrv 63 | ) { 64 | // {{{ 65 | unsigned stat = 0; 66 | 67 | if (pdrv >= MAX_DRIVES || NULL == DRIVES[pdrv].fd_addr 68 | || NULL == DRIVES[pdrv].fd_driver) 69 | return STA_NODISK; 70 | if (NULL == DRIVES[pdrv].fd_data) 71 | DRIVES[pdrv].fd_data= (DRIVES[pdrv].fd_driver->dio_init)( 72 | DRIVES[pdrv].fd_data); 73 | if (NULL == DRIVES[pdrv].fd_data 74 | || RES_OK != (*DRIVES[pdrv].fd_driver->dio_ioctl)( 75 | DRIVES[pdrv].fd_data, 76 | MMC_GET_SDSTAT, (char *)&stat)) 77 | stat = STA_NODISK; 78 | 79 | return stat; 80 | } 81 | // }}} 82 | 83 | DSTATUS disk_initialize( 84 | BYTE pdrv 85 | ) { 86 | // {{{ 87 | if (pdrv >= MAX_DRIVES || NULL == DRIVES[pdrv].fd_addr 88 | || NULL == DRIVES[pdrv].fd_driver) { 89 | return STA_NODISK; 90 | } else if (NULL != DRIVES[pdrv].fd_data 91 | || NULL != (DRIVES[pdrv].fd_data 92 | = (*DRIVES[pdrv].fd_driver->dio_init)( 93 | DRIVES[pdrv].fd_addr))) { 94 | return RES_OK; 95 | } else 96 | return STA_NODISK; 97 | } 98 | // }}} 99 | 100 | DRESULT disk_ioctl( 101 | BYTE pdrv, // [IN] Drive number 102 | BYTE cmd, // [IN] Control command code 103 | void *buff // [I/O parameter and data buffer 104 | ) { 105 | // {{{ 106 | if (pdrv >= MAX_DRIVES || NULL == DRIVES[pdrv].fd_addr 107 | || NULL == DRIVES[pdrv].fd_driver) 108 | return RES_ERROR; 109 | return (*DRIVES[pdrv].fd_driver->dio_ioctl)(DRIVES[pdrv].fd_data, 110 | cmd, buff); 111 | } 112 | // }}} 113 | 114 | DWORD get_fattime(void) { 115 | // {{{ 116 | DWORD result; 117 | unsigned thedate, clocktime; 118 | 119 | #ifdef _BOARD_HAS_VERSION 120 | thedate = *_version; 121 | #else 122 | thedate = 0x20191001; 123 | #endif 124 | #ifdef _BOARD_HAS_BUILDTIME 125 | clocktime = *_buildtime; 126 | #else 127 | clocktime = 0x0; // Midnight 128 | #endif 129 | 130 | #ifdef _BOARD_HAS_RTC 131 | clocktime = _rtc->r_clock; 132 | #endif 133 | 134 | unsigned year, month, day, hrs, mns, sec; 135 | 136 | year = ((thedate & 0xf0000000)>>28)*1000 + 137 | ((thedate & 0x0f000000)>>24)*100 + 138 | ((thedate & 0x00f00000)>>20)*10 + 139 | ((thedate & 0x000f0000)>>16); 140 | year -= 1980; 141 | 142 | month = ((thedate & 0x00f000)>>12)*10 + 143 | ((thedate & 0x000f00)>> 8); 144 | 145 | day = ((thedate & 0x00f0)>> 4)*10 + 146 | ((thedate & 0x000f) ); 147 | 148 | hrs = ((clocktime & 0xf00000)>>20)*10 + 149 | ((clocktime & 0x0f0000)>>16); 150 | 151 | mns = ((clocktime & 0xf000)>>12)*10 + 152 | ((clocktime & 0x0f00)>> 8); 153 | 154 | sec = ((clocktime & 0xf0)>> 4)*10 + 155 | ((clocktime & 0x0f)); 156 | 157 | result = (sec & 0x01f) | ((mns & 0x3f)<<5) 158 | | ((hrs & 0x01f)<<11) 159 | | ((day & 0x01f)<<16) 160 | | ((month & 0x0f)<<21) 161 | | ((year & 0x0f)<<21); 162 | 163 | return result; 164 | } 165 | // }}} 166 | 167 | DRESULT disk_read( 168 | BYTE pdrv, 169 | BYTE *buff, 170 | DWORD sector, 171 | UINT count) { 172 | // {{{ 173 | if (pdrv >= MAX_DRIVES || NULL == DRIVES[pdrv].fd_addr 174 | || NULL == DRIVES[pdrv].fd_driver) 175 | return RES_ERROR; 176 | return (*DRIVES[pdrv].fd_driver->dio_read)(DRIVES[pdrv].fd_data, 177 | sector, count, buff); 178 | } 179 | // }}} 180 | 181 | DRESULT disk_write( 182 | BYTE pdrv, 183 | const BYTE *buff, 184 | DWORD sector, 185 | UINT count) { 186 | // {{{ 187 | if (pdrv >= MAX_DRIVES || NULL == DRIVES[pdrv].fd_addr 188 | || NULL == DRIVES[pdrv].fd_driver) 189 | return RES_ERROR; 190 | return (*DRIVES[pdrv].fd_driver->dio_write)(DRIVES[pdrv].fd_data, 191 | sector, count, buff); 192 | } 193 | -------------------------------------------------------------------------------- /sw/diskiodrvr.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: sw/diskiodrvr.h 4 | // {{{ 5 | // Project: SD-Card controller 6 | // 7 | // Purpose: Defines a structure which can be used to identify both the 8 | // 1) number of drives (devices) in a system, and 2) what type 9 | // of drives and thus which software device driver, needs to be applied 10 | // to each device. 11 | // 12 | // Creator: Dan Gisselquist, Ph.D. 13 | // Gisselquist Technology, LLC 14 | // 15 | //////////////////////////////////////////////////////////////////////////////// 16 | // }}} 17 | // Copyright (C) 2016-2025, Gisselquist Technology, LLC 18 | // {{{ 19 | // This program is free software (firmware): you can redistribute it and/or 20 | // modify it under the terms of the GNU General Public License as published 21 | // by the Free Software Foundation, either version 3 of the License, or (at 22 | // your option) any later version. 23 | // 24 | // This program is distributed in the hope that it will be useful, but WITHOUT 25 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 26 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 27 | // for more details. 28 | // 29 | // You should have received a copy of the GNU General Public License along 30 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no 31 | // target there if the PDF file isn't present.) If not, see 32 | // for a copy. 33 | // }}} 34 | // License: GPL, v3, as defined and found on www.gnu.org, 35 | // {{{ 36 | // http://www.gnu.org/licenses/gpl.html 37 | // 38 | //////////////////////////////////////////////////////////////////////////////// 39 | // 40 | #ifndef DISKIODRVR_H 41 | #define DISKIODRVR_H 42 | // }}} 43 | 44 | #include 45 | 46 | typedef struct DISKIODRVR_S *(*DIO_INIT_FN)(void *io_addr); 47 | typedef int (*DIO_WRITE_FN)(void *, const unsigned, const unsigned, const char *); 48 | typedef int (*DIO_READ_FN)(void *, const unsigned, const unsigned, char *); 49 | typedef int (*DIO_IOCTL_FN)(void *, const char, char *); 50 | typedef struct DISKIODRVR_S { 51 | // struct DISKIODRVR_S * (*dio_init)(void *io_addr); 52 | DIO_INIT_FN dio_init; 53 | 54 | DIO_WRITE_FN dio_write; 55 | DIO_READ_FN dio_read; 56 | DIO_IOCTL_FN dio_ioctl; 57 | } DISKIODRVR; 58 | 59 | DISKIODRVR SDIODRVR = { (DIO_INIT_FN)&sdio_init, (DIO_WRITE_FN)&sdio_write, (DIO_READ_FN)&sdio_read, (DIO_IOCTL_FN)&sdio_ioctl }; 60 | DISKIODRVR SDSPIDRVR = { (DIO_INIT_FN)&sdspi_init,(DIO_WRITE_FN)&sdspi_write,(DIO_READ_FN)&sdspi_read,(DIO_IOCTL_FN)&sdspi_ioctl }; 61 | DISKIODRVR EMMCDRVR = { (DIO_INIT_FN)&emmc_init, (DIO_WRITE_FN)&emmc_write, (DIO_READ_FN)&emmc_read, (DIO_IOCTL_FN)&emmc_ioctl }; 62 | 63 | typedef struct FATDRIVE_S { 64 | void *fd_addr; 65 | DISKIODRVR *fd_driver; 66 | void *fd_data; 67 | } FATDRIVE; 68 | 69 | // UPDATE ME! 70 | // The following lines need to be updated from one board to the next, so that 71 | // there's one FATDRIVE triplet per drive on the board, and so that MAX_DRIVES 72 | // contains the number of items in the table. 73 | // 74 | #define MAX_DRIVES 4 75 | FATDRIVE DRIVES[MAX_DRIVES] = { 76 | #ifdef _BOARD_HAS_SDIO 77 | { (void *)_sdio, &SDIODRVR, NULL }, 78 | #else 79 | { NULL, NULL, NULL }, 80 | #endif 81 | #ifdef _BOARD_HAS_SDSPI 82 | { (void *)_sdspi, &SDSPIDRVR, NULL }, 83 | #else 84 | { NULL, NULL, NULL }, 85 | #endif 86 | #ifdef _BOARD_HAS_EMMC 87 | { (void *)_emmc, &EMMCDRVR, NULL }, 88 | #else 89 | { NULL, NULL, NULL }, 90 | #endif 91 | {NULL, NULL, NULL } 92 | }; 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /sw/emmcdrv.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: sw/emmcdrv.h 4 | // {{{ 5 | // Project: SD-Card controller 6 | // 7 | // Purpose: 8 | // 9 | // Creator: Dan Gisselquist, Ph.D. 10 | // Gisselquist Technology, LLC 11 | // 12 | //////////////////////////////////////////////////////////////////////////////// 13 | // }}} 14 | // Copyright (C) 2016-2025, Gisselquist Technology, LLC 15 | // {{{ 16 | // This program is free software (firmware): you can redistribute it and/or 17 | // modify it under the terms of the GNU General Public License as published 18 | // by the Free Software Foundation, either version 3 of the License, or (at 19 | // your option) any later version. 20 | // 21 | // This program is distributed in the hope that it will be useful, but WITHOUT 22 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 23 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 24 | // for more details. 25 | // 26 | // You should have received a copy of the GNU General Public License along 27 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no 28 | // target there if the PDF file isn't present.) If not, see 29 | // for a copy. 30 | // }}} 31 | // License: GPL, v3, as defined and found on www.gnu.org, 32 | // {{{ 33 | // http://www.gnu.org/licenses/gpl.html 34 | // 35 | //////////////////////////////////////////////////////////////////////////////// 36 | // 37 | // }}} 38 | #ifndef EMMCDRV_H 39 | #define EMMCDRV_H 40 | #include 41 | 42 | typedef struct EMMC_S { 43 | volatile uint32_t sd_cmd, sd_data, sd_fifa, sd_fifb, sd_phy; 44 | // #if (sizeof(void *) <= 4) && !defined(__LITTLE_ENDIAN__) 45 | volatile uint32_t sd_unused; 46 | // #endif 47 | volatile void *sd_dma_addr; 48 | // #if (sizeof(void *) <= 4) && defined(__LITTLE_ENDIAN__) 49 | // volatile uint32_t sd_unused; 50 | // #endif 51 | volatile uint32_t sd_dma_length; 52 | } EMMC; 53 | 54 | struct EMMCDRV_S; 55 | 56 | extern struct EMMCDRV_S *emmc_init(EMMC *dev); 57 | extern int emmc_write(struct EMMCDRV_S *dev, const unsigned sector, const unsigned count, const char *buf); 58 | extern int emmc_read(struct EMMCDRV_S *dev, const unsigned sector, const unsigned count, char *buf); 59 | extern int emmc_ioctl(struct EMMCDRV_S *dev, char cmd, char *buf); 60 | #endif 61 | -------------------------------------------------------------------------------- /sw/sdiodrv.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: sw/sdiodrv.h 4 | // {{{ 5 | // Project: SD-Card controller 6 | // 7 | // Purpose: 8 | // 9 | // Creator: Dan Gisselquist, Ph.D. 10 | // Gisselquist Technology, LLC 11 | // 12 | //////////////////////////////////////////////////////////////////////////////// 13 | // }}} 14 | // Copyright (C) 2016-2025, Gisselquist Technology, LLC 15 | // {{{ 16 | // This program is free software (firmware): you can redistribute it and/or 17 | // modify it under the terms of the GNU General Public License as published 18 | // by the Free Software Foundation, either version 3 of the License, or (at 19 | // your option) any later version. 20 | // 21 | // This program is distributed in the hope that it will be useful, but WITHOUT 22 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 23 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 24 | // for more details. 25 | // 26 | // You should have received a copy of the GNU General Public License along 27 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no 28 | // target there if the PDF file isn't present.) If not, see 29 | // for a copy. 30 | // }}} 31 | // License: GPL, v3, as defined and found on www.gnu.org, 32 | // {{{ 33 | // http://www.gnu.org/licenses/gpl.html 34 | // 35 | //////////////////////////////////////////////////////////////////////////////// 36 | // 37 | // }}} 38 | #ifndef SDIODRV_H 39 | #define SDIODRV_H 40 | #include 41 | 42 | typedef struct SDIO_S { 43 | volatile uint32_t sd_cmd, sd_data, sd_fifa, sd_fifb, sd_phy; 44 | // #if (sizeof(void *) <= 4) && !defined(__LITTLE_ENDIAN__) 45 | volatile uint32_t sd_unused; 46 | // #endif 47 | volatile void *sd_dma_addr; 48 | // #if (sizeof(void *) <= 4) && defined(__LITTLE_ENDIAN__) 49 | // volatile uint32_t sd_unused; 50 | // #endif 51 | volatile uint32_t sd_dma_length; 52 | } SDIO; 53 | 54 | struct SDIODRV_S; 55 | 56 | extern struct SDIODRV_S *sdio_init(SDIO *dev); 57 | extern int sdio_write(struct SDIODRV_S *dev, const unsigned sector, const unsigned count, const char *buf); 58 | extern int sdio_read(struct SDIODRV_S *dev, const unsigned sector, const unsigned count, char *buf); 59 | extern int sdio_ioctl(struct SDIODRV_S *dev, char cmd, char *buf); 60 | #endif 61 | -------------------------------------------------------------------------------- /sw/sdspidrv.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: sw/sdspidrv.h 4 | // {{{ 5 | // Project: SD-Card controller 6 | // 7 | // Purpose: Function header definitions and some constant definitions for 8 | // working with the SDSPI controller. Other constant definitions 9 | // are currently provided by the AutoFPGA script and placed into board.h. 10 | // You can (currently) find alternate definitions for these in the 11 | // autotest_tb.cpp file. 12 | // 13 | // Creator: Dan Gisselquist, Ph.D. 14 | // Gisselquist Technology, LLC 15 | // 16 | //////////////////////////////////////////////////////////////////////////////// 17 | // }}} 18 | // Copyright (C) 2016-2025, Gisselquist Technology, LLC 19 | // {{{ 20 | // This program is free software (firmware): you can redistribute it and/or 21 | // modify it under the terms of the GNU General Public License as published 22 | // by the Free Software Foundation, either version 3 of the License, or (at 23 | // your option) any later version. 24 | // 25 | // This program is distributed in the hope that it will be useful, but WITHOUT 26 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 27 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 28 | // for more details. 29 | // 30 | // You should have received a copy of the GNU General Public License along 31 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no 32 | // target there if the PDF file isn't present.) If not, see 33 | // for a copy. 34 | // }}} 35 | // License: GPL, v3, as defined and found on www.gnu.org, 36 | // {{{ 37 | // http://www.gnu.org/licenses/gpl.html 38 | // 39 | //////////////////////////////////////////////////////////////////////////////// 40 | // 41 | // }}} 42 | #ifndef SDSPIDRV_H 43 | #define SDSPIDRV_H 44 | 45 | extern int sdcard_err; 46 | 47 | struct SDSPI_S; 48 | struct SDSPIDRV_S; 49 | 50 | extern struct SDSPIDRV_S *sdspi_init(struct SDSPI_S *); 51 | extern int sdspi_read(struct SDSPIDRV_S *, unsigned sector, unsigned count, char *buf); 52 | extern int sdspi_write(struct SDSPIDRV_S *, unsigned sector, unsigned count, const char *buf); 53 | extern int sdspi_ioctl(struct SDSPIDRV_S *, char cmd, char *buf); 54 | 55 | #endif // SDSPIDRV_H 56 | --------------------------------------------------------------------------------