Synopsys, Coding Guidelines
Synopsys, Coding Guidelines
Introduction
This document summarizes coding guidelines addressing the synthesis of datapaths. Two classes of guidelines are
distinguished:
Guidelines that help achieve functional correctness and the intended behavior of arithmetic expressions in RTL
code.
Guidelines that help datapath synthesis to achieve the best possible QoR (quality of results).
Datapath Synthesis
To write RTL code that gives the best possible QoR during datapath synthesis, it is important to understand what
datapath functionality current synthesizers can efficiently implement, how the datapath synthesis flow works, and how
coding can influence the effectiveness of datapath synthesis.
The most important technique to improve the performance of a datapath is to avoid expensive carry-propagations
and to make use of redundant representations instead (like carry-save or partial-product) wherever possible. Other
techniques include high-level arithmetic optimizations (for example, common-subexpression sharing and constant
folding). These optimization techniques are most effective when the biggest and most complex possible datapath
https://solvnet.synopsys.com/retrieve/print/015771.html 1/19
1/16/13 Coding Guidelines for Datapath Synthesis
folding). These optimization techniques are most effective when the biggest and most complex possible datapath
blocks are extracted from the RTL code. This is enabled by supporting the following functionality:
Sum of Product (SOP): Arbitrary sum of products (that is, multiple products and summands added together) can
be implemented in one datapath block with one single carry-propagate final adder. Internal results are kept in
redundant number representation (for example, carry-save) wherever possible.
Product of Sum (POS): Limited product of sums (that is, a sum followed by a multiply) can be implemented in
one datapath block with one single carry-propagate final adder (that is, no carry-propagation before the
multiply). The limitation is that only one multiplication operand can be in redundant (carry-save) format; the other
operand has to be binary.
Select-op: Select-operations (that is, selectors, operand-wide multiplexers) can be implemented as part of a
datapath block on redundant internal results (that is, without carry-propagation before the select-op).
Comparison: Comparisons can be implemented as part of a datapath block on redundant internal results (that is,
without carry-propagation before the comparison).
Example: "t1 = a + b; t2 = c * d; z = t1 > t2" ('t1', 't2' in carry-save only if not truncated internally).
Shift: Constant and variable shifts can be implemented as part of a datapath block on redundant internal results
(that is, without carry-propagation before the comparison).
Synthesis Flow
1. Datapath extraction: The largest possible datapath blocks are extracted from the RTL code.
2. Datapath optimization: High-level arithmetic optimizations are carried out on the extracted datapath blocks.
3. Datapath generation: Flexible, context-driven datapath generators implement optimized netlists for the
datapath blocks under specified constraints, conditions, and libraries.
Datapath Extraction
Largest possible datapath blocks are extracted from the RTL code by merging connected operators into a single
partition.
The larger the partition is the more high-level optimizations can be applied and the fewer carry-propagations are
needed (shorter delay).
All internal operands of a datapath block can be in redundant carry-save representation to improve delay.
Therefore operands that need to be in binary representation cannot be internal to a datapath block.
Operators that require binary inputs or outputs → must be at the boundary of a datapath block.
Comparator: need a binary conversion for flag calculation → must be at output boundary.
Selector / shifter: need binary control input → control input must be at input boundary.
Coding Goals
RTL code can be optimized for datapath synthesis by achieving the following goals:
https://solvnet.synopsys.com/retrieve/print/015771.html 2/19
1/16/13 Coding Guidelines for Datapath Synthesis
Enable datapath extraction to extract the biggest possible datapath blocks.
The following guidelines will help you write code to achieve these goals.
Tool Support
Synopsys' Design Compiler supports some of the guidelines described in this article in the sense that synthesis gives
good results even if the code does not follow the guidelines. In other words, synthesis can efficiently handle bad code
as well. This is mentioned in the affected guidelines. This effectively makes these specific guidelines obsolete, however,
we still recommend to follow the guidelines for writing code that is unambiguous, clean, easy to read and portable.
General Guidelines
1. Signed Arithmetic
Rule: Use type 'signed' (VHDL, Verilog 2001) for signed/2's complement arithmetic (that is, do not emulate
signed arithmetic using unsigned operands/operations). Also, do not use the 'integer' type except for constant
values.
Rationale: Better QoR for a signed datapath as compared to an unsigned datapath emulating signed behavior.
Checks:
Resources report: Check for type and size of datapath operands (see resources report).
Tool Support: (partial) Simple sign-extension of unsigned inputs (as in the first "bad QoR" example above) is fully
supported by Design Compiler and automatically implemented as a signed operation. The second "bad QoR"
example is not directly recognized as a simple signed multiplication, resulting in a larger circuit.
2. Sign-/zero-extension
Rule: Do not manually sign-/zero-extend operands if possible. By using the appropriate unsigned/signed types,
correct extension is done in the following way:
Rationale: Better QoR because synthesis can more easily/reliably detect extended operands for optimal
implementation. The code is also easier to read and coding is less error-prone.
Example:
https://solvnet.synopsys.com/retrieve/print/015771.html 3/19
1/16/13 Coding Guidelines for Datapath Synthesis
VHDL Verilog
Tool Support: (full) Manual extensions are fully recognized by Design Compiler and do not affect the synthesis
result.
Verilog Guidelines
3. Mixed unsigned/signed expression (Verilog)
Rule: Do not mix unsigned and signed types in one expression. Mixed expressions are interpreted as unsigned in
Verilog.
Rationale: Unexpected behavior / functional incorrectness because Verilog interprets the entire expression as
unsigned if one operand is unsigned.
// expression becomes unsigned // zero-extended, cast to signed (add '0' as sign bit)
assign z = a * b; assign z = $signed({1'b0, a}) * b;
// -> unsigned multiply // -> signed multiply
Checks:
Resources report: Check for operation type (unsigned or signed?) (see resources report).
Note: Part-select results are unsigned, regardless of the operands. Therefore, part-selects of signed vectors (for
example, "a[6:0]" of "input signed [7:0] a") become unsigned, even if part-select specifies the entire vector
(for example, "a[7:0]" of "input signed [7:0] a").
Rule: Use type casts ($signed) to restore the correct type. Do not use part-selects that specify the entire
vector.
Example:
https://solvnet.synopsys.com/retrieve/print/015771.html 4/19
1/16/13 Coding Guidelines for Datapath Synthesis
Checks:
Elaboration warnings: Check for warnings about implicit unsigned-to-signed/signed-to-unsigned
conversions/assignments (see warning).
Resources report: Check for operation type (unsigned or signed?) (see resources report).
Context-determined expression: In an assignment, the left-hand side provides the context that determines
the width of the right-hand side expression (that is, the expression has the width of the vector it is
assigned to).
Example:
input [7:0] a, b;
output [8:0] z;
input [3:0] a;
input [7:0] b;
output [9:0] z;
Example:
https://solvnet.synopsys.com/retrieve/print/015771.html 5/19
1/16/13 Coding Guidelines for Datapath Synthesis
Special cases: Some expressions are not self-determined even though they seem to be. Then the
expression takes the width of the higher-level context (for example, the left-hand side of an assignment).
// concatenation expression (9 bits) expanded to 16 bits assign a_sgn = $signed({tc & a[7], a});
assign z = $signed({tc & a[7], a}) * assign b_sgn = $signed({tc & b[7], b});
$signed({tc & b[7], b}); assign z = a_sgn * b_sgn;
// -> 16x16=16 bit multiply // -> 9x9=16 bit multiply
Rule: Avoid using self-determined expressions. Use intermediate signals and additional assignments to make the
widths of arithmetic expressions unambiguous (context-determined expressions).
Checks:
Resources report: Check for implemented datapath blocks and size of input/output operands (see
resources report).
Tool Support: (partial) Design Compiler supports simple cases (like the "bad QoR" example above) where inputs
just get extended. But it is thinkable that in more complex expressions these effects have more impact and can
cause worse extraction and QoR.
VHDL Guidelines
6. Numeric packages (VHDL)
Rule: Use the official IEEE numeric package 'ieee.numeric_std' for numeric types and functions (the Synopsys
package 'ieee.std_logic_arith' is an acceptable alternative). Do not use several numeric packages at a time.
Rationale: Unambiguously specify whether arithmetic operations are unsigned or signed (2's complement).
Example:
Alternative 1 Alternative 2
Checks:
Resources report: Check for implemented datapath blocks and type of operands (see resources report).
https://solvnet.synopsys.com/retrieve/print/015771.html 6/19
1/16/13 Coding Guidelines for Datapath Synthesis
Rule: Cluster related datapath portions in the RTL code into a single combinational block. Do not separate them
into different blocks. In particular,
Keep related datapath portions within one single hierarchical component. Do not distribute them into
different levels or subcomponents of your design hierarchy.
Do not place registers between related datapath portions. If registers are required inside a datapath block
to meet QoR requirements, use retiming to move the registers to the optimal location after the entire
datapath block has been implemented (see guideline on Pipelining).
Note: Related datapath portions are portions of RTL code that describe datapath functionality
and that allow for certain optimizations/sharings if implemented together. This includes
datapath portions that share common inputs or that feed each other (that is, the output of one
datapath is used as input to another datapath), as well as datapath portions that have
mutually exclusive operations that can possibly be shared.
Rationale: Better QoR because bigger datapath blocks can be extracted and synthesized.
Checks:
Resources report: Check for the number and functionality of implemented datapath blocks (see resources
report).
Datapath extraction analysis: Message issued when sequential cells block extraction.
Tool Support: If datapath portions are spread across several levels of hierarchy, the blocks can be manually
ungrouped (ungroupcommand) before compilation in order to move all datapath portions into the same hierarchy
level.
Rule: Do not mix unsigned and signed types in a datapath cluster (that is, several expressions that form one
single complex datapath). Use signedports/signals or cast unsigned ports/signals to signed (using '$signed') to
make sure that all operands are signed in a signed datapath.
Rationale: Worse QoR because unsigned and signed operations are not merged together to form one single
datapath block (synthesis restriction).
Checks:
Elaboration warnings: Check for warnings about implicit signed-to-unsigned conversions (see warning).
https://solvnet.synopsys.com/retrieve/print/015771.html 7/19
1/16/13 Coding Guidelines for Datapath Synthesis
Resources report: Check for implemented datapath blocks and the operations they implement (see
resources report).
Datapath extraction analysis: Message issued when datapath leakage due to sign mismatch blocks
extraction.
Tool Support: (full) Mixed-sign extraction is now fully supported in Design Compiler. Datapath extraction can still
be blocked when mixed-sign expressions lead to datapath leakage.
Rule: Use selective zero-/sign-extension for implementing switchable unsigned/signed datapath (that is, a
datapath that can operate on unsigned or signed operands alternatively, controlled by a switch).
Rationale: Better QoR as compared to having two datapaths (unsigned and signed) followed by a selector.
Checks:
Resources report: Check for implemented datapath blocks and size/type of operands (see resources
report).
Rule: Make use of POS expressions (that is, add-multiply structures, "(a + b) * c").
Rationale: Synthesis can implement POS expressions efficiently by using carry-save multipliers (for example, a
multiplier that allows one input to be in carry-save format) without performing a carry-propagation before the
multiply. Better QoR is often achieved when compared to alternative expressions that try to avoid the POS
structure.
Note: Synthesis of increment-multiply structures (for example, "(a + ci) * c" with 'ci' being a single bit) is
especially efficient (same QoR as a regular multiply "a * c" when using Booth recoding).
https://solvnet.synopsys.com/retrieve/print/015771.html 8/19
1/16/13 Coding Guidelines for Datapath Synthesis
// trick for handling increment with regular multiplier // POS expression uses carry-save multiplier
assign z = a * b + (ci ? b : 0); assign z = (a + ci) * b;
Tool Support: (partial) Depending on how different the code is when using or avoiding POS Design Compiler can
give similar or very different QoR. If the code is very different, it is not possible to synthesize the same datapath
with same QoR.
Rule: Do not instantiate arithmetic DesignWare components if possible (for example, for explicitly forcing carry-
save format on intermediate results). Write arithmetic expressions in RTL instead. Also, do not hand-craft
arithmetic circuits with logic gates (logic operators or GTECH cells).
Rationale: Better QoR can be obtained from RTL expressions by exploiting the full potential of datapath
extraction and synthesis (for example, by using implicit carry-save formats internally).
Checks:
Resources report: Check for implemented datapath blocks (see resources report).
Datapath extraction analysis: Message issued when DW component instantiations block extraction.
Tool Support: (none) Instantiated DesignWare components are currently excluded from datapath extraction in
Design Compiler.
12. Pipelining
https://solvnet.synopsys.com/retrieve/print/015771.html 9/19
1/16/13 Coding Guidelines for Datapath Synthesis
12. Pipelining
Rule: For pipelining of datapaths, place the pipeline registers at the inputs or outputs of the RTL datapath code
and use retiming ('optimize_registers' in Design Compiler; see "Design Compiler Reference Manual: Register
Retiming") to move them to the optimal locations. Do not use DesignWare component instantiations and place the
registers manually.
Rationale: Better QoR can be obtained if datapath synthesis can first implement the entire datapath blocks
(without interfering registers) and later move the registers to the optimal locations.
Rule: Do not complement (negate) operands manually by inverting all bits and adding a '1' (for example, "a_neg =
~a + 1"). Instead, arithmetically complement operands by using the '-' operator (for example, "a_neg = -a").
Rationale: Manual complementing is not always recognized as an arithmetic operation and therefore can limit
datapath extraction and result in worse QoR. Arithmetically complemented operands can easily be extracted as
part of a bigger datapath.
Tool Support: (partial) Design Compiler converts simple manual complements (like "a_neg = ~a + 1") into
negations/subtractions ("a_neg = -a"). But it doesn't optimize more complex cases as in the example below.
https://solvnet.synopsys.com/retrieve/print/015771.html 10/19
1/16/13 Coding Guidelines for Datapath Synthesis
negations/subtractions ("a_neg = -a"). But it doesn't optimize more complex cases as in the example below.
Note: When a complement and a multiplication are involved, it is often beneficial to do the complement at the
inputs rather than the output (see examples in the following guideline). In simple cases this is done automatically
by Design Compiler.
Note: There are special arithmetic optimizations that are currently not automatically carried out by datapath
synthesis but that can potentially improve QoR. With some understanding of the datapath synthesis capabilities
and some experience in arithmetics, different solutions can be found that can give better results.
Example: Conditionally add/subtract a product -> conditionally complement one multiplier input (Verilog)
// manual complement prevents SOP extraction // complement multiplier using (+1/-1) multiply
assign p = a * b; assign z = ($signed({sign, 1'b1}) * a) * b + c;
assign z = (sign ? ~p : p) + // -> SOP (complement + carry-save multiply + add)
$signed({1'b0, sign}) + c;
// -> multiply + select + 3-operand add
Tool Support: (partial) Only certain high-level transformation of this kind are done automatically. The simple
transformation to move a complement from the output of a multiplier to the input is supported by Design Compiler.
In more complex cases an automatic transformation might not be feasible.
Note: Parallel constant multipliers, as in the example below, can be optimized for area by implementing them using
shifts and adds and sharing common constant terms.
Example:
Tool Support: (full) The above transformation to optimize for area (power) is done automatically in Design
Compiler. There is no need to optimize parallel constant multipliers in the RTL code.
https://solvnet.synopsys.com/retrieve/print/015771.html 11/19
1/16/13 Coding Guidelines for Datapath Synthesis
Note: Common subexpressions among different arithmetic expressions can be shared (to improve area) or
unshared (to improve timing).
Example:
Tool Support: (full) Unsharing (to optimize for timing) and sharing (to optimize for area) is automatically done in
Design Compiler based on the timing context, no matter whether sharing is done in the RTL code or not. Therefore
the two code examples will result in the same QoR.
17. Rounding
Note: The choice of rounding mode as well as how it is implemented can affect datapath extraction. All
asymmetric rounding modes can be implemented by adding constant bits at certain locations, resulting in optimal
datapath extraction. However, the symmetric (unbiased) rounding modes require accessing individual (variable)
bits from the operand to be rounded, which in turn requires this operand to be in binary representation and
therefore blocks extraction.
Rule: Use asymmetric rounding whenever possible. Perform asymmetric rounding by adding constant bits only.
Rule: Implement rounding mode 'round half up' by adding a constant 1 at bit position lsb-1. Do not add variable
bits for rounding if possible.
Rationale: Adding constant bits allows better datapath extraction and gives better QoR. Adding variable bits
https://solvnet.synopsys.com/retrieve/print/015771.html 12/19
1/16/13 Coding Guidelines for Datapath Synthesis
Rationale: Adding constant bits allows better datapath extraction and gives better QoR. Adding variable bits
requires binary conversion and can block datapath extraction.
Example:
Checks:
Resources report: Check for the number and functionality of extracted datapath blocks (see resources
report).
Tool Support: (Partial) In some simple cases the tool is able to do automatic conversion.
All rounding modes from the table above are available in DesignWare Datapath Functions (bottom of the
document) that are implemented for best possible datapath extraction and QoR.
Saturation therefore is a QoR trade-off. Doing saturation at certain locations in a datapath where operand widths
can be reduced significantly can be beneficial. However, excessive saturation on many operands with small width
reductions however can hurt QoR more than it helps.
Rule: Avoid excessive saturation on internal operands to reduce operand widths. Better carry some extra bits
further and saturate at the end. Only do saturation when the width reduction is significant.
Example:
Checks:
Resources report: Check for the number and functionality of extracted datapath blocks (see resources
report).
https://solvnet.synopsys.com/retrieve/print/015771.html 13/19
1/16/13 Coding Guidelines for Datapath Synthesis
Note: datapath leakage is when an internal operand is not wide enough to store the result of an operation, but
the full result is required later. This is caused by upper-bit truncation followed by a later extension.
Upper-bit truncation
Truncated MSB is required but not there for correct extension → arithmetically incorrect results
True leakage: internal operand is not wide enough to hold all values that can occur in an application
→ incorrect behavior (e.g. in simulation).
False leakage: internal operand is wide enough to hold all values that can occur in an application →
correct behavior.
Synthesis cannot distinguish between the two → all leakage can impact synthesis.
Conversion of a signed into an unsigned operand → operand has always upper-bit truncation.
Rule: Avoid upper-bit truncation that results in datapath leakage on internal results. Make internal operands wide
enough to hold the result of the driving operation (also for false leakage).
Rule: For unsigned subtractions make sure the resulting operand is as wide as the final result of the datapath
(i.e. it is not followed by an extension that would result in leakage).
Example:
https://solvnet.synopsys.com/retrieve/print/015771.html 14/19
1/16/13 Coding Guidelines for Datapath Synthesis
assign p = a * b + c; // 8*8+8=17 bits, assigned to 17 bits
// used in 17 bit expression (extended) -> datapath leakage assign p = a * b + c;
assign z = p + d; // used in 17 bit expression -> no datapath leakage
// -> 2 carry-propagations assign z = p + d;
// -> 1 carry-propagation
Checks:
Resources report: Check for the number and functionality of extracted datapath blocks (see
resources report).
Datapath extraction analysis: Message issued when datapath leakage blocks extraction.
Synthesis Reports
Design Compiler gives feedback on potential problems and on how datapaths were synthesized through several reports.
⇓
elaborate test ⇒ RTL elaboration warnings
⇓
analyze_datapath_extraction ⇒ Datapath extraction analysis
⇓
compile_ultra
⇓
analyze_datapath
report_resources -hier ⇒ Datapath synthesis reports
output [7:0] z;
assign z = a + b;
https://solvnet.synopsys.com/retrieve/print/015771.html 15/19
1/16/13 Coding Guidelines for Datapath Synthesis
Note: These warnings can indicate unwanted behavior (is the conversion / assignment really meaningful?). When
this behavior is wanted, the warnings can be avoided with the explicit type casts in the examples above.
Datapath extraction analysis can be run before a design is compiled to get the following information:
This feature is very useful to get quick feedback on datapath extraction without running a time-consuming full
compilation.
Note: Only coding guidelines that affect datapath extraction can be checked. The presence of messages does not
always mean the code can be improved. Also, the absence of messages does not mean everything is optimal.
Command:
Option -no_autoungroup: Corresponds to the same option of the compile_ultracommand. When this option is
used during compile it must also be used during datapath extraction analysis in get the same datapath extraction.
Option -no_report: By default this command prints out a resources report (similar to report_resources) at the
end for matching resources names. With this option the resources report is suppressed (much shorter output).
Messages:
Example:
Availability:
Command:
analyze_datapath
https://solvnet.synopsys.com/retrieve/print/015771.html 16/19
1/16/13 Coding Guidelines for Datapath Synthesis
analyze_datapath
Summary of number and area contribution of DW components and datapath blocks (percentage of total area
given).
Summary of number and type of instantiated and inferred DesignWare components (singletons).
Singletons:
out width
component count min max ave
----------------------------------------
DW01_add 11 10 16 13.2
DW01_sub 5 9 12 10.4
DW01_inc 2 6 6 6.0
DW01_dec 4 6 8 7.0
DW_cmp 2 16 20 18.0
DW_leftsh 1 12 12 12.0
DW_rightsh 3 5 12 8.6
DW_mult_uns 1 44 44 44.0
DW_mult_tc 4 8 12 11.0
Summary of number and type of operators that are extracted into datapath blocks.
Extracted Datapaths:
out width
operation count min max ave
----------------------------------------
+- 9 4 40 23.9
* 3 27 35 31.3
? 2 16 40 28.0
<< >> 20 12 16 13.8
== != 2 14 15 14.5
< <= > >= 1 15 15 15.0
Note: for comparators the input width is given (output is always just 1 bit).
Resources Report
Command:
report_resources -hier
assign x = a * b;
assign t = c * d;
assign y = (s ? -t : t) + e;
endmodule
https://solvnet.synopsys.com/retrieve/print/015771.html 17/19
1/16/13 Coding Guidelines for Datapath Synthesis
Example Resources Report: Report for complex datapath and singleton component
Implementation Report
Report of the
========================================================================= implementation for each
| | | Current | Set | module.
| Cell | Module | Implementation | Implementation |
========================================================================= 'str' is the generic name
| DP_OP_6_296_5095 | DP_OP_6_296_5095 | str (area) | | for the flexible SOP/POS
| mult_x_8_1 | DW_mult_tc | pparch | | implementation that is
========================================================================= used for all complex
datapath blocks. In
parenthesis the
optimization goal during
datapath generation is
given (such as 'area',
'speed', 'area,speed',
'power', 'power,speed').
https://solvnet.synopsys.com/retrieve/print/015771.html 18/19
1/16/13 Coding Guidelines for Datapath Synthesis
© 2012 Synopsys, Inc. 2012-06-01
https://solvnet.synopsys.com/retrieve/print/015771.html 19/19