Featured post

Top 5 books to refer for a VHDL beginner

VHDL (VHSIC-HDL, Very High-Speed Integrated Circuit Hardware Description Language) is a hardware description language used in electronic des...

Showing posts with label Verilog. Show all posts
Showing posts with label Verilog. Show all posts

Friday, 16 August 2013

Verilog and SV Event Scheduler

A simulation timeslot is divided into ordered regions to provide a predictable interaction between design constructs. Verilog event scheduler has four regions for each simulation time as Fig 1.

verilog_even_scheduler Fig 1: Active region is for executing process statements; Inactive region is for executing process statements postponed with a “#0″ procedural delay; NBA region is for updating non-blocking assignments; Monitor region is for executing $monitor and $strobe and for calling user routines registered gor execution during this read-only region.

SystemVerilog adds regions to provide a predictable interaction between assertions, design code and testbench code.

sv_event_schedularFig 2: Preponed region is fora smapling signal values before anything in the time slice changes their values; additional observed region is for assertion evaluation. Re-Active and Re-Inactive regions is for executing assertion action blocks and testbenchh programs; Postponed region is for system tasks that record signal values at the end of the time slice.

SV introduces new verification blocks:

— Program
To have clear sepration between testbench and design, SV introdueces program block, which contains full environment for testbench. It is intended to reduce user-induced races. It executes in the Re-Active region.

— Final
“Final” block is used to print summary information in log file at the end of simulation. It executes at the end of the simulation (after explicit or implicit call to $finish) without delays.
e.g.

program asic_with_ankit;
  int error, warning;
  initial begin
  //Main program activities…..
  end
  final begin
  $display (“Test is done with %d errors and %d warnings”, error, warning);
  end
endprogram

— clocking blocks
A clocking block identifies clock signals and captures the timing and synchronization requirements of the blocks being modeled. It supports following features
– Input sampling
– Synchronous events
– Synchronous drives
e.g.

clocking cb @(posedge clk);
  default input #1step //default timing skew for inputs/outputs
          output #3;
  input dout;
  output reset, data;
  output negedge enable;
endclocking

 

clocking_skew Fig 3 clocking skew example


Inputs are sampled at clock edge and outputs are driven at clock edge. Input skew designates sample time before clock edge and output skew designates driving time after the clocking event.

Get free daily email updates!

Follow us!

Tuesday, 8 January 2013

Creating .lib file from Verilog netlist

Creating a dummy .lib file is something every physical design engineer has done now and then. If you have a verilog model of the block available, your task gets easier. The following script automates .lib generation from your verilog netlist. Use this as a dummy .lib to get your design flow going or use it as a template for your analog blocks for modifying the values.

Customize, edit and use. The script creates a simple Data Structure. So any modification can be done pretty easily. The script parses the verilog for the module name specified, and collects the ports & directions. In the .lib file written out, a default capacitance and transition value is specified. This is a good starting point for your blocks.

Usage: create_lib <verilog_netlist> <module_name> [transition_value] [capacitance_value]

#!/usr/bin/perl

use strict;

if ($#ARGV < 1 ) {
    print "usage: create_lib <verilog_netlist> <module_name> \n";
    exit;
}

my $netlist = $ARGV[0] ;
my $module  = $ARGV[1] ;
my $tran = 2.5 ;
my $cap = 0.001;
my $signal_level = "VDD" ;

if(defined $ARGV[2]) {$tran = $ARGV[2];}
if(defined $ARGV[3]) {$cap = $ARGV[3];}
if(defined $ARGV[4]) {$signal_level = $ARGV[4];}

my $FF;
my $FO;
open $FF, "< $ARGV[0]" or die "Can't open $ARGV[0] : $!";
open $FO, ">$module.lib" or die "Can't open $module.lib for write : $!";

my $db = createTopLevelDB();
createDotLib($db,$FO);

sub createDotLib
{
    my $topLevelDBRef = shift;
    my $FO = shift ;   
    ### Header
    print $FO "library\($topLevelDBRef->{'design'}->{'cell'}\) {\n";
    print $FO "\n /* unit attributes */\n";
    print $FO "  time_unit : \"1ns\"\;\n";
    print $FO "  voltage_unit : \"1V\"\;\n";
    print $FO "  current_unit : \"1uA\"\;\n";
    print $FO "  pulling_resistance_unit : \"1kohm\"\;\n";
    print $FO "  leakage_power_unit : \"1nW\"\;\n";
    print $FO "  capacitive_load_unit\(1,pf\)\;\n\n";
    foreach my $direction (keys(%{$topLevelDBRef->{'bus'}})) {
        foreach my $bus_type (keys %{$topLevelDBRef->{'bus'}->{$direction}}) {
            my @bus_width =  split(/_/, $bus_type);
            my $bus_hi = $bus_width[1] ;
            my $bus_lo = $bus_width[2] ;
            my $bus_width = $bus_hi+1-$bus_lo;
            print $FO " type \($bus_type\) { \n";
            print $FO "   base_type : array ; \n" ;
                print $FO "   data_type : bit  \n" ;;
                print $FO "   bit_width : $bus_width   \n" ;;
                print $FO "   bit_from : $bus_hi  \n" ;;
                print $FO "   bit_to : $bus_lo ; \n" ;
                print $FO "   downto : true ; \n" ;
                print $FO " } \n" ;
        }
    }
    print $FO "\n  cell\($topLevelDBRef->{'design'}->{'cell'}\) {\n";
    foreach my $direction (keys(%{$topLevelDBRef->{'pins'}})) {
        foreach my $pin_name (@{$topLevelDBRef->{'pins'}->{$direction}}) {
            print $FO ("    pin\($pin_name\) { \n");
            print $FO ("\tdirection : $direction ;\n");
            if($direction eq "input") {
                print $FO ("\tmax_transition : $tran;\n");
            }
            print $FO ("\tcapacitance : $cap; \n");     
            print $FO ("    } \n") ;
        }
    }
    foreach my $direction (keys(%{$topLevelDBRef->{'bus'}})) {
        foreach my $bus_type (keys %{$topLevelDBRef->{'bus'}->{$direction}}) {
            my @bus_width =  split(/_/, $bus_type);
            my $bus_hi = $bus_width[1] ;
            my $bus_lo = $bus_width[2] ;
            foreach my $bus_name (@{$topLevelDBRef->{'bus'}->{$direction}{$bus_type}}) {
                                        chomp($bus_name);
                print "BUS $bus_name : $bus_type : $direction \n" ;
                print $FO ("    bus\($bus_name\) { \n");
                print $FO ("\tbus_type : $bus_type ;\n");
                print $FO ("\tdirection : $direction ;\n");
                if($direction eq "input") {
                    print $FO ("\tmax_transition : $tran;\n");
                }   
                for(my $i=$bus_lo; $i<=$bus_hi; $i++) {
                    print $FO ("\tpin\($bus_name\[$i\]\) { \n");
                    print $FO ("\t\tcapacitance : $cap; \n"); 
                    print $FO ("\t} \n") ;
                }
                print $FO ("    } \n") ;
            }
        }
    }
    print $FO ("  } \n") ;
    print $FO ("} \n") ;
}

sub createTopLevelDB
{
    my $find_top_module = 0;
    my %topLevelDB = () ;
    my %pins = () ;
    my %bus = () ;
    my @input_pins ;
    my @output_pins ;
    my @inout_pins ;
    my @bus_types ;
    my %input_bus = () ;
    my %output_bus = () ;
    my %inout_bus = () ;
    my %design = ();
    $design{'cell'} = $module;
    $design{'tran'} = $tran;
    $design{'cap'} = $cap;
    $design{'signal_level'} = $signal_level;
    while(my $line = <$FF>) {
        last if($find_top_module == 1);
        if($line=~/module\s+$module/) {
            $find_top_module = 1 ;
            while(my $line = <$FF>) {
                next if($line =~ "\s*//" );
                chomp($line);
                if ($line =~/input\s+/ ) {
                    $line=~s/\s*input\s+//;
                    $line=~s/;//;
                    if($line =~/\[(\d+):(\d+)\]/) {
                        my $bus_type = "bus_$1_$2";
                        $line=~s/\[(\d+):(\d+)\]//;
                        my @line =  split(/,/, $line);
                        unless(grep {$_ eq $bus_type} @bus_types) { 
                            push(@bus_types,$bus_type);
                        }
                        foreach my $pin (@line) {
                            $pin=~s/\s+//;
                            push(@{$input_bus{$bus_type}}, $pin );
                        }
                    }
                    else {
                        my @line =  split(/,/, $line);
                        foreach my $pin (@line) {
                            $pin=~s/\s+//;
                            push(@input_pins, $pin);
                        }
                    }
                }
                if ($line =~/output\s+/ ) {
                    $line=~s/\s*output\s+//;
                    $line=~s/;//;
                    if($line =~/\[(\d+):(\d+)\]/) {
                        my $bus_type = "bus_$1_$2";
                        $line=~s/\[(\d+):(\d+)\]//;
                        my @line =  split(/,/, $line);
                        unless(grep {$_ eq $bus_type} @bus_types) { 
                            push(@bus_types,$bus_type);
                        }
                        foreach my $pin (@line) {
                            $pin=~s/\s+//;
                            push(@{$output_bus{$bus_type}}, $pin );
                        }
                    }
                    else {
                        my @line =  split(/,/, $line);
                        foreach my $pin (@line) {
                            $pin=~s/\s+//;
                            push(@output_pins, $pin);
                        }
                    }

                }
                if ($line =~/inout\s+/ ) {
                    $line=~s/\s*inout\s+//;
                    $line=~s/;//;
                    if($line =~/\[(\d+):(\d+)\]/) {
                        my $bus_type = "bus_$1_$2";
                        $line=~s/\[(\d+):(\d+)\]//;
                        my @line =  split(/,/, $line);
                        unless(grep {$_ eq $bus_type} @bus_types) { 
                            push(@bus_types,$bus_type);
                        }
                        foreach my $pin (@line) {
                            $pin=~s/\s+//;
                            push(@{$inout_bus{$bus_type}}, $pin );
                        }
                    }
                    else {
                        my @line =  split(/,/, $line);
                        foreach my $pin (@line) {
                            $pin=~s/\s+//;
                            push(@inout_pins, $pin);
                        }
                    }

                }

                last if($line=~/endmodule/);
            }

        }
    }
    $pins{'input'} = \@input_pins;
    $pins{'output'} = \@output_pins;
    $pins{'inout'} = \@inout_pins;
    $bus{'input'} = \%input_bus;
    $bus{'output'} = \%output_bus;
    $bus{'inout'} = \%inout_bus;
    $topLevelDB{'pins'} = \%pins;
    $topLevelDB{'bus'} = \%bus;
    $topLevelDB{'design'} = \%design;
    return \%topLevelDB;
}

Saturday, 17 November 2012

Verilog and bit shifting (‘<<' and '>>’): Don’t push your luck

In Verilog there’s a bit shifter operator, which isn’t used a lot, since FPGA designers prefer to state exact bit vectors. But sometimes bit shifting makes the code significantly more readable. Too bad that Xilinx’ XST synthesizer doesn’t get it right in a specific case.

Namely, the following statement is perfectly legal:

always @(posedge clk)
reduce <= 1 + (end_offset >> (6 + rcb_is_128_bytes - format_shift) );

But it turns out that Xilinx ISE 13.2 XST synthesizer gets confused by the calculation of the shift rate, and creates something wrong. I can’t even tell what it did, but it was wrong.

So the rule is simple: It’s fine to have the shift number being a register (even combinatoric) or a wire, but no inline calculations. So this is fine:

always @(format_shift or rcb_is_128_bytes)
if (rcb_is_128_bytes)
case (format_shift)
0: shifter <= 7;
1: shifter <= 6;
default: shifter <= 5;
endcase
else
case (format_shift)
0: shifter <= 6;
1: shifter <= 5;
default: shifter <= 4;
endcase

always @(posedge clk)
reduce <= 1 + (end_offset >> shifter );

(assuming that format_shift goes from zero to 2).

Actually, I would bet that it’s equally fine to calculate the number of shifts and put the result in a wire. I went for the case statement hoping that the synthesizer will take the hint that not all values that fit into the registers are possible, and will hence avoid implementing impossible shift values.

Needless to say, I know about this because something went horribly wrong all of the sudden. I believe XST version 12.2 handled the shift calculation OK. And then people ask me why I don’t like upgrades.

Verilog and bit shifting (‘<<' and '>>’): Don’t push your luck

In Verilog there’s a bit shifter operator, which isn’t used a lot, since FPGA designers prefer to state exact bit vectors. But sometimes bit shifting makes the code significantly more readable. Too bad that Xilinx’ XST synthesizer doesn’t get it right in a specific case.

Namely, the following statement is perfectly legal:

always @(posedge clk)
reduce <= 1 + (end_offset >> (6 + rcb_is_128_bytes - format_shift) );

But it turns out that Xilinx ISE 13.2 XST synthesizer gets confused by the calculation of the shift rate, and creates something wrong. I can’t even tell what it did, but it was wrong.

So the rule is simple: It’s fine to have the shift number being a register (even combinatoric) or a wire, but no inline calculations. So this is fine:

always @(format_shift or rcb_is_128_bytes)
if (rcb_is_128_bytes)
case (format_shift)
0: shifter <= 7;
1: shifter <= 6;
default: shifter <= 5;
endcase
else
case (format_shift)
0: shifter <= 6;
1: shifter <= 5;
default: shifter <= 4;
endcase

always @(posedge clk)
reduce <= 1 + (end_offset >> shifter );

(assuming that format_shift goes from zero to 2).

Actually, I would bet that it’s equally fine to calculate the number of shifts and put the result in a wire. I went for the case statement hoping that the synthesizer will take the hint that not all values that fit into the registers are possible, and will hence avoid implementing impossible shift values.

Needless to say, I know about this because something went horribly wrong all of the sudden. I believe XST version 12.2 handled the shift calculation OK. And then people ask me why I don’t like upgrades.









Get free daily email updates!



Follow us!


Wednesday, 24 October 2012

Combinational Loop in Design

Combinational loops are logical structures that contain no synchronous feedback element. This kind of loops cause stability and reliability problemas,  as we will see in this article, violating the synchronous principles by making feedback with no register in the loop.

WHY? HOW? IS GENERATED A COMBINATIONAL LOOP? 

Basically, a combinational loop es implemented in hardware (gates) when in the written VHDL code describing combinational logic a signal that is in the left side of an assignment statement (that is, to the left of the <= symbol) it also is on the expression at the right side of the signal assignment statement (right of <=). For example the following lines of code generate a combinational loop, as long as they are written in a combinational process or in a concurrent signal assignment statement.

1 acc <= acc + data;
2
3 Z <= Z nand B;
4
5 cnt <= cnt + 1;

However, it's important to point out that if these same statements are written in a clocked process, each of them will generate the respective sequential logic. This is due to the fact that the signal assignment statement in clocked process will generate a register for the assigned signal, therefore the loop will be registered in this case, therefore no combinational loop is generated.

HARDWARE

The following figure shows a diagram of a combinational loop. 

As it is shown in the figure, the combinational logic output is fedbacked to the same combinational logic without any register in the loop. The logic between the first input an the last output can be made up of one or several levels of combinational logic. It can also have different signals coming in and coming out of that piece of logic, but at least one of the signal is going back (feedback) to the first logic level, as it can be seen in the following figure.

This kind of logic circuit usually is not desired, no wanted to be implemented. Hence, when the synthesis tool finds out about this combinational loop generates a warning message. 

Here is an example of VHDL code that generate a combinational loop when is implemented.

1 library ieee;
2 use ieee.std_logic_1164.all;
3
4 entity lazo_comb is
5 port(
6     a: in std_logic;
7     z: out std_logic);
8 end lazo_comb;
9
10 architecture beh of lazo_comb is
11
12 signal y: std_logic;
13
14 begin
15     z <= y;
16
17 process(a,y)
18 begin
19     y <= y nand a;
20 end process;
21
22 end beh;

The synthesis tool, Synplify in this case, generates the following warning regarding the combinational loop. 

The warning message "found combinational loop at 'y'" means that the signal 'y' is feed-backed to the input of the combinational logic without any register in the loop. This loop can be easily found when seeing the RTL view of the synthesized system, as it can be seen in the following figure. 


SIMULATION

The simulation of the system (very simple system) is shown in the following figure. 

The ModelSim windows details a lot of information that deserve a detailed analysis. First of all, the top window plots the waveforms of the signals from the described system, whose main expression is in the line 24 of the middle window. The bottom window, Transcript window, generates an error message, saying that the limit of iterations has been reached at 50ns and no stable value has been gotten. In other words, this mean that the system has began to oscillated and remained oscillating. The maximum number of iterations is configurable in ModelSim (Simulate->Runtime Options); as it's in most simulators. By default this value is set to 5000. Another important piece of information can be found in the bottom of the waveform window. There you can read that the number of Delta reached 5000, which is exactly the number maximum of iterations set in the runtime options, and even after that amount of deltas the system is not stable.

Why this simple logic is oscillating?
Well, analyzing the true table of the nand gate, while one of the input is stuck at '0', the output will be always '1'. That is happening in the simulation shown above. Whereas, when the input (signal a in the simulation) tries to change to '1', due to the fact the other input is still at '1' the output change to '0', then since the feedback input is '0', the output should go to '1', then that '1' is going back with the other input at '1', the output will go to '0' again, and so on...This is what is called an "unstable combinational loop". This kind of loop should NEVER be used in a real design.

Other point to bring out on this example is the importance of simulating a system. Assuming that we configured the FPGA without any simulation, based on the fact that the synthesis tool just gave us a 'warning'), we'd see an no stable output, spending some time (maybe a lot of time) trying to find out why the output is not stable. Conversely, by doing the simulation the problem would appear at first shot.

CODE STYLE

In designs with a large, very large, amount of code lines it is very easy to make mistakes and generate a combinational loop with no intention (as it can be seen in the example above). So, follow certain order when writting the code, trying to maintain a certain flow of data. Also, take a close look at the warnings generated by the synthesis tool. 

In case you deliberately want to implement a combinational loop, write a detailed description of the reason for doing that, and also write a comment in the constraint file. The reason for this last point is due to the fact that the Static Timing Analysis tool (STA) usually increase the minimum period of the system when it founds a combinational loop. Therefore, in this case you should tell to the STA tool to 'ignore' that particular path. The syntax for ignoring a path is 'set_false_path' for the Quartus (Altera) software, and for the ISE (Xilinx) you should use TIG with its resepctivs syntax in both cases.

Get free daily email updates!

Follow us!

Sunday, 9 September 2012

Vectors

Formal Definition

Vectors are multiple bit widths net or reg data type variables that can be declared by specifying their range.

Simplified Syntax

net_type [msb:lsb] list_of_net_identifiers;

reg [msb:lsb] list_of_register_identifiers;

Description

Vector range specification contains two constant expressions: the msb (most significant bit) constant expression, which is the left-hand value of the range and the lsb (least significant bit) constant expression, which is the right-hand value of the range. The msb and lsb constant expressions should be separated by a colon.

Both the msb constant expression and the lsb constant expression can be any value - positive, negative, or zero. The lsb constant expression can be greater, equal or less than the msb constant expression.

Vectors can be declared for all types of net data types and for reg data types. Specifying vectors for integer, real, realtime, and time data types is illegal.

Vector nets and registers are treated as unsigned values (see: Arithmetic expressions with registers and integers for more explanations).

Examples

Example 1

reg [3:0] addr;

The 'addr' variable is a 4-bit vector register made up of addr[3] (the most significant bit), addr[2], addr[1], and addr[0] (the least significant bit).

Example 2

wire [-3:4] d;

The d variable is 8-bit vector net made up of d[-3] (msb), d[-2], d[-1], d[0], d[1], d[2], d[3], d[4] (lsb).

Example 3

tri [5:0] x, y, z;

The above line declares three 6-bit vectors.

Important Notes

  • Both the msb and the lsb expressions should be constant expressions.
  • The msb and the lsb constant expressions may be positive, negative, or zero.
  • The lsb constant expression may be greater, equal or less than the msb constant expression.
  • Vectors can be declared only for nets and reg data types.
  • Vector declaration for integer, real, realtime, and time data types are illegal.

Value Change Dump (VCD) File

Formal Definition

The Value change dump (VCD) file contains information about any value changes on the selected variables.

Simplified Syntax

$dumpfile(name)

$dumpvars

$dumpvars(level, list_of_variables_or_modules)

$dumpoff

$dumpon

$dumpall

$dumplimit

$dumpflush

Description

$dumpfile(filename)

This task is used to specify the VCD file name. The filename parameter is optional. If it is not given, then the file will be named "Verilog.dump”.

$dumpvars(level, list_of_variables_or_modules)

This task is used to specify which variables should be dumped. Both parameters are optional and if none are used, then all variables will be dumped.

If level = 0, then all variables within the modules from the list will be dumped. If any module from the list contains module instances, then all variables from these modules will also be dumped.

If level = 1, then only listed variables and variables of listed modules will be dumped.

$dumpoff

This task stops the dumping of variables. All variables are dumped with x value and all next changes of variables will not be dumped.

$dumpon

This task starts previously stopped dumping of variables.

$dumpall

When this task is used, then the current value of all dumped variables will be written to file.

$dumplimit(filesize)

This task can set the maximum size of the VCD file.

$dumpflush

This task can be used to make sure that all changes of dumped variables are written to file.

Examples

module top;
reg a, b;
wire y;
assign y = a & b;
always begin
  a = 1'b0;
  #10;
  a = 1'b1;
  #10;
  a = 1'bx;
  #10;
end
always begin
  b = 1'b0;
  #30;
  b = 1'b1;
  #30;
  b = 1'bx;
  #30;
end
initial begin
  $dumpfile("test.txt");
  $dumpvars(1,a,y);
  #200;
  $dumpoff;
  #200;
  $dumpon;
  #20;
  $dumpall;
  #10;
  $dumpflush;
end
endmodule

The dumpfile will contain only changes of 'a' and 'y' variables. After 200 time units, dumping will be suspended for 200 time units. Next, dumping will start again and after 20 time units, all variables will be dumped.

Important Notes

  • Value change dump file can be used for hierarchical monitoring of all signal changes within design modules.


UDP State Table

Formal Definition

A UDP state table defines the behavior of UDP.

Simplified Syntax

table

  comb_input comb_input ... comb_input : output;

  seq_input seq_input ... seq_input : current_state : next_state;

endtable

Description

Each row of the state table defines the behavior of the UDP for a specific input combination. Each combination of inputs can be given only one time. It is illegal to define the same combination of inputs for different outputs.

The number of input values must match the number of UDP inputs in a port declaration.

The UDP state table for combinational and sequential UDPs is different. The combinational UDPs (Example 1) contain two fields: an input field and an output field. The sequential UDPs (Example 2) contain three fields: an input, a current state, and the next state (output) field.

The input field should contain a list of values (separated by white spaces), which should match the number of UDP input ports. The order of these ports is highly important. The first input port on the UDP port list matches the first input value in each row.

The rows of the state table can contain only 0, 1, unknown (x) value, and special characters. The high-impedance (z) value cannot be specified. The special characters are provided to increase readability of a description and to make it easier (Example 3).

Symbol

Interpretation

Comments

0

Logic 0

 

1

Logic 1

 

x

Unknown value

Not permitted in output field.

b

Substitute for 0 and 1

Not permitted in output field.

?

Substitute for 0, 1, and x

Not permitted in output field.

-

No change

Permitted only in output field of sequential UDPs.

(vw)

Transition from v to w value

Permitted only in input field of sequential UDPs. v and w can be 0, 1, x, b, and ?

*

Same as (??)

Any value change on input. Permitted only in input field of sequential UDPs.

r

Same as (01)

Rising edge on input. Permitted only in input field of sequential UDPs.

f

Same as (10)

Falling edge on input. Permitted only in input field of sequential UDPs.

p

Same as (01), (0x), (x1)

Positive edge on input. Permitted only in input field of sequential UDPs.

n

Same as (10), (1x), (x0)

Negative edge on input. Permitted only in input field of sequential UDPs.

Table 25: Summary of symbols

If some combinations of input signal values are not specified in a UDP state tables then the output value will be unknown (x).

Only one transition can appear in each row of sequential UDPs.

Examples

Example 1

primitive mux (o, i3, i2, i1, i0, a1, a0);

output o;
input i3, i2, i1, i0, a1, a0;
table
// i3 i2 i1 i0 a1 a0 : o;
0 ? ? ? 1 1 : 0;
1 ? ? ? 1 1 : 1;
? 0 ? ? 1 0 : 0;
? 1 ? ? 1 0 : 1;
? ? 0 ? 0 1 : 0;
? ? 1 ? 0 1 : 1;
? ? ? 0 0 0 : 0;
? ? ? 1 0 0 : 1;
endtable
endprimitive

If any address bit (a1, a0) is unknown, then the output value will be unknown (because there is no row which describes the output value for this combination of address signals).

If a1 = 0 and a0 = 0 then the signal from input i0 is driven to output (value of others inputs does not matter).

If a1 = 0 and a0 = 1 then signal from input i1 is driven to the output.

If a1 = 1 and a0 = 0 then signal from input i2 is driven to the output.

If a1 = 1 and a0 = 1 then signal from input i3 is driven to the output.

Example 2

primitive special_d_ff (q, clk, m, d, rst, set);
output q;
reg q;
input clk, m, d, rst, set;
table
// clk m d rst set : current : next;
// positive edge on clk and normal mode (m = 0)
(01) 0 0 0 0 : ? : 0 ; // line 1
(0x) 0 0 0 0 : ? : 0 ; // line 2
(x1) 0 0 0 0 : ? : 0 ; // line 3
(01) 0 1 0 0 : ? : 1 ; // line 4
(0x) 0 1 0 0 : ? : 1 ; // line 5
(x1) 0 1 0 0 : ? : 1 ; // line 6
// positive edge on clk and negation mode (m = 1)
p 1 ? 0 0 : 0 : 1 ; // line 7
p 1 ? 0 0 : 1 : 0 ; // line 8
// negative edge on clk and any mode (m = 0 or m = 1)
n ? ? 0 0 : ? : - ; // line 9
// reset
? ? ? 1 ? : ? : 0 ; // line 10
// preset
? ? ? 0 1 : ? : 1 ; // line 11
// any changes on inputs with no changes on clk
? * ? ? ? : ? : - ; // line 12
? ? * ? ? : ? : - ; // line 13
? ? ? * ? : ? : - ; // line 14
? ? ? ? * : ? : - ; // line 15
endtable
endprimitive

This is 'd' flip-flop with an additional input, which can convert it into a modulo 2 counter.

If m = 0 then this UDP works as a normal 'd' flip-flop (lines 1-6), but if m = 1 then it negates its current value (lines 7 and 8). If any falling edge occurs on the clk input, then it will not change the output (line 9). If rst is 1, then the output will go to 0 (line 10). If the rst is 0 and set is 1, then the output will go to 1 (line 11 - it means that rst has higher priority than set).

Any changes on the data input will not cause any changes on output (lines 12-15).

Example 3

primitive circuit_1 (o, i1, i2, i3);
output o;
input i1, i2, i3;
table
0 0 0 : 1 ;
0 0 1 : 1 ;
0 0 x : 1 ;
0 1 0 : 1 ;
0 1 1 : 1 ;
0 1 x : 1 ;
1 0 0 : 0 ;
1 0 1 : 0 ;
1 0 x : 0 ;
1 1 0 : 1 ;
1 1 1 : 1 ;
1 1 x : 1 ;
x 0 0 : 0 ;
x 0 1 : 0 ;
x 0 x : 0 ;
x 1 0 : 0 ;
x 1 1 : 0 ;
x 1 x : 0 ;
endtable
endprimitive
primitive circuit_2 (o, i1, i2, i3);
output o;
input i1, i2, i3;
table
0 ? ? : 1 ;
1 0 ? : 0 ;
1 1 ? : 1 ;
x b ? : 0 ;
endtable
endprimitive

'Circuit_1' and 'circit_2' are the same circuit, but the behavior of the 'circuit_1' was specified without special characters.

Important Notes

  • Each row of sequential UDPs can contain only one transition.
  • Special characters can make the UDP state table easier to read and write.
  • Any undefined combination of inputs will set the output to x value.

UDP Instantiation

Formal Definition

The UDP instantiation provides a means of using UDP in modules.

Simplified Syntax

udp_name (strengths) #(delays) instance_name[range] (list of ports);

Description

UDPs can be instantiated only within modules.

The name of an instance is optional (Example 1). A UDP instantiation can contain strength and delays declarations (Example 2). UDPs do not support high-impedance (z) values, therefore only two delays are permitted. Signals connected to input ports can be any net or reg data type. Only net data type variables can be connected to the output port. The strength declaration can contain only drive strength.

It is possible to specify an array of UDP instances by using a range (Example 3).

Examples

Example 1

primitive d_ff (q, clk, d);
...
endprimitive
d_ff (q, clk, d);

The name of an instance is optional.

Example 2

d_ff (weak1, strong0) #5 d1 (q, clk, d);

UDP instance with strength and delay declaration.

Example 3

wire [3:0] q;
reg [3:0] d;
reg clk;
d_ff flips[3:0] (q, clk, d);

Important Notes

· UDP instantiation can contain up to two delay values.


Timing Check Tasks


Formal Definition

Timing Check Tasks are for verification of timing properties of designs and for reporting timing violations.

Simplified Syntax

$setup (data_event, reference_event, limit[, notifier]) ;

$skew (reference_event, data_event, limit[,notifier]) ;

$hold (reference_event, data_event, limit[,notifier]) ;

$recovery (reference_event, data_event, limit, [notifier]) ;

$setuphold (reference_event, data_event, setup_limit, hold_limit, [notifier]) ;

$width (reference_event, limit, threshold [,notifier]) ;

$period (reference_event, limit[,notifier]) ;

$nochange (reference_event, data_event, start_edge_offset, end_edge_offset [,notifier]) ;

Description

Timing check tasks are invoked every time critical events occur within given time limits. See the table below with descriptions of all arguments:

Argument

Description

Type

Reference_event

The transition at a control signal that establishes the reference time for tracking timing violations on the data_event

Module input or inout that is scalar or vector net

Data_event

The signal change that initiates the timing check and is monitored for violations.

Module input or inout that is scalar or vector net

Limit

A time limit used to detect timing violations on the data_event

Constant expression or specparam

Threshold

The largest pulse width that is ignored by the timing check $width

Constant expression or specparam

Setup_limit

A time limit used to detect timing violations on the data_event for $setup.

Constant expression or specparam

Hold_limit

A time limit used to detect timing violations on the data_event for $hold.

Constant expression or specparam

Notifier

An optional argument that "notifies" the simulator when a timing violation occurs

Register

$setup checks setup time. When modeling synchronous circuits, flip-flops need time to force a correct value. Data cannot change within the setup time because flip-flops cannot detect the new value. If data changes within a given time limit, $setup reports a timing violation. If a data event and reference event occur at the same time there is no violation. The$setup first checks timing data then records a new data value. The formula to report a timing violation is as shown below:

(time of reference event) - (time of data event) < limit

Notice that the limit argument has to be a positive number.

$skew checks the following:

(time of data event) - (time of reference event) > limit

$skew can be used to check synchronicity of clocks inside a circuit. If different clocks are used in a design and are synchronized, $skew will report a timing violation when the active edge of one of them occurs outside the time limit allowed for the other clock to occur.

When the data event and the reference event occur at the same time, $skew will not report a timing violation.

$hold will report a timing violation if the following formula is true:

(time of data event) - (time of reference event) < limit

$hold simply checks that data is stable in the specified interval of time after the edge of the clock. In flip-flops, data should remain stable for a given time after the active edge of the clock to allow for propagation of data.

Also, a violation will be reported if the data event and the reference event occur at the same time.

$recovery responds when the following formula is true:

(time of data event) - (time of reference event) < limit

The 'reference_event' must be an edge-triggered event: posedge or negedge. A timing violation occurs if the time interval between an edge-triggered reference event and a data event exceeds the 'limit'. If a reference event and data event occur at the same time, a timing violation is reported. If a 'reference_event' argument is specified without edge specification, an error is reported.

$setuphold checks setup and hold timing violations. This task combines the functionality of $setup and $hold in one task. The following formula has to be applied:

setup_limit + hold_limit > 0

'reference_event' have to be one of the following:

  1. $hold lower bound event
  2. $setup upper bound event

'data_event' have to be one of the following:

  1. $hold upper bound event
  2. $setup lower bound event

In $width both limit and threshold have to be positive numbers. The 'reference_event' must be the edge specification, otherwise an error will be reported. The 'data_event' is not specified directly, but by default means 'reference_event' with opposite edge. A timing violation occurs with the following formula:

threshold < (time of data event) - (time of reference event) < limit

$width reports when width of the active-edge is too small. In FF case it is very important to ensure that the width of an active-edge is sufficient and FF will work properly.

The $period checks that a period of signal is sufficiently long. The reference_event has to be an edge specification. The data_event is not specified directly and by default, is the same as a reference_event. The $period reports a timing violation when the following formula comes true:

(time of data event) - (time of reference event) < limit

The $nochange checks if the data signal is stable in an interval of start_edge_offset and end_edge_offset. If the signal has changed, a timing violation is reported. The reference_event argument can be posedge or negedge but the edge control specifiers are disallowed.

Examples

Example 1

module setup (data1, data2, q);
input data1, data2;
output q;
and (q, data1, data2);
specify
specparam tsetup = 7, delay = 10 ;
(data1 => q) = 10 ;
$setup(data1, posedge data2, tsetup);
endspecify
endmodule

Example 2

module two_clocks (clk1, clk2, q);
input clk1, clk2;
output q;
specify
  specparam tskew = 7;
  $skew(posedge clk1, posedge clk2, tskew);
endspecify
endmodule

Example 3

module hold (data1, data2, q);
input data1, data2;
output q;
and (q, data1, data2);
specify
specparam thold = 7, delay = 10 ;
(data1 => q) = 10 ;
$hold(posedge data2, data1, thold);
endspecify
endmodule

Example 4

module recovery (in1, out1);
input in1 ;
output out1 ;
assign out1 = in1 ? 1'b1 : 1'bz ;
specify
  specparam trecovery = 10;
  $recovery(posedge in1, out1, trecovery);
endspecify
endmodule

Example 5

module setuphold (data1, data2, q);
input data1, data2;
output q;
and (q, data1, data2);
specify
specparam tsetup = 7,
thold = 7,
delay = 10 ;
(data1 => q) = 10 ;
$setuphold(posedge data2, data1, tsetup, thold);
endspecify
endmodule

Example 6

module width (data1, data2, q);
input data1, data2;
output q;
and (q, data1, data2);
specify
specparam twidth = 10,
delay = 10 ;
(data2 => q) = 10 ;
$width(posedge data2, twidth);
endspecify
endmodule

Example 7

module dff (clk, q);
input clk;
output q;
buf (q, clk);
specify
  specparam tperiod = 100 ;
  $period(posedge clk, tperiod);
endspecify
endmodule

Example 8

module nochange (data1, data2, q);
input data1, data2;
output q;
and (q, data1, data2);
specify
specparam tstart = -5,
tend = 5 ;
$nochange(posedge data2, data1, tstart, tend);
endspecify
endmodule

Important Notes

  • All timing check system tasks should be invoked within specify blocks.

Tasks

Formal Definition

Tasks provide a means of splitting code into small parts. Often tasks consist of frequently used functionalities.

Simplified Syntax

task identifier;

  parameter_declaration;

  input_declaration;

  output_declaration;

  inout_declaration;

  register_declaration;

  event_declaration;

  statement;

endtask

Description

Task definition begins with the keyword task and ends with the keyword endtask. A task should be followed by a task identifier and end with a semicolon. A task can contain a declaration of parameters, input arguments, output arguments, inout arguments, registers and events (these declarations are similar to module items declaration) but they are not required. Net declaration is illegal.

A task can contain zero or more behavioral statements, e.g. case statement, if statement. A begin-end block is required for bracketing multiple statements.

The task enabling statement should be made up of a task identifier and the list of comma-separated task arguments. The list of task arguments should be enclosed in parenthesis. If the task does not contain any argument declarations, then it should be enabled by specifying its identifier followed by a semicolon (Example 2).

The list of task enabling arguments should correspond exactly to the list of task arguments. If a task argument is declared as an input, then a corresponding argument of the task enabling statement can be any expression. If a task argument is declared as an output or an inout then the corresponding argument of the task enabling statement should be one of the following items:

  • Register data types
  • Memory references
  • Concatenations of registers or memory references
  • Bit-selects and part-selects of reg, integer and time registers

Only the last assignment to an output or an inout argument is passed to the corresponding task enabling arguments. If a task has assignments to global variables, then all changes of these variables are effective immediately.

Tasks can enable others tasks (Example 3) and functions. A task may be enabled several times in a module. If one task is enabled concurrently, then all registers and events declared in that task should be static, i.e., one variable for all instances.

A task can contain time-controlling statements. A task does not return a value by its name.

Examples

Example 1

task first_task;
  parameter size = 4;
  input a;
  integer a;
  inout [size-1:0] b;
  output c;
  reg [size-1:0] d;
  event e;
begin
  d = b;
  c = |d;
  b = ~b;
if (!a) -> e;
  end
endtask

This is an example of using parameters, input arguments, inout arguments, output arguments, registers and events within tasks. The 'a' argument is declared as an input and as an integer data type.

'First_task' can be enabled as follows:

integer x;
reg a, b, y;
reg [3:0] z;
reg [7:0] w;
first_task(x, z, y);
first_task(x, w[7:4], w[1]);
first_task(1, {a, b, w[3], x[0]}, y);

When being enabled, the first argument of the 'first_task' should be an integer data type expression, the second should be a 4-bit register expression, and the last argument should be 1-bit register expression.

Example 2

reg a, b;
task my_task; // task definition
begin
  a = 1'b1;
  b = 1'bx;
end
endtask
my_task; // task enabling

If 'my_task' is enabled then it will change the value of global variables 'a' and 'b'.

Example 3

task negation;
  inout data;
  data = ~data;
endtask
task my_nor;
  input a, b;
  output c;
  begin
  negation(a);
  negation(b);
  c = a & b;
  end
endtask

The 'my_nor' task enables negation tasks.

Important Notes

  • A task can contain time-controlling statements
  • A task does not return any value by its name

Structured Procedures

Formal Definition

Structured procedures provide a means of modeling blocks of procedural statements.

Simplified Syntax

always statement

initial statement

function

task

Description

Functions and tasks are described in the section: Task and Functions.

The initial statement (Example 1) is executed only during a simulation run. The always procedural block statement (Example 2) is executed continuously during simulation, i.e. when the flow of program reaches the last statement in the block, the flow continues with the first statement in the block.

The always statement should contain at least one procedural timing control because otherwise it may hang the simulation.

Module definition can contain more than one initial or always statement.

Care must be taken when same reg type variables are used in multiple procedural blocks, initial or always. This is because these blocks run in parallel and changing or assigning to one variable affects the same variable in another parallel block.

Examples

Example 1

initial out = 1'b0;
initial begin
  #10;
  a = 1'b0;
  #10;
  a = 1'b1;
  #10;
  a = 1'bz;
end

Example 2

always @(posedge clk)
q = d;
always #10 clk = ~clk;
initial clk = 0;
initial repeat(20)#\10 clk=~clk;

The first initial statement sets clk to 0 at time 0, and the second initial block toggles the clk 20 times every 10 time units.

Important Notes

· The always statement should contain at least one procedural timing control.


Strings

Formal Definition

The strings are sequences of 8-bit ASCII characters enclosed within quotation marks.

Simplified Syntax

"This is a string"

reg [8*number_of_characters:1] string_variable;

Description

The string should be given in one line. Strings can contain special characters (Example 1).

Character

Meaning

\n

New line character

\t

Tab character

\\

\ character

\”

" character

\ddd

A character specified by octal digit

Table 24: Summary of special characters

String variables should be declared as reg type vectors (Example 2). Each character needs 8 bits.

If a string variable is used in an expression, it should be treated as an unsigned value. If the size of a string assigned to a string variable is smaller than the declared size of the variable, then it will be left-padded with zeros.

The null string "” should be treated same as "\0”.

Concatenations of string variables preserve left-padded zeros of these variables (Example 3).

Examples

Example 1

"\n This is the first line\n This is the second line"
"\t Line\t with\t tab\t characters"

Example 2

reg [8*12:1] message;

The message variable can contain 12 characters.

Example 3

reg [10*8:1] s1, s2;
s1 = "Verilog";
s2 = "-HDL";
{s1, s2} <> {"Verilog", "-HDL"}

These expressions are not equal because {s1, s2} has 0s between "Verilog” and "-HDL” and {"Verilog”, "-HDL”} does not have any 0s between words.

Important Notes

  • Concatenation of string variables preserves left-padded zeros of these variables.

Strengths

Formal Definition

The strength declaration construct is used for modeling net type variables for a close correspondence with physical wires.

Simplified Syntax

(Strength1, Strength0)
(Strength0, Strength1)
Strength1:
supply1, strong1, pull1, large1, weak1, medium1, small1, highz1
Strength0:
supply0, strong0, pull0, large0, weak0, medium0, small0, highz0

Description

Strengths can be used to resolve which value should appear on a net or gate output.

There are two types of strengths: drive strengths (Example 1) and charge strengths (Example 2). The drive strengths can be used for nets (except trireg net), gates, and UDPs. The charge strengths can be used only for trireg nets. The drive strength types are supply, strong, pull, weak, and highz strengths. The charge strength types are large, mediumand small strengths.

All strengths can be ordered by their value. The supply strength is the strongest and the highz strength is the weakest strength level. Strength value can be displayed by system tasks ($display, $monitor - by using of the %v characters - see Display tasks for more explanation).

Strength

Value

Value displayed by display tasks

supply

7

Su

strong

6

St

pull

5

Pu

large

4

La

weak

3

We

medium

2

Me

small

1

Sm

highz

0

HiZ

Table 23 Strengths ordered by value

If two or more drivers drive a signal then it will have the value of the strongest driver (Example 3).

If two drivers of a net have the same strength and value, then the net result will have the same value and strength (Example 4).

If two drivers of a net have the same strength but different values then signal value will be unknown and it will have the same strength as both drivers (Example 5).

If one of the drivers of a net has an H or L value, then signal value will be n1n2X, where n1 is the strength value of the driver that has the smaller strength, and n2 is strength value of driver that has the larger strength (Example 6).

The combinations (highz0, highz1) and (highz1, highz0) are illegal.

Examples

Example 1

and (strong1, weak0) b(o, i1, i2);

Instance of and gate with strong1 strength and weak0 strength specified.

Example 2

trireg (medium) t;

The charge strength declaration for trireg net.

Example 3

buf (strong1, weak0) g1 (y, a);
buf (pull1, supply0) g2 (y, b);

If a = 0 and b = 0 then y will be 0 with supply strength because both gates will set y to 0 and supply (7) strength has bigger value than weak (3) strength.

If a = 0 and b = 1 then y will be 1 with pull strength because g1 will set y to 0 with weak (3) strength and g2 will set y to 1 with pull (5) strength (pull strength is stronger than the weak strength).

If a = 1 and b = 0 then y will be 0 with supply strength because g1 will set y to 1 with strong (6) strength and g2 will set y to 0 with supply (7) strength (supply strength is stronger than the strong strength).

If a = 1 and b = 1 then y will be 1 with strong strength because g1 will set y to 1 with strong (6) strength and g2 will set y to 1 with pull (5) strength.

Example 4

buf (strong1, weak0) g1 (y, a);
buf (strong1, weak0) g1 (y, b);

If a = 0 and b = 0 then y will be 0 with weak strength.

If a = 1 and b = 1 then y will be 1 with strong strength.

Example 5

buf (strong1, weak0) g1 (y, a);
buf (weak1, strong0) g1 (y, b);

If a = 1 and b = 0 then y will be x with strong strength.

Example 6

bufif0 (strong1, weak0) g1 (y, i1, ctrl);
bufif0 (strong1, weak0) g2 (y, i2, ctrl);

If ctrl = x, i1 = 0, and i2 = 1 then y will be x with 36X strength, because g1 will set y to L with strong strength (StL - 6) and g2 will set y to H with weak strength (WeH - 3).

Important Notes

  • If one of the drivers has an H or L value, then the output value will be X.

Module Instantiation


Stochastic Analysis Tasks

Formal Definition

Stochastic analysis tasks provide a means of managing queues.

Simplified Syntax

$q_initialize(identifier, type, length, status) ;
$q_add(identifier, job, information, status) ;
$q_remove(identifiers, job, information, status) ;
$q_full(identifier, status) ;
$q_exam(identifier, statistic_code, statistic_value, status) ;

Description

All statistic analysis tasks include identifier, and status arguments. The identifier is a unique integer value identifying the queue. The status argument is an output integer parameter giving information about the correctness of the specified task execution.

Status

Message

0

The queue generation was successful.

1

The queue cannot be increased; queue is full.

2

The identifier is undefined; please define an identifier.

3

Cannot remove a value; queue is empty.

4

The queue cannot be generated; this type is unsupported.

5

The length parameter is <= 0; the queue cannot be generated.

6

The identifier is duplicated; please define new identifier.

7

The queue cannot be generated; insufficient memory.

$q_initialize creates a queue. Parameter type determines the type of a queue. In case of 1, the created queue is FIFO and in case of 2 the queue is LIFO. Parameter length is an integer value specifying the maximum number of entries.

$q_add adds a new entry to the queue. Parameter job identifies the job. The special user-defined parameter, information, can maintain any information useful for the user.

$q_remove receives data from the queue. Parameters of this task are the same as those of the $q_add task.

$q_full checks to see of the queue identified by the identifier parameter is full.

$q_exam returns statistical information about the queue. Parameter statistic_code determines what you need to check and returns the result in statistic_value. The following table lists all possible values of statistic_code:

Statistic_code

Statistic_value

1

Length of queue.

2

Mean interarrival time.

3

Maximum length of queue.

4

Shortest wait time.

5

Longest wait time for jobs still in the queue.

6

Average wait time in the queue.

Examples

Example 1

always @(posedge clk)
begin
// check if queue1 is full
$q_full(queue1, status);
// if full then show message and remove one item
if (status) begin
  $display("Queue is full”);
  $q_remove(queue1, 1, info, status);
end
// add a new item to queue1
$q_add(queue1, 1, info, status);
// show message if there was an error
if (status)
  $display("Error %d”,status);
end
end

This example shows how to add a new element to the queues.

Important Notes

  • The status parameter value should be checked after all operations on the queue.

Specify Block

Formal Definition

Allows a specific delay across a module.

Simplified Syntax

specify

  specparam declaration ;

  path declaration ;

  system timing check ;

endspecify

Description

The Specify block was designed to define a delay across a module. It starts with specify and ends with the endspecify keyword. Inside the block the user can specify: specparamdeclaration, path declaration or system timing check.

The syntax of specparam declaration is the same as that of the parameter declaration. After the specparam keyword the user can specify any number of parameters but only constant expressions are allowed on the right-hand sides of parameter assignments. A comma can separate the assignments, and the last statement ends with a semicolon. A previously declared specparameter can be used to declare the new specparameters. Unlike parameters, specparams cannot be overwritten, nor can they be used outside of a specify block.

Examples

Example 1

module ...
...
specify
  (In => Out) = (10);
endspecify
...
endmodule

A specify block with only a path declaration. Delay between input In and output Out is 10 time units.

Example 2

module ...
...
specify
  specparam TRise = 10,
  TFall = 15;
  (In => Out) = (TRise, TFall) ;
endspecify
...
endmodule

Specparam declaration with two parameters TRise and TFall to specify delays on rising transition and falling transition.

Example 3

module ...
...
specify
  specparam TRise = 10,
  TFall = 15;
  (In => Out) = (TRise, TFall) ;
  $setup(Data_in, posedge Clock, TRise) ;
endspecify
...
endmodule

The full specify block with specparam declaration, path declaration and system timing check task.

Important Notes

· Specify blocks have to be inside the module declaration location.

· Specparams are not visible outside of the Specify blocks.

· The defparam keyword cannot be used to override a specparam value.


State Dependent Path

Formal Definition

State Dependent Path is a path that occurs only when the condition is met.

Simplified Syntax

if (condition) simple_module_path;

if (condition) edge_sensitive_path;

ifnone simple_module_path;

Description

Generally, state dependent path is comprised of three parts. A condition that enables the module path, a module path description and a delay that applies to the module path.

The condition is an expression using scalars or vectors of any type. It can also be part-selects or bit-selects of a vector. Constant numbers and specparams can be used in the condition expression. The result of the conditional expression can be one bit or multiple bits. If it is more than one bit, the least significant bit represents the result.

When no edge transition is specified for the inputs, it is called the simple state-dependent path. Example 1 shows the simple-dependent path.

If any edge transition is specified for the input, then it is called an edge-sensitive state-dependent path. Different delays can be used to the same path if the following rules are followed:

a. A declaration must be unique and should use an edge or a conditional expression or both.

b. The port for which the delay is specified must be referenced in exactly the same way. You cannot mix part select, bit-select and complete ports.

Examples

Example 1

module example1 (cond, in_1, in_2, out);
input in_1, in_2, cond ;
output out ;
and (out, in_1, in_2) ;
specify
  specparam TRise1 = 5,
  TFall1 = 5,
  TRise2 = 7,
  TFall2 = 7;
  if (cond) ( in_1, in_2 *> out ) = (TRise1, TFall1);
  if (~cond) ( in_1, in_2 *> out ) = (TRise2, TFall2);
endspecify
endmodule

If a conditional expression 'cond' is true, TRise1 and TFall1 will be assigned to a path as delays. When the conditional expression 'cond' is false, TRise2 and TFall2 will be used as the path delays.

Important Notes

· When a conditional expression evaluates to x or z, it should be treated as true.