This commit is contained in:
David Harris 2021-11-16 12:30:55 -08:00
commit 5a521e28ee
43 changed files with 366 additions and 2465 deletions

26
.gitignore vendored
View File

@ -19,27 +19,19 @@ wlft*
/imperas-riscv-tests/FunctionRadix.addr /imperas-riscv-tests/FunctionRadix.addr
/imperas-riscv-tests/ProgramMap.txt /imperas-riscv-tests/ProgramMap.txt
/imperas-riscv-tests/logs /imperas-riscv-tests/logs
/wally-pipelined/linux-testgen/qemu_output.txt
/wally-pipelined/linux-testgen/qemu_in_gdb_format.txt
*.o *.o
*.d *.d
testsBP/*/*/*.elf* testsBP/*/*/*.elf*
testsBP/*/OBJ/* testsBP/*/OBJ/*
testsBP/*/*.a testsBP/*/*.a
wally-pipelined/linux-testgen/linux-testvectors/* tests/linux-testgen/linux-testvectors/*
wally-pipelined/linux-testgen/nohup* !tests/linux-testgen/linux-testvectors/tvCopier.py
wally-pipelined/linux-testgen/x* !tests/linux-testgen/linux-testvectors/tvLinker.sh
!wally-pipelined/linux-testgen/linux-testvectors/tvCopier.py !tests/linux-testgen/linux-testvectors/tvUnlinker.sh
!wally-pipelined/linux-testgen/linux-testvectors/tvLinker.sh tests/linux-testgen/buildroot
!wally-pipelined/linux-testgen/linux-testvectors/tvUnlinker.sh tests/linux-testgen/buildroot-image-output
!wally-pipelined/linux-testgen/linux-testvectors/intermediate-outputs tests/linux-testgen/buildroot-config-src/main.config.old
wally-pipelined/linux-testgen/linux-testvectors/intermediate-outputs/* tests/linux-testgen/buildroot-config-src/linux.config.old
!wally-pipelined/linux-testgen/linux-testvectors/intermediate-outputs/git_create_dir.txt tests/linux-testgen/buildroot-config-src/busybox.config.old
wally-pipelined/linux-testgen/buildroot/
wally-pipelined/linux-testgen/buildroot-image-output
wally-pipelined/linux-testgen/buildroot-config-src/main.config.old
wally-pipelined/linux-testgen/buildroot-config-src/linux.config.old
wally-pipelined/linux-testgen/buildroot-config-src/busybox.config.old
wally-pipelined/regression/slack-notifier/slack-webhook-url.txt wally-pipelined/regression/slack-notifier/slack-webhook-url.txt
wally-pipelined/regression/logs wally-pipelined/regression/logs

View File

@ -8,15 +8,15 @@ To use Wally on Linux:
``` ```
git clone https://github.com/davidharrishmc/riscv-wally git clone https://github.com/davidharrishmc/riscv-wally
cd riscv-wally cd riscv-wally
cd imperas-riscv-tests cd addins
make *** can these clones be replaced with git submodule commands?
cd ../addins
git clone https://github.com/riscv-non-isa/riscv-arch-test git clone https://github.com/riscv-non-isa/riscv-arch-test
git clone https://github.com/riscv-software-src/riscv-isa-sim git clone https://github.com/riscv-software-src/riscv-isa-sim
cd riscv-isa-sim cd riscv-isa-sim
*** replace these with a copy from ../install/F and ../install/D containing the Makefile.includes already updated
cp -r arch_test_target/spike/device/rv32i_m/I arch_test_target/spike/device/rv32i_m/F cp -r arch_test_target/spike/device/rv32i_m/I arch_test_target/spike/device/rv32i_m/F
<edit arch_test_target/spike/device/rv32i_m/F/Makefile.include line 35 and change --isa=rv32i to --isa=rv32if> <edit arch_test_target/spike/device/rv32i_m/F/Makefile.include line 35 and change --isa=rv32i to --isa=rv32if>
cp -r arch_test_target/spike/device/rv32i_m/I arch_test_target/spike/device/rv64i_m/D cp -r arch_test_target/spike/device/rv64i_m/I arch_test_target/spike/device/rv64i_m/D
<edit arch_test_target/spike/device/rv64i_m/D/Makefile.include line 35 and change --isa=rv64i to --isa=rv64id> <edit arch_test_target/spike/device/rv64i_m/D/Makefile.include line 35 and change --isa=rv64i to --isa=rv64id>
mkdir build mkdir build
cd build cd build
@ -32,6 +32,15 @@ edit Makefile.include
make make
make XLEN=32 make XLEN=32
exe2memfile.pl work/*/*/*.elf # converts ELF files to a format that can be read by Modelsim exe2memfile.pl work/*/*/*.elf # converts ELF files to a format that can be read by Modelsim
cd ../../tests
cd imperas-riscv-tests
make
cd ../wally-riscv-arch-test
make
make XLEN=32
exe2memfile.pl work/*/*/*.elf # converts ELF files to a format that can be read by Modelsim
cd ../../tests/linux-testgen/linux-testvectors
./tvLinker.sh
``` ```
Notes: Notes:

View File

@ -0,0 +1,3 @@
echo "Warning: this script will only work if your repo is on Tera"
ln -s /courses/e190ax/linux-testvectors-shared/* ./
echo "Done!"

View File

@ -0,0 +1,13 @@
SHELL = /bin/sh
CFLAG = -Wall -g
CC = clang
all: fixBinMem
fixBinMem: fixBinMem.c
${CC} ${CFLAGS} fixBinMem.c -o fixBinMem
chmod +x fixBinMem
clean:
-rm -f fixBinMem

View File

@ -0,0 +1,5 @@
for index in {0..105}
do
instrs=$(((400+$index)*1000000))
echo "y" | ./genCheckpoint.sh $instrs
done

View File

@ -5,6 +5,7 @@ tcpPort=1237
# Run without GDB # Run without GDB
($customQemu \ ($customQemu \
-M virt \ -M virt \
-m 128M \
-nographic \ -nographic \
-bios $imageDir/fw_jump.elf -kernel $imageDir/Image -append "root=/dev/vda ro" -initrd $imageDir/rootfs.cpio \ -bios $imageDir/fw_jump.elf -kernel $imageDir/Image -append "root=/dev/vda ro" -initrd $imageDir/rootfs.cpio \
-singlestep -rtc clock=vm -icount shift=1,align=off,sleep=on) -singlestep -rtc clock=vm -icount shift=1,align=off,sleep=on)

Binary file not shown.

View File

@ -0,0 +1,33 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main(int argc, char *argv[]) {
if (argc < 3){
fprintf(stderr, "Expected 2 arguments: <raw GDB dump> <output binary>\n");
exit(1);
}
char* rawGDBfilePath = argv[1];
FILE* rawGDBfile;
if ((rawGDBfile = fopen(rawGDBfilePath,"rb"))==NULL) {
fprintf(stderr, "File not found: %s\n",rawGDBfilePath);
exit(1);
}
char* outFilePath = argv[2];
FILE* outFile = fopen(outFilePath,"w");
uint64_t qemuWord;
uint64_t verilogWord;
int bytesReturned=0;
do {
bytesReturned=fread(&qemuWord, 8, 1, rawGDBfile);
verilogWord = (((qemuWord>>0 )&0xff)<<56 |
((qemuWord>>8 )&0xff)<<48 |
((qemuWord>>16)&0xff)<<40 |
((qemuWord>>24)&0xff)<<32 |
((qemuWord>>32)&0xff)<<24 |
((qemuWord>>40)&0xff)<<16 |
((qemuWord>>48)&0xff)<<8 |
((qemuWord>>56)&0xff)<<0);
fwrite(&verilogWord, 8, 1, outFile);
} while(bytesReturned!=0);
return 0;
}

View File

@ -13,7 +13,7 @@ define genCheckpoint
set $checkPC=$arg3 set $checkPC=$arg3
set $checkPCoccurences=$arg4 set $checkPCoccurences=$arg4
eval "set $statePath = \"%s/stateGDB.txt\"", $statePath eval "set $statePath = \"%s/stateGDB.txt\"", $statePath
eval "set $ramPath = \"%s/ramGDB.txt\"", $ramPath eval "set $ramPath = \"%s/ramGDB.bin\"", $ramPath
# Connect to QEMU session # Connect to QEMU session
eval "target extended-remote :%d",$tcpPort eval "target extended-remote :%d",$tcpPort
@ -46,10 +46,7 @@ define genCheckpoint
# Log main memory to a file # Log main memory to a file
printf "GDB storing RAM to %s\n", $ramPath printf "GDB storing RAM to %s\n", $ramPath
eval "set logging file %s", $ramPath eval "dump binary memory %s 0x80000000 0xffffffff", $ramPath
set logging on
x/134217728xb 0x80000000
set logging off
kill kill
q q

View File

@ -3,36 +3,57 @@
source genSettings.sh source genSettings.sh
tcpPort=1236 tcpPort=1236
instrs=480000000 # Parse Commandline Arg
if [ "$#" -ne 1 ]; then
echo "genCheckpoint requires 1 argument: <num instrs>" >&2
exit 1
fi
instrs=$1
if ! [ "$instrs" -eq "$instrs" ] 2> /dev/null
then
echo "Error expected integer number of instructions, got $instrs" >&2
exit 1
fi
checkOutDir="$outDir/checkpoint$instrs" checkOutDir="$outDir/checkpoint$instrs"
checkIntermedDir="$checkOutDir/intermediate-outputs" checkIntermedDir="$checkOutDir/intermediate-outputs"
read -p "This scripts is going to create a checkpoint at $instrs instrs. read -p "This scripts is going to create a checkpoint at $instrs instrs.
Is that what you wanted? (y/n) " -n 1 -r Is that what you wanted? (y/n) " -n 1 -r
echo echo
if [[ $REPLY =~ ^[Yy]$ ]] if [[ $REPLY =~ ^[Yy]$ ]]
then then
echo "Creating checkpoint at $instrs instructions!"
mkdir -p $checkOutDir mkdir -p $checkOutDir
mkdir -p $checkIntermedDir mkdir -p $checkIntermedDir
# Identify instruction in trace
instr=$(sed "${instrs}q;d" "../linux-testvectors/all.txt") instr=$(sed "${instrs}q;d" "../linux-testvectors/all.txt")
echo "Found ${instrs}th instr: ${instr}." echo "Found ${instrs}th instr: ${instr}"
pc=$(echo $instr | cut -d " " -f1) pc=$(echo $instr | cut -d " " -f1)
asm=$(echo $instr | cut -d " " -f2) asm=$(echo $instr | cut -d " " -f2)
occurences=$(($(head -$instrs "../linux-testvectors/all.txt" | grep -c "${pc} ${asm}")-1)) occurences=$(($(head -$instrs "../linux-testvectors/all.txt" | grep -c "${pc} ${asm}")-1))
echo "It occurs ${occurences} times before the ${instrs}th instr." echo "It occurs ${occurences} times before the ${instrs}th instr."
# Simulate QEMU, parse QEMU trace, run GDB script which logs a bunch of data at the checkpoint
# GDB+QEMU
echo "Starting QEMU with attached GDB script at $(date +%H:%M:%S)"
($customQemu \ ($customQemu \
-M virt \ -M virt \
-nographic \ -nographic \
-bios $imageDir/fw_jump.elf -kernel $imageDir/Image -append "root=/dev/vda ro" -initrd $imageDir/rootfs.cpio \ -bios $imageDir/fw_jump.elf -kernel $imageDir/Image -append "root=/dev/vda ro" -initrd $imageDir/rootfs.cpio \
-singlestep -rtc clock=vm -icount shift=1,align=off,sleep=on,rr=replay,rrfile="$intermedDir/$recordFile" \ -singlestep -rtc clock=vm -icount shift=1,align=off,sleep=on,rr=replay,rrfile="$intermedDir/$recordFile" \
-gdb tcp::$tcpPort -S) \ -gdb tcp::$tcpPort -S) \
& riscv64-unknown-elf-gdb -x genCheckpoint.gdb -ex "genCheckpoint $tcpPort $instrs \"$checkIntermedDir\" \"$pc\" $occurences" & riscv64-unknown-elf-gdb --quiet \
-x genCheckpoint.gdb -ex "genCheckpoint $tcpPort $instrs \"$checkIntermedDir\" \"$pc\" $occurences"
echo "Completed GDB script completed at $(date +%H:%M:%S)"
# Post-Process GDB outputs # Post-Process GDB outputs
./parseState.py "$checkOutDir" ./parseState.py "$checkOutDir"
./fix_mem.py "$checkIntermedDir/ramGDB.txt" "$checkOutDir/ram.txt" echo "Changing Endianness at $(date +%H:%M:%S)"
tail -n+$($instrs+1) "$outDir/$traceFile" > "$checkOutDir/$traceFile" make
./fixBinMem "$checkIntermedDir/ramGDB.bin" "$checkOutDir/ram.bin"
echo "Creating truncated trace at $(date +%H:%M:%S)"
tail -n+$instrs "$outDir/$traceFile" > "$checkOutDir/$traceFile"
echo "Checkpoint completed at $(date +%H:%M:%S)"
else else
echo "You can change the number of instructions by editing the \"instrs\" variable in this script." echo "You can change the number of instructions by editing the \"instrs\" variable in this script."
echo "Have a nice day!" echo "Have a nice day!"

View File

@ -16,8 +16,8 @@ then
& riscv64-unknown-elf-gdb -quiet -x genInitMem.gdb -ex "genInitMem $tcpPort \"$intermedDir\"" & riscv64-unknown-elf-gdb -quiet -x genInitMem.gdb -ex "genInitMem $tcpPort \"$intermedDir\""
echo "Translating Mem from GDB to Questa format" echo "Translating Mem from GDB to Questa format"
./fix_mem.py "$intermedDir/bootmemGDB.txt" "$outDir/bootmem.txt" ./fixTxtMem.py "$intermedDir/bootmemGDB.txt" "$outDir/bootmem.txt"
./fix_mem.py "$intermedDir/ramGDB.txt" "$outDir/ram.txt" ./fixTxtMem.py "$intermedDir/ramGDB.txt" "$outDir/ram.txt"
echo "Done" echo "Done"
echo "Creating debugging objdump of linux image" echo "Creating debugging objdump of linux image"

View File

@ -4,7 +4,7 @@
# *** on the long term we'll want to include QEMU in the addins folder # *** on the long term we'll want to include QEMU in the addins folder
export customQemu="/courses/e190ax/qemu_sim/rv64_initrd/qemu_experimental/qemu/build/qemu-system-riscv64" export customQemu="/courses/e190ax/qemu_sim/rv64_initrd/qemu_experimental/qemu/build/qemu-system-riscv64"
export imageDir="../buildroot-image-output" export imageDir="../buildroot-image-output"
export outDir="../linux-testvectors-experimental" export outDir="../linux-testvectors"
export intermedDir="$outDir/intermediate-outputs" export intermedDir="$outDir/intermediate-outputs"
export traceFile="all.txt" export traceFile="all.txt"
export recordFile="all.qemu" export recordFile="all.qemu"

View File

@ -34,7 +34,8 @@ stateGDBpath = outDir+'intermediate-outputs/stateGDB.txt'
if not os.path.exists(stateGDBpath): if not os.path.exists(stateGDBpath):
sys.exit('Error input file '+stateGDBpath+'not found') sys.exit('Error input file '+stateGDBpath+'not found')
singleCSRs = ['pc','mip','mie','mscratch','mcause','mepc','mtvec','medeleg','mideleg','sscratch','scause','sepc','stvec','sedeleg','sideleg','satp','mstatus'] singleCSRs = ['pc','mip','mie','mscratch','mcause','mepc','mtvec','medeleg','mideleg','sscratch','scause','sepc','stvec','sedeleg','sideleg','satp','mstatus','priv']
# priv (current privilege mode) isn't technically a CSR but we can log it with the same machinery
thirtyTwoBitCSRs = ['mcounteren','scounteren'] thirtyTwoBitCSRs = ['mcounteren','scounteren']
listCSRs = ['hpmcounter','pmpaddr'] listCSRs = ['hpmcounter','pmpaddr']
pmpcfg = ['pmpcfg'] pmpcfg = ['pmpcfg']
@ -75,7 +76,7 @@ with open(stateGDBpath, 'r') as stateGDB:
outFile = open(outDir+outFileName, 'w') outFile = open(outDir+outFileName, 'w')
outFile.write(val+'\n') outFile.write(val+'\n')
outFile.close() outFile.close()
if name in thirtyTwoBitCSRs: elif name in thirtyTwoBitCSRs:
outFileName = 'checkpoint-'+name.upper() outFileName = 'checkpoint-'+name.upper()
outFile = open(outDir+outFileName, 'w') outFile = open(outDir+outFileName, 'w')
val = int(val,16) & 0xffffffff val = int(val,16) & 0xffffffff

View File

@ -31,8 +31,7 @@
`define BUILDROOT 1 `define BUILDROOT 1
`define BUSYBEAR 0 `define BUSYBEAR 0
`define LINUX_FIX_READ {'h10000005} `define LINUX_FIX_READ {'h10000005}
`define LINUX_TEST_VECTORS "../linux-testgen/linux-testvectors/" `define LINUX_TEST_VECTORS "../../tests/linux-testgen/linux-testvectors/"
//`define LINUX_TEST_VECTORS "/courses/e190ax/buildroot_boot/"
// RV32 or RV64: XLEN = 32 or 64 // RV32 or RV64: XLEN = 32 or 64
`define XLEN 64 `define XLEN 64
@ -114,8 +113,8 @@
`define PLIC_NUM_SRC 53 `define PLIC_NUM_SRC 53
`define PLIC_UART_ID 4 `define PLIC_UART_ID 4
`define TWO_BIT_PRELOAD "../config/busybear/twoBitPredictor.txt" `define TWO_BIT_PRELOAD "../config/buildroot/twoBitPredictor.txt"
`define BTB_PRELOAD "../config/busybear/BTBPredictor.txt" `define BTB_PRELOAD "../config/buildroot/BTBPredictor.txt"
`define BPRED_ENABLED 1 `define BPRED_ENABLED 1
`define BPTYPE "BPGSHARE" // BPLOCALPAg or BPGLOBAL or BPTWOBIT or BPGSHARE `define BPTYPE "BPGSHARE" // BPLOCALPAg or BPGLOBAL or BPTWOBIT or BPGSHARE
`define TESTSBP 0 `define TESTSBP 0

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,127 +0,0 @@
//////////////////////////////////////////
// busybear-config.vh
//
// Written: David_Harris@hmc.edu 4 January 2021
// Modified:
//
// Purpose: Specify which features are configured
// Macros to determine which modes are supported based on MISA
//
// A component of the Wally configurable RISC-V project.
//
// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
// OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
///////////////////////////////////////////
// include shared configuration
`include "wally-shared.vh"
`define QEMU 0
`define BUILDROOT 0
`define BUSYBEAR 1
`define LINUX_FIX_READ {'h10000005}
`define LINUX_TEST_VECTORS "/courses/e190ax/busybear_boot/"
//`define LINUX_TEST_VECTORS "../../../busybear_boot/"
// RV32 or RV64: XLEN = 32 or 64
`define XLEN 64
`define MISA (32'h0014112D)
`define ZICSR_SUPPORTED 1
`define ZIFENCEI_SUPPORTED 1
`define ZICOUNTERS_SUPPORTED 1
`define COUNTERS 32
`define DESIGN_COMPILER 0
// Microarchitectural Features
`define UARCH_PIPELINED 1
`define UARCH_SUPERSCALR 0
`define UARCH_SINGLECYCLE 0
`define MEM_DCACHE 1
`define MEM_DTIM 1
`define MEM_ICACHE 1
`define MEM_VIRTMEM 1
`define VECTORED_INTERRUPTS_SUPPORTED 1 // Domenico Ottolia 4/15: Support for vectored interrupts in _tvec csrs. Just implemented in src/privileged/trap.sv around line 75. Pretty sure this should be 1.
// TLB configuration. Entries should be a power of 2
`define ITLB_ENTRIES 32
`define DTLB_ENTRIES 32
// Cache configuration. Sizes should be a power of two
// typical configuration 4 ways, 4096 bytes per way, 256 bit or more blocks
`define DCACHE_NUMWAYS 4
`define DCACHE_WAYSIZEINBYTES 2048
`define DCACHE_BLOCKLENINBITS 256
`define DCACHE_REPLBITS 3
`define ICACHE_NUMWAYS 1
`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'h0000000000001000
// Peripheral Addresses
// Peripheral memory space extends from BASE to BASE+RANGE
// Range should be a thermometer code with 0's in the upper bits and 1s in the lower bits
`define BOOTTIM_SUPPORTED 1'b1
//`define BOOTTIM_BASE 56'h00000000 // spec had been 0x1000 to 0x2FFF, but dh truncated to 0x1000 to 0x1FFF because upper half seems to be all zeros and this is easier for decoder
//`define BOOTTIM_RANGE 56'h00003FFF
`define BOOTTIM_BASE 56'h00001000 // spec had been 0x1000 to 0x2FFF, but dh truncated to 0x1000 to 0x1FFF because upper half seems to be all zeros and this is easier for decoder
`define BOOTTIM_RANGE 56'h00000FFF
`define TIM_SUPPORTED 1'b1
`define TIM_BASE 56'h80000000
`define TIM_RANGE 56'h07FFFFFF
`define CLINT_SUPPORTED 1'b1
`define CLINT_BASE 56'h02000000
`define CLINT_RANGE 56'h0000FFFF
`define GPIO_SUPPORTED 1'b1
`define GPIO_BASE 56'h10012000
`define GPIO_RANGE 56'h000000FF
`define UART_SUPPORTED 1'b1
`define UART_BASE 56'h10000000
`define UART_RANGE 56'h00000007
`define PLIC_SUPPORTED 1'b1
`define PLIC_BASE 56'h0C000000
`define PLIC_RANGE 56'h03FFFFFF
// Bus Interface width
`define AHBW 64
// Test modes
// Tie GPIO outputs back to inputs
`define GPIO_LOOPBACK_TEST 0
// Hardware configuration
//`define UART_PRESCALE 1
`define UART_PRESCALE 0
// Interrupt configuration
`define PLIC_NUM_SRC 53
`define PLIC_UART_ID 4
`define TWO_BIT_PRELOAD "../config/busybear/twoBitPredictor.txt"
`define BTB_PRELOAD "../config/busybear/BTBPredictor.txt"
`define BPTYPE "BPGSHARE" // BPGLOBAL or BPTWOBIT or BPGSHARE
`define BPRED_ENABLED 1

View File

@ -1,38 +0,0 @@
Many of the scripts to build the linux ram.txt and trace files have changed over the Summer.
Specifically the parsed*.txt files have all been replaced by a single all.txt file which contains
all of the changes concurrent with a specific instruction.
Each line of all.txt is encoded in the following way.
The tokens are space deliminted (limitation the parsing function in system verilog). This could be
improved with some effort.
<Token> denotes a required token.
()? is an optional set of tokens. Exactly 0 or 1 of this pattern will occur.
The register update, memory operation, and CSR update are all possilbe but not present on all operations.
()+ is used to denote a variable number of this pattern with at least 1 instance of the pattern.
All integers are in hex and not zero extended.
<PC> <instruction bits> <instruction text> (<GPR> <Reg Number> <Value>)? (<MemR|MemW|MemRW> <Address> <WriteData if valid> <ReadData if valid>)? (<CSR> (<Name> <Value>)+)?
Example
1010 182b283 ld_t0,24(t0) GPR 5 80000000 MemR 1018 0 80000000
PC = 0x1010
Instruction encoding = 0x182_b283
instruction pneumonic (text) = ld_t0,24(t0)
Updating x5 to 0x8000_0000
Memory read at address 0x8000_0000 with read data of 0x8000_0000
CSR updates can occur in more than once for a single instruction. The multiple sets will appear as pairs of regsiter name followed by value.
**** This trace is generated using the CreateTrace.sh script.
Generation of ram.txt has not changed. Still use logBuildrootMem.sh
Only the all.txt and ram.txt are required to run modelsim's linux simulation. However there are three additional files will aid
in the debugging process. logBuildrootMem.sh was modified to also create an object dump from the vmlinux image. Using
extractFunctionRadix.sh the objdump is converted into two files vmlinux.objdump.addr and vmlinux.objdump.lab which contain
the addresses and labels of global functions in the linux binarary. The linux test bench is configured to uses these two files
to tell the user which function is currently being executed in modelsim.

View File

@ -1,57 +0,0 @@
If you do not need to update the Linux image, then go to ./linux-testvectors and
use tvCopier.py or tvLinker.sh to copy/link premade RAMs and testvectors from Tera.
The RAMs are needed for Wally to run the Linux code, and the testvectors are needed
to verify Wally is executing the code correctly.
If you instead wish to regenerate the RAMs and testvectors from a new Linux image,
you'll need to build the new Linux image, simulate it, and parse its output,
as described below.
*To build a new Linux image:
1. Git clone the Buildroot repository to ./buildroot:
git clone https://github.com/buildroot/buildroot.git
For reference, Wally (*** will) be proven to work on an image built using
Buildroot when the following was the most recent commit to the Buildroot repo:
commit 4047e10ed6e20492bae572d4929eaa5d67eed746
Author: Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
Date: Wed Jun 30 06:27:10 2021 +0200
2. If you wish to modify the configs, then in ./buildroot:
a. Run "make menuconfig" or "make linux-menuconfig" or "make busybox-menuconfig".
b. Use the TUI (terminal UI) to load in the existing configs.
For menuconfig, you can load in the source file from
"../buildroot-config-src/main.config"
For linux-menuconfig or busybox-menuconfig, load in from
"../../../../buildroot-config-src/<type>.config"
because for linux and busybox, make traverses down to
./buildroot/output/build/<linux or busybox>.
One annoying thing about the TUI is that if it has a path already loaded,
then before you can enter the new path to buildroot-config-src, you need to
delete the existing one from the textbox. Doing so requires more than backspace.
Once you've deleted as much of the existing path as you can see, arrow left to
check if there is more text you need to delete.
c. Likewise, when you are done editing, tell the TUI to save to the same location.
3. Finally go to ./buildroot-config-src and run make-buildroot.sh.
This script copies ./buildroot-config-src/main.config to ./buildroot/.config
and then invokes make. This is clumsy but effective because buildroot
sometimes does weird things to .config, like moving it to .config.old and
making a new .config -- doing so can really mess up symbolic/hard links.
4. If you'd like debugging symbols, then reconfigure Buildroot to output "vmlinux"
and run make-buildroot again.
*To generate new RAMs and testvectors from a Linux image:
1. sym link ./buildroot-image-output to either your new image in ./buildroot/output/image
or the existing image at /courses/e190ax/buildroot-image-output on Tera.
This might require first deleting the empty buildroot-image-output directory.
2. Then run ./testvector-generation/logBuildrootMem.sh to generate RAMs.
3. Then run ./testvector-generation/logAllBuildroot.sh to generate testvectors.
These latter two steps require QEMU.
Note that you can only have one instance of QEMU open at a time!
At least on Tera, it seems. Check "ps -ef" to see if anybody else is running QEMU.

View File

@ -1 +0,0 @@
This file only exists so that git will create ./.

View File

@ -1,9 +0,0 @@
echo "Warning: this script will only work if your repo is on Tera"
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
ln -s /courses/e190ax/buildroot_boot/vmlinux.objdump vmlinux.objdump
ln -s /courses/e190ax/buildroot_boot/vmlinux.objdump.addr vmlinux.objdump.addr
ln -s /courses/e190ax/buildroot_boot/vmlinux.objdump.lab vmlinux.objdump.lab
ln -s /courses/e190ax/buildroot_boot/checkpoint8500000 ./checkpoint8500000
echo "Done!"

View File

@ -0,0 +1,6 @@
make all:
make ../../tests/imperas-riscv-tests/
make ../../tests/wally-riscv-arch-test/
make XLEN=32 ../../tests/wally-riscv-arch-test/
exe2memfile.pl ../../tests/wally-riscv-arch-test/work/*/*/*.elf
cd ../../tests/linux-testgen/linux-testvectors/;./tvLinker.sh

View File

@ -60,20 +60,26 @@ add wave -noupdate -group {Decode Stage} /testbench/dut/hart/ieu/c/RegWriteD
add wave -noupdate -group {Decode Stage} /testbench/dut/hart/ieu/dp/RdD add wave -noupdate -group {Decode Stage} /testbench/dut/hart/ieu/dp/RdD
add wave -noupdate -group {Decode Stage} /testbench/dut/hart/ieu/dp/Rs1D add wave -noupdate -group {Decode Stage} /testbench/dut/hart/ieu/dp/Rs1D
add wave -noupdate -group {Decode Stage} /testbench/dut/hart/ieu/dp/Rs2D add wave -noupdate -group {Decode Stage} /testbench/dut/hart/ieu/dp/Rs2D
add wave -noupdate -group {Execution Stage} /testbench/dut/hart/ifu/PCE add wave -noupdate -expand -group {Execution Stage} /testbench/dut/hart/ifu/PCE
add wave -noupdate -group {Execution Stage} /testbench/InstrEName add wave -noupdate -expand -group {Execution Stage} /testbench/dut/hart/ifu/InstrE
add wave -noupdate -group {Execution Stage} /testbench/dut/hart/ifu/InstrE add wave -noupdate -expand -group {Execution Stage} /testbench/InstrEName
add wave -noupdate -group {Execution Stage} -color {Cornflower Blue} /testbench/FunctionName/FunctionName add wave -noupdate -expand -group {Execution Stage} /testbench/textE
add wave -noupdate -group {Memory Stage} /testbench/dut/hart/priv/trap/InstrValidM add wave -noupdate -expand -group {Execution Stage} -color {Cornflower Blue} /testbench/FunctionName/FunctionName
add wave -noupdate -group {Memory Stage} /testbench/dut/hart/PCM add wave -noupdate -expand -group {Memory Stage} /testbench/checkInstrM
add wave -noupdate -group {Memory Stage} /testbench/InstrMName add wave -noupdate -expand -group {Memory Stage} /testbench/dut/hart/priv/trap/InstrValidM
add wave -noupdate -group {Memory Stage} /testbench/dut/hart/InstrM add wave -noupdate -expand -group {Memory Stage} /testbench/dut/hart/PCM
add wave -noupdate -group {Memory Stage} /testbench/dut/hart/lsu/MemAdrM add wave -noupdate -expand -group {Memory Stage} /testbench/ExpectedPCM
add wave -noupdate -group {WriteBack stage} /testbench/PCW add wave -noupdate -expand -group {Memory Stage} /testbench/dut/hart/InstrM
add wave -noupdate -group {WriteBack stage} /testbench/InstrW add wave -noupdate -expand -group {Memory Stage} /testbench/InstrMName
add wave -noupdate -group {WriteBack stage} /testbench/InstrWName add wave -noupdate -expand -group {Memory Stage} /testbench/textM
add wave -noupdate -group {WriteBack stage} /testbench/InstrValidW add wave -noupdate -expand -group {Memory Stage} /testbench/dut/hart/lsu/MemAdrM
add wave -noupdate -group {WriteBack stage} /testbench/checkInstrW add wave -noupdate -expand -group {WriteBack stage} /testbench/checkInstrW
add wave -noupdate -expand -group {WriteBack stage} /testbench/InstrValidW
add wave -noupdate -expand -group {WriteBack stage} /testbench/PCW
add wave -noupdate -expand -group {WriteBack stage} /testbench/ExpectedPCW
add wave -noupdate -expand -group {WriteBack stage} /testbench/InstrW
add wave -noupdate -expand -group {WriteBack stage} /testbench/InstrWName
add wave -noupdate -expand -group {WriteBack stage} /testbench/textW
add wave -noupdate -group Bpred -color Orange /testbench/dut/hart/ifu/bpred/bpred/Predictor/DirPredictor/GHR add wave -noupdate -group Bpred -color Orange /testbench/dut/hart/ifu/bpred/bpred/Predictor/DirPredictor/GHR
add wave -noupdate -group Bpred -expand -group {branch update selection inputs} /testbench/dut/hart/ifu/bpred/bpred/Predictor/DirPredictor/BPPredF add wave -noupdate -group Bpred -expand -group {branch update selection inputs} /testbench/dut/hart/ifu/bpred/bpred/Predictor/DirPredictor/BPPredF
add wave -noupdate -group Bpred -expand -group {branch update selection inputs} {/testbench/dut/hart/ifu/bpred/bpred/Predictor/DirPredictor/InstrClassE[0]} add wave -noupdate -group Bpred -expand -group {branch update selection inputs} {/testbench/dut/hart/ifu/bpred/bpred/Predictor/DirPredictor/InstrClassE[0]}
@ -484,7 +490,6 @@ add wave -noupdate -group {debug trace} -expand -group mem /testbench/dut/hart/p
add wave -noupdate -group {debug trace} -expand -group mem /testbench/checkInstrM add wave -noupdate -group {debug trace} -expand -group mem /testbench/checkInstrM
add wave -noupdate -group {debug trace} -expand -group mem /testbench/dut/hart/PCM add wave -noupdate -group {debug trace} -expand -group mem /testbench/dut/hart/PCM
add wave -noupdate -group {debug trace} -expand -group mem /testbench/ExpectedPCM add wave -noupdate -group {debug trace} -expand -group mem /testbench/ExpectedPCM
add wave -noupdate -group {debug trace} -expand -group mem /testbench/line
add wave -noupdate -group {debug trace} -expand -group mem /testbench/textM add wave -noupdate -group {debug trace} -expand -group mem /testbench/textM
add wave -noupdate -group {debug trace} -expand -group mem -color Brown /testbench/dut/hart/hzu/TrapM add wave -noupdate -group {debug trace} -expand -group mem -color Brown /testbench/dut/hart/hzu/TrapM
add wave -noupdate -group {debug trace} -expand -group wb /testbench/checkInstrW add wave -noupdate -group {debug trace} -expand -group wb /testbench/checkInstrW
@ -510,7 +515,7 @@ add wave -noupdate /testbench/dut/uncore/dtim/memwrite
add wave -noupdate /testbench/dut/uncore/dtim/HWDATA add wave -noupdate /testbench/dut/uncore/dtim/HWDATA
add wave -noupdate /testbench/dut/uncore/dtim/risingHREADYTim add wave -noupdate /testbench/dut/uncore/dtim/risingHREADYTim
TreeUpdate [SetDefaultTree] TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 23} {209183247 ns} 0} {{Cursor 5} {229 ns} 0} WaveRestoreCursors {{Cursor 23} {209183247 ns} 0} {{Cursor 5} {5672440 ns} 0}
quietly wave cursor active 2 quietly wave cursor active 2
configure wave -namecolwidth 250 configure wave -namecolwidth 250
configure wave -valuecolwidth 314 configure wave -valuecolwidth 314
@ -526,4 +531,4 @@ configure wave -griddelta 40
configure wave -timeline 0 configure wave -timeline 0
configure wave -timelineunits ns configure wave -timelineunits ns
update update
WaveRestoreZoom {182 ns} {330 ns} WaveRestoreZoom {5672937 ns} {5673085 ns}

View File

@ -32,7 +32,7 @@ configs = [
] ]
def getBuildrootTC(short): def getBuildrootTC(short):
INSTR_LIMIT = 100000 # multiple of 100000 INSTR_LIMIT = 100000 # multiple of 100000
MAX_EXPECTED = 3000000 MAX_EXPECTED = 14000000
if short: if short:
BRcmd="vsim > {} -c <<!\ndo wally-buildroot-batch.do "+str(INSTR_LIMIT)+" 1 0\n!" BRcmd="vsim > {} -c <<!\ndo wally-buildroot-batch.do "+str(INSTR_LIMIT)+" 1 0\n!"
BRgrepstr=str(INSTR_LIMIT)+" instructions" BRgrepstr=str(INSTR_LIMIT)+" instructions"
@ -87,7 +87,7 @@ def main():
# max out at a limited number of concurrent processes to not overwhelm the system # max out at a limited number of concurrent processes to not overwhelm the system
if '-all' in sys.argv: if '-all' in sys.argv:
TIMEOUT_DUR = 3600 TIMEOUT_DUR = 4*3600
configs.append(getBuildrootTC(short=False)) configs.append(getBuildrootTC(short=False))
else: else:
TIMEOUT_DUR = 300 TIMEOUT_DUR = 300

View File

@ -87,12 +87,26 @@ def Mod_Space_at(Ln,loc,diff):
return NewString return NewString
def main_filehandler(overwrite=False): '''def main_filehandler(overwrite=False):
for filename in os.listdir(): for filename in os.listdir():
if ".py" not in filename: if ".sv" in filename:
GiantString = read_input(filename) GiantString = read_input(filename)
SOV = ID_start(GiantString) SOV = ID_start(GiantString)
ModifiedGS = modified_logNew(GiantString,SOV) ModifiedGS = modified_logNew(GiantString,SOV)
Newname = write_to_output(filename,ModifiedGS,overwrite) Newname = write_to_output(filename,ModifiedGS,overwrite)'''
def root_filehandler(path,overwrite=False):
for f in os.listdir(path):
if os.path.isdir(f):
root_filehandler(path+"/"+f)
else:
if ".sv" in f:
GiantString = read_input(f)
SOV = ID_start(GiantString)
ModifiedGS = modified_logNew(GiantString,SOV)
Newname = write_to_output(f,ModifiedGS,overwrite)
def driver(overwrite=False):
root_filehandler(os.getcwd())
main_filehandler(True) driver(True)

View File

@ -103,30 +103,35 @@ module testbench();
string checkpointDir; string checkpointDir;
logic [1:0] initPriv; logic [1:0] initPriv;
// Signals used to parse the trace file // Signals used to parse the trace file
integer data_file_all; `define DECLARE_TRACE_SCANNER_SIGNALS(STAGE) \
string name; integer traceFile``STAGE; \
integer matchCount; integer matchCount``STAGE; \
string line; string line``STAGE; \
logic [`XLEN-1:0] ExpectedPCM; string token``STAGE; \
logic [31:0] ExpectedInstrM; string ExpectedTokens``STAGE [31:0]; \
string textM; integer index``STAGE; \
string token; integer StartIndex``STAGE, EndIndex``STAGE; \
string ExpectedTokens [31:0]; integer TokenIndex``STAGE; \
integer index; integer MarkerIndex``STAGE; \
integer StartIndex, EndIndex; integer NumCSR``STAGE; \
integer TokenIndex; logic [`XLEN-1:0] ExpectedPC``STAGE; \
integer MarkerIndex; logic [31:0] ExpectedInstr``STAGE; \
integer NumCSRM; string text``STAGE; \
string MemOp``STAGE; \
string RegWrite``STAGE; \
integer ExpectedRegAdr``STAGE; \
logic [`XLEN-1:0] ExpectedRegValue``STAGE; \
logic [`XLEN-1:0] ExpectedMemAdr``STAGE, ExpectedMemReadData``STAGE, ExpectedMemWriteData``STAGE; \
string ExpectedCSRArray``STAGE[10:0]; \
logic [`XLEN-1:0] ExpectedCSRArrayValue``STAGE[10:0];
`DECLARE_TRACE_SCANNER_SIGNALS(E)
`DECLARE_TRACE_SCANNER_SIGNALS(M)
integer NextMIPexpected;
integer NextMepcExpected;
// Memory stage expected values from trace // Memory stage expected values from trace
logic checkInstrM; logic checkInstrM;
integer MIPexpected; integer MIPexpected;
string RegWriteM; string name;
integer ExpectedRegAdrM;
logic [`XLEN-1:0] ExpectedRegValueM;
string MemOpM;
logic [`XLEN-1:0] ExpectedMemAdrM, ExpectedMemReadDataM, ExpectedMemWriteDataM;
string ExpectedCSRArrayM[10:0];
logic [`XLEN-1:0] ExpectedCSRArrayValueM[10:0];
logic [`AHBW-1:0] readDataExpected; logic [`AHBW-1:0] readDataExpected;
// Write back stage expected values from trace // Write back stage expected values from trace
logic checkInstrW; logic checkInstrW;
@ -148,6 +153,11 @@ module testbench();
integer NumCSRPostWIndex; integer NumCSRPostWIndex;
logic [`XLEN-1:0] InstrCountW; logic [`XLEN-1:0] InstrCountW;
integer RequestDelayedMIP; integer RequestDelayedMIP;
integer ForceMIPFuture;
integer CSRIndex;
longint MepcExpected;
integer CheckMIPFutureE;
integer CheckMIPFutureM;
// Useful Aliases // Useful Aliases
`define RF dut.hart.ieu.dp.regf.rf `define RF dut.hart.ieu.dp.regf.rf
`define PC dut.hart.ifu.pcreg.q `define PC dut.hart.ifu.pcreg.q
@ -187,7 +197,7 @@ module testbench();
`define STATUS_MIE `CSR_BASE.csrsr.STATUS_MIE `define STATUS_MIE `CSR_BASE.csrsr.STATUS_MIE
`define STATUS_SIE `CSR_BASE.csrsr.STATUS_SIE `define STATUS_SIE `CSR_BASE.csrsr.STATUS_SIE
`define STATUS_UIE `CSR_BASE.csrsr.STATUS_UIE `define STATUS_UIE `CSR_BASE.csrsr.STATUS_UIE
`define CURR_PRIV dut.hart.priv.privmodereg.q `define PRIV dut.hart.priv.privmodereg.q
`define INSTRET dut.hart.priv.csr.genblk1.counters.genblk1.genblk2.INSTRETreg.q `define INSTRET dut.hart.priv.csr.genblk1.counters.genblk1.genblk2.INSTRETreg.q
// Common Macros // Common Macros
`define checkCSR(CSR) \ `define checkCSR(CSR) \
@ -265,6 +275,7 @@ module testbench();
endgenerate endgenerate
`INIT_CHECKPOINT_VAL(PC, [`XLEN-1:0]); `INIT_CHECKPOINT_VAL(PC, [`XLEN-1:0]);
`INIT_CHECKPOINT_VAL(MEDELEG, [`XLEN-1:0]); `INIT_CHECKPOINT_VAL(MEDELEG, [`XLEN-1:0]);
`INIT_CHECKPOINT_VAL(MIDELEG, [`XLEN-1:0]);
`INIT_CHECKPOINT_VAL(MIE, [11:0]); `INIT_CHECKPOINT_VAL(MIE, [11:0]);
`INIT_CHECKPOINT_VAL(MIP, [11:0]); `INIT_CHECKPOINT_VAL(MIP, [11:0]);
`INIT_CHECKPOINT_VAL(MCAUSE, [`XLEN-1:0]); `INIT_CHECKPOINT_VAL(MCAUSE, [`XLEN-1:0]);
@ -278,9 +289,11 @@ module testbench();
`INIT_CHECKPOINT_VAL(MTVEC, [`XLEN-1:0]); `INIT_CHECKPOINT_VAL(MTVEC, [`XLEN-1:0]);
`INIT_CHECKPOINT_VAL(STVEC, [`XLEN-1:0]); `INIT_CHECKPOINT_VAL(STVEC, [`XLEN-1:0]);
`INIT_CHECKPOINT_VAL(SATP, [`XLEN-1:0]); `INIT_CHECKPOINT_VAL(SATP, [`XLEN-1:0]);
`INIT_CHECKPOINT_VAL(PRIV, [1:0]);
`MAKE_CHECKPOINT_INIT_SIGNAL(MSTATUS, [`XLEN-1:0],0,0); `MAKE_CHECKPOINT_INIT_SIGNAL(MSTATUS, [`XLEN-1:0],0,0);
assign initPriv = (initPC[0][`XLEN-1]) ? 2'h2 : 2'h3; // *** a hacky way to detect initial privilege level integer ramFile;
integer readResult;
initial begin initial begin
force dut.hart.priv.SwIntM = 0; force dut.hart.priv.SwIntM = 0;
force dut.hart.priv.TimerIntM = 0; force dut.hart.priv.TimerIntM = 0;
@ -292,13 +305,18 @@ module testbench();
ProgramLabelMapFile = {`LINUX_TEST_VECTORS,"vmlinux.objdump.lab"}; ProgramLabelMapFile = {`LINUX_TEST_VECTORS,"vmlinux.objdump.lab"};
if (CHECKPOINT==0) begin // normal if (CHECKPOINT==0) begin // normal
$readmemh({`LINUX_TEST_VECTORS,"ram.txt"}, dut.uncore.dtim.RAM); $readmemh({`LINUX_TEST_VECTORS,"ram.txt"}, dut.uncore.dtim.RAM);
data_file_all = $fopen({`LINUX_TEST_VECTORS,"all.txt"}, "r"); traceFileM = $fopen({`LINUX_TEST_VECTORS,"all.txt"}, "r");
traceFileE = $fopen({`LINUX_TEST_VECTORS,"all.txt"}, "r");
InstrCountW = '0; InstrCountW = '0;
end else begin // checkpoint end else begin // checkpoint
$sformat(checkpointDir,"checkpoint%0d/",CHECKPOINT); $sformat(checkpointDir,"checkpoint%0d/",CHECKPOINT);
checkpointDir = {`LINUX_TEST_VECTORS,checkpointDir}; checkpointDir = {`LINUX_TEST_VECTORS,checkpointDir};
$readmemh({checkpointDir,"ram.txt"}, dut.uncore.dtim.RAM); //$readmemh({checkpointDir,"ram.txt"}, dut.uncore.dtim.RAM);
data_file_all = $fopen({checkpointDir,"all.txt"}, "r"); ramFile = $fopen({checkpointDir,"ram.bin"}, "rb");
readResult = $fread(dut.uncore.dtim.RAM,ramFile);
$fclose(ramFile);
traceFileE = $fopen({checkpointDir,"all.txt"}, "r");
traceFileM = $fopen({checkpointDir,"all.txt"}, "r");
InstrCountW = CHECKPOINT; InstrCountW = CHECKPOINT;
// manual checkpoint initializations that don't neatly fit into MACRO // manual checkpoint initializations that don't neatly fit into MACRO
force {`STATUS_TSR,`STATUS_TW,`STATUS_TVM,`STATUS_MXR,`STATUS_SUM,`STATUS_MPRV} = initMSTATUS[0][22:17]; force {`STATUS_TSR,`STATUS_TW,`STATUS_TVM,`STATUS_MXR,`STATUS_SUM,`STATUS_MPRV} = initMSTATUS[0][22:17];
@ -307,7 +325,6 @@ module testbench();
force {`STATUS_SPIE,`STATUS_UPIE,`STATUS_MIE} = initMSTATUS[0][5:3]; force {`STATUS_SPIE,`STATUS_UPIE,`STATUS_MIE} = initMSTATUS[0][5:3];
force {`STATUS_SIE,`STATUS_UIE} = initMSTATUS[0][1:0]; force {`STATUS_SIE,`STATUS_UIE} = initMSTATUS[0][1:0];
force `INSTRET = CHECKPOINT; force `INSTRET = CHECKPOINT;
force `CURR_PRIV = initPriv;
while (reset!==1) #1; while (reset!==1) #1;
while (reset!==0) #1; while (reset!==0) #1;
#1; #1;
@ -317,10 +334,13 @@ module testbench();
release {`STATUS_SPIE,`STATUS_UPIE,`STATUS_MIE}; release {`STATUS_SPIE,`STATUS_UPIE,`STATUS_MIE};
release {`STATUS_SIE,`STATUS_UIE}; release {`STATUS_SIE,`STATUS_UIE};
release `INSTRET; release `INSTRET;
release `CURR_PRIV;
end end
// Get the E-stage trace reader ahead of the M-stage trace reader
matchCountE = $fgets(lineE,traceFileE);
end end
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
//////////////////////////////////// CORE ///////////////////////////////////// //////////////////////////////////// CORE /////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -332,93 +352,161 @@ module testbench();
// on the next falling edge the expected state is compared to the wally state. // on the next falling edge the expected state is compared to the wally state.
// step 0: read the expected state // step 0: read the expected state
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;
`define SCAN_NEW_INSTR_FROM_TRACE(STAGE) \
// always check PC, instruction bits \
if (checkInstrM) begin \
// read 1 line of the trace file \
matchCount``STAGE = $fgets(line``STAGE, traceFile``STAGE); \
if(`DEBUG_TRACE >= 5) $display("Time %t, line %x", $time, line``STAGE); \
// extract PC, Instr \
matchCount``STAGE = $sscanf(line``STAGE, "%x %x %s", ExpectedPC``STAGE, ExpectedInstr``STAGE, text``STAGE); \
\
// for the life of me I cannot get any build in C or C++ string parsing functions/methods to work. \
// strtok was the best idea but it cannot be used correctly as system verilog does not have null \
// terminated strings. \
\
// Just going to do this char by char. \
StartIndex``STAGE = 0; \
TokenIndex``STAGE = 0; \
//$display("len = %d", line``STAGE.len()); \
for(index``STAGE = 0; index``STAGE < line``STAGE.len(); index``STAGE++) begin \
//$display("char = %s", line``STAGE[index]); \
if (line``STAGE[index``STAGE] == " " || line``STAGE[index``STAGE] == "\n") begin \
EndIndex``STAGE = index``STAGE; \
ExpectedTokens``STAGE[TokenIndex``STAGE] = line``STAGE.substr(StartIndex``STAGE, EndIndex``STAGE-1); \
//$display("In Tokenizer %s", line``STAGE.substr(StartIndex, EndIndex-1)); \
StartIndex``STAGE = EndIndex``STAGE + 1; \
TokenIndex``STAGE++; \
end \
end \
\
MarkerIndex``STAGE = 3; \
NumCSR``STAGE = 0; \
MemOp``STAGE = ""; \
RegWrite``STAGE = ""; \
\
#2; \
\
while(TokenIndex``STAGE > MarkerIndex``STAGE) begin \
// parse the GPR \
if (ExpectedTokens``STAGE[MarkerIndex``STAGE] == "GPR") begin \
RegWrite``STAGE = ExpectedTokens``STAGE[MarkerIndex``STAGE]; \
matchCount``STAGE = $sscanf(ExpectedTokens``STAGE[MarkerIndex``STAGE+1], "%d", ExpectedRegAdr``STAGE); \
matchCount``STAGE = $sscanf(ExpectedTokens``STAGE[MarkerIndex``STAGE+2], "%x", ExpectedRegValue``STAGE); \
MarkerIndex``STAGE += 3; \
// parse memory address, read data, and/or write data \
end else if(ExpectedTokens``STAGE[MarkerIndex``STAGE].substr(0, 2) == "Mem") begin \
MemOp``STAGE = ExpectedTokens``STAGE[MarkerIndex``STAGE]; \
matchCount``STAGE = $sscanf(ExpectedTokens``STAGE[MarkerIndex``STAGE+1], "%x", ExpectedMemAdr``STAGE); \
matchCount``STAGE = $sscanf(ExpectedTokens``STAGE[MarkerIndex``STAGE+2], "%x", ExpectedMemWriteData``STAGE); \
matchCount``STAGE = $sscanf(ExpectedTokens``STAGE[MarkerIndex``STAGE+3], "%x", ExpectedMemReadData``STAGE); \
MarkerIndex``STAGE += 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. \
end else if(ExpectedTokens``STAGE[MarkerIndex``STAGE] == "CSR" || NumCSR``STAGE > 0) begin \
if(ExpectedTokens``STAGE[MarkerIndex``STAGE] == "CSR") begin \
// all additional CSR's won't have this token. \
MarkerIndex``STAGE++; \
end \
matchCount``STAGE = $sscanf(ExpectedTokens``STAGE[MarkerIndex``STAGE], "%s", ExpectedCSRArray``STAGE[NumCSR``STAGE]); \
matchCount``STAGE = $sscanf(ExpectedTokens``STAGE[MarkerIndex``STAGE+1], "%x", ExpectedCSRArrayValue``STAGE[NumCSR``STAGE]); \
MarkerIndex``STAGE += 2; \
if(`"STAGE`"=="E") begin \
// match MIP to QEMU's because interrupts are imprecise \
if(ExpectedCSRArrayE[NumCSRE].substr(0, 2) == "mip") begin \
CheckMIPFutureE = 1; \
NextMIPexpected = ExpectedCSRArrayValueE[NumCSRE]; \
end \
// $display("%tn: ExpectedCSRArrayM[7] (MEPC) = %x",$time,ExpectedCSRArrayM[7]); \
// $display("%tn: ExpectedPCM = %x",$time,ExpectedPCM); \
// // if PC does not equal MEPC, request delayed MIP is True \
// if(ExpectedPCM != ExpectedCSRArrayM[7]) begin \
// RequestDelayedMIP = 1; \
// end else begin \
// $display("%tns: Updating MIP to %x",$time,ExpectedCSRArrayValueM[NumCSRM]); \
// MIPexpected = ExpectedCSRArrayValueM[NumCSRM]; \
// force dut.hart.priv.csr.genblk1.csri.MIP_REGW = MIPexpected; \
// end \
// end \
// $display("%tns: ExpectedCSRArrayM::: %p",$time,ExpectedCSRArrayM); \
if(ExpectedCSRArrayE[NumCSRE].substr(0,3) == "mepc") begin \
$display("hello! we are here."); \
MepcExpected = ExpectedCSRArrayValueE[NumCSRE]; \
$display("%tns: MepcExpected: %x",$time,MepcExpected); \
end \
end \
\
NumCSR``STAGE++; \
end \
end \
if(`"STAGE`"=="M") begin \
// override on special conditions \
if (ExpectedMemAdrM == 'h10000005) begin \
//$display("%tns, %d instrs: Overwriting read data from CLINT.", $time, InstrCountW); \
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); \
force dut.uncore.clint.clint.MTIME = ExpectedRegValueM; \
end \
end \
end \
always @(negedge clk) begin always @(negedge clk) begin
// always check PC, instruction bits `SCAN_NEW_INSTR_FROM_TRACE(E)
if (checkInstrM) begin end
// read 1 line of the trace file
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);
// for the life of me I cannot get any build in C or C++ string parsing functions/methods to work. always @(negedge clk) begin
// strtok was the best idea but it cannot be used correctly as system verilog does not have null `SCAN_NEW_INSTR_FROM_TRACE(M)
// terminated strings. end
// Just going to do this char by char. // MIP spoofing
StartIndex = 0; always @(posedge clk) begin
TokenIndex = 0; #1;
//$display("len = %d", line.len()); if(CheckMIPFutureE) CheckMIPFutureE <= 0;
for(index = 0; index < line.len(); index++) begin CheckMIPFutureM <= CheckMIPFutureE;
//$display("char = %s", line[index]); if(CheckMIPFutureM) begin
if (line[index] == " " || line[index] == "\n") begin $display("%tns: ExpectedPCM %x",$time,ExpectedPCM);
EndIndex = index; $display("%tns: ExpectedPCE %x",$time,ExpectedPCE);
ExpectedTokens[TokenIndex] = line.substr(StartIndex, EndIndex-1); $display("%tns: ExpectedPCW %x",$time,ExpectedPCW);
//$display("In Tokenizer %s", line.substr(StartIndex, EndIndex-1)); if((ExpectedPCE != MepcExpected) & ((MepcExpected - ExpectedPCE) * (MepcExpected - ExpectedPCE) <= 16)) begin
StartIndex = EndIndex + 1; // if((ExpectedPCM != MepcExpected) & ((MepcExpected - ExpectedPCM) * (MepcExpected - ExpectedPCM) <= 16)) begin
TokenIndex++; RequestDelayedMIP <= 1;
end $display("%tns: Requesting Delayed MIP. Current MEPC value is %x",$time,MepcExpected);
end end else begin // update MIP immediately
$display("%tns: Updating MIP to %x",$time,NextMIPexpected);
MarkerIndex = 3; MIPexpected = NextMIPexpected;
NumCSRM = 0; force dut.hart.priv.csr.genblk1.csri.MIP_REGW = MIPexpected;
MemOpM = "";
RegWriteM = "";
#2;
while(TokenIndex > MarkerIndex) begin
// parse the GPR
if (ExpectedTokens[MarkerIndex] == "GPR") begin
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
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.
end else if(ExpectedTokens[MarkerIndex] == "CSR" || NumCSRM > 0) begin
if(ExpectedTokens[MarkerIndex] == "CSR") begin
// all additional CSR's won't have this token.
MarkerIndex++;
end
matchCount = $sscanf(ExpectedTokens[MarkerIndex], "%s", ExpectedCSRArrayM[NumCSRM]);
matchCount = $sscanf(ExpectedTokens[MarkerIndex+1], "%x", ExpectedCSRArrayValueM[NumCSRM]);
MarkerIndex += 2;
// match MIP to QEMU's because interrupts are imprecise
if(ExpectedCSRArrayM[NumCSRM].substr(0, 2) == "mip") begin
$display("%tn: ExpectedCSRArrayM[7] (MEPC) = %x",$time,ExpectedCSRArrayM[7]);
$display("%tn: ExpectedPCM = %x",$time,ExpectedPCM);
// if PC does not equal MEPC, request delayed MIP is True
if(ExpectedPCM != ExpectedCSRArrayM[7]) begin
RequestDelayedMIP = 1;
end else begin
$display("%tns: Updating MIP to %x",$time,ExpectedCSRArrayValueM[NumCSRM]);
MIPexpected = ExpectedCSRArrayValueM[NumCSRM];
force dut.hart.priv.csr.genblk1.csri.MIP_REGW = MIPexpected;
end
end
NumCSRM++;
end
end
// override on special conditions
if (ExpectedMemAdrM == 'h10000005) begin
//$display("%tns, %d instrs: Overwriting read data from CLINT.", $time, InstrCountW);
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);
force dut.uncore.clint.clint.MTIME = ExpectedRegValueM;
end end
$display("%tn: ExpectedCSRArrayM = %p",$time,ExpectedCSRArrayM);
$display("%tn: ExpectedCSRArrayValueM = %p",$time,ExpectedCSRArrayValueM);
$display("%tn: ExpectedTokens = %p",$time,ExpectedTokensM);
$display("%tn: MepcExpected = %x",$time,MepcExpected);
$display("%tn: ExpectedPCM = %x",$time,ExpectedPCM);
// if PC does not equal MEPC, request delayed MIP is True
$display("%tns: Difference/multiplication thing: %x",$time,(MepcExpected - ExpectedPCM) * (MepcExpected - ExpectedPCM));
$display("%tn: ExpectedCSRArrayM[NumCSRM] %x",$time,ExpectedCSRArrayM[NumCSRM]);
$display("%tn: ExpectedCSRArrayValueM[NumCSRM] %x",$time,ExpectedCSRArrayValueM[NumCSRM]);
// if((ExpectedPCM != MepcExpected) & ((MepcExpected - ExpectedPCM) * (MepcExpected - ExpectedPCM) <= 16)) begin
// RequestDelayedMIP = 1;
// $display("%tns: Requesting Delayed MIP. Current MEPC value is %x",$time,MepcExpected);
// end else begin
// $display("%tns: Updating MIP to %x",$time,NextMIPexpected);
// MIPexpected = NextMIPexpected;
// force dut.hart.priv.csr.genblk1.csri.MIP_REGW = MIPexpected;
// end
end
if(RequestDelayedMIP) begin
$display("%tns: Executing Delayed MIP. Current MEPC value is %x",$time,dut.hart.priv.csr.genblk1.csrm.MEPC_REGW);
$display("%tns: Updating MIP to %x",$time,NextMIPexpected);
$display("%tns: MepcExpected %x",$time,MepcExpected);
MIPexpected = NextMIPexpected;
force dut.hart.priv.csr.genblk1.csri.MIP_REGW = MIPexpected;
$display("%tns: Finished Executing Delayed MIP. Current MEPC value is %x",$time,dut.hart.priv.csr.genblk1.csrm.MEPC_REGW);
RequestDelayedMIP = 0;
end end
end end
@ -449,7 +537,7 @@ module testbench();
ExpectedMemWriteDataW <= '0; ExpectedMemWriteDataW <= '0;
ExpectedMemReadDataW <= '0; ExpectedMemReadDataW <= '0;
NumCSRW <= '0; NumCSRW <= '0;
end else begin end else if (dut.hart.ieu.c.InstrValidM) begin
ExpectedPCW <= ExpectedPCM; ExpectedPCW <= ExpectedPCM;
ExpectedInstrW <= ExpectedInstrM; ExpectedInstrW <= ExpectedInstrM;
textW <= textM; textW <= textM;
@ -484,12 +572,6 @@ module testbench();
// step2: make all checks in the write back stage. // step2: make all checks in the write back stage.
assign checkInstrW = InstrValidW & ~dut.hart.StallW; // trapW will already be invalid in there was an InstrPageFault in the previous instruction. assign checkInstrW = InstrValidW & ~dut.hart.StallW; // trapW will already be invalid in there was an InstrPageFault in the previous instruction.
always @(negedge clk) begin always @(negedge clk) begin
if(RequestDelayedMIP) begin
$display("%tns: Updating MIP to %x",$time,ExpectedCSRArrayValueW[NumCSRM]);
MIPexpected = ExpectedCSRArrayValueW[NumCSRM];
force dut.hart.priv.csr.genblk1.csri.MIP_REGW = MIPexpected;
RequestDelayedMIP = 0;
end
// always check PC, instruction bits // always check PC, instruction bits
if (checkInstrW) begin if (checkInstrW) begin
InstrCountW += 1; InstrCountW += 1;
@ -521,7 +603,7 @@ module testbench();
if(MemOpW == "MemR" || MemOpW == "MemRW") begin if(MemOpW == "MemR" || MemOpW == "MemRW") begin
if(`DEBUG_TRACE >= 4) $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);
`checkEQ("ReadDataW",dut.hart.ieu.dp.ReadDataW,ExpectedMemReadDataW) `checkEQ("ReadDataW",dut.hart.ieu.dp.ReadDataW,ExpectedMemReadDataW)
end else if(ExpectedTokens[MarkerIndex] == "MemW" || ExpectedTokens[MarkerIndex] == "MemRW") begin end else if(MemOpW == "MemW" || MemOpW == "MemRW") begin
if(`DEBUG_TRACE >= 4) $display("\tWriteDataW: %016x ? expected: %016x", WriteDataW, ExpectedMemWriteDataW); if(`DEBUG_TRACE >= 4) $display("\tWriteDataW: %016x ? expected: %016x", WriteDataW, ExpectedMemWriteDataW);
`checkEQ("WriteDataW",ExpectedMemWriteDataW,ExpectedMemWriteDataW) `checkEQ("WriteDataW",ExpectedMemWriteDataW,ExpectedMemWriteDataW)
end end