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.
Continue learning
Related tutorials
- Related topic
Package Dependencies & Compilation Order
SystemVerilog package compilation order — why a package must be compiled before anything that imports it, the dependency graph as a DAG and its topological sort, circular-dependency detection and the shared-base-package fix, the export keyword and facade pattern for re-publishing nested imports, and the file-list, Makefile, and three-layer architecture that keep multi-package builds deterministic across VCS, Xcelium, and Questa.
- Related topic
The bind Construct
SystemVerilog bind — attach assertion and coverage checkers to RTL without editing the RTL. Binding to a module type vs a single instance, the .* and explicit port-connection forms, passing parameters through bind, the canonical FIFO-checker example, and bind vs direct instantiation. The non-intrusive way to verify code you do not own.
- Related topic
Direct Programming Interface (DPI-C)
SystemVerilog DPI-C — the standard interface for calling C/C++ from SystemVerilog and exposing SV back to C in the same simulator process. import vs export, the full SV↔C data-type mapping, the chandle type for C object lifetimes, pure vs context functions, a complete CRC-8 reference-model example, and the compile/link flow on VCS, Questa, and Xcelium.
Standards & specifications
- Governing standard
- IEEE Std 1800 (SystemVerilog)(opens IEEE in a new tab)
Defines SystemVerilog language semantics — syntax, data types, scheduling and the behaviour a conforming simulator must produce. It does not define tool-specific synthesis support or vendor methodology.
This page also covers RTL structure, verification approach and debugging technique. Those are engineering practice built on the standard, not requirements the standard itself imposes.
Where this fits
Part of the SystemVerilog curriculum.
