List fields are used very frequently in e. Lists of any data type, enumerated type, or user-defined struct can be defined in e.
An initial size can be specified for the list. The list initially contains that number of items. The size conforms to the initialization rules, the generation rules, and the packing rules. Even if an initial size is specified, the list size can change during the test if the list is operated on by a list method that changes the number of items. All list items are initialized to their default values when the list is created. For a generated list, the initial default values are replaced by generated values. The syntax for a list declaration is shown below.
[!][%]list-name[[length-exp]]: list of type ;
The components of a list field definition are shown in Table 4-4 below.
Lists are dynamic objects that are used for holding stimulus items, struct instances, data values, etc. Lists can be resized. Example 4-5 illustrates a list definition.
Example of a list field definition <' //Define a struct cell struct cell { %data: list of byte; //Physical Field: List of 8-bit values %length: uint; //Physical Field: Unsigned integer strings: list of string; //Virtual Field: List of Strings }; //Define a struct packet struct packet { %is_legal: bool; //Physical Field: Boolean cells: list of cell; //Virtual Field: List of struct cell //This field will contain multiple instances //of struct cell }; //Extend the sys struct extend sys { packets[16]: list of packet; //Virtual Field: List of 16 instances //of packet struct }; '>
Many pseudo-methods are available to operate on lists. When a list field is defined, the pseudo-methods can be used with that list field. Table 4-5 shows the commonly used pseudo-methods that are available to operate on a list. Any arguments required by the predefined method go in parentheses after the predefined method name. Pseudo-methods can be called in actions or constraints.
Once a list field or variable has been declared, you can operate on it with a list predefined method by attaching the predefined method name, preceded by a period, to the list name. Many of the list pseudo-methods take expressions as arguments and operate on every item in the list. Table 4-5 shows the most commonly used pseudo-methods available for lists.
Name | Arguments | Description | Example |
---|---|---|---|
Item of the same list type OR List of same type. | Adds the item or list to the end of the list. | var i_list: list of int; | |
add0(list); | Item of the same list type OR List of same type. | Adds the item or list to the start of the list. | var i_list: list of int; |
None | Deletes all items from the list. | var a_list; | |
Non-negative integer index. | Deletes the item at index location. Index=0 is the first item in the list. | var l_list: list of int = | |
Non-negative integer index. Item of the same list type OR List of same type. | Inserts the item or list at the specified index. | var l_list := {10; 20; 30}; | |
Item of the same list type. | Removes the last item from the list and returns it. | var l_list := {10; 20; 30}; | |
Item of the same list type. | Removes the first item from the list and returns it. Same as delete(0). | var l_list := {10; 20; 30}; | |
Integer indicating size to which the list is resized. | Resizes the list to the declared size and initializes all elements to the default value unless specified otherwise. | extend sys { | |
None | Returns an integer equal to the number of items in the list. A common use for this method is in a keep constraint, to specify an exact size or a range of values for the list size. | <' | |
None | Checks if the list is empty and returns a boolean value. Returns TRUE if list is empty, or FALSE if the list is not empty. |
|
Keyed lists are used to enable faster searching of lists by designating a particular field or value which is to be searched for. A keyed list can be used, for example, in the following ways:
As a hash table, in which searching only for a key avoids the overhead of reading the entire contents of each item in the list.
For a list that has the capacity to hold many items, but which in fact contains only a small percentage of its capacity, randomly spread across the range of possible items. An example is a sparse memory implementation.
Although all of the operations that can be done using a keyed list can also be done using a regular list, using a keyed list provides an advantage in the greater speed of searching a keyed list. The general syntax for defining a keyed list is as follows.
![%]list-name: list(key: key-field) of type ;
The components of a keyed list definition are described in Table 4-6 below.
! | Do not generate this list. For a keyed list, the "!" is required, not optional. |
% | Denotes a physical list. The "%" option may precede or follow the "!". |
list-name | Names the list being defined. |
key-field | Indicates the key of the list. For a list of structs, it is the name of a field of the struct. This is the field or value which the keyed list pseudo-methods will check when they operate on the list. For a list of scalars, the key can be the it variable referring to each item. The keyword it is context dependent and points to the relevant object in a particular context. See Table 4-7 and Example 4-6 for details on usage of the it variable. |
type | Indicates the type of items in the list. This can be any scalar type, string, or struct. It cannot be a list. |
Besides the key parameter, the keyed list syntax differs from regular list syntax in the following ways:
The list must be declared with the "!" do-not-generate operator. This means that you must build a keyed list item by item, since you cannot generate it.
The "[exp]" list size initialization syntax is not allowed for keyed lists. That is, "list[exp]: list(key: key) of type" is not legal. Similarly, you cannot use a keep constraint to constrain the size of a keyed list.
A keyed list is a distinct type, different from a regular list. This means that you cannot assign a keyed list to a regular list, nor assign a regular list to a keyed list. Table 4-7 shows three pseudo-methods associated with keyed lists.
Name | Arguments | Description | Example |
---|---|---|---|
key(key-exp); | The key of the item that is to be returned | Returns the list item that has the specified key, or NULL if no item with that key exists in the list. | var l_list: list(key: it) |
Key_index (key-exp); | The key to be searched for | Returns the integer index of the item that has the specified key, or returns UNDEF if no item with that key exists in the list. | var l_list: list(key: it) |
Key_exists (key-exp); | The key to be searched for | Returns TRUE if the key exists in the list, or FALSE if it does not. | var l_list: list(key: it) |
Example 4-6 shows an instance in which the list named cl is declared to be a keyed list of four-bit uints, with the key being the list item itself. That is, the key is the value of a four-bit uint. A list of 10 items is built up by generating items and adding them to the keyed list in the for loop.
Example of keyed lists <' extend sys { !cl: list(key: it) of uint(bits: 4); run() is also { var ch: uint(bits: 4); for i from 0 to 10 { gen ch; cl.add(ch); }; if cl.key_exists(8) then { print cl; print cl.key_index(8); }; }; }; '> Results cl = (10 items, decimal): 4 5 8 3 14 9 11 4 5 13 cl.key_index(8) = 2
We discussed only simple applications of keyed lists. Keyed lists can be used with complex structs, where a field in that struct can be used as a key.