diff --git a/addins/riscv-arch-test b/addins/riscv-arch-test index 873d16e74..197179fdc 160000 --- a/addins/riscv-arch-test +++ b/addins/riscv-arch-test @@ -1 +1 @@ -Subproject commit 873d16e748ad60023dcdda3926144957c096e31d +Subproject commit 197179fdc9dfeeca821e848f373c897a3fdae86c diff --git a/config/buildroot/config.vh b/config/buildroot/config.vh index 7b13a27f2..7d68affc0 100644 --- a/config/buildroot/config.vh +++ b/config/buildroot/config.vh @@ -119,6 +119,9 @@ localparam logic [63:0] PLIC_RANGE = 64'h03FFFFFF; localparam SDC_SUPPORTED = 1'b0; localparam logic [63:0] SDC_BASE = 64'h00013000; localparam logic [63:0] SDC_RANGE = 64'h0000007F; +localparam SPI_SUPPORTED = 1'b1; +localparam logic [63:0] SPI_BASE = 64'h10040000; +localparam logic [63:0] SPI_RANGE = 64'h00000FFF; // Bus Interface width localparam AHBW = 32'd64; @@ -127,6 +130,7 @@ localparam AHBW = 32'd64; // Tie GPIO outputs back to inputs localparam GPIO_LOOPBACK_TEST = 0; +localparam SPI_LOOPBACK_TEST = 0; // Hardware configuration localparam UART_PRESCALE = 32'd0; @@ -136,6 +140,7 @@ localparam PLIC_NUM_SRC = 32'd53; localparam PLIC_NUM_SRC_LT_32 = (PLIC_NUM_SRC < 32); localparam PLIC_UART_ID = 32'd10; localparam PLIC_GPIO_ID = 32'd3; +localparam PLIC_SPI_ID = 32'd6; localparam PLIC_SDC_ID = 32'd20; localparam BPRED_SUPPORTED = 1; diff --git a/config/fpga/config.vh b/config/fpga/config.vh index e690335f3..9ed009439 100644 --- a/config/fpga/config.vh +++ b/config/fpga/config.vh @@ -136,10 +136,15 @@ localparam SDC_SUPPORTED = 1'b1; localparam logic [63:0] SDC_BASE = 64'h00013000; localparam logic [63:0] SDC_RANGE = 64'h0000007F; +localparam SPI_SUPPORTED = 1'b1; +localparam logic [63:0] SPI_BASE = 64'h10040000; +localparam logic [63:0] SPI_RANGE = 64'h00000FFF; + // Test modes // Tie GPIO outputs back to inputs localparam GPIO_LOOPBACK_TEST = 0; +localparam SPI_LOOPBACK_TEST = 0; // Hardware configuration localparam UART_PRESCALE = 32'd0; @@ -150,6 +155,7 @@ localparam PLIC_NUM_SRC = 32'd53; localparam PLIC_NUM_SRC_LT_32 = (PLIC_NUM_SRC < 32); localparam PLIC_GPIO_ID = 32'd3; localparam PLIC_UART_ID = 32'd10; +localparam PLIC_SPI_ID = 32'd6; localparam PLIC_SDC_ID = 32'd20; localparam BPRED_SUPPORTED = 1; diff --git a/config/rv32e/config.vh b/config/rv32e/config.vh index 915ab7677..98d44eb18 100644 --- a/config/rv32e/config.vh +++ b/config/rv32e/config.vh @@ -120,6 +120,9 @@ localparam logic [63:0] PLIC_RANGE = 64'h03FFFFFF; localparam SDC_SUPPORTED = 1'b0; localparam logic [63:0] SDC_BASE = 64'h00013000; localparam logic [63:0] SDC_RANGE = 64'h0000007F; +localparam SPI_SUPPORTED = 1'b0; +localparam logic [63:0] SPI_BASE = 64'h10040000; +localparam logic [63:0] SPI_RANGE = 64'h00000FFF; // Bus Interface width localparam AHBW = 32'd32; @@ -128,6 +131,7 @@ localparam AHBW = 32'd32; // Tie GPIO outputs back to inputs localparam GPIO_LOOPBACK_TEST = 1; +localparam SPI_LOOPBACK_TEST = 0; // Hardware configuration localparam UART_PRESCALE = 32'd1; @@ -138,6 +142,7 @@ localparam PLIC_NUM_SRC = 32'd10; localparam PLIC_NUM_SRC_LT_32 = (PLIC_NUM_SRC < 32); localparam PLIC_GPIO_ID = 32'd3; localparam PLIC_UART_ID = 32'd10; +localparam PLIC_SPI_ID = 32'd6; localparam PLIC_SDC_ID = 32'd9; localparam BPRED_SUPPORTED = 0; diff --git a/config/rv32gc/config.vh b/config/rv32gc/config.vh index a76b42302..a0aacb38f 100644 --- a/config/rv32gc/config.vh +++ b/config/rv32gc/config.vh @@ -121,6 +121,9 @@ localparam logic [63:0] PLIC_RANGE = 64'h03FFFFFF; localparam SDC_SUPPORTED = 1'b0; localparam logic [63:0] SDC_BASE = 64'h00013000; localparam logic [63:0] SDC_RANGE = 64'h0000007F; +localparam SPI_SUPPORTED = 1'b1; +localparam logic [63:0] SPI_BASE = 64'h10040000; +localparam logic [63:0] SPI_RANGE = 64'h00000FFF; // Bus Interface width localparam AHBW = 32'd32; @@ -129,6 +132,7 @@ localparam AHBW = 32'd32; // Tie GPIO outputs back to inputs localparam GPIO_LOOPBACK_TEST = 1; +localparam SPI_LOOPBACK_TEST = 1; // Hardware configuration localparam UART_PRESCALE = 32'd1; @@ -139,6 +143,7 @@ localparam PLIC_NUM_SRC = 32'd10; localparam PLIC_NUM_SRC_LT_32 = (PLIC_NUM_SRC < 32); localparam PLIC_GPIO_ID = 32'd3; localparam PLIC_UART_ID = 32'd10; +localparam PLIC_SPI_ID = 32'd6; localparam PLIC_SDC_ID = 32'd9; localparam BPRED_SUPPORTED = 1; diff --git a/config/rv32i/config.vh b/config/rv32i/config.vh index d25f90135..9ae992e4a 100644 --- a/config/rv32i/config.vh +++ b/config/rv32i/config.vh @@ -120,6 +120,9 @@ localparam logic [63:0] PLIC_RANGE = 64'h03FFFFFF; localparam SDC_SUPPORTED = 1'b0; localparam logic [63:0] SDC_BASE = 64'h00013000; localparam logic [63:0] SDC_RANGE = 64'h0000007F; +localparam SPI_SUPPORTED = 1'b0; +localparam logic [63:0] SPI_BASE = 64'h10040000; +localparam logic [63:0] SPI_RANGE = 64'h00000FFF; // Bus Interface width localparam AHBW = 32'd32; @@ -128,6 +131,7 @@ localparam AHBW = 32'd32; // Tie GPIO outputs back to inputs localparam GPIO_LOOPBACK_TEST = 1; +localparam SPI_LOOPBACK_TEST = 1; // Hardware configuration localparam UART_PRESCALE = 32'd1; @@ -138,6 +142,8 @@ localparam PLIC_NUM_SRC = 32'd10; localparam PLIC_NUM_SRC_LT_32 = (PLIC_NUM_SRC < 32); localparam PLIC_GPIO_ID = 32'd3; localparam PLIC_UART_ID = 32'd10; +localparam PLIC_SPI_ID = 32'd6; + localparam PLIC_SDC_ID = 32'd9; localparam BPRED_SUPPORTED = 0; diff --git a/config/rv32imc/config.vh b/config/rv32imc/config.vh index 9fafafe71..ec5bc0e15 100644 --- a/config/rv32imc/config.vh +++ b/config/rv32imc/config.vh @@ -119,6 +119,9 @@ localparam logic [63:0] PLIC_RANGE = 64'h03FFFFFF; localparam SDC_SUPPORTED = 1'b0; localparam logic [63:0] SDC_BASE = 64'h00013000; localparam logic [63:0] SDC_RANGE = 64'h0000007F; +localparam SPI_SUPPORTED = 1'b1; +localparam logic [63:0] SPI_BASE = 64'h10040000; +localparam logic [63:0] SPI_RANGE = 64'h00000FFF; // Bus Interface width localparam AHBW = 32'd32; @@ -127,6 +130,7 @@ localparam AHBW = 32'd32; // Tie GPIO outputs back to inputs localparam GPIO_LOOPBACK_TEST = 1; +localparam SPI_LOOPBACK_TEST = 1; // Hardware configuration localparam UART_PRESCALE = 32'd1; @@ -137,6 +141,7 @@ localparam PLIC_NUM_SRC = 32'd10; localparam PLIC_NUM_SRC_LT_32 = (PLIC_NUM_SRC < 32); localparam PLIC_GPIO_ID = 32'd3; localparam PLIC_UART_ID = 32'd10; +localparam PLIC_SPI_ID = 32'd6; localparam PLIC_SDC_ID = 32'd9; localparam BPRED_SUPPORTED = 0; diff --git a/config/rv64fpquad/config.vh b/config/rv64fpquad/config.vh index 343de8b11..0fffba91e 100644 --- a/config/rv64fpquad/config.vh +++ b/config/rv64fpquad/config.vh @@ -125,11 +125,15 @@ localparam logic [63:0] PLIC_RANGE = 64'h03FFFFFF; localparam SDC_SUPPORTED = 1'b0; localparam logic [63:0] SDC_BASE = 64'h00013000; localparam logic [63:0] SDC_RANGE = 64'h0000007F; +localparam SPI_SUPPORTED = 1'b1; +localparam logic [63:0] SPI_BASE = 64'h10040000; +localparam logic [63:0] SPI_RANGE = 64'h00000FFF; // Test modes // Tie GPIO outputs back to inputs localparam GPIO_LOOPBACK_TEST = 1; +localparam SPI_LOOPBACK_TEST = 1; // Hardware configuration localparam UART_PRESCALE = 32'd1; @@ -140,6 +144,7 @@ localparam PLIC_NUM_SRC = 32'd10; localparam PLIC_NUM_SRC_LT_32 = (PLIC_NUM_SRC < 32); localparam PLIC_GPIO_ID = 32'd3; localparam PLIC_UART_ID = 32'd10; +localparam PLIC_SPI_ID = 32'd6; localparam PLIC_SDC_ID = 32'd9; localparam BPRED_SUPPORTED = 1; diff --git a/config/rv64gc/config.vh b/config/rv64gc/config.vh index 5853f87a4..af2402b4f 100644 --- a/config/rv64gc/config.vh +++ b/config/rv64gc/config.vh @@ -125,11 +125,15 @@ localparam logic [63:0] PLIC_RANGE = 64'h03FFFFFF; localparam SDC_SUPPORTED = 1'b0; localparam logic [63:0] SDC_BASE = 64'h00013000; localparam logic [63:0] SDC_RANGE = 64'h0000007F; +localparam SPI_SUPPORTED = 1'b1; +localparam logic [63:0] SPI_BASE = 64'h10040000; +localparam logic [63:0] SPI_RANGE = 64'h00000FFF; // Test modes // Tie GPIO outputs back to inputs localparam GPIO_LOOPBACK_TEST = 1; +localparam SPI_LOOPBACK_TEST = 1; // Hardware configuration localparam UART_PRESCALE = 32'd1; @@ -140,6 +144,7 @@ localparam PLIC_NUM_SRC = 32'd10; localparam PLIC_NUM_SRC_LT_32 = (PLIC_NUM_SRC < 32); localparam PLIC_GPIO_ID = 32'd3; localparam PLIC_UART_ID = 32'd10; +localparam PLIC_SPI_ID = 32'd6; localparam PLIC_SDC_ID = 32'd9; localparam BPRED_SUPPORTED = 1; diff --git a/config/rv64i/config.vh b/config/rv64i/config.vh index 35fe763a5..028d47c91 100644 --- a/config/rv64i/config.vh +++ b/config/rv64i/config.vh @@ -125,11 +125,15 @@ localparam logic [63:0] PLIC_RANGE = 64'h03FFFFFF; localparam SDC_SUPPORTED = 1'b0; localparam logic [63:0] SDC_BASE = 64'h00013000; localparam logic [63:0] SDC_RANGE = 64'h0000007F; +localparam SPI_SUPPORTED = 1'b0; +localparam logic [63:0] SPI_BASE = 64'h10040000; +localparam logic [63:0] SPI_RANGE = 64'h00000FFF; // Test modes // Tie GPIO outputs back to inputs localparam GPIO_LOOPBACK_TEST = 1; +localparam SPI_LOOPBACK_TEST = 1; // Hardware configuration localparam UART_PRESCALE = 32'd1; @@ -140,6 +144,7 @@ localparam PLIC_NUM_SRC = 32'd10; localparam PLIC_NUM_SRC_LT_32 = (PLIC_NUM_SRC < 32); localparam PLIC_GPIO_ID = 32'd3; localparam PLIC_UART_ID = 32'd10; +localparam PLIC_SPI_ID = 32'd6; localparam PLIC_SDC_ID = 32'd9; localparam BPRED_SUPPORTED = 0; diff --git a/config/shared/parameter-defs.vh b/config/shared/parameter-defs.vh index d79a18b40..dfb41ef9f 100644 --- a/config/shared/parameter-defs.vh +++ b/config/shared/parameter-defs.vh @@ -74,12 +74,17 @@ localparam cvw_t P = '{ SDC_SUPPORTED : SDC_SUPPORTED, SDC_BASE : SDC_BASE, SDC_RANGE : SDC_RANGE, + SPI_SUPPORTED : SPI_SUPPORTED, + SPI_BASE : SPI_BASE, + SPI_RANGE : SPI_RANGE, GPIO_LOOPBACK_TEST : GPIO_LOOPBACK_TEST, + SPI_LOOPBACK_TEST : SPI_LOOPBACK_TEST, UART_PRESCALE : UART_PRESCALE , PLIC_NUM_SRC : PLIC_NUM_SRC, PLIC_NUM_SRC_LT_32 : PLIC_NUM_SRC_LT_32, PLIC_GPIO_ID : PLIC_GPIO_ID, PLIC_UART_ID : PLIC_UART_ID, + PLIC_SPI_ID : PLIC_SPI_ID, PLIC_SDC_ID : PLIC_SDC_ID, BPRED_SUPPORTED : BPRED_SUPPORTED, /* verilator lint_off ENUMVALUE */ diff --git a/setup.csh b/setup.csh index 58b0918dd..0508c36d0 100755 --- a/setup.csh +++ b/setup.csh @@ -6,7 +6,7 @@ echo "Executing Wally setup.csh" # Path to Wally repository -set WALLY = $PWD +setenv WALLY $PWD echo '$WALLY set to ' ${WALLY} # Extend alias which makes extending PATH much easier. diff --git a/sim/imperas.ic b/sim/imperas.ic index 0afb81c10..adb10dcad 100644 --- a/sim/imperas.ic +++ b/sim/imperas.ic @@ -11,16 +11,21 @@ --override refRoot/cpu/tvec_align=64 # bit manipulation ---override cpu/add_implicit_Extensions=B +--override cpu/add_Extensions=B +#--override cpu/add_implicit_Extensions=B --override cpu/bitmanip_version=1.0.0 # More extensions +--override cpu/Zcb=T + +# Cache block operations --override cpu/Zicbom=T --override cpu/Zicbop=T --override cpu/Zicboz=T ---override cpu/Svpbmt=T + # 64 KiB continuous huge pages supported ---override cpu/Svnapot_page_mask=1<<16 +--override cpu/Svpbmt=T +--override cpu/Svnapot_page_mask=65536 # clarify @@ -39,10 +44,14 @@ --override cpu/ignore_non_leaf_DAU=1 --override cpu/wfi_is_nop=T --override cpu/misa_Extensions_mask=0x0 ---override cpu/updatePTEA=T ---override cpu/updatePTED=T --override cpu/Sstc=T +# Enable SVADU hardware update of A/D bits when menvcfg.HADE=1 +--override cpu/Svadu=T +--override cpu/updatePTEA=F +--override cpu/updatePTED=F + + # THIS NEEDS FIXING to 16 --override cpu/PMP_registers=16 --override cpu/PMP_undefined=T @@ -68,7 +77,8 @@ --callcommand refRoot/cpu/setPMA -lo 0x0002000000 -hi 0x000200FFFF -attributes " rw--A- 1248 " # CLINT --callcommand refRoot/cpu/setPMA -lo 0x000C000000 -hi 0x000FFFFFFF -attributes " rw--A- --4- " # PLIC --callcommand refRoot/cpu/setPMA -lo 0x0010000000 -hi 0x0010000007 -attributes " rw--A- 1--- " # UART0 error - 0x10000000 - 0x100000FF ---callcommand refRoot/cpu/setPMA -lo 0x0010060000 -hi 0x00100600FF -attributes " rw--A- --4- " # GPIO error - 0x10006000 - 0x100060FF +--callcommand refRoot/cpu/setPMA -lo 0x0010060000 -hi 0x00100600FF -attributes " rw--A- --4- " # GPIO error - 0x10069000 - 0x100600FF +--callcommand refRoot/cpu/setPMA -lo 0x0010040000 -hi 0x0010040FFF -attributes " rw--A- --4- " # SPI error - 0x10040000 - 0x10040FFF --callcommand refRoot/cpu/setPMA -lo 0x0080000000 -hi 0x008FFFFFFF -attributes " rwx--- 1248 " # UNCORE_RAM # Enable the Imperas instruction coverage diff --git a/sim/sim-wally b/sim/sim-wally index 6ffc3ca4f..78558c7f1 100755 --- a/sim/sim-wally +++ b/sim/sim-wally @@ -1,2 +1,2 @@ -vsim -do "do wally.do rv64gc wally64priv" +vsim -do "do wally.do rv64gc wally64periph" diff --git a/sim/sim-wally-batch b/sim/sim-wally-batch index f2c2a3c30..38caa95f3 100755 --- a/sim/sim-wally-batch +++ b/sim/sim-wally-batch @@ -1 +1 @@ -vsim -c -do "do wally-batch.do rv64gc wally64priv" +vsim -c -do "do wally-batch.do rv64gc wally64periph" diff --git a/sim/verilate b/sim/verilate index 7aab1ba63..c59494c1d 100755 --- a/sim/verilate +++ b/sim/verilate @@ -8,15 +8,9 @@ basepath=$(dirname $0)/.. #for config in rv32e rv64gc rv32gc rv32imc rv32i rv64i rv64fpquad; do for config in rv64gc; do echo "$config simulating..." - if !($verilator --timescale "1ns/1ns" --timing --cc "$@" --top-module testbench "-I$basepath/config/shared" "-I$basepath/config/$config" $basepath/src/wally/cvw.sv $basepath/testbench/common/*.sv $basepath/testbench/testbench.sv $basepath/src/*/*.sv $basepath/src/*/*/*.sv --relative-includes ); then + if !($verilator --timescale "1ns/1ns" --timing --exe --cc "$@" --top-module testbench "-I$basepath/config/shared" "-I$basepath/config/$config" $basepath/src/cvw.sv $basepath/testbench/testbench.sv $basepath/testbench/common/*.sv $basepath/src/*/*.sv $basepath/src/*/*/*.sv --relative-includes ); then echo "Exiting after $config lint due to errors or warnings" exit 1 fi done -echo "All lints run with no errors or warnings" - -# --lint-only just runs lint rather than trying to compile and simulate -# -I points to the include directory where files such as `include config.vh are found - -# For more exhaustive (and sometimes spurious) warnings, add --Wall to the Verilator command -# Unfortunately, this produces a bunch of UNUSED and UNDRIVEN signal warnings in blocks that are configured to not exist. +echo "Verilation complete" diff --git a/src/cache/cacheway.sv b/src/cache/cacheway.sv index 216cd82d2..f64397070 100644 --- a/src/cache/cacheway.sv +++ b/src/cache/cacheway.sv @@ -126,7 +126,7 @@ module cacheway import cvw::*; #(parameter cvw_t P, // Tag Array ///////////////////////////////////////////////////////////////////////////////////////////// - ram1p1rwe #(.P(P), .DEPTH(NUMLINES), .WIDTH(TAGLEN)) CacheTagMem(.clk, .ce(CacheEn), + ram1p1rwe #(.USE_SRAM(P.USE_SRAM), .DEPTH(NUMLINES), .WIDTH(TAGLEN)) CacheTagMem(.clk, .ce(CacheEn), .addr(CacheSet), .dout(ReadTag), .din(PAdr[PA_BITS-1:OFFSETLEN+INDEXLEN]), .we(SetValidEN)); @@ -148,12 +148,12 @@ module cacheway import cvw::*; #(parameter cvw_t P, for(words = 0; words < NUMSRAM; words++) begin: word if (!READ_ONLY_CACHE) begin:wordram - ram1p1rwbe #(.P(P), .DEPTH(NUMLINES), .WIDTH(SRAMLEN)) CacheDataMem(.clk, .ce(CacheEn), .addr(CacheSet), + ram1p1rwbe #(.USE_SRAM(P.USE_SRAM), .DEPTH(NUMLINES), .WIDTH(SRAMLEN)) CacheDataMem(.clk, .ce(CacheEn), .addr(CacheSet), .dout(ReadDataLine[SRAMLEN*(words+1)-1:SRAMLEN*words]), .din(LineWriteData[SRAMLEN*(words+1)-1:SRAMLEN*words]), .we(SelectedWriteWordEn), .bwe(FinalByteMask[SRAMLENINBYTES*(words+1)-1:SRAMLENINBYTES*words])); end else begin:wordram // no byte-enable needed for i$. - ram1p1rwe #(.P(P), .DEPTH(NUMLINES), .WIDTH(SRAMLEN)) CacheDataMem(.clk, .ce(CacheEn), .addr(CacheSet), + ram1p1rwe #(.USE_SRAM(P.USE_SRAM), .DEPTH(NUMLINES), .WIDTH(SRAMLEN)) CacheDataMem(.clk, .ce(CacheEn), .addr(CacheSet), .dout(ReadDataLine[SRAMLEN*(words+1)-1:SRAMLEN*words]), .din(LineWriteData[SRAMLEN*(words+1)-1:SRAMLEN*words]), .we(SelectedWriteWordEn)); diff --git a/src/cvw.sv b/src/cvw.sv index 5e53a4a2b..198042913 100644 --- a/src/cvw.sv +++ b/src/cvw.sv @@ -129,11 +129,15 @@ typedef struct packed { logic SDC_SUPPORTED; logic [63:0] SDC_BASE; logic [63:0] SDC_RANGE; + logic SPI_SUPPORTED; + logic [63:0] SPI_BASE; + logic [63:0] SPI_RANGE; // Test modes // Tie GPIO outputs back to inputs logic GPIO_LOOPBACK_TEST; + logic SPI_LOOPBACK_TEST; // Hardware configuration int UART_PRESCALE ; @@ -143,6 +147,7 @@ typedef struct packed { logic PLIC_NUM_SRC_LT_32; int PLIC_GPIO_ID; int PLIC_UART_ID; + int PLIC_SPI_ID; int PLIC_SDC_ID; logic BPRED_SUPPORTED; diff --git a/src/fpu/fdivsqrt/fdivsqrt.sv b/src/fpu/fdivsqrt/fdivsqrt.sv index 9112da9d1..5c5fa0f57 100644 --- a/src/fpu/fdivsqrt/fdivsqrt.sv +++ b/src/fpu/fdivsqrt/fdivsqrt.sv @@ -68,7 +68,7 @@ module fdivsqrt import cvw::*; #(parameter cvw_t P) ( logic BZeroM; // Denominator is zero logic IntDivM; // Integer operation logic [P.DIVBLEN:0] nM, mM; // Shift amounts - logic NegQuotM, ALTBM, AsM, W64M; // Special handling for postprocessor + logic ALTBM, AsM, BsM, W64M; // Special handling for postprocessor logic [P.XLEN-1:0] AM; // Original Numerator for postprocessor logic ISpecialCaseE; // Integer div/remainder special cases @@ -78,7 +78,7 @@ module fdivsqrt import cvw::*; #(parameter cvw_t P) ( // Int-specific .ForwardedSrcAE, .ForwardedSrcBE, .IntDivE, .W64E, .ISpecialCaseE, .BZeroM, .nM, .mM, .AM, - .IntDivM, .W64M, .NegQuotM, .ALTBM, .AsM); + .IntDivM, .W64M, .ALTBM, .AsM, .BsM); fdivsqrtfsm #(P) fdivsqrtfsm( // FSM .clk, .reset, .XInfE, .YInfE, .XZeroE, .YZeroE, .XNaNE, .YNaNE, @@ -96,6 +96,6 @@ module fdivsqrt import cvw::*; #(parameter cvw_t P) ( .SqrtE, .Firstun, .SqrtM, .SpecialCaseM, .QmM, .WZeroE, .DivStickyM, // Int-specific - .nM, .mM, .ALTBM, .AsM, .BZeroM, .NegQuotM, .W64M, .RemOpM(Funct3M[1]), .AM, + .nM, .mM, .ALTBM, .AsM, .BsM, .BZeroM, .W64M, .RemOpM(Funct3M[1]), .AM, .FIntDivResultM); endmodule diff --git a/src/fpu/fdivsqrt/fdivsqrtcycles.sv b/src/fpu/fdivsqrt/fdivsqrtcycles.sv index 09b17871a..ed28c9355 100644 --- a/src/fpu/fdivsqrt/fdivsqrtcycles.sv +++ b/src/fpu/fdivsqrt/fdivsqrtcycles.sv @@ -65,7 +65,8 @@ module fdivsqrtcycles import cvw::*; #(parameter cvw_t P) ( endcase always_comb begin - if (SqrtE) fbits = Nf + 2 + 2; // Nf + two fractional bits for round/guard + 2 for right shift by up to 2 + if (SqrtE) fbits = Nf + 2 + 1; // Nf + two fractional bits for round/guard + 2 for right shift by up to 2 *** unclear why it works with just +1; is it related to DIVCOPIES logic below? + // if (SqrtE) fbits = Nf + 2 + 2; // Nf + two fractional bits for round/guard + 2 for right shift by up to 2 else fbits = Nf + 2 + P.LOGR; // Nf + two fractional bits for round/guard + integer bits - try this when placing results in msbs if (P.IDIV_ON_FPU) CyclesE = IntDivE ? ((nE + 1)/P.DIVCOPIES) : (fbits + (P.LOGR*P.DIVCOPIES)-1)/(P.LOGR*P.DIVCOPIES); else CyclesE = (fbits + (P.LOGR*P.DIVCOPIES)-1)/(P.LOGR*P.DIVCOPIES); diff --git a/src/fpu/fdivsqrt/fdivsqrtpostproc.sv b/src/fpu/fdivsqrt/fdivsqrtpostproc.sv index 19856e932..c3c558902 100644 --- a/src/fpu/fdivsqrt/fdivsqrtpostproc.sv +++ b/src/fpu/fdivsqrt/fdivsqrtpostproc.sv @@ -34,9 +34,9 @@ module fdivsqrtpostproc import cvw::*; #(parameter cvw_t P) ( input logic [P.DIVb:0] FirstU, FirstUM, input logic [P.DIVb+1:0] FirstC, input logic SqrtE, - input logic Firstun, SqrtM, SpecialCaseM, NegQuotM, + input logic Firstun, SqrtM, SpecialCaseM, input logic [P.XLEN-1:0] AM, - input logic RemOpM, ALTBM, BZeroM, AsM, W64M, + input logic RemOpM, ALTBM, BZeroM, AsM, BsM, W64M, input logic [P.DIVBLEN:0] nM, mM, output logic [P.DIVb:0] QmM, output logic WZeroE, @@ -49,6 +49,7 @@ module fdivsqrtpostproc import cvw::*; #(parameter cvw_t P) ( logic NegStickyM; logic weq0E, WZeroM; logic [P.XLEN-1:0] IntDivResultM; + logic NegQuotM; // Integer quotient is negative ////////////////////////// // Execute Stage: Detect early termination for an exact result @@ -103,6 +104,7 @@ module fdivsqrtpostproc import cvw::*; #(parameter cvw_t P) ( assign UnsignedQuotM = {3'b000, PreQmM}; // Integer remainder: sticky and sign correction muxes + assign NegQuotM = AsM ^ BsM; // Integer Quotient is negative mux2 #(P.DIVb+4) normremdmux(W, W+D, NegStickyM, NormRemDM); mux2 #(P.DIVb+4) normremsmux(NormRemDM, -NormRemDM, AsM, NormRemM); mux2 #(P.DIVb+4) quotresmux(UnsignedQuotM, -UnsignedQuotM, NegQuotM, NormQuotM); diff --git a/src/fpu/fdivsqrt/fdivsqrtpreproc.sv b/src/fpu/fdivsqrt/fdivsqrtpreproc.sv index 5e14d3122..6c397576a 100644 --- a/src/fpu/fdivsqrt/fdivsqrtpreproc.sv +++ b/src/fpu/fdivsqrt/fdivsqrtpreproc.sv @@ -43,8 +43,8 @@ module fdivsqrtpreproc import cvw::*; #(parameter cvw_t P) ( output logic ISpecialCaseE, output logic [P.DURLEN-1:0] CyclesE, output logic [P.DIVBLEN:0] nM, mM, - output logic NegQuotM, ALTBM, IntDivM, W64M, - output logic AsM, BZeroM, + output logic ALTBM, IntDivM, W64M, + output logic AsM, BsM, BZeroM, output logic [P.XLEN-1:0] AM ); @@ -57,7 +57,6 @@ module fdivsqrtpreproc import cvw::*; #(parameter cvw_t P) ( logic NumerZeroE; // Numerator is zero (X or A) logic AZeroE, BZeroE; // A or B is Zero for integer division logic SignedDivE; // signed division - logic NegQuotE; // Integer quotient is negative logic AsE, BsE; // Signs of integer inputs logic [P.XLEN-1:0] AE; // input A after W64 adjustment logic ALTBE; @@ -84,7 +83,6 @@ module fdivsqrtpreproc import cvw::*; #(parameter cvw_t P) ( assign BZeroE = ~(|BE); assign AsE = AE[P.XLEN-1] & SignedDivE; assign BsE = BE[P.XLEN-1] & SignedDivE; - assign NegQuotE = AsE ^ BsE; // Integer Quotient is negative // Force integer inputs to be postiive mux2 #(P.XLEN) posamux(AE, -AE, AsE, PosA); @@ -192,9 +190,9 @@ module fdivsqrtpreproc import cvw::*; #(parameter cvw_t P) ( // pipeline registers flopen #(1) mdureg(clk, IFDivStartE, IntDivE, IntDivM); flopen #(1) altbreg(clk, IFDivStartE, ALTBE, ALTBM); - flopen #(1) negquotreg(clk, IFDivStartE, NegQuotE, NegQuotM); flopen #(1) bzeroreg(clk, IFDivStartE, BZeroE, BZeroM); flopen #(1) asignreg(clk, IFDivStartE, AsE, AsM); + flopen #(1) bsignreg(clk, IFDivStartE, BsE, BsM); flopen #(P.DIVBLEN+1) nreg(clk, IFDivStartE, nE, nM); flopen #(P.DIVBLEN+1) mreg(clk, IFDivStartE, mE, mM); flopen #(P.XLEN) srcareg(clk, IFDivStartE, AE, AM); diff --git a/src/generic/mem/ram1p1rwbe.sv b/src/generic/mem/ram1p1rwbe.sv index 46716aa75..4af3c255c 100644 --- a/src/generic/mem/ram1p1rwbe.sv +++ b/src/generic/mem/ram1p1rwbe.sv @@ -32,8 +32,7 @@ // WIDTH is number of bits in one "word" of the memory, DEPTH is number of such words -module ram1p1rwbe import cvw::*; #(parameter cvw_t P, parameter DEPTH=64, WIDTH=44, - parameter PRELOAD_ENABLED=0) ( +module ram1p1rwbe import cvw::*; #(parameter USE_SRAM=0, DEPTH=64, WIDTH=44, PRELOAD_ENABLED=0) ( input logic clk, input logic ce, input logic [$clog2(DEPTH)-1:0] addr, @@ -48,7 +47,7 @@ module ram1p1rwbe import cvw::*; #(parameter cvw_t P, parameter DEPTH=64, WIDTH= // *************************************************************************** // TRUE SRAM macro // *************************************************************************** - if ((P.USE_SRAM == 1) & (WIDTH == 128) & (DEPTH == 64)) begin // Cache data subarray + if ((USE_SRAM == 1) & (WIDTH == 128) & (DEPTH == 64)) begin // Cache data subarray genvar index; // 64 x 128-bit SRAM logic [WIDTH-1:0] BitWriteMask; @@ -58,7 +57,7 @@ module ram1p1rwbe import cvw::*; #(parameter cvw_t P, parameter DEPTH=64, WIDTH= .A(addr), .D(din), .BWEB(~BitWriteMask), .Q(dout)); - end else if ((P.USE_SRAM == 1) & (WIDTH == 44) & (DEPTH == 64)) begin // RV64 cache tag + end else if ((USE_SRAM == 1) & (WIDTH == 44) & (DEPTH == 64)) begin // RV64 cache tag genvar index; // 64 x 44-bit SRAM logic [WIDTH-1:0] BitWriteMask; @@ -68,7 +67,7 @@ module ram1p1rwbe import cvw::*; #(parameter cvw_t P, parameter DEPTH=64, WIDTH= .A(addr), .D(din), .BWEB(~BitWriteMask), .Q(dout)); - end else if ((P.USE_SRAM == 1) & (WIDTH == 22) & (DEPTH == 64)) begin // RV32 cache tag + end else if ((USE_SRAM == 1) & (WIDTH == 22) & (DEPTH == 64)) begin // RV32 cache tag genvar index; // 64 x 22-bit SRAM logic [WIDTH-1:0] BitWriteMask; diff --git a/src/generic/mem/ram1p1rwe.sv b/src/generic/mem/ram1p1rwe.sv index 40929544a..e3746c181 100644 --- a/src/generic/mem/ram1p1rwe.sv +++ b/src/generic/mem/ram1p1rwe.sv @@ -30,8 +30,7 @@ // WIDTH is number of bits in one "word" of the memory, DEPTH is number of such words -module ram1p1rwe import cvw::* ; #(parameter cvw_t P, - parameter DEPTH=64, WIDTH=44) ( +module ram1p1rwe import cvw::* ; #(parameter USE_SRAM=0, DEPTH=64, WIDTH=44) ( input logic clk, input logic ce, input logic [$clog2(DEPTH)-1:0] addr, @@ -45,19 +44,19 @@ module ram1p1rwe import cvw::* ; #(parameter cvw_t P, // *************************************************************************** // TRUE SRAM macro // *************************************************************************** - if ((P.USE_SRAM == 1) & (WIDTH == 128) & (DEPTH == 64)) begin // Cache data subarray + if ((USE_SRAM == 1) & (WIDTH == 128) & (DEPTH == 64)) begin // Cache data subarray // 64 x 128-bit SRAM ram1p1rwbe_64x128 sram1A (.CLK(clk), .CEB(~ce), .WEB(~we), .A(addr), .D(din), .BWEB('0), .Q(dout)); - end else if ((P.USE_SRAM == 1) & (WIDTH == 44) & (DEPTH == 64)) begin // RV64 cache tag + end else if ((USE_SRAM == 1) & (WIDTH == 44) & (DEPTH == 64)) begin // RV64 cache tag // 64 x 44-bit SRAM ram1p1rwbe_64x44 sram1B (.CLK(clk), .CEB(~ce), .WEB(~we), .A(addr), .D(din), .BWEB('0), .Q(dout)); - end else if ((P.USE_SRAM == 1) & (WIDTH == 22) & (DEPTH == 64)) begin // RV32 cache tag + end else if ((USE_SRAM == 1) & (WIDTH == 22) & (DEPTH == 64)) begin // RV32 cache tag // 64 x 22-bit SRAM ram1p1rwbe_64x22 sram1 (.CLK(clk), .CEB(~ce), .WEB(~we), .A(addr), .D(din), diff --git a/src/generic/mem/ram2p1r1wbe.sv b/src/generic/mem/ram2p1r1wbe.sv index 202d0432b..1ac11a633 100644 --- a/src/generic/mem/ram2p1r1wbe.sv +++ b/src/generic/mem/ram2p1r1wbe.sv @@ -31,8 +31,7 @@ // WIDTH is number of bits in one "word" of the memory, DEPTH is number of such words -module ram2p1r1wbe import cvw::*; #(parameter cvw_t P, - parameter DEPTH=1024, WIDTH=68) ( +module ram2p1r1wbe import cvw::*; #(parameter USE_SRAM=0, DEPTH=1024, WIDTH=68) ( input logic clk, input logic ce1, ce2, input logic [$clog2(DEPTH)-1:0] ra1, @@ -51,7 +50,7 @@ module ram2p1r1wbe import cvw::*; #(parameter cvw_t P, // TRUE Smem macro // *************************************************************************** - if ((P.USE_SRAM == 1) & (WIDTH == 68) & (DEPTH == 1024)) begin + if ((USE_SRAM == 1) & (WIDTH == 68) & (DEPTH == 1024)) begin ram2p1r1wbe_1024x68 memory1(.CLKA(clk), .CLKB(clk), .CEBA(~ce1), .CEBB(~ce2), @@ -63,7 +62,7 @@ module ram2p1r1wbe import cvw::*; #(parameter cvw_t P, .QA(rd1), .QB()); - end else if ((P.USE_SRAM == 1) & (WIDTH == 36) & (DEPTH == 1024)) begin + end else if ((USE_SRAM == 1) & (WIDTH == 36) & (DEPTH == 1024)) begin ram2p1r1wbe_1024x36 memory1(.CLKA(clk), .CLKB(clk), .CEBA(~ce1), .CEBB(~ce2), @@ -75,7 +74,7 @@ module ram2p1r1wbe import cvw::*; #(parameter cvw_t P, .QA(rd1), .QB()); - end else if ((P.USE_SRAM == 1) & (WIDTH == 2) & (DEPTH == 1024)) begin + end else if ((USE_SRAM == 1) & (WIDTH == 2) & (DEPTH == 1024)) begin logic [SRAMWIDTH-1:0] SRAMReadData; logic [SRAMWIDTH-1:0] SRAMWriteData; diff --git a/src/generic/mem/rom1p1r.sv b/src/generic/mem/rom1p1r.sv index 60d041423..93f8c82df 100644 --- a/src/generic/mem/rom1p1r.sv +++ b/src/generic/mem/rom1p1r.sv @@ -25,9 +25,7 @@ // This model actually works correctly with vivado. -module rom1p1r #(parameter ADDR_WIDTH = 8, - parameter DATA_WIDTH = 32, - parameter PRELOAD_ENABLED = 0) +module rom1p1r #(parameter ADDR_WIDTH = 8, DATA_WIDTH = 32, PRELOAD_ENABLED = 0) (input logic clk, input logic ce, input logic [ADDR_WIDTH-1:0] addr, diff --git a/src/ifu/bpred/btb.sv b/src/ifu/bpred/btb.sv index e93c1decb..066176daa 100644 --- a/src/ifu/bpred/btb.sv +++ b/src/ifu/bpred/btb.sv @@ -92,7 +92,7 @@ module btb import cvw::*; #(parameter cvw_t P, // An optimization may be using a PC relative address. - ram2p1r1wbe #(P, 2**Depth, P.XLEN+4) memory( + ram2p1r1wbe #(.USE_SRAM(P.USE_SRAM), .DEPTH(2**Depth), .WIDTH(P.XLEN+4)) memory( .clk, .ce1(~StallF | reset), .ra1(PCNextFIndex), .rd1(TableBTBPredF), .ce2(~StallW & ~FlushW), .wa2(PCMIndex), .wd2({InstrClassM, IEUAdrM}), .we2(BTBWrongM), .bwe2('1)); diff --git a/src/ifu/bpred/gshare.sv b/src/ifu/bpred/gshare.sv index 460acbcbf..fcdf46655 100644 --- a/src/ifu/bpred/gshare.sv +++ b/src/ifu/bpred/gshare.sv @@ -84,7 +84,7 @@ module gshare import cvw::*; #(parameter cvw_t P, assign BPDirPredF = MatchX ? FwdNewDirPredF : TableBPDirPredF; - ram2p1r1wbe #(P, 2**k, 2) PHT(.clk(clk), + ram2p1r1wbe #(.USE_SRAM(P.USE_SRAM), .DEPTH(2**k), .WIDTH(2)) PHT(.clk(clk), .ce1(~StallF), .ce2(~StallW & ~FlushW), .ra1(IndexNextF), .rd1(TableBPDirPredF), diff --git a/src/ifu/bpred/gsharebasic.sv b/src/ifu/bpred/gsharebasic.sv index 2914c3e3f..7ae9f0282 100644 --- a/src/ifu/bpred/gsharebasic.sv +++ b/src/ifu/bpred/gsharebasic.sv @@ -58,7 +58,7 @@ module gsharebasic import cvw::*; #(parameter cvw_t P, assign IndexM = GHRM; end - ram2p1r1wbe #(P, 2**k, 2) PHT(.clk(clk), + ram2p1r1wbe #(.USE_SRAM(P.USE_SRAM), .DEPTH(2**k), .WIDTH(2)) PHT(.clk(clk), .ce1(~StallF), .ce2(~StallW & ~FlushW), .ra1(IndexNextF), .rd1(BPDirPredF), diff --git a/src/ifu/bpred/localaheadbp.sv b/src/ifu/bpred/localaheadbp.sv index 266219416..4d6d536a7 100644 --- a/src/ifu/bpred/localaheadbp.sv +++ b/src/ifu/bpred/localaheadbp.sv @@ -59,7 +59,7 @@ module localaheadbp import cvw::*; #(parameter cvw_t P, //assign IndexNextF = LHR; assign IndexM = LHRW; - ram2p1r1wbe #(P, 2**k, 2) PHT(.clk(clk), + ram2p1r1wbe #(.USE_SRAM(P.USE_SRAM), .DEPTH(2**k), .WIDTH(2)) PHT(.clk(clk), .ce1(~StallD), .ce2(~StallW & ~FlushW), .ra1(LHRF), .rd1(BPDirPredD), @@ -92,7 +92,7 @@ module localaheadbp import cvw::*; #(parameter cvw_t P, assign IndexLHRM = {PCW[m+1] ^ PCW[1], PCW[m:2]}; assign IndexLHRNextF = {PCNextF[m+1] ^ PCNextF[1], PCNextF[m:2]}; - ram2p1r1wbe #(P, 2**m, k) BHT(.clk(clk), + ram2p1r1wbe #(.USE_SRAM(P.USE_SRAM), .DEPTH(2**m), .WIDTH(k)) BHT(.clk(clk), .ce1(~StallF), .ce2(~StallW & ~FlushW), .ra1(IndexLHRNextF), .rd1(LHRF), diff --git a/src/ifu/bpred/localbpbasic.sv b/src/ifu/bpred/localbpbasic.sv index 8037b743d..d3a694c33 100644 --- a/src/ifu/bpred/localbpbasic.sv +++ b/src/ifu/bpred/localbpbasic.sv @@ -56,7 +56,7 @@ module localbpbasic import cvw::*; #(parameter cvw_t P, assign IndexNextF = LHR; assign IndexM = LHRM; - ram2p1r1wbe #(P, 2**k, 2) PHT(.clk(clk), + ram2p1r1wbe #(.USE_SRAM(P.USE_SRAM), .DEPTH(2**k), .WIDTH(2)) PHT(.clk(clk), .ce1(~StallF), .ce2(~StallW & ~FlushW), .ra1(IndexNextF), .rd1(BPDirPredF), diff --git a/src/ifu/bpred/localrepairbp.sv b/src/ifu/bpred/localrepairbp.sv index 3af6d7b9f..95399e65a 100644 --- a/src/ifu/bpred/localrepairbp.sv +++ b/src/ifu/bpred/localrepairbp.sv @@ -58,7 +58,7 @@ module localrepairbp import cvw::*; #(parameter cvw_t P, logic SpeculativeFlushedF; - ram2p1r1wbe #(P, 2**k, 2) PHT(.clk(clk), + ram2p1r1wbe #(.USE_SRAM(P.USE_SRAM), .DEPTH(2**k), .WIDTH(2)) PHT(.clk(clk), .ce1(~StallD), .ce2(~StallW & ~FlushW), .ra1(LHRF), .rd1(BPDirPredD), @@ -89,7 +89,7 @@ module localrepairbp import cvw::*; #(parameter cvw_t P, assign IndexLHRM = {PCW[m+1] ^ PCW[1], PCW[m:2]}; assign IndexLHRNextF = {PCNextF[m+1] ^ PCNextF[1], PCNextF[m:2]}; - ram2p1r1wbe #(P, 2**m, k) BHT(.clk(clk), + ram2p1r1wbe #(.USE_SRAM(P.USE_SRAM), .DEPTH(2**m), .WIDTH(k)) BHT(.clk(clk), .ce1(~StallF), .ce2(~StallW & ~FlushW), .ra1(IndexLHRNextF), .rd1(LHRCommittedF), @@ -101,7 +101,7 @@ module localrepairbp import cvw::*; #(parameter cvw_t P, assign IndexLHRD = {PCE[m+1] ^ PCE[1], PCE[m:2]}; assign LHRNextE = BranchD ? {BPDirPredD[1], LHRE[k-1:1]} : LHRE; // *** replace with a small CAM - ram2p1r1wbe #(P, 2**m, k) SHB(.clk(clk), + ram2p1r1wbe #(.USE_SRAM(P.USE_SRAM), .DEPTH(2**m), .WIDTH(k)) SHB(.clk(clk), .ce1(~StallF), .ce2(~StallE & ~FlushE), .ra1(IndexLHRNextF), .rd1(LHRSpeculativeF), diff --git a/src/ifu/bpred/twoBitPredictor.sv b/src/ifu/bpred/twoBitPredictor.sv index 52e24d901..5b2fcb9b8 100644 --- a/src/ifu/bpred/twoBitPredictor.sv +++ b/src/ifu/bpred/twoBitPredictor.sv @@ -53,7 +53,7 @@ module twoBitPredictor import cvw::*; #(parameter cvw_t P, parameter XLEN, assign IndexM = {PCM[k+1] ^ PCM[1], PCM[k:2]}; - ram2p1r1wbe #(P, 2**k, 2) PHT(.clk(clk), + ram2p1r1wbe #(.USE_SRAM(P.USE_SRAM), .DEPTH(2**k), .WIDTH(2)) PHT(.clk(clk), .ce1(~StallF), .ce2(~StallW & ~FlushW), .ra1(IndexNextF), .rd1(BPDirPredF), diff --git a/src/ifu/ifu.sv b/src/ifu/ifu.sv index 325153ac5..4fdef8c6a 100644 --- a/src/ifu/ifu.sv +++ b/src/ifu/ifu.sv @@ -114,10 +114,7 @@ module ifu import cvw::*; #(parameter cvw_t P) ( logic [31:0] IROMInstrF; // Instruction from the IROM logic [31:0] ICacheInstrF; // Instruction from the I$ logic [31:0] InstrRawF; // Instruction from the IROM, I$, or bus - logic CompressedF; // The fetched instruction is compressed - logic CompressedD; // The decoded instruction is compressed - logic CompressedE; // The execution instruction is compressed - logic CompressedM; // The execution instruction is compressed + logic CompressedF, CompressedE; // The fetched instruction is compressed logic [31:0] PostSpillInstrRawF; // Fetch instruction after merge two halves of spill logic [31:0] InstrRawD; // Non-decompressed instruction in the Decode stage logic IllegalIEUInstrD; // IEU Instruction (regular or compressed) is not good @@ -389,31 +386,40 @@ module ifu import cvw::*; #(parameter cvw_t P) ( assign BranchMisalignedFaultE = (IEUAdrE[1] & ~P.COMPRESSED_SUPPORTED) & PCSrcE; flopenr #(1) InstrMisalignedReg(clk, reset, ~StallM, BranchMisalignedFaultE, InstrMisalignedFaultM); - // Instruction and PC pipeline registers - // Cannot use flopenrc for Instr(E/M) as it resets to NOP not 0. + // Instruction and PC pipeline registers flush to NOP, not zero mux2 #(32) FlushInstrEMux(InstrD, nop, FlushE, NextInstrD); - mux2 #(32) FlushInstrMMux(InstrE, nop, FlushM, NextInstrE); flopenr #(32) InstrEReg(clk, reset, ~StallE, NextInstrD, InstrE); flopenr #(P.XLEN) PCEReg(clk, reset, ~StallE, PCD, PCE); // InstrM is only needed with CSRs or atomic operations - if (P.ZICSR_SUPPORTED | P.A_SUPPORTED) + if (P.ZICSR_SUPPORTED | P.A_SUPPORTED) begin + mux2 #(32) FlushInstrMMux(InstrE, nop, FlushM, NextInstrE); flopenr #(32) InstrMReg(clk, reset, ~StallM, NextInstrE, InstrM); - else assign InstrM = 0; + end else assign InstrM = 0; // PCM is only needed with CSRs or branch prediction if (P.ZICSR_SUPPORTED | P.BPRED_SUPPORTED) flopenr #(P.XLEN) PCMReg(clk, reset, ~StallM, PCE, PCM); - else assign PCM = 0; - - flopenrc #(1) CompressedDReg(clk, reset, FlushD, ~StallD, CompressedF, CompressedD); - flopenrc #(1) CompressedEReg(clk, reset, FlushE, ~StallE, CompressedD, CompressedE); - assign PCLinkE = PCE + (CompressedE ? 'd2 : 'd4); // 'd4 means 4 but stops Design Compiler complaining about signed to unsigned conversion - + else assign PCM = 0; + + // If compressed instructions are supported, increment PCLink by 2 or 4 for a jal. Otherwise, just by 4 + if (P.COMPRESSED_SUPPORTED) begin + logic CompressedD; // instruction is compressed + flopenrc #(1) CompressedDReg(clk, reset, FlushD, ~StallD, CompressedF, CompressedD); + flopenrc #(1) CompressedEReg(clk, reset, FlushE, ~StallE, CompressedD, CompressedE); + assign PCLinkE = PCE + (CompressedE ? 'd2 : 'd4); // 'd4 means 4 but stops Design Compiler complaining about signed to unsigned conversion + end else begin + assign CompressedE = 0; + assign PCLinkE = PCE + 'd4; + end + // pipeline original compressed instruction in case it is needed for MTVAL on an illegal instruction exception - if (P.ZICSR_SUPPORTED) begin + if (P.ZICSR_SUPPORTED & P.COMPRESSED_SUPPORTED | 1) begin + logic CompressedM; // instruction is compressed flopenrc #(16) InstrRawEReg(clk, reset, FlushE, ~StallE, InstrRawD[15:0], InstrRawE); flopenrc #(16) InstrRawMReg(clk, reset, FlushM, ~StallM, InstrRawE, InstrRawM); flopenrc #(1) CompressedMReg(clk, reset, FlushM, ~StallM, CompressedE, CompressedM); mux2 #(32) InstrOrigMux(InstrM, {16'b0, InstrRawM}, CompressedM, InstrOrigM); - end else assign InstrOrigM = 0; + end else + assign InstrOrigM = InstrM; + endmodule diff --git a/src/lsu/dtim.sv b/src/lsu/dtim.sv index c8668e767..fb3d25adc 100644 --- a/src/lsu/dtim.sv +++ b/src/lsu/dtim.sv @@ -49,6 +49,6 @@ module dtim import cvw::*; #(parameter cvw_t P) ( assign we = MemRWM[0] & ~FlushW; // have to ignore write if Trap. - ram1p1rwbe #(.P(P), .DEPTH(DEPTH), .WIDTH(P.LLEN)) + ram1p1rwbe #(.USE_SRAM(P.USE_SRAM), .DEPTH(DEPTH), .WIDTH(P.LLEN)) ram(.clk, .ce, .we, .bwe(ByteMaskM), .addr(DTIMAdr[ADDR_WDITH+OFFSET-1:OFFSET]), .dout(ReadDataWordM), .din(WriteDataM)); endmodule diff --git a/src/mmu/adrdecs.sv b/src/mmu/adrdecs.sv index f3017ec54..3ee9c23d5 100644 --- a/src/mmu/adrdecs.sv +++ b/src/mmu/adrdecs.sv @@ -32,23 +32,24 @@ module adrdecs import cvw::*; #(parameter cvw_t P) ( input logic [P.PA_BITS-1:0] PhysicalAddress, input logic AccessRW, AccessRX, AccessRWX, input logic [1:0] Size, - output logic [10:0] SelRegions + output logic [11:0] SelRegions ); localparam logic [3:0] SUPPORTED_SIZE = (P.LLEN == 32 ? 4'b0111 : 4'b1111); // Determine which region of physical memory (if any) is being accessed - adrdec #(P.PA_BITS) dtimdec(PhysicalAddress, P.DTIM_BASE[P.PA_BITS-1:0], P.DTIM_RANGE[P.PA_BITS-1:0], P.DTIM_SUPPORTED, AccessRW, Size, SUPPORTED_SIZE, SelRegions[10]); - adrdec #(P.PA_BITS) iromdec(PhysicalAddress, P.IROM_BASE[P.PA_BITS-1:0], P.IROM_RANGE[P.PA_BITS-1:0], P.IROM_SUPPORTED, AccessRX, Size, SUPPORTED_SIZE, SelRegions[9]); - adrdec #(P.PA_BITS) ddr4dec(PhysicalAddress, P.EXT_MEM_BASE[P.PA_BITS-1:0], P.EXT_MEM_RANGE[P.PA_BITS-1:0], P.EXT_MEM_SUPPORTED, AccessRWX, Size, SUPPORTED_SIZE, SelRegions[8]); - adrdec #(P.PA_BITS) bootromdec(PhysicalAddress, P.BOOTROM_BASE[P.PA_BITS-1:0], P.BOOTROM_RANGE[P.PA_BITS-1:0], P.BOOTROM_SUPPORTED, AccessRX, Size, SUPPORTED_SIZE, SelRegions[7]); - adrdec #(P.PA_BITS) uncoreramdec(PhysicalAddress, P.UNCORE_RAM_BASE[P.PA_BITS-1:0], P.UNCORE_RAM_RANGE[P.PA_BITS-1:0], P.UNCORE_RAM_SUPPORTED, AccessRWX, Size, SUPPORTED_SIZE, SelRegions[6]); - adrdec #(P.PA_BITS) clintdec(PhysicalAddress, P.CLINT_BASE[P.PA_BITS-1:0], P.CLINT_RANGE[P.PA_BITS-1:0], P.CLINT_SUPPORTED, AccessRW, Size, SUPPORTED_SIZE, SelRegions[5]); - adrdec #(P.PA_BITS) gpiodec(PhysicalAddress, P.GPIO_BASE[P.PA_BITS-1:0], P.GPIO_RANGE[P.PA_BITS-1:0], P.GPIO_SUPPORTED, AccessRW, Size, 4'b0100, SelRegions[4]); - adrdec #(P.PA_BITS) uartdec(PhysicalAddress, P.UART_BASE[P.PA_BITS-1:0], P.UART_RANGE[P.PA_BITS-1:0], P.UART_SUPPORTED, AccessRW, Size, 4'b0001, SelRegions[3]); - adrdec #(P.PA_BITS) plicdec(PhysicalAddress, P.PLIC_BASE[P.PA_BITS-1:0], P.PLIC_RANGE[P.PA_BITS-1:0], P.PLIC_SUPPORTED, AccessRW, Size, 4'b0100, SelRegions[2]); - adrdec #(P.PA_BITS) sdcdec(PhysicalAddress, P.SDC_BASE[P.PA_BITS-1:0], P.SDC_RANGE[P.PA_BITS-1:0], P.SDC_SUPPORTED, AccessRW, Size, SUPPORTED_SIZE, SelRegions[1]); + adrdec #(P.PA_BITS) dtimdec(PhysicalAddress, P.DTIM_BASE[P.PA_BITS-1:0], P.DTIM_RANGE[P.PA_BITS-1:0], P.DTIM_SUPPORTED, AccessRW, Size, SUPPORTED_SIZE, SelRegions[11]); + adrdec #(P.PA_BITS) iromdec(PhysicalAddress, P.IROM_BASE[P.PA_BITS-1:0], P.IROM_RANGE[P.PA_BITS-1:0], P.IROM_SUPPORTED, AccessRX, Size, SUPPORTED_SIZE, SelRegions[10]); + adrdec #(P.PA_BITS) ddr4dec(PhysicalAddress, P.EXT_MEM_BASE[P.PA_BITS-1:0], P.EXT_MEM_RANGE[P.PA_BITS-1:0], P.EXT_MEM_SUPPORTED, AccessRWX, Size, SUPPORTED_SIZE, SelRegions[9]); + adrdec #(P.PA_BITS) bootromdec(PhysicalAddress, P.BOOTROM_BASE[P.PA_BITS-1:0], P.BOOTROM_RANGE[P.PA_BITS-1:0], P.BOOTROM_SUPPORTED, AccessRX, Size, SUPPORTED_SIZE, SelRegions[8]); + adrdec #(P.PA_BITS) uncoreramdec(PhysicalAddress, P.UNCORE_RAM_BASE[P.PA_BITS-1:0], P.UNCORE_RAM_RANGE[P.PA_BITS-1:0], P.UNCORE_RAM_SUPPORTED, AccessRWX, Size, SUPPORTED_SIZE, SelRegions[7]); + adrdec #(P.PA_BITS) clintdec(PhysicalAddress, P.CLINT_BASE[P.PA_BITS-1:0], P.CLINT_RANGE[P.PA_BITS-1:0], P.CLINT_SUPPORTED, AccessRW, Size, SUPPORTED_SIZE, SelRegions[6]); + adrdec #(P.PA_BITS) gpiodec(PhysicalAddress, P.GPIO_BASE[P.PA_BITS-1:0], P.GPIO_RANGE[P.PA_BITS-1:0], P.GPIO_SUPPORTED, AccessRW, Size, 4'b0100, SelRegions[5]); + adrdec #(P.PA_BITS) uartdec(PhysicalAddress, P.UART_BASE[P.PA_BITS-1:0], P.UART_RANGE[P.PA_BITS-1:0], P.UART_SUPPORTED, AccessRW, Size, 4'b0001, SelRegions[4]); + adrdec #(P.PA_BITS) plicdec(PhysicalAddress, P.PLIC_BASE[P.PA_BITS-1:0], P.PLIC_RANGE[P.PA_BITS-1:0], P.PLIC_SUPPORTED, AccessRW, Size, 4'b0100, SelRegions[3]); + adrdec #(P.PA_BITS) sdcdec(PhysicalAddress, P.SDC_BASE[P.PA_BITS-1:0], P.SDC_RANGE[P.PA_BITS-1:0], P.SDC_SUPPORTED, AccessRW, Size, SUPPORTED_SIZE & 4'b1100, SelRegions[2]); + adrdec #(P.PA_BITS) spidec(PhysicalAddress, P.SPI_BASE[P.PA_BITS-1:0], P.SPI_RANGE[P.PA_BITS-1:0], P.SPI_SUPPORTED, AccessRW, Size, 4'b0100, SelRegions[1]); - assign SelRegions[0] = ~|(SelRegions[10:1]); // none of the regions are selected + assign SelRegions[0] = ~|(SelRegions[11:1]); // none of the regions are selected endmodule // verilator lint_on UNOPTFLAT diff --git a/src/mmu/pmachecker.sv b/src/mmu/pmachecker.sv index 119e88d8c..7aa20fc2f 100644 --- a/src/mmu/pmachecker.sv +++ b/src/mmu/pmachecker.sv @@ -44,7 +44,7 @@ module pmachecker import cvw::*; #(parameter cvw_t P) ( logic PMAAccessFault; logic AccessRW, AccessRWX, AccessRX; - logic [10:0] SelRegions; + logic [11:0] SelRegions; logic AtomicAllowed; logic CacheableRegion, IdempotentRegion; @@ -57,18 +57,18 @@ module pmachecker import cvw::*; #(parameter cvw_t P) ( adrdecs #(P) adrdecs(PhysicalAddress, AccessRW, AccessRX, AccessRWX, Size, SelRegions); // Only non-core RAM/ROM memory regions are cacheable. PBMT can override cachable; NC and IO are uncachable - assign CacheableRegion = SelRegions[8] | SelRegions[7] | SelRegions[6]; // exclusion-tag: unused-cachable + assign CacheableRegion = SelRegions[9] | SelRegions[8] | SelRegions[7]; // exclusion-tag: unused-cachable assign Cacheable = (PBMemoryType == 2'b00) ? CacheableRegion : 0; // Nonidemdempotent means access could have side effect and must not be done speculatively or redundantly // I/O is nonidempotent. PBMT can override PMA; NC is idempotent and IO is non-idempotent - assign IdempotentRegion = SelRegions[10] | SelRegions[9] | SelRegions[8] | SelRegions[7] | SelRegions[6]; // exclusion-tag: unused-idempotent + assign IdempotentRegion = SelRegions[11] | SelRegions[10] | SelRegions[9] | SelRegions[8] | SelRegions[7]; // exclusion-tag: unused-idempotent assign Idempotent = (PBMemoryType == 2'b00) ? IdempotentRegion : (PBMemoryType == 2'b01); // Atomic operations are only allowed on RAM - assign AtomicAllowed = SelRegions[10] | SelRegions[8] | SelRegions[6]; // exclusion-tag: unused-atomic + assign AtomicAllowed = SelRegions[11] | SelRegions[9] | SelRegions[7]; // exclusion-tag: unused-idempotent // Check if tightly integrated memories are selected - assign SelTIM = SelRegions[10] | SelRegions[9]; // exclusion-tag: unused-tim + assign SelTIM = SelRegions[11] | SelRegions[10]; // exclusion-tag: unused-idempotent // Detect access faults assign PMAAccessFault = (SelRegions[0]) & AccessRWX | AtomicAccessM & ~AtomicAllowed; diff --git a/src/uncore/plic_apb.sv b/src/uncore/plic_apb.sv index 96f3eb6eb..8ced27319 100644 --- a/src/uncore/plic_apb.sv +++ b/src/uncore/plic_apb.sv @@ -49,7 +49,7 @@ module plic_apb import cvw::*; #(parameter cvw_t P) ( input logic PENABLE, output logic [P.XLEN-1:0] PRDATA, output logic PREADY, - input logic UARTIntr,GPIOIntr,SDCIntr, + input logic UARTIntr,GPIOIntr, SPIIntr, SDCIntr, output logic MExtInt, SExtInt ); @@ -156,6 +156,7 @@ module plic_apb import cvw::*; #(parameter cvw_t P) ( requests = {P.PLIC_NUM_SRC{1'b0}}; if(P.PLIC_GPIO_ID != 0) requests[P.PLIC_GPIO_ID] = GPIOIntr; if(P.PLIC_UART_ID != 0) requests[P.PLIC_UART_ID] = UARTIntr; + if(P.PLIC_SPI_ID != 0) requests[P.PLIC_SPI_ID] = SPIIntr; if(P.PLIC_SDC_ID !=0) requests[P.PLIC_SDC_ID] = SDCIntr; end diff --git a/src/uncore/ram_ahb.sv b/src/uncore/ram_ahb.sv index 17b6c8ed8..7b6c504bd 100644 --- a/src/uncore/ram_ahb.sv +++ b/src/uncore/ram_ahb.sv @@ -71,7 +71,7 @@ module ram_ahb import cvw::*; #(parameter cvw_t P, mux2 #(P.PA_BITS) adrmux(HADDR, HADDRD, memwriteD | ~HREADY, RamAddr); // single-ported RAM - ram1p1rwbe #(.P(P), .DEPTH(RANGE/8), .WIDTH(P.XLEN), .PRELOAD_ENABLED(P.FPGA)) memory(.clk(HCLK), .ce(1'b1), + ram1p1rwbe #(.USE_SRAM(P.USE_SRAM), .DEPTH(RANGE/8), .WIDTH(P.XLEN), .PRELOAD_ENABLED(P.FPGA)) memory(.clk(HCLK), .ce(1'b1), .addr(RamAddr[ADDR_WIDTH+OFFSET-1:OFFSET]), .we(memwriteD), .din(HWDATA), .bwe(HWSTRB), .dout(HREADRam)); // use this to add arbitrary latency to ram. Helps test AHB controller correctness diff --git a/src/uncore/spi_apb.sv b/src/uncore/spi_apb.sv new file mode 100644 index 000000000..4db435be6 --- /dev/null +++ b/src/uncore/spi_apb.sv @@ -0,0 +1,500 @@ +/////////////////////////////////////////// +// spi_apb.sv +// +// Written: Naiche Whyte-Aguayo nwhyteaguayo@g.hmc.edu 11/16/2022 + +// +// Purpose: SPI peripheral +// See FU540-C000-v1.0 for specifications +// +// 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. +//////////////////////////////////////////////////////////////////////////////////////////////// + +// Current limitations: Flash read sequencer mode not implemented, dual and quad modes untestable with current test plan. + +// Attempt to move from >= comparisons by initializing in FSM differently +// Parameterize SynchFIFO +// look at ReadIncrement/WriteIncrement delay necessity + +/* +SPI module is written to the specifications described in FU540-C000-v1.0. At the top level, it is consists of synchronous 8 byte transmit and recieve FIFOs connected to shift registers. +The FIFOs are connected to WALLY by an apb control register interface, which includes various control registers for modifying the SPI transmission along with registers for writing +to the transmit FIFO and reading from the receive FIFO. The transmissions themselves are then controlled by a finite state machine. The SPI module uses 4 tristate pins for SPI input/output, +along with a 4 bit Chip Select signal, a clock signal, and an interrupt signal to WALLY. +*/ + +module spi_apb import cvw::*; #(parameter cvw_t P) ( + input logic PCLK, PRESETn, + input logic PSEL, + input logic [7:0] PADDR, + input logic [P.XLEN-1:0] PWDATA, + input logic [P.XLEN/8-1:0] PSTRB, + input logic PWRITE, + input logic PENABLE, + output logic PREADY, + output logic [P.XLEN-1:0] PRDATA, + output logic SPIOut, + input logic SPIIn, + output logic [3:0] SPICS, + output logic SPIIntr +); + + //SPI control registers. Refer to SiFive FU540-C000 manual + logic [11:0] SckDiv; + logic [1:0] SckMode; + logic [1:0] ChipSelectID; + logic [3:0] ChipSelectDef; + logic [1:0] ChipSelectMode; + logic [15:0] Delay0, Delay1; + logic [4:0] Format; + logic [7:0] ReceiveData; + logic [2:0] TransmitWatermark, ReceiveWatermark; + logic [8:0] TransmitData; + logic [1:0] InterruptEnable, InterruptPending; + + //Bus interface signals + logic [7:0] Entry; + logic Memwrite; + logic [31:0] Din, Dout; + logic TransmitInactive; //High when there is no transmission, used as hardware interlock signal + + //FIFO FSM signals + //Watermark signals - TransmitReadMark = ip[0], ReceiveWriteMark = ip[1] + logic TransmitWriteMark, TransmitReadMark, RecieveWriteMark, RecieveReadMark; + logic TransmitFIFOWriteFull, TransmitFIFOReadEmpty; + logic TransmitFIFOReadIncrement; + logic TransmitFIFOWriteIncrement; + logic ReceiveFIFOReadIncrement; + logic ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty; + logic [7:0] TransmitFIFOReadData, ReceiveFIFOWriteData; + logic [2:0] TransmitWriteWatermarkLevel, ReceiveReadWatermarkLevel; + logic [7:0] ReceiveShiftRegEndian; //reverses ReceiveShiftReg if Format[2] set (little endian transmission) + + //Transmission signals + logic sck; + logic [11:0] DivCounter; //counter for sck + logic SCLKenable; //flip flop enable high every sclk edge + + //Delay signals + logic [8:0] ImplicitDelay1; //Adds implicit delay to cs-sck delay counter based on phase + logic [8:0] ImplicitDelay2; //Adds implicit delay to sck-cs delay counter based on phase + logic [8:0] CS_SCKCount; //Counter for cs-sck delay + logic [8:0] SCK_CSCount; //Counter for sck-cs delay + logic [8:0] InterCSCount; //Counter for inter cs delay + logic [8:0] InterXFRCount; //Counter for inter xfr delay + logic CS_SCKCompare; //Boolean comparison signal, high when CS_SCKCount >= cs-sck delay + logic SCK_CSCompare; //Boolean comparison signal, high when SCK_CSCount >= sck-cs delay + logic InterCSCompare; //Boolean comparison signal, high when InterCSCount >= inter cs delay + logic InterXFRCompare; //Boolean comparison signal, high when InterXFRCount >= inter xfr delay + logic ZeroDelayHoldMode; //High when ChipSelectMode is hold and Delay1[15:8] (InterXFR delay) is 0 + + //Frame counting signals + logic [3:0] FrameCount; //Counter for number of frames in transmission + logic FrameCompare; //Boolean comparison signal, high when FrameCount = Format[7:4] + logic [3:0] ReceivePenultimateFrame; //Frame number - 1 + logic [3:0] ReceivePenultimateFrameCount; //Counter + logic ReceivePenultimateFrameBoolean; //High when penultimate frame in transmission has been reached + + //State fsm signals + logic Active; //High when state is either Active1 or Active0 (during transmission) + logic Active0; //High when state is Active0 + + //Shift reg signals + logic ShiftEdge; //Determines which edge of sck to shift from TransmitShiftReg + logic [7:0] TransmitShiftReg; //Transmit shift register + logic [7:0] ReceiveShiftReg; //Receive shift register + logic SampleEdge; //Determines which edge of sck to sample from ReceiveShiftReg + logic [7:0] TransmitDataEndian; //Reverses TransmitData from txFIFO if littleendian, since TransmitReg always shifts MSB + logic TransmitShiftRegLoad; //Determines when to load TransmitShiftReg + logic ReceiveShiftFull; //High when receive shift register is full + logic TransmitShiftEmpty; //High when transmit shift register is empty + logic ShiftIn; //Determines whether to shift from SPIIn or SPIOut (if SPI_LOOPBACK_TEST) + logic [3:0] LeftShiftAmount; //Determines left shift amount to left-align data when little endian + logic [7:0] ASR; //AlignedReceiveShiftReg + + //CS signals + logic [3:0] ChipSelectAuto; //Assigns ChipSelect value to selected CS signal based on CS ID + logic [3:0] ChipSelectInternal; //Defines what each ChipSelect signal should be based on transmission status and ChipSelectDef + logic DelayMode; //Determines where to place implicit half cycle delay based on sck phase for CS assertion + + //Miscellaneous signals delayed/early by 1 PCLK cycle + logic ReceiveShiftFullDelay; //Delays ReceiveShiftFull signal by 1 PCLK cycle + logic TransmitFIFOWriteIncrementDelay; //TransmitFIFOWriteIncrement delayed by 1 PCLK cycle + logic ReceiveShiftFullDelayPCLK; //ReceiveShiftFull delayed by 1 PCLK cycle + logic TransmitFIFOReadEmptyDelay; + logic SCLKenableEarly; //SCLKenable 1 PCLK cycle early, needed for on time register changes when ChipSelectMode is hold and Delay1[15:8] (InterXFR delay) is 0 + + //APB access + assign Entry = {PADDR[7:2],2'b00}; // 32-bit word-aligned accesses + assign Memwrite = PWRITE & PENABLE & PSEL; // only write in access phase + assign PREADY = TransmitInactive; // tie PREADY to transmission for hardware interlock + + //Account for subword read/write circuitry + // -- Note SPI registers are 32 bits no matter what; access them with LW SW. + + assign Din = PWDATA[31:0]; + if (P.XLEN == 64) assign PRDATA = {Dout, Dout}; + else assign PRDATA = Dout; + + //Register access + always_ff@(posedge PCLK, negedge PRESETn) + if (~PRESETn) begin + SckDiv <= #1 12'd3; + SckMode <= #1 2'b0; + ChipSelectID <= #1 2'b0; + ChipSelectDef <= #1 4'b1111; + ChipSelectMode <= #1 0; + Delay0 <= #1 {8'b1,8'b1}; + Delay1 <= #1 {8'b0,8'b1}; + Format <= #1 {5'b10000}; + TransmitData <= #1 9'b0; + TransmitWatermark <= #1 3'b0; + ReceiveWatermark <= #1 3'b0; + InterruptEnable <= #1 2'b0; + InterruptPending <= #1 2'b0; + end else begin //writes + //According to FU540 spec: Once interrupt is pending, it will remain set until number + //of entries in tx/rx fifo is strictly more/less than tx/rxmark + + /* verilator lint_off CASEINCOMPLETE */ + if (Memwrite & TransmitInactive) + case(Entry) //flop to sample inputs + 8'h00: SckDiv <= Din[11:0]; + 8'h04: SckMode <= Din[1:0]; + 8'h10: ChipSelectID <= Din[1:0]; + 8'h14: ChipSelectDef <= Din[3:0]; + 8'h18: ChipSelectMode <= Din[1:0]; + 8'h28: Delay0 <= {Din[23:16], Din[7:0]}; + 8'h2C: Delay1 <= {Din[23:16], Din[7:0]}; + 8'h40: Format <= {Din[19:16], Din[2]}; + 8'h48: if (~TransmitFIFOWriteFull) TransmitData[7:0] <= Din[7:0]; + 8'h50: TransmitWatermark <= Din[2:0]; + 8'h54: ReceiveWatermark <= Din[2:0]; + 8'h70: InterruptEnable <= Din[1:0]; + endcase + /* verilator lint_off CASEINCOMPLETE */ + //interrupt clearance + InterruptPending[0] <= TransmitReadMark; + InterruptPending[1] <= RecieveWriteMark; + case(Entry) // flop to sample inputs + 8'h00: Dout <= #1 {20'b0, SckDiv}; + 8'h04: Dout <= #1 {30'b0, SckMode}; + 8'h10: Dout <= #1 {30'b0, ChipSelectID}; + 8'h14: Dout <= #1 {28'b0, ChipSelectDef}; + 8'h18: Dout <= #1 {30'b0, ChipSelectMode}; + 8'h28: Dout <= {8'b0, Delay0[15:8], 8'b0, Delay0[7:0]}; + 8'h2C: Dout <= {8'b0, Delay1[15:8], 8'b0, Delay1[7:0]}; + 8'h40: Dout <= {12'b0, Format[4:1], 13'b0, Format[0], 2'b0}; + 8'h48: Dout <= #1 {23'b0, TransmitFIFOWriteFull, 8'b0}; + 8'h4C: Dout <= #1 {23'b0, ReceiveFIFOReadEmpty, ReceiveData[7:0]}; + 8'h50: Dout <= #1 {29'b0, TransmitWatermark}; + 8'h54: Dout <= #1 {29'b0, ReceiveWatermark}; + 8'h70: Dout <= #1 {30'b0, InterruptEnable}; + 8'h74: Dout <= #1 {30'b0, InterruptPending}; + default: Dout <= #1 32'b0; + endcase + end + + //SPI enable generation, where SCLK = PCLK/(2*(SckDiv + 1)) + //Generates a high signal at the rising and falling edge of SCLK by counting from 0 to SckDiv + assign SCLKenable = (DivCounter == SckDiv); + assign SCLKenableEarly = ((DivCounter + 12'b1) == SckDiv); + always_ff @(posedge PCLK, negedge PRESETn) + if (~PRESETn) DivCounter <= #1 0; + else if (SCLKenable) DivCounter <= 0; + else DivCounter <= DivCounter + 12'b1; + + //Boolean logic that tracks frame progression + assign FrameCompare = (FrameCount < Format[4:1]); + assign ReceivePenultimateFrameBoolean = ((FrameCount + 4'b0001) == Format[4:1]); + + //Computing delays + // When sckmode.pha = 0, an extra half-period delay is implicit in the cs-sck delay, and vice-versa for sck-cs + assign ImplicitDelay1 = SckMode[0] ? 9'b0 : 9'b1; + assign ImplicitDelay2 = SckMode[0] ? 9'b1 : 9'b0; + + assign CS_SCKCompare = CS_SCKCount >= (({Delay0[7:0], 1'b0}) + ImplicitDelay1); + assign SCK_CSCompare = SCK_CSCount >= (({Delay0[15:8], 1'b0}) + ImplicitDelay2); + assign InterCSCompare = (InterCSCount >= ({Delay1[7:0],1'b0})); + assign InterXFRCompare = (InterXFRCount >= ({Delay1[15:8], 1'b0})); + + //Calculate when tx/rx shift registers are full/empty + TransmitShiftFSM TransmitShiftFSM_1 (PCLK, PRESETn, TransmitFIFOReadEmpty, ReceivePenultimateFrameBoolean, Active0, TransmitShiftEmpty); + ReceiveShiftFSM ReceiveShiftFSM_1 (PCLK, PRESETn, SCLKenable, ReceivePenultimateFrameBoolean, SampleEdge, SckMode[0], ReceiveShiftFull); + + //Calculate tx/rx fifo write and recieve increment signals + assign TransmitFIFOWriteIncrement = (Memwrite & (Entry == 8'h48) & ~TransmitFIFOWriteFull & TransmitInactive); + + always_ff @(posedge PCLK, negedge PRESETn) + if (~PRESETn) TransmitFIFOWriteIncrementDelay <= 0; + else TransmitFIFOWriteIncrementDelay <= TransmitFIFOWriteIncrement; + + always_ff @(posedge PCLK, negedge PRESETn) + if (~PRESETn) ReceiveFIFOReadIncrement <= 0; + else ReceiveFIFOReadIncrement <= ((Entry == 8'h4C) & ~ReceiveFIFOReadEmpty & PSEL & ~ReceiveFIFOReadIncrement); + + //Tx/Rx FIFOs + SynchFIFO #(3,8) txFIFO(PCLK, 1'b1, SCLKenable, PRESETn, TransmitFIFOWriteIncrementDelay, TransmitShiftEmpty, TransmitData[7:0], TransmitWriteWatermarkLevel, TransmitWatermark[2:0], TransmitFIFOReadData[7:0], TransmitFIFOWriteFull, TransmitFIFOReadEmpty, TransmitWriteMark, TransmitReadMark); + SynchFIFO #(3,8) rxFIFO(PCLK, SCLKenable, 1'b1, PRESETn, ReceiveShiftFullDelay, ReceiveFIFOReadIncrement, ReceiveShiftRegEndian, ReceiveWatermark[2:0], ReceiveReadWatermarkLevel, ReceiveData[7:0], ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty, RecieveWriteMark, RecieveReadMark); + + always_ff @(posedge PCLK, negedge PRESETn) + if (~PRESETn) TransmitFIFOReadEmptyDelay <= 1; + else if (SCLKenable) TransmitFIFOReadEmptyDelay <= TransmitFIFOReadEmpty; + + + always_ff @(posedge PCLK, negedge PRESETn) + if (~PRESETn) ReceiveShiftFullDelay <= 0; + else if (SCLKenable) ReceiveShiftFullDelay <= ReceiveShiftFull; + always_ff @(posedge PCLK, negedge PRESETn) + if (~PRESETn) ReceiveShiftFullDelayPCLK <= 0; + else if (SCLKenableEarly) ReceiveShiftFullDelayPCLK <= ReceiveShiftFull; + + assign TransmitShiftRegLoad = ~TransmitShiftEmpty & ~Active | (((ChipSelectMode == 2'b10) & ~|(Delay1[15:8])) & ((ReceiveShiftFullDelay | ReceiveShiftFull) & ~SampleEdge & ~TransmitFIFOReadEmpty)); + + //Main FSM which controls SPI transmission + typedef enum logic [2:0] {CS_INACTIVE, DELAY_0, ACTIVE_0, ACTIVE_1, DELAY_1,INTER_CS, INTER_XFR} statetype; + statetype state; + + always_ff @(posedge PCLK, negedge PRESETn) + if (~PRESETn) begin state <= CS_INACTIVE; + FrameCount <= 4'b0; + + /* verilator lint_off CASEINCOMPLETE */ + end else if (SCLKenable) begin + case (state) + CS_INACTIVE: begin + CS_SCKCount <= 9'b1; + SCK_CSCount <= 9'b10; + FrameCount <= 4'b0; + InterCSCount <= 9'b10; + InterXFRCount <= 9'b1; + if ((~TransmitFIFOReadEmpty | ~TransmitShiftEmpty) & ((|(Delay0[7:0])) | ~SckMode[0])) state <= DELAY_0; + else if ((~TransmitFIFOReadEmpty | ~TransmitShiftEmpty)) state <= ACTIVE_0; + end + DELAY_0: begin + CS_SCKCount <= CS_SCKCount + 9'b1; + if (CS_SCKCompare) state <= ACTIVE_0; + end + ACTIVE_0: begin + FrameCount <= FrameCount + 4'b1; + state <= ACTIVE_1; + end + ACTIVE_1: begin + InterXFRCount <= 9'b1; + if (FrameCompare) state <= ACTIVE_0; + else if ((ChipSelectMode[1:0] == 2'b10) & ~|(Delay1[15:8]) & (~TransmitFIFOReadEmpty)) begin + state <= ACTIVE_0; + CS_SCKCount <= 9'b1; + SCK_CSCount <= 9'b10; + FrameCount <= 4'b0; + InterCSCount <= 9'b10; + end + else if (ChipSelectMode[1:0] == 2'b10) state <= INTER_XFR; + else if (~|(Delay0[15:8]) & (~SckMode[0])) state <= INTER_CS; + else state <= DELAY_1; + end + DELAY_1: begin + SCK_CSCount <= SCK_CSCount + 9'b1; + if (SCK_CSCompare) state <= INTER_CS; + end + INTER_CS: begin + InterCSCount <= InterCSCount + 9'b1; + if (InterCSCompare ) state <= CS_INACTIVE; + end + INTER_XFR: begin + CS_SCKCount <= 9'b1; + SCK_CSCount <= 9'b10; + FrameCount <= 4'b0; + InterCSCount <= 9'b10; + InterXFRCount <= InterXFRCount + 9'b1; + if (InterXFRCompare & ~TransmitFIFOReadEmptyDelay) state <= ACTIVE_0; + else if (~|ChipSelectMode[1:0]) state <= CS_INACTIVE; + end + endcase + end + + /* verilator lint_off CASEINCOMPLETE */ + + 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 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 + 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; + 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, negedge PRESETn) + if(~PRESETn) TransmitShiftReg <= 8'b0; + else if (TransmitShiftRegLoad) TransmitShiftReg <= TransmitDataEndian; + else if (ShiftEdge & Active) TransmitShiftReg <= {TransmitShiftReg[6:0], 1'b0}; + + assign SPIOut = TransmitShiftReg[7]; + + //If in loopback mode, receive shift register is connected directly to module's output pins. Else, connected to SPIIn + //There are no setup/hold time issues because transmit shift register and receive shift register always shift/sample on opposite edges + assign ShiftIn = P.SPI_LOOPBACK_TEST ? SPIOut : SPIIn; + + //Receive shift register + always_ff @(posedge PCLK, negedge PRESETn) + if(~PRESETn) ReceiveShiftReg <= 8'b0; + else if (SampleEdge & SCLKenable) begin + if (~Active) ReceiveShiftReg <= 8'b0; + else ReceiveShiftReg <= {ReceiveShiftReg[6:0], ShiftIn}; + end + + //Aligns received data and reverses if little-endian + assign LeftShiftAmount = 4'h8 - Format[4:1]; + assign ASR = ReceiveShiftReg << LeftShiftAmount[2:0]; + assign ReceiveShiftRegEndian = Format[0] ? {ASR[0], ASR[1], ASR[2], ASR[3], ASR[4], ASR[5], ASR[6], ASR[7]} : ASR[7:0]; + + //Interrupt logic: raise interrupt if any enabled interrupts are pending + assign SPIIntr = |(InterruptPending & InterruptEnable); + + //Chip select logic + always_comb + case(ChipSelectID[1:0]) + 2'b00: ChipSelectAuto = {ChipSelectDef[3], ChipSelectDef[2], ChipSelectDef[1], ChipSelectInternal[0]}; + 2'b01: ChipSelectAuto = {ChipSelectDef[3],ChipSelectDef[2], ChipSelectInternal[1], ChipSelectDef[0]}; + 2'b10: ChipSelectAuto = {ChipSelectDef[3],ChipSelectInternal[2], ChipSelectDef[1], ChipSelectDef[0]}; + 2'b11: ChipSelectAuto = {ChipSelectInternal[3],ChipSelectDef[2], ChipSelectDef[1], ChipSelectDef[0]}; + endcase + + assign SPICS = ChipSelectMode[0] ? ChipSelectDef : ChipSelectAuto; +endmodule + +module SynchFIFO #(parameter M =3 , N= 8)( + input logic PCLK, wen, ren, PRESETn, + input logic winc,rinc, + input logic [N-1:0] wdata, + input logic [M-1:0] wwatermarklevel, rwatermarklevel, + output logic [N-1:0] rdata, + output logic wfull, rempty, + output logic wwatermark, rwatermark); + + /* Pointer FIFO using design elements from "Simulation and Synthesis Techniques + for Asynchronous FIFO Design" by Clifford E. Cummings. Namely, M bit read and write pointers + are an extra bit larger than address size to determine full/empty conditions. + Watermark comparisons use 2's complement subtraction between the M-1 bit pointers, + which are also used to address memory + */ + + logic [N-1:0] mem[2**M]; + logic [M:0] rptr, wptr; + logic [M:0] rptrnext, wptrnext; + logic rempty_val; + logic wfull_val; + logic [M-1:0] raddr; + logic [M-1:0] waddr; + + assign rdata = mem[raddr]; + always_ff @(posedge PCLK) + if (winc & ~wfull) mem[waddr] <= wdata; + + // write and read are enabled + always_ff @(posedge PCLK, negedge PRESETn) + if (~PRESETn) begin + rptr <= 0; + wptr <= 0; + wfull <= 1'b0; + rempty <= 1'b1; + end + else begin + if (wen) begin + wfull <= wfull_val; + wptr <= wptrnext; + end + if (ren) begin + rptr <= rptrnext; + rempty <= rempty_val; + end + end + + assign raddr = rptr[M-1:0]; + assign rptrnext = rptr + {3'b0, (rinc & ~rempty)}; + assign rempty_val = (wptr == rptrnext); + assign rwatermark = ((waddr - raddr) < rwatermarklevel) & ~wfull; + assign waddr = wptr[M-1:0]; + assign wwatermark = ((waddr - raddr) > wwatermarklevel) | wfull; + assign wptrnext = wptr + {3'b0, (winc & ~wfull)}; + assign wfull_val = ({~wptrnext[M], wptrnext[M-1:0]} == rptr); +endmodule + +module TransmitShiftFSM( + input logic PCLK, PRESETn, + input logic TransmitFIFOReadEmpty, ReceivePenultimateFrameBoolean, Active0, + output logic TransmitShiftEmpty); + + typedef enum logic [1:0] {TransmitShiftEmptyState, TransmitShiftHoldState, TransmitShiftNotEmptyState} statetype; + statetype TransmitState, TransmitNextState; + always_ff @(posedge PCLK, negedge PRESETn) + if (~PRESETn) TransmitState <= TransmitShiftEmptyState; + else TransmitState <= TransmitNextState; + + always_comb + case(TransmitState) + TransmitShiftEmptyState: begin + if (TransmitFIFOReadEmpty | (~TransmitFIFOReadEmpty & (ReceivePenultimateFrameBoolean & Active0))) TransmitNextState = TransmitShiftEmptyState; + else if (~TransmitFIFOReadEmpty) TransmitNextState = TransmitShiftNotEmptyState; + end + TransmitShiftNotEmptyState: begin + if (ReceivePenultimateFrameBoolean & Active0) TransmitNextState = TransmitShiftEmptyState; + else TransmitNextState = TransmitShiftNotEmptyState; + end + endcase + assign TransmitShiftEmpty = (TransmitNextState == TransmitShiftEmptyState); +endmodule + +module ReceiveShiftFSM( + input logic PCLK, PRESETn, SCLKenable, + input logic ReceivePenultimateFrameBoolean, SampleEdge, SckMode, + output logic ReceiveShiftFull +); + typedef enum logic [1:0] {ReceiveShiftFullState, ReceiveShiftNotFullState, ReceiveShiftDelayState} statetype; + statetype ReceiveState, ReceiveNextState; + always_ff @(posedge PCLK, negedge PRESETn) + if (~PRESETn) ReceiveState <= ReceiveShiftNotFullState; + else if (SCLKenable) begin + case (ReceiveState) + ReceiveShiftFullState: ReceiveState <= ReceiveShiftNotFullState; + ReceiveShiftNotFullState: if (ReceivePenultimateFrameBoolean & (SampleEdge)) ReceiveState <= ReceiveShiftDelayState; + else ReceiveState <= ReceiveShiftNotFullState; + ReceiveShiftDelayState: ReceiveState <= ReceiveShiftFullState; + endcase + end + + assign ReceiveShiftFull = SckMode ? (ReceiveState == ReceiveShiftFullState) : (ReceiveState == ReceiveShiftDelayState); +endmodule + + + + + + diff --git a/src/uncore/uncore.sv b/src/uncore/uncore.sv index d5822c914..916dc53ef 100644 --- a/src/uncore/uncore.sv +++ b/src/uncore/uncore.sv @@ -54,28 +54,31 @@ 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 SDCIntr, + input logic SPIIn, + output logic SPIOut, + output logic [3:0] SPICS ); logic [P.XLEN-1:0] HREADRam, HREADSDC; - logic [10:0] HSELRegions; - logic HSELDTIM, HSELIROM, HSELRam, HSELCLINT, HSELPLIC, HSELGPIO, HSELUART, HSELSDC; - logic HSELDTIMD, HSELIROMD, HSELEXTD, HSELRamD, HSELCLINTD, HSELPLICD, HSELGPIOD, HSELUARTD; + logic [11:0] HSELRegions; + 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; logic [P.XLEN-1:0] HREADBootRom; logic HSELBootRom, HSELBootRomD, HRESPBootRom, HREADYBootRom, HREADYSDC; logic HSELNoneD; - logic UARTIntr,GPIOIntr; + logic UARTIntr,GPIOIntr, SPIIntr; logic SDCIntM; logic PCLK, PRESETn, PWRITE, PENABLE; - logic [3:0] PSEL, PREADY; + logic [4:0] PSEL, PREADY; logic [31:0] PADDR; logic [P.XLEN-1:0] PWDATA; logic [P.XLEN/8-1:0] PSTRB; - logic [3:0][P.XLEN-1:0] PRDATA; + logic [4:0][P.XLEN-1:0] PRDATA; logic [P.XLEN-1:0] HREADBRIDGE; logic HRESPBRIDGE, HREADYBRIDGE, HSELBRIDGE, HSELBRIDGED; @@ -88,14 +91,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 {HSELDTIM, HSELIROM, HSELEXT, HSELBootRom, HSELRam, HSELCLINT, HSELGPIO, HSELUART, HSELPLIC, HSELEXTSDC} = HSELRegions[10:1]; + assign {HSELDTIM, HSELIROM, HSELEXT, HSELBootRom, HSELRam, HSELCLINT, HSELGPIO, HSELUART, HSELPLIC, HSELSDC, HSELSPI} = HSELRegions[11:1]; // AHB -> APB bridge - ahbapbbridge #(P, 4) ahbapbbridge ( - .HCLK, .HRESETn, .HSEL({HSELUART, HSELPLIC, HSELCLINT, HSELGPIO}), .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HTRANS, .HREADY, + ahbapbbridge #(P, 5) ahbapbbridge ( + .HCLK, .HRESETn, .HSEL({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; // if any of the bridge signals are selected + assign HSELBRIDGE = HSELGPIO | HSELCLINT | HSELPLIC | HSELUART | HSELSPI; // if any of the bridge signals are selected // on-chip RAM if (P.UNCORE_RAM_SUPPORTED) begin : ram @@ -121,7 +124,7 @@ module uncore import cvw::*; #(parameter cvw_t P)( if (P.PLIC_SUPPORTED == 1) begin : plic plic_apb #(P) plic(.PCLK, .PRESETn, .PSEL(PSEL[2]), .PADDR(PADDR[27:0]), .PWDATA, .PSTRB, .PWRITE, .PENABLE, - .PRDATA(PRDATA[2]), .PREADY(PREADY[2]), .UARTIntr, .GPIOIntr, .SDCIntr, .MExtInt, .SExtInt); + .PRDATA(PRDATA[2]), .PREADY(PREADY[2]), .UARTIntr, .GPIOIntr, .SDCIntr, .SPIIntr, .MExtInt, .SExtInt); end else begin : plic assign MExtInt = 0; assign SExtInt = 0; @@ -145,6 +148,14 @@ module uncore import cvw::*; #(parameter cvw_t P)( end else begin : uart assign UARTSout = 0; assign UARTIntr = 0; 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); + end else begin : spi + assign SPIOut = 0; assign SPICS = 0; assign SPIIntr = 0; + end // AHB Read Multiplexer assign HRDATA = ({P.XLEN{HSELRamD}} & HREADRam) | @@ -168,6 +179,8 @@ module uncore import cvw::*; #(parameter cvw_t P)( // takes more than 1 cycle to repsond it needs to hold on to the old select until the // device is ready. Hense this register must be selectively enabled by HREADY. // However on reset None must be seleted. - flopenl #(11) hseldelayreg(HCLK, ~HRESETn, HREADY, HSELRegions, 11'b1, {HSELDTIMD, HSELIROMD, HSELEXTD, HSELBootRomD, HSELRamD, HSELCLINTD, HSELGPIOD, HSELUARTD, HSELPLICD, HSELEXTSDCD, HSELNoneD}); + flopenl #(12) hseldelayreg(HCLK, ~HRESETn, HREADY, HSELRegions, 12'b1, + {HSELDTIMD, HSELIROMD, HSELEXTD, HSELBootRomD, HSELRamD, + HSELCLINTD, HSELGPIOD, HSELUARTD, HSELPLICD, HSELEXTSDCD, HSELSPID, HSELNoneD}); flopenr #(1) hselbridgedelayreg(HCLK, ~HRESETn, HREADY, HSELBRIDGE, HSELBRIDGED); endmodule diff --git a/src/wally/wallypipelinedsoc.sv b/src/wally/wallypipelinedsoc.sv index 2764d55f3..ab0071fff 100644 --- a/src/wally/wallypipelinedsoc.sv +++ b/src/wally/wallypipelinedsoc.sv @@ -54,11 +54,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 SDCIntr, + input logic SPIIn, // SPI pins in + output logic SPIOut, // SPI pins out + output logic [3:0] SPICS // SPI chip select pins ); // Uncore signals - logic [P.AHBW-1:0] HRDATA; // from AHB mux in uncore + logic [P.AHBW-1:0] HRDATA; // from AHB mux in uncore logic HRESP; // response from AHB logic MTimerInt, MSwInt;// timer and software interrupts from CLINT logic [63:0] MTIME_CLINT; // from CLINT to CSRs @@ -80,7 +83,7 @@ module wallypipelinedsoc import cvw::*; #(parameter cvw_t P) ( .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HSIZE, .HBURST, .HPROT, .HTRANS, .HMASTLOCK, .HRDATAEXT, .HREADYEXT, .HRESPEXT, .HRDATA, .HREADY, .HRESP, .HSELEXT, .HSELEXTSDC, .MTimerInt, .MSwInt, .MExtInt, .SExtInt, .GPIOIN, .GPIOOUT, .GPIOEN, .UARTSin, - .UARTSout, .MTIME_CLINT, .SDCIntr); + .UARTSout, .MTIME_CLINT, .SDCIntr, .SPIIn, .SPIOut, .SPICS); end endmodule diff --git a/synthDC/README.md b/synthDC/README.md index 91804b29b..edbd57340 100644 --- a/synthDC/README.md +++ b/synthDC/README.md @@ -31,3 +31,12 @@ SAIFPOWER 0: switching factor power analysis 1: RTL simulation driven power analysis. +----- +Extra Tool (PPA) + +To run ppa analysis that hones into target frequency, you can type: +python3 ppa/ppaSynth.py from the synthDC directory. This runs a sweep +across all modules listed at the bottom of the ppaSynth.py file. + + + diff --git a/synthDC/ppa/ppaAnalyze.py b/synthDC/ppa/ppaAnalyze.py index 03758cdf6..459a8520d 100755 --- a/synthDC/ppa/ppaAnalyze.py +++ b/synthDC/ppa/ppaAnalyze.py @@ -1,5 +1,9 @@ #!/usr/bin/python3 +# +# Python regression test for DC # Madeleine Masser-Frye mmasserfrye@hmc.edu 5/22 +# James Stine james.stine@okstate.edu 15 October 2023 +# import scipy.optimize as opt import subprocess @@ -565,6 +569,7 @@ def makeLineLegend(): fullLeg += [lines.Line2D([0], [0], color='black', label='smallest', linestyle='--')] fullLeg += [lines.Line2D([0], [0], color='blue', label='tsmc28', marker='^')] fullLeg += [lines.Line2D([0], [0], color='green', label='sky90', marker='o')] + fullLeg += [lines.Line2D([0], [0], color='green', label='sky130', marker='+')] fullLeg += [lines.Line2D([0], [0], color='red', label='combined', marker='_')] fig.legend(handles=fullLeg, ncol=5, handlelength=1.4, loc='center') saveStr = './plots/legend.png' @@ -689,7 +694,7 @@ def makePlotDirectory(): os.makedirs(new_directory) os.chdir(new_directory) if 'freq' in folder: - for tech in ['sky90', 'tsmc28']: + for tech in ['sky90', 'sky130', 'tsmc28']: for mod in modules: tech_directory = os.path.join(new_directory, tech) mod_directory = os.path.join(tech_directory, mod) @@ -702,15 +707,14 @@ def makePlotDirectory(): if __name__ == '__main__': ############################## # set up stuff, global variables - widths = [8, 16, 32, 64, 128] - modules = ['priorityencoder', 'add', 'csa', 'shiftleft', 'comparator', 'flop', 'mux2', 'mux4', 'mux8', 'mult'] #, 'mux2d', 'mux4d', 'mux8d'] + widths = [8, 16, 32, 64, 128] + modules = ['priorityencoder', 'add', 'csa', 'shiftleft', 'comparator', 'flop', 'mux2', 'mux4', 'mux8', 'mult'] normAddWidth = 32 # divisor to use with N since normalizing to add_32 - fitDict = {'add': ['cg', 'l', 'l'], 'mult': ['cg', 's', 's'], 'comparator': ['cg', 'l', 'l'], 'csa': ['c', 'l', 'l'], 'shiftleft': ['cg', 'l', 'ln'], 'flop': ['c', 'l', 'l'], 'priorityencoder': ['cg', 'l', 'l']} - fitDict.update(dict.fromkeys(['mux2', 'mux4', 'mux8'], ['cg', 'l', 'l'])) + fitDict = {'add': ['cg', 'l', 'l'], 'mult': ['cg', 's', 's'], 'comparator': ['cg', 'l', 'l'], 'csa': ['c', 'l', 'l'], 'shiftleft': ['cg', 'l', 'ln'], 'flop': ['c', 'l', 'l'], 'priorityencoder': ['cg', 'l', 'l']} fitDict.update(dict.fromkeys(['mux2', 'mux4', 'mux8'], ['cg', 'l', 'l'])) TechSpec = namedtuple("TechSpec", "tech color shape delay area lpower denergy") - techSpecs = [['sky90', 'green', 'o', 43.2e-3, 1440.600027, 714.057, 0.658022690438], ['tsmc28', 'blue', '^', 12.2e-3, 209.286002, 1060.0, .08153281695882594]] + techSpecs = [['sky90', 'green', 'o', 43.2e-3, 1440.600027, 714.057, 0.658022690438], ['sky130', 'red', 'o', 43.2e-3, 1440.600027, 714.057, 0.658022690438], ['tsmc28', 'blue', '^', 12.2e-3, 209.286002, 1060.0, .08153281695882594]] techSpecs = [TechSpec(*t) for t in techSpecs] combined = TechSpec('combined fit', 'red', '_', 0, 0, 0, 0) ############################## @@ -731,7 +735,8 @@ if __name__ == '__main__': for mod in modules: for w in widths: freqPlot('sky90', mod, w) - freqPlot('tsmc28', mod, w) - plotPPA(mod, norm=False) - plotPPA(mod, aleOpt=True) - plt.close('all') \ No newline at end of file + #freqPlot('sky130', mod, w) + #freqPlot('tsmc28', mod, w) + #plotPPA(mod, norm=False) + #plotPPA(mod, aleOpt=True) + plt.close('all') diff --git a/synthDC/ppa/ppaSynth.py b/synthDC/ppa/ppaSynth.py index cbfd52538..d9d07c10d 100755 --- a/synthDC/ppa/ppaSynth.py +++ b/synthDC/ppa/ppaSynth.py @@ -1,5 +1,9 @@ #!/usr/bin/python3 -# Madeleine Masser-Frye mmasserfrye@hmc.edu 6/22 +# +# Python regression test for DC +# Madeleine Masser-Frye mmasserfrye@hmc.edu 5/22 +# James Stine james.stine@okstate.edu 15 October 2023 +# import subprocess import re @@ -7,7 +11,9 @@ from multiprocessing import Pool from ppaAnalyze import synthsfromcsv def runCommand(module, width, tech, freq): - command = "make synth DESIGN=ppa_{}_{} TECH={} DRIVE=INV FREQ={} MAXOPT=1 MAXCORES=1".format(module, width, tech, freq) + command = "make synth DESIGN={} WIDTH={} TECH={} DRIVE=INV FREQ={} MAXOPT=1 MAXCORES=1".format(module, width, tech, freq) + print('here we go') + subprocess.Popen(command, shell=True) def deleteRedundant(synthsToRun): @@ -20,7 +26,7 @@ def deleteRedundant(synthsToRun): def freqSweep(module, width, tech): synthsToRun = [] arr = [-8, -6, -4, -2, 0, 2, 4, 6, 8] - allSynths = synthsfromcsv('bestSynths.csv') + allSynths = synthsfromcsv('ppa/bestSynths.csv') for synth in allSynths: if (synth.module == module) & (synth.tech == tech) & (synth.width == width): f = 1000/synth.delay @@ -54,20 +60,20 @@ def allCombos(widths, modules, techs, freqs): if __name__ == '__main__': ##### Run specific syntheses - widths = [8, 16, 32, 64, 128] - modules = ['mult', 'add', 'shiftleft', 'flop', 'comparator', 'priorityencoder', 'add', 'csa', 'mux2', 'mux4', 'mux8'] - techs = ['sky90', 'tsmc28'] - freqs = [5000] - synthsToRun = allCombos(widths, modules, techs, freqs) + widths = [8, 16, 32, 64, 128] + modules = ['mult', 'add', 'shiftleft', 'flop', 'comparator', 'priorityencoder', 'add', 'csa', 'mux2', 'mux4', 'mux8'] + techs = ['sky90', 'tsmc28'] + freqs = [5000] + synthsToRun = allCombos(widths, modules, techs, freqs) ##### Run a sweep based on best delay found in existing syntheses - module = 'add' - width = 32 - tech = 'sky90' - synthsToRun = freqSweep(module, width, tech) + module = 'add' + width = 32 + tech = 'sky90' + synthsToRun = freqSweep(module, width, tech) ##### Only do syntheses for which a run doesn't already exist - synthsToRun = filterRedundant(synthsToRun) - - pool = Pool(processes=25) - pool.starmap(print, synthsToRun) \ No newline at end of file + synthsToRun = filterRedundant(synthsToRun) + + pool = Pool(processes=25) + pool.starmap(runCommand, synthsToRun) diff --git a/synthDC/scripts/synth.tcl b/synthDC/scripts/synth.tcl index 91ec44e2a..ba548869f 100755 --- a/synthDC/scripts/synth.tcl +++ b/synthDC/scripts/synth.tcl @@ -32,17 +32,15 @@ eval file copy -force [glob ${hdl_src}/cvw.sv] {$outputDir/hdl/} eval file copy -force [glob ${hdl_src}/*/*.sv] {$outputDir/hdl/} eval file copy -force [glob ${hdl_src}/*/*/*.sv] {$outputDir/hdl/} -# Check if a wrapper is needed (when cvw_t parameters are used) +# Check if a wrapper is needed and create it (to pass parameters when cvw_t parameters are used) set wrapper 0 -if {[eval exec grep "cvw_t" {$outputDir/hdl/$::env(DESIGN).sv}] ne ""} { +if {[catch {eval exec grep "cvw_t" $outputDir/hdl/$::env(DESIGN).sv}] == 0} { + echo "Creating wrapper" set wrapper 1 # make the wrapper exec python3 $::env(WALLY)/synthDC/scripts/wrapperGen.py $::env(DESIGN) $outputDir/hdl } -# Only for FMA class project; comment out when done -# eval file copy -force [glob ${hdl_src}/fma/fma16.v] {hdl/} - # Enables name mapping if { $saifpower == 1 } { saif_map -start @@ -310,6 +308,8 @@ set filename [format "%s%s" $outputDir "/reports/mindelay.rep"] redirect $filename { report_timing -capacitance -transition_time -nets -delay_type min -nworst 1 } set filename [format "%s%s" $outputDir "/reports/per_module_timing.rep"] +redirect -append $filename { echo "\n\n\n//// Critical paths through Stall ////\n\n\n" } +redirect -append $filename { report_timing -capacitance -transition_time -nets -through {Stall*} -nworst 1 } redirect -append $filename { echo "\n\n\n//// Critical paths through ifu ////\n\n\n" } redirect -append $filename { report_timing -capacitance -transition_time -nets -through {ifu/*} -nworst 1 } redirect -append $filename { echo "\n\n\n//// Critical paths through ieu ////\n\n\n" } diff --git a/synthDC/scripts/wrapperGen.py b/synthDC/scripts/wrapperGen.py index 3a0984bc3..b570ad0c0 100755 --- a/synthDC/scripts/wrapperGen.py +++ b/synthDC/scripts/wrapperGen.py @@ -21,7 +21,7 @@ args=parser.parse_args() fin_path = glob.glob(f"{os.getenv('WALLY')}/src/**/{args.DESIGN}.sv",recursive=True)[0] -fin = open(fin_path, "r") +fin = open(fin_path, "r", encoding='utf-8') lines = fin.readlines() @@ -70,4 +70,4 @@ fout.write(buf) fin.close() fout.close() -#print(buf) \ No newline at end of file +#print(buf) diff --git a/testbench/common/shadowmem.sv b/testbench/common/DCaacheFlushFSM.sv similarity index 99% rename from testbench/common/shadowmem.sv rename to testbench/common/DCaacheFlushFSM.sv index 19884390d..1696a661c 100644 --- a/testbench/common/shadowmem.sv +++ b/testbench/common/DCaacheFlushFSM.sv @@ -1,5 +1,5 @@ /////////////////////////////////////////// -// shadowmem.sv +// DCacheFlushFSM.sv // // Written: David Harris David_Harris@hmc.edu and Ross Thompson ross1728@gmail.com // Modified: 14 June 2023 diff --git a/testbench/common/loggers.sv b/testbench/common/loggers.sv index 9dd2a7950..db259da7a 100644 --- a/testbench/common/loggers.sv +++ b/testbench/common/loggers.sv @@ -217,7 +217,7 @@ module loggers import cvw::*; #(parameter cvw_t P, logic PCSrcM; string LogFile; logic resetD, resetEdge; - flopenrc #(1) PCSrcMReg(clk, reset, dut.core.FlushM, ~dut.core.StallM, dut.core.ifu.bpred.bpred.Predictor.DirPredictor.PCSrcE, PCSrcM); + flopenrc #(1) PCSrcMReg(clk, reset, dut.core.FlushM, ~dut.core.StallM, dut.core.ifu.PCSrcE, PCSrcM); flop #(1) ResetDReg(clk, reset, resetD); assign resetEdge = ~reset & resetD; initial begin diff --git a/testbench/common/watchdog.sv b/testbench/common/watchdog.sv index 51ed8c30f..1e2b760ca 100644 --- a/testbench/common/watchdog.sv +++ b/testbench/common/watchdog.sv @@ -30,11 +30,13 @@ module watchdog #(parameter XLEN, WatchDogTimerThreshold) ); // check for hang up. - logic [XLEN-1:0] PCW; - flopenr #(XLEN) PCWReg(clk, reset, ~dut.core.ieu.dp.StallW, dut.core.ifu.PCM, PCW); - logic [XLEN-1:0] OldPCW; + logic [XLEN-1:0] PCM, PCW, OldPCW; integer WatchDogTimerCount; logic WatchDogTimeOut; + + flopenr #(XLEN) PCMReg(clk, reset, ~dut.core.ifu.StallM, dut.core.ifu.PCE, PCM); // duplicate PCM register because it is not in ifu for all configurations + flopenr #(XLEN) PCWReg(clk, reset, ~dut.core.ieu.dp.StallW, PCM, PCW); + always_ff @(posedge clk) begin OldPCW <= PCW; if(OldPCW == PCW) WatchDogTimerCount = WatchDogTimerCount + 1'b1; diff --git a/testbench/testbench-fp.sv b/testbench/testbench-fp.sv index 2ddd13072..e5f215e07 100644 --- a/testbench/testbench-fp.sv +++ b/testbench/testbench-fp.sv @@ -644,11 +644,11 @@ module testbenchfp; // Read the first test initial begin //string testname = {`PATH, Tests[TestNum]}; - string p = `PATH; + static string pp = `PATH; string testname; string tt0; tt0 = $psprintf("%s", Tests[TestNum]); - testname = {p, tt0}; + testname = {pp, tt0}; $display("Here you are %s", testname); $display("\n\nRunning %s vectors ", Tests[TestNum]); $readmemh(testname, TestVectors); diff --git a/testbench/testbench-imperas.sv b/testbench/testbench-imperas.sv index ac7e49a48..b503372d4 100644 --- a/testbench/testbench-imperas.sv +++ b/testbench/testbench-imperas.sv @@ -72,6 +72,7 @@ module testbench; logic HMASTLOCK; logic HCLK, HRESETn; logic [P.XLEN-1:0] PCW; + logic [31:0] NextInstrE, InstrM; string ProgramAddrMapFile, ProgramLabelMapFile; integer ProgramAddrLabelArray [string] = '{ "begin_signature" : 0, "tohost" : 0 }; @@ -81,7 +82,8 @@ module testbench; logic [31:0] GPIOIN, GPIOOUT, GPIOEN; logic UARTSin, UARTSout; - + logic SPIIn, SPIOut; + logic [3:0] SPICS; logic SDCIntr; logic HREADY; @@ -214,7 +216,7 @@ module testbench; `endif flopenr #(P.XLEN) PCWReg(clk, reset, ~dut.core.ieu.dp.StallW, dut.core.ifu.PCM, PCW); - flopenr #(32) InstrWReg(clk, reset, ~dut.core.ieu.dp.StallW, dut.core.ifu.InstrM, InstrW); + flopenr #(32) InstrWReg(clk, reset, ~dut.core.ieu.dp.StallW, InstrM, InstrW); // check assertions for a legal configuration riscvassertions #(P) riscvassertions(); @@ -255,13 +257,13 @@ module testbench; wallypipelinedsoc #(P) dut(.clk, .reset_ext, .reset, .HRDATAEXT, .HREADYEXT, .HRESPEXT, .HSELEXT, .HSELEXTSDC, .HCLK, .HRESETn, .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HSIZE, .HBURST, .HPROT, .HTRANS, .HMASTLOCK, .HREADY, .TIMECLK(1'b0), .GPIOIN, .GPIOOUT, .GPIOEN, - .UARTSin, .UARTSout, .SDCIntr); + .UARTSin, .UARTSout, .SDCIntr, .SPICS, .SPIOut, .SPIIn); // Track names of instructions instrTrackerTB it(clk, reset, dut.core.ieu.dp.FlushE, dut.core.ifu.InstrRawF[31:0], dut.core.ifu.InstrD, dut.core.ifu.InstrE, - dut.core.ifu.InstrM, InstrW, + InstrM, InstrW, InstrFName, InstrDName, InstrEName, InstrMName, InstrWName); // initialize tests @@ -298,6 +300,10 @@ module testbench; .ProgramLabelMapFile(ProgramLabelMapFile)); end + // Duplicate copy of pipeline registers that are optimized out of some configurations + mux2 #(32) FlushInstrMMux(dut.core.ifu.InstrE, dut.core.ifu.nop, dut.core.ifu.FlushM, NextInstrE); + flopenr #(32) InstrMReg(clk, reset, ~dut.core.ifu.StallM, NextInstrE, InstrM); + // Termination condition // terminate on a specific ECALL after li x3,1 for old Imperas tests, *** remove this when old imperas tests are removed // or sw gp,-56(t0) for new Imperas tests @@ -311,7 +317,7 @@ module testbench; (dut.core.ieu.dp.regf.we3 & dut.core.ieu.dp.regf.a3 == 3 & dut.core.ieu.dp.regf.wd3 == 1)) | - ((dut.core.ifu.InstrM == 32'h6f | dut.core.ifu.InstrM == 32'hfc32a423 | dut.core.ifu.InstrM == 32'hfc32a823) & dut.core.ieu.c.InstrValidM ) | + ((InstrM == 32'h6f | InstrM == 32'hfc32a423 | InstrM == 32'hfc32a823) & dut.core.ieu.c.InstrValidM ) | ((dut.core.lsu.IEUAdrM == ProgramAddrLabelArray["tohost"]) & InstrMName == "SW" ); DCacheFlushFSM #(P) DCacheFlushFSM(.clk(clk), diff --git a/testbench/testbench-linux-imperas.sv b/testbench/testbench-linux-imperas.sv index 52a351d2e..d38535003 100644 --- a/testbench/testbench-linux-imperas.sv +++ b/testbench/testbench-linux-imperas.sv @@ -229,10 +229,16 @@ module testbench; /////////////////////////////////////////////////////////////////////////////// /////////////////////////////// Cache Issue /////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// + + // Duplicate copy of pipeline registers that are optimized out of some configurations + logic [31:0] NextInstrE, InstrM; + mux2 #(32) FlushInstrMMux(dut.core.ifu.InstrE, dut.core.ifu.nop, dut.core.ifu.FlushM, NextInstrE); + flopenr #(32) InstrMReg(clk, reset, ~dut.core.ifu.StallM, NextInstrE, InstrM); + logic probe; if (NO_SPOOFING) assign probe = testbench.dut.core.PCM == 64'hffffffff80200c8c - & testbench.dut.core.InstrM != 32'h14021273 + & InstrM != 32'h14021273 & testbench.dut.core.InstrValidM; @@ -276,7 +282,9 @@ module testbench; logic SDCCmdOE; logic [3:0] SDCDatIn; logic SDCIntr; - + logic SPIIn, SPIOut; + logic [3:0] SPICS; + // Hardwire UART, GPIO pins assign GPIOIN = 0; @@ -434,13 +442,10 @@ module testbench; // Wally - wallypipelinedsoc #(P) dut(.clk, .reset, .reset_ext, - .HRDATAEXT, .HREADYEXT, .HREADY, .HSELEXT, .HRESPEXT, .HCLK, - .HRESETn, .HADDR, .HWDATA, .HWRITE, .HWSTRB, .HSIZE, .HBURST, .HPROT, - .HTRANS, .HMASTLOCK, - .TIMECLK('0), .GPIOIN, .GPIOOUT, .GPIOEN, - .UARTSin, .UARTSout, - .SDCIntr); + wallypipelinedsoc #(P) dut(.clk, .reset_ext, .reset, .HRDATAEXT, .HREADYEXT, .HRESPEXT, .HSELEXT, .HSELEXTSDC, + .HCLK, .HRESETn, .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HSIZE, .HBURST, .HPROT, + .HTRANS, .HMASTLOCK, .HREADY, .TIMECLK(1'b0), .GPIOIN, .GPIOOUT, .GPIOEN, + .UARTSin, .UARTSout, .SDCIntr, .SPICS, .SPIOut, .SPIIn); // W-stage hardware not needed by Wally itself parameter nop = 'h13; @@ -452,7 +457,7 @@ module testbench; `define FLUSHW dut.core.FlushW `define STALLW dut.core.StallW flopenrc #(P.XLEN) PCWReg(clk, reset, `FLUSHW, ~`STALLW, `PCM, PCW); - flopenr #(32) InstrWReg(clk, reset, ~`STALLW, `FLUSHW ? nop : dut.core.ifu.InstrM, InstrW); + flopenr #(32) InstrWReg(clk, reset, ~`STALLW, `FLUSHW ? nop : InstrM, InstrW); flopenrc #(1) controlregW(clk, reset, `FLUSHW, ~`STALLW, dut.core.ieu.c.InstrValidM, InstrValidW); flopenrc #(P.XLEN) IEUAdrWReg(clk, reset, `FLUSHW, ~`STALLW, dut.core.IEUAdrM, IEUAdrW); flopenrc #(P.XLEN) WriteDataWReg(clk, reset, `FLUSHW, ~`STALLW, dut.core.lsu.WriteDataM, WriteDataW); @@ -969,7 +974,7 @@ module testbench; instrTrackerTB it(clk, reset, dut.core.ieu.dp.FlushE, dut.core.ifu.InstrRawF[31:0], dut.core.ifu.InstrD, dut.core.ifu.InstrE, - dut.core.ifu.InstrM, InstrW, + InstrM, InstrW, InstrFName, InstrDName, InstrEName, InstrMName, InstrWName); // ------------------ diff --git a/testbench/testbench-linux.sv b/testbench/testbench-linux.sv index 683f55952..011c4d148 100644 --- a/testbench/testbench-linux.sv +++ b/testbench/testbench-linux.sv @@ -212,10 +212,16 @@ module testbench; /////////////////////////////////////////////////////////////////////////////// /////////////////////////////// Cache Issue /////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// + + // Duplicate copy of pipeline registers that are optimized out of some configurations + logic [31:0] NextInstrE, InstrM; + mux2 #(32) FlushInstrMMux(dut.core.ifu.InstrE, dut.core.ifu.nop, dut.core.ifu.FlushM, NextInstrE); + flopenr #(32) InstrMReg(dut.core.clk, dut.core.reset, ~dut.core.ifu.StallM, NextInstrE, InstrM); + logic probe; if (NO_SPOOFING) assign probe = testbench.dut.core.PCM == 64'hffffffff80200c8c - & testbench.dut.core.InstrM != 32'h14021273 + & InstrM != 32'h14021273 & testbench.dut.core.InstrValidM; @@ -252,6 +258,8 @@ module testbench; logic [31:0] GPIOIN; logic [31:0] GPIOOUT, GPIOEN; logic UARTSin, UARTSout; + logic SPIIn, SPIOut; + logic [3:0] SPICS; // FPGA-specific Stuff logic SDCIntr; @@ -262,13 +270,10 @@ module testbench; assign SDCIntr = 0; // Wally - wallypipelinedsoc #(P) dut(.clk, .reset, .reset_ext, - .HRDATAEXT, .HREADYEXT, .HREADY, .HSELEXT, .HSELEXTSDC, .HRESPEXT, .HCLK, - .HRESETn, .HADDR, .HWDATA, .HWRITE, .HWSTRB, .HSIZE, .HBURST, .HPROT, - .HTRANS, .HMASTLOCK, - .TIMECLK('0), .GPIOIN, .GPIOOUT, .GPIOEN, - .UARTSin, .UARTSout, - .SDCIntr); + wallypipelinedsoc #(P) dut(.clk, .reset_ext, .reset, .HRDATAEXT, .HREADYEXT, .HRESPEXT, .HSELEXT, .HSELEXTSDC, + .HCLK, .HRESETn, .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HSIZE, .HBURST, .HPROT, + .HTRANS, .HMASTLOCK, .HREADY, .TIMECLK(1'b0), .GPIOIN, .GPIOOUT, .GPIOEN, + .UARTSin, .UARTSout, .SDCIntr, .SPICS, .SPIOut, .SPIIn); // W-stage hardware not needed by Wally itself parameter nop = 'h13; @@ -280,7 +285,7 @@ module testbench; `define FLUSHW dut.core.FlushW `define STALLW dut.core.StallW flopenrc #(P.XLEN) PCWReg(clk, reset, `FLUSHW, ~`STALLW, `PCM, PCW); - flopenr #(32) InstrWReg(clk, reset, ~`STALLW, `FLUSHW ? nop : dut.core.ifu.InstrM, InstrW); + flopenr #(32) InstrWReg(clk, reset, ~`STALLW, `FLUSHW ? nop : InstrM, InstrW); flopenrc #(1) controlregW(clk, reset, `FLUSHW, ~`STALLW, dut.core.ieu.c.InstrValidM, InstrValidW); flopenrc #(P.XLEN) IEUAdrWReg(clk, reset, `FLUSHW, ~`STALLW, dut.core.IEUAdrM, IEUAdrW); flopenrc #(P.XLEN) WriteDataWReg(clk, reset, `FLUSHW, ~`STALLW, dut.core.lsu.WriteDataM, WriteDataW); @@ -794,7 +799,7 @@ module testbench; instrTrackerTB it(clk, reset, dut.core.ieu.dp.FlushE, dut.core.ifu.InstrRawF[31:0], dut.core.ifu.InstrD, dut.core.ifu.InstrE, - dut.core.ifu.InstrM, InstrW, + InstrM, InstrW, InstrFName, InstrDName, InstrEName, InstrMName, InstrWName); // ------------------ diff --git a/testbench/testbench-xcelium.sv b/testbench/testbench-xcelium.sv index 89a7cc995..44afbcd3b 100644 --- a/testbench/testbench-xcelium.sv +++ b/testbench/testbench-xcelium.sv @@ -70,6 +70,8 @@ module testbench; logic [3:0] SDCDatIn; tri1 [3:0] SDCDat; tri1 SDCCmd; + logic SPIIn, SPIOut; + logic [3:0] SPICS; logic HREADY; logic HSELEXT; @@ -426,10 +428,10 @@ module testbench; assign SDCDat = '0; end - wallypipelinedsoc #(P) dut(.clk, .reset_ext, .reset, .HRDATAEXT,.HREADYEXT, .HRESPEXT,.HSELEXT, - .HCLK, .HRESETn, .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HSIZE, .HBURST, .HPROT, - .HTRANS, .HMASTLOCK, .HREADY, .TIMECLK(1'b0), .GPIOIN, .GPIOOUT, .GPIOEN, - .UARTSin, .UARTSout, .SDCCmdIn, .SDCCmdOut, .SDCCmdOE, .SDCDatIn, .SDCCLK); + wallypipelinedsoc #(P) dut(.clk, .reset_ext, .reset, .HRDATAEXT, .HREADYEXT, .HRESPEXT, .HSELEXT, .HSELEXTSDC, + .HCLK, .HRESETn, .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HSIZE, .HBURST, .HPROT, + .HTRANS, .HMASTLOCK, .HREADY, .TIMECLK(1'b0), .GPIOIN, .GPIOOUT, .GPIOEN, + .UARTSin, .UARTSout, .SDCIntr, .SPICS, .SPIOut, .SPIIn); // generate clock to sequence tests always begin @@ -440,20 +442,25 @@ module testbench; // Support logic //////////////////////////////////////////////////////////////////////////////// + // Duplicate copy of pipeline registers that are optimized out of some configurations + logic [31:0] NextInstrE, InstrM; + mux2 #(32) FlushInstrMMux(dut.core.ifu.InstrE, dut.core.ifu.nop, dut.core.ifu.FlushM, NextInstrE); + flopenr #(32) InstrMReg(clk, reset, ~dut.core.ifu.StallM, NextInstrE, InstrM); + // Track names of instructions string InstrFName, InstrDName, InstrEName, InstrMName, InstrWName; logic [31:0] InstrW; - flopenr #(32) InstrWReg(clk, reset, ~dut.core.ieu.dp.StallW, dut.core.ifu.InstrM, InstrW); + flopenr #(32) InstrWReg(clk, reset, ~dut.core.ieu.dp.StallW, InstrM, InstrW); instrTrackerTB it(clk, reset, dut.core.ieu.dp.FlushE, dut.core.ifu.InstrRawF[31:0], dut.core.ifu.InstrD, dut.core.ifu.InstrE, - dut.core.ifu.InstrM, InstrW, + InstrM, InstrW, InstrFName, InstrDName, InstrEName, InstrMName, InstrWName); // watch for problems such as lockup, reading unitialized memory, bad configs watchdog #(P.XLEN, 1000000) watchdog(.clk, .reset); // check if PCW is stuck ramxdetector #(P.XLEN, P.LLEN) ramxdetector(clk, dut.core.lsu.MemRWM[1], dut.core.lsu.LSULoadAccessFaultM, dut.core.lsu.ReadDataM, - dut.core.ifu.PCM, dut.core.ifu.InstrM, dut.core.lsu.IEUAdrM, InstrMName); + dut.core.ifu.PCM, InstrM, dut.core.lsu.IEUAdrM, InstrMName); riscvassertions #(P) riscvassertions(); // check assertions for a legal configuration loggers #(P, TEST, PrintHPMCounters, I_CACHE_ADDR_LOGGER, D_CACHE_ADDR_LOGGER, BPRED_LOGGER) loggers (clk, reset, DCacheFlushStart, DCacheFlushDone, memfilename); @@ -478,7 +485,7 @@ module testbench; (dut.core.ieu.dp.regf.we3 & dut.core.ieu.dp.regf.a3 == 3 & dut.core.ieu.dp.regf.wd3 == 1)) | - ((dut.core.ifu.InstrM == 32'h6f | dut.core.ifu.InstrM == 32'hfc32a423 | dut.core.ifu.InstrM == 32'hfc32a823) & dut.core.ieu.c.InstrValidM ) | + ((InstrM == 32'h6f | InstrM == 32'hfc32a423 | InstrM == 32'hfc32a823) & dut.core.ieu.c.InstrValidM ) | ((dut.core.lsu.IEUAdrM == ProgramAddrLabelArray["tohost"]) & InstrMName == "SW" ); DCacheFlushFSM #(P) DCacheFlushFSM(.clk(clk), .reset(reset), .start(DCacheFlushStart), .done(DCacheFlushDone)); diff --git a/testbench/testbench.sv b/testbench/testbench.sv index 97d91b0ab..20f1412c9 100644 --- a/testbench/testbench.sv +++ b/testbench/testbench.sv @@ -64,7 +64,8 @@ module testbench; logic [31:0] GPIOIN, GPIOOUT, GPIOEN; logic UARTSin, UARTSout; - + logic SPIIn, SPIOut; + logic [3:0] SPICS; logic SDCIntr; logic HREADY; @@ -367,6 +368,7 @@ module testbench; // instantiate device to be tested assign GPIOIN = 0; assign UARTSin = 1; + assign SPIIn = 0; if(P.EXT_MEM_SUPPORTED) begin ram_ahb #(.BASE(P.EXT_MEM_BASE), .RANGE(P.EXT_MEM_RANGE)) @@ -397,7 +399,7 @@ module testbench; wallypipelinedsoc #(P) dut(.clk, .reset_ext, .reset, .HRDATAEXT, .HREADYEXT, .HRESPEXT, .HSELEXT, .HSELEXTSDC, .HCLK, .HRESETn, .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HSIZE, .HBURST, .HPROT, .HTRANS, .HMASTLOCK, .HREADY, .TIMECLK(1'b0), .GPIOIN, .GPIOOUT, .GPIOEN, - .UARTSin, .UARTSout, .SDCIntr); + .UARTSin, .UARTSout, .SDCIntr, .SPIIn, .SPIOut, .SPICS); // generate clock to sequence tests always begin @@ -408,20 +410,25 @@ module testbench; // Support logic //////////////////////////////////////////////////////////////////////////////// + // Duplicate copy of pipeline registers that are optimized out of some configurations + logic [31:0] NextInstrE, InstrM; + mux2 #(32) FlushInstrMMux(dut.core.ifu.InstrE, dut.core.ifu.nop, dut.core.ifu.FlushM, NextInstrE); + flopenr #(32) InstrMReg(clk, reset, ~dut.core.ifu.StallM, NextInstrE, InstrM); + // Track names of instructions string InstrFName, InstrDName, InstrEName, InstrMName, InstrWName; logic [31:0] InstrW; - flopenr #(32) InstrWReg(clk, reset, ~dut.core.ieu.dp.StallW, dut.core.ifu.InstrM, InstrW); + flopenr #(32) InstrWReg(clk, reset, ~dut.core.ieu.dp.StallW, InstrM, InstrW); instrTrackerTB it(clk, reset, dut.core.ieu.dp.FlushE, dut.core.ifu.InstrRawF[31:0], dut.core.ifu.InstrD, dut.core.ifu.InstrE, - dut.core.ifu.InstrM, InstrW, + InstrM, InstrW, InstrFName, InstrDName, InstrEName, InstrMName, InstrWName); // watch for problems such as lockup, reading unitialized memory, bad configs watchdog #(P.XLEN, 1000000) watchdog(.clk, .reset); // check if PCW is stuck ramxdetector #(P.XLEN, P.LLEN) ramxdetector(clk, dut.core.lsu.MemRWM[1], dut.core.lsu.LSULoadAccessFaultM, dut.core.lsu.ReadDataM, - dut.core.ifu.PCM, dut.core.ifu.InstrM, dut.core.lsu.IEUAdrM, InstrMName); + dut.core.ifu.PCM, InstrM, dut.core.lsu.IEUAdrM, InstrMName); riscvassertions #(P) riscvassertions(); // check assertions for a legal configuration loggers #(P, TEST, PrintHPMCounters, I_CACHE_ADDR_LOGGER, D_CACHE_ADDR_LOGGER, BPRED_LOGGER) loggers (clk, reset, DCacheFlushStart, DCacheFlushDone, memfilename); @@ -446,7 +453,7 @@ module testbench; (dut.core.ieu.dp.regf.we3 & dut.core.ieu.dp.regf.a3 == 3 & dut.core.ieu.dp.regf.wd3 == 1)) | - ((dut.core.ifu.InstrM == 32'h6f | dut.core.ifu.InstrM == 32'hfc32a423 | dut.core.ifu.InstrM == 32'hfc32a823) & dut.core.ieu.c.InstrValidM ) | + ((InstrM == 32'h6f | InstrM == 32'hfc32a423 | InstrM == 32'hfc32a823) & dut.core.ieu.c.InstrValidM ) | ((dut.core.lsu.IEUAdrM == ProgramAddrLabelArray["tohost"]) & InstrMName == "SW" ); DCacheFlushFSM #(P) DCacheFlushFSM(.clk(clk), .reset(reset), .start(DCacheFlushStart), .done(DCacheFlushDone)); diff --git a/testbench/tests.vh b/testbench/tests.vh index 7b9243368..8ebc98730 100644 --- a/testbench/tests.vh +++ b/testbench/tests.vh @@ -2010,7 +2010,8 @@ string arch64zbs[] = '{ "rv64i_m/privilege/src/WALLY-gpio-01.S", "rv64i_m/privilege/src/WALLY-plic-01.S", "rv64i_m/privilege/src/WALLY-plic-s-01.S", - "rv64i_m/privilege/src/WALLY-uart-01.S" + "rv64i_m/privilege/src/WALLY-uart-01.S", + "rv64i_m/privilege/src/WALLY-spi-01.S" }; string wally32e[] = '{ @@ -2096,7 +2097,8 @@ string arch64zbs[] = '{ "rv32i_m/privilege/src/WALLY-clint-01.S", "rv32i_m/privilege/src/WALLY-uart-01.S", "rv32i_m/privilege/src/WALLY-plic-01.S", - "rv32i_m/privilege/src/WALLY-plic-s-01.S" + "rv32i_m/privilege/src/WALLY-plic-s-01.S", + "rv32i_m/privilege/src/WALLY-spi-01.S" }; diff --git a/testbench/wallywrapper.sv b/testbench/wallywrapper.sv index 465aaec90..990ebfe74 100644 --- a/testbench/wallywrapper.sv +++ b/testbench/wallywrapper.sv @@ -1,11 +1,10 @@ /////////////////////////////////////////// -// testbench.sv +// wallywrapper.sv // // Written: David_Harris@hmc.edu 9 January 2021 // Modified: // -// Purpose: Wally Testbench and helper modules -// Applies test programs from the riscv-arch-test and Imperas suites +// Purpose: Wrapper module to define parameters for Wally Verilator linting // // A component of the Wally configurable RISC-V project. // @@ -51,6 +50,8 @@ module wallywrapper; logic [31:0] GPIOIN, GPIOOUT, GPIOEN; logic UARTSin, UARTSout; + logic SPIIn, SPIOut; + logic [3:0] SPICS; logic SDCIntr; logic HREADY; @@ -70,6 +71,6 @@ module wallywrapper; wallypipelinedsoc #(P) dut(.clk, .reset_ext, .reset, .HRDATAEXT,.HREADYEXT, .HRESPEXT,.HSELEXT, .HSELEXTSDC, .HCLK, .HRESETn, .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HSIZE, .HBURST, .HPROT, .HTRANS, .HMASTLOCK, .HREADY, .TIMECLK(1'b0), .GPIOIN, .GPIOOUT, .GPIOEN, - .UARTSin, .UARTSout, .SDCIntr); + .UARTSin, .UARTSout, .SPIIn, .SPIOut, .SPICS, .SDCIntr); endmodule diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/Makefrag b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/Makefrag index cb28d7cf4..67f7c2f93 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/Makefrag +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/Makefrag @@ -56,6 +56,7 @@ target_tests_nosim = \ WALLY-clint-01 \ WALLY-plic-01 \ WALLY-uart-01 \ + WALLY-spi-01 \ WALLY-cbom-01 \ WALLY-cboz-01 \ diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/references/WALLY-spi-01.reference_output b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/references/WALLY-spi-01.reference_output new file mode 100644 index 000000000..b1b76274e --- /dev/null +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/references/WALLY-spi-01.reference_output @@ -0,0 +1,288 @@ +00000003 # reset tests sck_div + +00000000 # sck_mode + +00000000 # cs_id + +0000000F # cs_def + +00000000 # cs_mode + +00010001 # delay 0 + +00000001 # delay 1 + +00080000 # fmt + +00000000 # tx_data + +00000000 # tx_mark + +00000000 # rx_mark + +00000000 # ie reset + +00000000 # ip reset + +00000000 # fifo watermark and edge case tests + +00000001 + +00000003 + +00000003 + +00000074 + +00000063 + +00000052 + +00000041 + +000000A1 + +00000003 + +000000B2 + +00000001 + +000000C3 + +000000D4 + +00000003 + +000000A4 + +00000001 + +000000B4 + +000000A5 + +000000B5 + +000000C5 + +000000D5 + +000000A7 + +000000B7 + +000000C7 + +00000002 + +000000D7 + +00000000 + +00000011 #basic read write + +000000FF + +000000A0 + +0000000B + +00000079 + +00000000 + +000000C0 + +00000011 + +00000020 #delay registers + +00000032 + +00000048 + +000000AF + +00000050 + +0000006B + +00000011 + +00000015 + +00000011 #delay1 + +00000022 + +00000033 + +00000044 + +0000007B + +00000021 + +00000032 + +00000043 + +00000054 + +00000066 + +00000077 + +00000088 + +00000099 + +00000066 + +00000077 + +00000088 + +00000099 + +00000065 + +00000076 + +00000087 + +00000098 + +00000048 + +000000DD + +000000CC + +000000BB + +000000AA + +000000DE + +000000CD + +000000BC + +000000AB + +000000CE hold mode deassert + +000000F0 #fmt register + +00000000 + +00000080 + +00000000 + +00000080 + +000000A8 + +000000F8 + +00000048 + +00000070 + +00000000 + +00000008 + +00000003 + +00000017 + +0000000F + +0000001F + +00000062 # hardware interlock + +00000026 + +000000D2 + +0000002D + +00000048 + +00000037 + +00000026 + +00000015 + +00000084 + +00000073 + +00000062 + +00000051 + +00000046 + +00000035 + +00000024 + +00000013 + +00000064 + +00000053 + +00000042 + +00000031 + +00000001 #watermark interrupts + +00000000 #read mip + +00000000 #read tx ip + +00000022 #clear 1 frame from rx fifo + +00000000 # read recieve ip + +00000002 #read recieve ip + +00000000 #read mip + +00000033 #clear frame + +00000000 # read receive ip + +00000044 #clear frame + +00000055 #clear frame + +00000001 #read tx ip + +00000800 #read mip + +00000022 #clear frame + +00000000 #read rx ip + +00000000 #read mip 94 + +00000002 #read rx ip + +00000800 #read mip + +00000033 #clear frame + +00000000 #read rx wm + +00000000 #read mip 99 + diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-TEST-LIB-32.h b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-TEST-LIB-32.h index b6304fbc6..abbfbaf56 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-TEST-LIB-32.h +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-TEST-LIB-32.h @@ -865,6 +865,7 @@ trap_handler_end_\MODE\(): // place to jump to so we can skip the trap handler a .equ PLIC_INTPRI_GPIO, 0x0C00000C # GPIO is interrupt 3 .equ PLIC_INTPRI_UART, 0x0C000028 # UART is interrupt 10 + .equ PLIC_INTPRI_SPI, 0x0C000018 # SPI in interrupt 6 .equ PLIC_INTPENDING0, 0x0C001000 # intPending0 register .equ PLIC_INTEN00, 0x0C002000 # interrupt enables for context 0 (machine mode) sources 31:1 .equ PLIC_INTEN10, 0x0C002080 # interrupt enables for context 1 (supervisor mode) sources 31:1 @@ -877,6 +878,7 @@ trap_handler_end_\MODE\(): // place to jump to so we can skip the trap handler a .4byte PLIC_THRESH1, 7, write32_test # Set PLIC supervisor mode interrupt threshold to 7 to accept no interrupts .4byte PLIC_INTPRI_GPIO, 7, write32_test # Set GPIO to high priority .4byte PLIC_INTPRI_UART, 7, write32_test # Set UART to high priority + .4byte PLIC_INTPRI_SPI, 7, write32_test # Set UART to high priority .4byte PLIC_INTEN00, 0xFFFFFFFF, write32_test # Enable all interrupt sources for machine mode .4byte PLIC_INTEN10, 0x00000000, write32_test # Disable all interrupt sources for supervisor mode .endm @@ -1028,6 +1030,12 @@ claim_m_plic_interrupts: // clears one non-pending PLIC interrupt sw t3, 0(t2) sw t4, -4(sp) addi sp, sp, -4 + li t2, 0x0C000018 // SPI priority + li t3, 7 + lw t4, 0(t2) + sw t3, 0(t2) + sw t4, -4(sp) + addi sp, sp, -4 li t2, 0x0C002000 li t3, 0x0C200004 li t4, 0xFFF @@ -1038,11 +1046,14 @@ claim_m_plic_interrupts: // clears one non-pending PLIC interrupt sw t6, 0(t2) // restore saved enable status li t2, 0x0C00000C // GPIO priority li t3, 0x0C000028 // UART priority - lw t4, 4(sp) // load stored GPIO and UART priority - lw t5, 0(sp) - addi sp, sp, 8 // restore stack pointer - sw t4, 0(t2) - sw t5, 0(t3) + li t6, 0x0C000018 // SPI priority + lw a4, 8(sp) // load stored GPIO prioroty + lw t4, 4(sp) // load stored UART priority + lw t5, 0(sp) // load stored SPI priority + addi sp, sp, 12 // restore stack pointer + sw a4, 0(t2) + sw t4, 0(t3) + sw t5, 0(t6) j test_loop claim_s_plic_interrupts: // clears one non-pending PLIC interrupt @@ -1128,6 +1139,34 @@ uart_clearmodemintr: lb t2, 0(t2) j test_loop +spi_data_wait: + li t2, 0x10040054 + sw t4, 0(t2) // set rx watermark level + li t2, 0x10040074 + lw t3, 0(t2) //read ip (interrupt pending register) + slli t3, t3, 28 + srli t3, t3, 28 + li t2, 0x00000002 + bge t3, t2, spi_data_ready //branch to done if transmission complete + j spi_data_wait //else check again + +spi_data_ready: + li t2, 0x10040070 + li t3, 0x00000000 + sw t3, 0(t2) //disable rx watermark interrupt + j test_loop + +spi_burst_send: //function for loading multiple frames at once to test delays without returning to test loop + mv t2, t4 + sw t2, 0(t3) + srli t2, t2, 8 + sw t2, 0(t3) + srli t2, t2, 8 + sw t2, 0(t3) + srli t2, t2, 8 + sw t2, 0(t3) + j test_loop + goto_s_mode: // return to address in t3, li a0, 3 // Trap handler behavior (go to supervisor mode) diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-spi-01.S b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-spi-01.S new file mode 100644 index 000000000..b9c82c92d --- /dev/null +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-spi-01.S @@ -0,0 +1,660 @@ +/////////////////////////////////////////// +// +// WALLY-spi +// +// Author: David_Harris@hmc.edu and Naiche Whyte-Aguayo +// +// Created 2023-02-01 +// +// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, +// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +// OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +/////////////////////////////////////////// + +#include "WALLY-TEST-LIB-32.h" + +RVTEST_ISA("RV32I_Zicsr_Zifencei") +RVTEST_CASE(0,"//check ISA:=regex(.*32.*);check ISA:=regex(.*I.*); def Drvtest_mtrap_routine=True;def TEST_CASE_1=True;def NO_SAIL=True;",spi) + +INIT_TESTS + +TRAP_HANDLER m + +j run_test_loop // begin test loop/table tests instead of executing inline code. + +INIT_TEST_TABLE + +END_TESTS + +TEST_STACK_AND_DATA + +.align 2 +test_cases: +# --------------------------------------------------------------------------------------------- +# Test Contents +# +# Here is where the actual tests are held, or rather, what the actual tests do. +# each entry consists of 3 values that will be read in as follows: +# +# '.4byte [x28 Value], [x29 Value], [x30 value]' +# or +# '.4byte [address], [value], [test type]' +# +# The encoding for x30 test type values can be found in the test handler in the framework file +# --------------------------------------------------------------------------------------------- + +.equ SPI, 0x10040000 +.equ sck_div, (SPI+0x00) +.equ sck_mode, (SPI+0x04) +.equ cs_id, (SPI+0x10) +.equ cs_def, (SPI+0x14) +.equ cs_mode, (SPI+0x18) +.equ delay0, (SPI+0x28) +.equ delay1, (SPI+0x2C) +.equ fmt, (SPI+0x40) +.equ tx_data, (SPI+0x48) +.equ rx_data, (SPI+0x4C) +.equ tx_mark, (SPI+0x50) +.equ rx_mark, (SPI+0x54) +.equ ie, (SPI+0x70) +.equ ip, (SPI+0x74) + +# =========== Verify all registers reset to correct values =========== + +.4byte sck_div, 0x00000003, read32_test # sck_div reset to 0x3 +.4byte sck_mode, 0x00000000, read32_test # sck_mode reset to 0x0 +.4byte cs_id, 0x00000000, read32_test # cs_id reset to 0x0 +.4byte cs_def, 0x0000000F, read32_test # cs_def reset to 0x1 +.4byte cs_mode, 0x00000000, read32_test # cs_mode reset to 0x0 +.4byte delay0, 0x00010001, read32_test # delay0 reset to [31:24] 0x0, [23:16] 0x1, [15:8] 0x0, [7:0] 0x1 +.4byte delay1, 0x00000001, read32_test # delay1 reset to 0x1 +.4byte fmt, 0x00080000, read32_test # fmt reset to [31:20] 0x0, [19:16] 0x8, [15:0] 0x0 for non-flash enabled SPI controllers +.4byte tx_data, 0x00000000, read32_test # tx_data [30:0] reset to 0x0, [31] read only +.4byte tx_mark, 0x00000000, read32_test # tx_mark reset to 0x0 for non-flash enabled controllers +.4byte rx_mark, 0x00000000, read32_test # rx_mark reset to 0x0 +.4byte ie, 0x00000000, read32_test # ie reset to 0x0 +.4byte ip, 0x00000000, read32_test # ip reset to 0x0 + +#test watermark interrupts at beginning where fifo read/write pointers are known b/c reset +# txwmp raised when # of entries in txfifo < txmark, rxwm raised when # of entries in rxfifo > rxmark + +.4byte ip, 0x00000000, read32_test # txfifo entries not < 0, rxfifo entries not > 0; +.4byte tx_mark, 0x00000004, write32_test # set tx_mark to 4 +.4byte rx_mark, 0x00000003, write32_test # set rx_mark to 3 +.4byte ip, 0x00000001, read32_test # tx entries < 4, rx entries ! > 3 +.4byte tx_data, 0x41526374, spi_burst_send +.4byte 0x0, 0x00000003, spi_data_wait +.4byte ip, 0x00000003, read32_test # tx entries < 4, rx entries > 3, visual inspection should see tx TransmitFIFOReadIncrement + +# txfifo wptr now at 0011, rxfifo wptr at 0000 + +.4byte rx_mark, 0x00000007, write32_test # set rx_mark to 7 +.4byte tx_data, 0xD4C3B2A1, spi_burst_send +.4byte 0x0, 0x00000007, spi_data_wait # rxfifo full, txfifo wptr at 1000, rxfifo wptr at 0000 +.4byte ip, 0x00000003, read32_test +.4byte rx_data, 0x00000074, read32_test +.4byte rx_data, 0x00000063, read32_test # clear 2 entries, txfifo wptr at 1000, rxfifo wptr at 0010 + + +.4byte tx_data, 0x000000A4, write32_test +.4byte tx_data, 0x000000B4, write32_test # tx 1010, rx 0010 +.4byte 0x0, 0x00000007, spi_data_wait # 8 tx 1010, rx 0010 +.4byte rx_mark, 0x00000004, write32_test +.4byte rx_data, 0x00000052, read32_test # 7 rx 0011 +.4byte rx_data, 0x00000041, read32_test # 6 rx 0100 +.4byte rx_data, 0x000000A1, read32_test # 5 rx 0101 +.4byte ip, 0x00000003, read32_test # 5 things in rx fifo +.4byte rx_data, 0x000000B2, read32_test # 4 tx 1010, rx 0110 +.4byte ip, 0x00000001, read32_test # 4 entries in rxfifo, not strictly greater than 4 + +.4byte rx_mark, 0x00000007, write32_test +.4byte tx_data, 0xD5C5B5A5, spi_burst_send # 8 tx1110, rx 0110 +.4byte 0x0, 0x00000007, spi_data_wait + +.4byte rx_mark, 0x00000005, write32_test +.4byte rx_data, 0x000000C3, read32_test # tx 1110, rx 0111 +.4byte rx_data, 0x000000D4, read32_test # tx 1110, rx 1000 +.4byte ip, 0x00000003, read32_test # 6 entries +.4byte rx_data, 0x000000A4, read32_test # tx 1110, rx 1001 +.4byte ip, 0x00000001, read32_test # 5 entries +.4byte rx_data, 0x000000B4, read32_test # tx 1110, rx 1010 +.4byte rx_data, 0x000000A5, read32_test # tx 1110, rx 1011 + +.4byte rx_mark, 0x00000006, write32_test +.4byte tx_data, 0xD7C7B7A7, spi_burst_send +.4byte 0x0, 0x00000006, spi_data_wait # tx 0010, rx 1011 +.4byte tx_mark, 0x00000000, write32_test +.4byte rx_mark, 0x00000000, write32_test +.4byte rx_data, 0x000000B5, read32_test # tx 0010, rx 1100 +.4byte rx_data, 0x000000C5, read32_test # tx 0010, rx 1101 +.4byte rx_data, 0x000000D5, read32_test # tx 0010, rx 1110 +.4byte rx_data, 0x000000A7, read32_test # tx 0010, rx 1111 +.4byte rx_data, 0x000000B7, read32_test # tx 0010, rx 0000 +.4byte rx_data, 0x000000C7, read32_test # tx 0010, rx 0001 +.4byte ip, 0x00000002, read32_test +.4byte rx_data, 0x000000D7, read32_test # tx 0010, rx 1010 +.4byte ip, 0x00000000, read32_test +.4byte tx_mark, 0x00000000, write32_test +.4byte rx_mark, 0x00000000, write32_test # reset watermark registers + +# =========== Basic read-write =========== + +.4byte tx_data, 0x000000011, write32_test # place 8'h11 into tx_data +.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.4byte rx_data, 0x00000011, read32_test # read rx_data + +# =========== Different cs_mode, sck_mode, cs_def, sck_div =========== + +# Test sck_div + +.4byte sck_div, 0x00000101, write32_test # set sck_div to 0x101 +.4byte tx_data, 0x000000FF, write32_test # place 8'h11 into tx_data +.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.4byte rx_data, 0x000000FF, read32_test # read rx_data + +# Test phase + +.4byte sck_div, 0x00000003, write32_test # reset sck_div to 0x03 so only sck_mode is different +.4byte sck_mode, 0x00000001, write32_test # change phase to falling edge +.4byte tx_data, 0x000000A0, write32_test # place 8'h11 into tx_data +.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.4byte rx_data, 0x000000A0, read32_test # read rx_data + +# Test polarity + +.4byte sck_mode, 0x00000000, write32_test # reset sck phase to rising edge +.4byte sck_mode, 0x00000002, write32_test # set sck polarity active low +.4byte tx_data, 0x0000000B, write32_test # place 8'h11 into tx_data +.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.4byte rx_data, 0x0000000B, read32_test # read rx_data + +# Test chip select polarity + +.4byte sck_mode, 0x00000000, write32_test # reset sck polarity to active high +.4byte cs_def, 0x0000000E, write32_test # set cs[0] to inactive low +.4byte tx_data, 0x00000079, write32_test # place 8'h11 into tx_data +.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.4byte rx_data, 0x00000079, read32_test # read rx_data + +# Test chip id + +.4byte cs_def, 0x0000000F, write32_test # reset all cs to active low +.4byte cs_id, 0x00000001, write32_test # select cs[1] +.4byte tx_data, 0x00000000, write32_test # place 8'h11 into tx_data +.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.4byte rx_data, 0x00000000, read32_test # read rx_data + +# Test cs hold mode + +.4byte cs_id, 0x00000000, write32_test # select cs[0] +.4byte cs_mode, 0x00000002, write32_test # set cs_mode to HOLD +.4byte tx_data, 0x000000C0, write32_test # place 8'h11 into tx_data +.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.4byte rx_data, 0x000000C0, read32_test # read rx_data + +# Test cs OFF mode + +.4byte cs_mode, 0x00000003, write32_test # set cs_mode to OFF +.4byte tx_data, 0x00000011, write32_test # place 8'h11 into tx_data +.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.4byte rx_data, 0x00000011, read32_test # read rx_data + +# =========== Test delay0 register =========== + +# Test cs-sck delay of 0 with sck phase = 0 (implicit half cycle delay) + +.4byte cs_mode, 0x00000000, write32_test # reset cs_mode to auto, all cs and sck mode settings should be defualt +.4byte delay0, 0x00010000, write32_test # set cs-sck delay to 0 +.4byte tx_data, 0x00000020, write32_test # place 8'h11 into tx_data +.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.4byte rx_data, 0x00000020, read32_test # read rx_data + +# Test cs-sck delay of 0 with sck phase 1 (no delay) + +.4byte sck_mode, 0x00000001, write32_test # set sck_mode[0] to 1 (sck phase = 1) +.4byte tx_data, 0x00000032, write32_test # place 8'h11 into tx_data +.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.4byte rx_data, 0x00000032, read32_test # read rx_data + +# Test arbitrary cs-sck delay (sck phase 1) + +.4byte delay0, 0x00010005, write32_test # set cs-sck delay to 5 cycles +.4byte tx_data, 0x00000048, write32_test # place 8'h11 into tx_data +.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.4byte rx_data, 0x00000048, read32_test # read rx_data + +# Test arbitrary cs-sck delay (sck phase 0) + +.4byte sck_mode, 0x00000000, write32_test # set sck phase to 0 +.4byte delay0, 0x00010005, write32_test # set cs-sck delay to AF cycles +.4byte tx_data, 0x000000AF, write32_test # place 8'h11 into tx_data +.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.4byte rx_data, 0x000000AF, read32_test # read rx_data + + +# Test sck-cs delay of 0 with sck phase = 0 (no delay) + +.4byte delay0, 0x00000001, write32_test # set cs-sck delay to 0 +.4byte tx_data, 0x00000050, write32_test # place 8'h11 into tx_data +.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.4byte rx_data, 0x00000050, read32_test # read rx_data + +# Test sck-cs delay of 0 with sck phase 1 (implicit half cycle delay) + +.4byte sck_mode, 0x00000001, write32_test # set sck_mode[0] to 1 (sck phase = 1) +.4byte tx_data, 0x0000006B, write32_test # place 8'h11 into tx_data +.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.4byte rx_data, 0x0000006B, read32_test # read rx_data + +# Test arbitrary sck-cs delay (sck phase 1) + +.4byte delay0, 0x00050001, write32_test # set cs-sck delay to A5 cycles +.4byte tx_data, 0x00000011, write32_test # place 8'h11 into tx_data +.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.4byte rx_data, 0x00000011, read32_test # read rx_data + +# Test arbitrary sck-cs delay (sck phase 0) + +.4byte sck_mode, 0x00000000, write32_test # set sck phase to 0 +.4byte delay0, 0x00050001, write32_test # set cs-sck delay to 5 cycles +.4byte tx_data, 0x00000015, write32_test # place 8'h11 into tx_data +.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.4byte rx_data, 0x00000015, read32_test # read rx_data + +# =========== Test delay1 register =========== + +# Test inter cs delay + + +.4byte delay0, 0x00010001, write32_test # reset delay0 register +.4byte delay1, 0x00000005, write32_test # set inter_cs delay to 5 +.4byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock +.4byte tx_data, 0x44332211, spi_burst_send +.4byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end +.4byte rx_data, 0x00000011, read32_test +.4byte rx_data, 0x00000022, read32_test +.4byte rx_data, 0x00000033, read32_test +.4byte rx_data, 0x00000044, read32_test + +#test long inter_cs delay + +.4byte delay1, 0x000000A5, write32_test +.4byte rx_mark, 0x0000000, write32_test # preset rx watermark b/c of hardware interlock +.4byte tx_data, 0x0000007B, write32_test +.4byte 0x0, 0x00000000, spi_data_wait +.4byte rx_data, 0x0000007B, read32_test + + +# Test inter_cs delay set to 0 + +.4byte delay1, 0x00000000, write32_test # set inter_cs delay to 5 +.4byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock +.4byte tx_data, 0x54433221, spi_burst_send +.4byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end +.4byte rx_data, 0x00000021, read32_test +.4byte rx_data, 0x00000032, read32_test +.4byte rx_data, 0x00000043, read32_test +.4byte rx_data, 0x00000054, read32_test + + +# Test inter_xfr delay of 0 (maybe change behavior to half-period instead of period) + +.4byte delay1, 0x00000001, write32_test # reset inter_cs delay to 1 +.4byte cs_mode, 0x00000002, write32_test # set cs_mode to HOLD +.4byte tx_data, 0x99887766, spi_burst_send +.4byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end +.4byte rx_data, 0x00000066, read32_test +.4byte rx_data, 0x00000077, read32_test +.4byte rx_data, 0x00000088, read32_test +.4byte rx_data, 0x00000099, read32_test + +# Test inter_xfr delay 0 with phase = 1 +.4byte sck_mode, 0x00000001, write32_test +.4byte tx_data, 0x99887766, spi_burst_send +.4byte 0x0, 0x00000003, spi_data_wait +.4byte rx_data, 0x00000066, read32_test +.4byte rx_data, 0x00000077, read32_test +.4byte rx_data, 0x00000088, read32_test +.4byte rx_data, 0x00000099, read32_test + + +# Test arbitrary inter_xfr delay + +.4byte delay1, 0x00050001, write32_test # set inter_xfr delay to 5 +.4byte sck_mode, 0x00000001, write32_test +.4byte tx_data, 0x98877665, spi_burst_send +.4byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end +.4byte rx_data, 0x00000065, read32_test +.4byte rx_data, 0x00000076, read32_test +.4byte rx_data, 0x00000087, read32_test +.4byte rx_data, 0x00000098, read32_test + +# test long inter_xfr delay +.4byte delay1, 0x00A50001, write32_test +.4byte rx_mark, 0x0000000, write32_test # preset rx watermark b/c of hardware interlock +.4byte tx_data, 0x00000048, write32_test +.4byte 0x0, 0x00000000, spi_data_wait +.4byte rx_data, 0x00000048, read32_test + +# Test cs-sck delay with cs_mode = HOLD + +.4byte delay1, 0x00000001, write32_test # set inter_xfr delay to 0 +.4byte delay0, 0x00010005, write32_test # set cs-sck delay to 5 (should have no effect because cs is never inactive) +.4byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock +.4byte tx_data, 0xAABBCCDD, spi_burst_send +.4byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end +.4byte rx_data, 0x000000DD, read32_test # read rx_data +.4byte rx_data, 0x000000CC, read32_test +.4byte rx_data, 0x000000BB, read32_test +.4byte rx_data, 0x000000AA, read32_test + +# Test sck-cs delay cs_mode = HOLD + +.4byte delay0, 0x00000501, write32_test # set sck-cs delay to 5 (should have no effect because cs is never inactive) +.4byte tx_data, 0xABBCCDDE, spi_burst_send # place 8'h11 into tx_data +.4byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end +.4byte rx_data, 0x000000DE, read32_test # read rx_data +.4byte rx_data, 0x000000CD, read32_test +.4byte rx_data, 0x000000BC, read32_test +.4byte rx_data, 0x000000AB, read32_test + +# Test hold mode deassert conditions + +.4byte delay1, 0x00000001, write32_test # reset delay1 register +.4byte delay0, 0x00010001, write32_test # reset delay0 register +.4byte cs_mode, 0x00000002, write32_test # set cs_mode to hold +.4byte tx_data, 0x000000CE, write32_test # place data into tx_data +.4byte cs_id, 0x00000001, write32_test #change selected cs pin. should deassert cs[0] in hold mode +.4byte cs_def, 0x0000000D, write32_test # change selected cs pins def value. should deassert cs[1] +.4byte cs_mode, 0x00000000, write32_test # change cs_mode to auto, should deassert cs[1], have now gone through all deassertion conditions +.4byte cs_def, 0x0000000F, write32_test # reset cs_def +.4byte cs_id, 0x00000000, write32_test # reset cs_id +.4byte rx_data, 0x000000CE, read32_test # clear rx_fifo + +# =========== Test frame format (fmt) register =========== + +# Test frame length of 4 + +.4byte delay1, 0x00000001, write32_test # reset delay1 register +.4byte delay0, 0x00010001, write32_test # reset delay0 register +.4byte sck_mode, 0x00000000, write32_test #reset sckmode register +.4byte cs_mode, 0x00000000, write32_test # set cs_mode to AUTO +.4byte fmt, 0x00040000, write32_test # set frame length to 4 +.4byte rx_mark, 0x0000000, write32_test # preset rx watermark b/c of hardware interlock +.4byte tx_data, 0x000000F0, write32_test # place 8'h11 into tx_data +.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.4byte rx_data, 0x000000F0, read32_test # read rx_data + +# Test frame length of 0 + +#.4byte fmt, 0x00000000, write32_test # set frame length to 4 +#.4byte tx_data, 0x00000077, write32_test # place 8'h11 into tx_data +#.4byte 0x0, 0x0101, spi_data_wait # wait for transmission to end +#.4byte rx_data, 0x00000077, read32_test # read rx_data + +# test frame length 1 burst +.4byte fmt, 0x00010000, write32_test +.4byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock +.4byte tx_data, 0x80008000, spi_burst_send +.4byte 0x0, 0x00000003, spi_data_wait +.4byte rx_data, 0x00000000, read32_test +.4byte rx_data, 0x00000080, read32_test +.4byte rx_data, 0x00000000, read32_test +.4byte rx_data, 0x00000080, read32_test + + +# Test big endian with frame length = 5 + +.4byte fmt, 0x00050000, write32_test # set frame length to 5, big endian +.4byte rx_mark, 0x0000000, write32_test # preset rx watermark b/c of hardware interlock +.4byte tx_data, 0x000000A8, write32_test # place 8'h11 into tx_data +.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.4byte rx_data, 0x000000A8, read32_test # read rx_data + +# Test big endian burst with frame length = 5 + +.4byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock +.4byte tx_data, 0x03774FFF, spi_burst_send +.4byte 0x0, 0x00000003, spi_data_wait +.4byte rx_data, 0x000000F8, read32_test +.4byte rx_data, 0x00000048, read32_test +.4byte rx_data, 0x00000070, read32_test +.4byte rx_data, 0x00000000, read32_test + + + + +# Test little endian with frame length = 5 + +.4byte fmt, 0x00050004, write32_test # set frame length to 5, little-endian +.4byte rx_mark, 0x0000000, write32_test # preset rx watermark b/c of hardware interlock +.4byte tx_data, 0x000000A8, write32_test # place 8'h11 into tx_data +.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.4byte rx_data, 0x00000008, read32_test # read rx_data -> 08 + +#test little endian burst with frame length = 5 + +.4byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock +.4byte tx_data, 0xFF4F7703, spi_burst_send +.4byte 0x0, 0x00000003, spi_data_wait +.4byte rx_data, 0x00000003, read32_test #03 +.4byte rx_data, 0x00000017, read32_test #17 +.4byte rx_data, 0x0000000F, read32_test #0F +.4byte rx_data, 0x0000001F, read32_test #1F + +# Test dual SPI protocol, frame length = 8, big endian + +#.4byte fmt, 0x00080001, write32_test # set frame length to 8, big-endian, dual SPI +#.4byte tx_data, 0x000000C8, write32_test # place 8'h11 into tx_data +#.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +#.4byte rx_data, 0x00000000, read32_test # read rx_data + +# Test dual SPI protocol, frame length = 4 + +#.4byte fmt, 0x00040001, write32_test # set frame length to 8, big-endian, dual SPI +#.4byte tx_data, 0x000000A2, write32_test # place 8'h11 into tx_data +#.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +#.4byte rx_data, 0x000000A0, read32_test # read rx_data + +# Test dual SPI protocol, frame length = 5 + +#.4byte fmt, 0x00050001, write32_test # set frame length to 8, big-endian, dual SPI +#.4byte tx_data, 0x00000075, write32_test # place 8'h11 into tx_data +#.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +#.4byte rx_data, 0x00000074, read32_test # read rx_data + +# Test dual SPI protocol burst, frame length = 5 +#.4byte tx_data, 0x30733FFF, spi_burst_send +#.4byte 0x0, 0x00000003, spi_data_wait +#.4byte rx_data, 0x000000FC, read32_test +#.4byte rx_data, 0x0000003C, read32_test +#.4byte rx_data, 0x00000070, read32_test +#.4byte rx_data, 0x00000030, read32_test + +# Test quad SPI protocol, frame length = 5 + +#.4byte fmt, 0x00050002, write32_test # set frame length to 8, big-endian, dual SPI +#.4byte tx_data, 0x0000003F, write32_test # place 8'h11 into tx_data +#.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +#.4byte rx_data, 0x0000003F, read32_test # read rx_data + +# Test quad SPI protocol, frame length = 4 + +#.4byte fmt, 0x00040002, write32_test # set frame length to 8, big-endian, dual SPI +#.4byte tx_data, 0x0000000F, write32_test # place 8'h11 into tx_data +#.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +#.4byte rx_data, 0x00000000, read32_test # read rx_data + +# Test quad SPI protocol, frame length = 8 + +#.4byte fmt, 0x00080002, write32_test # set frame length to 8, big-endian, dual SPI +#.4byte tx_data, 0x000000F0, write32_test # place 8'h11 into tx_data +#.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +#.4byte rx_data, 0x000000F0, read32_test # read rx_data + +#=========== Test Hardware Interlock ================ + +# interlock in base case + +.4byte fmt, 0x00080000, write32_test # reset fmt register +.4byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock +.4byte tx_data, 0x00000062, write32_test # initiate transmission +.4byte sck_mode, 0x00000002, write32_test # flip polarity during transmission +.4byte tx_data, 0x00000026, write32_test # transmit second frame w/ control register updated +.4byte 0x0, 0x00000001, spi_data_wait +.4byte rx_data, 0x00000062, read32_test +.4byte rx_data, 0x00000026, read32_test # clear rx fifo +.4byte sck_mode, 0x00000000, write32_test # reset polarity + +# interlock in case where cs_mode is auto, but there is minimal intercs delay + +.4byte delay0, 0x00000001, write32_test # set sck-cs delay to 0, with sck.pha 0 there is 0 delay +.4byte tx_data, 0x000000D2, write32_test # initiate transmission +.4byte sck_mode, 0x00000002, write32_test # flip sck polarity +.4byte tx_data, 0x0000002D, write32_test # transmit second frame +.4byte 0x0, 0x00000001, spi_data_wait +.4byte rx_data, 0x000000D2, read32_test +.4byte rx_data, 0x0000002D, read32_test # clear rx fifo +.4byte sck_mode, 0x00000000, write32_test # reset polarity + +# interlock in case where cs_mode = hold, 0 intercs delay +.4byte delay0, 0x00010001, write32_test # reset delay0 +.4byte sck_mode, 0x00000000, write32_test # reset polarity +.4byte cs_mode, 0x00000002, write32_test # set cs_mode to hold +.4byte tx_data, 0x15263748, spi_burst_send # place 4 frames into tx fifo +.4byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame) +.4byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end +.4byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock +.4byte sck_mode, 0x00000000, write32_test # flip polarity again +.4byte 0x0, 0x00000003, spi_data_wait # wait for final frame +.4byte rx_data, 0x00000048, read32_test +.4byte rx_data, 0x00000037, read32_test +.4byte rx_data, 0x00000026, read32_test +.4byte rx_data, 0x00000015, read32_test #clear rx fifo + +# interlock in case where cs_mode = hold, intercs delay + +.4byte sck_mode, 0x00000000, write32_test # reset polarity +.4byte delay1, 0x00010001, write32_test # set intercs delay to 1 +.4byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock +.4byte tx_data, 0x51627384, spi_burst_send # place 4 frames into tx fifo +.4byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame) +.4byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end +.4byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock +.4byte sck_mode, 0x00000000, write32_test # flip polarity again +.4byte 0x0, 0x00000003, spi_data_wait # wait for final frame +.4byte rx_data, 0x00000084, read32_test +.4byte rx_data, 0x00000073, read32_test +.4byte rx_data, 0x00000062, read32_test +.4byte rx_data, 0x00000051, read32_test #clear rx fifo + +# repeat previous set of tests with cs_mode = off + +.4byte cs_mode, 0x00000003, write32_test # set cs_mode to hold +.4byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock +.4byte tx_data, 0x13243546, spi_burst_send # place 4 frames into tx fifo +.4byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame) +.4byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end +.4byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock +.4byte sck_mode, 0x00000000, write32_test # flip polarity again +.4byte 0x0, 0x00000003, spi_data_wait # wait for final frame +.4byte rx_data, 0x00000046, read32_test +.4byte rx_data, 0x00000035, read32_test +.4byte rx_data, 0x00000024, read32_test +.4byte rx_data, 0x00000013, read32_test #clear rx fifo + +# interlock in case where cs_mode = hold, intercs delay + +.4byte sck_mode, 0x00000000, write32_test # reset polarity +.4byte delay1, 0x00000000, write32_test # set intercs delay to 0 +.4byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock +.4byte tx_data, 0x31425364, spi_burst_send # place 4 frames into tx fifo +.4byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame) +.4byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end +.4byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock +.4byte sck_mode, 0x00000000, write32_test # flip polarity again +.4byte 0x0, 0x00000003, spi_data_wait # wait for final frame +.4byte rx_data, 0x00000064, read32_test +.4byte rx_data, 0x00000053, read32_test +.4byte rx_data, 0x00000042, read32_test +.4byte rx_data, 0x00000031, read32_test #clear rx fifo + + + + + + + + + + +# =========== Test watermark interrupts =========== + +# Test transmit watermark interrupt (triggers when entries in tx FIFO < tx watermark) without external enables + +SETUP_PLIC + +.4byte delay1, 0x0000001, write32_test # reset delay1 register +.4byte cs_mode, 0x00000000, write32_test # reset cs_mode +.4byte tx_mark, 0x00000001, write32_test # set transmit watermark to 1 (any entry turns mark off) +#.4byte ie, 0x00000000, write32_test # enable transmit interrupt +.4byte ip, 0x00000001, read32_test # tx watermark interupt should be pending +.4byte 0x0, 0x00000000, readmip_test +.4byte tx_data, 0x55443322, spi_burst_send # place 4 entries in transmit fifo +.4byte ip, 0x00000000, read32_test # tx watermark interupt should be off 125 +.4byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end + +# test recieve watermark interrupt (triggers when entries in rx FIFO > rx watermark) + +.4byte tx_mark, 0x00000000, write32_test # set tx_mark to 0 +.4byte rx_data, 0x00000022, read32_test # clear one entry from rx FIFO +.4byte rx_mark, 0x00000003, write32_test # set recieve watermark to 3 +#.4byte ie, 0x0000002, write32_test # enable receive interrupts +.4byte ip, 0x00000000, read32_test # rx interrupts should be low (rx FIFO has 3 entries) +.4byte rx_mark, 0x00000002, write32_test # set recieve watermark to 2 +.4byte ip, 0x00000002, read32_test # recieve interrupt should be high +.4byte 0x0, 0x00000000, readmip_test +.4byte rx_data, 0x00000033, read32_test # clear one more entry from recieve FIFO (2 entries) +.4byte ip, 0x00000000, read32_test # receive interrupt should be low +.4byte rx_data, 0x00000044, read32_test +.4byte rx_data, 0x00000055, read32_test # clear rx fifo + + +.4byte tx_mark, 0x00000001, write32_test # set transmit watermark to 0 +.4byte ie, 0x00000001, write32_test # enable transmit interrupt +.4byte ip, 0x00000001, read32_test # tx watermark interupt should be pending +.4byte 0x0, 0x00000800, readmip_test +.4byte ie, 0x00000000, write32_test # disable tx intr +.4byte tx_data, 0x55443322, spi_burst_send # place 4 entries in transmit fifo +.4byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end + +# test recieve watermark interrupt (triggers when entries in rx FIFO > rx watermark) + +.4byte tx_mark, 0x00000000, write32_test +.4byte 0x0, 0x00000000, claim_m_plic_interrupts +.4byte rx_data, 0x00000022, read32_test # clear one entry from rx FIFO +.4byte rx_mark, 0x00000003, write32_test # set recieve watermark to 3 +.4byte ie, 0x0000002, write32_test # enable receive interrupts +.4byte ip, 0x00000000, read32_test # rx interrupts should be low (rx FIFO has 3 entries) +.4byte 0x0, 0x00000000, readmip_test +.4byte rx_mark, 0x00000002, write32_test # set recieve watermark to 2 +.4byte ip, 0x00000002, read32_test # recieve interrupt should be high +.4byte 0x0, 0x00000800, readmip_test +.4byte rx_data, 0x00000033, read32_test # clear one more entry from recieve FIFO (2 entries) +.4byte 0x0, 0x00000000, claim_m_plic_interrupts +.4byte ip, 0x00000000, read32_test # receive interrupt should be low +.4byte 0x0, 0x00000000, readmip_test + + + +.4byte 0x0, 0x0, terminate_test \ No newline at end of file diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/Makefrag b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/Makefrag index 36f3e8075..a640e0c06 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/Makefrag +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/Makefrag @@ -54,6 +54,9 @@ target_tests_nosim = \ WALLY-trap-s-01 \ WALLY-trap-u-01 \ WALLY-status-fp-enabled-01 \ + WALLY-spi-01 \ + WALLY-gpio-01 \ + WALLY-uart-01 \ WALLY-wfi-01 \ WALLY-cbom-01 \ WALLY-cboz-01 \ diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-spi-01.reference_output b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-spi-01.reference_output new file mode 100644 index 000000000..83376aab1 --- /dev/null +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-spi-01.reference_output @@ -0,0 +1,288 @@ +00000003 # reset tests sck_div +00000000 +00000000 # sck_mode +00000000 +00000000 # cs_id +00000000 +0000000F # cs_def +00000000 +00000000 # cs_mode +00000000 +00010001 # delay 0 +00000000 +00000001 # delay 1 +00000000 +00080000 # fmt +00000000 +00000000 # tx_data +00000000 +00000000 # tx_mark +00000000 +00000000 # rx_mark +00000000 +00000000 # ie reset +00000000 +00000000 # ip reset +00000000 +00000000 # fifo watermark and edge case tests +00000000 +00000001 +00000000 +00000003 +00000000 +00000003 +00000000 +00000074 +00000000 +00000063 +00000000 +00000052 +00000000 +00000041 +00000000 +000000A1 +00000000 +00000003 +00000000 +000000B2 +00000000 +00000001 +00000000 +000000C3 +00000000 +000000D4 +00000000 +00000003 +00000000 +000000A4 +00000000 +00000001 +00000000 +000000B4 +00000000 +000000A5 +00000000 +000000B5 +00000000 +000000C5 +00000000 +000000D5 +00000000 +000000A7 +00000000 +000000B7 +00000000 +000000C7 +00000000 +00000002 +00000000 +000000D7 +00000000 +00000000 +00000000 +00000011 #basic read write +00000000 +000000FF +00000000 +000000A0 +00000000 +0000000B +00000000 +00000079 +00000000 +00000000 +00000000 +000000C0 +00000000 +00000011 +00000000 +00000020 #delay registers +00000000 +00000032 +00000000 +00000048 +00000000 +000000AF +00000000 +00000050 +00000000 +0000006B +00000000 +00000011 +00000000 +00000015 +00000000 +00000011 #delay1 +00000000 +00000022 +00000000 +00000033 +00000000 +00000044 +00000000 +0000007B +00000000 +00000021 +00000000 +00000032 +00000000 +00000043 +00000000 +00000054 +00000000 +00000066 +00000000 +00000077 +00000000 +00000088 +00000000 +00000099 +00000000 +00000066 +00000000 +00000077 +00000000 +00000088 +00000000 +00000099 +00000000 +00000065 +00000000 +00000076 +00000000 +00000087 +00000000 +00000098 +00000000 +00000048 +00000000 +000000DD +00000000 +000000CC +00000000 +000000BB +00000000 +000000AA +00000000 +000000DE +00000000 +000000CD +00000000 +000000BC +00000000 +000000AB +00000000 +000000CE hold mode deassert +00000000 +000000F0 #fmt register +00000000 +00000000 +00000000 +00000080 +00000000 +00000000 +00000000 +00000080 +00000000 +000000A8 +00000000 +000000F8 +00000000 +00000048 +00000000 +00000070 +00000000 +00000000 +00000000 +00000008 +00000000 +00000003 +00000000 +00000017 +00000000 +0000000F +00000000 +0000001F +00000000 +00000062 # hardware interlock +00000000 +00000026 +00000000 +000000D2 +00000000 +0000002D +00000000 +00000048 +00000000 +00000037 +00000000 +00000026 +00000000 +00000015 +00000000 +00000084 +00000000 +00000073 +00000000 +00000062 +00000000 +00000051 +00000000 +00000046 +00000000 +00000035 +00000000 +00000024 +00000000 +00000013 +00000000 +00000064 +00000000 +00000053 +00000000 +00000042 +00000000 +00000031 +00000000 +00000001 #watermark interrupts +00000000 +00000000 #read mip +00000000 +00000000 #read tx ip +00000000 +00000022 #clear 1 frame from rx fifo +00000000 +00000000 # read recieve ip +00000000 +00000002 #read recieve ip +00000000 +00000000 #read mip +00000000 +00000033 #clear frame +00000000 +00000000 # read receive ip +00000000 +00000044 #clear frame +00000000 +00000055 #clear frame +00000000 +00000001 #read tx ip +00000000 +00000800 #read mip +00000000 +00000022 #clear frame +00000000 +00000000 #read rx ip +00000000 +00000000 #read mip 94 +00000000 +00000002 #read rx ip +00000000 +00000800 #read mip +00000000 +00000033 #clear frame +00000000 +00000000 #read rx wm +00000000 +00000000 #read mip 99 +00000000 \ No newline at end of file diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-TEST-LIB-64.h b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-TEST-LIB-64.h index 07a31d7d5..67d76c6ab 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-TEST-LIB-64.h +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-TEST-LIB-64.h @@ -886,6 +886,7 @@ trap_handler_end_\MODE\(): // place to jump to so we can skip the trap handler a .equ PLIC_INTPRI_GPIO, 0x0C00000C # GPIO is interrupt 3 .equ PLIC_INTPRI_UART, 0x0C000028 # UART is interrupt 10 + .equ PLIC_INTPRI_SPI, 0x0C000018 # SPI in interrupt 6 .equ PLIC_INTPENDING0, 0x0C001000 # intPending0 register .equ PLIC_INTEN00, 0x0C002000 # interrupt enables for context 0 (machine mode) sources 31:1 .equ PLIC_INTEN10, 0x0C002080 # interrupt enables for context 1 (supervisor mode) sources 31:1 @@ -898,6 +899,7 @@ trap_handler_end_\MODE\(): // place to jump to so we can skip the trap handler a .8byte PLIC_THRESH1, 7, write32_test # Set PLIC supervisor mode interrupt threshold to 7 to accept no interrupts .8byte PLIC_INTPRI_GPIO, 7, write32_test # Set GPIO to high priority .8byte PLIC_INTPRI_UART, 7, write32_test # Set UART to high priority + .8byte PLIC_INTPRI_SPI, 7, write32_test # Set SPI to high priority .8byte PLIC_INTEN00, 0xFFFFFFFF, write32_test # Enable all interrupt sources for machine mode .8byte PLIC_INTEN10, 0x00000000, write32_test # Disable all interrupt sources for supervisor mode .endm @@ -1067,6 +1069,12 @@ claim_m_plic_interrupts: // clears one non-pending PLIC interrupt sw t3, 0(t2) sw t4, -4(sp) addi sp, sp, -4 + li t2, 0x0C000018 // SPI priority + li t3, 7 + lw t4, 0(t2) + sw t3, 0(t2) + sw t4, -4(sp) + addi sp, sp, -4 li t2, 0x0C002000 li t3, 0x0C200004 li t4, 0xFFF @@ -1077,11 +1085,14 @@ claim_m_plic_interrupts: // clears one non-pending PLIC interrupt sw t6, 0(t2) // restore saved enable status li t2, 0x0C00000C // GPIO priority li t3, 0x0C000028 // UART priority - lw t4, 4(sp) // load stored GPIO and UART priority - lw t5, 0(sp) - addi sp, sp, 8 // restore stack pointer - sw t4, 0(t2) - sw t5, 0(t3) + li t6, 0x0C000018 // SPI priority + lw a4, 8(sp) // load stored GPIO prioroty + lw t4, 4(sp) // load stored UART priority + lw t5, 0(sp) // load stored SPI priority + addi sp, sp, 12 // restore stack pointer + sw a4, 0(t2) + sw t4, 0(t3) + sw t5, 0(t6) j test_loop claim_s_plic_interrupts: // clears one non-pending PLIC interrupt @@ -1167,6 +1178,34 @@ uart_clearmodemintr: lb t2, 0(t2) j test_loop +spi_data_wait: + li t2, 0x10040054 + sw t4, 0(t2) // set rx watermark level + li t2, 0x10040074 + lw t3, 0(t2) //read ip (interrupt pending register) + slli t3, t3, 56 + srli t3, t3, 56 + li t2, 0x00000002 + bge t3, t2, spi_data_ready //branch to done if transmission complete + j spi_data_wait //else check again + +spi_data_ready: + li t2, 0x10040070 + li t3, 0x00000000 + sw t3, 0(t2) //disable rx watermark interrupt + j test_loop + +spi_burst_send: //function for loading multiple frames at once to test delays without returning to test loop + mv t2, t4 + sw t2, 0(t3) + srli t2, t2, 8 + sw t2, 0(t3) + srli t2, t2, 8 + sw t2, 0(t3) + srli t2, t2, 8 + sw t2, 0(t3) + j test_loop + goto_s_mode: // return to address in t3, li a0, 3 // Trap handler behavior (go to supervisor mode) diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S new file mode 100644 index 000000000..266b0e74f --- /dev/null +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S @@ -0,0 +1,662 @@ +/////////////////////////////////////////// +// +// WALLY-spi +// +// Author: David_Harris@hmc.edu and Naiche Whyte-Aguayo +// +// Created 2023-02-01 +// +// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, +// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +// OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +/////////////////////////////////////////// + +#include "WALLY-TEST-LIB-64.h" + +RVTEST_ISA("RV64I_Zicsr_Zifencei") +RVTEST_CASE(0,"//check ISA:=regex(.*64.*);check ISA:=regex(.*I.*); def Drvtest_mtrap_routine=True;def TEST_CASE_1=True;def NO_SAIL=True;",spi) + +INIT_TESTS + +TRAP_HANDLER m + +j run_test_loop // begin test loop/table tests instead of executing inline code. + +INIT_TEST_TABLE + +END_TESTS + +TEST_STACK_AND_DATA + +.align 3 +test_cases: +# --------------------------------------------------------------------------------------------- +# Test Contents +# +# Here is where the actual tests are held, or rather, what the actual tests do. +# each entry consists of 3 values that will be read in as follows: +# +# '.8byte [x28 Value], [x29 Value], [x30 value]' +# or +# '.8byte [address], [value], [test type]' +# +# The encoding for x30 test type values can be found in the test handler in the framework file +# --------------------------------------------------------------------------------------------- + +.equ SPI, 0x10040000 +.equ sck_div, (SPI+0x00) +.equ sck_mode, (SPI+0x04) +.equ cs_id, (SPI+0x10) +.equ cs_def, (SPI+0x14) +.equ cs_mode, (SPI+0x18) +.equ delay0, (SPI+0x28) +.equ delay1, (SPI+0x2C) +.equ fmt, (SPI+0x40) +.equ tx_data, (SPI+0x48) +.equ rx_data, (SPI+0x4C) +.equ tx_mark, (SPI+0x50) +.equ rx_mark, (SPI+0x54) +.equ ie, (SPI+0x70) +.equ ip, (SPI+0x74) + +# =========== Verify all registers reset to correct values =========== + +.8byte sck_div, 0x00000003, read32_test # sck_div reset to 0x3 +.8byte sck_mode, 0x00000000, read32_test # sck_mode reset to 0x0 +.8byte cs_id, 0x00000000, read32_test # cs_id reset to 0x0 +.8byte cs_def, 0x0000000F, read32_test # cs_def reset to 0x1 +.8byte cs_mode, 0x00000000, read32_test # cs_mode reset to 0x0 +.8byte delay0, 0x00010001, read32_test # delay0 reset to [31:24] 0x0, [23:16] 0x1, [15:8] 0x0, [7:0] 0x1 +.8byte delay1, 0x00000001, read32_test # delay1 reset to 0x1 +.8byte fmt, 0x00080000, read32_test # fmt reset to [31:20] 0x0, [19:16] 0x8, [15:0] 0x0 for non-flash enabled SPI controllers +.8byte tx_data, 0x00000000, read32_test # tx_data [30:0] reset to 0x0, [31] read only +.8byte tx_mark, 0x00000000, read32_test # tx_mark reset to 0x0 for non-flash enabled controllers +.8byte rx_mark, 0x00000000, read32_test # rx_mark reset to 0x0 +.8byte ie, 0x00000000, read32_test # ie reset to 0x0 +.8byte ip, 0x00000000, read32_test # ip reset to 0x0 + +# =========== watermark interrupts =============== + +#test watermark interrupts at beginning where fifo read/write pointers are known b/c reset +# txwmp raised when # of entries in txfifo < txmark, rxwm raised when # of entries in rxfifo > rxmark + +.8byte ip, 0x00000000, read32_test # txfifo entries not < 0, rxfifo entries not > 0; +.8byte tx_mark, 0x00000004, write32_test # set tx_mark to 4 +.8byte rx_mark, 0x00000003, write32_test # set rx_mark to 3 +.8byte ip, 0x00000001, read32_test # tx entries < 4, rx entries ! > 3 +.8byte tx_data, 0x41526374, spi_burst_send +.8byte 0x0, 0x00000003, spi_data_wait +.8byte ip, 0x00000003, read32_test # tx entries < 4, rx entries > 3, visual inspection should see tx TransmitFIFOReadIncrement + +# txfifo wptr now at 0011, rxfifo wptr at 0000 + +.8byte rx_mark, 0x00000007, write32_test # set rx_mark to 7 +.8byte tx_data, 0xD4C3B2A1, spi_burst_send +.8byte 0x0, 0x00000007, spi_data_wait # rxfifo full, txfifo wptr at 1000, rxfifo wptr at 0000 +.8byte ip, 0x00000003, read32_test +.8byte rx_data, 0x00000074, read32_test +.8byte rx_data, 0x00000063, read32_test # clear 2 entries, txfifo wptr at 1000, rxfifo wptr at 0010 + + +.8byte tx_data, 0x000000A4, write32_test +.8byte tx_data, 0x000000B4, write32_test # tx 1010, rx 0010 +.8byte 0x0, 0x00000007, spi_data_wait # 8 tx 1010, rx 0010 +.8byte rx_mark, 0x00000004, write32_test +.8byte rx_data, 0x00000052, read32_test # 7 rx 0011 +.8byte rx_data, 0x00000041, read32_test # 6 rx 0100 +.8byte rx_data, 0x000000A1, read32_test # 5 rx 0101 +.8byte ip, 0x00000003, read32_test # 5 things in rx fifo +.8byte rx_data, 0x000000B2, read32_test # 4 tx 1010, rx 0110 +.8byte ip, 0x00000001, read32_test # 4 entries in rxfifo, not strictly greater than 4 + +.8byte rx_mark, 0x00000007, write32_test +.8byte tx_data, 0xD5C5B5A5, spi_burst_send # 8 tx1110, rx 0110 +.8byte 0x0, 0x00000007, spi_data_wait + +.8byte rx_mark, 0x00000005, write32_test +.8byte rx_data, 0x000000C3, read32_test # tx 1110, rx 0111 +.8byte rx_data, 0x000000D4, read32_test # tx 1110, rx 1000 +.8byte ip, 0x00000003, read32_test # 6 entries +.8byte rx_data, 0x000000A4, read32_test # tx 1110, rx 1001 +.8byte ip, 0x00000001, read32_test # 5 entries +.8byte rx_data, 0x000000B4, read32_test # tx 1110, rx 1010 +.8byte rx_data, 0x000000A5, read32_test # tx 1110, rx 1011 + +.8byte rx_mark, 0x00000006, write32_test +.8byte tx_data, 0xD7C7B7A7, spi_burst_send +.8byte 0x0, 0x00000006, spi_data_wait # tx 0010, rx 1011 +.8byte tx_mark, 0x00000000, write32_test +.8byte rx_mark, 0x00000000, write32_test +.8byte rx_data, 0x000000B5, read32_test # tx 0010, rx 1100 +.8byte rx_data, 0x000000C5, read32_test # tx 0010, rx 1101 +.8byte rx_data, 0x000000D5, read32_test # tx 0010, rx 1110 +.8byte rx_data, 0x000000A7, read32_test # tx 0010, rx 1111 +.8byte rx_data, 0x000000B7, read32_test # tx 0010, rx 0000 +.8byte rx_data, 0x000000C7, read32_test # tx 0010, rx 0001 +.8byte ip, 0x00000002, read32_test +.8byte rx_data, 0x000000D7, read32_test # tx 0010, rx 1010 +.8byte ip, 0x00000000, read32_test +.8byte tx_mark, 0x00000000, write32_test +.8byte rx_mark, 0x00000000, write32_test # reset watermark registers + +# =========== Basic read-write =========== + +.8byte tx_data, 0x000000011, write32_test # place 8'h11 into tx_data +.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.8byte rx_data, 0x00000011, read32_test # read rx_data + +# =========== Different cs_mode, sck_mode, cs_def, sck_div =========== + +# Test sck_div + +.8byte sck_div, 0x00000101, write32_test # set sck_div to 0x101 +.8byte tx_data, 0x000000FF, write32_test # place 8'h11 into tx_data +.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.8byte rx_data, 0x000000FF, read32_test # read rx_data + +# Test phase + +.8byte sck_div, 0x00000003, write32_test # reset sck_div to 0x03 so only sck_mode is different +.8byte sck_mode, 0x00000001, write32_test # change phase to falling edge +.8byte tx_data, 0x000000A0, write32_test # place 8'h11 into tx_data +.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.8byte rx_data, 0x000000A0, read32_test # read rx_data + +# Test polarity + +.8byte sck_mode, 0x00000000, write32_test # reset sck phase to rising edge +.8byte sck_mode, 0x00000002, write32_test # set sck polarity active low +.8byte tx_data, 0x0000000B, write32_test # place 8'h11 into tx_data +.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.8byte rx_data, 0x0000000B, read32_test # read rx_data + +# Test chip select polarity + +.8byte sck_mode, 0x00000000, write32_test # reset sck polarity to active high +.8byte cs_def, 0x0000000E, write32_test # set cs[0] to inactive low +.8byte tx_data, 0x00000079, write32_test # place 8'h11 into tx_data +.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.8byte rx_data, 0x00000079, read32_test # read rx_data + +# Test chip id + +.8byte cs_def, 0x0000000F, write32_test # reset all cs to active low +.8byte cs_id, 0x00000001, write32_test # select cs[1] +.8byte tx_data, 0x00000000, write32_test # place 8'h11 into tx_data +.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.8byte rx_data, 0x00000000, read32_test # read rx_data + +# Test cs hold mode + +.8byte cs_id, 0x00000000, write32_test # select cs[0] +.8byte cs_mode, 0x00000002, write32_test # set cs_mode to HOLD +.8byte tx_data, 0x000000C0, write32_test # place 8'h11 into tx_data +.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.8byte rx_data, 0x000000C0, read32_test # read rx_data + +# Test cs OFF mode + +.8byte cs_mode, 0x00000003, write32_test # set cs_mode to OFF +.8byte tx_data, 0x00000011, write32_test # place 8'h11 into tx_data +.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.8byte rx_data, 0x00000011, read32_test # read rx_data + +# =========== Test delay0 register =========== + +# Test cs-sck delay of 0 with sck phase = 0 (implicit half cycle delay) + +.8byte cs_mode, 0x00000000, write32_test # reset cs_mode to auto, all cs and sck mode settings should be defualt +.8byte delay0, 0x00010000, write32_test # set cs-sck delay to 0 +.8byte tx_data, 0x00000020, write32_test # place 8'h11 into tx_data +.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.8byte rx_data, 0x00000020, read32_test # read rx_data + +# Test cs-sck delay of 0 with sck phase 1 (no delay) + +.8byte sck_mode, 0x00000001, write32_test # set sck_mode[0] to 1 (sck phase = 1) +.8byte tx_data, 0x00000032, write32_test # place 8'h11 into tx_data +.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.8byte rx_data, 0x00000032, read32_test # read rx_data + +# Test arbitrary cs-sck delay (sck phase 1) + +.8byte delay0, 0x00010005, write32_test # set cs-sck delay to 5 cycles +.8byte tx_data, 0x00000048, write32_test # place 8'h11 into tx_data +.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.8byte rx_data, 0x00000048, read32_test # read rx_data + +# Test arbitrary cs-sck delay (sck phase 0) + +.8byte sck_mode, 0x00000000, write32_test # set sck phase to 0 +.8byte delay0, 0x00010005, write32_test # set cs-sck delay to AF cycles +.8byte tx_data, 0x000000AF, write32_test # place 8'h11 into tx_data +.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.8byte rx_data, 0x000000AF, read32_test # read rx_data + + +# Test sck-cs delay of 0 with sck phase = 0 (no delay) + +.8byte delay0, 0x00000001, write32_test # set cs-sck delay to 0 +.8byte tx_data, 0x00000050, write32_test # place 8'h11 into tx_data +.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.8byte rx_data, 0x00000050, read32_test # read rx_data + +# Test sck-cs delay of 0 with sck phase 1 (implicit half cycle delay) + +.8byte sck_mode, 0x00000001, write32_test # set sck_mode[0] to 1 (sck phase = 1) +.8byte tx_data, 0x0000006B, write32_test # place 8'h11 into tx_data +.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.8byte rx_data, 0x0000006B, read32_test # read rx_data + +# Test arbitrary sck-cs delay (sck phase 1) + +.8byte delay0, 0x00050001, write32_test # set cs-sck delay to A5 cycles +.8byte tx_data, 0x00000011, write32_test # place 8'h11 into tx_data +.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.8byte rx_data, 0x00000011, read32_test # read rx_data + +# Test arbitrary sck-cs delay (sck phase 0) + +.8byte sck_mode, 0x00000000, write32_test # set sck phase to 0 +.8byte delay0, 0x00050001, write32_test # set cs-sck delay to 5 cycles +.8byte tx_data, 0x00000015, write32_test # place 8'h11 into tx_data +.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.8byte rx_data, 0x00000015, read32_test # read rx_data + +# =========== Test delay1 register =========== + +# Test inter cs delay + + +.8byte delay0, 0x00010001, write32_test # reset delay0 register +.8byte delay1, 0x00000005, write32_test # set inter_cs delay to 5 +.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock +.8byte tx_data, 0x44332211, spi_burst_send +.8byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end +.8byte rx_data, 0x00000011, read32_test +.8byte rx_data, 0x00000022, read32_test +.8byte rx_data, 0x00000033, read32_test +.8byte rx_data, 0x00000044, read32_test + +#test long inter_cs delay + +.8byte delay1, 0x000000A5, write32_test +.8byte rx_mark, 0x0000000, write32_test # preset rx watermark b/c of hardware interlock +.8byte tx_data, 0x0000007B, write32_test +.8byte 0x0, 0x00000000, spi_data_wait +.8byte rx_data, 0x0000007B, read32_test + + +# Test inter_cs delay set to 0 + +.8byte delay1, 0x00000000, write32_test # set inter_cs delay to 5 +.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock +.8byte tx_data, 0x54433221, spi_burst_send +.8byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end +.8byte rx_data, 0x00000021, read32_test +.8byte rx_data, 0x00000032, read32_test +.8byte rx_data, 0x00000043, read32_test +.8byte rx_data, 0x00000054, read32_test + + +# Test inter_xfr delay of 0 (maybe change behavior to half-period instead of period) + +.8byte delay1, 0x00000001, write32_test # reset inter_cs delay to 1 +.8byte cs_mode, 0x00000002, write32_test # set cs_mode to HOLD +.8byte tx_data, 0x99887766, spi_burst_send +.8byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end +.8byte rx_data, 0x00000066, read32_test +.8byte rx_data, 0x00000077, read32_test +.8byte rx_data, 0x00000088, read32_test +.8byte rx_data, 0x00000099, read32_test + +# Test inter_xfr delay 0 with phase = 1 +.8byte sck_mode, 0x00000001, write32_test +.8byte tx_data, 0x99887766, spi_burst_send +.8byte 0x0, 0x00000003, spi_data_wait +.8byte rx_data, 0x00000066, read32_test +.8byte rx_data, 0x00000077, read32_test +.8byte rx_data, 0x00000088, read32_test +.8byte rx_data, 0x00000099, read32_test + + +# Test arbitrary inter_xfr delay + +.8byte delay1, 0x00050001, write32_test # set inter_xfr delay to 5 +.8byte sck_mode, 0x00000001, write32_test +.8byte tx_data, 0x98877665, spi_burst_send +.8byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end +.8byte rx_data, 0x00000065, read32_test +.8byte rx_data, 0x00000076, read32_test +.8byte rx_data, 0x00000087, read32_test +.8byte rx_data, 0x00000098, read32_test + +# test long inter_xfr delay +.8byte delay1, 0x00A50001, write32_test +.8byte rx_mark, 0x0000000, write32_test # preset rx watermark b/c of hardware interlock +.8byte tx_data, 0x00000048, write32_test +.8byte 0x0, 0x00000000, spi_data_wait +.8byte rx_data, 0x00000048, read32_test + +# Test cs-sck delay with cs_mode = HOLD + +.8byte delay1, 0x00000001, write32_test # set inter_xfr delay to 0 +.8byte delay0, 0x00010005, write32_test # set cs-sck delay to 5 (should have no effect because cs is never inactive) +.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock +.8byte tx_data, 0xAABBCCDD, spi_burst_send +.8byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end +.8byte rx_data, 0x000000DD, read32_test # read rx_data +.8byte rx_data, 0x000000CC, read32_test +.8byte rx_data, 0x000000BB, read32_test +.8byte rx_data, 0x000000AA, read32_test + +# Test sck-cs delay cs_mode = HOLD + +.8byte delay0, 0x00000501, write32_test # set sck-cs delay to 5 (should have no effect because cs is never inactive) +.8byte tx_data, 0xABBCCDDE, spi_burst_send # place 8'h11 into tx_data +.8byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end +.8byte rx_data, 0x000000DE, read32_test # read rx_data +.8byte rx_data, 0x000000CD, read32_test +.8byte rx_data, 0x000000BC, read32_test +.8byte rx_data, 0x000000AB, read32_test + +# Test hold mode deassert conditions + +.8byte delay1, 0x00000001, write32_test # reset delay1 register +.8byte delay0, 0x00010001, write32_test # reset delay0 register +.8byte cs_mode, 0x00000002, write32_test # set cs_mode to hold +.8byte tx_data, 0x000000CE, write32_test # place data into tx_data +.8byte cs_id, 0x00000001, write32_test #change selected cs pin. should deassert cs[0] in hold mode +.8byte cs_def, 0x0000000D, write32_test # change selected cs pins def value. should deassert cs[1] +.8byte cs_mode, 0x00000000, write32_test # change cs_mode to auto, should deassert cs[1], have now gone through all deassertion conditions +.8byte cs_def, 0x0000000F, write32_test # reset cs_def +.8byte cs_id, 0x00000000, write32_test # reset cs_id +.8byte rx_data, 0x000000CE, read32_test # clear rx_fifo + +# =========== Test frame format (fmt) register =========== + +# Test frame length of 4 + +.8byte delay1, 0x00000001, write32_test # reset delay1 register +.8byte delay0, 0x00010001, write32_test # reset delay0 register +.8byte sck_mode, 0x00000000, write32_test #reset sckmode register +.8byte cs_mode, 0x00000000, write32_test # set cs_mode to AUTO +.8byte fmt, 0x00040000, write32_test # set frame length to 4 +.8byte rx_mark, 0x0000000, write32_test # preset rx watermark b/c of hardware interlock +.8byte tx_data, 0x000000F0, write32_test # place 8'h11 into tx_data +.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.8byte rx_data, 0x000000F0, read32_test # read rx_data + +# Test frame length of 0 + +#.8byte fmt, 0x00000000, write32_test # set frame length to 4 +#.8byte tx_data, 0x00000077, write32_test # place 8'h11 into tx_data +#.8byte 0x0, 0x0101, spi_data_wait # wait for transmission to end +#.8byte rx_data, 0x00000077, read32_test # read rx_data + +# test frame length 1 burst +.8byte fmt, 0x00010000, write32_test +.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock +.8byte tx_data, 0x80008000, spi_burst_send +.8byte 0x0, 0x00000003, spi_data_wait +.8byte rx_data, 0x00000000, read32_test +.8byte rx_data, 0x00000080, read32_test +.8byte rx_data, 0x00000000, read32_test +.8byte rx_data, 0x00000080, read32_test + + +# Test big endian with frame length = 5 + +.8byte fmt, 0x00050000, write32_test # set frame length to 5, big endian +.8byte rx_mark, 0x0000000, write32_test # preset rx watermark b/c of hardware interlock +.8byte tx_data, 0x000000A8, write32_test # place 8'h11 into tx_data +.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.8byte rx_data, 0x000000A8, read32_test # read rx_data + +# Test big endian burst with frame length = 5 + +.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock +.8byte tx_data, 0x03774FFF, spi_burst_send +.8byte 0x0, 0x00000003, spi_data_wait +.8byte rx_data, 0x000000F8, read32_test +.8byte rx_data, 0x00000048, read32_test +.8byte rx_data, 0x00000070, read32_test +.8byte rx_data, 0x00000000, read32_test + + + + +# Test little endian with frame length = 5 + +.8byte fmt, 0x00050004, write32_test # set frame length to 5, little-endian +.8byte rx_mark, 0x0000000, write32_test # preset rx watermark b/c of hardware interlock +.8byte tx_data, 0x000000A8, write32_test # place 8'h11 into tx_data +.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +.8byte rx_data, 0x00000008, read32_test # read rx_data -> 08 + +#test little endian burst with frame length = 5 + +.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock +.8byte tx_data, 0xFF4F7703, spi_burst_send +.8byte 0x0, 0x00000003, spi_data_wait +.8byte rx_data, 0x00000003, read32_test #03 +.8byte rx_data, 0x00000017, read32_test #17 +.8byte rx_data, 0x0000000F, read32_test #0F +.8byte rx_data, 0x0000001F, read32_test #1F + +# Test dual SPI protocol, frame length = 8, big endian + +#.8byte fmt, 0x00080001, write32_test # set frame length to 8, big-endian, dual SPI +#.8byte tx_data, 0x000000C8, write32_test # place 8'h11 into tx_data +#.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +#.8byte rx_data, 0x00000000, read32_test # read rx_data + +# Test dual SPI protocol, frame length = 4 + +#.8byte fmt, 0x00040001, write32_test # set frame length to 8, big-endian, dual SPI +#.8byte tx_data, 0x000000A2, write32_test # place 8'h11 into tx_data +#.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +#.8byte rx_data, 0x000000A0, read32_test # read rx_data + +# Test dual SPI protocol, frame length = 5 + +#.8byte fmt, 0x00050001, write32_test # set frame length to 8, big-endian, dual SPI +#.8byte tx_data, 0x00000075, write32_test # place 8'h11 into tx_data +#.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +#.8byte rx_data, 0x00000074, read32_test # read rx_data + +# Test dual SPI protocol burst, frame length = 5 +#.8byte tx_data, 0x30733FFF, spi_burst_send +#.8byte 0x0, 0x00000003, spi_data_wait +#.8byte rx_data, 0x000000FC, read32_test +#.8byte rx_data, 0x0000003C, read32_test +#.8byte rx_data, 0x00000070, read32_test +#.8byte rx_data, 0x00000030, read32_test + +# Test quad SPI protocol, frame length = 5 + +#.8byte fmt, 0x00050002, write32_test # set frame length to 8, big-endian, dual SPI +#.8byte tx_data, 0x0000003F, write32_test # place 8'h11 into tx_data +#.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +#.8byte rx_data, 0x0000003F, read32_test # read rx_data + +# Test quad SPI protocol, frame length = 4 + +#.8byte fmt, 0x00040002, write32_test # set frame length to 8, big-endian, dual SPI +#.8byte tx_data, 0x0000000F, write32_test # place 8'h11 into tx_data +#.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +#.8byte rx_data, 0x00000000, read32_test # read rx_data + +# Test quad SPI protocol, frame length = 8 + +#.8byte fmt, 0x00080002, write32_test # set frame length to 8, big-endian, dual SPI +#.8byte tx_data, 0x000000F0, write32_test # place 8'h11 into tx_data +#.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end +#.8byte rx_data, 0x000000F0, read32_test # read rx_data + +#=========== Test Hardware Interlock ================ + +# interlock in base case + +.8byte fmt, 0x00080000, write32_test # reset fmt register +.8byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock +.8byte tx_data, 0x00000062, write32_test # initiate transmission +.8byte sck_mode, 0x00000002, write32_test # flip polarity during transmission +.8byte tx_data, 0x00000026, write32_test # transmit second frame w/ control register updated +.8byte 0x0, 0x00000001, spi_data_wait +.8byte rx_data, 0x00000062, read32_test +.8byte rx_data, 0x00000026, read32_test # clear rx fifo +.8byte sck_mode, 0x00000000, write32_test # reset polarity + +# interlock in case where cs_mode is auto, but there is minimal intercs delay + +.8byte delay0, 0x00000001, write32_test # set sck-cs delay to 0, with sck.pha 0 there is 0 delay +.8byte tx_data, 0x000000D2, write32_test # initiate transmission +.8byte sck_mode, 0x00000002, write32_test # flip sck polarity +.8byte tx_data, 0x0000002D, write32_test # transmit second frame +.8byte 0x0, 0x00000001, spi_data_wait +.8byte rx_data, 0x000000D2, read32_test +.8byte rx_data, 0x0000002D, read32_test # clear rx fifo +.8byte sck_mode, 0x00000000, write32_test # reset polarity + +# interlock in case where cs_mode = hold, 0 intercs delay +.8byte delay0, 0x00010001, write32_test # reset delay0 +.8byte sck_mode, 0x00000000, write32_test # reset polarity +.8byte cs_mode, 0x00000002, write32_test # set cs_mode to hold +.8byte tx_data, 0x15263748, spi_burst_send # place 4 frames into tx fifo +.8byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame) +.8byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end +.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock +.8byte sck_mode, 0x00000000, write32_test # flip polarity again +.8byte 0x0, 0x00000003, spi_data_wait # wait for final frame +.8byte rx_data, 0x00000048, read32_test +.8byte rx_data, 0x00000037, read32_test +.8byte rx_data, 0x00000026, read32_test +.8byte rx_data, 0x00000015, read32_test #clear rx fifo + +# interlock in case where cs_mode = hold, intercs delay + +.8byte sck_mode, 0x00000000, write32_test # reset polarity +.8byte delay1, 0x00010001, write32_test # set intercs delay to 1 +.8byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock +.8byte tx_data, 0x51627384, spi_burst_send # place 4 frames into tx fifo +.8byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame) +.8byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end +.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock +.8byte sck_mode, 0x00000000, write32_test # flip polarity again +.8byte 0x0, 0x00000003, spi_data_wait # wait for final frame +.8byte rx_data, 0x00000084, read32_test +.8byte rx_data, 0x00000073, read32_test +.8byte rx_data, 0x00000062, read32_test +.8byte rx_data, 0x00000051, read32_test #clear rx fifo + +# repeat previous set of tests with cs_mode = off + +.8byte cs_mode, 0x00000003, write32_test # set cs_mode to hold +.8byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock +.8byte tx_data, 0x13243546, spi_burst_send # place 4 frames into tx fifo +.8byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame) +.8byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end +.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock +.8byte sck_mode, 0x00000000, write32_test # flip polarity again +.8byte 0x0, 0x00000003, spi_data_wait # wait for final frame +.8byte rx_data, 0x00000046, read32_test +.8byte rx_data, 0x00000035, read32_test +.8byte rx_data, 0x00000024, read32_test +.8byte rx_data, 0x00000013, read32_test #clear rx fifo + +# interlock in case where cs_mode = hold, intercs delay + +.8byte sck_mode, 0x00000000, write32_test # reset polarity +.8byte delay1, 0x00000000, write32_test # set intercs delay to 0 +.8byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock +.8byte tx_data, 0x31425364, spi_burst_send # place 4 frames into tx fifo +.8byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame) +.8byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end +.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock +.8byte sck_mode, 0x00000000, write32_test # flip polarity again +.8byte 0x0, 0x00000003, spi_data_wait # wait for final frame +.8byte rx_data, 0x00000064, read32_test +.8byte rx_data, 0x00000053, read32_test +.8byte rx_data, 0x00000042, read32_test +.8byte rx_data, 0x00000031, read32_test #clear rx fifo + + + + + + + + + + +# =========== Test watermark interrupts =========== + +# Test transmit watermark interrupt (triggers when entries in tx FIFO < tx watermark) without external enables + +SETUP_PLIC + +.8byte delay1, 0x0000001, write32_test # reset delay1 register +.8byte cs_mode, 0x00000000, write32_test # reset cs_mode +.8byte tx_mark, 0x00000001, write32_test # set transmit watermark to 1 (any entry turns mark off) +#.8byte ie, 0x00000000, write32_test # enable transmit interrupt +.8byte ip, 0x00000001, read32_test # tx watermark interupt should be pending +.8byte 0x0, 0x00000000, readmip_test +.8byte tx_data, 0x55443322, spi_burst_send # place 4 entries in transmit fifo +.8byte ip, 0x00000000, read32_test # tx watermark interupt should be off 125 +.8byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end + +# test recieve watermark interrupt (triggers when entries in rx FIFO > rx watermark) + +.8byte tx_mark, 0x00000000, write32_test # set tx_mark to 0 +.8byte rx_data, 0x00000022, read32_test # clear one entry from rx FIFO +.8byte rx_mark, 0x00000003, write32_test # set recieve watermark to 3 +#.8byte ie, 0x0000002, write32_test # enable receive interrupts +.8byte ip, 0x00000000, read32_test # rx interrupts should be low (rx FIFO has 3 entries) +.8byte rx_mark, 0x00000002, write32_test # set recieve watermark to 2 +.8byte ip, 0x00000002, read32_test # recieve interrupt should be high +.8byte 0x0, 0x00000000, readmip_test +.8byte rx_data, 0x00000033, read32_test # clear one more entry from recieve FIFO (2 entries) +.8byte ip, 0x00000000, read32_test # receive interrupt should be low +.8byte rx_data, 0x00000044, read32_test +.8byte rx_data, 0x00000055, read32_test # clear rx fifo + + +.8byte tx_mark, 0x00000001, write32_test # set transmit watermark to 0 +.8byte ie, 0x00000001, write32_test # enable transmit interrupt +.8byte ip, 0x00000001, read32_test # tx watermark interupt should be pending +.8byte 0x0, 0x00000800, readmip_test +.8byte ie, 0x00000000, write32_test # disable tx intr +.8byte tx_data, 0x55443322, spi_burst_send # place 4 entries in transmit fifo +.8byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end + +# test recieve watermark interrupt (triggers when entries in rx FIFO > rx watermark) + +.8byte tx_mark, 0x00000000, write32_test +.8byte 0x0, 0x00000000, claim_m_plic_interrupts +.8byte rx_data, 0x00000022, read32_test # clear one entry from rx FIFO +.8byte rx_mark, 0x00000003, write32_test # set recieve watermark to 3 +.8byte ie, 0x0000002, write32_test # enable receive interrupts +.8byte ip, 0x00000000, read32_test # rx interrupts should be low (rx FIFO has 3 entries) +.8byte 0x0, 0x00000000, readmip_test +.8byte rx_mark, 0x00000002, write32_test # set recieve watermark to 2 +.8byte ip, 0x00000002, read32_test # recieve interrupt should be high +.8byte 0x0, 0x00000800, readmip_test +.8byte rx_data, 0x00000033, read32_test # clear one more entry from recieve FIFO (2 entries) +.8byte 0x0, 0x00000000, claim_m_plic_interrupts +.8byte ip, 0x00000000, read32_test # receive interrupt should be low +.8byte 0x0, 0x00000000, readmip_test + + + +.8byte 0x0, 0x0, terminate_test \ No newline at end of file