Product Documentation
Cadence Verilog-AMS Language Reference
Product Version 22.09, April 2022

5


Statements for the Analog Block

This chapter describes the assignment statements and the procedural control constructs and statements that the Cadence® Verilog®-AMS language supports within the analog block. For information, see the indicated locations. The constructs and statements discussed include

Verilog-AMS also supports statements for use in digital contexts. For more information, see the “Assignments” and “Behavioral Modeling” chapters, in the Verilog-XL Reference.

Assignment Statements

There are several kinds of assignment statements in Verilog-AMS: the procedural assignment statement, the branch contribution statement, and the indirect branch assignment statement are available for analog modeling. You use the procedural assignment statement to modify integer and real variables and you use the branch contribution and indirect branch assignment statements to modify branch values such as potential and flow.

In addition, Verilog-AMS supports the continuous assignment statement and the procedural assignment statement for digital modeling. Continuous assignment statements can be used only outside of the initial, always, and analog blocks. For more information on these statements, see the “Assignments” chapter, in the Verilog-XL Reference.

Procedural Assignment Statements in the Analog Block

Use the procedural assignment statement to modify integer and real variables.

procedural_assignment ::=
        lexpr = expression ;
lexpr ::=
        integer_identifier
|   real_identifier
|   array_element
array_element ::=
        integer_identifier [ constant_expression ]
|   real_identifier [ constant_expression ]

The left-hand operand of the procedural assignment used in analog blocks must be a modifiable integer or real variable or an element of an integer or real array. The type of the left-hand operand determines the type of the assignment.

The right-hand operand can be any arbitrary scalar expression constituted from legal operands and operators.

In the following code fragment, the variable phase is assigned a real value. The value must be real because phase is defined as a real variable.

real phase ;
analog begin
    phase = idt( gain*V(in) ) ;

You can also use procedural assignment statements to modify array values. For example, if r is declared as

real r[0:3], sum ;

you can make assignments such as

r[0] = 10.1 ;
r[1] = 11.1 ;
r[2] = 12.1 ;
r[3] = 13.1 ;
sum = r[0] + r[1] + r[2] + r[3] ;

Branch Contribution Statement

Use the branch contribution statement to modify signal values.

branch_contribution ::=
        bvalue <+ expression ;
bvalue ::=
        access_identifier ( analog_signal_list )
analog_signal_list ::=
        branch_identifier
|   node_or_port_identifier
|   node_or_port_identifier , node_or_port_identifier

bvalue specifies a source branch signal. bvalue must consist of an access function applied to a branch. expression can be linear, nonlinear, or dynamic.

Branch contribution statements must be placed within the analog block.

As discussed in the following list, the branch contribution statement differs in important ways from the procedural assignment statement.

Evaluation of a Branch Contribution Statement

For source branch contributions, the simulator evaluates the branch contribution statement as follows:

  1. The simulator evaluates the right-hand operand.
  2. The simulator adds the value of the right-hand operand to any previously retained value for the branch.
  3. At the end of the evaluation of the analog block, the simulator assigns the summed value to the source branch.

For example, given a pair of nodes declared with the electrical discipline, the code fragment

V(n1, n2) <+ expr1 ;
V(n1, n2) <+ expr2 ;

is equivalent to

V(n1, n2) <+ expr1 + expr2 ;

Creating a Switch Branch

When you contribute a flow to a branch that already has a value retained for potential, the simulator discards the value for potential and converts the branch to a flow source. Conversely, when you contribute a potential to a branch that already has a value retained for flow, the simulator discards the value for flow and converts the branch to a potential source. Branches converted from flow sources to potential sources, and vice versa, are known as switch branches. For additional information, see “Switch Branches”.

Indirect Branch Assignment Statement

Use the indirect branch assignment statement when it is difficult to separate the target from the equation.

indirect_branch_assignment ::=
        target : equation ;
target ::=
        bvalue
equation ::=
        nexpr == expression
nexpr ::=
        bvalue
|   ddt ( bvalue )
|   idt ( bvalue )     | idtmod ( bvalue )

An indirect branch assignment has this format:

V(out) : V(in) == 0 ;

Read this as “find V(out)such that V(in) is zero.” This example says that out should be driven with a voltage source and the voltage should be such that the given equation is satisfied. Any branches referenced in the equation are only probed and not driven, so in this example, V(in) acts as a voltage probe.

Indirect branch assignments can be used only within the analog block.

The next example models an ideal operational amplifier with infinite gain. The indirect assignment statement says “find V(out) such that V(pin, nin) is zero.”

module opamp (out, pin, nin) ;
output out ;
input pin, nin ;
voltage out, pin, nin ;
analog
    V(out) : V(pin, nin) == 0 ; // Indirect assignment
endmodule

Indirect assignments are incompatible with assignments made with the branch contribution statement. If you indirectly assign a value to a branch, you cannot then contribute to the branch by using the branch contribution statement.

Sequential Block Statement

Use a sequential block when you want to group two or more statements together so that they act like a single statement.

seq_block ::=
        begin [ : block_identifier { block_item_declaration } ]
            { statement }
        end
block_item_declaration ::=
        parameter_declaration
        integer_declaration
    |   real_declaration

For information on statement, see “Defining Module Analog Behavior”.

The statements included in a sequential block run sequentially.

If you add a block identifier, you can also declare local variables for use within the block. All the local variables you declare are static. In other words, a unique location exists for each local variable, and entering or leaving the block does not affect the value of a local variable.

The following code fragment uses two named blocks, declaring a local variable in each of them. Although the variables have the same name, the simulator handles them separately because each variable is local to its own block.

integer j ;
...
 for ( j = 0 ; j < 10 ; j=j+1 ) begin
if ( j%2 ) begin : odd
integer j ; // Declares a local variable
j = j+1 ;
$display ("Odd numbers counted so far = %d" , j ) ;
end else begin : even
integer j ; // Declares a local variable
j = j+1 ;
$display ("Even numbers counted so far = %d" , j ) ;
end
end

Each named block defines a new scope. For additional information, see “Scope Rules”.

Conditional Statement

Use the conditional statement to run a statement under the control of specified conditions.

conditional_statement ::=
        if ( expression ) statement1
   [ else statement2 ]

If expression evaluates to a nonzero number (true), the simulator executes statement1. If expression evaluates to zero (false) and the else statement is present, the simulator skips statement1 and executes statement2.

If expression consists entirely of genvar expressions, literal numerical constants, parameters, or the analysis function, statement1 and statement2 can include analog operators.

The simulator always matches an else statement with the closest previous if that lacks an else. In the following code fragment, for example, the first else goes with the inner if, as shown by the indentation.

if (index > 0)
    if (i > j) // The next else belongs to this if
        result = i ;
    else // This else belongs to the previous if
        result = j ;
else $strobe ("Index < 0"); // This else belongs to the first if

The following code fragment illustrates a particularly useful form of the if-else construct.

if ((value > 0)&&(value <= 1)) $strobe("Category A");
else if ((value > 1)&&(value <= 2)) $strobe("Category B");
else if ((value > 2)&&(value <= 3)) $strobe("Category C");
else if ((value > 3)&&(value <= 4)) $strobe("Category D");
else $strobe("Illegal value");

The simulator evaluates the expressions in order. If any one of them is true, the simulator runs the associated statement and ends the whole chain. The last else statement handles the default case, running if none of the other expressions is true.

Case Statement

Use the case construct to control which one of a series of statements runs.

case_statement ::=
        case ( expression ) case_item { case_item } endcase
case_item ::=
        test_expression { , test_expression } : statement
|   default [ : ] statement

The default statement is optional. Using more than one default statement in a case construct is illegal.

The simulator evaluates each test_expression in turn and compares it with expression. If there is a match, the statement associated with the matching test_expression runs. If none of the expressions in text_expression matches expression and if you coded a default case_item, the default statement runs. If all comparisons fail and you did not code a default case_item, none of the associated statements runs.

If expression and text_expression are genvar expressions, parameters, or the analysis function, statement can include analog operators; otherwise, statement cannot include analog operators.

The following code fragment determines what range value is in. For example, if value is 1.5 the first comparison fails. The second test_expression evaluates to 1 (true), which matches the case expression, so the $strobe("Category B") statement runs.

real value ;
...
 case (1)
((value > 0)&&(value <= 1)) : $strobe("Category A");
((value > 1)&&(value <= 2)) : $strobe("Category B");
((value > 2)&&(value <= 3)) : $strobe("Category C");
((value > 3)&&(value <= 4)) : $strobe("Category D");
value <= 0 , value >= 4 : $strobe("Out of range");
default $strobe("Error. Should never get here.");
endcase

Repeat Statement

Use the repeat statement when you want a statement to run a fixed number of times.

repeat_statement ::=
        repeat ( constant_expression ) statement

statement must not include any analog operators. For additional information, see “Analog Operators”.

The following example code repeats the loop exactly 10 times while summing the first 10 digits.

integer i, total ;
...
 i = 0 ;
total = 0 ;
repeat (10) begin
i = i + 1 ;
total = total + i ;
end

While Statement

Use the while statement when you want to be able to leave a loop when an expression is no longer valid.

while_statement ::=
        while ( expression ) statement

The while loop evaluates expression at each entry into the loop. If expression is nonzero (true), statement runs. If expression starts out as zero (false), statement never runs.

statement must not include any analog operators. For additional information, see “Analog Operators”.

The following code fragment counts the number of random numbers generated before rand becomes zero.

integer rand, count ;
...
 rand = abs($random % 10) ;
count = 0 ;
while (rand) begin
count = count + 1 ;
rand = abs($random % 10) ;
end ;
$strobe ("Count is %d", count) ;

For Statement

Use the for statement when you want a statement to run a fixed number of times.

for_statement ::=
        for ( initial_assignment ; expression ; 
             step_assignment ) statement

If initial_assignment, expression, and step_assignment are genvar expressions, the statement can include analog operators; otherwise, the statement must not include any analog operators. For additional information, see “Analog Operators”.

Use initial_assignment to initialize an integer loop control variable that controls the number of times the loop executes. The simulator evaluates expression at each entry into the loop. If expression evaluates to zero, the loop terminates. If expression evaluates to a nonzero value, the simulator first runs statement and then runs step_assignment. step_assignment is usually defined so that it modifies the loop control variable before the simulator evaluates expression again.

For example, to sum the first 10 even numbers, the repeat loop given earlier could be rewritten as a for loop.

integer j, total ;
...
 total = 0 ;
for ( j = 2; j < 22; j = j + 2 )
   total = total + j ;

Generate Statement

The generate statement is obsolete. To comply with current practice, use the genvar statement instead.

The generate statement is a looping construct that is unrolled at compile time. Use the generate statement to simplify your code or when you have a looping construct that contains analog operators. The generate statement can be used only within the analog block. The generate statement is supported only for backward compatibility.

generate_statement ::=
        generate index_identifier ( start_expr , 
        end_expr [ , incr_expr ] ) statement
start_expr ::=
        constant_expression
end_expr ::=
        constant_expression
incr_expr ::=
        constant_expression

index_identifier is an identifier used in statement. When statement is unrolled, each occurrence of index_identifier found in statement is replaced by a constant. You must be certain that nothing inside statement modifies the index.

In the first unrolled instance of statement, the compiler replaces each occurrence of index_identifier by the value start_expr. In the second instance, the compiler replaces each index_identifier by the value start_expr plus incr_expr. In the third instance, the compiler replaces each index_identifier by the value start_expr plus twice the incr_expr. This process continues until the replacement value is greater than the value of end_expr.

If you do not specify incr_expr, it takes the value +1 if end_expr is greater than start_expr. If end_expr is less than start_expr, incr_expr takes the value -1 by default.

The values of the start_expr, end_expr, and incr_expr determine how the generate statement behaves.

If And Then the generate statement

start_expr > end_expr

incr_expr > 0

does not execute

start_expr < end_expr

incr_expr < 0

does not execute

start_expr = end_expr

executes once

As an example of using the generate statement, consider the following module, which implements an analog-to-digital converter.

`define BITS 4
module adc (in, out) ;
input in ;
output [0:`BITS - 1] out ;
electrical in ;
electrical [0:`BITS - 1] out ;
parameter fullscale = 1.0, tdelay = 0.0, trantime = 10n ;
real samp, half ;
analog begin
    half = fullscale/2.0 ;
    samp = V(in) ;
    generate i (`BITS - 1,0) begin    // default increment = -1
        V(out[i]) <+ transition(samp > half, tdelay, trantime);
        if (samp > half) samp = samp - half ;
        samp = 2.0 * samp ;
    end
end
endmodule

Module adc is equivalent to the following module coded without using the generate statement.

`define BITS 4
module adc_unrolled (in, out) ;
input in ;
output [0:`BITS - 1] out ;
electrical in;
electrical [0:`BITS - 1] out ;
parameter fullscale = 1.0, tdelay = 0.0, trantime = 10n ;
real samp, half ;
analog begin
    half = fullscale/2.0 ;
    samp = V(in) ;
    V(out[3]) <+ transition(samp > half, tdelay, trantime);
    if (samp > half) samp = samp - half ;
    samp = 2.0 * samp ;
    V(out[2]) <+ transition(samp > half, tdelay, trantime);
    if (samp > half) samp = samp - half ;
    samp = 2.0 * samp ;
    V(out[1]) <+ transition(samp > half, tdelay, trantime);
    if (samp > half) samp = samp - half ;
    samp = 2.0 * samp ;
    V(out[0]) <+ transition(samp > half, tdelay, trantime);
    if (samp > half) samp = samp - half ;
    samp = 2.0 * samp ;
end
endmodule
Because the generate statement is unrolled at compile time, you cannot use the SimVision debugging tool to examine the value of index_identifier or to evaluate expressions that contain index_identifier. For example, if index_identifier is i, you cannot use a debugging command like print i nor can you use a command like print{a[i]}.

Return to top
 ⠀
X