Referring to Assembly, C, and C++ Variables. NXP CodeWarrior Development Studio
Реклама
Реклама
Chapter 20 Inline-Assembly for Power Architecture Build Tools
Comment
*/
20.1.10 Using the Preprocessor
You can use all preprocessor features, such as comments and macros, in the assembler. In multi-line macros, you must end each assembly statement with a semicolon (
;
) because the (
\
) operator removes newlines. For example:
#define remainder(x,y,z) \
divw z,x,y; \
mullw z,z,y; \
subf z,z,x
asm void newPointlessMath(void)
{
remainder(r3,r4,r5)
blr
}
20.2 Referring to Assembly, C, and C++ Variables
The compiler's inline assembler has access to the local and global variables declared in C or C++ source code. The assembler also allows access to members of array, struct
, and class
objects:
•
Using Local Variables and Arguments
•
•
Referring to Variables in Instruction Operands
•
Referring to Variables in Memory
•
•
•
Using Variable Names as Memory Locations
•
20.2.1 Using Local Variables and Arguments
CodeWarrior Development Studio for Power Architecture Processors Build Tools Reference Manual, Rev.
10.6, 02/2014
Freescale Semiconductor, Inc.
337
Referring to Assembly, C, and C++ Variables
To refer to a memory location, you can use the name of a local variable or argument.
The rule for assigning arguments to registers or memory depends on whether the function has a stack frame.
If function has a stack frame, the inline assembler assigns:
• scalar arguments declared as register
to general purpose registers r14
to r31
• floating-point arguments declared as register
to floating point fp14
to fp31
• other arguments to memory locations
If a function has no stack frame, the inline assembler assigns arguments that are declared register
and kept in registers. If you have variable or non-register arguments, the compiler will warn you that you should use frfree
NOTE
Some op-codes require registers, and others require objects. For example, if you use nofralloc
with function arguments, you may run into difficulties.
20.2.2 Creating a Stack Frame
You need to create a stack frame for a function if the function:
• calls other functions.
• declares non-register arguments or local variables.
To create a stack frame, use the fralloc
directive at the beginning of your function and the frfree
directive just before the blr
statement. The directive fralloc
automatically allocates
(while ffree
automatically de-allocates) memory for local variables, and saves and restores the register contents.
Listing 20-5. Example of creating a stack frame
asm void red ()
{
fralloc
// Your code here
frfree
blr
}
The fralloc
directive has an optional argument, number, that lets you specify the size, in bytes, of the parameter area of the stack frame. The stack frame is an area for storing parameters used by the assembly code. The compiler creates a 0-byte parameter area for you to pass variables into your assembly language functions.
CodeWarrior Development Studio for Power Architecture Processors Build Tools Reference Manual, Rev.
10.6, 02/2014
338 Freescale Semiconductor, Inc.
Chapter 20 Inline-Assembly for Power Architecture Build Tools
Function arguments are passed using registers. If your assembly-language routine calls any function that requires more parameters than will fit into registers r3
to r10
and fp1
to fp8
, you need to pass that size to fralloc
. In the case of integer values, registers r3
- r10 are used. For floating-point values, registers fp1
- fp8 are used.
As an example, if you pass 12 values of type long integer
to your assembly function, this would consume 16 bytes of the parameter area. Registers r3
- r10
will hold eight integers, leaving 4 byte integers in the parameter area.
20.2.3 Referring to Variables in Instruction Operands
For instructions that require register operands, (such as the add
instruction), global variables, function parameters, and local variables must be declared with the keyword register
.
shows inline assembly language statements that correctly use
C-language variables as operands in instructions that require register operands.
Listing 20-6. Using C Variables with Instructions that Require Register Operands
int my_global asm("r14")= 25; /* global variable */ int my_loc asm("r15")= 1; asm void red(register int *my_param)
{ register int result; fralloc add result, r4, my_global /* line 10 */ add result, my_global, my_param /* line 11 */ add result, my_param, my_loc /* line 12 */ frfree blr
}
In
Listing 20-6 on page 339 , the statement on line 10, 11, and 12 are all correct because
their operands are all declared with the register
keyword.
20.2.4 Referring to Variables in Memory
For instructions that take a memory operand (such as the lwz
instruction), follow these rules when using a C-language variable as an operand:
• Global variables and function parameters must:
Be declared/assigned with the register.
CodeWarrior Development Studio for Power Architecture Processors Build Tools Reference Manual, Rev.
10.6, 02/2014
Freescale Semiconductor, Inc.
339
Referring to Assembly, C, and C++ Variables
• Adhere to the syntax below when used as operands, so they are treated as an offset from zero.
instrName regName , 0(globalVarName ) or
instrName regName , 0(parameterName )
shows inline assembly language statements that correctly use
C-language variables as operands in instructions that take a memory operand.
Listing 20-7. Using C Variables with Instructions that Take a Memory Operand
int my_global asm("r14")= 25; /* global variable */ int my_loc = 1; /* my_loc is on memory, not in a register */ asm void red(register int *my_param)
{ lwz r4, 0(my_global) /* line 9 */ lwz r4, 0(my_param) /* line 10 */ lwz r4, my_loc /* line 11 */ lwz r4, my_loc(SP) blr
}
In
• The statement on line 9 is correct.
• The operand is fully expressed (because it is an offset from zero).
• The argument my_global
is in a register.
• The statement on line 10 is correct for the same reasons as stated above.
• The statement on line 11 is correct.
The CodeWarrior inline assembler automatically adds the contents of the
SP
register to local variable my_loc
.
• The statement on line 12 is correct.
Note that statements 11 and 12 are equivalent.
As mentioned above, the inline assembler automatically adds the
SP
register to local variable my_loc
, so explicitly including
(SP)
is redundant.
20.2.5 Referring to Registers
For a register operand, you must use one of the register names of the appropriate kind for the instruction. The register names are case-sensitive. You also can use a symbolic name for an argument or local variable that was assigned to a register.
CodeWarrior Development Studio for Power Architecture Processors Build Tools Reference Manual, Rev.
10.6, 02/2014
340 Freescale Semiconductor, Inc.
Chapter 20 Inline-Assembly for Power Architecture Build Tools
The general registers are
SP
, r0
to r31
, and gpr0
to gpr31
. The floating-point registers are fp0
to fp31
and f0
to f31
. The condition registers are cr0
to cr7
.
20.2.6 Referring to Labels
For a label operand, you can use the name of a label. For long branches (such as b
and bl instructions) you can also use function names. For bla
and la
instructions, use absolute addresses.
For other branches, you must use the name of a label. For example,
• b @3
- correct syntax for branching to a local label
• b red
- correct syntax for branching to external function red
• bl @3
- correct syntax for calling a local label
• bl red
- correct syntax for calling external function red
• bne red
- incorrect syntax; short branch outside function red
NOTE
You cannot use local labels that have already been declared in other functions.
20.2.7 Using Variable Names as Memory Locations
Whenever an instruction, such as a load instruction, a store instruction, or la
, requires a memory location, you can use a local or global variable name. You can modify local variable names with struct member references, class member references, array subscripts, or constant displacements. For example, all the local variable references in
Listing 20-8 on page 341 are valid.
Listing 20-8. Example of referring to variables stored in memory locations
asm void red(void){
long myVar;
long myArray[1];
Rect myRectArray[3];
fralloc
lwz r3,myVar(SP)
la r3,myVar(SP)
lwz r3,myRect.top
lwz r3,myArray[2](SP)
lwz r3,myRectArray[2].top
lbz r3,myRectArray[2].top+1(SP)
frfree
CodeWarrior Development Studio for Power Architecture Processors Build Tools Reference Manual, Rev.
10.6, 02/2014
Freescale Semiconductor, Inc.
341
Referring to Assembly, C, and C++ Variables
blr
}
You can also use a register variable that is a pointer to a struct
or class
to access a
member of the object, shown in Listing 20-9 on page 342
.
Listing 20-9. Example of referring to a struct or class member
void red(void){
Rect q;
register Rect *p = &q;
asm {
lwz r3,p->top;
}
}
You can use the
@hiword
and
@loword
directives to access the high and low four bytes of 8
byte long longs and software floating-point doubles ( Listing 20-10 on page 342
).
Listing 20-10. Example of referring to high and low words
long long gTheLongLong = 5; asm void Red(void); asm void Red(void)
{
fralloc
lwz r5, gTheLongLong@hiword
lwz r6, gTheLongLong@loword
frfree
blr
}
20.2.8 Using Immediate Operands
For an immediate operand, you can use an integer or enum constant, sizeof
expression, and any constant expression using any of the C dyadic and monadic arithmetic operators.
These expressions follow the same precedence and associativity rules as normal C expressions. The inline assembler carries out all arithmetic with 32-bit signed integers.
An immediate operand can also be a reference to a member of a struct or class type. You can use any struct or class name from a typedef
statement, followed by any number of member references. This evaluates to the offset of the member from the start of the struct.
For example:
lwz r4,Rect.top(r3)
addi r6,r6,Rect.left
As a side note, la rD,d(rA)
is the same as addi rD,rA,d
.
CodeWarrior Development Studio for Power Architecture Processors Build Tools Reference Manual, Rev.
10.6, 02/2014
342 Freescale Semiconductor, Inc.
Изтегляне
Реклама