Merge branch 'main' of github.com:davidharrishmc/riscv-wally into main

This commit is contained in:
kipmacsaigoren 2021-10-04 12:28:03 -05:00
commit b72e94badf
35 changed files with 643 additions and 480 deletions

View File

@ -66,6 +66,10 @@
`define ICACHE_WAYSIZEINBYTES 4096 `define ICACHE_WAYSIZEINBYTES 4096
`define ICACHE_BLOCKLENINBITS 256 `define ICACHE_BLOCKLENINBITS 256
// Integer Divider Configuration
// DIV_BITSPERCYCLE must be 1, 2, or 4
`define DIV_BITSPERCYCLE 4
// Legal number of PMP entries are 0, 16, or 64 // Legal number of PMP entries are 0, 16, or 64
`define PMP_ENTRIES 16 `define PMP_ENTRIES 16

View File

@ -66,6 +66,10 @@
`define ICACHE_WAYSIZEINBYTES 4096 `define ICACHE_WAYSIZEINBYTES 4096
`define ICACHE_BLOCKLENINBITS 256 `define ICACHE_BLOCKLENINBITS 256
// Integer Divider Configuration
// DIV_BITSPERCYCLE must be 1, 2, or 4
`define DIV_BITSPERCYCLE 4
// Legal number of PMP entries are 0, 16, or 64 // Legal number of PMP entries are 0, 16, or 64
`define PMP_ENTRIES 16 `define PMP_ENTRIES 16

View File

@ -65,6 +65,13 @@
`define ICACHE_WAYSIZEINBYTES 4096 `define ICACHE_WAYSIZEINBYTES 4096
`define ICACHE_BLOCKLENINBITS 256 `define ICACHE_BLOCKLENINBITS 256
// Integer Divider Configuration
// DIV_BITSPERCYCLE must be 1, 2, or 4
`define DIV_BITSPERCYCLE 4
// Legal number of PMP entries are 0, 16, or 64
`define PMP_ENTRIES 16
// Address space // Address space
`define RESET_VECTOR 64'h00000000000100b0 `define RESET_VECTOR 64'h00000000000100b0

View File

@ -66,6 +66,10 @@
`define ICACHE_WAYSIZEINBYTES 4096 `define ICACHE_WAYSIZEINBYTES 4096
`define ICACHE_BLOCKLENINBITS 256 `define ICACHE_BLOCKLENINBITS 256
// Integer Divider Configuration
// DIV_BITSPERCYCLE must be 1, 2, or 4
`define DIV_BITSPERCYCLE 4
// Legal number of PMP entries are 0, 16, or 64 // Legal number of PMP entries are 0, 16, or 64
`define PMP_ENTRIES 64 `define PMP_ENTRIES 64

View File

@ -64,6 +64,10 @@
`define ICACHE_WAYSIZEINBYTES 4096 `define ICACHE_WAYSIZEINBYTES 4096
`define ICACHE_BLOCKLENINBITS 256 `define ICACHE_BLOCKLENINBITS 256
// Integer Divider Configuration
// DIV_BITSPERCYCLE must be 1, 2, or 4
`define DIV_BITSPERCYCLE 4
// Legal number of PMP entries are 0, 16, or 64 // Legal number of PMP entries are 0, 16, or 64
`define PMP_ENTRIES 16 `define PMP_ENTRIES 16

View File

@ -64,6 +64,10 @@
`define ICACHE_WAYSIZEINBYTES 4096 `define ICACHE_WAYSIZEINBYTES 4096
`define ICACHE_BLOCKLENINBITS 256 `define ICACHE_BLOCKLENINBITS 256
// Integer Divider Configuration
// DIV_BITSPERCYCLE must be 1, 2, or 4
`define DIV_BITSPERCYCLE 4
// Legal number of PMP entries are 0, 16, or 64 // Legal number of PMP entries are 0, 16, or 64
`define PMP_ENTRIES 16 `define PMP_ENTRIES 16

View File

@ -66,6 +66,13 @@
`define ICACHE_WAYSIZEINBYTES 4096 `define ICACHE_WAYSIZEINBYTES 4096
`define ICACHE_BLOCKLENINBITS 256 `define ICACHE_BLOCKLENINBITS 256
// Integer Divider Configuration
// DIV_BITSPERCYCLE must be 1, 2, or 4
`define DIV_BITSPERCYCLE 4
// Legal number of PMP entries are 0, 16, or 64
`define PMP_ENTRIES 16
// Address space // Address space
`define RESET_VECTOR 64'h0000000000000000 `define RESET_VECTOR 64'h0000000000000000

View File

@ -65,6 +65,10 @@
`define ICACHE_WAYSIZEINBYTES 4096 `define ICACHE_WAYSIZEINBYTES 4096
`define ICACHE_BLOCKLENINBITS 256 `define ICACHE_BLOCKLENINBITS 256
// Integer Divider Configuration
// DIV_BITSPERCYCLE must be 1, 2, or 4
`define DIV_BITSPERCYCLE 1
// Legal number of PMP entries are 0, 16, or 64 // Legal number of PMP entries are 0, 16, or 64
`define PMP_ENTRIES 64 `define PMP_ENTRIES 64

View File

@ -66,6 +66,10 @@
`define ICACHE_WAYSIZEINBYTES 4096 `define ICACHE_WAYSIZEINBYTES 4096
`define ICACHE_BLOCKLENINBITS 256 `define ICACHE_BLOCKLENINBITS 256
// Integer Divider Configuration
// DIV_BITSPERCYCLE must be 1, 2, or 4
`define DIV_BITSPERCYCLE 4
// Legal number of PMP entries are 0, 16, or 64 // Legal number of PMP entries are 0, 16, or 64
`define PMP_ENTRIES 64 `define PMP_ENTRIES 64

View File

@ -64,6 +64,13 @@
`define ICACHE_WAYSIZEINBYTES 4096 `define ICACHE_WAYSIZEINBYTES 4096
`define ICACHE_BLOCKLENINBITS 256 `define ICACHE_BLOCKLENINBITS 256
// Integer Divider Configuration
// DIV_BITSPERCYCLE must be 1, 2, or 4
`define DIV_BITSPERCYCLE 4
// Legal number of PMP entries are 0, 16, or 64
`define PMP_ENTRIES 64
// Address space // Address space
`define RESET_VECTOR 64'h0000000080000000 `define RESET_VECTOR 64'h0000000080000000

View File

@ -1,9 +1,5 @@
echo "Warning: this script will only work if your repo is on Tera" echo "Warning: this script will only work if your repo is on Tera"
ln -s /courses/e190ax/buildroot_boot/parsedCSRs.txt parsedCSRs.txt ln -s /courses/e190ax/buildroot_boot/all.txt all.txt
ln -s /courses/e190ax/buildroot_boot/parsedMemRead.txt parsedMemRead.txt
ln -s /courses/e190ax/buildroot_boot/parsedMemWrite.txt parsedMemWrite.txt
ln -s /courses/e190ax/buildroot_boot/parsedPC.txt parsedPC.txt
ln -s /courses/e190ax/buildroot_boot/parsedRegs.txt parsedRegs.txt
ln -s /courses/e190ax/buildroot_boot/bootmem.txt bootmem.txt ln -s /courses/e190ax/buildroot_boot/bootmem.txt bootmem.txt
ln -s /courses/e190ax/buildroot_boot/ram.txt ram.txt ln -s /courses/e190ax/buildroot_boot/ram.txt ram.txt
echo "Done!" echo "Done!"

View File

@ -1,10 +1,6 @@
# This could be nice to use if you want to mess with the testvectors # This could be nice to use if you want to mess with the testvectors
# without corrupting the stable copies on Tera. # without corrupting the stable copies on Tera.
unlink parsedCSRs.txt unlink all.txt
unlink parsedMemRead.txt
unlink parsedMemWrite.txt
unlink parsedPC.txt
unlink parsedRegs.txt
unlink bootmem.txt unlink bootmem.txt
unlink ram.txt unlink ram.txt
echo "Done!" echo "Done!"

View File

@ -0,0 +1,35 @@
#!/bin/bash
# Oftentimes this script runs so long you'll go to sleep.
# But you don't want the script to die when your computer goes to sleep.
# So consider invoking this with nohup (i.e. "nohup ./logAllBuildroot.sh")
# You can run "tail -f nohup.out" to see what would've
# outputted to the terminal if you didn't use nohup
# use on tera.
customQemu="/courses/e190ax/qemu_sim/rv64_initrd/qemu_experimental/qemu/build/qemu-system-riscv64"
# use on other systems
#customQemu="qemu-system-riscv64"
instrs=50000000
imageDir="../buildroot-image-output"
outDir="../linux-testvectors/checkpoint$instrs"
intermedDir="$outDir/intermediate-outputs"
read -p "This scripts is going to create a checkpoint at $instrs instrs.
Is that what you wanted? (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]
then
mkdir -p $outDir
mkdir -p $intermedDir
# Simulate QEMU, parse QEMU trace, run GDB script which logs a bunch of data at the checkpoint
($customQemu -M virt -nographic -bios $imageDir/fw_jump.elf -kernel $imageDir/Image -append "root=/dev/vda ro" -initrd $imageDir/rootfs.cpio -rtc clock=vm -icount shift=1 -d nochain,cpu,in_asm -serial /dev/null -singlestep -gdb tcp::1240 -S 2>&1 1>&2 | ./parse_qemu.py | ./parseNew.py | ./remove_dup.awk > $intermedDir/rawTrace.txt) & riscv64-unknown-elf-gdb -x ./checkpoint.gdb -ex "createCheckpoint $instrs \"$intermedDir\""
# Post-Process GDB outputs
./parseState.py "$outDir"
./fix_mem.py "$intermedDir/ramGDB.txt" "$outDir/ram.txt"
else
echo "You can change the number of instructions by editing the \"instrs\" variable in this script."
echo "Have a nice day!"
fi

View File

@ -0,0 +1,56 @@
define createCheckpoint
# GDB config
set pagination off
set logging overwrite on
set logging redirect on
set confirm off
# QEMU must also use TCP port 1240
target extended-remote :1240
# QEMU Config
maintenance packet Qqemu.PhyMemMode:1
# Argument Parsing
set $statePath=$arg1
set $ramPath=$arg1
eval "set $statePath = \"%s/stateGDB.txt\"", $statePath
eval "set $ramPath = \"%s/ramGDB.txt\"", $ramPath
# Symbol file
file ../buildroot-image-output/vmlinux
# Step over reset vector into actual code
stepi 1000
# Set breakpoint for where to stop
b do_idle
# Proceed to checkpoint
printf "GDB proceeding to checkpoint at %d instrs\n", $arg0
stepi $arg0-1000
printf "Reached checkpoint at %d instrs\n", $arg0
# Log all registers to a file
printf "GDB storing state to %s\n", $statePath
eval "set logging file %s", $statePath
set logging on
info all-registers
set logging off
# Log main memory to a file
printf "GDB storing RAM to %s\n", $ramPath
eval "set logging file %s", $ramPath
set logging on
x/134217728xb 0x80000000
set logging off
# Continue to checkpoint; stop on the 3rd time
# Should reach login prompt by then
printf "GDB continuing execution to login prompt\n"
ignore 1 2
c
printf "GDB reached login prompt!\n"
kill
q
end

View File

@ -6,9 +6,10 @@ if len(sys.argv) != 3:
inputFile = sys.argv[1] inputFile = sys.argv[1]
outputFile = sys.argv[2] outputFile = sys.argv[2]
if not os.path.exists(inputFile): if not os.path.exists(inputFile):
sys.exit('Error input file '+inputFile+'not found') sys.exit('Error input file '+inputFile+' not found')
print('Translating '+os.path.basename(inputFile)+' to '+os.path.basename(outputFile)) print('Begin translating '+os.path.basename(inputFile)+' to '+os.path.basename(outputFile))
with open(inputFile, 'r') as f: with open(inputFile, 'r') as f:
with open(outputFile, 'w') as w: with open(outputFile, 'w') as w:
for l in f: for l in f:
w.write(f'{"".join([x[2:] for x in l.split()[:0:-1]])}\n') w.write(f'{"".join([x[2:] for x in l.split()[:0:-1]])}\n')
print('Finished translating '+os.path.basename(inputFile)+' to '+os.path.basename(outputFile)+'!')

View File

@ -140,6 +140,7 @@ CurrentInstr = ['0', '0', None, 'other', {'zero': 0, 'ra': 0, 'sp': 0, 'gp': 0,
lineNum = 0 lineNum = 0
StartLine = 0 StartLine = 0
EndLine = 0 EndLine = 0
numInstrs = 0
#instructions = [] #instructions = []
MemAdr = 0 MemAdr = 0
lines = [] lines = []
@ -195,6 +196,10 @@ for line in fileinput.input('-'):
lines.clear() lines.clear()
#instructions.append(MoveInstrToRegWriteLst) #instructions.append(MoveInstrToRegWriteLst)
PrintInstr(MoveInstrToRegWriteLst, sys.stdout) PrintInstr(MoveInstrToRegWriteLst, sys.stdout)
numInstrs +=1
if (numInstrs % 1e4 == 0):
sys.stderr.write('Trace parser reached '+str(numInstrs/1.0e6)+' million instrs.\n')
sys.stderr.flush()
lineNum += 1 lineNum += 1

View File

@ -0,0 +1,79 @@
#! /usr/bin/python3
import sys, os
################
# Helper Funcs #
################
def tokenize(string):
tokens = []
token = ''
whitespace = 0
prevWhitespace = 0
for char in string:
prevWhitespace = whitespace
whitespace = char in ' \t\n'
if (whitespace):
if ((not prevWhitespace) and (token != '')):
tokens.append(token)
token = ''
else:
token = token + char
return tokens
#############
# Main Code #
#############
print("Begin parsing state.")
# Parse Args
if len(sys.argv) != 2:
sys.exit('Error parseState.py expects 1 arg:\n parseState.py <path_to_checkpoint_dir>')
outDir = sys.argv[1]+'/'
stateGDBpath = outDir+'intermediate-outputs/stateGDB.txt'
if not os.path.exists(stateGDBpath):
sys.exit('Error input file '+stateGDBpath+'not found')
listCSRs = ['hpmcounter','pmpcfg','pmpaddr']
singleCSRs = ['mip','mie','mscratch','mcause','mepc','mtvec','medeleg','mideleg','mcounteren','sscratch','scause','sepc','stvec','sedeleg','sideleg','scounteren','satp','mstatus']
# Initialize List CSR files to empty
# (because later we'll open them in append mode)
for csr in listCSRs:
outFileName = 'checkpoint-'+csr.upper()
outFile = open(outDir+outFileName, 'w')
outFile.close()
# Initial State for Main Loop
currState = 'regFile'
regFileIndex = 0
outFileName = 'checkpoint-regfile.txt'
outFile = open(outDir+outFileName, 'w')
# Main Loop
with open(stateGDBpath, 'r') as stateGDB:
for line in stateGDB:
line = tokenize(line)
name = line[0]
val = line[1][2:]
if (currState == 'regFile'):
if (regFileIndex == 0 and name != 'zero'):
print('Whoops! Expected regFile registers to come first, starting with zero')
exit(1)
outFile.write(val+'\n')
regFileIndex += 1
if (regFileIndex == 32):
outFile.close()
currState = 'CSRs'
elif (currState == 'CSRs'):
if name in singleCSRs:
outFileName = 'checkpoint-'+name.upper()
outFile = open(outDir+outFileName, 'w')
outFile.write(val+'\n')
outFile.close()
elif name.strip('0123456789') in listCSRs:
outFileName = 'checkpoint-'+name.upper().strip('0123456789')
outFile = open(outDir+outFileName, 'a')
outFile.write(val+'\n')
outFile.close()
print("Finished parsing state!")

View File

@ -176,7 +176,7 @@ add wave -noupdate -group muldiv /testbench/dut/hart/mdu/FlushM
add wave -noupdate -group muldiv /testbench/dut/hart/mdu/FlushW add wave -noupdate -group muldiv /testbench/dut/hart/mdu/FlushW
add wave -noupdate -group muldiv /testbench/dut/hart/mdu/MulDivResultW add wave -noupdate -group muldiv /testbench/dut/hart/mdu/MulDivResultW
add wave -noupdate -group muldiv /testbench/dut/hart/mdu/genblk1/div/start add wave -noupdate -group muldiv /testbench/dut/hart/mdu/genblk1/div/start
add wave -noupdate -group muldiv /testbench/dut/hart/mdu/DivDoneE add wave -noupdate -group muldiv /testbench/dut/hart/mdu/DivDoneM
add wave -noupdate -group muldiv /testbench/dut/hart/mdu/DivBusyE add wave -noupdate -group muldiv /testbench/dut/hart/mdu/DivBusyE
add wave -noupdate -group divider /testbench/dut/hart/mdu/genblk1/div/fsm1/CURRENT_STATE add wave -noupdate -group divider /testbench/dut/hart/mdu/genblk1/div/fsm1/CURRENT_STATE
add wave -noupdate -group divider /testbench/dut/hart/mdu/genblk1/div/N add wave -noupdate -group divider /testbench/dut/hart/mdu/genblk1/div/N

View File

@ -43,7 +43,7 @@ view wave
do ./wave-dos/peripheral-waves.do do ./wave-dos/peripheral-waves.do
-- Run the Simulation -- Run the Simulation
#run 5000 #run 3600
run -all run -all
#quit #quit
noview ../testbench/testbench-imperas.sv noview ../testbench/testbench-imperas.sv

View File

@ -35,6 +35,11 @@ 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/SrcBE
add wave -hex /testbench/dut/hart/ieu/dp/ALUResultE add wave -hex /testbench/dut/hart/ieu/dp/ALUResultE
#add wave /testbench/dut/hart/ieu/dp/PCSrcE #add wave /testbench/dut/hart/ieu/dp/PCSrcE
add wave /testbench/dut/hart/mdu/genblk1/div/StartDivideE
add wave /testbench/dut/hart/mdu/DivBusyE
add wave -hex /testbench/dut/hart/mdu/genblk1/div/RemM
add wave -hex /testbench/dut/hart/mdu/genblk1/div/QuotM
add wave -divider add wave -divider
add wave -hex /testbench/dut/hart/ifu/PCM add wave -hex /testbench/dut/hart/ifu/PCM
add wave -hex /testbench/dut/hart/ifu/InstrM add wave -hex /testbench/dut/hart/ifu/InstrM
@ -48,9 +53,9 @@ add wave -hex /testbench/dut/hart/lsu/dcache/ReadDataM
add wave -hex /testbench/dut/hart/ebu/ReadDataM add wave -hex /testbench/dut/hart/ebu/ReadDataM
add wave -divider add wave -divider
add wave -hex /testbench/PCW add wave -hex /testbench/PCW
add wave -hex /testbench/InstrW #add wave -hex /testbench/InstrW
add wave -hex /testbench/dut/hart/ieu/c/InstrValidW add wave -hex /testbench/dut/hart/ieu/c/InstrValidW
add wave /testbench/InstrWName #add wave /testbench/InstrWName
add wave -hex /testbench/dut/hart/ReadDataW add wave -hex /testbench/dut/hart/ReadDataW
add wave -hex /testbench/dut/hart/ieu/dp/ResultW add wave -hex /testbench/dut/hart/ieu/dp/ResultW
add wave -hex /testbench/dut/hart/ieu/dp/RegWriteW add wave -hex /testbench/dut/hart/ieu/dp/RegWriteW

View File

@ -179,7 +179,7 @@ add wave -noupdate -group muldiv /testbench/dut/hart/mdu/FlushM
add wave -noupdate -group muldiv /testbench/dut/hart/mdu/FlushW add wave -noupdate -group muldiv /testbench/dut/hart/mdu/FlushW
add wave -noupdate -group muldiv /testbench/dut/hart/mdu/MulDivResultW add wave -noupdate -group muldiv /testbench/dut/hart/mdu/MulDivResultW
add wave -noupdate -group muldiv /testbench/dut/hart/mdu/genblk1/div/start add wave -noupdate -group muldiv /testbench/dut/hart/mdu/genblk1/div/start
add wave -noupdate -group muldiv /testbench/dut/hart/mdu/DivDoneE add wave -noupdate -group muldiv /testbench/dut/hart/mdu/DivDoneM
add wave -noupdate -group muldiv /testbench/dut/hart/mdu/DivBusyE add wave -noupdate -group muldiv /testbench/dut/hart/mdu/DivBusyE
add wave -noupdate -group divider /testbench/dut/hart/mdu/genblk1/div/fsm1/CURRENT_STATE add wave -noupdate -group divider /testbench/dut/hart/mdu/genblk1/div/fsm1/CURRENT_STATE
add wave -noupdate -group divider /testbench/dut/hart/mdu/genblk1/div/N add wave -noupdate -group divider /testbench/dut/hart/mdu/genblk1/div/N

View File

@ -0,0 +1,35 @@
///////////////////////////////////////////
// adder.sv
//
// Written: David_Harris@hmc.edu 2 October 2021
// Modified:
//
// Purpose: Adder
//
// 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 adder #(parameter WIDTH=8) (
input logic [WIDTH-1:0] a, b,
output logic [WIDTH-1:0] y);
assign y = a + b;
endmodule

View File

@ -0,0 +1,34 @@
///////////////////////////////////////////
// neg.sv
//
// Written: David_Harris@hmc.edu 28 September 2021
// Modified:
//
// Purpose: 2's complement negator
//
// 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 neg #(parameter WIDTH = 8) (
input logic [WIDTH-1:0] a,
output logic [WIDTH-1:0] y);
assign y = ~a + 1;
endmodule

View File

@ -30,9 +30,10 @@ module forward(
input logic [4:0] Rs1D, Rs2D, Rs1E, Rs2E, RdE, RdM, RdW, input logic [4:0] Rs1D, Rs2D, Rs1E, Rs2E, RdE, RdM, RdW,
input logic MemReadE, MulDivE, CSRReadE, input logic MemReadE, MulDivE, CSRReadE,
input logic RegWriteM, RegWriteW, input logic RegWriteM, RegWriteW,
input logic DivDoneE, DivBusyE, input logic DivBusyE,
input logic FWriteIntE, FWriteIntM, FWriteIntW, input logic FWriteIntE, FWriteIntM, FWriteIntW,
input logic SCE, input logic SCE,
input logic StallD,
// Forwarding controls // Forwarding controls
output logic [1:0] ForwardAE, ForwardBE, output logic [1:0] ForwardAE, ForwardBE,
output logic FPUStallD, LoadStallD, MulDivStallD, CSRRdStallD output logic FPUStallD, LoadStallD, MulDivStallD, CSRRdStallD
@ -53,7 +54,7 @@ module forward(
// Stall on dependent operations that finish in Mem Stage and can't bypass in time // Stall on dependent operations that finish in Mem Stage and can't bypass in time
assign FPUStallD = FWriteIntE & ((Rs1D == RdE) | (Rs2D == RdE)); assign FPUStallD = FWriteIntE & ((Rs1D == RdE) | (Rs2D == RdE));
assign LoadStallD = (MemReadE|SCE) & ((Rs1D == RdE) | (Rs2D == RdE)); assign LoadStallD = (MemReadE|SCE) & ((Rs1D == RdE) | (Rs2D == RdE));
assign MulDivStallD = MulDivE & ((Rs1D == RdE) | (Rs2D == RdE)) | MulDivE | DivBusyE; // *** extend with stalls for divide assign MulDivStallD = MulDivE & ((Rs1D == RdE) | (Rs2D == RdE));
assign CSRRdStallD = CSRReadE & ((Rs1D == RdE) | (Rs2D == RdE)); assign CSRRdStallD = CSRReadE & ((Rs1D == RdE) | (Rs2D == RdE));
endmodule endmodule

View File

@ -73,7 +73,6 @@ module ieu (
input logic FlushD, FlushE, FlushM, FlushW, input logic FlushD, FlushE, FlushM, FlushW,
output logic FPUStallD, LoadStallD, MulDivStallD, CSRRdStallD, output logic FPUStallD, LoadStallD, MulDivStallD, CSRRdStallD,
output logic PCSrcE, output logic PCSrcE,
input logic DivDoneE,
input logic DivBusyE, input logic DivBusyE,
output logic CSRReadM, CSRWriteM, PrivilegedM, output logic CSRReadM, CSRWriteM, PrivilegedM,
output logic CSRWritePendingDEM, output logic CSRWritePendingDEM,

View File

@ -278,13 +278,14 @@ module otf #(parameter WIDTH=8)
assign QMstar = R1Q; assign QMstar = R1Q;
endmodule // otf8 endmodule // otf8
/*
module adder #(parameter WIDTH=8) (input logic [WIDTH-1:0] a, b, module adder #(parameter WIDTH=8) (input logic [WIDTH-1:0] a, b,
output logic [WIDTH-1:0] y); output logic [WIDTH-1:0] y);
assign y = a + b; assign y = a + b;
endmodule // adder endmodule // adder
*/
module fa (input logic a, b, c, output logic sum, carry); module fa (input logic a, b, c, output logic sum, carry);

View File

@ -1,76 +0,0 @@
///////////////////////////////////////////
// intdiv_restoring.sv
//
// Written: David_Harris@hmc.edu 12 September 2021
// Modified:
//
// Purpose: Restoring integer division using a shift register a subtractor
//
// 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 intdiv_restoring (
input logic clk,
input logic reset,
input logic signedDivide,
input logic start,
input logic [`XLEN-1:0] X, D,
output logic busy, done,
output logic [`XLEN-1:0] Q, REM
);
logic [`XLEN-1:0] W, Win, Wshift, Wprime, Wnext, XQ, XQin, XQshift;
logic qi; // curent quotient bit
localparam STEPBITS = $clog2(`XLEN);
logic [STEPBITS:0] step;
logic div0;
// restoring division
mux2 #(`XLEN) wmux(W, 0, start, Win);
mux2 #(`XLEN) xmux(0, X, start, XQin);
assign {Wshift, XQshift} = {Win[`XLEN-2:0], XQin, qi};
assign {qi, Wprime} = Wshift - D; // subtractor, carry out determines quotient bit
mux2 #(`XLEN) wrestoremux(Wshift, Wprime, qi, Wnext);
flopen #(`XLEN) wreg(clk, busy, Wnext, W);
flopen #(`XLEN) xreg(clk, busy, XQshift, XQ);
// outputs
// *** sign extension, handling W instructions
assign div0 = (D == 0);
mux2 #(`XLEN) qmux(XQ, {`XLEN{1'b1}}, div0, Q); // Q taken from XQ register, or all 1s when dividing by zero
mux2 #(`XLEN) remmux(W, X, div0, REM); // REM taken from W register, or from X when dividing by zero
// busy logic
always_ff @(posedge clk)
if (start) begin
busy = 1; done = 0; step = 0;
end else if (busy) begin
step = step + 1;
if (step[STEPBITS] | div0) begin // *** early terminate on division by 0
step = 0;
busy = 0;
done = 1;
end
end else if (done) begin
done = 0;
end
endmodule // muldiv

View File

@ -0,0 +1,134 @@
///////////////////////////////////////////
// intdivrestoring.sv
//
// Written: David_Harris@hmc.edu 12 September 2021
// Modified:
//
// Purpose: Restoring integer division using a shift register and subtractor
//
// 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"
/* verilator lint_off UNOPTFLAT */
module intdivrestoring (
input logic clk,
input logic reset,
input logic StallM, FlushM,
input logic SignedDivideE, W64E,
input logic StartDivideE,
input logic [`XLEN-1:0] SrcAE, SrcBE,
output logic BusyE, DivDoneM,
output logic [`XLEN-1:0] QuotM, RemM
);
logic [`XLEN-1:0] WE[`DIV_BITSPERCYCLE:0];
logic [`XLEN-1:0] XQE[`DIV_BITSPERCYCLE:0];
logic [`XLEN-1:0] DSavedE, XSavedE, XSavedM, DinE, XinE, DnE, DAbsBE, XnE, XInitE, WM, XQM, WnM, XQnM;
localparam STEPBITS = $clog2(`XLEN/`DIV_BITSPERCYCLE);
logic [STEPBITS:0] step;
logic Div0E, Div0M;
logic DivInitE, SignXE, SignXM, SignDE, SignDM, NegWM, NegQM;
logic SignedDivideM;
// save inputs on the negative edge of the execute clock.
// This is unusual practice, but the inputs are not guaranteed to be stable due to some hazard and forwarding logic.
// Saving the inputs is the most hardware-efficient way to fix the issue.
flopen #(`XLEN) xsavereg(~clk, StartDivideE, SrcAE, XSavedE);
flopen #(`XLEN) dsavereg(~clk, StartDivideE, SrcBE, DSavedE);
// Handle sign extension for W-type instructions
generate
if (`XLEN == 64) begin // RV64 has W-type instructions
mux2 #(`XLEN) xinmux(XSavedE, {XSavedE[31:0], 32'b0}, W64E, XinE);
mux2 #(`XLEN) dinmux(DSavedE, {{32{DSavedE[31]&SignedDivideE}}, DSavedE[31:0]}, W64E, DinE);
end else begin // RV32 has no W-type instructions
assign XinE = XSavedE;
assign DinE = DSavedE;
end
endgenerate
// Extract sign bits and check fo division by zero
assign SignDE = DinE[`XLEN-1];
assign SignXE = XinE[`XLEN-1];
assign Div0E = (DinE == 0);
// pipeline registers
flopenrc #(1) SignedDivideMReg(clk, reset, FlushM, ~StallM, SignedDivideE, SignedDivideM);
flopenrc #(1) Div0eMReg(clk, reset, FlushM, ~StallM, Div0E, Div0M);
flopenrc #(1) SignDMReg(clk, reset, FlushM, ~StallM, SignDE, SignDM);
flopenrc #(1) SignXMReg(clk, reset, FlushM, ~StallM, SignXE, SignXM);
flopenrc #(`XLEN) XSavedMReg(clk, reset, FlushM, ~StallM, XSavedE, XSavedM); // is this truly necessary?
// Take absolute value for signed operations, and negate D to handle subtraction in divider stages
neg #(`XLEN) negd(DinE, DnE);
mux2 #(`XLEN) dabsmux(DnE, DinE, SignedDivideE & SignDE, DAbsBE); // take absolute value for signed operations, and negate for subtraction setp
neg #(`XLEN) negx(XinE, XnE);
mux2 #(`XLEN) xabsmux(XinE, XnE, SignedDivideE & SignXE, XInitE); // need original X as remainder if doing divide by 0
// initialization multiplexers on first cycle of operation (one cycle after start is asserted)
mux2 #(`XLEN) wmux(WM, {`XLEN{1'b0}}, DivInitE, WE[0]);
mux2 #(`XLEN) xmux(XQM, XInitE, DivInitE, XQE[0]);
// one copy of divstep for each bit produced per cycle
generate
genvar i;
for (i=0; i<`DIV_BITSPERCYCLE; i = i+1)
intdivrestoringstep divstep(WE[i], XQE[i], DAbsBE, WE[i+1], XQE[i+1]);
endgenerate
// registers after division steps
flopen #(`XLEN) wreg(clk, BusyE, WE[`DIV_BITSPERCYCLE], WM);
flopen #(`XLEN) xreg(clk, BusyE, XQE[`DIV_BITSPERCYCLE], XQM);
// Output selection logic in Memory Stage
// On final setp of signed operations, negate outputs as needed
assign NegWM = SignedDivideM & SignXM; // Remainder should have same sign as X
assign NegQM = SignedDivideM & (SignXM ^ SignDM); // Quotient should be negative if one operand is positive and the other is negative
neg #(`XLEN) wneg(WM, WnM);
neg #(`XLEN) qneg(XQM, XQnM);
// Select appropriate output: normal, negated, or for divide by zero
mux3 #(`XLEN) qmux(XQM, XQnM, {`XLEN{1'b1}}, {Div0M, NegQM}, QuotM); // Q taken from XQ register, negated if necessary, or all 1s when dividing by zero
mux3 #(`XLEN) remmux(WM, WnM, XSavedM, {Div0M, NegWM}, RemM); // REM taken from W register, negated if necessary, or from X when dividing by zero
// Divider FSM to sequence Init, Busy, and Done
always_ff @(posedge clk)
if (reset) begin
BusyE = 0; DivDoneM = 0; step = 0; DivInitE = 0;
end else if (StartDivideE & ~StallM) begin
if (Div0E) DivDoneM = 1;
else begin
BusyE = 1; step = 0; DivInitE = 1;
end
end else if (BusyE & ~DivDoneM) begin // pause one cycle at beginning of signed operations for absolute value
DivInitE = 0;
step = step + 1;
if (step[STEPBITS] | (`XLEN==64) & W64E & step[STEPBITS-1]) begin // complete in half the time for W-type instructions
step = 0;
BusyE = 0;
DivDoneM = 1;
end
end else if (DivDoneM) begin
DivDoneM = 0;
BusyE = 0;
end
endmodule
/* verilator lint_on UNOPTFLAT */

View File

@ -0,0 +1,43 @@
///////////////////////////////////////////
// intdivrestoringstep.sv
//
// Written: David_Harris@hmc.edu 2 October 2021
// Modified:
//
// Purpose: Restoring integer division using a shift register and subtractor
//
// 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"
/* verilator lint_off UNOPTFLAT */
module intdivrestoringstep(
input logic [`XLEN-1:0] W, XQ, DAbsB,
output logic [`XLEN-1:0] WOut, XQOut);
logic [`XLEN-1:0] WShift, WPrime;
logic qi, qib;
assign {WShift, XQOut} = {W[`XLEN-2:0], XQ, qi}; // shift W and X/Q left, insert quotient bit at bottom
adder #(`XLEN+1) wdsub({1'b0, WShift}, {1'b1, DAbsB}, {qib, WPrime}); // effective subtractor, carry out determines quotient bit
assign qi = ~qib;
mux2 #(`XLEN) wrestoremux(WShift, WPrime, qi, WOut); // if quotient is zero, restore W
endmodule
/* verilator lint_on UNOPTFLAT */

View File

@ -31,12 +31,11 @@ module muldiv (
input logic [31:0] InstrD, input logic [31:0] InstrD,
// Execute Stage interface // Execute Stage interface
input logic [`XLEN-1:0] SrcAE, SrcBE, input logic [`XLEN-1:0] SrcAE, SrcBE,
input logic [2:0] Funct3E, input logic [2:0] Funct3E, Funct3M,
input logic MulDivE, W64E, input logic MulDivE, W64E,
// Writeback stage // Writeback stage
output logic [`XLEN-1:0] MulDivResultW, output logic [`XLEN-1:0] MulDivResultW,
// Divide Done // Divide Done
output logic DivDoneE,
output logic DivBusyE, output logic DivBusyE,
// hazards // hazards
input logic StallE, StallM, StallW, FlushM, FlushW input logic StallE, StallM, StallW, FlushM, FlushW
@ -45,104 +44,54 @@ module muldiv (
generate generate
if (`M_SUPPORTED) begin if (`M_SUPPORTED) begin
logic [`XLEN-1:0] MulDivResultE, MulDivResultM; logic [`XLEN-1:0] MulDivResultE, MulDivResultM;
logic [`XLEN-1:0] PrelimResultE; logic [`XLEN-1:0] PrelimResultM;
logic [`XLEN-1:0] QuotE, RemE; logic [`XLEN-1:0] QuotM, RemM;
logic [`XLEN*2-1:0] ProdE; logic [`XLEN*2-1:0] ProdE, ProdM;
logic enable_q; logic StartDivideE, BusyE, DivDoneM;
logic [2:0] Funct3E_Q; logic SignedDivideE;
logic div0error; // ***unused logic W64M;
logic [`XLEN-1:0] N, D;
logic [`XLEN-1:0] Num0, Den0;
logic gclk;
logic DivStartE;
logic startDivideE;
logic signedDivide;
// Multiplier // Multiplier
mul mul(.*); mul mul(.*);
flopenrc #(`XLEN*2) ProdMReg(clk, reset, FlushM, ~StallM, ProdE, ProdM);
// Divide // Divide
// Start a divide when a new division instruction is received and the divider isn't already busy or finishing
assign StartDivideE = MulDivE & Funct3E[2] & ~BusyE & ~DivDoneM;
assign DivBusyE = StartDivideE | BusyE;
assign SignedDivideE = ~Funct3E[0];
intdivrestoring div(.clk, .reset, .StallM, .FlushM,
.SignedDivideE, .W64E, .StartDivideE, .SrcAE, .SrcBE, .BusyE, .DivDoneM, .QuotM, .RemM);
// *** replace this clock gater // Result multiplexer
always @(negedge clk) begin
enable_q <= ~StallM;
end
assign gclk = enable_q & clk;
// Handle sign extension for W-type instructions
if (`XLEN == 64) begin // RV64 has W-type instructions
assign Num0 = W64E ? {{32{SrcAE[31]&signedDivide}}, SrcAE[31:0]} : SrcAE;
assign Den0 = W64E ? {{32{SrcBE[31]&signedDivide}}, SrcBE[31:0]} : SrcBE;
end else begin // RV32 has no W-type instructions
assign Num0 = SrcAE;
assign Den0 = SrcBE;
end
// capture the Numerator/Denominator
flopenrc #(`XLEN) reg_num (.d(Num0), .q(N),
.en(startDivideE), .clear(DivDoneE),
.reset(reset), .clk(~gclk));
flopenrc #(`XLEN) reg_den (.d(Den0), .q(D),
.en(startDivideE), .clear(DivDoneE),
.reset(reset), .clk(~gclk));
assign signedDivide = (Funct3E[2]&~Funct3E[1]&~Funct3E[0]) | (Funct3E[2]&Funct3E[1]&~Funct3E[0]);
intdiv #(`XLEN) div (QuotE, RemE, DivDoneE, DivBusyE, div0error, N, D, gclk, reset, startDivideE, signedDivide);
//intdiv_restoring div(.clk, .reset, .signedDivide, .start(startDivideE), .X(N), .D(D), .busy(DivBusyE), .done(DivDoneE), .Q(QuotE), .REM(RemE));
// Added for debugging of start signal for divide
assign startDivideE = MulDivE&DivStartE&~DivBusyE;
// capture the start control signals since they are not held constant.
// *** appears to be unused
flopenrc #(3) funct3ereg (.d(Funct3E),
.q(Funct3E_Q),
.en(DivStartE),
.clear(DivDoneE),
.reset(reset),
.clk(clk));
// Select result
always_comb always_comb
case (Funct3E) case (Funct3M)
3'b000: PrelimResultE = ProdE[`XLEN-1:0]; 3'b000: PrelimResultM = ProdM[`XLEN-1:0];
3'b001: PrelimResultE = ProdE[`XLEN*2-1:`XLEN]; 3'b001: PrelimResultM = ProdM[`XLEN*2-1:`XLEN];
3'b010: PrelimResultE = ProdE[`XLEN*2-1:`XLEN]; 3'b010: PrelimResultM = ProdM[`XLEN*2-1:`XLEN];
3'b011: PrelimResultE = ProdE[`XLEN*2-1:`XLEN]; 3'b011: PrelimResultM = ProdM[`XLEN*2-1:`XLEN];
3'b100: PrelimResultE = QuotE; 3'b100: PrelimResultM = QuotM;
3'b101: PrelimResultE = QuotE; 3'b101: PrelimResultM = QuotM;
3'b110: PrelimResultE = RemE; 3'b110: PrelimResultM = RemM;
3'b111: PrelimResultE = RemE; 3'b111: PrelimResultM = RemM;
endcase // case (Funct3E)
// Start Divide process. This simplifies to DivStartE = Funct3E[2];
always_comb
case (Funct3E)
3'b000: DivStartE = 1'b0;
3'b001: DivStartE = 1'b0;
3'b010: DivStartE = 1'b0;
3'b011: DivStartE = 1'b0;
3'b100: DivStartE = 1'b1;
3'b101: DivStartE = 1'b1;
3'b110: DivStartE = 1'b1;
3'b111: DivStartE = 1'b1;
endcase endcase
// Handle sign extension for W-type instructions // Handle sign extension for W-type instructions
flopenrc #(1) W64MReg(clk, reset, FlushM, ~StallM, W64E, W64M);
if (`XLEN == 64) begin // RV64 has W-type instructions if (`XLEN == 64) begin // RV64 has W-type instructions
assign MulDivResultE = W64E ? {{32{PrelimResultE[31]}}, PrelimResultE[31:0]} : PrelimResultE; assign MulDivResultM = W64M ? {{32{PrelimResultM[31]}}, PrelimResultM[31:0]} : PrelimResultM;
end else begin // RV32 has no W-type instructions end else begin // RV32 has no W-type instructions
assign MulDivResultE = PrelimResultE; assign MulDivResultM = PrelimResultM;
end end
flopenrc #(`XLEN) MulDivResultMReg(clk, reset, FlushM, ~StallM, MulDivResultE, MulDivResultM); // Writeback stage pipeline register
flopenrc #(`XLEN) MulDivResultWReg(clk, reset, FlushW, ~StallW, MulDivResultM, MulDivResultW); flopenrc #(`XLEN) MulDivResultWReg(clk, reset, FlushW, ~StallW, MulDivResultM, MulDivResultW);
end else begin // no M instructions supported end else begin // no M instructions supported
assign MulDivResultW = 0; assign MulDivResultW = 0;
assign DivBusyE = 0; assign DivBusyE = 0;
assign DivDoneE = 0;
end end
endgenerate endgenerate

View File

@ -88,7 +88,6 @@ module wallypipelinedhart
logic InvalidateICacheM, FlushDCacheM; logic InvalidateICacheM, FlushDCacheM;
logic PCSrcE; logic PCSrcE;
logic CSRWritePendingDEM; logic CSRWritePendingDEM;
logic DivDoneE;
logic DivBusyE; logic DivBusyE;
logic RegWriteD; logic RegWriteD;
logic LoadStallD, StoreStallD, MulDivStallD, CSRRdStallD; logic LoadStallD, StoreStallD, MulDivStallD, CSRRdStallD;

View File

@ -13,5 +13,5 @@ module instrTrackerTB(
instrNameDecTB ddec(InstrD, InstrDName); instrNameDecTB ddec(InstrD, InstrDName);
instrNameDecTB edec(InstrE, InstrEName); instrNameDecTB edec(InstrE, InstrEName);
instrNameDecTB mdec(InstrM, InstrMName); instrNameDecTB mdec(InstrM, InstrMName);
instrNameDecTB wdec(InstrW, InstrWName); instrNameDecTB wdec(InstrW, InstrWName); // *** delete this because InstrW is deleted from IFU
endmodule endmodule

View File

@ -430,7 +430,7 @@ string tests32f[] = '{
// tests = {tests64p,tests64i, tests64periph}; // tests = {tests64p,tests64i, tests64periph};
if (`C_SUPPORTED) tests = {tests, tests64ic}; if (`C_SUPPORTED) tests = {tests, tests64ic};
// else tests = {tests, tests64iNOc}; // else tests = {tests, tests64iNOc};
if (`M_SUPPORTED) tests = {tests, tests64m}; if (`M_SUPPORTED) tests = {tests64m, tests};
/* if (`F_SUPPORTED) tests = {tests64f, tests}; /* if (`F_SUPPORTED) tests = {tests64f, tests};
if (`D_SUPPORTED) tests = {tests64d, tests}; if (`D_SUPPORTED) tests = {tests64d, tests};
if (`MEM_VIRTMEM) tests = {tests64mmu, tests}; if (`MEM_VIRTMEM) tests = {tests64mmu, tests};
@ -449,7 +449,7 @@ string tests32f[] = '{
tests = {tests32priv, tests32i}; tests = {tests32priv, tests32i};
//tests = {tests32i, tests32priv}; //tests = {tests32i, tests32priv};
if (`C_SUPPORTED) tests = {tests, tests32ic}; if (`C_SUPPORTED) tests = {tests, tests32ic};
if (`M_SUPPORTED) tests = {tests, tests32m}; if (`M_SUPPORTED) tests = {tests32m, tests};
//if (`C_SUPPORTED) tests = {tests32ic, tests}; //if (`C_SUPPORTED) tests = {tests32ic, tests};
//if (`M_SUPPORTED) tests = {tests32m, tests}; //if (`M_SUPPORTED) tests = {tests32m, tests};
/* tests = {tests32i, tests32p};//,tests32periph}; *** broken at the moment /* tests = {tests32i, tests32p};//,tests32periph}; *** broken at the moment

View File

@ -161,6 +161,10 @@ string tests32f[] = '{
}; };
string tests64m[] = '{ string tests64m[] = '{
"rv64m/I-REMUW-01", "3000",
"rv64m/I-REMW-01", "3000",
"rv64m/I-DIVUW-01", "3000",
"rv64m/I-DIVW-01", "3000",
"rv64m/I-MUL-01", "3000", "rv64m/I-MUL-01", "3000",
"rv64m/I-MULH-01", "3000", "rv64m/I-MULH-01", "3000",
"rv64m/I-MULHSU-01", "3000", "rv64m/I-MULHSU-01", "3000",
@ -168,12 +172,8 @@ string tests32f[] = '{
"rv64m/I-MULW-01", "3000", "rv64m/I-MULW-01", "3000",
"rv64m/I-DIV-01", "3000", "rv64m/I-DIV-01", "3000",
"rv64m/I-DIVU-01", "3000", "rv64m/I-DIVU-01", "3000",
"rv64m/I-DIVUW-01", "3000",
"rv64m/I-DIVW-01", "3000",
"rv64m/I-REM-01", "3000", "rv64m/I-REM-01", "3000",
"rv64m/I-REMU-01", "3000", "rv64m/I-REMU-01", "3000"
"rv64m/I-REMUW-01", "3000",
"rv64m/I-REMW-01", "3000"
}; };
string tests64ic[] = '{ string tests64ic[] = '{
@ -318,14 +318,14 @@ string tests32f[] = '{
}; };
string tests32m[] = '{ string tests32m[] = '{
"rv32m/I-DIVU-01", "2000",
"rv32m/I-REMU-01", "2000",
"rv32m/I-DIV-01", "2000",
"rv32m/I-REM-01", "2000",
"rv32m/I-MUL-01", "2000", "rv32m/I-MUL-01", "2000",
"rv32m/I-MULH-01", "2000", "rv32m/I-MULH-01", "2000",
"rv32m/I-MULHSU-01", "2000", "rv32m/I-MULHSU-01", "2000",
"rv32m/I-MULHU-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[] = '{ string tests32ic[] = '{
@ -536,11 +536,11 @@ string tests32f[] = '{
tests = {tests64p,tests64i, tests64periph}; tests = {tests64p,tests64i, tests64periph};
if (`C_SUPPORTED) tests = {tests, tests64ic}; if (`C_SUPPORTED) tests = {tests, tests64ic};
else tests = {tests, tests64iNOc}; else tests = {tests, tests64iNOc};
if (`M_SUPPORTED) tests = {tests, tests64m};
if (`F_SUPPORTED) tests = {tests64f, tests}; if (`F_SUPPORTED) tests = {tests64f, tests};
if (`D_SUPPORTED) tests = {tests64d, tests}; if (`D_SUPPORTED) tests = {tests64d, tests};
if (`MEM_VIRTMEM) tests = {tests64mmu, tests}; if (`MEM_VIRTMEM) tests = {tests64mmu, tests};
if (`A_SUPPORTED) tests = {tests64a, tests}; if (`A_SUPPORTED) tests = {tests64a, tests};
if (`M_SUPPORTED) tests = {tests64m, tests};
end end
//tests = {tests64a, tests}; //tests = {tests64a, tests};
end else begin // RV32 end else begin // RV32
@ -551,12 +551,12 @@ string tests32f[] = '{
tests = tests32p; tests = tests32p;
else begin else begin
tests = {tests32i, tests32p};//,tests32periph}; *** broken at the moment tests = {tests32i, tests32p};//,tests32periph}; *** broken at the moment
if (`C_SUPPORTED % 2 == 1) tests = {tests, tests32ic}; if (`C_SUPPORTED) tests = {tests, tests32ic};
else tests = {tests, tests32iNOc}; else tests = {tests, tests32iNOc};
if (`M_SUPPORTED % 2 == 1) tests = {tests, tests32m};
if (`F_SUPPORTED) tests = {tests32f, tests}; if (`F_SUPPORTED) tests = {tests32f, tests};
if (`MEM_VIRTMEM) tests = {tests32mmu, tests}; if (`MEM_VIRTMEM) tests = {tests32mmu, tests};
if (`A_SUPPORTED) tests = {tests32a, tests}; if (`A_SUPPORTED) tests = {tests32a, tests};
if (`M_SUPPORTED) tests = {tests32m, tests};
end end
end end
end end
@ -607,9 +607,9 @@ string tests32f[] = '{
end end
// read test vectors into memory // read test vectors into memory
memfilename = {"../../imperas-riscv-tests/work/", tests[test], ".elf.memfile"}; memfilename = {"../../imperas-riscv-tests/work/", tests[test], ".elf.memfile"};
romfilename = {"../../imperas-riscv-tests/imperas-boottim.txt"}; // romfilename = {"../../imperas-riscv-tests/imperas-boottim.txt"};
$readmemh(memfilename, dut.uncore.dtim.RAM); $readmemh(memfilename, dut.uncore.dtim.RAM);
$readmemh(romfilename, dut.uncore.bootdtim.bootdtim.RAM); // $readmemh(romfilename, dut.uncore.bootdtim.bootdtim.RAM);
ProgramAddrMapFile = {"../../imperas-riscv-tests/work/", tests[test], ".elf.objdump.addr"}; ProgramAddrMapFile = {"../../imperas-riscv-tests/work/", tests[test], ".elf.objdump.addr"};
ProgramLabelMapFile = {"../../imperas-riscv-tests/work/", tests[test], ".elf.objdump.lab"}; ProgramLabelMapFile = {"../../imperas-riscv-tests/work/", tests[test], ".elf.objdump.lab"};
$display("Read memfile %s", memfilename); $display("Read memfile %s", memfilename);
@ -743,6 +743,7 @@ module riscvassertions();
// Legal number of PMP entries are 0, 16, or 64 // Legal number of PMP entries are 0, 16, or 64
initial begin initial begin
assert (`PMP_ENTRIES == 0 || `PMP_ENTRIES==16 || `PMP_ENTRIES==64) else $error("Illegal number of PMP entries: PMP_ENTRIES must be 0, 16, or 64"); assert (`PMP_ENTRIES == 0 || `PMP_ENTRIES==16 || `PMP_ENTRIES==64) else $error("Illegal number of PMP entries: PMP_ENTRIES must be 0, 16, or 64");
assert (`DIV_BITSPERCYCLE == 1 || `DIV_BITSPERCYCLE==2 || `DIV_BITSPERCYCLE==4) else $error("Illegal number of divider bits/cycle: DIV_BITSPERCYCLE must be 1, 2, or 4");
assert (`F_SUPPORTED || ~`D_SUPPORTED) else $error("Can't support double without supporting float"); assert (`F_SUPPORTED || ~`D_SUPPORTED) else $error("Can't support double without supporting float");
assert (`XLEN == 64 || ~`D_SUPPORTED) else $error("Wally does not yet support D extensions on RV32"); assert (`XLEN == 64 || ~`D_SUPPORTED) else $error("Wally does not yet support D extensions on RV32");
assert (`DCACHE_WAYSIZEINBYTES <= 4096 || `MEM_DCACHE == 0 || `MEM_VIRTMEM == 0) else $error("DCACHE_WAYSIZEINBYTES cannot exceed 4 KiB when caches and vitual memory is enabled (to prevent aliasing)"); assert (`DCACHE_WAYSIZEINBYTES <= 4096 || `MEM_DCACHE == 0 || `MEM_VIRTMEM == 0) else $error("DCACHE_WAYSIZEINBYTES cannot exceed 4 KiB when caches and vitual memory is enabled (to prevent aliasing)");

View File

@ -21,24 +21,30 @@
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS // 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 // 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. // OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// When letting Wally go for it, let wally generate own interrupts
/////////////////////////////////////////// ///////////////////////////////////////////
`include "wally-config.vh" `include "wally-config.vh"
`define DEBUG_TRACE 0 `define DEBUG_TRACE 0
`define DontHaltOnCSRMisMatch 1 // Debug Levels
// 0: don't check against QEMU
// 1: print disagreements with QEMU, but only halt on PCW disagreements
// 2: halt on any disagreement with QEMU except CSRs
// 3: halt on all disagreements with QEMU
// 4: print memory accesses whenever they happen
// 5: print everything
module testbench(); module testbench();
parameter waveOnICount = `BUSYBEAR*140000 + `BUILDROOT*6779000; // # of instructions at which to turn on waves in graphical sim parameter waveOnICount = `BUSYBEAR*140000 + `BUILDROOT*8700000; // # of instructions at which to turn on waves in graphical sim
string ProgramAddrMapFile, ProgramLabelMapFile; string ProgramAddrMapFile, ProgramLabelMapFile;
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////// DUT ///////////////////////////////////// ///////////////////////////////////// DUT /////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
logic clk, reset; logic clk, reset;
logic [`AHBW-1:0] readDataExpected; logic [`AHBW-1:0] readDataExpected;
logic [31:0] HADDR; logic [31:0] HADDR;
logic [`AHBW-1:0] HWDATA; logic [`AHBW-1:0] HWDATA;
@ -51,7 +57,6 @@ module testbench();
logic HCLK, HRESETn; logic HCLK, HRESETn;
logic [`AHBW-1:0] HRDATAEXT; logic [`AHBW-1:0] HRDATAEXT;
logic HREADYEXT, HRESPEXT; logic HREADYEXT, HRESPEXT;
logic [31:0] GPIOPinsIn; logic [31:0] GPIOPinsIn;
logic [31:0] GPIOPinsOut, GPIOPinsEn; logic [31:0] GPIOPinsOut, GPIOPinsEn;
logic UARTSin, UARTSout; logic UARTSin, UARTSout;
@ -73,9 +78,11 @@ module testbench();
// Testbench Core // Testbench Core
integer warningCount = 0; integer warningCount = 0;
integer errorCount = 0; integer errorCount = 0;
integer MIPexpected;
// P, Instr Checking // P, Instr Checking
logic [`XLEN-1:0] PCW; logic [`XLEN-1:0] PCW;
integer data_file_all; integer data_file_all;
string name;
// Write Back stage signals needed for trace compare, but don't actually // Write Back stage signals needed for trace compare, but don't actually
// exist in CPU. // exist in CPU.
@ -85,7 +92,6 @@ module testbench();
logic checkInstrW; logic checkInstrW;
//integer RegAdr; //integer RegAdr;
integer fault; integer fault;
logic TrapW; logic TrapW;
@ -130,16 +136,26 @@ module testbench();
integer NumCSRMIndex; integer NumCSRMIndex;
integer NumCSRWIndex; integer NumCSRWIndex;
integer NumCSRPostWIndex; integer NumCSRPostWIndex;
// logic CurrentInterruptForce;
logic [`XLEN-1:0] InstrCountW; logic [`XLEN-1:0] InstrCountW;
// ----------- // ------
// Error Macro // Macros
// ----------- // ------
`define ERROR \
errorCount +=1; \ `define CSRwarn(CSR) \
$display("processed %0d instructions with %0d warnings", InstrCountW, warningCount); \ begin \
$stop; $display("CSR: %s = %016x, expected = %016x", ExpectedCSRArrayW[NumCSRPostWIndex], CSR, ExpectedCSRArrayValueW[NumCSRPostWIndex]); \
if (CSR != ExpectedCSRArrayValueW[NumCSRPostWIndex]) begin \
$display("%tns, %d instrs: CSR %s = %016x, does not equal expected value %016x", $time, InstrCountW, ExpectedCSRArrayW[NumCSRPostWIndex], CSR, ExpectedCSRArrayValueW[NumCSRPostWIndex]); \
if(`DEBUG_TRACE >= 3) fault = 1; \
end \
end
`define checkEQ(NAME, VAL, EXPECTED) \
if(VAL != EXPECTED) begin \
$display("%tns, %d instrs: %s %x differs from expected %x", $time, InstrCountW, NAME, VAL, EXPECTED); \
if ((NAME == "PCW") || (`DEBUG_TRACE >= 2)) fault = 1; \
end
initial begin initial begin
data_file_all = $fopen({`LINUX_TEST_VECTORS,"all.txt"}, "r"); data_file_all = $fopen({`LINUX_TEST_VECTORS,"all.txt"}, "r");
@ -149,16 +165,11 @@ module testbench();
force dut.hart.priv.ExtIntM = 0; force dut.hart.priv.ExtIntM = 0;
end end
/* -----\/----- EXCLUDED -----\/-----
initial begin
CurrentInterruptForce = 1'b0;
end
-----/\----- EXCLUDED -----/\----- */
assign checkInstrM = dut.hart.ieu.InstrValidM & ~dut.hart.priv.trap.InstrPageFaultM & ~dut.hart.priv.trap.InterruptM & ~dut.hart.StallM; assign checkInstrM = dut.hart.ieu.InstrValidM & ~dut.hart.priv.trap.InstrPageFaultM & ~dut.hart.priv.trap.InterruptM & ~dut.hart.StallM;
// trapW will already be invalid in there was an InstrPageFault in the previous instruction. assign checkInstrW = dut.hart.ieu.InstrValidW & ~dut.hart.StallW; // trapW will already be invalid in there was an InstrPageFault in the previous instruction.
assign checkInstrW = dut.hart.ieu.InstrValidW & ~dut.hart.StallW;
// Additonal W stage registers
flopenrc #(`XLEN) MemAdrWReg(clk, reset, dut.hart.FlushW, ~dut.hart.StallW, dut.hart.ieu.dp.MemAdrM, MemAdrW); flopenrc #(`XLEN) MemAdrWReg(clk, reset, dut.hart.FlushW, ~dut.hart.StallW, dut.hart.ieu.dp.MemAdrM, MemAdrW);
flopenrc #(`XLEN) WriteDataWReg(clk, reset, dut.hart.FlushW, ~dut.hart.StallW, dut.hart.WriteDataM, WriteDataW); flopenrc #(`XLEN) WriteDataWReg(clk, reset, dut.hart.FlushW, ~dut.hart.StallW, dut.hart.WriteDataM, WriteDataW);
flopenrc #(`XLEN) PCWReg(clk, reset, dut.hart.FlushW, ~dut.hart.ieu.dp.StallW, dut.hart.ifu.PCM, PCW); flopenrc #(`XLEN) PCWReg(clk, reset, dut.hart.FlushW, ~dut.hart.ieu.dp.StallW, dut.hart.ifu.PCM, PCW);
@ -177,7 +188,8 @@ module testbench();
if (checkInstrM) begin if (checkInstrM) begin
// read 1 line of the trace file // read 1 line of the trace file
matchCount = $fgets(line, data_file_all); matchCount = $fgets(line, data_file_all);
if(`DEBUG_TRACE > 1) $display("Time %t, line %x", $time, line); if(`DEBUG_TRACE >= 5) $display("Time %t, line %x", $time, line);
// extract PC, Instr
matchCount = $sscanf(line, "%x %x %s", ExpectedPCM, ExpectedInstrM, textM); matchCount = $sscanf(line, "%x %x %s", ExpectedPCM, ExpectedInstrM, textM);
//$display("matchCount %d, PCM %x ExpectedInstrM %x textM %x", matchCount, ExpectedPCM, ExpectedInstrM, textM); //$display("matchCount %d, PCM %x ExpectedInstrM %x textM %x", matchCount, ExpectedPCM, ExpectedInstrM, textM);
@ -213,18 +225,14 @@ module testbench();
RegWriteM = ExpectedTokens[MarkerIndex]; RegWriteM = ExpectedTokens[MarkerIndex];
matchCount = $sscanf(ExpectedTokens[MarkerIndex+1], "%d", ExpectedRegAdrM); matchCount = $sscanf(ExpectedTokens[MarkerIndex+1], "%d", ExpectedRegAdrM);
matchCount = $sscanf(ExpectedTokens[MarkerIndex+2], "%x", ExpectedRegValueM); matchCount = $sscanf(ExpectedTokens[MarkerIndex+2], "%x", ExpectedRegValueM);
MarkerIndex += 3; MarkerIndex += 3;
// parse memory address, read data, and/or write data // parse memory address, read data, and/or write data
end else if(ExpectedTokens[MarkerIndex].substr(0, 2) == "Mem") begin end else if(ExpectedTokens[MarkerIndex].substr(0, 2) == "Mem") begin
MemOpM = ExpectedTokens[MarkerIndex]; MemOpM = ExpectedTokens[MarkerIndex];
matchCount = $sscanf(ExpectedTokens[MarkerIndex+1], "%x", ExpectedMemAdrM); matchCount = $sscanf(ExpectedTokens[MarkerIndex+1], "%x", ExpectedMemAdrM);
matchCount = $sscanf(ExpectedTokens[MarkerIndex+2], "%x", ExpectedMemWriteDataM); matchCount = $sscanf(ExpectedTokens[MarkerIndex+2], "%x", ExpectedMemWriteDataM);
matchCount = $sscanf(ExpectedTokens[MarkerIndex+3], "%x", ExpectedMemReadDataM); matchCount = $sscanf(ExpectedTokens[MarkerIndex+3], "%x", ExpectedMemReadDataM);
MarkerIndex += 4; MarkerIndex += 4;
// parse CSRs, because there are 1 or more CSRs after the CSR token // parse CSRs, because there are 1 or more CSRs after the CSR token
// we check if the CSR token or the number of CSRs is greater than 0. // we check if the CSR token or the number of CSRs is greater than 0.
// if so then we want to parse for a CSR. // if so then we want to parse for a CSR.
@ -235,29 +243,12 @@ module testbench();
end end
matchCount = $sscanf(ExpectedTokens[MarkerIndex], "%s", ExpectedCSRArrayM[NumCSRM]); matchCount = $sscanf(ExpectedTokens[MarkerIndex], "%s", ExpectedCSRArrayM[NumCSRM]);
matchCount = $sscanf(ExpectedTokens[MarkerIndex+1], "%x", ExpectedCSRArrayValueM[NumCSRM]); matchCount = $sscanf(ExpectedTokens[MarkerIndex+1], "%x", ExpectedCSRArrayValueM[NumCSRM]);
MarkerIndex += 2; MarkerIndex += 2;
// match MIP to QEMU's because interrupts are imprecise
// if we get an xcause with the interrupt bit set we must generate an interrupt as interrupts if(ExpectedCSRArrayM[NumCSRM].substr(0, 2) == "mip") begin
// are imprecise. Forcing the trap at this time will allow wally to track what qemu does. $display("%tns: Updating MIP to %x",$time,ExpectedCSRArrayValueM[NumCSRM]);
// the msb of xcause will be set. MIPexpected = ExpectedCSRArrayValueM[NumCSRM];
// bits 1:0 select mode; 0 = user, 1 = superviser, 3 = machine force dut.hart.priv.csr.genblk1.csri.MIP_REGW = MIPexpected;
// bits 3:2 select the type of interrupt, 0 = software, 1 = timer, 2 = external
if(ExpectedCSRArrayM[NumCSRM].substr(1, 5) == "cause" && (ExpectedCSRArrayValueM[NumCSRM][`XLEN-1] == 1'b1)) begin
//what type?
ExpectedIntType = ExpectedCSRArrayValueM[NumCSRM] & 64'h0000_000C;
$display("%tns, %d instrs: CSR = %s. Forcing interrupt of cause = %x", $time, InstrCountW, ExpectedCSRArrayM[NumCSRM], ExpectedCSRArrayValueM[NumCSRM]);
forcedInterrupt = 1;
if(ExpectedIntType == 0) begin
force dut.hart.priv.SwIntM = 1'b1;
$display("Activate spoofed SwIntM");
end else if(ExpectedIntType == 4) begin
force dut.hart.priv.TimerIntM = 1'b1;
$display("Activate spoofed TimeIntM");
end else if(ExpectedIntType == 8) begin
force dut.hart.priv.ExtIntM = 1'b1;
$display("Activate spoofed ExtIntM");
end else forcedInterrupt = 0;
end end
NumCSRM++; NumCSRM++;
end end
@ -268,12 +259,10 @@ module testbench();
force dut.hart.ieu.dp.ReadDataM = ExpectedMemReadDataM; force dut.hart.ieu.dp.ReadDataM = ExpectedMemReadDataM;
end end
if(textM.substr(0,5) == "rdtime") begin if(textM.substr(0,5) == "rdtime") begin
$display("%tns, %d instrs: Overwrite MTIME_CLINT on read of MTIME in memory stage.", $time, InstrCountW); //$display("%tns, %d instrs: Overwrite MTIME_CLINT on read of MTIME in memory stage.", $time, InstrCountW);
force dut.uncore.clint.clint.MTIME = ExpectedRegValueM; force dut.uncore.clint.clint.MTIME = ExpectedRegValueM;
//dut.hart.ieu.dp.regf.wd3
end end
end
end // if (checkInstrM)
end end
// step 1: register expected state into the write back stage. // step 1: register expected state into the write back stage.
@ -320,38 +309,17 @@ module testbench();
ExpectedCSRArrayValueW[NumCSRWIndex] = ExpectedCSRArrayValueM[NumCSRWIndex]; ExpectedCSRArrayValueW[NumCSRWIndex] = ExpectedCSRArrayValueM[NumCSRWIndex];
end end
end end
// override on special conditions
#1; #1;
// override on special conditions
if(~dut.hart.StallW) begin if(~dut.hart.StallW) begin
if(textW.substr(0,5) == "rdtime") begin if(textW.substr(0,5) == "rdtime") begin
$display("%tns, %d instrs: Releasing force of MTIME_CLINT.", $time, InstrCountW); //$display("%tns, %d instrs: Releasing force of MTIME_CLINT.", $time, InstrCountW);
release dut.uncore.clint.clint.MTIME; release dut.uncore.clint.clint.MTIME;
//release dut.hart.ieu.dp.regf.wd3;
end end
if (ExpectedMemAdrM == 'h10000005) begin if (ExpectedMemAdrM == 'h10000005) begin
//$display("%tns, %d instrs: releasing force of ReadDataM.", $time, InstrCountW); //$display("%tns, %d instrs: releasing force of ReadDataM.", $time, InstrCountW);
release dut.hart.ieu.dp.ReadDataM; release dut.hart.ieu.dp.ReadDataM;
end end
// force interrupts to 0
if (forcedInterrupt) begin
forcedInterrupt = 0;
if(ExpectedIntType == 0) begin
force dut.hart.priv.SwIntM = 1'b0;
$display("Deactivate spoofed SwIntM");
end
else if(ExpectedIntType == 4) begin
force dut.hart.priv.TimerIntM = 1'b0;
$display("Deactivate spoofed TimeIntM");
end
else if(ExpectedIntType == 8) begin
force dut.hart.priv.ExtIntM = 1'b0;
$display("Deactivate spoofed ExtIntM");
end
end
end end
end end
end end
@ -365,203 +333,56 @@ module testbench();
if (InstrCountW == waveOnICount) $stop; if (InstrCountW == waveOnICount) $stop;
// print progress message // print progress message
if (InstrCountW % 'd100000 == 0) $display("Reached %d instructions", InstrCountW); if (InstrCountW % 'd100000 == 0) $display("Reached %d instructions", InstrCountW);
// check PCW
fault = 0; fault = 0;
if(PCW != ExpectedPCW) begin if (`DEBUG_TRACE >= 1) begin
$display("PCW: %016x does not equal ExpectedPCW: %016x", PCW, ExpectedPCW); `checkEQ("PCW",PCW,ExpectedPCW)
fault = 1; `checkEQ("InstrW",dut.hart.ifu.InstrW,ExpectedInstrW)
end `checkEQ("Instr Count",dut.hart.priv.csr.genblk1.counters.genblk1.INSTRET_REGW,InstrCountW)
// check instruction value
if(dut.hart.ifu.InstrW != ExpectedInstrW) begin
$display("InstrW: %x does not equal ExpectedInstrW: %x", dut.hart.ifu.InstrW, ExpectedInstrW);
fault = 1;
end
// check the number of instructions
if(dut.hart.priv.csr.genblk1.counters.genblk1.INSTRET_REGW != InstrCountW) begin
$display("%t, Number of instruction Retired = %d does not equal number of instructions in trace = %d", $time, dut.hart.priv.csr.genblk1.counters.genblk1.INSTRET_REGW, InstrCountW);
if(!`DontHaltOnCSRMisMatch) fault = 1;
end
#2; // delay 2 ns. #2; // delay 2 ns.
if(`DEBUG_TRACE >= 5) begin
$display("%tns, %d instrs: Reg Write Address %02d ? expected value: %02d", $time, InstrCountW, dut.hart.ieu.dp.regf.a3, ExpectedRegAdrW);
if(`DEBUG_TRACE > 2) begin $display("%tns, %d instrs: RF[%02d] %016x ? expected value: %016x", $time, InstrCountW, ExpectedRegAdrW, dut.hart.ieu.dp.regf.rf[ExpectedRegAdrW], ExpectedRegValueW);
$display("Reg Write Address: %02d ? expected value: %02d", dut.hart.ieu.dp.regf.a3, ExpectedRegAdrW);
$display("RF[%02d]: %016x ? expected value: %016x", ExpectedRegAdrW, dut.hart.ieu.dp.regf.rf[ExpectedRegAdrW], ExpectedRegValueW);
end end
if (RegWriteW == "GPR") begin if (RegWriteW == "GPR") begin
if (dut.hart.ieu.dp.regf.a3 != ExpectedRegAdrW) begin `checkEQ("Reg Write Address",dut.hart.ieu.dp.regf.a3,ExpectedRegAdrW)
$display("Reg Write Address: %02d does not equal expected value: %02d", dut.hart.ieu.dp.regf.a3, ExpectedRegAdrW); $sprintf(name,"RF[%02d]",ExpectedRegAdrW);
fault = 1; `checkEQ(name, dut.hart.ieu.dp.regf.rf[ExpectedRegAdrW], ExpectedRegValueW)
end end
if (dut.hart.ieu.dp.regf.rf[ExpectedRegAdrW] != ExpectedRegValueW) begin
$display("RF[%02d]: %016x does not equal expected value: %016x", ExpectedRegAdrW, dut.hart.ieu.dp.regf.rf[ExpectedRegAdrW], ExpectedRegValueW);
fault = 1;
end
end
if (MemOpW.substr(0,2) == "Mem") begin if (MemOpW.substr(0,2) == "Mem") begin
if(`DEBUG_TRACE > 3) $display("\tMemAdrW: %016x ? expected: %016x", MemAdrW, ExpectedMemAdrW); if(`DEBUG_TRACE >= 4) $display("\tMemAdrW: %016x ? expected: %016x", MemAdrW, ExpectedMemAdrW);
`checkEQ("MemAdrW",MemAdrW,ExpectedMemAdrW)
// always check address
if (MemAdrW != ExpectedMemAdrW) begin
$display("MemAdrW: %016x does not equal expected value: %016x", MemAdrW, ExpectedMemAdrW);
fault = 1;
end
// check read data
if(MemOpW == "MemR" || MemOpW == "MemRW") begin if(MemOpW == "MemR" || MemOpW == "MemRW") begin
if(`DEBUG_TRACE > 3) $display("\tReadDataW: %016x ? expected: %016x", dut.hart.ieu.dp.ReadDataW, ExpectedMemReadDataW); if(`DEBUG_TRACE >= 4) $display("\tReadDataW: %016x ? expected: %016x", dut.hart.ieu.dp.ReadDataW, ExpectedMemReadDataW);
if (dut.hart.ieu.dp.ReadDataW != ExpectedMemReadDataW) begin `checkEQ("ReadDataW",dut.hart.ieu.dp.ReadDataW,ExpectedMemReadDataW)
$display("ReadDataW: %016x does not equal expected value: %016x", dut.hart.ieu.dp.ReadDataW, ExpectedMemReadDataW); end else if(ExpectedTokens[MarkerIndex] == "MemW" || ExpectedTokens[MarkerIndex] == "MemRW") begin
fault = 1; if(`DEBUG_TRACE >= 4) $display("\tWriteDataW: %016x ? expected: %016x", WriteDataW, ExpectedMemWriteDataW);
`checkEQ("WriteDataW",ExpectedMemWriteDataW,ExpectedMemWriteDataW)
end end
end end
// check write data
else if(ExpectedTokens[MarkerIndex] == "MemW" || ExpectedTokens[MarkerIndex] == "MemRW") begin
if(`DEBUG_TRACE > 3) $display("\tWriteDataW: %016x ? expected: %016x", WriteDataW, ExpectedMemWriteDataW);
if (WriteDataW != ExpectedMemWriteDataW) begin
$display("WriteDataW: %016x does not equal expected value: %016x", WriteDataW, ExpectedMemWriteDataW);
fault = 1;
end
end
end
// check csr // check csr
//$display("%t, about to check csr, NumCSRW = %d", $time, NumCSRW);
for(NumCSRPostWIndex = 0; NumCSRPostWIndex < NumCSRW; NumCSRPostWIndex++) begin for(NumCSRPostWIndex = 0; NumCSRPostWIndex < NumCSRW; NumCSRPostWIndex++) begin
/* -----\/----- EXCLUDED -----\/-----
if(`DEBUG_TRACE > 0) begin
$display("%t, NumCSRPostWIndex = %d, Expected CSR: %s = %016x", $time, NumCSRPostWIndex, ExpectedCSRArrayW[NumCSRPostWIndex], ExpectedCSRArrayValueW[NumCSRPostWIndex]);
end
-----/\----- EXCLUDED -----/\----- */
case(ExpectedCSRArrayW[NumCSRPostWIndex]) case(ExpectedCSRArrayW[NumCSRPostWIndex])
"mhartid": begin "mhartid": `CSRwarn(dut.hart.priv.csr.genblk1.csrm.MHARTID_REGW)
if(`DEBUG_TRACE > 0) begin "mstatus": `CSRwarn(dut.hart.priv.csr.genblk1.csrm.MSTATUS_REGW)
$display("CSR: %s = %016x, expected = %016x", ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MHARTID_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]); "mtvec": `CSRwarn(dut.hart.priv.csr.genblk1.csrm.MTVEC_REGW)
"mip": `CSRwarn(dut.hart.priv.csr.genblk1.csrm.MIP_REGW)
"mie": `CSRwarn(dut.hart.priv.csr.genblk1.csrm.MIE_REGW)
"mideleg":`CSRwarn(dut.hart.priv.csr.genblk1.csrm.MIDELEG_REGW)
"medeleg": `CSRwarn(dut.hart.priv.csr.genblk1.csrm.MEDELEG_REGW)
"mepc": `CSRwarn(dut.hart.priv.csr.genblk1.csrm.MEPC_REGW)
"mtval": `CSRwarn(dut.hart.priv.csr.genblk1.csrm.MTVAL_REGW)
"sepc": `CSRwarn(dut.hart.priv.csr.genblk1.csrs.SEPC_REGW)
"scause": `CSRwarn(dut.hart.priv.csr.genblk1.csrs.genblk1.SCAUSE_REGW)
"stvec": `CSRwarn(dut.hart.priv.csr.genblk1.csrs.STVEC_REGW)
"stval": `CSRwarn(dut.hart.priv.csr.genblk1.csrs.genblk1.STVAL_REGW)
endcase
end end
if (dut.hart.priv.csr.genblk1.csrm.MHARTID_REGW != ExpectedCSRArrayValueW[NumCSRPostWIndex]) begin if (fault == 1) begin
$display("%t, CSR: %s = %016x, does not equal expected value %016x", $time, ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MHARTID_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]); errorCount +=1;
if(!`DontHaltOnCSRMisMatch) fault = 1; $display("processed %0d instructions with %0d warnings", InstrCountW, warningCount);
$stop;
end end
end end // if (`DEBUG_TRACE >= 1)
"mstatus": begin
if(`DEBUG_TRACE > 0) begin
$display("CSR: %s = %016x, expected = %016x", ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MSTATUS_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]);
end
if ((dut.hart.priv.csr.genblk1.csrm.MSTATUS_REGW) != (ExpectedCSRArrayValueW[NumCSRPostWIndex])) begin
$display("%t, CSR: %s = %016x, does not equal expected value %016x", $time, ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MSTATUS_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]);
if(!`DontHaltOnCSRMisMatch) fault = 1;
end
end
"mtvec": begin
if(`DEBUG_TRACE > 0) begin
$display("CSR: %s = %016x, expected = %016x", ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MTVEC_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]);
end
if (dut.hart.priv.csr.genblk1.csrm.MTVEC_REGW != ExpectedCSRArrayValueW[NumCSRPostWIndex]) begin
$display("%t, CSR: %s = %016x, does not equal expected value %016x", $time, ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MTVEC_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]);
if(!`DontHaltOnCSRMisMatch) fault = 1;
end
end
"mip": begin
if(`DEBUG_TRACE > 0) begin
$display("CSR: %s = %016x, expected = %016x", ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MIP_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]);
end
if (dut.hart.priv.csr.genblk1.csrm.MIP_REGW != ExpectedCSRArrayValueW[NumCSRPostWIndex]) begin
$display("%t, CSR: %s = %016x, does not equal expected value %016x", $time, ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MIP_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]);
if(!`DontHaltOnCSRMisMatch) fault = 1;
end
end
"mie": begin
if(`DEBUG_TRACE > 0) begin
$display("CSR: %s = %016x, expected = %016x", ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MIE_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]);
end
if (dut.hart.priv.csr.genblk1.csrm.MIE_REGW != ExpectedCSRArrayValueW[NumCSRPostWIndex]) begin
$display("%t, CSR: %s = %016x, does not equal expected value %016x", $time, ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MIE_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]);
if(!`DontHaltOnCSRMisMatch) fault = 1;
end
end
"mideleg": begin
if(`DEBUG_TRACE > 0) begin
$display("CSR: %s = %016x, expected = %016x", ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MIDELEG_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]);
end
if (dut.hart.priv.csr.genblk1.csrm.MIDELEG_REGW != ExpectedCSRArrayValueW[NumCSRPostWIndex]) begin
$display("%t, CSR: %s = %016x, does not equal expected value %016x", $time, ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MIDELEG_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]);
if(!`DontHaltOnCSRMisMatch) fault = 1;
end
end
"medeleg": begin
if(`DEBUG_TRACE > 0) begin
$display("CSR: %s = %016x, expected = %016x", ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MEDELEG_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]);
end
if (dut.hart.priv.csr.genblk1.csrm.MEDELEG_REGW != ExpectedCSRArrayValueW[NumCSRPostWIndex]) begin
$display("%t, CSR: %s = %016x, does not equal expected value %016x", $time, ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MEDELEG_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]);
if(!`DontHaltOnCSRMisMatch) fault = 1;
end
end
"mepc": begin
if(`DEBUG_TRACE > 0) begin
$display("CSR: %s = %016x, expected = %016x", ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MEPC_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]);
end
if (dut.hart.priv.csr.genblk1.csrm.MEPC_REGW != ExpectedCSRArrayValueW[NumCSRPostWIndex]) begin
$display("%t, CSR: %s = %016x, does not equal expected value %016x", $time, ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MEPC_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]);
if(!`DontHaltOnCSRMisMatch) fault = 1;
end
end
"mtval": begin
if(`DEBUG_TRACE > 0) begin
$display("CSR: %s = %016x, expected = %016x", ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MTVAL_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]);
end
if (dut.hart.priv.csr.genblk1.csrm.MTVAL_REGW != ExpectedCSRArrayValueW[NumCSRPostWIndex]) begin
$display("%t, CSR: %s = %016x, does not equal expected value %016x", $time, ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MTVAL_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]);
if(!`DontHaltOnCSRMisMatch) fault = 1;
end
end
"sepc": begin
if(`DEBUG_TRACE > 0) begin
$display("CSR: %s = %016x, expected = %016x", ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrs.SEPC_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]);
end
if (dut.hart.priv.csr.genblk1.csrs.SEPC_REGW != ExpectedCSRArrayValueW[NumCSRPostWIndex]) begin
$display("%t, CSR: %s = %016x, does not equal expected value %016x", $time, ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrs.SEPC_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]);
if(!`DontHaltOnCSRMisMatch) fault = 1;
end
end
"scause": begin
if(`DEBUG_TRACE > 0) begin
$display("CSR: %s = %016x, expected = %016x", ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrs.genblk1.SCAUSE_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]);
end
if (dut.hart.priv.csr.genblk1.csrs.genblk1.SCAUSE_REGW != ExpectedCSRArrayValueW[NumCSRPostWIndex]) begin
$display("%t, CSR: %s = %016x, does not equal expected value %016x", $time, ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrs.genblk1.SCAUSE_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]);
if(!`DontHaltOnCSRMisMatch) fault = 1;
end
end
"stvec": begin
if(`DEBUG_TRACE > 0) begin
$display("CSR: %s = %016x, expected = %016x", ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrs.STVEC_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]);
end
if (dut.hart.priv.csr.genblk1.csrs.STVEC_REGW != ExpectedCSRArrayValueW[NumCSRPostWIndex]) begin
$display("%t, CSR: %s = %016x, does not equal expected value %016x", $time, ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrs.STVEC_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]);
if(!`DontHaltOnCSRMisMatch) fault = 1;
end
end
"stval": begin
if(`DEBUG_TRACE > 0) begin
$display("CSR: %s = %016x, expected = %016x", ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrs.genblk1.STVAL_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]);
end
if (dut.hart.priv.csr.genblk1.csrs.genblk1.STVAL_REGW != ExpectedCSRArrayValueW[NumCSRPostWIndex]) begin
$display("%t, CSR: %s = %016x, does not equal expected value %016x", $time, ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrs.genblk1.STVAL_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]);
if(!`DontHaltOnCSRMisMatch) fault = 1;
end
end
endcase // case (ExpectedCSRArrayW[NumCSRPostWIndex])
end // for (NumCSRPostWIndex = 0; NumCSRPostWIndex < NumCSRW; NumCSRPostWIndex++)
if (fault == 1) begin `ERROR end
end // if (checkInstrW) end // if (checkInstrW)
end // always @ (negedge clk) end // always @ (negedge clk)