Revision 2 - 26 Feb. 2003
This Application Note tells you how to use the extended inline assembler that is integrated in the Keil C166 Compiler. With the extended inline assembler you may insert assembler instructions into C function code while retaining full debug and optimization capabilities. The extended inline assembler fully supports all C16x, XC16x, ST10 and Super10 instruction set extensions.
Information in this file, the accompany manuals, and software
is
Copyright © Keil Software, Inc and Keil Elektronik GmbH.
All rights reserved.
Revision History:
Rev 1: 25. Oct. 2002: Initial Version
Rev 2: 25. Feb. 2003: Added Inline-Assembly within Preprocessor Macros
The Keil C166 Compiler supports (in version 4.35 or higher) two types of inline assembly:
Inline Assembly with SRC directive: is compatible with previous versions of the C166 Compiler and generates an assembler source file. The assembler source file needs to be assembled with A166. Example:
C166 Measure.c SRC A166 Measure.SRC
The assembler source file might be used as template for own assembler programs. You may therefore modify the generated SRC file and use it as assembler source file in your µVision2 project.
Inline Assembly without SRC directive: the C166 Compiler assembles the inline assembly statements directly into the object code. The integrated assembler supports all instruction set variants (C166, C167, ST10, and XC16x) including MAC instructions.
The benefits of the integrated inline assembler are:
The set of instructions depends on the C166 compiler invocation directives as shown in the table below:
| Directive | Description |
|---|---|
| --- | 80C166 instruction set |
| MOD167 | C167 instruction set |
| EXTMAC | C167 instructions including ST10 MAC extensions |
| MODV2 | XC16x / Super10 instructions including MAC extensions |
Extended inline assembler blocks are started with __asm statetmens. The syntax is:
__asm { instruction ; comment }
__asm { ; open inline-assembly block
instruction ; comment
...
} // close inline-assembly block
Rules for __asm statement blocks:
Example:
int AddUp (int n, int near *pTab) {
__asm { ; open inline-assembly block
mov r2,pTab ; R2:=start of table
mov r3,n
cmp r3,#0
jmp cc_sle,stop ;
shl r3,#1 ; n * 2
add r3,r2 ; R3 := (n*2)+pTab, end of table + 2
mov r4,#0x00 ; clear result
lM: add r4,[r2+] ; add up next value
cmp r2,r3 ; end of table ?
jmp cc_nz,lM ; loop if not eot
ret ; need result in R4
}
stop:
__asm { nop ; single line assembly }
__asm { nop ; another nop }
return (0);
}
C macros offer a convenient way to insert assembly code into your source code, but they demand extra care because a macro expands into a single logical line. To create trouble-free macros, follow these rules:
Example:
#define ABLOCK __asm { /* comment */ \
__asm mov R5,#0x10 \
__asm l1: mov rl4,#'}' \
__asm mov R6,R5 \
__asm jnbs R6.2,l1 \
}
The last four __asm keywords seem superfluous, they are needed, however, because the macro expands into a single line.
The preprocessor's handling of '#' within macro definitions starting with __asm is relaxed since # is used for immediate values in assembly language. In pure C, something like #0x10 causes an error in the preprocessing phase due to violating the C preprocessor rules.
#define ABLOCK __asm { /* comment */ \
__asm mov R5,#0x10 \
__asm l1: mov rl4,#'}' \
__asm mov R6,R5 \
__asm bset R6.3 \
__asm jnbs R6.2,l1 \
}
int i;
void main (void) {
i = 1;
ABLOCK // expand inline assembly macro
i = 2;
}
The syntax of the A166 Macro Assembler apply also to __asm blocks.
Expression can be absolute or relocatable, as it is the case with the A166 Macro
Assembler.
Constants can be written in Assembler or C format, i.e. 0E123H, 0xE123, 256.
Assembler Symbols can refer to C identifiers such as automatic, global or external variable names, parameters, labels, enumerations, functions, and registerbank names. For you can refer to a registerbank as shown in the following example:
void FuncRB (void) using __MyBank {
...
}
mov r3,#__MyBank
scxt r3,#__MyBank
The Keil C166 Compiler optimizes the C code and assigns automatic variables and parameters to registers (if possible). When an variable is assigned to CPU registers, you may use it in almost all CPU instructions as direct operand. However, if the variable is located on the user stack or in fixed memory locations, only a few instructions can access this variable. Therefore the legal operand combinations depend on the location of such variables (CPU register, user stack, or fixed memory location). Illegal operand combinations are flagged as error by the C166 Compiler. The instruction combination determined by the C166 Compiler is shown in the listing file. Therefore you should generate a C166 Compiler listing and refer to this listing file in case of errors.
The following two examples show legal and illegal instruction set combinations:
Example 1: Valid access to a local variable
long lFunc (void) {
long l1 = 0; // l1 is assigned to R6/R7
__asm {
mov r2,#0x5678
mov r1,#0x1234
add word0 l1,r1
add word2 l1,r2
}
return (l1);
}
The instruction ADD WORD0 l1,r1 is converted to ADD R7,R1 which is a valid CPU instruction. The code generated for the above example is shown below:
0000 E006 MOV R6,#00H 0002 E007 MOV R7,#00H ;---- Variable 'l1' assigned to Register 'R6/R7' ---- 0004 E6F27856 mov r2,#0x5678 0008 E6F13412 mov r1,#0x1234 000C 0071 add word0 l1,r1 000E 0062 add word2 l1,r2
Example 2: Invalid access to a local variable
This example is almost identical to Example 1 except that the C166 Compiler does not assign the variable to a register due to the lack of an initial assignment.
long lFunc (void) {
long l1; // l1 is not assigned to registers
// because no initial value is present
__asm {
mov r2,#0x5678
mov r1,#0x1234
add word0 l1,r1 ; flagged as error
add word2 l1,r2
}
return (l1);
}
In the previous example, word0 l1 translates to [R0] so the resulting instruction is ADD [R0],R1. This operand combination is not a valid 166 instruction. The instruction is marked as erroneous and details can be reviewed in the listing file:
*** add word0 l1,r1 *** ______________^ *** add [Rn+#const],Rn *** ERROR C195 IN LINE 20 OF InlAsm.C: inline-asm: Invalid instruction operand(s)
The following operators are supported by the extended inline assembler:
| Operator | Description |
|---|---|
| % | modulo operator |
| $ | current PC offset (example: JMP cc_sgt,$-2) |
| . | bit position operator |
| , | expression separator |
| # | immediate operand operator |
| : | label operator (example: myLab:) |
| + - * / | arithmetic operators: addition, subtraction, multiplication, division |
| ( ) | expression precedence grouping |
| [ ] | used for indirect register operators (example: [R0+#0x10]) |
| & | ^ ! | binary operators: and, or, xor, not |
| == != <= < >= > |
relational operators: equal, not
equal, less or equal, less than, greater or equal, greater than |
| << >> | shift operators: shift left, shift right |
| PAG | page number operator (example: MOV R5,#PAG iTable) |
| POF | page offset operator (example: MOV R4,#POF iTable) |
| SEG | segment number operator (example: MOV R5,#SEG iTable) |
| SOF | segment offset operator (example: MOV R4,#SOF iTable) |
| SHORT | short type override (example: JMP SHORT myLabel) |
| FAR NEAR | far or near type override (example: CALL FAR Func) |
| BYTE WORD | type override (example: MOV WORD [R1+],#0x12) |
| sizeof | C like sizeof operator (example: MOV R3,#sizeof (pTable) * 2 ) |
| HIGH LOW | high or low byte of word operand (example: MOV RL4,#HIGH (SOF iTable) ) |
| BYTE0 BYTE1 BYTE2 BYTE3 | byte of word or long operand (example: MOV RL4,#BYTE2 iTable) ) |
| WORD0 WORD2 | low or high word of long operand (example: MOV R2,WORD0 xhuge_ptr) |
The access to a high or low word of parameters or local symbols of the data types long, unsigned long, far *, huge *, or xhuge * the WORD0 and WORD2 operators must be used. C166 stores far *, huge *, or xhuge * pointers and long values with low word first, then high word. This word order is also true for long values that are assigned to CPU registers and implies that R(n) is low word and R(n+1) is high word.
The example below shows how to access long values in __asm blocks:
int XpAddUp (int n, int xhuge *pTab) {
__asm {
mov r2,word0 pTab ; get SOF part of xhuge ptr
mov r3,word2 pTab ; get SEG part of xhuge ptr
cmp n,#0 ; count zero ?
jmp cc_sle,stop ; stop if so.
mov r4,#0x0000 ; clear result
lM: exts r3,#1
add r4,[r2] ; add data
add r2,#sizeof (n) ; xptrL + 2
addc r3,#0x00 ; xptrH + 1 + Cy
sub n,#1
jmp cc_nz,lM ; loop if not eot
ret ; return result in R4
}
stop:
return (0);
}
This example generates the following code:
; FUNCTION XpAddUp (BEGIN RMASK = @0x4010)
;---- Variable 'pTab' assigned to Register 'R9/R10' ----
;---- Variable 'n' assigned to Register 'R8' ----
004E F029 mov r2,word0 pTab ; get SOF part of xhuge ptr
0050 F03A mov r3,word2 pTab ; get SEG part of xhuge ptr
0052 4880 cmp n,#0 ; count zero ?
0054 BD08 jmp cc_sle,stop ; stop if so.
0056 E004 mov r4,#0x0000 ; clear result
0058 lM:
0058 DC03 lM: exts r3,#1
005A 084A add r4,[r2] ; add data
005C 0822 add r2,#sizeof (n) ; xptrL + 2
005E 1830 addc r3,#0x00 ; xptrH + 1 + Cy
0060 2881 sub n,#1
0062 3DFA jmp cc_nz,lM ; loop if not eot
0064 CB00 ret ; need result in R4
0066 stop:
0066 E004 MOV R4,#00H
0068 CB00 RET
; FUNCTION XpAddUp (END RMASK = @0x4010)
When using __asm blocks the user should be aware of the following:
__asm {
PUSH R0 ; save R0
...
POP R0 ; restore R0
}
__asm {
PUSH DPP2 ; save DPP2
MOV DPP2,#PAG buffer
...
POP DPP2 ; restore DPP2
}
At Keil Software, we are dedicated to providing you with the best development tools and technical support. That's why we offer numerous ways you can get the technical support you need to complete your embedded projects.
Many of the features of our Technical Support Knowledgebase and Web Site are the results of your suggestions. If you have any ideas that will improve them, please give us your feedback!
If you experience any problems or have any questions about this Application Note, contact one of our distributors or offices for assistance.
|
In the USA... |
In Europe... |
Copyright © Keil Software, Inc. and Keil Elektronik GmbH.
All rights reserved.
Visit our web site at www.keil.com.