mirror of
https://github.com/openhwgroup/cvw.git
synced 2025-06-28 09:36:01 -04:00
Merge branch 'openhwgroup:main' into main
This commit is contained in:
commit
c93cadc95c
19 changed files with 644 additions and 151 deletions
7
.github/workflows/install.yml
vendored
7
.github/workflows/install.yml
vendored
|
@ -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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||

|
||||

|
||||
|
||||
# core-v-wally
|
||||
|
||||
|
|
|
@ -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 #
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
1
bin/wsim
1
bin/wsim
|
@ -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
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
348
src/uncore/spi_controller.sv
Normal file
348
src/uncore/spi_controller.sv
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue