================= Flow A: Overview ================= Flow A is the fully open-source EDA/PDK quadrant of the thesis (Yosys + OpenROAD + KLayout, Sky130). This page explains the pipeline architecture; :doc:`running-your-own-design` shows how to point it at a design of your own. Pipeline stages ================ .. code-block:: text RTL (design.v) -> functional simulation (Icarus, via FuseSoC) -> synthesis (Yosys, via FuseSoC, target library from the PDK) -> post-synthesis functional simulation (Icarus, manual) -> post-synthesis PPA analysis (OpenROAD/OpenSTA, manual) -> place & route (OpenROAD, manual — standalone script) -> post-route SDF-back-annotated functional simulation (Icarus, manual) -> post-route PPA analysis (OpenROAD/OpenSTA, real OpenRCX parasitics) Why FuseSoC only covers two stages ==================================== FuseSoC/Edalize is used **only** for the RTL simulation and synthesis stages, via Edalize's Icarus and Yosys Tool-API backends. Place & route is run as a **standalone OpenROAD Tcl script**, not through Edalize's OpenROAD backend, because that backend is built specifically to drive the separate OpenROAD-flow-scripts (ORFS) project via its own Makefile/``config.mk`` format — a different, heavier toolchain than the hand-written Tcl flow used here. Everything from place-and-route onward (PPA analysis, gate-level simulation, SDF back-annotation) is likewise run by invoking ``openroad`` / ``iverilog`` directly, not through FuseSoC. This means for every design the flow needs: * a **FuseSoC core file** (``.core``) that describes two targets: ``sim`` (RTL functional simulation) and ``synth`` (Yosys synthesis) — see :doc:`running-your-own-design`; * three **standalone Tcl scripts** driven directly by ``openroad``: ``ppa_report.tcl`` (post-synthesis, pre-route PPA), ``pnr.tcl`` (floorplan → placement → CTS → routing → post-route PPA), and optionally a power-with-real-activity variant of each; * a handful of **manual Icarus invocations** for gate-level simulation (post-synthesis and post-route/SDF), since neither of those stages goes through FuseSoC. Output layout ============= FuseSoC-driven stages land under ``build/_//``. Everything driven directly by the standalone OpenROAD script (``pnr.tcl``) writes to the **project root** instead, since it isn't run through FuseSoC/Edalize and has no build-directory convention to follow: .. code-block:: text / ├── constraints/ │ └── .sdc ├── golden/ # expected-output reference data ├── .core # FuseSoC core file ├── rtl/ │ └── .v ├── scripts/ │ ├── synth.tcl # Yosys synthesis (custom template) │ ├── ppa_report.tcl # post-synthesis PPA │ └── pnr.tcl # place & route + post-route PPA ├── tb/ │ └── tb_.sv ├── build/ │ └── _/ │ ├── sim-icarus/ # RTL sim output │ ├── synth-yosys/ # synthesis output (netlist, reports) │ └── gls-icarus/ # gate-level sims (created manually) ├── _placed.def # from pnr.tcl, project root ├── _route.v # post-route netlist ├── _route.sdf # post-route SDF (real delays) ├── _route.spef # extracted parasitics ├── timing_postroute.rpt ├── timing_postroute_hold.rpt └── power_postroute.rpt Why the flow works this way ============================ A few design choices recur throughout the scripts and are worth knowing up front, since they explain "why is this step here" the first time you read ``synth.tcl`` or ``pnr.tcl``: * **``dfflibmap`` before ``abc``.** Generic/behavioral flip-flops must be mapped to real library cells before ABC's technology mapping runs, since OpenSTA/OpenROAD's Verilog reader only understands gate instantiations, not behavioral ``always`` blocks. * **Stripping ``signed`` from the mapped netlist.** Yosys still emits the ``signed`` qualifier on port/wire declarations in the gate-level netlist; OpenSTA/OpenROAD's Verilog reader does not support it, and it carries no structural meaning once the netlist is fully mapped, so it is safe (and required) to strip. * **Two ``place_pins`` calls in ``pnr.tcl``.** The first is required before ``global_placement`` (which hard-errors if a port has no location yet); the second is required after ``global_placement``, because that step does not move already-placed pins along with the cells it re-positions. * **``-density`` below the default in ``global_placement``.** OpenROAD's default target density (0.70) lets the placer satisfy the density constraint by compacting the netlist into a wirelength-optimal blob covering only part of the die, instead of spreading uniformly the way a commercial placer does by default. Setting ``-density`` close to the actual target utilization forces a uniform spread. * **``pnr.tcl`` must run headless.** ``detailed_route`` is known to segfault inside the OpenROAD GUI process (confirmed via a null-pointer dereference in ``dmesg``, not memory exhaustion). Every command up to (not including) routing can be typed into the GUI's Scripting console for visual inspection if needed. * **Post-route PPA reporting stays inside the same live ``openroad`` session as place & route.** Reloading a written ``.def`` in a fresh session does not restore the linked-network/global-route state that ``extract_parasitics``/``estimate_parasitics`` need — a standalone reload-and-report script fails with ``[ERROR EST-0005] Run global_route before estimating parasitics``. This is why ``pnr.tcl`` keeps floorplanning through PPA reporting in one uninterrupted script. * **Vectorless vs. real-activity power.** ``report_power`` with no VCD loaded uses OpenSTA's default/vectorless switching-activity assumption, which is not tied to the clock period in a physically meaningful way and can be off by an order of magnitude. For a trustworthy figure, capture a VCD from an already-verified-passing gate-level simulation and feed it to ``report_power`` via ``read_vcd`` — see :doc:`running-your-own-design` for the pattern. See :doc:`troubleshooting` for the full list of gotchas encountered running this flow, including the gate-level simulation flags (``-gspecify``, ``-ginterconnect``) and a testbench-timing pitfall that only shows up once real SDF delays are annotated.