The script parser has some advanced features that simplify creation of complicated generation scenarios. Such features include:
-
Using local and global integer variables
-
Using local and global structure variables
-
Using special data pattern creators in field assignments
-
Using multipliers with structure variables in field assignments
-
Using = + in field assignments
-
Initializing structure variables from hex streams
-
Supporting arithmetic operations with parser variables
-
Supporting concatenation operations for structure variables
-
Using parser sizeof operators
-
Using parser while, for, and if-else operators
-
Calling generation procedures with parameters
-
Allowing users to trace/debug the parser and follow variable and template construction
-
Supporting name aliasing for constants, settings, data patterns, templates, variables, instructions and named instruction parameters.
-
Using include paths to specify additional folders in which to look for included files
Local Numeric Parser Variables
You can declare a local numeric parser variable, which is seen only inside the generation procedure, and use it in field assignments.
[ Local ] var = expression
Note: The Local keyword is required if you already have a global variable with the same name. Using this keyword explicitly instructs the script parser to declare a local variable with the same name.
Example
y = 10 # Declare a global numeric variable with name 'y'.
Main
{
x = 0x10 # Declare a local variable 'x'.
Local y = 1 # Explicitly declare a local variable 'y'
Send TX_PACKET
{
DevAddr = x # Use the previously assigned variable 'x'
Endp = y + 2 # Use the previously assigned variable 'y' + 2
SeqNum = z # Create a new variable 'z' with value 0.
}
}
Local Structure Parser Variables
You can declare a local "structure" parser variable, which is seen only inside the generation procedure, and use it in a Send Packet instruction and field assignments.
[ Local ] $var = template_or_var_name
[ Local ] $var = $variable_name
Note: The Local keyword is required if you already have a global variable with the same name. Using this keyword explicitly instructs the script parser to declare a local variable with the same name.
Example
Main
{
# Declare a variable X as a packet of type MY_TX_PACKET.
$X = MY_TX_PACKET
# Note: Packet variables can be declared/redeclared and used many times.
# Declare a variable Y and change the default packet.
$Y = MY_TX_PACKET
# Template field values
{
DevAddr = 0x10
Endp = 2
}
# Declare a variable Z using the packet variable Y as a prototype.
$Z = Y
{
DevAddr = 0x10
Endp = 2
}
Local $Z = Y # Explicitly declare a local variable.
# Declare a structure variable having the same name as one of the
# templates.
$MY_TX_PACKET = MY_TX_PACKET
{
DevAddr = 0x10
Endp = 2
}
# Explicitly instruct the script parser to create a new
# structure variable based on the other structure variable rather
# than a template.
$W = $MY_TX_PACKET
# Send a packet based on the structure variable.
Send $W
}
Using Local Fields in Structure Variables
You can declare local fields within a structure variable. Use local fields to reassign bit offsets or append additional data to a structure variable.
These fields are only valid in the structure variable in which they are declared, not the packet template.
You can declare new structure variables based on the structure variable with local fields. However, it is illegal to assign an existing structure variable to a structure variable that contains declared local fields. This may or may not generate parse errors. If no parse errors are generated, the local fields are not in the assigned structure variable.
Note: See section Changing Structure Parser Variables for more examples.
Example
struct S1
{
F16 : 16 = 0xAABB
F8 : 8 = 0xFE
F32 : 32 = 0xABCD1234
}
Main
{
# Declare a structure variable based on struct S1.
$Pkt_Var1 = S1
# Declare local field F24 in structure variable $Pkt_Var1. The
# local field is from offset 0 and is 24 bits long (it has the same
# offsets as F16 and F8).
$Pkt_Var1
{
F24 : 0,24 = { 11 22 33 }
}
# Declare a structure variable based on struct S1.
$Pkt_Var2 = S1
# Declare local field F24 in structure variable $Pkt_Var2. The
# local field is 120 bits long at offset 56 (end of the structure
# variable).
$Pkt_Var2
{
F128 : 120 = { 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF }
}
# Declare structure variable $Pkt_Var3 (assigned from $Pkt_Var1).
$Pkt_Var3 = $Pkt_Var1
# Declare a structure variable based on struct S1.
$Pkt_Var4 = S1
# Bad assignment $Pkt_Var2 to $Pkt_Var4 (data NOT copied)
$Pkt_Var4 = $Pkt_Var2
}
Changing Structure Parser Variables
You can change a structure variable in a generation procedure by changing a field value, length, offset, or hex stream assignment, or you can add to or edit the structure variable by declaring local fields. You can also redeclare the variable.
Note: If you change a structure variable by a hex stream assignment and the structure variable has some variable-length fields, then only the first variable-length field is filled with data and all other variable-length fields have zero length.
Note: If you declare local fields within a structure variable, they are only valid in that structure variable, not the packet template. New structure variables can be declared based on the structure variable with local fields. However, it is illegal to assign an existing structure variable to a structure variable that contains declared local fields, and this generates parse errors.
Examples
Struct MY_STRUCT
{
V1 : 16
V2 : 8
V3 : 8
V4 : 32
}
Struct MY_STRUCT_2
{
F1 : 8
F2 : 32
F3 : * # Variable length
F4 : * # Variable length
F5 : 32
}
Main
{
# Change some fields in a structure variable.
$X { DevAddr = 0x12 }
# Assign some values at some offsets:
# The format is $PktVar[offset, length] =
# appropriate field assignment (numeric value, data pattern, etc.)
$X[16,8] = 0xAA
$X[16] = 0xAA
# Note: If the length value is omitted, the default is 8 bits.
offset = 16 # Preprocessor variable keeps the offset.
len = 8 # Preprocessor variable keeps the length.
$X[offset, len] = 0xAA
$X[offset] = 0xAA
$Y = MY_STRUCT
# Change the structure variable from a hex stream.
$Y = { 11 22 33 44 55 66 77 88 }
# After the above change, the variable Y fields have the
# following values:
# Y.V1 = { 11 22 }
# Y.V2 = 0x33
# Y.V3 = 0x44
# Y.V4 = { 55 66 77 88 }
# Change $Y from the above to {AA BB CC DD 55 66 77 88} and
# add local field F6 to variable X.
$Y { V_123 : 0, 32 = { AA BB CC DD }
$Z = MY_STRUCT_2
# Attempt to copy $Y to $Z. This will NOT work and may or may not
# generate a parse error.
# If no error is generated, the parser skipped this instruction.
# (Because $Z is derived from MY_STRUCT_2 and $Y is no longer
# purely MY_STRUCT_2 with its local variables,
# this assignment is not valid).
$Z = $Y
# Copy $Y to a newly instantiated $W structure variable.
# This is legal because $W does not have a packet template
# associated with it, because it is being declared.
$W = $Y
# Change $Y from the above to
# {AA BB CC DD 55 66 77 88 00 00 00 00 FF FF}
# and add local variable V5 at offset 96 with length 16.
# Offset 64-95 is padded with zeroes.
$Y { V5 : 96, 16 = { FF FF } }
# Send a packet of {FF 00 FE FD FC 66 77 88 00 00 00 00 FF FF} by
# modifying $Y from the above and
# instantiate local variables V3_1 and V3_2 for use
# in this send instruction only. [ No $ = send ]
Y
{
V1 = 255
V2 = 254
V3_1 : 16, 8 = 253
V3_2 : 24, 8 = 252
}
# COMPLEX LOCAL FIELD MANIPULATION EXAMPLES
$X = MY_STRUCT_2
# Change the structure variable from a hex stream.
$X = { 11 AA BB CC DD 22 33 44 BE EF BE EF }
# After the above change, the variable X fields have the
# following values:
# X.F1 = 0x11
# X.F2 = { AA BB CC DD }
# X.F3 = { 22 33 44 }
# X.F4 = empty
# X.F5 = { BE EF BE EF }
# Change $X from the above to
# {11 AA BB CC DD 22 33 44 BE F0 0D F0 0D}
# and add local field F6 to variable X.
# The variable length fields F3 & F4 are treated as empty
# and F5 is treated as having offset 40-71,
# hence F6 occupies offset 72-103.
$X { F6 : 32 = { F0 0D F0 0D } }
# Change $X from the above to
# {11 02 01 04 03 22 33 44 BE F0 0D F0 0D}
# and add local fields F2Lower and F2Upper to variable X.
$X{
F2Lower : 8, 16 = { 02 01 }
F2Upper : 24, 16 = { 04 03 }
}
# Change $X from the above to
# {C0 01 C0 DE 11 22 AA EE BE F0 0D F0 0D}
# and add local field F1_F2 and B3 to variable X.
# B3 is only 16 bits long, hence only AA EE is taken as data,
# and FF BB is truncated.
$X
{
F1_F2 : 0, 40 = { C0 01 C0 DE 11 }
B3 : 48, 16 = { AA EE FF BB } #Note: B3 is only 16 bits long.
}
# Send a packet of {C0 01 C0 DE 11 22 AA EE 44 55 22 33 44} by
# modifying $X from the above.
# Existing local field F6 is used and
# F7 is instantiated for use in this Send instruction only.
# F6 fills in from offset 72-103,
# because that is where it became declared
# when created in $X earlier.
# F7 fills in offset 64-79,
# because variable length fields F3 and F4 still exist,
# and there is a hole between offset 63-72.
Send $X{
F6 = { 11 22 33 44 }
F7 : 16 = { 44 55 }
}
}
Using Special Data Pattern Creators in Field Assignments
You can use special pattern constructors to simplify creation of data patterns.
Examples
Main
{
# Examples of using special data pattern declarations while
# assigning field values.
Send TX_PACKET
{
Endp = 0xEFBE
Data = { 01 02 03 00 0A } # Simple byte stream
Data = PATTERN_2 # Use declared data pattern.
# Use combined byte stream.
Data = { AA BB CC _11110000 12 34 56 78 [PATTERN_2] }
Data = 12, 0xAA # Specify data payload of 12 bytes and
# fill it by 0xAA: AA AA AA AA ... AA
# Specify data payload of 12 bytes and fill it starting
# from 1, incrementing each byte by 2: 01 03 05 07 09 ...
Data = 12, 1, 2
}
}
Using Structure Variables to Assign Field Values
You can use structure variables in field assignments.
Examples
Main
{
# Use structure variables to assign field values.
# Declare a 'structure' instance based on the template S1.
$S = S1
# Declare a 'structure' instance based on the template S2
# and change the default value for the S16 field.
$W = S2 { S16 = 2 }
Send TX_PACKET
{
Data = $S # Data field contains the payload of structure S.
}
Send TX_PACKET
{
# Example of concatenation of structures.
# Data field contains combined payload of structures S and W
Data = $S + $W
}
}
Using Multipliers to Assign Field Values
You can use a "multiplier" to assign repeated data and create complex assignments. This multiplier only works on structure variables when assigning fields.
Note: Though this multiplier uses the symbol *, this multiplier is not the arithmetic multiplier.
Examples
Generic $X
Generic $Y
Main
{
# Use multipliers to assign field values.
# Declare a packet variable of 'structure' instance Generic with
# data FB 01 02.
$TestIE = Generic { Data = { FB 01 02 } }
# Declare a 'structure' instance based on the template S2
# and change the default value for the S16 field.
$S2_Var = S2 { S16 = 2 }
Send TX_PACKET
{
Data = 10*$TestIE # Data field contains the sequence of $TestIE
# repeated 10 times:
# { FB 01 02 FB 01 02 FB 01 02 FB 01 02 FB 01
# 02 FB 01 02 FB 01 02 FB 01 02 FB 01 02 }
}
# Declare Packet Variable $X of structure Generic with data FF.
$X = Generic { Data = 0xFF }
# Packet Variable $Y contains the sequence of $TestIE repeated
# three times and $X repeated two times:
# { FB 01 02 FB 01 02 FB 01 02 FF FF }
$Y { Data = 3*$TestIE + 2*$X }
Num_of_Y = 5 # Local Numeric Variable
Send TX_PACKET
{
# Example of concatenation and multiplication of structures.
# Data field contains combined payload of:
# $S2_Var + $S2_Var + $X + $X + $X + $X + $X + $X + $X + $X + $X + $X
# + $X + $X + $X + $X + $Y + $Y + $Y + $Y + $Y
Data = $S2_Var*2 + 16*$X + Num_of_Y*$Y
}
}
Using the Append Operator in Field Assignments
You can append data to fields using = + (append operator) in field assignments. Use the append operator to generate dynamic packets and avoid restating previously assigned values. For example, if a packet variable field SomeField contains “01 02 03”, to add “04 05 06” you can assign SomeField = +{04 05 06} ), rather than assigning SomeField = {01 02 03 04 05 06}.
Important: Do not confuse this operator with the += operator, or a parse error will be generated! You can write the append operator as = + or =+ (without a space), but it is recommended to use the space to avoid confusion with the += operator.
Examples
Packet BPOIE
{
ElemID : 8 = 1
ElemLen : 8
BPLen : 8
Occupancy_Bitmap : *
DevAddrList : *
}
BPOIE $Beacon3_BPOIE
BPOIE $Beacon11_BPOIE
Main
{
$Beacon3_BPOIE
{
BPLen = 16
Occupancy_Bitmap = { 00 55 55 55 01 }
DevAddrList = { 04 00 }
}
# Generate DevAddrList for Addrs 5-16 : DevAddrList = {04 00} -->
# DevAddrList = { 04 00 05 00 06 00 07 00 08 00 09 00 0A 00
# 0B 00 0C 00 0D 00 0E 00 0F 00 10 00 }
for( i=5, i<17, i++)
{
$Beacon3_BPOIE{ DevAddrList = +{ i 00 } }
}
$Beacon11_BPOIE
{
BPLen = 16
Occupancy_Bitmap = { 10 55 15 55 01 }
DevAddrList = { 03 00 }
}
# Generate DevAddrList for Addrs 4-10 and 12-16 :
# DevAddrList = {03 00} -->
# DevAddrList = { 03 00 04 00 05 00 06 00 07 00 08 00 09 00
# 0A 00 0C 00 0D 00 0E 00 0F 00 10 00 }
for(i=4, i<17, i++)
{
if (i!=11)
{
$Beacon11_BPOIE{ DevAddrList = +{ i 00 } }
}
}
}
Initializing Struct Variables from Hex Streams
You can assign structure variables using hex streams. Rather than defining each field within a structure variable, set the structure variable equal to a hex/byte stream. The fields within the structure variable are then assigned based on the offset.
Assignments for Variables with Fixed-length Fields
For structure variables composed of fixed length fields (so that the structure variable has fixed length), assignments by hex streams fill the fields in offset order. Any overflow from the hex stream is truncated. For example, assigning an eight-byte structure variable to a twelve-byte hex stream loses the last four bytes of the hex stream.
Example
Packet GenericSample
{
Field_1 : 8
Field_2 : 32
Field_3 : 16
Field_4 : 4
Field_5 : 3
Field_6 : 1
}
GenericSample $Struct_Var
Main
{
$Struct_Var = { 01 02 03 04 05 06 07 08 }
# The following is the same as the line above.
$Struct_Var{
Field_1 = 1
Field_2 = { 02 03 04 05 }
Field_3 = { 06 07 }
Field_4 = 0
Field_5 = 4
Field_6 = 0
}
}
Assignments for Variables with Variable Length Fields
For structure variables that have one variable length field:
-
The hex stream fills all fixed-length fields prior to the first variable-length field, using a
top-down approach. -
The hex stream fills all fixed-length fields following the variable-length field using a bottom-up approach, in which the required number of bytes comes from the end of the hex stream and the fixed-length fields are filled in order.
-
The hex stream fills the variable-length field with the remaining bytes from the middle of the hex stream.
If a structure variable has more than one variable-length field (including interleaved variable-length and fixed-length fields), only the first variable-length field receives data. Later
variable-length fields receive no data and are blank. For these types of structure variables, it is not recommended to explicitly modify fields after assignment from a hex stream, because data is not logically assigned. Essentially, a structure variable with more than one variable-length field becomes a structure variable with only one variable-length field, the first one listed in offset order.
Example
Packet SF_Beacon
{
PHY : 40
MAC : 80
BH : 64
IEs : *
DATA: *
}
Packet GenericSample
{
First3_Bytes : 24
More_Bytes : *
Some_More_Len : 8
Some_More_Bytes : *
Even_More_Len : 8
Even_More_Bytes : *
Total_Len : 16
}
SF_Beacon $BeaconSlot2
GenericSample $X
Main
{
$BeaconSlot2 = { 00 0C 00 D0 00 00 00 FF FF 02 00 00 00 00 00
98 76 54 32 10 FC 02 00 01 02 03 00 }
# Equivalent to
$BeaconSlot2{
PHY = { 00 0C 00 D0 00 }
MAC = { 00 00 FF FF 02 00 00 00 00 00 }
BH = { 98 76 54 32 10 FC 02 00 }
IEs = { 01 02 03 00 }
# DATA is Empty.
}
$X = { 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 }
# Equivalent to
$X{
First3_Bytes = { 01 02 03 }
More_Bytes = { 04 05 06 07 08 09 0A 0B 0C 0D 0E }
Some_More_Len = 0x15
# Some_More_Bytes is empty.
Even_More_Len = { 10 }
# Even_More_Bytes is empty.
Total_Len = { 11 12 }
}
}
Sizeof Operators
Several kinds of sizeof operators are currently supported:
-
fld_size (field_name): Returns the length of the field in bits.
-
pkt_size (template): Returns the length of the template payload in bits.
-
pkt_size ($pkt_var_name): Returns the length of the structure variable payload in bits.
-
pttn_size (data_pattern): Returns the length of the data pattern payload in bits.
Note: Fields that are not initialized with a variable length (declared as f : *) have 0 length.
Examples
Main
{
# Examples of using 'sizeof' operators.
# Declare a 'structure' instance based on the template S1.
$S = S1
# Declare a 'structure' instance based on the template S2,
# changing the default value for the S16 field.
$W = S2 { S16 = 2 }
Send TX_PACKET
{
# Set the Len to the size of
# combined payload + the size of the 'Len' field.
Len = ( fld_size( Len ) + pkt_size( $S ) + pkt_size( $W ) ) / 8
# Same as the previous assignment.
Len = ( fld_size( Len ) + pkt_size( S1 ) + pkt_size( S2 ) ) / 8
# Data field contains combined payload of structures S and W.
Data = $S + $W
}
}
Preprocessor Integer Arithmetic
You can declare a preprocessor DWORD variable, make arithmetic operations with it, and use it in field and setting/parameter assignments.
Note: Arithmetic expressions are allowed only in numeric variable assignments. Some legal expressions are:
-
x = y + 2
-
TX_PACKET ( Delay = (x+y)*7 )
-
TX_PACKET ( x + 12 )
Examples
Const TX_PAYLOAD_OFFSET = 16 * 8
Const "Some Hex Data" = 0xAABB
Main
{
x = 2
y = ( z = 12 ) + ( TX_PAYLOAD_OFFSET + 36 ) / 8
z = 0x1 << 5
s = "Some Hex Data" # Constants may be used in operations.
x++
y--
z += ( x + y )
x = ( ( y & 0xFF ) >> 5 ) / 12
Send TX_PACKET ( Delay = x )
Send TX_PACKET
{
Endp = 0xEEEE
# Example of a data payload assignment that uses
# integer variables, constants, hex literals, binary literals,
# and a data pattern.
Data = { y y y 7a7a7a "Some Hex Data"
"Some Hex Data" 8b 8b _11110000 _00001111 z z z
[PATTERN_3] }
}
( Delay = y ) # Use an integer variable for a parameter setting.
}
Preprocessor If Operator
A special preprocessor If directive includes/excludes different parts of generation code depending on some condition.
Examples
Main
{
x = 180
y = 30
# Short if operator with only a 'then' clause
if( x > y )
{
# This block is parsed the usual way and all instructions
# are added to the current instruction block.
Send TX_PACKET
Send TX_PACKET ( Delay = 2000 )
}
if( x < y )
{
# This block is parsed in a special way:
# Only the "{" "}" are taken into account.
# Everything else is ignored.
Send DATA_PACKET
{
DevAddr = 0x02
Endp = 0
Data = { AA BB CC DD 12 34 56 78 [PATTERN_2] }
}
( Delay = 1000 )
}
# Full if operator with both 'then' and 'else' clauses.
if( x > y )
{
# This block is parsed the usual way and all instructions
# are added to the current instruction block.
Send MY_USB3_PKT
Send MY_DATA_PACKET ( Delay = 2000 )
}
else
{
# This block is parsed in a special way.
# Only "{" "}" are taken into account.
# Everything else is ignored.
Send MY_USB3_PKT
}
}
Preprocessor Loop Operators
Note: Loop operators can produce a huge number of instructions. Therefore, you should set a maximum allowed limit for the total number of loop iterations in a generation script. To do this, use the MaxLoopIterCount parser setting.
Examples
Main
{
k = 0
# 'while' loop operator.
while( k < 4 )
{
k++
# Skip the remaining part of the loop iteration.
if( k == 2 ) { skip_iteration }
# Stop the loop.
if( k == 3 ) { stop_loop }
Send TX_PACKET
{
Endp = 2
DevAddr = 0x10
# Data pattern uses preprocessor variables.
Data = { k k k k k }
}
}
# 'for' loop operator.
for( k = 0, k < 10, k++ )
{
# Skip the remaining part of the loop iteration.
if( k == 2 ) { skip_iteration }
# Stop the loop.
if( k == 4 ) { stop_loop }
Send TX_PACKET
{
Endp = 0
DevAddr = 0xB
# Data pattern uses preprocessor variables.
Data = { k k k k k }
}
}
}
Forward Declarations
You can use declared items in generation procedures before their declarations.
Example
Main
{
# The packet template 'SOME_PKT_TEMPLATE' is declared later.
Send SOME_PKT_TEMPLATE
{
Field0 = 0xAABBCCDD
}
Call Block1() # The procedure 'Block1' is declared later.
# Declare the 'SOME_PKT_TEMPLATE' packet template used above.
Packet SOME_PKT_TEMPLATE
{
Field0 : 32 = 0xFEFEFEFE
}
}
# Declare the procedure 'Block1' used above.
Block1
{
Send TX_PACKET
}
RAND Token
You can use a RAND token in places where numeric literals are used to insert pseudo-random numbers in the range 0 to 0x7fff.
Note: By default, RAND uses a different integer seed value every time the script is compiled. You can set the seed using the RandSeed setting.
Example
Main
{
# The packet template 'SOME_PKT_TEMPLATE' is declared later.
Send SOME_PKT_TEMPLATE
{
Field0 = { 00 RAND RAND RAND RAND 00 } # Set random hex stream.
}
x = RAND # Assign a random value to the numeric variable.
}
RandStream( n ) Primitive
The RandStream( n ) primitive is a utility, based on the RAND token, that produces a random byte stream, where n is the number of bytes in the stream.
Note: For a description of random seeding, see the Note in the Rand Token section.
Example
Main
{
# The packet template 'SOME_PKT_TEMPLATE' is declared later.
Send SOME_PKT_TEMPLATE
{
Fieldof32bytes = RandStream(32) # Set a random 32-byte stream.
}
}
Global Numeric and Structure Variables
You can declare global numeric and structure variables that can be used in different generation procedures during parsing. Such global variables can be changed in one generation procedure, and then the changes are used in other generation procedures.
Example
Const MY_CONST = 77
x = 0xAA # Declare global numeric variable 'x'.
y = 0x12 # Declare global numeric variable 'y'.
z = MY_CONST # Declare global numeric variable 'z'.
# Declare a global structure variable 'Z' based on the template
# 'TX_PACKET'.
TX_PACKET $Z
# Declare a global structure variable 'Y' based on the template
# 'TX_PACKET'and change the default template field values.
TX_PACKET $Y
{
DevAddr = 0xAABB
}
# Another way to declare global structure variables:
# Declare the global structure variable 'Z' based on the template
#'TX_PACKET'.
$Z = TX_PACKET
# Declare the global structure variable 'Y' based on the template
# 'TX_PACKET' and change the default template field values.
$Y = TX_PACKET
{
DevAddr = 0xAABB
}
Main
{
Send $Z # Send a packet based on the global structure variable Z.
Send SOME_PKT_TEMPLATE
{
Field0 = y # Use the global numeric variable 'y' to change the
# default template field values.
}
}
For more examples of using global variables, see the examples for the CALL directive in the next section.
Using the Call Directive for Generation Procedure Insertions
You can declare a generation procedure with parameters and then "call" the generation procedure using the Call directive. The Call command inserts the other procedure instructions and takes into account the passed parameters or global variables at every call. This is called "dynamic" insertion, as opposed to the "static" insertion implemented by the insert directive.
Note: The Call directive copies instructions from the generation procedure. The Insert directive does not copy instructions from the generation procedure. Rather, the generation parser inserts a special Insert instruction with a reference to the "inserted" generation procedure.
Calling a Generation Procedure with Parameters
Using the Call directive, the parser can insert instructions from another generation procedure and, before insertion, provide some values for local parameters for use during parsing of that procedure.
Example 1
# Declare a packet template.
Packet SOME_PKT_TEMPLATE
{
Field0 : 32 = 0xFEFEFEFE
}
# Declare a generation procedure with two numeric parameters.
Block1( x, y )
{
# Send a packet based on the template 'SOME_PKT_TEMPLATE'.
Send SOME_PKT_TEMPLATE
{
# Procedure parameters 'x' and 'y' are used to override
# the default template field values.
Field0 = x + y
}
}
# The generation procedure now has one structure variable parameter and
# two numeric parameters.
Block2( SOME_PKT_TEMPLATE $pkt_param, x, y )
{
# Send a packet based on the structure variable parameter
# to 'pkt_param'.
Send pkt_param
{
Field0 = x + y
}
}
# Call another generation procedure.
Main
{
Send TX_PACKET # Send packet based on the template 'TX_PACKET'.
$X = SOME_PKT_TEMPLATE # Declare a variable X as a packet of type
# SOME_PKT_TEMPLATE.
w = 1
u = 0xAABB
# "Call" the procedure 'Block2' with parameters.
# Note: The actual structure variable parameter
# must have '$' before the name of a variable.
Call Block2 ( $X, w, u )
$X # Change the local structure variable 'X'.
{
Field0 = 5096
}
w = 1024 # Change the local numeric variable 'w'.
u = 12 # Change the local numeric variable 'u'.
Call Block2 ( $X, w, u ) # Call the procedure 'Block2' with new
# parameters.
# Note: The parser checks the variable structure parameters when
# processing the Call directive and allows only structure variables
# derived from the templates specified in the procedure declaration.
$X = DIFFERENT_TEMPLATE # Redeclare a structure variable using a
# template not derived from 'SOME_PKT_TEMPLATE'.
Call Block2 ( $X, w, w ) # !!! yields a parsing error.
}
Example 2
struct Generic
{
Data : *
}
Packet SOME_PACKET
{
# Header
HdrField0 : 16
HdrField1 : 16
HdrField2 : 32
# Payload
Data : *
CRC32 : 32
}
Block( Generic $X, Generic $Y )
{
Send SOME_PACKET
{
HdrField0 = 0xAAAA
HdrField1 = 0xBBBB
HdrField2 = 0xABCDBEEF
Data = $X + $Y # Combined payload
}
}
Main
{
$X = Generic
{
Data = { AA BB CC DD }
}
$Y = Generic
{
Data = { 00 11 22 33 }
}
Call Block( $X, $Y ) # Send a packet based on 'SOME_PACKET'
# template and Data = { AA BB CC DD 00 11 22 33 }
$X # Change the structure variable 'X'.
{
Data = { BE EF DA CD }
}
$Y # Change the structure variable 'Y'.
{
Data = { BE EF DA CD }
}
Call Block( $X, $Y ) # Send a packet based on 'SOME_PACKET'
# template and Data = { BE EF DA CD BE EF DA CD }
}
Calling a Generation Procedure with No Parameters
You can "call" a generation procedure and omit some of its parameters, because procedure parameters have default values.
Example
Block2( SOME_PKT_TEMPLATE $pkt_param, x, y )
{
# Send a packet based on the structure variable parameter 'pkt_param'.
Send pkt_param
{
Field0 = x + y
}
}
Generation
{
# Call the procedure 'Block2' with no parameters.
# In this case, use the default values for procedure parameters.
# Note: '(' ')' is mandatory after the procedure's name.
Call Block2()
}
Nested Calls Using Global Variables
You can call another generation procedure inside a generation procedure. This is called "nested calls". During such calls, the current values of global variables are used when the called generation procedure is parsed.
Example
z = 18
SOME_PKT_TEMPLATE $Z # Declare a global structure variable 'Z'
# based on the template 'SOME_PKT_TEMPLATE'.
Main
{
$Y = SOME_PKT_TEMPLATE # Declare a local structure variable 'Y'
{
Field0 = z + 12 # Use a global variable 'z'.
}
z++ # Increment the global variable 'z'.
Send Y # Send packet based on the local structure variable 'Y'.
Call Block1( $Y, 12, 10 ) # Call 'Block1'.
}
Block1( SOME_PKT_TEMPLATE $p, x, y )
{
$p # Change the local structure variable 'p'.
{
Field0 = 2*(x + y) + z # Use local variables 'x', 'y' and global
# variable 'z' here.
}
Send Z # Send packet based on the global variable 'Z'.
$Z # Change the global structure variable 'Z'.
{
Field0 = 0x0000BEEF
}
$Z[0, 4] = 0xA # Change the 4 bits of structure variable 'Z'
# at offset 0 bits.
Call Block2( $p ) # Call 'Block2'.
}
Block2( SOME_PKT_TEMPLATE $p )
{
Send p # Send packet based on the local structure variable 'p'.
Send Z # Send packet based on the global structure variable 'Z'.
}
Parser Tracing Functions
Parser tracing functions are debug tools that allow you to follow the generation process. These functions track script generation procedures and allow you to observe instruction generation and the changes of values of variables and template structures. Because the Voyager USB 3.1 Exerciser can create sophisticated and dynamic generation scripts, these functions are helpful in debugging.
Note: These functions have no affect on the compiled firmware instruction output. They only follow the paths taken in scripts to create instructions or values of variables and template structures.
PTrace( ) : Parser Trace
PTrace( )
Parser Trace without any supplied parameters outputs the line number from which it was called to the compilation output window.
PTrace( “output_string” )
Parser Trace with a supplied string parameter outputs the supplied string to the compilation output window when called.
Example
Main
{
PTrace ()
Send TX_PACKET
{
Data = {AA BB CC DD}
}
PTrace (“Sending Second TX_PACKET”)
Send TX_PACKET
{
Data = {EE FF 00 11}
}
PTrace ()
}
Output Window
-- Parsing started: File: C:\Sample_PTrace.usb3g. Operation Starts at time 08:44:07 PM --
Parsing...
c:\sample_ptrace_1.usb3g
***Parser Trace Message(c:\sample_ptrace_1.usb3g, line: 52) PTrace( ) from line 52
Sending Second TX_PACKET ( PTrace( … ) from line 57
***Parser Trace Message(c:\sample_ptrace_1.usb3g, line: 62) PTrace( ) from line 62
Parsing is done...
C:\Sample_PTrace_1.usb3g - 0 error(s)
C:\Sample_PTrace_1.usb3g - Generation Blocks : 1, Total number of instructions : 2
-- Parsing Finished: File: C:\Sample_PTrace.usb3g. Operation ends at time 08:44:08 PM --
PTraceVar( ) : Parser Trace Variable
PTraceVar( <variable list var1, var2, …> )
The Parser Trace Variable outputs the values of the supplied comma-separated variables. Numeric variables are output in decimal and hex format. Packet variables are output in byte streams (hex). This primitive does not accept constants or data patterns, which generate parse errors.
Note: Numeric variables are DWORDS.
Example
packet GenericData
{
DATA : *
}
GenericData $XYZ { DATA = { 00 11 00 11 00 11 00 11 } }
global_var = 7
Main
{
local_var = 12
PTraceVar ( global_var, local_var, $XYZ )
Send $XYZ #Send $XYZ with the following data for the instance.
{
Data = {AA BB CC DD}
}
PTraceVar ( $XYZ )
# Modify the value of $XYZ.
$XYZ { DATA = { EE FF 00 11 global_var local_var } }
local_var = 777777
PTraceVar ( $XYZ, local_var )
Send $XYZ # Send $XYZ.
PTraceVar ( $XYZ )
}
Output Window
- Parsing started: File: C:\Sample_PTraceVar.usb3g. Operation Starts at time 09:29:17 AM-
Parsing... c:\sample_ptracevar.usb3g
GLOBAL_VAR = 7 (hex: 0x7) PTraceVar( global_var, … ) from line 60
LOCAL_VAR = 12 (hex: 0xC) PTraceVar( …, local_var, … ) from line 60
$XYZ = {00 11 00 11 00 11 00 11} - 8 byte(s) PTraceVar( …, $XYZ ) from line 60
$XYZ = {00 11 00 11 00 11 00 11} - 8 byte(s) PTraceVar( $XYZ ) from line 67
$XYZ = {EE FF 00 11 07 0C} - 6 byte(s) PTraceVar( $XYZ, … ) from line 69
LOCAL_VAR = 777777 (hex: 0xBDE31) PTraceVar( …, local_var ) from line 69
$XYZ = {EE FF 00 11 07 0C} - 6 byte(s) PTraceVar( $XYZ ) from line 71
Parsing is done... C:\Sample_PTraceVar.usb3g - 0 error(s)
C:\Sample_PTraceVar.usb3g - Generation Blocks : 1, Total number of instructions : 2
- Parsing Finished: File: C:\Sample_PTraceVar.usb3g. Operation ends at time 09:29:17 AM -
PTraceVarEx( ) : Parser Trace Variable Extended
PTraceVarEx( <variable list var1, var2, …> )
Parser Trace Variable Extended outputs the values of the supplied comma-separated variables. PTraceVarEx( ) is the same as PTraceVar( ), except that packet variable values are output in detail at the field level, rather than just as a byte stream. Numeric variables are output in decimal and hex format. This primitive does not accept constants or data patterns, which generate parse errors. In the example below, also note that the language is not case sensitive.
Note: Numeric variables are DWORDS.
Example
struct IE_Info # Create Struct IE_Info.
{
ElemID : 8
ElemLen : 8
}
Packet Test_IE_ChSelect : IE_INFO # Create Packet Test_IE_ChSelect.
{
ElemID = 251
ElemLen = 2
TModeSubType : 8 = 1
PHYChNum : 8
}
Packet BPOIE : IE_INFO # Create Packet BPOIE.
{
ElemID = 1
BPLen : 8
Occupancy : *
DevAddrList : *
}
Test_IE_ChSelect $Pkt_Var { PHYCHNUM = 5 } # Global Packet Variable
BPOIE $Pkt_Var2 # Global Packet Variable
{
BPLen = 12
Occupancy = { 00 01 00 }
DevAddrList = 0x0004
ElemLen = 6
}
alternateCHNum = 7 # Global Numeric Variable
Main
{
PTraceVarEx ( $Pkt_Var, $Pkt_Var2 )
Send $Pkt_Var
$Pkt_Var { phychnum = alternatechnum } # Modify $Pkt_Var.
PTraceVarEx ( AlternateCHNum, $Pkt_Var )
Send $Pkt_Var
Send $Pkt_Var2
$Pkt_Var2 = { 01 08 0C 00 05 00 04 00 05 00 } # Modify $Pkt_Var2.
pkt_Var2 = 1 # Declare Local Variable pkt_var2 (note no ‘$’).
PTraceVarEx ( $Pkt_Var2, Pkt_Var2 )
if(pkt_var2 != 0) { Send $Pkt_Var2 }
}
Output Window:
Parsing started: File: C:\Sample_PTraceVarEx.usb3g. Operation Starts at time 05:50:10 PM
Parsing... c:\sample_ptracevarex.usb3g
$PKT_VAR = {FB 02 01 05} - 4 byte(s) PTraceVarEx( $Pkt_Var, … ) from line 81
Template name: TEST_IE_CHSELECT
Fields:
Field : ELEMID
index = 0, offset = 0, length = 8
Value : FB
Field : ELEMLEN
index = 1, offset = 8, length = 8
Value : 02
Field : TMODESUBTYPE
index = 2, offset = 16, length = 8
Value : 01
Field : PHYCHNUM
index = 3, offset = 24, length = 8
Value : 05
$PKT_VAR2 = {01 06 0C 00 01 00 04} - 7 byte(s) PTraceVarEx( …, $Pkt_Var2 ) from line 81
Template name: BPOIE
Fields:
Field : ELEMID
index = 0, offset = 0, length = 8
Value : 01
Field : ELEMLEN
index = 1, offset = 8, length = 8
Value : 06
Field : BPLEN
index = 2, offset = 16, length = 8
Value : 0C
Field : OCCUPANCY
index = 3, offset = 24, length = 24 (Variable length)
Value : 00 01 00
Field : DEVADDRLIST
index = 4, offset = 48, length = 8 (Variable length)
Value : 04
ALTERNATECHNUM = 7 (hex: 0x7) PTraceVarEx( alternatechnum, … ) from line 84
$PKT_VAR = {FB 02 01 07} - 4 byte(s) PTraceVarEx( …, $Pkt_Var2 ) from line 84
Template name: TEST_IE_CHSELECT
Fields:
Field : ELEMID
index = 0, offset = 0, length = 8
Value : FB
Field : ELEMLEN
index = 1, offset = 8, length = 8
Value : 02
Field : TMODESUBTYPE
index = 2, offset = 16, length = 8
Value : 01
Field : PHYCHNUM
index = 3, offset = 24, length = 8
Value : 07
$PKT_VAR2 = {01 08 0C 00 05 00 04 00 05 00} - 10 byte(s) PTraceVarEx($Pkt_Var2, …)
from line 89
Template name: BPOIE
Fields:
Field : ELEMID
index = 0, offset = 0, length = 8
Value : 01
Field : ELEMLEN
index = 1, offset = 8, length = 8
Value : 08
Field : BPLEN
index = 2, offset = 16, length = 8
Value : 0C
Field : OCCUPANCY
index = 3, offset = 24, length = 56 (Variable length)
Value : 00 05 00 04 00 05 00
Field : DEVADDRLIST
index = 4, offset = 80, length = 0 (Variable length)
Value : FE
PKT_VAR2 = 1 (hex: 0x1) PTraceVarEx( …, pkt_var2 ) from line 89
Parsing is done... C:\Sample_PTraceVarEx.usb3g - 0 error(s)
C:\Sample_PTraceVarEx.usb3g - Generation Blocks : 1, Total number of instructions : 4
-Parsing Finished: File: C:\Sample_PTraceVarEx.usb3g. Operation ends at time 05:50:10 PM
PtraceTemplate( ) : Parser Trace Template
PTraceTemplate( <template list Template_1, Template_2, …> )
The Parser Trace Template displays the layout of the supplied comma-separated templates. Use it to verify that template declaration was written as intended or to look at what the template type contains when the template has include statements. This primitive does not accept parameters other than templates, such as struct, packet, and packet names, which generate parse errors.
Example
const DPH = 0x8
Packet USB3Common
{
Type : 5
}
struct LinkCtrlWord
{
Hseq : 3
LcwRsvd : 3
HDepth : 3
D1 : 1
D2 : 1
CRC_5 : 5 # Auto calculated
}
Packet DataPacket : USB3Common
{
#Dword 0
Type = DPH
RouteStr : 20
DevAddr : 7
#Dword 1
SeqNum : 5
Rsvd1 : 1
Delayed : 1
EOB : 1
Endp : 4
Rsvd2 : 3
Setup : 1
DataLen : 16
#Dword 2
StreamID : 16
Rsvd3 : 11
PP : 1
Rsvd4 : 4
#Dword 3
CRC_16 : 16 # Auto calculated
: LinkCtrlWord # structure template insertion
Data : *
CRC32 : 32
}
Main
{
PTraceTemplate ( DataPacket, LinkCtrlWord )
Send DataPacket { DATA = { 01 08 0C 00 05 00 04 00 05 00 } }
}
Output Window
Parsing C:\Usb3 Gen Scripts\Usb3GenTest1.usb3g ...
--------------------------------------------------
Template : DATAPACKET
Template group : Generic
Top Ancestor Name : USB3COMMON
Fields:
Field : TYPE
index = 0, offset = 0, length = 5
Value : 08
Field : ROUTESTR
index = 1, offset = 5, length = 20
Field : DEVADDR
index = 2, offset = 25, length = 7
Field : SEQNUM
index = 3, offset = 32, length = 5
Field : RSVD1
index = 4, offset = 37, length = 1
Field : DELAYED
index = 5, offset = 38, length = 1
Field : EOB
index = 6, offset = 39, length = 1
Field : ENDP
index = 7, offset = 40, length = 4
Field : RSVD2
index = 8, offset = 44, length = 3
Field : SETUP
index = 9, offset = 47, length = 1
Field : DATALEN
index = 10, offset = 48, length = 16
Field : STREAMID
index = 11, offset = 64, length = 16
Field : RSVD3
index = 12, offset = 80, length = 11
Field : PP
index = 13, offset = 91, length = 1
Field : RSVD4
index = 14, offset = 92, length = 4
Field : CRC_16
index = 15, offset = 96, length = 16
Field : HSEQ
index = 16, offset = 112, length = 3
Field : LCWRSVD
index = 17, offset = 115, length = 3
Field : HDEPTH
index = 18, offset = 118, length = 3
Field : D1
index = 19, offset = 121, length = 1
Field : D2
index = 20, offset = 122, length = 1
Field : CRC_5
index = 21, offset = 123, length = 5
Field : DATA
index = 22, offset = 128, length = 0(Variable length)
Field : CRC32
index = 23, offset = 128, length = 32
---------------------------------------------------------
---------------------------------------------------------
Template : LINKCTRLWORD
Template group : Generic
Fields:
Field : HSEQ
index = 0, offset = 0, length = 3
Field : LCWRSVD
index = 1, offset = 3, length = 3
Field : HDEPTH
index = 2, offset = 6, length = 3
Field : D1
index = 3, offset = 9, length = 1
Field : D2
index = 4, offset = 10, length = 1
Field : CRC_5
index = 5, offset = 11, length = 5
---------------------------------------------------------
C:\Usb3 Gen Scripts\Usb3GenTest1.usb3g - 0 error(s)
Name Aliasing
You can specify different names for named generation language syntax objects, such as constants, settings, data patterns, templates, variables, generation procedures, instructions, and named instruction parameters.
For example, you can specify a name that is more understandable for a specific user. You can also use the same object in different contexts.
After a name alias is created, for the script parser, the alias_name is equivalent to the alias_value.
Note: Though you can create many name aliases for the same alias value, you cannot redefine a name alias that was defined before. Also, you cannot create aliases for language keywords, so syntax constructions (like Send) can never be named objects.
%alias Alias_Name = Alias_Value
Examples
%alias TxScr = TxScramble
%alias RxDescr = RxDescramble
%alias DPacket = Usb3LongTemplateNameDataPacket
Set TxScr = 1 # Use an alias for the 'TxScr' setting.
Packet Usb3LongTemplateNameDataPacket
{
Data : *
}
Main
{
Send Usb3LongTemplateNameDataPacket
{
Data = {AA BB CC DD}
}
# Use an alias for the ‘Usb3LongTemplateNameDataPacket' template.
# Send a packet based on the ‘Usb3LongTemplateNameDataPacket'
# template.
# Using aliases for packet/structure templates allows you to
# use short names instead of the long names defined in
# large template libraries.
Send DPacket
{
Data = {AA BB CC DD}
}
# It is allowed to declare an alias (the same as constant,
# data pattern, and template) inside a generation procedure.
%alias DP = Usb3LongTemplateNameDataPacket
Send DP
{
Data = {11 22 33 44}
}
}
Include Path Directive
This feature allows you to specify additional folders in which the parser looks for included files. By default, the script parser tries to include a file using a name specified in the %include directive. If it cannot find the file, it looks for the file in the Application directory.
%include_path [=] "include path"
Note: The include_path name is supposed to end with "\". If it does not end with "\", the script parser adds "\" automatically.
Examples
%include_path "C:\Usb3Generation\"
# You can also use '=' after %include_path.
%include_path = "C:\Usb3Generation\Include\"
%include "MyDefs.ginc" # The parser looks for the file
# in the following folders:
# 1. Application folder
# 2. C:\Usb3Generation\
# 3. C:\Usb3Generation\Include\
Main
{
# Do something.
}