Merge branch 'openhwgroup:main' into main

This commit is contained in:
Rose Thompson 2024-10-29 15:46:25 -05:00 committed by GitHub
commit c93cadc95c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 644 additions and 151 deletions

View file

@ -67,6 +67,12 @@ jobs:
os: ubuntu-latest
image: null
riscv_path: /home/riscv
# Custom location user level installation
- name: custom-user-install
os: ubuntu-latest
image: null
user: true
riscv_path: $HOME/riscv-toolchain
# run on selected version of ubuntu or on ubuntu-latest with docker image
runs-on: ${{ matrix.os }}
@ -108,6 +114,7 @@ jobs:
fi
# Set environment variables for the rest of the job
- name: Set Environment Variables
if: always()
run: |
if [ ! -z ${{ matrix.riscv_path }} ]; then
sed -i 's,exit 1,export RISCV=${{ matrix.riscv_path }},g' setup.sh

View file

@ -1,4 +1,4 @@
![Installation CI](https://github.com/jordancarlin/cvw/actions/workflows/install.yml/badge.svg?branch=main)
![Installation CI](https://github.com/openhwgroup/cvw/actions/workflows/install.yml/badge.svg?branch=main)
# core-v-wally

View file

@ -84,7 +84,7 @@ from pathlib import Path
class FolderManager:
"""A class for managing folders and repository cloning."""
def __init__(self):
def __init__(self, basedir):
"""
Initialize the FolderManager instance.
@ -92,8 +92,12 @@ class FolderManager:
base_dir (str): The base directory where folders will be managed and repository will be cloned.
"""
env_extract_var = 'WALLY'
if os.environ.get(env_extract_var):
self.base_dir = os.environ.get(env_extract_var)
self.base_parent_dir = os.path.dirname(self.base_dir)
else:
self.base_dir = basedir
self.base_parent_dir = self.base_dir
# logger.info(f"Base directory: {self.base_dir}")
# logger.info(f"Parent Base directory: {self.base_parent_dir}")
@ -313,7 +317,7 @@ class TestRunner:
self.logger.error(f"Error making the tests. Target: {target}")
return False
def run_tests(self, test_type=None, test_name=None, test_extension=None):
def run_tests(self, test_type=None, test_name=None, test_extensions=None):
"""
Run a script through the terminal and save the output to a file.
@ -329,12 +333,12 @@ class TestRunner:
output_file = self.log_dir.joinpath(f"{test_name}-output.log")
os.chdir(self.sim_dir)
if test_extension:
command = [test_type, test_name, test_extension]
self.logger.info(f"Command used to run tests: {test_type} {test_name} {test_extension}")
if test_extensions:
command = [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]
self.logger.info(f"Command used to run tests: {test_type} {test_name}")
self.logger.info(f"Command used to run tests in directory {self.sim_dir}: {test_type} {test_name}")
# Execute the command using subprocess and save the output into a file
@ -348,10 +352,10 @@ class TestRunner:
self.logger.error("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 extention: {test_extension}")
self.logger.info(f"Test ran successfuly. Test type: {test_type}, 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 extention: {test_extension}")
self.logger.error(f"Error making test. Test type: {test_type}, test name: {test_name}, test extension: {' '.join(test_extensions)}")
return False, output_file
@ -406,23 +410,31 @@ class TestRunner:
# Remove ANSI escape codes
line = re.sub(r'\x1b\[[0-9;]*[mGK]', '', lines[index])
if "Success" in line:
if "Success" in line: # test succeeds
passed_configs.append(line.split(':')[0].strip())
elif "passed lint" in line:
passed_configs.append(line.split(' ')[0].strip())
passed_configs.append(f"Lint: {line.split(' ')[0].strip()}")
#passed_configs.append(line) # potentially use a space
elif "failed lint" in line:
failed_configs.append(line.split(' ')[0].strip(), "no log file")
failed_configs.append([f"Lint: {line.split(' ')[0].strip()}", "No Log File"])
#failed_configs.append(line)
elif "Failures detected in output" in line:
elif "Failures detected in output" in line: # Text explicitly fails
try:
config_name = line.split(':')[0].strip()
log_file = os.path.abspath("logs/"+config_name+".log")
log_file = os.path.abspath(os.path.join("logs", config_name, ".log"))
failed_configs.append((config_name, log_file))
except:
failed_configs.append((config_name, "Log file not found"))
elif "Timeout" in line: # Test times out
try:
config_name = line.split(':')[0].strip()
log_file = os.path.abspath("logs/"+config_name+".log")
failed_configs.append((f"Timeout: {config_name}", log_file))
except:
failed_configs.append((f"Timeout: {config_name}", "No Log File"))
index += 1
@ -535,7 +547,7 @@ class TestRunner:
md_file.write(f"\n**Total failed tests: {total_number_failures}**")
for (test_item, item) in zip(test_list, failed_tests):
md_file.write(f"\n\n### {test_item[1]} test")
md_file.write(f"\n**Command used:** {test_item[0]} {test_item[1]} {test_item[2]}\n\n")
md_file.write(f"\n**Command used:** {test_item[0]} {test_item[1]} {' '.join(test_item[2])}\n\n")
md_file.write(f"**Failed Tests:**\n")
@ -558,7 +570,7 @@ class TestRunner:
md_file.write(f"\n**Total successful tests: {total_number_success}**")
for (test_item, item) in zip(test_list, passed_tests):
md_file.write(f"\n\n### {test_item[1]} test")
md_file.write(f"\n**Command used:** {test_item[0]} {test_item[1]} {test_item[2]}\n\n")
md_file.write(f"\n**Command used:** {test_item[0]} {test_item[1]} {' '.join(test_item[2])}\n\n")
md_file.write(f"\n**Successful Tests:**\n")
@ -619,7 +631,7 @@ class TestRunner:
# check if there are any emails
if not receiver_emails:
self.logger.ERROR("No receiver emails provided.")
self.logger.error("No receiver emails provided.")
return
# grab the html file
@ -660,7 +672,7 @@ def main():
parser.add_argument('--path',default = "nightly", help='specify the path for where the nightly repositories will be cloned ex: "nightly-runs')
parser.add_argument('--repository',default = "https://github.com/openhwgroup/cvw", help='specify which github repository you want to clone')
parser.add_argument('--target', default = "all", help='types of tests you can make are: all, wally-riscv-arch-test, no')
parser.add_argument('--target', default = "--jobs", help='types of tests you can make are: all, wally-riscv-arch-test, no')
parser.add_argument('--tests', default = "nightly", help='types of tests you can run are: nightly, test, test_lint')
parser.add_argument('--send_email',default = "", nargs="+", help='What emails to send test results to. Example: "[email1],[email2],..."')
@ -682,7 +694,7 @@ def main():
log_file_path = log_path.joinpath("nightly_build.log")
previous_cvw_path = Path.home().joinpath(args.path,f"{yesterday}/cvw")
# creates the object
folder_manager = FolderManager()
folder_manager = FolderManager(basedir=args.path)
# setting the path on where to clone new repositories of cvw
folder_manager.create_folders([cvw_path, results_path, log_path])
@ -691,14 +703,18 @@ def main():
folder_manager.clone_repository(cvw_path, args.repository)
# Define tests that we can run
if (args.tests == "nightly"):
test_list = [["python", "regression-wally", "--nightly --buildroot"]]
elif (args.tests == "test"):
test_list = [["python", "regression-wally", ""]]
elif (args.tests == "test_lint"):
test_list = [["bash", "lint-wally", "-nightly"]]
#
# flags are a list
if (args.tests == "all"):
test_list = [["python", "./regression-wally", ["--nightly", "--buildroot"]]]
elif (args.tests == "nightly"):
test_list = [["python", "./regression-wally", ["--nightly"]]]
elif (args.tests == "regression"):
test_list = [["python", "./regression-wally", []]]
elif (args.tests == "lint"):
test_list = [["bash", "./lint-wally", ["--nightly"]]]
else:
print(f"Error: Invalid test '"+args.test+"' specified")
print(f"Error: Invalid test {args.tests} specified")
raise SystemExit
#############################################
@ -747,12 +763,12 @@ def main():
if args.target != "no":
test_runner.execute_makefile(target = args.target, makefile_path=test_runner.cvw)
if args.target == "all":
# Compile Linux for local testing
test_runner.set_env_var("RISCV",str(test_runner.cvw))
linux_path = test_runner.cvw / "linux"
test_runner.execute_makefile(target = "all_nosudo", makefile_path=linux_path)
test_runner.execute_makefile(target = "dumptvs_nosudo", makefile_path=linux_path)
# TODO: remove vestigial code if no longer wanted
# if args.target == "all":
# # Compile Linux for local testing
# test_runner.set_env_var("RISCV",str(test_runner.cvw))
# linux_path = test_runner.cvw / "linux"
# test_runner.execute_makefile(target = "all", makefile_path=linux_path)
#############################################
# RUN TESTS #
@ -766,9 +782,9 @@ def main():
total_failures = []
total_success = []
for test_type, test_name, test_extension in test_list:
for test_type, test_name, test_extensions in test_list:
check, output_location = test_runner.run_tests(test_type=test_type, test_name=test_name, test_extension=test_extension)
check, output_location = test_runner.run_tests(test_type=test_type, test_name=test_name, test_extensions=test_extensions)
try:
if check: # this checks if the test actually ran successfuly
output_log_list.append(output_location)
@ -778,7 +794,7 @@ def main():
passed, failed = test_runner.clean_format_output(input_file = output_location)
logger.info(f"{test_name} has been formatted to markdown")
except:
logger.ERROR(f"Error occured with formatting {test_name}")
logger.error(f"Error occured with formatting {test_name}")
logger.info(f"The # of failures are for {test_name}: {len(failed)}")
total_number_failures+= len(failed)
@ -789,14 +805,18 @@ def main():
total_success.append(passed)
test_runner.rewrite_to_markdown(test_name, passed, failed)
newlinechar = "\n"
logger.info(f"Failed tests: \n{newlinechar.join([x[0] for x in failed])}")
except Exception as e:
logger.error("There was an error in running the tests: {e}")
logger.error(f"There was an error in running the tests: {e}")
logger.info(f"The total sucesses for all tests ran are: {total_number_success}")
logger.info(f"The total failures for all tests ran are: {total_number_failures}")
# Copy actual test logs from sim/questa, sim/verilator
test_runner.copy_sim_logs([test_runner.cvw / "sim/questa/logs", test_runner.cvw / "sim/verilator/logs"])
# Copy actual test logs from sim/questa, sim/verilator, sim/vcs
if not args.tests == "test_lint":
test_runner.copy_sim_logs([test_runner.cvw / "sim/questa/logs", test_runner.cvw / "sim/verilator/logs", test_runner.cvw / "sim/vcs/logs"])
#############################################
# FORMAT TESTS #

View file

@ -507,7 +507,7 @@ def main():
TIMEOUT_DUR = 20*60 # seconds
os.system('rm -f questa/cov/*.ucdb')
elif args.fcov:
TIMEOUT_DUR = 2*60
TIMEOUT_DUR = 8*60
os.system('rm -f questa/fcov_ucdb/* questa/fcov_logs/* questa/fcov/*')
elif args.buildroot:
TIMEOUT_DUR = 60*1440 # 1 day
@ -534,6 +534,7 @@ def main():
try:
num_fail+=result.get(timeout=TIMEOUT_DUR)
except TimeoutError:
pool.terminate()
num_fail+=1
print(f"{bcolors.FAIL}%s: Timeout - runtime exceeded %d seconds{bcolors.ENDC}" % (config.cmd, TIMEOUT_DUR))

View file

@ -48,28 +48,64 @@ ENDC='\033[0m' # Reset to default color
error() {
echo -e "${FAIL_COLOR}Error: $STATUS installation failed"
echo -e "Error on line ${BASH_LINENO[0]} with command $BASH_COMMAND${ENDC}"
if [ -e "$RISCV/logs/$STATUS.log" ]; then
echo -e "Please check the log in $RISCV/logs/$STATUS.log for more information."
fi
exit 1
}
# Check if a git repository exists, is up to date, and has been installed
# Clones the repository if it doesn't exist
# clones the repository if it doesn't exist
# $1: repo name
# $2: repo url to clone from
# $3: file to check if already installed
# $4: upstream branch, optional, default is master
git_check() {
local repo=$1
local url=$2
local check=$3
local branch="${4:-master}"
if [[ ((! -e $repo) && ($(git clone "$url") || true)) || ($(cd "$repo"; git fetch; git rev-parse HEAD) != $(cd "$repo"; git rev-parse origin/"$branch")) || (! -e $check) ]]; then
return 0
# Clone repo if it doesn't exist
if [[ ! -e $repo ]]; then
for ((i=1; i<=5; i++)); do
git clone "$url" && break
echo -e "${WARNING_COLOR}Failed to clone $repo. Retrying.${ENDC}"
rm -rf "$repo"
sleep $i
done
if [[ ! -e $repo ]]; then
echo -e "${ERROR_COLOR}Failed to clone $repo after 5 attempts. Exiting.${ENDC}"
exit 1
fi
fi
# Get the current HEAD commit hash and the remote branch commit hash
cd "$repo"
git fetch
local local_head=$(git rev-parse HEAD)
local remote_head=$(git rev-parse origin/"$branch")
# Check if the git repository is not up to date or the specified file does not exist
if [[ "$local_head" != "$remote_head" ]]; then
echo "$repo is not up to date. Updating now."
true
elif [[ ! -e $check ]]; then
true
else
return 1
false
fi
}
# Log output to a file and only print lines with keywords
logger() {
local log="$RISCV/logs/$1.log"
cat < /dev/stdin | tee -a "$log" | (grep -iE --color=never "(\bwarning|\berror|\bfail|\bsuccess|\bstamp|\bdoesn't work)" || true) | (grep -viE --color=never "(_warning|warning_|_error|error_|-warning|warning-|-error|error-|Werror|error\.o|warning flags)" || true)
local log_file="$RISCV/logs/$1.log"
local keyword_pattern="(\bwarning|\berror|\bfail|\bsuccess|\bstamp|\bdoesn't work)"
local exclude_pattern="(_warning|warning_|_error|error_|-warning|warning-|-error|error-|Werror|error\.o|warning flags)"
cat < /dev/stdin | tee -a "$log_file" | \
(grep -iE --color=never "$keyword_pattern" || true) | \
(grep -viE --color=never "$exclude_pattern" || true)
}
set -e # break on error
@ -111,6 +147,10 @@ fi
export PATH=$PATH:$RISCV/bin:/usr/bin
export PKG_CONFIG_PATH=$RISCV/lib64/pkgconfig:$RISCV/lib/pkgconfig:$RISCV/share/pkgconfig:$RISCV/lib/x86_64-linux-gnu/pkgconfig:$PKG_CONFIG_PATH
if (( RHEL_VERSION != 8 )); then
retry_on_host_error="--retry-on-host-error"
fi
# Check for incompatible PATH environment variable before proceeding with installation
if [[ ":$PATH:" == *::* || ":$PATH:" == *:.:* ]]; then
echo -e "${FAIL_COLOR}Error: You seem to have the current working directory in your \$PATH environment variable."
@ -191,11 +231,13 @@ if (( RHEL_VERSION == 8 )) || (( UBUNTU_VERSION == 20 )); then
section_header "Installing glib"
pip install -U meson # Meson is needed to build glib
cd "$RISCV"
curl --location https://download.gnome.org/sources/glib/2.70/glib-2.70.5.tar.xz | tar xJ
wget -nv --retry-connrefused $retry_on_host_error https://download.gnome.org/sources/glib/2.70/glib-2.70.5.tar.xz
tar -xJf glib-2.70.5.tar.xz
rm -f glib-2.70.5.tar.xz
cd glib-2.70.5
meson setup _build --prefix="$RISCV"
meson compile -C _build
meson install -C _build
meson compile -C _build -j "${NUM_THREADS}" 2>&1 | logger $STATUS; [ "${PIPESTATUS[0]}" == 0 ]
meson install -C _build 2>&1 | logger $STATUS; [ "${PIPESTATUS[0]}" == 0 ]
cd "$RISCV"
rm -rf glib-2.70.5
echo -e "${SUCCESS_COLOR}glib successfully installed!${ENDC}"
@ -208,11 +250,13 @@ if (( RHEL_VERSION == 8 )); then
if [ ! -e "$RISCV"/include/gmp.h ]; then
section_header "Installing gmp"
cd "$RISCV"
curl --location https://ftp.gnu.org/gnu/gmp/gmp-6.3.0.tar.xz | tar xJ
wget -nv --retry-connrefused $retry_on_host_error https://ftp.gnu.org/gnu/gmp/gmp-6.3.0.tar.xz
tar -xJf gmp-6.3.0.tar.xz
rm -f gmp-6.3.0.tar.xz
cd gmp-6.3.0
./configure --prefix="$RISCV"
make -j "${NUM_THREADS}"
make install
make -j "${NUM_THREADS}" 2>&1 | logger $STATUS; [ "${PIPESTATUS[0]}" == 0 ]
make install 2>&1 | logger $STATUS; [ "${PIPESTATUS[0]}" == 0 ]
cd "$RISCV"
rm -rf gmp-6.3.0
echo -e "${SUCCESS_COLOR}gmp successfully installed!${ENDC}"
@ -231,7 +275,7 @@ STATUS="riscv-gnu-toolchain"
cd "$RISCV"
# Temporarily pin riscv-gnu-toolchain to use GCC 13.2.0. GCC 14 does not work with the Q extension.
if git_check "riscv-gnu-toolchain" "https://github.com/riscv/riscv-gnu-toolchain" "$RISCV/riscv-gnu-toolchain/stamps/build-gcc-newlib-stage2"; then
cd riscv-gnu-toolchain
cd "$RISCV"/riscv-gnu-toolchain
git reset --hard && git clean -f && git checkout master && git pull
./configure --prefix="${RISCV}" --with-multilib-generator="rv32e-ilp32e--;rv32i-ilp32--;rv32im-ilp32--;rv32iac-ilp32--;rv32imac-ilp32--;rv32imafc-ilp32f--;rv32imafdc-ilp32d--;rv64i-lp64--;rv64ic-lp64--;rv64iac-lp64--;rv64imac-lp64--;rv64imafdc-lp64d--;rv64im-lp64--;"
make -j "${NUM_THREADS}" 2>&1 | logger $STATUS; [ "${PIPESTATUS[0]}" == 0 ]
@ -257,7 +301,7 @@ STATUS="elf2hex"
cd "$RISCV"
export PATH=$RISCV/bin:$PATH
if git_check "elf2hex" "https://github.com/sifive/elf2hex.git" "$RISCV/bin/riscv64-unknown-elf-elf2bin"; then
cd elf2hex
cd "$RISCV"/elf2hex
git reset --hard && git clean -f && git checkout master && git pull
autoreconf -i
./configure --target=riscv64-unknown-elf --prefix="$RISCV"
@ -279,7 +323,7 @@ section_header "Installing/Updating QEMU"
STATUS="qemu"
cd "$RISCV"
if git_check "qemu" "https://github.com/qemu/qemu" "$RISCV/include/qemu-plugin.h"; then
cd qemu
cd "$RISCV"/qemu
git reset --hard && git clean -f && git checkout master && git pull --recurse-submodules -j "${NUM_THREADS}"
git submodule update --init --recursive
./configure --target-list=riscv64-softmmu --prefix="$RISCV"
@ -301,7 +345,7 @@ section_header "Installing/Updating SPIKE"
STATUS="spike"
cd "$RISCV"
if git_check "riscv-isa-sim" "https://github.com/riscv-software-src/riscv-isa-sim" "$RISCV/lib/pkgconfig/riscv-riscv.pc"; then
cd riscv-isa-sim
cd "$RISCV"/riscv-isa-sim
git reset --hard && git clean -f && git checkout master && git pull
mkdir -p build
cd build
@ -327,7 +371,7 @@ STATUS="verilator"
cd "$RISCV"
if git_check "verilator" "https://github.com/verilator/verilator" "$RISCV/share/pkgconfig/verilator.pc"; then
unset VERILATOR_ROOT
cd verilator
cd "$RISCV"/verilator
git reset --hard && git clean -f && git checkout master && git pull
autoconf
./configure --prefix="$RISCV"
@ -352,7 +396,9 @@ section_header "Installing/Updating Sail Compiler"
STATUS="Sail Compiler"
if [ ! -e "$RISCV"/bin/sail ]; then
cd "$RISCV"
curl --location https://github.com/rems-project/sail/releases/latest/download/sail.tar.gz | tar xvz --directory="$RISCV" --strip-components=1
wget -nv --retry-connrefused $retry_on_host_error --output-document=sail.tar.gz https://github.com/rems-project/sail/releases/latest/download/sail.tar.gz
tar xz --directory="$RISCV" --strip-components=1 -f sail.tar.gz
rm -f sail.tar.gz
echo -e "${SUCCESS_COLOR}Sail Compiler successfully installed/updated!${ENDC}"
else
echo -e "${SUCCESS_COLOR}Sail Compiler already installed.${ENDC}"
@ -363,7 +409,7 @@ fi
section_header "Installing/Updating RISC-V Sail Model"
STATUS="riscv-sail-model"
if git_check "sail-riscv" "https://github.com/riscv/sail-riscv.git" "$RISCV/bin/riscv_sim_RV32"; then
cd sail-riscv
cd "$RISCV"/sail-riscv
git reset --hard && git clean -f && git checkout master && git pull
ARCH=RV64 make -j "${NUM_THREADS}" c_emulator/riscv_sim_RV64 2>&1 | logger $STATUS; [ "${PIPESTATUS[0]}" == 0 ]
ARCH=RV32 make -j "${NUM_THREADS}" c_emulator/riscv_sim_RV32 2>&1 | logger $STATUS; [ "${PIPESTATUS[0]}" == 0 ]
@ -386,7 +432,7 @@ STATUS="OSU Skywater 130 cell library"
mkdir -p "$RISCV"/cad/lib
cd "$RISCV"/cad/lib
if git_check "sky130_osu_sc_t12" "https://foss-eda-tools.googlesource.com/skywater-pdk/libs/sky130_osu_sc_t12" "$RISCV/cad/lib/sky130_osu_sc_t12" "main"; then
cd sky130_osu_sc_t12
cd "$RISCV"/sky130_osu_sc_t12
git reset --hard && git clean -f && git checkout main && git pull
echo -e "${SUCCESS_COLOR}OSU Skywater library successfully installed!${ENDC}"
else
@ -428,8 +474,8 @@ section_header "Downloading Site Setup Script"
STATUS="site-setup scripts"
cd "$RISCV"
if [ ! -e "${RISCV}"/site-setup.sh ]; then
wget https://raw.githubusercontent.com/openhwgroup/cvw/main/site-setup.sh
wget https://raw.githubusercontent.com/openhwgroup/cvw/main/site-setup.csh
wget -nv --retry-connrefused $retry_on_host_error https://raw.githubusercontent.com/openhwgroup/cvw/main/site-setup.sh
wget -nv --retry-connrefused $retry_on_host_error https://raw.githubusercontent.com/openhwgroup/cvw/main/site-setup.csh
echo -e "${SUCCESS_COLOR}Site setup script successfully downloaded!${ENDC}"
echo -e "${WARNING_COLOR}Make sure to edit the environment variables in $RISCV/site-setup.sh (or .csh) to point to your installation of EDA tools and licensce files.${ENDC}"
else

View file

@ -91,6 +91,7 @@ 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"
# 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

@ -5,12 +5,20 @@
// This file is needed in the config subdirectory for each config supporting coverage.
// It defines which extensions are enabled for that config.
// Unprivileged extensions
`include "RV32I_coverage.svh"
`include "RV32M_coverage.svh"
`include "RV32F_coverage.svh"
`include "RV32D_coverage.svh"
`include "RV32ZfhD_coverage.svh"
`include "RV32Zfh_coverage.svh"
`include "RV32Zicond_coverage.svh"
`include "RV32Zca_coverage.svh"
`include "RV32Zcb_coverage.svh"
`include "RV32ZcbM_coverage.svh"
`include "RV32ZcbZbb_coverage.svh"
`include "RV32Zcf_coverage.svh"
`include "RV32Zcd_coverage.svh"
// Privileged extensions
`include "ZicsrM_coverage.svh"

View file

@ -59,6 +59,28 @@
#--override cpu/instret_undefined=T
#--override cpu/hpmcounter_undefined=T
## context registers not implemented
#--override cpu/scontext_undefined=True
#--override cpu/mcontext_undefined=True
# Disable all features that might want mseccfg or CSRs 7a0-7af
--override cpu/Smepmp_version=none
--override cpu/Smmpm=none
#--override cpu/Zicfilp=F
--override cpu/trigger_num=0 # disable CSRs 7a0-7a8
--override no_pseudo_inst=T # For code coverage, don't produce pseudoinstructions
# mcause and scause only have 4 lsbs of code and 1 msb of interrupt flag
#--override cpu/ecode_mask=0x8000000F # for RV32
--override cpu/ecode_mask=0x800000000000000F # for RV64
# Debug mode not yet supported
--override cpu/debug_mode=none
--override cpu/reset_address=0x80000000
--override cpu/unaligned=F # Zicclsm (should be true)

View file

@ -5,18 +5,25 @@
// This file is needed in the config subdirectory for each config supporting coverage.
// It defines which extensions are enabled for that config.
// Unprivileged extensions
`include "RV64I_coverage.svh"
`include "RV64M_coverage.svh"
`include "RV64F_coverage.svh"
`include "RV64D_coverage.svh"
`include "RV64ZfhD_coverage.svh"
`include "RV64Zfh_coverage.svh"
`include "RV64VM_coverage.svh"
`include "RV64VM_PMP_coverage.svh"
`include "RV64CBO_VM_coverage.svh"
`include "RV64CBO_PMP_coverage.svh"
`include "RV64Zicbom_coverage.svh"
`include "RV64Zicond_coverage.svh"
`include "RV64Zca_coverage.svh"
`include "RV64Zcb_coverage.svh"
`include "RV64ZcbM_coverage.svh"
`include "RV64ZcbZbb_coverage.svh"
`include "RV64ZcbZba_coverage.svh"
`include "RV64Zcd_coverage.svh"
// Privileged extensions
`include "RV64VM_coverage.svh"
`include "ZicsrM_coverage.svh"
// `include "RV64VM_PMP_coverage.svh"
// `include "RV64CBO_VM_coverage.svh"
// `include "RV64CBO_PMP_coverage.svh"
// `include "RV64Zicbom_coverage.svh"

View file

@ -57,15 +57,32 @@
#--override cpu/instret_undefined=T
#--override cpu/hpmcounter_undefined=T
--override cpu/scontext_undefined=T
--override cpu/mcontext_undefined=T
# context registers not implemented
#--override cpu/scontext_undefined=True
#--override cpu/mcontext_undefined=True
# Disable all features that might want mseccfg or CSRs 7a0-7af
--override cpu/Smepmp_version=none
--override cpu/Smmpm=none
#--override cpu/Zicfilp=F
--override cpu/trigger_num=0 # disable CSRs 7a0-7a8
# For code coverage, don't produce pseudoinstructions
--override no_pseudo_inst=T
# nonratified mnosie register not implemented
--override cpu/mnoise_undefined=T
# *** how to override other undefined registers: seed, mphmevent, mseccfg, debugger registers
#--override cpu/seed_undefined=T
#--override mhpmevent3_undefined=T
#--override cpu/mseccfg_undefined=T
#--override cpu/tselect_undefined=T
#--override cpu/tdata1_undefined=T
# mcause and scause only have 4 lsbs of code and 1 msb of interrupt flag
#--override cpu/ecode_mask=0x8000000F # for RV32
--override cpu/ecode_mask=0x800000000000000F # for RV64
# Debug mode not yet supported
--override cpu/debug_mode=none
# Zkr entropy source and seed register not supported.
--override cpu/Zkr=F
--override cpu/reset_address=0x80000000

View file

@ -27,9 +27,16 @@ BINARIES := fw_jump.elf vmlinux busybox
OBJDUMPS := $(foreach name, $(BINARIES), $(basename $(name) .elf))
OBJDUMPS := $(foreach name, $(OBJDUMPS), $(DIS)/$(name).objdump)
.PHONY: all generate disassemble install clean cleanDTB cleanDriver check_write_permissions
.PHONY: all generate disassemble install clean cleanDTB check_write_permissions check_environment
all: check_write_permissions clean download Image disassemble install dumptvs
all: check_environment check_write_permissions clean download Image disassemble install dumptvs
check_environment: $(RISCV)
ifeq ($(findstring :$(RISCV)/lib:,:$(LD_LIBRARY_PATH):),)
@(echo "ERROR: Your environment variables are not set correctly." >&2 \
&& echo "Make sure to source setup.sh or install buildroot using the wally-tool-chain-install.sh script." >&2 \
&& exit 1)
endif
check_write_permissions:
ifeq ($(SUDO), sudo)
@ -41,17 +48,17 @@ endif
&& exit 1)
@$(SUDO) rm -r $(RISCV)/.test
Image:
Image: check_environment
bash -c "unset LD_LIBRARY_PATH; $(MAKE) -C $(BUILDROOT)"
$(MAKE) generate
@echo "Buildroot Image successfully generated."
install: check_write_permissions
install: check_write_permissions check_environment
$(SUDO) rm -rf $(RISCV)/$(BUILDROOT)
$(SUDO) mv $(BUILDROOT) $(RISCV)/$(BUILDROOT)
@echo "Buildroot successfully installed."
dumptvs: check_write_permissions
dumptvs: check_write_permissions check_environment
$(SUDO) mkdir -p $(RISCV)/linux-testvectors
cd testvector-generation; ./genInitMem.sh
@echo "Testvectors successfully generated."
@ -70,7 +77,7 @@ $(RISCV):
@ echo "and sourced setup.sh"
# Disassembly rules ---------------------------------------------------
disassemble:
disassemble: check_environment
rm -rf $(BUILDROOT)/output/images/disassembly
find $(BUILDROOT)/output/build/linux-* -maxdepth 1 -name "vmlinux" | xargs cp -t $(BUILDROOT)/output/images/
mkdir -p $(DIS)
@ -114,9 +121,6 @@ $(BUILDROOT):
# ---------------------------------------------------------------------
cleanDriver:
rm -f $(DRIVER)
cleanDTB:
rm -f $(IMAGES)/*.dtb

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}/common"
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 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

@ -8,7 +8,6 @@
// See RISC-V Privileged Mode Specification 20190608 3.1.10-11
//
// Documentation: RISC-V System on Chip Design
// MHPMEVENT is not supported
//
// A component of the CORE-V-WALLY configurable RISC-V project.
// https://github.com/openhwgroup/cvw
@ -66,7 +65,8 @@ module csrc import cvw::*; #(parameter cvw_t P) (
localparam MTIME = 12'hB01; // this is a memory-mapped register; no such CSR exists, and access should faul;
localparam MHPMCOUNTERHBASE = 12'hB80;
localparam MTIMEH = 12'hB81; // this is a memory-mapped register; no such CSR exists, and access should fault
localparam MHPMEVENTBASE = 12'h320;
localparam MHPMEVENTBASE = 12'h323;
localparam MHPMEVENTLAST = 12'h33F;
localparam HPMCOUNTERBASE = 12'hC00;
localparam HPMCOUNTERHBASE = 12'hC80;
localparam TIME = 12'hC01;
@ -156,6 +156,9 @@ module csrc import cvw::*; #(parameter cvw_t P) (
if (PrivilegeModeW == P.M_MODE |
MCOUNTEREN_REGW[CounterNumM] & (!P.S_SUPPORTED | PrivilegeModeW == P.S_MODE | SCOUNTEREN_REGW[CounterNumM])) begin
IllegalCSRCAccessM = 1'b0;
if (CSRAdrM >= MHPMEVENTBASE & CSRAdrM <= MHPMEVENTLAST) begin
CSRCReadValM = '0; // mphmevent[3:31] tied to read-only zero
end else begin
if (P.XLEN==64) begin // 64-bit counter reads
// Veri lator doesn't realize this only occurs for XLEN=64
/* verilator lint_off WIDTH */
@ -188,6 +191,7 @@ module csrc import cvw::*; #(parameter cvw_t P) (
IllegalCSRCAccessM = 1'b1; // requested CSR doesn't exist
end
end
end
end else begin
CSRCReadValM = '0;
IllegalCSRCAccessM = 1'b1; // no privileges for this csr

View file

@ -128,10 +128,13 @@ module csrs import cvw::*; #(parameter cvw_t P) (
else
assign STimerInt = 1'b0;
logic [1:0] LegalizedCBIE;
assign LegalizedCBIE = CSRWriteValM[5:4] == 2'b10 ? SENVCFG_REGW[5:4] : CSRWriteValM[5:4]; // Assume WARL for reserved CBIE = 10, keeps old value
assign SENVCFG_WriteValM = {
{(P.XLEN-8){1'b0}},
CSRWriteValM[7] & P.ZICBOZ_SUPPORTED,
CSRWriteValM[6:4] & {3{P.ZICBOM_SUPPORTED}},
CSRWriteValM[6] & P.ZICBOM_SUPPORTED,
LegalizedCBIE & {2{P.ZICBOM_SUPPORTED}},
3'b0,
CSRWriteValM[0] & P.VIRTMEM_SUPPORTED
};

View file

@ -234,9 +234,9 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
// 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
// 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 ? PCLK : (DivCounter == SckDiv);
assign SCLKenable = ZeroDiv ? 1 : (DivCounter == SckDiv);
assign SCLKenableEarly = ((DivCounter + 12'b1) == SckDiv);
always_ff @(posedge PCLK)
if (~PRESETn) DivCounter <= '0;

View file

@ -0,0 +1,348 @@
///////////////////////////////////////////
// spi_controller.sv
//
// Written: jacobpease@protonmail.com
// Created: October 28th, 2024
// Modified:
//
// Purpose: Controller logic for SPI
//
// Documentation: RISC-V System on Chip Design
//
// 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.
////////////////////////////////////////////////////////////////////////////////////////////////
module spi_controller (
input logic PCLK,
input logic PRESETn,
input logic TransmitStart,
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
);
// CSMode Stuff
localparam HOLDMODE = 2'b10;
localparam AUTOMODE = 2'b00;
localparam OFFMODE = 2'b11;
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!
// Shift and Sample Edges
logic PreShiftEdge;
logic PreSampleEdge;
logic ShiftEdge;
logic SampleEdge;
// Frame stuff
logic [2: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;
// Delay Stuff
logic [7:0] cssck;
logic [7:0] sckcs;
logic [7:0] intercs;
logic [7:0] interxfr;
logic HasCSSCK;
logic HasSCKCS;
logic HasINTERCS;
logic HasINTERXFR;
logic EndOfCSSCK;
logic EndOfSCKCS;
logic EndOfINTERCS;
logic EndOfINTERXFR;
logic [7:0] CSSCKCounter;
logic [7:0] SCKCSCounter;
logic [7:0] INTERCSCounter;
logic [7:0] INTERXFRCounter;
logic DelayIsNext;
// Convenient Delay Reg Names
assign cssck = Delay0[7:0];
assign sckcs = Delay0[15:8];
assign intercs = Delay1[7:0];
assign interxfr = Delay1[15:8];
// Do we have delay for anything?
assign HasCSSCK = cssck > 8'b0;
assign HasSCKCS = sckcs > 8'b0;
assign HasINTERCS = intercs > 8'b0;
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;
// 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;
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;
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;
end else begin
// TODO: Consolidate into one delay counter since none of the
// delays happen at the same time?
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;
end
// SPICLK Logic
if (TransmitStart) begin
SPICLK <= SckMode[1];
end else if (SCLKenable & Transmitting) begin
SPICLK <= (~EndTransmission & ~DelayIsNext) ? ~SPICLK : SckMode[1];
end
// Reset divider
if (SCLKenable | TransmitStart) 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;
end
// Increment BitNum
if (ShiftEdge & Transmitting) begin
BitNum <= BitNum + 3'd1;
end else if (EndOfFrameDelay) begin
BitNum <= 3'b0;
end
end
end
// Delay ShiftEdge and SampleEdge by a half PCLK period
// Aligned EXACTLY ON THE MIDDLE of the leading and trailing edges.
// Sweeeeeeeeeet...
always_ff @(posedge ~PCLK) begin
if (~PRESETn | TransmitStart) begin
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;
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);
always_ff @(posedge PCLK) begin
if (~PRESETn) begin
CurrState <= INACTIVE;
end else if (SCLKenable) begin
CurrState <= NextState;
end
end
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
TRANSMIT: begin // TRANSMIT case --------------------------------
case(CSMode)
AUTOMODE: begin
if (EndTransmission) begin
NextState = INACTIVE;
end else if (ContinueTransmit) begin
NextState = SCKCS;
end
end
HOLDMODE: begin
if (EndTransmission) begin
NextState = HOLD;
end else if (ContinueTransmit) begin
if (HasINTERXFR) NextState = INTERXFR;
end
end
OFFMODE: begin
end
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 (HasINTERCS) NextState = INTERCS;
else NextState = TRANSMIT;
end
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.
NextState = TRANSMIT;
end
end
INTERCS: begin // INTERCS case ----------------------------------
if (EndOfINTERCS) begin
if (HasCSSCK) NextState = CSSCK;
else NextState = TRANSMIT;
end
end
INTERXFR: begin // INTERXFR case --------------------------------
if (EndOfINTERXFR) begin
NextState = TRANSMIT;
end
end
default: begin
NextState = INACTIVE;
end
endcase
end
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;
endmodule

View file

@ -540,7 +540,6 @@ module testbench;
always @(posedge clk) begin
if (LoadMem) begin
$readmemh(memfilename, dut.core.lsu.dtim.dtim.ram.ram.RAM);
$display("Read memfile %s", memfilename);
end
if (CopyRAM) begin
LogXLEN = (1 + P.XLEN/32); // 2 for rv32 and 3 for rv64

View file

@ -28,6 +28,12 @@
// The PMP tests are sensitive to the exact addresses in this code, so unfortunately
// modifying anything breaks those tests.
// Provides simple firmware services through ecall. Place argument in a0 and issue ecall:
// 0: change to user mode
// 1: change to supervisor mode
// 3: change to machine mode
// 4: terminate program
.section .text.init
.global rvtest_entry_point

View file

@ -32,59 +32,59 @@
00000003
00000074
00000074 # spi_burst_send
00000063
00000063 # spi_burst_send
00000052
00000052 # spi_burst_send
00000041
00000041 # spi_burst_send
000000A1
000000A1 # spi_burst_send
00000003
000000B2
000000B2 # spi_burst_send
00000001
000000C3
000000C3 # spi_burst_send
000000D4
000000D4 # spi_burst_send
00000003
000000A4
000000A4 # tx_data write test
00000001
000000B4
000000B4 # tx_data write test
000000A5
000000A5 # spi_burst_send
000000B5
000000B5 # spi_burst_send
000000C5
000000C5 # spi_burst_send
000000D5
000000D5 # spi_burst_send
000000A7
000000A7 # spi_burst_send
000000B7
000000B7 # spi_burst_send
000000C7
000000C7 # spi_burst_send
00000002
000000D7
000000D7 # spi_burst_send
00000000
00000011 #basic read write
000000FF
000000FF # first test sck_div
000000AE
000000AE # min sck_div first spi_burst_send
000000AD