TMS320C6000 Assembly Language
Tools
v8.1.x User's Guide
SPRUI03A - REVISED JANUARY 2016
4 Assembler Description
The TMS320C6000 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 TMS320C64x/C64x+ DSP CPU and Instruction Set Reference Guide, TMS320C6740 DSP CPU and Instruction Set Reference Guide, and TMS320C66x CPU and Instruction Set Reference Guide. |
4.1 Assembler Overview
The 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 TMS320C6000 C/C++ compiler.
4.3 Invoking the Assembler
To invoke the assembler, enter the following:
cl6xinput file [options] |
cl6x | 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.
Some runtime model options, such as --big_endian and --silicon version, influence the behavior of the assembler. These options are passed to the compiler, assembler, and linker from the shell utility, which is detailed in the TMS320C6000 Optimizing Compiler User's Guide.
Table 4-1 TMS320C6000 Assembler Options
Option | Alias | Description |
---|---|---|
-ar=num | Suppresses the assembler remark identified by num. A remark is an informational assembler message that is less severe than a warning. If you do not specify a value for #, all remarks are suppressed. | |
--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.8.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_undefine=name | -au | Undefines the predefined constant name, which overrides any --asm_define options for the specified constant. |
--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. 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. |
--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.5.1. |
--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.12. |
--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. |
4.4 The Application Binary Interface
An Application Binary Interface (ABI) defines the low level interface between object files, and between an executable and its execution environment. The ABI exists to allow ABI-compliant object code to link together, regardless of its source, and allows the resulting executable to run on any system that supports that ABI.
The C6000 compiler supports only the C6000 EABI ABI. For details, see The C6000 Embedded Application Binary Interface Application Report (SPRAB89).
COFF object files are no longer supported in v8.0 and later versions of the TI Code Generation Tools. If you would like to produce COFF output files, please use v7.4 of the Code Generation Tools and refer to SPRU186 for documentation.
Object modules conforming to different ABIs cannot be linked together. The linker detects this situation and generates an error; you will need to recompile C code or reassemble assembly code in order to move from COFF to ELF. Note that converting an assembly file from the COFF API to EABI requires some changes to the assembly code. See Chapter 14 of The C6000 Embedded Application Binary Interface Application Report (SPRAB89 for details.
4.5 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 C6X_A_DIR environment variable
- Any directories named with the C6X_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.5.1) or the C6X_A_DIR environment variable (described in Section 4.5.2). The C6X_C_DIR environment variable is discussed in the TMS320C6000 Optimizing Compiler User's Guide.
4.5.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:
cl6x --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) | cl6x --include_path=/tools/files source.asm |
Windows | cl6x --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.5.2 Using the C6X_A_DIR Environment Variable
An environment variable is a system symbol that you define and assign a string to. The assembler uses the C6X_A_DIR environment variable to name alternate directories that contain copy/include files or macro libraries.
The assembler looks for the C6X_A_DIR environment variable and then reads and processes it. If the assembler does not find the C6X_A_DIR variable, it then searches for C6X_C_DIR. The processor-specific variables are useful when you are using Texas Instruments tools for different processors at the same time.
See the TMS320C6000 Optimizing Compiler User's Guide for details on C6X_C_DIR.
The command syntax for assigning the environment variable is as follows:
Operating System | Enter |
---|---|
UNIX (Bourne Shell) | C6X_A_DIR="pathname1 ;pathname2 ; . . . "; export C6X_A_DIR |
Windows | set C6X_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 C6X_A_DIR= c:\path\one\to\tools ; c:\path\two\to\tools
set C6X_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) | C6X_A_DIR="/dsys"; export C6X_A_DIR |
Windows | set C6X_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 C6X_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 C6X_A_DIR |
Windows | set C6X_A_DIR= |
4.6 Source Statement Format
Each line in a TMS320C6000 assembly input file can be empty, a comment, an assembler directive, a macro invocation, or an assembly instruction.
Assembly language source statements can contain five ordered fields (label, mnemonic, unit specifier, operand list, and comment). The general syntax for source statements is as follows:
[label[:]] [||] [[register]] mnemonic [unit specifier] [operand list][;comment] |
A label can only be associated with the first instruction in an execute packet (a group of instructions that is to be executed in parallel).
Following are examples of source statements:
two .set 2 ; Symbol Two = 2
Label: MVK two,A2 ; Move 2 into register A2
.word 016h ; Initialize a word with 016h
There is no limit on characters per source statement. Each statement is one logical line of the input file. Use a backslash (\) to indicate continuation of the same instruction/directive across multiple lines.
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.
- In a conditional instruction, the condition register must be surrounded by square brackets.
- The functional unit specifier is optional. If you do not specify the functional unit, the assembler assigns a legal functional unit based on the mnemonic field and the other instructions in the execute packet.
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.6.1 Label Field
A label must be a legal identifier (see Section 4.8.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. You cannot use a label on an instruction that is in parallel with a previous instruction.
When you use a label on an assembly instruction or data directive, an assembler symbol (Section 4.8) with the same name is created. Its value is the current value of the section program counter (SPC, see Section 2.4.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 00000040 0000000A Start: .word 0Ah,3,7
00000044 00000003
00000048 00000007
When a label appears on a line by itself, it points to the instruction on the next line (the SPC is not incremented):
1 00000000 Here:
2 00000000 00000003 .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.6.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. There is one exception: the parallel bars (||) of the mnemonic field can start in column 1. The mnemonic field contains one of the following items:
- Parallel bars (||) indicate instructions that are in parallel with a previous instruction. You can have up to eight instructions that will be executed in parallel. The following example demonstrates six instructions to be executed in parallel:
- Square brackets ([ ]) indicate conditional instructions. The machine-instruction mnemonic is executed based on the value of the register within the brackets; valid register names are A0, A1, A2, B0, B1, and B2. These registers are often called predicate registers.
The instruction is executed if the value of the register is nonzero. If the register name is preceded by an exclamation point (!), then the instruction is executed if the value of the register is 0. For example:
[A1] ZERO A2 ; If A1 is not equal to zero, A2 = 0
The preceding exclamation point, if specified, is called a "logical NOT operator" or a "unary NOT operator".
Next, the mnemonic field contains one of the following items:
- Machine-instruction mnemonic (such as ADDK, MVKH, B)
- Assembler directive (such as .data, .list, .equ, .macro, .var, .mexit)
- Macro invocation
The || and "[predicate register]" constructs are not legal in combination with an assembler directive.
4.6.3 Unit Specifier Field
The unit specifier field is an optional field that follows the mnemonic field for machine-instruction mnemonics. The unit specifier field begins with a period (.) followed by a functional unit specifier. In general, one instruction can be assigned to each functional unit in a single instruction cycle. There are eight functional units, two of each functional type:
.D1 and .D2 | Data/addition/subtraction | |
.L1 and .L2 | ALU/compares/long data arithmetic | |
.M1 and .M2 | Multiply | |
.S1 and .S2 | Shift/ALU/branch/bit field | |
ALU refers to an arithmetic logic unit. |
There are several ways to use the unit specifier field:
- You can specify the particular functional unit (for example, .D1).
- You can specify only the functional type (for example, .M), and the assembler assigns the specific unit (for example, .M2).
- If you do not specify the functional unit, the assembler assigns the functional unit based on the mnemonic field, operand fields, and other instructions in the same execute packet.
For more information on functional units, including which assembly instructions require which functional type, see the TMS320C64x/C64x+ DSP CPU and Instruction Set Reference Guide, or TMS320C66x DSP CPU and Instruction Set Reference Guide, or TMS320C674x CPU and Instruction Set Reference Guide.
4.6.4 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.7 and Section 4.8)
- a register operand
- a memory reference operand
- an expression that evaluates to one of the above (see Section 4.9)
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.9 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.6.5 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.7 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.7.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.7.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.7.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.7.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.7.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.7.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.7.2 discusses character strings). A character literal represents a single integer value; a string is a sequence of characters. |
4.7.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.7.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. See Section 4.10.1 for built-in functions.
$strtod("NaN")
$strtod("Inf")
4.8 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.6 for more about symbols and the symbol tables in object files.
4.8.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.8.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 .bss, .global, .ref, or .def directives.
.global label1
label2: MVKL label2, B3
MVKH label2, B3
B label1
NOP 5
4.8.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:
SUB A1,1,A1
[A1] B $1
SUBC A3,A0,A3
NOP 4
.newblock ; undefine $1 to use it again
$1 SUB A2,1,A2
[A2] B $1
MPY A3,A3,A3
NOP 4
The following code uses a local label illegally:
$1:
SUB A1,1,A1
[A1] B $1
SUBC A3,A0,A3
NOP 4
$1 SUB A2,1,A2 ; WRONG - $1 is multiply defined
[A2] B $1
MPY A3,A3,A3
NOP 4
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?
nop 5
****************************************************************
** Include file has second definition of mylab **
****************************************************************
.copy "a.inc"
****************************************************************
** Third definition of mylab, reset upon exit from .include **
****************************************************************
mylab? nop
B mylab?
nop 5
****************************************************************
** Fourth definition of mylab in macro, macros use different **
** namespace to avoid conflicts **
****************************************************************
mymac .macro
mylab? nop
B mylab?
nop 5
.endm
****************************************************************
** Macro invocation **
****************************************************************
mymac
****************************************************************
** Reference to third definition of mylab. Definition is not **
** reset by macro invocation. **
****************************************************************
B mylab?
nop 5
****************************************************************
** Changing section, allowing fifth definition of mylab **
****************************************************************
.sect "Sect_One" nop
mylab? .word 0
nop
nop
B mylab?
nop 5
****************************************************************
** The .newblock directive allows sixth definition of mylab **
****************************************************************
.newblock
mylab? .word 0
nop
nop
B mylab?
nop 5
For more information about using labels in macros see Section 6.6.
4.8.4 Symbolic Constants
A symbolic constant is a symbol with a value that is an absolute constant expression (see Section 4.9). 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:
sym .set 3
MVK sym,B1
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:
sym .set B1
MVK 10,sym
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
.bss array, i_len*K ; declare an array of K "items" .text
LDW *+B14(array.delta + 2*i_len),A1
; access array [2].delta
The assembler also has many predefined symbolic constants; these are discussed in Section 4.8.6.
4.8.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:
cl6x --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:
cl6x --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.8.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).
In addition, the following predefined processor symbolic constants are available:
Table 4-2 C6000 Processor Symbolic Constants
Symbol name | Description |
---|---|
_ _TI_EABI_ _ | Set to 1 if EABI is enabled. EABI is now the only supported ABI; see Section 4.4. |
.TMS320C6X | Always set to 1 |
.TMS320C6400_PLUS | Set to 1 if target is C6400+, C6740, or C6600; otherwise 0 |
.TMS320C6600 | Set to 1 if target is C6600, otherwise 0 |
.TMS320C6740 | Set to 1 if target is C6740 or C6600, otherwise 0 |
.LITTLE_ENDIAN | Set to 1 if little-endian mode is selected (the -me assembler option is not used); otherwise 0 |
.ASSEMBLER_VERSION | Set to major * 1000000 + minor * 1000 + patch version. |
.BIG_ENDIAN | Set to 1 if big-endian mode is selected (the -me assembler option is used); otherwise 0 |
.SMALL_MODEL | Set to 1 if --memory_model:code=near and --memory_model:data=near, otherwise 0. |
.LARGE_MODEL | Set to 1 if .SMALL_MODEL is 0, otherwise 0. |
4.8.7 Registers
The names of C6000 registers are predefined symbols, including A0-A15 and B0-B15; and A16-31 and B16-31.
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, CSR can also be entered as csr.
See the "Register Conventions" section of the TMS320C6000 Optimizing Compiler User's Guide for details about the registers and their uses.
Table 4-3 CPU Control Registers
Register | Description |
---|---|
AMR | Addressing mode register |
CSR | Control status register |
DNUM | DSP core number register |
ECR | Exception clear register |
EFR | Exception flag register |
FADCR | (C6740 and C6600 only) Floating-point adder configuration register |
FAUCR | (C6740 and C6600 only) Floating-point auxiliary configuration register |
FMCR | (C6740 and C6600 only) Floating-point multiplier configuration register |
GFPGFR | Galois field polynomial generator function register |
GPLYA | GMPY A-side polynomial register |
GPLYB | GMPY B-side polynomial register |
ICR | Interrupt clear register |
IER | Interrupt enable register |
IERR | Interrupt exception report register |
IFR | Interrupt flag register (read only) |
ILC | Inner loop count register |
IRP | Interrupt return pointer |
ISR | Interrupt set register |
ISTP | Interrupt service table pointer |
ITSR | Interrupt task state register |
NRP | Nonmaskable interrupt return pointer |
NTSR | NMI/Exception task state register |
PCE1 | Program counter, E1 phase |
REP | Restricted entry point address register |
RILC | Reload inner loop count register |
SSR | Saturation status register |
TSCH | Time-stamp counter (high 32) register |
TSCL | Time-stamp counter (low 32) register |
TSR | Task status register |
4.8.8 Register Pairs
Many instructions in the C6000 instruction set across the various available target processors support a 64-bit register operand that can be specified as a register pair.
A register pair should be specified on the A side or the B side, depending on which functional unit an instruction is to be executed on, and whether a cross functional unit data path is utilized by the instruction. You cannot mix A-side and B-side registers in the same register pair operand.
The syntax for a register pair is as follows where (n%2 == 0):
Rn+1:Rn |
The legal register pairs are:
A1:A0 | B1:B0 |
A3:A2 | B3:B2 |
A5:A4 | B5:B4 |
A7:A6 | B7:B6 |
A9:A8 | B9:B8 |
A11:A10 | B11:B10 |
A13:A12 | B13:B12 |
A15:A14 | B15:B14 |
A17:A16 | B17:B16 |
A19:A18 | B19:B18 |
A21:A20 | B21:B20 |
A23:A22 | B23:B22 |
A25:A24 | B25:B24 |
A27:A26 | B27:B26 |
A29:A30 | B29:B30 |
A31:A32 | B31:B32 |
Here is an example of an ADD instruction that uses a register pair operand:
ADD.L1 A5:A4,A1,A3:A2
For details on using register pairs in linear assembly, see the TMS320C6000 Optimizing Compiler User's Guide.
For more information on functional units, including which assembly instructions require which functional type, see the TMS320C64x/C64x+ DSP CPU and Instruction Set Reference Guide, TMS320C66x CPU and Instruction Set Reference Guide, or TMS320C6740 DSP CPU and Instruction Set Reference Guide.
4.8.9 Register Quads (C6600 Only)
Several instructions in the C6600 instruction set support a 128-bit register operand which can be specified as a register quad.
A register quad should be specified on the A side or the B side, depending on which functional unit an instruction is to be executed on, and whether a cross functional unit data path is utilized by the instruction. You cannot mix A-side and B-side registers in the same register quad operand.
The general syntax for a register quad is as follows, where (n%4 == 0):
Rn+3 : Rn+2 : Rn+1 : Rn | or | Rn+3 :: Rn |
The legal register quads are:
A Register Quads | Short Form | B Register Quads | Short Form |
---|---|---|---|
A3:A2:A1:A0 | A3::A0 | B3:B2:B1:B0 | B3::B0 |
A7:A6:A5:A4 | A7::A4 | B7:B6:B5:B4 | B7::B4 |
A11:A10:A9:A8 | A11::A8 | B11:B10:B9:B8 | B11::B8 |
A15:A14:A13:A12 | A15::A12 | B15:B14:B13:B12 | B15::B12 |
A19:A18:A17:A16 | A19::A16 | B19:B18:B17:B16 | B19::B16 |
A23:A22:A21:A20 | A23::A20 | B23:B22:B21:B20 | B23::B20 |
A27:A26:A25:A24 | A27::A24 | B27:B26:B25:B24 | B27::B24 |
A31:A30:A29:A28 | A31::A28 | B31:B30:B29:B28 | B31::B28 |
Here is an example of an ADD instruction that uses register quad operands:
QMPYSP .M1 A27:A26:A25:A24, A11:A10:A9:A8, A19:A18:A17:A16
For details on using register quads in C6600 linear assembly, see the TMS320C6000 Optimizing Compiler User's Guide.
For more information on functional units, including which assembly instructions require which functional type, see the TMS320C66x CPU and Instruction Set Reference Guide.
4.8.10 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:
.global _table
.asg "B14", PAGEPTR
.asg "*+B15(4)", LOCAL1
.asg "*+B15(8)", LOCAL2
LDW *+PAGEPTR(_table),A0
NOP 4
STW A0,LOCAL1
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:
MAC .macro src1, src2, dst ; Multiply/Accumulate macro
MPY src1, src2, src2
NOP
ADD src2, dst, dst
.endm
* MAC macro invocation
MAC A0,A1,A2
See Section 6 for more information about macros.
4.9 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. Such expressions may contain at most 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.9.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-4, 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-4 lists the operators that can be used in expressions, according to precedence group.
Table 4-4 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.9.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.9.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.9.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 using the register relative addressing mode, the expression in brackets or parenthesis must be a well-defined expression, as described in Section 4.9.3. For example:
- Expressions used to describe the offset in register relative addressing mode for the registers B14 and B15, or expressions used as the operand to the branch instruction, are subject to the same limitations. For these two cases, all legal expressions can be reduced to one of two forms:
*+A4[15]
*+XA4[7]
relocatable symbol ± absolute symbol | B (extern_1-10) |
|
or | ||
a well-defined expression | *+B14/B15[14] |
4.9.5 Expression Examples
Following are examples of expressions that use relocatable and absolute symbols. These examples use four symbols that are defined in the same section:
.global extern_1 ; Defined in an external module
intern_1: .word '"D' ; Relocatable, defined in
; current module
intern_2 ; Relocatable, defined in
; current module
intern_3 ; Relocatable, defined in
; current module
- Example 1
- Example 2
- Example 3
- Example 4
The internal values must be forrmed by absolute constant expressions. The following examples are illegal because variables are used where constants are required.
.word extern_1 * intern_2 - 13 ; Illegal
MVKL (intern_1 - extern_1),A1 ; Illegal
The first statement in the following example is valid; the statements that follow it are illegal
B (extern_1 - 10) ; Legal
B (10-extern_1) ; Can't negate reloc. symbol
LDW *+B14 (-(intern_1)), A1 ; Can't negate reloc. symbol
LDW *+B14 (extern_1/10), A1 ; / not an additive operator
B (intern_1 + extern_1) ; Multiple relocatables
The first statement below is legal; although intern_1 and intern_2 are relocatable, their difference is absolute because they are in the same section. Subtracting one relocatable symbol from another reduces the expression to relocatable symbol + absolute value. The second statement is illegal because the sum of two relocatable symbols is not an absolute value.
B (intern_1 - intern_2 + extern_3) ; Legal
B (intern_1 + intern_2 + extern_3) ; Illegal
A relocatable symbol's placement in the expression is important to expression evaluation. Although the statement below is similar to the first statement in the previous example, it is illegal because of left-to-right operator precedence; the assembler attempts to add intern_1 to extern_3.
B (intern_1 + extern_3 - intern_2) ; Illegal
4.10 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.10.1 Built-In Math and Trigonometric Functions
The assembler supports built-in functions for conversions and various math computations. Table 4-5 describes the built-in functions. The expr must be an absolute constant expression.
Table 4-5 Built-In Mathematical Functions
Function | Description |
---|---|
$acos(expr) | Returns the arccosine of expr as a floating-point value |
$asin(expr) | Returns the arcsine of expr as a floating-point value |
$atan(expr) | Returns the arctangent of expr as a floating-point value |
$atan2(expr, y) | Returns the arctangent of expr as a floating-point value in range [-π, π] |
$ceil(expr) | Returns the smallest integer not less than expr |
$cos(expr) | Returns the cosine of expr as a floating-point value |
$cosh(expr) | Returns the hyperbolic cosine of expr as a floating-point value |
$cvf(expr) | Converts expr to a floating-point value |
$cvi(expr) | converts expr to integer value |
$exp(expr) | Returns the exponential function e expr |
$fabs(expr) | Returns the absolute value of expr as a floating-point value |
$floor(expr) | Returns the largest integer not greater than expr |
$fmod(expr, y) | Returns the remainder of expr1 ÷ expr2 |
$int(expr) | Returns 1 if expr has an integer value; else returns 0. Returns an integer. |
$ldexp(expr, expr2) | Multiplies expr by an integer power of 2. That is, expr1 × 2 expr2 |
$log(expr) | Returns the natural logarithm of expr, where expr>0 |
$log10(expr) | Returns the base 10 logarithm of expr, where expr>0 |
$max(expr1, expr2) | Returns the maximum of two values |
$min(expr1, expr2) | Returns the minimum of two values |
$pow(expr1, expr2) | Returns expr1raised to the power of expr2 |
$round(expr) | Returns expr rounded to the nearest integer |
$sgn(expr) | Returns the sign of expr. |
$sin(expr) | Returns the sine of expr |
$sinh(expr) | Returns the hyperbolic sine of expr as a floating-point value |
$sqrt(expr) | Returns the square root of expr, expr≥0, as a floating-point value |
$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(expr) | Returns the tangent of expr as a floating-point value |
$tanh(expr) | Returns the hyperbolic tangent of expr as a floating-point value |
$trunc(expr) | Returns expr rounded toward 0 |
4.10.2 C6x Built-In ELF Relocation Generating Operators
The assembler supports several C6000-specific ELF relocation generating built-in operators. The operators are used in compiler-generated code to support symbolic addressing of objects.
The operators are used to support various forms of DP-relative and PC-relative addressing instruction sequences. For more detailed information about DP-relative and PC-relative addressing instruction sequences, please see The C6000 Embedded Application Binary Interface Application Report (SPRAB89).
4.10.2.1 $DPR_BYTE(sym) / $DPR_HWORD(sym) / $DPR_WORD(sym)
The $DPR_BYTE(sym), $DPR_HWORD(sym), or $DPR_WORD(sym) operator can be applied in the source operand of a MVKL or MVKH instruction to load the DP-relative offset of a symbol's address into a register. These operators are used by the compiler when accessing data objects that are not within the signed 15-bit offset range that is needed for using the DP-relative addressing mode.
EABI requires that all sections that are accessed via DP-relative addressing be grouped together. The linker then uses the address of the first section in that group as the "static base" whose value is attached to the symbol __c6xabi_DSBT_BASE. DP-relative addressing then implicitly incorporates the value of __c6xabi_DSBT_BASE into the resolution of the referenced symbol. In the examples that follow, "static_base" in the comments indicates the location of this static base. See Chapter 4 of the The C6000 Embedded Application Binary Interface Application Report (SPRAB89) for more details about data allocation and addressing.
For example, suppose the compiler needs to access a 32-bit aligned data object called 'xyz' that is defined in the .far section. The compiler must assume that the .far section is too far away from the base of the .bss section (whose address the runtime library's boot routine has loaded into the DP register), so using DP-relative addressing mode to access 'xyz' directly is not possible. Instead, the compiler will use a MVKL/MVKH/LDW sequence of instructions:
MVKL $DPR_WORD(xyz),A0 ; load (xyz - static_base)/4 into A0
MVKH $DPR_WORD(xyz),A0
LDW *+DP[A0],A1 ; load *xyz into A1
This sequence of instructions is also referred to as far DP-relative addressing. The LDW instruction uses a scaled version of DP-relative indexed addressing. Similar to the $DPR_WORD(sym) operator, the $DPR_BYTE(sym) operator is provided to facilitate far DP-relative addressing of 8-bit data objects:
MVKL $DPR_BYTE(xyz),A0 ; load (xyz - static_base) into A0
MVKH $DPR_BYTE(xyz),A0
LDB *+DP[A0],A1 ; load *xyz into A1
The $DPR_HWORD(sym) operator is provided to facilitate far DP-relative addressing of 16-bit data objects:
MVKL $DPR_HWORD(xyz),A0 ; load (xyz - static_base)/2 into A0
MVKH $DPR_HWORD(xyz),A0
LDH *+DP[A0],A1 ; load *xyz into A1
If the data being accessed is within range of the anticipated value of the DP (assuming the static base is loaded into the DP before the MVK instructions are used), then a more efficient way to access the data can be to use MVK instructions. For example, the compiler can compute the address of an 8-bit data object in the .bss section:
MVK $DPR_BYTE(_char_X),A4 ; load (_char_X - static_base) into A4
ADD DP,A4,A4 ; compute address of _char_X
Similarly, the compiler can compute the address of a 16-bit data object that is defined in the .bss section:
MVK $DPR_HWORD(_short_X),A4 ; load (_short_X - static_base)/2 into A4
ADD DP,A4,A4 ; compute address of _short_X
It can also compute a 32-bit data object that is defined in the .bss section:
MVK $DPR_WORD(_int_X),A4 ; load (_int_X - static_base)/4 into A4
ADD DP,A4,A4 ; compute address of _int_X
4.10.2.2 $GOT(sym) / $DPR_GOT(sym)
The $GOT(sym) operator can be applied in the source operand of an LDW instruction. The $DPR_GOT(sym) operator can be applied in the source operand of a MVKL or MVKH instruction. These operators are used in the context of compiler-generated code under a dynamic linking ABI (either the Bare-Metal or Linux Dynamic Linking Model. See Chapter 14 of The C6000 Embedded Application Binary Interface Application Report (SPRAB89) for more details on the dynamic linking models supported in the C6000 Code Generation Tools (CGT).
Symbols that are preemptable or are imported by a dynamic module will be accessed via the Global Offset Table (GOT). A GOT entry for a symbol will contain the address of the symbol as it is determined at dynamic load time. To facilitate this resolution, the static linker will emit a dynamic relocation entry that is to be processed by the dynamic linker/loader. For more information on the GOT, see The C6000 Embedded Application Binary Interface Application Report (SPRAB89).
If the GOT entry for a symbol, xyz, is accessible using DP-relative addressing mode, then the compiler will generate a sequence to load the symbol that uses the $GOT(sym) op0erator as the offset part of the DP-relative addressing mode operand:
LDW *+DP[$GOT(xyz)],A0 ; load address of xyz into A0
; via access to GOT entry
LDW *A0,A1 ; load xyz into A2
The actual semantics of the $GOT(sym) operator is to return the DP- relative offset of the GOT entry for the referenced symbol (xyz above).
While $DPR_GOT(sym) is semantically similar to the $GOT(sym) operator, it is used when the GOT is not accessible using DP-relative addressing mode (offset is not within signed 15-bit range of the static base address that is loaded into the data pointer register (DP)). The DP-relative offset to the GOT entry is then loaded into an index register using a MVKL/MVKH instruction sequence, and the GOT entry is then accessed via DP-relative indexed addressing to load the address of the referenced symbol:
MVKL $DPR_GOT(xyz),A0 ; load DP-relative offset of
MVKH $DPR_GOT(xyz),A0 ; GOT entry for xyz into A0
LDW *+DP[A0],A1 ; get address of xyz via GOT entry
LDW *A1,A2 ; load xyz into A2
4.10.2.3 $PCR_OFFSET(x,y)
The $PCR_OFFSET(x,y) operator can be applied in the source operand of a MVKL, MVKH, or ADDK instruction to compute a PC-relative offset to be loaded into (in the case of MVKL/MVKH) or added to (in the case of ADDK) a register.
This operator is used in the context of compiler-generated code under the Linux ABI (using --linux compiler option). It helps the compiler to generate position-independent code by accessing a symbol that is defined in the same RO segment using PC-relative addressing.
For example, if there is to be a call to a function defined in the same file, but you would like to avoid generating a dynamic relocation that accesses the symbol that represents the destination of the call, then you can use the $PCR_OFFSET operator as follows:
dest:
<code> ...
make_pcr_call:
MVC PCE1, B0 ; set up PC reference point in B0
MVKL $PCR_OFFSET(dest, make_pcr_call), B1 ; compute dest - make_pcr_call
MVKH $PCR_OFFSET(dest, make_pcr_call), B1 ; and load it into B1
ADD B0,B1,B0 ; compute dest address into B0 register
B B0 ; call dest indirectly through B0
...
The above code sequence is position independent. No matter what address 'dest' is placed at load time, the call to 'dest' will still work since it is independent of the actual address of 'dest'. However, the call does have to maintain its position relative to the definition of 'dest'.
Also in the above sequence, the compiler creates a coupling between the MVC instruction and the 'make_pcr_call' label. The 'make_pcr_call' label must be associated with the address of the MVC instruction so that when the $PCR_OFFSET(dest, make_pcr_call) operator is applied, the 'make_pcr_call' symbol becomes a representative for the PC reference point. This means that the result of 'dest - make_pcr_call' becomes the PC-relative offset which when added to the PC reference point in B0 gives the address of 'dest'.
The relocation that is generated for the $PCR_OFFSET() operator is handled during the static link step in which a dynamic module is built. This static relocation can then be discarded and no dynamic relocation will be needed to resolve the call to 'dest' in the above example.
4.10.2.4 $LABEL_DIFF(x,y) Operator
The $LABEL_DIFF(x,y) operator can be applied to an argument for a 32-bit data-defining directive (like .word, for example). The operator simply computes the difference between two labels that are defined in the same section. This operator is sometimes used by the compiler under the Linux ABI (--linux compiler option) when generating position independent code for a switch statement.
For example, in Example 4-4 a switch table is generated which contains the PC-relative offsets of the switch case labels:
Example 4-4 Generating a Switch Table With Offset Switch Case Labels
.asg A15, FP
.asg B14, DP
.asg B15, SP
.sect ".text" .clink
.global myfunc
;******************************************************************************
;* FUNCTION NAME: myfunc *
;******************************************************************************
myfunc:
;** --------------------------------------------------------------------------*
B .S1 $C$L10
|| SUB .L2X A4,10,B5
|| STW .D2T2 B3,*SP--(16)
CMPGTU .L2 B5,7,B0
|| STW .D2T1 A4,*+SP(12)
|| MV .S2X A4,B4
[ B0] BNOP .S1 $C$L9,3
; BRANCH OCCURS {$C$L10} ; |6|
;** --------------------------------------------------------------------------*
$C$L1:
<case 0 code> ...
;** --------------------------------------------------------------------------*
$C$L2:
<case 1 code> ...
;** --------------------------------------------------------------------------*
$C$L3:
<case 2 code> ...
;** --------------------------------------------------------------------------*
$C$L4:
<case 3 code> ...
;** --------------------------------------------------------------------------*
$C$L5:
<case 4 code> ...
;** --------------------------------------------------------------------------*
$C$L6:
<case 5 code> ...
;** --------------------------------------------------------------------------*
$C$L7:
<case 6 code> ...
;** --------------------------------------------------------------------------*
$C$L8:
<case 7 code> ...
;** --------------------------------------------------------------------------*
$C$L9:
<default case code> ...
;** --------------------------------------------------------------------------*
$C$L10:
NOP 2
; BRANCHCC OCCURS {$C$L9} {-9} ;
;** --------------------------------------------------------------------------*
SUB .L2 B4,10,B5 ; Norm switch value -> switch table index
|| ADDKPC .S2 $C$SW1,B4,0 ; Load address of switch table to B4
LDW .D2T2 *+B4[B5],B5 ; Load PC-relative offset from switch table
NOP 4
ADD .L2 B5,B4,B4 ; Combine to get case label into B5
BNOP .S2 B4,5 ; Branch to case label
; BRANCH OCCURS {B4} ;
; Switch table definition
.align 32
.clink
$C$SW1: .nocmp
.word $LABEL_DIFF($C$L1,$C$SW1) ; 10
.word $LABEL_DIFF($C$L2,$C$SW1) ; 11
.word $LABEL_DIFF($C$L3,$C$SW1) ; 12
.word $LABEL_DIFF($C$L4,$C$SW1) ; 13
.word $LABEL_DIFF($C$L5,$C$SW1) ; 14
.word $LABEL_DIFF($C$L6,$C$SW1) ; 15
.word $LABEL_DIFF($C$L7,$C$SW1) ; 16
.word $LABEL_DIFF($C$L8,$C$SW1) ; 17
.align 32
.sect ".text" ...
Example 4-4 mixes data into the code section. Compression is disabled for the code section that contains the $LABEL_DIFF() operator, since the label difference must resolve to a constant value during assembly.
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, .bss, 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 | |
- | .bss, .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-5 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-6 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:
cl6x --symdebug:dwarf cvars.c addfive.asm --run_linker --library=lnk.cmd --library=rts6600.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-5 Viewing Assembly Variables as C Types C Program
typedef struct
{
int m1;
int m2;
} X;
X svar = { 1, 2 };
Example 4-6 Assembly Program for Example 4-5
;--------------------------------------------------------------------------------------
; 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
LDW .D2T2 *+B14(_svar+4),B4 ; load svar.m2 into B4
RET .S2 B3 ; return from function
NOP 3 ; delay slots 1-3
ADD .D2 5,B4,B4 ; add 5 to B4 (delay slot 4)
STW .D2T2 B4,*+B14(_svar+4) ; store B4 back into svar.m2 (delay slot 5)
.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 --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-7 shows the four fields contained in the cross-reference listing.
Example 4-7 An Assembler Cross-Reference Listing
LABEL VALUE DEFN REF
.BIG_ENDIAN 00000000 0
.LITTLE_ENDIAN 00000001 0
.TMS320C6400_PLUS 00000001 0
.TMS320C6600 00000000 0
.TMS320C6740 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-6 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-6 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 .bss or .usect section |
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.