quick.gif

space2.gif

space2.gif

space2.gif

space2.gif

space2.gif

space2.gif

space2.gif

   

space.gif

   

space.gif

  ../images/main/bullet_green_ball.gif Introduction to Units

e Units are the basic structural blocks for creating verification modules (verification cores) that can easily be integrated together to test larger and larger portions of an HDL design as it develops. Units, like structs, are compound data types that contain data fields, procedural methods, and other members. Unlike structs, however, a unit instance is bound to a particular component in the DUT (an HDL path). Furthermore, each unit instance has a unique and constant place (an e path) in the run-time data structure of an e program. Both the e path and the complete HDL path associated with a unit instance are determined before the run begins.

   

space.gif

To understand better about the applications of units, look at the below example. Which is a switch fabric with 6 ports. We can have one unit, which implements the driver part of the functionality of the testbench, and this driver can be instantiated 6 times with each of them have unique HDL paths.

   

space.gif

../images/specman/switch_fabric.gif
   

space.gif

The basic run-time data structure of an e program is a tree of unit instances whose root is sys, the only predefined unit in e. Additionally there are structs that are dynamically bound to unit instances. The run-time data structure of a typical e program using units is similar to that of the switch_fabric program shown in figure below.

   

space.gif

../images/specman/switch_fabric_sys.gif
   

space.gif

Each unit instance in the unit instance tree of the switch_fabric matches a module instance in the Verilog DUT, as shown in figure above. The one-to-one correspondence in this particular design between e unit instances and DUT module instances is not required for all designs. In more complex designs, there may be several levels of DUT hierarchy corresponding to a single level of hierarchy in the tree of e unit instances.

   

space.gif

Binding an e unit instance to a particular component in the DUT hierarchy allows you to reference signals within that DUT component using relative HDL path names. This ability to use relative path names to reference HDL objects allows you to freely change the combination of verification cores as the HDL design and the verification environment evolve. Regardless of where the DUT component is instantiated in the final integration, the HDL path names in the verification environment remain valid.

   

space.gif

  ../images/main/bulllet_4dots_orange.gif Defining Units And Fields

Units are the basic structural blocks for creating verification modules (verification cores) that can easily be integrated together to test larger designs. Units are a special kind of struct, with two important properties:

   

space.gif

  • Units or unit instances can be bound to a particular component in the DUT (an HDL path).
  • Each unit instance has a unique and constant parent unit (an e path). Unit instances create a static tree, determined during pre-run generation, in the runtime data structure of an e program.
   

space.gif

Because the base unit type (any_unit) is derived from the base struct type (any_struct), user-defined units have the same predefined methods. In addition, units can have verilog members and have several specialized predefined methods.

   

space.gif

A unit type can be extended or used as the basis for creating unit subtypes. Extended unit types or unit subtypes inherit the base type's members and contain additional members.

   

space.gif

Syntax : unit unit-type [like base-unit-type] { [unit-member; ...]}

   

space.gif

Parameter

Description

unit-type

The type of the new unit.

base-unit-type

The type of the unit from which the new unit inherits its members.

unit-member

Like structs, units can have the following types of members

-data fields for storing data

-methods for procedures

-events for defining temporal triggers

-coverage groups for defining coverage points

-when, for specifying inheritance subtypes

-declarative constraints for describing relations between data fields

-on, for specifying actions to perform upon event occurrences

-expect, for specifying temporal behavior rules

   

space.gif

The definition of a unit can be empty, containing no members.

   

space.gif

  ../images/main/bullet_star_pink.gif Example
   

space.gif


  1 module switch_fabric(
  2   clk, reset, data_in0, data_in1, data_in2,
  3   data_in3, data_in4, data_in5, data_in_valid0,
  4   data_in_valid1, data_in_valid2, data_in_valid3,
  5   data_in_valid4, data_in_valid5, data_out0,
  6   data_out1, data_out2, data_out3, data_out4,
  7   data_out5, data_out_ack0, data_out_ack1,
  8   data_out_ack2, data_out_ack3, data_out_ack4,
  9   data_out_ack5
 10 );
 11 
 12 input           clk, reset;
 13 input  [7:0]    data_in0, data_in1, data_in2, data_in3;
 14 input  [7:0]    data_in4, data_in5;
 15 input           data_in_valid0, data_in_valid1, data_in_valid2;
 16 input  [7:0]    data_in_valid3, data_in_valid4, data_in_valid5;
 17 output [7:0]    data_out0, data_out1, data_out2, data_out3;
 18 output [7:0]    data_out4, data_out5;
 19 output          data_out_ack0, data_out_ack1, data_out_ack2;
 20 output [7:0]    data_out_ack3, data_out_ack4, data_out_ack5;
 21 
 22 switch port_0 ( .clk(clk), .reset(reset), .data_in(data_in0), 
 23   .data_in_valid(data_in_valid0), .data_out(data_out0), 
 24   .data_out_ack(data_out_ack0));
 25 
 26 switch port_1 ( .clk(clk), .reset(reset), .data_in(data_in1), 
 27   .data_in_valid(data_in_valid1), .data_out(data_out1), 
 28   .data_out_ack(data_out_ack1));
 29 
 30 switch port_2 ( .clk(clk), .reset(reset), .data_in(data_in2), 
 31   .data_in_valid(data_in_valid2), .data_out(data_out2), .
 32   data_out_ack(data_out_ack2));
 33 
 34 switch port_3 ( .clk(clk), .reset(reset), .data_in(data_in3), 
 35   .data_in_valid(data_in_valid3), .data_out(data_out3), 
 36   .data_out_ack(data_out_ack3));
 37 
 38 switch port_4 ( .clk(clk), .reset(reset), .data_in(data_in4), 
 39   .data_in_valid(data_in_valid4), .data_out(data_out4), 
 40   .data_out_ack(data_out_ack4));
 41 
 42 switch port_5 ( .clk(clk), .reset(reset), .data_in(data_in5), 
 43   .data_in_valid(data_in_valid5), .data_out(data_out5), 
 44   .data_out_ack(data_out_ack5));
 45 
 46 endmodule
 47 
 48 module switch (
 49   clk,
 50   reset,
 51   data_in,
 52   data_in_valid,
 53   data_out,
 54   data_out_ack
 55 );
 56 
 57 input   clk;
 58 input   reset;
 59 input [7:0]  data_in;
 60 input   data_in_valid;
 61 output [7:0]  data_out;
 62 output  data_out_ack;
 63 
 64 reg [7:0]  data_out;
 65 reg   data_out_ack;
 66 
 67 always @ (posedge clk)
 68 if (reset) begin
 69    data_out <= 0;
 70    data_out_ack <= 0;
 71 end else if (data_in_valid) begin
 72    data_out <= data_in;
 73    data_out_ack <= 1;
 74 end else begin
 75    data_out <= 0;
 76    data_out_ack <= 0;
 77 end
 78 
 79 endmodule
You could download file switch_fabric.v here
   

space.gif


  1 `include "switch_fabric.v"
  2 
  3 module unit_example();
  4 
  5 reg  clk, reset;
  6 reg  [7:0] data_in0, data_in1, data_in2, data_in3;
  7 reg  [7:0] data_in4, data_in5;
  8 reg  data_in_valid0, data_in_valid1, data_in_valid2;
  9 reg  data_in_valid3, data_in_valid4, data_in_valid5;
 10 wire [7:0] data_out0, data_out1, data_out2; 
 11 wire [7:0] data_out3, data_out4, data_out5;
 12 wire data_out_ack0, data_out_ack1, data_out_ack2;
 13 wire data_out_ack3, data_out_ack4, data_out_ack5;
 14 
 15 initial begin
 16   clk = 0;
 17   reset = 0;
 18    #10  reset = 1;
 19    #10  reset = 0;
 20   data_in0  = 0;       
 21   data_in1  = 0;
 22   data_in2  = 0;
 23   data_in3  = 0;
 24   data_in4  = 0;
 25   data_in5  = 0;
 26   data_in_valid0  = 0;
 27   data_in_valid1  = 0;
 28   data_in_valid2  = 0;
 29   data_in_valid3  = 0;
 30   data_in_valid4  = 0;
 31   data_in_valid5  = 0;
 32 end
 33 
 34 always #2.5 clk = ~clk;
 35 
 36 switch_fabric U_switch_fabric(
 37  .clk(clk), .reset(reset),
 38  .data_in0(data_in0), .data_in1(data_in1),
 39  .data_in2(data_in2), .data_in3(data_in3),
 40  .data_in4(data_in4), .data_in5(data_in5),
 41  .data_in_valid0(data_in_valid0), .data_in_valid1(data_in_valid1),
 42  .data_in_valid2(data_in_valid2), .data_in_valid3(data_in_valid3),
 43  .data_in_valid4(data_in_valid4), .data_in_valid5(data_in_valid5),
 44  .data_out0(data_out0), .data_out1(data_out1),
 45  .data_out2(data_out2), .data_out3(data_out3),
 46  .data_out4(data_out4), .data_out5(data_out5),
 47  .data_out_ack0(data_out_ack0), .data_out_ack1(data_out_ack1),
 48  .data_out_ack2(data_out_ack2), .data_out_ack3(data_out_ack3),
 49  .data_out_ack4(data_out_ack4), .data_out_ack5(data_out_ack5)
 50 );
 51 
 52 endmodule
You could download file unit_example.v here
   

space.gif


  1 <'
  2 unit switch_driver {
  3    inst_no : uint;
  4    event clk is rise('clk')@sim; 
  5    // This is real dump driver!!!
  6    drive_data(data : byte)@clk is {
  7      wait cycle;
  8       outf ("Driving port : %d\n",inst_no);
  9       outf ("    in  data : %d\n",data);
 10      'data_in(inst_no)'       = data;
 11      'data_in_valid(inst_no)' = 1;
 12      wait cycle;
 13      'data_in(inst_no)'       = 0;
 14      'data_in_valid(inst_no)' = 0;
 15      wait cycle;
 16       outf ("    out data : %d\n",data);
 17      // Check if the data is coming out
 18      if ('data_out_ack(inst_no)' == 1) {
 19        check that data == 'data_out(inst_no)';
 20      } else {
 21        out ("There seems to be a error in DUT");
 22      };
 23    };
 24 };
 25 
 26 unit switch_fabric {
 27   ports: list of switch_driver is instance; 
 28   keep ports.size() == 6; 
 29   // Assign path and unique number to each drive instance 
 30   keep for each in ports {  
 31     .hdl_path() == ""; 
 32     .inst_no    == index;
 33   }; 
 34   // Have clock reference
 35   event clk is rise('clk')@sim; 
 36   // Drive traffic into switch
 37   txgen()@clk is {
 38     wait [10]*cycle;
 39     ports[0].drive_data(10);
 40     ports[1].drive_data(11);
 41     ports[2].drive_data(12);
 42     ports[3].drive_data(13);
 43     ports[4].drive_data(14);
 44     ports[5].drive_data(15);
 45     wait [10]*cycle;
 46     stop_run();
 47   };
 48 };
 49 
 50 extend sys {
 51   switch_fabric :  switch_fabric is instance;
 52   keep switch_fabric.hdl_path() == "unit_example";
 53   run() is also {
 54     start switch_fabric.txgen();
 55   };
 56 };
 57 '>
You could download file structs_units8.e here
   

space.gif

 Driving port : 0
     in  data : 10
     out data : 10
 Driving port : 1
     in  data : 11
     out data : 11
 Driving port : 2
     in  data : 12
     out data : 12
 Driving port : 3
     in  data : 13
     out data : 13
 Driving port : 4
     in  data : 14
     out data : 14
 Driving port : 5
     in  data : 15
     out data : 15
   

space.gif

   

space.gif

  ../images/main/bulllet_4dots_orange.gif Units vs. Structs

The decision of whether to model a DUT component with a unit or a struct often depends on your verification strategy. Compelling reasons for using a unit instead of a struct include:

   

space.gif

  • You intend to test the DUT component both standalone and integrated into a larger system. Modeling the DUT component with a unit instead of a struct allows you to use relative path names when referencing HDL objects. When you integrate the component with the rest of the design, you simply change the HDL path associated with the unit instance and all the HDL references it contains are updated to reflect the component s new position in the design hierarchy. This methodology eliminates the need for computed HDL names (for example, (path_str).sig ), which impact runtime performance.
  • Your e program has methods that access many signals at runtime. The correctness of all signal references within units are determined and checked during pre-run generation. If your e program does not contain user units, the absolute HDL references within structs are also checked during pre-run generation. However, if your e program does contain user units, the relative HDL references within structs are checked at run time. In this case, using units rather than structs can enhance runtime performance.
   

space.gif

On the other hand, using a struct to model abstract collections of data, like packets, allows you more flexibility as to when you generate the data. With structs, you can generate the data either during pre-run generation, at runtime, or on the fly, possibly in response to conditions in the DUT. Unit instances, however, can only be generated during pre-run generation, because each unit instance has a unique and constant place (an e path) in the runtime data structure of an e program, just as an HDL component instance has a constant place in the DUT hierarchical tree.Thus you cannot modify the unit tree by generating unit instances on the fly.

   

space.gif

Any allocated struct instance automatically establishes a reference to its parent unit. If this struct is a generated during pre-run generation it inherits the parent unit of its parent struct. If the struct is dynamically allocated by the new or gen action, then the parent unit is inherited from the struct belonging to the enclosing method.

   

space.gif

  ../images/main/bulllet_4dots_orange.gif HDL Paths and Units

Relative HDL paths are essential in creating a verification module that can be used to test a DUT component either standalone or integrated into different or larger systems. Binding an e unit instance to a particular component in the DUT hierarchy allows you to reference signals within that DUT component using relative HDL path names. Regardless of where the DUT component is instantiated in the final integration, the HDL path names are still valid. To illustrate this, let's look at how the switch_fabric is bound to the DUT unit_example (TB top).

   

space.gif

To associate a unit or unit instance with a DUT component, you use the hdl_path() method within a keep constrain as in the code shown in previous example.

   

space.gif

   

space.gif

  ../images/main/bulllet_4dots_orange.gif Predefined Methods for Any Unit

There is a predefined generic type any_unit, which is derived from any_struct. any_unit is the base type implicitly used in user-defined unit types, so all predefined methods for any_unit are available for any user-defined unit. The predefined methods for any_struct are also available for any user-defined unit.

   

space.gif

  • hdl_path()
  • full_hdl_path()
  • e_path()
  • agent()
  • get_parent_unit()
   

space.gif

  ../images/main/bullet_star_pink.gif hdl_path()

Returns the HDL path of a unit instance. The most important role of this method is to bind a unit instance to a particular component in the DUT hierarchy. Binding an e unit or unit instance to a DUT component allows you to reference signals within that component using relative HDL path names. Regardless of where the DUT component is instantiated in the final integration, the HDL path names are still valid. The binding of unit instances to HDL components is a part of the pre-run generation process and must be done in keep constraints. Although absolute HDL paths are allowed, relative HDL paths are recommended if you intend to follow a modular verification strategy.

   

space.gif

syntax : [unit-exp.]hdl_path(): string

   

space.gif

  ../images/main/bullet_star_pink.gif full_hdl_path()

Returns the absolute HDL path for the specified unit instance. This method is used mainly in informational messages. Like the hdl_path() method, this method returns the path as originally specified in the keep constraint, without making any macro substitutions.

   

space.gif

syntax : [unit-exp.]full_hdl_path(): string

   

space.gif

  ../images/main/bullet_star_pink.gif e_path()

Returns the location of a unit instance in the unit tree. This method is used mainly in informational messages.

   

space.gif

syntax : [unit-exp.]e_path(): string

   

space.gif

  ../images/main/bullet_star_pink.gif agent()

Specifying an agent identifies the simulator that is used to simulate the corresponding DUT component. Once a unit instance has an explicitly specified agent name then all other unit instances instantiated within it are implicitly bound to the same agent name, unless another agent is explicitly specified.

   

space.gif

An agent name may be omitted in a single-HDL environment but it must be defined implicitly or explicitly in a mixed HDL environment for each unit instance that is associated with a non-empty hdl_path(). If an agent name is not defined for a unit instance with a non-empty hdl_path() in a mixed HDL environment, Specman Elite issues an error message.

   

space.gif

Given the hdl_path() and agent() constraints, Specman Elite establishes a correspondence map between the unit instance HDL path and its agent name. Any HDL path below the path in the map is associated with the same agent unless otherwise specified. This map is further used internally to pick the right adapter for each accessed HDL object.

   

space.gif

It is possible to access Verilog signals from a VHDL unit instance code and vice-versa. Every signal is mapped to its HDL domain according to its full path, regardless of the specified agent of the unit that the signal is accessed from.

   

space.gif

When the agent() method is called procedurally, it returns the agent of the unit. The spelling of the agent string is exactly as specified in the corresponding constraint.

   

space.gif

syntax : keep [unit-exp.]agent() == string;

   

space.gif

Where

   

space.gif

string : One of the following predefined agent names: verilog, vhdl, mti_vlog, mti_vhdl, ncvlog and ncvhdl. Specifying the agent name as verilog or vhdl is preferred because it makes the e code portable between simulators. The predefined names are case-insensitive; in other words, verilog is the same as Verilog.

   

space.gif

  ../images/main/bullet_star_pink.gif get_parent_unit()

Returns a reference to the unit containing the current unit instance.

   

space.gif

syntax :[unit-exp.]get_parent_unit(): unit type

   

space.gif

  ../images/main/bulllet_4dots_orange.gif Unit-Related Predefined Methods for Any Struct

The predefined methods for any struct include

   

space.gif

  • get_unit() : Return a reference to a unit
  • get_enclosing_unit() :Return a reference to nearest unit of specified type
  • try_enclosing_unit() : Return a reference to nearest unit instance of specified type or NULL
  • set_unit() : Change the parent unit of a struct
   

space.gif

   

space.gif

   

space.gif

   

space.gif

space2.gif

space2.gif

space2.gif

space2.gif

space2.gif

  

Copyright 1998-2014

Deepak Kumar Tala - All rights reserved

Do you have any Comment? mail me at:deepak@asic-world.com