Foundation Express supports the following function statements.
Procedural assignments are assignment statements used inside a function. They are similar to the continuous assignment statements described in the Structural Descriptions chapter except that the left side of a procedural assignment can contain only reg variables and integers. Assignment statements set the value of the left side to the current value of the right side. The right side of the assignment can contain any arbitrary expression of the data types described in the Structural Descriptions chapter including simple constants and variables.
The left side of the procedural assignment statement can contain only the following data types.
Assignments are made bit-wise, with the low bit on the right side assigned to the low bit on the left side.
Multiple procedural assignments are allowed. The following example shows procedural assignments.
sum=a + b;
control[5]=(instruction==8'h2e);
{carry_in,a[7:0]}=9'h 120;
Procedural assignments in Verilog can be blocking in nature. For example, you can assign a delay of five time units with the following statement.
rega=#5 arg1 + arg2;
The expression arg1 + arg2 is evaluated, then execution is suspended for five time units before the assignment is performed and the next statement is processed. Execution of the next statement is blocked until the current statement's execution is completed.
On the other hand, RTL assignments let you define nonblocking procedural assignments with timing controls. If you use a nonblocking RTL assignment statement instead of the procedural assignment (as shown below), the sum is computed immediately, but the assignment is done after the five time-unit delay.
rega<=s#5 arg1 + arg2;
However, execution proceeds without waiting for the assignment to finish. Foundation Express ignores intra- and inter-assignment delays; therefore, the RTL assignment behaves like the blocking procedural assignment in this case.
To illustrate the difference in behavior between RTL assignments and blocking procedural assignments, consider the following two examples (and their resulting circuits) where there are multiple assignments. The first example shows RTL assignments.
regc<=data;
regd<=regc;
end
Figure 5.1 Schematic of RTL Assignments |
The above example is a description of a serial register implemented with RTL assignments. The recently assigned value of regc, which is data, is assigned to regd as the schematic in the figure above indicates. If blocking assignments are used, as in the figure below, a serial register is not synthesized because assignments are executed before proceeding.
The following example shows a blocking assignment.
always @(posedge clk) begin
rega=data
regb=rega;
end
Figure 5.2 Schematic of Blocking Assignment |
The following restrictions apply to RTL assignments.
reg b,c;
always begin
b<=#4a; //RTL assignment
c=#3b; //procedure assignment with
//blocking delay
end
Block statements are a way of syntactically grouping several statements into a single statement.
In Verilog, sequential blocks are delimited by the keywords begin and end. These begin...end blocks are commonly used in conjunction with if, case, and for statements to group several statements together. Functions and always blocks that contain more than one statement require a begin...end block to group the statements. Verilog also supplies a construct called a named block, as shown in the example below.
begin : block_name
reg local_variable_1;
integer local_variable_2;
parameter local variable_3;
... statements...
end
In Verilog, no semicolon (;) follows the begin or end keywords. You identify named blocks by following the begin keyword with a colon (:) and a block_name, as shown. You can use Verilog syntax to declare variables locally in a named block. You can include reg, integer, and parameter declarations within a named block but not in an unnamed block. You can use named blocks to use the disable statement.
The if...else statements execute a block of statements according to the value of one or more expressions.
The syntax of if...else statements follows.
if (expr)
begin
... statements...
end
else
begin
... statements...
end
The if statement consists of the keyword if, followed by an expression enclosed in parentheses. The if statement is followed by a statement or block of statements enclosed with the begin and end keywords. If the value of the expression is nonzero, the expression is true, and the statement block that follows is executed. If the value of the expression is zero, the expression is false, and the statement block that follows is not executed.
An optional else statement can follow an if statement. If the expression following the if keyword is false, the statement or block of statements following the else keyword is executed.
The if...else statements can cause registers to be synthesized. Registers are synthesized when you do not assign a value to the same reg variable in all branches of a conditional construct. Information on registers is detailed in the Register and Three-State Inference chapter.
Foundation Express synthesizes multiplexer logic (or similar select logic) from a single if statement. The conditional expression in an if statement is synthesized as a control signal to a multiplexer, which determines the appropriate path through the multiplexer. For example, the statements in the following example create multiplexer logic controlled by c and place either a or b in the variable x.
if (c)
x=a;
else
x=b;
The following example illustrates how if and else can be used to create an arbitrarily long if...else if...else structure.
begin
carry_in=0;
complement_arg=0;
end
else if(instruction==SUB)
begin
carry_in=1;
complement_arg = 1;
end
else
illegal_instruction=1;
The following example shows nested if and else statements.
if (select[1])
begin
if (select[0]) out=in[3];
else out=in[2];
end
else
begin
if(select[0]) out=in[1];
else out=in[0];
end
Foundation Express can synthesize a latch for a conditionally assigned variable. If a path exists that does not explicitly assign a value to a variable, the variable is conditionally assigned. See the Register and Three-State Inference chapter for more information.
In the following example, the variable value is conditionally driven. If c is not true, value is not assigned, and c retains its previous value.
always begin
if (c) begin
value=x;
end
Y=value;//causes a latch to be synthesized for
//value
end
The case statement is similar in function to the if...else conditional statement. The case statement allows a multipath branch in logic that is based on the value of an expression. One way to describe a multicycle circuit is with a case statement (see the case statement example after the case statement syntax). Another way is with multiple @ (clock-edge) statements, which are discussed later in this section.
The syntax for a case statement is shown below.
case (expr)
case_item1:begin
...statements...
end
case_item2:begin
...statements...
end
default:begin
...statements...
end
endcase
The case statement consists of the keyword case, followed by an expression in parentheses, followed by one or more case items (and associated statements to be executed), followed by the keyword endcase. A case item consists of an expression (usually a simple constant) or a list of expressions separated by commas, followed by a colon (:).
The expression following the case keyword is compared with each case item expression, one by one. When the expressions are equal, the condition evaluates to TRUE. Multiple expressions separated by commas can be used in each case item. When multiple expressions are used, the condition is said to be TRUE if any of the expressions in the case item match the expression following the case keyword.
The first case item that evaluates to TRUE determines the path. All subsequent case items are ignored, even if they are true. If no case item is true, no action is taken. You can define a default case item with the expression default, which is used when no other case item is true.
The following example shows a case statement.
case (state)
IDLE: begin
if (start)
next_state = STEP1;
else
next_state = IDLE;
end
STEP1: begin
/* do first state processing here */
next_state = STEP2;
end
STEP2: begin
/* do second state processing here */
next_state = IDLE;
end
endcase
Foundation Express automatically determines whether a case statement is full or parallel. A case statement is referred to as full case if all possible branches are specified. If you do not specify all possible branches, but you know that one or more branches can never occur, you can declare a case statement as full case with the //synopsys full_case directive. Otherwise, Foundation Express synthesizes a latch. See the Foundation Express Compiler Directives chapter for more information about full_case directives.
Foundation Express synthesizes optimal logic for the control signals of a case statement. If Foundation Express cannot statically determine that branches are parallel, it synthesizes hardware that includes a priority encoder. If Foundation Express can determine that no cases overlap (parallel case), a multiplexer is synthesized, because a priority encoder is not necessary. You can also declare a case statement as parallel case with the //synopsys parallel_case directive. Refer to the Foundation Express Compiler Directives chapter for information about parallel_case directives.
The following example is a case statement that is both full and parallel and does not result in either a latch or a priority encoder.
input [1:0] a;
always @(a or w or x or y or z) begin
case (a)
2'b11:
b = w ;
2'b10:
b = x ;
2'b01:
b = y ;
2'b00:
b = z ;
endcase
end
The following example shows a case statement that is parallel but not full that is missing branches for the cases 2'b01 and 2'b10. This example infers a latch for b.
input [1:0] a;
always @(a or w or z) begin
case (a)
2'b11:
b = w ;
2'b00:
b = z ;
endcase
end
The case statement in the following example is not parallel or full, because the input values of w and x cannot be determined. However, if you know that only one of the inputs equals 2'b11 at a given time, you can use the // synopsys parallel_case directive to avoid synthesizing a priority encoder. If you know that either w or x always equals 2'b11 (a situation known as a one-branch tree), you can use the //synopsys full_case directive to avoid synthesizing a latch.
always @( w or x) begin
case (2'b11)
w:
b = 10 ;
x:
b = 01 ;
endcase
end
The casex statement allows a multipath branch in logic according to the value of an expression, just like the case statement. The differences between the case statement and the casex statement are the keyword and the processing of the expressions.
The syntax for a casex statement follows.
casex (expr)
case_item1 : begin
...statements...
end
case_item2 : begin
...statements...
end
default : begin
...statements...
end
endcase
A case item can have expressions consisting of the following.
When a z, x, or ? appears in a case-item expression, it means that the corresponding bit of the casex expression is not compared. The following example shows a case item that includes an x.
reg [3:0] cond;
casex (cond)
4'b100x: out = 1;
default: out = 0;
endcase
In the above example, out is set to 1 if cond is equal to 4'b1000 or 4'b1001, because the last bit of cond is defined as x.
The following example shows a complicated section of code that can be simplified with a casex statement that uses the ? value.
if (cond[3]) out = 0;
else if (!cond[3] & cond[2] ) out = 1;
else if (!cond[3] & !cond[2] & cond[1] ) out = 2;
else if (!cond[3] & !cond[2] & !cond[1] & cond[0] ) out = 3;
else if (!cond[3] & !cond[2] & !cond[1] & !cond[0] ) out = 4;
The following example shows the simplified version of the same code.
casex (cond)
4'b1???: out = 0;
4'b001?: out = 2;
4'b0001: out = 3;
4'b0000: out = 4;
endcase
?, z, and x bits are allowed in case item expressions, but not in casex expressions. The following example shows casex in an illegal expression.
express = 3'bxz?;
...
casex (express) /* illegal testing of an expression*/
...
endcase
The casez statement allows a multipath branch in logic according to the value of an expression, just like the case statement. The differences between the case statement and the casez statement are the keyword and the way the expressions are processed. The casez statement acts exactly the same as the casex statement, except that x is not allowed in case item expressions; only z and ? are accepted as special characters.
The syntax for a casez statement follows.
casez ( expr )
case_item1 : begin
... statements ...
end
case_item2 : begin
... statements ...
end
default : begin
... statements ...
end
endcase
A case item can have expressions consisting of the following.
casez (what_is_it)
2'bz0: begin
/*accept anything with least significant bit zero*/
it_is = even;
end
2'bz1: begin
/*accept anything with least significant bit one*/
it_is = odd;
end
endcase
? and z bits are allowed in case items, but not in casez expressions.
The following example shows an illegal casez expression.
express = 1'bz;
...
casez (express) /* illegal testing of an expression*/
...
endcase
The for loop repeatedly executes a single statement or block of statements. The repetitions are performed over a range determined by the range expressions assigned to an index. Two range expressions are used in each for loop; low_range and high_range. In the syntax lines that follow, high_range is greater than or equal to low_range. Foundation Express recognizes both incrementing and decrementing loops. The statement to be duplicated is surrounded by begin and end statements.
Foundation Express allows four syntax forms for a for loop. They include the following.
for (index=low_range;index<high_range;index=index + step)
for (index=high_range;index>low_range;index=index - step)
for (index=low_range;index<=high_range;index=index + step)
for (index=high_range;index>=low_range;index=index - step)
The following example shows a simple for loop.
for (i = 0; i <= 31; i = i + 1) begin
s[i] = a[i] ^ b[i] ^ carry;
carry = a[i] & b[i] | a[i] & carry |
b[i] & carry;
end
For loops can be nested, as shown in the following example.
for (i = 6; i >= 0; i = i - 1)
for (j = 0; j <= i; j = j + 1)
if (value[j] > value[j+1]) begin
temp = value[j+1];
value[j+1] = value[j];
value[j] = temp;
end
You can use for loops as duplicating statements. The following example shows a for loop.
for ( i=0; i < 8; i=i+1 )
example[i] = a[i] & b[7-i];
The following example is the above for loop expanded into its longhand equivalent.
example[0] = a[0] & b[7];
example[1] = a[1] & b[6];
example[2] = a[2] & b[5];
example[3] = a[3] & b[4];
example[4] = a[4] & b[3];
example[5] = a[5] & b[2];
example[6] = a[6] & b[1];
example[7] = a[7] & b[0];
The while loop executes a statement until the controlling expression evaluates to FALSE. A while loop creates a conditional branch that must be broken by one of the following statements to prevent combinatorial feedback.
@ (posedge clock) or @ (negedge clock)
Foundation Express supports while loops if you insert one of the following expressions in every path through the loop.
@ (posedge clock) or @ (negedge clock)
The following example shows an unsupported while loop that has no event expression.
always
while (x < y)
x = x + z;
If you add @ (posedge clock) expressions after the while loop in the above example you get the supported version shown in the following example.
always
begin @ (posedge clock)
while (x < y)
begin
@ (posedge clock);
x = x + z;
end
end;
Infinite loops in Verilog use the keyword forever. You must break up an infinite loop with an @ (posedge clock) or @ (negedge clock) expression to prevent combinatorial feedback, as shown in the example below.
always
forever
begin
@ (posedge clock);
x = x + z;
end
You can use forever loops with a disable statement to implement synchronous resets for flip-flops. The disable statement is described in the next section. See the Register and Three-State Inference chapter for more information on synchronous resets.
The style illustrated in the example of the supported forever loop above is not recommended, because it is not testable. The synthesized state machine does not reset to a known state; therefore, it is impossible to create a test program for the state machine. The example of the synchronous reset of state register using disable in a forever loop (in the next section) illustrates how a synchronous reset for the state machine can be synthesized.
Foundation Express supports the disable statement when you use it in named blocks. When a disable statement is executed, it causes the named block to terminate. A comparator description that uses disable is shown in the example below.
begin : compare
for (i = 7; i >= 0; i = i - 1) begin
if (a[i] != b[i]) begin
greater_than = a[i];
less_than = ~a[i];
equal_to = 0;
/* comparison is done so stop looping */
disable compare;
end
end
/*If we get here a == b
If the disable statement is executed,the next three lines will not be executed*/
greater_than = 0;
less_than = 0;
equal_to = 1;
end
Note that the above example describes a combinatorial comparator. Although the description appears sequential, the generated logic runs in a single clock cycle.
You can also use a disable statement to implement a synchronous reset, as shown in the following example.
always
forever
begin: reset_label
@ (posedge clock);
if (reset) disable reset_label;
z = a;
@ (posedge clock);
if (reset) disable reset_label;
z = b;
end
The disable statement in the example above causes the block reset_label to immediately terminate and return to the beginning of the block. Therefore, the first state in the loop is synthesized as the reset state.