├── MANIFEST.in ├── docs ├── bugs.rst ├── about.rst ├── tutorial │ └── index.rst ├── flows.rst ├── copyright.rst ├── requirements.txt ├── index.rst ├── contents.rst ├── Makefile ├── quickstart.rst └── conf.py ├── tests ├── resources │ ├── test.v │ ├── cocotb │ │ └── results.xml │ ├── design0 │ │ └── design0.toml │ ├── Fitter_Resource_Utilization_by_Entity.csv │ └── Flow_Summary.csv ├── fake_tools │ ├── vivado │ ├── xtclsh │ ├── quartus_sh │ └── resource │ │ └── fake_vivado_reports ├── __init__.py ├── test_gtkw.py ├── test_cli.py ├── test_verilator.py ├── test_nvc.py ├── test_cocotb.py ├── test_ghdl.py ├── test_ise.py ├── test_yosys.py └── test_vivado.py ├── src └── xeda │ ├── data │ ├── __init__.py │ ├── boards │ │ ├── __init__.py │ │ └── ulx3s │ │ │ └── __init__.py │ └── boards.toml │ ├── flows │ ├── vivado │ │ ├── templates │ │ │ ├── __init__.py │ │ │ ├── vivado_power.tcl │ │ │ ├── clock.xdc │ │ │ └── util.tcl │ │ ├── vivado_postsynthsim.py │ │ └── vivado_power.py │ ├── diamond │ │ └── templates │ │ │ ├── __init__.py │ │ │ ├── constraints.ldc │ │ │ ├── constraints.sdc │ │ │ └── constraints.fdc │ ├── modelsim │ │ ├── templates │ │ │ ├── __init__.py │ │ │ └── run.tcl │ │ └── __init__.py │ ├── openroad │ │ ├── openroad_scripts │ │ │ ├── README.md │ │ │ ├── deletePowerNets.tcl │ │ │ ├── deleteNonClkNets.tcl │ │ │ ├── view_cells.tcl │ │ │ ├── gui.tcl │ │ │ └── LICENSE.md │ │ └── templates │ │ │ ├── filler.tcl │ │ │ ├── orflow.tcl │ │ │ ├── detailed_place.tcl │ │ │ ├── load.tcl │ │ │ ├── clocks.sdc │ │ │ ├── cts.tcl │ │ │ ├── io_place.tcl │ │ │ ├── floorplan.tcl │ │ │ ├── resize.tcl │ │ │ ├── detailed_route.tcl │ │ │ ├── finalize.tcl │ │ │ ├── macros.tcl.j2 │ │ │ ├── global_route.tcl │ │ │ ├── global_place.tcl │ │ │ └── resynth.tcl │ ├── yosys │ │ ├── __init__.py │ │ ├── templates │ │ │ ├── post_rtl.tcl │ │ │ ├── write_netlist.tcl │ │ │ ├── yosys_fpga_synth.tcl │ │ │ └── yosys_synth.tcl │ │ └── cxx_rtl.py │ ├── ise │ │ └── templates │ │ │ ├── constraints.ucf │ │ │ ├── constraints.xcf │ │ │ └── ise_synth.tcl │ ├── openxc7 │ │ └── templates │ │ │ └── constraints.xdc │ ├── quartus │ │ ├── templates │ │ │ ├── clock.sdc │ │ │ ├── settings.dse │ │ │ └── create_project.tcl │ │ └── quartus_dse.py │ ├── dc │ │ └── templates │ │ │ └── constraints.sdc │ ├── __init__.py │ └── openfpgaloader.py │ ├── console.py │ ├── platforms │ ├── sky130hs │ │ ├── tapcell.tcl │ │ ├── fastroute.tcl │ │ ├── fastroute_base.tcl │ │ ├── cells_clkgate_hs.v │ │ ├── cells_latch_hs.v │ │ ├── make_tracks.tcl │ │ ├── setRC.tcl │ │ ├── cells_adders_hs.v │ │ └── pdn.tcl │ ├── sky130hd │ │ ├── tapcell.tcl │ │ ├── lib │ │ │ └── sky130_fd_sc_hd__tt_025C_1v80.lib.gz │ │ ├── fastroute.tcl │ │ ├── fastroute_base.tcl │ │ ├── cells_clkgate_hd.v │ │ ├── cells_latch_hd.v │ │ ├── make_tracks.tcl │ │ ├── setRC.tcl │ │ ├── cells_adders_hd.v │ │ └── pdn.tcl │ ├── nangate45 │ │ ├── tapcell.tcl │ │ ├── gds │ │ │ ├── NangateOpenCellLibrary.gds │ │ │ └── NangateOpenCellLibrary.gds.orig │ │ ├── lib │ │ │ └── NangateOpenCellLibrary_typical.lib.gz │ │ ├── fastroute.tcl │ │ ├── cells_clkgate.v │ │ ├── template_pga.cfg │ │ ├── cells_latch.v │ │ ├── README.md │ │ ├── make_tracks.tcl │ │ ├── setRC.tcl │ │ ├── fakeram.tcl │ │ ├── cells_adders.v │ │ ├── grid_strategy-M1-M4-M7.tcl │ │ └── fakeram.cfg │ ├── asap7 │ │ ├── openlane │ │ │ ├── README │ │ │ ├── mapping.json │ │ │ └── asap7sc7p5t │ │ │ │ ├── config.tcl │ │ │ │ └── no_synth.cells │ │ ├── yosys │ │ │ ├── cells_clkgate_L.v │ │ │ ├── cells_clkgate_R.v │ │ │ ├── cells_clkgate_SL.v │ │ │ ├── cells_latch_L.v │ │ │ ├── cells_latch_R.v │ │ │ ├── cells_latch_SL.v │ │ │ ├── cells_adders_L.v │ │ │ ├── cells_adders_R.v │ │ │ └── cells_adders_SL.v │ │ ├── openroad │ │ │ ├── tapcell.tcl │ │ │ ├── pdn │ │ │ │ ├── pdn.cfg │ │ │ │ └── grid_strategy-M1-M2-M5-M6.tcl │ │ │ ├── post_mergeLib.py │ │ │ └── make_tracks.tcl │ │ ├── setRC.tcl │ │ ├── fakeram.cfg │ │ ├── config.lvt.toml │ │ └── config.slvt.toml │ ├── __init__.py │ ├── mk_to_toml.py │ └── platform.py │ ├── types.py │ ├── flow_runner │ ├── dse │ │ └── __init__.py │ └── __init__.py │ ├── version.py │ ├── __init__.py │ ├── flow │ ├── __init__.py │ └── sim.py │ ├── board.py │ └── units.py ├── .gitattributes ├── xeda.png ├── examples ├── boards │ └── ulx3s │ │ ├── dvi_test │ │ ├── ecp5pll.vhdl │ │ ├── gen_pll.py │ │ ├── xedaproject.toml │ │ ├── blink.vhd │ │ └── utils_pkg.vhdl │ │ └── blinky │ │ ├── blinky.xeda.yaml │ │ ├── blinky_vhdl.xeda.yaml │ │ ├── blinky.v │ │ └── xedaproject.toml ├── requirements.txt ├── sv │ └── fifo │ │ ├── fifo_cocotb.xeda.yaml │ │ ├── fifo.xeda.yaml │ │ └── fifo.sv ├── mixed_language │ └── blink │ │ ├── xedaproject.toml │ │ ├── blink.sv │ │ ├── blinky.xeda.toml │ │ └── blink_tb.cpp └── vhdl │ ├── full_adder.vhd │ ├── pipeline │ ├── pipelined_adder.toml │ ├── synthesize.py │ └── pipelined_adder.vhdl │ ├── Trivium │ ├── trivium.xeda.yaml │ └── trivium.toml │ ├── xedaproject.toml │ ├── sqrt │ ├── sqrt.toml │ ├── test.py │ └── tb_sqrt.py │ ├── full_adder_piped.vhd │ └── full_adder_tb.vhd ├── notebooks └── requirements.txt ├── .github ├── dependabot.yml └── workflows │ ├── dependency-review.yml │ ├── python-publish.yml │ ├── ci.yml │ └── codeql.yml ├── .readthedocs.yml ├── TODO.md ├── CHANGELOG.md ├── .pre-commit-config.yaml ├── tox.ini ├── .gitignore └── get_oss_cad_suite.py /MANIFEST.in: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/bugs.rst: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/about.rst: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/tutorial/index.rst: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/resources/test.v: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/xeda/data/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/xeda/data/boards/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/xeda/data/boards/ulx3s/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/fake_tools/vivado: -------------------------------------------------------------------------------- 1 | fake_tool.py -------------------------------------------------------------------------------- /tests/fake_tools/xtclsh: -------------------------------------------------------------------------------- 1 | fake_tool.py -------------------------------------------------------------------------------- /src/xeda/flows/vivado/templates/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/fake_tools/quartus_sh: -------------------------------------------------------------------------------- 1 | fake_tool.py -------------------------------------------------------------------------------- /src/xeda/flows/diamond/templates/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/xeda/flows/modelsim/templates/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | src/xeda/_version.py export-subst 2 | -------------------------------------------------------------------------------- /docs/flows.rst: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Flows 5 | ----- 6 | 7 | -------------------------------------------------------------------------------- /xeda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XedaHQ/xeda/HEAD/xeda.png -------------------------------------------------------------------------------- /examples/boards/ulx3s/dvi_test/ecp5pll.vhdl: -------------------------------------------------------------------------------- 1 | ../blinky/ecp5pll.vhdl -------------------------------------------------------------------------------- /src/xeda/console.py: -------------------------------------------------------------------------------- 1 | from rich.console import Console 2 | 3 | console = Console() 4 | -------------------------------------------------------------------------------- /src/xeda/platforms/sky130hs/tapcell.tcl: -------------------------------------------------------------------------------- 1 | tapcell \ 2 | -distance 14 \ 3 | -tapcell_master "sky130_fd_sc_hs__tap_1" 4 | -------------------------------------------------------------------------------- /src/xeda/platforms/sky130hd/tapcell.tcl: -------------------------------------------------------------------------------- 1 | tapcell \ 2 | -distance 14 \ 3 | -tapcell_master "sky130_fd_sc_hd__tapvpwrvgnd_1" 4 | -------------------------------------------------------------------------------- /tests/fake_tools/resource/fake_vivado_reports: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XedaHQ/xeda/HEAD/tests/fake_tools/resource/fake_vivado_reports -------------------------------------------------------------------------------- /src/xeda/flows/openroad/openroad_scripts/README.md: -------------------------------------------------------------------------------- 1 | Scripts are adopted from https://github.com/The-OpenROAD-Project/OpenROAD-flow-scripts 2 | -------------------------------------------------------------------------------- /notebooks/requirements.txt: -------------------------------------------------------------------------------- 1 | pandas 2 | jupyterlab 3 | nbformat 4 | plotly 5 | kaleido 6 | # for bokeh plots: 7 | bokeh 8 | jupyter_bokeh 9 | selenium -------------------------------------------------------------------------------- /src/xeda/platforms/nangate45/tapcell.tcl: -------------------------------------------------------------------------------- 1 | tapcell \ 2 | -distance 120 \ 3 | -tapcell_master "TAPCELL_X1" \ 4 | -endcap_master "TAPCELL_X1" 5 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | TESTS_DIR = Path(__file__).parent.absolute() 4 | RESOURCES_DIR = TESTS_DIR / "resources" 5 | -------------------------------------------------------------------------------- /docs/copyright.rst: -------------------------------------------------------------------------------- 1 | ********* 2 | Copyright 3 | ********* 4 | 5 | XEDA and this documentation is: 6 | 7 | Copyright © 2020 Kamyar Mohajerani. All rights reserved. -------------------------------------------------------------------------------- /src/xeda/flows/diamond/templates/constraints.ldc: -------------------------------------------------------------------------------- 1 | create_clock -period {{ "%.3f"|format(flow.clock_period) }} -name clock [get_ports {{design.rtl.clock_port}}] 2 | -------------------------------------------------------------------------------- /src/xeda/flows/diamond/templates/constraints.sdc: -------------------------------------------------------------------------------- 1 | create_clock -period {{ "%.3f"|format(flow.clock_period) }} -name clock [get_ports {{design.rtl.clock_port}}] 2 | -------------------------------------------------------------------------------- /src/xeda/platforms/nangate45/gds/NangateOpenCellLibrary.gds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XedaHQ/xeda/HEAD/src/xeda/platforms/nangate45/gds/NangateOpenCellLibrary.gds -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: pip 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 -------------------------------------------------------------------------------- /src/xeda/platforms/asap7/openlane/README: -------------------------------------------------------------------------------- 1 | This is for an experimental integration of OpenROAD-flow-scripts into 2 | OpenLane. These files are not used directly by ORFS. 3 | -------------------------------------------------------------------------------- /src/xeda/types.py: -------------------------------------------------------------------------------- 1 | """Type definitions""" 2 | 3 | import os 4 | from pathlib import Path 5 | from typing import Union 6 | 7 | PathLike = Union[str, Path, os.PathLike] 8 | -------------------------------------------------------------------------------- /src/xeda/platforms/__init__.py: -------------------------------------------------------------------------------- 1 | from .asics import AsicsPlatform 2 | from .platform import Platform 3 | 4 | __all__ = [ 5 | "Platform", 6 | "AsicsPlatform", 7 | ] 8 | -------------------------------------------------------------------------------- /src/xeda/platforms/nangate45/gds/NangateOpenCellLibrary.gds.orig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XedaHQ/xeda/HEAD/src/xeda/platforms/nangate45/gds/NangateOpenCellLibrary.gds.orig -------------------------------------------------------------------------------- /src/xeda/platforms/sky130hd/lib/sky130_fd_sc_hd__tt_025C_1v80.lib.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XedaHQ/xeda/HEAD/src/xeda/platforms/sky130hd/lib/sky130_fd_sc_hd__tt_025C_1v80.lib.gz -------------------------------------------------------------------------------- /src/xeda/platforms/nangate45/lib/NangateOpenCellLibrary_typical.lib.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XedaHQ/xeda/HEAD/src/xeda/platforms/nangate45/lib/NangateOpenCellLibrary_typical.lib.gz -------------------------------------------------------------------------------- /src/xeda/flow_runner/dse/__init__.py: -------------------------------------------------------------------------------- 1 | from .dse_runner import Dse, Optimizer 2 | from .fmax import FmaxOptimizer 3 | 4 | __all__ = [ 5 | "Dse", 6 | "Optimizer", 7 | "FmaxOptimizer", 8 | ] 9 | -------------------------------------------------------------------------------- /src/xeda/flows/openroad/templates/filler.tcl: -------------------------------------------------------------------------------- 1 | set_propagated_clock [all_clocks] 2 | 3 | filler_placement {{platform.fill_cells|join(" ")|embrace}} 4 | check_placement 5 | 6 | {{ write_checkpoint(step) }} 7 | -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | sphinx: 4 | configuration: docs/conf.py 5 | fail_on_warning: false 6 | 7 | python: 8 | version: "3.8" 9 | install: 10 | - requirements: docs/requirements.txt 11 | -------------------------------------------------------------------------------- /examples/requirements.txt: -------------------------------------------------------------------------------- 1 | cocotb ~= 2.0.0 2 | cocotb-coverage ~= 2.0.0 3 | setuptools >= 65.0 4 | pytest >= 8.0 5 | # cocolight>=0.0.3 6 | cocolight @ git+https://github.com/kammoh/cocolight.git -------------------------------------------------------------------------------- /src/xeda/platforms/sky130hs/fastroute.tcl: -------------------------------------------------------------------------------- 1 | set_global_routing_layer_adjustment $::env(MIN_ROUTING_LAYER)-$::env(MAX_ROUTING_LAYER) 0.3 2 | 3 | set_routing_layers -signal $::env(MIN_ROUTING_LAYER)-$::env(MAX_ROUTING_LAYER) 4 | -------------------------------------------------------------------------------- /src/xeda/platforms/sky130hd/fastroute.tcl: -------------------------------------------------------------------------------- 1 | set_global_routing_layer_adjustment $::env(MIN_ROUTING_LAYER)-$::env(MAX_ROUTING_LAYER) 0.3 2 | 3 | set_routing_layers -signal $::env(MIN_ROUTING_LAYER)-$::env(MAX_ROUTING_LAYER) 4 | 5 | -------------------------------------------------------------------------------- /src/xeda/platforms/sky130hd/fastroute_base.tcl: -------------------------------------------------------------------------------- 1 | set_global_routing_layer_adjustment $::env(MIN_ROUTING_LAYER)-$::env(MAX_ROUTING_LAYER) 0.3 2 | 3 | set_routing_layers -signal $::env(MIN_ROUTING_LAYER)-$::env(MAX_ROUTING_LAYER) 4 | -------------------------------------------------------------------------------- /src/xeda/platforms/sky130hs/fastroute_base.tcl: -------------------------------------------------------------------------------- 1 | set_global_routing_layer_adjustment $::env(MIN_ROUTING_LAYER)-$::env(MAX_ROUTING_LAYER) 0.3 2 | 3 | set_routing_layers -signal $::env(MIN_ROUTING_LAYER)-$::env(MAX_ROUTING_LAYER) 4 | -------------------------------------------------------------------------------- /examples/sv/fifo/fifo_cocotb.xeda.yaml: -------------------------------------------------------------------------------- 1 | sources: 2 | - fifo.sv 3 | top: fifo 4 | 5 | clock.port: clk 6 | 7 | tb: 8 | sources: 9 | - fifo_tb.py 10 | top: fifo_tb 11 | 12 | flows: 13 | verilator: 14 | timing: false -------------------------------------------------------------------------------- /src/xeda/version.py: -------------------------------------------------------------------------------- 1 | from importlib.metadata import PackageNotFoundError, version 2 | 3 | try: 4 | __version__ = version("xeda") 5 | except PackageNotFoundError: 6 | # package is not installed 7 | __version__ = "unknown" 8 | -------------------------------------------------------------------------------- /examples/mixed_language/blink/xedaproject.toml: -------------------------------------------------------------------------------- 1 | [[design]] 2 | name = "blink" 3 | 4 | [design.rtl] 5 | sources = ["blink.sv"] 6 | 7 | [design.tb] 8 | sources = ["blink_tb.cpp"] 9 | 10 | [flows.cxxrtl] 11 | cxxrtl.filename = "blink.cpp" 12 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx 2 | docutils 3 | sphinx-tabs 4 | sphinx-jinja 5 | sphinxcontrib.bibtex 6 | sphinx_panels 7 | sphinxext.rediraffe 8 | sphinxcontrib.mermaid 9 | sphinxext.opengraph 10 | autodoc_pydantic 11 | sphinx_book_theme 12 | myst-parser -------------------------------------------------------------------------------- /src/xeda/platforms/nangate45/fastroute.tcl: -------------------------------------------------------------------------------- 1 | set_global_routing_layer_adjustment metal2-metal3 0.5 2 | set_global_routing_layer_adjustment metal4-$::env(MAX_ROUTING_LAYER) 0.25 3 | 4 | set_routing_layers -signal $::env(MIN_ROUTING_LAYER)-$::env(MAX_ROUTING_LAYER) 5 | -------------------------------------------------------------------------------- /src/xeda/data/boards.toml: -------------------------------------------------------------------------------- 1 | ## board name _ variant _ version (no dots or otherwise surround with double quotes) 2 | [ULX3S_85F] 3 | name = 'ulx3s' 4 | fpga.part = 'LFE5U-85F-6BG381C' 5 | lpf = 'https://raw.githubusercontent.com/emard/ulx3s/master/doc/constraints/ulx3s_v20.lpf' 6 | -------------------------------------------------------------------------------- /src/xeda/flows/yosys/__init__.py: -------------------------------------------------------------------------------- 1 | from .cxx_rtl import CxxRtl 2 | from .yosys import HiLoMap, Yosys, preproc_libs 3 | from .yosys_fpga import YosysFpga 4 | 5 | __all__ = [ 6 | "Yosys", 7 | "HiLoMap", 8 | "preproc_libs", 9 | "YosysFpga", 10 | "CxxRtl", 11 | ] 12 | -------------------------------------------------------------------------------- /examples/boards/ulx3s/blinky/blinky.xeda.yaml: -------------------------------------------------------------------------------- 1 | sources: ["blinky.v"] 2 | top: blinky 3 | clock.port: "clk_25mhz" 4 | 5 | flows: 6 | openfpgaloader: 7 | clock.freq: 25MHz 8 | nextpnr: 9 | board: ULX3S_85F 10 | yosys_fpga: 11 | fpga.family: ecp5 12 | clock.freq: 25MHz 13 | -------------------------------------------------------------------------------- /src/xeda/flows/ise/templates/constraints.ucf: -------------------------------------------------------------------------------- 1 | {% for clock_name, clock in settings.clocks.items() %} 2 | {% if clock.port %} 3 | NET "{{clock.port}}" TNM_NET = "{{clock.port}}"; 4 | TIMESPEC "TS{{clock.port}}" = PERIOD "{{clock.port}}" {{"%.03f" % clock.period}} ns HIGH 50%; 5 | {% endif %} 6 | {% endfor %} -------------------------------------------------------------------------------- /src/xeda/flows/ise/templates/constraints.xcf: -------------------------------------------------------------------------------- 1 | {% for clock_name, clock in settings.clocks.items() %} 2 | {% if clock.port %} 3 | NET "{{clock.port}}" TNM_NET = "{{clock.port}}"; 4 | TIMESPEC "TS{{clock.port}}" = PERIOD "{{clock.port}}" {{"%.03f" % clock.period}} ns HIGH 50%; 5 | {% endif %} 6 | {% endfor %} -------------------------------------------------------------------------------- /examples/sv/fifo/fifo.xeda.yaml: -------------------------------------------------------------------------------- 1 | sources: 2 | - fifo.sv 3 | top: fifo 4 | 5 | clock.port: clk 6 | 7 | tb: 8 | sources: 9 | - fifo_tb.sv 10 | # - tb/fifo_tb.py 11 | # cocotb: true 12 | # top: fifo_tb 13 | 14 | flows: 15 | verilator: 16 | timing: true 17 | vcd: $PWD/fifo.vcd -------------------------------------------------------------------------------- /src/xeda/platforms/nangate45/cells_clkgate.v: -------------------------------------------------------------------------------- 1 | module OPENROAD_CLKGATE (CK, E, GCK); 2 | input CK; 3 | input E; 4 | output GCK; 5 | 6 | `ifdef OPENROAD_CLKGATE 7 | 8 | CLKGATE_X1 latch (.CK (CK), .E(E), .GCK(GCK)); 9 | 10 | `else 11 | 12 | assign GCK = CK; 13 | 14 | `endif 15 | 16 | endmodule -------------------------------------------------------------------------------- /src/xeda/platforms/sky130hd/cells_clkgate_hd.v: -------------------------------------------------------------------------------- 1 | module OPENROAD_CLKGATE (CK, E, GCK); 2 | input CK; 3 | input E; 4 | output GCK; 5 | 6 | `ifdef OPENROAD_CLKGATE 7 | 8 | sky130_fd_sc_hd__dlclkp_1 latch (.CLK (CK), .GATE(E), .GCLK(GCK)); 9 | 10 | `else 11 | 12 | assign GCK = CK; 13 | 14 | `endif 15 | 16 | endmodule 17 | -------------------------------------------------------------------------------- /src/xeda/platforms/sky130hs/cells_clkgate_hs.v: -------------------------------------------------------------------------------- 1 | module OPENROAD_CLKGATE (CK, E, GCK); 2 | input CK; 3 | input E; 4 | output GCK; 5 | 6 | `ifdef OPENROAD_CLKGATE 7 | 8 | sky130_fd_sc_hs__dlclkp_1 latch (.CLK (CK), .GATE(E), .GCLK(GCK)); 9 | 10 | `else 11 | 12 | assign GCK = CK; 13 | 14 | `endif 15 | 16 | endmodule 17 | -------------------------------------------------------------------------------- /examples/boards/ulx3s/dvi_test/gen_pll.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import logging 3 | from xeda.flows.nextpnr import EcpPLL 4 | 5 | log = logging.getLogger(__name__) 6 | 7 | log.root.setLevel(logging.DEBUG) 8 | 9 | f_pixel = 25.0 10 | 11 | if __name__ == "__main__": 12 | EcpPLL(clkouts=[600]).generate() # type: ignore 13 | -------------------------------------------------------------------------------- /src/xeda/platforms/asap7/yosys/cells_clkgate_L.v: -------------------------------------------------------------------------------- 1 | module OPENROAD_CLKGATE (CK, E, GCK); 2 | input CK; 3 | input E; 4 | output GCK; 5 | 6 | `ifdef OPENROAD_CLKGATE 7 | 8 | ICGx1_ASAP7_75t_L latch ( .CLK(CK), .ENA(E), .SE(1'b0), .GCLK(GCK) ); 9 | 10 | `else 11 | 12 | assign GCK = CK; 13 | 14 | `endif 15 | 16 | endmodule 17 | -------------------------------------------------------------------------------- /src/xeda/platforms/asap7/yosys/cells_clkgate_R.v: -------------------------------------------------------------------------------- 1 | module OPENROAD_CLKGATE (CK, E, GCK); 2 | input CK; 3 | input E; 4 | output GCK; 5 | 6 | `ifdef OPENROAD_CLKGATE 7 | 8 | ICGx1_ASAP7_75t_R latch ( .CLK(CK), .ENA(E), .SE(1'b0), .GCLK(GCK) ); 9 | 10 | `else 11 | 12 | assign GCK = CK; 13 | 14 | `endif 15 | 16 | endmodule 17 | -------------------------------------------------------------------------------- /src/xeda/platforms/asap7/yosys/cells_clkgate_SL.v: -------------------------------------------------------------------------------- 1 | module OPENROAD_CLKGATE (CK, E, GCK); 2 | input CK; 3 | input E; 4 | output GCK; 5 | 6 | `ifdef OPENROAD_CLKGATE 7 | 8 | ICGx1_ASAP7_75t_SL latch ( .CLK(CK), .ENA(E), .SE(1'b0), .GCLK(GCK) ); 9 | 10 | `else 11 | 12 | assign GCK = CK; 13 | 14 | `endif 15 | 16 | endmodule 17 | -------------------------------------------------------------------------------- /examples/boards/ulx3s/blinky/blinky_vhdl.xeda.yaml: -------------------------------------------------------------------------------- 1 | hdl.vhdl.standard: "2008" 2 | 3 | sources: ["ecp5pll.vhdl", "blinky.vhdl"] 4 | top: blinky 5 | clock.port: "clk_25mhz" 6 | 7 | flows: 8 | openfpgaloader: 9 | clock.freq: 25MHz 10 | nextpnr: 11 | board: ULX3S_85F 12 | yosys_fpga: 13 | fpga.family: ecp5 14 | clock.freq: 25MHz 15 | -------------------------------------------------------------------------------- /src/xeda/flows/openxc7/templates/constraints.xdc: -------------------------------------------------------------------------------- 1 | {% for clock_name, clock in settings.clocks.items() -%} 2 | {% if clock.port -%} 3 | create_clock -period {{"%.03f" % clock.period}} -name {{clock_name}} [get_ports {{clock.port}}] 4 | {% endif -%} 5 | {% endfor -%} 6 | 7 | {% if other_constraints %} 8 | {{ other_constraints }} 9 | {% endif -%} 10 | -------------------------------------------------------------------------------- /src/xeda/platforms/nangate45/template_pga.cfg: -------------------------------------------------------------------------------- 1 | pdn specify_grid stdcell { 2 | name low 3 | rails metal1 4 | layers { 5 | metal1 {width 0.17 pitch 2.4 offset 0} 6 | metal4 {width 0.48 pitch 55.2 offset 2} 7 | metal7 {width 1.40 pitch 40.8 offset 2} 8 | } 9 | connect {{metal1 metal4} {metal4 metal7}} 10 | } 11 | 12 | -------------------------------------------------------------------------------- /examples/mixed_language/blink/blink.sv: -------------------------------------------------------------------------------- 1 | module blink( 2 | input clk, 3 | input reset, 4 | output led 5 | ); 6 | logic [7:0] counter; 7 | 8 | always @(posedge clk) begin 9 | if (reset == 1) 10 | counter <= 0; 11 | else 12 | counter <= counter + 1'b1; 13 | end 14 | 15 | assign led = counter[7]; 16 | 17 | endmodule 18 | -------------------------------------------------------------------------------- /src/xeda/platforms/nangate45/cells_latch.v: -------------------------------------------------------------------------------- 1 | module $_DLATCH_P_(input E, input D, output Q); 2 | DLH_X1 _TECHMAP_REPLACE_ ( 3 | .D(D), 4 | .G(E), 5 | .Q(Q) 6 | ); 7 | endmodule 8 | 9 | module $_DLATCH_N_(input E, input D, output Q); 10 | DLL_X1 _TECHMAP_REPLACE_ ( 11 | .D(D), 12 | .GN(E), 13 | .Q(Q) 14 | ); 15 | endmodule -------------------------------------------------------------------------------- /src/xeda/flows/quartus/templates/clock.sdc: -------------------------------------------------------------------------------- 1 | {% for clock_name,clock in settings.clocks.items() -%} 2 | {% if clock.port -%} 3 | # create_clock -period {{ "%.3f"|format(clock.period) }} -name {{clock_name}} [get_ports {{clock.port}}] 4 | create_clock -period {{clock.period|round(3,'floor')}} -name {{clock_name}} [get_ports {{clock.port}}] 5 | {% endif -%} 6 | {% endfor -%} 7 | 8 | derive_pll_clocks 9 | derive_clock_uncertainty -------------------------------------------------------------------------------- /src/xeda/platforms/asap7/openroad/tapcell.tcl: -------------------------------------------------------------------------------- 1 | puts "\[INFO-FLOW\] Tap and End Cap cell insertion" 2 | puts "\[INFO-FLOW\] TAP Cell : $::env(TAP_CELL_NAME)" 3 | puts "\[INFO-FLOW\] ENDCAP Cell : $::env(TAP_CELL_NAME)" 4 | puts "\[INFO-FLOW\] TAP Cell Distance : 25" 5 | 6 | tapcell \ 7 | -distance 25 \ 8 | -tapcell_master "$::env(TAP_CELL_NAME)" \ 9 | -endcap_master "$::env(TAP_CELL_NAME)" 10 | -------------------------------------------------------------------------------- /src/xeda/platforms/asap7/yosys/cells_latch_L.v: -------------------------------------------------------------------------------- 1 | module $_DLATCH_P_(input E, input D, output Q); 2 | DHLx1_ASAP7_75t_L _TECHMAP_REPLACE_ ( 3 | .D(D), 4 | .CLK(E), 5 | .Q(Q) 6 | ); 7 | endmodule 8 | 9 | module $_DLATCH_N_(input E, input D, output Q); 10 | DLLx1_ASAP7_75t_L _TECHMAP_REPLACE_ ( 11 | .D(D), 12 | .CLK(E), 13 | .Q(Q) 14 | ); 15 | endmodule 16 | -------------------------------------------------------------------------------- /src/xeda/platforms/asap7/yosys/cells_latch_R.v: -------------------------------------------------------------------------------- 1 | module $_DLATCH_P_(input E, input D, output Q); 2 | DHLx1_ASAP7_75t_R _TECHMAP_REPLACE_ ( 3 | .D(D), 4 | .CLK(E), 5 | .Q(Q) 6 | ); 7 | endmodule 8 | 9 | module $_DLATCH_N_(input E, input D, output Q); 10 | DLLx1_ASAP7_75t_R _TECHMAP_REPLACE_ ( 11 | .D(D), 12 | .CLK(E), 13 | .Q(Q) 14 | ); 15 | endmodule 16 | -------------------------------------------------------------------------------- /src/xeda/platforms/asap7/yosys/cells_latch_SL.v: -------------------------------------------------------------------------------- 1 | module $_DLATCH_P_(input E, input D, output Q); 2 | DHLx1_ASAP7_75t_SL _TECHMAP_REPLACE_ ( 3 | .D(D), 4 | .CLK(E), 5 | .Q(Q) 6 | ); 7 | endmodule 8 | 9 | module $_DLATCH_N_(input E, input D, output Q); 10 | DLLx1_ASAP7_75t_SL _TECHMAP_REPLACE_ ( 11 | .D(D), 12 | .CLK(E), 13 | .Q(Q) 14 | ); 15 | endmodule 16 | -------------------------------------------------------------------------------- /src/xeda/platforms/sky130hd/cells_latch_hd.v: -------------------------------------------------------------------------------- 1 | module $_DLATCH_P_(input E, input D, output Q); 2 | sky130_fd_sc_hd__dlxtp_1 _TECHMAP_REPLACE_ ( 3 | .D(D), 4 | .GATE(E), 5 | .Q(Q) 6 | ); 7 | endmodule 8 | 9 | module $_DLATCH_N_(input E, input D, output Q); 10 | sky130_fd_sc_hd__dlxtn_1 _TECHMAP_REPLACE_ ( 11 | .D(D), 12 | .GATE_N(E), 13 | .Q(Q) 14 | ); 15 | endmodule 16 | -------------------------------------------------------------------------------- /src/xeda/platforms/sky130hs/cells_latch_hs.v: -------------------------------------------------------------------------------- 1 | module $_DLATCH_P_(input E, input D, output Q); 2 | sky130_fd_sc_hs__dlxtp_1 _TECHMAP_REPLACE_ ( 3 | .D(D), 4 | .GATE(E), 5 | .Q(Q) 6 | ); 7 | endmodule 8 | 9 | module $_DLATCH_N_(input E, input D, output Q); 10 | sky130_fd_sc_hs__dlxtn_1 _TECHMAP_REPLACE_ ( 11 | .D(D), 12 | .GATE_N(E), 13 | .Q(Q) 14 | ); 15 | endmodule 16 | -------------------------------------------------------------------------------- /examples/vhdl/full_adder.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | 4 | entity full_adder is 5 | port ( 6 | a : in std_logic; 7 | b : in std_logic; 8 | ci : in std_logic; 9 | s : out std_logic; 10 | co : out std_logic); 11 | end; 12 | 13 | architecture behavioral of full_adder is 14 | begin 15 | s <= a xor b xor ci; 16 | co <= (a and b) or (b and ci) or (ci and a); 17 | end; -------------------------------------------------------------------------------- /tests/resources/cocotb/results.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/mixed_language/blink/blinky.xeda.toml: -------------------------------------------------------------------------------- 1 | [rtl] 2 | sources = ["blink.sv"] 3 | top = "blink" 4 | # clocks = [{port = "clk"}] 5 | clock.port = "clk" 6 | 7 | [tb] 8 | sources = ["blink_tb.cpp"] 9 | 10 | [flows.cxxrtl] 11 | cxxrtl.filename = "blink.cpp" 12 | 13 | [flows.yosys_fpga] 14 | fpga.vendor = "xilinx" 15 | fpga.family = "xc7" 16 | clock.period = 5.0 17 | 18 | [flows.vivado_synth] 19 | fpga.part = "xc7a100tftg256-2L" 20 | clock.period = 5.0 21 | -------------------------------------------------------------------------------- /examples/vhdl/pipeline/pipelined_adder.toml: -------------------------------------------------------------------------------- 1 | name = 'pipelined_adder' 2 | description = 'Example VHDL design' 3 | language.vhdl.standard = 2008 4 | 5 | [rtl] 6 | sources = ['pipelined_adder.vhdl'] 7 | top = 'pipelined_adder' 8 | clock_port = 'clock' 9 | 10 | [tb] 11 | sources = ['pipelined_adder_tb.vhdl'] 12 | top = 'pipelined_adder_tb' 13 | uut = 'uut' 14 | 15 | [flow.openroad] 16 | platform = "sky130hd" 17 | clocks.main_clock.freq = "200 MHz" 18 | core_utilization = 45 19 | -------------------------------------------------------------------------------- /src/xeda/flows/diamond/templates/constraints.fdc: -------------------------------------------------------------------------------- 1 | {% if not flow.allow_dsps %} 2 | define_global_attribute syn_multstyle logic 3 | 4 | define_scope_collection all_insts {find -hier -net {*}} 5 | define_attribute {$all_insts} {syn_multstyle} {logic} 6 | {% endif %} 7 | 8 | {% if not flow.allow_brams %} 9 | define_global_attribute {syn_ramstyle} {distributed} 10 | 11 | define_scope_collection all_insts {find -hier -net {*}} 12 | define_attribute {$all_insts} {syn_ramstyle} {distributed} 13 | {% endif %} -------------------------------------------------------------------------------- /src/xeda/platforms/sky130hd/make_tracks.tcl: -------------------------------------------------------------------------------- 1 | make_tracks li1 -x_offset 0.23 -x_pitch 0.46 -y_offset 0.17 -y_pitch 0.34 2 | make_tracks met1 -x_offset 0.17 -x_pitch 0.34 -y_offset 0.17 -y_pitch 0.34 3 | make_tracks met2 -x_offset 0.23 -x_pitch 0.46 -y_offset 0.23 -y_pitch 0.46 4 | make_tracks met3 -x_offset 0.34 -x_pitch 0.68 -y_offset 0.34 -y_pitch 0.68 5 | make_tracks met4 -x_offset 0.46 -x_pitch 0.92 -y_offset 0.46 -y_pitch 0.92 6 | make_tracks met5 -x_offset 1.70 -x_pitch 3.40 -y_offset 1.70 -y_pitch 3.40 7 | -------------------------------------------------------------------------------- /tests/resources/design0/design0.toml: -------------------------------------------------------------------------------- 1 | name = 'design0' 2 | description = 'test' 3 | language.vhdl.standard = "2008" 4 | 5 | [rtl] 6 | sources = ['../test.v'] # by default relative paths are relative to the location of the TOML file, unless overridden by the "design_root" field 7 | top = 'design0' 8 | clock_port = 'clk' 9 | parameters = { G_IN_WIDTH = 32, G_ITERATIVE = true, G_STR= "abcd", G_BITVECTOR="7'b0101001" } 10 | 11 | # [tb] 12 | # sources = [] 13 | # cocotb = true 14 | # # top = 'tb_sqrt' 15 | -------------------------------------------------------------------------------- /src/xeda/platforms/sky130hs/make_tracks.tcl: -------------------------------------------------------------------------------- 1 | make_tracks li1 -x_offset 0.24 -x_pitch 0.48 -y_offset 0.185 -y_pitch 0.37 2 | make_tracks met1 -x_offset 0.185 -x_pitch 0.37 -y_offset 0.185 -y_pitch 0.37 3 | make_tracks met2 -x_offset 0.24 -x_pitch 0.48 -y_offset 0.24 -y_pitch 0.48 4 | make_tracks met3 -x_offset 0.37 -x_pitch 0.74 -y_offset 0.37 -y_pitch 0.74 5 | make_tracks met4 -x_offset 0.48 -x_pitch 0.96 -y_offset 0.48 -y_pitch 0.96 6 | make_tracks met5 -x_offset 1.85 -x_pitch 3.33 -y_offset 1.85 -y_pitch 3.33 7 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. XEDA documentation master file, created by 2 | sphinx-quickstart on Tue Sep 1 01:28:46 2020. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to XEDA's documentation! 7 | ================================ 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | :caption: Contents: 12 | 13 | 14 | 15 | Indices and tables 16 | ================== 17 | 18 | * :ref:`genindex` 19 | * :ref:`modindex` 20 | * :ref:`search` 21 | -------------------------------------------------------------------------------- /examples/vhdl/pipeline/synthesize.py: -------------------------------------------------------------------------------- 1 | from subprocess import check_call 2 | 3 | 4 | def quartus_synth(): 5 | check_call( 6 | [ 7 | "xeda", 8 | "run", 9 | "quartus", 10 | "--design", 11 | "pipelined_adder.toml", 12 | "--settings", 13 | "dockerized=true", 14 | "fpga.part=10CL016YU256C6G", 15 | "clock_period=15", 16 | ] 17 | ) 18 | 19 | 20 | if __name__ == "__main__": 21 | quartus_synth() 22 | -------------------------------------------------------------------------------- /src/xeda/flows/vivado/templates/vivado_power.tcl: -------------------------------------------------------------------------------- 1 | set_param tclapp.enableGitAccess 0 2 | 3 | puts "\n================================( Opening routed design from checkpoint )=================================" 4 | open_checkpoint {{checkpoint}} 5 | 6 | puts "\n================================( Reporting power from {{settings.saif}} )=================================" 7 | reset_switching_activity -all 8 | eval read_saif -verbose {{saif_file}} 9 | report_power -hier all -format xml -verbose -file {{settings.power_report_xml}} 10 | -------------------------------------------------------------------------------- /tests/resources/Fitter_Resource_Utilization_by_Entity.csv: -------------------------------------------------------------------------------- 1 | Compilation Hierarchy Node,ALMs needed [=A-B+C],[A] ALMs used in final placement,[B] Estimate of ALMs recoverable by dense packing,[C] Estimate of ALMs unavailable,ALMs used for memory,Combinational ALUTs,Dedicated Logic Registers,I/O Registers,Block Memory Bits,M10Ks,DSP Blocks,Pins,Virtual Pins,Full Hierarchy Name,Entity Name,Library Name 2 | |full_adder_piped,1.5 (1.5),1.5 (1.5),0.0 (0.0),0.0 (0.0),0.0 (0.0),3 (3),2 (2),0 (0),0,0,0,7,0,|full_adder_piped,full_adder_piped,work 3 | -------------------------------------------------------------------------------- /src/xeda/flows/openroad/templates/orflow.tcl: -------------------------------------------------------------------------------- 1 | {% from "macros.tcl.j2" import write_checkpoint, load_checkpoint, preamble, epilogue, section with context %} 2 | 3 | {% for step in steps_to_run %} 4 | {% set step_index = loop.index0 + starting_index %} 5 | {% set step_id = "%d_%s"|format(step_index, step) %} 6 | {% set prev_step_id = get_prev_step_id(step) %} 7 | {% if loop.index0 == 0 %} 8 | {% include "utils.tcl" %} 9 | {% endif %} 10 | {{ preamble(step, step_index) }} 11 | {% include step + '.tcl' %} 12 | {{ epilogue(step) }} 13 | {% endfor %} 14 | -------------------------------------------------------------------------------- /examples/vhdl/Trivium/trivium.xeda.yaml: -------------------------------------------------------------------------------- 1 | hdl.vhdl.standard: 2008 2 | 3 | sources: 4 | - trivium.vhdl 5 | parameters: 6 | G_IN_BITS: 64 7 | G_OUT_BITS: 64 8 | G_SETUP_ROUNDS: 4 9 | top: trivium 10 | clock.port: clk 11 | 12 | test: 13 | sources: 14 | - trivium_tb.py 15 | - cref/trivium64.c 16 | 17 | flows: 18 | vivado_synth: 19 | fpga.part: xc7a12tcsg325-3 20 | clock.freq: 200MHz 21 | yosys_fpga: 22 | fpga.part: xc7a12tcsg325-3 23 | clock.freq: 200MHz 24 | dc: 25 | target_libraries: 26 | - $PWD/lib/SAED90/saed90nm_typ_ht.db 27 | -------------------------------------------------------------------------------- /src/xeda/flow_runner/__init__.py: -------------------------------------------------------------------------------- 1 | from . import dse 2 | from .default_runner import ( 3 | DIR_NAME_HASH_LEN, 4 | DefaultRunner, 5 | FlowNotFoundError, 6 | FlowRunner, 7 | XedaOptions, 8 | add_file_logger, 9 | get_flow_class, 10 | scrub_runs, 11 | ) 12 | from .dse import Dse 13 | 14 | __all__ = [ 15 | "dse", 16 | "Dse", 17 | "FlowRunner", 18 | "DefaultRunner", 19 | "FlowNotFoundError", 20 | "XedaOptions", 21 | "get_flow_class", 22 | "add_file_logger", 23 | "DIR_NAME_HASH_LEN", 24 | "scrub_runs", 25 | ] 26 | -------------------------------------------------------------------------------- /docs/contents.rst: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | Xeda Documentation Contents 3 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4 | 5 | 6 | 7 | **Xeda** `/ˈziːdə/` is a cross-platform, cross-EDA, cross-target automated synthesis and simulation platform. 8 | It helps hardware developers to verify, evaluate, and deploy their RTL designs using multiple commercial and open-source electronic design automation flows. 9 | 10 | 11 | .. toctree:: 12 | tutorial/index.rst 13 | 14 | about.rst 15 | quickstart.rst 16 | flows.rst 17 | bugs.rst 18 | copyright.rst 19 | license.rst -------------------------------------------------------------------------------- /examples/vhdl/Trivium/trivium.toml: -------------------------------------------------------------------------------- 1 | name = "trivium" 2 | 3 | language.vhdl.standard = "2008" 4 | 5 | [rtl] 6 | sources = [ # 7 | "trivium.vhdl", 8 | ] 9 | parameters.G_IN_BITS = 64 10 | parameters.G_OUT_BITS = 64 # 96 11 | # parameters.G_SETUP_ROUNDS = 4 12 | top = "trivium" 13 | clock.port = "clk" 14 | 15 | 16 | [tb] 17 | sources = ["trivium_tb.py", "cref/trivium64.c"] 18 | cocotb = true 19 | 20 | [flow.vivado_synth] 21 | fpga.part = "xc7a12tcsg325-3" 22 | clock.freq = "200 MHz" 23 | 24 | [flow.yosys_fpga] 25 | fpga.part = "xc7a12tcsg325-3" 26 | clock.freq = "200 MHz" 27 | -------------------------------------------------------------------------------- /src/xeda/flows/quartus/templates/settings.dse: -------------------------------------------------------------------------------- 1 | # This file is generated by XEDA 2 | launcher=local 3 | group_id=xeda_dse 4 | num_concurrent={{dse.num_concurrent}} 5 | num_parallel_processors={{dse.nproc}} 6 | num_seeds={{dse.num_seeds}} 7 | explore={{dse.explore}} 8 | compile_flow={{dse.compile_flow}} 9 | auto_discover_files=True 10 | auto_overwrite_project=True 11 | save_results=all 12 | skip_base_compile=True 13 | time_limit_value={{dse.timeout}} 14 | stop_after_timing_met={{dse.stop_on_success}} 15 | report_filename={{settings.reports_dir}}/quartus_dse_report.json 16 | report_format=json -------------------------------------------------------------------------------- /src/xeda/__init__.py: -------------------------------------------------------------------------------- 1 | from . import design, flow_runner, flows 2 | from .cocotb import Cocotb 3 | from .design import Design 4 | from .flow import FPGA, Flow, SimFlow, SynthFlow 5 | from .flow_runner import DefaultRunner, Dse, FlowRunner 6 | from .tool import Tool 7 | from .version import __version__ 8 | 9 | __all__ = [ 10 | "__version__", 11 | "Cocotb", 12 | "DefaultRunner", 13 | "design", 14 | "Design", 15 | "Dse", 16 | "flow_runner", 17 | "FlowRunner", 18 | "flows", 19 | "Flow", 20 | "FPGA", 21 | "SimFlow", 22 | "SynthFlow", 23 | "Tool", 24 | ] 25 | -------------------------------------------------------------------------------- /src/xeda/platforms/asap7/openroad/pdn/pdn.cfg: -------------------------------------------------------------------------------- 1 | # Floorplan information - core boundary coordinates, std. cell row height, 2 | 3 | set ::halo 2 4 | 5 | # POWER or GROUND #Std. cell rails starting with power or ground rails at the bottom of the core area 6 | set ::rails_start_with "POWER" ; 7 | 8 | # POWER or GROUND #Upper metal stripes starting with power or ground rails at the left/bottom of the core area 9 | set ::stripes_start_with "POWER" ; 10 | 11 | # Power nets 12 | set ::power_nets "VDD" 13 | set ::ground_nets "VSS" 14 | 15 | ##===> Power grid strategy 16 | source $::env(PLATFORM_DIR)/openRoad/pdn/grid_strategy-M1-M2-M5-M6.cfg 17 | -------------------------------------------------------------------------------- /examples/vhdl/xedaproject.toml: -------------------------------------------------------------------------------- 1 | [[design]] 2 | name = 'full-adder' 3 | description = 'Example VHDL design' 4 | [design.rtl] 5 | sources = ['full_adder.vhd'] 6 | top = 'full_adder' 7 | clock_port = '' 8 | [design.tb] 9 | sources = ['full_adder_tb.vhd'] 10 | top = 'full_adder_tb' 11 | 12 | 13 | [flows.ghdl_sim] 14 | warn_error = true 15 | 16 | [flows.vivado_prj_synth] 17 | fpga.part = 'xc7a12tcsg325-1' 18 | clock_period = 5.0 19 | 20 | [flows.vivado_synth] 21 | fpga.part = 'xc7a12tcsg325-1' 22 | clock_period = 5.0 23 | 24 | [flows.ise_synth] 25 | fpga.family = "virtex5" 26 | fpga.device = "XC5VLX50" 27 | fpga.speed = -1 28 | fpga.package = "FFG676C" 29 | clock_period = 5.0 30 | 31 | -------------------------------------------------------------------------------- /tests/test_gtkw.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | from xeda.flows.ghdl import _get_wave_opt_signals, common_root 4 | 5 | TESTS_DIR = Path(__file__).parent.absolute() 6 | RESOURCES_DIR = TESTS_DIR / "resources" 7 | 8 | 9 | def test_gen_gtkw(): 10 | opt_file = RESOURCES_DIR / "wave.opt" 11 | extra_top = "top" 12 | 13 | signals, root_group = _get_wave_opt_signals(opt_file, extra_top) 14 | assert len(signals) > 1 15 | assert len(root_group) == 2 16 | 17 | 18 | def test_common_root(): 19 | cr = common_root([[1, 2, 3, 4, 5], [1, 2, 3, 7], [1, 2, 3], [1, 2, 3, 9]]) 20 | assert cr == [1, 2, 3] 21 | 22 | 23 | if __name__ == "__main__": 24 | test_gen_gtkw() 25 | -------------------------------------------------------------------------------- /examples/boards/ulx3s/dvi_test/xedaproject.toml: -------------------------------------------------------------------------------- 1 | [design] 2 | 3 | name = "dvi_test" 4 | 5 | [design.language] 6 | vhdl.standard = 2008 7 | 8 | [design.rtl] 9 | sources = [ 10 | "utils_pkg.vhdl", 11 | "vga.vhd", 12 | "vga2dvid.vhd", 13 | "tmds_encoder.vhd", 14 | "ecp5pll.vhdl", 15 | "top_vgatest.vhd", 16 | ] 17 | top = "top_vgatest" 18 | 19 | clock_port = "clk_25mhz" 20 | 21 | [flows.nextpnr] 22 | board = "ULX3S_85F" 23 | clock_period = 40 # 25 MHz 24 | detailed_timing_report = false # nextpnr BUG, o/w crashes 25 | 26 | [flows.openfpgaloader] 27 | board = "ULX3S_85F" 28 | clock_period = 40 # 25 MHz 29 | nextpnr.detailed_timing_report = false 30 | nextpnr.timing_allow_fail = true 31 | -------------------------------------------------------------------------------- /examples/boards/ulx3s/dvi_test/blink.vhd: -------------------------------------------------------------------------------- 1 | -- (c)EMARD 2 | -- License=BSD 3 | 4 | library IEEE; 5 | use IEEE.STD_LOGIC_1164.ALL; 6 | 7 | entity blink is 8 | generic 9 | ( 10 | bits: integer := 23 11 | ); 12 | port 13 | ( 14 | clk: in std_logic; -- main clock input from 25MHz clock source 15 | led: out std_logic_vector(7 downto 0) 16 | ); 17 | end; 18 | 19 | architecture Behavioral of blink is 20 | signal R_blink: std_logic_vector(bits-1 downto 0); 21 | begin 22 | process(clk) 23 | begin 24 | if rising_edge(clk) then 25 | R_blink <= R_blink+1; 26 | end if; 27 | end process; 28 | led <= R_blink(R_blink'high downto R_blink'high-7); 29 | end Behavioral; 30 | -------------------------------------------------------------------------------- /src/xeda/platforms/nangate45/README.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | The Nangate Open Cell Library is a generic open-source, standard-cell 4 | library provided for the purposes of research, testing, and exploring EDA 5 | flows. This library is purposely non-manufacturable. 6 | 7 | Version: PDKv1.3_v2010_12.Apache.CCL 8 | 9 | # Source 10 | 11 | Downloaded from https://projects.si2.org/openeda.si2.org/project/showfiles.php?group_id=63#503 12 | 13 | # Modifications 14 | 15 | - Performed abstract generation from the gds files to avoid polygon pin shapes in the LEF. 16 | - Added additional files and info required for the OpenROAD flow. 17 | - Fix contact enclosure by poly on cell `AOI21_X1` (rule CONTACT.5). 18 | - Added LICENSE. 19 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /examples/boards/ulx3s/blinky/blinky.v: -------------------------------------------------------------------------------- 1 | 2 | module blinky( 3 | input clk_25mhz, 4 | input [6:0] btn, 5 | output [7:0] led 6 | ); 7 | 8 | localparam ctr_width = 32; 9 | localparam ctr_lsb = 20; 10 | 11 | wire clk; 12 | assign clk = clk_25mhz; 13 | 14 | // __GEN_ECP5_PLL gen_pll_inst(.in_clk(clk_25mhz), .out_clk(pll_clk0), .locked(pll_locked)); 15 | 16 | 17 | reg [ctr_width-1:0] ctr; 18 | 19 | wire [2:0] cx; 20 | wire [2:0] shift_val; 21 | 22 | assign cx = ctr[ctr_lsb + 2:ctr_lsb]; 23 | assign shift_val = ctr[ctr_lsb + 3] ? (7 - cx) : cx; 24 | 25 | always @(posedge clk) begin 26 | ctr <= ctr + 1; 27 | led <= 1 << shift_val; 28 | end 29 | 30 | endmodule 31 | -------------------------------------------------------------------------------- /src/xeda/flows/openroad/templates/detailed_place.tcl: -------------------------------------------------------------------------------- 1 | 2 | set_placement_padding -global \ 3 | -left {{platform.cell_pad_in_sites_detail_placement}} \ 4 | -right {{platform.cell_pad_in_sites_detail_placement}} 5 | detailed_placement 6 | 7 | if {[info exists ::env(ENABLE_DPO)] && $::env(ENABLE_DPO)} { 8 | if {[info exist ::env(DPO_MAX_DISPLACEMENT)]} { 9 | improve_placement -max_displacement $::env(DPO_MAX_DISPLACEMENT) 10 | } else { 11 | improve_placement 12 | } 13 | } 14 | optimize_mirroring 15 | 16 | utl::info FLW 12 "Placement violations [check_placement -verbose]." 17 | 18 | estimate_parasitics -placement 19 | 20 | report_metrics "detailed place" true false 21 | 22 | {{ write_checkpoint(step) }} 23 | -------------------------------------------------------------------------------- /tests/resources/Flow_Summary.csv: -------------------------------------------------------------------------------- 1 | Flow Status,Successful - Tue Mar 1 11:10:35 2022 2 | Quartus Prime Version,21.1.0 Build 842 10/21/2021 SJ Lite Edition 3 | Revision Name,pipelined_adder 4 | Top-level Entity Name,full_adder_piped 5 | Family,Cyclone V 6 | Device,5CGXBC3B6F23C7 7 | Timing Models,Final 8 | Logic utilization (in ALMs),2 / 13,460 ( < 1 % ) 9 | Total registers,2 10 | Total pins,7 / 222 ( 3 % ) 11 | Total virtual pins,0 12 | Total block memory bits,0 / 1,382,400 ( 0 % ) 13 | Total DSP Blocks,0 / 57 ( 0 % ) 14 | Total HSSI RX PCSs,0 / 3 ( 0 % ) 15 | Total HSSI PMA RX Deserializers,0 / 3 ( 0 % ) 16 | Total HSSI TX PCSs,0 / 3 ( 0 % ) 17 | Total HSSI PMA TX Serializers,0 / 3 ( 0 % ) 18 | Total PLLs,0 / 7 ( 0 % ) 19 | Total DLLs,0 / 3 ( 0 % ) 20 | -------------------------------------------------------------------------------- /src/xeda/flows/openroad/openroad_scripts/deletePowerNets.tcl: -------------------------------------------------------------------------------- 1 | read_lef $::env(TECH_LEF) 2 | read_lef $::env(SC_LEF) 3 | if {[info exist ::env(ADDITIONAL_LEFS)]} { 4 | foreach lef $::env(ADDITIONAL_LEFS) { 5 | read_lef $lef 6 | } 7 | } 8 | 9 | # Read liberty files 10 | source $::env(SCRIPTS_DIR)/read_liberty.tcl 11 | 12 | # Read def and sdc 13 | read_def {{settings.results_dir}}/6_final.def 14 | 15 | proc deleteNetByName {name} { 16 | set db [ord::get_db] 17 | set chip [$db getChip] 18 | set block [$chip getBlock] 19 | set net [$block findNet $name] 20 | $net destroySWires 21 | puts "\[INFO\] Deleted net '[$net getName]'" 22 | } 23 | 24 | deleteNetByName VDD 25 | deleteNetByName VSS 26 | 27 | write_def {{settings.results_dir}}/6_final_no_power.def 28 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # Documentation 2 | - [ ] Usage 3 | - [ ] Development 4 | - [ ] Adding new flows 5 | - [ ] Developer docs for adding new flows 6 | 7 | # Main code 8 | 9 | - [ ] FIX lingering child processes after being killed 10 | - [x] Idea: Some code in Suite should be refactored to a FlowRunner class, suites/flows? should provide a run method. 11 | - [x] parallel runs 12 | - [.] Flow chaining 13 | - [ ] move DSE code to a plugin 14 | - [ ] Installation / set-up of tools 15 | - [ ] Run in docker 16 | 17 | ## Flows 18 | 19 | - [.] Support multiple clocks in synthesis at least with DefaultRunner 20 | - [x] Modelsim 21 | - [.] ghdl + yosys + nextpnr-ecp5 22 | - [ ] Synopsys VCS 23 | - [.] Synopsys DC 24 | - [ ] Synopsys ICC2 25 | - [ ] OpenROAD/OpenLANE 26 | - [x] Quartus: Power estimation 27 | -------------------------------------------------------------------------------- /src/xeda/flow/__init__.py: -------------------------------------------------------------------------------- 1 | from .flow import ( 2 | Flow, 3 | FlowDependencyFailure, 4 | FlowException, 5 | FlowFatalError, 6 | FlowSettingsError, 7 | FlowSettingsException, 8 | registered_flows, 9 | ) 10 | 11 | # from .decorators import define_flow, sim_flow, synth_flow 12 | from .fpga import FPGA 13 | from .sim import SimFlow 14 | from .synth import AsicSynthFlow, FpgaSynthFlow, PhysicalClock, SynthFlow 15 | 16 | __all__ = [ 17 | "Flow", 18 | "FPGA", 19 | "SimFlow", 20 | "SynthFlow", 21 | "FpgaSynthFlow", 22 | "AsicSynthFlow", 23 | "PhysicalClock", 24 | "registered_flows", 25 | "FlowDependencyFailure", 26 | "FlowFatalError", 27 | "FlowSettingsException", 28 | "FlowSettingsError", 29 | "FlowException", 30 | ] 31 | -------------------------------------------------------------------------------- /src/xeda/flows/yosys/templates/post_rtl.tcl: -------------------------------------------------------------------------------- 1 | {%- if settings.rtl_json %} 2 | yosys log -stdout "Writing JSON {{settings.rtl_json}}" 3 | yosys write_json {{settings.rtl_json}} 4 | {%- endif %} 5 | {%- if settings.rtl_verilog %} 6 | yosys log -stdout "Writing Verilog {{settings.rtl_verilog}}" 7 | yosys write_verilog {{settings.rtl_verilog}} 8 | {%- endif %} 9 | {%- if settings.rtl_vhdl %} 10 | yosys log -stdout " Writing VHDL {{settings.rtl_vhdl}}" 11 | yosys write_vhdl {{settings.rtl_vhdl}} 12 | {%- endif %} 13 | {%- if settings.rtl_graph %} 14 | yosys log -stdout "Writing RTL graph to {{settings.rtl_graph.with_suffix('dot')}}" 15 | yosys show -prefix {{settings.rtl_graph.with_suffix("")}} -format dot {{settings.rtl_graph_flags|join(" ")}} 16 | {%- endif %} 17 | 18 | {%- if settings.stop_after == "rtl" %} 19 | exit 20 | {%- endif %} -------------------------------------------------------------------------------- /examples/vhdl/sqrt/sqrt.toml: -------------------------------------------------------------------------------- 1 | name = "sqrt" 2 | description = "Iterative computation of square-root of an integer" 3 | language.vhdl.standard = "2008" 4 | 5 | [rtl] 6 | sources = ["sqrt.vhdl"] 7 | top = "sqrt" 8 | clock_port = "clk" 9 | parameters = { G_IN_WIDTH = 32 } 10 | # parameters = { G_IN_WIDTH = 32, G_ITERATIVE = true, G_STR= "abcd", G_BITVECTOR="7'b0101001" } 11 | 12 | [tb] 13 | sources = ["tb_sqrt.py"] 14 | cocotb = true 15 | # top = "tb_sqrt" # FIXME 16 | 17 | [flows.yosys_fpga] 18 | fpga.part = "xc7a100tftg256-2L" 19 | clock.freq = "100MHz" 20 | 21 | [flows.vivado_synth] 22 | fpga.part = "xc7a100tftg256-2L" 23 | clock_period = 5.0 24 | 25 | [flows.vivado_alt_synth] 26 | fpga.part = "xc7a100tftg256-2L" 27 | synth.strategy = "ExtraTimingCongestion" 28 | impl.strategy = "ExtraTimingCongestion" 29 | clock_period = 5.0 30 | -------------------------------------------------------------------------------- /src/xeda/platforms/asap7/openroad/post_mergeLib.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | 4 | print("[INFO-FLOW] Post Merge Lib") 5 | mergedFile = sys.argv[1] 6 | print("[INFO-FLOW] ", mergedFile) 7 | f = open(mergedFile, "r") 8 | 9 | lines = f.readlines() 10 | f.close() 11 | fo = open(mergedFile, "w") 12 | flag_pg = 0 13 | for line in lines: 14 | if len(line.split()) < 1: 15 | fo.write(line) 16 | continue 17 | if line.split()[0] == "pg_pin": 18 | flag_pg = 1 19 | fo.write(line) 20 | # fo.write(' direction : input;\n') 21 | continue 22 | if flag_pg == 1 and line.split()[0] == "}": 23 | flag_pg = 0 24 | fo.write(line) 25 | continue 26 | if flag_pg == 1 and line.split()[0] == "direction": 27 | continue 28 | fo.write(line) 29 | fo.close() 30 | -------------------------------------------------------------------------------- /src/xeda/platforms/nangate45/make_tracks.tcl: -------------------------------------------------------------------------------- 1 | make_tracks metal1 -x_offset 0.095 -x_pitch 0.19 -y_offset 0.07 -y_pitch 0.14 2 | make_tracks metal2 -x_offset 0.095 -x_pitch 0.19 -y_offset 0.07 -y_pitch 0.14 3 | make_tracks metal3 -x_offset 0.095 -x_pitch 0.19 -y_offset 0.07 -y_pitch 0.14 4 | make_tracks metal4 -x_offset 0.095 -x_pitch 0.28 -y_offset 0.07 -y_pitch 0.28 5 | make_tracks metal5 -x_offset 0.095 -x_pitch 0.28 -y_offset 0.07 -y_pitch 0.28 6 | make_tracks metal6 -x_offset 0.095 -x_pitch 0.28 -y_offset 0.07 -y_pitch 0.28 7 | make_tracks metal7 -x_offset 0.095 -x_pitch 0.8 -y_offset 0.07 -y_pitch 0.8 8 | make_tracks metal8 -x_offset 0.095 -x_pitch 0.8 -y_offset 0.07 -y_pitch 0.8 9 | make_tracks metal9 -x_offset 0.095 -x_pitch 1.6 -y_offset 0.07 -y_pitch 1.6 10 | make_tracks metal10 -x_offset 0.095 -x_pitch 1.6 -y_offset 0.07 -y_pitch 1.6 11 | -------------------------------------------------------------------------------- /examples/boards/ulx3s/blinky/xedaproject.toml: -------------------------------------------------------------------------------- 1 | [[design]] 2 | name = 'blinky' 3 | description = 'Running LEDs on the ULX3S board' 4 | 5 | [design.rtl] 6 | sources = ['blinky.v'] 7 | top = 'blinky' 8 | clock_port = 'clk_25mhz' 9 | 10 | [[design]] 11 | name = 'blinky-vhdl' 12 | description = 'LED chaser on ULX3S' 13 | language.vhdl.standard = 2008 14 | 15 | [design.rtl] 16 | sources = [ # 17 | "ecp5pll.vhdl", 18 | 'blinky.vhdl', 19 | ] 20 | top = 'blinky' 21 | clock_port = 'clk_25mhz' 22 | 23 | 24 | [flows.openfpgaloader] 25 | board = 'ULX3S_85F' 26 | clock_period = 40 # 25 MHz 27 | nextpnr.detailed_timing_report = false 28 | nextpnr.timing_allow_fail = true 29 | 30 | [flows.nextpnr] 31 | board = 'ULX3S_85F' 32 | clock_period = 40 # 25 MHz 33 | 34 | [flows.yosys_fpga] 35 | fpga.family = 'ecp5' 36 | clock_period = 40 # 37 | -------------------------------------------------------------------------------- /tests/test_cli.py: -------------------------------------------------------------------------------- 1 | from click.testing import CliRunner 2 | 3 | from xeda.cli import cli 4 | 5 | flows = ["ghdl_sim", "yosys", "nextpnr", "vivado_sim", "vivado_synth"] 6 | 7 | 8 | def test_cli_run_help(): 9 | runner = CliRunner() 10 | result = runner.invoke(cli, ["run", "--help"]) 11 | assert result.exit_code == 0 12 | assert "Usage: " in result.output 13 | 14 | 15 | def test_cli_list_flows(): 16 | runner = CliRunner() 17 | result = runner.invoke(cli, ["list-flows"]) 18 | assert result.exit_code == 0 19 | for flow in flows: 20 | assert flow in result.output 21 | 22 | 23 | def test_cli_list_settings(): 24 | runner = CliRunner() 25 | for flow_name in flows: 26 | result = runner.invoke(cli, ["list-settings", flow_name]) 27 | assert result.exit_code == 0, f"Failed: CLI list-settings {flow_name}" 28 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | 5 | ## [Unreleased] 6 | 7 | ### Fixed 8 | - Command line interface: 9 | - `list-settings`: improved display of types and default values 10 | ### Changed 11 | - WIP: Handling settings of dependency flow during `Settings` validation. 12 | ### Removed 13 | 14 | ### Added 15 | - Tool: ecppll (nextpnr's Lattice ECP5 PLL tool) 16 | - Examples: ULX3S adopted DVI test from EMARD 17 | - change LED chaser speed with buttons `5` and `6`! 18 | - Examples: improved version of `blinky` for the ULX3S board in VHDL 19 | - change LED chaser speed with buttons `5` and `6`! 20 | 21 | ## [v0.1.0-alpha.11] - 2022-04-16 22 | 23 | 24 | [Unreleased]: https://github.com/XedaHQ/xeda/compare/v0.1.0-alpha.1...HEAD 25 | [v0.1.0-alpha.11]: https://github.com/XedaHQ/xeda/releases/tag/v0.1.0-alpha.11 -------------------------------------------------------------------------------- /src/xeda/platforms/sky130hd/setRC.tcl: -------------------------------------------------------------------------------- 1 | # correlateRC.py gcd,ibex,aes,jpeg,chameleon,riscv32i,chameleon_hier 2 | # cap units pf/um 3 | set_layer_rc -layer li1 -capacitance 1.499e-04 -resistance 7.176e-02 4 | set_layer_rc -layer met1 -capacitance 1.72375E-04 -resistance 8.929e-04 5 | set_layer_rc -layer met2 -capacitance 1.36233E-04 -resistance 8.929e-04 6 | set_layer_rc -layer met3 -capacitance 2.14962E-04 -resistance 1.567e-04 7 | set_layer_rc -layer met4 -capacitance 1.48128E-04 -resistance 1.567e-04 8 | set_layer_rc -layer met5 -capacitance 1.54087E-04 -resistance 1.781e-05 9 | # end correlate 10 | 11 | set_layer_rc -via mcon -resistance 9.249146E-3 12 | set_layer_rc -via via -resistance 4.5E-3 13 | set_layer_rc -via via2 -resistance 3.368786E-3 14 | set_layer_rc -via via3 -resistance 0.376635E-3 15 | set_layer_rc -via via4 -resistance 0.00580E-3 16 | 17 | set_wire_rc -signal -layer met2 18 | set_wire_rc -clock -layer met5 19 | -------------------------------------------------------------------------------- /src/xeda/platforms/sky130hs/setRC.tcl: -------------------------------------------------------------------------------- 1 | # correlateRC.py gcd,ibex,aes,jpeg,chameleon,riscv32i,chameleon_hier 2 | # cap units pf/um 3 | set_layer_rc -layer li1 -capacitance 1.499e-04 -resistance 7.176e-02 4 | set_layer_rc -layer met1 -capacitance 1.72375E-04 -resistance 8.929e-04 5 | set_layer_rc -layer met2 -capacitance 1.36233E-04 -resistance 8.929e-04 6 | set_layer_rc -layer met3 -capacitance 2.14962E-04 -resistance 1.567e-04 7 | set_layer_rc -layer met4 -capacitance 1.48128E-04 -resistance 1.567e-04 8 | set_layer_rc -layer met5 -capacitance 1.54087E-04 -resistance 1.781e-05 9 | # end correlate 10 | 11 | set_layer_rc -via mcon -resistance 9.249146E-3 12 | set_layer_rc -via via -resistance 4.5E-3 13 | set_layer_rc -via via2 -resistance 3.368786E-3 14 | set_layer_rc -via via3 -resistance 0.376635E-3 15 | set_layer_rc -via via4 -resistance 0.00580E-3 16 | 17 | set_wire_rc -signal -layer met2 18 | set_wire_rc -clock -layer met5 19 | -------------------------------------------------------------------------------- /src/xeda/flows/openroad/templates/load.tcl: -------------------------------------------------------------------------------- 1 | #===========================(Read liberty libs)===============================# 2 | read_libraries 3 | #=============================(Read LEF files)================================# 4 | read_lef {{platform.tech_lef}} 5 | {% if platform.std_cell_lef %} 6 | read_lef {{platform.std_cell_lef}} 7 | {% endif %} 8 | 9 | {% for lef in platform.additional_lef_files %} 10 | read_lef {{lef}} 11 | {% endfor %} 12 | 13 | read_verilog {{netlist}} 14 | link_design {{design.rtl.top}} 15 | 16 | {% for sdc in settings.sdc_files %} 17 | read_sdc {{sdc}} 18 | {% endfor %} 19 | 20 | {% if platform.derate_tcl %} 21 | source {{platform.derate_tcl}} 22 | {% endif %} 23 | {% if platform.setrc_tcl %} 24 | source {{platform.setrc_tcl}} 25 | {% endif %} 26 | 27 | puts "Default units for flow" 28 | report_units 29 | report_units_metric 30 | 31 | puts "number instances in verilog is [llength [get_cells -hier *]]" 32 | 33 | {{ write_checkpoint(step) }} 34 | -------------------------------------------------------------------------------- /src/xeda/flows/vivado/templates/clock.xdc: -------------------------------------------------------------------------------- 1 | {% for clock_name, clock in settings.clocks.items() -%} 2 | {% if clock.port -%} 3 | create_clock -period {{"%.03f" % clock.period}} -name {{clock_name}} [get_ports {{clock.port}}] 4 | {% if settings.default_max_input_delay is not none -%} set_input_delay -max -clock {{clock_name}} {{settings.default_max_input_delay}} [filter [all_inputs] {NAME != {{clock.port}} }] {%- endif %} 5 | {% if settings.default_min_input_delay is not none -%} set_input_delay -min -clock {{clock_name}} {{settings.default_min_input_delay}} [filter [all_inputs] {NAME != {{clock.port}} }] {%- endif %} 6 | {% if settings.default_max_output_delay is not none -%} set_output_delay -max -clock {{clock_name}} {{settings.default_max_output_delay}} [all_outputs] {%- endif %} 7 | {% if settings.default_min_output_delay is not none -%} set_output_delay -min -clock {{clock_name}} {{settings.default_min_output_delay}} [all_outputs] {%- endif %} 8 | {% endif -%} 9 | {% endfor -%} 10 | -------------------------------------------------------------------------------- /src/xeda/platforms/nangate45/setRC.tcl: -------------------------------------------------------------------------------- 1 | # Liberty units are fF,kOhm 2 | set_layer_rc -layer metal1 -resistance 5.4286e-03 -capacitance 7.41819E-02 3 | set_layer_rc -layer metal2 -resistance 3.5714e-03 -capacitance 6.74606E-02 4 | set_layer_rc -layer metal3 -resistance 3.5714e-03 -capacitance 8.88758E-02 5 | set_layer_rc -layer metal4 -resistance 1.5000e-03 -capacitance 1.07121E-01 6 | set_layer_rc -layer metal5 -resistance 1.5000e-03 -capacitance 1.08964E-01 7 | set_layer_rc -layer metal6 -resistance 1.5000e-03 -capacitance 1.02044E-01 8 | set_layer_rc -layer metal7 -resistance 1.8750e-04 -capacitance 1.10436E-01 9 | set_layer_rc -layer metal8 -resistance 1.8750e-04 -capacitance 9.69714E-02 10 | # No calibration data available for metal9 and metal10 11 | #set_layer_rc -layer metal9 -resistance 3.7500e-05 -capacitance 3.6864e-02 12 | #set_layer_rc -layer metal10 -resistance 3.7500e-05 -capacitance 2.8042e-02 13 | 14 | set_wire_rc -signal -layer metal3 15 | set_wire_rc -clock -layer metal5 16 | -------------------------------------------------------------------------------- /.github/workflows/dependency-review.yml: -------------------------------------------------------------------------------- 1 | # Dependency Review Action 2 | # 3 | # This Action will scan dependency manifest files that change as part of a Pull Request, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging. 4 | # 5 | # Source repository: https://github.com/actions/dependency-review-action 6 | # Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement 7 | name: 'Dependency Review' 8 | on: [pull_request] 9 | 10 | permissions: 11 | contents: read 12 | 13 | jobs: 14 | dependency-review: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: 'Checkout Repository' 18 | uses: actions/checkout@v3 19 | - name: 'Dependency Review' 20 | uses: actions/dependency-review-action@v2 21 | -------------------------------------------------------------------------------- /examples/vhdl/full_adder_piped.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | 4 | entity full_adder_piped is 5 | port( 6 | clk : in std_logic; 7 | reset : in std_logic; 8 | in_a : in std_logic; 9 | in_b : in std_logic; 10 | in_ci : in std_logic; 11 | s : out std_logic; 12 | co : out std_logic 13 | ); 14 | end; 15 | 16 | architecture behavioral of full_adder_piped is 17 | signal a, b, ci : std_logic; 18 | begin 19 | process(clk) 20 | begin 21 | if rising_edge(clk) then 22 | if reset = '1' then 23 | s <= '0'; -- not really needed 24 | co <= '0'; -- not really needed 25 | else 26 | a <= in_a; 27 | b <= in_b; 28 | ci <= in_ci; 29 | s <= a xor b xor ci; 30 | co <= (a and b) or (b and ci) or (ci and a); 31 | end if; -- reset 32 | end if; -- clk rising_edge 33 | end process; 34 | end; 35 | -------------------------------------------------------------------------------- /src/xeda/flows/openroad/openroad_scripts/deleteNonClkNets.tcl: -------------------------------------------------------------------------------- 1 | read_lef $::env(TECH_LEF) 2 | read_lef $::env(SC_LEF) 3 | if {[info exist ::env(ADDITIONAL_LEFS)]} { 4 | foreach lef $::env(ADDITIONAL_LEFS) { 5 | read_lef $lef 6 | } 7 | } 8 | 9 | # Read liberty files 10 | source $::env(SCRIPTS_DIR)/read_liberty.tcl 11 | 12 | # Read def and sdc 13 | read_def {{settings.results_dir}}/6_final.def 14 | 15 | set block [[[ord::get_db] getChip] getBlock] 16 | set nets [$block getNets] 17 | set insts [$block getInsts] 18 | 19 | # Delete all non-clock nets 20 | foreach net $nets { 21 | set sigType [$net getSigType] 22 | set wire [$net getWire] 23 | if {"$sigType" eq "SIGNAL" && "$wire" ne "NULL"} { 24 | odb::dbWire_destroy $wire 25 | } elseif {"$sigType" eq "POWER" || 26 | "$sigType" eq "GROUND"} { 27 | $net destroySWires 28 | } 29 | } 30 | 31 | # Delete fill cells to clean up screenshot 32 | foreach inst $insts { 33 | if {"[[$inst getMaster] getType]" eq "CORE_SPACER"} { 34 | odb::dbInst_destroy $inst 35 | } 36 | } 37 | 38 | write_def {{settings.results_dir}}/6_final_only_clk.def 39 | -------------------------------------------------------------------------------- /src/xeda/platforms/asap7/setRC.tcl: -------------------------------------------------------------------------------- 1 | # Liberty units are fF,kOhm 2 | set_layer_rc -layer M1 -capacitance 1.1368e-01 -resistance 1.3889e-01 3 | set_layer_rc -layer M2 -capacitance 1.3426e-01 -resistance 2.4222e-02 4 | set_layer_rc -layer M3 -capacitance 1.2918e-01 -resistance 2.4222e-02 5 | set_layer_rc -layer M4 -capacitance 1.1396e-01 -resistance 1.6778e-02 6 | set_layer_rc -layer M5 -capacitance 1.3323e-01 -resistance 1.4677e-02 7 | set_layer_rc -layer M6 -capacitance 1.1575e-01 -resistance 1.0371e-02 8 | set_layer_rc -layer M7 -capacitance 1.3293e-01 -resistance 9.6720e-03 9 | set_layer_rc -layer M8 -capacitance 1.1822e-01 -resistance 7.4310e-03 10 | set_layer_rc -layer M9 -capacitance 1.3497e-01 -resistance 6.8740e-03 11 | 12 | set_layer_rc -via V1 -resistance 1.72E-02 13 | set_layer_rc -via V2 -resistance 1.72E-02 14 | set_layer_rc -via V3 -resistance 1.72E-02 15 | set_layer_rc -via V4 -resistance 1.18E-02 16 | set_layer_rc -via V5 -resistance 1.18E-02 17 | set_layer_rc -via V6 -resistance 8.20E-03 18 | set_layer_rc -via V7 -resistance 8.20E-03 19 | set_layer_rc -via V8 -resistance 6.30E-03 20 | 21 | set_wire_rc -layer M3 22 | -------------------------------------------------------------------------------- /.github/workflows/python-publish.yml: -------------------------------------------------------------------------------- 1 | # For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries 2 | 3 | name: Upload 📦 to PyPI 4 | on: 5 | pull_request: 6 | branches: 7 | - 'main' 8 | - 'releases/**' 9 | push: 10 | branches: 11 | - 'main' 12 | - 'releases/**' 13 | release: 14 | types: [published] 15 | jobs: 16 | deploy: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v3 20 | - name: Set up 🐍 21 | uses: actions/setup-python@v3 22 | with: 23 | python-version: '3.x' 24 | - name: Install dependencies 25 | run: | 26 | python -m pip install --upgrade pip 27 | pip install build 28 | - name: Build package 29 | run: python -m build 30 | - name: Publish 📦 to PyPI 31 | if: github.event.pull_request.merged == true || startsWith(github.ref, 'refs/tags') 32 | uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 33 | with: 34 | user: __token__ 35 | password: ${{ secrets.PYPI_API_TOKEN }} 36 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v4.4.0 4 | hooks: 5 | - id: check-ast 6 | - id: check-yaml 7 | - id: check-toml 8 | # - id: end-of-file-fixer 9 | # - id: check-added-large-files 10 | - id: check-case-conflict 11 | - id: check-merge-conflict 12 | - id: check-symlinks 13 | - id: destroyed-symlinks 14 | # - id: trailing-whitespace 15 | - id: check-vcs-permalinks 16 | - id: mixed-line-ending 17 | - id: detect-private-key 18 | - repo: https://github.com/psf/black 19 | rev: 22.12.0 20 | hooks: 21 | - id: black 22 | - repo: https://github.com/pre-commit/mirrors-mypy 23 | rev: v1.4.1 24 | hooks: 25 | - id: mypy 26 | args: [--install-types, --non-interactive, --ignore-missing-imports] 27 | additional_dependencies: 28 | - "pydantic>=1.10.4,<2.0" 29 | # - repo: local 30 | # hooks: 31 | # - id: pytest-check 32 | # name: pytest-check 33 | # entry: pytest 34 | # language: system 35 | # pass_filenames: false 36 | # always_run: false 37 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: ["main", "dev"] 5 | pull_request: 6 | branches: ["main", "dev"] 7 | workflow_dispatch: 8 | 9 | jobs: 10 | tox: 11 | strategy: 12 | fail-fast: false 13 | matrix: 14 | python-version: ["3.10", "3.11", "3.12", "3.13"] 15 | 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - uses: ghdl/setup-ghdl@v1 20 | with: 21 | backend: llvm 22 | - uses: YosysHQ/setup-oss-cad-suite@v3 23 | - uses: nickg/setup-nvc@v1 24 | with: 25 | version: latest 26 | - uses: actions/checkout@v4 27 | with: 28 | submodules: true 29 | fetch-depth: 0 30 | - name: Set up Python ${{ matrix.python-version }} 31 | uses: actions/setup-python@v5 32 | with: 33 | python-version: "${{ matrix.python-version }}" 34 | - name: Install dependencies 35 | run: | 36 | python -VV 37 | python -m pip install --upgrade pip 38 | python -m pip install --upgrade tox tox-gh-actions 39 | - name: "Run tox targets for ${{ matrix.python-version }}" 40 | run: "python -m tox" 41 | -------------------------------------------------------------------------------- /src/xeda/flows/dc/templates/constraints.sdc: -------------------------------------------------------------------------------- 1 | {% for clock_name, clock in settings.clocks.items() -%} 2 | {% if clock.port -%} 3 | create_clock -period {{"%.03f" % clock.period}} -name {{clock_name}} [get_ports {{clock.port}}] 4 | 5 | {% if settings.default_max_input_delay is not none -%} 6 | set max_input_delay {{settings.default_max_input_delay}} 7 | set input_ports [all_inputs -exclude_clock_ports] 8 | foreach_in_collection port $input_ports { 9 | set port_name [get_object_name $port] 10 | puts "Settings MAX input delay of port $port_name to $max_input_delay" 11 | set_input_delay -clock {{clock_name}} -max $max_input_delay $input_ports 12 | } 13 | {% endif -%} 14 | 15 | {% if settings.default_max_output_delay is not none -%} 16 | # Ensuring valid output can be captured on the clock edge 17 | set max_output_delay {{settings.default_max_output_delay}} 18 | set output_ports [all_outputs] 19 | foreach_in_collection port $output_ports { 20 | puts "Settings MAX output delay of port $port_name to $max_output_delay" 21 | set_output_delay -clock {{clock_name}} -max $max_output_delay $output_ports 22 | } 23 | {% endif -%} 24 | # set_dont_touch_network [find port {{clock.port}}] 25 | {% endif -%} 26 | {% endfor -%} 27 | -------------------------------------------------------------------------------- /tests/test_verilator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import tempfile 3 | from pathlib import Path 4 | 5 | from xeda.flow_runner import DefaultRunner 6 | from xeda.flows import Verilator 7 | 8 | TESTS_DIR = Path(__file__).parent.absolute() 9 | EXAMPLES_DIR = TESTS_DIR.parent / "examples" 10 | 11 | debug = False 12 | 13 | 14 | def test_yosys_synth_py() -> None: 15 | design_paths = [ 16 | EXAMPLES_DIR / "sv" / "fifo" / "fifo.xeda.yaml", 17 | EXAMPLES_DIR / "sv" / "fifo" / "fifo_cocotb.xeda.yaml", 18 | ] 19 | with tempfile.TemporaryDirectory(dir=Path.cwd()) as run_dir: 20 | print("Xeda run dir: ", run_dir) 21 | for design in design_paths: 22 | xeda_runner = DefaultRunner(run_dir, debug=debug) 23 | flow = xeda_runner.run(Verilator, design, flow_overrides=dict(debug=debug, verbose=debug)) 24 | assert flow is not None, "run_flow returned None" 25 | settings_json = flow.run_path / "settings.json" 26 | results_json = flow.run_path / "results.json" 27 | assert settings_json.exists() 28 | assert flow.succeeded 29 | assert isinstance(flow.settings, Verilator.Settings) 30 | assert results_json.exists() 31 | 32 | 33 | if __name__ == "__main__": 34 | test_yosys_synth_py() 35 | -------------------------------------------------------------------------------- /src/xeda/platforms/asap7/openroad/make_tracks.tcl: -------------------------------------------------------------------------------- 1 | make_tracks Pad -x_offset 0.116 -x_pitch 0.080 -y_offset 0.116 -y_pitch 0.080 2 | make_tracks M9 -x_offset 0.116 -x_pitch 0.080 -y_offset 0.116 -y_pitch 0.080 3 | make_tracks M8 -x_offset 0.116 -x_pitch 0.080 -y_offset 0.116 -y_pitch 0.080 4 | make_tracks M7 -x_offset 0.016 -x_pitch 0.064 -y_offset 0.016 -y_pitch 0.064 5 | make_tracks M6 -x_offset 0.012 -x_pitch 0.048 -y_offset 0.016 -y_pitch 0.064 6 | make_tracks M5 -x_offset 0.012 -x_pitch 0.048 -y_offset 0.012 -y_pitch 0.048 7 | make_tracks M4 -x_offset 0.009 -x_pitch 0.036 -y_offset 0.012 -y_pitch 0.048 8 | make_tracks M3 -x_offset 0.009 -x_pitch 0.036 -y_offset 0.009 -y_pitch 0.036 9 | 10 | make_tracks M2 -x_offset 0.009 -x_pitch 0.036 -y_offset 0.045 -y_pitch 0.270 11 | make_tracks M2 -x_offset 0.009 -x_pitch 0.036 -y_offset 0.081 -y_pitch 0.270 12 | make_tracks M2 -x_offset 0.009 -x_pitch 0.036 -y_offset 0.117 -y_pitch 0.270 13 | make_tracks M2 -x_offset 0.009 -x_pitch 0.036 -y_offset 0.153 -y_pitch 0.270 14 | make_tracks M2 -x_offset 0.009 -x_pitch 0.036 -y_offset 0.189 -y_pitch 0.270 15 | make_tracks M2 -x_offset 0.009 -x_pitch 0.036 -y_offset 0.225 -y_pitch 0.270 16 | make_tracks M2 -x_offset 0.009 -x_pitch 0.036 -y_offset 0.270 -y_pitch 0.270 17 | 18 | make_tracks M1 -x_offset 0.009 -x_pitch 0.036 -y_offset 0.009 -y_pitch 0.036 19 | -------------------------------------------------------------------------------- /tests/test_nvc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import tempfile 3 | from pathlib import Path 4 | 5 | from xeda.flow_runner import DefaultRunner 6 | from xeda.flows import Nvc 7 | 8 | TESTS_DIR = Path(__file__).parent.absolute() 9 | EXAMPLES_DIR = TESTS_DIR.parent / "examples" 10 | 11 | debug = False 12 | 13 | 14 | def test_yosys_synth_py() -> None: 15 | design_paths = [ 16 | EXAMPLES_DIR / "vhdl" / "sqrt" / "sqrt.toml", 17 | EXAMPLES_DIR / "vhdl" / "Trivium" / "trivium.xeda.yaml", 18 | EXAMPLES_DIR / "vhdl" / "pipeline" / "pipelined_adder.toml", 19 | ] 20 | with tempfile.TemporaryDirectory(dir=Path.cwd()) as run_dir: 21 | print("Xeda run dir: ", run_dir) 22 | for design in design_paths: 23 | xeda_runner = DefaultRunner(run_dir, debug=debug) 24 | flow = xeda_runner.run(Nvc, design, flow_overrides=dict(debug=debug, verbose=debug)) 25 | assert flow is not None, "run_flow returned None" 26 | settings_json = flow.run_path / "settings.json" 27 | results_json = flow.run_path / "results.json" 28 | assert settings_json.exists() 29 | assert flow.succeeded 30 | assert isinstance(flow.settings, Nvc.Settings) 31 | assert results_json.exists() 32 | 33 | 34 | if __name__ == "__main__": 35 | test_yosys_synth_py() 36 | -------------------------------------------------------------------------------- /src/xeda/platforms/nangate45/fakeram.tcl: -------------------------------------------------------------------------------- 1 | 2 | set design_rams { 3 | swerv {2048x39 256x34 64x21} 4 | bp_be_top {64x96 512x64 64x15} 5 | tinyRocket {64x32 1024x32} 6 | black_parrot {64x7 64x96 512x64 256x95 64x15} 7 | bp_multi_top {64x7 32x64 64x96 512x64 256x96 64x15} 8 | bp_fe_top {64x7 64x96 512x64} 9 | } 10 | 11 | set results_dir "~/import/fakeram/results" 12 | set flow_dir "~/import/flow/flow/platforms/nangate45" 13 | 14 | proc make_fakeram_links {} { 15 | global design_rams flow_dir 16 | 17 | foreach {design sizes} $design_rams { 18 | cd $flow_dir/$design 19 | foreach size $sizes { 20 | file delete fakeram45_$size.lib 21 | file delete fakeram45_$size.lef 22 | file link -symbolic fakeram45_$size.lib \ 23 | ../../../platforms/nangate45/lib/fakeram45_$size.lib 24 | file link -symbolic fakeram45_$size.lef \ 25 | ../../../platforms/nangate45/lef/fakeram45_$size.lef 26 | } 27 | } 28 | } 29 | 30 | proc copy_fakeram_results {} { 31 | global design_rams results_dir flow_dir 32 | 33 | foreach {design sizes} $design_rams { 34 | foreach size $sizes { 35 | file copy -force $results_dir/fakeram45_$size/fakeram45_$size.lib $flow_dir/lib/fakeram45_$size.lib 36 | file copy -force $results_dir/fakeram45_$size/fakeram45_$size.lef $flow_dir/lef/fakeram45_$size.lef 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/sv/fifo/fifo.sv: -------------------------------------------------------------------------------- 1 | `default_nettype none 2 | 3 | module fifo #( 4 | parameter DATA_WIDTH = 8, 5 | parameter LOG2_DEPTH = 4 6 | ) ( 7 | input logic clk, 8 | input logic reset, 9 | input logic enq_valid, 10 | input logic [DATA_WIDTH-1:0] enq_data, 11 | output logic enq_ready, 12 | input logic deq_ready, 13 | output logic [DATA_WIDTH-1:0] deq_data, 14 | output logic deq_valid 15 | ); 16 | logic [DATA_WIDTH-1:0] mem[2**LOG2_DEPTH]; 17 | logic [LOG2_DEPTH-1:0] write_ptr, read_ptr; 18 | logic maybe_full, overlap, do_write, do_read; 19 | 20 | assign overlap = write_ptr == read_ptr; 21 | assign do_write = enq_valid && enq_ready; 22 | assign do_read = deq_valid && deq_ready; 23 | 24 | assign enq_ready = !(overlap && maybe_full); 25 | assign deq_valid = maybe_full || !overlap; 26 | assign deq_data = mem[read_ptr]; 27 | 28 | 29 | always_ff @(posedge clk) begin 30 | if (reset) begin 31 | write_ptr <= '0; 32 | read_ptr <= '0; 33 | maybe_full <= 1'b0; 34 | end else begin 35 | if (do_write) begin 36 | mem[write_ptr] <= enq_data; 37 | write_ptr <= write_ptr + 1; 38 | maybe_full <= 1'b1; 39 | end 40 | if (do_read) begin 41 | read_ptr <= read_ptr + 1; 42 | maybe_full <= 1'b0; 43 | end 44 | end 45 | end 46 | 47 | endmodule 48 | -------------------------------------------------------------------------------- /tests/test_cocotb.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | from typing import Any, Dict 3 | 4 | from xeda import Cocotb 5 | from xeda.utils import WorkingDirectory 6 | 7 | TESTS_DIR = Path(__file__).parent.absolute() 8 | RESOURCES_DIR = TESTS_DIR / "resources" 9 | 10 | 11 | def test_cocotb_version(): 12 | cocotb = Cocotb(sim_name="ghdl") # type: ignore 13 | 14 | assert cocotb.version_gte(0) 15 | assert cocotb.version_gte(0, 0) 16 | assert cocotb.version_gte(0, 1) 17 | assert cocotb.version_gte(0, 1, 1) 18 | assert cocotb.version_gte(0, 1, 1, 1) 19 | assert cocotb.version_gte(1) 20 | assert cocotb.version_gte(1, 5) 21 | assert cocotb.version_gte(1, 6) 22 | 23 | 24 | def test_cocotb_parse_xml(): 25 | assert (RESOURCES_DIR / "cocotb" / "results.xml").exists() 26 | with WorkingDirectory(RESOURCES_DIR / "cocotb"): 27 | cocotb = Cocotb(sim_name="dummy") # type: ignore 28 | if cocotb.results is not None: 29 | for suite in cocotb.results.test_suites: 30 | for case in suite.test_cases: 31 | print(case) 32 | results: Dict[str, Any] = {"success": True} 33 | cocotb.add_results(results) 34 | print("Results:", results) 35 | assert results["success"] is False 36 | 37 | 38 | if __name__ == "__main__": 39 | test_cocotb_version() 40 | test_cocotb_parse_xml() 41 | -------------------------------------------------------------------------------- /tests/test_ghdl.py: -------------------------------------------------------------------------------- 1 | import tempfile 2 | from pathlib import Path 3 | 4 | from xeda.flow_runner import DefaultRunner 5 | from xeda.flows import GhdlSim 6 | 7 | TESTS_DIR = Path(__file__).parent.absolute() 8 | EXAMPLES_DIR = TESTS_DIR.parent / "examples" 9 | 10 | debug = False 11 | 12 | 13 | def test_yosys_synth_py() -> None: 14 | # settings = dict(fpga=FPGA("xc7a12tcsg325-1"), clock_period=5.5) 15 | # run_dir = "tests_run_dir" 16 | design_paths = [ 17 | EXAMPLES_DIR / "vhdl" / "sqrt" / "sqrt.toml", 18 | EXAMPLES_DIR / "vhdl" / "Trivium" / "trivium.xeda.yaml", 19 | EXAMPLES_DIR / "vhdl" / "pipeline" / "pipelined_adder.toml", 20 | ] 21 | with tempfile.TemporaryDirectory(dir=Path.cwd()) as run_dir: 22 | print("Xeda run dir: ", run_dir) 23 | for design in design_paths: 24 | xeda_runner = DefaultRunner(run_dir, debug=debug) 25 | flow = xeda_runner.run(GhdlSim, design, flow_overrides=dict(debug=debug, verbose=debug)) 26 | assert flow is not None, "run_flow returned None" 27 | settings_json = flow.run_path / "settings.json" 28 | results_json = flow.run_path / "results.json" 29 | assert settings_json.exists() 30 | assert flow.succeeded 31 | assert isinstance(flow.settings, GhdlSim.Settings) 32 | assert results_json.exists() 33 | 34 | 35 | if __name__ == "__main__": 36 | test_yosys_synth_py() 37 | -------------------------------------------------------------------------------- /tests/test_ise.py: -------------------------------------------------------------------------------- 1 | import os 2 | import tempfile 3 | from pathlib import Path 4 | 5 | from xeda import Design 6 | from xeda.flow import FPGA 7 | from xeda.flow_runner import DefaultRunner 8 | from xeda.flows import IseSynth 9 | 10 | TESTS_DIR = Path(__file__).parent.absolute() 11 | RESOURCES_DIR = TESTS_DIR / "resources" 12 | EXAMPLES_DIR = TESTS_DIR.parent / "examples" 13 | 14 | os.environ["PATH"] += os.pathsep + os.path.join(TESTS_DIR, "fake_tools") 15 | 16 | 17 | def test_ise_synth_py() -> None: 18 | path = RESOURCES_DIR / "design0/design0.toml" 19 | # Append to PATH so if the actual tool exists, would take precedences. 20 | assert path.exists() 21 | design = Design.from_toml(EXAMPLES_DIR / "vhdl" / "sqrt" / "sqrt.toml") 22 | settings = dict(fpga=FPGA("xc7a12tcsg325-1"), clock_period=5.5) 23 | with tempfile.TemporaryDirectory() as run_dir: 24 | print("Xeda run dir: ", run_dir) 25 | xeda_runner = DefaultRunner(run_dir, debug=True) 26 | flow = xeda_runner.run_flow(IseSynth, design, settings) 27 | assert flow is not None, "run_flow returned None" 28 | assert flow.run_path is not None, "run_flow returned None" 29 | settings_json = flow.run_path / "settings.json" 30 | results_json = flow.run_path / "results.json" 31 | assert settings_json.exists() 32 | assert results_json.exists() 33 | # assert flow.succeeded 34 | 35 | 36 | if __name__ == "__main__": 37 | test_ise_synth_py() 38 | -------------------------------------------------------------------------------- /src/xeda/flows/openroad/templates/clocks.sdc: -------------------------------------------------------------------------------- 1 | {% set all_clock_ports = settings.clocks.values()|map(attribute="port") %} 2 | 3 | set all_input_ports [all_inputs] 4 | set all_output_ports [all_outputs] 5 | set all_clock_ports [list {{all_clock_ports|join(" ")}}] 6 | 7 | {% for clock_name, clock in settings.clocks.items() %} 8 | {% if clock.port %} 9 | {% set clock_period = clock.period_unit(settings.platform.time_unit) %} 10 | set clk_port [get_ports {{clock.port}}] 11 | create_clock -period {{ "%.3f"|format(clock_period) }} -name {{clock_name}} $clk_port 12 | 13 | ## NOTE: includes other clock ports if multiple clocks are present 14 | set non_clock_inputs [lsearch -inline -all -not -exact $all_input_ports $clk_port] 15 | 16 | {% if settings.input_delay is not none %} 17 | set_input_delay {{"%.3f"|format(settings.input_delay)}} -clock {{clock_name}} $non_clock_inputs 18 | {% elif settings.input_delay_frac is not none %} 19 | set_input_delay [expr {{"%.3f"|format(settings.input_delay_frac)}} * {{"%.3f"|format(clock_period)}}] -clock {{clock_name}} $non_clock_inputs 20 | {% endif %} 21 | {% if settings.output_delay is not none %} 22 | set_output_delay {{"%.3f"|format(settings.output_delay)}} -clock {{clock_name}} $all_output_ports 23 | {% elif settings.output_delay_frac is not none %} 24 | set_output_delay [expr {{"%.3f"|format(settings.output_delay_frac)}} * {{"%.3f"|format(clock_period)}}] -clock {{clock_name}} $all_output_ports 25 | {% endif %} 26 | 27 | {% endif %} 28 | {% endfor %} 29 | -------------------------------------------------------------------------------- /src/xeda/flows/openroad/templates/cts.tcl: -------------------------------------------------------------------------------- 1 | # Clone clock tree inverters next to register loads 2 | # so cts does not try to buffer the inverted clocks. 3 | repair_clock_inverters 4 | 5 | # Run CTS 6 | clock_tree_synthesis -root_buf "{{platform.cts_buf_cell}}" -buf_list "{{platform.cts_buf_cell}}" \ 7 | -sink_clustering_enable \ 8 | -sink_clustering_size {{settings.cts_cluster_size}} \ 9 | -sink_clustering_max_diameter {{settings.cts_cluster_diameter}} {% if settings.cts_buf_distance %} -distance_between_buffers {{settings.cts_buf_distance}} {% endif %} \ 10 | -balance_levels 11 | 12 | set_propagated_clock [all_clocks] 13 | set_dont_use {{settings.dont_use_cells|join(" ")|embrace}} 14 | 15 | estimate_parasitics -placement 16 | report_metrics "cts pre-repair" 17 | 18 | repair_clock_nets 19 | estimate_parasitics -placement 20 | report_metrics "cts post-repair" 21 | 22 | set_placement_padding -global \ 23 | -left {{platform.cell_pad_in_sites_detail_placement}} \ 24 | -right {{platform.cell_pad_in_sites_detail_placement}} 25 | detailed_placement 26 | 27 | estimate_parasitics -placement 28 | 29 | puts "Repair setup and hold violations..." 30 | repair_timing {% if settings.setup_slack_margin %} -setup_margin {{settings.setup_slack_margin}} {% endif %} {% if settings.hold_slack_margin %} -hold_margin {{settings.hold_slack_margin}} {% endif %} 31 | 32 | detailed_placement 33 | check_placement -verbose 34 | report_metrics "cts final" 35 | 36 | {{ write_checkpoint(step, sdc=true)}} 37 | -------------------------------------------------------------------------------- /src/xeda/flows/openroad/openroad_scripts/view_cells.tcl: -------------------------------------------------------------------------------- 1 | # layout out all cells in SC_LEF in a grid for viewing 2 | 3 | read_lef $::env(TECH_LEF) 4 | read_lef $::env(SC_LEF) 5 | 6 | # Create the block 7 | set db [ord::get_db] 8 | set chip [odb::dbChip_create $db] 9 | set block [odb::dbBlock_create $chip all_cells] 10 | 11 | # Get all the masters 12 | set masters {} 13 | foreach lib [$db getLibs] { 14 | foreach master [$lib getMasters] { 15 | lappend masters $master 16 | } 17 | } 18 | 19 | # Find the number of masters & the max width and height of any master 20 | set max_width 0 21 | set max_height 0 22 | set num_masters 0 23 | foreach master $masters { 24 | set max_width [expr max($max_width, [$master getWidth])] 25 | set max_height [expr max($max_height, [$master getHeight])] 26 | incr num_masters 27 | } 28 | 29 | # The steps for laying out the cells 30 | set x_step [expr round(1.5 * $max_width)] 31 | set y_step [expr round(1.5 * $max_height)] 32 | 33 | # The number of cells per row 34 | set x_width [expr ceil(sqrt($num_masters * $y_step / $x_step))] 35 | 36 | # Make the instance array of masters 37 | set x 0 38 | set y 0 39 | foreach master $masters { 40 | set inst [odb::dbInst_create $block $master [$master getName]] 41 | $inst setPlacementStatus PLACED 42 | $inst setLocation [expr $x * $x_step] [expr $y * $y_step] 43 | 44 | incr x 45 | if {$x == $x_width} { 46 | set x 0 47 | incr y 48 | } 49 | } 50 | gui::design_created 51 | gui::fit 52 | -------------------------------------------------------------------------------- /src/xeda/platforms/nangate45/cells_adders.v: -------------------------------------------------------------------------------- 1 | 2 | (* techmap_celltype = "$fa" *) 3 | module _tech_fa (A, B, C, X, Y); 4 | parameter WIDTH = 1; 5 | (* force_downto *) 6 | input [WIDTH-1 : 0] A, B, C; 7 | (* force_downto *) 8 | output [WIDTH-1 : 0] X, Y; 9 | 10 | parameter _TECHMAP_CONSTVAL_A_ = WIDTH'bx; 11 | parameter _TECHMAP_CONSTVAL_B_ = WIDTH'bx; 12 | parameter _TECHMAP_CONSTVAL_C_ = WIDTH'bx; 13 | 14 | genvar i; 15 | generate for (i = 0; i < WIDTH; i = i + 1) begin 16 | if (_TECHMAP_CONSTVAL_A_[i] === 1'b0 || _TECHMAP_CONSTVAL_B_[i] === 1'b0 || _TECHMAP_CONSTVAL_C_[i] === 1'b0) begin 17 | if (_TECHMAP_CONSTVAL_C_[i] === 1'b0) begin 18 | HA_X1 halfadder_Cconst ( 19 | .A(A[i]), 20 | .B(B[i]), 21 | .CO(X[i]), .S(Y[i]) 22 | ); 23 | end 24 | else begin 25 | if (_TECHMAP_CONSTVAL_B_[i] === 1'b0) begin 26 | HA_X1 halfadder_Bconst ( 27 | .A(A[i]), 28 | .B(C[i]), 29 | .CO(X[i]), .S(Y[i]) 30 | ); 31 | end 32 | else begin 33 | HA_X1 halfadder_Aconst ( 34 | .A(B[i]), 35 | .B(C[i]), 36 | .CO(X[i]), .S(Y[i]) 37 | ); 38 | end 39 | end 40 | end 41 | else begin 42 | FA_X1 fulladder ( 43 | .A(A[i]), .B(B[i]), .CI(C[i]), .CO(X[i]), .S(Y[i]) 44 | ); 45 | end 46 | end endgenerate 47 | 48 | endmodule 49 | -------------------------------------------------------------------------------- /src/xeda/flows/modelsim/templates/run.tcl: -------------------------------------------------------------------------------- 1 | puts "\n===========================( Compiling HDL Sources )===========================" 2 | {% for src in design.sim_sources if src.type -%} 3 | {% if src.type == 'verilog' -%} 4 | if { [catch {eval vlog {{src.file}} {% if src.variant == "systemverilog" -%} -sv {%- endif -%} {{vlog_opts}} } error]} { 5 | puts $error 6 | exit 1 7 | } 8 | {% elif src.type == 'vhdl' -%} 9 | if { [catch {eval vcom {{src.file}} {{vcom_opts}} {%- if design.language.vhdl.standard in ("93", "1993") %} -93 {% elif design.language.vhdl.standard in ("08", "2008") %} -2008 {% elif design.language.vhdl.standard %} -{{design.language.vhdl.standard}} {% endif -%} } error]} { 10 | puts $error 11 | exit 1 12 | } 13 | {%- endif %} 14 | {%- endfor %} 15 | 16 | puts "\n===========================( Running simulation )===========================" 17 | 18 | {% if settings.vcd %} 19 | vcd file {{settings.vcd}} 20 | {% endif %} 21 | 22 | puts "\n===========================( *ENABLE ECHO* )===========================" 23 | if { [catch {eval vsim -t ps {{design.sim_tops|join(' ')}} {{vsim_opts}} {{generics_options}} } error]} { 24 | puts $error 25 | exit 1 26 | } 27 | vcd add -r {% if not debug and design.tb.uut %} {{design.tb.uut}}/* {% else %} * {% endif %} 28 | #run_wave 29 | run {% if 'stop_time' in flow %} {{settings.stop_time}} {%- else %} -all {%- endif %} 30 | puts "\n===========================( *DISABLE ECHO* )===========================" 31 | 32 | {% if settings.vcd %} 33 | vcd flush 34 | {% endif %} 35 | 36 | exit 37 | -------------------------------------------------------------------------------- /src/xeda/flows/openroad/templates/io_place.tcl: -------------------------------------------------------------------------------- 1 | {% if settings.floorplan_def %} 2 | puts "Skipping IO placement as DEF file was used to initialize floorplan." 3 | {% else %} 4 | 5 | {% if settings.io_constraints %} {# ---------------------------- #} 6 | source {{settings.io_constraints}} 7 | 8 | {% else %} {# -------------------------------------------------- #} 9 | # check the lower boundary of the PLACE_DENSITY and add PLACE_DENSITY_LB_ADDON if it exists 10 | {% if settings.place_density_lb_addon is not none %} 11 | set place_density_lb [gpl::get_global_placement_uniform_density \ 12 | -pad_left {{platform.cell_pad_in_sites_global_placement}} \ 13 | -pad_right {{platform.cell_pad_in_sites_global_placement}}] 14 | set place_density [expr $place_density_lb + {{settings.place_density_lb_addon}} + 0.01] 15 | if {$place_density > 1.0} { 16 | set place_density 1.0 17 | } 18 | {% else %} 19 | set place_density {{settings.place_density or platform.place_density}} 20 | {% endif %} 21 | 22 | global_placement -skip_io -density $place_density \ 23 | -pad_left {{platform.cell_pad_in_sites_global_placement}} \ 24 | -pad_right {{platform.cell_pad_in_sites_global_placement}} {{ settings.global_placement_args|join(" ") }} 25 | 26 | {% endif %} {# ------------------------------------------------- #} 27 | 28 | place_pins -hor_layer {{platform.io_placer_h}} -ver_layer {{platform.io_placer_v}} {% if settings.io_place_random %} -random {% endif %} {{settings.place_pins_args|join(" ")}} 29 | {% endif %} {# --not settings.floorplan_def-- #} 30 | 31 | {{ write_checkpoint(step) }} 32 | -------------------------------------------------------------------------------- /examples/vhdl/sqrt/test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import logging 4 | import os 5 | from pathlib import Path 6 | 7 | from xeda import Design, Flow 8 | from xeda.flow_runner import DefaultRunner 9 | from xeda.flows import GhdlSim, YosysFpga 10 | from xeda.tool import ExecutableNotFound 11 | 12 | log = logging.getLogger(__name__) 13 | 14 | SCRIPT_DIR = Path(__file__).parent.resolve() 15 | 16 | design = Design.from_toml(SCRIPT_DIR / "sqrt.toml") 17 | xeda_runner = DefaultRunner() 18 | 19 | 20 | def test_sqrt() -> None: 21 | LONG_TEST = [8, 9, 16, 17, 18, 20, 21, 31, 32, 63, 64, 66] 22 | QUICK_TEST = [8, 32] 23 | ws = QUICK_TEST 24 | if os.environ.get("LONG_TEST"): 25 | print("runing long test!") 26 | ws = LONG_TEST 27 | for w in ws: 28 | assert design.tb 29 | design.tb.parameters = {**design.tb.parameters, "G_IN_WIDTH": w} 30 | os.environ["NUM_TV"] = str(50) 31 | f: Flow = xeda_runner.run_flow(GhdlSim, design) 32 | if not f.succeeded: 33 | raise AssertionError(f"test failed for w={w}") 34 | 35 | 36 | def test_sqrt_yosys_synth() -> None: 37 | design.tb.parameters["G_IN_WIDTH"] = 32 38 | try: 39 | f = xeda_runner.run_flow( 40 | YosysFpga, 41 | design, 42 | {"fpga": {"part": "LFE5U-25F-6BG381C"}, "clock_period": 10.0}, 43 | ) 44 | assert f.succeeded 45 | except ExecutableNotFound: 46 | log.critical("Yosys executable not found") 47 | 48 | 49 | if __name__ == "__main__": 50 | test_sqrt() 51 | test_sqrt_yosys_synth() 52 | -------------------------------------------------------------------------------- /src/xeda/platforms/mk_to_toml.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | import argparse 3 | import re 4 | from pathlib import Path 5 | 6 | 7 | def escape(s: str): 8 | try: 9 | return str(float(s)) 10 | except ValueError: 11 | pass 12 | for d in ["$(ADDITIONAL_GDS)", "$(ADDITIONAL_LIBS)", "$(PLATFORM_DIR)/"]: 13 | s = s.replace(d, "") 14 | s = s.strip() 15 | if s.startswith('"') and s.endswith('"'): 16 | return s 17 | if not (s.startswith("$(") and s.endswith(")")): 18 | sp = re.split(r"\s+", s) 19 | if len(sp) > 1: 20 | return "[" + ", ".join(escape(s) for s in sp) + "]" 21 | s = s.replace("\\", "\\\\") 22 | s = s.replace('"', '\\"') 23 | return '"' + s + '"' 24 | 25 | 26 | def comment(s: str): 27 | return " # overridable" if s.startswith("?") else "" 28 | 29 | 30 | def callback(pat): 31 | return f"{pat.group(1).lower()} = {escape(pat.group(3))}{comment(pat.group(2))}\n" 32 | 33 | 34 | def convert(args): 35 | with open(args.config_mk) as f: 36 | content = f.read() 37 | # line continuations 38 | content = re.sub(r"[^\S\r\n]*\\[^\S\r\n]*\n[^\S\r\n]*", " ", content, re.MULTILINE | re.UNICODE) 39 | 40 | content = re.sub(r"export\s+(\w+)\s*(\??=)\s*([^\n]+)\s*", callback, content) 41 | with open(Path(args.config_mk).parent / "config.toml", "w") as f: 42 | f.write(content) 43 | 44 | 45 | if __name__ == "__main__": 46 | arg_parser = argparse.ArgumentParser() 47 | arg_parser.add_argument("config_mk", type=Path) 48 | args = arg_parser.parse_args() 49 | convert(args) 50 | -------------------------------------------------------------------------------- /src/xeda/platforms/sky130hd/cells_adders_hd.v: -------------------------------------------------------------------------------- 1 | 2 | (* techmap_celltype = "$fa" *) 3 | module _tech_fa (A, B, C, X, Y); 4 | parameter WIDTH = 1; 5 | (* force_downto *) 6 | input [WIDTH-1 : 0] A, B, C; 7 | (* force_downto *) 8 | output [WIDTH-1 : 0] X, Y; 9 | 10 | parameter _TECHMAP_CONSTVAL_A_ = WIDTH'bx; 11 | parameter _TECHMAP_CONSTVAL_B_ = WIDTH'bx; 12 | parameter _TECHMAP_CONSTVAL_C_ = WIDTH'bx; 13 | 14 | genvar i; 15 | generate for (i = 0; i < WIDTH; i = i + 1) begin 16 | if (_TECHMAP_CONSTVAL_A_[i] === 1'b0 || _TECHMAP_CONSTVAL_B_[i] === 1'b0 || _TECHMAP_CONSTVAL_C_[i] === 1'b0) begin 17 | if (_TECHMAP_CONSTVAL_C_[i] === 1'b0) begin 18 | sky130_fd_sc_hd__ha_1 halfadder_Cconst ( 19 | .A(A[i]), 20 | .B(B[i]), 21 | .COUT(X[i]), .SUM(Y[i]) 22 | ); 23 | end 24 | else begin 25 | if (_TECHMAP_CONSTVAL_B_[i] === 1'b0) begin 26 | sky130_fd_sc_hd__ha_1 halfadder_Bconst ( 27 | .A(A[i]), 28 | .B(C[i]), 29 | .COUT(X[i]), .SUM(Y[i]) 30 | ); 31 | end 32 | else begin 33 | sky130_fd_sc_hd__ha_1 halfadder_Aconst ( 34 | .A(B[i]), 35 | .B(C[i]), 36 | .COUT(X[i]), .SUM(Y[i]) 37 | ); 38 | end 39 | end 40 | end 41 | else begin 42 | sky130_fd_sc_hd__fa_1 fulladder ( 43 | .A(A[i]), .B(B[i]), .CIN(C[i]), .COUT(X[i]), .SUM(Y[i]) 44 | ); 45 | end 46 | end endgenerate 47 | 48 | endmodule 49 | -------------------------------------------------------------------------------- /src/xeda/platforms/sky130hs/cells_adders_hs.v: -------------------------------------------------------------------------------- 1 | 2 | (* techmap_celltype = "$fa" *) 3 | module _tech_fa (A, B, C, X, Y); 4 | parameter WIDTH = 1; 5 | (* force_downto *) 6 | input [WIDTH-1 : 0] A, B, C; 7 | (* force_downto *) 8 | output [WIDTH-1 : 0] X, Y; 9 | 10 | parameter _TECHMAP_CONSTVAL_A_ = WIDTH'bx; 11 | parameter _TECHMAP_CONSTVAL_B_ = WIDTH'bx; 12 | parameter _TECHMAP_CONSTVAL_C_ = WIDTH'bx; 13 | 14 | genvar i; 15 | generate for (i = 0; i < WIDTH; i = i + 1) begin 16 | if (_TECHMAP_CONSTVAL_A_[i] === 1'b0 || _TECHMAP_CONSTVAL_B_[i] === 1'b0 || _TECHMAP_CONSTVAL_C_[i] === 1'b0) begin 17 | if (_TECHMAP_CONSTVAL_C_[i] === 1'b0) begin 18 | sky130_fd_sc_hs__ha_1 halfadder_Cconst ( 19 | .A(A[i]), 20 | .B(B[i]), 21 | .COUT(X[i]), .SUM(Y[i]) 22 | ); 23 | end 24 | else begin 25 | if (_TECHMAP_CONSTVAL_B_[i] === 1'b0) begin 26 | sky130_fd_sc_hs__ha_1 halfadder_Bconst ( 27 | .A(A[i]), 28 | .B(C[i]), 29 | .COUT(X[i]), .SUM(Y[i]) 30 | ); 31 | end 32 | else begin 33 | sky130_fd_sc_hs__ha_1 halfadder_Aconst ( 34 | .A(B[i]), 35 | .B(C[i]), 36 | .COUT(X[i]), .SUM(Y[i]) 37 | ); 38 | end 39 | end 40 | end 41 | else begin 42 | sky130_fd_sc_hs__fa_1 fulladder ( 43 | .A(A[i]), .B(B[i]), .CIN(C[i]), .COUT(X[i]), .SUM(Y[i]) 44 | ); 45 | end 46 | end endgenerate 47 | 48 | endmodule 49 | -------------------------------------------------------------------------------- /src/xeda/flows/openroad/templates/floorplan.tcl: -------------------------------------------------------------------------------- 1 | {% if settings.floorplan_def %} 2 | # Initialize floorplan by reading in floorplan DEF 3 | puts "Read in Floorplan DEF to initialize floorplan: {{settings.floorplan_def}}" 4 | read_def -floorplan_initialize {{settings.floorplan_def}} 5 | 6 | {% elif settings.footprint %} 7 | # Initialize floorplan using ICeWall footprint 8 | ICeWall load_footprint {{settings.footprint}} 9 | initialize_floorplan \ 10 | -die_area [ICeWall get_die_area] \ 11 | -core_area [ICeWall get_core_area] \ 12 | -site {{platform.place_site}} 13 | ICeWall init_footprint {{settings.sig_map_file}} 14 | 15 | {% elif settings.core_utilization %} 16 | # Initialize floorplan using core_utilization 17 | initialize_floorplan -utilization {{settings.core_utilization}} \ 18 | -aspect_ratio {{settings.core_aspect_ratio}} \ 19 | -core_space {{settings.core_margin}} \ 20 | -site {{platform.place_site}} 21 | 22 | {% elif settings.core_area and settings.die_area %} 23 | # Initialize floorplan using DIE_AREA/CORE_AREA 24 | initialize_floorplan -die_area {{settings.die_area|join(" ")|embrace}} \ 25 | -core_area {{settings.core_area|join(" ")|embrace}} \ 26 | -site {{platform.place_site}} 27 | {% endif %} 28 | 29 | {% set make_tracks_tcl = settings.make_tracks_tcl or platform.make_tracks_tcl %} 30 | {% if make_tracks_tcl %} 31 | source {{make_tracks_tcl}} 32 | {% else %} 33 | make_tracks 34 | {% endif %} 35 | 36 | {% if settings.footprint_tcl %} 37 | source {{settings.footprint_tcl}} 38 | {% endif %} 39 | 40 | # remove buffers inserted by yosys/abc 41 | remove_buffers 42 | 43 | {{ write_checkpoint(step, sdc=true)}} 44 | -------------------------------------------------------------------------------- /src/xeda/flows/openroad/templates/resize.tcl: -------------------------------------------------------------------------------- 1 | estimate_parasitics -placement 2 | report_metrics "resizer pre" false false 3 | 4 | print_banner "instance_count" 5 | puts [sta::network_leaf_instance_count] 6 | 7 | print_banner "pin_count" 8 | puts [sta::network_leaf_pin_count] 9 | 10 | set_dont_use {{settings.dont_use_cells|join(" ")|embrace}} 11 | 12 | # Do not buffer chip-level designs 13 | {% if settings.footprint %} 14 | puts "Perform port buffering..." 15 | buffer_ports 16 | {% endif %} 17 | 18 | puts "Perform buffer insertion..." 19 | repair_design 20 | 21 | # Repair tie lo fanout 22 | puts "Repair tie lo fanout..." 23 | set tielo_cell_name {{platform.tielo_cell}} 24 | set tielo_lib_name [get_name [get_property [lindex [get_lib_cell $tielo_cell_name] 0] library]] 25 | set tielo_pin $tielo_lib_name/$tielo_cell_name/{{platform.tielo_port}} 26 | repair_tie_fanout -separation {{settings.tie_separation}} $tielo_pin 27 | 28 | # Repair tie hi fanout 29 | puts "Repair tie hi fanout..." 30 | set tiehi_cell_name {{platform.tiehi_cell}} 31 | set tiehi_lib_name [get_name [get_property [lindex [get_lib_cell $tiehi_cell_name] 0] library]] 32 | set tiehi_pin $tiehi_lib_name/$tiehi_cell_name/{{platform.tiehi_port}} 33 | repair_tie_fanout -separation {{settings.tie_separation}} $tiehi_pin 34 | 35 | # hold violations are not repaired until after CTS 36 | 37 | print_banner "report_floating_nets" 38 | report_floating_nets 39 | 40 | report_metrics "resizer" true false 41 | 42 | print_banner "instance_count" 43 | puts [sta::network_leaf_instance_count] 44 | 45 | print_banner "pin_count" 46 | puts [sta::network_leaf_pin_count] 47 | 48 | {{ write_checkpoint(step) }} 49 | -------------------------------------------------------------------------------- /src/xeda/platforms/asap7/fakeram.cfg: -------------------------------------------------------------------------------- 1 | # config file to drive ABKGroup Black-box FakeRAM2.0 Generator 2 | # https://github.com/ABKGroup/FakeRAM2.0.git 3 | # using Matt's fork to fix pin access issue 4 | # https://github.com/maliberty/FakeRAM2.0.git fix-obs branch 5 | 6 | #SAMPLE INPUT FILE; VALUES NOT REALISTIC 7 | { 8 | # The process node. 9 | "tech_nm": 7, 10 | 11 | # The operating voltage. 12 | "voltage": 0.7, 13 | 14 | # String to add in front of every metal layer number for the layer name. 15 | "metal_prefix": "M", 16 | 17 | # Horizontal Metal layer for macro pins 18 | "metal_layer": "M4", 19 | 20 | # The pin width for signal pins. 21 | "pin_width_nm": 24, 22 | 23 | # The minimum pin pitch for signal pins 24 | "pin_pitch_nm": 48, 25 | 26 | # Metal track pitch 27 | "metal_track_pitch_nm": 48, 28 | 29 | # Manufacturing Grid 30 | "manufacturing_grid_nm": 1, 31 | 32 | # Contacted Poly Pitch 33 | "contacted_poly_pitch_nm": 54, 34 | 35 | #column mux factor 36 | "column_mux_factor": 1, 37 | 38 | # Fin pitch 39 | "fin_pitch_nm" : 27, 40 | 41 | # Optional snap the width and height of the sram to a multiple value. 42 | "snap_width_nm": 190, 43 | "snap_height_nm": 1400, 44 | 45 | # List of SRAM configurations (name width depth and banks) 46 | "srams": [ 47 | {"name": "fakeram7_64x21", "width": 21, "depth": 64, "banks": 1}, 48 | {"name": "fakeram7_256x32", "width": 32, "depth": 256, "banks": 1}, 49 | {"name": "fakeram7_256x34", "width": 34, "depth": 256, "banks": 1}, 50 | {"name": "fakeram7_2048x39", "width": 39, "depth": 2048, "banks": 1} 51 | ] 52 | # TENTATIVE PARAMETERS 53 | } 54 | -------------------------------------------------------------------------------- /src/xeda/flows/modelsim/__init__.py: -------------------------------------------------------------------------------- 1 | # © 2020 [Kamyar Mohajerani](mailto:kamyar@ieee.org) 2 | 3 | from typing import Optional 4 | 5 | from ...flow import SimFlow 6 | from ...tool import Tool 7 | from ...utils import SDF 8 | 9 | 10 | class Modelsim(SimFlow): 11 | class Settings(SimFlow.Settings): 12 | sdf: SDF = SDF() 13 | modelsimini: Optional[str] = None 14 | 15 | def run(self) -> None: 16 | assert isinstance(self.settings, self.Settings) 17 | vcom_options = ["-lint"] 18 | vlog_options = ["-lint"] 19 | vsim_opts = [] 20 | tb = self.design.tb 21 | ss = self.settings 22 | # TODO are library paths supported? 23 | vsim_opts.extend([f"-L {lib_name}" for lib_name in ss.lib_paths]) 24 | sdf_root = ss.sdf.root if ss.sdf.root else tb.uut 25 | for dt, f in ss.sdf.delay_items(): 26 | assert sdf_root, "Neither settings.sdf.root or design.tb.uut are provided" 27 | vsim_opts.extend([f"-sdf{dt}", f"{sdf_root}={f}"]) 28 | 29 | tb_generics_opts = " ".join([f"-g{k}={v}" for k, v in tb.parameters.items()]) 30 | 31 | script_path = self.copy_from_template( 32 | "run.tcl", 33 | generics_options=tb_generics_opts, 34 | vcom_opts=" ".join(vcom_options), 35 | vlog_opts=" ".join(vlog_options), 36 | vsim_opts=" ".join(vsim_opts), 37 | ) 38 | 39 | modelsim_opts = ["-batch", "-do", f"do {script_path}"] 40 | if ss.modelsimini: 41 | modelsim_opts.extend(["-modelsimini", ss.modelsimini]) 42 | vsim = Tool("vsim") 43 | vsim.run(*modelsim_opts) 44 | -------------------------------------------------------------------------------- /src/xeda/platforms/asap7/yosys/cells_adders_L.v: -------------------------------------------------------------------------------- 1 | 2 | (* techmap_celltype = "$fa" *) 3 | module _tech_fa (A, B, C, X, Y); 4 | parameter WIDTH = 1; 5 | (* force_downto *) 6 | input [WIDTH-1 : 0] A, B, C; 7 | (* force_downto *) 8 | output [WIDTH-1 : 0] X, Y; 9 | 10 | wire [WIDTH-1 : 0] NX, NY; 11 | 12 | parameter _TECHMAP_CONSTVAL_A_ = WIDTH'bx; 13 | parameter _TECHMAP_CONSTVAL_B_ = WIDTH'bx; 14 | parameter _TECHMAP_CONSTVAL_C_ = WIDTH'bx; 15 | 16 | genvar i; 17 | generate for (i = 0; i < WIDTH; i = i + 1) begin 18 | if (_TECHMAP_CONSTVAL_A_[i] === 1'b0 || _TECHMAP_CONSTVAL_B_[i] === 1'b0 || _TECHMAP_CONSTVAL_C_[i] === 1'b0) begin 19 | if (_TECHMAP_CONSTVAL_C_[i] === 1'b0) begin 20 | HAxp5_ASAP7_75t_L halfadder_Cconst ( 21 | .A(A[i]), 22 | .B(B[i]), 23 | .CON(NX[i]), .SN(NY[i]) 24 | ); 25 | end 26 | else begin 27 | if (_TECHMAP_CONSTVAL_B_[i] === 1'b0) begin 28 | HAxp5_ASAP7_75t_L halfadder_Bconst ( 29 | .A(A[i]), 30 | .B(C[i]), 31 | .CON(NX[i]), .SN(NY[i]) 32 | ); 33 | end 34 | else begin 35 | HAxp5_ASAP7_75t_L halfadder_Aconst ( 36 | .A(B[i]), 37 | .B(C[i]), 38 | .CON(NX[i]), .SN(NY[i]) 39 | ); 40 | end 41 | end 42 | end 43 | else begin 44 | FAx1_ASAP7_75t_L fulladder ( 45 | .A(A[i]), .B(B[i]), .CI(C[i]), .CON(NX[i]), .SN(NY[i]) 46 | ); 47 | end 48 | 49 | assign X[i] = ~NX[i]; 50 | assign Y[i] = ~NY[i]; 51 | 52 | end endgenerate 53 | 54 | endmodule 55 | -------------------------------------------------------------------------------- /src/xeda/platforms/asap7/yosys/cells_adders_R.v: -------------------------------------------------------------------------------- 1 | 2 | (* techmap_celltype = "$fa" *) 3 | module _tech_fa (A, B, C, X, Y); 4 | parameter WIDTH = 1; 5 | (* force_downto *) 6 | input [WIDTH-1 : 0] A, B, C; 7 | (* force_downto *) 8 | output [WIDTH-1 : 0] X, Y; 9 | 10 | wire [WIDTH-1 : 0] NX, NY; 11 | 12 | parameter _TECHMAP_CONSTVAL_A_ = WIDTH'bx; 13 | parameter _TECHMAP_CONSTVAL_B_ = WIDTH'bx; 14 | parameter _TECHMAP_CONSTVAL_C_ = WIDTH'bx; 15 | 16 | genvar i; 17 | generate for (i = 0; i < WIDTH; i = i + 1) begin 18 | if (_TECHMAP_CONSTVAL_A_[i] === 1'b0 || _TECHMAP_CONSTVAL_B_[i] === 1'b0 || _TECHMAP_CONSTVAL_C_[i] === 1'b0) begin 19 | if (_TECHMAP_CONSTVAL_C_[i] === 1'b0) begin 20 | HAxp5_ASAP7_75t_R halfadder_Cconst ( 21 | .A(A[i]), 22 | .B(B[i]), 23 | .CON(NX[i]), .SN(NY[i]) 24 | ); 25 | end 26 | else begin 27 | if (_TECHMAP_CONSTVAL_B_[i] === 1'b0) begin 28 | HAxp5_ASAP7_75t_R halfadder_Bconst ( 29 | .A(A[i]), 30 | .B(C[i]), 31 | .CON(NX[i]), .SN(NY[i]) 32 | ); 33 | end 34 | else begin 35 | HAxp5_ASAP7_75t_R halfadder_Aconst ( 36 | .A(B[i]), 37 | .B(C[i]), 38 | .CON(NX[i]), .SN(NY[i]) 39 | ); 40 | end 41 | end 42 | end 43 | else begin 44 | FAx1_ASAP7_75t_R fulladder ( 45 | .A(A[i]), .B(B[i]), .CI(C[i]), .CON(NX[i]), .SN(NY[i]) 46 | ); 47 | end 48 | 49 | assign X[i] = ~NX[i]; 50 | assign Y[i] = ~NY[i]; 51 | 52 | end endgenerate 53 | 54 | endmodule 55 | -------------------------------------------------------------------------------- /src/xeda/platforms/asap7/yosys/cells_adders_SL.v: -------------------------------------------------------------------------------- 1 | 2 | (* techmap_celltype = "$fa" *) 3 | module _tech_fa (A, B, C, X, Y); 4 | parameter WIDTH = 1; 5 | (* force_downto *) 6 | input [WIDTH-1 : 0] A, B, C; 7 | (* force_downto *) 8 | output [WIDTH-1 : 0] X, Y; 9 | 10 | wire [WIDTH-1 : 0] NX, NY; 11 | 12 | parameter _TECHMAP_CONSTVAL_A_ = WIDTH'bx; 13 | parameter _TECHMAP_CONSTVAL_B_ = WIDTH'bx; 14 | parameter _TECHMAP_CONSTVAL_C_ = WIDTH'bx; 15 | 16 | genvar i; 17 | generate for (i = 0; i < WIDTH; i = i + 1) begin 18 | if (_TECHMAP_CONSTVAL_A_[i] === 1'b0 || _TECHMAP_CONSTVAL_B_[i] === 1'b0 || _TECHMAP_CONSTVAL_C_[i] === 1'b0) begin 19 | if (_TECHMAP_CONSTVAL_C_[i] === 1'b0) begin 20 | HAxp5_ASAP7_75t_SL halfadder_Cconst ( 21 | .A(A[i]), 22 | .B(B[i]), 23 | .CON(NX[i]), .SN(NY[i]) 24 | ); 25 | end 26 | else begin 27 | if (_TECHMAP_CONSTVAL_B_[i] === 1'b0) begin 28 | HAxp5_ASAP7_75t_SL halfadder_Bconst ( 29 | .A(A[i]), 30 | .B(C[i]), 31 | .CON(NX[i]), .SN(NY[i]) 32 | ); 33 | end 34 | else begin 35 | HAxp5_ASAP7_75t_SL halfadder_Aconst ( 36 | .A(B[i]), 37 | .B(C[i]), 38 | .CON(NX[i]), .SN(NY[i]) 39 | ); 40 | end 41 | end 42 | end 43 | else begin 44 | FAx1_ASAP7_75t_SL fulladder ( 45 | .A(A[i]), .B(B[i]), .CI(C[i]), .CON(NX[i]), .SN(NY[i]) 46 | ); 47 | end 48 | 49 | assign X[i] = ~NX[i]; 50 | assign Y[i] = ~NY[i]; 51 | 52 | end endgenerate 53 | 54 | endmodule 55 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | minversion = 4.0 3 | envlist = py{310,311,312,313}, mypy, black, ruff 4 | requires = 5 | tox-gh-actions 6 | isolated_build = True 7 | 8 | [gh-actions] 9 | python = 10 | 3.10: py310, mypy 11 | 3.11: py311, mypy, ruff 12 | 3.12: py312, mypy, black, ruff 13 | 3.13: py313, mypy, black, ruff 14 | 15 | [testenv] 16 | passenv = 17 | HOME 18 | PIP_* 19 | PYTEST_* 20 | deps = 21 | pytest>7 22 | pytest-cov 23 | mypy 24 | pylint 25 | ruff 26 | -r examples/requirements.txt 27 | # extras = 28 | 29 | commands = 30 | pytest 31 | 32 | [testenv:pytest] 33 | minversion = 7.1 34 | addopts = 35 | --verbose 36 | --doctest-modules 37 | testpaths = 38 | tests/ 39 | # examples/vhdl/sqrt 40 | # examples 41 | asyncio_mode=auto 42 | deps = 43 | pytest>7 44 | pytest-cov 45 | -r examples/requirements.txt 46 | commands = 47 | pytest -s -v 48 | skip_install = false 49 | 50 | [testenv:mypy] 51 | testpaths = 52 | src/ 53 | deps = 54 | mypy>=0.991 55 | commands = 56 | python -m mypy --install-types --non-interactive src 57 | skip_install = false 58 | 59 | [testenv:pylint] 60 | testpaths = 61 | src/ 62 | deps = pylint 63 | commands = 64 | pylint --rcfile=pyproject.toml src 65 | 66 | [testenv:black] 67 | testpaths = 68 | src/ 69 | deps = 70 | black 71 | commands = 72 | black --check --diff src 73 | 74 | [pycodestyle] 75 | max-line-length = 100 76 | # extend-ignore = D,E203 # D: Docstring errors, E203: see https://github.com/PyCQA/pycodestyle/issues/373 77 | ignore = 78 | E501 79 | line-too-long 80 | missing-module-docstring 81 | missing-function-docstring 82 | indent-size = 4 83 | exclude = 84 | .github 85 | .eggs 86 | .tox 87 | -------------------------------------------------------------------------------- /tests/test_yosys.py: -------------------------------------------------------------------------------- 1 | import tempfile 2 | from pathlib import Path 3 | 4 | from xeda.flow_runner import DefaultRunner 5 | from xeda.flows import YosysFpga 6 | 7 | TESTS_DIR = Path(__file__).parent.absolute() 8 | EXAMPLES_DIR = TESTS_DIR.parent / "examples" 9 | 10 | 11 | def test_yosys_synth_py() -> None: 12 | # settings = dict(fpga=FPGA("xc7a12tcsg325-1"), clock_period=5.5) 13 | # run_dir = "tests_run_dir" 14 | design_paths = [ 15 | EXAMPLES_DIR / "boards" / "ulx3s" / "blinky" / "blinky.xeda.yaml", 16 | EXAMPLES_DIR / "vhdl" / "sqrt" / "sqrt.toml", 17 | EXAMPLES_DIR / "vhdl" / "Trivium" / "trivium.toml", 18 | EXAMPLES_DIR / "vhdl" / "Trivium" / "trivium.xeda.yaml", 19 | EXAMPLES_DIR / "boards" / "ulx3s" / "blinky" / "blinky_vhdl.xeda.yaml", 20 | ] 21 | with tempfile.TemporaryDirectory(dir=Path.cwd()) as run_dir: 22 | print("Xeda run dir: ", run_dir) 23 | for design in design_paths: 24 | xeda_runner = DefaultRunner(run_dir, debug=True) 25 | flow = xeda_runner.run(YosysFpga, design, flow_overrides=dict(debug=True, verbose=True)) 26 | assert flow is not None, "run_flow returned None" 27 | settings_json = flow.run_path / "settings.json" 28 | results_json = flow.run_path / "results.json" 29 | assert settings_json.exists() 30 | assert flow.succeeded 31 | assert isinstance(flow.settings, YosysFpga.Settings) 32 | assert flow.settings.fpga is not None 33 | if flow.settings.fpga.vendor == "xilinx": 34 | assert flow.results.LUT > 1 35 | assert flow.results.FF > 1 36 | assert results_json.exists() 37 | 38 | 39 | if __name__ == "__main__": 40 | test_yosys_synth_py() 41 | -------------------------------------------------------------------------------- /src/xeda/flows/openroad/openroad_scripts/gui.tcl: -------------------------------------------------------------------------------- 1 | # Read liberty files 2 | source $::env(SCRIPTS_DIR)/read_liberty.tcl 3 | 4 | # Read def 5 | if {[info exist ::env(DEF_FILE)]} { 6 | # Read lef 7 | read_lef $::env(TECH_LEF) 8 | read_lef $::env(SC_LEF) 9 | if {[info exist ::env(ADDITIONAL_LEFS)]} { 10 | foreach lef $::env(ADDITIONAL_LEFS) { 11 | read_lef $lef 12 | } 13 | } 14 | set input_file $::env(DEF_FILE) 15 | read_def $input_file 16 | } else { 17 | set input_file $::env(ODB_FILE) 18 | read_db $input_file 19 | } 20 | 21 | if {![info exist ::env(GUI_NO_TIMING)]} { 22 | # Determine design stage (1 ... 6) 23 | set design_stage [lindex [split [file tail $input_file] "_"] 0] 24 | 25 | # Read SDC, first try to find the most recent SDC file for the stage 26 | set sdc_file "" 27 | for {set s $design_stage} {$s > 0} {incr s -1} { 28 | set sdc_file [glob -nocomplain -directory {{settings.results_dir}} -types f "${s}_\[A-Za-z\]*\.sdc"] 29 | if {$sdc_file != ""} { 30 | break 31 | } 32 | } 33 | if {$sdc_file == ""} { 34 | set sdc_file $::env(SDC_FILE) 35 | } 36 | read_sdc $sdc_file 37 | if [file exists $::env(PLATFORM_DIR)/derate.tcl] { 38 | source $::env(PLATFORM_DIR)/derate.tcl 39 | } 40 | 41 | source $::env(PLATFORM_DIR)/setRC.tcl 42 | if {$design_stage >= 4} { 43 | # CTS has run, so propagate clocks 44 | set_propagated_clock [all_clocks] 45 | } 46 | 47 | if {$design_stage >= 6 && [file exist {{settings.results_dir}}/6_final.spef]} { 48 | puts "Loading spef" 49 | read_spef {{settings.results_dir}}/6_final.spef 50 | } elseif {$design_stage >= 3} { 51 | puts "Estimating parasitics" 52 | estimate_parasitics -placement 53 | } 54 | 55 | # Cleanup temporary variables 56 | unset sdc_file s design_stage 57 | } 58 | -------------------------------------------------------------------------------- /examples/boards/ulx3s/dvi_test/utils_pkg.vhdl: -------------------------------------------------------------------------------- 1 | --===============================================================================================-- 2 | --! @file utils_pkg.vhdl 3 | --! @brief Utility package 4 | --! @author Kamyar Mohajerani 5 | --! @copyright Copyright (c) 2022 Kamyar Mohajerani 6 | --! 7 | --! @license Solderpad Hardware License v2.1 ([SHL-2.1](https://solderpad.org/licenses/SHL-2.1/)) 8 | --! @vhdl VHDL 2008 and later 9 | --! 10 | --! @details collection of utility functions, procedures, type definitions, etc. 11 | --! 12 | --===============================================================================================-- 13 | 14 | library ieee; 15 | use ieee.std_logic_1164.all; 16 | use ieee.numeric_std.all; 17 | 18 | package utils_pkg is 19 | -- types 20 | type T_UNSIGNED_ARRAY is array (natural range <>) of unsigned; 21 | 22 | -- functions 23 | function log2ceil(n : natural) return natural; 24 | function sum_bits(slv : std_logic_vector) return unsigned; 25 | 26 | end package; 27 | 28 | package body utils_pkg is 29 | --! Returns the number of bits required to represet values less than n (0 to n - 1 inclusive) 30 | function log2ceil(n : natural) return natural is 31 | variable r : natural := 0; 32 | begin 33 | while n > 2 ** r loop 34 | r := r + 1; 35 | end loop; 36 | return r; 37 | end function; 38 | 39 | --! Returns the sum of all bits in `slv` 40 | function sum_bits(slv : std_logic_vector) return unsigned is 41 | variable sum : unsigned(log2ceil(slv'length + 1) - 1 downto 0) := (others => '0'); 42 | begin 43 | for i in slv'range loop 44 | sum := sum + slv(i); 45 | end loop; 46 | return sum; 47 | end function; 48 | 49 | end package body; 50 | -------------------------------------------------------------------------------- /examples/vhdl/full_adder_tb.vhd: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | -- Testbench for full_adder 3 | -- Adopted from https://vhdlguide.readthedocs.io/en/latest/vhdl/testbench.html 4 | ------------------------------------------------------------------------------- 5 | 6 | library ieee; 7 | use ieee.std_logic_1164.all; 8 | 9 | entity full_adder_tb is 10 | end full_adder_tb; 11 | 12 | architecture behavior of full_adder_tb is 13 | component full_adder is 14 | port ( 15 | a : in std_logic; 16 | b : in std_logic; 17 | ci : in std_logic; 18 | s : out std_logic; 19 | co : out std_logic); 20 | end component; 21 | signal a, b, ci, s, co : std_logic; 22 | 23 | type test_vector is record 24 | a, b, ci : std_logic; 25 | s, co : std_logic; 26 | end record; 27 | 28 | type test_vector_array is array (natural range <>) of test_vector; 29 | constant test_vectors : test_vector_array := ( 30 | -- a, b, ci, s , co 31 | ('0', '0', '0', '0', '0'), 32 | ('0', '0', '1', '1', '0'), 33 | ('0', '1', '0', '1', '0'), 34 | ('1', '0', '0', '1', '0'), 35 | ('1', '1', '0', '0', '1'), 36 | ('0', '1', '1', '0', '1'), 37 | ('1', '0', '1', '0', '1'), 38 | ('1', '1', '1', '1', '1') 39 | ); 40 | begin 41 | uut : full_adder port map( 42 | a => a, 43 | b => b, 44 | ci => ci, 45 | s => s, 46 | co => co 47 | ); 48 | stim_proc : process 49 | constant delay : time := 10 ns; 50 | begin 51 | for i in test_vectors'range loop 52 | a <= test_vectors(i).a; 53 | b <= test_vectors(i).b; 54 | ci <= test_vectors(i).ci; 55 | wait for delay; 56 | assert (s = test_vectors(i).s) and (co = test_vectors(i).co) 57 | report "test_vector " & integer'image(i) & " failed" severity failure; 58 | end loop; 59 | report "full_adder_tb finished!"; 60 | wait; 61 | end process; 62 | end; -------------------------------------------------------------------------------- /src/xeda/platforms/asap7/config.lvt.toml: -------------------------------------------------------------------------------- 1 | platform = "asap7.lvt" 2 | version = "2.0" 3 | extends = "asap7" 4 | 5 | 6 | tiehi_cell = "TIEHIx1_ASAP7_75t_L" 7 | tiehi_port = "H" 8 | tielo_cell = "TIELOx1_ASAP7_75t_L" 9 | tielo_port = "L" 10 | min_buf_cells = "BUFx2_ASAP7_75t_L" 11 | min_buf_ports = ["A", "Y"] 12 | hold_buf_cell = "BUFx2_ASAP7_75t_L" 13 | abc_driver_cell = "BUFx2_ASAP7_75t_L" 14 | cts_buf_cell = "BUFx4_ASAP7_75t_L" 15 | fill_cells = "FILLERxp5_ASAP7_75t_L" 16 | tap_cell_name = "TAPCELL_ASAP7_75t_L" 17 | gds_files = ["gds/asap7sc7p5t_28_L_220121a.gds"] 18 | sc_lef = "lef/asap7sc7p5t_28_L_1x_220121a.lef" 19 | latch_map_file = "yosys/cells_latch_L.v" 20 | clkgate_map_file = "yosys/cells_clkgate_L.v" 21 | adder_map_file = "yosys/cells_adders_L.v" # overridable 22 | 23 | [corner.FF] 24 | dff_lib_file = "lib/asap7sc7p5t_SEQ_LVT_FF_nldm_220123.lib" 25 | lib_files = [ 26 | "lib/asap7sc7p5t_AO_LVT_FF_nldm_211120.lib.gz", 27 | "lib/asap7sc7p5t_INVBUF_LVT_FF_nldm_220122.lib.gz", 28 | "lib/asap7sc7p5t_OA_LVT_FF_nldm_211120.lib.gz", 29 | "lib/asap7sc7p5t_SIMPLE_LVT_FF_nldm_211120.lib.gz", 30 | "lib/asap7sc7p5t_SEQ_LVT_FF_nldm_220123.lib", 31 | ] 32 | 33 | [corner.SS] 34 | dff_lib_file = "lib/asap7sc7p5t_SEQ_LVT_SS_nldm_220123.lib" 35 | lib_files = [ 36 | "lib/asap7sc7p5t_AO_LVT_SS_nldm_211120.lib.gz", 37 | "lib/asap7sc7p5t_INVBUF_LVT_SS_nldm_220122.lib.gz", 38 | "lib/asap7sc7p5t_OA_LVT_SS_nldm_211120.lib.gz", 39 | "lib/asap7sc7p5t_SEQ_LVT_SS_nldm_220123.lib", 40 | "lib/asap7sc7p5t_SIMPLE_LVT_SS_nldm_211120.lib.gz", 41 | ] 42 | 43 | [corner.TT] 44 | dff_lib_file = "lib/asap7sc7p5t_SEQ_LVT_TT_nldm_220123.lib" 45 | lib_files = [ 46 | "lib/asap7sc7p5t_AO_LVT_TT_nldm_211120.lib.gz", 47 | "lib/asap7sc7p5t_INVBUF_LVT_TT_nldm_220122.lib.gz", 48 | "lib/asap7sc7p5t_OA_LVT_TT_nldm_211120.lib.gz", 49 | "lib/asap7sc7p5t_SEQ_LVT_TT_nldm_220123.lib", 50 | "lib/asap7sc7p5t_SIMPLE_LVT_TT_nldm_211120.lib.gz", 51 | ] 52 | -------------------------------------------------------------------------------- /src/xeda/flows/yosys/templates/write_netlist.tcl: -------------------------------------------------------------------------------- 1 | {% for arg in settings.post_synth_rename -%} 2 | yosys rename {{arg}} 3 | {% endfor -%} 4 | 5 | tee -o "final_check.log" check {% if settings.check_assert %} -assert {% endif %} 6 | 7 | yosys log -stdout "Writing stat to {{artifacts["utilization_report"]}}" 8 | tee -q -o {{artifacts["utilization_report"]}} stat {% if (artifacts.utilization_report|string).endswith(".json") %} -json {% endif %} {% if settings.liberty is defined and settings.liberty %} {% for lib in settings.liberty %} -liberty {{lib}} {% endfor %} {% elif settings.gates is defined and settings.gates %} -tech cmos {% endif %} 9 | {% if settings.sta -%} 10 | yosys log -stdout "Writing timing report to {{artifacts["timing_report"]}}" 11 | tee -o {{artifacts["timing_report"]}} ltp 12 | tee -a {{artifacts["timing_report"]}} sta 13 | {% endif -%} 14 | 15 | {% if settings.ltp -%} 16 | tee -o ltp.out ltp 17 | {% endif -%} 18 | 19 | {% if settings.debug or settings.verbose > 1 -%} 20 | yosys echo on 21 | {% endif -%} 22 | 23 | {% if artifacts.netlist_json -%} 24 | yosys log -stdout "Writing netlist {{artifacts.netlist_json}}" 25 | yosys write_json {{artifacts.netlist_json}} 26 | {% endif -%} 27 | 28 | {% if artifacts.netlist_verilog -%} 29 | {% for attr in settings.netlist_unset_attributes -%} 30 | yosys setattr -unset {{attr}} 31 | {% endfor -%} 32 | yosys log -stdout "Writing netlist {{artifacts.netlist_verilog}}" 33 | yosys write_verilog {{settings.netlist_verilog_flags|join(" ")}} {{artifacts.netlist_verilog}} 34 | {% endif -%} 35 | 36 | {% if settings.write_blif -%} 37 | yosys log -stdout "Writing BLIF to {{settings.write_blif}}" 38 | yosys write_blif -noalias {{settings.write_blif}} 39 | {% endif -%} 40 | 41 | {% if settings.netlist_graph -%} 42 | yosys log -stdout "Writing netlist graph to {{settings.netlist_graph.with_suffix('.dot')}}" 43 | yosys show -prefix {{settings.netlist_graph.with_suffix("")}} -format dot {{settings.netlist_graph_flags|join(" ")}} 44 | {% endif -%} 45 | -------------------------------------------------------------------------------- /src/xeda/platforms/asap7/config.slvt.toml: -------------------------------------------------------------------------------- 1 | platform = "asap7.slvt" 2 | version = "2.0" 3 | extends = "asap7" 4 | 5 | 6 | tiehi_cell = "TIEHIx1_ASAP7_75t_SL" 7 | tiehi_port = "H" 8 | tielo_cell = "TIELOx1_ASAP7_75t_SL" 9 | tielo_port = "L" 10 | min_buf_cell = "BUFx2_ASAP7_75t_SL" 11 | min_buf_ports = ["A", "Y"] 12 | hold_buf_cell = "BUFx2_ASAP7_75t_SL" 13 | abc_driver_cell = "BUFx2_ASAP7_75t_SL" 14 | cts_buf_cell = "BUFx4_ASAP7_75t_SL" 15 | fill_cells = "FILLERxp5_ASAP7_75t_SL" 16 | tap_cell_name = "TAPCELL_ASAP7_75t_SL" 17 | gds_files = ["gds/asap7sc7p5t_28_SL_220121a.gds"] 18 | sc_lef = "lef/asap7sc7p5t_28_SL_1x_220121a.lef" 19 | latch_map_file = "yosys/cells_latch_SL.v" 20 | clkgate_map_file = "yosys/cells_clkgate_SL.v" 21 | adder_map_file = "yosys/cells_adders_SL.v" # overridable 22 | 23 | [corner.FF] 24 | dff_lib_file = "lib/asap7sc7p5t_SEQ_SLVT_FF_nldm_220123.lib" 25 | lib_files = [ 26 | "lib/asap7sc7p5t_AO_SLVT_FF_nldm_211120.lib.gz", 27 | "lib/asap7sc7p5t_INVBUF_SLVT_FF_nldm_220122.lib.gz", 28 | "lib/asap7sc7p5t_OA_SLVT_FF_nldm_211120.lib.gz", 29 | "lib/asap7sc7p5t_SIMPLE_SLVT_FF_nldm_211120.lib.gz", 30 | "lib/asap7sc7p5t_SEQ_SLVT_FF_nldm_220123.lib", 31 | ] 32 | 33 | [corner.SS] 34 | dff_lib_file = "lib/asap7sc7p5t_SEQ_SLVT_SS_nldm_220123.lib" 35 | lib_files = [ 36 | "lib/asap7sc7p5t_AO_SLVT_SS_nldm_211120.lib.gz", 37 | "lib/asap7sc7p5t_INVBUF_SLVT_SS_nldm_220122.lib.gz", 38 | "lib/asap7sc7p5t_OA_SLVT_SS_nldm_211120.lib.gz", 39 | "lib/asap7sc7p5t_SEQ_SLVT_SS_nldm_220123.lib", 40 | "lib/asap7sc7p5t_SIMPLE_SLVT_SS_nldm_211120.lib.gz", 41 | ] 42 | 43 | [corner.TT] 44 | dff_lib_file = "lib/asap7sc7p5t_SEQ_SLVT_TT_nldm_220123.lib" 45 | lib_files = [ 46 | "lib/asap7sc7p5t_AO_SLVT_TT_nldm_211120.lib.gz", 47 | "lib/asap7sc7p5t_INVBUF_SLVT_TT_nldm_220122.lib.gz", 48 | "lib/asap7sc7p5t_OA_SLVT_TT_nldm_211120.lib.gz", 49 | "lib/asap7sc7p5t_SEQ_SLVT_TT_nldm_220123.lib", 50 | "lib/asap7sc7p5t_SIMPLE_SLVT_TT_nldm_211120.lib.gz", 51 | ] 52 | -------------------------------------------------------------------------------- /src/xeda/flows/vivado/templates/util.tcl: -------------------------------------------------------------------------------- 1 | proc reportCriticalPaths {fileName} { 2 | set FH [open $fileName w] 3 | puts $FH "Startpoint,StartClock,Endpoint,EndClock,Slack,Levels,LogicDelay,TotalDelay" 4 | # (max = setup/recovery, min = hold/removal) 5 | foreach path [get_timing_paths -delay_type max -max_paths 50 -nworst 1] { 6 | set startpoint [get_property STARTPOINT_PIN $path] 7 | set startclock [get_property STARTPOINT_CLOCK $path] 8 | set endpoint [get_property ENDPOINT_PIN $path] 9 | set endclock [get_property ENDPOINT_CLOCK $path] 10 | # Get the slack on the Timing Path object 11 | set slack [get_property SLACK $path] 12 | # Get the number of logic levels between startpoint and endpoint 13 | set levels [get_property LOGIC_LEVELS $path] 14 | # Get the logic delay 15 | set logic_delay [get_property DATAPATH_LOGIC_DELAY $path] 16 | # Get the total datapath delay 17 | set delay [get_property DATAPATH_DELAY $path] 18 | # Write to the CSV file 19 | puts $FH "$startpoint,$startclock,$endpoint,$endclock,$slack,$levels,$logic_delay,$delay" 20 | } 21 | close $FH 22 | puts "Created critical paths report: $fileName\n" 23 | } 24 | 25 | proc showWarningsAndErrors {} { 26 | set num_errors [get_msg_config -severity {ERROR} -count] 27 | set num_crit_warns [get_msg_config -severity {CRITICAL WARNING} -count] 28 | set num_warns [get_msg_config -severity {WARNING} -count] 29 | if {$num_errors > 0} { 30 | puts "Exiting Vivado due to $num_errors error(s)!" 31 | exit 1 32 | } 33 | if {$num_crit_warns > 0} { 34 | puts "** Number of Critical Warnings: $num_crit_warns" 35 | {%- if settings.fail_critical_warning %} 36 | puts "Exiting due to $num_crit_warns critical warning(s)!" 37 | exit 1 38 | {%- endif %} 39 | } 40 | # if $num_warns is non-emty and not zero 41 | if {[string length $num_warns] > 0 && $num_warns != 0} { 42 | puts "** Number of Warnings: $num_warns" 43 | } 44 | puts "\n" 45 | } 46 | -------------------------------------------------------------------------------- /src/xeda/flows/quartus/templates/create_project.tcl: -------------------------------------------------------------------------------- 1 | set design_name {{design.name}} 2 | set top {{design.rtl.top}} 3 | set fpga_part {{settings.fpga.part}} 4 | {%- if settings.debug %} 5 | foreach key [array names quartus] { 6 | puts "${key}=$quartus($key)" 7 | } 8 | {%- endif %} 9 | 10 | package require ::quartus::project 11 | 12 | puts "\n===========================( Setting up project and settings )===========================" 13 | project_new ${design_name} -overwrite 14 | {% if settings.nthreads is not none %} 15 | set_global_assignment -name NUM_PARALLEL_PROCESSORS {{settings.nthreads}} 16 | {% endif %} 17 | puts "supported FPGA families: [get_family_list]" 18 | 19 | set fpga_part_report [report_part_info $fpga_part] 20 | puts $fpga_part_report 21 | 22 | {%- if settings.fpga.family %} 23 | set_global_assignment -name FAMILY "{{settings.fpga.family}}" 24 | {%- endif %} 25 | # Use get_part_list to get a list of supported part numbers 26 | set_global_assignment -name DEVICE $fpga_part 27 | 28 | set_global_assignment -name TOP_LEVEL_ENTITY ${top} 29 | 30 | {%- if design.language.vhdl.standard %} 31 | set_global_assignment -name VHDL_INPUT_VERSION VHDL_{{design.language.vhdl.standard}} 32 | {%- endif %} 33 | 34 | {%- for src in design.rtl.sources %} 35 | set_global_assignment -name {{src.type.name|upper}}_FILE {{src.file}} 36 | {%- endfor %} 37 | 38 | {%- for k,v in design.rtl.parameters.items() %} 39 | set_parameter -name {{k}} {%if v is boolean -%} {{"true" if v else "false"}} {% elif v is string -%} "{{v}}" {%else-%} {{v}} {%endif%} 40 | {%- endfor %} 41 | 42 | {%- for sdc_file in sdc_files %} 43 | set_global_assignment -name SDC_FILE {{sdc_file}} 44 | {%- endfor %} 45 | 46 | {%- for k,v in project_settings.items() %} 47 | {%- if v is not none %} 48 | set_global_assignment -name {{k}} {%if v is boolean -%} {{"ON" if v else "OFF"}} {% elif v is number -%} {{v}} {%- else -%} "{{v}}" {%- endif %} 49 | {%- endif %} 50 | {%- endfor %} 51 | 52 | project_close -------------------------------------------------------------------------------- /src/xeda/platforms/asap7/openlane/mapping.json: -------------------------------------------------------------------------------- 1 | { 2 | "liberty": { 3 | "pdk": "flow/platforms/asap7/lib", 4 | "openlane": "libs.ref/asap7sc7p5t/lib", 5 | "files": ["*RVT*.lib"] 6 | }, 7 | "techlef": { 8 | "pdk": "flow/platforms/asap7/lef", 9 | "openlane": "libs.ref/asap7sc7p5t/techlef", 10 | "files": ["asap7_tech_1x_201209.lef"] 11 | }, 12 | "lef": { 13 | "pdk": "flow/platforms/asap7/lef", 14 | "openlane": "libs.ref/asap7sc7p5t/lef", 15 | "files": ["asap7sc7p5t_27_R_1x_201211.lef"] 16 | }, 17 | "gds": { 18 | "pdk": "flow/platforms/asap7/gds", 19 | "openlane": "libs.ref/asap7sc7p5t/gds", 20 | "files": ["asap7sc7p5t_27_R_1x_201211.gds"] 21 | }, 22 | "klayout": { 23 | "pdk": "flow/platforms/asap7/KLayout", 24 | "openlane": "libs.tech/klayout", 25 | "files": ["*.lyp", "*.lyt"] 26 | }, 27 | "rcx": { 28 | "pdk": "flow/platforms/asap7", 29 | "openlane": "libs.tech/openlane", 30 | "files": ["*.rules"] 31 | }, 32 | "config-platform": { 33 | "pdk": "flow/platforms/asap7/openlane", 34 | "openlane": "libs.tech/openlane", 35 | "files": ["config.tcl"] 36 | }, 37 | "config-stdcells": { 38 | "pdk": "flow/platforms/asap7/openlane/asap7sc7p5t", 39 | "openlane": "libs.tech/openlane/asap7sc7p5t", 40 | "files": ["config.tcl"] 41 | }, 42 | "pdn": { 43 | "pdk": "flow/platforms/asap7/openRoad/pdn", 44 | "openlane": "libs.tech/openlane/asap7sc7p5t", 45 | "files": ["grid_strategy-M1-M2-M5-M6.cfg"] 46 | }, 47 | "tracks": { 48 | "pdk": "flow/platforms/asap7/openRoad", 49 | "openlane": "libs.tech/openlane/asap7sc7p5t", 50 | "files": ["make_tracks.tcl"] 51 | }, 52 | "dont-use": { 53 | "pdk": "flow/platforms/asap7/openlane/asap7sc7p5t", 54 | "openlane": "libs.tech/openlane/asap7sc7p5t", 55 | "files": ["no_synth.cells"] 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/xeda/flows/openroad/templates/detailed_route.tcl: -------------------------------------------------------------------------------- 1 | set_propagated_clock [all_clocks] 2 | 3 | {% if settings.nthreads %} 4 | set_thread_count {{settings.nthreads}} 5 | {% endif %} 6 | 7 | {%- set additional_args = settings.detailed_route_additional_args|join(" ") %} 8 | {%- if platform.min_routing_layer %} 9 | {%- set additional_args = additional_args + " -bottom_routing_layer " + platform.min_routing_layer %} 10 | {%- endif %} 11 | {%- if platform.max_routing_layer %} 12 | {%- set additional_args = additional_args + " -top_routing_layer " + platform.max_routing_layer %} 13 | {%- endif %} 14 | {%- if platform.via_in_pin_min_layer %} 15 | {%- set additional_args = additional_args + " -via_in_pin_bottom_layer " + platform.via_in_pin_min_layer %} 16 | {%- endif %} 17 | {%- if platform.via_in_pin_max_layer %} 18 | {%- set additional_args = additional_args + " -via_in_pin_bottom_layer " + platform.via_in_pin_max_layer %} 19 | {%- endif %} 20 | {%- if settings.disable_via_gen %} 21 | {%- set additional_args = additional_args + " -disable_via_gen" %} 22 | {%- endif %} 23 | {%- if settings.db_process_node is not none %} 24 | {%- set additional_args = additional_args + " -db_process_node " + settings.db_process_node %} 25 | {%- endif %} 26 | {%- if settings.detailed_route_or_seed is not none %} 27 | {%- set additional_args = additional_args + " -or-seed " + settings.detailed_route_or_seed %} 28 | {%- endif %} 29 | {%- if settings.detailed_route_or_k is not none %} 30 | {%- set additional_args = additional_args + " -or-k " + settings.detailed_route_or_k %} 31 | {%- endif %} 32 | {%- if settings.repair_pdn_via_layer %} 33 | {%- set additional_args = additional_args + " -repair_pdn_vias " + settings.repair_pdn_via_layer %} 34 | {%- endif %} 35 | 36 | detailed_route -output_drc {{settings.reports_dir}}/{{step_id}}_drc.rpt \ 37 | -output_maze {{settings.results_dir}}/maze.log \ 38 | -save_guide_updates -verbose {{settings.verbose}} {{additional_args}} 39 | 40 | {% if settings.post_detailed_route_tcl %} 41 | source {{settings.post_detailed_route_tcl}} 42 | {% endif %} 43 | 44 | {{ write_checkpoint(step) }} 45 | -------------------------------------------------------------------------------- /src/xeda/flows/openroad/templates/finalize.tcl: -------------------------------------------------------------------------------- 1 | {{ load_checkpoint(step, sdc_from="cts") }} 2 | 3 | set_propagated_clock [all_clocks] 4 | 5 | # Ensure all OR created (rsz/cts) instances are connected 6 | global_connect 7 | 8 | # Delete routing obstructions for final DEF 9 | deleteRoutingObstructions 10 | 11 | {%- if settings.density_fill %} 12 | density_fill -rules {{platform.fill_config}} 13 | {%- endif %} 14 | 15 | {{ write_checkpoint(step, verilog=true, def=true) }} 16 | 17 | {% if platform.default_corner_settings.rcx_rules %} 18 | puts "Starting RCX" 19 | # RCX section 20 | define_process_corner -ext_model_index 0 X 21 | extract_parasitics -ext_model_file {{platform.default_corner_settings.rcx_rules}} 22 | 23 | set spef_file $results_dir/{{step_id}}.spef 24 | write_spef $spef_file 25 | file delete {{design.rtl.top}}.totCap 26 | 27 | # Read Spef for OpenSTA 28 | if { [file exists $spef_file]} { 29 | read_spef $spef_file 30 | } else { 31 | utl::error FLW 99 "SPEF file $spef_file does not exist!" 32 | } 33 | 34 | {% if settings.final_irdrop_analysis %} 35 | # Static IR drop analysis 36 | {% for net, voltage in platform.pwr_nets_voltages.items() %} 37 | puts "set_pdnsim_net_voltage {{net}}..." 38 | set_pdnsim_net_voltage -net {{net}} -voltage {{voltage}} 39 | puts "analyze_power_grid {{net}}..." 40 | analyze_power_grid -net {{net}} 41 | {% endfor %} 42 | {% for net, voltage in platform.gnd_nets_voltages.items() %} 43 | puts "set_pdnsim_net_voltage {{net}}..." 44 | set_pdnsim_net_voltage -net {{net}} -voltage {{voltage}} 45 | puts "analyze_power_grid {{net}}..." 46 | analyze_power_grid -net {{net}} 47 | {% endfor %} 48 | {% endif %} 49 | 50 | {% endif %} 51 | 52 | {% if settings.write_cdl and settings.cdl_masters_file %} 53 | write_cdl -masters {{cdl_masters_file}} $results_dir/{{step_id}}.cdl 54 | {% endif %} 55 | 56 | report_metrics {{step}} 57 | 58 | {% if settings.save_images %} 59 | {% include "save_images.tcl" %} 60 | 61 | # Save a final image if openroad is compiled with the gui 62 | if {[expr [llength [info procs save_image]] > 0]} { 63 | gui::show save_images false 64 | } 65 | {% endif %} 66 | -------------------------------------------------------------------------------- /src/xeda/flows/openroad/templates/macros.tcl.j2: -------------------------------------------------------------------------------- 1 | {% macro banner(msg, line_len = 80, line_char="=", top_line=true, bottom_line=true) %} 2 | {% set msg_len = (msg|length) %} 3 | {% set sp1 = (line_len - msg_len) // 2 %} 4 | {% set sp2 = line_len - sp1 - msg_len %} 5 | {% if top_line %} 6 | puts "{{ line_char * line_len }}" 7 | {% endif %} 8 | puts "{{ line_char * sp1 }}{{msg}}{{line_char * sp2 }}" 9 | {% if bottom_line %} 10 | puts "{{ line_char * line_len }}" 11 | {% endif %} 12 | {% endmacro %} 13 | 14 | {% macro preamble(step, step_index) %} 15 | {% set msg = (" Starting %s (%d/%d) "|format(step, step_index + 1, total_steps)) %} 16 | {{ banner(msg) }} 17 | {% endmacro %} 18 | 19 | {% macro epilogue(step) %} 20 | {{ banner("( %s done )"|format(step), line_char="-", top_line=false, bottom_line=false) }} 21 | {% endmacro %} 22 | 23 | {% macro load_checkpoint(step, sdc_from=none) %} 24 | {% set prev_step_id = get_prev_step_id(step) %} 25 | {% if prev_step_id and should_load_checkpoint(step) %} 26 | read_libraries 27 | read_db {{settings.checkpoints_dir}}/{{prev_step_id}}.odb 28 | {% if sdc_from %} 29 | {% set sdc_step_id = get_step_id(sdc_from) %} 30 | read_sdc {{settings.results_dir}}/{{sdc_step_id}}.sdc 31 | {% endif %} 32 | {% if platform.derate_tcl %} 33 | source {{platform.derate_tcl}} 34 | {% endif %} 35 | {% if platform.setrc_tcl %} 36 | source {{platform.setrc_tcl}} 37 | {% endif %} 38 | {% endif %} 39 | {% endmacro %} 40 | 41 | {% macro write_checkpoint(step, db=true, sdc=false, def=false, verilog=false) %} 42 | {% set step_id = get_step_id(step) %} 43 | {% if should_write_checkpoint(step) %} 44 | {% if db %} 45 | write_db {{settings.checkpoints_dir}}/{{step_id}}.odb 46 | {% endif %} 47 | {% if sdc %} 48 | write_sdc {{settings.results_dir}}/{{step_id}}.sdc 49 | {% endif %} 50 | {% if def %} 51 | write_def {{settings.results_dir}}/{{step_id}}.def 52 | {% endif %} 53 | {% if verilog %} 54 | write_verilog {{settings.results_dir}}/{{step_id}}.v 55 | {% endif %} 56 | {% endif %} 57 | {% endmacro %} 58 | 59 | {% macro section(name) %} 60 | {{ banner(" %s "|format(name), line_char="-", top_line=false, bottom_line=false) }} 61 | {% endmacro %} 62 | -------------------------------------------------------------------------------- /src/xeda/platforms/asap7/openroad/pdn/grid_strategy-M1-M2-M5-M6.tcl: -------------------------------------------------------------------------------- 1 | #################################### 2 | # global connections 3 | #################################### 4 | add_global_connection -net {VDD} -inst_pattern {.*} -pin_pattern {^VDD$} -power 5 | add_global_connection -net {VDD} -inst_pattern {.*} -pin_pattern {^VDDPE$} 6 | add_global_connection -net {VDD} -inst_pattern {.*} -pin_pattern {^VDDCE$} 7 | add_global_connection -net {VSS} -inst_pattern {.*} -pin_pattern {^VSS$} -ground 8 | add_global_connection -net {VSS} -inst_pattern {.*} -pin_pattern {^VSSE$} 9 | global_connect 10 | #################################### 11 | # voltage domains 12 | #################################### 13 | set_voltage_domain -name {CORE} -power {VDD} -ground {VSS} 14 | #################################### 15 | # standard cell grid 16 | #################################### 17 | define_pdn_grid -name {top} -voltage_domains {CORE} 18 | add_pdn_stripe -grid {top} -layer {M1} -width {0.018} -pitch {0.54} -offset {0} -followpins 19 | add_pdn_stripe -grid {top} -layer {M2} -width {0.018} -pitch {0.54} -offset {0} -followpins 20 | add_pdn_stripe -grid {top} -layer {M5} -width {0.12} -spacing {0.072} -pitch {11.88} -offset {0.300} 21 | add_pdn_stripe -grid {top} -layer {M6} -width {0.288} -spacing {0.096} -pitch {12} -offset {0.513} 22 | add_pdn_connect -grid {top} -layers {M1 M2} 23 | add_pdn_connect -grid {top} -layers {M2 M5} 24 | add_pdn_connect -grid {top} -layers {M5 M6} 25 | #################################### 26 | # macro grids 27 | #################################### 28 | #################################### 29 | # grid for: CORE_macro_grid_1 30 | #################################### 31 | define_pdn_grid -name {CORE_macro_grid_1} -voltage_domains {CORE} -macro -orient {R0 R180 MX MY} -cells {.*} 32 | add_pdn_connect -grid {CORE_macro_grid_1} -layers {M4 M5} 33 | #################################### 34 | # grid for: CORE_macro_grid_2 35 | #################################### 36 | define_pdn_grid -name {CORE_macro_grid_2} -voltage_domains {CORE} -macro -orient {R90 R270 MXR90 MYR90} -cells {.*} 37 | add_pdn_connect -grid {CORE_macro_grid_2} -layers {M4 M5} 38 | -------------------------------------------------------------------------------- /src/xeda/flows/yosys/templates/yosys_fpga_synth.tcl: -------------------------------------------------------------------------------- 1 | yosys logger -notime -stderr 2 | {% include 'read_files.tcl' -%} 3 | 4 | {% if settings.prep is not none -%} 5 | yosys prep {%- if settings.flatten %} -flatten {%- endif %} {%- if design.rtl.top %} -top {{design.rtl.top}} {%- else %} -auto-top {%- endif %} {{settings.prep|join(" ")}} 6 | {% else %} 7 | yosys proc 8 | {% if settings.flatten -%} 9 | yosys flatten 10 | {% endif -%} 11 | {% endif -%} 12 | 13 | {% include "post_rtl.tcl" -%} 14 | 15 | {% if settings.pre_synth_opt -%} 16 | yosys log -stdout "** Pre-synthesis optimization **" 17 | yosys opt -undriven -purge -keepdc -noff 18 | {% endif -%} 19 | 20 | yosys opt_clean -purge 21 | 22 | {% if settings.abc9 -%} 23 | {% if settings.flow3 -%} yosys scratchpad -copy abc9.script.flow3 abc9.script {%- endif %} 24 | {# decrease the target delay to account for interconnect delay #} 25 | {% if settings.main_clock and settings.main_clock.period_ps -%} yosys scratchpad -set abc9.D {{settings.main_clock.period_ps / 1.5}} {%- endif %} 26 | {% endif -%} 27 | 28 | yosys log -stdout "** FPGA synthesis for device {{settings.fpga}} **" 29 | {% if settings.fpga.vendor == "xilinx" -%} 30 | yosys log -stdout "*** Target: Xilinx {%if settings.fpga.part%} {{settings.fpga.part}} {%else%} {{settings.fpga.device}} {%endif%} ***" 31 | yosys synth_xilinx {% if settings.fpga.family %} -family {{"xc7" if settings.fpga.family.endswith("7") else settings.fpga.family}} {% endif %} {{settings.synth_flags|join(" ")}} 32 | {% elif settings.fpga.family %} 33 | yosys log -stdout "*** Target: {{settings.fpga.family}} ***" 34 | yosys synth_{{settings.fpga.family}} {{settings.synth_flags|join(" ")}} {% if design.rtl.top %} -top {{design.rtl.top}}{% endif %} 35 | {% else %} 36 | yosys log -stdout "[ERROR] Unknown FPGA vendor, family, or device" 37 | {% endif -%} 38 | 39 | 40 | {% if settings.post_synth_opt -%} 41 | yosys log -stdout "** Post-synthesis optimization **" 42 | yosys opt -full -fine -purge -sat -undriven 43 | {% endif -%} 44 | 45 | yosys opt_clean -purge 46 | 47 | {% if settings.splitnets -%} 48 | yosys splitnets 49 | {% endif -%} 50 | 51 | {% include "write_netlist.tcl" -%} 52 | -------------------------------------------------------------------------------- /src/xeda/flows/__init__.py: -------------------------------------------------------------------------------- 1 | # all Flow classes imported here can be used from FlowRunners and will be reported on the command-line help 2 | from __future__ import annotations 3 | 4 | import pkgutil 5 | from importlib import import_module 6 | from inspect import isabstract, isclass 7 | from typing import List, Type 8 | 9 | from ..flow import Flow 10 | from .bsc import Bsc 11 | from .dc import Dc 12 | from .diamond import DiamondSynth 13 | from .ghdl import GhdlSim, GhdlSynth 14 | from .ise import IseSynth 15 | from .modelsim import Modelsim 16 | from .nextpnr import Nextpnr 17 | from .nvc import Nvc 18 | from .openfpgaloader import Openfpgaloader 19 | from .openroad import Openroad 20 | from .openxc7 import OpenXC7 21 | from .quartus import Quartus 22 | from .vcs import Vcs 23 | from .verilator import Verilator 24 | from .vivado.vivado_alt_synth import VivadoAltSynth 25 | from .vivado.vivado_postsynthsim import VivadoPostsynthSim 26 | from .vivado.vivado_power import VivadoPower 27 | from .vivado.vivado_project import VivadoProject 28 | from .vivado.vivado_sim import VivadoSim 29 | from .vivado.vivado_synth import VivadoSynth 30 | from .yosys import CxxRtl, Yosys, YosysFpga 31 | 32 | __builtin_flows__: List[Type[Flow]] = [] 33 | 34 | __all__ = [ 35 | "__builtin_flows__", 36 | "Dc", 37 | "Bsc", 38 | "CxxRtl", 39 | "DiamondSynth", 40 | "GhdlSim", 41 | "GhdlSynth", 42 | "IseSynth", 43 | "Modelsim", 44 | "Nextpnr", 45 | "Nvc", 46 | "Openfpgaloader", 47 | "Openroad", 48 | "OpenXC7", 49 | "Quartus", 50 | "Nvc", 51 | "Verilator", 52 | "VivadoAltSynth", 53 | "VivadoPostsynthSim", 54 | "VivadoPower", 55 | "VivadoProject", 56 | "VivadoSim", 57 | "VivadoSynth", 58 | "Yosys", 59 | "YosysFpga", 60 | "Vcs", 61 | ] 62 | 63 | for loader, module_name, is_pkg in pkgutil.walk_packages(__path__): 64 | module = import_module("." + module_name, __package__) 65 | for attribute_name in dir(module): 66 | cls = getattr(module, attribute_name) 67 | if isclass(cls) and issubclass(cls, Flow) and not isabstract(cls): 68 | __builtin_flows__.append(cls) 69 | -------------------------------------------------------------------------------- /src/xeda/flows/openroad/templates/global_route.tcl: -------------------------------------------------------------------------------- 1 | {% if platform.fastroute_tcl %} 2 | source {{platform.fastroute_tcl}} 3 | {% else %} 4 | set_global_routing_layer_adjustment {{platform.min_routing_layer}}-{{platform.max_routing_layer}} {{settings.global_routing_layer_adjustment}} 5 | set_routing_layers -signal {{platform.min_routing_layer}}-{{platform.max_routing_layer}} 6 | {% endif %} 7 | 8 | global_route -guide_file {{settings.results_dir}}/route.guide \ 9 | -congestion_iterations {{settings.congestion_iterations}} \ 10 | -congestion_report_file {{settings.reports_dir}}/congestion.rpt {% if settings.verbose %} -verbose {% endif %} 11 | 12 | set_propagated_clock [all_clocks] 13 | estimate_parasitics -global_routing 14 | report_metrics "global route" 15 | 16 | {% if settings.repair_antennas %} 17 | repair_antennas 18 | {% endif %} 19 | 20 | print_banner "check_antennas" 21 | check_antennas -report_file {{settings.reports_dir}}/{{step_id}}_antenna.log 22 | 23 | {% if (settings.clocks|length) == 1 and settings.update_sdc_margin %} 24 | {{section("write_ref_sdc")}} 25 | # Write an SDC file with clock periods that result in slightly negative (failing) slack. 26 | set clks [all_clocks] 27 | set clk [lindex $clks 0] 28 | set clk_name [get_name $clk] 29 | set period [get_property $clk "period"] 30 | # Period is in sdc/liberty units. 31 | utl::info "write_ref_sdc" 7 "clock $clk_name period $period" 32 | set slack [sta::time_sta_ui [sta::worst_slack_cmd "max"]] 33 | set ref_period [expr ($period - $slack) * (1.0 - {{settings.update_sdc_margin}})] 34 | utl::info "write_ref_sdc" 8 "Clock $clk_name period [format %.3f $ref_period]" 35 | utl::info "write_ref_sdc" 9 "Clock $clk_name slack [format %.3f $slack]" 36 | 37 | set sources [$clk sources] 38 | # Redefine clock with updated period. 39 | create_clock -name $clk_name -period $ref_period $sources 40 | # Undo the set_propagated_clock so SDC at beginning of flow uses ideal clocks. 41 | unset_propagated_clock [all_clocks] 42 | write_sdc {{settings.results_dir}}/{{step_id}}_updated_clks.sdc 43 | # Reset 44 | create_clock -name $clk_name -period $period $sources 45 | set_propagated_clock [all_clocks] 46 | {% endif %} 47 | 48 | {{ write_checkpoint(step) }} 49 | -------------------------------------------------------------------------------- /src/xeda/flows/openroad/openroad_scripts/LICENSE.md: -------------------------------------------------------------------------------- 1 | The OpenROAD-flow-scripts repository (build and run scripts) has a BSD 3-Clause License with its text below. 2 | The flow relies on several tools, platforms and designs that each have their own licenses. 3 | 4 | The license below applies ***only*** to the build and run scripts, not the OpenROAD tools. 5 | See the README.md file LICENSE section for details on the location of each components' individual license. 6 | 7 | License for Build and Run scripts in the OpenROAD-flow-scripts repository only : 8 | 9 | BSD 3-Clause License 10 | 11 | Copyright (c) 2018, The Regents of the University of California 12 | All rights reserved. 13 | 14 | Redistribution and use in source and binary forms, with or without 15 | modification, are permitted provided that the following conditions are met: 16 | 17 | * Redistributions of source code must retain the above copyright notice, this 18 | list of conditions and the following disclaimer. 19 | 20 | * Redistributions in binary form must reproduce the above copyright notice, 21 | this list of conditions and the following disclaimer in the documentation 22 | and/or other materials provided with the distribution. 23 | 24 | * Neither the name of the copyright holder nor the names of its 25 | contributors may be used to endorse or promote products derived from 26 | this software without specific prior written permission. 27 | 28 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 29 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 31 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 32 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 34 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 35 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 36 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 37 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38 | -------------------------------------------------------------------------------- /src/xeda/flows/openroad/templates/global_place.tcl: -------------------------------------------------------------------------------- 1 | 2 | set_dont_use {{settings.dont_use_cells|join(" ")|embrace}} 3 | 4 | # set fastroute layer reduction 5 | {% if platform.fastroute_tcl %} 6 | source {{platform.fastroute_tcl}} 7 | {% else %} 8 | 9 | set_global_routing_layer_adjustment {{platform.min_routing_layer}}-{{platform.max_routing_layer}} 0.5 10 | set_routing_layers -signal {{platform.min_routing_layer}}-{{platform.max_routing_layer}} 11 | set_macro_extension 2 12 | {% endif %} 13 | 14 | # check the lower boundary of the PLACE_DENSITY and add PLACE_DENSITY_LB_ADDON if it exists 15 | {% if settings.place_density_lb_addon %} 16 | set place_density_lb [gpl::get_global_placement_uniform_density \ 17 | -pad_left {{platform.cell_pad_in_sites_global_placement}} \ 18 | -pad_right {{platform.cell_pad_in_sites_global_placement}}] 19 | set place_density [expr $place_density_lb + ((1.0 - $place_density_lb) * {{settings.place_density_lb_addon}} + 0.01] 20 | if {$place_density > 1.0} { 21 | utl::error FLW 24 "Place density exceeds 1.0 (current PLACE_DENSITY_LB_ADDON = {{settings.place_density_lb_addon}}). Please check if the value of PLACE_DENSITY_LB_ADDON is between 0 and 0.99." 22 | } 23 | {% else %} 24 | set place_density {{settings.place_density or platform.place_density}} 25 | {% endif %} 26 | 27 | set global_placement_args "{{ settings.global_placement_args|join(" ") }}" 28 | {% if settings.gpl_routability_driven %} 29 | append global_placement_args " -routability_driven" 30 | {% endif %} 31 | {% if settings.gpl_timing_driven %} 32 | append global_placement_args " -timing_driven" 33 | {% endif %} 34 | {% if settings.min_phi_coef is not none %} 35 | append global_placement_args " -min_phi_coef {{settings.min_phi_coef}}" 36 | {% endif %} 37 | 38 | {% if settings.max_phi_coef is not none %} 39 | append global_placement_args " -max_phi_coef {{settings.max_phi_coef}}" 40 | {% endif %} 41 | 42 | global_placement -density $place_density \ 43 | -pad_left {{platform.cell_pad_in_sites_global_placement}} \ 44 | -pad_right {{platform.cell_pad_in_sites_global_placement}} \ 45 | {*}$global_placement_args 46 | 47 | estimate_parasitics -placement 48 | report_metrics "global place" false false 49 | 50 | {{ write_checkpoint(step) }} 51 | -------------------------------------------------------------------------------- /examples/mixed_language/blink/blink_tb.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include "blink.h" 7 | 8 | int main() { 9 | cxxrtl_design::p_blink top; 10 | 11 | auto vcd_filename = "waves.vcd"; 12 | 13 | std::cout << "dumbping waveform to " << vcd_filename << std::endl; 14 | 15 | // debug_items maps the hierarchical names of signals and memories in the 16 | // design to a cxxrtl_object (a value, a wire, or a memory) 17 | cxxrtl::debug_items all_debug_items; 18 | 19 | // Load the debug items of the top down the whole design hierarchy 20 | top.debug_info(all_debug_items); 21 | 22 | // vcd_writer is the CXXRTL object that's responsible of creating a string 23 | // with the VCD file contents. 24 | cxxrtl::vcd_writer vcd; 25 | vcd.timescale(1, "ns"); 26 | 27 | // Here we tell the vcd writer to dump all the signals of the design, except 28 | // for the memories, to the VCD file. 29 | // 30 | // It's not necessary to load all debug objects to the VCD. There is, for 31 | // example, a vcd.add(, )) method which allows 32 | // creating your custom filter to decide what to add and what not. 33 | vcd.add_without_memories(all_debug_items); 34 | 35 | std::ofstream waves(vcd_filename); 36 | 37 | bool prev_led = 0; 38 | 39 | /// Is only a single-threaded sequential driver/monitor simulation supported?! 40 | 41 | for (int step = 0; step < 1000; ++step) { 42 | 43 | top.p_clk.set(false); 44 | top.step(); 45 | vcd.sample(step * 2 + 0); 46 | 47 | top.p_clk.set(true); 48 | top.step(); 49 | vcd.sample(step * 2 + 1); 50 | 51 | if (step < 2){ 52 | top.p_reset.set(true); 53 | continue; 54 | } else { 55 | top.p_reset.set(false); 56 | } 57 | 58 | bool cur_led = top.p_led.get(); 59 | uint32_t counter = top.p_counter.get(); 60 | 61 | if (cur_led != prev_led) { 62 | std::cout << "cycle " << step << " - led: " << cur_led 63 | << ", counter: " << counter << std::endl; 64 | } 65 | prev_led = cur_led; 66 | 67 | waves << vcd.buffer; 68 | vcd.buffer.clear(); 69 | } 70 | } -------------------------------------------------------------------------------- /src/xeda/flow/sim.py: -------------------------------------------------------------------------------- 1 | """simulation flow""" 2 | 3 | from __future__ import annotations 4 | 5 | import logging 6 | from abc import ABCMeta 7 | from pathlib import Path 8 | from typing import Dict, List, Optional, Union 9 | 10 | from ..cocotb import Cocotb, CocotbSettings 11 | from ..dataclass import Field, validator 12 | from ..design import Design 13 | from .flow import Flow 14 | 15 | log = logging.getLogger(__name__) 16 | 17 | __all__ = [ 18 | "SimFlow", 19 | ] 20 | 21 | 22 | class SimFlow(Flow, metaclass=ABCMeta): 23 | """superclass of all simulation flows""" 24 | 25 | cocotb_sim_name: Optional[str] = None 26 | 27 | class Settings(Flow.Settings): 28 | vcd: Union[None, str, Path] = Field( 29 | None, alias="waveform", description="Write waveform to file" 30 | ) 31 | stop_time: Union[None, str, int, float] = None 32 | cocotb: CocotbSettings = CocotbSettings() # type: ignore 33 | optimization_flags: List[str] = Field([], description="Optimization flags") 34 | 35 | @validator("vcd", pre=True) 36 | def _validate_vcd(cls, vcd): # pylint: disable=no-self-argument 37 | if vcd is not None: 38 | if isinstance(vcd, bool) and vcd is True: 39 | vcd = "dump.vcd" 40 | else: 41 | if ( 42 | isinstance(vcd, str) and vcd[1:].count(".") == 0 43 | ): # if it doesn't have an extension 44 | vcd += ".vcd" 45 | return vcd 46 | 47 | def __init__( 48 | self, 49 | settings: Union[Settings, Dict], 50 | design: Union[Design, Dict], 51 | run_path: Optional[Path] = None, 52 | **kwargs, 53 | ): 54 | super().__init__(settings, design, run_path, **kwargs) 55 | assert isinstance( 56 | self.settings, self.Settings 57 | ), "self.settings is not an instance of self.Settings class" 58 | self.cocotb: Optional[Cocotb] = ( 59 | Cocotb( 60 | **self.settings.cocotb.dict(), 61 | sim_name=self.cocotb_sim_name, 62 | dockerized=self.settings.dockerized, 63 | ) 64 | if self.cocotb_sim_name and self.design.tb.cocotb 65 | else None 66 | ) 67 | -------------------------------------------------------------------------------- /src/xeda/platforms/platform.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | from pathlib import Path 4 | from typing import Any, Dict, Optional, Type, TypeVar, Union 5 | 6 | from importlib_resources import as_file, files 7 | 8 | from ..dataclass import XedaBaseModel 9 | from ..utils import toml_load 10 | 11 | log = logging.getLogger(__name__) 12 | 13 | 14 | PlatformType = TypeVar("PlatformType", bound="Platform") 15 | 16 | 17 | class Platform(XedaBaseModel): 18 | root_dir: Path 19 | name: Optional[str] = None 20 | version: Optional[str] = None 21 | description: Optional[str] = None 22 | 23 | @classmethod 24 | def create(cls: Type[PlatformType], **kwargs) -> PlatformType: 25 | log.debug("create: kwargs=%s", str(kwargs)) 26 | return cls(**kwargs) 27 | 28 | @classmethod 29 | def from_toml( 30 | cls: Type[PlatformType], platform_toml: Union[str, os.PathLike], overrides={} 31 | ) -> PlatformType: 32 | path = Path(platform_toml) 33 | kv = {**toml_load(path), **overrides} 34 | return cls.create(root_dir=path.parent, **kv).with_absolute_paths() 35 | 36 | @classmethod 37 | def from_resource(cls: Type[PlatformType], name: str, overrides={}) -> PlatformType: 38 | res = files(__package__).joinpath(name, "config.toml") 39 | with as_file(res) as path: 40 | d = cls.from_toml(path, overrides) 41 | if not d.name: 42 | d.name = name 43 | return d 44 | 45 | def with_absolute_paths(self: PlatformType) -> PlatformType: 46 | rd = self.root_dir.absolute() 47 | 48 | def to_abs(v): 49 | if v and isinstance(v, Path) and not os.path.isabs(v): 50 | return rd / v 51 | return v 52 | 53 | def convert_rec(kv: Dict[str, Any], exclude_keys=[]): 54 | for k, v in kv.items(): 55 | if k in exclude_keys: 56 | continue 57 | if isinstance(v, dict): 58 | v = convert_rec(v) 59 | elif isinstance(v, (list, tuple)): 60 | v = [to_abs(ve) for ve in v] 61 | else: 62 | v = to_abs(v) 63 | kv[k] = v 64 | return kv 65 | 66 | return self.__class__(**convert_rec(self.dict(), exclude_keys=["root_dir"])) 67 | -------------------------------------------------------------------------------- /src/xeda/platforms/sky130hd/pdn.tcl: -------------------------------------------------------------------------------- 1 | #################################### 2 | # global connections 3 | #################################### 4 | add_global_connection -net {VDD} -inst_pattern {.*} -pin_pattern {^VDD$} -power 5 | add_global_connection -net {VDD} -inst_pattern {.*} -pin_pattern {^VDDPE$} 6 | add_global_connection -net {VDD} -inst_pattern {.*} -pin_pattern {^VDDCE$} 7 | add_global_connection -net {VDD} -inst_pattern {.*} -pin_pattern {VPWR} 8 | add_global_connection -net {VDD} -inst_pattern {.*} -pin_pattern {VPB} 9 | add_global_connection -net {VSS} -inst_pattern {.*} -pin_pattern {^VSS$} -ground 10 | add_global_connection -net {VSS} -inst_pattern {.*} -pin_pattern {^VSSE$} 11 | add_global_connection -net {VSS} -inst_pattern {.*} -pin_pattern {VGND} 12 | add_global_connection -net {VSS} -inst_pattern {.*} -pin_pattern {VNB} 13 | global_connect 14 | #################################### 15 | # voltage domains 16 | #################################### 17 | set_voltage_domain -name {CORE} -power {VDD} -ground {VSS} 18 | #################################### 19 | # standard cell grid 20 | #################################### 21 | define_pdn_grid -name {grid} -voltage_domains {CORE} 22 | add_pdn_stripe -grid {grid} -layer {met1} -width {0.48} -pitch {5.44} -offset {0} -followpins 23 | add_pdn_stripe -grid {grid} -layer {met4} -width {1.600} -pitch {27.140} -offset {13.570} 24 | add_pdn_stripe -grid {grid} -layer {met5} -width {1.600} -pitch {27.200} -offset {13.600} 25 | add_pdn_connect -grid {grid} -layers {met1 met4} 26 | add_pdn_connect -grid {grid} -layers {met4 met5} 27 | #################################### 28 | # macro grids 29 | #################################### 30 | #################################### 31 | # grid for: CORE_macro_grid_1 32 | #################################### 33 | define_pdn_grid -name {CORE_macro_grid_1} -voltage_domains {CORE} -macro -orient {R0 R180 MX MY} -halo {2.0 2.0 2.0 2.0} -default -grid_over_boundary 34 | add_pdn_connect -grid {CORE_macro_grid_1} -layers {met4 met5} 35 | #################################### 36 | # grid for: CORE_macro_grid_2 37 | #################################### 38 | define_pdn_grid -name {CORE_macro_grid_2} -voltage_domains {CORE} -macro -orient {R90 R270 MXR90 MYR90} -halo {2.0 2.0 2.0 2.0} -default -grid_over_boundary 39 | add_pdn_connect -grid {CORE_macro_grid_2} -layers {met4 met5} 40 | -------------------------------------------------------------------------------- /src/xeda/platforms/sky130hs/pdn.tcl: -------------------------------------------------------------------------------- 1 | #################################### 2 | # global connections 3 | #################################### 4 | add_global_connection -net {VDD} -inst_pattern {.*} -pin_pattern {^VDD$} -power 5 | add_global_connection -net {VDD} -inst_pattern {.*} -pin_pattern {^VDDPE$} 6 | add_global_connection -net {VDD} -inst_pattern {.*} -pin_pattern {^VDDCE$} 7 | add_global_connection -net {VDD} -inst_pattern {.*} -pin_pattern {VPWR} 8 | add_global_connection -net {VDD} -inst_pattern {.*} -pin_pattern {VPB} 9 | add_global_connection -net {VSS} -inst_pattern {.*} -pin_pattern {^VSS$} -ground 10 | add_global_connection -net {VSS} -inst_pattern {.*} -pin_pattern {^VSSE$} 11 | add_global_connection -net {VSS} -inst_pattern {.*} -pin_pattern {VGND} 12 | add_global_connection -net {VSS} -inst_pattern {.*} -pin_pattern {VNB} 13 | global_connect 14 | #################################### 15 | # voltage domains 16 | #################################### 17 | set_voltage_domain -name {CORE} -power {VDD} -ground {VSS} 18 | #################################### 19 | # standard cell grid 20 | #################################### 21 | define_pdn_grid -name {grid} -voltage_domains {CORE} 22 | add_pdn_stripe -grid {grid} -layer {met1} -width {0.48} -pitch {6.66} -offset {0} -followpins 23 | add_pdn_stripe -grid {grid} -layer {met4} -width {1.600} -pitch {27.140} -offset {13.570} 24 | add_pdn_stripe -grid {grid} -layer {met5} -width {1.600} -pitch {27.200} -offset {13.600} 25 | add_pdn_connect -grid {grid} -layers {met1 met4} 26 | add_pdn_connect -grid {grid} -layers {met4 met5} 27 | #################################### 28 | # macro grids 29 | #################################### 30 | #################################### 31 | # grid for: CORE_macro_grid_1 32 | #################################### 33 | define_pdn_grid -name {CORE_macro_grid_1} -voltage_domains {CORE} -macro -orient {R0 R180 MX MY} -halo {2.0 2.0 2.0 2.0} -default -grid_over_boundary 34 | add_pdn_connect -grid {CORE_macro_grid_1} -layers {met4 met5} 35 | #################################### 36 | # grid for: CORE_macro_grid_2 37 | #################################### 38 | define_pdn_grid -name {CORE_macro_grid_2} -voltage_domains {CORE} -macro -orient {R90 R270 MXR90 MYR90} -halo {2.0 2.0 2.0 2.0} -default -grid_over_boundary 39 | add_pdn_connect -grid {CORE_macro_grid_2} -layers {met4 met5} 40 | -------------------------------------------------------------------------------- /examples/vhdl/pipeline/pipelined_adder.vhdl: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | entity pipelined_adder is 6 | generic( 7 | W : positive := 32 8 | ); 9 | port( 10 | clock : in std_logic; 11 | reset : in std_logic; 12 | in_a : in std_logic_vector(W - 1 downto 0); 13 | in_b : in std_logic_vector(W - 1 downto 0); 14 | in_valid : in std_logic; 15 | in_ready : out std_logic; 16 | out_sum : out std_logic_vector(W downto 0); 17 | out_valid : out std_logic; 18 | out_ready : in std_logic 19 | ); 20 | end; 21 | 22 | architecture behavioral of pipelined_adder is 23 | constant DEPTH : positive := 2; 24 | 25 | -- registers 26 | signal l0_a, l0_b : std_logic_vector(W - 1 downto 0); 27 | signal l1_s : std_logic_vector(W downto 0); 28 | signal valid_pipe : std_logic_vector(0 to DEPTH - 1); 29 | 30 | -- wires 31 | signal valids : std_logic_vector(0 to DEPTH); 32 | signal readies : std_logic_vector(0 to DEPTH); 33 | begin 34 | 35 | process(all) 36 | begin 37 | readies(DEPTH) <= out_ready; 38 | in_ready <= readies(0); 39 | valids(0) <= in_valid; 40 | out_valid <= valids(DEPTH); 41 | 42 | for i in 0 to DEPTH - 1 loop 43 | readies(i) <= not valid_pipe(i) or readies(i + 1); 44 | valids(i + 1) <= valid_pipe(i); 45 | end loop; 46 | 47 | out_sum <= l1_s; 48 | end process; 49 | 50 | process(clock) 51 | begin 52 | if rising_edge(clock) then 53 | if reset = '1' then 54 | valid_pipe <= (others => '0'); 55 | else 56 | for i in 0 to DEPTH - 1 loop 57 | if readies(i) then 58 | valid_pipe(i) <= valids(i); 59 | end if; 60 | end loop; 61 | end if; 62 | end if; 63 | end process; 64 | 65 | process(clock) 66 | begin 67 | if rising_edge(clock) then 68 | -- Update logic for each stage: 69 | if readies(0) then 70 | l0_a <= in_a; 71 | l0_b <= in_b; 72 | end if; 73 | if readies(1) then 74 | l1_s <= std_logic_vector(unsigned('0' & l0_a) + unsigned(l0_b)); 75 | end if; 76 | end if; 77 | end process; 78 | end; 79 | -------------------------------------------------------------------------------- /examples/vhdl/sqrt/tb_sqrt.py: -------------------------------------------------------------------------------- 1 | import os 2 | import random 3 | 4 | import cocotb 5 | from cocotb.handle import HierarchyObject 6 | from cocolight import DutClock, DutReset, ValidReadyTb 7 | 8 | NUM_TV = int(os.environ.get("NUM_TV", 2000)) 9 | DEBUG = bool(os.environ.get("DEBUG", False)) 10 | 11 | 12 | class SqrtTb(ValidReadyTb): 13 | def __init__(self, dut: HierarchyObject, debug: bool = DEBUG): 14 | super().__init__(dut, DutClock("clk"), DutReset("rst"), debug) 15 | self.in_bus = self.driver("in", data_suffix="data") 16 | self.out_bus = self.monitor("out", data_suffix=["data_root", "data_rem"]) 17 | 18 | async def verify(self, rad: int): 19 | stimulus = cocotb.start_soon(self.in_bus.enqueue(rad)) 20 | out = await self.out_bus.dequeue() 21 | await stimulus 22 | 23 | root = int(out.data_root) 24 | remainder = int(out.data_rem) 25 | 26 | assert rad == root**2 + remainder, f"{rad} != {root} ** 2 + {remainder}" 27 | assert rad < (root + 1) ** 2, "returned root was smaller than expected" 28 | 29 | self.log.debug("radicand=%d got root=%d remainder=%d", rad, root, remainder) 30 | 31 | 32 | @cocotb.test 33 | async def test_sqrt_corners(dut: HierarchyObject, debug=False): 34 | tb = SqrtTb(dut, debug=debug) 35 | await tb.reset() 36 | tb.log.info("DUT: %s", str(dut)) 37 | # get bound parameters/generics from the simulator 38 | G_IN_WIDTH = tb.get_int_value("G_IN_WIDTH") 39 | tb.log.info(f"G_IN_WIDTH:{G_IN_WIDTH}") 40 | # await tb.clock_edge 41 | # TODO make sure ranges are within G_IN_WIDTH bits 42 | assert G_IN_WIDTH and G_IN_WIDTH >= 6 43 | testcases = list(range(30)) + list(range(2**G_IN_WIDTH - 70, 2**G_IN_WIDTH)) 44 | testcases += list(range(2**G_IN_WIDTH // 2 - 30, 2**G_IN_WIDTH // 2 + 30)) 45 | for rad in testcases: 46 | await tb.verify(rad) 47 | 48 | @cocotb.test 49 | async def test_sqrt(dut: HierarchyObject, num_tests: int = NUM_TV, debug=DEBUG): 50 | tb = SqrtTb(dut, debug=debug) 51 | await tb.reset() 52 | # get bound parameters/generics from the simulator 53 | G_IN_WIDTH = tb.get_value("G_IN_WIDTH", int) 54 | tb.log.info("G_IN_WIDTH:%d num_tests:%d", G_IN_WIDTH, num_tests) 55 | # await tb.clock_edge 56 | testcases = [random.getrandbits(G_IN_WIDTH) for _ in range(num_tests)] 57 | testcases = list(set(testcases)) 58 | for rad in testcases: 59 | await tb.verify(rad) 60 | -------------------------------------------------------------------------------- /src/xeda/board.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | from typing import Any, Dict, Optional, Union 4 | 5 | from importlib_resources import as_file, files 6 | 7 | from .dataclass import root_validator 8 | from .flow import FPGA, FpgaSynthFlow 9 | from .utils import toml_load 10 | 11 | __all__ = [ 12 | "get_board_file_path", 13 | "get_board_data", 14 | "WithFpgaBoardSettings", 15 | ] 16 | 17 | log = logging.getLogger(__name__) 18 | 19 | 20 | def get_board_file_path(file: str): 21 | # FIXME refactor and verify behavior 22 | # return pkg_resources.resource_filename("xeda.data.boards", file) 23 | res = files("xeda.data.boards").joinpath(file) 24 | return as_file(res) 25 | 26 | 27 | def get_board_data( 28 | board: Optional[str], custom_toml_file: Union[None, str, os.PathLike] = None 29 | ) -> Optional[Dict[str, Any]]: 30 | if not board: 31 | return None 32 | boards_data = {} 33 | if custom_toml_file: 34 | log.debug("Retrieving board data for %s from %s", board, custom_toml_file) 35 | boards_data = toml_load(custom_toml_file) 36 | else: 37 | res = files("xeda.data").joinpath("boards.toml") 38 | with as_file(res) as p: 39 | boards_data = toml_load(p) 40 | if boards_data and board in boards_data: 41 | log.info("Retrieved board data for %s", board) 42 | # else: 43 | # log.error( 44 | # "Unable to get resource %s.%s. Please check xeda installation.", 45 | # "xeda.data", 46 | # "boards.toml", 47 | # ) 48 | return boards_data.get(board) 49 | 50 | 51 | class WithFpgaBoardSettings(FpgaSynthFlow.Settings): 52 | board: Optional[str] = None 53 | custom_boards_file: Optional[str] = None 54 | 55 | @root_validator(pre=True) 56 | def _fpga_validate(cls, values: Dict[str, Any]) -> Dict[str, Any]: 57 | board_name = values.get("board") 58 | log.debug("_fpga_validate! board_name=%s", board_name) 59 | fpga = values.get("fpga") 60 | if not fpga and board_name: 61 | board_data = get_board_data(board_name) 62 | if board_data: 63 | board_fpga = board_data.get("fpga") 64 | log.info("FPGA info for board %s: %s", board_name, str(board_fpga)) 65 | if board_fpga: 66 | if isinstance(board_fpga, str): 67 | board_fpga = {"part": board_fpga} 68 | values["fpga"] = FPGA(**board_fpga) 69 | return values 70 | -------------------------------------------------------------------------------- /src/xeda/platforms/nangate45/grid_strategy-M1-M4-M7.tcl: -------------------------------------------------------------------------------- 1 | #################################### 2 | # global connections 3 | #################################### 4 | add_global_connection -net {VDD} -inst_pattern {.*} -pin_pattern {^VDD$} -power 5 | add_global_connection -net {VDD} -inst_pattern {.*} -pin_pattern {^VDDPE$} 6 | add_global_connection -net {VDD} -inst_pattern {.*} -pin_pattern {^VDDCE$} 7 | add_global_connection -net {VSS} -inst_pattern {.*} -pin_pattern {^VSS$} -ground 8 | add_global_connection -net {VSS} -inst_pattern {.*} -pin_pattern {^VSSE$} 9 | global_connect 10 | #################################### 11 | # voltage domains 12 | #################################### 13 | set_voltage_domain -name {CORE} -power {VDD} -ground {VSS} 14 | #################################### 15 | # standard cell grid 16 | #################################### 17 | define_pdn_grid -name {grid} -voltage_domains {CORE} 18 | add_pdn_stripe -grid {grid} -layer {metal1} -width {0.17} -pitch {2.4} -offset {0} -followpins 19 | add_pdn_stripe -grid {grid} -layer {metal4} -width {0.48} -pitch {56.0} -offset {2} 20 | add_pdn_stripe -grid {grid} -layer {metal7} -width {1.40} -pitch {40.0} -offset {2} 21 | add_pdn_connect -grid {grid} -layers {metal1 metal4} 22 | add_pdn_connect -grid {grid} -layers {metal4 metal7} 23 | #################################### 24 | # macro grids 25 | #################################### 26 | #################################### 27 | # grid for: CORE_macro_grid_1 28 | #################################### 29 | define_pdn_grid -name {CORE_macro_grid_1} -voltage_domains {CORE} -macro -orient {R0 R180 MX MY} -halo {2.0 2.0 2.0 2.0} -cells {.*} 30 | add_pdn_stripe -grid {CORE_macro_grid_1} -layer {metal5} -width {0.93} -pitch {10.0} -offset {2} 31 | add_pdn_stripe -grid {CORE_macro_grid_1} -layer {metal6} -width {0.93} -pitch {10.0} -offset {2} 32 | add_pdn_connect -grid {CORE_macro_grid_1} -layers {metal4 metal5} 33 | add_pdn_connect -grid {CORE_macro_grid_1} -layers {metal5 metal6} 34 | add_pdn_connect -grid {CORE_macro_grid_1} -layers {metal6 metal7} 35 | #################################### 36 | # grid for: CORE_macro_grid_2 37 | #################################### 38 | define_pdn_grid -name {CORE_macro_grid_2} -voltage_domains {CORE} -macro -orient {R90 R270 MXR90 MYR90} -halo {2.0 2.0 2.0 2.0} -cells {.*} 39 | add_pdn_stripe -grid {CORE_macro_grid_2} -layer {metal6} -width {0.93} -pitch {40.0} -offset {2} 40 | add_pdn_connect -grid {CORE_macro_grid_2} -layers {metal4 metal6} 41 | add_pdn_connect -grid {CORE_macro_grid_2} -layers {metal6 metal7} 42 | -------------------------------------------------------------------------------- /src/xeda/platforms/nangate45/fakeram.cfg: -------------------------------------------------------------------------------- 1 | # config file to drive BSG Black-box SRAM Generator 2 | # https://github.com/bespoke-silicon-group/bsg_fakeram.git 3 | # using cherry's fork to fix bugs 4 | # https://github.com/jjcherry56/bsg_fakeram.git nangate45 branch 5 | { 6 | # The process node. This is used to tell cacti what technology to use when 7 | # estimating power, performance and area numbers. 8 | "tech_nm": 45, 9 | 10 | # The operating voltage. 11 | "voltage": 1.1, 12 | 13 | # String to add in front of every metal layer number for the layer name. 14 | "metalPrefix": "metal", 15 | 16 | # The pin width for signal pins. 17 | "pinWidth_nm": 70, 18 | 19 | # The minimum pin pitch for signal pins (all pins will have a pitch that is a 20 | # multuple of this pitch. The first pin will be a multiple of this pitch from 21 | # the bottom edge of the macro too. 22 | "pinPitch_nm": 210, 23 | 24 | # Optional: snap the width and height of the sram to a multiple value. 25 | "snapWidth_nm": 190, 26 | "snapHeight_nm": 1400, 27 | 28 | # swap width and height to match existing aspect ratio 29 | "swapWidthHeight": true, 30 | 31 | # Flips the pin orientations. Non-fliped assumes metal1 is vertical therefore 32 | # supply pins on metal4 will be horizontal and signal pins will also be on 33 | # metal4. If set to true, supply pins on metal4 will be vertical and signal 34 | # pins will be on metal3. 35 | "flipPins": true, 36 | 37 | "libertyTimeUnit": "ns", 38 | "libertyCapUnit": "ff", 39 | "libertyPowerUnit": "nw", 40 | 41 | # List of SRAM configurations (name, width, depth, and banks) 42 | "srams": [ 43 | {"name": "fakeram45_1024x32", "width": 32, "depth": 1024, "banks": 1}, 44 | {"name": "fakeram45_2048x39", "width": 39, "depth": 2048, "banks": 1}, 45 | {"name": "fakeram45_256x34", "width": 34, "depth": 256, "banks": 1}, 46 | {"name": "fakeram45_256x95", "width": 95, "depth": 256, "banks": 1}, 47 | {"name": "fakeram45_256x96", "width": 96, "depth": 256, "banks": 1}, 48 | {"name": "fakeram45_32x64", "width": 64, "depth": 32, "banks": 1}, 49 | {"name": "fakeram45_512x64", "width": 64, "depth": 512, "banks": 1}, 50 | {"name": "fakeram45_64x15", "width": 15, "depth": 64, "banks": 1}, 51 | {"name": "fakeram45_64x21", "width": 21, "depth": 64, "banks": 1}, 52 | {"name": "fakeram45_64x32", "width": 32, "depth": 64, "banks": 1}, 53 | {"name": "fakeram45_64x7", "width": 7, "depth": 64, "banks": 1}, 54 | {"name": "fakeram45_64x96", "width": 96, "depth": 64, "banks": 1} 55 | ] 56 | } 57 | -------------------------------------------------------------------------------- /docs/quickstart.rst: -------------------------------------------------------------------------------- 1 | Quickstart 2 | ========== 3 | 4 | .. OUTDATED FIXME 5 | 6 | To get started with xeda, first create a ``xedaproject.toml`` file for your design. 7 | This file contains metadata, list of source files, and flow settings regarding 8 | your design. Below is an example ``xedaproject.toml`` which can be adapted to any design. 9 | 10 | Checkout the xedaproject_ section for the detailed structure of the file. 11 | 12 | .. TODO add xedaproject.toml breakdown 13 | 14 | 15 | .. code-block:: toml 16 | 17 | [project] 18 | name = "Project1" 19 | description = "My Project with 2 designs" 20 | 21 | [[design]] 22 | name = 'Design1' 23 | [design.rtl] 24 | sources = [ 25 | 'src_rtl/module1.vhd', 26 | 'src_rtl/top.v' 27 | ] 28 | top = 'Top' 29 | clock = 'clk' 30 | [design.tb] 31 | sources = [ 32 | 'top_tb.vhd', 33 | ] 34 | top = 'TopTB' 35 | 36 | 37 | 38 | After the ``xedaproject.toml`` file has been created for your design, you can now use xeda to generate simulation, synthesis and implementation results for your design using the supported tool of your choice. 39 | 40 | For example, if we want to simulate the above design with GHDL, we would run 41 | 42 | .. code-block:: bash 43 | 44 | $ xeda ghdl_sim 45 | 46 | If we are satisfied with the results of the simulation, we can have xeda synthesis and implement our design. For example, with Xilinx Vivado: 47 | 48 | .. code-block:: bash 49 | 50 | $ xeda vivado_synth 51 | 52 | If multiple ``[[design]]`` entries are present, the active design needs be specified using ``--design`` flag 53 | 54 | That's it! That's all xeda requires to simulate, synthesis, and implement an HDL design. 55 | 56 | As always, you can run ``xeda --help`` for the full list of arguments. 57 | 58 | 59 | xedaproject 60 | ----------- 61 | Settings: 62 | 63 | - ``project`` 64 | - ``design`` can be a list of multiple TOML tables, must use ``[[design]]`` instead of ``[design]`` 65 | - ``name``: a string that designates a name for this design. Recommended to avoid any whitespace. 66 | - ``rtl`` 67 | - ``sources``: a list of HDL files used for synthesis and simulation 68 | - ``top``: syntehsis top entity/module 69 | - ``tb`` 70 | - ``sources``: a list of testbench files used for simulation only 71 | - ``top``: simulation top entity/module/function 72 | - ``flows`` 73 | 74 | The sub-tables may include optional entries referenced only by a particular plugin. 75 | E.g., ``design.lwc`` is used by ``lwc`` plugins. 76 | 77 | 78 | bash-completion 79 | --------------- 80 | 81 | -------------------------------------------------------------------------------- /src/xeda/platforms/asap7/openlane/asap7sc7p5t/config.tcl: -------------------------------------------------------------------------------- 1 | set current_folder [file dirname [file normalize [info script]]] 2 | # Technology lib 3 | 4 | set libs_ref "$::env(PDK_ROOT)/$::env(PDK)/libs.ref/$::env(STD_CELL_LIBRARY)" 5 | 6 | set libs_tech "$::env(PDK_ROOT)/$::env(PDK)/libs.tech" 7 | 8 | set ::env(LIB_FASTEST) "" 9 | set ::env(LIB_TYPICAL) "" 10 | set ::env(LIB_SLOWEST) "" 11 | 12 | set lib_path "$libs_ref/lib" 13 | foreach lib {"AO" "INVBUF" "OA" "SEQ" "SIMPLE"} { 14 | append ::env(LIB_FASTEST) "$lib_path/asap7sc7p5t_${lib}_RVT_FF_nldm_201020.lib " 15 | append ::env(LIB_TYPICAL) "$lib_path/asap7sc7p5t_${lib}_RVT_TT_nldm_201020.lib " 16 | append ::env(LIB_SLOWEST) "$lib_path/asap7sc7p5t_${lib}_RVT_SS_nldm_201020.lib " 17 | } 18 | 19 | set ::env(LIB_SYNTH) $::env(LIB_TYPICAL) 20 | set ::env(LIB_RESIZER_OPT) $::env(LIB_SYNTH) 21 | 22 | set ::env(DFF_LIB_SYNTH) "$lib_path/asap7sc7p5t_SEQ_RVT_TT_nldm_201020.lib" 23 | 24 | set ::env(LIB_CTS) $::env(LIB_TYPICAL) 25 | 26 | # Placement site for core cells 27 | # This can be found in the technology lef 28 | set ::env(PLACE_SITE) "asap7sc7p5t" 29 | set ::env(PLACE_SITE_WIDTH) 0.054 30 | set ::env(PLACE_SITE_HEIGHT) 0.270 31 | 32 | # welltap and endcap cells 33 | set ::env(FP_WELLTAP_CELL) "TAPCELL_ASAP7_75t_R" 34 | set ::env(FP_ENDCAP_CELL) "TAPCELL_ASAP7_75t_R" 35 | 36 | # defaults (can be overridden by designs): 37 | set ::env(SYNTH_DRIVING_CELL) "BUFx2_ASAP7_75t_R" 38 | set ::env(SYNTH_DRIVING_CELL_PIN) "Y" 39 | set ::env(SYNTH_CAP_LOAD) "4.61057" ; # femtofarad INVx8_ASAP7_75t_R pin A cap 40 | set ::env(SYNTH_MIN_BUF_PORT) "BUFx2_ASAP7_75t_R A Y" 41 | set ::env(SYNTH_TIEHI_PORT) "TIEHIx1_ASAP7_75t_R H" 42 | set ::env(SYNTH_TIELO_PORT) "TIELOx1_ASAP7_75t_R L" 43 | 44 | # cts defaults 45 | set ::env(CTS_ROOT_BUFFER) BUFx4_ASAP7_75t_R 46 | set ::env(CELL_CLK_PORT) CLK 47 | 48 | # Placement defaults 49 | set ::env(PL_LIB) $::env(LIB_TYPICAL) 50 | 51 | # Fillcell insertion 52 | set ::env(FILL_CELL) "FILLERxp5_ASAP7_75t_R" 53 | set ::env(DECAP_CELL) "DECAPx1_ASAP7_75t_R" 54 | set ::env(RE_BUFFER_CELL) "" 55 | 56 | set ::env(CELL_PAD) 2 57 | set ::env(CELL_PAD_EXCLUDE) "" 58 | 59 | # Clk Buffers info CTS data 60 | set ::env(ROOT_CLK_BUFFER) BUFx4_ASAP7_75t_R 61 | set ::env(CLK_BUFFER) BUFx4_ASAP7_75t_R 62 | set ::env(CLK_BUFFER_INPUT) A 63 | set ::env(CLK_BUFFER_OUTPUT) Y 64 | set ::env(CTS_CLK_BUFFER_LIST) "BUFx4_ASAP7_75t_R" 65 | set ::env(FP_PDN_RAIL_WIDTH) 0.48 66 | # Determined from BUFx24_ASAP7_75t_R 67 | set ::env(CTS_MAX_CAP) 1474.56 68 | set ::env(DEFAULT_MAX_TRAN) 320 69 | 70 | set ::env(PDN_CFG) "$::env(PDK_ROOT)/$::env(PDK)/libs.tech/openlane/$::env(STD_CELL_LIBRARY)/grid_strategy-M1-M2-M5-M6.cfg" 71 | -------------------------------------------------------------------------------- /src/xeda/flows/openroad/templates/resynth.tcl: -------------------------------------------------------------------------------- 1 | {% if settings.resynth_for_timing %} 2 | repair_design 3 | repair_timing 4 | # pre restructure area/timing report (ideal clocks) 5 | puts "Post synth-opt area" 6 | report_design_area 7 | report_worst_slack -min -digits 3 8 | puts "Post synth-opt wns" 9 | report_worst_slack -max -digits 3 10 | puts "Post synth-opt tns" 11 | report_tns -digits 3 12 | 13 | if {![info exists save_checkpoint] || $save_checkpoint} { 14 | write_verilog {{settings.results_dir}}/{{step_id}}_pre_abc_timing.v 15 | } 16 | 17 | restructure -target timing -liberty_file {{merged_lib_file}} \ 18 | -work_dir {{settings.results_dir}} 19 | 20 | if {![info exists save_checkpoint] || $save_checkpoint} { 21 | write_verilog {{settings.results_dir}}/{{step_id}}_post_abc_timing.v 22 | } 23 | 24 | # post restructure area/timing report (ideal clocks) 25 | remove_buffers 26 | repair_design 27 | repair_timing 28 | 29 | puts "Post restructure-opt wns" 30 | report_worst_slack -max -digits 3 31 | puts "Post restructure-opt tns" 32 | report_tns -digits 3 33 | 34 | # remove buffers inserted by optimization 35 | remove_buffers 36 | {% endif %} 37 | 38 | {% if settings.resynth_for_area %} 39 | set num_instances [llength [get_cells -hier *]] 40 | puts "number instances before restructure is $num_instances" 41 | puts "Design Area before restructure" 42 | report_design_area 43 | report_design_area_metrics 44 | 45 | if {![info exists save_checkpoint] || $save_checkpoint} { 46 | write_verilog {{settings.results_dir}}/{{step_id}}_pre_abc.v 47 | } 48 | 49 | set tielo_cell_name {{platform.tielo_cell}} 50 | set tielo_lib_name [get_name [get_property [lindex [get_lib_cell $tielo_cell_name] 0] library]] 51 | set tielo_port $tielo_lib_name/$tielo_cell_name/{{platform.tielo_port}} 52 | 53 | set tiehi_cell_name {{platform.tiehi_cell}} 54 | set tiehi_lib_name [get_name [get_property [lindex [get_lib_cell $tiehi_cell_name] 0] library]] 55 | set tiehi_port $tiehi_lib_name/$tiehi_cell_name/{{platform.tiehi_port}} 56 | 57 | restructure -liberty_file {{merged_lib_file}} -target "area" \ 58 | -tiehi_port $tiehi_port \ 59 | -tielo_port $tielo_port \ 60 | -work_dir {{settings.results_dir}} 61 | 62 | # remove buffers inserted by abc 63 | remove_buffers 64 | 65 | if {![info exists save_checkpoint] || $save_checkpoint} { 66 | write_verilog {{settings.results_dir}}/{{step_id}}_post_abc.v 67 | } 68 | set num_instances [llength [get_cells -hier *]] 69 | puts "number instances after restructure is $num_instances" 70 | puts "Design Area after restructure" 71 | report_design_area 72 | report_design_area_metrics 73 | {% endif %} 74 | 75 | report_metrics "after resynth" false false 76 | 77 | {{ write_checkpoint(step) }} 78 | -------------------------------------------------------------------------------- /src/xeda/flows/vivado/vivado_postsynthsim.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from ...design import DesignSource, RtlSettings 4 | from ...flow import FlowFatalError 5 | from ...utils import SDF 6 | from .vivado_sim import VivadoSim 7 | from .vivado_synth import VivadoSynth 8 | 9 | log = logging.getLogger(__name__) 10 | 11 | 12 | class VivadoPostsynthSim(VivadoSim): 13 | """ 14 | Synthesizes & implements the design, then runs post-synthesis/post-implementation simulation on the generated netlist. 15 | The netlist can be optionally annotated with generated timing information (SDF). 16 | Depends on VivadoSynth 17 | """ 18 | 19 | class Settings(VivadoSim.Settings): 20 | synth: VivadoSynth.Settings 21 | timing_sim: bool = False 22 | 23 | def init(self) -> None: 24 | ss = self.settings 25 | assert isinstance(ss, self.Settings) 26 | 27 | ss.synth.write_netlist = True 28 | self.add_dependency(VivadoSynth, ss.synth) 29 | 30 | def run(self) -> None: 31 | synth_flow = self.completed_dependencies[0] 32 | assert isinstance(synth_flow, VivadoSynth) 33 | ss = self.settings 34 | assert isinstance(ss, self.Settings) 35 | 36 | artifacts_path = synth_flow.run_path / synth_flow.settings.outputs_dir / "route_design" 37 | synth_netlist_path = artifacts_path / "timesim.v" 38 | if not synth_netlist_path.exists(): 39 | raise FlowFatalError(f"Netlist {synth_netlist_path} does not exist!") 40 | postsynth_sources = [DesignSource(synth_netlist_path)] 41 | log.info("Setting post-synthesis sources to: %s", postsynth_sources) 42 | # also removing top-level generics and everything else 43 | self.design.rtl = RtlSettings( 44 | top=self.design.rtl.top, sources=postsynth_sources, attributes={} 45 | ) 46 | assert self.design.tb and self.design.tb.top 47 | self.design.tb.top = (self.design.tb.top[0], "glbl") 48 | 49 | if "simprims_ver" not in ss.lib_paths: 50 | ss.lib_paths.append(("simprims_ver", None)) 51 | 52 | if ss.timing_sim: 53 | if not ss.sdf.delay_items(): 54 | ss.sdf = SDF(max=str(artifacts_path / "timesim.max.sdf")) 55 | if not ss.sdf.root: 56 | ss.sdf.root = self.design.tb.uut 57 | log.info("Timing simulation using SDF %s", ss.sdf) 58 | 59 | ss.elab_flags.extend( 60 | [ 61 | "-maxdelay", 62 | "-transport_int_delays", 63 | "-pulse_r 0", 64 | "-pulse_int_r 0", 65 | "-pulse_e 0", 66 | "-pulse_int_e 0", 67 | ] 68 | ) 69 | # run VivadoSim 70 | super().run() 71 | -------------------------------------------------------------------------------- /tests/test_vivado.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | import tempfile 4 | from pathlib import Path 5 | 6 | from xeda import Design 7 | from xeda.flow import FPGA 8 | from xeda.flow_runner import DefaultRunner 9 | from xeda.flows import VivadoSynth 10 | from xeda.flows.vivado.vivado_synth import parse_hier_util, vivado_synth_generics 11 | 12 | TESTS_DIR = Path(__file__).parent.absolute() 13 | RESOURCES_DIR = TESTS_DIR / "resources" 14 | EXAMPLES_DIR = TESTS_DIR.parent / "examples" 15 | 16 | 17 | def test_vivado_synth_template() -> None: 18 | design = Design.from_toml(RESOURCES_DIR / "design0/design0.toml") 19 | settings = VivadoSynth.Settings(fpga=FPGA(part="abcd"), clock_period=5.5) # type: ignore 20 | run_dir = Path.cwd() / "vivado_synth_run" 21 | run_dir.mkdir(exist_ok=True) 22 | flow = VivadoSynth(settings, design, run_dir) # type: ignore 23 | tcl_file = flow.copy_from_template( 24 | "vivado_synth.tcl", 25 | xdc_files=[], 26 | tcl_files=[], 27 | generics=vivado_synth_generics(design.rtl.parameters), 28 | ) 29 | with open(run_dir / tcl_file) as f: 30 | vivado_tcl = f.read() 31 | expected_lines = [ 32 | """set_property generic {G_IN_WIDTH=32 G_ITERATIVE=1'b1 G_STR=\\"abcd\\" G_BITVECTOR=7'b0101001} [current_fileset]""", 33 | ] 34 | for line in expected_lines: 35 | assert line in vivado_tcl 36 | 37 | 38 | def test_vivado_synth_py() -> None: 39 | # Append to PATH so if the actual tool exists, would take precedences. 40 | os.environ["PATH"] = ( 41 | os.path.join(TESTS_DIR, "fake_tools") + os.pathsep + os.environ.get("PATH", "") 42 | ) 43 | design = Design.from_toml(EXAMPLES_DIR / "vhdl" / "sqrt" / "sqrt.toml") 44 | settings = dict(fpga=FPGA("xc7a12tcsg325-1"), clock_period=5.5) 45 | with tempfile.TemporaryDirectory(dir=Path.cwd()) as run_dir: 46 | print("Xeda run dir: ", run_dir) 47 | xeda_runner = DefaultRunner(run_dir, debug=True) 48 | flow = xeda_runner.run_flow(VivadoSynth, design, settings) 49 | assert flow is not None, "run_flow returned None" 50 | settings_json = flow.run_path / "settings.json" 51 | results_json = flow.run_path / "results.json" 52 | assert settings_json.exists() 53 | assert results_json.exists() 54 | assert flow.succeeded 55 | assert 0.3 < flow.results.runtime # type: ignore 56 | 57 | 58 | def test_parse_hier_util() -> None: 59 | d = parse_hier_util("tests/resources/vivado_synth/hierarchical_utilization.xml") 60 | # print(json.dumps(d, indent=2)) 61 | with open("hier.json", "w") as f: 62 | json.dump(d, f, indent=4) 63 | assert d 64 | 65 | 66 | if __name__ == "__main__": 67 | # test_vivado_synth_py() 68 | test_parse_hier_util() 69 | -------------------------------------------------------------------------------- /src/xeda/units.py: -------------------------------------------------------------------------------- 1 | import re 2 | from typing import Optional, Union 3 | 4 | from pint import UnitRegistry 5 | 6 | unit_registry = UnitRegistry(case_sensitive=False) 7 | Q_ = unit_registry.Quantity 8 | 9 | 10 | def unit_maybe_scale(unit: str): 11 | unit = unit.strip() 12 | scale = None 13 | m = re.match(r"(\d*\.?\d*)\s*(\w+)", unit) 14 | if m: 15 | sc = m.group(1) 16 | if sc and sc != "1": 17 | scale = float(sc) 18 | unit = m.group(2) 19 | if unit == "ps": 20 | unit = "picoseconds" 21 | if unit == "ns": 22 | unit = "nanoseconds" 23 | if unit == "ms": 24 | unit = "milliseconds" 25 | if unit == "us": 26 | unit = "microseconds" 27 | return unit, scale 28 | 29 | 30 | def convert_unit( 31 | value, 32 | to_unit, 33 | from_unit=None, 34 | ) -> float: 35 | try: 36 | value = float(value) 37 | except ValueError: 38 | pass 39 | from_scale = None 40 | to_scale = None 41 | if from_unit: 42 | from_unit, from_scale = unit_maybe_scale(from_unit) 43 | to_unit, to_scale = unit_maybe_scale(to_unit) 44 | if from_unit and isinstance(value, (float, int)): 45 | value = Q_(value, from_unit).to(to_unit).m 46 | elif isinstance(value, str): 47 | value = Q_(value).to(to_unit).m 48 | if from_scale: 49 | value *= from_scale 50 | if to_scale: 51 | value /= to_scale 52 | return float(value) 53 | 54 | 55 | def convert_freq(f: Union[str, float, int], target_unit="MHz") -> float: 56 | return convert_unit(f, target_unit) 57 | 58 | 59 | def freq_mhz_optional( 60 | f: Union[str, float, int, None], target_unit="MHz", require_positive=True, optional=True 61 | ) -> Optional[float]: 62 | if f is None: 63 | if optional: 64 | return f 65 | raise ValueError("Value is required") 66 | f = convert_freq(f, target_unit) 67 | if require_positive and f <= 0: 68 | raise ValueError("Value should be positive") 69 | return f 70 | 71 | 72 | def convert_time( 73 | f: Union[str, float, int], 74 | target_unit="ns", 75 | ) -> float: 76 | return convert_unit(f, target_unit) 77 | 78 | 79 | def time_ns_optional( 80 | f: Union[str, float, int, None], 81 | target_unit="ns", 82 | require_non_negative=True, 83 | require_non_zero=False, 84 | optional=True, 85 | ) -> Optional[float]: 86 | if f is None: 87 | if optional: 88 | return f 89 | raise ValueError("Value is required") 90 | f = convert_time(f, target_unit) 91 | if require_non_zero and f == 0: 92 | raise ValueError("Value should be non-zero") 93 | if require_non_negative and f < 0: 94 | raise ValueError("Value should be non-negative") 95 | return f 96 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # IDE folders 2 | .vscode/ 3 | 4 | # Byte-compiled / optimized / DLL files 5 | __pycache__/ 6 | *.py[cod] 7 | *$py.class 8 | 9 | # C extensions 10 | *.so 11 | 12 | # Distribution / packaging 13 | .Python 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | downloads/ 18 | eggs/ 19 | .eggs/ 20 | /lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | wheels/ 26 | share/python-wheels/ 27 | *.egg-info/ 28 | .installed.cfg 29 | *.egg 30 | MANIFEST 31 | 32 | # PyInstaller 33 | # Usually these files are written by a python script from a template 34 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 35 | *.manifest 36 | *.spec 37 | 38 | # Installer logs 39 | pip-log.txt 40 | pip-delete-this-directory.txt 41 | 42 | # Unit test / coverage reports 43 | htmlcov/ 44 | .tox/ 45 | .nox/ 46 | .coverage 47 | .coverage.* 48 | .cache 49 | nosetests.xml 50 | coverage.xml 51 | *.cover 52 | *.py,cover 53 | .hypothesis/ 54 | .pytest_cache/ 55 | cover/ 56 | 57 | # Translations 58 | *.mo 59 | *.pot 60 | 61 | # Django stuff: 62 | *.log 63 | local_settings.py 64 | db.sqlite3 65 | db.sqlite3-journal 66 | 67 | # Flask stuff: 68 | instance/ 69 | .webassets-cache 70 | 71 | # Scrapy stuff: 72 | .scrapy 73 | 74 | # Sphinx documentation 75 | docs/_build/ 76 | 77 | # PyBuilder 78 | .pybuilder/ 79 | target/ 80 | 81 | # Jupyter Notebook 82 | .ipynb_checkpoints 83 | 84 | # IPython 85 | profile_default/ 86 | ipython_config.py 87 | 88 | # pyenv 89 | # For a library or package, you might want to ignore these files since the code is 90 | # intended to run in multiple environments; otherwise, check them in: 91 | # .python-version 92 | 93 | # pipenv 94 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 95 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 96 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 97 | # install all needed dependencies. 98 | #Pipfile.lock 99 | 100 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 101 | __pypackages__/ 102 | 103 | # Celery stuff 104 | celerybeat-schedule 105 | celerybeat.pid 106 | 107 | # SageMath parsed files 108 | *.sage.py 109 | 110 | # Environments 111 | .env 112 | .venv 113 | env/ 114 | venv/ 115 | ENV/ 116 | env.bak/ 117 | venv.bak/ 118 | 119 | # Spyder project settings 120 | .spyderproject 121 | .spyproject 122 | 123 | # Rope project settings 124 | .ropeproject 125 | 126 | # mkdocs documentation 127 | /site 128 | 129 | # mypy 130 | .mypy_cache/ 131 | .dmypy.json 132 | dmypy.json 133 | 134 | # Pyre type checker 135 | .pyre/ 136 | 137 | # pytype static type analyzer 138 | .pytype/ 139 | 140 | # Cython debug symbols 141 | cython_debug/ 142 | 143 | -------------------------------------------------------------------------------- /src/xeda/flows/ise/templates/ise_synth.tcl: -------------------------------------------------------------------------------- 1 | 2 | ## Automatically generated by Xeda 3 | ## ISE 14.7 4 | 5 | puts "\n==============================( Creating Project )================================" 6 | if { [catch { project new {{design.name}} }] } { 7 | project open {{design.name}} 8 | } 9 | {% if settings.fpga.family %} 10 | project set family {{settings.fpga.family}} 11 | {% endif %} 12 | {% if settings.fpga.device %} 13 | project set device {{settings.fpga.device}} 14 | {% endif %} 15 | {% if settings.fpga.package %} 16 | project set package {{settings.fpga.package}} 17 | {% endif %} 18 | {% if settings.fpga.speed %} 19 | project set speed "-{{settings.fpga.speed}}" 20 | {% endif %} 21 | 22 | project set "Generate Detailed MAP Report" TRUE 23 | 24 | 25 | puts "\n==============================( Adding RTL Sources )================================" 26 | {% for src in design.rtl.sources %} 27 | xfile add {{src.file}} -copy 28 | {%- endfor %} 29 | 30 | {% if design.rtl.top %} 31 | project set top {{design.rtl.top}} 32 | {% else %} 33 | project set "Auto Implementation Top" TRUE 34 | {% endif %} 35 | 36 | puts "\n==============================( Adding Constraint Files )================================" 37 | {% for ucf_file in settings.ucf_files %} 38 | if { [catch { xfile add {{ucf_file}} }] } { 39 | puts "unable to add {{ucf_file}}" 40 | } 41 | {% endfor %} 42 | 43 | {% if settings.xcf_file %} 44 | project set "Use Synthesis Constraints File" TRUE 45 | project set "Synthesis Constraints File" "{{settings.xcf_file}}" 46 | {% endif %} 47 | 48 | # puts [project properties] # to see the full list of properties 49 | 50 | puts "\n==============================( Setting Options )================================" 51 | {% if settings.nthreads is not none %} 52 | project set "Enable Multi-Threading" {{2 if settings.nthreads and settings.nthreads > 1 else "Off"}} -process "MAP" 53 | project set "Enable Multi-Threading" {{[settings.nthreads, 4]|min if settings.nthreads and settings.nthreads > 1 else "Off"}} -process "Place & Route" 54 | {% endif %} 55 | 56 | {% for k, v in settings.translate_options.items() %} 57 | project set "{{k}}" {{v}} -process "Translate" 58 | {% endfor %} 59 | {% for k, v in settings.synthesis_options.items() %} 60 | project set "{{k}}" {{v}} -process "Synthesize - XST" 61 | {% endfor %} 62 | {% for k, v in settings.map_options.items() %} 63 | project set "{{k}}" {{v}} -process "Map" 64 | {% endfor %} 65 | {% for k, v in settings.pnr_options.items() %} 66 | project set "{{k}}" {{v}} -process "Place & Route" 67 | {% endfor %} 68 | {% for k, v in settings.trace_options.items() %} 69 | project set "{{k}}" {{v}} -process "Generate Post-Place & Route Static Timing" 70 | {% endfor %} 71 | 72 | 73 | puts "\n==============================( Implementing Design )================================" 74 | 75 | process run "Implement Design" 76 | 77 | # project close 78 | 79 | -------------------------------------------------------------------------------- /get_oss_cad_suite.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # pip install progressbar 4 | import progressbar 5 | 6 | import json 7 | import pprint 8 | import urllib.request 9 | import platform 10 | from pathlib import Path 11 | from shutil import unpack_archive, rmtree 12 | 13 | system = platform.system().lower() 14 | arch = platform.machine().lower() 15 | 16 | if arch == "x86_64" or arch == "amd64": 17 | arch = "x64" 18 | elif arch == "aarch64": 19 | arch = "arm64" 20 | 21 | # print("platform=", platform.platform()) 22 | print(system, arch) 23 | 24 | repo = "YosysHQ/oss-cad-suite-build" 25 | 26 | _json = json.loads( 27 | urllib.request.urlopen( 28 | urllib.request.Request( 29 | f"https://api.github.com/repos/{repo}/releases/latest", 30 | headers={"Accept": "application/vnd.github.v3+json"}, 31 | ) 32 | ).read() 33 | ) 34 | 35 | assets = _json["assets"] 36 | 37 | asset_ext = "tgz" if system in ["linux", "darwin"] else "zip" 38 | 39 | assets = [ 40 | asset 41 | for asset in assets 42 | if asset["name"].endswith(asset_ext) and f"{system}-{arch}" in asset["name"] 43 | ] 44 | 45 | if not assets: 46 | print(f"No suitable asset found for {system}-{arch}.") 47 | exit(1) 48 | 49 | asset = assets[0] 50 | # pprint.pprint(asset) 51 | name = asset["name"] 52 | size = asset["size"] 53 | updated_at = asset["updated_at"] 54 | url = asset["browser_download_url"] 55 | 56 | 57 | class MyProgressBar: 58 | def __init__(self): 59 | self.pbar = None 60 | 61 | def __call__(self, block_num, block_size, total_size): 62 | if not self.pbar: 63 | self.pbar = progressbar.ProgressBar(maxval=total_size) 64 | self.pbar.start() 65 | 66 | downloaded = block_num * block_size 67 | if downloaded < total_size: 68 | self.pbar.update(downloaded) 69 | else: 70 | self.pbar.finish() 71 | 72 | 73 | archive_file = Path(name) 74 | if archive_file.exists() and archive_file.stat().st_size == size: 75 | print(f"using previously downloaded {archive_file}...") 76 | else: 77 | print(f"Downloading {name} ({size} Bytes) from {url}...") 78 | urllib.request.urlretrieve(url, name, MyProgressBar()) 79 | 80 | 81 | target_dir = Path.home() / ".xeda" / "tools" 82 | 83 | # content of the archive 84 | target_subdir = target_dir / "oss-cad-suite" 85 | 86 | if target_dir.exists(): 87 | if target_subdir.exists(): 88 | print(f"Removing existing installation at {target_subdir}...") 89 | rmtree(target_subdir) 90 | else: 91 | target_dir.mkdir(parents=True) 92 | 93 | print(f"Unpacking {name} to {target_subdir}...") 94 | unpack_archive(name, target_dir) 95 | 96 | assert target_subdir.exists() and target_subdir.is_dir() 97 | bin_dir = target_subdir / "bin" 98 | assert bin_dir.exists() and bin_dir.is_dir() 99 | print(f"Installation complete. Add {bin_dir} to your PATH.") 100 | -------------------------------------------------------------------------------- /src/xeda/flows/yosys/templates/yosys_synth.tcl: -------------------------------------------------------------------------------- 1 | yosys logger -notime -stderr 2 | {% include 'read_files.tcl' %} 3 | 4 | {% if settings.prep is not none %} 5 | prep {% if settings.flatten %} -flatten {% endif %} {%if design.rtl.top %} -top {{design.rtl.top}} {% else %} -auto-top {% endif %} {{settings.prep|join(" ")}} 6 | {%- else %} 7 | procs 8 | {%- if settings.flatten %} 9 | flatten 10 | {%- endif %} 11 | {%- endif %} 12 | 13 | {% include "post_rtl.tcl" %} 14 | 15 | {%- if not settings.nosynth %} 16 | log -stdout "Running synthesis" 17 | synth {{settings.synth_flags|join(" ")}} {% if design.rtl.top %} -top {{design.rtl.top}}{% endif %} {%- if settings.noabc %} -noabc {%- endif %} 18 | {%- endif %} 19 | 20 | {#- TODO: ##### LSOracle ###### #} 21 | 22 | {%- if settings.post_synth_opt %} 23 | log -stdout "Post-synth optimization" 24 | opt -full -purge -sat 25 | {%- else %} 26 | opt -purge 27 | {%- endif %} 28 | 29 | {%- if settings.adder_map %} 30 | extract_fa 31 | techmap -map {{settings.adder_map}} 32 | techmap 33 | opt -purge 34 | {%- endif %} 35 | 36 | {%- for map in settings.other_maps %} 37 | techmap -map {{map}} 38 | {%- endfor %} 39 | 40 | {%- if settings.liberty %} 41 | log -stdout "Prepare mapping FFs to technology" 42 | dfflibmap -prepare -liberty {% if settings.dff_liberty -%} {{settings.dff_liberty}} {%- else -%} {{settings.liberty[0]}} {%- endif %} 43 | opt -purge 44 | {%- endif %} 45 | 46 | {%- if not settings.noabc %} 47 | log -stdout "Running ABC" 48 | abc {{settings.abc_flags|join(" ")}} 49 | {%- if settings.main_clock and settings.main_clock.period_ps %} -D {{"%.3f"|format(settings.main_clock.period_ps)}} {% endif %} 50 | {%- if settings.abc_script %} -script "{{settings.abc_script}}" {%- endif %} 51 | {%- if settings.liberty %} -liberty "{{settings.liberty[0]}}" {%- endif %} 52 | {%- if abc_constr_file %} -constr "{{abc_constr_file}}" {%- endif %} 53 | opt -purge 54 | {%- endif %} 55 | 56 | {%- if settings.liberty %} 57 | log -stdout "Mapping FFs to technology" 58 | dfflibmap -liberty {% if settings.dff_liberty -%} {{settings.dff_liberty}} {%- else -%} {{settings.liberty[0]}} {%- endif %} 59 | opt -purge 60 | {%- endif %} 61 | 62 | # replace undefined values with 0 63 | setundef -zero 64 | opt -full -purge 65 | 66 | {%- if settings.splitnets %} 67 | splitnets {%- if settings.splitnets_driver %} -driver {%- endif %} {%- if settings.splitnets_ports %} -ports {%-endif %} 68 | {%- endif %} 69 | 70 | opt_clean -purge 71 | 72 | {%- if settings.hilomap %} 73 | hilomap {% if settings.hilomap.singleton %} -singleton {% endif %} -hicell {{settings.hilomap.hi|join(" ")}} -locell {{settings.hilomap.lo|join(" ")}} 74 | {%- endif %} 75 | {% if settings.insbuf %} 76 | insbuf -buf {{settings.insbuf|join(" ")}} 77 | {%- endif %} 78 | 79 | opt -full -purge 80 | clean -purge 81 | 82 | {%- if settings.rmports %} 83 | rmports 84 | {%- endif %} 85 | 86 | {%- if settings.liberty %} 87 | check {% if settings.check_assert -%} -assert {% endif -%} -mapped 88 | {%- endif %} 89 | {% include "write_netlist.tcl" %} 90 | 91 | log -stdout "***** Synthesis Completed *****" 92 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ "main" ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ "main" ] 20 | schedule: 21 | - cron: '18 21 * * 1' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'python' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v3 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v2 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | 52 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 53 | # queries: security-extended,security-and-quality 54 | 55 | 56 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 57 | # If this step fails, then you should remove it and run the build manually (see below) 58 | - name: Autobuild 59 | uses: github/codeql-action/autobuild@v2 60 | 61 | # ℹ️ Command-line programs to run using the OS shell. 62 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 63 | 64 | # If the Autobuild fails above, remove it and uncomment the following three lines. 65 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 66 | 67 | # - run: | 68 | # echo "Run, Build Application using script" 69 | # ./location_of_script_within_repo/buildscript.sh 70 | 71 | - name: Perform CodeQL Analysis 72 | uses: github/codeql-action/analyze@v2 73 | with: 74 | category: "/language:${{matrix.language}}" 75 | -------------------------------------------------------------------------------- /src/xeda/flows/quartus/quartus_dse.py: -------------------------------------------------------------------------------- 1 | # TODO 2 | # class QuartusDse(QuartusSynth, DseFlow): 3 | # def run(self): 4 | # self.create_project() 5 | # # 'explore': Exploration flow to use, if not specified in --config 6 | # # configuration file. Valid flows: timing_aggressive, 7 | # # all_optimization_modes, timing_high_effort, seed, 8 | # # area_aggressive, power_high_effort, power_aggressive 9 | # # 'compile_flow': 'full_compile', 'fit_sta' and 'fit_sta_asm'. 10 | # # 'timeout': Limit the amount of time a compute node is allowed to run. Format: hh:mm:ss 11 | # if 'dse' not in self.settings.flow: 12 | # self.fatal('`flows.quartus.dse` settings are missing!') 13 | 14 | # dse = self.settings.flow['dse'] 15 | # if 'nproc' not in dse or not dse['nproc']: 16 | # dse['nproc'] = self.nthreads 17 | 18 | # script_path = self.copy_from_template(f'settings.dse', 19 | # dse=dse 20 | # ) 21 | # self.run_process('quartus_dse', 22 | # ['--use-dse-file', script_path, self.settings.design['name']], 23 | # stdout_logfile='dse_stdout.log', 24 | # initial_step="Running Quartus DSE", 25 | # ) 26 | # self.run_process('quartus_sh', 27 | # ['--dse', '-project', self.settings.design['name'], '-nogui', '-concurrent-compiles', '8', '-exploration-space', 28 | # "Extra Effort Space", '-optimization-goal', "Optimize for Speed", '-report-all-resource-usage', '-ignore-failed-base'], 29 | # stdout_logfile='dse_stdout.log' 30 | # ) 31 | # def quartus_gen_convert(k, x, sim): 32 | # if sim: 33 | # if isinstance(x, dict) and "file" in x: 34 | # p = x["file"] 35 | # assert isinstance(p, str), "value of `file` should be a relative or absolute path string" 36 | # x = self.conv_to_relative_path(p.strip()) 37 | # self.logger.info(f'Converting generic `{k}` marked as `file`: {p} -> {x}') 38 | # xl = str(x).strip().lower() 39 | # if xl == 'false': 40 | # return "1\\'b0" 41 | # if xl == 'true': 42 | # return "1\\'b1" 43 | # return x 44 | 45 | # self.run_process('quartus_eda', [prj_name, '--simulation', '--functional', '--tool=modelsim_oem', '--format=verilog'], 46 | # stdout_logfile='eda_1_stdout.log' 47 | # ) 48 | # DSE: 49 | 50 | # Available exploration spaces for this family are: 51 | # "Seed Sweep" 52 | # "Extra Effort Space" 53 | # "Extra Effort Space for Quartus Prime Integrated Synthesis Projects" 54 | # "Area Optimization Space" 55 | # "Signature: Placement Effort Multiplier" 56 | # "Custom Space" 57 | 58 | # Valid optimization-goal options are: 59 | # "Optimize for Speed" 60 | # "Optimize for Area" 61 | # "Optimize for Power" 62 | # "Optimize for Negative Slack and Failing Paths" 63 | # "Optimize for Average Period" 64 | # "Optimize for Quality of Fit" 65 | -------------------------------------------------------------------------------- /src/xeda/flows/vivado/vivado_power.py: -------------------------------------------------------------------------------- 1 | import html 2 | import logging 3 | from typing import Any, Dict 4 | from xml.etree import ElementTree 5 | 6 | from .vivado_postsynthsim import VivadoPostsynthSim 7 | from .vivado_sim import VivadoSim 8 | from .vivado_synth import VivadoSynth 9 | 10 | logger = logging.getLogger(__name__) 11 | 12 | 13 | class VivadoPower(VivadoSim): 14 | class Settings(VivadoSim.Settings): 15 | timing_sim: bool = True 16 | elab_debug: str = "typical" 17 | saif: str = "activity.saif" 18 | postsynthsim: VivadoPostsynthSim.Settings 19 | power_report_xml: str = "power_impl_timing.xml" 20 | 21 | def init(self) -> None: 22 | assert self.design.tb, "A testbench is required for power estimation" 23 | ss = self.settings 24 | assert isinstance(ss, self.Settings) 25 | ss.postsynthsim.timing_sim = ss.timing_sim 26 | ss.postsynthsim.elab_debug = ss.elab_debug 27 | ss.postsynthsim.saif = ss.saif 28 | self.add_dependency(VivadoPostsynthSim, ss.postsynthsim) 29 | 30 | def run(self) -> None: 31 | assert isinstance(self.settings, self.Settings) 32 | 33 | postsynth_sim_flow = self.pop_dependency(VivadoPostsynthSim) 34 | synth_flow = postsynth_sim_flow.pop_dependency(VivadoSynth) 35 | 36 | checkpoint = str( 37 | synth_flow.run_path 38 | / f"{self.design.name}.runs" 39 | / "impl_1" 40 | / f"{self.design.rtl.top}_routed.dcp" 41 | ) 42 | saif_file = str(postsynth_sim_flow.run_path / self.settings.saif) 43 | 44 | # assert isinstance(dep_synth_flow.settings, VivadoSynth.Settings) 45 | script_path = self.copy_from_template( 46 | "vivado_power.tcl", 47 | checkpoint=checkpoint, 48 | saif_file=saif_file, 49 | ) 50 | 51 | self.vivado.run("-source", script_path) 52 | 53 | def parse_power_report(self, report_xml) -> Dict[str, Any]: 54 | tree = ElementTree.parse(report_xml) 55 | results = {} 56 | for tablerow in tree.findall("./section[@title='Summary']/table/tablerow"): 57 | tablecells = tablerow.findall("tablecell") 58 | key, value = (html.unescape(x.attrib["contents"]).strip() for x in tablecells) 59 | results[key] = value 60 | 61 | for tablerow in tree.findall( 62 | "./section[@title='Summary']/section[@title='On-Chip Components']/table/tablerow" 63 | ): 64 | tablecells = tablerow.findall("tablecell") 65 | if len(tablecells) >= 2: 66 | contents = [html.unescape(x.attrib["contents"]).strip() for x in tablecells] 67 | key = contents[0] 68 | value = contents[1] 69 | results[f"Component Power: {key}"] = value 70 | 71 | return results 72 | 73 | def parse_reports(self) -> bool: 74 | assert isinstance(self.settings, self.Settings) 75 | report_xml = self.run_path / self.settings.power_report_xml 76 | results = self.parse_power_report(report_xml) 77 | self.results.update(**results) 78 | return True 79 | -------------------------------------------------------------------------------- /src/xeda/flows/yosys/cxx_rtl.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from pathlib import Path 3 | from typing import Any, List, Optional 4 | 5 | from ...dataclass import XedaBaseModel 6 | from ...design import SourceType 7 | from ...flow import SimFlow 8 | from ...flows.ghdl import GhdlSynth 9 | from ...tool import Docker, Tool 10 | from .common import YosysBase 11 | 12 | log = logging.getLogger(__name__) 13 | 14 | 15 | class CxxRtl(XedaBaseModel): 16 | filename: Optional[str] = None 17 | header: bool = True 18 | flatten: bool = True 19 | hierarchy: bool = True 20 | proc: bool = True 21 | debug: Optional[int] = None 22 | opt: Optional[int] = None 23 | namespace: Optional[str] = None 24 | ccflags: List[str] = [] 25 | 26 | 27 | class YosysSim(YosysBase, SimFlow): 28 | """Simulate with CXXRTL""" 29 | 30 | class Settings(YosysBase.Settings): 31 | cxxrtl: CxxRtl = CxxRtl() 32 | 33 | def run(self) -> None: 34 | assert isinstance(self.settings, self.Settings) 35 | ss = self.settings 36 | yosys = Tool( 37 | executable="yosys", 38 | docker=Docker(image="hdlc/impl"), # pyright: reportGeneralTypeIssues=none 39 | ) 40 | ss.flatten = True 41 | if not ss.cxxrtl.filename: 42 | ss.cxxrtl.filename = ( 43 | self.design.rtl.top if self.design.rtl.top else self.design.name + ".cpp" 44 | ) 45 | script_path = self.copy_from_template( 46 | "yosys_sim.tcl", 47 | lstrip_blocks=True, 48 | trim_blocks=True, 49 | ghdl_args=GhdlSynth.synth_args(ss.ghdl, self.design), 50 | ) 51 | log.info("Yosys script: %s", self.run_path.relative_to(Path.cwd()) / script_path) 52 | # args = ['-s', script_path] 53 | args = ["-c", script_path] 54 | if ss.log_file: 55 | args.extend(["-L", ss.log_file]) 56 | if not ss.verbose: # reduce noise unless verbose 57 | args.extend(["-T", "-Q"]) 58 | if not ss.debug: 59 | args.append("-q") 60 | self.results["_tool"] = yosys.info # TODO where should this go? 61 | log.info("Logging yosys output to %s", ss.log_file) 62 | yosys.run(*args) 63 | 64 | yosys_config = yosys.derive("yosys-config") 65 | yosys_include_dir = yosys_config.run_get_stdout("--datdir/include") 66 | cxx = yosys.derive("g++") 67 | assert ss.cxxrtl.filename 68 | cxxrtl_cpp = Path(ss.cxxrtl.filename) 69 | cxx_args: List[Any] = [cxxrtl_cpp] + [ 70 | f.path for f in self.design.sim_sources_of_type(SourceType.Cpp) 71 | ] 72 | sim_bin_file = cxxrtl_cpp.with_suffix("") 73 | cxx_args += ["-std=c++14"] 74 | cxx_args += ["-o", sim_bin_file] 75 | cxx_args += [f"-I{yosys_include_dir}"] 76 | if ss.cxxrtl.header: 77 | cxx_args += [f"-I{cxxrtl_cpp.parent}"] 78 | cxx_args += ss.cxxrtl.ccflags 79 | cxx.run(*cxx_args) 80 | sim_bin = yosys.derive(executable=Path.cwd() / sim_bin_file) 81 | sim_bin.run() 82 | 83 | def parse_reports(self) -> bool: 84 | return True 85 | -------------------------------------------------------------------------------- /src/xeda/flows/openfpgaloader.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from typing import Optional 3 | 4 | from ..board import WithFpgaBoardSettings, get_board_data 5 | from ..dataclass import validator 6 | from ..flow import FlowSettingsException, FpgaSynthFlow 7 | from ..tool import Tool 8 | from .nextpnr import Nextpnr 9 | 10 | __all__ = ["Openfpgaloader"] 11 | 12 | log = logging.getLogger(__name__) 13 | 14 | 15 | class Openfpgaloader(FpgaSynthFlow): 16 | ofpga_loader = Tool("openFPGALoader") 17 | 18 | class Settings(WithFpgaBoardSettings): 19 | clock_period: float 20 | reset: bool = False 21 | cable: Optional[str] = None 22 | nextpnr: Optional[Nextpnr.Settings] = None 23 | 24 | @validator("nextpnr", always=True, pre=True) 25 | def _validate_nextpnr(cls, value, values): 26 | clocks = values.get("clocks") 27 | fpga = values.get("fpga") 28 | board = values.get("board") 29 | if value is None: 30 | value = {} 31 | if isinstance(value, Nextpnr.Settings): 32 | value = value.dict() 33 | assert isinstance(value, (dict)), f"not a dict: {value}" 34 | value["fpga"] = fpga 35 | value["board"] = board 36 | value["clocks"] = clocks 37 | return Nextpnr.Settings(**value) 38 | 39 | def init(self) -> None: 40 | self.packer: Optional[Tool] = None 41 | assert isinstance(self.settings, self.Settings) 42 | ss = self.settings 43 | assert ss.nextpnr is not None 44 | self.add_dependency(Nextpnr, ss.nextpnr) 45 | if ss.fpga is None: 46 | raise FlowSettingsException("") 47 | if ss.fpga.family == "ecp5": # FIXME from fpga/board 48 | self.packer = Tool("ecppack") 49 | 50 | def run(self) -> None: 51 | assert isinstance(self.settings, self.Settings) 52 | ss = self.settings 53 | board_id = ss.board 54 | board_name = None 55 | if board_id: 56 | board_data = get_board_data(board_id) 57 | if board_data: 58 | board_name = board_data.get("name") 59 | next_pnr = self.completed_dependencies[0] 60 | assert isinstance(next_pnr, Nextpnr) 61 | assert isinstance(next_pnr.settings, Nextpnr.Settings) 62 | assert next_pnr.settings.textcfg 63 | text_cfg = next_pnr.run_path / next_pnr.settings.textcfg 64 | assert text_cfg.exists(), f"Can't find {text_cfg} generated by Nextpnr!" 65 | bitstream = f"{board_name}.bit" if board_name else "bitstream.bit" 66 | if self.packer: 67 | self.packer.run(text_cfg, bitstream) 68 | args = ["--bitstream", bitstream] 69 | if ss.cable: 70 | args.extend(["--cable", ss.cable]) 71 | elif board_name: 72 | args.extend(["--board", board_name]) 73 | assert ss.fpga is not None 74 | if ss.fpga.part: 75 | args.extend(["--fpga-part", ss.fpga.part]) 76 | if ss.reset: 77 | args.append("--reset") 78 | if ss.verbose: 79 | args.append("--verbose") 80 | self.ofpga_loader.run(*args) 81 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | # import os 14 | # import sys 15 | # sys.path.insert(0, os.path.abspath(".")) 16 | 17 | from importlib.metadata import version as release_version 18 | 19 | # -- Project information ----------------------------------------------------- 20 | 21 | project = "xeda" 22 | copyright = "2022, Kamyar Mohajerani" 23 | author = "Kamyar Mohajerani" 24 | version = release_version("xeda") 25 | 26 | master_doc = "index" 27 | language = "en" 28 | 29 | 30 | # -- General configuration --------------------------------------------------- 31 | 32 | # Add any Sphinx extension module names here, as strings. They can be 33 | # extensions coming with Sphinx (named "sphinx.ext.*") or your custom 34 | # ones. 35 | extensions = [ 36 | # "sphinxcontrib.bibtex", 37 | "myst_parser", 38 | "sphinx.ext.autodoc", 39 | "sphinx.ext.intersphinx", 40 | "sphinx.ext.viewcode", 41 | "sphinx_panels", 42 | "sphinxext.rediraffe", 43 | "sphinxcontrib.mermaid", 44 | "sphinxext.opengraph", 45 | "sphinxcontrib.autodoc_pydantic", 46 | "sphinx.ext.autosummary", 47 | "sphinx.ext.autodoc" 48 | ] 49 | 50 | # Add any paths that contain templates here, relative to this directory. 51 | templates_path = ["_templates"] 52 | 53 | # List of patterns, relative to source directory, that match files and 54 | # directories to ignore when looking for source files. 55 | # This pattern also affects html_static_path and html_extra_path. 56 | exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] 57 | 58 | 59 | # -- Options for HTML output ------------------------------------------------- 60 | 61 | # The theme to use for HTML and HTML Help pages. See the documentation for 62 | # a list of builtin themes. 63 | # 64 | html_theme = "sphinx_book_theme" 65 | html_logo = "../logo.svg" 66 | # html_favicon = "../logo.svg" 67 | html_title = "" 68 | html_theme_options = { 69 | "github_url": "https://github.com/XedaHQ/xeda", 70 | "repository_url": "https://github.com/XedaHQ/xeda", 71 | "use_edit_page_button": True, 72 | "repository_branch": "dev", 73 | "path_to_docs": "docs", 74 | } 75 | 76 | # Add any paths that contain custom static files (such as style sheets) here, 77 | # relative to this directory. They are copied after the builtin static files, 78 | # so a file named "default.css" will overwrite the builtin "default.css". 79 | html_static_path = ["_static"] 80 | 81 | intersphinx_mapping = { 82 | "python": ("https://docs.python.org/3.9", None), 83 | "pydantic": ("https://www.sphinx-doc.org/en/master", None), 84 | } 85 | 86 | 87 | autosummary_generate = True 88 | # autodoc_member_order = "bysource" 89 | -------------------------------------------------------------------------------- /src/xeda/platforms/asap7/openlane/asap7sc7p5t/no_synth.cells: -------------------------------------------------------------------------------- 1 | A2O1A1Ixp33_ASAP7_75t_R 2 | A2O1A1O1Ixp25_ASAP7_75t_R 3 | AO21x1_ASAP7_75t_R 4 | AO221x1_ASAP7_75t_R 5 | AO22x1_ASAP7_75t_R 6 | AO32x1_ASAP7_75t_R 7 | AO331x1_ASAP7_75t_R 8 | AO332x1_ASAP7_75t_R 9 | AO333x1_ASAP7_75t_R 10 | AOI211x1_ASAP7_75t_R 11 | AOI211xp5_ASAP7_75t_R 12 | AOI21x1_ASAP7_75t_R 13 | AOI21xp33_ASAP7_75t_R 14 | AOI21xp5_ASAP7_75t_R 15 | AOI221x1_ASAP7_75t_R 16 | AOI221xp5_ASAP7_75t_R 17 | AOI222xp33_ASAP7_75t_R 18 | AOI22x1_ASAP7_75t_R 19 | AOI22xp33_ASAP7_75t_R 20 | AOI22xp5_ASAP7_75t_R 21 | AOI311xp33_ASAP7_75t_R 22 | AOI31xp33_ASAP7_75t_R 23 | AOI31xp67_ASAP7_75t_R 24 | AOI321xp33_ASAP7_75t_R 25 | AOI322xp5_ASAP7_75t_R 26 | AOI32xp33_ASAP7_75t_R 27 | AOI331xp33_ASAP7_75t_R 28 | AOI332xp33_ASAP7_75t_R 29 | AOI333xp33_ASAP7_75t_R 30 | AOI33xp33_ASAP7_75t_R 31 | HB1xp67_ASAP7_75t_R 32 | HB2xp67_ASAP7_75t_R 33 | HB3xp67_ASAP7_75t_R 34 | HB4xp67_ASAP7_75t_R 35 | INVx1_ASAP7_75t_R 36 | INVxp33_ASAP7_75t_R 37 | INVxp67_ASAP7_75t_R 38 | O2A1O1Ixp33_ASAP7_75t_R 39 | O2A1O1Ixp5_ASAP7_75t_R 40 | OA331x1_ASAP7_75t_R 41 | OA332x1_ASAP7_75t_R 42 | OA333x1_ASAP7_75t_R 43 | OAI211xp5_ASAP7_75t_R 44 | OAI21x1_ASAP7_75t_R 45 | OAI21xp33_ASAP7_75t_R 46 | OAI21xp5_ASAP7_75t_R 47 | OAI221xp5_ASAP7_75t_R 48 | OAI222xp33_ASAP7_75t_R 49 | OAI22x1_ASAP7_75t_R 50 | OAI22xp33_ASAP7_75t_R 51 | OAI22xp5_ASAP7_75t_R 52 | OAI311xp33_ASAP7_75t_R 53 | OAI31xp33_ASAP7_75t_R 54 | OAI31xp67_ASAP7_75t_R 55 | OAI321xp33_ASAP7_75t_R 56 | OAI322xp33_ASAP7_75t_R 57 | OAI32xp33_ASAP7_75t_R 58 | OAI331xp33_ASAP7_75t_R 59 | OAI332xp33_ASAP7_75t_R 60 | OAI333xp33_ASAP7_75t_R 61 | OAI33xp33_ASAP7_75t_R 62 | ASYNC_DFFHx1_ASAP7_75t_R 63 | DFFHQNx1_ASAP7_75t_R 64 | DFFHQNx2_ASAP7_75t_R 65 | DFFHQNx3_ASAP7_75t_R 66 | DFFHQx4_ASAP7_75t_R 67 | DFFLQNx1_ASAP7_75t_R 68 | DHLx1_ASAP7_75t_R 69 | DLLx1_ASAP7_75t_R 70 | ICGx1_ASAP7_75t_R 71 | ICGx2_ASAP7_75t_R 72 | ICGx2p67DC_ASAP7_75t_R 73 | ICGx3_ASAP7_75t_R 74 | ICGx4DC_ASAP7_75t_R 75 | ICGx4_ASAP7_75t_R 76 | ICGx5_ASAP7_75t_R 77 | ICGx5p33DC_ASAP7_75t_R 78 | ICGx6p67DC_ASAP7_75t_R 79 | ICGx8DC_ASAP7_75t_R 80 | SDFHx1_ASAP7_75t_R 81 | SDFHx2_ASAP7_75t_R 82 | SDFHx3_ASAP7_75t_R 83 | SDFHx4_ASAP7_75t_R 84 | SDFLx1_ASAP7_75t_R 85 | SDFLx2_ASAP7_75t_R 86 | SDFLx3_ASAP7_75t_R 87 | SDFLx4_ASAP7_75t_R 88 | AND3x1_ASAP7_75t_R 89 | AND4x1_ASAP7_75t_R 90 | AND5x1_ASAP7_75t_R 91 | FAx1_ASAP7_75t_R 92 | HAxp5_ASAP7_75t_R 93 | MAJIxp5_ASAP7_75t_R 94 | NAND2x1_ASAP7_75t_R 95 | NAND2x1p5_ASAP7_75t_R 96 | NAND2xp33_ASAP7_75t_R 97 | NAND2xp5_ASAP7_75t_R 98 | NAND2xp67_ASAP7_75t_R 99 | NAND3x1_ASAP7_75t_R 100 | NAND3xp33_ASAP7_75t_R 101 | NAND4xp25_ASAP7_75t_R 102 | NAND4xp75_ASAP7_75t_R 103 | NAND5xp2_ASAP7_75t_R 104 | NOR2x1_ASAP7_75t_R 105 | NOR2x1p5_ASAP7_75t_R 106 | NOR2xp33_ASAP7_75t_R 107 | NOR2xp67_ASAP7_75t_R 108 | NOR3x1_ASAP7_75t_R 109 | NOR3xp33_ASAP7_75t_R 110 | NOR4xp25_ASAP7_75t_R 111 | NOR4xp75_ASAP7_75t_R 112 | NOR5xp2_ASAP7_75t_R 113 | OR3x1_ASAP7_75t_R 114 | OR4x1_ASAP7_75t_R 115 | OR5x1_ASAP7_75t_R 116 | TIEHIx1_ASAP7_75t_R 117 | TIELOx1_ASAP7_75t_R 118 | XNOR2x1_ASAP7_75t_R 119 | XNOR2xp5_ASAP7_75t_R 120 | XOR2x1_ASAP7_75t_R 121 | XOR2xp5_ASAP7_75t_R 122 | --------------------------------------------------------------------------------