From 1fec290d645ab8c0788d20f5316f49b1724c4276 Mon Sep 17 00:00:00 2001 From: GCHQDeveloper560 <48131108+GCHQDeveloper560@users.noreply.github.com> Date: Wed, 7 Jul 2021 12:39:27 +0100 Subject: [PATCH 1/4] Fix failing tests with Pandas 1.3 The previous syntax for checking a column of identical values fails with Pandas 1.3. The new check works with 1.3 and older versions. --- tests/test_reporting.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_reporting.py b/tests/test_reporting.py index 05f515a32..21a1d3b02 100644 --- a/tests/test_reporting.py +++ b/tests/test_reporting.py @@ -293,7 +293,7 @@ def test_picorv32_ise_spartan6_resources(picorv32_s6_data): # Check Control Set Information table df = rpt["Control Set Information"] - assert df["Clock Signal"].all() == "clk_BUFGP" + assert (df["Clock Signal"] == "clk_BUFGP").all() assert df.shape == (20, 6) rst_en = df[ @@ -672,7 +672,7 @@ def test_linux_on_litex_vexriscv_pipistrello_resources( df = rpt["IOB Properties"].set_index("IOB Name") ddr_io = df.filter(regex="ddram_*", axis=0) - assert ddr_io["IO Standard"].all() == "MOBILE_DDR" + assert (ddr_io["IO Standard"] == "MOBILE_DDR").all() # Check Control Set Information table df = rpt["Control Set Information"] From a811a8c43b2c5928d8a7b2f598914c766be472d6 Mon Sep 17 00:00:00 2001 From: GCHQDeveloper560 <48131108+GCHQDeveloper560@users.noreply.github.com> Date: Wed, 30 Jun 2021 17:08:35 +0100 Subject: [PATCH 2/4] Initial attempt to support phony targets in command generator --- edalize/apicula.py | 2 +- edalize/edatool.py | 20 +++++++++++++++-- edalize/icestorm.py | 12 +++++----- edalize/nextpnr.py | 4 ++-- edalize/symbiflow.py | 22 +++++++++---------- edalize/trellis.py | 2 +- edalize/vivado.py | 14 ++++++------ edalize/yosys.py | 2 +- tests/test_apicula/Makefile | 2 ++ tests/test_apicula/minimal/Makefile | 2 ++ tests/test_icestorm/Makefile | 2 ++ tests/test_icestorm/minimal/Makefile | 2 ++ tests/test_icestorm/nextpnr/Makefile | 2 ++ .../nextpnr/fpga_interchange/Makefile | 2 ++ tests/test_symbiflow/nextpnr/xilinx/Makefile | 2 ++ tests/test_symbiflow/vtr/Makefile | 2 ++ tests/test_trellis/Makefile | 2 ++ tests/test_trellis/minimal/Makefile | 2 ++ tests/test_vivado/Makefile | 2 ++ tests/test_vivado/minimal/Makefile | 2 ++ tests/test_vivado/yosys/Makefile | 2 ++ 21 files changed, 73 insertions(+), 31 deletions(-) diff --git a/edalize/apicula.py b/edalize/apicula.py index b7fe54e7b..2cd9e7a54 100644 --- a/edalize/apicula.py +++ b/edalize/apicula.py @@ -62,7 +62,7 @@ def configure_main(self): depends = self.name+'.pack' targets = self.name+'.fs' command = ['gowin_pack', '-d', self.tool_options.get('device'), '-o', targets, depends] - commands.add(command, [targets], [depends]) + commands.add(command, [self.EdaCommands.Target(targets)], [depends]) commands.set_default_target(targets) commands.write(os.path.join(self.work_root, 'Makefile')) diff --git a/edalize/edatool.py b/edalize/edatool.py index 85fe5f6ee..2a1221600 100644 --- a/edalize/edatool.py +++ b/edalize/edatool.py @@ -236,6 +236,14 @@ def __init__(self, command, targets, depends): self.targets = targets self.depends = depends + class Target: + def __init__(self, target, phony=False): + self.target = target + self.phony = phony + + def __str__(self): + return str(self.target) + def __init__(self): self.commands = [] self.header = "#Auto generated by Edalize\n\n" @@ -254,15 +262,23 @@ def write(self, outfile): f.write(f"all: {self.default_target}\n") + phony_targets = ["all"] for c in self.commands: - f.write(f"\n{' '.join(c.targets)}:") + cmd_targets = [] + for t in c.targets: + cmd_targets.append(str(t)) + if t.phony: + phony_targets.append(str(t)) + f.write(f"\n{' '.join(cmd_targets)}:") for d in c.depends: - f.write(" "+d) + f.write(" "+str(d)) f.write("\n") if c.command: f.write(f"\t$(EDALIZE_LAUNCHER) {' '.join(c.command)}\n") + f.write(f"\n.PHONY: {' '.join(phony_targets)}\n") + def set_default_target(self, target): self.default_target = target diff --git a/edalize/icestorm.py b/edalize/icestorm.py index ad6e9ce4e..49aef7c8a 100644 --- a/edalize/icestorm.py +++ b/edalize/icestorm.py @@ -67,7 +67,7 @@ def configure_main(self): command = ['arachne-pnr'] command += self.tool_options.get('arachne_pnr_options', []) command += ['-p', depends, '-o', targets] - commands.add(command, [depends], [targets]) + commands.add(command, [self.EdaCommands.Target(depends)], [targets]) set_default_target(self.name+'.bin') elif pnr == 'next': nextpnr = Nextpnr(yosys.edam, self.work_root) @@ -82,20 +82,20 @@ def configure_main(self): depends = self.name+'.asc' targets = self.name+'.bin' command = ['icepack', depends, targets] - commands.add(command, [targets], [depends]) + commands.add(command, [self.EdaCommands.Target(targets)], [depends]) #Timing analysis depends = self.name+'.asc' targets = self.name+'.tim' command = ['icetime', '-tmd', part or '', depends, targets] - commands.add(command, [targets], [depends]) - commands.add([], ["timing"], [targets]) + commands.add(command, [self.EdaCommands.Target(targets)], [depends]) + commands.add([], [self.EdaCommands.Target("timing", phony=True)], [targets]) #Statistics depends = self.name+'.asc' targets = self.name+'.stat' command = ['icebox_stat', depends, targets] - commands.add(command, [targets], [depends]) - commands.add([], ["stats"], [targets]) + commands.add(command, [self.EdaCommands.Target(targets)], [depends]) + commands.add([], [self.EdaCommands.Target("stats", phony=True)], [targets]) commands.write(os.path.join(self.work_root, 'Makefile')) diff --git a/edalize/nextpnr.py b/edalize/nextpnr.py index cdfa35366..3435873f0 100644 --- a/edalize/nextpnr.py +++ b/edalize/nextpnr.py @@ -79,8 +79,8 @@ def configure_main(self): command += constraints + ['--json', depends] + output #CLI target - commands.add(command, [targets], [depends]) + commands.add(command, [self.EdaCommands.Target(targets)], [depends]) #GUI target - commands.add(command+['--gui'], ["build-gui"], [depends]) + commands.add(command+['--gui'], [self.EdaCommands.Target("build-gui", phony=True)], [depends]) self.commands = commands.commands diff --git a/edalize/symbiflow.py b/edalize/symbiflow.py index 5b255d02c..101e01e87 100644 --- a/edalize/symbiflow.py +++ b/edalize/symbiflow.py @@ -185,7 +185,7 @@ def configure_nextpnr(self): command += ['--device', device] command += ['--top', self.toplevel] command += [depends, targets] - commands.add(command, [targets], [depends]) + commands.add(command, [self.EdaCommands.Target(targets)], [depends]) depends = self.name+'.netlist' targets = self.name+'.phys' @@ -196,14 +196,14 @@ def configure_nextpnr(self): command += ['--write', self.name+'.routed.json'] command += ['--phys', targets] command += [nextpnr_options] - commands.add(command, [targets], [depends]) + commands.add(command, [self.EdaCommands.Target(targets)], [depends]) depends = self.name+'.phys' targets = self.name+'.fasm' command = ['python', '-m', 'fpga_interchange.fasm_generator'] command += ['--schema_dir', '$(INTERCHANGE_SCHEMA_PATH)'] command += ['--family', family, device, self.name+'.netlist', depends, targets] - commands.add(command, [targets], [depends]) + commands.add(command, [self.EdaCommands.Target(targets)], [depends]) else: targets = self.name+'.fasm' command = ['nextpnr-'+arch, '--chipdb', chipdb] @@ -213,13 +213,13 @@ def configure_nextpnr(self): command += ['--fasm', targets] command += ['--log', 'nextpnr.log'] command += [nextpnr_options] - commands.add(command, [targets], [depends]) + commands.add(command, [self.EdaCommands.Target(targets)], [depends]) depends = self.name+'.fasm' targets = self.name+'.bit' command = ['symbiflow_write_bitstream', '-d', bitstream_device] command += ['-f', depends, '-p', partname, '-b', targets] - commands.add(command, [targets], [depends]) + commands.add(command, [self.EdaCommands.Target(targets)], [depends]) commands.set_default_target(targets) commands.write(os.path.join(self.work_root, 'Makefile')) @@ -290,7 +290,7 @@ def configure_vpr(self): command += ['-d', bitstream_device] command += ['-p' if vendor == 'xilinx' else '-P', partname] command += xdc_opts - commands.add(command, [targets], []) + commands.add(command, [self.EdaCommands.Target(targets)], []) #P&R eblif_opt = ['-e', self.toplevel+'.eblif'] @@ -299,26 +299,26 @@ def configure_vpr(self): depends = self.toplevel+'.eblif' targets = self.toplevel+'.net' command = ['symbiflow_pack'] + eblif_opt + device_opt + sdc_opts + vpr_options - commands.add(command, [targets], [depends]) + commands.add(command, [self.EdaCommands.Target(targets)], [depends]) depends = self.toplevel+'.net' targets = self.toplevel+'.place' command = ['symbiflow_place'] + eblif_opt + device_opt command += ['-n', depends, '-P', partname] command += sdc_opts + pcf_opts + vpr_options - commands.add(command, [targets], [depends]) + commands.add(command, [self.EdaCommands.Target(targets)], [depends]) depends = self.toplevel+'.place' targets = self.toplevel+'.route' command = ['symbiflow_route'] + eblif_opt + device_opt command += sdc_opts + vpr_options - commands.add(command, [targets], [depends]) + commands.add(command, [self.EdaCommands.Target(targets)], [depends]) depends = self.toplevel+'.route' targets = self.toplevel+'.fasm' command = ['symbiflow_write_fasm'] + eblif_opt + device_opt command += sdc_opts + vpr_options - commands.add(command, [targets], [depends]) + commands.add(command, [self.EdaCommands.Target(targets)], [depends]) depends = self.toplevel+'.fasm' targets = self.toplevel+'.bit' @@ -326,7 +326,7 @@ def configure_vpr(self): command += ['-f', depends] command += ['-p' if vendor == 'xilinx' else '-P', partname] command += ['-b', targets] - commands.add(command, [targets], [depends]) + commands.add(command, [self.EdaCommands.Target(targets)], [depends]) commands.set_default_target(targets) commands.write(os.path.join(self.work_root, 'Makefile')) diff --git a/edalize/trellis.py b/edalize/trellis.py index 1102f693b..d2b6cce64 100644 --- a/edalize/trellis.py +++ b/edalize/trellis.py @@ -57,7 +57,7 @@ def configure_main(self): depends = self.name+'.config' targets = self.name+'.bit' command = ['ecppack', '--svf', self.name+'.svf', depends, targets] - commands.add(command, [targets], [depends]) + commands.add(command, [self.EdaCommands.Target(targets)], [depends]) commands.set_default_target(self.name+'.bit') commands.write(os.path.join(self.work_root, 'Makefile')) diff --git a/edalize/vivado.py b/edalize/vivado.py index b338f798c..f71e068d9 100644 --- a/edalize/vivado.py +++ b/edalize/vivado.py @@ -183,25 +183,25 @@ def configure_main(self): #Create project file project_file = self.name+'.xpr' tcl_file = [self.name+'.tcl'] - commands.add(vivado_command+tcl_file, [project_file], tcl_file + edif_files) + commands.add(vivado_command+tcl_file, [self.EdaCommands.Target(project_file)], tcl_file + edif_files) #Synthesis target if synth_tool == 'yosys': commands.commands += yosys.commands - commands.add([], ['synth'], edif_files) + commands.add([], [self.EdaCommands.Target('synth', phony=True)], edif_files) else: depends = [f'{self.name}_synth.tcl', project_file] - targets = [f'{self.name}.runs/synth_1/__synthesis_is_complete__'] + targets = [self.EdaCommands.Target(f'{self.name}.runs/synth_1/__synthesis_is_complete__')] commands.add(vivado_command+depends, targets, depends) - commands.add([], ['synth'], targets) + commands.add([], [self.EdaCommands.Target('synth', phony=True)], targets) #Bitstream generation run_tcl = self.name+'_run.tcl' depends = [run_tcl, project_file] bitstream = self.name+'.bit' - commands.add(vivado_command+depends, [bitstream], depends) + commands.add(vivado_command+depends, [self.EdaCommands.Target(bitstream)], depends) - commands.add(['vivado', project_file], ['build-gui'], [project_file]) + commands.add(['vivado', project_file], [self.EdaCommands.Target('build-gui', phony=True)], [project_file]) depends = [self.name+'_pgm.tcl', bitstream] command = ['vivado', '-quiet', '-nolog', '-notrace', '-mode', 'batch', @@ -210,7 +210,7 @@ def configure_main(self): part = self.tool_options.get('part', "") command += [part] if part else [] command += [bitstream] - commands.add(command, ['pgm'], depends) + commands.add(command, [self.EdaCommands.Target('pgm', phony=True)], depends) commands.set_default_target(bitstream) commands.write(os.path.join(self.work_root, 'Makefile')) diff --git a/edalize/yosys.py b/edalize/yosys.py index ec7ca7221..9ca418d87 100644 --- a/edalize/yosys.py +++ b/edalize/yosys.py @@ -118,7 +118,7 @@ def configure_main(self): commands = self.EdaCommands() commands.add(['yosys', '-l', 'yosys.log', '-p', f'"tcl {template}"'], - [f'{self.name}.{output}' for output in ['blif', 'json','edif']], + [self.EdaCommands.Target(f'{self.name}.{output}') for output in ['blif', 'json','edif']], [template]) if self.tool_options.get('yosys_as_subtool'): self.commands = commands.commands diff --git a/tests/test_apicula/Makefile b/tests/test_apicula/Makefile index 83548a080..c3b09e608 100644 --- a/tests/test_apicula/Makefile +++ b/tests/test_apicula/Makefile @@ -13,3 +13,5 @@ build-gui: test_apicula_0.json test_apicula_0.fs: test_apicula_0.pack $(EDALIZE_LAUNCHER) gowin_pack -d GW1N-LV1QN48C6/I5 -o test_apicula_0.fs test_apicula_0.pack + +.PHONY: all build-gui diff --git a/tests/test_apicula/minimal/Makefile b/tests/test_apicula/minimal/Makefile index e524981a5..ee8156d55 100644 --- a/tests/test_apicula/minimal/Makefile +++ b/tests/test_apicula/minimal/Makefile @@ -13,3 +13,5 @@ build-gui: test_apicula_0.json test_apicula_0.fs: test_apicula_0.pack $(EDALIZE_LAUNCHER) gowin_pack -d GW1N-LV1QN48C6/I5 -o test_apicula_0.fs test_apicula_0.pack + +.PHONY: all build-gui diff --git a/tests/test_icestorm/Makefile b/tests/test_icestorm/Makefile index 81324df45..a0abc60e4 100644 --- a/tests/test_icestorm/Makefile +++ b/tests/test_icestorm/Makefile @@ -23,3 +23,5 @@ test_icestorm_0.stat: test_icestorm_0.asc $(EDALIZE_LAUNCHER) icebox_stat test_icestorm_0.asc test_icestorm_0.stat stats: test_icestorm_0.stat + +.PHONY: all build-gui timing stats diff --git a/tests/test_icestorm/minimal/Makefile b/tests/test_icestorm/minimal/Makefile index 81324df45..a0abc60e4 100644 --- a/tests/test_icestorm/minimal/Makefile +++ b/tests/test_icestorm/minimal/Makefile @@ -23,3 +23,5 @@ test_icestorm_0.stat: test_icestorm_0.asc $(EDALIZE_LAUNCHER) icebox_stat test_icestorm_0.asc test_icestorm_0.stat stats: test_icestorm_0.stat + +.PHONY: all build-gui timing stats diff --git a/tests/test_icestorm/nextpnr/Makefile b/tests/test_icestorm/nextpnr/Makefile index 9585e299d..38af285be 100644 --- a/tests/test_icestorm/nextpnr/Makefile +++ b/tests/test_icestorm/nextpnr/Makefile @@ -23,3 +23,5 @@ test_icestorm_0.stat: test_icestorm_0.asc $(EDALIZE_LAUNCHER) icebox_stat test_icestorm_0.asc test_icestorm_0.stat stats: test_icestorm_0.stat + +.PHONY: all build-gui timing stats diff --git a/tests/test_symbiflow/nextpnr/fpga_interchange/Makefile b/tests/test_symbiflow/nextpnr/fpga_interchange/Makefile index 45f8c956d..f759d16e1 100644 --- a/tests/test_symbiflow/nextpnr/fpga_interchange/Makefile +++ b/tests/test_symbiflow/nextpnr/fpga_interchange/Makefile @@ -20,3 +20,5 @@ test_symbiflow_nextpnr_fpga_interchange_0.fasm: test_symbiflow_nextpnr_fpga_inte test_symbiflow_nextpnr_fpga_interchange_0.bit: test_symbiflow_nextpnr_fpga_interchange_0.fasm $(EDALIZE_LAUNCHER) symbiflow_write_bitstream -d artix7 -f test_symbiflow_nextpnr_fpga_interchange_0.fasm -p xc7a35tcsg324-1csg324-1 -b test_symbiflow_nextpnr_fpga_interchange_0.bit + +.PHONY: all diff --git a/tests/test_symbiflow/nextpnr/xilinx/Makefile b/tests/test_symbiflow/nextpnr/xilinx/Makefile index edb6d337d..0684f42e6 100644 --- a/tests/test_symbiflow/nextpnr/xilinx/Makefile +++ b/tests/test_symbiflow/nextpnr/xilinx/Makefile @@ -10,3 +10,5 @@ test_symbiflow_nextpnr_xilinx_0.fasm: test_symbiflow_nextpnr_xilinx_0.json test_symbiflow_nextpnr_xilinx_0.bit: test_symbiflow_nextpnr_xilinx_0.fasm $(EDALIZE_LAUNCHER) symbiflow_write_bitstream -d artix7 -f test_symbiflow_nextpnr_xilinx_0.fasm -p xc7a35tcsg324-1csg324-1 -b test_symbiflow_nextpnr_xilinx_0.bit + +.PHONY: all diff --git a/tests/test_symbiflow/vtr/Makefile b/tests/test_symbiflow/vtr/Makefile index fe3f6604a..6218b6cbe 100644 --- a/tests/test_symbiflow/vtr/Makefile +++ b/tests/test_symbiflow/vtr/Makefile @@ -19,3 +19,5 @@ top_module.fasm: top_module.route top_module.bit: top_module.fasm $(EDALIZE_LAUNCHER) symbiflow_write_bitstream -d artix7 -f top_module.fasm -p xc7a35tcsg324-1csg324-1 -b top_module.bit + +.PHONY: all diff --git a/tests/test_trellis/Makefile b/tests/test_trellis/Makefile index e645b2dce..be74133fb 100644 --- a/tests/test_trellis/Makefile +++ b/tests/test_trellis/Makefile @@ -13,3 +13,5 @@ build-gui: test_trellis_0.json test_trellis_0.bit: test_trellis_0.config $(EDALIZE_LAUNCHER) ecppack --svf test_trellis_0.svf test_trellis_0.config test_trellis_0.bit + +.PHONY: all build-gui diff --git a/tests/test_trellis/minimal/Makefile b/tests/test_trellis/minimal/Makefile index 8ca6acecf..47fe33776 100644 --- a/tests/test_trellis/minimal/Makefile +++ b/tests/test_trellis/minimal/Makefile @@ -13,3 +13,5 @@ build-gui: test_trellis_0.json test_trellis_0.bit: test_trellis_0.config $(EDALIZE_LAUNCHER) ecppack --svf test_trellis_0.svf test_trellis_0.config test_trellis_0.bit + +.PHONY: all build-gui diff --git a/tests/test_vivado/Makefile b/tests/test_vivado/Makefile index 614dc7c66..8f18afcd4 100644 --- a/tests/test_vivado/Makefile +++ b/tests/test_vivado/Makefile @@ -18,3 +18,5 @@ build-gui: test_vivado_0.xpr pgm: test_vivado_0_pgm.tcl test_vivado_0.bit $(EDALIZE_LAUNCHER) vivado -quiet -nolog -notrace -mode batch -source test_vivado_0_pgm.tcl -tclargs xc7a35tcsg324-1 test_vivado_0.bit + +.PHONY: all synth build-gui pgm diff --git a/tests/test_vivado/minimal/Makefile b/tests/test_vivado/minimal/Makefile index 73d38c2b6..2a22f5308 100644 --- a/tests/test_vivado/minimal/Makefile +++ b/tests/test_vivado/minimal/Makefile @@ -18,3 +18,5 @@ build-gui: test_vivado_minimal_0.xpr pgm: test_vivado_minimal_0_pgm.tcl test_vivado_minimal_0.bit $(EDALIZE_LAUNCHER) vivado -quiet -nolog -notrace -mode batch -source test_vivado_minimal_0_pgm.tcl -tclargs xc7a35tcsg324-1 test_vivado_minimal_0.bit + +.PHONY: all synth build-gui pgm diff --git a/tests/test_vivado/yosys/Makefile b/tests/test_vivado/yosys/Makefile index 0c75202ee..251754150 100644 --- a/tests/test_vivado/yosys/Makefile +++ b/tests/test_vivado/yosys/Makefile @@ -18,3 +18,5 @@ build-gui: test_vivado_yosys_0.xpr pgm: test_vivado_yosys_0_pgm.tcl test_vivado_yosys_0.bit $(EDALIZE_LAUNCHER) vivado -quiet -nolog -notrace -mode batch -source test_vivado_yosys_0_pgm.tcl -tclargs xc7a35tcsg324-1 test_vivado_yosys_0.bit + +.PHONY: all synth build-gui pgm From 8ff4cf850b872853fde979159724a795196d6eae Mon Sep 17 00:00:00 2001 From: GCHQDeveloper560 <48131108+GCHQDeveloper560@users.noreply.github.com> Date: Fri, 2 Jul 2021 13:09:37 +0100 Subject: [PATCH 3/4] Support cases where more than one command is needed to generate a target --- edalize/apicula.py | 2 +- edalize/edatool.py | 4 ++-- edalize/icestorm.py | 8 ++++---- edalize/nextpnr.py | 4 ++-- edalize/symbiflow.py | 22 +++++++++++----------- edalize/trellis.py | 2 +- edalize/vivado.py | 10 +++++----- edalize/yosys.py | 2 +- 8 files changed, 27 insertions(+), 27 deletions(-) diff --git a/edalize/apicula.py b/edalize/apicula.py index 2cd9e7a54..b2b4bae92 100644 --- a/edalize/apicula.py +++ b/edalize/apicula.py @@ -62,7 +62,7 @@ def configure_main(self): depends = self.name+'.pack' targets = self.name+'.fs' command = ['gowin_pack', '-d', self.tool_options.get('device'), '-o', targets, depends] - commands.add(command, [self.EdaCommands.Target(targets)], [depends]) + commands.add([command], [self.EdaCommands.Target(targets)], [depends]) commands.set_default_target(targets) commands.write(os.path.join(self.work_root, 'Makefile')) diff --git a/edalize/edatool.py b/edalize/edatool.py index 2a1221600..bb09c60ba 100644 --- a/edalize/edatool.py +++ b/edalize/edatool.py @@ -274,8 +274,8 @@ def write(self, outfile): f.write(" "+str(d)) f.write("\n") - if c.command: - f.write(f"\t$(EDALIZE_LAUNCHER) {' '.join(c.command)}\n") + for cmd in c.command: + f.write(f"\t$(EDALIZE_LAUNCHER) {' '.join(cmd)}\n") f.write(f"\n.PHONY: {' '.join(phony_targets)}\n") diff --git a/edalize/icestorm.py b/edalize/icestorm.py index 49aef7c8a..0cce6790a 100644 --- a/edalize/icestorm.py +++ b/edalize/icestorm.py @@ -67,7 +67,7 @@ def configure_main(self): command = ['arachne-pnr'] command += self.tool_options.get('arachne_pnr_options', []) command += ['-p', depends, '-o', targets] - commands.add(command, [self.EdaCommands.Target(depends)], [targets]) + commands.add([command], [self.EdaCommands.Target(depends)], [targets]) set_default_target(self.name+'.bin') elif pnr == 'next': nextpnr = Nextpnr(yosys.edam, self.work_root) @@ -82,20 +82,20 @@ def configure_main(self): depends = self.name+'.asc' targets = self.name+'.bin' command = ['icepack', depends, targets] - commands.add(command, [self.EdaCommands.Target(targets)], [depends]) + commands.add([command], [self.EdaCommands.Target(targets)], [depends]) #Timing analysis depends = self.name+'.asc' targets = self.name+'.tim' command = ['icetime', '-tmd', part or '', depends, targets] - commands.add(command, [self.EdaCommands.Target(targets)], [depends]) + commands.add([command], [self.EdaCommands.Target(targets)], [depends]) commands.add([], [self.EdaCommands.Target("timing", phony=True)], [targets]) #Statistics depends = self.name+'.asc' targets = self.name+'.stat' command = ['icebox_stat', depends, targets] - commands.add(command, [self.EdaCommands.Target(targets)], [depends]) + commands.add([command], [self.EdaCommands.Target(targets)], [depends]) commands.add([], [self.EdaCommands.Target("stats", phony=True)], [targets]) commands.write(os.path.join(self.work_root, 'Makefile')) diff --git a/edalize/nextpnr.py b/edalize/nextpnr.py index 3435873f0..3b09b7db8 100644 --- a/edalize/nextpnr.py +++ b/edalize/nextpnr.py @@ -79,8 +79,8 @@ def configure_main(self): command += constraints + ['--json', depends] + output #CLI target - commands.add(command, [self.EdaCommands.Target(targets)], [depends]) + commands.add([command], [self.EdaCommands.Target(targets)], [depends]) #GUI target - commands.add(command+['--gui'], [self.EdaCommands.Target("build-gui", phony=True)], [depends]) + commands.add([command+['--gui']], [self.EdaCommands.Target("build-gui", phony=True)], [depends]) self.commands = commands.commands diff --git a/edalize/symbiflow.py b/edalize/symbiflow.py index 101e01e87..b8a118863 100644 --- a/edalize/symbiflow.py +++ b/edalize/symbiflow.py @@ -185,7 +185,7 @@ def configure_nextpnr(self): command += ['--device', device] command += ['--top', self.toplevel] command += [depends, targets] - commands.add(command, [self.EdaCommands.Target(targets)], [depends]) + commands.add([command], [self.EdaCommands.Target(targets)], [depends]) depends = self.name+'.netlist' targets = self.name+'.phys' @@ -196,14 +196,14 @@ def configure_nextpnr(self): command += ['--write', self.name+'.routed.json'] command += ['--phys', targets] command += [nextpnr_options] - commands.add(command, [self.EdaCommands.Target(targets)], [depends]) + commands.add([command], [self.EdaCommands.Target(targets)], [depends]) depends = self.name+'.phys' targets = self.name+'.fasm' command = ['python', '-m', 'fpga_interchange.fasm_generator'] command += ['--schema_dir', '$(INTERCHANGE_SCHEMA_PATH)'] command += ['--family', family, device, self.name+'.netlist', depends, targets] - commands.add(command, [self.EdaCommands.Target(targets)], [depends]) + commands.add([command], [self.EdaCommands.Target(targets)], [depends]) else: targets = self.name+'.fasm' command = ['nextpnr-'+arch, '--chipdb', chipdb] @@ -213,13 +213,13 @@ def configure_nextpnr(self): command += ['--fasm', targets] command += ['--log', 'nextpnr.log'] command += [nextpnr_options] - commands.add(command, [self.EdaCommands.Target(targets)], [depends]) + commands.add([command], [self.EdaCommands.Target(targets)], [depends]) depends = self.name+'.fasm' targets = self.name+'.bit' command = ['symbiflow_write_bitstream', '-d', bitstream_device] command += ['-f', depends, '-p', partname, '-b', targets] - commands.add(command, [self.EdaCommands.Target(targets)], [depends]) + commands.add([command], [self.EdaCommands.Target(targets)], [depends]) commands.set_default_target(targets) commands.write(os.path.join(self.work_root, 'Makefile')) @@ -290,7 +290,7 @@ def configure_vpr(self): command += ['-d', bitstream_device] command += ['-p' if vendor == 'xilinx' else '-P', partname] command += xdc_opts - commands.add(command, [self.EdaCommands.Target(targets)], []) + commands.add([command], [self.EdaCommands.Target(targets)], []) #P&R eblif_opt = ['-e', self.toplevel+'.eblif'] @@ -299,26 +299,26 @@ def configure_vpr(self): depends = self.toplevel+'.eblif' targets = self.toplevel+'.net' command = ['symbiflow_pack'] + eblif_opt + device_opt + sdc_opts + vpr_options - commands.add(command, [self.EdaCommands.Target(targets)], [depends]) + commands.add([command], [self.EdaCommands.Target(targets)], [depends]) depends = self.toplevel+'.net' targets = self.toplevel+'.place' command = ['symbiflow_place'] + eblif_opt + device_opt command += ['-n', depends, '-P', partname] command += sdc_opts + pcf_opts + vpr_options - commands.add(command, [self.EdaCommands.Target(targets)], [depends]) + commands.add([command], [self.EdaCommands.Target(targets)], [depends]) depends = self.toplevel+'.place' targets = self.toplevel+'.route' command = ['symbiflow_route'] + eblif_opt + device_opt command += sdc_opts + vpr_options - commands.add(command, [self.EdaCommands.Target(targets)], [depends]) + commands.add([command], [self.EdaCommands.Target(targets)], [depends]) depends = self.toplevel+'.route' targets = self.toplevel+'.fasm' command = ['symbiflow_write_fasm'] + eblif_opt + device_opt command += sdc_opts + vpr_options - commands.add(command, [self.EdaCommands.Target(targets)], [depends]) + commands.add([command], [self.EdaCommands.Target(targets)], [depends]) depends = self.toplevel+'.fasm' targets = self.toplevel+'.bit' @@ -326,7 +326,7 @@ def configure_vpr(self): command += ['-f', depends] command += ['-p' if vendor == 'xilinx' else '-P', partname] command += ['-b', targets] - commands.add(command, [self.EdaCommands.Target(targets)], [depends]) + commands.add([command], [self.EdaCommands.Target(targets)], [depends]) commands.set_default_target(targets) commands.write(os.path.join(self.work_root, 'Makefile')) diff --git a/edalize/trellis.py b/edalize/trellis.py index d2b6cce64..8d1eab09c 100644 --- a/edalize/trellis.py +++ b/edalize/trellis.py @@ -57,7 +57,7 @@ def configure_main(self): depends = self.name+'.config' targets = self.name+'.bit' command = ['ecppack', '--svf', self.name+'.svf', depends, targets] - commands.add(command, [self.EdaCommands.Target(targets)], [depends]) + commands.add([command], [self.EdaCommands.Target(targets)], [depends]) commands.set_default_target(self.name+'.bit') commands.write(os.path.join(self.work_root, 'Makefile')) diff --git a/edalize/vivado.py b/edalize/vivado.py index f71e068d9..a79907a10 100644 --- a/edalize/vivado.py +++ b/edalize/vivado.py @@ -183,7 +183,7 @@ def configure_main(self): #Create project file project_file = self.name+'.xpr' tcl_file = [self.name+'.tcl'] - commands.add(vivado_command+tcl_file, [self.EdaCommands.Target(project_file)], tcl_file + edif_files) + commands.add([vivado_command+tcl_file], [self.EdaCommands.Target(project_file)], tcl_file + edif_files) #Synthesis target if synth_tool == 'yosys': @@ -192,16 +192,16 @@ def configure_main(self): else: depends = [f'{self.name}_synth.tcl', project_file] targets = [self.EdaCommands.Target(f'{self.name}.runs/synth_1/__synthesis_is_complete__')] - commands.add(vivado_command+depends, targets, depends) + commands.add([vivado_command+depends], targets, depends) commands.add([], [self.EdaCommands.Target('synth', phony=True)], targets) #Bitstream generation run_tcl = self.name+'_run.tcl' depends = [run_tcl, project_file] bitstream = self.name+'.bit' - commands.add(vivado_command+depends, [self.EdaCommands.Target(bitstream)], depends) + commands.add([vivado_command+depends], [self.EdaCommands.Target(bitstream)], depends) - commands.add(['vivado', project_file], [self.EdaCommands.Target('build-gui', phony=True)], [project_file]) + commands.add([['vivado', project_file]], [self.EdaCommands.Target('build-gui', phony=True)], [project_file]) depends = [self.name+'_pgm.tcl', bitstream] command = ['vivado', '-quiet', '-nolog', '-notrace', '-mode', 'batch', @@ -210,7 +210,7 @@ def configure_main(self): part = self.tool_options.get('part', "") command += [part] if part else [] command += [bitstream] - commands.add(command, [self.EdaCommands.Target('pgm', phony=True)], depends) + commands.add([command], [self.EdaCommands.Target('pgm', phony=True)], depends) commands.set_default_target(bitstream) commands.write(os.path.join(self.work_root, 'Makefile')) diff --git a/edalize/yosys.py b/edalize/yosys.py index 9ca418d87..f427e8459 100644 --- a/edalize/yosys.py +++ b/edalize/yosys.py @@ -117,7 +117,7 @@ def configure_main(self): template_vars) commands = self.EdaCommands() - commands.add(['yosys', '-l', 'yosys.log', '-p', f'"tcl {template}"'], + commands.add([['yosys', '-l', 'yosys.log', '-p', f'"tcl {template}"']], [self.EdaCommands.Target(f'{self.name}.{output}') for output in ['blif', 'json','edif']], [template]) if self.tool_options.get('yosys_as_subtool'): From 9bf03eec0e775f2f290ffb55a70cde7979dd0e7c Mon Sep 17 00:00:00 2001 From: GCHQDeveloper560 <48131108+GCHQDeveloper560@users.noreply.github.com> Date: Fri, 2 Jul 2021 13:26:10 +0100 Subject: [PATCH 4/4] Initial attempt to make Quartus use the command generator This passes the tests, though the Jinja filtering previously used was complex enough that problems may appear in use. This attempts to duplicate the previous Makefiles, though that may not be good style with the command generator. This required modifying the header to include Makefile variables since there's not yet support for variables in the class --- edalize/quartus.py | 157 ++++++++++++++---- .../templates/quartus/quartus-pro-makefile.j2 | 34 ---- .../templates/quartus/quartus-std-makefile.j2 | 35 ---- setup.py | 2 - tests/test_quartus/Pro/Makefile | 5 +- tests/test_quartus/Standard/Makefile | 3 +- 6 files changed, 130 insertions(+), 106 deletions(-) delete mode 100644 edalize/templates/quartus/quartus-pro-makefile.j2 delete mode 100644 edalize/templates/quartus/quartus-std-makefile.j2 diff --git a/edalize/quartus.py b/edalize/quartus.py index 3fe4c347c..17ce9febf 100644 --- a/edalize/quartus.py +++ b/edalize/quartus.py @@ -5,7 +5,6 @@ import logging import os.path import os -import platform import subprocess import re import xml.etree.ElementTree as ET @@ -20,8 +19,6 @@ class Quartus(Edatool): # Define Standard edition to be our default version isPro = False - makefile_template = {False : "quartus-std-makefile.j2", - True : "quartus-pro-makefile.j2"} @classmethod def get_doc(cls, api_ver): @@ -106,10 +103,8 @@ def __init__(self, edam=None, work_root=None, eda_api=None, verbose=False): def configure_main(self): (src_files, incdirs) = self._get_fileset_files(force_slash=True) self.jinja_env.filters['src_file_filter'] = self.src_file_filter - self.jinja_env.filters['qsys_file_filter'] = self.qsys_file_filter has_vhdl2008 = 'vhdlSource-2008' in [x.file_type for x in src_files] - has_qsys = 'QSYS' in [x.file_type for x in src_files] escaped_name = self.name.replace(".", "_") @@ -125,51 +120,149 @@ def configure_main(self): 'has_vhdl2008' : has_vhdl2008 } - # Render Makefile based on detected version - self.render_template(self.makefile_template[self.isPro], - 'Makefile', - { 'name' : escaped_name, - 'src_files' : src_files, - 'tool_options' : self.tool_options}) + self._write_makefile(escaped_name, src_files) # Render the TCL project file self.render_template('quartus-project.tcl.j2', escaped_name + '.tcl', template_vars) + """ Write a the Makefile using EdaCommands from the base class + """ - # Helper to extract file type - def file_type(self, f): - return f.file_type.split('-')[0] + def _write_makefile(self, escaped_name, src_files): + # Write Makefile + commands = self.EdaCommands() + + # Add variables + # + # It would be better to make an official interface rather than muck with + # the header + + commands.header += f"""NAME := {escaped_name} +OPTIONS := {" ".join(self.tool_options["quartus_options"])} +DSE_OPTIONS := {" ".join(self.tool_options["dse_options"])} + +""" + + # Project file + depends = "$(NAME).tcl" + cmd = ["quartus_sh", "$(OPTIONS)", "-t", depends] + targets = [self.EdaCommands.Target("project", phony=True)] + commands.add([cmd], targets, [depends]) + + # Qsys + qsys_files = [f for f in src_files if f.file_type == "QSYS"] + depends = "project" + targets = [self.EdaCommands.Target("qsys", phony=True)] + cmds = [] + + for f in qsys_files: + + # Give QSYS files special attributes to make the logic in + # the Jinja2 templates much simplier + setattr(f, "simplename", os.path.basename(f.name).split(".qsys")[0]) + setattr(f, "srcdir", os.path.dirname(f.name) or ".") + setattr(f, "dstdir", os.path.join("qsys", f.simplename)) - # Filter for just QSYS files. This verifies that they are compatible - # with the identified Quartus version - def qsys_file_filter(self, f): - name = '' - if self.file_type(f) == 'QSYS': # Compatibility checks try: qsysTree = ET.parse(os.path.join(self.work_root, f.name)) try: - tool = qsysTree.find('component').attrib['tool'] - if tool == 'QsysPro' and self.isPro: - name = f.name + tool = qsysTree.find("component").attrib["tool"] + if not (tool == "QsysPro" and self.isPro): + continue except (AttributeError, KeyError): # Either a component wasn't found in the QSYS file, or it # had no associated tool information. Make the assumption # it was a Standard edition file - if not self.isPro: - name = f.name + if self.isPro: + continue except (ET.ParseError, IOError): logger.warning("Unable to parse QSYS file " + f.name) - # Give QSYS files special attributes to make the logic in - # the Jinja2 templates much simplier - setattr(f, "simplename", os.path.basename(f.name).split('.qsys')[0]) - setattr(f, "srcdir", os.path.dirname(f.name) or '.') - setattr(f, "dstdir", os.path.join('qsys', f.simplename)) - - return name + family = self.tool_options["family"] + device = self.tool_options["device"] + if self.isPro: + cmds.append( + [ + "qsys-generate", + f.name, + "--synthesis=VERILOG", + f'--family="{family}"', + f"--part={device}", + "--quartus-project=$(NAME)", + ] + ) + else: + cmds.append( + [ + "ip-generate", + f"--project-directory={f.srcdir}", + f"--output-directory={f.dstdir}", + f"--report-file=bsf:{f.dstdir}/{f.simplename}.bsf", + f'--system-info=DEVICE_FAMILY="{family}"', + f"--system-info=DEVICE={device}", + f"--component-file={f.srcdir}/{f.simplename}.qsys", + ] + ) + cmds.append( + [ + "ip-generate", + f"--project-directory={f.srcdir}", + f"--output-directory={f.dstdir}/synthesis", + "--file-set=QUARTUS_SYNTH", + f"--report-file=sopcinfo:{f.dstdir}/{f.simplename}.sopcinfo", + f"--report-file=html:{f.dstdir}/{f.simplename}.html", + f"--report-file=qip:{f.dstdir}/{f.simplename}.qip", + f"--report-file=cmp:{f.dstdir}/{f.simplename}.cmp", + "--report-file=svd", + f'--system-info=DEVICE_FAMILY="{family}"', + f"--system-info=DEVICE={device}", + f"--component-file={f.srcdir}/{f.simplename}.qsys", + "--language=VERILOG", + ] + ) + + commands.add(cmds, targets, [depends]) + + # syn + if self.isPro: + syn = "quartus_syn" + else: + syn = "quartus_map" + cmd = [syn, "$(OPTIONS)", "$(NAME)"] + targets = [self.EdaCommands.Target("syn", phony=True)] + commands.add([cmd], targets, ["qsys"]) + + # fit, asm, sta + for target, depends in [("fit", "syn"), ("asm", "fit"), ("sta", "asm")]: + cmd = [f"quartus_{target}", "$(OPTIONS)", "$(NAME)"] + targets = [self.EdaCommands.Target(target, phony=True)] + commands.add([cmd], targets, [depends]) + + # DSE + cmd = ["quartus_dse", "$(NAME)", "$(DSE_OPTIONS)"] + targets = [self.EdaCommands.Target("dse", phony=True)] + commands.add([cmd], targets, ["syn"]) + + # clean + cmd = ["rm", "-rf", "*.*"] + if self.isPro: + cmd += ["qdb", "tmp-clearbox"] + else: + cmd += ["db", "incremental_db"] + + targets = [self.EdaCommands.Target("clean", phony=True)] + commands.add([cmd], targets, []) + + commands.set_default_target("sta") + + commands.write(os.path.join(self.work_root, "Makefile")) + + # Helper to extract file type + def file_type(self, f): + return f.file_type.split('-')[0] # Allow the templates to get source file information def src_file_filter(self, f): @@ -181,7 +274,7 @@ def _append_library(f): def _handle_qsys(t, f): # Quartus Pro just passes QSYS files onto the compiler, but Standard - # expects to see them sepecified as QIP. The Makefile is responsible + # expects to see them specified as QIP. The Makefile is responsible # for creating that QIP file for Standard edition in a known place # which can be used below if self.isPro: diff --git a/edalize/templates/quartus/quartus-pro-makefile.j2 b/edalize/templates/quartus/quartus-pro-makefile.j2 deleted file mode 100644 index ff06d0c31..000000000 --- a/edalize/templates/quartus/quartus-pro-makefile.j2 +++ /dev/null @@ -1,34 +0,0 @@ -# Auto generated by Edalize -NAME := {{ name }} -OPTIONS := {{ tool_options.quartus_options|join(' ') }} -DSE_OPTIONS := {{ tool_options.dse_options|join(' ') }} - -all: sta - -project: $(NAME).tcl - $(EDALIZE_LAUNCHER) quartus_sh $(OPTIONS) -t $(NAME).tcl - -qsys: project -{% for qsys_file in src_files if qsys_file|qsys_file_filter %} - qsys-generate {{ qsys_file|qsys_file_filter }} --synthesis=VERILOG --family="{{ tool_options.family }}" --part={{ tool_options.device }} --quartus-project=$(NAME) -{% endfor %} - -syn: qsys - $(EDALIZE_LAUNCHER) quartus_syn $(OPTIONS) $(NAME) - -fit: syn - $(EDALIZE_LAUNCHER) quartus_fit $(OPTIONS) $(NAME) - -asm: fit - $(EDALIZE_LAUNCHER) quartus_asm $(OPTIONS) $(NAME) - -sta: asm - $(EDALIZE_LAUNCHER) quartus_sta $(OPTIONS) $(NAME) - -dse: syn - $(EDALIZE_LAUNCHER) quartus_dse $(NAME) $(DSE_OPTIONS) - -clean: - $(EDALIZE_LAUNCHER) rm -rf *.* qdb tmp-clearbox - -.PHONY: all project qsys syn fit asm sta dse clean diff --git a/edalize/templates/quartus/quartus-std-makefile.j2 b/edalize/templates/quartus/quartus-std-makefile.j2 deleted file mode 100644 index a7049d2ee..000000000 --- a/edalize/templates/quartus/quartus-std-makefile.j2 +++ /dev/null @@ -1,35 +0,0 @@ -# Auto generated by Edalize -NAME := {{ name }} -OPTIONS := {{ tool_options.quartus_options|join(' ') }} -DSE_OPTIONS := {{ tool_options.dse_options|join(' ') }} - -all: sta - -project: $(NAME).tcl - $(EDALIZE_LAUNCHER) quartus_sh $(OPTIONS) -t $(NAME).tcl - -qsys: project -{% for qsys_file in src_files if qsys_file|qsys_file_filter %} - $(EDALIZE_LAUNCHER) ip-generate --project-directory={{qsys_file.srcdir}} --output-directory={{qsys_file.dstdir}} --report-file=bsf:{{qsys_file.dstdir}}/{{qsys_file.simplename}}.bsf --system-info=DEVICE_FAMILY="{{tool_options.family}}" --system-info=DEVICE={{tool_options.device}} --component-file={{qsys_file.srcdir}}/{{qsys_file.simplename}}.qsys - $(EDALIZE_LAUNCHER) ip-generate --project-directory={{qsys_file.srcdir}} --output-directory={{qsys_file.dstdir}}/synthesis --file-set=QUARTUS_SYNTH --report-file=sopcinfo:{{qsys_file.dstdir}}/{{qsys_file.simplename}}.sopcinfo --report-file=html:{{qsys_file.dstdir}}/{{qsys_file.simplename}}.html --report-file=qip:{{qsys_file.dstdir}}/{{qsys_file.simplename}}.qip --report-file=cmp:{{qsys_file.dstdir}}/{{qsys_file.simplename}}.cmp --report-file=svd --system-info=DEVICE_FAMILY="{{tool_options.family}}" --system-info=DEVICE={{tool_options.device}} --component-file={{qsys_file.srcdir}}/{{qsys_file.simplename}}.qsys --language=VERILOG -{% endfor %} - -syn: qsys - $(EDALIZE_LAUNCHER) quartus_map $(OPTIONS) $(NAME) - -fit: syn - $(EDALIZE_LAUNCHER) quartus_fit $(OPTIONS) $(NAME) - -asm: fit - $(EDALIZE_LAUNCHER) quartus_asm $(OPTIONS) $(NAME) - -sta: asm - $(EDALIZE_LAUNCHER) quartus_sta $(OPTIONS) $(NAME) - -dse: syn - $(EDALIZE_LAUNCHER) quartus_dse $(NAME) $(DSE_OPTIONS) - -clean: - $(EDALIZE_LAUNCHER) rm -rf *.* db incremental_db - -.PHONY: all project qsys syn fit asm sta dse clean diff --git a/setup.py b/setup.py index 056af49c8..7519ab990 100644 --- a/setup.py +++ b/setup.py @@ -25,8 +25,6 @@ def read(fname): 'templates/vivado/vivado-synth.tcl.j2', 'templates/vunit/run.py.j2', 'templates/quartus/quartus-project.tcl.j2', - 'templates/quartus/quartus-std-makefile.j2', - 'templates/quartus/quartus-pro-makefile.j2', 'templates/ascentlint/Makefile.j2', 'templates/ascentlint/run-ascentlint.tcl.j2', 'templates/libero/libero-project.tcl.j2', diff --git a/tests/test_quartus/Pro/Makefile b/tests/test_quartus/Pro/Makefile index 516d6d67f..3a65943d8 100644 --- a/tests/test_quartus/Pro/Makefile +++ b/tests/test_quartus/Pro/Makefile @@ -1,4 +1,5 @@ -# Auto generated by Edalize +#Auto generated by Edalize + NAME := test_quartus_0 OPTIONS := some quartus_options DSE_OPTIONS := some dse_options @@ -9,7 +10,7 @@ project: $(NAME).tcl $(EDALIZE_LAUNCHER) quartus_sh $(OPTIONS) -t $(NAME).tcl qsys: project - qsys-generate qsys_file --synthesis=VERILOG --family="Cyclone V" --part=5CSXFC6D6F31C8ES --quartus-project=$(NAME) + $(EDALIZE_LAUNCHER) qsys-generate qsys_file --synthesis=VERILOG --family="Cyclone V" --part=5CSXFC6D6F31C8ES --quartus-project=$(NAME) syn: qsys $(EDALIZE_LAUNCHER) quartus_syn $(OPTIONS) $(NAME) diff --git a/tests/test_quartus/Standard/Makefile b/tests/test_quartus/Standard/Makefile index 2e2f91467..4be2671d9 100644 --- a/tests/test_quartus/Standard/Makefile +++ b/tests/test_quartus/Standard/Makefile @@ -1,4 +1,5 @@ -# Auto generated by Edalize +#Auto generated by Edalize + NAME := test_quartus_0 OPTIONS := some quartus_options DSE_OPTIONS := some dse_options