This commit is contained in:
David Harris 2021-11-16 12:30:55 -08:00
commit c610be25a7
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/ProgramMap.txt
/imperas-riscv-tests/logs
/wally-pipelined/linux-testgen/qemu_output.txt
/wally-pipelined/linux-testgen/qemu_in_gdb_format.txt
*.o
*.d
testsBP/*/*/*.elf*
testsBP/*/OBJ/*
testsBP/*/*.a
wally-pipelined/linux-testgen/linux-testvectors/*
wally-pipelined/linux-testgen/nohup*
wally-pipelined/linux-testgen/x*
!wally-pipelined/linux-testgen/linux-testvectors/tvCopier.py
!wally-pipelined/linux-testgen/linux-testvectors/tvLinker.sh
!wally-pipelined/linux-testgen/linux-testvectors/tvUnlinker.sh
!wally-pipelined/linux-testgen/linux-testvectors/intermediate-outputs
wally-pipelined/linux-testgen/linux-testvectors/intermediate-outputs/*
!wally-pipelined/linux-testgen/linux-testvectors/intermediate-outputs/git_create_dir.txt
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
tests/linux-testgen/linux-testvectors/*
!tests/linux-testgen/linux-testvectors/tvCopier.py
!tests/linux-testgen/linux-testvectors/tvLinker.sh
!tests/linux-testgen/linux-testvectors/tvUnlinker.sh
tests/linux-testgen/buildroot
tests/linux-testgen/buildroot-image-output
tests/linux-testgen/buildroot-config-src/main.config.old
tests/linux-testgen/buildroot-config-src/linux.config.old
tests/linux-testgen/buildroot-config-src/busybox.config.old
wally-pipelined/regression/slack-notifier/slack-webhook-url.txt
wally-pipelined/regression/logs

View File

@ -8,15 +8,15 @@ To use Wally on Linux:
```
git clone https://github.com/davidharrishmc/riscv-wally
cd riscv-wally
cd imperas-riscv-tests
make
cd ../addins
cd addins
*** can these clones be replaced with git submodule commands?
git clone https://github.com/riscv-non-isa/riscv-arch-test
git clone https://github.com/riscv-software-src/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
<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>
mkdir build
cd build
@ -32,6 +32,15 @@ edit Makefile.include
make
make XLEN=32
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:

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
($customQemu \
-M virt \
-m 128M \
-nographic \
-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)

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 $checkPCoccurences=$arg4
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
eval "target extended-remote :%d",$tcpPort
@ -46,10 +46,7 @@ define genCheckpoint
# 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
eval "dump binary memory %s 0x80000000 0xffffffff", $ramPath
kill
q

View File

@ -3,36 +3,57 @@
source genSettings.sh
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"
checkIntermedDir="$checkOutDir/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
echo "Creating checkpoint at $instrs instructions!"
mkdir -p $checkOutDir
mkdir -p $checkIntermedDir
# Identify instruction in trace
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)
asm=$(echo $instr | cut -d " " -f2)
occurences=$(($(head -$instrs "../linux-testvectors/all.txt" | grep -c "${pc} ${asm}")-1))
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 \
-M virt \
-nographic \
-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" \
-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
./parseState.py "$checkOutDir"
./fix_mem.py "$checkIntermedDir/ramGDB.txt" "$checkOutDir/ram.txt"
tail -n+$($instrs+1) "$outDir/$traceFile" > "$checkOutDir/$traceFile"
echo "Changing Endianness at $(date +%H:%M:%S)"
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
echo "You can change the number of instructions by editing the \"instrs\" variable in this script."
echo "Have a nice day!"

View File

@ -16,8 +16,8 @@ then
& riscv64-unknown-elf-gdb -quiet -x genInitMem.gdb -ex "genInitMem $tcpPort \"$intermedDir\""
echo "Translating Mem from GDB to Questa format"
./fix_mem.py "$intermedDir/bootmemGDB.txt" "$outDir/bootmem.txt"
./fix_mem.py "$intermedDir/ramGDB.txt" "$outDir/ram.txt"
./fixTxtMem.py "$intermedDir/bootmemGDB.txt" "$outDir/bootmem.txt"
./fixTxtMem.py "$intermedDir/ramGDB.txt" "$outDir/ram.txt"
echo "Done"
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
export customQemu="/courses/e190ax/qemu_sim/rv64_initrd/qemu_experimental/qemu/build/qemu-system-riscv64"
export imageDir="../buildroot-image-output"
export outDir="../linux-testvectors-experimental"
export outDir="../linux-testvectors"
export intermedDir="$outDir/intermediate-outputs"
export traceFile="all.txt"
export recordFile="all.qemu"

View File

@ -34,7 +34,8 @@ stateGDBpath = outDir+'intermediate-outputs/stateGDB.txt'
if not os.path.exists(stateGDBpath):
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']
listCSRs = ['hpmcounter','pmpaddr']
pmpcfg = ['pmpcfg']
@ -75,7 +76,7 @@ with open(stateGDBpath, 'r') as stateGDB:
outFile = open(outDir+outFileName, 'w')
outFile.write(val+'\n')
outFile.close()
if name in thirtyTwoBitCSRs:
elif name in thirtyTwoBitCSRs:
outFileName = 'checkpoint-'+name.upper()
outFile = open(outDir+outFileName, 'w')
val = int(val,16) & 0xffffffff

View File

@ -31,8 +31,7 @@
`define BUILDROOT 1
`define BUSYBEAR 0
`define LINUX_FIX_READ {'h10000005}
`define LINUX_TEST_VECTORS "../linux-testgen/linux-testvectors/"
//`define LINUX_TEST_VECTORS "/courses/e190ax/buildroot_boot/"
`define LINUX_TEST_VECTORS "../../tests/linux-testgen/linux-testvectors/"
// RV32 or RV64: XLEN = 32 or 64
`define XLEN 64
@ -114,8 +113,8 @@
`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 TWO_BIT_PRELOAD "../config/buildroot/twoBitPredictor.txt"
`define BTB_PRELOAD "../config/buildroot/BTBPredictor.txt"
`define BPRED_ENABLED 1
`define BPTYPE "BPGSHARE" // BPLOCALPAg or BPGLOBAL or BPTWOBIT or BPGSHARE
`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/Rs1D
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 -group {Execution Stage} /testbench/InstrEName
add wave -noupdate -group {Execution Stage} /testbench/dut/hart/ifu/InstrE
add wave -noupdate -group {Execution Stage} -color {Cornflower Blue} /testbench/FunctionName/FunctionName
add wave -noupdate -group {Memory Stage} /testbench/dut/hart/priv/trap/InstrValidM
add wave -noupdate -group {Memory Stage} /testbench/dut/hart/PCM
add wave -noupdate -group {Memory Stage} /testbench/InstrMName
add wave -noupdate -group {Memory Stage} /testbench/dut/hart/InstrM
add wave -noupdate -group {Memory Stage} /testbench/dut/hart/lsu/MemAdrM
add wave -noupdate -group {WriteBack stage} /testbench/PCW
add wave -noupdate -group {WriteBack stage} /testbench/InstrW
add wave -noupdate -group {WriteBack stage} /testbench/InstrWName
add wave -noupdate -group {WriteBack stage} /testbench/InstrValidW
add wave -noupdate -group {WriteBack stage} /testbench/checkInstrW
add wave -noupdate -expand -group {Execution Stage} /testbench/dut/hart/ifu/PCE
add wave -noupdate -expand -group {Execution Stage} /testbench/dut/hart/ifu/InstrE
add wave -noupdate -expand -group {Execution Stage} /testbench/InstrEName
add wave -noupdate -expand -group {Execution Stage} /testbench/textE
add wave -noupdate -expand -group {Execution Stage} -color {Cornflower Blue} /testbench/FunctionName/FunctionName
add wave -noupdate -expand -group {Memory Stage} /testbench/checkInstrM
add wave -noupdate -expand -group {Memory Stage} /testbench/dut/hart/priv/trap/InstrValidM
add wave -noupdate -expand -group {Memory Stage} /testbench/dut/hart/PCM
add wave -noupdate -expand -group {Memory Stage} /testbench/ExpectedPCM
add wave -noupdate -expand -group {Memory Stage} /testbench/dut/hart/InstrM
add wave -noupdate -expand -group {Memory Stage} /testbench/InstrMName
add wave -noupdate -expand -group {Memory Stage} /testbench/textM
add wave -noupdate -expand -group {Memory Stage} /testbench/dut/hart/lsu/MemAdrM
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 -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]}
@ -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/dut/hart/PCM
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 -color Brown /testbench/dut/hart/hzu/TrapM
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/risingHREADYTim
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
configure wave -namecolwidth 250
configure wave -valuecolwidth 314
@ -526,4 +531,4 @@ configure wave -griddelta 40
configure wave -timeline 0
configure wave -timelineunits ns
update
WaveRestoreZoom {182 ns} {330 ns}
WaveRestoreZoom {5672937 ns} {5673085 ns}

View File

@ -32,7 +32,7 @@ configs = [
]
def getBuildrootTC(short):
INSTR_LIMIT = 100000 # multiple of 100000
MAX_EXPECTED = 3000000
MAX_EXPECTED = 14000000
if short:
BRcmd="vsim > {} -c <<!\ndo wally-buildroot-batch.do "+str(INSTR_LIMIT)+" 1 0\n!"
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
if '-all' in sys.argv:
TIMEOUT_DUR = 3600
TIMEOUT_DUR = 4*3600
configs.append(getBuildrootTC(short=False))
else:
TIMEOUT_DUR = 300

View File

@ -87,12 +87,26 @@ def Mod_Space_at(Ln,loc,diff):
return NewString
def main_filehandler(overwrite=False):
'''def main_filehandler(overwrite=False):
for filename in os.listdir():
if ".py" not in filename:
if ".sv" in filename:
GiantString = read_input(filename)
SOV = ID_start(GiantString)
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;
logic [1:0] initPriv;
// Signals used to parse the trace file
integer data_file_all;
string name;
integer matchCount;
string line;
logic [`XLEN-1:0] ExpectedPCM;
logic [31:0] ExpectedInstrM;
string textM;
string token;
string ExpectedTokens [31:0];
integer index;
integer StartIndex, EndIndex;
integer TokenIndex;
integer MarkerIndex;
integer NumCSRM;
`define DECLARE_TRACE_SCANNER_SIGNALS(STAGE) \
integer traceFile``STAGE; \
integer matchCount``STAGE; \
string line``STAGE; \
string token``STAGE; \
string ExpectedTokens``STAGE [31:0]; \
integer index``STAGE; \
integer StartIndex``STAGE, EndIndex``STAGE; \
integer TokenIndex``STAGE; \
integer MarkerIndex``STAGE; \
integer NumCSR``STAGE; \
logic [`XLEN-1:0] ExpectedPC``STAGE; \
logic [31:0] ExpectedInstr``STAGE; \
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
logic checkInstrM;
integer MIPexpected;
string RegWriteM;
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];
string name;
logic [`AHBW-1:0] readDataExpected;
// Write back stage expected values from trace
logic checkInstrW;
@ -148,6 +153,11 @@ module testbench();
integer NumCSRPostWIndex;
logic [`XLEN-1:0] InstrCountW;
integer RequestDelayedMIP;
integer ForceMIPFuture;
integer CSRIndex;
longint MepcExpected;
integer CheckMIPFutureE;
integer CheckMIPFutureM;
// Useful Aliases
`define RF dut.hart.ieu.dp.regf.rf
`define PC dut.hart.ifu.pcreg.q
@ -187,7 +197,7 @@ module testbench();
`define STATUS_MIE `CSR_BASE.csrsr.STATUS_MIE
`define STATUS_SIE `CSR_BASE.csrsr.STATUS_SIE
`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
// Common Macros
`define checkCSR(CSR) \
@ -265,6 +275,7 @@ module testbench();
endgenerate
`INIT_CHECKPOINT_VAL(PC, [`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(MIP, [11:0]);
`INIT_CHECKPOINT_VAL(MCAUSE, [`XLEN-1:0]);
@ -278,9 +289,11 @@ module testbench();
`INIT_CHECKPOINT_VAL(MTVEC, [`XLEN-1:0]);
`INIT_CHECKPOINT_VAL(STVEC, [`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);
assign initPriv = (initPC[0][`XLEN-1]) ? 2'h2 : 2'h3; // *** a hacky way to detect initial privilege level
integer ramFile;
integer readResult;
initial begin
force dut.hart.priv.SwIntM = 0;
force dut.hart.priv.TimerIntM = 0;
@ -292,13 +305,18 @@ module testbench();
ProgramLabelMapFile = {`LINUX_TEST_VECTORS,"vmlinux.objdump.lab"};
if (CHECKPOINT==0) begin // normal
$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;
end else begin // checkpoint
$sformat(checkpointDir,"checkpoint%0d/",CHECKPOINT);
checkpointDir = {`LINUX_TEST_VECTORS,checkpointDir};
$readmemh({checkpointDir,"ram.txt"}, dut.uncore.dtim.RAM);
data_file_all = $fopen({checkpointDir,"all.txt"}, "r");
//$readmemh({checkpointDir,"ram.txt"}, dut.uncore.dtim.RAM);
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;
// 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];
@ -307,7 +325,6 @@ module testbench();
force {`STATUS_SPIE,`STATUS_UPIE,`STATUS_MIE} = initMSTATUS[0][5:3];
force {`STATUS_SIE,`STATUS_UIE} = initMSTATUS[0][1:0];
force `INSTRET = CHECKPOINT;
force `CURR_PRIV = initPriv;
while (reset!==1) #1;
while (reset!==0) #1;
#1;
@ -317,10 +334,13 @@ module testbench();
release {`STATUS_SPIE,`STATUS_UPIE,`STATUS_MIE};
release {`STATUS_SIE,`STATUS_UIE};
release `INSTRET;
release `CURR_PRIV;
end
// Get the E-stage trace reader ahead of the M-stage trace reader
matchCountE = $fgets(lineE,traceFileE);
end
///////////////////////////////////////////////////////////////////////////////
//////////////////////////////////// CORE /////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
@ -332,93 +352,161 @@ module testbench();
// on the next falling edge the expected state is compared to the wally 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 check PC, instruction bits
if (checkInstrM) begin
// 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);
`SCAN_NEW_INSTR_FROM_TRACE(E)
end
// 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 = 0;
TokenIndex = 0;
//$display("len = %d", line.len());
for(index = 0; index < line.len(); index++) begin
//$display("char = %s", line[index]);
if (line[index] == " " || line[index] == "\n") begin
EndIndex = index;
ExpectedTokens[TokenIndex] = line.substr(StartIndex, EndIndex-1);
//$display("In Tokenizer %s", line.substr(StartIndex, EndIndex-1));
StartIndex = EndIndex + 1;
TokenIndex++;
end
end
MarkerIndex = 3;
NumCSRM = 0;
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;
always @(negedge clk) begin
`SCAN_NEW_INSTR_FROM_TRACE(M)
end
// MIP spoofing
always @(posedge clk) begin
#1;
if(CheckMIPFutureE) CheckMIPFutureE <= 0;
CheckMIPFutureM <= CheckMIPFutureE;
if(CheckMIPFutureM) begin
$display("%tns: ExpectedPCM %x",$time,ExpectedPCM);
$display("%tns: ExpectedPCE %x",$time,ExpectedPCE);
$display("%tns: ExpectedPCW %x",$time,ExpectedPCW);
if((ExpectedPCE != MepcExpected) & ((MepcExpected - ExpectedPCE) * (MepcExpected - ExpectedPCE) <= 16)) begin
// 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 // update MIP immediately
$display("%tns: Updating MIP to %x",$time,NextMIPexpected);
MIPexpected = NextMIPexpected;
force dut.hart.priv.csr.genblk1.csri.MIP_REGW = MIPexpected;
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
@ -449,7 +537,7 @@ module testbench();
ExpectedMemWriteDataW <= '0;
ExpectedMemReadDataW <= '0;
NumCSRW <= '0;
end else begin
end else if (dut.hart.ieu.c.InstrValidM) begin
ExpectedPCW <= ExpectedPCM;
ExpectedInstrW <= ExpectedInstrM;
textW <= textM;
@ -484,12 +572,6 @@ module testbench();
// 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.
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
if (checkInstrW) begin
InstrCountW += 1;
@ -521,7 +603,7 @@ module testbench();
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
end else if(MemOpW == "MemW" || MemOpW == "MemRW") begin
if(`DEBUG_TRACE >= 4) $display("\tWriteDataW: %016x ? expected: %016x", WriteDataW, ExpectedMemWriteDataW);
`checkEQ("WriteDataW",ExpectedMemWriteDataW,ExpectedMemWriteDataW)
end