adding support for top-module parameter replacement during synthesis tests

This commit is contained in:
Blaise Tine 2024-02-10 21:54:35 -08:00
parent b8ccff7ade
commit 9e54ccde6d
3 changed files with 135 additions and 21 deletions

View file

@ -18,45 +18,56 @@ includes=()
externs=()
output_file=""
global_file=""
define_header=""
top_module=""
copy_folder=""
prepropressor=0
defines_str=""
params_str=""
includes_str=""
script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
# parse command arguments
while getopts D:I:J:O:G:C:Ph flag
while getopts D:G:T:I:J:O:H:C:Ph flag
do
case "${flag}" in
D) defines+=( ${OPTARG} )
defines_str+="-D${OPTARG} "
;;
G) params_str+="-G${OPTARG} "
;;
T) top_module=( ${OPTARG} )
;;
I) includes+=( ${OPTARG} )
includes_str+="-I${OPTARG} "
;;
J) externs+=( ${OPTARG} )
includes_str+="-I${OPTARG} "
;;
O) output_file=( ${OPTARG} );;
G) global_file=( ${OPTARG} );;
C) copy_folder=( ${OPTARG} );;
P) prepropressor=1;;
h) echo "Usage: [-D<macro>] [-I<include-path>] [-J<external-path>] [-O<output-file>] [-C<dest-folder>: copy to] [-G<global_header>] [-P: macro prepropressing] [-h help]"
O) output_file=( ${OPTARG} )
;;
H) define_header=( ${OPTARG} )
;;
C) copy_folder=( ${OPTARG} )
;;
P) prepropressor=1
;;
h) echo "Usage: [-D<macro>] [-G<param>=<value>] [-T<top-module>] [-I<include-path>] [-J<external-path>] [-O<output-file>] [-C<dest-folder>: copy to] [-H<define_header>] [-P: macro prepropressing] [-h help]"
exit 0
;;
\?)
echo "Invalid option: -$OPTARG" 1>&2
exit 1
;;
;;
\?) echo "Invalid option: -$OPTARG" 1>&2
exit 1
;;
esac
done
if [ "$global_file" != "" ]; then
directory=$(dirname "$global_file")
if [ "$define_header" != "" ]; then
directory=$(dirname "$define_header")
mkdir -p "$directory"
{
# dump defines into a global header
# dump defines into a header file
for value in ${defines[@]}; do
arrNV=(${value//=/ })
if (( ${#arrNV[@]} > 1 ));
@ -66,7 +77,7 @@ if [ "$global_file" != "" ]; then
echo "\`define $value"
fi
done
} > $global_file
} > $define_header
fi
if [ "$copy_folder" != "" ]; then
@ -74,9 +85,16 @@ if [ "$copy_folder" != "" ]; then
mkdir -p $copy_folder
for dir in ${includes[@]}; do
find "$dir" -maxdepth 1 -type f | while read -r file; do
ext="${file##*.}"
if [ $prepropressor != 0 ] && { [ "$ext" == "v" ] || [ "$ext" == "sv" ]; }; then
verilator $defines_str $includes_str -E -P $file > $copy_folder/$(basename -- $file)
file_ext="${file##*.}"
file_name=$(basename -- $file)
if [ $prepropressor != 0 ] && { [ "$file_ext" == "v" ] || [ "$file_ext" == "sv" ]; }; then
if [[ -n "$params_str" && $file_name == "$top_module."* ]]; then
temp_file=$(mktemp)
$script_dir/repl_params.py $params_str -T$top_module $file > $temp_file
verilator $defines_str $includes_str -E -P $temp_file > $copy_folder/$file_name
else
verilator $defines_str $includes_str -E -P $file > $copy_folder/$file_name
fi
else
cp $file $copy_folder
fi
@ -86,7 +104,7 @@ fi
if [ "$output_file" != "" ]; then
{
if [ "$global_file" == "" ]; then
if [ "$define_header" == "" ]; then
# dump defines
for value in ${defines[@]}; do
echo "+define+$value"

96
hw/scripts/repl_params.py Executable file
View file

@ -0,0 +1,96 @@
#!/usr/bin/env python3
# Copyright © 2019-2023
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# 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.
import re
import sys
def read_file_contents(filename):
with open(filename, 'r') as file:
return file.read()
def write_to_console(output):
print(output, end='')
def check_module_and_parameter_existence(file_content, top_module, params):
# Check if the module exists
module_exists_pattern = re.compile(rf'\bmodule\s+{top_module}\b', re.DOTALL)
if not re.search(module_exists_pattern, file_content):
print(f"Error: Top module '{top_module}' not found in file '{filename}'.")
sys.exit(1)
# Check if parameters exist
for param in params.keys():
param_exists_pattern = re.compile(rf'\bparameter\s+((?:\[\s*\d*\s*:\s*\d*\s*\]\s*)?(\w+\s+)?){param}\s*(\[\s*\])?\s*=', re.DOTALL)
if not re.search(param_exists_pattern, file_content):
print(f"Error: Parameter '{param}' not found in module '{top_module}'.")
sys.exit(1)
def replace_parameter(file_content, top_module, param, value):
# Define a pattern to locate the specified top module's parameter section
module_header_pattern = re.compile(rf'(module\s+{top_module}\s*.*?\(\s*)(.*?)(\)\s*;)', re.DOTALL)
param_declaration_pattern = re.compile(rf'(\bparameter\b\s+(?:\w+\s+)?{param}\s*=\s*)([^,;]+)', re.DOTALL)
def parameter_replacer(match):
before_params, params_section, after_params = match.groups()
# Check if the specific parameter is found within the parameter section
if re.search(param_declaration_pattern, params_section):
# Replace the parameter value, avoiding f-string for backreference
new_params_section = re.sub(param_declaration_pattern, lambda m: m.group(1) + value, params_section)
return f'{before_params}{new_params_section}{after_params}'
else:
return match.group(0) # Return original content if parameter not found
# Apply the replacement within the specified top module
modified_content, num_replacements = re.subn(module_header_pattern, parameter_replacer, file_content)
if num_replacements == 0:
print(f"Warning: Top module '{top_module}' or parameter '{param}' not found. No replacement made.")
return modified_content
def main():
args = sys.argv[1:]
filename = ''
top_module = ''
params = {}
for i, arg in enumerate(args):
if arg.startswith('-G'):
param, value = arg[2:].split('=')
params[param] = value
elif arg.startswith('-T'):
top_module = arg[2:]
else:
filename = arg
if not top_module:
print("Error: Top module not specified.")
sys.exit(1)
if not filename:
print("Error: Verilog file name not specified.")
sys.exit(1)
file_content = read_file_contents(filename)
check_module_and_parameter_existence(file_content, top_module, params)
for param, value in params.items():
file_content = replace_parameter(file_content, top_module, param, value)
write_to_console(file_content)
if __name__ == "__main__":
main()

View file

@ -34,7 +34,7 @@ all: gen-sources $(PROJECT).sta.rpt $(PROJECT).pow.rpt
gen-sources: src
src:
mkdir -p src
$(SCRIPT_DIR)/gen_sources.sh $(CONFIGS) $(RTL_INCLUDE) -P -Csrc
$(SCRIPT_DIR)/gen_sources.sh $(CONFIGS) $(RTL_INCLUDE) -T$(TOP_LEVEL_ENTITY) -P -Csrc
syn: $(PROJECT).syn.rpt