Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changed the behavior of the sim command to require --testbench flag if more than once benchmark is found. #343

Merged
merged 1 commit into from
Feb 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions apio/managers/arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,9 @@ def process_arguments(
"fpga_pack": config[PACK],
"fpga_idcode": config[IDCODE],
"verbose_all": config[VERBOSE][ALL],
"verbose_yosys": config[VERBOSE][YOSYS],
"verbose_pnr": config[VERBOSE][PNR],
# These two flags appear only in some of the commands.
"verbose_yosys": config[VERBOSE][YOSYS] if YOSYS in config[VERBOSE] else False,
"verbose_pnr": config[VERBOSE][PNR] if PNR in config[VERBOSE] else False,
"top_module": config[TOP_MODULE],
"testbench": config[TESTBENCH],
}
Expand Down Expand Up @@ -336,8 +337,11 @@ def print_configuration(config: dict) -> None:
print(f" testbench: {config[TESTBENCH]}")
print(" verbose:")
print(f" all: {config[VERBOSE][ALL]}")
print(f" yosys: {config[VERBOSE][YOSYS]}")
print(f" pnr: {config[VERBOSE][PNR]}")
# These two flags appear only in some of the commands.
if YOSYS in config[VERBOSE]:
print(f" yosys: {config[VERBOSE][YOSYS]}")
if PNR in config[VERBOSE]:
print(f" pnr: {config[VERBOSE][PNR]}")
print()


Expand Down
8 changes: 2 additions & 6 deletions apio/managers/scons.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,8 @@ def __init__(self, project_dir=""):
def clean(self, args):
"""DOC: TODO"""

try:
__, __, arch = process_arguments(args, self.resources)

# -- No architecture given: Uses ice40 as default
except Exception:
arch = "ice40"
# -- Split the arguments
__, __, arch = process_arguments(args, self.resources)

# --Clean the project: run scons -c (with aditional arguments)
return self.run("-c", arch=arch, variables=[], packages=[])
Expand Down
101 changes: 44 additions & 57 deletions apio/resources/ecp5/SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -107,59 +107,36 @@ list_scanner = env.Scanner(function=list_files_scan)
v_nodes = Glob('*.v')
v_files = [str(f) for f in v_nodes]

# Create lists of module and testbench files. Test benches are assumed
# to end with '_tb.v', case insensitive.
src_sim = [f for f in v_files if f[-5:].upper() != '_TB.V']
# Construct disjoint lists of .v module and testbench files.
src_synth = [f for f in v_files if f[-5:].upper() != '_TB.V']
list_tb = [f for f in v_files if f[-5:].upper() == '_TB.V']

# Handle the testbench selection, if any.
testbench = None

if TESTBENCH:
# Here when --testbench was specified.
testbench = TESTBENCH
else:
# Here when --testbench was not specified so we use the default behavior
# for backward compatibility. Currently we pick arbitrarily the first
# testbench in the Glob order.
if len(list_tb) > 1:
print('Warning: more than one testbench found.')
if len(list_tb) > 0:
testbench = list_tb[0]

# Add the testbench to the list of compiled files.
if testbench:
src_sim.append(testbench)

SIMULNAME = ''
TARGET_SIM = ''

# clean
if len(COMMAND_LINE_TARGETS) == 0:
if testbench is not None:
# -- Simulation name
SIMULNAME, ext = os.path.splitext(testbench)
# sim
elif 'sim' in COMMAND_LINE_TARGETS:
if testbench is None:
print('Error: no testbench found for simulation')
Exit(1)

# -- Simulation name
SIMULNAME, ext = os.path.splitext(testbench)

# -- Target sim name
if SIMULNAME:
TARGET_SIM = SIMULNAME # .replace('\\', '\\\\')

# -------- Get the synthesis files. They are ALL the files except the
# -------- testbench
src_synth = [f for f in src_sim if f not in list_tb]

if len(src_synth) == 0:
print('Error: no verilog files found (.v)')
print('Error: no verilog module files found (.v)')
Exit(1)

# If running the sim command, determine the testbench to simulate.
SIMULNAME = ''
if 'sim' in COMMAND_LINE_TARGETS:
if TESTBENCH:
testbench = TESTBENCH # Explicit from the --testbench flag.
else:
if len(list_tb) == 0:
print('Error: no testbench found for simulation.')
Exit(1)
if len(list_tb) > 1:
# TODO: consider to allow specifying the default testbench in apio.ini.
print('Error: found {} testbranches, please use the --testbench flag.'.format(len(list_tb)))
for tb in list_tb:
print('- {}'.format(tb))
Exit(1)
testbench = list_tb[0] # Pick the only available testbench.
# List of simulation files which Includes the testbench and all the module files.
src_sim = []
src_sim.extend(src_synth) # All the .v files.
src_sim.append(testbench)
SIMULNAME, _ = os.path.splitext(testbench)

# -- For debugging
# print('Testbench: {}'.format(testbench))
# print('SIM NAME: {}'.format(SIMULNAME))
Expand Down Expand Up @@ -228,7 +205,7 @@ AlwaysBuild(t)
# -- Icarus Verilog builders
iverilog = Builder(
action='iverilog {0} -o $TARGET -D VCD_OUTPUT={1} -D NO_INCLUDES "{2}/ecp5/cells_sim.v" $SOURCES'.format(
IVER_PATH, TARGET_SIM, YOSYS_PATH),
IVER_PATH, SIMULNAME, YOSYS_PATH),
suffix='.out',
src_suffix='.v',
source_scanner=list_scanner)
Expand All @@ -249,12 +226,14 @@ verify = env.Alias('verify', vout)
AlwaysBuild(verify)

# --- Simulation
sout = env.IVerilog(TARGET_SIM, src_sim)
vcd_file = env.VCD(sout)

waves = env.Alias('sim', vcd_file, 'gtkwave {0} {1}.gtkw'.format(
vcd_file[0], SIMULNAME))
AlwaysBuild(waves)
# Since the simulation targets are dynamic due to the testbench selection, we
# create them only when running simulation.
if 'sim' in COMMAND_LINE_TARGETS:
sout = env.IVerilog(SIMULNAME, src_sim)
vcd_file = env.VCD(sout)
waves = env.Alias('sim', vcd_file, 'gtkwave {0} {1}.gtkw'.format(
vcd_file[0], SIMULNAME))
AlwaysBuild(waves)

# -- Verilator builder
verilator = Builder(
Expand All @@ -277,6 +256,14 @@ AlwaysBuild(lint)

Default(bitstream)

# -- These is for cleaning the files generated using the alias targets
# -- These is for cleaning the artifact files.
if GetOption('clean'):
env.Default([t, vout, sout, vcd_file])
# Identify additional files that may not be associated with targets and
# associate them with a target such that they will be cleaned up as well.
# This cleans for example artifacts of past simulation since the testbench
# target are dynamic and changes with the selected testbench.
for glob_pattern in ['*.out', '*.vcd']:
for node in Glob(glob_pattern):
env.Clean(t, str(node))

env.Default([t, build, json_out, config_out])
105 changes: 41 additions & 64 deletions apio/resources/ice40/SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -105,59 +105,36 @@ list_scanner = env.Scanner(function=list_files_scan)
v_nodes = Glob('*.v')
v_files = [str(f) for f in v_nodes]

# Create lists of module and testbench files. Test benches are assumed
# to end with '_tb.v', case insensitive.
src_sim = [f for f in v_files if f[-5:].upper() != '_TB.V']
# Construct disjoint lists of .v module and testbench files.
src_synth = [f for f in v_files if f[-5:].upper() != '_TB.V']
list_tb = [f for f in v_files if f[-5:].upper() == '_TB.V']

# Handle the testbench selection, if any.
testbench = None

if TESTBENCH:
# Here when --testbench was specified.
testbench = TESTBENCH
else:
# Here when --testbench was not specified so we use the default behavior
# for backward compatibility. Currently we pick arbitrarily the first
# testbench in the Glob order.
if len(list_tb) > 1:
print('Warning: more than one testbench found.')
if len(list_tb) > 0:
testbench = list_tb[0]

# Add the testbench to the list of compiled files.
if testbench:
src_sim.append(testbench)

SIMULNAME = ''
TARGET_SIM = ''

# clean
if len(COMMAND_LINE_TARGETS) == 0:
if testbench is not None:
# -- Simulation name
SIMULNAME, ext = os.path.splitext(testbench)
# sim
elif 'sim' in COMMAND_LINE_TARGETS:
if testbench is None:
print('Error: no testbench found for simulation')
Exit(1)

# -- Simulation name
SIMULNAME, ext = os.path.splitext(testbench)

# -- Target sim name
if SIMULNAME:
TARGET_SIM = SIMULNAME # .replace('\\', '\\\\')

# -------- Get the synthesis files. They are ALL the files except the
# -------- testbench
src_synth = [f for f in src_sim if f not in list_tb]

if len(src_synth) == 0:
print('Error: no verilog files found (.v)')
print('Error: no verilog module files found (.v)')
Exit(1)

# If running the sim command, determine the testbench to simulate.
SIMULNAME = ''
if 'sim' in COMMAND_LINE_TARGETS:
if TESTBENCH:
testbench = TESTBENCH # Explicit from the --testbench flag.
else:
if len(list_tb) == 0:
print('Error: no testbench found for simulation.')
Exit(1)
if len(list_tb) > 1:
# TODO: consider to allow specifying the default testbench in apio.ini.
print('Error: found {} testbranches, please use the --testbench flag.'.format(len(list_tb)))
for tb in list_tb:
print('- {}'.format(tb))
Exit(1)
testbench = list_tb[0] # Pick the only available testbench.
# List of simulation files. Includes the testbench and all the .v files.
src_sim = []
src_sim.extend(src_synth) # All the .v files.
src_sim.append(testbench)
SIMULNAME, _ = os.path.splitext(testbench)

# -- For debugging
# print('Testbench: {}'.format(testbench))
# print('SIM NAME: {}'.format(SIMULNAME))
Expand Down Expand Up @@ -233,7 +210,7 @@ AlwaysBuild(t)
# -- Icarus Verilog builders
iverilog = Builder(
action='iverilog {0} -o $TARGET -D VCD_OUTPUT={1} -D NO_ICE40_DEFAULT_ASSIGNMENTS "{2}/ice40/cells_sim.v" $SOURCES'.format(
IVER_PATH, TARGET_SIM, YOSYS_PATH),
IVER_PATH, SIMULNAME, YOSYS_PATH),
suffix='.out',
src_suffix='.v',
source_scanner=list_scanner)
Expand All @@ -254,12 +231,14 @@ verify = env.Alias('verify', vout)
AlwaysBuild(verify)

# --- Simulation
sout = env.IVerilog(TARGET_SIM, src_sim)
vcd_file = env.VCD(sout)

waves = env.Alias('sim', vcd_file, 'gtkwave {0} {1}.gtkw'.format(
vcd_file[0], SIMULNAME))
AlwaysBuild(waves)
# Since the simulation targets are dynamic due to the testbench selection, we
# create them only when running simulation.
if 'sim' in COMMAND_LINE_TARGETS:
sout = env.IVerilog(SIMULNAME, src_sim)
vcd_file = env.VCD(sout)
waves = env.Alias('sim', vcd_file, 'gtkwave {0} {1}.gtkw'.format(
vcd_file[0], SIMULNAME))
AlwaysBuild(waves)

# -- Verilator builder
verilator = Builder(
Expand All @@ -283,14 +262,12 @@ Default(bitstream)

# -- These is for cleaning the artifact files.
if GetOption('clean'):
# Create a list of additional files that we want to clean up, regardless
# of the current dependencies. For example, artifacts of testbench
# simulations.
cleanup_nodes = []
# Identify additional files that may not be associated with targets and
# associate them with a target such that they will be cleaned up as well.
# This cleans for example artifacts of past simulation since the testbench
# target are dynamic and changes with the selected testbench.
for glob_pattern in ['*.out', '*.vcd']:
cleanup_nodes.extend(Glob(glob_pattern))
cleanup_files = [str(f) for f in cleanup_nodes]
cleanup_files.sort() # User report looks nicer with sorting (?)
for node in Glob(glob_pattern):
env.Clean(t, str(node))

env.Clean(t, cleanup_files)
env.Default([t, vout, sout, vcd_file])
env.Default([t, build, vout])