GLS · Chapter 2 · Netlists & Standard-Cell Libraries
Cell Simulation Models & UDPs
Gate-level simulation runs the Verilog simulation model of each standard cell, and understanding those models is what lets you reason about gate-level behaviour, especially unknown values. Simple combinational cells like an inverter or a NAND are modelled with Verilog gate primitives or a continuous assign. Complex and sequential cells, such as muxes, adders, flip-flops, and latches, are modelled with user-defined primitives: compact truth tables or state tables whose rows also define how the cell responds to unknown inputs. Those rows are the origin of X-pessimism, because a conservative model emits an unknown rather than guessing. The key idea is that the model, not the netlist, decides the unknown behaviour you see. This lesson dissects a representative UDP and shows how a functional-only model can hide an unknown that an accurate UDP would propagate.
Foundation13 min readGLSUDPCell ModelsX-propagationPrimitives
Chapter 2 · Section 2.3 · Netlists & Standard-Cell Libraries
Project thread — the flip-flop and gates that build the counter are, in GLS, whatever their cell models say they are. The DFF's UDP state table (here) is what will (or will not) let the counter recover from X at reset in 2.6.
1. Why Should I Learn This?
Gate-level X behaviour — the single most common source of GLS surprises — is decided by the cell models, not by the netlist. When a counter sits at X or an X propagates 'too far,' the answer is in the cell's UDP: its rows define what happens on unknown inputs, and a conservative UDP emits X rather than guessing (the root of X-pessimism, Chapter 6). If you do not know how cells are modelled, gate-level X looks like noise; once you do, it is readable.
This lesson turns the cells 2.2 defined into the behaviour GLS runs, and it underpins the rest of the chapter: 2.4 adds timing (specify) on top of these models, 2.5 adds sequential timing checks, and the counter of 2.6 lives or dies by its flop's UDP.
2. Real Silicon Story — the mux model that hid an X
A team debugging a gate-level X swaps in a 'cleaner' simulation model for a mux cell — one written functionally as assign Y = S ? B : A; instead of the library's UDP. The X on the output disappears, and they conclude the X was a modelling artifact and move on. Later, the same X reappears in a run using the accurate library models, and this time it traces to a real uninitialised select line.
The functional model hid the problem. With S ? B : A, an X on S picks a branch anyway (many simulators resolve X ? B : A toward a defined value or one branch), so the output looked clean. The library's UDP for that mux has an explicit row for S = X: if the two data inputs differ, the output is X — because the cell genuinely cannot know which input it selects when the control is unknown. That X was correct and informative — it was flagging an uninitialised select. The team had been misled because they changed the model, and the model — not the netlist — decides the X behaviour. The post-mortem lesson: GLS runs the cell's Verilog model, and for complex/sequential cells that model is a UDP whose rows define how the cell handles X; a functional-only shortcut can hide an X that an accurate UDP would propagate, so gate-level X must be reasoned about at the level of the cell models in use, not just the connectivity.
3. Concept — how cells are modelled, and where X-behaviour lives
GLS runs a Verilog simulation model for each cell. There are three common forms:
- Verilog gate primitives — simple combinational cells:
nand (Y, A, B);,not (Y, A);. Built-in VerilogX-handling. - Continuous
assign— simple combinational functions:assign Y = ~(A & B);. Inherits Verilog operatorX-semantics. - User-defined primitives (UDPs) — complex and all sequential cells: a compact truth table (combinational UDP) or state table (sequential UDP) listing the output for each input combination.
The UDP is where the important behaviour lives:
- A UDP row can name
Xand?(don't-care). The table explicitly defines the output for ambiguous/unknown inputs — this is where a cell'sX-handling is defined. - UDPs are usually conservative. When inputs are ambiguous, the row emits
Xrather than guessing — the origin of X-pessimism (a UDP may outputXwhere real silicon would settle to a value, Chapter 6). - Sequential UDPs carry state. The state table's left side includes the current output; edge inputs (e.g.
(01)= rising) model clocking — this is the flip-flop's model (timing checks come in 2.5). - The model, not the netlist, decides
X. Two models of the same cell (accurate UDP vs functional shortcut) behave differently onXfor an identical netlist.
Here is the anatomy of a cell simulation model:
4. Mental Model — the UDP is the cell's rulebook, and the X-rows are its 'I don't know' clauses
5. Working Example — a representative UDP (and the shortcut that hides X)
Here is a representative combinational UDP for a 2-to-1 mux, with the explicit X-handling row that makes it faithful.
// UDP for a 2:1 mux — REPRESENTATIVE (shape only; real library UDPs vary)
primitive MUX2_udp (Y, A, B, S);
output Y; input A, B, S;
table
// A B S : Y
0 ? 0 : 0 ; // S=0 -> pass A
1 ? 0 : 1 ;
? 0 1 : 0 ; // S=1 -> pass B
? 1 1 : 1 ;
0 0 x : 0 ; // S unknown but A==B -> output is still definite
1 1 x : 1 ;
0 1 x : x ; // S unknown AND A!=B -> genuinely undetermined -> X (the faithful row)
1 0 x : x ;
endtable
endprimitiveThe row 0 1 x : x is the point: when the select is X and the data inputs differ, the cell cannot know its output, so the UDP emits X. A functional shortcut has no such row:
// Functional shortcut for the SAME mux — HIDES the X on an unknown select
assign Y = S ? B : A; // X on S often resolves toward a branch -> output looks 'clean' -> ambiguity hiddenSame netlist, two models, different X-behaviour. And a sequential cell is a state table — the flip-flop that will hold the counter's value:
// Sequential UDP for a rising-edge DFF — REPRESENTATIVE (function only; timing checks come in 2.5)
primitive DFF_udp (Q, D, CK, RN);
output Q; input D, CK, RN; reg Q;
table
// D CK RN : Qcur : Qnext
? ? 0 : ? : 0 ; // active-low reset -> Q=0
0 (01) 1 : ? : 0 ; // rising CK -> capture D
1 (01) 1 : ? : 1 ;
? (?0) 1 : ? : - ; // falling/other CK edge -> hold ('-')
? b 1 : ? : - ; // steady CK -> hold
endtable
endprimitiveIts reset row (RN=0 → Q=0) is what a real netlist relies on to escape power-up X — the theme of 2.6.
6. Debugging Session — an X that vanishes when the cell model changes
A gate-level X disappears when a mux cell is modelled functionally (S ? B : A) instead of with its UDP — the model, not the netlist, was deciding the X, and the functional shortcut was hiding a real uninitialised select
THE MODEL DECIDES X — READ THE UDPA gate-level run shows an X on a mux output. An engineer swaps in a 'cleaner' functional model (assign Y = S ? B : A;) for that cell; the X disappears and the run looks healthy. Later, with the accurate library UDP, the same X returns — and traces to a real uninitialised select line.
The two models handle X differently, and the model — not the netlist — decides the X. The library's UDP for the mux has an explicit row for S = X with differing data inputs (0 1 x : x): the cell cannot determine its output when the select is unknown and the inputs disagree, so it faithfully emits X. That X was correct — it flagged a genuinely uninitialised select. The functional shortcut S ? B : A has no such clause: an X on S in a ?: expression often resolves toward some branch, so the output looked defined and the ambiguity was hidden. The netlist was identical in both runs; only the cell model changed, and with it the X-behaviour. This is the general shape of gate-level X debugging: the X is produced (or absorbed) inside the cell models, according to their UDP rows — so an X that changes when you change the model is telling you the model was governing it. It is not a netlist bug or a simulator bug; it is a modelling difference, and the accurate UDP was the correct one.
Use the accurate library cell models (the UDPs), not functional shortcuts, for GLS — the UDPs' X-rows are what make gate-level X faithful, and here the X was correctly flagging an uninitialised select to fix at the source (drive/reset the select). The lesson: GLS runs each cell's Verilog model; for complex/sequential cells that model is a UDP whose rows define the X-handling — so the model, not the netlist, decides gate-level X, and a functional shortcut can hide an X an accurate UDP would propagate. Two scope caveats: a representative UDP (like the one above) shows the shape, not the exact vendor model — use the real library models for signoff; and UDP X-handling is conservative — it may emit X where real silicon would settle to a value (X-pessimism, Chapter 6), so an X is a flag to investigate, not proof the hardware is broken.
7. Common Mistakes
- Debugging gate-level
Xfrom the netlist alone. TheXis produced inside the cell models — read the UDP rows of the cells it flows through. - Substituting functional shortcuts for library UDPs.
S ? B : Aand similar hideXthat an accurate UDP would propagate — use the real models. - Treating an
Xas proof of broken hardware. UDP X-handling is conservative (X-pessimism, Ch6) — anXis a flag to investigate, not a silicon verdict. - Assuming all cells are UDPs (or none are). Simple combinational cells use primitives/
assign; complex and all sequential cells use UDPs. - Taking a representative UDP as the exact model. Representative snippets show the shape; signoff uses the actual vendor models.
8. Industry Best Practices
- Use the accurate library cell models (UDPs) for GLS. Their
X-rows make gate-levelXfaithful — do not substitute functional shortcuts. - Debug gate-level
Xat the model level. Trace theXthrough the UDP rows of the cells it passes, not just the wiring. - Treat an
Xas a flag, not a verdict. UDP X-handling is conservative (X-pessimism, Ch6) — investigate the source; do not assume broken silicon. - Know which modelling form each cell uses. Primitives/
assignfor simple cells; UDPs (truth/state tables) for complex and sequential cells. - Keep representative and signoff models distinct. Representative UDPs teach the shape; use the real vendor models for actual runs.
Senior Engineer Thinking
- Beginner: "There's an
Xon this net — the netlist must be wrong." - Senior: "An
Xis produced inside a cell model. Which cell, and what does its UDP say for these inputs? If changing the model changes theX, the model was governing it — and the accurate UDP is usually the one telling the truth."
The senior debugs gate-level X at the level of cell models and UDP rows, and knows the model — not the netlist — decides X.
Silicon Impact
Getting cell models wrong cuts both ways. Hide X with functional shortcuts, and you mask real uninitialised logic — the uninitialised select or unreset flop reaches silicon and shows up as power-up-dependent, intermittent failures (the classic reset-gap escape, 2.6/Ch0). Over-trust a conservative UDP X, and you may chase X-pessimism 'bugs' that real silicon resolves electrically (Chapter 6), wasting debug effort or over-constraining the design. The discipline is to run accurate models (faithful X), then judge each X as a flag to investigate — real uninitialised state to fix at the source, versus pessimism to prove benign. That judgement — grounded in what the UDP actually says — is what keeps genuine X-bugs from taping out while not derailing on artifacts.
Engineering Checklist
- Used the accurate library cell models (UDPs), not functional shortcuts, for GLS.
- Debugged each gate-level
Xby reading the UDP rows of the cells it flows through. - Treated each
Xas a flag to investigate (real uninitialised state vs X-pessimism, Ch6) — not an automatic silicon verdict. - Knew the modelling form per cell (primitives/
assignvs UDP truth/state table). - Did not mistake a representative UDP for the exact vendor model.
Try Yourself
- Write the representative
MUX2_udpUDP above and instantiate it withSdriven to1'bxandA != B. - Observe: the output is
X— the faithful0 1 x : xrow firing (the cell cannot know its output). - Change: replace the instance with the functional
assign Y = S ? B : A;model and re-drive the sameXonS. - Expect: the output now looks defined — the shortcut hid the
X. Same netlist, different model, differentX-behaviour: proof the model decidesX.
Any Verilog simulator supports UDPs; no paid tool is required. Real library UDPs are vendor/PDK artifacts, but the truth/state-table mechanics and X-handling are identical to the representative snippet.
Interview Perspective
- Weak: "Each cell is just an
assignstatement for its logic function." - Good: "Simple cells use Verilog primitives or
assign; complex and sequential cells use UDPs — truth or state tables whose rows also define X-handling." - Senior: "GLS runs the cell's Verilog model, and the UDP's rows define the X-behaviour — the source of X-pessimism. The model, not the netlist, decides gate-level
X, so I debugXby reading the UDPs of the cells it flows through, using accurate models, and treating eachXas a flag to investigate rather than a silicon verdict."
9. Interview / Review Questions
10. Key Takeaways
- GLS runs each cell's Verilog simulation model (not the
.lib, 2.2): primitives /assignfor simple combinational cells; UDPs (truth table for combinational, state table for sequential) for complex and all sequential cells. - A UDP's rows define the cell's
X-handling — rows namingX/?— and are usually conservative ('unknown →X'), which is the origin of X-pessimism (Chapter 6): safe, sometimes over-cautious. - The model, not the netlist, decides
X. An accurate UDP and a functional shortcut (e.g. mux asS ? B : A) diverge onXfor an identical netlist — a shortcut can hide anXthe UDP would propagate. - Debug gate-level
Xat the model level — trace it through the UDP rows of the cells it flows through, using accurate models; treat eachXas a flag to investigate, not a silicon verdict. - A representative UDP shows the shape, not the exact vendor model; use the real models for signoff. Next: 2.4 — specify blocks & timing arcs layer timing on top of these models.
Quick Revision
GLS runs the cell's Verilog model. Simple cells = primitives/
assign; complex + sequential = UDPs (truth/state tables). The UDP's rows define X-handling (conservative 'unknown →X' = X-pessimism origin, Ch6). The model, not the netlist, decidesX— a functional shortcut (S ? B : A) can hide anXan accurate UDP propagates. DebugXby reading the UDP rows; treatXas a flag, not a verdict. Next: 2.4 — specify blocks & timing arcs.