mirror of
https://github.com/openhwgroup/cvw.git
synced 2025-06-28 01:32:49 -04:00
Improve buildroot and linux vector.
This commit is contained in:
parent
3aa183fadd
commit
e36c170204
25 changed files with 1261 additions and 6 deletions
|
@ -60,15 +60,24 @@ RUN opam init -y --disable-sandboxing && \
|
||||||
cp ${RISCV}/sail-riscv/c_emulator/riscv_sim_RV32 ${RISCV}/bin/riscv_sim_RV32 && \
|
cp ${RISCV}/sail-riscv/c_emulator/riscv_sim_RV32 ${RISCV}/bin/riscv_sim_RV32 && \
|
||||||
rm -rf ${RISCV}/sail-riscv
|
rm -rf ${RISCV}/sail-riscv
|
||||||
|
|
||||||
COPY ./wally /opt/riscv/wally_buildroot
|
COPY ./buildroot-config-src /opt/riscv/buildroot-config-src
|
||||||
|
COPY ./testvector-generation /opt/riscv/testvector-generation
|
||||||
|
|
||||||
# Buildroot
|
# # Buildroot
|
||||||
RUN git clone https://github.com/buildroot/buildroot.git && \
|
RUN git clone https://github.com/buildroot/buildroot.git && \
|
||||||
cd buildroot && \
|
cd buildroot && \
|
||||||
git checkout 2021.05 && \
|
git checkout 2021.05 && \
|
||||||
cp -r /opt/riscv/wally_buildroot ./board/wally && \
|
cp -r /opt/riscv/buildroot-config-src ./board/wally && \
|
||||||
cp ./board/wally/main.config .config && \
|
cp ./board/wally/main.config .config && \
|
||||||
make --jobs ${NUM_THREADS}
|
make --jobs ${NUM_THREADS} && \
|
||||||
|
# generate files for buildroot regression
|
||||||
|
mkdir -p ${RISCV}/linux-testvectors && \
|
||||||
|
cd /opt/riscv/testvector-generation && \
|
||||||
|
curl https://raw.githubusercontent.com/openhwgroup/cvw/main/linux/devicetree/wally-virt.dts --output ${RISCV}/buildroot/output/images/wally-virt.dts && \
|
||||||
|
dtc -I dts -O dtb ${RISCV}/buildroot/output/images/wally-virt.dts > ${RISCV}/buildroot/output/images/wally-virt.dtb && \
|
||||||
|
make && ./genInitMem.sh && \
|
||||||
|
chmod -R a+rw ${RISCV}/linux-testvectors && \
|
||||||
|
rm -rf ${RISCV}/buildroot
|
||||||
|
|
||||||
RUN pip3 install --no-cache-dir \
|
RUN pip3 install --no-cache-dir \
|
||||||
testresources riscv_config \
|
testresources riscv_config \
|
||||||
|
|
|
@ -5,8 +5,11 @@ ENV RUN_QUESTA=false
|
||||||
ENV USERNAME=cad
|
ENV USERNAME=cad
|
||||||
|
|
||||||
VOLUME [ "/home/${USERNAME}/cvw" ]
|
VOLUME [ "/home/${USERNAME}/cvw" ]
|
||||||
|
USER root
|
||||||
|
|
||||||
|
COPY --chown=${USERNAME}:${USERNAME} . /home/${USERNAME}
|
||||||
|
RUN chown -R ${USERNAME}:${USERNAME} /home/${USERNAME}
|
||||||
|
|
||||||
COPY . /home/${USERNAME}
|
|
||||||
USER ${USERNAME}
|
USER ${USERNAME}
|
||||||
WORKDIR /home/${USERNAME}/cvw
|
WORKDIR /home/${USERNAME}/cvw
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@ Hazards:
|
||||||
- If there is any change in `${CVW_HOME}/linux/buildroot-config-src` folder with main.config, you have to copy it to the current folder to `buildroot-config-src`
|
- If there is any change in `${CVW_HOME}/linux/buildroot-config-src` folder with main.config, you have to copy it to the current folder to `buildroot-config-src`
|
||||||
- If there is any change in `${CVW_HOME}/linux/testvector-generation` folder with main.config, you have to copy it to the current folder to `testvector-generation`
|
- If there is any change in `${CVW_HOME}/linux/testvector-generation` folder with main.config, you have to copy it to the current folder to `testvector-generation`
|
||||||
|
|
||||||
|
If you have any other questions, please read the [troubleshooting]() first.
|
||||||
|
|
||||||
## TODOs
|
## TODOs
|
||||||
|
|
||||||
- [ ] Pinning the tools version
|
- [ ] Pinning the tools version
|
||||||
|
@ -21,6 +23,7 @@ Hazards:
|
||||||
- [x] Configure the license for Questa
|
- [x] Configure the license for Questa
|
||||||
- [ ] Change the condition from empty string to 1
|
- [ ] Change the condition from empty string to 1
|
||||||
- [ ] Add linux testvector-generation
|
- [ ] Add linux testvector-generation
|
||||||
|
- [ ] Estimate the useless building intermediate files
|
||||||
|
|
||||||
## TL;DR
|
## TL;DR
|
||||||
|
|
||||||
|
@ -284,6 +287,40 @@ There are stages in the old Dockerfile:
|
||||||
- buildroot: `2021.05`
|
- buildroot: `2021.05`
|
||||||
- verilator: `v5.022`
|
- verilator: `v5.022`
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Permission Denied for .git
|
||||||
|
|
||||||
|
Description: permission problem in `/home/$USERNAME/cvw`.
|
||||||
|
|
||||||
|
```text
|
||||||
|
$ podman run -v cvw_temp:/home/cad/cvw -e CLEAN_CVW= -e BUILD_RISCOF= -e RUN_QUESTA= -v /cad/mentor/que
|
||||||
|
sta_sim-2023.4:/cad/mentor/questa_sim-xxxx.x_x --rm wallysoc/regression_wally
|
||||||
|
No CVW_GIT is provided
|
||||||
|
rm: cannot remove '/home/cad/cvw': Device or resource busy
|
||||||
|
Cloning into '/home/cad/cvw'...
|
||||||
|
/home/cad/cvw/.git: Permission denied
|
||||||
|
chmod: cannot access '/home/cad/cvw/setup.sh': No such file or directory
|
||||||
|
chmod: cannot access '/home/cad/cvw/site-setup.sh': No such file or directory
|
||||||
|
make: *** No rule to make target 'install'. Stop.
|
||||||
|
make: *** No rule to make target 'verify'. Stop.
|
||||||
|
make: *** No rule to make target 'coverage'. Stop.
|
||||||
|
make: *** No rule to make target 'benchmarks'. Stop.
|
||||||
|
/home/cad/run_regression.sh: line 64: cd: /home/cad/cvw/sim: No such file or directory
|
||||||
|
/home/cad/run_regression.sh: line 65: /home/cad/cvw/sim/regression_verilator.out: No such file or direc
|
||||||
|
tory
|
||||||
|
```
|
||||||
|
|
||||||
|
It may be caused by podman and I am not sure why it happens.
|
||||||
|
|
||||||
|
Solution: get into the container with interaction as root and change the permission of the folder/volume `/home/$USERNAME/cvw`
|
||||||
|
|
||||||
|
```shell
|
||||||
|
podman run -it --user root -v cvw_temp:/home/cad/cvw -e RUN_QUESTA= -v /cad/mentor/questa_sim-2023.4:/cad/mentor/questa_sim-xxxx.x_x --net=host --rm --privileged wallysoc/regression_wally /bin/bash
|
||||||
|
|
||||||
|
chown -R $USERNAME:$USERNAME /home/$USERNAME
|
||||||
|
```
|
||||||
|
|
||||||
## References
|
## References
|
||||||
|
|
||||||
- Dockerfile Docs: https://docs.docker.com/reference/dockerfile/
|
- Dockerfile Docs: https://docs.docker.com/reference/dockerfile/
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
# now only main branch is supported
|
# now only main branch is supported
|
||||||
if [ -z "${CVW_GIT}" ]; then
|
if [ -z "${CVW_GIT}" ]; then
|
||||||
echo "No CVW_GIT is provided"
|
echo "No CVW_GIT is provided"
|
||||||
CVW_GIT="https://github.com/openhwgroup/cvw"
|
export CVW_GIT="https://github.com/openhwgroup/cvw"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
git config --global http.version HTTP/1.1
|
git config --global http.version HTTP/1.1
|
||||||
|
|
47
docs/docker/testvector-generation/EmulateLinux.sh
Executable file
47
docs/docker/testvector-generation/EmulateLinux.sh
Executable file
|
@ -0,0 +1,47 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
usage() { echo "Usage: $0 [-h] [-b <path/to/buildroot>] [-d <path/to/device tree>]" 1>&2; exit 1; }
|
||||||
|
|
||||||
|
help() {
|
||||||
|
echo "Usage: $0 [OPTIONS] <device>"
|
||||||
|
echo " -b <path/to/buildroot> get images from given buildroot"
|
||||||
|
echo " -d <device tree name> specify device tree to use"
|
||||||
|
exit 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
# defaults
|
||||||
|
imageDir=$RISCV/buildroot/output/images
|
||||||
|
DEVICE_TREE=${imageDir}/wally-virt.dtb
|
||||||
|
|
||||||
|
# Process options and arguments. The following code grabs the single
|
||||||
|
# sdcard device argument no matter where it is in the positional
|
||||||
|
# parameters list.
|
||||||
|
ARGS=()
|
||||||
|
while [ $OPTIND -le "$#" ] ; do
|
||||||
|
if getopts "hb:d:" arg ; then
|
||||||
|
case "${arg}" in
|
||||||
|
h) help
|
||||||
|
;;
|
||||||
|
b) BUILDROOT=${OPTARG}
|
||||||
|
;;
|
||||||
|
d) DEVICE_TREE=${OPTARG}
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
ARGS+=("${!OPTIND}")
|
||||||
|
((OPTIND++))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# File location variables
|
||||||
|
imageDir=$BUILDROOT/output/images
|
||||||
|
|
||||||
|
tvDir=$RISCV/linux-testvectors
|
||||||
|
tcpPort=1239
|
||||||
|
|
||||||
|
# QEMU Simulation
|
||||||
|
qemu-system-riscv64 \
|
||||||
|
-M virt -m 256M -dtb $DEVICE_TREE \
|
||||||
|
-nographic \
|
||||||
|
-bios $imageDir/fw_jump.elf -kernel $imageDir/Image -append "root=/dev/vda ro"
|
||||||
|
-singlestep -rtc clock=vm -icount shift=0,align=off,sleep=on
|
13
docs/docker/testvector-generation/Makefile
Normal file
13
docs/docker/testvector-generation/Makefile
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
SHELL = /bin/sh
|
||||||
|
|
||||||
|
CFLAG = -Wall -g
|
||||||
|
CC = gcc
|
||||||
|
|
||||||
|
all: fixBinMem
|
||||||
|
|
||||||
|
fixBinMem: fixBinMem.c
|
||||||
|
${CC} ${CFLAGS} fixBinMem.c -o fixBinMem
|
||||||
|
chmod +x fixBinMem
|
||||||
|
|
||||||
|
clean:
|
||||||
|
-rm -f fixBinMem
|
6
docs/docker/testvector-generation/checkpointSweep.sh
Executable file
6
docs/docker/testvector-generation/checkpointSweep.sh
Executable file
|
@ -0,0 +1,6 @@
|
||||||
|
#!/bin/bash
|
||||||
|
for index in {450..500};
|
||||||
|
do
|
||||||
|
instrs=$(($index*1000000))
|
||||||
|
echo "y" | nice -n 5 ./genCheckpoint.sh $instrs
|
||||||
|
done
|
21
docs/docker/testvector-generation/debug.sh
Executable file
21
docs/docker/testvector-generation/debug.sh
Executable file
|
@ -0,0 +1,21 @@
|
||||||
|
#!/bin/bash
|
||||||
|
imageDir=$RISCV/buildroot/output/images
|
||||||
|
tvDir=$RISCV/linux-testvectors
|
||||||
|
tcpPort=1239
|
||||||
|
|
||||||
|
# QEMU Simulation
|
||||||
|
qemu-system-riscv64 \
|
||||||
|
-M virt -dtb $imageDir/wally-virt.dtb \
|
||||||
|
-nographic \
|
||||||
|
-bios $imageDir/fw_jump.elf -kernel $imageDir/Image -append "root=/dev/vda ro" -initrd $imageDir/rootfs.cpio \
|
||||||
|
-singlestep -rtc clock=vm -icount shift=0,align=off,sleep=on
|
||||||
|
# > ./qemu-serial \
|
||||||
|
# -gdb tcp::$tcpPort -S) \
|
||||||
|
# & riscv64-unknown-elf-gdb -quiet \
|
||||||
|
# -ex "set pagination off" \
|
||||||
|
# -ex "set logging overwrite on" \
|
||||||
|
# -ex "set logging redirect on" \
|
||||||
|
# -ex "set confirm off" \
|
||||||
|
# -ex "target extended-remote :$tcpPort" \
|
||||||
|
# -ex "maintenance packet Qqemu.PhyMemMode:1" \
|
||||||
|
# -ex "file $imageDir/vmlinux"
|
74
docs/docker/testvector-generation/disassembleBootTrace.py
Executable file
74
docs/docker/testvector-generation/disassembleBootTrace.py
Executable file
|
@ -0,0 +1,74 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
#
|
||||||
|
# disassembleBootTrace.py
|
||||||
|
# David_Harris@hmc.edu 22 November 2023
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
||||||
|
#
|
||||||
|
# Reads boottrace.log and disassembles the machine code
|
||||||
|
#
|
||||||
|
|
||||||
|
import csv
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
# read a file from sim/logs/boottrace.log and extract the second comma-separated field containing the instruction
|
||||||
|
print("Reading boottrace.log")
|
||||||
|
trace = []
|
||||||
|
count = 0
|
||||||
|
with open('../../sim/logs/boottrace.log') as f:
|
||||||
|
reader = csv.reader(f, delimiter=',')
|
||||||
|
for row in reader:
|
||||||
|
trace.append(row)
|
||||||
|
count = count + 1
|
||||||
|
if count > 50000000:
|
||||||
|
break
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
print("Disassembling boottrace.log instructions")
|
||||||
|
# Write an assembly language file with the machine code
|
||||||
|
with (open('boottrace.S', 'w')) as f:
|
||||||
|
f.write('main:\n')
|
||||||
|
for row in trace:
|
||||||
|
instr = row[1]
|
||||||
|
# scrape off leading white space from instr
|
||||||
|
instr = instr.lstrip()
|
||||||
|
# check if last character indicates an compressed or uncompressed instruction
|
||||||
|
lastNibble = instr[-1]
|
||||||
|
if (lastNibble == '3' or lastNibble == '7' or lastNibble == 'b' or lastNibble == 'f'):
|
||||||
|
# uncompressed
|
||||||
|
f.write('.word 0x' + instr + '\n')
|
||||||
|
else:
|
||||||
|
# compressed
|
||||||
|
instr = instr[-4:]
|
||||||
|
f.write('.hword 0x' + instr + '\n')
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
# Then assemble and disassemble the file
|
||||||
|
os.system('riscv64-unknown-elf-gcc -march=rv64gqc_zba_zbb_zbc_zbs_zfh_zicboz_zicbop_zicbom -mabi=lp64d -c boottrace.S')
|
||||||
|
os.system('riscv64-unknown-elf-objdump -D boottrace.o > boottrace.objdump')
|
||||||
|
|
||||||
|
# Patch disassembly back into boottrace
|
||||||
|
print("Inserting disassembly into trace")
|
||||||
|
dumpedLines = []
|
||||||
|
with (open('boottrace.objdump', 'r')) as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
f.close()
|
||||||
|
lines = lines[7:] # skip header
|
||||||
|
p = r'[^:]*:\s*(\S*)\s*(.*)'
|
||||||
|
for line in lines:
|
||||||
|
match = re.search(p, line)
|
||||||
|
if (match):
|
||||||
|
dump = [match.group(1), match.group(2)]
|
||||||
|
dumpedLines.append(dump)
|
||||||
|
|
||||||
|
linenum = 0
|
||||||
|
for i in range(len(trace)):
|
||||||
|
row = trace[i]
|
||||||
|
row.insert(2, dumpedLines[i][1])
|
||||||
|
|
||||||
|
# write trace back to csv file
|
||||||
|
print("Writing trace back to boottrace_disasm.log")
|
||||||
|
with (open('boottrace_disasm.log', 'w')) as f:
|
||||||
|
writer = csv.writer(f)
|
||||||
|
writer.writerows(trace)
|
||||||
|
f.close()
|
68
docs/docker/testvector-generation/filterTrapsToInterrupts.py
Executable file
68
docs/docker/testvector-generation/filterTrapsToInterrupts.py
Executable file
|
@ -0,0 +1,68 @@
|
||||||
|
#! /usr/bin/python3
|
||||||
|
import sys, os
|
||||||
|
from functools import reduce
|
||||||
|
|
||||||
|
################
|
||||||
|
# Helper Funcs #
|
||||||
|
################
|
||||||
|
|
||||||
|
def tokenize(string):
|
||||||
|
tokens = []
|
||||||
|
token = ''
|
||||||
|
whitespace = 0
|
||||||
|
prevWhitespace = 0
|
||||||
|
for char in string:
|
||||||
|
prevWhitespace = whitespace
|
||||||
|
whitespace = char in ' \t\n'
|
||||||
|
if (whitespace):
|
||||||
|
if ((not prevWhitespace) and (token != '')):
|
||||||
|
tokens.append(token)
|
||||||
|
token = ''
|
||||||
|
else:
|
||||||
|
token = token + char
|
||||||
|
return tokens
|
||||||
|
|
||||||
|
def strip0x(num):
|
||||||
|
return num[2:]
|
||||||
|
|
||||||
|
def stripZeroes(num):
|
||||||
|
num = num.strip('0')
|
||||||
|
if num=='':
|
||||||
|
return '0'
|
||||||
|
else:
|
||||||
|
return num
|
||||||
|
|
||||||
|
#############
|
||||||
|
# Main Code #
|
||||||
|
#############
|
||||||
|
print("Begin filtering traps down to just external interrupts.")
|
||||||
|
|
||||||
|
# Parse Args
|
||||||
|
if len(sys.argv) != 2:
|
||||||
|
sys.exit('Error filterTrapsToInterrupts.py expects 1 arg: <path_to_testvector_dir>')
|
||||||
|
tvDir = sys.argv[1]+'/'
|
||||||
|
trapsFilePath = tvDir+'traps.txt'
|
||||||
|
if not os.path.exists(trapsFilePath):
|
||||||
|
sys.exit('Error input file '+trapsFilePath+'not found')
|
||||||
|
|
||||||
|
with open(tvDir+'interrupts.txt', 'w') as interruptsFile:
|
||||||
|
with open(trapsFilePath, 'r') as trapsFile:
|
||||||
|
while True:
|
||||||
|
trap = trapsFile.readline()
|
||||||
|
if trap == '':
|
||||||
|
break
|
||||||
|
trapType = trap.split(' ')[-1]
|
||||||
|
if ('interrupt' in trap) and (('external' in trapType) or ('m_timer' in trapType)): # no s_timer because that is not controlled by CLINT
|
||||||
|
interruptsFile.write(trap) # overall line
|
||||||
|
interruptsFile.write(trapsFile.readline()) # attempted instr count
|
||||||
|
interruptsFile.write(trapsFile.readline()) # hart #
|
||||||
|
interruptsFile.write(trapsFile.readline()) # asynchronous
|
||||||
|
interruptsFile.write(trapsFile.readline()) # cause
|
||||||
|
interruptsFile.write(trapsFile.readline()) # epc
|
||||||
|
interruptsFile.write(trapsFile.readline()) # tval
|
||||||
|
interruptsFile.write(trapsFile.readline()) # description
|
||||||
|
else:
|
||||||
|
for i in range(7):
|
||||||
|
trapsFile.readline()
|
||||||
|
|
||||||
|
print("Finished filtering traps down to just external interrupts.")
|
33
docs/docker/testvector-generation/fixBinMem.c
Normal file
33
docs/docker/testvector-generation/fixBinMem.c
Normal 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;
|
||||||
|
}
|
146
docs/docker/testvector-generation/genCheckpoint.sh
Executable file
146
docs/docker/testvector-generation/genCheckpoint.sh
Executable file
|
@ -0,0 +1,146 @@
|
||||||
|
#!/bin/bash
|
||||||
|
tcpPort=1238
|
||||||
|
imageDir=$RISCV/buildroot/output/images
|
||||||
|
tvDir=$RISCV/linux-testvectors
|
||||||
|
recordFile="$tvDir/all.qemu"
|
||||||
|
traceFile="$tvDir/all.txt"
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
checkPtDir="$tvDir/checkpoint$instrs"
|
||||||
|
outTraceFile="$checkPtDir/all.txt"
|
||||||
|
rawStateFile="$checkPtDir/stateGDB.txt"
|
||||||
|
rawUartStateFile="$checkPtDir/uartStateGDB.txt"
|
||||||
|
uartStateFile="$checkPtDir/checkpoint-UART"
|
||||||
|
rawPlicStateFile="$checkPtDir/plicStateGDB.txt"
|
||||||
|
plicStateFile="$checkPtDir/checkpoint-PLIC"
|
||||||
|
rawRamFile="$checkPtDir/ramGDB.bin"
|
||||||
|
ramFile="$checkPtDir/ram.bin"
|
||||||
|
|
||||||
|
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!"
|
||||||
|
if [ ! -d "$tvDir" ]; then
|
||||||
|
echo "Error: linux testvector directory $tvDir not found!">&2
|
||||||
|
echo "Please create it. For example:">&2
|
||||||
|
echo " sudo mkdir -p $tvDir">&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
test -w $tvDir
|
||||||
|
if [ ! $? -eq 0 ]; then
|
||||||
|
echo "Error: insuffcient write privileges for linux testvector directory $tvDir !">&2
|
||||||
|
echo "Please chmod it. For example:">&2
|
||||||
|
echo " sudo chmod -R a+rw $tvDir">&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p $checkPtDir
|
||||||
|
|
||||||
|
# Identify instruction in trace
|
||||||
|
instr=$(sed "${instrs}q;d" "$traceFile")
|
||||||
|
echo "Found ${instrs}th instr: ${instr}"
|
||||||
|
pc=$(echo $instr | cut -d " " -f1)
|
||||||
|
asm=$(echo $instr | cut -d " " -f2)
|
||||||
|
occurences=$(($(head -$instrs "$traceFile" | grep -c "${pc} ${asm}")-1))
|
||||||
|
echo "It occurs ${occurences} times before the ${instrs}th instr."
|
||||||
|
|
||||||
|
# Create GDB script because GDB is terrible at handling arguments / variables
|
||||||
|
cat > genCheckpoint.gdb <<- end_of_script
|
||||||
|
set pagination off
|
||||||
|
set logging overwrite on
|
||||||
|
set logging redirect on
|
||||||
|
set confirm off
|
||||||
|
target extended-remote :$tcpPort
|
||||||
|
maintenance packet Qqemu.PhyMemMode:1
|
||||||
|
file $imageDir/vmlinux
|
||||||
|
# Step over reset vector into actual code
|
||||||
|
stepi 100
|
||||||
|
shell echo \"GDB proceeding to checkpoint at $instrs instrs, pc $pc\"
|
||||||
|
b *0x$pc
|
||||||
|
ignore 1 $occurences
|
||||||
|
c
|
||||||
|
shell echo \"Reached checkpoint at $instrs instrs\"
|
||||||
|
shell echo \"GDB storing CPU state to $rawStateFile\"
|
||||||
|
set logging file $rawStateFile
|
||||||
|
set logging on
|
||||||
|
info all-registers
|
||||||
|
set logging off
|
||||||
|
shell echo \"GDB storing UART state to $rawUartStateFile\"
|
||||||
|
# Save value of LCR
|
||||||
|
set \$LCR=*0x10000003 & 0xff
|
||||||
|
set logging file $rawUartStateFile
|
||||||
|
set logging on
|
||||||
|
# Change LCR to set DLAB=0 to be able to read RBR and IER
|
||||||
|
set {char}0x10000003 &= ~0x80
|
||||||
|
x/1xb 0x10000000
|
||||||
|
x/1xb 0x10000001
|
||||||
|
x/1xb 0x10000002
|
||||||
|
# But log original value of LCR
|
||||||
|
printf "0x10000003:\t0x%02x\n", \$LCR
|
||||||
|
x/1xb 0x10000004
|
||||||
|
x/1xb 0x10000005
|
||||||
|
x/1xb 0x10000006
|
||||||
|
x/1xb 0x10000007
|
||||||
|
set logging off
|
||||||
|
shell echo \"GDB storing PLIC state to $rawPlicStateFile\"
|
||||||
|
shell echo \"Note: this dumping assumes a maximum of 63 PLIC sources\"
|
||||||
|
set logging file $rawPlicStateFile
|
||||||
|
set logging on
|
||||||
|
# Priority Levels for sources 1 thru 63
|
||||||
|
x/63xw 0x0C000004
|
||||||
|
# Interrupt Enables for sources 1 thru 63 for contexts 0 and 1
|
||||||
|
x/2xw 0x0C002000
|
||||||
|
x/2xw 0x0C002080
|
||||||
|
# Global Priority Threshold for contexts 0 and 1
|
||||||
|
x/1xw 0x0C200000
|
||||||
|
x/1xw 0x0C201000
|
||||||
|
set logging off
|
||||||
|
shell echo \"GDB storing RAM to $rawRamFile\"
|
||||||
|
dump binary memory $rawRamFile 0x80000000 0x87ffffff
|
||||||
|
kill
|
||||||
|
q
|
||||||
|
end_of_script
|
||||||
|
|
||||||
|
# GDB+QEMU
|
||||||
|
echo "Starting QEMU in replay mode with attached GDB script at $(date +%H:%M:%S)"
|
||||||
|
(qemu-system-riscv64 \
|
||||||
|
-M virt -dtb $imageDir/wally-virt.dtb \
|
||||||
|
-nographic \
|
||||||
|
-bios $imageDir/fw_jump.elf -kernel $imageDir/Image -append "root=/dev/vda ro" -initrd $imageDir/rootfs.cpio \
|
||||||
|
-singlestep -rtc clock=vm -icount shift=0,align=off,sleep=on,rr=replay,rrfile=$recordFile \
|
||||||
|
-gdb tcp::$tcpPort -S \
|
||||||
|
1>./qemu-serial) \
|
||||||
|
& riscv64-unknown-elf-gdb --quiet -x genCheckpoint.gdb
|
||||||
|
|
||||||
|
echo "Completed GDB script at $(date +%H:%M:%S)"
|
||||||
|
|
||||||
|
# Post-Process GDB outputs
|
||||||
|
./parseState.py "$checkPtDir"
|
||||||
|
./parseUartState.py "$checkPtDir"
|
||||||
|
./parsePlicState.py "$checkPtDir"
|
||||||
|
echo "Changing Endianness at $(date +%H:%M:%S)"
|
||||||
|
make fixBinMem
|
||||||
|
./fixBinMem "$rawRamFile" "$ramFile"
|
||||||
|
echo "Copying over a truncated trace"
|
||||||
|
tail -n+$instrs $traceFile > $outTraceFile
|
||||||
|
|
||||||
|
echo "Checkpoint completed at $(date +%H:%M:%S)"
|
||||||
|
echo "You may want to restrict write access to $tvDir now and give cad ownership of it."
|
||||||
|
echo "Run the following:"
|
||||||
|
echo " sudo chown -R cad:cad $tvDir"
|
||||||
|
echo " sudo chmod -R go-w $tvDir"
|
||||||
|
fi
|
||||||
|
|
63
docs/docker/testvector-generation/genInitMem.sh
Executable file
63
docs/docker/testvector-generation/genInitMem.sh
Executable file
|
@ -0,0 +1,63 @@
|
||||||
|
#!/bin/bash
|
||||||
|
tcpPort=1235
|
||||||
|
imageDir=$RISCV/buildroot/output/images
|
||||||
|
tvDir=$RISCV/linux-testvectors
|
||||||
|
rawRamFile="$tvDir/ramGDB.bin"
|
||||||
|
ramFile="$tvDir/ram.bin"
|
||||||
|
rawBootmemFile="$tvDir/bootmemGDB.bin"
|
||||||
|
bootmemFile="$tvDir/bootmem.bin"
|
||||||
|
rawUntrimmedBootmemFile="$tvDir/untrimmedBootmemFileGDB.bin"
|
||||||
|
untrimmedBootmemFile="$tvDir/untrimmedBootmemFile.bin"
|
||||||
|
DEVICE_TREE=${imageDir}/wally-virt.dtb
|
||||||
|
|
||||||
|
if [ ! -d "$tvDir" ]; then
|
||||||
|
echo "Error: linux testvector directory $tvDir not found!">&2
|
||||||
|
echo "Please create it. For example:">&2
|
||||||
|
echo " sudo mkdir -p $tvDir">&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
test -w $tvDir
|
||||||
|
if [ ! $? -eq 0 ]; then
|
||||||
|
echo "Error: insuffcient write privileges for linux testvector directory $tvDir !">&2
|
||||||
|
echo "Please chmod it. For example:">&2
|
||||||
|
echo " sudo chmod -R a+rw $tvDir">&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Launching QEMU in replay mode!"
|
||||||
|
(qemu-system-riscv64 \
|
||||||
|
-M virt -m 256M -dtb $DEVICE_TREE \
|
||||||
|
-nographic \
|
||||||
|
-bios $imageDir/fw_jump.elf -kernel $imageDir/Image -append "root=/dev/vda ro" -initrd $imageDir/rootfs.cpio \
|
||||||
|
-gdb tcp::$tcpPort -S) \
|
||||||
|
& riscv64-unknown-elf-gdb --quiet \
|
||||||
|
-ex "set pagination off" \
|
||||||
|
-ex "set logging overwrite on" \
|
||||||
|
-ex "set logging redirect on" \
|
||||||
|
-ex "set confirm off" \
|
||||||
|
-ex "target extended-remote :$tcpPort" \
|
||||||
|
-ex "maintenance packet Qqemu.PhyMemMode:1" \
|
||||||
|
-ex "printf \"Creating $rawBootmemFile\n\"" \
|
||||||
|
-ex "dump binary memory $rawBootmemFile 0x1000 0x1fff" \
|
||||||
|
-ex "printf \"Creating $rawRamFile\n\"" \
|
||||||
|
-ex "dump binary memory $rawRamFile 0x80000000 0x8fffffff" \
|
||||||
|
-ex "kill" \
|
||||||
|
-ex "q"
|
||||||
|
|
||||||
|
#-ex "printf \"Warning - please verify that the second half of $rawUntrimmedBootmemFile is all 0s\n\"" \
|
||||||
|
#-ex "printf \"Creating $rawUntrimmedBootmemFile\n\"" \
|
||||||
|
#-ex "dump binary memory $rawUntrimmedBootmemFile 0x1000 0x2fff" \
|
||||||
|
|
||||||
|
echo "Changing Endianness"
|
||||||
|
make fixBinMem
|
||||||
|
./fixBinMem "$rawRamFile" "$ramFile"
|
||||||
|
./fixBinMem "$rawBootmemFile" "$bootmemFile"
|
||||||
|
#./fixBinMem "$rawUntrimmedBootmemFile" "$untrimmedBootmemFile" # doesn't seem to be used for anything
|
||||||
|
rm -f "$rawRamFile" "$rawBootmemFile" "$rawUntrimmedBootmemFile"
|
||||||
|
|
||||||
|
echo "genInitMem.sh completed!"
|
||||||
|
echo "You may want to restrict write access to $tvDir now and give cad ownership of it."
|
||||||
|
echo "Run the following:"
|
||||||
|
echo " sudo chown -R cad:cad $tvDir"
|
||||||
|
echo " sudo chmod -R go-w $tvDir"
|
||||||
|
|
38
docs/docker/testvector-generation/genRecording.sh
Executable file
38
docs/docker/testvector-generation/genRecording.sh
Executable file
|
@ -0,0 +1,38 @@
|
||||||
|
#!/bin/bash
|
||||||
|
imageDir=$RISCV/buildroot/output/images
|
||||||
|
tvDir=$RISCV/linux-testvectors
|
||||||
|
recordFile="$tvDir/all.qemu"
|
||||||
|
DEVICE_TREE=${imageDir}/wally-virt.dtb
|
||||||
|
|
||||||
|
read -p "Warning: running this script will overwrite $recordFile
|
||||||
|
Would you like to proceed? (y/n) " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ $REPLY =~ ^[Yy]$ ]]
|
||||||
|
then
|
||||||
|
if [ ! -d "$tvDir" ]; then
|
||||||
|
echo "Error: linux testvector directory $tvDir not found!">&2
|
||||||
|
echo "Please create it. For example:">&2
|
||||||
|
echo " sudo mkdir -p $tvDir">&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
test -w $tvDir
|
||||||
|
if [ ! $? -eq 0 ]; then
|
||||||
|
echo "Error: insuffcient write privileges for linux testvector directory $tvDir !">&2
|
||||||
|
echo "Please chmod it. For example:">&2
|
||||||
|
echo " sudo chmod -R a+rw $tvDir">&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Launching QEMU in record mode!"
|
||||||
|
qemu-system-riscv64 \
|
||||||
|
-M virt -m 256M -dtb $DEVICE_TREE \
|
||||||
|
-nographic \
|
||||||
|
-bios $imageDir/fw_jump.elf -kernel $imageDir/Image -append "root=/dev/vda ro" -initrd $imageDir/rootfs.cpio \
|
||||||
|
-singlestep -rtc clock=vm -icount shift=0,align=off,sleep=on,rr=record,rrfile=$recordFile
|
||||||
|
|
||||||
|
echo "genRecording.sh completed!"
|
||||||
|
echo "You may want to restrict write access to $tvDir now and give cad ownership of it."
|
||||||
|
echo "Run the following:"
|
||||||
|
echo " sudo chown -R cad:cad $tvDir"
|
||||||
|
echo " sudo chmod -R go-w $tvDir"
|
||||||
|
fi
|
54
docs/docker/testvector-generation/genTrace.sh
Executable file
54
docs/docker/testvector-generation/genTrace.sh
Executable file
|
@ -0,0 +1,54 @@
|
||||||
|
#!/bin/bash
|
||||||
|
tcpPort=1234
|
||||||
|
imageDir=$RISCV/buildroot/output/images
|
||||||
|
tvDir=$RISCV/linux-testvectors
|
||||||
|
recordFile="$tvDir/all.qemu"
|
||||||
|
traceFile="$tvDir/all.txt"
|
||||||
|
trapsFile="$tvDir/traps.txt"
|
||||||
|
interruptsFile="$tvDir/interrupts.txt"
|
||||||
|
DEVICE_TREE=${imageDir}/wally-virt.dtb
|
||||||
|
|
||||||
|
read -p "Warning: running this script will overwrite the contents of:
|
||||||
|
* $traceFile
|
||||||
|
* $trapsFile
|
||||||
|
* $interruptsFile
|
||||||
|
Would you like to proceed? (y/n) " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ $REPLY =~ ^[Yy]$ ]]
|
||||||
|
then
|
||||||
|
if [ ! -d "$tvDir" ]; then
|
||||||
|
echo "Error: linux testvector directory $tvDir not found!">&2
|
||||||
|
echo "Please create it. For example:">&2
|
||||||
|
echo " sudo mkdir -p $tvDir">&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
test -w $tvDir
|
||||||
|
if [ ! $? -eq 0 ]; then
|
||||||
|
echo "Error: insuffcient write privileges for linux testvector directory $tvDir !">&2
|
||||||
|
echo "Please chmod it. For example:">&2
|
||||||
|
echo " sudo chmod -R a+rw $tvDir">&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
touch $traceFile
|
||||||
|
touch $trapsFile
|
||||||
|
touch $interruptsFile
|
||||||
|
|
||||||
|
# QEMU Simulation
|
||||||
|
echo "Launching QEMU in replay mode!"
|
||||||
|
(qemu-system-riscv64 \
|
||||||
|
-M virt -m 256M -dtb $DEVICE_TREE \
|
||||||
|
-nographic \
|
||||||
|
-bios $imageDir/fw_jump.elf -kernel $imageDir/Image -append "root=/dev/vda ro" -initrd $imageDir/rootfs.cpio \
|
||||||
|
-singlestep -rtc clock=vm -icount shift=0,align=off,sleep=on,rr=replay,rrfile=$recordFile \
|
||||||
|
-d nochain,cpu,in_asm,int \
|
||||||
|
2>&1 >./qemu-serial | ./parseQEMUtoGDB.py | ./parseGDBtoTrace.py $trapsFile > $traceFile)
|
||||||
|
|
||||||
|
./filterTrapsToInterrupts.py $tvDir
|
||||||
|
|
||||||
|
echo "genTrace.sh completed!"
|
||||||
|
echo "You may want to restrict write access to $tvDir now and give cad ownership of it."
|
||||||
|
echo "Run the following:"
|
||||||
|
echo " sudo chown -R cad:cad $tvDir"
|
||||||
|
echo " sudo chmod -R go-w $tvDir"
|
||||||
|
fi
|
243
docs/docker/testvector-generation/parseGDBtoTrace.py
Executable file
243
docs/docker/testvector-generation/parseGDBtoTrace.py
Executable file
|
@ -0,0 +1,243 @@
|
||||||
|
#! /usr/bin/python3
|
||||||
|
import sys, fileinput, re
|
||||||
|
|
||||||
|
# Ross Thompson
|
||||||
|
# July 27, 2021
|
||||||
|
# Rewrite of the linux trace parser.
|
||||||
|
|
||||||
|
|
||||||
|
InstrStartDelim = '=>'
|
||||||
|
InstrEndDelim = '-----'
|
||||||
|
|
||||||
|
#InputFile = 'noparse.txt'
|
||||||
|
#InputFile = sys.stdin
|
||||||
|
#InputFile = 'temp.txt'
|
||||||
|
#OutputFile = 'parsedAll.txt'
|
||||||
|
|
||||||
|
HUMAN_READABLE = False
|
||||||
|
|
||||||
|
def toDict(lst):
|
||||||
|
'Converts the list of register values to a dictionary'
|
||||||
|
dct= {}
|
||||||
|
for item in lst:
|
||||||
|
regTup = item.split()
|
||||||
|
dct[regTup[0]] = int(regTup[2], 10)
|
||||||
|
del dct['pc']
|
||||||
|
return dct
|
||||||
|
|
||||||
|
def whichClass(text, Regs):
|
||||||
|
'Which instruction class?'
|
||||||
|
#print(text, Regs)
|
||||||
|
if text[0:2] == 'ld' or text[0:2] == 'lw' or text[0:2] == 'lh' or text[0:2] == 'lb':
|
||||||
|
return ('load', WhatAddr(text, Regs), None, WhatMemDestSource(text))
|
||||||
|
elif text[0:2] == 'sd' or text[0:2] == 'sw' or text[0:2] == 'sh' or text[0:2] == 'sb':
|
||||||
|
return ('store', WhatAddr(text, Regs), WhatMemDestSource(text), None)
|
||||||
|
elif text[0:3] == 'amo':
|
||||||
|
return ('amo', WhatAddrAMO(text, Regs), WhatMemDestSource(text), WhatMemDestSource(text))
|
||||||
|
elif text[0:2] == 'lr':
|
||||||
|
return ('lr', WhatAddrLR(text, Regs), None, WhatMemDestSource(text))
|
||||||
|
elif text[0:2] == 'sc':
|
||||||
|
return ('sc', WhatAddrSC(text, Regs), WhatMemDestSource(text), None)
|
||||||
|
else:
|
||||||
|
return ('other', None, None, None)
|
||||||
|
|
||||||
|
def whatChanged(dct0, dct1):
|
||||||
|
'Compares two dictionaries of instrution registers and indicates which registers changed'
|
||||||
|
dct = {}
|
||||||
|
for key in dct0:
|
||||||
|
if (dct1[key] != dct0[key]):
|
||||||
|
dct[key] = dct1[key]
|
||||||
|
return dct
|
||||||
|
|
||||||
|
def WhatMemDestSource(text):
|
||||||
|
''''What is the destination register. Used to compute where the read data is
|
||||||
|
on a load or the write data on a store.'''
|
||||||
|
return text.split()[1].split(',')[0]
|
||||||
|
|
||||||
|
def WhatAddr(text, Regs):
|
||||||
|
'What is the data memory address?'
|
||||||
|
Imm = text.split(',')[1]
|
||||||
|
(Imm, Src) = Imm.split('(')
|
||||||
|
Imm = int(Imm.strip(), 10)
|
||||||
|
Src = Src.strip(')').strip()
|
||||||
|
RegVal = Regs[Src]
|
||||||
|
return Imm + RegVal
|
||||||
|
|
||||||
|
def WhatAddrAMO(text, Regs):
|
||||||
|
'What is the data memory address?'
|
||||||
|
Src = text.split('(')[1]
|
||||||
|
Src = Src.strip(')').strip()
|
||||||
|
return Regs[Src]
|
||||||
|
|
||||||
|
def WhatAddrLR(text, Regs):
|
||||||
|
'What is the data memory address?'
|
||||||
|
Src = text.split('(')[1]
|
||||||
|
Src = Src.strip(')').strip()
|
||||||
|
return Regs[Src]
|
||||||
|
|
||||||
|
def WhatAddrSC(text, Regs):
|
||||||
|
'What is the data memory address?'
|
||||||
|
Src = text.split('(')[1]
|
||||||
|
Src = Src.strip(')').strip()
|
||||||
|
return Regs[Src]
|
||||||
|
|
||||||
|
def PrintInstr(instr):
|
||||||
|
if instr[2] == None:
|
||||||
|
return
|
||||||
|
ChangedRegisters = instr[4]
|
||||||
|
GPR = ''
|
||||||
|
CSR = []
|
||||||
|
for key in ChangedRegisters:
|
||||||
|
# filter out csr which are not checked.
|
||||||
|
if(key in RegNumber):
|
||||||
|
if(RegNumber[key] < 32):
|
||||||
|
# GPR
|
||||||
|
if(HUMAN_READABLE):
|
||||||
|
GPR = '{:-2d} {:016x}'.format(RegNumber[key], ChangedRegisters[key])
|
||||||
|
else:
|
||||||
|
GPR = '{:d} {:x}'.format(RegNumber[key], ChangedRegisters[key])
|
||||||
|
else:
|
||||||
|
if(HUMAN_READABLE):
|
||||||
|
CSR.extend([key, '{:016x}'.format(ChangedRegisters[key])])
|
||||||
|
else:
|
||||||
|
CSR.extend([key, '{:x}'.format(ChangedRegisters[key])])
|
||||||
|
|
||||||
|
CSRStr = ' '.join(CSR)
|
||||||
|
|
||||||
|
#print(instr)
|
||||||
|
|
||||||
|
if (HUMAN_READABLE == True):
|
||||||
|
outString='{:016x} {:08x} {:25s}'.format(instr[0], instr[1], instr[2])
|
||||||
|
if(len(GPR) != 0):
|
||||||
|
outString+=' GPR {}'.format(GPR)
|
||||||
|
if(instr[3] == 'load' or instr[3] == 'lr'):
|
||||||
|
outString+=' MemR {:016x} {:016x} {:016x}'.format(instr[5], 0, instr[7])
|
||||||
|
if(instr[3] == 'store'):
|
||||||
|
outString+='\t\t\t MemW {:016x} {:016x} {:016x}'.format(instr[5], instr[6], 0)
|
||||||
|
if(len(CSR) != 0):
|
||||||
|
outString+=' CSR {}'.format(CSRStr)
|
||||||
|
else:
|
||||||
|
outString='{:x} {:x} {:s}'.format(instr[0], instr[1], instr[2].replace(' ', '_'))
|
||||||
|
if(len(GPR) != 0):
|
||||||
|
outString+=' GPR {}'.format(GPR)
|
||||||
|
if(instr[3] == 'load' or instr[3] == 'lr'):
|
||||||
|
outString+=' MemR {:x} {:x} {:x}'.format(instr[5], 0, instr[7])
|
||||||
|
if(instr[3] == 'store'):
|
||||||
|
outString+=' MemW {:x} {:x} {:x}'.format(instr[5], instr[6], 0)
|
||||||
|
if(len(CSR) != 0):
|
||||||
|
outString+=' CSR {}'.format(CSRStr)
|
||||||
|
outString+='\n'
|
||||||
|
return outString
|
||||||
|
|
||||||
|
# =========
|
||||||
|
# Main Code
|
||||||
|
# =========
|
||||||
|
# Parse argument for interrupt file
|
||||||
|
if len(sys.argv) != 2:
|
||||||
|
sys.exit('Error parseGDBtoTrace.py expects 1 arg:\n <interrupt filename>>')
|
||||||
|
interruptFname = sys.argv[1]
|
||||||
|
# reg number
|
||||||
|
RegNumber = {'zero': 0, 'ra': 1, 'sp': 2, 'gp': 3, 'tp': 4, 't0': 5, 't1': 6, 't2': 7, 's0': 8, 's1': 9, 'a0': 10, 'a1': 11, 'a2': 12, 'a3': 13, 'a4': 14, 'a5': 15, 'a6': 16, 'a7': 17, 's2': 18, 's3': 19, 's4': 20, 's5': 21, 's6': 22, 's7': 23, 's8': 24, 's9': 25, 's10': 26, 's11': 27, 't3': 28, 't4': 29, 't5': 30, 't6': 31, 'mhartid': 32, 'mstatus': 33, 'mip': 34, 'mie': 35, 'mideleg': 36, 'medeleg': 37, 'mtvec': 38, 'stvec': 39, 'mepc': 40, 'sepc': 41, 'mcause': 42, 'scause': 43, 'mtval': 44, 'stval': 45, 'mscratch': 46, 'sscratch': 47, 'satp': 48}
|
||||||
|
# initial state
|
||||||
|
CurrentInstr = ['0', '0', None, 'other', {'zero': 0, 'ra': 0, 'sp': 0, 'gp': 0, 'tp': 0, 't0': 0, 't1': 0, 't2': 0, 's0': 0, 's1': 0, 'a0': 0, 'a1': 0, 'a2': 0, 'a3': 0, 'a4': 0, 'a5': 0, 'a6': 0, 'a7': 0, 's2': 0, 's3': 0, 's4': 0, 's5': 0, 's6': 0, 's7': 0, 's8': 0, 's9': 0, 's10': 0, 's11': 0, 't3': 0, 't4': 0, 't5': 0, 't6': 0, 'mhartid': 0, 'mstatus': 0, 'mip': 0, 'mie': 0, 'mideleg': 0, 'medeleg': 0, 'mtvec': 0, 'stvec': 0, 'mepc': 0, 'sepc': 0, 'mcause': 0, 'scause': 0, 'mtval': 0, 'stval': 0, 'mscratch': 0, 'sscratch': 0, 'satp': 0}, {}, None, None, None]
|
||||||
|
|
||||||
|
#with open (InputFile, 'r') as InputFileFP:
|
||||||
|
#lines = InputFileFP.readlines()
|
||||||
|
lineNum = 0
|
||||||
|
StartLine = 0
|
||||||
|
EndLine = 0
|
||||||
|
numInstrs = 0
|
||||||
|
#instructions = []
|
||||||
|
MemAdr = 0
|
||||||
|
lines = []
|
||||||
|
interrupts=open(interruptFname,'w')
|
||||||
|
interrupts.close()
|
||||||
|
|
||||||
|
prevInstrOutString=''
|
||||||
|
currInstrOutString=''
|
||||||
|
for line in fileinput.input('-'):
|
||||||
|
if line.startswith('riscv_cpu_do_interrupt'):
|
||||||
|
with open(interruptFname,'a') as interrupts:
|
||||||
|
# Write line
|
||||||
|
# Example line: hart:0, async:0, cause:0000000000000002, epc:0x0000000080008548, tval:0x0000000000000000, desc=illegal_instruction
|
||||||
|
interrupts.write(line)
|
||||||
|
# Write instruction count
|
||||||
|
interrupts.write(str(numInstrs)+'\n')
|
||||||
|
# Convert line to rows of info for easier Verilog parsing
|
||||||
|
vals=line.strip('riscv_cpu_do_interrupt: ').strip('\n').split(',')
|
||||||
|
vals=[val.split(':')[-1].strip(' ') for val in vals]
|
||||||
|
vals=[val.split('=')[-1].strip(' ') for val in vals]
|
||||||
|
for val in vals:
|
||||||
|
interrupts.write(val+'\n')
|
||||||
|
continue
|
||||||
|
lines.insert(lineNum, line)
|
||||||
|
if InstrStartDelim in line:
|
||||||
|
lineNum = 0
|
||||||
|
StartLine = lineNum
|
||||||
|
elif InstrEndDelim in line:
|
||||||
|
EndLine = lineNum
|
||||||
|
(InstrBits, text) = lines[StartLine].split(':')
|
||||||
|
InstrBits = int(InstrBits.strip('=> '), 16)
|
||||||
|
text = text.strip()
|
||||||
|
PC = int(lines[StartLine+1].split(':')[0][2:], 16)
|
||||||
|
Regs = toDict(lines[StartLine+2:EndLine])
|
||||||
|
(Class, Addr, WriteReg, ReadReg) = whichClass(text, Regs)
|
||||||
|
#print("CWR", Class, WriteReg, ReadReg)
|
||||||
|
PreviousInstr = CurrentInstr
|
||||||
|
|
||||||
|
Changed = whatChanged(PreviousInstr[4], Regs)
|
||||||
|
|
||||||
|
if (ReadReg !=None): ReadData = ReadReg
|
||||||
|
else: ReadData = None
|
||||||
|
|
||||||
|
if (WriteReg !=None): WriteData = WriteReg
|
||||||
|
else: WriteData = None
|
||||||
|
|
||||||
|
CurrentInstr = [PC, InstrBits, text, Class, Regs, Changed, Addr, WriteData, ReadData]
|
||||||
|
|
||||||
|
#print(CurrentInstr[0:4], PreviousInstr[5], CurrentInstr[6:7], PreviousInstr[8])
|
||||||
|
|
||||||
|
# pc, instrbits, text and class come from the last line.
|
||||||
|
MoveInstrToRegWriteLst = PreviousInstr[0:4]
|
||||||
|
# updated registers come from the current line.
|
||||||
|
MoveInstrToRegWriteLst.append(CurrentInstr[5]) # destination regs
|
||||||
|
# memory address if present comes from the last line.
|
||||||
|
MoveInstrToRegWriteLst.append(PreviousInstr[6]) # MemAdrM
|
||||||
|
# write data from the previous line
|
||||||
|
#MoveInstrToRegWriteLst.append(PreviousInstr[7]) # WriteDataM
|
||||||
|
|
||||||
|
if (PreviousInstr[7] != None):
|
||||||
|
MoveInstrToRegWriteLst.append(Regs[PreviousInstr[7]]) # WriteDataM
|
||||||
|
else:
|
||||||
|
MoveInstrToRegWriteLst.append(None)
|
||||||
|
|
||||||
|
# read data from the current line
|
||||||
|
#MoveInstrToRegWriteLst.append(PreviousInstr[8]) # ReadDataM
|
||||||
|
if (PreviousInstr[8] != None):
|
||||||
|
MoveInstrToRegWriteLst.append(Regs[PreviousInstr[8]]) # ReadDataM
|
||||||
|
else:
|
||||||
|
MoveInstrToRegWriteLst.append(None)
|
||||||
|
|
||||||
|
lines.clear()
|
||||||
|
#instructions.append(MoveInstrToRegWriteLst)
|
||||||
|
|
||||||
|
prevInstrOutString = currInstrOutString
|
||||||
|
currInstrOutString = PrintInstr(MoveInstrToRegWriteLst)
|
||||||
|
# Remove duplicates
|
||||||
|
if (PreviousInstr[0] != CurrentInstr[0]) and (currInstrOutString != None):
|
||||||
|
sys.stdout.write(currInstrOutString)
|
||||||
|
numInstrs += 1
|
||||||
|
if (numInstrs % 1e5 == 0):
|
||||||
|
sys.stderr.write('GDB trace parser reached '+str(numInstrs/1.0e6)+' million instrs.\n')
|
||||||
|
sys.stderr.flush()
|
||||||
|
lineNum += 1
|
||||||
|
|
||||||
|
|
||||||
|
#for instruction in instructions[1::]:
|
||||||
|
|
||||||
|
|
||||||
|
#with open(OutputFile, 'w') as OutputFileFP:
|
||||||
|
# print('opened file')
|
||||||
|
|
||||||
|
|
||||||
|
|
106
docs/docker/testvector-generation/parsePlicState.py
Executable file
106
docs/docker/testvector-generation/parsePlicState.py
Executable file
|
@ -0,0 +1,106 @@
|
||||||
|
#! /usr/bin/python3
|
||||||
|
import sys, os
|
||||||
|
from functools import reduce
|
||||||
|
|
||||||
|
################
|
||||||
|
# Helper Funcs #
|
||||||
|
################
|
||||||
|
|
||||||
|
def tokenize(string):
|
||||||
|
tokens = []
|
||||||
|
token = ''
|
||||||
|
whitespace = 0
|
||||||
|
prevWhitespace = 0
|
||||||
|
for char in string:
|
||||||
|
prevWhitespace = whitespace
|
||||||
|
whitespace = char in ' \t\n'
|
||||||
|
if (whitespace):
|
||||||
|
if ((not prevWhitespace) and (token != '')):
|
||||||
|
tokens.append(token)
|
||||||
|
token = ''
|
||||||
|
else:
|
||||||
|
token = token + char
|
||||||
|
return tokens
|
||||||
|
|
||||||
|
def strip0x(num):
|
||||||
|
return num[2:]
|
||||||
|
|
||||||
|
def stripZeroes(num):
|
||||||
|
num = int(num,16)
|
||||||
|
return hex(num)[2:]
|
||||||
|
|
||||||
|
#############
|
||||||
|
# Main Code #
|
||||||
|
#############
|
||||||
|
print("Begin parsing PLIC state.")
|
||||||
|
|
||||||
|
# Parse Args
|
||||||
|
if len(sys.argv) != 2:
|
||||||
|
sys.exit('Error parsePlicState.py expects 1 arg: <path_to_checkpoint_dir>')
|
||||||
|
outDir = sys.argv[1]+'/'
|
||||||
|
rawPlicStateFile = outDir+'plicStateGDB.txt'
|
||||||
|
if not os.path.exists(rawPlicStateFile):
|
||||||
|
sys.exit('Error input file '+rawPlicStateFile+'not found')
|
||||||
|
|
||||||
|
with open(rawPlicStateFile, 'r') as rawPlicStateFile:
|
||||||
|
plicIntPriorityArray = [] # iterates over number of different sources
|
||||||
|
# 0x0C000004 thru 0x0C000010
|
||||||
|
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
|
||||||
|
# 0x0C000014 thru 0x0C000020
|
||||||
|
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
|
||||||
|
# 0x0C000024 thru 0x0C000030
|
||||||
|
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
|
||||||
|
# 0x0C000034 thru 0x0C000040
|
||||||
|
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
|
||||||
|
# 0x0C000044 thru 0x0C000050
|
||||||
|
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
|
||||||
|
# 0x0C000054 thru 0x0C000060
|
||||||
|
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
|
||||||
|
# 0x0C000064 thru 0x0C000070
|
||||||
|
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
|
||||||
|
# 0x0C000074 thru 0x0C000080
|
||||||
|
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
|
||||||
|
# 0x0C000084 thru 0x0C000090
|
||||||
|
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
|
||||||
|
# 0x0C000094 thru 0x0C0000a0
|
||||||
|
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
|
||||||
|
# 0x0C0000a4 thru 0x0C0000b0
|
||||||
|
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
|
||||||
|
# 0x0C0000b4 thru 0x0C0000c0
|
||||||
|
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
|
||||||
|
# 0x0C0000c4 thru 0x0C0000d0
|
||||||
|
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
|
||||||
|
# 0x0C0000d4 thru 0x0C0000e0
|
||||||
|
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
|
||||||
|
# 0x0C0000e4 thru 0x0C0000f0
|
||||||
|
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
|
||||||
|
# 0x0C0000f4 thru 0x0C0000fc
|
||||||
|
plicIntPriorityArray += tokenize(rawPlicStateFile.readline())[1:]
|
||||||
|
|
||||||
|
plicIntEnableArray = [] # iterates over number of different contexts
|
||||||
|
# 0x0C020000 thru 0x0C020004
|
||||||
|
plicIntEnable = tokenize(rawPlicStateFile.readline())[1:]
|
||||||
|
plicIntEnable = map(strip0x,plicIntEnable)
|
||||||
|
plicIntEnableArray.append(reduce(lambda x,y: y+x,plicIntEnable))
|
||||||
|
# 0x0C020080 thru 0x0C020084
|
||||||
|
plicIntEnable = tokenize(rawPlicStateFile.readline())[1:]
|
||||||
|
plicIntEnable = map(strip0x,plicIntEnable)
|
||||||
|
plicIntEnableArray.append(reduce(lambda x,y: y+x,plicIntEnable))
|
||||||
|
|
||||||
|
plicIntPriorityThresholdArray = [] # iterates over number of different contexts
|
||||||
|
# 0x0C200000
|
||||||
|
plicIntPriorityThresholdArray += tokenize(rawPlicStateFile.readline())[1:]
|
||||||
|
# 0x0C201000
|
||||||
|
plicIntPriorityThresholdArray += tokenize(rawPlicStateFile.readline())[1:]
|
||||||
|
|
||||||
|
with open(outDir+'checkpoint-PLIC_INT_PRIORITY', 'w') as outFile:
|
||||||
|
for word in plicIntPriorityArray:
|
||||||
|
outFile.write(stripZeroes(word[2:])+'\n')
|
||||||
|
with open(outDir+'checkpoint-PLIC_INT_ENABLE', 'w') as outFile:
|
||||||
|
for word in plicIntEnableArray:
|
||||||
|
outFile.write(stripZeroes(word[2:])+'\n')
|
||||||
|
with open(outDir+'checkpoint-PLIC_THRESHOLD', 'w') as outFile:
|
||||||
|
for word in plicIntPriorityThresholdArray:
|
||||||
|
outFile.write(stripZeroes(word[2:])+'\n')
|
||||||
|
|
||||||
|
print("Finished parsing PLIC state!")
|
145
docs/docker/testvector-generation/parseQEMUtoGDB.py
Executable file
145
docs/docker/testvector-generation/parseQEMUtoGDB.py
Executable file
|
@ -0,0 +1,145 @@
|
||||||
|
#! /usr/bin/python3
|
||||||
|
import fileinput, sys
|
||||||
|
|
||||||
|
parseState = "idle"
|
||||||
|
beginPageFault = 0
|
||||||
|
inPageFault = 0
|
||||||
|
endPageFault = 0
|
||||||
|
CSRs = {}
|
||||||
|
pageFaultCSRs = {}
|
||||||
|
regs = {}
|
||||||
|
pageFaultRegs = {}
|
||||||
|
instrs = {}
|
||||||
|
instrCount = 0
|
||||||
|
returnAdr = 0
|
||||||
|
sys.stderr.write("reminder: parse_qemu.py takes input from stdin\n")
|
||||||
|
|
||||||
|
def printPC(l):
|
||||||
|
global parseState, inPageFault, CSRs, pageFaultCSRs, regs, pageFaultCSRs, instrs, instrCount
|
||||||
|
if not inPageFault:
|
||||||
|
inst = l.split()
|
||||||
|
if len(inst) > 3:
|
||||||
|
print(f'=> {inst[1]}:\t{inst[2]} {inst[3]}')
|
||||||
|
else:
|
||||||
|
print(f'=> {inst[1]}:\t{inst[2]}')
|
||||||
|
print(f'{inst[0]} 0x{inst[1]}')
|
||||||
|
instrCount += 1
|
||||||
|
if ((instrCount % 100000) == 0):
|
||||||
|
sys.stderr.write("QEMU parser reached "+str(instrCount)+" instrs\n")
|
||||||
|
|
||||||
|
def printCSRs():
|
||||||
|
global parseState, inPageFault, CSRs, pageFaultCSRs, regs, pageFaultCSRs, instrs
|
||||||
|
global interrupt_line
|
||||||
|
if not inPageFault:
|
||||||
|
for (csr,val) in CSRs.items():
|
||||||
|
print('{}{}{:#x} {}'.format(csr, ' '*(15-len(csr)), val, val))
|
||||||
|
print('-----') # end of current instruction
|
||||||
|
if len(interrupt_line)>0: # squish interrupts in between instructions
|
||||||
|
print(interrupt_line)
|
||||||
|
interrupt_line=""
|
||||||
|
|
||||||
|
def parseCSRs(l):
|
||||||
|
global parseState, inPageFault, CSRs, pageFaultCSRs, regs, pageFaultCSRs, instrs
|
||||||
|
if l.strip() and (not l.startswith("Disassembler")) and (not l.startswith("Please")):
|
||||||
|
# If we've hit the register file
|
||||||
|
if l.startswith(' x0/zero'):
|
||||||
|
parseState = "regFile"
|
||||||
|
if not inPageFault:
|
||||||
|
instr = instrs[CSRs["pc"]]
|
||||||
|
printPC(instr)
|
||||||
|
parseRegs(l)
|
||||||
|
# If we've hit a CSR
|
||||||
|
else:
|
||||||
|
csr = l.split()[0]
|
||||||
|
val = int(l.split()[1],16)
|
||||||
|
# Commented out this conditional because the pageFault instrs don't corrupt CSRs
|
||||||
|
#if inPageFault:
|
||||||
|
# Not sure if these CSRs should be updated or not during page fault.
|
||||||
|
#if l.startswith("mstatus") or l.startswith("mepc") or l.startswith("mcause") or l.startswith("mtval") or l.startswith("sepc") or l.startswith("scause") or l.startswith("stval"):
|
||||||
|
# We do update some CSRs
|
||||||
|
# CSRs[csr] = val
|
||||||
|
#else:
|
||||||
|
# Others we preserve until changed later
|
||||||
|
# pageFaultCSRs[csr] = val
|
||||||
|
#elif pageFaultCSRs and (csr in pageFaultCSRs):
|
||||||
|
# if (val != pageFaultCSRs[csr]):
|
||||||
|
# del pageFaultCSRs[csr]
|
||||||
|
# CSRs[csr] = val
|
||||||
|
#else:
|
||||||
|
# CSRs[csr] = val
|
||||||
|
#
|
||||||
|
# However SEPC and STVAL do get corrupted upon exiting
|
||||||
|
if endPageFault and ((csr == 'sepc') or (csr == 'stval')):
|
||||||
|
CSRs[csr] = returnAdr
|
||||||
|
pageFaultCSRs[csr] = val
|
||||||
|
elif pageFaultCSRs and (csr in pageFaultCSRs):
|
||||||
|
if (val != pageFaultCSRs[csr]):
|
||||||
|
del pageFaultCSRs[csr]
|
||||||
|
CSRs[csr] = val
|
||||||
|
else:
|
||||||
|
CSRs[csr] = val
|
||||||
|
|
||||||
|
def parseRegs(l):
|
||||||
|
global parseState, inPageFault, CSRs, pageFaultCSRs, regs, pageFaultCSRs, instrs, pageFaultRegs
|
||||||
|
if "pc" in l:
|
||||||
|
printCSRs()
|
||||||
|
# New non-disassembled instruction
|
||||||
|
parseState = "CSRs"
|
||||||
|
parseCSRs(l)
|
||||||
|
elif l.startswith('--------'):
|
||||||
|
# End of disassembled instruction
|
||||||
|
printCSRs()
|
||||||
|
parseState = "idle"
|
||||||
|
else:
|
||||||
|
s = l.split()
|
||||||
|
for i in range(0,len(s),2):
|
||||||
|
if '/' in s[i]:
|
||||||
|
reg = s[i].split('/')[1]
|
||||||
|
val = int(s[i+1], 16)
|
||||||
|
if inPageFault:
|
||||||
|
pageFaultRegs[reg] = val
|
||||||
|
else:
|
||||||
|
if pageFaultRegs and (reg in pageFaultRegs):
|
||||||
|
if (val != pageFaultRegs[reg]):
|
||||||
|
del pageFaultRegs[reg]
|
||||||
|
regs[reg] = val
|
||||||
|
else:
|
||||||
|
regs[reg] = val
|
||||||
|
val = regs[reg]
|
||||||
|
print('{}{}{:#x} {}'.format(reg, ' '*(15-len(reg)), val, val))
|
||||||
|
else:
|
||||||
|
sys.stderr.write("Whoops. Expected a list of reg file regs; got:\n"+l)
|
||||||
|
|
||||||
|
#############
|
||||||
|
# Main Code #
|
||||||
|
#############
|
||||||
|
interrupt_line=""
|
||||||
|
for l in fileinput.input():
|
||||||
|
#sys.stderr.write(l)
|
||||||
|
if l.startswith('riscv_cpu_do_interrupt'):
|
||||||
|
sys.stderr.write(l)
|
||||||
|
interrupt_line = l.strip('\n')
|
||||||
|
elif l.startswith('qemu-system-riscv64: QEMU: Terminated via GDBstub'):
|
||||||
|
break
|
||||||
|
elif l.startswith('IN:'):
|
||||||
|
# New disassembled instr
|
||||||
|
parseState = "instr"
|
||||||
|
elif (parseState == "instr") and l.startswith('0x'):
|
||||||
|
# New instruction
|
||||||
|
if "out of bounds" in l:
|
||||||
|
sys.stderr.write("Detected QEMU page fault error\n")
|
||||||
|
beginPageFault = not inPageFault
|
||||||
|
if beginPageFault:
|
||||||
|
returnAdr = int(l.split()[0][2:-1], 16)
|
||||||
|
sys.stderr.write('Saving SEPC of '+hex(returnAdr)+'\n')
|
||||||
|
inPageFault = 1
|
||||||
|
else:
|
||||||
|
endPageFault = inPageFault
|
||||||
|
inPageFault = 0
|
||||||
|
adr = int(l.split()[0][2:-1], 16)
|
||||||
|
instrs[adr] = l
|
||||||
|
parseState = "CSRs"
|
||||||
|
elif parseState == "CSRs":
|
||||||
|
parseCSRs(l)
|
||||||
|
elif parseState == "regFile":
|
||||||
|
parseRegs(l)
|
99
docs/docker/testvector-generation/parseState.py
Executable file
99
docs/docker/testvector-generation/parseState.py
Executable file
|
@ -0,0 +1,99 @@
|
||||||
|
#! /usr/bin/python3
|
||||||
|
import sys, os
|
||||||
|
|
||||||
|
################
|
||||||
|
# Helper Funcs #
|
||||||
|
################
|
||||||
|
|
||||||
|
def tokenize(string):
|
||||||
|
tokens = []
|
||||||
|
token = ''
|
||||||
|
whitespace = 0
|
||||||
|
prevWhitespace = 0
|
||||||
|
for char in string:
|
||||||
|
prevWhitespace = whitespace
|
||||||
|
whitespace = char in ' \t\n'
|
||||||
|
if (whitespace):
|
||||||
|
if ((not prevWhitespace) and (token != '')):
|
||||||
|
tokens.append(token)
|
||||||
|
token = ''
|
||||||
|
else:
|
||||||
|
token = token + char
|
||||||
|
return tokens
|
||||||
|
|
||||||
|
#############
|
||||||
|
# Main Code #
|
||||||
|
#############
|
||||||
|
print("Begin parsing CPU state.")
|
||||||
|
|
||||||
|
# Parse Args
|
||||||
|
if len(sys.argv) != 2:
|
||||||
|
sys.exit('Error parseState.py expects 1 arg:\n parseState.py <path_to_checkpoint_dir>')
|
||||||
|
outDir = sys.argv[1]+'/'
|
||||||
|
stateGDBpath = outDir+'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','priv','sie','sip','sstatus']
|
||||||
|
# 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']
|
||||||
|
|
||||||
|
# Initialize List CSR files to empty
|
||||||
|
# (because later we'll open them in append mode)
|
||||||
|
for csr in listCSRs+pmpcfg:
|
||||||
|
outFileName = 'checkpoint-'+csr.upper()
|
||||||
|
outFile = open(outDir+outFileName, 'w')
|
||||||
|
outFile.close()
|
||||||
|
|
||||||
|
# Initial State for Main Loop
|
||||||
|
currState = 'regFile'
|
||||||
|
regFileIndex = 0
|
||||||
|
outFileName = 'checkpoint-RF'
|
||||||
|
outFile = open(outDir+outFileName, 'w')
|
||||||
|
|
||||||
|
# Main Loop
|
||||||
|
with open(stateGDBpath, 'r') as stateGDB:
|
||||||
|
for line in stateGDB:
|
||||||
|
line = tokenize(line)
|
||||||
|
name = line[0]
|
||||||
|
val = line[1][2:]
|
||||||
|
if (currState == 'regFile'):
|
||||||
|
if (regFileIndex == 0 and name != 'zero'):
|
||||||
|
print('Whoops! Expected regFile registers to come first, starting with zero')
|
||||||
|
exit(1)
|
||||||
|
if (name != 'zero'):
|
||||||
|
# Wally doesn't need to know zero=0
|
||||||
|
outFile.write(val+'\n')
|
||||||
|
regFileIndex += 1
|
||||||
|
if (regFileIndex == 32):
|
||||||
|
outFile.close()
|
||||||
|
currState = 'CSRs'
|
||||||
|
elif (currState == 'CSRs'):
|
||||||
|
if name in singleCSRs:
|
||||||
|
outFileName = 'checkpoint-'+name.upper()
|
||||||
|
outFile = open(outDir+outFileName, 'w')
|
||||||
|
outFile.write(val+'\n')
|
||||||
|
outFile.close()
|
||||||
|
elif name in thirtyTwoBitCSRs:
|
||||||
|
outFileName = 'checkpoint-'+name.upper()
|
||||||
|
outFile = open(outDir+outFileName, 'w')
|
||||||
|
val = int(val,16) & 0xffffffff
|
||||||
|
outFile.write(hex(val)[2:]+'\n')
|
||||||
|
outFile.close()
|
||||||
|
elif name.strip('0123456789') in listCSRs:
|
||||||
|
outFileName = 'checkpoint-'+name.upper().strip('0123456789')
|
||||||
|
outFile = open(outDir+outFileName, 'a')
|
||||||
|
outFile.write(val+'\n')
|
||||||
|
outFile.close()
|
||||||
|
elif name.strip('0123456789') in pmpcfg:
|
||||||
|
outFileName = 'checkpoint-'+name.upper().strip('0123456789')
|
||||||
|
outFile = open(outDir+outFileName, 'a')
|
||||||
|
fourPmp = int(val,16)
|
||||||
|
for i in range(0,4):
|
||||||
|
byte = (fourPmp >> 8*i) & 0xff
|
||||||
|
outFile.write(hex(byte)[2:]+'\n')
|
||||||
|
outFile.close()
|
||||||
|
|
||||||
|
print("Finished parsing CPU state!")
|
50
docs/docker/testvector-generation/parseUartState.py
Executable file
50
docs/docker/testvector-generation/parseUartState.py
Executable file
|
@ -0,0 +1,50 @@
|
||||||
|
#! /usr/bin/python3
|
||||||
|
import sys, os
|
||||||
|
|
||||||
|
################
|
||||||
|
# Helper Funcs #
|
||||||
|
################
|
||||||
|
|
||||||
|
def tokenize(string):
|
||||||
|
tokens = []
|
||||||
|
token = ''
|
||||||
|
whitespace = 0
|
||||||
|
prevWhitespace = 0
|
||||||
|
for char in string:
|
||||||
|
prevWhitespace = whitespace
|
||||||
|
whitespace = char in ' \t\n'
|
||||||
|
if (whitespace):
|
||||||
|
if ((not prevWhitespace) and (token != '')):
|
||||||
|
tokens.append(token)
|
||||||
|
token = ''
|
||||||
|
else:
|
||||||
|
token = token + char
|
||||||
|
return tokens
|
||||||
|
|
||||||
|
#############
|
||||||
|
# Main Code #
|
||||||
|
#############
|
||||||
|
print("Begin parsing UART state.")
|
||||||
|
|
||||||
|
# Parse Args
|
||||||
|
if len(sys.argv) != 2:
|
||||||
|
sys.exit('Error parseUartState.py expects 1 arg: <path_to_checkpoint_dir>')
|
||||||
|
outDir = sys.argv[1]+'/'
|
||||||
|
rawUartStateFile = outDir+'uartStateGDB.txt'
|
||||||
|
if not os.path.exists(rawUartStateFile):
|
||||||
|
sys.exit('Error input file '+rawUartStateFile+'not found')
|
||||||
|
|
||||||
|
with open(rawUartStateFile, 'r') as rawUartStateFile:
|
||||||
|
uartBytes = []
|
||||||
|
for i in range(0,8):
|
||||||
|
uartBytes += tokenize(rawUartStateFile.readline())[1:]
|
||||||
|
with open(outDir+'checkpoint-UART_IER', 'w') as outFile:
|
||||||
|
outFile.write(uartBytes[1][2:])
|
||||||
|
with open(outDir+'checkpoint-UART_LCR', 'w') as outFile:
|
||||||
|
outFile.write(uartBytes[3][2:])
|
||||||
|
with open(outDir+'checkpoint-UART_MCR', 'w') as outFile:
|
||||||
|
outFile.write(uartBytes[4][2:])
|
||||||
|
with open(outDir+'checkpoint-UART_SCR', 'w') as outFile:
|
||||||
|
outFile.write(uartBytes[7][2:])
|
||||||
|
|
||||||
|
print("Finished parsing UART state!")
|
Loading…
Add table
Add a link
Reference in a new issue