Merge branch 'main' of https://github.com/openhwgroup/cvw into Z_enable

This commit is contained in:
Daniyal-R-A 2024-11-04 21:39:05 -08:00
commit 4dff7d17e6
39 changed files with 807 additions and 2004 deletions

3
.gitmodules vendored
View File

@ -25,9 +25,10 @@
sparseCheckout = true
path = addins/verilog-ethernet
url = https://github.com/rosethompson/verilog-ethernet.git
[submodule "cvw-arch-verif"]
[submodule "addins/cvw-arch-verif"]
path = addins/cvw-arch-verif
url = https://github.com/openhwgroup/cvw-arch-verif
ignore = dirty
[submodule "addins/riscvISACOV"]
path = addins/riscvISACOV
url = https://github.com/riscv-verification/riscvISACOV.git

@ -1 +1 @@
Subproject commit bbcba78647080dee82e96bc1b8ff9cd9a3cf7fa1
Subproject commit 6d658b7b42c83fd584008d72964cc75d0876b769

@ -1 +1 @@
Subproject commit ce04b4930545ae4c81e2f3b6f6935e2aac08679e
Subproject commit 3843c736e427a2b52a0d06e6220b073afa4be401

View File

@ -88,6 +88,18 @@ foreach my $key (@derivnames) {
open(my $unmod, $configunmod) or die "Could not open file '$configunmod' $!";
open(my $fh, '>>', $config) or die "Could not open file '$config' $!";
# Create symlink to imperas.ic for deriv buildroot
if ($key eq "buildroot") {
my $baseimperas_ic = "$ENV{WALLY}/config/$basederiv{$key}/imperas.ic";
if (! -e $baseimperas_ic) {
my $baseimperas_ic = "$ENV{WALLY}/config/deriv/$basederiv{$key}/config.vh";
}
if (-e $baseimperas_ic) { # If imperas.ic exists for base derivative, create hardlink to it
my $imperas_ic = "$dir/imperas.ic";
system("ln -T $baseimperas_ic $imperas_ic");
}
}
my $datestring = localtime();
my %hit = ();
print $fh "// Config $key automatically derived from $basederiv{$key} on $datestring using derivgen.pl\n";

View File

@ -261,9 +261,6 @@ class TestRunner:
cvw = folder.joinpath("cvw")
self.logger.info(f"cvw is: {cvw}")
# set the WALLY environmental variable to the new repository
os.environ["WALLY"] = str(cvw)
self.cvw = cvw
self.sim_dir = cvw.joinpath("bin")
self.base_parent_dir = folder
@ -292,11 +289,11 @@ class TestRunner:
output_file = self.log_dir.joinpath(f"make-{target}-output.log")
else: output_file = self.log_dir.joinpath(f"make-output.log")
# Execute make with target and cores/2
# Source setup script and execute make with target and cores/2
if target:
command = ["make", target, "--jobs=$(($(nproc)/2))"]
command = [f"source {os.path.join(self.cvw, 'setup.sh')} > /dev/null && make {target} --jobs=$(($(nproc)/2))"]
else:
command = ["make", "--jobs=$(($(nproc)/2))"]
command = [f"source {os.path.join(self.cvw, 'setup.sh')} > /dev/null && make --jobs=$(($(nproc)/2))"]
self.logger.info(f"Command used in directory {makefile_location}: {' '.join(command)}")
@ -305,7 +302,7 @@ class TestRunner:
formatted_datetime = self.current_datetime.strftime("%Y-%m-%d %H:%M:%S")
f.write(formatted_datetime)
f.write("\n\n")
result = subprocess.run(command, stdout=f, stderr=subprocess.STDOUT, text=True, shell=True)
result = subprocess.run(command, stdout=f, stderr=subprocess.STDOUT, text=True, shell=True, executable="/bin/bash")
# Execute the command using a subprocess and not save the output
#result = subprocess.run(command, text=True)
@ -334,12 +331,16 @@ class TestRunner:
output_file = self.log_dir.joinpath(f"{test_name}-output.log")
os.chdir(self.sim_dir)
# Source setup script and delete output from log on whatever test command gets run
command = f"source {os.path.join(self.cvw, 'setup.sh')} > /dev/null && "
if test_extensions:
command = [test_type, test_name] + test_extensions
commandext = [test_type, test_name] + test_extensions
self.logger.info(f"Command used to run tests in directory {self.sim_dir}: {test_type} {test_name} {' '.join(test_extensions)}")
else:
command = [test_type, test_name]
commandext = [test_type, test_name]
self.logger.info(f"Command used to run tests in directory {self.sim_dir}: {test_type} {test_name}")
command += " ".join(commandext)
# Execute the command using subprocess and save the output into a file
@ -348,15 +349,15 @@ class TestRunner:
formatted_datetime = self.current_datetime.strftime("%Y-%m-%d %H:%M:%S")
f.write(formatted_datetime)
f.write("\n\n")
result = subprocess.run(command, stdout=f, stderr=subprocess.STDOUT, text=True)
result = subprocess.run(command, stdout=f, stderr=subprocess.STDOUT, text=True, shell=True, executable="/bin/bash")
except Exception as e:
self.logger.error("There was an error in running the tests in the run_tests function: {e}")
self.logger.error(f"There was an error in running the tests in the run_tests function: {e}")
# Check if the command executed successfuly
if result.returncode or result.returncode == 0:
self.logger.info(f"Test ran successfuly. Test type: {test_type}, test name: {test_name}, test extension: {' '.join(test_extensions)}")
self.logger.info(f"Test ran successfuly. Test name: {test_name}, test extension: {' '.join(test_extensions)}")
return True, output_file
else:
self.logger.error(f"Error making test. Test type: {test_type}, test name: {test_name}, test extension: {' '.join(test_extensions)}")
self.logger.error(f"Error making test. Test name: {test_name}, test extension: {' '.join(test_extensions)}")
return False, output_file

View File

@ -539,7 +539,7 @@ def main():
num_fail = 0
results = {}
for config in configs:
results[config] = pool.apply_async(run_test_case,(config,))
results[config] = pool.apply_async(run_test_case,(config, args.dryrun))
for (config,result) in results.items():
try:
num_fail+=result.get(timeout=TIMEOUT_DUR)

View File

@ -65,7 +65,7 @@ if(args.testsuite.endswith('.elf') and args.elf == ""): # No --elf argument; che
print("ELF file not found: " + args.testsuite)
exit(1)
if(args.lockstep and not args.testsuite.endswith('.elf')):
if(args.lockstep and not args.testsuite.endswith('.elf') and not args.testsuite == "buildroot"):
print(f"Invalid Options. Cannot run a testsuite, {args.testsuite} with lockstep. Must run a single elf.")
exit(1)
@ -90,7 +90,9 @@ else: EnableLog = 0
prefix = ""
if (args.lockstep or args.lockstepverbose or args.fcov or args.fcovimp):
if (args.sim == "questa" or args.sim == "vcs"):
prefix = "IMPERAS_TOOLS=" + WALLY + "/config/"+args.config+"/imperas.ic"
prefix = "IMPERAS_TOOLS=" + os.path.join(WALLY, "config", args.config, "imperas.ic")
if not os.path.isfile(prefix): # If config is a derivative, look for imperas.ic in derivative configs
prefix = "IMPERAS_TOOLS=" + os.path.join(WALLY, "config", "deriv", args.config, "imperas.ic")
# Force Questa to use 64-bit mode, sometimes it defaults to 32-bit even on 64-bit machines
if (args.sim == "questa"):
prefix = "MTI_VCO_MODE=64 " + prefix

View File

@ -37,3 +37,5 @@
// Privileged extensions
`include "ZicsrM_coverage.svh"
`include "RV32VM_coverage.svh"
`include "RV32VM_PMP_coverage.svh"

View File

@ -5,3 +5,22 @@ wally/wallypipelinedcore.sv: logic InstrM
lsu/lsu.sv: logic IEUAdrM
lsu/lsu.sv: logic MemRWM
mmu/hptw.sv: logic SATP_REGW
uncore/spi_apb.sv: logic ShiftIn
uncore/spi_apb.sv: logic ReceiveShiftReg
uncore/spi_apb.sv: logic SCLKenable
uncore/spi_apb.sv: logic SampleEdge
uncore/spi_apb.sv: logic Active
uncore/spi_apb.sv: statetype state
uncore/spi_apb.sv: typedef rsrstatetype
uncore/spi_apb.sv: logic SPICLK
uncore/spi_apb.sv: logic SPIOut
uncore/spi_apb.sv: logic SPICS
uncore/spi_apb.sv: logic SckMode
uncore/spi_apb.sv: logic SckDiv
uncore/spi_apb.sv: logic ShiftEdge
uncore/spi_apb.sv: logic TransmitShiftRegLoad
uncore/spi_apb.sv: logic TransmitShiftReg
uncore/spi_apb.sv: logic TransmitData
uncore/spi_apb.sv: logic ReceiveData
uncore/spi_apb.sv: logic ReceiveShiftRegEndian
uncore/spi_apb.sv: logic ASR

View File

@ -191,7 +191,6 @@ set_property port_width 1 [get_debug_ports u_ila_0/probe33]
set_property PROBE_TYPE DATA_AND_TRIGGER [get_debug_ports u_ila_0/probe33]
connect_debug_port u_ila_0/probe33 [get_nets [list {wallypipelinedsoc/uncoregen.uncore/sdc.sdc/TransmitFIFOReadEmpty} ]]
# the debug hub has issues with the clocks from the mmcm so lets give up an connect to the 100Mhz input clock.
#connect_debug_port dbg_hub/clk [get_nets default_100mhz_clk]
connect_debug_port dbg_hub/clk [get_nets CPUCLK]

View File

@ -69,8 +69,8 @@ PreProcessFiles:
./insert_debug_comment.sh
# This line allows the Bootloader to be loaded in a Block RAM on the FPGA
sed -i "s/bit \[DATA_WIDTH-1:0\].*ROM.*/(\* rom_style=\"block\" \*) &/g" ../src/CopiedFiles_do_not_add_to_repo/generic/mem/rom1p1r.sv
sed -i 's/$$WALLY/\.\.\/\.\.\/\.\.\//g' ../src/CopiedFiles_do_not_add_to_repo/generic/mem/rom1p1r.sv
sed -i 's/$$WALLY/\.\.\/\.\.\/\.\.\//g' ../src/CopiedFiles_do_not_add_to_repo/generic/mem/ram1p1rwbe.sv
sed -i 's/$$WALLY/\.\.\/\.\.\//g' ../src/CopiedFiles_do_not_add_to_repo/generic/mem/rom1p1r.sv
sed -i 's/$$WALLY/\.\.\/\.\.\//g' ../src/CopiedFiles_do_not_add_to_repo/generic/mem/ram1p1rwbe.sv
# build the Zero stage boot loader (ZSBL)
.PHONY: zsbl

View File

@ -102,7 +102,8 @@ if {$board=="ArtyA7"} {
} else {
#source ../constraints/vcu-small-debug.xdc
#source ../constraints/small-debug.xdc
source ../constraints/small-debug-spi.xdc
#source ../constraints/small-debug.xdc
source ../constraints/big-debug-spi.xdc
}

View File

@ -135,45 +135,45 @@ int disk_read(BYTE * buf, LBA_t sector, UINT count) {
/* crc = crc16(crc, x); */
/* } while (--n > 0); */
/* n = 512/8; */
/* do { */
/* // Send 8 dummy bytes (fifo should be empty) */
/* for (j = 0; j < 8; j++) { */
/* spi_sendbyte(0xff); */
/* } */
/* // Reset counter. Process bytes AS THEY COME IN. */
/* for (j = 0; j < 8; j++) { */
/* while (!(read_reg(SPI_IP) & 2)) {} */
/* uint8_t x = spi_readbyte(); */
/* *p++ = x; */
/* // crc = crc16(crc, x); */
/* crc = ((crc << 8) ^ crctable[x ^ (crc >> 8)]) & 0xffff; */
/* } */
/* } while(--n > 0); */
n = 512;
// Initially fill the transmit fifo
for (j = 0; j < 8; j++) {
spi_sendbyte(0xff);
}
while (n > 0) {
// Wait for bytes to be received
while (!(read_reg(SPI_IP) & 2)) {}
// Read byte
uint8_t x = spi_readbyte();
// Send another dummy byte
if (n > 8) {
n = 512/8;
do {
// Send 8 dummy bytes (fifo should be empty)
for (j = 0; j < 8; j++) {
spi_sendbyte(0xff);
}
// Place received byte into memory
*p++ = x;
// Update CRC16 with fast table based method
crc = ((crc << 8) ^ crctable[x ^ (crc >> 8)]) & 0xffff;
n = n - 1;
}
// Reset counter. Process bytes AS THEY COME IN.
for (j = 0; j < 8; j++) {
while (!(read_reg(SPI_IP) & 2)) {}
uint8_t x = spi_readbyte();
*p++ = x;
// crc = crc16(crc, x);
crc = ((crc << 8) ^ crctable[x ^ (crc >> 8)]) & 0xffff;
}
} while(--n > 0);
/* n = 512; */
/* // Initially fill the transmit fifo */
/* for (j = 0; j < 8; j++) { */
/* spi_sendbyte(0xff); */
/* } */
/* while (n > 0) { */
/* // Wait for bytes to be received */
/* while (!(read_reg(SPI_IP) & 2)) {} */
/* // Read byte */
/* uint8_t x = spi_readbyte(); */
/* // Send another dummy byte */
/* if (n > 8) { */
/* spi_sendbyte(0xff); */
/* } */
/* // Place received byte into memory */
/* *p++ = x; */
/* // Update CRC16 with fast table based method */
/* crc = ((crc << 8) ^ crctable[x ^ (crc >> 8)]) & 0xffff; */
/* n = n - 1; */
/* } */
// Read CRC16 and check
crc_exp = ((uint16_t)spi_dummy() << 8);

View File

@ -1,4 +1,30 @@
#!/bin/bash
###########################################
## flash-sd.sh
##
## Written: Jacob Pease jacobpease@protonmail.com
## Created: August 22, 2023
##
## Purpose: A script to flash an sd card with a bootable linux image.
##
## A component of the CORE-V-WALLY configurable RISC-V project.
## https://github.com/openhwgroup/cvw
##
## Copyright (C) 2021-24 Harvey Mudd College & Oklahoma State University
##
## SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
##
## Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
## except in compliance with the License, or, at your option, the Apache License version 2.0. You
## may obtain a copy of the License at
##
## https:##solderpad.org/licenses/SHL-2.1/
##
## Unless required by applicable law or agreed to in writing, any work distributed under the
## License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
## either express or implied. See the License for the specific language governing permissions
## and limitations under the License.
################################################################################################
# Exit on any error (return code != 0)
# set -e

80
linux/sdcard/write-bytes.sh Executable file
View File

@ -0,0 +1,80 @@
#!/bin/bash
###########################################
## write-bytes.sh
##
## Written: Jacob Pease jacobpease@protonmail.com
## Created: November 2nd, 2024
## Modified:
##
## Purpose: Write a sequence of bytes from text file to an output file and a flash card.
##
## A component of the CORE-V-WALLY configurable RISC-V project.
## https://github.com/openhwgroup/cvw
##
## Copyright (C) 2021-24 Harvey Mudd College & Oklahoma State University
##
## SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
##
## Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
## except in compliance with the License, or, at your option, the Apache License version 2.0. You
## may obtain a copy of the License at
##
## https:##solderpad.org/licenses/SHL-2.1/
##
## Unless required by applicable law or agreed to in writing, any work distributed under the
## License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
## either express or implied. See the License for the specific language governing permissions
## and limitations under the License.
################################################################################################
# This file writes a bunch of bytes to the flash card based on a text
# file input with bytes written in hexadecimal.
usage() { echo "Usage: $0 [-zh] [-b <path/to/buildroot>] <device>" 1>&2; exit 1; }
help() {
echo "Usage: $0 [OPTIONS] <device>"
echo " -i Input text file with hex bytes."
echo " -b <path/to/buildroot> Output binary file."
exit 0;
}
INPUTFILE=""
OUTPUTFILE=""
ARGS=()
while [ $OPTIND -le "$#" ] ; do
if getopts "hi:o:" arg ; then
case "${arg}" in
h) help
;;
i) INPUTFILE=${OPTARG}
;;
o) OUTPUTFILE=${OPTARG}
;;
esac
else
ARGS+=("${!OPTIND}")
((OPTIND++))
fi
done
SDCARD=${ARGS[0]}
if [ ! -e $INPUTFILE ] ; then
echo -e "Error: Input file $INPUTFILE does not exist."
exit 1
fi
if [ -e $OUTPUTFILE ] ; then
echo -e "Error: Output file $OUTPUTFILE already exists."
exit 1
fi
for word in $(cat "$INPUTFILE")
do
echo -en "\x$word" >> $OUTPUTFILE
done
dd if=$OUTPUTFILE of="$SDCARD"

View File

@ -1,47 +0,0 @@
#!/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

View File

@ -1,6 +0,0 @@
#!/bin/bash
for index in {450..500};
do
instrs=$(($index*1000000))
echo "y" | nice -n 5 ./genCheckpoint.sh $instrs
done

View File

@ -1,21 +0,0 @@
#!/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"

View File

@ -1,74 +0,0 @@
#!/usr/bin/env 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()

View File

@ -1,68 +0,0 @@
#!/usr/bin/env 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.")

View File

@ -1,146 +0,0 @@
#!/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

View File

@ -1,38 +0,0 @@
#!/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

View File

@ -1,54 +0,0 @@
#!/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

View File

@ -1,243 +0,0 @@
#!/usr/bin/env python3
import sys, fileinput, re
# Rose 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')

View File

@ -1,106 +0,0 @@
#!/usr/bin/env 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!")

View File

@ -1,145 +0,0 @@
#!/usr/bin/env 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)

View File

@ -1,99 +0,0 @@
#!/usr/bin/env 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!")

View File

@ -1,50 +0,0 @@
#!/usr/bin/env 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!")

View File

@ -181,7 +181,7 @@ if {$DEBUG > 0} {
# suppress spurious warnngs about
# "Extra checking for conflicts with always_comb done at vopt time"
# because vsim will run vopt
set INC_DIRS "+incdir+${CONFIG}/${CFG} +incdir+${CONFIG}/deriv/${CFG} +incdir+${CONFIG}/shared +incdir+${FCRVVI} +incdir+${FCRVVI}/rv32 +incdir+${FCRVVI}/rv64 +incdir+${FCRVVI}/rv64_priv +incdir+${FCRVVI}/priv +incdir+${FCRVVI}/common +incdir+${FCRVVI}"
set INC_DIRS "+incdir+${CONFIG}/${CFG} +incdir+${CONFIG}/deriv/${CFG} +incdir+${CONFIG}/shared +incdir+${FCRVVI} +incdir+${FCRVVI}/rv32 +incdir+${FCRVVI}/rv64 +incdir+${FCRVVI}/rv64_priv +incdir+${FCRVVI}/priv +incdir+${FCRVVI}/rv32_priv +incdir+${FCRVVI}/common +incdir+${FCRVVI}"
set SOURCES "${SRC}/cvw.sv ${TB}/${TESTBENCH}.sv ${TB}/common/*.sv ${SRC}/*/*.sv ${SRC}/*/*/*.sv ${WALLY}/addins/verilog-ethernet/*/*.sv ${WALLY}/addins/verilog-ethernet/*/*/*/*.sv"
vlog -permissive -lint -work ${WKDIR} {*}${INC_DIRS} {*}${FCvlog} {*}${FCdefineCOVER_EXTS} {*}${lockstepvlog} {*}${SOURCES} -suppress 2282,2583,7053,7063,2596,13286

View File

@ -126,7 +126,7 @@ module fround import cvw::*; #(parameter cvw_t P) (
3'b001: RoundUp = 0; // RZ
3'b010: RoundUp = Xs & (Rp | Tp); // RN
3'b011: RoundUp = ~Xs & (Rp | Tp); // RP
3'b101: RoundUp = Rp; // RNTA
3'b100: RoundUp = Rp; // RNTA
default: RoundUp = 0; // should never happen
endcase

View File

@ -1,7 +1,9 @@
///////////////////////////////////////////
// spi_apb.sv
//
// Written: Naiche Whyte-Aguayo nwhyteaguayo@g.hmc.edu 11/16/2022
// Written: Naiche Whyte-Aguayo nwhyteaguayo@g.hmc.edu
// Jacob Pease jacobpease@protonmail.com (October 29th, 2024)
// Created: November 16th, 2022
//
// Purpose: SPI peripheral
//
@ -13,7 +15,7 @@
//
// A component of the Wally configurable RISC-V project.
//
// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University
// Copyright (C) 2021-24 Harvey Mudd College & Oklahoma State University
//
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
//
@ -30,438 +32,324 @@
////////////////////////////////////////////////////////////////////////////////////////////////
module spi_apb import cvw::*; #(parameter cvw_t P) (
input logic PCLK, PRESETn,
input logic PSEL,
input logic [7:0] PADDR,
input logic [P.XLEN-1:0] PWDATA,
input logic [P.XLEN/8-1:0] PSTRB,
input logic PWRITE,
input logic PENABLE,
output logic PREADY,
output logic [P.XLEN-1:0] PRDATA,
output logic SPIOut,
input logic SPIIn,
output logic [3:0] SPICS,
output logic SPIIntr,
output logic SPICLK
input logic PCLK, PRESETn,
input logic PSEL,
input logic [7:0] PADDR,
input logic [P.XLEN-1:0] PWDATA,
input logic [P.XLEN/8-1:0] PSTRB,
input logic PWRITE,
input logic PENABLE,
output logic PREADY,
output logic [P.XLEN-1:0] PRDATA,
output logic SPIOut,
input logic SPIIn,
output logic [3:0] SPICS,
output logic SPIIntr,
output logic SPICLK
);
// register map
localparam SPI_SCKDIV = 8'h00;
localparam SPI_SCKMODE = 8'h04;
localparam SPI_CSID = 8'h10;
localparam SPI_CSDEF = 8'h14;
localparam SPI_CSMODE = 8'h18;
localparam SPI_DELAY0 = 8'h28;
localparam SPI_DELAY1 = 8'h2C;
localparam SPI_FMT = 8'h40;
localparam SPI_TXDATA = 8'h48;
localparam SPI_RXDATA = 8'h4C;
localparam SPI_TXMARK = 8'h50;
localparam SPI_RXMARK = 8'h54;
localparam SPI_IE = 8'h70;
localparam SPI_IP = 8'h74;
// receive shift register states
typedef enum logic [1:0] {ReceiveShiftFullState, ReceiveShiftNotFullState, ReceiveShiftDelayState} rsrstatetype;
// SPI control registers. Refer to SiFive FU540-C000 manual
logic [11:0] SckDiv;
logic [1:0] SckMode;
logic [1:0] ChipSelectID;
logic [3:0] ChipSelectDef;
logic [1:0] ChipSelectMode;
logic [15:0] Delay0, Delay1;
logic [4:0] Format;
logic [7:0] ReceiveData;
logic [2:0] TransmitWatermark, ReceiveWatermark;
logic [8:0] TransmitData;
logic [1:0] InterruptEnable, InterruptPending;
// Bus interface signals
logic [7:0] Entry;
logic Memwrite;
logic [31:0] Din, Dout;
logic TransmitInactive; // High when there is no transmission, used as hardware interlock signal
// FIFO FSM signals
// Watermark signals - TransmitReadMark = ip[0], ReceiveWriteMark = ip[1]
logic TransmitWriteMark, TransmitReadMark, RecieveWriteMark, RecieveReadMark;
logic TransmitFIFOWriteFull, TransmitFIFOReadEmpty;
logic TransmitFIFOWriteIncrement;
logic ReceiveFiFoWriteInc;
logic ReceiveFIFOReadIncrement;
logic ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty;
logic [7:0] TransmitFIFOReadData;
/* verilator lint_off UNDRIVEN */
logic [2:0] TransmitWriteWatermarkLevel, ReceiveReadWatermarkLevel; // unused generic FIFO outputs
/* verilator lint_off UNDRIVEN */
logic [7:0] ReceiveShiftRegEndian; // Reverses ReceiveShiftReg if Format[2] set (little endian transmission)
rsrstatetype ReceiveState;
logic ReceiveFiFoTakingData;
// Transmission signals
logic ZeroDiv; // High when SckDiv is 0
logic [11:0] DivCounter; // Counter for sck
logic SCLKenable; // Flip flop enable high every sclk edge
// Delay signals
logic [8:0] ImplicitDelay1; // Adds implicit delay to cs-sck delay counter based on phase
logic [8:0] ImplicitDelay2; // Adds implicit delay to sck-cs delay counter based on phase
logic [8:0] CS_SCKCount; // Counter for cs-sck delay
logic [8:0] SCK_CSCount; // Counter for sck-cs delay
logic [8:0] InterCSCount; // Counter for inter cs delay
logic [8:0] InterXFRCount; // Counter for inter xfr delay
logic ZeroDelayHoldMode; // High when ChipSelectMode is hold and Delay1[15:8] (InterXFR delay) is 0
// Frame counting signals
logic FirstFrame;
logic [3:0] FrameCount; // Counter for number of frames in transmission
logic ReceivePenultimateFrame; // High when penultimate frame in transmission has been reached
// State fsm signals
logic Active; // High when state is either Active1 or Active0 (during transmission)
logic Active0; // High when state is Active0
// Shift reg signals
logic ShiftEdge; // Determines which edge of sck to shift from TransmitShiftReg
logic [7:0] TransmitShiftReg; // Transmit shift register
logic [7:0] ReceiveShiftReg; // Receive shift register
logic SampleEdge; // Determines which edge of sck to sample from ReceiveShiftReg
logic [7:0] TransmitDataEndian; // Reverses TransmitData from txFIFO if littleendian, since TransmitReg always shifts MSB
logic TransmitShiftRegLoad; // Determines when to load TransmitShiftReg
logic TransmitShiftRegLoadSingleCycle; // Version of TransmitShiftRegLoad which is only high for a single SCLK cycle to prevent double loads
logic TransmitShiftRegLoadDelay; // TransmitShiftRegLoad delayed by an SCLK cycle, inverted and anded with TransmitShiftRegLoad to create a single cycle signal
logic TransmitFIFOReadIncrement; // Increments Tx FIFO read ptr 1 cycle after Tx FIFO is read
logic ReceiveShiftFull; // High when receive shift register is full
logic TransmitShiftEmpty; // High when transmit shift register is empty
logic ShiftIn; // Determines whether to shift from SPIIn or SPIOut (if SPI_LOOPBACK_TEST)
logic [3:0] LeftShiftAmount; // Determines left shift amount to left-align data when little endian
logic [7:0] ASR; // AlignedReceiveShiftReg
logic ShiftEdgeSPICLK; // Changes ShiftEdge when SckDiv is 0
// CS signals
logic [3:0] ChipSelectAuto; // Assigns ChipSelect value to selected CS signal based on CS ID
logic [3:0] ChipSelectInternal; // Defines what each ChipSelect signal should be based on transmission status and ChipSelectDef
logic DelayMode; // Determines where to place implicit half cycle delay based on sck phase for CS assertion
// Miscellaneous signals delayed/early by 1 PCLK cycle
logic ReceiveShiftFullDelay; // Delays ReceiveShiftFull signal by 1 PCLK cycle
logic ReceiveShiftFullDelayPCLK; // ReceiveShiftFull delayed by 1 PCLK cycle
logic TransmitFIFOReadEmptyDelay;
logic SCLKenableEarly; // SCLKenable 1 PCLK cycle early, needed for on time register changes when ChipSelectMode is hold and Delay1[15:8] (InterXFR delay) is 0
// APB access
assign Entry = {PADDR[7:2],2'b00}; // 32-bit word-aligned accesses
assign Memwrite = PWRITE & PENABLE & PSEL; // Only write in access phase
assign PREADY = Entry == SPI_TXDATA | Entry == SPI_RXDATA | Entry == SPI_IP | TransmitInactive; // Tie PREADY to transmission for hardware interlock
// Account for subword read/write circuitry
// -- Note SPI registers are 32 bits no matter what; access them with LW SW.
assign Din = PWDATA[31:0];
if (P.XLEN == 64) assign PRDATA = { Dout, Dout};
else assign PRDATA = Dout;
// Register access
always_ff@(posedge PCLK)
if (~PRESETn) begin
SckDiv <= 12'd3;
SckMode <= 2'b0;
ChipSelectID <= 2'b0;
ChipSelectDef <= 4'b1111;
ChipSelectMode <= 2'b0;
Delay0 <= {8'b1,8'b1};
Delay1 <= {8'b0,8'b1};
Format <= {5'b10000};
TransmitData <= 9'b0;
TransmitWatermark <= 3'b0;
ReceiveWatermark <= 3'b0;
InterruptEnable <= 2'b0;
InterruptPending <= 2'b0;
end else begin // writes
/* verilator lint_off CASEINCOMPLETE */
if (Memwrite & TransmitInactive)
case(Entry) // flop to sample inputs
SPI_SCKDIV: SckDiv <= Din[11:0];
SPI_SCKMODE: SckMode <= Din[1:0];
SPI_CSID: ChipSelectID <= Din[1:0];
SPI_CSDEF: ChipSelectDef <= Din[3:0];
SPI_CSMODE: ChipSelectMode <= Din[1:0];
SPI_DELAY0: Delay0 <= {Din[23:16], Din[7:0]};
SPI_DELAY1: Delay1 <= {Din[23:16], Din[7:0]};
SPI_FMT: Format <= {Din[19:16], Din[2]};
SPI_TXMARK: TransmitWatermark <= Din[2:0];
SPI_RXMARK: ReceiveWatermark <= Din[2:0];
SPI_IE: InterruptEnable <= Din[1:0];
endcase
if (Memwrite)
case(Entry)
SPI_TXDATA: if (~TransmitFIFOWriteFull) TransmitData[7:0] <= Din[7:0];
endcase
/* verilator lint_off CASEINCOMPLETE */
// According to FU540 spec: Once interrupt is pending, it will remain set until number
// of entries in tx/rx fifo is strictly more/less than tx/rxmark
InterruptPending[0] <= TransmitReadMark;
InterruptPending[1] <= RecieveWriteMark;
case(Entry) // Flop to sample inputs
SPI_SCKDIV: Dout <= {20'b0, SckDiv};
SPI_SCKMODE: Dout <= {30'b0, SckMode};
SPI_CSID: Dout <= {30'b0, ChipSelectID};
SPI_CSDEF: Dout <= {28'b0, ChipSelectDef};
SPI_CSMODE: Dout <= {30'b0, ChipSelectMode};
SPI_DELAY0: Dout <= {8'b0, Delay0[15:8], 8'b0, Delay0[7:0]};
SPI_DELAY1: Dout <= {8'b0, Delay1[15:8], 8'b0, Delay1[7:0]};
SPI_FMT: Dout <= {12'b0, Format[4:1], 13'b0, Format[0], 2'b0};
SPI_TXDATA: Dout <= {TransmitFIFOWriteFull, 23'b0, 8'b0};
SPI_RXDATA: Dout <= {ReceiveFIFOReadEmpty, 23'b0, ReceiveData[7:0]};
SPI_TXMARK: Dout <= {29'b0, TransmitWatermark};
SPI_RXMARK: Dout <= {29'b0, ReceiveWatermark};
SPI_IE: Dout <= {30'b0, InterruptEnable};
SPI_IP: Dout <= {30'b0, InterruptPending};
default: Dout <= 32'b0;
endcase
end
// SPI enable generation, where SCLK = PCLK/(2*(SckDiv + 1))
// Asserts SCLKenable at the rising and falling edge of SCLK by counting from 0 to SckDiv
// Active at 2x SCLK frequency to account for implicit half cycle delays and actions on both clock edges depending on phase
// When SckDiv is 0, count doesn't work and SCLKenable is simply PCLK *** dh 10/26/24: this logic is seriously broken. SCLK is not scaled to PCLK/(2*(SckDiv + 1)). SCLKenableEarly doesn't work right for SckDiv=0
assign ZeroDiv = ~|(SckDiv[10:0]);
assign SCLKenable = ZeroDiv ? 1 : (DivCounter == SckDiv);
assign SCLKenableEarly = ((DivCounter + 12'b1) == SckDiv);
always_ff @(posedge PCLK)
if (~PRESETn) DivCounter <= '0;
else if (SCLKenable) DivCounter <= 12'b0;
else DivCounter <= DivCounter + 12'b1;
// Asserts when transmission is one frame before complete
assign ReceivePenultimateFrame = ((FrameCount + 4'b0001) == Format[4:1]);
assign FirstFrame = (FrameCount == 4'b0);
// Computing delays
// When sckmode.pha = 0, an extra half-period delay is implicit in the cs-sck delay, and vice-versa for sck-cs
assign ImplicitDelay1 = SckMode[0] ? 9'b0 : 9'b1;
assign ImplicitDelay2 = SckMode[0] ? 9'b1 : 9'b0;
// Calculate when tx/rx shift registers are full/empty
// Transmit Shift FSM
always_ff @(posedge PCLK)
if (~PRESETn) TransmitShiftEmpty <= 1'b1;
else if (TransmitShiftEmpty) begin
if (TransmitFIFOReadEmpty | (~TransmitFIFOReadEmpty & (ReceivePenultimateFrame & Active0))) TransmitShiftEmpty <= 1'b1;
else if (~TransmitFIFOReadEmpty) TransmitShiftEmpty <= 1'b0;
end else begin
if (ReceivePenultimateFrame & Active0) TransmitShiftEmpty <= 1'b1;
else TransmitShiftEmpty <= 1'b0;
end
// Receive Shift FSM
always_ff @(posedge PCLK)
if (~PRESETn) ReceiveState <= ReceiveShiftNotFullState;
else if (SCLKenable) begin
case (ReceiveState)
ReceiveShiftFullState: ReceiveState <= ReceiveShiftNotFullState;
ReceiveShiftNotFullState: if (ReceivePenultimateFrame & (SampleEdge)) ReceiveState <= ReceiveShiftDelayState;
else ReceiveState <= ReceiveShiftNotFullState;
ReceiveShiftDelayState: ReceiveState <= ReceiveShiftFullState;
endcase
end
assign ReceiveShiftFull = SckMode[0] ? (ReceiveState == ReceiveShiftFullState) : (ReceiveState == ReceiveShiftDelayState);
// Calculate tx/rx fifo write and recieve increment signals
always_ff @(posedge PCLK)
if (~PRESETn) TransmitFIFOWriteIncrement <= 1'b0;
else TransmitFIFOWriteIncrement <= (Memwrite & (Entry == SPI_TXDATA) & ~TransmitFIFOWriteFull);
always_ff @(posedge PCLK)
if (~PRESETn) ReceiveFIFOReadIncrement <= 1'b0;
else ReceiveFIFOReadIncrement <= ((Entry == SPI_RXDATA) & ~ReceiveFIFOReadEmpty & PSEL & ~ReceiveFIFOReadIncrement);
assign TransmitShiftRegLoad = ~TransmitShiftEmpty & ~Active | (((ChipSelectMode == 2'b10) & ~|(Delay1[15:8])) & ((ReceiveShiftFullDelay | ReceiveShiftFull) & ~SampleEdge & ~TransmitFIFOReadEmpty));
always_ff @(posedge PCLK)
if (~PRESETn) TransmitShiftRegLoadDelay <=0;
else if (SCLKenable) TransmitShiftRegLoadDelay <= TransmitShiftRegLoad;
assign TransmitShiftRegLoadSingleCycle = TransmitShiftRegLoad & ~TransmitShiftRegLoadDelay;
always_ff @(posedge PCLK)
if (~PRESETn) TransmitFIFOReadIncrement <= 0;
else if (SCLKenable) TransmitFIFOReadIncrement <= TransmitShiftRegLoadSingleCycle;
// Tx/Rx FIFOs
spi_fifo #(3,8) txFIFO(PCLK, 1'b1, SCLKenable, PRESETn, TransmitFIFOWriteIncrement, TransmitFIFOReadIncrement, TransmitData[7:0], TransmitWriteWatermarkLevel, TransmitWatermark[2:0],
TransmitFIFOReadData[7:0], TransmitFIFOWriteFull, TransmitFIFOReadEmpty, TransmitWriteMark, TransmitReadMark);
spi_fifo #(3,8) rxFIFO(PCLK, SCLKenable, 1'b1, PRESETn, ReceiveFiFoWriteInc, ReceiveFIFOReadIncrement, ReceiveShiftRegEndian, ReceiveWatermark[2:0], ReceiveReadWatermarkLevel,
ReceiveData[7:0], ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty, RecieveWriteMark, RecieveReadMark);
always_ff @(posedge PCLK)
if (~PRESETn) TransmitFIFOReadEmptyDelay <= 1'b1;
else if (SCLKenable) TransmitFIFOReadEmptyDelay <= TransmitFIFOReadEmpty;
always_ff @(posedge PCLK)
if (~PRESETn) ReceiveShiftFullDelay <= 1'b0;
else if (SCLKenable) ReceiveShiftFullDelay <= ReceiveShiftFull;
assign ReceiveFiFoTakingData = ReceiveFiFoWriteInc & ~ReceiveFIFOWriteFull;
// register map
localparam SPI_SCKDIV = 8'h00;
localparam SPI_SCKMODE = 8'h04;
localparam SPI_CSID = 8'h10;
localparam SPI_CSDEF = 8'h14;
localparam SPI_CSMODE = 8'h18;
localparam SPI_DELAY0 = 8'h28;
localparam SPI_DELAY1 = 8'h2C;
localparam SPI_FMT = 8'h40;
localparam SPI_TXDATA = 8'h48;
localparam SPI_RXDATA = 8'h4C;
localparam SPI_TXMARK = 8'h50;
localparam SPI_RXMARK = 8'h54;
localparam SPI_IE = 8'h70;
localparam SPI_IP = 8'h74;
always_ff @(posedge PCLK)
if (~PRESETn) ReceiveFiFoWriteInc <= 1'b0;
else if (SCLKenable & ReceiveShiftFull) ReceiveFiFoWriteInc <= 1'b1;
else if (SCLKenable & ReceiveFiFoTakingData) ReceiveFiFoWriteInc <= 1'b0;
always_ff @(posedge PCLK)
if (~PRESETn) ReceiveShiftFullDelayPCLK <= 1'b0;
else if (SCLKenableEarly) ReceiveShiftFullDelayPCLK <= ReceiveShiftFull;
// SPI control registers. Refer to SiFive FU540-C000 manual
logic [11:0] SckDiv;
logic [1:0] SckMode;
logic [1:0] ChipSelectID;
logic [3:0] ChipSelectDef;
logic [1:0] ChipSelectMode;
logic [15:0] Delay0, Delay1;
logic [4:0] Format;
logic [7:0] ReceiveData;
logic [8:0] TransmitData;
logic [2:0] TransmitWatermark, ReceiveWatermark;
logic [1:0] InterruptEnable, InterruptPending;
// Bus interface signals
logic [7:0] Entry;
logic Memwrite;
logic [31:0] Din, Dout;
// SPI Controller signals
logic SCLKenable;
logic EndOfFrame;
logic Transmitting;
logic InactiveState;
logic [3:0] FrameLength;
// Starting Transmission and restarting SCLKenable
logic ResetSCLKenable;
logic TransmitStart;
logic TransmitStartD;
// Main FSM which controls SPI transmission
typedef enum logic [2:0] {CS_INACTIVE, DELAY_0, ACTIVE_0, ACTIVE_1, DELAY_1,INTER_CS, INTER_XFR} statetype;
statetype state;
// Transmit Start State Machine Variables
typedef enum logic [1:0] {READY, START, WAIT} txState;
txState CurrState, NextState;
// FIFO Watermark signals - TransmitReadMark = ip[0], ReceiveWriteMark = ip[1]
logic TransmitWriteMark, TransmitReadMark, ReceiveWriteMark, ReceiveReadMark;
always_ff @(posedge PCLK)
if (~PRESETn) begin
state <= CS_INACTIVE;
FrameCount <= 4'b0;
SPICLK <= SckMode[1];
end else if (SCLKenable) begin
/* verilator lint_off CASEINCOMPLETE */
case (state)
CS_INACTIVE: begin
CS_SCKCount <= 9'b1;
SCK_CSCount <= 9'b10;
FrameCount <= 4'b0;
InterCSCount <= 9'b10;
InterXFRCount <= 9'b1;
if ((~TransmitFIFOReadEmpty | ~TransmitShiftEmpty) & ((|(Delay0[7:0])) | ~SckMode[0])) state <= DELAY_0;
else if ((~TransmitFIFOReadEmpty | ~TransmitShiftEmpty)) begin
state <= ACTIVE_0;
SPICLK <= ~SckMode[1];
end else SPICLK <= SckMode[1];
end
DELAY_0: begin
CS_SCKCount <= CS_SCKCount + 9'b1;
if (CS_SCKCount >= (({Delay0[7:0], 1'b0}) + ImplicitDelay1)) begin
state <= ACTIVE_0;
SPICLK <= ~SckMode[1];
end
end
ACTIVE_0: begin
FrameCount <= FrameCount + 4'b1;
SPICLK <= SckMode[1];
state <= ACTIVE_1;
end
ACTIVE_1: begin
InterXFRCount <= 9'b1;
if (FrameCount < Format[4:1]) begin
state <= ACTIVE_0;
SPICLK <= ~SckMode[1];
end
else if ((ChipSelectMode[1:0] == 2'b10) & ~|(Delay1[15:8]) & (~TransmitFIFOReadEmpty)) begin
state <= ACTIVE_0;
SPICLK <= ~SckMode[1];
CS_SCKCount <= 9'b1;
SCK_CSCount <= 9'b10;
FrameCount <= 4'b0;
InterCSCount <= 9'b10;
end
else if (ChipSelectMode[1:0] == 2'b10) state <= INTER_XFR;
else if (~|(Delay0[15:8]) & (~SckMode[0])) state <= INTER_CS;
else state <= DELAY_1;
end
DELAY_1: begin
SCK_CSCount <= SCK_CSCount + 9'b1;
if (SCK_CSCount >= (({Delay0[15:8], 1'b0}) + ImplicitDelay2)) state <= INTER_CS;
end
INTER_CS: begin
InterCSCount <= InterCSCount + 9'b1;
SPICLK <= SckMode[1];
if (InterCSCount >= ({Delay1[7:0],1'b0})) state <= CS_INACTIVE;
end
INTER_XFR: begin
CS_SCKCount <= 9'b1;
SCK_CSCount <= 9'b10;
FrameCount <= 4'b0;
InterCSCount <= 9'b10;
InterXFRCount <= InterXFRCount + 9'b1;
if ((InterXFRCount >= ({Delay1[15:8], 1'b0})) & (~TransmitFIFOReadEmptyDelay | ~TransmitShiftEmpty)) begin
state <= ACTIVE_0;
SPICLK <= ~SckMode[1];
end else if (~|ChipSelectMode[1:0]) state <= CS_INACTIVE;
else SPICLK <= SckMode[1];
end
endcase
/* verilator lint_off CASEINCOMPLETE */
end
// Transmit FIFO Signals
logic TransmitFIFOFull, TransmitFIFOEmpty;
logic TransmitFIFOWriteInc;
logic TransmitFIFOReadInc; // Increments Tx FIFO read ptr 1 cycle after Tx FIFO is read
logic [7:0] TransmitReadData;
// ReceiveFIFO Signals
logic ReceiveFIFOWriteInc;
logic ReceiveFIFOReadInc;
logic ReceiveFIFOFull, ReceiveFIFOEmpty;
/* verilator lint_off UNDRIVEN */
logic [2:0] TransmitWriteWatermarkLevel, ReceiveReadWatermarkLevel; // unused generic FIFO outputs
/* verilator lint_off UNDRIVEN */
logic [7:0] ReceiveShiftRegEndian; // Reverses ReceiveShiftReg if Format[2] set (little endian transmission)
assign DelayMode = SckMode[0] ? (state == DELAY_1) : (state == ACTIVE_1 & ReceiveShiftFull);
assign ChipSelectInternal = (state == CS_INACTIVE | state == INTER_CS | DelayMode & ~|(Delay0[15:8])) ? ChipSelectDef : ~ChipSelectDef;
assign Active = (state == ACTIVE_0 | state == ACTIVE_1);
assign SampleEdge = SckMode[0] ? (state == ACTIVE_1) : (state == ACTIVE_0);
assign ZeroDelayHoldMode = ((ChipSelectMode == 2'b10) & (~|(Delay1[7:4])));
assign TransmitInactive = ((state == INTER_CS) | (state == CS_INACTIVE) | (state == INTER_XFR) | (ReceiveShiftFullDelayPCLK & ZeroDelayHoldMode) | ((state == ACTIVE_1) & ((ChipSelectMode[1:0] == 2'b10) & ~|(Delay1[15:8]) & (~TransmitFIFOReadEmpty) & (FrameCount == Format[4:1]))));
assign Active0 = (state == ACTIVE_0);
assign ShiftEdgeSPICLK = ZeroDiv ? ~SPICLK : SPICLK;
// Shift reg signals
logic ShiftEdge; // Determines which edge of sck to shift from TransmitReg
logic SampleEdge; // Determines which edge of sck to sample from ReceiveShiftReg
logic [7:0] TransmitReg; // Transmit shift register
logic [7:0] ReceiveShiftReg; // Receive shift register
logic [7:0] TransmitDataEndian; // Reverses TransmitData from txFIFO if littleendian, since TransmitReg always shifts MSB
logic TransmitLoad; // Determines when to load TransmitReg
logic TransmitRegLoaded;
// Signal tracks which edge of sck to shift data
always_comb
case(SckMode[1:0])
2'b00: ShiftEdge = ShiftEdgeSPICLK & SCLKenable;
2'b01: ShiftEdge = (~ShiftEdgeSPICLK & ~FirstFrame & (|(FrameCount) | (CS_SCKCount >= (({Delay0[7:0], 1'b0}) + ImplicitDelay1))) & SCLKenable & (FrameCount != Format[4:1]) & ~TransmitInactive);
2'b10: ShiftEdge = ~ShiftEdgeSPICLK & SCLKenable;
2'b11: ShiftEdge = (ShiftEdgeSPICLK & ~FirstFrame & (|(FrameCount) | (CS_SCKCount >= (({Delay0[7:0], 1'b0}) + ImplicitDelay1))) & SCLKenable & (FrameCount != Format[4:1]) & ~TransmitInactive);
default: ShiftEdge = ShiftEdgeSPICLK & SCLKenable;
// Shift stuff due to Format register?
logic ShiftIn; // Determines whether to shift from SPIIn or SPIOut (if SPI_LOOPBACK_TEST)
logic [3:0] LeftShiftAmount; // Determines left shift amount to left-align data when little endian
logic [7:0] ASR; // AlignedReceiveShiftReg
// CS signals
logic [3:0] ChipSelectAuto; // Assigns ChipSelect value to selected CS signal based on CS ID
logic [3:0] ChipSelectInternal; // Defines what each ChipSelect signal should be based on transmission status and ChipSelectDef
// APB access
assign Entry = {PADDR[7:2],2'b00}; // 32-bit word-aligned accesses
assign Memwrite = PWRITE & PENABLE & PSEL; // Only write in access phase
assign PREADY = 1'b1;
// Account for subword read/write circuitry
// -- Note SPI registers are 32 bits no matter what; access them with LW SW.
assign Din = PWDATA[31:0];
if (P.XLEN == 64) assign PRDATA = { Dout, Dout};
else assign PRDATA = Dout;
// Register access
always_ff@(posedge PCLK)
if (~PRESETn) begin
SckDiv <= 12'd3;
SckMode <= 2'b0;
ChipSelectID <= 2'b0;
ChipSelectDef <= 4'b1111;
ChipSelectMode <= 2'b0;
Delay0 <= {8'b1,8'b1};
Delay1 <= {8'b0,8'b1};
Format <= {5'b10000};
TransmitData <= 9'b0;
TransmitWatermark <= 3'b0;
ReceiveWatermark <= 3'b0;
InterruptEnable <= 2'b0;
InterruptPending <= 2'b0;
end else begin // writes
/* verilator lint_off CASEINCOMPLETE */
if (Memwrite)
case(Entry) // flop to sample inputs
SPI_SCKDIV: SckDiv <= Din[11:0];
SPI_SCKMODE: SckMode <= Din[1:0];
SPI_CSID: ChipSelectID <= Din[1:0];
SPI_CSDEF: ChipSelectDef <= Din[3:0];
SPI_CSMODE: ChipSelectMode <= Din[1:0];
SPI_DELAY0: Delay0 <= {Din[23:16], Din[7:0]};
SPI_DELAY1: Delay1 <= {Din[23:16], Din[7:0]};
SPI_FMT: Format <= {Din[19:16], Din[2]};
SPI_TXMARK: TransmitWatermark <= Din[2:0];
SPI_RXMARK: ReceiveWatermark <= Din[2:0];
SPI_IE: InterruptEnable <= Din[1:0];
endcase
// Transmit shift register
assign TransmitDataEndian = Format[0] ? {TransmitFIFOReadData[0], TransmitFIFOReadData[1], TransmitFIFOReadData[2], TransmitFIFOReadData[3], TransmitFIFOReadData[4], TransmitFIFOReadData[5], TransmitFIFOReadData[6], TransmitFIFOReadData[7]} : TransmitFIFOReadData[7:0];
always_ff @(posedge PCLK)
if(~PRESETn) TransmitShiftReg <= 8'b0;
else if (TransmitShiftRegLoadSingleCycle) TransmitShiftReg <= TransmitDataEndian;
else if (ShiftEdge & Active) TransmitShiftReg <= {TransmitShiftReg[6:0], TransmitShiftReg[0]};
assign SPIOut = TransmitShiftReg[7];
// If in loopback mode, receive shift register is connected directly to module's output pins. Else, connected to SPIIn
// There are no setup/hold time issues because transmit shift register and receive shift register always shift/sample on opposite edges
assign ShiftIn = P.SPI_LOOPBACK_TEST ? SPIOut : SPIIn;
// Receive shift register
always_ff @(posedge PCLK)
if(~PRESETn) ReceiveShiftReg <= 8'b0;
else if (SampleEdge & SCLKenable) begin
if (~Active) ReceiveShiftReg <= 8'b0;
else ReceiveShiftReg <= {ReceiveShiftReg[6:0], ShiftIn};
end
// Aligns received data and reverses if little-endian
assign LeftShiftAmount = 4'h8 - Format[4:1];
assign ASR = ReceiveShiftReg << LeftShiftAmount[2:0];
assign ReceiveShiftRegEndian = Format[0] ? {ASR[0], ASR[1], ASR[2], ASR[3], ASR[4], ASR[5], ASR[6], ASR[7]} : ASR[7:0];
// Interrupt logic: raise interrupt if any enabled interrupts are pending
assign SPIIntr = |(InterruptPending & InterruptEnable);
// Chip select logic
always_comb
case(ChipSelectID[1:0])
2'b00: ChipSelectAuto = {ChipSelectDef[3], ChipSelectDef[2], ChipSelectDef[1], ChipSelectInternal[0]};
2'b01: ChipSelectAuto = {ChipSelectDef[3],ChipSelectDef[2], ChipSelectInternal[1], ChipSelectDef[0]};
2'b10: ChipSelectAuto = {ChipSelectDef[3],ChipSelectInternal[2], ChipSelectDef[1], ChipSelectDef[0]};
2'b11: ChipSelectAuto = {ChipSelectInternal[3],ChipSelectDef[2], ChipSelectDef[1], ChipSelectDef[0]};
if (Memwrite)
case(Entry)
SPI_TXDATA: if (~TransmitFIFOFull) TransmitData[7:0] <= Din[7:0];
endcase
/* verilator lint_off CASEINCOMPLETE */
// According to FU540 spec: Once interrupt is pending, it will remain set until number
// of entries in tx/rx fifo is strictly more/less than tx/rxmark
InterruptPending[0] <= TransmitReadMark;
InterruptPending[1] <= ReceiveWriteMark;
case(Entry) // Flop to sample inputs
SPI_SCKDIV: Dout <= {20'b0, SckDiv};
SPI_SCKMODE: Dout <= {30'b0, SckMode};
SPI_CSID: Dout <= {30'b0, ChipSelectID};
SPI_CSDEF: Dout <= {28'b0, ChipSelectDef};
SPI_CSMODE: Dout <= {30'b0, ChipSelectMode};
SPI_DELAY0: Dout <= {8'b0, Delay0[15:8], 8'b0, Delay0[7:0]};
SPI_DELAY1: Dout <= {8'b0, Delay1[15:8], 8'b0, Delay1[7:0]};
SPI_FMT: Dout <= {12'b0, Format[4:1], 13'b0, Format[0], 2'b0};
SPI_TXDATA: Dout <= {TransmitFIFOFull, 23'b0, 8'b0};
SPI_RXDATA: Dout <= {ReceiveFIFOEmpty, 23'b0, ReceiveData[7:0]};
SPI_TXMARK: Dout <= {29'b0, TransmitWatermark};
SPI_RXMARK: Dout <= {29'b0, ReceiveWatermark};
SPI_IE: Dout <= {30'b0, InterruptEnable};
SPI_IP: Dout <= {30'b0, InterruptPending};
default: Dout <= 32'b0;
endcase
end
assign SPICS = ChipSelectMode[0] ? ChipSelectDef : ChipSelectAuto;
// SPI Controller module -------------------------------------------
// This module controls state and timing signals that drive the rest of this module
assign ResetSCLKenable = Memwrite & (Entry == SPI_SCKDIV);
assign FrameLength = Format[4:1];
spi_controller controller(PCLK, PRESETn,
// Transmit Signals
TransmitStart, TransmitRegLoaded, ResetSCLKenable,
// Register Inputs
SckDiv, SckMode, ChipSelectMode, Delay0, Delay1, FrameLength,
// txFIFO stuff
TransmitFIFOEmpty,
// Timing
SCLKenable, ShiftEdge, SampleEdge, EndOfFrame,
// State stuff
Transmitting, InactiveState,
// Outputs
SPICLK);
// Transmit FIFO ---------------------------------------------------
// txFIFO write increment logic
flopr #(1) txwincreg(PCLK, ~PRESETn,
(Memwrite & (Entry == SPI_TXDATA) & ~TransmitFIFOFull),
TransmitFIFOWriteInc);
// txFIFO read increment logic
flopenr #(1) txrincreg(PCLK, ~PRESETn, SCLKenable,
TransmitStartD | (EndOfFrame & ~TransmitFIFOEmpty),
TransmitFIFOReadInc);
// Check whether TransmitReg has been loaded.
// We use this signal to prevent returning to the Ready state for TransmitStart
always_ff @(posedge PCLK) begin
if (~PRESETn) begin
TransmitRegLoaded <= 1'b0;
end else if (TransmitLoad) begin
TransmitRegLoaded <= 1'b1;
end else if (ShiftEdge | EndOfFrame) begin
TransmitRegLoaded <= 1'b0;
end
end
// Setup TransmitStart state machine
always_ff @(posedge PCLK)
if (~PRESETn) CurrState <= READY;
else CurrState <= NextState;
// State machine for starting transmissions
always_comb begin
case (CurrState)
READY: if (~TransmitFIFOEmpty & ~Transmitting) NextState = START;
else NextState = READY;
START: NextState = WAIT;
WAIT: if (~Transmitting & ~TransmitRegLoaded) NextState = READY;
else NextState = WAIT;
default: NextState = READY;
endcase
end
// Delayed TransmitStart signal for incrementing tx read point.
assign TransmitStart = (CurrState == START);
always_ff @(posedge PCLK)
if (~PRESETn) TransmitStartD <= 1'b0;
else if (TransmitStart) TransmitStartD <= 1'b1;
else if (SCLKenable) TransmitStartD <= 1'b0;
// Transmit FIFO
spi_fifo #(3,8) txFIFO(PCLK, 1'b1, SCLKenable, PRESETn,
TransmitFIFOWriteInc, TransmitFIFOReadInc,
TransmitData[7:0],
TransmitWriteWatermarkLevel, TransmitWatermark[2:0],
TransmitReadData[7:0],
TransmitFIFOFull,
TransmitFIFOEmpty,
TransmitWriteMark, TransmitReadMark);
// Receive FIFO ----------------------------------------------------
// Receive FIFO Read Increment register
flopr #(1) rxfiforincreg(PCLK, ~PRESETn,
((Entry == SPI_RXDATA) & ~ReceiveFIFOEmpty & PSEL & ~ReceiveFIFOReadInc),
ReceiveFIFOReadInc);
// Receive FIFO Write Increment register
flopenr #(1) rxfifowincreg(PCLK, ~PRESETn, SCLKenable,
EndOfFrame, ReceiveFIFOWriteInc);
// Receive FIFO
spi_fifo #(3,8) rxFIFO(PCLK, SCLKenable, 1'b1, PRESETn,
ReceiveFIFOWriteInc, ReceiveFIFOReadInc,
ReceiveShiftRegEndian, ReceiveWatermark[2:0],
ReceiveReadWatermarkLevel,
ReceiveData[7:0],
ReceiveFIFOFull,
ReceiveFIFOEmpty,
ReceiveWriteMark, ReceiveReadMark);
// Shift Registers --------------------------------------------------
// Transmit shift register
assign TransmitLoad = TransmitStart | (EndOfFrame & ~TransmitFIFOEmpty);
assign TransmitDataEndian = Format[0] ? {<<{TransmitReadData[7:0]}} : TransmitReadData[7:0];
always_ff @(posedge PCLK)
if(~PRESETn) TransmitReg <= 8'b0;
else if (TransmitLoad) TransmitReg <= TransmitDataEndian;
else if (ShiftEdge) TransmitReg <= {TransmitReg[6:0], TransmitReg[0]};
assign SPIOut = TransmitReg[7];
// If in loopback mode, receive shift register is connected directly
// to module's output pins. Else, connected to SPIIn. There are no
// setup/hold time issues because transmit shift register and receive
// shift register always shift/sample on opposite edges
assign ShiftIn = P.SPI_LOOPBACK_TEST ? SPIOut : SPIIn;
// Receive shift register
always_ff @(posedge PCLK)
if(~PRESETn) begin
ReceiveShiftReg <= 8'b0;
end else if (SampleEdge) begin
ReceiveShiftReg <= {ReceiveShiftReg[6:0], ShiftIn};
end
// Aligns received data and reverses if little-endian
assign LeftShiftAmount = 4'h8 - FrameLength;
assign ASR = ReceiveShiftReg << LeftShiftAmount[2:0];
assign ReceiveShiftRegEndian = Format[0] ? {<<{ASR[7:0]}} : ASR[7:0];
// Interrupt logic: raise interrupt if any enabled interrupts are pending
assign SPIIntr = |(InterruptPending & InterruptEnable);
// Chip select logic
assign ChipSelectInternal = InactiveState ? ChipSelectDef : ~ChipSelectDef;
always_comb
case(ChipSelectID[1:0])
2'b00: ChipSelectAuto = {ChipSelectDef[3], ChipSelectDef[2], ChipSelectDef[1], ChipSelectInternal[0]};
2'b01: ChipSelectAuto = {ChipSelectDef[3],ChipSelectDef[2], ChipSelectInternal[1], ChipSelectDef[0]};
2'b10: ChipSelectAuto = {ChipSelectDef[3],ChipSelectInternal[2], ChipSelectDef[1], ChipSelectDef[0]};
2'b11: ChipSelectAuto = {ChipSelectInternal[3],ChipSelectDef[2], ChipSelectDef[1], ChipSelectDef[0]};
endcase
assign SPICS = ChipSelectMode[0] ? ChipSelectDef : ChipSelectAuto;
endmodule

View File

@ -1,9 +1,8 @@
///////////////////////////////////////////
// spi_controller.sv
//
// Written: jacobpease@protonmail.com
// Written: Jacob Pease jacobpease@protonmail.com
// Created: October 28th, 2024
// Modified:
//
// Purpose: Controller logic for SPI
//
@ -12,7 +11,7 @@
// A component of the CORE-V-WALLY configurable RISC-V project.
// https://github.com/openhwgroup/cvw
//
// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University
// Copyright (C) 2021-24 Harvey Mudd College & Oklahoma State University
//
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
//
@ -28,21 +27,34 @@
// and limitations under the License.
////////////////////////////////////////////////////////////////////////////////////////////////
module spi_controller (
module spi_controller (
input logic PCLK,
input logic PRESETn,
// Start Transmission
input logic TransmitStart,
input logic TransmitRegLoaded,
input logic ResetSCLKenable,
// Registers
input logic [11:0] SckDiv,
input logic [1:0] SckMode,
input logic [1:0] CSMode,
input logic [15:0] Delay0,
input logic [15:0] Delay1,
input logic [7:0] txFIFORead,
input logic txFIFOReadEmpty,
output logic SPICLK,
output logic SPIOUT,
output logic CS
input logic [15:0] Delay0,
input logic [15:0] Delay1,
input logic [3:0] FrameLength,
// Is the Transmit FIFO Empty?
input logic TransmitFIFOEmpty,
// Control signals
output logic SCLKenable,
output logic ShiftEdge,
output logic SampleEdge,
output logic EndOfFrame,
output logic Transmitting,
output logic InactiveState,
output logic SPICLK
);
// CSMode Stuff
@ -50,44 +62,31 @@ module spi_controller (
localparam AUTOMODE = 2'b00;
localparam OFFMODE = 2'b11;
// FSM States
typedef enum logic [2:0] {INACTIVE, CSSCK, TRANSMIT, SCKCS, HOLD, INTERCS, INTERXFR} statetype;
statetype CurrState, NextState;
// SCLKenable stuff
logic [11:0] DivCounter;
logic SCLKenable;
logic SCLKenableEarly;
logic SCLKenableLate;
logic EdgeTiming;
logic ZeroDiv;
logic Clock0;
logic Clock1;
logic SCK; // SUPER IMPORTANT, THIS CAN'T BE THE SAME AS SPICLK!
logic SCK;
// Shift and Sample Edges
logic PreShiftEdge;
logic PreSampleEdge;
logic ShiftEdge;
logic SampleEdge;
logic EdgePulse;
logic ShiftEdgePulse;
logic SampleEdgePulse;
logic EndOfFramePulse;
logic PhaseOneOffset;
// Frame stuff
logic [2:0] BitNum;
logic [3:0] BitNum;
logic LastBit;
logic EndOfFrame;
logic EndOfFrameDelay;
logic PhaseOneOffset;
// Transmit Stuff
logic ContinueTransmit;
// SPIOUT Stuff
logic TransmitLoad;
logic [7:0] TransmitReg;
logic Transmitting;
logic EndTransmission;
logic HoldMode;
// logic TransmitRegLoaded; // TODO: Could be replaced by TransmitRegLoaded?
logic NextEndDelay;
logic CurrentEndDelay;
// Delay Stuff
logic [7:0] cssck;
@ -104,13 +103,12 @@ module spi_controller (
logic EndOfSCKCS;
logic EndOfINTERCS;
logic EndOfINTERXFR;
logic EndOfDelay;
logic [7:0] CSSCKCounter;
logic [7:0] SCKCSCounter;
logic [7:0] INTERCSCounter;
logic [7:0] INTERXFRCounter;
logic [7:0] DelayCounter;
logic DelayIsNext;
logic DelayState;
// Convenient Delay Reg Names
assign cssck = Delay0[7:0];
@ -125,67 +123,46 @@ module spi_controller (
assign HasINTERXFR = interxfr > 8'b0;
// Have we hit full delay for any of the delays?
assign EndOfCSSCK = CSSCKCounter == cssck;
assign EndOfSCKCS = SCKCSCounter == sckcs;
assign EndOfINTERCS = INTERCSCounter == intercs;
assign EndOfINTERXFR = INTERXFRCounter == interxfr;
assign EndOfCSSCK = (DelayCounter == cssck) & (CurrState == CSSCK);
assign EndOfSCKCS = (DelayCounter == sckcs) & (CurrState == SCKCS);
assign EndOfINTERCS = (DelayCounter == intercs) & (CurrState == INTERCS);
assign EndOfINTERXFR = (DelayCounter == interxfr) & (CurrState == INTERXFR);
assign EndOfDelay = EndOfCSSCK | EndOfSCKCS | EndOfINTERCS | EndOfINTERXFR;
// Clock Signal Stuff -----------------------------------------------
// I'm going to handle all clock stuff here, including ShiftEdge and
// SampleEdge. This makes sure that SPICLK is an output of a register
// and it properly synchronizes signals.
assign SCLKenableLate = DivCounter > SckDiv;
// SPI enable generation, where SCLK = PCLK/(2*(SckDiv + 1))
// Asserts SCLKenable at the rising and falling edge of SCLK by counting from 0 to SckDiv
// Active at 2x SCLK frequency to account for implicit half cycle delays and actions on both clock edges depending on phase
assign SCLKenable = DivCounter == SckDiv;
assign SCLKenableEarly = (DivCounter + 1'b1) == SckDiv;
assign LastBit = BitNum == 3'd7;
assign EdgeTiming = SckDiv > 12'b0 ? SCLKenableEarly : SCLKenable;
//assign SPICLK = Clock0;
assign ContinueTransmit = ~txFIFOReadEmpty & EndOfFrame;
assign EndTransmission = txFIFOReadEmpty & EndOfFrameDelay;
assign ContinueTransmit = ~TransmitFIFOEmpty & EndOfFrame;
assign EndTransmission = TransmitFIFOEmpty & EndOfFrame;
always_ff @(posedge PCLK) begin
if (~PRESETn) begin
DivCounter <= 12'b0;
SPICLK <= SckMode[1];
SCK <= 0;
BitNum <= 3'h0;
PreShiftEdge <= 0;
PreSampleEdge <= 0;
EndOfFrame <= 0;
BitNum <= 4'h0;
DelayCounter <= 0;
end else begin
// TODO: Consolidate into one delay counter since none of the
// delays happen at the same time?
// SCK logic for delay times
if (TransmitStart) begin
SCK <= 0;
end else if (SCLKenable) begin
SCK <= ~SCK;
end
if ((CurrState == CSSCK) & SCK) begin
CSSCKCounter <= CSSCKCounter + 8'd1;
end else begin
CSSCKCounter <= 8'd0;
end
if ((CurrState == SCKCS) & SCK) begin
SCKCSCounter <= SCKCSCounter + 8'd1;
end else begin
SCKCSCounter <= 8'd0;
end
if ((CurrState == INTERCS) & SCK) begin
INTERCSCounter <= INTERCSCounter + 8'd1;
end else begin
INTERCSCounter <= 8'd0;
end
if ((CurrState == INTERXFR) & SCK) begin
INTERXFRCounter <= INTERXFRCounter + 8'd1;
end else begin
INTERXFRCounter <= 8'd0;
// Counter for all four delay types
if (DelayState & SCK & SCLKenable) begin
DelayCounter <= DelayCounter + 8'd1;
end else if (SCLKenable & EndOfDelay) begin
DelayCounter <= 8'd0;
end
// SPICLK Logic
@ -196,32 +173,35 @@ module spi_controller (
end
// Reset divider
if (SCLKenable | TransmitStart) begin
if (SCLKenable | TransmitStart | ResetSCLKenable) begin
DivCounter <= 12'b0;
end else begin
DivCounter = DivCounter + 12'd1;
end
// EndOfFrame controller
// if (SckDiv > 0 ? SCLKenableEarly & LastBit & SPICLK : LastBit & ~SPICLK) begin
// EndOfFrame <= 1'b1;
// end else begin
// EndOfFrame <= 1'b0;
// end
if (~TransmitStart) begin
EndOfFrame <= (SckMode[1] ^ SckMode[0] ^ SPICLK) & SCLKenable & LastBit & Transmitting;
DivCounter <= DivCounter + 12'd1;
end
// Increment BitNum
if (ShiftEdge & Transmitting) begin
BitNum <= BitNum + 3'd1;
end else if (EndOfFrameDelay) begin
BitNum <= 3'b0;
BitNum <= BitNum + 4'd1;
end else if (EndOfFrame) begin
BitNum <= 4'b0;
end
end
end
// The very last bit in a frame of any length.
assign LastBit = (BitNum == FrameLength - 4'b1);
// Any SCLKenable pulse aligns with leading or trailing edge during
// Transmission. We can use this signal as the basis for ShiftEdge
// and SampleEdge.
assign EdgePulse = SCLKenable & Transmitting;
// Possible pulses for all edge types. Combined with SPICLK to get
// edges for different phase and polarity modes.
assign ShiftEdgePulse = EdgePulse & ~LastBit;
assign SampleEdgePulse = EdgePulse & ~DelayIsNext;
assign EndOfFramePulse = EdgePulse & LastBit;
// Delay ShiftEdge and SampleEdge by a half PCLK period
// Aligned EXACTLY ON THE MIDDLE of the leading and trailing edges.
// Sweeeeeeeeeet...
@ -230,21 +210,38 @@ module spi_controller (
ShiftEdge <= 0;
PhaseOneOffset <= 0;
SampleEdge <= 0;
EndOfFrameDelay <= 0;
end else begin
ShiftEdge <= ((SckMode[1] ^ SckMode[0] ^ SPICLK) & SCLKenable & ~LastBit & Transmitting) & PhaseOneOffset;
PhaseOneOffset <= PhaseOneOffset == 0 ? Transmitting & SCLKenable : PhaseOneOffset;
SampleEdge <= (SckMode[1] ^ SckMode[0] ^ ~SPICLK) & SCLKenable & Transmitting;
EndOfFrameDelay <= (SckMode[1] ^ SckMode[0] ^ SPICLK) & SCLKenable & LastBit & Transmitting;
EndOfFrame <= 0;
end else begin
PhaseOneOffset <= (PhaseOneOffset == 0) ? Transmitting & SCLKenable : ~EndOfFrame;
case(SckMode)
2'b00: begin
ShiftEdge <= SPICLK & ShiftEdgePulse;
SampleEdge <= ~SPICLK & SampleEdgePulse;
EndOfFrame <= SPICLK & EndOfFramePulse;
end
2'b01: begin
ShiftEdge <= ~SPICLK & ShiftEdgePulse & PhaseOneOffset;
SampleEdge <= SPICLK & SampleEdgePulse;
EndOfFrame <= ~SPICLK & EndOfFramePulse;
end
2'b10: begin
ShiftEdge <= ~SPICLK & ShiftEdgePulse;
SampleEdge <= SPICLK & SampleEdgePulse;
EndOfFrame <= ~SPICLK & EndOfFramePulse;
end
2'b11: begin
ShiftEdge <= SPICLK & ShiftEdgePulse & PhaseOneOffset;
SampleEdge <= ~SPICLK & SampleEdgePulse;
EndOfFrame <= SPICLK & EndOfFramePulse;
end
endcase
end
end
// typedef enum logic [2:0] {INACTIVE, CSSCK, TRANSMIT, SCKCS, HOLD, INTERCS, INTERXFR} statetype;
// statetype CurrState, NextState;
assign HoldMode = CSMode == 2'b10;
assign TransmitLoad = TransmitStart | (EndOfFrameDelay & ~txFIFOReadEmpty);
// Logic for continuing to transmit through Delay states after end of frame
assign NextEndDelay = NextState == SCKCS | NextState == INTERCS | NextState == INTERXFR;
assign CurrentEndDelay = CurrState == SCKCS | CurrState == INTERCS | CurrState == INTERXFR;
always_ff @(posedge PCLK) begin
if (~PRESETn) begin
CurrState <= INACTIVE;
@ -255,71 +252,68 @@ module spi_controller (
always_comb begin
case (CurrState)
INACTIVE: begin // INACTIVE case --------------------------------
if (TransmitStart) begin
if (~HasCSSCK) begin
NextState = TRANSMIT;
end else begin
NextState = CSSCK;
end
end else begin
NextState = INACTIVE;
end
end
CSSCK: begin // DELAY0 case -------------------------------------
if (EndOfCSSCK) begin
NextState = TRANSMIT;
end
end
INACTIVE: if (TransmitRegLoaded) begin
if (~HasCSSCK) NextState = TRANSMIT;
else NextState = CSSCK;
end else begin
NextState = INACTIVE;
end
CSSCK: if (EndOfCSSCK) NextState = TRANSMIT;
else NextState = CSSCK;
TRANSMIT: begin // TRANSMIT case --------------------------------
case(CSMode)
AUTOMODE: begin
if (EndTransmission) begin
NextState = INACTIVE;
end else if (ContinueTransmit) begin
NextState = SCKCS;
end
if (EndTransmission) NextState = INACTIVE;
else if (EndOfFrame) NextState = SCKCS;
else NextState = TRANSMIT;
end
HOLDMODE: begin
if (EndTransmission) begin
NextState = HOLD;
end else if (ContinueTransmit) begin
if (HasINTERXFR) NextState = INTERXFR;
end
if (EndTransmission) NextState = HOLD;
else if (ContinueTransmit & HasINTERXFR) NextState = INTERXFR;
else NextState = TRANSMIT;
end
OFFMODE: begin
if (EndTransmission) NextState = INACTIVE;
else if (ContinueTransmit & HasINTERXFR) NextState = INTERXFR;
else NextState = TRANSMIT;
end
default: NextState = TRANSMIT;
endcase
end
SCKCS: begin // SCKCS case --------------------------------------
if (EndOfSCKCS) begin
if (EndTransmission) begin
if (CSMode == AUTOMODE) NextState = INACTIVE;
else if (CSMode == HOLDMODE) NextState = HOLD;
end else if (ContinueTransmit) begin
if (~TransmitRegLoaded) begin
// if (CSMode == AUTOMODE) NextState = INACTIVE;
if (CSMode == HOLDMODE) NextState = HOLD;
else NextState = INACTIVE;
end else begin
if (HasINTERCS) NextState = INTERCS;
else NextState = TRANSMIT;
end
end else begin
NextState = SCKCS;
end
end
HOLD: begin // HOLD mode case -----------------------------------
if (CSMode == AUTOMODE) begin
NextState = INACTIVE;
end else if (TransmitStart) begin // If FIFO is written to, start again.
end else if (TransmitRegLoaded) begin // If FIFO is written to, start again.
NextState = TRANSMIT;
end
end else NextState = HOLD;
end
INTERCS: begin // INTERCS case ----------------------------------
if (EndOfINTERCS) begin
if (HasCSSCK) NextState = CSSCK;
else NextState = TRANSMIT;
end else begin
NextState = INTERCS;
end
end
INTERXFR: begin // INTERXFR case --------------------------------
if (EndOfINTERXFR) begin
NextState = TRANSMIT;
end else begin
NextState = INTERXFR;
end
end
default: begin
@ -330,19 +324,7 @@ module spi_controller (
assign Transmitting = CurrState == TRANSMIT;
assign DelayIsNext = (NextState == CSSCK | NextState == SCKCS | NextState == INTERCS | NextState == INTERXFR);
//
always_ff @(posedge PCLK) begin
if (~PRESETn) begin
TransmitReg <= 8'b0;
end else if (TransmitLoad) begin
TransmitReg <= txFIFORead;
end else if (ShiftEdge) begin
TransmitReg <= {TransmitReg[6:0], TransmitReg[0]};
end
end
assign SPIOUT = TransmitReg[7];
assign CS = CurrState == INACTIVE | CurrState == INTERCS;
assign DelayState = (CurrState == CSSCK | CurrState == SCKCS | CurrState == INTERCS | CurrState == INTERXFR);
assign InactiveState = CurrState == INACTIVE | CurrState == INTERCS;
endmodule

View File

@ -19,6 +19,10 @@ module spi_fifo #(parameter M=3, N=8)( // 2^M entries of N bits
logic [M:0] rptrnext, wptrnext;
logic [M-1:0] raddr;
logic [M-1:0] waddr;
logic [M-1:0] numVals;
assign numVals = waddr - raddr;
assign rdata = mem[raddr];
always_ff @(posedge PCLK)

View File

@ -72,7 +72,8 @@ string coverage64gc[] = '{
"pmpcfg2",
"pmppriority",
"pmpcbo",
"pmpadrdecs"
"pmpadrdecs",
"btbthrash"
};
string buildroot[] = '{

145
tests/coverage/btbthrash.S Normal file
View File

@ -0,0 +1,145 @@
///////////////////////////////////////////
// btbtrash.S
//
// Written: Rose Thompson rose@rosethompson.net 23 October 2024
//
// Purpose: Test the branch target buffer alias with divide and cache pipeline stalls
//
// A component of the CORE-V-WALLY configurable RISC-V project.
// https://github.com/openhwgroup/cvw
//
// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University
//
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
//
// Licensed under the Solderpad Hardware License v 2.1 (the License); you may not use this file
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
// may obtain a copy of the License at
//
// https://solderpad.org/licenses/SHL-2.1/
//
// Unless required by applicable law or agreed to in writing, any work distributed under the
// License is distributed on an AS IS BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions
// and limitations under the License.
////////////////////////////////////////////////////////////////////////////////////////////////
// load code to initalize stack, handle interrupts, terminate
#include "WALLY-init-lib.h"
main:
# Division test (having trouble with buildroot)
li x1, 1938759018
li x2, 3745029
li x3, 458
li x4, 29587209347
li x5, 28957
li x6, 298
li x7, 238562
li x8, 198674
li x9, 134
li x10, 906732
li x11, 29
li x12, 50912
li x13, 59
li x14, 6902385
li x15, 1923857
li x16, 3985
li x17, 3947
li x18, 15984
li x19, 5
li x20, 9684658489
li x21, 6548
li x22, 3564
li x23, 94
li x24, 689464
li x25, 42567
li x26, 98453
li x27, 648
li x28, 984
li x29, 6984
li x30, 864
# x31 will be our loop counter
li x31, 4
.align 12
jump1:
divuw x0, x1, x2
j jump3
jump4:
divuw x0, x5, x6
j jump5
jump6:
divuw x0, x10, x9
j jump7
jump8:
divuw x0, x14, x3
j jump9
jump10:
divuw x0, x18, x17
j jump11
jump12:
divuw x0, x21, x22
j jump13
jump14:
divuw x0, x24, x25
j jump15
jump16:
divuw x0, x29, x28
j jump17
jump18:
divuw x0, x1, x30
j jump19
jump20:
divuw x0, x3, x19
j jump21
jump22:
divuw x0, x12, x13
j jump23
.align 12 # size of the 1024 btb apart
jump2:
j jump1
jump3:
divuw x0, x4, x3
j jump4
jump5:
divuw x0, x7, x8
j jump6
jump7:
divuw x0, x12, x11
j jump8
jump9:
divuw x0, x15, x16
j jump10
jump11:
divuw x0, x20, x19
j jump12
jump13:
divuw x0, x24, x23
j jump14
jump15:
divuw x0, x26, x27
j jump16
jump17:
divuw x0, x29, x30
j jump18
jump19:
divuw x0, x2, x3
j jump20
jump21:
divuw x0, x4, x5
j jump22
jump23:
divuw x0, x20, x21
#j jump22
fence.i
addi x31, x31, -1
bne x31, x0, jump1
finsihed:
j done

View File

@ -238,46 +238,6 @@
0000001F
00000062 # hardware interlock
00000026
000000D2
0000002D
00000048
00000037
00000026
00000015
00000084
00000073
00000062
00000051
00000046
00000035
00000024
00000013
00000064
00000053
00000042
00000031
00000001 #watermark interrupts
00000000 #read mip

View File

@ -547,108 +547,13 @@ test_cases:
#.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
#.4byte rx_data, 0x000000F0, read32_test # read rx_data
#=========== Test Hardware Interlock ================
# interlock in base case
.4byte fmt, 0x00080000, write32_test # reset fmt register
.4byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock
.4byte tx_data, 0x00000062, write32_test # initiate transmission
.4byte sck_mode, 0x00000002, write32_test # flip polarity during transmission
.4byte tx_data, 0x00000026, write32_test # transmit second frame w/ control register updated
.4byte 0x0, 0x00000001, spi_data_wait
.4byte rx_data, 0x00000062, read32_test
.4byte rx_data, 0x00000026, read32_test # clear rx fifo
.4byte sck_mode, 0x00000000, write32_test # reset polarity
# interlock in case where cs_mode is auto, but there is minimal intercs delay
.4byte delay0, 0x00000001, write32_test # set sck-cs delay to 0, with sck.pha 0 there is 0 delay
.4byte tx_data, 0x000000D2, write32_test # initiate transmission
.4byte sck_mode, 0x00000002, write32_test # flip sck polarity
.4byte tx_data, 0x0000002D, write32_test # transmit second frame
.4byte 0x0, 0x00000001, spi_data_wait
.4byte rx_data, 0x000000D2, read32_test
.4byte rx_data, 0x0000002D, read32_test # clear rx fifo
.4byte sck_mode, 0x00000000, write32_test # reset polarity
# interlock in case where cs_mode = hold, 0 intercs delay
.4byte delay0, 0x00010001, write32_test # reset delay0
.4byte sck_mode, 0x00000000, write32_test # reset polarity
.4byte cs_mode, 0x00000002, write32_test # set cs_mode to hold
.4byte tx_data, 0x15263748, spi_burst_send # place 4 frames into tx fifo
.4byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame)
.4byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end
.4byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.4byte sck_mode, 0x00000000, write32_test # flip polarity again
.4byte 0x0, 0x00000003, spi_data_wait # wait for final frame
.4byte rx_data, 0x00000048, read32_test
.4byte rx_data, 0x00000037, read32_test
.4byte rx_data, 0x00000026, read32_test
.4byte rx_data, 0x00000015, read32_test #clear rx fifo
# interlock in case where cs_mode = hold, intercs delay
.4byte sck_mode, 0x00000000, write32_test # reset polarity
.4byte delay1, 0x00010001, write32_test # set intercs delay to 1
.4byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock
.4byte tx_data, 0x51627384, spi_burst_send # place 4 frames into tx fifo
.4byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame)
.4byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end
.4byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.4byte sck_mode, 0x00000000, write32_test # flip polarity again
.4byte 0x0, 0x00000003, spi_data_wait # wait for final frame
.4byte rx_data, 0x00000084, read32_test
.4byte rx_data, 0x00000073, read32_test
.4byte rx_data, 0x00000062, read32_test
.4byte rx_data, 0x00000051, read32_test #clear rx fifo
# repeat previous set of tests with cs_mode = off
.4byte cs_mode, 0x00000003, write32_test # set cs_mode to hold
.4byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock
.4byte tx_data, 0x13243546, spi_burst_send # place 4 frames into tx fifo
.4byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame)
.4byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end
.4byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.4byte sck_mode, 0x00000000, write32_test # flip polarity again
.4byte 0x0, 0x00000003, spi_data_wait # wait for final frame
.4byte rx_data, 0x00000046, read32_test
.4byte rx_data, 0x00000035, read32_test
.4byte rx_data, 0x00000024, read32_test
.4byte rx_data, 0x00000013, read32_test #clear rx fifo
# interlock in case where cs_mode = hold, intercs delay
.4byte sck_mode, 0x00000000, write32_test # reset polarity
.4byte delay1, 0x00000000, write32_test # set intercs delay to 0
.4byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock
.4byte tx_data, 0x31425364, spi_burst_send # place 4 frames into tx fifo
.4byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame)
.4byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end
.4byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.4byte sck_mode, 0x00000000, write32_test # flip polarity again
.4byte 0x0, 0x00000003, spi_data_wait # wait for final frame
.4byte rx_data, 0x00000064, read32_test
.4byte rx_data, 0x00000053, read32_test
.4byte rx_data, 0x00000042, read32_test
.4byte rx_data, 0x00000031, read32_test #clear rx fifo
# =========== Test watermark interrupts ===========
# Test transmit watermark interrupt (triggers when entries in tx FIFO < tx watermark) without external enables
SETUP_PLIC
.4byte fmt, 0x00080000, write32_test # reset format register
.4byte delay1, 0x0000001, write32_test # reset delay1 register
.4byte cs_mode, 0x00000000, write32_test # reset cs_mode
.4byte tx_mark, 0x00000001, write32_test # set transmit watermark to 1 (any entry turns mark off)

View File

@ -238,46 +238,6 @@
00000000
0000001F
00000000
00000062 # hardware interlock
00000000
00000026
00000000
000000D2
00000000
0000002D
00000000
00000048
00000000
00000037
00000000
00000026
00000000
00000015
00000000
00000084
00000000
00000073
00000000
00000062
00000000
00000051
00000000
00000046
00000000
00000035
00000000
00000024
00000000
00000013
00000000
00000064
00000000
00000053
00000000
00000042
00000000
00000031
00000000
00000001 #watermark interrupts
00000000
00000000 #read mip

View File

@ -551,94 +551,6 @@ test_cases:
#.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
#.8byte rx_data, 0x000000F0, read32_test # read rx_data
#=========== Test Hardware Interlock ================
# interlock in base case
.8byte fmt, 0x00080000, write32_test # reset fmt register
.8byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x00000062, write32_test # initiate transmission
.8byte sck_mode, 0x00000002, write32_test # flip polarity during transmission
.8byte tx_data, 0x00000026, write32_test # transmit second frame w/ control register updated
.8byte 0x0, 0x00000001, spi_data_wait
.8byte rx_data, 0x00000062, read32_test
.8byte rx_data, 0x00000026, read32_test # clear rx fifo
.8byte sck_mode, 0x00000000, write32_test # reset polarity
# interlock in case where cs_mode is auto, but there is minimal intercs delay
.8byte delay0, 0x00000001, write32_test # set sck-cs delay to 0, with sck.pha 0 there is 0 delay
.8byte tx_data, 0x000000D2, write32_test # initiate transmission
.8byte sck_mode, 0x00000002, write32_test # flip sck polarity
.8byte tx_data, 0x0000002D, write32_test # transmit second frame
.8byte 0x0, 0x00000001, spi_data_wait
.8byte rx_data, 0x000000D2, read32_test
.8byte rx_data, 0x0000002D, read32_test # clear rx fifo
.8byte sck_mode, 0x00000000, write32_test # reset polarity
# interlock in case where cs_mode = hold, 0 intercs delay
.8byte delay0, 0x00010001, write32_test # reset delay0
.8byte sck_mode, 0x00000000, write32_test # reset polarity
.8byte cs_mode, 0x00000002, write32_test # set cs_mode to hold
.8byte tx_data, 0x15263748, spi_burst_send # place 4 frames into tx fifo
.8byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame)
.8byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end
.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.8byte sck_mode, 0x00000000, write32_test # flip polarity again
.8byte 0x0, 0x00000003, spi_data_wait # wait for final frame
.8byte rx_data, 0x00000048, read32_test
.8byte rx_data, 0x00000037, read32_test
.8byte rx_data, 0x00000026, read32_test
.8byte rx_data, 0x00000015, read32_test #clear rx fifo
# interlock in case where cs_mode = hold, intercs delay
.8byte sck_mode, 0x00000000, write32_test # reset polarity
.8byte delay1, 0x00010001, write32_test # set intercs delay to 1
.8byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x51627384, spi_burst_send # place 4 frames into tx fifo
.8byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame)
.8byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end
.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.8byte sck_mode, 0x00000000, write32_test # flip polarity again
.8byte 0x0, 0x00000003, spi_data_wait # wait for final frame
.8byte rx_data, 0x00000084, read32_test
.8byte rx_data, 0x00000073, read32_test
.8byte rx_data, 0x00000062, read32_test
.8byte rx_data, 0x00000051, read32_test #clear rx fifo
# repeat previous set of tests with cs_mode = off
.8byte cs_mode, 0x00000003, write32_test # set cs_mode to hold
.8byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x13243546, spi_burst_send # place 4 frames into tx fifo
.8byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame)
.8byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end
.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.8byte sck_mode, 0x00000000, write32_test # flip polarity again
.8byte 0x0, 0x00000003, spi_data_wait # wait for final frame
.8byte rx_data, 0x00000046, read32_test
.8byte rx_data, 0x00000035, read32_test
.8byte rx_data, 0x00000024, read32_test
.8byte rx_data, 0x00000013, read32_test #clear rx fifo
# interlock in case where cs_mode = hold, intercs delay
.8byte sck_mode, 0x00000000, write32_test # reset polarity
.8byte delay1, 0x00000000, write32_test # set intercs delay to 0
.8byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x31425364, spi_burst_send # place 4 frames into tx fifo
.8byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame)
.8byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end
.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.8byte sck_mode, 0x00000000, write32_test # flip polarity again
.8byte 0x0, 0x00000003, spi_data_wait # wait for final frame
.8byte rx_data, 0x00000064, read32_test
.8byte rx_data, 0x00000053, read32_test
.8byte rx_data, 0x00000042, read32_test
.8byte rx_data, 0x00000031, read32_test #clear rx fifo
@ -652,7 +564,7 @@ test_cases:
# Test transmit watermark interrupt (triggers when entries in tx FIFO < tx watermark) without external enables
SETUP_PLIC
.8byte fmt, 0x00080000, write32_test # reset format register
.8byte delay1, 0x0000001, write32_test # reset delay1 register
.8byte cs_mode, 0x00000000, write32_test # reset cs_mode
.8byte sck_div, 0x00000100, write32_test # lower SPI clock rate so reads are done at correct time when ICACHE not supported