Verilog · Chapter 5.1.4 · Data & Variables
trireg Nets in Verilog
A normal wire has no memory: when every driver releases, the net floats to Z. A trireg does have memory, so when every driver releases it retains its last driven value as if a real capacitor were holding the charge. That capacitor is physical, appearing in dynamic-CMOS gates, precharge and evaluate domino logic, charge-shared bit-lines, and DRAM sense amplifiers. These are circuits that lean on parasitic capacitance to store information for a few nanoseconds before the next refresh. Verilog gives the trireg net three capacitor strengths, large, medium, and small, to rank the held charge against any later driver that might overwrite it. The mechanism is precise and the use cases are narrow, and the synthesis limitation is what keeps trireg in switch-level libraries rather than synthesisable RTL.
Foundation21 min readVerilogtriregCharge StorageDynamic CMOSSwitch-Level
Chapter 5 · Section 5.1.4 · Data & Variables
1. The Engineering Problem
You are modelling a dynamic-CMOS precharge / evaluate domino gate. During the precharge phase, a PMOS pulls the output node HIGH. During the evaluate phase, the precharge transistor turns off and the NMOS pull-down network either pulls the node LOW (if the input condition is true) or leaves it floating. The "leaves it floating" case is the whole point of dynamic logic — the output node holds its precharged HIGH value through the rest of the evaluate phase by relying on the parasitic capacitance of the node itself.
The straightforward translation to Verilog uses a regular wire:
wire eval_node;
assign eval_node = precharge ? 1'b1 : 1'bz; // PMOS precharge
assign eval_node = (eval & cond) ? 1'b0 : 1'bz; // NMOS evaluateThe simulation runs. During precharge, eval_node = 1. During evaluate-with-cond-false, both drivers release (drive Z), and the simulator reports eval_node = Z for the rest of the evaluate phase. Downstream logic samples Z and propagates X through every operator. The model is wrong — but the bug is not in the drivers; it's in the net type. A real silicon precharged node does not float to Z when both transistors are off; it holds its last-driven value because the parasitic capacitance keeps the charge. A wire has no such memory.
The fix is the trireg net type:
trireg (medium) eval_node;
assign eval_node = precharge ? 1'b1 : 1'bz;
assign eval_node = (eval & cond) ? 1'b0 : 1'bz;Same drivers, same statements — but now eval_node is a trireg (medium). When both drivers release, the resolution function does not return Z; it returns the last driven value at strength medium. Downstream logic sees 1 through the evaluate phase (the precharged HIGH is preserved), and the dynamic-gate model now matches the silicon.
This page is about the trireg net type, its three capacitor strengths, the resolution rules that distinguish "currently driven" from "released and holding," the optional charge-decay timing for modelling capacitor leakage, and the (narrow but real) places where trireg shows up in modern Verilog work.
2. Why trireg Exists
Static-CMOS digital logic has a simple invariant: at every cycle, every gate's output is being actively driven by either the pull-up network (PMOS, output = 1) or the pull-down network (NMOS, output = 0). The output node is never floating; a wire modelling the node is always driven by exactly one transistor.
Dynamic-CMOS logic breaks the invariant. The output node is driven during one phase of the clock and not driven during the other phase. The phases:
- Precharge phase — the clock is LOW. A dedicated precharge PMOS pulls the output node HIGH. The evaluate NMOS network is disabled (the foot transistor at the bottom is off). The node is actively driven HIGH.
- Evaluate phase — the clock is HIGH. The precharge PMOS turns off. The evaluate NMOS network turns on, conditional on the foot transistor. If the input condition forms a path from output to GND, the output node is pulled LOW. If the input condition does not form a path, no transistor drives the node — and the node retains its precharged HIGH value via the parasitic capacitance of the metal route, the gate inputs of downstream consumers, and the source/drain diffusion capacitance of the precharge transistor itself.
The "retains its precharged value" case is what trireg exists to model. A wire would return Z (floating) in this case; the silicon returns 1 (held by the capacitor). Without trireg, every dynamic-logic family — domino logic, NORA logic, true-single-phase clocked (TSPC) logic, charge-sharing SRAM cells, DRAM bit-lines — would simulate wrong in Verilog. The net would float to Z, downstream logic would propagate X, and the entire circuit class would be unrepresentable.
The original Verilog spec (1985) added trireg for exactly these circuit families. The keyword has lived in the language for forty years for one reason: the simulator needs to distinguish "actively driven net" from "released net with stored charge," and wire / tri cannot do that.
3. Mental Model
The mental-model has three practical consequences for any engineer touching trireg:
- A
triregalways has a value. Once any driver has charged the capacitor, the value is held indefinitely (or until the charge-decay timeout, or until another driver overwrites it). There is no "floating Z" state for atriregonce it has been driven at least once. - The capacitor size matters for resolution against subsequent drivers. A
largecapacitor (rank 4) holds against anyweak(rank 3) ormedium/small(ranks 2 / 1) subsequent driver. Asmallcapacitor (rank 1) gets overridden by anything stronger thanhighz. The size is a strength the held value carries; the 5.1.2 strength lattice fully integratestrireginto the resolution function. - The initial value is
X. Att = 0, before any driver has activated, thetrireg's capacitor is "uncharged" — the simulator returnsXto mark the absence of a stored value. Designs that rely ontriregfor charge storage need a reset / precharge phase to drive everytriregto a defined state before downstream logic samples it.
4. The Three Capacitor Strengths
IEEE 1364-2005 §6.1.2 defines exactly three capacitor strengths for trireg. They occupy the middle of the strength lattice (5.1.2 §4), ranked between pull (rank 5) and weak (rank 3, also called weak1 / weak0 for direction).
| Keyword | Rank | Physical analogue |
|---|---|---|
large | 4 | Long-life dynamic node — large parasitic capacitor (e.g. a wide metal route with many gate-input loads) |
medium | 2 | Default; typical-size capacitor in a dynamic gate output |
small | 1 | Short-life dynamic node — minimum parasitic (e.g. a single-gate-load wire, fast to discharge) |
A trireg declaration with no explicit capacitor strength defaults to medium. Most working trireg declarations use the default and only reach for large or small when the modelled circuit genuinely requires the distinction (a wide bit-line vs a single inverter input).
The three strengths matter in two places:
- Resolution against subsequent drivers. When a driver tries to overwrite the held charge, the strength lattice ranks driver-strength vs capacitor-strength. A
pulldriver (rank 5) beats alargecapacitor (rank 4) — the held value is overwritten. Aweakdriver (rank 3) loses to alargecapacitor (rank 4) — the held value persists. - Charge decay (optional). A
triregcan be declared with a charge-decay timeout —trireg #(charge_decay_value) (medium) node;— which specifies how many simulation time units the capacitor holds its charge before decaying toX. The decay only fires when the net is in the "held" state (no active driver); when a driver is active, the decay timer resets. The 5.1.2 page's strength axis governs the resolution behaviour during the hold; the decay timing governs how long the hold lasts.
The vast majority of trireg usage skips the decay timer and relies on the held value persisting indefinitely. The decay timer is mainly for DRAM bit-line modelling, where the simulation needs to assert "if the refresh cycle is missed, the cell forgets" within a defined window. Switch-level dynamic-logic models usually assume the next clock phase will overwrite the held value before any decay matters.
5. Syntax
`default_nettype none
// <trireg> [#(charge_decay)] [(strength)] [range] name [= continuous-assign];
trireg q0; // medium (default), scalar
trireg (large) q1; // explicit large
trireg (medium) [7:0] bus; // medium 8-bit vector
trireg (small) [WIDTH-1:0] payload; // small parametric width
trireg #(1000) (medium) q_decay; // 1000-time-unit charge decay
trireg #(500) (small) [3:0] dram_cell; // small + 500-tu decay (DRAM-like)
// Continuous-assign shorthand
trireg (large) held = drv; // first driver inlineThree syntax constraints the language forces:
- Capacitor strength is in its own parenthesised group. It must not be confused with the
(strength1, strength0)pair used byassignstatements (5.1.2 §6). Atrireg's strength specifier is a single keyword (large,medium, orsmall), not a pair — because the capacitor's stored charge has only one strength per cycle, not two. - Charge-decay precedes capacitor strength. Write
trireg #(decay) (strength) name;in that order. The#(decay)is a delay specifier following the same syntax as other Verilog#delay specifiers; the parenthesised capacitor strength comes next, then the range, then the identifier. signedis not legal ontrireg. Unlikewire/tri/wand/wor, thetriregnet type does not accept asignedmodifier. The held value is always treated as unsigned for resolution purposes.
5.1 The default capacitor strength is medium
If you write trireg q0; with no explicit strength, the simulator treats it as trireg (medium) q0;. Most code relies on this — explicit (medium) is unusual and reads as if the author was unsure of the default.
5.2 Charge decay is rare
The #(decay) form is uncommon in production Verilog. When you do see it, it's almost always in:
- DRAM cell models — where the decay simulates "if refresh is delayed past N time units, the cell forgets its value."
- Switch-level dynamic-logic libraries — where the model needs to flag "if the clock pulse is too slow, the precharged value leaks before evaluate fires."
- Academic / research codebases — modelling charge-redistribution analog effects.
Synthesisable RTL never uses #(decay) — it's a simulation-only timing primitive with no gate-level analogue.
6. The Two States
A trireg is always in one of two simulator-tracked states. The state determines what value the net presents and at what strength.
6.1 Driven state
At least one driver is outputting a non-Z value. The trireg behaves like a wire:
- The resolution function runs across all active drivers per the strength lattice (5.1.2 §7).
- The resolved value is presented to consumers at the resolved strength.
- The capacitor is implicitly "being charged" by the active driver — the capacitor's stored value at this instant equals the resolved value.
- The charge-decay timer (if any) is inhibited — the simulator does not run it while a driver is active.
6.2 Hold state
Every driver is outputting Z. The trireg switches to its capacitor-held value:
- The simulator presents the last value the net carried during its previous driven state.
- The strength becomes the declared capacitor strength (
large/medium/small). - The charge-decay timer (if any) starts counting from the moment the last driver released.
The transition from driven to hold is "released the last driver." The transition from hold back to driven is "any driver started outputting a non-Z value." Both transitions are events that wake the simulator's resolution function.
The interesting edge case: at t = 0, before any driver has ever been active, the trireg is in a third state — "never driven." The simulator presents X at the declared capacitor strength. As soon as the first driver activates, the third state ends and is never re-entered.
7. Visual Explanation
Three figures cover the trireg mechanism.
7.1 Visual A — driven vs hold transitions
The cycle-by-cycle picture. While precharge is active, the PMOS drives node = 1. While eval is active and cond is true, the NMOS drives node = 0. While both are inactive (released), the trireg retains the last driven value at capacitor strength.
trireg state transitions across precharge / evaluate phases
data flow7.2 Visual B — capacitor strength vs subsequent driver
The strength lattice in action. A trireg (large) holds its value at rank 4. A subsequent weak driver (rank 3) loses to the capacitor — the held value persists. A subsequent pull driver (rank 5) overrides the capacitor — the new driver's value wins.
7.3 Visual C — initial X and the first driver
At t = 0, the trireg has never been driven. The simulator presents X at the declared capacitor strength. The first driver to activate ends this "never driven" state; subsequent releases enter the hold state at the last driven value.
8. Dynamic-Logic Domino Gate Example
The canonical use case. A 2-input dynamic NAND in domino form: precharge HIGH, evaluate by pulling LOW if both inputs are true.
`default_nettype none
module dynamic_nand_domino (
input wire clk, // precharge HIGH; evaluate LOW
input wire a,
input wire b,
output wire y // domino output (static buffered)
);
// The dynamic node — needs a trireg because the evaluate phase may
// leave both transistors off, and the silicon node holds its
// precharged HIGH value through the rest of the phase.
trireg (medium) dyn_node;
// PMOS precharge: when clk is LOW, drive dyn_node to 1.
// (drives 1 actively; otherwise Z)
assign dyn_node = ~clk ? 1'b1 : 1'bz;
// NMOS evaluate: when clk is HIGH AND a AND b, drive dyn_node to 0.
// (drives 0 actively; otherwise Z)
assign dyn_node = (clk & a & b) ? 1'b0 : 1'bz;
// Static output buffer — the actual cell output. Required: dynamic
// nodes never drive downstream gates directly; always buffer.
assign y = ~dyn_node;
endmoduleWalk the resolution function for the three phases:
- Precharge (clk = 0). PMOS active, driving
1. NMOS released, drivingZ. Resolution:1atstrong1.dyn_nodeis driven; the capacitor charges.y = ~1 = 0. - Evaluate, condition true (clk = 1, a = 1, b = 1). PMOS released. NMOS active, driving
0. Resolution:0atstrong0.dyn_nodeis driven; the capacitor discharges.y = ~0 = 1. - Evaluate, condition false (clk = 1, a = 0 or b = 0). PMOS released. NMOS released. Resolution: hold state —
dyn_noderetains its last driven value (1from the most recent precharge) atmediumstrength.y = ~1 = 0.
The trireg-vs-wire distinction is sharp on the third case. A wire would resolve to Z, propagating X through ~. The trireg (medium) resolves to 1 at medium, propagating cleanly through the buffer. The static-cell output y is now valid throughout the evaluate phase — exactly the silicon's behaviour.
The required pattern: the dynamic node feeds only a static inverter (or some other static buffer). Cascading dynamic gates directly violates the noise-margin assumption of dynamic logic (the next gate's precharge transistor can fight the held charge of the previous gate's output during the next cycle). Domino logic enforces this by ending every dynamic stage with a static inverter, which is why the family is named for the cascading pattern.
9. Bit-Line Charge Sharing Example
The canonical SRAM bit-line model. A precharged bit-line is shared by N storage cells; during read, exactly one cell discharges the line through its access transistor. The bit-line capacitance is much larger than any single cell's storage capacitance, so the read voltage swing is small — typically modelled with a sense amplifier.
`default_nettype none
module sram_bitline (
input wire precharge, // precharge phase enable
input wire rd_en, // read enable
input wire [3:0] word_select, // one-hot row select
input wire [3:0] cell_data, // stored bits in the four cells
output wire bl_out // bit-line output (to sense amp)
);
// Bit-line — large capacitor because the metal route is long and
// every cell's access transistor adds a junction capacitance.
trireg (large) bit_line;
// Precharge phase: drive bit_line HIGH at strong strength.
assign bit_line = precharge ? 1'b1 : 1'bz;
// Read phase: the selected cell drives bit_line to its stored value;
// the unselected cells release.
assign bit_line = (rd_en & word_select[0]) ? cell_data[0] : 1'bz;
assign bit_line = (rd_en & word_select[1]) ? cell_data[1] : 1'bz;
assign bit_line = (rd_en & word_select[2]) ? cell_data[2] : 1'bz;
assign bit_line = (rd_en & word_select[3]) ? cell_data[3] : 1'bz;
assign bl_out = bit_line;
endmoduleThe walk:
- Precharge active.
bit_linedriven to1atstrong1. The capacitor charges to1. - Read with no selected cell. All five drivers (precharge + four cells) release.
bit_lineholds1atlarge1(the precharged value, at the large capacitor strength). - Read with selected cell storing
1. The selected cell drives1atstrong1. The other four drivers release. The driven value wins over the held capacitor strength;bit_line = 1atstrong1. - Read with selected cell storing
0. The selected cell drives0atstrong0. Resolution:strong0beats the heldlarge1(rank 6 > rank 4).bit_line = 0atstrong0— and on the next cycle when the cell releases, the capacitor now holds0instead of1.
The large capacitor strength matters because real bit-lines have very large parasitic capacitance — typically modelled as large rather than medium to reflect that a weak keeper (e.g. a leakage-replacement cell on the bit-line) cannot override the precharged value. The strength-aware resolution function is what makes this model accurate.
10. Charge-Decay Modelling
The optional #(decay) form models capacitor leakage — the held value decays toward X after the specified number of simulation time units. This is the right model for DRAM cells (where refresh must arrive before the leakage time) and for long-held dynamic nodes in silicon-debug investigations.
`default_nettype none
module dram_cell_model (
input wire precharge,
input wire write_en,
input wire write_data,
output wire cell_q
);
// Small capacitor + 1000-tu charge-decay timeout.
// If no refresh / write arrives within 1000 tu, the cell decays to X.
// Models the leakage current through the access transistor's
// sub-threshold path on a real DRAM cell.
trireg #(1000) (small) cell_node;
// Precharge: drive HIGH for one cycle.
assign cell_node = precharge ? 1'b1 : 1'bz;
// Write: overwrite the cell with write_data.
assign cell_node = write_en ? write_data : 1'bz;
assign cell_q = cell_node;
endmoduleThe decay behaviour:
- While any driver is active, the decay timer is inhibited.
- The moment all drivers release, the decay timer starts.
- If a new driver activates before the timer expires, the timer resets when the new driver releases (the cell is "refreshed").
- If the timer expires with no driver having activated,
cell_nodetransitions from "held last value atsmall" to "decayed toXatsmall."
The 1000 is in time units (the `timescale directive's primary unit). A `timescale 1ns/1ps then makes the decay 1000 nanoseconds. Real DRAM cells decay over milliseconds; the simulation typically scales the decay aggressively for runtime — accepting that "decay in 1000 ns" simulates the same logical behaviour as "decay in 64 ms" in the silicon, just compressed.
#(decay) is rare. Use it only when the simulation needs to verify "did the refresh arrive in time?" — which is essentially DRAM controller verification. Dynamic-CMOS modelling skips the decay entirely; the assumption is that the next clock phase will overwrite the held value before any decay matters.
11. Simulation Behavior
The simulator tracks each trireg's state (driven or hold), the last driven value, the capacitor strength, and (optionally) the decay timer. Updates happen on three events:
- A driver changes value or strength. The simulator re-runs the resolution function over all active drivers. If at least one driver is non-
Z, the net is in driven state with the resolved value; if all drivers areZ, the net transitions to hold state with the most-recently-driven value at capacitor strength. - The decay timer expires. Only fires when the net has been in hold state for the full decay window with no driver activity. The net transitions to
Xat capacitor strength. - Re-activation. Any driver becoming non-
Zwhile the net is in hold or decayed state transitions back to driven state; the decay timer (if any) is cancelled and resets.
The simulator's internal trireg data structure typically carries: current state (driven / hold / decayed / never-driven), last driven value, last driven strength, capacitor strength (compile-time), decay window (compile-time), pending decay event handle (runtime). Every event causes a state-machine transition.
12. Waveform Analysis
Two waveforms cover the trireg behaviour.
12.1 Waveform #1 — domino dynamic NAND
Dynamic NAND in domino form — trireg (medium) dyn_node
12 cyclesThe interesting cycles are the held evaluate phases (cycles 1, 3, 7). Both PMOS and NMOS are off; on a wire, dyn_node would resolve to Z and y would propagate X through ~. On the trireg (medium), the resolution function detects all drivers released and returns the last driven value (1 from the most recent precharge) at medium strength. y = ~1 = 0 throughout the hold, and the downstream consumer never sees X.
12.2 Waveform #2 — held value overridden by stronger driver
trireg (medium) held value vs subsequent pull and weak drivers
12 cyclesThe cycle-8 case is the lattice-aware lesson: medium is rank 2, weaker than weak (rank 3). A medium capacitor is not strong enough to resist a weak driver. To model a circuit where the dynamic node's stored charge should resist a weak keeper or leakage-replacement driver, declare the trireg as large (rank 4) — which beats weak (rank 3) but loses to pull (rank 5). The capacitor-strength choice is exactly the strength-lattice trade-off: pick the rank that matches the real physical capacitance relative to all other drivers in the circuit.
13. Synthesis Insight
trireg is rejected by every modern synthesis tool.
The reason is the same as wand / wor (5.1.3) and internal tri (5.1.1): no standard-cell library provides cells that implement capacitor-storage behaviour. The synthesis tool has no way to map a trireg to gates. The mapping options would be:
- A flip-flop or latch with an enable signal. The tool could infer a storage element from the multi-driver-with-release pattern, but the inference would be fragile (it has to recognise the "all drivers
Z" hold condition) and the result would not match the dynamic-logic behaviour (a flop is clocked; atriregis event-driven by driver releases). - Direct mapping to a custom dynamic-logic cell. A few foundries provide characterised dynamic-logic cells (typically in their datapath / multiplier macros), but these are not part of the standard-cell library and the synthesis tool does not infer them.
Most synthesis tools therefore reject trireg with an explicit error:
Error: Unsupported net type
triregat instancedyn_node. Use a flip-flop or latch with an enable signal for dynamic storage, or instantiate a dynamic-logic library cell.
The practical consequence: trireg lives only in simulation-only models — testbench BFMs, switch-level libraries, hand-characterised dynamic-logic cells. Synthesisable RTL never declares trireg.
The replacement pattern for synthesisable storage is straightforward — replace the dynamic node with a clocked flip-flop and explicit enable:
// Original dynamic-logic pattern (simulation-only):
trireg (medium) dyn_node;
assign dyn_node = ~clk ? 1'b1 : 1'bz;
assign dyn_node = (clk & a & b) ? 1'b0 : 1'bz;
// Synthesisable rewrite — static logic with a registered output:
reg dyn_node_q;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) dyn_node_q <= 1'b1; // precharge equivalent
else if (a & b) dyn_node_q <= 1'b0; // evaluate equivalent
else dyn_node_q <= dyn_node_q; // hold equivalent (no-op)
end
assign y = ~dyn_node_q;The rewrite produces the same logical behaviour but on static CMOS gates — no dynamic-logic noise margin concerns, no charge-decay timing, no trireg. The performance / area trade-off (dynamic logic was historically faster than static for the same gate count) is no longer competitive on modern process nodes; static logic plus a deeper pipeline beats dynamic logic on every metric except very specialised low-leakage circuits.
14. Industry Use Cases
The three places trireg actually shows up in modern engineering work:
14.1 Dynamic-logic cell models
A handful of foundries still provide custom dynamic-logic cells for high-speed datapath blocks — wide multipliers, dynamic adders, register-file decoders. The Verilog behavioural model of these cells uses trireg to model the precharge / evaluate / hold cycle. The synthesis flow does not actually run on these models; the standard-cell library carries the hand-characterised cell at a layout/timing level, and the synthesis tool instantiates the cell directly. The trireg model is for simulation only — gate-level and SDF-annotated simulation use the foundry's library cell.
14.2 DRAM cell behavioural models
Verification environments for memory controllers include a behavioural model of the DRAM array. Each cell is a trireg with a charge-decay timeout that simulates the refresh requirement. The decay timeout is typically scaled aggressively (1000 ns instead of 64 ms) to keep the simulation tractable, but the logical behaviour — "refresh must arrive before decay or the cell forgets" — is preserved exactly.
14.3 Switch-level cell libraries
Pre-2000 standard-cell libraries from Intel, IBM, and Motorola included switch-level Verilog models that used trireg to represent the parasitic capacitance on every internal node. The 5.1.2 strength-attenuation pattern from the pass-transistor section combines with trireg to model "value passes through, attenuated; node retains its charge after the pass-transistor turns off." Modern flows skip this layer — synthesis works directly on the standard-cell library — but maintenance work on legacy IP may still touch these models.
In all three cases, trireg is doing a modelling job, not generating a circuit. Real silicon uses real capacitors; trireg makes the simulator behave the same way.
15. Common Mistakes
Five pitfalls that catch engineers reading or writing trireg code.
15.1 Using trireg for digital state
The most common misuse. An engineer wants a signal to "remember its last value" — i.e., act as digital state — and reaches for trireg because the keyword's behaviour sounds right. The result is a trireg declaration in RTL that the synthesis tool then rejects. The right answer for digital state is a flip-flop (reg declared inside an always @(posedge clk) block) or a latch (always @(*) with conditional assignment). trireg models analog charge storage on a physical capacitor — not digital state.
15.2 Forgetting the initial X
At t = 0, every trireg is X until the first driver activates. Testbenches that read a trireg before the precharge cycle has run will see X and propagate it. Add a reset / precharge phase at simulation start that drives every trireg to a defined value before downstream logic samples it. (This is the same discipline as for any reg — initialise before reading.)
15.3 Mismatched capacitor strength vs subsequent driver
A trireg (medium) is rank 2, which is weaker than weak (rank 3). A weak keeper driver downstream of the trireg will override the held value. If the intent was "the capacitor's stored charge should resist a weak driver," the right declaration is trireg (large) (rank 4 > weak's rank 3). The capacitor-strength choice has to match the modelled circuit's relative capacitance, not just feel like a reasonable default.
15.4 Charge-decay timer never firing
The #(decay) timer resets every time a driver activates. If the driver activates frequently — e.g. every clock cycle — the decay timer never has time to expire, and the trireg behaves as if no decay timer existed. This is usually fine (the simulation matches the silicon), but it confuses engineers who expect the decay to fire on a fixed schedule. The decay only fires when the net stays in hold state continuously for the full window.
15.5 Vector trireg resolves per-bit
A 4-bit trireg is four independent capacitors. Each bit holds its last driven value independently — and each bit's decay timer (if any) runs independently. Don't reason about a vector trireg as a single stored value; reason bit by bit.
16. Debugging Lab
Three trireg debug post-mortems
17. Coding Guidelines
- Use
triregonly when a physical capacitor is doing physical work. Dynamic CMOS, precharge / evaluate, DRAM cells, bit-line modelling, switch-level libraries. Not for digital state — that's a flop or latch. - Match the capacitor strength to the modelled circuit's relative capacitance.
largefor wide bit-lines and long metal routes;medium(default) for typical dynamic gate outputs;smallfor fast-decay nodes. The choice has to make the trireg-vs-other-driver resolution come out right. - Every
triregneeds a precharge / reset / first-driver phase before the read. The initialXatt = 0does not disappear on its own; downstream logic that samples before precharge will seeXand propagate it. - Drivers output
Zfor "released." Using1'b1or1'b0to mean "released" overrides the held value instead of letting it persist — the trireg's hold-state semantic depends on every non-active driver outputtingZ. - Skip
#(decay)unless the simulation genuinely needs to verify refresh timing. Most dynamic-logic models do not need the decay; the next clock phase will overwrite the held value before any decay matters. triregis simulation-only. Synthesis tools reject it. Synthesisable RTL uses a clocked flop or latch with an enable for any digital state; thetriregdeclaration belongs in testbenches and behavioural models only.- Vector
triregresolves per-bit. A 4-bittriregis four independent capacitors. Each bit holds and decays independently. - Document the modelled circuit. A one-line comment naming the dynamic-logic family ("domino NAND output node — held across evaluate when no NMOS pull-down path") distinguishes intentional
trireguse from misuse for digital state.
18. Interview Q&A
19. Exercises
Three exercises that turn the trireg model into reflex.
Exercise 1 — Predict the resolved value
For each scenario, predict the trireg's state and resolved value.
| # | trireg strength | Last driven value | Current drivers | Resolved (value, strength) |
|---|---|---|---|---|
| 1 | large | 1 | all releasing | ? |
| 2 | medium | 0 | one pull1 driver | ? |
| 3 | small | 1 | one weak0 driver | ? |
| 4 | large | 0 | one pull1 and one weak0 | ? |
| 5 | medium | X (never driven) | one strong1 driver | ? |
| 6 | large | 1 | one weak0 driver | ? |
Hints. Compare driver strengths to the capacitor strength using the 5.1.2 lattice. If no driver is active, the trireg is in hold state.
Exercise 2 — Model a 2-input dynamic AND in domino form
Write a Verilog module dynamic_and_domino that implements a 2-input dynamic AND gate in domino logic. Specifications:
- Inputs:
wire clk(precharge LOW, evaluate HIGH),wire a,wire b. - Output:
wire y. - Behaviour: during precharge, the dynamic node is HIGH. During evaluate, the dynamic node falls to
0only ifa & bis true. The static output isy = ~dyn_node(the domino convention).
Hints. A 2-input dynamic AND needs the NMOS pull-down to fire when a & b is true — drive the dynamic node to 0 when clk & a & b. The precharge drives the dynamic node to 1 when ~clk. Use trireg (medium) dyn_node; for the dynamic node and a static assign y = ~dyn_node; for the buffered output.
Exercise 3 — Spot the trireg misuse
The following module appears in a synthesisable file and the synthesis tool errors out. Identify the misuse and rewrite the module without trireg while preserving the behaviour.
module sample_and_hold (
input wire sample,
input wire data_in,
output wire held_q
);
trireg (large) hold_node;
assign hold_node = sample ? data_in : 1'bz;
assign held_q = hold_node;
endmoduleWhat to produce. (a) Explain why the synthesis tool rejects this module. (b) Rewrite using a clocked flip-flop (with a clock input added) and explicit held_q output. (c) Identify one behavioural difference between the trireg version and the flop version — specifically, what happens at t = 0 before sample first asserts.
20. Summary
trireg is Verilog's capacitive-storage net — the language's primitive for modelling parasitic charge storage on dynamic-CMOS nodes. When at least one driver is active, a trireg behaves like a wire and resolves to the driven value at the driver's strength. When all drivers release, the trireg transitions to hold state and presents its last driven value at the declared capacitor strength — large (rank 4), medium (rank 2, the default), or small (rank 1).
The three capacitor strengths sit in the middle of the IEEE 1364 strength lattice between pull and weak, so the held charge resists a weak driver (only large capacitor) and yields to a pull driver. An optional #(decay) form models capacitor leakage — the held value decays to X after the specified simulation time if no driver activates.
The use cases are narrow:
- Dynamic-CMOS gate models — precharge / evaluate, domino logic, NORA, TSPC.
- DRAM cell models — with
#(decay)to verify refresh timing. - SRAM bit-line models —
largecapacitor on the bit-line,pull0from the selected cell,strong1from precharge. - Switch-level library cells — modelling parasitic capacitance on every internal node.
The synthesis story is the reason trireg stays in simulation-only code: every modern synthesis tool rejects trireg because no standard-cell library provides capacitor-storage cells. Synthesisable RTL that needs "remember last value" uses a flip-flop or latch with an enable — never trireg.
The day-to-day discipline:
- Use
triregonly when a physical capacitor is doing physical work. Dynamic CMOS, charge sharing, dynamic memory. Not for digital state — that's a flop. - Match the capacitor strength to the circuit's relative capacitance.
largefor wide bit-lines;mediumfor typical dynamic gates;smallfor fast-decay nodes. - Every
triregneeds a precharge / reset phase before the read. The initialXdoes not disappear on its own. - Drivers output
Zfor "released." Active0or1overrides the held value instead of letting it persist. #(decay)is rare. Use it only for verifying refresh timing — most dynamic-logic models don't need it.triregcannot be synthesised. Synthesisable RTL replaces it with a clocked flop / latch.
The sibling sub-pages drill further into the strength-aware net family: 5.1.5 tri0 / tri1 Nets covers implicit pull-up / pull-down drivers; 5.1.6 supply0 / supply1 covers the power and ground rail-tie nets at supply strength. Chapter 12 Switch-Level Modeling picks up the pmos / nmos / cmos primitives that combine with trireg to model full dynamic-logic cells.
Related Tutorials
- Signal Strengths — Chapter 5.1.2; the strength lattice this page extends with the three capacitor levels.
- Wired Nets (wand and wor) — Chapter 5.1.3; the orthogonal wired-logic resolution family.
- wire and tri Nets — Chapter 5.1.1; the baseline resolution function this page contrasts with.
- Physical Data Types — Chapter 5.1; the parent overview of the net family.
- Variables & Data Types — Chapter 5; nets and variables together.