Synthesis and Power Analysis
September 3, 2026 · View on GitHub
This guide explains how to run synthesis, timing analysis, area analysis, and power analysis for Vortex across all supported back-ends: Xilinx (Vivado), Altera (Quartus), Yosys (open-source), and Synopsys Design Compiler.
Table of Contents
- Design Configuration
- Generating SAIF Files
- Specifying SAIF_INST
- DUT Sub-Component Evaluation
- Xilinx (Vivado)
- Altera (Quartus)
- Yosys (Open-Source)
- Synopsys Design Compiler
- Understanding Power Reports
Design Configuration
All synthesis flows accept a CONFIGS variable to customize the hardware design at build time. CONFIGS is a string of preprocessor macro definitions (-D flags) that control core count, cache hierarchy, extensions, and other parameters.
Common configuration flags (all parameters live in the VX_CFG_* namespace; see VX_config.toml at the repo root for the full list):
| Flag | Description |
|---|---|
-DVX_CFG_NUM_CLUSTERS=N | Number of clusters |
-DVX_CFG_NUM_CORES=N | Number of cores per cluster |
-DVX_CFG_NUM_WARPS=N | Number of warps per core |
-DVX_CFG_NUM_THREADS=N | Number of threads per warp |
-DVX_CFG_L2_ENABLE | Enable shared L2 cache |
-DVX_CFG_L3_ENABLE | Enable shared L3 cache |
-DVX_CFG_EXT_TCU_ENABLE | Enable Tensor Core Unit |
-DVX_CFG_EXT_DXA_ENABLE | Enable DXA extension |
-DVX_CFG_DCACHE_SIZE=N | Set data cache size in bytes |
Example:
CONFIGS="-DVX_CFG_NUM_CLUSTERS=1 -DVX_CFG_NUM_CORES=4 -DVX_CFG_L2_ENABLE -DVX_CFG_EXT_TCU_ENABLE"
Overriding top-module parameters (-G)
CONFIGS may also carry Verilog parameter overrides as -G<NAME>=<value> alongside the -D macros. gen_sources.sh forwards these to repl_params.py, which rewrites the parameter's default in the top module's per-build copy (the source tree is untouched, so concurrent builds with different overrides stay isolated). gen_config ignores -G tokens, so no separate Makefile variable is needed.
This is mainly for the DUT unittest wrappers, whose knobs are Verilog parameters rather than VX_CFG_* macros — e.g. the cache wrapper's AMO_ENABLE and IS_LLC:
# LLC cache DUT, AMO disabled vs enabled (NT=NW=32)
CONFIGS="-DVX_CFG_NUM_THREADS=32 -DVX_CFG_NUM_WARPS=32 -GAMO_ENABLE=0 -GIS_LLC=1" PREFIX=amo0 make cache
CONFIGS="-DVX_CFG_NUM_THREADS=32 -DVX_CFG_NUM_WARPS=32 -GAMO_ENABLE=1 -GIS_LLC=1" PREFIX=amo1 make cache
All flows also support the NUM_CORES Makefile shorthand which auto-selects a pre-defined cluster/core/L2 configuration:
NUM_CORES=4 # equivalent to -DVX_CFG_NUM_CLUSTERS=1 -DVX_CFG_NUM_CORES=4 -DVX_CFG_L2_ENABLE
NUM_CORES=16 # equivalent to -DVX_CFG_NUM_CLUSTERS=1 -DVX_CFG_NUM_CORES=16 -DVX_CFG_L2_ENABLE
NUM_CORES=32 # equivalent to -DVX_CFG_NUM_CLUSTERS=2 -DVX_CFG_NUM_CORES=16 -DVX_CFG_L2_ENABLE
Using PREFIX for Isolated Builds
Use PREFIX=<unique_build_dir> to keep builds separate. Each flow creates a build directory derived from PREFIX so that multiple configurations can coexist without overwriting each other:
# Xilinx XRT: creates build_4c_<platform>_<target>/
PREFIX=build_4c NUM_CORES=4 make -C hw/syn/xilinx/xrt
# Synopsys: creates my_test_Vortex/
PREFIX=my_test make -C hw/syn/synopsys synthesis
The tinygpu Configuration for Fast Turnaround
When the component under investigation is outside the GPU core — the AFU shell, the command processor, the runtime, or the FPGA driver — a full-size Vortex build is wasted synthesis time. Most of the hours go into cores and caches that the bug does not live in, and every debug iteration pays for them again.
For those cases, use a deliberately minimal GPU: one core, two warps of two threads, all L1 caches off, and shared memory off.
CONFIGS="-DVX_CFG_NUM_CLUSTERS=1 -DVX_CFG_NUM_CORES=1 \
-DVX_CFG_NUM_WARPS=2 -DVX_CFG_NUM_THREADS=2 \
-DVX_CFG_ICACHE_DISABLE -DVX_CFG_DCACHE_DISABLE -DVX_CFG_LMEM_DISABLE"
Note the _DISABLE spelling: knobs that default to true in VX_config.toml are turned off by defining their _DISABLE guard, not by assigning =0.
This strips the design down to a single pipeline talking straight to the memory interface. Synthesis and place-and-route finish in a small fraction of the time a production configuration takes, and the resulting bitstream still exercises the complete external path: host to driver, driver to shell, shell to command processor, command processor to core, and the memory traffic back out. Timing closure is generally uneventful at this size, so a failure to close is itself a signal that the problem is in the surrounding logic rather than in core density.
Pair it with the sgemm benchmark. sgemm is well understood, self-checking, and touches every part of the external path — kernel launch, argument passing, bulk DMA in both directions, and completion signalling — while staying small enough to run quickly. A sgemm failure on tinygpu isolates the defect to the surrounding infrastructure, because the core configuration is too small to be hiding a microarchitectural corner case. Conversely, sgemm passing on tinygpu but failing at full size points back at the core, cache hierarchy, or a concurrency effect that only appears with more warps in flight.
Treat this as the first move when debugging external components, not a fallback after a long build fails. Once tinygpu is green, scale back up to the target configuration to confirm the fix under real conditions.
Generating SAIF Files
SAIF (Switching Activity Interchange Format) files capture signal toggle rates during simulation and are used to produce accurate power estimates. Vortex supports SAIF generation through its RTL simulators: rtlsim, opaesim, and xrtsim.
Method 1: Build the Simulator Directly
Build the simulator with SAIF tracing enabled, then run a workload:
# Build rtlsim with SAIF support
make -C sim/rtlsim SAIF=1
# Run a test application
make -C tests/regression/sgemm run-rtlsim
The SAIF file is written to trace.saif in the application directory.
Method 2: Use the Blackbox Test Driver
The ci/blackbox.sh script provides a convenient wrapper:
./ci/blackbox.sh --driver=rtlsim --app=sgemm --cores=4 --l2cache --saif
When --saif is passed, blackbox.sh:
- Builds the simulator with
SAIF=1 - Runs the application
- Copies the resulting
trace.saifto the current directory
--saif composes with --debug on every RTL driver, so a run can emit both the
run.log trace and the SAIF. It cannot be combined with --vcd: a model emits one
waveform format or the other.
Available drivers for SAIF generation:
| Driver | Simulator | Use Case |
|---|---|---|
rtlsim | Verilator RTL sim | General-purpose RTL power analysis |
opaesim | OPAE AFU simulator | Intel/Altera platform-specific analysis |
xrtsim | XRT simulator | Xilinx platform-specific analysis |
Specifying SAIF_INST
When reading a SAIF file, the tool must strip the testbench hierarchy prefix from signal names so they align with the synthesized netlist. SAIF_INST specifies this prefix.
Typical values:
| Flow | SAIF_INST |
|---|---|
| Xilinx DUT | TOP.rtlsim_shim.vortex |
| Xilinx XRT | TOP.vortex_afu_shim.vortex_afu |
| Synopsys / Yosys | Instance path matching your simulation hierarchy |
The path does not have to be absolute. A module instance name works if the tool can resolve it unambiguously (find-first semantics).
If the SAIF root scope already matches the top module, leave SAIF_INST empty.
DUT Sub-Component Evaluation
Both Xilinx and Altera provide DUT (Device Under Test) flows for synthesizing and analyzing sub-components in isolation, without the full platform wrapper. This is useful for evaluating individual units such as the TCU, FPU, cache, or a single core.
Xilinx DUT Targets
Located in hw/syn/xilinx/dut/. Available sub-component targets:
| Target | Module | Description |
|---|---|---|
unittest | Unit tests | Basic block tests |
scope | Scope analyzer | Debug scope |
mem_unit | Memory unit | Memory subsystem |
lmem | Local memory | Local/shared memory |
cache | Cache | Cache subsystem |
fpu | FPU | Floating-point unit |
tcu | TCU | Tensor Core Unit |
dxa | DXA | DXA extension |
core | Core | Single core |
issue | Issue unit | Instruction issue |
vortex | Vortex | Full processor (no AFU wrapper) |
top | Top | Full design with AFU |
cd hw/syn/xilinx/dut
# Synthesize the TCU in isolation
CONFIGS="-DVX_CFG_EXT_TCU_ENABLE" make tcu
# Synthesize a 4-core Vortex without the platform wrapper
CONFIGS="-DVX_CFG_NUM_CORES=4 -DVX_CFG_L2_ENABLE" make vortex
# Run power analysis on an existing tcu
make tcu-power SAIF_FILE=/path/to/trace.saif SAIF_INST=*.tensor_unit
Each target creates its build under <target>/<BUILD_DIR>/ (e.g., tcu/build/).
Altera DUT Targets
Located in hw/syn/altera/dut/. Same set of sub-component targets as Xilinx. Requires the DEVICE_FAMILY variable and IP cache generation:
cd hw/syn/altera/dut
# Generate IP cache first (required for fpu, vortex, top)
make ip-gen
# Synthesize TCU for Arria 10
DEVICE_FAMILY=arria10 CONFIGS="-DVX_CFG_EXT_TCU_ENABLE" make tcu
# Synthesize a single core for Stratix 10
DEVICE_FAMILY=stratix10 make core
Build directories include the device family: <target>/build_<device_family>/.
Xilinx (Vivado)
XRT Full-Platform Flow
Located in hw/syn/xilinx/xrt/. Builds a complete Vitis xclbin for deployment on Xilinx FPGAs.
Supported platforms: Alveo U50, U55C, U200, U250, U280, Versal VCK5000.
Running Synthesis
cd hw/syn/xilinx/xrt
# Build a 4-core design for U280
PREFIX=build_4c NUM_CORES=4 TARGET=hw \
PLATFORM=xilinx_u280_gen3x16_xdma_1_202310_1 \
CONFIGS="-DVX_CFG_L2_ENABLE -DVX_CFG_DCACHE_SIZE=8192" \
make > build.log 2>&1 &
Key variables:
| Variable | Default | Description |
|---|---|---|
PREFIX | build$(XLEN) | Build directory prefix |
TARGET | hw | hw for hardware, hw_emu for emulation |
PLATFORM | (required) | Xilinx platform identifier |
NUM_CORES | - | Shorthand for core configuration |
CONFIGS | - | Additional design macros |
MAX_JOBS | 8 | Parallel Vivado jobs |
Power Analysis
make power SAIF_FILE=/path/to/trace.saif SAIF_INST=TOP.vortex_afu_shim.vortex_afu BUILD_DIR=<build_dir>
The script (hw/scripts/xilinx_power_analysis.tcl) resolves the post-implementation checkpoint from BUILD_DIR automatically.
Where to Find Reports
XRT flow (under <BUILD_DIR>/):
| Report | Location | Content |
|---|---|---|
| Utilization | <BUILD_DIR>/bin/utilization.rpt | LUTs, FFs, BRAM, DSP |
| Timing | <BUILD_DIR>/bin/timing.rpt | Worst setup paths |
| Power (vectorless) | power_vectorless.rpt | Baseline power estimate |
| Power (SAIF) | power_saif.rpt | Activity-annotated power |
DUT flow (under <target>/<BUILD_DIR>/):
| Report | Location | Content |
|---|---|---|
| Post-synth utilization | post_synth_util.rpt | Hierarchical resource usage |
| Post-impl utilization | post_impl_util.rpt | Hierarchical resource usage after P&R |
| Timing | timing.rpt | 100 worst setup paths |
| Methodology | methodology.rpt | Design rule checks |
| Clock utilization | clock_utilization.rpt | Clock tree and register usage |
| RAM utilization | ram_utilization.rpt | Detailed RAM/BRAM usage |
| Power (vectorless) | power_vectorless.rpt | Baseline power |
| Power (VCD) | power_vcd.rpt | VCD-annotated power (if VCD_FILE set) |
| Power (SAIF) | power_saif.rpt | SAIF-annotated power (via make power) |
| DRC | drc.rpt | Design rule violations |
| High fanout nets | high_fanout_nets.rpt | Nets with >100 fanout |
Finding Key Metrics
- Fmax: Look in
timing.rptfor the worst negative slack (WNS). Fmax = 1 / (clock_period - WNS). - Total LUTs: In
post_impl_util.rpt, find the row forCLB LUTsorSlice LUTs. - Total DSPs: In
post_impl_util.rpt, find the row forDSPsorDSP48E2. - Total BRAM: In
post_impl_util.rpt, find the row forBlock RAM TileorRAMB36/RAMB18.
Altera (Quartus)
OPAE Full-Platform Flow
Located in hw/syn/altera/opae/. Builds AFU images for Intel OPAE platforms (Arria 10, Stratix 10).
Running Synthesis
cd hw/syn/altera/opae
# Full build: IP generation, setup, and synthesis
DEVICE_FAMILY=arria10 PREFIX=build_4c NUM_CORES=4 TARGET=fpga make
# For ASE simulation build
DEVICE_FAMILY=stratix10 TARGET=asesim make
Key variables:
| Variable | Default | Description |
|---|---|---|
DEVICE_FAMILY | arria10 | arria10 or stratix10 |
PREFIX | build$(XLEN) | Build directory prefix |
TARGET | fpga | fpga, asesim, or ase |
NUM_CORES | - | Shorthand for core configuration |
CONFIGS | - | Additional design macros |
Build directory: <PREFIX>_<device_family>_<target>_<num_cores>c/.
Power Analysis
Altera power analysis uses Quartus PowerPlay with VCD-based toggle annotation:
# Located in hw/syn/altera/power_play.sh
quartus_pow --input_vcd=trace.vcd \
--vcd_filter_glitches=on \
--default_input_io_toggle_rate=10000transitions/s \
$ProjectName
Where to Find Reports
Reports are generated in the synthesis build directory by the Quartus report scripts.
Area reports (from report_area.tcl):
| Report | Content |
|---|---|
*.syn.area.resource_summary.csv | Synthesis resource summary |
*.syn.area.resource_breakdown.csv | Resource breakdown by entity |
*.syn.area.ram_summary.csv | Synthesis RAM summary |
*.syn.area.stats.csv | Post-synthesis netlist statistics |
*.fit.area.resource_summary.csv | Fitter resource summary (post-P&R) |
*.fit.area.resource_breakdown.csv | Fitter resource breakdown by entity |
*.fit.area.ram_summary.csv | Fitter RAM summary |
*.fit.area.routing_summary.csv | Routing utilization |
*.fit.area.routing_global.csv | Global signal routing |
*.fit.area.routing_high_fanout.csv | High fanout signal routing |
Timing reports (from analyze_timing.tcl):
| Report | Content |
|---|---|
*.fit.timing.summary.txt | Summary with Fmax, setup/hold, clock summary |
*.fit.timing.setup.html | Top 200 setup violation paths (with routing) |
*.fit.timing.hold.html | Top 200 hold violation paths |
*.fit.timing.recovery.html | Recovery timing paths |
*.fit.timing.removal.html | Removal timing paths |
*.fit.timing.check_errors.html | Timing DRC (no clock, multiple clock, loops) |
*.fit.timing.check_metastability.html | Metastability report |
*.fit.timing_histogram.*.setup.html | Per-clock setup slack histograms |
*.fit.timing.setup.bottlenecks.txt | Bottleneck analysis (TNS, fanout, fanin) |
*.fit.timing.summary.fmax.csv | Fmax summary (CSV) |
*.fit.timing.summary.setup.csv | Setup summary (CSV) |
*.fit.timing.summary.hold.csv | Hold summary (CSV) |
*.fit.timing.summary.multicorner.csv | Multi-corner timing summary |
Finding Key Metrics
- Fmax: Open
*.fit.timing.summary.txtor*.fit.timing.summary.fmax.csv. The Fmax summary reports the restricted Fmax for each clock domain. - Total ALMs/LUTs: In
*.fit.area.resource_summary.csv, look forALMs needed(Stratix 10) orLogic utilization(Arria 10). - Total DSPs: In
*.fit.area.resource_summary.csv, look for theDSProw. - Total BRAM (M20K/M10K): In
*.fit.area.resource_summary.csv, look forM20K blocksorM10K blocks. Also see*.fit.area.ram_summary.csvfor detailed RAM usage by entity.
Yosys (Open-Source)
Located in hw/syn/yosys/. Uses Yosys/ABC for technology mapping and OpenSTA for pre-layout timing and power analysis. ASAP7 7.5-track v28 is the default PDK; NanGate45 remains available as a legacy option.
Running Synthesis
# First use installs the selected, pinned ASAP7 Liberty files automatically.
# Synthesis only (generic gates)
make -C build/hw/syn/yosys PREFIX=test NUM_CORES=1 synthesis
# Explicit legacy library selection
make -C build/hw/syn/yosys PREFIX=test NUM_CORES=1 PDK=nangate45 timing
# Synthesis + technology mapping
make -C build/hw/syn/yosys PREFIX=test NUM_CORES=1 techmap
# Full flow: synthesis + mapping + STA + power
make -C build/hw/syn/yosys PREFIX=test NUM_CORES=1 SAIF_FILE=/path/to/trace.saif SAIF_INST=<inst> timing
Key variables:
| Variable | Default | Description |
|---|---|---|
PREFIX | build | Build directory prefix |
TOP_LEVEL_ENTITY | Vortex | Top module name |
NUM_CORES | - | Shorthand for core configuration |
CONFIGS | - | Additional design macros |
CLOCK_FREQ | 800 | Target clock frequency in MHz |
DELAY_UNC | 0.02 | Clock uncertainty (fraction of period) |
DELAY_IO | 0.05 | I/O delay (fraction of period) |
ABC_DRIVER_CELL | ASAP7 RVT: BUFx4_ASAP7_75t_R | Input driver cell used by ABC for buffering and sizing |
ABC_LOAD | ASAP7: 5.0 | ABC primary-output load in fF |
YOSYS_FLATTEN | 1 | Flatten hierarchy before technology mapping for better cross-module optimization |
YOSYS_SHARE | 1 | Enable Yosys resource sharing before mapping; set to 0 to disable |
PDK | asap7 | asap7 or the legacy nangate45 library |
ASAP7_VT | rvt | ASAP7 threshold-voltage library: rvt or lvt |
CORNER | tt | ASAP7 tt, ss, or ff NLDM corner |
LIB_TGT | selected by PDK | Explicit custom Liberty override |
SAIF_FILE | - | SAIF file for power annotation |
SAIF_INST | top module | OpenSTA SAIF scope override |
DUT_FILELIST | - | VCS-style filelist for an arbitrary DUT |
SDC_FILE | project.sdc | Clock, reset, and I/O constraints |
Example synthesizing a TFR FEDP unit with FP8 and MX enabled with ASAP7 RVT at the default 800 MHz:
make -C build/hw/syn/yosys timing TOP_LEVEL_ENTITY=VX_tcu_fedp_tfr PREFIX=tfr_fedp CORNER=tt EXTRA_CONFIGS='-DVX_CFG_EXT_TCU_ENABLE -DVX_CFG_TCU_TYPE_TFR -DVX_CFG_NUM_THREADS=32 -DVX_CFG_TCU_FEDP_FP8_ENABLE -DVX_CFG_TCU_MX_ENABLE'
Output reports are written to build/hw/syn/yosys/tfr_fedp_VX_tcu_fedp_tfr/reports/
Build directory: <PREFIX>_<TOP_LEVEL_ENTITY>/ (e.g., test_Vortex/).
The flow uses sv2v to convert SystemVerilog sources to Verilog before feeding them to Yosys.
Per-DUT synthesis
The DUTs above are declared once, in hw/syn/yosys/dut/catalog.mk — a top module, an include path and a define set each — and driven through one dispatcher, so a hand run and the asic_gate (below) build the same thing:
make -C build/hw/syn/yosys/dut list # what is available
make -C build/hw/syn/yosys/dut om # synthesis + STA (TARGET=timing)
make -C build/hw/syn/yosys/dut tcu TARGET=synthesis # synthesis only
make -C build/hw/syn/yosys/dut om CLOCK_FREQ=500 # override the target clock
PREFIX defaults to the DUT name, so each DUT gets its own tree. That is not cosmetic: the flow caches $(BUILD_DIR)/src and does not regenerate it when EXTRA_INCLUDE changes, so two DUTs sharing one tree silently synthesize the first one's sources. Override PREFIX to keep an automated sweep away from a hand-run build of the same DUT.
Synthesis-regression gate (asic_gate)
ci/asic_gate.py runs that catalog against checked-in goldens in ci/baselines/synthesis/yosys/ and fails on a Fmax or cell-area move beyond ±5%. It is the ASIC sibling of ci/fpga_gate.py and shares its implementation (ci/synth_gate.py).
ci/asic_gate.py --list # builds and their recorded baselines
ci/asic_gate.py -b om -b tex # gate two builds
ci/asic_gate.py --update-baseline # re-record (human-reviewed, never in CI)
Two things about Fmax on this flow are worth knowing before reading a number. ABC maps to the target period and stops, so a design that closes does so with picoseconds of margin and its Fmax sits just above CLOCK_FREQ by construction — cell area is the sensitive metric, and Fmax is mostly a met/missed signal. And report_wns is worst negative slack, clamped at zero: run_sta.tcl uses report_worst_slack (signed) for exactly this reason, which is what worst_slack.rpt holds.
See docs/designs/continuous_integration.md §3.5 and §4.5.
The first ASAP7 invocation runs the generated build/hw/syn/libs/asap7/install.sh installer. It downloads and SHA-256 verifies only the selected VT's five logical groups (INVBUF, SIMPLE, AO, OA, and SEQ) at TT, SS, and FF, then writes the merged Liberty files to build/hw/syn/libs/asap7/lib/. Gate-level simulation additionally installs the selected functional Verilog models in build/hw/syn/libs/asap7/verilog/. Later invocations verify the installed files and skip the download and preparation. The pin manifest, installer, preparation script, and upstream license are versioned in hw/syn/libs/asap7/, alongside the other standard-cell collateral; configure instantiates only install.sh.in into the build tree, and it reads the manifest and preparation script from the source tree in place. No ASAP7 collateral is kept under third_party/, and the flow requires no OpenROAD executable or physical collateral.
Threshold-Voltage Selection
RVT is the default because it is the appropriate general-purpose implementation library. Use LVT to establish a timing-focused bound or when a design does not meet its target with RVT:
make -C build/hw/syn/yosys timing ASAP7_VT=lvt CLOCK_FREQ=1000
Arbitrary DUT and Gate-Level SAIF
An arbitrary Verilog DUT can bypass Vortex source generation with its own top, filelist, and SDC. Filelists may contain RTL files, -f, +incdir+, and +define+ entries.
make -C build/hw/syn/yosys timing TOP_LEVEL_ENTITY=my_dut \
DUT_FILELIST=/absolute/path/to/dut.f \
SDC_FILE=/absolute/path/to/dut.sdc PREFIX=my_dut
For gate-level simulation, provide a Verilator-compatible testbench filelist. The testbench must instantiate the mapped DUT (the default instance name is dut) and call $dumpfile("gate_raw.saif") plus $dumpvars. SIM_ARGS, GATE_SIM_FLAGS, TB_TOP, and GATE_DUT_INSTANCE are available for testbench-specific needs.
make -C build/hw/syn/yosys gate-saif TOP_LEVEL_ENTITY=my_dut \
DUT_FILELIST=/absolute/path/to/dut.f \
SDC_FILE=/absolute/path/to/dut.sdc \
TB_FILELIST=/absolute/path/to/tb.f SIM_ARGS="+seed=1"
make -C build/hw/syn/yosys timing TOP_LEVEL_ENTITY=my_dut \
DUT_FILELIST=/absolute/path/to/dut.f \
SDC_FILE=/absolute/path/to/dut.sdc \
SAIF_FILE=$PWD/build_my_dut/gate.saif
The gate simulation traces Yosys-generated underscore nets and retains the complete mapped-cell hierarchy before re-rooting the DUT SAIF scope. OpenSTA writes annotated and unannotated pin reports and treats a requested SAIF with zero coverage as an error.
SRAM Area Estimation
Yosys uses blackbox modules (VX_dp_ram_asic, VX_sp_ram_asic) for SRAM. The sram_cost.py script estimates SRAM area from the Yosys JSON netlist by inferring width and depth from port connectivity:
Area = (width x depth x SRAM_BIT_AREA) + SRAM_OVERHEAD
Defaults: SRAM_BIT_AREA=0.1 um^2/bit, SRAM_OVERHEAD=100.0 um^2. These can be overridden via environment variables.
Where to Find Reports
All reports are under <BUILD_DIR>/reports/:
| Report | Content |
|---|---|
yosys.log | Full Yosys synthesis log |
stat_lib.rpt | Cell count and area (post-mapping, by liberty cell type) |
sram_area.rpt | Estimated SRAM area breakdown |
sta.log | OpenSTA timing log |
setup.rpt / hold.rpt | Detailed setup and hold paths |
wns.rpt / tns.rpt | Worst and total negative slack (clamped at 0 when timing closes) |
worst_slack.rpt | Worst slack, signed — positive when the design closes with margin |
synth_summary.csv | One-row machine-readable summary of all of the above (synth_summary.py) |
power.rpt | Power estimate (vectorless or SAIF-annotated) |
power_hier.rpt | Hierarchical power breakdown |
saif_annotated.rpt | Pins covered by SAIF |
saif_unannotated.rpt | Signals not covered by SAIF |
Netlists are written to <BUILD_DIR>/out/:
| File | Content |
|---|---|
<TOP>_syn.v | Post-synthesis generic netlist |
<TOP>_mapped.v | Post-mapping technology netlist |
<TOP>.json | Yosys JSON netlist (used by sram_cost.py) |
Finding Key Metrics
- Total area: In
stat_lib.rpt, look forChip area for top module. Add the estimated SRAM area fromsram_area.rptfor the total. - Cell count: In
stat_lib.rpt, the per-cell-type breakdown shows gate counts. - Timing (WNS/TNS): In
sta.log, look for thereport_wnsandreport_tnsoutputs. Fmax = 1 / (target_period - WNS). - Power: In
power.rpt, look for total power.power_hier.rptbreaks it down by hierarchy.
Synopsys Design Compiler
Located in hw/syn/synopsys/. Uses Synopsys DC for ASIC synthesis with support for multiple technology libraries.
Supported Libraries
| LIB_TYPE | Technology | Path |
|---|---|---|
DEFAULT | NanGate 15nm OCL | Bundled in hw/syn/libs/ |
ASAP7 | ASAP7 7nm | /mnt/nas0/eda.libs/asap7/asap7sc7p5t_28/LIB/NLDM |
SAED14 | SAED 14nm SLVT | /mnt/nas0/eda.libs/saed14/EDK_03_2025 |
Running Synthesis
cd hw/syn/synopsys
# Default library, 1 core
PREFIX=test make synthesis
# ASAP7 library, 4 cores, with SAIF power
PREFIX=test NUM_CORES=4 LIB_TYPE=ASAP7 \
SAIF_FILE=/path/to/trace.saif SAIF_INST=<inst> \
make synthesis
# Synthesis without SRAM macros (blackbox)
PREFIX=test make synthesis-nosram
# Synthesis with estimated SRAM area
PREFIX=test make synthesis-estsram
Key variables:
| Variable | Default | Description |
|---|---|---|
PREFIX | build | Build directory prefix |
TOP_LEVEL_ENTITY | Vortex | Top module name |
NUM_CORES | - | Shorthand for core configuration |
CONFIGS | - | Additional design macros |
CLOCK_FREQ | 800 | Target frequency in MHz |
DELAY_UNC | 0.02 | Clock uncertainty (fraction of period) |
DELAY_IO | 0.05 | I/O delay (fraction of period) |
LIB_TYPE | DEFAULT | Technology library selection |
SAIF_FILE | - | SAIF file for power annotation |
SAIF_INST | - | Instance path prefix in SAIF |
Build directory: <PREFIX>_<TOP_LEVEL_ENTITY>/ (e.g., test_Vortex/).
Synthesis Variants
synthesis: Full synthesis with generated SRAM wrappers from the technology library's SRAM.dbfiles. Requires the library to provide SRAM models.synthesis-nosram: Synthesis without any SRAM logic. RAM modules are inferred by DC.synthesis-estsram: BlackboxesVX_dp_ram_asicandVX_sp_ram_asic, then estimates their area from port dimensions (same approach as Yosys).
Where to Find Reports
All reports are under <BUILD_DIR>/reports/:
| Report | Content |
|---|---|
area.rpt | Hierarchical area breakdown |
qor.rpt | Quality of Results summary (area, timing, utilization) |
timing_max.rpt | Setup timing (50 worst paths, with nets/transitions/capacitance) |
timing_min.rpt | Hold timing (50 worst paths) |
clock_skew.rpt | Clock skew analysis |
constraints_violators.rpt | All constraint violations |
check_design.rpt | Pre-synthesis design checks |
power_active.rpt | SAIF-annotated hierarchical power (if SAIF_FILE provided) |
power_vectorless.rpt | Vectorless power estimate (if no SAIF_FILE) |
saif_annotation_coverage.rpt | SAIF annotation coverage statistics |
Outputs are under <BUILD_DIR>/out/:
| File | Content |
|---|---|
<TOP>.mapped.ddc | Synopsys binary netlist |
<TOP>.mapped.v | Mapped gate-level Verilog |
<TOP>.mapped.sdf | Standard Delay Format for back-annotation |
<TOP>.post_compile.sdc | Post-compile timing constraints |
Finding Key Metrics
- Total area: In
area.rpt, look for the top-levelTotal cell area. The SRAM estimated area (if usingsynthesis-estsram) is printed in the build log asTotal Estimated SRAM Area. - Timing / Fmax: In
timing_max.rpt, the slack of the first path gives the worst negative slack (WNS). Fmax = 1 / (target_period - WNS). Also checkqor.rptfor a summary. - Power: In
power_active.rpt(with SAIF) orpower_vectorless.rpt(without), the hierarchical breakdown shows internal, switching, and leakage power per module. - Gate count: In
qor.rpt, look forDesign AreaandNumber of cells.
Understanding Power Reports
Power reports across all flows break down total power into similar categories. Understanding these helps identify optimization targets.
Power Components
| Component | Description |
|---|---|
| Dynamic power | Power consumed by signal switching activity |
| Internal | Short-circuit current during output transitions within cells |
| Switching | Charging/discharging of interconnect and load capacitances |
| Static (leakage) power | Power consumed even when signals are not switching; due to sub-threshold and gate leakage currents |
Total Power = Dynamic (Internal + Switching) + Static (Leakage)
Vectorless vs. Activity-Annotated
- Vectorless: The tool assumes a default toggle rate (typically 12.5%) and static probability (0.5) for all signals. Provides a rough baseline but can significantly over- or under-estimate actual power.
- SAIF/VCD-annotated: Uses real switching activity captured during simulation. Much more accurate for the specific workload simulated. Signals not covered by the SAIF/VCD fall back to the default toggle rate.
Always compare the vectorless and annotated reports to understand which modules differ most from the default assumption.
Tips
- Run a representative workload when generating SAIF files. Short or trivial tests will underestimate steady-state power.
- Check SAIF annotation coverage reports (
saif_annotation_coverage.rptin Synopsys,saif_unannotated.rptin Yosys) to ensure good signal coverage. - For Xilinx, the power report includes device-specific contributions (clocking, I/O, BRAM, DSP power) that are not present in ASIC flows.
- For hierarchical analysis, look at per-module power breakdowns to identify the most power-hungry blocks (e.g., caches, FPU, TCU).