SystemVerilog · Module 17
config & Library Mapping
SystemVerilog config blocks and library mapping — select which implementation of each module elaborates without editing the design. Library map files, the design / default liblist / instance / cell clauses, the four resolution rules, RTL-vs-GLS and corner switching, encrypted-IP integration, nested config, and config vs filelist.
Module 17 · Page 17.5
A real design has many implementations of the same module: a behavioral RTL model, a synthesized gate-level netlist, a fast-corner cell, a slow-corner cell, a vendor's encrypted IP. The config construct (with library mapping) is how you choose which implementation elaborates for each module — without editing a single design file. You declare named libraries (collections of files) in a map file, then write a config block that names the design root, a default library search order, and per-cell or per-instance overrides. Switching from RTL simulation to gate-level simulation (GLS), or from one timing corner to another, becomes a one-line change of which config you elaborate. This lesson covers library map files, the config clauses, the four resolution rules, the canonical RTL↔GLS and encrypted-IP flows, and config vs the familiar filelist.
1. Engineering Problem — One Design, Many Implementations
The same sram_4k exists three ways: a fast behavioral model for RTL regressions, the real vendor cell for GLS, and a slow-corner variant for hold checking. The same SoC must simulate in RTL mode today and gate-level mode tomorrow, against the same testbench. A third-party pll_core ships only as an encrypted netlist you can't read but must instantiate.
The crude approach — maintain a separate filelist per scenario and hand-swap files, or `ifdef the instantiations — does not scale: it cannot override one specific instance, it cannot swap all instances of a cell type at once, and every change edits design or build files that then drift. config solves this at the elaboration layer: the design source never changes; a small configuration block declares which library serves each module, with precise per-instance and per-cell overrides. One netlist, one testbench, many elaborations — selected by which config you point the simulator at.
2. Mental Model — Libraries Are Collections, config Is a Routing Table
The picture every engineer carries:
A library is a named collection of source files (declared in a map file with a glob pattern). A
configis a routing table that tells the elaborator, for every module reference it encounters: which library to look in first (default liblist), and which specific cells or instances to source from a different library (cell/instanceoverrides). The design root is named once (design lib.top), and you select a config at the command line (-top my_config). The design files themselves never mention libraries or configs — the mapping lives entirely outside them.
Four invariants this picture preserves:
- Zero design edits. Switching RTL↔GLS, corners, or IP versions changes only the config you elaborate — never a line of RTL or netlist.
- Resolution has a strict priority.
instanceoverride beatscelloverride beatsdefault liblist(searched left-to-right), with the implicitworklibrary as the final fallback. workis always there. Every simulator has a built-inworklibrary; files compiled without an explicit library land there.- It is an elaboration-time construct.
configchooses implementations; it produces no logic and is invisible to synthesis. It is the build-selection layer, not part of the design.
3. Visual Explanation — Libraries Feed a config That Resolves the Design
Named libraries point at files on disk; the config picks which one serves each module and elaborates the design from them.
4. Declaring Libraries — the Library Map File
Libraries are declared in a library map file (a .map/.f file; exact extension varies by simulator). The library keyword names a collection and binds it to one or more file glob patterns.
// design.map — library declarations
// Syntax: library <name> "glob" [, "glob2", ...];
// The implicit working library — where the top-level testbench lives
library work "./tb/*.sv", "./tb/top.sv";
// RTL source — functional, synthesizable
library rtl_lib "./rtl/*.sv", "./rtl/mem/*.sv", "./rtl/core/*.sv";
// Gate-level netlist + vendor cell models (incl. encrypted .vg)
library gate_lib "./netlist/top_netlist.v", "./pdk/tsmc28/cells/*.v", "./ip/encrypted/*.vg";
// Corner libraries — for hold (slow) and setup (fast) checking
library slow_lib "./pdk/tsmc28/slow/*.v";
library fast_lib "./pdk/tsmc28/fast/*.v";5. The config Construct
A config is a top-level block (like a module) that names the design root, a default library search order, and any overrides. You write one per simulation scenario — one for RTL, one for GLS, one per corner.
config rtl_sim_cfg; // configuration name
design work.top_tb; // top-level design root: lib.module
default liblist rtl_lib work; // search rtl_lib first, then work
instance top_tb.u_dut.u_sram use rtl_lib.sram_behavioral; // one exact instance
cell dff_x1 use gate_lib.dff_x1; // every instance of this cell type
endconfig
// A second config for GLS — same testbench, different libraries (no design edits)
config gls_cfg;
design work.top_tb;
default liblist gate_lib work;
instance top_tb.u_dut.u_sram use gate_lib.tsmc_sram_4k;
endconfigReading the clauses: config <name> … endconfig declares the block (activated with -top <name>); design lib.module sets the root the elaborator starts from; default liblist L1 L2 … is the ordered search path for any unoverridden reference; instance <path> use lib.cell overrides exactly one hierarchical instance (the most precise override); cell <type> use lib.cell overrides every instance of a module type at once.
6. The Four Resolution Rules
When the elaborator hits a module instantiation, it resolves the implementation in strict priority order — and getting this order wrong is the root of most config bugs.
instancerule (highest). Ainstance <exact path> use …override always wins for that one instance.cellrule. Acell <type> use …override applies to all instances of that module type.default liblist. Search each library left-to-right; the first one containing a module of the matching name wins.workfallback. No match in the liblist → try the implicitworklibrary. Still nothing → elaboration fails with "module not found."
config priority_demo;
design work.top;
default liblist rtl_lib work; // Rule 3
cell dff use gate_lib.dff; // Rule 2 — all dff instances
// instance top.u_core.u_setup_reg.u_dff use slow_lib.dff; // Rule 1 — one instance
endconfig
// Resolution for each module in top:
// top → work.top (design root)
// u_alu → rtl_lib.alu (Rule 3 — default liblist)
// u_sram → rtl_lib.sram (Rule 3)
// u_dff[*] → gate_lib.dff (Rule 2 — cell override)
// u_setup_reg.u_dff → slow_lib.dff (Rule 1 — instance override, if uncommented)7. Use Cases
7.1 RTL ↔ GLS switch (the most common)
Two configs, same testbench; pick the mode with one flag.
config rtl_cfg; // RTL functional sim
design work.chip_tb;
default liblist rtl_lib work;
cell sram_4k use models_lib.sram_behavioral; // fast behavioral SRAM
endconfig
config gls_cfg; // gate-level sim (netlist + SDF)
design work.chip_tb;
default liblist gate_lib work; // gate_lib FIRST — see §10 mistake 2
cell sram_4k use gate_lib.tsmc_sram_4k; // real vendor SRAM
endconfig# VCS — select the config with -top; only -top changes between modes
vcs -sverilog -f design.map sim_configs.sv -top rtl_cfg -o sim_rtl
vcs -sverilog -f design.map sim_configs.sv -top gls_cfg \
-sdf max:chip_tb.u_dut:chip.sdf -o sim_gls
# Questa
vlog -sv -mfcu sim_configs.sv ./rtl/*.sv ./gate/*.v
vsim -c gls_cfg -do "run -all; quit"
# Xcelium
xrun -sv -libmap design.map -top gls_cfg ./tb/*.sv ./gate/*.v$ vcs -f design.map sim_configs.sv -top gls_cfg -o sim_gls
Config: gls_cfg (activated) design root: work.chip_tb default libs: gate_lib work
Resolving chip_tb ... work.chip_tb [work]
Resolving alu ... gate_lib.alu [default liblist]
Resolving sram_4k ... gate_lib.tsmc_sram_4k [cell override]
Elaboration complete. 847 modules resolved.7.2 Encrypted-IP integration
Third-party IP often ships as an encrypted netlist you can't read or edit but must simulate. Map just those module names to the vendor library; everything else stays in your RTL.
// design.map: library vendor_ip "./vendor/encrypted/*.vg";
config rtl_with_vendor_ip;
design work.tb_top;
default liblist rtl_lib work; // your own RTL by default
cell pll_core use vendor_ip.pll_core; // map IP names → encrypted models
cell usb_phy use vendor_ip.usb_phy;
cell serdes_x4 use vendor_ip.serdes_x4;
endconfig7.3 Nested config
A cell clause can point at another config instead of a module, letting a sub-team own their block's mapping.
config cpu_core_cfg; // owned by the CPU team
design rtl_lib.cpu_core;
default liblist rtl_lib;
cell multiplier use opt_lib.fast_mul;
endconfig
config soc_cfg;
design work.soc_tb;
default liblist rtl_lib work;
cell cpu_core use work.cpu_core_cfg; // points at a CONFIG, not a module
endconfig8. config vs Filelist
Both compile files; they solve different problems.
| Aspect | Filelist (-f filelist.f) | config construct |
|---|---|---|
| Switching implementations | Separate filelist per scenario, hand-swapped | Single source, select by -top config_name |
| Per-instance override | Not possible without editing design files | instance clause — precise, path-based |
| Per-cell-type override | Not possible without editing instantiations | cell clause — swaps all instances at once |
| Encrypted IP | Works (point at the .vg) | Works (dedicated library) |
| Complexity | Simple — everyone understands it | Higher — needs libraries + resolution order |
| Best for | Single-mode RTL flows | Multi-mode: RTL + GLS + corners, IP integration |
In practice most teams use filelists for day-to-day RTL and switch to config for multi-corner GLS or encrypted-IP integration. They compose — you can use both together.
9. Industry Usage — Where config Shows Up
- RTL → GLS sign-off. One testbench, two configs (
rtl_cfg,gls_cfg) — the standard way to reuse the verification environment across abstraction levels. - Multi-corner GLS.
gls_slow_cfg(hold, min delays) andgls_fast_cfg(setup, max delays) select corner cell libraries vialiblistorder — pairs directly with the SDF corners from the previous lesson. - Encrypted / third-party IP. Map vendor IP module names to encrypted libraries while the rest of the design stays in source.
- Mixed-abstraction simulation. Keep most of the chip in fast RTL and elaborate only the block-under-test at gate level — an
instance/celloverride picks exactly which. - A/B model comparison. Swap one block between two implementations (behavioral vs cycle-accurate) by changing a single
cell/instanceclause.
config is elaboration-time only — it selects implementations and produces no logic; synthesis never sees it.
10. Debugging Guide — The Mistakes Everyone Makes Once
config & library mapping — bugs every engineer hits the first time
Symptom: A library "exists" but every lookup in it fails with a confusing "module not found."
Cause: The glob pattern doesn't match real files — e.g. "./RTL/*.sv" on a case-sensitive Linux filesystem where the directory is rtl. The library is defined but empty.
library rtl_lib "./RTL/*.sv"; // ❌ directory is ./rtl — zero files matchedFix: verify the glob in a shell first (ls ./rtl/*.sv); mind case sensitivity; use absolute paths while debugging.
Guardrail: a defined-but-empty library is the silent failure mode — confirm file counts before wiring the map.
Symptom: GLS "runs" but behaves like RTL; timing checks never fire.
Cause: default liblist rtl_lib gate_lib; finds the RTL version of every cell first (same names), so gate_lib is never reached. Same names, wrong models, no error.
config gls_cfg; default liblist rtl_lib gate_lib; ... endconfig // ❌ RTL winsFix: for GLS put the gate library first — default liblist gate_lib work; — with RTL only as a fallback for testbench helpers. Verify the elaboration trace shows gate-level names.
Guardrail: liblist is left-to-right priority; the intended implementation must come first.
Symptom: Simulation finishes at time 0 with no output.
Cause: design rtl_lib.dut_top; elaborates the DUT with no stimulus driving it.
Fix: point design at the top-level simulation module (the testbench in work): design work.tb_top;. The testbench instantiates the DUT, which resolves through the liblist.
Guardrail: the design root is the thing you'd pass to -top in a normal sim — the testbench, not the DUT.
Symptom: An instance override silently does nothing.
Cause: The path uses the module type name instead of the instance name. For cpu_core u_cpu_core(...), the path segment is u_cpu_core, not cpu_core.
instance top.cpu_core.alu use fast_lib.alu; // ❌ module names; instance is u_cpu_core/u_aluFix: use instance names from the instantiations: instance top.u_cpu_core.u_alu use fast_lib.alu;.
Guardrail: hierarchical paths are built from instance identifiers (the left name in type u_name(...)), never module type names.
11. Q & A
12. Cross-References & What's Next
This lesson covered library mapping and the config construct — declaring libraries, the design/liblist/instance/cell clauses, the four resolution rules, and the RTL↔GLS / encrypted-IP / nested patterns.
- Previous: 17.4 — Specify Blocks & Path Delays — the timing models
configselects between RTL and gate-level libraries; corner libraries pair with SDF corners. - Module index: Module 17 — Advanced Topics — the advanced-feature arc.
Related material elsewhere in the curriculum:
- Package Dependencies & Compilation Order — the other build-discipline lesson;
configselects which implementation, the file list controls order. - The bind Construct — another non-invasive, build-time mechanism that attaches to a design without editing it.
13. Quick Reference
// ── Library map file (design.map) ───────────────────────────────────
library work "./tb/*.sv";
library rtl_lib "./rtl/*.sv", "./rtl/sub/*.sv";
library gate_lib "./netlist/*.v", "./cells/*.v";
library slow_lib "./cells_slow/*.v";
// ── config block (sim_configs.sv) ───────────────────────────────────
config my_config;
design work.tb_top; // top-level design root
default liblist rtl_lib work; // search order (left-to-right)
cell sram_model use gate_lib.tsmc_sram; // all instances of this type
instance tb_top.u_dut.u_pll use gate_lib.pll_ip; // one exact instance (highest)
cell cpu_core use work.cpu_core_cfg; // nested config
endconfig
// Resolution priority: instance > cell > default liblist > work
// ── Activate ────────────────────────────────────────────────────────
// VCS: vcs -sv -f design.map sim_configs.sv -top my_config -o sim
// Questa: vlog -sv -mfcu sim_configs.sv ; vsim -c my_config
// Xcelium: xrun -sv -libmap design.map sim_configs.sv -top my_config14. Summary
The config construct selects which implementation of each module elaborates, without editing the design. A library is a named file collection declared in a map file; a config is a routing table that names the design root (design lib.top), a default search order (default liblist), and overrides — cell for every instance of a type, instance for one exact path. The elaborator resolves each reference by strict priority: instance → cell → default liblist (left-to-right) → work fallback, erroring if nothing matches.
That mechanism makes the hard build scenarios one-line changes: RTL↔GLS by selecting -top rtl_cfg vs -top gls_cfg against the same testbench; multi-corner GLS by ordering corner libraries (pairing with the SDF min/max corners); encrypted-IP integration by mapping IP names to a vendor library; and sub-team ownership via nested configs. Put the intended library first in the liblist (gate_lib first for GLS), point design at the testbench (not the DUT), and build instance paths from instance names. Use filelists for simple RTL and layer config on for multi-mode flows — it is an elaboration-time selection layer, invisible to synthesis, that keeps one design source serving every simulation scenario.