Troubleshooting¶
Gotchas encountered running Flow A, kept here so they don’t have to be re-discovered per design.
Environment / install¶
externally-managed-environmentonpip install --user fusesocUbuntu 24.04 blocks system-wide/user pip installs (PEP 668). Use a venv instead — see Getting Started.
ImportError: cannot import name 'walk_tool_packages' from 'edalize.edatool'Version mismatch between FuseSoC and the auto-installed Edalize. Fix:
pip install --upgrade edalize.this core was not foundrunning a design from a local checkoutFuseSoC doesn’t scan the working directory for
.corefiles by default — add--cores-root .to thefusesoc runcommand.
Synthesis¶
- Edalize’s Yosys backend crashes with a
TypeErrorbefore readingyosys_template The Tool-API Yosys backend requires a non-empty
archvalue in the.corefile’stools.yosyssection, even when a full customyosys_templateoverrides its entire built-in flow anyway. Setarch: genericas a placeholder.- OpenSTA/OpenROAD fails to parse the mapped netlist, or complains about
signed Yosys still emits the
signedqualifier on port/wire declarations after synthesis; OpenSTA/OpenROAD’s Verilog reader doesn’t support it.synth.tclalready strips it as its last step; if you hit this error on a netlist from a custom script, strip it yourself (it carries no structural meaning at this point):sed -i 's/ signed / /g' <mapped netlist>.v
- Registers left as behavioral
alwaysblocks instead of real cells dfflibmapmust run beforeabcin the synthesis script. Without it, OpenSTA/OpenROAD’s Verilog reader — which only understands gate instantiations — fails to parse the netlist.
Gate-level simulation¶
- 100% “Unable to match ModPath” errors during SDF-annotated simulation
Missing
-gspecify. It’s disabled by default in Icarus; without it, specify blocks are parsed but ignored, so$sdf_annotatehas no ModPath objects to attach delays to. The simulation may still report a “pass” in this state — that’s a false positive caused by zero real delay ever being applied. Verify real annotation actually happened by checking the SDF verbose log for nonzero “Putting delay:” lines, or by checking the “Unable to match ModPath” error count dropped to 0%.Could not find net. Did you run iverilog with '-ginterconnect'?Missing
-ginterconnect, required for SDF INTERCONNECT (net/wire delay) matching.- Functional mismatches appear only in the post-route SDF-annotated simulation, not at RTL or post-synthesis
Check static timing first (
report_worst_slack -maxand-min) — if both are comfortably MET, it is likely not a real setup/hold violation but a testbench-timing artifact: the stimulus is being driven on the same clock edge the DUT’s own input-capture register uses, leaving zero margin once real nonzero SDF cell/interconnect delays are applied. Moving the stimulus-driving block to the opposite edge (e.g. fromposedgetonegedgeif the DUT captures onposedge) typically resolves it, giving roughly half a clock period of margin. Confirm with a controlled, single-variable experiment (only change the stimulus edge, re-run against the same routed netlist and SDF file) before concluding this is the cause — a checker sampling-edge race can look similar but does not go away when the checker (rather than the stimulus) is moved to the other edge.- Vectorless
report_powernumbers look implausible (too high, or don’t respond to the clock period) report_powerwith no VCD loaded uses OpenSTA’s default/vectorless switching-activity assumption, which can overstate real power by an order of magnitude and isn’t meaningfully tied to the clock period. Capture a VCD from an already-verified-passing gate-level simulation and useread_vcdbeforereport_power— see the real-activity power section in Running Flow A on Your Own SV Design. A useful sanity check once you have both numbers: real-activity power should generally go up, not down, from pre-route to post-route (added interconnect parasitics add switching capacitance) — if the vectorless numbers show the opposite trend, that’s further evidence they weren’t physically meaningful to begin with.
Place & route¶
GPL-0326 <port> toplevel port is not placedduringglobal_placementRun
place_pinsbeforeglobal_placement— every top-level port needs a placed location first.- IO pins end up clustered on one edge instead of spread across all four
global_placementmoves standard cells to satisfy its density target but does not move already-placed pins along with them. Callplace_pinsa second time, afterglobal_placement.- Placer compacts the whole design into part of the die instead of spreading uniformly
The default target density (0.70) lets the placer satisfy the density constraint with a wirelength-optimal blob rather than a uniform spread. Pass an explicit
-densityclose to your actual target utilization toglobal_placement.detailed_route/TritonRoute crashes or segfaultsConfirmed (via a null-pointer dereference in
dmesg, not memory exhaustion) to be unsafe inside the OpenROAD GUI process. Runpnr.tclheadless (openroad -no_init -exit ...), not with-gui. Everything up to (not including) routing can still be typed into the GUI’s Scripting console for visual inspection if needed.[ERROR EST-0005] Run global_route before estimating parasitics for global routingReloading a written
.defin a freshopenroadsession does not restore the linked-network/global-route state thatextract_parasitics/estimate_parasiticsneed. Keep floorplanning through extraction (write_spef) in the onepnr.tclsession. Reporting does not need that state:post_route.tclreloads the routed netlist and reads the written SPEF instead.$sdf_annotatefails to match instances between the netlist and SDF<design>_route.sdfmust be written from the same routed netlist as the<design>_route.vyou simulate — instance names must match exactly.pnr.tclwrites<design>_route.v;post_route.tclreloads that file and writes the SDF, so the two stay consistent as long as you do not re-runpnr.tclwithout re-runningpost_route.tcl(make sdfhandles this through its dependencies).- Icarus’s default min:typ:max delay selection has nothing to pick for “typ”
write_sdfneeds the-include_typflag; without it, OpenROAD only emits min/max delays.
Multi-file designs (read_slang)¶
sorry: Overriding the default variable lifetime is not yet supportedIcarus Verilog does not support a per-declaration
automatic/staticlifetime override (e.g.automatic integer x;inside a procedural block with a different default lifetime) — this is a real Icarus limitation, not a SystemVerilog error;read_slanghandles the same construct correctly. Fix: remove the qualifier if the variable is always written before read in every iteration where it’s used (usually safe — check this holds before removing it blindly).error: '--ignore-unknown-modules' no longer supported with sv-elabRecent
read_slang/sv-elab builds have removed this flag. Drop it rather than searching for a replacement — it’s only needed when a referenced module genuinely isn’t in the.corefile’srtlfileset, which a complete fileset prevents in the first place.--compat-modeis deprecated/always-on (safe to drop too);--keep-hierarchyis explicitly flagged experimental/may-crash by the tool itself — avoid unless you specifically need preserved hierarchy for reporting.couldn't read file "scripts/yosys_common.tcl": no such file or directoryPath is relative to the caller’s working directory, which differs between
synth.tcl(run by Edalize frombuild/<core>_<version>/synth-yosys/, three levels below the project root) andppa_report.tcl/pnr.tcl(run standalone from the project root). Use../../../scripts/yosys_common.tclinsynth.tcland plainscripts/yosys_common.tclin the other two — this is already correct in the versions underflow-a/scripts/; this entry exists for when thesourceline gets copy-pasted between contexts by hand.parameter '<NAME>' not found in '<tb>.dut'during gate-level simulationSynthesis flattens/resolves module parameters, so the mapped/routed netlist’s top module no longer declares them. A testbench that worked fine for RTL sim with
dut #(.PARAM(PARAM)) dut (...)will fail to elaborate against any post-synthesis or post-route netlist. Fix: in the gate-level copy of the testbench only, drop the parameter override entirely (dut #(...) dut→dut dut) — this changes nothing functionally as long as the mapped netlist was synthesized with the same parameter value as the default.Unable to bind wire/reg/memory '<dut>.<submodule>.<signal>'during gate-level simulationA hierarchical debug reference into an internal submodule signal (
dut.u_sub.internal_signal) in the testbench. Synthesis renames/flattens internal nets, so these references can’t resolve against a gate-level netlist even when the design itself is correct. Remove or comment out these references in the gate-level copy of the testbench only — never edit the original RTL testbench used for pre-synthesis simulation.- Garbled/non-hex characters (e.g.
@AA@) in$displayoutput during SDF-annotated simulation, alongside functional mismatches Distinct from the clock-edge race described above (that one produces clean-but-wrong hex values on a clocked design) — this pattern, on a combinational path, means the output is still partially
Xwhen sampled: Verilog’s 4-state ternary (cond ? "PASS" : "FAIL") bitwise-blends both string literals whenconditself evaluates toX, producing corrupted text rather than picking one string. Root cause is almost always insufficient settling time between driving inputs and sampling outputs in the testbench — a delay like#1sized for a zero-delay functional model is nowhere near enough once real SDF gate/wire delays are annotated on a multi-ns combinational path. Fix: increase the testbench’s settling delay to at least 2x the real critical-path delay found intiming_fmax.rpt/timing_postroute.rptbefore re-running.synth.tclreportsno RTL files from the .core file's filesetsThe
synthtarget has nofilesets:entry, or the files in them lackfile_type: systemVerilogSource(Edalize ignores files whose type it doesn’t recognise as Verilog/SystemVerilog). Check the target listsfilesets: [rtl]and the fileset sets the file type.unknown TECH '<name>'/$PDK_ROOT is not setEvery flow script loads
scripts/tech/$TECH.tclthroughscripts/tech.tcl(TECHdefaults tosky130hd). ExportPDK_ROOT/PDKas in Getting Started, and runtclsh scripts/tech_query.tcl checkto list any missing PDK file.
Documentation build¶
sphinx-build -Wfails on a warningThe CI workflow (
.github/workflows/docs.yml) treats every Sphinx warning as an error. Common causes: a.. toctree::entry pointing at a page that doesn’t exist yet, or a duplicate section label across pages. Runsphinx-build -W docs docs/_build/htmllocally before pushing to catch these early.
Signoff, timing and repair¶
report_checks/write_sdfignore the extracted wires (setup slack too good, every SDF delay 0)OpenSTA only uses parasitics after
read_spef. Usescripts/post_route.tcl(make postroute), not reports made insidepnr.tcl.- Input hold is not checked, or the testbench fails hold at the first vector
set_input_delaywith-maxleaves min delays unset, so input hold paths are unconstrained. Useset_input_delaywithout-max, and launch the testbench inputs at+IN_DLYequal to the SDC input delay (a mismatch causes hold races and false SDF failures).- Hold fails at the
sscorner but passes attt Input-port-to-flop paths: the clock tree is slow at
sswhile the external input delay is fixed. Repair with a hold margin (HOLD_MARGIN, default 0.35 ns) so the paths keep margin at the slower corner; check withmake multicorner.- Setup fails at the
sscorner but passes attt repair_timingonly fixes violations in the library it reads, which isttby default. Runmake pnr-ss(repair againstss_100C_1v60; the default 0.5 nsSETUP_MARGINis applied), thenmake multicorner. In the reference run this movedsssetup from −2.26 ns to +0.29 ns. If it still fails, raiseSETUP_MARGINor relax the clock period.Pin count mismatch/ every cellNoMatchin LVSThe CDL written by
write_cdlis not the right cell schematic for the KLayout deck.lvs.shbuilds the schematic from the PDK SPICE throughlvs_prep.pyand runs the deck withscale=true,convert_subckts=trueandschematic_simplify=true.- LVS
MISMATCHwith the top cell Skipped, only tie or diode cells differ Tie cells (
conb_1) and antenna diodes (diode_2) have no device the layout extraction recognises.lvs_prep.pyrewrites the tie cell anddrop_cells.pyremoves the diodes from the schematic. LVS then no longer checks those cells.- LVS shows dangling power pins on cells inserted by the repair steps
Run
global_connectbeforewrite_def/write_cdl(already inpnr.tcl): cells created afterpdngenhave no power connections until then.- DRC reports
li.5(or other) on a few standard cells Run the same deck on the bare library cell (command in Flow A: Signoff and Results). If the cell alone violates, it is a PDK library finding, not caused by the flow.
probe_p_8,probec_p_8andlpflow_*cells are excluded withdont_use_cells.- Antenna violations remain after detailed route
Antenna repair works on the global-route estimate. Raise
ANT_MARGIN(percent) for more diodes; expect a different set of violating nets rather than zero. See Flow A: Signoff and Results.- A run directory vanished or a second launch broke the first
run_flow.shrefuses an existing tag. Start a new tag instead of deletingruns/<tag>; removing a directory under a running job makes the job fail with missing-file errors inlogs/.klayoutfails withModuleNotFoundError: pyain a helper scriptPATH order: with
oss-cad-suite/environmentsourced, the wrongpython3is found. Run helper scripts with~/klayout-venv/bin/python.- Windows/WSL:
/tmpis cleared Keep scripts and outputs you need under the project directory, not
/tmp.