diff --git a/wally-pipelined/config/buildroot/wally-config.vh b/wally-pipelined/config/buildroot/wally-config.vh index 1b6e030f..0a59bc3a 100644 --- a/wally-pipelined/config/buildroot/wally-config.vh +++ b/wally-pipelined/config/buildroot/wally-config.vh @@ -66,6 +66,10 @@ `define ICACHE_WAYSIZEINBYTES 4096 `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 diff --git a/wally-pipelined/config/busybear/wally-config.vh b/wally-pipelined/config/busybear/wally-config.vh index 86385bd8..614cfb2e 100644 --- a/wally-pipelined/config/busybear/wally-config.vh +++ b/wally-pipelined/config/busybear/wally-config.vh @@ -66,6 +66,10 @@ `define ICACHE_WAYSIZEINBYTES 4096 `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 diff --git a/wally-pipelined/config/coremark/wally-config.vh b/wally-pipelined/config/coremark/wally-config.vh index 32006c69..8b1ae7dc 100644 --- a/wally-pipelined/config/coremark/wally-config.vh +++ b/wally-pipelined/config/coremark/wally-config.vh @@ -65,6 +65,13 @@ `define ICACHE_WAYSIZEINBYTES 4096 `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 `define RESET_VECTOR 64'h00000000000100b0 diff --git a/wally-pipelined/config/coremark_bare/wally-config.vh b/wally-pipelined/config/coremark_bare/wally-config.vh index 8f79212b..be4a8320 100644 --- a/wally-pipelined/config/coremark_bare/wally-config.vh +++ b/wally-pipelined/config/coremark_bare/wally-config.vh @@ -66,6 +66,10 @@ `define ICACHE_WAYSIZEINBYTES 4096 `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 diff --git a/wally-pipelined/config/rv32ic/wally-config.vh b/wally-pipelined/config/rv32ic/wally-config.vh index dfe1c61e..3280c375 100644 --- a/wally-pipelined/config/rv32ic/wally-config.vh +++ b/wally-pipelined/config/rv32ic/wally-config.vh @@ -64,6 +64,10 @@ `define ICACHE_WAYSIZEINBYTES 4096 `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 diff --git a/wally-pipelined/config/rv32icfd/wally-config.vh b/wally-pipelined/config/rv32icfd/wally-config.vh index 2f0bc378..432906c8 100644 --- a/wally-pipelined/config/rv32icfd/wally-config.vh +++ b/wally-pipelined/config/rv32icfd/wally-config.vh @@ -64,6 +64,10 @@ `define ICACHE_WAYSIZEINBYTES 4096 `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 diff --git a/wally-pipelined/config/rv64BP/wally-config.vh b/wally-pipelined/config/rv64BP/wally-config.vh index c189cb0f..16219249 100644 --- a/wally-pipelined/config/rv64BP/wally-config.vh +++ b/wally-pipelined/config/rv64BP/wally-config.vh @@ -66,6 +66,13 @@ `define ICACHE_WAYSIZEINBYTES 4096 `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 `define RESET_VECTOR 64'h0000000000000000 diff --git a/wally-pipelined/config/rv64ic/wally-config.vh b/wally-pipelined/config/rv64ic/wally-config.vh index ef935ae2..bedfc4f3 100644 --- a/wally-pipelined/config/rv64ic/wally-config.vh +++ b/wally-pipelined/config/rv64ic/wally-config.vh @@ -65,6 +65,10 @@ `define ICACHE_WAYSIZEINBYTES 4096 `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 `define PMP_ENTRIES 64 diff --git a/wally-pipelined/config/rv64icfd/wally-config.vh b/wally-pipelined/config/rv64icfd/wally-config.vh index a91531dd..d3587ff4 100644 --- a/wally-pipelined/config/rv64icfd/wally-config.vh +++ b/wally-pipelined/config/rv64icfd/wally-config.vh @@ -66,6 +66,10 @@ `define ICACHE_WAYSIZEINBYTES 4096 `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 diff --git a/wally-pipelined/config/rv64imc/wally-config.vh b/wally-pipelined/config/rv64imc/wally-config.vh index 0a874a72..437a0040 100644 --- a/wally-pipelined/config/rv64imc/wally-config.vh +++ b/wally-pipelined/config/rv64imc/wally-config.vh @@ -64,6 +64,13 @@ `define ICACHE_WAYSIZEINBYTES 4096 `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 `define RESET_VECTOR 64'h0000000080000000 diff --git a/wally-pipelined/linux-testgen/linux-testvectors/tvLinker.sh b/wally-pipelined/linux-testgen/linux-testvectors/tvLinker.sh index 11c34645..f694b112 100755 --- a/wally-pipelined/linux-testgen/linux-testvectors/tvLinker.sh +++ b/wally-pipelined/linux-testgen/linux-testvectors/tvLinker.sh @@ -1,9 +1,5 @@ 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/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/all.txt all.txt ln -s /courses/e190ax/buildroot_boot/bootmem.txt bootmem.txt ln -s /courses/e190ax/buildroot_boot/ram.txt ram.txt echo "Done!" diff --git a/wally-pipelined/linux-testgen/linux-testvectors/tvUnlinker.sh b/wally-pipelined/linux-testgen/linux-testvectors/tvUnlinker.sh index 183d6a6e..bded8a16 100755 --- a/wally-pipelined/linux-testgen/linux-testvectors/tvUnlinker.sh +++ b/wally-pipelined/linux-testgen/linux-testvectors/tvUnlinker.sh @@ -1,10 +1,6 @@ # This could be nice to use if you want to mess with the testvectors # without corrupting the stable copies on Tera. -unlink parsedCSRs.txt -unlink parsedMemRead.txt -unlink parsedMemWrite.txt -unlink parsedPC.txt -unlink parsedRegs.txt +unlink all.txt unlink bootmem.txt unlink ram.txt echo "Done!" diff --git a/wally-pipelined/linux-testgen/testvector-generation/GenerateCheckpoint.sh b/wally-pipelined/linux-testgen/testvector-generation/GenerateCheckpoint.sh new file mode 100755 index 00000000..bd54523e --- /dev/null +++ b/wally-pipelined/linux-testgen/testvector-generation/GenerateCheckpoint.sh @@ -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 diff --git a/wally-pipelined/linux-testgen/testvector-generation/checkpoint.gdb b/wally-pipelined/linux-testgen/testvector-generation/checkpoint.gdb new file mode 100755 index 00000000..1b2c64f1 --- /dev/null +++ b/wally-pipelined/linux-testgen/testvector-generation/checkpoint.gdb @@ -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 diff --git a/wally-pipelined/linux-testgen/testvector-generation/fix_mem.py b/wally-pipelined/linux-testgen/testvector-generation/fix_mem.py index 66ff9cf0..0e2fbf82 100755 --- a/wally-pipelined/linux-testgen/testvector-generation/fix_mem.py +++ b/wally-pipelined/linux-testgen/testvector-generation/fix_mem.py @@ -6,9 +6,10 @@ if len(sys.argv) != 3: inputFile = sys.argv[1] outputFile = sys.argv[2] if not os.path.exists(inputFile): - sys.exit('Error input file '+inputFile+'not found') -print('Translating '+os.path.basename(inputFile)+' to '+os.path.basename(outputFile)) + sys.exit('Error input file '+inputFile+' not found') +print('Begin translating '+os.path.basename(inputFile)+' to '+os.path.basename(outputFile)) with open(inputFile, 'r') as f: with open(outputFile, 'w') as w: for l in f: 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)+'!') diff --git a/wally-pipelined/linux-testgen/testvector-generation/parseNew.py b/wally-pipelined/linux-testgen/testvector-generation/parseNew.py index 719286a2..7c2c0024 100755 --- a/wally-pipelined/linux-testgen/testvector-generation/parseNew.py +++ b/wally-pipelined/linux-testgen/testvector-generation/parseNew.py @@ -140,6 +140,7 @@ CurrentInstr = ['0', '0', None, 'other', {'zero': 0, 'ra': 0, 'sp': 0, 'gp': 0, lineNum = 0 StartLine = 0 EndLine = 0 +numInstrs = 0 #instructions = [] MemAdr = 0 lines = [] @@ -195,6 +196,10 @@ for line in fileinput.input('-'): lines.clear() #instructions.append(MoveInstrToRegWriteLst) 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 diff --git a/wally-pipelined/linux-testgen/testvector-generation/parseState.py b/wally-pipelined/linux-testgen/testvector-generation/parseState.py new file mode 100755 index 00000000..cd49ccdf --- /dev/null +++ b/wally-pipelined/linux-testgen/testvector-generation/parseState.py @@ -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 ') +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!") diff --git a/wally-pipelined/regression/linux-wave.do b/wally-pipelined/regression/linux-wave.do index 10d264d8..7a0ee7bd 100644 --- a/wally-pipelined/regression/linux-wave.do +++ b/wally-pipelined/regression/linux-wave.do @@ -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/MulDivResultW 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 divider /testbench/dut/hart/mdu/genblk1/div/fsm1/CURRENT_STATE add wave -noupdate -group divider /testbench/dut/hart/mdu/genblk1/div/N diff --git a/wally-pipelined/regression/wally-pipelined.do b/wally-pipelined/regression/wally-pipelined.do index 86165730..76e3d866 100644 --- a/wally-pipelined/regression/wally-pipelined.do +++ b/wally-pipelined/regression/wally-pipelined.do @@ -43,7 +43,7 @@ view wave do ./wave-dos/peripheral-waves.do -- Run the Simulation -#run 5000 +#run 3600 run -all #quit noview ../testbench/testbench-imperas.sv diff --git a/wally-pipelined/regression/wave-dos/peripheral-waves.do b/wally-pipelined/regression/wave-dos/peripheral-waves.do index 2da82b86..0203836e 100644 --- a/wally-pipelined/regression/wave-dos/peripheral-waves.do +++ b/wally-pipelined/regression/wave-dos/peripheral-waves.do @@ -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/ALUResultE #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 -hex /testbench/dut/hart/ifu/PCM 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 -divider 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 /testbench/InstrWName +#add wave /testbench/InstrWName add wave -hex /testbench/dut/hart/ReadDataW add wave -hex /testbench/dut/hart/ieu/dp/ResultW add wave -hex /testbench/dut/hart/ieu/dp/RegWriteW diff --git a/wally-pipelined/regression/wave.do b/wally-pipelined/regression/wave.do index d176c63f..8bff207f 100644 --- a/wally-pipelined/regression/wave.do +++ b/wally-pipelined/regression/wave.do @@ -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/MulDivResultW 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 divider /testbench/dut/hart/mdu/genblk1/div/fsm1/CURRENT_STATE add wave -noupdate -group divider /testbench/dut/hart/mdu/genblk1/div/N diff --git a/wally-pipelined/src/generic/adder.sv b/wally-pipelined/src/generic/adder.sv new file mode 100644 index 00000000..77cdf1ba --- /dev/null +++ b/wally-pipelined/src/generic/adder.sv @@ -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 + + diff --git a/wally-pipelined/src/generic/neg.sv b/wally-pipelined/src/generic/neg.sv new file mode 100644 index 00000000..a162a5c9 --- /dev/null +++ b/wally-pipelined/src/generic/neg.sv @@ -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 + diff --git a/wally-pipelined/src/ieu/forward.sv b/wally-pipelined/src/ieu/forward.sv index e7b3ff24..3e25ca7c 100644 --- a/wally-pipelined/src/ieu/forward.sv +++ b/wally-pipelined/src/ieu/forward.sv @@ -30,9 +30,10 @@ module forward( input logic [4:0] Rs1D, Rs2D, Rs1E, Rs2E, RdE, RdM, RdW, input logic MemReadE, MulDivE, CSRReadE, input logic RegWriteM, RegWriteW, - input logic DivDoneE, DivBusyE, + input logic DivBusyE, input logic FWriteIntE, FWriteIntM, FWriteIntW, input logic SCE, + input logic StallD, // Forwarding controls output logic [1:0] ForwardAE, ForwardBE, 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 assign FPUStallD = FWriteIntE & ((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)); endmodule diff --git a/wally-pipelined/src/ieu/ieu.sv b/wally-pipelined/src/ieu/ieu.sv index f2984d7f..234f767a 100644 --- a/wally-pipelined/src/ieu/ieu.sv +++ b/wally-pipelined/src/ieu/ieu.sv @@ -73,7 +73,6 @@ module ieu ( input logic FlushD, FlushE, FlushM, FlushW, output logic FPUStallD, LoadStallD, MulDivStallD, CSRRdStallD, output logic PCSrcE, - input logic DivDoneE, input logic DivBusyE, output logic CSRReadM, CSRWriteM, PrivilegedM, output logic CSRWritePendingDEM, diff --git a/wally-pipelined/src/muldiv/div.sv b/wally-pipelined/src/muldiv/div.sv index 30ea394f..b299af03 100755 --- a/wally-pipelined/src/muldiv/div.sv +++ b/wally-pipelined/src/muldiv/div.sv @@ -278,13 +278,14 @@ module otf #(parameter WIDTH=8) assign QMstar = R1Q; endmodule // otf8 - +/* module adder #(parameter WIDTH=8) (input logic [WIDTH-1:0] a, b, output logic [WIDTH-1:0] y); assign y = a + b; endmodule // adder +*/ module fa (input logic a, b, c, output logic sum, carry); diff --git a/wally-pipelined/src/muldiv/intdiv_restoring.sv b/wally-pipelined/src/muldiv/intdiv_restoring.sv deleted file mode 100644 index 9571ba72..00000000 --- a/wally-pipelined/src/muldiv/intdiv_restoring.sv +++ /dev/null @@ -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 - - diff --git a/wally-pipelined/src/muldiv/intdivrestoring.sv b/wally-pipelined/src/muldiv/intdivrestoring.sv new file mode 100644 index 00000000..5ab9b2b8 --- /dev/null +++ b/wally-pipelined/src/muldiv/intdivrestoring.sv @@ -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 */ diff --git a/wally-pipelined/src/muldiv/intdivrestoringstep.sv b/wally-pipelined/src/muldiv/intdivrestoringstep.sv new file mode 100644 index 00000000..73c4b546 --- /dev/null +++ b/wally-pipelined/src/muldiv/intdivrestoringstep.sv @@ -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 */ diff --git a/wally-pipelined/src/muldiv/muldiv.sv b/wally-pipelined/src/muldiv/muldiv.sv index 714f7ebe..8ffe91e9 100644 --- a/wally-pipelined/src/muldiv/muldiv.sv +++ b/wally-pipelined/src/muldiv/muldiv.sv @@ -31,12 +31,11 @@ module muldiv ( input logic [31:0] InstrD, // Execute Stage interface input logic [`XLEN-1:0] SrcAE, SrcBE, - input logic [2:0] Funct3E, + input logic [2:0] Funct3E, Funct3M, input logic MulDivE, W64E, // Writeback stage output logic [`XLEN-1:0] MulDivResultW, // Divide Done - output logic DivDoneE, output logic DivBusyE, // hazards input logic StallE, StallM, StallW, FlushM, FlushW @@ -45,104 +44,54 @@ module muldiv ( 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; + logic [`XLEN-1:0] PrelimResultM; + logic [`XLEN-1:0] QuotM, RemM; + logic [`XLEN*2-1:0] ProdE, ProdM; - logic enable_q; - logic [2:0] Funct3E_Q; - logic div0error; // ***unused - logic [`XLEN-1:0] N, D; - logic [`XLEN-1:0] Num0, Den0; - - logic gclk; - logic DivStartE; - logic startDivideE; - logic signedDivide; + logic StartDivideE, BusyE, DivDoneM; + logic SignedDivideE; + logic W64M; // Multiplier mul mul(.*); + flopenrc #(`XLEN*2) ProdMReg(clk, reset, FlushM, ~StallM, ProdE, ProdM); + // Divide - - // *** replace this clock gater - 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 + // 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); + + // Result multiplexer 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 // 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 + case (Funct3M) + 3'b000: PrelimResultM = ProdM[`XLEN-1:0]; + 3'b001: PrelimResultM = ProdM[`XLEN*2-1:`XLEN]; + 3'b010: PrelimResultM = ProdM[`XLEN*2-1:`XLEN]; + 3'b011: PrelimResultM = ProdM[`XLEN*2-1:`XLEN]; + 3'b100: PrelimResultM = QuotM; + 3'b101: PrelimResultM = QuotM; + 3'b110: PrelimResultM = RemM; + 3'b111: PrelimResultM = RemM; + endcase // 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 - 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 - assign MulDivResultE = PrelimResultE; + assign MulDivResultM = PrelimResultM; end - flopenrc #(`XLEN) MulDivResultMReg(clk, reset, FlushM, ~StallM, MulDivResultE, MulDivResultM); + // Writeback stage pipeline register + flopenrc #(`XLEN) MulDivResultWReg(clk, reset, FlushW, ~StallW, MulDivResultM, MulDivResultW); end else begin // no M instructions supported assign MulDivResultW = 0; assign DivBusyE = 0; - assign DivDoneE = 0; end endgenerate diff --git a/wally-pipelined/src/wally/wallypipelinedhart.sv b/wally-pipelined/src/wally/wallypipelinedhart.sv index eb5169eb..8a298594 100644 --- a/wally-pipelined/src/wally/wallypipelinedhart.sv +++ b/wally-pipelined/src/wally/wallypipelinedhart.sv @@ -88,7 +88,6 @@ module wallypipelinedhart logic InvalidateICacheM, FlushDCacheM; logic PCSrcE; logic CSRWritePendingDEM; - logic DivDoneE; logic DivBusyE; logic RegWriteD; logic LoadStallD, StoreStallD, MulDivStallD, CSRRdStallD; diff --git a/wally-pipelined/testbench/common/instrTrackerTB.sv b/wally-pipelined/testbench/common/instrTrackerTB.sv index 0283f650..2b0ca7c5 100644 --- a/wally-pipelined/testbench/common/instrTrackerTB.sv +++ b/wally-pipelined/testbench/common/instrTrackerTB.sv @@ -13,5 +13,5 @@ module instrTrackerTB( instrNameDecTB ddec(InstrD, InstrDName); instrNameDecTB edec(InstrE, InstrEName); instrNameDecTB mdec(InstrM, InstrMName); - instrNameDecTB wdec(InstrW, InstrWName); + instrNameDecTB wdec(InstrW, InstrWName); // *** delete this because InstrW is deleted from IFU endmodule diff --git a/wally-pipelined/testbench/testbench-arch.sv b/wally-pipelined/testbench/testbench-arch.sv index 7f4233ff..c1ef5a23 100644 --- a/wally-pipelined/testbench/testbench-arch.sv +++ b/wally-pipelined/testbench/testbench-arch.sv @@ -430,7 +430,7 @@ string tests32f[] = '{ // tests = {tests64p,tests64i, tests64periph}; if (`C_SUPPORTED) tests = {tests, tests64ic}; // else tests = {tests, tests64iNOc}; - if (`M_SUPPORTED) tests = {tests, tests64m}; + if (`M_SUPPORTED) tests = {tests64m, tests}; /* if (`F_SUPPORTED) tests = {tests64f, tests}; if (`D_SUPPORTED) tests = {tests64d, tests}; if (`MEM_VIRTMEM) tests = {tests64mmu, tests}; @@ -449,7 +449,7 @@ string tests32f[] = '{ tests = {tests32priv, tests32i}; //tests = {tests32i, tests32priv}; 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 (`M_SUPPORTED) tests = {tests32m, tests}; /* tests = {tests32i, tests32p};//,tests32periph}; *** broken at the moment diff --git a/wally-pipelined/testbench/testbench-imperas.sv b/wally-pipelined/testbench/testbench-imperas.sv index 31814076..3f6d449e 100644 --- a/wally-pipelined/testbench/testbench-imperas.sv +++ b/wally-pipelined/testbench/testbench-imperas.sv @@ -161,6 +161,10 @@ string tests32f[] = '{ }; 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-MULH-01", "3000", "rv64m/I-MULHSU-01", "3000", @@ -168,12 +172,8 @@ string tests32f[] = '{ "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" + "rv64m/I-REMU-01", "3000" }; string tests64ic[] = '{ @@ -318,14 +318,14 @@ string tests32f[] = '{ }; 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-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" + "rv32m/I-MULHU-01", "2000" }; string tests32ic[] = '{ @@ -536,11 +536,11 @@ string tests32f[] = '{ tests = {tests64p,tests64i, tests64periph}; if (`C_SUPPORTED) tests = {tests, tests64ic}; else tests = {tests, tests64iNOc}; - if (`M_SUPPORTED) tests = {tests, tests64m}; if (`F_SUPPORTED) tests = {tests64f, tests}; if (`D_SUPPORTED) tests = {tests64d, tests}; if (`MEM_VIRTMEM) tests = {tests64mmu, tests}; if (`A_SUPPORTED) tests = {tests64a, tests}; + if (`M_SUPPORTED) tests = {tests64m, tests}; end //tests = {tests64a, tests}; end else begin // RV32 @@ -551,12 +551,12 @@ string tests32f[] = '{ tests = tests32p; else begin 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}; - if (`M_SUPPORTED % 2 == 1) tests = {tests, tests32m}; if (`F_SUPPORTED) tests = {tests32f, tests}; if (`MEM_VIRTMEM) tests = {tests32mmu, tests}; if (`A_SUPPORTED) tests = {tests32a, tests}; + if (`M_SUPPORTED) tests = {tests32m, tests}; end end end @@ -607,9 +607,9 @@ string tests32f[] = '{ end // read test vectors into memory 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(romfilename, dut.uncore.bootdtim.bootdtim.RAM); +// $readmemh(romfilename, dut.uncore.bootdtim.bootdtim.RAM); ProgramAddrMapFile = {"../../imperas-riscv-tests/work/", tests[test], ".elf.objdump.addr"}; ProgramLabelMapFile = {"../../imperas-riscv-tests/work/", tests[test], ".elf.objdump.lab"}; $display("Read memfile %s", memfilename); @@ -743,6 +743,7 @@ module riscvassertions(); // Legal number of PMP entries are 0, 16, or 64 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 (`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 (`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)"); diff --git a/wally-pipelined/testbench/testbench-linux.sv b/wally-pipelined/testbench/testbench-linux.sv index 64bd24e7..76a1841b 100644 --- a/wally-pipelined/testbench/testbench-linux.sv +++ b/wally-pipelined/testbench/testbench-linux.sv @@ -21,24 +21,30 @@ // 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. + +// When letting Wally go for it, let wally generate own interrupts /////////////////////////////////////////// `include "wally-config.vh" `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(); - 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; /////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////// DUT ///////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// logic clk, reset; - logic [`AHBW-1:0] readDataExpected; logic [31:0] HADDR; logic [`AHBW-1:0] HWDATA; @@ -51,7 +57,6 @@ module testbench(); logic HCLK, HRESETn; logic [`AHBW-1:0] HRDATAEXT; logic HREADYEXT, HRESPEXT; - logic [31:0] GPIOPinsIn; logic [31:0] GPIOPinsOut, GPIOPinsEn; logic UARTSin, UARTSout; @@ -73,9 +78,11 @@ module testbench(); // Testbench Core integer warningCount = 0; integer errorCount = 0; + integer MIPexpected; // P, Instr Checking logic [`XLEN-1:0] PCW; integer data_file_all; + string name; // Write Back stage signals needed for trace compare, but don't actually // exist in CPU. @@ -85,7 +92,6 @@ module testbench(); logic checkInstrW; //integer RegAdr; - integer fault; logic TrapW; @@ -129,17 +135,27 @@ module testbench(); logic forcedInterrupt; integer NumCSRMIndex; integer NumCSRWIndex; - integer NumCSRPostWIndex; -// logic CurrentInterruptForce; + integer NumCSRPostWIndex; logic [`XLEN-1:0] InstrCountW; - // ----------- - // Error Macro - // ----------- - `define ERROR \ - errorCount +=1; \ - $display("processed %0d instructions with %0d warnings", InstrCountW, warningCount); \ - $stop; + // ------ + // Macros + // ------ + + `define CSRwarn(CSR) \ + begin \ + $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 data_file_all = $fopen({`LINUX_TEST_VECTORS,"all.txt"}, "r"); @@ -149,16 +165,11 @@ module testbench(); force dut.hart.priv.ExtIntM = 0; 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; - // trapW will already be invalid in there was an InstrPageFault in the previous instruction. - assign checkInstrW = dut.hart.ieu.InstrValidW & ~dut.hart.StallW; + assign checkInstrW = dut.hart.ieu.InstrValidW & ~dut.hart.StallW; // trapW will already be invalid in there was an InstrPageFault in the previous instruction. + // Additonal W stage registers 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) PCWReg(clk, reset, dut.hart.FlushW, ~dut.hart.ieu.dp.StallW, dut.hart.ifu.PCM, PCW); @@ -176,8 +187,9 @@ module testbench(); // always check PC, instruction bits if (checkInstrM) begin // read 1 line of the trace file - matchCount = $fgets(line, data_file_all); - if(`DEBUG_TRACE > 1) $display("Time %t, line %x", $time, line); + matchCount = $fgets(line, data_file_all); + if(`DEBUG_TRACE >= 5) $display("Time %t, line %x", $time, line); + // extract PC, Instr matchCount = $sscanf(line, "%x %x %s", ExpectedPCM, ExpectedInstrM, textM); //$display("matchCount %d, PCM %x ExpectedInstrM %x textM %x", matchCount, ExpectedPCM, ExpectedInstrM, textM); @@ -213,21 +225,17 @@ module testbench(); RegWriteM = ExpectedTokens[MarkerIndex]; matchCount = $sscanf(ExpectedTokens[MarkerIndex+1], "%d", ExpectedRegAdrM); matchCount = $sscanf(ExpectedTokens[MarkerIndex+2], "%x", ExpectedRegValueM); - 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 MemOpM = ExpectedTokens[MarkerIndex]; matchCount = $sscanf(ExpectedTokens[MarkerIndex+1], "%x", ExpectedMemAdrM); matchCount = $sscanf(ExpectedTokens[MarkerIndex+2], "%x", ExpectedMemWriteDataM); matchCount = $sscanf(ExpectedTokens[MarkerIndex+3], "%x", ExpectedMemReadDataM); - MarkerIndex += 4; - - // 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. - // if so then we want to parse for a CSR. + // 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. + // if so then we want to parse for a CSR. end else if(ExpectedTokens[MarkerIndex] == "CSR" || NumCSRM > 0) begin if(ExpectedTokens[MarkerIndex] == "CSR") begin // all additional CSR's won't have this token. @@ -235,30 +243,13 @@ module testbench(); end matchCount = $sscanf(ExpectedTokens[MarkerIndex], "%s", ExpectedCSRArrayM[NumCSRM]); matchCount = $sscanf(ExpectedTokens[MarkerIndex+1], "%x", ExpectedCSRArrayValueM[NumCSRM]); - MarkerIndex += 2; - - // if we get an xcause with the interrupt bit set we must generate an interrupt as interrupts - // are imprecise. Forcing the trap at this time will allow wally to track what qemu does. - // the msb of xcause will be set. - // bits 1:0 select mode; 0 = user, 1 = superviser, 3 = machine - // 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 + // match MIP to QEMU's because interrupts are imprecise + if(ExpectedCSRArrayM[NumCSRM].substr(0, 2) == "mip") begin + $display("%tns: Updating MIP to %x",$time,ExpectedCSRArrayValueM[NumCSRM]); + MIPexpected = ExpectedCSRArrayValueM[NumCSRM]; + force dut.hart.priv.csr.genblk1.csri.MIP_REGW = MIPexpected; + end NumCSRM++; end end @@ -268,12 +259,10 @@ module testbench(); force dut.hart.ieu.dp.ReadDataM = ExpectedMemReadDataM; end 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; - //dut.hart.ieu.dp.regf.wd3 end - - end // if (checkInstrM) + end end // step 1: register expected state into the write back stage. @@ -320,37 +309,16 @@ module testbench(); ExpectedCSRArrayValueW[NumCSRWIndex] = ExpectedCSRArrayValueM[NumCSRWIndex]; end end - // override on special conditions #1; - - + // override on special conditions if(~dut.hart.StallW) 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.hart.ieu.dp.regf.wd3; - end - + end if (ExpectedMemAdrM == 'h10000005) begin //$display("%tns, %d instrs: releasing force of ReadDataM.", $time, InstrCountW); - release dut.hart.ieu.dp.ReadDataM; - 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 + release dut.hart.ieu.dp.ReadDataM; end end end @@ -365,212 +333,65 @@ module testbench(); if (InstrCountW == waveOnICount) $stop; // print progress message if (InstrCountW % 'd100000 == 0) $display("Reached %d instructions", InstrCountW); - // check PCW fault = 0; - if(PCW != ExpectedPCW) begin - $display("PCW: %016x does not equal ExpectedPCW: %016x", PCW, ExpectedPCW); - fault = 1; - end - - // 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. - - - if(`DEBUG_TRACE > 2) begin - $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 - - if (RegWriteW == "GPR") begin - if (dut.hart.ieu.dp.regf.a3 != ExpectedRegAdrW) begin - $display("Reg Write Address: %02d does not equal expected value: %02d", dut.hart.ieu.dp.regf.a3, ExpectedRegAdrW); - fault = 1; + if (`DEBUG_TRACE >= 1) begin + `checkEQ("PCW",PCW,ExpectedPCW) + `checkEQ("InstrW",dut.hart.ifu.InstrW,ExpectedInstrW) + `checkEQ("Instr Count",dut.hart.priv.csr.genblk1.counters.genblk1.INSTRET_REGW,InstrCountW) + #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); + $display("%tns, %d instrs: RF[%02d] %016x ? expected value: %016x", $time, InstrCountW, ExpectedRegAdrW, dut.hart.ieu.dp.regf.rf[ExpectedRegAdrW], ExpectedRegValueW); 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(`DEBUG_TRACE > 3) $display("\tMemAdrW: %016x ? expected: %016x", 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(`DEBUG_TRACE > 3) $display("\tReadDataW: %016x ? expected: %016x", dut.hart.ieu.dp.ReadDataW, ExpectedMemReadDataW); - if (dut.hart.ieu.dp.ReadDataW != ExpectedMemReadDataW) begin - $display("ReadDataW: %016x does not equal expected value: %016x", dut.hart.ieu.dp.ReadDataW, ExpectedMemReadDataW); - fault = 1; - 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 - //$display("%t, about to check csr, NumCSRW = %d", $time, NumCSRW); - 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]) - "mhartid": begin - if(`DEBUG_TRACE > 0) begin - $display("CSR: %s = %016x, expected = %016x", ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MHARTID_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]); - end - if (dut.hart.priv.csr.genblk1.csrm.MHARTID_REGW != ExpectedCSRArrayValueW[NumCSRPostWIndex]) 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]); - if(!`DontHaltOnCSRMisMatch) fault = 1; - end + if (RegWriteW == "GPR") begin + `checkEQ("Reg Write Address",dut.hart.ieu.dp.regf.a3,ExpectedRegAdrW) + $sprintf(name,"RF[%02d]",ExpectedRegAdrW); + `checkEQ(name, dut.hart.ieu.dp.regf.rf[ExpectedRegAdrW], ExpectedRegValueW) + end + if (MemOpW.substr(0,2) == "Mem") begin + if(`DEBUG_TRACE >= 4) $display("\tMemAdrW: %016x ? expected: %016x", MemAdrW, ExpectedMemAdrW); + `checkEQ("MemAdrW",MemAdrW,ExpectedMemAdrW) + if(MemOpW == "MemR" || MemOpW == "MemRW") begin + if(`DEBUG_TRACE >= 4) $display("\tReadDataW: %016x ? expected: %016x", dut.hart.ieu.dp.ReadDataW, ExpectedMemReadDataW); + `checkEQ("ReadDataW",dut.hart.ieu.dp.ReadDataW,ExpectedMemReadDataW) + end else if(ExpectedTokens[MarkerIndex] == "MemW" || ExpectedTokens[MarkerIndex] == "MemRW") begin + if(`DEBUG_TRACE >= 4) $display("\tWriteDataW: %016x ? expected: %016x", WriteDataW, ExpectedMemWriteDataW); + `checkEQ("WriteDataW",ExpectedMemWriteDataW,ExpectedMemWriteDataW) end - "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 + // check csr + for(NumCSRPostWIndex = 0; NumCSRPostWIndex < NumCSRW; NumCSRPostWIndex++) begin + case(ExpectedCSRArrayW[NumCSRPostWIndex]) + "mhartid": `CSRwarn(dut.hart.priv.csr.genblk1.csrm.MHARTID_REGW) + "mstatus": `CSRwarn(dut.hart.priv.csr.genblk1.csrm.MSTATUS_REGW) + "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 + if (fault == 1) begin + errorCount +=1; + $display("processed %0d instructions with %0d warnings", InstrCountW, warningCount); + $stop; + end + end // if (`DEBUG_TRACE >= 1) end // if (checkInstrW) end // always @ (negedge clk) // track the current function FunctionName FunctionName(.reset(reset), - .clk(clk), - .ProgramAddrMapFile(ProgramAddrMapFile), - .ProgramLabelMapFile(ProgramLabelMapFile)); + .clk(clk), + .ProgramAddrMapFile(ProgramAddrMapFile), + .ProgramLabelMapFile(ProgramLabelMapFile)); ///////////////////////////////////////////////////////////////////////////////