TMS320C28x Assembly Language
Tools
v17.3.0.STS User's Guide
SPRU513M - REVISED MARCH 2017
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:
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.
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_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_listing_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 --asm_listing_cross_reference option, the assembler creates a listing file automatically, naming it with the same name as the input file with a .lst extension. |
--asm_undefine=name | -au | Undefines the predefined constant name, which overrides any --asm_define options for the specified constant. |
--cla_support[=cla0|cla1|cla2] | Specifies TMS320C28x Control Law Accelerator (CLA) Type 0, Type 1, or Type 2 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" |
--float_support={ fpu32} | Assembles code for C28x with 32-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. |
--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.12. |
--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:
- 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.
- Any directories named with the --include_path option
- Any directories named with the C2000_A_DIR environment variable
- 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:
- 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:\path\one\to\tools ; c:\path\two\to\tools
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 |
Windows | C2000_A_DIR=c:\dsys |
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:
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:
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 |
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.
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.
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 |
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 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.
--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.10.2 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.10.3 describes the CLA mode. Support for the CLA Type 0, Type 1, or Type 2 can be specified. This mode is controlled by options as follows: --cla_support=[cla0|cla1|cla2]
--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.10.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.10.2 C28x FPU32 Object Mode
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.15.
4.10.3 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|cla2] options, where cla0 indicates a CLA Type 0 device, cla1 indicates a Type 1 device, and so on. 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.
CLA2 background tasks are placed in the scratchpad with function frame sections of the form ".scratchpad:background:functionSectionName". The background task frame cannot be overlaid with any other function frames, since the background task is likely to be returned to after yielding to interrupts.
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:
[ ... ]
If the CLA function in the example above were a CLA2 background task, the .usect directive would instead identify the scratchpad frame as ".scratchpad:background:Cla1Prog:_Cla1Task2".
See the "CLA Compiler" chapter in the TMS320C28x Optimizing C/C++ Compiler User's Guide for more details.
4.11 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.
4.12 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.13 Cross-Reference Listings
A cross-reference listing shows symbols and their definitions. To obtain a cross-reference listing, invoke the assembler with the --asm_listing_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.14 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.15 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.15.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.15.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.15.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:
- Pipeline Conflict:
- Pipeline Conflict:
- Pipeline Conflict:
- Pipeline Conflict:
- Pipeline Conflict:
- Pipeline 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.
Two instructions write the same register in the same cycle.
Assembler Response:
The assembler generates an error message and aborts.
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.
Parallel operations have the same destination register.
Assembler Response:
The assembler gives a warning.
A read/write happens in the delay slot of a write of the same register.
Assembler Response:
The assembler gives a warning.
A SAVE operation happens in the delay slot of a pipeline operation.
Assembler Response:
The assembler gives a warning.
A RESTORE operation happens in the delay slot of a pipeline operation.
Assembler Response:
The assembler gives a warning.
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.
Copyright© 2017, 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.