RTL Coding Styles That Yield Simulation and Synthe
RTL Coding Styles That Yield Simulation and Synthe
net/publication/228554783
CITATIONS READS
20 1,478
2 authors, including:
Clifford E. Cummings
Sunburst Design, Inc.
25 PUBLICATIONS 378 CITATIONS
SEE PROFILE
All content following this page was uploaded by Clifford E. Cummings on 21 January 2015.
Don Mills
LCDM Engineering
Clifford E. Cummings
Sunburst Design, Inc.
ABSTRACT
This paper details, with examples, Verilog coding styles that will cause a mismatch between pre-
and post-synthesis simulations. Frequently, these mismatches are not discovered until after
silicon has been generated, and thus require the design to be re-submitted for a second spin.
Each coding style is accompanied by an example that shows the problem and an example of a
style that will match pre/post synthesis simulations. NOTE: Most of these coding styles also
apply to RTL models written in VHDL.
1.0 Introduction
The engineering task of converting a thought, an idea--or for the lucky ones, a specification--into
a physical design is what ASIC and FPGA design is all about. The methodology of top down
design requires transforming ideas from the abstract into a physical form that can be
implemented and built. Developing concise, accurate designs entails learning how RTL coding
styles synthesize and which styles can cause problems. This paper will discuss a number of
HDL coding styles that cause mismatches between RTL and gate-level simulations. The basic
premise is that any coding style that gives the HDL simulator information about the design that
cannot be passed on to the synthesis tool is a bad coding style. Additionally, any synthesis
switch that provides information to the synthesis tool that is not available to the simulator is bad.
If these guidelines are violated, the pre-synthesis RTL simulations will not match the post-
synthesis gate level simulations. These mismatches can be very hard to detect if all possible
logic combinations are not fully tested, and if not caught, are generally fatal to production
ASICs. In addition, complete testing becomes impractical as the size of a design reaches into the
millions of gates. The solution is to understand what coding styles or synthesis switches can
cause RTL to gate level simulation mismatches and avoid these constructs.
Synthesis tools infer combinational or latching logic from an always block with a sensitivity
list that does not contain the Verilog keywords posedge or negedge. For a combinational
always block, the logic inferred is derived from the equations in the block and has nothing to
do with the sensitivity list. The synthesis tool will read the sensitivity list and compare it against
the equations in the always block, only to report coding omissions that might cause a mismatch
between pre- and post-synthesis simulations.
The presence of signals in a sensitivity list that are not used in the always block will not make
any functional difference to either pre- or post-synthesis simulations. The only effect of
extraneous signals is that the pre-synthesis simulations will run more slowly. This is due to the
fact that the always block will be entered and evaluated more often than is necessary.
always @(a or b)
o = a & b;
endmodule
always @(a)
o = a & b;
endmodule
always
o = a & b;
endmodule
In module code2a below, the object temp is read prior to being assigned. The value assigned
to temp during the previous pass through the block will be used to determine the assignment to
o. In the next line temp is assigned its new value corresponding to the current pass through the
always block. During pre-synthesis simulation, temp will simulate as if it is latched. The
value will be held for use during the next pass through the always block. This same code will
synthesize as if the assignment order were listed correctly. This results in a mismatch between
pre- and post-synthesis simulations. The code in module code2b shows the correct ordering
which will result in pre- and post-synthesis simulations matching.
3.0 FUNCTIONS
Functions always synthesize to combinational logic. For this reason, some engineers choose to
code all combinational logic using functions. As long as the coded function simulates like
combinational logic, there is no problem using functions. The problem occurs when engineers
make a mistake in the combinational function code and create simulation code that behaves like
a latch. Since there are no synthesis tool warnings when function code simulates latch behavior,
the practice of using functions to model synthesizable combinational logic is dangerous.
In the following example, module code3a shows a typical way to code a latch. When the same
if statement is used inside a function, as shown in module code3b, the outcome is a 3-input
and gate. If the code in a function is written to infer a latch, the pre-synthesis simulation will
simulate the functionality of a latch, while the post-synthesis simulation will simulate
combinational logic. Thus, the results from pre- and post-synthesis simulations will not match.
In module code4a, a case statement is coded without using any synthesis directives. The
resultant design is a decoder built from 3-intput and gates and inverters. The pre- and post-
synthesis simulations will match. Module code4b uses a case statement with the synthesis
directive full_case. Because of the synthesis directive, the en input is optimized away
during synthesis and left as a dangling input. The pre-synthesis simulator results of modules
code4a and code4b will match the post-synthesis simulation results of module code4a, but
will not match the post-synthesis simulation results of module code4b.
// no full_case
// Decoder built from four 3-input and gates
// and two inverters
module code4a (y, a, en);
output [3:0] y;
input [1:0] a;
input en;
reg [3:0] y;
// full_case example
// Decoder built from four 2-input nor gates
// and two inverters
// The enable input is dangling (has been optimized away)
module code4b (y, a, en);
output [3:0] y;
input [1:0] a;
input en;
reg [3:0] y;
One consultant related the experience of adding parallel_case to an RTL design to improve
optimized area and speed. The RTL model (behaving like a priority encoder) passed the test
bench, but testing missed the flaw while simulating the gate-level model, which was
implemented as non-priority parallel logic. Result: the design was wrong, the flaw was not
discovered until ASIC prototypes were delivered, and the ASIC had to be redesigned at
significant cost in both dollars and schedule.
// no parallel_case
// Priority encoder - 2-input nand gate driving an
// inverter (z-output) and also driving a
// 3-input and gate (y-output)
module code5a (y, z, a, b, c, d);
output y, z;
input a, b, c, d;
reg y, z;
// parallel_case
// two parallel 2-input and gates
module code5b (y, z, a, b, c, d);
output y, z;
input a, b, c, d;
reg y, z;
The use of casex statements can cause design problems. A casex treats ‘X’s as "don't cares"
if they are in either the case expression or the case items. The problem with casex occurs when
an input tested by a casex expression is initialized to an unknown state. The pre-synthesis
simulation will treat the unknown input as a "don't care" when evaluated in the casex
statement. The equivalent post-synthesis simulation will propagate ‘X’s through the gate-level
model, if that condition is tested.
One company related an experience they had with the use of casex in a design. The design
went into a state where one of the inputs to a casex statement was unknown after the reset was
released. Since the pre-synthesis RTL simulation treated the unknown input as a "don't care",
the casex statement erroneously initialized the design to a working state. The gate-level
simulation was not sophisticated or detailed enough to catch the error and consequently, the first
turn of the ASIC came back with a serious flaw.
Module code6 below is a simple address decoder with an enable. Sometimes design errors in
an external interface will cause the enable to glitch to an unknown state after initialization,
before settling to a valid state. While the enable is in this unknown state, the case selector will
erroneously match one of the case conditions, based on the value of addr. In the pre-synthesis
design, this might mask a reset initialization problem that would only be visible in post-synthesis
simulations. A similar situation could exist if the MSB of the address bus went unknown while
en is asserted. This would cause either memce0 or memce1 to be asserted whenever the chip
select (cs) signal should have been asserted.
Guideline: Do not use casex for RTL coding. It is too easy to match a stray unknown signal. It
is better to use the casez statement as shown in the next section.
The use of casez statements can cause the same design problems as casex, but these
problems are less likely to be missed during verification. With casez, a problem would occur
if an input were initialized to a high impedance state. However, the casez statement is a short,
concise, and tabular method for coding certain useful structures, such as priority encoders,
interrupt handlers, and address decoders. Therefore, the casez statement should not be
completely dismissed from a design engineer’s repertoire of useful HDL coding structures.
Module code7 is the same simple address decoder with enable as shown in module code6
above, except that it uses a casez statement instead of the casex statement. The same
problem described in Section 4.3 will occur when one of the inputs goes to a high-impedance
state rather than an unknown state. Once again, an erroneous case match will occur, depending
on the state of the other inputs to the case statement. However, it is less likely that a stray match
will occur with a casez statement (floating input or tri-state driven signal) than with a casex
statement (signal goes unknown briefly), but a potential problem does exist. Note that casez is
useful for modeling address decoders and priority encoders.
Guideline: Use casez sparingly and cautiously for RTL coding since it is possible to match a
stray tri-state signal.
When making assignments in RTL code, sometimes it is tempting to assign the ‘X’ value. The
‘X’ assignment is interpreted as an unknown by the Verilog simulator (with the exception of
casex as previously discussed), but is interpreted as a "don't care" by synthesis tools. Making
‘X’ assignments can cause mismatches between pre- and post-synthesis simulations; however,
the technique of making ‘X’ assignments can also be a useful trick. In FSM designs where
there exist unused states, making an ‘X’ assignment to the state variable can help debug bogus
state transitions. This is done by defaulting the next state registers to ‘X’ prior to entering the
case statement, resulting in ‘X’ for any incorrect state transitions. Keep in mind that
synthesis tools interpret unused ‘X’ state transitions as “don’t cares” for better synthesis
optimization.
Modules code8a and code8b are simple Verilog models that implement 3-to-1 multiplexers.
The coding style used in module code8a will give a simulation mismatch if the select lines ever
take on the value of 2'b11. The coding style used in module code8b will have no such
mismatch. This mismatch can be valuable if the select line combination of 2'b11 is never
expected. If this select line combination does occur, it will become obvious during simulation as
the y output will be driven to an unexpected ‘X’ condition (which might facilitate debugging).
However, if the design routinely and harmlessly transitions through the 2'b11 select-state, the
first coding style will cause annoying simulation mismatches.
always @(a or b or c or s)
case (s)
2'b00: y = a;
2'b01: y = b;
2'b10, 2'b11: y = c;
endcase
endmodule
// synopsys translate_off
initial y1 = 1'b1;
// synopsys translate_on
Module code10a will simulate correctly 99% of the time (pre-synthesis). It has the flaw
described above. If the negedge is removed from the rstn and setn in the sensitivity list as
shown in module code10b, the design will not simulate correctly, either pre- or post-synthesis,
nor will it synthesize correctly. Finally, the code in module code10c shows the fix that will
simulate correctly 100% of the time, and will match pre- and post-synthesis simulations. This
code uses the translate_off/translate_on directives to force the correct output for the
exception condition described above.
// synopsys translate_off
// Bad DFF with asynchronous set and reset. This design
// will not compile from Synopsys, and the design will
// not simulate correctly.
module code10b (q, d, clk, rstn, setn);
output q;
input d, clk, rstn, setn;
reg q;
endmodule
// synopsys translate_on
// synopsys translate_off
always @(rstn or setn)
if (rstn && !setn) force q = 1;
else release q;
// synopsys translate_on
8.0 Conclusion
Knowing which coding styles can cause mismatches between pre- and post-synthesis
simulations, understanding why mismatches might occur, and avoiding error-prone coding styles
will greatly reduce RTL design flaws and the debug time necessary to fix the mismatches. As
ASICs continue to increase in size, the ability to run 100% coverage regression tests after each
synthesis turn is becoming more impractical. Designers must use every means available to
reduce risk early in the design cycle.
Mr. Mills has developed and implemented top-down ASIC design flows for a number of
companies. His specialty is design tool integration and design tool flow automation. Through his
work in developing and integrating top-down design flows, he has developed and taught a
number of methodology classes, which include ASIC design flow, Verilog, VHDL, Synopsys
synthesis, DFT, BSD (1149.1), and makefile automation.
Mr. Mills served as Technical Chair for the 1998 Synopsys Users Group (SNUG) Conference,
the 1999 Spring and Fall SNUG Conferences, and for the 2000 Spring SNUG Conference. Mr.
Mills has worked for L3 Communications, US Robotics, Honeywell, and a number of other
companies. He holds a Bachelor of Science in Electrical Engineering from Brigham Young
University, and is a member of the IEEE.
Cliff Cummings, President of Sunburst Design, Inc., is an independent EDA consultant and
trainer with 18 years of ASIC, FPGA and system design experience and eight years of Verilog,
synthesis and methodology training experience.
Mr. Cummings, a member of the IEEE 1364 Verilog Standards Group (VSG) since 1994,
currently chairs the VSG Behavioral Task Force, which is charged with proposing enhancements
to the Verilog language. Mr. Cummings is also a member of the IEEE Verilog Synthesis
Interoperability Working Group.
Mr. Cummings holds a BSEE from Brigham Young University and an MSEE from Oregon State
University.