What Synthesis Does With Your RTL
Section 8.1 was about RTL before synthesis sees it. Section 8.2 is about what synthesis does with it.
Section 5.3 taught that if-else builds a priority mux chain and case builds a flatter parallel decode. That is true and a useful model for writing RTL. This article goes past it, into what happens between your RTL and the netlist the tool hands back, because “the RTL implies this structure” and “the synthesized gates are exactly this structure” are two different claims, and the gap between them is where a lot of useful intuition lives.
Synthesis is not a literal translator
This surprises people who think of synthesis as “RTL translated mechanically into gates”: a modern synthesis tool does not take your if-else chain, build the cascaded mux structure from the Module 5 picture and stop. It first builds an internal representation of the Boolean function the RTL describes, largely independent of which control construct you used, and then runs that function through logic optimisation, the same kind of minimisation you did by hand with K-maps in Module 1, automated and applied at a scale no human could manage.
So two functionally equivalent pieces of RTL, one written as if-else and one as case, can produce identical gates after optimisation, if the optimiser finds they describe the same function and no real priority behaviour was required. The Module 5 model is about your stated intent, which matters for readability and for correctness when priority is required, but it is not a guarantee about the gate structure that survives optimisation when no real priority exists in the logic.
Where this matters: an example
// Written as a priority chain, but the conditions happen to be
// mutually exclusive by construction
always @(*) begin
result = 4'b0000;
if (sel == 2'b00) result = a;
else if (sel == 2'b01) result = b;
else if (sel == 2'b10) result = c;
else result = d;
end
Although this is if-else, sel can only ever equal one of 00, 01, 10 or the implicit 11. The conditions are mutually exclusive by construction. A good optimiser recognises this and builds the same flat mux it would have built from an equivalent case. The if-else syntax does not force a slower structure here, because the function has no priority dependency to preserve.
Contrast the interrupt encoder from Section 5.3, where nmi must override irq[3] even when both are asserted. There the if-else encodes a functional requirement (which signal wins when several are true), and no optimisation can flatten it without changing what the circuit computes. The priority is part of the specification, not an accident of phrasing.
The Module 5 model tells you what to write to express intent. What the optimiser does afterwards depends on whether that intent is a functional requirement (real priority, preserved) or an artefact of how you phrased mutually exclusive conditions (flattened into whatever is fastest). Both produce correct output; the difference is gate count and timing.
Technology mapping: the last step
After Boolean optimisation, one more stage produces the real netlist: technology mapping, where the optimised, technology-independent logic is translated into the gates available in the target standard cell library or FPGA fabric. This is where the NAND/NOR preference from Module 1’s CMOS articles becomes concrete. A tool targeting an ASIC library maps the logic onto whatever mix of NAND2, NAND3, AOI21, OAI22 and other compound cells the library offers, chosen to minimise area or delay according to your constraints (Section 8.3 covers how those are specified).
An FPGA is a different mapping problem. Instead of discrete gates, logic is packed into LUTs (look-up tables), small table-based blocks that implement any function of a fixed number of inputs, commonly 4 or 6. A LUT does not care whether the logic was an AND, an OR or an arbitrary truth table; the function only has to fit the LUT’s input count. That is why FPGA synthesis reports talk about LUT utilisation rather than gate counts.
Practice Exercise
Two fragments both describe a 2-to-1 mux, one with if-else and one with the conditional operator. Explain why you would expect identical synthesized gates from both, using the function-first model from this article.
Solution
// Fragment 1
always @(*) begin
if (sel) y = b;
else y = a;
end
// Fragment 2
assign y = sel ? b : a;
Both describe the same Boolean function, $y = sel \cdot b + \overline{sel} \cdot a$. Synthesis builds its internal representation from the function, not from the syntax used to express it, and since both reduce to the identical function the optimisation and mapping stages have nothing to distinguish. You would expect the same gates from both, which is why Verilog offers several equivalent ways to write the same combinational logic: the choice is about what reads more clearly to a person, not what produces better hardware.
Synthesis extracts the Boolean function the RTL describes, optimises it (flattening an if-else chain’s apparent priority when the conditions turn out to be mutually exclusive), and only then maps the result onto the target technology’s gates or LUTs. Real priority survives because it is a property of the function, not of the phrasing. In the next article we look at resource sharing, where the optimiser goes a step further and merges two separate operations in the RTL into one shared piece of hardware, with a real area-versus-timing trade attached.