Skip to content

Commit

Permalink
Merge pull request #343 from zapta/develop
Browse files Browse the repository at this point in the history
Changed the behavior of the sim command to require --testbench flag if more than once benchmark is found.
  • Loading branch information
Obijuan authored Feb 21, 2024
2 parents 3d3f214 + ffb9ff3 commit 5a20b52
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 131 deletions.
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])

0 comments on commit 5a20b52

Please sign in to comment.