Merge remote-tracking branch 'origin/tlb_toy' into busybear

This commit is contained in:
kaveh pezeshki 2021-02-22 02:23:01 -08:00
commit e146946e58
55 changed files with 8111 additions and 94 deletions

3
.gitmodules vendored
View File

@ -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/

@ -1 +0,0 @@
Subproject commit afb27bd558a9b6fabb6b768ae81ef122b4db9eea

View File

@ -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)

View File

@ -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)

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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

View File

@ -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});

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1 @@
vsim -do iter64.do -c

View File

@ -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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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";

View File

@ -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

View File

@ -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<<xlen)
else:
asigned = a
#print("a: " + str(a) + " amsb: "+str(amsb)+ " alsbs: " + str(alsbs) + " asigned: "+str(asigned))
return asigned
def computeExpected(a, b, test, xlen):
asigned = twoscomp(a)
bsigned = twoscomp(b)
if (test == "ADD"):
return a + b
elif (test == "SUB"):
return a - b
elif (test == "SLT"):
return asigned < bsigned
elif (test == "SLTU"):
return a < b
elif (test == "XOR"):
return a ^ b
elif (test == "OR"):
return a | b
elif (test == "AND"):
return a & b
else:
die("bad test name ", test)
# exit(1)
@ -37,9 +60,9 @@ def randRegs():
else:
return reg1, reg2, reg3
def writeVector(a, b, storecmd):
def writeVector(a, b, storecmd, xlen):
global testnum
expected = computeExpected(a, b, test)
expected = computeExpected(a, b, test, xlen)
expected = expected % 2**xlen # drop carry if necessary
if (expected < 0): # take twos complement
expected = 2**xlen + expected
@ -65,7 +88,7 @@ def writeVector(a, b, storecmd):
##################################
# change these to suite your tests
tests = ["ADD", "SUB"]
tests = ["ADD", "SUB", "SLT", "SLTU", "XOR", "OR", "AND"]
author = "David_Harris@hmc.edu & Katherine Parry"
xlens = [32, 64]
numrand = 100;
@ -111,11 +134,11 @@ for xlen in xlens:
# print directed and random test vectors
for a in corners:
for b in corners:
writeVector(a, b, storecmd)
writeVector(a, b, storecmd, xlen)
for i in range(0,numrand):
a = getrandbits(xlen)
b = getrandbits(xlen)
writeVector(a, b, storecmd)
writeVector(a, b, storecmd, xlen)
# print footer

View File

@ -0,0 +1,161 @@
#!/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 == "ADDI"):
return a + b
elif (test == "XORI"):
return a ^ b
elif (test == "ORI"):
return a | b
elif (test == "ANDI"):
return a & b
elif (test == "SLTI"):
return a < b
else:
die("bad test name ", test)
# exit(1)
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
expected = computeExpected(evaluateTwoComplement(a,xlen), evaluateTwoComplement(b, 12), test)
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 = ["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()

View File

@ -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()

View File

@ -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()

View File

@ -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
elif (test == "BLTU"):
return 0xcccc if a<b else 0xeeee
elif (test == "BGE"):
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()

View File

@ -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()

View File

@ -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()

View File

@ -0,0 +1,227 @@
#!/usr/bin/python3
##################################
# testgen-LOAD.py
#
# Jarred Allen <jaallen@g.hmc.edu> 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()

View File

@ -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<<xlen)
else:
asigned = a
#print("a: " + str(a) + " amsb: "+str(amsb)+ " alsbs: " + str(alsbs) + " asigned: "+str(asigned))
return asigned
def computeExpected(a, b, test, xlen):
asigned = twoscomp(a)
b = b % xlen
if (test == "SLL"):
return a << b
elif (test == "SRL"):
return a >> 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()

View File

@ -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()

View File

@ -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()

View File

@ -0,0 +1,282 @@
#!/usr/bin/python3
##################################
# testgen-STORE.py
#
# Jessica Torrey <jtorrey@hmc.edu> 03 February 2021
# Thomas Fleming <tfleming@hmc.edu> 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 <jtorrey@hmc.edu> & Thomas Fleming <tfleming@hmc.edu>"
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)]