From 3d9b185a98fca180c97e3dc53c3f3c4ae322e60a Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 15 May 2022 20:38:50 -0300
Subject: [PATCH 001/248] Updated README.md and modified version (0.3.0-dev)

---
 README.md        | 30 +++++++++++++++---------------
 fpga/__init__.py |  2 +-
 2 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/README.md b/README.md
index 8222587b..eb969487 100644
--- a/README.md
+++ b/README.md
@@ -1,30 +1,30 @@
 # PyFPGA [![License](https://img.shields.io/badge/License-GPL--3.0-darkgreen?style=flat-square)](LICENSE)
 
 ![GDHL](https://img.shields.io/badge/GHDL-last-brightgreen.svg?style=flat-square)
-![icestorm](https://img.shields.io/badge/icestorm-last-brightgreen.svg?style=flat-square)
+![Yosys](https://img.shields.io/badge/Yosys-last-brightgreen.svg?style=flat-square)
 ![nextpnr](https://img.shields.io/badge/nextpnr-last-brightgreen.svg?style=flat-square)
+![icestorm](https://img.shields.io/badge/icestorm-last-brightgreen.svg?style=flat-square)
 ![prjtrellis](https://img.shields.io/badge/prjtrellis-last-brightgreen.svg?style=flat-square)
-![Yosys](https://img.shields.io/badge/Yosys-last-brightgreen.svg?style=flat-square)
 
+![Vivado](https://img.shields.io/badge/Vivado-2019.2-blue.svg?style=flat-square)
+![Quartus](https://img.shields.io/badge/Quartus--Prime-19.1-blue.svg?style=flat-square)
 ![ISE](https://img.shields.io/badge/ISE-14.7-blue.svg?style=flat-square)
 ![Libero](https://img.shields.io/badge/Libero--Soc-12.2-blue.svg?style=flat-square)
-![Quartus](https://img.shields.io/badge/Quartus--Prime-19.1-blue.svg?style=flat-square)
-![Vivado](https://img.shields.io/badge/Vivado-2019.2-blue.svg?style=flat-square)
 
-PyFPGA is a **Python** Class for **vendor-independent FPGA development**.
-It allows using **a single project file** and **programmatically** executing
-**synthesis**, **implementation**, generation of **bitstream** and/or
-**transference** to supported boards.
+> **WARNING:** (2022-05-15) PyFPGA is in the process of being strongly rewritten/simplified.
+> Most changes are internal, but the API (`Project` class) will change.
 
-- The workflow is command-line centric.
-- It's friendly with *Version Control Systems* and *Continuous Integration* (CI).
-- Allows reproducibility and repeatability.
-- Consumes fewer system resources than GUI based workflows.
+PyFPGA is a **Python Package** for **vendor-agnostic** FPGA development.
+It provides a **Class** which allows the programmatically execution of **synthesis**,
+**place and route**, **bitstream generation** and/or **programming** of FPGA devices.
+Additionally, a set of **command-line helpers** are provided for quick and simple runs.
 
-Create your custom FPGA Tool using a workflow tailored to your needs!
+Features:
+* It's *Version Control Systems* and *Continuous Integration* friendly.
+* Allows reproducibility and repeatability.
+* Consumes fewer system resources than GUI based workflows.
 
-> **WARNING:** (2022-05-15) PyFPGA is in the process of being strongly rewritten/simplified.
-> Most changes are internal, but the API (`Project` class) will change.
+With PyFPGA you can create your custom FPGA tool using a workflow tailored to your needs!
 
 ## Usage
 
diff --git a/fpga/__init__.py b/fpga/__init__.py
index ffaf5fbc..bd3bc779 100644
--- a/fpga/__init__.py
+++ b/fpga/__init__.py
@@ -1,5 +1,5 @@
 """PyFPGA"""
 
-__version__ = '0.2.0'
+__version__ = '0.3.0-dev'
 
 from fpga.project import Project

From c18b44b6b89eafaaceb1aa985ef86728d1b9aa31 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 15 May 2022 20:40:25 -0300
Subject: [PATCH 002/248] resources: submodule added

---
 .gitmodules | 3 +++
 Makefile    | 3 +++
 resources   | 1 +
 3 files changed, 7 insertions(+)
 create mode 100644 .gitmodules
 create mode 160000 resources

diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 00000000..362bc8ae
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "resources"]
+	path = resources
+	url = https://github.com/PyFPGA/resources
diff --git a/Makefile b/Makefile
index 278baebc..8f1d8dc1 100644
--- a/Makefile
+++ b/Makefile
@@ -9,3 +9,6 @@ check:
 clean:
 	py3clean .
 	rm -fr build .pytest_cache
+
+submodule:
+	 git submodule update --init
diff --git a/resources b/resources
new file mode 160000
index 00000000..6a58bba3
--- /dev/null
+++ b/resources
@@ -0,0 +1 @@
+Subproject commit 6a58bba3b1c36d238d1111e910db02f0b284aef7

From 1e8a5468811c4fc265e8bcb8e573a0cc965a2a7f Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 22 May 2022 21:28:21 -0300
Subject: [PATCH 003/248] test: added mocks (for vendors tools)

---
 .github/workflows/test.yml      |  2 +-
 examples/Makefile               |  6 +++++-
 examples/ghdl/Makefile          |  2 +-
 examples/ghdl/ghdl.py           |  5 +----
 examples/hooks/Makefile         |  2 +-
 examples/hooks/strategies.py    |  5 +----
 examples/ise/ise.py             | 16 +++++-----------
 examples/libero/Makefile        |  2 +-
 examples/libero/libero.py       |  5 +----
 examples/misc/Makefile          |  2 +-
 examples/misc/capture.py        | 16 +++++-----------
 examples/multi/Makefile         |  2 +-
 examples/multi/memory.py        |  5 +----
 examples/multi/parameters.py    |  5 +----
 examples/multi/projects.py      |  5 +----
 examples/multi/verilog.py       |  5 +----
 examples/multi/vhdl.py          |  5 +----
 examples/openflow/icestorm.py   | 10 ++--------
 examples/openflow/prjtrellis.py | 10 ++--------
 examples/quartus/Makefile       |  2 +-
 examples/quartus/quartus.py     | 10 ++--------
 examples/vivado/Makefile        |  2 +-
 examples/vivado/design.py       |  5 +----
 examples/vivado/vivado.py       | 10 ++--------
 examples/yosys/Makefile         |  2 +-
 examples/yosys/ise.py           | 10 ++--------
 examples/yosys/vivado.py        | 10 ++--------
 examples/yosys/yosys.py         |  5 +----
 fpga/project.py                 | 16 +++++++---------
 test/mocks/impact               | 28 ++++++++++++++++++++++++++++
 test/mocks/libero               | 33 +++++++++++++++++++++++++++++++++
 test/mocks/quartus              | 27 +++++++++++++++++++++++++++
 test/mocks/quartus_pgm          | 29 +++++++++++++++++++++++++++++
 test/mocks/quartus_sh           | 27 +++++++++++++++++++++++++++
 test/mocks/vivado               | 30 ++++++++++++++++++++++++++++++
 test/mocks/xtclsh               | 27 +++++++++++++++++++++++++++
 36 files changed, 254 insertions(+), 129 deletions(-)
 create mode 100755 test/mocks/impact
 create mode 100755 test/mocks/libero
 create mode 100644 test/mocks/quartus
 create mode 100755 test/mocks/quartus_pgm
 create mode 100755 test/mocks/quartus_sh
 create mode 100755 test/mocks/vivado
 create mode 100755 test/mocks/xtclsh

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 96b267ed..2e5564e1 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -29,4 +29,4 @@ jobs:
     - name: Test
       run: |
         pytest
-        make -C examples
+        cd examples; make MOCKS=1
diff --git a/examples/Makefile b/examples/Makefile
index 77edba5c..7bfe3fc4 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -1,7 +1,11 @@
 #!/usr/bin/make
 
+ifdef MOCKS
+export PATH := $(PATH):$(PWD)/../test/mocks
+$(info INFO: using MOCKS for the vendor EDA tools)
+endif
 
 DIRS=$(wildcard */)
 
 all:
-	@$(foreach DIR, $(DIRS), make -C $(DIR);)
+	@$(foreach DIR, $(DIRS), make -C $(DIR) || exit;)
diff --git a/examples/ghdl/Makefile b/examples/ghdl/Makefile
index cd77fa54..f166a9f9 100644
--- a/examples/ghdl/Makefile
+++ b/examples/ghdl/Makefile
@@ -3,4 +3,4 @@
 SCRIPTS = $(wildcard *.py)
 
 all:
-	@$(foreach SCRIPT, $(SCRIPTS), python3 $(SCRIPT);)
+	@$(foreach SCRIPT, $(SCRIPTS), python3 $(SCRIPT) || exit;)
diff --git a/examples/ghdl/ghdl.py b/examples/ghdl/ghdl.py
index 9962d1bf..da2ef275 100644
--- a/examples/ghdl/ghdl.py
+++ b/examples/ghdl/ghdl.py
@@ -14,7 +14,4 @@
 prj.add_files('../../hdl/top.vhdl')
 prj.set_top('Top')
 
-try:
-    prj.generate()
-except RuntimeError:
-    print('ERROR:generate:Docker not found')
+prj.generate()
diff --git a/examples/hooks/Makefile b/examples/hooks/Makefile
index cd77fa54..f166a9f9 100644
--- a/examples/hooks/Makefile
+++ b/examples/hooks/Makefile
@@ -3,4 +3,4 @@
 SCRIPTS = $(wildcard *.py)
 
 all:
-	@$(foreach SCRIPT, $(SCRIPTS), python3 $(SCRIPT);)
+	@$(foreach SCRIPT, $(SCRIPTS), python3 $(SCRIPT) || exit;)
diff --git a/examples/hooks/strategies.py b/examples/hooks/strategies.py
index 89954eba..018b60eb 100644
--- a/examples/hooks/strategies.py
+++ b/examples/hooks/strategies.py
@@ -105,7 +105,4 @@
             'project'
         )
         PRJ.add_hook(commands[tool][strategy], 'project')
-        try:
-            PRJ.generate(to_task='syn')
-        except RuntimeError:
-            print('ERROR:generate:{} not found'.format(tool))
+        PRJ.generate(to_task='syn')
diff --git a/examples/ise/ise.py b/examples/ise/ise.py
index 14a95ae0..c4f90b41 100644
--- a/examples/ise/ise.py
+++ b/examples/ise/ise.py
@@ -37,16 +37,10 @@
 prj.add_files(BOARDS[args.board][2])
 
 if args.action in ['generate', 'all']:
-    try:
-        prj.generate()
-    except RuntimeError:
-        print('ERROR:generate:ISE not found')
+    prj.generate()
 
 if args.action in ['transfer', 'all']:
-    try:
-        prj.transfer('fpga')
-        #  prj.transfer('detect')
-        #  prj.transfer('unlock')
-        #  prj.transfer('spi', 1, 'N25Q128', 4)
-    except RuntimeError:
-        print('ERROR:transfer:ISE not found')
+    prj.transfer('fpga')
+    #  prj.transfer('detect')
+    #  prj.transfer('unlock')
+    #  prj.transfer('spi', 1, 'N25Q128', 4)
diff --git a/examples/libero/Makefile b/examples/libero/Makefile
index cd77fa54..f166a9f9 100644
--- a/examples/libero/Makefile
+++ b/examples/libero/Makefile
@@ -3,4 +3,4 @@
 SCRIPTS = $(wildcard *.py)
 
 all:
-	@$(foreach SCRIPT, $(SCRIPTS), python3 $(SCRIPT);)
+	@$(foreach SCRIPT, $(SCRIPTS), python3 $(SCRIPT) || exit;)
diff --git a/examples/libero/libero.py b/examples/libero/libero.py
index 7f0b39bb..32ef38a5 100644
--- a/examples/libero/libero.py
+++ b/examples/libero/libero.py
@@ -26,10 +26,7 @@
 prj.add_files('mkr.sdc')
 
 if args.action in ['generate', 'all']:
-    try:
-        prj.generate()
-    except RuntimeError:
-        print('ERROR:generate:Libero not found')
+    prj.generate()
 
 if args.action in ['transfer', 'all']:
     print('ERROR:transfer:Not yet implemented')
diff --git a/examples/misc/Makefile b/examples/misc/Makefile
index cd77fa54..f166a9f9 100644
--- a/examples/misc/Makefile
+++ b/examples/misc/Makefile
@@ -3,4 +3,4 @@
 SCRIPTS = $(wildcard *.py)
 
 all:
-	@$(foreach SCRIPT, $(SCRIPTS), python3 $(SCRIPT);)
+	@$(foreach SCRIPT, $(SCRIPTS), python3 $(SCRIPT) || exit;)
diff --git a/examples/misc/capture.py b/examples/misc/capture.py
index 8caa5a56..4284b212 100644
--- a/examples/misc/capture.py
+++ b/examples/misc/capture.py
@@ -16,14 +16,8 @@
 PRJ.add_files('../../hdl/*.vhdl', library='examples')
 PRJ.set_top('Top')
 
-try:
-    output = PRJ.generate(to_task='syn', capture=True)
-    print(output)
-except RuntimeError:
-    print('ERROR:generate:ISE not found')
-
-try:
-    output = PRJ.transfer(devtype='detect', capture=True)
-    print(output)
-except RuntimeError:
-    print('ERROR:transfer:ISE not found')
+output = PRJ.generate(to_task='syn', capture=True)
+print(output)
+
+output = PRJ.transfer(devtype='detect', capture=True)
+print(output)
diff --git a/examples/multi/Makefile b/examples/multi/Makefile
index cd77fa54..f166a9f9 100644
--- a/examples/multi/Makefile
+++ b/examples/multi/Makefile
@@ -3,4 +3,4 @@
 SCRIPTS = $(wildcard *.py)
 
 all:
-	@$(foreach SCRIPT, $(SCRIPTS), python3 $(SCRIPT);)
+	@$(foreach SCRIPT, $(SCRIPTS), python3 $(SCRIPT) || exit;)
diff --git a/examples/multi/memory.py b/examples/multi/memory.py
index fe67ee57..bbec7300 100644
--- a/examples/multi/memory.py
+++ b/examples/multi/memory.py
@@ -21,7 +21,4 @@
         else:
             PRJ.add_files('../../hdl/ram.v')
         PRJ.set_top('ram')
-        try:
-            PRJ.generate(to_task='syn')
-        except RuntimeError:
-            print('ERROR:generate:{} not found'.format(tool))
+        PRJ.generate(to_task='syn')
diff --git a/examples/multi/parameters.py b/examples/multi/parameters.py
index 45d73ad9..30012888 100644
--- a/examples/multi/parameters.py
+++ b/examples/multi/parameters.py
@@ -41,7 +41,4 @@
         # else:
         #     PRJ.add_files('../../hdl/fakes/parameters.v')
         # PRJ.set_top('Params')
-        try:
-            PRJ.generate(to_task='syn')
-        except RuntimeError:
-            print('ERROR:generate:{} not found'.format(tool))
+        PRJ.generate(to_task='syn')
diff --git a/examples/multi/projects.py b/examples/multi/projects.py
index 97cc83ec..dd7bb7ce 100644
--- a/examples/multi/projects.py
+++ b/examples/multi/projects.py
@@ -57,7 +57,4 @@
 }
 
 for prj in PROJECTS:
-    try:
-        PROJECTS[prj].generate('syn')
-    except RuntimeError:
-        print('ERROR:generate:tool not found')
+    PROJECTS[prj].generate('syn')
diff --git a/examples/multi/verilog.py b/examples/multi/verilog.py
index bfce523e..a751f566 100644
--- a/examples/multi/verilog.py
+++ b/examples/multi/verilog.py
@@ -21,7 +21,4 @@
     PRJ.add_files('../../hdl/blinking.v')
     PRJ.add_files('../../hdl/top.v')
     PRJ.set_top('Top')
-    try:
-        PRJ.generate(to_task='syn')
-    except RuntimeError:
-        print('ERROR:generate:{} not found'.format(tool))
+    PRJ.generate(to_task='syn')
diff --git a/examples/multi/vhdl.py b/examples/multi/vhdl.py
index b2563e41..7c6ee7d8 100644
--- a/examples/multi/vhdl.py
+++ b/examples/multi/vhdl.py
@@ -18,7 +18,4 @@
     PRJ.add_files('../../hdl/examples_pkg.vhdl', library='examples')
     PRJ.add_files('../../hdl/top.vhdl')
     PRJ.set_top('Top')
-    try:
-        PRJ.generate(to_task='syn')
-    except RuntimeError:
-        print('ERROR:generate:{} not found'.format(tool))
+    PRJ.generate(to_task='syn')
diff --git a/examples/openflow/icestorm.py b/examples/openflow/icestorm.py
index 05d5f96b..77a0e529 100644
--- a/examples/openflow/icestorm.py
+++ b/examples/openflow/icestorm.py
@@ -44,13 +44,7 @@
 prj.set_top('Top')
 
 if args.action in ['generate', 'all']:
-    try:
-        prj.generate()
-    except RuntimeError:
-        print('ERROR:generate:Docker not found')
+    prj.generate()
 
 if args.action in ['transfer', 'all']:
-    try:
-        prj.transfer()
-    except RuntimeError:
-        print('ERROR:transfer:Docker not found')
+    prj.transfer()
diff --git a/examples/openflow/prjtrellis.py b/examples/openflow/prjtrellis.py
index 59eb8311..86255567 100644
--- a/examples/openflow/prjtrellis.py
+++ b/examples/openflow/prjtrellis.py
@@ -44,13 +44,7 @@
 prj.set_top('Top')
 
 if args.action in ['generate', 'all']:
-    try:
-        prj.generate()
-    except RuntimeError:
-        print('ERROR:generate:Docker not found')
+    prj.generate()
 
 if args.action in ['transfer', 'all']:
-    try:
-        prj.transfer()
-    except RuntimeError:
-        print('ERROR:transfer:Docker not found')
+    prj.transfer()
diff --git a/examples/quartus/Makefile b/examples/quartus/Makefile
index cd77fa54..f166a9f9 100644
--- a/examples/quartus/Makefile
+++ b/examples/quartus/Makefile
@@ -3,4 +3,4 @@
 SCRIPTS = $(wildcard *.py)
 
 all:
-	@$(foreach SCRIPT, $(SCRIPTS), python3 $(SCRIPT);)
+	@$(foreach SCRIPT, $(SCRIPTS), python3 $(SCRIPT) || exit;)
diff --git a/examples/quartus/quartus.py b/examples/quartus/quartus.py
index 809036b0..6516fcd0 100644
--- a/examples/quartus/quartus.py
+++ b/examples/quartus/quartus.py
@@ -26,13 +26,7 @@
 prj.add_files('de10nano.tcl')
 
 if args.action in ['generate', 'all']:
-    try:
-        prj.generate()
-    except RuntimeError:
-        print('ERROR:generate:Quartus not found')
+    prj.generate()
 
 if args.action in ['transfer', 'all']:
-    try:
-        prj.transfer('fpga', 2)
-    except RuntimeError:
-        print('ERROR:transfer:Quartus not found')
+    prj.transfer('fpga', 2)
diff --git a/examples/vivado/Makefile b/examples/vivado/Makefile
index cd77fa54..f166a9f9 100644
--- a/examples/vivado/Makefile
+++ b/examples/vivado/Makefile
@@ -3,4 +3,4 @@
 SCRIPTS = $(wildcard *.py)
 
 all:
-	@$(foreach SCRIPT, $(SCRIPTS), python3 $(SCRIPT);)
+	@$(foreach SCRIPT, $(SCRIPTS), python3 $(SCRIPT) || exit;)
diff --git a/examples/vivado/design.py b/examples/vivado/design.py
index 4ea1cf31..7ac4eef3 100644
--- a/examples/vivado/design.py
+++ b/examples/vivado/design.py
@@ -30,7 +30,4 @@
 
 prj.add_hook(export, 'postbit')
 
-try:
-    prj.generate()
-except Exception as e:
-    logging.warning('{} ({})'.format(type(e).__name__, e))
+prj.generate()
diff --git a/examples/vivado/vivado.py b/examples/vivado/vivado.py
index 5b00bd1a..e28c861b 100644
--- a/examples/vivado/vivado.py
+++ b/examples/vivado/vivado.py
@@ -24,13 +24,7 @@
 prj.set_top('Blinking')
 
 if args.action in ['generate', 'all']:
-    try:
-        prj.generate()
-    except RuntimeError:
-        print('ERROR:generate:Vivado not found')
+    prj.generate()
 
 if args.action in ['transfer', 'all']:
-    try:
-        prj.transfer('fpga')
-    except RuntimeError:
-        print('ERROR:transfer:Vivado not found')
+    prj.transfer('fpga')
diff --git a/examples/yosys/Makefile b/examples/yosys/Makefile
index 9546d682..f07825c7 100644
--- a/examples/yosys/Makefile
+++ b/examples/yosys/Makefile
@@ -3,4 +3,4 @@
 SCRIPTS = $(wildcard *.py)
 
 all:
-	@$(foreach SCRIPT, $(SCRIPTS), python3 $(SCRIPT); python3 $(SCRIPT) --lang vhdl; )
+	@$(foreach SCRIPT, $(SCRIPTS), python3 $(SCRIPT) || exit; python3 $(SCRIPT) --lang vhdl || exit; )
diff --git a/examples/yosys/ise.py b/examples/yosys/ise.py
index b48d78b5..0d41d445 100644
--- a/examples/yosys/ise.py
+++ b/examples/yosys/ise.py
@@ -34,13 +34,7 @@
 prj.set_top('Top')
 
 if args.action in ['generate', 'all']:
-    try:
-        prj.generate()
-    except RuntimeError:
-        print('ERROR:generate:Docker or ISE not found')
+    prj.generate()
 
 if args.action in ['transfer', 'all']:
-    try:
-        prj.transfer()
-    except RuntimeError:
-        print('ERROR:transfer:ISE not found')
+    prj.transfer()
diff --git a/examples/yosys/vivado.py b/examples/yosys/vivado.py
index 1a5ea22f..d77061f8 100644
--- a/examples/yosys/vivado.py
+++ b/examples/yosys/vivado.py
@@ -34,13 +34,7 @@
 prj.set_top('Top')
 
 if args.action in ['generate', 'all']:
-    try:
-        prj.generate()
-    except RuntimeError:
-        print('ERROR:generate:Docker or Vivado not found')
+    prj.generate()
 
 if args.action in ['transfer', 'all']:
-    try:
-        prj.transfer()
-    except RuntimeError:
-        print('ERROR:transfer:Vivado not found')
+    prj.transfer()
diff --git a/examples/yosys/yosys.py b/examples/yosys/yosys.py
index 29316969..3f93ebfe 100644
--- a/examples/yosys/yosys.py
+++ b/examples/yosys/yosys.py
@@ -28,7 +28,4 @@
 
 prj.set_top('Top')
 
-try:
-    prj.generate()
-except RuntimeError:
-    print('ERROR:generate:Docker not found')
+prj.generate()
diff --git a/fpga/project.py b/fpga/project.py
index d9bc2f81..c6b5f18f 100644
--- a/fpga/project.py
+++ b/fpga/project.py
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2019-2021 Rodrigo A. Melo
+# Copyright (C) 2019-2022 Rodrigo A. Melo
 # Copyright (C) 2019-2020 INTI
 #
 # This program is free software: you can redistribute it and/or modify
@@ -17,10 +17,8 @@
 #
 
 """fpga.project
-
-This module implements the main class of PyFPGA, which provides
-functionalities to create a project, generate a bitstream and transfer it to a
-Device.
+This module implements the entry-point of PyFPGA, which provides
+functionalities to create a project, generate a bitstream and program a device.
 """
 
 import contextlib
@@ -48,7 +46,7 @@ class Project:
 
     :param tool: FPGA tool to be used
     :param project: project name (the tool name is used if none specified)
-    :param init: a dict to initialize some parameters
+    :param init: a dict with metadata about the project
     :param relative_to_script: specifies if the files/directories are relative
      to the script or the execution directory
     :raises NotImplementedError: when tool is unsupported
@@ -289,8 +287,8 @@ def generate(self, to_task='bit', from_task='prj', capture=False):
         :param capture: capture STDOUT and STDERR
         :returns: STDOUT and STDERR messages
         :raises ValueError: when from_task is later than to_task
+        :raises ValueError: when to_task or from_task are unsupported
         :raises RuntimeError: when the tool to be used is not found
-        :raises ValueError: when to_task or from_task are is unsupported
 
         .. note:: Valid values for **tasks** are
          ``prj`` (to creates the project file),
@@ -329,9 +327,9 @@ def transfer(
         :param width: bits width of the memory (when device is not *fpga*)
         :param capture: capture STDOUT and STDERR
         :returns: STDOUT and STDERR messages
-        :raises RuntimeError: when the tool to be used is not found
         :raises FileNotFoundError: when the bitstream is not found
         :raises ValueError: when devtype, position or width are unsupported
+        :raises RuntimeError: when the tool to be used is not found
         """
         _log.info(
             'transfering "%s" project using "%s" tool from "%s" directory',
@@ -352,7 +350,7 @@ def clean(self):
 
     @contextlib.contextmanager
     def _run_in_dir(self):
-        """Runs the tool in another directory."""
+        """Run the tool in another directory."""
         start = time.time()
         try:
             if not os.path.exists(self.outdir):
diff --git a/test/mocks/impact b/test/mocks/impact
new file mode 100755
index 00000000..17eee4a6
--- /dev/null
+++ b/test/mocks/impact
@@ -0,0 +1,28 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2022 Rodrigo A. Melo
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+import argparse
+
+parser = argparse.ArgumentParser()
+
+parser.add_argument('-batch', action='store_true', required=True)
+parser.add_argument('source')
+
+args = parser.parse_args()
+
+print(f'INFO:the {parser.prog.upper()} mock has been executed')
diff --git a/test/mocks/libero b/test/mocks/libero
new file mode 100755
index 00000000..3124978a
--- /dev/null
+++ b/test/mocks/libero
@@ -0,0 +1,33 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2022 Rodrigo A. Melo
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+import argparse
+import sys
+
+parser = argparse.ArgumentParser()
+
+parser.add_argument('source')
+
+args = parser.parse_args()
+
+
+if not args.source.startswith("SCRIPT:", 0):
+    print('ERROR:the parameter should start width "SCRIPT:"')
+    sys.exit(1)
+
+print(f'INFO:the {parser.prog.upper()} mock has been executed')
diff --git a/test/mocks/quartus b/test/mocks/quartus
new file mode 100644
index 00000000..495c255e
--- /dev/null
+++ b/test/mocks/quartus
@@ -0,0 +1,27 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2022 Rodrigo A. Melo
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+import argparse
+
+parser = argparse.ArgumentParser()
+
+parser.add_argument('--script', required=True)
+
+args = parser.parse_args()
+
+print(f'INFO:the {parser.prog.upper()} mock has been executed')
diff --git a/test/mocks/quartus_pgm b/test/mocks/quartus_pgm
new file mode 100755
index 00000000..3353ee46
--- /dev/null
+++ b/test/mocks/quartus_pgm
@@ -0,0 +1,29 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2022 Rodrigo A. Melo
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+import argparse
+
+parser = argparse.ArgumentParser()
+
+parser.add_argument('-c', required=True)
+parser.add_argument('--mode', choices=['jtag'], required=True)
+parser.add_argument('-o', required=True)
+
+args = parser.parse_args()
+
+print(f'INFO:the {parser.prog.upper()} mock has been executed')
diff --git a/test/mocks/quartus_sh b/test/mocks/quartus_sh
new file mode 100755
index 00000000..495c255e
--- /dev/null
+++ b/test/mocks/quartus_sh
@@ -0,0 +1,27 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2022 Rodrigo A. Melo
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+import argparse
+
+parser = argparse.ArgumentParser()
+
+parser.add_argument('--script', required=True)
+
+args = parser.parse_args()
+
+print(f'INFO:the {parser.prog.upper()} mock has been executed')
diff --git a/test/mocks/vivado b/test/mocks/vivado
new file mode 100755
index 00000000..7d598f7a
--- /dev/null
+++ b/test/mocks/vivado
@@ -0,0 +1,30 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2022 Rodrigo A. Melo
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+import argparse
+
+parser = argparse.ArgumentParser()
+
+parser.add_argument('-mode', choices=['batch'], required=True)
+parser.add_argument('-notrace', action='store_true', required=True)
+parser.add_argument('-quiet', action='store_true', required=True)
+parser.add_argument('-source', required=True)
+
+args = parser.parse_args()
+
+print(f'INFO:the {parser.prog.upper()} mock has been executed')
diff --git a/test/mocks/xtclsh b/test/mocks/xtclsh
new file mode 100755
index 00000000..71046506
--- /dev/null
+++ b/test/mocks/xtclsh
@@ -0,0 +1,27 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2022 Rodrigo A. Melo
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+import argparse
+
+parser = argparse.ArgumentParser()
+
+parser.add_argument('source')
+
+args = parser.parse_args()
+
+print(f'INFO:the {parser.prog.upper()} mock has been executed')

From 06c31d433abf5b8de08e4c34d2139ad3eaf4575b Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Tue, 24 May 2022 21:53:10 -0300
Subject: [PATCH 004/248] ci: fixed an 'exit status 2' issue

---
 .github/workflows/lint.yml |  1 -
 .github/workflows/test.yml | 22 +++++++++++++---------
 fpga/tool/template.sh      |  3 ++-
 3 files changed, 15 insertions(+), 11 deletions(-)

diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 0564dc22..7904c2d7 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -12,7 +12,6 @@ jobs:
       run: |
         pip install pycodestyle
         pip install pylint
-        pip install .
     - name: Lint
       run: |
         pycodestyle fpga examples test
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 2e5564e1..4af9850d 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,6 +11,16 @@ jobs:
         python-version: [3.6, 3.7, 3.8, 3.9]
     steps:
     - uses: actions/checkout@v2
+      with:
+        submodules: true
+        fetch-depth: 0
+    - name: Pull container images
+      run: |
+        docker pull hdlc/ghdl:yosys
+        docker pull hdlc/nextpnr:ice40
+        docker pull hdlc/nextpnr:ecp5
+        docker pull hdlc/icestorm
+        docker pull hdlc/prjtrellis
     - name: Set up Python ${{ matrix.python-version }}
       uses: actions/setup-python@v2
       with:
@@ -19,14 +29,8 @@ jobs:
       run: |
         pip install pytest
         pip install .
-    - name: Pull container images
-      run: |
-        docker pull hdlc/prjtrellis
-        docker pull hdlc/ghdl:yosys
-        docker pull hdlc/icestorm
-        docker pull hdlc/nextpnr:ecp5
-        docker pull hdlc/nextpnr:ice40
-    - name: Test
+    - name: Run test
+      run: pytest
+    - name: Run examples
       run: |
-        pytest
         cd examples; make MOCKS=1
diff --git a/fpga/tool/template.sh b/fpga/tool/template.sh
index c10dbdd6..06d82b20 100644
--- a/fpga/tool/template.sh
+++ b/fpga/tool/template.sh
@@ -73,7 +73,8 @@ MODULE=
 [ -n "$VHDLS" ] && MODULE="-m ghdl"
 
 function print () {{
-    tput setaf 6; echo ">>> PyFPGA ($1): $2"; tput sgr0;
+    # tput setaf 6; echo ">>> PyFPGA ($1): $2"; tput sgr0;
+    echo ">>> PyFPGA ($1): $2"
 }}
 
 ###############################################################################

From b896134e26977808809a731d44fa91376623c7b2 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Tue, 24 May 2022 22:20:55 -0300
Subject: [PATCH 005/248] ci: added python 3.10

---
 .github/workflows/test.yml | 6 +++---
 setup.py                   | 1 +
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 4af9850d..533e2019 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -8,7 +8,7 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        python-version: [3.6, 3.7, 3.8, 3.9]
+        pyver: ['3.6', '3.7', '3.8', '3.9', '3.10']
     steps:
     - uses: actions/checkout@v2
       with:
@@ -21,10 +21,10 @@ jobs:
         docker pull hdlc/nextpnr:ecp5
         docker pull hdlc/icestorm
         docker pull hdlc/prjtrellis
-    - name: Set up Python ${{ matrix.python-version }}
+    - name: Set up Python ${{ matrix.pyver }}
       uses: actions/setup-python@v2
       with:
-        python-version: ${{ matrix.python-version }}
+        python-version: ${{ matrix.pyver }}
     - name: Install dependencies
       run: |
         pip install pytest
diff --git a/setup.py b/setup.py
index 90266a5d..c0e7ae4c 100644
--- a/setup.py
+++ b/setup.py
@@ -34,6 +34,7 @@
         'Programming Language :: Python :: 3.7',
         'Programming Language :: Python :: 3.8',
         'Programming Language :: Python :: 3.9',
+        'Programming Language :: Python :: 3.10',
         'Topic :: Utilities',
         'Topic :: Software Development :: Build Tools',
         "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)"

From fda3a825c0dbec21a1a2ba8dc0c54fb73f74f5e9 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Tue, 24 May 2022 22:35:30 -0300
Subject: [PATCH 006/248] ci: added schedule based on cron

---
 .github/workflows/test.yml | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 533e2019..9ff37c04 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -2,13 +2,18 @@ name: 'test'
 
 on:
   push:
+  pull_request:
+  schedule: # Run once a week to ensure tests pass with updated dependencies
+    - cron: '0 0 * * 6'
 
 jobs:
   test:
-    runs-on: ubuntu-latest
     strategy:
       matrix:
+        os: ['ubuntu']
         pyver: ['3.6', '3.7', '3.8', '3.9', '3.10']
+    runs-on: ${{ matrix.os }}-latest
+    name: ${{ matrix.os }} | ${{ matrix.pyver }}
     steps:
     - uses: actions/checkout@v2
       with:

From dbfc133ad0bcdf0a44361fd0911e17b365aec710 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Wed, 25 May 2022 23:01:04 -0300
Subject: [PATCH 007/248] fpga: renamed add_path as add_vlog_include

---
 doc/basic.rst                   | 4 ++--
 doc/intro.rst                   | 6 +++---
 examples/multi/parameters.py    | 4 ++--
 examples/multi/verilog.py       | 4 ++--
 examples/openflow/icestorm.py   | 4 ++--
 examples/openflow/prjtrellis.py | 4 ++--
 examples/yosys/ise.py           | 4 ++--
 examples/yosys/vivado.py        | 4 ++--
 examples/yosys/yosys.py         | 4 ++--
 fpga/helpers/hdl2bit.py         | 2 +-
 fpga/project.py                 | 8 ++++----
 fpga/tool/__init__.py           | 4 ++--
 12 files changed, 26 insertions(+), 26 deletions(-)

diff --git a/doc/basic.rst b/doc/basic.rst
index a0d081ba..7a5456c8 100644
--- a/doc/basic.rst
+++ b/doc/basic.rst
@@ -70,8 +70,8 @@ file extension, and if it is a member of a VHDL package.
     change the order if needed.
   * If a file seems unsupported, you can always use the ``prefile`` or
     ``project`` :ref:`hooks`.
-  * In case of Verilog, ``add_path`` can be used to specify where to search for
-    included files.
+  * In case of Verilog, ``add_vlog_include`` can be used to specify where to
+    search for included files.
 
 Finally, the top-level must be specified:
 
diff --git a/doc/intro.rst b/doc/intro.rst
index db1d89d4..55d3576c 100644
--- a/doc/intro.rst
+++ b/doc/intro.rst
@@ -46,11 +46,11 @@ Detailed support
 +------------------------------+---------+----------+------------+-----------+----------+
 |``std_logic_vector`` (*VHDL*) | ``TBD`` | ``TBD``  |``TBD``     | ``TBD``   | ``TBD``  |
 +------------------------------+---------+----------+------------+-----------+----------+
-|**add_path**                  | ``Yes`` | ``Yes``  | ``Yes``    | ``Yes``   | ``Yes``  |
+|**add_vlog_include**          | ``Yes`` | ``Yes``  | ``Yes``    | ``Yes``   | ``Yes``  |
 +------------------------------+---------+----------+------------+-----------+----------+
-|**set_define** (*Verilog*)    | ``TBI`` | ``TBI``  | ``TBI``    | ``TBI``   | ``TBI``  |
+|**add_vlog_define**           | ``TBI`` | ``TBI``  | ``TBI``    | ``TBI``   | ``TBI``  |
 +------------------------------+---------+----------+------------+-----------+----------+
-|**set_arch** (*VHDL*)         | ``TBI`` | ``TBI``  | ``TBI``    | ``TBI``   | ``TBI``  |
+|**set_vhdl_arch**             | ``TBI`` | ``TBI``  | ``TBI``    | ``TBI``   | ``TBI``  |
 +------------------------------+---------+----------+------------+-----------+----------+
 |**generate**                  |         |          |            |           |          |
 +------------------------------+---------+----------+------------+-----------+----------+
diff --git a/examples/multi/parameters.py b/examples/multi/parameters.py
index 30012888..107bd2d4 100644
--- a/examples/multi/parameters.py
+++ b/examples/multi/parameters.py
@@ -26,8 +26,8 @@
         if hdl == 'vhdl':
             PRJ.add_files('../../hdl/blinking.vhdl')
         else:
-            PRJ.add_path('../../hdl/headers1')
-            PRJ.add_path('../../hdl/headers2')
+            PRJ.add_vlog_include('../../hdl/headers1')
+            PRJ.add_vlog_include('../../hdl/headers2')
             PRJ.add_files('../../hdl/blinking.v')
         PRJ.set_top('Blinking')
         # PRJ.set_param('INT', '15')
diff --git a/examples/multi/verilog.py b/examples/multi/verilog.py
index a751f566..b16be138 100644
--- a/examples/multi/verilog.py
+++ b/examples/multi/verilog.py
@@ -16,8 +16,8 @@
         continue
     PRJ = Project(tool)
     PRJ.set_outdir('../../build/multi/verilog/%s' % tool)
-    PRJ.add_path('../../hdl/headers1')
-    PRJ.add_path('../../hdl/headers2')
+    PRJ.add_vlog_include('../../hdl/headers1')
+    PRJ.add_vlog_include('../../hdl/headers2')
     PRJ.add_files('../../hdl/blinking.v')
     PRJ.add_files('../../hdl/top.v')
     PRJ.set_top('Top')
diff --git a/examples/openflow/icestorm.py b/examples/openflow/icestorm.py
index 77a0e529..a71bec78 100644
--- a/examples/openflow/icestorm.py
+++ b/examples/openflow/icestorm.py
@@ -31,8 +31,8 @@
 prj.set_part(BOARDS[args.board][0])
 
 if args.lang == 'verilog':
-    prj.add_path('../../hdl/headers1')
-    prj.add_path('../../hdl/headers2')
+    prj.add_vlog_include('../../hdl/headers1')
+    prj.add_vlog_include('../../hdl/headers2')
     prj.add_files('../../hdl/blinking.v')
     prj.add_files('../../hdl/top.v')
 else:  # args.lang == 'vhdl'
diff --git a/examples/openflow/prjtrellis.py b/examples/openflow/prjtrellis.py
index 86255567..bece88a9 100644
--- a/examples/openflow/prjtrellis.py
+++ b/examples/openflow/prjtrellis.py
@@ -31,8 +31,8 @@
 prj.set_part(BOARDS[args.board][0])
 
 if args.lang == 'verilog':
-    prj.add_path('../../hdl/headers1')
-    prj.add_path('../../hdl/headers2')
+    prj.add_vlog_include('../../hdl/headers1')
+    prj.add_vlog_include('../../hdl/headers2')
     prj.add_files('../../hdl/blinking.v')
     prj.add_files('../../hdl/top.v')
 else:  # args.lang == 'vhdl'
diff --git a/examples/yosys/ise.py b/examples/yosys/ise.py
index 0d41d445..6a900be9 100644
--- a/examples/yosys/ise.py
+++ b/examples/yosys/ise.py
@@ -21,8 +21,8 @@
 prj.set_part('XC6SLX9-2-CSG324')
 
 if args.lang == 'verilog':
-    prj.add_path('../../hdl/headers1')
-    prj.add_path('../../hdl/headers2')
+    prj.add_vlog_include('../../hdl/headers1')
+    prj.add_vlog_include('../../hdl/headers2')
     prj.add_files('../../hdl/blinking.v')
     prj.add_files('../../hdl/top.v')
 else:  # args.lang == 'vhdl'
diff --git a/examples/yosys/vivado.py b/examples/yosys/vivado.py
index d77061f8..4dfae60a 100644
--- a/examples/yosys/vivado.py
+++ b/examples/yosys/vivado.py
@@ -21,8 +21,8 @@
 prj.set_part('xc7z010-1-clg400')
 
 if args.lang == 'verilog':
-    prj.add_path('../../hdl/headers1')
-    prj.add_path('../../hdl/headers2')
+    prj.add_vlog_include('../../hdl/headers1')
+    prj.add_vlog_include('../../hdl/headers2')
     prj.add_files('../../hdl/blinking.v')
     prj.add_files('../../hdl/top.v')
 else:  # args.lang == 'vhdl'
diff --git a/examples/yosys/yosys.py b/examples/yosys/yosys.py
index 3f93ebfe..3553d515 100644
--- a/examples/yosys/yosys.py
+++ b/examples/yosys/yosys.py
@@ -17,8 +17,8 @@
 prj.set_outdir('../../build/yosys-{}'.format(args.lang))
 
 if args.lang == 'verilog':
-    prj.add_path('../../hdl/headers1')
-    prj.add_path('../../hdl/headers2')
+    prj.add_vlog_include('../../hdl/headers1')
+    prj.add_vlog_include('../../hdl/headers2')
     prj.add_files('../../hdl/blinking.v')
     prj.add_files('../../hdl/top.v')
 else:  # args.lang == 'vhdl'
diff --git a/fpga/helpers/hdl2bit.py b/fpga/helpers/hdl2bit.py
index 68378ca9..b73d0b8a 100644
--- a/fpga/helpers/hdl2bit.py
+++ b/fpga/helpers/hdl2bit.py
@@ -133,7 +133,7 @@ def main():
 
     if args.include is not None:
         for include in args.include:
-            prj.add_path(include)
+            prj.add_vlog_include(include)
 
     if args.file is not None:
         for file in args.file:
diff --git a/fpga/project.py b/fpga/project.py
index c6b5f18f..e2b2d6e9 100644
--- a/fpga/project.py
+++ b/fpga/project.py
@@ -108,7 +108,7 @@ def _initialize(self, init):
         if 'paths' in init:
             for path in init['paths']:
                 _log.debug('PATH = %s', path)
-                self.add_path(path)
+                self.add_vlog_include(path)
         for filetype in ['vhdl', 'verilog', 'constraint']:
             if filetype in init:
                 for file in init[filetype]:
@@ -208,8 +208,8 @@ def get_files(self):
         """
         return self.tool.get_files()
 
-    def add_path(self, path):
-        """Add a search path.
+    def add_vlog_include(self, path):
+        """Add a Verilog include path.
 
         Useful to specify where to search Verilog Included Files or IP
         repositories.
@@ -221,7 +221,7 @@ def add_path(self, path):
         path = os.path.normpath(path)
         if os.path.isdir(path):
             path = os.path.relpath(path, self.outdir)
-            self.tool.add_path(path)
+            self.tool.add_vlog_include(path)
         else:
             raise NotADirectoryError(path)
 
diff --git a/fpga/tool/__init__.py b/fpga/tool/__init__.py
index 1f82fc3e..54e8f594 100644
--- a/fpga/tool/__init__.py
+++ b/fpga/tool/__init__.py
@@ -143,8 +143,8 @@ def get_files(self):
         """Get the files of the project."""
         return self.files
 
-    def add_path(self, path):
-        """Add a search path."""
+    def add_vlog_include(self, path):
+        """Add a Verilog include path."""
         self.paths.append(path)
 
     def set_top(self, top):

From 579f275d51a7f1c87e196b90679f71e4e7e9015a Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Wed, 25 May 2022 23:06:45 -0300
Subject: [PATCH 008/248] fpga: added add_vlog_define and set_vhdl_arch in
 project.py (not implemented)

---
 fpga/project.py | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/fpga/project.py b/fpga/project.py
index e2b2d6e9..6567baa1 100644
--- a/fpga/project.py
+++ b/fpga/project.py
@@ -225,6 +225,14 @@ def add_vlog_include(self, path):
         else:
             raise NotADirectoryError(path)
 
+    def add_vlog_define(self, name, value):
+        """Add a Verilog define."""
+        raise NotImplementedError()
+
+    def set_vhdl_arch(self, name):
+        """Set the VHDL architecture."""
+        raise NotImplementedError()
+
     def set_top(self, toplevel):
         """Set the top level of the project.
 

From 6699cd91bd097a1fce2abbb6a647cabf70a75473 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Thu, 26 May 2022 22:14:25 -0300
Subject: [PATCH 009/248] fpga: renamed set_param as add_param

---
 doc/advanced.rst             |  4 ++--
 doc/intro.rst                |  2 +-
 examples/multi/parameters.py | 14 +++++++-------
 examples/vivado/vivado.py    |  2 +-
 fpga/helpers/hdl2bit.py      |  2 +-
 fpga/project.py              |  8 ++++----
 fpga/tool/__init__.py        |  4 ++--
 7 files changed, 18 insertions(+), 18 deletions(-)

diff --git a/doc/advanced.rst b/doc/advanced.rst
index 0cfea3af..9ff52609 100644
--- a/doc/advanced.rst
+++ b/doc/advanced.rst
@@ -99,9 +99,9 @@ The generics/parameters of the project can be optionally changed with:
 
 .. code-block:: python
 
-   prj.set_param('param1', value1)
+   prj.add_param('param1', value1)
    ...
-   prj.set_param('paramN', valueN)
+   prj.add_param('paramN', valueN)
 
 Generate options
 ================
diff --git a/doc/intro.rst b/doc/intro.rst
index 55d3576c..62d93d7e 100644
--- a/doc/intro.rst
+++ b/doc/intro.rst
@@ -32,7 +32,7 @@ Detailed support
 +------------------------------+---------+----------+------------+-----------+----------+
 |``block_design``              | ``NY``  | ``NY``   | ``NY``     | ``NY``    | ``Yes``  |
 +------------------------------+---------+----------+------------+-----------+----------+
-|**set_param**                 |         |          |            |           |          |
+|**add_param**                 |         |          |            |           |          |
 +------------------------------+---------+----------+------------+-----------+----------+
 |``boolean`` (*VHDL/Verilog*)  | ``TBD`` | ``TBD``  |``TBD``     | ``TBD``   | ``TBD``  |
 +------------------------------+---------+----------+------------+-----------+----------+
diff --git a/examples/multi/parameters.py b/examples/multi/parameters.py
index 107bd2d4..f1912c85 100644
--- a/examples/multi/parameters.py
+++ b/examples/multi/parameters.py
@@ -20,8 +20,8 @@
             if tool in ['openflow', 'yosys', 'yosys-ise', 'yosys-vivado']:
                 continue
         PRJ = Project(tool)
-        PRJ.set_param('FREQ', '50000000')
-        PRJ.set_param('SECS', '2')
+        PRJ.add_param('FREQ', '50000000')
+        PRJ.add_param('SECS', '2')
         PRJ.set_outdir('../../build/multi/params/%s/%s' % (tool, hdl))
         if hdl == 'vhdl':
             PRJ.add_files('../../hdl/blinking.vhdl')
@@ -30,11 +30,11 @@
             PRJ.add_vlog_include('../../hdl/headers2')
             PRJ.add_files('../../hdl/blinking.v')
         PRJ.set_top('Blinking')
-        # PRJ.set_param('INT', '15')
-        # PRJ.set_param('REA', '1.5')
-        # PRJ.set_param('LOG', "'1'")
-        # PRJ.set_param('VEC', '"10101010"')
-        # PRJ.set_param('STR', '"WXYZ"')
+        # PRJ.add_param('INT', '15')
+        # PRJ.add_param('REA', '1.5')
+        # PRJ.add_param('LOG', "'1'")
+        # PRJ.add_param('VEC', '"10101010"')
+        # PRJ.add_param('STR', '"WXYZ"')
         # PRJ.set_outdir('../../build/multi/params/%s/%s' % (tool, hdl))
         # if hdl == 'vhdl':
         #     PRJ.add_files('../../hdl/fakes/generics.vhdl')
diff --git a/examples/vivado/vivado.py b/examples/vivado/vivado.py
index e28c861b..bf1830a1 100644
--- a/examples/vivado/vivado.py
+++ b/examples/vivado/vivado.py
@@ -18,7 +18,7 @@
 
 prj.set_outdir('../../build/vivado')
 
-prj.set_param('FREQ', '125000000')
+prj.add_param('FREQ', '125000000')
 prj.add_files('../../hdl/blinking.vhdl')
 prj.add_files('zybo.xdc')
 prj.set_top('Blinking')
diff --git a/fpga/helpers/hdl2bit.py b/fpga/helpers/hdl2bit.py
index b73d0b8a..87ed4159 100644
--- a/fpga/helpers/hdl2bit.py
+++ b/fpga/helpers/hdl2bit.py
@@ -145,7 +145,7 @@ def main():
 
     if args.param is not None:
         for param in args.param:
-            prj.set_param(param[0], param[1])
+            prj.add_param(param[0], param[1])
 
     prj.add_files(args.top)
     prj.set_top(args.top)
diff --git a/fpga/project.py b/fpga/project.py
index 6567baa1..d3f84a68 100644
--- a/fpga/project.py
+++ b/fpga/project.py
@@ -125,7 +125,7 @@ def _initialize(self, init):
         if 'params' in init:
             for parname, parvalue in init['params'].items():
                 _log.debug('PARAM = %s %s', parname, parvalue)
-                self.set_param(parname, parvalue)
+                self.add_param(parname, parvalue)
         if 'top' in init:
             _log.debug('TOP = %s', init['top'])
             self.set_top(init['top'])
@@ -154,13 +154,13 @@ def set_part(self, part):
         """
         self.tool.set_part(part)
 
-    def set_param(self, name, value):
-        """Set a Generic/Parameter Value.
+    def add_param(self, name, value):
+        """Add a Generic/Parameter Value.
 
         :param name: parameter/generic name
         :param value: value to be assigned
         """
-        self.tool.set_param(name, value)
+        self.tool.add_param(name, value)
 
     def add_files(self, pathname, filetype=None, library=None, options=None):
         """Adds files to the project.
diff --git a/fpga/tool/__init__.py b/fpga/tool/__init__.py
index 54e8f594..8ced52bb 100644
--- a/fpga/tool/__init__.py
+++ b/fpga/tool/__init__.py
@@ -130,8 +130,8 @@ def set_part(self, part):
         """Set the target PART."""
         self.part['name'] = part
 
-    def set_param(self, name, value):
-        """Set a Generic/Parameter Value."""
+    def add_param(self, name, value):
+        """Add a Generic/Parameter Value."""
         self.params.append([name, value])
 
     def add_file(self, file, filetype, library, options):

From d1bd35cffa035104761e12e3c22f1e4b2f00de4b Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Thu, 26 May 2022 22:52:45 -0300
Subject: [PATCH 010/248] fpga: renamed 'imp' as 'par'

---
 doc/advanced.rst       |  8 ++++----
 doc/intro.rst          |  2 +-
 fpga/project.py        |  4 ++--
 fpga/tool/__init__.py  |  8 ++++----
 fpga/tool/template.sh  |  6 +++---
 fpga/tool/template.tcl | 20 ++++++++++----------
 6 files changed, 24 insertions(+), 24 deletions(-)

diff --git a/doc/advanced.rst b/doc/advanced.rst
index 9ff52609..3ee54d32 100644
--- a/doc/advanced.rst
+++ b/doc/advanced.rst
@@ -68,9 +68,9 @@ The following table depicts the parts of the *Project Creation* and the
 +--------------------------+----------------------+
 | Files addition           | **postsyn** hook     |
 +--------------------------+----------------------+
-| Top specification        | Implementation       |
+| Top specification        | Place and Route      |
 +--------------------------+----------------------+
-| Parameters specification | **postimp** hook     |
+| Parameters specification | **postpar** hook     |
 +--------------------------+----------------------+
 | **project** hook         | Bitstream generation |
 +--------------------------+----------------------+
@@ -87,7 +87,7 @@ specify additional *hooks* in different parts of the flow, using:
 .. NOTE::
 
   * Valid vaues for *phase* are ``prefile``, ``project`` (default), ``preflow``,
-    ``postsyn``, ``postimp`` and ``postbit``.
+    ``postsyn``, ``postpar`` and ``postbit``.
   * The *hook* string must be a valid command (supported by the used tool).
   * If more than one *hook* is needed in the same *phase*, you can call this
     method several times (the commands will be executed in order).
@@ -115,7 +115,7 @@ The method ``generate`` (previously seen at the end of
 
 With *to_task* and *from_taks* (with default values ``bit`` and ``prj``),
 you are selecting the first and last task to execute when `generate` is
-invoqued. The order and available tasks are ``prj``, ``syn``, ``imp`` and ``bit``.
+invoqued. The order and available tasks are ``prj``, ``syn``, ``par`` and ``bit``.
 It can be useful in at least two cases:
 
 * Maybe you created a file project with the GUI of the Tool and only want to
diff --git a/doc/intro.rst b/doc/intro.rst
index 62d93d7e..67c8e087 100644
--- a/doc/intro.rst
+++ b/doc/intro.rst
@@ -58,7 +58,7 @@ Detailed support
 +------------------------------+---------+----------+------------+-----------+----------+
 |``syn``                       | ``Yes`` | ``Yes``  | ``Yes``    | ``Yes``   | ``Yes``  |
 +------------------------------+---------+----------+------------+-----------+----------+
-|``imp``                       | ``Yes`` | ``Yes``  | ``Yes``    | ``Yes``   | ``Yes``  |
+|``par``                       | ``Yes`` | ``Yes``  | ``Yes``    | ``Yes``   | ``Yes``  |
 +------------------------------+---------+----------+------------+-----------+----------+
 |``bit``                       | ``Yes`` | ``Yes``  | ``Yes``    | ``Yes``   | ``Yes``  |
 +------------------------------+---------+----------+------------+-----------+----------+
diff --git a/fpga/project.py b/fpga/project.py
index d3f84a68..f3f99b7a 100644
--- a/fpga/project.py
+++ b/fpga/project.py
@@ -278,8 +278,8 @@ def add_hook(self, hook, phase='project'):
          ``prefile`` (to add options needed to find files),
          ``project`` (to add project related options),
          ``preflow`` (to change options previous to run the flow),
-         ``postsyn`` (to perform an action between *syn* and *imp*),
-         ``postimp`` (to perform an action between *imp* and *bit*) and
+         ``postsyn`` (to perform an action between *syn* and *par*),
+         ``postpar`` (to perform an action between *par* and *bit*) and
          ``postbit`` (to perform an action after *bit*)
 
         .. warning:: Using a hook, you will be probably broken the vendor
diff --git a/fpga/tool/__init__.py b/fpga/tool/__init__.py
index 8ced52bb..9fc09685 100644
--- a/fpga/tool/__init__.py
+++ b/fpga/tool/__init__.py
@@ -30,8 +30,8 @@
 
 FILETYPES = ['verilog', 'vhdl', 'constraint', 'design']
 MEMWIDTHS = [1, 2, 4, 8, 16, 32]
-PHASES = ['prefile', 'project', 'preflow', 'postsyn', 'postimp', 'postbit']
-TASKS = ['prj', 'syn', 'imp', 'bit']
+PHASES = ['prefile', 'project', 'preflow', 'postsyn', 'postpar', 'postbit']
+TASKS = ['prj', 'syn', 'par', 'bit']
 
 
 def check_value(value, values):
@@ -83,7 +83,7 @@ def __init__(self, project):
             'project': [],
             'preflow': [],
             'postsyn': [],
-            'postimp': [],
+            'postpar': [],
             'postbit': []
         }
         self.files = {
@@ -202,7 +202,7 @@ def _create_gen_script(self, tasks):
         tcl = tcl.replace('#PROJECT_CMDS#', '\n'.join(self.cmds['project']))
         tcl = tcl.replace('#PREFLOW_CMDS#', '\n'.join(self.cmds['preflow']))
         tcl = tcl.replace('#POSTSYN_CMDS#', '\n'.join(self.cmds['postsyn']))
-        tcl = tcl.replace('#POSTIMP_CMDS#', '\n'.join(self.cmds['postimp']))
+        tcl = tcl.replace('#POSTPAR_CMDS#', '\n'.join(self.cmds['postpar']))
         tcl = tcl.replace('#POSTBIT_CMDS#', '\n'.join(self.cmds['postbit']))
         with open(f'{self._TOOL}.tcl', 'w', encoding='utf-8') as file:
             file.write(tcl)
diff --git a/fpga/tool/template.sh b/fpga/tool/template.sh
index 06d82b20..f2b271eb 100644
--- a/fpga/tool/template.sh
+++ b/fpga/tool/template.sh
@@ -40,7 +40,7 @@ INCLUDES="{includes}"
 VERILOGS="{verilogs}"
 CONSTRAINTS="{constraints}"
 
-# taks = prj syn imp bit
+# taks = prj syn par bit
 TASKS="{tasks}"
 
 #
@@ -137,9 +137,9 @@ fi
 # Place and Route
 ###############################################################################
 
-if [[ $TASKS == *"imp"* ]]; then
+if [[ $TASKS == *"par"* ]]; then
 
-print "nextpnr-$FAMILY" "running 'implementation'"
+print "nextpnr-$FAMILY" "running 'place and route'"
 
 INPUT="--json $PROJECT.json"
 
diff --git a/fpga/tool/template.tcl b/fpga/tool/template.tcl
index 238f6891..7466d534 100644
--- a/fpga/tool/template.tcl
+++ b/fpga/tool/template.tcl
@@ -18,7 +18,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
 # Description: Tcl script to create a new project and performs synthesis,
-# implementation and bitstream generation.
+# place and route, and bitstream generation.
 #
 # Supported TOOLs: ise, libero, quartus, vivado
 #
@@ -41,7 +41,7 @@ set DEVICE   #DEVICE#
 set PACKAGE  #PACKAGE#
 set SPEED    #SPEED#
 set TOP      #TOP#
-# TASKS = prj syn imp bit
+# TASKS = prj syn par bit
 set TASKS    [list #TASKS#]
 
 set PARAMS   [list #PARAMS#]
@@ -65,8 +65,8 @@ proc fpga_commands { PHASE } {
         "postsyn" {
 #POSTSYN_CMDS#
         }
-        "postimp" {
-#POSTIMP_CMDS#
+        "postpar" {
+#POSTPAR_CMDS#
         }
         "postbit" {
 #POSTBIT_CMDS#
@@ -384,9 +384,9 @@ proc fpga_run_syn {} {
     }
 }
 
-proc fpga_run_imp {} {
+proc fpga_run_par {} {
     global TOOL PRESYNTH
-    fpga_print "running 'implementation'"
+    fpga_print "running 'place and route'"
     switch $TOOL {
         "ise"     {
             process run "Translate"
@@ -470,7 +470,7 @@ if { [lsearch -exact $TASKS "prj"] >= 0 } {
 # Design Flow
 #
 
-if { [lsearch -regexp $TASKS "syn|imp|bit"] >= 0 } {
+if { [lsearch -regexp $TASKS "syn|par|bit"] >= 0 } {
     fpga_print "running the Design Flow"
     if { [catch {
         fpga_open $PROJECT
@@ -479,9 +479,9 @@ if { [lsearch -regexp $TASKS "syn|imp|bit"] >= 0 } {
             fpga_run_syn
             fpga_commands "postsyn"
         }
-        if { [lsearch -exact $TASKS "imp"] >= 0 } {
-            fpga_run_imp
-            fpga_commands "postimp"
+        if { [lsearch -exact $TASKS "par"] >= 0 } {
+            fpga_run_par
+            fpga_commands "postpar"
         }
         if { [lsearch -exact $TASKS "bit"] >= 0 } {
             fpga_run_bit

From bbdc605c5ab17c680af87db097bec8a550a1831d Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Thu, 26 May 2022 23:32:58 -0300
Subject: [PATCH 011/248] Updated shields in README.md

---
 README.md | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/README.md b/README.md
index eb969487..97fad22f 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,10 @@
 # PyFPGA [![License](https://img.shields.io/badge/License-GPL--3.0-darkgreen?style=flat-square)](LICENSE)
 
-![GDHL](https://img.shields.io/badge/GHDL-last-brightgreen.svg?style=flat-square)
-![Yosys](https://img.shields.io/badge/Yosys-last-brightgreen.svg?style=flat-square)
-![nextpnr](https://img.shields.io/badge/nextpnr-last-brightgreen.svg?style=flat-square)
-![icestorm](https://img.shields.io/badge/icestorm-last-brightgreen.svg?style=flat-square)
-![prjtrellis](https://img.shields.io/badge/prjtrellis-last-brightgreen.svg?style=flat-square)
-
 ![Vivado](https://img.shields.io/badge/Vivado-2019.2-blue.svg?style=flat-square)
 ![Quartus](https://img.shields.io/badge/Quartus--Prime-19.1-blue.svg?style=flat-square)
-![ISE](https://img.shields.io/badge/ISE-14.7-blue.svg?style=flat-square)
 ![Libero](https://img.shields.io/badge/Libero--Soc-12.2-blue.svg?style=flat-square)
+![ISE](https://img.shields.io/badge/ISE-14.7-blue.svg?style=flat-square)
+![Openflow](https://img.shields.io/badge/Openflow-GHDL%20%7C%20Yosys%20%7C%20nextpnr%20%7C%20icestorm%20%7C%20prjtrellis-darkgreen.svg?style=flat-square)
 
 > **WARNING:** (2022-05-15) PyFPGA is in the process of being strongly rewritten/simplified.
 > Most changes are internal, but the API (`Project` class) will change.
@@ -95,7 +90,7 @@ Should you achieve either success of failure on non-POSIX systems, please let us
 **Notes:**
 
 - The open-source tools are supported trough container images from the
-[ghdl/docker](https://github.com/ghdl/docker) project, so
+[HDL containers](https://hdl.github.io/containers) project, so
 [Docker](https://www.docker.com/) ~~or [Podman](https://podman.io/)~~ must be
 installed. The same workflow can be used in CI services.
 - ISE, Libero-Soc, Quartus Prime and Vivado, must be ready to be executed from

From fe8bcbcd383037fe893d34be206896c4b3c62bff Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Fri, 27 May 2022 00:02:29 -0300
Subject: [PATCH 012/248] fpga: renamed 'init' as 'meta'

---
 examples/multi/projects.py |  6 +++---
 fpga/project.py            | 40 +++++++++++++++++++-------------------
 2 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/examples/multi/projects.py b/examples/multi/projects.py
index dd7bb7ce..3d267a93 100644
--- a/examples/multi/projects.py
+++ b/examples/multi/projects.py
@@ -14,7 +14,7 @@
     'prj1': Project(
         'vivado',
         'vivado-prj',
-        {
+        meta={
             'outdir': '../../build/multi/projects/vivado',
             'part': 'xc7k70t-3-fbg484',
             'vhdl': [
@@ -28,7 +28,7 @@
     'prj2': Project(
         'ise',
         'ise-prj',
-        {
+        meta={
             'outdir': '../../build/multi/projects/ise',
             'part': 'xc6slx9-2-csg324',
             'vhdl': [
@@ -40,7 +40,7 @@
     'prj3': Project(
         'quartus',
         'qurtus-prj',
-        {
+        meta={
             'outdir': '../../build/multi/projects/quartus',
             'part': '5CEBA2F17A7',
             'paths': [
diff --git a/fpga/project.py b/fpga/project.py
index f3f99b7a..069d2be7 100644
--- a/fpga/project.py
+++ b/fpga/project.py
@@ -46,7 +46,7 @@ class Project:
 
     :param tool: FPGA tool to be used
     :param project: project name (the tool name is used if none specified)
-    :param init: a dict with metadata about the project
+    :param meta: a dict with metadata about the project
     :param relative_to_script: specifies if the files/directories are relative
      to the script or the execution directory
     :raises NotImplementedError: when tool is unsupported
@@ -57,7 +57,7 @@ class Project:
     """
 
     def __init__(
-            self, tool='vivado', project=None, init=None,
+            self, tool='vivado', project=None, meta=None,
             relative_to_script=True):
         """Class constructor."""
         if tool == 'ghdl':
@@ -93,25 +93,25 @@ def __init__(
         self._absdir = os.path.join(self._rundir, self._reldir)
         _log.debug('ABSDIR = %s', self._absdir)
         self.set_outdir('build')
-        self._initialize(init)
+        self._initialize(meta)
 
-    def _initialize(self, init):
+    def _initialize(self, meta):
         """Set some of the most used internal parameters."""
-        if init is None:
+        if meta is None:
             return
-        if 'outdir' in init:
-            _log.debug('OUTDIR = %s', init['outdir'])
-            self.set_outdir(init['outdir'])
-        if 'part' in init:
-            _log.debug('PART = %s', init['part'])
-            self.set_part(init['part'])
-        if 'paths' in init:
-            for path in init['paths']:
+        if 'outdir' in meta:
+            _log.debug('OUTDIR = %s', meta['outdir'])
+            self.set_outdir(meta['outdir'])
+        if 'part' in meta:
+            _log.debug('PART = %s', meta['part'])
+            self.set_part(meta['part'])
+        if 'paths' in meta:
+            for path in meta['paths']:
                 _log.debug('PATH = %s', path)
                 self.add_vlog_include(path)
         for filetype in ['vhdl', 'verilog', 'constraint']:
-            if filetype in init:
-                for file in init[filetype]:
+            if filetype in meta:
+                for file in meta[filetype]:
                     if isinstance(file, list):
                         filename = file[0]
                         library = file[1]
@@ -122,13 +122,13 @@ def _initialize(self, init):
                         'FILE = %s %s %s', filename, filetype, library
                     )
                     self.add_files(filename, filetype, library)
-        if 'params' in init:
-            for parname, parvalue in init['params'].items():
+        if 'params' in meta:
+            for parname, parvalue in meta['params'].items():
                 _log.debug('PARAM = %s %s', parname, parvalue)
                 self.add_param(parname, parvalue)
-        if 'top' in init:
-            _log.debug('TOP = %s', init['top'])
-            self.set_top(init['top'])
+        if 'top' in meta:
+            _log.debug('TOP = %s', meta['top'])
+            self.set_top(meta['top'])
 
     def set_outdir(self, outdir):
         """Sets the OUTput DIRectory (where to put the resulting files).

From 8777ee8ebfba2dffd41b29f5d6d330d96610e353 Mon Sep 17 00:00:00 2001
From: lmcapacho <lmcapacho@gmail.com>
Date: Tue, 31 Jan 2023 18:46:32 -0500
Subject: [PATCH 013/248] fix: ModuleNotFoundError: No module named
 'fpga.helpers'

---
 setup.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/setup.py b/setup.py
index c0e7ae4c..05036c4a 100644
--- a/setup.py
+++ b/setup.py
@@ -15,7 +15,7 @@
     author_email='rodrigomelo9@gmail.com',
     license='GPLv3',
     url='https://github.com/PyFPGA/pyfpga',
-    package_data={'': ['tool/*.sh', 'tool/*.tcl']},
+    package_data={'': ['tool/*.sh', 'tool/*.tcl', 'helpers/*']},
     packages=find_packages(),
     entry_points={
         'console_scripts': [

From 7f49fdf6dc873e56132c61bf902ee463199fa90e Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 19 May 2024 21:27:38 -0300
Subject: [PATCH 014/248] Improved existing mocks

---
 test/mocks/libero     | 22 +++++++++++++++++++++-
 test/mocks/quartus    | 27 ---------------------------
 test/mocks/quartus_sh | 42 +++++++++++++++++++++++++++++++++++++++++-
 test/mocks/vivado     | 43 ++++++++++++++++++++++++++++++++++++++++++-
 test/mocks/xtclsh     | 23 ++++++++++++++++++++++-
 5 files changed, 126 insertions(+), 31 deletions(-)
 delete mode 100644 test/mocks/quartus

diff --git a/test/mocks/libero b/test/mocks/libero
index 3124978a..b0f0b691 100755
--- a/test/mocks/libero
+++ b/test/mocks/libero
@@ -17,17 +17,37 @@
 #
 
 import argparse
+import subprocess
 import sys
 
+
 parser = argparse.ArgumentParser()
 
 parser.add_argument('source')
 
 args = parser.parse_args()
 
+tool = parser.prog
 
 if not args.source.startswith("SCRIPT:", 0):
     print('ERROR:the parameter should start width "SCRIPT:"')
     sys.exit(1)
 
-print(f'INFO:the {parser.prog.upper()} mock has been executed')
+tcl = f'''
+proc unknown {{ cmmd args }} {{ }}
+
+source {args.source.replace('SCRIPT:', '')}
+'''
+
+with open(f'{tool}-mock.tcl', 'w', encoding='utf-8') as file:
+    file.write(tcl)
+
+subprocess.run(
+   f'tclsh {tool}-mock.tcl',
+   shell=True,
+   check=True,
+   universal_newlines=True,
+   #stdout=output, stderr=subprocess.STDOUT
+)
+
+print(f'INFO:the {tool.upper()} mock has been executed')
diff --git a/test/mocks/quartus b/test/mocks/quartus
deleted file mode 100644
index 495c255e..00000000
--- a/test/mocks/quartus
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2022 Rodrigo A. Melo
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-
-import argparse
-
-parser = argparse.ArgumentParser()
-
-parser.add_argument('--script', required=True)
-
-args = parser.parse_args()
-
-print(f'INFO:the {parser.prog.upper()} mock has been executed')
diff --git a/test/mocks/quartus_sh b/test/mocks/quartus_sh
index 495c255e..a002e73d 100755
--- a/test/mocks/quartus_sh
+++ b/test/mocks/quartus_sh
@@ -17,6 +17,9 @@
 #
 
 import argparse
+import os
+import subprocess
+
 
 parser = argparse.ArgumentParser()
 
@@ -24,4 +27,41 @@ parser.add_argument('--script', required=True)
 
 args = parser.parse_args()
 
-print(f'INFO:the {parser.prog.upper()} mock has been executed')
+tool = parser.prog
+
+tcl = f'''
+lappend auto_path pkg
+
+proc unknown {{ cmmd args }} {{ }}
+
+source {args.script}
+'''
+
+with open(f'{tool}-mock.tcl', 'w', encoding='utf-8') as file:
+    file.write(tcl)
+
+tcl = f'''
+namespace eval ::quartus {{
+  namespace export project
+}}
+'''
+
+if not os.path.exists('pkg'):
+    os.makedirs('pkg')
+
+package ifneeded ::quartus 1.0 [list source quartus-pkg.tcl]
+
+pkgIndex.tcl
+
+with open(f'pkg/quartus.tcl', 'w', encoding='utf-8') as file:
+    file.write(tcl)
+
+subprocess.run(
+   f'tclsh {tool}-mock.tcl',
+   shell=True,
+   check=True,
+   universal_newlines=True,
+   #stdout=output, stderr=subprocess.STDOUT
+)
+
+print(f'INFO:the {tool.upper()} mock has been executed')
diff --git a/test/mocks/vivado b/test/mocks/vivado
index 7d598f7a..af5614d1 100755
--- a/test/mocks/vivado
+++ b/test/mocks/vivado
@@ -17,6 +17,8 @@
 #
 
 import argparse
+import subprocess
+
 
 parser = argparse.ArgumentParser()
 
@@ -27,4 +29,43 @@ parser.add_argument('-source', required=True)
 
 args = parser.parse_args()
 
-print(f'INFO:the {parser.prog.upper()} mock has been executed')
+tool = parser.prog
+
+
+#proc create_project    {{ args }} {{ }}
+#proc open_project      {{ args }} {{ }}
+#proc current_project   {{ args }} {{ }}
+#proc current_fileset   {{ args }} {{ }}
+#proc get_filesets      {{ args }} {{ }}
+#proc set_property      {{ args }} {{ }}
+#proc add_files         {{ args }} {{ }}
+#proc get_files         {{ args }} {{ }}
+#proc reset_run         {{ args }} {{ }}
+#proc launch_runs       {{ args }} {{ }}
+#proc get_runs          {{ args }} {{ }}
+#proc wait_on_run       {{ args }} {{ }}
+#proc open_run          {{ args }} {{ }}
+#proc write_bitstream   {{ args }} {{ }}
+#proc close_project     {{ args }} {{ }}
+#proc current_bd_design {{ args }} {{ }}
+#proc get_bd_cells      {{ args }} {{ }}
+
+
+tcl = f'''
+proc unknown {{ cmmd args }} {{ }}
+
+source {args.source}
+'''
+
+with open(f'{tool}-mock.tcl', 'w', encoding='utf-8') as file:
+    file.write(tcl)
+
+subprocess.run(
+   f'tclsh {tool}-mock.tcl',
+   shell=True,
+   check=True,
+   universal_newlines=True,
+   #stdout=output, stderr=subprocess.STDOUT
+)
+
+print(f'INFO:the {tool.upper()} mock has been executed')
diff --git a/test/mocks/xtclsh b/test/mocks/xtclsh
index 71046506..12046fa3 100755
--- a/test/mocks/xtclsh
+++ b/test/mocks/xtclsh
@@ -17,6 +17,8 @@
 #
 
 import argparse
+import subprocess
+
 
 parser = argparse.ArgumentParser()
 
@@ -24,4 +26,23 @@ parser.add_argument('source')
 
 args = parser.parse_args()
 
-print(f'INFO:the {parser.prog.upper()} mock has been executed')
+tool = parser.prog
+
+tcl = f'''
+proc unknown {{ cmmd args }} {{ }}
+
+source {args.source}
+'''
+
+with open(f'{tool}-mock.tcl', 'w', encoding='utf-8') as file:
+    file.write(tcl)
+
+subprocess.run(
+   f'tclsh {tool}-mock.tcl',
+   shell=True,
+   check=True,
+   universal_newlines=True,
+   #stdout=output, stderr=subprocess.STDOUT
+)
+
+print(f'INFO:the {tool.upper()} mock has been executed')

From 4cc3513e05b2643475e174b53542e533c6719b77 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 25 May 2024 23:51:41 -0300
Subject: [PATCH 015/248] Added a new WIP Project class under the pyfpga
 directory

---
 pyfpga/project.py | 119 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 119 insertions(+)
 create mode 100644 pyfpga/project.py

diff --git a/pyfpga/project.py b/pyfpga/project.py
new file mode 100644
index 00000000..881a7187
--- /dev/null
+++ b/pyfpga/project.py
@@ -0,0 +1,119 @@
+#
+# Copyright (C) 2019-2024 Rodrigo A. Melo
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+
+"""pyfpga.project
+This module implements the entry-point of PyFPGA, which provides
+functionalities to create a project, generate a bitstream and
+program a device.
+"""
+
+from pathlib import Path
+
+TASKS = ['prj', 'elb', 'syn', 'par', 'bit']
+
+TOOLS = [
+    'ghdl',
+    'ise',
+    'libero',
+    'openflow',
+    'quartus',
+    'vivado',
+    'yosys',
+    'yosys-ise',
+    'yosys-vivado'
+]
+
+
+class Project:
+    """Class to manage an FPGA project.
+
+    :param tool: tool name
+    :type tool: str
+    :param name: project name (tool name by default)
+    :type name: str, optional
+    :param data: pre-populated data for the project
+    :type data: dict, optional
+    :param odir: output directory
+    :type odir: str, optional
+    :raises NotImplementedError: unsupported tool
+
+    .. note::
+     Supported tool names are:
+     ``ghdl``
+     ``ise``
+     ``libero``
+     ``openflow``
+     ``quartus``
+     ``vivado``
+     ``yosys``
+     ``yosys-ise``
+     ``yosys-vivado``
+    """
+
+    def __init__(self, tool, name=None, data=None, odir='results'):
+        """Class constructor."""
+        if tool not in TOOLS:
+            raise NotImplementedError(f'unsupported tool ({tool}).')
+        self.tool = tool
+        self.name = name or tool
+        self.data = data or {}
+        self.odir = Path(odir)
+        self.odir.mkdir(parents=True, exist_ok=True)
+
+    def set_part(self, name):
+        """Templ placeholder"""
+        raise NotImplementedError('Method is not implemented yet.')
+
+    def add_file(self, pathname, filetype=None, library=None, options=None):
+        """Templ placeholder"""
+        raise NotImplementedError('Method is not implemented yet.')
+
+    def add_vlog(self, pathname, options=None):
+        """Templ placeholder"""
+        self.add_file(pathname, filetype='vlog', options=options)
+
+    def add_slog(self, pathname, options=None):
+        """Templ placeholder"""
+        self.add_file(pathname, filetype='slog', options=options)
+
+    def add_vhdl(self, pathname, library=None, options=None):
+        """Templ placeholder"""
+        self.add_file(
+            pathname, filetype='vhdl',
+            library=library, options=options
+        )
+
+    def add_param(self, name, value):
+        """Templ placeholder"""
+        raise NotImplementedError('Method is not implemented yet.')
+
+    def add_include(self, path):
+        """Templ placeholder"""
+        raise NotImplementedError('Method is not implemented yet.')
+
+    def add_define(self, name, value):
+        """Templ placeholder"""
+        raise NotImplementedError('Method is not implemented yet.')
+
+    def set_arch(self, name):
+        """Templ placeholder"""
+        raise NotImplementedError('Method is not implemented yet.')
+
+    def set_top(self, name):
+        """Templ placeholder"""
+        raise NotImplementedError('Method is not implemented yet.')
+
+    def add_hook(self, stage, hook):
+        """Templ placeholder"""
+        raise NotImplementedError('Method is not implemented yet.')
+
+    def make(self, last='bit', first='prj', capture=False):
+        """Templ placeholder"""
+        raise NotImplementedError('Method is not implemented yet.')
+
+    def prog(self, position=1, bitstream=None):
+        """Templ placeholder"""
+        raise NotImplementedError('Method is not implemented yet.')

From a9a25b1e37753146b38a21d3723c1ee279341c0d Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 25 May 2024 23:52:35 -0300
Subject: [PATCH 016/248] ci: updated, modified to analyze pyfpga instead of
 fpga

---
 .github/workflows/lint.yml | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 7904c2d7..61d227d9 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -7,12 +7,25 @@ jobs:
   lint:
     runs-on: ubuntu-latest
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v4
     - name: Install dependencies
       run: |
         pip install pycodestyle
         pip install pylint
     - name: Lint
       run: |
-        pycodestyle fpga examples test
-        pylint fpga
+        pycodestyle pyfpga examples test
+        pylint pyfpga
+
+jobs:
+  lint:
+    runs-on: ubuntu-latest
+    steps:
+    - name: Checkout code
+      uses: actions/checkout@v4
+    - name: Install dependencies
+      run: pip install pycodestyle pylint
+    - name: Run linters
+      run: |
+        pycodestyle pyfpga examples test
+        pylint pyfpga

From 4b037ae4b5b9f55522ac00518c8aea1bbf23684a Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 25 May 2024 23:57:13 -0300
Subject: [PATCH 017/248] ci: renamed doc as docs, disabled docs and test

---
 .github/workflows/{doc.yml => docs.yml} | 4 ++--
 .github/workflows/test.yml              | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)
 rename .github/workflows/{doc.yml => docs.yml} (93%)

diff --git a/.github/workflows/doc.yml b/.github/workflows/docs.yml
similarity index 93%
rename from .github/workflows/doc.yml
rename to .github/workflows/docs.yml
index ee0ecc54..a89f8848 100644
--- a/.github/workflows/doc.yml
+++ b/.github/workflows/docs.yml
@@ -1,11 +1,11 @@
-name: 'doc'
+name: 'docs'
 
 on:
   push:
     branches:
       - main
 
-jobs:
+.jobs:
   linux:
     runs-on: ubuntu-latest
     steps:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 9ff37c04..25761f18 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -6,7 +6,7 @@ on:
   schedule: # Run once a week to ensure tests pass with updated dependencies
     - cron: '0 0 * * 6'
 
-jobs:
+.jobs:
   test:
     strategy:
       matrix:

From 828815976d1ed96cfe7666197e51e109a7d1589d Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 25 May 2024 23:59:25 -0300
Subject: [PATCH 018/248] ci: fixed lint action

---
 .github/workflows/lint.yml | 14 --------------
 1 file changed, 14 deletions(-)

diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 61d227d9..73ce2436 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -3,20 +3,6 @@ name: 'lint'
 on:
   push:
 
-jobs:
-  lint:
-    runs-on: ubuntu-latest
-    steps:
-    - uses: actions/checkout@v4
-    - name: Install dependencies
-      run: |
-        pip install pycodestyle
-        pip install pylint
-    - name: Lint
-      run: |
-        pycodestyle pyfpga examples test
-        pylint pyfpga
-
 jobs:
   lint:
     runs-on: ubuntu-latest

From 73476674de47524c6d6fc9246a9793d294c9e126 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 26 May 2024 09:01:21 -0300
Subject: [PATCH 019/248] ci: updated Makefile and used for the lint action

---
 .github/workflows/lint.yml | 4 +---
 Makefile                   | 8 +++++---
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 73ce2436..5f912102 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -12,6 +12,4 @@ jobs:
     - name: Install dependencies
       run: pip install pycodestyle pylint
     - name: Run linters
-      run: |
-        pycodestyle pyfpga examples test
-        pylint pyfpga
+      run: make lint
diff --git a/Makefile b/Makefile
index 8f1d8dc1..f8f3ca10 100644
--- a/Makefile
+++ b/Makefile
@@ -1,9 +1,11 @@
 #!/usr/bin/make
 
-check:
-	pycodestyle fpga examples test
-	pylint -s n fpga
+lint:
+	pycodestyle pyfpga examples test
+	pylint -s n pyfpga
 	git diff --check --cached
+
+test:
 	pytest test
 
 clean:

From 4d845b679843cfd66df16fa3fe75df794ba3e9f5 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 26 May 2024 13:42:54 -0300
Subject: [PATCH 020/248] Modified project to employ enumerations

---
 pyfpga/project.py | 104 ++++++++++++++++++++++++++--------------------
 1 file changed, 59 insertions(+), 45 deletions(-)

diff --git a/pyfpga/project.py b/pyfpga/project.py
index 881a7187..25da8911 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -10,110 +10,124 @@
 program a device.
 """
 
+from enum import Enum
 from pathlib import Path
 
 TASKS = ['prj', 'elb', 'syn', 'par', 'bit']
 
-TOOLS = [
-    'ghdl',
-    'ise',
-    'libero',
-    'openflow',
-    'quartus',
-    'vivado',
-    'yosys',
-    'yosys-ise',
-    'yosys-vivado'
-]
+
+class Tool(Enum):
+    """Enumeration of supported FPGA tools."""
+    GHDL = 'ghdl'
+    ISE = 'ise'
+    LIBERO = 'libero'
+    OPENFLOW = 'openflow'
+    QUARTUS = 'quartus'
+    VIVADO = 'vivado'
+    YOSYS = 'yosys'
+    YOSYS_ISE = 'yosys-ise'
+    YOSYS_VIVADO = 'yosys-vivado'
+
+
+class Step(Enum):
+    """Enumeration of supported Steps"""
+    PRJ = 'prj'
+    ELB = 'elb'
+    SYN = 'syn'
+    PAR = 'par'
+    BIT = 'bit'
+
+
+class Hook(Enum):
+    """Enumeration of supported Hooks"""
+    PREFILE = 'prefile'
+    PROJECT = 'project'
+    PREFLOW = 'preflow'
+    POSTSYN = 'postsyn'
+    POSTPAR = 'postpar'
+    POSTBIT = 'postbit'
 
 
 class Project:
     """Class to manage an FPGA project.
 
     :param tool: tool name
-    :type tool: str
+    :type tool: Tool
     :param name: project name (tool name by default)
     :type name: str, optional
     :param data: pre-populated data for the project
     :type data: dict, optional
     :param odir: output directory
     :type odir: str, optional
-    :raises NotImplementedError: unsupported tool
-
-    .. note::
-     Supported tool names are:
-     ``ghdl``
-     ``ise``
-     ``libero``
-     ``openflow``
-     ``quartus``
-     ``vivado``
-     ``yosys``
-     ``yosys-ise``
-     ``yosys-vivado``
+    :raises TypeError: when a value is not a valid enum
+    :raises NotImplementedError: when a method is not implemented yet
     """
 
     def __init__(self, tool, name=None, data=None, odir='results'):
         """Class constructor."""
-        if tool not in TOOLS:
-            raise NotImplementedError(f'unsupported tool ({tool}).')
+        if not isinstance(tool, Tool):
+            raise TypeError('tool must be a Tool enum.')
         self.tool = tool
-        self.name = name or tool
+        self.name = name or tool.value
         self.data = data or {}
         self.odir = Path(odir)
         self.odir.mkdir(parents=True, exist_ok=True)
 
     def set_part(self, name):
-        """Templ placeholder"""
+        """Temp placeholder"""
         raise NotImplementedError('Method is not implemented yet.')
 
     def add_file(self, pathname, filetype=None, library=None, options=None):
-        """Templ placeholder"""
+        """Temp placeholder"""
         raise NotImplementedError('Method is not implemented yet.')
 
     def add_vlog(self, pathname, options=None):
-        """Templ placeholder"""
+        """Temp placeholder"""
         self.add_file(pathname, filetype='vlog', options=options)
 
     def add_slog(self, pathname, options=None):
-        """Templ placeholder"""
+        """Temp placeholder"""
         self.add_file(pathname, filetype='slog', options=options)
 
     def add_vhdl(self, pathname, library=None, options=None):
-        """Templ placeholder"""
+        """Temp placeholder"""
         self.add_file(
             pathname, filetype='vhdl',
             library=library, options=options
         )
 
-    def add_param(self, name, value):
-        """Templ placeholder"""
+    def add_include(self, path):
+        """Temp placeholder"""
         raise NotImplementedError('Method is not implemented yet.')
 
-    def add_include(self, path):
-        """Templ placeholder"""
+    def add_param(self, name, value):
+        """Temp placeholder"""
         raise NotImplementedError('Method is not implemented yet.')
 
     def add_define(self, name, value):
-        """Templ placeholder"""
+        """Temp placeholder"""
         raise NotImplementedError('Method is not implemented yet.')
 
     def set_arch(self, name):
-        """Templ placeholder"""
+        """Temp placeholder"""
         raise NotImplementedError('Method is not implemented yet.')
 
     def set_top(self, name):
-        """Templ placeholder"""
+        """Temp placeholder"""
         raise NotImplementedError('Method is not implemented yet.')
 
-    def add_hook(self, stage, hook):
-        """Templ placeholder"""
+    def add_hook(self, hook, content):
+        """Temp placeholder"""
+        # if not isinstance(hook, Hook):
+        #     raise TypeError('hook must be a Hook enum.')
         raise NotImplementedError('Method is not implemented yet.')
 
-    def make(self, last='bit', first='prj', capture=False):
-        """Templ placeholder"""
+    def make(self, end=Step.BIT, start=Step.PRJ, capture=False):
+        """Temp placeholder"""
+        # if not isinstance(end, Step) or not isinstance(start, Step):
+        #     raise TypeError('start and end must be a Step enum.')
         raise NotImplementedError('Method is not implemented yet.')
 
     def prog(self, position=1, bitstream=None):
-        """Templ placeholder"""
+        """Temp placeholder"""
         raise NotImplementedError('Method is not implemented yet.')

From 049af6ba8b6d7654ddbd51ad5a6e26a2ce08eae4 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 26 May 2024 13:43:32 -0300
Subject: [PATCH 021/248] Added docs with the skeleton generated by
 sphinx-quickstart

---
 docs/Makefile  | 20 +++++++++++++++++++
 docs/conf.py   | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++
 docs/index.rst | 20 +++++++++++++++++++
 3 files changed, 92 insertions(+)
 create mode 100644 docs/Makefile
 create mode 100644 docs/conf.py
 create mode 100644 docs/index.rst

diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 00000000..d4bb2cbb
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,20 @@
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line, and also
+# from the environment for the first two.
+SPHINXOPTS    ?=
+SPHINXBUILD   ?= sphinx-build
+SOURCEDIR     = .
+BUILDDIR      = _build
+
+# Put it first so that "make" without argument is like "make help".
+help:
+	@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+.PHONY: help Makefile
+
+# Catch-all target: route all unknown targets to Sphinx using the new
+# "make mode" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).
+%: Makefile
+	@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/docs/conf.py b/docs/conf.py
new file mode 100644
index 00000000..cddcb632
--- /dev/null
+++ b/docs/conf.py
@@ -0,0 +1,52 @@
+# Configuration file for the Sphinx documentation builder.
+#
+# This file only contains a selection of the most common options. For a full
+# list see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+# -- Path setup --------------------------------------------------------------
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#
+# import os
+# import sys
+# sys.path.insert(0, os.path.abspath('.'))
+
+
+# -- Project information -----------------------------------------------------
+
+project = 'PyFPGA'
+copyright = '2024, Rodrigo Alejandro Melo'
+author = 'Rodrigo Alejandro Melo'
+
+
+# -- General configuration ---------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [
+]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This pattern also affects html_static_path and html_extra_path.
+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+
+
+# -- Options for HTML output -------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+#
+html_theme = 'alabaster'
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
\ No newline at end of file
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644
index 00000000..d2be65e2
--- /dev/null
+++ b/docs/index.rst
@@ -0,0 +1,20 @@
+.. PyFPGA documentation master file, created by
+   sphinx-quickstart on Sun May 26 13:21:40 2024.
+   You can adapt this file completely to your liking, but it should at least
+   contain the root `toctree` directive.
+
+Welcome to PyFPGA's documentation!
+==================================
+
+.. toctree::
+   :maxdepth: 2
+   :caption: Contents:
+
+
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`

From 2f67bdeebc6786a8ea6fe39555cbd0c1ebf721f2 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 26 May 2024 13:48:13 -0300
Subject: [PATCH 022/248] ci: updated docs

---
 .github/workflows/docs.yml | 23 +++++++++++++----------
 1 file changed, 13 insertions(+), 10 deletions(-)

diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index a89f8848..a794a243 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -3,17 +3,20 @@ name: 'docs'
 on:
   push:
     branches:
-      - main
+#      - main
 
-.jobs:
-  linux:
+jobs:
+  build:
     runs-on: ubuntu-latest
     steps:
-    - uses: actions/checkout@v2
-    - uses: buildthedocs/btd@v0
+    - name: Checkout repository
+      uses: actions/checkout@v4
+    - name: Install dependencies
+      run: pip install sphinx
+    - name: Build Sphinx documentation
+      run: cd docs; make html
+    - name: Deploy to GitHub Pages
+      uses: peaceiris/actions-gh-pages@v4
       with:
-        token: ${{ secrets.GITHUB_TOKEN }}
-    - uses: actions/upload-artifact@master
-      with:
-        name: doc
-        path: doc/_build/html
+        github_token: ${{ secrets.GITHUB_TOKEN }}
+        publish_dir: docs/_build/html

From 35534ebb012007b1f6456e8540c819bec60e8cfe Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 26 May 2024 15:40:46 -0300
Subject: [PATCH 023/248] Moved content from doc/images into docs/images and
 docs/_static

---
 {doc/images => docs/_static}/logo.png   | Bin
 {doc/images => docs/_static}/schema.png | Bin
 {doc => docs}/images/images.fodg        |   0
 {doc => docs}/images/logo.fodg          |   0
 4 files changed, 0 insertions(+), 0 deletions(-)
 rename {doc/images => docs/_static}/logo.png (100%)
 rename {doc/images => docs/_static}/schema.png (100%)
 rename {doc => docs}/images/images.fodg (100%)
 rename {doc => docs}/images/logo.fodg (100%)

diff --git a/doc/images/logo.png b/docs/_static/logo.png
similarity index 100%
rename from doc/images/logo.png
rename to docs/_static/logo.png
diff --git a/doc/images/schema.png b/docs/_static/schema.png
similarity index 100%
rename from doc/images/schema.png
rename to docs/_static/schema.png
diff --git a/doc/images/images.fodg b/docs/images/images.fodg
similarity index 100%
rename from doc/images/images.fodg
rename to docs/images/images.fodg
diff --git a/doc/images/logo.fodg b/docs/images/logo.fodg
similarity index 100%
rename from doc/images/logo.fodg
rename to docs/images/logo.fodg

From fe579279e7b277473732fbbd1303fbecefeceaf3 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 26 May 2024 15:41:16 -0300
Subject: [PATCH 024/248] Moved doc contento to docs/wip

---
 doc/api.rst                        | 8 --------
 {doc => docs/wip}/Makefile         | 0
 {doc => docs/wip}/advanced.rst     | 0
 {doc => docs/wip}/basic.rst        | 0
 {doc => docs/wip}/conf.py          | 0
 {doc => docs/wip}/dev.rst          | 0
 {doc => docs/wip}/index.rst        | 0
 {doc => docs/wip}/intro.rst        | 2 +-
 {doc => docs/wip}/requirements.txt | 0
 {doc => docs/wip}/tools.rst        | 0
 10 files changed, 1 insertion(+), 9 deletions(-)
 delete mode 100644 doc/api.rst
 rename {doc => docs/wip}/Makefile (100%)
 rename {doc => docs/wip}/advanced.rst (100%)
 rename {doc => docs/wip}/basic.rst (100%)
 rename {doc => docs/wip}/conf.py (100%)
 rename {doc => docs/wip}/dev.rst (100%)
 rename {doc => docs/wip}/index.rst (100%)
 rename {doc => docs/wip}/intro.rst (98%)
 rename {doc => docs/wip}/requirements.txt (100%)
 rename {doc => docs/wip}/tools.rst (100%)

diff --git a/doc/api.rst b/doc/api.rst
deleted file mode 100644
index 1be17600..00000000
--- a/doc/api.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-.. program:: pyfpga
-
-.. _api:
-
-API Reference
-#############
-
-.. automodule:: fpga.project
diff --git a/doc/Makefile b/docs/wip/Makefile
similarity index 100%
rename from doc/Makefile
rename to docs/wip/Makefile
diff --git a/doc/advanced.rst b/docs/wip/advanced.rst
similarity index 100%
rename from doc/advanced.rst
rename to docs/wip/advanced.rst
diff --git a/doc/basic.rst b/docs/wip/basic.rst
similarity index 100%
rename from doc/basic.rst
rename to docs/wip/basic.rst
diff --git a/doc/conf.py b/docs/wip/conf.py
similarity index 100%
rename from doc/conf.py
rename to docs/wip/conf.py
diff --git a/doc/dev.rst b/docs/wip/dev.rst
similarity index 100%
rename from doc/dev.rst
rename to docs/wip/dev.rst
diff --git a/doc/index.rst b/docs/wip/index.rst
similarity index 100%
rename from doc/index.rst
rename to docs/wip/index.rst
diff --git a/doc/intro.rst b/docs/wip/intro.rst
similarity index 98%
rename from doc/intro.rst
rename to docs/wip/intro.rst
index 67c8e087..b10d326a 100644
--- a/doc/intro.rst
+++ b/docs/wip/intro.rst
@@ -84,4 +84,4 @@ Detailed support
 Next Steps
 ----------
 
-You can read the :ref:`basic` and :ref:`advanced` sections, check the detailed :ref:`api` or start with the available :repo:`Examples <examples>`.
+You can read the :ref:`basic` and :ref:`advanced` sections, check the detailed :ref:`api` or start with the available :repositoy:`Examples <examples>`.
diff --git a/doc/requirements.txt b/docs/wip/requirements.txt
similarity index 100%
rename from doc/requirements.txt
rename to docs/wip/requirements.txt
diff --git a/doc/tools.rst b/docs/wip/tools.rst
similarity index 100%
rename from doc/tools.rst
rename to docs/wip/tools.rst

From 0717dc143b9d722da00512d49c69220fb7685ec1 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 26 May 2024 15:43:08 -0300
Subject: [PATCH 025/248] docs: added intro (empty) and api (automodule)

---
 docs/api.rst   |  6 ++++++
 docs/conf.py   | 45 +++++++++++++++++----------------------------
 docs/index.rst | 26 ++++++++++----------------
 docs/intro.rst |  4 ++++
 4 files changed, 37 insertions(+), 44 deletions(-)
 create mode 100644 docs/api.rst
 create mode 100644 docs/intro.rst

diff --git a/docs/api.rst b/docs/api.rst
new file mode 100644
index 00000000..b3e29cd3
--- /dev/null
+++ b/docs/api.rst
@@ -0,0 +1,6 @@
+.. program:: pyfpga
+
+API Reference
+=============
+
+.. automodule:: pyfpga.project
diff --git a/docs/conf.py b/docs/conf.py
index cddcb632..10511f00 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -1,19 +1,4 @@
-# Configuration file for the Sphinx documentation builder.
-#
-# This file only contains a selection of the most common options. For a full
-# list see the documentation:
-# https://www.sphinx-doc.org/en/master/usage/configuration.html
-
-# -- Path setup --------------------------------------------------------------
-
-# If extensions (or modules to document with autodoc) are in another directory,
-# add these directories to sys.path here. If the directory is relative to the
-# documentation root, use os.path.abspath to make it absolute, like shown here.
-#
-# import os
-# import sys
-# sys.path.insert(0, os.path.abspath('.'))
-
+# -*- coding: utf-8 -*-
 
 # -- Project information -----------------------------------------------------
 
@@ -21,32 +6,36 @@
 copyright = '2024, Rodrigo Alejandro Melo'
 author = 'Rodrigo Alejandro Melo'
 
-
 # -- General configuration ---------------------------------------------------
 
-# Add any Sphinx extension module names here, as strings. They can be
-# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
-# ones.
 extensions = [
+    'sphinx.ext.autodoc',
+    'sphinx.ext.extlinks',
+    'sphinx.ext.intersphinx',
+    'sphinx.ext.todo',
+    'sphinx.ext.viewcode',
 ]
 
-# Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
+autodoc_default_options = {
+    "members": True,
+    'undoc-members': True,
+    'inherited-members': True,
+}
 
-# List of patterns, relative to source directory, that match files and
-# directories to ignore when looking for source files.
-# This pattern also affects html_static_path and html_extra_path.
-exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+extlinks = {
+   'repositoy': ('https://github.com/PyFPGA/pyfpga/tree/main/%s', None)
+}
 
+exclude_patterns = ['_build', 'wip']
 
 # -- Options for HTML output -------------------------------------------------
 
 # The theme to use for HTML and HTML Help pages.  See the documentation for
 # a list of builtin themes.
 #
-html_theme = 'alabaster'
+html_theme = 'sphinx_rtd_theme'
 
 # Add any paths that contain custom static files (such as style sheets) here,
 # relative to this directory. They are copied after the builtin static files,
 # so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
\ No newline at end of file
+html_static_path = ['_static']
diff --git a/docs/index.rst b/docs/index.rst
index d2be65e2..2c9d734c 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -1,20 +1,14 @@
-.. PyFPGA documentation master file, created by
-   sphinx-quickstart on Sun May 26 13:21:40 2024.
-   You can adapt this file completely to your liking, but it should at least
-   contain the root `toctree` directive.
+.. program:: pyfpga
 
-Welcome to PyFPGA's documentation!
-==================================
-
-.. toctree::
-   :maxdepth: 2
-   :caption: Contents:
+PyFPGA's documentation
+======================
 
+.. image:: _static/logo.png
+   :width: 200 px
+   :align: center
+   :target: https://github.com/PyFPGA/pyfpga
 
+.. toctree::
 
-Indices and tables
-==================
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
+   intro
+   api
diff --git a/docs/intro.rst b/docs/intro.rst
new file mode 100644
index 00000000..63b4e29e
--- /dev/null
+++ b/docs/intro.rst
@@ -0,0 +1,4 @@
+.. program:: pyfpga
+
+Introduction
+============

From 33bfdcc0a3c949d377b4ca2063810d89fcb8ab78 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 26 May 2024 15:43:34 -0300
Subject: [PATCH 026/248] ci: updated/enabled docs

---
 .github/workflows/docs.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index a794a243..c1dabef5 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -12,7 +12,7 @@ jobs:
     - name: Checkout repository
       uses: actions/checkout@v4
     - name: Install dependencies
-      run: pip install sphinx
+      run: pip install sphinx sphinx-rtd-theme
     - name: Build Sphinx documentation
       run: cd docs; make html
     - name: Deploy to GitHub Pages

From ece35b05f221a95f68d922be5bd284cdba27e1da Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 26 May 2024 15:43:54 -0300
Subject: [PATCH 027/248] Removed unused config files

---
 .btd.yml  |  5 -----
 .pylintrc | 16 ----------------
 2 files changed, 21 deletions(-)
 delete mode 100644 .btd.yml
 delete mode 100644 .pylintrc

diff --git a/.btd.yml b/.btd.yml
deleted file mode 100644
index a9be9d62..00000000
--- a/.btd.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-input: doc
-output: _build
-target: gh-pages
-formats: [ html ]
-theme: https://codeload.github.com/buildthedocs/sphinx.theme/tar.gz/v0
diff --git a/.pylintrc b/.pylintrc
deleted file mode 100644
index 40d501d1..00000000
--- a/.pylintrc
+++ /dev/null
@@ -1,16 +0,0 @@
-[MASTER]
-ignore=ignore
-jobs=0
-suggestion-mode=yes
-
-[REPORTS]
-score=no
-
-[MESSAGES CONTROL]
-disable=duplicate-code,
-        import-outside-toplevel,
-        raise-missing-from,
-        too-many-arguments,
-        too-many-branches,
-        too-many-instance-attributes,
-        too-many-locals

From c2957c0740a4f41857be713e88c22a3d76777943 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 26 May 2024 15:47:57 -0300
Subject: [PATCH 028/248] ci: updated docs and lint to be similar

---
 .github/workflows/docs.yml | 4 ++--
 .github/workflows/lint.yml | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index c1dabef5..0db33e9b 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -6,14 +6,14 @@ on:
 #      - main
 
 jobs:
-  build:
+  docs:
     runs-on: ubuntu-latest
     steps:
     - name: Checkout repository
       uses: actions/checkout@v4
     - name: Install dependencies
       run: pip install sphinx sphinx-rtd-theme
-    - name: Build Sphinx documentation
+    - name: Build documentation
       run: cd docs; make html
     - name: Deploy to GitHub Pages
       uses: peaceiris/actions-gh-pages@v4
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 5f912102..3907a5c4 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -7,7 +7,7 @@ jobs:
   lint:
     runs-on: ubuntu-latest
     steps:
-    - name: Checkout code
+    - name: Checkout repository
       uses: actions/checkout@v4
     - name: Install dependencies
       run: pip install pycodestyle pylint

From 3d29a99c2f854764074716a54783449da606b673 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 26 May 2024 15:55:30 -0300
Subject: [PATCH 029/248] docs: fixed to find pyfpga.project

---
 docs/conf.py | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/docs/conf.py b/docs/conf.py
index 10511f00..3e57d268 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -1,5 +1,10 @@
 # -*- coding: utf-8 -*-
 
+import sys, re
+from pathlib import Path
+
+sys.path.insert(0, str(Path.cwd().resolve().parent))
+
 # -- Project information -----------------------------------------------------
 
 project = 'PyFPGA'
@@ -30,12 +35,5 @@
 
 # -- Options for HTML output -------------------------------------------------
 
-# The theme to use for HTML and HTML Help pages.  See the documentation for
-# a list of builtin themes.
-#
 html_theme = 'sphinx_rtd_theme'
-
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
 html_static_path = ['_static']

From fa24be14db12618a4632b68125d29f7493d7d3a9 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 26 May 2024 19:25:14 -0300
Subject: [PATCH 030/248] Implemented some simple methods of project.py

---
 Makefile          |  4 +++-
 pyfpga/project.py | 22 ++++++++++++++--------
 test/test_data.py | 38 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 55 insertions(+), 9 deletions(-)
 create mode 100644 test/test_data.py

diff --git a/Makefile b/Makefile
index f8f3ca10..ca7165f0 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,7 @@
 #!/usr/bin/make
 
+.PHONY: test
+
 lint:
 	pycodestyle pyfpga examples test
 	pylint -s n pyfpga
@@ -13,4 +15,4 @@ clean:
 	rm -fr build .pytest_cache
 
 submodule:
-	 git submodule update --init
+	git submodule update --init
diff --git a/pyfpga/project.py b/pyfpga/project.py
index 25da8911..778df51f 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -13,8 +13,6 @@
 from enum import Enum
 from pathlib import Path
 
-TASKS = ['prj', 'elb', 'syn', 'par', 'bit']
-
 
 class Tool(Enum):
     """Enumeration of supported FPGA tools."""
@@ -67,6 +65,8 @@ def __init__(self, tool, name=None, data=None, odir='results'):
         """Class constructor."""
         if not isinstance(tool, Tool):
             raise TypeError('tool must be a Tool enum.')
+        if data and not isinstance(data, dict):
+            raise TypeError('data must be a dict.')
         self.tool = tool
         self.name = name or tool.value
         self.data = data or {}
@@ -75,7 +75,7 @@ def __init__(self, tool, name=None, data=None, odir='results'):
 
     def set_part(self, name):
         """Temp placeholder"""
-        raise NotImplementedError('Method is not implemented yet.')
+        self.data['part'] = name
 
     def add_file(self, pathname, filetype=None, library=None, options=None):
         """Temp placeholder"""
@@ -98,23 +98,29 @@ def add_vhdl(self, pathname, library=None, options=None):
 
     def add_include(self, path):
         """Temp placeholder"""
-        raise NotImplementedError('Method is not implemented yet.')
+        if 'includes' not in self.data:
+            self.data['includes'] = []
+        self.data['includes'].append(path)
 
     def add_param(self, name, value):
         """Temp placeholder"""
-        raise NotImplementedError('Method is not implemented yet.')
+        if 'params' not in self.data:
+            self.data['params'] = {}
+        self.data['params'][name] = value
 
     def add_define(self, name, value):
         """Temp placeholder"""
-        raise NotImplementedError('Method is not implemented yet.')
+        if 'defines' not in self.data:
+            self.data['defines'] = {}
+        self.data['defines'][name] = value
 
     def set_arch(self, name):
         """Temp placeholder"""
-        raise NotImplementedError('Method is not implemented yet.')
+        self.data['arch'] = name
 
     def set_top(self, name):
         """Temp placeholder"""
-        raise NotImplementedError('Method is not implemented yet.')
+        self.data['top'] = name
 
     def add_hook(self, hook, content):
         """Temp placeholder"""
diff --git a/test/test_data.py b/test/test_data.py
new file mode 100644
index 00000000..b1d03546
--- /dev/null
+++ b/test/test_data.py
@@ -0,0 +1,38 @@
+import os
+import pytest
+
+from pyfpga.project import Project, Tool
+
+pattern = {
+    'part': 'PARTNAME',
+    'top': 'TOPNAME',
+    'arch': 'ARCHNAME',
+    'includes': ['INC1', 'INC2', 'INC3'],
+    'params': {
+        'PARAM1': 'VALUE1',
+        'PARAM2': 'VALUE2',
+        'PARAM3': 'VALUE3'
+    },
+    'defines': {
+        'DEF1': 'VALUE1',
+        'DEF2': 'VALUE2',
+        'DEF3': 'VALUE3'
+    },
+}
+
+
+def test_names():
+    prj = Project(Tool.VIVADO)
+    prj.set_part('PARTNAME')
+    prj.set_top('TOPNAME')
+    prj.set_arch('ARCHNAME')
+    prj.add_include('INC1')
+    prj.add_include('INC2')
+    prj.add_include('INC3')
+    prj.add_param('PARAM1', 'VALUE1')
+    prj.add_param('PARAM2', 'VALUE2')
+    prj.add_param('PARAM3', 'VALUE3')
+    prj.add_define('DEF1', 'VALUE1')
+    prj.add_define('DEF2', 'VALUE2')
+    prj.add_define('DEF3', 'VALUE3')
+    assert prj.data == pattern, 'ERROR: unexpected data'

From c545884c04d2e717e7ca1dd27d60d8035432dbdb Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 26 May 2024 19:25:33 -0300
Subject: [PATCH 031/248] ci: simplified/enabled test

---
 .github/workflows/test.yml   | 26 ++++++--------------------
 Makefile                     |  2 +-
 {fpga => pyfpga}/__init__.py |  2 --
 3 files changed, 7 insertions(+), 23 deletions(-)
 rename {fpga => pyfpga}/__init__.py (54%)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 25761f18..7581de65 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -2,40 +2,26 @@ name: 'test'
 
 on:
   push:
-  pull_request:
-  schedule: # Run once a week to ensure tests pass with updated dependencies
-    - cron: '0 0 * * 6'
 
-.jobs:
+jobs:
   test:
     strategy:
       matrix:
         os: ['ubuntu']
-        pyver: ['3.6', '3.7', '3.8', '3.9', '3.10']
+        pyver: [3.8, 3.9, 3.10, 3.11, 3.12]
     runs-on: ${{ matrix.os }}-latest
     name: ${{ matrix.os }} | ${{ matrix.pyver }}
     steps:
-    - uses: actions/checkout@v2
+    - name: Checkout repository
+      uses: actions/checkout@v4
       with:
         submodules: true
         fetch-depth: 0
-    - name: Pull container images
-      run: |
-        docker pull hdlc/ghdl:yosys
-        docker pull hdlc/nextpnr:ice40
-        docker pull hdlc/nextpnr:ecp5
-        docker pull hdlc/icestorm
-        docker pull hdlc/prjtrellis
     - name: Set up Python ${{ matrix.pyver }}
-      uses: actions/setup-python@v2
+      uses: actions/setup-python@v5
       with:
         python-version: ${{ matrix.pyver }}
     - name: Install dependencies
-      run: |
-        pip install pytest
-        pip install .
+      run: pip install pytest
     - name: Run test
       run: pytest
-    - name: Run examples
-      run: |
-        cd examples; make MOCKS=1
diff --git a/Makefile b/Makefile
index ca7165f0..0302d56e 100644
--- a/Makefile
+++ b/Makefile
@@ -8,7 +8,7 @@ lint:
 	git diff --check --cached
 
 test:
-	pytest test
+	pytest
 
 clean:
 	py3clean .
diff --git a/fpga/__init__.py b/pyfpga/__init__.py
similarity index 54%
rename from fpga/__init__.py
rename to pyfpga/__init__.py
index bd3bc779..b9bae46e 100644
--- a/fpga/__init__.py
+++ b/pyfpga/__init__.py
@@ -1,5 +1,3 @@
 """PyFPGA"""
 
 __version__ = '0.3.0-dev'
-
-from fpga.project import Project

From d886fb30c58df9623847c734fcedc52a83a9bb94 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 27 May 2024 22:33:55 -0300
Subject: [PATCH 032/248] Added the target docs at Makefile

---
 .github/workflows/docs.yml | 2 +-
 Makefile                   | 6 +++++-
 docs/api.rst               | 2 --
 docs/index.rst             | 2 --
 docs/intro.rst             | 2 --
 5 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 0db33e9b..26c51962 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -14,7 +14,7 @@ jobs:
     - name: Install dependencies
       run: pip install sphinx sphinx-rtd-theme
     - name: Build documentation
-      run: cd docs; make html
+      run: make docs
     - name: Deploy to GitHub Pages
       uses: peaceiris/actions-gh-pages@v4
       with:
diff --git a/Makefile b/Makefile
index 0302d56e..afcec92e 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,9 @@
 #!/usr/bin/make
 
-.PHONY: test
+.PHONY: docs test
+
+docs:
+	cd docs; make html
 
 lint:
 	pycodestyle pyfpga examples test
@@ -12,6 +15,7 @@ test:
 
 clean:
 	py3clean .
+	cd docs; make clean
 	rm -fr build .pytest_cache
 
 submodule:
diff --git a/docs/api.rst b/docs/api.rst
index b3e29cd3..ef62c294 100644
--- a/docs/api.rst
+++ b/docs/api.rst
@@ -1,5 +1,3 @@
-.. program:: pyfpga
-
 API Reference
 =============
 
diff --git a/docs/index.rst b/docs/index.rst
index 2c9d734c..dd21b211 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -1,5 +1,3 @@
-.. program:: pyfpga
-
 PyFPGA's documentation
 ======================
 
diff --git a/docs/intro.rst b/docs/intro.rst
index 63b4e29e..c516b331 100644
--- a/docs/intro.rst
+++ b/docs/intro.rst
@@ -1,4 +1,2 @@
-.. program:: pyfpga
-
 Introduction
 ============

From 5d798be15dff72c813eec46cd54a946d442d5555 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 27 May 2024 22:37:50 -0300
Subject: [PATCH 033/248] Renamed test to tests

---
 .github/workflows/test.yml        | 4 ++--
 Makefile                          | 4 ++--
 {test => tests}/mocks/impact      | 0
 {test => tests}/mocks/libero      | 0
 {test => tests}/mocks/quartus_pgm | 0
 {test => tests}/mocks/quartus_sh  | 0
 {test => tests}/mocks/vivado      | 0
 {test => tests}/mocks/xtclsh      | 0
 {test => tests}/test_data.py      | 0
 {test => tests}/test_files.py     | 0
 {test => tests}/test_part.py      | 0
 {test => tests}/test_top.py       | 0
 12 files changed, 4 insertions(+), 4 deletions(-)
 rename {test => tests}/mocks/impact (100%)
 rename {test => tests}/mocks/libero (100%)
 rename {test => tests}/mocks/quartus_pgm (100%)
 rename {test => tests}/mocks/quartus_sh (100%)
 rename {test => tests}/mocks/vivado (100%)
 rename {test => tests}/mocks/xtclsh (100%)
 rename {test => tests}/test_data.py (100%)
 rename {test => tests}/test_files.py (100%)
 rename {test => tests}/test_part.py (100%)
 rename {test => tests}/test_top.py (100%)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 7581de65..6cd55c21 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -23,5 +23,5 @@ jobs:
         python-version: ${{ matrix.pyver }}
     - name: Install dependencies
       run: pip install pytest
-    - name: Run test
-      run: pytest
+    - name: Run tests
+      run: make test
diff --git a/Makefile b/Makefile
index afcec92e..3e3d9555 100644
--- a/Makefile
+++ b/Makefile
@@ -1,12 +1,12 @@
 #!/usr/bin/make
 
-.PHONY: docs test
+.PHONY: docs
 
 docs:
 	cd docs; make html
 
 lint:
-	pycodestyle pyfpga examples test
+	pycodestyle pyfpga examples tests
 	pylint -s n pyfpga
 	git diff --check --cached
 
diff --git a/test/mocks/impact b/tests/mocks/impact
similarity index 100%
rename from test/mocks/impact
rename to tests/mocks/impact
diff --git a/test/mocks/libero b/tests/mocks/libero
similarity index 100%
rename from test/mocks/libero
rename to tests/mocks/libero
diff --git a/test/mocks/quartus_pgm b/tests/mocks/quartus_pgm
similarity index 100%
rename from test/mocks/quartus_pgm
rename to tests/mocks/quartus_pgm
diff --git a/test/mocks/quartus_sh b/tests/mocks/quartus_sh
similarity index 100%
rename from test/mocks/quartus_sh
rename to tests/mocks/quartus_sh
diff --git a/test/mocks/vivado b/tests/mocks/vivado
similarity index 100%
rename from test/mocks/vivado
rename to tests/mocks/vivado
diff --git a/test/mocks/xtclsh b/tests/mocks/xtclsh
similarity index 100%
rename from test/mocks/xtclsh
rename to tests/mocks/xtclsh
diff --git a/test/test_data.py b/tests/test_data.py
similarity index 100%
rename from test/test_data.py
rename to tests/test_data.py
diff --git a/test/test_files.py b/tests/test_files.py
similarity index 100%
rename from test/test_files.py
rename to tests/test_files.py
diff --git a/test/test_part.py b/tests/test_part.py
similarity index 100%
rename from test/test_part.py
rename to tests/test_part.py
diff --git a/test/test_top.py b/tests/test_top.py
similarity index 100%
rename from test/test_top.py
rename to tests/test_top.py

From 833cb4ae3a836d22290b70c7b87498320a66771e Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 27 May 2024 23:03:58 -0300
Subject: [PATCH 034/248] Removed tool and data from Project

---
 pyfpga/project.py  | 41 ++++++-----------------------------------
 tests/test_data.py |  4 ++--
 2 files changed, 8 insertions(+), 37 deletions(-)

diff --git a/pyfpga/project.py b/pyfpga/project.py
index 778df51f..a963bea7 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -4,29 +4,14 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-"""pyfpga.project
-This module implements the entry-point of PyFPGA, which provides
-functionalities to create a project, generate a bitstream and
-program a device.
+"""
+Base class that implements agnostic methods to deal with FPGA projects.
 """
 
 from enum import Enum
 from pathlib import Path
 
 
-class Tool(Enum):
-    """Enumeration of supported FPGA tools."""
-    GHDL = 'ghdl'
-    ISE = 'ise'
-    LIBERO = 'libero'
-    OPENFLOW = 'openflow'
-    QUARTUS = 'quartus'
-    VIVADO = 'vivado'
-    YOSYS = 'yosys'
-    YOSYS_ISE = 'yosys-ise'
-    YOSYS_VIVADO = 'yosys-vivado'
-
-
 class Step(Enum):
     """Enumeration of supported Steps"""
     PRJ = 'prj'
@@ -47,29 +32,19 @@ class Hook(Enum):
 
 
 class Project:
-    """Class to manage an FPGA project.
+    """Base class to manage an FPGA project.
 
-    :param tool: tool name
-    :type tool: Tool
     :param name: project name (tool name by default)
     :type name: str, optional
-    :param data: pre-populated data for the project
-    :type data: dict, optional
     :param odir: output directory
     :type odir: str, optional
-    :raises TypeError: when a value is not a valid enum
     :raises NotImplementedError: when a method is not implemented yet
     """
 
-    def __init__(self, tool, name=None, data=None, odir='results'):
+    def __init__(self, name=None, odir='results'):
         """Class constructor."""
-        if not isinstance(tool, Tool):
-            raise TypeError('tool must be a Tool enum.')
-        if data and not isinstance(data, dict):
-            raise TypeError('data must be a dict.')
-        self.tool = tool
-        self.name = name or tool.value
-        self.data = data or {}
+        self.data = {}
+        self.name = name
         self.odir = Path(odir)
         self.odir.mkdir(parents=True, exist_ok=True)
 
@@ -124,14 +99,10 @@ def set_top(self, name):
 
     def add_hook(self, hook, content):
         """Temp placeholder"""
-        # if not isinstance(hook, Hook):
-        #     raise TypeError('hook must be a Hook enum.')
         raise NotImplementedError('Method is not implemented yet.')
 
     def make(self, end=Step.BIT, start=Step.PRJ, capture=False):
         """Temp placeholder"""
-        # if not isinstance(end, Step) or not isinstance(start, Step):
-        #     raise TypeError('start and end must be a Step enum.')
         raise NotImplementedError('Method is not implemented yet.')
 
     def prog(self, position=1, bitstream=None):
diff --git a/tests/test_data.py b/tests/test_data.py
index b1d03546..e603af21 100644
--- a/tests/test_data.py
+++ b/tests/test_data.py
@@ -1,7 +1,7 @@
 import os
 import pytest
 
-from pyfpga.project import Project, Tool
+from pyfpga.project import Project
 
 pattern = {
     'part': 'PARTNAME',
@@ -22,7 +22,7 @@
 
 
 def test_names():
-    prj = Project(Tool.VIVADO)
+    prj = Project()
     prj.set_part('PARTNAME')
     prj.set_top('TOPNAME')
     prj.set_arch('ARCHNAME')

From 292e6ea4560111eb90082818fc1eddcf62f80976 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 27 May 2024 23:12:19 -0300
Subject: [PATCH 035/248] ci: attempt to fix test

---
 .github/workflows/test.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 6cd55c21..061381db 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -8,7 +8,7 @@ jobs:
     strategy:
       matrix:
         os: ['ubuntu']
-        pyver: [3.8, 3.9, 3.10, 3.11, 3.12]
+        pyver: ['3.8', '3.9', '3.10', '3.11', '3.12']
     runs-on: ${{ matrix.os }}-latest
     name: ${{ matrix.os }} | ${{ matrix.pyver }}
     steps:

From 13b5169914db1956096d45b5ba929f7cff33fd7e Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 27 May 2024 23:38:30 -0300
Subject: [PATCH 036/248] Added add_cons for constraint files

---
 pyfpga/project.py | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/pyfpga/project.py b/pyfpga/project.py
index a963bea7..231fcb2c 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -56,9 +56,9 @@ def add_file(self, pathname, filetype=None, library=None, options=None):
         """Temp placeholder"""
         raise NotImplementedError('Method is not implemented yet.')
 
-    def add_vlog(self, pathname, options=None):
+    def add_cons(self, pathname, options=None):
         """Temp placeholder"""
-        self.add_file(pathname, filetype='vlog', options=options)
+        self.add_file(pathname, filetype='cons', options=options)
 
     def add_slog(self, pathname, options=None):
         """Temp placeholder"""
@@ -71,6 +71,10 @@ def add_vhdl(self, pathname, library=None, options=None):
             library=library, options=options
         )
 
+    def add_vlog(self, pathname, options=None):
+        """Temp placeholder"""
+        self.add_file(pathname, filetype='vlog', options=options)
+
     def add_include(self, path):
         """Temp placeholder"""
         if 'includes' not in self.data:

From f6958f6f90ef478e7e66814eab6572dfa4377dad Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Tue, 28 May 2024 21:40:51 -0300
Subject: [PATCH 037/248] Added logging into the new Project class and an
 example

---
 examples/misc/logging.py | 25 +++++++++++++++++++++++++
 pyfpga/project.py        | 16 ++++++++++++++++
 2 files changed, 41 insertions(+)
 create mode 100644 examples/misc/logging.py

diff --git a/examples/misc/logging.py b/examples/misc/logging.py
new file mode 100644
index 00000000..55a214c7
--- /dev/null
+++ b/examples/misc/logging.py
@@ -0,0 +1,25 @@
+"""
+This script demonstrates how to utilize the logging functionality within the
+pyfpga package. The following steps are covered:
+
+1. Creating an instance of the Project class.
+2. Testing logging with the default INFO level.
+3. Setting the logging level to DEBUG to capture more detailed information.
+4. Disabling logging by removing all handlers.
+
+Usage:
+- By default, the logger captures messages with level INFO and higher.
+- To see more detailed debug information, set the logger level to DEBUG.
+- To disable logging, remove all handlers from the logger.
+"""
+
+import logging
+
+from pyfpga.project import Project
+
+prj = Project()
+prj._test_logging()
+prj.logger.setLevel(logging.DEBUG)
+prj._test_logging()
+prj.logger.handlers = []
+prj._test_logging()
diff --git a/pyfpga/project.py b/pyfpga/project.py
index 231fcb2c..61d772f5 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -8,6 +8,8 @@
 Base class that implements agnostic methods to deal with FPGA projects.
 """
 
+import logging
+
 from enum import Enum
 from pathlib import Path
 
@@ -47,6 +49,16 @@ def __init__(self, name=None, odir='results'):
         self.name = name
         self.odir = Path(odir)
         self.odir.mkdir(parents=True, exist_ok=True)
+        # logging config
+        self.logger = logging.getLogger(self.__class__.__name__)
+        self.logger.setLevel(logging.INFO)
+        handler = logging.StreamHandler()
+        formatter = logging.Formatter(
+            '%(asctime)s - %(levelname)s - %(message)s',
+            datefmt='%Y-%m-%d %H:%M:%S'
+        )
+        handler.setFormatter(formatter)
+        self.logger.addHandler(handler)
 
     def set_part(self, name):
         """Temp placeholder"""
@@ -112,3 +124,7 @@ def make(self, end=Step.BIT, start=Step.PRJ, capture=False):
     def prog(self, position=1, bitstream=None):
         """Temp placeholder"""
         raise NotImplementedError('Method is not implemented yet.')
+
+    def _test_logging(self):
+        self.logger.info('It is an INFO message')
+        self.logger.debug('It is anDEBUG message')

From 9bcc17074d295e622a54f0569794a63c5248fb11 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Tue, 28 May 2024 21:48:41 -0300
Subject: [PATCH 038/248] Added a Makefile target to update the resources
 module

---
 Makefile | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 3e3d9555..351413fc 100644
--- a/Makefile
+++ b/Makefile
@@ -18,5 +18,8 @@ clean:
 	cd docs; make clean
 	rm -fr build .pytest_cache
 
-submodule:
+submodule-init:
 	git submodule update --init
+
+submodule-update:
+	cd resources; git checkout main; git pull

From 1b2fbe97d43dbe5d883577c43b28ea2c9b57faf9 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Tue, 28 May 2024 23:30:36 -0300
Subject: [PATCH 039/248] Renamed logging.py as logger.py (examples/misc) to
 avoid circular dependencies

---
 examples/misc/{logging.py => logger.py} |  6 +++---
 pyfpga/project.py                       | 14 ++++++++++----
 2 files changed, 13 insertions(+), 7 deletions(-)
 rename examples/misc/{logging.py => logger.py} (90%)

diff --git a/examples/misc/logging.py b/examples/misc/logger.py
similarity index 90%
rename from examples/misc/logging.py
rename to examples/misc/logger.py
index 55a214c7..7f34ca1c 100644
--- a/examples/misc/logging.py
+++ b/examples/misc/logger.py
@@ -18,8 +18,8 @@
 from pyfpga.project import Project
 
 prj = Project()
-prj._test_logging()
+prj.set_part('EXAMPLE')
 prj.logger.setLevel(logging.DEBUG)
-prj._test_logging()
+prj.set_part('EXAMPLE')
 prj.logger.handlers = []
-prj._test_logging()
+prj.set_part('EXAMPLE')
diff --git a/pyfpga/project.py b/pyfpga/project.py
index 61d772f5..59a9e016 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -62,6 +62,7 @@ def __init__(self, name=None, odir='results'):
 
     def set_part(self, name):
         """Temp placeholder"""
+        self.logger.debug('Executing set_part')
         self.data['part'] = name
 
     def add_file(self, pathname, filetype=None, library=None, options=None):
@@ -70,14 +71,17 @@ def add_file(self, pathname, filetype=None, library=None, options=None):
 
     def add_cons(self, pathname, options=None):
         """Temp placeholder"""
+        self.logger.debug('Executing add_cons')
         self.add_file(pathname, filetype='cons', options=options)
 
     def add_slog(self, pathname, options=None):
         """Temp placeholder"""
+        self.logger.debug('Executing add_slog')
         self.add_file(pathname, filetype='slog', options=options)
 
     def add_vhdl(self, pathname, library=None, options=None):
         """Temp placeholder"""
+        self.logger.debug('Executing add_vhdl')
         self.add_file(
             pathname, filetype='vhdl',
             library=library, options=options
@@ -85,32 +89,38 @@ def add_vhdl(self, pathname, library=None, options=None):
 
     def add_vlog(self, pathname, options=None):
         """Temp placeholder"""
+        self.logger.debug('Executing add_vlog')
         self.add_file(pathname, filetype='vlog', options=options)
 
     def add_include(self, path):
         """Temp placeholder"""
+        self.logger.debug('Executing add_include')
         if 'includes' not in self.data:
             self.data['includes'] = []
         self.data['includes'].append(path)
 
     def add_param(self, name, value):
         """Temp placeholder"""
+        self.logger.debug('Executing add_param')
         if 'params' not in self.data:
             self.data['params'] = {}
         self.data['params'][name] = value
 
     def add_define(self, name, value):
         """Temp placeholder"""
+        self.logger.debug('Executing add_define')
         if 'defines' not in self.data:
             self.data['defines'] = {}
         self.data['defines'][name] = value
 
     def set_arch(self, name):
         """Temp placeholder"""
+        self.logger.debug('Executing set_arch')
         self.data['arch'] = name
 
     def set_top(self, name):
         """Temp placeholder"""
+        self.logger.debug('Executing set_top')
         self.data['top'] = name
 
     def add_hook(self, hook, content):
@@ -124,7 +134,3 @@ def make(self, end=Step.BIT, start=Step.PRJ, capture=False):
     def prog(self, position=1, bitstream=None):
         """Temp placeholder"""
         raise NotImplementedError('Method is not implemented yet.')
-
-    def _test_logging(self):
-        self.logger.info('It is an INFO message')
-        self.logger.debug('It is anDEBUG message')

From abbb2b577891ab758b636487fddd7a6801151e9e Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Wed, 29 May 2024 23:11:27 -0300
Subject: [PATCH 040/248] Added a private method to run the underlaying tool

---
 pyfpga/project.py | 42 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 40 insertions(+), 2 deletions(-)

diff --git a/pyfpga/project.py b/pyfpga/project.py
index 59a9e016..a33cb563 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -9,9 +9,13 @@
 """
 
 import logging
+import os
+import subprocess
 
 from enum import Enum
+from datetime import datetime
 from pathlib import Path
+from time import time
 
 
 class Step(Enum):
@@ -47,8 +51,8 @@ def __init__(self, name=None, odir='results'):
         """Class constructor."""
         self.data = {}
         self.name = name
-        self.odir = Path(odir)
-        self.odir.mkdir(parents=True, exist_ok=True)
+        self.odir = odir
+        # self.odir.mkdir(parents=True, exist_ok=True)
         # logging config
         self.logger = logging.getLogger(self.__class__.__name__)
         self.logger.setLevel(logging.INFO)
@@ -134,3 +138,37 @@ def make(self, end=Step.BIT, start=Step.PRJ, capture=False):
     def prog(self, position=1, bitstream=None):
         """Temp placeholder"""
         raise NotImplementedError('Method is not implemented yet.')
+
+    def _run(self, command):
+        self.logger.info('Running the underlying tool (%s)', datetime.now())
+        run_error = 0
+        old_dir = Path.cwd()
+        new_dir = Path(self.odir)
+        start = time.time()
+        try:
+            os.chdir(new_dir)
+            with open('run.log', 'w', encoding='utf-8') as logfile:
+                subprocess.run(
+                    command, shell=True, check=True, text=True,
+                    stdout=logfile, stderr=subprocess.STDOUT
+                )
+        except subprocess.CalledProcessError:
+            with open('run.log', 'r', encoding='utf-8') as logfile:
+                lines = logfile.readlines()
+                last_lines = lines[-10:] if len(lines) >= 10 else lines
+                for line in last_lines:
+                    self.logger.error(line.strip())
+            run_error = 1
+        finally:
+            os.chdir(old_dir)
+            end = time.time()
+            self.logger.info('Done (%s)', datetime.now())
+            elapsed = end - start
+            self.logger.info(
+                'Elapsed time %dh %dm %.2fs',
+                int(elapsed // 3600),
+                int((elapsed % 3600) // 60),
+                elapsed % 60
+            )
+            if run_error:
+                raise RuntimeError('Error running the underlying tool')

From 1b1f5a2abaa27107d2c611fc66b0c392d2ac0b49 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Wed, 29 May 2024 23:50:13 -0300
Subject: [PATCH 041/248] Replaced add_hook by a one functions for each hook

---
 pyfpga/project.py | 33 +++++++++++++++++++++------------
 1 file changed, 21 insertions(+), 12 deletions(-)

diff --git a/pyfpga/project.py b/pyfpga/project.py
index a33cb563..912a61e8 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -21,22 +21,11 @@
 class Step(Enum):
     """Enumeration of supported Steps"""
     PRJ = 'prj'
-    ELB = 'elb'
     SYN = 'syn'
     PAR = 'par'
     BIT = 'bit'
 
 
-class Hook(Enum):
-    """Enumeration of supported Hooks"""
-    PREFILE = 'prefile'
-    PROJECT = 'project'
-    PREFLOW = 'preflow'
-    POSTSYN = 'postsyn'
-    POSTPAR = 'postpar'
-    POSTBIT = 'postbit'
-
-
 class Project:
     """Base class to manage an FPGA project.
 
@@ -127,7 +116,27 @@ def set_top(self, name):
         self.logger.debug('Executing set_top')
         self.data['top'] = name
 
-    def add_hook(self, hook, content):
+    def add_precfg_hook(self, content):
+        """Temp placeholder"""
+        raise NotImplementedError('Method is not implemented yet.')
+
+    def add_postcfg_hook(self, content):
+        """Temp placeholder"""
+        raise NotImplementedError('Method is not implemented yet.')
+
+    def add_presyn_hook(self, content):
+        """Temp placeholder"""
+        raise NotImplementedError('Method is not implemented yet.')
+
+    def add_prepar_hook(self, content):
+        """Temp placeholder"""
+        raise NotImplementedError('Method is not implemented yet.')
+
+    def add_prebit_hook(self, content):
+        """Temp placeholder"""
+        raise NotImplementedError('Method is not implemented yet.')
+
+    def add_postbit_hook(self, content):
         """Temp placeholder"""
         raise NotImplementedError('Method is not implemented yet.')
 

From 992cfab25705ace6051e0bb3e8e58b7b07378400 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Wed, 29 May 2024 23:50:40 -0300
Subject: [PATCH 042/248] docs: added hooks

---
 docs/hooks.rst | 27 +++++++++++++++++++++++++++
 docs/index.rst |  1 +
 2 files changed, 28 insertions(+)
 create mode 100644 docs/hooks.rst

diff --git a/docs/hooks.rst b/docs/hooks.rst
new file mode 100644
index 00000000..a9328332
--- /dev/null
+++ b/docs/hooks.rst
@@ -0,0 +1,27 @@
+Hooks
+=====
+
+.. code-block::
+
+    create project
+    config project
+    part
+    precfg hook
+    params
+    defines
+    includes
+    files
+    arch
+    top
+    postcfg hook
+    close project
+
+    open project
+    presyn hook
+    synthesis
+    prepar hook
+    place_and_route
+    prebit hook
+    bitstream
+    postbit hook
+    close project
diff --git a/docs/index.rst b/docs/index.rst
index dd21b211..69643350 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -9,4 +9,5 @@ PyFPGA's documentation
 .. toctree::
 
    intro
+   hooks
    api

From b9700cd6226a007337d5be8293d6989eaf0e96cb Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Thu, 30 May 2024 00:06:18 -0300
Subject: [PATCH 043/248] Updated the NOTICE about PyFPGA being rewritten

---
 README.md                 |  4 +--
 docs/index.rst            |  5 ++++
 docs/wip/Makefile         | 57 ---------------------------------------
 docs/wip/index.rst        | 32 ----------------------
 docs/wip/requirements.txt |  7 -----
 5 files changed, 7 insertions(+), 98 deletions(-)
 delete mode 100644 docs/wip/Makefile
 delete mode 100644 docs/wip/index.rst
 delete mode 100644 docs/wip/requirements.txt

diff --git a/README.md b/README.md
index 97fad22f..671fa6a1 100644
--- a/README.md
+++ b/README.md
@@ -6,8 +6,8 @@
 ![ISE](https://img.shields.io/badge/ISE-14.7-blue.svg?style=flat-square)
 ![Openflow](https://img.shields.io/badge/Openflow-GHDL%20%7C%20Yosys%20%7C%20nextpnr%20%7C%20icestorm%20%7C%20prjtrellis-darkgreen.svg?style=flat-square)
 
-> **WARNING:** (2022-05-15) PyFPGA is in the process of being strongly rewritten/simplified.
-> Most changes are internal, but the API (`Project` class) will change.
+> **WARNING:** (2024-05-20) PyFPGA is in the process of being strongly rewritten/simplified.
+> Most changes are internal, but the API will also change.
 
 PyFPGA is a **Python Package** for **vendor-agnostic** FPGA development.
 It provides a **Class** which allows the programmatically execution of **synthesis**,
diff --git a/docs/index.rst b/docs/index.rst
index 69643350..96f4b3d9 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -6,6 +6,11 @@ PyFPGA's documentation
    :align: center
    :target: https://github.com/PyFPGA/pyfpga
 
+.. ATTENTION::
+
+  (2024-05-20) PyFPGA is in the process of being strongly rewritten/simplified.
+  Most changes are internal, but the API will also change.
+
 .. toctree::
 
    intro
diff --git a/docs/wip/Makefile b/docs/wip/Makefile
deleted file mode 100644
index 247b174d..00000000
--- a/docs/wip/Makefile
+++ /dev/null
@@ -1,57 +0,0 @@
-CP=cp
-
-# Sphinx options.
-SPHINXOPTS    =
-SPHINXBUILD   = sphinx-build
-PAPER         =
-BUILDDIR      = _build
-
-PAPEROPT_a4     = -D latex_paper_size=a4
-PAPEROPT_letter = -D latex_paper_size=letter
-ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees -T -D language=en $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
-
-all: pyfpga.info
-
-#---
-
-man:
-	$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
-
-#---
-
-html:
-	PYTHONPATH=$(shell pwd)/.. $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
-
-#---
-
-latex:
-	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
-
-#---
-
-texi: pyfpga.texi
-pyfpga.texi:
-	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
-	$(CP) $(BUILDDIR)/texinfo/PyFPGA.texi $@
-
-info: pyfpga.info
-pyfpga.info: pyfpga.texi
-	makeinfo -o $@ $<
-
-dvi: pyfpga.dvi
-pyfpga.dvi: pyfpga.texi
-	texi2dvi $<
-
-pyfpga.ps: pyfpga.dvi
-	dvips $<
-
-pdf: pyfpga.pdf
-pyfpga.pdf: pyfpga.dvi
-	dvipdf $<
-
-#---
-
-clean:
-	$(RM) *~ *.dvi *.info *.aux *.cp *.fn *.ky *.log
-	$(RM) *.pdf *.pg *.toc *.tp *.vr *.texi
-	$(RM) -rf _build
diff --git a/docs/wip/index.rst b/docs/wip/index.rst
deleted file mode 100644
index 8975c13b..00000000
--- a/docs/wip/index.rst
+++ /dev/null
@@ -1,32 +0,0 @@
-.. program:: pyfpga
-
-PyFPGA Documentation
-####################
-
-.. image:: images/logo.png
-   :width: 200 px
-   :align: center
-   :target: https://github.com/PyFPGA/pyfpga
-
-.. raw:: html
-
-    <p style="text-align: center;">
-      <a title="GitLab Repository" href="https://github.com/PyFPGA/pyfpga"><img src="https://img.shields.io/badge/-PyFPGA/pyfpga-323131.svg?longCache=true&style=flat-square&logo=github"></a><!--
-      -->
-    </p>
-
-    <hr>
-
-.. ATTENTION::
-
-  (2022-05-15) PyFPGA is in the process of being strongly rewritten/simplified.
-  Most changes are internal, but the API (`Project` class) will change.
-
-.. toctree::
-
-   intro
-   basic
-   advanced
-   tools
-   api
-   dev
diff --git a/docs/wip/requirements.txt b/docs/wip/requirements.txt
deleted file mode 100644
index 2406283f..00000000
--- a/docs/wip/requirements.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-#-r ../requirements.txt
-sphinx>=3.0.0
-recommonmark
-python-dateutil
-# sphinxcontrib-textstyle>=0.2.1
-# sphinxcontrib-spelling>=2.2.0
-# changelog>=0.3.5
\ No newline at end of file

From 5c9f31ed96ca05bb543d747cb400ebb1c3d2fc1a Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Thu, 30 May 2024 18:08:33 -0300
Subject: [PATCH 044/248] Moved templates from fpga/tool to pyfpga/templates

---
 fpga/tool/template.sh => pyfpga/templates/openflow.jinja | 0
 fpga/tool/template.tcl => pyfpga/templates/vivado.jinja  | 0
 2 files changed, 0 insertions(+), 0 deletions(-)
 rename fpga/tool/template.sh => pyfpga/templates/openflow.jinja (100%)
 rename fpga/tool/template.tcl => pyfpga/templates/vivado.jinja (100%)

diff --git a/fpga/tool/template.sh b/pyfpga/templates/openflow.jinja
similarity index 100%
rename from fpga/tool/template.sh
rename to pyfpga/templates/openflow.jinja
diff --git a/fpga/tool/template.tcl b/pyfpga/templates/vivado.jinja
similarity index 100%
rename from fpga/tool/template.tcl
rename to pyfpga/templates/vivado.jinja

From 93eeb269a2acb4c0f2961f06ea1b04141365fbb1 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Thu, 30 May 2024 18:51:53 -0300
Subject: [PATCH 045/248] Content of vivado.jinja was split into 4 templates

---
 pyfpga/templates/ise.jinja      | 263 ++++++++++++++++++++++++++++
 pyfpga/templates/libero.jinja   | 294 ++++++++++++++++++++++++++++++++
 pyfpga/templates/openflow.jinja |  19 +--
 pyfpga/templates/quartus.jinja  | 261 ++++++++++++++++++++++++++++
 pyfpga/templates/vivado.jinja   | 237 +------------------------
 5 files changed, 824 insertions(+), 250 deletions(-)
 create mode 100644 pyfpga/templates/ise.jinja
 create mode 100644 pyfpga/templates/libero.jinja
 create mode 100644 pyfpga/templates/quartus.jinja

diff --git a/pyfpga/templates/ise.jinja b/pyfpga/templates/ise.jinja
new file mode 100644
index 00000000..1830b97b
--- /dev/null
+++ b/pyfpga/templates/ise.jinja
@@ -0,0 +1,263 @@
+#
+# PyFPGA
+# Copyright (C) 2015-2024 Rodrigo A. Melo
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+
+set TOOL     #TOOL#
+set PRESYNTH #PRESYNTH#
+set PROJECT  #PROJECT#
+set PART     #PART#
+set FAMILY   #FAMILY#
+set DEVICE   #DEVICE#
+set PACKAGE  #PACKAGE#
+set SPEED    #SPEED#
+set TOP      #TOP#
+# TASKS = prj syn par bit
+set TASKS    [list #TASKS#]
+
+set PARAMS   [list #PARAMS#]
+
+proc fpga_files {} {
+#FILES#
+}
+
+proc fpga_commands { PHASE } {
+    fpga_print "setting commands for the phase '$PHASE'"
+    switch $PHASE {
+        "prefile" {
+#PREFILE_CMDS#
+        }
+        "project" {
+#PROJECT_CMDS#
+        }
+        "preflow" {
+#PREFLOW_CMDS#
+        }
+        "postsyn" {
+#POSTSYN_CMDS#
+        }
+        "postpar" {
+#POSTPAR_CMDS#
+        }
+        "postbit" {
+#POSTBIT_CMDS#
+        }
+    }
+}
+
+#
+# Procedures
+#
+
+proc fpga_print { MSG } {
+    global TOOL
+    puts ">>> PyFPGA ($TOOL): $MSG"
+}
+
+proc fpga_create { PROJECT } {
+    global TOOL
+    fpga_print "creating the project '$PROJECT'"
+    switch $TOOL {
+        "ise"     {
+            if { [ file exists $PROJECT.xise ] } { file delete $PROJECT.xise }
+            project new $PROJECT.xise
+        }
+    }
+}
+
+proc fpga_open { PROJECT } {
+    global TOOL
+    fpga_print "opening the project '$PROJECT'"
+    switch $TOOL {
+        "ise"     { project open $PROJECT.xise }
+    }
+}
+
+proc fpga_close {} {
+    global TOOL
+    fpga_print "closing the project"
+    switch $TOOL {
+        "ise"     { project close }
+    }
+}
+
+proc fpga_part { PART } {
+    global TOOL FAMILY DEVICE PACKAGE SPEED
+    fpga_print "adding the part '$PART'"
+    switch $TOOL {
+        "ise"     {
+            project set family  $FAMILY
+            project set device  $DEVICE
+            project set package $PACKAGE
+            project set speed   $SPEED
+        }
+    }
+}
+
+proc fpga_file {FILE {LIBRARY "work"}} {
+    global TOOL TOP
+    set message "adding the file '$FILE'"
+    if { $LIBRARY != "work" } { append message " (into the VHDL library '$LIBRARY')" }
+    fpga_print $message
+    regexp -nocase {\.(\w*)$} $FILE -> ext
+    if { $ext == "tcl" } {
+        source $FILE
+        return
+    }
+    switch $TOOL {
+        "ise" {
+            if {$ext == "xcf"} {
+                project set "Synthesis Constraints File" $FILE -process "Synthesize - XST"
+            } elseif { $LIBRARY != "work" } {
+                lib_vhdl new $LIBRARY
+                xfile add $FILE -lib_vhdl $LIBRARY
+            } else {
+                xfile add $FILE
+            }
+        }
+    }
+}
+
+proc fpga_include {PATH} {
+    global TOOL INCLUDED
+    lappend INCLUDED $PATH
+    fpga_print "setting '$PATH' as a search location"
+    switch $TOOL {
+        "ise" {
+            # Verilog Included Files are NOT added
+            project set "Verilog Include Directories" \
+            [join $INCLUDED "|"] -process "Synthesize - XST"
+        }
+    }
+}
+
+proc fpga_top { TOP } {
+    global TOOL
+    fpga_print "specifying the top level '$TOP'"
+    switch $TOOL {
+        "ise"     {
+            project set top $TOP
+        }
+    }
+}
+
+proc fpga_params {} {
+    global TOOL PARAMS
+    if { [llength $PARAMS] == 0 } { return }
+    fpga_print "setting generics/parameters"
+    switch $TOOL {
+        "ise"     {
+            set assigns [list]
+            foreach PARAM $PARAMS { lappend assigns [join $PARAM "="] }
+            project set "Generics, Parameters" "[join $assigns]" -process "Synthesize - XST"
+        }
+    }
+}
+
+proc fpga_run_syn {} {
+    global TOOL PRESYNTH
+    fpga_print "running 'synthesis'"
+    switch $TOOL {
+        "ise"     {
+            if { $PRESYNTH == "True" } {
+                project set top_level_module_type "EDIF"
+            } else {
+                project clean
+                process run "Synthesize"
+                if { [process get "Synthesize" status] == "errors" } { exit 2 }
+            }
+        }
+    }
+}
+
+proc fpga_run_par {} {
+    global TOOL PRESYNTH
+    fpga_print "running 'place and route'"
+    switch $TOOL {
+        "ise"     {
+            process run "Translate"
+            if { [process get "Translate" status] == "errors" } { exit 2 }
+            process run "Map"
+            if { [process get "Map" status] == "errors" } { exit 2 }
+            process run "Place & Route"
+            if { [process get "Place & Route" status] == "errors" } { exit 2 }
+        }
+    }
+}
+
+proc fpga_run_bit {} {
+    global TOOL PROJECT TOP
+    fpga_print "running 'bitstream generation'"
+    switch $TOOL {
+        "ise"     {
+            process run "Generate Programming File"
+            if { [process get "Generate Programming File" status] == "errors" } { exit 2 }
+            catch { file rename -force $TOP.bit $PROJECT.bit }
+        }
+    }
+}
+
+#
+# Start of the script
+#
+
+fpga_print "start of the Tcl script (interpreter $tcl_version)"
+
+#
+# Project Creation
+#
+
+if { [lsearch -exact $TASKS "prj"] >= 0 } {
+    fpga_print "running the Project Creation"
+    if { [catch {
+        fpga_create $PROJECT
+        fpga_part $PART
+        fpga_commands "prefile"
+        fpga_files
+        fpga_top $TOP
+        fpga_params
+        fpga_commands "project"
+        fpga_close
+    } ERRMSG]} {
+        puts "ERROR: there was a problem creating a New Project.\n"
+        puts $ERRMSG
+        exit 1
+    }
+}
+
+#
+# Design Flow
+#
+
+if { [lsearch -regexp $TASKS "syn|par|bit"] >= 0 } {
+    fpga_print "running the Design Flow"
+    if { [catch {
+        fpga_open $PROJECT
+        fpga_commands "preflow"
+        if { [lsearch -exact $TASKS "syn"] >= 0 } {
+            fpga_run_syn
+            fpga_commands "postsyn"
+        }
+        if { [lsearch -exact $TASKS "par"] >= 0 } {
+            fpga_run_par
+            fpga_commands "postpar"
+        }
+        if { [lsearch -exact $TASKS "bit"] >= 0 } {
+            fpga_run_bit
+            fpga_commands "postbit"
+        }
+        fpga_close
+    } ERRMSG]} {
+        puts "ERROR: there was a problem running the Design Flow.\n"
+        puts $ERRMSG
+        exit 2
+    }
+}
+
+#
+# End of the script
+#
+
+fpga_print "end of the Tcl script"
diff --git a/pyfpga/templates/libero.jinja b/pyfpga/templates/libero.jinja
new file mode 100644
index 00000000..39919f94
--- /dev/null
+++ b/pyfpga/templates/libero.jinja
@@ -0,0 +1,294 @@
+#
+# PyFPGA
+# Copyright (C) 2015-2024 Rodrigo A. Melo
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+
+set TOOL     #TOOL#
+set PRESYNTH #PRESYNTH#
+set PROJECT  #PROJECT#
+set PART     #PART#
+set FAMILY   #FAMILY#
+set DEVICE   #DEVICE#
+set PACKAGE  #PACKAGE#
+set SPEED    #SPEED#
+set TOP      #TOP#
+# TASKS = prj syn par bit
+set TASKS    [list #TASKS#]
+
+set PARAMS   [list #PARAMS#]
+
+proc fpga_files {} {
+#FILES#
+}
+
+proc fpga_commands { PHASE } {
+    fpga_print "setting commands for the phase '$PHASE'"
+    switch $PHASE {
+        "prefile" {
+#PREFILE_CMDS#
+        }
+        "project" {
+#PROJECT_CMDS#
+        }
+        "preflow" {
+#PREFLOW_CMDS#
+        }
+        "postsyn" {
+#POSTSYN_CMDS#
+        }
+        "postpar" {
+#POSTPAR_CMDS#
+        }
+        "postbit" {
+#POSTBIT_CMDS#
+        }
+    }
+}
+
+#
+# Procedures
+#
+
+proc fpga_print { MSG } {
+    global TOOL
+    puts ">>> PyFPGA ($TOOL): $MSG"
+}
+
+proc fpga_create { PROJECT } {
+    global TOOL
+    fpga_print "creating the project '$PROJECT'"
+    switch $TOOL {
+        "libero"  {
+            if { [ file exists $PROJECT ] } { file delete -force -- $PROJECT }
+            new_project -name $PROJECT -location $PROJECT -hdl {VHDL} -family {SmartFusion2}
+        }
+    }
+}
+
+proc fpga_open { PROJECT } {
+    global TOOL
+    fpga_print "opening the project '$PROJECT'"
+    switch $TOOL {
+        "libero"  {
+            open_project $PROJECT/$PROJECT.prjx
+        }
+    }
+}
+
+proc fpga_close {} {
+    global TOOL
+    fpga_print "closing the project"
+    switch $TOOL {
+        "libero"  { close_project }
+    }
+}
+
+proc fpga_part { PART } {
+    global TOOL FAMILY DEVICE PACKAGE SPEED
+    fpga_print "adding the part '$PART'"
+    switch $TOOL {
+        "libero"  {
+            set_device -family $FAMILY -die $DEVICE -package $PACKAGE -speed $SPEED
+        }
+    }
+}
+
+proc fpga_file {FILE {LIBRARY "work"}} {
+    global TOOL TOP
+    set message "adding the file '$FILE'"
+    if { $LIBRARY != "work" } { append message " (into the VHDL library '$LIBRARY')" }
+    fpga_print $message
+    regexp -nocase {\.(\w*)$} $FILE -> ext
+    if { $ext == "tcl" } {
+        source $FILE
+        return
+    }
+    switch $TOOL {
+        "libero" {
+            global LIBERO_PLACE_CONSTRAINTS
+            global LIBERO_OTHER_CONSTRAINTS
+            if {$ext == "pdc"} {
+                create_links -io_pdc $FILE
+                append LIBERO_PLACE_CONSTRAINTS "-file $FILE "
+            } elseif {$ext == "sdc"} {
+                create_links -sdc $FILE
+                append LIBERO_PLACE_CONSTRAINTS "-file $FILE "
+                append LIBERO_OTHER_CONSTRAINTS "-file $FILE "
+            } else {
+                create_links -library $LIBRARY -hdl_source $FILE
+                build_design_hierarchy
+            }
+        }
+    }
+}
+
+proc fpga_include {PATH} {
+    global TOOL INCLUDED
+    lappend INCLUDED $PATH
+    fpga_print "setting '$PATH' as a search location"
+    switch $TOOL {
+        "libero" {
+            # Verilog Included Files are ALSO added
+            # They must be specified after set_root (see fpga_top)
+            foreach FILE [glob -nocomplain $PATH/*.vh] {
+                create_links -hdl_source $FILE
+            }
+            build_design_hierarchy
+        }
+    }
+}
+
+proc fpga_top { TOP } {
+    global TOOL
+    fpga_print "specifying the top level '$TOP'"
+    switch $TOOL {
+        "libero"  {
+            set_root $TOP
+            # Verilog Included files
+            global INCLUDED PARAMS
+            set cmd "configure_tool -name {SYNTHESIZE} -params {SYNPLIFY_OPTIONS:"
+            if { [info exists INCLUDED] && [llength $INCLUDED] > 0 } {
+                # See <ROOT>/poc/include/libero.tcl for details
+                set PATHS "../../"
+                append PATHS [join $INCLUDED ";../../"]
+                append cmd "set_option -include_path \"$PATHS\""
+                append cmd "\n"
+            }
+            foreach PARAM $PARAMS {
+                set assign [join $PARAM]
+                append cmd "set_option -hdl_param -set \"$assign\""
+                append cmd "\n"
+            }
+            append cmd "}"
+            eval $cmd
+            # Constraints
+            # PDC is only used for PLACEROUTE.
+            # SDC is used by ALL (SYNTHESIZE, PLACEROUTE and VERIFYTIMING).
+            global LIBERO_PLACE_CONSTRAINTS
+            global LIBERO_OTHER_CONSTRAINTS
+            if { [info exists LIBERO_OTHER_CONSTRAINTS] } {
+                set cmd "organize_tool_files -tool {SYNTHESIZE} "
+                append cmd $LIBERO_OTHER_CONSTRAINTS
+                append cmd "-module $TOP -input_type {constraint}"
+                eval $cmd
+                set cmd "organize_tool_files -tool {VERIFYTIMING} "
+                append cmd $LIBERO_OTHER_CONSTRAINTS
+                append cmd "-module $TOP -input_type {constraint}"
+                eval $cmd
+            }
+            if { [info exists LIBERO_PLACE_CONSTRAINTS] } {
+                set cmd "organize_tool_files -tool {PLACEROUTE} "
+                append cmd $LIBERO_PLACE_CONSTRAINTS
+                append cmd "-module $TOP -input_type {constraint}"
+                eval $cmd
+            }
+        }
+    }
+}
+
+proc fpga_params {} {
+    global TOOL PARAMS
+    if { [llength $PARAMS] == 0 } { return }
+    fpga_print "setting generics/parameters"
+    switch $TOOL {
+        "libero"  {
+            # They must be specified after set_root (see fpga_top)
+        }
+    }
+}
+
+proc fpga_run_syn {} {
+    global TOOL PRESYNTH
+    fpga_print "running 'synthesis'"
+    switch $TOOL {
+        "libero"  {
+            run_tool -name {SYNTHESIZE}
+        }
+    }
+}
+
+proc fpga_run_par {} {
+    global TOOL PRESYNTH
+    fpga_print "running 'place and route'"
+    switch $TOOL {
+        "libero"  {
+            run_tool -name {PLACEROUTE}
+            run_tool -name {VERIFYTIMING}
+        }
+    }
+}
+
+proc fpga_run_bit {} {
+    global TOOL PROJECT TOP
+    fpga_print "running 'bitstream generation'"
+    switch $TOOL {
+        "libero"  {
+            run_tool -name {GENERATEPROGRAMMINGFILE}
+        }
+    }
+}
+
+#
+# Start of the script
+#
+
+fpga_print "start of the Tcl script (interpreter $tcl_version)"
+
+#
+# Project Creation
+#
+
+if { [lsearch -exact $TASKS "prj"] >= 0 } {
+    fpga_print "running the Project Creation"
+    if { [catch {
+        fpga_create $PROJECT
+        fpga_part $PART
+        fpga_commands "prefile"
+        fpga_files
+        fpga_top $TOP
+        fpga_params
+        fpga_commands "project"
+        fpga_close
+    } ERRMSG]} {
+        puts "ERROR: there was a problem creating a New Project.\n"
+        puts $ERRMSG
+        exit 1
+    }
+}
+
+#
+# Design Flow
+#
+
+if { [lsearch -regexp $TASKS "syn|par|bit"] >= 0 } {
+    fpga_print "running the Design Flow"
+    if { [catch {
+        fpga_open $PROJECT
+        fpga_commands "preflow"
+        if { [lsearch -exact $TASKS "syn"] >= 0 } {
+            fpga_run_syn
+            fpga_commands "postsyn"
+        }
+        if { [lsearch -exact $TASKS "par"] >= 0 } {
+            fpga_run_par
+            fpga_commands "postpar"
+        }
+        if { [lsearch -exact $TASKS "bit"] >= 0 } {
+            fpga_run_bit
+            fpga_commands "postbit"
+        }
+        fpga_close
+    } ERRMSG]} {
+        puts "ERROR: there was a problem running the Design Flow.\n"
+        puts $ERRMSG
+        exit 2
+    }
+}
+
+#
+# End of the script
+#
+
+fpga_print "end of the Tcl script"
diff --git a/pyfpga/templates/openflow.jinja b/pyfpga/templates/openflow.jinja
index f2b271eb..f50b0786 100644
--- a/pyfpga/templates/openflow.jinja
+++ b/pyfpga/templates/openflow.jinja
@@ -1,22 +1,9 @@
 #!/bin/bash
 #
-# Copyright (C) 2020 Rodrigo A. Melo
+# PyFPGA
+# Copyright (C) 2020-2024 Rodrigo A. Melo
 #
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-# This file implements an open-source flow based on ghdl, ghdl-yosys-plugin,
-# yosys, nextpnr, icestorm and prjtrellis.
+# SPDX-License-Identifier: GPL-3.0-or-later
 #
 
 set -e
diff --git a/pyfpga/templates/quartus.jinja b/pyfpga/templates/quartus.jinja
new file mode 100644
index 00000000..8e54e4ea
--- /dev/null
+++ b/pyfpga/templates/quartus.jinja
@@ -0,0 +1,261 @@
+#
+# PyFPGA
+# Copyright (C) 2015-2024 Rodrigo A. Melo
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+
+set TOOL     #TOOL#
+set PRESYNTH #PRESYNTH#
+set PROJECT  #PROJECT#
+set PART     #PART#
+set FAMILY   #FAMILY#
+set DEVICE   #DEVICE#
+set PACKAGE  #PACKAGE#
+set SPEED    #SPEED#
+set TOP      #TOP#
+# TASKS = prj syn par bit
+set TASKS    [list #TASKS#]
+
+set PARAMS   [list #PARAMS#]
+
+proc fpga_files {} {
+#FILES#
+}
+
+proc fpga_commands { PHASE } {
+    fpga_print "setting commands for the phase '$PHASE'"
+    switch $PHASE {
+        "prefile" {
+#PREFILE_CMDS#
+        }
+        "project" {
+#PROJECT_CMDS#
+        }
+        "preflow" {
+#PREFLOW_CMDS#
+        }
+        "postsyn" {
+#POSTSYN_CMDS#
+        }
+        "postpar" {
+#POSTPAR_CMDS#
+        }
+        "postbit" {
+#POSTBIT_CMDS#
+        }
+    }
+}
+
+#
+# Procedures
+#
+
+proc fpga_print { MSG } {
+    global TOOL
+    puts ">>> PyFPGA ($TOOL): $MSG"
+}
+
+proc fpga_create { PROJECT } {
+    global TOOL
+    fpga_print "creating the project '$PROJECT'"
+    switch $TOOL {
+        "quartus" {
+            package require ::quartus::project
+            project_new $PROJECT -overwrite
+            set_global_assignment -name NUM_PARALLEL_PROCESSORS ALL
+        }
+    }
+}
+
+proc fpga_open { PROJECT } {
+    global TOOL
+    fpga_print "opening the project '$PROJECT'"
+    switch $TOOL {
+        "quartus" {
+            package require ::quartus::flow
+            project_open -force $PROJECT.qpf
+        }
+    }
+}
+
+proc fpga_close {} {
+    global TOOL
+    fpga_print "closing the project"
+    switch $TOOL {
+        "quartus" { project_close }
+    }
+}
+
+proc fpga_part { PART } {
+    global TOOL FAMILY DEVICE PACKAGE SPEED
+    fpga_print "adding the part '$PART'"
+    switch $TOOL {
+        "quartus" {
+            set_global_assignment -name DEVICE $PART
+        }
+    }
+}
+
+proc fpga_file {FILE {LIBRARY "work"}} {
+    global TOOL TOP
+    set message "adding the file '$FILE'"
+    if { $LIBRARY != "work" } { append message " (into the VHDL library '$LIBRARY')" }
+    fpga_print $message
+    regexp -nocase {\.(\w*)$} $FILE -> ext
+    if { $ext == "tcl" } {
+        source $FILE
+        return
+    }
+    switch $TOOL {
+        "quartus" {
+            if {$ext == "v"} {
+                set TYPE VERILOG_FILE
+            } elseif {$ext == "sv"} {
+                set TYPE SYSTEMVERILOG_FILE
+            } elseif {$ext == "vhdl" || $ext == "vhd"} {
+                set TYPE VHDL_FILE
+            } elseif {$ext == "sdc"} {
+                set TYPE SDC_FILE
+            } else {
+                set TYPE SOURCE_FILE
+            }
+            if { $LIBRARY != "work" } {
+                set_global_assignment -name $TYPE $FILE -library $LIBRARY
+            } else {
+                set_global_assignment -name $TYPE $FILE
+            }
+        }
+    }
+}
+
+proc fpga_include {PATH} {
+    global TOOL INCLUDED
+    lappend INCLUDED $PATH
+    fpga_print "setting '$PATH' as a search location"
+    switch $TOOL {
+        "quartus" {
+            # Verilog Included Files are NOT added
+            foreach INCLUDE $INCLUDED {
+                set_global_assignment -name SEARCH_PATH $INCLUDE
+            }
+        }
+    }
+}
+
+proc fpga_top { TOP } {
+    global TOOL
+    fpga_print "specifying the top level '$TOP'"
+    switch $TOOL {
+        "quartus" {
+            set_global_assignment -name TOP_LEVEL_ENTITY $TOP
+        }
+    }
+}
+
+proc fpga_params {} {
+    global TOOL PARAMS
+    if { [llength $PARAMS] == 0 } { return }
+    fpga_print "setting generics/parameters"
+    switch $TOOL {
+        "quartus" {
+            foreach PARAM $PARAMS {
+                eval "set_parameter -name $PARAM"
+            }
+        }
+    }
+}
+
+proc fpga_run_syn {} {
+    global TOOL PRESYNTH
+    fpga_print "running 'synthesis'"
+    switch $TOOL {
+        "quartus" {
+            execute_module -tool map
+        }
+    }
+}
+
+proc fpga_run_par {} {
+    global TOOL PRESYNTH
+    fpga_print "running 'place and route'"
+    switch $TOOL {
+        "quartus" {
+            execute_module -tool fit
+            execute_module -tool sta
+        }
+    }
+}
+
+proc fpga_run_bit {} {
+    global TOOL PROJECT TOP
+    fpga_print "running 'bitstream generation'"
+    switch $TOOL {
+        "quartus" {
+            execute_module -tool asm
+        }
+    }
+}
+
+#
+# Start of the script
+#
+
+fpga_print "start of the Tcl script (interpreter $tcl_version)"
+
+#
+# Project Creation
+#
+
+if { [lsearch -exact $TASKS "prj"] >= 0 } {
+    fpga_print "running the Project Creation"
+    if { [catch {
+        fpga_create $PROJECT
+        fpga_part $PART
+        fpga_commands "prefile"
+        fpga_files
+        fpga_top $TOP
+        fpga_params
+        fpga_commands "project"
+        fpga_close
+    } ERRMSG]} {
+        puts "ERROR: there was a problem creating a New Project.\n"
+        puts $ERRMSG
+        exit 1
+    }
+}
+
+#
+# Design Flow
+#
+
+if { [lsearch -regexp $TASKS "syn|par|bit"] >= 0 } {
+    fpga_print "running the Design Flow"
+    if { [catch {
+        fpga_open $PROJECT
+        fpga_commands "preflow"
+        if { [lsearch -exact $TASKS "syn"] >= 0 } {
+            fpga_run_syn
+            fpga_commands "postsyn"
+        }
+        if { [lsearch -exact $TASKS "par"] >= 0 } {
+            fpga_run_par
+            fpga_commands "postpar"
+        }
+        if { [lsearch -exact $TASKS "bit"] >= 0 } {
+            fpga_run_bit
+            fpga_commands "postbit"
+        }
+        fpga_close
+    } ERRMSG]} {
+        puts "ERROR: there was a problem running the Design Flow.\n"
+        puts $ERRMSG
+        exit 2
+    }
+}
+
+#
+# End of the script
+#
+
+fpga_print "end of the Tcl script"
diff --git a/pyfpga/templates/vivado.jinja b/pyfpga/templates/vivado.jinja
index 7466d534..5758f1c7 100644
--- a/pyfpga/templates/vivado.jinja
+++ b/pyfpga/templates/vivado.jinja
@@ -1,35 +1,8 @@
 #
-# PyFPGA Master Tcl
+# PyFPGA
+# Copyright (C) 2015-2024 Rodrigo A. Melo
 #
-# Copyright (C) 2015-2020 INTI
-# Copyright (C) 2015-2020 Rodrigo A. Melo
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-# Description: Tcl script to create a new project and performs synthesis,
-# place and route, and bitstream generation.
-#
-# Supported TOOLs: ise, libero, quartus, vivado
-#
-# Notes:
-# * fpga_ is used to avoid name collisions.
-# * The 'in' operator was introduced by Tcl 8.5, but some Tools uses 8.4,
-#   so 'lsearch' is used to test if a value is in a list.
-#
-
-#
-# Things to tuneup (#SOMETHING#) for each project
+# SPDX-License-Identifier: GPL-3.0-or-later
 #
 
 set TOOL     #TOOL#
@@ -87,19 +60,6 @@ proc fpga_create { PROJECT } {
     global TOOL
     fpga_print "creating the project '$PROJECT'"
     switch $TOOL {
-        "ise"     {
-            if { [ file exists $PROJECT.xise ] } { file delete $PROJECT.xise }
-            project new $PROJECT.xise
-        }
-        "libero"  {
-            if { [ file exists $PROJECT ] } { file delete -force -- $PROJECT }
-            new_project -name $PROJECT -location $PROJECT -hdl {VHDL} -family {SmartFusion2}
-        }
-        "quartus" {
-            package require ::quartus::project
-            project_new $PROJECT -overwrite
-            set_global_assignment -name NUM_PARALLEL_PROCESSORS ALL
-        }
         "vivado"  { create_project -force $PROJECT }
     }
 }
@@ -108,14 +68,6 @@ proc fpga_open { PROJECT } {
     global TOOL
     fpga_print "opening the project '$PROJECT'"
     switch $TOOL {
-        "ise"     { project open $PROJECT.xise }
-        "libero"  {
-            open_project $PROJECT/$PROJECT.prjx
-        }
-        "quartus" {
-            package require ::quartus::flow
-            project_open -force $PROJECT.qpf
-        }
         "vivado"  { open_project $PROJECT }
     }
 }
@@ -124,9 +76,6 @@ proc fpga_close {} {
     global TOOL
     fpga_print "closing the project"
     switch $TOOL {
-        "ise"     { project close }
-        "libero"  { close_project }
-        "quartus" { project_close }
         "vivado"  { close_project }
     }
 }
@@ -135,18 +84,6 @@ proc fpga_part { PART } {
     global TOOL FAMILY DEVICE PACKAGE SPEED
     fpga_print "adding the part '$PART'"
     switch $TOOL {
-        "ise"     {
-            project set family  $FAMILY
-            project set device  $DEVICE
-            project set package $PACKAGE
-            project set speed   $SPEED
-        }
-        "libero"  {
-            set_device -family $FAMILY -die $DEVICE -package $PACKAGE -speed $SPEED
-        }
-        "quartus" {
-            set_global_assignment -name DEVICE $PART
-        }
         "vivado"  {
             set_property "part" $PART [current_project]
         }
@@ -164,49 +101,6 @@ proc fpga_file {FILE {LIBRARY "work"}} {
         return
     }
     switch $TOOL {
-        "ise" {
-            if {$ext == "xcf"} {
-                project set "Synthesis Constraints File" $FILE -process "Synthesize - XST"
-            } elseif { $LIBRARY != "work" } {
-                lib_vhdl new $LIBRARY
-                xfile add $FILE -lib_vhdl $LIBRARY
-            } else {
-                xfile add $FILE
-            }
-        }
-        "libero" {
-            global LIBERO_PLACE_CONSTRAINTS
-            global LIBERO_OTHER_CONSTRAINTS
-            if {$ext == "pdc"} {
-                create_links -io_pdc $FILE
-                append LIBERO_PLACE_CONSTRAINTS "-file $FILE "
-            } elseif {$ext == "sdc"} {
-                create_links -sdc $FILE
-                append LIBERO_PLACE_CONSTRAINTS "-file $FILE "
-                append LIBERO_OTHER_CONSTRAINTS "-file $FILE "
-            } else {
-                create_links -library $LIBRARY -hdl_source $FILE
-                build_design_hierarchy
-            }
-        }
-        "quartus" {
-            if {$ext == "v"} {
-                set TYPE VERILOG_FILE
-            } elseif {$ext == "sv"} {
-                set TYPE SYSTEMVERILOG_FILE
-            } elseif {$ext == "vhdl" || $ext == "vhd"} {
-                set TYPE VHDL_FILE
-            } elseif {$ext == "sdc"} {
-                set TYPE SDC_FILE
-            } else {
-                set TYPE SOURCE_FILE
-            }
-            if { $LIBRARY != "work" } {
-                set_global_assignment -name $TYPE $FILE -library $LIBRARY
-            } else {
-                set_global_assignment -name $TYPE $FILE
-            }
-        }
         "vivado" {
             if { $LIBRARY != "work" } {
                 add_files $FILE
@@ -223,25 +117,6 @@ proc fpga_include {PATH} {
     lappend INCLUDED $PATH
     fpga_print "setting '$PATH' as a search location"
     switch $TOOL {
-        "ise" {
-            # Verilog Included Files are NOT added
-            project set "Verilog Include Directories" \
-            [join $INCLUDED "|"] -process "Synthesize - XST"
-        }
-        "libero" {
-            # Verilog Included Files are ALSO added
-            # They must be specified after set_root (see fpga_top)
-            foreach FILE [glob -nocomplain $PATH/*.vh] {
-                create_links -hdl_source $FILE
-            }
-            build_design_hierarchy
-        }
-        "quartus" {
-            # Verilog Included Files are NOT added
-            foreach INCLUDE $INCLUDED {
-                set_global_assignment -name SEARCH_PATH $INCLUDE
-            }
-        }
         "vivado" {
             # Verilog Included Files are NOT added
             set_property "include_dirs" $INCLUDED [current_fileset]
@@ -264,7 +139,6 @@ proc fpga_design {FILE} {
                 set TOP design_1_wrapper
             }
         }
-        default  { puts "UNSUPPORTED by '$TOOL'" }
     }
 }
 
@@ -272,53 +146,6 @@ proc fpga_top { TOP } {
     global TOOL
     fpga_print "specifying the top level '$TOP'"
     switch $TOOL {
-        "ise"     {
-            project set top $TOP
-        }
-        "libero"  {
-            set_root $TOP
-            # Verilog Included files
-            global INCLUDED PARAMS
-            set cmd "configure_tool -name {SYNTHESIZE} -params {SYNPLIFY_OPTIONS:"
-            if { [info exists INCLUDED] && [llength $INCLUDED] > 0 } {
-                # See <ROOT>/poc/include/libero.tcl for details
-                set PATHS "../../"
-                append PATHS [join $INCLUDED ";../../"]
-                append cmd "set_option -include_path \"$PATHS\""
-                append cmd "\n"
-            }
-            foreach PARAM $PARAMS {
-                set assign [join $PARAM]
-                append cmd "set_option -hdl_param -set \"$assign\""
-                append cmd "\n"
-            }
-            append cmd "}"
-            eval $cmd
-            # Constraints
-            # PDC is only used for PLACEROUTE.
-            # SDC is used by ALL (SYNTHESIZE, PLACEROUTE and VERIFYTIMING).
-            global LIBERO_PLACE_CONSTRAINTS
-            global LIBERO_OTHER_CONSTRAINTS
-            if { [info exists LIBERO_OTHER_CONSTRAINTS] } {
-                set cmd "organize_tool_files -tool {SYNTHESIZE} "
-                append cmd $LIBERO_OTHER_CONSTRAINTS
-                append cmd "-module $TOP -input_type {constraint}"
-                eval $cmd
-                set cmd "organize_tool_files -tool {VERIFYTIMING} "
-                append cmd $LIBERO_OTHER_CONSTRAINTS
-                append cmd "-module $TOP -input_type {constraint}"
-                eval $cmd
-            }
-            if { [info exists LIBERO_PLACE_CONSTRAINTS] } {
-                set cmd "organize_tool_files -tool {PLACEROUTE} "
-                append cmd $LIBERO_PLACE_CONSTRAINTS
-                append cmd "-module $TOP -input_type {constraint}"
-                eval $cmd
-            }
-        }
-        "quartus" {
-            set_global_assignment -name TOP_LEVEL_ENTITY $TOP
-        }
         "vivado"  {
             set_property top $TOP [current_fileset]
         }
@@ -330,19 +157,6 @@ proc fpga_params {} {
     if { [llength $PARAMS] == 0 } { return }
     fpga_print "setting generics/parameters"
     switch $TOOL {
-        "ise"     {
-            set assigns [list]
-            foreach PARAM $PARAMS { lappend assigns [join $PARAM "="] }
-            project set "Generics, Parameters" "[join $assigns]" -process "Synthesize - XST"
-        }
-        "libero"  {
-            # They must be specified after set_root (see fpga_top)
-        }
-        "quartus" {
-            foreach PARAM $PARAMS {
-                eval "set_parameter -name $PARAM"
-            }
-        }
         "vivado"  {
             set assigns [list]
             foreach PARAM $PARAMS { lappend assigns [join $PARAM "="] }
@@ -356,21 +170,6 @@ proc fpga_run_syn {} {
     global TOOL PRESYNTH
     fpga_print "running 'synthesis'"
     switch $TOOL {
-        "ise"     {
-            if { $PRESYNTH == "True" } {
-                project set top_level_module_type "EDIF"
-            } else {
-                project clean
-                process run "Synthesize"
-                if { [process get "Synthesize" status] == "errors" } { exit 2 }
-            }
-        }
-        "libero"  {
-            run_tool -name {SYNTHESIZE}
-        }
-        "quartus" {
-            execute_module -tool map
-        }
         "vivado"  {
             if { $PRESYNTH == "True" } {
                 set_property design_mode GateLvl [current_fileset]
@@ -380,7 +179,6 @@ proc fpga_run_syn {} {
                 wait_on_run synth_1
             }
         }
-        default  { puts "UNSUPPORTED by '$TOOL'" }
     }
 }
 
@@ -388,22 +186,6 @@ proc fpga_run_par {} {
     global TOOL PRESYNTH
     fpga_print "running 'place and route'"
     switch $TOOL {
-        "ise"     {
-            process run "Translate"
-            if { [process get "Translate" status] == "errors" } { exit 2 }
-            process run "Map"
-            if { [process get "Map" status] == "errors" } { exit 2 }
-            process run "Place & Route"
-            if { [process get "Place & Route" status] == "errors" } { exit 2 }
-        }
-        "libero"  {
-            run_tool -name {PLACEROUTE}
-            run_tool -name {VERIFYTIMING}
-        }
-        "quartus" {
-            execute_module -tool fit
-            execute_module -tool sta
-        }
         "vivado"  {
             if {$PRESYNTH == "False"} {
                 open_run synth_1
@@ -411,7 +193,6 @@ proc fpga_run_par {} {
             launch_runs impl_1
             wait_on_run impl_1
         }
-        default  { puts "UNSUPPORTED by '$TOOL'" }
     }
 }
 
@@ -419,22 +200,10 @@ proc fpga_run_bit {} {
     global TOOL PROJECT TOP
     fpga_print "running 'bitstream generation'"
     switch $TOOL {
-        "ise"     {
-            process run "Generate Programming File"
-            if { [process get "Generate Programming File" status] == "errors" } { exit 2 }
-            catch { file rename -force $TOP.bit $PROJECT.bit }
-        }
-        "libero"  {
-            run_tool -name {GENERATEPROGRAMMINGFILE}
-        }
-        "quartus" {
-            execute_module -tool asm
-        }
         "vivado"  {
             open_run impl_1
             write_bitstream -force $PROJECT
         }
-        default  { puts "UNSUPPORTED by '$TOOL'" }
     }
 }
 

From 5c2ad6ffe1084cdbae147569ed04d7e66fecbf59 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Thu, 30 May 2024 19:28:49 -0300
Subject: [PATCH 046/248] Templates clean-up

---
 pyfpga/templates/ise.jinja     | 248 +++++++--------------------
 pyfpga/templates/libero.jinja  | 305 ++++++++++-----------------------
 pyfpga/templates/quartus.jinja | 240 ++++++--------------------
 pyfpga/templates/vivado.jinja  | 251 +++++++--------------------
 4 files changed, 258 insertions(+), 786 deletions(-)

diff --git a/pyfpga/templates/ise.jinja b/pyfpga/templates/ise.jinja
index 1830b97b..2aa7a6b1 100644
--- a/pyfpga/templates/ise.jinja
+++ b/pyfpga/templates/ise.jinja
@@ -5,7 +5,6 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-set TOOL     #TOOL#
 set PRESYNTH #PRESYNTH#
 set PROJECT  #PROJECT#
 set PART     #PART#
@@ -23,241 +22,112 @@ proc fpga_files {} {
 #FILES#
 }
 
-proc fpga_commands { PHASE } {
-    fpga_print "setting commands for the phase '$PHASE'"
-    switch $PHASE {
-        "prefile" {
-#PREFILE_CMDS#
-        }
-        "project" {
-#PROJECT_CMDS#
-        }
-        "preflow" {
-#PREFLOW_CMDS#
-        }
-        "postsyn" {
-#POSTSYN_CMDS#
-        }
-        "postpar" {
-#POSTPAR_CMDS#
-        }
-        "postbit" {
-#POSTBIT_CMDS#
-        }
-    }
-}
-
-#
-# Procedures
-#
-
-proc fpga_print { MSG } {
-    global TOOL
-    puts ">>> PyFPGA ($TOOL): $MSG"
-}
-
 proc fpga_create { PROJECT } {
-    global TOOL
-    fpga_print "creating the project '$PROJECT'"
-    switch $TOOL {
-        "ise"     {
-            if { [ file exists $PROJECT.xise ] } { file delete $PROJECT.xise }
-            project new $PROJECT.xise
-        }
-    }
+    if { [ file exists $PROJECT.xise ] } { file delete $PROJECT.xise }
+    project new $PROJECT.xise
 }
 
 proc fpga_open { PROJECT } {
-    global TOOL
-    fpga_print "opening the project '$PROJECT'"
-    switch $TOOL {
-        "ise"     { project open $PROJECT.xise }
-    }
+    project open $PROJECT.xise
 }
 
 proc fpga_close {} {
-    global TOOL
-    fpga_print "closing the project"
-    switch $TOOL {
-        "ise"     { project close }
-    }
+    project close
 }
 
 proc fpga_part { PART } {
-    global TOOL FAMILY DEVICE PACKAGE SPEED
-    fpga_print "adding the part '$PART'"
-    switch $TOOL {
-        "ise"     {
-            project set family  $FAMILY
-            project set device  $DEVICE
-            project set package $PACKAGE
-            project set speed   $SPEED
-        }
-    }
+    project set family  $FAMILY
+    project set device  $DEVICE
+    project set package $PACKAGE
+    project set speed   $SPEED
 }
 
 proc fpga_file {FILE {LIBRARY "work"}} {
-    global TOOL TOP
     set message "adding the file '$FILE'"
     if { $LIBRARY != "work" } { append message " (into the VHDL library '$LIBRARY')" }
-    fpga_print $message
     regexp -nocase {\.(\w*)$} $FILE -> ext
     if { $ext == "tcl" } {
         source $FILE
         return
     }
-    switch $TOOL {
-        "ise" {
-            if {$ext == "xcf"} {
-                project set "Synthesis Constraints File" $FILE -process "Synthesize - XST"
-            } elseif { $LIBRARY != "work" } {
-                lib_vhdl new $LIBRARY
-                xfile add $FILE -lib_vhdl $LIBRARY
-            } else {
-                xfile add $FILE
-            }
-        }
+    if {$ext == "xcf"} {
+        project set "Synthesis Constraints File" $FILE -process "Synthesize - XST"
+    } elseif { $LIBRARY != "work" } {
+        lib_vhdl new $LIBRARY
+        xfile add $FILE -lib_vhdl $LIBRARY
+    } else {
+        xfile add $FILE
     }
 }
 
 proc fpga_include {PATH} {
-    global TOOL INCLUDED
     lappend INCLUDED $PATH
-    fpga_print "setting '$PATH' as a search location"
-    switch $TOOL {
-        "ise" {
-            # Verilog Included Files are NOT added
-            project set "Verilog Include Directories" \
-            [join $INCLUDED "|"] -process "Synthesize - XST"
-        }
-    }
+    # Verilog Included Files are NOT added
+    project set "Verilog Include Directories" \
+    [join $INCLUDED "|"] -process "Synthesize - XST"
 }
 
 proc fpga_top { TOP } {
-    global TOOL
-    fpga_print "specifying the top level '$TOP'"
-    switch $TOOL {
-        "ise"     {
-            project set top $TOP
-        }
-    }
+    project set top $TOP
 }
 
 proc fpga_params {} {
-    global TOOL PARAMS
     if { [llength $PARAMS] == 0 } { return }
-    fpga_print "setting generics/parameters"
-    switch $TOOL {
-        "ise"     {
-            set assigns [list]
-            foreach PARAM $PARAMS { lappend assigns [join $PARAM "="] }
-            project set "Generics, Parameters" "[join $assigns]" -process "Synthesize - XST"
-        }
-    }
+    set assigns [list]
+    foreach PARAM $PARAMS { lappend assigns [join $PARAM "="] }
+    project set "Generics, Parameters" "[join $assigns]" -process "Synthesize - XST"
 }
 
 proc fpga_run_syn {} {
-    global TOOL PRESYNTH
-    fpga_print "running 'synthesis'"
-    switch $TOOL {
-        "ise"     {
-            if { $PRESYNTH == "True" } {
-                project set top_level_module_type "EDIF"
-            } else {
-                project clean
-                process run "Synthesize"
-                if { [process get "Synthesize" status] == "errors" } { exit 2 }
-            }
-        }
+    if { $PRESYNTH == "True" } {
+        project set top_level_module_type "EDIF"
+    } else {
+        project clean
+        process run "Synthesize"
+        if { [process get "Synthesize" status] == "errors" } { exit 2 }
     }
 }
 
 proc fpga_run_par {} {
-    global TOOL PRESYNTH
-    fpga_print "running 'place and route'"
-    switch $TOOL {
-        "ise"     {
-            process run "Translate"
-            if { [process get "Translate" status] == "errors" } { exit 2 }
-            process run "Map"
-            if { [process get "Map" status] == "errors" } { exit 2 }
-            process run "Place & Route"
-            if { [process get "Place & Route" status] == "errors" } { exit 2 }
-        }
-    }
+    process run "Translate"
+    if { [process get "Translate" status] == "errors" } { exit 2 }
+    process run "Map"
+    if { [process get "Map" status] == "errors" } { exit 2 }
+    process run "Place & Route"
+    if { [process get "Place & Route" status] == "errors" } { exit 2 }
 }
 
 proc fpga_run_bit {} {
-    global TOOL PROJECT TOP
-    fpga_print "running 'bitstream generation'"
-    switch $TOOL {
-        "ise"     {
-            process run "Generate Programming File"
-            if { [process get "Generate Programming File" status] == "errors" } { exit 2 }
-            catch { file rename -force $TOP.bit $PROJECT.bit }
-        }
-    }
+    process run "Generate Programming File"
+    if { [process get "Generate Programming File" status] == "errors" } { exit 2 }
+    catch { file rename -force $TOP.bit $PROJECT.bit }
 }
 
-#
-# Start of the script
-#
-
-fpga_print "start of the Tcl script (interpreter $tcl_version)"
-
-#
-# Project Creation
-#
-
 if { [lsearch -exact $TASKS "prj"] >= 0 } {
-    fpga_print "running the Project Creation"
-    if { [catch {
-        fpga_create $PROJECT
-        fpga_part $PART
-        fpga_commands "prefile"
-        fpga_files
-        fpga_top $TOP
-        fpga_params
-        fpga_commands "project"
-        fpga_close
-    } ERRMSG]} {
-        puts "ERROR: there was a problem creating a New Project.\n"
-        puts $ERRMSG
-        exit 1
-    }
+    fpga_create $PROJECT
+    fpga_part $PART
+    {{ PRECFG }}
+    fpga_files
+    fpga_top $TOP
+    fpga_params
+    {{ POSTCFG }}
+    fpga_close
 }
 
-#
-# Design Flow
-#
-
 if { [lsearch -regexp $TASKS "syn|par|bit"] >= 0 } {
-    fpga_print "running the Design Flow"
-    if { [catch {
-        fpga_open $PROJECT
-        fpga_commands "preflow"
-        if { [lsearch -exact $TASKS "syn"] >= 0 } {
-            fpga_run_syn
-            fpga_commands "postsyn"
-        }
-        if { [lsearch -exact $TASKS "par"] >= 0 } {
-            fpga_run_par
-            fpga_commands "postpar"
-        }
-        if { [lsearch -exact $TASKS "bit"] >= 0 } {
-            fpga_run_bit
-            fpga_commands "postbit"
-        }
-        fpga_close
-    } ERRMSG]} {
-        puts "ERROR: there was a problem running the Design Flow.\n"
-        puts $ERRMSG
-        exit 2
+    fpga_open $PROJECT
+    if { [lsearch -exact $TASKS "syn"] >= 0 } {
+        {{ PRESYN }}
+        fpga_run_syn
+    }
+    if { [lsearch -exact $TASKS "par"] >= 0 } {
+        {{ PREPAR }}
+        fpga_run_par
+    }
+    if { [lsearch -exact $TASKS "bit"] >= 0 } {
+        {{ PREBIT }}
+        fpga_run_bit
+        {{ POSTBIT }}
     }
+    fpga_close
 }
-
-#
-# End of the script
-#
-
-fpga_print "end of the Tcl script"
diff --git a/pyfpga/templates/libero.jinja b/pyfpga/templates/libero.jinja
index 39919f94..7cdcfd33 100644
--- a/pyfpga/templates/libero.jinja
+++ b/pyfpga/templates/libero.jinja
@@ -5,7 +5,6 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-set TOOL     #TOOL#
 set PRESYNTH #PRESYNTH#
 set PROJECT  #PROJECT#
 set PART     #PART#
@@ -23,272 +22,140 @@ proc fpga_files {} {
 #FILES#
 }
 
-proc fpga_commands { PHASE } {
-    fpga_print "setting commands for the phase '$PHASE'"
-    switch $PHASE {
-        "prefile" {
-#PREFILE_CMDS#
-        }
-        "project" {
-#PROJECT_CMDS#
-        }
-        "preflow" {
-#PREFLOW_CMDS#
-        }
-        "postsyn" {
-#POSTSYN_CMDS#
-        }
-        "postpar" {
-#POSTPAR_CMDS#
-        }
-        "postbit" {
-#POSTBIT_CMDS#
-        }
-    }
-}
-
-#
-# Procedures
-#
-
-proc fpga_print { MSG } {
-    global TOOL
-    puts ">>> PyFPGA ($TOOL): $MSG"
-}
-
 proc fpga_create { PROJECT } {
-    global TOOL
-    fpga_print "creating the project '$PROJECT'"
-    switch $TOOL {
-        "libero"  {
-            if { [ file exists $PROJECT ] } { file delete -force -- $PROJECT }
-            new_project -name $PROJECT -location $PROJECT -hdl {VHDL} -family {SmartFusion2}
-        }
-    }
+    if { [ file exists $PROJECT ] } { file delete -force -- $PROJECT }
+    new_project -name $PROJECT -location $PROJECT -hdl {VHDL} -family {SmartFusion2}
 }
 
 proc fpga_open { PROJECT } {
-    global TOOL
-    fpga_print "opening the project '$PROJECT'"
-    switch $TOOL {
-        "libero"  {
-            open_project $PROJECT/$PROJECT.prjx
-        }
-    }
+    open_project $PROJECT/$PROJECT.prjx
 }
 
 proc fpga_close {} {
-    global TOOL
-    fpga_print "closing the project"
-    switch $TOOL {
-        "libero"  { close_project }
-    }
+    close_project
 }
 
 proc fpga_part { PART } {
-    global TOOL FAMILY DEVICE PACKAGE SPEED
-    fpga_print "adding the part '$PART'"
-    switch $TOOL {
-        "libero"  {
-            set_device -family $FAMILY -die $DEVICE -package $PACKAGE -speed $SPEED
-        }
-    }
+    set_device -family $FAMILY -die $DEVICE -package $PACKAGE -speed $SPEED
 }
 
 proc fpga_file {FILE {LIBRARY "work"}} {
-    global TOOL TOP
     set message "adding the file '$FILE'"
     if { $LIBRARY != "work" } { append message " (into the VHDL library '$LIBRARY')" }
-    fpga_print $message
     regexp -nocase {\.(\w*)$} $FILE -> ext
     if { $ext == "tcl" } {
         source $FILE
         return
     }
-    switch $TOOL {
-        "libero" {
-            global LIBERO_PLACE_CONSTRAINTS
-            global LIBERO_OTHER_CONSTRAINTS
-            if {$ext == "pdc"} {
-                create_links -io_pdc $FILE
-                append LIBERO_PLACE_CONSTRAINTS "-file $FILE "
-            } elseif {$ext == "sdc"} {
-                create_links -sdc $FILE
-                append LIBERO_PLACE_CONSTRAINTS "-file $FILE "
-                append LIBERO_OTHER_CONSTRAINTS "-file $FILE "
-            } else {
-                create_links -library $LIBRARY -hdl_source $FILE
-                build_design_hierarchy
-            }
-        }
+    global LIBERO_PLACE_CONSTRAINTS
+    global LIBERO_OTHER_CONSTRAINTS
+    if {$ext == "pdc"} {
+        create_links -io_pdc $FILE
+        append LIBERO_PLACE_CONSTRAINTS "-file $FILE "
+    } elseif {$ext == "sdc"} {
+        create_links -sdc $FILE
+        append LIBERO_PLACE_CONSTRAINTS "-file $FILE "
+        append LIBERO_OTHER_CONSTRAINTS "-file $FILE "
+    } else {
+        create_links -library $LIBRARY -hdl_source $FILE
+        build_design_hierarchy
     }
 }
 
 proc fpga_include {PATH} {
-    global TOOL INCLUDED
     lappend INCLUDED $PATH
-    fpga_print "setting '$PATH' as a search location"
-    switch $TOOL {
-        "libero" {
-            # Verilog Included Files are ALSO added
-            # They must be specified after set_root (see fpga_top)
-            foreach FILE [glob -nocomplain $PATH/*.vh] {
-                create_links -hdl_source $FILE
-            }
-            build_design_hierarchy
-        }
+    # Verilog Included Files are ALSO added
+    # They must be specified after set_root (see fpga_top)
+    foreach FILE [glob -nocomplain $PATH/*.vh] {
+        create_links -hdl_source $FILE
     }
+    build_design_hierarchy
 }
 
 proc fpga_top { TOP } {
-    global TOOL
-    fpga_print "specifying the top level '$TOP'"
-    switch $TOOL {
-        "libero"  {
-            set_root $TOP
-            # Verilog Included files
-            global INCLUDED PARAMS
-            set cmd "configure_tool -name {SYNTHESIZE} -params {SYNPLIFY_OPTIONS:"
-            if { [info exists INCLUDED] && [llength $INCLUDED] > 0 } {
-                # See <ROOT>/poc/include/libero.tcl for details
-                set PATHS "../../"
-                append PATHS [join $INCLUDED ";../../"]
-                append cmd "set_option -include_path \"$PATHS\""
-                append cmd "\n"
-            }
-            foreach PARAM $PARAMS {
-                set assign [join $PARAM]
-                append cmd "set_option -hdl_param -set \"$assign\""
-                append cmd "\n"
-            }
-            append cmd "}"
-            eval $cmd
-            # Constraints
-            # PDC is only used for PLACEROUTE.
-            # SDC is used by ALL (SYNTHESIZE, PLACEROUTE and VERIFYTIMING).
-            global LIBERO_PLACE_CONSTRAINTS
-            global LIBERO_OTHER_CONSTRAINTS
-            if { [info exists LIBERO_OTHER_CONSTRAINTS] } {
-                set cmd "organize_tool_files -tool {SYNTHESIZE} "
-                append cmd $LIBERO_OTHER_CONSTRAINTS
-                append cmd "-module $TOP -input_type {constraint}"
-                eval $cmd
-                set cmd "organize_tool_files -tool {VERIFYTIMING} "
-                append cmd $LIBERO_OTHER_CONSTRAINTS
-                append cmd "-module $TOP -input_type {constraint}"
-                eval $cmd
-            }
-            if { [info exists LIBERO_PLACE_CONSTRAINTS] } {
-                set cmd "organize_tool_files -tool {PLACEROUTE} "
-                append cmd $LIBERO_PLACE_CONSTRAINTS
-                append cmd "-module $TOP -input_type {constraint}"
-                eval $cmd
-            }
-        }
+    set_root $TOP
+    # Verilog Included files
+    set cmd "configure_tool -name {SYNTHESIZE} -params {SYNPLIFY_OPTIONS:"
+    if { [info exists INCLUDED] && [llength $INCLUDED] > 0 } {
+        # See <ROOT>/poc/include/libero.tcl for details
+        set PATHS "../../"
+        append PATHS [join $INCLUDED ";../../"]
+        append cmd "set_option -include_path \"$PATHS\""
+        append cmd "\n"
+    }
+    foreach PARAM $PARAMS {
+        set assign [join $PARAM]
+        append cmd "set_option -hdl_param -set \"$assign\""
+        append cmd "\n"
+    }
+    append cmd "}"
+    eval $cmd
+    # Constraints
+    # PDC is only used for PLACEROUTE.
+    # SDC is used by ALL (SYNTHESIZE, PLACEROUTE and VERIFYTIMING).
+    global LIBERO_PLACE_CONSTRAINTS
+    global LIBERO_OTHER_CONSTRAINTS
+    if { [info exists LIBERO_OTHER_CONSTRAINTS] } {
+        set cmd "organize_tool_files -tool {SYNTHESIZE} "
+        append cmd $LIBERO_OTHER_CONSTRAINTS
+        append cmd "-module $TOP -input_type {constraint}"
+        eval $cmd
+        set cmd "organize_tool_files -tool {VERIFYTIMING} "
+        append cmd $LIBERO_OTHER_CONSTRAINTS
+        append cmd "-module $TOP -input_type {constraint}"
+        eval $cmd
+    }
+    if { [info exists LIBERO_PLACE_CONSTRAINTS] } {
+        set cmd "organize_tool_files -tool {PLACEROUTE} "
+        append cmd $LIBERO_PLACE_CONSTRAINTS
+        append cmd "-module $TOP -input_type {constraint}"
+        eval $cmd
     }
 }
 
 proc fpga_params {} {
-    global TOOL PARAMS
     if { [llength $PARAMS] == 0 } { return }
-    fpga_print "setting generics/parameters"
-    switch $TOOL {
-        "libero"  {
-            # They must be specified after set_root (see fpga_top)
-        }
-    }
+    # They must be specified after set_root (see fpga_top)
 }
 
 proc fpga_run_syn {} {
-    global TOOL PRESYNTH
-    fpga_print "running 'synthesis'"
-    switch $TOOL {
-        "libero"  {
-            run_tool -name {SYNTHESIZE}
-        }
-    }
+    run_tool -name {SYNTHESIZE}
 }
 
 proc fpga_run_par {} {
-    global TOOL PRESYNTH
-    fpga_print "running 'place and route'"
-    switch $TOOL {
-        "libero"  {
-            run_tool -name {PLACEROUTE}
-            run_tool -name {VERIFYTIMING}
-        }
-    }
+    run_tool -name {PLACEROUTE}
+    run_tool -name {VERIFYTIMING}
 }
 
 proc fpga_run_bit {} {
-    global TOOL PROJECT TOP
-    fpga_print "running 'bitstream generation'"
-    switch $TOOL {
-        "libero"  {
-            run_tool -name {GENERATEPROGRAMMINGFILE}
-        }
-    }
+    run_tool -name {GENERATEPROGRAMMINGFILE}
 }
 
-#
-# Start of the script
-#
-
-fpga_print "start of the Tcl script (interpreter $tcl_version)"
-
-#
-# Project Creation
-#
-
 if { [lsearch -exact $TASKS "prj"] >= 0 } {
-    fpga_print "running the Project Creation"
-    if { [catch {
-        fpga_create $PROJECT
-        fpga_part $PART
-        fpga_commands "prefile"
-        fpga_files
-        fpga_top $TOP
-        fpga_params
-        fpga_commands "project"
-        fpga_close
-    } ERRMSG]} {
-        puts "ERROR: there was a problem creating a New Project.\n"
-        puts $ERRMSG
-        exit 1
-    }
+    fpga_create $PROJECT
+    fpga_part $PART
+    {{ PRECFG }}
+    fpga_files
+    fpga_top $TOP
+    fpga_params
+    {{ POSTCFG }}
+    fpga_close
 }
 
-#
-# Design Flow
-#
-
 if { [lsearch -regexp $TASKS "syn|par|bit"] >= 0 } {
-    fpga_print "running the Design Flow"
-    if { [catch {
-        fpga_open $PROJECT
-        fpga_commands "preflow"
-        if { [lsearch -exact $TASKS "syn"] >= 0 } {
-            fpga_run_syn
-            fpga_commands "postsyn"
-        }
-        if { [lsearch -exact $TASKS "par"] >= 0 } {
-            fpga_run_par
-            fpga_commands "postpar"
-        }
-        if { [lsearch -exact $TASKS "bit"] >= 0 } {
-            fpga_run_bit
-            fpga_commands "postbit"
-        }
-        fpga_close
-    } ERRMSG]} {
-        puts "ERROR: there was a problem running the Design Flow.\n"
-        puts $ERRMSG
-        exit 2
+    fpga_open $PROJECT
+    if { [lsearch -exact $TASKS "syn"] >= 0 } {
+        {{ PRESYN }}
+        fpga_run_syn
+    }
+    if { [lsearch -exact $TASKS "par"] >= 0 } {
+        {{ PREPAR }}
+        fpga_run_par
+    }
+    if { [lsearch -exact $TASKS "bit"] >= 0 } {
+        {{ PREBIT }}
+        fpga_run_bit
+        {{ POSTBIT }}
     }
+    fpga_close
 }
-
-#
-# End of the script
-#
-
-fpga_print "end of the Tcl script"
diff --git a/pyfpga/templates/quartus.jinja b/pyfpga/templates/quartus.jinja
index 8e54e4ea..4a46bce8 100644
--- a/pyfpga/templates/quartus.jinja
+++ b/pyfpga/templates/quartus.jinja
@@ -5,7 +5,6 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-set TOOL     #TOOL#
 set PRESYNTH #PRESYNTH#
 set PROJECT  #PROJECT#
 set PART     #PART#
@@ -23,239 +22,108 @@ proc fpga_files {} {
 #FILES#
 }
 
-proc fpga_commands { PHASE } {
-    fpga_print "setting commands for the phase '$PHASE'"
-    switch $PHASE {
-        "prefile" {
-#PREFILE_CMDS#
-        }
-        "project" {
-#PROJECT_CMDS#
-        }
-        "preflow" {
-#PREFLOW_CMDS#
-        }
-        "postsyn" {
-#POSTSYN_CMDS#
-        }
-        "postpar" {
-#POSTPAR_CMDS#
-        }
-        "postbit" {
-#POSTBIT_CMDS#
-        }
-    }
-}
-
-#
-# Procedures
-#
-
-proc fpga_print { MSG } {
-    global TOOL
-    puts ">>> PyFPGA ($TOOL): $MSG"
-}
-
 proc fpga_create { PROJECT } {
-    global TOOL
-    fpga_print "creating the project '$PROJECT'"
-    switch $TOOL {
-        "quartus" {
-            package require ::quartus::project
-            project_new $PROJECT -overwrite
-            set_global_assignment -name NUM_PARALLEL_PROCESSORS ALL
-        }
-    }
+    package require ::quartus::project
+    project_new $PROJECT -overwrite
+    set_global_assignment -name NUM_PARALLEL_PROCESSORS ALL
 }
 
 proc fpga_open { PROJECT } {
-    global TOOL
-    fpga_print "opening the project '$PROJECT'"
-    switch $TOOL {
-        "quartus" {
-            package require ::quartus::flow
-            project_open -force $PROJECT.qpf
-        }
-    }
+    package require ::quartus::flow
+    project_open -force $PROJECT.qpf
 }
 
 proc fpga_close {} {
-    global TOOL
-    fpga_print "closing the project"
-    switch $TOOL {
-        "quartus" { project_close }
-    }
+    project_close
 }
 
 proc fpga_part { PART } {
-    global TOOL FAMILY DEVICE PACKAGE SPEED
-    fpga_print "adding the part '$PART'"
-    switch $TOOL {
-        "quartus" {
-            set_global_assignment -name DEVICE $PART
-        }
-    }
+    set_global_assignment -name DEVICE $PART
 }
 
 proc fpga_file {FILE {LIBRARY "work"}} {
-    global TOOL TOP
     set message "adding the file '$FILE'"
     if { $LIBRARY != "work" } { append message " (into the VHDL library '$LIBRARY')" }
-    fpga_print $message
     regexp -nocase {\.(\w*)$} $FILE -> ext
     if { $ext == "tcl" } {
         source $FILE
         return
     }
-    switch $TOOL {
-        "quartus" {
-            if {$ext == "v"} {
-                set TYPE VERILOG_FILE
-            } elseif {$ext == "sv"} {
-                set TYPE SYSTEMVERILOG_FILE
-            } elseif {$ext == "vhdl" || $ext == "vhd"} {
-                set TYPE VHDL_FILE
-            } elseif {$ext == "sdc"} {
-                set TYPE SDC_FILE
-            } else {
-                set TYPE SOURCE_FILE
-            }
-            if { $LIBRARY != "work" } {
-                set_global_assignment -name $TYPE $FILE -library $LIBRARY
-            } else {
-                set_global_assignment -name $TYPE $FILE
-            }
-        }
+    if {$ext == "v"} {
+        set TYPE VERILOG_FILE
+    } elseif {$ext == "sv"} {
+        set TYPE SYSTEMVERILOG_FILE
+    } elseif {$ext == "vhdl" || $ext == "vhd"} {
+        set TYPE VHDL_FILE
+    } elseif {$ext == "sdc"} {
+        set TYPE SDC_FILE
+    } else {
+        set TYPE SOURCE_FILE
+    }
+    if { $LIBRARY != "work" } {
+        set_global_assignment -name $TYPE $FILE -library $LIBRARY
+    } else {
+        set_global_assignment -name $TYPE $FILE
     }
 }
 
 proc fpga_include {PATH} {
-    global TOOL INCLUDED
     lappend INCLUDED $PATH
-    fpga_print "setting '$PATH' as a search location"
-    switch $TOOL {
-        "quartus" {
-            # Verilog Included Files are NOT added
-            foreach INCLUDE $INCLUDED {
-                set_global_assignment -name SEARCH_PATH $INCLUDE
-            }
-        }
+    # Verilog Included Files are NOT added
+    foreach INCLUDE $INCLUDED {
+        set_global_assignment -name SEARCH_PATH $INCLUDE
     }
 }
 
 proc fpga_top { TOP } {
-    global TOOL
-    fpga_print "specifying the top level '$TOP'"
-    switch $TOOL {
-        "quartus" {
-            set_global_assignment -name TOP_LEVEL_ENTITY $TOP
-        }
-    }
+    set_global_assignment -name TOP_LEVEL_ENTITY $TOP
 }
 
 proc fpga_params {} {
-    global TOOL PARAMS
     if { [llength $PARAMS] == 0 } { return }
-    fpga_print "setting generics/parameters"
-    switch $TOOL {
-        "quartus" {
-            foreach PARAM $PARAMS {
-                eval "set_parameter -name $PARAM"
-            }
-        }
+    foreach PARAM $PARAMS {
+        eval "set_parameter -name $PARAM"
     }
 }
 
 proc fpga_run_syn {} {
-    global TOOL PRESYNTH
-    fpga_print "running 'synthesis'"
-    switch $TOOL {
-        "quartus" {
-            execute_module -tool map
-        }
-    }
+    execute_module -tool map
 }
 
 proc fpga_run_par {} {
-    global TOOL PRESYNTH
-    fpga_print "running 'place and route'"
-    switch $TOOL {
-        "quartus" {
-            execute_module -tool fit
-            execute_module -tool sta
-        }
-    }
+    execute_module -tool fit
+    execute_module -tool sta
 }
 
 proc fpga_run_bit {} {
-    global TOOL PROJECT TOP
-    fpga_print "running 'bitstream generation'"
-    switch $TOOL {
-        "quartus" {
-            execute_module -tool asm
-        }
-    }
+    execute_module -tool asm
 }
 
-#
-# Start of the script
-#
-
-fpga_print "start of the Tcl script (interpreter $tcl_version)"
-
-#
-# Project Creation
-#
-
 if { [lsearch -exact $TASKS "prj"] >= 0 } {
-    fpga_print "running the Project Creation"
-    if { [catch {
-        fpga_create $PROJECT
-        fpga_part $PART
-        fpga_commands "prefile"
-        fpga_files
-        fpga_top $TOP
-        fpga_params
-        fpga_commands "project"
-        fpga_close
-    } ERRMSG]} {
-        puts "ERROR: there was a problem creating a New Project.\n"
-        puts $ERRMSG
-        exit 1
-    }
+    fpga_create $PROJECT
+    fpga_part $PART
+    {{ PRECFG }}
+    fpga_files
+    fpga_top $TOP
+    fpga_params
+    {{ POSTCFG }}
+    fpga_close
 }
 
-#
-# Design Flow
-#
-
 if { [lsearch -regexp $TASKS "syn|par|bit"] >= 0 } {
-    fpga_print "running the Design Flow"
-    if { [catch {
-        fpga_open $PROJECT
-        fpga_commands "preflow"
-        if { [lsearch -exact $TASKS "syn"] >= 0 } {
-            fpga_run_syn
-            fpga_commands "postsyn"
-        }
-        if { [lsearch -exact $TASKS "par"] >= 0 } {
-            fpga_run_par
-            fpga_commands "postpar"
-        }
-        if { [lsearch -exact $TASKS "bit"] >= 0 } {
-            fpga_run_bit
-            fpga_commands "postbit"
-        }
-        fpga_close
-    } ERRMSG]} {
-        puts "ERROR: there was a problem running the Design Flow.\n"
-        puts $ERRMSG
-        exit 2
+    fpga_open $PROJECT
+    if { [lsearch -exact $TASKS "syn"] >= 0 } {
+        {{ PRESYN }}
+        fpga_run_syn
+    }
+    if { [lsearch -exact $TASKS "par"] >= 0 } {
+        {{ PREPAR }}
+        fpga_run_par
+    }
+    if { [lsearch -exact $TASKS "bit"] >= 0 } {
+        {{ PREBIT }}
+        fpga_run_bit
+        {{ POSTBIT }}
     }
+    fpga_close
 }
-
-#
-# End of the script
-#
-
-fpga_print "end of the Tcl script"
diff --git a/pyfpga/templates/vivado.jinja b/pyfpga/templates/vivado.jinja
index 5758f1c7..a8fac10d 100644
--- a/pyfpga/templates/vivado.jinja
+++ b/pyfpga/templates/vivado.jinja
@@ -5,7 +5,6 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-set TOOL     #TOOL#
 set PRESYNTH #PRESYNTH#
 set PROJECT  #PROJECT#
 set PART     #PART#
@@ -23,249 +22,117 @@ proc fpga_files {} {
 #FILES#
 }
 
-proc fpga_commands { PHASE } {
-    fpga_print "setting commands for the phase '$PHASE'"
-    switch $PHASE {
-        "prefile" {
-#PREFILE_CMDS#
-        }
-        "project" {
-#PROJECT_CMDS#
-        }
-        "preflow" {
-#PREFLOW_CMDS#
-        }
-        "postsyn" {
-#POSTSYN_CMDS#
-        }
-        "postpar" {
-#POSTPAR_CMDS#
-        }
-        "postbit" {
-#POSTBIT_CMDS#
-        }
-    }
-}
-
-#
-# Procedures
-#
-
-proc fpga_print { MSG } {
-    global TOOL
-    puts ">>> PyFPGA ($TOOL): $MSG"
-}
-
 proc fpga_create { PROJECT } {
-    global TOOL
-    fpga_print "creating the project '$PROJECT'"
-    switch $TOOL {
-        "vivado"  { create_project -force $PROJECT }
-    }
+    create_project -force $PROJECT
 }
 
 proc fpga_open { PROJECT } {
-    global TOOL
-    fpga_print "opening the project '$PROJECT'"
-    switch $TOOL {
-        "vivado"  { open_project $PROJECT }
-    }
+    open_project $PROJECT
 }
 
 proc fpga_close {} {
-    global TOOL
-    fpga_print "closing the project"
-    switch $TOOL {
-        "vivado"  { close_project }
-    }
+    close_project
 }
 
 proc fpga_part { PART } {
-    global TOOL FAMILY DEVICE PACKAGE SPEED
-    fpga_print "adding the part '$PART'"
-    switch $TOOL {
-        "vivado"  {
-            set_property "part" $PART [current_project]
-        }
-    }
-}
+    set_property "part" $PART [current_project]
+ }
 
 proc fpga_file {FILE {LIBRARY "work"}} {
-    global TOOL TOP
     set message "adding the file '$FILE'"
     if { $LIBRARY != "work" } { append message " (into the VHDL library '$LIBRARY')" }
-    fpga_print $message
     regexp -nocase {\.(\w*)$} $FILE -> ext
     if { $ext == "tcl" } {
         source $FILE
         return
     }
-    switch $TOOL {
-        "vivado" {
-            if { $LIBRARY != "work" } {
-                add_files $FILE
-                set_property library $LIBRARY [get_files $FILE]
-            } else {
-                add_files $FILE
-            }
-        }
+    if { $LIBRARY != "work" } {
+        add_files $FILE
+        set_property library $LIBRARY [get_files $FILE]
+    } else {
+        add_files $FILE
     }
 }
 
 proc fpga_include {PATH} {
-    global TOOL INCLUDED
     lappend INCLUDED $PATH
-    fpga_print "setting '$PATH' as a search location"
-    switch $TOOL {
-        "vivado" {
-            # Verilog Included Files are NOT added
-            set_property "include_dirs" $INCLUDED [current_fileset]
-        }
-    }
+    # Verilog Included Files are NOT added
+    set_property "include_dirs" $INCLUDED [current_fileset]
 }
 
 proc fpga_design {FILE} {
-    global TOOL TOP INCLUDED
     fpga_print "including the block design '$FILE'"
-    switch $TOOL {
-        "vivado" {
-            if { [info exists INCLUDED] && [llength $INCLUDED] > 0 } {
-                set_property "ip_repo_paths" $INCLUDED [get_filesets sources_1]
-                update_ip_catalog -rebuild
-            }
-            source $FILE
-            make_wrapper -force -files [get_files design_1.bd] -top -import
-            if { $TOP == "UNDEFINED"} {
-                set TOP design_1_wrapper
-            }
-        }
+    if { [info exists INCLUDED] && [llength $INCLUDED] > 0 } {
+        set_property "ip_repo_paths" $INCLUDED [get_filesets sources_1]
+        update_ip_catalog -rebuild
+    }
+    source $FILE
+    make_wrapper -force -files [get_files design_1.bd] -top -import
+    if { $TOP == "UNDEFINED"} {
+        set TOP design_1_wrapper
     }
 }
 
 proc fpga_top { TOP } {
-    global TOOL
-    fpga_print "specifying the top level '$TOP'"
-    switch $TOOL {
-        "vivado"  {
-            set_property top $TOP [current_fileset]
-        }
-    }
+    set_property top $TOP [current_fileset]
 }
 
 proc fpga_params {} {
-    global TOOL PARAMS
     if { [llength $PARAMS] == 0 } { return }
-    fpga_print "setting generics/parameters"
-    switch $TOOL {
-        "vivado"  {
-            set assigns [list]
-            foreach PARAM $PARAMS { lappend assigns [join $PARAM "="] }
-            set obj [get_filesets sources_1]
-            set_property "generic" "[join $assigns]" -objects $obj
-        }
-    }
+    set assigns [list]
+    foreach PARAM $PARAMS { lappend assigns [join $PARAM "="] }
+    set obj [get_filesets sources_1]
+    set_property "generic" "[join $assigns]" -objects $obj
 }
 
 proc fpga_run_syn {} {
-    global TOOL PRESYNTH
-    fpga_print "running 'synthesis'"
-    switch $TOOL {
-        "vivado"  {
-            if { $PRESYNTH == "True" } {
-                set_property design_mode GateLvl [current_fileset]
-            } else {
-                reset_run synth_1
-                launch_runs synth_1
-                wait_on_run synth_1
-            }
-        }
+    if { $PRESYNTH == "True" } {
+        set_property design_mode GateLvl [current_fileset]
+    } else {
+        reset_run synth_1
+        launch_runs synth_1
+        wait_on_run synth_1
     }
 }
 
 proc fpga_run_par {} {
-    global TOOL PRESYNTH
-    fpga_print "running 'place and route'"
-    switch $TOOL {
-        "vivado"  {
-            if {$PRESYNTH == "False"} {
-                open_run synth_1
-            }
-            launch_runs impl_1
-            wait_on_run impl_1
-        }
+    if {$PRESYNTH == "False"} {
+        open_run synth_1
     }
+    launch_runs impl_1
+    wait_on_run impl_1
 }
 
 proc fpga_run_bit {} {
-    global TOOL PROJECT TOP
-    fpga_print "running 'bitstream generation'"
-    switch $TOOL {
-        "vivado"  {
-            open_run impl_1
-            write_bitstream -force $PROJECT
-        }
-    }
+    open_run impl_1
+    write_bitstream -force $PROJECT
 }
 
-#
-# Start of the script
-#
-
-fpga_print "start of the Tcl script (interpreter $tcl_version)"
-
-#
-# Project Creation
-#
-
 if { [lsearch -exact $TASKS "prj"] >= 0 } {
-    fpga_print "running the Project Creation"
-    if { [catch {
-        fpga_create $PROJECT
-        fpga_part $PART
-        fpga_commands "prefile"
-        fpga_files
-        fpga_top $TOP
-        fpga_params
-        fpga_commands "project"
-        fpga_close
-    } ERRMSG]} {
-        puts "ERROR: there was a problem creating a New Project.\n"
-        puts $ERRMSG
-        exit 1
-    }
+    fpga_create $PROJECT
+    fpga_part $PART
+    {{ PRECFG }}
+    fpga_files
+    fpga_top $TOP
+    fpga_params
+    {{ POSTCFG }}
+    fpga_close
 }
 
-#
-# Design Flow
-#
-
 if { [lsearch -regexp $TASKS "syn|par|bit"] >= 0 } {
-    fpga_print "running the Design Flow"
-    if { [catch {
-        fpga_open $PROJECT
-        fpga_commands "preflow"
-        if { [lsearch -exact $TASKS "syn"] >= 0 } {
-            fpga_run_syn
-            fpga_commands "postsyn"
-        }
-        if { [lsearch -exact $TASKS "par"] >= 0 } {
-            fpga_run_par
-            fpga_commands "postpar"
-        }
-        if { [lsearch -exact $TASKS "bit"] >= 0 } {
-            fpga_run_bit
-            fpga_commands "postbit"
-        }
-        fpga_close
-    } ERRMSG]} {
-        puts "ERROR: there was a problem running the Design Flow.\n"
-        puts $ERRMSG
-        exit 2
+    fpga_open $PROJECT
+    if { [lsearch -exact $TASKS "syn"] >= 0 } {
+        {{ PRESYN }}
+        fpga_run_syn
+    }
+    if { [lsearch -exact $TASKS "par"] >= 0 } {
+        {{ PREPAR }}
+        fpga_run_par
+    }
+    if { [lsearch -exact $TASKS "bit"] >= 0 } {
+        {{ PREBIT }}
+        fpga_run_bit
+        {{ POSTBIT }}
     }
+    fpga_close
 }
-
-#
-# End of the script
-#
-
-fpga_print "end of the Tcl script"

From b20db612652d8d4c85b8c16e99e95722d6133ca9 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Fri, 31 May 2024 19:34:40 -0300
Subject: [PATCH 047/248] Added two hook stages, returned to the single
 function version

---
 docs/hooks.rst    |  2 ++
 pyfpga/project.py | 47 +++++++++++++++--------------------------------
 2 files changed, 17 insertions(+), 32 deletions(-)

diff --git a/docs/hooks.rst b/docs/hooks.rst
index a9328332..498aceed 100644
--- a/docs/hooks.rst
+++ b/docs/hooks.rst
@@ -19,8 +19,10 @@ Hooks
     open project
     presyn hook
     synthesis
+    postsyn hook
     prepar hook
     place_and_route
+    postpar hook
     prebit hook
     bitstream
     postbit hook
diff --git a/pyfpga/project.py b/pyfpga/project.py
index 912a61e8..d700e8df 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -12,20 +12,11 @@
 import os
 import subprocess
 
-from enum import Enum
 from datetime import datetime
 from pathlib import Path
 from time import time
 
 
-class Step(Enum):
-    """Enumeration of supported Steps"""
-    PRJ = 'prj'
-    SYN = 'syn'
-    PAR = 'par'
-    BIT = 'bit'
-
-
 class Project:
     """Base class to manage an FPGA project.
 
@@ -116,32 +107,24 @@ def set_top(self, name):
         self.logger.debug('Executing set_top')
         self.data['top'] = name
 
-    def add_precfg_hook(self, content):
-        """Temp placeholder"""
-        raise NotImplementedError('Method is not implemented yet.')
-
-    def add_postcfg_hook(self, content):
-        """Temp placeholder"""
-        raise NotImplementedError('Method is not implemented yet.')
-
-    def add_presyn_hook(self, content):
-        """Temp placeholder"""
-        raise NotImplementedError('Method is not implemented yet.')
-
-    def add_prepar_hook(self, content):
-        """Temp placeholder"""
-        raise NotImplementedError('Method is not implemented yet.')
-
-    def add_prebit_hook(self, content):
-        """Temp placeholder"""
-        raise NotImplementedError('Method is not implemented yet.')
-
-    def add_postbit_hook(self, content):
-        """Temp placeholder"""
+    def add_hook(self, stage, hook):
+        """Add hook for a specific stage."""
+        stages = [
+            'precfg', 'postcfg', 'presyn', 'postsyn',
+            'prepar', 'postpar', 'prebit', 'postbit'
+        ]
+        if stage not in stages:
+            raise ValueError('Invalid stage.')
+        _ = self
+        _ = hook
         raise NotImplementedError('Method is not implemented yet.')
 
-    def make(self, end=Step.BIT, start=Step.PRJ, capture=False):
+    def make(self, end='bit', start='prj'):
         """Temp placeholder"""
+        steps = ['prj', 'syn', 'par', 'bit']
+        if end not in steps or start not in steps:
+            raise ValueError('Invalid steps.')
+        _ = self
         raise NotImplementedError('Method is not implemented yet.')
 
     def prog(self, position=1, bitstream=None):

From b48ad68cda44f6026ecc69b052dca7e635a9f2b7 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Fri, 31 May 2024 21:09:02 -0300
Subject: [PATCH 048/248] Templates simplified, still WIP

---
 pyfpga/templates/ise.jinja     | 157 ++++++++++++-------------
 pyfpga/templates/libero.jinja  | 201 +++++++++++++++------------------
 pyfpga/templates/quartus.jinja | 133 ++++++++++------------
 pyfpga/templates/vivado.jinja  | 156 +++++++++++--------------
 4 files changed, 291 insertions(+), 356 deletions(-)

diff --git a/pyfpga/templates/ise.jinja b/pyfpga/templates/ise.jinja
index 2aa7a6b1..a5f31223 100644
--- a/pyfpga/templates/ise.jinja
+++ b/pyfpga/templates/ise.jinja
@@ -5,41 +5,19 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-set PRESYNTH #PRESYNTH#
-set PROJECT  #PROJECT#
-set PART     #PART#
-set FAMILY   #FAMILY#
-set DEVICE   #DEVICE#
-set PACKAGE  #PACKAGE#
-set SPEED    #SPEED#
-set TOP      #TOP#
-# TASKS = prj syn par bit
-set TASKS    [list #TASKS#]
-
-set PARAMS   [list #PARAMS#]
+set PRESYNTH {{ PRESYNTH }}
+set PROJECT  {{ PROJECT }}
+set PART     {{ PART }}
+set FAMILY   {{ FAMILY }}
+set DEVICE   {{ DEVICE }}
+set PACKAGE  {{ PACKAGE }}
+set SPEED    {{ SPEED }}
+set TOP      {{ TOP }}
 
-proc fpga_files {} {
-#FILES#
-}
+set PARAMS   [list {{ PARAMS }}]
 
-proc fpga_create { PROJECT } {
-    if { [ file exists $PROJECT.xise ] } { file delete $PROJECT.xise }
-    project new $PROJECT.xise
-}
-
-proc fpga_open { PROJECT } {
-    project open $PROJECT.xise
-}
-
-proc fpga_close {} {
-    project close
-}
-
-proc fpga_part { PART } {
-    project set family  $FAMILY
-    project set device  $DEVICE
-    project set package $PACKAGE
-    project set speed   $SPEED
+proc fpga_files {} {
+{{ FILES }}
 }
 
 proc fpga_file {FILE {LIBRARY "work"}} {
@@ -67,10 +45,6 @@ proc fpga_include {PATH} {
     [join $INCLUDED "|"] -process "Synthesize - XST"
 }
 
-proc fpga_top { TOP } {
-    project set top $TOP
-}
-
 proc fpga_params {} {
     if { [llength $PARAMS] == 0 } { return }
     set assigns [list]
@@ -78,56 +52,69 @@ proc fpga_params {} {
     project set "Generics, Parameters" "[join $assigns]" -process "Synthesize - XST"
 }
 
-proc fpga_run_syn {} {
-    if { $PRESYNTH == "True" } {
-        project set top_level_module_type "EDIF"
-    } else {
-        project clean
-        process run "Synthesize"
-        if { [process get "Synthesize" status] == "errors" } { exit 2 }
-    }
-}
+#------------------------------------------------------------------------------
 
-proc fpga_run_par {} {
-    process run "Translate"
-    if { [process get "Translate" status] == "errors" } { exit 2 }
-    process run "Map"
-    if { [process get "Map" status] == "errors" } { exit 2 }
-    process run "Place & Route"
-    if { [process get "Place & Route" status] == "errors" } { exit 2 }
-}
+{% if PRJ %}
+if { [ file exists $PROJECT.xise ] } { file delete $PROJECT.xise }
+project new $PROJECT.xise
 
-proc fpga_run_bit {} {
-    process run "Generate Programming File"
-    if { [process get "Generate Programming File" status] == "errors" } { exit 2 }
-    catch { file rename -force $TOP.bit $PROJECT.bit }
-}
+project set family  $FAMILY
+project set device  $DEVICE
+project set package $PACKAGE
+project set speed   $SPEED
 
-if { [lsearch -exact $TASKS "prj"] >= 0 } {
-    fpga_create $PROJECT
-    fpga_part $PART
-    {{ PRECFG }}
-    fpga_files
-    fpga_top $TOP
-    fpga_params
-    {{ POSTCFG }}
-    fpga_close
-}
+{{ PRECFG }}
 
-if { [lsearch -regexp $TASKS "syn|par|bit"] >= 0 } {
-    fpga_open $PROJECT
-    if { [lsearch -exact $TASKS "syn"] >= 0 } {
-        {{ PRESYN }}
-        fpga_run_syn
-    }
-    if { [lsearch -exact $TASKS "par"] >= 0 } {
-        {{ PREPAR }}
-        fpga_run_par
-    }
-    if { [lsearch -exact $TASKS "bit"] >= 0 } {
-        {{ PREBIT }}
-        fpga_run_bit
-        {{ POSTBIT }}
-    }
-    fpga_close
+fpga_files
+
+project set top $TOP
+
+fpga_params
+
+{{ POSTCFG }}
+
+project close
+{% endif %}
+
+{% if SYN or PAR or BIT %}
+project open $PROJECT.xise
+
+{% if SYN %}
+{{ PRESYN }}
+
+if { $PRESYNTH == "True" } {
+    project set top_level_module_type "EDIF"
+} else {
+    project clean
+    process run "Synthesize"
+    if { [process get "Synthesize" status] == "errors" } { exit 2 }
 }
+
+{{ POSTSYN }}
+{% endif %}
+
+{% if PAR %}
+{{ PREPAR }}
+
+process run "Translate"
+if { [process get "Translate" status] == "errors" } { exit 2 }
+process run "Map"
+if { [process get "Map" status] == "errors" } { exit 2 }
+process run "Place & Route"
+if { [process get "Place & Route" status] == "errors" } { exit 2 }
+
+{{ POSTPAR }}
+{% endif %}
+
+{% if BIT %}
+{{ PREBIT }}
+
+process run "Generate Programming File"
+if { [process get "Generate Programming File" status] == "errors" } { exit 2 }
+catch { file rename -force $TOP.bit $PROJECT.bit }
+
+{{ POSTBIT }}
+{% endif %}
+
+project close
+{% endif %}
diff --git a/pyfpga/templates/libero.jinja b/pyfpga/templates/libero.jinja
index 7cdcfd33..8e703ed3 100644
--- a/pyfpga/templates/libero.jinja
+++ b/pyfpga/templates/libero.jinja
@@ -5,38 +5,19 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-set PRESYNTH #PRESYNTH#
-set PROJECT  #PROJECT#
-set PART     #PART#
-set FAMILY   #FAMILY#
-set DEVICE   #DEVICE#
-set PACKAGE  #PACKAGE#
-set SPEED    #SPEED#
-set TOP      #TOP#
-# TASKS = prj syn par bit
-set TASKS    [list #TASKS#]
-
-set PARAMS   [list #PARAMS#]
+set PRESYNTH {{ PRESYNTH }}
+set PROJECT  {{ PROJECT }}
+set PART     {{ PART }}
+set FAMILY   {{ FAMILY }}
+set DEVICE   {{ DEVICE }}
+set PACKAGE  {{ PACKAGE }}
+set SPEED    {{ SPEED }}
+set TOP      {{ TOP }}
 
-proc fpga_files {} {
-#FILES#
-}
-
-proc fpga_create { PROJECT } {
-    if { [ file exists $PROJECT ] } { file delete -force -- $PROJECT }
-    new_project -name $PROJECT -location $PROJECT -hdl {VHDL} -family {SmartFusion2}
-}
-
-proc fpga_open { PROJECT } {
-    open_project $PROJECT/$PROJECT.prjx
-}
+set PARAMS   [list {{ PARAMS }}]
 
-proc fpga_close {} {
-    close_project
-}
-
-proc fpga_part { PART } {
-    set_device -family $FAMILY -die $DEVICE -package $PACKAGE -speed $SPEED
+proc fpga_files {} {
+{{ FILES }}
 }
 
 proc fpga_file {FILE {LIBRARY "work"}} {
@@ -72,90 +53,96 @@ proc fpga_include {PATH} {
     build_design_hierarchy
 }
 
-proc fpga_top { TOP } {
-    set_root $TOP
-    # Verilog Included files
-    set cmd "configure_tool -name {SYNTHESIZE} -params {SYNPLIFY_OPTIONS:"
-    if { [info exists INCLUDED] && [llength $INCLUDED] > 0 } {
-        # See <ROOT>/poc/include/libero.tcl for details
-        set PATHS "../../"
-        append PATHS [join $INCLUDED ";../../"]
-        append cmd "set_option -include_path \"$PATHS\""
-        append cmd "\n"
-    }
-    foreach PARAM $PARAMS {
-        set assign [join $PARAM]
-        append cmd "set_option -hdl_param -set \"$assign\""
-        append cmd "\n"
-    }
-    append cmd "}"
-    eval $cmd
-    # Constraints
-    # PDC is only used for PLACEROUTE.
-    # SDC is used by ALL (SYNTHESIZE, PLACEROUTE and VERIFYTIMING).
-    global LIBERO_PLACE_CONSTRAINTS
-    global LIBERO_OTHER_CONSTRAINTS
-    if { [info exists LIBERO_OTHER_CONSTRAINTS] } {
-        set cmd "organize_tool_files -tool {SYNTHESIZE} "
-        append cmd $LIBERO_OTHER_CONSTRAINTS
-        append cmd "-module $TOP -input_type {constraint}"
-        eval $cmd
-        set cmd "organize_tool_files -tool {VERIFYTIMING} "
-        append cmd $LIBERO_OTHER_CONSTRAINTS
-        append cmd "-module $TOP -input_type {constraint}"
-        eval $cmd
-    }
-    if { [info exists LIBERO_PLACE_CONSTRAINTS] } {
-        set cmd "organize_tool_files -tool {PLACEROUTE} "
-        append cmd $LIBERO_PLACE_CONSTRAINTS
-        append cmd "-module $TOP -input_type {constraint}"
-        eval $cmd
-    }
-}
-
 proc fpga_params {} {
     if { [llength $PARAMS] == 0 } { return }
     # They must be specified after set_root (see fpga_top)
 }
 
-proc fpga_run_syn {} {
-    run_tool -name {SYNTHESIZE}
-}
+#------------------------------------------------------------------------------
 
-proc fpga_run_par {} {
-    run_tool -name {PLACEROUTE}
-    run_tool -name {VERIFYTIMING}
-}
+{% if PRJ %}
+if { [ file exists $PROJECT ] } { file delete -force -- $PROJECT }
+new_project -name $PROJECT -location $PROJECT -hdl {VHDL} -family {SmartFusion2}
 
-proc fpga_run_bit {} {
-    run_tool -name {GENERATEPROGRAMMINGFILE}
-}
+set_device -family $FAMILY -die $DEVICE -package $PACKAGE -speed $SPEED
 
-if { [lsearch -exact $TASKS "prj"] >= 0 } {
-    fpga_create $PROJECT
-    fpga_part $PART
-    {{ PRECFG }}
-    fpga_files
-    fpga_top $TOP
-    fpga_params
-    {{ POSTCFG }}
-    fpga_close
-}
+{{ PRECFG }}
 
-if { [lsearch -regexp $TASKS "syn|par|bit"] >= 0 } {
-    fpga_open $PROJECT
-    if { [lsearch -exact $TASKS "syn"] >= 0 } {
-        {{ PRESYN }}
-        fpga_run_syn
-    }
-    if { [lsearch -exact $TASKS "par"] >= 0 } {
-        {{ PREPAR }}
-        fpga_run_par
-    }
-    if { [lsearch -exact $TASKS "bit"] >= 0 } {
-        {{ PREBIT }}
-        fpga_run_bit
-        {{ POSTBIT }}
-    }
-    fpga_close
+fpga_files
+
+set_root $TOP
+# Verilog Included files
+set cmd "configure_tool -name {SYNTHESIZE} -params {SYNPLIFY_OPTIONS:"
+if { [info exists INCLUDED] && [llength $INCLUDED] > 0 } {
+    # See <ROOT>/poc/include/libero.tcl for details
+    set PATHS "../../"
+    append PATHS [join $INCLUDED ";../../"]
+    append cmd "set_option -include_path \"$PATHS\""
+    append cmd "\n"
+}
+foreach PARAM $PARAMS {
+    set assign [join $PARAM]
+    append cmd "set_option -hdl_param -set \"$assign\""
+    append cmd "\n"
+}
+append cmd "}"
+eval $cmd
+# Constraints
+# PDC is only used for PLACEROUTE.
+# SDC is used by ALL (SYNTHESIZE, PLACEROUTE and VERIFYTIMING).
+global LIBERO_PLACE_CONSTRAINTS
+global LIBERO_OTHER_CONSTRAINTS
+if { [info exists LIBERO_OTHER_CONSTRAINTS] } {
+    set cmd "organize_tool_files -tool {SYNTHESIZE} "
+    append cmd $LIBERO_OTHER_CONSTRAINTS
+    append cmd "-module $TOP -input_type {constraint}"
+    eval $cmd
+    set cmd "organize_tool_files -tool {VERIFYTIMING} "
+    append cmd $LIBERO_OTHER_CONSTRAINTS
+    append cmd "-module $TOP -input_type {constraint}"
+    eval $cmd
+}
+if { [info exists LIBERO_PLACE_CONSTRAINTS] } {
+    set cmd "organize_tool_files -tool {PLACEROUTE} "
+    append cmd $LIBERO_PLACE_CONSTRAINTS
+    append cmd "-module $TOP -input_type {constraint}"
+    eval $cmd
 }
+
+fpga_params
+
+{{ POSTCFG }}
+
+close_project
+{% endif %}
+
+{% if SYN or PAR or BIT %}
+open_project $PROJECT/$PROJECT.prjx
+
+{% if SYN %}
+{{ PRESYN }}
+
+run_tool -name {SYNTHESIZE}
+
+{{ POSTSYN }}
+{% endif %}
+
+{% if PAR %}
+{{ PREPAR }}
+
+run_tool -name {PLACEROUTE}
+run_tool -name {VERIFYTIMING}
+
+{{ POSTPAR }}
+{% endif %}
+
+{% if BIT %}
+{{ PREBIT }}
+
+run_tool -name {GENERATEPROGRAMMINGFILE}
+
+{{ POSTBIT }}
+{% endif %}
+
+close_project
+{% endif %}
diff --git a/pyfpga/templates/quartus.jinja b/pyfpga/templates/quartus.jinja
index 4a46bce8..966035ca 100644
--- a/pyfpga/templates/quartus.jinja
+++ b/pyfpga/templates/quartus.jinja
@@ -5,40 +5,19 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-set PRESYNTH #PRESYNTH#
-set PROJECT  #PROJECT#
-set PART     #PART#
-set FAMILY   #FAMILY#
-set DEVICE   #DEVICE#
-set PACKAGE  #PACKAGE#
-set SPEED    #SPEED#
-set TOP      #TOP#
-# TASKS = prj syn par bit
-set TASKS    [list #TASKS#]
-
-set PARAMS   [list #PARAMS#]
+set PRESYNTH {{ PRESYNTH }}
+set PROJECT  {{ PROJECT }}
+set PART     {{ PART }}
+set FAMILY   {{ FAMILY }}
+set DEVICE   {{ DEVICE }}
+set PACKAGE  {{ PACKAGE }}
+set SPEED    {{ SPEED }}
+set TOP      {{ TOP }}
 
-proc fpga_files {} {
-#FILES#
-}
+set PARAMS   [list {{ PARAMS }}]
 
-proc fpga_create { PROJECT } {
-    package require ::quartus::project
-    project_new $PROJECT -overwrite
-    set_global_assignment -name NUM_PARALLEL_PROCESSORS ALL
-}
-
-proc fpga_open { PROJECT } {
-    package require ::quartus::flow
-    project_open -force $PROJECT.qpf
-}
-
-proc fpga_close {} {
-    project_close
-}
-
-proc fpga_part { PART } {
-    set_global_assignment -name DEVICE $PART
+proc fpga_files {} {
+{{ FILES }}
 }
 
 proc fpga_file {FILE {LIBRARY "work"}} {
@@ -75,10 +54,6 @@ proc fpga_include {PATH} {
     }
 }
 
-proc fpga_top { TOP } {
-    set_global_assignment -name TOP_LEVEL_ENTITY $TOP
-}
-
 proc fpga_params {} {
     if { [llength $PARAMS] == 0 } { return }
     foreach PARAM $PARAMS {
@@ -86,44 +61,56 @@ proc fpga_params {} {
     }
 }
 
-proc fpga_run_syn {} {
-    execute_module -tool map
-}
+#------------------------------------------------------------------------------
 
-proc fpga_run_par {} {
-    execute_module -tool fit
-    execute_module -tool sta
-}
+{% if PRJ %}
+package require ::quartus::project
+project_new $PROJECT -overwrite
+set_global_assignment -name NUM_PARALLEL_PROCESSORS ALL
 
-proc fpga_run_bit {} {
-    execute_module -tool asm
-}
+set_global_assignment -name DEVICE $PART
 
-if { [lsearch -exact $TASKS "prj"] >= 0 } {
-    fpga_create $PROJECT
-    fpga_part $PART
-    {{ PRECFG }}
-    fpga_files
-    fpga_top $TOP
-    fpga_params
-    {{ POSTCFG }}
-    fpga_close
-}
+{{ PRECFG }}
 
-if { [lsearch -regexp $TASKS "syn|par|bit"] >= 0 } {
-    fpga_open $PROJECT
-    if { [lsearch -exact $TASKS "syn"] >= 0 } {
-        {{ PRESYN }}
-        fpga_run_syn
-    }
-    if { [lsearch -exact $TASKS "par"] >= 0 } {
-        {{ PREPAR }}
-        fpga_run_par
-    }
-    if { [lsearch -exact $TASKS "bit"] >= 0 } {
-        {{ PREBIT }}
-        fpga_run_bit
-        {{ POSTBIT }}
-    }
-    fpga_close
-}
+fpga_files
+
+set_global_assignment -name TOP_LEVEL_ENTITY $TOP
+
+fpga_params
+
+{{ POSTCFG }}
+
+project_close
+{% endif %}
+
+{% if SYN or PAR or BIT %}
+package require ::quartus::flow
+project_open -force $PROJECT.qpf
+
+{% if SYN %}
+{{ PRESYN }}
+
+execute_module -tool map
+
+{{ POSTSYN }}
+{% endif %}
+
+{% if PAR %}
+{{ PREPAR }}
+
+execute_module -tool fit
+execute_module -tool sta
+
+{{ POSTPAR }}
+{% endif %}
+
+{% if BIT %}
+{{ PREBIT }}
+
+execute_module -tool asm
+
+{{ POSTBIT }}
+{% endif %}
+
+project_close
+{% endif %}
diff --git a/pyfpga/templates/vivado.jinja b/pyfpga/templates/vivado.jinja
index a8fac10d..0cb772ea 100644
--- a/pyfpga/templates/vivado.jinja
+++ b/pyfpga/templates/vivado.jinja
@@ -5,39 +5,21 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-set PRESYNTH #PRESYNTH#
-set PROJECT  #PROJECT#
-set PART     #PART#
-set FAMILY   #FAMILY#
-set DEVICE   #DEVICE#
-set PACKAGE  #PACKAGE#
-set SPEED    #SPEED#
-set TOP      #TOP#
-# TASKS = prj syn par bit
-set TASKS    [list #TASKS#]
-
-set PARAMS   [list #PARAMS#]
+set PRESYNTH {{ PRESYNTH }}
+set PROJECT  {{ PROJECT }}
+set PART     {{ PART }}
+set FAMILY   {{ FAMILY }}
+set DEVICE   {{ DEVICE }}
+set PACKAGE  {{ PACKAGE }}
+set SPEED    {{ SPEED }}
+set TOP      {{ TOP }}
 
-proc fpga_files {} {
-#FILES#
-}
-
-proc fpga_create { PROJECT } {
-    create_project -force $PROJECT
-}
-
-proc fpga_open { PROJECT } {
-    open_project $PROJECT
-}
+set PARAMS   [list {{ PARAMS }}]
 
-proc fpga_close {} {
-    close_project
+proc fpga_files {} {
+{{ FILES }}
 }
 
-proc fpga_part { PART } {
-    set_property "part" $PART [current_project]
- }
-
 proc fpga_file {FILE {LIBRARY "work"}} {
     set message "adding the file '$FILE'"
     if { $LIBRARY != "work" } { append message " (into the VHDL library '$LIBRARY')" }
@@ -60,23 +42,6 @@ proc fpga_include {PATH} {
     set_property "include_dirs" $INCLUDED [current_fileset]
 }
 
-proc fpga_design {FILE} {
-    fpga_print "including the block design '$FILE'"
-    if { [info exists INCLUDED] && [llength $INCLUDED] > 0 } {
-        set_property "ip_repo_paths" $INCLUDED [get_filesets sources_1]
-        update_ip_catalog -rebuild
-    }
-    source $FILE
-    make_wrapper -force -files [get_files design_1.bd] -top -import
-    if { $TOP == "UNDEFINED"} {
-        set TOP design_1_wrapper
-    }
-}
-
-proc fpga_top { TOP } {
-    set_property top $TOP [current_fileset]
-}
-
 proc fpga_params {} {
     if { [llength $PARAMS] == 0 } { return }
     set assigns [list]
@@ -85,54 +50,63 @@ proc fpga_params {} {
     set_property "generic" "[join $assigns]" -objects $obj
 }
 
-proc fpga_run_syn {} {
-    if { $PRESYNTH == "True" } {
-        set_property design_mode GateLvl [current_fileset]
-    } else {
-        reset_run synth_1
-        launch_runs synth_1
-        wait_on_run synth_1
-    }
-}
+#------------------------------------------------------------------------------
 
-proc fpga_run_par {} {
-    if {$PRESYNTH == "False"} {
-        open_run synth_1
-    }
-    launch_runs impl_1
-    wait_on_run impl_1
-}
+{% if PRJ %}
+create_project -force $PROJECT
 
-proc fpga_run_bit {} {
-    open_run impl_1
-    write_bitstream -force $PROJECT
-}
+set_property "part" $PART [current_project]
+
+{{ PRECFG }}
+
+fpga_files
+
+set_property top $TOP [current_fileset]
+
+fpga_params
 
-if { [lsearch -exact $TASKS "prj"] >= 0 } {
-    fpga_create $PROJECT
-    fpga_part $PART
-    {{ PRECFG }}
-    fpga_files
-    fpga_top $TOP
-    fpga_params
-    {{ POSTCFG }}
-    fpga_close
+{{ POSTCFG }}
+
+close_project
+{% endif %}
+
+{% if SYN or PAR or BIT %}
+open_project $PROJECT
+
+{% if SYN %}
+{{ PRESYN }}
+
+if { $PRESYNTH == "True" } {
+    set_property design_mode GateLvl [current_fileset]
+} else {
+    reset_run synth_1
+    launch_runs synth_1
+    wait_on_run synth_1
 }
 
-if { [lsearch -regexp $TASKS "syn|par|bit"] >= 0 } {
-    fpga_open $PROJECT
-    if { [lsearch -exact $TASKS "syn"] >= 0 } {
-        {{ PRESYN }}
-        fpga_run_syn
-    }
-    if { [lsearch -exact $TASKS "par"] >= 0 } {
-        {{ PREPAR }}
-        fpga_run_par
-    }
-    if { [lsearch -exact $TASKS "bit"] >= 0 } {
-        {{ PREBIT }}
-        fpga_run_bit
-        {{ POSTBIT }}
-    }
-    fpga_close
+{{ POSTSYN }}
+{% endif %}
+
+{% if PAR %}
+{{ PREPAR }}
+
+if {$PRESYNTH == "False"} {
+    open_run synth_1
 }
+launch_runs impl_1
+wait_on_run impl_1
+
+{{ POSTPAR }}
+{% endif %}
+
+{% if BIT %}
+{{ PREBIT }}
+
+open_run impl_1
+write_bitstream -force $PROJECT
+
+{{ POSTBIT }}
+{% endif %}
+
+close_project
+{% endif %}

From 52e82f1c36816efe0be6f11b4fc61169952a814b Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Fri, 31 May 2024 22:02:01 -0300
Subject: [PATCH 049/248] Renamed step PRJ as CFG

---
 pyfpga/project.py              | 2 +-
 pyfpga/templates/ise.jinja     | 6 ++++--
 pyfpga/templates/libero.jinja  | 6 ++++--
 pyfpga/templates/quartus.jinja | 8 +++++---
 pyfpga/templates/vivado.jinja  | 9 +++++++--
 5 files changed, 21 insertions(+), 10 deletions(-)

diff --git a/pyfpga/project.py b/pyfpga/project.py
index d700e8df..26f5a7d9 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -121,7 +121,7 @@ def add_hook(self, stage, hook):
 
     def make(self, end='bit', start='prj'):
         """Temp placeholder"""
-        steps = ['prj', 'syn', 'par', 'bit']
+        steps = ['cfg', 'syn', 'par', 'bit']
         if end not in steps or start not in steps:
             raise ValueError('Invalid steps.')
         _ = self
diff --git a/pyfpga/templates/ise.jinja b/pyfpga/templates/ise.jinja
index a5f31223..02adbc57 100644
--- a/pyfpga/templates/ise.jinja
+++ b/pyfpga/templates/ise.jinja
@@ -52,9 +52,9 @@ proc fpga_params {} {
     project set "Generics, Parameters" "[join $assigns]" -process "Synthesize - XST"
 }
 
-#------------------------------------------------------------------------------
+#--[ Project configuration ]---------------------------------------------------
 
-{% if PRJ %}
+{% if CFG %}
 if { [ file exists $PROJECT.xise ] } { file delete $PROJECT.xise }
 project new $PROJECT.xise
 
@@ -76,6 +76,8 @@ fpga_params
 project close
 {% endif %}
 
+#--[ Design flow ]-------------------------------------------------------------
+
 {% if SYN or PAR or BIT %}
 project open $PROJECT.xise
 
diff --git a/pyfpga/templates/libero.jinja b/pyfpga/templates/libero.jinja
index 8e703ed3..ac335d55 100644
--- a/pyfpga/templates/libero.jinja
+++ b/pyfpga/templates/libero.jinja
@@ -58,9 +58,9 @@ proc fpga_params {} {
     # They must be specified after set_root (see fpga_top)
 }
 
-#------------------------------------------------------------------------------
+#--[ Project configuration ]---------------------------------------------------
 
-{% if PRJ %}
+{% if CFG %}
 if { [ file exists $PROJECT ] } { file delete -force -- $PROJECT }
 new_project -name $PROJECT -location $PROJECT -hdl {VHDL} -family {SmartFusion2}
 
@@ -116,6 +116,8 @@ fpga_params
 close_project
 {% endif %}
 
+#--[ Design flow ]-------------------------------------------------------------
+
 {% if SYN or PAR or BIT %}
 open_project $PROJECT/$PROJECT.prjx
 
diff --git a/pyfpga/templates/quartus.jinja b/pyfpga/templates/quartus.jinja
index 966035ca..7c94c7cb 100644
--- a/pyfpga/templates/quartus.jinja
+++ b/pyfpga/templates/quartus.jinja
@@ -61,12 +61,11 @@ proc fpga_params {} {
     }
 }
 
-#------------------------------------------------------------------------------
+#--[ Project configuration ]---------------------------------------------------
 
-{% if PRJ %}
+{% if CFG %}
 package require ::quartus::project
 project_new $PROJECT -overwrite
-set_global_assignment -name NUM_PARALLEL_PROCESSORS ALL
 
 set_global_assignment -name DEVICE $PART
 
@@ -83,9 +82,12 @@ fpga_params
 project_close
 {% endif %}
 
+#--[ Design flow ]-------------------------------------------------------------
+
 {% if SYN or PAR or BIT %}
 package require ::quartus::flow
 project_open -force $PROJECT.qpf
+set_global_assignment -name NUM_PARALLEL_PROCESSORS ALL
 
 {% if SYN %}
 {{ PRESYN }}
diff --git a/pyfpga/templates/vivado.jinja b/pyfpga/templates/vivado.jinja
index 0cb772ea..2fc0b4bf 100644
--- a/pyfpga/templates/vivado.jinja
+++ b/pyfpga/templates/vivado.jinja
@@ -50,9 +50,9 @@ proc fpga_params {} {
     set_property "generic" "[join $assigns]" -objects $obj
 }
 
-#------------------------------------------------------------------------------
+#--[ Project configuration ]---------------------------------------------------
 
-{% if PRJ %}
+{% if CFG %}
 create_project -force $PROJECT
 
 set_property "part" $PART [current_project]
@@ -70,8 +70,11 @@ fpga_params
 close_project
 {% endif %}
 
+#--[ Design flow ]-------------------------------------------------------------
+
 {% if SYN or PAR or BIT %}
 open_project $PROJECT
+set_param general.maxThreads [expr {[exec nproc] < 32 ? [exec nproc] : 32}]
 
 {% if SYN %}
 {{ PRESYN }}
@@ -93,6 +96,7 @@ if { $PRESYNTH == "True" } {
 if {$PRESYNTH == "False"} {
     open_run synth_1
 }
+reset_run impl_1
 launch_runs impl_1
 wait_on_run impl_1
 
@@ -104,6 +108,7 @@ wait_on_run impl_1
 
 open_run impl_1
 write_bitstream -force $PROJECT
+write_debug_probes -force -quiet $PROJECT.ltx
 
 {{ POSTBIT }}
 {% endif %}

From d1eb4b1c54f7d65ec163831dfce3de86a4c5cb51 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Fri, 31 May 2024 23:41:42 -0300
Subject: [PATCH 050/248] Last iteration on templates before final
 customization

---
 pyfpga/templates/ise.jinja     | 21 ++++++---------
 pyfpga/templates/libero.jinja  |  5 ----
 pyfpga/templates/quartus.jinja |  5 ----
 pyfpga/templates/vivado.jinja  | 47 +++++++++++++++++++++-------------
 4 files changed, 37 insertions(+), 41 deletions(-)

diff --git a/pyfpga/templates/ise.jinja b/pyfpga/templates/ise.jinja
index 02adbc57..08678558 100644
--- a/pyfpga/templates/ise.jinja
+++ b/pyfpga/templates/ise.jinja
@@ -5,7 +5,6 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-set PRESYNTH {{ PRESYNTH }}
 set PROJECT  {{ PROJECT }}
 set PART     {{ PART }}
 set FAMILY   {{ FAMILY }}
@@ -16,10 +15,6 @@ set TOP      {{ TOP }}
 
 set PARAMS   [list {{ PARAMS }}]
 
-proc fpga_files {} {
-{{ FILES }}
-}
-
 proc fpga_file {FILE {LIBRARY "work"}} {
     set message "adding the file '$FILE'"
     if { $LIBRARY != "work" } { append message " (into the VHDL library '$LIBRARY')" }
@@ -65,7 +60,7 @@ project set speed   $SPEED
 
 {{ PRECFG }}
 
-fpga_files
+{{ FILES }}
 
 project set top $TOP
 
@@ -84,13 +79,13 @@ project open $PROJECT.xise
 {% if SYN %}
 {{ PRESYN }}
 
-if { $PRESYNTH == "True" } {
-    project set top_level_module_type "EDIF"
-} else {
-    project clean
-    process run "Synthesize"
-    if { [process get "Synthesize" status] == "errors" } { exit 2 }
-}
+{% if PRESYNTH %}
+project set top_level_module_type "EDIF"
+{% else %}
+project clean
+process run "Synthesize"
+if { [process get "Synthesize" status] == "errors" } { exit 2 }
+{% endif %}
 
 {{ POSTSYN }}
 {% endif %}
diff --git a/pyfpga/templates/libero.jinja b/pyfpga/templates/libero.jinja
index ac335d55..35ec3f52 100644
--- a/pyfpga/templates/libero.jinja
+++ b/pyfpga/templates/libero.jinja
@@ -5,7 +5,6 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-set PRESYNTH {{ PRESYNTH }}
 set PROJECT  {{ PROJECT }}
 set PART     {{ PART }}
 set FAMILY   {{ FAMILY }}
@@ -16,10 +15,6 @@ set TOP      {{ TOP }}
 
 set PARAMS   [list {{ PARAMS }}]
 
-proc fpga_files {} {
-{{ FILES }}
-}
-
 proc fpga_file {FILE {LIBRARY "work"}} {
     set message "adding the file '$FILE'"
     if { $LIBRARY != "work" } { append message " (into the VHDL library '$LIBRARY')" }
diff --git a/pyfpga/templates/quartus.jinja b/pyfpga/templates/quartus.jinja
index 7c94c7cb..76c29fc5 100644
--- a/pyfpga/templates/quartus.jinja
+++ b/pyfpga/templates/quartus.jinja
@@ -5,7 +5,6 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-set PRESYNTH {{ PRESYNTH }}
 set PROJECT  {{ PROJECT }}
 set PART     {{ PART }}
 set FAMILY   {{ FAMILY }}
@@ -16,10 +15,6 @@ set TOP      {{ TOP }}
 
 set PARAMS   [list {{ PARAMS }}]
 
-proc fpga_files {} {
-{{ FILES }}
-}
-
 proc fpga_file {FILE {LIBRARY "work"}} {
     set message "adding the file '$FILE'"
     if { $LIBRARY != "work" } { append message " (into the VHDL library '$LIBRARY')" }
diff --git a/pyfpga/templates/vivado.jinja b/pyfpga/templates/vivado.jinja
index 2fc0b4bf..c1805387 100644
--- a/pyfpga/templates/vivado.jinja
+++ b/pyfpga/templates/vivado.jinja
@@ -5,7 +5,6 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-set PRESYNTH {{ PRESYNTH }}
 set PROJECT  {{ PROJECT }}
 set PART     {{ PART }}
 set FAMILY   {{ FAMILY }}
@@ -16,10 +15,6 @@ set TOP      {{ TOP }}
 
 set PARAMS   [list {{ PARAMS }}]
 
-proc fpga_files {} {
-{{ FILES }}
-}
-
 proc fpga_file {FILE {LIBRARY "work"}} {
     set message "adding the file '$FILE'"
     if { $LIBRARY != "work" } { append message " (into the VHDL library '$LIBRARY')" }
@@ -54,16 +49,32 @@ proc fpga_params {} {
 
 {% if CFG %}
 create_project -force $PROJECT
+set_property source_mgmt_mode None [current_project]
+set_property STEPS.SYNTH_DESIGN.ARGS.ASSERT true [get_runs synth_1]
 
-set_property "part" $PART [current_project]
+set_property part $PART [current_project]
 
 {{ PRECFG }}
 
-fpga_files
+{{ FILES }}
 
 set_property top $TOP [current_fileset]
 
-fpga_params
+{% if DEFINES %}
+set_property verilog_define { {{ DEFINES}} } [current_fileset]
+{% endif %}
+
+{% if INCLUDES %}
+set_property include_dirs { {{ INCLUDES}} } [current_fileset]
+{% endif %}
+
+{% if PARAMS %}
+set_property generic { {{ PARAMS }} } -objects [get_filesets sources_1]
+{% endif %}
+
+{% if ARCH %}
+set_property top_arch {{ ARCH }} [current_fileset]
+{% endif %}
 
 {{ POSTCFG }}
 
@@ -79,13 +90,13 @@ set_param general.maxThreads [expr {[exec nproc] < 32 ? [exec nproc] : 32}]
 {% if SYN %}
 {{ PRESYN }}
 
-if { $PRESYNTH == "True" } {
-    set_property design_mode GateLvl [current_fileset]
-} else {
-    reset_run synth_1
-    launch_runs synth_1
-    wait_on_run synth_1
-}
+{% if PRESYNTH %}
+set_property design_mode GateLvl [current_fileset]
+{% else %}
+reset_run synth_1
+launch_runs synth_1
+wait_on_run synth_1
+{% endif %}
 
 {{ POSTSYN }}
 {% endif %}
@@ -93,9 +104,9 @@ if { $PRESYNTH == "True" } {
 {% if PAR %}
 {{ PREPAR }}
 
-if {$PRESYNTH == "False"} {
-    open_run synth_1
-}
+{% if not PRESYNTH %}
+open_run synth_1
+{% endif %}
 reset_run impl_1
 launch_runs impl_1
 wait_on_run impl_1

From 504b1fcbf5b87281f51af17745b77f1286bdf05b Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 1 Jun 2024 00:04:19 -0300
Subject: [PATCH 051/248] docs: re-added previously removed sections, with a
 WIP notice

---
 docs/{wip => }/advanced.rst       |  18 ++---
 docs/{wip => }/basic.rst          |  27 +++++--
 docs/index.rst                    |   5 +-
 docs/{wip/intro.rst => tools.rst} |  48 +++++++----
 docs/wip/conf.py                  | 129 ------------------------------
 docs/wip/dev.rst                  |  75 -----------------
 docs/wip/tools.rst                |  34 --------
 7 files changed, 64 insertions(+), 272 deletions(-)
 rename docs/{wip => }/advanced.rst (97%)
 rename docs/{wip => }/basic.rst (89%)
 rename docs/{wip/intro.rst => tools.rst} (71%)
 delete mode 100644 docs/wip/conf.py
 delete mode 100644 docs/wip/dev.rst
 delete mode 100644 docs/wip/tools.rst

diff --git a/docs/wip/advanced.rst b/docs/advanced.rst
similarity index 97%
rename from docs/wip/advanced.rst
rename to docs/advanced.rst
index 3ee54d32..245f4c08 100644
--- a/docs/wip/advanced.rst
+++ b/docs/advanced.rst
@@ -1,12 +1,12 @@
-.. program:: pyfpga
+Advanced usage
+==============
 
-.. _advanced:
+.. ATTENTION::
 
-Advanced usage
-##############
+  (2024-05-31) To be updated.
 
 Multi project managment
-=======================
+-----------------------
 
 .. code-block:: python
 
@@ -54,7 +54,7 @@ Multi project managment
 .. _hooks:
 
 Hooks
-=====
+-----
 
 The following table depicts the parts of the *Project Creation* and the
 *Design Flow* internally performed by PyFPGA.
@@ -93,7 +93,7 @@ specify additional *hooks* in different parts of the flow, using:
     method several times (the commands will be executed in order).
 
 Parameters
-==========
+----------
 
 The generics/parameters of the project can be optionally changed with:
 
@@ -104,7 +104,7 @@ The generics/parameters of the project can be optionally changed with:
    prj.add_param('paramN', valueN)
 
 Generate options
-================
+----------------
 
 The method ``generate`` (previously seen at the end of
 [Basic usage](#basic-usage) section) has optional parameters:
@@ -143,7 +143,7 @@ In case of *capture*, it is useful to catch execution messages to be
 post-processed or saved to a file.
 
 Exceptions
-==========
+----------
 
 Finally, you must run the bitstream generation or its transfer. Both of them
 are time-consuming tasks, performed by a backend tool, which could fail.
diff --git a/docs/wip/basic.rst b/docs/basic.rst
similarity index 89%
rename from docs/wip/basic.rst
rename to docs/basic.rst
index 7a5456c8..824aea8d 100644
--- a/docs/wip/basic.rst
+++ b/docs/basic.rst
@@ -1,12 +1,12 @@
-.. program:: pyfpga
+Basic usage
+===========
 
-.. _basic:
+.. ATTENTION::
 
-Basic usage
-###########
+  (2024-05-31) To be updated.
 
 Project Creation
-================
+----------------
 
 The first steps are import the module and instantiate the ``Project`` *class*,
 specifying the *TOOL* to use and, optionally, a *PROJECT NAME* (the *tool*
@@ -23,6 +23,17 @@ name is used when *no name* is provided).
   The supported tool are: ``ghdl``, ``ise``, ``libero``, ``openflow``,
   ``quartus``, ``vivado``, ``yosys``, ``yosys-ise`` and ``yosys-vivado``.
 
+.. ATTENTION::
+
+  PyFPGA assumes that the backend Tool is ready to run.
+  This implies, depending on the operating system, things such as:
+
+  * Tool installed.
+  * A valid License configured.
+  * Tool available in the system PATH.
+  * GNU/Linux: extra packages installed, environment variables assigned
+    and permissions granted on devices (to transfer the bitstream).
+
 By default, the directory where the project is generated is called ``build``
 and is located in the same place that the script, but another name and location
 can be specified.
@@ -85,7 +96,7 @@ Finally, the top-level must be specified:
   to automatically extract the top-level name.
 
 Project generation
-==================
+------------------
 
 Next step if to generate the project. In the most basic form, you can run the
 following to get a bitstream:
@@ -111,7 +122,7 @@ Additionally, you can specify which task to perform:
   * ``bit``: (default) to perform synthesis, implementation and bitstream generation.
 
 Bitstream transfer
-==================
+------------------
 
 This method is in charge of run the needed tool to transfer a bitstream to a
 device (commonly an FPGA, but memories are also supported in some cases).
@@ -134,7 +145,7 @@ Jtag chain. When a memory is used as *devtype*, the *part* name and the
     (udev rule, be a part of a group, etc).
 
 Logging capabilities
-====================
+--------------------
 
 PyFPGA uses the `logging <https://docs.python.org/3/library/logging.html>`_
 module, with a *NULL* handler and the *INFO* level by default.
diff --git a/docs/index.rst b/docs/index.rst
index 96f4b3d9..4984a41d 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -8,11 +8,14 @@ PyFPGA's documentation
 
 .. ATTENTION::
 
-  (2024-05-20) PyFPGA is in the process of being strongly rewritten/simplified.
+  (2024-05-31) PyFPGA is in the process of being strongly rewritten/simplified.
   Most changes are internal, but the API will also change.
 
 .. toctree::
 
    intro
+   basic
+   advanced
    hooks
+   tools
    api
diff --git a/docs/wip/intro.rst b/docs/tools.rst
similarity index 71%
rename from docs/wip/intro.rst
rename to docs/tools.rst
index b10d326a..0bbbcc5a 100644
--- a/docs/wip/intro.rst
+++ b/docs/tools.rst
@@ -1,18 +1,39 @@
-.. program:: pyfpga
-
-Introduction
-############
+Tools support
+=============
 
 .. ATTENTION::
 
-  PyFPGA assumes that the backend Tool is ready to run.
-  This implies, depending on the operating system, things such as:
+  (2024-05-31) To be updated.
+
++---------------+-----------+---------+-----+-----------------------------------------------+
+| Tools         | Vendor    | Version | Tcl | Comment                                       |
++===============+===========+=========+=====+===============================================+
+| ISE           | Xilinx    | 14.7    | 8.4 | Discontinued in 2013                          |
++---------------+-----------+---------+-----+-----------------------------------------------+
+| Libero-SoC    | Microsemi | 12.2    | 8.5 | Important changes in version 12.0 (2019)      |
++---------------+-----------+---------+-----+-----------------------------------------------+
+| Quartus Prime | Intel     | 19.1    | 8.6 | Known as Quartus II until version 15.0 (2015) |
++---------------+-----------+---------+-----+-----------------------------------------------+
+| Vivado        | Xilinx    | 2019.1  | 8.5 | Introduced in 2012, it superseded ISE         |
++---------------+-----------+---------+-----+-----------------------------------------------+
+| Yosys         |           | 0.9-dev | 8.6 | The open-source synthesizer                   |
++---------------+-----------+---------+-----+-----------------------------------------------+
+
+
+* ISE supports devices starting from Spartan 3/Virtex 4 until some first members of the 7 series.
+  Previous Spartan/Virtex devices were supported until version 10. Vivado supports devices starting
+  from the 7 series.
 
-  * Tool installed.
-  * A valid License configured.
-  * Tool available in the system PATH.
-  * GNU/Linux: extra packages installed, environment variables assigned
-    and permissions granted on devices (to transfer the bitstream).
+* Libero-SoC had a fork for PolarFire devices which was merged in version 12.0 (2019).
+  Libero SoC v12.0 and later supports PolarFire, RTG4, SmartFusion2 and IGLOO2 FPGA families.
+  Libero SoC v11.9 and earlier are the alternative to work with SmartFusion, IGLOO, ProASIC3 and
+  Fusion families.
+  Libero IDE v9.2 (2016) was the last version of the previous tool to work with antifuse and older
+  flash devices.
+
+* Since the change from Quartus II to Prime, three editions are available: Pro (for Agilex,
+  Stratix 10, Arria 10 and Cyclone GX devices), Standard (for Cyclone 10 LP and earlier devices)
+  and Lite (a high-volume low-end subset of the Standard edition).
 
 Detailed support
 ----------------
@@ -80,8 +101,3 @@ Detailed support
 * ``NY``: Not yet, but maybe someday
 * ``TBD``: To Be Defined
 * ``TBI``: To Be Implemented
-
-Next Steps
-----------
-
-You can read the :ref:`basic` and :ref:`advanced` sections, check the detailed :ref:`api` or start with the available :repositoy:`Examples <examples>`.
diff --git a/docs/wip/conf.py b/docs/wip/conf.py
deleted file mode 100644
index ffead9cc..00000000
--- a/docs/wip/conf.py
+++ /dev/null
@@ -1,129 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import sys, re
-from pathlib import Path
-#from json import dump, loads
-
-sys.path.insert(0, str(Path('.').resolve()))
-
-# -- General configuration ------------------------------------------------
-
-needs_sphinx = '3.0'
-
-extensions = [
-    #'recommonmark',
-    'sphinx.ext.autodoc',
-    'sphinx.ext.extlinks',
-    'sphinx.ext.intersphinx',
-    'sphinx.ext.todo',
-    'sphinx.ext.graphviz',
-    'sphinx.ext.mathjax',
-    'sphinx.ext.ifconfig',
-    'sphinx.ext.viewcode',
-]
-
-autodoc_default_options = {
-    "members": True,
-    'undoc-members': True,
-    #'private-members': True,
-    'inherited-members': True,
-}
-
-templates_path = ['_templates']
-
-source_suffix = {
-    '.rst': 'restructuredtext',
-    # '.txt': 'markdown',
-    #'.md': 'markdown',
-}
-
-master_doc = 'index'
-
-roject = u'PyFPGA'
-copyright = u'2019-2021, Rodrigo Alejandro Melo and contributors'
-author = u'Rodrigo Alejandro Melo and contributors'
-
-version = "latest"
-release = version  # The full version, including alpha/beta/rc tags.
-
-language = None
-
-exclude_patterns = []
-
-todo_include_todos = True
-todo_link_only = True
-
-# -- Options for HTML output ----------------------------------------------
-
-html_logo = "images/logo.png"
-
-html_theme_options = {
-    'logo_only': True,
-    'home_breadcrumbs': False,
-    'vcs_pageview_mode': 'blob',
-}
-
-html_context = {
-    'gitlab_user': 'rodrigomelo9',
-    'gitlab_repo': 'pyfpga',
-    'gitlab_version': 'master',
-    'conf_py_path': '/doc/',
-    'display_gitlab': True
-}
-#ctx = Path(__file__).resolve().parent / 'context.json'
-#if ctx.is_file():
-#    html_context.update(loads(ctx.open('r').read()))
-
-html_theme_path = ["."]
-html_theme = "_theme"
-
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
-#html_static_path = ['_static']
-
-# Output file base name for HTML help builder.
-htmlhelp_basename = 'PyFPGAdoc'
-
-# -- Options for LaTeX output ---------------------------------------------
-
-latex_elements = {
-    'papersize': 'a4paper',
-}
-
-# Grouping the document tree into LaTeX files. List of tuples
-# (source start file, target name, title, author, documentclass [howto, manual, or own class]).
-latex_documents = [
-    (master_doc, 'PyFPGA.tex', u'PyFPGA Documentation', author, 'manual'),
-]
-
-# -- Options for manual page output ---------------------------------------
-
-# One entry per manual page. List of tuples
-# (source start file, name, description, authors, manual section).
-man_pages = [
-    (master_doc, 'PyFPGA', u'PyFPGA Documentation', [author], 1)
-]
-
-# -- Options for Texinfo output -------------------------------------------
-
-# Grouping the document tree into Texinfo files. List of tuples
-# (source start file, target name, title, author, dir menu entry, description, category)
-texinfo_documents = [
-  (master_doc, 'PyFPGA', u'PyFPGA Documentation', author, 'PyFPGA', 'Python Class for vendor-independent FPGA development', 'Miscellaneous'),
-]
-
-# -- Sphinx.Ext.InterSphinx -----------------------------------------------
-
-#intersphinx_mapping = {
-#   'python': ('https://docs.python.org/3.8/', None),
-#   'ghdl': ('https://ghdl.github.io/ghdl', None),
-#   'vunit': ('https://vunit.github.io', None),
-#   'matplotlib': ('https://matplotlib.org/', None)
-#}
-
-# -- Sphinx.Ext.ExtLinks --------------------------------------------------
-extlinks = {
-   'wikipedia': ('https://en.wikipedia.org/wiki/%s', None),
-   'repo': ('https://github.com/PyFPGA/pyfpga/blob/main/%s', None)
-}
diff --git a/docs/wip/dev.rst b/docs/wip/dev.rst
deleted file mode 100644
index 39486ea3..00000000
--- a/docs/wip/dev.rst
+++ /dev/null
@@ -1,75 +0,0 @@
-.. program:: pyfpga
-
-Development Notes
-#################
-
-To install a local clone of the repository (for development):
-
-.. code-block:: shell
-
-   git clone https://gitlab.com/rodrigomelo9/pyfpga.git
-   cd pyfpga
-   sudo pip install -e .
-
-.. NOTE::
-  With `-e` (`--editable`) your application is installed into site-packages
-  via a kind of symlink, so you do not need to reinstall it after changes.
-
-PyFPGA uses PEP8 guidelines.
-
-The following is an overview of the main PyFPGA components and its
-relationship, which is explained in the sub-sections of this document.
-
-.. figure:: images/schema.png
-   :align: center
-   :alt: PyFPGA components
-
-   PyFPGA components
-
-fpga/tool/template.tcl
-======================
-
-Many (all?) FPGA development Tools provides a Tcl (Tool Command Language)
-interface for the Bitstream generation.
-This multi-vendor master Tcl was developed, where the different commands to
-solve the complete workflow were encapsulated into procedures
-(using the ``fpga_*`` prefix to avoid namespace conflicts).
-
-.. NOTE::
-  To add a new Tool, a *case* in the *switch* of each ``fpga_*`` must be
-  provided.
-
-.. NOTE::
-  This file is compliant with Tcl 8.4 because is the oldest used by a
-  supported FPGA Tool (Xilinx ISE).
-
-fpga/tool/<TOOL>.py
-===================
-
-A base class (``__init__.py``) was developed to provides a uniform API to be
-implemented for each supported Tool.
-Also, validation of values is performed here.
-
-Classes to supports each Tool (``<TOOL>.py``) implements the base class, ideally
-setting a few variables.
-
-.. NOTE::
-  Transfer of the bitstream to a device is not always performed by a Tcl
-  script, so special methods must be developed, following the proposed API.
-
-fpga/project.py
-===============
-
-This class implements the Application Programming Interface (API) which is
-employed to manage an FPGA project. It solves high-level things such as
-collect several files using glob, setting and use of a working/output
-directory and time measurement.
-
-FAQ
-====
-
-How to deal with deprecated Tcl commands?
------------------------------------------
-
-From Vivado 2019.1 to 2019.2, ``open_hw`` changed to ``open_hw_manager``:
-``if { [ catch { open_hw_manager } ] } { open_hw }``
diff --git a/docs/wip/tools.rst b/docs/wip/tools.rst
deleted file mode 100644
index 365a4844..00000000
--- a/docs/wip/tools.rst
+++ /dev/null
@@ -1,34 +0,0 @@
-.. program:: pyfpga
-
-Per tool usage
-##############
-
-+---------------+-----------+---------+-----+-----------------------------------------------+
-| Tools         | Vendor    | Version | Tcl | Comment                                       |
-+===============+===========+=========+=====+===============================================+
-| ISE           | Xilinx    | 14.7    | 8.4 | Discontinued in 2013                          |
-+---------------+-----------+---------+-----+-----------------------------------------------+
-| Libero-SoC    | Microsemi | 12.2    | 8.5 | Important changes in version 12.0 (2019)      |
-+---------------+-----------+---------+-----+-----------------------------------------------+
-| Quartus Prime | Intel     | 19.1    | 8.6 | Known as Quartus II until version 15.0 (2015) |
-+---------------+-----------+---------+-----+-----------------------------------------------+
-| Vivado        | Xilinx    | 2019.1  | 8.5 | Introduced in 2012, it superseded ISE         |
-+---------------+-----------+---------+-----+-----------------------------------------------+
-| Yosys         |           | 0.9-dev | 8.6 | The open-source synthesizer                   |
-+---------------+-----------+---------+-----+-----------------------------------------------+
-
-
-* ISE supports devices starting from Spartan 3/Virtex 4 until some first members of the 7 series.
-  Previous Spartan/Virtex devices were supported until version 10. Vivado supports devices starting
-  from the 7 series.
-
-* Libero-SoC had a fork for PolarFire devices which was merged in version 12.0 (2019).
-  Libero SoC v12.0 and later supports PolarFire, RTG4, SmartFusion2 and IGLOO2 FPGA families.
-  Libero SoC v11.9 and earlier are the alternative to work with SmartFusion, IGLOO, ProASIC3 and
-  Fusion families.
-  Libero IDE v9.2 (2016) was the last version of the previous tool to work with antifuse and older
-  flash devices.
-
-* Since the change from Quartus II to Prime, three editions are available: Pro (for Agilex,
-  Stratix 10, Arria 10 and Cyclone GX devices), Standard (for Cyclone 10 LP and earlier devices)
-  and Lite (a high-volume low-end subset of the Standard edition).

From a01bcd7cc20fbc55eaf9306585e8a7d938934d8c Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 1 Jun 2024 01:09:36 -0300
Subject: [PATCH 052/248] README updated/simplified

---
 README.md | 97 ++++++++++++++-----------------------------------------
 1 file changed, 24 insertions(+), 73 deletions(-)

diff --git a/README.md b/README.md
index 671fa6a1..3a60df40 100644
--- a/README.md
+++ b/README.md
@@ -6,24 +6,19 @@
 ![ISE](https://img.shields.io/badge/ISE-14.7-blue.svg?style=flat-square)
 ![Openflow](https://img.shields.io/badge/Openflow-GHDL%20%7C%20Yosys%20%7C%20nextpnr%20%7C%20icestorm%20%7C%20prjtrellis-darkgreen.svg?style=flat-square)
 
-> **WARNING:** (2024-05-20) PyFPGA is in the process of being strongly rewritten/simplified.
-> Most changes are internal, but the API will also change.
+PyFPGA is an abstraction layer for working with FPGA development tools in a vendor-agnostic, programmatic way. It is a Python package that provides:
+* One **class** per supported tool for **project creation**, **synthesis**, **place and route**, **bitstream generation**, and **programming**.
+* A set of **command-line helpers** for simple projects or quick evaluations.
 
-PyFPGA is a **Python Package** for **vendor-agnostic** FPGA development.
-It provides a **Class** which allows the programmatically execution of **synthesis**,
-**place and route**, **bitstream generation** and/or **programming** of FPGA devices.
-Additionally, a set of **command-line helpers** are provided for quick and simple runs.
+With PyFPGA, you can create your own FPGA development workflow tailored to your needs!
 
-Features:
-* It's *Version Control Systems* and *Continuous Integration* friendly.
-* Allows reproducibility and repeatability.
-* Consumes fewer system resources than GUI based workflows.
+Some of its benefits are:
+* It provides a unified API between tools/devices.
+* It's **Version Control Systems** and **Continuous Integration friendly**.
+* It ensures reproducibility and repeatability.
+* It consumes fewer system resources than GUI-based workflows.
 
-With PyFPGA you can create your custom FPGA tool using a workflow tailored to your needs!
-
-## Usage
-
-A minimal example of how to use PyFPGA:
+## Basic example
 
 ```py
 from fpga import Project
@@ -48,80 +43,36 @@ prj.set_top('Top')
 prj.generate()
 ```
 
-Now, you can read the [docs](https://pyfpga.github.io/pyfpga/) or find
-more examples in subdir [examples](examples).
+The next steps are to read the [docs](https://pyfpga.github.io/pyfpga) or take a look at [examples](examples).
 
-The API implemented by the `Project class` provides:
+## Support
 
-- A constructor where the TOOL must be specified and an optional PROJECT NAME can be indicated
-- Methods to set the target device PART, to add multiple HDL, Constraint and Tcl files to the
- project (in case of VHDL an optional PACKAGE NAME can be specified) and to specify the TOP-LEVEL
-- Methods to specify a different OUTPUT directory or get some project configurations
-- Methods to generate a bitstream and transfer it to a device (running the selected EDA Tool)
-- The capability of specifying an optimization strategy (area, power or speed) when the bitstream
- is generated
-- A method to add Verilog Included File directories
-- A method to specify generics/parameters values
-- Methods to add Tcl commands in up to six different parts of the Flow (workaround for not yet
- implemented features)
-- Optional logging capabilities which include the display of the Tool Execution Time
+PyFPGA is a Python package developed having GNU/Linux platform on mind, but it should run well on any POSIX-compatible OS, and probably others!
+If you encounter compatibility issues, please inform us via the [issues](https://github.com/PyFPGA/pyfpga/issues) tracker.
 
-## Support
+For a comprehensive list of supported tools, features and limitations, please refer to the [tools support](https://pyfpga.github.io/pyfpga/tools.html) page.
 
-PyFPGA is a Python 3 package, which is developed on Debian GNU/Linux.
-It should run on any other POSIX compatible OS and probably also on different OS.
-Should you achieve either success of failure on non-POSIX systems, please let us know through the
-[issue](https://github.com/PyFPGA/pyfpga/issues) tracker.
-
-- The whole development flow (from reading HDL and constraint sources to producing a bitstream)
- can be performed with ISE (Xilinx), Vivado (Xilinx), Quarts Prime (Intel/Altera), Libero-SoC
- (Microsemi) and/or with open-source tools.
-- GDHL (`--synth`) allows converting VHDL sources into a VHDL 1993 netlist.
-- Yosys allows synthesising Verilog and VHDL (using `ghdl-yosys-plugin`) and supports multiple
- output formats: JSON, Verilog, EDIF, etc.
-  - nextpnr can be used for implementation of JSON netlists.
-  - Also, ISE and Vivado are supported for implementation of Verilog netlists.
-- Transferring bitstreams and programming devices:
-  - ISE (Impact) can be used for programming FPGAs and/or memories (BPI and SPI) through JTAG.
-  - Vivado, Quartus and iceprog (IceStorm, for ice40 devices) can be used to programming FPGAs.
-  - Programming with Libero-SoC and programming ECP5 devices (prjtrellis, openocd) is not yet
-   supported.
-
-**Notes:**
-
-- The open-source tools are supported trough container images from the
-[HDL containers](https://hdl.github.io/containers) project, so
-[Docker](https://www.docker.com/) ~~or [Podman](https://podman.io/)~~ must be
-installed. The same workflow can be used in CI services.
-- ISE, Libero-Soc, Quartus Prime and Vivado, must be ready to be executed from
-the terminal (installed and well configured).
+> **NOTE:**
+> PyFPGA assumes that the underlying tools required for operation are ready to be executed from the running terminal.
+> This includes having the tools installed, properly configured, and licensed (when needed).
 
 ## Installation
 
-PyFPGA requires Python `>=3.6`. For now, it's only available as a git repository
-hosted on GitHub. It can be installed with pip:
+PyFPGA requires Python>=3.7.
+
+At the moment, it's only available as a git repository hosted on GitHub. It can be installed with pip:
 
 ```
 pip install 'git+https://github.com/PyFPGA/pyfpga#egg=pyfpga'
 ```
 
-> On GNU/Linux, installing pip packages on the system requires `sudo`.
-> Alternatively, use `--local` for installing PyFPGA in your HOME.
-
-You can get a copy of the repository either through git clone or downloading a
-tarball/zipfile:
+Alternatively, you can get a copy of the repository either through git clone or downloading a tarball/zipfile, and then:
 
 ```
 git clone https://github.com/PyFPGA/pyfpga.git
 cd pyfpga
-```
-
-Then, use pip from the root of the repo:
-
-```
 pip install -e .
 ```
 
-> With `-e` (`--editable`) your application is installed into site-packages via
-> a kind of symlink. That allows pulling changes through git or changing the
-> branch, without the need to reinstall the package.
+> With `-e` (`--editable`) your application is installed into site-packages via a kind of symlink.
+> That allows pulling changes through git or changing the branch, avoiding the need to reinstall the package.

From 087e3a6d79829b8a91308ab20b0758ffe01ce098 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 1 Jun 2024 18:56:30 -0300
Subject: [PATCH 053/248] Moved helpers from fpga to pyfpga

---
 {fpga => pyfpga}/helpers/bitprog.py | 0
 {fpga => pyfpga}/helpers/hdl2bit.py | 0
 {fpga => pyfpga}/helpers/prj2bit.py | 0
 3 files changed, 0 insertions(+), 0 deletions(-)
 rename {fpga => pyfpga}/helpers/bitprog.py (100%)
 rename {fpga => pyfpga}/helpers/hdl2bit.py (100%)
 rename {fpga => pyfpga}/helpers/prj2bit.py (100%)

diff --git a/fpga/helpers/bitprog.py b/pyfpga/helpers/bitprog.py
similarity index 100%
rename from fpga/helpers/bitprog.py
rename to pyfpga/helpers/bitprog.py
diff --git a/fpga/helpers/hdl2bit.py b/pyfpga/helpers/hdl2bit.py
similarity index 100%
rename from fpga/helpers/hdl2bit.py
rename to pyfpga/helpers/hdl2bit.py
diff --git a/fpga/helpers/prj2bit.py b/pyfpga/helpers/prj2bit.py
similarity index 100%
rename from fpga/helpers/prj2bit.py
rename to pyfpga/helpers/prj2bit.py

From e9f2dca70c65bfaa177b5989a4b491af5a88c211 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 1 Jun 2024 18:57:38 -0300
Subject: [PATCH 054/248] Renamed fpga/project.py as pyfpga/factory.py

---
 fpga/project.py => pyfpga/factory.py | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename fpga/project.py => pyfpga/factory.py (100%)

diff --git a/fpga/project.py b/pyfpga/factory.py
similarity index 100%
rename from fpga/project.py
rename to pyfpga/factory.py

From b6a0356bb364e7113463687be89bbe803a468ba5 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 1 Jun 2024 19:02:34 -0300
Subject: [PATCH 055/248] Simplified some methods at project, defined internal
 data structure, updated setup.py

---
 pyfpga/project.py  | 12 +++---------
 setup.py           | 16 ++++++++--------
 tests/test_data.py | 19 +++++++++++++++++--
 3 files changed, 28 insertions(+), 19 deletions(-)

diff --git a/pyfpga/project.py b/pyfpga/project.py
index 26f5a7d9..5ac00cd4 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -79,23 +79,17 @@ def add_vlog(self, pathname, options=None):
     def add_include(self, path):
         """Temp placeholder"""
         self.logger.debug('Executing add_include')
-        if 'includes' not in self.data:
-            self.data['includes'] = []
-        self.data['includes'].append(path)
+        self.data.setdefault('includes', []).append(path)
 
     def add_param(self, name, value):
         """Temp placeholder"""
         self.logger.debug('Executing add_param')
-        if 'params' not in self.data:
-            self.data['params'] = {}
-        self.data['params'][name] = value
+        self.data.setdefault('params', {})[name] = value
 
     def add_define(self, name, value):
         """Temp placeholder"""
         self.logger.debug('Executing add_define')
-        if 'defines' not in self.data:
-            self.data['defines'] = {}
-        self.data['defines'][name] = value
+        self.data.setdefault('defines', {})[name] = value
 
     def set_arch(self, name):
         """Temp placeholder"""
diff --git a/setup.py b/setup.py
index 05036c4a..e6b45d1b 100644
--- a/setup.py
+++ b/setup.py
@@ -7,7 +7,7 @@
 
 setup(
     name='pyfpga',
-    version=fpga.__version__,
+    version=pyfpga.__version__,
     description='A Python package to use FPGA development tools programmatically',
     long_description=long_description,
     long_description_content_type='text/markdown',
@@ -15,13 +15,13 @@
     author_email='rodrigomelo9@gmail.com',
     license='GPLv3',
     url='https://github.com/PyFPGA/pyfpga',
-    package_data={'': ['tool/*.sh', 'tool/*.tcl', 'helpers/*']},
+    package_data={'': ['templates/*.jinja', 'helpers/*']},
     packages=find_packages(),
     entry_points={
         'console_scripts': [
-            'fpga-hdl2bit = fpga.helpers.hdl2bit:main',
-            'fpga-prj2bit = fpga.helpers.prj2bit:main',
-            'fpga-bitprog = fpga.helpers.bitprog:main'
+            'fpga-hdl2bit = pyfpga.helpers.hdl2bit:main',
+            'fpga-prj2bit = pyfpga.helpers.prj2bit:main',
+            'fpga-bitprog = pyfpga.helpers.bitprog:main'
         ],
     },
     classifiers=[
@@ -30,14 +30,14 @@
         'Intended Audience :: Developers',
         'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
         'Operating System :: OS Independent',
-        'Programming Language :: Python :: 3.6',
         'Programming Language :: Python :: 3.7',
         'Programming Language :: Python :: 3.8',
         'Programming Language :: Python :: 3.9',
         'Programming Language :: Python :: 3.10',
+        'Programming Language :: Python :: 3.11',
+        'Programming Language :: Python :: 3.12',
         'Topic :: Utilities',
         'Topic :: Software Development :: Build Tools',
         "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)"
-    ],
-    install_requires=['pyyaml']
+    ]
 )
diff --git a/tests/test_data.py b/tests/test_data.py
index e603af21..3b7da4df 100644
--- a/tests/test_data.py
+++ b/tests/test_data.py
@@ -5,9 +5,13 @@
 
 pattern = {
     'part': 'PARTNAME',
-    'top': 'TOPNAME',
-    'arch': 'ARCHNAME',
     'includes': ['INC1', 'INC2', 'INC3'],
+    'files': {
+        'path1': {'type': 'TYPE1', 'options': 'OPTION1', 'library': 'LIBRARY1'},
+        'path2': {'type': 'TYPE2', 'options': 'OPTION2', 'library': 'LIBRARY2'},
+        'path3': {'type': 'TYPE3', 'options': 'OPTION3', 'library': 'LIBRARY3'}
+    },
+    'top': 'TOPNAME',
     'params': {
         'PARAM1': 'VALUE1',
         'PARAM2': 'VALUE2',
@@ -18,6 +22,17 @@
         'DEF2': 'VALUE2',
         'DEF3': 'VALUE3'
     },
+    'arch': 'ARCHNAME',
+    'hooks': {
+        'precfg': ['HOOK1', 'HOOK2', 'HOOKn'],
+        'postcfg': ['HOOK1', 'HOOK2', 'HOOKn'],
+        'presyn': ['HOOK1', 'HOOK2', 'HOOKn'],
+        'postsyn': ['HOOK1', 'HOOK2', 'HOOKn'],
+        'prepar': ['HOOK1', 'HOOK2', 'HOOKn'],
+        'postpar': ['HOOK1', 'HOOK2', 'HOOKn'],
+        'prebit': ['HOOK1', 'HOOK2', 'HOOKn'],
+        'postbit': ['HOOK1', 'HOOK2', 'HOOKn']
+    }
 }
 
 

From 16b3999a832341b3626e15ae0c6177f2f4284444 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 1 Jun 2024 19:31:11 -0300
Subject: [PATCH 056/248] Fixed pylint complaint

---
 tests/test_data.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/tests/test_data.py b/tests/test_data.py
index 3b7da4df..66652fd5 100644
--- a/tests/test_data.py
+++ b/tests/test_data.py
@@ -7,9 +7,9 @@
     'part': 'PARTNAME',
     'includes': ['INC1', 'INC2', 'INC3'],
     'files': {
-        'path1': {'type': 'TYPE1', 'options': 'OPTION1', 'library': 'LIBRARY1'},
-        'path2': {'type': 'TYPE2', 'options': 'OPTION2', 'library': 'LIBRARY2'},
-        'path3': {'type': 'TYPE3', 'options': 'OPTION3', 'library': 'LIBRARY3'}
+        'path1': {'type': 'TYPE1', 'options': 'OPT1', 'library': 'LIB1'},
+        'path2': {'type': 'TYPE2', 'options': 'OPT2', 'library': 'LIB2'},
+        'path3': {'type': 'TYPE3', 'options': 'OPT3', 'library': 'LIB3'}
     },
     'top': 'TOPNAME',
     'params': {

From 2bf79bc5f5e23b085089b783b39e74148f684243 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 1 Jun 2024 20:17:52 -0300
Subject: [PATCH 057/248] Fixed pylint complaints

---
 pyfpga/factory.py | 80 ++++++++---------------------------------------
 1 file changed, 13 insertions(+), 67 deletions(-)

diff --git a/pyfpga/factory.py b/pyfpga/factory.py
index 069d2be7..d05695d1 100644
--- a/pyfpga/factory.py
+++ b/pyfpga/factory.py
@@ -1,24 +1,11 @@
 #
-# Copyright (C) 2019-2022 Rodrigo A. Melo
-# Copyright (C) 2019-2020 INTI
+# Copyright (C) 2019-2024 Rodrigo A. Melo
 #
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+# SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-"""fpga.project
-This module implements the entry-point of PyFPGA, which provides
-functionalities to create a project, generate a bitstream and program a device.
+"""
+A factory class to create FPGA projects.
 """
 
 import contextlib
@@ -29,6 +16,12 @@
 import re
 import time
 
+from fpga.tool.ise import Ise
+from fpga.tool.libero import Libero
+from fpga.tool.openflow import Openflow
+from fpga.tool.quartus import Quartus
+from fpga.tool.vivado import Vivado
+
 
 TOOLS = [
     'ghdl', 'ise', 'libero', 'openflow', 'quartus', 'vivado', 'yosys',
@@ -57,29 +50,22 @@ class Project:
     """
 
     def __init__(
-            self, tool='vivado', project=None, meta=None,
+            self, tool='vivado', project=None,
             relative_to_script=True):
         """Class constructor."""
         if tool == 'ghdl':
-            from fpga.tool.openflow import Openflow
             self.tool = Openflow(project, frontend='ghdl', backend='vhdl')
         elif tool in ['ise', 'yosys-ise']:
-            from fpga.tool.ise import Ise
             self.tool = Ise(project, 'yosys' if 'yosys' in tool else '')
         elif tool == 'libero':
-            from fpga.tool.libero import Libero
             self.tool = Libero(project)
         elif tool == 'openflow':
-            from fpga.tool.openflow import Openflow
             self.tool = Openflow(project)
         elif tool == 'quartus':
-            from fpga.tool.quartus import Quartus
             self.tool = Quartus(project)
         elif tool in ['vivado', 'yosys-vivado']:
-            from fpga.tool.vivado import Vivado
             self.tool = Vivado(project, 'yosys' if 'yosys' in tool else '')
         elif tool == 'yosys':
-            from fpga.tool.openflow import Openflow
             self.tool = Openflow(project, frontend='yosys', backend='verilog')
         else:
             raise NotImplementedError(tool)
@@ -93,42 +79,6 @@ def __init__(
         self._absdir = os.path.join(self._rundir, self._reldir)
         _log.debug('ABSDIR = %s', self._absdir)
         self.set_outdir('build')
-        self._initialize(meta)
-
-    def _initialize(self, meta):
-        """Set some of the most used internal parameters."""
-        if meta is None:
-            return
-        if 'outdir' in meta:
-            _log.debug('OUTDIR = %s', meta['outdir'])
-            self.set_outdir(meta['outdir'])
-        if 'part' in meta:
-            _log.debug('PART = %s', meta['part'])
-            self.set_part(meta['part'])
-        if 'paths' in meta:
-            for path in meta['paths']:
-                _log.debug('PATH = %s', path)
-                self.add_vlog_include(path)
-        for filetype in ['vhdl', 'verilog', 'constraint']:
-            if filetype in meta:
-                for file in meta[filetype]:
-                    if isinstance(file, list):
-                        filename = file[0]
-                        library = file[1]
-                    else:
-                        filename = file
-                        library = None
-                    _log.debug(
-                        'FILE = %s %s %s', filename, filetype, library
-                    )
-                    self.add_files(filename, filetype, library)
-        if 'params' in meta:
-            for parname, parvalue in meta['params'].items():
-                _log.debug('PARAM = %s %s', parname, parvalue)
-                self.add_param(parname, parvalue)
-        if 'top' in meta:
-            _log.debug('TOP = %s', meta['top'])
-            self.set_top(meta['top'])
 
     def set_outdir(self, outdir):
         """Sets the OUTput DIRectory (where to put the resulting files).
@@ -324,8 +274,7 @@ def set_bitstream(self, path):
         self.tool.set_bitstream(path)
 
     def transfer(
-            self, devtype='fpga', position=1, part='', width=1,
-            capture=False):
+            self, devtype='fpga', position=1, part='', width=1):
         """Transfers the generated bitstream to a device.
 
         :param devtype: *fpga* or other valid option
@@ -333,7 +282,6 @@ def transfer(
         :param position: position of the device in the JTAG chain
         :param part: name of the memory (when device is not *fpga*)
         :param width: bits width of the memory (when device is not *fpga*)
-        :param capture: capture STDOUT and STDERR
         :returns: STDOUT and STDERR messages
         :raises FileNotFoundError: when the bitstream is not found
         :raises ValueError: when devtype, position or width are unsupported
@@ -344,9 +292,7 @@ def transfer(
             self.tool.project, self.tool.get_configs()['tool'], self.outdir
         )
         with self._run_in_dir():
-            if capture:
-                _log.info('the execution messages are being captured')
-            return self.tool.transfer(devtype, position, part, width, capture)
+            return self.tool.transfer(devtype, position, part, width, True)
 
     def clean(self):
         """Clean the generated project files."""

From c88eaa6caee14696a61130a983085a58c8bad0fd Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 1 Jun 2024 20:23:04 -0300
Subject: [PATCH 058/248] Renamed and implemented _add_file, implemented
 add_hook

---
 pyfpga/project.py  | 19 +++++++++----------
 tests/test_data.py | 43 ++++++++++++++++++++++++++++++++-----------
 2 files changed, 41 insertions(+), 21 deletions(-)

diff --git a/pyfpga/project.py b/pyfpga/project.py
index 5ac00cd4..bb922c9c 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -49,24 +49,25 @@ def set_part(self, name):
         self.logger.debug('Executing set_part')
         self.data['part'] = name
 
-    def add_file(self, pathname, filetype=None, library=None, options=None):
-        """Temp placeholder"""
-        raise NotImplementedError('Method is not implemented yet.')
+    def _add_file(self, pathname, filetype=None, library=None, options=None):
+        self.data.setdefault('files', {})[pathname] = {
+            'type': filetype, 'options': options, 'library': library
+        }
 
     def add_cons(self, pathname, options=None):
         """Temp placeholder"""
         self.logger.debug('Executing add_cons')
-        self.add_file(pathname, filetype='cons', options=options)
+        self._add_file(pathname, filetype='cons', options=options)
 
     def add_slog(self, pathname, options=None):
         """Temp placeholder"""
         self.logger.debug('Executing add_slog')
-        self.add_file(pathname, filetype='slog', options=options)
+        self._add_file(pathname, filetype='slog', options=options)
 
     def add_vhdl(self, pathname, library=None, options=None):
         """Temp placeholder"""
         self.logger.debug('Executing add_vhdl')
-        self.add_file(
+        self._add_file(
             pathname, filetype='vhdl',
             library=library, options=options
         )
@@ -74,7 +75,7 @@ def add_vhdl(self, pathname, library=None, options=None):
     def add_vlog(self, pathname, options=None):
         """Temp placeholder"""
         self.logger.debug('Executing add_vlog')
-        self.add_file(pathname, filetype='vlog', options=options)
+        self._add_file(pathname, filetype='vlog', options=options)
 
     def add_include(self, path):
         """Temp placeholder"""
@@ -109,9 +110,7 @@ def add_hook(self, stage, hook):
         ]
         if stage not in stages:
             raise ValueError('Invalid stage.')
-        _ = self
-        _ = hook
-        raise NotImplementedError('Method is not implemented yet.')
+        self.data.setdefault('hooks', {}).setdefault(stage, []).append(hook)
 
     def make(self, end='bit', start='prj'):
         """Temp placeholder"""
diff --git a/tests/test_data.py b/tests/test_data.py
index 66652fd5..b17b2dd4 100644
--- a/tests/test_data.py
+++ b/tests/test_data.py
@@ -7,9 +7,10 @@
     'part': 'PARTNAME',
     'includes': ['INC1', 'INC2', 'INC3'],
     'files': {
-        'path1': {'type': 'TYPE1', 'options': 'OPT1', 'library': 'LIB1'},
-        'path2': {'type': 'TYPE2', 'options': 'OPT2', 'library': 'LIB2'},
-        'path3': {'type': 'TYPE3', 'options': 'OPT3', 'library': 'LIB3'}
+        'path1': {'type': 'vhdl', 'options': 'OPT1', 'library': 'LIB1'},
+        'path2': {'type': 'vlog', 'options': 'OPT2', 'library': None},
+        'path3': {'type': 'slog', 'options': 'OPT3', 'library': None},
+        'path4': {'type': 'cons', 'options': 'OPT4', 'library': None}
     },
     'top': 'TOPNAME',
     'params': {
@@ -24,14 +25,14 @@
     },
     'arch': 'ARCHNAME',
     'hooks': {
-        'precfg': ['HOOK1', 'HOOK2', 'HOOKn'],
-        'postcfg': ['HOOK1', 'HOOK2', 'HOOKn'],
-        'presyn': ['HOOK1', 'HOOK2', 'HOOKn'],
-        'postsyn': ['HOOK1', 'HOOK2', 'HOOKn'],
-        'prepar': ['HOOK1', 'HOOK2', 'HOOKn'],
-        'postpar': ['HOOK1', 'HOOK2', 'HOOKn'],
-        'prebit': ['HOOK1', 'HOOK2', 'HOOKn'],
-        'postbit': ['HOOK1', 'HOOK2', 'HOOKn']
+        'precfg': ['HOOK1', 'HOOK2'],
+        'postcfg': ['HOOK1', 'HOOK2'],
+        'presyn': ['HOOK1', 'HOOK2'],
+        'postsyn': ['HOOK1', 'HOOK2'],
+        'prepar': ['HOOK1', 'HOOK2'],
+        'postpar': ['HOOK1', 'HOOK2'],
+        'prebit': ['HOOK1', 'HOOK2'],
+        'postbit': ['HOOK1', 'HOOK2']
     }
 }
 
@@ -50,4 +51,24 @@ def test_names():
     prj.add_define('DEF1', 'VALUE1')
     prj.add_define('DEF2', 'VALUE2')
     prj.add_define('DEF3', 'VALUE3')
+    prj.add_vhdl('path1', 'LIB1', 'OPT1')
+    prj.add_vlog('path2', 'OPT2')
+    prj.add_slog('path3', 'OPT3')
+    prj.add_cons('path4', 'OPT4')
+    prj.add_hook('precfg', 'HOOK1')
+    prj.add_hook('precfg', 'HOOK2')
+    prj.add_hook('postcfg', 'HOOK1')
+    prj.add_hook('postcfg', 'HOOK2')
+    prj.add_hook('presyn', 'HOOK1')
+    prj.add_hook('presyn', 'HOOK2')
+    prj.add_hook('postsyn', 'HOOK1')
+    prj.add_hook('postsyn', 'HOOK2')
+    prj.add_hook('prepar', 'HOOK1')
+    prj.add_hook('prepar', 'HOOK2')
+    prj.add_hook('postpar', 'HOOK1')
+    prj.add_hook('postpar', 'HOOK2')
+    prj.add_hook('prebit', 'HOOK1')
+    prj.add_hook('prebit', 'HOOK2')
+    prj.add_hook('postbit', 'HOOK1')
+    prj.add_hook('postbit', 'HOOK2')
     assert prj.data == pattern, 'ERROR: unexpected data'

From ecb3aa4c27777859d79902690bdd4b68ae57cc36 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 2 Jun 2024 09:28:00 -0300
Subject: [PATCH 059/248] Added some pending doc-strings

---
 pyfpga/project.py | 88 +++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 82 insertions(+), 6 deletions(-)

diff --git a/pyfpga/project.py b/pyfpga/project.py
index bb922c9c..0a5479c0 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -8,6 +8,7 @@
 Base class that implements agnostic methods to deal with FPGA projects.
 """
 
+# import glob
 import logging
 import os
 import subprocess
@@ -45,11 +46,52 @@ def __init__(self, name=None, odir='results'):
         self.logger.addHandler(handler)
 
     def set_part(self, name):
-        """Temp placeholder"""
+        """Set the FPGA part name.
+
+        :param name: FPGA part name
+        :type name: str
+        """
         self.logger.debug('Executing set_part')
         self.data['part'] = name
 
     def _add_file(self, pathname, filetype=None, library=None, options=None):
+        # """Adds files to the project.
+        #
+        # :param pathname: a relative path to a file, which can contain
+        #  shell-style wildcards (glob compliant)
+        # :param filetype: specifies the file type
+        # :param library: an optional VHDL library name
+        # :param options: to be provided to the underlying tool
+        # :raises FileNotFoundError: when a file specified as pathname is not
+        #  found
+        # :raises ValueError: when *filetype* is unsupported
+        #
+        # .. note:: Valid values for *filetype* are ``vhdl``, ``verilog``,
+        # ``system_verilog``, ``constraint`` (default) and ``block_design``
+        # (only **Vivado** is currently supported). If None provided, this
+        # value is automatically discovered based on the extension (
+        # ``.vhd`` or ``.vhdl``, ``.v`` and ``.sv``).
+        # """
+        # pathname = os.path.join(self._absdir, pathname)
+        # pathname = os.path.normpath(pathname)
+        # _log.debug('PATHNAME = %s', pathname)
+        # files = glob.glob(pathname)
+        # if len(files) == 0:
+        #     raise FileNotFoundError(pathname)
+        # for file in files:
+        #     if not os.path.exists(file):
+        #         raise FileNotFoundError(file)
+        #     if filetype is None:
+        #         ext = os.path.splitext(file)[1]
+        #         if ext in ['.vhd', '.vhdl']:
+        #             filetype = 'vhdl'
+        #         elif ext in ['.v', '.sv']:
+        #             filetype = 'verilog'
+        #         else:
+        #             filetype = 'constraint'
+        #         _log.debug('add_files: %s filetype detected', filetype)
+        #     file = os.path.relpath(file, self.outdir)
+        #     self.tool.add_file(file, filetype, library, options)
         self.data.setdefault('files', {})[pathname] = {
             'type': filetype, 'options': options, 'library': library
         }
@@ -78,27 +120,61 @@ def add_vlog(self, pathname, options=None):
         self._add_file(pathname, filetype='vlog', options=options)
 
     def add_include(self, path):
-        """Temp placeholder"""
+        """Add an Include path.
+
+        Specify where to search for Included Verilog Files, IP repos, etc.
+
+        :param path: path of a directory
+        :type name: str
+        :raises NotADirectoryError: if path is not a directory
+        """
         self.logger.debug('Executing add_include')
+        # path = os.path.join(self._absdir, path)
+        # path = os.path.normpath(path)
+        # if os.path.isdir(path):
+        #     path = os.path.relpath(path, self.outdir)
+        #     self.tool.add_vlog_include(path)
+        # else:
+        #     raise NotADirectoryError(path)
         self.data.setdefault('includes', []).append(path)
 
     def add_param(self, name, value):
-        """Temp placeholder"""
+        """Add a Parameter/Generic Value.
+
+        :param name: parameter/generic name
+        :type name: str
+        :param value: parameter/generic value
+        :type name: str
+        """
         self.logger.debug('Executing add_param')
         self.data.setdefault('params', {})[name] = value
 
     def add_define(self, name, value):
-        """Temp placeholder"""
+        """Add a Verilog Defile Value.
+
+        :param name: define name
+        :type name: str
+        :param value: define value
+        :type name: str
+        """
         self.logger.debug('Executing add_define')
         self.data.setdefault('defines', {})[name] = value
 
     def set_arch(self, name):
-        """Temp placeholder"""
+        """Set the VHDL architecture.
+
+        :param name: architecture name
+        :type name: str
+        """
         self.logger.debug('Executing set_arch')
         self.data['arch'] = name
 
     def set_top(self, name):
-        """Temp placeholder"""
+        """Set the name of the top level component.
+
+        :param name: top-level name
+        :type name: str
+        """
         self.logger.debug('Executing set_top')
         self.data['top'] = name
 

From 316dfdcb5693c11368d1b2989bd312d2b014d1f1 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 2 Jun 2024 09:28:52 -0300
Subject: [PATCH 060/248] Removed already processed things

---
 pyfpga/factory.py | 189 +++-------------------------------------------
 1 file changed, 12 insertions(+), 177 deletions(-)

diff --git a/pyfpga/factory.py b/pyfpga/factory.py
index d05695d1..55b92fb3 100644
--- a/pyfpga/factory.py
+++ b/pyfpga/factory.py
@@ -8,13 +8,9 @@
 A factory class to create FPGA projects.
 """
 
-import contextlib
-import glob
 import inspect
 import logging
 import os
-import re
-import time
 
 from fpga.tool.ise import Ise
 from fpga.tool.libero import Libero
@@ -78,142 +74,6 @@ def __init__(
         _log.debug('RELDIR = %s', self._reldir)
         self._absdir = os.path.join(self._rundir, self._reldir)
         _log.debug('ABSDIR = %s', self._absdir)
-        self.set_outdir('build')
-
-    def set_outdir(self, outdir):
-        """Sets the OUTput DIRectory (where to put the resulting files).
-
-        :param outdir: path to the output directory
-        """
-        self.outdir = os.path.normpath(os.path.join(self._absdir, outdir))
-        _log.debug('OUTDIR = %s', self.outdir)
-
-    def get_configs(self):
-        """Gets the Project Configurations.
-
-        :returns: a dict which includes ``tool`` and ``project`` names, the
-         ``extension`` of a project file (according to the selected tool) and
-         the ``part`` to be used
-        """
-        return self.tool.get_configs()
-
-    def set_part(self, part):
-        """Set the target FPGA part.
-
-        :param part: the FPGA part as specified by the tool
-        """
-        self.tool.set_part(part)
-
-    def add_param(self, name, value):
-        """Add a Generic/Parameter Value.
-
-        :param name: parameter/generic name
-        :param value: value to be assigned
-        """
-        self.tool.add_param(name, value)
-
-    def add_files(self, pathname, filetype=None, library=None, options=None):
-        """Adds files to the project.
-
-        :param pathname: a relative path to a file, which can contain
-         shell-style wildcards (glob compliant)
-        :param filetype: specifies the file type
-        :param library: an optional VHDL library name
-        :param options: to be provided to the underlying tool
-        :raises FileNotFoundError: when a file specified as pathname is not
-         found
-        :raises ValueError: when *filetype* is unsupported
-
-        .. note:: Valid values for *filetype* are ``vhdl``, ``verilog``,
-        ``system_verilog``, ``constraint`` (default) and ``block_design``
-        (only **Vivado** is currently supported). If None provided, this
-        value is automatically discovered based on the extension (
-        ``.vhd`` or ``.vhdl``, ``.v`` and ``.sv``).
-        """
-        pathname = os.path.join(self._absdir, pathname)
-        pathname = os.path.normpath(pathname)
-        _log.debug('PATHNAME = %s', pathname)
-        files = glob.glob(pathname)
-        if len(files) == 0:
-            raise FileNotFoundError(pathname)
-        for file in files:
-            if not os.path.exists(file):
-                raise FileNotFoundError(file)
-            if filetype is None:
-                ext = os.path.splitext(file)[1]
-                if ext in ['.vhd', '.vhdl']:
-                    filetype = 'vhdl'
-                elif ext in ['.v', '.sv']:
-                    filetype = 'verilog'
-                else:
-                    filetype = 'constraint'
-                _log.debug('add_files: %s filetype detected', filetype)
-            file = os.path.relpath(file, self.outdir)
-            self.tool.add_file(file, filetype, library, options)
-
-    def get_files(self):
-        """Get the files of the project.
-
-        :returns: a list with the files of the project
-        """
-        return self.tool.get_files()
-
-    def add_vlog_include(self, path):
-        """Add a Verilog include path.
-
-        Useful to specify where to search Verilog Included Files or IP
-        repositories.
-
-        :param path: a relative path to a directory
-        :raises NotADirectoryError: when path is not a directory
-        """
-        path = os.path.join(self._absdir, path)
-        path = os.path.normpath(path)
-        if os.path.isdir(path):
-            path = os.path.relpath(path, self.outdir)
-            self.tool.add_vlog_include(path)
-        else:
-            raise NotADirectoryError(path)
-
-    def add_vlog_define(self, name, value):
-        """Add a Verilog define."""
-        raise NotImplementedError()
-
-    def set_vhdl_arch(self, name):
-        """Set the VHDL architecture."""
-        raise NotImplementedError()
-
-    def set_top(self, toplevel):
-        """Set the top level of the project.
-
-        :param toplevel: name or file path of the top level entity/module
-        :raises FileNotFoundError: when toplevel is a not found file
-        """
-        if os.path.splitext(toplevel)[1]:
-            toplevel = os.path.join(self._absdir, toplevel)
-            toplevel = os.path.normpath(toplevel)
-            if os.path.exists(toplevel):
-                with open(toplevel, 'r', encoding='utf-8') as file:
-                    hdl = file.read()
-                # Removing comments, newlines and carriage-returns
-                hdl = re.sub(r'--.*[$\n]|\/\/.*[$\n]', '', hdl)
-                hdl = hdl.replace('\n', '').replace('\r', '')
-                hdl = re.sub(r'\/\*.*\*\/', '', hdl)
-                # Finding modules/entities
-                top = re.findall(r'module\s+(\w+)\s*[#(;]', hdl)
-                top.extend(re.findall(r'entity\s+(\w+)\s+is', hdl))
-                if len(top) > 0:
-                    self.tool.set_top(top[-1])
-                    if len(top) > 1:
-                        _log.warning(
-                            'set_top: more than one Top found (last selected)'
-                        )
-                else:
-                    self.tool.set_top('UNDEFINED')
-            else:
-                raise FileNotFoundError(toplevel)
-        else:
-            self.tool.set_top(toplevel)
 
     def add_hook(self, hook, phase='project'):
         """Adds a hook in the specified phase.
@@ -254,14 +114,13 @@ def generate(self, to_task='bit', from_task='prj', capture=False):
          ``imp`` (to runs implementation) and
          ``bit`` (to generates the bitstream)
         """
-        _log.info(
-            'generating "%s" project using "%s" tool into "%s" directory',
-            self.tool.project, self.tool.get_configs()['tool'], self.outdir
-        )
-        with self._run_in_dir():
-            if capture:
-                _log.info('the execution messages are being captured')
-            return self.tool.generate(to_task, from_task, capture)
+        # _log.info(
+        #     'generating "%s" project using "%s" tool into "%s" directory',
+        #     self.tool.project, self.tool.get_configs()['tool'], self.outdir
+        # )
+        if capture:
+            _log.info('the execution messages are being captured')
+        return self.tool.generate(to_task, from_task, capture)
 
     def set_bitstream(self, path):
         """Set the bitstream file to transfer.
@@ -287,32 +146,8 @@ def transfer(
         :raises ValueError: when devtype, position or width are unsupported
         :raises RuntimeError: when the tool to be used is not found
         """
-        _log.info(
-            'transfering "%s" project using "%s" tool from "%s" directory',
-            self.tool.project, self.tool.get_configs()['tool'], self.outdir
-        )
-        with self._run_in_dir():
-            return self.tool.transfer(devtype, position, part, width, True)
-
-    def clean(self):
-        """Clean the generated project files."""
-        _log.info(
-            'cleaning the generated project files into "%s"', self.outdir
-        )
-        with self._run_in_dir():
-            self.tool.clean()
-
-    @contextlib.contextmanager
-    def _run_in_dir(self):
-        """Run the tool in another directory."""
-        start = time.time()
-        try:
-            if not os.path.exists(self.outdir):
-                _log.debug('the output directory did not exist (created)')
-                os.makedirs(self.outdir)
-            os.chdir(self.outdir)
-            yield
-        finally:
-            end = time.time()
-            os.chdir(self._rundir)
-            _log.info('executed in %.3f seconds', end-start)
+        # _log.info(
+        #     'transfering "%s" project using "%s" tool from "%s" directory',
+        #     self.tool.project, self.tool.get_configs()['tool'], self.outdir
+        # )
+        return self.tool.transfer(devtype, position, part, width, True)

From 739b12f3967248ed90f665e73088b2aa87bb93aa Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 2 Jun 2024 09:32:05 -0300
Subject: [PATCH 061/248] Removed test_top.py (top autodiscovery was
 deprecated)

---
 Makefile          |  2 +-
 tests/test_top.py | 31 -------------------------------
 2 files changed, 1 insertion(+), 32 deletions(-)
 delete mode 100644 tests/test_top.py

diff --git a/Makefile b/Makefile
index 351413fc..6e5d920f 100644
--- a/Makefile
+++ b/Makefile
@@ -11,7 +11,7 @@ lint:
 	git diff --check --cached
 
 test:
-	pytest
+	pytest tests
 
 clean:
 	py3clean .
diff --git a/tests/test_top.py b/tests/test_top.py
deleted file mode 100644
index fdb894f4..00000000
--- a/tests/test_top.py
+++ /dev/null
@@ -1,31 +0,0 @@
-import os
-import pytest
-
-from fpga.project import Project
-
-
-def get_pathfile(file):
-    return os.path.join(os.path.dirname(__file__), file)
-
-
-def test_default():
-    prj = Project()
-    assert prj.tool.top == "UNDEFINED"
-
-
-def test_names():
-    prj = Project()
-    prj.set_top('test1')
-    assert prj.tool.top == "test1"
-    prj.set_top('test2')
-    assert prj.tool.top == "test2"
-
-
-def test_files():
-    prj = Project()
-    prj.set_top(get_pathfile('../hdl/fakes/top.vhdl'))
-    assert prj.tool.top == "Top1"
-    prj.set_top(get_pathfile('../hdl/fakes/top.v'))
-    assert prj.tool.top == "Top1"
-    prj.set_top(get_pathfile('../README.md'))
-    assert prj.tool.top == "UNDEFINED"

From 62e2fd9dd11846a3c5c237d7b92801ca01fb8896 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 2 Jun 2024 13:34:45 -0300
Subject: [PATCH 062/248] Renamed hooks as internals, added info about the
 internal data structure

---
 docs/hooks.rst     | 29 -------------------
 docs/index.rst     |  4 +--
 docs/internals.rst | 70 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 72 insertions(+), 31 deletions(-)
 delete mode 100644 docs/hooks.rst
 create mode 100644 docs/internals.rst

diff --git a/docs/hooks.rst b/docs/hooks.rst
deleted file mode 100644
index 498aceed..00000000
--- a/docs/hooks.rst
+++ /dev/null
@@ -1,29 +0,0 @@
-Hooks
-=====
-
-.. code-block::
-
-    create project
-    config project
-    part
-    precfg hook
-    params
-    defines
-    includes
-    files
-    arch
-    top
-    postcfg hook
-    close project
-
-    open project
-    presyn hook
-    synthesis
-    postsyn hook
-    prepar hook
-    place_and_route
-    postpar hook
-    prebit hook
-    bitstream
-    postbit hook
-    close project
diff --git a/docs/index.rst b/docs/index.rst
index 4984a41d..88c75aa4 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -16,6 +16,6 @@ PyFPGA's documentation
    intro
    basic
    advanced
-   hooks
-   tools
    api
+   tools
+   internals
diff --git a/docs/internals.rst b/docs/internals.rst
new file mode 100644
index 00000000..0ec8ded5
--- /dev/null
+++ b/docs/internals.rst
@@ -0,0 +1,70 @@
+Internals
+=========
+
+Underlying tool steps
+---------------------
+
+.. code-block::
+
+    create project
+    config project
+    part
+    precfg hook
+    params
+    defines
+    includes
+    files
+    arch
+    top
+    postcfg hook
+    close project
+
+    open project
+    presyn hook
+    synthesis
+    postsyn hook
+    prepar hook
+    place_and_route
+    postpar hook
+    prebit hook
+    bitstream
+    postbit hook
+    close project
+
+Internal data structure
+-----------------------
+
+.. code-block::
+
+    data = {
+        'part': 'PARTNAME',
+        'includes': ['DIR1', 'DIR2', 'DIR3'],
+        'files': {
+            'file1': {'type': 'vhdl', 'options': 'OPT1', 'library': 'LIB1'},
+            'file2': {'type': 'vlog', 'options': 'OPT2', 'library': None},
+            'file3': {'type': 'slog', 'options': 'OPT3', 'library': None},
+            'file4': {'type': 'cons', 'options': 'OPT4', 'library': None}
+        },
+        'top': 'TOPNAME',
+        'params': {
+            'PAR1': 'VAL1',
+            'PAR2': 'VAL2',
+            'PAR3': 'VAL3'
+        },
+        'defines': {
+            'DEF1': 'VAL1',
+            'DEF2': 'VAL2',
+            'DEF3': 'VAL3'
+        },
+        'arch': 'ARCHNAME',
+        'hooks': {
+            'precfg': ['CMD1', 'CMD2'],
+            'postcfg': ['CMD1', 'CMD2'],
+            'presyn': ['CMD1', 'CMD2'],
+            'postsyn': ['CMD1', 'CMD2'],
+            'prepar': ['CMD1', 'CMD2'],
+            'postpar': ['CMD1', 'CMD2'],
+            'prebit': ['CMD1', 'CMD2'],
+            'postbit': ['CMD1', 'CMD2']
+        }
+    }

From ea3c46820a003258656b453918811dd8a263b7a7 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 2 Jun 2024 13:36:59 -0300
Subject: [PATCH 063/248] Added a directory with empty files, to test methods
 that deal with directories/files

---
 tests/fakedata/dir1/slog1.sv   | 0
 tests/fakedata/dir1/slog1.svh  | 0
 tests/fakedata/dir1/vhdl1.vhd  | 0
 tests/fakedata/dir1/vhdl1.vhdl | 0
 tests/fakedata/dir1/vlog1.v    | 0
 tests/fakedata/dir1/vlog1.vh   | 0
 tests/fakedata/dir2/slog2.sv   | 0
 tests/fakedata/dir2/slog2.svh  | 0
 tests/fakedata/dir2/vhdl2.vhd  | 0
 tests/fakedata/dir2/vhdl2.vhdl | 0
 tests/fakedata/dir2/vlog2.v    | 0
 tests/fakedata/dir2/vlog2.vh   | 0
 tests/fakedata/dir3/slog3.sv   | 0
 tests/fakedata/dir3/slog3.svh  | 0
 tests/fakedata/dir3/vhdl3.vhd  | 0
 tests/fakedata/dir3/vhdl3.vhdl | 0
 tests/fakedata/dir3/vlog3.v    | 0
 tests/fakedata/dir3/vlog3.vh   | 0
 tests/fakedata/slog0.sv        | 0
 tests/fakedata/slog0.svh       | 0
 tests/fakedata/vhdl0.vhd       | 0
 tests/fakedata/vhdl0.vhdl      | 0
 tests/fakedata/vlog0.v         | 0
 tests/fakedata/vlog0.vh        | 0
 24 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 tests/fakedata/dir1/slog1.sv
 create mode 100644 tests/fakedata/dir1/slog1.svh
 create mode 100644 tests/fakedata/dir1/vhdl1.vhd
 create mode 100644 tests/fakedata/dir1/vhdl1.vhdl
 create mode 100644 tests/fakedata/dir1/vlog1.v
 create mode 100644 tests/fakedata/dir1/vlog1.vh
 create mode 100644 tests/fakedata/dir2/slog2.sv
 create mode 100644 tests/fakedata/dir2/slog2.svh
 create mode 100644 tests/fakedata/dir2/vhdl2.vhd
 create mode 100644 tests/fakedata/dir2/vhdl2.vhdl
 create mode 100644 tests/fakedata/dir2/vlog2.v
 create mode 100644 tests/fakedata/dir2/vlog2.vh
 create mode 100644 tests/fakedata/dir3/slog3.sv
 create mode 100644 tests/fakedata/dir3/slog3.svh
 create mode 100644 tests/fakedata/dir3/vhdl3.vhd
 create mode 100644 tests/fakedata/dir3/vhdl3.vhdl
 create mode 100644 tests/fakedata/dir3/vlog3.v
 create mode 100644 tests/fakedata/dir3/vlog3.vh
 create mode 100644 tests/fakedata/slog0.sv
 create mode 100644 tests/fakedata/slog0.svh
 create mode 100644 tests/fakedata/vhdl0.vhd
 create mode 100644 tests/fakedata/vhdl0.vhdl
 create mode 100644 tests/fakedata/vlog0.v
 create mode 100644 tests/fakedata/vlog0.vh

diff --git a/tests/fakedata/dir1/slog1.sv b/tests/fakedata/dir1/slog1.sv
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/fakedata/dir1/slog1.svh b/tests/fakedata/dir1/slog1.svh
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/fakedata/dir1/vhdl1.vhd b/tests/fakedata/dir1/vhdl1.vhd
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/fakedata/dir1/vhdl1.vhdl b/tests/fakedata/dir1/vhdl1.vhdl
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/fakedata/dir1/vlog1.v b/tests/fakedata/dir1/vlog1.v
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/fakedata/dir1/vlog1.vh b/tests/fakedata/dir1/vlog1.vh
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/fakedata/dir2/slog2.sv b/tests/fakedata/dir2/slog2.sv
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/fakedata/dir2/slog2.svh b/tests/fakedata/dir2/slog2.svh
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/fakedata/dir2/vhdl2.vhd b/tests/fakedata/dir2/vhdl2.vhd
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/fakedata/dir2/vhdl2.vhdl b/tests/fakedata/dir2/vhdl2.vhdl
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/fakedata/dir2/vlog2.v b/tests/fakedata/dir2/vlog2.v
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/fakedata/dir2/vlog2.vh b/tests/fakedata/dir2/vlog2.vh
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/fakedata/dir3/slog3.sv b/tests/fakedata/dir3/slog3.sv
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/fakedata/dir3/slog3.svh b/tests/fakedata/dir3/slog3.svh
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/fakedata/dir3/vhdl3.vhd b/tests/fakedata/dir3/vhdl3.vhd
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/fakedata/dir3/vhdl3.vhdl b/tests/fakedata/dir3/vhdl3.vhdl
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/fakedata/dir3/vlog3.v b/tests/fakedata/dir3/vlog3.v
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/fakedata/dir3/vlog3.vh b/tests/fakedata/dir3/vlog3.vh
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/fakedata/slog0.sv b/tests/fakedata/slog0.sv
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/fakedata/slog0.svh b/tests/fakedata/slog0.svh
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/fakedata/vhdl0.vhd b/tests/fakedata/vhdl0.vhd
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/fakedata/vhdl0.vhdl b/tests/fakedata/vhdl0.vhdl
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/fakedata/vlog0.v b/tests/fakedata/vlog0.v
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/fakedata/vlog0.vh b/tests/fakedata/vlog0.vh
new file mode 100644
index 00000000..e69de29b

From 1455a0993e9f517127f7623574ca19a4875d4549 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 2 Jun 2024 16:55:51 -0300
Subject: [PATCH 064/248] Removed unused things

---
 pyfpga/factory.py | 137 +++++-----------------------------------------
 1 file changed, 14 insertions(+), 123 deletions(-)

diff --git a/pyfpga/factory.py b/pyfpga/factory.py
index 55b92fb3..d7fc3502 100644
--- a/pyfpga/factory.py
+++ b/pyfpga/factory.py
@@ -8,146 +8,37 @@
 A factory class to create FPGA projects.
 """
 
-import inspect
-import logging
-import os
-
 from fpga.tool.ise import Ise
 from fpga.tool.libero import Libero
 from fpga.tool.openflow import Openflow
 from fpga.tool.quartus import Quartus
 from fpga.tool.vivado import Vivado
 
+# pylint: disable=return-in-init
+# pylint: disable=no-else-return
+# pylint: disable=too-many-return-statements
+# pylint: disable=too-few-public-methods
 
-TOOLS = [
-    'ghdl', 'ise', 'libero', 'openflow', 'quartus', 'vivado', 'yosys',
-    'yosys-ise', 'yosys-vivado'
-]
-
-
-_log = logging.getLogger(__name__)
-_log.level = logging.INFO
-_log.addHandler(logging.NullHandler())
-
-
-class Project:
-    """Class to manage an FPGA project.
 
-    :param tool: FPGA tool to be used
-    :param project: project name (the tool name is used if none specified)
-    :param meta: a dict with metadata about the project
-    :param relative_to_script: specifies if the files/directories are relative
-     to the script or the execution directory
-    :raises NotImplementedError: when tool is unsupported
-
-    .. note:: Valid values for **tool** are ``ghdl``, ``ise``, ``libero``,
-     ``openflow``, ``quartus``, ``vivado``, ``yosys``, ``yosys-ise`` and
-     ``yosys-vivado``
-    """
+class Factory:
+    """A factory class to create FPGA projects."""
 
     def __init__(
-            self, tool='vivado', project=None,
-            relative_to_script=True):
+            self, tool='vivado', project=None):
         """Class constructor."""
         if tool == 'ghdl':
-            self.tool = Openflow(project, frontend='ghdl', backend='vhdl')
+            return Openflow(project, frontend='ghdl', backend='vhdl')
         elif tool in ['ise', 'yosys-ise']:
-            self.tool = Ise(project, 'yosys' if 'yosys' in tool else '')
+            return Ise(project, 'yosys' if 'yosys' in tool else '')
         elif tool == 'libero':
-            self.tool = Libero(project)
+            return Libero(project)
         elif tool == 'openflow':
-            self.tool = Openflow(project)
+            return Openflow(project)
         elif tool == 'quartus':
-            self.tool = Quartus(project)
+            return Quartus(project)
         elif tool in ['vivado', 'yosys-vivado']:
-            self.tool = Vivado(project, 'yosys' if 'yosys' in tool else '')
+            return Vivado(project, 'yosys' if 'yosys' in tool else '')
         elif tool == 'yosys':
-            self.tool = Openflow(project, frontend='yosys', backend='verilog')
+            return Openflow(project, frontend='yosys', backend='verilog')
         else:
             raise NotImplementedError(tool)
-        self._rundir = os.getcwd()
-        _log.debug('RUNDIR = %s', self._rundir)
-        if relative_to_script:
-            self._reldir = os.path.dirname(inspect.stack()[-1].filename)
-        else:
-            self._reldir = ''
-        _log.debug('RELDIR = %s', self._reldir)
-        self._absdir = os.path.join(self._rundir, self._reldir)
-        _log.debug('ABSDIR = %s', self._absdir)
-
-    def add_hook(self, hook, phase='project'):
-        """Adds a hook in the specified phase.
-
-        A hook is a place that allows you to insert customized programming.
-
-        :param hook: is a string representing a tool specific command
-        :param phase: the phase where to insert a hook
-        :raises ValueError: when phase is unsupported
-
-        .. note:: Valid values for *phase* are
-         ``prefile`` (to add options needed to find files),
-         ``project`` (to add project related options),
-         ``preflow`` (to change options previous to run the flow),
-         ``postsyn`` (to perform an action between *syn* and *par*),
-         ``postpar`` (to perform an action between *par* and *bit*) and
-         ``postbit`` (to perform an action after *bit*)
-
-        .. warning:: Using a hook, you will be probably broken the vendor
-         independence
-        """
-        self.tool.add_hook(hook, phase)
-
-    def generate(self, to_task='bit', from_task='prj', capture=False):
-        """Run the FPGA tool.
-
-        :param to_task: last task
-        :param from_task: first task
-        :param capture: capture STDOUT and STDERR
-        :returns: STDOUT and STDERR messages
-        :raises ValueError: when from_task is later than to_task
-        :raises ValueError: when to_task or from_task are unsupported
-        :raises RuntimeError: when the tool to be used is not found
-
-        .. note:: Valid values for **tasks** are
-         ``prj`` (to creates the project file),
-         ``syn`` (to performs the synthesis),
-         ``imp`` (to runs implementation) and
-         ``bit`` (to generates the bitstream)
-        """
-        # _log.info(
-        #     'generating "%s" project using "%s" tool into "%s" directory',
-        #     self.tool.project, self.tool.get_configs()['tool'], self.outdir
-        # )
-        if capture:
-            _log.info('the execution messages are being captured')
-        return self.tool.generate(to_task, from_task, capture)
-
-    def set_bitstream(self, path):
-        """Set the bitstream file to transfer.
-
-        :param path: path to the bitstream file
-        """
-        path = os.path.join(self._absdir, path)
-        if not os.path.exists(path):
-            raise FileNotFoundError(path)
-        self.tool.set_bitstream(path)
-
-    def transfer(
-            self, devtype='fpga', position=1, part='', width=1):
-        """Transfers the generated bitstream to a device.
-
-        :param devtype: *fpga* or other valid option
-         (depending on the used tool, it could be *spi*, *bpi*, etc)
-        :param position: position of the device in the JTAG chain
-        :param part: name of the memory (when device is not *fpga*)
-        :param width: bits width of the memory (when device is not *fpga*)
-        :returns: STDOUT and STDERR messages
-        :raises FileNotFoundError: when the bitstream is not found
-        :raises ValueError: when devtype, position or width are unsupported
-        :raises RuntimeError: when the tool to be used is not found
-        """
-        # _log.info(
-        #     'transfering "%s" project using "%s" tool from "%s" directory',
-        #     self.tool.project, self.tool.get_configs()['tool'], self.outdir
-        # )
-        return self.tool.transfer(devtype, position, part, width, True)

From df2a2a2d94d9802bc0260e0491aba1ada57b70ca Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 2 Jun 2024 16:56:45 -0300
Subject: [PATCH 065/248] Removed test_files.py

---
 Makefile            |  2 +-
 tests/test_files.py | 18 ------------------
 2 files changed, 1 insertion(+), 19 deletions(-)
 delete mode 100644 tests/test_files.py

diff --git a/Makefile b/Makefile
index 6e5d920f..9c8032b2 100644
--- a/Makefile
+++ b/Makefile
@@ -11,7 +11,7 @@ lint:
 	git diff --check --cached
 
 test:
-	pytest tests
+	cd tests; pytest
 
 clean:
 	py3clean .
diff --git a/tests/test_files.py b/tests/test_files.py
deleted file mode 100644
index ffe55f81..00000000
--- a/tests/test_files.py
+++ /dev/null
@@ -1,18 +0,0 @@
-import os
-import pytest
-
-from fpga.project import Project, TOOLS
-
-
-def get_path(file):
-    return os.path.join(os.path.dirname(__file__), file)
-
-
-@pytest.mark.parametrize('tool', TOOLS)
-def test_files(tool):
-    prj = Project(tool)
-    prj.add_files(get_path('../hdl/*.vhdl'))
-    prj.add_files(get_path('../hdl/*.v'))
-    assert len(prj.get_files()['verilog']) == 3
-    assert len(prj.get_files()['vhdl']) == 4
-    assert len(prj.get_files()['constraint']) == 0

From 79175ed68107321a9e2a45101b0aedebeb011c87 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 2 Jun 2024 16:57:03 -0300
Subject: [PATCH 066/248] Implemented directory/file exists check

---
 pyfpga/project.py  | 131 +++++++++++++++++++++++++--------------------
 tests/test_data.py | 115 ++++++++++++++++++++++-----------------
 2 files changed, 140 insertions(+), 106 deletions(-)

diff --git a/pyfpga/project.py b/pyfpga/project.py
index 0a5479c0..f7d49537 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -8,7 +8,7 @@
 Base class that implements agnostic methods to deal with FPGA projects.
 """
 
-# import glob
+import glob
 import logging
 import os
 import subprocess
@@ -55,59 +55,48 @@ def set_part(self, name):
         self.data['part'] = name
 
     def _add_file(self, pathname, filetype=None, library=None, options=None):
-        # """Adds files to the project.
-        #
-        # :param pathname: a relative path to a file, which can contain
-        #  shell-style wildcards (glob compliant)
-        # :param filetype: specifies the file type
-        # :param library: an optional VHDL library name
-        # :param options: to be provided to the underlying tool
-        # :raises FileNotFoundError: when a file specified as pathname is not
-        #  found
-        # :raises ValueError: when *filetype* is unsupported
-        #
-        # .. note:: Valid values for *filetype* are ``vhdl``, ``verilog``,
-        # ``system_verilog``, ``constraint`` (default) and ``block_design``
-        # (only **Vivado** is currently supported). If None provided, this
-        # value is automatically discovered based on the extension (
-        # ``.vhd`` or ``.vhdl``, ``.v`` and ``.sv``).
-        # """
-        # pathname = os.path.join(self._absdir, pathname)
-        # pathname = os.path.normpath(pathname)
-        # _log.debug('PATHNAME = %s', pathname)
-        # files = glob.glob(pathname)
-        # if len(files) == 0:
-        #     raise FileNotFoundError(pathname)
-        # for file in files:
-        #     if not os.path.exists(file):
-        #         raise FileNotFoundError(file)
-        #     if filetype is None:
-        #         ext = os.path.splitext(file)[1]
-        #         if ext in ['.vhd', '.vhdl']:
-        #             filetype = 'vhdl'
-        #         elif ext in ['.v', '.sv']:
-        #             filetype = 'verilog'
-        #         else:
-        #             filetype = 'constraint'
-        #         _log.debug('add_files: %s filetype detected', filetype)
-        #     file = os.path.relpath(file, self.outdir)
-        #     self.tool.add_file(file, filetype, library, options)
-        self.data.setdefault('files', {})[pathname] = {
-            'type': filetype, 'options': options, 'library': library
-        }
-
-    def add_cons(self, pathname, options=None):
-        """Temp placeholder"""
+        files = glob.glob(pathname)
+        if len(files) == 0:
+            raise FileNotFoundError(pathname)
+        for file in files:
+            path = Path(file).resolve()
+            self.data.setdefault('files', {})[path] = {
+                'type': filetype, 'options': options, 'library': library
+            }
+
+    def add_cons(self, pathname):
+        """Add constraint file/s.
+
+        :param pathname: path to a constraint file (glob compliant)
+        :type pathname: str
+        :raises FileNotFoundError: when pathname is not found
+        """
         self.logger.debug('Executing add_cons')
-        self._add_file(pathname, filetype='cons', options=options)
+        self._add_file(pathname, filetype='cons', options=None)
 
     def add_slog(self, pathname, options=None):
-        """Temp placeholder"""
+        """Add System Verilog file/s.
+
+        :param pathname: path to a SV file (glob compliant)
+        :type pathname: str
+        :param options: for the underlying tool
+        :type options: str, optional
+        :raises FileNotFoundError: when pathname is not found
+        """
         self.logger.debug('Executing add_slog')
         self._add_file(pathname, filetype='slog', options=options)
 
     def add_vhdl(self, pathname, library=None, options=None):
-        """Temp placeholder"""
+        """Add VHDL file/s.
+
+        :param pathname: path to a SV file (glob compliant)
+        :type pathname: str
+        :param library: VHDL library name
+        :type library: str, optional
+        :param options: for the underlying tool
+        :type options: str, optional
+        :raises FileNotFoundError: when pathname is not found
+        """
         self.logger.debug('Executing add_vhdl')
         self._add_file(
             pathname, filetype='vhdl',
@@ -115,7 +104,14 @@ def add_vhdl(self, pathname, library=None, options=None):
         )
 
     def add_vlog(self, pathname, options=None):
-        """Temp placeholder"""
+        """Add Verilog file/s.
+
+        :param pathname: path to a SV file (glob compliant)
+        :type pathname: str
+        :param options: for the underlying tool
+        :type options: str, optional
+        :raises FileNotFoundError: when pathname is not found
+        """
         self.logger.debug('Executing add_vlog')
         self._add_file(pathname, filetype='vlog', options=options)
 
@@ -129,13 +125,9 @@ def add_include(self, path):
         :raises NotADirectoryError: if path is not a directory
         """
         self.logger.debug('Executing add_include')
-        # path = os.path.join(self._absdir, path)
-        # path = os.path.normpath(path)
-        # if os.path.isdir(path):
-        #     path = os.path.relpath(path, self.outdir)
-        #     self.tool.add_vlog_include(path)
-        # else:
-        #     raise NotADirectoryError(path)
+        path = Path(path).resolve()
+        if not path.is_dir():
+            raise NotADirectoryError(path)
         self.data.setdefault('includes', []).append(path)
 
     def add_param(self, name, value):
@@ -179,7 +171,16 @@ def set_top(self, name):
         self.data['top'] = name
 
     def add_hook(self, stage, hook):
-        """Add hook for a specific stage."""
+        """Add a hook in the specific stage.
+
+        A hook is a place that allows you to insert customized code.
+
+        :param stage: where to insert the hook
+        :type stage: str
+        :param hook: a tool-specific command
+        :type hook: str
+        :raises ValueError: when stage is invalid
+        """
         stages = [
             'precfg', 'postcfg', 'presyn', 'postsyn',
             'prepar', 'postpar', 'prebit', 'postbit'
@@ -189,7 +190,15 @@ def add_hook(self, stage, hook):
         self.data.setdefault('hooks', {}).setdefault(stage, []).append(hook)
 
     def make(self, end='bit', start='prj'):
-        """Temp placeholder"""
+        """Run the underlying tool.
+
+        :param end: last task
+        :type end: str, optional
+        :param start: first task
+        :type start: str, optional
+
+        .. note:: Valid values are ``cfg``, ``syn``, ``imp`` and ``bit``.
+        """
         steps = ['cfg', 'syn', 'par', 'bit']
         if end not in steps or start not in steps:
             raise ValueError('Invalid steps.')
@@ -197,7 +206,13 @@ def make(self, end='bit', start='prj'):
         raise NotImplementedError('Method is not implemented yet.')
 
     def prog(self, position=1, bitstream=None):
-        """Temp placeholder"""
+        """Program the FPGA
+
+        :param position: position of the device in the JTAG chain
+        :type position: str, optional
+        :param bitstream: bitstream to be programmed
+        :type bitstream: str, optional
+        """
         raise NotImplementedError('Method is not implemented yet.')
 
     def _run(self, command):
diff --git a/tests/test_data.py b/tests/test_data.py
index b17b2dd4..4c363de5 100644
--- a/tests/test_data.py
+++ b/tests/test_data.py
@@ -1,38 +1,58 @@
 import os
 import pytest
 
+from pathlib import Path
+
 from pyfpga.project import Project
 
 pattern = {
     'part': 'PARTNAME',
-    'includes': ['INC1', 'INC2', 'INC3'],
+    'includes': [
+        Path('fakedata/dir1').resolve(),
+        Path('fakedata/dir2').resolve(),
+        Path('fakedata/dir3').resolve()
+    ],
     'files': {
-        'path1': {'type': 'vhdl', 'options': 'OPT1', 'library': 'LIB1'},
-        'path2': {'type': 'vlog', 'options': 'OPT2', 'library': None},
-        'path3': {'type': 'slog', 'options': 'OPT3', 'library': None},
-        'path4': {'type': 'cons', 'options': 'OPT4', 'library': None}
+        Path('fakedata/dir1/slog1.sv').resolve():
+            {'type': 'slog', 'options': None, 'library': None},
+        Path('fakedata/dir2/slog2.sv').resolve():
+            {'type': 'slog', 'options': None, 'library': None},
+        Path('fakedata/dir3/slog3.sv').resolve():
+            {'type': 'slog', 'options': None, 'library': None},
+        Path('fakedata/dir1/vhdl1.vhdl').resolve():
+            {'type': 'vhdl', 'options': None, 'library': None},
+        Path('fakedata/dir2/vhdl2.vhdl').resolve():
+            {'type': 'vhdl', 'options': None, 'library': None},
+        Path('fakedata/dir3/vhdl3.vhdl').resolve():
+            {'type': 'vhdl', 'options': None, 'library': None},
+        Path('fakedata/dir1/vlog1.v').resolve():
+            {'type': 'vlog', 'options': None, 'library': None},
+        Path('fakedata/dir2/vlog2.v').resolve():
+            {'type': 'vlog', 'options': None, 'library': None},
+        Path('fakedata/dir3/vlog3.v').resolve():
+            {'type': 'vlog', 'options': None, 'library': None}
     },
     'top': 'TOPNAME',
     'params': {
-        'PARAM1': 'VALUE1',
-        'PARAM2': 'VALUE2',
-        'PARAM3': 'VALUE3'
+        'PAR1': 'VAL1',
+        'PAR2': 'VAL2',
+        'PAR3': 'VAL3'
     },
     'defines': {
-        'DEF1': 'VALUE1',
-        'DEF2': 'VALUE2',
-        'DEF3': 'VALUE3'
+        'DEF1': 'VAL1',
+        'DEF2': 'VAL2',
+        'DEF3': 'VAL3'
     },
     'arch': 'ARCHNAME',
     'hooks': {
-        'precfg': ['HOOK1', 'HOOK2'],
-        'postcfg': ['HOOK1', 'HOOK2'],
-        'presyn': ['HOOK1', 'HOOK2'],
-        'postsyn': ['HOOK1', 'HOOK2'],
-        'prepar': ['HOOK1', 'HOOK2'],
-        'postpar': ['HOOK1', 'HOOK2'],
-        'prebit': ['HOOK1', 'HOOK2'],
-        'postbit': ['HOOK1', 'HOOK2']
+        'precfg': ['CMD1', 'CMD2'],
+        'postcfg': ['CMD1', 'CMD2'],
+        'presyn': ['CMD1', 'CMD2'],
+        'postsyn': ['CMD1', 'CMD2'],
+        'prepar': ['CMD1', 'CMD2'],
+        'postpar': ['CMD1', 'CMD2'],
+        'prebit': ['CMD1', 'CMD2'],
+        'postbit': ['CMD1', 'CMD2']
     }
 }
 
@@ -42,33 +62,32 @@ def test_names():
     prj.set_part('PARTNAME')
     prj.set_top('TOPNAME')
     prj.set_arch('ARCHNAME')
-    prj.add_include('INC1')
-    prj.add_include('INC2')
-    prj.add_include('INC3')
-    prj.add_param('PARAM1', 'VALUE1')
-    prj.add_param('PARAM2', 'VALUE2')
-    prj.add_param('PARAM3', 'VALUE3')
-    prj.add_define('DEF1', 'VALUE1')
-    prj.add_define('DEF2', 'VALUE2')
-    prj.add_define('DEF3', 'VALUE3')
-    prj.add_vhdl('path1', 'LIB1', 'OPT1')
-    prj.add_vlog('path2', 'OPT2')
-    prj.add_slog('path3', 'OPT3')
-    prj.add_cons('path4', 'OPT4')
-    prj.add_hook('precfg', 'HOOK1')
-    prj.add_hook('precfg', 'HOOK2')
-    prj.add_hook('postcfg', 'HOOK1')
-    prj.add_hook('postcfg', 'HOOK2')
-    prj.add_hook('presyn', 'HOOK1')
-    prj.add_hook('presyn', 'HOOK2')
-    prj.add_hook('postsyn', 'HOOK1')
-    prj.add_hook('postsyn', 'HOOK2')
-    prj.add_hook('prepar', 'HOOK1')
-    prj.add_hook('prepar', 'HOOK2')
-    prj.add_hook('postpar', 'HOOK1')
-    prj.add_hook('postpar', 'HOOK2')
-    prj.add_hook('prebit', 'HOOK1')
-    prj.add_hook('prebit', 'HOOK2')
-    prj.add_hook('postbit', 'HOOK1')
-    prj.add_hook('postbit', 'HOOK2')
+    prj.add_include('fakedata/dir1')
+    prj.add_include('fakedata/dir2')
+    prj.add_include('fakedata/dir3')
+    prj.add_slog('fakedata/**/*.sv')
+    prj.add_vhdl('fakedata/**/*.vhdl')
+    prj.add_vlog('fakedata/**/*.v')
+    prj.add_param('PAR1', 'VAL1')
+    prj.add_param('PAR2', 'VAL2')
+    prj.add_param('PAR3', 'VAL3')
+    prj.add_define('DEF1', 'VAL1')
+    prj.add_define('DEF2', 'VAL2')
+    prj.add_define('DEF3', 'VAL3')
+    prj.add_hook('precfg', 'CMD1')
+    prj.add_hook('precfg', 'CMD2')
+    prj.add_hook('postcfg', 'CMD1')
+    prj.add_hook('postcfg', 'CMD2')
+    prj.add_hook('presyn', 'CMD1')
+    prj.add_hook('presyn', 'CMD2')
+    prj.add_hook('postsyn', 'CMD1')
+    prj.add_hook('postsyn', 'CMD2')
+    prj.add_hook('prepar', 'CMD1')
+    prj.add_hook('prepar', 'CMD2')
+    prj.add_hook('postpar', 'CMD1')
+    prj.add_hook('postpar', 'CMD2')
+    prj.add_hook('prebit', 'CMD1')
+    prj.add_hook('prebit', 'CMD2')
+    prj.add_hook('postbit', 'CMD1')
+    prj.add_hook('postbit', 'CMD2')
     assert prj.data == pattern, 'ERROR: unexpected data'

From 53bb363aa5c5cc2cf5ad5af846b019e2fd0bf0be Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Tue, 4 Jun 2024 21:25:39 -0300
Subject: [PATCH 067/248] Moved things from fpga to pyfpga

---
 pyfpga/factory.py                               |  2 +-
 {fpga/tool => pyfpga}/ise.py                    | 16 ++--------------
 {fpga/tool => pyfpga}/libero.py                 | 16 ++--------------
 {fpga/tool => pyfpga}/openflow.py               | 16 ++--------------
 {fpga/tool => pyfpga}/quartus.py                | 16 ++--------------
 .../templates/openflow-prog.jinja               | 17 +++--------------
 pyfpga/templates/vivado.jinja                   |  1 -
 fpga/tool/__init__.py => pyfpga/tool.py         | 16 ++--------------
 {fpga/tool => pyfpga}/vivado.py                 | 16 ++--------------
 9 files changed, 16 insertions(+), 100 deletions(-)
 rename {fpga/tool => pyfpga}/ise.py (88%)
 rename {fpga/tool => pyfpga}/libero.py (76%)
 rename {fpga/tool => pyfpga}/openflow.py (91%)
 rename {fpga/tool => pyfpga}/quartus.py (66%)
 rename fpga/tool/openprog.sh => pyfpga/templates/openflow-prog.jinja (57%)
 rename fpga/tool/__init__.py => pyfpga/tool.py (92%)
 rename {fpga/tool => pyfpga}/vivado.py (78%)

diff --git a/pyfpga/factory.py b/pyfpga/factory.py
index d7fc3502..d48547f6 100644
--- a/pyfpga/factory.py
+++ b/pyfpga/factory.py
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2019-2024 Rodrigo A. Melo
+# Copyright (C) 2024 Rodrigo A. Melo
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
diff --git a/fpga/tool/ise.py b/pyfpga/ise.py
similarity index 88%
rename from fpga/tool/ise.py
rename to pyfpga/ise.py
index c6f5e83d..817ca433 100644
--- a/fpga/tool/ise.py
+++ b/pyfpga/ise.py
@@ -1,19 +1,7 @@
 #
-# Copyright (C) 2019-2020 INTI
-# Copyright (C) 2019-2021 Rodrigo A. Melo
+# Copyright (C) 2019-2024 Rodrigo A. Melo
 #
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+# SPDX-License-Identifier: GPL-3.0-or-later
 #
 
 """fpga.tool.ise
diff --git a/fpga/tool/libero.py b/pyfpga/libero.py
similarity index 76%
rename from fpga/tool/libero.py
rename to pyfpga/libero.py
index ee463993..c037284c 100644
--- a/fpga/tool/libero.py
+++ b/pyfpga/libero.py
@@ -1,19 +1,7 @@
 #
-# Copyright (C) 2019-2020 INTI
-# Copyright (C) 2019-2021 Rodrigo A. Melo
+# Copyright (C) 2019-2024 Rodrigo A. Melo
 #
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+# SPDX-License-Identifier: GPL-3.0-or-later
 #
 
 """fpga.tool.libero
diff --git a/fpga/tool/openflow.py b/pyfpga/openflow.py
similarity index 91%
rename from fpga/tool/openflow.py
rename to pyfpga/openflow.py
index 0eb6b905..b8207d58 100644
--- a/fpga/tool/openflow.py
+++ b/pyfpga/openflow.py
@@ -1,19 +1,7 @@
 #
-# Copyright (C) 2020 INTI
-# Copyright (C) 2020-2021 Rodrigo A. Melo
+# Copyright (C) 2020-2024 Rodrigo A. Melo
 #
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+# SPDX-License-Identifier: GPL-3.0-or-later
 #
 
 """fpga.tool.openflow
diff --git a/fpga/tool/quartus.py b/pyfpga/quartus.py
similarity index 66%
rename from fpga/tool/quartus.py
rename to pyfpga/quartus.py
index f7644618..94db6ad6 100644
--- a/fpga/tool/quartus.py
+++ b/pyfpga/quartus.py
@@ -1,19 +1,7 @@
 #
-# Copyright (C) 2019-2020 INTI
-# Copyright (C) 2019-2020 Rodrigo A. Melo
+# Copyright (C) 2019-2024 Rodrigo A. Melo
 #
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+# SPDX-License-Identifier: GPL-3.0-or-later
 #
 
 """fpga.tool.quartus
diff --git a/fpga/tool/openprog.sh b/pyfpga/templates/openflow-prog.jinja
similarity index 57%
rename from fpga/tool/openprog.sh
rename to pyfpga/templates/openflow-prog.jinja
index 2746d050..3be40f53 100644
--- a/fpga/tool/openprog.sh
+++ b/pyfpga/templates/openflow-prog.jinja
@@ -1,19 +1,8 @@
-#!/bin/bash
 #
-# Copyright (C) 2020 Rodrigo A. Melo
+# PyFPGA
+# Copyright (C) 2020-2024 Rodrigo A. Melo
 #
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+# SPDX-License-Identifier: GPL-3.0-or-later
 #
 
 set -e
diff --git a/pyfpga/templates/vivado.jinja b/pyfpga/templates/vivado.jinja
index c1805387..16bed243 100644
--- a/pyfpga/templates/vivado.jinja
+++ b/pyfpga/templates/vivado.jinja
@@ -85,7 +85,6 @@ close_project
 
 {% if SYN or PAR or BIT %}
 open_project $PROJECT
-set_param general.maxThreads [expr {[exec nproc] < 32 ? [exec nproc] : 32}]
 
 {% if SYN %}
 {{ PRESYN }}
diff --git a/fpga/tool/__init__.py b/pyfpga/tool.py
similarity index 92%
rename from fpga/tool/__init__.py
rename to pyfpga/tool.py
index 9fc09685..f02931a3 100644
--- a/fpga/tool/__init__.py
+++ b/pyfpga/tool.py
@@ -1,19 +1,7 @@
 #
-# Copyright (C) 2019-2020 INTI
-# Copyright (C) 2019-2021 Rodrigo A. Melo
+# Copyright (C) 2019-2024 Rodrigo A. Melo
 #
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+# SPDX-License-Identifier: GPL-3.0-or-later
 #
 
 """fpga.tool
diff --git a/fpga/tool/vivado.py b/pyfpga/vivado.py
similarity index 78%
rename from fpga/tool/vivado.py
rename to pyfpga/vivado.py
index 067644ed..24cd2ae9 100644
--- a/fpga/tool/vivado.py
+++ b/pyfpga/vivado.py
@@ -1,19 +1,7 @@
 #
-# Copyright (C) 2019-2020 INTI
-# Copyright (C) 2019-2020 Rodrigo A. Melo
+# Copyright (C) 2019-2024 Rodrigo A. Melo
 #
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+# SPDX-License-Identifier: GPL-3.0-or-later
 #
 
 """fpga.tool.vivado

From 29aae524114ed2b7f835cbf74220fda888b534de Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Tue, 4 Jun 2024 22:09:40 -0300
Subject: [PATCH 068/248] Removed unused things, commented others

---
 pyfpga/factory.py  |  22 +--
 pyfpga/ise.py      | 243 +++++++++++++++--------------
 pyfpga/libero.py   | 127 ++++++++-------
 pyfpga/openflow.py | 381 +++++++++++++++++++++++----------------------
 pyfpga/quartus.py  |  94 +++++------
 pyfpga/tool.py     | 372 ++++++++++++++++++-------------------------
 pyfpga/vivado.py   | 115 +++++++-------
 7 files changed, 660 insertions(+), 694 deletions(-)

diff --git a/pyfpga/factory.py b/pyfpga/factory.py
index d48547f6..6236730e 100644
--- a/pyfpga/factory.py
+++ b/pyfpga/factory.py
@@ -8,11 +8,11 @@
 A factory class to create FPGA projects.
 """
 
-from fpga.tool.ise import Ise
-from fpga.tool.libero import Libero
-from fpga.tool.openflow import Openflow
-from fpga.tool.quartus import Quartus
-from fpga.tool.vivado import Vivado
+from pyfpga.ise import Ise
+from pyfpga.libero import Libero
+from pyfpga.openflow import Openflow
+from pyfpga.quartus import Quartus
+from pyfpga.vivado import Vivado
 
 # pylint: disable=return-in-init
 # pylint: disable=no-else-return
@@ -27,18 +27,18 @@ def __init__(
             self, tool='vivado', project=None):
         """Class constructor."""
         if tool == 'ghdl':
-            return Openflow(project, frontend='ghdl', backend='vhdl')
-        elif tool in ['ise', 'yosys-ise']:
-            return Ise(project, 'yosys' if 'yosys' in tool else '')
+            return Openflow(project)  # , frontend='ghdl', backend='vhdl')
+        elif tool == 'ise':
+            return Ise(project)
         elif tool == 'libero':
             return Libero(project)
         elif tool == 'openflow':
             return Openflow(project)
         elif tool == 'quartus':
             return Quartus(project)
-        elif tool in ['vivado', 'yosys-vivado']:
-            return Vivado(project, 'yosys' if 'yosys' in tool else '')
+        elif tool == 'vivado':
+            return Vivado(project)
         elif tool == 'yosys':
-            return Openflow(project, frontend='yosys', backend='verilog')
+            return Openflow(project)  # , frontend='yosys', backend='verilog')
         else:
             raise NotImplementedError(tool)
diff --git a/pyfpga/ise.py b/pyfpga/ise.py
index 817ca433..329e6e48 100644
--- a/pyfpga/ise.py
+++ b/pyfpga/ise.py
@@ -4,14 +4,13 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-"""fpga.tool.ise
-
-Implements the support of ISE (Xilinx).
+"""
+Implements support for ISE.
 """
 
-import re
+# import re
 
-from fpga.tool import Tool, run
+from pyfpga.project import Project
 
 _TEMPLATES = {
     'fpga': """setMode -bs
@@ -68,118 +67,126 @@
 """
 }
 
+# pylint: disable=too-few-public-methods
+
 
-class Ise(Tool):
-    """Implementation of the class to support ISE."""
-
-    _TOOL = 'ise'
-    _EXTENSION = 'xise'
-    _PART = 'xc7k160t-3-fbg484'
-    _GEN_PROGRAM = 'xtclsh'
-    _GEN_COMMAND = 'xtclsh ise.tcl'
-    _TRF_PROGRAM = 'impact'
-    _TRF_COMMAND = 'impact -batch ise-prog.impact'
-    _BIT_EXT = ['bit']
-    _DEVTYPES = ['fpga', 'spi', 'bpi', 'detect', 'unlock']
-    _CLEAN = [
-        # directories
-        'iseconfig', '_ngo', 'xlnx_auto_0_xdb', '_xmsgs', 'xst',
-        # files
-        '*.bgn', '*.bld', '*.bit',
-        '*.cmd_log', '*.csv',
-        '*.drc',
-        '*.gise',
-        '*.html',
-        '*.log', '*.lso',
-        '*.map', '*.mrp',
-        '*.ncd', '*.ngc', '*.ngd', '*.ngm', '*.ngr',
-        '*.pad', '*.par', '*.pcf', '*.prj', '*.ptwx',
-        '*.stx', '*.syr',
-        '*.twr', '*.twx',
-        '*.unroutes', '*.ut',
-        '*.txt',
-        '*.xml', '*.xpi', '*.xrpt', '*.xst', '*.xwbt',
-        '_impact*',
-        # pyfpga
-        '*.impact', 'ise.tcl'
-    ]
-
-    def __init__(self, project, frontend=None):
-        super().__init__(project)
-        if frontend == 'yosys':
-            from fpga.tool.openflow import Openflow
-            self.tool = Openflow(
-                self.project,
-                frontend='yosys',
-                backend='ise'
-            )
-            self.presynth = True
-
-    def set_part(self, part):
-        try:
-            device, speed, package = re.findall(r'(\w+)-(\w+)-(\w+)', part)[0]
-            if len(speed) > len(package):
-                speed, package = package, speed
-            part = f'{device}-{speed}-{package}'
-        except IndexError:
-            raise ValueError(
-                'Part must be DEVICE-SPEED-PACKAGE or DEVICE-PACKAGE-SPEED'
-            )
-        self.part['name'] = part
-        self.part['family'] = get_family(part)
-        self.part['device'] = device
-        self.part['package'] = package
-        self.part['speed'] = '-' + speed
-
-    def generate(self, to_task, from_task, capture):
-        if self.presynth and from_task in ['prj', 'syn']:
-            self.tool.set_part(self.part['name'])
-            self.tool.set_top(self.top)
-            self.tool.paths = self.paths
-            self.tool.files['vhdl'] = self.files['vhdl']
-            self.tool.files['verilog'] = self.files['verilog']
-            self.tool.params = self.params
-            output1 = self.tool.generate('syn', 'prj', capture)
-            output2 = super().generate(to_task, from_task, capture)
-            return str(output1) + str(output2)
-        return super().generate(to_task, from_task, capture)
-
-    def transfer(self, devtype, position, part, width, capture):
-        super().transfer(devtype, position, part, width, capture)
-        temp = _TEMPLATES[devtype]
-        if devtype not in ['detect', 'unlock']:
-            temp = temp.replace('#BITSTREAM#', self.bitstream)
-            temp = temp.replace('#POSITION#', str(position))
-            temp = temp.replace('#NAME#', part)
-            temp = temp.replace('#WIDTH#', str(width))
-        with open('ise-prog.impact', 'w', encoding='utf-8') as file:
-            file.write(temp)
-        return run(self._TRF_COMMAND, capture)
-
-
-def get_family(part):
-    """Get the Family name from the specified part name."""
-    part = part.lower()
-    families = {
-        r'xc7a\d+l': 'artix7l',
-        r'xc7a': 'artix7',
-        r'xc7k\d+l': 'kintex7l',
-        r'xc7k': 'kintex7',
-        r'xc3sd\d+a': 'spartan3adsp',
-        r'xc3s\d+a': 'spartan3a',
-        r'xc3s\d+e': 'spartan3e',
-        r'xc3s': 'spartan3',
-        r'xc6s\d+l': 'spartan6l',
-        r'xc6s': 'spartan6',
-        r'xc4v': 'virtex4',
-        r'xc5v': 'virtex5',
-        r'xc6v\d+l': 'virtex6l',
-        r'xc6v': 'virtex6',
-        r'xc7v\d+l': 'virtex7l',
-        r'xc7v': 'virtex7',
-        r'xc7z': 'zynq'
+class Ise(Project):
+    """Class to support ISE projects."""
+
+    tool = {
+        'program': 'xtclsh',
+        'command': 'xtclsh ise.tcl',
     }
-    for key, value in families.items():
-        if re.match(key, part):
-            return value
-    return 'UNKNOWN'
+
+#     _TOOL = 'ise'
+#     _EXTENSION = 'xise'
+#     _PART = 'xc7k160t-3-fbg484'
+#     _GEN_PROGRAM = 'xtclsh'
+#     _GEN_COMMAND = 'xtclsh ise.tcl'
+#     _TRF_PROGRAM = 'impact'
+#     _TRF_COMMAND = 'impact -batch ise-prog.impact'
+#     _BIT_EXT = ['bit']
+#     _DEVTYPES = ['fpga', 'spi', 'bpi', 'detect', 'unlock']
+#     _CLEAN = [
+#         # directories
+#         'iseconfig', '_ngo', 'xlnx_auto_0_xdb', '_xmsgs', 'xst',
+#         # files
+#         '*.bgn', '*.bld', '*.bit',
+#         '*.cmd_log', '*.csv',
+#         '*.drc',
+#         '*.gise',
+#         '*.html',
+#         '*.log', '*.lso',
+#         '*.map', '*.mrp',
+#         '*.ncd', '*.ngc', '*.ngd', '*.ngm', '*.ngr',
+#         '*.pad', '*.par', '*.pcf', '*.prj', '*.ptwx',
+#         '*.stx', '*.syr',
+#         '*.twr', '*.twx',
+#         '*.unroutes', '*.ut',
+#         '*.txt',
+#         '*.xml', '*.xpi', '*.xrpt', '*.xst', '*.xwbt',
+#         '_impact*',
+#         # pyfpga
+#         '*.impact', 'ise.tcl'
+#     ]
+
+#     def __init__(self, project, frontend=None):
+#         super().__init__(project)
+#         if frontend == 'yosys':
+#             from fpga.tool.openflow import Openflow
+#             self.tool = Openflow(
+#                 self.project,
+#                 frontend='yosys',
+#                 backend='ise'
+#             )
+#             self.presynth = True
+
+#     def set_part(self, part):
+#         try:
+#             device, speed, package =
+#                 re.findall(r'(\w+)-(\w+)-(\w+)', part)[0]
+#             if len(speed) > len(package):
+#                 speed, package = package, speed
+#             part = f'{device}-{speed}-{package}'
+#         except IndexError:
+#             raise ValueError(
+#                 'Part must be DEVICE-SPEED-PACKAGE or DEVICE-PACKAGE-SPEED'
+#             )
+#         self.part['name'] = part
+#         self.part['family'] = get_family(part)
+#         self.part['device'] = device
+#         self.part['package'] = package
+#         self.part['speed'] = '-' + speed
+
+#     def generate(self, to_task, from_task, capture):
+#         if self.presynth and from_task in ['prj', 'syn']:
+#             self.tool.set_part(self.part['name'])
+#             self.tool.set_top(self.top)
+#             self.tool.paths = self.paths
+#             self.tool.files['vhdl'] = self.files['vhdl']
+#             self.tool.files['verilog'] = self.files['verilog']
+#             self.tool.params = self.params
+#             output1 = self.tool.generate('syn', 'prj', capture)
+#             output2 = super().generate(to_task, from_task, capture)
+#             return str(output1) + str(output2)
+#         return super().generate(to_task, from_task, capture)
+
+#     def transfer(self, devtype, position, part, width, capture):
+#         super().transfer(devtype, position, part, width, capture)
+#         temp = _TEMPLATES[devtype]
+#         if devtype not in ['detect', 'unlock']:
+#             temp = temp.replace('#BITSTREAM#', self.bitstream)
+#             temp = temp.replace('#POSITION#', str(position))
+#             temp = temp.replace('#NAME#', part)
+#             temp = temp.replace('#WIDTH#', str(width))
+#         with open('ise-prog.impact', 'w', encoding='utf-8') as file:
+#             file.write(temp)
+#         return run(self._TRF_COMMAND, capture)
+
+
+# def get_family(part):
+#     """Get the Family name from the specified part name."""
+#     part = part.lower()
+#     families = {
+#         r'xc7a\d+l': 'artix7l',
+#         r'xc7a': 'artix7',
+#         r'xc7k\d+l': 'kintex7l',
+#         r'xc7k': 'kintex7',
+#         r'xc3sd\d+a': 'spartan3adsp',
+#         r'xc3s\d+a': 'spartan3a',
+#         r'xc3s\d+e': 'spartan3e',
+#         r'xc3s': 'spartan3',
+#         r'xc6s\d+l': 'spartan6l',
+#         r'xc6s': 'spartan6',
+#         r'xc4v': 'virtex4',
+#         r'xc5v': 'virtex5',
+#         r'xc6v\d+l': 'virtex6l',
+#         r'xc6v': 'virtex6',
+#         r'xc7v\d+l': 'virtex7l',
+#         r'xc7v': 'virtex7',
+#         r'xc7z': 'zynq'
+#     }
+#     for key, value in families.items():
+#         if re.match(key, part):
+#             return value
+#     return 'UNKNOWN'
diff --git a/pyfpga/libero.py b/pyfpga/libero.py
index c037284c..5513698e 100644
--- a/pyfpga/libero.py
+++ b/pyfpga/libero.py
@@ -4,14 +4,13 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-"""fpga.tool.libero
-
-Implements the support of Libero (Microchip/Microsemi).
+"""
+Implements support for Libero.
 """
 
-import re
+# import re
 
-from fpga.tool import Tool
+from pyfpga.project import Project
 
 _TEMPLATES = {
     'fpga': """\
@@ -28,64 +27,72 @@
 # -clk_mode {free_running_clk} -programming_method {spi_slave} \
 # -force_freq {OFF} -freq {4000000}"
 
+# pylint: disable=too-few-public-methods
+
 
-class Libero(Tool):
-    """Implementation of the class to support Libero."""
+class Libero(Project):
+    """Class to support Libero."""
 
-    _TOOL = 'libero'
-    _EXTENSION = 'prjx'
-    _PART = 'mpf100t-1-fcg484'
-    _GEN_PROGRAM = 'libero'
-    _GEN_COMMAND = 'libero SCRIPT:libero.tcl'
-    _DEVTYPES = ['fpga']
-    _CLEAN = [
-        # directories
-        'libero',
-        # pyfpga
-        'libero.tcl'
-    ]
+    tool = {
+        'program': 'libero',
+        'command': 'libero SCRIPT:libero.tcl',
+    }
 
-    def set_part(self, part):
-        try:
-            device, speed, package = re.findall(r'(\w+)-(\w+)-*(\w*)', part)[0]
-            if len(speed) > len(package):
-                speed, package = package, speed
-            if speed == '':
-                speed = 'STD'
-            part = f'{device}-{speed}-{package}'
-        except IndexError:
-            raise ValueError(
-                'Part must be DEVICE-SPEED-PACKAGE or DEVICE-PACKAGE'
-            )
-        self.part['name'] = part
-        self.part['family'] = get_family(part)
-        self.part['device'] = device
-        self.part['package'] = package
-        self.part['speed'] = 'STD' if speed == 'STD' else '-' + speed
+#     _TOOL = 'libero'
+#     _EXTENSION = 'prjx'
+#     _PART = 'mpf100t-1-fcg484'
+#     _GEN_PROGRAM = 'libero'
+#     _GEN_COMMAND = 'libero SCRIPT:libero.tcl'
+#     _DEVTYPES = ['fpga']
+#     _CLEAN = [
+#         # directories
+#         'libero',
+#         # pyfpga
+#         'libero.tcl'
+#     ]
 
-    def transfer(self, devtype, position, part, width, capture):
-        super().transfer(devtype, position, part, width, capture)
-        raise NotImplementedError('transfer(libero)')
+#     def set_part(self, part):
+#         try:
+#             device, speed, package =
+#                 re.findall(r'(\w+)-(\w+)-*(\w*)', part)[0]
+#             if len(speed) > len(package):
+#                 speed, package = package, speed
+#             if speed == '':
+#                 speed = 'STD'
+#             part = f'{device}-{speed}-{package}'
+#         except IndexError:
+#             raise ValueError(
+#                 'Part must be DEVICE-SPEED-PACKAGE or DEVICE-PACKAGE'
+#             )
+#         self.part['name'] = part
+#         self.part['family'] = get_family(part)
+#         self.part['device'] = device
+#         self.part['package'] = package
+#         self.part['speed'] = 'STD' if speed == 'STD' else '-' + speed
 
+#     def transfer(self, devtype, position, part, width, capture):
+#         super().transfer(devtype, position, part, width, capture)
+#         raise NotImplementedError('transfer(libero)')
 
-def get_family(part):
-    """Get the Family name from the specified part name."""
-    part = part.lower()
-    families = {
-        r'm2s': 'SmartFusion2',
-        r'm2gl': 'Igloo2',
-        r'rt4g': 'RTG4',
-        r'mpf': 'PolarFire',
-        r'a2f': 'SmartFusion',
-        r'afs': 'Fusion',
-        r'aglp': 'IGLOO+',
-        r'agle': 'IGLOOE',
-        r'agl': 'IGLOO',
-        r'a3p\d+l': 'ProAsic3L',
-        r'a3pe': 'ProAsic3E',
-        r'a3p': 'ProAsic3'
-    }
-    for key, value in families.items():
-        if re.match(key, part):
-            return value
-    return 'UNKNOWN'
+
+# def get_family(part):
+#     """Get the Family name from the specified part name."""
+#     part = part.lower()
+#     families = {
+#         r'm2s': 'SmartFusion2',
+#         r'm2gl': 'Igloo2',
+#         r'rt4g': 'RTG4',
+#         r'mpf': 'PolarFire',
+#         r'a2f': 'SmartFusion',
+#         r'afs': 'Fusion',
+#         r'aglp': 'IGLOO+',
+#         r'agle': 'IGLOOE',
+#         r'agl': 'IGLOO',
+#         r'a3p\d+l': 'ProAsic3L',
+#         r'a3pe': 'ProAsic3E',
+#         r'a3p': 'ProAsic3'
+#     }
+#     for key, value in families.items():
+#         if re.match(key, part):
+#             return value
+#     return 'UNKNOWN'
diff --git a/pyfpga/openflow.py b/pyfpga/openflow.py
index b8207d58..b010ae40 100644
--- a/pyfpga/openflow.py
+++ b/pyfpga/openflow.py
@@ -4,203 +4,210 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-"""fpga.tool.openflow
-
-Implements the support of the open-source tools.
 """
+Implements support for an Open Source development flow.
+"""
+
+# import os
+from pyfpga.project import Project
+
+# pylint: disable=too-few-public-methods
 
-import os
-from fpga.tool import Tool, run
 
+class Openflow(Project):
+    """Class to support Openflow."""
 
-class Openflow(Tool):
-    """Implementation of the class to support the open-source tools."""
+    tool = {
+        'program': 'docker',
+        'command': 'bash openflow.sh',
+    }
 
-    _TOOL = 'openflow'
-    _PART = 'hx8k-ct256'
-    _GEN_PROGRAM = 'docker'
-    _GEN_COMMAND = 'bash openflow.sh'
-    _TRF_PROGRAM = 'docker'
-    _TRF_COMMAND = 'bash openprog.sh'
-    _BIT_EXT = ['bit']
-    _DEVTYPES = ['fpga']
-    _CLEAN = [
-        # files
-        '*.asc', '*.bit', '*.cf', '*.config', '*.edif', '*.json', '*.rpt',
-        '*.svf',
-        # pyfpga
-        '*.sh'
-    ]
+#     _TOOL = 'openflow'
+#     _PART = 'hx8k-ct256'
+#     _GEN_PROGRAM = 'docker'
+#     _GEN_COMMAND = 'bash openflow.sh'
+#     _TRF_PROGRAM = 'docker'
+#     _TRF_COMMAND = 'bash openprog.sh'
+#     _BIT_EXT = ['bit']
+#     _DEVTYPES = ['fpga']
+#     _CLEAN = [
+#         # files
+#         '*.asc', '*.bit', '*.cf', '*.config', '*.edif', '*.json', '*.rpt',
+#         '*.svf',
+#         # pyfpga
+#         '*.sh'
+#     ]
 
-    def __init__(self, project, frontend='yosys', backend='nextpnr'):
-        # The valid frontends are be ghdl and yosys
-        # The valid backends are:
-        # * For ghdl -> vhdl
-        # * For yosys -> ise, nextpnr, verilog, verilog-nosynth and vivado
-        super().__init__(project)
-        self.backend = backend
-        self.frontend = frontend
+#     def __init__(self, project, frontend='yosys', backend='nextpnr'):
+#         # The valid frontends are be ghdl and yosys
+#         # The valid backends are:
+#         # * For ghdl -> vhdl
+#         # * For yosys -> ise, nextpnr, verilog, verilog-nosynth and vivado
+#         super().__init__(project)
+#         self.backend = backend
+#         self.frontend = frontend
 
-    def _configure(self):
-        super()._configure()
-        # OCI ENGINE
-        engine = self.configs.get('oci', {}).get('engine', {})
-        command = engine.get('command', 'docker') + ' run --rm'
-        volumes = '-v ' + ('-v ').join(engine.get('volumes', ['$HOME:$HOME']))
-        work = '-w ' + engine.get('work', '$PWD')
-        self.oci_engine = f'{command} {volumes} {work}'
-        # Containers
-        defaults = {
-            'ghdl': 'ghdl/synth:beta',
-            'yosys': 'ghdl/synth:beta',
-            'nextpnr-ice40': 'ghdl/synth:nextpnr-ice40',
-            'icetime': 'ghdl/synth:icestorm',
-            'icepack': 'ghdl/synth:icestorm',
-            'iceprog': '--device /dev/bus/usb ghdl/synth:prog',
-            'nextpnr-ecp5': 'ghdl/synth:nextpnr-ecp5',
-            'ecppack': 'ghdl/synth:trellis',
-            'openocd': '--device /dev/bus/usb ghdl/synth:prog'
-        }
-        self.tools = {}
-        self.conts = {}
-        tools = self.configs.get('tools', {})
-        containers = self.configs.get('oci', {}).get('containers', {})
-        for tool, container in defaults.items():
-            self.tools[tool] = tools.get(tool, tool)
-            self.conts[tool] = containers.get(tool, container)
+#     def _configure(self):
+#         super()._configure()
+#         # OCI ENGINE
+#         engine = self.configs.get('oci', {}).get('engine', {})
+#         command = engine.get('command', 'docker') + ' run --rm'
+#         volumes =
+#             '-v ' + ('-v ').join(engine.get('volumes', ['$HOME:$HOME']))
+#         work = '-w ' + engine.get('work', '$PWD')
+#         self.oci_engine = f'{command} {volumes} {work}'
+#         # Containers
+#         defaults = {
+#             'ghdl': 'ghdl/synth:beta',
+#             'yosys': 'ghdl/synth:beta',
+#             'nextpnr-ice40': 'ghdl/synth:nextpnr-ice40',
+#             'icetime': 'ghdl/synth:icestorm',
+#             'icepack': 'ghdl/synth:icestorm',
+#             'iceprog': '--device /dev/bus/usb ghdl/synth:prog',
+#             'nextpnr-ecp5': 'ghdl/synth:nextpnr-ecp5',
+#             'ecppack': 'ghdl/synth:trellis',
+#             'openocd': '--device /dev/bus/usb ghdl/synth:prog'
+#         }
+#         self.tools = {}
+#         self.conts = {}
+#         tools = self.configs.get('tools', {})
+#         containers = self.configs.get('oci', {}).get('containers', {})
+#         for tool, container in defaults.items():
+#             self.tools[tool] = tools.get(tool, tool)
+#             self.conts[tool] = containers.get(tool, container)
 
-    def set_part(self, part):
-        self.part['name'] = part
-        self.part['family'] = get_family(part)
-        if self.part['family'] in ['ice40', 'ecp5']:
-            aux = part.split('-')
-            if len(aux) == 2:
-                self.part['device'] = aux[0]
-                self.part['package'] = aux[1]
-            elif len(aux) == 3:
-                self.part['device'] = f'{aux[0]}-{aux[1]}'
-                self.part['package'] = aux[2]
-            else:
-                raise ValueError('Part must be DEVICE-PACKAGE')
-            if self.part['device'].endswith('4k'):
-                # See http://www.clifford.at/icestorm/
-                self.part['device'] = self.part['device'].replace('4', '8')
-                self.part['package'] += ":4k"
+#     def set_part(self, part):
+#         self.part['name'] = part
+#         self.part['family'] = get_family(part)
+#         if self.part['family'] in ['ice40', 'ecp5']:
+#             aux = part.split('-')
+#             if len(aux) == 2:
+#                 self.part['device'] = aux[0]
+#                 self.part['package'] = aux[1]
+#             elif len(aux) == 3:
+#                 self.part['device'] = f'{aux[0]}-{aux[1]}'
+#                 self.part['package'] = aux[2]
+#             else:
+#                 raise ValueError('Part must be DEVICE-PACKAGE')
+#             if self.part['device'].endswith('4k'):
+#                 # See http://www.clifford.at/icestorm/
+#                 self.part['device'] = self.part['device'].replace('4', '8')
+#                 self.part['package'] += ":4k"
 
-    def _create_gen_script(self, tasks):
-        # Verilog includes
-        paths = []
-        for path in self.paths:
-            paths.append(f'verilog_defaults -add -I{path}')
-        # Files
-        constraints = []
-        verilogs = []
-        vhdls = []
-        for file in self.files['vhdl']:
-            lib = ''
-            if file[1] is not None:
-                lib = f'--work={file[1]}'
-            vhdls.append(f'{self.tools["ghdl"]} -a $FLAGS {lib} {file[0]}')
-        for file in self.files['verilog']:
-            if file[0].endswith('.sv'):
-                verilogs.append(f'read_verilog -sv -defer {file[0]}')
-            else:
-                verilogs.append(f'read_verilog -defer {file[0]}')
-        for file in self.files['constraint']:
-            constraints.append(file[0])
-        if len(vhdls) > 0:
-            verilogs = [f'ghdl $FLAGS {self.top}']
-        # Parameters
-        params = []
-        for param in self.params:
-            params.append(f'chparam -set {param[0]} {param[1]} {self.top}')
-        # Script creation
-        template = os.path.join(os.path.dirname(__file__), 'template.sh')
-        with open(template, 'r', encoding='utf-8') as file:
-            text = file.read()
-        text = text.format(
-            backend=self.backend,
-            constraints='\\\n'+'\n'.join(constraints),
-            device=self.part['device'],
-            includes='\\\n'+'\n'.join(paths),
-            family=self.part['family'],
-            frontend=self.frontend,
-            package=self.part['package'],
-            params='\\\n'+'\n'.join(params),
-            project=self.project,
-            tasks=tasks,
-            top=self.top,
-            verilogs='\\\n'+'\n'.join(verilogs),
-            vhdls='\\\n'+'\n'.join(vhdls),
-            #
-            oci_engine=self.oci_engine,
-            cont_ghdl=self.conts['ghdl'],
-            cont_yosys=self.conts['yosys'],
-            cont_nextpnr_ice40=self.conts['nextpnr-ice40'],
-            cont_icetime=self.conts['icetime'],
-            cont_icepack=self.conts['icepack'],
-            cont_nextpnr_ecp5=self.conts['nextpnr-ecp5'],
-            cont_ecppack=self.conts['ecppack'],
-            tool_ghdl=self.tools['ghdl'],
-            tool_yosys=self.tools['yosys'],
-            tool_nextpnr_ice40=self.tools['nextpnr-ice40'],
-            tool_icetime=self.tools['icetime'],
-            tool_icepack=self.tools['icepack'],
-            tool_nextpnr_ecp5=self.tools['nextpnr-ecp5'],
-            tool_ecppack=self.tools['ecppack']
-        )
-        with open(f'{self._TOOL}.sh', 'w', encoding='utf-8') as file:
-            file.write(text)
+#     def _create_gen_script(self, tasks):
+#         # Verilog includes
+#         paths = []
+#         for path in self.paths:
+#             paths.append(f'verilog_defaults -add -I{path}')
+#         # Files
+#         constraints = []
+#         verilogs = []
+#         vhdls = []
+#         for file in self.files['vhdl']:
+#             lib = ''
+#             if file[1] is not None:
+#                 lib = f'--work={file[1]}'
+#             vhdls.append(f'{self.tools["ghdl"]} -a $FLAGS {lib} {file[0]}')
+#         for file in self.files['verilog']:
+#             if file[0].endswith('.sv'):
+#                 verilogs.append(f'read_verilog -sv -defer {file[0]}')
+#             else:
+#                 verilogs.append(f'read_verilog -defer {file[0]}')
+#         for file in self.files['constraint']:
+#             constraints.append(file[0])
+#         if len(vhdls) > 0:
+#             verilogs = [f'ghdl $FLAGS {self.top}']
+#         # Parameters
+#         params = []
+#         for param in self.params:
+#             params.append(f'chparam -set {param[0]} {param[1]} {self.top}')
+#         # Script creation
+#         template = os.path.join(os.path.dirname(__file__), 'template.sh')
+#         with open(template, 'r', encoding='utf-8') as file:
+#             text = file.read()
+#         text = text.format(
+#             backend=self.backend,
+#             constraints='\\\n'+'\n'.join(constraints),
+#             device=self.part['device'],
+#             includes='\\\n'+'\n'.join(paths),
+#             family=self.part['family'],
+#             frontend=self.frontend,
+#             package=self.part['package'],
+#             params='\\\n'+'\n'.join(params),
+#             project=self.project,
+#             tasks=tasks,
+#             top=self.top,
+#             verilogs='\\\n'+'\n'.join(verilogs),
+#             vhdls='\\\n'+'\n'.join(vhdls),
+#             #
+#             oci_engine=self.oci_engine,
+#             cont_ghdl=self.conts['ghdl'],
+#             cont_yosys=self.conts['yosys'],
+#             cont_nextpnr_ice40=self.conts['nextpnr-ice40'],
+#             cont_icetime=self.conts['icetime'],
+#             cont_icepack=self.conts['icepack'],
+#             cont_nextpnr_ecp5=self.conts['nextpnr-ecp5'],
+#             cont_ecppack=self.conts['ecppack'],
+#             tool_ghdl=self.tools['ghdl'],
+#             tool_yosys=self.tools['yosys'],
+#             tool_nextpnr_ice40=self.tools['nextpnr-ice40'],
+#             tool_icetime=self.tools['icetime'],
+#             tool_icepack=self.tools['icepack'],
+#             tool_nextpnr_ecp5=self.tools['nextpnr-ecp5'],
+#             tool_ecppack=self.tools['ecppack']
+#         )
+#         with open(f'{self._TOOL}.sh', 'w', encoding='utf-8') as file:
+#             file.write(text)
 
-    def generate(self, to_task, from_task, capture):
-        if self.frontend == 'ghdl' or 'verilog' in self.backend:
-            to_task = 'syn'
-            from_task = 'syn'
-        return super().generate(to_task, from_task, capture)
+#     def generate(self, to_task, from_task, capture):
+#         if self.frontend == 'ghdl' or 'verilog' in self.backend:
+#             to_task = 'syn'
+#             from_task = 'syn'
+#         return super().generate(to_task, from_task, capture)
 
-    def transfer(self, devtype, position, part, width, capture):
-        super().transfer(devtype, position, part, width, capture)
-        template = os.path.join(os.path.dirname(__file__), 'openprog.sh')
-        with open(template, 'r', encoding='utf-8') as file:
-            text = file.read()
-        text = text.format(
-            family=self.part['family'],
-            project=self.project,
-            #
-            oci_engine=self.oci_engine,
-            cont_iceprog=self.conts['iceprog'],
-            cont_openocd=self.conts['openocd'],
-            tool_iceprog=self.tools['iceprog'],
-            tool_openocd=self.tools['openocd']
-        )
-        with open('openprog.sh', 'w', encoding='utf-8') as file:
-            file.write(text)
-        return run(self._TRF_COMMAND, capture)
+#     def transfer(self, devtype, position, part, width, capture):
+#         super().transfer(devtype, position, part, width, capture)
+#         template = os.path.join(os.path.dirname(__file__), 'openprog.sh')
+#         with open(template, 'r', encoding='utf-8') as file:
+#             text = file.read()
+#         text = text.format(
+#             family=self.part['family'],
+#             project=self.project,
+#             #
+#             oci_engine=self.oci_engine,
+#             cont_iceprog=self.conts['iceprog'],
+#             cont_openocd=self.conts['openocd'],
+#             tool_iceprog=self.tools['iceprog'],
+#             tool_openocd=self.tools['openocd']
+#         )
+#         with open('openprog.sh', 'w', encoding='utf-8') as file:
+#             file.write(text)
+#         return run(self._TRF_COMMAND, capture)
 
 
-def get_family(part):
-    """Get the Family name from the specified part name."""
-    part = part.lower()
-    families = [
-        # From <YOSYS>/techlibs/xilinx/synth_xilinx.cc
-        'xcup', 'xcu', 'xc7', 'xc6s', 'xc6v', 'xc5v', 'xc4v', 'xc3sda',
-        'xc3sa', 'xc3se', 'xc3s', 'xc2vp', 'xc2v', 'xcve', 'xcv'
-    ]
-    for family in families:
-        if part.startswith(family):
-            return family
-    families = [
-        # From <nextpnr>/ice40/main.cc
-        'lp384', 'lp1k', 'lp4k', 'lp8k', 'hx1k', 'hx4k', 'hx8k',
-        'up3k', 'up5k', 'u1k', 'u2k', 'u4k'
-    ]
-    if part.startswith(tuple(families)):
-        return 'ice40'
-    families = [
-        # From <nextpnr>/ecp5/main.cc
-        '12k', '25k', '45k', '85k', 'um-25k', 'um-45k', 'um-85k',
-        'um5g-25k', 'um5g-45k', 'um5g-85k'
-    ]
-    if part.startswith(tuple(families)):
-        return 'ecp5'
-    return 'UNKNOWN'
+# def get_family(part):
+#     """Get the Family name from the specified part name."""
+#     part = part.lower()
+#     families = [
+#         # From <YOSYS>/techlibs/xilinx/synth_xilinx.cc
+#         'xcup', 'xcu', 'xc7', 'xc6s', 'xc6v', 'xc5v', 'xc4v', 'xc3sda',
+#         'xc3sa', 'xc3se', 'xc3s', 'xc2vp', 'xc2v', 'xcve', 'xcv'
+#     ]
+#     for family in families:
+#         if part.startswith(family):
+#             return family
+#     families = [
+#         # From <nextpnr>/ice40/main.cc
+#         'lp384', 'lp1k', 'lp4k', 'lp8k', 'hx1k', 'hx4k', 'hx8k',
+#         'up3k', 'up5k', 'u1k', 'u2k', 'u4k'
+#     ]
+#     if part.startswith(tuple(families)):
+#         return 'ice40'
+#     families = [
+#         # From <nextpnr>/ecp5/main.cc
+#         '12k', '25k', '45k', '85k', 'um-25k', 'um-45k', 'um-85k',
+#         'um5g-25k', 'um5g-45k', 'um5g-85k'
+#     ]
+#     if part.startswith(tuple(families)):
+#         return 'ecp5'
+#     return 'UNKNOWN'
diff --git a/pyfpga/quartus.py b/pyfpga/quartus.py
index 94db6ad6..9c6c861e 100644
--- a/pyfpga/quartus.py
+++ b/pyfpga/quartus.py
@@ -4,50 +4,54 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-"""fpga.tool.quartus
-
-Implements the support of Quartus (Intel/Altera).
+"""
+Implements support for Quartus.
 """
 
-import re
-import subprocess
-
-from fpga.tool import Tool, run
-
-
-class Quartus(Tool):
-    """Implementation of the class to support Quartus."""
-
-    _TOOL = 'quartus'
-    _EXTENSION = 'qpf'
-    _PART = '10cl120zf780i8g'
-    _GEN_PROGRAM = 'quartus_sh'
-    _GEN_COMMAND = 'quartus_sh --script quartus.tcl'
-    _TRF_PROGRAM = 'quartus_pgm'
-    _TRF_COMMAND = 'quartus_pgm -c %s --mode jtag -o "p;%s@%s"'
-    _BIT_EXT = ['sof', 'pof']
-    _DEVTYPES = ['fpga', 'detect']
-    _CLEAN = [
-        # directories
-        'db', 'incremental_db', 'output_files',
-        # files
-        '*.done', '*.jdi', '*.log', '*.pin', '*.pof', '*.qws', '*.rpt',
-        '*.smsg', '*.sld', '*.sof', '*.sop', '*.summary', '*.txt',
-        # pyfpga
-        'quartus.tcl'
-    ]
-
-    def transfer(self, devtype, position, part, width, capture):
-        super().transfer(devtype, position, part, width, capture)
-        result = subprocess.run(
-            'jtagconfig', shell=True, check=True,
-            stdout=subprocess.PIPE, universal_newlines=True
-        )
-        result = result.stdout
-        if devtype == 'detect':
-            print(result)
-        else:
-            cable = re.match(r"1\) (.*) \[", result).groups()[0]
-            cmd = self._TRF_COMMAND % (cable, self.bitstream, position)
-            result = run(cmd, capture)
-        return result
+# import re
+# import subprocess
+
+from pyfpga.project import Project
+
+
+class Quartus(Project):
+    """Class to support Quartus."""
+
+    tool = {
+        'program': 'quartus_sh',
+        'command': 'quartus_sh --script quartus.tcl',
+    }
+
+#     _TOOL = 'quartus'
+#     _EXTENSION = 'qpf'
+#     _PART = '10cl120zf780i8g'
+#     _GEN_PROGRAM = 'quartus_sh'
+#     _GEN_COMMAND = 'quartus_sh --script quartus.tcl'
+#     _TRF_PROGRAM = 'quartus_pgm'
+#     _TRF_COMMAND = 'quartus_pgm -c %s --mode jtag -o "p;%s@%s"'
+#     _BIT_EXT = ['sof', 'pof']
+#     _DEVTYPES = ['fpga', 'detect']
+#     _CLEAN = [
+#         # directories
+#         'db', 'incremental_db', 'output_files',
+#         # files
+#         '*.done', '*.jdi', '*.log', '*.pin', '*.pof', '*.qws', '*.rpt',
+#         '*.smsg', '*.sld', '*.sof', '*.sop', '*.summary', '*.txt',
+#         # pyfpga
+#         'quartus.tcl'
+#     ]
+
+#     def transfer(self, devtype, position, part, width, capture):
+#         super().transfer(devtype, position, part, width, capture)
+#         result = subprocess.run(
+#             'jtagconfig', shell=True, check=True,
+#             stdout=subprocess.PIPE, universal_newlines=True
+#         )
+#         result = result.stdout
+#         if devtype == 'detect':
+#             print(result)
+#         else:
+#             cable = re.match(r"1\) (.*) \[", result).groups()[0]
+#             cmd = self._TRF_COMMAND % (cable, self.bitstream, position)
+#             result = run(cmd, capture)
+#         return result
diff --git a/pyfpga/tool.py b/pyfpga/tool.py
index f02931a3..19a756d4 100644
--- a/pyfpga/tool.py
+++ b/pyfpga/tool.py
@@ -9,40 +9,17 @@
 Defines the interface to be inherited to support a tool.
 """
 
-from glob import glob
-import os
-import subprocess
-from shutil import rmtree, which
-from yaml import safe_load
-
 
 FILETYPES = ['verilog', 'vhdl', 'constraint', 'design']
 MEMWIDTHS = [1, 2, 4, 8, 16, 32]
 PHASES = ['prefile', 'project', 'preflow', 'postsyn', 'postpar', 'postbit']
 TASKS = ['prj', 'syn', 'par', 'bit']
 
+# def tcl_path(path):
+#     """Returns a Tcl suitable path."""
+#     return path.replace(os.path.sep, "/")
 
-def check_value(value, values):
-    """Check if VALUE is included in VALUES."""
-    if value not in values:
-        joined_values = ", ".join(values)
-        raise ValueError(f'{value} is not a valid value [{joined_values}]')
-
-
-def run(command, capture):
-    """Run a command."""
-    output = subprocess.PIPE if capture else None
-    check = not capture
-    result = subprocess.run(
-        command, shell=True, check=check, universal_newlines=True,
-        stdout=output, stderr=subprocess.STDOUT
-    )
-    return result.stdout
-
-
-def tcl_path(path):
-    """Returns a Tcl suitable path."""
-    return path.replace(os.path.sep, "/")
+# pylint: disable=too-few-public-methods
 
 
 class Tool:
@@ -51,195 +28,152 @@ class Tool:
     It is the basic interface for tool implementations.
     """
 
-    # Following variables are set in each inheritance (if employed)
-    _TOOL = None         # tool name
-    _EXTENSION = None    # project file extension
-    _PART = None         # default device part name
-    _GEN_PROGRAM = None  # program used when generate is executed
-    _GEN_COMMAND = None  # command to run when generate is executed
-    _TRF_PROGRAM = None  # program used when transfer is executed
-    _TRF_COMMAND = None  # command to run when transfer is executed
-    _BIT_EXT = []        # Supported BITstream EXTensions
-    _DEVTYPES = []       # Supported DEVice TYPES
-    _CLEAN = []          # Files to be CLEAN
-
-    def __init__(self, project):
-        """Initializes the attributes of the class."""
-        self.bitstream = None
-        self.cmds = {
-            'prefile': [],
-            'project': [],
-            'preflow': [],
-            'postsyn': [],
-            'postpar': [],
-            'postbit': []
-        }
-        self.files = {
-            'vhdl': [],
-            'verilog': [],
-            'constraint': [],
-            'design': []
-        }
-        self.params = []
-        self.part = {
-            'name': 'UNSET',
-            'family': 'UNSET',
-            'device': 'UNSET',
-            'package': 'UNSET',
-            'speed': 'UNSET'
-        }
-        self.paths = []
-        self.presynth = False
-        self.project = self._TOOL if project is None else project
-        self.set_part(self._PART)
-        self.set_top('UNDEFINED')
-        self._configure()
-
-    def _configure(self):
-        """Configures the underlying tools."""
-        filename = '.pyfpga.yml'
-        self.configs = {}
-        if os.path.exists(filename):
-            with open(filename, 'r', encoding='utf-8') as file:
-                data = safe_load(file)
-                if self._TOOL in data:
-                    self.configs = data[self._TOOL]
-
-    def get_configs(self):
-        """Get Configurations."""
-        return {
-            'tool': self._TOOL,
-            'project': self.project,
-            'extension': self._EXTENSION,
-            'part': self.part['name']
-        }
-
-    def set_part(self, part):
-        """Set the target PART."""
-        self.part['name'] = part
-
-    def add_param(self, name, value):
-        """Add a Generic/Parameter Value."""
-        self.params.append([name, value])
-
-    def add_file(self, file, filetype, library, options):
-        """Add a file to the project of the specified **type**."""
-        check_value(filetype, FILETYPES)
-        self.files[filetype].append([file, library, options])
-
-    def get_files(self):
-        """Get the files of the project."""
-        return self.files
-
-    def add_vlog_include(self, path):
-        """Add a Verilog include path."""
-        self.paths.append(path)
-
-    def set_top(self, top):
-        """Set the TOP LEVEL of the project."""
-        self.top = top
-
-    def add_hook(self, hook, phase):
-        """Add the specified *hook* in the desired *phase*."""
-        check_value(phase, PHASES)
-        self.cmds[phase].append(hook)
-
-    def _create_gen_script(self, tasks):
-        """Create the script for generate execution."""
-        # Paths and files
-        files = []
-        if self.presynth:
-            files.append(f'    fpga_file {self.project}.edif')
-        else:
-            for path in self.paths:
-                files.append(f'    fpga_include {tcl_path(path)}')
-            for file in self.files['verilog']:
-                files.append(f'    fpga_file {tcl_path(file[0])}')
-            for file in self.files['vhdl']:
-                if file[1] is None:
-                    files.append(f'    fpga_file {tcl_path(file[0])}')
-                else:
-                    files.append(
-                        f'    fpga_file {tcl_path(file[0])} {file[1]}'
-                    )
-        for file in self.files['design']:
-            files.append(f'    fpga_design {tcl_path(file[0])}')
-        for file in self.files['constraint']:
-            files.append(f'    fpga_file {tcl_path(file[0])}')
-        # Parameters
-        params = []
-        for param in self.params:
-            params.append(f'{{ {param[0]} {param[1]} }}')
-        # Script creation
-        template = os.path.join(os.path.dirname(__file__), 'template.tcl')
-        with open(template, 'r', encoding='utf-8') as file:
-            tcl = file.read()
-        tcl = tcl.replace('#TOOL#', self._TOOL)
-        tcl = tcl.replace('#PRESYNTH#', "True" if self.presynth else "False")
-        tcl = tcl.replace('#PROJECT#', self.project)
-        tcl = tcl.replace('#PART#', self.part['name'])
-        tcl = tcl.replace('#FAMILY#', self.part['family'])
-        tcl = tcl.replace('#DEVICE#', self.part['device'])
-        tcl = tcl.replace('#PACKAGE#', self.part['package'])
-        tcl = tcl.replace('#SPEED#', self.part['speed'])
-        tcl = tcl.replace('#PARAMS#', ' '.join(params))
-        tcl = tcl.replace('#FILES#', '\n'.join(files))
-        tcl = tcl.replace('#TOP#', self.top)
-        tcl = tcl.replace('#TASKS#', tasks)
-        tcl = tcl.replace('#PREFILE_CMDS#', '\n'.join(self.cmds['prefile']))
-        tcl = tcl.replace('#PROJECT_CMDS#', '\n'.join(self.cmds['project']))
-        tcl = tcl.replace('#PREFLOW_CMDS#', '\n'.join(self.cmds['preflow']))
-        tcl = tcl.replace('#POSTSYN_CMDS#', '\n'.join(self.cmds['postsyn']))
-        tcl = tcl.replace('#POSTPAR_CMDS#', '\n'.join(self.cmds['postpar']))
-        tcl = tcl.replace('#POSTBIT_CMDS#', '\n'.join(self.cmds['postbit']))
-        with open(f'{self._TOOL}.tcl', 'w', encoding='utf-8') as file:
-            file.write(tcl)
-
-    def generate(self, to_task, from_task, capture):
-        """Run the FPGA tool."""
-        check_value(to_task, TASKS)
-        check_value(from_task, TASKS)
-        to_index = TASKS.index(to_task)
-        from_index = TASKS.index(from_task)
-        if from_index > to_index:
-            raise ValueError(
-                f'initial task "{from_task}" cannot be later than the ' +
-                f'last task "{to_task}"'
-            )
-        tasks = " ".join(TASKS[from_index:to_index+1])
-        self._create_gen_script(tasks)
-        if not which(self._GEN_PROGRAM):
-            raise RuntimeError(f'program "{self._GEN_PROGRAM}" not found')
-        return run(self._GEN_COMMAND, capture)
-
-    def set_bitstream(self, path):
-        """Set the bitstream file to transfer."""
-        self.bitstream = path
-
-    def transfer(self, devtype, position, part, width, capture):
-        """Transfer a bitstream."""
-        if not which(self._TRF_PROGRAM):
-            raise RuntimeError(f'program "{self._TRF_PROGRAM}" not found')
-        check_value(devtype, self._DEVTYPES)
-        check_value(position, range(10))
-        isinstance(part, str)
-        check_value(width, MEMWIDTHS)
-        isinstance(capture, bool)
-        # Bitstream autodiscovery
-        if not self.bitstream and devtype not in ['detect', 'unlock']:
-            bitstream = []
-            for ext in self._BIT_EXT:
-                bitstream.extend(glob(f'**/*.{ext}', recursive=True))
-            if len(bitstream) == 0:
-                raise FileNotFoundError('bitStream not found')
-            self.bitstream = bitstream[0]
-
-    def clean(self):
-        """Clean the generated project files."""
-        for path in self._CLEAN:
-            elements = glob(path)
-            for element in elements:
-                if os.path.isfile(element):
-                    os.remove(element)
-                else:
-                    rmtree(element)
+#     # Following variables are set in each inheritance (if employed)
+#     _TOOL = None         # tool name
+#     _EXTENSION = None    # project file extension
+#     _PART = None         # default device part name
+#     _GEN_PROGRAM = None  # program used when generate is executed
+#     _GEN_COMMAND = None  # command to run when generate is executed
+#     _TRF_PROGRAM = None  # program used when transfer is executed
+#     _TRF_COMMAND = None  # command to run when transfer is executed
+#     _BIT_EXT = []        # Supported BITstream EXTensions
+#     _DEVTYPES = []       # Supported DEVice TYPES
+#     _CLEAN = []          # Files to be CLEAN
+
+#     def __init__(self, project):
+#         """Initializes the attributes of the class."""
+#         self.bitstream = None
+#         self.cmds = {
+#             'prefile': [],
+#             'project': [],
+#             'preflow': [],
+#             'postsyn': [],
+#             'postpar': [],
+#             'postbit': []
+#         }
+#         self.files = {
+#             'vhdl': [],
+#             'verilog': [],
+#             'constraint': [],
+#             'design': []
+#         }
+#         self.params = []
+#         self.part = {
+#             'name': 'UNSET',
+#             'family': 'UNSET',
+#             'device': 'UNSET',
+#             'package': 'UNSET',
+#             'speed': 'UNSET'
+#         }
+#         self.paths = []
+#         self.presynth = False
+#         self.project = self._TOOL if project is None else project
+#         self.set_part(self._PART)
+#         self.set_top('UNDEFINED')
+#         self._configure()
+
+#     def _configure(self):
+#         """Configures the underlying tools."""
+#         filename = '.pyfpga.yml'
+#         self.configs = {}
+#         if os.path.exists(filename):
+#             with open(filename, 'r', encoding='utf-8') as file:
+#                 data = safe_load(file)
+#                 if self._TOOL in data:
+#                     self.configs = data[self._TOOL]
+
+#     def _create_gen_script(self, tasks):
+#         """Create the script for generate execution."""
+#         # Paths and files
+#         files = []
+#         if self.presynth:
+#             files.append(f'    fpga_file {self.project}.edif')
+#         else:
+#             for path in self.paths:
+#                 files.append(f'    fpga_include {tcl_path(path)}')
+#             for file in self.files['verilog']:
+#                 files.append(f'    fpga_file {tcl_path(file[0])}')
+#             for file in self.files['vhdl']:
+#                 if file[1] is None:
+#                     files.append(f'    fpga_file {tcl_path(file[0])}')
+#                 else:
+#                     files.append(
+#                         f'    fpga_file {tcl_path(file[0])} {file[1]}'
+#                     )
+#         for file in self.files['design']:
+#             files.append(f'    fpga_design {tcl_path(file[0])}')
+#         for file in self.files['constraint']:
+#             files.append(f'    fpga_file {tcl_path(file[0])}')
+#         # Parameters
+#         params = []
+#         for param in self.params:
+#             params.append(f'{{ {param[0]} {param[1]} }}')
+#         # Script creation
+#         template = os.path.join(os.path.dirname(__file__), 'template.tcl')
+#         with open(template, 'r', encoding='utf-8') as file:
+#             tcl = file.read()
+#         tcl = tcl.replace('#TOOL#', self._TOOL)
+#         tcl = tcl.replace('#PRESYNTH#', "True" if self.presynth else "False")
+#         tcl = tcl.replace('#PROJECT#', self.project)
+#         tcl = tcl.replace('#PART#', self.part['name'])
+#         tcl = tcl.replace('#FAMILY#', self.part['family'])
+#         tcl = tcl.replace('#DEVICE#', self.part['device'])
+#         tcl = tcl.replace('#PACKAGE#', self.part['package'])
+#         tcl = tcl.replace('#SPEED#', self.part['speed'])
+#         tcl = tcl.replace('#PARAMS#', ' '.join(params))
+#         tcl = tcl.replace('#FILES#', '\n'.join(files))
+#         tcl = tcl.replace('#TOP#', self.top)
+#         tcl = tcl.replace('#TASKS#', tasks)
+#         tcl = tcl.replace('#PREFILE_CMDS#', '\n'.join(self.cmds['prefile']))
+#         tcl = tcl.replace('#PROJECT_CMDS#', '\n'.join(self.cmds['project']))
+#         tcl = tcl.replace('#PREFLOW_CMDS#', '\n'.join(self.cmds['preflow']))
+#         tcl = tcl.replace('#POSTSYN_CMDS#', '\n'.join(self.cmds['postsyn']))
+#         tcl = tcl.replace('#POSTPAR_CMDS#', '\n'.join(self.cmds['postpar']))
+#         tcl = tcl.replace('#POSTBIT_CMDS#', '\n'.join(self.cmds['postbit']))
+#         with open(f'{self._TOOL}.tcl', 'w', encoding='utf-8') as file:
+#             file.write(tcl)
+
+#     def generate(self, to_task, from_task, capture):
+#         """Run the FPGA tool."""
+#         check_value(to_task, TASKS)
+#         check_value(from_task, TASKS)
+#         to_index = TASKS.index(to_task)
+#         from_index = TASKS.index(from_task)
+#         if from_index > to_index:
+#             raise ValueError(
+#                 f'initial task "{from_task}" cannot be later than the ' +
+#                 f'last task "{to_task}"'
+#             )
+#         tasks = " ".join(TASKS[from_index:to_index+1])
+#         self._create_gen_script(tasks)
+#         if not which(self._GEN_PROGRAM):
+#             raise RuntimeError(f'program "{self._GEN_PROGRAM}" not found')
+#         return run(self._GEN_COMMAND, capture)
+
+#     def transfer(self, devtype, position, part, width, capture):
+#         """Transfer a bitstream."""
+#         if not which(self._TRF_PROGRAM):
+#             raise RuntimeError(f'program "{self._TRF_PROGRAM}" not found')
+#         check_value(devtype, self._DEVTYPES)
+#         check_value(position, range(10))
+#         isinstance(part, str)
+#         check_value(width, MEMWIDTHS)
+#         isinstance(capture, bool)
+#         # Bitstream autodiscovery
+#         if not self.bitstream and devtype not in ['detect', 'unlock']:
+#             bitstream = []
+#             for ext in self._BIT_EXT:
+#                 bitstream.extend(glob(f'**/*.{ext}', recursive=True))
+#             if len(bitstream) == 0:
+#                 raise FileNotFoundError('bitStream not found')
+#             self.bitstream = bitstream[0]
+
+#     def clean(self):
+#         """Clean the generated project files."""
+#         for path in self._CLEAN:
+#             elements = glob(path)
+#             for element in elements:
+#                 if os.path.isfile(element):
+#                     os.remove(element)
+#                 else:
+#                     rmtree(element)
diff --git a/pyfpga/vivado.py b/pyfpga/vivado.py
index 24cd2ae9..46008024 100644
--- a/pyfpga/vivado.py
+++ b/pyfpga/vivado.py
@@ -4,12 +4,11 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-"""fpga.tool.vivado
-
-Implements the support of Vivado (Xilinx).
+"""
+Implements support for Vivado.
 """
 
-from fpga.tool import Tool, run
+from pyfpga.project import Project
 
 _TEMPLATES = {
     'fpga': """\
@@ -28,58 +27,66 @@
 """
 }
 
+# pylint: disable=too-few-public-methods
+
+
+class Vivado(Project):
+    """Class to support Vivado."""
 
-class Vivado(Tool):
-    """Implementation of the class to support Vivado."""
+    tool = {
+        'program': 'vivado',
+        'command': 'vivado -mode batch -notrace -quiet -source vivado.tcl',
+    }
 
-    _TOOL = 'vivado'
-    _EXTENSION = 'xpr'
-    _PART = 'xc7k160t-3-fbg484'
-    _GEN_PROGRAM = 'vivado'
-    _GEN_COMMAND = 'vivado -mode batch -notrace -quiet -source vivado.tcl'
-    _TRF_PROGRAM = 'vivado'
-    _TRF_COMMAND = 'vivado -mode batch -notrace -quiet -source vivado-prog.tcl'
-    _BIT_EXT = ['bit']
-    _DEVTYPES = ['fpga', 'detect']
-    _CLEAN = [
-        # directories
-        '*.cache', '*.hw', '*.ip_user_files', '*.runs', '*.sim', '.Xil',
-        # files
-        '*.bit', '*.jou', '*.log', '*.rpt', 'vivado_*.zip',
-        # pyfpga
-        'vivado.tcl', 'vivado-prog.tcl'
-    ]
+#     _TOOL = 'vivado'
+#     _EXTENSION = 'xpr'
+#     _PART = 'xc7k160t-3-fbg484'
+#     _GEN_PROGRAM = 'vivado'
+#     _GEN_COMMAND = 'vivado -mode batch -notrace -quiet -source vivado.tcl'
+#     _TRF_PROGRAM = 'vivado'
+#     _TRF_COMMAND =
+#         'vivado -mode batch -notrace -quiet -source vivado-prog.tcl'
+#     _BIT_EXT = ['bit']
+#     _DEVTYPES = ['fpga', 'detect']
+#     _CLEAN = [
+#         # directories
+#         '*.cache', '*.hw', '*.ip_user_files', '*.runs', '*.sim', '.Xil',
+#         # files
+#         '*.bit', '*.jou', '*.log', '*.rpt', 'vivado_*.zip',
+#         # pyfpga
+#         'vivado.tcl', 'vivado-prog.tcl'
+#     ]
 
-    def __init__(self, project, frontend=None):
-        super().__init__(project)
-        if frontend == 'yosys':
-            from fpga.tool.openflow import Openflow
-            self.tool = Openflow(
-                self.project,
-                frontend='yosys',
-                backend='vivado'
-            )
-            self.presynth = True
+#     def __init__(self, project, frontend=None):
+#         super().__init__(project)
+#         if frontend == 'yosys':
+#             from fpga.tool.openflow import Openflow
+#             self.tool = Openflow(
+#                 self.project,
+#                 frontend='yosys',
+#                 backend='vivado'
+#             )
+#             self.presynth = True
 
-    def generate(self, to_task, from_task, capture):
-        if self.presynth and from_task in ['prj', 'syn']:
-            self.tool.set_part(self.part['name'])
-            self.tool.set_top(self.top)
-            self.tool.paths = self.paths
-            self.tool.files['vhdl'] = self.files['vhdl']
-            self.tool.files['verilog'] = self.files['verilog']
-            self.tool.params = self.params
-            output1 = self.tool.generate('syn', 'prj', capture)
-            self.set_top(self.project)
-            output2 = super().generate(to_task, from_task, capture)
-            return str(output1) + str(output2)
-        return super().generate(to_task, from_task, capture)
+#     def generate(self, to_task, from_task, capture):
+#         if self.presynth and from_task in ['prj', 'syn']:
+#             self.tool.set_part(self.part['name'])
+#             self.tool.set_top(self.top)
+#             self.tool.paths = self.paths
+#             self.tool.files['vhdl'] = self.files['vhdl']
+#             self.tool.files['verilog'] = self.files['verilog']
+#             self.tool.params = self.params
+#             output1 = self.tool.generate('syn', 'prj', capture)
+#             self.set_top(self.project)
+#             output2 = super().generate(to_task, from_task, capture)
+#             return str(output1) + str(output2)
+#         return super().generate(to_task, from_task, capture)
 
-    def transfer(self, devtype, position, part, width, capture):
-        super().transfer(devtype, position, part, width, capture)
-        temp = _TEMPLATES[devtype]
-        if devtype != 'detect':
-            temp = temp.replace('#BITSTREAM#', self.bitstream)
-        with open('vivado-prog.tcl', 'w', encoding='utf-8') as file:
-            file.write(temp)
-        return run(self._TRF_COMMAND, capture)
+#     def transfer(self, devtype, position, part, width, capture):
+#         super().transfer(devtype, position, part, width, capture)
+#         temp = _TEMPLATES[devtype]
+#         if devtype != 'detect':
+#             temp = temp.replace('#BITSTREAM#', self.bitstream)
+#         with open('vivado-prog.tcl', 'w', encoding='utf-8') as file:
+#             file.write(temp)
+#         return run(self._TRF_COMMAND, capture)

From 7d10d7b9acb7422776d07aad6253157c96799b70 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Tue, 4 Jun 2024 22:14:41 -0300
Subject: [PATCH 069/248] Added to check if the needed underlying tool is
 available

---
 pyfpga/project.py | 46 ++++++++++++++++++++++++++++++----------------
 1 file changed, 30 insertions(+), 16 deletions(-)

diff --git a/pyfpga/project.py b/pyfpga/project.py
index f7d49537..5c054dd3 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -15,6 +15,7 @@
 
 from datetime import datetime
 from pathlib import Path
+from shutil import which
 from time import time
 
 
@@ -25,9 +26,12 @@ class Project:
     :type name: str, optional
     :param odir: output directory
     :type odir: str, optional
-    :raises NotImplementedError: when a method is not implemented yet
+    :raises ValueError: when an invalid value is specified
+    :raises RuntimeError: when the needed underlying tool is not available
     """
 
+    tool = {}
+
     def __init__(self, name=None, odir='results'):
         """Class constructor."""
         self.data = {}
@@ -189,31 +193,41 @@ def add_hook(self, stage, hook):
             raise ValueError('Invalid stage.')
         self.data.setdefault('hooks', {}).setdefault(stage, []).append(hook)
 
-    def make(self, end='bit', start='prj'):
+    def make(self, last='bit', first='prj'):
         """Run the underlying tool.
 
-        :param end: last task
-        :type end: str, optional
-        :param start: first task
-        :type start: str, optional
+        :param last: last step
+        :type last: str, optional
+        :param first: first step
+        :type first: str, optional
 
-        .. note:: Valid values are ``cfg``, ``syn``, ``imp`` and ``bit``.
+        .. note:: valid steps are ``cfg``, ``syn``, ``imp`` and ``bit``.
         """
         steps = ['cfg', 'syn', 'par', 'bit']
-        if end not in steps or start not in steps:
-            raise ValueError('Invalid steps.')
-        _ = self
-        raise NotImplementedError('Method is not implemented yet.')
-
-    def prog(self, position=1, bitstream=None):
+        if last not in steps:
+            raise ValueError('Invalid last step.')
+        if first not in steps:
+            raise ValueError('Invalid first step.')
+        if steps.index(first) > steps.index(last):
+            raise ValueError('Invalid steps combination.')
+        if not which(self.tool['program']):
+            raise RuntimeError(f'{self.tool["program"]} not found.')
+        self._run(self.tool['command'])
+
+    def prog(self, bitstream=None, position=1):
         """Program the FPGA
 
-        :param position: position of the device in the JTAG chain
-        :type position: str, optional
         :param bitstream: bitstream to be programmed
         :type bitstream: str, optional
+        :param position: position of the device in the JTAG chain
+        :type position: str, optional
         """
-        raise NotImplementedError('Method is not implemented yet.')
+        if position not in range(1, 9):
+            raise ValueError('Invalid position.')
+        _ = bitstream
+        if not which(self.tool['program']):
+            raise RuntimeError(f'{self.tool["program"]} not found.')
+        self._run(self.tool['command'])
 
     def _run(self, command):
         self.logger.info('Running the underlying tool (%s)', datetime.now())

From b1c26827eb18119e15019d3922127643dfad6cdc Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Wed, 5 Jun 2024 20:30:37 -0300
Subject: [PATCH 070/248] Removed unused things

---
 pyfpga/ise.py      | 64 ++++++-------------------------------
 pyfpga/libero.py   | 20 +++++-------
 pyfpga/openflow.py | 24 ++++++--------
 pyfpga/quartus.py  | 27 ++++++----------
 pyfpga/tool.py     | 78 ++--------------------------------------------
 pyfpga/vivado.py   | 62 +++++-------------------------------
 6 files changed, 45 insertions(+), 230 deletions(-)

diff --git a/pyfpga/ise.py b/pyfpga/ise.py
index 329e6e48..17fb4706 100644
--- a/pyfpga/ise.py
+++ b/pyfpga/ise.py
@@ -78,48 +78,17 @@ class Ise(Project):
         'command': 'xtclsh ise.tcl',
     }
 
-#     _TOOL = 'ise'
-#     _EXTENSION = 'xise'
-#     _PART = 'xc7k160t-3-fbg484'
-#     _GEN_PROGRAM = 'xtclsh'
-#     _GEN_COMMAND = 'xtclsh ise.tcl'
-#     _TRF_PROGRAM = 'impact'
-#     _TRF_COMMAND = 'impact -batch ise-prog.impact'
-#     _BIT_EXT = ['bit']
+    tool = {
+        'def-part': 'xc7k160t-3-fbg484',
+        'proj-ext': 'xise',
+        'make-app': 'xtclsh',
+        'make-opt': 'ise.tcl',
+        'prog-app': 'impact',
+        'prog-opt': '-batch ise-prog.impact',
+        'binaries': ['bit']
+    }
+
 #     _DEVTYPES = ['fpga', 'spi', 'bpi', 'detect', 'unlock']
-#     _CLEAN = [
-#         # directories
-#         'iseconfig', '_ngo', 'xlnx_auto_0_xdb', '_xmsgs', 'xst',
-#         # files
-#         '*.bgn', '*.bld', '*.bit',
-#         '*.cmd_log', '*.csv',
-#         '*.drc',
-#         '*.gise',
-#         '*.html',
-#         '*.log', '*.lso',
-#         '*.map', '*.mrp',
-#         '*.ncd', '*.ngc', '*.ngd', '*.ngm', '*.ngr',
-#         '*.pad', '*.par', '*.pcf', '*.prj', '*.ptwx',
-#         '*.stx', '*.syr',
-#         '*.twr', '*.twx',
-#         '*.unroutes', '*.ut',
-#         '*.txt',
-#         '*.xml', '*.xpi', '*.xrpt', '*.xst', '*.xwbt',
-#         '_impact*',
-#         # pyfpga
-#         '*.impact', 'ise.tcl'
-#     ]
-
-#     def __init__(self, project, frontend=None):
-#         super().__init__(project)
-#         if frontend == 'yosys':
-#             from fpga.tool.openflow import Openflow
-#             self.tool = Openflow(
-#                 self.project,
-#                 frontend='yosys',
-#                 backend='ise'
-#             )
-#             self.presynth = True
 
 #     def set_part(self, part):
 #         try:
@@ -138,19 +107,6 @@ class Ise(Project):
 #         self.part['package'] = package
 #         self.part['speed'] = '-' + speed
 
-#     def generate(self, to_task, from_task, capture):
-#         if self.presynth and from_task in ['prj', 'syn']:
-#             self.tool.set_part(self.part['name'])
-#             self.tool.set_top(self.top)
-#             self.tool.paths = self.paths
-#             self.tool.files['vhdl'] = self.files['vhdl']
-#             self.tool.files['verilog'] = self.files['verilog']
-#             self.tool.params = self.params
-#             output1 = self.tool.generate('syn', 'prj', capture)
-#             output2 = super().generate(to_task, from_task, capture)
-#             return str(output1) + str(output2)
-#         return super().generate(to_task, from_task, capture)
-
 #     def transfer(self, devtype, position, part, width, capture):
 #         super().transfer(devtype, position, part, width, capture)
 #         temp = _TEMPLATES[devtype]
diff --git a/pyfpga/libero.py b/pyfpga/libero.py
index 5513698e..966ac5d9 100644
--- a/pyfpga/libero.py
+++ b/pyfpga/libero.py
@@ -38,18 +38,14 @@ class Libero(Project):
         'command': 'libero SCRIPT:libero.tcl',
     }
 
-#     _TOOL = 'libero'
-#     _EXTENSION = 'prjx'
-#     _PART = 'mpf100t-1-fcg484'
-#     _GEN_PROGRAM = 'libero'
-#     _GEN_COMMAND = 'libero SCRIPT:libero.tcl'
-#     _DEVTYPES = ['fpga']
-#     _CLEAN = [
-#         # directories
-#         'libero',
-#         # pyfpga
-#         'libero.tcl'
-#     ]
+    tool = {
+        'def-part': 'mpf100t-1-fcg484',
+        'proj-ext': 'prjx',
+        'make-app': 'libero',
+        'make-opt': 'SCRIPT:libero.tcl',
+        'prog-app': '',
+        'prog-opt': ''
+    }
 
 #     def set_part(self, part):
 #         try:
diff --git a/pyfpga/openflow.py b/pyfpga/openflow.py
index b010ae40..f8a1150b 100644
--- a/pyfpga/openflow.py
+++ b/pyfpga/openflow.py
@@ -22,21 +22,15 @@ class Openflow(Project):
         'command': 'bash openflow.sh',
     }
 
-#     _TOOL = 'openflow'
-#     _PART = 'hx8k-ct256'
-#     _GEN_PROGRAM = 'docker'
-#     _GEN_COMMAND = 'bash openflow.sh'
-#     _TRF_PROGRAM = 'docker'
-#     _TRF_COMMAND = 'bash openprog.sh'
-#     _BIT_EXT = ['bit']
-#     _DEVTYPES = ['fpga']
-#     _CLEAN = [
-#         # files
-#         '*.asc', '*.bit', '*.cf', '*.config', '*.edif', '*.json', '*.rpt',
-#         '*.svf',
-#         # pyfpga
-#         '*.sh'
-#     ]
+    tool = {
+        'def-part': 'hx8k-ct256',
+        'proj-ext': '',
+        'make-app': 'docker',
+        'make-cmd': 'bash openflow.sh',
+        'prog-app': 'docker',
+        'prog-cmd': 'bash openprog.sh',
+        'binaries': ['bit']
+    }
 
 #     def __init__(self, project, frontend='yosys', backend='nextpnr'):
 #         # The valid frontends are be ghdl and yosys
diff --git a/pyfpga/quartus.py b/pyfpga/quartus.py
index 9c6c861e..064af33b 100644
--- a/pyfpga/quartus.py
+++ b/pyfpga/quartus.py
@@ -22,24 +22,15 @@ class Quartus(Project):
         'command': 'quartus_sh --script quartus.tcl',
     }
 
-#     _TOOL = 'quartus'
-#     _EXTENSION = 'qpf'
-#     _PART = '10cl120zf780i8g'
-#     _GEN_PROGRAM = 'quartus_sh'
-#     _GEN_COMMAND = 'quartus_sh --script quartus.tcl'
-#     _TRF_PROGRAM = 'quartus_pgm'
-#     _TRF_COMMAND = 'quartus_pgm -c %s --mode jtag -o "p;%s@%s"'
-#     _BIT_EXT = ['sof', 'pof']
-#     _DEVTYPES = ['fpga', 'detect']
-#     _CLEAN = [
-#         # directories
-#         'db', 'incremental_db', 'output_files',
-#         # files
-#         '*.done', '*.jdi', '*.log', '*.pin', '*.pof', '*.qws', '*.rpt',
-#         '*.smsg', '*.sld', '*.sof', '*.sop', '*.summary', '*.txt',
-#         # pyfpga
-#         'quartus.tcl'
-#     ]
+    tool = {
+        'def-part': '10cl120zf780i8g',
+        'proj-ext': 'qpf',
+        'make-app': 'quartus_sh',
+        'make-opt': '--script quartus.tcl',
+        'prog-app': 'quartus_pgm',
+        'prog-opt': '-c %s --mode jtag -o "p;%s@%s"',
+        'binaries': ['sof', 'pof']
+    }
 
 #     def transfer(self, devtype, position, part, width, capture):
 #         super().transfer(devtype, position, part, width, capture)
diff --git a/pyfpga/tool.py b/pyfpga/tool.py
index 19a756d4..30309ad0 100644
--- a/pyfpga/tool.py
+++ b/pyfpga/tool.py
@@ -4,17 +4,10 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-"""fpga.tool
-
+"""
 Defines the interface to be inherited to support a tool.
 """
 
-
-FILETYPES = ['verilog', 'vhdl', 'constraint', 'design']
-MEMWIDTHS = [1, 2, 4, 8, 16, 32]
-PHASES = ['prefile', 'project', 'preflow', 'postsyn', 'postpar', 'postbit']
-TASKS = ['prj', 'syn', 'par', 'bit']
-
 # def tcl_path(path):
 #     """Returns a Tcl suitable path."""
 #     return path.replace(os.path.sep, "/")
@@ -23,64 +16,7 @@
 
 
 class Tool:
-    """Tool interface.
-
-    It is the basic interface for tool implementations.
-    """
-
-#     # Following variables are set in each inheritance (if employed)
-#     _TOOL = None         # tool name
-#     _EXTENSION = None    # project file extension
-#     _PART = None         # default device part name
-#     _GEN_PROGRAM = None  # program used when generate is executed
-#     _GEN_COMMAND = None  # command to run when generate is executed
-#     _TRF_PROGRAM = None  # program used when transfer is executed
-#     _TRF_COMMAND = None  # command to run when transfer is executed
-#     _BIT_EXT = []        # Supported BITstream EXTensions
-#     _DEVTYPES = []       # Supported DEVice TYPES
-#     _CLEAN = []          # Files to be CLEAN
-
-#     def __init__(self, project):
-#         """Initializes the attributes of the class."""
-#         self.bitstream = None
-#         self.cmds = {
-#             'prefile': [],
-#             'project': [],
-#             'preflow': [],
-#             'postsyn': [],
-#             'postpar': [],
-#             'postbit': []
-#         }
-#         self.files = {
-#             'vhdl': [],
-#             'verilog': [],
-#             'constraint': [],
-#             'design': []
-#         }
-#         self.params = []
-#         self.part = {
-#             'name': 'UNSET',
-#             'family': 'UNSET',
-#             'device': 'UNSET',
-#             'package': 'UNSET',
-#             'speed': 'UNSET'
-#         }
-#         self.paths = []
-#         self.presynth = False
-#         self.project = self._TOOL if project is None else project
-#         self.set_part(self._PART)
-#         self.set_top('UNDEFINED')
-#         self._configure()
-
-#     def _configure(self):
-#         """Configures the underlying tools."""
-#         filename = '.pyfpga.yml'
-#         self.configs = {}
-#         if os.path.exists(filename):
-#             with open(filename, 'r', encoding='utf-8') as file:
-#                 data = safe_load(file)
-#                 if self._TOOL in data:
-#                     self.configs = data[self._TOOL]
+    """Tool interface."""
 
 #     def _create_gen_script(self, tasks):
 #         """Create the script for generate execution."""
@@ -167,13 +103,3 @@ class Tool:
 #             if len(bitstream) == 0:
 #                 raise FileNotFoundError('bitStream not found')
 #             self.bitstream = bitstream[0]
-
-#     def clean(self):
-#         """Clean the generated project files."""
-#         for path in self._CLEAN:
-#             elements = glob(path)
-#             for element in elements:
-#                 if os.path.isfile(element):
-#                     os.remove(element)
-#                 else:
-#                     rmtree(element)
diff --git a/pyfpga/vivado.py b/pyfpga/vivado.py
index 46008024..c5b36cdb 100644
--- a/pyfpga/vivado.py
+++ b/pyfpga/vivado.py
@@ -34,59 +34,11 @@ class Vivado(Project):
     """Class to support Vivado."""
 
     tool = {
-        'program': 'vivado',
-        'command': 'vivado -mode batch -notrace -quiet -source vivado.tcl',
+        'def-part': 'xc7k160t-3-fbg484',
+        'proj-ext': 'xpr',
+        'make-app': 'vivado',
+        'make-opt': '-mode batch -notrace -quiet -source vivado.tcl',
+        'prog-app': 'vivado',
+        'prog-opt': '-mode batch -notrace -quiet -source vivado-prog.tcl',
+        'binaries': ['bit']
     }
-
-#     _TOOL = 'vivado'
-#     _EXTENSION = 'xpr'
-#     _PART = 'xc7k160t-3-fbg484'
-#     _GEN_PROGRAM = 'vivado'
-#     _GEN_COMMAND = 'vivado -mode batch -notrace -quiet -source vivado.tcl'
-#     _TRF_PROGRAM = 'vivado'
-#     _TRF_COMMAND =
-#         'vivado -mode batch -notrace -quiet -source vivado-prog.tcl'
-#     _BIT_EXT = ['bit']
-#     _DEVTYPES = ['fpga', 'detect']
-#     _CLEAN = [
-#         # directories
-#         '*.cache', '*.hw', '*.ip_user_files', '*.runs', '*.sim', '.Xil',
-#         # files
-#         '*.bit', '*.jou', '*.log', '*.rpt', 'vivado_*.zip',
-#         # pyfpga
-#         'vivado.tcl', 'vivado-prog.tcl'
-#     ]
-
-#     def __init__(self, project, frontend=None):
-#         super().__init__(project)
-#         if frontend == 'yosys':
-#             from fpga.tool.openflow import Openflow
-#             self.tool = Openflow(
-#                 self.project,
-#                 frontend='yosys',
-#                 backend='vivado'
-#             )
-#             self.presynth = True
-
-#     def generate(self, to_task, from_task, capture):
-#         if self.presynth and from_task in ['prj', 'syn']:
-#             self.tool.set_part(self.part['name'])
-#             self.tool.set_top(self.top)
-#             self.tool.paths = self.paths
-#             self.tool.files['vhdl'] = self.files['vhdl']
-#             self.tool.files['verilog'] = self.files['verilog']
-#             self.tool.params = self.params
-#             output1 = self.tool.generate('syn', 'prj', capture)
-#             self.set_top(self.project)
-#             output2 = super().generate(to_task, from_task, capture)
-#             return str(output1) + str(output2)
-#         return super().generate(to_task, from_task, capture)
-
-#     def transfer(self, devtype, position, part, width, capture):
-#         super().transfer(devtype, position, part, width, capture)
-#         temp = _TEMPLATES[devtype]
-#         if devtype != 'detect':
-#             temp = temp.replace('#BITSTREAM#', self.bitstream)
-#         with open('vivado-prog.tcl', 'w', encoding='utf-8') as file:
-#             file.write(temp)
-#         return run(self._TRF_COMMAND, capture)

From 6abcbd5d3a76cc2093f82388be3b19c06863d8fb Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Wed, 5 Jun 2024 21:21:09 -0300
Subject: [PATCH 071/248] Moved things from Python scripts to templates

---
 pyfpga/ise.py                        | 55 -------------------------
 pyfpga/libero.py                     | 15 -------
 pyfpga/templates/ise-prog.jinja      | 60 ++++++++++++++++++++++++++++
 pyfpga/templates/ise.jinja           |  1 -
 pyfpga/templates/libero-prog.jinja   | 20 ++++++++++
 pyfpga/templates/libero.jinja        |  1 -
 pyfpga/templates/openflow-prog.jinja |  1 -
 pyfpga/templates/openflow.jinja      |  2 -
 pyfpga/templates/quartus-prog.jinja  |  7 ++++
 pyfpga/templates/quartus.jinja       |  1 -
 pyfpga/templates/vivado-prog.jinja   | 13 ++++++
 pyfpga/templates/vivado.jinja        |  1 -
 pyfpga/vivado.py                     | 17 --------
 13 files changed, 100 insertions(+), 94 deletions(-)
 create mode 100644 pyfpga/templates/ise-prog.jinja
 create mode 100644 pyfpga/templates/libero-prog.jinja
 create mode 100644 pyfpga/templates/quartus-prog.jinja
 create mode 100644 pyfpga/templates/vivado-prog.jinja

diff --git a/pyfpga/ise.py b/pyfpga/ise.py
index 17fb4706..cd39634e 100644
--- a/pyfpga/ise.py
+++ b/pyfpga/ise.py
@@ -12,61 +12,6 @@
 
 from pyfpga.project import Project
 
-_TEMPLATES = {
-    'fpga': """setMode -bs
-setCable -port auto
-Identify -inferir
-assignFile -p #POSITION# -file #BITSTREAM#
-Program -p #POSITION#
-
-quit
-""",
-    'spi': """setMode -pff
-addConfigDevice -name #NAME# -path .
-setSubmode -pffspi
-addDesign -version 0 -name 0
-addDeviceChain -index 0
-addDevice -p 1 -file #BITSTREAM#
-generate -generic
-
-setMode -bs
-setCable -port auto
-Identify
-attachflash -position #POSITION# -spi #NAME#
-assignfiletoattachedflash -position #POSITION# -file ./#NAME#.mcs
-Program -p #POSITION# -dataWidth #WIDTH# -spionly -e -v -loadfpga
-
-quit
-""",
-    'bpi': """setMode -pff
-addConfigDevice -name #NAME# -path .
-setSubmode -pffbpi
-addDesign -version 0 -name 0
-addDeviceChain -index 0
-setAttribute -configdevice -attr flashDataWidth -value #WIDTH#
-addDevice -p 1 -file #BITSTREAM#
-generate -generic
-
-setMode -bs
-setCable -port auto
-Identify
-attachflash -position #POSITION# -bpi #NAME#
-assignfiletoattachedflash -position #POSITION# -file ./#NAME#.mcs
-Program -p #POSITION# -dataWidth #WIDTH# \
--rs1 NONE -rs0 NONE -bpionly -e -v -loadfpga
-
-quit
-""",
-    'detect': """setMode -bs
-setCable -port auto
-Identify -inferir
-quit
-""",
-    'unlock': """cleancablelock
-quit
-"""
-}
-
 # pylint: disable=too-few-public-methods
 
 
diff --git a/pyfpga/libero.py b/pyfpga/libero.py
index 966ac5d9..7061f040 100644
--- a/pyfpga/libero.py
+++ b/pyfpga/libero.py
@@ -12,21 +12,6 @@
 
 from pyfpga.project import Project
 
-_TEMPLATES = {
-    'fpga': """\
-""",
-    'detect': """\
-"""
-}
-
-# open_project -file {$TEMPDIR/libero.prjx}
-# run_tool -name {CONFIGURE_CHAIN} -script {$TEMPDIR/flashpro.tcl}
-# run_tool -name {PROGRAMDEVICE}
-
-# set flashpro_programmer "configure_flashpro5_prg -vpump {ON} \
-# -clk_mode {free_running_clk} -programming_method {spi_slave} \
-# -force_freq {OFF} -freq {4000000}"
-
 # pylint: disable=too-few-public-methods
 
 
diff --git a/pyfpga/templates/ise-prog.jinja b/pyfpga/templates/ise-prog.jinja
new file mode 100644
index 00000000..4c18a072
--- /dev/null
+++ b/pyfpga/templates/ise-prog.jinja
@@ -0,0 +1,60 @@
+#
+# Copyright (C) 2015-2024 Rodrigo A. Melo
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+
+_TEMPLATES = {
+    'fpga': """setMode -bs
+setCable -port auto
+Identify -inferir
+assignFile -p #POSITION# -file #BITSTREAM#
+Program -p #POSITION#
+
+quit
+""",
+    'spi': """setMode -pff
+addConfigDevice -name #NAME# -path .
+setSubmode -pffspi
+addDesign -version 0 -name 0
+addDeviceChain -index 0
+addDevice -p 1 -file #BITSTREAM#
+generate -generic
+
+setMode -bs
+setCable -port auto
+Identify
+attachflash -position #POSITION# -spi #NAME#
+assignfiletoattachedflash -position #POSITION# -file ./#NAME#.mcs
+Program -p #POSITION# -dataWidth #WIDTH# -spionly -e -v -loadfpga
+
+quit
+""",
+    'bpi': """setMode -pff
+addConfigDevice -name #NAME# -path .
+setSubmode -pffbpi
+addDesign -version 0 -name 0
+addDeviceChain -index 0
+setAttribute -configdevice -attr flashDataWidth -value #WIDTH#
+addDevice -p 1 -file #BITSTREAM#
+generate -generic
+
+setMode -bs
+setCable -port auto
+Identify
+attachflash -position #POSITION# -bpi #NAME#
+assignfiletoattachedflash -position #POSITION# -file ./#NAME#.mcs
+Program -p #POSITION# -dataWidth #WIDTH# \
+-rs1 NONE -rs0 NONE -bpionly -e -v -loadfpga
+
+quit
+""",
+    'detect': """setMode -bs
+setCable -port auto
+Identify -inferir
+quit
+""",
+    'unlock': """cleancablelock
+quit
+"""
+}
diff --git a/pyfpga/templates/ise.jinja b/pyfpga/templates/ise.jinja
index 08678558..c70efad6 100644
--- a/pyfpga/templates/ise.jinja
+++ b/pyfpga/templates/ise.jinja
@@ -1,5 +1,4 @@
 #
-# PyFPGA
 # Copyright (C) 2015-2024 Rodrigo A. Melo
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
diff --git a/pyfpga/templates/libero-prog.jinja b/pyfpga/templates/libero-prog.jinja
new file mode 100644
index 00000000..ed9effe2
--- /dev/null
+++ b/pyfpga/templates/libero-prog.jinja
@@ -0,0 +1,20 @@
+#
+# Copyright (C) 2015-2024 Rodrigo A. Melo
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+
+_TEMPLATES = {
+    'fpga': """\
+""",
+    'detect': """\
+"""
+}
+
+# open_project -file {$TEMPDIR/libero.prjx}
+# run_tool -name {CONFIGURE_CHAIN} -script {$TEMPDIR/flashpro.tcl}
+# run_tool -name {PROGRAMDEVICE}
+
+# set flashpro_programmer "configure_flashpro5_prg -vpump {ON} \
+# -clk_mode {free_running_clk} -programming_method {spi_slave} \
+# -force_freq {OFF} -freq {4000000}"
diff --git a/pyfpga/templates/libero.jinja b/pyfpga/templates/libero.jinja
index 35ec3f52..1b230c2c 100644
--- a/pyfpga/templates/libero.jinja
+++ b/pyfpga/templates/libero.jinja
@@ -1,5 +1,4 @@
 #
-# PyFPGA
 # Copyright (C) 2015-2024 Rodrigo A. Melo
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
diff --git a/pyfpga/templates/openflow-prog.jinja b/pyfpga/templates/openflow-prog.jinja
index 3be40f53..027eb388 100644
--- a/pyfpga/templates/openflow-prog.jinja
+++ b/pyfpga/templates/openflow-prog.jinja
@@ -1,5 +1,4 @@
 #
-# PyFPGA
 # Copyright (C) 2020-2024 Rodrigo A. Melo
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
diff --git a/pyfpga/templates/openflow.jinja b/pyfpga/templates/openflow.jinja
index f50b0786..d3a0a703 100644
--- a/pyfpga/templates/openflow.jinja
+++ b/pyfpga/templates/openflow.jinja
@@ -1,6 +1,4 @@
-#!/bin/bash
 #
-# PyFPGA
 # Copyright (C) 2020-2024 Rodrigo A. Melo
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
diff --git a/pyfpga/templates/quartus-prog.jinja b/pyfpga/templates/quartus-prog.jinja
new file mode 100644
index 00000000..45ee765b
--- /dev/null
+++ b/pyfpga/templates/quartus-prog.jinja
@@ -0,0 +1,7 @@
+#
+# Copyright (C) 2015-2024 Rodrigo A. Melo
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+
+{{ COMMAND }} -c %s --mode jtag -o "p;{{ BITSTREAM }}@{{ POSITION }}"
diff --git a/pyfpga/templates/quartus.jinja b/pyfpga/templates/quartus.jinja
index 76c29fc5..cf660a8d 100644
--- a/pyfpga/templates/quartus.jinja
+++ b/pyfpga/templates/quartus.jinja
@@ -1,5 +1,4 @@
 #
-# PyFPGA
 # Copyright (C) 2015-2024 Rodrigo A. Melo
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
diff --git a/pyfpga/templates/vivado-prog.jinja b/pyfpga/templates/vivado-prog.jinja
new file mode 100644
index 00000000..7b148b22
--- /dev/null
+++ b/pyfpga/templates/vivado-prog.jinja
@@ -0,0 +1,13 @@
+#
+# Copyright (C) 2015-2024 Rodrigo A. Melo
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+
+if { [ catch { open_hw_manager } ] } { open_hw }
+connect_hw_server
+open_hw_target
+puts [get_hw_devices]
+set obj [lindex [get_hw_devices [current_hw_device]] 0]
+set_property PROGRAM.FILE {{ BITSTREAM }} $obj
+program_hw_devices $obj
diff --git a/pyfpga/templates/vivado.jinja b/pyfpga/templates/vivado.jinja
index 16bed243..5c4e6049 100644
--- a/pyfpga/templates/vivado.jinja
+++ b/pyfpga/templates/vivado.jinja
@@ -1,5 +1,4 @@
 #
-# PyFPGA
 # Copyright (C) 2015-2024 Rodrigo A. Melo
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
diff --git a/pyfpga/vivado.py b/pyfpga/vivado.py
index c5b36cdb..15dfa008 100644
--- a/pyfpga/vivado.py
+++ b/pyfpga/vivado.py
@@ -10,23 +10,6 @@
 
 from pyfpga.project import Project
 
-_TEMPLATES = {
-    'fpga': """\
-if { [ catch { open_hw_manager } ] } { open_hw }
-connect_hw_server
-open_hw_target
-set obj [lindex [get_hw_devices [current_hw_device]] 0]
-set_property PROGRAM.FILE #BITSTREAM# $obj
-program_hw_devices $obj
-""",
-    'detect': """\
-if { [ catch { open_hw_manager } ] } { open_hw }
-connect_hw_server
-open_hw_target
-puts [get_hw_devices]
-"""
-}
-
 # pylint: disable=too-few-public-methods
 
 

From 713bbc75ecfd5589ec2fc1f6a01142ff1e653cfe Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Thu, 6 Jun 2024 23:18:17 -0300
Subject: [PATCH 072/248] Added a method to create files based on templates

---
 pyfpga/project.py | 42 +++++++++++++++++++++++++++++++-----------
 1 file changed, 31 insertions(+), 11 deletions(-)

diff --git a/pyfpga/project.py b/pyfpga/project.py
index 5c054dd3..a6193683 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -17,6 +17,7 @@
 from pathlib import Path
 from shutil import which
 from time import time
+from jinja2 import Environment, FileSystemLoader
 
 
 class Project:
@@ -37,7 +38,6 @@ def __init__(self, name=None, odir='results'):
         self.data = {}
         self.name = name
         self.odir = odir
-        # self.odir.mkdir(parents=True, exist_ok=True)
         # logging config
         self.logger = logging.getLogger(self.__class__.__name__)
         self.logger.setLevel(logging.INFO)
@@ -210,9 +210,10 @@ def make(self, last='bit', first='prj'):
             raise ValueError('Invalid first step.')
         if steps.index(first) > steps.index(last):
             raise ValueError('Invalid steps combination.')
-        if not which(self.tool['program']):
-            raise RuntimeError(f'{self.tool["program"]} not found.')
-        self._run(self.tool['command'])
+        self._make_prepare()
+        if not which(self.tool['make-app']):
+            raise RuntimeError(f'{self.tool["make-app"]} not found.')
+        self._run(self.tool['make-cmd'])
 
     def prog(self, bitstream=None, position=1):
         """Program the FPGA
@@ -225,9 +226,28 @@ def prog(self, bitstream=None, position=1):
         if position not in range(1, 9):
             raise ValueError('Invalid position.')
         _ = bitstream
-        if not which(self.tool['program']):
-            raise RuntimeError(f'{self.tool["program"]} not found.')
-        self._run(self.tool['command'])
+        self._prog_prepare()
+        if not which(self.tool['prog-app']):
+            raise RuntimeError(f'{self.tool["prog-app"]} not found.')
+        self._run(self.tool['prog-cmd'])
+
+    def _make_prepare(self):
+        raise NotImplementedError('Tool-dependent')
+
+    def _prog_prepare(self):
+        raise NotImplementedError('Tool-dependent')
+
+    def _create_file(self, basename, extension, context):
+        tempdir = Path(__file__).parent.joinpath('templates')
+        jinja_file_loader = FileSystemLoader(str(tempdir))
+        jinja_env = Environment(loader=jinja_file_loader)
+        jinja_template = jinja_env.get_template(f'{basename}.jinja')
+        content = jinja_template.render(context)
+        directory = Path(self.odir)
+        directory.mkdir(parents=True, exist_ok=True)
+        filename = f'{basename}.{extension}'
+        with open(directory / filename, 'w', encoding='utf-8') as file:
+            file.write(content)
 
     def _run(self, command):
         self.logger.info('Running the underlying tool (%s)', datetime.now())
@@ -237,14 +257,14 @@ def _run(self, command):
         start = time.time()
         try:
             os.chdir(new_dir)
-            with open('run.log', 'w', encoding='utf-8') as logfile:
+            with open('run.log', 'w', encoding='utf-8') as file:
                 subprocess.run(
                     command, shell=True, check=True, text=True,
-                    stdout=logfile, stderr=subprocess.STDOUT
+                    stdout=file, stderr=subprocess.STDOUT
                 )
         except subprocess.CalledProcessError:
-            with open('run.log', 'r', encoding='utf-8') as logfile:
-                lines = logfile.readlines()
+            with open('run.log', 'r', encoding='utf-8') as file:
+                lines = file.readlines()
                 last_lines = lines[-10:] if len(lines) >= 10 else lines
                 for line in last_lines:
                     self.logger.error(line.strip())

From e506e2fb858186d7e54ac23009f486797885c6fc Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Thu, 6 Jun 2024 23:18:40 -0300
Subject: [PATCH 073/248] Tool-specific data reorganized

---
 pyfpga/ise.py      | 27 +++++++++++----------------
 pyfpga/libero.py   | 26 +++++++++++---------------
 pyfpga/openflow.py | 28 +++++++++++-----------------
 pyfpga/quartus.py  | 31 ++++++++++++++-----------------
 pyfpga/vivado.py   | 29 +++++++++++++++++------------
 5 files changed, 64 insertions(+), 77 deletions(-)

diff --git a/pyfpga/ise.py b/pyfpga/ise.py
index cd39634e..61fee4be 100644
--- a/pyfpga/ise.py
+++ b/pyfpga/ise.py
@@ -12,26 +12,22 @@
 
 from pyfpga.project import Project
 
-# pylint: disable=too-few-public-methods
-
 
 class Ise(Project):
     """Class to support ISE projects."""
 
-    tool = {
-        'program': 'xtclsh',
-        'command': 'xtclsh ise.tcl',
-    }
+    def __init__(self, name='ise', odir='results'):
+        super().__init__(name=name, odir=odir)
+        self.set_part('xc7k160t-3-fbg484')
+
+    def _make_prepare(self):
+        self.tool['make-app'] = 'xtclsh'
+        self.tool['make-cmd'] = 'xtclsh ise.tcl'
 
-    tool = {
-        'def-part': 'xc7k160t-3-fbg484',
-        'proj-ext': 'xise',
-        'make-app': 'xtclsh',
-        'make-opt': 'ise.tcl',
-        'prog-app': 'impact',
-        'prog-opt': '-batch ise-prog.impact',
-        'binaries': ['bit']
-    }
+    def _prog_prepare(self):
+        # binaries = ['bit']
+        self.tool['prog-app'] = 'impact'
+        self.tool['prog-cmd'] = 'impact -batch impact-prog'
 
 #     _DEVTYPES = ['fpga', 'spi', 'bpi', 'detect', 'unlock']
 
@@ -64,7 +60,6 @@ class Ise(Project):
 #             file.write(temp)
 #         return run(self._TRF_COMMAND, capture)
 
-
 # def get_family(part):
 #     """Get the Family name from the specified part name."""
 #     part = part.lower()
diff --git a/pyfpga/libero.py b/pyfpga/libero.py
index 7061f040..1c842fb9 100644
--- a/pyfpga/libero.py
+++ b/pyfpga/libero.py
@@ -12,25 +12,22 @@
 
 from pyfpga.project import Project
 
-# pylint: disable=too-few-public-methods
-
 
 class Libero(Project):
     """Class to support Libero."""
 
-    tool = {
-        'program': 'libero',
-        'command': 'libero SCRIPT:libero.tcl',
-    }
+    def __init__(self, name='libero', odir='results'):
+        super().__init__(name=name, odir=odir)
+        self.set_part('mpf100t-1-fcg484')
+
+    def _make_prepare(self):
+        self.tool['make-app'] = 'libero'
+        self.tool['make-cmd'] = 'libero SCRIPT:libero.tcl'
 
-    tool = {
-        'def-part': 'mpf100t-1-fcg484',
-        'proj-ext': 'prjx',
-        'make-app': 'libero',
-        'make-opt': 'SCRIPT:libero.tcl',
-        'prog-app': '',
-        'prog-opt': ''
-    }
+    def _prog_prepare(self):
+        # binaries = ['bit']
+        self.tool['prog-app'] = ''
+        self.tool['prog-cmd'] = ''
 
 #     def set_part(self, part):
 #         try:
@@ -55,7 +52,6 @@ class Libero(Project):
 #         super().transfer(devtype, position, part, width, capture)
 #         raise NotImplementedError('transfer(libero)')
 
-
 # def get_family(part):
 #     """Get the Family name from the specified part name."""
 #     part = part.lower()
diff --git a/pyfpga/openflow.py b/pyfpga/openflow.py
index f8a1150b..7ecbb9cd 100644
--- a/pyfpga/openflow.py
+++ b/pyfpga/openflow.py
@@ -8,29 +8,24 @@
 Implements support for an Open Source development flow.
 """
 
-# import os
 from pyfpga.project import Project
 
-# pylint: disable=too-few-public-methods
-
 
 class Openflow(Project):
     """Class to support Openflow."""
 
-    tool = {
-        'program': 'docker',
-        'command': 'bash openflow.sh',
-    }
+    def __init__(self, name='openflow', odir='results'):
+        super().__init__(name=name, odir=odir)
+        self.set_part('hx8k-ct256')
+
+    def _make_prepare(self):
+        self.tool['make-app'] = 'docker'
+        self.tool['make-cmd'] = 'bash openflow.sh'
 
-    tool = {
-        'def-part': 'hx8k-ct256',
-        'proj-ext': '',
-        'make-app': 'docker',
-        'make-cmd': 'bash openflow.sh',
-        'prog-app': 'docker',
-        'prog-cmd': 'bash openprog.sh',
-        'binaries': ['bit']
-    }
+    def _prog_prepare(self):
+        # binaries = ['bit']
+        self.tool['prog-app'] = 'docker'
+        self.tool['prog-cmd'] = 'bash openflow-prog.sh'
 
 #     def __init__(self, project, frontend='yosys', backend='nextpnr'):
 #         # The valid frontends are be ghdl and yosys
@@ -178,7 +173,6 @@ class Openflow(Project):
 #             file.write(text)
 #         return run(self._TRF_COMMAND, capture)
 
-
 # def get_family(part):
 #     """Get the Family name from the specified part name."""
 #     part = part.lower()
diff --git a/pyfpga/quartus.py b/pyfpga/quartus.py
index 064af33b..55dd6434 100644
--- a/pyfpga/quartus.py
+++ b/pyfpga/quartus.py
@@ -9,28 +9,25 @@
 """
 
 # import re
-# import subprocess
 
 from pyfpga.project import Project
 
 
 class Quartus(Project):
-    """Class to support Quartus."""
-
-    tool = {
-        'program': 'quartus_sh',
-        'command': 'quartus_sh --script quartus.tcl',
-    }
-
-    tool = {
-        'def-part': '10cl120zf780i8g',
-        'proj-ext': 'qpf',
-        'make-app': 'quartus_sh',
-        'make-opt': '--script quartus.tcl',
-        'prog-app': 'quartus_pgm',
-        'prog-opt': '-c %s --mode jtag -o "p;%s@%s"',
-        'binaries': ['sof', 'pof']
-    }
+    """Class to support Quartus projects."""
+
+    def __init__(self, name='quartus', odir='results'):
+        super().__init__(name=name, odir=odir)
+        self.set_part('10cl120zf780i8g')
+
+    def _make_prepare(self):
+        self.tool['make-app'] = 'quartus_sh'
+        self.tool['make-cmd'] = 'quartus_sh --script quartus.tcl'
+
+    def _prog_prepare(self):
+        # binaries = ['sof', 'pof']
+        self.tool['prog-app'] = 'quartus_pgm'
+        self.tool['prog-cmd'] = 'bash quartus-prog.sh'
 
 #     def transfer(self, devtype, position, part, width, capture):
 #         super().transfer(devtype, position, part, width, capture)
diff --git a/pyfpga/vivado.py b/pyfpga/vivado.py
index 15dfa008..4b53f7ca 100644
--- a/pyfpga/vivado.py
+++ b/pyfpga/vivado.py
@@ -10,18 +10,23 @@
 
 from pyfpga.project import Project
 
-# pylint: disable=too-few-public-methods
-
 
 class Vivado(Project):
-    """Class to support Vivado."""
+    """Class to support Vivado projects."""
+
+    def __init__(self, name='vivado', odir='results'):
+        super().__init__(name=name, odir=odir)
+        self.set_part('xc7k160t-3-fbg484')
+
+    def _make_prepare(self):
+        self.tool['make-app'] = 'vivado'
+        self.tool['make-cmd'] = (
+            'vivado -mode batch -notrace -quiet -source vivado.tcl'
+        )
 
-    tool = {
-        'def-part': 'xc7k160t-3-fbg484',
-        'proj-ext': 'xpr',
-        'make-app': 'vivado',
-        'make-opt': '-mode batch -notrace -quiet -source vivado.tcl',
-        'prog-app': 'vivado',
-        'prog-opt': '-mode batch -notrace -quiet -source vivado-prog.tcl',
-        'binaries': ['bit']
-    }
+    def _prog_prepare(self):
+        # binaries = ['bit']
+        self.tool['prog-app'] = 'vivado'
+        self.tool['prog-cmd'] = (
+            'vivado -mode batch -notrace -quiet -source vivado-prog.tcl'
+        )

From bebd9e892e3011a468342a9ff7157f63f238f795 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Fri, 7 Jun 2024 00:36:30 -0300
Subject: [PATCH 074/248] Ignored results

---
 .gitignore | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/.gitignore b/.gitignore
index 2e7693ab..964a59fd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,5 @@
 *build
 ignore*
+results
 venv
 __pycache__
-*.egg-info
-_theme

From f496a2a0bb9a86be5d64c82d61734115430144ad Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Fri, 7 Jun 2024 00:37:08 -0300
Subject: [PATCH 075/248] Removed unused imports

---
 tests/test_data.py | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/tests/test_data.py b/tests/test_data.py
index 4c363de5..0994d9db 100644
--- a/tests/test_data.py
+++ b/tests/test_data.py
@@ -1,6 +1,3 @@
-import os
-import pytest
-
 from pathlib import Path
 
 from pyfpga.project import Project
@@ -57,7 +54,7 @@
 }
 
 
-def test_names():
+def test_data():
     prj = Project()
     prj.set_part('PARTNAME')
     prj.set_top('TOPNAME')

From cf81ebfdf0d81a057b771da2f53039635d28bcd8 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 10 Jun 2024 20:25:11 -0300
Subject: [PATCH 076/248] Modified how to deal with steps; started the Vivado
 implementation

---
 pyfpga/ise.py                 |  2 +-
 pyfpga/libero.py              |  2 +-
 pyfpga/openflow.py            |  2 +-
 pyfpga/project.py             | 15 ++++---
 pyfpga/quartus.py             |  2 +-
 pyfpga/templates/vivado.jinja | 73 +++++++++++++++--------------------
 pyfpga/vivado.py              | 22 ++++++++---
 tests/test_part.py            | 44 ++++++++++-----------
 tests/test_vivado.py          | 22 +++++++++++
 9 files changed, 104 insertions(+), 80 deletions(-)
 create mode 100644 tests/test_vivado.py

diff --git a/pyfpga/ise.py b/pyfpga/ise.py
index 61fee4be..72e577bc 100644
--- a/pyfpga/ise.py
+++ b/pyfpga/ise.py
@@ -20,7 +20,7 @@ def __init__(self, name='ise', odir='results'):
         super().__init__(name=name, odir=odir)
         self.set_part('xc7k160t-3-fbg484')
 
-    def _make_prepare(self):
+    def _make_prepare(self, steps):
         self.tool['make-app'] = 'xtclsh'
         self.tool['make-cmd'] = 'xtclsh ise.tcl'
 
diff --git a/pyfpga/libero.py b/pyfpga/libero.py
index 1c842fb9..35d4d89f 100644
--- a/pyfpga/libero.py
+++ b/pyfpga/libero.py
@@ -20,7 +20,7 @@ def __init__(self, name='libero', odir='results'):
         super().__init__(name=name, odir=odir)
         self.set_part('mpf100t-1-fcg484')
 
-    def _make_prepare(self):
+    def _make_prepare(self, steps):
         self.tool['make-app'] = 'libero'
         self.tool['make-cmd'] = 'libero SCRIPT:libero.tcl'
 
diff --git a/pyfpga/openflow.py b/pyfpga/openflow.py
index 7ecbb9cd..cb756727 100644
--- a/pyfpga/openflow.py
+++ b/pyfpga/openflow.py
@@ -18,7 +18,7 @@ def __init__(self, name='openflow', odir='results'):
         super().__init__(name=name, odir=odir)
         self.set_part('hx8k-ct256')
 
-    def _make_prepare(self):
+    def _make_prepare(self, steps):
         self.tool['make-app'] = 'docker'
         self.tool['make-cmd'] = 'bash openflow.sh'
 
diff --git a/pyfpga/project.py b/pyfpga/project.py
index a6193683..e71b550a 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -193,7 +193,7 @@ def add_hook(self, stage, hook):
             raise ValueError('Invalid stage.')
         self.data.setdefault('hooks', {}).setdefault(stage, []).append(hook)
 
-    def make(self, last='bit', first='prj'):
+    def make(self, last='bit', first='cfg'):
         """Run the underlying tool.
 
         :param last: last step
@@ -208,9 +208,12 @@ def make(self, last='bit', first='prj'):
             raise ValueError('Invalid last step.')
         if first not in steps:
             raise ValueError('Invalid first step.')
-        if steps.index(first) > steps.index(last):
+        first_index = steps.index(first)
+        last_index = steps.index(last)
+        if first_index > last_index:
             raise ValueError('Invalid steps combination.')
-        self._make_prepare()
+        selected_steps = steps[first_index:last_index + 1]
+        self._make_prepare([step.upper() for step in selected_steps])
         if not which(self.tool['make-app']):
             raise RuntimeError(f'{self.tool["make-app"]} not found.')
         self._run(self.tool['make-cmd'])
@@ -231,7 +234,7 @@ def prog(self, bitstream=None, position=1):
             raise RuntimeError(f'{self.tool["prog-app"]} not found.')
         self._run(self.tool['prog-cmd'])
 
-    def _make_prepare(self):
+    def _make_prepare(self, steps):
         raise NotImplementedError('Tool-dependent')
 
     def _prog_prepare(self):
@@ -254,7 +257,7 @@ def _run(self, command):
         run_error = 0
         old_dir = Path.cwd()
         new_dir = Path(self.odir)
-        start = time.time()
+        start = time()
         try:
             os.chdir(new_dir)
             with open('run.log', 'w', encoding='utf-8') as file:
@@ -271,7 +274,7 @@ def _run(self, command):
             run_error = 1
         finally:
             os.chdir(old_dir)
-            end = time.time()
+            end = time()
             self.logger.info('Done (%s)', datetime.now())
             elapsed = end - start
             self.logger.info(
diff --git a/pyfpga/quartus.py b/pyfpga/quartus.py
index 55dd6434..c635ffa5 100644
--- a/pyfpga/quartus.py
+++ b/pyfpga/quartus.py
@@ -20,7 +20,7 @@ def __init__(self, name='quartus', odir='results'):
         super().__init__(name=name, odir=odir)
         self.set_part('10cl120zf780i8g')
 
-    def _make_prepare(self):
+    def _make_prepare(self, steps):
         self.tool['make-app'] = 'quartus_sh'
         self.tool['make-cmd'] = 'quartus_sh --script quartus.tcl'
 
diff --git a/pyfpga/templates/vivado.jinja b/pyfpga/templates/vivado.jinja
index 5c4e6049..cfc6734b 100644
--- a/pyfpga/templates/vivado.jinja
+++ b/pyfpga/templates/vivado.jinja
@@ -6,43 +6,37 @@
 
 set PROJECT  {{ PROJECT }}
 set PART     {{ PART }}
-set FAMILY   {{ FAMILY }}
-set DEVICE   {{ DEVICE }}
-set PACKAGE  {{ PACKAGE }}
-set SPEED    {{ SPEED }}
 set TOP      {{ TOP }}
 
-set PARAMS   [list {{ PARAMS }}]
-
-proc fpga_file {FILE {LIBRARY "work"}} {
-    set message "adding the file '$FILE'"
-    if { $LIBRARY != "work" } { append message " (into the VHDL library '$LIBRARY')" }
-    regexp -nocase {\.(\w*)$} $FILE -> ext
-    if { $ext == "tcl" } {
-        source $FILE
-        return
-    }
-    if { $LIBRARY != "work" } {
-        add_files $FILE
-        set_property library $LIBRARY [get_files $FILE]
-    } else {
-        add_files $FILE
-    }
-}
-
-proc fpga_include {PATH} {
-    lappend INCLUDED $PATH
-    # Verilog Included Files are NOT added
-    set_property "include_dirs" $INCLUDED [current_fileset]
-}
-
-proc fpga_params {} {
-    if { [llength $PARAMS] == 0 } { return }
-    set assigns [list]
-    foreach PARAM $PARAMS { lappend assigns [join $PARAM "="] }
-    set obj [get_filesets sources_1]
-    set_property "generic" "[join $assigns]" -objects $obj
-}
+# proc fpga_file {FILE {LIBRARY "work"}} {
+#     set message "adding the file '$FILE'"
+#     if { $LIBRARY != "work" } { append message " (into the VHDL library '$LIBRARY')" }
+#     regexp -nocase {\.(\w*)$} $FILE -> ext
+#     if { $ext == "tcl" } {
+#         source $FILE
+#         return
+#     }
+#     if { $LIBRARY != "work" } {
+#         add_files $FILE
+#         set_property library $LIBRARY [get_files $FILE]
+#     } else {
+#         add_files $FILE
+#     }
+# }
+
+# proc fpga_include {PATH} {
+#     lappend INCLUDED $PATH
+#     # Verilog Included Files are NOT added
+#     set_property "include_dirs" $INCLUDED [current_fileset]
+# }
+
+# proc fpga_params {} {
+#     if { [llength $PARAMS] == 0 } { return }
+#     set assigns [list]
+#     foreach PARAM $PARAMS { lappend assigns [join $PARAM "="] }
+#     set obj [get_filesets sources_1]
+#     set_property "generic" "[join $assigns]" -objects $obj
+# }
 
 #--[ Project configuration ]---------------------------------------------------
 
@@ -88,13 +82,11 @@ open_project $PROJECT
 {% if SYN %}
 {{ PRESYN }}
 
-{% if PRESYNTH %}
-set_property design_mode GateLvl [current_fileset]
-{% else %}
+# PRESYNTH
+# set_property design_mode GateLvl [current_fileset]
 reset_run synth_1
 launch_runs synth_1
 wait_on_run synth_1
-{% endif %}
 
 {{ POSTSYN }}
 {% endif %}
@@ -102,9 +94,6 @@ wait_on_run synth_1
 {% if PAR %}
 {{ PREPAR }}
 
-{% if not PRESYNTH %}
-open_run synth_1
-{% endif %}
 reset_run impl_1
 launch_runs impl_1
 wait_on_run impl_1
diff --git a/pyfpga/vivado.py b/pyfpga/vivado.py
index 4b53f7ca..7c7c88b8 100644
--- a/pyfpga/vivado.py
+++ b/pyfpga/vivado.py
@@ -14,15 +14,27 @@
 class Vivado(Project):
     """Class to support Vivado projects."""
 
-    def __init__(self, name='vivado', odir='results'):
-        super().__init__(name=name, odir=odir)
-        self.set_part('xc7k160t-3-fbg484')
-
-    def _make_prepare(self):
+    def _make_prepare(self, steps):
         self.tool['make-app'] = 'vivado'
         self.tool['make-cmd'] = (
             'vivado -mode batch -notrace -quiet -source vivado.tcl'
         )
+        context = {
+            'PROJECT': self.name or 'vivado',
+            'PART': self.data.get('part', 'xc7k160t-3-fbg484'),
+            'TOP': self.data.get('top', 'top')
+        }
+        for step in steps:
+            context[step] = 1
+        if 'hooks' in self.data:
+            for stage in self.data['hooks']:
+                context[stage.upper()] = '\n'.join(self.data['hooks'][stage])
+        # FILES
+        # DEFINES
+        # INCLUDES
+        # PARAMS
+        # ARCH
+        self._create_file('vivado', 'tcl', context)
 
     def _prog_prepare(self):
         # binaries = ['bit']
diff --git a/tests/test_part.py b/tests/test_part.py
index a1c2861a..5cee3e71 100644
--- a/tests/test_part.py
+++ b/tests/test_part.py
@@ -1,29 +1,27 @@
-import pytest
+from pyfpga.project import Project
 
-from fpga.project import Project
 
+# def get_part(prj):
+#     return prj.get_configs()['part'].lower()
 
-def get_part(prj):
-    return prj.get_configs()['part'].lower()
 
+# def test_ise():
+#     prj = Project('ise')
+#     assert get_part(prj) == "xc7k160t-3-fbg484"
+#     prj.set_part('XC6SLX9-2-CSG324')
+#     assert get_part(prj) == "xc6slx9-2-csg324"
+#     prj.set_part('XC6SLX9-2L-CSG324')
+#     assert get_part(prj) == "xc6slx9-2l-csg324"
+#     prj.set_part('XC6SLX9-CSG324-3')
+#     assert get_part(prj) == "xc6slx9-3-csg324"
 
-def test_ise():
-    prj = Project('ise')
-    assert get_part(prj) == "xc7k160t-3-fbg484"
-    prj.set_part('XC6SLX9-2-CSG324')
-    assert get_part(prj) == "xc6slx9-2-csg324"
-    prj.set_part('XC6SLX9-2L-CSG324')
-    assert get_part(prj) == "xc6slx9-2l-csg324"
-    prj.set_part('XC6SLX9-CSG324-3')
-    assert get_part(prj) == "xc6slx9-3-csg324"
 
-
-def test_libero():
-    prj = Project('libero')
-    assert get_part(prj) == "mpf100t-1-fcg484"
-    prj.set_part('m2s010-3-tq144')
-    assert get_part(prj) == "m2s010-3-tq144"
-    prj.set_part('m2s010-tq144-2')
-    assert get_part(prj) == "m2s010-2-tq144"
-    prj.set_part('m2s010-tq144')
-    assert get_part(prj) == "m2s010-std-tq144"
+# def test_libero():
+#     prj = Project('libero')
+#     assert get_part(prj) == "mpf100t-1-fcg484"
+#     prj.set_part('m2s010-3-tq144')
+#     assert get_part(prj) == "m2s010-3-tq144"
+#     prj.set_part('m2s010-tq144-2')
+#     assert get_part(prj) == "m2s010-2-tq144"
+#     prj.set_part('m2s010-tq144')
+#     assert get_part(prj) == "m2s010-std-tq144"
diff --git a/tests/test_vivado.py b/tests/test_vivado.py
new file mode 100644
index 00000000..1aa74916
--- /dev/null
+++ b/tests/test_vivado.py
@@ -0,0 +1,22 @@
+from pyfpga.vivado import Vivado
+
+
+def test_vivado():
+    prj = Vivado()
+    prj.add_hook('precfg', 'HOOK1')
+    prj.add_hook('precfg', 'HOOK1')
+    prj.add_hook('postcfg', 'HOOK2')
+    prj.add_hook('postcfg', 'HOOK2')
+    prj.add_hook('presyn', 'HOOK3')
+    prj.add_hook('presyn', 'HOOK3')
+    prj.add_hook('postsyn', 'HOOK4')
+    prj.add_hook('postsyn', 'HOOK4')
+    prj.add_hook('prepar', 'HOOK5')
+    prj.add_hook('prepar', 'HOOK5')
+    prj.add_hook('postpar', 'HOOK6')
+    prj.add_hook('postpar', 'HOOK6')
+    prj.add_hook('prebit', 'HOOK7')
+    prj.add_hook('prebit', 'HOOK7')
+    prj.add_hook('postbit', 'HOOK8')
+    prj.add_hook('postbit', 'HOOK8')
+    prj.make()

From d02b81ed17f74a99b44e1c1cc1f02d0a95cee786 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 10 Jun 2024 22:25:03 -0300
Subject: [PATCH 077/248] Implemented use of arch, defines, includes and params

---
 pyfpga/templates/vivado.jinja | 34 ----------------------------------
 pyfpga/vivado.py              | 27 ++++++++++++++++++++++-----
 tests/test_vivado.py          |  8 ++++++++
 3 files changed, 30 insertions(+), 39 deletions(-)

diff --git a/pyfpga/templates/vivado.jinja b/pyfpga/templates/vivado.jinja
index cfc6734b..d12942e2 100644
--- a/pyfpga/templates/vivado.jinja
+++ b/pyfpga/templates/vivado.jinja
@@ -8,38 +8,6 @@ set PROJECT  {{ PROJECT }}
 set PART     {{ PART }}
 set TOP      {{ TOP }}
 
-# proc fpga_file {FILE {LIBRARY "work"}} {
-#     set message "adding the file '$FILE'"
-#     if { $LIBRARY != "work" } { append message " (into the VHDL library '$LIBRARY')" }
-#     regexp -nocase {\.(\w*)$} $FILE -> ext
-#     if { $ext == "tcl" } {
-#         source $FILE
-#         return
-#     }
-#     if { $LIBRARY != "work" } {
-#         add_files $FILE
-#         set_property library $LIBRARY [get_files $FILE]
-#     } else {
-#         add_files $FILE
-#     }
-# }
-
-# proc fpga_include {PATH} {
-#     lappend INCLUDED $PATH
-#     # Verilog Included Files are NOT added
-#     set_property "include_dirs" $INCLUDED [current_fileset]
-# }
-
-# proc fpga_params {} {
-#     if { [llength $PARAMS] == 0 } { return }
-#     set assigns [list]
-#     foreach PARAM $PARAMS { lappend assigns [join $PARAM "="] }
-#     set obj [get_filesets sources_1]
-#     set_property "generic" "[join $assigns]" -objects $obj
-# }
-
-#--[ Project configuration ]---------------------------------------------------
-
 {% if CFG %}
 create_project -force $PROJECT
 set_property source_mgmt_mode None [current_project]
@@ -74,8 +42,6 @@ set_property top_arch {{ ARCH }} [current_fileset]
 close_project
 {% endif %}
 
-#--[ Design flow ]-------------------------------------------------------------
-
 {% if SYN or PAR or BIT %}
 open_project $PROJECT
 
diff --git a/pyfpga/vivado.py b/pyfpga/vivado.py
index 7c7c88b8..60a7fcf8 100644
--- a/pyfpga/vivado.py
+++ b/pyfpga/vivado.py
@@ -29,11 +29,28 @@ def _make_prepare(self, steps):
         if 'hooks' in self.data:
             for stage in self.data['hooks']:
                 context[stage.upper()] = '\n'.join(self.data['hooks'][stage])
-        # FILES
-        # DEFINES
-        # INCLUDES
-        # PARAMS
-        # ARCH
+        #     if { $LIBRARY != "work" } {
+        #         add_files $FILE
+        #         set_property library $LIBRARY [get_files $FILE]
+        #     } else {
+        #         add_files $FILE
+        if 'arch' in self.data:
+            context['ARCH'] = self.data['arch']
+        if 'defines' in self.data:
+            defines = []
+            for key,value in self.data['defines'].items():
+                defines.append(f'{key}={value}')
+            context['DEFINES'] = ' '.join(defines)
+        if 'includes' in self.data:
+            includes = []
+            for include in self.data['includes']:
+                includes.append(str(include))
+            context['INCLUDES'] = ' '.join(includes)
+        if 'params' in self.data:
+            params = []
+            for key,value in self.data['params'].items():
+                params.append(f'{key}={value}')
+            context['PARAMS'] = ' '.join(params)
         self._create_file('vivado', 'tcl', context)
 
     def _prog_prepare(self):
diff --git a/tests/test_vivado.py b/tests/test_vivado.py
index 1aa74916..9d6a2e34 100644
--- a/tests/test_vivado.py
+++ b/tests/test_vivado.py
@@ -3,6 +3,14 @@
 
 def test_vivado():
     prj = Vivado()
+
+    prj.set_arch('ARCHNAME')
+    prj.add_include('fakedata/dir1')
+    prj.add_include('fakedata/dir2')
+    prj.add_param('PARAM1', 'VALUE1')
+    prj.add_param('PARAM2', 'VALUE2')
+    prj.add_define('DEFINE1', 'VALUE1')
+    prj.add_define('DEFINE2', 'VALUE2')
     prj.add_hook('precfg', 'HOOK1')
     prj.add_hook('precfg', 'HOOK1')
     prj.add_hook('postcfg', 'HOOK2')

From 6824d99b46861f4d55d6d6e561a0ee806112568e Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 17 Jun 2024 19:32:37 -0300
Subject: [PATCH 078/248] Fixed linter issues

---
 pyfpga/vivado.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pyfpga/vivado.py b/pyfpga/vivado.py
index 60a7fcf8..597afceb 100644
--- a/pyfpga/vivado.py
+++ b/pyfpga/vivado.py
@@ -38,7 +38,7 @@ def _make_prepare(self, steps):
             context['ARCH'] = self.data['arch']
         if 'defines' in self.data:
             defines = []
-            for key,value in self.data['defines'].items():
+            for key, value in self.data['defines'].items():
                 defines.append(f'{key}={value}')
             context['DEFINES'] = ' '.join(defines)
         if 'includes' in self.data:
@@ -48,7 +48,7 @@ def _make_prepare(self, steps):
             context['INCLUDES'] = ' '.join(includes)
         if 'params' in self.data:
             params = []
-            for key,value in self.data['params'].items():
+            for key, value in self.data['params'].items():
                 params.append(f'{key}={value}')
             context['PARAMS'] = ' '.join(params)
         self._create_file('vivado', 'tcl', context)

From b178c922bce66bf27cfa0891cde9bb14dfe0d74d Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 17 Jun 2024 19:33:01 -0300
Subject: [PATCH 079/248] Added add_fileset, to be implemented

---
 pyfpga/project.py | 42 +++++++++++++++++++++++++++---------------
 1 file changed, 27 insertions(+), 15 deletions(-)

diff --git a/pyfpga/project.py b/pyfpga/project.py
index e71b550a..8fcd75ec 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -58,6 +58,21 @@ def set_part(self, name):
         self.logger.debug('Executing set_part')
         self.data['part'] = name
 
+    def add_include(self, path):
+        """Add an Include path.
+
+        Specify where to search for Included Verilog Files, IP repos, etc.
+
+        :param path: path of a directory
+        :type name: str
+        :raises NotADirectoryError: if path is not a directory
+        """
+        self.logger.debug('Executing add_include')
+        path = Path(path).resolve()
+        if not path.is_dir():
+            raise NotADirectoryError(path)
+        self.data.setdefault('includes', []).append(path)
+
     def _add_file(self, pathname, filetype=None, library=None, options=None):
         files = glob.glob(pathname)
         if len(files) == 0:
@@ -119,21 +134,6 @@ def add_vlog(self, pathname, options=None):
         self.logger.debug('Executing add_vlog')
         self._add_file(pathname, filetype='vlog', options=options)
 
-    def add_include(self, path):
-        """Add an Include path.
-
-        Specify where to search for Included Verilog Files, IP repos, etc.
-
-        :param path: path of a directory
-        :type name: str
-        :raises NotADirectoryError: if path is not a directory
-        """
-        self.logger.debug('Executing add_include')
-        path = Path(path).resolve()
-        if not path.is_dir():
-            raise NotADirectoryError(path)
-        self.data.setdefault('includes', []).append(path)
-
     def add_param(self, name, value):
         """Add a Parameter/Generic Value.
 
@@ -165,6 +165,18 @@ def set_arch(self, name):
         self.logger.debug('Executing set_arch')
         self.data['arch'] = name
 
+    def add_fileset(self, pathname):
+        """Add fileset file/s.
+
+        :param pathname: path to a fileset file
+        :type pathname: str
+        :raises FileNotFoundError: when pathname is not found
+        """
+        self.logger.debug('Executing add_fileset')
+        if not os.path.exists(pathname):
+            raise FileNotFoundError(pathname)
+        raise NotImplementedError()
+
     def set_top(self, name):
         """Set the name of the top level component.
 

From f77f21420e6bd4343b7388dfb5c511cc4f9e5433 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 17 Jun 2024 21:57:57 -0300
Subject: [PATCH 080/248] Slightly modified the internal data structure

---
 docs/internals.rst          | 14 +++++---
 pyfpga/project.py           | 66 +++++++++++++++++++------------------
 tests/fakedata/cons/all.xdc |  0
 tests/fakedata/cons/par.xdc |  0
 tests/fakedata/cons/syn.xdc |  0
 tests/test_data.py          | 40 +++++++++++-----------
 6 files changed, 64 insertions(+), 56 deletions(-)
 create mode 100644 tests/fakedata/cons/all.xdc
 create mode 100644 tests/fakedata/cons/par.xdc
 create mode 100644 tests/fakedata/cons/syn.xdc

diff --git a/docs/internals.rst b/docs/internals.rst
index 0ec8ded5..6bf036ea 100644
--- a/docs/internals.rst
+++ b/docs/internals.rst
@@ -40,12 +40,15 @@ Internal data structure
         'part': 'PARTNAME',
         'includes': ['DIR1', 'DIR2', 'DIR3'],
         'files': {
-            'file1': {'type': 'vhdl', 'options': 'OPT1', 'library': 'LIB1'},
-            'file2': {'type': 'vlog', 'options': 'OPT2', 'library': None},
-            'file3': {'type': 'slog', 'options': 'OPT3', 'library': None},
-            'file4': {'type': 'cons', 'options': 'OPT4', 'library': None}
+            'FILE1': ['vhdl', 'LIB1'],
+            'FILE2': ['vlog'],
+            'FILE3': ['slog']
+        },
+        'constraints': {
+            'FILE1': ['syn', 'par'],
+            'FILE2': ['syn'],
+            'FILE3': ['par']
         },
-        'top': 'TOPNAME',
         'params': {
             'PAR1': 'VAL1',
             'PAR2': 'VAL2',
@@ -57,6 +60,7 @@ Internal data structure
             'DEF3': 'VAL3'
         },
         'arch': 'ARCHNAME',
+        'top': 'TOPNAME',
         'hooks': {
             'precfg': ['CMD1', 'CMD2'],
             'postcfg': ['CMD1', 'CMD2'],
diff --git a/pyfpga/project.py b/pyfpga/project.py
index 8fcd75ec..b563ea38 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -73,66 +73,68 @@ def add_include(self, path):
             raise NotADirectoryError(path)
         self.data.setdefault('includes', []).append(path)
 
-    def _add_file(self, pathname, filetype=None, library=None, options=None):
-        files = glob.glob(pathname)
+    def _add_file(self, pathname, filetype=None, library=None):
+        files = glob.glob(pathname, recursive=True)
         if len(files) == 0:
             raise FileNotFoundError(pathname)
         for file in files:
             path = Path(file).resolve()
-            self.data.setdefault('files', {})[path] = {
-                'type': filetype, 'options': options, 'library': library
-            }
-
-    def add_cons(self, pathname):
-        """Add constraint file/s.
-
-        :param pathname: path to a constraint file (glob compliant)
-        :type pathname: str
-        :raises FileNotFoundError: when pathname is not found
-        """
-        self.logger.debug('Executing add_cons')
-        self._add_file(pathname, filetype='cons', options=None)
-
-    def add_slog(self, pathname, options=None):
+            attr = []
+            if filetype:
+                attr.append(filetype)
+            if library:
+                attr.append(library)
+            self.data.setdefault('files', {})[path] = attr
+
+    def add_slog(self, pathname):
         """Add System Verilog file/s.
 
         :param pathname: path to a SV file (glob compliant)
         :type pathname: str
-        :param options: for the underlying tool
-        :type options: str, optional
         :raises FileNotFoundError: when pathname is not found
         """
         self.logger.debug('Executing add_slog')
-        self._add_file(pathname, filetype='slog', options=options)
+        self._add_file(pathname, 'slog')
 
-    def add_vhdl(self, pathname, library=None, options=None):
+    def add_vhdl(self, pathname, library=None):
         """Add VHDL file/s.
 
         :param pathname: path to a SV file (glob compliant)
         :type pathname: str
         :param library: VHDL library name
         :type library: str, optional
-        :param options: for the underlying tool
-        :type options: str, optional
         :raises FileNotFoundError: when pathname is not found
         """
         self.logger.debug('Executing add_vhdl')
-        self._add_file(
-            pathname, filetype='vhdl',
-            library=library, options=options
-        )
+        self._add_file(pathname, 'vhdl', library)
 
-    def add_vlog(self, pathname, options=None):
+    def add_vlog(self, pathname):
         """Add Verilog file/s.
 
         :param pathname: path to a SV file (glob compliant)
         :type pathname: str
-        :param options: for the underlying tool
-        :type options: str, optional
         :raises FileNotFoundError: when pathname is not found
         """
         self.logger.debug('Executing add_vlog')
-        self._add_file(pathname, filetype='vlog', options=options)
+        self._add_file(pathname, 'vlog')
+
+    def add_constraint(self, path, syn=True, par=True):
+        """Add a constraint file.
+
+        :param pathname: path of a file
+        :type pathname: str
+        :raises FileNotFoundError: if path is not found
+        """
+        self.logger.debug('Executing add_constraint')
+        path = Path(path).resolve()
+        if not path.is_file():
+            raise FileNotFoundError(path)
+        attr = []
+        if syn:
+            attr.append('syn')
+        if par:
+            attr.append('par')
+        self.data.setdefault('constraints', {})[path] = attr
 
     def add_param(self, name, value):
         """Add a Parameter/Generic Value.
@@ -213,7 +215,7 @@ def make(self, last='bit', first='cfg'):
         :param first: first step
         :type first: str, optional
 
-        .. note:: valid steps are ``cfg``, ``syn``, ``imp`` and ``bit``.
+        .. note:: valid steps are ``cfg``, ``syn``, ``par`` and ``bit``.
         """
         steps = ['cfg', 'syn', 'par', 'bit']
         if last not in steps:
diff --git a/tests/fakedata/cons/all.xdc b/tests/fakedata/cons/all.xdc
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/fakedata/cons/par.xdc b/tests/fakedata/cons/par.xdc
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/fakedata/cons/syn.xdc b/tests/fakedata/cons/syn.xdc
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/test_data.py b/tests/test_data.py
index 0994d9db..2b2324a1 100644
--- a/tests/test_data.py
+++ b/tests/test_data.py
@@ -10,24 +10,23 @@
         Path('fakedata/dir3').resolve()
     ],
     'files': {
-        Path('fakedata/dir1/slog1.sv').resolve():
-            {'type': 'slog', 'options': None, 'library': None},
-        Path('fakedata/dir2/slog2.sv').resolve():
-            {'type': 'slog', 'options': None, 'library': None},
-        Path('fakedata/dir3/slog3.sv').resolve():
-            {'type': 'slog', 'options': None, 'library': None},
-        Path('fakedata/dir1/vhdl1.vhdl').resolve():
-            {'type': 'vhdl', 'options': None, 'library': None},
-        Path('fakedata/dir2/vhdl2.vhdl').resolve():
-            {'type': 'vhdl', 'options': None, 'library': None},
-        Path('fakedata/dir3/vhdl3.vhdl').resolve():
-            {'type': 'vhdl', 'options': None, 'library': None},
-        Path('fakedata/dir1/vlog1.v').resolve():
-            {'type': 'vlog', 'options': None, 'library': None},
-        Path('fakedata/dir2/vlog2.v').resolve():
-            {'type': 'vlog', 'options': None, 'library': None},
-        Path('fakedata/dir3/vlog3.v').resolve():
-            {'type': 'vlog', 'options': None, 'library': None}
+        Path('fakedata/vhdl0.vhdl').resolve(): ['vhdl', 'LIB'],
+        Path('fakedata/dir1/vhdl1.vhdl').resolve(): ['vhdl', 'LIB'],
+        Path('fakedata/dir2/vhdl2.vhdl').resolve(): ['vhdl', 'LIB'],
+        Path('fakedata/dir3/vhdl3.vhdl').resolve(): ['vhdl', 'LIB'],
+        Path('fakedata/vlog0.v').resolve(): ['vlog'],
+        Path('fakedata/dir1/vlog1.v').resolve(): ['vlog'],
+        Path('fakedata/dir2/vlog2.v').resolve(): ['vlog'],
+        Path('fakedata/dir3/vlog3.v').resolve(): ['vlog'],
+        Path('fakedata/slog0.sv').resolve(): ['slog'],
+        Path('fakedata/dir1/slog1.sv').resolve(): ['slog'],
+        Path('fakedata/dir2/slog2.sv').resolve(): ['slog'],
+        Path('fakedata/dir3/slog3.sv').resolve(): ['slog']
+    },
+    'constraints': {
+        Path('fakedata/cons/all.xdc').resolve(): ['syn', 'par'],
+        Path('fakedata/cons/syn.xdc').resolve(): ['syn'],
+        Path('fakedata/cons/par.xdc').resolve(): ['par']
     },
     'top': 'TOPNAME',
     'params': {
@@ -63,8 +62,11 @@ def test_data():
     prj.add_include('fakedata/dir2')
     prj.add_include('fakedata/dir3')
     prj.add_slog('fakedata/**/*.sv')
-    prj.add_vhdl('fakedata/**/*.vhdl')
+    prj.add_vhdl('fakedata/**/*.vhdl', 'LIB')
     prj.add_vlog('fakedata/**/*.v')
+    prj.add_constraint('fakedata/cons/all.xdc')
+    prj.add_constraint('fakedata/cons/syn.xdc', True, False)
+    prj.add_constraint('fakedata/cons/par.xdc', False, True)
     prj.add_param('PAR1', 'VAL1')
     prj.add_param('PAR2', 'VAL2')
     prj.add_param('PAR3', 'VAL3')

From b17a2004318ee142590896c8e2794bfa2cc2a670 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Thu, 20 Jun 2024 17:52:37 -0300
Subject: [PATCH 081/248] More small adjustments in the internal data structure

---
 docs/internals.rst | 14 ++++++-------
 pyfpga/project.py  | 50 +++++++++++++++++++++++++++-------------------
 tests/test_data.py | 42 +++++++++++++++++++++-----------------
 3 files changed, 61 insertions(+), 45 deletions(-)

diff --git a/docs/internals.rst b/docs/internals.rst
index 6bf036ea..910df99a 100644
--- a/docs/internals.rst
+++ b/docs/internals.rst
@@ -40,14 +40,15 @@ Internal data structure
         'part': 'PARTNAME',
         'includes': ['DIR1', 'DIR2', 'DIR3'],
         'files': {
-            'FILE1': ['vhdl', 'LIB1'],
-            'FILE2': ['vlog'],
-            'FILE3': ['slog']
+            'FILE1': {'hdl': 'vhdl', 'lib': 'LIB1'}
+            'FILE2': {'hdl': 'vlog'},
+            'FILE3': {'hdl': 'slog'}
         },
+        'top': 'TOPNAME',
         'constraints': {
-            'FILE1': ['syn', 'par'],
-            'FILE2': ['syn'],
-            'FILE3': ['par']
+            'FILE1': 'all',
+            'FILE2': 'syn',
+            'FILE3': 'par'
         },
         'params': {
             'PAR1': 'VAL1',
@@ -60,7 +61,6 @@ Internal data structure
             'DEF3': 'VAL3'
         },
         'arch': 'ARCHNAME',
-        'top': 'TOPNAME',
         'hooks': {
             'precfg': ['CMD1', 'CMD2'],
             'postcfg': ['CMD1', 'CMD2'],
diff --git a/pyfpga/project.py b/pyfpga/project.py
index b563ea38..d7758ad0 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -23,12 +23,10 @@
 class Project:
     """Base class to manage an FPGA project.
 
-    :param name: project name (tool name by default)
+    :param name: project name (tool name when nothing specified)
     :type name: str, optional
     :param odir: output directory
     :type odir: str, optional
-    :raises ValueError: when an invalid value is specified
-    :raises RuntimeError: when the needed underlying tool is not available
     """
 
     tool = {}
@@ -73,17 +71,17 @@ def add_include(self, path):
             raise NotADirectoryError(path)
         self.data.setdefault('includes', []).append(path)
 
-    def _add_file(self, pathname, filetype=None, library=None):
+    def _add_file(self, pathname, hdl=None, lib=None):
         files = glob.glob(pathname, recursive=True)
         if len(files) == 0:
             raise FileNotFoundError(pathname)
         for file in files:
             path = Path(file).resolve()
-            attr = []
-            if filetype:
-                attr.append(filetype)
-            if library:
-                attr.append(library)
+            attr = {}
+            if hdl:
+                attr['hdl'] = hdl
+            if lib:
+                attr['lib'] = lib
             self.data.setdefault('files', {})[path] = attr
 
     def add_slog(self, pathname):
@@ -96,17 +94,17 @@ def add_slog(self, pathname):
         self.logger.debug('Executing add_slog')
         self._add_file(pathname, 'slog')
 
-    def add_vhdl(self, pathname, library=None):
+    def add_vhdl(self, pathname, lib=None):
         """Add VHDL file/s.
 
         :param pathname: path to a SV file (glob compliant)
         :type pathname: str
-        :param library: VHDL library name
-        :type library: str, optional
+        :param lib: VHDL library name
+        :type lib: str, optional
         :raises FileNotFoundError: when pathname is not found
         """
         self.logger.debug('Executing add_vhdl')
-        self._add_file(pathname, 'vhdl', library)
+        self._add_file(pathname, 'vhdl', lib)
 
     def add_vlog(self, pathname):
         """Add Verilog file/s.
@@ -118,23 +116,22 @@ def add_vlog(self, pathname):
         self.logger.debug('Executing add_vlog')
         self._add_file(pathname, 'vlog')
 
-    def add_constraint(self, path, syn=True, par=True):
+    def add_constraint(self, path, when='all'):
         """Add a constraint file.
 
         :param pathname: path of a file
         :type pathname: str
+        :param when: always ('all'), synthesis ('syn') or P&R ('par')
+        :type only: str, optional
         :raises FileNotFoundError: if path is not found
         """
         self.logger.debug('Executing add_constraint')
         path = Path(path).resolve()
         if not path.is_file():
             raise FileNotFoundError(path)
-        attr = []
-        if syn:
-            attr.append('syn')
-        if par:
-            attr.append('par')
-        self.data.setdefault('constraints', {})[path] = attr
+        if when not in ['all', 'syn', 'par']:
+            raise ValueError('Invalid only.')
+        self.data.setdefault('constraints', {})[path] = when
 
     def add_param(self, name, value):
         """Add a Parameter/Generic Value.
@@ -199,6 +196,7 @@ def add_hook(self, stage, hook):
         :type hook: str
         :raises ValueError: when stage is invalid
         """
+        self.logger.debug('Executing add_hook')
         stages = [
             'precfg', 'postcfg', 'presyn', 'postsyn',
             'prepar', 'postpar', 'prebit', 'postbit'
@@ -214,9 +212,18 @@ def make(self, last='bit', first='cfg'):
         :type last: str, optional
         :param first: first step
         :type first: str, optional
+        :raises ValueError: for missing or wrong values
+        :raises RuntimeError: when the needed underlying tool is not found
 
         .. note:: valid steps are ``cfg``, ``syn``, ``par`` and ``bit``.
         """
+        self.logger.debug('Executing make')
+        if 'part' not in self.data:
+            self.logger.info('No part specified, using a default value')
+        if 'top' not in self.data:
+            self.logger.warning('No top specified')
+        if 'files' not in self.data:
+            self.logger.warning('No files specified')
         steps = ['cfg', 'syn', 'par', 'bit']
         if last not in steps:
             raise ValueError('Invalid last step.')
@@ -239,7 +246,10 @@ def prog(self, bitstream=None, position=1):
         :type bitstream: str, optional
         :param position: position of the device in the JTAG chain
         :type position: str, optional
+        :raises ValueError: for missing or wrong values
+        :raises RuntimeError: when the needed underlying tool is not found
         """
+        self.logger.debug('Executing prog')
         if position not in range(1, 9):
             raise ValueError('Invalid position.')
         _ = bitstream
diff --git a/tests/test_data.py b/tests/test_data.py
index 2b2324a1..c4a355c0 100644
--- a/tests/test_data.py
+++ b/tests/test_data.py
@@ -10,25 +10,31 @@
         Path('fakedata/dir3').resolve()
     ],
     'files': {
-        Path('fakedata/vhdl0.vhdl').resolve(): ['vhdl', 'LIB'],
-        Path('fakedata/dir1/vhdl1.vhdl').resolve(): ['vhdl', 'LIB'],
-        Path('fakedata/dir2/vhdl2.vhdl').resolve(): ['vhdl', 'LIB'],
-        Path('fakedata/dir3/vhdl3.vhdl').resolve(): ['vhdl', 'LIB'],
-        Path('fakedata/vlog0.v').resolve(): ['vlog'],
-        Path('fakedata/dir1/vlog1.v').resolve(): ['vlog'],
-        Path('fakedata/dir2/vlog2.v').resolve(): ['vlog'],
-        Path('fakedata/dir3/vlog3.v').resolve(): ['vlog'],
-        Path('fakedata/slog0.sv').resolve(): ['slog'],
-        Path('fakedata/dir1/slog1.sv').resolve(): ['slog'],
-        Path('fakedata/dir2/slog2.sv').resolve(): ['slog'],
-        Path('fakedata/dir3/slog3.sv').resolve(): ['slog']
+        Path('fakedata/vhdl0.vhdl').resolve(): {'hdl': 'vhdl', 'lib': 'LIB'},
+        Path('fakedata/dir1/vhdl1.vhdl').resolve(): {
+            'hdl': 'vhdl', 'lib': 'LIB'
+        },
+        Path('fakedata/dir2/vhdl2.vhdl').resolve(): {
+            'hdl': 'vhdl', 'lib': 'LIB'
+        },
+        Path('fakedata/dir3/vhdl3.vhdl').resolve(): {
+            'hdl': 'vhdl', 'lib': 'LIB'
+        },
+        Path('fakedata/vlog0.v').resolve(): {'hdl': 'vlog'},
+        Path('fakedata/dir1/vlog1.v').resolve(): {'hdl': 'vlog'},
+        Path('fakedata/dir2/vlog2.v').resolve(): {'hdl': 'vlog'},
+        Path('fakedata/dir3/vlog3.v').resolve(): {'hdl': 'vlog'},
+        Path('fakedata/slog0.sv').resolve(): {'hdl': 'slog'},
+        Path('fakedata/dir1/slog1.sv').resolve(): {'hdl': 'slog'},
+        Path('fakedata/dir2/slog2.sv').resolve(): {'hdl': 'slog'},
+        Path('fakedata/dir3/slog3.sv').resolve(): {'hdl': 'slog'}
     },
+    'top': 'TOPNAME',
     'constraints': {
-        Path('fakedata/cons/all.xdc').resolve(): ['syn', 'par'],
-        Path('fakedata/cons/syn.xdc').resolve(): ['syn'],
-        Path('fakedata/cons/par.xdc').resolve(): ['par']
+        Path('fakedata/cons/all.xdc').resolve(): 'all',
+        Path('fakedata/cons/syn.xdc').resolve(): 'syn',
+        Path('fakedata/cons/par.xdc').resolve(): 'par'
     },
-    'top': 'TOPNAME',
     'params': {
         'PAR1': 'VAL1',
         'PAR2': 'VAL2',
@@ -65,8 +71,8 @@ def test_data():
     prj.add_vhdl('fakedata/**/*.vhdl', 'LIB')
     prj.add_vlog('fakedata/**/*.v')
     prj.add_constraint('fakedata/cons/all.xdc')
-    prj.add_constraint('fakedata/cons/syn.xdc', True, False)
-    prj.add_constraint('fakedata/cons/par.xdc', False, True)
+    prj.add_constraint('fakedata/cons/syn.xdc', 'syn')
+    prj.add_constraint('fakedata/cons/par.xdc', 'par')
     prj.add_param('PAR1', 'VAL1')
     prj.add_param('PAR2', 'VAL2')
     prj.add_param('PAR3', 'VAL3')

From 2c087d6a74a71252f39a3984801624a586c4d341 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Thu, 20 Jun 2024 17:54:15 -0300
Subject: [PATCH 082/248] Finished implementation of _make_prepare for Vivado

---
 pyfpga/templates/vivado.jinja | 33 ++++++++++----------
 pyfpga/vivado.py              | 58 +++++++++++++++++++++++++----------
 tests/test_vivado.py          | 41 ++++++++++++-------------
 3 files changed, 78 insertions(+), 54 deletions(-)

diff --git a/pyfpga/templates/vivado.jinja b/pyfpga/templates/vivado.jinja
index d12942e2..05b1f0fa 100644
--- a/pyfpga/templates/vivado.jinja
+++ b/pyfpga/templates/vivado.jinja
@@ -4,37 +4,36 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-set PROJECT  {{ PROJECT }}
-set PART     {{ PART }}
-set TOP      {{ TOP }}
+#--[ Project configuration ]--------------------------------------------------
 
 {% if CFG %}
-create_project -force $PROJECT
-set_property source_mgmt_mode None [current_project]
+create_project -force {{ PROJECT }}
+set_property SOURCE_MGMT_MODE None [current_project]
 set_property STEPS.SYNTH_DESIGN.ARGS.ASSERT true [get_runs synth_1]
-
-set_property part $PART [current_project]
+set_property PART {{ PART }} [current_project]
 
 {{ PRECFG }}
 
 {{ FILES }}
 
-set_property top $TOP [current_fileset]
+{% if TOP %}
+set_property TOP {{ TOP }} [current_fileset]
+{% endif %}
 
 {% if DEFINES %}
-set_property verilog_define { {{ DEFINES}} } [current_fileset]
+set_property VERILOG_DEFINE { {{ DEFINES}} } [current_fileset]
 {% endif %}
 
 {% if INCLUDES %}
-set_property include_dirs { {{ INCLUDES}} } [current_fileset]
+set_property INCLUDE_DIRS { {{ INCLUDES}} } [current_fileset]
 {% endif %}
 
 {% if PARAMS %}
-set_property generic { {{ PARAMS }} } -objects [get_filesets sources_1]
+set_property GENERIC { {{ PARAMS }} } -objects [get_filesets sources_1]
 {% endif %}
 
 {% if ARCH %}
-set_property top_arch {{ ARCH }} [current_fileset]
+set_property TOP_ARCH {{ ARCH }} [current_fileset]
 {% endif %}
 
 {{ POSTCFG }}
@@ -42,14 +41,16 @@ set_property top_arch {{ ARCH }} [current_fileset]
 close_project
 {% endif %}
 
+#--[ Design flow ]-------------------------------------------------------------
+
 {% if SYN or PAR or BIT %}
-open_project $PROJECT
+open_project {{ PROJECT }}
 
 {% if SYN %}
 {{ PRESYN }}
 
 # PRESYNTH
-# set_property design_mode GateLvl [current_fileset]
+# set_property DESIGN_MODE GateLvl [current_fileset]
 reset_run synth_1
 launch_runs synth_1
 wait_on_run synth_1
@@ -71,8 +72,8 @@ wait_on_run impl_1
 {{ PREBIT }}
 
 open_run impl_1
-write_bitstream -force $PROJECT
-write_debug_probes -force -quiet $PROJECT.ltx
+write_bitstream -force {{ PROJECT }}
+write_debug_probes -force -quiet {{ PROJECT }}.ltx
 
 {{ POSTBIT }}
 {% endif %}
diff --git a/pyfpga/vivado.py b/pyfpga/vivado.py
index 597afceb..d776b52a 100644
--- a/pyfpga/vivado.py
+++ b/pyfpga/vivado.py
@@ -8,6 +8,9 @@
 Implements support for Vivado.
 """
 
+# pylint: disable=too-many-locals
+# pylint: disable=too-many-branches
+
 from pyfpga.project import Project
 
 
@@ -21,36 +24,57 @@ def _make_prepare(self, steps):
         )
         context = {
             'PROJECT': self.name or 'vivado',
-            'PART': self.data.get('part', 'xc7k160t-3-fbg484'),
-            'TOP': self.data.get('top', 'top')
+            'PART': self.data.get('part', 'xc7k160t-3-fbg484')
         }
         for step in steps:
             context[step] = 1
-        if 'hooks' in self.data:
-            for stage in self.data['hooks']:
-                context[stage.upper()] = '\n'.join(self.data['hooks'][stage])
-        #     if { $LIBRARY != "work" } {
-        #         add_files $FILE
-        #         set_property library $LIBRARY [get_files $FILE]
-        #     } else {
-        #         add_files $FILE
-        if 'arch' in self.data:
-            context['ARCH'] = self.data['arch']
-        if 'defines' in self.data:
-            defines = []
-            for key, value in self.data['defines'].items():
-                defines.append(f'{key}={value}')
-            context['DEFINES'] = ' '.join(defines)
         if 'includes' in self.data:
             includes = []
             for include in self.data['includes']:
                 includes.append(str(include))
             context['INCLUDES'] = ' '.join(includes)
+        files = []
+        if 'files' in self.data:
+            for file in self.data['files']:
+                files.append(f'add_file {file}')
+            for file in self.data['files']:
+                if 'lib' in self.data['files'][file]:
+                    lib = self.data['files'][file]['lib']
+                    files.append(
+                        f'set_property library {lib} [get_files {file}]'
+                    )
+        if 'constraints' in self.data:
+            for file in self.data['constraints']:
+                files.append(f'add_file -fileset constrs_1 {file}')
+            for file in self.data['constraints']:
+                if self.data['constraints'][file] == 'syn':
+                    prop = 'USED_IN_IMPLEMENTATION FALSE'
+                if self.data['constraints'][file] == 'syn':
+                    prop = 'USED_IN_SYNTHESIS FALSE'
+                if self.data['constraints'][file] != 'all':
+                    files.append(f'set_property {prop} [get_files {file}]')
+            first = next(iter(self.data['constraints']))
+            prop = f'TARGET_CONSTRS_FILE {first}'
+            files.append(f'set_property {prop} [current_fileset -constrset]')
+        if files:
+            context['FILES'] = '\n'.join(files)
+        if 'top' in self.data:
+            context['TOP'] = self.data['top']
+        if 'defines' in self.data:
+            defines = []
+            for key, value in self.data['defines'].items():
+                defines.append(f'{key}={value}')
+            context['DEFINES'] = ' '.join(defines)
         if 'params' in self.data:
             params = []
             for key, value in self.data['params'].items():
                 params.append(f'{key}={value}')
             context['PARAMS'] = ' '.join(params)
+        if 'arch' in self.data:
+            context['ARCH'] = self.data['arch']
+        if 'hooks' in self.data:
+            for stage in self.data['hooks']:
+                context[stage.upper()] = '\n'.join(self.data['hooks'][stage])
         self._create_file('vivado', 'tcl', context)
 
     def _prog_prepare(self):
diff --git a/tests/test_vivado.py b/tests/test_vivado.py
index 9d6a2e34..9afa353d 100644
--- a/tests/test_vivado.py
+++ b/tests/test_vivado.py
@@ -3,28 +3,27 @@
 
 def test_vivado():
     prj = Vivado()
-
+    prj.set_part('PARTNAME')
+    prj.set_top('TOPNAME')
     prj.set_arch('ARCHNAME')
     prj.add_include('fakedata/dir1')
     prj.add_include('fakedata/dir2')
-    prj.add_param('PARAM1', 'VALUE1')
-    prj.add_param('PARAM2', 'VALUE2')
-    prj.add_define('DEFINE1', 'VALUE1')
-    prj.add_define('DEFINE2', 'VALUE2')
-    prj.add_hook('precfg', 'HOOK1')
-    prj.add_hook('precfg', 'HOOK1')
-    prj.add_hook('postcfg', 'HOOK2')
-    prj.add_hook('postcfg', 'HOOK2')
-    prj.add_hook('presyn', 'HOOK3')
-    prj.add_hook('presyn', 'HOOK3')
-    prj.add_hook('postsyn', 'HOOK4')
-    prj.add_hook('postsyn', 'HOOK4')
-    prj.add_hook('prepar', 'HOOK5')
-    prj.add_hook('prepar', 'HOOK5')
-    prj.add_hook('postpar', 'HOOK6')
-    prj.add_hook('postpar', 'HOOK6')
-    prj.add_hook('prebit', 'HOOK7')
-    prj.add_hook('prebit', 'HOOK7')
-    prj.add_hook('postbit', 'HOOK8')
-    prj.add_hook('postbit', 'HOOK8')
+    prj.add_slog('fakedata/**/*.sv')
+    prj.add_vhdl('fakedata/**/*.vhdl', 'LIB')
+    prj.add_vlog('fakedata/**/*.v')
+    prj.add_constraint('fakedata/cons/all.xdc')
+    prj.add_constraint('fakedata/cons/syn.xdc', 'syn')
+    prj.add_constraint('fakedata/cons/par.xdc', 'par')
+    prj.add_param('PAR1', 'VAL1')
+    prj.add_param('PAR2', 'VAL2')
+    prj.add_define('DEF1', 'VAL1')
+    prj.add_define('DEF2', 'VAL2')
+    prj.add_hook('precfg', 'PRECFG_HOOK')
+    prj.add_hook('postcfg', 'POSTCFG_HOOK')
+    prj.add_hook('presyn', 'PRESYN_HOOK')
+    prj.add_hook('postsyn', 'POSTSYN_HOOK')
+    prj.add_hook('prepar', 'PREPAR_HOOK')
+    prj.add_hook('postpar', 'POSTPAR_HOOK')
+    prj.add_hook('prebit', 'PREBIT_HOOK')
+    prj.add_hook('postbit', 'POSTBIT_HOOK')
     prj.make()

From cf2011395d27146849a1ee392a74157d3fa79b35 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Thu, 20 Jun 2024 18:22:36 -0300
Subject: [PATCH 083/248] Moved submodule 'resources' to 'examples/resources'

---
 .gitmodules                     | 6 +++---
 Makefile                        | 4 ++--
 resources => examples/resources | 0
 3 files changed, 5 insertions(+), 5 deletions(-)
 rename resources => examples/resources (100%)

diff --git a/.gitmodules b/.gitmodules
index 362bc8ae..cba0ef31 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,3 @@
-[submodule "resources"]
-	path = resources
-	url = https://github.com/PyFPGA/resources
+[submodule "examples/resources"]
+	path = examples/resources
+	url = git@github.com:PyFPGA/resources.git
diff --git a/Makefile b/Makefile
index 9c8032b2..f9eda4cb 100644
--- a/Makefile
+++ b/Makefile
@@ -19,7 +19,7 @@ clean:
 	rm -fr build .pytest_cache
 
 submodule-init:
-	git submodule update --init
+	git submodule update --init --recursive
 
 submodule-update:
-	cd resources; git checkout main; git pull
+	cd examples/resources; git checkout main; git pull
diff --git a/resources b/examples/resources
similarity index 100%
rename from resources
rename to examples/resources

From 0d6ad2acc173cca47374848a4d5b320cfaebb653 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Thu, 20 Jun 2024 18:36:11 -0300
Subject: [PATCH 084/248] Removed 'hdl', superseded by 'examples/resources'

---
 examples/resources      |  2 +-
 hdl/blinking.v          | 28 ------------------
 hdl/blinking.vhdl       | 33 ---------------------
 hdl/data/memory.dat     | 64 -----------------------------------------
 hdl/examples_pkg.vhdl   | 17 -----------
 hdl/fakes/generics.vhdl | 41 --------------------------
 hdl/fakes/parameters.v  | 51 --------------------------------
 hdl/fakes/top.v         | 10 -------
 hdl/fakes/top.vhdl      |  5 ----
 hdl/headers1/freq.vh    |  1 -
 hdl/headers2/secs.vh    |  1 -
 hdl/ram.v               | 21 --------------
 hdl/ram.vhdl            | 45 -----------------------------
 hdl/top.v               | 11 -------
 hdl/top.vhdl            | 21 --------------
 15 files changed, 1 insertion(+), 350 deletions(-)
 delete mode 100644 hdl/blinking.v
 delete mode 100644 hdl/blinking.vhdl
 delete mode 100644 hdl/data/memory.dat
 delete mode 100644 hdl/examples_pkg.vhdl
 delete mode 100644 hdl/fakes/generics.vhdl
 delete mode 100644 hdl/fakes/parameters.v
 delete mode 100644 hdl/fakes/top.v
 delete mode 100644 hdl/fakes/top.vhdl
 delete mode 100644 hdl/headers1/freq.vh
 delete mode 100644 hdl/headers2/secs.vh
 delete mode 100644 hdl/ram.v
 delete mode 100644 hdl/ram.vhdl
 delete mode 100644 hdl/top.v
 delete mode 100644 hdl/top.vhdl

diff --git a/examples/resources b/examples/resources
index 6a58bba3..53d36f1d 160000
--- a/examples/resources
+++ b/examples/resources
@@ -1 +1 @@
-Subproject commit 6a58bba3b1c36d238d1111e910db02f0b284aef7
+Subproject commit 53d36f1d9d49b26e42d09aaf1e0e6c6fac7736e2
diff --git a/hdl/blinking.v b/hdl/blinking.v
deleted file mode 100644
index f8bf669c..00000000
--- a/hdl/blinking.v
+++ /dev/null
@@ -1,28 +0,0 @@
-`include "freq.vh"
-`include "secs.vh"
-
-module Blinking #(
-   parameter FREQ = `DEFAULT_FREQ,
-   parameter SECS = `DEFAULT_SECS
-)(
-   input  wire clk_i,
-   output wire led_o
-);
-
-localparam DIV = FREQ*SECS;
-
-reg                 led;
-reg [$clog2(DIV)-1:0] cnt = 0;
-
-always @(posedge clk_i) begin
-   if (cnt == DIV-1) begin
-      cnt = 0;
-      led <= ~led;
-   end else begin
-      cnt = cnt + 1;
-   end
-end
-
-assign led_o = led;
-
-endmodule
diff --git a/hdl/blinking.vhdl b/hdl/blinking.vhdl
deleted file mode 100644
index a50fbbbc..00000000
--- a/hdl/blinking.vhdl
+++ /dev/null
@@ -1,33 +0,0 @@
-library IEEE;
-use IEEE.std_logic_1164.all;
-
-entity Blinking is
-   generic (
-      FREQ  : positive:=25e6;
-      SECS  : positive:=1
-   );
-   port (
-      clk_i :  in std_logic;
-      led_o : out std_logic
-   );
-end entity Blinking;
-
-architecture RTL of Blinking is
-   constant DIV : positive:=FREQ*SECS-1;
-   signal   led : std_logic;
-begin
-   blink:
-   process (clk_i)
-      variable cnt: natural range 0 to DIV:=0;
-   begin
-      if rising_edge(clk_i) then
-         if cnt=DIV then
-            cnt:=0;
-            led <= not(led);
-         else
-            cnt:=cnt+1;
-         end if;
-      end if;
-   end process blink;
-   led_o <= led;
-end architecture RTL;
diff --git a/hdl/data/memory.dat b/hdl/data/memory.dat
deleted file mode 100644
index a7dda8d9..00000000
--- a/hdl/data/memory.dat
+++ /dev/null
@@ -1,64 +0,0 @@
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
-00000000000000000000000000000000
diff --git a/hdl/examples_pkg.vhdl b/hdl/examples_pkg.vhdl
deleted file mode 100644
index 3f15f041..00000000
--- a/hdl/examples_pkg.vhdl
+++ /dev/null
@@ -1,17 +0,0 @@
-library IEEE;
-use IEEE.std_logic_1164.all;
-
-package Examples is
-
-   component Blinking is
-      generic (
-         FREQ  : positive:=25e6;
-         SECS  : positive:=1
-      );
-      port (
-         clk_i :  in std_logic;
-         led_o : out std_logic
-      );
-   end component Blinking;
-
-end package Examples;
diff --git a/hdl/fakes/generics.vhdl b/hdl/fakes/generics.vhdl
deleted file mode 100644
index 4e010ebc..00000000
--- a/hdl/fakes/generics.vhdl
+++ /dev/null
@@ -1,41 +0,0 @@
-library IEEE;
-use IEEE.std_logic_1164.all;
-use IEEE.numeric_std.all;
-
-entity Params is
-   generic (
-      BOO : boolean:=FALSE;
-      INT : integer:=0;
-      LOG : std_logic:='0';
-      VEC : std_logic_vector(7 downto 0):="00000000";
-      STR : string:="ABCD";
-      REA : real:=0.0
-   );
-   port (
-      boo_o : out std_logic;
-      int_o : out std_logic_vector(7 downto 0);
-      log_o : out std_logic;
-      vec_o : out std_logic_vector(7 downto 0);
-      str_o : out std_logic;
-      rea_o : out std_logic
-   );
-end entity Params;
-
-architecture RTL of Params is
-begin
-
-   assert BOO=True       report "The boolean is not True" severity failure;
-   assert INT=255        report "The integer is not 255" severity failure;
-   assert LOG='1'        report "The std_logic is not '1'" severity failure;
-   assert VEC="11111111" report "The std_logic_vector is not 11111111" severity failure;
-   assert STR="WXYZ"     report "The string is not WXYZ" severity failure;
-   assert REA=1.1        report "The real is not 1.1" severity failure;
-
-   boo_o <= '1' when BOO else '0';
-   int_o <= std_logic_vector(to_unsigned(INT, 8));
-   log_o <= LOG;
-   vec_o <= VEC;
-   str_o <= '1' when STR="WXYZ" else '0';
-   rea_o <= '1' when REA=1.1 else '0';
-
-end architecture RTL;
diff --git a/hdl/fakes/parameters.v b/hdl/fakes/parameters.v
deleted file mode 100644
index 9dd81c51..00000000
--- a/hdl/fakes/parameters.v
+++ /dev/null
@@ -1,51 +0,0 @@
-module Params #(
-   parameter BOO = 0,
-   parameter INT = 0,
-   parameter LOG = 1'b0,
-   parameter VEC = 8'd0,
-   parameter STR = "ABCD",
-   parameter REA = 0.0
-)(
-   output wire boo_o,
-   output wire [7:0] int_o,
-   output wire log_o,
-   output wire [7:0] vec_o,
-   output wire str_o,
-   output wire rea_o
-);
-
-   initial begin
-      if (BOO != 1) begin
-         $display("The boolean is not True");
-         $finish;
-      end
-      if (INT != 255) begin
-         $display("The integer is not 255");
-         $finish;
-      end
-      if (LOG != 1) begin
-         $display("The std_logic is not '1'");
-         $finish;
-      end
-      if (VEC != 8'b11111111) begin
-         $display("The std_logic_vector is not 11111111");
-         $finish;
-      end
-      if (STR != "WXYZ") begin
-         $display("The string is not WXYZ");
-         $finish;
-      end
-      if (REA != 1.1) begin
-         $display("The real is not 1.1");
-         $finish;
-      end
-   end
-
-   assign boo_o = BOO;
-   assign int_o = INT;
-   assign log_o = LOG;
-   assign vec_o = VEC;
-   assign str_o = (STR=="WXYZ") ? 1'b1 : 1'b0;
-   assign rea_o = (REA==1.1) ? 1'b1 : 1'b0;
-
-endmodule
diff --git a/hdl/fakes/top.v b/hdl/fakes/top.v
deleted file mode 100644
index 3bc0b7c1..00000000
--- a/hdl/fakes/top.v
+++ /dev/null
@@ -1,10 +0,0 @@
-module Top1 ();
-endmodule
-
-// module Top2 ();
-// endmodule
-
-/*
-module Top3 ();
-endmodule
-*/
diff --git a/hdl/fakes/top.vhdl b/hdl/fakes/top.vhdl
deleted file mode 100644
index 01063ae8..00000000
--- a/hdl/fakes/top.vhdl
+++ /dev/null
@@ -1,5 +0,0 @@
-entity Top1 is
-end entity Top1;
-
--- entity Top2 is
--- end entity Top1;
diff --git a/hdl/headers1/freq.vh b/hdl/headers1/freq.vh
deleted file mode 100644
index 2b27b844..00000000
--- a/hdl/headers1/freq.vh
+++ /dev/null
@@ -1 +0,0 @@
-`define DEFAULT_FREQ 25000000
diff --git a/hdl/headers2/secs.vh b/hdl/headers2/secs.vh
deleted file mode 100644
index aa252d2f..00000000
--- a/hdl/headers2/secs.vh
+++ /dev/null
@@ -1 +0,0 @@
-`define DEFAULT_SECS 1
diff --git a/hdl/ram.v b/hdl/ram.v
deleted file mode 100644
index 35be5b06..00000000
--- a/hdl/ram.v
+++ /dev/null
@@ -1,21 +0,0 @@
-// A RAM initialized with an external file
-
-module ram (
-    input             clk_i,
-    input             we_i,
-    input       [5:0] addr_i,
-    input      [31:0] data_i,
-    output reg [31:0] data_o
-);
-
-reg [31:0] ram [0:63];
-
-initial $readmemb("data/memory.dat",ram);
-
-always @(posedge clk_i) begin
-    if (we_i)
-        ram[addr_i] <= data_i;
-    data_o <= ram[addr_i];
-end
-
-endmodule
diff --git a/hdl/ram.vhdl b/hdl/ram.vhdl
deleted file mode 100644
index 36d68bd1..00000000
--- a/hdl/ram.vhdl
+++ /dev/null
@@ -1,45 +0,0 @@
--- A RAM initialized with an external file
-
-library IEEE;
-use IEEE.std_logic_1164.all;
-use IEEE.numeric_std.all;
-use STD.textio.all;
-
-entity ram is
-    port(
-        clk_i  : in  std_logic;
-        we_i   : in  std_logic;
-        addr_i : in  std_logic_vector(5 downto 0);
-        data_i : in  std_logic_vector(31 downto 0);
-        data_o : out std_logic_vector(31 downto 0)
-    );
-end ram;
-
-architecture RTL of ram is
-    type mem_t is array (0 to 63) of bit_vector(31 downto 0);
-
-    impure function init(filename : in string) return mem_t is
-        file     fh  : text is filename;
-        variable l   : line;
-        variable mem : mem_t;
-    begin
-        for i in mem_t'range loop
-            readline(fh, l);
-            read(l, mem(i));
-        end loop;
-        return mem;
-    end function;
-
-    signal ram : mem_t := init("data/memory.dat");
-begin
-    memory:
-    process(clk_i)
-    begin
-        if rising_edge(clk_i) then
-            if we_i = '1' then
-                ram(to_integer(unsigned(addr_i))) <= to_bitvector(data_i);
-            end if;
-            data_o <= to_stdlogicvector(ram(to_integer(unsigned(addr_i))));
-        end if;
-    end process;
-end architecture RTL;
diff --git a/hdl/top.v b/hdl/top.v
deleted file mode 100644
index 787fbdbd..00000000
--- a/hdl/top.v
+++ /dev/null
@@ -1,11 +0,0 @@
-module Top (
-   input  wire clk_i,
-   output wire led_o
-);
-
-localparam FREQ = 50000000;
-
-Blinking #(.FREQ (FREQ), .SECS (1))
-   dut (.clk_i (clk_i), .led_o (led_o));
-
-endmodule
diff --git a/hdl/top.vhdl b/hdl/top.vhdl
deleted file mode 100644
index 80919fd6..00000000
--- a/hdl/top.vhdl
+++ /dev/null
@@ -1,21 +0,0 @@
-library IEEE;
-use IEEE.std_logic_1164.all;
-library Examples;
-use Examples.examples.all;
-
-entity Top is
-   port (
-      clk_i :  in std_logic;
-      led_o : out std_logic
-   );
-end entity Top;
-
-architecture Structural of Top is
-   constant FREQ : positive := 50e6;
-begin
-
-   dut: Blinking
-      generic map (FREQ => FREQ, SECS => 1)
-      port map (clk_i => clk_i, led_o => led_o);
-
-end architecture Structural;

From 293d1f02867a6569d379d70ed7aa6d7b83b78f7c Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Thu, 20 Jun 2024 19:27:40 -0300
Subject: [PATCH 085/248] Updated resources, removed zybo.xdc

---
 examples/resources       |  2 +-
 examples/vivado/zybo.xdc | 10 ----------
 2 files changed, 1 insertion(+), 11 deletions(-)
 delete mode 100644 examples/vivado/zybo.xdc

diff --git a/examples/resources b/examples/resources
index 53d36f1d..7f34b14e 160000
--- a/examples/resources
+++ b/examples/resources
@@ -1 +1 @@
-Subproject commit 53d36f1d9d49b26e42d09aaf1e0e6c6fac7736e2
+Subproject commit 7f34b14e2cdcbcbd6f57053a033a2abdd3ff1900
diff --git a/examples/vivado/zybo.xdc b/examples/vivado/zybo.xdc
deleted file mode 100644
index 9b6fe3d3..00000000
--- a/examples/vivado/zybo.xdc
+++ /dev/null
@@ -1,10 +0,0 @@
-# Xilinx Design Constraints
-#
-# Are based on the standard Synopsys Design Constraints (SDC) format.
-
-create_clock -name clk_i -period 8 [get_ports clk_i]
-
-set_property PACKAGE_PIN L16 [get_ports clk_i]
-set_property IOSTANDARD LVCMOS33 [get_ports clk_i]
-set_property PACKAGE_PIN M14 [get_ports led_o]
-set_property IOSTANDARD LVCMOS33 [get_ports led_o]

From 07e53be5e8b22bd3dabafc6a0f650e9dfe1f78a6 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Thu, 20 Jun 2024 19:28:08 -0300
Subject: [PATCH 086/248] Updated Vivado example to use the new PyFPGA

---
 examples/vivado/vivado.py | 39 +++++++++++++++++++++------------------
 1 file changed, 21 insertions(+), 18 deletions(-)

diff --git a/examples/vivado/vivado.py b/examples/vivado/vivado.py
index bf1830a1..497734d3 100644
--- a/examples/vivado/vivado.py
+++ b/examples/vivado/vivado.py
@@ -1,30 +1,33 @@
-"""Vivado example project."""
+"""Vivado VHDL example project."""
 
 import argparse
-import logging
 
-from fpga.project import Project
-
-logging.basicConfig()
+from pyfpga.vivado import Vivado
 
 parser = argparse.ArgumentParser()
 parser.add_argument(
-    '--action', choices=['generate', 'transfer', 'all'], default='generate',
+    '--action', choices=['make', 'prog', 'all'], default='make'
+)
+parser.add_argument(
+    '--source', choices=['vhdl', 'vlog', 'design'], default='vhdl'
 )
 args = parser.parse_args()
 
-prj = Project('vivado')
+prj = Vivado(odir=f'../build/vivado-{args.source}')
 prj.set_part('xc7z010-1-clg400')
 
-prj.set_outdir('../../build/vivado')
-
 prj.add_param('FREQ', '125000000')
-prj.add_files('../../hdl/blinking.vhdl')
-prj.add_files('zybo.xdc')
-prj.set_top('Blinking')
-
-if args.action in ['generate', 'all']:
-    prj.generate()
-
-if args.action in ['transfer', 'all']:
-    prj.transfer('fpga')
+if args.source == 'vhdl':
+    prj.add_vhdl('../resources/vhdl/blink.vhdl')
+if args.source == 'vlog':
+    prj.add_vlog('../resources/vlog/blink.v')
+prj.add_constraint('../resources/constraints/zybo/timing.xdc', 'syn')
+prj.add_constraint('../resources/constraints/zybo/clk.xdc', 'par')
+prj.add_constraint('../resources/constraints/zybo/led.xdc', 'par')
+prj.set_top('Blink')
+
+if args.action in ['make', 'all']:
+    prj.make()
+
+if args.action in ['prog', 'all']:
+    prj.prog()

From d3bb077ea6f1327397730424804949fd71da1cb9 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Thu, 20 Jun 2024 19:28:56 -0300
Subject: [PATCH 087/248] Fixed double timestamp

---
 pyfpga/project.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/pyfpga/project.py b/pyfpga/project.py
index d7758ad0..7e381620 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -13,7 +13,6 @@
 import os
 import subprocess
 
-from datetime import datetime
 from pathlib import Path
 from shutil import which
 from time import time
@@ -277,7 +276,9 @@ def _create_file(self, basename, extension, context):
             file.write(content)
 
     def _run(self, command):
-        self.logger.info('Running the underlying tool (%s)', datetime.now())
+        self.logger.info(
+            'Running the underlying tool (%s)', self.tool['make-app']
+        )
         run_error = 0
         old_dir = Path.cwd()
         new_dir = Path(self.odir)
@@ -299,7 +300,6 @@ def _run(self, command):
         finally:
             os.chdir(old_dir)
             end = time()
-            self.logger.info('Done (%s)', datetime.now())
             elapsed = end - start
             self.logger.info(
                 'Elapsed time %dh %dm %.2fs',

From 804bcc1dbd930c2fed0a7bb006ca64068cf250fc Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 23 Jun 2024 16:35:16 -0300
Subject: [PATCH 088/248] Added a script to enable mock-ups

---
 tests/mocks/source-me.sh | 5 +++++
 1 file changed, 5 insertions(+)
 create mode 100644 tests/mocks/source-me.sh

diff --git a/tests/mocks/source-me.sh b/tests/mocks/source-me.sh
new file mode 100644
index 00000000..1f035b47
--- /dev/null
+++ b/tests/mocks/source-me.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+MDIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd)
+
+export PATH=$PATH:$MDIR

From 33429d04e0c7c232fea25d7cedadd22eaa172ac9 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 23 Jun 2024 17:39:56 -0300
Subject: [PATCH 089/248] Improved some messages and how to indicate the
 command to run

---
 pyfpga/project.py | 57 ++++++++++++++++++++++-------------------------
 pyfpga/vivado.py  | 10 ++-------
 2 files changed, 29 insertions(+), 38 deletions(-)

diff --git a/pyfpga/project.py b/pyfpga/project.py
index 7e381620..52106923 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -14,7 +14,6 @@
 import subprocess
 
 from pathlib import Path
-from shutil import which
 from time import time
 from jinja2 import Environment, FileSystemLoader
 
@@ -204,39 +203,41 @@ def add_hook(self, stage, hook):
             raise ValueError('Invalid stage.')
         self.data.setdefault('hooks', {}).setdefault(stage, []).append(hook)
 
-    def make(self, last='bit', first='cfg'):
+    def make(self, first='cfg', last='bit'):
         """Run the underlying tool.
 
-        :param last: last step
-        :type last: str, optional
         :param first: first step
         :type first: str, optional
+        :param last: last step
+        :type last: str, optional
         :raises ValueError: for missing or wrong values
-        :raises RuntimeError: when the needed underlying tool is not found
+        :raises RuntimeError: error running the needed underlying tool
 
         .. note:: valid steps are ``cfg``, ``syn``, ``par`` and ``bit``.
         """
         self.logger.debug('Executing make')
         if 'part' not in self.data:
-            self.logger.info('No part specified, using a default value')
-        if 'top' not in self.data:
-            self.logger.warning('No top specified')
-        if 'files' not in self.data:
-            self.logger.warning('No files specified')
-        steps = ['cfg', 'syn', 'par', 'bit']
+            self.logger.info('Using the default PART')
+        steps = {
+            'cfg': 'Project Creation',
+            'syn': 'Synthesis',
+            'par': 'Place and Route',
+            'bit': 'Bitstream generation'
+        }
         if last not in steps:
             raise ValueError('Invalid last step.')
         if first not in steps:
             raise ValueError('Invalid first step.')
-        first_index = steps.index(first)
-        last_index = steps.index(last)
-        if first_index > last_index:
+        keys = list(steps.keys())
+        index = [keys.index(first), keys.index(last)]
+        if index[0] > index[1]:
             raise ValueError('Invalid steps combination.')
-        selected_steps = steps[first_index:last_index + 1]
-        self._make_prepare([step.upper() for step in selected_steps])
-        if not which(self.tool['make-app']):
-            raise RuntimeError(f'{self.tool["make-app"]} not found.')
-        self._run(self.tool['make-cmd'])
+        message = f'from {steps[first]} to {steps[last]}'
+        if first == last:
+            message = steps[first]
+        self.logger.info('Running %s', message)
+        selected = [step.upper() for step in keys[index[0]:index[1]+1]]
+        self._run(self._make_prepare(selected))
 
     def prog(self, bitstream=None, position=1):
         """Program the FPGA
@@ -246,16 +247,15 @@ def prog(self, bitstream=None, position=1):
         :param position: position of the device in the JTAG chain
         :type position: str, optional
         :raises ValueError: for missing or wrong values
-        :raises RuntimeError: when the needed underlying tool is not found
+        :raises RuntimeError: error running the needed underlying tool
         """
         self.logger.debug('Executing prog')
         if position not in range(1, 9):
             raise ValueError('Invalid position.')
         _ = bitstream
         self._prog_prepare()
-        if not which(self.tool['prog-app']):
-            raise RuntimeError(f'{self.tool["prog-app"]} not found.')
-        self._run(self.tool['prog-cmd'])
+        self.logger.info('Programming')
+        self._run(self._prog_prepare())
 
     def _make_prepare(self, steps):
         raise NotImplementedError('Tool-dependent')
@@ -276,10 +276,7 @@ def _create_file(self, basename, extension, context):
             file.write(content)
 
     def _run(self, command):
-        self.logger.info(
-            'Running the underlying tool (%s)', self.tool['make-app']
-        )
-        run_error = 0
+        error = 0
         old_dir = Path.cwd()
         new_dir = Path(self.odir)
         start = time()
@@ -296,7 +293,7 @@ def _run(self, command):
                 last_lines = lines[-10:] if len(lines) >= 10 else lines
                 for line in last_lines:
                     self.logger.error(line.strip())
-            run_error = 1
+            error = 1
         finally:
             os.chdir(old_dir)
             end = time()
@@ -307,5 +304,5 @@ def _run(self, command):
                 int((elapsed % 3600) // 60),
                 elapsed % 60
             )
-            if run_error:
-                raise RuntimeError('Error running the underlying tool')
+            if error:
+                raise RuntimeError('Problem with the underlying tool')
diff --git a/pyfpga/vivado.py b/pyfpga/vivado.py
index d776b52a..9999f443 100644
--- a/pyfpga/vivado.py
+++ b/pyfpga/vivado.py
@@ -18,10 +18,6 @@ class Vivado(Project):
     """Class to support Vivado projects."""
 
     def _make_prepare(self, steps):
-        self.tool['make-app'] = 'vivado'
-        self.tool['make-cmd'] = (
-            'vivado -mode batch -notrace -quiet -source vivado.tcl'
-        )
         context = {
             'PROJECT': self.name or 'vivado',
             'PART': self.data.get('part', 'xc7k160t-3-fbg484')
@@ -76,10 +72,8 @@ def _make_prepare(self, steps):
             for stage in self.data['hooks']:
                 context[stage.upper()] = '\n'.join(self.data['hooks'][stage])
         self._create_file('vivado', 'tcl', context)
+        return 'vivado -mode batch -notrace -quiet -source vivado.tcl'
 
     def _prog_prepare(self):
         # binaries = ['bit']
-        self.tool['prog-app'] = 'vivado'
-        self.tool['prog-cmd'] = (
-            'vivado -mode batch -notrace -quiet -source vivado-prog.tcl'
-        )
+        return 'vivado -mode batch -notrace -quiet -source vivado-prog.tcl'

From a2cd4120112b41b33511b3f1a209b693b9f30a83 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 23 Jun 2024 19:55:36 -0300
Subject: [PATCH 090/248] Modified to print the last 20 lines of the log file

---
 pyfpga/project.py | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/pyfpga/project.py b/pyfpga/project.py
index 52106923..5008f3e6 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -276,6 +276,7 @@ def _create_file(self, basename, extension, context):
             file.write(content)
 
     def _run(self, command):
+        NUM = 20
         error = 0
         old_dir = Path.cwd()
         new_dir = Path(self.odir)
@@ -290,9 +291,11 @@ def _run(self, command):
         except subprocess.CalledProcessError:
             with open('run.log', 'r', encoding='utf-8') as file:
                 lines = file.readlines()
-                last_lines = lines[-10:] if len(lines) >= 10 else lines
+                last_lines = lines[-NUM:] if len(lines) >= NUM else lines
                 for line in last_lines:
-                    self.logger.error(line.strip())
+                    message = line.strip()
+                    if len(message):
+                        print(f'>> {message}')
             error = 1
         finally:
             os.chdir(old_dir)

From bbcd7a1808f3e345d723a4530c429bbe69325fac Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 23 Jun 2024 20:36:26 -0300
Subject: [PATCH 091/248] Added new sources, updated the Vivado example

---
 examples/sources/slog/blink.sv           | 23 ++++++++++++++++
 examples/sources/slog/include/header.svh |  1 +
 examples/sources/slog/top.sv             | 24 +++++++++++++++++
 examples/sources/vhdl/blink.vhdl         | 34 ++++++++++++++++++++++++
 examples/sources/vhdl/blink_pkg.vhdl     | 16 +++++++++++
 examples/sources/vhdl/top.vhdl           | 25 +++++++++++++++++
 examples/sources/vlog/blink.v            | 23 ++++++++++++++++
 examples/sources/vlog/include/header.vh  |  1 +
 examples/sources/vlog/top.v              | 24 +++++++++++++++++
 examples/vivado/sources/zybo/clk.xdc     |  2 ++
 examples/vivado/sources/zybo/led.xdc     |  2 ++
 examples/vivado/sources/zybo/timing.xdc  |  1 +
 examples/vivado/vivado.py                | 20 +++++++++-----
 13 files changed, 189 insertions(+), 7 deletions(-)
 create mode 100644 examples/sources/slog/blink.sv
 create mode 100644 examples/sources/slog/include/header.svh
 create mode 100644 examples/sources/slog/top.sv
 create mode 100644 examples/sources/vhdl/blink.vhdl
 create mode 100644 examples/sources/vhdl/blink_pkg.vhdl
 create mode 100644 examples/sources/vhdl/top.vhdl
 create mode 100644 examples/sources/vlog/blink.v
 create mode 100644 examples/sources/vlog/include/header.vh
 create mode 100644 examples/sources/vlog/top.v
 create mode 100644 examples/vivado/sources/zybo/clk.xdc
 create mode 100644 examples/vivado/sources/zybo/led.xdc
 create mode 100644 examples/vivado/sources/zybo/timing.xdc

diff --git a/examples/sources/slog/blink.sv b/examples/sources/slog/blink.sv
new file mode 100644
index 00000000..b74bfe08
--- /dev/null
+++ b/examples/sources/slog/blink.sv
@@ -0,0 +1,23 @@
+module Blink #(
+  parameter int FREQ = 25000000
+)(
+  input  clk_i,
+  output led_o
+);
+
+  localparam int          DIV = FREQ;
+  logic                   led = 0;
+  logic [$clog2(DIV)-1:0] cnt = 0;
+
+  always_ff @(posedge clk_i) begin
+    if (cnt == DIV-1) begin
+      cnt <= 0;
+      led <= ~led;
+    end else begin
+      cnt <= cnt + 1;
+    end
+  end
+
+  assign led_o = led;
+
+endmodule
diff --git a/examples/sources/slog/include/header.svh b/examples/sources/slog/include/header.svh
new file mode 100644
index 00000000..78aa9bfd
--- /dev/null
+++ b/examples/sources/slog/include/header.svh
@@ -0,0 +1 @@
+`define INCLUDE
diff --git a/examples/sources/slog/top.sv b/examples/sources/slog/top.sv
new file mode 100644
index 00000000..24e780e5
--- /dev/null
+++ b/examples/sources/slog/top.sv
@@ -0,0 +1,24 @@
+`include "header.svh"
+
+module Top #(
+  parameter FREQ = 0
+)(
+  input  clk_i,
+  output led_o
+);
+
+  initial begin
+    if (FREQ==0) begin
+      $stop("FREQ must be greater than 0");
+      $error("FREQ must be greater than 0");
+      $fatal("FREQ must be greater than 0");
+    end
+  end
+
+`ifdef INCLUDE
+`ifdef DEFINE
+  Blink #(.FREQ (FREQ)) dut (.clk_i (clk_i), .led_o (led_o));
+`endif
+`endif
+
+endmodule
diff --git a/examples/sources/vhdl/blink.vhdl b/examples/sources/vhdl/blink.vhdl
new file mode 100644
index 00000000..9b9a4bc3
--- /dev/null
+++ b/examples/sources/vhdl/blink.vhdl
@@ -0,0 +1,34 @@
+library IEEE;
+use IEEE.std_logic_1164.all;
+
+entity Blink is
+  generic (
+    FREQ  : positive := 25e6
+  );
+  port (
+    clk_i : in  std_logic;
+    led_o : out std_logic
+  );
+end entity Blink;
+
+architecture RTL of Blink is
+  constant DIV : positive := FREQ;
+  signal   led : std_logic := '0';
+  signal   cnt : natural range 0 to DIV-1 := 0;
+begin
+
+  blink_p: process (clk_i)
+  begin
+    if rising_edge(clk_i) then
+      if cnt = DIV-1 then
+        cnt <= 0;
+        led <= not led;
+      else
+        cnt <= cnt + 1;
+      end if;
+    end if;
+  end process blink_p;
+
+  led_o <= led;
+
+end architecture RTL;
diff --git a/examples/sources/vhdl/blink_pkg.vhdl b/examples/sources/vhdl/blink_pkg.vhdl
new file mode 100644
index 00000000..115f0899
--- /dev/null
+++ b/examples/sources/vhdl/blink_pkg.vhdl
@@ -0,0 +1,16 @@
+library IEEE;
+use IEEE.std_logic_1164.all;
+
+package blink_pkg is
+
+  component Blink is
+    generic (
+      FREQ  : natural:=25e6
+    );
+    port (
+      clk_i :  in std_logic;
+      led_o : out std_logic
+    );
+  end component Blink;
+
+end package blink_pkg;
diff --git a/examples/sources/vhdl/top.vhdl b/examples/sources/vhdl/top.vhdl
new file mode 100644
index 00000000..0ff6d780
--- /dev/null
+++ b/examples/sources/vhdl/top.vhdl
@@ -0,0 +1,25 @@
+library IEEE;
+use IEEE.std_logic_1164.all;
+library blink_lib;
+use blink_lib.blink_pkg.all;
+
+entity Top is
+  generic (
+    FREQ : natural := 0
+  );
+  port (
+    clk_i :  in std_logic;
+    led_o : out std_logic
+  );
+end entity Top;
+
+architecture ARCH of Top is
+begin
+
+  assert FREQ > 0 report "FREQ must be greater than 0" severity failure;
+
+  blink_i: Blink
+  generic map (FREQ => FREQ)
+  port map (clk_i => clk_i, led_o => led_o);
+
+end architecture ARCH;
diff --git a/examples/sources/vlog/blink.v b/examples/sources/vlog/blink.v
new file mode 100644
index 00000000..7522e0f7
--- /dev/null
+++ b/examples/sources/vlog/blink.v
@@ -0,0 +1,23 @@
+module Blink #(
+  parameter FREQ = 25000000
+)(
+  input  clk_i,
+  output led_o
+);
+
+  localparam            DIV = FREQ;
+  reg                   led = 0;
+  reg [$clog2(DIV)-1:0] cnt = 0;
+
+  always @(posedge clk_i) begin
+    if (cnt == DIV-1) begin
+      cnt <= 0;
+      led <= ~led;
+    end else begin
+      cnt <= cnt + 1;
+    end
+  end
+
+  assign led_o = led;
+
+endmodule
diff --git a/examples/sources/vlog/include/header.vh b/examples/sources/vlog/include/header.vh
new file mode 100644
index 00000000..78aa9bfd
--- /dev/null
+++ b/examples/sources/vlog/include/header.vh
@@ -0,0 +1 @@
+`define INCLUDE
diff --git a/examples/sources/vlog/top.v b/examples/sources/vlog/top.v
new file mode 100644
index 00000000..6c63ebae
--- /dev/null
+++ b/examples/sources/vlog/top.v
@@ -0,0 +1,24 @@
+`include "header.vh"
+
+module Top #(
+  parameter FREQ = 0
+)(
+  input  clk_i,
+  output led_o
+);
+
+  initial begin
+    if (FREQ==0) begin
+      $stop("FREQ must be greater than 0");
+      $error("FREQ must be greater than 0");
+      $fatal("FREQ must be greater than 0");
+    end
+  end
+
+`ifdef INCLUDE
+`ifdef DEFINE
+  Blink #(.FREQ (FREQ)) dut (.clk_i (clk_i), .led_o (led_o));
+`endif
+`endif
+
+endmodule
diff --git a/examples/vivado/sources/zybo/clk.xdc b/examples/vivado/sources/zybo/clk.xdc
new file mode 100644
index 00000000..877602c7
--- /dev/null
+++ b/examples/vivado/sources/zybo/clk.xdc
@@ -0,0 +1,2 @@
+set_property PACKAGE_PIN L16 [get_ports clk_i]
+set_property IOSTANDARD LVCMOS33 [get_ports clk_i]
diff --git a/examples/vivado/sources/zybo/led.xdc b/examples/vivado/sources/zybo/led.xdc
new file mode 100644
index 00000000..8106c5cc
--- /dev/null
+++ b/examples/vivado/sources/zybo/led.xdc
@@ -0,0 +1,2 @@
+set_property PACKAGE_PIN M14 [get_ports led_o]
+set_property IOSTANDARD LVCMOS33 [get_ports led_o]
diff --git a/examples/vivado/sources/zybo/timing.xdc b/examples/vivado/sources/zybo/timing.xdc
new file mode 100644
index 00000000..be3d63fc
--- /dev/null
+++ b/examples/vivado/sources/zybo/timing.xdc
@@ -0,0 +1 @@
+create_clock -name clk_i -period 8 [get_ports clk_i]
diff --git a/examples/vivado/vivado.py b/examples/vivado/vivado.py
index 497734d3..9f9ed802 100644
--- a/examples/vivado/vivado.py
+++ b/examples/vivado/vivado.py
@@ -9,7 +9,7 @@
     '--action', choices=['make', 'prog', 'all'], default='make'
 )
 parser.add_argument(
-    '--source', choices=['vhdl', 'vlog', 'design'], default='vhdl'
+    '--source', choices=['vlog', 'vhdl', 'slog', 'design'], default='vlog'
 )
 args = parser.parse_args()
 
@@ -18,13 +18,19 @@
 
 prj.add_param('FREQ', '125000000')
 if args.source == 'vhdl':
-    prj.add_vhdl('../resources/vhdl/blink.vhdl')
+    prj.add_vhdl('../sources/vhdl/*.vhdl', 'blink_lib')
 if args.source == 'vlog':
-    prj.add_vlog('../resources/vlog/blink.v')
-prj.add_constraint('../resources/constraints/zybo/timing.xdc', 'syn')
-prj.add_constraint('../resources/constraints/zybo/clk.xdc', 'par')
-prj.add_constraint('../resources/constraints/zybo/led.xdc', 'par')
-prj.set_top('Blink')
+    prj.add_include('../sources/vlog/include')
+    prj.add_vlog('../sources/vlog/*.v')
+if args.source == 'slog':
+    prj.add_include('../sources/slog/include')
+    prj.add_vlog('../sources/slog/*.sv')
+if args.source in ['vlog', 'slog']:
+    prj.add_define('DEFINE', '1')
+prj.add_constraint('sources/zybo/timing.xdc', 'syn')
+prj.add_constraint('sources/zybo/clk.xdc', 'par')
+prj.add_constraint('sources/zybo/led.xdc', 'par')
+prj.set_top('Top')
 
 if args.action in ['make', 'all']:
     prj.make()

From 3a4d7173d4dde4fe6a489110ddc3f67205346c05 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 23 Jun 2024 21:14:01 -0300
Subject: [PATCH 092/248] Implemented programming with Vivado

---
 pyfpga/ise.py      |  2 +-
 pyfpga/libero.py   |  2 +-
 pyfpga/openflow.py |  2 +-
 pyfpga/project.py  | 10 ++++------
 pyfpga/quartus.py  |  2 +-
 pyfpga/vivado.py   | 10 ++++++++--
 6 files changed, 16 insertions(+), 12 deletions(-)

diff --git a/pyfpga/ise.py b/pyfpga/ise.py
index 72e577bc..d5289930 100644
--- a/pyfpga/ise.py
+++ b/pyfpga/ise.py
@@ -24,7 +24,7 @@ def _make_prepare(self, steps):
         self.tool['make-app'] = 'xtclsh'
         self.tool['make-cmd'] = 'xtclsh ise.tcl'
 
-    def _prog_prepare(self):
+    def _prog_prepare(self, bitstream, position):
         # binaries = ['bit']
         self.tool['prog-app'] = 'impact'
         self.tool['prog-cmd'] = 'impact -batch impact-prog'
diff --git a/pyfpga/libero.py b/pyfpga/libero.py
index 35d4d89f..a717f1b7 100644
--- a/pyfpga/libero.py
+++ b/pyfpga/libero.py
@@ -24,7 +24,7 @@ def _make_prepare(self, steps):
         self.tool['make-app'] = 'libero'
         self.tool['make-cmd'] = 'libero SCRIPT:libero.tcl'
 
-    def _prog_prepare(self):
+    def _prog_prepare(self, bitstream, position):
         # binaries = ['bit']
         self.tool['prog-app'] = ''
         self.tool['prog-cmd'] = ''
diff --git a/pyfpga/openflow.py b/pyfpga/openflow.py
index cb756727..0b7865ba 100644
--- a/pyfpga/openflow.py
+++ b/pyfpga/openflow.py
@@ -22,7 +22,7 @@ def _make_prepare(self, steps):
         self.tool['make-app'] = 'docker'
         self.tool['make-cmd'] = 'bash openflow.sh'
 
-    def _prog_prepare(self):
+    def _prog_prepare(self, bitstream, position):
         # binaries = ['bit']
         self.tool['prog-app'] = 'docker'
         self.tool['prog-cmd'] = 'bash openflow-prog.sh'
diff --git a/pyfpga/project.py b/pyfpga/project.py
index 5008f3e6..951b1c3f 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -252,15 +252,13 @@ def prog(self, bitstream=None, position=1):
         self.logger.debug('Executing prog')
         if position not in range(1, 9):
             raise ValueError('Invalid position.')
-        _ = bitstream
-        self._prog_prepare()
         self.logger.info('Programming')
-        self._run(self._prog_prepare())
+        self._run(self._prog_prepare(bitstream, position))
 
     def _make_prepare(self, steps):
         raise NotImplementedError('Tool-dependent')
 
-    def _prog_prepare(self):
+    def _prog_prepare(self, bitstream, position):
         raise NotImplementedError('Tool-dependent')
 
     def _create_file(self, basename, extension, context):
@@ -276,7 +274,7 @@ def _create_file(self, basename, extension, context):
             file.write(content)
 
     def _run(self, command):
-        NUM = 20
+        num = 20
         error = 0
         old_dir = Path.cwd()
         new_dir = Path(self.odir)
@@ -291,7 +289,7 @@ def _run(self, command):
         except subprocess.CalledProcessError:
             with open('run.log', 'r', encoding='utf-8') as file:
                 lines = file.readlines()
-                last_lines = lines[-NUM:] if len(lines) >= NUM else lines
+                last_lines = lines[-num:] if len(lines) >= num else lines
                 for line in last_lines:
                     message = line.strip()
                     if len(message):
diff --git a/pyfpga/quartus.py b/pyfpga/quartus.py
index c635ffa5..4ca2bf78 100644
--- a/pyfpga/quartus.py
+++ b/pyfpga/quartus.py
@@ -24,7 +24,7 @@ def _make_prepare(self, steps):
         self.tool['make-app'] = 'quartus_sh'
         self.tool['make-cmd'] = 'quartus_sh --script quartus.tcl'
 
-    def _prog_prepare(self):
+    def _prog_prepare(self, bitstream, position):
         # binaries = ['sof', 'pof']
         self.tool['prog-app'] = 'quartus_pgm'
         self.tool['prog-cmd'] = 'bash quartus-prog.sh'
diff --git a/pyfpga/vivado.py b/pyfpga/vivado.py
index 9999f443..3470123e 100644
--- a/pyfpga/vivado.py
+++ b/pyfpga/vivado.py
@@ -11,6 +11,7 @@
 # pylint: disable=too-many-locals
 # pylint: disable=too-many-branches
 
+from pathlib import Path
 from pyfpga.project import Project
 
 
@@ -74,6 +75,11 @@ def _make_prepare(self, steps):
         self._create_file('vivado', 'tcl', context)
         return 'vivado -mode batch -notrace -quiet -source vivado.tcl'
 
-    def _prog_prepare(self):
-        # binaries = ['bit']
+    def _prog_prepare(self, bitstream, position):
+        _ = position  # Not needed for Vivado
+        if not bitstream:
+            basename = self.name or 'vivado'
+            bitstream = Path(self.odir).resolve() / f'{basename}.bit'
+        context = {'BITSTREAM': bitstream}
+        self._create_file('vivado-prog', 'tcl', context)
         return 'vivado -mode batch -notrace -quiet -source vivado-prog.tcl'

From 2bb960ce888a6f5fe43970e6a47281ed9cebf578 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 23 Jun 2024 21:17:32 -0300
Subject: [PATCH 093/248] ci: added to install pyfpga and prepare mock-ups

---
 .github/workflows/test.yml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 061381db..40699986 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -22,6 +22,6 @@ jobs:
       with:
         python-version: ${{ matrix.pyver }}
     - name: Install dependencies
-      run: pip install pytest
+      run: pip install . && pip install pytest
     - name: Run tests
-      run: make test
+      run: source tests/mocks/source-me.sh && make test

From eb7c046f353094bd0242eaf199bf05d19c7ae8f3 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 23 Jun 2024 21:21:29 -0300
Subject: [PATCH 094/248] Fixed/updated package name

---
 setup.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/setup.py b/setup.py
index e6b45d1b..9018d2d7 100644
--- a/setup.py
+++ b/setup.py
@@ -1,6 +1,6 @@
 from setuptools import setup, find_packages
 
-import fpga
+import pyfpga
 
 with open('README.md', 'r') as fh:
     long_description = fh.read()

From 4177a8b70e1afe98f2c17840b384d7b2c8a6561c Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 23 Jun 2024 21:31:11 -0300
Subject: [PATCH 095/248] Fixed/updated package name, added jinja2 as
 dependency, deprecated Python 3.7

---
 setup.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/setup.py b/setup.py
index 9018d2d7..a3eaab1d 100644
--- a/setup.py
+++ b/setup.py
@@ -30,7 +30,6 @@
         'Intended Audience :: Developers',
         'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
         'Operating System :: OS Independent',
-        'Programming Language :: Python :: 3.7',
         'Programming Language :: Python :: 3.8',
         'Programming Language :: Python :: 3.9',
         'Programming Language :: Python :: 3.10',
@@ -39,5 +38,6 @@
         'Topic :: Utilities',
         'Topic :: Software Development :: Build Tools',
         "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)"
-    ]
+    ],
+    install_requires=['jinja2']
 )

From 80cfbce1aec28dfef14330ceb8dd63d312d2e13e Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 23 Jun 2024 22:43:25 -0300
Subject: [PATCH 096/248] Updated the header of the mocks

---
 tests/mocks/impact      | 21 +++++----------
 tests/mocks/libero      | 21 ++++-----------
 tests/mocks/quartus_pgm | 21 +++++----------
 tests/mocks/quartus_sh  | 21 ++++-----------
 tests/mocks/vivado      | 57 ++++++++++++++++-------------------------
 tests/mocks/xtclsh      | 21 ++++-----------
 6 files changed, 51 insertions(+), 111 deletions(-)

diff --git a/tests/mocks/impact b/tests/mocks/impact
index 17eee4a6..0fbbacbc 100755
--- a/tests/mocks/impact
+++ b/tests/mocks/impact
@@ -1,23 +1,14 @@
 #!/usr/bin/env python3
+
 #
-# Copyright (C) 2022 Rodrigo A. Melo
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
+# Copyright (C) 2022-2024 Rodrigo A. Melo
 #
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+# SPDX-License-Identifier: GPL-3.0-or-later
 #
 
 import argparse
 
+
 parser = argparse.ArgumentParser()
 
 parser.add_argument('-batch', action='store_true', required=True)
@@ -25,4 +16,6 @@ parser.add_argument('source')
 
 args = parser.parse_args()
 
-print(f'INFO:the {parser.prog.upper()} mock has been executed')
+tool = parser.prog
+
+print(f'INFO:the {tool.upper()} mock has been executed')
diff --git a/tests/mocks/libero b/tests/mocks/libero
index b0f0b691..a4663e9d 100755
--- a/tests/mocks/libero
+++ b/tests/mocks/libero
@@ -1,19 +1,9 @@
 #!/usr/bin/env python3
+
 #
-# Copyright (C) 2022 Rodrigo A. Melo
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
+# Copyright (C) 2022-2024 Rodrigo A. Melo
 #
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+# SPDX-License-Identifier: GPL-3.0-or-later
 #
 
 import argparse
@@ -34,7 +24,7 @@ if not args.source.startswith("SCRIPT:", 0):
     sys.exit(1)
 
 tcl = f'''
-proc unknown {{ cmmd args }} {{ }}
+proc unknown args {{ }}
 
 source {args.source.replace('SCRIPT:', '')}
 '''
@@ -46,8 +36,7 @@ subprocess.run(
    f'tclsh {tool}-mock.tcl',
    shell=True,
    check=True,
-   universal_newlines=True,
-   #stdout=output, stderr=subprocess.STDOUT
+   universal_newlines=True
 )
 
 print(f'INFO:the {tool.upper()} mock has been executed')
diff --git a/tests/mocks/quartus_pgm b/tests/mocks/quartus_pgm
index 3353ee46..8993ca10 100755
--- a/tests/mocks/quartus_pgm
+++ b/tests/mocks/quartus_pgm
@@ -1,23 +1,14 @@
 #!/usr/bin/env python3
+
 #
-# Copyright (C) 2022 Rodrigo A. Melo
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
+# Copyright (C) 2022-2024 Rodrigo A. Melo
 #
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+# SPDX-License-Identifier: GPL-3.0-or-later
 #
 
 import argparse
 
+
 parser = argparse.ArgumentParser()
 
 parser.add_argument('-c', required=True)
@@ -26,4 +17,6 @@ parser.add_argument('-o', required=True)
 
 args = parser.parse_args()
 
-print(f'INFO:the {parser.prog.upper()} mock has been executed')
+tool = parser.prog
+
+print(f'INFO:the {tool.upper()} mock has been executed')
diff --git a/tests/mocks/quartus_sh b/tests/mocks/quartus_sh
index a002e73d..64a8cf65 100755
--- a/tests/mocks/quartus_sh
+++ b/tests/mocks/quartus_sh
@@ -1,19 +1,9 @@
 #!/usr/bin/env python3
+
 #
-# Copyright (C) 2022 Rodrigo A. Melo
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
+# Copyright (C) 2022-2024 Rodrigo A. Melo
 #
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+# SPDX-License-Identifier: GPL-3.0-or-later
 #
 
 import argparse
@@ -32,7 +22,7 @@ tool = parser.prog
 tcl = f'''
 lappend auto_path pkg
 
-proc unknown {{ cmmd args }} {{ }}
+proc unknown args {{ }}
 
 source {args.script}
 '''
@@ -60,8 +50,7 @@ subprocess.run(
    f'tclsh {tool}-mock.tcl',
    shell=True,
    check=True,
-   universal_newlines=True,
-   #stdout=output, stderr=subprocess.STDOUT
+   universal_newlines=True
 )
 
 print(f'INFO:the {tool.upper()} mock has been executed')
diff --git a/tests/mocks/vivado b/tests/mocks/vivado
index af5614d1..f6a47eff 100755
--- a/tests/mocks/vivado
+++ b/tests/mocks/vivado
@@ -1,19 +1,9 @@
 #!/usr/bin/env python3
+
 #
-# Copyright (C) 2022 Rodrigo A. Melo
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
+# Copyright (C) 2022-2024 Rodrigo A. Melo
 #
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+# SPDX-License-Identifier: GPL-3.0-or-later
 #
 
 import argparse
@@ -31,28 +21,26 @@ args = parser.parse_args()
 
 tool = parser.prog
 
-
-#proc create_project    {{ args }} {{ }}
-#proc open_project      {{ args }} {{ }}
-#proc current_project   {{ args }} {{ }}
-#proc current_fileset   {{ args }} {{ }}
-#proc get_filesets      {{ args }} {{ }}
-#proc set_property      {{ args }} {{ }}
-#proc add_files         {{ args }} {{ }}
-#proc get_files         {{ args }} {{ }}
-#proc reset_run         {{ args }} {{ }}
-#proc launch_runs       {{ args }} {{ }}
-#proc get_runs          {{ args }} {{ }}
-#proc wait_on_run       {{ args }} {{ }}
-#proc open_run          {{ args }} {{ }}
-#proc write_bitstream   {{ args }} {{ }}
-#proc close_project     {{ args }} {{ }}
-#proc current_bd_design {{ args }} {{ }}
-#proc get_bd_cells      {{ args }} {{ }}
-
+#proc create_project    args {{ }}
+#proc open_project      args {{ }}
+#proc current_project   args {{ }}
+#proc current_fileset   args {{ }}
+#proc get_filesets      args {{ }}
+#proc set_property      args {{ }}
+#proc add_files         args {{ }}
+#proc get_files         args {{ }}
+#proc reset_run         args {{ }}
+#proc launch_runs       args {{ }}
+#proc get_runs          args {{ }}
+#proc wait_on_run       args {{ }}
+#proc open_run          args {{ }}
+#proc write_bitstream   args {{ }}
+#proc close_project     args {{ }}
+#proc current_bd_design args {{ }}
+#proc get_bd_cells      args {{ }}
 
 tcl = f'''
-proc unknown {{ cmmd args }} {{ }}
+proc unknown args {{ }}
 
 source {args.source}
 '''
@@ -64,8 +52,7 @@ subprocess.run(
    f'tclsh {tool}-mock.tcl',
    shell=True,
    check=True,
-   universal_newlines=True,
-   #stdout=output, stderr=subprocess.STDOUT
+   universal_newlines=True
 )
 
 print(f'INFO:the {tool.upper()} mock has been executed')
diff --git a/tests/mocks/xtclsh b/tests/mocks/xtclsh
index 12046fa3..7621c4d9 100755
--- a/tests/mocks/xtclsh
+++ b/tests/mocks/xtclsh
@@ -1,19 +1,9 @@
 #!/usr/bin/env python3
+
 #
-# Copyright (C) 2022 Rodrigo A. Melo
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
+# Copyright (C) 2022-2024 Rodrigo A. Melo
 #
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+# SPDX-License-Identifier: GPL-3.0-or-later
 #
 
 import argparse
@@ -29,7 +19,7 @@ args = parser.parse_args()
 tool = parser.prog
 
 tcl = f'''
-proc unknown {{ cmmd args }} {{ }}
+proc unknown args {{ }}
 
 source {args.source}
 '''
@@ -41,8 +31,7 @@ subprocess.run(
    f'tclsh {tool}-mock.tcl',
    shell=True,
    check=True,
-   universal_newlines=True,
-   #stdout=output, stderr=subprocess.STDOUT
+   universal_newlines=True
 )
 
 print(f'INFO:the {tool.upper()} mock has been executed')

From 57149f80b2f2ff8aeb30a68a3439721551427083 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 23 Jun 2024 23:00:04 -0300
Subject: [PATCH 097/248] Updated README.md

---
 README.md | 29 +++++++++--------------------
 1 file changed, 9 insertions(+), 20 deletions(-)

diff --git a/README.md b/README.md
index 3a60df40..1294d710 100644
--- a/README.md
+++ b/README.md
@@ -14,33 +14,22 @@ With PyFPGA, you can create your own FPGA development workflow tailored to your
 
 Some of its benefits are:
 * It provides a unified API between tools/devices.
-* It's **Version Control Systems** and **Continuous Integration friendly**.
+* It's **Version Control Systems** and **Continuous Integration** friendly.
 * It ensures reproducibility and repeatability.
 * It consumes fewer system resources than GUI-based workflows.
 
 ## Basic example
 
 ```py
-from fpga import Project
+from pyfpga import Vivado
 
-# Specify the backend tool and an optional project name
-prj = Project('vivado', 'example')
-
-# Set the device/part
+prj = Vivado('example')
 prj.set_part('xc7z010-1-clg400')
-
-# Add HDL sources to the project
-prj.add_files('location1/*.v')
-prj.add_files('location2/top.v')
-
-# Optionally add constraint files to the project
-prj.add_files('location3/example.xdc')
-
-# Set the top-level unit name
+prj.add_vlog('location1/*.v')
+prj.add_vlog('location2/top.v')
+prj.add_constraint('location3/example.xdc')
 prj.set_top('Top')
-
-# Generate the bitstream running the tool
-prj.generate()
+prj.make()
 ```
 
 The next steps are to read the [docs](https://pyfpga.github.io/pyfpga) or take a look at [examples](examples).
@@ -54,11 +43,11 @@ For a comprehensive list of supported tools, features and limitations, please re
 
 > **NOTE:**
 > PyFPGA assumes that the underlying tools required for operation are ready to be executed from the running terminal.
-> This includes having the tools installed, properly configured, and licensed (when needed).
+> This includes having the tools installed, properly configured and licensed (when needed).
 
 ## Installation
 
-PyFPGA requires Python>=3.7.
+PyFPGA requires Python>=3.8.
 
 At the moment, it's only available as a git repository hosted on GitHub. It can be installed with pip:
 

From 33ea70b889caa212d1f04fa5f888045709561df1 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 23 Jun 2024 23:04:55 -0300
Subject: [PATCH 098/248] Renamed add_constraint as add_cons

---
 README.md                 | 2 +-
 examples/vivado/vivado.py | 6 +++---
 pyfpga/project.py         | 4 ++--
 tests/test_data.py        | 6 +++---
 tests/test_vivado.py      | 6 +++---
 5 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/README.md b/README.md
index 1294d710..aa17c849 100644
--- a/README.md
+++ b/README.md
@@ -27,7 +27,7 @@ prj = Vivado('example')
 prj.set_part('xc7z010-1-clg400')
 prj.add_vlog('location1/*.v')
 prj.add_vlog('location2/top.v')
-prj.add_constraint('location3/example.xdc')
+prj.add_cons('location3/example.xdc')
 prj.set_top('Top')
 prj.make()
 ```
diff --git a/examples/vivado/vivado.py b/examples/vivado/vivado.py
index 9f9ed802..930e62cd 100644
--- a/examples/vivado/vivado.py
+++ b/examples/vivado/vivado.py
@@ -27,9 +27,9 @@
     prj.add_vlog('../sources/slog/*.sv')
 if args.source in ['vlog', 'slog']:
     prj.add_define('DEFINE', '1')
-prj.add_constraint('sources/zybo/timing.xdc', 'syn')
-prj.add_constraint('sources/zybo/clk.xdc', 'par')
-prj.add_constraint('sources/zybo/led.xdc', 'par')
+prj.add_cons('sources/zybo/timing.xdc', 'syn')
+prj.add_cons('sources/zybo/clk.xdc', 'par')
+prj.add_cons('sources/zybo/led.xdc', 'par')
 prj.set_top('Top')
 
 if args.action in ['make', 'all']:
diff --git a/pyfpga/project.py b/pyfpga/project.py
index 951b1c3f..179ef179 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -114,7 +114,7 @@ def add_vlog(self, pathname):
         self.logger.debug('Executing add_vlog')
         self._add_file(pathname, 'vlog')
 
-    def add_constraint(self, path, when='all'):
+    def add_cons(self, path, when='all'):
         """Add a constraint file.
 
         :param pathname: path of a file
@@ -123,7 +123,7 @@ def add_constraint(self, path, when='all'):
         :type only: str, optional
         :raises FileNotFoundError: if path is not found
         """
-        self.logger.debug('Executing add_constraint')
+        self.logger.debug('Executing add_cons')
         path = Path(path).resolve()
         if not path.is_file():
             raise FileNotFoundError(path)
diff --git a/tests/test_data.py b/tests/test_data.py
index c4a355c0..69446951 100644
--- a/tests/test_data.py
+++ b/tests/test_data.py
@@ -70,9 +70,9 @@ def test_data():
     prj.add_slog('fakedata/**/*.sv')
     prj.add_vhdl('fakedata/**/*.vhdl', 'LIB')
     prj.add_vlog('fakedata/**/*.v')
-    prj.add_constraint('fakedata/cons/all.xdc')
-    prj.add_constraint('fakedata/cons/syn.xdc', 'syn')
-    prj.add_constraint('fakedata/cons/par.xdc', 'par')
+    prj.add_cons('fakedata/cons/all.xdc')
+    prj.add_cons('fakedata/cons/syn.xdc', 'syn')
+    prj.add_cons('fakedata/cons/par.xdc', 'par')
     prj.add_param('PAR1', 'VAL1')
     prj.add_param('PAR2', 'VAL2')
     prj.add_param('PAR3', 'VAL3')
diff --git a/tests/test_vivado.py b/tests/test_vivado.py
index 9afa353d..787e90cb 100644
--- a/tests/test_vivado.py
+++ b/tests/test_vivado.py
@@ -11,9 +11,9 @@ def test_vivado():
     prj.add_slog('fakedata/**/*.sv')
     prj.add_vhdl('fakedata/**/*.vhdl', 'LIB')
     prj.add_vlog('fakedata/**/*.v')
-    prj.add_constraint('fakedata/cons/all.xdc')
-    prj.add_constraint('fakedata/cons/syn.xdc', 'syn')
-    prj.add_constraint('fakedata/cons/par.xdc', 'par')
+    prj.add_cons('fakedata/cons/all.xdc')
+    prj.add_cons('fakedata/cons/syn.xdc', 'syn')
+    prj.add_cons('fakedata/cons/par.xdc', 'par')
     prj.add_param('PAR1', 'VAL1')
     prj.add_param('PAR2', 'VAL2')
     prj.add_define('DEF1', 'VAL1')

From cefcc9a18876bf7499d23f0bb07cbb94288a1108 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 24 Jun 2024 19:34:32 -0300
Subject: [PATCH 099/248] Removed support for VHDL architectures

---
 docs/internals.rst            | 1 -
 pyfpga/project.py             | 9 ---------
 pyfpga/templates/vivado.jinja | 4 ----
 pyfpga/vivado.py              | 2 --
 tests/test_data.py            | 2 --
 tests/test_vivado.py          | 1 -
 6 files changed, 19 deletions(-)

diff --git a/docs/internals.rst b/docs/internals.rst
index 910df99a..bcaa371f 100644
--- a/docs/internals.rst
+++ b/docs/internals.rst
@@ -60,7 +60,6 @@ Internal data structure
             'DEF2': 'VAL2',
             'DEF3': 'VAL3'
         },
-        'arch': 'ARCHNAME',
         'hooks': {
             'precfg': ['CMD1', 'CMD2'],
             'postcfg': ['CMD1', 'CMD2'],
diff --git a/pyfpga/project.py b/pyfpga/project.py
index 179ef179..faaacffe 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -153,15 +153,6 @@ def add_define(self, name, value):
         self.logger.debug('Executing add_define')
         self.data.setdefault('defines', {})[name] = value
 
-    def set_arch(self, name):
-        """Set the VHDL architecture.
-
-        :param name: architecture name
-        :type name: str
-        """
-        self.logger.debug('Executing set_arch')
-        self.data['arch'] = name
-
     def add_fileset(self, pathname):
         """Add fileset file/s.
 
diff --git a/pyfpga/templates/vivado.jinja b/pyfpga/templates/vivado.jinja
index 05b1f0fa..2c593f69 100644
--- a/pyfpga/templates/vivado.jinja
+++ b/pyfpga/templates/vivado.jinja
@@ -32,10 +32,6 @@ set_property INCLUDE_DIRS { {{ INCLUDES}} } [current_fileset]
 set_property GENERIC { {{ PARAMS }} } -objects [get_filesets sources_1]
 {% endif %}
 
-{% if ARCH %}
-set_property TOP_ARCH {{ ARCH }} [current_fileset]
-{% endif %}
-
 {{ POSTCFG }}
 
 close_project
diff --git a/pyfpga/vivado.py b/pyfpga/vivado.py
index 3470123e..c0a625e6 100644
--- a/pyfpga/vivado.py
+++ b/pyfpga/vivado.py
@@ -67,8 +67,6 @@ def _make_prepare(self, steps):
             for key, value in self.data['params'].items():
                 params.append(f'{key}={value}')
             context['PARAMS'] = ' '.join(params)
-        if 'arch' in self.data:
-            context['ARCH'] = self.data['arch']
         if 'hooks' in self.data:
             for stage in self.data['hooks']:
                 context[stage.upper()] = '\n'.join(self.data['hooks'][stage])
diff --git a/tests/test_data.py b/tests/test_data.py
index 69446951..250ea793 100644
--- a/tests/test_data.py
+++ b/tests/test_data.py
@@ -45,7 +45,6 @@
         'DEF2': 'VAL2',
         'DEF3': 'VAL3'
     },
-    'arch': 'ARCHNAME',
     'hooks': {
         'precfg': ['CMD1', 'CMD2'],
         'postcfg': ['CMD1', 'CMD2'],
@@ -63,7 +62,6 @@ def test_data():
     prj = Project()
     prj.set_part('PARTNAME')
     prj.set_top('TOPNAME')
-    prj.set_arch('ARCHNAME')
     prj.add_include('fakedata/dir1')
     prj.add_include('fakedata/dir2')
     prj.add_include('fakedata/dir3')
diff --git a/tests/test_vivado.py b/tests/test_vivado.py
index 787e90cb..57781a09 100644
--- a/tests/test_vivado.py
+++ b/tests/test_vivado.py
@@ -5,7 +5,6 @@ def test_vivado():
     prj = Vivado()
     prj.set_part('PARTNAME')
     prj.set_top('TOPNAME')
-    prj.set_arch('ARCHNAME')
     prj.add_include('fakedata/dir1')
     prj.add_include('fakedata/dir2')
     prj.add_slog('fakedata/**/*.sv')

From 9584c4936f4c40689e47acf9df24513696ff940f Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 24 Jun 2024 19:41:19 -0300
Subject: [PATCH 100/248] Removed unused files

---
 pyfpga/factory.py |  44 -------------------
 pyfpga/tool.py    | 105 ----------------------------------------------
 2 files changed, 149 deletions(-)
 delete mode 100644 pyfpga/factory.py
 delete mode 100644 pyfpga/tool.py

diff --git a/pyfpga/factory.py b/pyfpga/factory.py
deleted file mode 100644
index 6236730e..00000000
--- a/pyfpga/factory.py
+++ /dev/null
@@ -1,44 +0,0 @@
-#
-# Copyright (C) 2024 Rodrigo A. Melo
-#
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-
-"""
-A factory class to create FPGA projects.
-"""
-
-from pyfpga.ise import Ise
-from pyfpga.libero import Libero
-from pyfpga.openflow import Openflow
-from pyfpga.quartus import Quartus
-from pyfpga.vivado import Vivado
-
-# pylint: disable=return-in-init
-# pylint: disable=no-else-return
-# pylint: disable=too-many-return-statements
-# pylint: disable=too-few-public-methods
-
-
-class Factory:
-    """A factory class to create FPGA projects."""
-
-    def __init__(
-            self, tool='vivado', project=None):
-        """Class constructor."""
-        if tool == 'ghdl':
-            return Openflow(project)  # , frontend='ghdl', backend='vhdl')
-        elif tool == 'ise':
-            return Ise(project)
-        elif tool == 'libero':
-            return Libero(project)
-        elif tool == 'openflow':
-            return Openflow(project)
-        elif tool == 'quartus':
-            return Quartus(project)
-        elif tool == 'vivado':
-            return Vivado(project)
-        elif tool == 'yosys':
-            return Openflow(project)  # , frontend='yosys', backend='verilog')
-        else:
-            raise NotImplementedError(tool)
diff --git a/pyfpga/tool.py b/pyfpga/tool.py
deleted file mode 100644
index 30309ad0..00000000
--- a/pyfpga/tool.py
+++ /dev/null
@@ -1,105 +0,0 @@
-#
-# Copyright (C) 2019-2024 Rodrigo A. Melo
-#
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-
-"""
-Defines the interface to be inherited to support a tool.
-"""
-
-# def tcl_path(path):
-#     """Returns a Tcl suitable path."""
-#     return path.replace(os.path.sep, "/")
-
-# pylint: disable=too-few-public-methods
-
-
-class Tool:
-    """Tool interface."""
-
-#     def _create_gen_script(self, tasks):
-#         """Create the script for generate execution."""
-#         # Paths and files
-#         files = []
-#         if self.presynth:
-#             files.append(f'    fpga_file {self.project}.edif')
-#         else:
-#             for path in self.paths:
-#                 files.append(f'    fpga_include {tcl_path(path)}')
-#             for file in self.files['verilog']:
-#                 files.append(f'    fpga_file {tcl_path(file[0])}')
-#             for file in self.files['vhdl']:
-#                 if file[1] is None:
-#                     files.append(f'    fpga_file {tcl_path(file[0])}')
-#                 else:
-#                     files.append(
-#                         f'    fpga_file {tcl_path(file[0])} {file[1]}'
-#                     )
-#         for file in self.files['design']:
-#             files.append(f'    fpga_design {tcl_path(file[0])}')
-#         for file in self.files['constraint']:
-#             files.append(f'    fpga_file {tcl_path(file[0])}')
-#         # Parameters
-#         params = []
-#         for param in self.params:
-#             params.append(f'{{ {param[0]} {param[1]} }}')
-#         # Script creation
-#         template = os.path.join(os.path.dirname(__file__), 'template.tcl')
-#         with open(template, 'r', encoding='utf-8') as file:
-#             tcl = file.read()
-#         tcl = tcl.replace('#TOOL#', self._TOOL)
-#         tcl = tcl.replace('#PRESYNTH#', "True" if self.presynth else "False")
-#         tcl = tcl.replace('#PROJECT#', self.project)
-#         tcl = tcl.replace('#PART#', self.part['name'])
-#         tcl = tcl.replace('#FAMILY#', self.part['family'])
-#         tcl = tcl.replace('#DEVICE#', self.part['device'])
-#         tcl = tcl.replace('#PACKAGE#', self.part['package'])
-#         tcl = tcl.replace('#SPEED#', self.part['speed'])
-#         tcl = tcl.replace('#PARAMS#', ' '.join(params))
-#         tcl = tcl.replace('#FILES#', '\n'.join(files))
-#         tcl = tcl.replace('#TOP#', self.top)
-#         tcl = tcl.replace('#TASKS#', tasks)
-#         tcl = tcl.replace('#PREFILE_CMDS#', '\n'.join(self.cmds['prefile']))
-#         tcl = tcl.replace('#PROJECT_CMDS#', '\n'.join(self.cmds['project']))
-#         tcl = tcl.replace('#PREFLOW_CMDS#', '\n'.join(self.cmds['preflow']))
-#         tcl = tcl.replace('#POSTSYN_CMDS#', '\n'.join(self.cmds['postsyn']))
-#         tcl = tcl.replace('#POSTPAR_CMDS#', '\n'.join(self.cmds['postpar']))
-#         tcl = tcl.replace('#POSTBIT_CMDS#', '\n'.join(self.cmds['postbit']))
-#         with open(f'{self._TOOL}.tcl', 'w', encoding='utf-8') as file:
-#             file.write(tcl)
-
-#     def generate(self, to_task, from_task, capture):
-#         """Run the FPGA tool."""
-#         check_value(to_task, TASKS)
-#         check_value(from_task, TASKS)
-#         to_index = TASKS.index(to_task)
-#         from_index = TASKS.index(from_task)
-#         if from_index > to_index:
-#             raise ValueError(
-#                 f'initial task "{from_task}" cannot be later than the ' +
-#                 f'last task "{to_task}"'
-#             )
-#         tasks = " ".join(TASKS[from_index:to_index+1])
-#         self._create_gen_script(tasks)
-#         if not which(self._GEN_PROGRAM):
-#             raise RuntimeError(f'program "{self._GEN_PROGRAM}" not found')
-#         return run(self._GEN_COMMAND, capture)
-
-#     def transfer(self, devtype, position, part, width, capture):
-#         """Transfer a bitstream."""
-#         if not which(self._TRF_PROGRAM):
-#             raise RuntimeError(f'program "{self._TRF_PROGRAM}" not found')
-#         check_value(devtype, self._DEVTYPES)
-#         check_value(position, range(10))
-#         isinstance(part, str)
-#         check_value(width, MEMWIDTHS)
-#         isinstance(capture, bool)
-#         # Bitstream autodiscovery
-#         if not self.bitstream and devtype not in ['detect', 'unlock']:
-#             bitstream = []
-#             for ext in self._BIT_EXT:
-#                 bitstream.extend(glob(f'**/*.{ext}', recursive=True))
-#             if len(bitstream) == 0:
-#                 raise FileNotFoundError('bitStream not found')
-#             self.bitstream = bitstream[0]

From b04a22290fc811f210b3416186bfbff9a714f5d9 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 24 Jun 2024 19:43:54 -0300
Subject: [PATCH 101/248] Moved the zybo constraints from the Vivado example to
 sources

---
 examples/{vivado => }/sources/zybo/clk.xdc    | 0
 examples/{vivado => }/sources/zybo/led.xdc    | 0
 examples/{vivado => }/sources/zybo/timing.xdc | 0
 examples/vivado/vivado.py                     | 6 +++---
 4 files changed, 3 insertions(+), 3 deletions(-)
 rename examples/{vivado => }/sources/zybo/clk.xdc (100%)
 rename examples/{vivado => }/sources/zybo/led.xdc (100%)
 rename examples/{vivado => }/sources/zybo/timing.xdc (100%)

diff --git a/examples/vivado/sources/zybo/clk.xdc b/examples/sources/zybo/clk.xdc
similarity index 100%
rename from examples/vivado/sources/zybo/clk.xdc
rename to examples/sources/zybo/clk.xdc
diff --git a/examples/vivado/sources/zybo/led.xdc b/examples/sources/zybo/led.xdc
similarity index 100%
rename from examples/vivado/sources/zybo/led.xdc
rename to examples/sources/zybo/led.xdc
diff --git a/examples/vivado/sources/zybo/timing.xdc b/examples/sources/zybo/timing.xdc
similarity index 100%
rename from examples/vivado/sources/zybo/timing.xdc
rename to examples/sources/zybo/timing.xdc
diff --git a/examples/vivado/vivado.py b/examples/vivado/vivado.py
index 930e62cd..99ec2745 100644
--- a/examples/vivado/vivado.py
+++ b/examples/vivado/vivado.py
@@ -27,9 +27,9 @@
     prj.add_vlog('../sources/slog/*.sv')
 if args.source in ['vlog', 'slog']:
     prj.add_define('DEFINE', '1')
-prj.add_cons('sources/zybo/timing.xdc', 'syn')
-prj.add_cons('sources/zybo/clk.xdc', 'par')
-prj.add_cons('sources/zybo/led.xdc', 'par')
+prj.add_cons('../sources/zybo/timing.xdc', 'syn')
+prj.add_cons('../sources/zybo/clk.xdc', 'par')
+prj.add_cons('../sources/zybo/led.xdc', 'par')
 prj.set_top('Top')
 
 if args.action in ['make', 'all']:

From 8fcf3d700767f8713d18c051c2ad1d68ec687fc7 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 24 Jun 2024 20:28:50 -0300
Subject: [PATCH 102/248] Simplified Vivado example content

---
 examples/vivado/Makefile              |   6 -
 examples/vivado/README.md             |  31 --
 examples/vivado/design.py             |  33 --
 examples/vivado/design.tcl            | 608 --------------------------
 examples/vivado/{vivado.py => run.py} |   0
 examples/vivado/run.sh                |  10 +
 6 files changed, 10 insertions(+), 678 deletions(-)
 delete mode 100644 examples/vivado/Makefile
 delete mode 100644 examples/vivado/README.md
 delete mode 100644 examples/vivado/design.py
 delete mode 100644 examples/vivado/design.tcl
 rename examples/vivado/{vivado.py => run.py} (100%)
 create mode 100644 examples/vivado/run.sh

diff --git a/examples/vivado/Makefile b/examples/vivado/Makefile
deleted file mode 100644
index f166a9f9..00000000
--- a/examples/vivado/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/usr/bin/make
-
-SCRIPTS = $(wildcard *.py)
-
-all:
-	@$(foreach SCRIPT, $(SCRIPTS), python3 $(SCRIPT) || exit;)
diff --git a/examples/vivado/README.md b/examples/vivado/README.md
deleted file mode 100644
index 42c3fbf0..00000000
--- a/examples/vivado/README.md
+++ /dev/null
@@ -1,31 +0,0 @@
-# Vivado examples
-
-The Zybo related things are the FPGA part and the constraints file.
-Modify them to make this example compatible with another board.
-
-* `python3 vivado.py` generates a bitstream based on VHDL files.
-* `python3 vivado.py --action transfer` to transfer the generated bitstream to the board.
-* `python3 design.py` generates the bitstream based on a Vivado Block design.
-
-## How to get a compatible Vivado Block Design
-
-* In the *Flow Navigator* panel, under *IP INTEGRATOR*, click on *Create Block Design*.
-* Work on your design.
-* *File* -> *Export* -> *Export Block Design* to create a Tcl file to re-generate your design.
-
-> Tip: open the generated Tcl file and remove the following code (which is generally a problem instead of help):
-
-```tcl
-################################################################
-# Check if script is running in correct Vivado version.
-################################################################
-set scripts_vivado_version 2019.2
-set current_vivado_version [version -short]
-
-if { [string first $scripts_vivado_version $current_vivado_version] == -1 } {
-   puts ""
-   catch {common::send_msg_id "BD_TCL-109" "ERROR" "This script was generated using Vivado <$scripts_vivado_version> and is being run in <$current_vivado_version> of Vivado. Please run the script in Vivado <$scripts_vivado_version> then open the design in Vivado <$current_vivado_version>. Upgrade the design by running \"Tools => Report => Report IP Status...\", then run write_bd_tcl to create an updated script."}
-
-   return 1
-}
-```
diff --git a/examples/vivado/design.py b/examples/vivado/design.py
deleted file mode 100644
index 7ac4eef3..00000000
--- a/examples/vivado/design.py
+++ /dev/null
@@ -1,33 +0,0 @@
-"""Zybo block design example project."""
-
-import logging
-
-from fpga.project import Project
-
-logging.basicConfig()
-
-prj = Project('vivado', 'zybo-design')
-prj.set_part('xc7z010-1-clg400')
-
-prj.set_outdir('../../build/zybo-design')
-
-prj.add_files('../../hdl/blinking.vhdl')
-prj.add_files('zybo.xdc')
-prj.add_files('design.tcl', filetype='design')
-
-export = """
-set PROJECT %s
-if { [ catch {
-    # Vitis
-    write_hw_platform -fixed -force -include_bit -file ${PROJECT}.xsa
-} ] } {
-    # SDK
-    write_hwdef -force -file ${PROJECT}.hwdef
-    write_sysdef -force -hwdef [glob -nocomplain *.hwdef] \\
-       -bitfile [glob -nocomplain *.bit] -file ${PROJECT}.hdf
-}
-""" % ('zybo-design')
-
-prj.add_hook(export, 'postbit')
-
-prj.generate()
diff --git a/examples/vivado/design.tcl b/examples/vivado/design.tcl
deleted file mode 100644
index 4b10a0d4..00000000
--- a/examples/vivado/design.tcl
+++ /dev/null
@@ -1,608 +0,0 @@
-################################################################
-# START
-################################################################
-
-# CHANGE DESIGN NAME HERE
-variable design_name
-set design_name design_1
-
-# If you do not already have an existing IP Integrator design open,
-# you can create a design using the following command:
-#    create_bd_design $design_name
-
-# Creating design if needed
-set errMsg ""
-set nRet 0
-
-set cur_design [current_bd_design -quiet]
-set list_cells [get_bd_cells -quiet]
-
-if { ${design_name} eq "" } {
-   # USE CASES:
-   #    1) Design_name not set
-
-   set errMsg "Please set the variable <design_name> to a non-empty value."
-   set nRet 1
-
-} elseif { ${cur_design} ne "" && ${list_cells} eq "" } {
-   # USE CASES:
-   #    2): Current design opened AND is empty AND names same.
-   #    3): Current design opened AND is empty AND names diff; design_name NOT in project.
-   #    4): Current design opened AND is empty AND names diff; design_name exists in project.
-
-   if { $cur_design ne $design_name } {
-      common::send_msg_id "BD_TCL-001" "INFO" "Changing value of <design_name> from <$design_name> to <$cur_design> since current design is empty."
-      set design_name [get_property NAME $cur_design]
-   }
-   common::send_msg_id "BD_TCL-002" "INFO" "Constructing design in IPI design <$cur_design>..."
-
-} elseif { ${cur_design} ne "" && $list_cells ne "" && $cur_design eq $design_name } {
-   # USE CASES:
-   #    5) Current design opened AND has components AND same names.
-
-   set errMsg "Design <$design_name> already exists in your project, please set the variable <design_name> to another value."
-   set nRet 1
-} elseif { [get_files -quiet ${design_name}.bd] ne "" } {
-   # USE CASES:
-   #    6) Current opened design, has components, but diff names, design_name exists in project.
-   #    7) No opened design, design_name exists in project.
-
-   set errMsg "Design <$design_name> already exists in your project, please set the variable <design_name> to another value."
-   set nRet 2
-
-} else {
-   # USE CASES:
-   #    8) No opened design, design_name not in project.
-   #    9) Current opened design, has components, but diff names, design_name not in project.
-
-   common::send_msg_id "BD_TCL-003" "INFO" "Currently there is no design <$design_name> in project, so creating one..."
-
-   create_bd_design $design_name
-
-   common::send_msg_id "BD_TCL-004" "INFO" "Making design <$design_name> as current_bd_design."
-   current_bd_design $design_name
-
-}
-
-common::send_msg_id "BD_TCL-005" "INFO" "Currently the variable <design_name> is equal to \"$design_name\"."
-
-if { $nRet != 0 } {
-   catch {common::send_msg_id "BD_TCL-114" "ERROR" $errMsg}
-   return $nRet
-}
-
-set bCheckIPsPassed 1
-##################################################################
-# CHECK IPs
-##################################################################
-set bCheckIPs 1
-if { $bCheckIPs == 1 } {
-   set list_check_ips "\
-xilinx.com:ip:processing_system7:5.5\
-"
-
-   set list_ips_missing ""
-   common::send_msg_id "BD_TCL-006" "INFO" "Checking if the following IPs exist in the project's IP catalog: $list_check_ips ."
-
-   foreach ip_vlnv $list_check_ips {
-      set ip_obj [get_ipdefs -all $ip_vlnv]
-      if { $ip_obj eq "" } {
-         lappend list_ips_missing $ip_vlnv
-      }
-   }
-
-   if { $list_ips_missing ne "" } {
-      catch {common::send_msg_id "BD_TCL-115" "ERROR" "The following IPs are not found in the IP Catalog:\n  $list_ips_missing\n\nResolution: Please add the repository containing the IP(s) to the project." }
-      set bCheckIPsPassed 0
-   }
-
-}
-
-##################################################################
-# CHECK Modules
-##################################################################
-set bCheckModules 1
-if { $bCheckModules == 1 } {
-   set list_check_mods "\
-Blinking\
-"
-
-   set list_mods_missing ""
-   common::send_msg_id "BD_TCL-006" "INFO" "Checking if the following modules exist in the project's sources: $list_check_mods ."
-
-   foreach mod_vlnv $list_check_mods {
-      if { [can_resolve_reference $mod_vlnv] == 0 } {
-         lappend list_mods_missing $mod_vlnv
-      }
-   }
-
-   if { $list_mods_missing ne "" } {
-      catch {common::send_msg_id "BD_TCL-115" "ERROR" "The following module(s) are not found in the project: $list_mods_missing" }
-      common::send_msg_id "BD_TCL-008" "INFO" "Please add source files for the missing module(s) above."
-      set bCheckIPsPassed 0
-   }
-}
-
-if { $bCheckIPsPassed != 1 } {
-  common::send_msg_id "BD_TCL-1003" "WARNING" "Will not continue with creation of design due to the error(s) above."
-  return 3
-}
-
-##################################################################
-# DESIGN PROCs
-##################################################################
-
-
-
-# Procedure to create entire design; Provide argument to make
-# procedure reusable. If parentCell is "", will use root.
-proc create_root_design { parentCell } {
-
-  variable design_name
-
-  if { $parentCell eq "" } {
-     set parentCell [get_bd_cells /]
-  }
-
-  # Get object for parentCell
-  set parentObj [get_bd_cells $parentCell]
-  if { $parentObj == "" } {
-     catch {common::send_msg_id "BD_TCL-100" "ERROR" "Unable to find parent cell <$parentCell>!"}
-     return
-  }
-
-  # Make sure parentObj is hier blk
-  set parentType [get_property TYPE $parentObj]
-  if { $parentType ne "hier" } {
-     catch {common::send_msg_id "BD_TCL-101" "ERROR" "Parent <$parentObj> has TYPE = <$parentType>. Expected to be <hier>."}
-     return
-  }
-
-  # Save current instance; Restore later
-  set oldCurInst [current_bd_instance .]
-
-  # Set parent object as current
-  current_bd_instance $parentObj
-
-
-  # Create interface ports
-  set DDR [ create_bd_intf_port -mode Master -vlnv xilinx.com:interface:ddrx_rtl:1.0 DDR ]
-
-  set FIXED_IO [ create_bd_intf_port -mode Master -vlnv xilinx.com:display_processing_system7:fixedio_rtl:1.0 FIXED_IO ]
-
-
-  # Create ports
-  set clk_i [ create_bd_port -dir I clk_i ]
-  set led_o [ create_bd_port -dir O led_o ]
-
-  # Create instance: Blinking_0, and set properties
-  set block_name Blinking
-  set block_cell_name Blinking_0
-  if { [catch {set Blinking_0 [create_bd_cell -type module -reference $block_name $block_cell_name] } errmsg] } {
-     catch {common::send_msg_id "BD_TCL-105" "ERROR" "Unable to add referenced block <$block_name>. Please add the files for ${block_name}'s definition into the project."}
-     return 1
-   } elseif { $Blinking_0 eq "" } {
-     catch {common::send_msg_id "BD_TCL-106" "ERROR" "Unable to referenced block <$block_name>. Please add the files for ${block_name}'s definition into the project."}
-     return 1
-   }
-    set_property -dict [ list \
-   CONFIG.FREQ {125000000} \
- ] $Blinking_0
-
-  # Create instance: processing_system7_0, and set properties
-  set processing_system7_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:processing_system7:5.5 processing_system7_0 ]
-  set_property -dict [ list \
-   CONFIG.PCW_ACT_APU_PERIPHERAL_FREQMHZ {650} \
-   CONFIG.PCW_ACT_CAN_PERIPHERAL_FREQMHZ {10} \
-   CONFIG.PCW_ACT_DCI_PERIPHERAL_FREQMHZ {10} \
-   CONFIG.PCW_ACT_ENET0_PERIPHERAL_FREQMHZ {10} \
-   CONFIG.PCW_ACT_ENET1_PERIPHERAL_FREQMHZ {10} \
-   CONFIG.PCW_ACT_FPGA0_PERIPHERAL_FREQMHZ {10} \
-   CONFIG.PCW_ACT_FPGA1_PERIPHERAL_FREQMHZ {10} \
-   CONFIG.PCW_ACT_FPGA2_PERIPHERAL_FREQMHZ {10} \
-   CONFIG.PCW_ACT_FPGA3_PERIPHERAL_FREQMHZ {10} \
-   CONFIG.PCW_ACT_PCAP_PERIPHERAL_FREQMHZ {200} \
-   CONFIG.PCW_ACT_QSPI_PERIPHERAL_FREQMHZ {200} \
-   CONFIG.PCW_ACT_SDIO_PERIPHERAL_FREQMHZ {50} \
-   CONFIG.PCW_ACT_SMC_PERIPHERAL_FREQMHZ {10} \
-   CONFIG.PCW_ACT_SPI_PERIPHERAL_FREQMHZ {10} \
-   CONFIG.PCW_ACT_TPIU_PERIPHERAL_FREQMHZ {200} \
-   CONFIG.PCW_ACT_TTC0_CLK0_PERIPHERAL_FREQMHZ {108} \
-   CONFIG.PCW_ACT_TTC0_CLK1_PERIPHERAL_FREQMHZ {108} \
-   CONFIG.PCW_ACT_TTC0_CLK2_PERIPHERAL_FREQMHZ {108} \
-   CONFIG.PCW_ACT_TTC1_CLK0_PERIPHERAL_FREQMHZ {108} \
-   CONFIG.PCW_ACT_TTC1_CLK1_PERIPHERAL_FREQMHZ {108} \
-   CONFIG.PCW_ACT_TTC1_CLK2_PERIPHERAL_FREQMHZ {108} \
-   CONFIG.PCW_ACT_UART_PERIPHERAL_FREQMHZ {100} \
-   CONFIG.PCW_ACT_WDT_PERIPHERAL_FREQMHZ {108} \
-   CONFIG.PCW_APU_PERIPHERAL_FREQMHZ {650} \
-   CONFIG.PCW_ARMPLL_CTRL_FBDIV {26} \
-   CONFIG.PCW_CAN_PERIPHERAL_DIVISOR0 {1} \
-   CONFIG.PCW_CAN_PERIPHERAL_DIVISOR1 {1} \
-   CONFIG.PCW_CLK0_FREQ {10000000} \
-   CONFIG.PCW_CLK1_FREQ {10000000} \
-   CONFIG.PCW_CLK2_FREQ {10000000} \
-   CONFIG.PCW_CLK3_FREQ {10000000} \
-   CONFIG.PCW_CPU_CPU_PLL_FREQMHZ {1300} \
-   CONFIG.PCW_CPU_PERIPHERAL_DIVISOR0 {2} \
-   CONFIG.PCW_CRYSTAL_PERIPHERAL_FREQMHZ {50.000000} \
-   CONFIG.PCW_DCI_PERIPHERAL_DIVISOR0 {15} \
-   CONFIG.PCW_DCI_PERIPHERAL_DIVISOR1 {7} \
-   CONFIG.PCW_DDRPLL_CTRL_FBDIV {21} \
-   CONFIG.PCW_DDR_DDR_PLL_FREQMHZ {1050} \
-   CONFIG.PCW_DDR_PERIPHERAL_DIVISOR0 {2} \
-   CONFIG.PCW_DDR_RAM_HIGHADDR {0x1FFFFFFF} \
-   CONFIG.PCW_ENET0_ENET0_IO {<Select>} \
-   CONFIG.PCW_ENET0_GRP_MDIO_ENABLE {0} \
-   CONFIG.PCW_ENET0_GRP_MDIO_IO {<Select>} \
-   CONFIG.PCW_ENET0_PERIPHERAL_DIVISOR0 {1} \
-   CONFIG.PCW_ENET0_PERIPHERAL_DIVISOR1 {1} \
-   CONFIG.PCW_ENET0_PERIPHERAL_ENABLE {0} \
-   CONFIG.PCW_ENET0_PERIPHERAL_FREQMHZ {1000 Mbps} \
-   CONFIG.PCW_ENET0_RESET_ENABLE {0} \
-   CONFIG.PCW_ENET1_PERIPHERAL_DIVISOR0 {1} \
-   CONFIG.PCW_ENET1_PERIPHERAL_DIVISOR1 {1} \
-   CONFIG.PCW_ENET1_RESET_ENABLE {0} \
-   CONFIG.PCW_ENET_RESET_ENABLE {0} \
-   CONFIG.PCW_ENET_RESET_SELECT {<Select>} \
-   CONFIG.PCW_EN_CLK0_PORT {0} \
-   CONFIG.PCW_EN_EMIO_TTC0 {0} \
-   CONFIG.PCW_EN_EMIO_WP_SDIO0 {1} \
-   CONFIG.PCW_EN_ENET0 {0} \
-   CONFIG.PCW_EN_GPIO {0} \
-   CONFIG.PCW_EN_QSPI {1} \
-   CONFIG.PCW_EN_RST0_PORT {0} \
-   CONFIG.PCW_EN_SDIO0 {1} \
-   CONFIG.PCW_EN_TTC0 {0} \
-   CONFIG.PCW_EN_UART1 {1} \
-   CONFIG.PCW_EN_USB0 {0} \
-   CONFIG.PCW_FCLK0_PERIPHERAL_DIVISOR0 {1} \
-   CONFIG.PCW_FCLK0_PERIPHERAL_DIVISOR1 {1} \
-   CONFIG.PCW_FCLK1_PERIPHERAL_DIVISOR0 {1} \
-   CONFIG.PCW_FCLK1_PERIPHERAL_DIVISOR1 {1} \
-   CONFIG.PCW_FCLK2_PERIPHERAL_DIVISOR0 {1} \
-   CONFIG.PCW_FCLK2_PERIPHERAL_DIVISOR1 {1} \
-   CONFIG.PCW_FCLK3_PERIPHERAL_DIVISOR0 {1} \
-   CONFIG.PCW_FCLK3_PERIPHERAL_DIVISOR1 {1} \
-   CONFIG.PCW_FCLK_CLK0_BUF {FALSE} \
-   CONFIG.PCW_FPGA0_PERIPHERAL_FREQMHZ {100} \
-   CONFIG.PCW_FPGA_FCLK0_ENABLE {0} \
-   CONFIG.PCW_FPGA_FCLK1_ENABLE {0} \
-   CONFIG.PCW_FPGA_FCLK2_ENABLE {0} \
-   CONFIG.PCW_FPGA_FCLK3_ENABLE {0} \
-   CONFIG.PCW_GPIO_MIO_GPIO_ENABLE {0} \
-   CONFIG.PCW_GPIO_MIO_GPIO_IO {<Select>} \
-   CONFIG.PCW_I2C0_RESET_ENABLE {0} \
-   CONFIG.PCW_I2C1_RESET_ENABLE {0} \
-   CONFIG.PCW_I2C_PERIPHERAL_FREQMHZ {25} \
-   CONFIG.PCW_I2C_RESET_ENABLE {0} \
-   CONFIG.PCW_IOPLL_CTRL_FBDIV {32} \
-   CONFIG.PCW_IO_IO_PLL_FREQMHZ {1600} \
-   CONFIG.PCW_MIO_0_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_0_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_0_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_0_SLEW {<Select>} \
-   CONFIG.PCW_MIO_10_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_10_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_10_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_10_SLEW {<Select>} \
-   CONFIG.PCW_MIO_11_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_11_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_11_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_11_SLEW {<Select>} \
-   CONFIG.PCW_MIO_12_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_12_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_12_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_12_SLEW {<Select>} \
-   CONFIG.PCW_MIO_13_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_13_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_13_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_13_SLEW {<Select>} \
-   CONFIG.PCW_MIO_14_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_14_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_14_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_14_SLEW {<Select>} \
-   CONFIG.PCW_MIO_15_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_15_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_15_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_15_SLEW {<Select>} \
-   CONFIG.PCW_MIO_16_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_16_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_16_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_16_SLEW {<Select>} \
-   CONFIG.PCW_MIO_17_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_17_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_17_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_17_SLEW {<Select>} \
-   CONFIG.PCW_MIO_18_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_18_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_18_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_18_SLEW {<Select>} \
-   CONFIG.PCW_MIO_19_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_19_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_19_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_19_SLEW {<Select>} \
-   CONFIG.PCW_MIO_1_DIRECTION {out} \
-   CONFIG.PCW_MIO_1_IOTYPE {LVCMOS 3.3V} \
-   CONFIG.PCW_MIO_1_PULLUP {disabled} \
-   CONFIG.PCW_MIO_1_SLEW {fast} \
-   CONFIG.PCW_MIO_20_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_20_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_20_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_20_SLEW {<Select>} \
-   CONFIG.PCW_MIO_21_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_21_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_21_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_21_SLEW {<Select>} \
-   CONFIG.PCW_MIO_22_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_22_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_22_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_22_SLEW {<Select>} \
-   CONFIG.PCW_MIO_23_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_23_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_23_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_23_SLEW {<Select>} \
-   CONFIG.PCW_MIO_24_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_24_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_24_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_24_SLEW {<Select>} \
-   CONFIG.PCW_MIO_25_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_25_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_25_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_25_SLEW {<Select>} \
-   CONFIG.PCW_MIO_26_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_26_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_26_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_26_SLEW {<Select>} \
-   CONFIG.PCW_MIO_27_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_27_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_27_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_27_SLEW {<Select>} \
-   CONFIG.PCW_MIO_28_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_28_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_28_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_28_SLEW {<Select>} \
-   CONFIG.PCW_MIO_29_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_29_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_29_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_29_SLEW {<Select>} \
-   CONFIG.PCW_MIO_2_DIRECTION {inout} \
-   CONFIG.PCW_MIO_2_IOTYPE {LVCMOS 3.3V} \
-   CONFIG.PCW_MIO_2_PULLUP {disabled} \
-   CONFIG.PCW_MIO_2_SLEW {fast} \
-   CONFIG.PCW_MIO_30_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_30_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_30_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_30_SLEW {<Select>} \
-   CONFIG.PCW_MIO_31_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_31_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_31_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_31_SLEW {<Select>} \
-   CONFIG.PCW_MIO_32_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_32_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_32_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_32_SLEW {<Select>} \
-   CONFIG.PCW_MIO_33_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_33_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_33_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_33_SLEW {<Select>} \
-   CONFIG.PCW_MIO_34_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_34_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_34_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_34_SLEW {<Select>} \
-   CONFIG.PCW_MIO_35_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_35_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_35_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_35_SLEW {<Select>} \
-   CONFIG.PCW_MIO_36_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_36_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_36_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_36_SLEW {<Select>} \
-   CONFIG.PCW_MIO_37_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_37_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_37_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_37_SLEW {<Select>} \
-   CONFIG.PCW_MIO_38_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_38_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_38_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_38_SLEW {<Select>} \
-   CONFIG.PCW_MIO_39_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_39_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_39_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_39_SLEW {<Select>} \
-   CONFIG.PCW_MIO_3_DIRECTION {inout} \
-   CONFIG.PCW_MIO_3_IOTYPE {LVCMOS 3.3V} \
-   CONFIG.PCW_MIO_3_PULLUP {disabled} \
-   CONFIG.PCW_MIO_3_SLEW {fast} \
-   CONFIG.PCW_MIO_40_DIRECTION {inout} \
-   CONFIG.PCW_MIO_40_IOTYPE {LVCMOS 1.8V} \
-   CONFIG.PCW_MIO_40_PULLUP {disabled} \
-   CONFIG.PCW_MIO_40_SLEW {fast} \
-   CONFIG.PCW_MIO_41_DIRECTION {inout} \
-   CONFIG.PCW_MIO_41_IOTYPE {LVCMOS 1.8V} \
-   CONFIG.PCW_MIO_41_PULLUP {disabled} \
-   CONFIG.PCW_MIO_41_SLEW {fast} \
-   CONFIG.PCW_MIO_42_DIRECTION {inout} \
-   CONFIG.PCW_MIO_42_IOTYPE {LVCMOS 1.8V} \
-   CONFIG.PCW_MIO_42_PULLUP {disabled} \
-   CONFIG.PCW_MIO_42_SLEW {fast} \
-   CONFIG.PCW_MIO_43_DIRECTION {inout} \
-   CONFIG.PCW_MIO_43_IOTYPE {LVCMOS 1.8V} \
-   CONFIG.PCW_MIO_43_PULLUP {disabled} \
-   CONFIG.PCW_MIO_43_SLEW {fast} \
-   CONFIG.PCW_MIO_44_DIRECTION {inout} \
-   CONFIG.PCW_MIO_44_IOTYPE {LVCMOS 1.8V} \
-   CONFIG.PCW_MIO_44_PULLUP {disabled} \
-   CONFIG.PCW_MIO_44_SLEW {fast} \
-   CONFIG.PCW_MIO_45_DIRECTION {inout} \
-   CONFIG.PCW_MIO_45_IOTYPE {LVCMOS 1.8V} \
-   CONFIG.PCW_MIO_45_PULLUP {disabled} \
-   CONFIG.PCW_MIO_45_SLEW {fast} \
-   CONFIG.PCW_MIO_46_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_46_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_46_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_46_SLEW {<Select>} \
-   CONFIG.PCW_MIO_47_DIRECTION {in} \
-   CONFIG.PCW_MIO_47_IOTYPE {LVCMOS 1.8V} \
-   CONFIG.PCW_MIO_47_PULLUP {disabled} \
-   CONFIG.PCW_MIO_47_SLEW {slow} \
-   CONFIG.PCW_MIO_48_DIRECTION {out} \
-   CONFIG.PCW_MIO_48_IOTYPE {LVCMOS 1.8V} \
-   CONFIG.PCW_MIO_48_PULLUP {disabled} \
-   CONFIG.PCW_MIO_48_SLEW {slow} \
-   CONFIG.PCW_MIO_49_DIRECTION {in} \
-   CONFIG.PCW_MIO_49_IOTYPE {LVCMOS 1.8V} \
-   CONFIG.PCW_MIO_49_PULLUP {disabled} \
-   CONFIG.PCW_MIO_49_SLEW {slow} \
-   CONFIG.PCW_MIO_4_DIRECTION {inout} \
-   CONFIG.PCW_MIO_4_IOTYPE {LVCMOS 3.3V} \
-   CONFIG.PCW_MIO_4_PULLUP {disabled} \
-   CONFIG.PCW_MIO_4_SLEW {fast} \
-   CONFIG.PCW_MIO_50_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_50_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_50_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_50_SLEW {<Select>} \
-   CONFIG.PCW_MIO_51_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_51_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_51_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_51_SLEW {<Select>} \
-   CONFIG.PCW_MIO_52_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_52_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_52_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_52_SLEW {<Select>} \
-   CONFIG.PCW_MIO_53_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_53_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_53_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_53_SLEW {<Select>} \
-   CONFIG.PCW_MIO_5_DIRECTION {inout} \
-   CONFIG.PCW_MIO_5_IOTYPE {LVCMOS 3.3V} \
-   CONFIG.PCW_MIO_5_PULLUP {disabled} \
-   CONFIG.PCW_MIO_5_SLEW {fast} \
-   CONFIG.PCW_MIO_6_DIRECTION {out} \
-   CONFIG.PCW_MIO_6_IOTYPE {LVCMOS 3.3V} \
-   CONFIG.PCW_MIO_6_PULLUP {disabled} \
-   CONFIG.PCW_MIO_6_SLEW {fast} \
-   CONFIG.PCW_MIO_7_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_7_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_7_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_7_SLEW {<Select>} \
-   CONFIG.PCW_MIO_8_DIRECTION {out} \
-   CONFIG.PCW_MIO_8_IOTYPE {LVCMOS 3.3V} \
-   CONFIG.PCW_MIO_8_PULLUP {disabled} \
-   CONFIG.PCW_MIO_8_SLEW {fast} \
-   CONFIG.PCW_MIO_9_DIRECTION {<Select>} \
-   CONFIG.PCW_MIO_9_IOTYPE {<Select>} \
-   CONFIG.PCW_MIO_9_PULLUP {<Select>} \
-   CONFIG.PCW_MIO_9_SLEW {<Select>} \
-   CONFIG.PCW_MIO_TREE_PERIPHERALS {unassigned#Quad SPI Flash#Quad SPI Flash#Quad SPI Flash#Quad SPI Flash#Quad SPI Flash#Quad SPI Flash#unassigned#Quad SPI Flash#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#SD 0#SD 0#SD 0#SD 0#SD 0#SD 0#unassigned#SD 0#UART 1#UART 1#unassigned#unassigned#unassigned#unassigned} \
-   CONFIG.PCW_MIO_TREE_SIGNALS {unassigned#qspi0_ss_b#qspi0_io[0]#qspi0_io[1]#qspi0_io[2]#qspi0_io[3]/HOLD_B#qspi0_sclk#unassigned#qspi_fbclk#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#unassigned#clk#cmd#data[0]#data[1]#data[2]#data[3]#unassigned#cd#tx#rx#unassigned#unassigned#unassigned#unassigned} \
-   CONFIG.PCW_NAND_GRP_D8_ENABLE {0} \
-   CONFIG.PCW_NAND_PERIPHERAL_ENABLE {0} \
-   CONFIG.PCW_NOR_GRP_A25_ENABLE {0} \
-   CONFIG.PCW_NOR_GRP_CS0_ENABLE {0} \
-   CONFIG.PCW_NOR_GRP_CS1_ENABLE {0} \
-   CONFIG.PCW_NOR_GRP_SRAM_CS0_ENABLE {0} \
-   CONFIG.PCW_NOR_GRP_SRAM_CS1_ENABLE {0} \
-   CONFIG.PCW_NOR_GRP_SRAM_INT_ENABLE {0} \
-   CONFIG.PCW_NOR_PERIPHERAL_ENABLE {0} \
-   CONFIG.PCW_PCAP_PERIPHERAL_DIVISOR0 {8} \
-   CONFIG.PCW_PRESET_BANK1_VOLTAGE {LVCMOS 1.8V} \
-   CONFIG.PCW_QSPI_GRP_FBCLK_ENABLE {1} \
-   CONFIG.PCW_QSPI_GRP_FBCLK_IO {MIO 8} \
-   CONFIG.PCW_QSPI_GRP_IO1_ENABLE {0} \
-   CONFIG.PCW_QSPI_GRP_SINGLE_SS_ENABLE {1} \
-   CONFIG.PCW_QSPI_GRP_SINGLE_SS_IO {MIO 1 .. 6} \
-   CONFIG.PCW_QSPI_GRP_SS1_ENABLE {0} \
-   CONFIG.PCW_QSPI_PERIPHERAL_DIVISOR0 {8} \
-   CONFIG.PCW_QSPI_PERIPHERAL_ENABLE {1} \
-   CONFIG.PCW_QSPI_PERIPHERAL_FREQMHZ {200} \
-   CONFIG.PCW_QSPI_QSPI_IO {MIO 1 .. 6} \
-   CONFIG.PCW_SD0_GRP_CD_ENABLE {1} \
-   CONFIG.PCW_SD0_GRP_CD_IO {MIO 47} \
-   CONFIG.PCW_SD0_GRP_POW_ENABLE {0} \
-   CONFIG.PCW_SD0_GRP_WP_ENABLE {1} \
-   CONFIG.PCW_SD0_GRP_WP_IO {EMIO} \
-   CONFIG.PCW_SD0_PERIPHERAL_ENABLE {1} \
-   CONFIG.PCW_SD0_SD0_IO {MIO 40 .. 45} \
-   CONFIG.PCW_SDIO_PERIPHERAL_DIVISOR0 {32} \
-   CONFIG.PCW_SDIO_PERIPHERAL_FREQMHZ {50} \
-   CONFIG.PCW_SDIO_PERIPHERAL_VALID {1} \
-   CONFIG.PCW_SINGLE_QSPI_DATA_MODE {x4} \
-   CONFIG.PCW_SMC_PERIPHERAL_DIVISOR0 {1} \
-   CONFIG.PCW_SPI_PERIPHERAL_DIVISOR0 {1} \
-   CONFIG.PCW_TPIU_PERIPHERAL_DIVISOR0 {1} \
-   CONFIG.PCW_TTC0_CLK0_PERIPHERAL_FREQMHZ {133.333333} \
-   CONFIG.PCW_TTC0_CLK1_PERIPHERAL_FREQMHZ {133.333333} \
-   CONFIG.PCW_TTC0_CLK2_PERIPHERAL_FREQMHZ {133.333333} \
-   CONFIG.PCW_TTC0_PERIPHERAL_ENABLE {0} \
-   CONFIG.PCW_TTC0_TTC0_IO {<Select>} \
-   CONFIG.PCW_TTC_PERIPHERAL_FREQMHZ {50} \
-   CONFIG.PCW_UART1_GRP_FULL_ENABLE {0} \
-   CONFIG.PCW_UART1_PERIPHERAL_ENABLE {1} \
-   CONFIG.PCW_UART1_UART1_IO {MIO 48 .. 49} \
-   CONFIG.PCW_UART_PERIPHERAL_DIVISOR0 {16} \
-   CONFIG.PCW_UART_PERIPHERAL_FREQMHZ {100} \
-   CONFIG.PCW_UART_PERIPHERAL_VALID {1} \
-   CONFIG.PCW_UIPARAM_ACT_DDR_FREQ_MHZ {525} \
-   CONFIG.PCW_UIPARAM_DDR_BANK_ADDR_COUNT {3} \
-   CONFIG.PCW_UIPARAM_DDR_BOARD_DELAY0 {0.176} \
-   CONFIG.PCW_UIPARAM_DDR_BOARD_DELAY1 {0.159} \
-   CONFIG.PCW_UIPARAM_DDR_BOARD_DELAY2 {0.162} \
-   CONFIG.PCW_UIPARAM_DDR_BOARD_DELAY3 {0.187} \
-   CONFIG.PCW_UIPARAM_DDR_CL {7} \
-   CONFIG.PCW_UIPARAM_DDR_COL_ADDR_COUNT {10} \
-   CONFIG.PCW_UIPARAM_DDR_CWL {6} \
-   CONFIG.PCW_UIPARAM_DDR_DEVICE_CAPACITY {2048 MBits} \
-   CONFIG.PCW_UIPARAM_DDR_DQS_TO_CLK_DELAY_0 {-0.073} \
-   CONFIG.PCW_UIPARAM_DDR_DQS_TO_CLK_DELAY_1 {-0.034} \
-   CONFIG.PCW_UIPARAM_DDR_DQS_TO_CLK_DELAY_2 {-0.03} \
-   CONFIG.PCW_UIPARAM_DDR_DQS_TO_CLK_DELAY_3 {-0.082} \
-   CONFIG.PCW_UIPARAM_DDR_DRAM_WIDTH {16 Bits} \
-   CONFIG.PCW_UIPARAM_DDR_FREQ_MHZ {525} \
-   CONFIG.PCW_UIPARAM_DDR_PARTNO {MT41K128M16 JT-125} \
-   CONFIG.PCW_UIPARAM_DDR_ROW_ADDR_COUNT {14} \
-   CONFIG.PCW_UIPARAM_DDR_SPEED_BIN {DDR3_1066F} \
-   CONFIG.PCW_UIPARAM_DDR_TRAIN_DATA_EYE {1} \
-   CONFIG.PCW_UIPARAM_DDR_TRAIN_READ_GATE {1} \
-   CONFIG.PCW_UIPARAM_DDR_TRAIN_WRITE_LEVEL {1} \
-   CONFIG.PCW_UIPARAM_DDR_T_FAW {40.0} \
-   CONFIG.PCW_UIPARAM_DDR_T_RAS_MIN {35.0} \
-   CONFIG.PCW_UIPARAM_DDR_T_RC {48.75} \
-   CONFIG.PCW_UIPARAM_DDR_T_RCD {7} \
-   CONFIG.PCW_UIPARAM_DDR_T_RP {7} \
-   CONFIG.PCW_USB0_PERIPHERAL_ENABLE {0} \
-   CONFIG.PCW_USB0_PERIPHERAL_FREQMHZ {60} \
-   CONFIG.PCW_USB0_RESET_ENABLE {0} \
-   CONFIG.PCW_USB0_RESET_IO {<Select>} \
-   CONFIG.PCW_USB0_USB0_IO {<Select>} \
-   CONFIG.PCW_USB1_RESET_ENABLE {0} \
-   CONFIG.PCW_USB_RESET_ENABLE {0} \
-   CONFIG.PCW_USB_RESET_SELECT {<Select>} \
-   CONFIG.PCW_USE_M_AXI_GP0 {0} \
- ] $processing_system7_0
-
-  # Create interface connections
-  connect_bd_intf_net -intf_net processing_system7_0_DDR [get_bd_intf_ports DDR] [get_bd_intf_pins processing_system7_0/DDR]
-  connect_bd_intf_net -intf_net processing_system7_0_FIXED_IO [get_bd_intf_ports FIXED_IO] [get_bd_intf_pins processing_system7_0/FIXED_IO]
-
-  # Create port connections
-  connect_bd_net -net Blinking_0_led_o [get_bd_ports led_o] [get_bd_pins Blinking_0/led_o]
-  connect_bd_net -net clk_i_1 [get_bd_ports clk_i] [get_bd_pins Blinking_0/clk_i]
-
-  # Create address segments
-
-
-  # Restore current instance
-  current_bd_instance $oldCurInst
-
-  validate_bd_design
-  save_bd_design
-}
-# End of create_root_design()
-
-
-##################################################################
-# MAIN FLOW
-##################################################################
-
-create_root_design ""
diff --git a/examples/vivado/vivado.py b/examples/vivado/run.py
similarity index 100%
rename from examples/vivado/vivado.py
rename to examples/vivado/run.py
diff --git a/examples/vivado/run.sh b/examples/vivado/run.sh
new file mode 100644
index 00000000..f85dcc03
--- /dev/null
+++ b/examples/vivado/run.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+ACTIONS=("make" "prog" "all")
+SOURCES=("vlog" "vhdl" "slog" "design")
+
+for ACTION in "${ACTIONS[@]}"; do
+  for SOURCE in "${SOURCES[@]}"; do
+    python3 run.py --action $ACTION --source $SOURCE
+  done
+done

From 6c68cafcb668e2bf921b0dbc0abd2ec79a9fedde Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 24 Jun 2024 21:19:17 -0300
Subject: [PATCH 103/248] Added support for the Arty A7 35T in the Vivado
 example

---
 examples/sources/arty/a7-35t/clk.xdc        |  2 ++
 examples/sources/arty/a7-35t/led.xdc        |  2 ++
 examples/sources/arty/a7-35t/timing.xdc     |  1 +
 examples/sources/zybo/{ => ZYBO}/clk.xdc    |  0
 examples/sources/zybo/{ => ZYBO}/led.xdc    |  0
 examples/sources/zybo/{ => ZYBO}/timing.xdc |  0
 examples/vivado/run.py                      | 31 +++++++++++++++------
 examples/vivado/run.sh                      | 12 ++++++--
 8 files changed, 36 insertions(+), 12 deletions(-)
 create mode 100644 examples/sources/arty/a7-35t/clk.xdc
 create mode 100644 examples/sources/arty/a7-35t/led.xdc
 create mode 100644 examples/sources/arty/a7-35t/timing.xdc
 rename examples/sources/zybo/{ => ZYBO}/clk.xdc (100%)
 rename examples/sources/zybo/{ => ZYBO}/led.xdc (100%)
 rename examples/sources/zybo/{ => ZYBO}/timing.xdc (100%)

diff --git a/examples/sources/arty/a7-35t/clk.xdc b/examples/sources/arty/a7-35t/clk.xdc
new file mode 100644
index 00000000..ee01dcb3
--- /dev/null
+++ b/examples/sources/arty/a7-35t/clk.xdc
@@ -0,0 +1,2 @@
+set_property PACKAGE_PIN E3 [get_ports clk_i]
+set_property IOSTANDARD LVCMOS33 [get_ports clk_i]
diff --git a/examples/sources/arty/a7-35t/led.xdc b/examples/sources/arty/a7-35t/led.xdc
new file mode 100644
index 00000000..bf6d2304
--- /dev/null
+++ b/examples/sources/arty/a7-35t/led.xdc
@@ -0,0 +1,2 @@
+set_property PACKAGE_PIN H5  [get_ports led_o]
+set_property IOSTANDARD LVCMOS33 [get_ports led_o]
diff --git a/examples/sources/arty/a7-35t/timing.xdc b/examples/sources/arty/a7-35t/timing.xdc
new file mode 100644
index 00000000..4bfaa72f
--- /dev/null
+++ b/examples/sources/arty/a7-35t/timing.xdc
@@ -0,0 +1 @@
+create_clock -name clk_i -period 10.0 [get_ports clk_i]
diff --git a/examples/sources/zybo/clk.xdc b/examples/sources/zybo/ZYBO/clk.xdc
similarity index 100%
rename from examples/sources/zybo/clk.xdc
rename to examples/sources/zybo/ZYBO/clk.xdc
diff --git a/examples/sources/zybo/led.xdc b/examples/sources/zybo/ZYBO/led.xdc
similarity index 100%
rename from examples/sources/zybo/led.xdc
rename to examples/sources/zybo/ZYBO/led.xdc
diff --git a/examples/sources/zybo/timing.xdc b/examples/sources/zybo/ZYBO/timing.xdc
similarity index 100%
rename from examples/sources/zybo/timing.xdc
rename to examples/sources/zybo/ZYBO/timing.xdc
diff --git a/examples/vivado/run.py b/examples/vivado/run.py
index 99ec2745..2431466e 100644
--- a/examples/vivado/run.py
+++ b/examples/vivado/run.py
@@ -1,22 +1,37 @@
-"""Vivado VHDL example project."""
+"""Vivado examples."""
 
 import argparse
 
 from pyfpga.vivado import Vivado
 
+
 parser = argparse.ArgumentParser()
 parser.add_argument(
-    '--action', choices=['make', 'prog', 'all'], default='make'
+    '--board', choices=['zybo', 'arty'], default='zybo'
 )
 parser.add_argument(
-    '--source', choices=['vlog', 'vhdl', 'slog', 'design'], default='vlog'
+    '--source', choices=['vlog', 'vhdl', 'slog'], default='vlog'
+)
+parser.add_argument(
+    '--action', choices=['make', 'prog', 'all'], default='make'
 )
 args = parser.parse_args()
 
-prj = Vivado(odir=f'../build/vivado-{args.source}')
-prj.set_part('xc7z010-1-clg400')
+prj = Vivado(odir=f'../build/vivado')
+
+if args.board == 'zybo':
+    prj.set_part('xc7z010-1-clg400')
+    prj.add_param('FREQ', '125000000')
+    prj.add_cons('../sources/zybo/ZYBO/timing.xdc', 'syn')
+    prj.add_cons('../sources/zybo/ZYBO/clk.xdc', 'par')
+    prj.add_cons('../sources/zybo/ZYBO/led.xdc', 'par')
+if args.board == 'arty':
+    prj.set_part('xc7a35ticsg324-1L')
+    prj.add_param('FREQ', '100000000')
+    prj.add_cons('../sources/arty/a7-35t/timing.xdc', 'syn')
+    prj.add_cons('../sources/arty/a7-35t/clk.xdc', 'par')
+    prj.add_cons('../sources/arty/a7-35t/led.xdc', 'par')
 
-prj.add_param('FREQ', '125000000')
 if args.source == 'vhdl':
     prj.add_vhdl('../sources/vhdl/*.vhdl', 'blink_lib')
 if args.source == 'vlog':
@@ -27,9 +42,7 @@
     prj.add_vlog('../sources/slog/*.sv')
 if args.source in ['vlog', 'slog']:
     prj.add_define('DEFINE', '1')
-prj.add_cons('../sources/zybo/timing.xdc', 'syn')
-prj.add_cons('../sources/zybo/clk.xdc', 'par')
-prj.add_cons('../sources/zybo/led.xdc', 'par')
+
 prj.set_top('Top')
 
 if args.action in ['make', 'all']:
diff --git a/examples/vivado/run.sh b/examples/vivado/run.sh
index f85dcc03..bd894b91 100644
--- a/examples/vivado/run.sh
+++ b/examples/vivado/run.sh
@@ -1,10 +1,16 @@
 #!/bin/bash
 
+set -e
+
+BOARDS=("zybo" "arty")
+SOURCES=("vlog" "vhdl" "slog")
 ACTIONS=("make" "prog" "all")
-SOURCES=("vlog" "vhdl" "slog" "design")
 
-for ACTION in "${ACTIONS[@]}"; do
+for BOARD in "${BOARDS[@]}"; do
   for SOURCE in "${SOURCES[@]}"; do
-    python3 run.py --action $ACTION --source $SOURCE
+    for ACTION in "${ACTIONS[@]}"; do
+      echo "> $BOARD - $SOURCE - $ACTION"
+      python3 run.py --board $BOARD --source $SOURCE --action $ACTION
+    done
   done
 done

From c0b02c6680811185da203e470d4c7a5712565302 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Tue, 25 Jun 2024 22:08:00 -0300
Subject: [PATCH 104/248] Added initial (very early stage) support for Openflow

---
 examples/openflow/run.py        |  37 ++++++
 pyfpga/openflow.py              |  76 +++++++++++--
 pyfpga/templates/openflow.jinja | 194 ++++++--------------------------
 3 files changed, 141 insertions(+), 166 deletions(-)
 create mode 100644 examples/openflow/run.py

diff --git a/examples/openflow/run.py b/examples/openflow/run.py
new file mode 100644
index 00000000..8677a8a4
--- /dev/null
+++ b/examples/openflow/run.py
@@ -0,0 +1,37 @@
+"""Vivado examples."""
+
+import argparse
+
+from pyfpga.openflow import Openflow
+
+
+parser = argparse.ArgumentParser()
+parser.add_argument(
+    '--board', choices=['icestick', 'edu-ciaa', 'orangecrab', 'ecp5evn'],
+    default='icestick'
+)
+parser.add_argument(
+    '--source', choices=['vlog', 'vhdl', 'slog'], default='vlog'
+)
+parser.add_argument(
+    '--action', choices=['make', 'prog', 'all'], default='make'
+)
+args = parser.parse_args()
+
+prj = Openflow(odir='../build/openflow')
+
+prj.add_param('FREQ', '100000000')
+
+if args.source == 'vlog':
+    prj.add_include('../sources/vlog/include')
+    prj.add_vlog('../sources/vlog/*.v')
+if args.source in ['vlog', 'slog']:
+    prj.add_define('DEFINE', '1')
+
+prj.set_top('Top')
+
+if args.action in ['make', 'all']:
+    prj.make()
+
+if args.action in ['prog', 'all']:
+    prj.prog()
diff --git a/pyfpga/openflow.py b/pyfpga/openflow.py
index 0b7865ba..2849b4ba 100644
--- a/pyfpga/openflow.py
+++ b/pyfpga/openflow.py
@@ -8,19 +8,81 @@
 Implements support for an Open Source development flow.
 """
 
+# pylint: disable=too-many-locals
+# pylint: disable=too-many-branches
+# pylint: disable=duplicate-code
+
 from pyfpga.project import Project
 
 
 class Openflow(Project):
-    """Class to support Openflow."""
-
-    def __init__(self, name='openflow', odir='results'):
-        super().__init__(name=name, odir=odir)
-        self.set_part('hx8k-ct256')
+    """Class to support Open Source tools."""
 
     def _make_prepare(self, steps):
-        self.tool['make-app'] = 'docker'
-        self.tool['make-cmd'] = 'bash openflow.sh'
+        context = {
+            'PROJECT': self.name or 'openflow',
+            'PART': self.data.get('part', 'hx8k-ct256')
+        }
+        for step in steps:
+            context[step] = 1
+        if 'includes' in self.data:
+            includes = []
+            for include in self.data['includes']:
+                includes.append(f'-I{str(include)}')
+            context['INCLUDES'] = ' '.join(includes)
+        files = []
+        if 'files' in self.data:
+            for file in self.data['files']:
+                files.append(f'read_verilog -defer {file}')
+        if files:
+            context['VLOGS'] = '\n'.join(files)
+#            for file in self.data['files']:
+#                if 'lib' in self.data['files'][file]:
+#                    lib = self.data['files'][file]['lib']
+#                    files.append(
+#                        f'set_property library {lib} [get_files {file}]'
+#                    )
+#        if 'constraints' in self.data:
+#            for file in self.data['constraints']:
+#                files.append(f'add_file -fileset constrs_1 {file}')
+#            for file in self.data['constraints']:
+#                if self.data['constraints'][file] == 'syn':
+#                    prop = 'USED_IN_IMPLEMENTATION FALSE'
+#                if self.data['constraints'][file] == 'syn':
+#                    prop = 'USED_IN_SYNTHESIS FALSE'
+#                if self.data['constraints'][file] != 'all':
+#                    files.append(f'set_property {prop} [get_files {file}]')
+#            first = next(iter(self.data['constraints']))
+#            prop = f'TARGET_CONSTRS_FILE {first}'
+#            files.append(f'set_property {prop} [current_fileset -constrset]')
+#        if files:
+#            context['FILES'] = '\n'.join(files)
+        if 'top' in self.data:
+            context['TOP'] = self.data['top']
+        if 'defines' in self.data:
+            defines = []
+            for key, value in self.data['defines'].items():
+                defines.append(f'-D{key}={value}')
+            context['DEFINES'] = ' '.join(defines)
+        if 'params' in self.data:
+            params = []
+            for key, value in self.data['params'].items():
+                params.append(f'-set {key} {value}')
+            context['PARAMS'] = ' '.join(params)
+        if 'hooks' in self.data:
+            for stage in self.data['hooks']:
+                context[stage.upper()] = '\n'.join(self.data['hooks'][stage])
+        self._create_file('openflow', 'sh', context)
+        return 'bash openflow.sh'
+
+#    def _prog_prepare(self, bitstream, position):
+#        _ = position  # Not needed for Vivado
+#        if not bitstream:
+#            basename = self.name or 'vivado'
+#            bitstream = Path(self.odir).resolve() / f'{basename}.bit'
+#        context = {'BITSTREAM': bitstream}
+#        self._create_file('vivado-prog', 'tcl', context)
+#        return 'vivado -mode batch -notrace -quiet -source vivado-prog.tcl'
 
     def _prog_prepare(self, bitstream, position):
         # binaries = ['bit']
diff --git a/pyfpga/templates/openflow.jinja b/pyfpga/templates/openflow.jinja
index d3a0a703..6b4580c2 100644
--- a/pyfpga/templates/openflow.jinja
+++ b/pyfpga/templates/openflow.jinja
@@ -6,162 +6,38 @@
 
 set -e
 
-###############################################################################
-# Things to tuneup
-###############################################################################
-
-FRONTEND={frontend}
-BACKEND={backend}
-PROJECT={project}
-FAMILY={family}
-DEVICE={device}
-PACKAGE={package}
-TOP={top}
-
-PARAMS="{params}"
-FLAGS="--std=08 -fsynopsys -fexplicit -frelaxed"
-VHDLS="{vhdls}"
-INCLUDES="{includes}"
-VERILOGS="{verilogs}"
-CONSTRAINTS="{constraints}"
-
-# taks = prj syn par bit
-TASKS="{tasks}"
-
-#
-# Tools configuration
-#
-
-OCI_ENGINE="{oci_engine}"
-
-CONT_GHDL="{cont_ghdl}"
-CONT_YOSYS="{cont_yosys}"
-CONT_NEXTPNR_ICE40="{cont_nextpnr_ice40}"
-CONT_ICETIME="{cont_icetime}"
-CONT_ICEPACK="{cont_icepack}"
-CONT_NEXTPNR_ECP5="{cont_nextpnr_ecp5}"
-CONT_ECPPACK="{cont_ecppack}"
-
-TOOL_GHDL="{tool_ghdl}"
-TOOL_YOSYS="{tool_yosys}"
-TOOL_NEXTPNR_ICE40="{tool_nextpnr_ice40}"
-TOOL_ICETIME="{tool_icetime}"
-TOOL_ICEPACK="{tool_icepack}"
-TOOL_NEXTPNR_ECP5="{tool_nextpnr_ecp5}"
-TOOL_ECPPACK="{tool_ecppack}"
-
-###############################################################################
-# Support
-###############################################################################
-
-MODULE=
-[ -n "$VHDLS" ] && MODULE="-m ghdl"
-
-function print () {{
-    # tput setaf 6; echo ">>> PyFPGA ($1): $2"; tput sgr0;
-    echo ">>> PyFPGA ($1): $2"
-}}
-
-###############################################################################
-# Synthesis
-###############################################################################
-
-if [[ $TASKS == *"syn"* ]]; then
-
-print "$FRONTEND" "running 'synthesis'"
-
-### GHDL
-
-if [[ $FRONTEND == "ghdl" ]]; then
-
-$OCI_ENGINE $CONT_GHDL /bin/bash -c "
-$VHDLS
-$TOOL_GHDL --synth $FLAGS $TOP
-" > $PROJECT.vhdl
-
-fi
-
-### Yosys (with ghdl-yosys-plugin)
-
-if [[ $FRONTEND == "yosys" ]]; then
-
-SYNTH=
-WRITE=
-if [[ $BACKEND == "vivado" ]]; then
-    SYNTH="synth_xilinx -top $TOP -family $FAMILY"
-    WRITE="write_edif -pvector bra $PROJECT.edif"
-elif [[ $BACKEND == "ise" ]]; then
-    SYNTH="synth_xilinx -top $TOP -family $FAMILY -ise"
-    WRITE="write_edif -pvector bra $PROJECT.edif"
-elif [[ $BACKEND == "nextpnr" ]]; then
-    SYNTH="synth_$FAMILY -top $TOP -json $PROJECT.json"
-elif [[ $BACKEND == "verilog-nosynth" ]]; then
-    WRITE="write_verilog $PROJECT.v"
-else
-    SYNTH="synth -top $TOP"
-    WRITE="write_verilog $PROJECT.v"
-fi
-
-$OCI_ENGINE $CONT_YOSYS /bin/bash -c "
-$VHDLS
-$TOOL_YOSYS -Q $MODULE -p '
-$INCLUDES;
-$VERILOGS;
-$PARAMS;
-$SYNTH;
-$WRITE
-'"
-
-fi
-
-###
-
-fi
-
-###############################################################################
-# Place and Route
-###############################################################################
-
-if [[ $TASKS == *"par"* ]]; then
-
-print "nextpnr-$FAMILY" "running 'place and route'"
-
-INPUT="--json $PROJECT.json"
-
-if [[ $FAMILY == "ice40" ]]; then
-    CONSTRAINT="--pcf $CONSTRAINTS"
-    OUTPUT="--asc $PROJECT.asc"
-    $OCI_ENGINE $CONT_NEXTPNR_ICE40 $TOOL_NEXTPNR_ICE40 \
-        --$DEVICE --package $PACKAGE $CONSTRAINT $INPUT $OUTPUT
-    $OCI_ENGINE $CONT_ICETIME $TOOL_ICETIME \
-        -d $DEVICE -mtr $PROJECT.rpt $PROJECT.asc
-fi
-
-if [[ $FAMILY == "ecp5" ]]; then
-    CONSTRAINT="--lpf $CONSTRAINTS"
-    OUTPUT="--textcfg $PROJECT.config"
-    $OCI_ENGINE $CONT_NEXTPNR_ECP5 $TOOL_NEXTPNR_ECP5 \
-        --$DEVICE --package $PACKAGE $CONSTRAINT $INPUT $OUTPUT
-fi
-
-fi
-
-###############################################################################
-# Bitstream generation
-###############################################################################
-
-if [[ $TASKS == *"bit"* ]]; then
-
-if [[ $FAMILY == "ice40" ]]; then
-    print "icepack" "running 'bitstream generation'"
-    $OCI_ENGINE $CONT_ICEPACK $TOOL_ICEPACK \
-        $PROJECT.asc $PROJECT.bit
-fi
-
-if [[ $FAMILY == "ecp5" ]]; then
-    print "eccpack" "running 'bitstream generation'"
-    $OCI_ENGINE $CONT_ECPPACK $TOOL_ECPPACK \
-        --svf $PROJECT.svf $PROJECT.config $PROJECT.bit
-fi
-
-fi
+DOCKER="docker run --rm -v $HOME:$HOME -w $PWD"
+
+{% if SYN %}
+$DOCKER hdlc/ghdl:yosys /bin/bash -c "
+{{ PRESYN }}
+{{ VHDLS }}
+yosys -Q -m ghdl -p '
+{% if INCLUDES %}
+verilog_defaults -add {{ INCLUDES }}
+{% endif %}
+{% if DEFINES %}
+verilog_defines {{ DEFINES }}
+{% endif %}
+{{ VLOGS }}
+{{ SLOGS }}
+{% if PARAMS %}
+chparam {{ PARAMS }} {{ TOP }}
+{% endif %}
+synth -top {{ TOP }}
+'
+{{ POSTSYN }}
+"
+{% endif %}
+
+{% if PAR %}
+{{ PREPAR }}
+
+{{ POSTPAR }}
+{% endif %}
+
+{% if BIT %}
+{{ PREBIT }}
+
+{{ POSTBIT }}
+{% endif %}

From aaef6c1b2b63369152bdbd51fa54c9e40490c6e3 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Tue, 25 Jun 2024 22:22:44 -0300
Subject: [PATCH 105/248] Removed resources submodule

---
 .gitmodules                          | 3 ---
 examples/resources                   | 1 -
 examples/sources/de10nano/clk.sdc    | 1 +
 examples/sources/de10nano/clk.tcl    | 1 +
 examples/sources/de10nano/led.tcl    | 1 +
 examples/sources/ecp5evn/clk.lpf     | 2 ++
 examples/sources/ecp5evn/led.lpf     | 2 ++
 examples/sources/edu-ciaa/clk.pcf    | 1 +
 examples/sources/edu-ciaa/led.pcf    | 1 +
 examples/sources/icestick/clk.pcf    | 1 +
 examples/sources/icestick/led.pcf    | 1 +
 examples/sources/maker-board/clk.pdc | 1 +
 examples/sources/maker-board/clk.sdc | 1 +
 examples/sources/maker-board/led.pdc | 1 +
 examples/sources/nexys3/clk.ucf      | 1 +
 examples/sources/nexys3/clk.xcf      | 2 ++
 examples/sources/nexys3/led.ucf      | 1 +
 examples/sources/orangecrab/clk.lpf  | 2 ++
 examples/sources/orangecrab/led.lpf  | 2 ++
 examples/sources/s6micro/clk.ucf     | 1 +
 examples/sources/s6micro/clk.xcf     | 2 ++
 examples/sources/s6micro/led.ucf     | 1 +
 22 files changed, 26 insertions(+), 4 deletions(-)
 delete mode 100644 .gitmodules
 delete mode 160000 examples/resources
 create mode 100644 examples/sources/de10nano/clk.sdc
 create mode 100644 examples/sources/de10nano/clk.tcl
 create mode 100644 examples/sources/de10nano/led.tcl
 create mode 100644 examples/sources/ecp5evn/clk.lpf
 create mode 100644 examples/sources/ecp5evn/led.lpf
 create mode 100644 examples/sources/edu-ciaa/clk.pcf
 create mode 100644 examples/sources/edu-ciaa/led.pcf
 create mode 100644 examples/sources/icestick/clk.pcf
 create mode 100644 examples/sources/icestick/led.pcf
 create mode 100644 examples/sources/maker-board/clk.pdc
 create mode 100644 examples/sources/maker-board/clk.sdc
 create mode 100644 examples/sources/maker-board/led.pdc
 create mode 100644 examples/sources/nexys3/clk.ucf
 create mode 100644 examples/sources/nexys3/clk.xcf
 create mode 100644 examples/sources/nexys3/led.ucf
 create mode 100644 examples/sources/orangecrab/clk.lpf
 create mode 100644 examples/sources/orangecrab/led.lpf
 create mode 100644 examples/sources/s6micro/clk.ucf
 create mode 100644 examples/sources/s6micro/clk.xcf
 create mode 100644 examples/sources/s6micro/led.ucf

diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index cba0ef31..00000000
--- a/.gitmodules
+++ /dev/null
@@ -1,3 +0,0 @@
-[submodule "examples/resources"]
-	path = examples/resources
-	url = git@github.com:PyFPGA/resources.git
diff --git a/examples/resources b/examples/resources
deleted file mode 160000
index 7f34b14e..00000000
--- a/examples/resources
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 7f34b14e2cdcbcbd6f57053a033a2abdd3ff1900
diff --git a/examples/sources/de10nano/clk.sdc b/examples/sources/de10nano/clk.sdc
new file mode 100644
index 00000000..00363616
--- /dev/null
+++ b/examples/sources/de10nano/clk.sdc
@@ -0,0 +1 @@
+create_clock -period 20 [get_ports clk_i]
diff --git a/examples/sources/de10nano/clk.tcl b/examples/sources/de10nano/clk.tcl
new file mode 100644
index 00000000..2d72bdd4
--- /dev/null
+++ b/examples/sources/de10nano/clk.tcl
@@ -0,0 +1 @@
+set_location_assignment PIN_V11 -to clk_i
diff --git a/examples/sources/de10nano/led.tcl b/examples/sources/de10nano/led.tcl
new file mode 100644
index 00000000..4159ac36
--- /dev/null
+++ b/examples/sources/de10nano/led.tcl
@@ -0,0 +1 @@
+set_location_assignment PIN_W15 -to led_o
diff --git a/examples/sources/ecp5evn/clk.lpf b/examples/sources/ecp5evn/clk.lpf
new file mode 100644
index 00000000..c6c70332
--- /dev/null
+++ b/examples/sources/ecp5evn/clk.lpf
@@ -0,0 +1,2 @@
+LOCATE COMP "clk_i" SITE "A10";
+IOBUF PORT "clk_i" IO_TYPE=LVCMOS33;
diff --git a/examples/sources/ecp5evn/led.lpf b/examples/sources/ecp5evn/led.lpf
new file mode 100644
index 00000000..529c0b89
--- /dev/null
+++ b/examples/sources/ecp5evn/led.lpf
@@ -0,0 +1,2 @@
+LOCATE COMP "led_o" SITE "A13";
+IOBUF PORT "led_o" IO_TYPE=LVCMOS25;
diff --git a/examples/sources/edu-ciaa/clk.pcf b/examples/sources/edu-ciaa/clk.pcf
new file mode 100644
index 00000000..cfd62a35
--- /dev/null
+++ b/examples/sources/edu-ciaa/clk.pcf
@@ -0,0 +1 @@
+set_io clk_i 94
diff --git a/examples/sources/edu-ciaa/led.pcf b/examples/sources/edu-ciaa/led.pcf
new file mode 100644
index 00000000..92e61517
--- /dev/null
+++ b/examples/sources/edu-ciaa/led.pcf
@@ -0,0 +1 @@
+set_io led_o 4
diff --git a/examples/sources/icestick/clk.pcf b/examples/sources/icestick/clk.pcf
new file mode 100644
index 00000000..8b246ac7
--- /dev/null
+++ b/examples/sources/icestick/clk.pcf
@@ -0,0 +1 @@
+set_io clk_i 21
diff --git a/examples/sources/icestick/led.pcf b/examples/sources/icestick/led.pcf
new file mode 100644
index 00000000..9a56ae6f
--- /dev/null
+++ b/examples/sources/icestick/led.pcf
@@ -0,0 +1 @@
+set_io led_o 95
diff --git a/examples/sources/maker-board/clk.pdc b/examples/sources/maker-board/clk.pdc
new file mode 100644
index 00000000..c0070c73
--- /dev/null
+++ b/examples/sources/maker-board/clk.pdc
@@ -0,0 +1 @@
+set_io clk_i -DIRECTION INPUT -pinname 23 -fixed yes
diff --git a/examples/sources/maker-board/clk.sdc b/examples/sources/maker-board/clk.sdc
new file mode 100644
index 00000000..00363616
--- /dev/null
+++ b/examples/sources/maker-board/clk.sdc
@@ -0,0 +1 @@
+create_clock -period 20 [get_ports clk_i]
diff --git a/examples/sources/maker-board/led.pdc b/examples/sources/maker-board/led.pdc
new file mode 100644
index 00000000..703bd95a
--- /dev/null
+++ b/examples/sources/maker-board/led.pdc
@@ -0,0 +1 @@
+set_io led_o -DIRECTION OUTPUT -pinname 117 -fixed yes
diff --git a/examples/sources/nexys3/clk.ucf b/examples/sources/nexys3/clk.ucf
new file mode 100644
index 00000000..c0230e2d
--- /dev/null
+++ b/examples/sources/nexys3/clk.ucf
@@ -0,0 +1 @@
+NET "clk_i" LOC = "V10";
diff --git a/examples/sources/nexys3/clk.xcf b/examples/sources/nexys3/clk.xcf
new file mode 100644
index 00000000..a200fdeb
--- /dev/null
+++ b/examples/sources/nexys3/clk.xcf
@@ -0,0 +1,2 @@
+NET "clk_i" TNM_NET = "clk_i";
+TIMESPEC "TS_clk_i" = PERIOD "clk_i" 10.00 ns HIGH 50%;
diff --git a/examples/sources/nexys3/led.ucf b/examples/sources/nexys3/led.ucf
new file mode 100644
index 00000000..c210831b
--- /dev/null
+++ b/examples/sources/nexys3/led.ucf
@@ -0,0 +1 @@
+NET "led_o" LOC = "U16";
diff --git a/examples/sources/orangecrab/clk.lpf b/examples/sources/orangecrab/clk.lpf
new file mode 100644
index 00000000..ed801503
--- /dev/null
+++ b/examples/sources/orangecrab/clk.lpf
@@ -0,0 +1,2 @@
+LOCATE COMP "clk_i" SITE "A9";
+IOBUF PORT "clk_i" IO_TYPE=LVCMOS33;
diff --git a/examples/sources/orangecrab/led.lpf b/examples/sources/orangecrab/led.lpf
new file mode 100644
index 00000000..cad54d2b
--- /dev/null
+++ b/examples/sources/orangecrab/led.lpf
@@ -0,0 +1,2 @@
+LOCATE COMP "led_o" SITE "K4";
+IOBUF PORT "led_o" IO_TYPE=LVCMOS33;
diff --git a/examples/sources/s6micro/clk.ucf b/examples/sources/s6micro/clk.ucf
new file mode 100644
index 00000000..c0230e2d
--- /dev/null
+++ b/examples/sources/s6micro/clk.ucf
@@ -0,0 +1 @@
+NET "clk_i" LOC = "V10";
diff --git a/examples/sources/s6micro/clk.xcf b/examples/sources/s6micro/clk.xcf
new file mode 100644
index 00000000..2f24ee45
--- /dev/null
+++ b/examples/sources/s6micro/clk.xcf
@@ -0,0 +1,2 @@
+NET "clk_i" TNM_NET = "clk_i";
+TIMESPEC "TS_clk_i" = PERIOD "clk_i" 20.00 ns HIGH 50%;
diff --git a/examples/sources/s6micro/led.ucf b/examples/sources/s6micro/led.ucf
new file mode 100644
index 00000000..c557e8c5
--- /dev/null
+++ b/examples/sources/s6micro/led.ucf
@@ -0,0 +1 @@
+NET "led_o" LOC = "C2";

From ed239f9526d88ffeccdeaf7f15dd1fc9b993f3bb Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Tue, 25 Jun 2024 23:57:28 -0300
Subject: [PATCH 106/248] Modified HDL to depends on more than one
 param/include/define

---
 examples/openflow/run.py                   |  9 ++--
 examples/sources/slog/blink.sv             |  5 ++-
 examples/sources/slog/include/header.svh   |  1 -
 examples/sources/slog/include1/header1.svh |  1 +
 examples/sources/slog/include2/header2.svh |  1 +
 examples/sources/slog/top.sv               | 49 ++++++++++++++++++----
 examples/sources/vhdl/blink.vhdl           |  5 ++-
 examples/sources/vhdl/blink_pkg.vhdl       |  3 +-
 examples/sources/vhdl/top.vhdl             |  8 ++--
 examples/sources/vlog/blink.v              |  5 ++-
 examples/sources/vlog/include/header.vh    |  1 -
 examples/sources/vlog/include1/header1.vh  |  1 +
 examples/sources/vlog/include2/header2.vh  |  1 +
 examples/sources/vlog/top.v                | 49 ++++++++++++++++++----
 examples/vivado/run.py                     | 10 +++--
 15 files changed, 113 insertions(+), 36 deletions(-)
 delete mode 100644 examples/sources/slog/include/header.svh
 create mode 100644 examples/sources/slog/include1/header1.svh
 create mode 100644 examples/sources/slog/include2/header2.svh
 delete mode 100644 examples/sources/vlog/include/header.vh
 create mode 100644 examples/sources/vlog/include1/header1.vh
 create mode 100644 examples/sources/vlog/include2/header2.vh

diff --git a/examples/openflow/run.py b/examples/openflow/run.py
index 8677a8a4..d591b195 100644
--- a/examples/openflow/run.py
+++ b/examples/openflow/run.py
@@ -1,4 +1,4 @@
-"""Vivado examples."""
+"""Openflow examples."""
 
 import argparse
 
@@ -21,12 +21,15 @@
 prj = Openflow(odir='../build/openflow')
 
 prj.add_param('FREQ', '100000000')
+prj.add_param('SECS', '1')
 
 if args.source == 'vlog':
-    prj.add_include('../sources/vlog/include')
+    prj.add_include('../sources/vlog/include1')
+    prj.add_include('../sources/vlog/include2')
     prj.add_vlog('../sources/vlog/*.v')
 if args.source in ['vlog', 'slog']:
-    prj.add_define('DEFINE', '1')
+    prj.add_define('DEFINE1', '1')
+    prj.add_define('DEFINE2', '1')
 
 prj.set_top('Top')
 
diff --git a/examples/sources/slog/blink.sv b/examples/sources/slog/blink.sv
index b74bfe08..4e2679e9 100644
--- a/examples/sources/slog/blink.sv
+++ b/examples/sources/slog/blink.sv
@@ -1,11 +1,12 @@
 module Blink #(
-  parameter int FREQ = 25000000
+  parameter int FREQ = 25000000,
+  parameter int SECS = 1
 )(
   input  clk_i,
   output led_o
 );
 
-  localparam int          DIV = FREQ;
+  localparam int          DIV = FREQ*SECS;
   logic                   led = 0;
   logic [$clog2(DIV)-1:0] cnt = 0;
 
diff --git a/examples/sources/slog/include/header.svh b/examples/sources/slog/include/header.svh
deleted file mode 100644
index 78aa9bfd..00000000
--- a/examples/sources/slog/include/header.svh
+++ /dev/null
@@ -1 +0,0 @@
-`define INCLUDE
diff --git a/examples/sources/slog/include1/header1.svh b/examples/sources/slog/include1/header1.svh
new file mode 100644
index 00000000..ed066ea9
--- /dev/null
+++ b/examples/sources/slog/include1/header1.svh
@@ -0,0 +1 @@
+`define INCLUDE1
diff --git a/examples/sources/slog/include2/header2.svh b/examples/sources/slog/include2/header2.svh
new file mode 100644
index 00000000..c45793ec
--- /dev/null
+++ b/examples/sources/slog/include2/header2.svh
@@ -0,0 +1 @@
+`define INCLUDE2
diff --git a/examples/sources/slog/top.sv b/examples/sources/slog/top.sv
index 24e780e5..4665011a 100644
--- a/examples/sources/slog/top.sv
+++ b/examples/sources/slog/top.sv
@@ -1,23 +1,54 @@
-`include "header.svh"
+`include "header1.svh"
+`include "header2.svh"
 
 module Top #(
-  parameter FREQ = 0
+  parameter int FREQ = 0,
+  parameter int SECS = 0
 )(
   input  clk_i,
   output led_o
 );
 
   initial begin
-    if (FREQ==0) begin
-      $stop("FREQ must be greater than 0");
-      $error("FREQ must be greater than 0");
-      $fatal("FREQ must be greater than 0");
+    if (!FREQ) begin
+      $stop("FREQ not set");
+      $error("FREQ not set");
+      $fatal("FREQ not set");
     end
+    if (!SECS) begin
+      $stop("SECS not set");
+      $error("SECS not set");
+      $fatal("SECS not set");
+    end
+    `ifndef INCLUDE1
+      $stop("INCLUDE1 not defined");
+      $error("INCLUDE1 not defined");
+      $fatal("INCLUDE1 not defined");
+    `endif
+    `ifndef INCLUDE2
+      $stop("INCLUDE2 not defined");
+      $error("INCLUDE2 not defined");
+      $fatal("INCLUDE2 not defined");
+    `endif
+    `ifndef DEFINE1
+      $stop("DEFINE1 not defined");
+      $error("DEFINE1 not defined");
+      $fatal("DEFINE1 not defined");
+    `endif
+    `ifndef DEFINE2
+      $stop("DEFINE2 not defined");
+      $error("DEFINE2 not defined");
+      $fatal("DEFINE2 not defined");
+    `endif
   end
 
-`ifdef INCLUDE
-`ifdef DEFINE
-  Blink #(.FREQ (FREQ)) dut (.clk_i (clk_i), .led_o (led_o));
+`ifdef INCLUDE1
+`ifdef INCLUDE2
+`ifdef DEFINE1
+`ifdef DEFINE2
+  Blink #(.FREQ (FREQ), .SECS (SECS)) dut (.clk_i (clk_i), .led_o (led_o));
+`endif
+`endif
 `endif
 `endif
 
diff --git a/examples/sources/vhdl/blink.vhdl b/examples/sources/vhdl/blink.vhdl
index 9b9a4bc3..156f553c 100644
--- a/examples/sources/vhdl/blink.vhdl
+++ b/examples/sources/vhdl/blink.vhdl
@@ -3,7 +3,8 @@ use IEEE.std_logic_1164.all;
 
 entity Blink is
   generic (
-    FREQ  : positive := 25e6
+    FREQ  : positive := 25e6;
+    SECS  : positive := 1
   );
   port (
     clk_i : in  std_logic;
@@ -12,7 +13,7 @@ entity Blink is
 end entity Blink;
 
 architecture RTL of Blink is
-  constant DIV : positive := FREQ;
+  constant DIV : positive := FREQ*SECS;
   signal   led : std_logic := '0';
   signal   cnt : natural range 0 to DIV-1 := 0;
 begin
diff --git a/examples/sources/vhdl/blink_pkg.vhdl b/examples/sources/vhdl/blink_pkg.vhdl
index 115f0899..3f6ee86a 100644
--- a/examples/sources/vhdl/blink_pkg.vhdl
+++ b/examples/sources/vhdl/blink_pkg.vhdl
@@ -5,7 +5,8 @@ package blink_pkg is
 
   component Blink is
     generic (
-      FREQ  : natural:=25e6
+      FREQ  : positive := 25e6;
+      SECS  : positive := 1
     );
     port (
       clk_i :  in std_logic;
diff --git a/examples/sources/vhdl/top.vhdl b/examples/sources/vhdl/top.vhdl
index 0ff6d780..24977d6c 100644
--- a/examples/sources/vhdl/top.vhdl
+++ b/examples/sources/vhdl/top.vhdl
@@ -5,7 +5,8 @@ use blink_lib.blink_pkg.all;
 
 entity Top is
   generic (
-    FREQ : natural := 0
+    FREQ : natural := 0;
+    SECS : natural := 0
   );
   port (
     clk_i :  in std_logic;
@@ -16,10 +17,11 @@ end entity Top;
 architecture ARCH of Top is
 begin
 
-  assert FREQ > 0 report "FREQ must be greater than 0" severity failure;
+  assert FREQ > 0 report "FREQ not set" severity failure;
+  assert SECS > 0 report "SECS not set" severity failure;
 
   blink_i: Blink
-  generic map (FREQ => FREQ)
+  generic map (FREQ => FREQ, SECS => SECS)
   port map (clk_i => clk_i, led_o => led_o);
 
 end architecture ARCH;
diff --git a/examples/sources/vlog/blink.v b/examples/sources/vlog/blink.v
index 7522e0f7..120b8c9f 100644
--- a/examples/sources/vlog/blink.v
+++ b/examples/sources/vlog/blink.v
@@ -1,11 +1,12 @@
 module Blink #(
-  parameter FREQ = 25000000
+  parameter FREQ = 25000000,
+  parameter SECS = 1
 )(
   input  clk_i,
   output led_o
 );
 
-  localparam            DIV = FREQ;
+  localparam            DIV = FREQ*SECS;
   reg                   led = 0;
   reg [$clog2(DIV)-1:0] cnt = 0;
 
diff --git a/examples/sources/vlog/include/header.vh b/examples/sources/vlog/include/header.vh
deleted file mode 100644
index 78aa9bfd..00000000
--- a/examples/sources/vlog/include/header.vh
+++ /dev/null
@@ -1 +0,0 @@
-`define INCLUDE
diff --git a/examples/sources/vlog/include1/header1.vh b/examples/sources/vlog/include1/header1.vh
new file mode 100644
index 00000000..ed066ea9
--- /dev/null
+++ b/examples/sources/vlog/include1/header1.vh
@@ -0,0 +1 @@
+`define INCLUDE1
diff --git a/examples/sources/vlog/include2/header2.vh b/examples/sources/vlog/include2/header2.vh
new file mode 100644
index 00000000..c45793ec
--- /dev/null
+++ b/examples/sources/vlog/include2/header2.vh
@@ -0,0 +1 @@
+`define INCLUDE2
diff --git a/examples/sources/vlog/top.v b/examples/sources/vlog/top.v
index 6c63ebae..fb6dff0b 100644
--- a/examples/sources/vlog/top.v
+++ b/examples/sources/vlog/top.v
@@ -1,23 +1,54 @@
-`include "header.vh"
+`include "header1.vh"
+`include "header2.vh"
 
 module Top #(
-  parameter FREQ = 0
+  parameter FREQ = 0,
+  parameter SECS = 0
 )(
   input  clk_i,
   output led_o
 );
 
   initial begin
-    if (FREQ==0) begin
-      $stop("FREQ must be greater than 0");
-      $error("FREQ must be greater than 0");
-      $fatal("FREQ must be greater than 0");
+    if (!FREQ) begin
+      $stop("FREQ not set");
+      $error("FREQ not set");
+      $fatal("FREQ not set");
     end
+    if (!SECS) begin
+      $stop("SECS not set");
+      $error("SECS not set");
+      $fatal("SECS not set");
+    end
+    `ifndef INCLUDE1
+      $stop("INCLUDE1 not defined");
+      $error("INCLUDE1 not defined");
+      $fatal("INCLUDE1 not defined");
+    `endif
+    `ifndef INCLUDE2
+      $stop("INCLUDE2 not defined");
+      $error("INCLUDE2 not defined");
+      $fatal("INCLUDE2 not defined");
+    `endif
+    `ifndef DEFINE1
+      $stop("DEFINE1 not defined");
+      $error("DEFINE1 not defined");
+      $fatal("DEFINE1 not defined");
+    `endif
+    `ifndef DEFINE2
+      $stop("DEFINE2 not defined");
+      $error("DEFINE2 not defined");
+      $fatal("DEFINE2 not defined");
+    `endif
   end
 
-`ifdef INCLUDE
-`ifdef DEFINE
-  Blink #(.FREQ (FREQ)) dut (.clk_i (clk_i), .led_o (led_o));
+`ifdef INCLUDE1
+`ifdef INCLUDE2
+`ifdef DEFINE1
+`ifdef DEFINE2
+  Blink #(.FREQ (FREQ), .SECS (SECS)) dut (.clk_i (clk_i), .led_o (led_o));
+`endif
+`endif
 `endif
 `endif
 
diff --git a/examples/vivado/run.py b/examples/vivado/run.py
index 2431466e..cf110c2f 100644
--- a/examples/vivado/run.py
+++ b/examples/vivado/run.py
@@ -31,17 +31,21 @@
     prj.add_cons('../sources/arty/a7-35t/timing.xdc', 'syn')
     prj.add_cons('../sources/arty/a7-35t/clk.xdc', 'par')
     prj.add_cons('../sources/arty/a7-35t/led.xdc', 'par')
+prj.add_param('SECS', '1')
 
 if args.source == 'vhdl':
     prj.add_vhdl('../sources/vhdl/*.vhdl', 'blink_lib')
 if args.source == 'vlog':
-    prj.add_include('../sources/vlog/include')
+    prj.add_include('../sources/vlog/include1')
+    prj.add_include('../sources/vlog/include2')
     prj.add_vlog('../sources/vlog/*.v')
 if args.source == 'slog':
-    prj.add_include('../sources/slog/include')
+    prj.add_include('../sources/slog/include1')
+    prj.add_include('../sources/slog/include2')
     prj.add_vlog('../sources/slog/*.sv')
 if args.source in ['vlog', 'slog']:
-    prj.add_define('DEFINE', '1')
+    prj.add_define('DEFINE1', '1')
+    prj.add_define('DEFINE2', '1')
 
 prj.set_top('Top')
 

From 12ab0a46edf30dac01bee4916675b37e00d11d5d Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Wed, 26 Jun 2024 00:16:30 -0300
Subject: [PATCH 107/248] Small fix

---
 examples/vivado/run.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/vivado/run.py b/examples/vivado/run.py
index cf110c2f..8ae97d6f 100644
--- a/examples/vivado/run.py
+++ b/examples/vivado/run.py
@@ -17,7 +17,7 @@
 )
 args = parser.parse_args()
 
-prj = Vivado(odir=f'../build/vivado')
+prj = Vivado(odir='../build/vivado')
 
 if args.board == 'zybo':
     prj.set_part('xc7z010-1-clg400')

From e61cf5b979197350c8d3e509ea29b4a304e83543 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Wed, 26 Jun 2024 00:17:07 -0300
Subject: [PATCH 108/248] Simplified Openflow example content

---
 examples/openflow/Makefile            |  7 ----
 examples/openflow/ecp5evn.lpf         |  5 ---
 examples/openflow/edu-ciaa-fpga.pcf   |  2 --
 examples/openflow/icestick.pcf        |  2 --
 examples/openflow/icestorm.py         | 50 ---------------------------
 examples/openflow/orangecrab_r0.2.lpf |  5 ---
 examples/openflow/prjtrellis.py       | 50 ---------------------------
 examples/openflow/run.py              | 27 +++++++++++++++
 examples/openflow/run.sh              | 16 +++++++++
 9 files changed, 43 insertions(+), 121 deletions(-)
 delete mode 100644 examples/openflow/Makefile
 delete mode 100644 examples/openflow/ecp5evn.lpf
 delete mode 100644 examples/openflow/edu-ciaa-fpga.pcf
 delete mode 100644 examples/openflow/icestick.pcf
 delete mode 100644 examples/openflow/icestorm.py
 delete mode 100644 examples/openflow/orangecrab_r0.2.lpf
 delete mode 100644 examples/openflow/prjtrellis.py
 create mode 100644 examples/openflow/run.sh

diff --git a/examples/openflow/Makefile b/examples/openflow/Makefile
deleted file mode 100644
index 05df0f94..00000000
--- a/examples/openflow/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/usr/bin/make
-
-all:
-	python3 icestorm.py --lang verilog
-	python3 icestorm.py --lang vhdl
-	python3 prjtrellis.py --board ecp5evn
-	python3 prjtrellis.py --lang vhdl
diff --git a/examples/openflow/ecp5evn.lpf b/examples/openflow/ecp5evn.lpf
deleted file mode 100644
index 1b0195e3..00000000
--- a/examples/openflow/ecp5evn.lpf
+++ /dev/null
@@ -1,5 +0,0 @@
-LOCATE COMP "clk_i" SITE "A10";
-IOBUF PORT "clk_i" IO_TYPE=LVCMOS33;
-
-LOCATE COMP "led_o" SITE "A13";
-IOBUF PORT "led_o" IO_TYPE=LVCMOS25;
diff --git a/examples/openflow/edu-ciaa-fpga.pcf b/examples/openflow/edu-ciaa-fpga.pcf
deleted file mode 100644
index 17fb1134..00000000
--- a/examples/openflow/edu-ciaa-fpga.pcf
+++ /dev/null
@@ -1,2 +0,0 @@
-set_io clk_i 94
-set_io led_o 4
diff --git a/examples/openflow/icestick.pcf b/examples/openflow/icestick.pcf
deleted file mode 100644
index caa6e413..00000000
--- a/examples/openflow/icestick.pcf
+++ /dev/null
@@ -1,2 +0,0 @@
-set_io clk_i 21
-set_io led_o 95
diff --git a/examples/openflow/icestorm.py b/examples/openflow/icestorm.py
deleted file mode 100644
index a71bec78..00000000
--- a/examples/openflow/icestorm.py
+++ /dev/null
@@ -1,50 +0,0 @@
-"""Icestorm example project."""
-
-import argparse
-import logging
-
-from fpga.project import Project
-
-logging.basicConfig()
-
-parser = argparse.ArgumentParser()
-parser.add_argument(
-    '--action', choices=['generate', 'transfer', 'all'], default='generate'
-)
-parser.add_argument(
-    '--lang', choices=['verilog', 'vhdl'], default='verilog'
-)
-parser.add_argument(
-    '--board',
-    choices=['icestick', 'edu-ciaa-fpga'],
-    default='icestick'
-)
-args = parser.parse_args()
-
-BOARDS = {
-    'icestick': ['hx1k-tq144', 'icestick.pcf'],
-    'edu-ciaa-fpga': ['hx4k-tq144', 'edu-ciaa-fpga.pcf']
-}
-
-prj = Project('openflow')
-prj.set_outdir('../../build/icestorm-{}-{}'.format(args.board, args.lang))
-prj.set_part(BOARDS[args.board][0])
-
-if args.lang == 'verilog':
-    prj.add_vlog_include('../../hdl/headers1')
-    prj.add_vlog_include('../../hdl/headers2')
-    prj.add_files('../../hdl/blinking.v')
-    prj.add_files('../../hdl/top.v')
-else:  # args.lang == 'vhdl'
-    prj.add_files('../../hdl/blinking.vhdl', library='examples')
-    prj.add_files('../../hdl/examples_pkg.vhdl', library='examples')
-    prj.add_files('../../hdl/top.vhdl')
-
-prj.add_files(BOARDS[args.board][1])
-prj.set_top('Top')
-
-if args.action in ['generate', 'all']:
-    prj.generate()
-
-if args.action in ['transfer', 'all']:
-    prj.transfer()
diff --git a/examples/openflow/orangecrab_r0.2.lpf b/examples/openflow/orangecrab_r0.2.lpf
deleted file mode 100644
index 573a3e2a..00000000
--- a/examples/openflow/orangecrab_r0.2.lpf
+++ /dev/null
@@ -1,5 +0,0 @@
-LOCATE COMP "clk_i" SITE "A9";
-IOBUF PORT "clk_i" IO_TYPE=LVCMOS33;
-
-LOCATE COMP "led_o" SITE "K4";
-IOBUF PORT "led_o" IO_TYPE=LVCMOS33;
diff --git a/examples/openflow/prjtrellis.py b/examples/openflow/prjtrellis.py
deleted file mode 100644
index bece88a9..00000000
--- a/examples/openflow/prjtrellis.py
+++ /dev/null
@@ -1,50 +0,0 @@
-"""Trellis example project."""
-
-import argparse
-import logging
-
-from fpga.project import Project
-
-logging.basicConfig()
-
-parser = argparse.ArgumentParser()
-parser.add_argument(
-    '--action', choices=['generate', 'transfer', 'all'], default='generate'
-)
-parser.add_argument(
-    '--lang', choices=['verilog', 'vhdl'], default='verilog'
-)
-parser.add_argument(
-    '--board',
-    choices=['orangecrab', 'ecp5evn'],
-    default='orangecrab'
-)
-args = parser.parse_args()
-
-BOARDS = {
-    'orangecrab': ['25k-CSFBGA285', 'orangecrab_r0.2.lpf'],
-    'ecp5evn': ['um5g-85k-CABGA381', 'ecp5evn.lpf']
-}
-
-prj = Project('openflow')
-prj.set_outdir('../../build/prjtrellis-{}-{}'.format(args.board, args.lang))
-prj.set_part(BOARDS[args.board][0])
-
-if args.lang == 'verilog':
-    prj.add_vlog_include('../../hdl/headers1')
-    prj.add_vlog_include('../../hdl/headers2')
-    prj.add_files('../../hdl/blinking.v')
-    prj.add_files('../../hdl/top.v')
-else:  # args.lang == 'vhdl'
-    prj.add_files('../../hdl/blinking.vhdl', library='examples')
-    prj.add_files('../../hdl/examples_pkg.vhdl', library='examples')
-    prj.add_files('../../hdl/top.vhdl')
-
-prj.add_files(BOARDS[args.board][1])
-prj.set_top('Top')
-
-if args.action in ['generate', 'all']:
-    prj.generate()
-
-if args.action in ['transfer', 'all']:
-    prj.transfer()
diff --git a/examples/openflow/run.py b/examples/openflow/run.py
index d591b195..b01153c3 100644
--- a/examples/openflow/run.py
+++ b/examples/openflow/run.py
@@ -20,13 +20,40 @@
 
 prj = Openflow(odir='../build/openflow')
 
+if args.board == 'icestick':
+    prj.set_part('hx1k-tq144')
+    prj.add_param('FREQ', '100000000')
+    prj.add_cons('../sources/icestick/clk.pcf', 'par')
+    prj.add_cons('../sources/icestick/led.pcf', 'par')
+if args.board == 'edu-ciaa':
+    prj.set_part('hx1k-tq144')
+    prj.add_param('FREQ', '100000000')
+    prj.add_cons('../sources/edu-ciaa/clk.pcf', 'par')
+    prj.add_cons('../sources/edu-ciaa/led.pcf', 'par')
+if args.board == 'orangecrab':
+    prj.set_part('25k-CSFBGA285')
+    prj.add_param('FREQ', '100000000')
+    prj.add_cons('../sources/orangecrab/clk.lpf', 'par')
+    prj.add_cons('../sources/orangecrab/led.lpf', 'par')
+if args.board == 'ecp5evn':
+    prj.set_part('um5g-85k-CABGA381')
+    prj.add_param('FREQ', '100000000')
+    prj.add_cons('../sources/ecp5evn/clk.lpf', 'par')
+    prj.add_cons('../sources/ecp5evn/led.lpf', 'par')
+
 prj.add_param('FREQ', '100000000')
 prj.add_param('SECS', '1')
 
+if args.source == 'vhdl':
+    prj.add_vhdl('../sources/vhdl/*.vhdl', 'blink_lib')
 if args.source == 'vlog':
     prj.add_include('../sources/vlog/include1')
     prj.add_include('../sources/vlog/include2')
     prj.add_vlog('../sources/vlog/*.v')
+if args.source == 'slog':
+    prj.add_include('../sources/slog/include1')
+    prj.add_include('../sources/slog/include2')
+    prj.add_vlog('../sources/slog/*.sv')
 if args.source in ['vlog', 'slog']:
     prj.add_define('DEFINE1', '1')
     prj.add_define('DEFINE2', '1')
diff --git a/examples/openflow/run.sh b/examples/openflow/run.sh
new file mode 100644
index 00000000..4e213f40
--- /dev/null
+++ b/examples/openflow/run.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+set -e
+
+BOARDS=("icestick" "edu-ciaa" "orangecrab" "ecp5evn")
+SOURCES=("vlog" "vhdl" "slog")
+ACTIONS=("make" "prog" "all")
+
+for BOARD in "${BOARDS[@]}"; do
+  for SOURCE in "${SOURCES[@]}"; do
+    for ACTION in "${ACTIONS[@]}"; do
+      echo "> $BOARD - $SOURCE - $ACTION"
+      python3 run.py --board $BOARD --source $SOURCE --action $ACTION
+    done
+  done
+done

From b52435e41b0d7bed910c2c0344697519db57972a Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Wed, 26 Jun 2024 00:29:30 -0300
Subject: [PATCH 109/248] Removed deprecated files

---
 examples/ghdl/Makefile        |  6 ------
 examples/ghdl/ghdl.py         | 17 -----------------
 examples/hooks/Makefile       |  6 ------
 examples/ise/Makefile         |  7 -------
 examples/ise/nexys3.ucf       |  7 -------
 examples/ise/nexys3.xcf       |  6 ------
 examples/ise/s6micro.ucf      |  7 -------
 examples/ise/s6micro.xcf      |  6 ------
 examples/libero/Makefile      |  6 ------
 examples/libero/mkr.pdc       |  4 ----
 examples/libero/mkr.sdc       |  6 ------
 examples/misc/Makefile        |  6 ------
 examples/misc/capture.py      | 23 -----------------------
 examples/misc/logger.py       | 25 -------------------------
 examples/multi/Makefile       |  6 ------
 examples/quartus/Makefile     |  6 ------
 examples/quartus/de10nano.sdc |  6 ------
 examples/quartus/de10nano.tcl |  2 --
 examples/yosys/Makefile       |  6 ------
 examples/yosys/README.md      | 26 --------------------------
 examples/yosys/yosys.py       | 31 -------------------------------
 21 files changed, 215 deletions(-)
 delete mode 100644 examples/ghdl/Makefile
 delete mode 100644 examples/ghdl/ghdl.py
 delete mode 100644 examples/hooks/Makefile
 delete mode 100644 examples/ise/Makefile
 delete mode 100644 examples/ise/nexys3.ucf
 delete mode 100644 examples/ise/nexys3.xcf
 delete mode 100644 examples/ise/s6micro.ucf
 delete mode 100644 examples/ise/s6micro.xcf
 delete mode 100644 examples/libero/Makefile
 delete mode 100644 examples/libero/mkr.pdc
 delete mode 100644 examples/libero/mkr.sdc
 delete mode 100644 examples/misc/Makefile
 delete mode 100644 examples/misc/capture.py
 delete mode 100644 examples/misc/logger.py
 delete mode 100644 examples/multi/Makefile
 delete mode 100644 examples/quartus/Makefile
 delete mode 100644 examples/quartus/de10nano.sdc
 delete mode 100644 examples/quartus/de10nano.tcl
 delete mode 100644 examples/yosys/Makefile
 delete mode 100644 examples/yosys/README.md
 delete mode 100644 examples/yosys/yosys.py

diff --git a/examples/ghdl/Makefile b/examples/ghdl/Makefile
deleted file mode 100644
index f166a9f9..00000000
--- a/examples/ghdl/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/usr/bin/make
-
-SCRIPTS = $(wildcard *.py)
-
-all:
-	@$(foreach SCRIPT, $(SCRIPTS), python3 $(SCRIPT) || exit;)
diff --git a/examples/ghdl/ghdl.py b/examples/ghdl/ghdl.py
deleted file mode 100644
index da2ef275..00000000
--- a/examples/ghdl/ghdl.py
+++ /dev/null
@@ -1,17 +0,0 @@
-"""Generic GHDL example project."""
-
-import logging
-
-from fpga.project import Project
-
-logging.basicConfig()
-
-prj = Project('ghdl')
-prj.set_outdir('../../build/ghdl')
-
-prj.add_files('../../hdl/blinking.vhdl', library='examples')
-prj.add_files('../../hdl/examples_pkg.vhdl', library='examples')
-prj.add_files('../../hdl/top.vhdl')
-prj.set_top('Top')
-
-prj.generate()
diff --git a/examples/hooks/Makefile b/examples/hooks/Makefile
deleted file mode 100644
index f166a9f9..00000000
--- a/examples/hooks/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/usr/bin/make
-
-SCRIPTS = $(wildcard *.py)
-
-all:
-	@$(foreach SCRIPT, $(SCRIPTS), python3 $(SCRIPT) || exit;)
diff --git a/examples/ise/Makefile b/examples/ise/Makefile
deleted file mode 100644
index 230d1cf7..00000000
--- a/examples/ise/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/usr/bin/make
-
-SCRIPTS = $(wildcard *.py)
-
-all:
-	python3 ise.py
-	python3 ise.py --board s6micro
diff --git a/examples/ise/nexys3.ucf b/examples/ise/nexys3.ucf
deleted file mode 100644
index 298bd77a..00000000
--- a/examples/ise/nexys3.ucf
+++ /dev/null
@@ -1,7 +0,0 @@
-# User Constraints File
-#
-# Used during the implementation to specify timing, placement and pinout
-# constraints.
-
-NET "clk_i" LOC = "V10";
-NET "led_o" LOC = "U16";
diff --git a/examples/ise/nexys3.xcf b/examples/ise/nexys3.xcf
deleted file mode 100644
index d8b19371..00000000
--- a/examples/ise/nexys3.xcf
+++ /dev/null
@@ -1,6 +0,0 @@
-# Xilinx Constraint File
-#
-# Used during the synthesis (XST) to specify timing and synthesis constraints.
-
-NET "clk_i" TNM_NET = "clk_i";
-TIMESPEC "TS_clk_i" = PERIOD "clk_i" 10.00 ns HIGH 50%;
diff --git a/examples/ise/s6micro.ucf b/examples/ise/s6micro.ucf
deleted file mode 100644
index 18a5cc0f..00000000
--- a/examples/ise/s6micro.ucf
+++ /dev/null
@@ -1,7 +0,0 @@
-# User Constraints File
-#
-# Used during the implementation to specify timing, placement and pinout
-# constraints.
-
-NET "clk_i" LOC = "V10";
-NET "led_o" LOC = "C2";
diff --git a/examples/ise/s6micro.xcf b/examples/ise/s6micro.xcf
deleted file mode 100644
index 6849968d..00000000
--- a/examples/ise/s6micro.xcf
+++ /dev/null
@@ -1,6 +0,0 @@
-# Xilinx Constraint File
-#
-# Used during the synthesis (XST) to specify timing and synthesis constraints.
-
-NET "clk_i" TNM_NET = "clk_i";
-TIMESPEC "TS_clk_i" = PERIOD "clk_i" 20.00 ns HIGH 50%;
diff --git a/examples/libero/Makefile b/examples/libero/Makefile
deleted file mode 100644
index f166a9f9..00000000
--- a/examples/libero/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/usr/bin/make
-
-SCRIPTS = $(wildcard *.py)
-
-all:
-	@$(foreach SCRIPT, $(SCRIPTS), python3 $(SCRIPT) || exit;)
diff --git a/examples/libero/mkr.pdc b/examples/libero/mkr.pdc
deleted file mode 100644
index 78acfe06..00000000
--- a/examples/libero/mkr.pdc
+++ /dev/null
@@ -1,4 +0,0 @@
-# Physical Design Constraints
-
-set_io clk_i -DIRECTION INPUT -pinname 23 -fixed yes
-set_io led_o -DIRECTION OUTPUT -pinname 117 -fixed yes
diff --git a/examples/libero/mkr.sdc b/examples/libero/mkr.sdc
deleted file mode 100644
index db18e27b..00000000
--- a/examples/libero/mkr.sdc
+++ /dev/null
@@ -1,6 +0,0 @@
-# Synopsys Design Constraint
-#
-# Is a Tcl-based format used by Synopsys tools to specify the design intent
-# and timing constraints.
-
-create_clock -period 20 [get_ports clk_i]
diff --git a/examples/misc/Makefile b/examples/misc/Makefile
deleted file mode 100644
index f166a9f9..00000000
--- a/examples/misc/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/usr/bin/make
-
-SCRIPTS = $(wildcard *.py)
-
-all:
-	@$(foreach SCRIPT, $(SCRIPTS), python3 $(SCRIPT) || exit;)
diff --git a/examples/misc/capture.py b/examples/misc/capture.py
deleted file mode 100644
index 4284b212..00000000
--- a/examples/misc/capture.py
+++ /dev/null
@@ -1,23 +0,0 @@
-"""PyFPGA capture example.
-
-Example about how to capture the execution messages to be post-processed
-or saved into a file.
-"""
-
-import logging
-
-from fpga.project import Project
-
-logging.basicConfig()
-
-PRJ = Project('ise', 'capture')
-PRJ.set_outdir('../../build/capture')
-
-PRJ.add_files('../../hdl/*.vhdl', library='examples')
-PRJ.set_top('Top')
-
-output = PRJ.generate(to_task='syn', capture=True)
-print(output)
-
-output = PRJ.transfer(devtype='detect', capture=True)
-print(output)
diff --git a/examples/misc/logger.py b/examples/misc/logger.py
deleted file mode 100644
index 7f34ca1c..00000000
--- a/examples/misc/logger.py
+++ /dev/null
@@ -1,25 +0,0 @@
-"""
-This script demonstrates how to utilize the logging functionality within the
-pyfpga package. The following steps are covered:
-
-1. Creating an instance of the Project class.
-2. Testing logging with the default INFO level.
-3. Setting the logging level to DEBUG to capture more detailed information.
-4. Disabling logging by removing all handlers.
-
-Usage:
-- By default, the logger captures messages with level INFO and higher.
-- To see more detailed debug information, set the logger level to DEBUG.
-- To disable logging, remove all handlers from the logger.
-"""
-
-import logging
-
-from pyfpga.project import Project
-
-prj = Project()
-prj.set_part('EXAMPLE')
-prj.logger.setLevel(logging.DEBUG)
-prj.set_part('EXAMPLE')
-prj.logger.handlers = []
-prj.set_part('EXAMPLE')
diff --git a/examples/multi/Makefile b/examples/multi/Makefile
deleted file mode 100644
index f166a9f9..00000000
--- a/examples/multi/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/usr/bin/make
-
-SCRIPTS = $(wildcard *.py)
-
-all:
-	@$(foreach SCRIPT, $(SCRIPTS), python3 $(SCRIPT) || exit;)
diff --git a/examples/quartus/Makefile b/examples/quartus/Makefile
deleted file mode 100644
index f166a9f9..00000000
--- a/examples/quartus/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/usr/bin/make
-
-SCRIPTS = $(wildcard *.py)
-
-all:
-	@$(foreach SCRIPT, $(SCRIPTS), python3 $(SCRIPT) || exit;)
diff --git a/examples/quartus/de10nano.sdc b/examples/quartus/de10nano.sdc
deleted file mode 100644
index db18e27b..00000000
--- a/examples/quartus/de10nano.sdc
+++ /dev/null
@@ -1,6 +0,0 @@
-# Synopsys Design Constraint
-#
-# Is a Tcl-based format used by Synopsys tools to specify the design intent
-# and timing constraints.
-
-create_clock -period 20 [get_ports clk_i]
diff --git a/examples/quartus/de10nano.tcl b/examples/quartus/de10nano.tcl
deleted file mode 100644
index 19494e68..00000000
--- a/examples/quartus/de10nano.tcl
+++ /dev/null
@@ -1,2 +0,0 @@
-set_location_assignment PIN_V11 -to clk_i
-set_location_assignment PIN_W15 -to led_o
diff --git a/examples/yosys/Makefile b/examples/yosys/Makefile
deleted file mode 100644
index f07825c7..00000000
--- a/examples/yosys/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/usr/bin/make
-
-SCRIPTS = $(wildcard *.py)
-
-all:
-	@$(foreach SCRIPT, $(SCRIPTS), python3 $(SCRIPT) || exit; python3 $(SCRIPT) --lang vhdl || exit; )
diff --git a/examples/yosys/README.md b/examples/yosys/README.md
deleted file mode 100644
index 44649f92..00000000
--- a/examples/yosys/README.md
+++ /dev/null
@@ -1,26 +0,0 @@
-# Yosys examples
-
-## Yosys synthesis
-
-* Verilog project: `python3 yosys.py`
-* VHDL project: `python3 yosys.py --lang vhdl`
-
-## Yosys using ISE as backend
-
-Bitstream generation:
-* Verilog project: `python3 ise.py`
-* VHDL project: `python3 ise.py --lang vhdl`
-
-Spartan-6 FPGA LX9 MicroBoard programming:
-* Verilog project: `python3 ise.py --action transfer`
-* VHDL project: `python3 ise.py --lang vhdl --action transfer`
-
-## Yosys using Vivado as backend
-
-Bitstream generation:
-* Verilog project: `python3 vivado.py`
-* VHDL project: `python3 vivado.py --lang vhdl`
-
-Zybo programming:
-* Verilog project: `python3 vivado.py --action transfer`
-* VHDL project: `python3 vivado.py --lang vhdl --action transfer`
diff --git a/examples/yosys/yosys.py b/examples/yosys/yosys.py
deleted file mode 100644
index 3553d515..00000000
--- a/examples/yosys/yosys.py
+++ /dev/null
@@ -1,31 +0,0 @@
-"""Yosys example project."""
-
-import argparse
-import logging
-
-from fpga.project import Project
-
-logging.basicConfig()
-
-parser = argparse.ArgumentParser()
-parser.add_argument(
-    '--lang', choices=['verilog', 'vhdl'], default='verilog',
-)
-args = parser.parse_args()
-
-prj = Project('yosys')
-prj.set_outdir('../../build/yosys-{}'.format(args.lang))
-
-if args.lang == 'verilog':
-    prj.add_vlog_include('../../hdl/headers1')
-    prj.add_vlog_include('../../hdl/headers2')
-    prj.add_files('../../hdl/blinking.v')
-    prj.add_files('../../hdl/top.v')
-else:  # args.lang == 'vhdl'
-    prj.add_files('../../hdl/blinking.vhdl', library='examples')
-    prj.add_files('../../hdl/examples_pkg.vhdl', library='examples')
-    prj.add_files('../../hdl/top.vhdl')
-
-prj.set_top('Top')
-
-prj.generate()

From 548d7ab4a9a4e972d1c8e1b30260dd9c8430f695 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Thu, 27 Jun 2024 22:58:09 -0300
Subject: [PATCH 110/248] Implemented par and bit for Openflow

---
 pyfpga/openflow.py              | 120 +++++---------------------------
 pyfpga/templates/openflow.jinja |  67 +++++++++++++++++-
 2 files changed, 83 insertions(+), 104 deletions(-)

diff --git a/pyfpga/openflow.py b/pyfpga/openflow.py
index 2849b4ba..10321b4c 100644
--- a/pyfpga/openflow.py
+++ b/pyfpga/openflow.py
@@ -12,6 +12,7 @@
 # pylint: disable=too-many-branches
 # pylint: disable=duplicate-code
 
+from pathlib import Path
 from pyfpga.project import Project
 
 
@@ -21,7 +22,10 @@ class Openflow(Project):
     def _make_prepare(self, steps):
         context = {
             'PROJECT': self.name or 'openflow',
-            'PART': self.data.get('part', 'hx8k-ct256')
+            'PART': self.data.get('part', 'hx8k-ct256'),
+            'FAMILY': 'ice40',
+            'DEVICE': 'hx8k',
+            'PACKAGE': 'tq144:4k'
         }
         for step in steps:
             context[step] = 1
@@ -42,21 +46,11 @@ def _make_prepare(self, steps):
 #                    files.append(
 #                        f'set_property library {lib} [get_files {file}]'
 #                    )
-#        if 'constraints' in self.data:
-#            for file in self.data['constraints']:
-#                files.append(f'add_file -fileset constrs_1 {file}')
-#            for file in self.data['constraints']:
-#                if self.data['constraints'][file] == 'syn':
-#                    prop = 'USED_IN_IMPLEMENTATION FALSE'
-#                if self.data['constraints'][file] == 'syn':
-#                    prop = 'USED_IN_SYNTHESIS FALSE'
-#                if self.data['constraints'][file] != 'all':
-#                    files.append(f'set_property {prop} [get_files {file}]')
-#            first = next(iter(self.data['constraints']))
-#            prop = f'TARGET_CONSTRS_FILE {first}'
-#            files.append(f'set_property {prop} [current_fileset -constrset]')
-#        if files:
-#            context['FILES'] = '\n'.join(files)
+        if 'constraints' in self.data:
+            constraints = []
+            for constraint in self.data['constraints']:
+                constraints.append(str(constraint))
+            context['CONSTRAINTS'] = ' '.join(constraints)
         if 'top' in self.data:
             context['TOP'] = self.data['top']
         if 'defines' in self.data:
@@ -75,57 +69,14 @@ def _make_prepare(self, steps):
         self._create_file('openflow', 'sh', context)
         return 'bash openflow.sh'
 
-#    def _prog_prepare(self, bitstream, position):
-#        _ = position  # Not needed for Vivado
-#        if not bitstream:
-#            basename = self.name or 'vivado'
-#            bitstream = Path(self.odir).resolve() / f'{basename}.bit'
-#        context = {'BITSTREAM': bitstream}
-#        self._create_file('vivado-prog', 'tcl', context)
-#        return 'vivado -mode batch -notrace -quiet -source vivado-prog.tcl'
-
     def _prog_prepare(self, bitstream, position):
-        # binaries = ['bit']
-        self.tool['prog-app'] = 'docker'
-        self.tool['prog-cmd'] = 'bash openflow-prog.sh'
-
-#     def __init__(self, project, frontend='yosys', backend='nextpnr'):
-#         # The valid frontends are be ghdl and yosys
-#         # The valid backends are:
-#         # * For ghdl -> vhdl
-#         # * For yosys -> ise, nextpnr, verilog, verilog-nosynth and vivado
-#         super().__init__(project)
-#         self.backend = backend
-#         self.frontend = frontend
-
-#     def _configure(self):
-#         super()._configure()
-#         # OCI ENGINE
-#         engine = self.configs.get('oci', {}).get('engine', {})
-#         command = engine.get('command', 'docker') + ' run --rm'
-#         volumes =
-#             '-v ' + ('-v ').join(engine.get('volumes', ['$HOME:$HOME']))
-#         work = '-w ' + engine.get('work', '$PWD')
-#         self.oci_engine = f'{command} {volumes} {work}'
-#         # Containers
-#         defaults = {
-#             'ghdl': 'ghdl/synth:beta',
-#             'yosys': 'ghdl/synth:beta',
-#             'nextpnr-ice40': 'ghdl/synth:nextpnr-ice40',
-#             'icetime': 'ghdl/synth:icestorm',
-#             'icepack': 'ghdl/synth:icestorm',
-#             'iceprog': '--device /dev/bus/usb ghdl/synth:prog',
-#             'nextpnr-ecp5': 'ghdl/synth:nextpnr-ecp5',
-#             'ecppack': 'ghdl/synth:trellis',
-#             'openocd': '--device /dev/bus/usb ghdl/synth:prog'
-#         }
-#         self.tools = {}
-#         self.conts = {}
-#         tools = self.configs.get('tools', {})
-#         containers = self.configs.get('oci', {}).get('containers', {})
-#         for tool, container in defaults.items():
-#             self.tools[tool] = tools.get(tool, tool)
-#             self.conts[tool] = containers.get(tool, container)
+        _ = position
+        if not bitstream:
+            basename = self.name or 'openflow'
+            bitstream = Path(self.odir).resolve() / f'{basename}.bit'
+        context = {'BITSTREAM': bitstream}
+        self._create_file('openflow-prog', 'sh', context)
+        return 'bash openflow-prog.sh'
 
 #     def set_part(self, part):
 #         self.part['name'] = part
@@ -172,43 +123,6 @@ def _prog_prepare(self, bitstream, position):
 #         params = []
 #         for param in self.params:
 #             params.append(f'chparam -set {param[0]} {param[1]} {self.top}')
-#         # Script creation
-#         template = os.path.join(os.path.dirname(__file__), 'template.sh')
-#         with open(template, 'r', encoding='utf-8') as file:
-#             text = file.read()
-#         text = text.format(
-#             backend=self.backend,
-#             constraints='\\\n'+'\n'.join(constraints),
-#             device=self.part['device'],
-#             includes='\\\n'+'\n'.join(paths),
-#             family=self.part['family'],
-#             frontend=self.frontend,
-#             package=self.part['package'],
-#             params='\\\n'+'\n'.join(params),
-#             project=self.project,
-#             tasks=tasks,
-#             top=self.top,
-#             verilogs='\\\n'+'\n'.join(verilogs),
-#             vhdls='\\\n'+'\n'.join(vhdls),
-#             #
-#             oci_engine=self.oci_engine,
-#             cont_ghdl=self.conts['ghdl'],
-#             cont_yosys=self.conts['yosys'],
-#             cont_nextpnr_ice40=self.conts['nextpnr-ice40'],
-#             cont_icetime=self.conts['icetime'],
-#             cont_icepack=self.conts['icepack'],
-#             cont_nextpnr_ecp5=self.conts['nextpnr-ecp5'],
-#             cont_ecppack=self.conts['ecppack'],
-#             tool_ghdl=self.tools['ghdl'],
-#             tool_yosys=self.tools['yosys'],
-#             tool_nextpnr_ice40=self.tools['nextpnr-ice40'],
-#             tool_icetime=self.tools['icetime'],
-#             tool_icepack=self.tools['icepack'],
-#             tool_nextpnr_ecp5=self.tools['nextpnr-ecp5'],
-#             tool_ecppack=self.tools['ecppack']
-#         )
-#         with open(f'{self._TOOL}.sh', 'w', encoding='utf-8') as file:
-#             file.write(text)
 
 #     def generate(self, to_task, from_task, capture):
 #         if self.frontend == 'ghdl' or 'verilog' in self.backend:
diff --git a/pyfpga/templates/openflow.jinja b/pyfpga/templates/openflow.jinja
index 6b4580c2..971149be 100644
--- a/pyfpga/templates/openflow.jinja
+++ b/pyfpga/templates/openflow.jinja
@@ -6,7 +6,9 @@
 
 set -e
 
-DOCKER="docker run --rm -v $HOME:$HOME -w $PWD"
+DOCKER="docker run --user $(id -u):$(id -g) --rm -v $HOME:$HOME -w $PWD"
+
+# Synthesis -------------------------------------------------------------------
 
 {% if SYN %}
 $DOCKER hdlc/ghdl:yosys /bin/bash -c "
@@ -25,19 +27,82 @@ verilog_defines {{ DEFINES }}
 chparam {{ PARAMS }} {{ TOP }}
 {% endif %}
 synth -top {{ TOP }}
+synth_{{ FAMILY }} -top {{ TOP }} -json {{ PROJECT }}.json
 '
 {{ POSTSYN }}
 "
 {% endif %}
 
+#SYNTH=
+#WRITE=
+#if [[ $BACKEND == "vivado" ]]; then
+#    SYNTH="synth_xilinx -top $TOP -family $FAMILY"
+#    WRITE="write_edif -pvector bra $PROJECT.edif"
+#elif [[ $BACKEND == "ise" ]]; then
+#    SYNTH="synth_xilinx -top $TOP -family $FAMILY -ise"
+#    WRITE="write_edif -pvector bra $PROJECT.edif"
+#elif [[ $BACKEND == "nextpnr" ]]; then
+#    SYNTH="synth_$FAMILY -top $TOP -json $PROJECT.json"
+#elif [[ $BACKEND == "verilog-nosynth" ]]; then
+#    WRITE="write_verilog $PROJECT.v"
+#else
+#    SYNTH="synth -top $TOP"
+#    WRITE="write_verilog $PROJECT.v"
+#fi
+
+# Place and Route -------------------------------------------------------------
+
 {% if PAR %}
+
+CONSTRAINTS="{{ CONSTRAINTS }}"
+
+{% if FAMILY == 'ice40' %}
+if [ -n "$CONSTRAINTS" ]; then
+  cat $CONSTRAINTS > constraints.pcf
+  CONSTRAINT="--pcf constraints.pcf"
+fi
+$DOCKER hdlc/nextpnr:ice40 /bin/bash -c "
 {{ PREPAR }}
+nextpnr-ice40 --{{ DEVICE }} --package {{ PACKAGE }} $CONSTRAINT --json {{ PROJECT }}.json --asc {{ PROJECT }}.asc
+{{ POSTPAR }}
+"
+$DOCKER hdlc/icestorm /bin/bash -c "
+icetime -d {{ DEVICE }} -mtr {{ PROJECT }}.rpt {{ PROJECT }}.asc
+"
+{% endif %}
 
+{% if FAMILY == 'ecp5' %}
+if [ -n "$CONSTRAINTS" ]; then
+  cat $CONSTRAINTS > constraints.lpf
+  CONSTRAINT="--lpf constraints.lpf"
+fi
+$DOCKER hdlc/nextpnr:ecp5 /bin/bash -c "
+{{ PREPAR }}
+nextpnr-ecp5 --{{ DEVICE }} --package {{ PACKAGE }} $CONSTRAINT --json {{ PROJECT }}.json --textcfg {{ PROJECT }}.config
 {{ POSTPAR }}
+"
 {% endif %}
 
+{% endif %}
+
+# Bitstream -------------------------------------------------------------------
+
 {% if BIT %}
+
+{% if FAMILY == 'ice40' %}
+$DOCKER hdlc/icestorm /bin/bash -c "
 {{ PREBIT }}
+icepack {{ PROJECT }}.asc {{ PROJECT }}.bit
+{{ POSTBIT }}
+"
+{% endif %}
 
+{% if FAMILY == 'ecp5' %}
+$DOCKER hdlc/icestorm /bin/bash -c "
+{{ PREBIT }}
+ecppack --svf {{ PROJECT }}.svf {{ PROJECT }}.config {{ PROJECT }}.bit
 {{ POSTBIT }}
+"
+{% endif %}
+
 {% endif %}

From 69ae00b474feaa58abd78ad6f16c5910323e460f Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Thu, 27 Jun 2024 23:22:29 -0300
Subject: [PATCH 111/248] Prepared template for Openflow programming

---
 pyfpga/templates/openflow-prog.jinja | 37 ++++++----------------------
 1 file changed, 7 insertions(+), 30 deletions(-)

diff --git a/pyfpga/templates/openflow-prog.jinja b/pyfpga/templates/openflow-prog.jinja
index 027eb388..fc1c1105 100644
--- a/pyfpga/templates/openflow-prog.jinja
+++ b/pyfpga/templates/openflow-prog.jinja
@@ -6,35 +6,12 @@
 
 set -e
 
-###############################################################################
-# Things to tuneup
-###############################################################################
+DOCKER="docker run --user $(id -u):$(id -g) --rm -v $HOME:$HOME -w $PWD"
 
-FAMILY={family}
-PROJECT={project}
+{% if FAMILY == 'ice40' %}
+$DOCKER --device /dev/bus/usb hdlc/prog iceprog {{ PROJECT }}.bit
+{% endif %}
 
-#
-# Tools configuration
-#
-
-OCI_ENGINE="{oci_engine}"
-
-CONT_ICEPROG="{cont_iceprog}"
-CONT_OPENOCD="{cont_openocd}"
-
-TOOL_ICEPROG="{tool_iceprog}"
-TOOL_OPENOCD="{tool_openocd}"
-
-###############################################################################
-# Programming
-###############################################################################
-
-if [[ $FAMILY == "ice40" ]]; then
-    $OCI_ENGINE $CONT_ICEPROG $TOOL_ICEPROG $PROJECT.bit
-elif [[ $FAMILY == "ecp5" ]]; then
-    $OCI_ENGINE $CONT_OPENOCD $TOOL_OPENOCD \
-        -f /usr/share/trellis/misc/openocd/ecp5-evn.cfg \
-        -c "transport select jtag; init; svf $PROJECT.svf; exit"
-else
-    echo "ERROR: unsuported tool" && exit 1
-fi
+{% if FAMILY == 'ecp5' %}
+$DOCKER --device /dev/bus/usb hdlc/prog openocd -f /usr/share/trellis/misc/openocd/ecp5-evn.cfg -c "transport select jtag; init; svf {{ PROJECT }}.svf; exit"
+{% endif %}

From 1d1c157276f12aba111aabc53d932113760bb28e Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Fri, 28 Jun 2024 20:33:14 -0300
Subject: [PATCH 112/248] Added get_info to obtain extra information based on
 the PART

---
 pyfpga/ise.py      | 103 ++++++++++++++++++++---------------
 pyfpga/libero.py   |  99 ++++++++++++++++++---------------
 pyfpga/openflow.py | 133 ++++++++++++++++++---------------------------
 tests/test_part.py |  53 +++++++++++-------
 4 files changed, 201 insertions(+), 187 deletions(-)

diff --git a/pyfpga/ise.py b/pyfpga/ise.py
index d5289930..22dab08f 100644
--- a/pyfpga/ise.py
+++ b/pyfpga/ise.py
@@ -8,7 +8,11 @@
 Implements support for ISE.
 """
 
-# import re
+# pylint: disable=too-many-locals
+# pylint: disable=too-many-branches
+# pylint: disable=duplicate-code
+
+import re
 
 from pyfpga.project import Project
 
@@ -31,23 +35,6 @@ def _prog_prepare(self, bitstream, position):
 
 #     _DEVTYPES = ['fpga', 'spi', 'bpi', 'detect', 'unlock']
 
-#     def set_part(self, part):
-#         try:
-#             device, speed, package =
-#                 re.findall(r'(\w+)-(\w+)-(\w+)', part)[0]
-#             if len(speed) > len(package):
-#                 speed, package = package, speed
-#             part = f'{device}-{speed}-{package}'
-#         except IndexError:
-#             raise ValueError(
-#                 'Part must be DEVICE-SPEED-PACKAGE or DEVICE-PACKAGE-SPEED'
-#             )
-#         self.part['name'] = part
-#         self.part['family'] = get_family(part)
-#         self.part['device'] = device
-#         self.part['package'] = package
-#         self.part['speed'] = '-' + speed
-
 #     def transfer(self, devtype, position, part, width, capture):
 #         super().transfer(devtype, position, part, width, capture)
 #         temp = _TEMPLATES[devtype]
@@ -60,29 +47,57 @@ def _prog_prepare(self, bitstream, position):
 #             file.write(temp)
 #         return run(self._TRF_COMMAND, capture)
 
-# def get_family(part):
-#     """Get the Family name from the specified part name."""
-#     part = part.lower()
-#     families = {
-#         r'xc7a\d+l': 'artix7l',
-#         r'xc7a': 'artix7',
-#         r'xc7k\d+l': 'kintex7l',
-#         r'xc7k': 'kintex7',
-#         r'xc3sd\d+a': 'spartan3adsp',
-#         r'xc3s\d+a': 'spartan3a',
-#         r'xc3s\d+e': 'spartan3e',
-#         r'xc3s': 'spartan3',
-#         r'xc6s\d+l': 'spartan6l',
-#         r'xc6s': 'spartan6',
-#         r'xc4v': 'virtex4',
-#         r'xc5v': 'virtex5',
-#         r'xc6v\d+l': 'virtex6l',
-#         r'xc6v': 'virtex6',
-#         r'xc7v\d+l': 'virtex7l',
-#         r'xc7v': 'virtex7',
-#         r'xc7z': 'zynq'
-#     }
-#     for key, value in families.items():
-#         if re.match(key, part):
-#             return value
-#     return 'UNKNOWN'
+
+def get_info(part):
+    """Get info about the FPGA part.
+
+    :param part: the FPGA part as specified by the tool
+    :returns: a dictionary with the keys family, device, speed and package
+    """
+    part = part.lower()
+    # Looking for the family
+    family = None
+    families = {
+        r'xc7a\d+l': 'artix7l',
+        r'xc7a': 'artix7',
+        r'xc7k\d+l': 'kintex7l',
+        r'xc7k': 'kintex7',
+        r'xc3sd\d+a': 'spartan3adsp',
+        r'xc3s\d+a': 'spartan3a',
+        r'xc3s\d+e': 'spartan3e',
+        r'xc3s': 'spartan3',
+        r'xc6s\d+l': 'spartan6l',
+        r'xc6s': 'spartan6',
+        r'xc4v': 'virtex4',
+        r'xc5v': 'virtex5',
+        r'xc6v\d+l': 'virtex6l',
+        r'xc6v': 'virtex6',
+        r'xc7v\d+l': 'virtex7l',
+        r'xc7v': 'virtex7',
+        r'xc7z': 'zynq'
+    }
+    for key, value in families.items():
+        if re.match(key, part):
+            family = value
+            break
+    # Looking for the device, package and speed
+    device = None
+    speed = None
+    package = None
+    aux = part.split('-')
+    if len(aux) == 3:
+        device = aux[0]
+        if len(aux[1]) < len(aux[2]):
+            speed = aux[1]
+            package = aux[2]
+        else:
+            speed = aux[2]
+            package = aux[1]
+    else:
+        raise ValueError(
+            'Part must be DEVICE-SPEED-PACKAGE or DEVICE-PACKAGE-SPEED'
+        )
+    # Finish
+    return {
+        'family': family, 'device': device, 'speed': speed, 'package': package
+    }
diff --git a/pyfpga/libero.py b/pyfpga/libero.py
index a717f1b7..7f807906 100644
--- a/pyfpga/libero.py
+++ b/pyfpga/libero.py
@@ -8,7 +8,11 @@
 Implements support for Libero.
 """
 
-# import re
+# pylint: disable=too-many-locals
+# pylint: disable=too-many-branches
+# pylint: disable=duplicate-code
+
+import re
 
 from pyfpga.project import Project
 
@@ -29,47 +33,56 @@ def _prog_prepare(self, bitstream, position):
         self.tool['prog-app'] = ''
         self.tool['prog-cmd'] = ''
 
-#     def set_part(self, part):
-#         try:
-#             device, speed, package =
-#                 re.findall(r'(\w+)-(\w+)-*(\w*)', part)[0]
-#             if len(speed) > len(package):
-#                 speed, package = package, speed
-#             if speed == '':
-#                 speed = 'STD'
-#             part = f'{device}-{speed}-{package}'
-#         except IndexError:
-#             raise ValueError(
-#                 'Part must be DEVICE-SPEED-PACKAGE or DEVICE-PACKAGE'
-#             )
-#         self.part['name'] = part
-#         self.part['family'] = get_family(part)
-#         self.part['device'] = device
-#         self.part['package'] = package
-#         self.part['speed'] = 'STD' if speed == 'STD' else '-' + speed
 
-#     def transfer(self, devtype, position, part, width, capture):
-#         super().transfer(devtype, position, part, width, capture)
-#         raise NotImplementedError('transfer(libero)')
+def get_info(part):
+    """Get info about the FPGA part.
 
-# def get_family(part):
-#     """Get the Family name from the specified part name."""
-#     part = part.lower()
-#     families = {
-#         r'm2s': 'SmartFusion2',
-#         r'm2gl': 'Igloo2',
-#         r'rt4g': 'RTG4',
-#         r'mpf': 'PolarFire',
-#         r'a2f': 'SmartFusion',
-#         r'afs': 'Fusion',
-#         r'aglp': 'IGLOO+',
-#         r'agle': 'IGLOOE',
-#         r'agl': 'IGLOO',
-#         r'a3p\d+l': 'ProAsic3L',
-#         r'a3pe': 'ProAsic3E',
-#         r'a3p': 'ProAsic3'
-#     }
-#     for key, value in families.items():
-#         if re.match(key, part):
-#             return value
-#     return 'UNKNOWN'
+    :param part: the FPGA part as specified by the tool
+    :returns: a dictionary with the keys family, device, speed and package
+    """
+    part = part.lower()
+    # Looking for the family
+    family = None
+    families = {
+        r'm2s': 'SmartFusion2',
+        r'm2gl': 'Igloo2',
+        r'rt4g': 'RTG4',
+        r'mpf': 'PolarFire',
+        r'a2f': 'SmartFusion',
+        r'afs': 'Fusion',
+        r'aglp': 'IGLOO+',
+        r'agle': 'IGLOOE',
+        r'agl': 'IGLOO',
+        r'a3p\d+l': 'ProAsic3L',
+        r'a3pe': 'ProAsic3E',
+        r'a3p': 'ProAsic3'
+    }
+    for key, value in families.items():
+        if re.match(key, part):
+            family = value
+            break
+    # Looking for the device and package
+    device = None
+    speed = None
+    package = None
+    aux = part.split('-')
+    if len(aux) == 2:
+        device = aux[0]
+        speed = 'STD'
+        package = aux[1]
+    elif len(aux) == 3:
+        device = aux[0]
+        if len(aux[1]) < len(aux[2]):
+            speed = aux[1]
+            package = aux[2]
+        else:
+            speed = aux[2]
+            package = aux[1]
+    else:
+        raise ValueError(
+            'Part must be DEVICE-SPEED-PACKAGE or DEVICE-PACKAGE'
+        )
+    # Finish
+    return {
+        'family': family, 'device': device, 'speed': speed, 'package': package
+    }
diff --git a/pyfpga/openflow.py b/pyfpga/openflow.py
index 10321b4c..8b40b259 100644
--- a/pyfpga/openflow.py
+++ b/pyfpga/openflow.py
@@ -20,12 +20,12 @@ class Openflow(Project):
     """Class to support Open Source tools."""
 
     def _make_prepare(self, steps):
+        info = get_info(self.data.get('part', 'hx8k-ct256'))
         context = {
             'PROJECT': self.name or 'openflow',
-            'PART': self.data.get('part', 'hx8k-ct256'),
-            'FAMILY': 'ice40',
-            'DEVICE': 'hx8k',
-            'PACKAGE': 'tq144:4k'
+            'FAMILY': info['family'],
+            'DEVICE': info['device'],
+            'PACKAGE': info['package']
         }
         for step in steps:
             context[step] = 1
@@ -78,29 +78,7 @@ def _prog_prepare(self, bitstream, position):
         self._create_file('openflow-prog', 'sh', context)
         return 'bash openflow-prog.sh'
 
-#     def set_part(self, part):
-#         self.part['name'] = part
-#         self.part['family'] = get_family(part)
-#         if self.part['family'] in ['ice40', 'ecp5']:
-#             aux = part.split('-')
-#             if len(aux) == 2:
-#                 self.part['device'] = aux[0]
-#                 self.part['package'] = aux[1]
-#             elif len(aux) == 3:
-#                 self.part['device'] = f'{aux[0]}-{aux[1]}'
-#                 self.part['package'] = aux[2]
-#             else:
-#                 raise ValueError('Part must be DEVICE-PACKAGE')
-#             if self.part['device'].endswith('4k'):
-#                 # See http://www.clifford.at/icestorm/
-#                 self.part['device'] = self.part['device'].replace('4', '8')
-#                 self.part['package'] += ":4k"
-
 #     def _create_gen_script(self, tasks):
-#         # Verilog includes
-#         paths = []
-#         for path in self.paths:
-#             paths.append(f'verilog_defaults -add -I{path}')
 #         # Files
 #         constraints = []
 #         verilogs = []
@@ -119,59 +97,56 @@ def _prog_prepare(self, bitstream, position):
 #             constraints.append(file[0])
 #         if len(vhdls) > 0:
 #             verilogs = [f'ghdl $FLAGS {self.top}']
-#         # Parameters
-#         params = []
-#         for param in self.params:
-#             params.append(f'chparam -set {param[0]} {param[1]} {self.top}')
 
-#     def generate(self, to_task, from_task, capture):
-#         if self.frontend == 'ghdl' or 'verilog' in self.backend:
-#             to_task = 'syn'
-#             from_task = 'syn'
-#         return super().generate(to_task, from_task, capture)
 
-#     def transfer(self, devtype, position, part, width, capture):
-#         super().transfer(devtype, position, part, width, capture)
-#         template = os.path.join(os.path.dirname(__file__), 'openprog.sh')
-#         with open(template, 'r', encoding='utf-8') as file:
-#             text = file.read()
-#         text = text.format(
-#             family=self.part['family'],
-#             project=self.project,
-#             #
-#             oci_engine=self.oci_engine,
-#             cont_iceprog=self.conts['iceprog'],
-#             cont_openocd=self.conts['openocd'],
-#             tool_iceprog=self.tools['iceprog'],
-#             tool_openocd=self.tools['openocd']
-#         )
-#         with open('openprog.sh', 'w', encoding='utf-8') as file:
-#             file.write(text)
-#         return run(self._TRF_COMMAND, capture)
+def get_info(part):
+    """Get info about the FPGA part.
 
-# def get_family(part):
-#     """Get the Family name from the specified part name."""
-#     part = part.lower()
-#     families = [
-#         # From <YOSYS>/techlibs/xilinx/synth_xilinx.cc
-#         'xcup', 'xcu', 'xc7', 'xc6s', 'xc6v', 'xc5v', 'xc4v', 'xc3sda',
-#         'xc3sa', 'xc3se', 'xc3s', 'xc2vp', 'xc2v', 'xcve', 'xcv'
-#     ]
-#     for family in families:
-#         if part.startswith(family):
-#             return family
-#     families = [
-#         # From <nextpnr>/ice40/main.cc
-#         'lp384', 'lp1k', 'lp4k', 'lp8k', 'hx1k', 'hx4k', 'hx8k',
-#         'up3k', 'up5k', 'u1k', 'u2k', 'u4k'
-#     ]
-#     if part.startswith(tuple(families)):
-#         return 'ice40'
-#     families = [
-#         # From <nextpnr>/ecp5/main.cc
-#         '12k', '25k', '45k', '85k', 'um-25k', 'um-45k', 'um-85k',
-#         'um5g-25k', 'um5g-45k', 'um5g-85k'
-#     ]
-#     if part.startswith(tuple(families)):
-#         return 'ecp5'
-#     return 'UNKNOWN'
+    :param part: the FPGA part as specified by the tool
+    :returns: a dictionary with the keys family, device and package
+    """
+    part = part.lower()
+    # Looking for the family
+    family = None
+    families = [
+        # From <YOSYS>/techlibs/xilinx/synth_xilinx.cc
+        'xcup', 'xcu', 'xc7', 'xc6s', 'xc6v', 'xc5v', 'xc4v', 'xc3sda',
+        'xc3sa', 'xc3se', 'xc3s', 'xc2vp', 'xc2v', 'xcve', 'xcv'
+    ]
+    for item in families:
+        if part.startswith(item):
+            family = item
+            break
+    families = [
+        # From <nextpnr>/ice40/main.cc
+        'lp384', 'lp1k', 'lp4k', 'lp8k', 'hx1k', 'hx4k', 'hx8k',
+        'up3k', 'up5k', 'u1k', 'u2k', 'u4k'
+    ]
+    if part.startswith(tuple(families)):
+        family = 'ice40'
+    families = [
+        # From <nextpnr>/ecp5/main.cc
+        '12k', '25k', '45k', '85k', 'um-25k', 'um-45k', 'um-85k',
+        'um5g-25k', 'um5g-45k', 'um5g-85k'
+    ]
+    if part.startswith(tuple(families)):
+        family = 'ecp5'
+    # Looking for the device and package
+    device = None
+    package = None
+    aux = part.split('-')
+    if len(aux) == 2:
+        device = aux[0]
+        package = aux[1]
+    elif len(aux) == 3:
+        device = f'{aux[0]}-{aux[1]}'
+        package = aux[2]
+    else:
+        raise ValueError('Part must be DEVICE-PACKAGE')
+    if family in ['lp4k', 'hx4k']:  # See http://www.clifford.at/icestorm
+        device = device.replace('4', '8')
+        package += ":4k"
+    if family == 'ecp5':
+        package = package.upper()
+    # Finish
+    return {'family': family, 'device': device, 'package': package}
diff --git a/tests/test_part.py b/tests/test_part.py
index 5cee3e71..7fd24ec7 100644
--- a/tests/test_part.py
+++ b/tests/test_part.py
@@ -1,27 +1,38 @@
-from pyfpga.project import Project
+from pyfpga.ise import get_info as get_info_ise
+from pyfpga.libero import get_info as get_info_libero
+from pyfpga.openflow import get_info as get_info_openflow
 
 
-# def get_part(prj):
-#     return prj.get_configs()['part'].lower()
+def test_ise():
+    info = {
+        'family': 'kintex7',
+        'device': 'xc7k160t',
+        'speed': '3',
+        'package': 'fbg484'
+    }
+    assert get_info_ise('xc7k160t-3-fbg484') == info
+    assert get_info_ise('xc7k160t-fbg484-3') == info
 
 
-# def test_ise():
-#     prj = Project('ise')
-#     assert get_part(prj) == "xc7k160t-3-fbg484"
-#     prj.set_part('XC6SLX9-2-CSG324')
-#     assert get_part(prj) == "xc6slx9-2-csg324"
-#     prj.set_part('XC6SLX9-2L-CSG324')
-#     assert get_part(prj) == "xc6slx9-2l-csg324"
-#     prj.set_part('XC6SLX9-CSG324-3')
-#     assert get_part(prj) == "xc6slx9-3-csg324"
+def test_libero():
+    info = {
+        'family': 'SmartFusion2',
+        'device': 'm2s010',
+        'speed': '1',
+        'package': 'tq144'
+    }
+    assert get_info_libero('m2s010-1-tq144') == info
+    assert get_info_libero('m2s010-tq144-1') == info
+    info['speed'] = 'STD'
+    assert get_info_libero('m2s010-tq144') == info
 
 
-# def test_libero():
-#     prj = Project('libero')
-#     assert get_part(prj) == "mpf100t-1-fcg484"
-#     prj.set_part('m2s010-3-tq144')
-#     assert get_part(prj) == "m2s010-3-tq144"
-#     prj.set_part('m2s010-tq144-2')
-#     assert get_part(prj) == "m2s010-2-tq144"
-#     prj.set_part('m2s010-tq144')
-#     assert get_part(prj) == "m2s010-std-tq144"
+def test_openflow():
+    info = {'family': 'xc7', 'device': 'xc7k160t-3', 'package': 'fbg484'}
+    assert get_info_openflow('xc7k160t-3-fbg484') == info
+    info = {'family': 'ice40', 'device': 'hx1k', 'package': 'tq144'}
+    assert get_info_openflow('hx1k-tq144') == info
+    info = {'family': 'ecp5', 'device': '25k', 'package': 'CSFBGA285'}
+    assert get_info_openflow('25k-CSFBGA285') == info
+    info = {'family': 'ecp5', 'device': 'um5g-85k', 'package': 'CABGA381'}
+    assert get_info_openflow('um5g-85k-CABGA381') == info

From 7031a189d0b0432b0002f4f6783bb97c5b97d729 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 29 Jun 2024 00:54:19 -0300
Subject: [PATCH 113/248] Re-added ISE support

---
 examples/ise/ise.py        |  46 ----------------
 examples/ise/run.py        |  50 +++++++++++++++++
 pyfpga/ise.py              |  65 ++++++++++++++++++----
 pyfpga/templates/ise.jinja | 108 ++++++++++++++++---------------------
 4 files changed, 151 insertions(+), 118 deletions(-)
 delete mode 100644 examples/ise/ise.py
 create mode 100644 examples/ise/run.py

diff --git a/examples/ise/ise.py b/examples/ise/ise.py
deleted file mode 100644
index c4f90b41..00000000
--- a/examples/ise/ise.py
+++ /dev/null
@@ -1,46 +0,0 @@
-"""ISE example project."""
-
-import argparse
-import logging
-
-from fpga.project import Project
-
-logging.basicConfig()
-
-parser = argparse.ArgumentParser()
-parser.add_argument(
-    '--action', choices=['generate', 'transfer', 'all'], default='generate',
-)
-parser.add_argument(
-    '--board',
-    choices=['nexys3', 's6micro'],
-    default='nexys3'
-)
-args = parser.parse_args()
-
-BOARDS = {
-    'nexys3': ['XC6SLX16-3-CSG324', 'nexys3.ucf', 'nexys3.xcf'],
-    's6micro': ['XC6SLX9-2-CSG324', 's6micro.ucf', 's6micro.xcf']
-}
-
-prj = Project('ise')
-prj.set_part(BOARDS[args.board][0])
-
-prj.set_outdir('../../build/ise-{}'.format(args.board))
-
-prj.add_files('../../hdl/blinking.vhdl', library='examples')
-prj.add_files('../../hdl/examples_pkg.vhdl', library='examples')
-prj.add_files('../../hdl/top.vhdl')
-prj.set_top('Top')
-
-prj.add_files(BOARDS[args.board][1])
-prj.add_files(BOARDS[args.board][2])
-
-if args.action in ['generate', 'all']:
-    prj.generate()
-
-if args.action in ['transfer', 'all']:
-    prj.transfer('fpga')
-    #  prj.transfer('detect')
-    #  prj.transfer('unlock')
-    #  prj.transfer('spi', 1, 'N25Q128', 4)
diff --git a/examples/ise/run.py b/examples/ise/run.py
new file mode 100644
index 00000000..93a35b13
--- /dev/null
+++ b/examples/ise/run.py
@@ -0,0 +1,50 @@
+"""ISE examples."""
+
+import argparse
+
+from pyfpga.ise import Ise
+
+parser = argparse.ArgumentParser()
+parser.add_argument(
+    '--board', choices=['s6micro', 'nexys3'], default='s6micro'
+)
+parser.add_argument(
+    '--source', choices=['vlog', 'vhdl'], default='vlog'
+)
+parser.add_argument(
+    '--action', choices=['make', 'prog', 'all'], default='make'
+)
+args = parser.parse_args()
+
+prj = Ise(odir='../build/ise')
+
+if args.board == 's6micro':
+    prj.set_part('xc6slx9-2-csg324')
+    prj.add_param('FREQ', '125000000')
+    prj.add_cons('../sources/s6micro/clk.xcf', 'syn')
+    prj.add_cons('../sources/s6micro/clk.ucf', 'par')
+    prj.add_cons('../sources/s6micro/led.ucf', 'par')
+if args.board == 'nexys3':
+    prj.set_part('xc6slx16-3-csg32')
+    prj.add_param('FREQ', '100000000')
+    prj.add_cons('../sources/nexys3/clk.xcf', 'syn')
+    prj.add_cons('../sources/nexys3/clk.ucf', 'par')
+    prj.add_cons('../sources/nexys3/led.ucf', 'par')
+prj.add_param('SECS', '1')
+
+if args.source == 'vhdl':
+    prj.add_vhdl('../sources/vhdl/*.vhdl', 'blink_lib')
+if args.source == 'vlog':
+    prj.add_include('../sources/vlog/include1')
+    prj.add_include('../sources/vlog/include2')
+    prj.add_vlog('../sources/vlog/*.v')
+    prj.add_define('DEFINE1', '1')
+    prj.add_define('DEFINE2', '1')
+
+prj.set_top('Top')
+
+if args.action in ['make', 'all']:
+    prj.make()
+
+if args.action in ['prog', 'all']:
+    prj.prog()
diff --git a/pyfpga/ise.py b/pyfpga/ise.py
index 22dab08f..1777539b 100644
--- a/pyfpga/ise.py
+++ b/pyfpga/ise.py
@@ -20,18 +20,65 @@
 class Ise(Project):
     """Class to support ISE projects."""
 
-    def __init__(self, name='ise', odir='results'):
-        super().__init__(name=name, odir=odir)
-        self.set_part('xc7k160t-3-fbg484')
-
     def _make_prepare(self, steps):
-        self.tool['make-app'] = 'xtclsh'
-        self.tool['make-cmd'] = 'xtclsh ise.tcl'
+        info = get_info(self.data.get('part', 'xc7k160t-3-fbg484'))
+        context = {
+            'PROJECT': self.name or 'ise',
+            'FAMILY': info['family'],
+            'DEVICE': info['device'],
+            'SPEED': info['speed'],
+            'PACKAGE': info['package']
+        }
+        for step in steps:
+            context[step] = 1
+        if 'includes' in self.data:
+            includes = []
+            for include in self.data['includes']:
+                includes.append(str(include))
+            context['INCLUDES'] = '|'.join(includes)
+        files = []
+        if 'files' in self.data:
+            for file in self.data['files']:
+                if 'lib' in self.data['files']:
+                    lib = self.data['files'][file]['lib']
+                    files.append(f'lib_vhdl new {lib}')
+                    files.append(f'xfile add {file} -lib_vhdl {lib}')
+                else:
+                    files.append(f'xfile add {file}')
+        if 'constraints' in self.data:
+            for file in self.data['constraints']:
+                files.append(f'xfile add {file}')
+        if files:
+            context['FILES'] = '\n'.join(files)
+        if 'top' in self.data:
+            context['TOP'] = self.data['top']
+        if 'defines' in self.data:
+            defines = []
+            for key, value in self.data['defines'].items():
+                defines.append(f'{key}={value}')
+            context['DEFINES'] = ' | '.join(defines)
+        if 'params' in self.data:
+            params = []
+            for key, value in self.data['params'].items():
+                params.append(f'{key}={value}')
+            context['PARAMS'] = ' '.join(params)
+        if 'hooks' in self.data:
+            for stage in self.data['hooks']:
+                context[stage.upper()] = '\n'.join(self.data['hooks'][stage])
+        self._create_file('ise', 'tcl', context)
+        return 'xtclsh ise.tcl'
 
     def _prog_prepare(self, bitstream, position):
-        # binaries = ['bit']
-        self.tool['prog-app'] = 'impact'
-        self.tool['prog-cmd'] = 'impact -batch impact-prog'
+        if not bitstream:
+            basename = self.name or 'ise'
+            bitstream = Path(self.odir).resolve() / f'{basename}.bit'
+        context = {'BITSTREAM': bitstream, 'POSITION': position}
+        self._create_file('vivado-prog', 'tcl', context)
+        return 'impact -batch impact-prog'
+
+    def add_slog(self, pathname):
+        """Add System Verilog file/s."""
+        raise NotImplementedError('ISE does not support SystemVerilog')
 
 #     _DEVTYPES = ['fpga', 'spi', 'bpi', 'detect', 'unlock']
 
diff --git a/pyfpga/templates/ise.jinja b/pyfpga/templates/ise.jinja
index c70efad6..79b3f9de 100644
--- a/pyfpga/templates/ise.jinja
+++ b/pyfpga/templates/ise.jinja
@@ -4,66 +4,49 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-set PROJECT  {{ PROJECT }}
-set PART     {{ PART }}
-set FAMILY   {{ FAMILY }}
-set DEVICE   {{ DEVICE }}
-set PACKAGE  {{ PACKAGE }}
-set SPEED    {{ SPEED }}
-set TOP      {{ TOP }}
-
-set PARAMS   [list {{ PARAMS }}]
-
-proc fpga_file {FILE {LIBRARY "work"}} {
-    set message "adding the file '$FILE'"
-    if { $LIBRARY != "work" } { append message " (into the VHDL library '$LIBRARY')" }
-    regexp -nocase {\.(\w*)$} $FILE -> ext
-    if { $ext == "tcl" } {
-        source $FILE
-        return
-    }
-    if {$ext == "xcf"} {
-        project set "Synthesis Constraints File" $FILE -process "Synthesize - XST"
-    } elseif { $LIBRARY != "work" } {
-        lib_vhdl new $LIBRARY
-        xfile add $FILE -lib_vhdl $LIBRARY
-    } else {
-        xfile add $FILE
-    }
-}
-
-proc fpga_include {PATH} {
-    lappend INCLUDED $PATH
-    # Verilog Included Files are NOT added
-    project set "Verilog Include Directories" \
-    [join $INCLUDED "|"] -process "Synthesize - XST"
-}
-
-proc fpga_params {} {
-    if { [llength $PARAMS] == 0 } { return }
-    set assigns [list]
-    foreach PARAM $PARAMS { lappend assigns [join $PARAM "="] }
-    project set "Generics, Parameters" "[join $assigns]" -process "Synthesize - XST"
-}
-
-#--[ Project configuration ]---------------------------------------------------
+#    if {$ext == "xcf"} {
+#        project set "Synthesis Constraints File" $FILE -process "Synthesize - XST"
+#    } elseif { $LIBRARY != "work" } {
+#        lib_vhdl new $LIBRARY
+#        xfile add $FILE -lib_vhdl $LIBRARY
+#    } else {
+#        xfile add $FILE
+#    }
+#}
+
+#--[ Project configuration ]--------------------------------------------------
 
 {% if CFG %}
-if { [ file exists $PROJECT.xise ] } { file delete $PROJECT.xise }
-project new $PROJECT.xise
-
-project set family  $FAMILY
-project set device  $DEVICE
-project set package $PACKAGE
-project set speed   $SPEED
+if { [ file exists {{ PROJECT }}.xise ] } { file delete {{ PROJECT }}.xise }
+project new {{ PROJECT }}.xise
+project set family  {{ FAMILY }}
+project set device  {{ DEVICE }}
+project set package {{ PACKAGE }}
+project set speed  -{{ SPEED }}
 
 {{ PRECFG }}
 
 {{ FILES }}
+{% if CONSTRAINTS %}
+project set "Synthesis Constraints File" "{{ CONSTRAINTS }}" -process "Synthesize - XST"
+{% endif %}
 
-project set top $TOP
+{% if TOP %}
+project set top {{ TOP }}
+{% endif %}
 
-fpga_params
+{% if DEFINES %}
+project set "Verilog Macros" "{{ DEFINES }}" -process "Synthesize - XST"
+{% endif %}
+
+{% if INCLUDES %}
+project set "Verilog Include Directories" "{{ INCLUDES }}" -process "Synthesize - XST"
+# [join $INCLUDED "|"]
+{% endif %}
+
+{% if PARAMS %}
+project set "Generics, Parameters" "{{ PARAMS }}" -process "Synthesize - XST"
+{% endif %}
 
 {{ POSTCFG }}
 
@@ -73,18 +56,16 @@ project close
 #--[ Design flow ]-------------------------------------------------------------
 
 {% if SYN or PAR or BIT %}
-project open $PROJECT.xise
+project open {{ PROJECT }}.xise
 
 {% if SYN %}
 {{ PRESYN }}
 
-{% if PRESYNTH %}
-project set top_level_module_type "EDIF"
-{% else %}
+# PRESYNTH
+#project set top_level_module_type "EDIF"
 project clean
 process run "Synthesize"
-if { [process get "Synthesize" status] == "errors" } { exit 2 }
-{% endif %}
+if { [process get "Synthesize" status] == "errors" } { exit 1 }
 
 {{ POSTSYN }}
 {% endif %}
@@ -93,11 +74,11 @@ if { [process get "Synthesize" status] == "errors" } { exit 2 }
 {{ PREPAR }}
 
 process run "Translate"
-if { [process get "Translate" status] == "errors" } { exit 2 }
+if { [process get "Translate" status] == "errors" } { exit 1 }
 process run "Map"
-if { [process get "Map" status] == "errors" } { exit 2 }
+if { [process get "Map" status] == "errors" } { exit 1 }
 process run "Place & Route"
-if { [process get "Place & Route" status] == "errors" } { exit 2 }
+if { [process get "Place & Route" status] == "errors" } { exit 1 }
 
 {{ POSTPAR }}
 {% endif %}
@@ -106,8 +87,9 @@ if { [process get "Place & Route" status] == "errors" } { exit 2 }
 {{ PREBIT }}
 
 process run "Generate Programming File"
-if { [process get "Generate Programming File" status] == "errors" } { exit 2 }
-catch { file rename -force $TOP.bit $PROJECT.bit }
+if { [process get "Generate Programming File" status] == "errors" } { exit 1 }
+# catch { file rename -force {{ TOP }}.bit {{ PROJECT }}.bit }
+file rename -force {{ TOP }}.bit {{ PROJECT }}.bit
 
 {{ POSTBIT }}
 {% endif %}

From f0044941e1c7535d9e93c7bc159e3ed8f7bcd2e4 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 29 Jun 2024 14:00:55 -0300
Subject: [PATCH 114/248] Fixed to include ISE XST constraints

---
 pyfpga/ise.py              |  5 +++++
 pyfpga/templates/ise.jinja | 10 ----------
 2 files changed, 5 insertions(+), 10 deletions(-)

diff --git a/pyfpga/ise.py b/pyfpga/ise.py
index 1777539b..b3c86739 100644
--- a/pyfpga/ise.py
+++ b/pyfpga/ise.py
@@ -46,8 +46,13 @@ def _make_prepare(self, steps):
                 else:
                     files.append(f'xfile add {file}')
         if 'constraints' in self.data:
+            constraints = []
             for file in self.data['constraints']:
                 files.append(f'xfile add {file}')
+                if file.suffix == '.xcf':
+                    constraints.append(str(file))
+            if constraints:
+                context['CONSTRAINTS'] = " ".join(constraints)
         if files:
             context['FILES'] = '\n'.join(files)
         if 'top' in self.data:
diff --git a/pyfpga/templates/ise.jinja b/pyfpga/templates/ise.jinja
index 79b3f9de..024e0edb 100644
--- a/pyfpga/templates/ise.jinja
+++ b/pyfpga/templates/ise.jinja
@@ -4,16 +4,6 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-#    if {$ext == "xcf"} {
-#        project set "Synthesis Constraints File" $FILE -process "Synthesize - XST"
-#    } elseif { $LIBRARY != "work" } {
-#        lib_vhdl new $LIBRARY
-#        xfile add $FILE -lib_vhdl $LIBRARY
-#    } else {
-#        xfile add $FILE
-#    }
-#}
-
 #--[ Project configuration ]--------------------------------------------------
 
 {% if CFG %}

From 349af14700764a5f3a5956b787f2c4f19c185da3 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 29 Jun 2024 15:13:05 -0300
Subject: [PATCH 115/248] Modified to have different log files for make and
 prog

---
 pyfpga/project.py | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/pyfpga/project.py b/pyfpga/project.py
index faaacffe..d33dbd93 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -228,7 +228,7 @@ def make(self, first='cfg', last='bit'):
             message = steps[first]
         self.logger.info('Running %s', message)
         selected = [step.upper() for step in keys[index[0]:index[1]+1]]
-        self._run(self._make_prepare(selected))
+        self._run(self._make_prepare(selected), 'make.log')
 
     def prog(self, bitstream=None, position=1):
         """Program the FPGA
@@ -244,7 +244,7 @@ def prog(self, bitstream=None, position=1):
         if position not in range(1, 9):
             raise ValueError('Invalid position.')
         self.logger.info('Programming')
-        self._run(self._prog_prepare(bitstream, position))
+        self._run(self._prog_prepare(bitstream, position), 'prog.log')
 
     def _make_prepare(self, steps):
         raise NotImplementedError('Tool-dependent')
@@ -264,7 +264,7 @@ def _create_file(self, basename, extension, context):
         with open(directory / filename, 'w', encoding='utf-8') as file:
             file.write(content)
 
-    def _run(self, command):
+    def _run(self, command, logname):
         num = 20
         error = 0
         old_dir = Path.cwd()
@@ -272,13 +272,13 @@ def _run(self, command):
         start = time()
         try:
             os.chdir(new_dir)
-            with open('run.log', 'w', encoding='utf-8') as file:
+            with open(logname, 'w', encoding='utf-8') as file:
                 subprocess.run(
                     command, shell=True, check=True, text=True,
                     stdout=file, stderr=subprocess.STDOUT
                 )
         except subprocess.CalledProcessError:
-            with open('run.log', 'r', encoding='utf-8') as file:
+            with open(logname, 'r', encoding='utf-8') as file:
                 lines = file.readlines()
                 last_lines = lines[-num:] if len(lines) >= num else lines
                 for line in last_lines:

From 47cb94286a5f6189ddcf71d876cdeb41e9fd3371 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 29 Jun 2024 15:25:34 -0300
Subject: [PATCH 116/248] Small fix on quartus-prog and prepared ise-prog

---
 pyfpga/templates/ise-prog.jinja     | 56 +++++++++++++----------------
 pyfpga/templates/quartus-prog.jinja |  2 +-
 2 files changed, 25 insertions(+), 33 deletions(-)

diff --git a/pyfpga/templates/ise-prog.jinja b/pyfpga/templates/ise-prog.jinja
index 4c18a072..2ba0c193 100644
--- a/pyfpga/templates/ise-prog.jinja
+++ b/pyfpga/templates/ise-prog.jinja
@@ -4,57 +4,49 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-_TEMPLATES = {
-    'fpga': """setMode -bs
+cleancablelock
+
+{% if FPGA %}
+setMode -bs
 setCable -port auto
 Identify -inferir
-assignFile -p #POSITION# -file #BITSTREAM#
-Program -p #POSITION#
+assignFile -p {{ POSITION }} -file  {{ BITSTREAM }}
+Program -p {{ POSITION }}
+{% endif %}
 
-quit
-""",
-    'spi': """setMode -pff
-addConfigDevice -name #NAME# -path .
+{% if SPI %}
+setMode -pff
+addConfigDevice -name {{ NAME }} -path .
 setSubmode -pffspi
 addDesign -version 0 -name 0
 addDeviceChain -index 0
-addDevice -p 1 -file #BITSTREAM#
+addDevice -p 1 -file {{ BITSTREAM }}
 generate -generic
 
 setMode -bs
 setCable -port auto
 Identify
-attachflash -position #POSITION# -spi #NAME#
-assignfiletoattachedflash -position #POSITION# -file ./#NAME#.mcs
-Program -p #POSITION# -dataWidth #WIDTH# -spionly -e -v -loadfpga
+attachflash -position {{ POSITION }} -spi {{ NAME }}
+assignfiletoattachedflash -position {{ POSITION }} -file ./{{ NAME }}.mcs
+Program -p {{ POSITION }} -dataWidth {{ WIDTH }} -spionly -e -v -loadfpga
+{% endif %}
 
-quit
-""",
-    'bpi': """setMode -pff
-addConfigDevice -name #NAME# -path .
+{% if BPI %}
+setMode -pff
+addConfigDevice -name {{ NAME }} -path .
 setSubmode -pffbpi
 addDesign -version 0 -name 0
 addDeviceChain -index 0
-setAttribute -configdevice -attr flashDataWidth -value #WIDTH#
-addDevice -p 1 -file #BITSTREAM#
+setAttribute -configdevice -attr flashDataWidth -value {{ WIDTH }}
+addDevice -p 1 -file {{ BITSTREAM }}
 generate -generic
 
 setMode -bs
 setCable -port auto
 Identify
-attachflash -position #POSITION# -bpi #NAME#
-assignfiletoattachedflash -position #POSITION# -file ./#NAME#.mcs
-Program -p #POSITION# -dataWidth #WIDTH# \
--rs1 NONE -rs0 NONE -bpionly -e -v -loadfpga
+attachflash -position {{ POSITION }} -bpi {{ NAME }}
+assignfiletoattachedflash -position {{ POSITION }} -file ./{{ NAME }}.mcs
+Program -p {{ POSITION }} -dataWidth {{ WIDTH }} -rs1 NONE -rs0 NONE -bpionly -e -v -loadfpga
+{% endif %}
 
 quit
-""",
-    'detect': """setMode -bs
-setCable -port auto
-Identify -inferir
-quit
-""",
-    'unlock': """cleancablelock
-quit
-"""
-}
diff --git a/pyfpga/templates/quartus-prog.jinja b/pyfpga/templates/quartus-prog.jinja
index 45ee765b..d754fee5 100644
--- a/pyfpga/templates/quartus-prog.jinja
+++ b/pyfpga/templates/quartus-prog.jinja
@@ -4,4 +4,4 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-{{ COMMAND }} -c %s --mode jtag -o "p;{{ BITSTREAM }}@{{ POSITION }}"
+quartus_pgm -c {{ CABLE }} --mode jtag -o "p;{{ BITSTREAM }}@{{ POSITION }}"

From 7e13dc7767a88351a5782b84e0ecd88b2155c813 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 29 Jun 2024 15:27:55 -0300
Subject: [PATCH 117/248] Added missing import of Path

---
 pyfpga/ise.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/pyfpga/ise.py b/pyfpga/ise.py
index b3c86739..370c80ce 100644
--- a/pyfpga/ise.py
+++ b/pyfpga/ise.py
@@ -14,6 +14,7 @@
 
 import re
 
+from pathlib import Path
 from pyfpga.project import Project
 
 

From f2fa17f73b887af724051adb8dc9779455146a7d Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 29 Jun 2024 16:11:42 -0300
Subject: [PATCH 118/248] Added to raise an exception for Libero programming

---
 pyfpga/libero.py                   | 4 +---
 pyfpga/templates/libero-prog.jinja | 7 -------
 2 files changed, 1 insertion(+), 10 deletions(-)

diff --git a/pyfpga/libero.py b/pyfpga/libero.py
index 7f807906..5cf8efe4 100644
--- a/pyfpga/libero.py
+++ b/pyfpga/libero.py
@@ -29,9 +29,7 @@ def _make_prepare(self, steps):
         self.tool['make-cmd'] = 'libero SCRIPT:libero.tcl'
 
     def _prog_prepare(self, bitstream, position):
-        # binaries = ['bit']
-        self.tool['prog-app'] = ''
-        self.tool['prog-cmd'] = ''
+        raise NotImplementedError('Libero programming not supported')
 
 
 def get_info(part):
diff --git a/pyfpga/templates/libero-prog.jinja b/pyfpga/templates/libero-prog.jinja
index ed9effe2..95b740f0 100644
--- a/pyfpga/templates/libero-prog.jinja
+++ b/pyfpga/templates/libero-prog.jinja
@@ -4,13 +4,6 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-_TEMPLATES = {
-    'fpga': """\
-""",
-    'detect': """\
-"""
-}
-
 # open_project -file {$TEMPDIR/libero.prjx}
 # run_tool -name {CONFIGURE_CHAIN} -script {$TEMPDIR/flashpro.tcl}
 # run_tool -name {PROGRAMDEVICE}

From fa66cfac6355b968e72c23e9c7601835afebbd0d Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 29 Jun 2024 18:17:47 -0300
Subject: [PATCH 119/248] Re-added Quartus support (WIP)

---
 examples/ise/run.py            |  1 +
 examples/quartus/quartus.py    | 32 --------------
 examples/quartus/run.py        | 50 +++++++++++++++++++++
 pyfpga/quartus.py              | 71 +++++++++++++++++++++++++----
 pyfpga/templates/quartus.jinja | 81 +++++++++-------------------------
 5 files changed, 135 insertions(+), 100 deletions(-)
 delete mode 100644 examples/quartus/quartus.py
 create mode 100644 examples/quartus/run.py

diff --git a/examples/ise/run.py b/examples/ise/run.py
index 93a35b13..3bd89df9 100644
--- a/examples/ise/run.py
+++ b/examples/ise/run.py
@@ -4,6 +4,7 @@
 
 from pyfpga.ise import Ise
 
+
 parser = argparse.ArgumentParser()
 parser.add_argument(
     '--board', choices=['s6micro', 'nexys3'], default='s6micro'
diff --git a/examples/quartus/quartus.py b/examples/quartus/quartus.py
deleted file mode 100644
index 6516fcd0..00000000
--- a/examples/quartus/quartus.py
+++ /dev/null
@@ -1,32 +0,0 @@
-"""Quartus example project."""
-
-import argparse
-import logging
-
-from fpga.project import Project
-
-logging.basicConfig()
-
-parser = argparse.ArgumentParser()
-parser.add_argument(
-    '--action', choices=['generate', 'transfer', 'all'], default='generate',
-)
-args = parser.parse_args()
-
-prj = Project('quartus')
-prj.set_part('5CSEBA6U23I7')
-
-prj.set_outdir('../../build/quartus')
-
-prj.add_files('../../hdl/blinking.vhdl', library='examples')
-prj.add_files('../../hdl/examples_pkg.vhdl', library='examples')
-prj.add_files('../../hdl/top.vhdl')
-prj.set_top('Top')
-prj.add_files('de10nano.sdc')
-prj.add_files('de10nano.tcl')
-
-if args.action in ['generate', 'all']:
-    prj.generate()
-
-if args.action in ['transfer', 'all']:
-    prj.transfer('fpga', 2)
diff --git a/examples/quartus/run.py b/examples/quartus/run.py
new file mode 100644
index 00000000..0453ac8e
--- /dev/null
+++ b/examples/quartus/run.py
@@ -0,0 +1,50 @@
+"""Quartus examples."""
+
+import argparse
+
+from pyfpga.quartus import Quartus
+
+
+parser = argparse.ArgumentParser()
+parser.add_argument(
+    '--board', choices=['de10nano'], default='de10nano'
+)
+parser.add_argument(
+    '--source', choices=['vlog', 'vhdl', 'slog'], default='vlog'
+)
+parser.add_argument(
+    '--action', choices=['make', 'prog', 'all'], default='make'
+)
+args = parser.parse_args()
+
+prj = Quartus(odir='../build/quartus')
+
+if args.board == 'de10nano':
+    prj.set_part('5CSEBA6U23I7')
+    prj.add_param('FREQ', '125000000')
+    prj.add_cons('../sources/de10nano/clk.sdc', 'syn')
+    prj.add_cons('../sources/de10nano/clk.tcl', 'par')
+    prj.add_cons('../sources/de10nano/led.tcl', 'par')
+prj.add_param('SECS', '1')
+
+if args.source == 'vhdl':
+    prj.add_vhdl('../sources/vhdl/*.vhdl', 'blink_lib')
+if args.source == 'vlog':
+    prj.add_include('../sources/vlog/include1')
+    prj.add_include('../sources/vlog/include2')
+    prj.add_vlog('../sources/vlog/*.v')
+if args.source == 'slog':
+    prj.add_include('../sources/slog/include1')
+    prj.add_include('../sources/slog/include2')
+    prj.add_vlog('../sources/slog/*.sv')
+if args.source in ['vlog', 'slog']:
+    prj.add_define('DEFINE1', '1')
+    prj.add_define('DEFINE2', '1')
+
+prj.set_top('Top')
+
+if args.action in ['make', 'all']:
+    prj.make()
+
+if args.action in ['prog', 'all']:
+    prj.prog()
diff --git a/pyfpga/quartus.py b/pyfpga/quartus.py
index 4ca2bf78..fda50647 100644
--- a/pyfpga/quartus.py
+++ b/pyfpga/quartus.py
@@ -8,7 +8,9 @@
 Implements support for Quartus.
 """
 
-# import re
+# pylint: disable=too-many-locals
+# pylint: disable=too-many-branches
+# pylint: disable=duplicate-code
 
 from pyfpga.project import Project
 
@@ -16,18 +18,69 @@
 class Quartus(Project):
     """Class to support Quartus projects."""
 
-    def __init__(self, name='quartus', odir='results'):
-        super().__init__(name=name, odir=odir)
-        self.set_part('10cl120zf780i8g')
-
     def _make_prepare(self, steps):
-        self.tool['make-app'] = 'quartus_sh'
-        self.tool['make-cmd'] = 'quartus_sh --script quartus.tcl'
+        context = {
+            'PROJECT': self.name or 'quartus',
+            'PART': self.data.get('part', '10cl120zf780i8g')
+        }
+        for step in steps:
+            context[step] = 1
+        if 'includes' in self.data:
+            includes = []
+            for include in self.data['includes']:
+                includes.append(str(include))
+            context['INCLUDES'] = ' '.join(includes)
+        files = []
+        if 'files' in self.data:
+            types = {
+                'slog': 'SYSTEMVERILOG_FILE',
+                'vhdl': 'VHDL_FILE',
+                'vlog': 'VERILOG_FILE'
+            }
+            for file in self.data['files']:
+                hdl = self.data['files'][file]['hdl']
+                lib = self.data['files'][file].get('lib', None)
+                typ = types[hdl]
+                line = f'set_global_assignment -name {typ} {file}'
+                if lib:
+                    line += f' -library {lib}'
+                files.append(line)
+        if 'constraints' in self.data:
+            for file in self.data['constraints']:
+                if file.suffix == '.sdc':
+                    line = f'set_global_assignment -name SDC_FILE {file}'
+                else:
+                    line = f'source {file}'
+                files.append(line)
+        if files:
+            context['FILES'] = '\n'.join(files)
+        if 'top' in self.data:
+            context['TOP'] = self.data['top']
+        if 'defines' in self.data:
+            defines = []
+            for key, value in self.data['defines'].items():
+                defines.append(f'{key} {value}')
+            context['DEFINES'] = ' '.join(defines)
+        if 'params' in self.data:
+            params = []
+            for key, value in self.data['params'].items():
+                params.append(f'{key} {value}')
+            context['PARAMS'] = ' '.join(params)
+        if 'hooks' in self.data:
+            for stage in self.data['hooks']:
+                context[stage.upper()] = '\n'.join(self.data['hooks'][stage])
+        self._create_file('quartus', 'tcl', context)
+        return 'quartus_sh --script quartus.tcl'
 
     def _prog_prepare(self, bitstream, position):
         # binaries = ['sof', 'pof']
-        self.tool['prog-app'] = 'quartus_pgm'
-        self.tool['prog-cmd'] = 'bash quartus-prog.sh'
+        _ = position  # Not needed for Vivado
+        # if not bitstream:
+        #     basename = self.name or 'quartus'
+        #     bitstream = Path(self.odir).resolve() / f'{basename}.bit'
+        context = {'BITSTREAM': bitstream}
+        self._create_file('quartus-prog', 'tcl', context)
+        return 'bash quartus-prog.sh'
 
 #     def transfer(self, devtype, position, part, width, capture):
 #         super().transfer(devtype, position, part, width, capture)
diff --git a/pyfpga/templates/quartus.jinja b/pyfpga/templates/quartus.jinja
index cf660a8d..4b98174a 100644
--- a/pyfpga/templates/quartus.jinja
+++ b/pyfpga/templates/quartus.jinja
@@ -4,72 +4,35 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-set PROJECT  {{ PROJECT }}
-set PART     {{ PART }}
-set FAMILY   {{ FAMILY }}
-set DEVICE   {{ DEVICE }}
-set PACKAGE  {{ PACKAGE }}
-set SPEED    {{ SPEED }}
-set TOP      {{ TOP }}
-
-set PARAMS   [list {{ PARAMS }}]
-
-proc fpga_file {FILE {LIBRARY "work"}} {
-    set message "adding the file '$FILE'"
-    if { $LIBRARY != "work" } { append message " (into the VHDL library '$LIBRARY')" }
-    regexp -nocase {\.(\w*)$} $FILE -> ext
-    if { $ext == "tcl" } {
-        source $FILE
-        return
-    }
-    if {$ext == "v"} {
-        set TYPE VERILOG_FILE
-    } elseif {$ext == "sv"} {
-        set TYPE SYSTEMVERILOG_FILE
-    } elseif {$ext == "vhdl" || $ext == "vhd"} {
-        set TYPE VHDL_FILE
-    } elseif {$ext == "sdc"} {
-        set TYPE SDC_FILE
-    } else {
-        set TYPE SOURCE_FILE
-    }
-    if { $LIBRARY != "work" } {
-        set_global_assignment -name $TYPE $FILE -library $LIBRARY
-    } else {
-        set_global_assignment -name $TYPE $FILE
-    }
-}
-
-proc fpga_include {PATH} {
-    lappend INCLUDED $PATH
-    # Verilog Included Files are NOT added
-    foreach INCLUDE $INCLUDED {
-        set_global_assignment -name SEARCH_PATH $INCLUDE
-    }
-}
-
-proc fpga_params {} {
-    if { [llength $PARAMS] == 0 } { return }
-    foreach PARAM $PARAMS {
-        eval "set_parameter -name $PARAM"
-    }
-}
-
 #--[ Project configuration ]---------------------------------------------------
 
 {% if CFG %}
 package require ::quartus::project
-project_new $PROJECT -overwrite
-
-set_global_assignment -name DEVICE $PART
+project_new {{ PROJECT }} -overwrite
+set_global_assignment -name DEVICE {{ PART }}
 
 {{ PRECFG }}
 
-fpga_files
+{{ FILES }}
+
+{% if TOP %}
+set_global_assignment -name TOP_LEVEL_ENTITY {{ TOP }}
+{% endif %}
+
+{% if DEFINES %}
+set defines [dict create {{ DEFINES }}]
+foreach {key value} $defines {set_global_assignment -name VERILOG_MACRO "$key=$value"}
+{% endif %}
 
-set_global_assignment -name TOP_LEVEL_ENTITY $TOP
+{% if INCLUDES %}
+set includes { {{ INCLUDES}} }
+foreach value $includes {set_global_assignment -name SEARCH_PATH $value}
+{% endif %}
 
-fpga_params
+{% if PARAMS %}
+set params [dict create {{ PARAMS }}]
+foreach {key value} $params {set_parameter -name $key $value}
+{% endif %}
 
 {{ POSTCFG }}
 
@@ -80,8 +43,8 @@ project_close
 
 {% if SYN or PAR or BIT %}
 package require ::quartus::flow
-project_open -force $PROJECT.qpf
-set_global_assignment -name NUM_PARALLEL_PROCESSORS ALL
+project_open -force {{ PROJECT }}.qpf
+# set_global_assignment -name NUM_PARALLEL_PROCESSORS ALL
 
 {% if SYN %}
 {{ PRESYN }}

From 2b34189694b5a5107e3379b8d9198542008337c5 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 29 Jun 2024 20:54:48 -0300
Subject: [PATCH 120/248] Fix duplicate logging issue when creating new
 instances

---
 pyfpga/project.py | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/pyfpga/project.py b/pyfpga/project.py
index d33dbd93..b9192c03 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -36,14 +36,15 @@ def __init__(self, name=None, odir='results'):
         self.odir = odir
         # logging config
         self.logger = logging.getLogger(self.__class__.__name__)
-        self.logger.setLevel(logging.INFO)
-        handler = logging.StreamHandler()
-        formatter = logging.Formatter(
-            '%(asctime)s - %(levelname)s - %(message)s',
-            datefmt='%Y-%m-%d %H:%M:%S'
-        )
-        handler.setFormatter(formatter)
-        self.logger.addHandler(handler)
+        if not self.logger.handlers:
+            self.logger.setLevel(logging.INFO)
+            handler = logging.StreamHandler()
+            formatter = logging.Formatter(
+                '%(asctime)s - %(levelname)s - %(message)s',
+                datefmt='%Y-%m-%d %H:%M:%S'
+            )
+            handler.setFormatter(formatter)
+            self.logger.addHandler(handler)
 
     def set_part(self, name):
         """Set the FPGA part name.

From c8841d5ddd933e15f98d9363806b7ad0c3893cbf Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 29 Jun 2024 20:58:53 -0300
Subject: [PATCH 121/248] Add a test to verify support of the specified tool

---
 tests/projects/support.py | 126 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 126 insertions(+)
 create mode 100644 tests/projects/support.py

diff --git a/tests/projects/support.py b/tests/projects/support.py
new file mode 100644
index 00000000..3b529f14
--- /dev/null
+++ b/tests/projects/support.py
@@ -0,0 +1,126 @@
+"""Vivado examples."""
+
+import sys
+
+from pyfpga.ise import Ise
+from pyfpga.libero import Libero
+from pyfpga.openflow import Openflow
+from pyfpga.quartus import Quartus
+from pyfpga.vivado import Vivado
+
+
+classes = {
+    'ise': Ise,
+    'libero': Libero,
+    'openflow': Openflow,
+    'quartus': Quartus,
+    'vivado': Vivado
+}
+
+tool = sys.argv[1] if len(sys.argv) > 1 else 'openflow'
+
+Class = classes.get(tool)
+
+if Class is None:
+    sys.exit('Unsupported tool')
+
+print(f'* Class Under Test: {Class.__name__}')
+
+try:
+    print('* Verilog Includes')
+    prj = Class()
+    prj.add_vlog('../../examples/sources/vlog/*.v')
+    prj.set_top('Top')
+    prj.add_define('DEFINE1', '1')
+    prj.add_define('DEFINE2', '1')
+    prj.add_param('FREQ', '1')
+    prj.add_param('SECS', '1')
+    prj.make()
+    sys.exit('* FAIL')
+except SystemExit:
+    raise
+except:
+    print('* PASS')
+
+try:
+    print('* Verilog Defines')
+    prj = Class()
+    prj.add_vlog('../../examples/sources/vlog/*.v')
+    prj.set_top('Top')
+    prj.add_include('../../examples/sources/vlog/include1')
+    prj.add_include('../../examples/sources/vlog/include2')
+    prj.add_param('FREQ', '1')
+    prj.add_param('SECS', '1')
+    prj.make()
+    sys.exit('* FAIL')
+except SystemExit:
+    raise
+except:
+    print('* PASS')
+
+try:
+    print('* Verilog Parameters')
+    prj = Class()
+    prj.add_vlog('../../examples/sources/vlog/*.v')
+    prj.set_top('Top')
+    prj.add_include('../../examples/sources/vlog/include1')
+    prj.add_include('../../examples/sources/vlog/include2')
+    prj.add_define('DEFINE1', '1')
+    prj.add_define('DEFINE2', '1')
+    prj.make()
+    sys.exit('* FAIL')
+except SystemExit:
+    raise
+except:
+    print('* PASS')
+
+print('* Verilog Support')
+prj = Class()
+prj.add_vlog('../../examples/sources/vlog/*.v')
+prj.set_top('Top')
+prj.add_include('../../examples/sources/vlog/include1')
+prj.add_include('../../examples/sources/vlog/include2')
+prj.add_define('DEFINE1', '1')
+prj.add_define('DEFINE2', '1')
+prj.add_param('FREQ', '1')
+prj.add_param('SECS', '1')
+prj.make()
+print('* PASS')
+
+if tool not in ['ise', 'openflow']:
+    print('* System Verilog Support')
+    prj = Class()
+    prj.add_vlog('../../examples/sources/slog/*.sv')
+    prj.set_top('Top')
+    prj.add_include('../../examples/sources/slog/include1')
+    prj.add_include('../../examples/sources/slog/include2')
+    prj.add_define('DEFINE1', '1')
+    prj.add_define('DEFINE2', '1')
+    prj.add_param('FREQ', '1')
+    prj.add_param('SECS', '1')
+    prj.make()
+    print('* PASS')
+
+if tool not in ['openflow']:
+    try:
+        print('* VHDL Generics')
+        prj = Class()
+        prj.add_vhdl('../../examples/sources/vhdl/*.vhdl', 'blink_lib')
+        prj.set_top('Top')
+        prj.make()
+        sys.exit('* FAIL')
+    except SystemExit:
+        raise
+    except:
+        print('* PASS')
+
+    print('* VHDL Support')
+    prj = Class()
+    prj.add_vhdl('../../examples/sources/vhdl/*.vhdl', 'blink_lib')
+    prj.set_top('Top')
+    prj.add_param('FREQ', '1')
+    prj.add_param('SECS', '1')
+    prj.make()
+    print('* PASS')
+
+print(f'* Class Under Test works as expected')

From d8eebcfd2d8b2d64956ed64a86d1dcc4a54b4bde Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 29 Jun 2024 22:33:41 -0300
Subject: [PATCH 122/248] Improve/simplify the generation of an intentional
 error

---
 examples/sources/slog/top.sv   | 55 +++++++++++-----------------------
 examples/sources/vhdl/top.vhdl |  8 +++--
 examples/sources/vlog/top.v    | 55 +++++++++++-----------------------
 3 files changed, 41 insertions(+), 77 deletions(-)

diff --git a/examples/sources/slog/top.sv b/examples/sources/slog/top.sv
index 4665011a..cfc700e3 100644
--- a/examples/sources/slog/top.sv
+++ b/examples/sources/slog/top.sv
@@ -9,47 +9,28 @@ module Top #(
   output led_o
 );
 
-  initial begin
-    if (!FREQ) begin
-      $stop("FREQ not set");
-      $error("FREQ not set");
-      $fatal("FREQ not set");
-    end
-    if (!SECS) begin
-      $stop("SECS not set");
-      $error("SECS not set");
-      $fatal("SECS not set");
-    end
-    `ifndef INCLUDE1
-      $stop("INCLUDE1 not defined");
-      $error("INCLUDE1 not defined");
-      $fatal("INCLUDE1 not defined");
-    `endif
-    `ifndef INCLUDE2
-      $stop("INCLUDE2 not defined");
-      $error("INCLUDE2 not defined");
-      $fatal("INCLUDE2 not defined");
-    `endif
-    `ifndef DEFINE1
-      $stop("DEFINE1 not defined");
-      $error("DEFINE1 not defined");
-      $fatal("DEFINE1 not defined");
-    `endif
-    `ifndef DEFINE2
-      $stop("DEFINE2 not defined");
-      $error("DEFINE2 not defined");
-      $fatal("DEFINE2 not defined");
-    `endif
-  end
-
-`ifdef INCLUDE1
-`ifdef INCLUDE2
-`ifdef DEFINE1
-`ifdef DEFINE2
   Blink #(.FREQ (FREQ), .SECS (SECS)) dut (.clk_i (clk_i), .led_o (led_o));
+
+`ifndef INCLUDE1
+  Top Top (.clk_i (clk_i), .led_o (led_o));
 `endif
+
+`ifndef INCLUDE2
+  Top Top (.clk_i (clk_i), .led_o (led_o));
 `endif
+
+`ifndef DEFINE1
+  Top Top (.clk_i (clk_i), .led_o (led_o));
 `endif
+
+`ifndef DEFINE2
+  Top Top (.clk_i (clk_i), .led_o (led_o));
 `endif
 
+  generate
+    if (!FREQ || !SECS) begin: gen_error
+      Top Top (.clk_i (clk_i), .led_o (led_o));
+    end
+  endgenerate
+
 endmodule
diff --git a/examples/sources/vhdl/top.vhdl b/examples/sources/vhdl/top.vhdl
index 24977d6c..c6537185 100644
--- a/examples/sources/vhdl/top.vhdl
+++ b/examples/sources/vhdl/top.vhdl
@@ -17,11 +17,13 @@ end entity Top;
 architecture ARCH of Top is
 begin
 
-  assert FREQ > 0 report "FREQ not set" severity failure;
-  assert SECS > 0 report "SECS not set" severity failure;
-
   blink_i: Blink
   generic map (FREQ => FREQ, SECS => SECS)
   port map (clk_i => clk_i, led_o => led_o);
 
+  gen_error : if FREQ=0 or SECS=0 generate
+    top_i: entity work.Top
+    port map (clk_i => clk_i, led_o => led_o);
+  end generate gen_error;
+
 end architecture ARCH;
diff --git a/examples/sources/vlog/top.v b/examples/sources/vlog/top.v
index fb6dff0b..f47433ba 100644
--- a/examples/sources/vlog/top.v
+++ b/examples/sources/vlog/top.v
@@ -9,47 +9,28 @@ module Top #(
   output led_o
 );
 
-  initial begin
-    if (!FREQ) begin
-      $stop("FREQ not set");
-      $error("FREQ not set");
-      $fatal("FREQ not set");
-    end
-    if (!SECS) begin
-      $stop("SECS not set");
-      $error("SECS not set");
-      $fatal("SECS not set");
-    end
-    `ifndef INCLUDE1
-      $stop("INCLUDE1 not defined");
-      $error("INCLUDE1 not defined");
-      $fatal("INCLUDE1 not defined");
-    `endif
-    `ifndef INCLUDE2
-      $stop("INCLUDE2 not defined");
-      $error("INCLUDE2 not defined");
-      $fatal("INCLUDE2 not defined");
-    `endif
-    `ifndef DEFINE1
-      $stop("DEFINE1 not defined");
-      $error("DEFINE1 not defined");
-      $fatal("DEFINE1 not defined");
-    `endif
-    `ifndef DEFINE2
-      $stop("DEFINE2 not defined");
-      $error("DEFINE2 not defined");
-      $fatal("DEFINE2 not defined");
-    `endif
-  end
-
-`ifdef INCLUDE1
-`ifdef INCLUDE2
-`ifdef DEFINE1
-`ifdef DEFINE2
   Blink #(.FREQ (FREQ), .SECS (SECS)) dut (.clk_i (clk_i), .led_o (led_o));
+
+`ifndef INCLUDE1
+  Top Top (.clk_i (clk_i), .led_o (led_o));
 `endif
+
+`ifndef INCLUDE2
+  Top Top (.clk_i (clk_i), .led_o (led_o));
 `endif
+
+`ifndef DEFINE1
+  Top Top (.clk_i (clk_i), .led_o (led_o));
 `endif
+
+`ifndef DEFINE2
+  Top Top (.clk_i (clk_i), .led_o (led_o));
 `endif
 
+  generate
+    if (!FREQ || !SECS) begin: gen_error
+      Top Top (.clk_i (clk_i), .led_o (led_o));
+    end
+  endgenerate
+
 endmodule

From 032a8e171a8d7cbf816601230b4d652e3ad86163 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 29 Jun 2024 22:34:34 -0300
Subject: [PATCH 123/248] Fix VHDL libraries support for ISE

---
 pyfpga/ise.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pyfpga/ise.py b/pyfpga/ise.py
index 370c80ce..6109742d 100644
--- a/pyfpga/ise.py
+++ b/pyfpga/ise.py
@@ -40,7 +40,7 @@ def _make_prepare(self, steps):
         files = []
         if 'files' in self.data:
             for file in self.data['files']:
-                if 'lib' in self.data['files']:
+                if 'lib' in self.data['files'][file]:
                     lib = self.data['files'][file]['lib']
                     files.append(f'lib_vhdl new {lib}')
                     files.append(f'xfile add {file} -lib_vhdl {lib}')

From c072eafad1caa60039a86d897888cc5b8664111e Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 29 Jun 2024 22:36:35 -0300
Subject: [PATCH 124/248] Improve/simplify the test to verify support

---
 tests/projects/support.py | 49 ++++++++++++++++++---------------------
 1 file changed, 23 insertions(+), 26 deletions(-)

diff --git a/tests/projects/support.py b/tests/projects/support.py
index 3b529f14..99ec3cb7 100644
--- a/tests/projects/support.py
+++ b/tests/projects/support.py
@@ -24,10 +24,10 @@
 if Class is None:
     sys.exit('Unsupported tool')
 
-print(f'* Class Under Test: {Class.__name__}')
+print(f'INFO: the Class Under Test is {Class.__name__}')
 
 try:
-    print('* Verilog Includes')
+    print('INFO: checking Verilog Includes')
     prj = Class()
     prj.add_vlog('../../examples/sources/vlog/*.v')
     prj.set_top('Top')
@@ -35,15 +35,15 @@
     prj.add_define('DEFINE2', '1')
     prj.add_param('FREQ', '1')
     prj.add_param('SECS', '1')
-    prj.make()
-    sys.exit('* FAIL')
+    prj.make(last='syn')
+    sys.exit('ERROR: something does not work as expected')
 except SystemExit:
     raise
 except:
-    print('* PASS')
+    pass
 
 try:
-    print('* Verilog Defines')
+    print('INFO: checking Verilog Defines')
     prj = Class()
     prj.add_vlog('../../examples/sources/vlog/*.v')
     prj.set_top('Top')
@@ -51,15 +51,15 @@
     prj.add_include('../../examples/sources/vlog/include2')
     prj.add_param('FREQ', '1')
     prj.add_param('SECS', '1')
-    prj.make()
-    sys.exit('* FAIL')
+    prj.make(last='syn')
+    sys.exit('ERROR: something does not work as expected')
 except SystemExit:
     raise
 except:
-    print('* PASS')
+    pass
 
 try:
-    print('* Verilog Parameters')
+    print('INFO: checking Verilog Parameters')
     prj = Class()
     prj.add_vlog('../../examples/sources/vlog/*.v')
     prj.set_top('Top')
@@ -67,14 +67,14 @@
     prj.add_include('../../examples/sources/vlog/include2')
     prj.add_define('DEFINE1', '1')
     prj.add_define('DEFINE2', '1')
-    prj.make()
-    sys.exit('* FAIL')
+    prj.make(last='syn')
+    sys.exit('ERROR: something does not work as expected')
 except SystemExit:
     raise
 except:
-    print('* PASS')
+    pass
 
-print('* Verilog Support')
+print('INFO: checking Verilog Support')
 prj = Class()
 prj.add_vlog('../../examples/sources/vlog/*.v')
 prj.set_top('Top')
@@ -84,11 +84,10 @@
 prj.add_define('DEFINE2', '1')
 prj.add_param('FREQ', '1')
 prj.add_param('SECS', '1')
-prj.make()
-print('* PASS')
+prj.make(last='syn')
 
 if tool not in ['ise', 'openflow']:
-    print('* System Verilog Support')
+    print('INFO: checking System Verilog Support')
     prj = Class()
     prj.add_vlog('../../examples/sources/slog/*.sv')
     prj.set_top('Top')
@@ -98,21 +97,20 @@
     prj.add_define('DEFINE2', '1')
     prj.add_param('FREQ', '1')
     prj.add_param('SECS', '1')
-    prj.make()
-    print('* PASS')
+    prj.make(last='syn')
 
 if tool not in ['openflow']:
     try:
-        print('* VHDL Generics')
+        print('INFO: checking VHDL Generics')
         prj = Class()
         prj.add_vhdl('../../examples/sources/vhdl/*.vhdl', 'blink_lib')
         prj.set_top('Top')
-        prj.make()
-        sys.exit('* FAIL')
+        prj.make(last='syn')
+        sys.exit('ERROR: something does not work as expected')
     except SystemExit:
         raise
     except:
-        print('* PASS')
+        pass
 
     print('* VHDL Support')
     prj = Class()
@@ -120,7 +118,6 @@
     prj.set_top('Top')
     prj.add_param('FREQ', '1')
     prj.add_param('SECS', '1')
-    prj.make()
-    print('* PASS')
+    prj.make(last='syn')
 
-print(f'* Class Under Test works as expected')
+print(f'INFO: Class Under Test works as expected')

From f403d88826cf25fd131dfe997d1857e8e34af638 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 29 Jun 2024 22:37:11 -0300
Subject: [PATCH 125/248] Add a script to run the ISE examples

---
 examples/ise/run.sh      | 13 +++++++++++++
 examples/openflow/run.sh |  7 ++-----
 examples/vivado/run.sh   |  7 ++-----
 3 files changed, 17 insertions(+), 10 deletions(-)
 create mode 100644 examples/ise/run.sh

diff --git a/examples/ise/run.sh b/examples/ise/run.sh
new file mode 100644
index 00000000..c13ee1c0
--- /dev/null
+++ b/examples/ise/run.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+set -e
+
+BOARDS=("s6micro" "nexys3")
+SOURCES=("vlog" "vhdl")
+
+for BOARD in "${BOARDS[@]}"; do
+  for SOURCE in "${SOURCES[@]}"; do
+    echo "> $BOARD - $SOURCE"
+    python3 run.py --board $BOARD --source $SOURCE
+  done
+done
diff --git a/examples/openflow/run.sh b/examples/openflow/run.sh
index 4e213f40..986538d5 100644
--- a/examples/openflow/run.sh
+++ b/examples/openflow/run.sh
@@ -4,13 +4,10 @@ set -e
 
 BOARDS=("icestick" "edu-ciaa" "orangecrab" "ecp5evn")
 SOURCES=("vlog" "vhdl" "slog")
-ACTIONS=("make" "prog" "all")
 
 for BOARD in "${BOARDS[@]}"; do
   for SOURCE in "${SOURCES[@]}"; do
-    for ACTION in "${ACTIONS[@]}"; do
-      echo "> $BOARD - $SOURCE - $ACTION"
-      python3 run.py --board $BOARD --source $SOURCE --action $ACTION
-    done
+    echo "> $BOARD - $SOURCE"
+    python3 run.py --board $BOARD --source $SOURCE
   done
 done
diff --git a/examples/vivado/run.sh b/examples/vivado/run.sh
index bd894b91..3b6a065a 100644
--- a/examples/vivado/run.sh
+++ b/examples/vivado/run.sh
@@ -4,13 +4,10 @@ set -e
 
 BOARDS=("zybo" "arty")
 SOURCES=("vlog" "vhdl" "slog")
-ACTIONS=("make" "prog" "all")
 
 for BOARD in "${BOARDS[@]}"; do
   for SOURCE in "${SOURCES[@]}"; do
-    for ACTION in "${ACTIONS[@]}"; do
-      echo "> $BOARD - $SOURCE - $ACTION"
-      python3 run.py --board $BOARD --source $SOURCE --action $ACTION
-    done
+    echo "> $BOARD - $SOURCE"
+    python3 run.py --board $BOARD --source $SOURCE
   done
 done

From f027f228968188289861fce8945ba2b2685efb2d Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 29 Jun 2024 22:39:53 -0300
Subject: [PATCH 126/248] Fix pylint complaint

---
 tests/projects/support.py | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/tests/projects/support.py b/tests/projects/support.py
index 99ec3cb7..358cb8ae 100644
--- a/tests/projects/support.py
+++ b/tests/projects/support.py
@@ -39,7 +39,7 @@
     sys.exit('ERROR: something does not work as expected')
 except SystemExit:
     raise
-except:
+except Exception:
     pass
 
 try:
@@ -55,7 +55,7 @@
     sys.exit('ERROR: something does not work as expected')
 except SystemExit:
     raise
-except:
+except Exception:
     pass
 
 try:
@@ -71,7 +71,7 @@
     sys.exit('ERROR: something does not work as expected')
 except SystemExit:
     raise
-except:
+except Exception:
     pass
 
 print('INFO: checking Verilog Support')
@@ -109,7 +109,7 @@
         sys.exit('ERROR: something does not work as expected')
     except SystemExit:
         raise
-    except:
+    except Exception:
         pass
 
     print('* VHDL Support')

From daf7f7ca82ee48d01179dd44f136db7a3beea21a Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 30 Jun 2024 14:38:48 -0300
Subject: [PATCH 127/248] Add checking of success to force an error if not

---
 pyfpga/templates/vivado.jinja | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/pyfpga/templates/vivado.jinja b/pyfpga/templates/vivado.jinja
index 2c593f69..8f0cbb8e 100644
--- a/pyfpga/templates/vivado.jinja
+++ b/pyfpga/templates/vivado.jinja
@@ -50,6 +50,8 @@ open_project {{ PROJECT }}
 reset_run synth_1
 launch_runs synth_1
 wait_on_run synth_1
+#report_property [get_runs synth_1]
+if { [get_property STATUS [get_runs synth_1]] ne "synth_design Complete!" } { exit 1 }
 
 {{ POSTSYN }}
 {% endif %}
@@ -60,6 +62,8 @@ wait_on_run synth_1
 reset_run impl_1
 launch_runs impl_1
 wait_on_run impl_1
+#report_property [get_runs impl_1]
+if { [get_property STATUS [get_runs impl_1]] ne "route_design Complete!" } { exit 1 }
 
 {{ POSTPAR }}
 {% endif %}

From 23a89d720f6b0b91cb42a9de60635493f8262b76 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 30 Jun 2024 15:10:05 -0300
Subject: [PATCH 128/248] Modified default part

---
 pyfpga/quartus.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pyfpga/quartus.py b/pyfpga/quartus.py
index fda50647..fec1e25b 100644
--- a/pyfpga/quartus.py
+++ b/pyfpga/quartus.py
@@ -21,7 +21,7 @@ class Quartus(Project):
     def _make_prepare(self, steps):
         context = {
             'PROJECT': self.name or 'quartus',
-            'PART': self.data.get('part', '10cl120zf780i8g')
+            'PART': self.data.get('part', '10M50SCE144I7G')
         }
         for step in steps:
             context[step] = 1

From b26ac58a3155c39888c360a16451ff4b83df6e47 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 30 Jun 2024 15:10:22 -0300
Subject: [PATCH 129/248] Fix SystemVerilog test

---
 tests/projects/support.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/projects/support.py b/tests/projects/support.py
index 358cb8ae..4ce15596 100644
--- a/tests/projects/support.py
+++ b/tests/projects/support.py
@@ -89,7 +89,7 @@
 if tool not in ['ise', 'openflow']:
     print('INFO: checking System Verilog Support')
     prj = Class()
-    prj.add_vlog('../../examples/sources/slog/*.sv')
+    prj.add_slog('../../examples/sources/slog/*.sv')
     prj.set_top('Top')
     prj.add_include('../../examples/sources/slog/include1')
     prj.add_include('../../examples/sources/slog/include2')

From 063c5bb9e07dfc3c69f33897ab31fd2658c9e8d2 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 30 Jun 2024 15:25:39 -0300
Subject: [PATCH 130/248] Fix Vivado mock-up after last changes on the Vivado
 template

---
 tests/mocks/vivado | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/tests/mocks/vivado b/tests/mocks/vivado
index f6a47eff..fb59d819 100755
--- a/tests/mocks/vivado
+++ b/tests/mocks/vivado
@@ -42,6 +42,21 @@ tool = parser.prog
 tcl = f'''
 proc unknown args {{ }}
 
+proc get_runs {{run_name}} {{
+  return $run_name
+}}
+
+proc get_property {{property run}} {{
+  if {{ $property eq "STATUS" }} {{
+    if {{ $run eq "synth_1" }} {{
+      return "synth_design Complete!"
+    }} elseif {{ $run eq "impl_1" }} {{
+      return "route_design Complete!"
+    }}
+  }}
+  return ""
+}}
+
 source {args.source}
 '''
 

From 73417f832a950ff1bac77409af97099e8a524dd5 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 30 Jun 2024 20:03:36 -0300
Subject: [PATCH 131/248] Clean-up

---
 pyfpga/ise.py                       | 17 +--------
 pyfpga/libero.py                    | 57 ++++++++++++++++++++++++++---
 pyfpga/openflow.py                  | 43 +++++++---------------
 pyfpga/project.py                   |  2 -
 pyfpga/quartus.py                   | 27 +++-----------
 pyfpga/templates/quartus-prog.jinja |  8 +++-
 pyfpga/vivado.py                    |  5 +--
 7 files changed, 81 insertions(+), 78 deletions(-)

diff --git a/pyfpga/ise.py b/pyfpga/ise.py
index 6109742d..a964af7c 100644
--- a/pyfpga/ise.py
+++ b/pyfpga/ise.py
@@ -14,7 +14,6 @@
 
 import re
 
-from pathlib import Path
 from pyfpga.project import Project
 
 
@@ -77,7 +76,7 @@ def _make_prepare(self, steps):
     def _prog_prepare(self, bitstream, position):
         if not bitstream:
             basename = self.name or 'ise'
-            bitstream = Path(self.odir).resolve() / f'{basename}.bit'
+            bitstream = f'{basename}.bit'
         context = {'BITSTREAM': bitstream, 'POSITION': position}
         self._create_file('vivado-prog', 'tcl', context)
         return 'impact -batch impact-prog'
@@ -86,20 +85,6 @@ def add_slog(self, pathname):
         """Add System Verilog file/s."""
         raise NotImplementedError('ISE does not support SystemVerilog')
 
-#     _DEVTYPES = ['fpga', 'spi', 'bpi', 'detect', 'unlock']
-
-#     def transfer(self, devtype, position, part, width, capture):
-#         super().transfer(devtype, position, part, width, capture)
-#         temp = _TEMPLATES[devtype]
-#         if devtype not in ['detect', 'unlock']:
-#             temp = temp.replace('#BITSTREAM#', self.bitstream)
-#             temp = temp.replace('#POSITION#', str(position))
-#             temp = temp.replace('#NAME#', part)
-#             temp = temp.replace('#WIDTH#', str(width))
-#         with open('ise-prog.impact', 'w', encoding='utf-8') as file:
-#             file.write(temp)
-#         return run(self._TRF_COMMAND, capture)
-
 
 def get_info(part):
     """Get info about the FPGA part.
diff --git a/pyfpga/libero.py b/pyfpga/libero.py
index 5cf8efe4..1d0dc983 100644
--- a/pyfpga/libero.py
+++ b/pyfpga/libero.py
@@ -20,13 +20,58 @@
 class Libero(Project):
     """Class to support Libero."""
 
-    def __init__(self, name='libero', odir='results'):
-        super().__init__(name=name, odir=odir)
-        self.set_part('mpf100t-1-fcg484')
-
     def _make_prepare(self, steps):
-        self.tool['make-app'] = 'libero'
-        self.tool['make-cmd'] = 'libero SCRIPT:libero.tcl'
+        info = get_info(self.data.get('part', 'mpf100t-1-fcg484'))
+        context = {
+            'PROJECT': self.name or 'ise',
+            'FAMILY': info['family'],
+            'DEVICE': info['device'],
+            'SPEED': info['speed'],
+            'PACKAGE': info['package']
+        }
+        for step in steps:
+            context[step] = 1
+        if 'includes' in self.data:
+            includes = []
+            for include in self.data['includes']:
+                includes.append(str(include))
+            context['INCLUDES'] = '|'.join(includes)
+        files = []
+        if 'files' in self.data:
+            for file in self.data['files']:
+                if 'lib' in self.data['files'][file]:
+                    lib = self.data['files'][file]['lib']
+                    files.append(f'lib_vhdl new {lib}')
+                    files.append(f'xfile add {file} -lib_vhdl {lib}')
+                else:
+                    files.append(f'xfile add {file}')
+        if 'constraints' in self.data:
+            constraints = []
+            for file in self.data['constraints']:
+                files.append(f'xfile add {file}')
+                if file.suffix == '.xcf':
+                    constraints.append(str(file))
+            if constraints:
+                context['CONSTRAINTS'] = " ".join(constraints)
+        if files:
+            context['FILES'] = '\n'.join(files)
+        if 'top' in self.data:
+            context['TOP'] = self.data['top']
+        if 'defines' in self.data:
+            defines = []
+            for key, value in self.data['defines'].items():
+                defines.append(f'{key}={value}')
+            context['DEFINES'] = ' | '.join(defines)
+        if 'params' in self.data:
+            params = []
+            for key, value in self.data['params'].items():
+                params.append(f'{key}={value}')
+            context['PARAMS'] = ' '.join(params)
+        if 'hooks' in self.data:
+            for stage in self.data['hooks']:
+                context[stage.upper()] = '\n'.join(self.data['hooks'][stage])
+        self._create_file('ise', 'tcl', context)
+        return 'libero SCRIPT:libero.tcl'
 
     def _prog_prepare(self, bitstream, position):
         raise NotImplementedError('Libero programming not supported')
diff --git a/pyfpga/openflow.py b/pyfpga/openflow.py
index 8b40b259..51dcd84a 100644
--- a/pyfpga/openflow.py
+++ b/pyfpga/openflow.py
@@ -12,7 +12,6 @@
 # pylint: disable=too-many-branches
 # pylint: disable=duplicate-code
 
-from pathlib import Path
 from pyfpga.project import Project
 
 
@@ -40,12 +39,18 @@ def _make_prepare(self, steps):
                 files.append(f'read_verilog -defer {file}')
         if files:
             context['VLOGS'] = '\n'.join(files)
-#            for file in self.data['files']:
-#                if 'lib' in self.data['files'][file]:
-#                    lib = self.data['files'][file]['lib']
-#                    files.append(
-#                        f'set_property library {lib} [get_files {file}]'
-#                    )
+#         for file in self.files['vhdl']:
+#             lib = ''
+#             if file[1] is not None:
+#                 lib = f'--work={file[1]}'
+#             vhdls.append(f'{self.tools["ghdl"]} -a $FLAGS {lib} {file[0]}')
+#         for file in self.files['verilog']:
+#             if file[0].endswith('.sv'):
+#                 verilogs.append(f'read_verilog -sv -defer {file[0]}')
+#             else:
+#                 verilogs.append(f'read_verilog -defer {file[0]}')
+#         if len(vhdls) > 0:
+#             verilogs = [f'ghdl $FLAGS {self.top}']
         if 'constraints' in self.data:
             constraints = []
             for constraint in self.data['constraints']:
@@ -70,34 +75,14 @@ def _make_prepare(self, steps):
         return 'bash openflow.sh'
 
     def _prog_prepare(self, bitstream, position):
-        _ = position
+        _ = position  # Not needed
         if not bitstream:
             basename = self.name or 'openflow'
-            bitstream = Path(self.odir).resolve() / f'{basename}.bit'
+            bitstream = f'{basename}.bit'
         context = {'BITSTREAM': bitstream}
         self._create_file('openflow-prog', 'sh', context)
         return 'bash openflow-prog.sh'
 
-#     def _create_gen_script(self, tasks):
-#         # Files
-#         constraints = []
-#         verilogs = []
-#         vhdls = []
-#         for file in self.files['vhdl']:
-#             lib = ''
-#             if file[1] is not None:
-#                 lib = f'--work={file[1]}'
-#             vhdls.append(f'{self.tools["ghdl"]} -a $FLAGS {lib} {file[0]}')
-#         for file in self.files['verilog']:
-#             if file[0].endswith('.sv'):
-#                 verilogs.append(f'read_verilog -sv -defer {file[0]}')
-#             else:
-#                 verilogs.append(f'read_verilog -defer {file[0]}')
-#         for file in self.files['constraint']:
-#             constraints.append(file[0])
-#         if len(vhdls) > 0:
-#             verilogs = [f'ghdl $FLAGS {self.top}']
-
 
 def get_info(part):
     """Get info about the FPGA part.
diff --git a/pyfpga/project.py b/pyfpga/project.py
index b9192c03..b77b8159 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -27,8 +27,6 @@ class Project:
     :type odir: str, optional
     """
 
-    tool = {}
-
     def __init__(self, name=None, odir='results'):
         """Class constructor."""
         self.data = {}
diff --git a/pyfpga/quartus.py b/pyfpga/quartus.py
index fec1e25b..417a497a 100644
--- a/pyfpga/quartus.py
+++ b/pyfpga/quartus.py
@@ -73,26 +73,11 @@ def _make_prepare(self, steps):
         return 'quartus_sh --script quartus.tcl'
 
     def _prog_prepare(self, bitstream, position):
-        # binaries = ['sof', 'pof']
-        _ = position  # Not needed for Vivado
-        # if not bitstream:
-        #     basename = self.name or 'quartus'
-        #     bitstream = Path(self.odir).resolve() / f'{basename}.bit'
-        context = {'BITSTREAM': bitstream}
+        # sof: SRAM Object File
+        # pof: Programming Object File
+        if not bitstream:
+            basename = self.name or 'quartus'
+            bitstream = f'{basename}.sof'
+        context = {'BITSTREAM': bitstream, 'POSITION': position}
         self._create_file('quartus-prog', 'tcl', context)
         return 'bash quartus-prog.sh'
-
-#     def transfer(self, devtype, position, part, width, capture):
-#         super().transfer(devtype, position, part, width, capture)
-#         result = subprocess.run(
-#             'jtagconfig', shell=True, check=True,
-#             stdout=subprocess.PIPE, universal_newlines=True
-#         )
-#         result = result.stdout
-#         if devtype == 'detect':
-#             print(result)
-#         else:
-#             cable = re.match(r"1\) (.*) \[", result).groups()[0]
-#             cmd = self._TRF_COMMAND % (cable, self.bitstream, position)
-#             result = run(cmd, capture)
-#         return result
diff --git a/pyfpga/templates/quartus-prog.jinja b/pyfpga/templates/quartus-prog.jinja
index d754fee5..62839a6b 100644
--- a/pyfpga/templates/quartus-prog.jinja
+++ b/pyfpga/templates/quartus-prog.jinja
@@ -4,4 +4,10 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-quartus_pgm -c {{ CABLE }} --mode jtag -o "p;{{ BITSTREAM }}@{{ POSITION }}"
+RESULT=$(jtagconfig)
+echo "$RESULT"
+
+# cable = re.match(r"1\) (.*) \[", result).groups()[0]
+CABLE=$(echo "$RESULT" | awk -F '1\\) | \\[' '/1\)/ {print $2}')
+
+quartus_pgm -c $CABLE --mode jtag -o "p;{{ BITSTREAM }}@{{ POSITION }}"
diff --git a/pyfpga/vivado.py b/pyfpga/vivado.py
index c0a625e6..1858ed82 100644
--- a/pyfpga/vivado.py
+++ b/pyfpga/vivado.py
@@ -11,7 +11,6 @@
 # pylint: disable=too-many-locals
 # pylint: disable=too-many-branches
 
-from pathlib import Path
 from pyfpga.project import Project
 
 
@@ -74,10 +73,10 @@ def _make_prepare(self, steps):
         return 'vivado -mode batch -notrace -quiet -source vivado.tcl'
 
     def _prog_prepare(self, bitstream, position):
-        _ = position  # Not needed for Vivado
+        _ = position  # Not needed
         if not bitstream:
             basename = self.name or 'vivado'
-            bitstream = Path(self.odir).resolve() / f'{basename}.bit'
+            bitstream = f'{basename}.bit'
         context = {'BITSTREAM': bitstream}
         self._create_file('vivado-prog', 'tcl', context)
         return 'vivado -mode batch -notrace -quiet -source vivado-prog.tcl'

From 030b335ddb24e759b420b67ce1a00884a36bd825 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 30 Jun 2024 23:14:40 -0300
Subject: [PATCH 132/248] Re-added support for Libero (WIP)

---
 examples/libero/libero.py     |  32 --------
 examples/libero/run.py        |  45 +++++++++++
 pyfpga/libero.py              |  22 ++---
 pyfpga/templates/libero.jinja | 148 ++++++++++++++--------------------
 4 files changed, 116 insertions(+), 131 deletions(-)
 delete mode 100644 examples/libero/libero.py
 create mode 100644 examples/libero/run.py

diff --git a/examples/libero/libero.py b/examples/libero/libero.py
deleted file mode 100644
index 32ef38a5..00000000
--- a/examples/libero/libero.py
+++ /dev/null
@@ -1,32 +0,0 @@
-"""Libero example project."""
-
-import argparse
-import logging
-
-from fpga.project import Project
-
-logging.basicConfig()
-
-parser = argparse.ArgumentParser()
-parser.add_argument(
-    '--action', choices=['generate', 'transfer', 'all'], default='generate',
-)
-args = parser.parse_args()
-
-prj = Project('libero')
-prj.set_part('m2s010-1-tq144')
-
-prj.set_outdir('../../build/libero')
-
-prj.add_files('../../hdl/blinking.vhdl', library='examples')
-prj.add_files('../../hdl/examples_pkg.vhdl', library='examples')
-prj.add_files('../../hdl/top.vhdl')
-prj.set_top('Top')
-prj.add_files('mkr.pdc')
-prj.add_files('mkr.sdc')
-
-if args.action in ['generate', 'all']:
-    prj.generate()
-
-if args.action in ['transfer', 'all']:
-    print('ERROR:transfer:Not yet implemented')
diff --git a/examples/libero/run.py b/examples/libero/run.py
new file mode 100644
index 00000000..87e9dc06
--- /dev/null
+++ b/examples/libero/run.py
@@ -0,0 +1,45 @@
+"""Libero examples."""
+
+import argparse
+
+from pyfpga.libero import Libero
+
+parser = argparse.ArgumentParser()
+parser.add_argument(
+    '--source', choices=['vlog', 'vhdl', 'slog'], default='vlog'
+)
+parser.add_argument(
+    '--action', choices=['make', 'prog', 'all'], default='make'
+)
+args = parser.parse_args()
+
+prj = Libero(odir='../build/libero')
+
+prj.set_part('m2s010-1-tq144')
+prj.add_param('FREQ', '125000000')
+prj.add_cons('../sources/maker-board/clk.sdc', 'syn')
+prj.add_cons('../sources/maker-board/clk.pdc', 'par')
+prj.add_cons('../sources/maker-board/led.pdc', 'par')
+prj.add_param('SECS', '1')
+
+if args.source == 'vhdl':
+    prj.add_vhdl('../sources/vhdl/*.vhdl', 'blink_lib')
+if args.source == 'vlog':
+    prj.add_include('../sources/vlog/include1')
+    prj.add_include('../sources/vlog/include2')
+    prj.add_vlog('../sources/vlog/*.v')
+if args.source == 'slog':
+    prj.add_include('../sources/slog/include1')
+    prj.add_include('../sources/slog/include2')
+    prj.add_vlog('../sources/slog/*.sv')
+if args.source in ['vlog', 'slog']:
+    prj.add_define('DEFINE1', '1')
+    prj.add_define('DEFINE2', '1')
+
+prj.set_top('Top')
+
+if args.action in ['make', 'all']:
+    prj.make()
+
+if args.action in ['prog', 'all']:
+    prj.prog()
diff --git a/pyfpga/libero.py b/pyfpga/libero.py
index 1d0dc983..29fc471a 100644
--- a/pyfpga/libero.py
+++ b/pyfpga/libero.py
@@ -23,7 +23,7 @@ class Libero(Project):
     def _make_prepare(self, steps):
         info = get_info(self.data.get('part', 'mpf100t-1-fcg484'))
         context = {
-            'PROJECT': self.name or 'ise',
+            'PROJECT': self.name or 'libero',
             'FAMILY': info['family'],
             'DEVICE': info['device'],
             'SPEED': info['speed'],
@@ -35,22 +35,24 @@ def _make_prepare(self, steps):
             includes = []
             for include in self.data['includes']:
                 includes.append(str(include))
-            context['INCLUDES'] = '|'.join(includes)
+            context['INCLUDES'] = ';'.join(includes)
         files = []
         if 'files' in self.data:
             for file in self.data['files']:
                 if 'lib' in self.data['files'][file]:
                     lib = self.data['files'][file]['lib']
-                    files.append(f'lib_vhdl new {lib}')
-                    files.append(f'xfile add {file} -lib_vhdl {lib}')
+                    files.append(
+                        f'create_links -library {lib} -hdl_source {file}'
+                    )
                 else:
-                    files.append(f'xfile add {file}')
+                    files.append(f'create_links -hdl_source {file}')
         if 'constraints' in self.data:
             constraints = []
             for file in self.data['constraints']:
-                files.append(f'xfile add {file}')
-                if file.suffix == '.xcf':
-                    constraints.append(str(file))
+                if file.suffix == '.sdc':
+                    constraints.append(f'create_links -sdc {file}')
+                else:
+                    constraints.append(f'create_links -io_pdc {file}')
             if constraints:
                 context['CONSTRAINTS'] = " ".join(constraints)
         if files:
@@ -61,7 +63,7 @@ def _make_prepare(self, steps):
             defines = []
             for key, value in self.data['defines'].items():
                 defines.append(f'{key}={value}')
-            context['DEFINES'] = ' | '.join(defines)
+            context['DEFINES'] = ' '.join(defines)
         if 'params' in self.data:
             params = []
             for key, value in self.data['params'].items():
@@ -70,7 +72,7 @@ def _make_prepare(self, steps):
         if 'hooks' in self.data:
             for stage in self.data['hooks']:
                 context[stage.upper()] = '\n'.join(self.data['hooks'][stage])
-        self._create_file('ise', 'tcl', context)
+        self._create_file('libero', 'tcl', context)
         return 'libero SCRIPT:libero.tcl'
 
     def _prog_prepare(self, bitstream, position):
diff --git a/pyfpga/templates/libero.jinja b/pyfpga/templates/libero.jinja
index 1b230c2c..cc8af1e9 100644
--- a/pyfpga/templates/libero.jinja
+++ b/pyfpga/templates/libero.jinja
@@ -4,106 +4,76 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-set PROJECT  {{ PROJECT }}
-set PART     {{ PART }}
-set FAMILY   {{ FAMILY }}
-set DEVICE   {{ DEVICE }}
-set PACKAGE  {{ PACKAGE }}
-set SPEED    {{ SPEED }}
-set TOP      {{ TOP }}
-
-set PARAMS   [list {{ PARAMS }}]
-
-proc fpga_file {FILE {LIBRARY "work"}} {
-    set message "adding the file '$FILE'"
-    if { $LIBRARY != "work" } { append message " (into the VHDL library '$LIBRARY')" }
-    regexp -nocase {\.(\w*)$} $FILE -> ext
-    if { $ext == "tcl" } {
-        source $FILE
-        return
-    }
-    global LIBERO_PLACE_CONSTRAINTS
-    global LIBERO_OTHER_CONSTRAINTS
-    if {$ext == "pdc"} {
-        create_links -io_pdc $FILE
-        append LIBERO_PLACE_CONSTRAINTS "-file $FILE "
-    } elseif {$ext == "sdc"} {
-        create_links -sdc $FILE
-        append LIBERO_PLACE_CONSTRAINTS "-file $FILE "
-        append LIBERO_OTHER_CONSTRAINTS "-file $FILE "
-    } else {
-        create_links -library $LIBRARY -hdl_source $FILE
-        build_design_hierarchy
-    }
-}
-
-proc fpga_include {PATH} {
-    lappend INCLUDED $PATH
-    # Verilog Included Files are ALSO added
-    # They must be specified after set_root (see fpga_top)
-    foreach FILE [glob -nocomplain $PATH/*.vh] {
-        create_links -hdl_source $FILE
-    }
-    build_design_hierarchy
-}
-
-proc fpga_params {} {
-    if { [llength $PARAMS] == 0 } { return }
-    # They must be specified after set_root (see fpga_top)
-}
+#proc fpga_include {PATH} {
+#    lappend INCLUDED $PATH
+#    # Verilog Included Files are ALSO added
+#    # They must be specified after set_root (see fpga_top)
+#    foreach FILE [glob -nocomplain $PATH/*.vh] {
+#        create_links -hdl_source $FILE
+#    }
+#    build_design_hierarchy
+#}
 
 #--[ Project configuration ]---------------------------------------------------
 
 {% if CFG %}
-if { [ file exists $PROJECT ] } { file delete -force -- $PROJECT }
-new_project -name $PROJECT -location $PROJECT -hdl {VHDL} -family {SmartFusion2}
+if { [ file exists {{ PROJECT }} ] } { file delete -force -- {{ PROJECT }} }
+new_project -name {{ PROJECT }} -location . -hdl {VHDL} -family {SmartFusion2}
 
-set_device -family $FAMILY -die $DEVICE -package $PACKAGE -speed $SPEED
+set_device -family {{ FAMILY }} -die {{ DEVICE }} -package {{ PACKAGE }} -speed {{ SPEED }}
 
 {{ PRECFG }}
 
-fpga_files
-
-set_root $TOP
-# Verilog Included files
-set cmd "configure_tool -name {SYNTHESIZE} -params {SYNPLIFY_OPTIONS:"
-if { [info exists INCLUDED] && [llength $INCLUDED] > 0 } {
-    # See <ROOT>/poc/include/libero.tcl for details
-    set PATHS "../../"
-    append PATHS [join $INCLUDED ";../../"]
-    append cmd "set_option -include_path \"$PATHS\""
-    append cmd "\n"
-}
-foreach PARAM $PARAMS {
-    set assign [join $PARAM]
-    append cmd "set_option -hdl_param -set \"$assign\""
-    append cmd "\n"
+{{ FILES }}
+build_design_hierarchy
+
+{% if TOP %}
+set_root {{ TOP }}
+{% endif %}
+
+{% if INCLUDES or DEFINES or PARAMS %}
+configure_tool -name {SYNTHESIZE} -params {SYNPLIFY_OPTIONS:
+{% if INCLUDES %}  set_option -include_path "{{ INCLUDES }}"{% endif %}
+{% if DEFINES %}  set_option -hdl_define "{{ DEFINES }}"{% endif %}
+{% if PARAMS %}  set_option -hdl_param "{{ PARAMS }}"{% endif %}
 }
-append cmd "}"
-eval $cmd
+{% endif %}
+
 # Constraints
 # PDC is only used for PLACEROUTE.
 # SDC is used by ALL (SYNTHESIZE, PLACEROUTE and VERIFYTIMING).
-global LIBERO_PLACE_CONSTRAINTS
-global LIBERO_OTHER_CONSTRAINTS
-if { [info exists LIBERO_OTHER_CONSTRAINTS] } {
-    set cmd "organize_tool_files -tool {SYNTHESIZE} "
-    append cmd $LIBERO_OTHER_CONSTRAINTS
-    append cmd "-module $TOP -input_type {constraint}"
-    eval $cmd
-    set cmd "organize_tool_files -tool {VERIFYTIMING} "
-    append cmd $LIBERO_OTHER_CONSTRAINTS
-    append cmd "-module $TOP -input_type {constraint}"
-    eval $cmd
-}
-if { [info exists LIBERO_PLACE_CONSTRAINTS] } {
-    set cmd "organize_tool_files -tool {PLACEROUTE} "
-    append cmd $LIBERO_PLACE_CONSTRAINTS
-    append cmd "-module $TOP -input_type {constraint}"
-    eval $cmd
-}
-
-fpga_params
+#global LIBERO_PLACE_CONSTRAINTS
+#global LIBERO_OTHER_CONSTRAINTS
+#if { [info exists LIBERO_OTHER_CONSTRAINTS] } {
+#    set cmd "organize_tool_files -tool {SYNTHESIZE} "
+#    append cmd $LIBERO_OTHER_CONSTRAINTS
+#    append cmd "-module {{ TOP }} -input_type {constraint}"
+#    eval $cmd
+#    set cmd "organize_tool_files -tool {VERIFYTIMING} "
+#    append cmd $LIBERO_OTHER_CONSTRAINTS
+#    append cmd "-module {{ TOP }} -input_type {constraint}"
+#    eval $cmd
+#}
+#if { [info exists LIBERO_PLACE_CONSTRAINTS] } {
+#    set cmd "organize_tool_files -tool {PLACEROUTE} "
+#    append cmd $LIBERO_PLACE_CONSTRAINTS
+#    append cmd "-module {{ TOP }} -input_type {constraint}"
+#    eval $cmd
+#}
+
+#organize_tool_files -tool {SYNTHESIZE} \
+#  -file ../resources/constraints/maker-board/clk.sdc \
+#  -module Blink -input_type {constraint}
+
+#organize_tool_files -tool {PLACEROUTE} \
+#  -file ../resources/constraints/maker-board/clk.sdc \
+#  -file ../resources/constraints/maker-board/clk.pdc \
+#  -file ../resources/constraints/maker-board/led.pdc \
+#  -module Blink -input_type {constraint}
+
+#organize_tool_files -tool {VERIFYTIMING} \
+#  -file ../resources/constraints/maker-board/clk.sdc \
+#  -module Blink -input_type {constraint}
 
 {{ POSTCFG }}
 
@@ -113,7 +83,7 @@ close_project
 #--[ Design flow ]-------------------------------------------------------------
 
 {% if SYN or PAR or BIT %}
-open_project $PROJECT/$PROJECT.prjx
+open_project {{ PROJECT }}/{{ PROJECT }}.prjx
 
 {% if SYN %}
 {{ PRESYN }}

From 6ae7ce5f603e9a3f712d866e0b38d54da2a59e1a Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 1 Jul 2024 22:07:18 -0300
Subject: [PATCH 133/248] Fix quartus_sh mock-up

---
 tests/mocks/quartus_sh | 24 ++++++------------------
 1 file changed, 6 insertions(+), 18 deletions(-)

diff --git a/tests/mocks/quartus_sh b/tests/mocks/quartus_sh
index 64a8cf65..472f639f 100755
--- a/tests/mocks/quartus_sh
+++ b/tests/mocks/quartus_sh
@@ -20,30 +20,18 @@ args = parser.parse_args()
 tool = parser.prog
 
 tcl = f'''
-lappend auto_path pkg
-
 proc unknown args {{ }}
 
-source {args.script}
-'''
+package provide ::quartus::project 1.0
+namespace eval ::quartus::project {{ }}
 
-with open(f'{tool}-mock.tcl', 'w', encoding='utf-8') as file:
-    file.write(tcl)
+package provide ::quartus::flow 1.0
+namespace eval ::quartus::flow {{ }}
 
-tcl = f'''
-namespace eval ::quartus {{
-  namespace export project
-}}
+source {args.script}
 '''
 
-if not os.path.exists('pkg'):
-    os.makedirs('pkg')
-
-package ifneeded ::quartus 1.0 [list source quartus-pkg.tcl]
-
-pkgIndex.tcl
-
-with open(f'pkg/quartus.tcl', 'w', encoding='utf-8') as file:
+with open(f'{tool}-mock.tcl', 'w', encoding='utf-8') as file:
     file.write(tcl)
 
 subprocess.run(

From 4b8fe9eade9434042aaa5295b1061762e27fa835 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 1 Jul 2024 22:08:41 -0300
Subject: [PATCH 134/248] Fix ecp5 flow

---
 pyfpga/templates/openflow.jinja | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pyfpga/templates/openflow.jinja b/pyfpga/templates/openflow.jinja
index 971149be..f9b3ba05 100644
--- a/pyfpga/templates/openflow.jinja
+++ b/pyfpga/templates/openflow.jinja
@@ -98,7 +98,7 @@ icepack {{ PROJECT }}.asc {{ PROJECT }}.bit
 {% endif %}
 
 {% if FAMILY == 'ecp5' %}
-$DOCKER hdlc/icestorm /bin/bash -c "
+$DOCKER hdlc/prjtrellis /bin/bash -c "
 {{ PREBIT }}
 ecppack --svf {{ PROJECT }}.svf {{ PROJECT }}.config {{ PROJECT }}.bit
 {{ POSTBIT }}

From 4769fe29191af81156f57ee2548175d24df78e65 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 1 Jul 2024 22:10:25 -0300
Subject: [PATCH 135/248] Fix to abort if the bit file doesn't exists

---
 pyfpga/templates/ise.jinja | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/pyfpga/templates/ise.jinja b/pyfpga/templates/ise.jinja
index 024e0edb..701a028d 100644
--- a/pyfpga/templates/ise.jinja
+++ b/pyfpga/templates/ise.jinja
@@ -78,8 +78,7 @@ if { [process get "Place & Route" status] == "errors" } { exit 1 }
 
 process run "Generate Programming File"
 if { [process get "Generate Programming File" status] == "errors" } { exit 1 }
-# catch { file rename -force {{ TOP }}.bit {{ PROJECT }}.bit }
-file rename -force {{ TOP }}.bit {{ PROJECT }}.bit
+catch { file rename -force {{ TOP }}.bit {{ PROJECT }}.bit }
 
 {{ POSTBIT }}
 {% endif %}

From 17af7b689a0e80773e6f268691f29065a87f6033 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 1 Jul 2024 22:11:39 -0300
Subject: [PATCH 136/248] Merged several examples under the project directory

---
 examples/ise/run.sh                           | 13 ---------
 examples/openflow/run.sh                      | 13 ---------
 examples/{ise/run.py => projects/ise.py}      |  0
 .../{libero/run.py => projects/libero.py}     | 14 +++++----
 .../{openflow/run.py => projects/openflow.py} |  0
 .../{quartus/run.py => projects/quartus.py}   |  0
 examples/projects/regress.sh                  | 29 +++++++++++++++++++
 .../{vivado/run.py => projects/vivado.py}     |  0
 examples/vivado/run.sh                        | 13 ---------
 9 files changed, 38 insertions(+), 44 deletions(-)
 delete mode 100644 examples/ise/run.sh
 delete mode 100644 examples/openflow/run.sh
 rename examples/{ise/run.py => projects/ise.py} (100%)
 rename examples/{libero/run.py => projects/libero.py} (73%)
 rename examples/{openflow/run.py => projects/openflow.py} (100%)
 rename examples/{quartus/run.py => projects/quartus.py} (100%)
 create mode 100644 examples/projects/regress.sh
 rename examples/{vivado/run.py => projects/vivado.py} (100%)
 delete mode 100644 examples/vivado/run.sh

diff --git a/examples/ise/run.sh b/examples/ise/run.sh
deleted file mode 100644
index c13ee1c0..00000000
--- a/examples/ise/run.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-
-set -e
-
-BOARDS=("s6micro" "nexys3")
-SOURCES=("vlog" "vhdl")
-
-for BOARD in "${BOARDS[@]}"; do
-  for SOURCE in "${SOURCES[@]}"; do
-    echo "> $BOARD - $SOURCE"
-    python3 run.py --board $BOARD --source $SOURCE
-  done
-done
diff --git a/examples/openflow/run.sh b/examples/openflow/run.sh
deleted file mode 100644
index 986538d5..00000000
--- a/examples/openflow/run.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-
-set -e
-
-BOARDS=("icestick" "edu-ciaa" "orangecrab" "ecp5evn")
-SOURCES=("vlog" "vhdl" "slog")
-
-for BOARD in "${BOARDS[@]}"; do
-  for SOURCE in "${SOURCES[@]}"; do
-    echo "> $BOARD - $SOURCE"
-    python3 run.py --board $BOARD --source $SOURCE
-  done
-done
diff --git a/examples/ise/run.py b/examples/projects/ise.py
similarity index 100%
rename from examples/ise/run.py
rename to examples/projects/ise.py
diff --git a/examples/libero/run.py b/examples/projects/libero.py
similarity index 73%
rename from examples/libero/run.py
rename to examples/projects/libero.py
index 87e9dc06..9d2fc6da 100644
--- a/examples/libero/run.py
+++ b/examples/projects/libero.py
@@ -5,6 +5,9 @@
 from pyfpga.libero import Libero
 
 parser = argparse.ArgumentParser()
+parser.add_argument(
+    '--board', choices=['maker-board'], default='maker-board'
+)
 parser.add_argument(
     '--source', choices=['vlog', 'vhdl', 'slog'], default='vlog'
 )
@@ -15,11 +18,12 @@
 
 prj = Libero(odir='../build/libero')
 
-prj.set_part('m2s010-1-tq144')
-prj.add_param('FREQ', '125000000')
-prj.add_cons('../sources/maker-board/clk.sdc', 'syn')
-prj.add_cons('../sources/maker-board/clk.pdc', 'par')
-prj.add_cons('../sources/maker-board/led.pdc', 'par')
+if args.board == 'maker-board':
+    prj.set_part('m2s010-1-tq144')
+    prj.add_param('FREQ', '125000000')
+    prj.add_cons('../sources/maker-board/clk.sdc', 'syn')
+    prj.add_cons('../sources/maker-board/clk.pdc', 'par')
+    prj.add_cons('../sources/maker-board/led.pdc', 'par')
 prj.add_param('SECS', '1')
 
 if args.source == 'vhdl':
diff --git a/examples/openflow/run.py b/examples/projects/openflow.py
similarity index 100%
rename from examples/openflow/run.py
rename to examples/projects/openflow.py
diff --git a/examples/quartus/run.py b/examples/projects/quartus.py
similarity index 100%
rename from examples/quartus/run.py
rename to examples/projects/quartus.py
diff --git a/examples/projects/regress.sh b/examples/projects/regress.sh
new file mode 100644
index 00000000..f5513b3e
--- /dev/null
+++ b/examples/projects/regress.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+set -e
+
+declare -A TOOLS
+
+TOOLS["ise"]="s6micro nexys3"
+TOOLS["libero"]="maker-board"
+TOOLS["openflow"]="icestick edu-ciaa orangecrab ecp5evn"
+TOOLS["quartus"]="de10nano"
+TOOLS["vivado"]="zybo arty"
+
+SOURCES=("vlog" "vhdl" "slog")
+
+for TOOL in "${!TOOLS[@]}"; do
+  BOARDS=${TOOLS[$TOOL]}
+  for BOARD in $BOARDS; do
+    for SOURCE in "${SOURCES[@]}"; do
+      if [[ "$TOOL" == "ise" && "$SOURCE" == "slog" ]]; then
+        continue
+      fi
+      if [[ "$TOOL" == "openflow" && "$SOURCE" != "vlog" ]]; then
+        continue
+      fi
+      echo "> $TOOL - $BOARD - $SOURCE"
+      python3 $TOOL.py --board $BOARD --source $SOURCE
+    done
+  done
+done
diff --git a/examples/vivado/run.py b/examples/projects/vivado.py
similarity index 100%
rename from examples/vivado/run.py
rename to examples/projects/vivado.py
diff --git a/examples/vivado/run.sh b/examples/vivado/run.sh
deleted file mode 100644
index 3b6a065a..00000000
--- a/examples/vivado/run.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-
-set -e
-
-BOARDS=("zybo" "arty")
-SOURCES=("vlog" "vhdl" "slog")
-
-for BOARD in "${BOARDS[@]}"; do
-  for SOURCE in "${SOURCES[@]}"; do
-    echo "> $BOARD - $SOURCE"
-    python3 run.py --board $BOARD --source $SOURCE
-  done
-done

From bce2b2f23107a01285c367194121790851f17bd8 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 1 Jul 2024 22:17:50 -0300
Subject: [PATCH 137/248] Removed deprecated files/examples

---
 examples/Makefile            | 11 -------
 examples/configs.yml         | 26 ----------------
 examples/multi/memory.py     | 24 ---------------
 examples/multi/parameters.py | 44 --------------------------
 examples/multi/projects.py   | 60 ------------------------------------
 examples/multi/verilog.py    | 24 ---------------
 examples/multi/vhdl.py       | 21 -------------
 7 files changed, 210 deletions(-)
 delete mode 100644 examples/Makefile
 delete mode 100644 examples/configs.yml
 delete mode 100644 examples/multi/memory.py
 delete mode 100644 examples/multi/parameters.py
 delete mode 100644 examples/multi/projects.py
 delete mode 100644 examples/multi/verilog.py
 delete mode 100644 examples/multi/vhdl.py

diff --git a/examples/Makefile b/examples/Makefile
deleted file mode 100644
index 7bfe3fc4..00000000
--- a/examples/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/usr/bin/make
-
-ifdef MOCKS
-export PATH := $(PATH):$(PWD)/../test/mocks
-$(info INFO: using MOCKS for the vendor EDA tools)
-endif
-
-DIRS=$(wildcard */)
-
-all:
-	@$(foreach DIR, $(DIRS), make -C $(DIR) || exit;)
diff --git a/examples/configs.yml b/examples/configs.yml
deleted file mode 100644
index 9feaf6b7..00000000
--- a/examples/configs.yml
+++ /dev/null
@@ -1,26 +0,0 @@
-openflow:
-    oci:
-        engine:
-            command: docker
-            volumes: ["$HOME:$HOME"]
-            work: $PWD
-        containers:
-            ghdl: "ghdl/synth:beta"
-            yosys: "ghdl/synth:beta"
-            nextpnr-ice40: "ghdl/synth:nextpnr-ice40"
-            icetime: "ghdl/synth:icestorm"
-            icepack: "ghdl/synth:icestorm"
-            iceprog: "--device /dev/bus/usb ghdl/synth:prog"
-            nextpnr-ecp5: "ghdl/synth:nextpnr-ecp5"
-            ecppack: "ghdl/synth:trellis"
-            openocd: "--device /dev/bus/usb ghdl/synth:prog"
-    tools:
-        ghdl: ghdl
-        yosys: yosys
-        nextpnr-ice40: nextpnr-ice40
-        icetime: icetime
-        icepack: icepack
-        iceprog: iceprog
-        nextpnr-ecp5: nextpnr-ecp5
-        ecppack: ecppack
-        openocd: openocd
diff --git a/examples/multi/memory.py b/examples/multi/memory.py
deleted file mode 100644
index bbec7300..00000000
--- a/examples/multi/memory.py
+++ /dev/null
@@ -1,24 +0,0 @@
-"""PyFPGA example about Memory Content Files inclusion.
-
-This example is mainly used as a test of this feature through the different
-tools.
-"""
-
-import logging
-
-from fpga.project import Project, TOOLS
-
-logging.basicConfig()
-
-for hdl in ['vhdl', 'verilog']:
-    for tool in TOOLS:
-        if tool == 'ghdl' and hdl == 'verilog':
-            continue
-        PRJ = Project(tool)
-        PRJ.set_outdir('../../build/multi/memory/%s/%s' % (tool, hdl))
-        if hdl == 'vhdl':
-            PRJ.add_files('../../hdl/ram.vhdl')
-        else:
-            PRJ.add_files('../../hdl/ram.v')
-        PRJ.set_top('ram')
-        PRJ.generate(to_task='syn')
diff --git a/examples/multi/parameters.py b/examples/multi/parameters.py
deleted file mode 100644
index f1912c85..00000000
--- a/examples/multi/parameters.py
+++ /dev/null
@@ -1,44 +0,0 @@
-"""PyFPGA Multi Vendor example where parameters are changed.
-
-The main idea of a multi-vendor project is to implements the same HDL code
-with different tools, to make comparisons. The project name is not important
-and the default devices are used. In this example, VHDL and Verilog
-files are synthesized changing the value of its generics/parameters.
-"""
-
-import logging
-
-from fpga.project import Project, TOOLS
-
-logging.basicConfig()
-
-for hdl in ['vhdl', 'verilog']:
-    for tool in TOOLS:
-        if tool == 'ghdl':
-            continue
-        if hdl == 'vhdl':
-            if tool in ['openflow', 'yosys', 'yosys-ise', 'yosys-vivado']:
-                continue
-        PRJ = Project(tool)
-        PRJ.add_param('FREQ', '50000000')
-        PRJ.add_param('SECS', '2')
-        PRJ.set_outdir('../../build/multi/params/%s/%s' % (tool, hdl))
-        if hdl == 'vhdl':
-            PRJ.add_files('../../hdl/blinking.vhdl')
-        else:
-            PRJ.add_vlog_include('../../hdl/headers1')
-            PRJ.add_vlog_include('../../hdl/headers2')
-            PRJ.add_files('../../hdl/blinking.v')
-        PRJ.set_top('Blinking')
-        # PRJ.add_param('INT', '15')
-        # PRJ.add_param('REA', '1.5')
-        # PRJ.add_param('LOG', "'1'")
-        # PRJ.add_param('VEC', '"10101010"')
-        # PRJ.add_param('STR', '"WXYZ"')
-        # PRJ.set_outdir('../../build/multi/params/%s/%s' % (tool, hdl))
-        # if hdl == 'vhdl':
-        #     PRJ.add_files('../../hdl/fakes/generics.vhdl')
-        # else:
-        #     PRJ.add_files('../../hdl/fakes/parameters.v')
-        # PRJ.set_top('Params')
-        PRJ.generate(to_task='syn')
diff --git a/examples/multi/projects.py b/examples/multi/projects.py
deleted file mode 100644
index 3d267a93..00000000
--- a/examples/multi/projects.py
+++ /dev/null
@@ -1,60 +0,0 @@
-"""PyFPGA Multi Project example.
-
-The main idea of a multi-project is to manage more than one project with the
-same script.
-"""
-
-import logging
-
-from fpga.project import Project
-
-logging.basicConfig()
-
-PROJECTS = {
-    'prj1': Project(
-        'vivado',
-        'vivado-prj',
-        meta={
-            'outdir': '../../build/multi/projects/vivado',
-            'part': 'xc7k70t-3-fbg484',
-            'vhdl': [
-                ['../../hdl/blinking.vhdl', 'examples'],
-                ['../../hdl/examples_pkg.vhdl', 'examples'],
-                '../../hdl/top.vhdl'
-                ],
-            'top': 'Top'
-        }
-    ),
-    'prj2': Project(
-        'ise',
-        'ise-prj',
-        meta={
-            'outdir': '../../build/multi/projects/ise',
-            'part': 'xc6slx9-2-csg324',
-            'vhdl': [
-                '../../hdl/blinking.vhdl'
-                ],
-            'top': 'Blinking'
-        }
-    ),
-    'prj3': Project(
-        'quartus',
-        'qurtus-prj',
-        meta={
-            'outdir': '../../build/multi/projects/quartus',
-            'part': '5CEBA2F17A7',
-            'paths': [
-                '../../hdl/headers1',
-                '../../hdl/headers2'
-            ],
-            'verilog': [
-                '../../hdl/blinking.v',
-                '../../hdl/top.v'
-            ],
-            'top': 'Top'
-        }
-    )
-}
-
-for prj in PROJECTS:
-    PROJECTS[prj].generate('syn')
diff --git a/examples/multi/verilog.py b/examples/multi/verilog.py
deleted file mode 100644
index b16be138..00000000
--- a/examples/multi/verilog.py
+++ /dev/null
@@ -1,24 +0,0 @@
-"""PyFPGA Multi Vendor Verilog example.
-
-The main idea of a multi-vendor project is to implements the same HDL code
-with different tools, to make comparisons. The project name is not important
-and the default devices could be used.
-"""
-
-import logging
-
-from fpga.project import Project, TOOLS
-
-logging.basicConfig()
-
-for tool in TOOLS:
-    if tool == 'ghdl':
-        continue
-    PRJ = Project(tool)
-    PRJ.set_outdir('../../build/multi/verilog/%s' % tool)
-    PRJ.add_vlog_include('../../hdl/headers1')
-    PRJ.add_vlog_include('../../hdl/headers2')
-    PRJ.add_files('../../hdl/blinking.v')
-    PRJ.add_files('../../hdl/top.v')
-    PRJ.set_top('Top')
-    PRJ.generate(to_task='syn')
diff --git a/examples/multi/vhdl.py b/examples/multi/vhdl.py
deleted file mode 100644
index 7c6ee7d8..00000000
--- a/examples/multi/vhdl.py
+++ /dev/null
@@ -1,21 +0,0 @@
-"""PyFPGA Multi Vendor VHDL example.
-
-The main idea of a multi-vendor project is to implements the same HDL code
-with different tools, to make comparisons. The project name is not important
-and the default devices are used.
-"""
-
-import logging
-
-from fpga.project import Project, TOOLS
-
-logging.basicConfig()
-
-for tool in TOOLS:
-    PRJ = Project(tool)
-    PRJ.set_outdir('../../build/multi/vhdl/%s' % tool)
-    PRJ.add_files('../../hdl/blinking.vhdl', library='examples')
-    PRJ.add_files('../../hdl/examples_pkg.vhdl', library='examples')
-    PRJ.add_files('../../hdl/top.vhdl')
-    PRJ.set_top('Top')
-    PRJ.generate(to_task='syn')

From db4a4eae532775492a91c6e51fc269fb14fbc7b8 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 1 Jul 2024 22:36:48 -0300
Subject: [PATCH 138/248] Moved constraint files under the cons directory

---
 examples/projects/ise.py                         | 12 ++++++------
 examples/projects/libero.py                      |  8 ++++----
 examples/projects/openflow.py                    | 16 ++++++++--------
 examples/projects/quartus.py                     |  6 +++---
 examples/projects/regress.sh                     |  2 +-
 examples/projects/vivado.py                      | 12 ++++++------
 examples/sources/{zybo => cons}/ZYBO/clk.xdc     |  0
 examples/sources/{zybo => cons}/ZYBO/led.xdc     |  0
 examples/sources/{zybo => cons}/ZYBO/timing.xdc  |  0
 .../{arty/a7-35t => cons/arty_a7_35t}/clk.xdc    |  0
 .../{arty/a7-35t => cons/arty_a7_35t}/led.xdc    |  0
 .../{arty/a7-35t => cons/arty_a7_35t}/timing.xdc |  0
 examples/sources/{ => cons}/de10nano/clk.sdc     |  0
 examples/sources/{ => cons}/de10nano/clk.tcl     |  0
 examples/sources/{ => cons}/de10nano/led.tcl     |  0
 examples/sources/{ => cons}/ecp5evn/clk.lpf      |  0
 examples/sources/{ => cons}/ecp5evn/led.lpf      |  0
 examples/sources/{ => cons}/edu-ciaa/clk.pcf     |  0
 examples/sources/{ => cons}/edu-ciaa/led.pcf     |  0
 examples/sources/{ => cons}/icestick/clk.pcf     |  0
 examples/sources/{ => cons}/icestick/led.pcf     |  0
 .../sources/{maker-board => cons/maker}/clk.pdc  |  0
 .../sources/{maker-board => cons/maker}/clk.sdc  |  0
 .../sources/{maker-board => cons/maker}/led.pdc  |  0
 examples/sources/{ => cons}/nexys3/clk.ucf       |  0
 examples/sources/{ => cons}/nexys3/clk.xcf       |  0
 examples/sources/{ => cons}/nexys3/led.ucf       |  0
 examples/sources/{ => cons}/orangecrab/clk.lpf   |  0
 examples/sources/{ => cons}/orangecrab/led.lpf   |  0
 examples/sources/{ => cons}/s6micro/clk.ucf      |  0
 examples/sources/{ => cons}/s6micro/clk.xcf      |  0
 examples/sources/{ => cons}/s6micro/led.ucf      |  0
 32 files changed, 28 insertions(+), 28 deletions(-)
 rename examples/sources/{zybo => cons}/ZYBO/clk.xdc (100%)
 rename examples/sources/{zybo => cons}/ZYBO/led.xdc (100%)
 rename examples/sources/{zybo => cons}/ZYBO/timing.xdc (100%)
 rename examples/sources/{arty/a7-35t => cons/arty_a7_35t}/clk.xdc (100%)
 rename examples/sources/{arty/a7-35t => cons/arty_a7_35t}/led.xdc (100%)
 rename examples/sources/{arty/a7-35t => cons/arty_a7_35t}/timing.xdc (100%)
 rename examples/sources/{ => cons}/de10nano/clk.sdc (100%)
 rename examples/sources/{ => cons}/de10nano/clk.tcl (100%)
 rename examples/sources/{ => cons}/de10nano/led.tcl (100%)
 rename examples/sources/{ => cons}/ecp5evn/clk.lpf (100%)
 rename examples/sources/{ => cons}/ecp5evn/led.lpf (100%)
 rename examples/sources/{ => cons}/edu-ciaa/clk.pcf (100%)
 rename examples/sources/{ => cons}/edu-ciaa/led.pcf (100%)
 rename examples/sources/{ => cons}/icestick/clk.pcf (100%)
 rename examples/sources/{ => cons}/icestick/led.pcf (100%)
 rename examples/sources/{maker-board => cons/maker}/clk.pdc (100%)
 rename examples/sources/{maker-board => cons/maker}/clk.sdc (100%)
 rename examples/sources/{maker-board => cons/maker}/led.pdc (100%)
 rename examples/sources/{ => cons}/nexys3/clk.ucf (100%)
 rename examples/sources/{ => cons}/nexys3/clk.xcf (100%)
 rename examples/sources/{ => cons}/nexys3/led.ucf (100%)
 rename examples/sources/{ => cons}/orangecrab/clk.lpf (100%)
 rename examples/sources/{ => cons}/orangecrab/led.lpf (100%)
 rename examples/sources/{ => cons}/s6micro/clk.ucf (100%)
 rename examples/sources/{ => cons}/s6micro/clk.xcf (100%)
 rename examples/sources/{ => cons}/s6micro/led.ucf (100%)

diff --git a/examples/projects/ise.py b/examples/projects/ise.py
index 3bd89df9..a1b9dba0 100644
--- a/examples/projects/ise.py
+++ b/examples/projects/ise.py
@@ -22,15 +22,15 @@
 if args.board == 's6micro':
     prj.set_part('xc6slx9-2-csg324')
     prj.add_param('FREQ', '125000000')
-    prj.add_cons('../sources/s6micro/clk.xcf', 'syn')
-    prj.add_cons('../sources/s6micro/clk.ucf', 'par')
-    prj.add_cons('../sources/s6micro/led.ucf', 'par')
+    prj.add_cons('../sources/cons/s6micro/clk.xcf', 'syn')
+    prj.add_cons('../sources/cons/s6micro/clk.ucf', 'par')
+    prj.add_cons('../sources/cons/s6micro/led.ucf', 'par')
 if args.board == 'nexys3':
     prj.set_part('xc6slx16-3-csg32')
     prj.add_param('FREQ', '100000000')
-    prj.add_cons('../sources/nexys3/clk.xcf', 'syn')
-    prj.add_cons('../sources/nexys3/clk.ucf', 'par')
-    prj.add_cons('../sources/nexys3/led.ucf', 'par')
+    prj.add_cons('../sources/cons/nexys3/clk.xcf', 'syn')
+    prj.add_cons('../sources/cons/nexys3/clk.ucf', 'par')
+    prj.add_cons('../sources/cons/nexys3/led.ucf', 'par')
 prj.add_param('SECS', '1')
 
 if args.source == 'vhdl':
diff --git a/examples/projects/libero.py b/examples/projects/libero.py
index 9d2fc6da..9c570a0e 100644
--- a/examples/projects/libero.py
+++ b/examples/projects/libero.py
@@ -6,7 +6,7 @@
 
 parser = argparse.ArgumentParser()
 parser.add_argument(
-    '--board', choices=['maker-board'], default='maker-board'
+    '--board', choices=['maker'], default='maker'
 )
 parser.add_argument(
     '--source', choices=['vlog', 'vhdl', 'slog'], default='vlog'
@@ -21,9 +21,9 @@
 if args.board == 'maker-board':
     prj.set_part('m2s010-1-tq144')
     prj.add_param('FREQ', '125000000')
-    prj.add_cons('../sources/maker-board/clk.sdc', 'syn')
-    prj.add_cons('../sources/maker-board/clk.pdc', 'par')
-    prj.add_cons('../sources/maker-board/led.pdc', 'par')
+    prj.add_cons('../sources/cons/maker/clk.sdc', 'syn')
+    prj.add_cons('../sources/cons/maker/clk.pdc', 'par')
+    prj.add_cons('../sources/cons/maker/led.pdc', 'par')
 prj.add_param('SECS', '1')
 
 if args.source == 'vhdl':
diff --git a/examples/projects/openflow.py b/examples/projects/openflow.py
index b01153c3..43c20f0b 100644
--- a/examples/projects/openflow.py
+++ b/examples/projects/openflow.py
@@ -23,23 +23,23 @@
 if args.board == 'icestick':
     prj.set_part('hx1k-tq144')
     prj.add_param('FREQ', '100000000')
-    prj.add_cons('../sources/icestick/clk.pcf', 'par')
-    prj.add_cons('../sources/icestick/led.pcf', 'par')
+    prj.add_cons('../sources/cons/icestick/clk.pcf', 'par')
+    prj.add_cons('../sources/cons/icestick/led.pcf', 'par')
 if args.board == 'edu-ciaa':
     prj.set_part('hx1k-tq144')
     prj.add_param('FREQ', '100000000')
-    prj.add_cons('../sources/edu-ciaa/clk.pcf', 'par')
-    prj.add_cons('../sources/edu-ciaa/led.pcf', 'par')
+    prj.add_cons('../sources/cons/edu-ciaa/clk.pcf', 'par')
+    prj.add_cons('../sources/cons/edu-ciaa/led.pcf', 'par')
 if args.board == 'orangecrab':
     prj.set_part('25k-CSFBGA285')
     prj.add_param('FREQ', '100000000')
-    prj.add_cons('../sources/orangecrab/clk.lpf', 'par')
-    prj.add_cons('../sources/orangecrab/led.lpf', 'par')
+    prj.add_cons('../sources/cons/orangecrab/clk.lpf', 'par')
+    prj.add_cons('../sources/cons/orangecrab/led.lpf', 'par')
 if args.board == 'ecp5evn':
     prj.set_part('um5g-85k-CABGA381')
     prj.add_param('FREQ', '100000000')
-    prj.add_cons('../sources/ecp5evn/clk.lpf', 'par')
-    prj.add_cons('../sources/ecp5evn/led.lpf', 'par')
+    prj.add_cons('../sources/cons/ecp5evn/clk.lpf', 'par')
+    prj.add_cons('../sources/cons/ecp5evn/led.lpf', 'par')
 
 prj.add_param('FREQ', '100000000')
 prj.add_param('SECS', '1')
diff --git a/examples/projects/quartus.py b/examples/projects/quartus.py
index 0453ac8e..ed5e4270 100644
--- a/examples/projects/quartus.py
+++ b/examples/projects/quartus.py
@@ -22,9 +22,9 @@
 if args.board == 'de10nano':
     prj.set_part('5CSEBA6U23I7')
     prj.add_param('FREQ', '125000000')
-    prj.add_cons('../sources/de10nano/clk.sdc', 'syn')
-    prj.add_cons('../sources/de10nano/clk.tcl', 'par')
-    prj.add_cons('../sources/de10nano/led.tcl', 'par')
+    prj.add_cons('../sources/cons/de10nano/clk.sdc', 'syn')
+    prj.add_cons('../sources/cons/de10nano/clk.tcl', 'par')
+    prj.add_cons('../sources/cons/de10nano/led.tcl', 'par')
 prj.add_param('SECS', '1')
 
 if args.source == 'vhdl':
diff --git a/examples/projects/regress.sh b/examples/projects/regress.sh
index f5513b3e..6af2f12b 100644
--- a/examples/projects/regress.sh
+++ b/examples/projects/regress.sh
@@ -5,7 +5,7 @@ set -e
 declare -A TOOLS
 
 TOOLS["ise"]="s6micro nexys3"
-TOOLS["libero"]="maker-board"
+TOOLS["libero"]="maker"
 TOOLS["openflow"]="icestick edu-ciaa orangecrab ecp5evn"
 TOOLS["quartus"]="de10nano"
 TOOLS["vivado"]="zybo arty"
diff --git a/examples/projects/vivado.py b/examples/projects/vivado.py
index 8ae97d6f..1ef6ace7 100644
--- a/examples/projects/vivado.py
+++ b/examples/projects/vivado.py
@@ -22,15 +22,15 @@
 if args.board == 'zybo':
     prj.set_part('xc7z010-1-clg400')
     prj.add_param('FREQ', '125000000')
-    prj.add_cons('../sources/zybo/ZYBO/timing.xdc', 'syn')
-    prj.add_cons('../sources/zybo/ZYBO/clk.xdc', 'par')
-    prj.add_cons('../sources/zybo/ZYBO/led.xdc', 'par')
+    prj.add_cons('../sources/cons/ZYBO/timing.xdc', 'syn')
+    prj.add_cons('../sources/cons/ZYBO/clk.xdc', 'par')
+    prj.add_cons('../sources/cons/ZYBO/led.xdc', 'par')
 if args.board == 'arty':
     prj.set_part('xc7a35ticsg324-1L')
     prj.add_param('FREQ', '100000000')
-    prj.add_cons('../sources/arty/a7-35t/timing.xdc', 'syn')
-    prj.add_cons('../sources/arty/a7-35t/clk.xdc', 'par')
-    prj.add_cons('../sources/arty/a7-35t/led.xdc', 'par')
+    prj.add_cons('../sources/cons/arty_a7_35t/timing.xdc', 'syn')
+    prj.add_cons('../sources/cons/arty_a7_35t/clk.xdc', 'par')
+    prj.add_cons('../sources/cons/arty_a7_35t/led.xdc', 'par')
 prj.add_param('SECS', '1')
 
 if args.source == 'vhdl':
diff --git a/examples/sources/zybo/ZYBO/clk.xdc b/examples/sources/cons/ZYBO/clk.xdc
similarity index 100%
rename from examples/sources/zybo/ZYBO/clk.xdc
rename to examples/sources/cons/ZYBO/clk.xdc
diff --git a/examples/sources/zybo/ZYBO/led.xdc b/examples/sources/cons/ZYBO/led.xdc
similarity index 100%
rename from examples/sources/zybo/ZYBO/led.xdc
rename to examples/sources/cons/ZYBO/led.xdc
diff --git a/examples/sources/zybo/ZYBO/timing.xdc b/examples/sources/cons/ZYBO/timing.xdc
similarity index 100%
rename from examples/sources/zybo/ZYBO/timing.xdc
rename to examples/sources/cons/ZYBO/timing.xdc
diff --git a/examples/sources/arty/a7-35t/clk.xdc b/examples/sources/cons/arty_a7_35t/clk.xdc
similarity index 100%
rename from examples/sources/arty/a7-35t/clk.xdc
rename to examples/sources/cons/arty_a7_35t/clk.xdc
diff --git a/examples/sources/arty/a7-35t/led.xdc b/examples/sources/cons/arty_a7_35t/led.xdc
similarity index 100%
rename from examples/sources/arty/a7-35t/led.xdc
rename to examples/sources/cons/arty_a7_35t/led.xdc
diff --git a/examples/sources/arty/a7-35t/timing.xdc b/examples/sources/cons/arty_a7_35t/timing.xdc
similarity index 100%
rename from examples/sources/arty/a7-35t/timing.xdc
rename to examples/sources/cons/arty_a7_35t/timing.xdc
diff --git a/examples/sources/de10nano/clk.sdc b/examples/sources/cons/de10nano/clk.sdc
similarity index 100%
rename from examples/sources/de10nano/clk.sdc
rename to examples/sources/cons/de10nano/clk.sdc
diff --git a/examples/sources/de10nano/clk.tcl b/examples/sources/cons/de10nano/clk.tcl
similarity index 100%
rename from examples/sources/de10nano/clk.tcl
rename to examples/sources/cons/de10nano/clk.tcl
diff --git a/examples/sources/de10nano/led.tcl b/examples/sources/cons/de10nano/led.tcl
similarity index 100%
rename from examples/sources/de10nano/led.tcl
rename to examples/sources/cons/de10nano/led.tcl
diff --git a/examples/sources/ecp5evn/clk.lpf b/examples/sources/cons/ecp5evn/clk.lpf
similarity index 100%
rename from examples/sources/ecp5evn/clk.lpf
rename to examples/sources/cons/ecp5evn/clk.lpf
diff --git a/examples/sources/ecp5evn/led.lpf b/examples/sources/cons/ecp5evn/led.lpf
similarity index 100%
rename from examples/sources/ecp5evn/led.lpf
rename to examples/sources/cons/ecp5evn/led.lpf
diff --git a/examples/sources/edu-ciaa/clk.pcf b/examples/sources/cons/edu-ciaa/clk.pcf
similarity index 100%
rename from examples/sources/edu-ciaa/clk.pcf
rename to examples/sources/cons/edu-ciaa/clk.pcf
diff --git a/examples/sources/edu-ciaa/led.pcf b/examples/sources/cons/edu-ciaa/led.pcf
similarity index 100%
rename from examples/sources/edu-ciaa/led.pcf
rename to examples/sources/cons/edu-ciaa/led.pcf
diff --git a/examples/sources/icestick/clk.pcf b/examples/sources/cons/icestick/clk.pcf
similarity index 100%
rename from examples/sources/icestick/clk.pcf
rename to examples/sources/cons/icestick/clk.pcf
diff --git a/examples/sources/icestick/led.pcf b/examples/sources/cons/icestick/led.pcf
similarity index 100%
rename from examples/sources/icestick/led.pcf
rename to examples/sources/cons/icestick/led.pcf
diff --git a/examples/sources/maker-board/clk.pdc b/examples/sources/cons/maker/clk.pdc
similarity index 100%
rename from examples/sources/maker-board/clk.pdc
rename to examples/sources/cons/maker/clk.pdc
diff --git a/examples/sources/maker-board/clk.sdc b/examples/sources/cons/maker/clk.sdc
similarity index 100%
rename from examples/sources/maker-board/clk.sdc
rename to examples/sources/cons/maker/clk.sdc
diff --git a/examples/sources/maker-board/led.pdc b/examples/sources/cons/maker/led.pdc
similarity index 100%
rename from examples/sources/maker-board/led.pdc
rename to examples/sources/cons/maker/led.pdc
diff --git a/examples/sources/nexys3/clk.ucf b/examples/sources/cons/nexys3/clk.ucf
similarity index 100%
rename from examples/sources/nexys3/clk.ucf
rename to examples/sources/cons/nexys3/clk.ucf
diff --git a/examples/sources/nexys3/clk.xcf b/examples/sources/cons/nexys3/clk.xcf
similarity index 100%
rename from examples/sources/nexys3/clk.xcf
rename to examples/sources/cons/nexys3/clk.xcf
diff --git a/examples/sources/nexys3/led.ucf b/examples/sources/cons/nexys3/led.ucf
similarity index 100%
rename from examples/sources/nexys3/led.ucf
rename to examples/sources/cons/nexys3/led.ucf
diff --git a/examples/sources/orangecrab/clk.lpf b/examples/sources/cons/orangecrab/clk.lpf
similarity index 100%
rename from examples/sources/orangecrab/clk.lpf
rename to examples/sources/cons/orangecrab/clk.lpf
diff --git a/examples/sources/orangecrab/led.lpf b/examples/sources/cons/orangecrab/led.lpf
similarity index 100%
rename from examples/sources/orangecrab/led.lpf
rename to examples/sources/cons/orangecrab/led.lpf
diff --git a/examples/sources/s6micro/clk.ucf b/examples/sources/cons/s6micro/clk.ucf
similarity index 100%
rename from examples/sources/s6micro/clk.ucf
rename to examples/sources/cons/s6micro/clk.ucf
diff --git a/examples/sources/s6micro/clk.xcf b/examples/sources/cons/s6micro/clk.xcf
similarity index 100%
rename from examples/sources/s6micro/clk.xcf
rename to examples/sources/cons/s6micro/clk.xcf
diff --git a/examples/sources/s6micro/led.ucf b/examples/sources/cons/s6micro/led.ucf
similarity index 100%
rename from examples/sources/s6micro/led.ucf
rename to examples/sources/cons/s6micro/led.ucf

From ba268eeab18d12eb8e71532c51a444fda60fd6c9 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Wed, 3 Jul 2024 21:19:34 -0300
Subject: [PATCH 139/248] Added a list of similar projects

---
 README.md | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/README.md b/README.md
index aa17c849..9630e0ce 100644
--- a/README.md
+++ b/README.md
@@ -65,3 +65,11 @@ pip install -e .
 
 > With `-e` (`--editable`) your application is installed into site-packages via a kind of symlink.
 > That allows pulling changes through git or changing the branch, avoiding the need to reinstall the package.
+
+## Similar projects
+
+* [edalize](https://github.com/olofk/edalize): an abstraction library for interfacing EDA tools.
+* [Hdlmake](https://ohwr.org/project/hdl-make): tool for generating multi-purpose makefiles for FPGA projects.
+* HDL On Git ([Hog](https://gitlab.com/hog-cern/Hog)): a set of Tcl/Shell scripts plus a suitable methodology to handle HDL designs in a GitLab repository.
+* IPbus Builder ([IPBB](https://github.com/ipbus/ipbb)): a tool for streamlining the synthesis, implementation and simulation of modular firmware projects over multiple platforms.
+* [tsfpa](https://github.com/tsfpga/tsfpga): a flexible and scalable development platform for modern FPGA projects.

From b13cc74292a19e5b4f0b8b174fd0406e148f9995 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Wed, 3 Jul 2024 21:20:03 -0300
Subject: [PATCH 140/248] Removed an extra add_param

---
 examples/projects/openflow.py | 2 --
 1 file changed, 2 deletions(-)

diff --git a/examples/projects/openflow.py b/examples/projects/openflow.py
index 43c20f0b..8eec90e4 100644
--- a/examples/projects/openflow.py
+++ b/examples/projects/openflow.py
@@ -40,8 +40,6 @@
     prj.add_param('FREQ', '100000000')
     prj.add_cons('../sources/cons/ecp5evn/clk.lpf', 'par')
     prj.add_cons('../sources/cons/ecp5evn/led.lpf', 'par')
-
-prj.add_param('FREQ', '100000000')
 prj.add_param('SECS', '1')
 
 if args.source == 'vhdl':

From e153c19e29c1495fb5fdbf106098366ecfa28484 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Wed, 3 Jul 2024 21:21:30 -0300
Subject: [PATCH 141/248] Small improvements

---
 tests/projects/support.py | 37 +++++++++++++++++++------------------
 1 file changed, 19 insertions(+), 18 deletions(-)

diff --git a/tests/projects/support.py b/tests/projects/support.py
index 4ce15596..12cb13c9 100644
--- a/tests/projects/support.py
+++ b/tests/projects/support.py
@@ -1,5 +1,6 @@
-"""Vivado examples."""
+"""Support examples."""
 
+import argparse
 import sys
 
 from pyfpga.ise import Ise
@@ -9,7 +10,7 @@
 from pyfpga.vivado import Vivado
 
 
-classes = {
+tools = {
     'ise': Ise,
     'libero': Libero,
     'openflow': Openflow,
@@ -17,18 +18,18 @@
     'vivado': Vivado
 }
 
-tool = sys.argv[1] if len(sys.argv) > 1 else 'openflow'
+parser = argparse.ArgumentParser()
+parser.add_argument(
+    '--tool', default='openflow',
+    choices=['ise', 'libero', 'quartus', 'openflow', 'vivado']
+)
+args = parser.parse_args()
 
-Class = classes.get(tool)
-
-if Class is None:
-    sys.exit('Unsupported tool')
-
-print(f'INFO: the Class Under Test is {Class.__name__}')
+print(f'INFO: the Tool Under Test is {args.tool}')
 
 try:
     print('INFO: checking Verilog Includes')
-    prj = Class()
+    prj = tools[args.tool]()
     prj.add_vlog('../../examples/sources/vlog/*.v')
     prj.set_top('Top')
     prj.add_define('DEFINE1', '1')
@@ -44,7 +45,7 @@
 
 try:
     print('INFO: checking Verilog Defines')
-    prj = Class()
+    prj = tools[args.tool]()
     prj.add_vlog('../../examples/sources/vlog/*.v')
     prj.set_top('Top')
     prj.add_include('../../examples/sources/vlog/include1')
@@ -60,7 +61,7 @@
 
 try:
     print('INFO: checking Verilog Parameters')
-    prj = Class()
+    prj = tools[args.tool]()
     prj.add_vlog('../../examples/sources/vlog/*.v')
     prj.set_top('Top')
     prj.add_include('../../examples/sources/vlog/include1')
@@ -75,7 +76,7 @@
     pass
 
 print('INFO: checking Verilog Support')
-prj = Class()
+prj = tools[args.tool]()
 prj.add_vlog('../../examples/sources/vlog/*.v')
 prj.set_top('Top')
 prj.add_include('../../examples/sources/vlog/include1')
@@ -86,9 +87,9 @@
 prj.add_param('SECS', '1')
 prj.make(last='syn')
 
-if tool not in ['ise', 'openflow']:
+if args.tool not in ['ise', 'openflow']:
     print('INFO: checking System Verilog Support')
-    prj = Class()
+    prj = tools[args.tool]()
     prj.add_slog('../../examples/sources/slog/*.sv')
     prj.set_top('Top')
     prj.add_include('../../examples/sources/slog/include1')
@@ -99,10 +100,10 @@
     prj.add_param('SECS', '1')
     prj.make(last='syn')
 
-if tool not in ['openflow']:
+if args.tool not in ['openflow']:
     try:
         print('INFO: checking VHDL Generics')
-        prj = Class()
+        prj = tools[args.tool]()
         prj.add_vhdl('../../examples/sources/vhdl/*.vhdl', 'blink_lib')
         prj.set_top('Top')
         prj.make(last='syn')
@@ -113,7 +114,7 @@
         pass
 
     print('* VHDL Support')
-    prj = Class()
+    prj = tools[args.tool]()
     prj.add_vhdl('../../examples/sources/vhdl/*.vhdl', 'blink_lib')
     prj.set_top('Top')
     prj.add_param('FREQ', '1')

From 508f58a5ae6b29ab4855b8fc1210206c4390051d Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Wed, 3 Jul 2024 21:22:13 -0300
Subject: [PATCH 142/248] Fix board name

---
 examples/projects/libero.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/projects/libero.py b/examples/projects/libero.py
index 9c570a0e..10d6b36d 100644
--- a/examples/projects/libero.py
+++ b/examples/projects/libero.py
@@ -18,7 +18,7 @@
 
 prj = Libero(odir='../build/libero')
 
-if args.board == 'maker-board':
+if args.board == 'maker':
     prj.set_part('m2s010-1-tq144')
     prj.add_param('FREQ', '125000000')
     prj.add_cons('../sources/cons/maker/clk.sdc', 'syn')

From aa342893ea291931f46601bf37d672ab6540c779 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Wed, 3 Jul 2024 21:23:06 -0300
Subject: [PATCH 143/248] Improved support for Libero (still WIP)

---
 pyfpga/libero.py              | 35 +++++++++++++--------------------
 pyfpga/templates/libero.jinja | 37 +++++++++++++++++++----------------
 2 files changed, 34 insertions(+), 38 deletions(-)

diff --git a/pyfpga/libero.py b/pyfpga/libero.py
index 29fc471a..a6aa6adf 100644
--- a/pyfpga/libero.py
+++ b/pyfpga/libero.py
@@ -31,11 +31,6 @@ def _make_prepare(self, steps):
         }
         for step in steps:
             context[step] = 1
-        if 'includes' in self.data:
-            includes = []
-            for include in self.data['includes']:
-                includes.append(str(include))
-            context['INCLUDES'] = ';'.join(includes)
         files = []
         if 'files' in self.data:
             for file in self.data['files']:
@@ -57,21 +52,19 @@ def _make_prepare(self, steps):
                 context['CONSTRAINTS'] = " ".join(constraints)
         if files:
             context['FILES'] = '\n'.join(files)
-        if 'top' in self.data:
-            context['TOP'] = self.data['top']
-        if 'defines' in self.data:
-            defines = []
-            for key, value in self.data['defines'].items():
-                defines.append(f'{key}={value}')
-            context['DEFINES'] = ' '.join(defines)
-        if 'params' in self.data:
-            params = []
-            for key, value in self.data['params'].items():
-                params.append(f'{key}={value}')
-            context['PARAMS'] = ' '.join(params)
+        context['INCLUDES'] = self.data.get('includes', None) # ';'.join(includes)
+        context['TOP'] = self.data.get('top', None)
+        context['DEFINES'] = self.data.get('defines', None)
+        context['PARAMS'] = self.data.get('params', None)
         if 'hooks' in self.data:
-            for stage in self.data['hooks']:
-                context[stage.upper()] = '\n'.join(self.data['hooks'][stage])
+            context['PRECFG'] = self.data['hooks'].get('precfg', None)
+            context['POSTCFG'] = self.data['hooks'].get('postcfg', None)
+            context['PRESYN'] = self.data['hooks'].get('presyn', None)
+            context['POSTSYN'] = self.data['hooks'].get('postsyn', None)
+            context['PREPAR'] = self.data['hooks'].get('prepar', None)
+            context['POSTPAR'] = self.data['hooks'].get('postpar', None)
+            context['PRESBIT'] = self.data['hooks'].get('prebit', None)
+            context['POSTBIT'] = self.data['hooks'].get('postbit', None)
         self._create_file('libero', 'tcl', context)
         return 'libero SCRIPT:libero.tcl'
 
@@ -118,10 +111,10 @@ def get_info(part):
     elif len(aux) == 3:
         device = aux[0]
         if len(aux[1]) < len(aux[2]):
-            speed = aux[1]
+            speed = f'-{aux[1]}'
             package = aux[2]
         else:
-            speed = aux[2]
+            speed = f'-{aux[2]}'
             package = aux[1]
     else:
         raise ValueError(
diff --git a/pyfpga/templates/libero.jinja b/pyfpga/templates/libero.jinja
index cc8af1e9..6eb0e090 100644
--- a/pyfpga/templates/libero.jinja
+++ b/pyfpga/templates/libero.jinja
@@ -4,41 +4,44 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-#proc fpga_include {PATH} {
-#    lappend INCLUDED $PATH
-#    # Verilog Included Files are ALSO added
-#    # They must be specified after set_root (see fpga_top)
-#    foreach FILE [glob -nocomplain $PATH/*.vh] {
-#        create_links -hdl_source $FILE
-#    }
-#    build_design_hierarchy
-#}
-
 #--[ Project configuration ]---------------------------------------------------
 
 {% if CFG %}
 if { [ file exists {{ PROJECT }} ] } { file delete -force -- {{ PROJECT }} }
-new_project -name {{ PROJECT }} -location . -hdl {VHDL} -family {SmartFusion2}
+new_project -name {{ PROJECT }} -location {libero} -hdl {VERILOG} -family {SmartFusion2}
 
 set_device -family {{ FAMILY }} -die {{ DEVICE }} -package {{ PACKAGE }} -speed {{ SPEED }}
 
 {{ PRECFG }}
 
+{% if INCLUDES %}set_global_include_path_order -paths "{{ INCLUDES | join(' ') }}"{% endif %}
+
 {{ FILES }}
 build_design_hierarchy
 
-{% if TOP %}
-set_root {{ TOP }}
-{% endif %}
+{% if TOP %}set_root {{ TOP }}{% endif %}
 
 {% if INCLUDES or DEFINES or PARAMS %}
 configure_tool -name {SYNTHESIZE} -params {SYNPLIFY_OPTIONS:
-{% if INCLUDES %}  set_option -include_path "{{ INCLUDES }}"{% endif %}
-{% if DEFINES %}  set_option -hdl_define "{{ DEFINES }}"{% endif %}
-{% if PARAMS %}  set_option -hdl_param "{{ PARAMS }}"{% endif %}
+{% if INCLUDES %}
+{% for INCLUDE in INCLUDES %}
+  set_option -include_path "{{ INCLUDE }}"
+{% endfor %}
+{% endif %}
+{% if DEFINES %}
+{% for KEY, VALUE in DEFINES.items() %}
+  set_option -hdl_define -set {{ KEY }}={{ VALUE }}
+{% endfor %}
+{% endif %}
+{% if PARAMS %}
+{% for KEY, VALUE in PARAMS.items() %}
+  set_option -hdl_param -set {{ KEY }}={{ VALUE }}
+{% endfor %}
+{% endif %}
 }
 {% endif %}
 
+
 # Constraints
 # PDC is only used for PLACEROUTE.
 # SDC is used by ALL (SYNTHESIZE, PLACEROUTE and VERIFYTIMING).

From 0c2ecb35fa33eae06155bc345b57bc9f84257789 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Thu, 4 Jul 2024 18:25:51 -0300
Subject: [PATCH 144/248] Modify how to generate an intentional error

---
 examples/sources/slog/top.sv   | 32 ++++++++++++++++++++++++++------
 examples/sources/vhdl/top.vhdl | 19 ++++++++++++++++---
 examples/sources/vlog/top.v    | 32 ++++++++++++++++++++++++++------
 3 files changed, 68 insertions(+), 15 deletions(-)

diff --git a/examples/sources/slog/top.sv b/examples/sources/slog/top.sv
index cfc700e3..f36d5ee0 100644
--- a/examples/sources/slog/top.sv
+++ b/examples/sources/slog/top.sv
@@ -12,24 +12,44 @@ module Top #(
   Blink #(.FREQ (FREQ), .SECS (SECS)) dut (.clk_i (clk_i), .led_o (led_o));
 
 `ifndef INCLUDE1
-  Top Top (.clk_i (clk_i), .led_o (led_o));
+  reg led;
+  always @(posedge clk_i) led <= 1'b0;
+  always @(posedge clk_i) led <= 1'b1;
+  assign led_o = led;
+  initial begin $stop; end
 `endif
 
 `ifndef INCLUDE2
-  Top Top (.clk_i (clk_i), .led_o (led_o));
+  reg led;
+  always @(posedge clk_i) led <= 1'b0;
+  always @(posedge clk_i) led <= 1'b1;
+  assign led_o = led;
+  initial begin $stop; end
 `endif
 
 `ifndef DEFINE1
-  Top Top (.clk_i (clk_i), .led_o (led_o));
+  reg led;
+  always @(posedge clk_i) led <= 1'b0;
+  always @(posedge clk_i) led <= 1'b1;
+  assign led_o = led;
+  initial begin $stop; end
 `endif
 
 `ifndef DEFINE2
-  Top Top (.clk_i (clk_i), .led_o (led_o));
+  reg led;
+  always @(posedge clk_i) led <= 1'b0;
+  always @(posedge clk_i) led <= 1'b1;
+  assign led_o = led;
+  initial begin $stop; end
 `endif
 
   generate
-    if (!FREQ || !SECS) begin: gen_error
-      Top Top (.clk_i (clk_i), .led_o (led_o));
+    if (!FREQ || !SECS) begin
+      reg led;
+      always @(posedge clk_i) led <= 1'b0;
+      always @(posedge clk_i) led <= 1'b1;
+      assign led_o = led;
+      initial begin $stop; end
     end
   endgenerate
 
diff --git a/examples/sources/vhdl/top.vhdl b/examples/sources/vhdl/top.vhdl
index c6537185..c89ad50e 100644
--- a/examples/sources/vhdl/top.vhdl
+++ b/examples/sources/vhdl/top.vhdl
@@ -15,15 +15,28 @@ entity Top is
 end entity Top;
 
 architecture ARCH of Top is
+  signal led : std_logic;
 begin
 
   blink_i: Blink
   generic map (FREQ => FREQ, SECS => SECS)
   port map (clk_i => clk_i, led_o => led_o);
 
-  gen_error : if FREQ=0 or SECS=0 generate
-    top_i: entity work.Top
-    port map (clk_i => clk_i, led_o => led_o);
+  gen_error: if (FREQ=0 or SECS=0) generate
+  begin
+    process(clk_i)
+    begin
+      if rising_edge(clk_i) then
+        led <= '0';
+      end if;
+    end process;
+    process(clk_i)
+    begin
+      if rising_edge(clk_i) then
+        led <= '1';
+      end if;
+    end process;
+    led_o <= led;
   end generate gen_error;
 
 end architecture ARCH;
diff --git a/examples/sources/vlog/top.v b/examples/sources/vlog/top.v
index f47433ba..5d3b9562 100644
--- a/examples/sources/vlog/top.v
+++ b/examples/sources/vlog/top.v
@@ -12,24 +12,44 @@ module Top #(
   Blink #(.FREQ (FREQ), .SECS (SECS)) dut (.clk_i (clk_i), .led_o (led_o));
 
 `ifndef INCLUDE1
-  Top Top (.clk_i (clk_i), .led_o (led_o));
+  reg led;
+  always @(posedge clk_i) led <= 1'b0;
+  always @(posedge clk_i) led <= 1'b1;
+  assign led_o = led;
+  initial begin $stop; end
 `endif
 
 `ifndef INCLUDE2
-  Top Top (.clk_i (clk_i), .led_o (led_o));
+  reg led;
+  always @(posedge clk_i) led <= 1'b0;
+  always @(posedge clk_i) led <= 1'b1;
+  assign led_o = led;
+  initial begin $stop; end
 `endif
 
 `ifndef DEFINE1
-  Top Top (.clk_i (clk_i), .led_o (led_o));
+  reg led;
+  always @(posedge clk_i) led <= 1'b0;
+  always @(posedge clk_i) led <= 1'b1;
+  assign led_o = led;
+  initial begin $stop; end
 `endif
 
 `ifndef DEFINE2
-  Top Top (.clk_i (clk_i), .led_o (led_o));
+  reg led;
+  always @(posedge clk_i) led <= 1'b0;
+  always @(posedge clk_i) led <= 1'b1;
+  assign led_o = led;
+  initial begin $stop; end
 `endif
 
   generate
-    if (!FREQ || !SECS) begin: gen_error
-      Top Top (.clk_i (clk_i), .led_o (led_o));
+    if (!FREQ || !SECS) begin
+      reg led;
+      always @(posedge clk_i) led <= 1'b0;
+      always @(posedge clk_i) led <= 1'b1;
+      assign led_o = led;
+      initial begin $stop; end
     end
   endgenerate
 

From 8b93f66fea27ed7156f49a277a8ef4910ffcf84e Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Thu, 4 Jul 2024 18:28:20 -0300
Subject: [PATCH 145/248] Modified to be Libero compatible

---
 examples/projects/libero.py | 1 +
 tests/projects/support.py   | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/examples/projects/libero.py b/examples/projects/libero.py
index 10d6b36d..4f4360d7 100644
--- a/examples/projects/libero.py
+++ b/examples/projects/libero.py
@@ -28,6 +28,7 @@
 
 if args.source == 'vhdl':
     prj.add_vhdl('../sources/vhdl/*.vhdl', 'blink_lib')
+    prj.add_vhdl('../sources/vhdl/top.vhdl')
 if args.source == 'vlog':
     prj.add_include('../sources/vlog/include1')
     prj.add_include('../sources/vlog/include2')
diff --git a/tests/projects/support.py b/tests/projects/support.py
index 12cb13c9..d0f4827e 100644
--- a/tests/projects/support.py
+++ b/tests/projects/support.py
@@ -105,6 +105,7 @@
         print('INFO: checking VHDL Generics')
         prj = tools[args.tool]()
         prj.add_vhdl('../../examples/sources/vhdl/*.vhdl', 'blink_lib')
+        prj.add_vhdl('../../examples/sources/vhdl/top.vhdl')
         prj.set_top('Top')
         prj.make(last='syn')
         sys.exit('ERROR: something does not work as expected')
@@ -116,6 +117,7 @@
     print('* VHDL Support')
     prj = tools[args.tool]()
     prj.add_vhdl('../../examples/sources/vhdl/*.vhdl', 'blink_lib')
+    prj.add_vhdl('../../examples/sources/vhdl/top.vhdl')
     prj.set_top('Top')
     prj.add_param('FREQ', '1')
     prj.add_param('SECS', '1')

From 211bbb7495fa392716a4308344c84e8e0c92533d Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Fri, 5 Jul 2024 00:01:53 -0300
Subject: [PATCH 146/248] Finished support for Libero

---
 pyfpga/libero.py              | 25 ++--------------
 pyfpga/templates/libero.jinja | 55 ++++++++++-------------------------
 2 files changed, 19 insertions(+), 61 deletions(-)

diff --git a/pyfpga/libero.py b/pyfpga/libero.py
index a6aa6adf..b9a76d60 100644
--- a/pyfpga/libero.py
+++ b/pyfpga/libero.py
@@ -31,28 +31,9 @@ def _make_prepare(self, steps):
         }
         for step in steps:
             context[step] = 1
-        files = []
-        if 'files' in self.data:
-            for file in self.data['files']:
-                if 'lib' in self.data['files'][file]:
-                    lib = self.data['files'][file]['lib']
-                    files.append(
-                        f'create_links -library {lib} -hdl_source {file}'
-                    )
-                else:
-                    files.append(f'create_links -hdl_source {file}')
-        if 'constraints' in self.data:
-            constraints = []
-            for file in self.data['constraints']:
-                if file.suffix == '.sdc':
-                    constraints.append(f'create_links -sdc {file}')
-                else:
-                    constraints.append(f'create_links -io_pdc {file}')
-            if constraints:
-                context['CONSTRAINTS'] = " ".join(constraints)
-        if files:
-            context['FILES'] = '\n'.join(files)
-        context['INCLUDES'] = self.data.get('includes', None) # ';'.join(includes)
+        context['FILES'] = self.data.get('files', None)
+        context['CONSTRAINTS'] = self.data.get('constraints', None)
+        context['INCLUDES'] = self.data.get('includes', None)
         context['TOP'] = self.data.get('top', None)
         context['DEFINES'] = self.data.get('defines', None)
         context['PARAMS'] = self.data.get('params', None)
diff --git a/pyfpga/templates/libero.jinja b/pyfpga/templates/libero.jinja
index 6eb0e090..36db875a 100644
--- a/pyfpga/templates/libero.jinja
+++ b/pyfpga/templates/libero.jinja
@@ -9,18 +9,32 @@
 {% if CFG %}
 if { [ file exists {{ PROJECT }} ] } { file delete -force -- {{ PROJECT }} }
 new_project -name {{ PROJECT }} -location {libero} -hdl {VERILOG} -family {SmartFusion2}
-
 set_device -family {{ FAMILY }} -die {{ DEVICE }} -package {{ PACKAGE }} -speed {{ SPEED }}
 
 {{ PRECFG }}
 
 {% if INCLUDES %}set_global_include_path_order -paths "{{ INCLUDES | join(' ') }}"{% endif %}
 
-{{ FILES }}
+{% for name, attr in FILES.items() %}
+create_links -hdl_source {{ name }}{% if 'lib' in attr %} -library {{ attr.lib }}{% endif %}
+{% endfor %}
+{% for name, attr in CONSTRAINTS.items() %}{% set name_str = name|string %}
+create_links {% if name_str.endswith('.sdc') %}-sdc{% else %}-io_pdc{% endif %} {{ name_str }}
+{% endfor %}
+
 build_design_hierarchy
 
 {% if TOP %}set_root {{ TOP }}{% endif %}
 
+{% set sdc_files = [] %}{% set pdc_files = [] %}
+{% for name, attr in CONSTRAINTS.items() %}{% set name_str = name|string %}
+{% if name_str.endswith('.sdc') %}{% set _ = sdc_files.append(name_str) %}{% endif %}{% set _ = pdc_files.append(name_str) %}
+{% endfor %}
+
+{% if sdc_files %}organize_tool_files -tool {SYNTHESIZE}   -file {{ sdc_files | join(' -file ') }} -module {{ TOP }} -input_type {constraint}{% endif %}
+{% if pdc_files %}organize_tool_files -tool {PLACEROUTE}   -file {{ pdc_files | join(' -file ') }} -module {{ TOP }} -input_type {constraint}{% endif %}
+{% if sdc_files %}organize_tool_files -tool {VERIFYTIMING} -file {{ sdc_files | join(' -file ') }} -module {{ TOP }} -input_type {constraint}{% endif %}
+
 {% if INCLUDES or DEFINES or PARAMS %}
 configure_tool -name {SYNTHESIZE} -params {SYNPLIFY_OPTIONS:
 {% if INCLUDES %}
@@ -41,43 +55,6 @@ configure_tool -name {SYNTHESIZE} -params {SYNPLIFY_OPTIONS:
 }
 {% endif %}
 
-
-# Constraints
-# PDC is only used for PLACEROUTE.
-# SDC is used by ALL (SYNTHESIZE, PLACEROUTE and VERIFYTIMING).
-#global LIBERO_PLACE_CONSTRAINTS
-#global LIBERO_OTHER_CONSTRAINTS
-#if { [info exists LIBERO_OTHER_CONSTRAINTS] } {
-#    set cmd "organize_tool_files -tool {SYNTHESIZE} "
-#    append cmd $LIBERO_OTHER_CONSTRAINTS
-#    append cmd "-module {{ TOP }} -input_type {constraint}"
-#    eval $cmd
-#    set cmd "organize_tool_files -tool {VERIFYTIMING} "
-#    append cmd $LIBERO_OTHER_CONSTRAINTS
-#    append cmd "-module {{ TOP }} -input_type {constraint}"
-#    eval $cmd
-#}
-#if { [info exists LIBERO_PLACE_CONSTRAINTS] } {
-#    set cmd "organize_tool_files -tool {PLACEROUTE} "
-#    append cmd $LIBERO_PLACE_CONSTRAINTS
-#    append cmd "-module {{ TOP }} -input_type {constraint}"
-#    eval $cmd
-#}
-
-#organize_tool_files -tool {SYNTHESIZE} \
-#  -file ../resources/constraints/maker-board/clk.sdc \
-#  -module Blink -input_type {constraint}
-
-#organize_tool_files -tool {PLACEROUTE} \
-#  -file ../resources/constraints/maker-board/clk.sdc \
-#  -file ../resources/constraints/maker-board/clk.pdc \
-#  -file ../resources/constraints/maker-board/led.pdc \
-#  -module Blink -input_type {constraint}
-
-#organize_tool_files -tool {VERIFYTIMING} \
-#  -file ../resources/constraints/maker-board/clk.sdc \
-#  -module Blink -input_type {constraint}
-
 {{ POSTCFG }}
 
 close_project

From c64e9f648295ebc79386853c3d0a633e324a00ac Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Fri, 5 Jul 2024 00:07:53 -0300
Subject: [PATCH 147/248] Fix value of speed in a Libero test case

---
 tests/test_part.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/test_part.py b/tests/test_part.py
index 7fd24ec7..86087946 100644
--- a/tests/test_part.py
+++ b/tests/test_part.py
@@ -18,7 +18,7 @@ def test_libero():
     info = {
         'family': 'SmartFusion2',
         'device': 'm2s010',
-        'speed': '1',
+        'speed': '-1',
         'package': 'tq144'
     }
     assert get_info_libero('m2s010-1-tq144') == info

From 7ddd0e50ca019b25de1145b15b02972f63a9e5a5 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Fri, 5 Jul 2024 18:27:00 -0300
Subject: [PATCH 148/248] Updated tools versions

---
 README.md | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/README.md b/README.md
index 9630e0ce..cfc2e872 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,8 @@
 # PyFPGA [![License](https://img.shields.io/badge/License-GPL--3.0-darkgreen?style=flat-square)](LICENSE)
 
-![Vivado](https://img.shields.io/badge/Vivado-2019.2-blue.svg?style=flat-square)
-![Quartus](https://img.shields.io/badge/Quartus--Prime-19.1-blue.svg?style=flat-square)
-![Libero](https://img.shields.io/badge/Libero--Soc-12.2-blue.svg?style=flat-square)
+![Vivado](https://img.shields.io/badge/Vivado-2022.1-blue.svg?style=flat-square)
+![Quartus](https://img.shields.io/badge/Quartus--Prime-23.1-blue.svg?style=flat-square)
+![Libero](https://img.shields.io/badge/Libero--Soc-2024.1-blue.svg?style=flat-square)
 ![ISE](https://img.shields.io/badge/ISE-14.7-blue.svg?style=flat-square)
 ![Openflow](https://img.shields.io/badge/Openflow-GHDL%20%7C%20Yosys%20%7C%20nextpnr%20%7C%20icestorm%20%7C%20prjtrellis-darkgreen.svg?style=flat-square)
 

From 154da913850b538f8118e59754458683cfbadec4 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Fri, 5 Jul 2024 20:30:42 -0300
Subject: [PATCH 149/248] Add to check basic support based on the Blink module

---
 tests/projects/support.py | 70 ++++++++++++++++++++++++---------------
 1 file changed, 44 insertions(+), 26 deletions(-)

diff --git a/tests/projects/support.py b/tests/projects/support.py
index d0f4827e..13c9b868 100644
--- a/tests/projects/support.py
+++ b/tests/projects/support.py
@@ -27,8 +27,26 @@
 
 print(f'INFO: the Tool Under Test is {args.tool}')
 
+print('INFO: checking basic Verilog Support')
+prj = tools[args.tool]()
+prj.add_vlog('../../examples/sources/vlog/blink.v')
+prj.set_top('Blink')
+prj.make(last='syn')
+
+print('INFO: checking advanced Verilog Support')
+prj = tools[args.tool]()
+prj.add_vlog('../../examples/sources/vlog/*.v')
+prj.set_top('Top')
+prj.add_include('../../examples/sources/vlog/include1')
+prj.add_include('../../examples/sources/vlog/include2')
+prj.add_define('DEFINE1', '1')
+prj.add_define('DEFINE2', '1')
+prj.add_param('FREQ', '1')
+prj.add_param('SECS', '1')
+prj.make(last='syn')
+
 try:
-    print('INFO: checking Verilog Includes')
+    print('INFO: checking Verilog Includes Support')
     prj = tools[args.tool]()
     prj.add_vlog('../../examples/sources/vlog/*.v')
     prj.set_top('Top')
@@ -44,7 +62,7 @@
     pass
 
 try:
-    print('INFO: checking Verilog Defines')
+    print('INFO: checking Verilog Defines Support')
     prj = tools[args.tool]()
     prj.add_vlog('../../examples/sources/vlog/*.v')
     prj.set_top('Top')
@@ -60,7 +78,7 @@
     pass
 
 try:
-    print('INFO: checking Verilog Parameters')
+    print('INFO: checking Verilog Parameters Support')
     prj = tools[args.tool]()
     prj.add_vlog('../../examples/sources/vlog/*.v')
     prj.set_top('Top')
@@ -75,20 +93,14 @@
 except Exception:
     pass
 
-print('INFO: checking Verilog Support')
-prj = tools[args.tool]()
-prj.add_vlog('../../examples/sources/vlog/*.v')
-prj.set_top('Top')
-prj.add_include('../../examples/sources/vlog/include1')
-prj.add_include('../../examples/sources/vlog/include2')
-prj.add_define('DEFINE1', '1')
-prj.add_define('DEFINE2', '1')
-prj.add_param('FREQ', '1')
-prj.add_param('SECS', '1')
-prj.make(last='syn')
-
 if args.tool not in ['ise', 'openflow']:
-    print('INFO: checking System Verilog Support')
+    print('INFO: checking basic System Verilog Support')
+    prj = tools[args.tool]()
+    prj.add_slog('../../examples/sources/slog/blink.sv')
+    prj.set_top('Blink')
+    prj.make(last='syn')
+
+    print('INFO: checking advanced System Verilog Support')
     prj = tools[args.tool]()
     prj.add_slog('../../examples/sources/slog/*.sv')
     prj.set_top('Top')
@@ -101,6 +113,21 @@
     prj.make(last='syn')
 
 if args.tool not in ['openflow']:
+    print('* INFO: checking basic VHDL Support')
+    prj = tools[args.tool]()
+    prj.add_vhdl('../../examples/sources/vhdl/blink.vhdl')
+    prj.set_top('Blink')
+    prj.make(last='syn')
+
+    print('* INFO: checking advanced VHDL Support')
+    prj = tools[args.tool]()
+    prj.add_vhdl('../../examples/sources/vhdl/*.vhdl', 'blink_lib')
+    prj.add_vhdl('../../examples/sources/vhdl/top.vhdl')
+    prj.set_top('Top')
+    prj.add_param('FREQ', '1')
+    prj.add_param('SECS', '1')
+    prj.make(last='syn')
+
     try:
         print('INFO: checking VHDL Generics')
         prj = tools[args.tool]()
@@ -114,13 +141,4 @@
     except Exception:
         pass
 
-    print('* VHDL Support')
-    prj = tools[args.tool]()
-    prj.add_vhdl('../../examples/sources/vhdl/*.vhdl', 'blink_lib')
-    prj.add_vhdl('../../examples/sources/vhdl/top.vhdl')
-    prj.set_top('Top')
-    prj.add_param('FREQ', '1')
-    prj.add_param('SECS', '1')
-    prj.make(last='syn')
-
-print(f'INFO: Class Under Test works as expected')
+print(f'INFO: Tool Under Test works as expected')

From c00c278073cbac9cefc07da2622b1911a9552f7d Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Fri, 5 Jul 2024 20:33:30 -0300
Subject: [PATCH 150/248] Libero support slightly improved

---
 pyfpga/libero.py              |  2 +-
 pyfpga/templates/libero.jinja | 29 +++++++++++++----------------
 2 files changed, 14 insertions(+), 17 deletions(-)

diff --git a/pyfpga/libero.py b/pyfpga/libero.py
index b9a76d60..813eb3da 100644
--- a/pyfpga/libero.py
+++ b/pyfpga/libero.py
@@ -31,9 +31,9 @@ def _make_prepare(self, steps):
         }
         for step in steps:
             context[step] = 1
+        context['INCLUDES'] = self.data.get('includes', None)
         context['FILES'] = self.data.get('files', None)
         context['CONSTRAINTS'] = self.data.get('constraints', None)
-        context['INCLUDES'] = self.data.get('includes', None)
         context['TOP'] = self.data.get('top', None)
         context['DEFINES'] = self.data.get('defines', None)
         context['PARAMS'] = self.data.get('params', None)
diff --git a/pyfpga/templates/libero.jinja b/pyfpga/templates/libero.jinja
index 36db875a..a0f6259d 100644
--- a/pyfpga/templates/libero.jinja
+++ b/pyfpga/templates/libero.jinja
@@ -15,21 +15,24 @@ set_device -family {{ FAMILY }} -die {{ DEVICE }} -package {{ PACKAGE }} -speed
 
 {% if INCLUDES %}set_global_include_path_order -paths "{{ INCLUDES | join(' ') }}"{% endif %}
 
-{% for name, attr in FILES.items() %}
+{% if FILES %}{% for name, attr in FILES.items() %}
 create_links -hdl_source {{ name }}{% if 'lib' in attr %} -library {{ attr.lib }}{% endif %}
-{% endfor %}
-{% for name, attr in CONSTRAINTS.items() %}{% set name_str = name|string %}
+{% endfor %}{% endif %}
+
+{% if CONSTRAINTS %}{% for name, attr in CONSTRAINTS.items() %}{% set name_str = name|string %}
 create_links {% if name_str.endswith('.sdc') %}-sdc{% else %}-io_pdc{% endif %} {{ name_str }}
-{% endfor %}
+{% endfor %}{% endif %}
 
 build_design_hierarchy
 
 {% if TOP %}set_root {{ TOP }}{% endif %}
 
+{% if CONSTRAINTS %}
 {% set sdc_files = [] %}{% set pdc_files = [] %}
 {% for name, attr in CONSTRAINTS.items() %}{% set name_str = name|string %}
 {% if name_str.endswith('.sdc') %}{% set _ = sdc_files.append(name_str) %}{% endif %}{% set _ = pdc_files.append(name_str) %}
 {% endfor %}
+{% endif %}
 
 {% if sdc_files %}organize_tool_files -tool {SYNTHESIZE}   -file {{ sdc_files | join(' -file ') }} -module {{ TOP }} -input_type {constraint}{% endif %}
 {% if pdc_files %}organize_tool_files -tool {PLACEROUTE}   -file {{ pdc_files | join(' -file ') }} -module {{ TOP }} -input_type {constraint}{% endif %}
@@ -37,21 +40,15 @@ build_design_hierarchy
 
 {% if INCLUDES or DEFINES or PARAMS %}
 configure_tool -name {SYNTHESIZE} -params {SYNPLIFY_OPTIONS:
-{% if INCLUDES %}
-{% for INCLUDE in INCLUDES %}
+{% if INCLUDES %}{% for INCLUDE in INCLUDES %}
   set_option -include_path "{{ INCLUDE }}"
-{% endfor %}
-{% endif %}
-{% if DEFINES %}
-{% for KEY, VALUE in DEFINES.items() %}
+{% endfor %}{% endif %}
+{% if DEFINES %}{% for KEY, VALUE in DEFINES.items() %}
   set_option -hdl_define -set {{ KEY }}={{ VALUE }}
-{% endfor %}
-{% endif %}
-{% if PARAMS %}
-{% for KEY, VALUE in PARAMS.items() %}
+{% endfor %}{% endif %}
+{% if PARAMS %}{% for KEY, VALUE in PARAMS.items() %}
   set_option -hdl_param -set {{ KEY }}={{ VALUE }}
-{% endfor %}
-{% endif %}
+{% endfor %}{% endif %}
 }
 {% endif %}
 

From 7963eb1c36bd518b50ec9b175b5e63d114246bff Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Fri, 5 Jul 2024 20:34:09 -0300
Subject: [PATCH 151/248] Quartus support improved/simplified

---
 pyfpga/quartus.py              | 57 +++++++++-------------------------
 pyfpga/templates/quartus.jinja | 41 +++++++++++++++---------
 2 files changed, 40 insertions(+), 58 deletions(-)

diff --git a/pyfpga/quartus.py b/pyfpga/quartus.py
index 417a497a..10a5927e 100644
--- a/pyfpga/quartus.py
+++ b/pyfpga/quartus.py
@@ -25,50 +25,21 @@ def _make_prepare(self, steps):
         }
         for step in steps:
             context[step] = 1
-        if 'includes' in self.data:
-            includes = []
-            for include in self.data['includes']:
-                includes.append(str(include))
-            context['INCLUDES'] = ' '.join(includes)
-        files = []
-        if 'files' in self.data:
-            types = {
-                'slog': 'SYSTEMVERILOG_FILE',
-                'vhdl': 'VHDL_FILE',
-                'vlog': 'VERILOG_FILE'
-            }
-            for file in self.data['files']:
-                hdl = self.data['files'][file]['hdl']
-                lib = self.data['files'][file].get('lib', None)
-                typ = types[hdl]
-                line = f'set_global_assignment -name {typ} {file}'
-                if lib:
-                    line += f' -library {lib}'
-                files.append(line)
-        if 'constraints' in self.data:
-            for file in self.data['constraints']:
-                if file.suffix == '.sdc':
-                    line = f'set_global_assignment -name SDC_FILE {file}'
-                else:
-                    line = f'source {file}'
-                files.append(line)
-        if files:
-            context['FILES'] = '\n'.join(files)
-        if 'top' in self.data:
-            context['TOP'] = self.data['top']
-        if 'defines' in self.data:
-            defines = []
-            for key, value in self.data['defines'].items():
-                defines.append(f'{key} {value}')
-            context['DEFINES'] = ' '.join(defines)
-        if 'params' in self.data:
-            params = []
-            for key, value in self.data['params'].items():
-                params.append(f'{key} {value}')
-            context['PARAMS'] = ' '.join(params)
+        context['INCLUDES'] = self.data.get('includes', None)
+        context['FILES'] = self.data.get('files', None)
+        context['CONSTRAINTS'] = self.data.get('constraints', None)
+        context['TOP'] = self.data.get('top', None)
+        context['DEFINES'] = self.data.get('defines', None)
+        context['PARAMS'] = self.data.get('params', None)
         if 'hooks' in self.data:
-            for stage in self.data['hooks']:
-                context[stage.upper()] = '\n'.join(self.data['hooks'][stage])
+            context['PRECFG'] = self.data['hooks'].get('precfg', None)
+            context['POSTCFG'] = self.data['hooks'].get('postcfg', None)
+            context['PRESYN'] = self.data['hooks'].get('presyn', None)
+            context['POSTSYN'] = self.data['hooks'].get('postsyn', None)
+            context['PREPAR'] = self.data['hooks'].get('prepar', None)
+            context['POSTPAR'] = self.data['hooks'].get('postpar', None)
+            context['PRESBIT'] = self.data['hooks'].get('prebit', None)
+            context['POSTBIT'] = self.data['hooks'].get('postbit', None)
         self._create_file('quartus', 'tcl', context)
         return 'quartus_sh --script quartus.tcl'
 
diff --git a/pyfpga/templates/quartus.jinja b/pyfpga/templates/quartus.jinja
index 4b98174a..3f97e363 100644
--- a/pyfpga/templates/quartus.jinja
+++ b/pyfpga/templates/quartus.jinja
@@ -13,26 +13,37 @@ set_global_assignment -name DEVICE {{ PART }}
 
 {{ PRECFG }}
 
-{{ FILES }}
-
-{% if TOP %}
-set_global_assignment -name TOP_LEVEL_ENTITY {{ TOP }}
+{% if FILES %}{% for NAME, ATTR in FILES.items() %}
+{% if ATTR.hdl == "vhdl" %}
+set_global_assignment -name VHDL_FILE {{ NAME }} {% if 'lib' in ATTR %} -library {{ ATTR.lib }}{% endif %}
+{% elif ATTR.hdl == "vlog" %}
+set_global_assignment -name VERILOG_FILE {{ NAME }}
+{% elif ATTR.hdl == "slog" %}
+set_global_assignment -name SYSTEMVERILOG_FILE {{ NAME }}
 {% endif %}
+{% endfor %}{% endif %}
 
-{% if DEFINES %}
-set defines [dict create {{ DEFINES }}]
-foreach {key value} $defines {set_global_assignment -name VERILOG_MACRO "$key=$value"}
+{% if CONSTRAINTS %}{% for name, attr in CONSTRAINTS.items() %}{% set name_str = name|string %}
+{% if name_str.endswith('.sdc') %}
+set_global_assignment -name SDC_FILE {{ name_str }}
+{% else %}
+source {{ name_str }}
 {% endif %}
+{% endfor %}{% endif %}
 
-{% if INCLUDES %}
-set includes { {{ INCLUDES}} }
-foreach value $includes {set_global_assignment -name SEARCH_PATH $value}
-{% endif %}
+{% if TOP %}set_global_assignment -name TOP_LEVEL_ENTITY {{ TOP }}{% endif %}
 
-{% if PARAMS %}
-set params [dict create {{ PARAMS }}]
-foreach {key value} $params {set_parameter -name $key $value}
-{% endif %}
+{% if INCLUDES %}{% for INCLUDE in INCLUDES %}
+set_global_assignment -name SEARCH_PATH {{ INCLUDE }}
+{% endfor %}{% endif %}
+
+{% if DEFINES %}{% for KEY, VALUE in DEFINES.items() %}
+set_global_assignment -name VERILOG_MACRO {{ KEY }}={{ VALUE }}
+{% endfor %}{% endif %}
+
+{% if PARAMS %}{% for KEY, VALUE in PARAMS.items() %}
+set_parameter -name {{ KEY }} {{ VALUE }}
+{% endfor %}{% endif %}
 
 {{ POSTCFG }}
 

From 250409906a0c8f3466097e64b1f55aff57097812 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Fri, 5 Jul 2024 22:00:58 -0300
Subject: [PATCH 152/248] Applied a few format fixes

---
 pyfpga/templates/libero.jinja  |  8 ++++----
 pyfpga/templates/quartus.jinja | 22 +++++++++++-----------
 pyfpga/templates/vivado.jinja  |  2 +-
 3 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/pyfpga/templates/libero.jinja b/pyfpga/templates/libero.jinja
index a0f6259d..3d961e51 100644
--- a/pyfpga/templates/libero.jinja
+++ b/pyfpga/templates/libero.jinja
@@ -43,11 +43,11 @@ configure_tool -name {SYNTHESIZE} -params {SYNPLIFY_OPTIONS:
 {% if INCLUDES %}{% for INCLUDE in INCLUDES %}
   set_option -include_path "{{ INCLUDE }}"
 {% endfor %}{% endif %}
-{% if DEFINES %}{% for KEY, VALUE in DEFINES.items() %}
-  set_option -hdl_define -set {{ KEY }}={{ VALUE }}
+{% if DEFINES %}{% for key, value in DEFINES.items() %}
+  set_option -hdl_define -set {{ key }}={{ value }}
 {% endfor %}{% endif %}
-{% if PARAMS %}{% for KEY, VALUE in PARAMS.items() %}
-  set_option -hdl_param -set {{ KEY }}={{ VALUE }}
+{% if PARAMS %}{% for key, value in PARAMS.items() %}
+  set_option -hdl_param -set {{ key }}={{ value }}
 {% endfor %}{% endif %}
 }
 {% endif %}
diff --git a/pyfpga/templates/quartus.jinja b/pyfpga/templates/quartus.jinja
index 3f97e363..1caa2108 100644
--- a/pyfpga/templates/quartus.jinja
+++ b/pyfpga/templates/quartus.jinja
@@ -13,13 +13,13 @@ set_global_assignment -name DEVICE {{ PART }}
 
 {{ PRECFG }}
 
-{% if FILES %}{% for NAME, ATTR in FILES.items() %}
-{% if ATTR.hdl == "vhdl" %}
-set_global_assignment -name VHDL_FILE {{ NAME }} {% if 'lib' in ATTR %} -library {{ ATTR.lib }}{% endif %}
-{% elif ATTR.hdl == "vlog" %}
-set_global_assignment -name VERILOG_FILE {{ NAME }}
-{% elif ATTR.hdl == "slog" %}
-set_global_assignment -name SYSTEMVERILOG_FILE {{ NAME }}
+{% if FILES %}{% for name, attr in FILES.items() %}
+{% if attr.hdl == "vhdl" %}
+set_global_assignment -name VHDL_FILE {{ name }} {% if 'lib' in attr %} -library {{ attr.lib }}{% endif %}
+{% elif attr.hdl == "vlog" %}
+set_global_assignment -name VERILOG_FILE {{ name }}
+{% elif attr.hdl == "slog" %}
+set_global_assignment -name SYSTEMVERILOG_FILE {{ name }}
 {% endif %}
 {% endfor %}{% endif %}
 
@@ -37,12 +37,12 @@ source {{ name_str }}
 set_global_assignment -name SEARCH_PATH {{ INCLUDE }}
 {% endfor %}{% endif %}
 
-{% if DEFINES %}{% for KEY, VALUE in DEFINES.items() %}
-set_global_assignment -name VERILOG_MACRO {{ KEY }}={{ VALUE }}
+{% if DEFINES %}{% for key, value in DEFINES.items() %}
+set_global_assignment -name VERILOG_MACRO {{ key }}={{ value }}
 {% endfor %}{% endif %}
 
-{% if PARAMS %}{% for KEY, VALUE in PARAMS.items() %}
-set_parameter -name {{ KEY }} {{ VALUE }}
+{% if PARAMS %}{% for key, value in PARAMS.items() %}
+set_parameter -name {{ key }} {{ value }}
 {% endfor %}{% endif %}
 
 {{ POSTCFG }}
diff --git a/pyfpga/templates/vivado.jinja b/pyfpga/templates/vivado.jinja
index 8f0cbb8e..ffef4aa8 100644
--- a/pyfpga/templates/vivado.jinja
+++ b/pyfpga/templates/vivado.jinja
@@ -4,7 +4,7 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-#--[ Project configuration ]--------------------------------------------------
+#--[ Project configuration ]---------------------------------------------------
 
 {% if CFG %}
 create_project -force {{ PROJECT }}

From cae0d326fe1c903787767879970704aca96fd8eb Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Fri, 5 Jul 2024 22:01:48 -0300
Subject: [PATCH 153/248] ISE support improved/simplified

---
 pyfpga/ise.py              | 52 ++++++++++----------------------------
 pyfpga/templates/ise.jinja | 30 ++++++++++++----------
 2 files changed, 31 insertions(+), 51 deletions(-)

diff --git a/pyfpga/ise.py b/pyfpga/ise.py
index a964af7c..9e173f2f 100644
--- a/pyfpga/ise.py
+++ b/pyfpga/ise.py
@@ -31,45 +31,21 @@ def _make_prepare(self, steps):
         }
         for step in steps:
             context[step] = 1
-        if 'includes' in self.data:
-            includes = []
-            for include in self.data['includes']:
-                includes.append(str(include))
-            context['INCLUDES'] = '|'.join(includes)
-        files = []
-        if 'files' in self.data:
-            for file in self.data['files']:
-                if 'lib' in self.data['files'][file]:
-                    lib = self.data['files'][file]['lib']
-                    files.append(f'lib_vhdl new {lib}')
-                    files.append(f'xfile add {file} -lib_vhdl {lib}')
-                else:
-                    files.append(f'xfile add {file}')
-        if 'constraints' in self.data:
-            constraints = []
-            for file in self.data['constraints']:
-                files.append(f'xfile add {file}')
-                if file.suffix == '.xcf':
-                    constraints.append(str(file))
-            if constraints:
-                context['CONSTRAINTS'] = " ".join(constraints)
-        if files:
-            context['FILES'] = '\n'.join(files)
-        if 'top' in self.data:
-            context['TOP'] = self.data['top']
-        if 'defines' in self.data:
-            defines = []
-            for key, value in self.data['defines'].items():
-                defines.append(f'{key}={value}')
-            context['DEFINES'] = ' | '.join(defines)
-        if 'params' in self.data:
-            params = []
-            for key, value in self.data['params'].items():
-                params.append(f'{key}={value}')
-            context['PARAMS'] = ' '.join(params)
+        context['INCLUDES'] = self.data.get('includes', None)
+        context['FILES'] = self.data.get('files', None)
+        context['CONSTRAINTS'] = self.data.get('constraints', None)
+        context['TOP'] = self.data.get('top', None)
+        context['DEFINES'] = self.data.get('defines', None)
+        context['PARAMS'] = self.data.get('params', None)
         if 'hooks' in self.data:
-            for stage in self.data['hooks']:
-                context[stage.upper()] = '\n'.join(self.data['hooks'][stage])
+            context['PRECFG'] = self.data['hooks'].get('precfg', None)
+            context['POSTCFG'] = self.data['hooks'].get('postcfg', None)
+            context['PRESYN'] = self.data['hooks'].get('presyn', None)
+            context['POSTSYN'] = self.data['hooks'].get('postsyn', None)
+            context['PREPAR'] = self.data['hooks'].get('prepar', None)
+            context['POSTPAR'] = self.data['hooks'].get('postpar', None)
+            context['PRESBIT'] = self.data['hooks'].get('prebit', None)
+            context['POSTBIT'] = self.data['hooks'].get('postbit', None)
         self._create_file('ise', 'tcl', context)
         return 'xtclsh ise.tcl'
 
diff --git a/pyfpga/templates/ise.jinja b/pyfpga/templates/ise.jinja
index 701a028d..d72a26ae 100644
--- a/pyfpga/templates/ise.jinja
+++ b/pyfpga/templates/ise.jinja
@@ -4,7 +4,7 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
-#--[ Project configuration ]--------------------------------------------------
+#--[ Project configuration ]---------------------------------------------------
 
 {% if CFG %}
 if { [ file exists {{ PROJECT }}.xise ] } { file delete {{ PROJECT }}.xise }
@@ -16,26 +16,30 @@ project set speed  -{{ SPEED }}
 
 {{ PRECFG }}
 
-{{ FILES }}
-{% if CONSTRAINTS %}
-project set "Synthesis Constraints File" "{{ CONSTRAINTS }}" -process "Synthesize - XST"
-{% endif %}
+{% if FILES %}{% for name, attr in FILES.items() %}
+{% if 'lib' in attr %}lib_vhdl new {{ attr.lib }}{% endif %}
+xfile add {{ name }}{% if 'lib' in attr %} -lib_vhdl {{ attr.lib }}{% endif %}
+{% endfor %}{% endif %}
 
-{% if TOP %}
-project set top {{ TOP }}
+{% if CONSTRAINTS %}{% for name, attr in CONSTRAINTS.items() %}{% set name_str = name|string %}
+xfile add {{ name_str }}
+{% if name_str.endswith('.xcf') %}
+project set "Synthesis Constraints File" "{{ name_str }}" -process "Synthesize - XST"
 {% endif %}
+{% endfor %}{% endif %}
 
-{% if DEFINES %}
-project set "Verilog Macros" "{{ DEFINES }}" -process "Synthesize - XST"
-{% endif %}
+{% if TOP %}project set top {{ TOP }}{% endif %}
 
 {% if INCLUDES %}
-project set "Verilog Include Directories" "{{ INCLUDES }}" -process "Synthesize - XST"
-# [join $INCLUDED "|"]
+project set "Verilog Include Directories" "{{ INCLUDES | join('|') }}" -process "Synthesize - XST"
+{% endif %}
+
+{% if DEFINES %}
+project set "Verilog Macros" "{{ DEFINES.items() | map('join', '=') | join(' | ') }}" -process "Synthesize - XST"
 {% endif %}
 
 {% if PARAMS %}
-project set "Generics, Parameters" "{{ PARAMS }}" -process "Synthesize - XST"
+project set "Generics, Parameters" "{{ PARAMS.items() | map('join', '=') | join(' ') }}" -process "Synthesize - XST"
 {% endif %}
 
 {{ POSTCFG }}

From d0226be81eaaaa949da142d7ff0f28a1351fd3ac Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 6 Jul 2024 00:09:38 -0300
Subject: [PATCH 154/248] Fix intentional error generation for Vivado

---
 examples/sources/slog/top.sv | 10 +++++-----
 examples/sources/vlog/top.v  | 10 +++++-----
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/examples/sources/slog/top.sv b/examples/sources/slog/top.sv
index f36d5ee0..732ae368 100644
--- a/examples/sources/slog/top.sv
+++ b/examples/sources/slog/top.sv
@@ -16,7 +16,7 @@ module Top #(
   always @(posedge clk_i) led <= 1'b0;
   always @(posedge clk_i) led <= 1'b1;
   assign led_o = led;
-  initial begin $stop; end
+  initial begin $stop; $error("intentional"); end
 `endif
 
 `ifndef INCLUDE2
@@ -24,7 +24,7 @@ module Top #(
   always @(posedge clk_i) led <= 1'b0;
   always @(posedge clk_i) led <= 1'b1;
   assign led_o = led;
-  initial begin $stop; end
+  initial begin $stop; $error("intentional"); end
 `endif
 
 `ifndef DEFINE1
@@ -32,7 +32,7 @@ module Top #(
   always @(posedge clk_i) led <= 1'b0;
   always @(posedge clk_i) led <= 1'b1;
   assign led_o = led;
-  initial begin $stop; end
+  initial begin $stop; $error("intentional"); end
 `endif
 
 `ifndef DEFINE2
@@ -40,7 +40,7 @@ module Top #(
   always @(posedge clk_i) led <= 1'b0;
   always @(posedge clk_i) led <= 1'b1;
   assign led_o = led;
-  initial begin $stop; end
+  initial begin $stop; $error("intentional"); end
 `endif
 
   generate
@@ -49,7 +49,7 @@ module Top #(
       always @(posedge clk_i) led <= 1'b0;
       always @(posedge clk_i) led <= 1'b1;
       assign led_o = led;
-      initial begin $stop; end
+      initial begin $stop; $error("intentional"); end
     end
   endgenerate
 
diff --git a/examples/sources/vlog/top.v b/examples/sources/vlog/top.v
index 5d3b9562..9a6d452b 100644
--- a/examples/sources/vlog/top.v
+++ b/examples/sources/vlog/top.v
@@ -16,7 +16,7 @@ module Top #(
   always @(posedge clk_i) led <= 1'b0;
   always @(posedge clk_i) led <= 1'b1;
   assign led_o = led;
-  initial begin $stop; end
+  initial begin $stop; $error("intentional"); end
 `endif
 
 `ifndef INCLUDE2
@@ -24,7 +24,7 @@ module Top #(
   always @(posedge clk_i) led <= 1'b0;
   always @(posedge clk_i) led <= 1'b1;
   assign led_o = led;
-  initial begin $stop; end
+  initial begin $stop; $error("intentional"); end
 `endif
 
 `ifndef DEFINE1
@@ -32,7 +32,7 @@ module Top #(
   always @(posedge clk_i) led <= 1'b0;
   always @(posedge clk_i) led <= 1'b1;
   assign led_o = led;
-  initial begin $stop; end
+  initial begin $stop; $error("intentional"); end
 `endif
 
 `ifndef DEFINE2
@@ -40,7 +40,7 @@ module Top #(
   always @(posedge clk_i) led <= 1'b0;
   always @(posedge clk_i) led <= 1'b1;
   assign led_o = led;
-  initial begin $stop; end
+  initial begin $stop; $error("intentional"); end
 `endif
 
   generate
@@ -49,7 +49,7 @@ module Top #(
       always @(posedge clk_i) led <= 1'b0;
       always @(posedge clk_i) led <= 1'b1;
       assign led_o = led;
-      initial begin $stop; end
+      initial begin $stop; $error("intentional"); end
     end
   endgenerate
 

From fbd52b16cf3050d6038a31e14cb89ed50058796e Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 6 Jul 2024 00:10:05 -0300
Subject: [PATCH 155/248] Vivado support improved/simplified

---
 pyfpga/templates/vivado.jinja | 29 ++++++++++++------
 pyfpga/vivado.py              | 58 +++++++++--------------------------
 2 files changed, 34 insertions(+), 53 deletions(-)

diff --git a/pyfpga/templates/vivado.jinja b/pyfpga/templates/vivado.jinja
index ffef4aa8..6a40c459 100644
--- a/pyfpga/templates/vivado.jinja
+++ b/pyfpga/templates/vivado.jinja
@@ -14,22 +14,33 @@ set_property PART {{ PART }} [current_project]
 
 {{ PRECFG }}
 
-{{ FILES }}
-
-{% if TOP %}
-set_property TOP {{ TOP }} [current_fileset]
+{% if FILES %}{% for name, attr in FILES.items() %}
+add_file {{ name }}
+{% if 'lib' in attr %}set_property library {{ attr.lib }} [get_files {{ name }}]{% endif %}
+{% endfor %}{% endif %}
+
+{% if CONSTRAINTS %}{% for name, attr in CONSTRAINTS.items() %}
+add_file -fileset constrs_1 {{ name }}
+{% if attr == "syn" %}
+set_property USED_IN_IMPLEMENTATION FALSE [get_files {{ name }}]
+{% elif attr == "par" %}
+set_property USED_IN_SYNTHESIS FALSE [get_files {{ name }}]
 {% endif %}
+{% if loop.first %}set_property TARGET_CONSTRS_FILE {{ name }} [current_fileset -constrset]{% endif %}
+{% endfor %}{% endif %}
 
-{% if DEFINES %}
-set_property VERILOG_DEFINE { {{ DEFINES}} } [current_fileset]
-{% endif %}
+{% if TOP %}set_property TOP {{ TOP }} [current_fileset]{% endif %}
 
 {% if INCLUDES %}
-set_property INCLUDE_DIRS { {{ INCLUDES}} } [current_fileset]
+set_property INCLUDE_DIRS { {{ INCLUDES | join(' ') }} } [current_fileset]
+{% endif %}
+
+{% if DEFINES %}
+set_property VERILOG_DEFINE { {{ DEFINES.items() | map('join', '=') | join(' ') }} }  [current_fileset]
 {% endif %}
 
 {% if PARAMS %}
-set_property GENERIC { {{ PARAMS }} } -objects [get_filesets sources_1]
+set_property GENERIC { {{ PARAMS.items() | map('join', '=') | join(' ') }} } -objects [get_filesets sources_1]
 {% endif %}
 
 {{ POSTCFG }}
diff --git a/pyfpga/vivado.py b/pyfpga/vivado.py
index 1858ed82..c0a48864 100644
--- a/pyfpga/vivado.py
+++ b/pyfpga/vivado.py
@@ -24,51 +24,21 @@ def _make_prepare(self, steps):
         }
         for step in steps:
             context[step] = 1
-        if 'includes' in self.data:
-            includes = []
-            for include in self.data['includes']:
-                includes.append(str(include))
-            context['INCLUDES'] = ' '.join(includes)
-        files = []
-        if 'files' in self.data:
-            for file in self.data['files']:
-                files.append(f'add_file {file}')
-            for file in self.data['files']:
-                if 'lib' in self.data['files'][file]:
-                    lib = self.data['files'][file]['lib']
-                    files.append(
-                        f'set_property library {lib} [get_files {file}]'
-                    )
-        if 'constraints' in self.data:
-            for file in self.data['constraints']:
-                files.append(f'add_file -fileset constrs_1 {file}')
-            for file in self.data['constraints']:
-                if self.data['constraints'][file] == 'syn':
-                    prop = 'USED_IN_IMPLEMENTATION FALSE'
-                if self.data['constraints'][file] == 'syn':
-                    prop = 'USED_IN_SYNTHESIS FALSE'
-                if self.data['constraints'][file] != 'all':
-                    files.append(f'set_property {prop} [get_files {file}]')
-            first = next(iter(self.data['constraints']))
-            prop = f'TARGET_CONSTRS_FILE {first}'
-            files.append(f'set_property {prop} [current_fileset -constrset]')
-        if files:
-            context['FILES'] = '\n'.join(files)
-        if 'top' in self.data:
-            context['TOP'] = self.data['top']
-        if 'defines' in self.data:
-            defines = []
-            for key, value in self.data['defines'].items():
-                defines.append(f'{key}={value}')
-            context['DEFINES'] = ' '.join(defines)
-        if 'params' in self.data:
-            params = []
-            for key, value in self.data['params'].items():
-                params.append(f'{key}={value}')
-            context['PARAMS'] = ' '.join(params)
+        context['INCLUDES'] = self.data.get('includes', None)
+        context['FILES'] = self.data.get('files', None)
+        context['CONSTRAINTS'] = self.data.get('constraints', None)
+        context['TOP'] = self.data.get('top', None)
+        context['DEFINES'] = self.data.get('defines', None)
+        context['PARAMS'] = self.data.get('params', None)
         if 'hooks' in self.data:
-            for stage in self.data['hooks']:
-                context[stage.upper()] = '\n'.join(self.data['hooks'][stage])
+            context['PRECFG'] = self.data['hooks'].get('precfg', None)
+            context['POSTCFG'] = self.data['hooks'].get('postcfg', None)
+            context['PRESYN'] = self.data['hooks'].get('presyn', None)
+            context['POSTSYN'] = self.data['hooks'].get('postsyn', None)
+            context['PREPAR'] = self.data['hooks'].get('prepar', None)
+            context['POSTPAR'] = self.data['hooks'].get('postpar', None)
+            context['PRESBIT'] = self.data['hooks'].get('prebit', None)
+            context['POSTBIT'] = self.data['hooks'].get('postbit', None)
         self._create_file('vivado', 'tcl', context)
         return 'vivado -mode batch -notrace -quiet -source vivado.tcl'
 

From 8d2a067f4bd8374b6e7e7fda54dac8cd866eb0d8 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 6 Jul 2024 13:42:33 -0300
Subject: [PATCH 156/248] Openflow support improved/simplified

---
 pyfpga/openflow.py              | 56 +++++++++------------------------
 pyfpga/templates/openflow.jinja | 18 ++++++-----
 2 files changed, 25 insertions(+), 49 deletions(-)

diff --git a/pyfpga/openflow.py b/pyfpga/openflow.py
index 51dcd84a..a2e4092d 100644
--- a/pyfpga/openflow.py
+++ b/pyfpga/openflow.py
@@ -28,49 +28,21 @@ def _make_prepare(self, steps):
         }
         for step in steps:
             context[step] = 1
-        if 'includes' in self.data:
-            includes = []
-            for include in self.data['includes']:
-                includes.append(f'-I{str(include)}')
-            context['INCLUDES'] = ' '.join(includes)
-        files = []
-        if 'files' in self.data:
-            for file in self.data['files']:
-                files.append(f'read_verilog -defer {file}')
-        if files:
-            context['VLOGS'] = '\n'.join(files)
-#         for file in self.files['vhdl']:
-#             lib = ''
-#             if file[1] is not None:
-#                 lib = f'--work={file[1]}'
-#             vhdls.append(f'{self.tools["ghdl"]} -a $FLAGS {lib} {file[0]}')
-#         for file in self.files['verilog']:
-#             if file[0].endswith('.sv'):
-#                 verilogs.append(f'read_verilog -sv -defer {file[0]}')
-#             else:
-#                 verilogs.append(f'read_verilog -defer {file[0]}')
-#         if len(vhdls) > 0:
-#             verilogs = [f'ghdl $FLAGS {self.top}']
-        if 'constraints' in self.data:
-            constraints = []
-            for constraint in self.data['constraints']:
-                constraints.append(str(constraint))
-            context['CONSTRAINTS'] = ' '.join(constraints)
-        if 'top' in self.data:
-            context['TOP'] = self.data['top']
-        if 'defines' in self.data:
-            defines = []
-            for key, value in self.data['defines'].items():
-                defines.append(f'-D{key}={value}')
-            context['DEFINES'] = ' '.join(defines)
-        if 'params' in self.data:
-            params = []
-            for key, value in self.data['params'].items():
-                params.append(f'-set {key} {value}')
-            context['PARAMS'] = ' '.join(params)
+        context['INCLUDES'] = self.data.get('includes', None)
+        context['FILES'] = self.data.get('files', None)
+        context['CONSTRAINTS'] = self.data.get('constraints', None)
+        context['TOP'] = self.data.get('top', None)
+        context['DEFINES'] = self.data.get('defines', None)
+        context['PARAMS'] = self.data.get('params', None)
         if 'hooks' in self.data:
-            for stage in self.data['hooks']:
-                context[stage.upper()] = '\n'.join(self.data['hooks'][stage])
+            context['PRECFG'] = self.data['hooks'].get('precfg', None)
+            context['POSTCFG'] = self.data['hooks'].get('postcfg', None)
+            context['PRESYN'] = self.data['hooks'].get('presyn', None)
+            context['POSTSYN'] = self.data['hooks'].get('postsyn', None)
+            context['PREPAR'] = self.data['hooks'].get('prepar', None)
+            context['POSTPAR'] = self.data['hooks'].get('postpar', None)
+            context['PRESBIT'] = self.data['hooks'].get('prebit', None)
+            context['POSTBIT'] = self.data['hooks'].get('postbit', None)
         self._create_file('openflow', 'sh', context)
         return 'bash openflow.sh'
 
diff --git a/pyfpga/templates/openflow.jinja b/pyfpga/templates/openflow.jinja
index f9b3ba05..d29cbbc5 100644
--- a/pyfpga/templates/openflow.jinja
+++ b/pyfpga/templates/openflow.jinja
@@ -13,18 +13,22 @@ DOCKER="docker run --user $(id -u):$(id -g) --rm -v $HOME:$HOME -w $PWD"
 {% if SYN %}
 $DOCKER hdlc/ghdl:yosys /bin/bash -c "
 {{ PRESYN }}
-{{ VHDLS }}
 yosys -Q -m ghdl -p '
 {% if INCLUDES %}
-verilog_defaults -add {{ INCLUDES }}
+verilog_defaults -add{% for path in INCLUDES %} -I{{ path }}{% endfor %}
 {% endif %}
 {% if DEFINES %}
-verilog_defines {{ DEFINES }}
+verilog_defines{% for key, value in DEFINES.items() %} -D{{ key }}={{ value }}{% endfor %}
 {% endif %}
-{{ VLOGS }}
-{{ SLOGS }}
+{% if FILES %}{% for name, attr in FILES.items() %}
+{% if attr.hdl == "vlog" %}
+read_verilog -defer {{ name }}
+{% elif attr.hdl == "slog" %}
+read_verilog -defer -sv {{ name }}
+{% endif %}
+{% endfor %}{% endif %}
 {% if PARAMS %}
-chparam {{ PARAMS }} {{ TOP }}
+chparam{% for key, value in PARAMS.items() %} -set {{ key }} {{ value }}{% endfor %}
 {% endif %}
 synth -top {{ TOP }}
 synth_{{ FAMILY }} -top {{ TOP }} -json {{ PROJECT }}.json
@@ -54,7 +58,7 @@ synth_{{ FAMILY }} -top {{ TOP }} -json {{ PROJECT }}.json
 
 {% if PAR %}
 
-CONSTRAINTS="{{ CONSTRAINTS }}"
+CONSTRAINTS="{{ CONSTRAINTS | join(' ') }}"
 
 {% if FAMILY == 'ice40' %}
 if [ -n "$CONSTRAINTS" ]; then

From 6936d14cef5bc2e56ca4374b107b4f9ac3999782 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 6 Jul 2024 14:09:16 -0300
Subject: [PATCH 157/248] Fix SV files inclusion

---
 examples/projects/openflow.py | 2 +-
 examples/projects/quartus.py  | 2 +-
 examples/projects/vivado.py   | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/examples/projects/openflow.py b/examples/projects/openflow.py
index 8eec90e4..b40f6c96 100644
--- a/examples/projects/openflow.py
+++ b/examples/projects/openflow.py
@@ -51,7 +51,7 @@
 if args.source == 'slog':
     prj.add_include('../sources/slog/include1')
     prj.add_include('../sources/slog/include2')
-    prj.add_vlog('../sources/slog/*.sv')
+    prj.add_slog('../sources/slog/*.sv')
 if args.source in ['vlog', 'slog']:
     prj.add_define('DEFINE1', '1')
     prj.add_define('DEFINE2', '1')
diff --git a/examples/projects/quartus.py b/examples/projects/quartus.py
index ed5e4270..07cfedc4 100644
--- a/examples/projects/quartus.py
+++ b/examples/projects/quartus.py
@@ -36,7 +36,7 @@
 if args.source == 'slog':
     prj.add_include('../sources/slog/include1')
     prj.add_include('../sources/slog/include2')
-    prj.add_vlog('../sources/slog/*.sv')
+    prj.add_slog('../sources/slog/*.sv')
 if args.source in ['vlog', 'slog']:
     prj.add_define('DEFINE1', '1')
     prj.add_define('DEFINE2', '1')
diff --git a/examples/projects/vivado.py b/examples/projects/vivado.py
index 1ef6ace7..367f2861 100644
--- a/examples/projects/vivado.py
+++ b/examples/projects/vivado.py
@@ -42,7 +42,7 @@
 if args.source == 'slog':
     prj.add_include('../sources/slog/include1')
     prj.add_include('../sources/slog/include2')
-    prj.add_vlog('../sources/slog/*.sv')
+    prj.add_slog('../sources/slog/*.sv')
 if args.source in ['vlog', 'slog']:
     prj.add_define('DEFINE1', '1')
     prj.add_define('DEFINE2', '1')

From ed6257b0bb4c4f8cdce9bfe5b966a6eafdd143f1 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 7 Jul 2024 21:49:29 -0300
Subject: [PATCH 158/248] Modified to try SV for Openflow

---
 tests/projects/support.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/projects/support.py b/tests/projects/support.py
index 13c9b868..4aa0d009 100644
--- a/tests/projects/support.py
+++ b/tests/projects/support.py
@@ -93,7 +93,7 @@
 except Exception:
     pass
 
-if args.tool not in ['ise', 'openflow']:
+if args.tool not in ['ise']:
     print('INFO: checking basic System Verilog Support')
     prj = tools[args.tool]()
     prj.add_slog('../../examples/sources/slog/blink.sv')

From f249f1431c25e1a9147a0aa6513efa4300c4a6ed Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 7 Jul 2024 22:02:31 -0300
Subject: [PATCH 159/248] Cosmetic changes to Jinja templates

---
 pyfpga/templates/ise-prog.jinja      | 10 ++++
 pyfpga/templates/ise.jinja           | 45 ++++++++++++---
 pyfpga/templates/libero-prog.jinja   |  1 +
 pyfpga/templates/libero.jinja        | 82 ++++++++++++++++++++++------
 pyfpga/templates/openflow-prog.jinja |  1 +
 pyfpga/templates/openflow.jinja      | 25 +++++++--
 pyfpga/templates/quartus-prog.jinja  |  2 +
 pyfpga/templates/quartus.jinja       | 63 ++++++++++++++++-----
 pyfpga/templates/vivado-prog.jinja   |  2 +
 pyfpga/templates/vivado.jinja        | 47 +++++++++++++---
 10 files changed, 228 insertions(+), 50 deletions(-)

diff --git a/pyfpga/templates/ise-prog.jinja b/pyfpga/templates/ise-prog.jinja
index 2ba0c193..0f0e38c9 100644
--- a/pyfpga/templates/ise-prog.jinja
+++ b/pyfpga/templates/ise-prog.jinja
@@ -1,11 +1,15 @@
+{#
 #
 # Copyright (C) 2015-2024 Rodrigo A. Melo
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
+#}
 
 cleancablelock
 
+{# ------------------------------------------------------------------------- #}
+
 {% if FPGA %}
 setMode -bs
 setCable -port auto
@@ -14,6 +18,8 @@ assignFile -p {{ POSITION }} -file  {{ BITSTREAM }}
 Program -p {{ POSITION }}
 {% endif %}
 
+{# ------------------------------------------------------------------------- #}
+
 {% if SPI %}
 setMode -pff
 addConfigDevice -name {{ NAME }} -path .
@@ -31,6 +37,8 @@ assignfiletoattachedflash -position {{ POSITION }} -file ./{{ NAME }}.mcs
 Program -p {{ POSITION }} -dataWidth {{ WIDTH }} -spionly -e -v -loadfpga
 {% endif %}
 
+{# ------------------------------------------------------------------------- #}
+
 {% if BPI %}
 setMode -pff
 addConfigDevice -name {{ NAME }} -path .
@@ -49,4 +57,6 @@ assignfiletoattachedflash -position {{ POSITION }} -file ./{{ NAME }}.mcs
 Program -p {{ POSITION }} -dataWidth {{ WIDTH }} -rs1 NONE -rs0 NONE -bpionly -e -v -loadfpga
 {% endif %}
 
+{# ------------------------------------------------------------------------- #}
+
 quit
diff --git a/pyfpga/templates/ise.jinja b/pyfpga/templates/ise.jinja
index d72a26ae..10811ebf 100644
--- a/pyfpga/templates/ise.jinja
+++ b/pyfpga/templates/ise.jinja
@@ -1,12 +1,17 @@
+{#
 #
 # Copyright (C) 2015-2024 Rodrigo A. Melo
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
+#}
 
-#--[ Project configuration ]---------------------------------------------------
+{# ------------------------------------------------------------------------- #}
+{# Project configuration                                                     #}
+{# ------------------------------------------------------------------------- #}
 
 {% if CFG %}
+
 if { [ file exists {{ PROJECT }}.xise ] } { file delete {{ PROJECT }}.xise }
 project new {{ PROJECT }}.xise
 project set family  {{ FAMILY }}
@@ -16,19 +21,26 @@ project set speed  -{{ SPEED }}
 
 {{ PRECFG }}
 
-{% if FILES %}{% for name, attr in FILES.items() %}
+{% if FILES %}
+{% for name, attr in FILES.items() %}
 {% if 'lib' in attr %}lib_vhdl new {{ attr.lib }}{% endif %}
 xfile add {{ name }}{% if 'lib' in attr %} -lib_vhdl {{ attr.lib }}{% endif %}
-{% endfor %}{% endif %}
+{% endfor %}
+{% endif %}
 
-{% if CONSTRAINTS %}{% for name, attr in CONSTRAINTS.items() %}{% set name_str = name|string %}
+{% if CONSTRAINTS %}
+{% for name, attr in CONSTRAINTS.items() %}
+{% set name_str = name|string %}
 xfile add {{ name_str }}
 {% if name_str.endswith('.xcf') %}
 project set "Synthesis Constraints File" "{{ name_str }}" -process "Synthesize - XST"
 {% endif %}
-{% endfor %}{% endif %}
+{% endfor %}
+{% endif %}
 
-{% if TOP %}project set top {{ TOP }}{% endif %}
+{% if TOP %}
+project set top {{ TOP }}
+{% endif %}
 
 {% if INCLUDES %}
 project set "Verilog Include Directories" "{{ INCLUDES | join('|') }}" -process "Synthesize - XST"
@@ -45,14 +57,21 @@ project set "Generics, Parameters" "{{ PARAMS.items() | map('join', '=') | join(
 {{ POSTCFG }}
 
 project close
+
 {% endif %}
 
-#--[ Design flow ]-------------------------------------------------------------
+{# ------------------------------------------------------------------------- #}
+{# Design flow                                                               #}
+{# ------------------------------------------------------------------------- #}
 
 {% if SYN or PAR or BIT %}
+
 project open {{ PROJECT }}.xise
 
+{# Synthesis --------------------------------------------------------------- #}
+
 {% if SYN %}
+
 {{ PRESYN }}
 
 # PRESYNTH
@@ -62,9 +81,13 @@ process run "Synthesize"
 if { [process get "Synthesize" status] == "errors" } { exit 1 }
 
 {{ POSTSYN }}
+
 {% endif %}
 
+{# Place and Route --------------------------------------------------------- #}
+
 {% if PAR %}
+
 {{ PREPAR }}
 
 process run "Translate"
@@ -75,9 +98,13 @@ process run "Place & Route"
 if { [process get "Place & Route" status] == "errors" } { exit 1 }
 
 {{ POSTPAR }}
+
 {% endif %}
 
+{# Bitstream generation ---------------------------------------------------- #}
+
 {% if BIT %}
+
 {{ PREBIT }}
 
 process run "Generate Programming File"
@@ -85,7 +112,11 @@ if { [process get "Generate Programming File" status] == "errors" } { exit 1 }
 catch { file rename -force {{ TOP }}.bit {{ PROJECT }}.bit }
 
 {{ POSTBIT }}
+
 {% endif %}
 
+{# ------------------------------------------------------------------------- #}
+
 project close
+
 {% endif %}
diff --git a/pyfpga/templates/libero-prog.jinja b/pyfpga/templates/libero-prog.jinja
index 95b740f0..5bd27ab5 100644
--- a/pyfpga/templates/libero-prog.jinja
+++ b/pyfpga/templates/libero-prog.jinja
@@ -3,6 +3,7 @@
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
+#}
 
 # open_project -file {$TEMPDIR/libero.prjx}
 # run_tool -name {CONFIGURE_CHAIN} -script {$TEMPDIR/flashpro.tcl}
diff --git a/pyfpga/templates/libero.jinja b/pyfpga/templates/libero.jinja
index 3d961e51..f62d78dc 100644
--- a/pyfpga/templates/libero.jinja
+++ b/pyfpga/templates/libero.jinja
@@ -1,36 +1,55 @@
+{#
 #
 # Copyright (C) 2015-2024 Rodrigo A. Melo
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
+#}
 
-#--[ Project configuration ]---------------------------------------------------
+{# ------------------------------------------------------------------------- #}
+{# Project configuration                                                     #}
+{# ------------------------------------------------------------------------- #}
 
 {% if CFG %}
+
 if { [ file exists {{ PROJECT }} ] } { file delete -force -- {{ PROJECT }} }
 new_project -name {{ PROJECT }} -location {libero} -hdl {VERILOG} -family {SmartFusion2}
 set_device -family {{ FAMILY }} -die {{ DEVICE }} -package {{ PACKAGE }} -speed {{ SPEED }}
 
 {{ PRECFG }}
 
-{% if INCLUDES %}set_global_include_path_order -paths "{{ INCLUDES | join(' ') }}"{% endif %}
+{% if INCLUDES %}
+set_global_include_path_order -paths "{{ INCLUDES | join(' ') }}"
+{% endif %}
 
-{% if FILES %}{% for name, attr in FILES.items() %}
+{% if FILES %}
+{% for name, attr in FILES.items() %}
 create_links -hdl_source {{ name }}{% if 'lib' in attr %} -library {{ attr.lib }}{% endif %}
-{% endfor %}{% endif %}
+{% endfor %}
+{% endif %}
 
-{% if CONSTRAINTS %}{% for name, attr in CONSTRAINTS.items() %}{% set name_str = name|string %}
+{% if CONSTRAINTS %}
+{% for name, attr in CONSTRAINTS.items() %}
+{% set name_str = name|string %}
 create_links {% if name_str.endswith('.sdc') %}-sdc{% else %}-io_pdc{% endif %} {{ name_str }}
-{% endfor %}{% endif %}
+{% endfor %}
+{% endif %}
 
 build_design_hierarchy
 
-{% if TOP %}set_root {{ TOP }}{% endif %}
+{% if TOP %}
+set_root {{ TOP }}
+{% endif %}
 
 {% if CONSTRAINTS %}
-{% set sdc_files = [] %}{% set pdc_files = [] %}
-{% for name, attr in CONSTRAINTS.items() %}{% set name_str = name|string %}
-{% if name_str.endswith('.sdc') %}{% set _ = sdc_files.append(name_str) %}{% endif %}{% set _ = pdc_files.append(name_str) %}
+{% set sdc_files = [] %}
+{% set pdc_files = [] %}
+{% for name, attr in CONSTRAINTS.items() %}
+{% set name_str = name|string %}
+{% if name_str.endswith('.sdc') %}
+{% set _ = sdc_files.append(name_str) %}
+{% endif %}
+{% set _ = pdc_files.append(name_str) %}
 {% endfor %}
 {% endif %}
 
@@ -40,52 +59,81 @@ build_design_hierarchy
 
 {% if INCLUDES or DEFINES or PARAMS %}
 configure_tool -name {SYNTHESIZE} -params {SYNPLIFY_OPTIONS:
-{% if INCLUDES %}{% for INCLUDE in INCLUDES %}
+
+{% if INCLUDES %}
+{% for INCLUDE in INCLUDES %}
   set_option -include_path "{{ INCLUDE }}"
-{% endfor %}{% endif %}
-{% if DEFINES %}{% for key, value in DEFINES.items() %}
+{% endfor %}
+{% endif %}
+
+{% if DEFINES %}
+{% for key, value in DEFINES.items() %}
   set_option -hdl_define -set {{ key }}={{ value }}
-{% endfor %}{% endif %}
-{% if PARAMS %}{% for key, value in PARAMS.items() %}
+{% endfor %}
+{% endif %}
+
+{% if PARAMS %}
+{% for key, value in PARAMS.items() %}
   set_option -hdl_param -set {{ key }}={{ value }}
-{% endfor %}{% endif %}
+{% endfor %}
+{% endif %}
+
 }
 {% endif %}
 
 {{ POSTCFG }}
 
 close_project
+
 {% endif %}
 
-#--[ Design flow ]-------------------------------------------------------------
+{# ------------------------------------------------------------------------- #}
+{# Design flow                                                               #}
+{# ------------------------------------------------------------------------- #}
 
 {% if SYN or PAR or BIT %}
+
 open_project {{ PROJECT }}/{{ PROJECT }}.prjx
 
+{# Synthesis --------------------------------------------------------------- #}
+
 {% if SYN %}
+
 {{ PRESYN }}
 
 run_tool -name {SYNTHESIZE}
 
 {{ POSTSYN }}
+
 {% endif %}
 
+{# Place and Route --------------------------------------------------------- #}
+
 {% if PAR %}
+
 {{ PREPAR }}
 
 run_tool -name {PLACEROUTE}
 run_tool -name {VERIFYTIMING}
 
 {{ POSTPAR }}
+
 {% endif %}
 
+{# Bitstream generation ---------------------------------------------------- #}
+
 {% if BIT %}
+
 {{ PREBIT }}
 
 run_tool -name {GENERATEPROGRAMMINGFILE}
 
 {{ POSTBIT }}
+
 {% endif %}
 
+{# ------------------------------------------------------------------------- #}
+
 close_project
+
 {% endif %}
diff --git a/pyfpga/templates/openflow-prog.jinja b/pyfpga/templates/openflow-prog.jinja
index fc1c1105..637a3c7c 100644
--- a/pyfpga/templates/openflow-prog.jinja
+++ b/pyfpga/templates/openflow-prog.jinja
@@ -3,6 +3,7 @@
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
+#}
 
 set -e
 
diff --git a/pyfpga/templates/openflow.jinja b/pyfpga/templates/openflow.jinja
index d29cbbc5..338cb74e 100644
--- a/pyfpga/templates/openflow.jinja
+++ b/pyfpga/templates/openflow.jinja
@@ -1,35 +1,48 @@
+{#
 #
 # Copyright (C) 2020-2024 Rodrigo A. Melo
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
+#}
 
 set -e
 
 DOCKER="docker run --user $(id -u):$(id -g) --rm -v $HOME:$HOME -w $PWD"
 
-# Synthesis -------------------------------------------------------------------
+{# ------------------------------------------------------------------------- #}
+{# Design flow                                                               #}
+{# ------------------------------------------------------------------------- #}
+
+{# Synthesis --------------------------------------------------------------- #}
 
 {% if SYN %}
 $DOCKER hdlc/ghdl:yosys /bin/bash -c "
 {{ PRESYN }}
 yosys -Q -m ghdl -p '
+
 {% if INCLUDES %}
 verilog_defaults -add{% for path in INCLUDES %} -I{{ path }}{% endfor %}
 {% endif %}
+
 {% if DEFINES %}
 verilog_defines{% for key, value in DEFINES.items() %} -D{{ key }}={{ value }}{% endfor %}
 {% endif %}
-{% if FILES %}{% for name, attr in FILES.items() %}
+
+{% if FILES %}
+{% for name, attr in FILES.items() %}
 {% if attr.hdl == "vlog" %}
 read_verilog -defer {{ name }}
 {% elif attr.hdl == "slog" %}
 read_verilog -defer -sv {{ name }}
 {% endif %}
-{% endfor %}{% endif %}
+{% endfor %}
+{% endif %}
+
 {% if PARAMS %}
 chparam{% for key, value in PARAMS.items() %} -set {{ key }} {{ value }}{% endfor %}
 {% endif %}
+
 synth -top {{ TOP }}
 synth_{{ FAMILY }} -top {{ TOP }} -json {{ PROJECT }}.json
 '
@@ -37,6 +50,7 @@ synth_{{ FAMILY }} -top {{ TOP }} -json {{ PROJECT }}.json
 "
 {% endif %}
 
+{#
 #SYNTH=
 #WRITE=
 #if [[ $BACKEND == "vivado" ]]; then
@@ -53,8 +67,9 @@ synth_{{ FAMILY }} -top {{ TOP }} -json {{ PROJECT }}.json
 #    SYNTH="synth -top $TOP"
 #    WRITE="write_verilog $PROJECT.v"
 #fi
+#}
 
-# Place and Route -------------------------------------------------------------
+{# Place and Route --------------------------------------------------------- #}
 
 {% if PAR %}
 
@@ -89,7 +104,7 @@ nextpnr-ecp5 --{{ DEVICE }} --package {{ PACKAGE }} $CONSTRAINT --json {{ PROJEC
 
 {% endif %}
 
-# Bitstream -------------------------------------------------------------------
+{# Bitstream generation ---------------------------------------------------- #}
 
 {% if BIT %}
 
diff --git a/pyfpga/templates/quartus-prog.jinja b/pyfpga/templates/quartus-prog.jinja
index 62839a6b..f33a7fb6 100644
--- a/pyfpga/templates/quartus-prog.jinja
+++ b/pyfpga/templates/quartus-prog.jinja
@@ -1,8 +1,10 @@
+{#
 #
 # Copyright (C) 2015-2024 Rodrigo A. Melo
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
+#}
 
 RESULT=$(jtagconfig)
 echo "$RESULT"
diff --git a/pyfpga/templates/quartus.jinja b/pyfpga/templates/quartus.jinja
index 1caa2108..acd221ea 100644
--- a/pyfpga/templates/quartus.jinja
+++ b/pyfpga/templates/quartus.jinja
@@ -1,19 +1,25 @@
+{#
 #
 # Copyright (C) 2015-2024 Rodrigo A. Melo
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
+#}
 
-#--[ Project configuration ]---------------------------------------------------
+{# ------------------------------------------------------------------------- #}
+{# Project configuration                                                     #}
+{# ------------------------------------------------------------------------- #}
 
 {% if CFG %}
+
 package require ::quartus::project
 project_new {{ PROJECT }} -overwrite
 set_global_assignment -name DEVICE {{ PART }}
 
 {{ PRECFG }}
 
-{% if FILES %}{% for name, attr in FILES.items() %}
+{% if FILES %}
+{% for name, attr in FILES.items() %}
 {% if attr.hdl == "vhdl" %}
 set_global_assignment -name VHDL_FILE {{ name }} {% if 'lib' in attr %} -library {{ attr.lib }}{% endif %}
 {% elif attr.hdl == "vlog" %}
@@ -21,66 +27,97 @@ set_global_assignment -name VERILOG_FILE {{ name }}
 {% elif attr.hdl == "slog" %}
 set_global_assignment -name SYSTEMVERILOG_FILE {{ name }}
 {% endif %}
-{% endfor %}{% endif %}
+{% endfor %}
+{% endif %}
 
-{% if CONSTRAINTS %}{% for name, attr in CONSTRAINTS.items() %}{% set name_str = name|string %}
+{% if CONSTRAINTS %}
+{% for name, attr in CONSTRAINTS.items() %}
+{% set name_str = name|string %}
 {% if name_str.endswith('.sdc') %}
 set_global_assignment -name SDC_FILE {{ name_str }}
 {% else %}
 source {{ name_str }}
 {% endif %}
-{% endfor %}{% endif %}
+{% endfor %}
+{% endif %}
 
-{% if TOP %}set_global_assignment -name TOP_LEVEL_ENTITY {{ TOP }}{% endif %}
+{% if TOP %}
+set_global_assignment -name TOP_LEVEL_ENTITY {{ TOP }}
+{% endif %}
 
-{% if INCLUDES %}{% for INCLUDE in INCLUDES %}
+{% if INCLUDES %}
+{% for INCLUDE in INCLUDES %}
 set_global_assignment -name SEARCH_PATH {{ INCLUDE }}
-{% endfor %}{% endif %}
+{% endfor %}
+{% endif %}
 
-{% if DEFINES %}{% for key, value in DEFINES.items() %}
+{% if DEFINES %}
+{% for key, value in DEFINES.items() %}
 set_global_assignment -name VERILOG_MACRO {{ key }}={{ value }}
-{% endfor %}{% endif %}
+{% endfor %}
+{% endif %}
 
-{% if PARAMS %}{% for key, value in PARAMS.items() %}
+{% if PARAMS %}
+{% for key, value in PARAMS.items() %}
 set_parameter -name {{ key }} {{ value }}
-{% endfor %}{% endif %}
+{% endfor %}
+{% endif %}
 
 {{ POSTCFG }}
 
 project_close
+
 {% endif %}
 
-#--[ Design flow ]-------------------------------------------------------------
+{# ------------------------------------------------------------------------- #}
+{# Design flow                                                               #}
+{# ------------------------------------------------------------------------- #}
 
 {% if SYN or PAR or BIT %}
+
 package require ::quartus::flow
 project_open -force {{ PROJECT }}.qpf
 # set_global_assignment -name NUM_PARALLEL_PROCESSORS ALL
 
+{# Synthesis --------------------------------------------------------------- #}
+
 {% if SYN %}
+
 {{ PRESYN }}
 
 execute_module -tool map
 
 {{ POSTSYN }}
+
 {% endif %}
 
+{# Place and Route --------------------------------------------------------- #}
+
 {% if PAR %}
+
 {{ PREPAR }}
 
 execute_module -tool fit
 execute_module -tool sta
 
 {{ POSTPAR }}
+
 {% endif %}
 
+{# Bitstream generation ---------------------------------------------------- #}
+
 {% if BIT %}
+
 {{ PREBIT }}
 
 execute_module -tool asm
 
 {{ POSTBIT }}
+
 {% endif %}
 
+{# ------------------------------------------------------------------------- #}
+
 project_close
+
 {% endif %}
diff --git a/pyfpga/templates/vivado-prog.jinja b/pyfpga/templates/vivado-prog.jinja
index 7b148b22..c2d9a9cb 100644
--- a/pyfpga/templates/vivado-prog.jinja
+++ b/pyfpga/templates/vivado-prog.jinja
@@ -1,8 +1,10 @@
+{#
 #
 # Copyright (C) 2015-2024 Rodrigo A. Melo
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
+#}
 
 if { [ catch { open_hw_manager } ] } { open_hw }
 connect_hw_server
diff --git a/pyfpga/templates/vivado.jinja b/pyfpga/templates/vivado.jinja
index 6a40c459..6c303254 100644
--- a/pyfpga/templates/vivado.jinja
+++ b/pyfpga/templates/vivado.jinja
@@ -1,12 +1,17 @@
+{#
 #
 # Copyright (C) 2015-2024 Rodrigo A. Melo
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
+#}
 
-#--[ Project configuration ]---------------------------------------------------
+{# ------------------------------------------------------------------------- #}
+{# Project configuration                                                     #}
+{# ------------------------------------------------------------------------- #}
 
 {% if CFG %}
+
 create_project -force {{ PROJECT }}
 set_property SOURCE_MGMT_MODE None [current_project]
 set_property STEPS.SYNTH_DESIGN.ARGS.ASSERT true [get_runs synth_1]
@@ -14,12 +19,15 @@ set_property PART {{ PART }} [current_project]
 
 {{ PRECFG }}
 
-{% if FILES %}{% for name, attr in FILES.items() %}
+{% if FILES %}
+{% for name, attr in FILES.items() %}
 add_file {{ name }}
 {% if 'lib' in attr %}set_property library {{ attr.lib }} [get_files {{ name }}]{% endif %}
-{% endfor %}{% endif %}
+{% endfor %}
+{% endif %}
 
-{% if CONSTRAINTS %}{% for name, attr in CONSTRAINTS.items() %}
+{% if CONSTRAINTS %}
+{% for name, attr in CONSTRAINTS.items() %}
 add_file -fileset constrs_1 {{ name }}
 {% if attr == "syn" %}
 set_property USED_IN_IMPLEMENTATION FALSE [get_files {{ name }}]
@@ -27,16 +35,19 @@ set_property USED_IN_IMPLEMENTATION FALSE [get_files {{ name }}]
 set_property USED_IN_SYNTHESIS FALSE [get_files {{ name }}]
 {% endif %}
 {% if loop.first %}set_property TARGET_CONSTRS_FILE {{ name }} [current_fileset -constrset]{% endif %}
-{% endfor %}{% endif %}
+{% endfor %}
+{% endif %}
 
-{% if TOP %}set_property TOP {{ TOP }} [current_fileset]{% endif %}
+{% if TOP %}
+set_property TOP {{ TOP }} [current_fileset]
+{% endif %}
 
 {% if INCLUDES %}
 set_property INCLUDE_DIRS { {{ INCLUDES | join(' ') }} } [current_fileset]
 {% endif %}
 
 {% if DEFINES %}
-set_property VERILOG_DEFINE { {{ DEFINES.items() | map('join', '=') | join(' ') }} }  [current_fileset]
+set_property VERILOG_DEFINE { {{ DEFINES.items() | map('join', '=') | join(' ') }} } [current_fileset]
 {% endif %}
 
 {% if PARAMS %}
@@ -46,14 +57,21 @@ set_property GENERIC { {{ PARAMS.items() | map('join', '=') | join(' ') }} } -ob
 {{ POSTCFG }}
 
 close_project
+
 {% endif %}
 
-#--[ Design flow ]-------------------------------------------------------------
+{# ------------------------------------------------------------------------- #}
+{# Design flow                                                               #}
+{# ------------------------------------------------------------------------- #}
 
 {% if SYN or PAR or BIT %}
+
 open_project {{ PROJECT }}
 
+{# Synthesis --------------------------------------------------------------- #}
+
 {% if SYN %}
+
 {{ PRESYN }}
 
 # PRESYNTH
@@ -62,12 +80,17 @@ reset_run synth_1
 launch_runs synth_1
 wait_on_run synth_1
 #report_property [get_runs synth_1]
+
 if { [get_property STATUS [get_runs synth_1]] ne "synth_design Complete!" } { exit 1 }
 
 {{ POSTSYN }}
+
 {% endif %}
 
+{# Place and Route --------------------------------------------------------- #}
+
 {% if PAR %}
+
 {{ PREPAR }}
 
 reset_run impl_1
@@ -77,9 +100,13 @@ wait_on_run impl_1
 if { [get_property STATUS [get_runs impl_1]] ne "route_design Complete!" } { exit 1 }
 
 {{ POSTPAR }}
+
 {% endif %}
 
+{# Bitstream generation ---------------------------------------------------- #}
+
 {% if BIT %}
+
 {{ PREBIT }}
 
 open_run impl_1
@@ -87,7 +114,11 @@ write_bitstream -force {{ PROJECT }}
 write_debug_probes -force -quiet {{ PROJECT }}.ltx
 
 {{ POSTBIT }}
+
 {% endif %}
 
+{# ------------------------------------------------------------------------- #}
+
 close_project
+
 {% endif %}

From 0efbd0e098eb683f1629455cbf3946e5a9489ea9 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 7 Jul 2024 22:17:25 -0300
Subject: [PATCH 160/248] Copyright notice updated

---
 pyfpga/helpers/bitprog.py            | 16 ++--------------
 pyfpga/helpers/hdl2bit.py            | 16 ++--------------
 pyfpga/helpers/prj2bit.py            | 16 ++--------------
 pyfpga/ise.py                        |  2 +-
 pyfpga/libero.py                     |  2 +-
 pyfpga/openflow.py                   |  2 +-
 pyfpga/project.py                    |  2 +-
 pyfpga/quartus.py                    |  2 +-
 pyfpga/templates/ise-prog.jinja      |  2 +-
 pyfpga/templates/ise.jinja           |  2 +-
 pyfpga/templates/libero-prog.jinja   |  2 +-
 pyfpga/templates/libero.jinja        |  2 +-
 pyfpga/templates/openflow-prog.jinja |  2 +-
 pyfpga/templates/openflow.jinja      |  2 +-
 pyfpga/templates/quartus-prog.jinja  |  2 +-
 pyfpga/templates/quartus.jinja       |  2 +-
 pyfpga/templates/vivado-prog.jinja   |  2 +-
 pyfpga/templates/vivado.jinja        |  2 +-
 pyfpga/vivado.py                     |  2 +-
 tests/mocks/impact                   |  2 +-
 tests/mocks/libero                   |  2 +-
 tests/mocks/quartus_pgm              |  2 +-
 tests/mocks/quartus_sh               |  2 +-
 tests/mocks/vivado                   |  2 +-
 tests/mocks/xtclsh                   |  2 +-
 25 files changed, 28 insertions(+), 64 deletions(-)

diff --git a/pyfpga/helpers/bitprog.py b/pyfpga/helpers/bitprog.py
index a15e18a3..0282f263 100644
--- a/pyfpga/helpers/bitprog.py
+++ b/pyfpga/helpers/bitprog.py
@@ -1,20 +1,8 @@
 #!/usr/bin/env python3
 #
-# Copyright (C) 2020 INTI
-# Copyright (C) 2020 Rodrigo A. Melo
+# Copyright (C) 2020 PyFPGA Project
 #
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+# SPDX-License-Identifier: GPL-3.0-or-later
 #
 
 """
diff --git a/pyfpga/helpers/hdl2bit.py b/pyfpga/helpers/hdl2bit.py
index 87ed4159..8b6d9173 100644
--- a/pyfpga/helpers/hdl2bit.py
+++ b/pyfpga/helpers/hdl2bit.py
@@ -1,20 +1,8 @@
 #!/usr/bin/env python3
 #
-# Copyright (C) 2020 INTI
-# Copyright (C) 2020 Rodrigo A. Melo
+# Copyright (C) 2020 PyFPGA Project
 #
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+# SPDX-License-Identifier: GPL-3.0-or-later
 #
 
 """
diff --git a/pyfpga/helpers/prj2bit.py b/pyfpga/helpers/prj2bit.py
index 1cd8a74e..4a0a6886 100644
--- a/pyfpga/helpers/prj2bit.py
+++ b/pyfpga/helpers/prj2bit.py
@@ -1,20 +1,8 @@
 #!/usr/bin/env python3
 #
-# Copyright (C) 2020 INTI
-# Copyright (C) 2020 Rodrigo A. Melo
+# Copyright (C) 2020 PyFPGA Project
 #
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+# SPDX-License-Identifier: GPL-3.0-or-later
 #
 
 """
diff --git a/pyfpga/ise.py b/pyfpga/ise.py
index 9e173f2f..b8f33706 100644
--- a/pyfpga/ise.py
+++ b/pyfpga/ise.py
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2019-2024 Rodrigo A. Melo
+# Copyright (C) 2019-2024 PyFPGA Project
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
diff --git a/pyfpga/libero.py b/pyfpga/libero.py
index 813eb3da..7c07a6a1 100644
--- a/pyfpga/libero.py
+++ b/pyfpga/libero.py
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2019-2024 Rodrigo A. Melo
+# Copyright (C) 2019-2024 PyFPGA Project
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
diff --git a/pyfpga/openflow.py b/pyfpga/openflow.py
index a2e4092d..63712a85 100644
--- a/pyfpga/openflow.py
+++ b/pyfpga/openflow.py
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2020-2024 Rodrigo A. Melo
+# Copyright (C) 2020-2024 PyFPGA Project
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
diff --git a/pyfpga/project.py b/pyfpga/project.py
index b77b8159..19570036 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2019-2024 Rodrigo A. Melo
+# Copyright (C) 2019-2024 PyFPGA Project
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
diff --git a/pyfpga/quartus.py b/pyfpga/quartus.py
index 10a5927e..0cc5f93d 100644
--- a/pyfpga/quartus.py
+++ b/pyfpga/quartus.py
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2019-2024 Rodrigo A. Melo
+# Copyright (C) 2019-2024 PyFPGA Project
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
diff --git a/pyfpga/templates/ise-prog.jinja b/pyfpga/templates/ise-prog.jinja
index 0f0e38c9..1c2203ee 100644
--- a/pyfpga/templates/ise-prog.jinja
+++ b/pyfpga/templates/ise-prog.jinja
@@ -1,6 +1,6 @@
 {#
 #
-# Copyright (C) 2015-2024 Rodrigo A. Melo
+# Copyright (C) 2015-2024 PyFPGA Project
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
diff --git a/pyfpga/templates/ise.jinja b/pyfpga/templates/ise.jinja
index 10811ebf..73c5fce9 100644
--- a/pyfpga/templates/ise.jinja
+++ b/pyfpga/templates/ise.jinja
@@ -1,6 +1,6 @@
 {#
 #
-# Copyright (C) 2015-2024 Rodrigo A. Melo
+# Copyright (C) 2015-2024 PyFPGA Project
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
diff --git a/pyfpga/templates/libero-prog.jinja b/pyfpga/templates/libero-prog.jinja
index 5bd27ab5..f2369645 100644
--- a/pyfpga/templates/libero-prog.jinja
+++ b/pyfpga/templates/libero-prog.jinja
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2015-2024 Rodrigo A. Melo
+# Copyright (C) 2015-2024 PyFPGA Project
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
diff --git a/pyfpga/templates/libero.jinja b/pyfpga/templates/libero.jinja
index f62d78dc..3f061cdf 100644
--- a/pyfpga/templates/libero.jinja
+++ b/pyfpga/templates/libero.jinja
@@ -1,6 +1,6 @@
 {#
 #
-# Copyright (C) 2015-2024 Rodrigo A. Melo
+# Copyright (C) 2015-2024 PyFPGA Project
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
diff --git a/pyfpga/templates/openflow-prog.jinja b/pyfpga/templates/openflow-prog.jinja
index 637a3c7c..81942426 100644
--- a/pyfpga/templates/openflow-prog.jinja
+++ b/pyfpga/templates/openflow-prog.jinja
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2020-2024 Rodrigo A. Melo
+# Copyright (C) 2020-2024 PyFPGA Project
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
diff --git a/pyfpga/templates/openflow.jinja b/pyfpga/templates/openflow.jinja
index 338cb74e..15a82f4a 100644
--- a/pyfpga/templates/openflow.jinja
+++ b/pyfpga/templates/openflow.jinja
@@ -1,6 +1,6 @@
 {#
 #
-# Copyright (C) 2020-2024 Rodrigo A. Melo
+# Copyright (C) 2020-2024 PyFPGA Project
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
diff --git a/pyfpga/templates/quartus-prog.jinja b/pyfpga/templates/quartus-prog.jinja
index f33a7fb6..23786f22 100644
--- a/pyfpga/templates/quartus-prog.jinja
+++ b/pyfpga/templates/quartus-prog.jinja
@@ -1,6 +1,6 @@
 {#
 #
-# Copyright (C) 2015-2024 Rodrigo A. Melo
+# Copyright (C) 2015-2024 PyFPGA Project
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
diff --git a/pyfpga/templates/quartus.jinja b/pyfpga/templates/quartus.jinja
index acd221ea..fa26aa9a 100644
--- a/pyfpga/templates/quartus.jinja
+++ b/pyfpga/templates/quartus.jinja
@@ -1,6 +1,6 @@
 {#
 #
-# Copyright (C) 2015-2024 Rodrigo A. Melo
+# Copyright (C) 2015-2024 PyFPGA Project
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
diff --git a/pyfpga/templates/vivado-prog.jinja b/pyfpga/templates/vivado-prog.jinja
index c2d9a9cb..72ccb91d 100644
--- a/pyfpga/templates/vivado-prog.jinja
+++ b/pyfpga/templates/vivado-prog.jinja
@@ -1,6 +1,6 @@
 {#
 #
-# Copyright (C) 2015-2024 Rodrigo A. Melo
+# Copyright (C) 2015-2024 PyFPGA Project
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
diff --git a/pyfpga/templates/vivado.jinja b/pyfpga/templates/vivado.jinja
index 6c303254..5b80a7d5 100644
--- a/pyfpga/templates/vivado.jinja
+++ b/pyfpga/templates/vivado.jinja
@@ -1,6 +1,6 @@
 {#
 #
-# Copyright (C) 2015-2024 Rodrigo A. Melo
+# Copyright (C) 2015-2024 PyFPGA Project
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
diff --git a/pyfpga/vivado.py b/pyfpga/vivado.py
index c0a48864..3cc39d6e 100644
--- a/pyfpga/vivado.py
+++ b/pyfpga/vivado.py
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2019-2024 Rodrigo A. Melo
+# Copyright (C) 2019-2024 PyFPGA Project
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
diff --git a/tests/mocks/impact b/tests/mocks/impact
index 0fbbacbc..1446c5e0 100755
--- a/tests/mocks/impact
+++ b/tests/mocks/impact
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3
 
 #
-# Copyright (C) 2022-2024 Rodrigo A. Melo
+# Copyright (C) 2022-2024 PyFPGA Project
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
diff --git a/tests/mocks/libero b/tests/mocks/libero
index a4663e9d..510b9926 100755
--- a/tests/mocks/libero
+++ b/tests/mocks/libero
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3
 
 #
-# Copyright (C) 2022-2024 Rodrigo A. Melo
+# Copyright (C) 2022-2024 PyFPGA Project
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
diff --git a/tests/mocks/quartus_pgm b/tests/mocks/quartus_pgm
index 8993ca10..150e1ae9 100755
--- a/tests/mocks/quartus_pgm
+++ b/tests/mocks/quartus_pgm
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3
 
 #
-# Copyright (C) 2022-2024 Rodrigo A. Melo
+# Copyright (C) 2022-2024 PyFPGA Project
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
diff --git a/tests/mocks/quartus_sh b/tests/mocks/quartus_sh
index 472f639f..7f437145 100755
--- a/tests/mocks/quartus_sh
+++ b/tests/mocks/quartus_sh
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3
 
 #
-# Copyright (C) 2022-2024 Rodrigo A. Melo
+# Copyright (C) 2022-2024 PyFPGA Project
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
diff --git a/tests/mocks/vivado b/tests/mocks/vivado
index fb59d819..3bc95381 100755
--- a/tests/mocks/vivado
+++ b/tests/mocks/vivado
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3
 
 #
-# Copyright (C) 2022-2024 Rodrigo A. Melo
+# Copyright (C) 2022-2024 PyFPGA Project
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
diff --git a/tests/mocks/xtclsh b/tests/mocks/xtclsh
index 7621c4d9..22f66a77 100755
--- a/tests/mocks/xtclsh
+++ b/tests/mocks/xtclsh
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3
 
 #
-# Copyright (C) 2022-2024 Rodrigo A. Melo
+# Copyright (C) 2022-2024 PyFPGA Project
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #

From fa84608232053ef59e84b6862954c45acb72f194 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 7 Jul 2024 23:53:39 -0300
Subject: [PATCH 161/248] Fix paths in TCL on Windows

---
 pyfpga/project.py              |  6 +++---
 pyfpga/templates/ise.jinja     |  7 +++----
 pyfpga/templates/libero.jinja  | 10 ++++-----
 pyfpga/templates/quartus.jinja |  7 +++----
 tests/test_data.py             | 38 ++++++++++++++++++----------------
 5 files changed, 33 insertions(+), 35 deletions(-)

diff --git a/pyfpga/project.py b/pyfpga/project.py
index 19570036..16ee090e 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -66,7 +66,7 @@ def add_include(self, path):
         path = Path(path).resolve()
         if not path.is_dir():
             raise NotADirectoryError(path)
-        self.data.setdefault('includes', []).append(path)
+        self.data.setdefault('includes', []).append(path.as_posix())
 
     def _add_file(self, pathname, hdl=None, lib=None):
         files = glob.glob(pathname, recursive=True)
@@ -79,7 +79,7 @@ def _add_file(self, pathname, hdl=None, lib=None):
                 attr['hdl'] = hdl
             if lib:
                 attr['lib'] = lib
-            self.data.setdefault('files', {})[path] = attr
+            self.data.setdefault('files', {})[path.as_posix()] = attr
 
     def add_slog(self, pathname):
         """Add System Verilog file/s.
@@ -128,7 +128,7 @@ def add_cons(self, path, when='all'):
             raise FileNotFoundError(path)
         if when not in ['all', 'syn', 'par']:
             raise ValueError('Invalid only.')
-        self.data.setdefault('constraints', {})[path] = when
+        self.data.setdefault('constraints', {})[path.as_posix()] = when
 
     def add_param(self, name, value):
         """Add a Parameter/Generic Value.
diff --git a/pyfpga/templates/ise.jinja b/pyfpga/templates/ise.jinja
index 73c5fce9..647856e2 100644
--- a/pyfpga/templates/ise.jinja
+++ b/pyfpga/templates/ise.jinja
@@ -30,10 +30,9 @@ xfile add {{ name }}{% if 'lib' in attr %} -lib_vhdl {{ attr.lib }}{% endif %}
 
 {% if CONSTRAINTS %}
 {% for name, attr in CONSTRAINTS.items() %}
-{% set name_str = name|string %}
-xfile add {{ name_str }}
-{% if name_str.endswith('.xcf') %}
-project set "Synthesis Constraints File" "{{ name_str }}" -process "Synthesize - XST"
+xfile add {{ name }}
+{% if name.endswith('.xcf') %}
+project set "Synthesis Constraints File" "{{ name }}" -process "Synthesize - XST"
 {% endif %}
 {% endfor %}
 {% endif %}
diff --git a/pyfpga/templates/libero.jinja b/pyfpga/templates/libero.jinja
index 3f061cdf..b4a36d64 100644
--- a/pyfpga/templates/libero.jinja
+++ b/pyfpga/templates/libero.jinja
@@ -30,8 +30,7 @@ create_links -hdl_source {{ name }}{% if 'lib' in attr %} -library {{ attr.lib }
 
 {% if CONSTRAINTS %}
 {% for name, attr in CONSTRAINTS.items() %}
-{% set name_str = name|string %}
-create_links {% if name_str.endswith('.sdc') %}-sdc{% else %}-io_pdc{% endif %} {{ name_str }}
+create_links {% if name.endswith('.sdc') %}-sdc{% else %}-io_pdc{% endif %} {{ name }}
 {% endfor %}
 {% endif %}
 
@@ -45,11 +44,10 @@ set_root {{ TOP }}
 {% set sdc_files = [] %}
 {% set pdc_files = [] %}
 {% for name, attr in CONSTRAINTS.items() %}
-{% set name_str = name|string %}
-{% if name_str.endswith('.sdc') %}
-{% set _ = sdc_files.append(name_str) %}
+{% if name.endswith('.sdc') %}
+{% set _ = sdc_files.append(name) %}
 {% endif %}
-{% set _ = pdc_files.append(name_str) %}
+{% set _ = pdc_files.append(name) %}
 {% endfor %}
 {% endif %}
 
diff --git a/pyfpga/templates/quartus.jinja b/pyfpga/templates/quartus.jinja
index fa26aa9a..29826df1 100644
--- a/pyfpga/templates/quartus.jinja
+++ b/pyfpga/templates/quartus.jinja
@@ -32,11 +32,10 @@ set_global_assignment -name SYSTEMVERILOG_FILE {{ name }}
 
 {% if CONSTRAINTS %}
 {% for name, attr in CONSTRAINTS.items() %}
-{% set name_str = name|string %}
-{% if name_str.endswith('.sdc') %}
-set_global_assignment -name SDC_FILE {{ name_str }}
+{% if name.endswith('.sdc') %}
+set_global_assignment -name SDC_FILE {{ name }}
 {% else %}
-source {{ name_str }}
+source {{ name }}
 {% endif %}
 {% endfor %}
 {% endif %}
diff --git a/tests/test_data.py b/tests/test_data.py
index 250ea793..34f4c633 100644
--- a/tests/test_data.py
+++ b/tests/test_data.py
@@ -5,35 +5,37 @@
 pattern = {
     'part': 'PARTNAME',
     'includes': [
-        Path('fakedata/dir1').resolve(),
-        Path('fakedata/dir2').resolve(),
-        Path('fakedata/dir3').resolve()
+        Path('fakedata/dir1').resolve().as_posix(),
+        Path('fakedata/dir2').resolve().as_posix(),
+        Path('fakedata/dir3').resolve().as_posix()
     ],
     'files': {
-        Path('fakedata/vhdl0.vhdl').resolve(): {'hdl': 'vhdl', 'lib': 'LIB'},
-        Path('fakedata/dir1/vhdl1.vhdl').resolve(): {
+        Path('fakedata/vhdl0.vhdl').resolve().as_posix(): {
             'hdl': 'vhdl', 'lib': 'LIB'
         },
-        Path('fakedata/dir2/vhdl2.vhdl').resolve(): {
+        Path('fakedata/dir1/vhdl1.vhdl').resolve().as_posix(): {
             'hdl': 'vhdl', 'lib': 'LIB'
         },
-        Path('fakedata/dir3/vhdl3.vhdl').resolve(): {
+        Path('fakedata/dir2/vhdl2.vhdl').resolve().as_posix(): {
             'hdl': 'vhdl', 'lib': 'LIB'
         },
-        Path('fakedata/vlog0.v').resolve(): {'hdl': 'vlog'},
-        Path('fakedata/dir1/vlog1.v').resolve(): {'hdl': 'vlog'},
-        Path('fakedata/dir2/vlog2.v').resolve(): {'hdl': 'vlog'},
-        Path('fakedata/dir3/vlog3.v').resolve(): {'hdl': 'vlog'},
-        Path('fakedata/slog0.sv').resolve(): {'hdl': 'slog'},
-        Path('fakedata/dir1/slog1.sv').resolve(): {'hdl': 'slog'},
-        Path('fakedata/dir2/slog2.sv').resolve(): {'hdl': 'slog'},
-        Path('fakedata/dir3/slog3.sv').resolve(): {'hdl': 'slog'}
+        Path('fakedata/dir3/vhdl3.vhdl').resolve().as_posix(): {
+            'hdl': 'vhdl', 'lib': 'LIB'
+        },
+        Path('fakedata/vlog0.v').resolve().as_posix(): {'hdl': 'vlog'},
+        Path('fakedata/dir1/vlog1.v').resolve().as_posix(): {'hdl': 'vlog'},
+        Path('fakedata/dir2/vlog2.v').resolve().as_posix(): {'hdl': 'vlog'},
+        Path('fakedata/dir3/vlog3.v').resolve().as_posix(): {'hdl': 'vlog'},
+        Path('fakedata/slog0.sv').resolve().as_posix(): {'hdl': 'slog'},
+        Path('fakedata/dir1/slog1.sv').resolve().as_posix(): {'hdl': 'slog'},
+        Path('fakedata/dir2/slog2.sv').resolve().as_posix(): {'hdl': 'slog'},
+        Path('fakedata/dir3/slog3.sv').resolve().as_posix(): {'hdl': 'slog'}
     },
     'top': 'TOPNAME',
     'constraints': {
-        Path('fakedata/cons/all.xdc').resolve(): 'all',
-        Path('fakedata/cons/syn.xdc').resolve(): 'syn',
-        Path('fakedata/cons/par.xdc').resolve(): 'par'
+        Path('fakedata/cons/all.xdc').resolve().as_posix(): 'all',
+        Path('fakedata/cons/syn.xdc').resolve().as_posix(): 'syn',
+        Path('fakedata/cons/par.xdc').resolve().as_posix(): 'par'
     },
     'params': {
         'PAR1': 'VAL1',

From f437eb7b7d4a97f77198b25a2d42b3a4e4055675 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 8 Jul 2024 22:34:45 -0300
Subject: [PATCH 162/248] Added comments to easily identify each section

---
 pyfpga/templates/ise.jinja      | 38 +++++++++-------------------
 pyfpga/templates/libero.jinja   | 44 +++++++++++----------------------
 pyfpga/templates/openflow.jinja | 16 +++---------
 pyfpga/templates/quartus.jinja  | 38 +++++++++-------------------
 pyfpga/templates/vivado.jinja   | 38 +++++++++-------------------
 5 files changed, 50 insertions(+), 124 deletions(-)

diff --git a/pyfpga/templates/ise.jinja b/pyfpga/templates/ise.jinja
index 647856e2..6af287ca 100644
--- a/pyfpga/templates/ise.jinja
+++ b/pyfpga/templates/ise.jinja
@@ -6,11 +6,7 @@
 #
 #}
 
-{# ------------------------------------------------------------------------- #}
-{# Project configuration                                                     #}
-{# ------------------------------------------------------------------------- #}
-
-{% if CFG %}
+{% if CFG %}# Project configuration -------------------------------------------------------
 
 if { [ file exists {{ PROJECT }}.xise ] } { file delete {{ PROJECT }}.xise }
 project new {{ PROJECT }}.xise
@@ -21,14 +17,14 @@ project set speed  -{{ SPEED }}
 
 {{ PRECFG }}
 
-{% if FILES %}
+{% if FILES %}# Files inclusion
 {% for name, attr in FILES.items() %}
 {% if 'lib' in attr %}lib_vhdl new {{ attr.lib }}{% endif %}
 xfile add {{ name }}{% if 'lib' in attr %} -lib_vhdl {{ attr.lib }}{% endif %}
 {% endfor %}
 {% endif %}
 
-{% if CONSTRAINTS %}
+{% if CONSTRAINTS %}# Constraints inclusion
 {% for name, attr in CONSTRAINTS.items() %}
 xfile add {{ name }}
 {% if name.endswith('.xcf') %}
@@ -37,19 +33,19 @@ project set "Synthesis Constraints File" "{{ name }}" -process "Synthesize - XST
 {% endfor %}
 {% endif %}
 
-{% if TOP %}
+{% if TOP %}# Top-level specification
 project set top {{ TOP }}
 {% endif %}
 
-{% if INCLUDES %}
+{% if INCLUDES %}# Verilog Includes
 project set "Verilog Include Directories" "{{ INCLUDES | join('|') }}" -process "Synthesize - XST"
 {% endif %}
 
-{% if DEFINES %}
+{% if DEFINES %}# Verilog Defines
 project set "Verilog Macros" "{{ DEFINES.items() | map('join', '=') | join(' | ') }}" -process "Synthesize - XST"
 {% endif %}
 
-{% if PARAMS %}
+{% if PARAMS %}# Verilog Parameters / VHDL Generics
 project set "Generics, Parameters" "{{ PARAMS.items() | map('join', '=') | join(' ') }}" -process "Synthesize - XST"
 {% endif %}
 
@@ -59,17 +55,11 @@ project close
 
 {% endif %}
 
-{# ------------------------------------------------------------------------- #}
-{# Design flow                                                               #}
-{# ------------------------------------------------------------------------- #}
-
-{% if SYN or PAR or BIT %}
+{% if SYN or PAR or BIT %}# Design flow -----------------------------------------------------------------
 
 project open {{ PROJECT }}.xise
 
-{# Synthesis --------------------------------------------------------------- #}
-
-{% if SYN %}
+{% if SYN %}# Synthesis
 
 {{ PRESYN }}
 
@@ -83,9 +73,7 @@ if { [process get "Synthesize" status] == "errors" } { exit 1 }
 
 {% endif %}
 
-{# Place and Route --------------------------------------------------------- #}
-
-{% if PAR %}
+{% if PAR %}# Place and Route
 
 {{ PREPAR }}
 
@@ -100,9 +88,7 @@ if { [process get "Place & Route" status] == "errors" } { exit 1 }
 
 {% endif %}
 
-{# Bitstream generation ---------------------------------------------------- #}
-
-{% if BIT %}
+{% if BIT %}# Bitstream generation
 
 {{ PREBIT }}
 
@@ -114,8 +100,6 @@ catch { file rename -force {{ TOP }}.bit {{ PROJECT }}.bit }
 
 {% endif %}
 
-{# ------------------------------------------------------------------------- #}
-
 project close
 
 {% endif %}
diff --git a/pyfpga/templates/libero.jinja b/pyfpga/templates/libero.jinja
index b4a36d64..a4be188f 100644
--- a/pyfpga/templates/libero.jinja
+++ b/pyfpga/templates/libero.jinja
@@ -6,11 +6,7 @@
 #
 #}
 
-{# ------------------------------------------------------------------------- #}
-{# Project configuration                                                     #}
-{# ------------------------------------------------------------------------- #}
-
-{% if CFG %}
+{% if CFG %}# Project configuration -------------------------------------------------------
 
 if { [ file exists {{ PROJECT }} ] } { file delete -force -- {{ PROJECT }} }
 new_project -name {{ PROJECT }} -location {libero} -hdl {VERILOG} -family {SmartFusion2}
@@ -18,17 +14,17 @@ set_device -family {{ FAMILY }} -die {{ DEVICE }} -package {{ PACKAGE }} -speed
 
 {{ PRECFG }}
 
-{% if INCLUDES %}
+{% if INCLUDES %}# Verilog Includes (Libero)
 set_global_include_path_order -paths "{{ INCLUDES | join(' ') }}"
 {% endif %}
 
-{% if FILES %}
+{% if FILES %}# Files inclusion
 {% for name, attr in FILES.items() %}
 create_links -hdl_source {{ name }}{% if 'lib' in attr %} -library {{ attr.lib }}{% endif %}
 {% endfor %}
 {% endif %}
 
-{% if CONSTRAINTS %}
+{% if CONSTRAINTS %}# Constraints inclusion
 {% for name, attr in CONSTRAINTS.items() %}
 create_links {% if name.endswith('.sdc') %}-sdc{% else %}-io_pdc{% endif %} {{ name }}
 {% endfor %}
@@ -36,11 +32,11 @@ create_links {% if name.endswith('.sdc') %}-sdc{% else %}-io_pdc{% endif %} {{ n
 
 build_design_hierarchy
 
-{% if TOP %}
+{% if TOP %}# Top-level specification
 set_root {{ TOP }}
 {% endif %}
 
-{% if CONSTRAINTS %}
+{% if CONSTRAINTS %}# Constraints configuration
 {% set sdc_files = [] %}
 {% set pdc_files = [] %}
 {% for name, attr in CONSTRAINTS.items() %}
@@ -55,22 +51,22 @@ set_root {{ TOP }}
 {% if pdc_files %}organize_tool_files -tool {PLACEROUTE}   -file {{ pdc_files | join(' -file ') }} -module {{ TOP }} -input_type {constraint}{% endif %}
 {% if sdc_files %}organize_tool_files -tool {VERIFYTIMING} -file {{ sdc_files | join(' -file ') }} -module {{ TOP }} -input_type {constraint}{% endif %}
 
-{% if INCLUDES or DEFINES or PARAMS %}
+{% if INCLUDES or DEFINES or PARAMS %}# Synopsys configuration
 configure_tool -name {SYNTHESIZE} -params {SYNPLIFY_OPTIONS:
 
-{% if INCLUDES %}
+{% if INCLUDES %}# Verilog Includes (Synopsys)
 {% for INCLUDE in INCLUDES %}
   set_option -include_path "{{ INCLUDE }}"
 {% endfor %}
 {% endif %}
 
-{% if DEFINES %}
+{% if DEFINES %}# Verilog Defines (Synopsys)
 {% for key, value in DEFINES.items() %}
   set_option -hdl_define -set {{ key }}={{ value }}
 {% endfor %}
 {% endif %}
 
-{% if PARAMS %}
+{% if PARAMS %}# Verilog Parameters / VHDL Generics (Synopsys)
 {% for key, value in PARAMS.items() %}
   set_option -hdl_param -set {{ key }}={{ value }}
 {% endfor %}
@@ -85,17 +81,11 @@ close_project
 
 {% endif %}
 
-{# ------------------------------------------------------------------------- #}
-{# Design flow                                                               #}
-{# ------------------------------------------------------------------------- #}
-
-{% if SYN or PAR or BIT %}
+{% if SYN or PAR or BIT %}# Design flow -----------------------------------------------------------------
 
 open_project {{ PROJECT }}/{{ PROJECT }}.prjx
 
-{# Synthesis --------------------------------------------------------------- #}
-
-{% if SYN %}
+{% if SYN %}# Synthesis
 
 {{ PRESYN }}
 
@@ -105,9 +95,7 @@ run_tool -name {SYNTHESIZE}
 
 {% endif %}
 
-{# Place and Route --------------------------------------------------------- #}
-
-{% if PAR %}
+{% if PAR %}# Place and Route
 
 {{ PREPAR }}
 
@@ -118,9 +106,7 @@ run_tool -name {VERIFYTIMING}
 
 {% endif %}
 
-{# Bitstream generation ---------------------------------------------------- #}
-
-{% if BIT %}
+{% if BIT %}# Bitstream generation
 
 {{ PREBIT }}
 
@@ -130,8 +116,6 @@ run_tool -name {GENERATEPROGRAMMINGFILE}
 
 {% endif %}
 
-{# ------------------------------------------------------------------------- #}
-
 close_project
 
 {% endif %}
diff --git a/pyfpga/templates/openflow.jinja b/pyfpga/templates/openflow.jinja
index 15a82f4a..02e57662 100644
--- a/pyfpga/templates/openflow.jinja
+++ b/pyfpga/templates/openflow.jinja
@@ -10,13 +10,7 @@ set -e
 
 DOCKER="docker run --user $(id -u):$(id -g) --rm -v $HOME:$HOME -w $PWD"
 
-{# ------------------------------------------------------------------------- #}
-{# Design flow                                                               #}
-{# ------------------------------------------------------------------------- #}
-
-{# Synthesis --------------------------------------------------------------- #}
-
-{% if SYN %}
+{% if SYN %}# Synthesis
 $DOCKER hdlc/ghdl:yosys /bin/bash -c "
 {{ PRESYN }}
 yosys -Q -m ghdl -p '
@@ -69,9 +63,7 @@ synth_{{ FAMILY }} -top {{ TOP }} -json {{ PROJECT }}.json
 #fi
 #}
 
-{# Place and Route --------------------------------------------------------- #}
-
-{% if PAR %}
+{% if PAR %}# Place and Route
 
 CONSTRAINTS="{{ CONSTRAINTS | join(' ') }}"
 
@@ -104,9 +96,7 @@ nextpnr-ecp5 --{{ DEVICE }} --package {{ PACKAGE }} $CONSTRAINT --json {{ PROJEC
 
 {% endif %}
 
-{# Bitstream generation ---------------------------------------------------- #}
-
-{% if BIT %}
+{% if BIT %}# Bitstream generation
 
 {% if FAMILY == 'ice40' %}
 $DOCKER hdlc/icestorm /bin/bash -c "
diff --git a/pyfpga/templates/quartus.jinja b/pyfpga/templates/quartus.jinja
index 29826df1..dcbcb5d9 100644
--- a/pyfpga/templates/quartus.jinja
+++ b/pyfpga/templates/quartus.jinja
@@ -6,11 +6,7 @@
 #
 #}
 
-{# ------------------------------------------------------------------------- #}
-{# Project configuration                                                     #}
-{# ------------------------------------------------------------------------- #}
-
-{% if CFG %}
+{% if CFG %}# Project configuration -------------------------------------------------------
 
 package require ::quartus::project
 project_new {{ PROJECT }} -overwrite
@@ -18,7 +14,7 @@ set_global_assignment -name DEVICE {{ PART }}
 
 {{ PRECFG }}
 
-{% if FILES %}
+{% if FILES %}# Files inclusion
 {% for name, attr in FILES.items() %}
 {% if attr.hdl == "vhdl" %}
 set_global_assignment -name VHDL_FILE {{ name }} {% if 'lib' in attr %} -library {{ attr.lib }}{% endif %}
@@ -30,7 +26,7 @@ set_global_assignment -name SYSTEMVERILOG_FILE {{ name }}
 {% endfor %}
 {% endif %}
 
-{% if CONSTRAINTS %}
+{% if CONSTRAINTS %}# Constraints inclusion
 {% for name, attr in CONSTRAINTS.items() %}
 {% if name.endswith('.sdc') %}
 set_global_assignment -name SDC_FILE {{ name }}
@@ -40,23 +36,23 @@ source {{ name }}
 {% endfor %}
 {% endif %}
 
-{% if TOP %}
+{% if TOP %}# Top-level specification
 set_global_assignment -name TOP_LEVEL_ENTITY {{ TOP }}
 {% endif %}
 
-{% if INCLUDES %}
+{% if INCLUDES %}# Verilog Includes
 {% for INCLUDE in INCLUDES %}
 set_global_assignment -name SEARCH_PATH {{ INCLUDE }}
 {% endfor %}
 {% endif %}
 
-{% if DEFINES %}
+{% if DEFINES %}# Verilog Defines
 {% for key, value in DEFINES.items() %}
 set_global_assignment -name VERILOG_MACRO {{ key }}={{ value }}
 {% endfor %}
 {% endif %}
 
-{% if PARAMS %}
+{% if PARAMS %}# Verilog Parameters / VHDL Generics
 {% for key, value in PARAMS.items() %}
 set_parameter -name {{ key }} {{ value }}
 {% endfor %}
@@ -68,19 +64,13 @@ project_close
 
 {% endif %}
 
-{# ------------------------------------------------------------------------- #}
-{# Design flow                                                               #}
-{# ------------------------------------------------------------------------- #}
-
-{% if SYN or PAR or BIT %}
+{% if SYN or PAR or BIT %}# Design flow -----------------------------------------------------------------
 
 package require ::quartus::flow
 project_open -force {{ PROJECT }}.qpf
 # set_global_assignment -name NUM_PARALLEL_PROCESSORS ALL
 
-{# Synthesis --------------------------------------------------------------- #}
-
-{% if SYN %}
+{% if SYN %}# Synthesis
 
 {{ PRESYN }}
 
@@ -90,9 +80,7 @@ execute_module -tool map
 
 {% endif %}
 
-{# Place and Route --------------------------------------------------------- #}
-
-{% if PAR %}
+{% if PAR %}# Place and Route
 
 {{ PREPAR }}
 
@@ -103,9 +91,7 @@ execute_module -tool sta
 
 {% endif %}
 
-{# Bitstream generation ---------------------------------------------------- #}
-
-{% if BIT %}
+{% if BIT %}# Bitstream generation
 
 {{ PREBIT }}
 
@@ -115,8 +101,6 @@ execute_module -tool asm
 
 {% endif %}
 
-{# ------------------------------------------------------------------------- #}
-
 project_close
 
 {% endif %}
diff --git a/pyfpga/templates/vivado.jinja b/pyfpga/templates/vivado.jinja
index 5b80a7d5..19a53aee 100644
--- a/pyfpga/templates/vivado.jinja
+++ b/pyfpga/templates/vivado.jinja
@@ -6,11 +6,7 @@
 #
 #}
 
-{# ------------------------------------------------------------------------- #}
-{# Project configuration                                                     #}
-{# ------------------------------------------------------------------------- #}
-
-{% if CFG %}
+{% if CFG %}# Project configuration -------------------------------------------------------
 
 create_project -force {{ PROJECT }}
 set_property SOURCE_MGMT_MODE None [current_project]
@@ -19,14 +15,14 @@ set_property PART {{ PART }} [current_project]
 
 {{ PRECFG }}
 
-{% if FILES %}
+{% if FILES %}# Files inclusion
 {% for name, attr in FILES.items() %}
 add_file {{ name }}
 {% if 'lib' in attr %}set_property library {{ attr.lib }} [get_files {{ name }}]{% endif %}
 {% endfor %}
 {% endif %}
 
-{% if CONSTRAINTS %}
+{% if CONSTRAINTS %}# Constraints inclusion
 {% for name, attr in CONSTRAINTS.items() %}
 add_file -fileset constrs_1 {{ name }}
 {% if attr == "syn" %}
@@ -38,19 +34,19 @@ set_property USED_IN_SYNTHESIS FALSE [get_files {{ name }}]
 {% endfor %}
 {% endif %}
 
-{% if TOP %}
+{% if TOP %}# Top-level specification
 set_property TOP {{ TOP }} [current_fileset]
 {% endif %}
 
-{% if INCLUDES %}
+{% if INCLUDES %}# Verilog Includes
 set_property INCLUDE_DIRS { {{ INCLUDES | join(' ') }} } [current_fileset]
 {% endif %}
 
-{% if DEFINES %}
+{% if DEFINES %}# Verilog Defines
 set_property VERILOG_DEFINE { {{ DEFINES.items() | map('join', '=') | join(' ') }} } [current_fileset]
 {% endif %}
 
-{% if PARAMS %}
+{% if PARAMS %}# Verilog Parameters / VHDL Generics
 set_property GENERIC { {{ PARAMS.items() | map('join', '=') | join(' ') }} } -objects [get_filesets sources_1]
 {% endif %}
 
@@ -60,17 +56,11 @@ close_project
 
 {% endif %}
 
-{# ------------------------------------------------------------------------- #}
-{# Design flow                                                               #}
-{# ------------------------------------------------------------------------- #}
-
-{% if SYN or PAR or BIT %}
+{% if SYN or PAR or BIT %}# Design flow -----------------------------------------------------------------
 
 open_project {{ PROJECT }}
 
-{# Synthesis --------------------------------------------------------------- #}
-
-{% if SYN %}
+{% if SYN %}# Synthesis
 
 {{ PRESYN }}
 
@@ -87,9 +77,7 @@ if { [get_property STATUS [get_runs synth_1]] ne "synth_design Complete!" } { ex
 
 {% endif %}
 
-{# Place and Route --------------------------------------------------------- #}
-
-{% if PAR %}
+{% if PAR %}# Place and Route
 
 {{ PREPAR }}
 
@@ -103,9 +91,7 @@ if { [get_property STATUS [get_runs impl_1]] ne "route_design Complete!" } { exi
 
 {% endif %}
 
-{# Bitstream generation ---------------------------------------------------- #}
-
-{% if BIT %}
+{% if BIT %}# Bitstream generation
 
 {{ PREBIT }}
 
@@ -117,8 +103,6 @@ write_debug_probes -force -quiet {{ PROJECT }}.ltx
 
 {% endif %}
 
-{# ------------------------------------------------------------------------- #}
-
 close_project
 
 {% endif %}

From a34381909804057fde54dd131e877737343a6644 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 8 Jul 2024 23:37:14 -0300
Subject: [PATCH 163/248] Change template variables from uppercase to lowercase

---
 pyfpga/ise.py                        | 40 +++++++--------
 pyfpga/libero.py                     | 38 +++++++-------
 pyfpga/openflow.py                   | 38 +++++++-------
 pyfpga/project.py                    |  2 +-
 pyfpga/quartus.py                    | 34 ++++++-------
 pyfpga/templates/ise-prog.jinja      | 32 ++++++------
 pyfpga/templates/ise.jinja           | 66 ++++++++++++------------
 pyfpga/templates/libero.jinja        | 76 ++++++++++++++--------------
 pyfpga/templates/openflow-prog.jinja |  8 +--
 pyfpga/templates/openflow.jinja      | 66 ++++++++++++------------
 pyfpga/templates/quartus-prog.jinja  |  2 +-
 pyfpga/templates/quartus.jinja       | 58 ++++++++++-----------
 pyfpga/templates/vivado-prog.jinja   |  2 +-
 pyfpga/templates/vivado.jinja        | 60 +++++++++++-----------
 pyfpga/vivado.py                     | 32 ++++++------
 15 files changed, 277 insertions(+), 277 deletions(-)

diff --git a/pyfpga/ise.py b/pyfpga/ise.py
index b8f33706..86e1e05a 100644
--- a/pyfpga/ise.py
+++ b/pyfpga/ise.py
@@ -23,29 +23,29 @@ class Ise(Project):
     def _make_prepare(self, steps):
         info = get_info(self.data.get('part', 'xc7k160t-3-fbg484'))
         context = {
-            'PROJECT': self.name or 'ise',
-            'FAMILY': info['family'],
-            'DEVICE': info['device'],
-            'SPEED': info['speed'],
-            'PACKAGE': info['package']
+            'project': self.name or 'ise',
+            'family': info['family'],
+            'device': info['device'],
+            'speed': info['speed'],
+            'package': info['package']
         }
         for step in steps:
             context[step] = 1
-        context['INCLUDES'] = self.data.get('includes', None)
-        context['FILES'] = self.data.get('files', None)
-        context['CONSTRAINTS'] = self.data.get('constraints', None)
-        context['TOP'] = self.data.get('top', None)
-        context['DEFINES'] = self.data.get('defines', None)
-        context['PARAMS'] = self.data.get('params', None)
+        context['includes'] = self.data.get('includes', None)
+        context['files'] = self.data.get('files', None)
+        context['constraints'] = self.data.get('constraints', None)
+        context['top'] = self.data.get('top', None)
+        context['defines'] = self.data.get('defines', None)
+        context['params'] = self.data.get('params', None)
         if 'hooks' in self.data:
-            context['PRECFG'] = self.data['hooks'].get('precfg', None)
-            context['POSTCFG'] = self.data['hooks'].get('postcfg', None)
-            context['PRESYN'] = self.data['hooks'].get('presyn', None)
-            context['POSTSYN'] = self.data['hooks'].get('postsyn', None)
-            context['PREPAR'] = self.data['hooks'].get('prepar', None)
-            context['POSTPAR'] = self.data['hooks'].get('postpar', None)
-            context['PRESBIT'] = self.data['hooks'].get('prebit', None)
-            context['POSTBIT'] = self.data['hooks'].get('postbit', None)
+            context['precfg'] = self.data['hooks'].get('precfg', None)
+            context['postcfg'] = self.data['hooks'].get('postcfg', None)
+            context['presyn'] = self.data['hooks'].get('presyn', None)
+            context['postsyn'] = self.data['hooks'].get('postsyn', None)
+            context['prepar'] = self.data['hooks'].get('prepar', None)
+            context['postpar'] = self.data['hooks'].get('postpar', None)
+            context['presbit'] = self.data['hooks'].get('prebit', None)
+            context['postbit'] = self.data['hooks'].get('postbit', None)
         self._create_file('ise', 'tcl', context)
         return 'xtclsh ise.tcl'
 
@@ -53,7 +53,7 @@ def _prog_prepare(self, bitstream, position):
         if not bitstream:
             basename = self.name or 'ise'
             bitstream = f'{basename}.bit'
-        context = {'BITSTREAM': bitstream, 'POSITION': position}
+        context = {'bitstream': bitstream, 'position': position}
         self._create_file('vivado-prog', 'tcl', context)
         return 'impact -batch impact-prog'
 
diff --git a/pyfpga/libero.py b/pyfpga/libero.py
index 7c07a6a1..45536a6d 100644
--- a/pyfpga/libero.py
+++ b/pyfpga/libero.py
@@ -23,29 +23,29 @@ class Libero(Project):
     def _make_prepare(self, steps):
         info = get_info(self.data.get('part', 'mpf100t-1-fcg484'))
         context = {
-            'PROJECT': self.name or 'libero',
-            'FAMILY': info['family'],
-            'DEVICE': info['device'],
-            'SPEED': info['speed'],
-            'PACKAGE': info['package']
+            'project': self.name or 'libero',
+            'family': info['family'],
+            'device': info['device'],
+            'speed': info['speed'],
+            'package': info['package']
         }
         for step in steps:
             context[step] = 1
-        context['INCLUDES'] = self.data.get('includes', None)
-        context['FILES'] = self.data.get('files', None)
-        context['CONSTRAINTS'] = self.data.get('constraints', None)
-        context['TOP'] = self.data.get('top', None)
-        context['DEFINES'] = self.data.get('defines', None)
-        context['PARAMS'] = self.data.get('params', None)
+        context['includes'] = self.data.get('includes', None)
+        context['files'] = self.data.get('files', None)
+        context['constraints'] = self.data.get('constraints', None)
+        context['top'] = self.data.get('top', None)
+        context['defines'] = self.data.get('defines', None)
+        context['params'] = self.data.get('params', None)
         if 'hooks' in self.data:
-            context['PRECFG'] = self.data['hooks'].get('precfg', None)
-            context['POSTCFG'] = self.data['hooks'].get('postcfg', None)
-            context['PRESYN'] = self.data['hooks'].get('presyn', None)
-            context['POSTSYN'] = self.data['hooks'].get('postsyn', None)
-            context['PREPAR'] = self.data['hooks'].get('prepar', None)
-            context['POSTPAR'] = self.data['hooks'].get('postpar', None)
-            context['PRESBIT'] = self.data['hooks'].get('prebit', None)
-            context['POSTBIT'] = self.data['hooks'].get('postbit', None)
+            context['precfg'] = self.data['hooks'].get('precfg', None)
+            context['postcfg'] = self.data['hooks'].get('postcfg', None)
+            context['presyn'] = self.data['hooks'].get('presyn', None)
+            context['postsyn'] = self.data['hooks'].get('postsyn', None)
+            context['prepar'] = self.data['hooks'].get('prepar', None)
+            context['postpar'] = self.data['hooks'].get('postpar', None)
+            context['presbit'] = self.data['hooks'].get('prebit', None)
+            context['postbit'] = self.data['hooks'].get('postbit', None)
         self._create_file('libero', 'tcl', context)
         return 'libero SCRIPT:libero.tcl'
 
diff --git a/pyfpga/openflow.py b/pyfpga/openflow.py
index 63712a85..c8663277 100644
--- a/pyfpga/openflow.py
+++ b/pyfpga/openflow.py
@@ -21,28 +21,28 @@ class Openflow(Project):
     def _make_prepare(self, steps):
         info = get_info(self.data.get('part', 'hx8k-ct256'))
         context = {
-            'PROJECT': self.name or 'openflow',
-            'FAMILY': info['family'],
-            'DEVICE': info['device'],
-            'PACKAGE': info['package']
+            'project': self.name or 'openflow',
+            'family': info['family'],
+            'device': info['device'],
+            'package': info['package']
         }
         for step in steps:
             context[step] = 1
-        context['INCLUDES'] = self.data.get('includes', None)
-        context['FILES'] = self.data.get('files', None)
-        context['CONSTRAINTS'] = self.data.get('constraints', None)
-        context['TOP'] = self.data.get('top', None)
-        context['DEFINES'] = self.data.get('defines', None)
-        context['PARAMS'] = self.data.get('params', None)
+        context['includes'] = self.data.get('includes', None)
+        context['files'] = self.data.get('files', None)
+        context['constraints'] = self.data.get('constraints', None)
+        context['top'] = self.data.get('top', None)
+        context['defines'] = self.data.get('defines', None)
+        context['params'] = self.data.get('params', None)
         if 'hooks' in self.data:
-            context['PRECFG'] = self.data['hooks'].get('precfg', None)
-            context['POSTCFG'] = self.data['hooks'].get('postcfg', None)
-            context['PRESYN'] = self.data['hooks'].get('presyn', None)
-            context['POSTSYN'] = self.data['hooks'].get('postsyn', None)
-            context['PREPAR'] = self.data['hooks'].get('prepar', None)
-            context['POSTPAR'] = self.data['hooks'].get('postpar', None)
-            context['PRESBIT'] = self.data['hooks'].get('prebit', None)
-            context['POSTBIT'] = self.data['hooks'].get('postbit', None)
+            context['precfg'] = self.data['hooks'].get('precfg', None)
+            context['postcfg'] = self.data['hooks'].get('postcfg', None)
+            context['presyn'] = self.data['hooks'].get('presyn', None)
+            context['postsyn'] = self.data['hooks'].get('postsyn', None)
+            context['prepar'] = self.data['hooks'].get('prepar', None)
+            context['postpar'] = self.data['hooks'].get('postpar', None)
+            context['presbit'] = self.data['hooks'].get('prebit', None)
+            context['postbit'] = self.data['hooks'].get('postbit', None)
         self._create_file('openflow', 'sh', context)
         return 'bash openflow.sh'
 
@@ -51,7 +51,7 @@ def _prog_prepare(self, bitstream, position):
         if not bitstream:
             basename = self.name or 'openflow'
             bitstream = f'{basename}.bit'
-        context = {'BITSTREAM': bitstream}
+        context = {'bitstream': bitstream}
         self._create_file('openflow-prog', 'sh', context)
         return 'bash openflow-prog.sh'
 
diff --git a/pyfpga/project.py b/pyfpga/project.py
index 16ee090e..3ad42b71 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -226,7 +226,7 @@ def make(self, first='cfg', last='bit'):
         if first == last:
             message = steps[first]
         self.logger.info('Running %s', message)
-        selected = [step.upper() for step in keys[index[0]:index[1]+1]]
+        selected = keys[index[0]:index[1]+1]
         self._run(self._make_prepare(selected), 'make.log')
 
     def prog(self, bitstream=None, position=1):
diff --git a/pyfpga/quartus.py b/pyfpga/quartus.py
index 0cc5f93d..5ffa3c71 100644
--- a/pyfpga/quartus.py
+++ b/pyfpga/quartus.py
@@ -20,26 +20,26 @@ class Quartus(Project):
 
     def _make_prepare(self, steps):
         context = {
-            'PROJECT': self.name or 'quartus',
-            'PART': self.data.get('part', '10M50SCE144I7G')
+            'project': self.name or 'quartus',
+            'part': self.data.get('part', '10M50SCE144I7G')
         }
         for step in steps:
             context[step] = 1
-        context['INCLUDES'] = self.data.get('includes', None)
-        context['FILES'] = self.data.get('files', None)
-        context['CONSTRAINTS'] = self.data.get('constraints', None)
-        context['TOP'] = self.data.get('top', None)
-        context['DEFINES'] = self.data.get('defines', None)
-        context['PARAMS'] = self.data.get('params', None)
+        context['includes'] = self.data.get('includes', None)
+        context['files'] = self.data.get('files', None)
+        context['constraints'] = self.data.get('constraints', None)
+        context['top'] = self.data.get('top', None)
+        context['defines'] = self.data.get('defines', None)
+        context['params'] = self.data.get('params', None)
         if 'hooks' in self.data:
-            context['PRECFG'] = self.data['hooks'].get('precfg', None)
-            context['POSTCFG'] = self.data['hooks'].get('postcfg', None)
-            context['PRESYN'] = self.data['hooks'].get('presyn', None)
-            context['POSTSYN'] = self.data['hooks'].get('postsyn', None)
-            context['PREPAR'] = self.data['hooks'].get('prepar', None)
-            context['POSTPAR'] = self.data['hooks'].get('postpar', None)
-            context['PRESBIT'] = self.data['hooks'].get('prebit', None)
-            context['POSTBIT'] = self.data['hooks'].get('postbit', None)
+            context['precfg'] = self.data['hooks'].get('precfg', None)
+            context['postcfg'] = self.data['hooks'].get('postcfg', None)
+            context['presyn'] = self.data['hooks'].get('presyn', None)
+            context['postsyn'] = self.data['hooks'].get('postsyn', None)
+            context['prepar'] = self.data['hooks'].get('prepar', None)
+            context['postpar'] = self.data['hooks'].get('postpar', None)
+            context['presbit'] = self.data['hooks'].get('prebit', None)
+            context['postbit'] = self.data['hooks'].get('postbit', None)
         self._create_file('quartus', 'tcl', context)
         return 'quartus_sh --script quartus.tcl'
 
@@ -49,6 +49,6 @@ def _prog_prepare(self, bitstream, position):
         if not bitstream:
             basename = self.name or 'quartus'
             bitstream = f'{basename}.sof'
-        context = {'BITSTREAM': bitstream, 'POSITION': position}
+        context = {'bitstream': bitstream, 'position': position}
         self._create_file('quartus-prog', 'tcl', context)
         return 'bash quartus-prog.sh'
diff --git a/pyfpga/templates/ise-prog.jinja b/pyfpga/templates/ise-prog.jinja
index 1c2203ee..abf4cb54 100644
--- a/pyfpga/templates/ise-prog.jinja
+++ b/pyfpga/templates/ise-prog.jinja
@@ -10,51 +10,51 @@ cleancablelock
 
 {# ------------------------------------------------------------------------- #}
 
-{% if FPGA %}
+{% if fpga %}
 setMode -bs
 setCable -port auto
 Identify -inferir
-assignFile -p {{ POSITION }} -file  {{ BITSTREAM }}
-Program -p {{ POSITION }}
+assignFile -p {{ position }} -file  {{ bitstream }}
+Program -p {{ position }}
 {% endif %}
 
 {# ------------------------------------------------------------------------- #}
 
-{% if SPI %}
+{% if spi %}
 setMode -pff
-addConfigDevice -name {{ NAME }} -path .
+addConfigDevice -name {{ name }} -path .
 setSubmode -pffspi
 addDesign -version 0 -name 0
 addDeviceChain -index 0
-addDevice -p 1 -file {{ BITSTREAM }}
+addDevice -p 1 -file {{ bitstream }}
 generate -generic
 
 setMode -bs
 setCable -port auto
 Identify
-attachflash -position {{ POSITION }} -spi {{ NAME }}
-assignfiletoattachedflash -position {{ POSITION }} -file ./{{ NAME }}.mcs
-Program -p {{ POSITION }} -dataWidth {{ WIDTH }} -spionly -e -v -loadfpga
+attachflash -position {{ position }} -spi {{ name }}
+assignfiletoattachedflash -position {{ position }} -file ./{{ name }}.mcs
+Program -p {{ position }} -dataWidth {{ width }} -spionly -e -v -loadfpga
 {% endif %}
 
 {# ------------------------------------------------------------------------- #}
 
-{% if BPI %}
+{% if bpi %}
 setMode -pff
-addConfigDevice -name {{ NAME }} -path .
+addConfigDevice -name {{ name }} -path .
 setSubmode -pffbpi
 addDesign -version 0 -name 0
 addDeviceChain -index 0
-setAttribute -configdevice -attr flashDataWidth -value {{ WIDTH }}
-addDevice -p 1 -file {{ BITSTREAM }}
+setAttribute -configdevice -attr flashDataWidth -value {{ width }}
+addDevice -p 1 -file {{ bitstream }}
 generate -generic
 
 setMode -bs
 setCable -port auto
 Identify
-attachflash -position {{ POSITION }} -bpi {{ NAME }}
-assignfiletoattachedflash -position {{ POSITION }} -file ./{{ NAME }}.mcs
-Program -p {{ POSITION }} -dataWidth {{ WIDTH }} -rs1 NONE -rs0 NONE -bpionly -e -v -loadfpga
+attachflash -position {{ position }} -bpi {{ name }}
+assignfiletoattachedflash -position {{ position }} -file ./{{ name }}.mcs
+Program -p {{ position }} -dataWidth {{ width }} -rs1 NONE -rs0 NONE -bpionly -e -v -loadfpga
 {% endif %}
 
 {# ------------------------------------------------------------------------- #}
diff --git a/pyfpga/templates/ise.jinja b/pyfpga/templates/ise.jinja
index 6af287ca..eec1c970 100644
--- a/pyfpga/templates/ise.jinja
+++ b/pyfpga/templates/ise.jinja
@@ -6,26 +6,26 @@
 #
 #}
 
-{% if CFG %}# Project configuration -------------------------------------------------------
+{% if cfg %}# Project configuration -------------------------------------------------------
 
-if { [ file exists {{ PROJECT }}.xise ] } { file delete {{ PROJECT }}.xise }
-project new {{ PROJECT }}.xise
-project set family  {{ FAMILY }}
-project set device  {{ DEVICE }}
-project set package {{ PACKAGE }}
-project set speed  -{{ SPEED }}
+if { [ file exists {{ project }}.xise ] } { file delete {{ project }}.xise }
+project new {{ project }}.xise
+project set family  {{ family }}
+project set device  {{ device }}
+project set package {{ package }}
+project set speed  -{{ speed }}
 
-{{ PRECFG }}
+{{ precfg }}
 
-{% if FILES %}# Files inclusion
-{% for name, attr in FILES.items() %}
+{% if files %}# Files inclusion
+{% for name, attr in files.items() %}
 {% if 'lib' in attr %}lib_vhdl new {{ attr.lib }}{% endif %}
 xfile add {{ name }}{% if 'lib' in attr %} -lib_vhdl {{ attr.lib }}{% endif %}
 {% endfor %}
 {% endif %}
 
-{% if CONSTRAINTS %}# Constraints inclusion
-{% for name, attr in CONSTRAINTS.items() %}
+{% if constraints %}# Constraints inclusion
+{% for name, attr in constraints.items() %}
 xfile add {{ name }}
 {% if name.endswith('.xcf') %}
 project set "Synthesis Constraints File" "{{ name }}" -process "Synthesize - XST"
@@ -33,35 +33,35 @@ project set "Synthesis Constraints File" "{{ name }}" -process "Synthesize - XST
 {% endfor %}
 {% endif %}
 
-{% if TOP %}# Top-level specification
-project set top {{ TOP }}
+{% if top %}# Top-level specification
+project set top {{ top }}
 {% endif %}
 
-{% if INCLUDES %}# Verilog Includes
-project set "Verilog Include Directories" "{{ INCLUDES | join('|') }}" -process "Synthesize - XST"
+{% if includes %}# Verilog Includes
+project set "Verilog Include Directories" "{{ includes | join('|') }}" -process "Synthesize - XST"
 {% endif %}
 
-{% if DEFINES %}# Verilog Defines
-project set "Verilog Macros" "{{ DEFINES.items() | map('join', '=') | join(' | ') }}" -process "Synthesize - XST"
+{% if defines %}# Verilog Defines
+project set "Verilog Macros" "{{ defines.items() | map('join', '=') | join(' | ') }}" -process "Synthesize - XST"
 {% endif %}
 
-{% if PARAMS %}# Verilog Parameters / VHDL Generics
-project set "Generics, Parameters" "{{ PARAMS.items() | map('join', '=') | join(' ') }}" -process "Synthesize - XST"
+{% if params %}# Verilog Parameters / VHDL Generics
+project set "Generics, Parameters" "{{ params.items() | map('join', '=') | join(' ') }}" -process "Synthesize - XST"
 {% endif %}
 
-{{ POSTCFG }}
+{{ postcfg }}
 
 project close
 
 {% endif %}
 
-{% if SYN or PAR or BIT %}# Design flow -----------------------------------------------------------------
+{% if syn or par or bit %}# Design flow -----------------------------------------------------------------
 
-project open {{ PROJECT }}.xise
+project open {{ project }}.xise
 
-{% if SYN %}# Synthesis
+{% if syn %}# Synthesis
 
-{{ PRESYN }}
+{{ presyn }}
 
 # PRESYNTH
 #project set top_level_module_type "EDIF"
@@ -69,13 +69,13 @@ project clean
 process run "Synthesize"
 if { [process get "Synthesize" status] == "errors" } { exit 1 }
 
-{{ POSTSYN }}
+{{ postsyn }}
 
 {% endif %}
 
-{% if PAR %}# Place and Route
+{% if par %}# Place and Route
 
-{{ PREPAR }}
+{{ prepar }}
 
 process run "Translate"
 if { [process get "Translate" status] == "errors" } { exit 1 }
@@ -84,19 +84,19 @@ if { [process get "Map" status] == "errors" } { exit 1 }
 process run "Place & Route"
 if { [process get "Place & Route" status] == "errors" } { exit 1 }
 
-{{ POSTPAR }}
+{{ postpar }}
 
 {% endif %}
 
-{% if BIT %}# Bitstream generation
+{% if bit %}# Bitstream generation
 
-{{ PREBIT }}
+{{ prebit }}
 
 process run "Generate Programming File"
 if { [process get "Generate Programming File" status] == "errors" } { exit 1 }
-catch { file rename -force {{ TOP }}.bit {{ PROJECT }}.bit }
+catch { file rename -force {{ top }}.bit {{ project }}.bit }
 
-{{ POSTBIT }}
+{{ postbit }}
 
 {% endif %}
 
diff --git a/pyfpga/templates/libero.jinja b/pyfpga/templates/libero.jinja
index a4be188f..77176050 100644
--- a/pyfpga/templates/libero.jinja
+++ b/pyfpga/templates/libero.jinja
@@ -6,40 +6,40 @@
 #
 #}
 
-{% if CFG %}# Project configuration -------------------------------------------------------
+{% if cfg %}# Project configuration -------------------------------------------------------
 
-if { [ file exists {{ PROJECT }} ] } { file delete -force -- {{ PROJECT }} }
-new_project -name {{ PROJECT }} -location {libero} -hdl {VERILOG} -family {SmartFusion2}
-set_device -family {{ FAMILY }} -die {{ DEVICE }} -package {{ PACKAGE }} -speed {{ SPEED }}
+if { [ file exists {{ project }} ] } { file delete -force -- {{ project }} }
+new_project -name {{ project }} -location {libero} -hdl {VERILOG} -family {SmartFusion2}
+set_device -family {{ family }} -die {{ device }} -package {{ package }} -speed {{ speed }}
 
-{{ PRECFG }}
+{{ precfg }}
 
-{% if INCLUDES %}# Verilog Includes (Libero)
-set_global_include_path_order -paths "{{ INCLUDES | join(' ') }}"
+{% if includes %}# Verilog Includes (Libero)
+set_global_include_path_order -paths "{{ includes | join(' ') }}"
 {% endif %}
 
-{% if FILES %}# Files inclusion
-{% for name, attr in FILES.items() %}
+{% if files %}# Files inclusion
+{% for name, attr in files.items() %}
 create_links -hdl_source {{ name }}{% if 'lib' in attr %} -library {{ attr.lib }}{% endif %}
 {% endfor %}
 {% endif %}
 
-{% if CONSTRAINTS %}# Constraints inclusion
-{% for name, attr in CONSTRAINTS.items() %}
+{% if constraints %}# Constraints inclusion
+{% for name, attr in constraints.items() %}
 create_links {% if name.endswith('.sdc') %}-sdc{% else %}-io_pdc{% endif %} {{ name }}
 {% endfor %}
 {% endif %}
 
 build_design_hierarchy
 
-{% if TOP %}# Top-level specification
-set_root {{ TOP }}
+{% if top %}# Top-level specification
+set_root {{ top }}
 {% endif %}
 
-{% if CONSTRAINTS %}# Constraints configuration
+{% if constraints %}# Constraints configuration
 {% set sdc_files = [] %}
 {% set pdc_files = [] %}
-{% for name, attr in CONSTRAINTS.items() %}
+{% for name, attr in constraints.items() %}
 {% if name.endswith('.sdc') %}
 {% set _ = sdc_files.append(name) %}
 {% endif %}
@@ -47,27 +47,27 @@ set_root {{ TOP }}
 {% endfor %}
 {% endif %}
 
-{% if sdc_files %}organize_tool_files -tool {SYNTHESIZE}   -file {{ sdc_files | join(' -file ') }} -module {{ TOP }} -input_type {constraint}{% endif %}
-{% if pdc_files %}organize_tool_files -tool {PLACEROUTE}   -file {{ pdc_files | join(' -file ') }} -module {{ TOP }} -input_type {constraint}{% endif %}
-{% if sdc_files %}organize_tool_files -tool {VERIFYTIMING} -file {{ sdc_files | join(' -file ') }} -module {{ TOP }} -input_type {constraint}{% endif %}
+{% if sdc_files %}organize_tool_files -tool {SYNTHESIZE}   -file {{ sdc_files | join(' -file ') }} -module {{ top }} -input_type {constraint}{% endif %}
+{% if pdc_files %}organize_tool_files -tool {PLACEROUTE}   -file {{ pdc_files | join(' -file ') }} -module {{ top }} -input_type {constraint}{% endif %}
+{% if sdc_files %}organize_tool_files -tool {VERIFYTIMING} -file {{ sdc_files | join(' -file ') }} -module {{ top }} -input_type {constraint}{% endif %}
 
-{% if INCLUDES or DEFINES or PARAMS %}# Synopsys configuration
+{% if includes or defines or params %}# Synopsys configuration
 configure_tool -name {SYNTHESIZE} -params {SYNPLIFY_OPTIONS:
 
-{% if INCLUDES %}# Verilog Includes (Synopsys)
-{% for INCLUDE in INCLUDES %}
-  set_option -include_path "{{ INCLUDE }}"
+{% if includes %}# Verilog Includes (Synopsys)
+{% for include in includes %}
+  set_option -include_path "{{ include }}"
 {% endfor %}
 {% endif %}
 
-{% if DEFINES %}# Verilog Defines (Synopsys)
-{% for key, value in DEFINES.items() %}
+{% if defines %}# Verilog Defines (Synopsys)
+{% for key, value in defines.items() %}
   set_option -hdl_define -set {{ key }}={{ value }}
 {% endfor %}
 {% endif %}
 
-{% if PARAMS %}# Verilog Parameters / VHDL Generics (Synopsys)
-{% for key, value in PARAMS.items() %}
+{% if params %}# Verilog Parameters / VHDL Generics (Synopsys)
+{% for key, value in params.items() %}
   set_option -hdl_param -set {{ key }}={{ value }}
 {% endfor %}
 {% endif %}
@@ -75,44 +75,44 @@ configure_tool -name {SYNTHESIZE} -params {SYNPLIFY_OPTIONS:
 }
 {% endif %}
 
-{{ POSTCFG }}
+{{ postcfg }}
 
 close_project
 
 {% endif %}
 
-{% if SYN or PAR or BIT %}# Design flow -----------------------------------------------------------------
+{% if syn or par or bit %}# Design flow -----------------------------------------------------------------
 
-open_project {{ PROJECT }}/{{ PROJECT }}.prjx
+open_project {{ project }}/{{ project }}.prjx
 
-{% if SYN %}# Synthesis
+{% if syn %}# Synthesis
 
-{{ PRESYN }}
+{{ presyn }}
 
 run_tool -name {SYNTHESIZE}
 
-{{ POSTSYN }}
+{{ postsyn }}
 
 {% endif %}
 
-{% if PAR %}# Place and Route
+{% if par %}# Place and Route
 
-{{ PREPAR }}
+{{ prepar }}
 
 run_tool -name {PLACEROUTE}
 run_tool -name {VERIFYTIMING}
 
-{{ POSTPAR }}
+{{ postpar }}
 
 {% endif %}
 
-{% if BIT %}# Bitstream generation
+{% if bit %}# Bitstream generation
 
-{{ PREBIT }}
+{{ prebit }}
 
 run_tool -name {GENERATEPROGRAMMINGFILE}
 
-{{ POSTBIT }}
+{{ postbit }}
 
 {% endif %}
 
diff --git a/pyfpga/templates/openflow-prog.jinja b/pyfpga/templates/openflow-prog.jinja
index 81942426..47fad80d 100644
--- a/pyfpga/templates/openflow-prog.jinja
+++ b/pyfpga/templates/openflow-prog.jinja
@@ -9,10 +9,10 @@ set -e
 
 DOCKER="docker run --user $(id -u):$(id -g) --rm -v $HOME:$HOME -w $PWD"
 
-{% if FAMILY == 'ice40' %}
-$DOCKER --device /dev/bus/usb hdlc/prog iceprog {{ PROJECT }}.bit
+{% if family == 'ice40' %}
+$DOCKER --device /dev/bus/usb hdlc/prog iceprog {{ project }}.bit
 {% endif %}
 
-{% if FAMILY == 'ecp5' %}
-$DOCKER --device /dev/bus/usb hdlc/prog openocd -f /usr/share/trellis/misc/openocd/ecp5-evn.cfg -c "transport select jtag; init; svf {{ PROJECT }}.svf; exit"
+{% if family == 'ecp5' %}
+$DOCKER --device /dev/bus/usb hdlc/prog openocd -f /usr/share/trellis/misc/openocd/ecp5-evn.cfg -c "transport select jtag; init; svf {{ project }}.svf; exit"
 {% endif %}
diff --git a/pyfpga/templates/openflow.jinja b/pyfpga/templates/openflow.jinja
index 02e57662..5aa9b29b 100644
--- a/pyfpga/templates/openflow.jinja
+++ b/pyfpga/templates/openflow.jinja
@@ -10,21 +10,21 @@ set -e
 
 DOCKER="docker run --user $(id -u):$(id -g) --rm -v $HOME:$HOME -w $PWD"
 
-{% if SYN %}# Synthesis
+{% if syn %}# Synthesis
 $DOCKER hdlc/ghdl:yosys /bin/bash -c "
-{{ PRESYN }}
+{{ presyn }}
 yosys -Q -m ghdl -p '
 
-{% if INCLUDES %}
-verilog_defaults -add{% for path in INCLUDES %} -I{{ path }}{% endfor %}
+{% if includes %}
+verilog_defaults -add{% for path in includes %} -I{{ path }}{% endfor %}
 {% endif %}
 
-{% if DEFINES %}
-verilog_defines{% for key, value in DEFINES.items() %} -D{{ key }}={{ value }}{% endfor %}
+{% if defines %}
+verilog_defines{% for key, value in defines.items() %} -D{{ key }}={{ value }}{% endfor %}
 {% endif %}
 
-{% if FILES %}
-{% for name, attr in FILES.items() %}
+{% if files %}
+{% for name, attr in files.items() %}
 {% if attr.hdl == "vlog" %}
 read_verilog -defer {{ name }}
 {% elif attr.hdl == "slog" %}
@@ -33,14 +33,14 @@ read_verilog -defer -sv {{ name }}
 {% endfor %}
 {% endif %}
 
-{% if PARAMS %}
-chparam{% for key, value in PARAMS.items() %} -set {{ key }} {{ value }}{% endfor %}
+{% if params %}
+chparam{% for key, value in params.items() %} -set {{ key }} {{ value }}{% endfor %}
 {% endif %}
 
-synth -top {{ TOP }}
-synth_{{ FAMILY }} -top {{ TOP }} -json {{ PROJECT }}.json
+synth -top {{ top }}
+synth_{{ family }} -top {{ top }} -json {{ project }}.json
 '
-{{ POSTSYN }}
+{{ postsyn }}
 "
 {% endif %}
 
@@ -63,54 +63,54 @@ synth_{{ FAMILY }} -top {{ TOP }} -json {{ PROJECT }}.json
 #fi
 #}
 
-{% if PAR %}# Place and Route
+{% if par %}# Place and Route
 
-CONSTRAINTS="{{ CONSTRAINTS | join(' ') }}"
+CONSTRAINTS="{{ constraints | join(' ') }}"
 
-{% if FAMILY == 'ice40' %}
+{% if family == 'ice40' %}
 if [ -n "$CONSTRAINTS" ]; then
   cat $CONSTRAINTS > constraints.pcf
   CONSTRAINT="--pcf constraints.pcf"
 fi
 $DOCKER hdlc/nextpnr:ice40 /bin/bash -c "
-{{ PREPAR }}
-nextpnr-ice40 --{{ DEVICE }} --package {{ PACKAGE }} $CONSTRAINT --json {{ PROJECT }}.json --asc {{ PROJECT }}.asc
-{{ POSTPAR }}
+{{ prepar }}
+nextpnr-ice40 --{{ device }} --package {{ package }} $CONSTRAINT --json {{ project }}.json --asc {{ project }}.asc
+{{ postpar }}
 "
 $DOCKER hdlc/icestorm /bin/bash -c "
-icetime -d {{ DEVICE }} -mtr {{ PROJECT }}.rpt {{ PROJECT }}.asc
+icetime -d {{ device }} -mtr {{ project }}.rpt {{ project }}.asc
 "
 {% endif %}
 
-{% if FAMILY == 'ecp5' %}
+{% if family == 'ecp5' %}
 if [ -n "$CONSTRAINTS" ]; then
   cat $CONSTRAINTS > constraints.lpf
   CONSTRAINT="--lpf constraints.lpf"
 fi
 $DOCKER hdlc/nextpnr:ecp5 /bin/bash -c "
-{{ PREPAR }}
-nextpnr-ecp5 --{{ DEVICE }} --package {{ PACKAGE }} $CONSTRAINT --json {{ PROJECT }}.json --textcfg {{ PROJECT }}.config
-{{ POSTPAR }}
+{{ prepar }}
+nextpnr-ecp5 --{{ device }} --package {{ package }} $CONSTRAINT --json {{ project }}.json --textcfg {{ project }}.config
+{{ postpar }}
 "
 {% endif %}
 
 {% endif %}
 
-{% if BIT %}# Bitstream generation
+{% if bit %}# Bitstream generation
 
-{% if FAMILY == 'ice40' %}
+{% if family == 'ice40' %}
 $DOCKER hdlc/icestorm /bin/bash -c "
-{{ PREBIT }}
-icepack {{ PROJECT }}.asc {{ PROJECT }}.bit
-{{ POSTBIT }}
+{{ prebit }}
+icepack {{ project }}.asc {{ project }}.bit
+{{ postbit }}
 "
 {% endif %}
 
-{% if FAMILY == 'ecp5' %}
+{% if family == 'ecp5' %}
 $DOCKER hdlc/prjtrellis /bin/bash -c "
-{{ PREBIT }}
-ecppack --svf {{ PROJECT }}.svf {{ PROJECT }}.config {{ PROJECT }}.bit
-{{ POSTBIT }}
+{{ prebit }}
+ecppack --svf {{ project }}.svf {{ project }}.config {{ project }}.bit
+{{ postbit }}
 "
 {% endif %}
 
diff --git a/pyfpga/templates/quartus-prog.jinja b/pyfpga/templates/quartus-prog.jinja
index 23786f22..0d7af942 100644
--- a/pyfpga/templates/quartus-prog.jinja
+++ b/pyfpga/templates/quartus-prog.jinja
@@ -12,4 +12,4 @@ echo "$RESULT"
 # cable = re.match(r"1\) (.*) \[", result).groups()[0]
 CABLE=$(echo "$RESULT" | awk -F '1\\) | \\[' '/1\)/ {print $2}')
 
-quartus_pgm -c $CABLE --mode jtag -o "p;{{ BITSTREAM }}@{{ POSITION }}"
+quartus_pgm -c $CABLE --mode jtag -o "p;{{ bitstream }}@{{ position }}"
diff --git a/pyfpga/templates/quartus.jinja b/pyfpga/templates/quartus.jinja
index dcbcb5d9..7ffb78a6 100644
--- a/pyfpga/templates/quartus.jinja
+++ b/pyfpga/templates/quartus.jinja
@@ -6,16 +6,16 @@
 #
 #}
 
-{% if CFG %}# Project configuration -------------------------------------------------------
+{% if cfg %}# Project configuration -------------------------------------------------------
 
 package require ::quartus::project
-project_new {{ PROJECT }} -overwrite
-set_global_assignment -name DEVICE {{ PART }}
+project_new {{ project }} -overwrite
+set_global_assignment -name DEVICE {{ part }}
 
-{{ PRECFG }}
+{{ precfg }}
 
-{% if FILES %}# Files inclusion
-{% for name, attr in FILES.items() %}
+{% if files %}# Files inclusion
+{% for name, attr in files.items() %}
 {% if attr.hdl == "vhdl" %}
 set_global_assignment -name VHDL_FILE {{ name }} {% if 'lib' in attr %} -library {{ attr.lib }}{% endif %}
 {% elif attr.hdl == "vlog" %}
@@ -26,8 +26,8 @@ set_global_assignment -name SYSTEMVERILOG_FILE {{ name }}
 {% endfor %}
 {% endif %}
 
-{% if CONSTRAINTS %}# Constraints inclusion
-{% for name, attr in CONSTRAINTS.items() %}
+{% if constraints %}# Constraints inclusion
+{% for name, attr in constraints.items() %}
 {% if name.endswith('.sdc') %}
 set_global_assignment -name SDC_FILE {{ name }}
 {% else %}
@@ -36,68 +36,68 @@ source {{ name }}
 {% endfor %}
 {% endif %}
 
-{% if TOP %}# Top-level specification
-set_global_assignment -name TOP_LEVEL_ENTITY {{ TOP }}
+{% if top %}# Top-level specification
+set_global_assignment -name TOP_LEVEL_ENTITY {{ top }}
 {% endif %}
 
-{% if INCLUDES %}# Verilog Includes
-{% for INCLUDE in INCLUDES %}
-set_global_assignment -name SEARCH_PATH {{ INCLUDE }}
+{% if includes %}# Verilog Includes
+{% for include in includes %}
+set_global_assignment -name SEARCH_PATH {{ include }}
 {% endfor %}
 {% endif %}
 
-{% if DEFINES %}# Verilog Defines
-{% for key, value in DEFINES.items() %}
+{% if defines %}# Verilog Defines
+{% for key, value in defines.items() %}
 set_global_assignment -name VERILOG_MACRO {{ key }}={{ value }}
 {% endfor %}
 {% endif %}
 
-{% if PARAMS %}# Verilog Parameters / VHDL Generics
-{% for key, value in PARAMS.items() %}
+{% if params %}# Verilog Parameters / VHDL Generics
+{% for key, value in params.items() %}
 set_parameter -name {{ key }} {{ value }}
 {% endfor %}
 {% endif %}
 
-{{ POSTCFG }}
+{{ postcfg }}
 
 project_close
 
 {% endif %}
 
-{% if SYN or PAR or BIT %}# Design flow -----------------------------------------------------------------
+{% if syn or par or bit %}# Design flow -----------------------------------------------------------------
 
 package require ::quartus::flow
-project_open -force {{ PROJECT }}.qpf
+project_open -force {{ project }}.qpf
 # set_global_assignment -name NUM_PARALLEL_PROCESSORS ALL
 
-{% if SYN %}# Synthesis
+{% if syn %}# Synthesis
 
-{{ PRESYN }}
+{{ presyn }}
 
 execute_module -tool map
 
-{{ POSTSYN }}
+{{ postsyn }}
 
 {% endif %}
 
-{% if PAR %}# Place and Route
+{% if par %}# Place and Route
 
-{{ PREPAR }}
+{{ prepar }}
 
 execute_module -tool fit
 execute_module -tool sta
 
-{{ POSTPAR }}
+{{ postpar }}
 
 {% endif %}
 
-{% if BIT %}# Bitstream generation
+{% if bit %}# Bitstream generation
 
-{{ PREBIT }}
+{{ prebit }}
 
 execute_module -tool asm
 
-{{ POSTBIT }}
+{{ postbit }}
 
 {% endif %}
 
diff --git a/pyfpga/templates/vivado-prog.jinja b/pyfpga/templates/vivado-prog.jinja
index 72ccb91d..eeeab0ca 100644
--- a/pyfpga/templates/vivado-prog.jinja
+++ b/pyfpga/templates/vivado-prog.jinja
@@ -11,5 +11,5 @@ connect_hw_server
 open_hw_target
 puts [get_hw_devices]
 set obj [lindex [get_hw_devices [current_hw_device]] 0]
-set_property PROGRAM.FILE {{ BITSTREAM }} $obj
+set_property PROGRAM.FILE {{ bitstream }} $obj
 program_hw_devices $obj
diff --git a/pyfpga/templates/vivado.jinja b/pyfpga/templates/vivado.jinja
index 19a53aee..6aa4e456 100644
--- a/pyfpga/templates/vivado.jinja
+++ b/pyfpga/templates/vivado.jinja
@@ -6,24 +6,24 @@
 #
 #}
 
-{% if CFG %}# Project configuration -------------------------------------------------------
+{% if cfg %}# Project configuration -------------------------------------------------------
 
-create_project -force {{ PROJECT }}
+create_project -force {{ project }}
 set_property SOURCE_MGMT_MODE None [current_project]
 set_property STEPS.SYNTH_DESIGN.ARGS.ASSERT true [get_runs synth_1]
-set_property PART {{ PART }} [current_project]
+set_property PART {{ part }} [current_project]
 
-{{ PRECFG }}
+{{ precfg }}
 
-{% if FILES %}# Files inclusion
-{% for name, attr in FILES.items() %}
+{% if files %}# Files inclusion
+{% for name, attr in files.items() %}
 add_file {{ name }}
 {% if 'lib' in attr %}set_property library {{ attr.lib }} [get_files {{ name }}]{% endif %}
 {% endfor %}
 {% endif %}
 
-{% if CONSTRAINTS %}# Constraints inclusion
-{% for name, attr in CONSTRAINTS.items() %}
+{% if constraints %}# Constraints inclusion
+{% for name, attr in constraints.items() %}
 add_file -fileset constrs_1 {{ name }}
 {% if attr == "syn" %}
 set_property USED_IN_IMPLEMENTATION FALSE [get_files {{ name }}]
@@ -34,35 +34,35 @@ set_property USED_IN_SYNTHESIS FALSE [get_files {{ name }}]
 {% endfor %}
 {% endif %}
 
-{% if TOP %}# Top-level specification
-set_property TOP {{ TOP }} [current_fileset]
+{% if top %}# Top-level specification
+set_property TOP {{ top }} [current_fileset]
 {% endif %}
 
-{% if INCLUDES %}# Verilog Includes
-set_property INCLUDE_DIRS { {{ INCLUDES | join(' ') }} } [current_fileset]
+{% if includes %}# Verilog Includes
+set_property INCLUDE_DIRS { {{ includes | join(' ') }} } [current_fileset]
 {% endif %}
 
-{% if DEFINES %}# Verilog Defines
-set_property VERILOG_DEFINE { {{ DEFINES.items() | map('join', '=') | join(' ') }} } [current_fileset]
+{% if defines %}# Verilog Defines
+set_property VERILOG_DEFINE { {{ defines.items() | map('join', '=') | join(' ') }} } [current_fileset]
 {% endif %}
 
-{% if PARAMS %}# Verilog Parameters / VHDL Generics
-set_property GENERIC { {{ PARAMS.items() | map('join', '=') | join(' ') }} } -objects [get_filesets sources_1]
+{% if params %}# Verilog Parameters / VHDL Generics
+set_property GENERIC { {{ params.items() | map('join', '=') | join(' ') }} } -objects [get_filesets sources_1]
 {% endif %}
 
-{{ POSTCFG }}
+{{ postcfg }}
 
 close_project
 
 {% endif %}
 
-{% if SYN or PAR or BIT %}# Design flow -----------------------------------------------------------------
+{% if syn or par or bit %}# Design flow -----------------------------------------------------------------
 
-open_project {{ PROJECT }}
+open_project {{ project }}
 
-{% if SYN %}# Synthesis
+{% if syn %}# Synthesis
 
-{{ PRESYN }}
+{{ presyn }}
 
 # PRESYNTH
 # set_property DESIGN_MODE GateLvl [current_fileset]
@@ -73,13 +73,13 @@ wait_on_run synth_1
 
 if { [get_property STATUS [get_runs synth_1]] ne "synth_design Complete!" } { exit 1 }
 
-{{ POSTSYN }}
+{{ postsyn }}
 
 {% endif %}
 
-{% if PAR %}# Place and Route
+{% if par %}# Place and Route
 
-{{ PREPAR }}
+{{ prepar }}
 
 reset_run impl_1
 launch_runs impl_1
@@ -87,19 +87,19 @@ wait_on_run impl_1
 #report_property [get_runs impl_1]
 if { [get_property STATUS [get_runs impl_1]] ne "route_design Complete!" } { exit 1 }
 
-{{ POSTPAR }}
+{{ postpar }}
 
 {% endif %}
 
-{% if BIT %}# Bitstream generation
+{% if bit %}# Bitstream generation
 
-{{ PREBIT }}
+{{ prebit }}
 
 open_run impl_1
-write_bitstream -force {{ PROJECT }}
-write_debug_probes -force -quiet {{ PROJECT }}.ltx
+write_bitstream -force {{ project }}
+write_debug_probes -force -quiet {{ project }}.ltx
 
-{{ POSTBIT }}
+{{ postbit }}
 
 {% endif %}
 
diff --git a/pyfpga/vivado.py b/pyfpga/vivado.py
index 3cc39d6e..b5f59f4e 100644
--- a/pyfpga/vivado.py
+++ b/pyfpga/vivado.py
@@ -19,26 +19,26 @@ class Vivado(Project):
 
     def _make_prepare(self, steps):
         context = {
-            'PROJECT': self.name or 'vivado',
-            'PART': self.data.get('part', 'xc7k160t-3-fbg484')
+            'project': self.name or 'vivado',
+            'part': self.data.get('part', 'xc7k160t-3-fbg484')
         }
         for step in steps:
             context[step] = 1
-        context['INCLUDES'] = self.data.get('includes', None)
-        context['FILES'] = self.data.get('files', None)
-        context['CONSTRAINTS'] = self.data.get('constraints', None)
-        context['TOP'] = self.data.get('top', None)
-        context['DEFINES'] = self.data.get('defines', None)
-        context['PARAMS'] = self.data.get('params', None)
+        context['includes'] = self.data.get('includes', None)
+        context['files'] = self.data.get('files', None)
+        context['constraints'] = self.data.get('constraints', None)
+        context['top'] = self.data.get('top', None)
+        context['defines'] = self.data.get('defines', None)
+        context['params'] = self.data.get('params', None)
         if 'hooks' in self.data:
-            context['PRECFG'] = self.data['hooks'].get('precfg', None)
-            context['POSTCFG'] = self.data['hooks'].get('postcfg', None)
-            context['PRESYN'] = self.data['hooks'].get('presyn', None)
-            context['POSTSYN'] = self.data['hooks'].get('postsyn', None)
-            context['PREPAR'] = self.data['hooks'].get('prepar', None)
-            context['POSTPAR'] = self.data['hooks'].get('postpar', None)
-            context['PRESBIT'] = self.data['hooks'].get('prebit', None)
-            context['POSTBIT'] = self.data['hooks'].get('postbit', None)
+            context['precfg'] = self.data['hooks'].get('precfg', None)
+            context['postcfg'] = self.data['hooks'].get('postcfg', None)
+            context['presyn'] = self.data['hooks'].get('presyn', None)
+            context['postsyn'] = self.data['hooks'].get('postsyn', None)
+            context['prepar'] = self.data['hooks'].get('prepar', None)
+            context['postpar'] = self.data['hooks'].get('postpar', None)
+            context['presbit'] = self.data['hooks'].get('prebit', None)
+            context['postbit'] = self.data['hooks'].get('postbit', None)
         self._create_file('vivado', 'tcl', context)
         return 'vivado -mode batch -notrace -quiet -source vivado.tcl'
 

From 9e63f29f18f3b4935cf7596e612f7d42607af7d4 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Tue, 9 Jul 2024 00:25:15 -0300
Subject: [PATCH 164/248] Modify how the flow steps and hooks are used on the
 templates

---
 pyfpga/ise.py                   | 13 ++-----------
 pyfpga/libero.py                | 13 ++-----------
 pyfpga/openflow.py              | 13 ++-----------
 pyfpga/quartus.py               | 13 ++-----------
 pyfpga/templates/ise.jinja      | 26 +++++++++++++-------------
 pyfpga/templates/libero.jinja   | 26 +++++++++++++-------------
 pyfpga/templates/openflow.jinja | 26 +++++++++++++-------------
 pyfpga/templates/quartus.jinja  | 26 +++++++++++++-------------
 pyfpga/templates/vivado.jinja   | 27 +++++++++++++--------------
 pyfpga/vivado.py                | 13 ++-----------
 10 files changed, 75 insertions(+), 121 deletions(-)

diff --git a/pyfpga/ise.py b/pyfpga/ise.py
index 86e1e05a..b2d102a0 100644
--- a/pyfpga/ise.py
+++ b/pyfpga/ise.py
@@ -29,23 +29,14 @@ def _make_prepare(self, steps):
             'speed': info['speed'],
             'package': info['package']
         }
-        for step in steps:
-            context[step] = 1
+        context['steps'] = steps
         context['includes'] = self.data.get('includes', None)
         context['files'] = self.data.get('files', None)
         context['constraints'] = self.data.get('constraints', None)
         context['top'] = self.data.get('top', None)
         context['defines'] = self.data.get('defines', None)
         context['params'] = self.data.get('params', None)
-        if 'hooks' in self.data:
-            context['precfg'] = self.data['hooks'].get('precfg', None)
-            context['postcfg'] = self.data['hooks'].get('postcfg', None)
-            context['presyn'] = self.data['hooks'].get('presyn', None)
-            context['postsyn'] = self.data['hooks'].get('postsyn', None)
-            context['prepar'] = self.data['hooks'].get('prepar', None)
-            context['postpar'] = self.data['hooks'].get('postpar', None)
-            context['presbit'] = self.data['hooks'].get('prebit', None)
-            context['postbit'] = self.data['hooks'].get('postbit', None)
+        context['hooks'] = self.data.get('hooks', None)
         self._create_file('ise', 'tcl', context)
         return 'xtclsh ise.tcl'
 
diff --git a/pyfpga/libero.py b/pyfpga/libero.py
index 45536a6d..00014dc8 100644
--- a/pyfpga/libero.py
+++ b/pyfpga/libero.py
@@ -29,23 +29,14 @@ def _make_prepare(self, steps):
             'speed': info['speed'],
             'package': info['package']
         }
-        for step in steps:
-            context[step] = 1
+        context['steps'] = steps
         context['includes'] = self.data.get('includes', None)
         context['files'] = self.data.get('files', None)
         context['constraints'] = self.data.get('constraints', None)
         context['top'] = self.data.get('top', None)
         context['defines'] = self.data.get('defines', None)
         context['params'] = self.data.get('params', None)
-        if 'hooks' in self.data:
-            context['precfg'] = self.data['hooks'].get('precfg', None)
-            context['postcfg'] = self.data['hooks'].get('postcfg', None)
-            context['presyn'] = self.data['hooks'].get('presyn', None)
-            context['postsyn'] = self.data['hooks'].get('postsyn', None)
-            context['prepar'] = self.data['hooks'].get('prepar', None)
-            context['postpar'] = self.data['hooks'].get('postpar', None)
-            context['presbit'] = self.data['hooks'].get('prebit', None)
-            context['postbit'] = self.data['hooks'].get('postbit', None)
+        context['hooks'] = self.data.get('hooks', None)
         self._create_file('libero', 'tcl', context)
         return 'libero SCRIPT:libero.tcl'
 
diff --git a/pyfpga/openflow.py b/pyfpga/openflow.py
index c8663277..feb7a41e 100644
--- a/pyfpga/openflow.py
+++ b/pyfpga/openflow.py
@@ -26,23 +26,14 @@ def _make_prepare(self, steps):
             'device': info['device'],
             'package': info['package']
         }
-        for step in steps:
-            context[step] = 1
+        context['steps'] = steps
         context['includes'] = self.data.get('includes', None)
         context['files'] = self.data.get('files', None)
         context['constraints'] = self.data.get('constraints', None)
         context['top'] = self.data.get('top', None)
         context['defines'] = self.data.get('defines', None)
         context['params'] = self.data.get('params', None)
-        if 'hooks' in self.data:
-            context['precfg'] = self.data['hooks'].get('precfg', None)
-            context['postcfg'] = self.data['hooks'].get('postcfg', None)
-            context['presyn'] = self.data['hooks'].get('presyn', None)
-            context['postsyn'] = self.data['hooks'].get('postsyn', None)
-            context['prepar'] = self.data['hooks'].get('prepar', None)
-            context['postpar'] = self.data['hooks'].get('postpar', None)
-            context['presbit'] = self.data['hooks'].get('prebit', None)
-            context['postbit'] = self.data['hooks'].get('postbit', None)
+        context['hooks'] = self.data.get('hooks', None)
         self._create_file('openflow', 'sh', context)
         return 'bash openflow.sh'
 
diff --git a/pyfpga/quartus.py b/pyfpga/quartus.py
index 5ffa3c71..1f4cb2e5 100644
--- a/pyfpga/quartus.py
+++ b/pyfpga/quartus.py
@@ -23,23 +23,14 @@ def _make_prepare(self, steps):
             'project': self.name or 'quartus',
             'part': self.data.get('part', '10M50SCE144I7G')
         }
-        for step in steps:
-            context[step] = 1
+        context['steps'] = steps
         context['includes'] = self.data.get('includes', None)
         context['files'] = self.data.get('files', None)
         context['constraints'] = self.data.get('constraints', None)
         context['top'] = self.data.get('top', None)
         context['defines'] = self.data.get('defines', None)
         context['params'] = self.data.get('params', None)
-        if 'hooks' in self.data:
-            context['precfg'] = self.data['hooks'].get('precfg', None)
-            context['postcfg'] = self.data['hooks'].get('postcfg', None)
-            context['presyn'] = self.data['hooks'].get('presyn', None)
-            context['postsyn'] = self.data['hooks'].get('postsyn', None)
-            context['prepar'] = self.data['hooks'].get('prepar', None)
-            context['postpar'] = self.data['hooks'].get('postpar', None)
-            context['presbit'] = self.data['hooks'].get('prebit', None)
-            context['postbit'] = self.data['hooks'].get('postbit', None)
+        context['hooks'] = self.data.get('hooks', None)
         self._create_file('quartus', 'tcl', context)
         return 'quartus_sh --script quartus.tcl'
 
diff --git a/pyfpga/templates/ise.jinja b/pyfpga/templates/ise.jinja
index eec1c970..b44e003a 100644
--- a/pyfpga/templates/ise.jinja
+++ b/pyfpga/templates/ise.jinja
@@ -6,7 +6,7 @@
 #
 #}
 
-{% if cfg %}# Project configuration -------------------------------------------------------
+{% if 'cfg' in steps %}# Project configuration -------------------------------------------------------
 
 if { [ file exists {{ project }}.xise ] } { file delete {{ project }}.xise }
 project new {{ project }}.xise
@@ -15,7 +15,7 @@ project set device  {{ device }}
 project set package {{ package }}
 project set speed  -{{ speed }}
 
-{{ precfg }}
+{{ hooks.precfg | join('\n') }}
 
 {% if files %}# Files inclusion
 {% for name, attr in files.items() %}
@@ -49,19 +49,19 @@ project set "Verilog Macros" "{{ defines.items() | map('join', '=') | join(' | '
 project set "Generics, Parameters" "{{ params.items() | map('join', '=') | join(' ') }}" -process "Synthesize - XST"
 {% endif %}
 
-{{ postcfg }}
+{{ hooks.postcfg | join('\n') }}
 
 project close
 
 {% endif %}
 
-{% if syn or par or bit %}# Design flow -----------------------------------------------------------------
+{% if 'syn' in steps or 'par' in steps or 'bit' in steps %}# Design flow -----------------------------------------------------------------
 
 project open {{ project }}.xise
 
-{% if syn %}# Synthesis
+{% if 'syn' in steps %}# Synthesis
 
-{{ presyn }}
+{{ hooks.presyn | join('\n') }}
 
 # PRESYNTH
 #project set top_level_module_type "EDIF"
@@ -69,13 +69,13 @@ project clean
 process run "Synthesize"
 if { [process get "Synthesize" status] == "errors" } { exit 1 }
 
-{{ postsyn }}
+{{ hooks.postsyn | join('\n') }}
 
 {% endif %}
 
-{% if par %}# Place and Route
+{% if 'par' in steps %}# Place and Route
 
-{{ prepar }}
+{{ hooks.prepar | join('\n') }}
 
 process run "Translate"
 if { [process get "Translate" status] == "errors" } { exit 1 }
@@ -84,19 +84,19 @@ if { [process get "Map" status] == "errors" } { exit 1 }
 process run "Place & Route"
 if { [process get "Place & Route" status] == "errors" } { exit 1 }
 
-{{ postpar }}
+{{ hooks.postpar | join('\n') }}
 
 {% endif %}
 
-{% if bit %}# Bitstream generation
+{% if 'bit' in steps %}# Bitstream generation
 
-{{ prebit }}
+{{ hooks.prebit | join('\n') }}
 
 process run "Generate Programming File"
 if { [process get "Generate Programming File" status] == "errors" } { exit 1 }
 catch { file rename -force {{ top }}.bit {{ project }}.bit }
 
-{{ postbit }}
+{{ hooks.postbit | join('\n') }}
 
 {% endif %}
 
diff --git a/pyfpga/templates/libero.jinja b/pyfpga/templates/libero.jinja
index 77176050..310807d5 100644
--- a/pyfpga/templates/libero.jinja
+++ b/pyfpga/templates/libero.jinja
@@ -6,13 +6,13 @@
 #
 #}
 
-{% if cfg %}# Project configuration -------------------------------------------------------
+{% if 'cfg' in steps %}# Project configuration -------------------------------------------------------
 
 if { [ file exists {{ project }} ] } { file delete -force -- {{ project }} }
 new_project -name {{ project }} -location {libero} -hdl {VERILOG} -family {SmartFusion2}
 set_device -family {{ family }} -die {{ device }} -package {{ package }} -speed {{ speed }}
 
-{{ precfg }}
+{{ hooks.precfg | join('\n') }}
 
 {% if includes %}# Verilog Includes (Libero)
 set_global_include_path_order -paths "{{ includes | join(' ') }}"
@@ -75,44 +75,44 @@ configure_tool -name {SYNTHESIZE} -params {SYNPLIFY_OPTIONS:
 }
 {% endif %}
 
-{{ postcfg }}
+{{ hooks.postcfg | join('\n') }}
 
 close_project
 
 {% endif %}
 
-{% if syn or par or bit %}# Design flow -----------------------------------------------------------------
+{% if 'syn' in steps or 'par' in steps or 'bit' in steps %}# Design flow -----------------------------------------------------------------
 
 open_project {{ project }}/{{ project }}.prjx
 
-{% if syn %}# Synthesis
+{% if 'syn' in steps %}# Synthesis
 
-{{ presyn }}
+{{ hooks.presyn | join('\n') }}
 
 run_tool -name {SYNTHESIZE}
 
-{{ postsyn }}
+{{ hooks.postsyn | join('\n') }}
 
 {% endif %}
 
-{% if par %}# Place and Route
+{% if 'par' in steps %}# Place and Route
 
-{{ prepar }}
+{{ hooks.prepar | join('\n') }}
 
 run_tool -name {PLACEROUTE}
 run_tool -name {VERIFYTIMING}
 
-{{ postpar }}
+{{ hooks.postpar | join('\n') }}
 
 {% endif %}
 
-{% if bit %}# Bitstream generation
+{% if 'bit' in steps %}# Bitstream generation
 
-{{ prebit }}
+{{ hooks.prebit | join('\n') }}
 
 run_tool -name {GENERATEPROGRAMMINGFILE}
 
-{{ postbit }}
+{{ hooks.postbit | join('\n') }}
 
 {% endif %}
 
diff --git a/pyfpga/templates/openflow.jinja b/pyfpga/templates/openflow.jinja
index 5aa9b29b..05d01344 100644
--- a/pyfpga/templates/openflow.jinja
+++ b/pyfpga/templates/openflow.jinja
@@ -10,9 +10,9 @@ set -e
 
 DOCKER="docker run --user $(id -u):$(id -g) --rm -v $HOME:$HOME -w $PWD"
 
-{% if syn %}# Synthesis
+{% if 'syn' in steps %}# Synthesis
 $DOCKER hdlc/ghdl:yosys /bin/bash -c "
-{{ presyn }}
+{{ hooks.presyn | join('\n') }}
 yosys -Q -m ghdl -p '
 
 {% if includes %}
@@ -40,7 +40,7 @@ chparam{% for key, value in params.items() %} -set {{ key }} {{ value }}{% endfo
 synth -top {{ top }}
 synth_{{ family }} -top {{ top }} -json {{ project }}.json
 '
-{{ postsyn }}
+{{ hooks.postsyn | join('\n') }}
 "
 {% endif %}
 
@@ -63,7 +63,7 @@ synth_{{ family }} -top {{ top }} -json {{ project }}.json
 #fi
 #}
 
-{% if par %}# Place and Route
+{% if 'par' in steps %}# Place and Route
 
 CONSTRAINTS="{{ constraints | join(' ') }}"
 
@@ -73,9 +73,9 @@ if [ -n "$CONSTRAINTS" ]; then
   CONSTRAINT="--pcf constraints.pcf"
 fi
 $DOCKER hdlc/nextpnr:ice40 /bin/bash -c "
-{{ prepar }}
+{{ hooks.prepar | join('\n') }}
 nextpnr-ice40 --{{ device }} --package {{ package }} $CONSTRAINT --json {{ project }}.json --asc {{ project }}.asc
-{{ postpar }}
+{{ hooks.postpar | join('\n') }}
 "
 $DOCKER hdlc/icestorm /bin/bash -c "
 icetime -d {{ device }} -mtr {{ project }}.rpt {{ project }}.asc
@@ -88,29 +88,29 @@ if [ -n "$CONSTRAINTS" ]; then
   CONSTRAINT="--lpf constraints.lpf"
 fi
 $DOCKER hdlc/nextpnr:ecp5 /bin/bash -c "
-{{ prepar }}
+{{ hooks.prepar | join('\n') }}
 nextpnr-ecp5 --{{ device }} --package {{ package }} $CONSTRAINT --json {{ project }}.json --textcfg {{ project }}.config
-{{ postpar }}
+{{ hooks.postpar | join('\n') }}
 "
 {% endif %}
 
 {% endif %}
 
-{% if bit %}# Bitstream generation
+{% if 'bit' in steps %}# Bitstream generation
 
 {% if family == 'ice40' %}
 $DOCKER hdlc/icestorm /bin/bash -c "
-{{ prebit }}
+{{ hooks.prebit | join('\n') }}
 icepack {{ project }}.asc {{ project }}.bit
-{{ postbit }}
+{{ hooks.postbit | join('\n') }}
 "
 {% endif %}
 
 {% if family == 'ecp5' %}
 $DOCKER hdlc/prjtrellis /bin/bash -c "
-{{ prebit }}
+{{ prebit | join('\n') }}
 ecppack --svf {{ project }}.svf {{ project }}.config {{ project }}.bit
-{{ postbit }}
+{{ postbit | join('\n') }}
 "
 {% endif %}
 
diff --git a/pyfpga/templates/quartus.jinja b/pyfpga/templates/quartus.jinja
index 7ffb78a6..468b88ca 100644
--- a/pyfpga/templates/quartus.jinja
+++ b/pyfpga/templates/quartus.jinja
@@ -6,13 +6,13 @@
 #
 #}
 
-{% if cfg %}# Project configuration -------------------------------------------------------
+{% if 'cfg' in steps %}# Project configuration -------------------------------------------------------
 
 package require ::quartus::project
 project_new {{ project }} -overwrite
 set_global_assignment -name DEVICE {{ part }}
 
-{{ precfg }}
+{{ hooks.precfg | join('\n') }}
 
 {% if files %}# Files inclusion
 {% for name, attr in files.items() %}
@@ -58,46 +58,46 @@ set_parameter -name {{ key }} {{ value }}
 {% endfor %}
 {% endif %}
 
-{{ postcfg }}
+{{ hooks.postcfg | join('\n') }}
 
 project_close
 
 {% endif %}
 
-{% if syn or par or bit %}# Design flow -----------------------------------------------------------------
+{% if 'syn' in steps or 'par' in steps or 'bit' in steps %}# Design flow -----------------------------------------------------------------
 
 package require ::quartus::flow
 project_open -force {{ project }}.qpf
 # set_global_assignment -name NUM_PARALLEL_PROCESSORS ALL
 
-{% if syn %}# Synthesis
+{% if 'syn' in steps %}# Synthesis
 
-{{ presyn }}
+{{ hooks.presyn | join('\n') }}
 
 execute_module -tool map
 
-{{ postsyn }}
+{{ hooks.postsyn | join('\n') }}
 
 {% endif %}
 
-{% if par %}# Place and Route
+{% if 'par' in steps %}# Place and Route
 
-{{ prepar }}
+{{ hooks.prepar | join('\n') }}
 
 execute_module -tool fit
 execute_module -tool sta
 
-{{ postpar }}
+{{ hooks.postpar | join('\n') }}
 
 {% endif %}
 
-{% if bit %}# Bitstream generation
+{% if 'bit' in steps %}# Bitstream generation
 
-{{ prebit }}
+{{ hooks.prebit | join('\n') }}
 
 execute_module -tool asm
 
-{{ postbit }}
+{{ hooks.postbit | join('\n') }}
 
 {% endif %}
 
diff --git a/pyfpga/templates/vivado.jinja b/pyfpga/templates/vivado.jinja
index 6aa4e456..573a7fcb 100644
--- a/pyfpga/templates/vivado.jinja
+++ b/pyfpga/templates/vivado.jinja
@@ -6,14 +6,14 @@
 #
 #}
 
-{% if cfg %}# Project configuration -------------------------------------------------------
+{% if 'cfg' in steps %}# Project configuration -------------------------------------------------------
 
 create_project -force {{ project }}
 set_property SOURCE_MGMT_MODE None [current_project]
 set_property STEPS.SYNTH_DESIGN.ARGS.ASSERT true [get_runs synth_1]
 set_property PART {{ part }} [current_project]
 
-{{ precfg }}
+{{ hooks.precfg | join('\n') }}
 
 {% if files %}# Files inclusion
 {% for name, attr in files.items() %}
@@ -50,19 +50,19 @@ set_property VERILOG_DEFINE { {{ defines.items() | map('join', '=') | join(' ')
 set_property GENERIC { {{ params.items() | map('join', '=') | join(' ') }} } -objects [get_filesets sources_1]
 {% endif %}
 
-{{ postcfg }}
+{{ hooks.postcfg | join('\n') }}
 
 close_project
 
 {% endif %}
 
-{% if syn or par or bit %}# Design flow -----------------------------------------------------------------
+{% if 'syn' in steps or 'par' in steps or 'bit' in steps %}# Design flow -----------------------------------------------------------------
 
 open_project {{ project }}
 
-{% if syn %}# Synthesis
+{% if 'syn' in steps %}# Synthesis
 
-{{ presyn }}
+{{ hooks.presyn | join('\n') }}
 
 # PRESYNTH
 # set_property DESIGN_MODE GateLvl [current_fileset]
@@ -70,16 +70,15 @@ reset_run synth_1
 launch_runs synth_1
 wait_on_run synth_1
 #report_property [get_runs synth_1]
-
 if { [get_property STATUS [get_runs synth_1]] ne "synth_design Complete!" } { exit 1 }
 
-{{ postsyn }}
+{{ hooks.postsyn | join('\n') }}
 
 {% endif %}
 
-{% if par %}# Place and Route
+{% if 'par' in steps %}# Place and Route
 
-{{ prepar }}
+{{ hooks.prepar | join('\n') }}
 
 reset_run impl_1
 launch_runs impl_1
@@ -87,19 +86,19 @@ wait_on_run impl_1
 #report_property [get_runs impl_1]
 if { [get_property STATUS [get_runs impl_1]] ne "route_design Complete!" } { exit 1 }
 
-{{ postpar }}
+{{ hooks.postpar | join('\n') }}
 
 {% endif %}
 
-{% if bit %}# Bitstream generation
+{% if 'bit' in steps %}# Bitstream generation
 
-{{ prebit }}
+{{ hooks.prebit | join('\n') }}
 
 open_run impl_1
 write_bitstream -force {{ project }}
 write_debug_probes -force -quiet {{ project }}.ltx
 
-{{ postbit }}
+{{ hooks.postbit | join('\n') }}
 
 {% endif %}
 
diff --git a/pyfpga/vivado.py b/pyfpga/vivado.py
index b5f59f4e..e68916f6 100644
--- a/pyfpga/vivado.py
+++ b/pyfpga/vivado.py
@@ -22,23 +22,14 @@ def _make_prepare(self, steps):
             'project': self.name or 'vivado',
             'part': self.data.get('part', 'xc7k160t-3-fbg484')
         }
-        for step in steps:
-            context[step] = 1
+        context['steps'] = steps
         context['includes'] = self.data.get('includes', None)
         context['files'] = self.data.get('files', None)
         context['constraints'] = self.data.get('constraints', None)
         context['top'] = self.data.get('top', None)
         context['defines'] = self.data.get('defines', None)
         context['params'] = self.data.get('params', None)
-        if 'hooks' in self.data:
-            context['precfg'] = self.data['hooks'].get('precfg', None)
-            context['postcfg'] = self.data['hooks'].get('postcfg', None)
-            context['presyn'] = self.data['hooks'].get('presyn', None)
-            context['postsyn'] = self.data['hooks'].get('postsyn', None)
-            context['prepar'] = self.data['hooks'].get('prepar', None)
-            context['postpar'] = self.data['hooks'].get('postpar', None)
-            context['presbit'] = self.data['hooks'].get('prebit', None)
-            context['postbit'] = self.data['hooks'].get('postbit', None)
+        context['hooks'] = self.data.get('hooks', None)
         self._create_file('vivado', 'tcl', context)
         return 'vivado -mode batch -notrace -quiet -source vivado.tcl'
 

From f4e9c73684a4ab3d26415337e2f3a8a8f9a566da Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Tue, 9 Jul 2024 19:51:48 -0300
Subject: [PATCH 165/248] Refactor tool classes to simplify implementation

---
 pyfpga/ise.py                        | 46 ++++++++++------------------
 pyfpga/libero.py                     | 40 ++++++++++--------------
 pyfpga/openflow.py                   | 43 ++++++++------------------
 pyfpga/project.py                    | 29 ++++++++++++------
 pyfpga/quartus.py                    | 39 +++++++----------------
 pyfpga/templates/ise.jinja           | 16 +++++-----
 pyfpga/templates/libero.jinja        | 16 +++++-----
 pyfpga/templates/openflow-prog.jinja |  6 ++--
 pyfpga/templates/openflow.jinja      | 20 ++++++------
 pyfpga/templates/quartus.jinja       | 16 +++++-----
 pyfpga/templates/vivado.jinja        | 16 +++++-----
 pyfpga/vivado.py                     | 38 ++++++++---------------
 12 files changed, 133 insertions(+), 192 deletions(-)

diff --git a/pyfpga/ise.py b/pyfpga/ise.py
index b2d102a0..03eb8707 100644
--- a/pyfpga/ise.py
+++ b/pyfpga/ise.py
@@ -8,10 +8,6 @@
 Implements support for ISE.
 """
 
-# pylint: disable=too-many-locals
-# pylint: disable=too-many-branches
-# pylint: disable=duplicate-code
-
 import re
 
 from pyfpga.project import Project
@@ -20,39 +16,29 @@
 class Ise(Project):
     """Class to support ISE projects."""
 
-    def _make_prepare(self, steps):
-        info = get_info(self.data.get('part', 'xc7k160t-3-fbg484'))
-        context = {
-            'project': self.name or 'ise',
-            'family': info['family'],
-            'device': info['device'],
-            'speed': info['speed'],
-            'package': info['package']
-        }
-        context['steps'] = steps
-        context['includes'] = self.data.get('includes', None)
-        context['files'] = self.data.get('files', None)
-        context['constraints'] = self.data.get('constraints', None)
-        context['top'] = self.data.get('top', None)
-        context['defines'] = self.data.get('defines', None)
-        context['params'] = self.data.get('params', None)
-        context['hooks'] = self.data.get('hooks', None)
-        self._create_file('ise', 'tcl', context)
-        return 'xtclsh ise.tcl'
+    def _configure(self):
+        tool = 'ise'
+        self.conf['tool'] = tool
+        self.conf['make_cmd'] = f'xtclsh {tool}.tcl'
+        self.conf['make_ext'] = 'tcl'
+        self.conf['prog_bit'] = 'bit'
+        self.conf['prog_cmd'] = f'impact -batch {tool}-prog.tcl'
+        self.conf['prog_ext'] = 'tcl'
 
-    def _prog_prepare(self, bitstream, position):
-        if not bitstream:
-            basename = self.name or 'ise'
-            bitstream = f'{basename}.bit'
-        context = {'bitstream': bitstream, 'position': position}
-        self._create_file('vivado-prog', 'tcl', context)
-        return 'impact -batch impact-prog'
+    def _make_custom(self):
+        info = get_info(self.data.get('part', 'xc7k160t-3-fbg484'))
+        self.data['family'] = info['family']
+        self.data['device'] = info['device']
+        self.data['speed'] = info['speed']
+        self.data['package'] = info['package']
 
     def add_slog(self, pathname):
         """Add System Verilog file/s."""
         raise NotImplementedError('ISE does not support SystemVerilog')
 
 
+# pylint: disable=duplicate-code
+
 def get_info(part):
     """Get info about the FPGA part.
 
diff --git a/pyfpga/libero.py b/pyfpga/libero.py
index 00014dc8..2f1e4bc4 100644
--- a/pyfpga/libero.py
+++ b/pyfpga/libero.py
@@ -8,10 +8,6 @@
 Implements support for Libero.
 """
 
-# pylint: disable=too-many-locals
-# pylint: disable=too-many-branches
-# pylint: disable=duplicate-code
-
 import re
 
 from pyfpga.project import Project
@@ -20,30 +16,28 @@
 class Libero(Project):
     """Class to support Libero."""
 
-    def _make_prepare(self, steps):
+    def _configure(self):
+        tool = 'libero'
+        self.conf['tool'] = tool
+        self.conf['make_cmd'] = f'{tool} SCRIPT:{tool}.tcl'
+        self.conf['make_ext'] = 'tcl'
+        self.conf['prog_bit'] = None
+        self.conf['prog_cmd'] = None
+        self.conf['prog_ext'] = None
+
+    def _make_custom(self):
         info = get_info(self.data.get('part', 'mpf100t-1-fcg484'))
-        context = {
-            'project': self.name or 'libero',
-            'family': info['family'],
-            'device': info['device'],
-            'speed': info['speed'],
-            'package': info['package']
-        }
-        context['steps'] = steps
-        context['includes'] = self.data.get('includes', None)
-        context['files'] = self.data.get('files', None)
-        context['constraints'] = self.data.get('constraints', None)
-        context['top'] = self.data.get('top', None)
-        context['defines'] = self.data.get('defines', None)
-        context['params'] = self.data.get('params', None)
-        context['hooks'] = self.data.get('hooks', None)
-        self._create_file('libero', 'tcl', context)
-        return 'libero SCRIPT:libero.tcl'
+        self.data['family'] = info['family']
+        self.data['device'] = info['device']
+        self.data['speed'] = info['speed']
+        self.data['package'] = info['package']
 
-    def _prog_prepare(self, bitstream, position):
+    def _prog_custom(self):
         raise NotImplementedError('Libero programming not supported')
 
 
+# pylint: disable=duplicate-code
+
 def get_info(part):
     """Get info about the FPGA part.
 
diff --git a/pyfpga/openflow.py b/pyfpga/openflow.py
index feb7a41e..07cefac4 100644
--- a/pyfpga/openflow.py
+++ b/pyfpga/openflow.py
@@ -8,43 +8,26 @@
 Implements support for an Open Source development flow.
 """
 
-# pylint: disable=too-many-locals
-# pylint: disable=too-many-branches
-# pylint: disable=duplicate-code
-
 from pyfpga.project import Project
 
 
 class Openflow(Project):
     """Class to support Open Source tools."""
 
-    def _make_prepare(self, steps):
-        info = get_info(self.data.get('part', 'hx8k-ct256'))
-        context = {
-            'project': self.name or 'openflow',
-            'family': info['family'],
-            'device': info['device'],
-            'package': info['package']
-        }
-        context['steps'] = steps
-        context['includes'] = self.data.get('includes', None)
-        context['files'] = self.data.get('files', None)
-        context['constraints'] = self.data.get('constraints', None)
-        context['top'] = self.data.get('top', None)
-        context['defines'] = self.data.get('defines', None)
-        context['params'] = self.data.get('params', None)
-        context['hooks'] = self.data.get('hooks', None)
-        self._create_file('openflow', 'sh', context)
-        return 'bash openflow.sh'
+    def _configure(self):
+        tool = 'openflow'
+        self.conf['tool'] = tool
+        self.conf['make_cmd'] = f'bash {tool}.sh'
+        self.conf['make_ext'] = 'sh'
+        self.conf['prog_bit'] = 'bit'
+        self.conf['prog_cmd'] = f'bash {tool}-prog.sh'
+        self.conf['prog_ext'] = 'sh'
 
-    def _prog_prepare(self, bitstream, position):
-        _ = position  # Not needed
-        if not bitstream:
-            basename = self.name or 'openflow'
-            bitstream = f'{basename}.bit'
-        context = {'bitstream': bitstream}
-        self._create_file('openflow-prog', 'sh', context)
-        return 'bash openflow-prog.sh'
+    def _make_custom(self):
+        info = get_info(self.data.get('part', 'hx8k-ct256'))
+        self.data['family'] = info['family']
+        self.data['device'] = info['device']
+        self.data['package'] = info['package']
 
 
 def get_info(part):
diff --git a/pyfpga/project.py b/pyfpga/project.py
index 3ad42b71..1cdceaa0 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -29,8 +29,10 @@ class Project:
 
     def __init__(self, name=None, odir='results'):
         """Class constructor."""
+        self.conf = {}
         self.data = {}
-        self.name = name
+        self._configure()
+        self.data['project'] = name or self.conf['tool']
         self.odir = odir
         # logging config
         self.logger = logging.getLogger(self.__class__.__name__)
@@ -226,8 +228,10 @@ def make(self, first='cfg', last='bit'):
         if first == last:
             message = steps[first]
         self.logger.info('Running %s', message)
-        selected = keys[index[0]:index[1]+1]
-        self._run(self._make_prepare(selected), 'make.log')
+        self.data['steps'] = keys[index[0]:index[1]+1]
+        self._make_custom()
+        self._create_file(self.conf['tool'], self.conf['make_ext'])
+        self._run(self.conf['make_cmd'], 'make.log')
 
     def prog(self, bitstream=None, position=1):
         """Program the FPGA
@@ -243,20 +247,27 @@ def prog(self, bitstream=None, position=1):
         if position not in range(1, 9):
             raise ValueError('Invalid position.')
         self.logger.info('Programming')
-        self._run(self._prog_prepare(bitstream, position), 'prog.log')
+        if not bitstream:
+            bitstream = f'{self.data["project"]}.{self.conf["prog_bit"]}'
+        self._prog_custom()
+        self._create_file(f'{self.conf["tool"]}-prog', self.conf['prog_ext'])
+        self._run(self.conf['prog_cmd'], 'prog.log')
 
-    def _make_prepare(self, steps):
+    def _configure(self):
         raise NotImplementedError('Tool-dependent')
 
-    def _prog_prepare(self, bitstream, position):
-        raise NotImplementedError('Tool-dependent')
+    def _make_custom(self):
+        pass
+
+    def _prog_custom(self):
+        pass
 
-    def _create_file(self, basename, extension, context):
+    def _create_file(self, basename, extension):
         tempdir = Path(__file__).parent.joinpath('templates')
         jinja_file_loader = FileSystemLoader(str(tempdir))
         jinja_env = Environment(loader=jinja_file_loader)
         jinja_template = jinja_env.get_template(f'{basename}.jinja')
-        content = jinja_template.render(context)
+        content = jinja_template.render(self.data)
         directory = Path(self.odir)
         directory.mkdir(parents=True, exist_ok=True)
         filename = f'{basename}.{extension}'
diff --git a/pyfpga/quartus.py b/pyfpga/quartus.py
index 1f4cb2e5..8cd8f66a 100644
--- a/pyfpga/quartus.py
+++ b/pyfpga/quartus.py
@@ -8,38 +8,21 @@
 Implements support for Quartus.
 """
 
-# pylint: disable=too-many-locals
-# pylint: disable=too-many-branches
-# pylint: disable=duplicate-code
-
 from pyfpga.project import Project
 
 
 class Quartus(Project):
     """Class to support Quartus projects."""
 
-    def _make_prepare(self, steps):
-        context = {
-            'project': self.name or 'quartus',
-            'part': self.data.get('part', '10M50SCE144I7G')
-        }
-        context['steps'] = steps
-        context['includes'] = self.data.get('includes', None)
-        context['files'] = self.data.get('files', None)
-        context['constraints'] = self.data.get('constraints', None)
-        context['top'] = self.data.get('top', None)
-        context['defines'] = self.data.get('defines', None)
-        context['params'] = self.data.get('params', None)
-        context['hooks'] = self.data.get('hooks', None)
-        self._create_file('quartus', 'tcl', context)
-        return 'quartus_sh --script quartus.tcl'
+    def _configure(self):
+        tool = 'quartus'
+        self.conf['tool'] = tool
+        self.conf['make_cmd'] = f'quartus_sh --script {tool}.tcl'
+        self.conf['make_ext'] = 'tcl'
+        self.conf['prog_bit'] = 'sof'
+        self.conf['prog_cmd'] = f'bash {tool}-prog.tcl'
+        self.conf['prog_ext'] = 'tcl'
 
-    def _prog_prepare(self, bitstream, position):
-        # sof: SRAM Object File
-        # pof: Programming Object File
-        if not bitstream:
-            basename = self.name or 'quartus'
-            bitstream = f'{basename}.sof'
-        context = {'bitstream': bitstream, 'position': position}
-        self._create_file('quartus-prog', 'tcl', context)
-        return 'bash quartus-prog.sh'
+    def _make_custom(self):
+        if 'part' not in self.data:
+            self.data['part'] = '10M50SCE144I7G'
diff --git a/pyfpga/templates/ise.jinja b/pyfpga/templates/ise.jinja
index b44e003a..c90f2d5e 100644
--- a/pyfpga/templates/ise.jinja
+++ b/pyfpga/templates/ise.jinja
@@ -15,7 +15,7 @@ project set device  {{ device }}
 project set package {{ package }}
 project set speed  -{{ speed }}
 
-{{ hooks.precfg | join('\n') }}
+{% if hooks %}{{ hooks.precfg | join('\n') }}{% endif %}
 
 {% if files %}# Files inclusion
 {% for name, attr in files.items() %}
@@ -49,7 +49,7 @@ project set "Verilog Macros" "{{ defines.items() | map('join', '=') | join(' | '
 project set "Generics, Parameters" "{{ params.items() | map('join', '=') | join(' ') }}" -process "Synthesize - XST"
 {% endif %}
 
-{{ hooks.postcfg | join('\n') }}
+{% if hooks %}{{ hooks.postcfg | join('\n') }}{% endif %}
 
 project close
 
@@ -61,7 +61,7 @@ project open {{ project }}.xise
 
 {% if 'syn' in steps %}# Synthesis
 
-{{ hooks.presyn | join('\n') }}
+{% if hooks %}{{ hooks.presyn | join('\n') }}{% endif %}
 
 # PRESYNTH
 #project set top_level_module_type "EDIF"
@@ -69,13 +69,13 @@ project clean
 process run "Synthesize"
 if { [process get "Synthesize" status] == "errors" } { exit 1 }
 
-{{ hooks.postsyn | join('\n') }}
+{% if hooks %}{{ hooks.postsyn | join('\n') }}{% endif %}
 
 {% endif %}
 
 {% if 'par' in steps %}# Place and Route
 
-{{ hooks.prepar | join('\n') }}
+{% if hooks %}{{ hooks.prepar | join('\n') }}{% endif %}
 
 process run "Translate"
 if { [process get "Translate" status] == "errors" } { exit 1 }
@@ -84,19 +84,19 @@ if { [process get "Map" status] == "errors" } { exit 1 }
 process run "Place & Route"
 if { [process get "Place & Route" status] == "errors" } { exit 1 }
 
-{{ hooks.postpar | join('\n') }}
+{% if hooks %}{{ hooks.postpar | join('\n') }}{% endif %}
 
 {% endif %}
 
 {% if 'bit' in steps %}# Bitstream generation
 
-{{ hooks.prebit | join('\n') }}
+{% if hooks %}{{ hooks.prebit | join('\n') }}{% endif %}
 
 process run "Generate Programming File"
 if { [process get "Generate Programming File" status] == "errors" } { exit 1 }
 catch { file rename -force {{ top }}.bit {{ project }}.bit }
 
-{{ hooks.postbit | join('\n') }}
+{% if hooks %}{{ hooks.postbit | join('\n') }}{% endif %}
 
 {% endif %}
 
diff --git a/pyfpga/templates/libero.jinja b/pyfpga/templates/libero.jinja
index 310807d5..6962f97d 100644
--- a/pyfpga/templates/libero.jinja
+++ b/pyfpga/templates/libero.jinja
@@ -12,7 +12,7 @@ if { [ file exists {{ project }} ] } { file delete -force -- {{ project }} }
 new_project -name {{ project }} -location {libero} -hdl {VERILOG} -family {SmartFusion2}
 set_device -family {{ family }} -die {{ device }} -package {{ package }} -speed {{ speed }}
 
-{{ hooks.precfg | join('\n') }}
+{% if hooks %}{{ hooks.precfg | join('\n') }}{% endif %}
 
 {% if includes %}# Verilog Includes (Libero)
 set_global_include_path_order -paths "{{ includes | join(' ') }}"
@@ -75,7 +75,7 @@ configure_tool -name {SYNTHESIZE} -params {SYNPLIFY_OPTIONS:
 }
 {% endif %}
 
-{{ hooks.postcfg | join('\n') }}
+{% if hooks %}{{ hooks.postcfg | join('\n') }}{% endif %}
 
 close_project
 
@@ -87,32 +87,32 @@ open_project {{ project }}/{{ project }}.prjx
 
 {% if 'syn' in steps %}# Synthesis
 
-{{ hooks.presyn | join('\n') }}
+{% if hooks %}{{ hooks.presyn | join('\n') }}{% endif %}
 
 run_tool -name {SYNTHESIZE}
 
-{{ hooks.postsyn | join('\n') }}
+{% if hooks %}{{ hooks.postsyn | join('\n') }}{% endif %}
 
 {% endif %}
 
 {% if 'par' in steps %}# Place and Route
 
-{{ hooks.prepar | join('\n') }}
+{% if hooks %}{{ hooks.prepar | join('\n') }}{% endif %}
 
 run_tool -name {PLACEROUTE}
 run_tool -name {VERIFYTIMING}
 
-{{ hooks.postpar | join('\n') }}
+{% if hooks %}{{ hooks.postpar | join('\n') }}{% endif %}
 
 {% endif %}
 
 {% if 'bit' in steps %}# Bitstream generation
 
-{{ hooks.prebit | join('\n') }}
+{% if hooks %}{{ hooks.prebit | join('\n') }}{% endif %}
 
 run_tool -name {GENERATEPROGRAMMINGFILE}
 
-{{ hooks.postbit | join('\n') }}
+{% if hooks %}{{ hooks.postbit | join('\n') }}{% endif %}
 
 {% endif %}
 
diff --git a/pyfpga/templates/openflow-prog.jinja b/pyfpga/templates/openflow-prog.jinja
index 47fad80d..7956b2b3 100644
--- a/pyfpga/templates/openflow-prog.jinja
+++ b/pyfpga/templates/openflow-prog.jinja
@@ -9,10 +9,8 @@ set -e
 
 DOCKER="docker run --user $(id -u):$(id -g) --rm -v $HOME:$HOME -w $PWD"
 
-{% if family == 'ice40' %}
-$DOCKER --device /dev/bus/usb hdlc/prog iceprog {{ project }}.bit
-{% endif %}
-
 {% if family == 'ecp5' %}
 $DOCKER --device /dev/bus/usb hdlc/prog openocd -f /usr/share/trellis/misc/openocd/ecp5-evn.cfg -c "transport select jtag; init; svf {{ project }}.svf; exit"
+{% else %}
+$DOCKER --device /dev/bus/usb hdlc/prog iceprog {{ project }}.bit
 {% endif %}
diff --git a/pyfpga/templates/openflow.jinja b/pyfpga/templates/openflow.jinja
index 05d01344..175a68a7 100644
--- a/pyfpga/templates/openflow.jinja
+++ b/pyfpga/templates/openflow.jinja
@@ -12,7 +12,7 @@ DOCKER="docker run --user $(id -u):$(id -g) --rm -v $HOME:$HOME -w $PWD"
 
 {% if 'syn' in steps %}# Synthesis
 $DOCKER hdlc/ghdl:yosys /bin/bash -c "
-{{ hooks.presyn | join('\n') }}
+{% if hooks %}{{ hooks.presyn | join('\n') }}{% endif %}
 yosys -Q -m ghdl -p '
 
 {% if includes %}
@@ -40,7 +40,7 @@ chparam{% for key, value in params.items() %} -set {{ key }} {{ value }}{% endfo
 synth -top {{ top }}
 synth_{{ family }} -top {{ top }} -json {{ project }}.json
 '
-{{ hooks.postsyn | join('\n') }}
+{% if hooks %}{{ hooks.postsyn | join('\n') }}{% endif %}
 "
 {% endif %}
 
@@ -73,9 +73,9 @@ if [ -n "$CONSTRAINTS" ]; then
   CONSTRAINT="--pcf constraints.pcf"
 fi
 $DOCKER hdlc/nextpnr:ice40 /bin/bash -c "
-{{ hooks.prepar | join('\n') }}
+{% if hooks %}{{ hooks.prepar | join('\n') }}{% endif %}
 nextpnr-ice40 --{{ device }} --package {{ package }} $CONSTRAINT --json {{ project }}.json --asc {{ project }}.asc
-{{ hooks.postpar | join('\n') }}
+{% if hooks %}{{ hooks.postpar | join('\n') }}{% endif %}
 "
 $DOCKER hdlc/icestorm /bin/bash -c "
 icetime -d {{ device }} -mtr {{ project }}.rpt {{ project }}.asc
@@ -88,9 +88,9 @@ if [ -n "$CONSTRAINTS" ]; then
   CONSTRAINT="--lpf constraints.lpf"
 fi
 $DOCKER hdlc/nextpnr:ecp5 /bin/bash -c "
-{{ hooks.prepar | join('\n') }}
+{% if hooks %}{{ hooks.prepar | join('\n') }}{% endif %}
 nextpnr-ecp5 --{{ device }} --package {{ package }} $CONSTRAINT --json {{ project }}.json --textcfg {{ project }}.config
-{{ hooks.postpar | join('\n') }}
+{% if hooks %}{{ hooks.postpar | join('\n') }}{% endif %}
 "
 {% endif %}
 
@@ -100,17 +100,17 @@ nextpnr-ecp5 --{{ device }} --package {{ package }} $CONSTRAINT --json {{ projec
 
 {% if family == 'ice40' %}
 $DOCKER hdlc/icestorm /bin/bash -c "
-{{ hooks.prebit | join('\n') }}
+{% if hooks %}{{ hooks.prebit | join('\n') }}{% endif %}
 icepack {{ project }}.asc {{ project }}.bit
-{{ hooks.postbit | join('\n') }}
+{% if hooks %}{{ hooks.postbit | join('\n') }}{% endif %}
 "
 {% endif %}
 
 {% if family == 'ecp5' %}
 $DOCKER hdlc/prjtrellis /bin/bash -c "
-{{ prebit | join('\n') }}
+{% if hooks %}{{ prebit | join('\n') }}{% endif %}
 ecppack --svf {{ project }}.svf {{ project }}.config {{ project }}.bit
-{{ postbit | join('\n') }}
+{% if hooks %}{{ postbit | join('\n') }}{% endif %}
 "
 {% endif %}
 
diff --git a/pyfpga/templates/quartus.jinja b/pyfpga/templates/quartus.jinja
index 468b88ca..5013e1f8 100644
--- a/pyfpga/templates/quartus.jinja
+++ b/pyfpga/templates/quartus.jinja
@@ -12,7 +12,7 @@ package require ::quartus::project
 project_new {{ project }} -overwrite
 set_global_assignment -name DEVICE {{ part }}
 
-{{ hooks.precfg | join('\n') }}
+{% if hooks %}{{ hooks.precfg | join('\n') }}{% endif %}
 
 {% if files %}# Files inclusion
 {% for name, attr in files.items() %}
@@ -58,7 +58,7 @@ set_parameter -name {{ key }} {{ value }}
 {% endfor %}
 {% endif %}
 
-{{ hooks.postcfg | join('\n') }}
+{% if hooks %}{{ hooks.postcfg | join('\n') }}{% endif %}
 
 project_close
 
@@ -72,32 +72,32 @@ project_open -force {{ project }}.qpf
 
 {% if 'syn' in steps %}# Synthesis
 
-{{ hooks.presyn | join('\n') }}
+{% if hooks %}{{ hooks.presyn | join('\n') }}{% endif %}
 
 execute_module -tool map
 
-{{ hooks.postsyn | join('\n') }}
+{% if hooks %}{{ hooks.postsyn | join('\n') }}{% endif %}
 
 {% endif %}
 
 {% if 'par' in steps %}# Place and Route
 
-{{ hooks.prepar | join('\n') }}
+{% if hooks %}{{ hooks.prepar | join('\n') }}{% endif %}
 
 execute_module -tool fit
 execute_module -tool sta
 
-{{ hooks.postpar | join('\n') }}
+{% if hooks %}{{ hooks.postpar | join('\n') }}{% endif %}
 
 {% endif %}
 
 {% if 'bit' in steps %}# Bitstream generation
 
-{{ hooks.prebit | join('\n') }}
+{% if hooks %}{{ hooks.prebit | join('\n') }}{% endif %}
 
 execute_module -tool asm
 
-{{ hooks.postbit | join('\n') }}
+{% if hooks %}{{ hooks.postbit | join('\n') }}{% endif %}
 
 {% endif %}
 
diff --git a/pyfpga/templates/vivado.jinja b/pyfpga/templates/vivado.jinja
index 573a7fcb..babbf3b6 100644
--- a/pyfpga/templates/vivado.jinja
+++ b/pyfpga/templates/vivado.jinja
@@ -13,7 +13,7 @@ set_property SOURCE_MGMT_MODE None [current_project]
 set_property STEPS.SYNTH_DESIGN.ARGS.ASSERT true [get_runs synth_1]
 set_property PART {{ part }} [current_project]
 
-{{ hooks.precfg | join('\n') }}
+{% if hooks %}{{ hooks.precfg | join('\n') }}{% endif %}
 
 {% if files %}# Files inclusion
 {% for name, attr in files.items() %}
@@ -50,7 +50,7 @@ set_property VERILOG_DEFINE { {{ defines.items() | map('join', '=') | join(' ')
 set_property GENERIC { {{ params.items() | map('join', '=') | join(' ') }} } -objects [get_filesets sources_1]
 {% endif %}
 
-{{ hooks.postcfg | join('\n') }}
+{% if hooks %}{{ hooks.postcfg | join('\n') }}{% endif %}
 
 close_project
 
@@ -62,7 +62,7 @@ open_project {{ project }}
 
 {% if 'syn' in steps %}# Synthesis
 
-{{ hooks.presyn | join('\n') }}
+{% if hooks %}{{ hooks.presyn | join('\n') }}{% endif %}
 
 # PRESYNTH
 # set_property DESIGN_MODE GateLvl [current_fileset]
@@ -72,13 +72,13 @@ wait_on_run synth_1
 #report_property [get_runs synth_1]
 if { [get_property STATUS [get_runs synth_1]] ne "synth_design Complete!" } { exit 1 }
 
-{{ hooks.postsyn | join('\n') }}
+{% if hooks %}{{ hooks.postsyn | join('\n') }}{% endif %}
 
 {% endif %}
 
 {% if 'par' in steps %}# Place and Route
 
-{{ hooks.prepar | join('\n') }}
+{% if hooks %}{{ hooks.prepar | join('\n') }}{% endif %}
 
 reset_run impl_1
 launch_runs impl_1
@@ -86,19 +86,19 @@ wait_on_run impl_1
 #report_property [get_runs impl_1]
 if { [get_property STATUS [get_runs impl_1]] ne "route_design Complete!" } { exit 1 }
 
-{{ hooks.postpar | join('\n') }}
+{% if hooks %}{{ hooks.postpar | join('\n') }}{% endif %}
 
 {% endif %}
 
 {% if 'bit' in steps %}# Bitstream generation
 
-{{ hooks.prebit | join('\n') }}
+{% if hooks %}{{ hooks.prebit | join('\n') }}{% endif %}
 
 open_run impl_1
 write_bitstream -force {{ project }}
 write_debug_probes -force -quiet {{ project }}.ltx
 
-{{ hooks.postbit | join('\n') }}
+{% if hooks %}{{ hooks.postbit | join('\n') }}{% endif %}
 
 {% endif %}
 
diff --git a/pyfpga/vivado.py b/pyfpga/vivado.py
index e68916f6..0391a17f 100644
--- a/pyfpga/vivado.py
+++ b/pyfpga/vivado.py
@@ -8,36 +8,22 @@
 Implements support for Vivado.
 """
 
-# pylint: disable=too-many-locals
-# pylint: disable=too-many-branches
-
 from pyfpga.project import Project
 
 
 class Vivado(Project):
     """Class to support Vivado projects."""
 
-    def _make_prepare(self, steps):
-        context = {
-            'project': self.name or 'vivado',
-            'part': self.data.get('part', 'xc7k160t-3-fbg484')
-        }
-        context['steps'] = steps
-        context['includes'] = self.data.get('includes', None)
-        context['files'] = self.data.get('files', None)
-        context['constraints'] = self.data.get('constraints', None)
-        context['top'] = self.data.get('top', None)
-        context['defines'] = self.data.get('defines', None)
-        context['params'] = self.data.get('params', None)
-        context['hooks'] = self.data.get('hooks', None)
-        self._create_file('vivado', 'tcl', context)
-        return 'vivado -mode batch -notrace -quiet -source vivado.tcl'
+    def _configure(self):
+        tool = 'vivado'
+        command = 'vivado -mode batch -notrace -quiet -source'
+        self.conf['tool'] = tool
+        self.conf['make_cmd'] = f'{command} {tool}.tcl'
+        self.conf['make_ext'] = 'tcl'
+        self.conf['prog_bit'] = 'bit'
+        self.conf['prog_cmd'] = f'{command} {tool}-prog.tcl'
+        self.conf['prog_ext'] = 'tcl'
 
-    def _prog_prepare(self, bitstream, position):
-        _ = position  # Not needed
-        if not bitstream:
-            basename = self.name or 'vivado'
-            bitstream = f'{basename}.bit'
-        context = {'BITSTREAM': bitstream}
-        self._create_file('vivado-prog', 'tcl', context)
-        return 'vivado -mode batch -notrace -quiet -source vivado-prog.tcl'
+    def _make_custom(self):
+        if 'part' not in self.data:
+            self.data['part'] = 'xc7k160t-3-fbg484'

From 8e3de7579a5b885e1d156223d6daf435b15691c5 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Tue, 9 Jul 2024 21:30:28 -0300
Subject: [PATCH 166/248] Fix after last changes

---
 tests/test_data.py | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/tests/test_data.py b/tests/test_data.py
index 34f4c633..3ba4e4a9 100644
--- a/tests/test_data.py
+++ b/tests/test_data.py
@@ -1,8 +1,9 @@
 from pathlib import Path
 
-from pyfpga.project import Project
+from pyfpga.vivado import Vivado
 
 pattern = {
+    'project': 'EXAMPLE',
     'part': 'PARTNAME',
     'includes': [
         Path('fakedata/dir1').resolve().as_posix(),
@@ -61,7 +62,7 @@
 
 
 def test_data():
-    prj = Project()
+    prj = Vivado('EXAMPLE')
     prj.set_part('PARTNAME')
     prj.set_top('TOPNAME')
     prj.add_include('fakedata/dir1')

From 52985d91f257ed72bf434b0127c559313efef419 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Tue, 9 Jul 2024 21:30:53 -0300
Subject: [PATCH 167/248] Fix missing check of top

---
 pyfpga/templates/openflow.jinja | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/pyfpga/templates/openflow.jinja b/pyfpga/templates/openflow.jinja
index 175a68a7..2cafa31d 100644
--- a/pyfpga/templates/openflow.jinja
+++ b/pyfpga/templates/openflow.jinja
@@ -37,7 +37,10 @@ read_verilog -defer -sv {{ name }}
 chparam{% for key, value in params.items() %} -set {{ key }} {{ value }}{% endfor %}
 {% endif %}
 
+{% if top%}
 synth -top {{ top }}
+{% endif %}
+
 synth_{{ family }} -top {{ top }} -json {{ project }}.json
 '
 {% if hooks %}{{ hooks.postsyn | join('\n') }}{% endif %}

From 6cd70eb3df590ba6b173a95c769648f28647fa45 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Tue, 9 Jul 2024 21:31:45 -0300
Subject: [PATCH 168/248] Renamed (expanded) test_vivado.py as test_tools.py

---
 tests/test_tools.py  | 71 ++++++++++++++++++++++++++++++++++++++++++++
 tests/test_vivado.py | 28 -----------------
 2 files changed, 71 insertions(+), 28 deletions(-)
 create mode 100644 tests/test_tools.py
 delete mode 100644 tests/test_vivado.py

diff --git a/tests/test_tools.py b/tests/test_tools.py
new file mode 100644
index 00000000..d7924dd7
--- /dev/null
+++ b/tests/test_tools.py
@@ -0,0 +1,71 @@
+from pyfpga.ise import Ise
+from pyfpga.libero import Libero
+from pyfpga.openflow import Openflow
+from pyfpga.quartus import Quartus
+from pyfpga.vivado import Vivado
+
+
+tools = {
+    'ise': Ise,
+    'libero': Libero,
+    'openflow': Openflow,
+    'quartus': Quartus,
+    'vivado': Vivado
+}
+
+def test_ise():
+    generate('ise')
+
+def test_libero():
+    generate('libero')
+
+def test_openflow():
+    generate('openflow')
+
+def test_quartus():
+    generate('quartus')
+
+def test_vivado():
+    generate('vivado')
+
+def generate(tool):
+    prj = tools[tool](odir=f'results/{tool}')
+    prj.set_part('PARTNAME')
+    prj.set_top('TOPNAME')
+    prj.add_include('fakedata/dir1')
+    prj.add_include('fakedata/dir2')
+    if tool != 'ise':
+        prj.add_slog('fakedata/**/*.sv')
+    prj.add_vhdl('fakedata/**/*.vhdl', 'LIB')
+    prj.add_vlog('fakedata/**/*.v')
+    prj.add_cons('fakedata/cons/all.xdc')
+    prj.add_cons('fakedata/cons/syn.xdc', 'syn')
+    prj.add_cons('fakedata/cons/par.xdc', 'par')
+    prj.add_param('PAR1', 'VAL1')
+    prj.add_param('PAR2', 'VAL2')
+    prj.add_define('DEF1', 'VAL1')
+    prj.add_define('DEF2', 'VAL2')
+    prj.add_hook('precfg', 'HOOK01')
+    prj.add_hook('precfg', 'HOOK02')
+    prj.add_hook('postcfg', 'HOOK03')
+    prj.add_hook('postcfg', 'HOOK04')
+    prj.add_hook('presyn', 'HOOK05')
+    prj.add_hook('presyn', 'HOOK06')
+    prj.add_hook('postsyn', 'HOOK07')
+    prj.add_hook('postsyn', 'HOOK08')
+    prj.add_hook('prepar', 'HOOK09')
+    prj.add_hook('prepar', 'HOOK10')
+    prj.add_hook('postpar', 'HOOK11')
+    prj.add_hook('postpar', 'HOOK12')
+    prj.add_hook('prebit', 'HOOK13')
+    prj.add_hook('prebit', 'HOOK14')
+    prj.add_hook('postbit', 'HOOK15')
+    prj.add_hook('postbit', 'HOOK16')
+    try:
+        prj.make()
+    except Exception:
+        pass
+    try:
+        prj.prog()
+    except Exception:
+        pass
diff --git a/tests/test_vivado.py b/tests/test_vivado.py
deleted file mode 100644
index 57781a09..00000000
--- a/tests/test_vivado.py
+++ /dev/null
@@ -1,28 +0,0 @@
-from pyfpga.vivado import Vivado
-
-
-def test_vivado():
-    prj = Vivado()
-    prj.set_part('PARTNAME')
-    prj.set_top('TOPNAME')
-    prj.add_include('fakedata/dir1')
-    prj.add_include('fakedata/dir2')
-    prj.add_slog('fakedata/**/*.sv')
-    prj.add_vhdl('fakedata/**/*.vhdl', 'LIB')
-    prj.add_vlog('fakedata/**/*.v')
-    prj.add_cons('fakedata/cons/all.xdc')
-    prj.add_cons('fakedata/cons/syn.xdc', 'syn')
-    prj.add_cons('fakedata/cons/par.xdc', 'par')
-    prj.add_param('PAR1', 'VAL1')
-    prj.add_param('PAR2', 'VAL2')
-    prj.add_define('DEF1', 'VAL1')
-    prj.add_define('DEF2', 'VAL2')
-    prj.add_hook('precfg', 'PRECFG_HOOK')
-    prj.add_hook('postcfg', 'POSTCFG_HOOK')
-    prj.add_hook('presyn', 'PRESYN_HOOK')
-    prj.add_hook('postsyn', 'POSTSYN_HOOK')
-    prj.add_hook('prepar', 'PREPAR_HOOK')
-    prj.add_hook('postpar', 'POSTPAR_HOOK')
-    prj.add_hook('prebit', 'PREBIT_HOOK')
-    prj.add_hook('postbit', 'POSTBIT_HOOK')
-    prj.make()

From 1629745c855b44d77a68ebeee88f01af3fdb3e87 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Tue, 9 Jul 2024 21:36:12 -0300
Subject: [PATCH 169/248] Fix lint issue

---
 tests/test_tools.py | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/tests/test_tools.py b/tests/test_tools.py
index d7924dd7..3eb7cc0d 100644
--- a/tests/test_tools.py
+++ b/tests/test_tools.py
@@ -13,21 +13,27 @@
     'vivado': Vivado
 }
 
+
 def test_ise():
     generate('ise')
 
+
 def test_libero():
     generate('libero')
 
+
 def test_openflow():
     generate('openflow')
 
+
 def test_quartus():
     generate('quartus')
 
+
 def test_vivado():
     generate('vivado')
 
+
 def generate(tool):
     prj = tools[tool](odir=f'results/{tool}')
     prj.set_part('PARTNAME')

From 664e26b7d0eb263c02a1b06e3017e67ce4513b30 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Tue, 9 Jul 2024 22:04:56 -0300
Subject: [PATCH 170/248] Add to check if resulting files exist

---
 tests/test_tools.py | 34 +++++++++++++++++++++++++++-------
 1 file changed, 27 insertions(+), 7 deletions(-)

diff --git a/tests/test_tools.py b/tests/test_tools.py
index 3eb7cc0d..56895931 100644
--- a/tests/test_tools.py
+++ b/tests/test_tools.py
@@ -1,3 +1,4 @@
+from pathlib import Path
 from pyfpga.ise import Ise
 from pyfpga.libero import Libero
 from pyfpga.openflow import Openflow
@@ -15,28 +16,47 @@
 
 
 def test_ise():
-    generate('ise')
+    tool = 'ise'
+    generate(tool, 'DEVICE-PACKAGE-SPEED')
+    base = f'results/{tool}/{tool}'
+    assert Path(f'{base}.tcl').exists(), 'file not found'
+    assert Path(f'{base}-prog.tcl').exists(), 'file not found'
 
 
 def test_libero():
-    generate('libero')
+    tool = 'libero'
+    generate(tool, 'DEVICE-PACKAGE-SPEED')
+    base = f'results/{tool}/{tool}'
+    assert Path(f'{base}.tcl').exists(), 'file not found'
 
 
 def test_openflow():
-    generate('openflow')
+    tool = 'openflow'
+    generate(tool, 'DEVICE-PACKAGE')
+    base = f'results/{tool}/{tool}'
+    assert Path(f'{base}.sh').exists(), 'file not found'
+    assert Path(f'{base}-prog.sh').exists(), 'file not found'
 
 
 def test_quartus():
-    generate('quartus')
+    tool = 'quartus'
+    generate(tool, 'PARTNAME')
+    base = f'results/{tool}/{tool}'
+    assert Path(f'{base}.tcl').exists(), 'file not found'
+    assert Path(f'{base}-prog.tcl').exists(), 'file not found'
 
 
 def test_vivado():
-    generate('vivado')
+    tool = 'vivado'
+    generate(tool, 'PARTNAME')
+    base = f'results/{tool}/{tool}'
+    assert Path(f'{base}.tcl').exists(), 'file not found'
+    assert Path(f'{base}-prog.tcl').exists(), 'file not found'
 
 
-def generate(tool):
+def generate(tool, part):
     prj = tools[tool](odir=f'results/{tool}')
-    prj.set_part('PARTNAME')
+    prj.set_part(part)
     prj.set_top('TOPNAME')
     prj.add_include('fakedata/dir1')
     prj.add_include('fakedata/dir2')

From c6c655808823656d2569c74cec5779d93eb9fcf8 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Wed, 10 Jul 2024 20:33:08 -0300
Subject: [PATCH 171/248] Renamed parameter name as project

---
 pyfpga/project.py | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/pyfpga/project.py b/pyfpga/project.py
index 1cdceaa0..212fafbe 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -21,18 +21,18 @@
 class Project:
     """Base class to manage an FPGA project.
 
-    :param name: project name (tool name when nothing specified)
-    :type name: str, optional
+    :param project: project name (tool name when nothing specified)
+    :type project: str, optional
     :param odir: output directory
     :type odir: str, optional
     """
 
-    def __init__(self, name=None, odir='results'):
+    def __init__(self, project=None, odir='results'):
         """Class constructor."""
         self.conf = {}
         self.data = {}
         self._configure()
-        self.data['project'] = name or self.conf['tool']
+        self.data['project'] = project or self.conf['tool']
         self.odir = odir
         # logging config
         self.logger = logging.getLogger(self.__class__.__name__)

From 16799d8449278b5cac02e8bd010fed53abe4f80b Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Wed, 10 Jul 2024 20:41:45 -0300
Subject: [PATCH 172/248] Fix the name of a similar project

---
 README.md | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/README.md b/README.md
index cfc2e872..c3e12f21 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,10 @@
 # PyFPGA [![License](https://img.shields.io/badge/License-GPL--3.0-darkgreen?style=flat-square)](LICENSE)
 
-![Vivado](https://img.shields.io/badge/Vivado-2022.1-blue.svg?style=flat-square)
-![Quartus](https://img.shields.io/badge/Quartus--Prime-23.1-blue.svg?style=flat-square)
-![Libero](https://img.shields.io/badge/Libero--Soc-2024.1-blue.svg?style=flat-square)
 ![ISE](https://img.shields.io/badge/ISE-14.7-blue.svg?style=flat-square)
+![Libero](https://img.shields.io/badge/Libero--Soc-2024.1-blue.svg?style=flat-square)
+![Quartus](https://img.shields.io/badge/Quartus--Prime-23.1-blue.svg?style=flat-square)
+![Vivado](https://img.shields.io/badge/Vivado-2022.1-blue.svg?style=flat-square)
+
 ![Openflow](https://img.shields.io/badge/Openflow-GHDL%20%7C%20Yosys%20%7C%20nextpnr%20%7C%20icestorm%20%7C%20prjtrellis-darkgreen.svg?style=flat-square)
 
 PyFPGA is an abstraction layer for working with FPGA development tools in a vendor-agnostic, programmatic way. It is a Python package that provides:
@@ -72,4 +73,4 @@ pip install -e .
 * [Hdlmake](https://ohwr.org/project/hdl-make): tool for generating multi-purpose makefiles for FPGA projects.
 * HDL On Git ([Hog](https://gitlab.com/hog-cern/Hog)): a set of Tcl/Shell scripts plus a suitable methodology to handle HDL designs in a GitLab repository.
 * IPbus Builder ([IPBB](https://github.com/ipbus/ipbb)): a tool for streamlining the synthesis, implementation and simulation of modular firmware projects over multiple platforms.
-* [tsfpa](https://github.com/tsfpga/tsfpga): a flexible and scalable development platform for modern FPGA projects.
+* [tsfpga](https://github.com/tsfpga/tsfpga): a flexible and scalable development platform for modern FPGA projects.

From a2e816de348f90aecea6a49e403f897be469d12f Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Fri, 12 Jul 2024 21:49:25 -0300
Subject: [PATCH 173/248] Add a class to deal with multiple tools in the same
 project

---
 pyfpga/factory.py         | 40 +++++++++++++++++++++++++++++++++++++++
 tests/projects/support.py | 37 ++++++++++++------------------------
 tests/test_tools.py       | 17 ++---------------
 3 files changed, 54 insertions(+), 40 deletions(-)
 create mode 100644 pyfpga/factory.py

diff --git a/pyfpga/factory.py b/pyfpga/factory.py
new file mode 100644
index 00000000..197b69d3
--- /dev/null
+++ b/pyfpga/factory.py
@@ -0,0 +1,40 @@
+#
+# Copyright (C) 2024 Rodrigo A. Melo
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+
+"""
+A factory class to create FPGA projects.
+"""
+
+# pylint: disable=too-few-public-methods
+
+from pyfpga.ise import Ise
+from pyfpga.libero import Libero
+from pyfpga.openflow import Openflow
+from pyfpga.quartus import Quartus
+from pyfpga.vivado import Vivado
+
+
+tools = {
+    'ise': Ise,
+    'libero': Libero,
+    'openflow': Openflow,
+    'quartus': Quartus,
+    'vivado': Vivado
+}
+
+
+class Factory:
+    """A factory class to create FPGA projects."""
+
+    def __init__(self, tool='vivado', project=None, odir='results'):
+        """Class constructor."""
+        if tool not in tools:
+            raise NotImplementedError(f'{tool} is unsupported')
+        self._instance = tools[tool](project, odir)
+
+    def __getattr__(self, name):
+        """Delegate attribute access to the tool instance."""
+        return getattr(self._instance, name)
diff --git a/tests/projects/support.py b/tests/projects/support.py
index 4aa0d009..2e26e3b5 100644
--- a/tests/projects/support.py
+++ b/tests/projects/support.py
@@ -3,20 +3,7 @@
 import argparse
 import sys
 
-from pyfpga.ise import Ise
-from pyfpga.libero import Libero
-from pyfpga.openflow import Openflow
-from pyfpga.quartus import Quartus
-from pyfpga.vivado import Vivado
-
-
-tools = {
-    'ise': Ise,
-    'libero': Libero,
-    'openflow': Openflow,
-    'quartus': Quartus,
-    'vivado': Vivado
-}
+from pyfpga.factory import Factory
 
 parser = argparse.ArgumentParser()
 parser.add_argument(
@@ -28,13 +15,13 @@
 print(f'INFO: the Tool Under Test is {args.tool}')
 
 print('INFO: checking basic Verilog Support')
-prj = tools[args.tool]()
+prj = Factory(args.tool)
 prj.add_vlog('../../examples/sources/vlog/blink.v')
 prj.set_top('Blink')
 prj.make(last='syn')
 
 print('INFO: checking advanced Verilog Support')
-prj = tools[args.tool]()
+prj = Factory(args.tool)
 prj.add_vlog('../../examples/sources/vlog/*.v')
 prj.set_top('Top')
 prj.add_include('../../examples/sources/vlog/include1')
@@ -47,7 +34,7 @@
 
 try:
     print('INFO: checking Verilog Includes Support')
-    prj = tools[args.tool]()
+    prj = Factory(args.tool)
     prj.add_vlog('../../examples/sources/vlog/*.v')
     prj.set_top('Top')
     prj.add_define('DEFINE1', '1')
@@ -63,7 +50,7 @@
 
 try:
     print('INFO: checking Verilog Defines Support')
-    prj = tools[args.tool]()
+    prj = Factory(args.tool)
     prj.add_vlog('../../examples/sources/vlog/*.v')
     prj.set_top('Top')
     prj.add_include('../../examples/sources/vlog/include1')
@@ -79,7 +66,7 @@
 
 try:
     print('INFO: checking Verilog Parameters Support')
-    prj = tools[args.tool]()
+    prj = Factory(args.tool)
     prj.add_vlog('../../examples/sources/vlog/*.v')
     prj.set_top('Top')
     prj.add_include('../../examples/sources/vlog/include1')
@@ -95,13 +82,13 @@
 
 if args.tool not in ['ise']:
     print('INFO: checking basic System Verilog Support')
-    prj = tools[args.tool]()
+    prj = Factory(args.tool)
     prj.add_slog('../../examples/sources/slog/blink.sv')
     prj.set_top('Blink')
     prj.make(last='syn')
 
     print('INFO: checking advanced System Verilog Support')
-    prj = tools[args.tool]()
+    prj = Factory(args.tool)
     prj.add_slog('../../examples/sources/slog/*.sv')
     prj.set_top('Top')
     prj.add_include('../../examples/sources/slog/include1')
@@ -114,13 +101,13 @@
 
 if args.tool not in ['openflow']:
     print('* INFO: checking basic VHDL Support')
-    prj = tools[args.tool]()
+    prj = Factory(args.tool)
     prj.add_vhdl('../../examples/sources/vhdl/blink.vhdl')
     prj.set_top('Blink')
     prj.make(last='syn')
 
     print('* INFO: checking advanced VHDL Support')
-    prj = tools[args.tool]()
+    prj = Factory(args.tool)
     prj.add_vhdl('../../examples/sources/vhdl/*.vhdl', 'blink_lib')
     prj.add_vhdl('../../examples/sources/vhdl/top.vhdl')
     prj.set_top('Top')
@@ -130,7 +117,7 @@
 
     try:
         print('INFO: checking VHDL Generics')
-        prj = tools[args.tool]()
+        prj = Factory(args.tool)
         prj.add_vhdl('../../examples/sources/vhdl/*.vhdl', 'blink_lib')
         prj.add_vhdl('../../examples/sources/vhdl/top.vhdl')
         prj.set_top('Top')
@@ -141,4 +128,4 @@
     except Exception:
         pass
 
-print(f'INFO: Tool Under Test works as expected')
+print(f'INFO: {args.tool} support works as expected')
diff --git a/tests/test_tools.py b/tests/test_tools.py
index 56895931..7c23c4a1 100644
--- a/tests/test_tools.py
+++ b/tests/test_tools.py
@@ -1,18 +1,5 @@
 from pathlib import Path
-from pyfpga.ise import Ise
-from pyfpga.libero import Libero
-from pyfpga.openflow import Openflow
-from pyfpga.quartus import Quartus
-from pyfpga.vivado import Vivado
-
-
-tools = {
-    'ise': Ise,
-    'libero': Libero,
-    'openflow': Openflow,
-    'quartus': Quartus,
-    'vivado': Vivado
-}
+from pyfpga.factory import Factory
 
 
 def test_ise():
@@ -55,7 +42,7 @@ def test_vivado():
 
 
 def generate(tool, part):
-    prj = tools[tool](odir=f'results/{tool}')
+    prj = Factory(tool, odir=f'results/{tool}')
     prj.set_part(part)
     prj.set_top('TOPNAME')
     prj.add_include('fakedata/dir1')

From 0657ee2a1ffafd008e9ac2c36bdc5bf3287ae296 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Fri, 12 Jul 2024 21:51:42 -0300
Subject: [PATCH 174/248] Remove arch specification

---
 docs/internals.rst | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/docs/internals.rst b/docs/internals.rst
index bcaa371f..fd388ae4 100644
--- a/docs/internals.rst
+++ b/docs/internals.rst
@@ -9,26 +9,25 @@ Underlying tool steps
     create project
     config project
     part
-    precfg hook
+    precfg (hook)
     params
     defines
     includes
     files
-    arch
     top
-    postcfg hook
+    postcfg (hook)
     close project
 
     open project
-    presyn hook
+    presyn (hook)
     synthesis
-    postsyn hook
-    prepar hook
+    postsyn (hook)
+    prepar (hook)
     place_and_route
-    postpar hook
-    prebit hook
+    postpar (hook)
+    prebit (hook)
     bitstream
-    postbit hook
+    postbit (hook)
     close project
 
 Internal data structure

From 727ba516eb6adf4bcfc6431b56249af1b0a296e9 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 13 Jul 2024 20:35:06 -0300
Subject: [PATCH 175/248] Make STEPS accessible for external access

---
 pyfpga/project.py | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/pyfpga/project.py b/pyfpga/project.py
index 212fafbe..4f4d9de0 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -18,6 +18,14 @@
 from jinja2 import Environment, FileSystemLoader
 
 
+STEPS = {
+    'cfg': 'Project Creation',
+    'syn': 'Synthesis',
+    'par': 'Place and Route',
+    'bit': 'Bitstream generation'
+}
+
+
 class Project:
     """Base class to manage an FPGA project.
 
@@ -210,23 +218,17 @@ def make(self, first='cfg', last='bit'):
         self.logger.debug('Executing make')
         if 'part' not in self.data:
             self.logger.info('Using the default PART')
-        steps = {
-            'cfg': 'Project Creation',
-            'syn': 'Synthesis',
-            'par': 'Place and Route',
-            'bit': 'Bitstream generation'
-        }
-        if last not in steps:
+        if last not in STEPS:
             raise ValueError('Invalid last step.')
-        if first not in steps:
+        if first not in STEPS:
             raise ValueError('Invalid first step.')
-        keys = list(steps.keys())
+        keys = list(STEPS.keys())
         index = [keys.index(first), keys.index(last)]
         if index[0] > index[1]:
             raise ValueError('Invalid steps combination.')
-        message = f'from {steps[first]} to {steps[last]}'
+        message = f'from {STEPS[first]} to {STEPS[last]}'
         if first == last:
-            message = steps[first]
+            message = STEPS[first]
         self.logger.info('Running %s', message)
         self.data['steps'] = keys[index[0]:index[1]+1]
         self._make_custom()

From 3f9f8b419589280d7d805390fa0ac29ccd36d105 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 13 Jul 2024 20:35:18 -0300
Subject: [PATCH 176/248] Make TOOLS accessible for external access

---
 pyfpga/factory.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/pyfpga/factory.py b/pyfpga/factory.py
index 197b69d3..80782183 100644
--- a/pyfpga/factory.py
+++ b/pyfpga/factory.py
@@ -17,7 +17,7 @@
 from pyfpga.vivado import Vivado
 
 
-tools = {
+TOOLS = {
     'ise': Ise,
     'libero': Libero,
     'openflow': Openflow,
@@ -31,9 +31,9 @@ class Factory:
 
     def __init__(self, tool='vivado', project=None, odir='results'):
         """Class constructor."""
-        if tool not in tools:
+        if tool not in TOOLS:
             raise NotImplementedError(f'{tool} is unsupported')
-        self._instance = tools[tool](project, odir)
+        self._instance = TOOLS[tool](project, odir)
 
     def __getattr__(self, name):
         """Delegate attribute access to the tool instance."""

From 6661d219a577f93cc3ea39656d306ba93b16238b Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 15 Jul 2024 00:01:08 -0300
Subject: [PATCH 177/248] hdl2bit and prj2bit reimplemented

---
 pyfpga/helpers/hdl2bit.py | 123 +++++++++++++++++++++++---------------
 pyfpga/helpers/prj2bit.py |  68 +++++++++------------
 2 files changed, 103 insertions(+), 88 deletions(-)

diff --git a/pyfpga/helpers/hdl2bit.py b/pyfpga/helpers/hdl2bit.py
index 8b6d9173..13d36507 100644
--- a/pyfpga/helpers/hdl2bit.py
+++ b/pyfpga/helpers/hdl2bit.py
@@ -1,38 +1,35 @@
 #!/usr/bin/env python3
 #
-# Copyright (C) 2020 PyFPGA Project
+# Copyright (C) 2020-2024 PyFPGA Project
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 
 """
-A CLI helper utility to go from FPGA design files to a bitstream.
+A CLI helper utility to transform HDL design files into a bitstream.
 """
 
 import argparse
-import logging
 import sys
 
-from fpga import __version__ as version
-from fpga.project import Project, TOOLS
-from fpga.tool import TASKS
+from pathlib import Path
+from pyfpga import __version__ as version
+from pyfpga.factory import Factory, TOOLS
+from pyfpga.project import STEPS
 
-logging.basicConfig()
-logging.getLogger('fpga.project').level = logging.INFO
+tools = list(TOOLS.keys())
+steps = list(STEPS.keys())
 
-EPILOGUE = """
+EPILOGUE = f"""
 Supported values of arguments with choices:
-* TOOL = {}
-* TASK = {}
+* TOOL = {'|'.join(tools)}
+* STEP = {'|'.join(steps)}
 
 Notes:
 * PATH and FILE must be relative to the execution directory.
 * The default PART name and how to specify it depends on the selected TOOL.
 * More than one '--file', '--include' or '--param' arguments can be specified.
-""".format(
-    " | ".join(TOOLS),
-    " | ".join(TASKS[1:len(TASKS)])
-)
+"""
 
 
 def main():
@@ -49,28 +46,22 @@ def main():
     parser.add_argument(
         '-v', '--version',
         action='version',
-        version='v{}'.format(version)
-    )
-
-    parser.add_argument(
-        'top',
-        metavar='TOPFILE',
-        help='a top-level file'
+        version=f'v{version}'
     )
 
     parser.add_argument(
         '-t', '--tool',
         metavar='TOOL',
         default='vivado',
-        choices=TOOLS,
+        choices=tools,
         help='backend tool to be used [vivado]'
     )
 
     parser.add_argument(
-        '-o', '--outdir',
+        '-o', '--odir',
         metavar='PATH',
-        default='temp',
-        help='where to generate files [temp]'
+        default='results',
+        help='where to generate files [results]'
     )
 
     parser.add_argument(
@@ -81,67 +72,105 @@ def main():
 
     parser.add_argument(
         '-f', '--file',
-        metavar='FILE[,PACKAGE]',
+        metavar='FILE[,LIBRARY]',
         action='append',
-        help='add a design file (specifying an optional VHDL package)'
+        help='add a design file (optionally specifying a VHDL library)'
     )
 
     parser.add_argument(
         '-i', '--include',
         metavar='PATH',
         action='append',
-        help='specify where to search Verilog included files'
+        help='specify a Verilog Include directory'
+    )
+
+    parser.add_argument(
+        '--define',
+        metavar=('DEFINE', 'VALUE'),
+        action='append',
+        nargs=2,
+        help='define and set the value of a Verilog Define'
     )
 
     parser.add_argument(
         '--param',
-        metavar=('GENERIC/PARAMETER', 'VALUE'),
+        metavar=('PARAMETER', 'VALUE'),
         action='append',
         nargs=2,
-        help='set the value of a generic/parameter of the top-level'
+        help='set the value of a Generic/Parameter of the top-level'
     )
 
     parser.add_argument(
-        '--run',
-        metavar='TASK',
-        choices=TASKS[1:len(TASKS)],
+        '--project',
+        metavar='PROJECT',
+        help='optional PROJECT name'
+    )
+
+    parser.add_argument(
+        '--last',
+        metavar='STEP',
+        choices=steps,
         default='bit',
-        help='task to perform [{}]'.format('bit')
+        help=f'last step to perform [{steps[-1]}] ({"|".join(steps)})'
+    )
+
+    parser.add_argument(
+        'toplevel',
+        metavar='TOPLEVEL',
+        help='the top-level name'
     )
 
     args = parser.parse_args()
 
+    # -------------------------------------------------------------------------
     # Solving with PyFPGA
+    # -------------------------------------------------------------------------
 
-    prj = Project(args.tool, relative_to_script=False)
-    prj.set_outdir(args.outdir)
+    project = args.project or args.tool
+
+    prj = Factory(args.tool, project, odir=args.odir)
 
     if args.part is not None:
         prj.set_part(args.part)
 
     if args.include is not None:
         for include in args.include:
-            prj.add_vlog_include(include)
+            prj.add_include(include)
 
     if args.file is not None:
         for file in args.file:
-            file = file.split(',')
-            if len(file) > 1:
-                prj.add_files(file[0], library=file[1])
+            aux = file.split(',')
+            file = aux[0]
+            lib = aux[1] if len(aux) > 1 else None
+            ext = Path(file).suffix.lower()
+            if ext == '.v':
+                print(f'* Adding Verilog file: {file}')
+                prj.add_vlog(file)
+            elif ext == '.sv':
+                print(f'* Adding System Verilog file: {file}')
+                prj.add_slog(file)
+            elif ext in ['.vhd', '.vhdl']:
+                if lib:
+                    print(f'* Adding VHDL file: {file} (library={lib})')
+                else:
+                    print(f'* Adding VHDL file: {file}')
+                prj.add_vhdl(file, lib)
             else:
-                prj.add_files(file[0])
+                print(f'* Adding Constraint file: {file}')
+                prj.add_cons(file)
+
+    if args.define is not None:
+        for define in args.define:
+            prj.add_define(define[0], define[1])
 
     if args.param is not None:
         for param in args.param:
             prj.add_param(param[0], param[1])
 
-    prj.add_files(args.top)
-    prj.set_top(args.top)
+    prj.set_top(args.toplevel)
 
     try:
-        prj.generate(args.run)
-    except RuntimeError:
-        logging.error('{} not found'.format(args.tool))
+        prj.make(last=args.last)
     except Exception as e:
         sys.exit('{} ({})'.format(type(e).__name__, e))
 
diff --git a/pyfpga/helpers/prj2bit.py b/pyfpga/helpers/prj2bit.py
index 4a0a6886..1124e452 100644
--- a/pyfpga/helpers/prj2bit.py
+++ b/pyfpga/helpers/prj2bit.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 #
-# Copyright (C) 2020 PyFPGA Project
+# Copyright (C) 2020-2024 PyFPGA Project
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
@@ -10,16 +10,14 @@
 """
 
 import argparse
-import logging
-import os
 import sys
 
-from fpga import __version__ as version
-from fpga.project import Project
-from fpga.tool import TASKS
+from pathlib import Path
+from pyfpga import __version__ as version
+from pyfpga.factory import Factory, TOOLS
+from pyfpga.project import STEPS
 
-logging.basicConfig()
-logging.getLogger('fpga.project').level = logging.INFO
+steps = list(STEPS.keys())[1:len(STEPS)]
 
 
 def main():
@@ -34,29 +32,21 @@ def main():
     parser.add_argument(
         '-v', '--version',
         action='version',
-        version='v{}'.format(version)
+        version=f'v{version}'
     )
 
     parser.add_argument(
-        'project',
-        metavar='PRJFILE',
-        help='a vendor project file'
-    )
-
-    parser.add_argument(
-        '--run',
-        metavar='TASK',
-        choices=TASKS[1:len(TASKS)],
+        '--last',
+        metavar='STEP',
+        choices=steps,
         default='bit',
-        help='task to perform [{}] ({})'.format(
-            'bit', " | ".join(TASKS[1:len(TASKS)])
-        )
+        help=f'last step to perform [{steps[-1]}] ({"|".join(steps)})'
     )
 
     parser.add_argument(
-        '--clean',
-        action='store_true',
-        help='clean the generated project files'
+        'prjfile',
+        metavar='PRJFILE',
+        help='a vendor Project File'
     )
 
     args = parser.parse_args()
@@ -70,34 +60,30 @@ def main():
         '.xpr': 'vivado'
     }
 
-    if not os.path.exists(args.project):
-        sys.exit('Project file not found')
+    prjfile = Path(args.prjfile)
+
+    if not prjfile.exists():
+        sys.exit('file not found.')
 
-    outdir = os.path.dirname(args.project)
-    project, extension = os.path.splitext(args.project)
-    project = os.path.basename(project)
+    directory = prjfile.parent
+    base_name = prjfile.stem
+    extension = prjfile.suffix
 
     tool = ''
     if extension in tool_per_ext:
         tool = tool_per_ext[extension]
-        print('{} Project file found.'.format(tool))
+        print(f'* {tool} project file found.')
     else:
-        sys.exit('Unknown Project file extension')
+        sys.exit('Unknown project file extension')
 
+    # -------------------------------------------------------------------------
     # Solving with PyFPGA
+    # -------------------------------------------------------------------------
 
-    prj = Project(tool, project=project, relative_to_script=False)
-    prj.set_outdir(outdir)
-
-    prj.set_top(project)
+    prj = Factory(tool, base_name, directory)
 
     try:
-        if args.clean:
-            prj.clean()
-        else:
-            prj.generate(args.run, 'syn')
-    except RuntimeError:
-        logging.error('{} not found'.format(tool))
+        prj.make('syn', args.last)
     except Exception as e:
         sys.exit('{} ({})'.format(type(e).__name__, e))
 

From 0df825dbab08398ab749c2f42f4a78e14473c48a Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 15 Jul 2024 00:01:47 -0300
Subject: [PATCH 178/248] Remove info message not compatible with prj2bit

---
 pyfpga/project.py | 2 --
 1 file changed, 2 deletions(-)

diff --git a/pyfpga/project.py b/pyfpga/project.py
index 4f4d9de0..72e7edc0 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -216,8 +216,6 @@ def make(self, first='cfg', last='bit'):
         .. note:: valid steps are ``cfg``, ``syn``, ``par`` and ``bit``.
         """
         self.logger.debug('Executing make')
-        if 'part' not in self.data:
-            self.logger.info('Using the default PART')
         if last not in STEPS:
             raise ValueError('Invalid last step.')
         if first not in STEPS:

From 2f2cdf3a54ac6cba9294e2887276ab8ce97c1021 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 15 Jul 2024 00:41:08 -0300
Subject: [PATCH 179/248] Implemented new tests for helpers

Closes #38
---
 examples/helpers/Makefile    |  39 ----
 examples/helpers/ise.sh      |  18 ++
 examples/helpers/ise.xise    | 353 -----------------------------------
 examples/helpers/libero.sh   |  18 ++
 examples/helpers/openflow.sh |  11 ++
 examples/helpers/quartus.qpf |   3 -
 examples/helpers/quartus.qsf |  24 ---
 examples/helpers/quartus.sh  |  18 ++
 examples/helpers/vivado.sh   |  18 ++
 examples/helpers/vivado.xpr  | 204 --------------------
 10 files changed, 83 insertions(+), 623 deletions(-)
 delete mode 100644 examples/helpers/Makefile
 create mode 100644 examples/helpers/ise.sh
 delete mode 100644 examples/helpers/ise.xise
 create mode 100644 examples/helpers/libero.sh
 create mode 100644 examples/helpers/openflow.sh
 delete mode 100644 examples/helpers/quartus.qpf
 delete mode 100644 examples/helpers/quartus.qsf
 create mode 100644 examples/helpers/quartus.sh
 create mode 100644 examples/helpers/vivado.sh
 delete mode 100644 examples/helpers/vivado.xpr

diff --git a/examples/helpers/Makefile b/examples/helpers/Makefile
deleted file mode 100644
index dbec8388..00000000
--- a/examples/helpers/Makefile
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/usr/bin/make
-
-OUTDIR = ../../build/helpers
-HLPDIR = ../../fpga/helpers
-HDLDIR = ../../hdl
-
-all: hdl2bit-vhdl hdl2bit-verilog prj2bit bitprog
-
-hdl2bit-vhdl:
-	python3 $(HLPDIR)/hdl2bit.py \
-	--outdir $(OUTDIR) \
-	--tool ise --run syn \
-	-f $(HDLDIR)/*.vhdl,examples $(HDLDIR)/top.vhdl
-
-hdl2bit-verilog:
-	python3 $(HLPDIR)/hdl2bit.py \
-	--outdir $(OUTDIR) \
-	--tool ise --run syn \
-	-i $(HDLDIR)/headers1 -i $(HDLDIR)/headers2 \
-	-f $(HDLDIR)/blinking.v $(HDLDIR)/top.v
-
-prj2bit:
-	mkdir -p $(OUTDIR)
-	cp ise.xise quartus.* vivado.xpr $(OUTDIR)
-	python3 $(HLPDIR)/prj2bit.py --run syn $(OUTDIR)/ise.xise
-	python3 $(HLPDIR)/prj2bit.py --run syn $(OUTDIR)/quartus.qpf
-	python3 $(HLPDIR)/prj2bit.py --run syn $(OUTDIR)/vivado.xpr
-
-bitprog:
-	python3 $(HLPDIR)/bitprog.py \
-	--outdir $(OUTDIR) \
-	--tool ise \
-	-d fpga -p 2 \
-	../../README.md
-
-clean:
-	python3 $(HLPDIR)/prj2bit.py --clean $(OUTDIR)/ise.xise
-	python3 $(HLPDIR)/prj2bit.py --clean $(OUTDIR)/quartus.qpf
-	python3 $(HLPDIR)/prj2bit.py --clean $(OUTDIR)/vivado.xpr
diff --git a/examples/helpers/ise.sh b/examples/helpers/ise.sh
new file mode 100644
index 00000000..11e73ba8
--- /dev/null
+++ b/examples/helpers/ise.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+set -e
+
+HDIR=../../pyfpga/helpers
+
+python3 $HDIR/hdl2bit.py -t ise -o results/ise-vlog -p xc6slx16-3-csg32 \
+    -i ../sources/vlog/include1 -i ../sources/vlog/include2 \
+    -f ../sources/vlog/blink.v -f ../sources/vlog/top.v \
+    -f ../sources/cons/nexys3/clk.xcf -f ../sources/cons/nexys3/clk.ucf -f ../sources/cons/nexys3/led.ucf \
+    --define DEFINE1 1 --define DEFINE2 1 --param FREQ 125000000 --param SECS 1 Top
+
+python3 $HDIR/hdl2bit.py -t ise -o results/ise-vhdl -p xc6slx16-3-csg32 --project example \
+    -f ../sources/vhdl/blink.vhdl,blink_lib -f ../sources/vhdl/blink_pkg.vhdl,blink_lib -f ../sources/vhdl/top.vhdl \
+    -f ../sources/cons/nexys3/clk.xcf -f ../sources/cons/nexys3/clk.ucf -f ../sources/cons/nexys3/led.ucf \
+    --param FREQ 125000000 --param SECS 1 --last cfg Top
+
+python3 $HDIR/prj2bit.py results/ise-vhdl/example.xise
diff --git a/examples/helpers/ise.xise b/examples/helpers/ise.xise
deleted file mode 100644
index 6233d9b1..00000000
--- a/examples/helpers/ise.xise
+++ /dev/null
@@ -1,353 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
-<project xmlns="http://www.xilinx.com/XMLSchema" xmlns:xil_pn="http://www.xilinx.com/XMLSchema">
-
-  <version xil_pn:ise_version="14.7" xil_pn:schema_version="2"/>
-
-  <files>
-    <file xil_pn:name="../../hdl/blinking.vhdl" xil_pn:type="FILE_VHDL">
-      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="1"/>
-      <association xil_pn:name="Implementation" xil_pn:seqID="2"/>
-      <library xil_pn:name="examples"/>
-    </file>
-    <file xil_pn:name="../../hdl/examples_pkg.vhdl" xil_pn:type="FILE_VHDL">
-      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="2"/>
-      <association xil_pn:name="Implementation" xil_pn:seqID="1"/>
-      <library xil_pn:name="examples"/>
-    </file>
-    <file xil_pn:name="../../hdl/top.vhdl" xil_pn:type="FILE_VHDL">
-      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="3"/>
-      <association xil_pn:name="Implementation" xil_pn:seqID="3"/>
-    </file>
-    <file xil_pn:name="../../examples/ise/s6micro.ucf" xil_pn:type="FILE_UCF">
-      <association xil_pn:name="Implementation" xil_pn:seqID="0"/>
-    </file>
-  </files>
-
-  <properties>
-    <property xil_pn:name="AES Initial Vector spartan6" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="AES Key (Hex String) spartan6" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Add I/O Buffers" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Allow Logic Optimization Across Hierarchy" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Allow SelectMAP Pins to Persist" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Allow Unexpanded Blocks" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Allow Unmatched LOC Constraints" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Allow Unmatched Timing Group Constraints" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Analysis Effort Level" xil_pn:value="Standard" xil_pn:valueState="default"/>
-    <property xil_pn:name="Asynchronous To Synchronous" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Auto Implementation Compile Order" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Auto Implementation Top" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Automatic BRAM Packing" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Automatically Insert glbl Module in the Netlist" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Automatically Run Generate Target PROM/ACE File" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="BRAM Utilization Ratio" xil_pn:value="100" xil_pn:valueState="default"/>
-    <property xil_pn:name="Bring Out Global Set/Reset Net as a Port" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Bring Out Global Tristate Net as a Port" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Bus Delimiter" xil_pn:value="&lt;>" xil_pn:valueState="default"/>
-    <property xil_pn:name="Case" xil_pn:value="Maintain" xil_pn:valueState="default"/>
-    <property xil_pn:name="Case Implementation Style" xil_pn:value="None" xil_pn:valueState="default"/>
-    <property xil_pn:name="Change Device Speed To" xil_pn:value="-2" xil_pn:valueState="default"/>
-    <property xil_pn:name="Change Device Speed To Post Trace" xil_pn:value="-2" xil_pn:valueState="default"/>
-    <property xil_pn:name="Combinatorial Logic Optimization" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Compile EDK Simulation Library" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Compile SIMPRIM (Timing) Simulation Library" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Compile UNISIM (Functional) Simulation Library" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Compile XilinxCoreLib (CORE Generator) Simulation Library" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Compile for HDL Debugging" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Configuration Clk (Configuration Pins)" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
-    <property xil_pn:name="Configuration Pin Done" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
-    <property xil_pn:name="Configuration Pin M0" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
-    <property xil_pn:name="Configuration Pin M1" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
-    <property xil_pn:name="Configuration Pin M2" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
-    <property xil_pn:name="Configuration Pin Program" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
-    <property xil_pn:name="Configuration Rate spartan6" xil_pn:value="2" xil_pn:valueState="default"/>
-    <property xil_pn:name="Correlate Output to Input Design" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Create ASCII Configuration File" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Create Binary Configuration File" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Create Bit File" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Create I/O Pads from Ports" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Create IEEE 1532 Configuration File spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Create Logic Allocation File" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Create Mask File" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Create ReadBack Data Files" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Cross Clock Analysis" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="DSP Utilization Ratio" xil_pn:value="100" xil_pn:valueState="default"/>
-    <property xil_pn:name="Delay Values To Be Read from SDF" xil_pn:value="Setup Time" xil_pn:valueState="default"/>
-    <property xil_pn:name="Device" xil_pn:value="xc6slx16" xil_pn:valueState="non-default"/>
-    <property xil_pn:name="Device Family" xil_pn:value="Spartan6" xil_pn:valueState="non-default"/>
-    <property xil_pn:name="Device Speed Grade/Select ABS Minimum" xil_pn:value="-2" xil_pn:valueState="default"/>
-    <property xil_pn:name="Disable Detailed Package Model Insertion" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Do Not Escape Signal and Instance Names in Netlist" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Done (Output Events)" xil_pn:value="Default (4)" xil_pn:valueState="default"/>
-    <property xil_pn:name="Drive Awake Pin During Suspend/Wake Sequence spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Drive Done Pin High" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Enable BitStream Compression" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Enable Cyclic Redundancy Checking (CRC) spartan6" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Enable Debugging of Serial Mode BitStream" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Enable External Master Clock spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Enable Internal Done Pipe" xil_pn:value="true" xil_pn:valueState="non-default"/>
-    <property xil_pn:name="Enable Message Filtering" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Enable Multi-Pin Wake-Up Suspend Mode spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Enable Multi-Threading" xil_pn:value="Off" xil_pn:valueState="default"/>
-    <property xil_pn:name="Enable Multi-Threading par spartan6" xil_pn:value="Off" xil_pn:valueState="default"/>
-    <property xil_pn:name="Enable Outputs (Output Events)" xil_pn:value="Default (5)" xil_pn:valueState="default"/>
-    <property xil_pn:name="Enable Suspend/Wake Global Set/Reset spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Encrypt Bitstream spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Encrypt Key Select spartan6" xil_pn:value="BBRAM" xil_pn:valueState="default"/>
-    <property xil_pn:name="Equivalent Register Removal Map" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Equivalent Register Removal XST" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Essential Bits" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Evaluation Development Board" xil_pn:value="None Specified" xil_pn:valueState="default"/>
-    <property xil_pn:name="Exclude Compilation of Deprecated EDK Cores" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Exclude Compilation of EDK Sub-Libraries" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Extra Cost Tables Map" xil_pn:value="0" xil_pn:valueState="default"/>
-    <property xil_pn:name="Extra Effort (Highest PAR level only)" xil_pn:value="None" xil_pn:valueState="default"/>
-    <property xil_pn:name="FPGA Start-Up Clock" xil_pn:value="CCLK" xil_pn:valueState="default"/>
-    <property xil_pn:name="FSM Encoding Algorithm" xil_pn:value="Auto" xil_pn:valueState="default"/>
-    <property xil_pn:name="FSM Style" xil_pn:value="LUT" xil_pn:valueState="default"/>
-    <property xil_pn:name="Filter Files From Compile Order" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Flatten Output Netlist" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Functional Model Target Language ArchWiz" xil_pn:value="Verilog" xil_pn:valueState="default"/>
-    <property xil_pn:name="Functional Model Target Language Coregen" xil_pn:value="Verilog" xil_pn:valueState="default"/>
-    <property xil_pn:name="Functional Model Target Language Schematic" xil_pn:value="Verilog" xil_pn:valueState="default"/>
-    <property xil_pn:name="GTS Cycle During Suspend/Wakeup Sequence spartan6" xil_pn:value="4" xil_pn:valueState="default"/>
-    <property xil_pn:name="GWE Cycle During Suspend/Wakeup Sequence spartan6" xil_pn:value="5" xil_pn:valueState="default"/>
-    <property xil_pn:name="Generate Architecture Only (No Entity Declaration)" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Generate Asynchronous Delay Report" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Generate Clock Region Report" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Generate Constraints Interaction Report" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Generate Constraints Interaction Report Post Trace" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Generate Datasheet Section" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Generate Datasheet Section Post Trace" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Generate Detailed MAP Report" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Generate Multiple Hierarchical Netlist Files" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Generate Post-Place &amp; Route Power Report" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Generate Post-Place &amp; Route Simulation Model" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Generate RTL Schematic" xil_pn:value="Yes" xil_pn:valueState="default"/>
-    <property xil_pn:name="Generate SAIF File for Power Optimization/Estimation Par" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Generate Testbench File" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Generate Timegroups Section" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Generate Timegroups Section Post Trace" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Generics, Parameters" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Global Optimization Goal" xil_pn:value="AllClockNets" xil_pn:valueState="default"/>
-    <property xil_pn:name="Global Optimization map spartan6" xil_pn:value="Off" xil_pn:valueState="default"/>
-    <property xil_pn:name="Global Set/Reset Port Name" xil_pn:value="GSR_PORT" xil_pn:valueState="default"/>
-    <property xil_pn:name="Global Tristate Port Name" xil_pn:value="GTS_PORT" xil_pn:valueState="default"/>
-    <property xil_pn:name="Hierarchy Separator" xil_pn:value="/" xil_pn:valueState="default"/>
-    <property xil_pn:name="ISim UUT Instance Name" xil_pn:value="UUT" xil_pn:valueState="default"/>
-    <property xil_pn:name="Ignore User Timing Constraints Map" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Ignore User Timing Constraints Par" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Implementation Top" xil_pn:value="Architecture|Top|Structural" xil_pn:valueState="non-default"/>
-    <property xil_pn:name="Implementation Top File" xil_pn:value="../../hdl/top.vhdl" xil_pn:valueState="non-default"/>
-    <property xil_pn:name="Implementation Top Instance Path" xil_pn:value="/Top" xil_pn:valueState="non-default"/>
-    <property xil_pn:name="Include 'uselib Directive in Verilog File" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Include SIMPRIM Models in Verilog File" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Include UNISIM Models in Verilog File" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Include sdf_annotate task in Verilog File" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Incremental Compilation" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Insert Buffers to Prevent Pulse Swallowing" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Instantiation Template Target Language Xps" xil_pn:value="Verilog" xil_pn:valueState="default"/>
-    <property xil_pn:name="JTAG Pin TCK" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
-    <property xil_pn:name="JTAG Pin TDI" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
-    <property xil_pn:name="JTAG Pin TDO" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
-    <property xil_pn:name="JTAG Pin TMS" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
-    <property xil_pn:name="Keep Hierarchy" xil_pn:value="No" xil_pn:valueState="default"/>
-    <property xil_pn:name="LUT Combining Map" xil_pn:value="Off" xil_pn:valueState="default"/>
-    <property xil_pn:name="LUT Combining Xst" xil_pn:value="Auto" xil_pn:valueState="default"/>
-    <property xil_pn:name="Language" xil_pn:value="VHDL" xil_pn:valueState="default"/>
-    <property xil_pn:name="Last Applied Goal" xil_pn:value="Balanced" xil_pn:valueState="default"/>
-    <property xil_pn:name="Last Applied Strategy" xil_pn:value="Xilinx Default (unlocked)" xil_pn:valueState="default"/>
-    <property xil_pn:name="Last Unlock Status" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Launch SDK after Export" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Library for Verilog Sources" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Load glbl" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Manual Implementation Compile Order" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Map Slice Logic into Unused Block RAMs" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Mask Pins for Multi-Pin Wake-Up Suspend Mode spartan6" xil_pn:value="0x00" xil_pn:valueState="default"/>
-    <property xil_pn:name="Max Fanout" xil_pn:value="100000" xil_pn:valueState="default"/>
-    <property xil_pn:name="Maximum Compression" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Maximum Number of Lines in Report" xil_pn:value="1000" xil_pn:valueState="default"/>
-    <property xil_pn:name="Maximum Signal Name Length" xil_pn:value="20" xil_pn:valueState="default"/>
-    <property xil_pn:name="Move First Flip-Flop Stage" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Move Last Flip-Flop Stage" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="MultiBoot: Insert IPROG CMD in the Bitfile spartan6" xil_pn:value="Enable" xil_pn:valueState="default"/>
-    <property xil_pn:name="MultiBoot: Next Configuration Mode spartan6" xil_pn:value="001" xil_pn:valueState="default"/>
-    <property xil_pn:name="MultiBoot: Starting Address for Golden Configuration spartan6" xil_pn:value="0x00000000" xil_pn:valueState="default"/>
-    <property xil_pn:name="MultiBoot: Starting Address for Next Configuration spartan6" xil_pn:value="0x00000000" xil_pn:valueState="default"/>
-    <property xil_pn:name="MultiBoot: Use New Mode for Next Configuration spartan6" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="MultiBoot: User-Defined Register for Failsafe Scheme spartan6" xil_pn:value="0x0000" xil_pn:valueState="default"/>
-    <property xil_pn:name="Netlist Hierarchy" xil_pn:value="As Optimized" xil_pn:valueState="default"/>
-    <property xil_pn:name="Netlist Translation Type" xil_pn:value="Timestamp" xil_pn:valueState="default"/>
-    <property xil_pn:name="Number of Clock Buffers" xil_pn:value="16" xil_pn:valueState="default"/>
-    <property xil_pn:name="Number of Paths in Error/Verbose Report" xil_pn:value="3" xil_pn:valueState="default"/>
-    <property xil_pn:name="Number of Paths in Error/Verbose Report Post Trace" xil_pn:value="3" xil_pn:valueState="default"/>
-    <property xil_pn:name="Optimization Effort spartan6" xil_pn:value="Normal" xil_pn:valueState="default"/>
-    <property xil_pn:name="Optimization Goal" xil_pn:value="Speed" xil_pn:valueState="default"/>
-    <property xil_pn:name="Optimize Instantiated Primitives" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Other Bitgen Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Other Bitgen Command Line Options spartan6" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Other Compiler Options" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Other Compiler Options Map" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Other Compiler Options Par" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Other Compiler Options Translate" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Other Compxlib Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Other Map Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Other NETGEN Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Other Ngdbuild Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Other Place &amp; Route Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Other Simulator Commands Behavioral" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Other Simulator Commands Post-Map" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Other Simulator Commands Post-Route" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Other Simulator Commands Post-Translate" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Other XPWR Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Other XST Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Output Extended Identifiers" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Output File Name" xil_pn:value="Top" xil_pn:valueState="default"/>
-    <property xil_pn:name="Overwrite Compiled Libraries" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Pack I/O Registers into IOBs" xil_pn:value="Auto" xil_pn:valueState="default"/>
-    <property xil_pn:name="Pack I/O Registers/Latches into IOBs" xil_pn:value="Off" xil_pn:valueState="default"/>
-    <property xil_pn:name="Package" xil_pn:value="csg324" xil_pn:valueState="default"/>
-    <property xil_pn:name="Perform Advanced Analysis" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Perform Advanced Analysis Post Trace" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Perform Timing-Driven Packing and Placement" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Place &amp; Route Effort Level (Overall)" xil_pn:value="High" xil_pn:valueState="default"/>
-    <property xil_pn:name="Place And Route Mode" xil_pn:value="Normal Place and Route" xil_pn:valueState="default"/>
-    <property xil_pn:name="Place MultiBoot Settings into Bitstream spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Placer Effort Level Map" xil_pn:value="High" xil_pn:valueState="default"/>
-    <property xil_pn:name="Placer Extra Effort Map" xil_pn:value="None" xil_pn:valueState="default"/>
-    <property xil_pn:name="Port to be used" xil_pn:value="Auto - default" xil_pn:valueState="default"/>
-    <property xil_pn:name="Post Map Simulation Model Name" xil_pn:value="Top_map.v" xil_pn:valueState="default"/>
-    <property xil_pn:name="Post Place &amp; Route Simulation Model Name" xil_pn:value="Top_timesim.v" xil_pn:valueState="default"/>
-    <property xil_pn:name="Post Synthesis Simulation Model Name" xil_pn:value="Top_synthesis.v" xil_pn:valueState="default"/>
-    <property xil_pn:name="Post Translate Simulation Model Name" xil_pn:value="Top_translate.v" xil_pn:valueState="default"/>
-    <property xil_pn:name="Power Reduction Map spartan6" xil_pn:value="Off" xil_pn:valueState="default"/>
-    <property xil_pn:name="Power Reduction Par" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Power Reduction Xst" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Preferred Language" xil_pn:value="Verilog" xil_pn:valueState="default"/>
-    <property xil_pn:name="Produce Verbose Report" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Project Description" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Property Specification in Project File" xil_pn:value="Store all values" xil_pn:valueState="default"/>
-    <property xil_pn:name="RAM Extraction" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="RAM Style" xil_pn:value="Auto" xil_pn:valueState="default"/>
-    <property xil_pn:name="ROM Extraction" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="ROM Style" xil_pn:value="Auto" xil_pn:valueState="default"/>
-    <property xil_pn:name="Read Cores" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Reduce Control Sets" xil_pn:value="Auto" xil_pn:valueState="default"/>
-    <property xil_pn:name="Regenerate Core" xil_pn:value="Under Current Project Setting" xil_pn:valueState="default"/>
-    <property xil_pn:name="Register Balancing" xil_pn:value="No" xil_pn:valueState="default"/>
-    <property xil_pn:name="Register Duplication Map" xil_pn:value="Off" xil_pn:valueState="default"/>
-    <property xil_pn:name="Register Duplication Xst" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Register Ordering spartan6" xil_pn:value="4" xil_pn:valueState="default"/>
-    <property xil_pn:name="Release Write Enable (Output Events)" xil_pn:value="Default (6)" xil_pn:valueState="default"/>
-    <property xil_pn:name="Rename Design Instance in Testbench File to" xil_pn:value="UUT" xil_pn:valueState="default"/>
-    <property xil_pn:name="Rename Top Level Architecture To" xil_pn:value="Structure" xil_pn:valueState="default"/>
-    <property xil_pn:name="Rename Top Level Entity to" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Rename Top Level Module To" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Report Fastest Path(s) in Each Constraint" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Report Fastest Path(s) in Each Constraint Post Trace" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Report Paths by Endpoint" xil_pn:value="3" xil_pn:valueState="default"/>
-    <property xil_pn:name="Report Paths by Endpoint Post Trace" xil_pn:value="3" xil_pn:valueState="default"/>
-    <property xil_pn:name="Report Type" xil_pn:value="Verbose Report" xil_pn:valueState="default"/>
-    <property xil_pn:name="Report Type Post Trace" xil_pn:value="Verbose Report" xil_pn:valueState="default"/>
-    <property xil_pn:name="Report Unconstrained Paths" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Report Unconstrained Paths Post Trace" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Reset On Configuration Pulse Width" xil_pn:value="100" xil_pn:valueState="default"/>
-    <property xil_pn:name="Resource Sharing" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Retain Hierarchy" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Retry Configuration if CRC Error Occurs spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Revision Select" xil_pn:value="00" xil_pn:valueState="default"/>
-    <property xil_pn:name="Revision Select Tristate" xil_pn:value="Disable" xil_pn:valueState="default"/>
-    <property xil_pn:name="Run Design Rules Checker (DRC)" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Run for Specified Time" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Run for Specified Time Map" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Run for Specified Time Par" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Run for Specified Time Translate" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Safe Implementation" xil_pn:value="No" xil_pn:valueState="default"/>
-    <property xil_pn:name="Security" xil_pn:value="Enable Readback and Reconfiguration" xil_pn:valueState="default"/>
-    <property xil_pn:name="Selected Simulation Root Source Node Behavioral" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Selected Simulation Root Source Node Post-Map" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Selected Simulation Root Source Node Post-Route" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Selected Simulation Root Source Node Post-Translate" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Selected Simulation Source Node" xil_pn:value="UUT" xil_pn:valueState="default"/>
-    <property xil_pn:name="Set SPI Configuration Bus Width spartan6" xil_pn:value="1" xil_pn:valueState="default"/>
-    <property xil_pn:name="Setup External Master Clock Division spartan6" xil_pn:value="1" xil_pn:valueState="default"/>
-    <property xil_pn:name="Shift Register Extraction" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Shift Register Minimum Size spartan6" xil_pn:value="2" xil_pn:valueState="default"/>
-    <property xil_pn:name="Show All Models" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Simulation Model Target" xil_pn:value="Verilog" xil_pn:valueState="default"/>
-    <property xil_pn:name="Simulation Run Time ISim" xil_pn:value="1000 ns" xil_pn:valueState="default"/>
-    <property xil_pn:name="Simulation Run Time Map" xil_pn:value="1000 ns" xil_pn:valueState="default"/>
-    <property xil_pn:name="Simulation Run Time Par" xil_pn:value="1000 ns" xil_pn:valueState="default"/>
-    <property xil_pn:name="Simulation Run Time Translate" xil_pn:value="1000 ns" xil_pn:valueState="default"/>
-    <property xil_pn:name="Simulator" xil_pn:value="ISim (VHDL/Verilog)" xil_pn:valueState="default"/>
-    <property xil_pn:name="Slice Utilization Ratio" xil_pn:value="100" xil_pn:valueState="default"/>
-    <property xil_pn:name="Specify 'define Macro Name and Value" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Specify Top Level Instance Names Behavioral" xil_pn:value="Default" xil_pn:valueState="default"/>
-    <property xil_pn:name="Specify Top Level Instance Names Post-Map" xil_pn:value="Default" xil_pn:valueState="default"/>
-    <property xil_pn:name="Specify Top Level Instance Names Post-Route" xil_pn:value="Default" xil_pn:valueState="default"/>
-    <property xil_pn:name="Specify Top Level Instance Names Post-Translate" xil_pn:value="Default" xil_pn:valueState="default"/>
-    <property xil_pn:name="Speed Grade" xil_pn:value="-2" xil_pn:valueState="non-default"/>
-    <property xil_pn:name="Starting Placer Cost Table (1-100) Map spartan6" xil_pn:value="1" xil_pn:valueState="default"/>
-    <property xil_pn:name="Synthesis Tool" xil_pn:value="XST (VHDL/Verilog)" xil_pn:valueState="default"/>
-    <property xil_pn:name="Target Simulator" xil_pn:value="Please Specify" xil_pn:valueState="default"/>
-    <property xil_pn:name="Timing Mode Map" xil_pn:value="Performance Evaluation" xil_pn:valueState="default"/>
-    <property xil_pn:name="Timing Mode Par" xil_pn:value="Performance Evaluation" xil_pn:valueState="default"/>
-    <property xil_pn:name="Top-Level Module Name in Output Netlist" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Top-Level Source Type" xil_pn:value="HDL" xil_pn:valueState="default"/>
-    <property xil_pn:name="Trim Unconnected Signals" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Tristate On Configuration Pulse Width" xil_pn:value="0" xil_pn:valueState="default"/>
-    <property xil_pn:name="Unused IOB Pins" xil_pn:value="Pull Down" xil_pn:valueState="default"/>
-    <property xil_pn:name="Use 64-bit PlanAhead on 64-bit Systems" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Use Clock Enable" xil_pn:value="Auto" xil_pn:valueState="default"/>
-    <property xil_pn:name="Use Custom Project File Behavioral" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Use Custom Project File Post-Map" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Use Custom Project File Post-Route" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Use Custom Project File Post-Translate" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Use Custom Simulation Command File Behavioral" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Use Custom Simulation Command File Map" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Use Custom Simulation Command File Par" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Use Custom Simulation Command File Translate" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Use Custom Waveform Configuration File Behav" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Use Custom Waveform Configuration File Map" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Use Custom Waveform Configuration File Par" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Use Custom Waveform Configuration File Translate" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Use DSP Block spartan6" xil_pn:value="Auto" xil_pn:valueState="default"/>
-    <property xil_pn:name="Use LOC Constraints" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="Use RLOC Constraints" xil_pn:value="Yes" xil_pn:valueState="default"/>
-    <property xil_pn:name="Use Smart Guide" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Use Synchronous Reset" xil_pn:value="Auto" xil_pn:valueState="default"/>
-    <property xil_pn:name="Use Synchronous Set" xil_pn:value="Auto" xil_pn:valueState="default"/>
-    <property xil_pn:name="Use Synthesis Constraints File" xil_pn:value="true" xil_pn:valueState="default"/>
-    <property xil_pn:name="User Browsed Strategy Files" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="UserID Code (8 Digit Hexadecimal)" xil_pn:value="0xFFFFFFFF" xil_pn:valueState="default"/>
-    <property xil_pn:name="VCCAUX Voltage Level spartan6" xil_pn:value="2.5V" xil_pn:valueState="default"/>
-    <property xil_pn:name="VHDL Source Analysis Standard" xil_pn:value="VHDL-93" xil_pn:valueState="default"/>
-    <property xil_pn:name="Value Range Check" xil_pn:value="false" xil_pn:valueState="default"/>
-    <property xil_pn:name="Verilog Macros" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="Wait for DCM and PLL Lock (Output Events) spartan6" xil_pn:value="Default (NoWait)" xil_pn:valueState="default"/>
-    <property xil_pn:name="Wakeup Clock spartan6" xil_pn:value="Startup Clock" xil_pn:valueState="default"/>
-    <property xil_pn:name="Watchdog Timer Value spartan6" xil_pn:value="0xFFFF" xil_pn:valueState="default"/>
-    <property xil_pn:name="Working Directory" xil_pn:value="." xil_pn:valueState="non-default"/>
-    <property xil_pn:name="Write Timing Constraints" xil_pn:value="false" xil_pn:valueState="default"/>
-    <!--                                                                                  -->
-    <!-- The following properties are for internal use only. These should not be modified.-->
-    <!--                                                                                  -->
-    <property xil_pn:name="PROP_BehavioralSimTop" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="PROP_DesignName" xil_pn:value="ise" xil_pn:valueState="non-default"/>
-    <property xil_pn:name="PROP_DevFamilyPMName" xil_pn:value="spartan6" xil_pn:valueState="default"/>
-    <property xil_pn:name="PROP_FPGAConfiguration" xil_pn:value="FPGAConfiguration" xil_pn:valueState="default"/>
-    <property xil_pn:name="PROP_PostMapSimTop" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="PROP_PostParSimTop" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="PROP_PostSynthSimTop" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="PROP_PostXlateSimTop" xil_pn:value="" xil_pn:valueState="default"/>
-    <property xil_pn:name="PROP_PreSynthesis" xil_pn:value="PreSynthesis" xil_pn:valueState="default"/>
-    <property xil_pn:name="PROP_intProjectCreationTimestamp" xil_pn:value="2020-03-16T16:18:39" xil_pn:valueState="non-default"/>
-    <property xil_pn:name="PROP_intWbtProjectID" xil_pn:value="B648D1B8F4BEACF2D00ECCB3CF3FDEAA" xil_pn:valueState="non-default"/>
-    <property xil_pn:name="PROP_intWorkingDirLocWRTProjDir" xil_pn:value="Same" xil_pn:valueState="non-default"/>
-    <property xil_pn:name="PROP_intWorkingDirUsed" xil_pn:value="No" xil_pn:valueState="non-default"/>
-  </properties>
-
-  <libraries>
-    <library xil_pn:name="examples"/>
-  </libraries>
-
-</project>
diff --git a/examples/helpers/libero.sh b/examples/helpers/libero.sh
new file mode 100644
index 00000000..1a56da93
--- /dev/null
+++ b/examples/helpers/libero.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+set -e
+
+HDIR=../../pyfpga/helpers
+
+python3 $HDIR/hdl2bit.py -t libero -o results/libero-vlog -p m2s010-1-tq144 \
+    -i ../sources/vlog/include1 -i ../sources/vlog/include2 \
+    -f ../sources/vlog/blink.v -f ../sources/vlog/top.v \
+    -f ../sources/cons/maker/clk.sdc -f ../sources/cons/maker/clk.pdc -f ../sources/cons/maker/led.pdc \
+    --define DEFINE1 1 --define DEFINE2 1 --param FREQ 125000000 --param SECS 1 Top
+
+python3 $HDIR/hdl2bit.py -t libero -o results/libero-vhdl -p m2s010-1-tq144 --project example \
+    -f ../sources/vhdl/blink.vhdl,blink_lib -f ../sources/vhdl/blink_pkg.vhdl,blink_lib -f ../sources/vhdl/top.vhdl \
+    -f ../sources/cons/maker/clk.sdc -f ../sources/cons/maker/clk.pdc -f ../sources/cons/maker/led.pdc \
+    --param FREQ 125000000 --param SECS 1 --last cfg Top
+
+python3 $HDIR/prj2bit.py results/libero-vhdl/libero/example.prjx
diff --git a/examples/helpers/openflow.sh b/examples/helpers/openflow.sh
new file mode 100644
index 00000000..7b959a1a
--- /dev/null
+++ b/examples/helpers/openflow.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+set -e
+
+HDIR=../../pyfpga/helpers
+
+python3 $HDIR/hdl2bit.py -t openflow -o results/openflow-vlog -p hx1k-tq144 \
+    -i ../sources/vlog/include1 -i ../sources/vlog/include2 \
+    -f ../sources/vlog/blink.v -f ../sources/vlog/top.v \
+    -f ../sources/cons/icestick/clk.pcf -f ../sources/cons/icestick/led.pcf \
+    --define DEFINE1 1 --define DEFINE2 1 --param FREQ 100000000 --param SECS 1 Top
diff --git a/examples/helpers/quartus.qpf b/examples/helpers/quartus.qpf
deleted file mode 100644
index 4abe28eb..00000000
--- a/examples/helpers/quartus.qpf
+++ /dev/null
@@ -1,3 +0,0 @@
-QUARTUS_VERSION = "18.1"
-DATE = "22:03:07  March 16, 2020"
-PROJECT_REVISION = "quartus"
diff --git a/examples/helpers/quartus.qsf b/examples/helpers/quartus.qsf
deleted file mode 100644
index 3c046b57..00000000
--- a/examples/helpers/quartus.qsf
+++ /dev/null
@@ -1,24 +0,0 @@
-set_global_assignment -name FAMILY "Cyclone V"
-set_global_assignment -name DEVICE 5CSEBA6U23I7
-set_global_assignment -name TOP_LEVEL_ENTITY top
-set_global_assignment -name ORIGINAL_QUARTUS_VERSION 18.1.0
-set_global_assignment -name PROJECT_CREATION_TIME_DATE "22:03:07  MARCH 16, 2020"
-set_global_assignment -name LAST_QUARTUS_VERSION "18.1.0 Lite Edition"
-set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
-set_global_assignment -name MIN_CORE_JUNCTION_TEMP "-40"
-set_global_assignment -name MAX_CORE_JUNCTION_TEMP 100
-set_global_assignment -name ERROR_CHECK_FREQUENCY_DIVISOR 256
-set_global_assignment -name EDA_SIMULATION_TOOL "ModelSim-Altera (Verilog)"
-set_global_assignment -name EDA_TIME_SCALE "1 ps" -section_id eda_simulation
-set_global_assignment -name EDA_OUTPUT_DATA_FORMAT "VERILOG HDL" -section_id eda_simulation
-set_global_assignment -name POWER_PRESET_COOLING_SOLUTION "23 MM HEAT SINK WITH 200 LFPM AIRFLOW"
-set_global_assignment -name POWER_BOARD_THERMAL_MODEL "NONE (CONSERVATIVE)"
-set_global_assignment -name TCL_SCRIPT_FILE ../../examples/quartus/de10nano.tcl
-set_global_assignment -name SDC_FILE ../../examples/quartus/de10nano.sdc
-set_global_assignment -name VHDL_FILE ../../hdl/top.vhdl
-set_global_assignment -name VHDL_FILE ../../hdl/examples_pkg.vhdl -library examples
-set_global_assignment -name VHDL_FILE ../../hdl/blinking.vhdl -library examples
-set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top
-set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top
-set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
-set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
diff --git a/examples/helpers/quartus.sh b/examples/helpers/quartus.sh
new file mode 100644
index 00000000..b2ae4437
--- /dev/null
+++ b/examples/helpers/quartus.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+set -e
+
+HDIR=../../pyfpga/helpers
+
+python3 $HDIR/hdl2bit.py -t quartus -o results/quartus-vlog -p 5CSEBA6U23I7 \
+    -i ../sources/vlog/include1 -i ../sources/vlog/include2 \
+    -f ../sources/vlog/blink.v -f ../sources/vlog/top.v \
+    -f ../sources/cons/de10nano/clk.sdc -f ../sources/cons/de10nano/clk.tcl -f ../sources/cons/de10nano/led.tcl \
+    --define DEFINE1 1 --define DEFINE2 1 --param FREQ 125000000 --param SECS 1 Top
+
+python3 $HDIR/hdl2bit.py -t quartus -o results/quartus-vhdl -p 5CSEBA6U23I7 --project example \
+    -f ../sources/vhdl/blink.vhdl,blink_lib -f ../sources/vhdl/blink_pkg.vhdl,blink_lib -f ../sources/vhdl/top.vhdl \
+    -f ../sources/cons/de10nano/clk.sdc -f ../sources/cons/de10nano/clk.tcl -f ../sources/cons/de10nano/led.tcl \
+    --param FREQ 125000000 --param SECS 1 --last cfg Top
+
+python3 $HDIR/prj2bit.py results/quartus-vhdl/example.qpf
diff --git a/examples/helpers/vivado.sh b/examples/helpers/vivado.sh
new file mode 100644
index 00000000..868599a3
--- /dev/null
+++ b/examples/helpers/vivado.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+set -e
+
+HDIR=../../pyfpga/helpers
+
+python3 $HDIR/hdl2bit.py -t vivado -o results/vivado-vlog -p xc7z010-1-clg400 \
+    -i ../sources/vlog/include1 -i ../sources/vlog/include2 \
+    -f ../sources/vlog/blink.v -f ../sources/vlog/top.v \
+    -f ../sources/cons/ZYBO/timing.xdc -f ../sources/cons/ZYBO/clk.xdc -f ../sources/cons/ZYBO/led.xdc \
+    --define DEFINE1 1 --define DEFINE2 1 --param FREQ 125000000 --param SECS 1 Top
+
+python3 $HDIR/hdl2bit.py -t vivado -o results/vivado-vhdl -p xc7z010-1-clg400 --project example \
+    -f ../sources/vhdl/blink.vhdl,blink_lib -f ../sources/vhdl/blink_pkg.vhdl,blink_lib -f ../sources/vhdl/top.vhdl \
+    -f ../sources/cons/ZYBO/timing.xdc -f ../sources/cons/ZYBO/clk.xdc -f ../sources/cons/ZYBO/led.xdc \
+    --param FREQ 125000000 --param SECS 1 --last cfg Top
+
+python3 $HDIR/prj2bit.py results/vivado-vhdl/example.xpr
diff --git a/examples/helpers/vivado.xpr b/examples/helpers/vivado.xpr
deleted file mode 100644
index 521ddb20..00000000
--- a/examples/helpers/vivado.xpr
+++ /dev/null
@@ -1,204 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Product Version: Vivado v2019.2 (64-bit)              -->
-<!--                                                         -->
-<!-- Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.   -->
-
-<Project Version="7" Minor="44" Path="./vivado.xpr">
-  <DefaultLaunch Dir="$PRUNDIR"/>
-  <Configuration>
-    <Option Name="Id" Val="22631844048a4353bd9203eebcbe9e6d"/>
-    <Option Name="Part" Val="xc7z010clg400-1"/>
-    <Option Name="CompiledLibDir" Val="$PCACHEDIR/compile_simlib"/>
-    <Option Name="CompiledLibDirXSim" Val=""/>
-    <Option Name="CompiledLibDirModelSim" Val="$PCACHEDIR/compile_simlib/modelsim"/>
-    <Option Name="CompiledLibDirQuesta" Val="$PCACHEDIR/compile_simlib/questa"/>
-    <Option Name="CompiledLibDirIES" Val="$PCACHEDIR/compile_simlib/ies"/>
-    <Option Name="CompiledLibDirXcelium" Val="$PCACHEDIR/compile_simlib/xcelium"/>
-    <Option Name="CompiledLibDirVCS" Val="$PCACHEDIR/compile_simlib/vcs"/>
-    <Option Name="CompiledLibDirRiviera" Val="$PCACHEDIR/compile_simlib/riviera"/>
-    <Option Name="CompiledLibDirActivehdl" Val="$PCACHEDIR/compile_simlib/activehdl"/>
-    <Option Name="BoardPart" Val=""/>
-    <Option Name="ActiveSimSet" Val="sim_1"/>
-    <Option Name="DefaultLib" Val="xil_defaultlib"/>
-    <Option Name="ProjectType" Val="Default"/>
-    <Option Name="IPOutputRepo" Val="$PCACHEDIR/ip"/>
-    <Option Name="IPCachePermission" Val="read"/>
-    <Option Name="IPCachePermission" Val="write"/>
-    <Option Name="EnableCoreContainer" Val="FALSE"/>
-    <Option Name="CreateRefXciForCoreContainers" Val="FALSE"/>
-    <Option Name="IPUserFilesDir" Val="$PIPUSERFILESDIR"/>
-    <Option Name="IPStaticSourceDir" Val="$PIPUSERFILESDIR/ipstatic"/>
-    <Option Name="EnableBDX" Val="FALSE"/>
-    <Option Name="WTXSimLaunchSim" Val="0"/>
-    <Option Name="WTModelSimLaunchSim" Val="0"/>
-    <Option Name="WTQuestaLaunchSim" Val="0"/>
-    <Option Name="WTIesLaunchSim" Val="0"/>
-    <Option Name="WTVcsLaunchSim" Val="0"/>
-    <Option Name="WTRivieraLaunchSim" Val="0"/>
-    <Option Name="WTActivehdlLaunchSim" Val="0"/>
-    <Option Name="WTXSimExportSim" Val="0"/>
-    <Option Name="WTModelSimExportSim" Val="0"/>
-    <Option Name="WTQuestaExportSim" Val="0"/>
-    <Option Name="WTIesExportSim" Val="0"/>
-    <Option Name="WTVcsExportSim" Val="0"/>
-    <Option Name="WTRivieraExportSim" Val="0"/>
-    <Option Name="WTActivehdlExportSim" Val="0"/>
-    <Option Name="GenerateIPUpgradeLog" Val="TRUE"/>
-    <Option Name="XSimRadix" Val="hex"/>
-    <Option Name="XSimTimeUnit" Val="ns"/>
-    <Option Name="XSimArrayDisplayLimit" Val="1024"/>
-    <Option Name="XSimTraceLimit" Val="65536"/>
-    <Option Name="SimTypes" Val="rtl"/>
-    <Option Name="SimTypes" Val="bfm"/>
-    <Option Name="SimTypes" Val="tlm"/>
-    <Option Name="SimTypes" Val="tlm_dpi"/>
-    <Option Name="MEMEnableMemoryMapGeneration" Val="TRUE"/>
-    <Option Name="DcpsUptoDate" Val="TRUE"/>
-  </Configuration>
-  <FileSets Version="1" Minor="31">
-    <FileSet Name="sources_1" Type="DesignSrcs" RelSrcDir="$PSRCDIR/sources_1">
-      <Filter Type="Srcs"/>
-      <File Path="$PPRDIR/../../hdl/blinking.vhdl">
-        <FileInfo>
-          <Attr Name="Library" Val="examples"/>
-          <Attr Name="UsedIn" Val="synthesis"/>
-          <Attr Name="UsedIn" Val="simulation"/>
-        </FileInfo>
-      </File>
-      <File Path="$PPRDIR/../../hdl/examples_pkg.vhdl">
-        <FileInfo>
-          <Attr Name="Library" Val="examples"/>
-          <Attr Name="UsedIn" Val="synthesis"/>
-          <Attr Name="UsedIn" Val="simulation"/>
-        </FileInfo>
-      </File>
-      <File Path="$PPRDIR/../../hdl/top.vhdl">
-        <FileInfo>
-          <Attr Name="UsedIn" Val="synthesis"/>
-          <Attr Name="UsedIn" Val="simulation"/>
-        </FileInfo>
-      </File>
-      <Config>
-        <Option Name="DesignMode" Val="RTL"/>
-        <Option Name="TopModule" Val="Top"/>
-        <Option Name="TopAutoSet" Val="TRUE"/>
-      </Config>
-    </FileSet>
-    <FileSet Name="constrs_1" Type="Constrs" RelSrcDir="$PSRCDIR/constrs_1">
-      <Filter Type="Constrs"/>
-      <File Path="$PPRDIR/../../examples/vivado/zybo.xdc">
-        <FileInfo>
-          <Attr Name="UsedIn" Val="synthesis"/>
-          <Attr Name="UsedIn" Val="implementation"/>
-        </FileInfo>
-      </File>
-      <Config>
-        <Option Name="ConstrsType" Val="XDC"/>
-      </Config>
-    </FileSet>
-    <FileSet Name="sim_1" Type="SimulationSrcs" RelSrcDir="$PSRCDIR/sim_1">
-      <Config>
-        <Option Name="DesignMode" Val="RTL"/>
-        <Option Name="TopModule" Val="Top"/>
-        <Option Name="TopLib" Val="xil_defaultlib"/>
-        <Option Name="TopAutoSet" Val="TRUE"/>
-        <Option Name="TransportPathDelay" Val="0"/>
-        <Option Name="TransportIntDelay" Val="0"/>
-        <Option Name="SelectedSimModel" Val="rtl"/>
-        <Option Name="SrcSet" Val="sources_1"/>
-      </Config>
-    </FileSet>
-    <FileSet Name="utils_1" Type="Utils" RelSrcDir="$PSRCDIR/utils_1">
-      <Filter Type="Utils"/>
-      <Config>
-        <Option Name="TopAutoSet" Val="TRUE"/>
-      </Config>
-    </FileSet>
-  </FileSets>
-  <Simulators>
-    <Simulator Name="XSim">
-      <Option Name="Description" Val="Vivado Simulator"/>
-      <Option Name="CompiledLib" Val="0"/>
-    </Simulator>
-    <Simulator Name="ModelSim">
-      <Option Name="Description" Val="ModelSim Simulator"/>
-    </Simulator>
-    <Simulator Name="Questa">
-      <Option Name="Description" Val="Questa Advanced Simulator"/>
-    </Simulator>
-    <Simulator Name="IES">
-      <Option Name="Description" Val="Incisive Enterprise Simulator (IES)"/>
-    </Simulator>
-    <Simulator Name="Xcelium">
-      <Option Name="Description" Val="Xcelium Parallel Simulator"/>
-    </Simulator>
-    <Simulator Name="VCS">
-      <Option Name="Description" Val="Verilog Compiler Simulator (VCS)"/>
-    </Simulator>
-    <Simulator Name="Riviera">
-      <Option Name="Description" Val="Riviera-PRO Simulator"/>
-    </Simulator>
-  </Simulators>
-  <Runs Version="1" Minor="11">
-    <Run Id="synth_1" Type="Ft3:Synth" SrcSet="sources_1" Part="xc7z010clg400-1" ConstrsSet="constrs_1" Description="Vivado Synthesis Defaults" AutoIncrementalCheckpoint="false" WriteIncrSynthDcp="false" State="current" IncludeInArchive="true">
-      <Strategy Version="1" Minor="2">
-        <StratHandle Name="Vivado Synthesis Defaults" Flow="Vivado Synthesis 2019">
-          <Desc>Vivado Synthesis Defaults</Desc>
-        </StratHandle>
-        <Step Id="synth_design"/>
-      </Strategy>
-      <ReportStrategy Name="Vivado Synthesis Default Reports" Flow="Vivado Synthesis 2019"/>
-      <Report Name="ROUTE_DESIGN.REPORT_METHODOLOGY" Enabled="1"/>
-      <RQSFiles/>
-    </Run>
-    <Run Id="impl_1" Type="Ft2:EntireDesign" Part="xc7z010clg400-1" ConstrsSet="constrs_1" Description="Default settings for Implementation." AutoIncrementalCheckpoint="false" WriteIncrSynthDcp="false" State="current" SynthRun="synth_1" IncludeInArchive="true" GenFullBitstream="true">
-      <Strategy Version="1" Minor="2">
-        <StratHandle Name="Vivado Implementation Defaults" Flow="Vivado Implementation 2019">
-          <Desc>Default settings for Implementation.</Desc>
-        </StratHandle>
-        <Step Id="init_design"/>
-        <Step Id="opt_design"/>
-        <Step Id="power_opt_design"/>
-        <Step Id="place_design"/>
-        <Step Id="post_place_power_opt_design"/>
-        <Step Id="phys_opt_design" EnableStepBool="1"/>
-        <Step Id="route_design"/>
-        <Step Id="post_route_phys_opt_design"/>
-        <Step Id="write_bitstream"/>
-      </Strategy>
-      <ReportStrategy Name="Vivado Implementation Default Reports" Flow="Vivado Implementation 2019"/>
-      <Report Name="ROUTE_DESIGN.REPORT_METHODOLOGY" Enabled="1"/>
-      <RQSFiles/>
-    </Run>
-  </Runs>
-  <Board/>
-  <DashboardSummary Version="1" Minor="0">
-    <Dashboards>
-      <Dashboard Name="default_dashboard">
-        <Gadgets>
-          <Gadget Name="drc_1" Type="drc" Version="1" Row="2" Column="0">
-            <GadgetParam Name="REPORTS" Type="string_list" Value="impl_1#impl_1_route_report_drc_0 "/>
-          </Gadget>
-          <Gadget Name="methodology_1" Type="methodology" Version="1" Row="2" Column="1">
-            <GadgetParam Name="REPORTS" Type="string_list" Value="impl_1#impl_1_route_report_methodology_0 "/>
-          </Gadget>
-          <Gadget Name="power_1" Type="power" Version="1" Row="1" Column="0">
-            <GadgetParam Name="REPORTS" Type="string_list" Value="impl_1#impl_1_route_report_power_0 "/>
-          </Gadget>
-          <Gadget Name="timing_1" Type="timing" Version="1" Row="0" Column="1">
-            <GadgetParam Name="REPORTS" Type="string_list" Value="impl_1#impl_1_route_report_timing_summary_0 "/>
-          </Gadget>
-          <Gadget Name="utilization_1" Type="utilization" Version="1" Row="0" Column="0">
-            <GadgetParam Name="REPORTS" Type="string_list" Value="synth_1#synth_1_synth_report_utilization_0 "/>
-            <GadgetParam Name="RUN.STEP" Type="string" Value="synth_design"/>
-            <GadgetParam Name="RUN.TYPE" Type="string" Value="synthesis"/>
-          </Gadget>
-          <Gadget Name="utilization_2" Type="utilization" Version="1" Row="1" Column="1">
-            <GadgetParam Name="REPORTS" Type="string_list" Value="impl_1#impl_1_place_report_utilization_0 "/>
-          </Gadget>
-        </Gadgets>
-      </Dashboard>
-      <CurrentDashboard>default_dashboard</CurrentDashboard>
-    </Dashboards>
-  </DashboardSummary>
-</Project>

From 79bb0b4d81c57760615f24332735275192423f89 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 15 Jul 2024 01:10:09 -0300
Subject: [PATCH 180/248] Add workaround for prj2bit

---
 pyfpga/templates/libero.jinja | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/pyfpga/templates/libero.jinja b/pyfpga/templates/libero.jinja
index 6962f97d..aaddbf9b 100644
--- a/pyfpga/templates/libero.jinja
+++ b/pyfpga/templates/libero.jinja
@@ -83,7 +83,9 @@ close_project
 
 {% if 'syn' in steps or 'par' in steps or 'bit' in steps %}# Design flow -----------------------------------------------------------------
 
-open_project {{ project }}/{{ project }}.prjx
+if { [catch {open_project {{ project }}/{{ project }}.prjx} ] } {
+  open_project {{ project }}.prjx
+}
 
 {% if 'syn' in steps %}# Synthesis
 

From d9b02da7709e5819bf843be5c4bd84a5d0b2cced Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 15 Jul 2024 01:49:45 -0300
Subject: [PATCH 181/248] docs: added helpers

---
 docs/Makefile    |  6 +++++-
 docs/helpers.rst | 12 ++++++++++++
 docs/index.rst   |  1 +
 docs/tools.rst   | 13 ++++---------
 4 files changed, 22 insertions(+), 10 deletions(-)
 create mode 100644 docs/helpers.rst

diff --git a/docs/Makefile b/docs/Makefile
index d4bb2cbb..48576179 100644
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -14,7 +14,11 @@ help:
 
 .PHONY: help Makefile
 
+$(BUILDDIR)/hdl2bit $(BUILDDIR)/prj2bit:
+	@mkdir -p $(@D)
+	@python3 ../pyfpga/helpers/$(@F).py -h > $@
+
 # Catch-all target: route all unknown targets to Sphinx using the new
 # "make mode" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).
-%: Makefile
+%: Makefile $(BUILDDIR)/hdl2bit $(BUILDDIR)/prj2bit
 	@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/docs/helpers.rst b/docs/helpers.rst
new file mode 100644
index 00000000..e5623c92
--- /dev/null
+++ b/docs/helpers.rst
@@ -0,0 +1,12 @@
+Helpers
+=======
+
+hdl2bit
+-------
+
+.. literalinclude:: _build/hdl2bit
+
+prj2bit
+-------
+
+.. literalinclude:: _build/prj2bit
diff --git a/docs/index.rst b/docs/index.rst
index 88c75aa4..ad539fe4 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -17,5 +17,6 @@ PyFPGA's documentation
    basic
    advanced
    api
+   helpers
    tools
    internals
diff --git a/docs/tools.rst b/docs/tools.rst
index 0bbbcc5a..a7c6dc55 100644
--- a/docs/tools.rst
+++ b/docs/tools.rst
@@ -1,25 +1,20 @@
 Tools support
 =============
 
-.. ATTENTION::
-
-  (2024-05-31) To be updated.
-
 +---------------+-----------+---------+-----+-----------------------------------------------+
 | Tools         | Vendor    | Version | Tcl | Comment                                       |
 +===============+===========+=========+=====+===============================================+
 | ISE           | Xilinx    | 14.7    | 8.4 | Discontinued in 2013                          |
 +---------------+-----------+---------+-----+-----------------------------------------------+
-| Libero-SoC    | Microsemi | 12.2    | 8.5 | Important changes in version 12.0 (2019)      |
+| Libero-SoC    | Microsemi | 2024.1  | 8.5 | Important changes in version 12.0 (2019)      |
 +---------------+-----------+---------+-----+-----------------------------------------------+
-| Quartus Prime | Intel     | 19.1    | 8.6 | Known as Quartus II until version 15.0 (2015) |
+| Openflow      |           |         |     |                                               |
 +---------------+-----------+---------+-----+-----------------------------------------------+
-| Vivado        | Xilinx    | 2019.1  | 8.5 | Introduced in 2012, it superseded ISE         |
+| Quartus Prime | Intel     | 23.1    | 8.6 | Known as Quartus II until version 15.0 (2015) |
 +---------------+-----------+---------+-----+-----------------------------------------------+
-| Yosys         |           | 0.9-dev | 8.6 | The open-source synthesizer                   |
+| Vivado        | Xilinx    | 2022.1  | 8.5 | Introduced in 2012, it superseded ISE         |
 +---------------+-----------+---------+-----+-----------------------------------------------+
 
-
 * ISE supports devices starting from Spartan 3/Virtex 4 until some first members of the 7 series.
   Previous Spartan/Virtex devices were supported until version 10. Vivado supports devices starting
   from the 7 series.

From d713c90793c9b71fdb1b5d9c7a212813adc11557 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 15 Jul 2024 01:56:50 -0300
Subject: [PATCH 182/248] ci: add pyfpga as dependency

---
 .github/workflows/docs.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 26c51962..0f17d958 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -12,7 +12,7 @@ jobs:
     - name: Checkout repository
       uses: actions/checkout@v4
     - name: Install dependencies
-      run: pip install sphinx sphinx-rtd-theme
+      run: pip install . && pip install sphinx sphinx-rtd-theme
     - name: Build documentation
       run: make docs
     - name: Deploy to GitHub Pages

From 42fe56d3ea1a223202aa3de0c445921130543dbd Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Wed, 17 Jul 2024 20:00:23 -0300
Subject: [PATCH 183/248] bitprog reimplemented

---
 pyfpga/helpers/bitprog.py | 107 +++++++++++++++-----------------------
 1 file changed, 42 insertions(+), 65 deletions(-)

diff --git a/pyfpga/helpers/bitprog.py b/pyfpga/helpers/bitprog.py
index 0282f263..6af85884 100644
--- a/pyfpga/helpers/bitprog.py
+++ b/pyfpga/helpers/bitprog.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 #
-# Copyright (C) 2020 PyFPGA Project
+# Copyright (C) 2020-2024 PyFPGA Project
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
@@ -10,34 +10,25 @@
 """
 
 import argparse
-import logging
 import sys
 
-from fpga import __version__ as version
-from fpga.project import Project, TOOLS
-from fpga.tool import MEMWIDTHS
+from pathlib import Path
+from pyfpga import __version__ as version
+from pyfpga.factory import Factory, TOOLS
+from pyfpga.project import STEPS
 
-logging.basicConfig()
-logging.getLogger('fpga.project').level = logging.INFO
+tools = list(TOOLS.keys())
+devs = ['fpga', 'spi', 'bpi']
+positions = range(1, 10)
+widths = [2**i for i in range(6)]
 
-DEVS = ['fpga', 'spi', 'bpi']
-POSITIONS = range(1, 10)
-ACTIONS = ['program', 'detect', 'unlock']
-
-EPILOGUE = """
+EPILOGUE = f"""
 Supported values of arguments with choices:
-* TOOL = {}
-* DEVTYPE = {}
-* POSITIONS = {}
-* MEMWIDTH = {}
-* ACTION = {}
-""".format(
-    " | ".join(TOOLS),
-    " | ".join(DEVS),
-    " | ".join(str(x) for x in POSITIONS),
-    " | ".join(str(x) for x in MEMWIDTHS),
-    " | ".join(ACTIONS)
-)
+* TOOL = {'|'.join(tools)}
+* TYPE = {'|'.join(devs)}
+* POSITION = {'|'.join(map(str, positions))}
+* WIDTH = {'|'.join(map(str, widths))}
+"""
 
 
 def main():
@@ -54,43 +45,36 @@ def main():
     parser.add_argument(
         '-v', '--version',
         action='version',
-        version='v{}'.format(version)
-    )
-
-    parser.add_argument(
-        'bit',
-        metavar='BITFILE',
-        nargs='?',
-        help='a bitstream file'
+        version=f'v{version}'
     )
 
     parser.add_argument(
         '-t', '--tool',
         metavar='TOOL',
         default='vivado',
-        choices=TOOLS,
+        choices=tools,
         help='backend tool to be used [vivado]'
     )
 
     parser.add_argument(
-        '-o', '--outdir',
+        '-o', '--odir',
         metavar='PATH',
-        default='temp',
-        help='where to generate files [temp]'
+        default='results',
+        help='where to generate files [results]'
     )
 
     parser.add_argument(
         '-d', '--device',
-        metavar='DEVTYPE',
-        choices=DEVS,
-        default=DEVS[0],
-        help='the target device type [{}]'.format(DEVS[0])
+        metavar='TYPE',
+        choices=devs,
+        default=devs[0],
+        help=f'the target device type [{devs[0]}]'
     )
 
     parser.add_argument(
         '-p', '--position',
         metavar='POSITION',
-        choices=POSITIONS,
+        choices=positions,
         type=int,
         default=1,
         help='the device position into the JTAG chain [1]'
@@ -98,47 +82,40 @@ def main():
 
     parser.add_argument(
         '-m', '--memname',
-        metavar='MEMNAME',
-        default='',
-        help='memory name if spi or bpi selected'
+        metavar='NAME',
+        help='memory name for SPI or BPI devices [None]'
     )
 
     parser.add_argument(
         '-w', '--width',
-        metavar='MEMWIDTH',
-        choices=MEMWIDTHS,
+        metavar='WIDTH',
+        choices=widths,
         type=int,
         default=1,
-        help='memory width if spi or bpi selected [1]'
+        help='memory width for SPI or BPI devices [1]'
     )
 
     parser.add_argument(
-        '--run',
-        metavar='ACTION',
-        choices=ACTIONS,
-        default=ACTIONS[0],
-        help='action to perform [{}]'.format(ACTIONS[0])
+        'bit',
+        metavar='BITFILE',
+        help='a bitstream file'
     )
 
     args = parser.parse_args()
 
+    # -------------------------------------------------------------------------
     # Solving with PyFPGA
+    # -------------------------------------------------------------------------
 
-    prj = Project(args.tool, relative_to_script=False)
-    prj.set_outdir(args.outdir)
-
-    if args.run == 'program':
-        devtype = args.device
-        prj.set_bitstream(args.bit)
-    elif args.run == 'detect':
-        devtype = 'detect'
-    else:  # args.run == 'unlock'
-        devtype = 'unlock'
+    prj = Factory(args.tool, odir=args.odir)
 
     try:
-        prj.transfer(devtype, args.position, args.memname, args.width)
-    except RuntimeError:
-        logging.error('{} not found'.format(args.tool))
+        if args.device == 'fpga':
+            prj.prog(args.bit, args.position)
+        if args.device == 'spi':
+            prj.prog_spi(args.bit, args.position, args.width, args.memname)
+        if args.device == 'bpi':
+            prj.prog_bpi(args.bit, args.position, args.width, args.memname)
     except Exception as e:
         sys.exit('{} ({})'.format(type(e).__name__, e))
 

From 995eae3b119c3a2af4c87195c571ee78547198f3 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Wed, 17 Jul 2024 20:02:37 -0300
Subject: [PATCH 184/248] docs: add bitprog help

---
 docs/Makefile    | 13 +++----------
 docs/helpers.rst |  5 +++++
 2 files changed, 8 insertions(+), 10 deletions(-)

diff --git a/docs/Makefile b/docs/Makefile
index 48576179..a9325d75 100644
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -1,24 +1,17 @@
-# Minimal makefile for Sphinx documentation
-#
-
-# You can set these variables from the command line, and also
-# from the environment for the first two.
 SPHINXOPTS    ?=
 SPHINXBUILD   ?= sphinx-build
 SOURCEDIR     = .
 BUILDDIR      = _build
+HELPERS       = $(BUILDDIR)/hdl2bit $(BUILDDIR)/prj2bit $(BUILDDIR)/bitprog
 
-# Put it first so that "make" without argument is like "make help".
 help:
 	@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
 
 .PHONY: help Makefile
 
-$(BUILDDIR)/hdl2bit $(BUILDDIR)/prj2bit:
+$(HELPERS):
 	@mkdir -p $(@D)
 	@python3 ../pyfpga/helpers/$(@F).py -h > $@
 
-# Catch-all target: route all unknown targets to Sphinx using the new
-# "make mode" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).
-%: Makefile $(BUILDDIR)/hdl2bit $(BUILDDIR)/prj2bit
+%: Makefile $(HELPERS)
 	@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/docs/helpers.rst b/docs/helpers.rst
index e5623c92..542deb27 100644
--- a/docs/helpers.rst
+++ b/docs/helpers.rst
@@ -10,3 +10,8 @@ prj2bit
 -------
 
 .. literalinclude:: _build/prj2bit
+
+bitprog
+-------
+
+.. literalinclude:: _build/bitprog

From 6220dbdd07cb1181bcccb577dffe88b3a1c47bd7 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 5 Aug 2024 20:51:40 -0300
Subject: [PATCH 185/248] Modified to use TOOLS for choices

---
 tests/projects/support.py | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/tests/projects/support.py b/tests/projects/support.py
index 2e26e3b5..68bc88b1 100644
--- a/tests/projects/support.py
+++ b/tests/projects/support.py
@@ -3,12 +3,13 @@
 import argparse
 import sys
 
-from pyfpga.factory import Factory
+from pyfpga.factory import Factory, TOOLS
+
 
 parser = argparse.ArgumentParser()
 parser.add_argument(
     '--tool', default='openflow',
-    choices=['ise', 'libero', 'quartus', 'openflow', 'vivado']
+    choices=list(TOOLS.keys())
 )
 args = parser.parse_args()
 

From cc89caf82268d7769e6c3a3717cef7f899ded4f3 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 5 Aug 2024 21:59:23 -0300
Subject: [PATCH 186/248] Modify tests to be able of run pytest from project
 root

---
 Makefile            |  2 +-
 tests/test_data.py  | 72 ++++++++++++++++++++++++++++-----------------
 tests/test_tools.py | 18 +++++++-----
 3 files changed, 56 insertions(+), 36 deletions(-)

diff --git a/Makefile b/Makefile
index f9eda4cb..fb528da7 100644
--- a/Makefile
+++ b/Makefile
@@ -11,7 +11,7 @@ lint:
 	git diff --check --cached
 
 test:
-	cd tests; pytest
+	pytest
 
 clean:
 	py3clean .
diff --git a/tests/test_data.py b/tests/test_data.py
index 3ba4e4a9..a8e2af19 100644
--- a/tests/test_data.py
+++ b/tests/test_data.py
@@ -2,41 +2,59 @@
 
 from pyfpga.vivado import Vivado
 
+tdir = Path(__file__).parent.resolve()
+
 pattern = {
     'project': 'EXAMPLE',
     'part': 'PARTNAME',
     'includes': [
-        Path('fakedata/dir1').resolve().as_posix(),
-        Path('fakedata/dir2').resolve().as_posix(),
-        Path('fakedata/dir3').resolve().as_posix()
+        Path(tdir / 'fakedata/dir1').resolve().as_posix(),
+        Path(tdir / 'fakedata/dir2').resolve().as_posix(),
+        Path(tdir / 'fakedata/dir3').resolve().as_posix()
     ],
     'files': {
-        Path('fakedata/vhdl0.vhdl').resolve().as_posix(): {
+        Path(tdir / 'fakedata/vhdl0.vhdl').resolve().as_posix(): {
             'hdl': 'vhdl', 'lib': 'LIB'
         },
-        Path('fakedata/dir1/vhdl1.vhdl').resolve().as_posix(): {
+        Path(tdir / 'fakedata/dir1/vhdl1.vhdl').resolve().as_posix(): {
             'hdl': 'vhdl', 'lib': 'LIB'
         },
-        Path('fakedata/dir2/vhdl2.vhdl').resolve().as_posix(): {
+        Path(tdir / 'fakedata/dir2/vhdl2.vhdl').resolve().as_posix(): {
             'hdl': 'vhdl', 'lib': 'LIB'
         },
-        Path('fakedata/dir3/vhdl3.vhdl').resolve().as_posix(): {
+        Path(tdir / 'fakedata/dir3/vhdl3.vhdl').resolve().as_posix(): {
             'hdl': 'vhdl', 'lib': 'LIB'
         },
-        Path('fakedata/vlog0.v').resolve().as_posix(): {'hdl': 'vlog'},
-        Path('fakedata/dir1/vlog1.v').resolve().as_posix(): {'hdl': 'vlog'},
-        Path('fakedata/dir2/vlog2.v').resolve().as_posix(): {'hdl': 'vlog'},
-        Path('fakedata/dir3/vlog3.v').resolve().as_posix(): {'hdl': 'vlog'},
-        Path('fakedata/slog0.sv').resolve().as_posix(): {'hdl': 'slog'},
-        Path('fakedata/dir1/slog1.sv').resolve().as_posix(): {'hdl': 'slog'},
-        Path('fakedata/dir2/slog2.sv').resolve().as_posix(): {'hdl': 'slog'},
-        Path('fakedata/dir3/slog3.sv').resolve().as_posix(): {'hdl': 'slog'}
+        Path(tdir / 'fakedata/vlog0.v').resolve().as_posix(): {
+            'hdl': 'vlog'
+        },
+        Path(tdir / 'fakedata/dir1/vlog1.v').resolve().as_posix(): {
+            'hdl': 'vlog'
+        },
+        Path(tdir / 'fakedata/dir2/vlog2.v').resolve().as_posix(): {
+            'hdl': 'vlog'
+        },
+        Path(tdir / 'fakedata/dir3/vlog3.v').resolve().as_posix(): {
+            'hdl': 'vlog'
+        },
+        Path(tdir / 'fakedata/slog0.sv').resolve().as_posix(): {
+            'hdl': 'slog'
+        },
+        Path(tdir / 'fakedata/dir1/slog1.sv').resolve().as_posix(): {
+            'hdl': 'slog'
+        },
+        Path(tdir / 'fakedata/dir2/slog2.sv').resolve().as_posix(): {
+            'hdl': 'slog'
+        },
+        Path(tdir / 'fakedata/dir3/slog3.sv').resolve().as_posix(): {
+            'hdl': 'slog'
+        }
     },
     'top': 'TOPNAME',
     'constraints': {
-        Path('fakedata/cons/all.xdc').resolve().as_posix(): 'all',
-        Path('fakedata/cons/syn.xdc').resolve().as_posix(): 'syn',
-        Path('fakedata/cons/par.xdc').resolve().as_posix(): 'par'
+        Path(tdir / 'fakedata/cons/all.xdc').resolve().as_posix(): 'all',
+        Path(tdir / 'fakedata/cons/syn.xdc').resolve().as_posix(): 'syn',
+        Path(tdir / 'fakedata/cons/par.xdc').resolve().as_posix(): 'par'
     },
     'params': {
         'PAR1': 'VAL1',
@@ -65,15 +83,15 @@ def test_data():
     prj = Vivado('EXAMPLE')
     prj.set_part('PARTNAME')
     prj.set_top('TOPNAME')
-    prj.add_include('fakedata/dir1')
-    prj.add_include('fakedata/dir2')
-    prj.add_include('fakedata/dir3')
-    prj.add_slog('fakedata/**/*.sv')
-    prj.add_vhdl('fakedata/**/*.vhdl', 'LIB')
-    prj.add_vlog('fakedata/**/*.v')
-    prj.add_cons('fakedata/cons/all.xdc')
-    prj.add_cons('fakedata/cons/syn.xdc', 'syn')
-    prj.add_cons('fakedata/cons/par.xdc', 'par')
+    prj.add_include(str(tdir / 'fakedata/dir1'))
+    prj.add_include(str(tdir / 'fakedata/dir2'))
+    prj.add_include(str(tdir / 'fakedata/dir3'))
+    prj.add_slog(str(tdir / 'fakedata/**/*.sv'))
+    prj.add_vhdl(str(tdir / 'fakedata/**/*.vhdl'), 'LIB')
+    prj.add_vlog(str(tdir / 'fakedata/**/*.v'))
+    prj.add_cons(str(tdir / 'fakedata/cons/all.xdc'))
+    prj.add_cons(str(tdir / 'fakedata/cons/syn.xdc'), 'syn')
+    prj.add_cons(str(tdir / 'fakedata/cons/par.xdc'), 'par')
     prj.add_param('PAR1', 'VAL1')
     prj.add_param('PAR2', 'VAL2')
     prj.add_param('PAR3', 'VAL3')
diff --git a/tests/test_tools.py b/tests/test_tools.py
index 7c23c4a1..45f972ed 100644
--- a/tests/test_tools.py
+++ b/tests/test_tools.py
@@ -1,6 +1,8 @@
 from pathlib import Path
 from pyfpga.factory import Factory
 
+tdir = Path(__file__).parent.resolve()
+
 
 def test_ise():
     tool = 'ise'
@@ -45,15 +47,15 @@ def generate(tool, part):
     prj = Factory(tool, odir=f'results/{tool}')
     prj.set_part(part)
     prj.set_top('TOPNAME')
-    prj.add_include('fakedata/dir1')
-    prj.add_include('fakedata/dir2')
+    prj.add_include(str(tdir / 'fakedata/dir1'))
+    prj.add_include(str(tdir / 'fakedata/dir2'))
     if tool != 'ise':
-        prj.add_slog('fakedata/**/*.sv')
-    prj.add_vhdl('fakedata/**/*.vhdl', 'LIB')
-    prj.add_vlog('fakedata/**/*.v')
-    prj.add_cons('fakedata/cons/all.xdc')
-    prj.add_cons('fakedata/cons/syn.xdc', 'syn')
-    prj.add_cons('fakedata/cons/par.xdc', 'par')
+        prj.add_slog(str(tdir / 'fakedata/**/*.sv'))
+    prj.add_vhdl(str(tdir / 'fakedata/**/*.vhdl'), 'LIB')
+    prj.add_vlog(str(tdir / 'fakedata/**/*.v'))
+    prj.add_cons(str(tdir / 'fakedata/cons/all.xdc'))
+    prj.add_cons(str(tdir / 'fakedata/cons/syn.xdc'), 'syn')
+    prj.add_cons(str(tdir / 'fakedata/cons/par.xdc'), 'par')
     prj.add_param('PAR1', 'VAL1')
     prj.add_param('PAR2', 'VAL2')
     prj.add_define('DEF1', 'VAL1')

From 6fecb1d17c5d0ee247911625fa86f23b64f65141 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Thu, 8 Aug 2024 22:01:21 -0300
Subject: [PATCH 187/248] docs: added new sections

---
 docs/extending.rst | 2 ++
 docs/index.rst     | 3 ++-
 docs/tools.rst     | 4 ++--
 3 files changed, 6 insertions(+), 3 deletions(-)
 create mode 100644 docs/extending.rst

diff --git a/docs/extending.rst b/docs/extending.rst
new file mode 100644
index 00000000..20d48463
--- /dev/null
+++ b/docs/extending.rst
@@ -0,0 +1,2 @@
+Extending
+=========
diff --git a/docs/index.rst b/docs/index.rst
index ad539fe4..e9241b3e 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -16,7 +16,8 @@ PyFPGA's documentation
    intro
    basic
    advanced
-   api
    helpers
+   api
    tools
    internals
+   extending
diff --git a/docs/tools.rst b/docs/tools.rst
index a7c6dc55..ffd3d97b 100644
--- a/docs/tools.rst
+++ b/docs/tools.rst
@@ -1,5 +1,5 @@
-Tools support
-=============
+Tools
+=====
 
 +---------------+-----------+---------+-----+-----------------------------------------------+
 | Tools         | Vendor    | Version | Tcl | Comment                                       |

From e36413d6c41b9483cbcce375251320c288525699 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Thu, 8 Aug 2024 22:39:46 -0300
Subject: [PATCH 188/248] docs: complete introduction section

---
 docs/basic.rst | 18 +-----------------
 docs/intro.rst | 24 ++++++++++++++++++++++++
 2 files changed, 25 insertions(+), 17 deletions(-)

diff --git a/docs/basic.rst b/docs/basic.rst
index 824aea8d..b178c0fc 100644
--- a/docs/basic.rst
+++ b/docs/basic.rst
@@ -3,7 +3,7 @@ Basic usage
 
 .. ATTENTION::
 
-  (2024-05-31) To be updated.
+  (2024-08-08) To be updated.
 
 Project Creation
 ----------------
@@ -18,22 +18,6 @@ name is used when *no name* is provided).
 
    prj = Project('vivado', 'projectName')
 
-.. NOTE::
-
-  The supported tool are: ``ghdl``, ``ise``, ``libero``, ``openflow``,
-  ``quartus``, ``vivado``, ``yosys``, ``yosys-ise`` and ``yosys-vivado``.
-
-.. ATTENTION::
-
-  PyFPGA assumes that the backend Tool is ready to run.
-  This implies, depending on the operating system, things such as:
-
-  * Tool installed.
-  * A valid License configured.
-  * Tool available in the system PATH.
-  * GNU/Linux: extra packages installed, environment variables assigned
-    and permissions granted on devices (to transfer the bitstream).
-
 By default, the directory where the project is generated is called ``build``
 and is located in the same place that the script, but another name and location
 can be specified.
diff --git a/docs/intro.rst b/docs/intro.rst
index c516b331..abc7e945 100644
--- a/docs/intro.rst
+++ b/docs/intro.rst
@@ -1,2 +1,26 @@
 Introduction
 ============
+
+PyFPGA is a Python package that provides an abstraction layer for working with FPGA development tools in a vendor-agnostic, programmatic way. It includes:
+
+* A **class** for each supported tool, enabling **project creation**, **synthesis**, **place and route**, **bitstream generation**, and **programming**.
+* A set of **command-line** helpers for simple projects or quick evaluations.
+
+With PyFPGA, you can create your own FPGA development workflow tailored to your needs. Some of its key benefits include:
+
+* A unified API across different tools and devices.
+* Compatibility with *Version Control Systems* and *Continuous Integration*.
+* Ensured reproducibility and repeatability.
+* Lower resource consumption compared to GUI-based workflows.
+
+It currently supports vendor tools such as ``Diamond``, ``Ise``, ``Quartus``, ``Libero``, and ``Vivado``, as well as ``Openflow``, a solution based on *Free/Libre and Open Source Software* (**FLOSS**).
+
+.. ATTENTION::
+
+  PyFPGA assumes that the backend tool is ready to run.
+  This implies, depending on the operating system, the following:
+
+  * The tool is installed.
+  * A valid license, if needed, is configured.
+  * The tool is available in the system PATH.
+  * On GNU/Linux: required packages are installed, environment variables are set, and permissions are granted for devices (to transfer the bitstream).

From 908533866584ce4c62fd81afda5b017a11b2df5a Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 11 Aug 2024 17:21:09 -0300
Subject: [PATCH 189/248] Add Vivado hooks examples

---
 examples/hooks/vivado.py | 41 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)
 create mode 100644 examples/hooks/vivado.py

diff --git a/examples/hooks/vivado.py b/examples/hooks/vivado.py
new file mode 100644
index 00000000..8621ae11
--- /dev/null
+++ b/examples/hooks/vivado.py
@@ -0,0 +1,41 @@
+"""Vivado hooks examples."""
+
+from pathlib import Path
+from pyfpga.vivado import Vivado
+
+
+prj = Vivado()
+
+prj.set_part('xc7z010-1-clg400')
+
+prj.add_param('FREQ', '125000000')
+prj.add_param('SECS', '1')
+prj.add_define('DEFINE1', '1')
+prj.add_define('DEFINE2', '1')
+
+prj.add_include('../sources/slog/include1')
+prj.add_include('../sources/slog/include2')
+prj.add_slog('../sources/slog/*.sv')
+
+prj.add_cons('../sources/cons/ZYBO/timing.xdc')
+prj.add_cons('../sources/cons/ZYBO/clk.xdc')
+prj.add_cons('../sources/cons/ZYBO/led.xdc')
+
+prj.set_top('Top')
+
+prj.add_hook('precfg', '''
+set obj [get_runs synth_1]
+set_property strategy "Flow_AreaOptimized_high" $obj
+set_property "steps.synth_design.args.directive" "AreaOptimized_high" $obj
+set_property "steps.synth_design.args.control_set_opt_threshold" "1" $obj
+set obj [get_runs impl_1]
+set_property strategy "Area_Explore" $obj
+set_property "steps.opt_design.args.directive" "ExploreArea" $obj
+''')
+
+prj.add_hook('postcfg', f'''
+set_property USED_IN_SYNTHESIS FALSE [get_files {Path('../sources/cons/ZYBO/clk.xdc').resolve()}]
+set_property USED_IN_SYNTHESIS FALSE [get_files {Path('../sources/cons/ZYBO/led.xdc').resolve()}]
+''')
+
+prj.make()

From e1c6ebf875c74282b95a76c9ed6bd2f96dd4589c Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 11 Aug 2024 17:41:52 -0300
Subject: [PATCH 190/248] Remove the 'when' parameter from 'add_cons'
 (Vivado-specific)

---
 docs/internals.rst            | 12 ++++++------
 examples/hooks/vivado.py      |  5 +++--
 examples/projects/ise.py      | 12 ++++++------
 examples/projects/libero.py   |  6 +++---
 examples/projects/openflow.py | 16 ++++++++--------
 examples/projects/quartus.py  |  6 +++---
 examples/projects/vivado.py   | 12 ++++++------
 pyfpga/project.py             |  9 +++------
 pyfpga/templates/vivado.jinja |  5 -----
 tests/test_data.py            | 10 +++++-----
 tests/test_tools.py           |  4 ++--
 11 files changed, 45 insertions(+), 52 deletions(-)

diff --git a/docs/internals.rst b/docs/internals.rst
index fd388ae4..4da687d2 100644
--- a/docs/internals.rst
+++ b/docs/internals.rst
@@ -39,15 +39,15 @@ Internal data structure
         'part': 'PARTNAME',
         'includes': ['DIR1', 'DIR2', 'DIR3'],
         'files': {
-            'FILE1': {'hdl': 'vhdl', 'lib': 'LIB1'}
-            'FILE2': {'hdl': 'vlog'},
-            'FILE3': {'hdl': 'slog'}
+            'FILE1': {'hdl': 'vhdl', 'lib': 'LIB1', 'opt': 'OPTS'},
+            'FILE2': {'hdl': 'vlog', 'opt': 'OPTS'},
+            'FILE3': {'hdl': 'slog', 'opt': 'OPTS'}
         },
         'top': 'TOPNAME',
         'constraints': {
-            'FILE1': 'all',
-            'FILE2': 'syn',
-            'FILE3': 'par'
+            'FILE1': {'opt': 'OPTS'},
+            'FILE2': {'opt': 'OPTS'},
+            'FILE3': {'opt': 'OPTS'}
         },
         'params': {
             'PAR1': 'VAL1',
diff --git a/examples/hooks/vivado.py b/examples/hooks/vivado.py
index 8621ae11..9d239247 100644
--- a/examples/hooks/vivado.py
+++ b/examples/hooks/vivado.py
@@ -33,9 +33,10 @@
 set_property "steps.opt_design.args.directive" "ExploreArea" $obj
 ''')
 
+place = ['../sources/cons/ZYBO/clk.xdc', '../sources/cons/ZYBO/led.xdc']
 prj.add_hook('postcfg', f'''
-set_property USED_IN_SYNTHESIS FALSE [get_files {Path('../sources/cons/ZYBO/clk.xdc').resolve()}]
-set_property USED_IN_SYNTHESIS FALSE [get_files {Path('../sources/cons/ZYBO/led.xdc').resolve()}]
+set_property USED_IN_SYNTHESIS FALSE [get_files {Path(place[0]).resolve()}]
+set_property USED_IN_SYNTHESIS FALSE [get_files {Path(place[1]).resolve()}]
 ''')
 
 prj.make()
diff --git a/examples/projects/ise.py b/examples/projects/ise.py
index a1b9dba0..a81082a2 100644
--- a/examples/projects/ise.py
+++ b/examples/projects/ise.py
@@ -22,15 +22,15 @@
 if args.board == 's6micro':
     prj.set_part('xc6slx9-2-csg324')
     prj.add_param('FREQ', '125000000')
-    prj.add_cons('../sources/cons/s6micro/clk.xcf', 'syn')
-    prj.add_cons('../sources/cons/s6micro/clk.ucf', 'par')
-    prj.add_cons('../sources/cons/s6micro/led.ucf', 'par')
+    prj.add_cons('../sources/cons/s6micro/clk.xcf')
+    prj.add_cons('../sources/cons/s6micro/clk.ucf')
+    prj.add_cons('../sources/cons/s6micro/led.ucf')
 if args.board == 'nexys3':
     prj.set_part('xc6slx16-3-csg32')
     prj.add_param('FREQ', '100000000')
-    prj.add_cons('../sources/cons/nexys3/clk.xcf', 'syn')
-    prj.add_cons('../sources/cons/nexys3/clk.ucf', 'par')
-    prj.add_cons('../sources/cons/nexys3/led.ucf', 'par')
+    prj.add_cons('../sources/cons/nexys3/clk.xcf')
+    prj.add_cons('../sources/cons/nexys3/clk.ucf')
+    prj.add_cons('../sources/cons/nexys3/led.ucf')
 prj.add_param('SECS', '1')
 
 if args.source == 'vhdl':
diff --git a/examples/projects/libero.py b/examples/projects/libero.py
index 4f4360d7..e9e2697c 100644
--- a/examples/projects/libero.py
+++ b/examples/projects/libero.py
@@ -21,9 +21,9 @@
 if args.board == 'maker':
     prj.set_part('m2s010-1-tq144')
     prj.add_param('FREQ', '125000000')
-    prj.add_cons('../sources/cons/maker/clk.sdc', 'syn')
-    prj.add_cons('../sources/cons/maker/clk.pdc', 'par')
-    prj.add_cons('../sources/cons/maker/led.pdc', 'par')
+    prj.add_cons('../sources/cons/maker/clk.sdc')
+    prj.add_cons('../sources/cons/maker/clk.pdc')
+    prj.add_cons('../sources/cons/maker/led.pdc')
 prj.add_param('SECS', '1')
 
 if args.source == 'vhdl':
diff --git a/examples/projects/openflow.py b/examples/projects/openflow.py
index b40f6c96..0b1242b3 100644
--- a/examples/projects/openflow.py
+++ b/examples/projects/openflow.py
@@ -23,23 +23,23 @@
 if args.board == 'icestick':
     prj.set_part('hx1k-tq144')
     prj.add_param('FREQ', '100000000')
-    prj.add_cons('../sources/cons/icestick/clk.pcf', 'par')
-    prj.add_cons('../sources/cons/icestick/led.pcf', 'par')
+    prj.add_cons('../sources/cons/icestick/clk.pcf')
+    prj.add_cons('../sources/cons/icestick/led.pcf')
 if args.board == 'edu-ciaa':
     prj.set_part('hx1k-tq144')
     prj.add_param('FREQ', '100000000')
-    prj.add_cons('../sources/cons/edu-ciaa/clk.pcf', 'par')
-    prj.add_cons('../sources/cons/edu-ciaa/led.pcf', 'par')
+    prj.add_cons('../sources/cons/edu-ciaa/clk.pcf')
+    prj.add_cons('../sources/cons/edu-ciaa/led.pcf')
 if args.board == 'orangecrab':
     prj.set_part('25k-CSFBGA285')
     prj.add_param('FREQ', '100000000')
-    prj.add_cons('../sources/cons/orangecrab/clk.lpf', 'par')
-    prj.add_cons('../sources/cons/orangecrab/led.lpf', 'par')
+    prj.add_cons('../sources/cons/orangecrab/clk.lpf')
+    prj.add_cons('../sources/cons/orangecrab/led.lpf')
 if args.board == 'ecp5evn':
     prj.set_part('um5g-85k-CABGA381')
     prj.add_param('FREQ', '100000000')
-    prj.add_cons('../sources/cons/ecp5evn/clk.lpf', 'par')
-    prj.add_cons('../sources/cons/ecp5evn/led.lpf', 'par')
+    prj.add_cons('../sources/cons/ecp5evn/clk.lpf')
+    prj.add_cons('../sources/cons/ecp5evn/led.lpf')
 prj.add_param('SECS', '1')
 
 if args.source == 'vhdl':
diff --git a/examples/projects/quartus.py b/examples/projects/quartus.py
index 07cfedc4..cccbb372 100644
--- a/examples/projects/quartus.py
+++ b/examples/projects/quartus.py
@@ -22,9 +22,9 @@
 if args.board == 'de10nano':
     prj.set_part('5CSEBA6U23I7')
     prj.add_param('FREQ', '125000000')
-    prj.add_cons('../sources/cons/de10nano/clk.sdc', 'syn')
-    prj.add_cons('../sources/cons/de10nano/clk.tcl', 'par')
-    prj.add_cons('../sources/cons/de10nano/led.tcl', 'par')
+    prj.add_cons('../sources/cons/de10nano/clk.sdc')
+    prj.add_cons('../sources/cons/de10nano/clk.tcl')
+    prj.add_cons('../sources/cons/de10nano/led.tcl')
 prj.add_param('SECS', '1')
 
 if args.source == 'vhdl':
diff --git a/examples/projects/vivado.py b/examples/projects/vivado.py
index 367f2861..35ccecc7 100644
--- a/examples/projects/vivado.py
+++ b/examples/projects/vivado.py
@@ -22,15 +22,15 @@
 if args.board == 'zybo':
     prj.set_part('xc7z010-1-clg400')
     prj.add_param('FREQ', '125000000')
-    prj.add_cons('../sources/cons/ZYBO/timing.xdc', 'syn')
-    prj.add_cons('../sources/cons/ZYBO/clk.xdc', 'par')
-    prj.add_cons('../sources/cons/ZYBO/led.xdc', 'par')
+    prj.add_cons('../sources/cons/ZYBO/timing.xdc')
+    prj.add_cons('../sources/cons/ZYBO/clk.xdc')
+    prj.add_cons('../sources/cons/ZYBO/led.xdc')
 if args.board == 'arty':
     prj.set_part('xc7a35ticsg324-1L')
     prj.add_param('FREQ', '100000000')
-    prj.add_cons('../sources/cons/arty_a7_35t/timing.xdc', 'syn')
-    prj.add_cons('../sources/cons/arty_a7_35t/clk.xdc', 'par')
-    prj.add_cons('../sources/cons/arty_a7_35t/led.xdc', 'par')
+    prj.add_cons('../sources/cons/arty_a7_35t/timing.xdc')
+    prj.add_cons('../sources/cons/arty_a7_35t/clk.xdc')
+    prj.add_cons('../sources/cons/arty_a7_35t/led.xdc')
 prj.add_param('SECS', '1')
 
 if args.source == 'vhdl':
diff --git a/pyfpga/project.py b/pyfpga/project.py
index 72e7edc0..e6ba24fe 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -123,22 +123,19 @@ def add_vlog(self, pathname):
         self.logger.debug('Executing add_vlog')
         self._add_file(pathname, 'vlog')
 
-    def add_cons(self, path, when='all'):
+    def add_cons(self, path):
         """Add a constraint file.
 
         :param pathname: path of a file
         :type pathname: str
-        :param when: always ('all'), synthesis ('syn') or P&R ('par')
-        :type only: str, optional
         :raises FileNotFoundError: if path is not found
         """
         self.logger.debug('Executing add_cons')
         path = Path(path).resolve()
         if not path.is_file():
             raise FileNotFoundError(path)
-        if when not in ['all', 'syn', 'par']:
-            raise ValueError('Invalid only.')
-        self.data.setdefault('constraints', {})[path.as_posix()] = when
+        attr = {}
+        self.data.setdefault('constraints', {})[path.as_posix()] = attr
 
     def add_param(self, name, value):
         """Add a Parameter/Generic Value.
diff --git a/pyfpga/templates/vivado.jinja b/pyfpga/templates/vivado.jinja
index babbf3b6..e214cfb4 100644
--- a/pyfpga/templates/vivado.jinja
+++ b/pyfpga/templates/vivado.jinja
@@ -25,11 +25,6 @@ add_file {{ name }}
 {% if constraints %}# Constraints inclusion
 {% for name, attr in constraints.items() %}
 add_file -fileset constrs_1 {{ name }}
-{% if attr == "syn" %}
-set_property USED_IN_IMPLEMENTATION FALSE [get_files {{ name }}]
-{% elif attr == "par" %}
-set_property USED_IN_SYNTHESIS FALSE [get_files {{ name }}]
-{% endif %}
 {% if loop.first %}set_property TARGET_CONSTRS_FILE {{ name }} [current_fileset -constrset]{% endif %}
 {% endfor %}
 {% endif %}
diff --git a/tests/test_data.py b/tests/test_data.py
index a8e2af19..49b0645b 100644
--- a/tests/test_data.py
+++ b/tests/test_data.py
@@ -52,9 +52,9 @@
     },
     'top': 'TOPNAME',
     'constraints': {
-        Path(tdir / 'fakedata/cons/all.xdc').resolve().as_posix(): 'all',
-        Path(tdir / 'fakedata/cons/syn.xdc').resolve().as_posix(): 'syn',
-        Path(tdir / 'fakedata/cons/par.xdc').resolve().as_posix(): 'par'
+        Path(tdir / 'fakedata/cons/all.xdc').resolve().as_posix(): {},
+        Path(tdir / 'fakedata/cons/syn.xdc').resolve().as_posix(): {},
+        Path(tdir / 'fakedata/cons/par.xdc').resolve().as_posix(): {}
     },
     'params': {
         'PAR1': 'VAL1',
@@ -90,8 +90,8 @@ def test_data():
     prj.add_vhdl(str(tdir / 'fakedata/**/*.vhdl'), 'LIB')
     prj.add_vlog(str(tdir / 'fakedata/**/*.v'))
     prj.add_cons(str(tdir / 'fakedata/cons/all.xdc'))
-    prj.add_cons(str(tdir / 'fakedata/cons/syn.xdc'), 'syn')
-    prj.add_cons(str(tdir / 'fakedata/cons/par.xdc'), 'par')
+    prj.add_cons(str(tdir / 'fakedata/cons/syn.xdc'))
+    prj.add_cons(str(tdir / 'fakedata/cons/par.xdc'))
     prj.add_param('PAR1', 'VAL1')
     prj.add_param('PAR2', 'VAL2')
     prj.add_param('PAR3', 'VAL3')
diff --git a/tests/test_tools.py b/tests/test_tools.py
index 45f972ed..a2950019 100644
--- a/tests/test_tools.py
+++ b/tests/test_tools.py
@@ -54,8 +54,8 @@ def generate(tool, part):
     prj.add_vhdl(str(tdir / 'fakedata/**/*.vhdl'), 'LIB')
     prj.add_vlog(str(tdir / 'fakedata/**/*.v'))
     prj.add_cons(str(tdir / 'fakedata/cons/all.xdc'))
-    prj.add_cons(str(tdir / 'fakedata/cons/syn.xdc'), 'syn')
-    prj.add_cons(str(tdir / 'fakedata/cons/par.xdc'), 'par')
+    prj.add_cons(str(tdir / 'fakedata/cons/syn.xdc'))
+    prj.add_cons(str(tdir / 'fakedata/cons/par.xdc'))
     prj.add_param('PAR1', 'VAL1')
     prj.add_param('PAR2', 'VAL2')
     prj.add_define('DEF1', 'VAL1')

From e0943bdb50d426a4e2db1b4ded2ebcb93c8836e3 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 11 Aug 2024 18:37:19 -0300
Subject: [PATCH 191/248] Add a Vivado Elaboration example (using hooks)

Closes #39
---
 examples/hooks/vivado-elab.py | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)
 create mode 100644 examples/hooks/vivado-elab.py

diff --git a/examples/hooks/vivado-elab.py b/examples/hooks/vivado-elab.py
new file mode 100644
index 00000000..f21c550f
--- /dev/null
+++ b/examples/hooks/vivado-elab.py
@@ -0,0 +1,23 @@
+"""Vivado elaboration example."""
+
+from pyfpga.vivado import Vivado
+
+
+prj = Vivado()
+
+prj.set_part('xc7z010-1-clg400')
+
+prj.add_param('FREQ', '125000000')
+prj.add_param('SECS', '1')
+prj.add_define('DEFINE1', '1')
+prj.add_define('DEFINE2', '1')
+
+prj.add_include('../sources/slog/include1')
+prj.add_include('../sources/slog/include2')
+prj.add_slog('../sources/slog/*.sv')
+
+prj.set_top('Top')
+
+prj.add_hook('presyn', 'synth_design -rtl -rtl_skip_mlo; exit 0')
+
+prj.make()

From 83d1e59e413600cbd13f37e74e5c18eeec49d811 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 11 Aug 2024 22:09:21 -0300
Subject: [PATCH 192/248] Adds set_debug()

---
 pyfpga/project.py | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/pyfpga/project.py b/pyfpga/project.py
index e6ba24fe..86d9f267 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -200,6 +200,10 @@ def add_hook(self, stage, hook):
             raise ValueError('Invalid stage.')
         self.data.setdefault('hooks', {}).setdefault(stage, []).append(hook)
 
+    def set_debug(self):
+        """Enables debug messages."""
+        self.logger.setLevel(logging.DEBUG)
+
     def make(self, first='cfg', last='bit'):
         """Run the underlying tool.
 

From 0103506a38d2d50ff4b95c89d3c96aec597670a5 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 11 Aug 2024 22:10:01 -0300
Subject: [PATCH 193/248] docs: rewritten basic usage

---
 docs/basic.rst | 163 ++++++++++++++++++++++---------------------------
 docs/index.rst |   5 --
 2 files changed, 74 insertions(+), 94 deletions(-)

diff --git a/docs/basic.rst b/docs/basic.rst
index b178c0fc..5efcfccd 100644
--- a/docs/basic.rst
+++ b/docs/basic.rst
@@ -1,148 +1,133 @@
 Basic usage
 ===========
 
-.. ATTENTION::
+Project Configuration
+---------------------
 
-  (2024-08-08) To be updated.
+The first steps involve importing the necessary module to support the desired tool and instantiating the corresponding *class*:
 
-Project Creation
-----------------
+.. code-block:: python
+
+   from pyfpga.vivado import Vivado
+
+   prj = Vivado('PRJNAME', odir='OUTDIR')
 
-The first steps are import the module and instantiate the ``Project`` *class*,
-specifying the *TOOL* to use and, optionally, a *PROJECT NAME* (the *tool*
-name is used when *no name* is provided).
+In the example, we are using Vivado, specifying the optional parameter *project name* (*tool name* if omitted) and *output directory* (*results* by default).
+
+Next step is to specify the target FPGA device:
 
 .. code-block:: python
 
-   from fpga.project import Project
+   prj.set_part('xc7k160t-3-fbg484')
+
+.. note::
 
-   prj = Project('vivado', 'projectName')
+  Default parts are provided for each supported tool.
 
-By default, the directory where the project is generated is called ``build``
-and is located in the same place that the script, but another name and location
-can be specified.
+HDL source files are added using one of the following methods:
 
 .. code-block:: python
 
-   prj.set_outdir('../temp')
+   prj.add_vhdl('PATH_TO_FILES_GLOB_COMPATIBLE', 'OPTIONAL_LIBNAME')
+   prj.add_vlog('PATH_TO_FILES_GLOB_COMPATIBLE')
+   prj.add_slog('PATH_TO_FILES_GLOB_COMPATIBLE')
 
-Next, the FPGA part would be specified:
+In these methods, you provide a path to the files. The path can include wildcards (like `*.vhdl`), allowing you to match multiple files at once.
 
-.. code-block:: python
+For `add_vhdl`, you can also optionally specify a library name where the files will be included.
 
-   prj.set_part('xc7k160t-3-fbg484')
+.. note::
+
+   Internally, the methods that specify files use `glob`_ to support wildcards and `Path`_ to obtain absolute paths.
 
-.. NOTE::
+  .. _glob: https://docs.python.org/3/library/glob.html
+  .. _Path: https://docs.python.org/3/library/pathlib.html
 
-  You can use the default FPGA part for a quick test or make a lazy comparison
-  between tools, but generally, you will want to specify a particular one.
-  Examples about how to specify a part according the tool, are (default values
-  when ``set_part`` is not employed):
+Generics/parameters can be specified with:
+
+.. code-block:: python
 
-    * **Ise:** ``xc7k160t-3-fbg484`` (*device-speed-package*)
-    * **Libero:** ``mpf100t-1-fcg484`` (*device-speed-package*)
-    * **Openflow:** ``hx8k-ct256`` (*device-package*)
-    * **Quartus:** ``10cl120zf780i8g`` (*part*)
-    * **Vivado:** ``xc7k160t-3-fbg484`` (*part*)
+   prj.add_param('PARAMNAME', 'PARAMVALUE')
 
-The files addition method allows specifying one or more HDL or constraint files
-(also block designs in case of Vivado).
-It uses ``glob`` internally, which makes available the use of wildcards.
-The path to their location must be relative to the Python script, and there
-are optional parameters to indicate the file type (``vhdl``, ``verilog``,
-``constraint`` or ``design``), which is automatically detected based on the
-file extension, and if it is a member of a VHDL package.
+For Verilog and SystemVerilog, the following methods are also available:
 
 .. code-block:: python
 
-   prj.add_files('hdl/blinking.vhdl', library='examples')
-   prj.add_files('hdl/examples_pkg.vhdl', library='examples')
-   prj.add_files('hdl/top.vhdl')
+   prj.add_include('PATH_TO_A_DIRECTORY')
+   prj.add_define('DEFNAME', 'DEFVALUE')
 
-.. NOTE::
+Constraint source files are included using the following:
 
-  * In some cases, the files order could be a problem, so take into account to
-    change the order if needed.
-  * If a file seems unsupported, you can always use the ``prefile`` or
-    ``project`` :ref:`hooks`.
-  * In case of Verilog, ``add_vlog_include`` can be used to specify where to
-    search for included files.
+.. code-block:: python
+
+   prj.add_cons('PATH_TO_FILES_GLOB_COMPATIBLE')
 
-Finally, the top-level must be specified:
+Finally, the top-level can be specified as follows:
 
 .. code-block:: python
 
    prj.set_top('Top')
 
-.. NOTE::
+.. note::
 
-  A relative path to a valid VHDL/Verilog file is also accepted by ``set_top``,
-  to automatically extract the top-level name.
+   The order of the methods described in this section is not significant.
+   They will be arranged in the required order by the underlying template.
 
-Project generation
-------------------
+Bitstream generation
+--------------------
 
-Next step if to generate the project. In the most basic form, you can run the
-following to get a bitstream:
+After configuring the project, you can run the following to generate a bitstream:
 
 .. code-block:: python
 
-   prj.generate()
+   prj.make()
 
-Additionally, you can specify which task to perform:
+By default, this method performs *project creation*, *synthesis*, *place and route*, and *bitstream generation*.
+However, you can optionally specify both the initial and final stages, as follows:
 
 .. code-block:: python
 
-   prj.generate('syn')
-
-.. NOTE::
-
-  The valid values are:
+   prj.make(first='syn', last='par')
 
-  * ``prj``: to generate only a project file (only supported for privative tools)
-  * ``syn``: to performs synthesis.
-  * ``imp``: to performs synthesis and implementation (place and route,
-    optimizations and static timming analysis when available).
-  * ``bit``: (default) to perform synthesis, implementation and bitstream generation.
+.. note::
 
-Bitstream transfer
-------------------
+   Valid values are:
 
-This method is in charge of run the needed tool to transfer a bitstream to a
-device (commonly an FPGA, but memories are also supported in some cases).
-It has up to four main optional parameters:
+   * ``cfg``: generates the project file
+   * ``syn``: performs synthesis
+   * ``par``: performs place and route
+   * ``bit``: performs bitstream generation
 
-.. code-block:: python
+.. note::
 
-   prj.transfer(devtype, position, part, width)
+   After executing this method, you will find the file `<TOOL>.tcl` (or `sh` in some cases) in the output directory.
+   For debugging purposes, if things do not work as expected, you can review this file.
 
-Where *devtype* is ``fpga`` by default but can also be ``spi``, ``bpi``, etc, if
-supported. An integer number can be used to specify the *position* (1) in the
-Jtag chain. When a memory is used as *devtype*, the *part* name and the
-*width* in bits must be also specified.
+Bitstream programming
+---------------------
 
-.. NOTE::
+The final step is programming the FPGA:
 
-  * In Xilinx, `spi` and `bpi` memories are out of the Jtag chain and are
-    programmed through the FPGA. You must specify the FPGA *position*.
-  * In a Linux systems, you need to have permission over the device
-    (udev rule, be a part of a group, etc).
+.. code-block:: python
 
-Logging capabilities
---------------------
+   prj.prog('BITSTREAM', 'POSITION')
 
-PyFPGA uses the `logging <https://docs.python.org/3/library/logging.html>`_
-module, with a *NULL* handler and the *INFO* level by default.
-Messages can be enabled with:
+Both `BITSTREAM` and `POSITION` are optional.
+If `BITSTREAM` is not specified, PyFPGA will attempt to discover it based on project information.
+The `POSITION` parameter is not always required (depends on the tool being used).
 
-.. code-block:: python
+.. note::
 
-   import logging
+   After executing this method, you will find the file `<TOOL>prog.tcl` (or `sh` in some cases) in the output directory.
+   For debugging purposes, if things do not work as expected, you can review this file.
 
-   logging.basicConfig()
+Debugging
+---------
 
-You can enable *DEBUG* messages adding:
+Under the hood, `logging`_ is employed. To enable debug messages, you can use:
 
 .. code-block:: python
 
-   logging.getLogger('fpga.project').level = logging.DEBUG
+   prj.set_debug()
+
+.. _logging: https://docs.python.org/3/library/logging.html
diff --git a/docs/index.rst b/docs/index.rst
index e9241b3e..3e8dfcb0 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -6,11 +6,6 @@ PyFPGA's documentation
    :align: center
    :target: https://github.com/PyFPGA/pyfpga
 
-.. ATTENTION::
-
-  (2024-05-31) PyFPGA is in the process of being strongly rewritten/simplified.
-  Most changes are internal, but the API will also change.
-
 .. toctree::
 
    intro

From e552a69fa8aba9a736dc7ae2b7717cd9f1b8c772 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 11 Aug 2024 23:29:57 -0300
Subject: [PATCH 194/248] docs: rewritten (WIP) advanced usage

---
 docs/advanced.rst | 184 +++++++++++-----------------------------------
 1 file changed, 42 insertions(+), 142 deletions(-)

diff --git a/docs/advanced.rst b/docs/advanced.rst
index 245f4c08..44762476 100644
--- a/docs/advanced.rst
+++ b/docs/advanced.rst
@@ -1,161 +1,61 @@
 Advanced usage
 ==============
 
-.. ATTENTION::
-
-  (2024-05-31) To be updated.
-
-Multi project managment
------------------------
-
-.. code-block:: python
+PyFPGA offers advanced features for more customized and flexible control over FPGA project management.
+This section covers two key advanced features:
 
-   PROJECTS = {
-       '<NAME1>': Project(
-           '<TOOLNAME>',
-           '<PROJECTNAME>',
-           {
-               'outdir': '<DIRNAME>',
-               'part': '<PARTNAME>'
-               'paths': [
-                   '<PATHNAME1>',
-                   ...
-                   '<PATHNAMEn>'
-               ],
-               'vhdl': [
-                   ['<FILENAME1>', '<LIBRARYNAME1>'],
-                   '<FILENAME2>',
-                   ...
-                   '<FILENAMEn>'
-               ],
-               'verilog': [
-                   '<FILENAME1>',
-                   ...
-                   '<FILENAMEn>'
-               ],
-               'constraint': [
-                   '<FILENAME1>',
-                   ...
-                   '<FILENAMEn>'
-               ],
-               'params': {
-                   '<PARAMNAME1>': '<VALUE1>',
-                   ...
-                   '<PARAMNAMEn>': '<VALUEn>'
-               },
-               'top': '<TOPNAME>'
-           }
-       )
-       '<NAME2>': Project(
-           ...
-       )
-   }
+1. **Hooks**: These are points in the code where you can insert custom code to extend or modify the behavior of the tool.
+Hooks provide a way to integrate additional functionality or perform specific actions at predefined stages of the project lifecycle.
 
-.. _hooks:
+2. **Options**: This feature allows you to specify additional options to fine-tune the tool's behavior.
+Options provide greater control over the tool's operation and enable you to customize the processing according to your specific requirements.
 
 Hooks
 -----
 
-The following table depicts the parts of the *Project Creation* and the
-*Design Flow* internally performed by PyFPGA.
-
-+--------------------------+----------------------+
-| Project Creation         | Design Flow          |
-+==========================+======================+
-| Part specification       | **preflow** hook     |
-+--------------------------+----------------------+
-| **prefile** hook         | Synthesis            |
-+--------------------------+----------------------+
-| Files addition           | **postsyn** hook     |
-+--------------------------+----------------------+
-| Top specification        | Place and Route      |
-+--------------------------+----------------------+
-| Parameters specification | **postpar** hook     |
-+--------------------------+----------------------+
-| **project** hook         | Bitstream generation |
-+--------------------------+----------------------+
-|                          | **postbit** hook     |
-+--------------------------+----------------------+
-
-If the provided API if not enough or suitable for your project, you can
-specify additional *hooks* in different parts of the flow, using:
-
-.. code-block:: python
-
-   prj.add_hook(hook, phase)
-
-.. NOTE::
-
-  * Valid vaues for *phase* are ``prefile``, ``project`` (default), ``preflow``,
-    ``postsyn``, ``postpar`` and ``postbit``.
-  * The *hook* string must be a valid command (supported by the used tool).
-  * If more than one *hook* is needed in the same *phase*, you can call this
-    method several times (the commands will be executed in order).
-
-Parameters
-----------
-
-The generics/parameters of the project can be optionally changed with:
-
-.. code-block:: python
-
-   prj.add_param('param1', value1)
-   ...
-   prj.add_param('paramN', valueN)
-
-Generate options
-----------------
-
-The method ``generate`` (previously seen at the end of
-[Basic usage](#basic-usage) section) has optional parameters:
+Hooks allow you to insert custom code at specific stages of the project lifecycle. The available hooks are:
+
++---------+---------------------------------------------------------------------------------------------+
+| Stage   | Description                                                                                 |
++=========+=============================================================================================+
+| precfg  | Code inserted after project creation and before files inclusion (e.g., specify HDL version) |
++---------+---------------------------------------------------------------------------------------------+
+| postcfg | Code inserted after files inclusion (e.g., additional project configurations)               |
++---------+---------------------------------------------------------------------------------------------+
+| presyn  | Code inserted before synthesis (e.g., synthesis-specific options)                           |
++---------+---------------------------------------------------------------------------------------------+
+| postsyn | Code inserted after synthesis (e.g., report generation)                                     |
++---------+---------------------------------------------------------------------------------------------+
+| prepar  | Code inserted before place and route (e.g., place-and-route-specific options)               |
++---------+---------------------------------------------------------------------------------------------+
+| postpar | Code inserted after place and route (e.g., report generation)                               |
++---------+---------------------------------------------------------------------------------------------+
+| prebit  | Code inserted before bitstream generation (e.g., bitstream-specific options)                |
++---------+---------------------------------------------------------------------------------------------+
+| postbit | Code inserted after bitstream generation (e.g., report generation)                          |
++---------+---------------------------------------------------------------------------------------------+
+
+You can specify hooks for a specific stage either line-by-line:
 
 .. code-block:: python
 
-   prj.generate(to_task, from_task, capture)
+   prj.add_hook('presyn', 'COMMAND1')
+   prj.add_hook('presyn', 'COMMAND2')
+   prj.add_hook('presyn', 'COMMAND3')
 
-With *to_task* and *from_taks* (with default values ``bit`` and ``prj``),
-you are selecting the first and last task to execute when `generate` is
-invoqued. The order and available tasks are ``prj``, ``syn``, ``par`` and ``bit``.
-It can be useful in at least two cases:
-
-* Maybe you created a file project with the GUI of the Tool and only want to
-  run the Design Flow, so you can use: ``generate(to_task='bit', from_task='syn')``
-
-* Despite that a method to insert particular commands is provided, you would
-  want to perform some processing from Python between tasks, using something
-  like:
+Or in a multi-line format:
 
 .. code-block:: python
 
-   prj.generate(to_task='syn', from_task='prj')
-   #Some other Python commands here
-   prj.generate(to_task='bit', from_task='syn')
+   prj.add_hook('presyn', """
+   COMMAND1
+   COMMAND2
+   COMMAND3
+   """)
 
-In case of *capture*, it is useful to catch execution messages to be
-post-processed or saved to a file:
-
-.. code-block:: python
+Options
+-------
 
-   result = prj.generate(capture=True)
-   print(result)
-
-In case of *capture*, it is useful to catch execution messages to be
-post-processed or saved to a file.
-
-Exceptions
-----------
-
-Finally, you must run the bitstream generation or its transfer. Both of them
-are time-consuming tasks, performed by a backend tool, which could fail.
-Exceptions are raised in such cases, that should be ideally caught to avoid
-abnormal program termination.
-
-.. code-block:: python
-
-   try:
-       prj.generate()
-       prj.transfer()
-   except Exception as e:
-       print('{} ({})'.format(type(e).__name__, e))
+.. ATTENTION::
 
-And wait for the backend Tool to accomplish its task.
+   WIP feature.

From fe6937afec60b92dc27c224ac0f8f1450b43831f Mon Sep 17 00:00:00 2001
From: Markus Koch <markus@notsyncing.net>
Date: Thu, 1 Aug 2024 07:53:32 +0200
Subject: [PATCH 195/248] Implement support for Lattice Diamond

---
 README.md                             |   1 +
 examples/hooks/diamond.py             |  52 +++++++++++++
 examples/projects/diamond.py          |  51 +++++++++++++
 examples/sources/cons/brevia2/clk.lpf |   3 +
 examples/sources/cons/brevia2/io.lpf  |   4 +
 pyfpga/diamond.py                     |  30 ++++++++
 pyfpga/factory.py                     |   2 +
 pyfpga/templates/diamond-prog.jinja   |  19 +++++
 pyfpga/templates/diamond.jinja        | 105 ++++++++++++++++++++++++++
 tests/mocks/diamondc                  |  38 ++++++++++
 tests/test_tools.py                   |   7 ++
 11 files changed, 312 insertions(+)
 create mode 100644 examples/hooks/diamond.py
 create mode 100644 examples/projects/diamond.py
 create mode 100644 examples/sources/cons/brevia2/clk.lpf
 create mode 100644 examples/sources/cons/brevia2/io.lpf
 create mode 100644 pyfpga/diamond.py
 create mode 100644 pyfpga/templates/diamond-prog.jinja
 create mode 100644 pyfpga/templates/diamond.jinja
 create mode 100755 tests/mocks/diamondc

diff --git a/README.md b/README.md
index c3e12f21..28441fcf 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,6 @@
 # PyFPGA [![License](https://img.shields.io/badge/License-GPL--3.0-darkgreen?style=flat-square)](LICENSE)
 
+![Diamond](https://img.shields.io/badge/Diamond-3.13-blue.svg?style=flat-square)
 ![ISE](https://img.shields.io/badge/ISE-14.7-blue.svg?style=flat-square)
 ![Libero](https://img.shields.io/badge/Libero--Soc-2024.1-blue.svg?style=flat-square)
 ![Quartus](https://img.shields.io/badge/Quartus--Prime-23.1-blue.svg?style=flat-square)
diff --git a/examples/hooks/diamond.py b/examples/hooks/diamond.py
new file mode 100644
index 00000000..eac463fa
--- /dev/null
+++ b/examples/hooks/diamond.py
@@ -0,0 +1,52 @@
+"""Diamond example hooks."""
+
+from pyfpga.diamond import Diamond
+
+prj = Diamond(odir='../build/diamond')
+
+hooks = {
+    "reports": """
+prj_run Map -task MapTrace -forceOne
+prj_run PAR -task PARTrace -forceOne
+prj_run PAR -task IOTiming -forceOne
+    """,
+
+    "netlist_simulation": """
+prj_run Map -task MapVerilogSimFile
+prj_run Map -task MapVHDLSimFile -forceOne
+prj_run Export -task TimingSimFileVHD -forceOne
+prj_run Export -task TimingSimFileVlg -forceOne
+prj_run Export -task IBIS -forceOne
+    """,
+
+    "progfile_ecp5u": """
+prj_run Export -task Promgen -forceOne
+    """,
+
+    "progfile_machxo2": """
+prj_run Export -task Jedecgen -forceOne
+    """
+}
+
+prj.set_part('LFXP2-5E-5TN144C')
+
+prj.add_param('FREQ', '50000000')
+prj.add_param('SECS', '1')
+
+prj.add_cons('../sources/cons/brevia2/clk.lpf', 'syn')
+prj.add_cons('../sources/cons/brevia2/clk.lpf', 'par')
+prj.add_cons('../sources/cons/brevia2/io.lpf', 'par')
+
+prj.add_include('../sources/vlog/include1')
+prj.add_include('../sources/vlog/include2')
+prj.add_vlog('../sources/vlog/*.v')
+
+prj.add_define('DEFINE1', '1')
+prj.add_define('DEFINE2', '1')
+
+prj.set_top('Top')
+
+for hook_name, hook in hooks.items():
+	prj.add_hook('postpar', hook)
+
+prj.make()
diff --git a/examples/projects/diamond.py b/examples/projects/diamond.py
new file mode 100644
index 00000000..9e602d5c
--- /dev/null
+++ b/examples/projects/diamond.py
@@ -0,0 +1,51 @@
+"""Diamond examples."""
+
+import argparse
+
+from pyfpga.diamond import Diamond
+
+
+parser = argparse.ArgumentParser()
+parser.add_argument(
+    '--board', choices=['brevia2'], default='brevia2'
+)
+parser.add_argument(
+    '--source', choices=['vlog', 'vhdl', 'slog'], default='vlog'
+)
+parser.add_argument(
+    '--action', choices=['make', 'prog', 'all'], default='make'
+)
+args = parser.parse_args()
+
+prj = Diamond(odir='../build/diamond')
+
+if args.board == 'brevia2':
+    prj.set_part('LFXP2-5E-5TN144C')
+    prj.add_param('FREQ', '50000000')
+    prj.add_cons('../sources/cons/brevia2/clk.lpf', 'syn')
+    prj.add_cons('../sources/cons/brevia2/clk.lpf', 'par')
+    prj.add_cons('../sources/cons/brevia2/io.lpf', 'par')
+prj.add_param('SECS', '1')
+
+if args.source == 'vhdl':
+    prj.add_vhdl('../sources/vhdl/*.vhdl', 'blink_lib')
+    prj.add_vhdl('../sources/vhdl/top.vhdl')
+if args.source == 'vlog':
+    prj.add_include('../sources/vlog/include1')
+    prj.add_include('../sources/vlog/include2')
+    prj.add_vlog('../sources/vlog/*.v')
+if args.source == 'slog':
+    prj.add_include('../sources/slog/include1')
+    prj.add_include('../sources/slog/include2')
+    prj.add_slog('../sources/slog/*.sv')
+if args.source in ['vlog', 'slog']:
+    prj.add_define('DEFINE1', '1')
+    prj.add_define('DEFINE2', '1')
+
+prj.set_top('Top')
+
+if args.action in ['make', 'all']:
+    prj.make()
+
+if args.action in ['prog', 'all']:
+    prj.prog()
diff --git a/examples/sources/cons/brevia2/clk.lpf b/examples/sources/cons/brevia2/clk.lpf
new file mode 100644
index 00000000..c0d5f789
--- /dev/null
+++ b/examples/sources/cons/brevia2/clk.lpf
@@ -0,0 +1,3 @@
+BLOCK RESETPATHS ;
+BLOCK ASYNCPATHS ;
+FREQUENCY NET "clk_i_c" 50.000000 MHz ;
diff --git a/examples/sources/cons/brevia2/io.lpf b/examples/sources/cons/brevia2/io.lpf
new file mode 100644
index 00000000..9933563f
--- /dev/null
+++ b/examples/sources/cons/brevia2/io.lpf
@@ -0,0 +1,4 @@
+LOCATE COMP "clk_i" SITE "21" ;
+IOBUF PORT "clk_i" IO_TYPE=LVCMOS33 ;
+LOCATE COMP "led_o" SITE "37" ;
+IOBUF PORT "led_o" IO_TYPE=LVCMOS33 ;
diff --git a/pyfpga/diamond.py b/pyfpga/diamond.py
new file mode 100644
index 00000000..a5b3e622
--- /dev/null
+++ b/pyfpga/diamond.py
@@ -0,0 +1,30 @@
+#
+# Copyright (C) 2024 PyFPGA Project
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+
+"""
+Implements support for Diamond.
+"""
+
+import os
+from pyfpga.project import Project
+
+
+class Diamond(Project):
+    """Class to support Diamond projects."""
+
+    def _configure(self):
+        tool = 'diamond'
+        executable = 'pnmainc' if os.name == 'nt' else 'diamondc'
+        self.conf['tool'] = tool
+        self.conf['make_cmd'] = f'{executable} {tool}.tcl'
+        self.conf['make_ext'] = 'tcl'
+        self.conf['prog_bit'] = 'bit'
+        self.conf['prog_cmd'] = f'sh {tool}-prog.sh'
+        self.conf['prog_ext'] = 'sh'
+
+    def _make_custom(self):
+        if 'part' not in self.data:
+            self.data['part'] = 'LFXP2-5E-5TN144C'
diff --git a/pyfpga/factory.py b/pyfpga/factory.py
index 80782183..753ce84d 100644
--- a/pyfpga/factory.py
+++ b/pyfpga/factory.py
@@ -10,6 +10,7 @@
 
 # pylint: disable=too-few-public-methods
 
+from pyfpga.diamond import Diamond
 from pyfpga.ise import Ise
 from pyfpga.libero import Libero
 from pyfpga.openflow import Openflow
@@ -18,6 +19,7 @@
 
 
 TOOLS = {
+    'diamond': Diamond,
     'ise': Ise,
     'libero': Libero,
     'openflow': Openflow,
diff --git a/pyfpga/templates/diamond-prog.jinja b/pyfpga/templates/diamond-prog.jinja
new file mode 100644
index 00000000..e1a1e57c
--- /dev/null
+++ b/pyfpga/templates/diamond-prog.jinja
@@ -0,0 +1,19 @@
+{#
+# Copyright (C) 2024 PyFPGA Project
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+#}
+
+if [ "$DIAMOND_XCF" == "" ]; then
+	DIAMOND_XCF=impl1/impl1.xcf
+fi
+
+if [ -f "$DIAMOND_XCF" ]; then
+	pgrcmd -infile $DIAMOND_XCF
+else
+	echo "ERROR: Automatic programming with Diamond is not yet supported."
+	echo "       Please create the `realpath $DIAMOND_XCF` file manually and rerun the prog command."
+	echo "       Hint: You can change the location of the XCF file by setting the DIAMOND_XCF environment variable."
+	exit 1
+fi
diff --git a/pyfpga/templates/diamond.jinja b/pyfpga/templates/diamond.jinja
new file mode 100644
index 00000000..3a191524
--- /dev/null
+++ b/pyfpga/templates/diamond.jinja
@@ -0,0 +1,105 @@
+{#
+#
+# Copyright (C) 2015-2024 PyFPGA Project
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+#}
+
+{% if 'cfg' in steps %}# Project configuration -------------------------------------------------------
+
+prj_project new -name {{ project }} -dev {{ part }}
+
+# For now, let's enforce Synplify as LSE (the default) has broken top level generic handling
+prj_syn set synplify
+
+{% if hooks %}{{ hooks.precfg | join('\n') }}{% endif %}
+
+{% if files %}# Files inclusion
+{% for name, attr in files.items() %}
+prj_src add {% if 'lib' in attr %}-work {{ attr.lib }}{% else %}{% endif %} {{ name }}
+{% endfor %}
+{% endif %}
+
+{% if constraints %}
+# Constraints inclusion
+#   Diamond only supports one constraints file, so we need to combine them into the default diamond.lpf.
+#   We can't just do `prj_src add <constraints-file>` multiple times.
+set fileId [open diamond.lpf "w"]
+{% for name, attr in constraints.items() %}
+set fp [open "{{ name }}" r]
+set file_data [read $fp]
+close $fp
+puts -nonewline $fileId $file_data
+{% endfor %}
+close $fileId
+{% endif %}
+
+{% if top %}# Top-level specification
+prj_impl option top "{{ top }}"
+{% endif %}
+
+{% if includes %}# Verilog Includes
+{% for include in includes %}
+prj_impl option -append {include path} {{ "{"+include+"}" }}
+{% endfor %}
+{% endif %}
+
+{% if defines %}# Verilog Defines
+{% for key, value in defines.items() %}
+prj_impl option -append VERILOG_DIRECTIVES {{ key }}={{ value }}
+{% endfor %}
+{% endif %}
+
+{% if params %}# Verilog Parameters / VHDL Generics
+{% for key, value in params.items() %}
+prj_impl option -append HDL_PARAM {{ key }}={{ value }}
+{% endfor %}
+{% endif %}
+
+{% if hooks %}{{ hooks.postcfg | join('\n') }}{% endif %}
+
+prj_project save
+prj_project close
+
+{% endif %}
+
+{% if 'syn' in steps or 'par' in steps or 'bit' in steps %}# Design flow -----------------------------------------------------------------
+
+prj_project open {{ project }}.ldf
+
+{% if 'syn' in steps %}# Synthesis
+
+{% if hooks %}{{ hooks.presyn | join('\n') }}{% endif %}
+
+prj_run Synthesis -forceOne
+
+{% if hooks %}{{ hooks.postsyn | join('\n') }}{% endif %}
+
+{% endif %}
+
+{% if 'par' in steps %} # Translate, Map, and Place and Route
+{% if hooks %}{{ hooks.prepar | join('\n') }}{% endif %}
+
+prj_run Translate -forceOne
+prj_run Map -forceOne
+prj_run PAR -forceOne
+
+{% if hooks %}{{ hooks.postpar | join('\n') }}{% endif %}
+
+{% endif %}
+
+{% if 'bit' in steps %}# Bitstream generation
+
+{% if hooks %}{{ hooks.prebit | join('\n') }}{% endif %}
+
+prj_run Export -task Bitgen -forceOne
+
+{% if hooks %}{{ hooks.postbit | join('\n') }}{% endif %}
+
+{% endif %}
+
+prj_project save
+prj_project close
+
+{% endif %}
diff --git a/tests/mocks/diamondc b/tests/mocks/diamondc
new file mode 100755
index 00000000..1beac9c1
--- /dev/null
+++ b/tests/mocks/diamondc
@@ -0,0 +1,38 @@
+#!/usr/bin/env python3
+
+#
+# Copyright (C) 2024 PyFPGA Project
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+
+import argparse
+import subprocess
+import sys
+
+
+parser = argparse.ArgumentParser()
+
+parser.add_argument('source')
+
+args = parser.parse_args()
+
+tool = parser.prog
+
+tcl = f'''
+proc unknown args {{ }}
+
+source {args.source}
+'''
+
+with open(f'{tool}-mock.tcl', 'w', encoding='utf-8') as file:
+    file.write(tcl)
+
+subprocess.run(
+   f'tclsh {tool}-mock.tcl',
+   shell=True,
+   check=True,
+   universal_newlines=True
+)
+
+print(f'INFO:the {tool.upper()} mock has been executed')
diff --git a/tests/test_tools.py b/tests/test_tools.py
index 45f972ed..ffaa7e5b 100644
--- a/tests/test_tools.py
+++ b/tests/test_tools.py
@@ -4,6 +4,13 @@
 tdir = Path(__file__).parent.resolve()
 
 
+def test_diamond():
+    tool = 'diamond'
+    generate(tool, 'PARTNAME')
+    base = f'results/{tool}/{tool}'
+    assert Path(f'{base}.tcl').exists(), 'file not found'
+
+
 def test_ise():
     tool = 'ise'
     generate(tool, 'DEVICE-PACKAGE-SPEED')

From 45995b8a93ed384b2173570a343d0e22a5049981 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 12 Aug 2024 19:50:32 -0300
Subject: [PATCH 196/248] Fix a linter issue

---
 examples/hooks/diamond.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/hooks/diamond.py b/examples/hooks/diamond.py
index eac463fa..0e0b5d55 100644
--- a/examples/hooks/diamond.py
+++ b/examples/hooks/diamond.py
@@ -47,6 +47,6 @@
 prj.set_top('Top')
 
 for hook_name, hook in hooks.items():
-	prj.add_hook('postpar', hook)
+    prj.add_hook('postpar', hook)
 
 prj.make()

From 95afdae1f2db803c09c872fb991d6b45d3d06e7f Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 12 Aug 2024 20:04:04 -0300
Subject: [PATCH 197/248] docs: add content to 'Extending'

---
 docs/extending.rst | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/docs/extending.rst b/docs/extending.rst
index 20d48463..03c995cf 100644
--- a/docs/extending.rst
+++ b/docs/extending.rst
@@ -1,2 +1,40 @@
 Extending
 =========
+
+1. Add support for the new tool:
+
+.. code-block:: python
+
+   pyfpga/templates/<NEWTOOL>.jinja
+   pyfpga/templates/<NEWTOOL>-prog.jinja
+   pyfpga/<NEWTOOL>.py
+
+2. Include the new tool on Factory:
+
+.. code-block:: python
+
+   pyfpga/factory.py
+
+3. Add tests and a tool mock-up:
+
+.. code-block:: python
+
+   tests/test_tools.py
+   tests/mocks/<NEWTOOL_EXECUTABLE>
+
+4. Updated the project's documentation:
+
+.. code-block:: python
+
+   README.md
+   docs
+
+5. [OPTIONAL] Add examples:
+
+.. code-block:: python
+
+   examples/sources/cons/<NEWBOARD>/timing.<EXT>
+   examples/sources/cons/<NEWBOARD>/clk.<EXT>
+   examples/sources/cons/<NEWBOARD>/led.<EXT>
+   examples/projects/<NEWTOOL>.py
+   examples/hooks/<NEWTOOL>.py

From dd8e4de3b8ea10f9d3e3ac3aa4cd112be81ba105 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 12 Aug 2024 20:21:03 -0300
Subject: [PATCH 198/248] A few constraint files were renamed to maintain names
 coherency

---
 examples/helpers/ise.sh                                | 4 ++--
 examples/helpers/libero.sh                             | 4 ++--
 examples/helpers/quartus.sh                            | 4 ++--
 examples/hooks/diamond.py                              | 5 ++---
 examples/projects/diamond.py                           | 5 ++---
 examples/projects/ise.py                               | 4 ++--
 examples/projects/libero.py                            | 2 +-
 examples/projects/quartus.py                           | 2 +-
 examples/sources/cons/brevia2/{io.lpf => led.lpf}      | 0
 examples/sources/cons/de10nano/{clk.sdc => timing.sdc} | 0
 examples/sources/cons/maker/{clk.sdc => timing.sdc}    | 0
 examples/sources/cons/nexys3/{clk.xcf => timing.xcf}   | 0
 examples/sources/cons/s6micro/{clk.xcf => timing.xcf}  | 0
 13 files changed, 14 insertions(+), 16 deletions(-)
 rename examples/sources/cons/brevia2/{io.lpf => led.lpf} (100%)
 rename examples/sources/cons/de10nano/{clk.sdc => timing.sdc} (100%)
 rename examples/sources/cons/maker/{clk.sdc => timing.sdc} (100%)
 rename examples/sources/cons/nexys3/{clk.xcf => timing.xcf} (100%)
 rename examples/sources/cons/s6micro/{clk.xcf => timing.xcf} (100%)

diff --git a/examples/helpers/ise.sh b/examples/helpers/ise.sh
index 11e73ba8..a366c6e9 100644
--- a/examples/helpers/ise.sh
+++ b/examples/helpers/ise.sh
@@ -7,12 +7,12 @@ HDIR=../../pyfpga/helpers
 python3 $HDIR/hdl2bit.py -t ise -o results/ise-vlog -p xc6slx16-3-csg32 \
     -i ../sources/vlog/include1 -i ../sources/vlog/include2 \
     -f ../sources/vlog/blink.v -f ../sources/vlog/top.v \
-    -f ../sources/cons/nexys3/clk.xcf -f ../sources/cons/nexys3/clk.ucf -f ../sources/cons/nexys3/led.ucf \
+    -f ../sources/cons/nexys3/timing.xcf -f ../sources/cons/nexys3/clk.ucf -f ../sources/cons/nexys3/led.ucf \
     --define DEFINE1 1 --define DEFINE2 1 --param FREQ 125000000 --param SECS 1 Top
 
 python3 $HDIR/hdl2bit.py -t ise -o results/ise-vhdl -p xc6slx16-3-csg32 --project example \
     -f ../sources/vhdl/blink.vhdl,blink_lib -f ../sources/vhdl/blink_pkg.vhdl,blink_lib -f ../sources/vhdl/top.vhdl \
-    -f ../sources/cons/nexys3/clk.xcf -f ../sources/cons/nexys3/clk.ucf -f ../sources/cons/nexys3/led.ucf \
+    -f ../sources/cons/nexys3/timing.xcf -f ../sources/cons/nexys3/clk.ucf -f ../sources/cons/nexys3/led.ucf \
     --param FREQ 125000000 --param SECS 1 --last cfg Top
 
 python3 $HDIR/prj2bit.py results/ise-vhdl/example.xise
diff --git a/examples/helpers/libero.sh b/examples/helpers/libero.sh
index 1a56da93..8d270c48 100644
--- a/examples/helpers/libero.sh
+++ b/examples/helpers/libero.sh
@@ -7,12 +7,12 @@ HDIR=../../pyfpga/helpers
 python3 $HDIR/hdl2bit.py -t libero -o results/libero-vlog -p m2s010-1-tq144 \
     -i ../sources/vlog/include1 -i ../sources/vlog/include2 \
     -f ../sources/vlog/blink.v -f ../sources/vlog/top.v \
-    -f ../sources/cons/maker/clk.sdc -f ../sources/cons/maker/clk.pdc -f ../sources/cons/maker/led.pdc \
+    -f ../sources/cons/maker/timing.sdc -f ../sources/cons/maker/clk.pdc -f ../sources/cons/maker/led.pdc \
     --define DEFINE1 1 --define DEFINE2 1 --param FREQ 125000000 --param SECS 1 Top
 
 python3 $HDIR/hdl2bit.py -t libero -o results/libero-vhdl -p m2s010-1-tq144 --project example \
     -f ../sources/vhdl/blink.vhdl,blink_lib -f ../sources/vhdl/blink_pkg.vhdl,blink_lib -f ../sources/vhdl/top.vhdl \
-    -f ../sources/cons/maker/clk.sdc -f ../sources/cons/maker/clk.pdc -f ../sources/cons/maker/led.pdc \
+    -f ../sources/cons/maker/timing.sdc -f ../sources/cons/maker/clk.pdc -f ../sources/cons/maker/led.pdc \
     --param FREQ 125000000 --param SECS 1 --last cfg Top
 
 python3 $HDIR/prj2bit.py results/libero-vhdl/libero/example.prjx
diff --git a/examples/helpers/quartus.sh b/examples/helpers/quartus.sh
index b2ae4437..b532ed83 100644
--- a/examples/helpers/quartus.sh
+++ b/examples/helpers/quartus.sh
@@ -7,12 +7,12 @@ HDIR=../../pyfpga/helpers
 python3 $HDIR/hdl2bit.py -t quartus -o results/quartus-vlog -p 5CSEBA6U23I7 \
     -i ../sources/vlog/include1 -i ../sources/vlog/include2 \
     -f ../sources/vlog/blink.v -f ../sources/vlog/top.v \
-    -f ../sources/cons/de10nano/clk.sdc -f ../sources/cons/de10nano/clk.tcl -f ../sources/cons/de10nano/led.tcl \
+    -f ../sources/cons/de10nano/timing.sdc -f ../sources/cons/de10nano/clk.tcl -f ../sources/cons/de10nano/led.tcl \
     --define DEFINE1 1 --define DEFINE2 1 --param FREQ 125000000 --param SECS 1 Top
 
 python3 $HDIR/hdl2bit.py -t quartus -o results/quartus-vhdl -p 5CSEBA6U23I7 --project example \
     -f ../sources/vhdl/blink.vhdl,blink_lib -f ../sources/vhdl/blink_pkg.vhdl,blink_lib -f ../sources/vhdl/top.vhdl \
-    -f ../sources/cons/de10nano/clk.sdc -f ../sources/cons/de10nano/clk.tcl -f ../sources/cons/de10nano/led.tcl \
+    -f ../sources/cons/de10nano/timing.sdc -f ../sources/cons/de10nano/clk.tcl -f ../sources/cons/de10nano/led.tcl \
     --param FREQ 125000000 --param SECS 1 --last cfg Top
 
 python3 $HDIR/prj2bit.py results/quartus-vhdl/example.qpf
diff --git a/examples/hooks/diamond.py b/examples/hooks/diamond.py
index 0e0b5d55..389b9a60 100644
--- a/examples/hooks/diamond.py
+++ b/examples/hooks/diamond.py
@@ -33,9 +33,8 @@
 prj.add_param('FREQ', '50000000')
 prj.add_param('SECS', '1')
 
-prj.add_cons('../sources/cons/brevia2/clk.lpf', 'syn')
-prj.add_cons('../sources/cons/brevia2/clk.lpf', 'par')
-prj.add_cons('../sources/cons/brevia2/io.lpf', 'par')
+prj.add_cons('../sources/cons/brevia2/clk.lpf')
+prj.add_cons('../sources/cons/brevia2/led.lpf')
 
 prj.add_include('../sources/vlog/include1')
 prj.add_include('../sources/vlog/include2')
diff --git a/examples/projects/diamond.py b/examples/projects/diamond.py
index 9e602d5c..4f5a85de 100644
--- a/examples/projects/diamond.py
+++ b/examples/projects/diamond.py
@@ -22,9 +22,8 @@
 if args.board == 'brevia2':
     prj.set_part('LFXP2-5E-5TN144C')
     prj.add_param('FREQ', '50000000')
-    prj.add_cons('../sources/cons/brevia2/clk.lpf', 'syn')
-    prj.add_cons('../sources/cons/brevia2/clk.lpf', 'par')
-    prj.add_cons('../sources/cons/brevia2/io.lpf', 'par')
+    prj.add_cons('../sources/cons/brevia2/clk.lpf')
+    prj.add_cons('../sources/cons/brevia2/led.lpf')
 prj.add_param('SECS', '1')
 
 if args.source == 'vhdl':
diff --git a/examples/projects/ise.py b/examples/projects/ise.py
index a81082a2..38d886c1 100644
--- a/examples/projects/ise.py
+++ b/examples/projects/ise.py
@@ -22,13 +22,13 @@
 if args.board == 's6micro':
     prj.set_part('xc6slx9-2-csg324')
     prj.add_param('FREQ', '125000000')
-    prj.add_cons('../sources/cons/s6micro/clk.xcf')
+    prj.add_cons('../sources/cons/s6micro/timing.xcf')
     prj.add_cons('../sources/cons/s6micro/clk.ucf')
     prj.add_cons('../sources/cons/s6micro/led.ucf')
 if args.board == 'nexys3':
     prj.set_part('xc6slx16-3-csg32')
     prj.add_param('FREQ', '100000000')
-    prj.add_cons('../sources/cons/nexys3/clk.xcf')
+    prj.add_cons('../sources/cons/nexys3/timing.xcf')
     prj.add_cons('../sources/cons/nexys3/clk.ucf')
     prj.add_cons('../sources/cons/nexys3/led.ucf')
 prj.add_param('SECS', '1')
diff --git a/examples/projects/libero.py b/examples/projects/libero.py
index e9e2697c..4edd978e 100644
--- a/examples/projects/libero.py
+++ b/examples/projects/libero.py
@@ -21,7 +21,7 @@
 if args.board == 'maker':
     prj.set_part('m2s010-1-tq144')
     prj.add_param('FREQ', '125000000')
-    prj.add_cons('../sources/cons/maker/clk.sdc')
+    prj.add_cons('../sources/cons/maker/timing.sdc')
     prj.add_cons('../sources/cons/maker/clk.pdc')
     prj.add_cons('../sources/cons/maker/led.pdc')
 prj.add_param('SECS', '1')
diff --git a/examples/projects/quartus.py b/examples/projects/quartus.py
index cccbb372..02ed76d3 100644
--- a/examples/projects/quartus.py
+++ b/examples/projects/quartus.py
@@ -22,7 +22,7 @@
 if args.board == 'de10nano':
     prj.set_part('5CSEBA6U23I7')
     prj.add_param('FREQ', '125000000')
-    prj.add_cons('../sources/cons/de10nano/clk.sdc')
+    prj.add_cons('../sources/cons/de10nano/timing.sdc')
     prj.add_cons('../sources/cons/de10nano/clk.tcl')
     prj.add_cons('../sources/cons/de10nano/led.tcl')
 prj.add_param('SECS', '1')
diff --git a/examples/sources/cons/brevia2/io.lpf b/examples/sources/cons/brevia2/led.lpf
similarity index 100%
rename from examples/sources/cons/brevia2/io.lpf
rename to examples/sources/cons/brevia2/led.lpf
diff --git a/examples/sources/cons/de10nano/clk.sdc b/examples/sources/cons/de10nano/timing.sdc
similarity index 100%
rename from examples/sources/cons/de10nano/clk.sdc
rename to examples/sources/cons/de10nano/timing.sdc
diff --git a/examples/sources/cons/maker/clk.sdc b/examples/sources/cons/maker/timing.sdc
similarity index 100%
rename from examples/sources/cons/maker/clk.sdc
rename to examples/sources/cons/maker/timing.sdc
diff --git a/examples/sources/cons/nexys3/clk.xcf b/examples/sources/cons/nexys3/timing.xcf
similarity index 100%
rename from examples/sources/cons/nexys3/clk.xcf
rename to examples/sources/cons/nexys3/timing.xcf
diff --git a/examples/sources/cons/s6micro/clk.xcf b/examples/sources/cons/s6micro/timing.xcf
similarity index 100%
rename from examples/sources/cons/s6micro/clk.xcf
rename to examples/sources/cons/s6micro/timing.xcf

From d169a7b20e44dc43da80e09141cf695bcb82a17d Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 12 Aug 2024 20:26:51 -0300
Subject: [PATCH 199/248] Update copyright

---
 pyfpga/factory.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pyfpga/factory.py b/pyfpga/factory.py
index 753ce84d..6da4029a 100644
--- a/pyfpga/factory.py
+++ b/pyfpga/factory.py
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2024 Rodrigo A. Melo
+# Copyright (C) 2024 PyFPGA Project
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #

From 25613a6b710d529e48379899655cd84cb5ebc216 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 12 Aug 2024 22:15:29 -0300
Subject: [PATCH 200/248] docs: 'Tools' rewritten

---
 docs/tools.rst | 236 +++++++++++++++++++++++++++++--------------------
 1 file changed, 141 insertions(+), 95 deletions(-)

diff --git a/docs/tools.rst b/docs/tools.rst
index ffd3d97b..8839ac2d 100644
--- a/docs/tools.rst
+++ b/docs/tools.rst
@@ -1,98 +1,144 @@
 Tools
 =====
 
-+---------------+-----------+---------+-----+-----------------------------------------------+
-| Tools         | Vendor    | Version | Tcl | Comment                                       |
-+===============+===========+=========+=====+===============================================+
-| ISE           | Xilinx    | 14.7    | 8.4 | Discontinued in 2013                          |
-+---------------+-----------+---------+-----+-----------------------------------------------+
-| Libero-SoC    | Microsemi | 2024.1  | 8.5 | Important changes in version 12.0 (2019)      |
-+---------------+-----------+---------+-----+-----------------------------------------------+
-| Openflow      |           |         |     |                                               |
-+---------------+-----------+---------+-----+-----------------------------------------------+
-| Quartus Prime | Intel     | 23.1    | 8.6 | Known as Quartus II until version 15.0 (2015) |
-+---------------+-----------+---------+-----+-----------------------------------------------+
-| Vivado        | Xilinx    | 2022.1  | 8.5 | Introduced in 2012, it superseded ISE         |
-+---------------+-----------+---------+-----+-----------------------------------------------+
-
-* ISE supports devices starting from Spartan 3/Virtex 4 until some first members of the 7 series.
-  Previous Spartan/Virtex devices were supported until version 10. Vivado supports devices starting
-  from the 7 series.
-
-* Libero-SoC had a fork for PolarFire devices which was merged in version 12.0 (2019).
-  Libero SoC v12.0 and later supports PolarFire, RTG4, SmartFusion2 and IGLOO2 FPGA families.
-  Libero SoC v11.9 and earlier are the alternative to work with SmartFusion, IGLOO, ProASIC3 and
-  Fusion families.
-  Libero IDE v9.2 (2016) was the last version of the previous tool to work with antifuse and older
-  flash devices.
-
-* Since the change from Quartus II to Prime, three editions are available: Pro (for Agilex,
-  Stratix 10, Arria 10 and Cyclone GX devices), Standard (for Cyclone 10 LP and earlier devices)
-  and Lite (a high-volume low-end subset of the Standard edition).
-
-Detailed support
-----------------
-
-+------------------------------+---------+----------+------------+-----------+----------+
-|                              | ISE     | Libero   | Openflow   | Quartus   | Vivado   |
-+==============================+=========+==========+============+===========+==========+
-|**add_files**                 |         |          |            |           |          |
-+------------------------------+---------+----------+------------+-----------+----------+
-|``vhdl``                      | ``Yes`` | ``Yes``  | ``Yes``    | ``Yes``   | ``Yes``  |
-+------------------------------+---------+----------+------------+-----------+----------+
-|``verilog``                   | ``Yes`` | ``Yes``  | ``Yes``    | ``Yes``   | ``Yes``  |
-+------------------------------+---------+----------+------------+-----------+----------+
-|``system_verilog``            | ``TBD`` | ``TBD``  | ``TBD``    | ``TBD``   | ``TBD``  |
-+------------------------------+---------+----------+------------+-----------+----------+
-|``constraint``                | ``Yes`` | ``Yes``  | ``Yes``    | ``Yes``   | ``Yes``  |
-+------------------------------+---------+----------+------------+-----------+----------+
-|``block_design``              | ``NY``  | ``NY``   | ``NY``     | ``NY``    | ``Yes``  |
-+------------------------------+---------+----------+------------+-----------+----------+
-|**add_param**                 |         |          |            |           |          |
-+------------------------------+---------+----------+------------+-----------+----------+
-|``boolean`` (*VHDL/Verilog*)  | ``TBD`` | ``TBD``  |``TBD``     | ``TBD``   | ``TBD``  |
-+------------------------------+---------+----------+------------+-----------+----------+
-|``integer`` (*VHDL/Verilog*)  | ``TBD`` | ``TBD``  |``TBD``     | ``TBD``   | ``TBD``  |
-+------------------------------+---------+----------+------------+-----------+----------+
-|``string`` (*VHDL/Verilog*)   | ``TBD`` | ``TBD``  |``TBD``     | ``TBD``   | ``TBD``  |
-+------------------------------+---------+----------+------------+-----------+----------+
-|``real`` (*VHDL/Verilog*)     | ``TBD`` | ``TBD``  |``TBD``     | ``TBD``   | ``TBD``  |
-+------------------------------+---------+----------+------------+-----------+----------+
-|``std_logic`` (*VHDL*)        | ``TBD`` | ``TBD``  |``TBD``     | ``TBD``   | ``TBD``  |
-+------------------------------+---------+----------+------------+-----------+----------+
-|``std_logic_vector`` (*VHDL*) | ``TBD`` | ``TBD``  |``TBD``     | ``TBD``   | ``TBD``  |
-+------------------------------+---------+----------+------------+-----------+----------+
-|**add_vlog_include**          | ``Yes`` | ``Yes``  | ``Yes``    | ``Yes``   | ``Yes``  |
-+------------------------------+---------+----------+------------+-----------+----------+
-|**add_vlog_define**           | ``TBI`` | ``TBI``  | ``TBI``    | ``TBI``   | ``TBI``  |
-+------------------------------+---------+----------+------------+-----------+----------+
-|**set_vhdl_arch**             | ``TBI`` | ``TBI``  | ``TBI``    | ``TBI``   | ``TBI``  |
-+------------------------------+---------+----------+------------+-----------+----------+
-|**generate**                  |         |          |            |           |          |
-+------------------------------+---------+----------+------------+-----------+----------+
-|``prj``                       | ``Yes`` | ``Yes``  | ``No``     | ``Yes``   | ``Yes``  |
-+------------------------------+---------+----------+------------+-----------+----------+
-|``syn``                       | ``Yes`` | ``Yes``  | ``Yes``    | ``Yes``   | ``Yes``  |
-+------------------------------+---------+----------+------------+-----------+----------+
-|``par``                       | ``Yes`` | ``Yes``  | ``Yes``    | ``Yes``   | ``Yes``  |
-+------------------------------+---------+----------+------------+-----------+----------+
-|``bit``                       | ``Yes`` | ``Yes``  | ``Yes``    | ``Yes``   | ``Yes``  |
-+------------------------------+---------+----------+------------+-----------+----------+
-|**transfer**                  |         |          |            |           |          |
-+------------------------------+---------+----------+------------+-----------+----------+
-|``fpga``                      | ``Yes`` | ``NY``   | ``Yes``    | ``Yes``   | ``Yes``  |
-+------------------------------+---------+----------+------------+-----------+----------+
-|``spi``                       | ``Yes`` | ``NY``   | ``NY``     | ``NY``    | ``NY``   |
-+------------------------------+---------+----------+------------+-----------+----------+
-|``bpi``                       | ``Yes`` | ``NY``   | ``NY``     | ``NY``    | ``NY``   |
-+------------------------------+---------+----------+------------+-----------+----------+
-|``detect``                    | ``Yes`` | ``NY``   | ``NY``     | ``Yes``   | ``Yes``  |
-+------------------------------+---------+----------+------------+-----------+----------+
-|``unlock``                    | ``Yes`` | ``No``   | ``No``     | ``No``    | ``No``   |
-+------------------------------+---------+----------+------------+-----------+----------+
-
-* ``Yes``: already supported
-* ``No``: no plans (or unneeded)
-* ``NY``: Not yet, but maybe someday
-* ``TBD``: To Be Defined
-* ``TBI``: To Be Implemented
+.. list-table:: Default PyFPGA's parts per tool
+   :header-rows: 1
+
+   * - Tool
+     - Vendor
+     - Default device
+     - Name format
+   * - Diamond
+     - Lattice
+     - LFXP2-5E-5TN144C
+     - device-speed-package
+   * - ISE
+     - Xilinx
+     - XC7K160T-3-FBG484
+     - device-speed-package
+   * - Libero
+     - Microchip/Microsemi
+     - MPF100T-1-FCG484
+     - device-speed-package
+   * - Openflow
+     - FLOSS
+     - HX8K-CT256
+     - device-package
+   * - Quartus
+     - Intel/Altera
+     - 10M50SCE144I7G
+     - part
+   * - Vivado
+     - AMD/Xilinx
+     - XC7K160T-3-FBG484
+     - device-speed-package
+
+Diamond
+-------
+
+`Diamond downloads <https://www.latticesemi.com/latticediamond>`_
+
+Diamond is the previous generation EDA tool from Lattice.
+
+Example:
+
+.. code::
+
+   from pyfpga.diamond import Diamond
+
+   prj = Diamond()
+
+ISE
+---
+
+`ISE downloads <https://www.xilinx.com/support/download/index.html/content/xilinx/en/downloadNav/vivado-design-tools/archive-ise.html>`_
+
+ISE (*Integrated Software Environment*) is the previous Xilinx's EDA, superseded by Vivado.
+The last version is ISE 14.7, launched in October 2013.
+It supports devices starting from Spartan 3/Virtex 4 until some of the first members of the 7 series (all the 7 series and above are supported by Vivado).
+Previous Spartan/Virtex devices were supported until version 10.
+
+.. attention::
+
+   ISE supports Verilog 2001 and VHDL 1993, but not SystemVerilog.
+
+Example:
+
+.. code::
+
+   from pyfpga.ise import Ise
+
+   prj = Ise()
+
+Libero
+------
+
+`Libero downloads <https://www.microchip.com/en-us/products/fpgas-and-plds/fpga-and-soc-design-tools/fpga/libero-software-later-versions>`_
+
+Libero-SoC (Microsemi, acquired by Microchip in 2018) is the evolution of Libero-IDE (Actel, acquired by Microsemi in 2010).
+PyFPGA supports Libero-SoC starting from 12.0, which supports most modern families.
+For other devices, Libero-SoC 11.9 or Libero-IDE v9.2 are needed, but these versions are not supported by PyFPGA.
+
+Example:
+
+.. code::
+
+   from pyfpga.libero import Libero
+
+   prj = Libero()
+
+Openflow
+--------
+
+`Docker downloads <https://docs.docker.com/engine/install/>`_
+
+Openflow is the combination of different Free/Libre and Open Source (FLOSS) tools:
+
+* Yosys for synthesis, with ghdl-yosys-plugin for VHDL support.
+* nextpnr in its ice40 and ecp5 versions.
+* Projects icestorm and Trellis.
+
+It relies on Docker and fine-grain containers.
+
+.. attention::
+
+   It is currently the only flow not solved using Tcl (it uses docker in a bash script instead).
+
+Example:
+
+.. code::
+
+   from pyfpga.openflow import Openflow
+
+   prj = Openflow()
+
+Quartus
+-------
+
+`Quartus downloads <https://www.intel.com/content/www/us/en/products/details/fpga/development-tools/quartus-prime/resource.html>`_
+
+Quartus Prime (Intel) is the continuation of Quartus II (Altera) and is divided into the Pro, Standard, and Lite editions, each supporting different families.
+
+Example:
+
+.. code::
+
+   from pyfpga.quartus import Quartus
+
+   prj = Quartus()
+
+Vivado
+------
+
+`Vivado downloads <https://www.xilinx.com/support/download.html>`_
+
+Vivado is the current EDA tool from Xilinx, which has superseded ISE and supports the 7 series and above.
+It is included with Vitis, the SDK for embedded applications.
+
+Example:
+
+.. code::
+
+   from pyfpga.vivado import Vivado
+
+   prj = Vivado()

From 29b3d35593715d854cfd9984a429cbde91de423d Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 12 Aug 2024 22:37:05 -0300
Subject: [PATCH 201/248] docs: 'Internals' updated

---
 docs/internals.rst | 124 ++++++++++++++++++++++++---------------------
 1 file changed, 65 insertions(+), 59 deletions(-)

diff --git a/docs/internals.rst b/docs/internals.rst
index 4da687d2..504b69ec 100644
--- a/docs/internals.rst
+++ b/docs/internals.rst
@@ -1,72 +1,78 @@
 Internals
 =========
 
-Underlying tool steps
----------------------
+Underlying steps
+----------------
 
 .. code-block::
 
-    create project
-    config project
-    part
-    precfg (hook)
-    params
-    defines
-    includes
-    files
-    top
-    postcfg (hook)
-    close project
+   project creation [options]
+   project configuration
+   part
+   precfg hook
+   params
+   defines
+   includes
+   files [options]
+   top
+   postcfg hook
+   project close
 
-    open project
-    presyn (hook)
-    synthesis
-    postsyn (hook)
-    prepar (hook)
-    place_and_route
-    postpar (hook)
-    prebit (hook)
-    bitstream
-    postbit (hook)
-    close project
+   project open
+   presyn hook
+   synthesis [options]
+   postsyn hook
+   prepar hook
+   place_and_route [options]
+   postpar hook
+   prebit hook
+   bitstream [options]
+   postbit hook
+   project close
 
 Internal data structure
 -----------------------
 
 .. code-block::
 
-    data = {
-        'part': 'PARTNAME',
-        'includes': ['DIR1', 'DIR2', 'DIR3'],
-        'files': {
-            'FILE1': {'hdl': 'vhdl', 'lib': 'LIB1', 'opt': 'OPTS'},
-            'FILE2': {'hdl': 'vlog', 'opt': 'OPTS'},
-            'FILE3': {'hdl': 'slog', 'opt': 'OPTS'}
-        },
-        'top': 'TOPNAME',
-        'constraints': {
-            'FILE1': {'opt': 'OPTS'},
-            'FILE2': {'opt': 'OPTS'},
-            'FILE3': {'opt': 'OPTS'}
-        },
-        'params': {
-            'PAR1': 'VAL1',
-            'PAR2': 'VAL2',
-            'PAR3': 'VAL3'
-        },
-        'defines': {
-            'DEF1': 'VAL1',
-            'DEF2': 'VAL2',
-            'DEF3': 'VAL3'
-        },
-        'hooks': {
-            'precfg': ['CMD1', 'CMD2'],
-            'postcfg': ['CMD1', 'CMD2'],
-            'presyn': ['CMD1', 'CMD2'],
-            'postsyn': ['CMD1', 'CMD2'],
-            'prepar': ['CMD1', 'CMD2'],
-            'postpar': ['CMD1', 'CMD2'],
-            'prebit': ['CMD1', 'CMD2'],
-            'postbit': ['CMD1', 'CMD2']
-        }
-    }
+   data = {
+       'part': 'PARTNAME',
+       'includes': ['DIR1', 'DIR2', 'DIR3'],
+       'files': {
+           'FILE1': {'hdl': 'vhdl', 'lib': 'LIB1', 'opt': 'OPTS'},
+           'FILE2': {'hdl': 'vlog', 'opt': 'OPTS'},
+           'FILE3': {'hdl': 'slog', 'opt': 'OPTS'}
+       },
+       'top': 'TOPNAME',
+       'constraints': {
+           'FILE1': {'opt': 'OPTS'},
+           'FILE2': {'opt': 'OPTS'},
+           'FILE3': {'opt': 'OPTS'}
+       },
+       'params': {
+           'PAR1': 'VAL1',
+           'PAR2': 'VAL2',
+           'PAR3': 'VAL3'
+       },
+       'defines': {
+           'DEF1': 'VAL1',
+           'DEF2': 'VAL2',
+           'DEF3': 'VAL3'
+       },
+       'hooks': {
+           'precfg': ['CMD1', 'CMD2'],
+           'postcfg': ['CMD1', 'CMD2'],
+           'presyn': ['CMD1', 'CMD2'],
+           'postsyn': ['CMD1', 'CMD2'],
+           'prepar': ['CMD1', 'CMD2'],
+           'postpar': ['CMD1', 'CMD2'],
+           'prebit': ['CMD1', 'CMD2'],
+           'postbit': ['CMD1', 'CMD2']
+       },
+       'options': {
+           'prj': 'OPTS',
+           'syn': 'OPTS',
+           'pre': 'OPTS',
+           'pre': 'OPTS'
+       }
+   }

From 9fb634e7cc92420fb32b1da893c035a4bfade2c7 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 12 Aug 2024 22:46:42 -0300
Subject: [PATCH 202/248] docs: 'advanced' was updated/simplified

---
 docs/advanced.rst | 13 ++++---------
 1 file changed, 4 insertions(+), 9 deletions(-)

diff --git a/docs/advanced.rst b/docs/advanced.rst
index 44762476..84046c48 100644
--- a/docs/advanced.rst
+++ b/docs/advanced.rst
@@ -1,14 +1,7 @@
 Advanced usage
 ==============
 
-PyFPGA offers advanced features for more customized and flexible control over FPGA project management.
-This section covers two key advanced features:
-
-1. **Hooks**: These are points in the code where you can insert custom code to extend or modify the behavior of the tool.
-Hooks provide a way to integrate additional functionality or perform specific actions at predefined stages of the project lifecycle.
-
-2. **Options**: This feature allows you to specify additional options to fine-tune the tool's behavior.
-Options provide greater control over the tool's operation and enable you to customize the processing according to your specific requirements.
+The flow implemented by PyFPGA should be sufficient for most cases, but further customizations are possible and discussed in this section.
 
 Hooks
 -----
@@ -56,6 +49,8 @@ Or in a multi-line format:
 Options
 -------
 
+Options allow you to specify additional settings to fine-tune certain commands. The available options are:
+
 .. ATTENTION::
 
-   WIP feature.
+   This feature is WIP.

From cdfec22663b543c0476dec96f6514fdb1c1d0f28 Mon Sep 17 00:00:00 2001
From: Markus Koch <markus@notsyncing.net>
Date: Thu, 22 Aug 2024 11:04:32 +0200
Subject: [PATCH 203/248] diamond: Use the project name as prefix for the
 combined constraints

Diamond defaults to <project_name>.lpf. This fixes #49.
---
 pyfpga/templates/diamond.jinja | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pyfpga/templates/diamond.jinja b/pyfpga/templates/diamond.jinja
index 3a191524..175be04d 100644
--- a/pyfpga/templates/diamond.jinja
+++ b/pyfpga/templates/diamond.jinja
@@ -25,7 +25,7 @@ prj_src add {% if 'lib' in attr %}-work {{ attr.lib }}{% else %}{% endif %} {{ n
 # Constraints inclusion
 #   Diamond only supports one constraints file, so we need to combine them into the default diamond.lpf.
 #   We can't just do `prj_src add <constraints-file>` multiple times.
-set fileId [open diamond.lpf "w"]
+set fileId [open {{ project }}.lpf "w"]
 {% for name, attr in constraints.items() %}
 set fp [open "{{ name }}" r]
 set file_data [read $fp]

From b2cd5cb82b26dee68fd03d1fe0b5210617a04cc2 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Thu, 22 Aug 2024 22:44:00 -0300
Subject: [PATCH 204/248] openflow: use the project name as the name for the
 combined constraints

---
 pyfpga/templates/openflow.jinja | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/pyfpga/templates/openflow.jinja b/pyfpga/templates/openflow.jinja
index 2cafa31d..861a0917 100644
--- a/pyfpga/templates/openflow.jinja
+++ b/pyfpga/templates/openflow.jinja
@@ -37,7 +37,7 @@ read_verilog -defer -sv {{ name }}
 chparam{% for key, value in params.items() %} -set {{ key }} {{ value }}{% endfor %}
 {% endif %}
 
-{% if top%}
+{% if top %}
 synth -top {{ top }}
 {% endif %}
 
@@ -71,10 +71,10 @@ synth_{{ family }} -top {{ top }} -json {{ project }}.json
 CONSTRAINTS="{{ constraints | join(' ') }}"
 
 {% if family == 'ice40' %}
-if [ -n "$CONSTRAINTS" ]; then
-  cat $CONSTRAINTS > constraints.pcf
-  CONSTRAINT="--pcf constraints.pcf"
-fi
+{% if constraints %}
+cat $CONSTRAINTS > {{ project }}.pcf
+CONSTRAINT="--pcf {{ project }}.pcf"
+{% endif %}
 $DOCKER hdlc/nextpnr:ice40 /bin/bash -c "
 {% if hooks %}{{ hooks.prepar | join('\n') }}{% endif %}
 nextpnr-ice40 --{{ device }} --package {{ package }} $CONSTRAINT --json {{ project }}.json --asc {{ project }}.asc
@@ -86,10 +86,10 @@ icetime -d {{ device }} -mtr {{ project }}.rpt {{ project }}.asc
 {% endif %}
 
 {% if family == 'ecp5' %}
-if [ -n "$CONSTRAINTS" ]; then
-  cat $CONSTRAINTS > constraints.lpf
-  CONSTRAINT="--lpf constraints.lpf"
-fi
+{% if constraints %}
+cat $CONSTRAINTS > {{ project }}.lpf
+CONSTRAINT="--lpf {{ project }}.lpf"
+{% endif %}
 $DOCKER hdlc/nextpnr:ecp5 /bin/bash -c "
 {% if hooks %}{{ hooks.prepar | join('\n') }}{% endif %}
 nextpnr-ecp5 --{{ device }} --package {{ package }} $CONSTRAINT --json {{ project }}.json --textcfg {{ project }}.config

From e87cde86f3481268fed37bd5dc546c41b4c0f78f Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Thu, 22 Aug 2024 22:49:39 -0300
Subject: [PATCH 205/248] openflow: add missing comments

---
 pyfpga/templates/openflow.jinja | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/pyfpga/templates/openflow.jinja b/pyfpga/templates/openflow.jinja
index 861a0917..088a77dc 100644
--- a/pyfpga/templates/openflow.jinja
+++ b/pyfpga/templates/openflow.jinja
@@ -15,15 +15,15 @@ $DOCKER hdlc/ghdl:yosys /bin/bash -c "
 {% if hooks %}{{ hooks.presyn | join('\n') }}{% endif %}
 yosys -Q -m ghdl -p '
 
-{% if includes %}
+{% if includes %}# Verilog Includes
 verilog_defaults -add{% for path in includes %} -I{{ path }}{% endfor %}
 {% endif %}
 
-{% if defines %}
+{% if defines %}# Verilog Defines
 verilog_defines{% for key, value in defines.items() %} -D{{ key }}={{ value }}{% endfor %}
 {% endif %}
 
-{% if files %}
+{% if files %}# Files inclusion
 {% for name, attr in files.items() %}
 {% if attr.hdl == "vlog" %}
 read_verilog -defer {{ name }}
@@ -33,11 +33,11 @@ read_verilog -defer -sv {{ name }}
 {% endfor %}
 {% endif %}
 
-{% if params %}
+{% if params %}# Verilog Parameters / VHDL Generics
 chparam{% for key, value in params.items() %} -set {{ key }} {{ value }}{% endfor %}
 {% endif %}
 
-{% if top %}
+{% if top %}# Top-level specification
 synth -top {{ top }}
 {% endif %}
 

From 93d1bb08ad455f09f9982341fa5d9e90d8457aa1 Mon Sep 17 00:00:00 2001
From: Benjamin ZIEGLER <Benjamin.Ziegler@urbanandmainlines.com>
Date: Fri, 16 Aug 2024 14:13:11 +0200
Subject: [PATCH 206/248] Print actual data when adding configurations to a
 project

---
 pyfpga/project.py | 23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/pyfpga/project.py b/pyfpga/project.py
index 86d9f267..0b7298b8 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -60,7 +60,7 @@ def set_part(self, name):
         :param name: FPGA part name
         :type name: str
         """
-        self.logger.debug('Executing set_part')
+        self.logger.debug(f'Executing set_part: {name}')
         self.data['part'] = name
 
     def add_include(self, path):
@@ -72,7 +72,7 @@ def add_include(self, path):
         :type name: str
         :raises NotADirectoryError: if path is not a directory
         """
-        self.logger.debug('Executing add_include')
+        self.logger.debug(f'Executing add_include: {path}')
         path = Path(path).resolve()
         if not path.is_dir():
             raise NotADirectoryError(path)
@@ -98,7 +98,7 @@ def add_slog(self, pathname):
         :type pathname: str
         :raises FileNotFoundError: when pathname is not found
         """
-        self.logger.debug('Executing add_slog')
+        self.logger.debug(f'Executing add_slog: {pathname}')
         self._add_file(pathname, 'slog')
 
     def add_vhdl(self, pathname, lib=None):
@@ -110,7 +110,8 @@ def add_vhdl(self, pathname, lib=None):
         :type lib: str, optional
         :raises FileNotFoundError: when pathname is not found
         """
-        self.logger.debug('Executing add_vhdl')
+        lib_str = 'default library' if lib is None else lib
+        self.logger.debug(f'Executing add_vhdl: {lib_str} : {pathname}')
         self._add_file(pathname, 'vhdl', lib)
 
     def add_vlog(self, pathname):
@@ -120,7 +121,7 @@ def add_vlog(self, pathname):
         :type pathname: str
         :raises FileNotFoundError: when pathname is not found
         """
-        self.logger.debug('Executing add_vlog')
+        self.logger.debug(f'Executing add_vlog: {pathname}')
         self._add_file(pathname, 'vlog')
 
     def add_cons(self, path):
@@ -130,7 +131,7 @@ def add_cons(self, path):
         :type pathname: str
         :raises FileNotFoundError: if path is not found
         """
-        self.logger.debug('Executing add_cons')
+        self.logger.debug(f'Executing add_cons: {path}')
         path = Path(path).resolve()
         if not path.is_file():
             raise FileNotFoundError(path)
@@ -145,7 +146,7 @@ def add_param(self, name, value):
         :param value: parameter/generic value
         :type name: str
         """
-        self.logger.debug('Executing add_param')
+        self.logger.debug(f'Executing add_param: {name} : {value}')
         self.data.setdefault('params', {})[name] = value
 
     def add_define(self, name, value):
@@ -156,7 +157,7 @@ def add_define(self, name, value):
         :param value: define value
         :type name: str
         """
-        self.logger.debug('Executing add_define')
+        self.logger.debug(f'Executing add_define: {name} : {value}')
         self.data.setdefault('defines', {})[name] = value
 
     def add_fileset(self, pathname):
@@ -166,7 +167,7 @@ def add_fileset(self, pathname):
         :type pathname: str
         :raises FileNotFoundError: when pathname is not found
         """
-        self.logger.debug('Executing add_fileset')
+        self.logger.debug(f'Executing add_fileset: {pathname}')
         if not os.path.exists(pathname):
             raise FileNotFoundError(pathname)
         raise NotImplementedError()
@@ -177,7 +178,7 @@ def set_top(self, name):
         :param name: top-level name
         :type name: str
         """
-        self.logger.debug('Executing set_top')
+        self.logger.debug(f'Executing set_top: {name}')
         self.data['top'] = name
 
     def add_hook(self, stage, hook):
@@ -191,7 +192,7 @@ def add_hook(self, stage, hook):
         :type hook: str
         :raises ValueError: when stage is invalid
         """
-        self.logger.debug('Executing add_hook')
+        self.logger.debug(f'Executing add_hook: {stage} : {hook}')
         stages = [
             'precfg', 'postcfg', 'presyn', 'postsyn',
             'prepar', 'postpar', 'prebit', 'postbit'

From 1bdbb64fefbe2ad186039aea279dffc58d79b695 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Wed, 28 Aug 2024 22:13:28 -0300
Subject: [PATCH 207/248] Fix linting issue

---
 pyfpga/project.py | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/pyfpga/project.py b/pyfpga/project.py
index 0b7298b8..b6061b0f 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -60,7 +60,7 @@ def set_part(self, name):
         :param name: FPGA part name
         :type name: str
         """
-        self.logger.debug(f'Executing set_part: {name}')
+        self.logger.debug('Executing set_part: %s', name)
         self.data['part'] = name
 
     def add_include(self, path):
@@ -72,7 +72,7 @@ def add_include(self, path):
         :type name: str
         :raises NotADirectoryError: if path is not a directory
         """
-        self.logger.debug(f'Executing add_include: {path}')
+        self.logger.debug('Executing add_include: %s', path)
         path = Path(path).resolve()
         if not path.is_dir():
             raise NotADirectoryError(path)
@@ -98,7 +98,7 @@ def add_slog(self, pathname):
         :type pathname: str
         :raises FileNotFoundError: when pathname is not found
         """
-        self.logger.debug(f'Executing add_slog: {pathname}')
+        self.logger.debug('Executing add_slog: %s', pathname)
         self._add_file(pathname, 'slog')
 
     def add_vhdl(self, pathname, lib=None):
@@ -111,7 +111,7 @@ def add_vhdl(self, pathname, lib=None):
         :raises FileNotFoundError: when pathname is not found
         """
         lib_str = 'default library' if lib is None else lib
-        self.logger.debug(f'Executing add_vhdl: {lib_str} : {pathname}')
+        self.logger.debug('Executing add_vhdl: %s : %s', lib_str, pathname)
         self._add_file(pathname, 'vhdl', lib)
 
     def add_vlog(self, pathname):
@@ -121,7 +121,7 @@ def add_vlog(self, pathname):
         :type pathname: str
         :raises FileNotFoundError: when pathname is not found
         """
-        self.logger.debug(f'Executing add_vlog: {pathname}')
+        self.logger.debug('Executing add_vlog: %s', pathname)
         self._add_file(pathname, 'vlog')
 
     def add_cons(self, path):
@@ -131,7 +131,7 @@ def add_cons(self, path):
         :type pathname: str
         :raises FileNotFoundError: if path is not found
         """
-        self.logger.debug(f'Executing add_cons: {path}')
+        self.logger.debug('Executing add_cons: %s', path)
         path = Path(path).resolve()
         if not path.is_file():
             raise FileNotFoundError(path)
@@ -146,7 +146,7 @@ def add_param(self, name, value):
         :param value: parameter/generic value
         :type name: str
         """
-        self.logger.debug(f'Executing add_param: {name} : {value}')
+        self.logger.debug('Executing add_param: %s : %s', name, value)
         self.data.setdefault('params', {})[name] = value
 
     def add_define(self, name, value):
@@ -157,7 +157,7 @@ def add_define(self, name, value):
         :param value: define value
         :type name: str
         """
-        self.logger.debug(f'Executing add_define: {name} : {value}')
+        self.logger.debug('Executing add_define: %s : %s', name, value)
         self.data.setdefault('defines', {})[name] = value
 
     def add_fileset(self, pathname):
@@ -167,7 +167,7 @@ def add_fileset(self, pathname):
         :type pathname: str
         :raises FileNotFoundError: when pathname is not found
         """
-        self.logger.debug(f'Executing add_fileset: {pathname}')
+        self.logger.debug('Executing add_fileset: %s', pathname)
         if not os.path.exists(pathname):
             raise FileNotFoundError(pathname)
         raise NotImplementedError()
@@ -178,7 +178,7 @@ def set_top(self, name):
         :param name: top-level name
         :type name: str
         """
-        self.logger.debug(f'Executing set_top: {name}')
+        self.logger.debug('Executing set_top: %s', name)
         self.data['top'] = name
 
     def add_hook(self, stage, hook):
@@ -192,7 +192,7 @@ def add_hook(self, stage, hook):
         :type hook: str
         :raises ValueError: when stage is invalid
         """
-        self.logger.debug(f'Executing add_hook: {stage} : {hook}')
+        self.logger.debug('Executing add_hook: %s : %s', stage, hook)
         stages = [
             'precfg', 'postcfg', 'presyn', 'postsyn',
             'prepar', 'postpar', 'prebit', 'postbit'

From d584bce2894632bf6c6739be408b4467eccd1cf3 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Fri, 30 Aug 2024 19:04:20 -0300
Subject: [PATCH 208/248] docs: add generation timestamp

---
 docs/index.rst | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/docs/index.rst b/docs/index.rst
index 3e8dfcb0..685e7ac0 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -16,3 +16,9 @@ PyFPGA's documentation
    tools
    internals
    extending
+
+.. |timestamp| date:: %Y-%m-%d %H:%M (%Z)
+
+.. note::
+
+   Documentation generated on |timestamp|.

From d866f8bcf0a9be8e254abc2fa2f097fecb43d805 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Fri, 30 Aug 2024 20:11:04 -0300
Subject: [PATCH 209/248] openflow: re-added Synthesis for Xilinx devices

---
 pyfpga/templates/openflow.jinja | 33 +++++++++++----------------------
 1 file changed, 11 insertions(+), 22 deletions(-)

diff --git a/pyfpga/templates/openflow.jinja b/pyfpga/templates/openflow.jinja
index 088a77dc..a77a25fd 100644
--- a/pyfpga/templates/openflow.jinja
+++ b/pyfpga/templates/openflow.jinja
@@ -37,35 +37,24 @@ read_verilog -defer -sv {{ name }}
 chparam{% for key, value in params.items() %} -set {{ key }} {{ value }}{% endfor %}
 {% endif %}
 
-{% if top %}# Top-level specification
+# Top-level specification and Syntesis
+{% if family in ['ice40', 'ecp5'] %}
+synth_{{ family }} -top {{ top }} -json {{ project }}.json
+{% elif family in ['xc6s', 'xc6v', 'xc5v', 'xc4v', 'xc3sda', 'xc3sa', 'xc3se', 'xc3s', 'xc2vp', 'xc2v', 'xcve', 'xcv'] %}
+synth_xilinx -top {{ top }} -family {{ family }}
+write_edif -pvector bra {{ project }}.edif -ise
+{% elif family %}
+synth_xilinx -top {{ top }} -family {{ family }}
+write_edif -pvector bra {{ project }}.edif
+{% else %}
 synth -top {{ top }}
+write_verilog {{ project }}.v
 {% endif %}
-
-synth_{{ family }} -top {{ top }} -json {{ project }}.json
 '
 {% if hooks %}{{ hooks.postsyn | join('\n') }}{% endif %}
 "
 {% endif %}
 
-{#
-#SYNTH=
-#WRITE=
-#if [[ $BACKEND == "vivado" ]]; then
-#    SYNTH="synth_xilinx -top $TOP -family $FAMILY"
-#    WRITE="write_edif -pvector bra $PROJECT.edif"
-#elif [[ $BACKEND == "ise" ]]; then
-#    SYNTH="synth_xilinx -top $TOP -family $FAMILY -ise"
-#    WRITE="write_edif -pvector bra $PROJECT.edif"
-#elif [[ $BACKEND == "nextpnr" ]]; then
-#    SYNTH="synth_$FAMILY -top $TOP -json $PROJECT.json"
-#elif [[ $BACKEND == "verilog-nosynth" ]]; then
-#    WRITE="write_verilog $PROJECT.v"
-#else
-#    SYNTH="synth -top $TOP"
-#    WRITE="write_verilog $PROJECT.v"
-#fi
-#}
-
 {% if 'par' in steps %}# Place and Route
 
 CONSTRAINTS="{{ constraints | join(' ') }}"

From 5ae1a819a4e66d5f1948f196ee40cc7e44d4bc4e Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Fri, 30 Aug 2024 20:21:33 -0300
Subject: [PATCH 210/248] Added Diamond into regress.sh

---
 examples/projects/regress.sh | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/examples/projects/regress.sh b/examples/projects/regress.sh
index 6af2f12b..22c8f9e8 100644
--- a/examples/projects/regress.sh
+++ b/examples/projects/regress.sh
@@ -4,6 +4,7 @@ set -e
 
 declare -A TOOLS
 
+TOOLS["diamond"]="brevia2"
 TOOLS["ise"]="s6micro nexys3"
 TOOLS["libero"]="maker"
 TOOLS["openflow"]="icestick edu-ciaa orangecrab ecp5evn"
@@ -19,7 +20,7 @@ for TOOL in "${!TOOLS[@]}"; do
       if [[ "$TOOL" == "ise" && "$SOURCE" == "slog" ]]; then
         continue
       fi
-      if [[ "$TOOL" == "openflow" && "$SOURCE" != "vlog" ]]; then
+      if [[ "$TOOL" == "openflow" && "$SOURCE" == "vhdl" ]]; then
         continue
       fi
       echo "> $TOOL - $BOARD - $SOURCE"

From 024a89a29a01ebc8a7d44553e7bce68e99ad0efe Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Fri, 30 Aug 2024 20:23:05 -0300
Subject: [PATCH 211/248] examples: modify output directory of projects

---
 examples/projects/diamond.py  | 2 +-
 examples/projects/ise.py      | 3 ++-
 examples/projects/libero.py   | 2 +-
 examples/projects/openflow.py | 3 ++-
 examples/projects/quartus.py  | 3 ++-
 examples/projects/vivado.py   | 3 ++-
 6 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/examples/projects/diamond.py b/examples/projects/diamond.py
index 4f5a85de..0128d7c3 100644
--- a/examples/projects/diamond.py
+++ b/examples/projects/diamond.py
@@ -17,7 +17,7 @@
 )
 args = parser.parse_args()
 
-prj = Diamond(odir='../build/diamond')
+prj = Diamond(odir=f'results/diamond/{args.source}/{args.board}')
 
 if args.board == 'brevia2':
     prj.set_part('LFXP2-5E-5TN144C')
diff --git a/examples/projects/ise.py b/examples/projects/ise.py
index 38d886c1..279a5db0 100644
--- a/examples/projects/ise.py
+++ b/examples/projects/ise.py
@@ -17,7 +17,7 @@
 )
 args = parser.parse_args()
 
-prj = Ise(odir='../build/ise')
+prj = Ise(odir=f'results/ise/{args.source}/{args.board}')
 
 if args.board == 's6micro':
     prj.set_part('xc6slx9-2-csg324')
@@ -35,6 +35,7 @@
 
 if args.source == 'vhdl':
     prj.add_vhdl('../sources/vhdl/*.vhdl', 'blink_lib')
+    prj.add_vhdl('../sources/vhdl/top.vhdl')
 if args.source == 'vlog':
     prj.add_include('../sources/vlog/include1')
     prj.add_include('../sources/vlog/include2')
diff --git a/examples/projects/libero.py b/examples/projects/libero.py
index 4edd978e..dd2c5861 100644
--- a/examples/projects/libero.py
+++ b/examples/projects/libero.py
@@ -16,7 +16,7 @@
 )
 args = parser.parse_args()
 
-prj = Libero(odir='../build/libero')
+prj = Libero(odir=f'results/libero/{args.source}/{args.board}')
 
 if args.board == 'maker':
     prj.set_part('m2s010-1-tq144')
diff --git a/examples/projects/openflow.py b/examples/projects/openflow.py
index 0b1242b3..56a6b2ab 100644
--- a/examples/projects/openflow.py
+++ b/examples/projects/openflow.py
@@ -18,7 +18,7 @@
 )
 args = parser.parse_args()
 
-prj = Openflow(odir='../build/openflow')
+prj = Openflow(odir=f'results/openflow/{args.source}/{args.board}')
 
 if args.board == 'icestick':
     prj.set_part('hx1k-tq144')
@@ -44,6 +44,7 @@
 
 if args.source == 'vhdl':
     prj.add_vhdl('../sources/vhdl/*.vhdl', 'blink_lib')
+    prj.add_vhdl('../sources/vhdl/top.vhdl')
 if args.source == 'vlog':
     prj.add_include('../sources/vlog/include1')
     prj.add_include('../sources/vlog/include2')
diff --git a/examples/projects/quartus.py b/examples/projects/quartus.py
index 02ed76d3..eb7e889e 100644
--- a/examples/projects/quartus.py
+++ b/examples/projects/quartus.py
@@ -17,7 +17,7 @@
 )
 args = parser.parse_args()
 
-prj = Quartus(odir='../build/quartus')
+prj = Quartus(odir=f'results/quartus/{args.source}/{args.board}')
 
 if args.board == 'de10nano':
     prj.set_part('5CSEBA6U23I7')
@@ -29,6 +29,7 @@
 
 if args.source == 'vhdl':
     prj.add_vhdl('../sources/vhdl/*.vhdl', 'blink_lib')
+    prj.add_vhdl('../sources/vhdl/top.vhdl')
 if args.source == 'vlog':
     prj.add_include('../sources/vlog/include1')
     prj.add_include('../sources/vlog/include2')
diff --git a/examples/projects/vivado.py b/examples/projects/vivado.py
index 35ccecc7..af497b91 100644
--- a/examples/projects/vivado.py
+++ b/examples/projects/vivado.py
@@ -17,7 +17,7 @@
 )
 args = parser.parse_args()
 
-prj = Vivado(odir='../build/vivado')
+prj = Vivado(odir=f'results/vivado/{args.source}/{args.board}')
 
 if args.board == 'zybo':
     prj.set_part('xc7z010-1-clg400')
@@ -35,6 +35,7 @@
 
 if args.source == 'vhdl':
     prj.add_vhdl('../sources/vhdl/*.vhdl', 'blink_lib')
+    prj.add_vhdl('../sources/vhdl/top.vhdl')
 if args.source == 'vlog':
     prj.add_include('../sources/vlog/include1')
     prj.add_include('../sources/vlog/include2')

From e63851de95b1dc13e4a7c5a7786e0506f979e25d Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Fri, 30 Aug 2024 20:27:22 -0300
Subject: [PATCH 212/248] examples: remove odir specification in diamond
 (hooks)

---
 examples/hooks/diamond.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/examples/hooks/diamond.py b/examples/hooks/diamond.py
index 389b9a60..ce4f3558 100644
--- a/examples/hooks/diamond.py
+++ b/examples/hooks/diamond.py
@@ -1,8 +1,8 @@
-"""Diamond example hooks."""
+"""Diamond hooks examples."""
 
 from pyfpga.diamond import Diamond
 
-prj = Diamond(odir='../build/diamond')
+prj = Diamond()
 
 hooks = {
     "reports": """

From 0d95e0178f22262f5cfb3a818060a83711a70085 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Fri, 30 Aug 2024 21:16:56 -0300
Subject: [PATCH 213/248] Add to remove the results directories

---
 Makefile | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index fb528da7..88a8c3da 100644
--- a/Makefile
+++ b/Makefile
@@ -16,7 +16,9 @@ test:
 clean:
 	py3clean .
 	cd docs; make clean
-	rm -fr build .pytest_cache
+	rm -fr .pytest_cache
+	rm -fr `find . -name results`
+	rm -fr `find . -name __pycache__`
 
 submodule-init:
 	git submodule update --init --recursive

From 99f235e3711c8b1b96defb2f6b3cb89978b563ab Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Fri, 30 Aug 2024 21:24:59 -0300
Subject: [PATCH 214/248] docs: minor changes in the generation

---
 .github/workflows/docs.yml          |   2 +-
 docs/Makefile                       |   2 +-
 docs/conf.py                        |   8 ++++----
 docs/helpers.rst                    |   6 +++---
 docs/{_static => images}/logo.png   | Bin
 docs/{_static => images}/schema.png | Bin
 docs/index.rst                      |   2 +-
 7 files changed, 10 insertions(+), 10 deletions(-)
 rename docs/{_static => images}/logo.png (100%)
 rename docs/{_static => images}/schema.png (100%)

diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 0f17d958..85963a48 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -19,4 +19,4 @@ jobs:
       uses: peaceiris/actions-gh-pages@v4
       with:
         github_token: ${{ secrets.GITHUB_TOKEN }}
-        publish_dir: docs/_build/html
+        publish_dir: docs/build/html
diff --git a/docs/Makefile b/docs/Makefile
index a9325d75..13352008 100644
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -1,7 +1,7 @@
 SPHINXOPTS    ?=
 SPHINXBUILD   ?= sphinx-build
 SOURCEDIR     = .
-BUILDDIR      = _build
+BUILDDIR      = build
 HELPERS       = $(BUILDDIR)/hdl2bit $(BUILDDIR)/prj2bit $(BUILDDIR)/bitprog
 
 help:
diff --git a/docs/conf.py b/docs/conf.py
index 3e57d268..530ce742 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -8,8 +8,8 @@
 # -- Project information -----------------------------------------------------
 
 project = 'PyFPGA'
-copyright = '2024, Rodrigo Alejandro Melo'
-author = 'Rodrigo Alejandro Melo'
+copyright = '2016-2024, PyFPGA Project'
+author = 'PyFPGA contributors'
 
 # -- General configuration ---------------------------------------------------
 
@@ -31,9 +31,9 @@
    'repositoy': ('https://github.com/PyFPGA/pyfpga/tree/main/%s', None)
 }
 
-exclude_patterns = ['_build', 'wip']
+exclude_patterns = ['build']
 
 # -- Options for HTML output -------------------------------------------------
 
 html_theme = 'sphinx_rtd_theme'
-html_static_path = ['_static']
+html_static_path = ['images']
diff --git a/docs/helpers.rst b/docs/helpers.rst
index 542deb27..619f2c35 100644
--- a/docs/helpers.rst
+++ b/docs/helpers.rst
@@ -4,14 +4,14 @@ Helpers
 hdl2bit
 -------
 
-.. literalinclude:: _build/hdl2bit
+.. literalinclude:: build/hdl2bit
 
 prj2bit
 -------
 
-.. literalinclude:: _build/prj2bit
+.. literalinclude:: build/prj2bit
 
 bitprog
 -------
 
-.. literalinclude:: _build/bitprog
+.. literalinclude:: build/bitprog
diff --git a/docs/_static/logo.png b/docs/images/logo.png
similarity index 100%
rename from docs/_static/logo.png
rename to docs/images/logo.png
diff --git a/docs/_static/schema.png b/docs/images/schema.png
similarity index 100%
rename from docs/_static/schema.png
rename to docs/images/schema.png
diff --git a/docs/index.rst b/docs/index.rst
index 685e7ac0..3bfdf197 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -1,7 +1,7 @@
 PyFPGA's documentation
 ======================
 
-.. image:: _static/logo.png
+.. image:: images/logo.png
    :width: 200 px
    :align: center
    :target: https://github.com/PyFPGA/pyfpga

From 7fc1ab9017328b405841ccc704273f47484a5461 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Fri, 30 Aug 2024 21:57:42 -0300
Subject: [PATCH 215/248] Removed an unneeded comment

---
 pyfpga/templates/libero.jinja | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pyfpga/templates/libero.jinja b/pyfpga/templates/libero.jinja
index aaddbf9b..c64d8a5d 100644
--- a/pyfpga/templates/libero.jinja
+++ b/pyfpga/templates/libero.jinja
@@ -14,7 +14,7 @@ set_device -family {{ family }} -die {{ device }} -package {{ package }} -speed
 
 {% if hooks %}{{ hooks.precfg | join('\n') }}{% endif %}
 
-{% if includes %}# Verilog Includes (Libero)
+{% if includes %}# Verilog Includes
 set_global_include_path_order -paths "{{ includes | join(' ') }}"
 {% endif %}
 

From ed36eaddd0daad22cbb401b64b689089604932b9 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 31 Aug 2024 08:41:17 -0300
Subject: [PATCH 216/248] tests: moved from projects/support.py to simply
 support.py

---
 tests/{projects => }/support.py | 40 ++++++++++++++++-----------------
 1 file changed, 20 insertions(+), 20 deletions(-)
 rename tests/{projects => }/support.py (70%)

diff --git a/tests/projects/support.py b/tests/support.py
similarity index 70%
rename from tests/projects/support.py
rename to tests/support.py
index 68bc88b1..128a17c5 100644
--- a/tests/projects/support.py
+++ b/tests/support.py
@@ -17,16 +17,16 @@
 
 print('INFO: checking basic Verilog Support')
 prj = Factory(args.tool)
-prj.add_vlog('../../examples/sources/vlog/blink.v')
+prj.add_vlog('../examples/sources/vlog/blink.v')
 prj.set_top('Blink')
 prj.make(last='syn')
 
 print('INFO: checking advanced Verilog Support')
 prj = Factory(args.tool)
-prj.add_vlog('../../examples/sources/vlog/*.v')
+prj.add_vlog('../examples/sources/vlog/*.v')
 prj.set_top('Top')
-prj.add_include('../../examples/sources/vlog/include1')
-prj.add_include('../../examples/sources/vlog/include2')
+prj.add_include('../examples/sources/vlog/include1')
+prj.add_include('../examples/sources/vlog/include2')
 prj.add_define('DEFINE1', '1')
 prj.add_define('DEFINE2', '1')
 prj.add_param('FREQ', '1')
@@ -36,7 +36,7 @@
 try:
     print('INFO: checking Verilog Includes Support')
     prj = Factory(args.tool)
-    prj.add_vlog('../../examples/sources/vlog/*.v')
+    prj.add_vlog('../examples/sources/vlog/*.v')
     prj.set_top('Top')
     prj.add_define('DEFINE1', '1')
     prj.add_define('DEFINE2', '1')
@@ -52,10 +52,10 @@
 try:
     print('INFO: checking Verilog Defines Support')
     prj = Factory(args.tool)
-    prj.add_vlog('../../examples/sources/vlog/*.v')
+    prj.add_vlog('../examples/sources/vlog/*.v')
     prj.set_top('Top')
-    prj.add_include('../../examples/sources/vlog/include1')
-    prj.add_include('../../examples/sources/vlog/include2')
+    prj.add_include('../examples/sources/vlog/include1')
+    prj.add_include('../examples/sources/vlog/include2')
     prj.add_param('FREQ', '1')
     prj.add_param('SECS', '1')
     prj.make(last='syn')
@@ -68,10 +68,10 @@
 try:
     print('INFO: checking Verilog Parameters Support')
     prj = Factory(args.tool)
-    prj.add_vlog('../../examples/sources/vlog/*.v')
+    prj.add_vlog('../examples/sources/vlog/*.v')
     prj.set_top('Top')
-    prj.add_include('../../examples/sources/vlog/include1')
-    prj.add_include('../../examples/sources/vlog/include2')
+    prj.add_include('../examples/sources/vlog/include1')
+    prj.add_include('../examples/sources/vlog/include2')
     prj.add_define('DEFINE1', '1')
     prj.add_define('DEFINE2', '1')
     prj.make(last='syn')
@@ -84,16 +84,16 @@
 if args.tool not in ['ise']:
     print('INFO: checking basic System Verilog Support')
     prj = Factory(args.tool)
-    prj.add_slog('../../examples/sources/slog/blink.sv')
+    prj.add_slog('../examples/sources/slog/blink.sv')
     prj.set_top('Blink')
     prj.make(last='syn')
 
     print('INFO: checking advanced System Verilog Support')
     prj = Factory(args.tool)
-    prj.add_slog('../../examples/sources/slog/*.sv')
+    prj.add_slog('../examples/sources/slog/*.sv')
     prj.set_top('Top')
-    prj.add_include('../../examples/sources/slog/include1')
-    prj.add_include('../../examples/sources/slog/include2')
+    prj.add_include('../examples/sources/slog/include1')
+    prj.add_include('../examples/sources/slog/include2')
     prj.add_define('DEFINE1', '1')
     prj.add_define('DEFINE2', '1')
     prj.add_param('FREQ', '1')
@@ -103,14 +103,14 @@
 if args.tool not in ['openflow']:
     print('* INFO: checking basic VHDL Support')
     prj = Factory(args.tool)
-    prj.add_vhdl('../../examples/sources/vhdl/blink.vhdl')
+    prj.add_vhdl('../examples/sources/vhdl/blink.vhdl')
     prj.set_top('Blink')
     prj.make(last='syn')
 
     print('* INFO: checking advanced VHDL Support')
     prj = Factory(args.tool)
-    prj.add_vhdl('../../examples/sources/vhdl/*.vhdl', 'blink_lib')
-    prj.add_vhdl('../../examples/sources/vhdl/top.vhdl')
+    prj.add_vhdl('../examples/sources/vhdl/*.vhdl', 'blink_lib')
+    prj.add_vhdl('../examples/sources/vhdl/top.vhdl')
     prj.set_top('Top')
     prj.add_param('FREQ', '1')
     prj.add_param('SECS', '1')
@@ -119,8 +119,8 @@
     try:
         print('INFO: checking VHDL Generics')
         prj = Factory(args.tool)
-        prj.add_vhdl('../../examples/sources/vhdl/*.vhdl', 'blink_lib')
-        prj.add_vhdl('../../examples/sources/vhdl/top.vhdl')
+        prj.add_vhdl('../examples/sources/vhdl/*.vhdl', 'blink_lib')
+        prj.add_vhdl('../examples/sources/vhdl/top.vhdl')
         prj.set_top('Top')
         prj.make(last='syn')
         sys.exit('ERROR: something does not work as expected')

From 9188bd8f795af65458f6a380f0d5f012d5212ee9 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 31 Aug 2024 09:04:30 -0300
Subject: [PATCH 217/248] Add to specify the tool to run in regress.sh

---
 examples/projects/regress.sh | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/examples/projects/regress.sh b/examples/projects/regress.sh
index 22c8f9e8..be6219a0 100644
--- a/examples/projects/regress.sh
+++ b/examples/projects/regress.sh
@@ -13,7 +13,12 @@ TOOLS["vivado"]="zybo arty"
 
 SOURCES=("vlog" "vhdl" "slog")
 
+SPECIFIED_TOOL=$1
+
 for TOOL in "${!TOOLS[@]}"; do
+  if [[ -n "$SPECIFIED_TOOL" && "$TOOL" != "$SPECIFIED_TOOL" ]]; then
+    continue
+  fi
   BOARDS=${TOOLS[$TOOL]}
   for BOARD in $BOARDS; do
     for SOURCE in "${SOURCES[@]}"; do

From f203de16cc71fae6a6307f3eb159517589607d81 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 31 Aug 2024 09:05:23 -0300
Subject: [PATCH 218/248] Removed unused targets and added all

---
 Makefile | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/Makefile b/Makefile
index 88a8c3da..892fdcb4 100644
--- a/Makefile
+++ b/Makefile
@@ -2,6 +2,8 @@
 
 .PHONY: docs
 
+all: docs lint test
+
 docs:
 	cd docs; make html
 
@@ -19,9 +21,3 @@ clean:
 	rm -fr .pytest_cache
 	rm -fr `find . -name results`
 	rm -fr `find . -name __pycache__`
-
-submodule-init:
-	git submodule update --init --recursive
-
-submodule-update:
-	cd examples/resources; git checkout main; git pull

From a4ffd5df78f53fdb96276e695c194e8f25ceda1d Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 31 Aug 2024 09:11:07 -0300
Subject: [PATCH 219/248] docs: improve the extending section

---
 docs/extending.rst | 76 ++++++++++++++++++++++++++++++++++------------
 1 file changed, 56 insertions(+), 20 deletions(-)

diff --git a/docs/extending.rst b/docs/extending.rst
index 03c995cf..18956259 100644
--- a/docs/extending.rst
+++ b/docs/extending.rst
@@ -1,40 +1,76 @@
 Extending
 =========
 
-1. Add support for the new tool:
+.. note::
 
-.. code-block:: python
+   All <TOOL> classes inherit from project.py.
+
+This is a guide on how to add support for a new TOOL.
+
+Add support for the new tool
+----------------------------
+
+.. code-block:: bash
 
    pyfpga/templates/<NEWTOOL>.jinja
    pyfpga/templates/<NEWTOOL>-prog.jinja
    pyfpga/<NEWTOOL>.py
+   pyfpga/factory.py # UPDATE
+   pyfpga/helpers/prj2bit.py # UPDATE
 
-2. Include the new tool on Factory:
+Add tests and a tool mock-up
+----------------------------
 
-.. code-block:: python
+.. code-block:: bash
 
-   pyfpga/factory.py
+   tests/test_tools.py # UPDATE
+   tests/support.py # UPDATE if exceptions are needed
+   tests/mocks/<NEWCOMMAND>
 
-3. Add tests and a tool mock-up:
+Add examples
+------------
 
-.. code-block:: python
+.. code-block:: bash
 
-   tests/test_tools.py
-   tests/mocks/<NEWTOOL_EXECUTABLE>
+   examples/sources/cons/<NEWBOARD>/timing.<EXT>
+   examples/sources/cons/<NEWBOARD>/clk.<EXT>
+   examples/sources/cons/<NEWBOARD>/led.<EXT>
+   examples/projects/<NEWTOOL>.py
+   examples/projects/regress.sh # UPDATE
+   examples/helpers/<NEWTOOL>.sh
+   examples/hooks/<NEWTOOL>.py # OPTIONAL
 
-4. Updated the project's documentation:
+Verify the code
+---------------
 
-.. code-block:: python
+Run it at the root of the repo.
 
-   README.md
-   docs
+.. code-block:: bash
 
-5. [OPTIONAL] Add examples:
+   make docs
+   make lint
+   make test
 
-.. code-block:: python
+.. tip::
 
-   examples/sources/cons/<NEWBOARD>/timing.<EXT>
-   examples/sources/cons/<NEWBOARD>/clk.<EXT>
-   examples/sources/cons/<NEWBOARD>/led.<EXT>
-   examples/projects/<NEWTOOL>.py
-   examples/hooks/<NEWTOOL>.py
+   You can simply run ``make`` to perform all the operations.
+   Running ``make clean`` will remove all the generated files.
+
+Verify the functionality
+------------------------
+
+.. code-block:: bash
+
+   cd examples/projects/
+   bash regress.sh <NEWTOOL>
+   cd ../../tests/
+   python3 support.py --tool <NEWTOOL>
+
+Updated the documentation
+-------------------------
+
+.. code-block:: bash
+
+   README.md
+   docs/intro.rst
+   docs/tools.rst

From 8f7e89a4a554714ce1089765c94bb9469f3f1f12 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 31 Aug 2024 09:29:59 -0300
Subject: [PATCH 220/248] examples: renamed yosys as misc

---
 examples/{yosys/ise.py => misc/yosys-ise.py}       | 0
 examples/{yosys/vivado.py => misc/yosys-vivado.py} | 0
 2 files changed, 0 insertions(+), 0 deletions(-)
 rename examples/{yosys/ise.py => misc/yosys-ise.py} (100%)
 rename examples/{yosys/vivado.py => misc/yosys-vivado.py} (100%)

diff --git a/examples/yosys/ise.py b/examples/misc/yosys-ise.py
similarity index 100%
rename from examples/yosys/ise.py
rename to examples/misc/yosys-ise.py
diff --git a/examples/yosys/vivado.py b/examples/misc/yosys-vivado.py
similarity index 100%
rename from examples/yosys/vivado.py
rename to examples/misc/yosys-vivado.py

From 578ee491c9cb75949ec563b449521bdcb7804fa8 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 31 Aug 2024 09:31:10 -0300
Subject: [PATCH 221/248] examples: update/simplify README.md

---
 examples/README.md | 60 +++++++---------------------------------------
 1 file changed, 8 insertions(+), 52 deletions(-)

diff --git a/examples/README.md b/examples/README.md
index e648ca00..2ec68b5e 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -1,55 +1,11 @@
-# PyFPGA examples
+# PyFPGA Examples
 
-## Tool-specific examples
+In this section, you will find:
 
-Led blinking examples where a Bitstream is generated and transfer to a
-supported board. It shows the inclusion of Constraints files.
+* `projects`: basic but complete examples for each supported tool.
+* `helpers`: examples of the PyFPGA helpers.
+* `hooks`: how to use this feature.
+* `misc`: miscellaneous examples.
 
-* [ghdl](ghdl): VHDL synthesis with GDHL (`--synth`)
-* [ise](ise): Spartan-6 FPGA LX9 MicroBoard (Avnet)
-* [libero](libero): Digi-Key SmartFusion2 Maker Board (Digi-Key)
-* [openflow](openflow):
-  * IceStick (`icestorm.py`)
-  * EDU-CIAA-FPGA (`icestorm.py --board edu-ciaa-fpga`)
-  * OrangeCrab-r0.2 (`prjtrellis.py`)
-  * ECP5 Evaluation Board (`prjtrellis.py --board ecp5evn`)
-* [quartus](quartus): DE10Nano (Terasic)
-* [vivado](vivado): Zybo (Digilent)
-* [yosys](yosys):
-  * Verilog synthesis with Yosys (using `ghdl-yosys-plugin` for VHDL)
-  * Spartan-6 FPGA LX9 MicroBoard (`ise.py`)
-  * Zybo (`vivado.py`)
-
-## Multi-project examples
-
-Examples where more than a project is solved in the same script.
-
-* [multi/projects.py](multi/projects.py): it uses a dict with three project
-names where different tools, part names, files and top-level names can be
-specified. In this manner, you can manage alternatives or sub-products of your
-design in a single place.
-* [multi/verilog.py](multi/verilog.py): here the same set of Verilog files are
-synthesised with all the available tools, which is useful to make comparations
-and check portability.
-* [multi/vhdl.py](multi/vhdl.py): the same concept that the previous one, but
-using VHDL instead of Verilog files. The main difference is how to deal with
-VHDL libraries.
-* [multi/parameters.py](multi/parameters.py): VHDL and Verilog files are
-synthesized changing the value of its generics/parameters.
-* [multi/memory.py](multi/memory.py): it tests the Memory Content Files
-inclusion capability of the supported tools.
-
-## Hooks examples
-
-* [hooks/strategies.py](hooks/strategies.py): the same HDL is synthesized by
-different tools, changing the optimization strategy (`area`, `power` and
-`speed`).
-
-## Helpers
-
-Examples to exercise developed helper tools such as `hdl2bit`, `prj2bit` and
-`bitprog`.
-
-## Miscellaneous examples
-
-* [misc/capture.py](misc/capture.py): it shows how to capture the execution messages.
+For an example where all the tools are employed based on the same code, you can check
+[support.py](../tests/support.py) (located under the [tests](../tests) directory).

From fbf80e0b1834f861fc836eb4e132184071de1c2f Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 31 Aug 2024 10:08:55 -0300
Subject: [PATCH 222/248] diamondc: removed unused import

---
 tests/mocks/diamondc | 1 -
 1 file changed, 1 deletion(-)

diff --git a/tests/mocks/diamondc b/tests/mocks/diamondc
index 1beac9c1..50303cb3 100755
--- a/tests/mocks/diamondc
+++ b/tests/mocks/diamondc
@@ -8,7 +8,6 @@
 
 import argparse
 import subprocess
-import sys
 
 
 parser = argparse.ArgumentParser()

From 884fda8490a2b9e2d9e69b5ab7e983868f2688d4 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 31 Aug 2024 10:09:33 -0300
Subject: [PATCH 223/248] Simplified how to clean docs

---
 Makefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 892fdcb4..2f2402c4 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@ test:
 
 clean:
 	py3clean .
-	cd docs; make clean
+	rm -fr docs/build
 	rm -fr .pytest_cache
 	rm -fr `find . -name results`
 	rm -fr `find . -name __pycache__`

From 7851b97872258d7728f6be271b6f83f21ca420a5 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 31 Aug 2024 10:25:45 -0300
Subject: [PATCH 224/248] ci: modified when to trigger the docs actions

---
 .github/workflows/docs.yml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 85963a48..1db219c9 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -2,6 +2,8 @@ name: 'docs'
 
 on:
   push:
+    paths:
+      - 'docs/**'
     branches:
 #      - main
 

From c7e5369def5d4fb26dfcee20ca5f7b33dea40177 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 31 Aug 2024 13:21:24 -0300
Subject: [PATCH 225/248] openflow: re-added VHDL support (WIP)

---
 pyfpga/templates/openflow.jinja | 21 ++++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/pyfpga/templates/openflow.jinja b/pyfpga/templates/openflow.jinja
index a77a25fd..b5b6d96c 100644
--- a/pyfpga/templates/openflow.jinja
+++ b/pyfpga/templates/openflow.jinja
@@ -13,6 +13,17 @@ DOCKER="docker run --user $(id -u):$(id -g) --rm -v $HOME:$HOME -w $PWD"
 {% if 'syn' in steps %}# Synthesis
 $DOCKER hdlc/ghdl:yosys /bin/bash -c "
 {% if hooks %}{{ hooks.presyn | join('\n') }}{% endif %}
+
+{% set gflags = '--std=08 -fsynopsys -fexplicit -frelaxed' %}
+{% if files %}# Files inclusion
+{% for name, attr in files.items() %}
+{% if attr.hdl == "vhdl" %}
+ghdl -a {{ gflags }}{% if 'lib' in attr %} --work={{ attr.lib }}{% endif %} {{ name }}
+{% endif %}
+{% endfor %}
+{% endif %}
+ghdl -a --std=08 -fsynopsys -fexplicit -frelaxed /home/rodrigo/repos-ram/PyFPGA/pyfpga/examples/sources/vhdl/top.vhdl
+
 yosys -Q -m ghdl -p '
 
 {% if includes %}# Verilog Includes
@@ -29,13 +40,21 @@ verilog_defines{% for key, value in defines.items() %} -D{{ key }}={{ value }}{%
 read_verilog -defer {{ name }}
 {% elif attr.hdl == "slog" %}
 read_verilog -defer -sv {{ name }}
+{% elif attr.hdl == "vhdl" %}
+{% if loop.first %}
+# VHDL Generics
+{% set generics = "-gFREQ=125000000 -gSECS=1" %}
+ghdl {{ gflags }} {{ generics }} {{ top }}
+{% endif %}
 {% endif %}
 {% endfor %}
 {% endif %}
 
-{% if params %}# Verilog Parameters / VHDL Generics
+{#
+{% if params %}# Verilog Parameters
 chparam{% for key, value in params.items() %} -set {{ key }} {{ value }}{% endfor %}
 {% endif %}
+#}
 
 # Top-level specification and Syntesis
 {% if family in ['ice40', 'ecp5'] %}

From 01991d7a0fe600b778b20545015dad3e99bee740 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 31 Aug 2024 13:36:01 -0300
Subject: [PATCH 226/248] openflow: add generics support

---
 pyfpga/templates/openflow.jinja | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/pyfpga/templates/openflow.jinja b/pyfpga/templates/openflow.jinja
index b5b6d96c..a0c18dd6 100644
--- a/pyfpga/templates/openflow.jinja
+++ b/pyfpga/templates/openflow.jinja
@@ -42,19 +42,18 @@ read_verilog -defer {{ name }}
 read_verilog -defer -sv {{ name }}
 {% elif attr.hdl == "vhdl" %}
 {% if loop.first %}
-# VHDL Generics
-{% set generics = "-gFREQ=125000000 -gSECS=1" %}
-ghdl {{ gflags }} {{ generics }} {{ top }}
+{% if params %}# VHDL Generics
+ghdl {{ gflags }}{% for key, value in params.items() %} -g{{ key }}={{ value }}{% endfor %} {{ top }}
+{% else %}
+ghdl {{ gflags }} {{ top }}
 {% endif %}
 {% endif %}
-{% endfor %}
 {% endif %}
-
-{#
-{% if params %}# Verilog Parameters
+{% if loop.last and attr.hdl in ["vlog", "slog"] and params %}# Verilog Parameters
 chparam{% for key, value in params.items() %} -set {{ key }} {{ value }}{% endfor %}
 {% endif %}
-#}
+{% endfor %}
+{% endif %}
 
 # Top-level specification and Syntesis
 {% if family in ['ice40', 'ecp5'] %}

From 2864ced35c7468daa0c803185db6b2d9e4770f0c Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 2 Sep 2024 19:38:14 -0300
Subject: [PATCH 227/248] openflow: properly re-added VHDL support

Closes #51
---
 examples/projects/regress.sh    | 3 ---
 pyfpga/project.py               | 6 ++++--
 pyfpga/templates/openflow.jinja | 5 ++---
 3 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/examples/projects/regress.sh b/examples/projects/regress.sh
index be6219a0..45b7d848 100644
--- a/examples/projects/regress.sh
+++ b/examples/projects/regress.sh
@@ -25,9 +25,6 @@ for TOOL in "${!TOOLS[@]}"; do
       if [[ "$TOOL" == "ise" && "$SOURCE" == "slog" ]]; then
         continue
       fi
-      if [[ "$TOOL" == "openflow" && "$SOURCE" == "vhdl" ]]; then
-        continue
-      fi
       echo "> $TOOL - $BOARD - $SOURCE"
       python3 $TOOL.py --board $BOARD --source $SOURCE
     done
diff --git a/pyfpga/project.py b/pyfpga/project.py
index b6061b0f..10bb57ea 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -83,13 +83,15 @@ def _add_file(self, pathname, hdl=None, lib=None):
         if len(files) == 0:
             raise FileNotFoundError(pathname)
         for file in files:
-            path = Path(file).resolve()
+            path = Path(file).resolve().as_posix()
             attr = {}
             if hdl:
                 attr['hdl'] = hdl
             if lib:
                 attr['lib'] = lib
-            self.data.setdefault('files', {})[path.as_posix()] = attr
+            if path in self.data.get('files', {}):
+                del self.data['files'][path]
+            self.data.setdefault('files', {})[path] = attr
 
     def add_slog(self, pathname):
         """Add System Verilog file/s.
diff --git a/pyfpga/templates/openflow.jinja b/pyfpga/templates/openflow.jinja
index a0c18dd6..79977719 100644
--- a/pyfpga/templates/openflow.jinja
+++ b/pyfpga/templates/openflow.jinja
@@ -15,14 +15,13 @@ $DOCKER hdlc/ghdl:yosys /bin/bash -c "
 {% if hooks %}{{ hooks.presyn | join('\n') }}{% endif %}
 
 {% set gflags = '--std=08 -fsynopsys -fexplicit -frelaxed' %}
-{% if files %}# Files inclusion
+{% if files %}# VHDL Files inclusion
 {% for name, attr in files.items() %}
 {% if attr.hdl == "vhdl" %}
 ghdl -a {{ gflags }}{% if 'lib' in attr %} --work={{ attr.lib }}{% endif %} {{ name }}
 {% endif %}
 {% endfor %}
 {% endif %}
-ghdl -a --std=08 -fsynopsys -fexplicit -frelaxed /home/rodrigo/repos-ram/PyFPGA/pyfpga/examples/sources/vhdl/top.vhdl
 
 yosys -Q -m ghdl -p '
 
@@ -34,7 +33,7 @@ verilog_defaults -add{% for path in includes %} -I{{ path }}{% endfor %}
 verilog_defines{% for key, value in defines.items() %} -D{{ key }}={{ value }}{% endfor %}
 {% endif %}
 
-{% if files %}# Files inclusion
+{% if files %}# VLOG Files inclusion
 {% for name, attr in files.items() %}
 {% if attr.hdl == "vlog" %}
 read_verilog -defer {{ name }}

From aa29487869b751bed48cf167cdd2658e279a4da9 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 2 Sep 2024 20:34:54 -0300
Subject: [PATCH 228/248] docs: add a hint about file processing order

---
 docs/basic.rst     | 35 ++++++++++++++++++++++++-----------
 docs/extending.rst |  2 +-
 2 files changed, 25 insertions(+), 12 deletions(-)

diff --git a/docs/basic.rst b/docs/basic.rst
index 5efcfccd..0b40c35f 100644
--- a/docs/basic.rst
+++ b/docs/basic.rst
@@ -4,7 +4,7 @@ Basic usage
 Project Configuration
 ---------------------
 
-The first steps involve importing the necessary module to support the desired tool and instantiating the corresponding *class*:
+The first steps involve importing the necessary module to support the desired tool and instantiating the corresponding ``class``:
 
 .. code-block:: python
 
@@ -12,7 +12,9 @@ The first steps involve importing the necessary module to support the desired to
 
    prj = Vivado('PRJNAME', odir='OUTDIR')
 
-In the example, we are using Vivado, specifying the optional parameter *project name* (*tool name* if omitted) and *output directory* (*results* by default).
+In the example, we are using Vivado, specifying the optional parameters
+``project name`` (``tool name`` if omitted) and ``output directory``
+(``results`` by default).
 
 Next step is to specify the target FPGA device:
 
@@ -32,9 +34,8 @@ HDL source files are added using one of the following methods:
    prj.add_vlog('PATH_TO_FILES_GLOB_COMPATIBLE')
    prj.add_slog('PATH_TO_FILES_GLOB_COMPATIBLE')
 
-In these methods, you provide a path to the files. The path can include wildcards (like `*.vhdl`), allowing you to match multiple files at once.
-
-For `add_vhdl`, you can also optionally specify a library name where the files will be included.
+In these methods, you provide a path to the files. The path can include wildcards (like ``*.vhdl``), allowing you to match multiple files at once.
+In case of ``add_vhdl``, you can also optionally specify a library name where the files will be included.
 
 .. note::
 
@@ -43,6 +44,15 @@ For `add_vhdl`, you can also optionally specify a library name where the files w
   .. _glob: https://docs.python.org/3/library/glob.html
   .. _Path: https://docs.python.org/3/library/pathlib.html
 
+.. hint::
+
+   Files are processed in the order they are added. If a file is specified more than once,
+   it is removed from its previous position and placed at the end of the list.
+   This allows you to ensure that a file is processed after others when necessary
+   (e.g., placing a top-level at the end) or to customize options
+   (e.g., removing a VHDL library specification in case of a top-level)
+   when multiple files are added using a wildcard.
+
 Generics/parameters can be specified with:
 
 .. code-block:: python
@@ -82,7 +92,8 @@ After configuring the project, you can run the following to generate a bitstream
 
    prj.make()
 
-By default, this method performs *project creation*, *synthesis*, *place and route*, and *bitstream generation*.
+By default, this method performs **project creation**, **synthesis**, **place and route**,
+and **bitstream generation**.
 However, you can optionally specify both the initial and final stages, as follows:
 
 .. code-block:: python
@@ -100,7 +111,8 @@ However, you can optionally specify both the initial and final stages, as follow
 
 .. note::
 
-   After executing this method, you will find the file `<TOOL>.tcl` (or `sh` in some cases) in the output directory.
+   After executing this method, you will find the file ``<TOOL>.tcl``
+   (``<TOOL>.sh`` in some cases) in the output directory.
    For debugging purposes, if things do not work as expected, you can review this file.
 
 Bitstream programming
@@ -112,13 +124,14 @@ The final step is programming the FPGA:
 
    prj.prog('BITSTREAM', 'POSITION')
 
-Both `BITSTREAM` and `POSITION` are optional.
-If `BITSTREAM` is not specified, PyFPGA will attempt to discover it based on project information.
-The `POSITION` parameter is not always required (depends on the tool being used).
+Both ``BITSTREAM`` and ``POSITION`` are optional.
+If ``BITSTREAM`` is not specified, PyFPGA will attempt to discover it based on project information.
+The ``POSITION`` parameter is not always required (depends on the tool being used).
 
 .. note::
 
-   After executing this method, you will find the file `<TOOL>prog.tcl` (or `sh` in some cases) in the output directory.
+   After executing this method, you will find the file ``<TOOL>prog.tcl``
+   (``<TOOL>-prog.sh`` in some cases) in the output directory.
    For debugging purposes, if things do not work as expected, you can review this file.
 
 Debugging
diff --git a/docs/extending.rst b/docs/extending.rst
index 18956259..746ffc5d 100644
--- a/docs/extending.rst
+++ b/docs/extending.rst
@@ -3,7 +3,7 @@ Extending
 
 .. note::
 
-   All <TOOL> classes inherit from project.py.
+   All <TOOL> classes inherit from ``Project`` (``project.py``).
 
 This is a guide on how to add support for a new TOOL.
 

From 9a2df317a720e6899aad003a5b6bb38e16c73ed3 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 2 Sep 2024 21:29:43 -0300
Subject: [PATCH 229/248] docs: added a diagram about Openflow

---
 docs/images/Makefile     |  15 +++
 docs/images/openflow.dot |  28 +++++
 docs/images/openflow.svg | 224 +++++++++++++++++++++++++++++++++++++++
 docs/tools.rst           |   4 +
 4 files changed, 271 insertions(+)
 create mode 100644 docs/images/Makefile
 create mode 100644 docs/images/openflow.dot
 create mode 100644 docs/images/openflow.svg

diff --git a/docs/images/Makefile b/docs/images/Makefile
new file mode 100644
index 00000000..2f5b759b
--- /dev/null
+++ b/docs/images/Makefile
@@ -0,0 +1,15 @@
+#!/usr/bin/make
+
+FILES  = $(wildcard *.dot)
+FILES := $(basename $(FILES))
+FILES := $(addsuffix .svg,$(FILES))
+
+ODIR = .
+
+vpath %.svg $(ODIR)
+
+%.svg: %.dot
+	@mkdir -p $(ODIR)
+	dot -Tsvg $< -o $(ODIR)/$@
+
+all: $(FILES)
diff --git a/docs/images/openflow.dot b/docs/images/openflow.dot
new file mode 100644
index 00000000..1d1dec16
--- /dev/null
+++ b/docs/images/openflow.dot
@@ -0,0 +1,28 @@
+digraph openflow {
+  graph [ranksep=0.25];
+  node [shape = doublecircle];
+  node [shape = rectangle];
+  GHDL "ghdl-yosys-plugin" Yosys "nextpnr-ice40" "nextpnr-ecp5" icetime icepack iceprog eccpack;
+  node [shape = note ];
+  VHDL Verilog;
+  node [shape = box3d ];
+  ice40;
+  node [shape = oval];
+  "bit-ice40" [label=".bit"];
+  "bit-ecp5"  [label=".bit"];
+  VHDL                -> {GHDL "ghdl-yosys-plugin"};
+  GHDL                -> "ghdl-yosys-plugin";
+  "ghdl-yosys-plugin" -> Yosys;
+  Verilog             -> Yosys;
+  Yosys               -> ".json";
+  ".json"             -> {"nextpnr-ice40" "nextpnr-ecp5"};
+  "nextpnr-ice40"     -> ".asc";
+  "nextpnr-ecp5"      -> ".config";
+  ".asc"              -> {icetime icepack};
+  icepack             -> "bit-ice40";
+  "bit-ice40"         -> iceprog;
+  iceprog             -> ice40;
+  ".config"           -> eccpack;
+  eccpack             -> "bit-ecp5";
+  {rank = same; GHDL ; "ghdl-yosys-plugin"; Yosys;}
+}
diff --git a/docs/images/openflow.svg b/docs/images/openflow.svg
new file mode 100644
index 00000000..3ee12ac3
--- /dev/null
+++ b/docs/images/openflow.svg
@@ -0,0 +1,224 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 2.43.0 (0)
+ -->
+<!-- Title: openflow Pages: 1 -->
+<svg width="396pt" height="476pt"
+ viewBox="0.00 0.00 395.50 476.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 472)">
+<title>openflow</title>
+<polygon fill="white" stroke="transparent" points="-4,4 -4,-472 391.5,-472 391.5,4 -4,4"/>
+<!-- GHDL -->
+<g id="node1" class="node">
+<title>GHDL</title>
+<polygon fill="none" stroke="black" points="60,-414 0,-414 0,-378 60,-378 60,-414"/>
+<text text-anchor="middle" x="30" y="-392.3" font-family="Times,serif" font-size="14.00">GHDL</text>
+</g>
+<!-- ghdl&#45;yosys&#45;plugin -->
+<g id="node2" class="node">
+<title>ghdl&#45;yosys&#45;plugin</title>
+<polygon fill="none" stroke="black" points="220,-414 78,-414 78,-378 220,-378 220,-414"/>
+<text text-anchor="middle" x="149" y="-392.3" font-family="Times,serif" font-size="14.00">ghdl&#45;yosys&#45;plugin</text>
+</g>
+<!-- GHDL&#45;&gt;ghdl&#45;yosys&#45;plugin -->
+<g id="edge3" class="edge">
+<title>GHDL&#45;&gt;ghdl&#45;yosys&#45;plugin</title>
+<path fill="none" stroke="black" d="M60.21,-396C62.7,-396 65.19,-396 67.68,-396"/>
+<polygon fill="black" stroke="black" points="67.9,-399.5 77.9,-396 67.9,-392.5 67.9,-399.5"/>
+</g>
+<!-- Yosys -->
+<g id="node3" class="node">
+<title>Yosys</title>
+<polygon fill="none" stroke="black" points="294,-414 238,-414 238,-378 294,-378 294,-414"/>
+<text text-anchor="middle" x="266" y="-392.3" font-family="Times,serif" font-size="14.00">Yosys</text>
+</g>
+<!-- ghdl&#45;yosys&#45;plugin&#45;&gt;Yosys -->
+<g id="edge4" class="edge">
+<title>ghdl&#45;yosys&#45;plugin&#45;&gt;Yosys</title>
+<path fill="none" stroke="black" d="M220.3,-396C222.76,-396 225.22,-396 227.68,-396"/>
+<polygon fill="black" stroke="black" points="227.79,-399.5 237.79,-396 227.79,-392.5 227.79,-399.5"/>
+</g>
+<!-- .json -->
+<g id="node15" class="node">
+<title>.json</title>
+<ellipse fill="none" stroke="black" cx="266" cy="-342" rx="32.49" ry="18"/>
+<text text-anchor="middle" x="266" y="-338.3" font-family="Times,serif" font-size="14.00">.json</text>
+</g>
+<!-- Yosys&#45;&gt;.json -->
+<g id="edge6" class="edge">
+<title>Yosys&#45;&gt;.json</title>
+<path fill="none" stroke="black" d="M266,-377.97C266,-375.57 266,-373.06 266,-370.52"/>
+<polygon fill="black" stroke="black" points="269.5,-370.24 266,-360.24 262.5,-370.24 269.5,-370.24"/>
+</g>
+<!-- nextpnr&#45;ice40 -->
+<g id="node4" class="node">
+<title>nextpnr&#45;ice40</title>
+<polygon fill="none" stroke="black" points="258,-306 142,-306 142,-270 258,-270 258,-306"/>
+<text text-anchor="middle" x="200" y="-284.3" font-family="Times,serif" font-size="14.00">nextpnr&#45;ice40</text>
+</g>
+<!-- .asc -->
+<g id="node16" class="node">
+<title>.asc</title>
+<ellipse fill="none" stroke="black" cx="200" cy="-234" rx="28.7" ry="18"/>
+<text text-anchor="middle" x="200" y="-230.3" font-family="Times,serif" font-size="14.00">.asc</text>
+</g>
+<!-- nextpnr&#45;ice40&#45;&gt;.asc -->
+<g id="edge9" class="edge">
+<title>nextpnr&#45;ice40&#45;&gt;.asc</title>
+<path fill="none" stroke="black" d="M200,-269.97C200,-267.57 200,-265.06 200,-262.52"/>
+<polygon fill="black" stroke="black" points="203.5,-262.24 200,-252.24 196.5,-262.24 203.5,-262.24"/>
+</g>
+<!-- nextpnr&#45;ecp5 -->
+<g id="node5" class="node">
+<title>nextpnr&#45;ecp5</title>
+<polygon fill="none" stroke="black" points="387.5,-306 276.5,-306 276.5,-270 387.5,-270 387.5,-306"/>
+<text text-anchor="middle" x="332" y="-284.3" font-family="Times,serif" font-size="14.00">nextpnr&#45;ecp5</text>
+</g>
+<!-- .config -->
+<g id="node17" class="node">
+<title>.config</title>
+<ellipse fill="none" stroke="black" cx="332" cy="-234" rx="41.69" ry="18"/>
+<text text-anchor="middle" x="332" y="-230.3" font-family="Times,serif" font-size="14.00">.config</text>
+</g>
+<!-- nextpnr&#45;ecp5&#45;&gt;.config -->
+<g id="edge10" class="edge">
+<title>nextpnr&#45;ecp5&#45;&gt;.config</title>
+<path fill="none" stroke="black" d="M332,-269.97C332,-267.57 332,-265.06 332,-262.52"/>
+<polygon fill="black" stroke="black" points="335.5,-262.24 332,-252.24 328.5,-262.24 335.5,-262.24"/>
+</g>
+<!-- icetime -->
+<g id="node6" class="node">
+<title>icetime</title>
+<polygon fill="none" stroke="black" points="167.5,-198 98.5,-198 98.5,-162 167.5,-162 167.5,-198"/>
+<text text-anchor="middle" x="133" y="-176.3" font-family="Times,serif" font-size="14.00">icetime</text>
+</g>
+<!-- icepack -->
+<g id="node7" class="node">
+<title>icepack</title>
+<polygon fill="none" stroke="black" points="256,-198 186,-198 186,-162 256,-162 256,-198"/>
+<text text-anchor="middle" x="221" y="-176.3" font-family="Times,serif" font-size="14.00">icepack</text>
+</g>
+<!-- bit&#45;ice40 -->
+<g id="node13" class="node">
+<title>bit&#45;ice40</title>
+<ellipse fill="none" stroke="black" cx="221" cy="-126" rx="27" ry="18"/>
+<text text-anchor="middle" x="221" y="-122.3" font-family="Times,serif" font-size="14.00">.bit</text>
+</g>
+<!-- icepack&#45;&gt;bit&#45;ice40 -->
+<g id="edge13" class="edge">
+<title>icepack&#45;&gt;bit&#45;ice40</title>
+<path fill="none" stroke="black" d="M221,-161.97C221,-159.57 221,-157.06 221,-154.52"/>
+<polygon fill="black" stroke="black" points="224.5,-154.24 221,-144.24 217.5,-154.24 224.5,-154.24"/>
+</g>
+<!-- iceprog -->
+<g id="node8" class="node">
+<title>iceprog</title>
+<polygon fill="none" stroke="black" points="256,-90 186,-90 186,-54 256,-54 256,-90"/>
+<text text-anchor="middle" x="221" y="-68.3" font-family="Times,serif" font-size="14.00">iceprog</text>
+</g>
+<!-- ice40 -->
+<g id="node12" class="node">
+<title>ice40</title>
+<polygon fill="none" stroke="black" points="248.5,-36 197.5,-36 193.5,-32 193.5,0 244.5,0 248.5,-4 248.5,-36"/>
+<polyline fill="none" stroke="black" points="244.5,-32 193.5,-32 "/>
+<polyline fill="none" stroke="black" points="244.5,-32 244.5,0 "/>
+<polyline fill="none" stroke="black" points="244.5,-32 248.5,-36 "/>
+<text text-anchor="middle" x="221" y="-14.3" font-family="Times,serif" font-size="14.00">ice40</text>
+</g>
+<!-- iceprog&#45;&gt;ice40 -->
+<g id="edge15" class="edge">
+<title>iceprog&#45;&gt;ice40</title>
+<path fill="none" stroke="black" d="M221,-53.97C221,-51.57 221,-49.06 221,-46.52"/>
+<polygon fill="black" stroke="black" points="224.5,-46.24 221,-36.24 217.5,-46.24 224.5,-46.24"/>
+</g>
+<!-- eccpack -->
+<g id="node9" class="node">
+<title>eccpack</title>
+<polygon fill="none" stroke="black" points="368.5,-198 295.5,-198 295.5,-162 368.5,-162 368.5,-198"/>
+<text text-anchor="middle" x="332" y="-176.3" font-family="Times,serif" font-size="14.00">eccpack</text>
+</g>
+<!-- bit&#45;ecp5 -->
+<g id="node14" class="node">
+<title>bit&#45;ecp5</title>
+<ellipse fill="none" stroke="black" cx="332" cy="-126" rx="27" ry="18"/>
+<text text-anchor="middle" x="332" y="-122.3" font-family="Times,serif" font-size="14.00">.bit</text>
+</g>
+<!-- eccpack&#45;&gt;bit&#45;ecp5 -->
+<g id="edge17" class="edge">
+<title>eccpack&#45;&gt;bit&#45;ecp5</title>
+<path fill="none" stroke="black" d="M332,-161.97C332,-159.57 332,-157.06 332,-154.52"/>
+<polygon fill="black" stroke="black" points="335.5,-154.24 332,-144.24 328.5,-154.24 335.5,-154.24"/>
+</g>
+<!-- VHDL -->
+<g id="node10" class="node">
+<title>VHDL</title>
+<polygon fill="none" stroke="black" points="113.5,-468 60.5,-468 60.5,-432 119.5,-432 119.5,-462 113.5,-468"/>
+<polyline fill="none" stroke="black" points="113.5,-468 113.5,-462 "/>
+<polyline fill="none" stroke="black" points="119.5,-462 113.5,-462 "/>
+<text text-anchor="middle" x="90" y="-446.3" font-family="Times,serif" font-size="14.00">VHDL</text>
+</g>
+<!-- VHDL&#45;&gt;GHDL -->
+<g id="edge1" class="edge">
+<title>VHDL&#45;&gt;GHDL</title>
+<path fill="none" stroke="black" d="M70.35,-431.97C66.25,-428.42 61.86,-424.61 57.53,-420.86"/>
+<polygon fill="black" stroke="black" points="59.74,-418.15 49.9,-414.24 55.16,-423.44 59.74,-418.15"/>
+</g>
+<!-- VHDL&#45;&gt;ghdl&#45;yosys&#45;plugin -->
+<g id="edge2" class="edge">
+<title>VHDL&#45;&gt;ghdl&#45;yosys&#45;plugin</title>
+<path fill="none" stroke="black" d="M109.32,-431.97C113.35,-428.42 117.67,-424.61 121.93,-420.86"/>
+<polygon fill="black" stroke="black" points="124.25,-423.48 129.44,-414.24 119.62,-418.23 124.25,-423.48"/>
+</g>
+<!-- Verilog -->
+<g id="node11" class="node">
+<title>Verilog</title>
+<polygon fill="none" stroke="black" points="293.5,-468 232.5,-468 232.5,-432 299.5,-432 299.5,-462 293.5,-468"/>
+<polyline fill="none" stroke="black" points="293.5,-468 293.5,-462 "/>
+<polyline fill="none" stroke="black" points="299.5,-462 293.5,-462 "/>
+<text text-anchor="middle" x="266" y="-446.3" font-family="Times,serif" font-size="14.00">Verilog</text>
+</g>
+<!-- Verilog&#45;&gt;Yosys -->
+<g id="edge5" class="edge">
+<title>Verilog&#45;&gt;Yosys</title>
+<path fill="none" stroke="black" d="M266,-431.97C266,-429.57 266,-427.06 266,-424.52"/>
+<polygon fill="black" stroke="black" points="269.5,-424.24 266,-414.24 262.5,-424.24 269.5,-424.24"/>
+</g>
+<!-- bit&#45;ice40&#45;&gt;iceprog -->
+<g id="edge14" class="edge">
+<title>bit&#45;ice40&#45;&gt;iceprog</title>
+<path fill="none" stroke="black" d="M221,-107.97C221,-105.57 221,-103.06 221,-100.52"/>
+<polygon fill="black" stroke="black" points="224.5,-100.24 221,-90.24 217.5,-100.24 224.5,-100.24"/>
+</g>
+<!-- .json&#45;&gt;nextpnr&#45;ice40 -->
+<g id="edge7" class="edge">
+<title>.json&#45;&gt;nextpnr&#45;ice40</title>
+<path fill="none" stroke="black" d="M247.97,-326.79C242.4,-322.41 236.12,-317.46 229.98,-312.62"/>
+<polygon fill="black" stroke="black" points="231.79,-309.59 221.77,-306.15 227.46,-315.09 231.79,-309.59"/>
+</g>
+<!-- .json&#45;&gt;nextpnr&#45;ecp5 -->
+<g id="edge8" class="edge">
+<title>.json&#45;&gt;nextpnr&#45;ecp5</title>
+<path fill="none" stroke="black" d="M284.03,-326.79C289.6,-322.41 295.88,-317.46 302.02,-312.62"/>
+<polygon fill="black" stroke="black" points="304.54,-315.09 310.23,-306.15 300.21,-309.59 304.54,-315.09"/>
+</g>
+<!-- .asc&#45;&gt;icetime -->
+<g id="edge11" class="edge">
+<title>.asc&#45;&gt;icetime</title>
+<path fill="none" stroke="black" d="M182.75,-219.61C176.86,-215.04 170.08,-209.78 163.47,-204.65"/>
+<polygon fill="black" stroke="black" points="165.3,-201.64 155.26,-198.27 161.01,-207.17 165.3,-201.64"/>
+</g>
+<!-- .asc&#45;&gt;icepack -->
+<g id="edge12" class="edge">
+<title>.asc&#45;&gt;icepack</title>
+<path fill="none" stroke="black" d="M206.76,-216.26C207.9,-213.44 209.1,-210.46 210.31,-207.46"/>
+<polygon fill="black" stroke="black" points="213.61,-208.65 214.11,-198.06 207.12,-206.03 213.61,-208.65"/>
+</g>
+<!-- .config&#45;&gt;eccpack -->
+<g id="edge16" class="edge">
+<title>.config&#45;&gt;eccpack</title>
+<path fill="none" stroke="black" d="M332,-215.97C332,-213.57 332,-211.06 332,-208.52"/>
+<polygon fill="black" stroke="black" points="335.5,-208.24 332,-198.24 328.5,-208.24 335.5,-208.24"/>
+</g>
+</g>
+</svg>
diff --git a/docs/tools.rst b/docs/tools.rst
index 8839ac2d..1f2ee57b 100644
--- a/docs/tools.rst
+++ b/docs/tools.rst
@@ -94,6 +94,10 @@ Openflow
 
 Openflow is the combination of different Free/Libre and Open Source (FLOSS) tools:
 
+.. image:: images/openflow.svg
+   :width: 70%
+   :align: center
+
 * Yosys for synthesis, with ghdl-yosys-plugin for VHDL support.
 * nextpnr in its ice40 and ecp5 versions.
 * Projects icestorm and Trellis.

From 29ed35a312a7f3586b01c70ac8855d0e5a78f2f7 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 2 Sep 2024 21:52:16 -0300
Subject: [PATCH 230/248] ci: modified to trigger docs when the branch is main
 or dev

---
 .github/workflows/docs.yml | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 1db219c9..8d26b1af 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -5,7 +5,8 @@ on:
     paths:
       - 'docs/**'
     branches:
-#      - main
+      - main
+      - dev
 
 jobs:
   docs:

From 9aa363f3b3b23d89d7947f5c228bed9b287e8173 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 2 Sep 2024 23:51:08 -0300
Subject: [PATCH 231/248] ci: add windows tests

---
 .github/workflows/test.yml | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 40699986..0b33ba57 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -4,7 +4,7 @@ on:
   push:
 
 jobs:
-  test:
+  test-lin:
     strategy:
       matrix:
         os: ['ubuntu']
@@ -25,3 +25,20 @@ jobs:
       run: pip install . && pip install pytest
     - name: Run tests
       run: source tests/mocks/source-me.sh && make test
+  test-win:
+    runs-on: windows-latest
+    name: windows | 3.12
+    steps:
+    - name: Checkout repository
+      uses: actions/checkout@v4
+      with:
+        submodules: true
+        fetch-depth: 0
+    - name: Set up Python 3.12
+      uses: actions/setup-python@v5
+      with:
+        python-version: 3.12
+    - name: Install dependencies
+      run: pip install . && pip install pytest
+    - name: Run tests
+      run: make test

From 6dc528a4e724b398fd734cabf7c420fd66b3280e Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 2 Sep 2024 23:59:09 -0300
Subject: [PATCH 232/248] ci: add to run regress.sh

---
 .github/workflows/test.yml | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 0b33ba57..d45d0543 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -24,7 +24,9 @@ jobs:
     - name: Install dependencies
       run: pip install . && pip install pytest
     - name: Run tests
-      run: source tests/mocks/source-me.sh && make test
+      run: |
+        source tests/mocks/source-me.sh && make test
+        cd examples/projects && bash regress.sh
   test-win:
     runs-on: windows-latest
     name: windows | 3.12

From 48af8b24979e93d26381a4db9c3c26791b4f6831 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Wed, 4 Sep 2024 20:09:23 -0300
Subject: [PATCH 233/248] ci: modified when to trigger the docs actions

---
 .github/workflows/docs.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 8d26b1af..bf55bcfb 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -4,6 +4,7 @@ on:
   push:
     paths:
       - 'docs/**'
+      - 'pyfpga/project.py'
     branches:
       - main
       - dev

From fcd51f6e5c1ea741d10a956292a5de3ac90f48b2 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Wed, 4 Sep 2024 20:25:17 -0300
Subject: [PATCH 234/248] ci: modified to run ubuntu and windows tests using
 the same job

---
 .github/workflows/test.yml | 39 ++++++++++++++------------------------
 tests/test_tools.py        |  4 ++--
 2 files changed, 16 insertions(+), 27 deletions(-)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index d45d0543..12e54f2c 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -4,19 +4,25 @@ on:
   push:
 
 jobs:
-  test-lin:
+  test:
     strategy:
       matrix:
-        os: ['ubuntu']
-        pyver: ['3.8', '3.9', '3.10', '3.11', '3.12']
+        os: [ubuntu, windows]
+        pyver: [3.8, 3.9, 3.10, 3.11, 3.12]
+        exclude:
+          - os: windows
+            pyver: 3.8
+          - os: windows
+            pyver: 3.9
+          - os: windows
+            pyver: 3.10
+          - os: windows
+            pyver: 3.11
     runs-on: ${{ matrix.os }}-latest
     name: ${{ matrix.os }} | ${{ matrix.pyver }}
     steps:
     - name: Checkout repository
       uses: actions/checkout@v4
-      with:
-        submodules: true
-        fetch-depth: 0
     - name: Set up Python ${{ matrix.pyver }}
       uses: actions/setup-python@v5
       with:
@@ -25,22 +31,5 @@ jobs:
       run: pip install . && pip install pytest
     - name: Run tests
       run: |
-        source tests/mocks/source-me.sh && make test
-        cd examples/projects && bash regress.sh
-  test-win:
-    runs-on: windows-latest
-    name: windows | 3.12
-    steps:
-    - name: Checkout repository
-      uses: actions/checkout@v4
-      with:
-        submodules: true
-        fetch-depth: 0
-    - name: Set up Python 3.12
-      uses: actions/setup-python@v5
-      with:
-        python-version: 3.12
-    - name: Install dependencies
-      run: pip install . && pip install pytest
-    - name: Run tests
-      run: make test
+        make test
+        cd examples/projects && bash regress.sh --notool
diff --git a/tests/test_tools.py b/tests/test_tools.py
index ad28632a..98f00055 100644
--- a/tests/test_tools.py
+++ b/tests/test_tools.py
@@ -85,9 +85,9 @@ def generate(tool, part):
     prj.add_hook('postbit', 'HOOK16')
     try:
         prj.make()
-    except Exception:
+    except RuntimeError:
         pass
     try:
         prj.prog()
-    except Exception:
+    except RuntimeError:
         pass

From 1a0ff918b0f63b58c52193aeed798f78aa4c7c00 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 7 Sep 2024 14:22:48 -0300
Subject: [PATCH 235/248] Add the --notool option, to avoid errors when tools
 are not available

---
 examples/projects/diamond.py  | 16 +++++++++++-----
 examples/projects/ise.py      | 16 +++++++++++-----
 examples/projects/libero.py   | 16 +++++++++++-----
 examples/projects/openflow.py | 16 +++++++++++-----
 examples/projects/quartus.py  | 16 +++++++++++-----
 examples/projects/regress.sh  | 25 +++++++++++++++++++++++--
 examples/projects/vivado.py   | 16 +++++++++++-----
 7 files changed, 89 insertions(+), 32 deletions(-)

diff --git a/examples/projects/diamond.py b/examples/projects/diamond.py
index 0128d7c3..464be7ff 100644
--- a/examples/projects/diamond.py
+++ b/examples/projects/diamond.py
@@ -15,6 +15,9 @@
 parser.add_argument(
     '--action', choices=['make', 'prog', 'all'], default='make'
 )
+parser.add_argument(
+    '--notool', action='store_true'
+)
 args = parser.parse_args()
 
 prj = Diamond(odir=f'results/diamond/{args.source}/{args.board}')
@@ -43,8 +46,11 @@
 
 prj.set_top('Top')
 
-if args.action in ['make', 'all']:
-    prj.make()
-
-if args.action in ['prog', 'all']:
-    prj.prog()
+try:
+    if args.action in ['make', 'all']:
+        prj.make()
+    if args.action in ['prog', 'all']:
+        prj.prog()
+except RuntimeError:
+    if not args.notool:
+        raise
diff --git a/examples/projects/ise.py b/examples/projects/ise.py
index 279a5db0..1955d34d 100644
--- a/examples/projects/ise.py
+++ b/examples/projects/ise.py
@@ -15,6 +15,9 @@
 parser.add_argument(
     '--action', choices=['make', 'prog', 'all'], default='make'
 )
+parser.add_argument(
+    '--notool', action='store_true'
+)
 args = parser.parse_args()
 
 prj = Ise(odir=f'results/ise/{args.source}/{args.board}')
@@ -45,8 +48,11 @@
 
 prj.set_top('Top')
 
-if args.action in ['make', 'all']:
-    prj.make()
-
-if args.action in ['prog', 'all']:
-    prj.prog()
+try:
+    if args.action in ['make', 'all']:
+        prj.make()
+    if args.action in ['prog', 'all']:
+        prj.prog()
+except RuntimeError:
+    if not args.notool:
+        raise
diff --git a/examples/projects/libero.py b/examples/projects/libero.py
index dd2c5861..8bb94b7a 100644
--- a/examples/projects/libero.py
+++ b/examples/projects/libero.py
@@ -14,6 +14,9 @@
 parser.add_argument(
     '--action', choices=['make', 'prog', 'all'], default='make'
 )
+parser.add_argument(
+    '--notool', action='store_true'
+)
 args = parser.parse_args()
 
 prj = Libero(odir=f'results/libero/{args.source}/{args.board}')
@@ -43,8 +46,11 @@
 
 prj.set_top('Top')
 
-if args.action in ['make', 'all']:
-    prj.make()
-
-if args.action in ['prog', 'all']:
-    prj.prog()
+try:
+    if args.action in ['make', 'all']:
+        prj.make()
+    if args.action in ['prog', 'all']:
+        prj.prog()
+except RuntimeError:
+    if not args.notool:
+        raise
diff --git a/examples/projects/openflow.py b/examples/projects/openflow.py
index 56a6b2ab..98e2e999 100644
--- a/examples/projects/openflow.py
+++ b/examples/projects/openflow.py
@@ -16,6 +16,9 @@
 parser.add_argument(
     '--action', choices=['make', 'prog', 'all'], default='make'
 )
+parser.add_argument(
+    '--notool', action='store_true'
+)
 args = parser.parse_args()
 
 prj = Openflow(odir=f'results/openflow/{args.source}/{args.board}')
@@ -59,8 +62,11 @@
 
 prj.set_top('Top')
 
-if args.action in ['make', 'all']:
-    prj.make()
-
-if args.action in ['prog', 'all']:
-    prj.prog()
+try:
+    if args.action in ['make', 'all']:
+        prj.make()
+    if args.action in ['prog', 'all']:
+        prj.prog()
+except RuntimeError:
+    if not args.notool:
+        raise
diff --git a/examples/projects/quartus.py b/examples/projects/quartus.py
index eb7e889e..258fa8e6 100644
--- a/examples/projects/quartus.py
+++ b/examples/projects/quartus.py
@@ -15,6 +15,9 @@
 parser.add_argument(
     '--action', choices=['make', 'prog', 'all'], default='make'
 )
+parser.add_argument(
+    '--notool', action='store_true'
+)
 args = parser.parse_args()
 
 prj = Quartus(odir=f'results/quartus/{args.source}/{args.board}')
@@ -44,8 +47,11 @@
 
 prj.set_top('Top')
 
-if args.action in ['make', 'all']:
-    prj.make()
-
-if args.action in ['prog', 'all']:
-    prj.prog()
+try:
+    if args.action in ['make', 'all']:
+        prj.make()
+    if args.action in ['prog', 'all']:
+        prj.prog()
+except RuntimeError:
+    if not args.notool:
+        raise
diff --git a/examples/projects/regress.sh b/examples/projects/regress.sh
index 45b7d848..a260b52e 100644
--- a/examples/projects/regress.sh
+++ b/examples/projects/regress.sh
@@ -13,7 +13,24 @@ TOOLS["vivado"]="zybo arty"
 
 SOURCES=("vlog" "vhdl" "slog")
 
-SPECIFIED_TOOL=$1
+SPECIFIED_TOOL=""
+NOTOOL=false
+while [[ "$#" -gt 0 ]]; do
+  case $1 in
+    --tool)
+      SPECIFIED_TOOL="$2"
+      shift 2
+      ;;
+    --notool)
+      NOTOOL=true
+      shift
+      ;;
+    *)
+      echo "Invalid option: $1"
+      exit 1
+      ;;
+  esac
+done
 
 for TOOL in "${!TOOLS[@]}"; do
   if [[ -n "$SPECIFIED_TOOL" && "$TOOL" != "$SPECIFIED_TOOL" ]]; then
@@ -26,7 +43,11 @@ for TOOL in "${!TOOLS[@]}"; do
         continue
       fi
       echo "> $TOOL - $BOARD - $SOURCE"
-      python3 $TOOL.py --board $BOARD --source $SOURCE
+      if [[ "$NOTOOL" == true ]]; then
+        python3 $TOOL.py --board $BOARD --source $SOURCE --notool
+      else
+        python3 $TOOL.py --board $BOARD --source $SOURCE
+      fi
     done
   done
 done
diff --git a/examples/projects/vivado.py b/examples/projects/vivado.py
index af497b91..33fba3f3 100644
--- a/examples/projects/vivado.py
+++ b/examples/projects/vivado.py
@@ -15,6 +15,9 @@
 parser.add_argument(
     '--action', choices=['make', 'prog', 'all'], default='make'
 )
+parser.add_argument(
+    '--notool', action='store_true'
+)
 args = parser.parse_args()
 
 prj = Vivado(odir=f'results/vivado/{args.source}/{args.board}')
@@ -50,8 +53,11 @@
 
 prj.set_top('Top')
 
-if args.action in ['make', 'all']:
-    prj.make()
-
-if args.action in ['prog', 'all']:
-    prj.prog()
+try:
+    if args.action in ['make', 'all']:
+        prj.make()
+    if args.action in ['prog', 'all']:
+        prj.prog()
+except RuntimeError:
+    if not args.notool:
+        raise

From 8c061c1fe94672806b2f5efabdee92573234f4c9 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 7 Sep 2024 14:27:55 -0300
Subject: [PATCH 236/248] ci: fix issue specifyng the Python version

---
 .github/workflows/test.yml | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 12e54f2c..076ec499 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -7,17 +7,17 @@ jobs:
   test:
     strategy:
       matrix:
-        os: [ubuntu, windows]
-        pyver: [3.8, 3.9, 3.10, 3.11, 3.12]
+        os: ['ubuntu', 'windows']
+        pyver: ['3.8', '3.9', '3.10', '3.11', '3.12']
         exclude:
-          - os: windows
-            pyver: 3.8
-          - os: windows
-            pyver: 3.9
-          - os: windows
-            pyver: 3.10
-          - os: windows
-            pyver: 3.11
+          - os: 'windows'
+            pyver: '3.8'
+          - os: 'windows'
+            pyver: '3.9'
+          - os: 'windows'
+            pyver: '3.10'
+          - os: 'windows'
+            pyver: '3.11'
     runs-on: ${{ matrix.os }}-latest
     name: ${{ matrix.os }} | ${{ matrix.pyver }}
     steps:

From e313901c7cc51437f4f23eb2ab328a2ef0e847ef Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 7 Sep 2024 21:54:07 -0300
Subject: [PATCH 237/248] tests: checking that paths are posix-like

---
 tests/test_data.py | 77 ++++++++++++++++++++++++----------------------
 1 file changed, 41 insertions(+), 36 deletions(-)

diff --git a/tests/test_data.py b/tests/test_data.py
index 49b0645b..d4d8d0f8 100644
--- a/tests/test_data.py
+++ b/tests/test_data.py
@@ -57,24 +57,24 @@
         Path(tdir / 'fakedata/cons/par.xdc').resolve().as_posix(): {}
     },
     'params': {
-        'PAR1': 'VAL1',
-        'PAR2': 'VAL2',
-        'PAR3': 'VAL3'
+        'PAR1': 'VAL01',
+        'PAR2': 'VAL02',
+        'PAR3': 'VAL03'
     },
     'defines': {
-        'DEF1': 'VAL1',
-        'DEF2': 'VAL2',
-        'DEF3': 'VAL3'
+        'DEF1': 'VAL01',
+        'DEF2': 'VAL02',
+        'DEF3': 'VAL03'
     },
     'hooks': {
-        'precfg': ['CMD1', 'CMD2'],
-        'postcfg': ['CMD1', 'CMD2'],
-        'presyn': ['CMD1', 'CMD2'],
-        'postsyn': ['CMD1', 'CMD2'],
-        'prepar': ['CMD1', 'CMD2'],
-        'postpar': ['CMD1', 'CMD2'],
-        'prebit': ['CMD1', 'CMD2'],
-        'postbit': ['CMD1', 'CMD2']
+        'precfg': ['CMD01', 'CMD02'],
+        'postcfg': ['CMD03', 'CMD04'],
+        'presyn': ['CMD05', 'CMD06'],
+        'postsyn': ['CMD07', 'CMD08'],
+        'prepar': ['CMD09', 'CMD10'],
+        'postpar': ['CMD11', 'CMD12'],
+        'prebit': ['CMD13', 'CMD14'],
+        'postbit': ['CMD15', 'CMD16']
     }
 }
 
@@ -92,26 +92,31 @@ def test_data():
     prj.add_cons(str(tdir / 'fakedata/cons/all.xdc'))
     prj.add_cons(str(tdir / 'fakedata/cons/syn.xdc'))
     prj.add_cons(str(tdir / 'fakedata/cons/par.xdc'))
-    prj.add_param('PAR1', 'VAL1')
-    prj.add_param('PAR2', 'VAL2')
-    prj.add_param('PAR3', 'VAL3')
-    prj.add_define('DEF1', 'VAL1')
-    prj.add_define('DEF2', 'VAL2')
-    prj.add_define('DEF3', 'VAL3')
-    prj.add_hook('precfg', 'CMD1')
-    prj.add_hook('precfg', 'CMD2')
-    prj.add_hook('postcfg', 'CMD1')
-    prj.add_hook('postcfg', 'CMD2')
-    prj.add_hook('presyn', 'CMD1')
-    prj.add_hook('presyn', 'CMD2')
-    prj.add_hook('postsyn', 'CMD1')
-    prj.add_hook('postsyn', 'CMD2')
-    prj.add_hook('prepar', 'CMD1')
-    prj.add_hook('prepar', 'CMD2')
-    prj.add_hook('postpar', 'CMD1')
-    prj.add_hook('postpar', 'CMD2')
-    prj.add_hook('prebit', 'CMD1')
-    prj.add_hook('prebit', 'CMD2')
-    prj.add_hook('postbit', 'CMD1')
-    prj.add_hook('postbit', 'CMD2')
+    prj.add_param('PAR1', 'VAL01')
+    prj.add_param('PAR2', 'VAL02')
+    prj.add_param('PAR3', 'VAL03')
+    prj.add_define('DEF1', 'VAL01')
+    prj.add_define('DEF2', 'VAL02')
+    prj.add_define('DEF3', 'VAL03')
+    prj.add_hook('precfg', 'CMD01')
+    prj.add_hook('precfg', 'CMD02')
+    prj.add_hook('postcfg', 'CMD03')
+    prj.add_hook('postcfg', 'CMD04')
+    prj.add_hook('presyn', 'CMD05')
+    prj.add_hook('presyn', 'CMD06')
+    prj.add_hook('postsyn', 'CMD07')
+    prj.add_hook('postsyn', 'CMD08')
+    prj.add_hook('prepar', 'CMD09')
+    prj.add_hook('prepar', 'CMD10')
+    prj.add_hook('postpar', 'CMD11')
+    prj.add_hook('postpar', 'CMD12')
+    prj.add_hook('prebit', 'CMD13')
+    prj.add_hook('prebit', 'CMD14')
+    prj.add_hook('postbit', 'CMD15')
+    prj.add_hook('postbit', 'CMD16')
     assert prj.data == pattern, 'ERROR: unexpected data'
+    paths = prj.data['includes'] + list(prj.data['files'].keys())
+    for path in paths:
+        assert '\\' not in path, (
+            f"'{path}' contains a '\\' character, which is not allowed."
+        )

From d94057e431663c5280aedc38de847397d667d907 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 7 Sep 2024 22:00:35 -0300
Subject: [PATCH 238/248] ci: moved to run regress from test.yml to the
 Makefile

---
 .github/workflows/test.yml | 4 +---
 Makefile                   | 1 +
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 076ec499..b04f05be 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -30,6 +30,4 @@ jobs:
     - name: Install dependencies
       run: pip install . && pip install pytest
     - name: Run tests
-      run: |
-        make test
-        cd examples/projects && bash regress.sh --notool
+      run: make test
diff --git a/Makefile b/Makefile
index 2f2402c4..7893bb51 100644
--- a/Makefile
+++ b/Makefile
@@ -14,6 +14,7 @@ lint:
 
 test:
 	pytest
+	cd examples/projects && bash regress.sh --notool
 
 clean:
 	py3clean .

From d6b773b334f6b3a705528312f0e141ae77b465c0 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 9 Nov 2024 09:23:57 -0300
Subject: [PATCH 239/248] prj2bit: improve ERROR messages

---
 pyfpga/helpers/prj2bit.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/pyfpga/helpers/prj2bit.py b/pyfpga/helpers/prj2bit.py
index 1124e452..ea633b6b 100644
--- a/pyfpga/helpers/prj2bit.py
+++ b/pyfpga/helpers/prj2bit.py
@@ -63,7 +63,7 @@ def main():
     prjfile = Path(args.prjfile)
 
     if not prjfile.exists():
-        sys.exit('file not found.')
+        sys.exit(f'ERROR: {prjfile} file not found.')
 
     directory = prjfile.parent
     base_name = prjfile.stem
@@ -72,9 +72,9 @@ def main():
     tool = ''
     if extension in tool_per_ext:
         tool = tool_per_ext[extension]
-        print(f'* {tool} project file found.')
+        print(f'INFO: {tool} project file found.')
     else:
-        sys.exit('Unknown project file extension')
+        sys.exit(f'ERROR: unknown project file extension ({extension})')
 
     # -------------------------------------------------------------------------
     # Solving with PyFPGA

From 5c5c4f99500481db7b9e2b6a1b28f84f745e96b6 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 10 Nov 2024 11:47:08 -0300
Subject: [PATCH 240/248] Add constraints for the mpfs-disco-kit board

---
 examples/sources/cons/mpfs-disco-kit/clk.pdc    | 1 +
 examples/sources/cons/mpfs-disco-kit/led.pdc    | 1 +
 examples/sources/cons/mpfs-disco-kit/timing.sdc | 1 +
 3 files changed, 3 insertions(+)
 create mode 100644 examples/sources/cons/mpfs-disco-kit/clk.pdc
 create mode 100644 examples/sources/cons/mpfs-disco-kit/led.pdc
 create mode 100644 examples/sources/cons/mpfs-disco-kit/timing.sdc

diff --git a/examples/sources/cons/mpfs-disco-kit/clk.pdc b/examples/sources/cons/mpfs-disco-kit/clk.pdc
new file mode 100644
index 00000000..61f7332f
--- /dev/null
+++ b/examples/sources/cons/mpfs-disco-kit/clk.pdc
@@ -0,0 +1 @@
+set_io -port_name clk_i -DIRECTION INPUT -pin_name R18 -fixed true
diff --git a/examples/sources/cons/mpfs-disco-kit/led.pdc b/examples/sources/cons/mpfs-disco-kit/led.pdc
new file mode 100644
index 00000000..678d3bf4
--- /dev/null
+++ b/examples/sources/cons/mpfs-disco-kit/led.pdc
@@ -0,0 +1 @@
+set_io -port_name led_o -DIRECTION OUTPUT -pin_name T18 -fixed true
diff --git a/examples/sources/cons/mpfs-disco-kit/timing.sdc b/examples/sources/cons/mpfs-disco-kit/timing.sdc
new file mode 100644
index 00000000..00363616
--- /dev/null
+++ b/examples/sources/cons/mpfs-disco-kit/timing.sdc
@@ -0,0 +1 @@
+create_clock -period 20 [get_ports clk_i]

From 25e683c7fa9c4c7d19c47bf99f5aed94c3efd249 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 10 Nov 2024 12:06:53 -0300
Subject: [PATCH 241/248] Fix support for PolarFireSoC devices

---
 examples/projects/libero.py   |  9 ++++++++-
 pyfpga/libero.py              | 29 +++++++++++++++++++++++++----
 pyfpga/templates/libero.jinja |  4 ++--
 tests/test_part.py            |  3 ++-
 4 files changed, 37 insertions(+), 8 deletions(-)

diff --git a/examples/projects/libero.py b/examples/projects/libero.py
index 8bb94b7a..3498a6e3 100644
--- a/examples/projects/libero.py
+++ b/examples/projects/libero.py
@@ -6,7 +6,7 @@
 
 parser = argparse.ArgumentParser()
 parser.add_argument(
-    '--board', choices=['maker'], default='maker'
+    '--board', choices=['mpfs-disco-kit', 'maker'], default='mpfs-disco-kit'
 )
 parser.add_argument(
     '--source', choices=['vlog', 'vhdl', 'slog'], default='vlog'
@@ -21,6 +21,13 @@
 
 prj = Libero(odir=f'results/libero/{args.source}/{args.board}')
 
+
+if args.board == 'mpfs-disco-kit':
+    prj.set_part('MPFS095T-1-FCSG325E')
+    prj.add_param('FREQ', '50000000')
+    prj.add_cons('../sources/cons/mpfs-disco-kit/timing.sdc')
+    prj.add_cons('../sources/cons/mpfs-disco-kit/clk.pdc')
+    prj.add_cons('../sources/cons/mpfs-disco-kit/led.pdc')
 if args.board == 'maker':
     prj.set_part('m2s010-1-tq144')
     prj.add_param('FREQ', '125000000')
diff --git a/pyfpga/libero.py b/pyfpga/libero.py
index 2f1e4bc4..6f1bda0f 100644
--- a/pyfpga/libero.py
+++ b/pyfpga/libero.py
@@ -31,9 +31,10 @@ def _make_custom(self):
         self.data['device'] = info['device']
         self.data['speed'] = info['speed']
         self.data['package'] = info['package']
+        self.data['prange'] = info['prange']
 
     def _prog_custom(self):
-        raise NotImplementedError('Libero programming not supported')
+        raise NotImplementedError('Libero programming not supported yet')
 
 
 # pylint: disable=duplicate-code
@@ -42,7 +43,7 @@ def get_info(part):
     """Get info about the FPGA part.
 
     :param part: the FPGA part as specified by the tool
-    :returns: a dictionary with the keys family, device, speed and package
+    :returns: a dict with the keys family, device, speed, package and prange
     """
     part = part.lower()
     # Looking for the family
@@ -51,6 +52,7 @@ def get_info(part):
         r'm2s': 'SmartFusion2',
         r'm2gl': 'Igloo2',
         r'rt4g': 'RTG4',
+        r'mpfs': 'PolarFireSoC',
         r'mpf': 'PolarFire',
         r'a2f': 'SmartFusion',
         r'afs': 'Fusion',
@@ -65,10 +67,11 @@ def get_info(part):
         if re.match(key, part):
             family = value
             break
-    # Looking for the device and package
+    # Looking for the device, speed and package
     device = None
     speed = None
     package = None
+    prange = None
     aux = part.split('-')
     if len(aux) == 2:
         device = aux[0]
@@ -86,7 +89,25 @@ def get_info(part):
         raise ValueError(
             'Part must be DEVICE-SPEED-PACKAGE or DEVICE-PACKAGE'
         )
+    # Looking for a part_range
+    pranges = {
+        'c': 'COM',
+        'e': 'EXT',
+        'i': 'IND',
+        'm': 'MIL',
+        't1': 'TGrade1'
+    }
+    prange = 'COM'
+    for suffix, name in pranges.items():
+        if package.endswith(suffix):
+            package = package[:-len(suffix)]
+            prange = name
+            break
     # Finish
     return {
-        'family': family, 'device': device, 'speed': speed, 'package': package
+        'family': family,
+        'device': device,
+        'speed': speed,
+        'package': package,
+        'prange': prange
     }
diff --git a/pyfpga/templates/libero.jinja b/pyfpga/templates/libero.jinja
index c64d8a5d..499a9230 100644
--- a/pyfpga/templates/libero.jinja
+++ b/pyfpga/templates/libero.jinja
@@ -9,8 +9,8 @@
 {% if 'cfg' in steps %}# Project configuration -------------------------------------------------------
 
 if { [ file exists {{ project }} ] } { file delete -force -- {{ project }} }
-new_project -name {{ project }} -location {libero} -hdl {VERILOG} -family {SmartFusion2}
-set_device -family {{ family }} -die {{ device }} -package {{ package }} -speed {{ speed }}
+new_project -name {{ project }} -location libero -hdl VERILOG -family {{ family }}
+set_device -family {{ family }} -die {{ device }} -package {{ package}} -speed {{ speed }} -part_range {{ prange }}
 
 {% if hooks %}{{ hooks.precfg | join('\n') }}{% endif %}
 
diff --git a/tests/test_part.py b/tests/test_part.py
index 86087946..5319e3dc 100644
--- a/tests/test_part.py
+++ b/tests/test_part.py
@@ -19,7 +19,8 @@ def test_libero():
         'family': 'SmartFusion2',
         'device': 'm2s010',
         'speed': '-1',
-        'package': 'tq144'
+        'package': 'tq144',
+        'prange': 'COM'
     }
     assert get_info_libero('m2s010-1-tq144') == info
     assert get_info_libero('m2s010-tq144-1') == info

From a90c1f4e11f084791a21835a366587e0f9a65b95 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 10 Nov 2024 22:09:48 -0300
Subject: [PATCH 242/248] Improve PART format parsing (ise, libero and
 openflow)

---
 docs/tools.rst             | 26 +++++++++++
 pyfpga/ise.py              | 20 ++++----
 pyfpga/libero.py           | 20 ++++----
 pyfpga/openflow.py         | 15 ++++--
 pyfpga/templates/ise.jinja |  2 +-
 tests/test_part.py         | 96 ++++++++++++++++++++++++++++++++++----
 6 files changed, 147 insertions(+), 32 deletions(-)

diff --git a/docs/tools.rst b/docs/tools.rst
index 1f2ee57b..38da3ef3 100644
--- a/docs/tools.rst
+++ b/docs/tools.rst
@@ -70,6 +70,13 @@ Example:
 
    prj = Ise()
 
+Valid PART formats:
+
+.. code::
+
+   <DEVICE>-<SPEED>-<PACKAGE>
+   <DEVICE>-<PACKAGE>-<SPEED>
+
 Libero
 ------
 
@@ -87,6 +94,19 @@ Example:
 
    prj = Libero()
 
+Valid PART formats:
+
+.. code::
+
+   <DEVICE>-<PACKAGE>
+   <DEVICE>-<SPEED><PACKAGE>
+   <DEVICE>-<SPEED>-<PACKAGE>
+   <DEVICE>-<PACKAGE>-<SPEED>
+   <DEVICE>-<PACKAGE><RANGE>
+   <DEVICE>-<SPEED><PACKAGE><RANGE>
+   <DEVICE>-<SPEED>-<PACKAGE><RANGE>
+   <DEVICE>-<PACKAGE><RANGE>-<SPEED>
+
 Openflow
 --------
 
@@ -116,6 +136,12 @@ Example:
 
    prj = Openflow()
 
+Valid PART formats:
+
+.. code::
+
+   <DEVICE>-<PACKAGE>
+
 Quartus
 -------
 
diff --git a/pyfpga/ise.py b/pyfpga/ise.py
index 03eb8707..5ca52f8a 100644
--- a/pyfpga/ise.py
+++ b/pyfpga/ise.py
@@ -43,9 +43,9 @@ def get_info(part):
     """Get info about the FPGA part.
 
     :param part: the FPGA part as specified by the tool
-    :returns: a dictionary with the keys family, device, speed and package
+    :returns: a dict with the keys family, device, speed and package
     """
-    part = part.lower()
+    part = part.lower().replace(' ', '')
     # Looking for the family
     family = None
     families = {
@@ -71,7 +71,7 @@ def get_info(part):
         if re.match(key, part):
             family = value
             break
-    # Looking for the device, package and speed
+    # Looking for the other values
     device = None
     speed = None
     package = None
@@ -79,16 +79,18 @@ def get_info(part):
     if len(aux) == 3:
         device = aux[0]
         if len(aux[1]) < len(aux[2]):
-            speed = aux[1]
+            speed = f'-{aux[1]}'
             package = aux[2]
         else:
-            speed = aux[2]
+            speed = f'-{aux[2]}'
             package = aux[1]
     else:
-        raise ValueError(
-            'Part must be DEVICE-SPEED-PACKAGE or DEVICE-PACKAGE-SPEED'
-        )
+        valid = 'DEVICE-SPEED-PACKAGE or DEVICE-PACKAGE-SPEED'
+        raise ValueError(f'Invalid PART format ({valid})')
     # Finish
     return {
-        'family': family, 'device': device, 'speed': speed, 'package': package
+        'family': family,
+        'device': device,
+        'speed': speed,
+        'package': package
     }
diff --git a/pyfpga/libero.py b/pyfpga/libero.py
index 6f1bda0f..e0ab20df 100644
--- a/pyfpga/libero.py
+++ b/pyfpga/libero.py
@@ -14,7 +14,7 @@
 
 
 class Libero(Project):
-    """Class to support Libero."""
+    """Class to support Libero projects."""
 
     def _configure(self):
         tool = 'libero'
@@ -45,12 +45,12 @@ def get_info(part):
     :param part: the FPGA part as specified by the tool
     :returns: a dict with the keys family, device, speed, package and prange
     """
-    part = part.lower()
+    part = part.lower().replace(' ', '')
     # Looking for the family
     family = None
     families = {
         r'm2s': 'SmartFusion2',
-        r'm2gl': 'Igloo2',
+        r'm2gl': 'IGLOO2',
         r'rt4g': 'RTG4',
         r'mpfs': 'PolarFireSoC',
         r'mpf': 'PolarFire',
@@ -67,7 +67,7 @@ def get_info(part):
         if re.match(key, part):
             family = value
             break
-    # Looking for the device, speed and package
+    # Looking for the other values
     device = None
     speed = None
     package = None
@@ -75,8 +75,12 @@ def get_info(part):
     aux = part.split('-')
     if len(aux) == 2:
         device = aux[0]
-        speed = 'STD'
         package = aux[1]
+        if package[0].isdigit():
+            speed = f'-{package[0]}'
+            package = package[1:]
+        else:
+            speed = 'STD'
     elif len(aux) == 3:
         device = aux[0]
         if len(aux[1]) < len(aux[2]):
@@ -86,10 +90,8 @@ def get_info(part):
             speed = f'-{aux[2]}'
             package = aux[1]
     else:
-        raise ValueError(
-            'Part must be DEVICE-SPEED-PACKAGE or DEVICE-PACKAGE'
-        )
-    # Looking for a part_range
+        valid = 'DEVICE-[SPEED][-]PACKAGE[PRANGE][-SPEED]'
+        raise ValueError(f'Invalid PART format ({valid})')
     pranges = {
         'c': 'COM',
         'e': 'EXT',
diff --git a/pyfpga/openflow.py b/pyfpga/openflow.py
index 07cefac4..25ab9fc4 100644
--- a/pyfpga/openflow.py
+++ b/pyfpga/openflow.py
@@ -34,9 +34,9 @@ def get_info(part):
     """Get info about the FPGA part.
 
     :param part: the FPGA part as specified by the tool
-    :returns: a dictionary with the keys family, device and package
+    :returns: a dict with the keys family, device and package
     """
-    part = part.lower()
+    part = part.lower().replace(' ', '')
     # Looking for the family
     family = None
     families = [
@@ -62,7 +62,7 @@ def get_info(part):
     ]
     if part.startswith(tuple(families)):
         family = 'ecp5'
-    # Looking for the device and package
+    # Looking for the other values
     device = None
     package = None
     aux = part.split('-')
@@ -73,11 +73,16 @@ def get_info(part):
         device = f'{aux[0]}-{aux[1]}'
         package = aux[2]
     else:
-        raise ValueError('Part must be DEVICE-PACKAGE')
+        valid = 'DEVICE-PACKAGE'
+        raise ValueError(f'Invalid PART format ({valid})')
     if family in ['lp4k', 'hx4k']:  # See http://www.clifford.at/icestorm
         device = device.replace('4', '8')
         package += ":4k"
     if family == 'ecp5':
         package = package.upper()
     # Finish
-    return {'family': family, 'device': device, 'package': package}
+    return {
+        'family': family,
+        'device': device,
+        'package': package
+    }
diff --git a/pyfpga/templates/ise.jinja b/pyfpga/templates/ise.jinja
index c90f2d5e..54803e9b 100644
--- a/pyfpga/templates/ise.jinja
+++ b/pyfpga/templates/ise.jinja
@@ -13,7 +13,7 @@ project new {{ project }}.xise
 project set family  {{ family }}
 project set device  {{ device }}
 project set package {{ package }}
-project set speed  -{{ speed }}
+project set speed   {{ speed }}
 
 {% if hooks %}{{ hooks.precfg | join('\n') }}{% endif %}
 
diff --git a/tests/test_part.py b/tests/test_part.py
index 5319e3dc..1d155aa8 100644
--- a/tests/test_part.py
+++ b/tests/test_part.py
@@ -7,25 +7,105 @@ def test_ise():
     info = {
         'family': 'kintex7',
         'device': 'xc7k160t',
-        'speed': '3',
+        'speed': '-3',
         'package': 'fbg484'
     }
     assert get_info_ise('xc7k160t-3-fbg484') == info
     assert get_info_ise('xc7k160t-fbg484-3') == info
+    info['speed'] = '-3l'
+    assert get_info_ise('xc7k160t-3L-fbg484') == info
+    assert get_info_ise('xc7k160t-fbg484-3L') == info
 
 
 def test_libero():
     info = {
         'family': 'SmartFusion2',
-        'device': 'm2s010',
-        'speed': '-1',
-        'package': 'tq144',
+        'device': 'm2s025t',
+        'speed': 'STD',
+        'package': 'fg484',
         'prange': 'COM'
     }
-    assert get_info_libero('m2s010-1-tq144') == info
-    assert get_info_libero('m2s010-tq144-1') == info
-    info['speed'] = 'STD'
-    assert get_info_libero('m2s010-tq144') == info
+    assert get_info_libero('M2S025T-FG484') == info
+    info['prange'] = 'IND'
+    assert get_info_libero('M2S025T-FG484I') == info
+    info['speed'] = '-1'
+    info['prange'] = 'COM'
+    assert get_info_libero('M2S025T-1FG484') == info
+    assert get_info_libero('M2S025T-1-FG484') == info
+    assert get_info_libero('M2S025T-FG484-1') == info
+    info['prange'] = 'IND'
+    assert get_info_libero('M2S025T-1FG484I') == info
+    assert get_info_libero('M2S025T-1-FG484I') == info
+    assert get_info_libero('M2S025T-FG484I-1') == info
+    info['prange'] = 'MIL'
+    assert get_info_libero('M2S025T-1FG484M') == info
+    assert get_info_libero('M2S025T-1-FG484M') == info
+    assert get_info_libero('M2S025T-FG484M-1') == info
+    info = {
+        'family': 'IGLOO2',
+        'device': 'm2gl025',
+        'speed': 'STD',
+        'package': 'fg484',
+        'prange': 'COM'
+    }
+    assert get_info_libero('M2GL025-FG484') == info
+    info['prange'] = 'IND'
+    assert get_info_libero('M2GL025-FG484I') == info
+    info['speed'] = '-1'
+    info['prange'] = 'COM'
+    assert get_info_libero('M2GL025-1FG484') == info
+    assert get_info_libero('M2GL025-1-FG484') == info
+    assert get_info_libero('M2GL025-FG484-1') == info
+    info['prange'] = 'IND'
+    assert get_info_libero('M2GL025-1FG484I') == info
+    assert get_info_libero('M2GL025-1-FG484I') == info
+    assert get_info_libero('M2GL025-FG484I-1') == info
+    info['prange'] = 'MIL'
+    assert get_info_libero('M2GL025-1FG484M') == info
+    assert get_info_libero('M2GL025-1-FG484M') == info
+    assert get_info_libero('M2GL025-FG484M-1') == info
+    info['prange'] = 'TGrade1'
+    assert get_info_libero('M2GL025-1FG484T1') == info
+    assert get_info_libero('M2GL025-1-FG484T1') == info
+    assert get_info_libero('M2GL025-FG484T1-1') == info
+    info = {
+        'family': 'PolarFire',
+        'device': 'mpf300ts_es',
+        'speed': 'STD',
+        'package': 'fg484',
+        'prange': 'EXT'
+    }
+    assert get_info_libero('MPF300TS_ES-FG484E') == info
+    info['prange'] = 'IND'
+    assert get_info_libero('MPF300TS_ES-FG484I') == info
+    info['speed'] = '-1'
+    info['prange'] = 'EXT'
+    assert get_info_libero('MPF300TS_ES-1FG484E') == info
+    assert get_info_libero('MPF300TS_ES-1-FG484E') == info
+    assert get_info_libero('MPF300TS_ES-FG484E-1') == info
+    info['prange'] = 'IND'
+    assert get_info_libero('MPF300TS_ES-1FG484I') == info
+    assert get_info_libero('MPF300TS_ES-1-FG484I') == info
+    assert get_info_libero('MPF300TS_ES-FG484I-1') == info
+    info = {
+        'family': 'PolarFireSoC',
+        'device': 'mpfs025t',
+        'speed': 'STD',
+        'package': 'fcvg484',
+        'prange': 'EXT'
+    }
+    assert get_info_libero('MPFS025T-FCVG484E') == info
+    info['prange'] = 'IND'
+    assert get_info_libero('MPFS025T-FCVG484I') == info
+    info['speed'] = '-1'
+    info['prange'] = 'EXT'
+    assert get_info_libero('MPFS025T-1FCVG484E') == info
+    assert get_info_libero('MPFS025T-1-FCVG484E') == info
+    assert get_info_libero('MPFS025T-FCVG484E-1') == info
+    info['prange'] = 'IND'
+    assert get_info_libero('MPFS025T-1FCVG484I') == info
+    assert get_info_libero('MPFS025T-1-FCVG484I') == info
+    assert get_info_libero('MPFS025T-FCVG484I-1') == info
 
 
 def test_openflow():

From 167fbeb84b0c05a1b2b7b83c62766387dcadb2a4 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Mon, 11 Nov 2024 23:46:59 -0300
Subject: [PATCH 243/248] Initial support for Libero programming

---
 pyfpga/libero.py                     | 12 +++++-------
 pyfpga/templates/libero-prog.jinja   | 14 ++++++--------
 pyfpga/templates/openflow-prog.jinja |  1 +
 3 files changed, 12 insertions(+), 15 deletions(-)

diff --git a/pyfpga/libero.py b/pyfpga/libero.py
index e0ab20df..01800102 100644
--- a/pyfpga/libero.py
+++ b/pyfpga/libero.py
@@ -21,9 +21,9 @@ def _configure(self):
         self.conf['tool'] = tool
         self.conf['make_cmd'] = f'{tool} SCRIPT:{tool}.tcl'
         self.conf['make_ext'] = 'tcl'
-        self.conf['prog_bit'] = None
-        self.conf['prog_cmd'] = None
-        self.conf['prog_ext'] = None
+        self.conf['prog_bit'] = 'pdd'
+        self.conf['prog_cmd'] = f'{tool} SCRIPT:{tool}-prog.tcl'
+        self.conf['prog_ext'] = 'tcl'
 
     def _make_custom(self):
         info = get_info(self.data.get('part', 'mpf100t-1-fcg484'))
@@ -33,9 +33,6 @@ def _make_custom(self):
         self.data['package'] = info['package']
         self.data['prange'] = info['prange']
 
-    def _prog_custom(self):
-        raise NotImplementedError('Libero programming not supported yet')
-
 
 # pylint: disable=duplicate-code
 
@@ -97,7 +94,8 @@ def get_info(part):
         'e': 'EXT',
         'i': 'IND',
         'm': 'MIL',
-        't1': 'TGrade1'
+        't1': 'TGrade1',
+        't2': 'TGrade2'
     }
     prange = 'COM'
     for suffix, name in pranges.items():
diff --git a/pyfpga/templates/libero-prog.jinja b/pyfpga/templates/libero-prog.jinja
index f2369645..df37dc0b 100644
--- a/pyfpga/templates/libero-prog.jinja
+++ b/pyfpga/templates/libero-prog.jinja
@@ -1,14 +1,12 @@
+{#
 #
-# Copyright (C) 2015-2024 PyFPGA Project
+# Copyright (C) 2024 PyFPGA Project
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
 #}
 
-# open_project -file {$TEMPDIR/libero.prjx}
-# run_tool -name {CONFIGURE_CHAIN} -script {$TEMPDIR/flashpro.tcl}
-# run_tool -name {PROGRAMDEVICE}
-
-# set flashpro_programmer "configure_flashpro5_prg -vpump {ON} \
-# -clk_mode {free_running_clk} -programming_method {spi_slave} \
-# -force_freq {OFF} -freq {4000000}"
+if { [catch {open_project {{ project }}/{{ project }}.prjx} ] } {
+  open_project {{ project }}.prjx
+}
+run_tool -name {PROGRAMDEVICE}
diff --git a/pyfpga/templates/openflow-prog.jinja b/pyfpga/templates/openflow-prog.jinja
index 7956b2b3..5055b505 100644
--- a/pyfpga/templates/openflow-prog.jinja
+++ b/pyfpga/templates/openflow-prog.jinja
@@ -1,3 +1,4 @@
+{#
 #
 # Copyright (C) 2020-2024 PyFPGA Project
 #

From 113f78dcee91516a97c51bdc33219b1471df99ee Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 23 Nov 2024 23:44:02 -0300
Subject: [PATCH 244/248] Modified to employ absolute paths when a bitstream is
 specified

---
 pyfpga/project.py | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/pyfpga/project.py b/pyfpga/project.py
index 10bb57ea..b49b2174 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -253,6 +253,9 @@ def prog(self, bitstream=None, position=1):
         self.logger.info('Programming')
         if not bitstream:
             bitstream = f'{self.data["project"]}.{self.conf["prog_bit"]}'
+        else:
+            bitstream = Path(bitstream).resolve().as_posix()
+        self.data['bitstream'] = bitstream
         self._prog_custom()
         self._create_file(f'{self.conf["tool"]}-prog', self.conf['prog_ext'])
         self._run(self.conf['prog_cmd'], 'prog.log')

From c4340abeefe16b8710bb949459daebb41229b690 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sat, 23 Nov 2024 23:44:46 -0300
Subject: [PATCH 245/248] Improved Libero programming support

---
 pyfpga/libero.py                   |  4 ++--
 pyfpga/templates/libero-prog.jinja | 11 +++++++----
 pyfpga/templates/libero.jinja      |  1 +
 3 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/pyfpga/libero.py b/pyfpga/libero.py
index 01800102..b0661d14 100644
--- a/pyfpga/libero.py
+++ b/pyfpga/libero.py
@@ -21,8 +21,8 @@ def _configure(self):
         self.conf['tool'] = tool
         self.conf['make_cmd'] = f'{tool} SCRIPT:{tool}.tcl'
         self.conf['make_ext'] = 'tcl'
-        self.conf['prog_bit'] = 'pdd'
-        self.conf['prog_cmd'] = f'{tool} SCRIPT:{tool}-prog.tcl'
+        self.conf['prog_bit'] = 'ppd'
+        self.conf['prog_cmd'] = f'FPExpress SCRIPT:{tool}-prog.tcl'
         self.conf['prog_ext'] = 'tcl'
 
     def _make_custom(self):
diff --git a/pyfpga/templates/libero-prog.jinja b/pyfpga/templates/libero-prog.jinja
index df37dc0b..3dba4fd8 100644
--- a/pyfpga/templates/libero-prog.jinja
+++ b/pyfpga/templates/libero-prog.jinja
@@ -6,7 +6,10 @@
 #
 #}
 
-if { [catch {open_project {{ project }}/{{ project }}.prjx} ] } {
-  open_project {{ project }}.prjx
-}
-run_tool -name {PROGRAMDEVICE}
+file delete -force -- libero-prog
+new_project -name libero -location libero-prog -mode single
+
+set_programming_file -file {{ bitstream }}
+set_programming_action -action {PROGRAM}
+
+run_selected_actions
diff --git a/pyfpga/templates/libero.jinja b/pyfpga/templates/libero.jinja
index 499a9230..71b9afc1 100644
--- a/pyfpga/templates/libero.jinja
+++ b/pyfpga/templates/libero.jinja
@@ -113,6 +113,7 @@ run_tool -name {VERIFYTIMING}
 {% if hooks %}{{ hooks.prebit | join('\n') }}{% endif %}
 
 run_tool -name {GENERATEPROGRAMMINGFILE}
+catch { file copy -force {{ project }}/designer/{{ top }}/{{ top }}.ppd {{ project }}.ppd }
 
 {% if hooks %}{{ hooks.postbit | join('\n') }}{% endif %}
 

From aa24928256aafe93b0b5a0a5b17436cb961bd840 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 24 Nov 2024 13:15:04 -0300
Subject: [PATCH 246/248] Add to check if the bitstream exists

---
 pyfpga/project.py | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/pyfpga/project.py b/pyfpga/project.py
index b49b2174..b5d947ac 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -245,6 +245,7 @@ def prog(self, bitstream=None, position=1):
         :param position: position of the device in the JTAG chain
         :type position: str, optional
         :raises ValueError: for missing or wrong values
+        :raises FileNotFoundError: when bitstream is not found
         :raises RuntimeError: error running the needed underlying tool
         """
         self.logger.debug('Executing prog')
@@ -255,6 +256,8 @@ def prog(self, bitstream=None, position=1):
             bitstream = f'{self.data["project"]}.{self.conf["prog_bit"]}'
         else:
             bitstream = Path(bitstream).resolve().as_posix()
+        if not os.path.exists(bitstream):
+            raise FileNotFoundError(bitstream)
         self.data['bitstream'] = bitstream
         self._prog_custom()
         self._create_file(f'{self.conf["tool"]}-prog', self.conf['prog_ext'])

From 3666ac73500dc8b742659b2954e1c4215a271e5e Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 24 Nov 2024 13:52:51 -0300
Subject: [PATCH 247/248] ise: replace file rename by copy

---
 pyfpga/templates/ise.jinja | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pyfpga/templates/ise.jinja b/pyfpga/templates/ise.jinja
index 54803e9b..34577302 100644
--- a/pyfpga/templates/ise.jinja
+++ b/pyfpga/templates/ise.jinja
@@ -94,7 +94,7 @@ if { [process get "Place & Route" status] == "errors" } { exit 1 }
 
 process run "Generate Programming File"
 if { [process get "Generate Programming File" status] == "errors" } { exit 1 }
-catch { file rename -force {{ top }}.bit {{ project }}.bit }
+catch { file copy -force {{ top }}.bit {{ project }}.bit }
 
 {% if hooks %}{{ hooks.postbit | join('\n') }}{% endif %}
 

From ef4ae95cd67c132253200d4209f2bda4092467d9 Mon Sep 17 00:00:00 2001
From: "Rodrigo A. Melo" <rodrigomelo9@gmail.com>
Date: Sun, 24 Nov 2024 22:59:15 -0300
Subject: [PATCH 248/248] Improve bitstream handling

---
 pyfpga/diamond.py                    |  2 +-
 pyfpga/ise.py                        |  2 +-
 pyfpga/libero.py                     |  2 +-
 pyfpga/openflow.py                   |  6 +++++-
 pyfpga/project.py                    | 10 +++++++---
 pyfpga/quartus.py                    |  2 +-
 pyfpga/templates/openflow-prog.jinja |  4 ++--
 pyfpga/vivado.py                     |  2 +-
 tests/mocks/FPExpress                | 25 +++++++++++++++++++++++++
 tests/mocks/libero                   | 13 ++++++++++++-
 tests/mocks/quartus_sh               |  9 +++++++++
 tests/mocks/vivado                   |  9 +++++++++
 tests/mocks/xtclsh                   |  9 +++++++++
 tests/test_tools.py                  |  8 ++++++++
 14 files changed, 91 insertions(+), 12 deletions(-)
 create mode 100755 tests/mocks/FPExpress

diff --git a/pyfpga/diamond.py b/pyfpga/diamond.py
index a5b3e622..01226a6d 100644
--- a/pyfpga/diamond.py
+++ b/pyfpga/diamond.py
@@ -21,7 +21,7 @@ def _configure(self):
         self.conf['tool'] = tool
         self.conf['make_cmd'] = f'{executable} {tool}.tcl'
         self.conf['make_ext'] = 'tcl'
-        self.conf['prog_bit'] = 'bit'
+        self.conf['prog_bit'] = ['bit']
         self.conf['prog_cmd'] = f'sh {tool}-prog.sh'
         self.conf['prog_ext'] = 'sh'
 
diff --git a/pyfpga/ise.py b/pyfpga/ise.py
index 5ca52f8a..048b140b 100644
--- a/pyfpga/ise.py
+++ b/pyfpga/ise.py
@@ -21,7 +21,7 @@ def _configure(self):
         self.conf['tool'] = tool
         self.conf['make_cmd'] = f'xtclsh {tool}.tcl'
         self.conf['make_ext'] = 'tcl'
-        self.conf['prog_bit'] = 'bit'
+        self.conf['prog_bit'] = ['bit']
         self.conf['prog_cmd'] = f'impact -batch {tool}-prog.tcl'
         self.conf['prog_ext'] = 'tcl'
 
diff --git a/pyfpga/libero.py b/pyfpga/libero.py
index b0661d14..37c56650 100644
--- a/pyfpga/libero.py
+++ b/pyfpga/libero.py
@@ -21,7 +21,7 @@ def _configure(self):
         self.conf['tool'] = tool
         self.conf['make_cmd'] = f'{tool} SCRIPT:{tool}.tcl'
         self.conf['make_ext'] = 'tcl'
-        self.conf['prog_bit'] = 'ppd'
+        self.conf['prog_bit'] = ['ppd', 'stp', 'bit', 'jed']
         self.conf['prog_cmd'] = f'FPExpress SCRIPT:{tool}-prog.tcl'
         self.conf['prog_ext'] = 'tcl'
 
diff --git a/pyfpga/openflow.py b/pyfpga/openflow.py
index 25ab9fc4..299abc7c 100644
--- a/pyfpga/openflow.py
+++ b/pyfpga/openflow.py
@@ -19,7 +19,7 @@ def _configure(self):
         self.conf['tool'] = tool
         self.conf['make_cmd'] = f'bash {tool}.sh'
         self.conf['make_ext'] = 'sh'
-        self.conf['prog_bit'] = 'bit'
+        self.conf['prog_bit'] = ['svf', 'bit']
         self.conf['prog_cmd'] = f'bash {tool}-prog.sh'
         self.conf['prog_ext'] = 'sh'
 
@@ -29,6 +29,10 @@ def _make_custom(self):
         self.data['device'] = info['device']
         self.data['package'] = info['package']
 
+    def _prog_custom(self):
+        info = get_info(self.data.get('part', 'hx8k-ct256'))
+        self.data['family'] = info['family']
+
 
 def get_info(part):
     """Get info about the FPGA part.
diff --git a/pyfpga/project.py b/pyfpga/project.py
index b5d947ac..75eaec47 100644
--- a/pyfpga/project.py
+++ b/pyfpga/project.py
@@ -253,10 +253,14 @@ def prog(self, bitstream=None, position=1):
             raise ValueError('Invalid position.')
         self.logger.info('Programming')
         if not bitstream:
-            bitstream = f'{self.data["project"]}.{self.conf["prog_bit"]}'
+            for ext in self.conf['prog_bit']:
+                candidate = Path(self.odir) / f'{self.data["project"]}.{ext}'
+                if candidate.exists():
+                    bitstream = candidate.resolve()
+                    break
         else:
-            bitstream = Path(bitstream).resolve().as_posix()
-        if not os.path.exists(bitstream):
+            bitstream = Path(bitstream).resolve()
+        if not bitstream or not bitstream.exists():
             raise FileNotFoundError(bitstream)
         self.data['bitstream'] = bitstream
         self._prog_custom()
diff --git a/pyfpga/quartus.py b/pyfpga/quartus.py
index 8cd8f66a..747c6628 100644
--- a/pyfpga/quartus.py
+++ b/pyfpga/quartus.py
@@ -19,7 +19,7 @@ def _configure(self):
         self.conf['tool'] = tool
         self.conf['make_cmd'] = f'quartus_sh --script {tool}.tcl'
         self.conf['make_ext'] = 'tcl'
-        self.conf['prog_bit'] = 'sof'
+        self.conf['prog_bit'] = ['sof', 'pof']
         self.conf['prog_cmd'] = f'bash {tool}-prog.tcl'
         self.conf['prog_ext'] = 'tcl'
 
diff --git a/pyfpga/templates/openflow-prog.jinja b/pyfpga/templates/openflow-prog.jinja
index 5055b505..b26de159 100644
--- a/pyfpga/templates/openflow-prog.jinja
+++ b/pyfpga/templates/openflow-prog.jinja
@@ -11,7 +11,7 @@ set -e
 DOCKER="docker run --user $(id -u):$(id -g) --rm -v $HOME:$HOME -w $PWD"
 
 {% if family == 'ecp5' %}
-$DOCKER --device /dev/bus/usb hdlc/prog openocd -f /usr/share/trellis/misc/openocd/ecp5-evn.cfg -c "transport select jtag; init; svf {{ project }}.svf; exit"
+$DOCKER --device /dev/bus/usb hdlc/prog openocd -f /usr/share/trellis/misc/openocd/ecp5-evn.cfg -c "transport select jtag; init; svf {{ bitstream }}; exit"
 {% else %}
-$DOCKER --device /dev/bus/usb hdlc/prog iceprog {{ project }}.bit
+$DOCKER --device /dev/bus/usb hdlc/prog iceprog {{ bitstream }}
 {% endif %}
diff --git a/pyfpga/vivado.py b/pyfpga/vivado.py
index 0391a17f..2b04819d 100644
--- a/pyfpga/vivado.py
+++ b/pyfpga/vivado.py
@@ -20,7 +20,7 @@ def _configure(self):
         self.conf['tool'] = tool
         self.conf['make_cmd'] = f'{command} {tool}.tcl'
         self.conf['make_ext'] = 'tcl'
-        self.conf['prog_bit'] = 'bit'
+        self.conf['prog_bit'] = ['bit']
         self.conf['prog_cmd'] = f'{command} {tool}-prog.tcl'
         self.conf['prog_ext'] = 'tcl'
 
diff --git a/tests/mocks/FPExpress b/tests/mocks/FPExpress
new file mode 100755
index 00000000..8947406b
--- /dev/null
+++ b/tests/mocks/FPExpress
@@ -0,0 +1,25 @@
+#!/usr/bin/env python3
+
+#
+# Copyright (C) 2024 PyFPGA Project
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+
+import argparse
+import sys
+
+
+parser = argparse.ArgumentParser()
+
+parser.add_argument('source')
+
+args = parser.parse_args()
+
+tool = parser.prog
+
+if not args.source.startswith("SCRIPT:", 0):
+    print('ERROR:the parameter should start width "SCRIPT:"')
+    sys.exit(1)
+
+print(f'INFO:the {tool.upper()} mock has been executed')
diff --git a/tests/mocks/libero b/tests/mocks/libero
index 510b9926..94c8dd05 100755
--- a/tests/mocks/libero
+++ b/tests/mocks/libero
@@ -7,6 +7,7 @@
 #
 
 import argparse
+import re
 import subprocess
 import sys
 
@@ -23,10 +24,12 @@ if not args.source.startswith("SCRIPT:", 0):
     print('ERROR:the parameter should start width "SCRIPT:"')
     sys.exit(1)
 
+args.source = args.source.replace('SCRIPT:', '')
+
 tcl = f'''
 proc unknown args {{ }}
 
-source {args.source.replace('SCRIPT:', '')}
+source {args.source}
 '''
 
 with open(f'{tool}-mock.tcl', 'w', encoding='utf-8') as file:
@@ -39,4 +42,12 @@ subprocess.run(
    universal_newlines=True
 )
 
+pattern = r'new_project\s+-name\s+(\S+)\s'
+with open(args.source, 'r', encoding='utf-8') as file:
+    match = re.search(pattern, file.read())
+    if match:
+        project = match.group(1)
+        with open(f'{project}.ppd', 'w', encoding='utf-8') as file:
+            pass
+
 print(f'INFO:the {tool.upper()} mock has been executed')
diff --git a/tests/mocks/quartus_sh b/tests/mocks/quartus_sh
index 7f437145..38f6507d 100755
--- a/tests/mocks/quartus_sh
+++ b/tests/mocks/quartus_sh
@@ -8,6 +8,7 @@
 
 import argparse
 import os
+import re
 import subprocess
 
 
@@ -41,4 +42,12 @@ subprocess.run(
    universal_newlines=True
 )
 
+pattern = r'project_new\s+(\S+)\s'
+with open(args.script, 'r', encoding='utf-8') as file:
+    match = re.search(pattern, file.read())
+    if match:
+        project = match.group(1)
+        with open(f'{project}.sof', 'w', encoding='utf-8') as file:
+            pass
+
 print(f'INFO:the {tool.upper()} mock has been executed')
diff --git a/tests/mocks/vivado b/tests/mocks/vivado
index 3bc95381..2f5cbe69 100755
--- a/tests/mocks/vivado
+++ b/tests/mocks/vivado
@@ -7,6 +7,7 @@
 #
 
 import argparse
+import re
 import subprocess
 
 
@@ -70,4 +71,12 @@ subprocess.run(
    universal_newlines=True
 )
 
+pattern = r'create_project\s+-force\s+(\S+)'
+with open(args.source, 'r', encoding='utf-8') as file:
+    match = re.search(pattern, file.read())
+    if match:
+        project = match.group(1)
+        with open(f'{project}.bit', 'w', encoding='utf-8') as file:
+            pass
+
 print(f'INFO:the {tool.upper()} mock has been executed')
diff --git a/tests/mocks/xtclsh b/tests/mocks/xtclsh
index 22f66a77..4064f790 100755
--- a/tests/mocks/xtclsh
+++ b/tests/mocks/xtclsh
@@ -7,6 +7,7 @@
 #
 
 import argparse
+import re
 import subprocess
 
 
@@ -34,4 +35,12 @@ subprocess.run(
    universal_newlines=True
 )
 
+pattern = r'project\s+new\s+(\S+)\.xise'
+with open(args.source, 'r', encoding='utf-8') as file:
+    match = re.search(pattern, file.read())
+    if match:
+        project = match.group(1)
+        with open(f'{project}.bit', 'w', encoding='utf-8') as file:
+            pass
+
 print(f'INFO:the {tool.upper()} mock has been executed')
diff --git a/tests/test_tools.py b/tests/test_tools.py
index 98f00055..a2b3e489 100644
--- a/tests/test_tools.py
+++ b/tests/test_tools.py
@@ -9,6 +9,7 @@ def test_diamond():
     generate(tool, 'PARTNAME')
     base = f'results/{tool}/{tool}'
     assert Path(f'{base}.tcl').exists(), 'file not found'
+    assert Path(f'{base}-prog.sh').exists(), 'file not found'
 
 
 def test_ise():
@@ -24,6 +25,7 @@ def test_libero():
     generate(tool, 'DEVICE-PACKAGE-SPEED')
     base = f'results/{tool}/{tool}'
     assert Path(f'{base}.tcl').exists(), 'file not found'
+    assert Path(f'{base}-prog.tcl').exists(), 'file not found'
 
 
 def test_openflow():
@@ -87,6 +89,12 @@ def generate(tool, part):
         prj.make()
     except RuntimeError:
         pass
+    if tool == 'libero':
+        open(f'results/{tool}/{tool}.ppd', 'w').close()
+    elif tool == 'quartus':
+        open(f'results/{tool}/{tool}.sof', 'w').close()
+    else:
+        open(f'results/{tool}/{tool}.bit', 'w').close()
     try:
         prj.prog()
     except RuntimeError: