v10.50 v10.55 Alpha v10.54 Alpha v10.53 Alpha v10.52 Alpha v10.51 Alpha
v10.50 v10.55 Alpha v10.54 Alpha v10.53 Alpha v10.52 Alpha v10.51 Alpha

Advanced Script Parser Features

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.

C++
[ 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:

  1. The hex stream fills all fixed-length fields prior to the first variable-length field, using a
    top-down approach.

  2. 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.

  3. 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.

C++
%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.
}