Skip to content

Instantly share code, notes, and snippets.

@ianklatzco
Last active January 2, 2019 05:58
Show Gist options
  • Save ianklatzco/75c3af557cb0aca122141037470eb162 to your computer and use it in GitHub Desktop.
Save ianklatzco/75c3af557cb0aca122141037470eb162 to your computer and use it in GitHub Desktop.
Python testcode for ECE411

These scripts automatically compile RISC-V code, simulate it with the command line version of ModelSim, and report the time it took to run the code in nanoseconds.

It is particularly useful for the final part of the course, where you will be tweaking your CPU for performance, but you might get some use out of modifying the scripts a bit for the earlier MPs as well.

Assumptions:

  • Your code lives in ~/ece411/reponame.
  • rv_load_memory.sh is in reponame/testcode.
  • These two scripts (run_tests.py and run-all-tests.sh) live in reponame/testcode/python.
  • You are running the scripts while current directory is reponame/.

You'll need to change h to your repo's name in the top of both scripts.

This code relies on the run_NAME_msim_verilog.do files generated by Quartus after you attempt to build at least once. This must be done whenever you add a new file to the project.

#!/bin/bash
echo "Usage: ./testcode/python/run-all-tests.sh"
# Copy rv_load_memory.sh into ./testcode.
# run me from project root (ie, h)
DIRECTORY="/home/"$USER"/ece411/h" # CHANGEME
echo "If things are breaking, delete simulation/modelsim and h/db, and open modelsim from quartus once."
cd $DIRECTORY
function run_tests()
{
( cd ./testcode/python && python -c 'import run_tests; run_tests.test()' )
}
# Run all three competition testcodes.
echo y | ./testcode/rv_load_memory.sh ./testcode/competition/comp1.s 1>/dev/null && printf "comp1.s: " && run_tests
echo y | ./testcode/rv_load_memory.sh ./testcode/competition/comp2.s 1>/dev/null && printf "comp2.s: " && run_tests
echo y | ./testcode/rv_load_memory.sh ./testcode/competition/comp3.s 1>/dev/null && printf "comp3.s: " && run_tests
import os
path = "/home/" + os.getlogin() + "/ece411/h" # changeme
# print("then compile() to compile")
# print("then test() next")
from subprocess import PIPE, Popen
import time
from os import getcwd, chdir
pipe_all = {"stdin" : PIPE, "stdout" : PIPE}#, "stderr" : PIPE}
def compile():
vsim_pipe = Popen(["/software/altera/13.1/modelsim_ase/bin/vsim", "-c"], **pipe_all)
chdir(path+"/simulation/modelsim")
dolines = open(path + "/simulation/modelsim/cpu_run_msim_rtl_verilog.do", 'r').readlines()
initdo = "".join(dolines[:-2])
# Opens a command line for modelsim.
vsim_pipe = Popen(["/software/altera/13.1/modelsim_ase/bin/vsim", "-c"], **pipe_all)
vsim_pipe.communicate(initdo)
vsim_pipe.wait()
print ("\nCompilation complete!\n")
return
def test():
chdir(path+"/simulation/modelsim")
vsim_pipe = Popen(["/software/altera/13.1/modelsim_ase/bin/vsim", "-c"], **pipe_all)
f = "".join(open("cpu_run_msim_rtl_verilog.do").readlines())
command1 = \
'radix hex;'\
'add list halt ;'\
'when {halt == "1"} {write list test1.lst} ;'\
'run -all;exit;\n'
vsim_pipe.communicate( f+command1 )
# command2 = \
# 'delete list *;'\
# 'add list pmem_write;'\
# 'restart -f;'\
# 'nowhen *;'\
# 'when {halt == "1"} {write list test2.lst; exit} ;'\
# 'run -all\n'
time = open("test1.lst").readlines()[-1].split()[0][0:-3] + " nanoseconds\n"
print(time)
return
# vsim_pipe.wait()
# I thought this might be useful, but it ended up not working.
# add list -notrigger write_data;\
# add list write;\
# add list -notrigger write_address;\
#!/bin/bash
# as in appeared in fall 2018.
# Settings
DEFAULT_TARGET=$HOME/ece411/h/simulation/modelsim/memory.lst
ASSEMBLER=/class/ece411/software/riscv-tools/bin/riscv32-unknown-elf-gcc
OBJCOPY=/class/ece411/software/riscv-tools/bin/riscv32-unknown-elf-objcopy
OBJDUMP=/class/ece411/software/riscv-tools/bin/riscv32-unknown-elf-objdump
ADDRESSABILITY=32
# ADDRESSABILITY=1
# Command line parameters
ASM_FILE=$1
TARGET_FILE=${2:-$DEFAULT_TARGET}
ADDRESSABILITY=${3:-$ADDRESSABILITY}
# Print usage
if [[ "$#" -lt 1 ]]; then
echo "Compile a RISC-V assembly file and write a memory file for simulation."
echo "Usage: $0 <asm-file> [memory-file]"
exit 0
fi
# Remove temporary directory on exit
cleanup()
{
rm -rf -- "$WORK_DIR"
# echo "$WORK_DIR"
}
trap cleanup exit
# Create temporary directory
WORK_DIR="$(mktemp -d)"
# Copy files to temporary directory
cp "$ASM_FILE" "$WORK_DIR"
# Fail if assembler cannot be found
if [ ! -x "$ASSEMBLER" ]; then
echo "Cannot execute assembler at $ASSEMBLER." >&2
echo "Make sure it exists and is executable." >&2
exit 1
fi
OBJ_FILE="${WORK_DIR}/$(basename $ASM_FILE .asm).obj"
# Assemble code
"$ASSEMBLER" -ffreestanding -nostdlib "${WORK_DIR}/$(basename $ASM_FILE)" -Wl,--no-relax -o "$OBJ_FILE"
# Fail if object file doesn't exist or has no memory content
if [[ ! -e "$OBJ_FILE" || "$(cat "$OBJ_FILE" | wc -c)" -le "1" ]]; then
echo "Error assembling $ASM_FILE, not generating binary file" >&2
exit 2
fi
# Fail if objcopy cannot be found
if [ ! -x "$OBJCOPY" ]; then
echo "Cannot execute objcopy at $OBJCOPY" >&2
echo "Make sure it exists and is executable." >&2
exit 1
fi
BIN_FILE="${WORK_DIR}/$(basename $ASM_FILE .asm).bin"
"$OBJDUMP" -D "$OBJ_FILE"
"$OBJCOPY" -O binary "$OBJ_FILE" "$BIN_FILE"
hexdump $BIN_FILE
# Fail if binary file doesn't exist or has no memory content
if [[ ! -e "$BIN_FILE" || "$(cat "$BIN_FILE" | wc -c)" -le "1" ]]; then
echo "Error binarizing $OBJ_FILE, not generating memory file" >&2
exit 3
fi
# Fail if the target directory doesn't exist
if [[ ! -d "$(dirname "$TARGET_FILE")" ]]; then
echo "Directory $(dirname "$TARGET_FILE") does not exist." >&2
echo "Did you specify the correct target path? Aborting." >&2
exit 4
fi
# Ask if user wants to overwrite target
if [ -e "$TARGET_FILE" ]; then
echo "Target file $TARGET_FILE exists."
read -p "Overwrite? [y/N] " CONF
shopt -s nocasematch
if [[ "${CONF}" != "y" && "${CONF}" != "yes" ]]; then
echo "Aborting." >&2
exit 0
fi
shopt -u nocasematch
fi
# Write memory to file
function log2 {
local x=0
for (( y=$1-1 ; $y > 0; y >>= 1 )) ; do
let x=$x+1
done
echo $x
}
z=$( log2 $ADDRESSABILITY )
hex="0x00000060"
result=$(( hex >> $z ))
mem_start=$(printf "@%08x\n" $result)
{
echo $mem_start
hexdump -ve $ADDRESSABILITY'/1 "%02X " "\n"' "$BIN_FILE" \
| awk '{for (i = NF; i > 0; i--) printf "%s", $i; print ""}'
} > "$TARGET_FILE"
echo "Assembled $ASM_FILE and wrote memory contents to $TARGET_FILE"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment