TMS320C28x Assembly Language Tools v15.12.0.LTS User's Guide
SPRU513J - REVISED JANUARY 2016

4 Assembler Description

The TMS320C28x assembler translates assembly language source files into machine language object files. These files are object modules, which are discussed in Section 2. Source files can contain the following assembly language elements:

Assembler directives described in Section 5
Macro directives described in Section 6
Assembly language instructions described in the TMS320C28x DSP CPU and Instruction Set Reference Guide.

4.1 Assembler Overview

The 2-pass assembler does the following:

  • Processes the source statements in a text file to produce a relocatable object file
  • Produces a source listing (if requested) and provides you with control over this listing
  • Allows you to divide your code into sections and maintain a section program counter (SPC) for each section of object code
  • Defines and references global symbols and appends a cross-reference listing to the source listing (if requested)
  • Allows conditional assembly
  • Supports macros, allowing you to define macros inline or in a library

4.2 The Assembler's Role in the Software Development Flow

Figure 4-1 illustrates the assembler's role in the software development flow. The shaded portion highlights the most common assembler development path. The assembler accepts assembly language source files as input, both those you create and those created by the TMS320C28x C/C++ compiler.

Figure 4-1 The Assembler in the TMS320C28x Software Development Flow assyflow_pru513.gif

4.3 Invoking the Assembler

To invoke the assembler, enter the following:

cl2000input file [options]
cl2000 is the command that invokes the assembler through the compiler. The compiler considers any file with an .asm extension to be an assembly file and invokes the assembler.
input file names the assembly language source file.
options

identify the assembler options that you want to use. Options are case sensitive and can appear anywhere on the command line following the command. Precede each option with one or two hyphens as shown.

The valid assembler options are listed in Table 4-1.

Table 4-1 TMS320C28x Assembler Options

Option Alias Description
--absolute_listing -aa Creates an absolute listing. When you use --absolute_listing, the assembler does not produce an object file. The --absolute_listing option is used in conjunction with the absolute lister.
--asm_code_fill=value Specifies fill value for code sections. Default is zero. See Section 4.10.
--asm_data_fill=value Specifies fill value for data sections. Default is NOP instructions. See Section 4.10.
--asm_define=name[=def] -ad Sets the name symbol. This is equivalent to defining name with a .set directive in the case of a numeric value or with an .asg directive otherwise. If value is omitted, the symbol is set to 1. See Section 4.7.5.
--asm_dependency -apd Performs preprocessing for assembly files, but instead of writing preprocessed output, writes a list of dependency lines suitable for input to a standard make utility. The list is written to a file with the same name as the source file but with a .ppa extension.
--asm_includes -api Performs preprocessing for assembly files, but instead of writing preprocessed output, writes a list of files included with the .include directive. The list is written to a file with the same name as the source file but with a .ppa extension.
--asm_listing -al Produces a listing file with the same name as the input file with a .lst extension.
--asm_remarks -mw Enables additional assembly-time checking. A warning is generated if an .ebss allocation size is greater than 64 words, or a 16-bit operand value resides outside of the -32768 to 65535 range.
--asm_undefine=name -au Undefines the predefined constant name, which overrides any --asm_define options for the specified constant.
--c2xlp_src_compatible -m20 Accepts C2xLP assembly instructions and encodes them as equivalent C28x instructions. See Section 4.11.
--cdebug_asm_data -mg Produces C-type symbolic debugging for assembly variables defined in assembly source code using data directives. This support is for basic C types, structures, and arrays.
--cla_support[=cla0|cla1] Specifies TMS320C28x Control Law Accelerator (CLA) Type 0 or Type 1 support. This option is used to compile or assemble code written for the CLA. This option does not need any special library support when linking; the libraries used for C28x with/without FPU support should be sufficient.
--cmd_file=filename -@ Appends the contents of a file to the command line. You can use this option to avoid limitations on command line length imposed by the host operating system. Use an asterisk or a semicolon (* or ;) at the beginning of a line in the command file to include comments. Comments that begin in any other column must begin with a semicolon. Within the command file, filenames or option parameters containing embedded spaces or hyphens must be surrounded with quotation marks. For example: "this-file.asm"
--copy_file=filename -ahc Copies the specified file for the assembly module. The file is inserted before source file statements. The copied file appears in the assembly listing files.
--cross_reference -ax Produces a cross-reference table and appends it to the end of the listing file; it also adds cross-reference information to the object file for use by the cross-reference utility. If you do not request a listing file but use the --cross_reference option, the assembler creates a listing file automatically, naming it with the same name as the input file with a .lst extension.
--float_support={ fpu32|fpu64} Assembles code for C28x with 32-bit or 64-bit hardware FPU support.
--include_file=filename -ahi Includes the specified file for the assembly module. The file is included before source file statements. The included file does not appear in the assembly listing files.
--include_path=pathname -I Specifies a directory where the assembler can find files named by the .copy, .include, or .mlib directives. There is no limit to the number of directories you can specify in this manner; each pathname must be preceded by the --include_path option. See Section 4.4.1.
--out_as_uout -mu Encodes C2xlp OUT instructions as C28x UOUT instructions. The C28x processor has protected (OUT) and unprotected (UOUT) instructions. By default, the assembler encodes C2xlp OUT instructions as C28x protected OUT instructions. This option is ignored if --c2xlp_src_compatible is not specified.
--output_all_syms -as Puts all defined symbols in the object file's symbol table. The assembler usually puts only global symbols into the symbol table. When you use --output_all_syms, symbols defined as labels or as assembly-time constants are also placed in the table.
--quiet -q Suppresses the banner and progress information (assembler runs in quiet mode).
--symdebug:dwarf or
--symdebug:none
-g (DWARF is on by default) Enables assembler source debugging in the C source debugger. Line information is output to the object module for every line of source in the assembly language source file. You cannot use this option on assembly code that contains .line directives. See Section 4.13.
--syms_ignore_case -ac Makes case insignificant in the assembly language files. For example, --syms_ignore_case makes the symbols ABC and abc equivalent. If you do not use this option, case is significant (default). Case significance is enforced primarily with symbol names, not with mnemonics and register names.
--vcu_support[=vcu0|vcu2] Specifies support for the Viterbi, Complex Math and CRC Unit (VCU), Type 0 or Type 2. The default is vcu0. Note that there is no VCU Type 1. This option is useful only if the source is in assembly code, written for the VCU. The option is ignored for C/C++ code. This option does not require any special library support from the linker; the libraries used for C28x with/without VCU support should be sufficient.

4.4 Naming Alternate Directories for Assembler Input

The .copy, .include, and .mlib directives tell the assembler to use code from external files. The .copy and .include directives tell the assembler to read source statements from another file, and the .mlib directive names a library that contains macro functions. Section 5 contains examples of the .copy, .include, and .mlib directives. The syntax for these directives is:

.copy ["]filename["]
.include ["]filename["]
.mlib ["]filename["]

The filename names a copy/include file that the assembler reads statements from or a macro library that contains macro definitions. If filename begins with a number the double quotes are required. Quotes are recommended so that there is no issue in dealing with path information that is included in the filename specification or path names that include white space. The filename may be a complete pathname, a partial pathname, or a filename with no path information.

The assembler searches for the file in the following locations in the order given:

  1. The directory that contains the current source file. The current source file is the file being assembled when the .copy, .include, or .mlib directive is encountered.
  2. Any directories named with the --include_path option
  3. Any directories named with the C2000_A_DIR environment variable
  4. Any directories named with the C2000_C_DIR environment variable

Because of this search hierarchy, you can augment the assembler's directory search algorithm by using the --include_path option (described in Section 4.4.1) or the C2000_A_DIR environment variable (described in Section 4.4.2). The C2000_C_DIR environment variable is discussed in the TMS320C28x Optimizing C/C++ Compiler User's Guide.

4.4.1 Using the --include_path Assembler Option

The --include_path assembler option names an alternate directory that contains copy/include files or macro libraries. The format of the --include_path option is as follows:

cl2000 --include_path=pathname source filename [other options]

There is no limit to the number of --include_path options per invocation; each --include_path option names one pathname. In assembly source, you can use the .copy, .include, or .mlib directive without specifying path information. If the assembler does not find the file in the directory that contains the current source file, it searches the paths designated by the --include_path options.

For example, assume that a file called source.asm is in the current directory; source.asm contains the following directive statement:

.copy "copy.asm"

Assume the following paths for the copy.asm file:

UNIX: /tools/files/copy.asm
Windows: c:\tools\files\copy.asm

You could set up the search path with the commands shown below:

Operating System Enter
UNIX (Bourne shell) cl2000 --include_path=/tools/files source.asm
Windows cl2000 --include_path=c:\tools\files source.asm

The assembler first searches for copy.asm in the current directory because source.asm is in the current directory. Then the assembler searches in the directory named with the --include_path option.

4.4.2 Using the C2000_A_DIR Environment Variable

An environment variable is a system symbol that you define and assign a string to. The assembler uses the C2000_A_DIR environment variable to name alternate directories that contain copy/include files or macro libraries.

The assembler looks for the C2000_A_DIR environment variable and then reads and processes it. If the assembler does not find the C2000_A_DIR variable, it then searches for C2000_C_DIR. The processor-specific variables are useful when you are using Texas Instruments tools for different processors at the same time.

See the TMS320C28x Optimizing C/C++ Compiler User's Guide for details on C2000_C_DIR.

The command syntax for assigning the environment variable is as follows:

Operating System Enter
UNIX (Bourne Shell) C2000_A_DIR="pathname1 ;pathname2 ; . . . "; export C2000_A_DIR
Windows set C2000_A_DIR=pathname1 ;pathname2 ; . . .

The pathnames are directories that contain copy/include files or macro libraries. The pathnames must follow these constraints:

  • Pathnames must be separated with a semicolon.
  • Spaces or tabs at the beginning or end of a path are ignored. For example the space before and after the semicolon in the following is ignored:
  • set C28X_A_DIR= c:\path\one\to\tools ; c:\path\two\to\tools
  • Spaces and tabs are allowed within paths to accommodate Windows directories that contain spaces. For example, the pathnames in the following are valid:
  • set C28X_A_DIR=c:\first path\to\tools;d:\second path\to\tools

In assembly source, you can use the .copy, .include, or .mlib directive without specifying path information. If the assembler does not find the file in the directory that contains the current source file or in directories named by the --include_path option, it searches the paths named by the environment variable.

For example, assume that a file called source.asm contains these statements:

.copy "copy1.asm" .copy "copy2.asm"

Assume the following paths for the files:

UNIX: /tools/files/copy1.asm and /dsys/copy2.asm
Windows: c:\tools\files\copy1.asm and c:\dsys\copy2.asm

You could set up the search path with the commands shown below:

Operating System Enter
UNIX (Bourne shell) C2000_A_DIR="/dsys"; export C2000_A_DIR
cl2000 --include_path=/tools/files source.asm
Windows C2000_A_DIR=c:\dsys
cl2000 --include_path=c:\tools\files source.asm

The assembler first searches for copy1.asm and copy2.asm in the current directory because source.asm is in the current directory. Then the assembler searches in the directory named with the --include_path option and finds copy1.asm. Finally, the assembler searches the directory named with C2000_A_DIR and finds copy2.asm.

The environment variable remains set until you reboot the system or reset the variable by entering one of these commands:

Operating System Enter
UNIX (Bourne shell) unset C2000_A_DIR
Windows set C2000_A_DIR=

4.5 Source Statement Format

Each line in a TMS320C28x assembly input file can be empty, a comment, an assembler directive, a macro invocation, or an assembly instruction.

Assembly language source statements can contain four ordered fields (label, mnemonic, operand list, and comment). The general syntax for source statements is as follows:

[label[:] ] [||] mnemonic [operand list] [;comment]

Labels cannot be placed on instructions that have parallel bars.

Following are examples of source statements:

two .set 2 ; Symbol two = 2 Begin: MOV AR1,#two ; Load AR1 with 2 .word 016h ; Initialize a word with 016h

The C28x assembler reads an unlimited number of characters per line. Source statements that extend beyond 400 characters in length (including comments) are truncated in the listing file.

Follow these guidelines:

  • All statements must begin with a label, a blank, an asterisk, or a semicolon.
  • Labels are optional for most statements; if used, they must begin in column 1.
  • One or more space or tab characters must separate each field.
  • Comments are optional. Comments that begin in column 1 can begin with an asterisk or a semicolon (* or ;), but comments that begin in any other column must begin with a semicolon.

NOTE

A mnemonic cannot begin in column 1 or it will be interpreted as a label. Mnemonic opcodes and assembler directive names without the . prefix are valid label names. Remember to always use whitespace before the mnemonic, or the assembler will think the identifier is a new label definition.

The following sections describe each of the fields.

4.5.1 Label Field

A label must be a legal identifier (see Section 4.7.1) placed in column 1. Every instruction may optionally have a label. Many directives allow a label, and some require a label.

A label can be followed by a colon (:). The colon is not treated as part of the label name. If you do not use a label, the first character position must contain a blank, a semicolon, or an asterisk.

When you use a label on an assembly instruction or data directive, an assembler symbol (Section 4.7) with the same name is created. Its value is the current value of the section program counter (SPC, see Section 2.3.5). This symbol represents the address of that instruction. In the following example, the .word directive is used to create an array of 3 words. Because a label was used, the assembly symbol Start refers to the first word, and the symbol will have the value 40h.

. . . . . . . . . . . . 9 * Assume some code was assembled 10 000040 000A Start: .word 0Ah,3,7 000044 0003 000048 0007

A label on a line by itself is a valid statement. When a label appears on a line by itself, it points to the instruction on the next line (the SPC is not incremented):

1 000000 Here: 2 000000 0003 .word 3

A label on a line by itself is equivalent to writing:

Here: .equ $ ; $ provides the current value of the SPC

If you do not use a label, the character in column 1 must be a blank, an asterisk, or a semicolon.

4.5.2 Mnemonic Field

The mnemonic field follows the label field. The mnemonic field cannot start in column 1; if it does, it is interpreted as a label. The mnemonic field can begin with pipe symbols (||) when the previous instruction is a RPT. Pipe symbols that follow a RPT instruction indicate instructions that are repeated. For example:

instrpt_pru513.gif

In the case of C28x with FPU support, the mnemonic field can begin with pipe symbols to indicate instructions that are to be executed in parallel. For example, in the instance given below, Inst1 and Inst2 are FPU instructions that execute in parallel:

instrpt_fpu_pru513.gif

Next, the mnemonic field contains one of the following items:

  • Machine-instruction mnemonic (such as ADD, MOV, or B)
  • Assembler directive (such as .data, .list, .equ)
  • Macro directive (such as .macro, .var, .mexit)
  • Macro invocation

4.5.3 Operand Field

The operand field follows the mnemonic field and contains zero or more comma-separated operands. An operand can be one of the following:

  • an immediate operand (usually a constant or symbol) (see Section 4.6 and Section 4.7)
  • a register operand
  • a memory reference operand
  • an expression that evaluates to one of the above (see Section 4.8)

An immediate operand is encoded directly in the instruction. The value of an immediate operand must be a constant expression. Most instructions with an immediate operand require an absolute constant expression, such as 1234. Some instructions (such as a call instruction) allow a relocatable constant expression, such as a symbol defined in another file. (See Section 4.8 for details about types of expressions.)

A register operand is a special pre-defined symbol that represents a CPU register.

A memory reference operand uses one of several memory addressing modes to refer to a location in memory. Memory reference operands use a special target-specific syntax defined in the appropriate CPU and Instruction Set Reference Guide.

You must separate operands with commas. Not all operand types are supported for all operands. See the description of the specific instruction in the CPU and Instruction Set Reference Guide for your device family.

4.5.4 Comment Field

A comment can begin in any column and extends to the end of the source line. A comment can contain any ASCII character, including blanks. Comments are printed in the assembly source listing, but they do not affect the assembly.

A source statement that contains only a comment is valid. If it begins in column 1, it can start with a semicolon ( ; ) or an asterisk ( *). Comments that begin anywhere else on the line must begin with a semicolon. The asterisk identifies a comment only if it appears in column 1.

4.6 Literal Constants

A literal constant (also known as a literal or in some other documents as an immediate value) is a value that represents itself, such as 12, 3.14, or "hello".

The assembler supports several types of literals:

  • Binary integer literals
  • Octal integer literals
  • Decimal integer literals
  • Hexadecimal integer literals
  • Character literals
  • Character string literals
  • Floating-point literals

Error checking for invalid or incomplete literals is performed.

4.6.1 Integer Literals

The assembler maintains each integer literal internally as a 32-bit signless quantity. Literals are considered unsigned values, and are not sign extended. For example, the literal 00FFh is equal to 00FF (base 16) or 255 (base 10); it does not equal -1. which is 0FFFFFFFFh (base 16). Note that if you store 0FFh in a .byte location, the bits will be exactly the same as if you had stored -1. It is up to the reader of that location to interpret the signedness of the bits.

4.6.1.1 Binary Integer Literals

A binary integer literal is a string of up to 32 binary digits (0s and 1s) followed by the suffix B (or b). Binary literals of the form "0[bB][10]+" are also supported. If fewer than 32 digits are specified, the assembler right justifies the value and fills the unspecified bits with zeros. These are examples of valid binary literals:

00000000B Literal equal to 010 or 016
0100000b Literal equal to 3210 or 2016
01b Literal equal to 110 or 116
11111000B Literal equal to 24810 or 0F816
0b00101010 Literal equal to 4210 or 2A16
0B101010 Literal equal to 4210 or 2A16
4.6.1.2 Octal Integer Literals

An octal integer literal is a string of up to 11 octal digits (0 through 7) followed by the suffix Q (or q). Octal literals may also begin with a 0, contain no 8 or 9 digits, and end with no suffix. These are examples of valid octal literals:

10Q Literal equal to 810 or 816
054321 Literal equal to 2273710 or 58D116
100000Q Literal equal to 3276810 or 800016
226q Literal equal to 15010 or 9616

NOTE

Octal Numbers Are Not Accepted With C2xlp Syntax Mode

When the --c2xlp_src_compatible option is specified, cl2000 accepts C2xlp source code. The C2xlp assembler interpreted numbers with leading zeros as decimal integers, that is 010 was interpreted as 10. Because of this, when cl2000 is invoked with --c2xlp_src_compatible --asm_remarks, the assembler issues a warning when it encounters an octal number.

4.6.1.3 Decimal Integer Literals

A decimal integer literal is a string of decimal digits ranging from -2147 483 648 to 4 294 967 295. These are examples of valid decimal integer literals:

1000 Literal equal to 100010 or 3E816
-32768 Literal equal to -32 76810 or -800016
25 Literal equal to 2510 or 1916
4815162342 Literal equal to 481516234210 or 11F018BE616
4.6.1.4 Hexadecimal Integer Literals

A hexadecimal integer literal is a string of up to eight hexadecimal digits followed by the suffix H (or h) or preceded by 0x. A hexadecimal literal must begin with a decimal value (0-9) if it is indicated by the H or h suffix.

Hexadecimal digits include the decimal values 0-9 and the letters A-F or a-f. If fewer than eight hexadecimal digits are specified, the assembler right-justifies the bits.

These are examples of valid hexadecimal literals:

78h Literal equal to 12010 or 007816
0x78 Literal equal to 12010 or 007816
0Fh Literal equal to 1510 or 000F16
37ACh Literal equal to 1425210 or 37AC16
4.6.1.5 Character Literals

A character literal is a single character enclosed in single quotes. The characters are represented internally as 8-bit ASCII characters. Two consecutive single quotes are required to represent each single quote that is part of a character literal. A character literal consisting only of two single quotes is valid and is assigned the value 0. These are examples of valid character literals:

'a' Defines the character literal a and is represented internally as 6116
'C' Defines the character literal C and is represented internally as 4316
'''' Defines the character literal ' and is represented internally as 2716
'' Defines a null character and is represented internally as 0016
Notice the difference between character literals and character string literals (Section 4.6.2 discusses character strings). A character literal represents a single integer value; a string is a sequence of characters.

4.6.2 Character String Literals

A character string is a sequence of characters enclosed in double quotes. Double quotes that are part of character strings are represented by two consecutive double quotes. The maximum length of a string varies and is defined for each directive that requires a character string. Characters are represented internally as 8-bit ASCII characters.

These are examples of valid character strings:

"sample program" defines the 14-character string sample program.
"PLAN ""C""" defines the 8-character string PLAN "C".

Character strings are used for the following:

  • Filenames, as in .copy "filename"
  • Section names, as in .sect "section name"
  • Data initialization directives, as in .byte "charstring"
  • Operands of .string directives

4.6.3 Floating-Point Literals

A floating-point literal is a string of decimal digits followed by a required decimal point, an optional fractional portion, and an optional exponent portion. The syntax for a floating-point number is:

[ +|- ] nnn . [ nnn] [ E|e [ +|- ] nnn ]

Replace nnn with a string of decimal digits. You can precede nnn with a + or a -. You must specify a decimal point. For example, 3.e5 is valid, but 3e5 is not valid. The exponent indicates a power of 10. These are examples of valid floating-point literals:

3.0 3.14 3. -0.314e13 +314.59e-2

The assembler syntax does not support all C89-style float literals nor C99-style hexadecimal constants, but the $strtod built-in mathematical function supports both. If you want to specify a floating-point literal using one of those formats, use $strtod. For example:

$strtod(".3") $strtod("0x1.234p-5")

You cannot directly use NaN, Inf, or -Inf as floating-point literals. Instead, use $strtod to express these values. The "NaN" and "Inf" strings are handled case-insensitively.

$strtod("NaN") $strtod("Inf")

4.7 Assembler Symbols

An assembler symbol is a named 32-bit signless integer value, usually representing an address or absolute integer. A symbol can represent such things as the starting address of a function, variable, or section. The name of a symbol must be a legal identifier. The identifier becomes a symbolic representation of the symbol's value, and may be used in subsequent instructions to refer to the symbol's location or value.

Some assembler symbols become external symbols, and are placed in the object file's symbol table. A symbol is valid only within the module in which it is defined, unless you use the .global directive or the .def directive to declare it as an external symbol (see .global directive).

See Section 2.5 for more about symbols and the symbol tables in object files.

4.7.1 Identifiers

Identifiers are names used as labels, registers, symbols, and substitution symbols. An identifier is a string of alphanumeric characters, the dollar sign, and underscores (A-Z, a-z, 0-9, $, and _). The first character in an identifier cannot be a number, and identifiers cannot contain embedded blanks. The identifiers you define are case sensitive; for example, the assembler recognizes ABC, Abc, and abc as three distinct identifiers. You can override case sensitivity with the --syms_ignore_case assembler option (see Section 4.3).

4.7.2 Labels

An identifier used as a label becomes an assembler symbol, which represent an address in the program. Labels within a file must be unique.

NOTE

A mnemonic cannot begin in column 1 or it will be interpreted as a label. Mnemonic opcodes and assembler directive names without the . prefix are valid label names. Remember to always use whitespace before the mnemonic, or the assembler will think the identifier is a new label definition.

Symbols derived from labels can also be used as the operands of .global, .ref, or .def directives.

.global label1 label2: NOP ADD AR1, label1 SB label2, UNC

4.7.3 Local Labels

Local labels are special labels whose scope and effect are temporary. A local label can be defined in two ways:

  • $n, where n is a decimal digit in the range 0-9. For example, $4 and $1 are valid local labels. See Example 4-1.
  • name?, where name is any legal identifier as described above. The assembler replaces the question mark with a period followed by a unique number. When the source code is expanded, you will not see the unique number in the listing file. Your label appears with the question mark as it did in the source definition. See Example 4-2.

You cannot declare these types of labels as global.

Normal labels must be unique (they can be declared only once), and they can be used as constants in the operand field. Local labels, however, can be undefined and defined again. Local labels cannot be defined by directives.

A local label can be undefined or reset in one of these ways:

  • By using the .newblock directive
  • By changing sections (using a .sect, .text, or .data directive)
  • By entering an include file (specified by the .include or .copy directive)
  • By leaving an include file (specified by the .include or .copy directive)

Example 4-1 Local Labels of the Form $n

This is an example of code that declares and uses a local label legally:

$1: ADDB AL, #-7 B $1, GEQ .newblock ; undefine $1 to use it again. $1 MOV T, AL MPYB ACC, T, #7 CMP AL, #1000 B $1, LT

The following code uses a local label illegally:

$1: ADDB AL, #-7 B $1, GEQ $1 MOV T, AL ; WRONG - $1 is multiply defined. MPYB ACC, T, #7 CMP AL, #1000 B $1, LT

The $1 label is not undefined before being reused by the second branch instruction. Therefore, $1 is redefined, which is illegal.

Local labels are especially useful in macros. If a macro contains a normal label and is called more than once, the assembler issues a multiple-definition error. If you use a local label and .newblock within a macro, however, the local label is used and reset each time the macro is expanded.

Up to ten local labels of the $n form can be in effect at one time. Local labels of the form name? are not limited. After you undefine a local label, you can define it and use it again. Local labels do not appear in the object code symbol table.

Example 4-2 Local Labels of the Form name?

**************************************************************** ** First definition of local label mylab ** **************************************************************** nop mylab? nop B mylab?, UNC **************************************************************** ** Include file has second definition of mylab ** **************************************************************** .copy "a.inc" **************************************************************** ** Third definition of mylab, reset upon exit from .include ** **************************************************************** mylab? nop B mylab?, UNC **************************************************************** ** Fourth definition of mylab in macro, macros use different ** ** namespace to avoid conflicts ** **************************************************************** mymac .macro mylab? nop B mylab?, UNC .endm **************************************************************** ** Macro invocation ** **************************************************************** mymac **************************************************************** ** Reference to third definition of mylab. Definition is not ** ** reset by macro invocation. ** **************************************************************** B mylab?, UNC **************************************************************** ** Changing section, allowing fifth definition of mylab ** **************************************************************** .sect "Sect_One" nop mylab? .word 0 nop nop B mylab?, UNC **************************************************************** ** The .newblock directive allows sixth definition of mylab ** **************************************************************** .newblock mylab? .word 0 nop nop B mylab?, UNC

For more information about using labels in macros see Section 6.6.

4.7.4 Symbolic Constants

A symbolic constant is a symbol with a value that is an absolute constant expression (see Section 4.8). By using symbolic constants, you can assign meaningful names to constant expressions. The .set and .struct/.tag/.endstruct directives enable you to set symbolic constants (see Define Assembly-Time Constant). Once defined, symbolic constants cannot be redefined.

If you use the .set directive to assign a value to a symbol , the symbol becomes a symbolic constant and may be used where a constant expression is expected. For example:

shift3 .set 3 MOV AR1, #shift3

You can also use the .set directive to assign symbolic constants for other symbols, such as register names. In this case, the symbolic constant becomes a synonym for the register:

myReg .set AR1 MOV myReg, #3

The following example shows how the .set directive can be used with the .struct, .tag. and .endstruct directives. It creates the symbolic constants K, maxbuf, item, value, delta, and i_len.

K .set 1024 ; constant definitions maxbuf .set 2*K item .struct ; item structure definition value .int ; value offset = 0 delta .int ; delta offset = 4 i_len .endstruct ; item size = 8 array .tag item array .usect ".ebss", i_len*K ; declare an array of K "items" .text MOV array.delta, AR1 ; access array .delta

The assembler also has many predefined symbolic constants; these are discussed in Section 4.7.6.

4.7.5 Defining Symbolic Constants (--asm_define Option)

The --asm_define option equates a constant value or a string with a symbol. The symbol can then be used in place of a value in assembly source. The format of the --asm_define option is as follows:

cl2000 --asm_define=name[=value]

The name is the name of the symbol you want to define. The value is the constant or string value you want to assign to the symbol. If the value is omitted, the symbol is set to 1. If you want to define a quoted string and keep the quotation marks, do one of the following:

  • For Windows, use --asm_define=name="\"value\"". For example, --asm_define=car="\"sedan\""
  • For UNIX, use --asm_define=name='"value"'. For example, --asm_define=car='"sedan"'
  • For Code Composer, enter the definition in a file and include that file with the --cmd_file (or -@) option.

Once you have defined the name with the --asm_define option, the symbol can be used with assembly directives and instructions as if it had been defined with the .set directive. For example, on the command line you enter:

cl2000 --asm_define=SYM1=1 --asm_define=SYM2=2 --asm_define=SYM3=3 --asm_define=SYM4=4 value.asm

Since you have assigned values to SYM1, SYM2, SYM3, and SYM4, you can use them in source code. Example 4-3 shows how the value.asm file uses these symbols without defining them explicitly.

Within assembler source, you can test the symbol defined with the --asm_define option with these directives:

Type of Test Directive Usage
Existence .if $isdefed("name")
Nonexistence .if $isdefed("name") = 0
Equal to value .ifname=value
Not equal to value .if name!=value

The argument to the $isdefed built-in function must be enclosed in quotes. The quotes cause the argument to be interpreted literally rather than as a substitution symbol.

Example 4-3 Using Symbolic Constants Defined on Command Line

IF_4: .if SYM4 = SYM2 * SYM2 .byte SYM4 ; Equal values .else .byte SYM2 * SYM2 ; Unequal values .endif IF_5: .if SYM1 <= 10 .byte 10 ; Less than / equal .else .byte SYM1 ; Greater than .endif IF_6: .if SYM3 * SYM2 != SYM4 + SYM2 .byte SYM3 * SYM2 ; Unequal value .else .byte SYM4 + SYM4 ; Equal values .endif IF_7: .if SYM1 = SYM2 .byte SYM1 .elseif SYM2 + SYM3 = 5 .byte SYM2 + SYM3 .endif

4.7.6 Predefined Symbolic Constants

The assembler has several types of predefined symbols.

$, the dollar-sign character, represents the current value of the section program counter (SPC). $ is a relocatable symbol if you are using COFF.

In addition, the following predefined processor symbolic constants are available:

Table 4-2 C28x Processor Symbolic Constants

Symbol name Description
.TMS320C2000 Always set to 1
.TMS320C2800 Set to 1 for C28x
.TMS320C2800_FPU32 Set to 1 for C28x with 32-bit FPU support, otherwise 0

4.7.7 Registers

The names of C28x registers are predefined symbols.

In addition, control register names are predefined symbols.

Register symbols and aliases can be entered as all uppercase or all lowercase characters.

Control register symbols can be entered in all upper-case or all lower-case characters. For example, IER can also be entered as ier.

See the "Register Conventions" section of the TMS320C28x Optimizing C/C++ Compiler User's Guide for details about the registers and their uses.

Table 4-3 CPU Control Registers

Register Description
ACC/AH, AL Accumulator/accumulator high, accumulator low
DBGIER Debug interrupt enable register
DP Data page pointer
IER Interrupt enable register
IFR Interrupt flag pointer
P/PH, PL Product register/product high, product low
PC Program counter
RPC Return program counter
ST0 Status register 0
ST1 Status register 1
SP Stack pointer register
TH Multiplicant high register; an alias of T register
XAR0/AR0H, AR0 Auxiliary register 0/auxiliary 0 high, auxiliary 0 low
XAR1/AR1H, AR1 Auxiliary register 1/auxiliary 1 high, auxiliary 1 low
XAR2/AR2H, AR2 Auxiliary register 2/auxiliary 2 high, auxiliary 2 low
XAR3/AR3H, AR3 Auxiliary register 3/auxiliary 3 high, auxiliary 3 low
XAR4/AR4H, AR4 Auxiliary register 4/auxiliary 4 high, auxiliary 4 low
XAR5/AR5H, AR5 Auxiliary register 5/auxiliary 5 high, auxiliary 5 low
XAR6/AR6H, AR6 Auxiliary register 6/auxiliary 6 high, auxiliary 6 low
XAR7/AR7H, AR7 Auxiliary register 7/auxiliary 7 high, auxiliary 7 low
XT/T, TL Multiplicand register/Multiplicant high, multiplicant low

Table 4-4 FPU Control Registers

Register Description
R0H Floating point register 0
R1H Floating point register 1
R2H Floating point register 2
R3H Floating point register 3
R4H Floating point register 4
R5H Floating point register 5
R6H Floating point register 6
R7H Floating point register 7
STF Floating point status register

Table 4-5 VCU Registers

Register Description
VSTATUS VCU status and control register
VR0-VR8 VCU registers
VT0, VT1 VCU transition bit registers
VCRC VCU CRC result register

4.7.8 Substitution Symbols

Symbols can be assigned a string value. This enables you to create aliases for character strings by equating them to symbolic names. Symbols that represent character strings are called substitution symbols. When the assembler encounters a substitution symbol, its string value is substituted for the symbol name. Unlike symbolic constants, substitution symbols can be redefined.

A string can be assigned to a substitution symbol anywhere within a program; for example:

.asg "AR1", myReg ;register AR1 .asg "*+XAR2 [2]", ARG1 ;first arg .asg "*+XAR2 [1]", ARG2 ;second arg

When you are using macros, substitution symbols are important because macro parameters are actually substitution symbols that are assigned a macro argument. The following code shows how substitution symbols are used in macros:

add2 .macro A, B ; add2 macro definition MOV AL, A ADD AL, B .endm *add2 invocation add2 LOC1, LOC2 ;add "LOC1" argument to a ;second argument "LOC2". MOV AL,LOC1 ADD AL,LOC2

See Section 6 for more information about macros.

4.8 Expressions

Nearly all values and operands in assembly language are expressions, which may be any of the following:

  • a literal constant
  • a register
  • a register pair
  • a memory reference
  • a symbol
  • a built-in function invocation
  • a mathematical or logical operation on one or more expressions

This section defines several types of expressions that are referred to throughout this document. Some instruction operands accept limited types of expressions. For example, the .if directive requires its operand be an absolute constant expression with an integer value. Absolute in the context of assembly code means that the value of the expression must be known at assembly time.

A constant expression is any expression that does not in any way refer to a register or memory reference. An immediate operand will usually not accept a register or memory reference. It must be given a constant expression. Constant expressions may be any of the following:

  • a literal constant
  • an address constant expression
  • a symbol whose value is a constant expression
  • a built-in function invocation on a constant expression
  • a mathematical or logical operation on one or more constant expressions

An address constant expression is a special case of a constant expression. Some immediate operands that require an address value can accept a symbol plus an addend; for example, some branch instructions. The symbol must have a value that is an address, and it may be an external symbol. The addend must be an absolute constant expression with an integer value. For example, a valid address constant expression is "array+4".

A constant expression may be absolute or relocatable. Absolute means known at assembly time. Relocatable means constant, but not known until link time. External symbols are relocatable, even if they refer to a symbol defined in the same module.

An absolute constant expression may not refer to any external symbols anywhere in the expression. In other words, an absolute constant expression may be any of the following:

  • a literal constant
  • an absolute address constant expression
  • a symbol whose value is an absolute constant expression
  • a built-in function invocation whose arguments are all absolute constant expressions
  • a mathematical or logical operation on one or more absolute constant expressions

A relocatable constant expression refers to at least one external symbol. A relocatable constant expression may be any of the following:

  • an external symbol
  • a relocatable address constant expression
  • a symbol whose value is a relocatable constant expression
  • a built-in function invocation with any arguments that are relocatable constant expressions
  • a mathematical or logical operation on one or more expressions, at least one of which is a relocatable constant expression

In some cases, the value of a relocatable address expression may be known at assembly time. For example, a relative displacement branch may branch to a label defined in the same section.

4.8.1 Mathematical and Logical Operators

The operands of a mathematical or logical operator must be well-defined expressions. That is, you must use the correct number of operands and the operation must make sense. For example, you cannot take the XOR of a floating-point value. In addition, well-defined expressions contain only symbols or assembly-time constants that have been defined before they occur in the directive's expression.

Three main factors influence the order of expression evaluation:

Parentheses Expressions enclosed in parentheses are always evaluated first.

8 / (4 / 2) = 4, but 8 / 4 / 2 = 1

You cannot substitute braces ( { } ) or brackets ( [ ] ) for parentheses.

Precedence groups Operators, listed in Table 4-6, are divided into nine precedence groups. When parentheses do not determine the order of expression evaluation, the highest precedence operation is evaluated first.

8 + 4 / 2 = 10 (4 / 2 is evaluated first)

Left-to-right evaluation When parentheses and precedence groups do not determine the order of expression evaluation, the expressions are evaluated from left to right, except for Group 1, which is evaluated from right to left.

8 / 4*2 = 4, but 8 / (4*2) = 1

Table 4-6 lists the operators that can be used in expressions, according to precedence group.

NOTE

Difference in Precedence For C2xlp Source

When cl2000 is invoked with --c2xlp_src_compatible, the assembler accepts C2xlp source code. A programmer writing code for the C2xlp assembler would assume different precedence than that used by the C28x assembler. Therefore when invoked with the --c2xlp_src_compatible --asm_remarks options, the C28x assembler issues a warning when it encounters an expression such as a + b << c.

Table 4-6 Operators Used in Expressions (Precedence)

Group(1) Operator Description(2)
1 +
-
~
!
Unary plus
Unary minus
1s complement
Logical NOT
2 *
/
%
Multiplication
Division
Modulo
3 +
-
Addition
Subtraction
4 <<
>>
Shift left
Shift right
5 <
<=
>
>=
Less than
Less than or equal to
Greater than
Greater than or equal to
6 =[=]
!=
Equal to
Not equal to
7 & Bitwise AND
8 ^ Bitwise exclusive OR (XOR)
9 | Bitwise OR
(1) Group 1 operators are evaluated right to left. All other operators are evaluated left to right.
(2) Unary + and - have higher precedence than the binary forms.

The assembler checks for overflow and underflow conditions when arithmetic operations are performed during assembly. It issues a warning (the "value truncated" message) whenever an overflow or underflow occurs. The assembler does not check for overflow or underflow in multiplication.

4.8.2 Relational Operators and Conditional Expressions

The assembler supports relational operators that can be used in any expression; they are especially useful for conditional assembly. Relational operators include the following:

= Equal to

! =

Not equal to
< Less than <= Less than or equal to
> Greater than > = Greater than or equal to

Conditional expressions evaluate to 1 if true and 0 if false and can be used only on operands of equivalent types; for example, absolute value compared to absolute value, but not absolute value compared to relocatable value.

4.8.3 Well-Defined Expressions

Some assembler directives, such as .if, require well-defined absolute constant expressions as operands. Well-defined expressions contain only symbols or assembly-time constants that have been defined before they occur in the directive's expression. In addition, they must use the correct number of operands and the operation must make sense. The evaluation of a well-defined expression must be unambiguous.

This is an example of a well-defined expression:

1000h+X

where X was previously defined as an absolute symbol.

4.8.4 Legal Expressions

With the exception of the following expression contexts, there is no restriction on combinations of operations, constants, internally defined symbols, and externally defined symbols.

When an expression contains more than one relocatable symbol or cannot be evaluated during assembly, the assembler encodes a relocation expression in the object file that is later evaluated by the linker. If the final value of the expression is larger in bits than the space reserved for it, you receive an error message from the linker. See Section 2.6 for more information on relocation expressions.

When using the register relative addressing mode, the expression in brackets or parenthesis must be a well-defined expression, as described in Section 4.8.3. For example:

*+XA4[7]

4.9 Built-in Functions and Operators

The assembler supports built-in mathematical functions and built-in addressing operators.

The built-in substitution symbol functions are discussed in Section 6.3.2.

4.9.1 Built-In Math and Trigonometric Functions

The assembler supports many built-in mathematical functions. The built-in functions always return a value and they can be used in conditional assembly or any place where a constant can be used.

In Table 4-7 x, y and z are type float, n is an int. The functions $cvi, $int and $sgn return an integer and all other functions return a float. Angles for trigonometric functions are expressed in radians.

Table 4-7 Built-In Mathematical Functions

Function Description
$acos(x) Returns cos-1(x) in range [0, π], -1<=x<=1
$asin(x) Returns sin-1(x) in range [-π/2, π/2], -1<=x<=1
$atanx) Returns tan-1(x) in range [-π/2, π/2]
$atan2(x, y) Returns tan-1(y/x) in range [-π, π]
$ceil(x) Returns the smallest integer not less than x, as a float
$cos(x) Returns the cosine of x
$cosh(x) Returns the hyperbolic cosine of x
$cvf(n) Converts an integer to a float
$cvi(x) Converts a float to an integer. Returns an integer.
$exp(x) Returns the exponential function e x
$fabs(x) Returns the absolute value |x|
$floor(x) Returns the largest integer not greater than x, as a float
$fmod(x, y) Returns the floating-point remainder of x/y, with the same sign as x
$int(x) Returns 1 if x has an integer value; else returns 0. Returns an integer.
$ldexp(x, n) Multiplies x by an integer power of 2. That is, x × 2n
$log(x) Returns the natural logarithm ln(x), where x>0
$log10(x) Returns the base-10 logarithm log10(x), where x>0
$max(x, y, ...z) Returns the greatest value from the argument list
$min(x, y, ...z) Returns the smallest value from the argument list
$pow(x, y) Returns xy
$round(x) Returns x rounded to the nearest integer
$sgn(x) Returns the sign of x. Returns 1 if x is positive, 0 if x is zero, and -1 if x is negative. Returns an integer.
$sin(x) Returns the sine of x
$sinh(x) Returns the hyperbolic sine of x
$sqrt(x) Returns the square root of x, x≥0
$strtod(str) Converts a character string to a double precision floating-point value. The string contains a properly-formatted C99-style floating-point literal.
$tan(x) Returns the tangent of x
$tanh(x) Returns the hyperbolic tangent of x
$trunc(x) Returns x truncated toward 0

4.10 Specifying Assembler Fill Values (--asm_code_fill and --asm_data_fill)

The C28x assembler allows you to specify fill values to fill the holes created by the assembler.

The .align directive aligns the section program counter (SPC) on the next boundary, depending on the size in words parameter. The assembler might create holes to align the SPC. For example consider the following assembly code:

.sect "MyData" .align 1 .field 0x01,16 .align 2 .field 0x00010002,32 .sect "MyProg" .align 1 MOV ah, #0 .align 2 MOV acc,#1234 << 5

The assembler supports the --asm_code_fill and --asm_data_fill options to enable you to specify the fill values for the code sections and data sections, respectively. You can specify a 16-bit value with these options in decimal (1024), octal (02000) or hexadecimal (0x400) format.

The assembler uses the default values of zero for data sections and NOP instructions for code sections.

A code section is defined as either a .text section or any section that has an instruction to encode. The following are considered to be code sections:

Example 1

.text .field 0x100, 16

Example 2

.data .field 0x100, 16 MOV al, #1

Example 3

.sect "MyProg" MOV al, #0

Any section other than a .text section is considered a data section if it does not have any instruction to encode. For example:

.sect "MyData" .field 0x100, 16

4.11 TMS320C28x Assembler Modes

The C28x assembler operates in different modes. These modes are controlled by options as follows:

-v28: The -v28 is the default, and no other silicon version is supported for the -v option. Therefore you do not need to specify -v28 explicitly.

--c2xlp_src_compatible: C28x object mode--Accept C2xlp Syntax Mode

--float_support: Accept FPU32 instructions. To support some special floating point instructions when a 32-bit floating point unit (FPU) is available, the assembler operates in FPU32 mode. Section 4.11.3 describes the FPU32 mode. The syntax is: --float_support=fpu32

--cla_support: Accept CLA instructions. To support special floating point instructions that run on the Control Law Accelerator (CLA), the assembler operates in CLA mode. Section 4.11.4 describes the CLA mode. Support for the CLA Type 0 or Type 1 can be specified. This mode is controlled by options as follows: --cla_support=[cla0|cla1]

--vcu_support: Accept VCU instructions. To support the Viterbi, Complex Math and CRC Unit (VCU) instructions, the assembler operates in VCU mode. Support for the VCU Type 0 or Type 2 can be specified. This mode is controlled by options as follows: --vcu_support=[vcu0|vcu2]

--tmu_support: Substitute TMU instructions. To support the Trigonometric Math Unit (TMU), TMU instructions are used for floating point division and trigonometric functions. Support for the TMU Type 0 can be specified using the following compiler option: --tmu_support=[tmu0]

Refer to the TMS320C28x DSP CPU and Instruction Set Reference Guide for more details on different object modes and addressing modes supported by the C28x processor.

4.11.1 C28x Object Mode

This mode supports all the C28x instructions and generates C28x object code. New users of the C28x processor should use the assembler in this mode. This mode is the default.

This mode generates an error if old C27x syntax is used. For example, the following instructions are illegal in this mode:

MOV AL, *AR0++ ; *AR0++ is illegal addressing for C28x.

4.11.2 C28x Object - Accept C2xlp Syntax Mode

This mode supports all the C28x instructions and generates C28x object code but also supports C2xlp instruction syntax.

The C28x processor includes features and instructions that make the processor as backward compatible to the C2xlp processor as possible. In order to make the C28x processor source code compatible with C2xlp, the assembler accepts C2xlp instructions and encodes them as equivalent C28x instructions.

This mode assumes LP addressing mode compatibility (AMODE = 1) and a data page of 128-words. Refer to the TMS320C28x DSP CPU And Instruction Set Reference Guide for information on C2xlp instructions and additional details.

The C27x syntax is not supported in this mode and generates an error. Also any incompatible C2xlp instructions cause the assembler to generate an error. For example, the following instructions are illegal in this mode:

MOV AL, *AR0++ ; *AR0++ is illegal addressing for C28x. TRAP ; Incompatible C2XLP instruction.

In this mode, C28x and C2xlp source code can be freely intermixed within a file as shown below.

; C2xlp Source Code LDP #VarA LACL VarA LAR AR0, *+, AR2 SACL *+ . . . LC FuncA . . . ; C28x Source Code using LP Addressing (AMODE = 1) FuncA: MOV DP, #VarB MOV AL, @@VarB MOVL XAR0, *XAR0++ MOV *XAR2++, AL LRET

When the C28x assembler is invoked with --asm_remarks switch, it performs additional checking for the following cases:

  • The C1x/C2x/C2xx/C5x assembler accepts numbers with leading zero as decimal integers, that is 010 is treated as 10 and not as 8. The C28x assembler treats constants with leading zeros as octal numbers. There may be C2xlp assembly code that contains decimal numbers with leading zeros. When these files are assembled with the C28x assembler the results will not be what you expect as the C28x assembler treats such constants as octal numbers. So the assembler when invoked with --c2xlp_src_compatible --asm_remarks, checks for such numbers and issues a warning that the constant is parsed as an octal number.
  • For example, consider the following listing produced using the --c2xlp_src_compatible --asm_remarks options:

    1 00000000 FF20 lacc #023 "octal.asm", WARNING! at line 1: [W0000] Constant parsed as an octal number 00000001 0013
  • The C1x/C2x/C2xx/C5 assembler uses a different order of operator precedence expression. In the C1x/C2x/C2xx/C5 assembler, the shift operators (<< and >>) have higher precedence than the binary + and - operators. The C28x assembler follows the order of precedence of C language where the above mentioned sequence is reversed. The C28x assembler issues a warning about the precedence used if the following are true:
    • The --c2xlp_src_compatible --asm_remarks options are specified.
    • The source code contains any expression involving binary additive operators (+ and -) and the shift operators (<< and >>).
    • The precedence is not forced by parentheses. For example, consider the following listing produced using the --c2xlp_src_compatible --asm_remarks options:
    • 1 00000000 FF20 lacc #(3 + 4 << 2) ; Warning generated "pre.asm", WARNING! at line 1: [W9999] The binary + and - operators have higher precedence than the shift operators 00000001 001C 2 00000002 FF20 lacc #((3 + 4) << 2) ; NO warning 00000003 001C

4.11.3 C28x FPU32 and FPU64 Object Modes

The FPU32 mode is used when the hardware 32-bit floating-point co-processor support is available on the C28x. The FPU32 mode is invoked by specifying the--float_support=fpu32 option. This mode supports all C28x instructions. The differences are as follows:

  • Some special floating point instructions are supported. These are documented in the TMS320C28x Floating Point Unit and Instruction Set Reference Guide.
  • The assembler in this mode checks for pipeline conflicts. This is because the FPU32 instructions are not pipeline protected. The C28x instructions are pipeline protected, which means that a new instruction cannot read/write its operands until all preceding C28x instructions have finished writing those operands. This is not the case with the FPU32 instructions: an FPU instruction can access its operands while another instruction is writing them, causing race conditions. Thus the assembler has to check for pipeline conflicts and issue warnings/errors as appropriate. The pipeline conflict detection feature is described in Section 4.17.

The FPU64 mode supports a 64-bit version of the floating point co-processor. It is invoked by specifying the --float_support=fpu64 option. This mode is similar to the FPU32 mode, but enables additional instructions.

4.11.4 C28x CLA Object Mode

The CLA mode is used when the hardware Control Law Accelerator support is available on the C28x. This mode is available by invoking the compiler with the –v28 and --cla_support=[cla0|cla1] options, where cla0 indicates a CLA Type 0 device and cla1 indicates a Type 1 device. The --cla_support option can be specified along with other C28x options, such as those for specifying FPU support. Specifying both FPU and CLA options means that support is available for both types of accelerators. The CLA mode is very similar to the C28x mode (with/without FPU support). The differences are:

  • The CLA is similar to a cut-down version of the FPU32 that is optimized to perform math tasks only. Some special floating point instructions are supported. These are documented in TMS320x28xx, 28xxx DSP Peripherals Reference Guide.
  • The CLA pipeline is unprotected, but at this time, the tools do not detect pipeline conflicts for the CLA. You need to write CLA instructions in such a way that there are no pipeline conflicts.
  • Assembly files containing CLA instructions can also contain C28x and FPU instructions. However, the CLA instructions should always be in a separate, named section. This section cannot contain any non-CLA instructions. Mixing CLA and non-CLA instructions in the same section is illegal and results in an assembler/linker error.
  • When a linker command file is written, care must be taken to put all data referenced by CLA instructions within addresses 0-64K. This is because the CLA data read bus only has a 64K address range.
  • A linker output section containing a CLA input section cannot contain any non-CLA input sections.
  • The CLA mode does not need any special library support. Any of the C28x libraries suffices.
  • The name of the section containing CLA instructions should be unique both within the file and across all files that are compiled and linked into the same output file.

The CLA compiler places all CLA function data, arguments, and temporary storage in function frames in the .scratchpad section. Function frame scratchpad sections are named in the form ".scratchpad:functionSectionName". (Each function has its own subsection and therefore a unique section name.) For example: .scratchpad:Cla1Prog:_Cla1Task2 would be the compiler-generated scratchpad section name for a function called Cla1Task2().

The CLA compiler's naming convention for the function scratchpad symbol is of the form __cla_functionSymbol_sp, but this is not required in assembly code.

The following example shows compiled code with a .sect directive for a CLA function and a .usect directive to identify the function scratchpad frame. This .usect directive identifies the function frame as part of the .scratchpad section and allows the compiler to use overlays when possible. Overlaid function frames use the same physical memory, thereby reducing memory utilization. It is recommended that assembly code follow the ".scratchpad:" naming convention to reduce memory requirements.

.sect "Cla1Prog:_Cla1Task2" .align 2 __cla_Cla1Task2_sp .usect ".scratchpad:Cla1Prog:_Cla1Task2",14,0,1 .global _Cla1Task2 ;*************************************************************** ;* FNAME: _Cla1Task2 FR SIZE: 14 * ;* * ;* FUNCTION ENVIRONMENT * ;* * ;* FUNCTION PROPERTIES * ;* 14 Auto, 12 SOE * ;*************************************************************** _Cla1Task2: [ ... ]

See the "CLA Compiler" chapter in the TMS320C28x Optimizing C/C++ Compiler User's Guide for more details.

4.12 Source Listings

A source listing shows source statements and the object code they produce. To obtain a listing file, invoke the assembler with the --asm_listing option (see Section 4.3).

Two banner lines, a blank line, and a title line are at the top of each source listing page. Any title supplied by the .title directive is printed on the title line. A page number is printed to the right of the title. If you do not use the .title directive, the name of the source file is printed. The assembler inserts a blank line below the title line.

Each line in the source file produces at least one line in the listing file. This line shows a source statement number, an SPC value, the object code assembled, and the source statement. Figure 4-2 shows these in an actual listing file.

Field 1: Source Statement Number

Line number

The source statement number is a decimal number. The assembler numbers source lines as it encounters them in the source file; some statements increment the line counter but are not listed. (For example, .title statements and statements following a .nolist are not listed.) The difference between two consecutive source line numbers indicates the number of intervening statements in the source file that are not listed.

Include file letter

A letter preceding the line number indicates the line is assembled from the include file designated by the letter.

Nesting level number

A number preceding the line number indicates the nesting level of macro expansions or loop blocks.

Field 2: Section Program Counter

This field contains the SPC value, which is hexadecimal. All sections (.text, .data, .ebss, and named sections) maintain separate SPCs. Some directives do not affect the SPC and leave this field blank.

Field 3: Object Code

This field contains the hexadecimal representation of the object code. All machine instructions and directives use this field to list object code. This field also indicates the relocation type associated with an operand for this line of source code. If more than one operand is relocatable, this column indicates the relocation type for the first operand. The characters that can appear in this column and their associated relocation types are listed below:

! undefined external reference
' .text relocatable
+ .sect relocatable
" .data relocatable
- .usect relocatable
% relocation expression

Field 4: Source Statement Field

This field contains the characters of the source statement as they were scanned by the assembler. The assembler accepts a maximum line length of 200 characters. Spacing in this field is determined by the spacing in the source statement.

Figure 4-2 shows an assembler listing with each of the four fields identified.

Figure 4-2 Example Assembler Listing assylist_pru513.gif

4.13 Debugging Assembly Source

By default, when you compile an assembly file, the assembler provides symbolic debugging information that allows you to step through your assembly code in a debugger rather than using the Disassembly window in Code Composer Studio. This enables you to view source comments and other source-code annotations while debugging. The default has the same behavior as using the --symdebug:dwarf option. You can disable the generation of debugging information by using the --symdebug:none option.

The .asmfunc and .endasmfunc (see .asmfunc directive) directives enable you to use C characteristics in assembly code that makes the process of debugging an assembly file more closely resemble debugging a C/C++ source file.

The .asmfunc and .endasmfunc directives allow you to name certain areas of your code, and make these areas appear in the debugger as C functions. Contiguous sections of assembly code that are not enclosed by the .asmfunc and .endasmfunc directives are automatically placed in assembler-defined functions named with this syntax:

$filename:starting source line:ending source line$

If you want to view your variables as a user-defined type in C code, the types must be declared and the variables must be defined in a C file. This C file can then be referenced in assembly code using the .ref directive (see .ref directive). Example 4-4 shows the cvar.c C program that defines a variable, svar, as the structure type X. The svar variable is then referenced in the addfive.asm assembly program in Example 4-5 and 5 is added to svar's second data member.

Compile both source files with the --symdebug:dwarf option (-g) and link them as follows:

cl2000 -symdebug:dwarf cvars.c addfive.asm --run_linker --library=lnk.cmd --library=rts2800_ml.lib --output_file=addfive.out

When you load this program into a symbolic debugger, addfive appears as a C function. You can monitor the values in svar while stepping through main just as you would any regular C variable.

Example 4-4 Viewing Assembly Variables as C Types C Program

typedef struct { int m1; int m2; } X; X svar = { 1, 2 };

Example 4-5 Assembly Program for Example 4-4

;------------------------------------------------------------------------------ ; Tell the assembler we're referencing variable "_svar", which is defined in ; another file (cvars.c). ;------------------------------------------------------------------------------ .ref _svar ;------------------------------------------------------------------------------ ; addfive() - Add five to the second data member of _svar ;------------------------------------------------------------------------------ .text .global addfive addfive: .asmfunc MOVZ DP,#_svar+1 ; load the DP with svar's memory page ADD @_svar+1,#5 ; add 5 to svar.m2 LRETR ; return from function .endasmfunc

4.14 C-Type Symbolic Debugging for Assembly Variables (--cdebug_asm_data Option)

When you assemble with the --cdebug_asm_data option, the assembler produces the debug information for assembly source debug. The assembler outputs C-type symbolic debugging information for symbols defined in assembly source code using the data directives. This support is for basic C types, structures and arrays. You have the ability to inform the assembler how to interpret an assembly label as a C variable with basic type information.

The assembly data directives have been modified to produce debug information when using --cdebug_asm_data in these ways:

  • Data directives for initialized data. The assembler outputs debugging information for data initialized with the .byte, .field, .float, .int, or .long directive. For the following, the assembler emits debug information to interpret int_sym as a C integer:
  • int_sym .int 10h

    More than one initial value is interpreted as an array of the type designated by the directive. This example is interpreted as an integer array of four and the appropriate debug information is produced:

    int_sym .int 10h, 11h, 12h, 13h

    For symbolic information to be produced, you must have a label designated with the data directive. Compare the first and second lines of code shown below:

    int_sym .int 10h .int 11h --> Will not have debug info.
  • Data directives for uninitialized data. The .usect directive accepts a type designation as an optional operand. This type operand is used to produce the appropriate debug information for the symbol defined using the .usect directive. For example, the following generates similar debug information as the initialized data directive shown above:
  • int_sym .usect ".ebss", 1,1,0,int

    The type operand can be one of the following. If a type is not specified no debug information is produced.

    CHAR FLOAT LDOUBLE SCHAR UCHAR ULONG
    DOUBLE INT LONG SHORT UINT USHORT

    In the following example, the parameter int_sym is treated as an array of four integers:

    int_sym .usect ".ebss",4,1,0,int

    The size specified must be a multiple of the type specified. If no type operand is specified no warning is issued. The following code will generate a warning since 3 is not a multiple of the size of a long.

    double_sym .usect ".ebss", 3,1,0,long
  • Debug information for assembly structures. The assembler also outputs symbolic information on structures defined in assembly. Here is an example of a structure:
  • structlab .struct mem1 .int mem2 .int struct_len .endstruct struct1 .tag structlab struct1 .usect ".ebss", 2, 1, 0, structlab

    For the structure example, debug information is produced to treat struct1 as the C structure:

    struct struct1{ int mem1; int mem2; };

    The assembler outputs arrays of structures if the size specified by the .usect directive is a multiple of the size of struct type. As with uninitialized data directives, if the size specified is not a multiple of the structure size, a warning is generated. This example properly accounts for alignment constraints imposed by the member types:

    struct1 .usect ".ebss",struct_len * 3, 1, 0, structlab

4.15 Cross-Reference Listings

A cross-reference listing shows symbols and their definitions. To obtain a cross-reference listing, invoke the assembler with the --cross_reference option (see Section 4.3) or use the .option directive with the X operand (see Select Listing Options). The assembler appends the cross-reference to the end of the source listing. Example 4-6 shows the four fields contained in the cross-reference listing.

Example 4-6 An Assembler Cross-Reference Listing

LABEL VALUE DEFN REF .TMS320C2800 00000001 0 _func 00000000' 18 var1 00000000- 4 17 var2 00000004- 5 18
Label column contains each symbol that was defined or referenced during the assembly.
Value column contains an 8-digit hexadecimal number (which is the value assigned to the symbol) or a name that describes the symbol's attributes. A value may also be preceded by a character that describes the symbol's attributes. Table 4-8 lists these characters and names.
Definition (DEFN) column contains the statement number that defines the symbol. This column is blank for undefined symbols.
Reference (REF) column lists the line numbers of statements that reference the symbol. A blank in this column indicates that the symbol was never used.

Table 4-8 Symbol Attributes

Character or Name Meaning
REF External reference (global symbol)
UNDF Undefined
' Symbol defined in a .text section
" Symbol defined in a .data section
+ Symbol defined in a .sect section
- Symbol defined in a .usect section

4.16 Smart Encoding

To improve efficiency, the assembler reduces instruction size whenever possible. For example, a branch instruction of two words can be changed to a short branch one-word instruction if the offset is 8 bits. Table 4-9 lists the instruction to be changed and the change that occurs.

Table 4-9 Smart Encoding for Efficiency

This instruction... Is encoded as...
MOV AX, #8Bit MOVB AX, #8Bit
ADD AX, #8BitSigned ADDB AX, #8BitSigned
CMP AX, #8Bit CMPB AX, #8Bit
ADD ACC, #8Bit ADDB ACC, #8Bit
SUB ACC, #8Bit SUBB ACC, #8Bit
AND AX, #8BitMask ANDB AX, #8BitMask
OR AX, #8BitMask ORB AX, #8BitMask
XOR AX, #8BitMask XORB AX, #8BitMask
B 8BitOffset, cond SB 8BitOffset, cond
LB 8BitOffset, cond SB 8BitOffset, cond
MOVH loc, ACC << 0 MOV loc, AH
MOV loc, ACC << 0 MOV loc, AL
MOVL XARn, #8Bit MOVB XARn, #8Bit

The assembler also intuitively changes instruction formats during smart encoding. For example, to push the accumulator value to the stack, you use MOV *SP++, ACC. Since it would be intuitive to use PUSH ACC for this operation, the assembler accepts PUSH ACC and through smart encoding, changes it to MOV *SP++, ACC. Table 4-10 shows a list of instructions recognized during intuitive smart encoding and what the instruction is changed to.

Table 4-10 Smart Encoding Intuitively

This instruction... Is encoded as...
MOV P, #0 MPY P, T, #0
SUB loc, #16BitSigned ADD loc, #-16BitSigned
ADDB SP, #-7Bit SUBB SP, #7Bit
ADDB aux, #-7Bit SUBB aux, #7Bit
SUBB AX, #8BitSigned ADDB AX, #-8BitSigned
PUSH IER MOV *SP++, IER
POP IER MOV IER, *--SP
PUSH ACC MOV *SP++, ACC
POP ACC MOV ACC, *--SP
PUSH XARn MOV *SP++, XARn
POP XARn MOV XARn, *--SP
PUSH #16Bit MOV *SP++, #16Bit
MPY ACC, T, #8Bit MPYB ACC, T, #8Bit

In some cases, you might want a 2-word instruction even when there is an equivalent 1-word instruction available. In such cases, smart encoding for efficiency could be a problem. Therefore, the equivalent instructions in Table 4-11 are provided; these instructions will not be optimized.

Table 4-11 Instructions That Avoid Smart Encoding

This instruction... Is encoded as...
MOVW AX, #8Bit MOV AX, #8Bit
ADDW AX, #8Bit ADD AX, #8Bit
CMPW AX, #8Bit CMP AX, #8Bit
ADDW ACC, #8Bit ADD ACC, #8Bit
SUBW ACC, #8Bit SUB ACC, #8Bit
JMP 8BitOffset, cond B 8BitOffset, cond

4.17 Pipeline Conflict Detection

Pipeline Conflict Detection (PCD) is a feature implemented on the TMS320C28x 5.0 Compiler, for targets with hardware floating point unit (FPU) support only. This is because the FPU instructions are not pipeline protected whereas the C28x instructions are. Beginning with version 6.0, similar protections are provided for targets with support for the Viterbi, Complex Math and CRC Unit (VCU).

4.17.1 Protected and Unprotected Pipeline Instructions

The C28x target with FPU/VCU support has a mix of protected and unprotected pipeline instructions. This necessitates some checks in the compiler and assembler that are not necessary for a C28x target without such support.

By design, a (non-FPU) C28x instruction does not read/write an operand until all previous instructions have finished writing that operand. The hardware stalls until this condition is true. As hardware stalls are employed to preserve operand integrity, the compiler and assembler need not keep track of register reads and writes by instructions in the pipeline. Thus, the C28x instructions are pipeline protected, meaning that an instruction will not attempt to read/write a register while that register is still being written by another instruction.

The situation is different when FPU support is enabled. While the non-FPU instructions are pipeline protected, the FPU instructions aren't. This implies that an FPU instruction could attempt to read/write a register while it is still being written by a previous instruction. This can cause undefined behavior, and the compiler and assembler need to protect against such conflicting register accesses. The same is true for VCU instructions.

4.17.2 Pipeline Conflict Prevention and Detection

The compiler, when generating assembly code from C/C++ programs, ensures that the generated code does not have any pipeline conflicts. It does this by either scheduling non-conflicting instructions between two potentially conflicting instructions, or inserting NOP instructions wherever necessary. For details on the compiler, please see the .

While conflict prevention by the compiler is sufficient for C/C++ test cases, this does not cover manually-written assembly language code. Assembly code can contain instructions that have pipeline conflicts. The assembler needs to detect such conflicts and issue warnings or errors, depending on the severity of the situation. This is what the Pipeline Conflict Detection (PCD) feature in the assembler, is designed to do.

4.17.3 Pipeline Conflicts Detected

The assembler detects certain pipeline conflicts, and based on their severity, issues either an error message or a warning. The types of pipeline conflicts detected are listed below, along with the assembler actions in the event of each conflict.

  • Pipeline Conflict:
  • An instruction reads a register when it is being written by another instruction.

    Assembler Response:

    The assembler generates an error message and aborts.

  • Pipeline Conflict:
  • Two instructions write the same register in the same cycle.

    Assembler Response:

    The assembler generates an error message and aborts.

  • Pipeline Conflict:
  • Instructions FRACF32, I16TOF32, UI16TOF32, F32TOI32, and/or F32TOUI32 are present in the delay slot of a specific type of MOV32 instruction that moves a value from a CPU register or memory location to an FPU register.

    Assembler Response:

    The assembler gives an error message and aborts, as the hardware is not able to correctly execute this sequence.

  • Pipeline Conflict:
  • Parallel operations have the same destination register.

    Assembler Response:

    The assembler gives a warning.

  • Pipeline Conflict:
  • A read/write happens in the delay slot of a write of the same register.

    Assembler Response:

    The assembler gives a warning.

  • Pipeline Conflict:
  • A SAVE operation happens in the delay slot of a pipeline operation.

    Assembler Response:

    The assembler gives a warning.

  • Pipeline Conflict:
  • A RESTORE operation happens in the delay slot of a pipeline operation.

    Assembler Response:

    The assembler gives a warning.

  • Pipeline Conflict:
  • A SETFLG instruction tries to modify the LUF or LVF flag while certain instructions that modify LUF/LVF (such as ADDF32, SUBF32, EINVF32, EISQRTF32 etc) have pending writes.

    Assembler Response:

    The assembler does not check for which instructions have pending writes; on encountering a SETFLG when any write is pending, the assembler issues a detailed warning, asking you to ensure that the SETFLG is not in the delay slot of the specified instructions.

For the actual timing of each FPU instruction, and pipeline modeling, please refer to the TMS320C28x Floating Point Unit and Instruction Set Reference Guide. Timing information for VCU instructions can be found in the TMS320x28xx, 28xxx DSP Peripherals Reference Guide.

Submit Documentation Feedback

Copyright© 2016, Texas Instruments Incorporated. An IMPORTANT NOTICE for this document addresses availability, warranty, changes, use in safety-critical applications, intellectual property matters and other important disclaimers.