PRU Assembly Reference Guide

From Texas Instruments Wiki
Jump to: navigation, search

^ Up to main Programmable Realtime Unit Software Development Table of Contents

This arcticle is part of a collection of articles describing software development on the PRU subsystem included in OMAP-L1x8/C674m/AM18xx devices (where m is an even number).  To navigate to the main PRU software development page click on the link above.

Overview

PASM is a non-linking two pass assembler. It assembles programs as a single monolithic image and directly generates executable code. As there is no linking stage in a PASM build, there are no section or segment directives, nor memory maps or command files.

In PASM, there are four basic assembly operators. These include dot "." commands, hash "#" commands, labels, and instructions (mnemonics). The user may supply comments that are invisible to the assembler.


Dot Commands

Dot commands are used to control the assembler, for example ".origin" and ".proc". They can also be used to declare complex data types as in the ".struct" directive.

The syntax rules for a dot command are as follows:

  • Must be the only assembly type on the line
  • Can be followed by a comment
  • Does not need to start in column 0

Origin (.origin) Command

The origin command is used to specify a code offset in the PRU source file. Typically a single origin statement is specified before any instructions, but multiple origin commands can be specified in order to insert space into the code map.

Example:

    .origin    8       // Start the next instruction at code offset 8

Entry Point (.entrypoint) Command

The entry point command is used to specify the code entry point to the debugger, and stores the information in the debug output file (*.dbg). It has no affect on any other output file type.

By default PASM will set the entry point to the first instruction generated by the assembly.

Examples:

    .entrypoint 0        // Set code entrypoint to address 0
    .entrypoint Start    // Set code entrypoint to the code label "Start"

Set Call/Return Register (.setcallreg) Command

This command sets the call/return register that is used in the CALL and RET pseudo op instructions. If this command is not specified, a default register of R30.w0 is used. This command must appear in the source code prior to any program instructions, and it must specify a 16 bit register field.

Example:

    .setcallreg  r15.w2  // Use R15.W2 in the CALL/RET pseudo ops

Start Macro Definition (.macro)

The .macro command is used to begin the definition of a macro. In the assembler, a macro can only be used in place of an opcode. There is always a single parameter to the command, being the name of the macro. Each macro section must start with a ".macro" and end with an ".endm".

See here for more details on using macros.

Example:

    .macro  mov32               // Define macro "mov32"        

Specific Macro Parameter(s) (.mparam)

The .mparam command is used to add one or more parameters to a macro. The form of the command is:

    .mparam   param1 [= default_value] [, param2 [= default_value] ]

When a parameter is given a default value, it is considered an optional parameter. Any optional parameters must be the last parameters specified in the parameter list. It is acceptable to supply both required and optional parameters on the same .mparam line.

See here for more details on using macros.

Example:

    .mparam    dst, src    // Define 2 required parameters, "dst" and "src"
    .mparam    temp = r0   // Define an optional parameter "temp" that
                           // defaults to the value "r0".

End Macro Definition (.endm)

The .endm command is used to complete the definition of a macro. It is required at the end of any macro specification. There are no parameters.

See here for more details on using macros.

Example:

    .endm                   // Completed defining macro

Structure (.struct) Command

The structure command is used to open a declaration to a new structure in PASM. PASM uses structures to generate standard equates, and allow the user to perform register allocation to private structure instances.

See here for more details on using scope and structures.

Example:

    .struct myStruct        // Declare a structure template called "myStruct"

End Structure (.ends) Command

The end structure command is used to close a structure declaration. PASM uses structures to generate standard equates, and allow the user to perform register allocation to private structure instances.

See here for more details on using scope and structures.

Example:

    .ends

Field Directives (.u8, .u16, .u32)

Field directives are used within an open structure declaration to define fields within the structure.

See here for more details on using scope and structures.

Example:

    .struct MyStruct
        .u32    MyInt                   // 32 bit field
        .u16    MyShort                 // 16 bit field
        .u8     MyByte1                 //  8 bit field
        .u8     MyByte2                 //  8 bit field
    .ends

Assignment Directive (.assign)

The assignment directive is used to map a defined structure onto the PRU register file. An assign statement can begin on any register boundary.

The programmer may declare the full assignment span manually (both starting and ending register), or leave the ending register blank. When the programmer declares a full register span, PASM will generate an error when the specified span is incorrect. This allows the programmer to formally map structures to specific register spans, reducing the chance that register assignments will accidentally overlap.

Some structures will also require specific alignments due to how their fields are arranged within the structure. PASM will generate an error if the structure alignment requirements can not be met with the specified starting register.

See here for more details on using scope and structures.

Example:

    .assign MyStruct, R4, R5, MyName1  // Make sure this uses R4 thru R5
    .assign MyStruct, R6,  *, MyName2  // Don’t need to validate the range

Enter New Variable Scope (.enter)

The .enter command is used to create and enter a new variable scope. There is a single parameter to the command that specifies the name of the scope. Any structures that are assigned inside a named scope can only be accessed when the scope is open. Use of variable scopes is optional.

See here for more details on using scope and structures.

Example:

    .enter  Scope1      // Create and enter scope named "Scope1"

Leave a Variable Scope (.leave)

The .leave command is used to leave a specific variable scope. There is a single parameter to the command that specifies the name of the scope to leave. Scopes do not need to be entered or left in any particular order, but a natural ordering can be enforced by the programmer.

See here for more details on using scope and structures.

Example:

    .enter Scope1       // Create and enter scope named "Scope1"
      .enter Scope2     // Create and enter scope named "Scope2"
      .leave Scope2     // Leave scope named "Scope2"
    .leave Scope1       // Leave scope named "Scope1"

Referencing an Existing Variable Scope (.using)

The .using command is used to enter a specific variable scope that has been previously created and left. There is a single parameter to the command that specifies the name of the scope to enter. The .leave command is then used to leave the scope after being entered with .using.

See here for more details on using scope and structures.

Example:

    .using Scope1       // Enter existing scope named "Scope1"
      .using Scope2     // Enter existing scope named "Scope2"
      .leave Scope2     // Leave scope named "Scope2"
    .leave Scope1       // Leave scope named "Scope1"

Hash Commands

Hash commands are used to control the assembler pre-processor. They are quite similar to their C counterparts.

The syntax rules for a hash command are as follows:

  • Must be the only assembly type on the line
  • Can be followed by a comment
  • Does not need to start in column 0

Include (#include) Command

The #include command is used to include additional source files in the assembly process. When a "#include" is specified, the included file is immediately opened, parsed, and processed.

The calling syntax for #include can use quotes ’" "’ or brackets "< >". Specifying quotes is functionally equivalent to specifying brackets. For example:

#include "localInclude.h"
#include "c:\include\myInclude.h"
#include <inc\myInclude.h>

As PASM uses a monolithic single source approach, the #include statement can be used to specify external source files. This allows a developer to break up a complicated application into several smaller source files.

For example, an application may consist of a master source file "myApp.p" which itself contains nothing but include commands for including sub source files. The contents of "myApp.p" may appear as follows:

#include "myInitialization.p"
#include "myMainLoop.p"
#include "mySubroutines.p"

The above lines would include each source file in turn, concatenating one after the other in the final code image. Each of these included source files may have additional include files of their own.

Including the same include file multiple times will not result in an error, however including files recursively will result in an error.

Define (#define) Command

The "#define" command is used to specify a simple text substitution. Any text defined in a #define is substituted for the defined name within the code.

For example, if the programmer writes:

#define BUFFER_ADDRESS	0x08001000
        ldi     r1.w0, BUFFER_ADDRESS & 0xFFFF
        ldi     r1.w2, BUFFER_ADDRESS >> 16

This would load 0x1000 into register r1.w0 and then 0x0800 into register r1.w2.

Equates are expanded recursively, so the value of the define does not need to be resolved until it is used. For example:

#define B A
#define A 1
        ldi     r1, B

The above will load "1" in register r1.

Undefine (#undef) Command

The "#undef" command is used to undefined a constant that was previously assigned via #define.

For example:

// Redefine our buffer address without generating an assmbler warning
#undef BUFFER_ADDRESS
#define BUFFER_ADDRESS	0x08001000

Error (#error) Command

The "#error" command is used to specify an error during assembly. For example, if the programmer wishes to verify the constant value MYMODE is defined, they can write:

#ifndef MYMODE
#error Mode not specified
#endif

The above will produce an error if the program is assembled and MYMODE is not defined.

"If Defined" (#ifdef) Command

The "#ifdef" command is used to specify a block of conditional code based on whether the supplied constant is defined. Here, the code inside the #ifdef block will be assembled only if the constant is defined, regardless of its defined value. Every #ifdef must be followed by a #endif. For example:

#define MYVAL 1
#ifdef MYVAL
    // This code in this block will be assembled
#endif

#undef MYVAL
#ifdef MYVAL
    // This code in this block will NOT be assembled
#endif

"If Not Defined" (#ifndef) Command

The "#ifndef" command is used to specify a block of conditional code based on whether the supplied constant is defined. Here, the code inside the #ifndef block will be assembled only if the constant is not defined. Every #ifndef must be followed by a #endif. For example:

#define MYVAL 1
#ifndef MYVAL
    // This code in this block will NOT be assembled
#endif

#undef MYVAL
#ifndef MYVAL
    // This code in this block will be assembled
#endif

"End If" (#endif) Command

The "#endif" command is used to close a previously open #ifdef or #ifndef, thus closing the conditional assembly block.

"Else" (#else) Command

The "#else" command is used to specify a block of conditional code based on a previous #ifdef or #ifndef, allowing for the opposite case. For example:

#define MYVAL 1
#ifdef MYVAL
    // This code in this block will be assembled
#else
    // This code in this block will NOT be assembled
#endif

Labels

Labels are used denote program addresses. When placed at the beginning of a source line and immediately followed by a colon ’:’, they mark a program address location. When referenced by an instruction, the corresponding marked address is substituted for the label.

The syntax rules for labels are as follows:

  • A label definition must be immediately followed by a colon.
  • Only instructions and/or comments can occupy the same source line as a label.
  • Labels can use characters ’A’-’Z’, ’a’-’z’, ’0’-’9’ plus underscores ’_’ and dots ’.’.
  • A label can not begin with a number (’0’-’9’).

The following illustrates defining and using the label named "loop_label":

        ldi     r0, 100
loop_label:
        sub     r0, r0, 1
        qbne    loop_label, r0, 0
        ret


Comments

In PASM comments are transparent to all other operations, thus they can appear anywhere on any source line. However, since comments are terminated by the end of line, they are by definition, the last field on a line.

The syntax rules for comments are as follows:

  • Comments must be preceded by ’//’
  • Comments are always the last field to appear on a line

The following illustrates defining a comment:

       //-------------------------
       // This is a comment
       //-------------------------
       ldi     r0, 100     // This is a comment


Return to Main Page on PRU Software Development

Click here.