diff --git a/.gitmodules b/.gitmodules index e406bcfa5..22f34ffd0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "riscv-o3"] - path = riscv-o3 - url = git@github.com:stineje/riscv-o3.git [submodule "sky130/sky130_osu_sc_t12"] path = sky130/sky130_osu_sc_t12 url = https://foss-eda-tools.googlesource.com/skywater-pdk/libs/sky130_osu_sc_t12/ diff --git a/riscv-o3 b/riscv-o3 deleted file mode 160000 index afb27bd55..000000000 --- a/riscv-o3 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit afb27bd558a9b6fabb6b768ae81ef122b4db9eea diff --git a/wally-pipelined/config/rv32ic/wally-config.vh b/wally-pipelined/config/rv32ic/wally-config.vh index b264ebca5..a5d3ba302 100644 --- a/wally-pipelined/config/rv32ic/wally-config.vh +++ b/wally-pipelined/config/rv32ic/wally-config.vh @@ -27,7 +27,7 @@ // RV32 or RV64: XLEN = 32 or 64 `define XLEN 32 -`define MISA (32'h00000104) +`define MISA (32'h00000104 | 1 << 12) `define A_SUPPORTED ((`MISA >> 0) % 2 == 1) `define C_SUPPORTED ((`MISA >> 2) % 2 == 1) `define D_SUPPORTED ((`MISA >> 3) % 2 == 1) diff --git a/wally-pipelined/config/rv64ic/wally-config.vh b/wally-pipelined/config/rv64ic/wally-config.vh index eb340ddc2..a46bfbe80 100644 --- a/wally-pipelined/config/rv64ic/wally-config.vh +++ b/wally-pipelined/config/rv64ic/wally-config.vh @@ -28,7 +28,7 @@ `define XLEN 64 //`define MISA (32'h00000104) -`define MISA (32'h00000104 | 1<<5 | 1<<18 | 1 << 20) +`define MISA (32'h00000104 | 1<<5 | 1<<18 | 1 << 20 | 1 << 12) `define A_SUPPORTED ((`MISA >> 0) % 2 == 1) `define C_SUPPORTED ((`MISA >> 2) % 2 == 1) `define D_SUPPORTED ((`MISA >> 3) % 2 == 1) diff --git a/wally-pipelined/config/rv64icfd/wally-config.vh b/wally-pipelined/config/rv64icfd/wally-config.vh new file mode 100644 index 000000000..9e8dccc96 --- /dev/null +++ b/wally-pipelined/config/rv64icfd/wally-config.vh @@ -0,0 +1,89 @@ +////////////////////////////////////////// +// wally-config.vh +// +// Written: David_Harris@hmc.edu 4 January 2021 +// Modified: Brett Mathis +// +// Purpose: Specify which features are configured +// Macros to determine which modes are supported based on MISA +// +// A component of the Wally configurable RISC-V project. +// +// 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. +/////////////////////////////////////////// + +// RV32 or RV64: XLEN = 32 or 64 +`define XLEN 64 + +//`define MISA (32'h00000104) +`define MISA (32'h00000104 | 1<<5 | 1<<18 | 1 << 20) +`define A_SUPPORTED ((`MISA >> 0) % 2 == 1) +`define C_SUPPORTED ((`MISA >> 2) % 2 == 1) +`define D_SUPPORTED ((`MISA >> 3) % 2 == 1) +`define F_SUPPORTED ((`MISA >> 5) % 2 == 1) +`define M_SUPPORTED ((`MISA >> 12) % 2 == 1) +`define S_SUPPORTED ((`MISA >> 18) % 2 == 1) +`define U_SUPPORTED ((`MISA >> 20) % 2 == 1) +`define ZCSR_SUPPORTED 1 +`define ZCOUNTERS_SUPPORTED 1 +// N-mode user-level interrupts are depricated per Andrew Waterman 1/13/21 +//`define N_SUPPORTED ((MISA >> 13) % 2 == 1) +`define N_SUPPORTED 0 + +`define M_MODE (2'b11) +`define S_MODE (2'b01) +`define U_MODE (2'b00) + +// Microarchitectural Features +`define UARCH_PIPELINED 1 +`define UARCH_SUPERSCALR 0 +`define UARCH_SINGLECYCLE 0 +`define MEM_DCACHE 0 +`define MEM_DTIM 1 +`define MEM_ICACHE 0 +`define MEM_VIRTMEM 0 + +// Address space +`define RESET_VECTOR 64'h0000000080000000 + +// Bus Interface width +`define AHBW 64 + +// Peripheral Addresses +// Peripheral memory space extends from BASE to BASE+RANGE +// Range should be a thermometer code with 0's in the upper bits and 1s in the lower bits + +`define TIMBASE 32'h80000000 +`define TIMRANGE 32'h0007FFFF +`define CLINTBASE 32'h02000000 +`define CLINTRANGE 32'h0000FFFF +`define GPIOBASE 32'h10012000 +`define GPIORANGE 32'h000000FF +`define UARTBASE 32'h10000000 +`define UARTRANGE 32'h00000007 + +// Test modes + +// Tie GPIO outputs back to inputs +`define GPIO_LOOPBACK_TEST 0 + + +// Hardware configuration +`define UART_PRESCALE 1 + +/* verilator lint_off STMTDLY */ +/* verilator lint_off WIDTH */ +/* verilator lint_off ASSIGNDLY */ +/* verilator lint_off PINCONNECTEMPTY */ diff --git a/wally-pipelined/lint-wally b/wally-pipelined/lint-wally index 198e8969b..f90a1010e 100755 --- a/wally-pipelined/lint-wally +++ b/wally-pipelined/lint-wally @@ -1,7 +1,8 @@ # check for warnings in Verilog code # The verilator lint tool is faster and better than Modelsim so it is best to run this first. -verilator --lint-only --top-module wallypipelinedsoc -Iconfig/rv64ic src/*/*.sv +verilator --lint-only --top-module wallypipelinedsoc -Iconfig/rv64ic src/*/*.sv +#verilator --lint-only --top-module wallypipelinedsoc -Iconfig/rv64ic src/*/*.sv src/*/div/*.sv # --lint-only just runs lint rather than trying to compile and simulate # -I points to the include directory where files such as `include wally-config.vh are found diff --git a/wally-pipelined/regression/wally-busybear.do b/wally-pipelined/regression/wally-busybear.do index 5a210b598..2eb67e6ba 100644 --- a/wally-pipelined/regression/wally-busybear.do +++ b/wally-pipelined/regression/wally-busybear.do @@ -17,10 +17,10 @@ onbreak {resume} # create library -if [file exists work] { - vdel -all +if [file exists work-busybear] { + vdel -all -lib work-busybear } -vlib work +vlib work-busybear # compile source files # suppress spurious warnngs about diff --git a/wally-pipelined/regression/wally-coremark.do b/wally-pipelined/regression/wally-coremark.do new file mode 100644 index 000000000..e564990f9 --- /dev/null +++ b/wally-pipelined/regression/wally-coremark.do @@ -0,0 +1,101 @@ +# wally-coremark.do +# +# Modification by Oklahoma State University & Harvey Mudd College +# Use with Testbench +# James Stine, 2008; David Harris 2021 +# Go Cowboys!!!!!! +# +# Takes 1:10 to run RV64IC tests using gui + +# Use this wally-pipelined.do file to run this example. +# Either bring up ModelSim and type the following at the "ModelSim>" prompt: +# do wally-pipelined.do +# or, to run from a shell, type the following at the shell prompt: +# vsim -do wally-pipelined.do -c +# (omit the "-c" to see the GUI while running from the shell) + +onbreak {resume} + +# create library +if [file exists work] { + vdel -all +} +vlib work + +# compile source files +# suppress spurious warnngs about +# "Extra checking for conflicts with always_comb done at vopt time" +# because vsim will run vopt + +# default to config/rv64ic, but allow this to be overridden at the command line. For example: +# do wally-pipelined.do ../config/rv32ic +switch $argc { + 0 {vlog +incdir+../config/rv64ic ../testbench/testbench-coremark.sv ../src/*/*.sv -suppress 2583} + 1 {vlog +incdir+$1 ../testbench/testbench-coremark.sv ../src/*/*.sv -suppress 2583} +} +# start and run simulation +# remove +acc flag for faster sim during regressions if there is no need to access internal signals +vopt +acc work.testbench -o workopt +vsim workopt + +view wave + +-- display input and output signals as hexidecimal values +# Diplays All Signals recursively +add wave /testbench/clk +add wave /testbench/reset +add wave -divider +add wave /testbench/dut/hart/ebu/IReadF +add wave /testbench/dut/hart/DataStall +add wave /testbench/dut/hart/InstrStall +add wave /testbench/dut/hart/StallF +add wave /testbench/dut/hart/StallD +add wave /testbench/dut/hart/FlushD +add wave /testbench/dut/hart/FlushE +add wave /testbench/dut/hart/FlushM +add wave /testbench/dut/hart/FlushW + +add wave -divider +add wave -hex /testbench/dut/hart/ifu/PCF +add wave -hex /testbench/dut/hart/ifu/InstrF +#add wave -hex /testbench/dut/hart/ifu/PCD +add wave -hex /testbench/dut/hart/ifu/InstrD +add wave -divider +#add wave -hex /testbench/dut/hart/ifu/PCE +#add wave -hex /testbench/dut/hart/ifu/InstrE +add wave -hex /testbench/dut/hart/ieu/dp/SrcAE +add wave -hex /testbench/dut/hart/ieu/dp/SrcBE +add wave -hex /testbench/dut/hart/ieu/dp/ALUResultE +add wave /testbench/dut/hart/ieu/dp/PCSrcE +add wave -divider +#add wave -hex /testbench/dut/hart/ifu/PCM +#add wave -hex /testbench/dut/hart/ifu/InstrM +add wave /testbench/dut/uncore/dtim/memwrite +add wave -hex /testbench/dut/uncore/HADDR +add wave -hex /testbench/dut/uncore/HWDATA +add wave -divider +add wave -hex /testbench/dut/hart/ifu/PCW +add wave /testbench/dut/hart/ieu/dp/RegWriteW +add wave -hex /testbench/dut/hart/ieu/dp/ResultW +add wave -hex /testbench/dut/hart/ieu/dp/RdW +add wave -divider +#add ww +add wave -hex -r /testbench/* + +-- Set Wave Output Items +TreeUpdate [SetDefaultTree] +WaveRestoreZoom {0 ps} {100 ps} +configure wave -namecolwidth 250 +configure wave -valuecolwidth 120 +configure wave -justifyvalue left +configure wave -signalnamewidth 0 +configure wave -snapdistance 10 +configure wave -datasetprefix 0 +configure wave -rowmargin 4 +configure wave -childrowmargin 2 +set DefaultRadix hexadecimal + +-- Run the Simulation +#run 1000 +run -all +#quit diff --git a/wally-pipelined/regression/wally-peripherals.do b/wally-pipelined/regression/wally-peripherals.do new file mode 100644 index 000000000..d9d9daa37 --- /dev/null +++ b/wally-pipelined/regression/wally-peripherals.do @@ -0,0 +1,108 @@ +# wally-peripherals.do +# +# Created by Ben Bracker (bbracker@hmc.edu) on 11 Feb. 2021 +# +# Based on wally-pipelined.do by +# James Stine, 2008; David Harris 2021 +# Go Cowboys!!!!!! + +# Use this wally-pipelined.do file to run this example. +# Either bring up ModelSim and type the following at the "ModelSim>" prompt: +# do wally-pipelined.do +# or, to run from a shell, type the following at the shell prompt: +# vsim -do wally-pipelined.do -c +# (omit the "-c" to see the GUI while running from the shell) + +onbreak {resume} + +# create library +if [file exists work] { + vdel -all +} +vlib work + +# compile source files +# suppress spurious warnngs about +# "Extra checking for conflicts with always_comb done at vopt time" +# because vsim will run vopt + +# default to config/rv64ic, but allow this to be overridden at the command line. For example: +# do wally-pipelined.do ../config/rv32ic +# That said, I don't think there are any peripherals that use anything but rv64i just yet. +switch $argc { + 0 {vlog +incdir+../config/rv64ic ../testbench/testbench-peripherals.sv ../src/*/*.sv -suppress 2583} + 1 {vlog +incdir+$1 ../testbench/testbench-peripherals.sv ../src/*/*.sv -suppress 2583} +} +# start and run simulation +# remove +acc flag for faster sim during regressions if there is no need to access internal signals +vopt +acc work.testbench -o workopt +vsim workopt + +view wave + +-- display input and output signals as hexidecimal values +# Diplays All Signals recursively +add wave /testbench/clk +add wave /testbench/reset +add wave -divider +add wave /testbench/dut/hart/ebu/IReadF +add wave /testbench/dut/hart/DataStall +add wave /testbench/dut/hart/InstrStall +add wave /testbench/dut/hart/StallF +add wave /testbench/dut/hart/StallD +add wave /testbench/dut/hart/FlushD +add wave /testbench/dut/hart/FlushE +add wave /testbench/dut/hart/FlushM +add wave /testbench/dut/hart/FlushW + +add wave -divider +add wave -hex /testbench/dut/hart/ifu/PCF +add wave -hex /testbench/dut/hart/ifu/InstrF +add wave /testbench/InstrFName +#add wave -hex /testbench/dut/hart/ifu/PCD +add wave -hex /testbench/dut/hart/ifu/InstrD +add wave /testbench/InstrDName +add wave -divider +#add wave -hex /testbench/dut/hart/ifu/PCE +#add wave -hex /testbench/dut/hart/ifu/InstrE +add wave /testbench/InstrEName +add wave -hex /testbench/dut/hart/ieu/dp/SrcAE +add wave -hex /testbench/dut/hart/ieu/dp/SrcBE +add wave -hex /testbench/dut/hart/ieu/dp/ALUResultE +add wave /testbench/dut/hart/ieu/dp/PCSrcE +add wave -divider +#add wave -hex /testbench/dut/hart/ifu/PCM +#add wave -hex /testbench/dut/hart/ifu/InstrM +add wave /testbench/InstrMName +add wave /testbench/dut/uncore/dtim/memwrite +add wave -hex /testbench/dut/uncore/HADDR +add wave -hex /testbench/dut/uncore/HWDATA +add wave -divider +add wave -hex /testbench/dut/hart/ifu/PCW +add wave /testbench/InstrWName +add wave /testbench/dut/hart/ieu/dp/RegWriteW +add wave -hex /testbench/dut/hart/ieu/dp/ResultW +add wave -hex /testbench/dut/hart/ieu/dp/RdW +add wave -divider +add wave -hex /testbench/dut/uncore/uart/u/* +add wave -divider +#add ww +add wave -hex -r /testbench/* + +-- Set Wave Output Items +TreeUpdate [SetDefaultTree] +WaveRestoreZoom {0 ps} {100 ps} +configure wave -namecolwidth 250 +configure wave -valuecolwidth 120 +configure wave -justifyvalue left +configure wave -signalnamewidth 0 +configure wave -snapdistance 10 +configure wave -datasetprefix 0 +configure wave -rowmargin 4 +configure wave -childrowmargin 2 +set DefaultRadix hexadecimal + +-- Run the Simulation +run 5000 +#run -all +#quit diff --git a/wally-pipelined/src/fpu/build_temp/fcsr.sv b/wally-pipelined/src/fpu/build_temp/fcsr.sv new file mode 100644 index 000000000..64f3f7b92 --- /dev/null +++ b/wally-pipelined/src/fpu/build_temp/fcsr.sv @@ -0,0 +1,29 @@ +`include "../../config/rv64icfd/wally-config.vh" + +module fcsr( + input logic [2:0] frm, + input logic reset, + input logic clear, + input logic clk, + input logic write, + input logic [4:0] flags, + output logic [31:0] readData); + + //register I/O assignment + logic [31:0] regInput; + logic [31:0] regOutput; + + //no L instruction support + //only last 8 bits used for FCSR + + //latching input to write signal + //AND clk and write and remove latch + //for clk-based write + assign regInput = (write) ? {24'h0,frm,flags} : regInput; + + floprc #(32) (.clk(clk), .reset(reset), .clear(clear), .d(regInput), .q(regOutput)); + + assign readData = regOutput; + + +endmodule diff --git a/wally-pipelined/src/fpu/build_temp/fctrl.sv b/wally-pipelined/src/fpu/build_temp/fctrl.sv new file mode 100644 index 000000000..13451165d --- /dev/null +++ b/wally-pipelined/src/fpu/build_temp/fctrl.sv @@ -0,0 +1,143 @@ +`include "../../config/rv64icfd/wally-config.vh" + +module fctrl ( + input logic [6:0] Funct7D, + input logic [6:0] OpD, + input logic [4:0] Rs2D, + input logic [4:0] Rs1D, + input logic [2:0] FrmW, + output logic WriteEnD, + output logic DivSqrtStartD, + output logic [2:0] regSelD, + output logic [2:0] writeSelD, + output logic [3:0] OpCtrlD, + output logic FmtD, + output logic WriteIntD); + + + + //precision is taken directly from instruction + assign FmtD = Funct7D[0]; + + //all subsequent logic is based on the table present + //in Section 5 of Wally Architecture Specification + + //write is enabled for all fp instruciton op codes + //sans fp load + logic isFP, isFPLD; + always_comb begin + //case statement is easier to modify + //in case of errors + case(OpD) + //fp instructions sans load + 7'b1010011 : begin isFP = 1'b1; isFPLD = 1'b0; end + 7'b1000011 : begin isFP = 1'b1; isFPLD = 1'b0; end + 7'b1000111 : begin isFP = 1'b1; isFPLD = 1'b0; end + 7'b1001011 : begin isFP = 1'b1; isFPLD = 1'b0; end + 7'b1001111 : begin isFP = 1'b1; isFPLD = 1'b0; end + 7'b0100111 : begin isFP = 1'b1; isFPLD = 1'b0; end + //fp load + 7'b1010011 : begin isFP = 1'b1; isFPLD = 1'b1; end + default : begin isFP = 1'b0; isFPLD = 1'b0; end + endcase + end + + assign WriteEnD = isFP & ~isFPLD; + + //useful intermediary signals + // + //(mult only not supported in current datapath) + //set third FMA operand to zero in this case + //(or equivalent) + logic isAddSub, isFMA, isMult, isDivSqrt, isCvt, isCmp, isFPSTR; + + always_comb begin + //checks all but FMA/store/load + if(OpD == 7'b1010011) begin + case(Funct7D) + //compare + 7'b10100?? : begin isAddSub = 1'b0; isFMA = 1'b0; isMult = 1'b0; isDivSqrt = 1'b0; isCvt = 1'b0; isCmp = 1'b1; isFPSTR = 1'b0; end + //div/sqrt + 7'b0?011?? : begin isAddSub = 1'b0; isFMA = 1'b0; isMult = 1'b0; isDivSqrt = 1'b1; isCvt = 1'b0; isCmp = 1'b0; isFPSTR = 1'b0; end + //add/sub + 7'b0000??? : begin isAddSub = 1'b1; isFMA = 1'b0; isMult = 1'b0; isDivSqrt = 1'b0; isCvt = 1'b0; isCmp = 1'b0; isFPSTR = 1'b0; end + //mult + 7'b00010?? : begin isAddSub = 1'b0; isFMA = 1'b0; isMult = 1'b1; isDivSqrt = 1'b0; isCvt = 1'b0; isCmp = 1'b0; isFPSTR = 1'b0; end + //convert (not precision) + 7'b110?0?? : begin isAddSub = 1'b0; isFMA = 1'b0; isMult = 1'b0; isDivSqrt = 1'b0; isCvt = 1'b1; isCmp = 1'b0; isFPSTR = 1'b0; end + //convert (precision) + 7'b010000? : begin isAddSub = 1'b0; isFMA = 1'b0; isMult = 1'b0; isDivSqrt = 1'b0; isCvt = 1'b1; isCmp = 1'b0; isFPSTR = 1'b0; end + endcase + end + //FMA/store/load + else begin + case(OpD) + //4 FMA instructions + 7'b1000011 : begin isAddSub = 1'b0; isFMA = 1'b1; isMult = 1'b0; isDivSqrt = 1'b0; isCvt = 1'b0; isCmp = 1'b0; isFPSTR = 1'b0; end + 7'b1000111 : begin isAddSub = 1'b0; isFMA = 1'b1; isMult = 1'b0; isDivSqrt = 1'b0; isCvt = 1'b0; isCmp = 1'b0; isFPSTR = 1'b0; end + 7'b1001011 : begin isAddSub = 1'b0; isFMA = 1'b1; isMult = 1'b0; isDivSqrt = 1'b0; isCvt = 1'b0; isCmp = 1'b0; isFPSTR = 1'b0; end + 7'b1001111 : begin isAddSub = 1'b0; isFMA = 1'b1; isMult = 1'b0; isDivSqrt = 1'b0; isCvt = 1'b0; isCmp = 1'b0; isFPSTR = 1'b0; end + //store (load already found) + 7'b0100111 : begin isAddSub = 1'b0; isFMA = 1'b0; isMult = 1'b0; isDivSqrt = 1'b0; isCvt = 1'b0; isCmp = 1'b0; isFPSTR = 1'b1; end + endcase + end + end + + //register is chosen based on operation performed + //---- + //write selection is chosen in the same way as + //register selection + // + + // reg/write sel logic and assignment + // + // 3'b000 = add/sub/cvt + // 3'b001 = sign + // 3'b010 = fma + // 3'b011 = cmp + // 3'b100 = div/sqrt + // + //reg select + + //this value is used enough to be shorthand + logic isSign; + assign isSign = ~Funct7D[6] & ~Funct7D[5] & Funct7D[4] & ~Funct7D[3] & ~Funct7D[2]; + + + assign regSelD[2] = isDivSqrt & ~isFMA; + assign regSelD[1] = isFMA | isCmp; + //AND of Funct7 for sign + assign regSelD[0] = isCmp | isSign; + + //write select + assign writeSelD[2] = isDivSqrt & ~isFMA; + assign writeSelD[1] = isFMA | isCmp; + //AND of Funct7 for sign + assign writeSelD[0] = isCmp | isSign; + + //if op is div/sqrt - start div/sqrt + assign DivSqrtStartD = isDivSqrt & ~isFMA; + + //operation control for each fp operation + //has to be expanded over standard to account for + //integrated fpadd/cvt + // + //will integrate FMA opcodes into design later + // + //conversion instructions will + //also need to be added later as I find the opcode + //version I used for this repo + + assign OpCtrlD[3] = 1'b0; + //if is positive sign injection OR is precision convert + assign OpCtrlD[2] = (isSign & ~FrmW[0]) | (~Funct7D[6] & Funct7D[5] & ~Funct7D[4] & ~Funct7D[3] & ~Funct7D[2] & ~Funct7D[1]); + //if is precision convert OR is sign xor + assign OpCtrlD[1] = (isSign & FrmW[1]) | (~Funct7D[6] & Funct7D[5] & ~Funct7D[4] & ~Funct7D[3] & ~Funct7D[2] & ~Funct7D[1]); + //if is sqrt OR is sub OR is single-precision cmp OR negation + assign OpCtrlD[0] = (isDivSqrt & ~isFMA & Funct7D[6]) | (isAddSub & ~isFMA & Funct7D[2]) | (isCmp & ~isFMA & Funct7D[0]) | (isSign & FrmW[0]); + + //write to integer source if conv to int occurs + //AND of Funct7 for int results + assign WriteIntD = isCvt & (Funct7D[6] & Funct7D[5] & ~Funct7D[4] & ~Funct7D[3] & ~Funct7D[2] & ~Funct7D[1]); + +endmodule diff --git a/wally-pipelined/src/fpu/build_temp/fputop.sv b/wally-pipelined/src/fpu/build_temp/fputop.sv new file mode 100644 index 000000000..3b29e4da5 --- /dev/null +++ b/wally-pipelined/src/fpu/build_temp/fputop.sv @@ -0,0 +1,65 @@ +`include "../../config/rv64icfd/wally-config.vh" + +module fputop ( + input logic [2:0] FrmW, + input logic reset, + input logic clear, + input logic clk, + input logic [31:0] InstrD, + input logic [`XLEN-1:0] SrcAE, + input logic [`XLEN-1:0] SrcAW, + output logic [31:0] FSROutW, + output logic DivSqrtDoneE, + output logic FInvalInstrD, + output logic [`XLEN-1:0] FPUResultW); + + /*fctrl (); + + //regfile instantiation and decode stage + + //write signal mux + + //address signal mux + + //parallel floating-point registers are + //used for modularity and future performance + //comparisons between operation sets + freg1adr (); + + freg2adr (); + + freg2adr (); + + freg2adr (); + + freg3adr (); + + //can easily be merged into privledged core + //if necessary + fcsr (); + + //E pipe and execution stage + + fpdivsqrt (); + + fma1 (); + + fpaddcvt1 (); + + fpcmp1 (); + + fpsign (); + + //M pipe and memory stage + + fma2 (); + + fpaddcvt2 (); + + fpcmp2 (); + + //W pipe and writeback stage + + //flag signal mux +*/ +endmodule diff --git a/wally-pipelined/src/fpu/build_temp/freg.sv b/wally-pipelined/src/fpu/build_temp/freg.sv new file mode 100644 index 000000000..6da116d5f --- /dev/null +++ b/wally-pipelined/src/fpu/build_temp/freg.sv @@ -0,0 +1,513 @@ +`include "../../config/rv64icfd/wally-config.vh" + +module freg1adr ( + input logic [2:0] frm, + input logic reset, + input logic clear, + input logic clk, + input logic [4:0] rd, + input logic write, + input logic [4:0] adr1, + input logic [`XLEN-1:0] writeData, + output logic [`XLEN-1:0] readData); + + //note - not word aligning based on precision of + //operation (frm) + + //reg number should remain static, but it doesn't hurt + //to parameterize + parameter numRegs = 32; + + //intermediary signals - useful for debugging + //and easy instatiation of generated modules + logic [`XLEN-1:0] [numRegs-1:0] regInput; + logic [`XLEN-1:0] [numRegs-1:0] regOutput; + + //generate fp registers themselves + genvar i; + generate + for (i = 0; i < numRegs; i = i + 1) begin:register + + floprc #(`XLEN) (.clk(clk), .reset(reset), .clear(clear), .d(regInput[i][`XLEN-1:0]), .q(regOutput[i][`XLEN-1:0])); + end + + endgenerate + + //this could be done with: + // + //assign readData = regOutput[adr1]; + // + //but always_comb allows for finer control + + + //address decoder + //only 1 for this fp register set + //used with fpsign + //defaults to outputting zeroes + always_comb begin + case(adr1) + 5'b00000 : readData = regOutput[0]; + 5'b00001 : readData = regOutput[1]; + 5'b00010 : readData = regOutput[2]; + 5'b00011 : readData = regOutput[3]; + 5'b00100 : readData = regOutput[4]; + 5'b00101 : readData = regOutput[5]; + 5'b00110 : readData = regOutput[6]; + 5'b00111 : readData = regOutput[7]; + 5'b01000 : readData = regOutput[8]; + 5'b01001 : readData = regOutput[9]; + 5'b01010 : readData = regOutput[10]; + 5'b01011 : readData = regOutput[11]; + 5'b01100 : readData = regOutput[12]; + 5'b01101 : readData = regOutput[13]; + 5'b01110 : readData = regOutput[14]; + 5'b01111 : readData = regOutput[15]; + 5'b10000 : readData = regOutput[16]; + 5'b10001 : readData = regOutput[17]; + 5'b10010 : readData = regOutput[18]; + 5'b10011 : readData = regOutput[19]; + 5'b10100 : readData = regOutput[20]; + 5'b10101 : readData = regOutput[21]; + 5'b10110 : readData = regOutput[22]; + 5'b10111 : readData = regOutput[23]; + 5'b11000 : readData = regOutput[24]; + 5'b11001 : readData = regOutput[25]; + 5'b11010 : readData = regOutput[26]; + 5'b11011 : readData = regOutput[27]; + 5'b11100 : readData = regOutput[28]; + 5'b11101 : readData = regOutput[29]; + 5'b11110 : readData = regOutput[30]; + 5'b11111 : readData = regOutput[31]; + default : readData = `XLEN'h0; + endcase + end + + //destination register decoder + //only change input values on write + //defaults to undefined with invalid address + // + //note - this is an intermediary signal, so + //this is not asynch assignment. FF in flopr + //will not update data until clk pulse + always_comb begin + if(write) begin + case(rd) + 5'b00000 : regInput[0] = writeData; + 5'b00001 : regInput[1] = writeData; + 5'b00010 : regInput[2] = writeData; + 5'b00011 : regInput[3] = writeData; + 5'b00100 : regInput[4] = writeData; + 5'b00101 : regInput[5] = writeData; + 5'b00110 : regInput[6] = writeData; + 5'b00111 : regInput[7] = writeData; + 5'b01000 : regInput[8] = writeData; + 5'b01000 : regInput[9] = writeData; + 5'b01001 : regInput[10] = writeData; + 5'b01010 : regInput[11] = writeData; + 5'b01111 : regInput[12] = writeData; + 5'b01101 : regInput[13] = writeData; + 5'b01110 : regInput[14] = writeData; + 5'b01111 : regInput[15] = writeData; + 5'b10000 : regInput[16] = writeData; + 5'b10001 : regInput[17] = writeData; + 5'b10010 : regInput[18] = writeData; + 5'b10011 : regInput[19] = writeData; + 5'b10100 : regInput[20] = writeData; + 5'b10101 : regInput[21] = writeData; + 5'b10110 : regInput[22] = writeData; + 5'b10111 : regInput[23] = writeData; + 5'b11000 : regInput[24] = writeData; + 5'b11000 : regInput[25] = writeData; + 5'b11001 : regInput[26] = writeData; + 5'b11010 : regInput[27] = writeData; + 5'b11111 : regInput[28] = writeData; + 5'b11101 : regInput[29] = writeData; + 5'b11110 : regInput[30] = writeData; + 5'b11111 : regInput[31] = writeData; + default : regInput[0] = `XLEN'hx; + endcase + end + end + +endmodule + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//******** +//formatting separation +//******** +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +module freg2adr ( + input logic [2:0] frm, + input logic reset, + input logic clear, + input logic clk, + input logic [4:0] rd, + input logic write, + input logic [4:0] adr1, + input logic [4:0] adr2, + input logic [`XLEN-1:0] writeData, + output logic [`XLEN-1:0] readData1, + output logic [`XLEN-1:0] readData2); + + //note - not word aligning based on precision of + //operation (frm) + + //reg number should remain static, but it doesn't hurt + //to parameterize + parameter numRegs = 32; + + //intermediary signals - useful for debugging + //and easy instatiation of generated modules + logic [`XLEN-1:0] [numRegs-1:0] regInput; + logic [`XLEN-1:0] [numRegs-1:0] regOutput; + + //generate fp registers themselves + genvar i; + generate + for (i = 0; i < numRegs; i = i + 1) begin:register + + floprc #(`XLEN) (.clk(clk), .reset(reset), .clear(clear), .d(regInput[i][`XLEN-1:0]), .q(regOutput[i][`XLEN-1:0])); + end + + endgenerate + + //address decoder + //2 are used for this fp register set + //used with fpadd/cvt, fpdiv/sqrt, and fpcmp + //defaults to outputting zeroes + always_comb begin + + //adderss 1 decoder + case(adr1) + 5'b00000 : readData1 = regOutput[0]; + 5'b00001 : readData1 = regOutput[1]; + 5'b00010 : readData1 = regOutput[2]; + 5'b00011 : readData1 = regOutput[3]; + 5'b00100 : readData1 = regOutput[4]; + 5'b00101 : readData1 = regOutput[5]; + 5'b00110 : readData1 = regOutput[6]; + 5'b00111 : readData1 = regOutput[7]; + 5'b01000 : readData1 = regOutput[8]; + 5'b01001 : readData1 = regOutput[9]; + 5'b01010 : readData1 = regOutput[10]; + 5'b01011 : readData1 = regOutput[11]; + 5'b01100 : readData1 = regOutput[12]; + 5'b01101 : readData1 = regOutput[13]; + 5'b01110 : readData1 = regOutput[14]; + 5'b01111 : readData1 = regOutput[15]; + 5'b10000 : readData1 = regOutput[16]; + 5'b10001 : readData1 = regOutput[17]; + 5'b10010 : readData1 = regOutput[18]; + 5'b10011 : readData1 = regOutput[19]; + 5'b10100 : readData1 = regOutput[20]; + 5'b10101 : readData1 = regOutput[21]; + 5'b10110 : readData1 = regOutput[22]; + 5'b10111 : readData1 = regOutput[23]; + 5'b11000 : readData1 = regOutput[24]; + 5'b11001 : readData1 = regOutput[25]; + 5'b11010 : readData1 = regOutput[26]; + 5'b11011 : readData1 = regOutput[27]; + 5'b11100 : readData1 = regOutput[28]; + 5'b11101 : readData1 = regOutput[29]; + 5'b11110 : readData1 = regOutput[30]; + 5'b11111 : readData1 = regOutput[31]; + default : readData1 = `XLEN'h0; + endcase + + //address 2 decoder + case(adr2) + 5'b00000 : readData2 = regOutput[0]; + 5'b00001 : readData2 = regOutput[1]; + 5'b00010 : readData2 = regOutput[2]; + 5'b00011 : readData2 = regOutput[3]; + 5'b00100 : readData2 = regOutput[4]; + 5'b00101 : readData2 = regOutput[5]; + 5'b00110 : readData2 = regOutput[6]; + 5'b00111 : readData2 = regOutput[7]; + 5'b01000 : readData2 = regOutput[8]; + 5'b01001 : readData2 = regOutput[9]; + 5'b01010 : readData2 = regOutput[10]; + 5'b01011 : readData2 = regOutput[11]; + 5'b01100 : readData2 = regOutput[12]; + 5'b01101 : readData2 = regOutput[13]; + 5'b01110 : readData2 = regOutput[14]; + 5'b01111 : readData2 = regOutput[15]; + 5'b10000 : readData2 = regOutput[16]; + 5'b10001 : readData2 = regOutput[17]; + 5'b10010 : readData2 = regOutput[18]; + 5'b10011 : readData2 = regOutput[19]; + 5'b10100 : readData2 = regOutput[20]; + 5'b10101 : readData2 = regOutput[21]; + 5'b10110 : readData2 = regOutput[22]; + 5'b10111 : readData2 = regOutput[23]; + 5'b11000 : readData2 = regOutput[24]; + 5'b11001 : readData2 = regOutput[25]; + 5'b11010 : readData2 = regOutput[26]; + 5'b11011 : readData2 = regOutput[27]; + 5'b11100 : readData2 = regOutput[28]; + 5'b11101 : readData2 = regOutput[29]; + 5'b11110 : readData2 = regOutput[30]; + 5'b11111 : readData2 = regOutput[31]; + default : readData2 = `XLEN'h0; + endcase + end + + //destination register decoder + //only change input values on write + //defaults to undefined with invalid address + // + //note - this is an intermediary signal, so + //this is not asynch assignment. FF in flopr + //will not update data until clk pulse + always_comb begin + if(write) begin + case(rd) + 5'b00000 : regInput[0] = writeData; + 5'b00001 : regInput[1] = writeData; + 5'b00010 : regInput[2] = writeData; + 5'b00011 : regInput[3] = writeData; + 5'b00100 : regInput[4] = writeData; + 5'b00101 : regInput[5] = writeData; + 5'b00110 : regInput[6] = writeData; + 5'b00111 : regInput[7] = writeData; + 5'b01000 : regInput[8] = writeData; + 5'b01000 : regInput[9] = writeData; + 5'b01001 : regInput[10] = writeData; + 5'b01010 : regInput[11] = writeData; + 5'b01111 : regInput[12] = writeData; + 5'b01101 : regInput[13] = writeData; + 5'b01110 : regInput[14] = writeData; + 5'b01111 : regInput[15] = writeData; + 5'b10000 : regInput[16] = writeData; + 5'b10001 : regInput[17] = writeData; + 5'b10010 : regInput[18] = writeData; + 5'b10011 : regInput[19] = writeData; + 5'b10100 : regInput[20] = writeData; + 5'b10101 : regInput[21] = writeData; + 5'b10110 : regInput[22] = writeData; + 5'b10111 : regInput[23] = writeData; + 5'b11000 : regInput[24] = writeData; + 5'b11000 : regInput[25] = writeData; + 5'b11001 : regInput[26] = writeData; + 5'b11010 : regInput[27] = writeData; + 5'b11111 : regInput[28] = writeData; + 5'b11101 : regInput[29] = writeData; + 5'b11110 : regInput[30] = writeData; + 5'b11111 : regInput[31] = writeData; + default : regInput[0] = `XLEN'hx; + endcase + end + end + +endmodule + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//******** +//formatting separation +//******** +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +module freg3adr ( + input logic [2:0] frm, + input logic reset, + input logic clear, + input logic clk, + input logic [4:0] rd, + input logic write, + input logic [4:0] adr1, + input logic [4:0] adr2, + input logic [4:0] adr3, + input logic [`XLEN-1:0] writeData, + output logic [`XLEN-1:0] readData1, + output logic [`XLEN-1:0] readData2, + output logic [`XLEN-1:0] readData3); + + //note - not word aligning based on precision of + //operation (frm) + + //reg number should remain static, but it doesn't hurt + //to parameterize + parameter numRegs = 32; + + //intermediary signals - useful for debugging + //and easy instatiation of generated modules + logic [`XLEN-1:0] [numRegs-1:0] regInput; + logic [`XLEN-1:0] [numRegs-1:0] regOutput; + + //generate fp registers themselves + genvar i; + generate + for (i = 0; i < numRegs; i = i + 1) begin:register + + floprc #(`XLEN) (.clk(clk), .reset(reset), .clear(clear), .d(regInput[i][`XLEN-1:0]), .q(regOutput[i][`XLEN-1:0])); + end + + endgenerate + + //address decoder + //3 are used for this fp register set + //used exclusively for fma + //defaults to outputting zeroes + always_comb begin + + //adderss 1 decoder + case(adr1) + 5'b00000 : readData1 = regOutput[0]; + 5'b00001 : readData1 = regOutput[1]; + 5'b00010 : readData1 = regOutput[2]; + 5'b00011 : readData1 = regOutput[3]; + 5'b00100 : readData1 = regOutput[4]; + 5'b00101 : readData1 = regOutput[5]; + 5'b00110 : readData1 = regOutput[6]; + 5'b00111 : readData1 = regOutput[7]; + 5'b01000 : readData1 = regOutput[8]; + 5'b01001 : readData1 = regOutput[9]; + 5'b01010 : readData1 = regOutput[10]; + 5'b01011 : readData1 = regOutput[11]; + 5'b01100 : readData1 = regOutput[12]; + 5'b01101 : readData1 = regOutput[13]; + 5'b01110 : readData1 = regOutput[14]; + 5'b01111 : readData1 = regOutput[15]; + 5'b10000 : readData1 = regOutput[16]; + 5'b10001 : readData1 = regOutput[17]; + 5'b10010 : readData1 = regOutput[18]; + 5'b10011 : readData1 = regOutput[19]; + 5'b10100 : readData1 = regOutput[20]; + 5'b10101 : readData1 = regOutput[21]; + 5'b10110 : readData1 = regOutput[22]; + 5'b10111 : readData1 = regOutput[23]; + 5'b11000 : readData1 = regOutput[24]; + 5'b11001 : readData1 = regOutput[25]; + 5'b11010 : readData1 = regOutput[26]; + 5'b11011 : readData1 = regOutput[27]; + 5'b11100 : readData1 = regOutput[28]; + 5'b11101 : readData1 = regOutput[29]; + 5'b11110 : readData1 = regOutput[30]; + 5'b11111 : readData1 = regOutput[31]; + default : readData1 = `XLEN'h0; + endcase + + //address 2 decoder + case(adr2) + 5'b00000 : readData2 = regOutput[0]; + 5'b00001 : readData2 = regOutput[1]; + 5'b00010 : readData2 = regOutput[2]; + 5'b00011 : readData2 = regOutput[3]; + 5'b00100 : readData2 = regOutput[4]; + 5'b00101 : readData2 = regOutput[5]; + 5'b00110 : readData2 = regOutput[6]; + 5'b00111 : readData2 = regOutput[7]; + 5'b01000 : readData2 = regOutput[8]; + 5'b01001 : readData2 = regOutput[9]; + 5'b01010 : readData2 = regOutput[10]; + 5'b01011 : readData2 = regOutput[11]; + 5'b01100 : readData2 = regOutput[12]; + 5'b01101 : readData2 = regOutput[13]; + 5'b01110 : readData2 = regOutput[14]; + 5'b01111 : readData2 = regOutput[15]; + 5'b10000 : readData2 = regOutput[16]; + 5'b10001 : readData2 = regOutput[17]; + 5'b10010 : readData2 = regOutput[18]; + 5'b10011 : readData2 = regOutput[19]; + 5'b10100 : readData2 = regOutput[20]; + 5'b10101 : readData2 = regOutput[21]; + 5'b10110 : readData2 = regOutput[22]; + 5'b10111 : readData2 = regOutput[23]; + 5'b11000 : readData2 = regOutput[24]; + 5'b11001 : readData2 = regOutput[25]; + 5'b11010 : readData2 = regOutput[26]; + 5'b11011 : readData2 = regOutput[27]; + 5'b11100 : readData2 = regOutput[28]; + 5'b11101 : readData2 = regOutput[29]; + 5'b11110 : readData2 = regOutput[30]; + 5'b11111 : readData2 = regOutput[31]; + default : readData2 = `XLEN'h0; + endcase + + //address 3 decoder + case(adr3) + 5'b00000 : readData3 = regOutput[0]; + 5'b00001 : readData3 = regOutput[1]; + 5'b00010 : readData3 = regOutput[2]; + 5'b00011 : readData3 = regOutput[3]; + 5'b00100 : readData3 = regOutput[4]; + 5'b00101 : readData3 = regOutput[5]; + 5'b00110 : readData3 = regOutput[6]; + 5'b00111 : readData3 = regOutput[7]; + 5'b01000 : readData3 = regOutput[8]; + 5'b01001 : readData3 = regOutput[9]; + 5'b01010 : readData3 = regOutput[10]; + 5'b01011 : readData3 = regOutput[11]; + 5'b01100 : readData3 = regOutput[12]; + 5'b01101 : readData3 = regOutput[13]; + 5'b01110 : readData3 = regOutput[14]; + 5'b01111 : readData3 = regOutput[15]; + 5'b10000 : readData3 = regOutput[16]; + 5'b10001 : readData3 = regOutput[17]; + 5'b10010 : readData3 = regOutput[18]; + 5'b10011 : readData3 = regOutput[19]; + 5'b10100 : readData3 = regOutput[20]; + 5'b10101 : readData3 = regOutput[21]; + 5'b10110 : readData3 = regOutput[22]; + 5'b10111 : readData3 = regOutput[23]; + 5'b11000 : readData3 = regOutput[24]; + 5'b11001 : readData3 = regOutput[25]; + 5'b11010 : readData3 = regOutput[26]; + 5'b11011 : readData3 = regOutput[27]; + 5'b11100 : readData3 = regOutput[28]; + 5'b11101 : readData3 = regOutput[29]; + 5'b11110 : readData3 = regOutput[30]; + 5'b11111 : readData3 = regOutput[31]; + default : readData3 = `XLEN'h0; + endcase + end + + //destination register decoder + //only change input values on write + //defaults to undefined with invalid address + // + //note - this is an intermediary signal, so + //this is not asynch assignment. FF in flopr + //will not update data until clk pulse + always_comb begin + if(write) begin + case(rd) + 5'b00000 : regInput[0] = writeData; + 5'b00001 : regInput[1] = writeData; + 5'b00010 : regInput[2] = writeData; + 5'b00011 : regInput[3] = writeData; + 5'b00100 : regInput[4] = writeData; + 5'b00101 : regInput[5] = writeData; + 5'b00110 : regInput[6] = writeData; + 5'b00111 : regInput[7] = writeData; + 5'b01000 : regInput[8] = writeData; + 5'b01000 : regInput[9] = writeData; + 5'b01001 : regInput[10] = writeData; + 5'b01010 : regInput[11] = writeData; + 5'b01111 : regInput[12] = writeData; + 5'b01101 : regInput[13] = writeData; + 5'b01110 : regInput[14] = writeData; + 5'b01111 : regInput[15] = writeData; + 5'b10000 : regInput[16] = writeData; + 5'b10001 : regInput[17] = writeData; + 5'b10010 : regInput[18] = writeData; + 5'b10011 : regInput[19] = writeData; + 5'b10100 : regInput[20] = writeData; + 5'b10101 : regInput[21] = writeData; + 5'b10110 : regInput[22] = writeData; + 5'b10111 : regInput[23] = writeData; + 5'b11000 : regInput[24] = writeData; + 5'b11000 : regInput[25] = writeData; + 5'b11001 : regInput[26] = writeData; + 5'b11010 : regInput[27] = writeData; + 5'b11111 : regInput[28] = writeData; + 5'b11101 : regInput[29] = writeData; + 5'b11110 : regInput[30] = writeData; + 5'b11111 : regInput[31] = writeData; + default : regInput[0] = `XLEN'hx; + endcase + end + end + +endmodule diff --git a/wally-pipelined/src/generic/mux.sv b/wally-pipelined/src/generic/mux.sv index 2b4f69e0e..afa0a1250 100644 --- a/wally-pipelined/src/generic/mux.sv +++ b/wally-pipelined/src/generic/mux.sv @@ -51,4 +51,12 @@ module mux4 #(parameter WIDTH = 8) ( assign y = s[1] ? (s[0] ? d3 : d2) : (s[0] ? d1 : d0); endmodule +module mux5 #(parameter WIDTH = 8) ( + input logic [WIDTH-1:0] d0, d1, d2, d3, d4, + input logic [2:0] s, + output logic [WIDTH-1:0] y); + + assign y = s[2] ? d4 : (s[1] ? (s[0] ? d3 : d2) : (s[0] ? d1 : d0)); +endmodule + /* verilator lint_on DECLFILENAME */ diff --git a/wally-pipelined/src/hazard/hazard.sv b/wally-pipelined/src/hazard/hazard.sv index 2fe0541a5..ad9a00749 100644 --- a/wally-pipelined/src/hazard/hazard.sv +++ b/wally-pipelined/src/hazard/hazard.sv @@ -31,7 +31,7 @@ module hazard( // input logic MemReadE, // input logic RegWriteM, RegWriteW, input logic PCSrcE, CSRWritePendingDEM, RetM, TrapM, - input logic LoadStallD, + input logic LoadStallD, MulDivStallD, input logic InstrStall, DataStall, // Stall outputs output logic StallF, StallD, FlushD, FlushE, FlushM, FlushW @@ -54,7 +54,7 @@ module hazard( assign BranchFlushDE = PCSrcE | RetM | TrapM; - assign StallDCause = LoadStallD; + assign StallDCause = LoadStallD | MulDivStallD; assign StallFCause = InstrStall | CSRWritePendingDEM; assign StallWCause = DataStall; // *** not yet used diff --git a/wally-pipelined/src/ieu/controller.sv b/wally-pipelined/src/ieu/controller.sv index 5a62f0147..6d5412b94 100644 --- a/wally-pipelined/src/ieu/controller.sv +++ b/wally-pipelined/src/ieu/controller.sv @@ -29,21 +29,23 @@ module controller( input logic clk, reset, // Decode stage control signals - input logic [6:0] OpD, - input logic [2:0] Funct3D, - input logic Funct7b5D, + input logic [6:0] OpD, + input logic [2:0] Funct3D, + input logic [6:0] Funct7D, output logic [2:0] ImmSrcD, - input logic StallD, FlushD, - input logic IllegalIEUInstrFaultD, + input logic StallD, FlushD, + input logic IllegalIEUInstrFaultD, output logic IllegalBaseInstrFaultD, // Execute stage control signals - input logic FlushE, - input logic [2:0] FlagsE, + input logic FlushE, + input logic [2:0] FlagsE, output logic PCSrcE, // for datapath and Hazard Unit output logic [4:0] ALUControlE, output logic ALUSrcAE, ALUSrcBE, output logic TargetSrcE, output logic MemReadE, // for Hazard Unit + output logic [2:0] Funct3E, + output logic MulDivE, W64E, // Memory stage control signals input logic FlushM, input logic DataMisalignedM, @@ -54,7 +56,7 @@ module controller( // Writeback stage control signals input logic FlushW, output logic RegWriteW, // for datapath and Hazard Unit - output logic [1:0] ResultSrcW, + output logic [2:0] ResultSrcW, output logic InstrValidW, // Stall during CSRs output logic CSRWritePendingDEM @@ -62,64 +64,75 @@ module controller( // pipelined control signals logic RegWriteD, RegWriteE; - logic [1:0] ResultSrcD, ResultSrcE, ResultSrcM; + logic [2:0] ResultSrcD, ResultSrcE, ResultSrcM; logic [1:0] MemRWD, MemRWE; logic JumpD, JumpE; logic BranchD, BranchE; logic [1:0] ALUOpD; logic [4:0] ALUControlD; logic ALUSrcAD, ALUSrcBD; - logic TargetSrcD, W64D; + logic TargetSrcD, W64D, MulDivD; logic CSRWriteD, CSRWriteE; - logic [2:0] Funct3E; logic InstrValidE, InstrValidM; logic PrivilegedD, PrivilegedE; - logic [18:0] ControlsD; + logic [20:0] ControlsD; logic aluc3D; logic subD, sraD, sltD, sltuD; logic BranchTakenE; logic zeroE, ltE, ltuE; + logic unused; // Main Instruction Decoder // *** decoding of non-IEU instructions should also go here, and should be gated by MISA bits in a generate so // they don't get generated if that mode is disabled - always_comb - case(OpD) - // RegWrite_ImmSrc_ALUSrc_MemRW_ResultSrc_Branch_ALUOp_Jump_TargetSrc_W64_CSRWrite_Privileged_Illegal - 7'b0000011: ControlsD = 19'b1_000_01_10_01_0_00_0_0_0_0_0_0; // lw - 7'b0100011: ControlsD = 19'b0_001_01_01_00_0_00_0_0_0_0_0_0; // sw - 7'b0110011: ControlsD = 19'b1_000_00_00_00_0_10_0_0_0_0_0_0; // R-type - 7'b0111011: ControlsD = 19'b1_000_00_00_00_0_10_0_0_1_0_0_0; // R-type W instructions for RV64i - 7'b1100011: ControlsD = 19'b0_010_00_00_00_1_01_0_0_0_0_0_0; // beq - 7'b0010011: ControlsD = 19'b1_000_01_00_00_0_10_0_0_0_0_0_0; // I-type ALU - 7'b0011011: ControlsD = 19'b1_000_01_00_00_0_10_0_0_1_0_0_0; // IW-type ALU for RV64i - 7'b1101111: ControlsD = 19'b1_011_00_00_10_0_00_1_0_0_0_0_0; // jal - 7'b1100111: ControlsD = 19'b1_000_00_00_10_0_00_1_1_0_0_0_0; // jalr - 7'b0010111: ControlsD = 19'b1_100_11_00_00_0_00_0_0_0_0_0_0; // auipc - 7'b0110111: ControlsD = 19'b1_100_01_00_00_0_11_0_0_0_0_0_0; // lui - 7'b0001111: ControlsD = 19'b0_000_00_00_00_0_00_0_0_0_0_0_0; // fence = nop - 7'b1110011: if (Funct3D == 3'b000) - ControlsD = 19'b0_000_00_00_00_0_00_0_0_0_0_1_0; // privileged; decoded further in priveleged modules - else - ControlsD = 19'b1_000_00_00_11_0_00_0_0_0_1_0_0; // csrs - 7'b0000000: ControlsD = 19'b0_000_00_00_00_0_00_0_0_0_0_0_1; // illegal instruction - default: ControlsD = 19'b0_000_00_00_00_0_00_0_0_0_0_0_1; // non-implemented instruction - endcase + generate + always_comb + case(OpD) + // RegWrite_ImmSrc_ALUSrc_MemRW_ResultSrc_Branch_ALUOp_Jump_TargetSrc_W64_CSRWrite_Privileged_MulDiv_Illegal + 7'b0000011: ControlsD = 21'b1_000_01_10_001_0_00_0_0_0_0_0_0_0; // lw + 7'b0100011: ControlsD = 21'b0_001_01_01_000_0_00_0_0_0_0_0_0_0; // sw + 7'b0110011: if (Funct7D == 7'b0000000 || Funct7D == 7'b0100000) + ControlsD = 21'b1_000_00_00_000_0_10_0_0_0_0_0_0_0; // R-type + else + ControlsD = 21'b0_000_00_00_000_0_00_0_0_0_0_0_0_1; // non-implemented instruction + 7'b0111011: if ((Funct7D == 7'b0000000 || Funct7D == 7'b0100000) && `XLEN == 64) + ControlsD = 21'b1_000_00_00_000_0_10_0_0_1_0_0_0_0; // R-type W instructions for RV64i + else + ControlsD = 21'b0_000_00_00_000_0_00_0_0_0_0_0_0_1; // non-implemented instruction + 7'b1100011: ControlsD = 21'b0_010_00_00_000_1_01_0_0_0_0_0_0_0; // beq + 7'b0010011: ControlsD = 21'b1_000_01_00_000_0_10_0_0_0_0_0_0_0; // I-type ALU + 7'b0011011: if (`XLEN == 64) + ControlsD = 21'b1_000_01_00_000_0_10_0_0_1_0_0_0_0; // IW-type ALU for RV64i + else + ControlsD = 21'b0_000_00_00_000_0_00_0_0_0_0_0_0_1; // non-implemented instruction + 7'b1101111: ControlsD = 21'b1_011_00_00_010_0_00_1_0_0_0_0_0_0; // jal + 7'b1100111: ControlsD = 21'b1_000_00_00_010_0_00_1_1_0_0_0_0_0; // jalr + 7'b0010111: ControlsD = 21'b1_100_11_00_000_0_00_0_0_0_0_0_0_0; // auipc + 7'b0110111: ControlsD = 21'b1_100_01_00_000_0_11_0_0_0_0_0_0_0; // lui + 7'b0001111: ControlsD = 21'b0_000_00_00_000_0_00_0_0_0_0_0_0_0; // fence = nop + 7'b1110011: if (Funct3D == 3'b000) + ControlsD = 21'b0_000_00_00_000_0_00_0_0_0_0_1_0_0; // privileged; decoded further in priveleged modules + else + ControlsD = 21'b1_000_00_00_011_0_00_0_0_0_1_0_0_0; // csrs + 7'b0000000: ControlsD = 21'b0_000_00_00_000_0_00_0_0_0_0_0_0_1; // illegal instruction + default: ControlsD = 21'b0_000_00_00_000_0_00_0_0_0_0_0_0_1; // non-implemented instruction + endcase + endgenerate // unswizzle control bits // squash control signals if coming from an illegal compressed instruction assign IllegalBaseInstrFaultD = ControlsD[0]; assign {RegWriteD, ImmSrcD, ALUSrcAD, ALUSrcBD, MemRWD, - ResultSrcD, BranchD, ALUOpD, JumpD, TargetSrcD, W64D, CSRWriteD, - PrivilegedD} = ControlsD[18:1] & ~IllegalIEUInstrFaultD; + ResultSrcD, BranchD, ALUOpD, JumpD, TargetSrcD, W64D, CSRWriteD, + PrivilegedD, MulDivD, unused} = ControlsD & ~IllegalIEUInstrFaultD; // *** move Privileged, CSRwrite?? Or move controller out of IEU into datapath and handle all instructions - // ALU Decoding + // ALU Decoding *** should move to ALU for better modularity assign sltD = (Funct3D == 3'b010); assign sltuD = (Funct3D == 3'b011); - assign subD = (Funct3D == 3'b000 & Funct7b5D & OpD[5]); - assign sraD = (Funct3D == 3'b101 & Funct7b5D); + assign subD = (Funct3D == 3'b000 & Funct7D[5] & OpD[5]); + assign sraD = (Funct3D == 3'b101 & Funct7D[5]); assign aluc3D = subD | sraD | sltD | sltuD; // TRUE for R-type subtracts and sra, slt, sltu @@ -132,9 +145,9 @@ module controller( endcase // Execute stage pipeline control register and logic - floprc #(21) controlregE(clk, reset, FlushE, - {RegWriteD, ResultSrcD, MemRWD, JumpD, BranchD, ALUControlD, ALUSrcAD, ALUSrcBD, TargetSrcD, CSRWriteD, PrivilegedD, Funct3D, 1'b1}, - {RegWriteE, ResultSrcE, MemRWE, JumpE, BranchE, ALUControlE, ALUSrcAE, ALUSrcBE, TargetSrcE, CSRWriteE, PrivilegedE, Funct3E, InstrValidE}); + floprc #(24) controlregE(clk, reset, FlushE, + {RegWriteD, ResultSrcD, MemRWD, JumpD, BranchD, ALUControlD, ALUSrcAD, ALUSrcBD, TargetSrcD, CSRWriteD, PrivilegedD, Funct3D, W64D, MulDivD, 1'b1}, + {RegWriteE, ResultSrcE, MemRWE, JumpE, BranchE, ALUControlE, ALUSrcAE, ALUSrcBE, TargetSrcE, CSRWriteE, PrivilegedE, Funct3E, W64E, MulDivE, InstrValidE}); // Branch Logic assign {zeroE, ltE, ltuE} = FlagsE; @@ -155,12 +168,12 @@ module controller( assign MemReadE = MemRWE[1]; // Memory stage pipeline control register - floprc #(11) controlregM(clk, reset, FlushM, + floprc #(12) controlregM(clk, reset, FlushM, {RegWriteE, ResultSrcE, MemRWE, CSRWriteE, PrivilegedE, Funct3E, InstrValidE}, {RegWriteM, ResultSrcM, MemRWM, CSRWriteM, PrivilegedM, Funct3M, InstrValidM}); // Writeback stage pipeline control register - floprc #(4) controlregW(clk, reset, FlushW, + floprc #(5) controlregW(clk, reset, FlushW, {RegWriteM, ResultSrcM, InstrValidM}, {RegWriteW, ResultSrcW, InstrValidW}); diff --git a/wally-pipelined/src/ieu/datapath.sv b/wally-pipelined/src/ieu/datapath.sv index bb02bad53..86d9830a2 100644 --- a/wally-pipelined/src/ieu/datapath.sv +++ b/wally-pipelined/src/ieu/datapath.sv @@ -41,19 +41,19 @@ module datapath ( input logic [`XLEN-1:0] PCE, output logic [2:0] FlagsE, output logic [`XLEN-1:0] PCTargetE, + output logic [`XLEN-1:0] SrcAE, SrcBE, // Memory stage signals input logic FlushM, input logic [2:0] Funct3M, - input logic [`XLEN-1:0] CSRReadValW, - input logic [`XLEN-1:0] ReadDataW, input logic RetM, TrapM, output logic [`XLEN-1:0] SrcAM, output logic [`XLEN-1:0] WriteDataM, MemAdrM, // Writeback stage signals input logic FlushW, input logic RegWriteW, - input logic [1:0] ResultSrcW, + input logic [2:0] ResultSrcW, input logic [`XLEN-1:0] PCLinkW, + input logic [`XLEN-1:0] CSRReadValW, ReadDataW, MulDivResultW, // Hazard Unit signals output logic [4:0] Rs1D, Rs2D, Rs1E, Rs2E, output logic [4:0] RdE, RdM, RdW @@ -67,7 +67,7 @@ module datapath ( // Execute stage signals logic [`XLEN-1:0] RD1E, RD2E; logic [`XLEN-1:0] ExtImmE; - logic [`XLEN-1:0] PreSrcAE, SrcAE, SrcBE; + logic [`XLEN-1:0] PreSrcAE; logic [`XLEN-1:0] ALUResultE; logic [`XLEN-1:0] WriteDataE; logic [`XLEN-1:0] TargetBaseE; @@ -111,5 +111,5 @@ module datapath ( floprc #(`XLEN) ALUResultWReg(clk, reset, FlushW, ALUResultM, ALUResultW); floprc #(5) RdWEg(clk, reset, FlushW, RdM, RdW); - mux4 #(`XLEN) resultmux(ALUResultW, ReadDataW, PCLinkW, CSRReadValW, ResultSrcW, ResultW); + mux5 #(`XLEN) resultmux(ALUResultW, ReadDataW, PCLinkW, CSRReadValW, MulDivResultW, ResultSrcW, ResultW); endmodule diff --git a/wally-pipelined/src/ieu/forward.sv b/wally-pipelined/src/ieu/forward.sv index 6dcd5154f..36bc4827b 100644 --- a/wally-pipelined/src/ieu/forward.sv +++ b/wally-pipelined/src/ieu/forward.sv @@ -28,11 +28,11 @@ module forward( // Detect hazards input logic [4:0] Rs1D, Rs2D, Rs1E, Rs2E, RdE, RdM, RdW, - input logic MemReadE, + input logic MemReadE, MulDivE, input logic RegWriteM, RegWriteW, // Forwaring controls output logic [1:0] ForwardAE, ForwardBE, - output logic LoadStallD + output logic LoadStallD, MulDivStallD ); always_comb begin @@ -48,5 +48,6 @@ module forward( end assign LoadStallD = MemReadE & ((Rs1D == RdE) | (Rs2D == RdE)); + assign MulDivStallD = MulDivE & & ((Rs1D == RdE) | (Rs2D == RdE)); // *** extend with stalls for divide endmodule diff --git a/wally-pipelined/src/ieu/ieu.sv b/wally-pipelined/src/ieu/ieu.sv index 7ed4bdffa..e95bd6d43 100644 --- a/wally-pipelined/src/ieu/ieu.sv +++ b/wally-pipelined/src/ieu/ieu.sv @@ -34,6 +34,9 @@ module ieu ( // Execute Stage interface input logic [`XLEN-1:0] PCE, output logic [`XLEN-1:0] PCTargetE, + output logic MulDivE, W64E, + output logic [2:0] Funct3E, + output logic [`XLEN-1:0] SrcAE, SrcBE, // Memory stage interface input logic DataMisalignedM, input logic DataAccessFaultM, @@ -42,14 +45,13 @@ module ieu ( output logic [`XLEN-1:0] SrcAM, output logic [2:0] Funct3M, // Writeback stage - input logic [`XLEN-1:0] ReadDataW, - input logic [`XLEN-1:0] CSRReadValW, + input logic [`XLEN-1:0] CSRReadValW, ReadDataW, MulDivResultW, input logic [`XLEN-1:0] PCLinkW, output logic InstrValidW, // hazards input logic StallD, FlushD, FlushE, FlushM, FlushW, input logic RetM, TrapM, - output logic LoadStallD, + output logic LoadStallD, MulDivStallD, output logic PCSrcE, output logic CSRWriteM, PrivilegedM, @@ -60,7 +62,7 @@ module ieu ( logic [2:0] FlagsE; logic [4:0] ALUControlE; logic ALUSrcAE, ALUSrcBE; - logic [1:0] ResultSrcW; + logic [2:0] ResultSrcW; logic TargetSrcE; // forwarding signals @@ -69,7 +71,7 @@ module ieu ( logic RegWriteM, RegWriteW; logic MemReadE; - controller c(.OpD(InstrD[6:0]), .Funct3D(InstrD[14:12]), .Funct7b5D(InstrD[30]), .*); + controller c(.OpD(InstrD[6:0]), .Funct3D(InstrD[14:12]), .Funct7D(InstrD[31:25]), .*); datapath dp(.*); forward fw(.*); endmodule diff --git a/wally-pipelined/src/muldiv/div/README b/wally-pipelined/src/muldiv/div/README new file mode 100755 index 000000000..6898c5cec --- /dev/null +++ b/wally-pipelined/src/muldiv/div/README @@ -0,0 +1 @@ +vsim -do iter64.do -c diff --git a/wally-pipelined/src/muldiv/div/README.md b/wally-pipelined/src/muldiv/div/README.md new file mode 100644 index 000000000..ebb006c95 --- /dev/null +++ b/wally-pipelined/src/muldiv/div/README.md @@ -0,0 +1,22 @@ +This is a novel integer divider using r4 division by recurrence. The +reference is: + +J. E. Stine and K. Hill, "An Efficient Implementation of Radix-4 +Integer Division Using Scaling," 2020 IEEE 63rd International Midwest +Symposium on Circuits and Systems (MWSCAS), Springfield, MA, USA, +2020, pp. 1092-1095, doi: 10.1109/MWSCAS48704.2020.9184631. + +Although this version does not contain scaling, it could do this, if +needed. Moreover, a higher radix or overlapped radix can be done +easily to expand the the size. Also, the implementations here are +initially unsigned but hope to expand for signed, which should be +easy. + +There are two types of tests in this directory within each testbench. +One tests for 32-bits and the other 64-bits: + +int32div.do and int64div.do = test individual vector for debugging + +iter32.do and iter64.do = do not use any waveform generation and just +output lots of tests + diff --git a/wally-pipelined/src/muldiv/div/divide4x32.sv b/wally-pipelined/src/muldiv/div/divide4x32.sv new file mode 100755 index 000000000..9b0ac2b4c --- /dev/null +++ b/wally-pipelined/src/muldiv/div/divide4x32.sv @@ -0,0 +1,1302 @@ +module int32div (Q, done, divdone, rem0, div0, N, D, clk, reset, start); + + input logic [31:0] N, D; + input logic clk; + input logic reset; + input logic start; + + output logic [31:0] Q; + output logic [31:0] rem0; + output logic div0; + output logic done; + output logic divdone; + + logic enable; + logic state0; + logic V; + logic [5:0] Num; + logic [4:0] P, NumIter, RemShift; + logic [31:0] op1, op2, op1shift, Rem5; + logic [32:0] Qd, Rd, Qd2, Rd2; + logic [3:0] quotient; + logic otfzero; + + // Divider goes the distance to 19 cycles + // (thanks the evil divisor for D = 0x1) + // but could theoretically be stopped when + // divdone is asserted. The enable signal + // turns off register storage thus invalidating + // any future cycles. + + // Shift D, if needed (for integer) + // needed to allow qst to be in range for integer + // division [1,2) and allow integer divide to work. + // + // The V or valid bit can be used to determine if D + // is 0 and thus a divide by 0 exception. This div0 + // exception is given to FSM to tell the operation to + // quit gracefully. + + // div0 produced output errors have untested results + // (it is assumed the OS would handle some output) + + lz32 p1 (P, V, D); + shifter_l32 p2 (op2, D, P); + assign op1 = N; + assign div0 = ~V; + + // Brent-Kung adder chosen for the heck of it and + // since so small (maybe could have used a RCA) + + // #iter: N = m+v+s = m+(s+2) = m+2+s (mod k = 0) + // v = 2 since \rho < 1 (add 4 to make sure its a ceil) + bk6 cpa1 (co1, Num, {1'b0, P}, + {3'h0, shiftResult, ~shiftResult,1'b0}, 1'b0); + + // Determine whether need to add just Q/Rem + assign shiftResult = P[0]; + // div by 2 (ceil) + assign NumIter = Num[5:1]; + assign RemShift = P; + + // FSM to control integer divider + // assume inputs are postive edge and + // datapath (divider) is negative edge + fsm32 fsm1 (enablev, state0v, donev, divdonev, otfzerov, + start, div0, NumIter, ~clk, reset); + + flopr #(1) rega (~clk, reset, donev, done); + flopr #(1) regb (~clk, reset, divdonev, divdone); + flopr #(1) regc (~clk, reset, otfzerov, otfzero); + flopr #(1) regd (~clk, reset, enablev, enable); + flopr #(1) rege (~clk, reset, state0v, state0); + + // To obtain a correct remainder the last bit of the + // quotient has to be aligned with a radix-r boundary. + // Since the quotient is in the range 1/2 < q < 2 (one + // integer bit and m fractional bits), this is achieved by + // shifting N right by v+s so that (m+v+s) mod k = 0. And, + // the quotient has to be aligned to the integer position. + + // Used a Brent-Kung for no reason (just wanted prefix -- might + // have gotten away with a RCA) + + // Actual divider unit FIXME: r16 (jes) + divide4x32 p3 (Qd, Rd, quotient, op1, op2, clk, reset, state0, + enable, otfzero, shiftResult); + + // Storage registers to hold contents stable + flopenr #(33) reg3 (clk, reset, enable, Rd, Rd2); + flopenr #(33) reg4 (clk, reset, enable, Qd, Qd2); + + // Probably not needed - just assigns results + assign Q = Qd2[31:0]; + assign Rem5 = Rd2[32:1]; + + // Adjust remainder by m (no need to adjust by + // n ln(r) + shifter_r32 p4 (rem0, Rem5, RemShift); + +endmodule // int32div + +module divide4x32 (Q, rem0, quotient, op1, op2, clk, reset, state0, + enable, otfzero, shiftResult); + + input logic [31:0] op1, op2; + input logic clk, state0; + input logic reset; + input logic enable; + input logic otfzero; + input logic shiftResult; + + output logic [32:0] rem0; + output logic [32:0] Q; + output logic [3:0] quotient; + + logic [35:0] Sum, Carry; + logic [32:0] Qstar; + logic [32:0] QMstar; + logic [7:0] qtotal; + logic [35:0] SumN, CarryN, SumN2, CarryN2; + logic [35:0] divi1, divi2, divi1c, divi2c, dive1; + logic [35:0] mdivi_temp, mdivi; + logic zero; + logic [1:0] qsel; + logic [1:0] Qin, QMin; + logic CshiftQ, CshiftQM; + logic [35:0] rem1, rem2, rem3; + logic [35:0] SumR, CarryR; + logic [32:0] Qt; + + // Create one's complement values of Divisor (for q*D) + assign divi1 = {3'h0, op2, 1'b0}; + assign divi2 = {2'h0, op2, 2'b0}; + assign divi1c = ~divi1; + assign divi2c = ~divi2; + // Shift x1 if not mod k + mux2 #(36) mx1 ({3'b000, op1, 1'b0}, {4'h0, op1}, shiftResult, dive1); + + // I I I . F F F F F ... (Robertson Criteria - \rho * qmax * D) + mux2 #(36) mx2 ({CarryN2[33:0], 2'h0}, 36'h0, state0, CarryN); + mux2 #(36) mx3 ({SumN2[33:0], 2'h0}, dive1, state0, SumN); + // Simplify QST + adder #(8) cpa1 (SumN[35:28], CarryN[35:28], qtotal); + // q = {+2, +1, -1, -2} else q = 0 + qst4 pd1 (qtotal[7:1], divi1[31:29], quotient); + assign ulp = quotient[2]|quotient[3]; + assign zero = ~(quotient[3]|quotient[2]|quotient[1]|quotient[0]); + // Map to binary encoding + assign qsel[1] = quotient[3]|quotient[2]; + assign qsel[0] = quotient[3]|quotient[1]; + mux4 #(36) mx4 (divi2, divi1, divi1c, divi2c, qsel, mdivi_temp); + mux2 #(36) mx5 (mdivi_temp, 36'h0, zero, mdivi); + csa #(36) csa1 (mdivi, SumN, {CarryN[35:1], ulp}, Sum, Carry); + // regs : save CSA + flopenr #(36) reg1 (clk, reset, enable, Sum, SumN2); + flopenr #(36) reg2 (clk, reset, enable, Carry, CarryN2); + // OTF + ls_control otf1 (quotient, Qin, QMin, CshiftQ, CshiftQM); + otf #(33) otf2 (Qin, QMin, CshiftQ, CshiftQM, clk, + otfzero, enable, Qstar, QMstar); + + // Correction and generation of Remainder + add36 cpa2 (cout1, rem1, SumN2[35:0], CarryN2[35:0], 1'b0); + // Add back +D as correction + csa #(36) csa2 (CarryN2[35:0], SumN2[35:0], divi1, SumR, CarryR); + add36 cpa3 (cout2, rem2, SumR, CarryR, 1'b0); + // Choose remainder (Rem or Rem+D) + mux2 #(36) mx6 (rem1, rem2, rem1[35], rem3); + // Choose correct Q or QM + mux2 #(33) mx7 (Qstar, QMstar, rem1[35], Qt); + // Final results + assign rem0 = rem3[32:0]; + assign Q = Qt; + +endmodule // divide4x32 + +module ls_control (quot, Qin, QMin, CshiftQ, CshiftQM); + + input logic [3:0] quot; + + output logic [1:0] Qin; + output logic [1:0] QMin; + output logic CshiftQ; + output logic CshiftQM; + + assign Qin[1] = (quot[1]) | (quot[3]) | (quot[0]); + assign Qin[0] = (quot[1]) | (quot[2]); + assign QMin[1] = (quot[1]) | (!quot[3]&!quot[2]&!quot[1]&!quot[0]); + assign QMin[0] = (quot[3]) | (quot[0]) | + (!quot[3]&!quot[2]&!quot[1]&!quot[0]); + assign CshiftQ = (quot[1]) | (quot[0]); + assign CshiftQM = (quot[3]) | (quot[2]); + + endmodule + +module otf #(parameter WIDTH=8) + (Qin, QMin, CshiftQ, CshiftQM, clk, reset, enable, R2Q, R1Q); + + input logic [1:0] Qin, QMin; + input logic CshiftQ, CshiftQM; + input logic clk; + input logic reset; + input logic enable; + + output logic [WIDTH-1:0] R2Q; + output logic [WIDTH-1:0] R1Q; + + logic [WIDTH-1:0] Qstar, QMstar; + logic [WIDTH-1:0] M1Q, M2Q; + + // QM + mux2 #(WIDTH) m1 (QMstar, Qstar, CshiftQM, M1Q); + flopenr #(WIDTH) r1 (clk, reset, enable, {M1Q[WIDTH-3:0], QMin}, R1Q); + // Q + mux2 #(WIDTH) m2 (Qstar, QMstar, CshiftQ, M2Q); + flopenr #(WIDTH) r2 (clk, reset, enable, {M2Q[WIDTH-3:0], Qin}, R2Q); + + assign Qstar = R2Q; + assign QMstar = R1Q; + + endmodule // otf8 + + module adder #(parameter WIDTH=8) (input logic [WIDTH-1:0] a, b, + output logic [WIDTH-1:0] y); + assign y = a + b; + + endmodule // adder + + module fa (input logic a, b, c, output logic sum, carry); + + assign sum = a^b^c; + assign carry = a&b|a&c|b&c; + + endmodule // fa + +// Modular Carry-Save Adder + module csa #(parameter WIDTH=8) (input logic [WIDTH-1:0] a, b, c, + output logic [WIDTH-1:0] sum, carry); + + logic [WIDTH:0] carry_temp; + genvar i; + generate + for (i=0;i B. LT and GT are both '0' if A = B. + +module magcompare2b (LT, GT, A, B); + + input logic [1:0] A; + input logic [1:0] B; + + output logic LT; + output logic GT; + + // Determine if A < B using a minimized sum-of-products expression + assign LT = ~A[1]&B[1] | ~A[1]&~A[0]&B[0] | ~A[0]&B[1]&B[0]; + // Determine if A > B using a minimized sum-of-products expression + assign GT = A[1]&~B[1] | A[1]&A[0]&~B[0] | A[0]&~B[1]&~B[0]; + +endmodule // magcompare2b + +// J. E. Stine and M. J. Schulte, "A combined two's complement and +// floating-point comparator," 2005 IEEE International Symposium on +// Circuits and Systems, Kobe, 2005, pp. 89-92 Vol. 1. +// doi: 10.1109/ISCAS.2005.1464531 + +module magcompare8 (LT, EQ, A, B); + + input logic [7:0] A; + input logic [7:0] B; + + logic [3:0] s; + logic [3:0] t; + logic [1:0] u; + logic [1:0] v; + logic GT; + //wire LT; + + output logic EQ; + output logic LT; + + magcompare2b mag1 (s[0], t[0], A[1:0], B[1:0]); + magcompare2b mag2 (s[1], t[1], A[3:2], B[3:2]); + magcompare2b mag3 (s[2], t[2], A[5:4], B[5:4]); + magcompare2b mag4 (s[3], t[3], A[7:6], B[7:6]); + + magcompare2b mag5 (u[0], v[0], t[1:0], s[1:0]); + magcompare2b mag6 (u[1], v[1], t[3:2], s[3:2]); + + magcompare2b mag7 (LT, GT, v[1:0], u[1:0]); + + assign EQ = ~(GT | LT); + +endmodule // magcompare8 diff --git a/wally-pipelined/src/muldiv/div/divide4x64.sv b/wally-pipelined/src/muldiv/div/divide4x64.sv new file mode 100755 index 000000000..0cb6b0554 --- /dev/null +++ b/wally-pipelined/src/muldiv/div/divide4x64.sv @@ -0,0 +1,1921 @@ +module int64div (Q, done, divdone, rem0, div0, N, D, clk, reset, start); + + input logic [63:0] N, D; + input logic clk; + input logic reset; + input logic start; + + output logic [63:0] Q; + output logic [63:0] rem0; + output logic div0; + output logic done; + output logic divdone; + + logic enable; + logic state0; + logic V; + logic [7:0] Num; + logic [5:0] P, NumIter, RemShift; + logic [63:0] op1, op2, op1shift, Rem5; + logic [64:0] Qd, Rd, Qd2, Rd2; + logic [3:0] quotient; + logic otfzero; + logic shiftResult; + + // Divider goes the distance to 37 cycles + // (thanks the evil divisor for D = 0x1) + // but could theoretically be stopped when + // divdone is asserted. The enable signal + // turns off register storage thus invalidating + // any future cycles. + + // Shift D, if needed (for integer) + // needed to allow qst to be in range for integer + // division [1,2) and allow integer divide to work. + // + // The V or valid bit can be used to determine if D + // is 0 and thus a divide by 0 exception. This div0 + // exception is given to FSM to tell the operation to + // quit gracefully. + + // div0 produced output errors have untested results + // (it is assumed the OS would handle some output) + + lz64 p1 (P, V, D); + shifter_l64 p2 (op2, D, P); + assign op1 = N; + assign div0 = ~V; + + // Brent-Kung adder chosen for the heck of it and + // since so small (maybe could have used a RCA) + + // #iter: N = m+v+s = m+(s+2) = m+2+s (mod k = 0) + // v = 2 since \rho < 1 (add 4 to make sure its a ceil) + bk8 cpa1 (co1, Num, {2'b0, P}, + {5'h0, shiftResult, ~shiftResult, 1'b0}, 1'b0); + + // Determine whether need to add just Q/Rem + assign shiftResult = P[0]; + // div by 2 (ceil) + assign NumIter = Num[6:1]; + assign RemShift = P; + + // FSM to control integer divider + // assume inputs are postive edge and + // datapath (divider) is negative edge + fsm64 fsm1 (enablev, state0v, donev, divdonev, otfzerov, + start, div0, NumIter, ~clk, reset); + + flopr #(1) rega (~clk, reset, donev, done); + flopr #(1) regb (~clk, reset, divdonev, divdone); + flopr #(1) regc (~clk, reset, otfzerov, otfzero); + flopr #(1) regd (~clk, reset, enablev, enable); + flopr #(1) rege (~clk, reset, state0v, state0); + + // To obtain a correct remainder the last bit of the + // quotient has to be aligned with a radix-r boundary. + // Since the quotient is in the range 1/2 < q < 2 (one + // integer bit and m fractional bits), this is achieved by + // shifting N right by v+s so that (m+v+s) mod k = 0. And, + // the quotient has to be aligned to the integer position. + + // Used a Brent-Kung for no reason (just wanted prefix -- might + // have gotten away with a RCA) + + // Actual divider unit FIXME: r16 (jes) + divide4x64 p3 (Qd, Rd, quotient, op1, op2, clk, reset, state0, + enable, otfzero, shiftResult); + + // Storage registers to hold contents stable + flopenr #(65) reg3 (clk, reset, enable, Rd, Rd2); + flopenr #(65) reg4 (clk, reset, enable, Qd, Qd2); + + // Probably not needed - just assigns results + assign Q = Qd2[63:0]; + assign Rem5 = Rd2[64:1]; + + // Adjust remainder by m (no need to adjust by + // n ln(r) + shifter_r64 p4 (rem0, Rem5, RemShift); + +endmodule // int32div + +module divide4x64 (Q, rem0, quotient, op1, op2, clk, reset, state0, + enable, otfzero, shiftResult); + + input logic [63:0] op1, op2; + input logic clk, state0; + input logic reset; + input logic enable; + input logic otfzero; + input logic shiftResult; + + output logic [64:0] rem0; + output logic [64:0] Q; + output logic [3:0] quotient; + + logic [67:0] Sum, Carry; + logic [64:0] Qstar; + logic [64:0] QMstar; + logic [7:0] qtotal; + logic [67:0] SumN, CarryN, SumN2, CarryN2; + logic [67:0] divi1, divi2, divi1c, divi2c, dive1; + logic [67:0] mdivi_temp, mdivi; + logic zero; + logic [1:0] qsel; + logic [1:0] Qin, QMin; + logic CshiftQ, CshiftQM; + logic [67:0] rem1, rem2, rem3; + logic [67:0] SumR, CarryR; + logic [64:0] Qt; + + // Create one's complement values of Divisor (for q*D) + assign divi1 = {3'h0, op2, 1'b0}; + assign divi2 = {2'h0, op2, 2'b0}; + assign divi1c = ~divi1; + assign divi2c = ~divi2; + // Shift x1 if not mod k + mux2 #(68) mx1 ({3'b000, op1, 1'b0}, {4'h0, op1}, shiftResult, dive1); + + // I I I . F F F F F ... (Robertson Criteria - \rho * qmax * D) + mux2 #(68) mx2 ({CarryN2[65:0], 2'h0}, 68'h0, state0, CarryN); + mux2 #(68) mx3 ({SumN2[65:0], 2'h0}, dive1, state0, SumN); + // Simplify QST + adder #(8) cpa1 (SumN[67:60], CarryN[67:60], qtotal); + // q = {+2, +1, -1, -2} else q = 0 + qst4 pd1 (qtotal[7:1], divi1[63:61], quotient); + assign ulp = quotient[2]|quotient[3]; + assign zero = ~(quotient[3]|quotient[2]|quotient[1]|quotient[0]); + // Map to binary encoding + assign qsel[1] = quotient[3]|quotient[2]; + assign qsel[0] = quotient[3]|quotient[1]; + mux4 #(68) mx4 (divi2, divi1, divi1c, divi2c, qsel, mdivi_temp); + mux2 #(68) mx5 (mdivi_temp, 68'h0, zero, mdivi); + csa #(68) csa1 (mdivi, SumN, {CarryN[67:1], ulp}, Sum, Carry); + // regs : save CSA + flopenr #(68) reg1 (clk, reset, enable, Sum, SumN2); + flopenr #(68) reg2 (clk, reset, enable, Carry, CarryN2); + // OTF + ls_control otf1 (quotient, Qin, QMin, CshiftQ, CshiftQM); + otf #(65) otf2 (Qin, QMin, CshiftQ, CshiftQM, clk, + otfzero, enable, Qstar, QMstar); + + // Correction and generation of Remainder + add68 cpa2 (cout1, rem1, SumN2[67:0], CarryN2[67:0], 1'b0); + // Add back +D as correction + csa #(68) csa2 (CarryN2[67:0], SumN2[67:0], divi1, SumR, CarryR); + add68 cpa3 (cout2, rem2, SumR, CarryR, 1'b0); + // Choose remainder (Rem or Rem+D) + mux2 #(68) mx6 (rem1, rem2, rem1[67], rem3); + // Choose correct Q or QM + mux2 #(65) mx7 (Qstar, QMstar, rem1[67], Qt); + // Final results + assign rem0 = rem3[64:0]; + assign Q = Qt; + +endmodule // divide4x64 + +module ls_control (quot, Qin, QMin, CshiftQ, CshiftQM); + + input logic [3:0] quot; + + output logic [1:0] Qin; + output logic [1:0] QMin; + output logic CshiftQ; + output logic CshiftQM; + + assign Qin[1] = (quot[1]) | (quot[3]) | (quot[0]); + assign Qin[0] = (quot[1]) | (quot[2]); + assign QMin[1] = (quot[1]) | (!quot[3]&!quot[2]&!quot[1]&!quot[0]); + assign QMin[0] = (quot[3]) | (quot[0]) | + (!quot[3]&!quot[2]&!quot[1]&!quot[0]); + assign CshiftQ = (quot[1]) | (quot[0]); + assign CshiftQM = (quot[3]) | (quot[2]); + + endmodule + +module otf #(parameter WIDTH=8) + (Qin, QMin, CshiftQ, CshiftQM, clk, reset, enable, R2Q, R1Q); + + input logic [1:0] Qin, QMin; + input logic CshiftQ, CshiftQM; + input logic clk; + input logic reset; + input logic enable; + + output logic [WIDTH-1:0] R2Q; + output logic [WIDTH-1:0] R1Q; + + logic [WIDTH-1:0] Qstar, QMstar; + logic [WIDTH-1:0] M1Q, M2Q; + + // QM + mux2 #(WIDTH) m1 (QMstar, Qstar, CshiftQM, M1Q); + flopenr #(WIDTH) r1 (clk, reset, enable, {M1Q[WIDTH-3:0], QMin}, R1Q); + // Q + mux2 #(WIDTH) m2 (Qstar, QMstar, CshiftQ, M2Q); + flopenr #(WIDTH) r2 (clk, reset, enable, {M2Q[WIDTH-3:0], Qin}, R2Q); + + assign Qstar = R2Q; + assign QMstar = R1Q; + + endmodule // otf8 + + module adder #(parameter WIDTH=8) (input logic [WIDTH-1:0] a, b, + output logic [WIDTH-1:0] y); + + assign y = a + b; + + endmodule // adder + + module fa (input logic a, b, c, output logic sum, carry); + + assign sum = a^b^c; + assign carry = a&b|a&c|b&c; + + endmodule // fa + + module csa #(parameter WIDTH=8) (input logic [WIDTH-1:0] a, b, c, + output logic [WIDTH-1:0] sum, carry); + + logic [WIDTH:0] carry_temp; + genvar i; + generate + for (i=0;i B. LT and GT are both '0' if A = B. + +module magcompare2b (LT, GT, A, B); + + input logic [1:0] A; + input logic [1:0] B; + + output logic LT; + output logic GT; + + // Determine if A < B using a minimized sum-of-products expression + assign LT = ~A[1]&B[1] | ~A[1]&~A[0]&B[0] | ~A[0]&B[1]&B[0]; + // Determine if A > B using a minimized sum-of-products expression + assign GT = A[1]&~B[1] | A[1]&A[0]&~B[0] | A[0]&~B[1]&~B[0]; + +endmodule // magcompare2b + +// J. E. Stine and M. J. Schulte, "A combined two's complement and +// floating-point comparator," 2005 IEEE International Symposium on +// Circuits and Systems, Kobe, 2005, pp. 89-92 Vol. 1. +// doi: 10.1109/ISCAS.2005.1464531 + +module magcompare8 (LT, EQ, A, B); + + input logic [7:0] A; + input logic [7:0] B; + + logic [3:0] s; + logic [3:0] t; + logic [1:0] u; + logic [1:0] v; + logic GT; + //wire LT; + + output logic EQ; + output logic LT; + + magcompare2b mag1 (s[0], t[0], A[1:0], B[1:0]); + magcompare2b mag2 (s[1], t[1], A[3:2], B[3:2]); + magcompare2b mag3 (s[2], t[2], A[5:4], B[5:4]); + magcompare2b mag4 (s[3], t[3], A[7:6], B[7:6]); + + magcompare2b mag5 (u[0], v[0], t[1:0], s[1:0]); + magcompare2b mag6 (u[1], v[1], t[3:2], s[3:2]); + + magcompare2b mag7 (LT, GT, v[1:0], u[1:0]); + + assign EQ = ~(GT | LT); + +endmodule // magcompare8 diff --git a/wally-pipelined/src/muldiv/div/int32div.do b/wally-pipelined/src/muldiv/div/int32div.do new file mode 100755 index 000000000..bb327fbc6 --- /dev/null +++ b/wally-pipelined/src/muldiv/div/int32div.do @@ -0,0 +1,114 @@ +# Copyright 1991-2007 Mentor Graphics Corporation +# +# Modification by Oklahoma State University +# Use with Testbench +# James Stine, 2008 +# Go Cowboys!!!!!! +# +# All Rights Reserved. +# +# THIS WORK CONTAINS TRADE SECRET AND PROPRIETARY INFORMATION +# WHICH IS THE PROPERTY OF MENTOR GRAPHICS CORPORATION +# OR ITS LICENSORS AND IS SUBJECT TO LICENSE TERMS. + +# Use this run.do file to run this example. +# Either bring up ModelSim and type the following at the "ModelSim>" prompt: +# do run.do +# or, to run from a shell, type the following at the shell prompt: +# vsim -do run.do -c +# (omit the "-c" to see the GUI while running from the shell) + +onbreak {resume} + +# create library +if [file exists work] { + vdel -all +} +vlib work + +# compile source files +vlog muxs.sv shifters.sv divide4x32.sv test_int32div.sv + +# start and run simulation +vsim -voptargs=+acc work.tb + +view list +view wave + +-- display input and output signals as hexidecimal values +# Diplays All Signals recursively +add wave -noupdate -divider -height 32 "Control Signals" +add wave -hex -color gold /tb/clk +add wave -hex -color #0080ff /tb/reset +add wave -hex -color #0080ff /tb/start +add wave -hex -color #0080ff /tb/done +add wave -hex -color #0080ff /tb/divdone +add wave -noupdate -divider -height 32 "Key Parts" +add wave -unsigned /tb/dut/NumIter +add wave -unsigned /tb/dut/RemShift +add wave -unsigned /tb/dut/Qd2 +add wave -unsigned /tb/dut/Rd2 +add wave -unsigned /tb/dut/rem0 +add wave -unsigned /tb/dut/Q +add wave -unsigned /tb/dut/P +add wave -unsigned /tb/dut/shiftResult +add wave -noupdate -divider -height 32 "FSM" +add wave -hex /tb/dut/fsm1/CURRENT_STATE +add wave -hex /tb/dut/fsm1/NEXT_STATE +add wave -hex -color #0080ff /tb/dut/fsm1/start +add wave -hex -color #0080ff /tb/dut/fsm1/state0 +add wave -hex -color #0080ff /tb/dut/fsm1/done +add wave -hex -color #0080ff /tb/dut/fsm1/en +add wave -hex -color #0080ff /tb/dut/fsm1/divdone +add wave -hex -color #0080ff /tb/dut/fsm1/reset +add wave -hex -color #0080ff /tb/dut/fsm1/otfzero +add wave -hex -color #0080ff /tb/dut/fsm1/LT +add wave -hex -color #0080ff /tb/dut/fsm1/EQ +add wave -hex -color gold /tb/dut/fsm1/clk +add wave -noupdate -divider -height 32 "Datapath" +add wave -hex /tb/dut/N +add wave -hex /tb/dut/D +add wave -hex /tb/dut/reset +add wave -hex /tb/dut/start +add wave -hex /tb/dut/Q +add wave -hex /tb/dut/rem0 +add wave -hex /tb/dut/div0 +add wave -hex /tb/dut/done +add wave -hex /tb/dut/divdone +add wave -hex /tb/dut/enable +add wave -hex /tb/dut/state0 +add wave -hex /tb/dut/V +add wave -hex /tb/dut/Num +add wave -hex /tb/dut/P +add wave -hex /tb/dut/NumIter +add wave -hex /tb/dut/RemShift +add wave -hex /tb/dut/op1 +add wave -hex /tb/dut/op2 +add wave -hex /tb/dut/op1shift +add wave -hex /tb/dut/Rem5 +add wave -hex /tb/dut/Qd +add wave -hex /tb/dut/Rd +add wave -hex /tb/dut/Qd2 +add wave -hex /tb/dut/Rd2 +add wave -hex /tb/dut/quotient +add wave -hex /tb/dut/otfzero +add wave -noupdate -divider -height 32 "Divider" +add wave -hex -r /tb/dut/p3/* + + +-- Set Wave Output Items +TreeUpdate [SetDefaultTree] +WaveRestoreZoom {0 ps} {75 ns} +configure wave -namecolwidth 150 +configure wave -valuecolwidth 100 +configure wave -justifyvalue left +configure wave -signalnamewidth 0 +configure wave -snapdistance 10 +configure wave -datasetprefix 0 +configure wave -rowmargin 4 +configure wave -childrowmargin 2 + +-- Run the Simulation +run 138ns + + diff --git a/wally-pipelined/src/muldiv/div/int64div.do b/wally-pipelined/src/muldiv/div/int64div.do new file mode 100755 index 000000000..0516f2108 --- /dev/null +++ b/wally-pipelined/src/muldiv/div/int64div.do @@ -0,0 +1,114 @@ +# Copyright 1991-2007 Mentor Graphics Corporation +# +# Modification by Oklahoma State University +# Use with Testbench +# James Stine, 2008 +# Go Cowboys!!!!!! +# +# All Rights Reserved. +# +# THIS WORK CONTAINS TRADE SECRET AND PROPRIETARY INFORMATION +# WHICH IS THE PROPERTY OF MENTOR GRAPHICS CORPORATION +# OR ITS LICENSORS AND IS SUBJECT TO LICENSE TERMS. + +# Use this run.do file to run this example. +# Either bring up ModelSim and type the following at the "ModelSim>" prompt: +# do run.do +# or, to run from a shell, type the following at the shell prompt: +# vsim -do run.do -c +# (omit the "-c" to see the GUI while running from the shell) + +onbreak {resume} + +# create library +if [file exists work] { + vdel -all +} +vlib work + +# compile source files +vlog muxs.sv shifters.sv divide4x64.sv test_int64div.sv + +# start and run simulation +vsim -voptargs=+acc work.tb + +view list +view wave + +-- display input and output signals as hexidecimal values +# Diplays All Signals recursively +add wave -noupdate -divider -height 32 "Control Signals" +add wave -hex -color gold /tb/clk +add wave -hex -color #0080ff /tb/reset +add wave -hex -color #0080ff /tb/start +add wave -hex -color #0080ff /tb/done +add wave -hex -color #0080ff /tb/divdone +add wave -noupdate -divider -height 32 "Key Parts" +add wave -unsigned /tb/dut/NumIter +add wave -unsigned /tb/dut/RemShift +add wave -unsigned /tb/dut/Qd2 +add wave -unsigned /tb/dut/Rd2 +add wave -unsigned /tb/dut/rem0 +add wave -unsigned /tb/dut/Q +add wave -unsigned /tb/dut/P +add wave -unsigned /tb/dut/shiftResult +add wave -noupdate -divider -height 32 "FSM" +add wave -hex /tb/dut/fsm1/CURRENT_STATE +add wave -hex /tb/dut/fsm1/NEXT_STATE +add wave -hex -color #0080ff /tb/dut/fsm1/start +add wave -hex -color #0080ff /tb/dut/fsm1/state0 +add wave -hex -color #0080ff /tb/dut/fsm1/done +add wave -hex -color #0080ff /tb/dut/fsm1/en +add wave -hex -color #0080ff /tb/dut/fsm1/divdone +add wave -hex -color #0080ff /tb/dut/fsm1/reset +add wave -hex -color #0080ff /tb/dut/fsm1/otfzero +add wave -hex -color #0080ff /tb/dut/fsm1/LT +add wave -hex -color #0080ff /tb/dut/fsm1/EQ +add wave -hex -color gold /tb/dut/fsm1/clk +add wave -noupdate -divider -height 32 "Datapath" +add wave -hex /tb/dut/N +add wave -hex /tb/dut/D +add wave -hex /tb/dut/reset +add wave -hex /tb/dut/start +add wave -hex /tb/dut/Q +add wave -hex /tb/dut/rem0 +add wave -hex /tb/dut/div0 +add wave -hex /tb/dut/done +add wave -hex /tb/dut/divdone +add wave -hex /tb/dut/enable +add wave -hex /tb/dut/state0 +add wave -hex /tb/dut/V +add wave -hex /tb/dut/Num +add wave -hex /tb/dut/P +add wave -hex /tb/dut/NumIter +add wave -hex /tb/dut/RemShift +add wave -hex /tb/dut/op1 +add wave -hex /tb/dut/op2 +add wave -hex /tb/dut/op1shift +add wave -hex /tb/dut/Rem5 +add wave -hex /tb/dut/Qd +add wave -hex /tb/dut/Rd +add wave -hex /tb/dut/Qd2 +add wave -hex /tb/dut/Rd2 +add wave -hex /tb/dut/quotient +add wave -hex /tb/dut/otfzero +add wave -noupdate -divider -height 32 "Divider" +add wave -hex -r /tb/dut/p3/* + + +-- Set Wave Output Items +TreeUpdate [SetDefaultTree] +WaveRestoreZoom {0 ps} {75 ns} +configure wave -namecolwidth 150 +configure wave -valuecolwidth 100 +configure wave -justifyvalue left +configure wave -signalnamewidth 0 +configure wave -snapdistance 10 +configure wave -datasetprefix 0 +configure wave -rowmargin 4 +configure wave -childrowmargin 2 + +-- Run the Simulation +run 138ns + + diff --git a/wally-pipelined/src/muldiv/div/iter32.do b/wally-pipelined/src/muldiv/div/iter32.do new file mode 100755 index 000000000..0472bd7db --- /dev/null +++ b/wally-pipelined/src/muldiv/div/iter32.do @@ -0,0 +1,50 @@ +# Copyright 1991-2007 Mentor Graphics Corporation +# +# Modification by Oklahoma State University +# Use with Testbench +# James Stine, 2008 +# Go Cowboys!!!!!! +# +# All Rights Reserved. +# +# THIS WORK CONTAINS TRADE SECRET AND PROPRIETARY INFORMATION +# WHICH IS THE PROPERTY OF MENTOR GRAPHICS CORPORATION +# OR ITS LICENSORS AND IS SUBJECT TO LICENSE TERMS. + +# Use this run.do file to run this example. +# Either bring up ModelSim and type the following at the "ModelSim>" prompt: +# do run.do +# or, to run from a shell, type the following at the shell prompt: +# vsim -do run.do -c +# (omit the "-c" to see the GUI while running from the shell) + +onbreak {resume} + +# create library +if [file exists work] { + vdel -all +} +vlib work + +# compile source files +vlog muxs.sv shifters.sv divide4x32.sv test_iter32.sv + +# start and run simulation +vsim -voptargs=+acc work.tb + + +-- Set Wave Output Items +TreeUpdate [SetDefaultTree] +WaveRestoreZoom {0 ps} {75 ns} +configure wave -namecolwidth 150 +configure wave -valuecolwidth 100 +configure wave -justifyvalue left +configure wave -signalnamewidth 0 +configure wave -snapdistance 10 +configure wave -datasetprefix 0 +configure wave -rowmargin 4 +configure wave -childrowmargin 2 + +-- Run the Simulation +run 9586700ns +quit diff --git a/wally-pipelined/src/muldiv/div/iter64.do b/wally-pipelined/src/muldiv/div/iter64.do new file mode 100755 index 000000000..0154d5f7c --- /dev/null +++ b/wally-pipelined/src/muldiv/div/iter64.do @@ -0,0 +1,50 @@ +# Copyright 1991-2007 Mentor Graphics Corporation +# +# Modification by Oklahoma State University +# Use with Testbench +# James Stine, 2008 +# Go Cowboys!!!!!! +# +# All Rights Reserved. +# +# THIS WORK CONTAINS TRADE SECRET AND PROPRIETARY INFORMATION +# WHICH IS THE PROPERTY OF MENTOR GRAPHICS CORPORATION +# OR ITS LICENSORS AND IS SUBJECT TO LICENSE TERMS. + +# Use this run.do file to run this example. +# Either bring up ModelSim and type the following at the "ModelSim>" prompt: +# do run.do +# or, to run from a shell, type the following at the shell prompt: +# vsim -do run.do -c +# (omit the "-c" to see the GUI while running from the shell) + +onbreak {resume} + +# create library +if [file exists work] { + vdel -all +} +vlib work + +# compile source files +vlog muxs.sv shifters.sv divide4x64.sv test_iter64.sv + +# start and run simulation +vsim -voptargs=+acc work.tb + + +-- Set Wave Output Items +TreeUpdate [SetDefaultTree] +WaveRestoreZoom {0 ps} {75 ns} +configure wave -namecolwidth 150 +configure wave -valuecolwidth 100 +configure wave -justifyvalue left +configure wave -signalnamewidth 0 +configure wave -snapdistance 10 +configure wave -datasetprefix 0 +configure wave -rowmargin 4 +configure wave -childrowmargin 2 + +-- Run the Simulation +run 9586700ns +quit diff --git a/wally-pipelined/src/muldiv/div/muxs.sv b/wally-pipelined/src/muldiv/div/muxs.sv new file mode 100644 index 000000000..d13045e6d --- /dev/null +++ b/wally-pipelined/src/muldiv/div/muxs.sv @@ -0,0 +1,51 @@ +module mux2 #(parameter WIDTH = 8) + (input logic [WIDTH-1:0] d0, d1, + input logic s, + output logic [WIDTH-1:0] y); + + assign y = s ? d1 : d0; + +endmodule // mux2 + +module mux3 #(parameter WIDTH = 8) + (input logic [WIDTH-1:0] d0, d1, d2, + input logic [1:0] s, + output logic [WIDTH-1:0] y); + + assign y = s[1] ? d2 : (s[0] ? d1 : d0); + +endmodule // mux3 + +module mux4 #(parameter WIDTH = 8) + (input logic [WIDTH-1:0] d0, d1, d2, d3, + input logic [1:0] s, + output logic [WIDTH-1:0] y); + + assign y = s[1] ? (s[0] ? d3 : d2) : (s[0] ? d1 : d0); + +endmodule // mux4 + +module mux21x32 (Z, A, B, Sel); + + input logic [31:0] A; + input logic [31:0] B; + input logic Sel; + + output logic [31:0] Z; + + assign Z = Sel ? B : A; + +endmodule // mux21x32 + +module mux21x64 (Z, A, B, Sel); + + input logic [63:0] A; + input logic [63:0] B; + input logic Sel; + + output logic [63:0] Z; + + assign Z = Sel ? B : A; + +endmodule // mux21x64 + diff --git a/wally-pipelined/src/muldiv/div/shifters.sv b/wally-pipelined/src/muldiv/div/shifters.sv new file mode 100644 index 000000000..85c4e5b68 --- /dev/null +++ b/wally-pipelined/src/muldiv/div/shifters.sv @@ -0,0 +1,106 @@ +module shifter_l64 (Z, A, Shift); + + input logic [63:0] A; + input logic [5:0] Shift; + + logic [63:0] stage1; + logic [63:0] stage2; + logic [63:0] stage3; + logic [63:0] stage4; + logic [63:0] stage5; + logic [31:0] thirtytwozeros = 32'h0; + logic [15:0] sixteenzeros = 16'h0; + logic [ 7:0] eightzeros = 8'h0; + logic [ 3:0] fourzeros = 4'h0; + logic [ 1:0] twozeros = 2'b00; + logic onezero = 1'b0; + + output logic [63:0] Z; + + mux21x64 mx01(stage1, A, {A[31:0], thirtytwozeros}, Shift[5]); + mux21x64 mx02(stage2, stage1, {stage1[47:0], sixteenzeros}, Shift[4]); + mux21x64 mx03(stage3, stage2, {stage2[55:0], eightzeros}, Shift[3]); + mux21x64 mx04(stage4, stage3, {stage3[59:0], fourzeros}, Shift[2]); + mux21x64 mx05(stage5, stage4, {stage4[61:0], twozeros}, Shift[1]); + mux21x64 mx06(Z, stage5, {stage5[62:0], onezero}, Shift[0]); + +endmodule // shifter_l64 + +module shifter_r64 (Z, A, Shift); + + input logic [63:0] A; + input logic [5:0] Shift; + + logic [63:0] stage1; + logic [63:0] stage2; + logic [63:0] stage3; + logic [63:0] stage4; + logic [63:0] stage5; + logic [31:0] thirtytwozeros = 32'h0; + logic [15:0] sixteenzeros = 16'h0; + logic [ 7:0] eightzeros = 8'h0; + logic [ 3:0] fourzeros = 4'h0; + logic [ 1:0] twozeros = 2'b00; + logic onezero = 1'b0; + + output logic [63:0] Z; + + mux21x64 mx01(stage1, A, {thirtytwozeros, A[63:32]}, Shift[5]); + mux21x64 mx02(stage2, stage1, {sixteenzeros, stage1[63:16]}, Shift[4]); + mux21x64 mx03(stage3, stage2, {eightzeros, stage2[63:8]}, Shift[3]); + mux21x64 mx04(stage4, stage3, {fourzeros, stage3[63:4]}, Shift[2]); + mux21x64 mx05(stage5, stage4, {twozeros, stage4[63:2]}, Shift[1]); + mux21x64 mx06(Z, stage5, {onezero, stage5[63:1]}, Shift[0]); + +endmodule // shifter_r64 + +module shifter_l32 (Z, A, Shift); + + input logic [31:0] A; + input logic [4:0] Shift; + + logic [31:0] stage1; + logic [31:0] stage2; + logic [31:0] stage3; + logic [31:0] stage4; + logic [15:0] sixteenzeros = 16'h0; + logic [ 7:0] eightzeros = 8'h0; + logic [ 3:0] fourzeros = 4'h0; + logic [ 1:0] twozeros = 2'b00; + logic onezero = 1'b0; + + output logic [31:0] Z; + + mux21x32 mx01(stage1, A, {A[15:0], sixteenzeros}, Shift[4]); + mux21x32 mx02(stage2, stage1, {stage1[23:0], eightzeros}, Shift[3]); + mux21x32 mx03(stage3, stage2, {stage2[27:0], fourzeros}, Shift[2]); + mux21x32 mx04(stage4, stage3, {stage3[29:0], twozeros}, Shift[1]); + mux21x32 mx05(Z , stage4, {stage4[30:0], onezero}, Shift[0]); + +endmodule // shifter_l32 + +module shifter_r32 (Z, A, Shift); + + input logic [31:0] A; + input logic [4:0] Shift; + + logic [31:0] stage1; + logic [31:0] stage2; + logic [31:0] stage3; + logic [31:0] stage4; + logic [15:0] sixteenzeros = 16'h0; + logic [ 7:0] eightzeros = 8'h0; + logic [ 3:0] fourzeros = 4'h0; + logic [ 1:0] twozeros = 2'b00; + logic onezero = 1'b0; + + output logic [31:0] Z; + + mux21x32 mx01(stage1, A, {sixteenzeros, A[31:16]}, Shift[4]); + mux21x32 mx02(stage2, stage1, {eightzeros, stage1[31:8]}, Shift[3]); + mux21x32 mx03(stage3, stage2, {fourzeros, stage2[31:4]}, Shift[2]); + mux21x32 mx04(stage4, stage3, {twozeros, stage3[31:2]}, Shift[1]); + mux21x32 mx05(Z , stage4, {onezero, stage4[31:1]}, Shift[0]); + +endmodule // shifter_r32 + diff --git a/wally-pipelined/src/muldiv/div/test_int32div.sv b/wally-pipelined/src/muldiv/div/test_int32div.sv new file mode 100755 index 000000000..c9260ecc8 --- /dev/null +++ b/wally-pipelined/src/muldiv/div/test_int32div.sv @@ -0,0 +1,50 @@ +module tb; + + logic [31:0] N, D; + logic clk; + logic reset; + logic start; + + logic [31:0] Q; + logic [31:0] rem; + logic div0; + logic done; + logic divdone; + + integer handle3; + integer desc3; + integer i; + + logic [7:0] count [0:15]; + + int32div dut (Q, done, divdone, rem, div0, N, D, clk, reset, start); + + initial + begin + clk = 1'b0; + forever #5 clk = ~clk; + end + + initial + begin + #800 $finish; + end + + + initial + begin + #0 N = 32'h0; + #0 D = 32'h0; + #0 start = 1'b0; + #0 reset = 1'b1; + #22 reset = 1'b0; + //#25 N = 32'h9830_07C0; + //#0 D = 32'h0000_000C; + #25 N = 32'h06b9_7b0d; + #0 D = 32'h46df_998d; + #0 start = 1'b1; + #50 start = 1'b0; + + end + +endmodule // tb diff --git a/wally-pipelined/src/muldiv/div/test_int64div.sv b/wally-pipelined/src/muldiv/div/test_int64div.sv new file mode 100644 index 000000000..ad415f0ff --- /dev/null +++ b/wally-pipelined/src/muldiv/div/test_int64div.sv @@ -0,0 +1,51 @@ +module tb; + + logic [63:0] N, D; + logic clk; + logic reset; + logic start; + + logic [63:0] Q; + logic [63:0] rem; + logic div0; + logic done; + logic divdone; + + integer handle3; + integer desc3; + integer i; + + logic [7:0] count [0:15]; + + int64div dut (Q, done, divdone, rem, div0, N, D, clk, reset, start); + + initial + begin + clk = 1'b0; + forever #5 clk = ~clk; + end + + initial + begin + #800 $finish; + end + + + initial + begin + #0 N = 64'h0; + #0 D = 64'h0; + #0 start = 1'b0; + #0 reset = 1'b1; + #22 reset = 1'b0; + //#25 N = 64'h0000_0000_9830_07C0; + //#0 D = 64'h0000_0000_0000_000C; + #25 N = 64'h0000_0000_06b9_7b0d; + #0 D = 64'h0000_0000_46df_998d; + #0 start = 1'b1; + #50 start = 1'b0; + + + end + +endmodule // tb diff --git a/wally-pipelined/src/muldiv/div/test_iter32.sv b/wally-pipelined/src/muldiv/div/test_iter32.sv new file mode 100755 index 000000000..94a42c211 --- /dev/null +++ b/wally-pipelined/src/muldiv/div/test_iter32.sv @@ -0,0 +1,74 @@ +module tb; + + logic [31:0] N, D; + logic clk; + logic reset; + logic start; + + logic [31:0] Q; + logic [31:0] rem0; + logic div0; + logic done; + logic divdone; + + integer handle3; + integer desc3; + integer i; + + bit [31:0] Ncomp; + bit [31:0] Dcomp; + bit [31:0] Qcomp; + bit [31:0] Rcomp; + + logic [7:0] count [0:15]; + + int32div dut (Q, done, divdone, rem0, div0, N, D, clk, reset, start); + + initial + begin + clk = 1'b0; + forever #5 clk = ~clk; + end + + initial + begin + handle3 = $fopen("iter32.out"); + #8000000 $finish; + end + + always @(posedge clk, posedge reset) + begin + desc3 = handle3; + #0 start = 1'b0; + #0 reset = 1'b1; + #30 reset = 1'b0; + for (i=0; i<2; i=i+1) + begin + N = $random; + D = $random; + start <= 1'b1; + // Wait 2 cycles (to be sure) + repeat (2) + @(posedge clk); + start <= 1'b0; + repeat (25) + @(posedge clk); + Ncomp = N; + Dcomp = D; + Qcomp = Ncomp/Dcomp; + Rcomp = Ncomp%Dcomp; + $fdisplay(desc3, "%h %h %h %h || %h %h || %b %b", + N, D, Q, rem0, Qcomp, Rcomp, + (Q==Qcomp), (rem0==Rcomp)); + end // for (i=0; i<2, i=i+1) + + + end + +endmodule // tb + + + + + + diff --git a/wally-pipelined/src/muldiv/div/test_iter64.sv b/wally-pipelined/src/muldiv/div/test_iter64.sv new file mode 100755 index 000000000..0674d8665 --- /dev/null +++ b/wally-pipelined/src/muldiv/div/test_iter64.sv @@ -0,0 +1,72 @@ +module tb; + + logic [63:0] N, D; + logic clk; + logic reset; + logic start; + + logic [63:0] Q; + logic [63:0] rem0; + logic div0; + logic done; + logic divdone; + + integer handle3; + integer desc3; + integer i; + + bit [63:0] Ncomp; + bit [63:0] Dcomp; + bit [63:0] Qcomp; + bit [63:0] Rcomp; + + logic [7:0] count [0:15]; + + int64div dut (Q, done, divdone, rem0, div0, N, D, clk, reset, start); + + initial + begin + clk = 1'b0; + forever #5 clk = ~clk; + end + + initial + begin + handle3 = $fopen("iter64.out"); + #8000000 $finish; + end + + always @(posedge clk, posedge reset) + begin + desc3 = handle3; + #0 start = 1'b0; + #0 reset = 1'b1; + #30 reset = 1'b0; + for (i=0; i<2; i=i+1) + begin + N = $random; + D = $random; + start <= 1'b1; + // Wait 2 cycles (to be sure) + repeat (2) + @(posedge clk); + start <= 1'b0; + repeat (41) + @(posedge clk); + Ncomp = N; + Dcomp = D; + Qcomp = Ncomp/Dcomp; + Rcomp = Ncomp%Dcomp; + $fdisplay(desc3, "%h %h %h %h || %h %h || %b %b", + N, D, Q, rem0, Qcomp, Rcomp, + (Q==Qcomp), (rem0==Rcomp)); + end // for (i=0; i<2, i=i+1) + end + +endmodule // tb + + + + + + diff --git a/wally-pipelined/src/muldiv/muldiv.sv b/wally-pipelined/src/muldiv/muldiv.sv new file mode 100644 index 000000000..40f980602 --- /dev/null +++ b/wally-pipelined/src/muldiv/muldiv.sv @@ -0,0 +1,76 @@ +/////////////////////////////////////////// +// muldiv.sv +// +// Written: David_Harris@hmc.edu 9 January 2021 +// Modified: +// +// Purpose: M extension multiply and divide +// +// A component of the Wally configurable RISC-V project. +// +// 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-config.vh" + +module muldiv ( + input logic clk, reset, + // Decode Stage interface + input logic [31:0] InstrD, + // Execute Stage interface + input logic [`XLEN-1:0] SrcAE, SrcBE, + input logic [2:0] Funct3E, + input logic MulDivE, W64E, + // Writeback stage + output logic [`XLEN-1:0] MulDivResultW, + // hazards + input logic FlushM, FlushW +); + + generate + if (`M_SUPPORTED) begin + logic [`XLEN-1:0] MulDivResultE, MulDivResultM; + logic [`XLEN-1:0] PrelimResultE; + logic [`XLEN-1:0] QuotE, RemE; + logic [`XLEN*2-1:0] ProdE; + + // Select result + always_comb + case (Funct3E) + 3'b000: PrelimResultE = ProdE[`XLEN-1:0]; + 3'b001: PrelimResultE = ProdE[`XLEN*2-1:`XLEN]; + 3'b010: PrelimResultE = ProdE[`XLEN*2-1:`XLEN]; + 3'b011: PrelimResultE = ProdE[`XLEN*2-1:`XLEN]; + 3'b100: PrelimResultE = QuotE; + 3'b101: PrelimResultE = QuotE; + 3'b110: PrelimResultE = RemE; + 3'b111: PrelimResultE = RemE; + endcase + + // Handle sign extension for W-type instructions + if (`XLEN == 64) begin // RV64 has W-type instructions + assign MulDivResultE = W64E ? {{32{PrelimResultE[31]}}, PrelimResultE[31:0]} : PrelimResultE; + end else begin // RV32 has no W-type instructions + assign MulDivResultE = PrelimResultE; + end + + floprc #(`XLEN) MulDivResultMReg(clk, reset, FlushM, MulDivResultE, MulDivResultM); + floprc #(`XLEN) MulDivResultWReg(clk, reset, FlushW, MulDivResultM, MulDivResultW); + end else begin // no M instructions supported + assign MulDivResultW = 0; + end + endgenerate +endmodule + diff --git a/wally-pipelined/src/tlb_toy/tlb_testbench.sv b/wally-pipelined/src/tlb_toy/tlb_testbench.sv new file mode 100644 index 000000000..add65d3db --- /dev/null +++ b/wally-pipelined/src/tlb_toy/tlb_testbench.sv @@ -0,0 +1,53 @@ +module testbench(); + logic clk, reset; + + // DUT inputs + logic [31:0] PCF; + logic [31:0] PageTableEntryF; + logic ITLBWriteF, ITLBFlushF; + + // DUT outputs + logic [31:0] PCPF; + logic ITLBMissF, ITLBHitF; + + // Testbench signals + logic [33:0] expected; + logic [31:0] vectornum, errors; + logic [99:0] testvectors[10000:0]; + + // instantiate device under test + tlb_toy dut(.*); + + // generate clock + always begin + clk=1; #5; clk=0; #5; + end + + // at start of test, load vectors and pulse reset + initial begin + $readmemb("tlb_toy.tv", testvectors); + vectornum = 0; errors = 0; reset = 1; #22; reset = 0; + end + + // apply test vectors on rising edge of clk + always @(posedge clk) begin + #1; {PCF, PageTableEntryF, ITLBWriteF, ITLBFlushF, expected} = testvectors[vectornum]; + end + + // check results on falling edge of clk + always @(negedge clk) + if (~reset) begin // skip during reset + if ({PCPF, ITLBMissF, ITLBHitF} !== expected) begin // check result + $display("Error: PCF = %b, write = %b, data = %b, flush = %b", PCF, + ITLBWriteF, PageTableEntryF, ITLBFlushF); + $display(" outputs = %b %b %b (%b expected)", + PCPF, ITLBMissF, ITLBHitF, expected); + errors = errors + 1; + end + vectornum = vectornum + 1; + if (testvectors[vectornum] === 100'bx) begin + $display("%d tests completed with %d errors", vectornum, errors); + $stop; + end + end +endmodule diff --git a/wally-pipelined/src/tlb_toy/tlb_toy.sv b/wally-pipelined/src/tlb_toy/tlb_toy.sv new file mode 100644 index 000000000..43c94babe --- /dev/null +++ b/wally-pipelined/src/tlb_toy/tlb_toy.sv @@ -0,0 +1,208 @@ +/////////////////////////////////////////// +// tlb_toy.sv +// +// Written: jtorrey@hmc.edu 16 February 2021 +// Modified: +// +// Purpose: Example translation lookaside buffer +// Cache of virtural-to-physical address translations +// +// A component of the Wally configurable RISC-V project. +// +// 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-config.vh" + +/** + * sv32 specs + * ---------- + * Virtual address [31:0] (32 bits) + * [________________________________] + * |--VPN1--||--VPN0--||----OFF---| + * 10 10 12 + * + * Physical address [33:0] (34 bits) + * [__________________________________] + * |---PPN1---||--PPN0--||----OFF---| + * 12 10 12 + * + * Page Table Entry [31:0] (32 bits) + * [________________________________] + * |---PPN1---||--PPN0--|||DAGUXWRV + * 12 10 ^^ + * RSW(2) -- for OS + */ + +/* *** TODO: + * - add LRU algorithm (select the write index based on which entry was used + * least recently) + * - rename signals to use .* notation in CAM and RAM + */ + +module tlb_toy ( + input clk, reset, + + // Virtual address input + input [31:0] PCF, + + // Controls for writing a new entry to the TLB + input [31:0] PageTableEntryF, + input ITLBWriteF, + + // Invalidate all TLB entries + input ITLBFlushF, + + // Physical address outputs + output [31:0] PCPF, + output ITLBMissF, + output ITLBHitF +); + // Index (currently random) to write the next TLB entry + logic [2:0] WriteIndexF; + + // Sections of the virtual and physical addresses + logic [19:0] VirtualPageNumberF; + logic [21:0] PhysicalPageNumberF; + logic [11:0] PageOffsetF; + logic [33:0] PhysicalAddressF; + + // Pattern and pattern location in the CAM + logic [2:0] VPNIndexF; + + // RAM access location + logic [2:0] ITLBEntryIndex; + + // Page table entry matching the virtual address + logic [31:0] PTEMatchF; + + assign VirtualPageNumberF = PCF[31:12]; + assign PageOffsetF = PCF[11:0]; + + // Choose a read or write location to the entry list + mux2 #(3) indexmux(VPNIndexF, WriteIndexF, ITLBWriteF, ITLBEntryIndex); + + // Currently use random replacement algorithm + rand3 rdm(clk, reset, WriteIndexF); + + ram8x32 ram(clk, reset, ITLBEntryIndex, PageTableEntryF, ITLBWriteF, PTEMatchF); + cam8x21 cam(clk, reset, ITLBWriteF, VirtualPageNumberF, WriteIndexF, + ITLBFlushF, VPNIndexF, ITLBHitF); + + always_comb begin + assign PhysicalPageNumberF = PTEMatchF[31:10]; + + if (ITLBHitF) begin + assign PhysicalAddressF = {PhysicalPageNumberF, PageOffsetF}; + end else begin + assign PhysicalAddressF = 34'b0; + end + end + + assign PCPF = PhysicalAddressF[31:0]; + assign ITLBMissF = ~ITLBHitF & ~(ITLBWriteF | ITLBFlushF); + +endmodule + +// *** Add parameter for number of tlb lines (currently 8) +module ram8x32 ( + input clk, reset, + input [2:0] address, + input [31:0] data, + input we, + + output [31:0] out_data +); + + logic [31:0] ram [0:7]; + always @(posedge clk) begin + if (we) ram[address] <= data; + end + + assign out_data = ram[address]; + + initial begin + for (int i = 0; i < 8; i++) + ram[i] = 32'h0; + end + +endmodule + +module cam8x21 ( + input clk, reset, we, + input [19:0] pattern, + input [2:0] write_address, + input ITLBFlushF, + output [2:0] matched_address, + output match_found +); + + logic [20:0] ram [0:7]; + logic [7:0] match_line; + + logic [2:0] matched_address_comb; + logic match_found_comb; + + always @(posedge clk) begin + if (we) ram[write_address] <= {1'b1,pattern}; + if (ITLBFlushF) begin + for (int i = 0; i < 8; i++) + ram[i][20] = 1'b0; + end + end + + // *** Check whether this for loop synthesizes correctly + always_comb begin + match_found_comb = 1'b0; + matched_address_comb = 3'b0; + for (int i = 0; i < 8; i++) begin + if (ram[i] == {1'b1,pattern} && !match_found_comb) begin + matched_address_comb = i; + match_found_comb = 1; + end else begin + matched_address_comb = matched_address_comb; + match_found_comb = match_found_comb; + end + end + end + + assign matched_address = matched_address_comb; + assign match_found = match_found_comb & ~(we | ITLBFlushF); + + initial begin + for (int i = 0; i < 8; i++) + ram[i] <= 0; + end + +endmodule + +module mux2 #(parameter WIDTH = 8) ( + input logic [WIDTH-1:0] d0, d1, + input logic s, + output logic [WIDTH-1:0] y); + + assign y = s ? d1 : d0; +endmodule + +module rand3 ( + input clk, reset, + output [2:0] WriteIndexF +); + + logic [31:0] data; + assign data = $urandom; + assign WriteIndexF = data[2:0]; + +endmodule diff --git a/wally-pipelined/src/tlb_toy/tlb_toy.tv b/wally-pipelined/src/tlb_toy/tlb_toy.tv new file mode 100644 index 000000000..329f3aacc --- /dev/null +++ b/wally-pipelined/src/tlb_toy/tlb_toy.tv @@ -0,0 +1,11 @@ +// tlb_toy.tv +// PCF _ PageTableEntryF _ ITLBWriteF _ ITLBFlushF ___ PCPF _ ITLBMissF _ ITLBHitF +10101010101010101010101010101010_00000000000000000000000000000000_0_0___00000000000000000000000000000000_1_0 +// Write test: Add translation aaaaa -> 044444 to TLB +10101010101010101010101010101010_00010001000100010001001100110010_1_0___00000000000000000000000000000000_0_0 +10101010101010101010101010101010_00000000000000000000000000000000_0_0___01000100010001000100101010101010_0_1 +10101010101010101010101010101010_00000000000000000000000000000000_0_0___01000100010001000100101010101010_0_1 +10101010100010101010101010101010_00000000000000000000000000000000_0_0___00000000000000000000000000000000_1_0 +// Flush test: should invalidate all entries +00000000000000000000000000000000_00000000000000000000000000000000_0_1___00000000000000000000000000000000_0_0 +10101010101010101010101010101010_00000000000000000000000000000000_0_0___00000000000000000000000000000000_1_0 diff --git a/wally-pipelined/src/uncore/uartPC16550D.sv b/wally-pipelined/src/uncore/uartPC16550D.sv index ec3e25227..445dca38c 100644 --- a/wally-pipelined/src/uncore/uartPC16550D.sv +++ b/wally-pipelined/src/uncore/uartPC16550D.sv @@ -76,7 +76,6 @@ module uartPC16550D( // shift registrs and FIFOs logic [9:0] rxshiftreg; - logic [11:0] txshiftreg; logic [10:0] rxfifo[15:0]; logic [7:0] txfifo[15:0]; logic [3:0] rxfifohead, rxfifotail, txfifohead, txfifotail, rxfifotriggerlevel; @@ -323,7 +322,7 @@ module uartPC16550D( txbitssent <= 0; end else if ((txstate == UART_IDLE) && txsrfull) begin // start transmitting txstate <= UART_ACTIVE; - txoversampledcnt <= 0; + txoversampledcnt <= 1; txbitssent <= 0; end else if (txbaudpulse & (txstate == UART_ACTIVE)) begin txoversampledcnt <= txoversampledcnt + 1; @@ -366,7 +365,7 @@ module uartPC16550D( // registers & FIFO always_ff @(posedge HCLK, negedge HRESETn) if (~HRESETn) begin - txfifohead <= 0; txfifotail <= 0; txhrfull <= 0; txsrfull <= 0; TXHR <= 0; txsr <= 0; + txfifohead <= 0; txfifotail <= 0; txhrfull <= 0; txsrfull <= 0; TXHR <= 0; txsr <= 12'hfff; end else begin if (~MEMWb && A == 3'b000 && ~DLAB) begin // writing transmit holding register or fifo if (fifoenabled) begin @@ -378,19 +377,19 @@ module uartPC16550D( end $display("UART transmits: %c",Din); // for testbench end - if (txstate == UART_IDLE) // move data into tx shift register if available - if (fifoenabled) + if (txstate == UART_IDLE) begin // move data into tx shift register if available + if (fifoenabled) begin if (~txfifoempty) begin txsr <= txdata; txfifotail <= txfifotail+1; txsrfull <= 1; end - else if (txhrfull) begin + end else if (txhrfull) begin txsr <= txdata; txhrfull <= 0; txsrfull <= 1; end - else if (txstate == UART_DONE) txsrfull <= 0; // done transmitting shift register + end else if (txstate == UART_DONE) txsrfull <= 0; // done transmitting shift register else if (txstate == UART_ACTIVE && txnextbit) txsr <= {txsr[10:0], 1'b1}; // shift txhr if (!MEMWb && A == 3'b010) // writes to FIFO control register if (Din[2] | ~Din[0]) begin // tx FIFO reste or FIFO disable clears FIFO contents diff --git a/wally-pipelined/src/uncore/uncore.sv b/wally-pipelined/src/uncore/uncore.sv index ada1eb93c..170e02c85 100644 --- a/wally-pipelined/src/uncore/uncore.sv +++ b/wally-pipelined/src/uncore/uncore.sv @@ -58,7 +58,7 @@ module uncore ( logic HSELTim, HSELCLINT, HSELGPIO, PreHSELUART, HSELUART; logic HRESPTim, HRESPCLINT, HRESPGPIO, HRESPUART; logic HREADYTim, HREADYCLINT, HREADYGPIO, HREADYUART; - logic MemRW; + logic [1:0] MemRW; logic [1:0] MemRWtim, MemRWclint, MemRWgpio, MemRWuart; logic UARTIntr;// *** will need to tie INTR to an interrupt handler diff --git a/wally-pipelined/src/wally/wallypipelinedhart.sv b/wally-pipelined/src/wally/wallypipelinedhart.sv index 408045e23..957336f1f 100644 --- a/wally-pipelined/src/wally/wallypipelinedhart.sv +++ b/wally-pipelined/src/wally/wallypipelinedhart.sv @@ -53,13 +53,16 @@ module wallypipelinedhart ( logic RetM, TrapM; // new signals that must connect through DP + logic MulDivE, W64E; logic CSRWriteM, PrivilegedM; + logic [`XLEN-1:0] SrcAE, SrcBE; logic [`XLEN-1:0] SrcAM; + logic [2:0] Funct3E; // logic [31:0] InstrF; logic [31:0] InstrD, InstrM; logic [`XLEN-1:0] PCE, PCM, PCLinkW; logic [`XLEN-1:0] PCTargetE; - logic [`XLEN-1:0] CSRReadValW; + logic [`XLEN-1:0] CSRReadValW, MulDivResultW; logic [`XLEN-1:0] PrivilegedNextPCM; logic [1:0] MemRWM; logic InstrValidW; @@ -73,7 +76,7 @@ module wallypipelinedhart ( logic PCSrcE; logic CSRWritePendingDEM; - logic LoadStallD; + logic LoadStallD, MulDivStallD; logic [4:0] SetFflagsM; logic [2:0] FRM_REGW; logic FloatRegWriteW; @@ -100,9 +103,9 @@ module wallypipelinedhart ( .*); //assign InstrF = ReadDataM[31:0]; -/* - mdu mdu(.*); // multiply and divide unit - fpu fpu(.*); // floating point unit + + muldiv mdu(.*); // multiply and divide unit + /* fpu fpu(.*); // floating point unit */ hazard hzu(.*); // global stall and flush control diff --git a/wally-pipelined/testbench/testbench-coremark.sv b/wally-pipelined/testbench/testbench-coremark.sv new file mode 100644 index 000000000..fe2dbf239 --- /dev/null +++ b/wally-pipelined/testbench/testbench-coremark.sv @@ -0,0 +1,47 @@ +`include "wally-config.vh" + +module testbench(); + logic clk; + logic reset; + + string memfilename; + + logic [`AHBW-1:0] HRDATAEXT; + logic HREADYEXT, HRESPEXT; + logic [31:0] HADDR; + logic [`AHBW-1:0] HWDATA; + logic HWRITE; + logic [2:0] HSIZE; + logic [2:0] HBURST; + logic [3:0] HPROT; + logic [1:0] HTRANS; + logic HMASTLOCK; + logic HCLK, HRESETn; + + logic [31:0] GPIOPinsIn, GPIOPinsOut, GPIOPinsEn; + logic UARTSin, UARTSout; + + // instantiate device to be tested + assign GPIOPinsIn = 0; + assign UARTSin = 1; + assign HREADYEXT = 1; + assign HRESPEXT = 0; + assign HRDATAEXT = 0; + + wallypipelinedsoc dut(.*); + + // initialize tests + initial + begin + memfilename = "../../imperas-riscv-tests/riscv-ovpsim-plus/examples/CoreMark/coremark.RV64I.bare.elf.memfile"; + $readmemh(memfilename, dut.imem.RAM); + $readmemh(memfilename, dut.uncore.dtim.RAM); + reset = 1; # 22; reset = 0; + end + + // generate clock to sequence tests + always + begin + clk = 1; # 5; clk = 0; # 5; + end +endmodule diff --git a/wally-pipelined/testbench/testbench-imperas.sv b/wally-pipelined/testbench/testbench-imperas.sv index 67a896445..ce36c0364 100644 --- a/wally-pipelined/testbench/testbench-imperas.sv +++ b/wally-pipelined/testbench/testbench-imperas.sv @@ -37,6 +37,21 @@ module testbench(); string InstrFName, InstrDName, InstrEName, InstrMName, InstrWName; logic [31:0] InstrW; logic [`XLEN-1:0] meminit; + string tests64m[] = '{ + "rv64m/I-MUL-01", "3000", + "rv64m/I-MULH-01", "3000", + "rv64m/I-MULHSU-01", "3000", + "rv64m/I-MULHU-01", "3000", + "rv64m/I-MULW-01", "3000" +// "rv64m/I-DIV-01", "3000", +// "rv64m/I-DIVU-01", "3000", + // "rv64m/I-DIVUW-01", "3000", + // "rv64m/I-DIVW-01", "3000", +// "rv64m/I-REM-01", "3000", +// "rv64m/I-REMU-01", "3000", +// "rv64m/I-REMUW-01", "3000", +// "rv64m/I-REMW-01", "3000" + }; string tests64ic[] = '{ "rv64ic/I-C-ADD-01", "3000", @@ -136,7 +151,51 @@ string tests64iNOc[] = { "rv64i/I-XOR-01", "3000", "rv64i/I-XORI-01", "3000", "rv64i/WALLY-ADD", "4000", - "rv64i/WALLY-SUB", "4000" + "rv64i/WALLY-SUB", "4000", + "rv64i/WALLY-ADDI", "3000", + "rv64i/WALLY-ANDI", "3000", + "rv64i/WALLY-ORI", "3000", + "rv64i/WALLY-XORI", "3000", + "rv64i/WALLY-SLTI", "3000", + "rv64i/WALLY-SLTIU", "3000", + "rv64i/WALLY-SLLI", "3000", + "rv64i/WALLY-SRLI", "3000", + "rv64i/WALLY-SRAI", "3000", + "rv64i/WALLY-LOAD", "11bf0", + "rv64i/WALLY-JAL", "4000", + "rv64i/WALLY-STORE", "3000", + "rv64i/WALLY-ADDIW", "3000", + "rv64i/WALLY-SLLIW", "3000", + "rv64i/WALLY-SRLIW", "3000", + "rv64i/WALLY-SRAIW", "3000", + "rv64i/WALLY-ADDW", "4000", + "rv64i/WALLY-SUBW", "4000", + "rv64i/WALLY-SLLW", "3000", + "rv64i/WALLY-SRLW", "3000", + "rv64i/WALLY-SRAW", "3000", + "rv64i/WALLY-BEQ" ,"5000", + "rv64i/WALLY-BNE", "5000 ", + "rv64i/WALLY-BLTU", "5000 ", + "rv64i/WALLY-BLT", "5000", + "rv64i/WALLY-BGE", "5000 ", + "rv64i/WALLY-BGEU", "5000 ", + "rv64i/WALLY-CSRRW", "4000", + "rv64i/WALLY-CSRRS", "4000", + "rv64i/WALLY-CSRRC", "5000", + "rv64i/WALLY-CSRRWI", "4000", + "rv64i/WALLY-CSRRSI", "4000", + "rv64i/WALLY-CSRRCI", "4000" + + }; + string tests32m[] = '{ + "rv32m/I-MUL-01", "2000", + "rv32m/I-MULH-01", "2000", + "rv32m/I-MULHSU-01", "2000", + "rv32m/I-MULHU-01", "2000" +// "rv32m/I-DIV-01", "2000", +// "rv32m/I-DIVU-01", "2000", +// "rv32m/I-REM-01", "2000", +// "rv32m/I-REMU-01", "2000" }; string tests32ic[] = '{ // "rv32ic/WALLY-C-ADHOC-01", "2000", @@ -217,10 +276,35 @@ string tests32i[] = { "rv32i/I-XOR-01","2000", "rv32i/I-XORI-01","2000", "rv32i/WALLY-ADD", "3000", - "rv32i/WALLY-SUB", "3000" + "rv32i/WALLY-SUB", "3000", + "rv32i/WALLY-ADDI", "2000", + "rv32i/WALLY-ANDI", "2000", + "rv32i/WALLY-ORI", "2000", + "rv32i/WALLY-XORI", "2000", + "rv32i/WALLY-SLTI", "2000", + "rv32i/WALLY-SLTIU", "2000", + "rv32i/WALLY-SLLI", "2000", + "rv32i/WALLY-SRLI", "2000", + "rv32i/WALLY-SRAI", "2000", + "rv32i/WALLY-LOAD", "11c00", + "rv32i/WALLY-SUB", "3000", + "rv32i/WALLY-STORE", "2000", + "rv32i/WALLY-JAL", "3000", + "rv32i/WALLY-BEQ" ,"4000", + "rv32i/WALLY-BNE", "4000 ", + "rv32i/WALLY-BLTU", "4000 ", + "rv32i/WALLY-BLT", "4000", + "rv32i/WALLY-BGE", "4000 ", + "rv32i/WALLY-BGEU", "4000 ", + "rv32i/WALLY-CSRRW", "3000", + "rv32i/WALLY-CSRRS", "3000", + "rv32i/WALLY-CSRRC", "4000", + "rv32i/WALLY-CSRRWI", "3000", + "rv32i/WALLY-CSRRSI", "3000", + "rv32i/WALLY-CSRRCI", "3000" + }; string tests[]; - logic [`AHBW-1:0] HRDATAEXT; logic HREADYEXT, HRESPEXT; logic [31:0] HADDR; @@ -240,10 +324,12 @@ string tests32i[] = { tests = {tests64i}; if (`C_SUPPORTED % 2 == 1) tests = {tests, tests64ic}; else tests = {tests, tests64iNOc}; + if (`M_SUPPORTED % 2 == 1) tests = {tests64m, tests}; end else begin // RV32 tests = {tests32i}; if (`C_SUPPORTED % 2 == 1) tests = {tests, tests32ic}; else tests = {tests, tests32iNOc}; + if (`M_SUPPORTED % 2 == 1) tests = {tests, tests32m}; end string signame, memfilename; @@ -432,10 +518,18 @@ module instrNameDecTB( else name = "ILLEGAL"; 10'b0111011_000: if (funct7 == 7'b0000000) name = "ADDW"; else if (funct7 == 7'b0100000) name = "SUBW"; + else if (funct7 == 7'b0000001) name = "MULW"; + else name = "ILLEGAL"; + 10'b0111011_001: if (funct7 == 7'b0000000) name = "SLLW"; + else if (funct7 == 7'b0000001) name = "DIVW"; else name = "ILLEGAL"; - 10'b0111011_001: name = "SLLW"; 10'b0111011_101: if (funct7 == 7'b0000000) name = "SRLW"; else if (funct7 == 7'b0100000) name = "SRAW"; + else if (funct7 == 7'b0000001) name = "DIVUW"; + else name = "ILLEGAL"; + 10'b0111011_110: if (funct7 == 7'b0000001) name = "REMW"; + else name = "ILLEGAL"; + 10'b0111011_111: if (funct7 == 7'b0000001) name = "REMUW"; else name = "ILLEGAL"; 10'b0110011_000: if (funct7 == 7'b0000000) name = "ADD"; else if (funct7 == 7'b0000001) name = "MUL"; @@ -448,10 +542,10 @@ module instrNameDecTB( else if (funct7 == 7'b0000001) name = "MULHSU"; else name = "ILLEGAL"; 10'b0110011_011: if (funct7 == 7'b0000000) name = "SLTU"; - else if (funct7 == 7'b0000001) name = "DIV"; + else if (funct7 == 7'b0000001) name = "MULHU"; else name = "ILLEGAL"; 10'b0110011_100: if (funct7 == 7'b0000000) name = "XOR"; - else if (funct7 == 7'b0000001) name = "MUL"; + else if (funct7 == 7'b0000001) name = "DIV"; else name = "ILLEGAL"; 10'b0110011_101: if (funct7 == 7'b0000000) name = "SRL"; else if (funct7 == 7'b0000001) name = "DIVU"; diff --git a/wally-pipelined/testbench/testbench-peripherals.sv b/wally-pipelined/testbench/testbench-peripherals.sv new file mode 100644 index 000000000..24180431d --- /dev/null +++ b/wally-pipelined/testbench/testbench-peripherals.sv @@ -0,0 +1,305 @@ +/////////////////////////////////////////// +// testbench-peripherals.sv +// +// Written: Ben Bracker (bbracker@hmc.edu) 11 Feb. 2021 +// Based on: testbench-imperas.sv by David Harris +// +// Purpose: Wally Testbench and helper modules +// Applies test programs meant to test peripherals +// These tests assume the processor itself is already working! +// +// A component of the Wally configurable RISC-V project. +// +// 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-config.vh" + +module testbench(); + logic clk; + logic reset; + + int test, i, errors, totalerrors; + logic [31:0] sig32[0:10000]; + logic [`XLEN-1:0] signature[0:10000]; + logic [`XLEN-1:0] testadr; + string InstrFName, InstrDName, InstrEName, InstrMName, InstrWName; + logic [31:0] InstrW; + logic [`XLEN-1:0] meminit; + + string tests[] = '{ + "peripherals/WALLY-UART", "2000" + }; + + logic [`AHBW-1:0] HRDATAEXT; + logic HREADYEXT, HRESPEXT; + logic [31:0] HADDR; + logic [`AHBW-1:0] HWDATA; + logic HWRITE; + logic [2:0] HSIZE; + logic [2:0] HBURST; + logic [3:0] HPROT; + logic [1:0] HTRANS; + logic HMASTLOCK; + logic HCLK, HRESETn; + + + // pick tests based on modes supported + // *** actually I no longer support this + // would need to put this back in if you wanted to test anything other than rv64i + + string signame, memfilename; + + logic [31:0] GPIOPinsIn, GPIOPinsOut, GPIOPinsEn; + logic UARTSin, UARTSout; + + // instantiate device to be tested + assign GPIOPinsIn = 0; + assign UARTSin = 1; + assign HREADYEXT = 1; + assign HRESPEXT = 0; + assign HRDATAEXT = 0; + + wallypipelinedsoc dut(.*); + + // Track names of instructions + instrTrackerTB it(clk, reset, dut.hart.ieu.dp.FlushE, + dut.hart.ifu.InstrD, dut.hart.ifu.InstrE, + dut.hart.ifu.InstrM, InstrW, + InstrDName, InstrEName, InstrMName, InstrWName); + + // initialize tests + initial + begin + test = 0; + totalerrors = 0; + testadr = 0; + // fill memory with defined values to reduce Xs in simulation + if (`XLEN == 32) meminit = 32'hFEDC0123; + else meminit = 64'hFEDCBA9876543210; + for (i=0; i<=65535; i = i+1) begin + //dut.imem.RAM[i] = meminit; + // dut.uncore.RAM[i] = meminit; + end + // read test vectors into memory + memfilename = {"../../imperas-riscv-tests/work/", tests[test], ".elf.memfile"}; + $readmemh(memfilename, dut.imem.RAM); + $readmemh(memfilename, dut.uncore.dtim.RAM); + reset = 1; # 22; reset = 0; + end + + // generate clock to sequence tests + always + begin + clk = 1; # 5; clk = 0; # 5; + end + + // check results + always @(negedge clk) + begin + if (dut.hart.priv.EcallFaultM && + (dut.hart.ieu.dp.regf.rf[3] == 1 || (dut.hart.ieu.dp.regf.we3 && dut.hart.ieu.dp.regf.a3 == 3 && dut.hart.ieu.dp.regf.wd3 == 1))) begin + $display("Code ended with ecall with gp = 1"); + #60; // give time for instructions in pipeline to finish + // clear signature to prevent contamination from previous tests + for(i=0; i<10000; i=i+1) begin + sig32[i] = 'bx; + end + + // read signature, reformat in 64 bits if necessary + signame = {"../../imperas-riscv-tests/work/", tests[test], ".signature.output"}; + $readmemh(signame, sig32); + i = 0; + while (i < 10000) begin + if (`XLEN == 32) begin + signature[i] = sig32[i]; + i = i+1; + end else begin + signature[i/2] = {sig32[i+1], sig32[i]}; + i = i + 2; + end + end + + // Check errors + i = 0; + errors = 0; + if (`XLEN == 32) + testadr = tests[test+1].atohex()/4; + else + testadr = tests[test+1].atohex()/8; + /* verilator lint_off INFINITELOOP */ + while (signature[i] !== 'bx) begin + //$display("signature[%h] = %h", i, signature[i]); + if (signature[i] !== dut.uncore.dtim.RAM[testadr+i]) begin + if (signature[i+4] !== 'bx || signature[i] !== 32'hFFFFFFFF) begin + // report errors unless they are garbage at the end of the sim + // kind of hacky test for garbage right now + errors = errors+1; + $display(" Error on test %s result %d: adr = %h sim = %h, signature = %h", + tests[test], i, (testadr+i)*`XLEN/8, dut.uncore.dtim.RAM[testadr+i], signature[i]); + end + end + i = i + 1; + end + /* verilator lint_on INFINITELOOP */ + if (errors == 0) $display("%s succeeded. Brilliant!!!", tests[test]); + else begin + $display("%s failed with %d errors. :(", tests[test], errors); + totalerrors = totalerrors+1; + end + test = test + 2; + if (test == tests.size()) begin + if (totalerrors == 0) $display("SUCCESS! All tests ran without failures."); + else $display("FAIL: %d test programs had errors", totalerrors); + $stop; + end + else begin + memfilename = {"../../imperas-riscv-tests/work/", tests[test], ".elf.memfile"}; + $readmemh(memfilename, dut.imem.RAM); + $readmemh(memfilename, dut.uncore.dtim.RAM); + $display("Read memfile %s", memfilename); + reset = 1; # 17; reset = 0; + end + end + end +endmodule + +/* verilator lint_on STMTDLY */ +/* verilator lint_on WIDTH */ + +module instrTrackerTB( + input logic clk, reset, FlushE, + input logic [31:0] InstrD, + input logic [31:0] InstrE, InstrM, + output logic [31:0] InstrW, + output string InstrDName, InstrEName, InstrMName, InstrWName); + + // stage Instr to Writeback for visualization + flopr #(32) InstrWReg(clk, reset, InstrM, InstrW); + + instrNameDecTB ddec(InstrD, InstrDName); + instrNameDecTB edec(InstrE, InstrEName); + instrNameDecTB mdec(InstrM, InstrMName); + instrNameDecTB wdec(InstrW, InstrWName); +endmodule + +// decode the instruction name, to help the test bench +module instrNameDecTB( + input logic [31:0] instr, + output string name); + + logic [6:0] op; + logic [2:0] funct3; + logic [6:0] funct7; + logic [11:0] imm; + + assign op = instr[6:0]; + assign funct3 = instr[14:12]; + assign funct7 = instr[31:25]; + assign imm = instr[31:20]; + + // it would be nice to add the operands to the name + // create another variable called decoded + + always_comb + casez({op, funct3}) + 10'b0000000_000: name = "BAD"; + 10'b0000011_000: name = "LB"; + 10'b0000011_001: name = "LH"; + 10'b0000011_010: name = "LW"; + 10'b0000011_011: name = "LD"; + 10'b0000011_100: name = "LBU"; + 10'b0000011_101: name = "LHU"; + 10'b0000011_110: name = "LWU"; + 10'b0010011_000: if (instr[31:15] == 0 && instr[11:7] ==0) name = "NOP/FLUSH"; + else name = "ADDI"; + 10'b0010011_001: if (funct7[6:1] == 6'b000000) name = "SLLI"; + else name = "ILLEGAL"; + 10'b0010011_010: name = "SLTI"; + 10'b0010011_011: name = "SLTIU"; + 10'b0010011_100: name = "XORI"; + 10'b0010011_101: if (funct7[6:1] == 6'b000000) name = "SRLI"; + else if (funct7[6:1] == 6'b010000) name = "SRAI"; + else name = "ILLEGAL"; + 10'b0010011_110: name = "ORI"; + 10'b0010011_111: name = "ANDI"; + 10'b0010111_???: name = "AUIPC"; + 10'b0100011_000: name = "SB"; + 10'b0100011_001: name = "SH"; + 10'b0100011_010: name = "SW"; + 10'b0100011_011: name = "SD"; + 10'b0011011_000: name = "ADDIW"; + 10'b0011011_001: name = "SLLIW"; + 10'b0011011_101: if (funct7 == 7'b0000000) name = "SRLIW"; + else if (funct7 == 7'b0100000) name = "SRAIW"; + else name = "ILLEGAL"; + 10'b0111011_000: if (funct7 == 7'b0000000) name = "ADDW"; + else if (funct7 == 7'b0100000) name = "SUBW"; + else name = "ILLEGAL"; + 10'b0111011_001: name = "SLLW"; + 10'b0111011_101: if (funct7 == 7'b0000000) name = "SRLW"; + else if (funct7 == 7'b0100000) name = "SRAW"; + else name = "ILLEGAL"; + 10'b0110011_000: if (funct7 == 7'b0000000) name = "ADD"; + else if (funct7 == 7'b0000001) name = "MUL"; + else if (funct7 == 7'b0100000) name = "SUB"; + else name = "ILLEGAL"; + 10'b0110011_001: if (funct7 == 7'b0000000) name = "SLL"; + else if (funct7 == 7'b0000001) name = "MULH"; + else name = "ILLEGAL"; + 10'b0110011_010: if (funct7 == 7'b0000000) name = "SLT"; + else if (funct7 == 7'b0000001) name = "MULHSU"; + else name = "ILLEGAL"; + 10'b0110011_011: if (funct7 == 7'b0000000) name = "SLTU"; + else if (funct7 == 7'b0000001) name = "DIV"; + else name = "ILLEGAL"; + 10'b0110011_100: if (funct7 == 7'b0000000) name = "XOR"; + else if (funct7 == 7'b0000001) name = "MUL"; + else name = "ILLEGAL"; + 10'b0110011_101: if (funct7 == 7'b0000000) name = "SRL"; + else if (funct7 == 7'b0000001) name = "DIVU"; + else if (funct7 == 7'b0100000) name = "SRA"; + else name = "ILLEGAL"; + 10'b0110011_110: if (funct7 == 7'b0000000) name = "OR"; + else if (funct7 == 7'b0000001) name = "REM"; + else name = "ILLEGAL"; + 10'b0110011_111: if (funct7 == 7'b0000000) name = "AND"; + else if (funct7 == 7'b0000001) name = "REMU"; + else name = "ILLEGAL"; + 10'b0110111_???: name = "LUI"; + 10'b1100011_000: name = "BEQ"; + 10'b1100011_001: name = "BNE"; + 10'b1100011_100: name = "BLT"; + 10'b1100011_101: name = "BGE"; + 10'b1100011_110: name = "BLTU"; + 10'b1100011_111: name = "BGEU"; + 10'b1100111_000: name = "JALR"; + 10'b1101111_???: name = "JAL"; + 10'b1110011_000: if (imm == 0) name = "ECALL"; + else if (imm == 1) name = "EBREAK"; + else if (imm == 2) name = "URET"; + else if (imm == 258) name = "SRET"; + else if (imm == 770) name = "MRET"; + else name = "ILLEGAL"; + 10'b1110011_001: name = "CSRRW"; + 10'b1110011_010: name = "CSRRS"; + 10'b1110011_011: name = "CSRRC"; + 10'b1110011_101: name = "CSRRWI"; + 10'b1110011_110: name = "CSRRSI"; + 10'b1110011_111: name = "CSRRCI"; + 10'b0001111_???: name = "FENCE"; + default: name = "ILLEGAL"; + endcase +endmodule diff --git a/wally-pipelined/testgen/testgen-ADD-SUB.py b/wally-pipelined/testgen/testgen-ADD-SUB-SLT-SLTU-XOR-OR-AND.py similarity index 82% rename from wally-pipelined/testgen/testgen-ADD-SUB.py rename to wally-pipelined/testgen/testgen-ADD-SUB-SLT-SLTU-XOR-OR-AND.py index 16e02be6b..9f795036b 100755 --- a/wally-pipelined/testgen/testgen-ADD-SUB.py +++ b/wally-pipelined/testgen/testgen-ADD-SUB-SLT-SLTU-XOR-OR-AND.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 ################################## -# testgen-ADD-SUB.py +# testgen-ADD-SUB-SLT-SLTU-XOR-OR-AND.py # # David_Harris@hmc.edu 19 January 2021 # @@ -19,11 +19,34 @@ from random import getrandbits # functions ################################## -def computeExpected(a, b, test): +def twoscomp(a): + amsb = a >> (xlen-1) + alsbs = ((1 << (xlen-1)) - 1) & a + if (amsb): + asigned = a - (1<> 32) + "\n" + r.write(line) + testnum = testnum+1 + +################################## +# main body +################################## + +# change these to suite your tests +tests = ["ADDI", "XORI", "ORI", "ANDI", "SLTI"] +author = "Shriya Nadgauda & Ethan Falicov" +xlens = [32, 64] +numrand = 100 + + +# setup +seed(0) # make tests reproducible + +# generate files for each test +for xlen in xlens: + formatstrlen = str(int(xlen/4)) + formatstr = "0x{:0" + formatstrlen + "x}" # format as xlen-bit hexadecimal number + formatrefstr = "{:08x}" # format as xlen-bit hexadecimal number with no leading 0x + + formatstrimm12 = "0x{:03x}" # format as 3-bit hexadecimal number + if (xlen == 32): + storecmd = "sw" + wordsize = 4 + else: + storecmd = "sd" + wordsize = 8 + + for test in tests: + corners1 = [0, 1, 2, 0xFF, 0x624B3E976C52DD14 % 2**xlen, 2**(xlen-1)-2, 2**(xlen-1)-1, + 2**(xlen-1), 2**(xlen-1)+1, 0xC365DDEB9173AB42 % 2**xlen, 2**(xlen)-2, 2**(xlen)-1] + + immBitSize = 12 + corners2 = [0, 1, 2, 0xFF, 0x624 % 2**immBitSize, 2**(immBitSize-1)-2, 2**(immBitSize-1)-1, + 2**(immBitSize-1), 2**(immBitSize-1)+1, 0xC36 % 2**immBitSize, 2**(immBitSize)-2, 2**(immBitSize)-1] + + imperaspath = "../../imperas-riscv-tests/riscv-test-suite/rv" + str(xlen) + "i/" + basename = "WALLY-" + test + fname = imperaspath + "src/" + basename + ".S" + refname = imperaspath + "references/" + basename + ".reference_output" + testnum = 0 + + # print custom header part + f = open(fname, "w") + r = open(refname, "w") + line = "///////////////////////////////////////////\n" + f.write(line) + lines="// "+fname+ "\n// " + author + "\n" + f.write(lines) + line ="// Created " + str(datetime.now()) + f.write(line) + + # insert generic header + h = open("testgen_header.S", "r") + for line in h: + f.write(line) + + # print directed and random test vectors + for a in corners1: + for b in corners2: + writeVector(a, b, storecmd) + for i in range(0,numrand): + a = getrandbits(xlen) + b = getrandbits(12) + writeVector(a, b, storecmd) + + + # print footer + h = open("testgen_footer.S", "r") + for line in h: + f.write(line) + + # Finish + lines = ".fill " + str(testnum) + ", " + str(wordsize) + ", -1\n" + lines = lines + "\nRV_COMPLIANCE_DATA_END\n" + f.write(lines) + f.close() + r.close() + + + diff --git a/wally-pipelined/testgen/testgen-ADDIW-SLLIW-SRLIW-SRAIW.py b/wally-pipelined/testgen/testgen-ADDIW-SLLIW-SRLIW-SRAIW.py new file mode 100755 index 000000000..57a2bad77 --- /dev/null +++ b/wally-pipelined/testgen/testgen-ADDIW-SLLIW-SRLIW-SRAIW.py @@ -0,0 +1,182 @@ +#!/usr/bin/python3 +################################## +# testgen-ADDIW-SLLIW-SRLIW-SRAIW.py +# +# ehedenberg@hmc.edu 4 February 2021 +# heavily influenced by Prof Harris Code +# +# Generate directed and random test vectors for RISC-V Design Validation. +################################## + +################################## +# libraries +################################## +from datetime import datetime +from random import randint +from random import seed +from random import getrandbits +import sys + +################################## +# functions +################################## +def logical_rshift(signed_integer, places): + unsigned_integer=signed_integer%(1<<32) + return unsigned_integer >> places + +def toSigned12bit(n): + n=n & 0xfff + if (n&(1<<11)): + n=n|0xfffffffffffff000 + return n + +def toSigned32bit(n): + n=n & 0xffffffff + if (n&(1<<31)): + n=n|0xffffffff00000000 + return n + + +def computeExpected(a, b, test): + if (test == "ADDIW"): + b=toSigned12bit(b) + return a + b + elif (test == "SLLIW"): + return (a << b) + elif (test == "SRLIW"): + return logical_rshift(a, b) + elif(test == "SRAIW"): + a= toSigned32bit(a) + return a >> b + else: + die("bad test name ", test) + # exit(1) + +def randRegs(): + reg1 = randint(1,31) + reg2 = randint(1,31) + reg3 = randint(1,31) + if (reg1 == 6 or reg2 == 6 or reg3 == 6 or reg1 == reg2): + return randRegs() + else: + return reg1, reg2, reg3 + +def writeVector(a, b, storecmd): + global testnum + expected = computeExpected(a, b, test) + expected = expected % 2**64 # drop carry if necessary + if (expected < 0): # take twos complement + expected = 2**64 + expected + #expected=expected+2^32<<32 + if (expected >= (2**32)): + expected=expected%(2**32) + expected=toSigned32bit(expected) + reg1, reg2, reg3 = randRegs() + lines = "\n# Testcase " + str(testnum) + ": rs1:x" + str(reg1) + "(" + formatstr.format(a) + lines = lines + "), imm:"+formatstr.format(b) + lines = lines + ", result rd:x" + str(reg3) + "(" + formatstr.format(expected) +")\n" + lines = lines + "li x" + str(reg1) + ", MASK_XLEN(" + formatstr.format(a) + ")\n" + #lines = lines + "li x" + str(reg2) + ", MASK_XLEN(" + formatstr.format(b) + ")\n" + lines = lines + test + " x" + str(reg3) + ", x" + str(reg1) + ", SEXT_IMM(" + formatstr.format(b) + ")\n" + lines = lines + storecmd + " x" + str(reg3) + ", " + str(wordsize*testnum) + "(x6)\n" + lines = lines + "RVTEST_IO_ASSERT_GPR_EQ(x7, x" + str(reg3) +", "+formatstr.format(expected)+")\n" + #lines = lines + str(b)+"\n" + f.write(lines) + if (xlen == 32): + line = formatrefstr.format(expected)+"\n" + else: + line = formatrefstr.format(expected % 2**32)+"\n" + formatrefstr.format(expected >> 32) + "\n" + r.write(line) + testnum = testnum+1 + +################################## +# main body +################################## + +# change these to suite your tests +tests = ["ADDIW", "SLLIW", "SRLIW", "SRAIW"] +author = "Eizabeth Hedenberg" +xlens = [64] +shiftlen=5 +addlen=12 +numrand = 100 + +# setup +seed(0) # make tests reproducible + +# generate files for each test +for xlen in xlens: + formatstrlen = str(int(xlen/4)) + #formatstrlen6=str(int()) + formatstr = "0x{:0" + formatstrlen + "x}" # format as xlen-bit hexadecimal number + #formatstr6 = "0x{:0" + "2" + "x}" # format as xlen-bit hexadecimal number + formatrefstr = "{:08x}" # format as xlen-bit hexadecimal number with no leading 0x + if (xlen == 32): + storecmd = "sw" + wordsize = 4 + else: + storecmd = "sd" + wordsize = 8 + for test in tests: + cornersa = [0, 1, 2, 0xFF, 0x624B3E976C52DD14 % 2**xlen, 2**(xlen-1)-2, 2**(xlen-1)-1, + 2**(xlen-1), 2**(xlen-1)+1, 0xC365DDEB9173AB42 % 2**xlen, 2**(xlen)-2, 2**(xlen)-1] + #test both confined to top 32 and not + cornersshift=[0, 1, 2, 2**(shiftlen)-1, 2**(shiftlen)-2, 0b00101, 0b01110] + #6 bits: 0, 1, 2, largest, largest -1, largest -2, 21, 46 + cornersadd=[0, 1, 2, 2**(addlen-1), 2**(addlen-1)-1, 2**(addlen-1)-2, 2**(addlen-1)+1, 2**(addlen)-2, 2**(addlen)-1, 0b001010010101, 0b101011101111] + #12 bit, 0, 1, 2 argest positive, largest -1, largest -2, largest negative number, -2, -1, random + imperaspath = "../../imperas-riscv-tests/riscv-test-suite/rv" + str(xlen) + "i/" + basename = "WALLY-" + test + fname = imperaspath + "src/" + basename + ".S" + refname = imperaspath + "references/" + basename + ".reference_output" + testnum = 0 + + # print custom header part + f = open(fname, "w") + r = open(refname, "w") + line = "///////////////////////////////////////////\n" + f.write(line) + lines="// "+fname+ "\n// " + author + "\n" + f.write(lines) + line ="// Created " + str(datetime.now()) + f.write(line) + + # insert generic header + h = open("testgen_header.S", "r") + for line in h: + f.write(line) + + # print directed and random test vectors + if test=="ADDIW": + for a in cornersa: + for b in cornersadd: + writeVector(a, b, storecmd) + for i in range(0,numrand): + a = getrandbits(xlen) + b = getrandbits(12) + writeVector(a, b, storecmd) + else: + for a in cornersa: + for b in cornersshift: + writeVector(a, b, storecmd) + for i in range(0,numrand): + a = getrandbits(xlen) + b = getrandbits(5) + writeVector(a, b, storecmd) + + + # print footer + h = open("testgen_footer.S", "r") + for line in h: + f.write(line) + + # Finish + lines = ".fill " + str(testnum) + ", " + str(wordsize) + ", -1\n" + lines = lines + "\nRV_COMPLIANCE_DATA_END\n" + f.write(lines) + f.close() + r.close() + + + + diff --git a/wally-pipelined/testgen/testgen-ADDW-SUBW-SLLW-SRLW-SRAW.py b/wally-pipelined/testgen/testgen-ADDW-SUBW-SLLW-SRLW-SRAW.py new file mode 100755 index 000000000..d95bc3fc4 --- /dev/null +++ b/wally-pipelined/testgen/testgen-ADDW-SUBW-SLLW-SRLW-SRAW.py @@ -0,0 +1,174 @@ +#!/usr/bin/python3 +################################## +# testgen-ADDW-SUBW-SLLW-SRLW-SRAW.py +# +# trao@g.hmc.edu 11 February 2021 +# Based on testgen-ADD-SUB.py by Prof. David Harris +# +# Generate directed and random test vectors for RISC-V Design Validation. +################################## + +################################## +# libraries +################################## +from datetime import datetime +from random import randint +from random import seed +from random import getrandbits +import sys + +################################## +# functions +################################## +def logical_rshift(signed_integer, places): + unsigned_integer=signed_integer%(1<<32) + return unsigned_integer >> places + +def toSigned12bit(n): + n=n & 0xfff + if (n&(1<<11)): + n=n|0xfffffffffffff000 + return n + +def toSigned32bit(n): + n=n & 0xffffffff + if (n&(1<<31)): + n=n|0xffffffff00000000 + return n + + +def computeExpected(a, b, test): + if (test == "ADDW"): + return toSigned32bit(a + b) + elif (test == "SUBW"): + return toSigned32bit(a - b) + elif (test == "SLLW"): + b = b & 0x1F + return toSigned32bit(a << b) + elif (test == "SRLW"): + b = b & 0x1F + return toSigned32bit(logical_rshift(a, b)) + elif(test == "SRAW"): + a= toSigned32bit(a) + b = b & 0x1F + return toSigned32bit(a >> b) + else: + die("bad test name ", test) + # exit(1) + +def randRegs(): + reg1 = randint(1,31) + reg2 = randint(1,31) + reg3 = randint(1,31) + if (reg1 == 6 or reg2 == 6 or reg3 == 6 or reg1 == reg2): + return randRegs() + else: + return reg1, reg2, reg3 + +def writeVector(a, b, storecmd): + global testnum + expected = computeExpected(a, b, test) + expected = expected % 2**xlen # drop carry if necessary + if (expected < 0): # take twos complement + expected = 2**xlen + expected + reg1, reg2, reg3 = randRegs() + lines = "\n# Testcase " + str(testnum) + ": rs1:x" + str(reg1) + "(" + formatstr.format(a) + lines = lines + "), rs2:x" + str(reg2) + "(" +formatstr.format(b) + lines = lines + "), result rd:x" + str(reg3) + "(" + formatstr.format(expected) +")\n" + lines = lines + "li x" + str(reg1) + ", MASK_XLEN(" + formatstr.format(a) + ")\n" + lines = lines + "li x" + str(reg2) + ", MASK_XLEN(" + formatstr.format(b) + ")\n" + lines = lines + test + " x" + str(reg3) + ", x" + str(reg1) + ", x" + str(reg2) + "\n" + lines = lines + storecmd + " x" + str(reg3) + ", " + str(wordsize*testnum) + "(x6)\n" + lines = lines + "RVTEST_IO_ASSERT_GPR_EQ(x7, " + str(reg3) +", "+formatstr.format(expected)+")\n" + f.write(lines) + line = formatrefstr.format(expected % 2**32)+"\n" + formatrefstr.format(expected >> 32) + "\n" + r.write(line) + testnum = testnum+1 + +################################## +# main body +################################## + +# change these to suite your tests +tests = ["ADDW", "SUBW", "SLLW", "SRLW", "SRAW"] +author = "Tejus Rao" +xlens = [64] +shiftlen=5 +addlen=32 +numrand = 100 + +# setup +seed(0) # make tests reproducible + +# generate files for each test +for xlen in xlens: + formatstrlen = str(int(xlen/4)) + #formatstrlen6=str(int()) + formatstr = "0x{:0" + formatstrlen + "x}" # format as xlen-bit hexadecimal number + #formatstr6 = "0x{:0" + "2" + "x}" # format as xlen-bit hexadecimal number + formatrefstr = "{:08x}" # format as xlen-bit hexadecimal number with no leading 0x + storecmd = "sd" + wordsize = 8 + for test in tests: + cornersa = [0, 1, 2, 0xFF, 0x624B3E976C52DD14 % 2**xlen, 2**(xlen-1)-2, 2**(xlen-1)-1, + 2**(xlen-1), 2**(xlen-1)+1, 0xC365DDEB9173AB42 % 2**xlen, 2**(xlen)-2, 2**(xlen)-1] + #test both confined to top 32 and not + cornersshift=[0, 1, 2, 2**(shiftlen)-1, 2**(shiftlen)-2, 0b00101, 0b01110] + #6 bits: 0, 1, 2, largest, largest -1, largest -2, 21, 46 + cornersadd=[0, 1, 2, 2**(addlen-1), 2**(addlen-1)-1, 2**(addlen-1)-2, 2**(addlen-1)+1, 2**(addlen)-2, 2**(addlen)-1, 0b001010010101, 0b101011101111] + #12 bit, 0, 1, 2 argest positive, largest -1, largest -2, largest negative number, -2, -1, random + imperaspath = "../../imperas-riscv-tests/riscv-test-suite/rv" + str(xlen) + "i/" + basename = "WALLY-" + test + fname = imperaspath + "src/" + basename + ".S" + refname = imperaspath + "references/" + basename + ".reference_output" + testnum = 0 + + # print custom header part + f = open(fname, "w") + r = open(refname, "w") + line = "///////////////////////////////////////////\n" + f.write(line) + lines="// "+fname+ "\n// " + author + "\n" + f.write(lines) + line ="// Created " + str(datetime.now()) + f.write(line) + + # insert generic header + h = open("testgen_header.S", "r") + for line in h: + f.write(line) + + # print directed and random test vectors + if test=="ADDW" or test == "SUBW": + for a in cornersa: + for b in cornersadd: + writeVector(a, b, storecmd) + for i in range(0,numrand): + a = getrandbits(xlen) + b = getrandbits(xlen) + writeVector(a, b, storecmd) + else: + for a in cornersa: + for b in cornersshift: + writeVector(a, b, storecmd) + for i in range(0,numrand): + a = getrandbits(xlen) + b = getrandbits(5) + writeVector(a, b, storecmd) + + + # print footer + h = open("testgen_footer.S", "r") + for line in h: + f.write(line) + + # Finish + lines = ".fill " + str(testnum) + ", " + str(wordsize) + ", -1\n" + lines = lines + "\nRV_COMPLIANCE_DATA_END\n" + f.write(lines) + f.close() + r.close() + + + + diff --git a/wally-pipelined/testgen/testgen-BRANCH.py b/wally-pipelined/testgen/testgen-BRANCH.py new file mode 100755 index 000000000..04a9caa80 --- /dev/null +++ b/wally-pipelined/testgen/testgen-BRANCH.py @@ -0,0 +1,155 @@ +#!/usr/bin/python3 +################################## +# testgen-branch.py +# +# ssanghai@hmc.edu 13th Feb 2021 +# +# Generate directed and random test vectors for RISC-V Design Validation. +################################## + +################################## +# libraries +################################## +from datetime import datetime +from random import randint +from random import seed +from random import getrandbits + +################################## +# functions +################################## +def computeExpected(a, b, test): + if (test == "BEQ"): + return 0xcccc if a==b else 0xeeee + elif (test == "BNE"): + return 0xeeee if a==b else 0xcccc + elif (test == "BGEU"): + return 0xcccc if a>=b else 0xeeee + elif (test == "BLT"): + if (1<<(xlen-1)) & a: + a = a -(2**xlen) + if (1<<(xlen-1)) & b: + b = b - (2**xlen) + return 0xcccc if a=b else 0xeeee + else: + die("bad test name ", test) + # exit(1) + +def randRegs(): + reg1 = randint(2,31) + reg2 = randint(2,31) + if (reg1 == 6 or reg2 == 6 or reg1 == reg2): + return randRegs() + else: + return reg1, reg2 + +label = 0 + +def writeVector(a, b, storecmd): + global testnum + global label + expected = computeExpected(a, b, test) + expected = expected % 2**xlen # drop carry if necessary + if (expected < 0): # take twos complement + expected = 2**xlen + expected + reg1, reg2 = randRegs() + lines = "\n# Testcase " + str(testnum) + ": rs1:x" + str(reg1) + "(" + formatstr.format(a) + lines = lines + "), rs2:x" + str(reg2) + "(" +formatstr.format(b) + "\n" + lines = lines + "li x1, MASK_XLEN(0xcccc)\n" + lines = lines + "li x" + str(reg1) + ", MASK_XLEN(" + formatstr.format(a) + ")\n" + lines = lines + "li x" + str(reg2) + ", MASK_XLEN(" + formatstr.format(b) + ")\n" + lines = lines + test + " x" + str(reg1) + ", x" + str(reg2) + ", " + str(label) + "f\n" + lines = lines + "li x1, MASK_XLEN(0xeeee)\n" + lines = lines + str(label) + ":\n" + lines = lines + storecmd + " x1, " + str(wordsize*testnum) + "(x6)\n" + lines = lines + "RVTEST_IO_ASSERT_GPR_EQ(x7, x1, "+formatstr.format(expected)+")\n" + f.write(lines) + if (xlen == 32): + line = formatrefstr.format(expected)+"\n" + else: + line = formatrefstr.format(expected % 2**32)+"\n" + formatrefstr.format(expected >> 32) + "\n" + r.write(line) + label += 1 + testnum = testnum+1 + +################################## +# main body +################################## + +# change these to suite your tests +tests = ["BEQ", "BNE", "BLT", "BGE", "BGEU", "BLTU"] +author = "Shreya Sanghai" +xlens = [32, 64] +numrand = 100 + +# setup +seed(0) # make tests reproducible + +# generate files for each test +for xlen in xlens: + formatstrlen = str(int(xlen/4)) + formatstr = "0x{:0" + formatstrlen + "x}" # format as xlen-bit hexadecimal number + formatrefstr = "{:08x}" # format as xlen-bit hexadecimal number with no leading 0x + if (xlen == 32): + storecmd = "sw" + wordsize = 4 + else: + storecmd = "sd" + wordsize = 8 + for test in tests: + corners = [0, 1, 2, 0xFF, 0x624B3E976C52DD14 % 2**xlen, 2**(xlen-1)-2, 2**(xlen-1)-1, + 2**(xlen-1), 2**(xlen-1)+1, 0xC365DDEB9173AB42 % 2**xlen, 2**(xlen)-2, 2**(xlen)-1] + imperaspath = "../../imperas-riscv-tests/riscv-test-suite/rv" + str(xlen) + "i/" + basename = "WALLY-" + test + fname = imperaspath + "src/" + basename + ".S" + refname = imperaspath + "references/" + basename + ".reference_output" + testnum = 0 + + # print custom header part + f = open(fname, "w") + r = open(refname, "w") + line = "///////////////////////////////////////////\n" + f.write(line) + lines="// "+fname+ "\n// " + author + "\n" + f.write(lines) + line ="// Created " + str(datetime.now()) + f.write(line) + + # insert generic header + h = open("testgen_header.S", "r") + for line in h: + f.write(line) + + # print directed and random test vectors + for a in corners: + for b in corners: + writeVector(a, b, storecmd) + for i in range(0,numrand): + a = getrandbits(xlen) + b = getrandbits(xlen) + writeVector(a, b, storecmd) + + + # print footer + h = open("testgen_footer.S", "r") + for line in h: + f.write(line) + + # Finish + lines = ".fill " + str(testnum) + ", " + str(wordsize) + ", -1\n" + lines = lines + "\nRV_COMPLIANCE_DATA_END\n" + f.write(lines) + f.close() + r.close() + + + + diff --git a/wally-pipelined/testgen/testgen-CSR.py b/wally-pipelined/testgen/testgen-CSR.py new file mode 100644 index 000000000..0b694cd39 --- /dev/null +++ b/wally-pipelined/testgen/testgen-CSR.py @@ -0,0 +1,194 @@ +#!/usr/bin/python3 +################################## +# testgen-ADD-SUB.py +# +# ushakya@hmc.edu & dottolia@hmc.edu 14 Feb 2021 +# +# Generate directed and random test vectors for RISC-V Design Validation. +################################## + +################################## +# libraries +################################## +from datetime import datetime +from random import randint +from random import seed +from random import getrandbits + +################################## +# functions +################################## + +# def computeExpected(a, b, test): +# if (test == "ADD"): +# return a + b +# elif (test == "SUB"): +# return a - b +# else: +# die("bad test name ", test) +# # exit(1) + +def randRegs(): + reg1 = randint(1,31) + reg2 = randint(1,31) + reg3 = randint(1,31) + if (reg1 == 6 or reg2 == 6 or reg3 == 6 or reg1 == reg2): + return randRegs() + else: + return reg1, reg2, reg3 + +def writeVector(a, b, storecmd): + global testnum + #expected = computeExpected(a, b, test) + #expected = expected % 2**xlen # drop carry if necessary + #if (expected < 0): # take twos complement + # expected = 2**xlen + expected + csr = "mscratch" + + reg1, reg2, reg3 = randRegs() + lines = "\n# Testcase " + str(testnum) + ": " + csr + "\n" + lines = lines + "li x" + str(reg1) + ", MASK_XLEN(" + formatstr.format(a) + ")\n" + lines = lines + "li x" + str(reg2) + ", MASK_XLEN(0)\n" + + # Page 6 of unpriviledged spec + # For both CSRRS and CSRRC, if rs1=x0, then the instruction will not write to the CSR at all, and so shall not cause any of the side effects + + expected = a + + if test == "csrrw": + lines += test + " x" + str(reg2) + ", " + csr + ", x" + str(reg1) + "\n" + lines += test + " x" + str(reg2) + ", " + csr + ", x" + str(reg1) + "\n" + + elif test == "csrrs": # at some point, try writing a non-zero value first + lines += "csrrw x0, " + csr + ", x0\n" # set csr to 0 + + lines += test + " x" + str(reg2) + ", " + csr + ", x" + str(reg1) + "\n" + lines += test + " x" + str(reg2) + ", " + csr + ", x" + str(reg1) + "\n" + elif test == "csrrc": # at some point, try writing a non-one value first + allOnes = "0xFFFFFFFF" if xlen == 32 else "0xFFFFFFFFFFFFFFFF" + + lines += "li x" + str(reg1) + ", MASK_XLEN(" + allOnes + ")\n" + lines += "csrrw x0, " + csr + ", x" + str(reg1) + "\n" # set csr to all ones + + lines += "li x" + str(reg1) + ", MASK_XLEN(" + formatstr.format(a) + ")\n" + + lines += test + " x" + str(reg2) + ", " + csr + ", x" + str(reg1) + "\n" + lines += test + " x" + str(reg2) + ", " + csr + ", x" + str(reg1) + "\n" + + expected = a ^ 0xFFFFFFFF if xlen == 32 else a ^ 0xFFFFFFFFFFFFFFFF + elif test == "csrrwi": + a = a & 0x1F # imm is only 5 bits + + lines += test + " x" + str(reg2) + ", " + csr + ", " + str(a) + "\n" + lines += test + " x" + str(reg2) + ", " + csr + ", " + str(a) + "\n" + + expected = a + elif test == "csrrsi": # at some point, try writing a non-zero value first + a = a & 0x1F + + lines += "csrrw x0, " + csr + ", x0\n" # set csr to 0 + + lines += test + " x" + str(reg2) + ", " + csr + ", " + str(a) + "\n" + lines += test + " x" + str(reg2) + ", " + csr + ", " + str(a) + "\n" + + expected = a + elif test == "csrrci": # at some point, try writing a non-one value first + a = a & 0x1F + allOnes = "0xFFFFFFFF" if xlen == 32 else "0xFFFFFFFFFFFFFFFF" + + lines += "li x" + str(reg1) + ", MASK_XLEN(" + allOnes + ")\n" + lines += "csrrw x0, " + csr + ", x" + str(reg1) + "\n" # set csr to all ones + + lines += test + " x" + str(reg2) + ", " + csr + ", " + str(a) + "\n" + lines += test + " x" + str(reg2) + ", " + csr + ", " + str(a) + "\n" + + expected = a ^ 0xFFFFFFFF if xlen == 32 else a ^ 0xFFFFFFFFFFFFFFFF + + + lines += storecmd + " x" + str(reg2) + ", " + str(wordsize*testnum) + "(x6)\n" + lines += "RVTEST_IO_ASSERT_GPR_EQ(x7, " + str(reg2) +", "+formatstr.format(expected)+")\n" + f.write(lines) + if (xlen == 32): + line = formatrefstr.format(expected)+"\n" + else: + line = formatrefstr.format(expected % 2**32)+"\n" + formatrefstr.format(expected >> 32) + "\n" + r.write(line) + testnum = testnum+1 + +################################## +# main body +################################## + +# change these to suite your tests +# csrrw, csrrs, csrrc, csrrwi, csrrsi, csrrci +tests = ["csrrw", "csrrs", "csrrc", "csrrwi", "csrrsi", "csrrci"] +author = "ushakya@hmc.edu & dottolia@hmc.edu" +xlens = [32, 64] +numrand = 60; + +# setup +seed(0xC365DDEB9173AB42) # make tests reproducible + +# generate files for each test +for xlen in xlens: + formatstrlen = str(int(xlen/4)) + formatstr = "0x{:0" + formatstrlen + "x}" # format as xlen-bit hexadecimal number + formatrefstr = "{:08x}" # format as xlen-bit hexadecimal number with no leading 0x + if (xlen == 32): + storecmd = "sw" + wordsize = 4 + else: + storecmd = "sd" + wordsize = 8 + for test in tests: + corners = [ + 0, 1, 2, 0x1E, 0x1F, 0xFF, + 0x624B3E976C52DD14 % 2**xlen, 2**(xlen-1)-2, 2**(xlen-1)-1, + 2**(xlen-1), 2**(xlen-1)+1, 0xC365DDEB9173AB42 % 2**xlen, 2**(xlen)-2, 2**(xlen)-1 + ] + imperaspath = "../../imperas-riscv-tests/riscv-test-suite/rv" + str(xlen) + "i/" + basename = "WALLY-" + test.upper() + fname = imperaspath + "src/" + basename + ".S" + refname = imperaspath + "references/" + basename + ".reference_output" + testnum = 0 + + # print custom header part + f = open(fname, "w") + r = open(refname, "w") + line = "///////////////////////////////////////////\n" + f.write(line) + lines="// "+fname+ "\n// " + author + "\n" + f.write(lines) + line ="// Created " + str(datetime.now()) + f.write(line) + + # insert generic header + h = open("testgen_header.S", "r") + for line in h: + f.write(line) + + # print directed and random test vectors + for a in corners: + for b in corners: + writeVector(a, b, storecmd) + for i in range(0,numrand): + a = getrandbits(xlen) + b = getrandbits(xlen) + writeVector(a, b, storecmd) + + + # print footer + h = open("testgen_footer.S", "r") + for line in h: + f.write(line) + + # Finish + lines = ".fill " + str(testnum) + ", " + str(wordsize) + ", -1\n" + lines = lines + "\nRV_COMPLIANCE_DATA_END\n" + f.write(lines) + f.close() + r.close() + + + + diff --git a/wally-pipelined/testgen/testgen-JAL.py b/wally-pipelined/testgen/testgen-JAL.py new file mode 100755 index 000000000..09f58a566 --- /dev/null +++ b/wally-pipelined/testgen/testgen-JAL.py @@ -0,0 +1,260 @@ +#!/usr/bin/python3 +################################## +# testgen-JAL.py +# +# Ben Bracker (bbracker@hmc.edu) 19 January 2021 +# Based on testgen-ADD-SUB.py by David Harris +# +# Generate directed and random test vectors for RISC-V Design Validation. +################################## + +################################## +# libraries +################################## +from datetime import datetime +from random import randint +from random import choice +from random import seed +from random import getrandbits +from copy import deepcopy + +################################## +# functions +################################## + +def InitTestGroup(): + global TestGroup,TestGroupSizes,AllRegs,UnusedRegs,StoreAdrReg + TestGroup += 1 + TestGroupSizes.append(0) + UnusedRegs = deepcopy(AllRegs) + oldStoreAdrReg = StoreAdrReg + while ((StoreAdrReg == oldStoreAdrReg) or (StoreAdrReg == 0) or (StoreAdrReg == 31)): + StoreAdrReg = choice(UnusedRegs) + UnusedRegs.remove(StoreAdrReg) + f.write("\n # ---------------------------------------------------------------------------------------------\n") + f.write(" # new register for address of test results\n") + addInst(" la x"+str(StoreAdrReg)+", test_1_res\n") + f.write(" # ---------------------------------------------------------------------------------------------\n") + +def registerSelect(): + # ensures that rd experiences all possible registers + # *** does not yet ensure that rs experiences all possible registers + # ensures that at least once rd = rs + global UnusedRegs + if len(UnusedRegs)==0: + InitTestGroup() + rd = choice(UnusedRegs) + rs = choice(UnusedRegs) + UnusedRegs.remove(rd) + OtherRegs = deepcopy(AllRegs) + OtherRegs.remove(StoreAdrReg) + OtherRegs.remove(rd) + try: + OtherRegs.remove(0) + except: + pass + try: + OtherRegs.remove(rs) + except: + pass + DataReg = choice(OtherRegs) + OtherRegs.remove(DataReg) + OtherRd = choice(OtherRegs) + return (rd,rs,DataReg,OtherRd) + +def addInst(line): + global CurrAdr + f.write(line) + if ("li x" in line): + CurrAdr += 8 if (xlen == 32) else 20 + elif ("la x" in line): + CurrAdr += 8 + else: + CurrAdr += 4 + +def writeForwardsJumpVector(spacers): + global TestNum + rd, rs, DataReg, OtherRd = registerSelect() + if (xlen==64): + expected = int("fedbca9876540000",16) + unexpected = int("ffff0000ffff0000",16) + else: + expected = int("fedbca98",16) + unexpected = int("ff00ff00",16) + + + f.write("\n") + f.write(" # Testcase "+str(TestNum)+" address cmp result rd:x"+str(rd)+"("+formatstr.format(CurrAdr+44)+") data result rd:x"+str(DataReg)+"("+formatstr.format(expected)+")\n") + addInst(" li x"+str(DataReg)+", "+formatstr.format(expected)+"\n") + addInst(" JAL x"+str(rd)+", 1f\n") + LinkAdr = CurrAdr if (rd!=0) else 0 # rd's expected value + for i in range(spacers): + addInst(" li x"+str(DataReg)+", "+formatstr.format(unexpected)+"\n") + f.write("1:\n") + addInst(" "+storecmd+" x"+str(rd)+", "+str(wordsize*(2*TestNum+0))+"(x"+str(StoreAdrReg)+")\n") + f.write(" RVTEST_IO_ASSERT_GPR_EQ(x"+str(StoreAdrReg+1)+", x"+str(rd)+", "+formatstr.format(LinkAdr)+")\n") + addInst(" "+storecmd+" x"+str(DataReg)+", "+str(wordsize*(2*TestNum+1))+"(x"+str(StoreAdrReg)+")\n") + f.write(" RVTEST_IO_ASSERT_GPR_EQ(x"+str(StoreAdrReg+1)+", x"+str(DataReg)+", "+formatstr.format(expected)+")\n") + writeExpectedToRef(LinkAdr) + writeExpectedToRef(expected) + TestNum = TestNum+1 + +def writeBackwardsJumpVector(spacers): + global TestNum + rd, rs, DataReg,OtherRd = registerSelect() + if (xlen==64): + expected = int("fedbca9876540000",16) + unexpected = int("ffff0000ffff0000",16) + else: + expected = int("fedbca98",16) + unexpected = int("ff00ff00",16) + + f.write("\n") + f.write(" # Testcase "+str(TestNum)+" address cmp result rd:x"+str(rd)+"("+formatstr.format(CurrAdr+20+8*spacers)+") data result rd:x"+str(DataReg)+"("+formatstr.format(expected)+")\n") + addInst(" JAL x"+str(OtherRd)+", 2f\n") + f.write("1:\n") + addInst(" li x"+str(DataReg)+", "+formatstr.format(expected)+"\n") + addInst(" JAL x"+str(OtherRd)+", 3f\n") + f.write("2:\n") + for i in range(spacers): + addInst(" li x"+str(DataReg)+", "+formatstr.format(unexpected)+"\n") + addInst(" JAL x"+str(rd)+", 1b\n") + LinkAdr = CurrAdr if (rd!=0) else 0 # rd's expected value + f.write("3:\n") + addInst(" "+storecmd+" x"+str(rd)+", "+str(wordsize*(2*TestNum+0))+"(x"+str(StoreAdrReg)+")\n") + f.write(" RVTEST_IO_ASSERT_GPR_EQ(x"+str(StoreAdrReg+1)+", x"+str(rd)+", "+formatstr.format(LinkAdr)+")\n") + addInst(" "+storecmd+" x"+str(DataReg)+", "+str(wordsize*(2*TestNum+1))+"(x"+str(StoreAdrReg)+")\n") + f.write(" RVTEST_IO_ASSERT_GPR_EQ(x"+str(StoreAdrReg+1)+", x"+str(DataReg)+", "+formatstr.format(expected)+")\n") + writeExpectedToRef(LinkAdr) + writeExpectedToRef(expected) + TestNum = TestNum+1 + +def writeChainVector(repetitions,spacers): + global TestNum + rd, rs, DataReg,OtherRd = registerSelect() + if (xlen==64): + expected = int("fedbca9876540000",16) + unexpected = int("ffff0000ffff0000",16) + else: + expected = int("fedbca98",16) + unexpected = int("ff00ff00",16) + + f.write("\n") + f.write(" # Testcase "+str(TestNum)+" address cmp result rd:x"+str(rd)+"(ugh; if you really wanted to, you could figure it out) data result rd:x"+str(DataReg)+"("+formatstr.format(expected)+")\n") + addInst(" li x"+str(DataReg)+", "+formatstr.format(expected)+"\n") + for i in range(repetitions): + addInst(" JAL x"+str(OtherRd)+", "+str(3*i+2)+"f\n") + if spacers: + for j in range(i): + addInst(" li x"+str(DataReg)+", "+formatstr.format(unexpected)+"\n") + f.write(str(3*i+1)+":\n") + addInst(" JAL x"+str(OtherRd)+", "+str(3*i+3)+"f\n") + if spacers: + for j in range(i): + addInst(" li x"+str(DataReg)+", "+formatstr.format(unexpected)+"\n") + f.write(str(3*i+2)+":\n") + addInst(" JAL x"+str(rd)+", "+str(3*i+1)+"b\n") + LinkAdr = CurrAdr if (rd!=0) else 0 # rd's expected value + if spacers: + for j in range(i): + addInst(" li x"+str(DataReg)+", "+formatstr.format(unexpected)+"\n") + f.write(str(3*i+3)+":\n") + addInst(" "+storecmd+" x"+str(rd)+", "+str(wordsize*(2*TestNum+0))+"(x"+str(StoreAdrReg)+")\n") + f.write(" RVTEST_IO_ASSERT_GPR_EQ(x"+str(StoreAdrReg+1)+", x"+str(rd)+", "+formatstr.format(LinkAdr)+")\n") + addInst(" "+storecmd+" x"+str(DataReg)+", "+str(wordsize*(2*TestNum+1))+"(x"+str(StoreAdrReg)+")\n") + f.write(" RVTEST_IO_ASSERT_GPR_EQ(x"+str(StoreAdrReg+1)+", x"+str(DataReg)+", "+formatstr.format(expected)+")\n") + writeExpectedToRef(LinkAdr) + writeExpectedToRef(expected) + TestNum = TestNum+1 + + +def writeExpectedToRef(expected): + global TestGroupSizes + TestGroupSizes[TestGroup-1] += 1 + if (xlen == 32): + r.write(formatrefstr.format(expected)+"\n") + else: + r.write(formatrefstr.format(expected % 2**32)+"\n" + formatrefstr.format(expected >> 32)+"\n") + +################################## +# main body +################################## + +# change these to suite your tests +tests = ["JAL"] +author = "Ben Bracker (bbracker@hmc.edu)" +xlens = [32,64] +numtests = 100; + +# setup +seed(0) # make tests reproducible + +# generate files for each test +for xlen in xlens: + CurrAdr = int("80000108",16) + TestNum = 0 + TestGroup = 1 + TestGroupSizes = [0] + AllRegs = list(range(0,32)) + UnusedRegs = deepcopy(AllRegs) + StoreAdrReg = 6 # matches what's in header script + UnusedRegs.remove(6) + + formatstrlen = str(int(xlen/4)) + formatstr = "0x{:0" + formatstrlen + "x}" # format as xlen-bit hexadecimal number + formatrefstr = "{:08x}" # format as xlen-bit hexadecimal number with no leading 0x + if (xlen == 32): + storecmd = "sw" + wordsize = 4 + else: + storecmd = "sd" + wordsize = 8 + for test in tests: + imperaspath = "../../imperas-riscv-tests/riscv-test-suite/rv" + str(xlen) + "i/" + basename = "WALLY-" + test + fname = imperaspath + "src/" + basename + ".S" + refname = imperaspath + "references/" + basename + ".reference_output" + + # print custom header part + f = open(fname, "w") + r = open(refname, "w") + f.write("///////////////////////////////////////////\n") + f.write("// "+fname+ "\n") + f.write("//\n") + f.write("// This file can be used to test the RISC-V JAL instruction.\n") + f.write("// But be warned that altering the test environment may break this test!\n") + f.write("// In order to work, this test expects that the first instruction (la)\n") + f.write("// be allocated at 0x80000100.\n") + f.write("//\n") + f.write("// " + author + "\n") + f.write("// Created "+str(datetime.now())+"\n") + + # insert generic header + h = open("testgen_header.S", "r") + for line in h: + f.write(line) + + # print directed test vectors + for i in range(0,31): + writeForwardsJumpVector(randint(0,4)) + for i in range(0,31): + writeBackwardsJumpVector(randint(0,4)) + writeForwardsJumpVector(100) + writeBackwardsJumpVector(100) + writeChainVector(6,True) + writeChainVector(16,False) + + # print footer + h = open("testgen_footer.S", "r") + for line in h: + f.write(line) + + # Finish + f.write(".fill "+str(sum(TestGroupSizes))+", "+str(wordsize)+", -1\n") + f.write("\nRV_COMPLIANCE_DATA_END\n") + f.close() + r.close() + + + + diff --git a/wally-pipelined/testgen/testgen-LOAD.py b/wally-pipelined/testgen/testgen-LOAD.py new file mode 100755 index 000000000..4a80fbfc7 --- /dev/null +++ b/wally-pipelined/testgen/testgen-LOAD.py @@ -0,0 +1,227 @@ +#!/usr/bin/python3 +################################## +# testgen-LOAD.py +# +# Jarred Allen 02 February 2021 +# +# Generate directed and random test vectors for RISC-V Design Validation. +################################## + +################################## +# libraries +################################## +from datetime import datetime +from random import randint, seed, getrandbits + +################################## +# functions +################################## + +def rand_reg(): + """Produce a random register (skipping 6 and 31, since they're used for other things)""" + r = randint(1,29) + if r >= 6: + r += 1 + return r + +def rand_value(width): + """Generate a random value which fits in the given width""" + return randint(0, (1 << width) - 1) + +def rand_offset(): + """Generate a random offset""" + ret = rand_value(12) + # print("Random offset: %d" % ret) + return ret + +def rand_source(): + """Generate a random value for the source register, such that the load address is in the test data""" + ret = randint(1 << 12, (1 << 12) + (1 << 10)) + # print("Random source: %d" % ret) + return ret + +def add_offset_to_source(source, offset): + """Find the address from the given source value and offset""" + if offset & 0x800: + offset -= 0x1000 + return source + offset + +def insert_into_data(test_data, source, offset, value, width, xlen): + """Insert the given value into the given location of the test data""" + address = add_offset_to_source(source, offset) + # print("Test #%d" % testcase_num) + # print(f"Source: {source}, Offset: {offset}, Value: {value}, Width: {width}, xlen: {xlen}, Addr: {address}") + if address < 0: + return False + word_offset = address % (xlen // 8) + word_address = address - word_offset + if word_address in test_data: + return False + test_data[word_address] = value * (1 << (word_offset*8)) + ((~(((1 << width)-1) << (word_offset*8))) & rand_value(xlen)) + # print(f"Word: {hex(test_data[word_address])}") + return True + +def align(address, width): + """Align the address to the given width, in bits""" + return address - (address % (width // 8)) + +testcase_num = 0 +def generate_case(xlen, instruction, load_register, source_register, source_register_value, offset, expected): + """Produce the specified test case and return it as a pair of strings, where the first is the test case and the second is the output""" + global testcase_num + if xlen == 64: + store = "sd" + elif xlen == 32: + if instruction in ["lwu", "ld"]: + raise Exception("Instruction %s not supported in RV32I" % instruction) + store = "sw" + else: + raise Exception("Unknown xlen value: %s" % xlen) + if offset >= 0x800: + offset -= 0x1000 + if widths[instruction] != xlen: + expected = expected % (1 << widths[instruction]) + if 'u' not in instruction: + if expected & (1 << (widths[instruction] - 1)): + expected = (expected + ~((1 << widths[instruction]) - 1)) & ((1 << xlen) - 1) + data = f"""# Testcase {testcase_num}: source {offset}(x{source_register} == {source_register_value}), result: x{load_register} == {expected} + la x31, test_data + lui x{source_register}, {source_register_value // (1 << 12)} + addi x{source_register}, x{source_register}, {source_register_value % (1 << 12)} + add x{source_register}, x{source_register}, x31 + {instruction} x{load_register}, {offset}(x{source_register}) + {store} x{load_register}, {(testcase_num*xlen//8) % 0x800}(x6) + RVTEST_IO_ASSERT_GPR_EQ(x8, x{load_register}, {expected}) + + """ + testcase_num += 1 + if testcase_num*xlen//8 % 0x800 == 0: + data += "# Adjust x6 because we're storing too many things\naddi x6, x6, 1024\naddi x6, x6, 1024\n\n" + if xlen == 32: + reference_output = "{:08x}\n".format(expected) + elif xlen == 64: + reference_output = "{:08x}\n{:08x}\n".format(expected % (1 << 32), expected >> 32) + return (data, reference_output) + +def write_header(outfile): + outfile.write(f"""/////////////////////////////////////////// +// +// WALLY-LOAD +// +// Author: {author} +// +// Created {str(datetime.now())} +// +""") + outfile.write(open("testgen_header.S", "r").read()) + +def write_test_data(outfile, test_data, xlen): + # print("Begin writing test data:") + # print("{} entries, from address {} to {}".format(len(test_data), min(test_data.keys()), max(test_data.keys()))) + # print(test_data) + outfile.write(""" + .align 16 +test_data: + + """) + if xlen == 32: + data_word = ".word" + elif xlen == 64: + data_word = ".dword" + else: + raise Exception("Unknown xlen: %d" % xlen) + byte_width = xlen // 8 + for addr in [0] + sorted(test_data.keys()): + if addr in test_data: + word = f" {data_word} {hex(test_data[addr] % (1 << xlen))} # test_data+{hex(addr)}\n" + else: + word = "" + try: + fill_len = (min(k for k in test_data.keys() if k > addr) - addr) // byte_width - 1 + if word == "": + fill_len += 1 + fill = f" .fill {fill_len}, {byte_width}, 0x0\n" + except: + fill = "" + case = word+fill + outfile.write(case) + +################################## +# main body +################################## + +widths = { + "lb": 8, + "lbu": 8, + "lh": 16, + "lhu": 16, + "lw": 32, + "lwu": 32, + "ld": 64, +} +instructions = [i for i in widths] +author = "Jarred Allen" +xlens = [32, 64] +numrand = 100; + +# setup +seed(0) # make tests reproducible + +for xlen in xlens: + testcase_num = 0 + fname = "../../imperas-riscv-tests/riscv-test-suite/rv{}i/src/WALLY-LOAD.S".format(xlen) + refname = "../../imperas-riscv-tests/riscv-test-suite/rv{}i/references/WALLY-LOAD.reference_output".format(xlen) + f = open(fname, "w") + r = open(refname, "w") + write_header(f) + test_data = dict() + corner_values = [0x00, 0xFFFFFFFF, 0x7F, 0x7FFF, 0x7FFFFFFF] + if xlen == 64: + corner_values += [0xFFFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFF] + corner_offsets = [0x800, 0x000, 0x7FF] + for instruction in instructions: + print("Running xlen: %d, instruction: %s" % (xlen, instruction)) + if xlen == 32: + if instruction in ["lwu", "ld"]: + continue + for value in corner_values + [rand_value(widths[instruction]) for _ in range(3)]: + value = value % (1 << widths[instruction]) + source_reg = rand_source() + for offset in corner_offsets + [rand_offset() for _ in range(3)]: + offset = align(offset, widths[instruction]) + source_reg = align(source_reg, widths[instruction]) + if insert_into_data(test_data, source_reg, offset, value, widths[instruction], xlen): + data, output = generate_case(xlen, instruction, rand_reg(), rand_reg(), source_reg, offset, value) + f.write(data) + r.write(output) + while testcase_num % 4: + source = rand_source() + offset = rand_offset() + value = rand_value(widths[instruction]) + if insert_into_data(test_data, source, offset, value, widths['lb'], xlen): + data, output = generate_case(xlen, 'lb', rand_reg(), rand_reg(), source, offset, value) + f.write(data) + r.write(output) + f.write("""# --------------------------------------------------------------------------------------------- + + RVTEST_IO_WRITE_STR(x31, "Test End\\n") + + # --------------------------------------------------------------------------------------------- + + RV_COMPLIANCE_HALT + +RV_COMPLIANCE_CODE_END + + .data + # Input data section +""") + write_test_data(f, test_data, xlen) + f.write("""# Output data section. +RV_COMPLIANCE_DATA_BEGIN + +test_1_res: +""") + f.write(f".fill {testcase_num}, {xlen//8}, -1\n") + f.write("\nRV_COMPLIANCE_DATA_END\n") + f.close() + r.close() diff --git a/wally-pipelined/testgen/testgen-SLL-SRL-SRA.py b/wally-pipelined/testgen/testgen-SLL-SRL-SRA.py new file mode 100755 index 000000000..6b4996d90 --- /dev/null +++ b/wally-pipelined/testgen/testgen-SLL-SRL-SRA.py @@ -0,0 +1,154 @@ +#!/usr/bin/python3 +################################## +# testgen-SLL-SRL-SRA.py +# +# David_Harris@hmc.edu 19 January 2021 +# +# Generate directed and random test vectors for RISC-V Design Validation. +################################## + +################################## +# libraries +################################## +from datetime import datetime +from random import randint +from random import seed +from random import getrandbits + +################################## +# functions +################################## + +def twoscomp(a): + amsb = a >> (xlen-1) + alsbs = ((1 << (xlen-1)) - 1) & a + if (amsb): + asigned = a - (1<> b + elif (test == "SRA"): + return asigned >> b + else: + die("bad test name ", test) + # exit(1) + +def randRegs(): + reg1 = randint(1,31) + reg2 = randint(1,31) + reg3 = randint(1,31) + if (reg1 == 6 or reg2 == 6 or reg3 == 6 or reg1 == reg2): + return randRegs() + else: + return reg1, reg2, reg3 + +def writeVector(a, b, storecmd, xlen): + global testnum + expected = computeExpected(a, b, test, xlen) + expected = expected % 2**xlen # drop carry if necessary + if (expected < 0): # take twos complement + expected = 2**xlen + expected + reg1, reg2, reg3 = randRegs() + lines = "\n# Testcase " + str(testnum) + ": rs1:x" + str(reg1) + "(" + formatstr.format(a) + lines = lines + "), rs2:x" + str(reg2) + "(" +formatstr.format(b) + lines = lines + "), result rd:x" + str(reg3) + "(" + formatstr.format(expected) +")\n" + lines = lines + "li x" + str(reg1) + ", MASK_XLEN(" + formatstr.format(a) + ")\n" + lines = lines + "li x" + str(reg2) + ", MASK_XLEN(" + formatstr.format(b) + ")\n" + lines = lines + test + " x" + str(reg3) + ", x" + str(reg1) + ", x" + str(reg2) + "\n" + lines = lines + storecmd + " x" + str(reg3) + ", " + str(wordsize*testnum) + "(x6)\n" + lines = lines + "RVTEST_IO_ASSERT_GPR_EQ(x7, " + str(reg3) +", "+formatstr.format(expected)+")\n" + f.write(lines) + if (xlen == 32): + line = formatrefstr.format(expected)+"\n" + else: + line = formatrefstr.format(expected % 2**32)+"\n" + formatrefstr.format(expected >> 32) + "\n" + r.write(line) + testnum = testnum+1 + +################################## +# main body +################################## + +# change these to suite your tests +tests = ["SLL", "SRL", "SRA"] +author = "David_Harris@hmc.edu" +xlens = [32, 64] +numrand = 48 + +# setup +seed(0) # make tests reproducible + +# generate files for each test +for xlen in xlens: + formatstrlen = str(int(xlen/4)) + formatstr = "0x{:0" + formatstrlen + "x}" # format as xlen-bit hexadecimal number + formatrefstr = "{:08x}" # format as xlen-bit hexadecimal number with no leading 0x + if (xlen == 32): + storecmd = "sw" + wordsize = 4 + else: + storecmd = "sd" + wordsize = 8 + for test in tests: + corners = [0, 1, 2, 0xFF, 0x624B3E976C52DD14 % 2**xlen, 2**(xlen-1)-2, 2**(xlen-1)-1, + 2**(xlen-1), 2**(xlen-1)+1, 0xC365DDEB9173AB42 % 2**xlen, 2**(xlen)-2, 2**(xlen)-1] + if (xlen == 32): + shamt = [0, 1, 2, 3, 4, 8, 15, 16, 29, 30, 31] + else: + shamt = [0, 1, 3, 8, 15, 16, 29, 31, 32, 47, 48, 62, 63] + + imperaspath = "../../imperas-riscv-tests/riscv-test-suite/rv" + str(xlen) + "i/" + basename = "WALLY-" + test + fname = imperaspath + "src/" + basename + ".S" + refname = imperaspath + "references/" + basename + ".reference_output" + testnum = 0 + + # print custom header part + f = open(fname, "w") + r = open(refname, "w") + line = "///////////////////////////////////////////\n" + f.write(line) + lines="// "+fname+ "\n// " + author + "\n" + f.write(lines) + line ="// Created " + str(datetime.now()) + f.write(line) + + # insert generic header + h = open("testgen_header.S", "r") + for line in h: + f.write(line) + + # print directed and random test vectors + for a in corners: + for b in shamt: + writeVector(a, b, storecmd, xlen) + for i in range(0,numrand): + a = getrandbits(xlen) + b = getrandbits(xlen) + writeVector(a, b, storecmd, xlen) + + + # print footer + h = open("testgen_footer.S", "r") + for line in h: + f.write(line) + + # Finish + lines = ".fill " + str(testnum) + ", " + str(wordsize) + ", -1\n" + lines = lines + "\nRV_COMPLIANCE_DATA_END\n" + f.write(lines) + f.close() + r.close() + + + + diff --git a/wally-pipelined/testgen/testgen-SLLI-SRLI-SRAI.py b/wally-pipelined/testgen/testgen-SLLI-SRLI-SRAI.py new file mode 100644 index 000000000..201763890 --- /dev/null +++ b/wally-pipelined/testgen/testgen-SLLI-SRLI-SRAI.py @@ -0,0 +1,189 @@ +#!/usr/bin/python3 +################################## +# testgen-ADD-SUB.py +# +# David_Harris@hmc.edu 19 January 2021 +# +# Generate directed and random test vectors for RISC-V Design Validation. +################################## + +################################## +# libraries +################################## +from datetime import datetime +from random import randint +from random import seed +from random import getrandbits + +################################## +# functions +################################## + +def computeExpected(a, b, test): + if (test == "SLLI"): + return a << b + elif (test == "SRLI"): + return srli(a,b) + elif (test == "SRAI"): + return a >> b + else: + die("bad test name ", test) + # exit(1) + +def signExt(b, bits): + a_str = bin(b)[2::] + if (a_str[0] == "b"): + a_str = a_str[1:] + + if (len(a_str) < 12): + zeroPadding = "0" * (bits - len(a_str)) + a_str = zeroPadding + a_str + + print( "{:x}, {:s} ".format(b, a_str)) + padding = a_str[len(a_str)-1] * (bits - len(a_str)) + return int(padding + a_str, 2) + + +def evaluateTwoComplement(b, bits): + if (b & (1 << (bits -1))!= 0): + b = b - (1 << bits) + return b + + +def srli(a,b): + if (a < 0): + a = 2**xlen + a + if (b==0): + return a + a_str = bin(a)[2:] + if a_str[0]== "b": + a_str = a_str[1:] + # print(a_str) + numZeroPad = (len(a_str)-abs(b)) + out = a_str[:numZeroPad] + if (numZeroPad <= 0): + return 0 + print("a: {:b}, b: {:d}, out:{:b}".format(a, b, int(out,2))) + return int(out,2) + +def randRegs(): + reg1 = randint(1,31) + reg3 = randint(1,31) + if (reg1 == 6 or reg3 == 6): + return randRegs() + else: + return reg1, reg3 + +def writeVector(a, b, storecmd): + global testnum + + + + + expected = computeExpected(evaluateTwoComplement(a, xlen), b, test) +# print( "original {:x}, sign Extended {:x} ".format(b, signExt(b,xlen))) +# print (str(a) + "<" + str(signExt(b,xlen)) + " : " + str(expected)) + expected = expected % 2**xlen # drop carry if necessary + if (expected < 0): # take twos complement + expected = 2**xlen + expected + + + + reg1, reg3 = randRegs() + lines = "\n# Testcase " + str(testnum) + ": rs1:x" + str(reg1) + "(" + formatstr.format(a) + lines = lines + "), imm5:" + "(" +formatstrimm5.format(b) + lines = lines + "), result rd:x" + str(reg3) + "(" + formatstr.format(expected) +")\n" + lines = lines + "li x" + str(reg1) + ", MASK_XLEN(" + formatstr.format(a) + ")\n" + lines = lines + test + " x" + str(reg3) + ", x" + str(reg1) + ", " + formatstrimm5.format(b) + "\n" + # lines = lines + test + " x" + str(reg3) + ", x" + str(reg1) + ", MASK_XLEN(" + formatstr.format(b) + ")\n" + lines = lines + storecmd + " x" + str(reg3) + ", " + str(wordsize*testnum) + "(x6)\n" + lines = lines + "RVTEST_IO_ASSERT_GPR_EQ(x7, " +"x" + str(reg3) +", "+formatstr.format(expected)+")\n" + f.write(lines) + if (xlen == 32): + line = formatrefstr.format(expected)+"\n" + else: + line = formatrefstr.format(expected % 2**32)+"\n" + formatrefstr.format(expected >> 32) + "\n" + r.write(line) + testnum = testnum+1 + +################################## +# main body +################################## + +# change these to suite your tests +tests = ["SLLI", "SRLI", "SRAI"] +author = "Shriya Nadgauda & Ethan Falicov" +xlens = [32, 64] +numrand = 100 + + +# setup +seed(0) # make tests reproducible + +# generate files for each test +for xlen in xlens: + formatstrlen = str(int(xlen/4)) + formatstr = "0x{:0" + formatstrlen + "x}" # format as xlen-bit hexadecimal number + formatrefstr = "{:08x}" # format as xlen-bit hexadecimal number with no leading 0x + + formatstrimm5 = "0b{:05b}" # format as 5-bit binary number + if (xlen == 32): + storecmd = "sw" + wordsize = 4 + else: + storecmd = "sd" + wordsize = 8 + + for test in tests: + corners1 = [0, 1, 2, 0xFF, 0x624B3E976C52DD14 % 2**xlen, 2**(xlen-1)-2, 2**(xlen-1)-1, + 2**(xlen-1), 2**(xlen-1)+1, 0xC365DDEB9173AB42 % 2**xlen, 2**(xlen)-2, 2**(xlen)-1] + + immBitSize = 5 + corners2 = [0, 1, 2, 0x07, 0x14 % 2**immBitSize, 2**(immBitSize-1)-2, 2**(immBitSize-1)-1, + 2**(immBitSize-1), 2**(immBitSize-1)+1, 0x06 % 2**immBitSize, 2**(immBitSize)-2, 2**(immBitSize)-1] + + imperaspath = "../../imperas-riscv-tests/riscv-test-suite/rv" + str(xlen) + "i/" + basename = "WALLY-" + test + fname = imperaspath + "src/" + basename + ".S" + refname = imperaspath + "references/" + basename + ".reference_output" + testnum = 0 + + # print custom header part + f = open(fname, "w") + r = open(refname, "w") + line = "///////////////////////////////////////////\n" + f.write(line) + lines="// "+fname+ "\n// " + author + "\n" + f.write(lines) + line ="// Created " + str(datetime.now()) + f.write(line) + + # insert generic header + h = open("testgen_header.S", "r") + for line in h: + f.write(line) + + # print directed and random test vectors + for a in corners1: + for b in corners2: + writeVector(a, b, storecmd) + for i in range(0,numrand): + a = getrandbits(xlen) + b = getrandbits(5) + writeVector(a, b, storecmd) + + + # print footer + h = open("testgen_footer.S", "r") + for line in h: + f.write(line) + + # Finish + lines = ".fill " + str(testnum) + ", " + str(wordsize) + ", -1\n" + lines = lines + "\nRV_COMPLIANCE_DATA_END\n" + f.write(lines) + f.close() + r.close() + + + diff --git a/wally-pipelined/testgen/testgen-SLTIU.py b/wally-pipelined/testgen/testgen-SLTIU.py new file mode 100644 index 000000000..25eb5ddfb --- /dev/null +++ b/wally-pipelined/testgen/testgen-SLTIU.py @@ -0,0 +1,173 @@ +#!/usr/bin/python3 +################################## +# testgen-ADD-SUB.py +# +# David_Harris@hmc.edu 19 January 2021 +# +# Generate directed and random test vectors for RISC-V Design Validation. +################################## + +################################## +# libraries +################################## +from datetime import datetime +from random import randint +from random import seed +from random import getrandbits + +################################## +# functions +################################## + +def computeExpected(a, b, test): + if (test == "SLTIU"): + return a < b + else: + die("bad test name ", test) + # exit(1) + +def signExt(b, bits): + a_str = bin(b)[2::] + if (a_str[0] == "b"): + a_str = a_str[1:] + + if (len(a_str) < 12): + zeroPadding = "0" * (12 - len(a_str)) + a_str = zeroPadding + a_str + + + padding = a_str[0] * (bits - len(a_str)) + print( "b {:x}, sign extended {:s} ".format(b, padding + a_str)) + return int(padding + a_str, 2) + + + +def evaluateTwoComplement(b, bits): + if (b & (1 << (bits -1))!= 0): + b = b - (1 << bits) + return b + + +def randRegs(): + reg1 = randint(1,31) + reg3 = randint(1,31) + if (reg1 == 6 or reg3 == 6): + return randRegs() + else: + return reg1, reg3 + +def writeVector(a, b, storecmd): + global testnum + + + + signExtImm = signExt(b,xlen) + if signExtImm < 0: + signExtImm = signExtImm + 2 ** xlen + expected = computeExpected(a, signExtImm, test) + # s + + expected = expected % 2**xlen # drop carry if necessary + if (expected < 0): # take twos complement + expected = 2**xlen + expected + + + + reg1, reg3 = randRegs() + lines = "\n# Testcase " + str(testnum) + ": rs1:x" + str(reg1) + "(" + formatstr.format(a) + lines = lines + "), imm12:" + "(" +formatstrimm12.format(b) + lines = lines + "), result rd:x" + str(reg3) + "(" + formatstr.format(expected) +")\n" + lines = lines + "li x" + str(reg1) + ", MASK_XLEN(" + formatstr.format(a) + ")\n" + lines = lines + test + " x" + str(reg3) + ", x" + str(reg1) + ", SEXT_IMM(" + formatstrimm12.format(b) + ")\n" + # lines = lines + test + " x" + str(reg3) + ", x" + str(reg1) + ", MASK_XLEN(" + formatstr.format(b) + ")\n" + lines = lines + storecmd + " x" + str(reg3) + ", " + str(wordsize*testnum) + "(x6)\n" + lines = lines + "RVTEST_IO_ASSERT_GPR_EQ(x7, " +"x" + str(reg3) +", "+formatstr.format(expected)+")\n" + f.write(lines) + if (xlen == 32): + line = formatrefstr.format(expected)+"\n" + else: + line = formatrefstr.format(expected % 2**32)+"\n" + formatrefstr.format(expected >> 32) + "\n" + r.write(line) + testnum = testnum+1 + +################################## +# main body +################################## + +# change these to suite your tests +tests = ["SLTIU"] +author = "Shriya Nadgauda & Ethan Falicov" +xlens = [32, 64] +numrand = 100 + + +# setup +seed(0) # make tests reproducible + +# generate files for each test +for xlen in xlens: + formatstrlen = str(int(xlen/4)) + formatstr = "0x{:0" + formatstrlen + "x}" # format as xlen-bit hexadecimal number + formatrefstr = "{:08x}" # format as xlen-bit hexadecimal number with no leading 0x + + formatstrimm12 = "0x{:03x}" # format as 3-bit hexadecimal number + if (xlen == 32): + storecmd = "sw" + wordsize = 4 + else: + storecmd = "sd" + wordsize = 8 + + for test in tests: + corners1 = [0, 1, 2, 0xFF, 0x624B3E976C52DD14 % 2**xlen, 2**(xlen-1)-2, 2**(xlen-1)-1, + 2**(xlen-1), 2**(xlen-1)+1, 0xC365DDEB9173AB42 % 2**xlen, 2**(xlen)-2, 2**(xlen)-1] + + immBitSize = 12 + corners2 = [0, 1, 2, 0xFF, 0x624 % 2**immBitSize, 2**(immBitSize-1)-2, 2**(immBitSize-1)-1, + 2**(immBitSize-1), 2**(immBitSize-1)+1, 0xC36 % 2**immBitSize, 2**(immBitSize)-2, 2**(immBitSize)-1] + + imperaspath = "../../imperas-riscv-tests/riscv-test-suite/rv" + str(xlen) + "i/" + basename = "WALLY-" + test + fname = imperaspath + "src/" + basename + ".S" + refname = imperaspath + "references/" + basename + ".reference_output" + testnum = 0 + + # print custom header part + f = open(fname, "w") + r = open(refname, "w") + line = "///////////////////////////////////////////\n" + f.write(line) + lines="// "+fname+ "\n// " + author + "\n" + f.write(lines) + line ="// Created " + str(datetime.now()) + f.write(line) + + # insert generic header + h = open("testgen_header.S", "r") + for line in h: + f.write(line) + + # print directed and random test vectors + for a in corners1: + for b in corners2: + writeVector(a, b, storecmd) + for i in range(0,numrand): + a = getrandbits(xlen) + b = getrandbits(12) + writeVector(a, b, storecmd) + + + # print footer + h = open("testgen_footer.S", "r") + for line in h: + f.write(line) + + # Finish + lines = ".fill " + str(testnum) + ", " + str(wordsize) + ", -1\n" + lines = lines + "\nRV_COMPLIANCE_DATA_END\n" + f.write(lines) + f.close() + r.close() + + + diff --git a/wally-pipelined/testgen/testgen-STORE.py b/wally-pipelined/testgen/testgen-STORE.py new file mode 100755 index 000000000..d4a995d48 --- /dev/null +++ b/wally-pipelined/testgen/testgen-STORE.py @@ -0,0 +1,282 @@ +#!/usr/bin/python3 +################################## +# testgen-STORE.py +# +# Jessica Torrey 03 February 2021 +# Thomas Fleming 03 February 2021 +# +# Generate directed and random test vectors for RISC-V Design Validation. +################################## + +################################## +# libraries +################################## +from datetime import datetime +from random import randint, seed, getrandbits +from textwrap import dedent + +################################## +# global structures +################################## +size_to_store = {8: "sd", 4: "sw", 2: "sh", 1: "sb"} +size_to_load = {8: "ld", 4: "lw", 2: "lh", 1: "lb"} +store_to_size = {"sd": 8, "sw": 4, "sh": 2, "sb": 1} +testcase_num = 0 +signature_len = 2000 +signature = [0xff for _ in range(signature_len)] + +################################## +# functions +################################## + +def rand_reg(): + """ + Produce a random register from 1 to 31 (skipping 6, since r6 is used for + other things). + """ + r = randint(1,30) + if r >= 6: + r += 1 + return r + +def rand_regs(): + """ + Generate two random, unequal register numbers (skipping x6). + """ + rs1 = rand_reg() + rs2 = rand_reg() + while rs1 == rs2: + rs2 = rand_reg() + + return rs1, rs2 + +def generate_case(xlen, instruction, value_register, value, addr_register, offset, base_delta): + """ + Create assembly code for a given STORE test case, returned as a string. + + Generates an `xlen`-bit test case for `instruction` (one of sb, sh, sw, or + sd) that loads `value` into `value_register`, then attempts to store that + value in memory at address (x6 + `base_delta`). The test case + assumes the current base address for the signature is in register x6. + + The form of the STORE instruction is as follows: + + `instruction` `value_register` `offset`(`addr_register`) + """ + global testcase_num + + hex_value = f"{value:0{xlen // 4}x}" + + data = f"""# Testcase {testcase_num}: source: x{value_register} (value 0x{hex_value}), destination: {offset}(x{addr_register}) ({base_delta} bytes into signature) + addi x{addr_register}, x6, {base_delta} + li x{value_register}, MASK_XLEN({-offset}) + add x{addr_register}, x{addr_register}, x{value_register} + li x{value_register}, 0x{hex_value} + {instruction} x{value_register}, {offset}(x{addr_register}) + """ + + update_signature(store_to_size[instruction], value, base_delta) + + testcase_num += 1 + return data + +def validate_memory(scratch_register, value_register, value, base_delta, length): + """ + Create assembly code to verify that `length` bytes at mem[x6 + `base_delta`] + store `value`. + + Assumes x6 stores the current base address for the signature. + """ + truncated_value = value & (2**(length * 8) - 1) + hex_value = f"{truncated_value:0{length * 2}x}" + + load = size_to_load[length] + data = f"""addi x{scratch_register}, x6, {base_delta} + {load} x{value_register}, 0(x{scratch_register}) + RVTEST_IO_ASSERT_GPR_EQ(x{scratch_register}, x{value_register}, 0x{hex_value}) + + """ + return data + +def update_signature(length, value, base_delta): + """ + Write the lower `length` bytes of `value` to the little-endian signature + array, starting at byte `base_delta`. + """ + truncated_value = value & (2**(length * 8) - 1) + value_bytes = truncated_value.to_bytes(length, 'little') + #print("n: {}, value: {:x}, trunc: {:x}, length: {}, bd: {:x}".format(testcase_num, value, truncated_value, length, base_delta)) + for i in range(length): + signature[base_delta + i] = value_bytes[i] + +def write_signature(outfile): + """ + Writes successive 32-bit words from the signature array into a given file. + """ + for i in range(0, signature_len, 4): + word = list(reversed(signature[i:i+4])) + hexword = bytearray(word).hex() + outfile.write(f"{hexword}\n") + +def write_header(outfile): + """ + Write the name of the test file, authors, and creation date. + """ + outfile.write(dedent(f"""\ + /////////////////////////////////////////// + // + // WALLY-STORE + // + // Author: {author} + // + // Created {str(datetime.now())} + """)) + outfile.write(open("testgen_header.S", "r").read()) + +def write_footer(outfile): + """ + Write necessary closing code, including a data section for the signature. + """ + outfile.write(open("testgen_footer.S", 'r').read()) + data_section = dedent(f"""\ + \t.fill {signature_len}, 1, -1 + RV_COMPLIANCE_DATA_END + """) + outfile.write(data_section) + +################################## +# test cases +################################## + +def write_basic_tests(outfile, xlen, instr_len, num, base_delta): + """ + Test basic functionality of STORE, using random registers, offsets, and + values. + + Creates `num` tests for a single store instruction of length `instr_len`, + writing to memory at consecutive locations, starting `base_delta` bytes from + the start of the signature. + + Returns the number of bytes from the start of the signature where testing + ended. + """ + instruction = size_to_store[instr_len] + for i in range(num): + value_register, addr_register = rand_regs() + offset = randint(-2**(12 - 1), 2**(12 - 1) - 1) + value = randint(0, 2**(instr_len * 8) - 1) + test = generate_case(xlen, instruction, value_register, value, addr_register, offset, base_delta) + validate = validate_memory(addr_register, value_register, value, base_delta, instr_len) + outfile.write(test) + outfile.write(validate) + base_delta += instr_len + return base_delta + +def write_random_store_tests(outfile, xlen, instr_len, num, min_base_delta): + """ + Test random access of STORE, using random registers, offsets, values, and + memory locations. + + Creates `num` tests for a single store instruction of length `instr_len`, + writing to memory at random locations between `min_base_delta` bytes past + the start of the signature to the end of the signature. + """ + instruction = size_to_store[instr_len] + for i in range(num): + base_delta = randint(min_base_delta, signature_len - 1) + base_delta -= (base_delta % instr_len) + value_register, addr_register = rand_regs() + offset = randint(-2**(12 - 1), 2**(12 - 1) - 1) + value = randint(0, 2**(instr_len * 8) - 1) + + test = generate_case(xlen, instruction, value_register, value, addr_register, offset, base_delta) + validate = validate_memory(addr_register, value_register, value, base_delta, instr_len) + outfile.write(test) + outfile.write(validate) + +def write_repeated_store_tests(outfile, xlen, instr_len, num, base_delta): + """ + Test repeated access of STORE, using random registers, offsets, values, and a + single memory location. + + Creates `num` tests for a single store instruction of length `instr_len`, + writing to memory `base_delta` bytes past the start of the signature. + """ + instruction = size_to_store[instr_len] + for i in range(num): + value_register, addr_register = rand_regs() + offset = 0 + value = (1 << ((2 * i) % xlen)) + + test = generate_case(xlen, instruction, value_register, value, addr_register, offset, base_delta) + validate = validate_memory(addr_register, value_register, value, base_delta, instr_len) + + outfile.write(test) + outfile.write(validate) + +def write_corner_case_tests(outfile, xlen, instr_len, base_delta): + instruction = size_to_store[instr_len] + + corner_cases_32 = [0x0, 0x10000001, 0x01111111] + corner_cases_64 = [0x1000000000000001, 0x0111111111111111] + corner_cases = corner_cases_32 + if xlen == 64: + corner_cases += corner_cases_64 + + for offset in corner_cases: + for value in corner_cases: + value_register, addr_register = rand_regs() + test = generate_case(xlen, instruction, value_register, value, addr_register, offset, base_delta) + validate = validate_memory(addr_register, value_register, value, base_delta, instr_len) + + outfile.write(test) + outfile.write(validate) + + base_delta += instr_len + + return base_delta + +################################## +# main body +################################## + +instructions = ["sd", "sw", "sh", "sb"] +author = "Jessica Torrey & Thomas Fleming " +xlens = [32, 64] +numrand = 100 + +# setup +seed(0) # make tests reproducible + +for xlen in xlens: + if (xlen == 32): + wordsize = 4 + else: + wordsize = 8 + + fname = f"../../imperas-riscv-tests/riscv-test-suite/rv{xlen}i/src/WALLY-STORE.S" + refname = f"../../imperas-riscv-tests/riscv-test-suite/rv{xlen}i/references/WALLY-STORE.reference_output" + f = open(fname, "w") + r = open(refname, "w") + + write_header(f) + + base_delta = 0 + + for instruction in instructions: + if xlen == 32 and instruction == 'sd': + continue + instr_len = store_to_size[instruction] + base_delta = write_basic_tests(f, xlen, instr_len, 5, base_delta) + write_repeated_store_tests(f, xlen, instr_len, 32, base_delta) + write_random_store_tests(f, xlen, instr_len, 5, base_delta + wordsize) + + write_footer(f) + + write_signature(r) + f.close() + r.close() + + # Reset testcase_num and signature + testcase_num = 0 + signature = [0xff for _ in range(signature_len)]