Verilog descriptions are mapped to logic by the creation of blocks of combinatorial circuits and storage elements. A statement or an operator in a Verilog function can represent a block of combinatorial logic or, in some cases, a latch or register.
The description fragment shown in the following example represents four logic blocks.
if (b < 10)
y = a + b;
else
y = a + 10;
The logic blocks created by Foundation Express are custom-built for their environment. That is, if a and b are 4-bit quantities, a 4-bit adder is built. If a and b are 9-bit quantities, a 9-bit adder is built. Because Foundation Express incorporates a large set of these customized logic blocks, it can translate most Verilog statements and operators.
Foundation Express provides significant control over the preoptimization structure, or organization of components, in your design. Whether or not your design structure is preserved after optimization depends on the options you select. Foundation Express automatically chooses the best structure for your design. You can view the preoptimized structure in the schematic window and then correlate it back to the original HDL source code.
You control structure by the way you order assignment statements and the way you use variables. Each Verilog assignment statement implies a piece of logic. The following examples illustrate two possible descriptions of an adder's carry chain. The second example results in a ripple carry implementation, as in the first example. The third example has more structure (gates), because the HDL source includes temporary registers, and it results in a carry-lookahead implementation, as in the second example.
// a is the addend
// b is the augend
// c is the carry
// cin is the carry in
c0 = (a0 & b0) |
(a0 | b0) & cin;
c1 = (a1 & b1) |
(a1 | b1) & c0;
// p's are propagate
// g's are generate
p0 = a0 | b0;
g0 = a0 & b0;
p1 = a1 | b1;
g1 = a1 & b1;
c0 = g0 | p0 & cin;
c1 = g1 | p1 & g0 | p1 & p0 & cin;
You can also use parentheses to control the structure of complex components in a design. Foundation Express uses parentheses to define logic groupings. The following two examples illustrate two groupings of adders. The circuit diagrams show how grouping the logic affects the way the circuit is synthesized. When the first example is parsed, (a + b) is grouped together by default, then c and d are added one at a time.
z = a + b + c + d;
z = (a + b) + (c + d);
Note: Manual or automatic resource sharing can also affect the structure of a design.
In many circumstances, you can improve the quality of synthesized circuits by better describing your high-level knowledge of a circuit. Foundation Express cannot always derive details of a circuit architecture. Any additional architectural information you can provide to Foundation Express can result in a more efficient circuit.
Foundation Express uses the properties of arithmetic operators (such as the associative and commutative properties of addition) to rearrange an expression so that it results in an optimized implementation. You can also use arithmetic properties to control the choice of implementation for an expression. Three forms of arithmetic optimization are discussed in this section.
If your goal is to speed up your design, arithmetic optimization can minimize the delay through an expression tree by rearranging the sequence of the operations. Consider the statement in the following example.
Z <= A + B + C + D;
The parser performs each addition in order, as though parentheses were placed as shown, and constructs the expression tree shown in the following figure:
Z <= ((A + B) + C) + D);
If all signals arrive at the same time, the critical path can be reduced to two adders.
Z <= (A + B) + (C + D);
The parser evaluates the expressions in parentheses first and constructs a balanced adder tree, as shown in the following figure.
.
Suppose signals B, C, and D arrive at the same time and signal A arrives last. The expression tree that produces the minimum delay is shown in the following figure.
You can use parentheses in expressions to exercise more control over the way expression trees are constructed. Parentheses are regarded as user directives that force an expression tree to use the groupings inside the parentheses. The expression tree cannot be rearranged to violate these groupings.
To illustrate the effect of parentheses on the construction of an expression tree, consider the following example.
Q <= ((A + (B + C)) + D + E) + F;
The parentheses in the expression in the above example define the following subexpressions, whose numbers correspond to those in the figure following the example:
1 (B + C)
2 (A + (B + C))
3 ((A + (B + C)) + D + E)
These subexpressions must be preserved in the expression tree. The default expression tree for the above examples are shown in the following figure.
When Foundation Express performs arithmetic optimization, it considers how to handle the overflow from carry bits during addition. The optimized structure of an expression tree is affected by the bit-widths you declare for storing intermediate results. For example, suppose you write an expression that adds two 4-bit numbers and stores the result in a 4-bit register. If the result of the addition overflows the 4-bit output, the most significant bits are truncated. The following example shows how Foundation Express handles overflow characteristics.
t <= a + b; // a and b are 4-bit numbers
z <= t + c; // c is a 6-bit number
In the above example, three variables are added (a + b + c). A temporary variable, t, holds the intermediate result of a + b. Suppose t is declared as a 4-bit variable so the overflow bits from the addition of a + b are truncated. The parser determines the default structure of the expression tree, which is shown in the following figure.
Now suppose the addition is performed without a temporary variable (z = a + b + c). Foundation Express determines that five bits are needed to store the intermediate result of the addition, so no overflow condition exists. The results of the final addition might be different from the first case, where a 4-bit temporary variable is declared that truncates the result of the intermediate addition. Therefore, these two expression trees do not always yield the same result. The expression tree for the second case is shown in the following figure.
Subexpressions consist of two or more variables in an expression. If the same subexpression appears in more than one equation, you might want to share these operations to reduce the area of your circuit. You can force common subexpressions to be shared by declaring a temporary variable to store the subexpression, then use the temporary variable wherever you want to repeat the subexpression. The following example shows a group of simple additions that use the common subexpression (a + b).
temp <= a + b;
x <= temp;
y <= temp + c;
Instead of manually forcing common subexpressions to be shared, you can let Foundation Express automatically determine whether sharing common subexpressions improves your circuit. You do not need to declare a temporary variable to hold the common subexpression in this case.
In some cases, sharing common subexpressions results in more adders being built. Consider the following example, where A + B is a common subexpression.
if cond1
Y <= A + B;
else
Y <= C + D;
end;
if cond2
Z <= E + F;
else
Z <= A + B;
end;
If the common subexpression A + B is shared, three adders are needed to implement the following section of code.
(A + B)
(C + D)
(E + F)
If the common subexpression is not shared, only two adders are needed: one to implement the additions A + B and C + D and one to implement the additions E + F and A + B.
Foundation Express analyzes common subexpressions during the resource sharing phase of the compile command and considers area costs and timing characteristics. To turn off the sharing of common subexpressions for the current design, use the constraint manager.
The Foundation Express parser does not identify common subexpressions unless you use parentheses or write them in the same order. For example, the two equations in the following example use the common subexpression A + B.
Z <= D + A + B;
The parser does not recognize A + B as a common subexpression, because it parses the second equation as (D + A) + B. You can force the parser to recognize the common subexpression by rewriting the second assignment statement as
Z <= A + B + D;
or
Z <= D + (A + B);
Note: You do not have to rewrite the assignment statement, because Foundation Express recognizes common subexpressions automatically.
You can improve circuits by using operators more carefully. In the following example, the adder sums the 8-bit value of a with the lower 4 bits of temp. Although temp is declared as an 8-bit value, the upper 4 bits of temp are always 0, so only the lower 4 bits of temp are needed for the addition.
You can simplify the addition by changing temp to temp [3:0], as shown in the following example. Now, instead of using eight full adders to perform the addition, four full adders are used for the lower 4 bits and four half adders are used for the upper 4 bits. This yields a significant savings in circuit area.
input [7:0] a,b;
output [8:0] y;
function [8:0] add_lt_10;
input [7:0] a,b;
reg [7:0] temp;
begin
if (b < 10)
temp = b;
else
temp = 10;
add_lt_10 = a + temp [3:0]; // use [3:0] for temp
end
endfunction
assign y = add_lt_10(a,b);
endmodule
When you build finite state machines, you can often specify a constant value of a signal in a particular state. You can write your Verilog description so that Foundation Express produces a more efficient circuit.
The following example shows the Verilog description of a simple finite state machine.
module machine (x, clock, current_state, z);
input x, clock;
output [1:0] current_state;
output z;
reg [1:0] current_state;
reg z;
/* Redeclared as reg so they can be assigned to in always statements. By default, ports are wires and cannot be assigned to in 'always' */
reg [1:0] next_state;
reg previous_z;
parameter [1:0] set0 = 0,
hold0 = 1,
set1 = 2;
always @ (x or current_state) begin case (current_state)
//synopsys full_case
/* declared full_case to avoid extraneous latches */
set0:
begin
z = 0 ; //set z to 0
next_state = hold0;
end
hold0:
begin
z = previous_z; //hold value of z
if (x == 0)
next_state = hold0;
else
next_state = set1;
end
set1:
begin
z = 1; //set z to 1
next_state = set0;
end
endcase
end
always @ (posedge clock) begin
current_state = next_state;
previous_z = z;
end
endmodule
In the state hold0, the output z retains its value from the previous state. To synthesize this circuit, a flip-flop is inserted to hold the state previous_z. However, you can make some assertions about the value of z. In the state hold0, the value of z is always 0. This can be deduced from the fact that the state hold0 is entered only from the state set0, where z is always assigned the value 0.
The following example shows how the Verilog description can be changed to use this assertion, resulting in a simpler circuit (because the flip-flop for previous_z is not required). The changed line is shown in bold.
module machine (x, clock, current_state, z);
input x, clock;
output [1:0] current_state;
output z;
reg [1:0] current_state;
reg z;
/* Redeclared as reg so they can be assigned to in always statements. By default, ports are wires and cannot be assigned to in 'always'
*/
reg [1:0] next_state;
parameter [1:0] set0 = 0,
hold0 = 1,
set1 = 2;
always @ (x or current_state) begin
case (current_state) //synopsys full_case
/* declared full_case to avoid extraneous latches */
set0:
begin
z = 0 ; //set z to 0
next_state = hold0;
end
hold0:
begin
z = 0; //hold z at 0
if (x == 0)
next_state = hold0;
else
next_state = set1;
end
set1:
begin
z = 1; //set z to 1
next_state = set0;
end
endcase
end
always @ (posedge clock) begin
current_state = next_state;
end
endmodule
You can use an implicit state style or an explicit state style to describe a state machine. In the implicit state style, a clock edge (negedge or posedge) signals a transition in the circuit from one state to another. In the explicit state style, you use a constant declaration to assign a value to all states. Each state and its transition to the next state are defined under the case statement. Use the implicit state style to describe a single flow of control through a circuit (where each state in the state machine can be reached only from one other state). Use the explicit state style to describe operations such as synchronous resets.
The following example shows a description of a circuit that sums data over three clock cycles. The circuit has a single flow of control, so the implicit style is preferable.
module sum3 ( data, clk, total );
input [7:0] data;
input clk;
output [7:0] total;
reg total;
always
begin
@ (posedge clk)
total = data;
@ (posedge clk)
total = total + data;
@ (posedge clk)
total = total + data;
end
endmodule
Note: With the implicit state style, you must use the same clock phase (either posedge or negedge) for each event expression. Implicit states can be updated only if they are controlled by a single clock phase.
The following example shows a description of the same circuit in the explicit state style. This circuit description requires more lines of code than the previous example, although Foundation Express synthesizes the same circuit for both descriptions.
module sum3 ( data, clk, total );
input [7:0] data;
input clk;
output [7:0] total;
reg total;
reg [1:0] state;
parameter S0 = 0, S1 = 1, S2 = 2;
always @ (posedge clk)
begin
case (state)
S0: begin
total = data;
state = S1;
end
S1: begin
total = total + data;
state = S2;
end
default : begin
total = total + data;
state = S0;
end
endcase
end
endmodule
The following example shows a description of the same circuit with a synchronous reset added. This example is coded in the explicit state style. Notice that the reset operation is addressed once before the case statement.
module SUM3 ( data, clk, total, reset );
input [7:0] data;
input clk, reset;
output [7:0] total;
reg total;
reg [1:0] state;
parameter S0 = 0, S1 = 1, S2 = 2;
always @ (posedge clk)
begin
if (reset)
state = S0;
else
case (state)
S0:begin
total = data;
state = S1;
end
S1:begin
total = total + data;
state = S2;
end
default : begin
total = total + data;
state = S0;
end
endcase;
end
endmodule
The following example shows how to describe the same function in the implicit state style. This style is not as efficient for describing synchronous resets. In this case, the reset operation has to be addressed for every always @ statement.
module SUM3 ( data, clk, total, reset );
input [7:0] data;
input clk, reset;
output [7:0] total;
reg total;
always
begin: reset_label
@ (posedge clk)
if (reset)
begin
total = 8'b0;
disable reset_label;
end
else
total = data;
@ (posedge clk)
if (reset)
begin
total = 8'b0;
disable reset_label;
end
else
total = total + data;
@ (posedge clk)
if (reset)
begin
total = 8'b0;
disable reset_label;
end
else
total = total + data;
end
endmodule
In an always block that is triggered by a clock edge, every variable that has a value assigned has its value held in a flip-flop.
Organize your Verilog description so you build only as many registers as you need. The following example shows a description where extra registers are implied.
module count (clock, reset, and_bits, or_bits, xor_bits);
input clock, reset;
output and_bits, or_bits, xor_bits;
reg and_bits, or_bits, xor_bits;
reg [2:0] count;
always @(posedge clock) begin
if (reset)
count = 3'60;
else
count = count + 1;
and_bits = & count;
or_bits = | count;
xor_bits = ^ count;
end
endmodule
This description implies the use of six flip-flops: three to hold the values of count and one each to hold and_bits, or_bits, and xor_bits. However, the values of the outputs and_bits, or_bits, and xor_bits depend solely on the values of count. Because count is registered, there is no reason to register the three outputs. The synthesized circuit is shown in the following figure.
To avoid implying extra registers, you can assign the outputs from within an asynchronous always block. The following example shows the same logic described with two always blocks, one synchronous and one asynchronous, which separate registered or sequential logic from combinatorial logic. This technique is useful for describing finite state machines. Signal assignments in the synchronous always block are registered. Signal assignments in the asynchronous always block are not. Therefore, this version of the design uses three fewer flip-flops than the version in the above example.
module count (clock, reset, and_bits, or_bits, xor_bits);
input clock, reset;
output and_bits, or_bits, xor_bits;
reg and_bits, or_bits, xor_bits;
reg [2:0] count;
always @(posedge clock) begin//synchronous
if (reset)
count = 3'b0;
else
count = count + 1;
end
always @(count) begin//asynchronous
and_bits = & count;
or_bits = | count;
xor_bits = ^ count;
end
endmodule
The more efficient version of the circuit is shown in the following figure.
To compute values synchronously and store them in flip-flops, set up an always block with a signal edge trigger. To let other values change asynchronously, make a separate always block with no signal edge trigger. Put the assignments you want clocked in the always block with the signal edge trigger and the other assignments in the other always block. This technique is used for creating Mealy machines, such as the one in the following example. Note that out changes asynchronously with in1 or in2.
module mealy (in1, in2, clk, reset, out);
input in1, in2, clk, reset;
output out;
reg current_state, next_state, out;
always @(posedge clk or negedge reset)
// state vector flip-flops (sequential)
if (!reset)
current_state = 1'b0;
else
current_state = next_state;
always @(in1 or in2 or current_state)
// output and state vector decode (combinatorial)
case (current_state)
0: begin
next_state = 1;
out = 1'b0;
end
1: if (in1) begin
next_state = 1'b0;
out = in2;
end
else begin
next_state = 1'b1;
out = !in2;
end
endcase
endmodule
The schematic for this circuit is shown in the following figure.