diff --git a/.gitignore b/.gitignore index 3a6dad8b0..3d3d875f0 100644 --- a/.gitignore +++ b/.gitignore @@ -193,6 +193,9 @@ config/deriv docs/docker/buildroot-config-src docs/docker/testvector-generation sim/questa/cov +sim/questa/fcovrvvi +sim/questa/fcovrvvi_logs +sim/questa/fcovrvvi_ucdb sim/covhtmlreport/ sim/questa/logs sim/questa/wkdir diff --git a/.gitmodules b/.gitmodules index 0400ae926..24d02b22e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -28,3 +28,6 @@ sparseCheckout = true path = addins/verilog-ethernet url = https://github.com/ross144/verilog-ethernet.git +[submodule "cvw-arch-verif"] + path = cvw-arch-verif + url = https://github.com/openhwgroup/cvw-arch-verif diff --git a/bin/regression-wally b/bin/regression-wally index 0027b55f4..95c3a7c99 100755 --- a/bin/regression-wally +++ b/bin/regression-wally @@ -340,6 +340,7 @@ defaultsim = "verilator" # Default simulator for all other tests parser = argparse.ArgumentParser() parser.add_argument("--ccov", help="Code Coverage", action="store_true") parser.add_argument("--fcov", help="Functional Coverage", action="store_true") +parser.add_argument("--fcovrvvi", help="Functional Coverage RVVI", action="store_true") parser.add_argument("--nightly", help="Run large nightly regression", action="store_true") parser.add_argument("--buildroot", help="Include Buildroot Linux boot test (takes many hours, done along with --nightly)", action="store_true") parser.add_argument("--testfloat", help="Include Testfloat floating-point unit tests", action="store_true") @@ -357,6 +358,8 @@ if (args.ccov): # only run RV64GC tests in coverage mode coverStr = '--ccov' elif (args.fcov): # only run RV64GC tests in lockstep in coverage mode coverStr = '--fcov' +elif (args.fcovrvvi): # only run RV64GC tests in rvvi coverage mode + coverStr = '--fcovrvvi' else: coverStr = '' @@ -392,6 +395,10 @@ elif (args.fcov): # only run RV64GC tests on Questa in lockstep in functional c # grepstr="SUCCESS! All tests ran without failures", # grepfile = sim_log) #configs.append(tc) +elif (args.fcovrvvi): # only run RV64GC tests on Questa in rvvi coverage mode + addTests(tests64gc_nofp, coveragesim) + if (args.fp): + addTests(tests64gc_fp, coveragesim) else: for sim in sims: if (not (args.buildroot and sim == defaultsim)): # skip short buildroot sim if running long one @@ -501,6 +508,9 @@ def main(): if args.ccov: TIMEOUT_DUR = 20*60 # seconds os.system('rm -f questa/cov/*.ucdb') + elif args.fcovrvvi: + TIMEOUT_DUR = 20*60 + os.system('rm -f questa/fcovrvvi_ucdb/* questa/fcovrvvi_logs/* questa/fcovrvvi/*') elif args.fcov: TIMEOUT_DUR = 1*60 os.system('rm -f questa/fcov_ucdb/* questa/fcov_logs/* questa/fcov/*') @@ -535,6 +545,8 @@ def main(): os.system('make QuestaCodeCoverage') if args.fcov: os.system('make QuestaFunctCoverage') + if args.fcovrvvi: + os.system('make QuestaFunctCoverageRvvi') # Count the number of failures if num_fail: print(f"{bcolors.FAIL}Regression failed with %s failed configurations{bcolors.ENDC}" % num_fail) diff --git a/bin/wsim b/bin/wsim index cd1c77d12..e35ec6841 100755 --- a/bin/wsim +++ b/bin/wsim @@ -28,6 +28,7 @@ parser.add_argument("--tb", "-t", help="Testbench", choices=["testbench", "testb parser.add_argument("--gui", "-g", help="Simulate with GUI", action="store_true") parser.add_argument("--ccov", "-c", help="Code Coverage", action="store_true") parser.add_argument("--fcov", "-f", help="Functional Coverage, implies lockstep", action="store_true") +parser.add_argument("--fcovrvvi", "-fr", help="Functional Coverage RVVI", action="store_true") parser.add_argument("--args", "-a", help="Optional arguments passed to simulator via $value$plusargs", default="") parser.add_argument("--vcd", "-v", help="Generate testbench.vcd", action="store_true") parser.add_argument("--lockstep", "-l", help="Run ImperasDV lock, step, and compare.", action="store_true") @@ -57,7 +58,7 @@ if(args.testsuite.endswith('.elf') and args.elf == ""): # No --elf argument; che # Validate arguments -if (args.gui or args.ccov or args.fcov or args.lockstep): +if (args.gui or args.ccov or args.fcov or args.fcovrvvi or args.lockstep): if args.sim not in ["questa", "vcs"]: print("Option only supported for Questa and VCS") exit(1) @@ -95,10 +96,12 @@ if (args.ccov): flags += " --ccov" if (args.fcov): flags += " --fcov" +if (args.fcovrvvi): + flags += "--fcovrvvi" # create the output sub-directories. regressionDir = WALLY + '/sim/' -for d in ["logs", "wkdir", "cov", "ucdb", "fcov", "fcov_ucdb"]: +for d in ["logs", "wkdir", "cov", "ucdb", "fcov", "fcov_ucdb", "fcovrvvi", "fcovrvvi_ucdb"]: try: os.mkdir(regressionDir+args.sim+"/"+d) except: diff --git a/config/derivlist.txt b/config/derivlist.txt index c689d2cb9..ab9ee703f 100644 --- a/config/derivlist.txt +++ b/config/derivlist.txt @@ -50,7 +50,8 @@ PLIC_NUM_SRC 32'd53 deriv fpga buildroot BOOTROM_PRELOAD 1 UNCORE_RAM_BASE 64'h2000 -UNCORE_RAM_RANGE 64'hFFF +UNCORE_RAM_RANGE 64'h1FFF +BOOTROM_RANGE 64'hFFF EXT_MEM_SUPPORTED 1 EXT_MEM_BASE 64'h80000000 EXT_MEM_RANGE 64'h0FFFFFFF diff --git a/cvw-arch-verif b/cvw-arch-verif new file mode 160000 index 000000000..2a4f56ec9 --- /dev/null +++ b/cvw-arch-verif @@ -0,0 +1 @@ +Subproject commit 2a4f56ec97db7cdd6fd13fb928122d408fefbf1e diff --git a/fpga/constraints/constraints-ArtyA7.xdc b/fpga/constraints/constraints-ArtyA7.xdc index 556c75c43..e4774280f 100644 --- a/fpga/constraints/constraints-ArtyA7.xdc +++ b/fpga/constraints/constraints-ArtyA7.xdc @@ -4,6 +4,7 @@ # This clock is not used by wally or the AHB Bus. However it is used by the AXI BUS on the DD3 IP. #create_generated_clock -name CLKDiv64_Gen -source [get_pins wallypipelinedsoc/uncore.uncore/sdc.SDC/sd_top/slow_clk_divider/clkMux/I0] -multiply_by 1 -divide_by 1 [get_pins wallypipelinedsoc/uncore.uncore/sdc.SDC/sd_top/slow_clk_divider/clkMux/O] +create_generated_clock -name SPISDCClock -source [get_pins clk_out3_xlnx_mmcm] -multiply_by 1 -divide_by 1 [get_pins wallypipelinedsoc/uncore.uncore/sdc.sdc/SPICLK] ##### clock ##### set_property PACKAGE_PIN E3 [get_ports {default_100mhz_clk}] @@ -60,6 +61,7 @@ set_property IOSTANDARD LVCMOS33 [get_ports {GPO[2]}] set_property IOSTANDARD LVCMOS33 [get_ports {GPO[1]}] set_property IOSTANDARD LVCMOS33 [get_ports {GPO[0]}] set_max_delay -to [get_ports {GPO[*]}] 20.000 + set_output_delay -clock [get_clocks clk_out3_xlnx_mmcm] -min -add_delay 0.000 [get_ports {GPO[*]}] set_output_delay -clock [get_clocks clk_out3_xlnx_mmcm] -max -add_delay 0.000 [get_ports {GPO[*]}] @@ -100,42 +102,52 @@ set_property IOSTANDARD LVCMOS33 [get_ports {south_reset}] ##### SD Card I/O ##### #***** may have to switch to Pmod JB or JC. -set_property PACKAGE_PIN D4 [get_ports {SDCDat[3]}] -set_property PACKAGE_PIN D2 [get_ports {SDCDat[2]}] -set_property PACKAGE_PIN E2 [get_ports {SDCDat[1]}] -set_property PACKAGE_PIN F4 [get_ports {SDCDat[0]}] -set_property PACKAGE_PIN F3 [get_ports SDCCLK] -set_property PACKAGE_PIN D3 [get_ports {SDCCmd}] -set_property PACKAGE_PIN H2 [get_ports {SDCCD}] +#set_property PACKAGE_PIN D4 [get_ports {SDCDat[3]}] +#set_property PACKAGE_PIN D2 [get_ports {SDCDat[2]}] +#set_property PACKAGE_PIN E2 [get_ports {SDCDat[1]}] +#set_property PACKAGE_PIN F4 [get_ports {SDCDat[0]}] +#set_property PACKAGE_PIN F3 [get_ports SDCCLK] +#set_property PACKAGE_PIN D3 [get_ports {SDCCmd}] +#set_property PACKAGE_PIN H2 [get_ports {SDCCD}] + +#set_property IOSTANDARD LVCMOS33 [get_ports {SDCDat[3]}] +#set_property IOSTANDARD LVCMOS33 [get_ports {SDCDat[2]}] +#set_property IOSTANDARD LVCMOS33 [get_ports {SDCDat[1]}] +#set_property IOSTANDARD LVCMOS33 [get_ports {SDCDat[0]}] +#set_property IOSTANDARD LVCMOS33 [get_ports SDCCLK] +#set_property IOSTANDARD LVCMOS33 [get_ports {SDCCmd}] +#set_property IOSTANDARD LVCMOS33 [get_ports {SDCCD}] +#set_property PULLUP true [get_ports {SDCDat[3]}] +#set_property PULLUP true [get_ports {SDCDat[2]}] +#set_property PULLUP true [get_ports {SDCDat[1]}] +#set_property PULLUP true [get_ports {SDCDat[0]}] +#set_property PULLUP true [get_ports {SDCCmd}] +#set_property PULLUP true [get_ports {SDCCD}] + +# SDCDat[3] +set_property -dict {PACKAGE_PIN D4 IOSTANDARD LVCMOS33 PULLUP true} [get_ports {SDCCS}] +# set_property -dict {PACKAGE_PIN D2 IOSTANDARD LVCMOS33 PULLUP true} [get_ports {SDCDat[2]}] +# set_property -dict {PACKAGE_PIN E2 IOSTANDARD LVCMOS33 PULLUP true} [get_ports {SDCDat[1]}] +# SDCDat[0] +set_property -dict {PACKAGE_PIN F4 IOSTANDARD LVCMOS33 PULLUP true} [get_ports {SDCIn}] +set_property -dict {PACKAGE_PIN F3 IOSTANDARD LVCMOS33 PULLUP true} [get_ports {SDCCLK}] +set_property -dict {PACKAGE_PIN D3 IOSTANDARD LVCMOS33 PULLUP true} [get_ports {SDCCmd}] +set_property -dict {PACKAGE_PIN H2 IOSTANDARD LVCMOS33 PULLUP true} [get_ports {SDCCD}] +set_property -dict {PACKAGE_PIN G2 IOSTANDARD LVCMOS33 PULLUP true} [get_ports {SDCWP}] -set_property IOSTANDARD LVCMOS33 [get_ports {SDCDat[3]}] -set_property IOSTANDARD LVCMOS33 [get_ports {SDCDat[2]}] -set_property IOSTANDARD LVCMOS33 [get_ports {SDCDat[1]}] -set_property IOSTANDARD LVCMOS33 [get_ports {SDCDat[0]}] -set_property IOSTANDARD LVCMOS33 [get_ports SDCCLK] -set_property IOSTANDARD LVCMOS33 [get_ports {SDCCmd}] -set_property IOSTANDARD LVCMOS33 [get_ports {SDCCD}] -set_property PULLUP true [get_ports {SDCDat[3]}] -set_property PULLUP true [get_ports {SDCDat[2]}] -set_property PULLUP true [get_ports {SDCDat[1]}] -set_property PULLUP true [get_ports {SDCDat[0]}] -set_property PULLUP true [get_ports {SDCCmd}] -set_property PULLUP true [get_ports {SDCCD}] +set_input_delay -clock [get_clocks SPISDCClock] -min -add_delay 2.500 [get_ports {SDCCS}] +set_input_delay -clock [get_clocks SPISDCClock] -max -add_delay 10.000 [get_ports {SDCCS}] +set_input_delay -clock [get_clocks SPISDCClock] -min -add_delay 2.500 [get_ports {SDCIn}] +set_input_delay -clock [get_clocks SPISDCClock] -max -add_delay 10.000 [get_ports {SDCIn}] -set_input_delay -clock [get_clocks clk_out3_xlnx_mmcm] -min -add_delay 2.500 [get_ports {SDCDat[*]}] -set_input_delay -clock [get_clocks clk_out3_xlnx_mmcm] -max -add_delay 21.000 [get_ports {SDCDat[*]}] +set_output_delay -clock [get_clocks SPISDCClock] -min -add_delay 2.000 [get_ports {SDCCmd}] +set_output_delay -clock [get_clocks SPISDCClock] -max -add_delay 6.000 [get_ports {SDCCmd}] -set_input_delay -clock [get_clocks clk_out3_xlnx_mmcm] -min -add_delay 2.500 [get_ports {SDCCmd}] -set_input_delay -clock [get_clocks clk_out3_xlnx_mmcm] -max -add_delay 14.000 [get_ports {SDCCmd}] +set_output_delay -clock [get_clocks SPISDCClock] 0.000 [get_ports SDCCLK] -set_output_delay -clock [get_clocks clk_out3_xlnx_mmcm] -min -add_delay 2.000 [get_ports {SDCCmd}] -set_output_delay -clock [get_clocks clk_out3_xlnx_mmcm] -max -add_delay 6.000 [get_ports {SDCCmd}] - -set_output_delay -clock [get_clocks clk_out3_xlnx_mmcm] 0.000 [get_ports SDCCLK] - #set_multicycle_path -from [get_pins xlnx_ddr3_c0/u_xlnx_ddr3_mig/u_memc_ui_top_axi/mem_intfc0/ddr_phy_top0/u_ddr_calib_top/init_calib_complete_reg/C] -to [get_pins xlnx_proc_sys_reset_0/U0/EXT_LPF/lpf_int_reg/D] 10 set_max_delay -datapath_only -from [get_pins xlnx_ddr3_c0/u_xlnx_ddr3_mig/u_memc_ui_top_axi/mem_intfc0/ddr_phy_top0/u_ddr_calib_top/init_calib_complete_reg/C] -to [get_pins xlnx_proc_sys_reset_0/U0/EXT_LPF/lpf_int_reg/D] 20.000 diff --git a/fpga/generator/Makefile b/fpga/generator/Makefile index c23e22ee0..5fbbfec33 100644 --- a/fpga/generator/Makefile +++ b/fpga/generator/Makefile @@ -1,14 +1,14 @@ dst := IP # vcu118 -#export XILINX_PART := xcvu9p-flga2104-2L-e -#export XILINX_BOARD := xilinx.com:vcu118:part0:2.4 -#export board := vcu118 +# export XILINX_PART := xcvu9p-flga2104-2L-e +# export XILINX_BOARD := xilinx.com:vcu118:part0:2.4 +# export board := vcu118 # vcu108 -#export XILINX_PART := xcvu095-ffva2104-2-e -#export XILINX_BOARD := xilinx.com:vcu108:part0:1.2 -#export board := vcu108 +# export XILINX_PART := xcvu095-ffva2104-2-e +# export XILINX_BOARD := xilinx.com:vcu108:part0:1.7 +# export board := vcu108 # Arty A7 export XILINX_PART := xc7a100tcsg324-1 @@ -40,11 +40,11 @@ IP_Arty: $(dst)/xlnx_proc_sys_reset.log \ $(dst)/xlnx_ddr3-$(board).log \ $(dst)/xlnx_mmcm.log \ $(dst)/xlnx_axi_clock_converter.log \ - $(dst)/xlnx_ahblite_axi_bridge.log \ - $(dst)/xlnx_axi_crossbar.log \ - $(dst)/xlnx_axi_dwidth_conv_32to64.log \ - $(dst)/xlnx_axi_dwidth_conv_64to32.log \ - $(dst)/xlnx_axi_prtcl_conv.log + $(dst)/xlnx_ahblite_axi_bridge.log +#$(dst)/xlnx_axi_crossbar.log \ +#$(dst)/xlnx_axi_dwidth_conv_32to64.log \ +#$(dst)/xlnx_axi_dwidth_conv_64to32.log \ +#$(dst)/xlnx_axi_prtcl_conv.log PreProcessFiles: @@ -61,6 +61,7 @@ PreProcessFiles: # This line allows the Bootloader to be loaded in a Block RAM on the FPGA sed -i "s/bit \[DATA_WIDTH-1:0\].*ROM.*/(\* rom_style=\"block\" \*) &/g" ../src/CopiedFiles_do_not_add_to_repo/generic/mem/rom1p1r.sv sed -i 's/$$WALLY/\.\.\/\.\.\/\.\.\//g' ../src/CopiedFiles_do_not_add_to_repo/generic/mem/rom1p1r.sv + sed -i 's/$$WALLY/\.\.\/\.\.\/\.\.\//g' ../src/CopiedFiles_do_not_add_to_repo/generic/mem/ram1p1rwbe.sv $(dst)/%.log: %.tcl mkdir -p IP diff --git a/fpga/generator/wally.tcl b/fpga/generator/wally.tcl index 93c2788a2..b2e1e359e 100644 --- a/fpga/generator/wally.tcl +++ b/fpga/generator/wally.tcl @@ -27,10 +27,10 @@ read_ip IP/xlnx_proc_sys_reset.srcs/sources_1/ip/xlnx_proc_sys_reset/xlnx_proc_s read_ip IP/xlnx_ahblite_axi_bridge.srcs/sources_1/ip/xlnx_ahblite_axi_bridge/xlnx_ahblite_axi_bridge.xci read_ip IP/xlnx_axi_clock_converter.srcs/sources_1/ip/xlnx_axi_clock_converter/xlnx_axi_clock_converter.xci # Added crossbar - Jacob Pease <2023-01-12 Thu> -read_ip IP/xlnx_axi_crossbar.srcs/sources_1/ip/xlnx_axi_crossbar/xlnx_axi_crossbar.xci -read_ip IP/xlnx_axi_dwidth_conv_32to64.srcs/sources_1/ip/xlnx_axi_dwidth_conv_32to64/xlnx_axi_dwidth_conv_32to64.xci -read_ip IP/xlnx_axi_dwidth_conv_64to32.srcs/sources_1/ip/xlnx_axi_dwidth_conv_64to32/xlnx_axi_dwidth_conv_64to32.xci -read_ip IP/xlnx_axi_prtcl_conv.srcs/sources_1/ip/xlnx_axi_prtcl_conv/xlnx_axi_prtcl_conv.xci +#read_ip IP/xlnx_axi_crossbar.srcs/sources_1/ip/xlnx_axi_crossbar/xlnx_axi_crossbar.xci +#read_ip IP/xlnx_axi_dwidth_conv_32to64.srcs/sources_1/ip/xlnx_axi_dwidth_conv_32to64/xlnx_axi_dwidth_conv_32to64.xci +#read_ip IP/xlnx_axi_dwidth_conv_64to32.srcs/sources_1/ip/xlnx_axi_dwidth_conv_64to32/xlnx_axi_dwidth_conv_64to32.xci +#read_ip IP/xlnx_axi_prtcl_conv.srcs/sources_1/ip/xlnx_axi_prtcl_conv/xlnx_axi_prtcl_conv.xci if {$board=="ArtyA7"} { read_ip IP/xlnx_ddr3.srcs/sources_1/ip/xlnx_ddr3/xlnx_ddr3.xci @@ -91,10 +91,8 @@ write_verilog -force -mode funcsim sim/syn-funcsim.v if {$board=="ArtyA7"} { #source ../constraints/small-debug.xdc source ../constraints/small-debug-rvvi.xdc - } else { - # source ../constraints/vcu-small-debug.xdc - source ../constraints/debug6.xdc + source ../constraints/vcu-small-debug.xdc } diff --git a/fpga/src/fpgaTopArtyA7.sv b/fpga/src/fpgaTopArtyA7.sv index 827ca1438..fa2aa59a9 100644 --- a/fpga/src/fpgaTopArtyA7.sv +++ b/fpga/src/fpgaTopArtyA7.sv @@ -33,17 +33,21 @@ module fpgaTop #(parameter logic RVVI_SYNTH_SUPPORTED = 1) (* mark_debug = "true" *) input resetn, input south_reset, - input [3:0] GPI, - output [4:0] GPO, + // GPIO signals + input [3:0] GPI, + output [4:0] GPO, - input UARTSin, - output UARTSout, - - inout [3:0] SDCDat, - output SDCCLK, - inout SDCCmd, - input SDCCD, + // UART Signals + input UARTSin, + output UARTSout, + // SDC Signals connecting to an SPI peripheral + input SDCIn, + output SDCCLK, + output SDCCmd, + output SDCCS, + input SDCCD, + input SDCWP, /* * Ethernet: 100BASE-T MII */ @@ -76,6 +80,7 @@ module fpgaTop #(parameter logic RVVI_SYNTH_SUPPORTED = 1) output [0:0] ddr3_odt ); + // MMCM Signals wire CPUCLK; wire c0_ddr4_ui_clk_sync_rst; wire bus_struct_reset; @@ -84,12 +89,12 @@ module fpgaTop #(parameter logic RVVI_SYNTH_SUPPORTED = 1) wire peripheral_aresetn; wire mb_reset; + // AHB Signals from Wally wire HCLKOpen; wire HRESETnOpen; wire [63:0] HRDATAEXT; wire HREADYEXT; wire HRESPEXT; - wire HSELEXTSDC; // TEMP BOOT SIGNAL - JACOB wire HSELEXT; wire [55:0] HADDR; wire [63:0] HWDATA; @@ -102,12 +107,10 @@ module fpgaTop #(parameter logic RVVI_SYNTH_SUPPORTED = 1) wire [3:0] HPROT; wire HMASTLOCK; + // GPIO Signals wire [31:0] GPIOIN, GPIOOUT, GPIOEN; - wire SDCCmdIn; - wire SDCCmdOE; - wire SDCCmdOut; - + // AHB to AXI Bridge Signals wire [3:0] m_axi_awid; wire [7:0] m_axi_awlen; wire [2:0] m_axi_awsize; @@ -115,40 +118,40 @@ module fpgaTop #(parameter logic RVVI_SYNTH_SUPPORTED = 1) wire [3:0] m_axi_awcache; wire [31:0] m_axi_awaddr; wire [2:0] m_axi_awprot; - wire m_axi_awvalid; - wire m_axi_awready; - wire m_axi_awlock; + wire m_axi_awvalid; + wire m_axi_awready; + wire m_axi_awlock; wire [63:0] m_axi_wdata; wire [7:0] m_axi_wstrb; - wire m_axi_wlast; - wire m_axi_wvalid; - wire m_axi_wready; + wire m_axi_wlast; + wire m_axi_wvalid; + wire m_axi_wready; wire [3:0] m_axi_bid; wire [1:0] m_axi_bresp; - wire m_axi_bvalid; - wire m_axi_bready; + wire m_axi_bvalid; + wire m_axi_bready; wire [3:0] m_axi_arid; wire [7:0] m_axi_arlen; wire [2:0] m_axi_arsize; wire [1:0] m_axi_arburst; wire [2:0] m_axi_arprot; wire [3:0] m_axi_arcache; - wire m_axi_arvalid; + wire m_axi_arvalid; wire [31:0] m_axi_araddr; wire m_axi_arlock; - wire m_axi_arready; + wire m_axi_arready; wire [3:0] m_axi_rid; wire [63:0] m_axi_rdata; wire [1:0] m_axi_rresp; - wire m_axi_rvalid; - wire m_axi_rlast; - wire m_axi_rready; + wire m_axi_rvalid; + wire m_axi_rlast; + wire m_axi_rready; + // AXI Signals going out of Clock Converter wire [3:0] BUS_axi_arregion; wire [3:0] BUS_axi_arqos; wire [3:0] BUS_axi_awregion; wire [3:0] BUS_axi_awqos; - wire [3:0] BUS_axi_awid; wire [7:0] BUS_axi_awlen; wire [2:0] BUS_axi_awsize; @@ -188,250 +191,10 @@ module fpgaTop #(parameter logic RVVI_SYNTH_SUPPORTED = 1) wire BUSCLK; wire sdio_reset_open; - // Crossbar to Bus ------------------------------------------------ - - wire s00_axi_aclk; - wire s00_axi_aresetn; - wire [3:0] s00_axi_awid; - wire [31:0]s00_axi_awaddr; - wire [7:0]s00_axi_awlen; - wire [2:0]s00_axi_awsize; - wire [1:0]s00_axi_awburst; - wire [0:0]s00_axi_awlock; - wire [3:0]s00_axi_awcache; - wire [2:0]s00_axi_awprot; - wire [3:0]s00_axi_awregion; - wire [3:0]s00_axi_awqos; - wire s00_axi_awvalid; - wire s00_axi_awready; - wire [63:0]s00_axi_wdata; - wire [7:0]s00_axi_wstrb; - wire s00_axi_wlast; - wire s00_axi_wvalid; - wire s00_axi_wready; - wire [1:0]s00_axi_bresp; - wire s00_axi_bvalid; - wire s00_axi_bready; - wire [3:0] s00_axi_arid; - wire [31:0]s00_axi_araddr; - wire [7:0]s00_axi_arlen; - wire [2:0]s00_axi_arsize; - wire [1:0]s00_axi_arburst; - wire [0:0]s00_axi_arlock; - wire [3:0]s00_axi_arcache; - wire [2:0]s00_axi_arprot; - wire [3:0]s00_axi_arregion; - wire [3:0]s00_axi_arqos; - wire s00_axi_arvalid; - wire s00_axi_arready; - wire [63:0]s00_axi_rdata; - wire [1:0]s00_axi_rresp; - wire s00_axi_rlast; - wire s00_axi_rvalid; - wire s00_axi_rready; - - wire [3:0] s00_axi_bid; - wire [3:0] s00_axi_rid; - - // 64to32 dwidth converter input interface------------------------- - wire s01_axi_aclk; - wire s01_axi_aresetn; - wire [3:0]s01_axi_awid; - wire [31:0]s01_axi_awaddr; - wire [7:0]s01_axi_awlen; - wire [2:0]s01_axi_awsize; - wire [1:0]s01_axi_awburst; - wire [0:0]s01_axi_awlock; - wire [3:0]s01_axi_awcache; - wire [2:0]s01_axi_awprot; - wire [3:0]s01_axi_awregion; - wire [3:0]s01_axi_awqos; // qos signals need to be 0 for SDC - wire s01_axi_awvalid; - wire s01_axi_awready; - wire [63:0]s01_axi_wdata; - wire [7:0]s01_axi_wstrb; - wire s01_axi_wlast; - wire s01_axi_wvalid; - wire s01_axi_wready; - wire [1:0]s01_axi_bresp; - wire s01_axi_bvalid; - wire s01_axi_bready; - wire [31:0]s01_axi_araddr; - wire [7:0]s01_axi_arlen; - wire [3:0] s01_axi_arid; - wire [2:0]s01_axi_arsize; - wire [1:0]s01_axi_arburst; - wire [0:0]s01_axi_arlock; - wire [3:0]s01_axi_arcache; - wire [2:0]s01_axi_arprot; - wire [3:0]s01_axi_arregion; - wire [3:0]s01_axi_arqos; // - wire s01_axi_arvalid; - wire s01_axi_arready; - wire [63:0]s01_axi_rdata; - wire [1:0]s01_axi_rresp; - wire s01_axi_rlast; - wire s01_axi_rvalid; - wire s01_axi_rready; - - // Output Interface - wire [31:0]axi4in_axi_awaddr; - wire [7:0]axi4in_axi_awlen; - wire [2:0]axi4in_axi_awsize; - wire [1:0]axi4in_axi_awburst; - wire [0:0]axi4in_axi_awlock; - wire [3:0]axi4in_axi_awcache; - wire [2:0]axi4in_axi_awprot; - wire [3:0]axi4in_axi_awregion; - wire [3:0]axi4in_axi_awqos; - wire axi4in_axi_awvalid; - wire axi4in_axi_awready; - wire [31:0]axi4in_axi_wdata; - wire [3:0]axi4in_axi_wstrb; - wire axi4in_axi_wlast; - wire axi4in_axi_wvalid; - wire axi4in_axi_wready; - wire [1:0]axi4in_axi_bresp; - wire axi4in_axi_bvalid; - wire axi4in_axi_bready; - wire [31:0]axi4in_axi_araddr; - wire [7:0]axi4in_axi_arlen; - wire [2:0]axi4in_axi_arsize; - wire [1:0]axi4in_axi_arburst; - wire [0:0]axi4in_axi_arlock; - wire [3:0]axi4in_axi_arcache; - wire [2:0]axi4in_axi_arprot; - wire [3:0]axi4in_axi_arregion; - wire [3:0]axi4in_axi_arqos; - wire axi4in_axi_arvalid; - wire axi4in_axi_arready; - wire [31:0]axi4in_axi_rdata; - wire [1:0]axi4in_axi_rresp; - wire axi4in_axi_rlast; - wire axi4in_axi_rvalid; - wire axi4in_axi_rready; - - // AXI4 to AXI4-Lite Protocol converter output - wire [31:0]SDCin_axi_awaddr; - wire [2:0]SDCin_axi_awprot; - wire SDCin_axi_awvalid; - wire SDCin_axi_awready; - wire [31:0]SDCin_axi_wdata; - wire [3:0]SDCin_axi_wstrb; - wire SDCin_axi_wvalid; - wire SDCin_axi_wready; - wire [1:0]SDCin_axi_bresp; - wire SDCin_axi_bvalid; - wire SDCin_axi_bready; - wire [31:0]SDCin_axi_araddr; - wire [2:0]SDCin_axi_arprot; - wire SDCin_axi_arvalid; - wire SDCin_axi_arready; - wire [31:0]SDCin_axi_rdata; - wire [1:0]SDCin_axi_rresp; - wire SDCin_axi_rvalid; - wire SDCin_axi_rready; - // ---------------------------------------------------------------- - - // 32to64 dwidth converter input interface ----------------------- - wire [31:0]SDCout_axi_awaddr; - wire [7:0]SDCout_axi_awlen; - wire [2:0]SDCout_axi_awsize; - wire [1:0]SDCout_axi_awburst; - wire [0:0]SDCout_axi_awlock; - wire [3:0]SDCout_axi_awcache; - wire [2:0]SDCout_axi_awprot; - wire [3:0]SDCout_axi_awregion; - wire [3:0]SDCout_axi_awqos; - wire SDCout_axi_awvalid; - wire SDCout_axi_awready; - wire [31:0]SDCout_axi_wdata; - wire [3:0]SDCout_axi_wstrb; - wire SDCout_axi_wlast; - wire SDCout_axi_wvalid; - wire SDCout_axi_wready; - wire [1:0]SDCout_axi_bresp; - wire SDCout_axi_bvalid; - wire SDCout_axi_bready; - wire [31:0]SDCout_axi_araddr; - wire [7:0]SDCout_axi_arlen; - wire [2:0]SDCout_axi_arsize; - wire [1:0]SDCout_axi_arburst; - wire [0:0]SDCout_axi_arlock; - wire [3:0]SDCout_axi_arcache; - wire [2:0]SDCout_axi_arprot; - wire [3:0]SDCout_axi_arregion; - wire [3:0]SDCout_axi_arqos; - wire SDCout_axi_arvalid; - wire SDCout_axi_arready; - wire [31:0]SDCout_axi_rdata; - wire [1:0]SDCout_axi_rresp; - wire SDCout_axi_rlast; - wire SDCout_axi_rvalid; - wire SDCout_axi_rready; - - // Output Interface - wire [3:0]m01_axi_awid; - wire [31:0]m01_axi_awaddr; - wire [7:0]m01_axi_awlen; - wire [2:0]m01_axi_awsize; - wire [1:0]m01_axi_awburst; - wire [0:0]m01_axi_awlock; - wire [3:0]m01_axi_awcache; - wire [2:0]m01_axi_awprot; - wire [3:0]m01_axi_awregion; - wire [3:0]m01_axi_awqos; - wire m01_axi_awvalid; - wire m01_axi_awready; - wire [63:0]m01_axi_wdata; - wire [7:0]m01_axi_wstrb; - wire m01_axi_wlast; - wire m01_axi_wvalid; - wire m01_axi_wready; - wire [3:0] m01_axi_bid; - wire [1:0]m01_axi_bresp; - wire m01_axi_bvalid; - wire m01_axi_bready; - wire [3:0] m01_axi_arid; - wire [31:0]m01_axi_araddr; - wire [7:0]m01_axi_arlen; - wire [2:0]m01_axi_arsize; - wire [1:0]m01_axi_arburst; - wire [0:0]m01_axi_arlock; - wire [3:0]m01_axi_arcache; - wire [2:0]m01_axi_arprot; - wire [3:0]m01_axi_arregion; - wire [3:0]m01_axi_arqos; - wire m01_axi_arvalid; - wire m01_axi_arready; - wire [3:0] m01_axi_rid; - wire [63:0]m01_axi_rdata; - wire [1:0]m01_axi_rresp; - wire m01_axi_rlast; - wire m01_axi_rvalid; - wire m01_axi_rready; - - // Old SDC input - // wire [3:0] SDCDatIn; - - // New SDC Command IOBUF connections - wire sd_cmd_i; - wire sd_cmd_reg_o; - wire sd_cmd_reg_t; - - // SD Card Interrupt signal - wire SDCIntr; - - // New SDC Data IOBUF connections - wire [3:0] sd_dat_i; - wire [3:0] sd_dat_reg_o; - wire sd_dat_reg_t; - - - wire c0_init_calib_complete; + wire c0_init_calib_complete; wire dbg_clk; wire [511 : 0] dbg_bus; - wire ui_clk_sync_rst; + wire ui_clk_sync_rst; wire CLK208; wire clk167; @@ -440,18 +203,21 @@ module fpgaTop #(parameter logic RVVI_SYNTH_SUPPORTED = 1) wire app_sr_active; wire app_ref_ack; wire app_zq_ack; - wire mmcm_locked; + wire mmcm_locked; wire [11:0] device_temp; - wire mmcm1_locked; + wire mmcm1_locked; (* mark_debug = "true" *) logic RVVIStall; - assign GPIOIN = {28'b0, GPI}; + assign GPIOIN = {25'b0, SDCCD, SDCWP, 1'b0, GPI}; assign GPO = GPIOOUT[4:0]; assign ahblite_resetn = peripheral_aresetn; assign cpu_reset = bus_struct_reset; assign calib = c0_init_calib_complete; + logic [3:0] SDCCSin; + assign SDCCS = SDCCSin[0]; + // mmcm // the ddr3 mig7 requires 2 input clocks @@ -466,26 +232,7 @@ module fpgaTop #(parameter logic RVVI_SYNTH_SUPPORTED = 1) .reset(1'b0), .locked(mmcm1_locked), .clk_in1(default_100mhz_clk)); - -/* -----\/----- EXCLUDED -----\/----- - // SD Card Tristate - IOBUF iobufSDCMD(.T(~SDCCmdOE), // iobuf's T is active low - .I(SDCCmdOut), - .O(SDCCmdIn), - .IO(SDCCmd)); - -----/\----- EXCLUDED -----/\----- */ - // IOBUFS for new SDC peripheral - IOBUF IOBUF_cmd (.O(sd_cmd_i), .IO(SDCCmd), .I(sd_cmd_reg_o), .T(sd_cmd_reg_t)); - genvar i; - generate - for (i = 0; i < 4; i = i + 1) begin - IOBUF iobufSDCDat(.T(sd_dat_reg_t), - .I(sd_dat_reg_o[i]), - .O(sd_dat_i[i]), - .IO(SDCDat[i]) ); - end - endgenerate // reset controller XILINX IP @@ -501,26 +248,24 @@ module fpgaTop #(parameter logic RVVI_SYNTH_SUPPORTED = 1) .interconnect_aresetn(interconnect_aresetn), //open .peripheral_aresetn(peripheral_aresetn)); - // wally - // RT and JP: FIXME add sdc interrupt and HSELEXTSDC, remove old sdc after the new sdc ahb version is implemented - `include "parameter-defs.vh" - + + // Wally wallypipelinedsoc #(P) wallypipelinedsoc(.clk(CPUCLK), .reset_ext(bus_struct_reset), .reset(), .HRDATAEXT, .HREADYEXT, .HRESPEXT, .HSELEXT, - .HSELEXTSDC, .HCLK(HCLKOpen), .HRESETn(HRESETnOpen), + .HCLK(HCLKOpen), .HRESETn(HRESETnOpen), .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HSIZE, .HBURST, .HPROT, .HTRANS, .HMASTLOCK, .HREADY, .TIMECLK(1'b0), .GPIOIN, .GPIOOUT, .GPIOEN, - .UARTSin, .UARTSout, .SDCIntr, .ExternalStall(RVVIStall)); + .UARTSin, .UARTSout, .SDCIn, .SDCCmd, .SDCCS(SDCCSin), .SDCCLK, .ExternalStall(RVVIStall)); // ahb lite to axi bridge xlnx_ahblite_axi_bridge xlnx_ahblite_axi_bridge_0 (.s_ahb_hclk(CPUCLK), .s_ahb_hresetn(peripheral_aresetn), - .s_ahb_hsel(HSELEXT | HSELEXTSDC), + .s_ahb_hsel(HSELEXT), .s_ahb_haddr(HADDR[31:0]), .s_ahb_hprot(HPROT), .s_ahb_htrans(HTRANS), @@ -568,432 +313,49 @@ module fpgaTop #(parameter logic RVVI_SYNTH_SUPPORTED = 1) .m_axi_rlast(m_axi_rlast), .m_axi_rready(m_axi_rready)); - // AXI Crossbar for arbitrating the SDC and CPU -------------- - xlnx_axi_crossbar xlnx_axi_crossbar_0 - (.aclk(CPUCLK), - .aresetn(peripheral_aresetn), - - // Connect Masters - .s_axi_awid({4'b1000, m_axi_awid}), - .s_axi_awaddr({m01_axi_awaddr, m_axi_awaddr}), - .s_axi_awlen({m01_axi_awlen, m_axi_awlen}), - .s_axi_awsize({m01_axi_awsize, m_axi_awsize}), - .s_axi_awburst({m01_axi_awburst, m_axi_awburst}), - .s_axi_awlock({m01_axi_awlock, m_axi_awlock}), - .s_axi_awcache({m01_axi_awcache, m_axi_awcache}), - .s_axi_awprot({m01_axi_awprot, m_axi_awprot}), - .s_axi_awqos(8'b0), - .s_axi_awvalid({m01_axi_awvalid, m_axi_awvalid}), - .s_axi_awready({m01_axi_awready, m_axi_awready}), - .s_axi_wdata({m01_axi_wdata, m_axi_wdata}), - .s_axi_wstrb({m01_axi_wstrb, m_axi_wstrb}), - .s_axi_wlast({m01_axi_wlast, m_axi_wlast}), - .s_axi_wvalid({m01_axi_wvalid, m_axi_wvalid}), - .s_axi_wready({m01_axi_wready, m_axi_wready}), - .s_axi_bid({m01_axi_bid, m_axi_bid}), - .s_axi_bresp({m01_axi_bresp, m_axi_bresp}), - .s_axi_bvalid({m01_axi_bvalid, m_axi_bvalid}), - .s_axi_bready({m01_axi_bready, m_axi_bready}), - .s_axi_arid({4'b1000, m_axi_arid}), - .s_axi_araddr({m01_axi_araddr, m_axi_araddr}), - .s_axi_arlen({m01_axi_arlen, m_axi_arlen}), - .s_axi_arsize({m01_axi_arsize, m_axi_arsize}), - .s_axi_arburst({m01_axi_arburst, m_axi_arburst}), - .s_axi_arlock({m01_axi_arlock, m_axi_arlock}), - .s_axi_arcache({m01_axi_arcache, m_axi_arcache}), - .s_axi_arprot({m01_axi_arprot, m_axi_arprot}), - .s_axi_arqos(8'b0), - .s_axi_arvalid({m01_axi_arvalid, m_axi_arvalid}), - .s_axi_arready({m01_axi_arready, m_axi_arready}), - .s_axi_rid({m01_axi_rid, m_axi_rid}), - .s_axi_rdata({m01_axi_rdata, m_axi_rdata}), - .s_axi_rresp({m01_axi_rresp, m_axi_rresp}), - .s_axi_rlast({m01_axi_rlast, m_axi_rlast}), - .s_axi_rvalid({m01_axi_rvalid, m_axi_rvalid}), - .s_axi_rready({m01_axi_rready, m_axi_rready}), - - // Connect Slaves - .m_axi_awid({s01_axi_awid, s00_axi_awid}), - .m_axi_awlen({s01_axi_awlen, s00_axi_awlen}), - .m_axi_awsize({s01_axi_awsize, s00_axi_awsize}), - .m_axi_awburst({s01_axi_awburst, s00_axi_awburst}), - .m_axi_awcache({s01_axi_awcache, s00_axi_awcache}), - .m_axi_awaddr({s01_axi_awaddr, s00_axi_awaddr}), - .m_axi_awprot({s01_axi_awprot, s00_axi_awprot}), - .m_axi_awregion({s01_axi_awregion, s00_axi_awregion}), - .m_axi_awqos({s01_axi_awqos, s00_axi_awqos}), - .m_axi_awvalid({s01_axi_awvalid, s00_axi_awvalid}), - .m_axi_awready({s01_axi_awready, s00_axi_awready}), - .m_axi_awlock({s01_axi_awlock, s00_axi_awlock}), - .m_axi_wdata({s01_axi_wdata, s00_axi_wdata}), - .m_axi_wstrb({s01_axi_wstrb, s00_axi_wstrb}), - .m_axi_wlast({s01_axi_wlast, s00_axi_wlast}), - .m_axi_wvalid({s01_axi_wvalid, s00_axi_wvalid}), - .m_axi_wready({s01_axi_wready, s00_axi_wready}), - .m_axi_bid({4'b1000, s00_axi_bid}), - .m_axi_bresp({s01_axi_bresp, s00_axi_bresp}), - .m_axi_bvalid({s01_axi_bvalid, s00_axi_bvalid}), - .m_axi_bready({s01_axi_bready, s00_axi_bready}), - .m_axi_arid({s01_axi_arid, s00_axi_arid}), - .m_axi_arlen({s01_axi_arlen, s00_axi_arlen}), - .m_axi_arsize({s01_axi_arsize, s00_axi_arsize}), - .m_axi_arburst({s01_axi_arburst, s00_axi_arburst}), - .m_axi_arprot({s01_axi_arprot, s00_axi_arprot}), - .m_axi_arregion({s01_axi_arregion, s00_axi_arregion}), - .m_axi_arqos({s01_axi_arqos, s00_axi_arqos}), - .m_axi_arcache({s01_axi_arcache, s00_axi_arcache}), - .m_axi_arvalid({s01_axi_arvalid, s00_axi_arvalid}), - .m_axi_araddr({s01_axi_araddr, s00_axi_araddr}), - .m_axi_arlock({s01_axi_arlock, s00_axi_arlock}), - .m_axi_arready({s01_axi_arready, s00_axi_arready}), - .m_axi_rid({4'b1000, s00_axi_rid}), - .m_axi_rdata({s01_axi_rdata, s00_axi_rdata}), - .m_axi_rresp({s01_axi_rresp, s00_axi_rresp}), - .m_axi_rvalid({s01_axi_rvalid, s00_axi_rvalid}), - .m_axi_rlast({s01_axi_rlast, s00_axi_rlast}), - .m_axi_rready({s01_axi_rready, s00_axi_rready}) - ); - - // ----------------------------------------------------- - - // SDC Implementation ---------------------------------- - // - // The SDC peripheral from Eugene Tarassov takes in an AXI4Lite - // interface and outputs an AXI4 interface. In order to convert from - // one to the other, we use these dwidth converters to make sure the - // bit widths match the rest of the bus. - - xlnx_axi_dwidth_conv_64to32 axi_conv_down - (.s_axi_aclk(CPUCLK), - .s_axi_aresetn(peripheral_aresetn), - - // Slave interface - .s_axi_awaddr(s01_axi_awaddr), - .s_axi_awlen(s01_axi_awlen), - .s_axi_awsize(s01_axi_awsize), - .s_axi_awburst(s01_axi_awburst), - .s_axi_awlock(s01_axi_awlock), - .s_axi_awcache(s01_axi_awcache), - .s_axi_awprot(s01_axi_awprot), - .s_axi_awregion(s01_axi_awregion), - .s_axi_awqos(4'b0), - .s_axi_awvalid(s01_axi_awvalid), - .s_axi_awready(s01_axi_awready), - .s_axi_wdata(s01_axi_wdata), - .s_axi_wstrb(s01_axi_wstrb), - .s_axi_wlast(s01_axi_wlast), - .s_axi_wvalid(s01_axi_wvalid), - .s_axi_wready(s01_axi_wready), - .s_axi_bresp(s01_axi_bresp), - .s_axi_bvalid(s01_axi_bvalid), - .s_axi_bready(s01_axi_bready), - .s_axi_araddr(s01_axi_araddr), - .s_axi_arlen(s01_axi_arlen), - .s_axi_arsize(s01_axi_arsize), - .s_axi_arburst(s01_axi_arburst), - .s_axi_arlock(s01_axi_arlock), - .s_axi_arcache(s01_axi_arcache), - .s_axi_arprot(s01_axi_arprot), - .s_axi_arregion(s01_axi_arregion), - .s_axi_arqos(4'b0), - .s_axi_arvalid(s01_axi_arvalid), - .s_axi_arready(s01_axi_arready), - .s_axi_rdata(s01_axi_rdata), - .s_axi_rresp(s01_axi_rresp), - .s_axi_rlast(s01_axi_rlast), - .s_axi_rvalid(s01_axi_rvalid), - .s_axi_rready(s01_axi_rready), - - // Master interface - .m_axi_awaddr(axi4in_axi_awaddr), - .m_axi_awlen(axi4in_axi_awlen), - .m_axi_awsize(axi4in_axi_awsize), - .m_axi_awburst(axi4in_axi_awburst), - .m_axi_awlock(axi4in_axi_awlock), - .m_axi_awcache(axi4in_axi_awcache), - .m_axi_awprot(axi4in_axi_awprot), - .m_axi_awregion(axi4in_axi_awregion), - .m_axi_awqos(axi4in_axi_awqos), - .m_axi_awvalid(axi4in_axi_awvalid), - .m_axi_awready(axi4in_axi_awready), - .m_axi_wdata(axi4in_axi_wdata), - .m_axi_wstrb(axi4in_axi_wstrb), - .m_axi_wlast(axi4in_axi_wlast), - .m_axi_wvalid(axi4in_axi_wvalid), - .m_axi_wready(axi4in_axi_wready), - .m_axi_bresp(axi4in_axi_bresp), - .m_axi_bvalid(axi4in_axi_bvalid), - .m_axi_bready(axi4in_axi_bready), - .m_axi_araddr(axi4in_axi_araddr), - .m_axi_arlen(axi4in_axi_arlen), - .m_axi_arsize(axi4in_axi_arsize), - .m_axi_arburst(axi4in_axi_arburst), - .m_axi_arlock(axi4in_axi_arlock), - .m_axi_arcache(axi4in_axi_arcache), - .m_axi_arprot(axi4in_axi_arprot), - .m_axi_arregion(axi4in_axi_arregion), - .m_axi_arqos(axi4in_axi_arqos), - .m_axi_arvalid(axi4in_axi_arvalid), - .m_axi_arready(axi4in_axi_arready), - .m_axi_rdata(axi4in_axi_rdata), - .m_axi_rresp(axi4in_axi_rresp), - .m_axi_rlast(axi4in_axi_rlast), - .m_axi_rvalid(axi4in_axi_rvalid), - .m_axi_rready(axi4in_axi_rready) - ); - - xlnx_axi_prtcl_conv axi4tolite - (.aclk(CPUCLK), - .aresetn(peripheral_aresetn), - - // AXI4 In - .s_axi_awaddr(axi4in_axi_awaddr), - .s_axi_awlen(axi4in_axi_awlen), - .s_axi_awsize(axi4in_axi_awsize), - .s_axi_awburst(axi4in_axi_awburst), - .s_axi_awlock(axi4in_axi_awlock), - .s_axi_awcache(axi4in_axi_awcache), - .s_axi_awprot(axi4in_axi_awprot), - .s_axi_awregion(axi4in_axi_awregion), - .s_axi_awqos(axi4in_axi_awqos), - .s_axi_awvalid(axi4in_axi_awvalid), - .s_axi_awready(axi4in_axi_awready), - .s_axi_wdata(axi4in_axi_wdata), - .s_axi_wstrb(axi4in_axi_wstrb), - .s_axi_wlast(axi4in_axi_wlast), - .s_axi_wvalid(axi4in_axi_wvalid), - .s_axi_wready(axi4in_axi_wready), - .s_axi_bresp(axi4in_axi_bresp), - .s_axi_bvalid(axi4in_axi_bvalid), - .s_axi_bready(axi4in_axi_bready), - .s_axi_araddr(axi4in_axi_araddr), - .s_axi_arlen(axi4in_axi_arlen), - .s_axi_arsize(axi4in_axi_arsize), - .s_axi_arburst(axi4in_axi_arburst), - .s_axi_arlock(axi4in_axi_arlock), - .s_axi_arcache(axi4in_axi_arcache), - .s_axi_arprot(axi4in_axi_arprot), - .s_axi_arregion(axi4in_axi_arregion), - .s_axi_arqos(axi4in_axi_arqos), - .s_axi_arvalid(axi4in_axi_arvalid), - .s_axi_arready(axi4in_axi_arready), - .s_axi_rdata(axi4in_axi_rdata), - .s_axi_rresp(axi4in_axi_rresp), - .s_axi_rlast(axi4in_axi_rlast), - .s_axi_rvalid(axi4in_axi_rvalid), - .s_axi_rready(axi4in_axi_rready), - - // AXI4Lite Out - .m_axi_awaddr(SDCin_axi_awaddr), - .m_axi_awprot(SDCin_axi_awprot), - .m_axi_awvalid(SDCin_axi_awvalid), - .m_axi_awready(SDCin_axi_awready), - .m_axi_wdata(SDCin_axi_wdata), - .m_axi_wstrb(SDCin_axi_wstrb), - .m_axi_wvalid(SDCin_axi_wvalid), - .m_axi_wready(SDCin_axi_wready), - .m_axi_bresp(SDCin_axi_bresp), - .m_axi_bvalid(SDCin_axi_bvalid), - .m_axi_bready(SDCin_axi_bready), - .m_axi_araddr(SDCin_axi_araddr), - .m_axi_arprot(SDCin_axi_arprot), - .m_axi_arvalid(SDCin_axi_arvalid), - .m_axi_arready(SDCin_axi_arready), - .m_axi_rdata(SDCin_axi_rdata), - .m_axi_rresp(SDCin_axi_rresp), - .m_axi_rvalid(SDCin_axi_rvalid), - .m_axi_rready(SDCin_axi_rready) - - ); - - - sdc_controller axiSDC - (.clock(CPUCLK), - .async_resetn(peripheral_aresetn), - - // Slave Interface - .s_axi_awaddr({8'b0, SDCin_axi_awaddr[7:0]}), - .s_axi_awvalid(SDCin_axi_awvalid), - .s_axi_awready(SDCin_axi_awready), - .s_axi_wdata(SDCin_axi_wdata), - .s_axi_wvalid(SDCin_axi_wvalid), - .s_axi_wready(SDCin_axi_wready), - .s_axi_bresp(SDCin_axi_bresp), - .s_axi_bvalid(SDCin_axi_bvalid), - .s_axi_bready(SDCin_axi_bready), - .s_axi_araddr({8'b0, SDCin_axi_araddr[7:0]}), - .s_axi_arvalid(SDCin_axi_arvalid), - .s_axi_arready(SDCin_axi_arready), - .s_axi_rdata(SDCin_axi_rdata), - .s_axi_rresp(SDCin_axi_rresp), - .s_axi_rvalid(SDCin_axi_rvalid), - .s_axi_rready(SDCin_axi_rready), - .sdio_reset(sdio_reset_open), - - // Master Interface - .m_axi_awaddr(SDCout_axi_awaddr), - .m_axi_awlen(SDCout_axi_awlen), - .m_axi_awvalid(SDCout_axi_awvalid), - .m_axi_awready(SDCout_axi_awready), - .m_axi_wdata(SDCout_axi_wdata), - .m_axi_wlast(SDCout_axi_wlast), - .m_axi_wvalid(SDCout_axi_wvalid), - .m_axi_wready(SDCout_axi_wready), - .m_axi_bresp(SDCout_axi_bresp), - .m_axi_bvalid(SDCout_axi_bvalid), - .m_axi_bready(SDCout_axi_bready), - .m_axi_araddr(SDCout_axi_araddr), - .m_axi_arlen(SDCout_axi_arlen), - .m_axi_arvalid(SDCout_axi_arvalid), - .m_axi_arready(SDCout_axi_arready), - .m_axi_rdata(SDCout_axi_rdata), - .m_axi_rlast(SDCout_axi_rlast), - .m_axi_rresp(SDCout_axi_rresp), - .m_axi_rvalid(SDCout_axi_rvalid), - .m_axi_rready(SDCout_axi_rready), - - // SDC interface - //.sdio_cmd(1'b0), - //.sdio_dat(4'b0), - //.sdio_cd(1'b0) - - .sd_dat_reg_t(sd_dat_reg_t), - .sd_dat_reg_o(sd_dat_reg_o), - .sd_dat_i(sd_dat_i), - - .sd_cmd_reg_t(sd_cmd_reg_t), - .sd_cmd_reg_o(sd_cmd_reg_o), - .sd_cmd_i(sd_cmd_i), - - .sdio_clk(SDCCLK), - .sdio_cd(SDCCD), - - .interrupt(SDCIntr) - ); - - xlnx_axi_dwidth_conv_32to64 axi_conv_up - (.s_axi_aclk(CPUCLK), - .s_axi_aresetn(peripheral_aresetn), - - // Slave interface - .s_axi_awaddr(SDCout_axi_awaddr), - .s_axi_awlen(SDCout_axi_awlen), - .s_axi_awsize(3'b010), - .s_axi_awburst(2'b01), - .s_axi_awlock(1'b0), - .s_axi_awcache(4'b0), - .s_axi_awprot(3'b0), - .s_axi_awregion(4'b0), - .s_axi_awqos(4'b0), - .s_axi_awvalid(SDCout_axi_awvalid), - .s_axi_awready(SDCout_axi_awready), - .s_axi_wdata(SDCout_axi_wdata), - .s_axi_wstrb(8'b11111111), - .s_axi_wlast(SDCout_axi_wlast), - .s_axi_wvalid(SDCout_axi_wvalid), - .s_axi_wready(SDCout_axi_wready), - .s_axi_bresp(SDCout_axi_bresp), - .s_axi_bvalid(SDCout_axi_bvalid), - .s_axi_bready(SDCout_axi_bready), - .s_axi_araddr(SDCout_axi_araddr), - .s_axi_arlen(SDCout_axi_arlen), - .s_axi_arsize(3'b010), - .s_axi_arburst(2'b01), - .s_axi_arlock(1'b0), - .s_axi_arcache(4'b0), - .s_axi_arprot(3'b0), - .s_axi_arregion(4'b0), - .s_axi_arqos(4'b0), - .s_axi_arvalid(SDCout_axi_arvalid), - .s_axi_arready(SDCout_axi_arready), - .s_axi_rdata(SDCout_axi_rdata), - .s_axi_rresp(SDCout_axi_rresp), - .s_axi_rlast(SDCout_axi_rlast), - .s_axi_rvalid(SDCout_axi_rvalid), - .s_axi_rready(SDCout_axi_rready), - - // Master interface - .m_axi_awaddr(m01_axi_awaddr), - .m_axi_awlen(m01_axi_awlen), - .m_axi_awsize(m01_axi_awsize), - .m_axi_awburst(m01_axi_awburst), - .m_axi_awlock(m01_axi_awlock), - .m_axi_awcache(m01_axi_awcache), - .m_axi_awprot(m01_axi_awprot), - .m_axi_awregion(m01_axi_awregion), - .m_axi_awqos(m01_axi_awqos), - .m_axi_awvalid(m01_axi_awvalid), - .m_axi_awready(m01_axi_awready), - .m_axi_wdata(m01_axi_wdata), - .m_axi_wstrb(m01_axi_wstrb), - .m_axi_wlast(m01_axi_wlast), - .m_axi_wvalid(m01_axi_wvalid), - .m_axi_wready(m01_axi_wready), - .m_axi_bresp(m01_axi_bresp), - .m_axi_bvalid(m01_axi_bvalid), - .m_axi_bready(m01_axi_bready), - .m_axi_araddr(m01_axi_araddr), - .m_axi_arlen(m01_axi_arlen), - .m_axi_arsize(m01_axi_arsize), - .m_axi_arburst(m01_axi_arburst), - .m_axi_arlock(m01_axi_arlock), - .m_axi_arcache(m01_axi_arcache), - .m_axi_arprot(m01_axi_arprot), - .m_axi_arregion(m01_axi_arregion), - .m_axi_arqos(m01_axi_arqos), - .m_axi_arvalid(m01_axi_arvalid), - .m_axi_arready(m01_axi_arready), - .m_axi_rdata(m01_axi_rdata), - .m_axi_rresp(m01_axi_rresp), - .m_axi_rlast(m01_axi_rlast), - .m_axi_rvalid(m01_axi_rvalid), - .m_axi_rready(m01_axi_rready) - ); - - // End SDC signals -------------------------------------------- - + // AXI Clock Converter xlnx_axi_clock_converter xlnx_axi_clock_converter_0 (.s_axi_aclk(CPUCLK), .s_axi_aresetn(peripheral_aresetn), - .s_axi_awid(s00_axi_awid), - .s_axi_awlen(s00_axi_awlen), - .s_axi_awsize(s00_axi_awsize), - .s_axi_awburst(s00_axi_awburst), - .s_axi_awcache(s00_axi_awcache), - .s_axi_awaddr(s00_axi_awaddr[30:0] ), - .s_axi_awprot(s00_axi_awprot), + .s_axi_awid(m_axi_awid), + .s_axi_awlen(m_axi_awlen), + .s_axi_awsize(m_axi_awsize), + .s_axi_awburst(m_axi_awburst), + .s_axi_awcache(m_axi_awcache), + .s_axi_awaddr(m_axi_awaddr[30:0] ), + .s_axi_awprot(m_axi_awprot), .s_axi_awregion(4'b0), // this could be a bug. bridge does not have these outputs .s_axi_awqos(4'b0), // this could be a bug. bridge does not have these outputs - .s_axi_awvalid(s00_axi_awvalid), - .s_axi_awready(s00_axi_awready), - .s_axi_awlock(s00_axi_awlock), - .s_axi_wdata(s00_axi_wdata), - .s_axi_wstrb(s00_axi_wstrb), - .s_axi_wlast(s00_axi_wlast), - .s_axi_wvalid(s00_axi_wvalid), - .s_axi_wready(s00_axi_wready), - .s_axi_bid(s00_axi_bid), - .s_axi_bresp(s00_axi_bresp), - .s_axi_bvalid(s00_axi_bvalid), - .s_axi_bready(s00_axi_bready), - .s_axi_arid(s00_axi_arid), - .s_axi_arlen(s00_axi_arlen), - .s_axi_arsize(s00_axi_arsize), - .s_axi_arburst(s00_axi_arburst), - .s_axi_arprot(s00_axi_arprot), + .s_axi_awvalid(m_axi_awvalid), + .s_axi_awready(m_axi_awready), + .s_axi_awlock(m_axi_awlock), + .s_axi_wdata(m_axi_wdata), + .s_axi_wstrb(m_axi_wstrb), + .s_axi_wlast(m_axi_wlast), + .s_axi_wvalid(m_axi_wvalid), + .s_axi_wready(m_axi_wready), + .s_axi_bid(m_axi_bid), + .s_axi_bresp(m_axi_bresp), + .s_axi_bvalid(m_axi_bvalid), + .s_axi_bready(m_axi_bready), + .s_axi_arid(m_axi_arid), + .s_axi_arlen(m_axi_arlen), + .s_axi_arsize(m_axi_arsize), + .s_axi_arburst(m_axi_arburst), + .s_axi_arprot(m_axi_arprot), .s_axi_arregion(4'b0), // this could be a bug. bridge does not have these outputs .s_axi_arqos(4'b0), // this could be a bug. bridge does not have these outputs - .s_axi_arcache(s00_axi_arcache), - .s_axi_arvalid(s00_axi_arvalid), - .s_axi_araddr(s00_axi_araddr[30:0]), - .s_axi_arlock(s00_axi_arlock), - .s_axi_arready(s00_axi_arready), - .s_axi_rid(s00_axi_rid), - .s_axi_rdata(s00_axi_rdata), - .s_axi_rresp(s00_axi_rresp), - .s_axi_rvalid(s00_axi_rvalid), - .s_axi_rlast(s00_axi_rlast), - .s_axi_rready(s00_axi_rready), + .s_axi_arcache(m_axi_arcache), + .s_axi_arvalid(m_axi_arvalid), + .s_axi_araddr(m_axi_araddr[30:0]), + .s_axi_arlock(m_axi_arlock), + .s_axi_arready(m_axi_arready), + .s_axi_rid(m_axi_rid), + .s_axi_rdata(m_axi_rdata), + .s_axi_rresp(m_axi_rresp), + .s_axi_rvalid(m_axi_rvalid), + .s_axi_rlast(m_axi_rlast), + .s_axi_rready(m_axi_rready), .m_axi_aclk(BUSCLK), .m_axi_aresetn(resetn), @@ -1037,6 +399,7 @@ module fpgaTop #(parameter logic RVVI_SYNTH_SUPPORTED = 1) .m_axi_rlast(BUS_axi_rlast), .m_axi_rready(BUS_axi_rready)); + // DDR3 Controller xlnx_ddr3 xlnx_ddr3_c0 ( // ddr3 I/O diff --git a/fpga/zsbl/Makefile b/fpga/zsbl/Makefile index 37323b813..85bfc67eb 100644 --- a/fpga/zsbl/Makefile +++ b/fpga/zsbl/Makefile @@ -17,6 +17,7 @@ OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(OBJECTS)) TARGETDIR := bin TARGET := $(TARGETDIR)/boot +MEMFILES := $(TARGETDIR/boot.mem $(TARGETDIR)/data.mem ROOT := .. LIBRARY_DIRS := LIBRARY_FILES := @@ -37,7 +38,7 @@ AR=riscv64-unknown-elf-ar #Default Make -all: directories $(TARGET).memfile +all: directories $(TARGET).memfile #Remake remake: clean all @@ -48,7 +49,7 @@ directories: @mkdir -p $(BUILDDIR) clean: - rm -rf $(BUILDDIR) $(TARGETDIR) *.memfile *.objdump + rm -rf $(BUILDDIR) $(TARGETDIR) *.memfile *.objdump boot.mem data.mem #Needed for building additional library projects @@ -112,3 +113,7 @@ $(TARGET).memfile: $(TARGET) extractFunctionRadix.sh $<.objdump mkdir -p ../../imperas-riscv-tests/work/rv64BP/ cp -f $(TARGETDIR)/* ../../imperas-riscv-tests/work/rv64BP/ + @echo 'Splitting memfile.' + ./splitfile.sh $@ + mv boot.mem ../src/boot.mem + mv data.mem ../src/data.mem diff --git a/fpga/zsbl/boot.c b/fpga/zsbl/boot.c index 6e4780f55..566393cb6 100644 --- a/fpga/zsbl/boot.c +++ b/fpga/zsbl/boot.c @@ -1,422 +1,146 @@ +/////////////////////////////////////////////////////////////////////// +// boot.c +// +// Written: Jacob Pease jacob.pease@okstate.edu 7/22/2024 +// +// Purpose: Main bootloader entry point +// +// +// +// A component of the Wally configurable RISC-V project. +// +// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University +// +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// Licensed under the Solderpad Hardware License v 2.1 (the +// “License”); you may not use this file except in compliance with the +// License, or, at your option, the Apache License version 2.0. You +// may obtain a copy of the License at +// +// https://solderpad.org/licenses/SHL-2.1/ +// +// Unless required by applicable law or agreed to in writing, any work +// distributed under the License is distributed on an “AS IS” BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +// implied. See the License for the specific language governing +// permissions and limitations under the License. +/////////////////////////////////////////////////////////////////////// + #include #include "boot.h" #include "gpt.h" +#include "uart.h" +#include "spi.h" +#include "sd.h" +#include "time.h" +#include "riscv.h" +#include "fail.h" -/* Card type flags (card_type) */ -#define CT_MMC 0x01 /* MMC ver 3 */ -#define CT_SD1 0x02 /* SD ver 1 */ -#define CT_SD2 0x04 /* SD ver 2 */ -#define CT_SDC (CT_SD1|CT_SD2) /* SD */ -#define CT_BLOCK 0x08 /* Block addressing */ +int disk_read(BYTE * buf, LBA_t sector, UINT count) { + uint64_t r; + UINT i; + volatile uint8_t *p = buf; -#define CMD0 (0) /* GO_IDLE_STATE */ -#define CMD1 (1) /* SEND_OP_COND */ -#define CMD2 (2) /* SEND_CID */ -#define CMD3 (3) /* RELATIVE_ADDR */ -#define CMD4 (4) -#define CMD5 (5) /* SLEEP_WAKE (SDC) */ -#define CMD6 (6) /* SWITCH_FUNC */ -#define CMD7 (7) /* SELECT */ -#define CMD8 (8) /* SEND_IF_COND */ -#define CMD9 (9) /* SEND_CSD */ -#define CMD10 (10) /* SEND_CID */ -#define CMD11 (11) -#define CMD12 (12) /* STOP_TRANSMISSION */ -#define CMD13 (13) -#define CMD15 (15) -#define CMD16 (16) /* SET_BLOCKLEN */ -#define CMD17 (17) /* READ_SINGLE_BLOCK */ -#define CMD18 (18) /* READ_MULTIPLE_BLOCK */ -#define CMD19 (19) -#define CMD20 (20) -#define CMD23 (23) -#define CMD24 (24) -#define CMD25 (25) -#define CMD27 (27) -#define CMD28 (28) -#define CMD29 (29) -#define CMD30 (30) -#define CMD32 (32) -#define CMD33 (33) -#define CMD38 (38) -#define CMD42 (42) -#define CMD55 (55) /* APP_CMD */ -#define CMD56 (56) -#define ACMD6 (0x80+6) /* define the data bus width */ -#define ACMD41 (0x80+41) /* SEND_OP_COND (ACMD) */ + UINT modulus = count/50; -// Capability bits -#define SDC_CAPABILITY_SD_4BIT 0x0001 -#define SDC_CAPABILITY_SD_RESET 0x0002 -#define SDC_CAPABILITY_ADDR 0xff00 - -// Control bits -#define SDC_CONTROL_SD_4BIT 0x0001 -#define SDC_CONTROL_SD_RESET 0x0002 - -// Card detect bits -#define SDC_CARD_INSERT_INT_EN 0x0001 -#define SDC_CARD_INSERT_INT_REQ 0x0002 -#define SDC_CARD_REMOVE_INT_EN 0x0004 -#define SDC_CARD_REMOVE_INT_REQ 0x0008 - -// Command status bits -#define SDC_CMD_INT_STATUS_CC 0x0001 // Command complete -#define SDC_CMD_INT_STATUS_EI 0x0002 // Any error -#define SDC_CMD_INT_STATUS_CTE 0x0004 // Timeout -#define SDC_CMD_INT_STATUS_CCRC 0x0008 // CRC error -#define SDC_CMD_INT_STATUS_CIE 0x0010 // Command code check error - -// Data status bits -#define SDC_DAT_INT_STATUS_TRS 0x0001 // Transfer complete -#define SDC_DAT_INT_STATUS_ERR 0x0002 // Any error -#define SDC_DAT_INT_STATUS_CTE 0x0004 // Timeout -#define SDC_DAT_INT_STATUS_CRC 0x0008 // CRC error -#define SDC_DAT_INT_STATUS_CFE 0x0010 // Data FIFO underrun or overrun - - -#define ERR_EOF 30 -#define ERR_NOT_ELF 31 -#define ERR_ELF_BITS 32 -#define ERR_ELF_ENDIANNESS 33 -#define ERR_CMD_CRC 34 -#define ERR_CMD_CHECK 35 -#define ERR_DATA_CRC 36 -#define ERR_DATA_FIFO 37 -#define ERR_BUF_ALIGNMENT 38 -#define FR_DISK_ERR 39 -#define FR_TIMEOUT 40 - -struct sdc_regs { - volatile uint32_t argument; - volatile uint32_t command; - volatile uint32_t response1; - volatile uint32_t response2; - volatile uint32_t response3; - volatile uint32_t response4; - volatile uint32_t data_timeout; - volatile uint32_t control; - volatile uint32_t cmd_timeout; - volatile uint32_t clock_divider; - volatile uint32_t software_reset; - volatile uint32_t power_control; - volatile uint32_t capability; - volatile uint32_t cmd_int_status; - volatile uint32_t cmd_int_enable; - volatile uint32_t dat_int_status; - volatile uint32_t dat_int_enable; - volatile uint32_t block_size; - volatile uint32_t block_count; - volatile uint32_t card_detect; - volatile uint32_t res_50; - volatile uint32_t res_54; - volatile uint32_t res_58; - volatile uint32_t res_5c; - volatile uint64_t dma_addres; -}; - -#define MAX_BLOCK_CNT 0x1000 - -#define SDC 0x00013000; - -// static struct sdc_regs * const regs __attribute__((section(".rodata"))) = (struct sdc_regs *)0x00013000; - -// static int errno __attribute__((section(".bss"))); -// static DSTATUS drv_status __attribute__((section(".bss"))); -// static BYTE card_type __attribute__((section(".bss"))); -// static uint32_t response[4] __attribute__((section(".bss"))); -// static int alt_mem __attribute__((section(".bss"))); - -/*static const char * errno_to_str(void) { - switch (errno) { - case ERR_EOF: return "Unexpected EOF"; - case ERR_NOT_ELF: return "Not an ELF file"; - case ERR_ELF_BITS: return "Wrong ELF word size"; - case ERR_ELF_ENDIANNESS: return "Wrong ELF endianness"; - case ERR_CMD_CRC: return "Command CRC error"; - case ERR_CMD_CHECK: return "Command code check error"; - case ERR_DATA_CRC: return "Data CRC error"; - case ERR_DATA_FIFO: return "Data FIFO error"; - case ERR_BUF_ALIGNMENT: return "Bad buffer alignment"; - case FR_DISK_ERR: return "Disk error"; - case FR_TIMEOUT: return "Timeout"; - } - return "Unknown error code"; - }*/ - -static void usleep(unsigned us) { - uintptr_t cycles0; - uintptr_t cycles1; - asm volatile ("csrr %0, 0xB00" : "=r" (cycles0)); - for (;;) { - asm volatile ("csrr %0, 0xB00" : "=r" (cycles1)); - if (cycles1 - cycles0 >= us * 100) break; - } -} - -static int sdc_cmd_finish(unsigned cmd, uint32_t * response) { - struct sdc_regs * regs = (struct sdc_regs *)SDC; + uint8_t crc = 0; + crc = crc7(crc, 0x40 | SD_CMD_READ_BLOCK_MULTIPLE); + crc = crc7(crc, (sector >> 24) & 0xff); + crc = crc7(crc, (sector >> 16) & 0xff); + crc = crc7(crc, (sector >> 8) & 0xff); + crc = crc7(crc, sector & 0xff); + crc = crc | 1; - while (1) { - unsigned status = regs->cmd_int_status; - if (status) { - // clear interrupts - regs->cmd_int_status = 0; - while (regs->software_reset != 0) {} - if (status == SDC_CMD_INT_STATUS_CC) { - // get response - response[0] = regs->response1; - response[1] = regs->response2; - response[2] = regs->response3; - response[3] = regs->response4; - return 0; - } - /* errno = FR_DISK_ERR; - if (status & SDC_CMD_INT_STATUS_CTE) errno = FR_TIMEOUT; - if (status & SDC_CMD_INT_STATUS_CCRC) errno = ERR_CMD_CRC; - if (status & SDC_CMD_INT_STATUS_CIE) errno = ERR_CMD_CHECK;*/ - break; - } - } - return -1; -} + if ((r = sd_cmd(18, sector & 0xffffffff, crc) & 0xff) != 0x00) { + print_uart("disk_read: CMD18 failed. r = 0x"); + print_uart_byte(r); + print_uart("\r\n"); + fail(); + // return -1; + } -static int sdc_data_finish(void) { - int status; - struct sdc_regs * regs = (struct sdc_regs *)SDC; + print_uart("\r Blocks loaded: "); + print_uart("0"); + print_uart("/"); + print_uart_dec(count); + // write_reg(SPI_CSMODE, SIFIVE_SPI_CSMODE_MODE_HOLD); + // Begin reading blocks + for (i = 0; i < count; i++) { + uint16_t crc, crc_exp; + uint64_t n = 0; + + // Wait for data token + while((r = spi_dummy()) != SD_DATA_TOKEN); + // println_with_byte("Received data token: 0x", r & 0xff); + + // println_with_dec("Block ", i); + // Read block into memory. + /* for (int j = 0; j < 64; j++) { */ + /* *buf = sd_read64(&crc); */ + /* println_with_addr("0x", *buf); */ + /* buf = buf + 64; */ + /* } */ + crc = 0; + n = 512; + do { + uint8_t x = spi_dummy(); + *p++ = x; + crc = crc16(crc, x); + } while (--n > 0); - while ((status = regs->dat_int_status) == 0) {} - regs->dat_int_status = 0; - while (regs->software_reset != 0) {} + // Read CRC16 and check + crc_exp = ((uint16_t)spi_dummy() << 8); + crc_exp |= spi_dummy(); - if (status == SDC_DAT_INT_STATUS_TRS) return 0; - /* errno = FR_DISK_ERR; - if (status & SDC_DAT_INT_STATUS_CTE) errno = FR_TIMEOUT; - if (status & SDC_DAT_INT_STATUS_CRC) errno = ERR_DATA_CRC; - if (status & SDC_DAT_INT_STATUS_CFE) errno = ERR_DATA_FIFO;*/ - return -1; -} - -static int send_data_cmd(unsigned cmd, unsigned arg, void * buf, unsigned blocks, uint32_t * response) { - struct sdc_regs * regs = (struct sdc_regs *)SDC; - - unsigned command = (cmd & 0x3f) << 8; - switch (cmd) { - case CMD0: - case CMD4: - case CMD15: - // No responce - break; - case CMD11: - case CMD13: - case CMD16: - case CMD17: - case CMD18: - case CMD19: - case CMD23: - case CMD24: - case CMD25: - case CMD27: - case CMD30: - case CMD32: - case CMD33: - case CMD42: - case CMD55: - case CMD56: - case ACMD6: - // R1 - command |= 1; // 48 bits - command |= 1 << 3; // resp CRC - command |= 1 << 4; // resp OPCODE - break; - case CMD7: - case CMD12: - case CMD20: - case CMD28: - case CMD29: - case CMD38: - // R1b - command |= 1; // 48 bits - command |= 1 << 2; // busy - command |= 1 << 3; // resp CRC - command |= 1 << 4; // resp OPCODE - break; - case CMD2: - case CMD9: - case CMD10: - // R2 - command |= 2; // 136 bits - command |= 1 << 3; // resp CRC - break; - case ACMD41: - // R3 - command |= 1; // 48 bits - break; - case CMD3: - // R6 - command |= 1; // 48 bits - command |= 1 << 2; // busy - command |= 1 << 3; // resp CRC - command |= 1 << 4; // resp OPCODE - break; - case CMD8: - // R7 - command |= 1; // 48 bits - command |= 1 << 3; // resp CRC - command |= 1 << 4; // resp OPCODE - break; + if (crc != crc_exp) { + print_uart("Stinking CRC16 didn't match on block read.\r\n"); + print_uart_int(i); + print_uart("\r\n"); + //return -1; + fail(); } - if (blocks) { - command |= 1 << 5; - if ((intptr_t)buf & 3) { - // errno = ERR_BUF_ALIGNMENT; - return -1; - } - regs->dma_addres = (uint64_t)(intptr_t)buf; - regs->block_size = 511; - regs->block_count = blocks - 1; - regs->data_timeout = 0x1FFFFFF; + if ( (i % modulus) == 0 ) { + print_uart("\r Blocks loaded: "); + print_uart_dec(i); + print_uart("/"); + print_uart_dec(count); } - regs->command = command; - regs->cmd_timeout = 0xFFFFF; - regs->argument = arg; + } - if (sdc_cmd_finish(cmd, response) < 0) return -1; - if (blocks) return sdc_data_finish(); + sd_cmd(SD_CMD_STOP_TRANSMISSION, 0, 0x01); - return 0; -} - -#define send_cmd(cmd, arg, response) send_data_cmd(cmd, arg, NULL, 0, response) - -static BYTE ini_sd(void) { - struct sdc_regs * regs = (struct sdc_regs *)SDC; - unsigned rca; - BYTE card_type; - uint32_t response[4]; - - /* Reset controller */ - regs->software_reset = 1; - while ((regs->software_reset & 1) == 0) {} - - // This clock divider is meant to initialize the card at - // 400kHz - - // 22MHz/400kHz = 55 (base 10) = 0x37 - 0x01 = 0x36 - regs->clock_divider = 0x36; - regs->software_reset = 0; - while (regs->software_reset) {} - usleep(5000); - - card_type = 0; - // drv_status = STA_NOINIT; - - if (regs->capability & SDC_CAPABILITY_SD_RESET) { - /* Power cycle SD card */ - regs->control |= SDC_CONTROL_SD_RESET; - usleep(1000000); - regs->control &= ~SDC_CONTROL_SD_RESET; - usleep(100000); - } - - /* Enter Idle state */ - send_cmd(CMD0, 0, response); - - card_type = CT_SD1; - if (send_cmd(CMD8, 0x1AA, response) == 0) { - if ((response[0] & 0xfff) != 0x1AA) { - // errno = ERR_CMD_CHECK; - return -1; - } - card_type = CT_SD2; - } - - /* Wait for leaving idle state (ACMD41 with HCS bit) */ - while (1) { - /* ACMD41, Set Operating Conditions: Host High Capacity & 3.3V */ - if (send_cmd(CMD55, 0, response) < 0 || send_cmd(ACMD41, 0x40300000, response) < 0) return -1; - if (response[0] & (1 << 31)) { - if (response[0] & (1 << 30)) card_type |= CT_BLOCK; - break; - } - } - - /* Enter Identification state */ - if (send_cmd(CMD2, 0, response) < 0) return -1; - - /* Get RCA (Relative Card Address) */ - rca = 0x1234; - if (send_cmd(CMD3, rca << 16, response) < 0) return -1; - rca = response[0] >> 16; - - /* Select card */ - if (send_cmd(CMD7, rca << 16, response) < 0) return -1; - - /* Clock 25MHz */ - // 22Mhz/2 = 11Mhz - regs->clock_divider = 1; - usleep(10000); - - /* Bus width 1-bit */ - regs->control = 0; - if (send_cmd(CMD55, rca << 16, response) < 0 || send_cmd(ACMD6, 0, response) < 0) return -1; - - /* Set R/W block length to 512 */ - if (send_cmd(CMD16, 512, response) < 0) return -1; - - // drv_status &= ~STA_NOINIT; - return card_type; -} - -int disk_read(BYTE * buf, LBA_t sector, UINT count, BYTE card_type) { - - /* This is not needed. This has everything to do with the FAT - filesystem stuff that I'm not including. All I need to do is - initialize the SD card and read from it. Anything in here that is - checking for potential errors, I'm going to have to temporarily - do without. - */ - // if (!count) return RES_PARERR; - /* if (drv_status & STA_NOINIT) return RES_NOTRDY; */ - - uint32_t response[4]; - struct sdc_regs * regs = (struct sdc_regs *)SDC; - - /* Convert LBA to byte address if needed */ - if (!(card_type & CT_BLOCK)) sector *= 512; - while (count > 0) { - UINT bcnt = count > MAX_BLOCK_CNT ? MAX_BLOCK_CNT : count; - unsigned bytes = bcnt * 512; - if (send_data_cmd(bcnt == 1 ? CMD17 : CMD18, sector, buf, bcnt, response) < 0) return 1; - if (bcnt > 1 && send_cmd(CMD12, 0, response) < 0) return 1; - sector += (card_type & CT_BLOCK) ? bcnt : bytes; - count -= bcnt; - buf += bytes; - } - - return 0;; -} - -void copyFlash(QWORD address, QWORD * Dst, DWORD numBlocks) { - BYTE card_type; - int ret = 0; - - card_type = ini_sd(); - - // BYTE * buf = (BYTE *)Dst; - - // if (disk_read(buf, (LBA_t)address, (UINT)numBlocks, card_type) < 0) /* UART Print function?*/; - - ret = gpt_load_partitions(card_type); -} - -/* -int main() { - ini_sd(); - - + print_uart("\r Blocks loaded: "); + print_uart_dec(count); + print_uart("/"); + print_uart_dec(count); + // write_reg(SPI_CSMODE, SIFIVE_SPI_CSMODE_MODE_AUTO); + //spi_txrx(0xff); + print_uart("\r\n"); return 0; } -*/ + +// copyFlash: -------------------------------------------------------- +// A lot happens in this function: +// * The Wally banner is printed +// * The peripherals are initialized +void copyFlash(QWORD address, QWORD * Dst, DWORD numBlocks) { + int ret = 0; + + // Initialize UART for messages + init_uart(20000000, 115200); + + // Print the wally banner + print_uart(BANNER); + + /* print_uart("System clock speed: "); */ + /* print_uart_dec(SYSTEMCLOCK); */ + /* print_uart("\r\n"); */ + + // Intialize the SD card + init_sd(SYSTEMCLOCK, 5000000); + + ret = gpt_load_partitions(); +} diff --git a/fpga/zsbl/boot.h b/fpga/zsbl/boot.h index 77d403145..0c09a1e52 100644 --- a/fpga/zsbl/boot.h +++ b/fpga/zsbl/boot.h @@ -1,3 +1,32 @@ +/////////////////////////////////////////////////////////////////////// +// boot.h +// +// Written: Jaocb Pease jacob.pease@okstate.edu 7/22/2024 +// +// Purpose: Header for boot.c, main bootloader entry point +// +// +// +// A component of the Wally configurable RISC-V project. +// +// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University +// +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// Licensed under the Solderpad Hardware License v 2.1 (the +// “License”); you may not use this file except in compliance with the +// License, or, at your option, the Apache License version 2.0. You +// may obtain a copy of the License at +// +// https://solderpad.org/licenses/SHL-2.1/ +// +// Unless required by applicable law or agreed to in writing, any work +// distributed under the License is distributed on an “AS IS” BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +// implied. See the License for the specific language governing +// permissions and limitations under the License. +/////////////////////////////////////////////////////////////////////// + #ifndef WALLYBOOT #define WALLYBOOT 10000 @@ -19,8 +48,20 @@ typedef QWORD LBA_t; #define OPENSBI_ADDRESS 0x80000000 // FW_TEXT_START #define KERNEL_ADDRESS 0x80200000 // FW_JUMP_ADDR +#define BANNER " █▀█ █▀█ █▀█ █▀▀ █ █\r\n" \ +" █ █ █ █▄▀ █▄▄ ▄▄▄ █ █\r\n" \ +" █▄█ █▄█ █ █ █▄▄ ▀▄▀\r\n" \ +" ____ ____ ____ ___ ___ ____ ___\r\n" \ +" \\ \\ / / / \\ | | | | \\ \\ / /\r\n" \ +" \\ \\ __ / / / \\ | | | | \\ \\/ /\r\n" \ +" \\ \\/ \\/ / / /\\ \\ | | | | \\ /\r\n" \ +" \\ / / ____ \\ | |___ | |___ | |\r\n" \ +" \\___/\\___/ /___/ \\___\\|_______||_______| |___|\r\n\r\n" + // Export disk_read -int disk_read(BYTE * buf, LBA_t sector, UINT count, BYTE card_type); +int disk_read(BYTE * buf, LBA_t sector, UINT count); + +#define SYSTEMCLOCK 20000000 #endif // WALLYBOOT diff --git a/fpga/zsbl/fail.c b/fpga/zsbl/fail.c new file mode 100644 index 000000000..4430c4a8f --- /dev/null +++ b/fpga/zsbl/fail.c @@ -0,0 +1,49 @@ +/////////////////////////////////////////////////////////////////////// +// fail.c +// +// Written: Jaocb Pease jacob.pease@okstate.edu 7/22/2024 +// +// Purpose: Prints information on the uart when a fatal bug is +// encountered. Will expand this later. +// +// +// +// A component of the Wally configurable RISC-V project. +// +// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University +// +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// Licensed under the Solderpad Hardware License v 2.1 (the +// “License”); you may not use this file except in compliance with the +// License, or, at your option, the Apache License version 2.0. You +// may obtain a copy of the License at +// +// https://solderpad.org/licenses/SHL-2.1/ +// +// Unless required by applicable law or agreed to in writing, any work +// distributed under the License is distributed on an “AS IS” BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +// implied. See the License for the specific language governing +// permissions and limitations under the License. +/////////////////////////////////////////////////////////////////////// + +#include "fail.h" +#include "uart.h" +#include "riscv.h" +#include "time.h" + +void fail() { + // Get address that led to failure + register uint64_t addr; + asm volatile ("mv %0, ra" : "=r"(addr) : : "memory"); + + // Print message + print_time(); + println_with_addr("Failed at: 0x", addr); + + // Loop forever + while(1) { + + } +} diff --git a/fpga/zsbl/fail.h b/fpga/zsbl/fail.h new file mode 100644 index 000000000..c965265d1 --- /dev/null +++ b/fpga/zsbl/fail.h @@ -0,0 +1,33 @@ +/////////////////////////////////////////////////////////////////////// +// fail.h +// +// Written: Jaocb Pease jacob.pease@okstate.edu 7/22/2024 +// +// Purpose: Function prototype for fail, +// +// +// +// A component of the Wally configurable RISC-V project. +// +// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University +// +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// Licensed under the Solderpad Hardware License v 2.1 (the +// “License”); you may not use this file except in compliance with the +// License, or, at your option, the Apache License version 2.0. You +// may obtain a copy of the License at +// +// https://solderpad.org/licenses/SHL-2.1/ +// +// Unless required by applicable law or agreed to in writing, any work +// distributed under the License is distributed on an “AS IS” BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +// implied. See the License for the specific language governing +// permissions and limitations under the License. +/////////////////////////////////////////////////////////////////////// + +#pragma once +#include + +void fail(); diff --git a/fpga/zsbl/gpt.c b/fpga/zsbl/gpt.c index 97e3e4e46..e21176f05 100644 --- a/fpga/zsbl/gpt.c +++ b/fpga/zsbl/gpt.c @@ -1,19 +1,38 @@ +/////////////////////////////////////////////////////////////////////// +// gpt.c +// +// Written: Jaocb Pease jacob.pease@okstate.edu 7/22/2024 +// +// Purpose: Code to read GPT Partitions off of an SD card. +// +// +// +// A component of the Wally configurable RISC-V project. +// +// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University +// +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// Licensed under the Solderpad Hardware License v 2.1 (the +// “License”); you may not use this file except in compliance with the +// License, or, at your option, the Apache License version 2.0. You +// may obtain a copy of the License at +// +// https://solderpad.org/licenses/SHL-2.1/ +// +// Unless required by applicable law or agreed to in writing, any work +// distributed under the License is distributed on an “AS IS” BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +// implied. See the License for the specific language governing +// permissions and limitations under the License. +/////////////////////////////////////////////////////////////////////// + #include "gpt.h" #include "boot.h" +#include "uart.h" #include -/* PSUEDOCODE - - Need to load GPT LBA 1 and read through the partition entries. - I need to find each of the relevant partition entries, possibly - by their partition names. - -*/ - -int gpt_load_partitions(BYTE card_type) { - // In this version of the GPT partition code - // I'm going to assume that the SD card is already initialized. - +int gpt_load_partitions() { // size_t block_size = 512/8; // long int lba1_buf[block_size]; @@ -21,26 +40,51 @@ int gpt_load_partitions(BYTE card_type) { int ret = 0; //ret = disk_read(/* BYTE * buf, LBA_t sector, UINT count, BYTE card_type */); - ret = disk_read(lba1_buf, 1, 1, card_type); - - /* Possible error handling with UART message - if ( ret != 0 ) { - - }*/ + print_time(); + println("Getting GPT information."); + ret = disk_read(lba1_buf, 1, 1); gpt_pth_t *lba1 = (gpt_pth_t *)lba1_buf; + print_time(); + println("Getting partition entries."); BYTE lba2_buf[512]; - ret = disk_read(lba2_buf, (LBA_t)lba1->partition_entries_lba, 1, card_type); + ret = disk_read(lba2_buf, (LBA_t)lba1->partition_entries_lba, 1); // Load parition entries for the relevant boot partitions. partition_entries_t *fdt = (partition_entries_t *)(lba2_buf); partition_entries_t *opensbi = (partition_entries_t *)(lba2_buf + 128); partition_entries_t *kernel = (partition_entries_t *)(lba2_buf + 256); - ret = disk_read((BYTE *)FDT_ADDRESS, fdt->first_lba, fdt->last_lba - fdt->first_lba + 1, card_type); - ret = disk_read((BYTE *)OPENSBI_ADDRESS, opensbi->first_lba, opensbi->last_lba - opensbi->first_lba + 1, card_type); - ret = disk_read((BYTE *)KERNEL_ADDRESS, kernel->first_lba,kernel->last_lba - kernel->first_lba + 1, card_type); + // Load device tree + print_time(); + println_with_int("Loading device tree at: 0x", FDT_ADDRESS); + ret = disk_read((BYTE *)FDT_ADDRESS, fdt->first_lba, fdt->last_lba - fdt->first_lba + 1); + if (ret < 0) { + print_uart("Failed to load device tree!\r\n"); + return -1; + } + + // Load OpenSBI + print_time(); + println_with_int("Loading OpenSBI at: 0x", OPENSBI_ADDRESS); + ret = disk_read((BYTE *)OPENSBI_ADDRESS, opensbi->first_lba, opensbi->last_lba - opensbi->first_lba + 1); + if (ret < 0) { + print_uart("Failed to load OpenSBI!\r\n"); + return -1; + } + + // Load Linux + print_time(); + println_with_int("Loading Linux Kernel at: 0x", KERNEL_ADDRESS); + ret = disk_read((BYTE *)KERNEL_ADDRESS, kernel->first_lba,kernel->last_lba - kernel->first_lba + 1); + if (ret < 0) { + print_uart("Failed to load Linux!\r\n"); + return -1; + } + + print_time(); + println("Done! Flashing LEDs and jumping to OpenSBI..."); return 0; } diff --git a/fpga/zsbl/gpt.h b/fpga/zsbl/gpt.h index 4aefae229..8cd3ecc11 100644 --- a/fpga/zsbl/gpt.h +++ b/fpga/zsbl/gpt.h @@ -1,3 +1,32 @@ +/////////////////////////////////////////////////////////////////////// +// gpt.h +// +// Written: Jaocb Pease jacob.pease@okstate.edu 7/22/2024 +// +// Purpose: Header for gpt.c, contains gpt structs +// +// +// +// A component of the Wally configurable RISC-V project. +// +// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University +// +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// Licensed under the Solderpad Hardware License v 2.1 (the +// “License”); you may not use this file except in compliance with the +// License, or, at your option, the Apache License version 2.0. You +// may obtain a copy of the License at +// +// https://solderpad.org/licenses/SHL-2.1/ +// +// Unless required by applicable law or agreed to in writing, any work +// distributed under the License is distributed on an “AS IS” BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +// implied. See the License for the specific language governing +// permissions and limitations under the License. +/////////////////////////////////////////////////////////////////////// + #pragma once #include @@ -37,4 +66,4 @@ typedef struct partition_entries } partition_entries_t; // Find boot partition and load it to the destination -int gpt_load_partitions(BYTE card_type); +int gpt_load_partitions(); diff --git a/fpga/zsbl/riscv.S b/fpga/zsbl/riscv.S new file mode 100644 index 000000000..b2d86599c --- /dev/null +++ b/fpga/zsbl/riscv.S @@ -0,0 +1,58 @@ +/////////////////////////////////////////////////////////////////////// +// riscv.S +// +// Written: Jaocb Pease jacob.pease@okstate.edu 7/22/2024 +// +// Purpose: Basic utility functions for reading registers +// +// +// +// A component of the Wally configurable RISC-V project. +// +// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University +// +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// Licensed under the Solderpad Hardware License v 2.1 (the +// “License”); you may not use this file except in compliance with the +// License, or, at your option, the Apache License version 2.0. You +// may obtain a copy of the License at +// +// https://solderpad.org/licenses/SHL-2.1/ +// +// Unless required by applicable law or agreed to in writing, any work +// distributed under the License is distributed on an “AS IS” BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +// implied. See the License for the specific language governing +// permissions and limitations under the License. +/////////////////////////////////////////////////////////////////////// + +.section .text +.globl read_mcycle +.type read_mcycle, @function +read_mcycle: + csrr a0, mcycle + ret + +.section .text +.globl get_ra +.type get_ra, @function +get_ra: + mv a0, ra + ret + +.section .text +.globl set_status_fs +.type set_status_fs, @function +set_status_fs: + lui t1, 0x6 + csrs mstatus, t1 + ret + +.section .text +.globl clear_status_fs +.type clear_status_fs, @function +clear_status_fs: + lui t1, 0x6 + csrc mstatus, t1 + ret diff --git a/fpga/zsbl/riscv.h b/fpga/zsbl/riscv.h new file mode 100644 index 000000000..543fe5cde --- /dev/null +++ b/fpga/zsbl/riscv.h @@ -0,0 +1,36 @@ +/////////////////////////////////////////////////////////////////////// +// riscv.h +// +// Written: Jaocb Pease jacob.pease@okstate.edu 7/22/2024 +// +// Purpose: Function prototypes for riscv utility functions +// +// +// +// A component of the Wally configurable RISC-V project. +// +// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University +// +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// Licensed under the Solderpad Hardware License v 2.1 (the +// “License”); you may not use this file except in compliance with the +// License, or, at your option, the Apache License version 2.0. You +// may obtain a copy of the License at +// +// https://solderpad.org/licenses/SHL-2.1/ +// +// Unless required by applicable law or agreed to in writing, any work +// distributed under the License is distributed on an “AS IS” BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +// implied. See the License for the specific language governing +// permissions and limitations under the License. +/////////////////////////////////////////////////////////////////////// + +#pragma once +#include + +uint64_t read_mcycle(); +uint64_t get_ra(); +void set_status_fs(); +void clear_status_fs(); diff --git a/fpga/zsbl/sd.c b/fpga/zsbl/sd.c new file mode 100644 index 000000000..1f95d8477 --- /dev/null +++ b/fpga/zsbl/sd.c @@ -0,0 +1,255 @@ +/////////////////////////////////////////////////////////////////////// +// sd.c +// +// Written: Jaocb Pease jacob.pease@okstate.edu 7/22/2024 +// +// Purpose: SD Card protocol functions +// +// +// +// A component of the Wally configurable RISC-V project. +// +// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University +// +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// Licensed under the Solderpad Hardware License v 2.1 (the +// “License”); you may not use this file except in compliance with the +// License, or, at your option, the Apache License version 2.0. You +// may obtain a copy of the License at +// +// https://solderpad.org/licenses/SHL-2.1/ +// +// Unless required by applicable law or agreed to in writing, any work +// distributed under the License is distributed on an “AS IS” BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +// implied. See the License for the specific language governing +// permissions and limitations under the License. +/////////////////////////////////////////////////////////////////////// + +#include "sd.h" +#include "spi.h" +#include "uart.h" +#include "fail.h" +#include "time.h" + +// Parallel byte update CRC7-CCITT algorithm. +// The result is the CRC7 result, left shifted over by 1 +// which is perfect, since we append a 1 at the end anyway +uint8_t crc7(uint8_t prev, uint8_t in) { + // CRC polynomial 0x89 + uint8_t remainder = prev ^ in; + remainder ^= (remainder >> 4) ^ (remainder >> 7); + remainder = (remainder << 1) ^ (remainder << 4); + return remainder & 0xff; +} + +// Need to check this. This could be wrong as well. +uint16_t crc16(uint16_t crc, uint8_t data) { + // CRC polynomial 0x11021 + crc = (uint8_t)(crc >> 8) | (crc << 8); + crc ^= data; + crc ^= (uint8_t)(crc >> 4) & 0xf; + crc ^= crc << 12; + crc ^= (crc & 0xff) << 5; + return crc; +} + +// sd_cmd ------------------------------------------------------------ +// Sends SD card command using SPI mode. +// This function: +// * Chooses the response length based on the input command +// * Makes use of SPI's full duplex. For every byte sent, +// a byte is received. Thus for every byte sent as part of +// a command, a useless byte must be read from the receive +// FIFO. +// * Takes advantage of the Sifive SPI peripheral spec's +// watermark and interrupt features to determine when a +// transfer is complete. This should save on cycles since +// no arbitrary delays need to be added. + +uint64_t sd_cmd(uint8_t cmd, uint32_t arg, uint8_t crc) { + uint8_t response_len; + uint8_t i; + uint8_t shiftAmnt; + uint64_t r; + uint8_t rbyte; + + // Initialize the response with 0's. + r = 0; + + // Choose response length based on cmd input. + // Most commands return an R1 format response. + switch (cmd) { + case 8: + response_len = R7_RESPONSE; + break; + case 12: + response_len = R1B_RESPONSE; + break; + default: + response_len = R1_RESPONSE; + break; + } + + // Make interrupt pending after response fifo receives the correct + // response length. Probably unecessary so let's wait and see what + // happens. + // write_reg(SPI_RXMARK, response_len); + + // Chip select must remain asserted during transaction + if (cmd != SD_CMD_STOP_TRANSMISSION) { + write_reg(SPI_CSMODE, SIFIVE_SPI_CSMODE_MODE_HOLD); + } + + // Write all 7 bytes into transfer fifo + // spi_sendbyte(0xff); + spi_dummy(); + spi_sendbyte(0x40 | cmd); + spi_sendbyte(arg >> 24); + spi_sendbyte(arg >> 16); + spi_sendbyte(arg >> 8); + spi_sendbyte(arg); + spi_sendbyte(crc); + + // Wait for command to send + // The Transfer IP bit should go high when the txFIFO is empty + // while(!(read_reg(SPI_IP) & 1)) {} + waittx(); + + // Read the dummy rxFIFO entries to move the head back to the tail + for (i = 0; i < 7; i++) { + spi_readbyte(); + } + + // Send "dummy signals". Since SPI is duplex, + // useless bytes must be transferred + /* for (i = 0; i < response_len; i++) { */ + /* spi_sendbyte(0xFF); */ + /* } */ + + /* // Wait for transfer fifo again */ + /* waittx(); */ + + // Wait for actual response from SD card + // All responses start with a 0. Output of SDCIn is high, unless + // a message is being transferred. + do { + rbyte = spi_dummy(); + } while ( (rbyte & 0x80) != 0 ); + + // Note about the compiler. In order to compile as sll instead of + // sllw, the number to shift has to be a 64 bit number. + r = ((uint64_t)rbyte) << ((response_len - 1)*8); + + // Read rxfifo response + for (i = 1; i < response_len; i++) { + rbyte = spi_dummy(); + r = r | (((uint64_t)rbyte) << ((response_len - 1 - i)*8)); + } + + if (cmd != 18) { + write_reg(SPI_CSMODE, SIFIVE_SPI_CSMODE_MODE_AUTO); + } else { + spi_dummy(); + } + return r; +} // sd_cmd + +uint64_t sd_read64(uint16_t * crc) { + uint64_t r; + uint8_t rbyte; + int i; + + /* for (i = 0; i < 8; i++) { */ + /* spi_sendbyte(0xFF); */ + /* } */ + + /* waittx(); */ + + for (i = 0; i < 8; i++) { + rbyte = spi_dummy(); + *crc = crc16(*crc, rbyte); + r = r | ((uint64_t)(rbyte) << ((8 - 1 - i)*8)); + } + + return r; +} + +// Utility defines for CMD0, CMD8, CMD55, and ACMD41 +#define CMD0() sd_cmd( 0, 0x00000000, 0x95) // Reset SD card into IDLE state +#define CMD8() sd_cmd( 8, 0x000001aa, 0x87) // +#define CMD55() sd_cmd(55, 0x00000000, 0x65) // +#define ACMD41() sd_cmd(41, 0x40000000, 0x77) // + +// init_sd: ---------------------------------------------------------- +// This first initializes the SPI peripheral then initializes the SD +// card itself. We use the uart to display anything that goes wrong. +int init_sd(uint32_t freq, uint32_t sdclk){ + print_time(); + println("Initializing SPI Controller."); + spi_init(); + + uint64_t r; + uint32_t newClockDiv; + int n; + + print_time(); + println("Initializing SD Card in SPI mode."); + // This is necessary. This is the card's pre-init state initialization. + write_reg(SPI_CSMODE, SIFIVE_SPI_CSMODE_MODE_OFF); + for (int i = 0; i < 10; i++) { + spi_txrx(0xff); + } + write_reg(SPI_CSMODE, SIFIVE_SPI_CSMODE_MODE_AUTO); + + // CMD0 -------------------------------------------------------------- + // Reset SD Card command + // Initializes SD card into SPI mode if CS is asserted '0' + // We expect to get the R1 response 0x01 which means that the + // card has been put into the idle state. + print_time(); + print_uart("CMD0: "); + n = 0; + do { + r = CMD0(); + n++; + if (n == 1000) { + fail(); + } + } while ( r != 0x01 ); + println_with_r1("Success, r = 0x", r & 0xff); + + // CMD8 ------------------------------------------------------------- + // + print_time(); + print_uart("CMD8: "); + r = CMD8(); + if ((r & 0x000000ff0000ffff) != 0x01000001aa) { + println_with_r7("Failed, 0x", r); + fail(); + } + println_with_r7("Success, 0x", r); + + // ACMD41 ----------------------------------------------------------- + print_time(); + print_uart("ACMD41: "); + n = 0; + do { + CMD55(); + r = ACMD41(); + n++; + if (n == 1000) { + fail(); + } + } while (r == 0x1); + println_with_r1("Success, r = 0x", r & 0xff); + + print_time(); + println_with_dec("New clock frequency: ", (uint64_t)sdclk); + spi_set_clock(freq, sdclk); + + print_time(); + println("SD card is initialized."); +} + diff --git a/fpga/zsbl/sd.h b/fpga/zsbl/sd.h new file mode 100644 index 000000000..f66686560 --- /dev/null +++ b/fpga/zsbl/sd.h @@ -0,0 +1,49 @@ +/////////////////////////////////////////////////////////////////////// +// sd.h +// +// Written: Jaocb Pease jacob.pease@okstate.edu 7/22/2024 +// +// Purpose: Header file for SD card protocol functions. Defines some +// useful macros. +// +// +// +// A component of the Wally configurable RISC-V project. +// +// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University +// +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// Licensed under the Solderpad Hardware License v 2.1 (the +// “License”); you may not use this file except in compliance with the +// License, or, at your option, the Apache License version 2.0. You +// may obtain a copy of the License at +// +// https://solderpad.org/licenses/SHL-2.1/ +// +// Unless required by applicable law or agreed to in writing, any work +// distributed under the License is distributed on an “AS IS” BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +// implied. See the License for the specific language governing +// permissions and limitations under the License. +/////////////////////////////////////////////////////////////////////// + +#pragma once + +#include + +// Command names +#define SD_CMD_STOP_TRANSMISSION 12 +#define SD_CMD_READ_BLOCK_MULTIPLE 18 +#define SD_DATA_TOKEN 0xfe + +// Response lengths in bytes +#define R1_RESPONSE 1 +#define R7_RESPONSE 5 +#define R1B_RESPONSE 2 + +uint8_t crc7(uint8_t prev, uint8_t in); +uint16_t crc16(uint16_t crc, uint8_t data); +uint64_t sd_cmd(uint8_t cmd, uint32_t arg, uint8_t crc); +uint64_t sd_read64(uint16_t * crc); +int init_sd(uint32_t freq, uint32_t sdclk); diff --git a/fpga/zsbl/spi.c b/fpga/zsbl/spi.c new file mode 100644 index 000000000..04d609648 --- /dev/null +++ b/fpga/zsbl/spi.c @@ -0,0 +1,91 @@ +/////////////////////////////////////////////////////////////////////// +// spi.c +// +// Written: Jaocb Pease jacob.pease@okstate.edu 7/22/2024 +// +// Purpose: SPI Controller API for bootloader +// +// +// +// A component of the Wally configurable RISC-V project. +// +// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University +// +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// Licensed under the Solderpad Hardware License v 2.1 (the +// “License”); you may not use this file except in compliance with the +// License, or, at your option, the Apache License version 2.0. You +// may obtain a copy of the License at +// +// https://solderpad.org/licenses/SHL-2.1/ +// +// Unless required by applicable law or agreed to in writing, any work +// distributed under the License is distributed on an “AS IS” BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +// implied. See the License for the specific language governing +// permissions and limitations under the License. +/////////////////////////////////////////////////////////////////////// + +#include "spi.h" + +uint8_t spi_txrx(uint8_t byte) { + spi_sendbyte(byte); + waittx(); + return spi_readbyte(); +} + +uint8_t spi_dummy() { + return spi_txrx(0xff); +} + +uint64_t spi_read64() { + uint64_t r; + uint8_t rbyte; + int i; + + for (i = 0; i < 8; i++) { + spi_sendbyte(0xFF); + } + + waittx(); + + for (i = 0; i < 8; i++) { + rbyte = spi_readbyte(); + r = r | (rbyte << ((8 - 1 - i)*8)); + } + + return r; +} + +void spi_set_clock(uint32_t clkin, uint32_t clkout) { + uint32_t div = (clkin/(2*clkout)) - 1; + write_reg(SPI_SCKDIV, div); +} + +// Initialize Sifive FU540 based SPI Controller +void spi_init(uint32_t clkin) { + // Enable interrupts + write_reg(SPI_IE, 0x3); + + // Set TXMARK to 1. If the number of entries is < 1 + // IP's txwm field will go high. + // Set RXMARK to 0. If the number of entries is > 0 + // IP's rwxm field will go high. + write_reg(SPI_TXMARK, 1); + write_reg(SPI_RXMARK, 0); + + // Set Delay 0 to default + write_reg(SPI_DELAY0, + SIFIVE_SPI_DELAY0_CSSCK(1) | + SIFIVE_SPI_DELAY0_SCKCS(1)); + + // Set Delay 1 to default + write_reg(SPI_DELAY1, + SIFIVE_SPI_DELAY1_INTERCS(1) | + SIFIVE_SPI_DELAY1_INTERXFR(0)); + + // Initialize the SPI controller clock to + // div = (20MHz/(2*400kHz)) - 1 = 24 = 0x18 + write_reg(SPI_SCKDIV, 0x18); +} diff --git a/fpga/zsbl/spi.h b/fpga/zsbl/spi.h new file mode 100644 index 000000000..d2bf1191c --- /dev/null +++ b/fpga/zsbl/spi.h @@ -0,0 +1,87 @@ +#pragma once +#ifndef SPI_HEADER +#define SPI_HEADER + +#include + +#define SPI_BASE 0x13000 /* Base address of SPI device used for SDC */ + +/* register offsets */ +#define SPI_SCKDIV SPI_BASE + 0x00 /* Serial clock divisor */ +#define SPI_SCKMODE SPI_BASE + 0x04 /* Serial clock mode */ +#define SPI_CSID SPI_BASE + 0x10 /* Chip select ID */ +#define SPI_CSDEF SPI_BASE + 0x14 /* Chip select default */ +#define SPI_CSMODE SPI_BASE + 0x18 /* Chip select mode */ +#define SPI_DELAY0 SPI_BASE + 0x28 /* Delay control 0 */ +#define SPI_DELAY1 SPI_BASE + 0x2c /* Delay control 1 */ +#define SPI_FMT SPI_BASE + 0x40 /* Frame format */ +#define SPI_TXDATA SPI_BASE + 0x48 /* Tx FIFO data */ +#define SPI_RXDATA SPI_BASE + 0x4c /* Rx FIFO data */ +#define SPI_TXMARK SPI_BASE + 0x50 /* Tx FIFO [<35;39;29Mwatermark */ +#define SPI_RXMARK SPI_BASE + 0x54 /* Rx FIFO watermark */ + +/* Non-implemented +#define SPI_FCTRL SPI_BASE + 0x60 // SPI flash interface control +#define SPI_FFMT SPI_BASE + 0x64 // SPI flash instruction format +*/ +#define SPI_IE SPI_BASE + 0x70 /* Interrupt Enable Register */ +#define SPI_IP SPI_BASE + 0x74 /* Interrupt Pendings Register */ + +/* delay0 bits */ +#define SIFIVE_SPI_DELAY0_CSSCK(x) ((uint32_t)(x)) +#define SIFIVE_SPI_DELAY0_CSSCK_MASK 0xffU +#define SIFIVE_SPI_DELAY0_SCKCS(x) ((uint32_t)(x) << 16) +#define SIFIVE_SPI_DELAY0_SCKCS_MASK (0xffU << 16) + +/* delay1 bits */ +#define SIFIVE_SPI_DELAY1_INTERCS(x) ((uint32_t)(x)) +#define SIFIVE_SPI_DELAY1_INTERCS_MASK 0xffU +#define SIFIVE_SPI_DELAY1_INTERXFR(x) ((uint32_t)(x) << 16) +#define SIFIVE_SPI_DELAY1_INTERXFR_MASK (0xffU << 16) + +/* csmode bits */ +#define SIFIVE_SPI_CSMODE_MODE_AUTO 0U +#define SIFIVE_SPI_CSMODE_MODE_HOLD 2U +#define SIFIVE_SPI_CSMODE_MODE_OFF 3U + +// inline void write_reg(uintptr_t addr, uint32_t value); +//inline uint32_t read_reg(uintptr_t addr); +//inline void spi_sendbyte(uint8_t byte); +//inline void waittx(); +//inline void waitrx(); +uint8_t spi_txrx(uint8_t byte); +uint8_t spi_dummy(); +//inline uint8_t spi_readbyte(); +uint64_t spi_read64(); +void spi_init(); +void spi_set_clock(uint32_t clkin, uint32_t clkout); + +static inline void write_reg(uintptr_t addr, uint32_t value) { + volatile uint32_t * loc = (volatile uint32_t *) addr; + *loc = value; +} + +// Read a register +static inline uint32_t read_reg(uintptr_t addr) { + return *(volatile uint32_t *) addr; +} + +// Queues a single byte in the transfer fifo +static inline void spi_sendbyte(uint8_t byte) { + // Write byte to transfer fifo + write_reg(SPI_TXDATA, byte); +} + +static inline void waittx() { + while(!(read_reg(SPI_IP) & 1)) {} +} + +static inline void waitrx() { + while(read_reg(SPI_IP) & 2) {} +} + +static inline uint8_t spi_readbyte() { + return read_reg(SPI_RXDATA); +} + +#endif diff --git a/fpga/zsbl/splitfile.sh b/fpga/zsbl/splitfile.sh new file mode 100755 index 000000000..fc943576c --- /dev/null +++ b/fpga/zsbl/splitfile.sh @@ -0,0 +1,48 @@ +####################################################################### +# splitfile.sh +# +# Written: Jaocb Pease jacob.pease@okstate.edu 7/22/2024 +# +# Purpose: Used to split boot.mem into two sections for FPGA +# +# +# +# A component of the Wally configurable RISC-V project. +# +# Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University +# +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +# +# Licensed under the Solderpad Hardware License v 2.1 (the +# “License”); you may not use this file except in compliance with the +# License, or, at your option, the Apache License version 2.0. You +# may obtain a copy of the License at +# +# https://solderpad.org/licenses/SHL-2.1/ +# +# Unless required by applicable law or agreed to in writing, any work +# distributed under the License is distributed on an “AS IS” BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. See the License for the specific language governing +# permissions and limitations under the License. +###################################################################### + + +# Acquired from here. +# https:##stackoverflow.com#questions#3066948#how-to-file-split-at-a-line-number +file_name=$1 + +# set first K lines: +K=512 + +# line count (N): +N=$(wc -l < $file_name) + +# length of the bottom file: +L=$(( $N - $K )) + +# create the top of file: +head -n $K $file_name > boot.mem + +# create bottom of file: +tail -n $L $file_name > data.mem diff --git a/fpga/zsbl/time.c b/fpga/zsbl/time.c new file mode 100644 index 000000000..c265eea05 --- /dev/null +++ b/fpga/zsbl/time.c @@ -0,0 +1,49 @@ +/////////////////////////////////////////////////////////////////////// +// time.c +// +// Written: Jaocb Pease jacob.pease@okstate.edu 7/22/2024 +// +// Purpose: Gets and prints the current time. +// +// +// +// A component of the Wally configurable RISC-V project. +// +// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University +// +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// Licensed under the Solderpad Hardware License v 2.1 (the +// “License”); you may not use this file except in compliance with the +// License, or, at your option, the Apache License version 2.0. You +// may obtain a copy of the License at +// +// https://solderpad.org/licenses/SHL-2.1/ +// +// Unless required by applicable law or agreed to in writing, any work +// distributed under the License is distributed on an “AS IS” BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +// implied. See the License for the specific language governing +// permissions and limitations under the License. +/////////////////////////////////////////////////////////////////////// + +#include "time.h" +#include "boot.h" +#include "riscv.h" +#include "uart.h" + +float getTime() { + set_status_fs(); + float numCycles = (float)read_mcycle(); + float ret = numCycles/SYSTEMCLOCK; + // clear_status_fs(); + return ret; +} + +void print_time() { + print_uart("["); + set_status_fs(); + print_uart_float(getTime(),5); + clear_status_fs(); + print_uart("] "); +} diff --git a/fpga/zsbl/time.h b/fpga/zsbl/time.h new file mode 100644 index 000000000..8bf7064af --- /dev/null +++ b/fpga/zsbl/time.h @@ -0,0 +1,34 @@ +/////////////////////////////////////////////////////////////////////// +// spi.c +// +// Written: Jaocb Pease jacob.pease@okstate.edu 7/22/2024 +// +// Purpose: Time function prototypes +// +// +// +// A component of the Wally configurable RISC-V project. +// +// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University +// +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// Licensed under the Solderpad Hardware License v 2.1 (the +// “License”); you may not use this file except in compliance with the +// License, or, at your option, the Apache License version 2.0. You +// may obtain a copy of the License at +// +// https://solderpad.org/licenses/SHL-2.1/ +// +// Unless required by applicable law or agreed to in writing, any work +// distributed under the License is distributed on an “AS IS” BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +// implied. See the License for the specific language governing +// permissions and limitations under the License. +/////////////////////////////////////////////////////////////////////// + +#pragma once +#include + +float getTime(); +void print_time(); diff --git a/fpga/zsbl/uart.c b/fpga/zsbl/uart.c new file mode 100644 index 000000000..580265d98 --- /dev/null +++ b/fpga/zsbl/uart.c @@ -0,0 +1,193 @@ +/////////////////////////////////////////////////////////////////////// +// uart.c +// +// Written: Jaocb Pease jacob.pease@okstate.edu 7/22/2024 +// +// Purpose: Uart printing functions, as well as functions for printing +// hex, decimal, and floating point numbers. +// +// +// +// A component of the Wally configurable RISC-V project. +// +// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University +// +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// Licensed under the Solderpad Hardware License v 2.1 (the +// “License”); you may not use this file except in compliance with the +// License, or, at your option, the Apache License version 2.0. You +// may obtain a copy of the License at +// +// https://solderpad.org/licenses/SHL-2.1/ +// +// Unless required by applicable law or agreed to in writing, any work +// distributed under the License is distributed on an “AS IS” BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +// implied. See the License for the specific language governing +// permissions and limitations under the License. +/////////////////////////////////////////////////////////////////////// + +#include "uart.h" + +void write_reg_u8(uintptr_t addr, uint8_t value) +{ + volatile uint8_t *loc_addr = (volatile uint8_t *)addr; + *loc_addr = value; +} + +uint8_t read_reg_u8(uintptr_t addr) +{ + return *(volatile uint8_t *)addr; +} + +int is_transmit_empty() +{ + return read_reg_u8(UART_LSR) & 0x20; +} + +int is_receive_empty() +{ + return !(read_reg_u8(UART_LSR) & 0x1); +} + +void write_serial(char a) +{ + while (is_transmit_empty() == 0) {}; + + write_reg_u8(UART_THR, a); +} + +void init_uart(uint32_t freq, uint32_t baud) +{ + // Alternative divisor calculation. From OpenSBI code. + // Reduces error for every possible frequency. + uint32_t divisor = (freq + 8 * baud) /(baud << 4); + + write_reg_u8(UART_IER, 0x00); // Disable all interrupts + write_reg_u8(UART_LCR, 0x80); // Enable DLAB (set baud rate divisor) + write_reg_u8(UART_DLL, divisor & 0xFF); // divisor (lo byte) + write_reg_u8(UART_DLM, (divisor >> 8) & 0xFF); // divisor (hi byte) + write_reg_u8(UART_LCR, 0x03); // 8 bits, no parity, one stop bit + write_reg_u8(UART_FCR, 0xC7); // Enable FIFO, clear them, with 14-byte threshold +} + +void print_uart(const char *str) +{ + const char *cur = &str[0]; + while (*cur != '\0') { + write_serial((uint8_t)*cur); + ++cur; + } +} + +uint8_t bin_to_hex_table[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + +void bin_to_hex(uint8_t inp, uint8_t res[2]) +{ + res[1] = bin_to_hex_table[inp & 0xf]; + res[0] = bin_to_hex_table[(inp >> 4) & 0xf]; + return; +} + +void print_uart_hex(uint64_t addr, int n) +{ + int i; + for (i = n - 1; i > -1; i--) { + uint8_t cur = (addr >> (i * 8)) & 0xff; + uint8_t hex[2]; + bin_to_hex(cur, hex); + write_serial(hex[0]); + write_serial(hex[1]); + } +} + +void print_uart_dec(uint64_t addr) { + + // floor(log(2^64)) = 19 + char str[19] = {'\0'}; + uint8_t length = 1; + + uint64_t cur = addr; + while (cur != 0) { + char digit = bin_to_hex_table[cur % 10]; + // write_serial(digit); + str[length] = digit; + cur = cur/10; + length++; + } + + for (int i = length; i > -1; i--) { + write_serial(str[i]); + } +} + +// Print a floating point number on the UART +void print_uart_float(float num, int precision) { + char str[32] = {'\0'}; + char digit; + uint8_t length = precision + 1; + int i; + uint64_t cur; + + str[precision] = '.'; + + int pow = 1; + + // Calculate power for precision + for (i = 0; i < precision; i++) { + pow = pow * 10; + } + + cur = (uint64_t)(num * pow); + for (i = 0; i < precision; i++) { + digit = bin_to_hex_table[cur % 10]; + str[i] = digit; + cur = cur / 10; + } + + cur = (uint64_t)num; + do { + digit = bin_to_hex_table[cur % 10]; + str[length] = digit; + cur = cur/10; + length++; + } while (cur != 0); + + for (i = length; i > -1; i--) { + write_serial(str[i]); + } +} + +/* void print_uart_int(uint32_t addr) */ +/* { */ +/* int i; */ +/* for (i = 3; i > -1; i--) { */ +/* uint8_t cur = (addr >> (i * 8)) & 0xff; */ +/* uint8_t hex[2]; */ +/* bin_to_hex(cur, hex); */ +/* write_serial(hex[0]); */ +/* write_serial(hex[1]); */ +/* } */ +/* } */ + +/* void print_uart_addr(uint64_t addr) */ +/* { */ +/* int i; */ +/* for (i = 7; i > -1; i--) { */ +/* uint8_t cur = (addr >> (i * 8)) & 0xff; */ +/* uint8_t hex[2]; */ +/* bin_to_hex(cur, hex); */ +/* write_serial(hex[0]); */ +/* write_serial(hex[1]); */ +/* } */ +/* } */ + +/* void print_uart_byte(uint8_t byte) */ +/* { */ +/* uint8_t hex[2]; */ +/* bin_to_hex(byte, hex); */ +/* write_serial(hex[0]); */ +/* write_serial(hex[1]); */ +/* } */ diff --git a/fpga/zsbl/uart.h b/fpga/zsbl/uart.h new file mode 100644 index 000000000..96c55ffe8 --- /dev/null +++ b/fpga/zsbl/uart.h @@ -0,0 +1,87 @@ +/////////////////////////////////////////////////////////////////////// +// uart.h +// +// Written: Jaocb Pease jacob.pease@okstate.edu 7/22/2024 +// +// Purpose: Header for the UART functions. +// +// +// +// A component of the Wally configurable RISC-V project. +// +// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University +// +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// Licensed under the Solderpad Hardware License v 2.1 (the +// “License”); you may not use this file except in compliance with the +// License, or, at your option, the Apache License version 2.0. You +// may obtain a copy of the License at +// +// https://solderpad.org/licenses/SHL-2.1/ +// +// Unless required by applicable law or agreed to in writing, any work +// distributed under the License is distributed on an “AS IS” BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +// implied. See the License for the specific language governing +// permissions and limitations under the License. +/////////////////////////////////////////////////////////////////////// + +#pragma once +#include +#include "riscv.h" +#include "time.h" + +// UART register addresses +#define UART_BASE 0x10000000 + +#define UART_RBR UART_BASE + 0x00 +#define UART_THR UART_BASE + 0x00 +#define UART_IER UART_BASE + 0x01 +#define UART_IIR UART_BASE + 0x02 +#define UART_FCR UART_BASE + 0x02 +#define UART_LCR UART_BASE + 0x03 +#define UART_MCR UART_BASE + 0x04 +#define UART_LSR UART_BASE + 0x05 +#define UART_MSR UART_BASE + 0x06 +#define UART_SCR UART_BASE + 0x07 +#define UART_DLL UART_BASE + 0x00 +#define UART_DLM UART_BASE + 0x01 + +// Primary function prototypes +void init_uart(uint32_t freq, uint32_t baud); +void write_reg_u8(uintptr_t addr, uint8_t value); +uint8_t read_reg_u8(uintptr_t addr); +int read_serial(uint8_t *res); +void print_uart(const char* str); +void print_uart_int(uint32_t addr); +void print_uart_dec(uint64_t addr); +void print_uart_addr(uint64_t addr); +void print_uart_hex(uint64_t addr, int n); +void print_uart_byte(uint8_t byte); +void print_uart_float(float num, int precision); +// void print_time(); + +// Print numbers in hex with specified widths +#define print_uart_int(addr) print_uart_hex(addr, 4) +#define print_uart_addr(addr) print_uart_hex(addr, 8) +#define print_uart_byte(addr) print_uart_hex(addr, 1) +#define print_r7(addr) print_uart_hex(addr, 5) +#define print_r1(addr) print_uart_byte(addr) + +// Print line with numbers utility macros +#define println(msg) print_uart(msg "\r\n"); +#define println_with_dec(msg, num) print_uart(msg); print_uart_dec(num); print_uart("\r\n") +#define println_with_byte(msg, num) print_uart(msg); print_uart_byte(num); print_uart("\r\n") +#define println_with_int(msg, num) print_uart(msg); print_uart_int(num); print_uart("\r\n") +#define println_with_addr(msg, num) print_uart(msg); print_uart_addr(num); print_uart("\r\n") +#define println_with_r1(msg, num) print_uart(msg); print_r1(num); print_uart("\r\n") +#define println_with_r7(msg, num) print_uart(msg); print_r7(num); print_uart("\r\n") +#define println_with_float(msg, num) print_uart(msg); set_status_fs(); print_uart_float(num,5); clear_status_fs(); print_uart("\r\n") + +/* #define print_time() print_uart("["); \ */ +/* set_status_fs(); \ */ +/* print_uart_float(getTime(),5); \ */ +/* clear_status_fs(); \ */ +/* print_uart("] ") */ + diff --git a/linux/Makefile b/linux/Makefile index d195dfa41..65632a0d0 100644 --- a/linux/Makefile +++ b/linux/Makefile @@ -107,7 +107,7 @@ $(IMAGES)/busybox: # Generating new Buildroot directories -------------------------------- -download: $(BUILDROOT)/package/fpga-axi-sdc $(WALLYBOARD) +download: $(WALLYBOARD) cp $(WALLYBOARD)/main.config $(BUILDROOT)/.config @echo "Buildroot successfully download." diff --git a/linux/buildroot-config-src/buildroot-2023.05.1/linux.config b/linux/buildroot-config-src/buildroot-2023.05.1/linux.config index e348cde78..047be24c2 100644 --- a/linux/buildroot-config-src/buildroot-2023.05.1/linux.config +++ b/linux/buildroot-config-src/buildroot-2023.05.1/linux.config @@ -2,7 +2,7 @@ # Automatically generated file; DO NOT EDIT. # Linux/riscv 6.6.0 Kernel Configuration # -CONFIG_CC_VERSION_TEXT="riscv64-buildroot-linux-gnu-gcc.br_real (Buildroot 2023.05.3-dirty) 12.3.0" +CONFIG_CC_VERSION_TEXT="riscv64-buildroot-linux-gnu-gcc.br_real (Buildroot 2023.05.3) 12.3.0" CONFIG_CC_IS_GCC=y CONFIG_GCC_VERSION=120300 CONFIG_CLANG_VERSION=0 @@ -1042,7 +1042,7 @@ CONFIG_MMC_BLOCK_MINORS=8 # # CONFIG_MMC_DEBUG is not set # CONFIG_MMC_SDHCI is not set -# CONFIG_MMC_SPI is not set +CONFIG_MMC_SPI=y # CONFIG_MMC_DW is not set # CONFIG_MMC_USDHI6ROL0 is not set # CONFIG_MMC_CQHCI is not set @@ -1455,7 +1455,7 @@ CONFIG_CRYPTO_HASH2=y # CONFIG_CRYPTO_POLY1305 is not set # CONFIG_CRYPTO_RMD160 is not set # CONFIG_CRYPTO_SHA1 is not set -# CONFIG_CRYPTO_SHA256 is not set +CONFIG_CRYPTO_SHA256=y # CONFIG_CRYPTO_SHA512 is not set # CONFIG_CRYPTO_SHA3 is not set # CONFIG_CRYPTO_SM3_GENERIC is not set @@ -1527,13 +1527,14 @@ CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y CONFIG_CRYPTO_LIB_POLY1305_RSIZE=1 # CONFIG_CRYPTO_LIB_POLY1305 is not set # CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set +CONFIG_CRYPTO_LIB_SHA256=y # end of Crypto library routines # CONFIG_CRC_CCITT is not set CONFIG_CRC16=y # CONFIG_CRC_T10DIF is not set # CONFIG_CRC64_ROCKSOFT is not set -# CONFIG_CRC_ITU_T is not set +CONFIG_CRC_ITU_T=y CONFIG_CRC32=y # CONFIG_CRC32_SELFTEST is not set CONFIG_CRC32_SLICEBY8=y @@ -1542,7 +1543,7 @@ CONFIG_CRC32_SLICEBY8=y # CONFIG_CRC32_BIT is not set # CONFIG_CRC64 is not set # CONFIG_CRC4 is not set -# CONFIG_CRC7 is not set +CONFIG_CRC7=y # CONFIG_LIBCRC32C is not set # CONFIG_CRC8 is not set # CONFIG_RANDOM32_SELFTEST is not set @@ -1599,7 +1600,7 @@ CONFIG_PRINTK_TIME=y # CONFIG_STACKTRACE_BUILD_ID is not set CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7 CONFIG_CONSOLE_LOGLEVEL_QUIET=4 -CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=7 # CONFIG_BOOT_PRINTK_DELAY is not set # CONFIG_DYNAMIC_DEBUG is not set # CONFIG_DYNAMIC_DEBUG_CORE is not set diff --git a/linux/devicetree/wally-artya7.dts b/linux/devicetree/wally-artya7.dts index 87933bcc0..99b8ff00d 100644 --- a/linux/devicetree/wally-artya7.dts +++ b/linux/devicetree/wally-artya7.dts @@ -5,11 +5,11 @@ #size-cells = <0x02>; compatible = "wally-virt"; model = "wally-virt,qemu"; - + chosen { linux,initrd-end = <0x85c43a00>; linux,initrd-start = <0x84200000>; - bootargs = "root=/dev/vda ro console=ttyS0,115200"; + bootargs = "root=/dev/vda ro console=ttyS0,115200 loglevel=7"; stdout-path = "/soc/uart@10000000"; }; @@ -51,6 +51,25 @@ compatible = "simple-bus"; ranges; + refclk: refclk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0x1312D00>; + clock-output-names = "xtal"; + }; + + gpio0: gpio@10060000 { + compatible = "sifive,gpio0"; + interrupt-parent = <0x03>; + interrupts = <3>; + reg = <0x00 0x10060000 0x00 0x1000>; + reg-names = "control"; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + uart@10000000 { interrupts = <0x0a>; interrupt-parent = <0x03>; @@ -70,18 +89,24 @@ #address-cells = <0x00>; }; - mmc@13000 { - interrupts = <0x14>; - compatible = "riscv,axi-sd-card-1.0"; - reg = <0x00 0x13000 0x00 0x7F>; - fifo-depth = <256>; - bus-width = <4>; + spi@13000 { + compatible = "sifive,spi0"; interrupt-parent = <0x03>; - clock = <0x1312D00>; - max-frequency = <0x1312D00>; - cap-sd-highspeed; - cap-mmc-highspeed; - no-sdio; + interrupts = <0x14>; + reg = <0x0 0x13000 0x0 0x1000>; + reg-names = "control"; + clocks = <&refclk>; + + #address-cells = <1>; + #size-cells = <0>; + mmc@0 { + compatible = "mmc-spi-slot"; + reg = <0>; + spi-max-frequency = <5000000>; + voltage-ranges = <3300 3300>; + disable-wp; + // gpios = <&gpio0 6 1>; + }; }; clint@2000000 { diff --git a/sim/questa/wally.do b/sim/questa/wally.do index 632e2c156..43892c356 100644 --- a/sim/questa/wally.do +++ b/sim/questa/wally.do @@ -31,6 +31,7 @@ set WALLY $::env(WALLY) set CONFIG ${WALLY}/config set SRC ${WALLY}/src set TB ${WALLY}/testbench +set FCRVVI ${WALLY}/addins/cvw-arch-verif/fcov # create library if [file exists ${WKDIR}] { @@ -39,11 +40,16 @@ if [file exists ${WKDIR}] { vlib ${WKDIR} # Create directory for coverage data mkdir -p cov +# Create directory for functional coverage data +mkdir ${WALLY}/addins/cvw-arch-verif/work set ccov 0 set CoverageVoptArg "" set CoverageVsimArg "" +set FuncCovRVVI 0 +set FCdefineRVVI_COVERAGE "" + set FunctCoverage 0 set riscvISACOVsrc "" set FCdefineINCLUDE_TRACE2COV "" @@ -113,6 +119,13 @@ if {$CoverageIndex >= 0} { set lst [lreplace $lst $CoverageIndex $CoverageIndex] } +set FCoverageIndexRVVI [lsearch -exact $lst "--fcovrvvi"] +if {$FCoverageIndexRVVI >= 0} { + set FuncCovRVVI 1 + set FCdefineRVVI_COVERAGE "+define+RVVI_COVERAGE" + set lst [lreplace $lst $FCoverageIndexRVVI $FCoverageIndexRVVI] +} + # if +coverage found set flag and remove from list set FunctCoverageIndex [lsearch -exact $lst "--fcov"] if {$FunctCoverageIndex >= 0} { @@ -172,6 +185,7 @@ if {$DEBUG > 0} { echo "GUI = $GUI" echo "ccov = $ccov" echo "lockstep = $lockstep" + echo "FuncCovRVVI = $FuncCovRVVI" echo "FunctCoverage = $FunctCoverage" echo "remaining list = $lst" echo "Extra +args = $PlusArgs" @@ -197,7 +211,7 @@ set temp3 [lindex $PlusArgs 3] # "Extra checking for conflicts with always_comb done at vopt time" # because vsim will run vopt -vlog -lint -work ${WKDIR} +incdir+${CONFIG}/${CFG} +incdir+${CONFIG}/deriv/${CFG} +incdir+${CONFIG}/shared ${lockstepvoptstring} ${FCdefineIDV_INCLUDE_TRACE2COV} ${FCdefineINCLUDE_TRACE2COV} ${ImperasPubInc} ${ImperasPrivInc} ${rvviFiles} ${FCdefineCOVER_BASE_RV64I} ${FCdefineCOVER_LEVEL_DV_PR_EXT} ${FCdefineCOVER_RV64I} ${FCdefineCOVER_RV64M} ${FCdefineCOVER_RV64A} ${FCdefineCOVER_RV64F} ${FCdefineCOVER_RV64D} ${FCdefineCOVER_RV64ZICSR} ${FCdefineCOVER_RV64C} ${idvFiles} ${riscvISACOVsrc} ${SRC}/cvw.sv ${TB}/${TESTBENCH}.sv ${TB}/common/*.sv ${SRC}/*/*.sv ${SRC}/*/*/*.sv ${WALLY}/addins/verilog-ethernet/*/*.sv ${WALLY}/addins/verilog-ethernet/*/*/*/*.sv -suppress 2583 -suppress 7063,2596,13286 +vlog -lint -work ${WKDIR} +incdir+${CONFIG}/${CFG} +incdir+${CONFIG}/deriv/${CFG} +incdir+${CONFIG}/shared ${lockstepvoptstring} ${FCdefineIDV_INCLUDE_TRACE2COV} ${FCdefineINCLUDE_TRACE2COV} ${ImperasPubInc} ${ImperasPrivInc} ${rvviFiles} ${FCdefineCOVER_BASE_RV64I} ${FCdefineCOVER_LEVEL_DV_PR_EXT} ${FCdefineCOVER_RV64I} ${FCdefineCOVER_RV64M} ${FCdefineCOVER_RV64A} ${FCdefineCOVER_RV64F} ${FCdefineCOVER_RV64D} ${FCdefineCOVER_RV64ZICSR} ${FCdefineCOVER_RV64C} ${FCdefineRVVI_COVERAGE} ${idvFiles} ${riscvISACOVsrc} ${SRC}/cvw.sv ${TB}/${TESTBENCH}.sv ${TB}/common/*.sv ${SRC}/*/*.sv ${SRC}/*/*/*.sv +incdir+${FCRVVI}/common +incdir+${FCRVVI} ${WALLY}/addins/verilog-ethernet/*/*.sv ${WALLY}/addins/verilog-ethernet/*/*/*/*.sv -suppress 2583 -suppress 7063,2596,13286 # start and run simulation # remove +acc flag for faster sim during regressions if there is no need to access internal signals @@ -224,6 +238,11 @@ if {$FunctCoverage} { coverage save -onexit ${UCDB} } +if {$FuncCovRVVI} { + set UCDB ${WALLY}/addins/cvw-arch-verif/work/${CFG}_${TESTSUITE}.ucdb + coverage save -onexit ${UCDB} +} + run -all if {$ccov} { diff --git a/src/generic/mem/ram1p1rwbe.sv b/src/generic/mem/ram1p1rwbe.sv index d333048b7..d17262d22 100644 --- a/src/generic/mem/ram1p1rwbe.sv +++ b/src/generic/mem/ram1p1rwbe.sv @@ -83,11 +83,30 @@ module ram1p1rwbe import cvw::*; #(parameter USE_SRAM=0, DEPTH=64, WIDTH=44, PRE end else begin: ram bit [WIDTH-1:0] RAM[DEPTH-1:0]; - if (PRELOAD_ENABLED) begin - initial begin - RAM[0] = 64'h00600100d2e3ca40; + // if (PRELOAD_ENABLED) begin + // initial begin + // RAM[0] = 64'h00600100d2e3ca40; + // end + // end + + `ifdef VERILATOR + import "DPI-C" function string getenvval(input string env_name); + `endif + + initial + if (PRELOAD_ENABLED) begin + if (WIDTH == 64) begin + `ifdef VERILATOR + // because Verilator doesn't automatically accept $WALLY from shell + string WALLY_DIR = getenvval("WALLY"); + $readmemh({WALLY_DIR,"/fpga/src/data.mem"}, RAM, 0); // load boot RAM for FPGA + `else + $readmemh({"$WALLY/fpga/src/data.mem"}, RAM, 0); // load boot RAM for FPGA + `endif + end else begin // put something in the RAM so it is not optimized away + RAM[0] = 'h00002197; + end end - end // Combinational read: register address and read after clock edge logic [$clog2(DEPTH)-1:0] addrd; diff --git a/src/uncore/spi_apb.sv b/src/uncore/spi_apb.sv index 94f188120..cadb49dfb 100644 --- a/src/uncore/spi_apb.sv +++ b/src/uncore/spi_apb.sv @@ -42,7 +42,8 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( output logic SPIOut, input logic SPIIn, output logic [3:0] SPICS, - output logic SPIIntr + output logic SPIIntr, + output logic SPICLK ); // register map @@ -99,7 +100,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( rsrstatetype ReceiveState; // Transmission signals - logic sck; + // logic sck; logic [11:0] DivCounter; // Counter for sck logic SCLKenable; // Flip flop enable high every sclk edge @@ -147,6 +148,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( // APB access assign Entry = {PADDR[7:2],2'b00}; // 32-bit word-aligned accesses assign Memwrite = PWRITE & PENABLE & PSEL; // Only write in access phase + // JACOB: This shouldn't behave this way assign PREADY = TransmitInactive; // Tie PREADY to transmission for hardware interlock // Account for subword read/write circuitry @@ -358,29 +360,32 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( assign DelayMode = SckMode[0] ? (state == DELAY_1) : (state == ACTIVE_1 & ReceiveShiftFull); assign ChipSelectInternal = (state == CS_INACTIVE | state == INTER_CS | DelayMode & ~|(Delay0[15:8])) ? ChipSelectDef : ~ChipSelectDef; - assign sck = (state == ACTIVE_0) ? ~SckMode[1] : SckMode[1]; + assign SPICLK = (state == ACTIVE_0) ? ~SckMode[1] : SckMode[1]; assign Active = (state == ACTIVE_0 | state == ACTIVE_1); assign SampleEdge = SckMode[0] ? (state == ACTIVE_1) : (state == ACTIVE_0); assign ZeroDelayHoldMode = ((ChipSelectMode == 2'b10) & (~|(Delay1[7:4]))); assign TransmitInactive = ((state == INTER_CS) | (state == CS_INACTIVE) | (state == INTER_XFR) | (ReceiveShiftFullDelayPCLK & ZeroDelayHoldMode)); assign Active0 = (state == ACTIVE_0); - // Signal tracks which edge of sck to shift data + // Signal tracks which edge of sck to shift data + // Jacob: We need to confirm that this represents the actual polarity and phase options for sampling. + // The first option now samples on the leading edge and shifts on the falling edge like it's supposed to. + // We need to confirm the validity of the other options. always_comb case(SckMode[1:0]) - 2'b00: ShiftEdge = ~sck & SCLKenable; - 2'b01: ShiftEdge = (sck & |(FrameCount) & SCLKenable); - 2'b10: ShiftEdge = sck & SCLKenable; - 2'b11: ShiftEdge = (~sck & |(FrameCount) & SCLKenable); - default: ShiftEdge = sck & SCLKenable; + 2'b00: ShiftEdge = SPICLK & SCLKenable; + 2'b01: ShiftEdge = (SPICLK & |(FrameCount) & SCLKenable); // Probably wrong + 2'b10: ShiftEdge = ~SPICLK & SCLKenable; // Probably wrong + 2'b11: ShiftEdge = (~SPICLK & |(FrameCount) & SCLKenable); // Probably wrong + default: ShiftEdge = SPICLK & SCLKenable; endcase // Transmit shift register assign TransmitDataEndian = Format[0] ? {TransmitFIFOReadData[0], TransmitFIFOReadData[1], TransmitFIFOReadData[2], TransmitFIFOReadData[3], TransmitFIFOReadData[4], TransmitFIFOReadData[5], TransmitFIFOReadData[6], TransmitFIFOReadData[7]} : TransmitFIFOReadData[7:0]; always_ff @(posedge PCLK) - if(~PRESETn) TransmitShiftReg <= 8'b0; + if(~PRESETn) TransmitShiftReg <= 8'b0; // Temporarily changing to 1s else if (TransmitShiftRegLoad) TransmitShiftReg <= TransmitDataEndian; - else if (ShiftEdge & Active) TransmitShiftReg <= {TransmitShiftReg[6:0], 1'b0}; + else if (ShiftEdge & Active) TransmitShiftReg <= {TransmitShiftReg[6:0], TransmitShiftReg[0]}; // Temporarily changing to 1s assign SPIOut = TransmitShiftReg[7]; diff --git a/src/uncore/uncore.sv b/src/uncore/uncore.sv index 39a2be09a..21dd956ed 100644 --- a/src/uncore/uncore.sv +++ b/src/uncore/uncore.sv @@ -46,7 +46,6 @@ module uncore import cvw::*; #(parameter cvw_t P)( output logic [P.AHBW-1:0] HRDATA, output logic HREADY, HRESP, output logic HSELEXT, - output logic HSELEXTSDC, // peripheral pins output logic MTimerInt, MSwInt, // Timer and software interrupts from CLINT output logic MExtInt, SExtInt, // External interrupts from PLIC @@ -55,16 +54,20 @@ module uncore import cvw::*; #(parameter cvw_t P)( output logic [31:0] GPIOOUT, GPIOEN, // GPIO pin output value and enable input logic UARTSin, // UART serial input output logic UARTSout, // UART serial output - input logic SDCIntr, input logic SPIIn, output logic SPIOut, - output logic [3:0] SPICS + output logic [3:0] SPICS, + output logic SPICLK, + input logic SDCIn, + output logic SDCCmd, + output logic [3:0] SDCCS, + output logic SDCCLK ); logic [P.XLEN-1:0] HREADRam, HREADSDC; logic [11:0] HSELRegions; - logic HSELDTIM, HSELIROM, HSELRam, HSELCLINT, HSELPLIC, HSELGPIO, HSELUART, HSELSPI; + logic HSELDTIM, HSELIROM, HSELRam, HSELCLINT, HSELPLIC, HSELGPIO, HSELUART,HSELSDC, HSELSPI; logic HSELDTIMD, HSELIROMD, HSELEXTD, HSELRamD, HSELCLINTD, HSELPLICD, HSELGPIOD, HSELUARTD, HSELSDCD, HSELSPID; logic HRESPRam, HRESPSDC; logic HREADYRam, HRESPSDCD; @@ -75,18 +78,18 @@ module uncore import cvw::*; #(parameter cvw_t P)( logic SDCIntM; logic PCLK, PRESETn, PWRITE, PENABLE; - logic [4:0] PSEL; + logic [5:0] PSEL; logic [31:0] PADDR; logic [P.XLEN-1:0] PWDATA; logic [P.XLEN/8-1:0] PSTRB; /* verilator lint_off UNDRIVEN */ // undriven in rv32e configuration - logic [4:0] PREADY; - logic [4:0][P.XLEN-1:0] PRDATA; + logic [5:0] PREADY; + logic [5:0][P.XLEN-1:0] PRDATA; /* verilator lint_on UNDRIVEN */ logic [P.XLEN-1:0] HREADBRIDGE; logic HRESPBRIDGE, HREADYBRIDGE, HSELBRIDGE, HSELBRIDGED; - - (* mark_debug = "true" *) logic HSELEXTSDCD; + /* SDC Interrupt (SPI Controller) */ + logic SDCIntr; // Determine which region of physical memory (if any) is being accessed @@ -95,14 +98,14 @@ module uncore import cvw::*; #(parameter cvw_t P)( adrdecs #(P) adrdecs(HADDR, 1'b1, 1'b1, 1'b1, HSIZE[1:0], HSELRegions); // unswizzle HSEL signals - assign {HSELSPI, HSELEXTSDC, HSELPLIC, HSELUART, HSELGPIO, HSELCLINT, HSELRam, HSELBootRom, HSELEXT, HSELIROM, HSELDTIM} = HSELRegions[11:1]; + assign {HSELSPI, HSELSDC, HSELPLIC, HSELUART, HSELGPIO, HSELCLINT, HSELRam, HSELBootRom, HSELEXT, HSELIROM, HSELDTIM} = HSELRegions[11:1]; // AHB -> APB bridge - ahbapbbridge #(P, 5) ahbapbbridge ( - .HCLK, .HRESETn, .HSEL({HSELSPI, HSELUART, HSELPLIC, HSELCLINT, HSELGPIO}), .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HTRANS, .HREADY, + ahbapbbridge #(P, 6) ahbapbbridge ( + .HCLK, .HRESETn, .HSEL({HSELSDC, HSELSPI, HSELUART, HSELPLIC, HSELCLINT, HSELGPIO}), .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HTRANS, .HREADY, .HRDATA(HREADBRIDGE), .HRESP(HRESPBRIDGE), .HREADYOUT(HREADYBRIDGE), .PCLK, .PRESETn, .PSEL, .PWRITE, .PENABLE, .PADDR, .PWDATA, .PSTRB, .PREADY, .PRDATA); - assign HSELBRIDGE = HSELGPIO | HSELCLINT | HSELPLIC | HSELUART | HSELSPI; // if any of the bridge signals are selected + assign HSELBRIDGE = HSELGPIO | HSELCLINT | HSELPLIC | HSELUART | HSELSPI | HSELSDC; // if any of the bridge signals are selected // on-chip RAM if (P.UNCORE_RAM_SUPPORTED) begin : ram @@ -142,6 +145,7 @@ module uncore import cvw::*; #(parameter cvw_t P)( end else begin : gpio assign GPIOOUT = '0; assign GPIOEN = '0; assign GPIOIntr = 1'b0; end + if (P.UART_SUPPORTED == 1) begin : uartgen // Hack to work around Verilator bug https://github.com/verilator/verilator/issues/4769 uart_apb #(P) uart( .PCLK, .PRESETn, .PSEL(PSEL[3]), .PADDR(PADDR[2:0]), .PWDATA, .PSTRB, .PWRITE, .PENABLE, @@ -152,28 +156,39 @@ module uncore import cvw::*; #(parameter cvw_t P)( end else begin : uart assign UARTSout = 1'b0; assign UARTIntr = 1'b0; end + if (P.SPI_SUPPORTED == 1) begin : spi spi_apb #(P) spi ( .PCLK, .PRESETn, .PSEL(PSEL[4]), .PADDR(PADDR[7:0]), .PWDATA, .PSTRB, .PWRITE, .PENABLE, .PREADY(PREADY[4]), .PRDATA(PRDATA[4]), - .SPIOut, .SPIIn, .SPICS, .SPIIntr); + .SPIOut, .SPIIn, .SPICS, .SPICLK, .SPIIntr); end else begin : spi - assign SPIOut = 1'b0; assign SPICS = '0; assign SPIIntr = 1'b0; + assign SPIOut = 1'b0; assign SPICS = '0; assign SPIIntr = 1'b0; assign SPICLK = 1'b0; end + if (P.SDC_SUPPORTED == 1) begin : sdc + spi_apb #(P) sdc( + .PCLK, .PRESETn, .PSEL(PSEL[5]), .PADDR(PADDR[7:0]), .PWDATA, .PSTRB, .PWRITE, .PENABLE, + .PREADY(PREADY[5]), .PRDATA(PRDATA[5]), + .SPIOut(SDCCmd), .SPIIn(SDCIn), .SPICS(SDCCS), .SPICLK(SDCCLK), .SPIIntr(SDCIntr)); + end else begin : sdc + assign SDCCmd = '0; assign SDCCS = 4'b0; assign SDCIntr = 1'b0; assign SDCCLK = 1'b0; + end + + // AHB Read Multiplexer assign HRDATA = ({P.XLEN{HSELRamD}} & HREADRam) | - ({P.XLEN{HSELEXTD | HSELEXTSDCD}} & HRDATAEXT) | + ({P.XLEN{HSELEXTD}} & HRDATAEXT) | ({P.XLEN{HSELBRIDGED}} & HREADBRIDGE) | ({P.XLEN{HSELBootRomD}} & HREADBootRom); assign HRESP = HSELRamD & HRESPRam | - (HSELEXTD | HSELEXTSDCD) & HRESPEXT | + HSELEXTD & HRESPEXT | HSELBRIDGE & HRESPBRIDGE | HSELBootRomD & HRESPBootRom; assign HREADY = HSELRamD & HREADYRam | - (HSELEXTD | HSELEXTSDCD) & HREADYEXT | + HSELEXTD & HREADYEXT | HSELBRIDGED & HREADYBRIDGE | HSELBootRomD & HREADYBootRom | HSELNoneD; // don't lock up the bus if no region is being accessed @@ -184,7 +199,7 @@ module uncore import cvw::*; #(parameter cvw_t P)( // device is ready. Hense this register must be selectively enabled by HREADY. // However on reset None must be seleted. flopenl #(12) hseldelayreg(HCLK, ~HRESETn, HREADY, HSELRegions, 12'b1, - {HSELSPID, HSELEXTSDCD, HSELPLICD, HSELUARTD, HSELGPIOD, HSELCLINTD, + {HSELSPID, HSELSDCD, HSELPLICD, HSELUARTD, HSELGPIOD, HSELCLINTD, HSELRamD, HSELBootRomD, HSELEXTD, HSELIROMD, HSELDTIMD, HSELNoneD}); flopenr #(1) hselbridgedelayreg(HCLK, ~HRESETn, HREADY, HSELBRIDGE, HSELBRIDGED); endmodule diff --git a/src/wally/wallypipelinedsoc.sv b/src/wally/wallypipelinedsoc.sv index 273a7f633..2e534ba59 100644 --- a/src/wally/wallypipelinedsoc.sv +++ b/src/wally/wallypipelinedsoc.sv @@ -35,7 +35,6 @@ module wallypipelinedsoc import cvw::*; #(parameter cvw_t P) ( input logic [P.AHBW-1:0] HRDATAEXT, input logic HREADYEXT, HRESPEXT, output logic HSELEXT, - output logic HSELEXTSDC, // fpga debug signals input logic ExternalStall, // outputs to external memory, shared with uncore memory @@ -57,10 +56,14 @@ module wallypipelinedsoc import cvw::*; #(parameter cvw_t P) ( output logic [31:0] GPIOEN, // output enables for GPIO input logic UARTSin, // UART serial data input output logic UARTSout, // UART serial data output - input logic SDCIntr, input logic SPIIn, // SPI pins in output logic SPIOut, // SPI pins out - output logic [3:0] SPICS // SPI chip select pins + output logic [3:0] SPICS, // SPI chip select pins + output logic SPICLK, // SPI clock + input logic SDCIn, // SDC DATA[0] to SPI DI + output logic SDCCmd, // SDC CMD from SPI DO + output logic [3:0] SDCCS, // SDC Card Detect from SPI CS + output logic SDCCLK // SDC Clock from SPI Clock ); // Uncore signals @@ -84,12 +87,12 @@ module wallypipelinedsoc import cvw::*; #(parameter cvw_t P) ( if (P.BUS_SUPPORTED) begin : uncoregen // Hack to work around Verilator bug https://github.com/verilator/verilator/issues/4769 uncore #(P) uncore(.HCLK, .HRESETn, .TIMECLK, .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HSIZE, .HBURST, .HPROT, .HTRANS, .HMASTLOCK, .HRDATAEXT, - .HREADYEXT, .HRESPEXT, .HRDATA, .HREADY, .HRESP, .HSELEXT, .HSELEXTSDC, + .HREADYEXT, .HRESPEXT, .HRDATA, .HREADY, .HRESP, .HSELEXT, .MTimerInt, .MSwInt, .MExtInt, .SExtInt, .GPIOIN, .GPIOOUT, .GPIOEN, .UARTSin, - .UARTSout, .MTIME_CLINT, .SDCIntr, .SPIIn, .SPIOut, .SPICS); + .UARTSout, .MTIME_CLINT, .SPIIn, .SPIOut, .SPICS, .SPICLK, .SDCIn, .SDCCmd, .SDCCS, .SDCCLK); end else begin - assign {HRDATA, HREADY, HRESP, HSELEXT, HSELEXTSDC, MTimerInt, MSwInt, MExtInt, SExtInt, - MTIME_CLINT, GPIOOUT, GPIOEN, UARTSout, SPIOut, SPICS} = '0; + assign {HRDATA, HREADY, HRESP, HSELEXT, MTimerInt, MSwInt, MExtInt, SExtInt, + MTIME_CLINT, GPIOOUT, GPIOEN, UARTSout, SPIOut, SPICS, SPICLK, SDCCmd, SDCCS, SDCCLK} = '0; end diff --git a/testbench/testbench.sv b/testbench/testbench.sv index 6c3bf7d64..df87eb9b5 100644 --- a/testbench/testbench.sv +++ b/testbench/testbench.sv @@ -33,6 +33,12 @@ `include "idv/idv.svh" `endif +`ifdef RVVI_COVERAGE + `include "RISCV_trace_data.svh" + `include "rvvicov.svh" + `include "wrapper.sv" +`endif + import cvw::*; module testbench; @@ -76,8 +82,7 @@ module testbench; // DUT signals logic [P.AHBW-1:0] HRDATAEXT; - logic HREADYEXT, HRESPEXT; - logic HSELEXTSDC; + logic HREADYEXT, HRESPEXT; logic [P.PA_BITS-1:0] HADDR; logic [P.AHBW-1:0] HWDATA; logic [P.XLEN/8-1:0] HWSTRB; @@ -93,7 +98,11 @@ module testbench; logic UARTSin, UARTSout; logic SPIIn, SPIOut; logic [3:0] SPICS; - logic SDCIntr; + logic SPICLK; + logic SDCCmd; + logic SDCIn; + logic [3:0] SDCCS; + logic SDCCLK; logic HREADY; logic HSELEXT; @@ -372,6 +381,11 @@ module testbench; uartoutfile = $fopen(uartoutfilename, "w"); // delete UART output file ProgramAddrMapFile = {RISCV_DIR, "/buildroot/output/images/disassembly/vmlinux.objdump.addr"}; ProgramLabelMapFile = {RISCV_DIR, "/buildroot/output/images/disassembly/vmlinux.objdump.lab"}; + end else if(TEST == "fpga") begin + bootmemfilename = {WALLY_DIR, "/fpga/src/boot.mem"}; + memfilename = {WALLY_DIR, "/fpga/src/data.mem"}; + ProgramAddrMapFile = {WALLY_DIR, "/fpga/zsbl/bin/boot.objdump.addr"}; + ProgramLabelMapFile = {WALLY_DIR, "/fpga/zsbl/bin/boot.objdump.lab"}; end else if(ElfFile != "none") begin elffilename = ElfFile; memfilename = {ElfFile, ".memfile"}; @@ -506,6 +520,23 @@ module testbench; end readResult = $fread(dut.uncoregen.uncore.ram.ram.memory.ram.RAM, memFile); $fclose(memFile); + end else if (TEST == "fpga") begin + memFile = $fopen(bootmemfilename, "rb"); + if (memFile == 0) begin + $display("Error: Could not open file %s", memfilename); + $finish; + end + if (P.BOOTROM_SUPPORTED) begin + readResult = $fread(dut.uncoregen.uncore.bootrom.bootrom.memory.ROM, memFile); + end + $fclose(memFile); + memFile = $fopen(memfilename, "rb"); + if (memFile == 0) begin + $display("Error: Could not open file %s", memfilename); + $finish; + end + readResult = $fread(dut.uncoregen.uncore.ram.ram.memory.ram.RAM, memFile); + $fclose(memFile); end else begin uncoreMemFile = $fopen(memfilename, "r"); // Is there a better way to test if a file exists? if (uncoreMemFile == 0) begin @@ -585,16 +616,16 @@ module testbench; assign SDCDat = sd_dat_reg_t ? sd_dat_reg_o : sd_dat_i; assign SDCDatIn = SDCDat; -----/\----- EXCLUDED -----/\----- */ - assign SDCIntr = 1'b0; end else begin - assign SDCIntr = 1'b0; + assign SDCIn = 1'b1; + end wallypipelinedsoc #(P) dut(.clk, .reset_ext, .reset, .ExternalStall(RVVIStall), - .HRDATAEXT, .HREADYEXT, .HRESPEXT, .HSELEXT, .HSELEXTSDC, + .HRDATAEXT, .HREADYEXT, .HRESPEXT, .HSELEXT, .HCLK, .HRESETn, .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HSIZE, .HBURST, .HPROT, .HTRANS, .HMASTLOCK, .HREADY, .TIMECLK(1'b0), .GPIOIN, .GPIOOUT, .GPIOEN, - .UARTSin, .UARTSout, .SDCIntr, .SPIIn, .SPIOut, .SPICS); + .UARTSin, .UARTSout, .SPIIn, .SPIOut, .SPICS, .SPICLK, .SDCIn, .SDCCmd, .SDCCS, .SDCCLK); // generate clock to sequence tests always begin @@ -957,6 +988,12 @@ test_pmp_coverage #(P) pmp_inst(clk); /* verilator lint_on WIDTHTRUNC */ /* verilator lint_on WIDTHEXPAND */ +`ifdef RVVI_COVERAGE + rvviTrace #(.XLEN(P.XLEN), .FLEN(P.FLEN)) rvvi(); + wallyTracer #(P) wallyTracer(rvvi); + wrapper #(P) wrap(clk); +`endif + endmodule /* verilator lint_on STMTDLY */ diff --git a/testbench/wallywrapper.sv b/testbench/wallywrapper.sv index 13092098a..62c7b67e7 100644 --- a/testbench/wallywrapper.sv +++ b/testbench/wallywrapper.sv @@ -32,7 +32,7 @@ module wallywrapper import cvw::*;( input logic clk, input logic reset_ext, input logic SPIIn, - input logic SDCIntr + input logic SDCIn ); `include "parameter-defs.vh" @@ -56,10 +56,15 @@ module wallywrapper import cvw::*;( logic UARTSin, UARTSout; logic SPIOut; logic [3:0] SPICS; + logic SPICLK; + + logic SDCCmd; + logic [3:0] SDCCS; + logic SDCCLK; logic HREADY; logic HSELEXT; - logic HSELEXTSDC; + logic ExternalStall; // instantiate device to be tested @@ -72,9 +77,9 @@ module wallywrapper import cvw::*;( assign ExternalStall = '0; - wallypipelinedsoc #(P) dut(.clk, .reset_ext, .reset, .ExternalStall, .HRDATAEXT,.HREADYEXT, .HRESPEXT,.HSELEXT, .HSELEXTSDC, + wallypipelinedsoc #(P) dut(.clk, .reset_ext, .reset, .ExternalStall, .HRDATAEXT,.HREADYEXT, .HRESPEXT,.HSELEXT, .HCLK, .HRESETn, .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HSIZE, .HBURST, .HPROT, .HTRANS, .HMASTLOCK, .HREADY, .TIMECLK(1'b0), .GPIOIN, .GPIOOUT, .GPIOEN, - .UARTSin, .UARTSout, .SPIIn, .SPIOut, .SPICS, .SDCIntr); + .UARTSin, .UARTSout, .SPIIn, .SPIOut, .SPICS, .SPICLK, .SDCIn, .SDCCmd, .SDCCS, .SDCCLK); endmodule diff --git a/tests/riscof/Makefile b/tests/riscof/Makefile index aaa8a8344..1d42cf10c 100644 --- a/tests/riscof/Makefile +++ b/tests/riscof/Makefile @@ -4,13 +4,18 @@ work_dir = ./riscof_work work = ./work arch_workdir = $(work)/riscv-arch-test wally_workdir = $(work)/wally-riscv-arch-test +custom_test_dir = ../../addins/cvw-arch-verif/test +submodule_work_dir = ../../addins/cvw-arch-verif/riscof_work current_dir = $(shell pwd) #XLEN ?= 64 all: root arch32 wally32 arch32e arch64 wally64 + wally-riscv-arch-test: root wally64 wally32 +custom: new_test + root: mkdir -p $(work_dir) mkdir -p $(work) @@ -47,6 +52,9 @@ wally64: quad64: riscof run --work-dir=$(work_dir) --config=config64.ini --suite=$(wally_dir)/riscv-test-suite/rv64i_m/Q/riscv-ctg/tests/ --env=$(wally_dir)/riscv-test-suite/env + +new_test: + riscof run --work-dir=$(submodule_work_dir) --config=config64.ini --suite=$(custom_test_dir)/ --env=$(wally_dir)/riscv-test-suite/env --no-browser #wally32e: # riscof run --work-dir=$(work_dir) --config=config32e.ini --suite=$(wally_dir)/riscv-test-suite/ --env=$(wally_dir)/riscv-test-suite/env --no-browser --no-dut-run @@ -66,3 +74,4 @@ clean: rm -rf $(work_dir) rm -rf $(wally_workdir) rm -rf $(arch_workdir) + rm -rf $(submodule_wor_dir)