Download Pragma Preprocessor Directives

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
Other Features
Pragma Preprocessor Directives
1. Introduction
This document explores the extended pragma directives supported by the NC30 compiler.
2. MAP the variable to the ROM section #pragma ROM
Syntax: #pragma ROM variable_name
As shown in the example below, before using #pragma ROM directive, the variable cResult is stored in
data memory. But, after using the #pragma ROM directive, the variable cResult is stored in the ROM data
area.
Code before using #pragma ROM1
Code after using #pragma ROM1
char cResult = 5;
void main(void){
F0012 7CF201 _main ENTER #01H
char cLocal;
if(cResult == 5)
F0015 7480000001 LDE.B 10000H,R0L
F001A E405
CMP.B #05H,R0L
F001C CE01FF
STZ #01H,-1H[FB]
cLocal = 1;
}
F001F 7DF2
EXITD
#pragma ROM cResult
char cResult = 5;
void main(void){
F0012 7CF201 _main ENTER #01H
char cLocal;
if(cResult == 5)
F0015 748000000F LDE.B F0000H,R0L
F001A E405
CMP.B #05H,R0L
F001C CE01FF
STZ #01H,-1H[FB]
cLocal = 1;
}
F001F 7DF2
EXITD
Example 1 Map the Variable to the ROM Section
*1–Code modification option [-fFRAM] is enabled in the example.
Note:
The #pragma ROM definition is effective for static and non-extern global variables. As shown in the
example below, the compiler does not map the non-static variable cResult to the ROM.
Code with #pragma ROM on static data
Code with #pragma ROM on non static data
#pragma ROM cResult
#pragma ROM cResult
void main(void){
void main(void){
F0012 7CF201 _main ENTER #01H
F0010 7CF202 _main ENTER #02H
static char cResult = 5;
char cResult = 5;
F0013 C605FF MOV.B #05H,-1H[FB]
char cLocal;
char cLocal;
if(cResult == 5)
if(cResult == 5)
F0015 748000000F LDE.B F0000H,R0L
F001A E405
CMP.B #05H,R0L
F0016 E605FF CMP.B #05H,-1H[FB]
F001C CE01FF
STZ #01H,-1H[FB] F0019 CE01FE STZ #01H,-2H[FB]
cLocal = 1;
cLocal = 1;
}
}
F001F 7DF2
EXITD
F001C 7DF2
EXITD
Example 2 Map Static and Non-extern Variable to ROM Section
3. MAP the variable to SB Data section #pragma SBDATA
Syntax: #pragma SBDATA variable_name
As shown in the example below, before using #pragma SBDATA, the compiler generates code to fetch the
variable ucData from the data memory. But, after using #pragma SBDATA, the compiler generates code to
fetch the variable ucData from SB data section using SB relative addressing mode.
1
V1.03
Before using SB Addressing mode (5 Bytes)
After using SB Addressing mode (4 Bytes)
unsigned char ucData;
void main(void){
ucData = 10;
F0010 C70A1C04 _main
MOV.B #0AH,041CH
}
F0014 F3
RTS
#pragma SBDATA ucData
unsigned char ucData;
void main(void){
ucData = 10;
F0010 C50A00 _main
MOV.B #0AH,00H[SB]
}
F0013 F3
RTS
Example 3 Storing the Variable Into SB Section
4. Inhibits the packing of structure #pragma STRUCT
Syntax: #pragma STRUCT struct_tag unpack: Add padding at the end of the structure to make the
structure size even.
#pragma STRUCT struct_tag arrange: Arrange structure in descending order of size.
As shown in the example below, before using #pragma STRUCT directive, the compiler allocates memory
to the structure sBuffer in order of declaration of its elements and, the size of the structure is 9 bytes.
However, after using the #pragma STRUCT unpack/arrange directives, the compiler allocates memory in a
manner, such that, even sized elements are allocated first, and, the compiler pads 1 byte at the end of the
structure to make the structure size even i.e. 10 bytes.
Code before using #pragma STRUCT
Code after using #pragma STRUCT
struct sBuffer {
int iWByte;
char cMSByte1;
int iLSByte1;
long iDWByte;
} ;
struct sBuffer sB1;
void main(void){
F0010 7CF201 _main ENTER #01H
unsigned char cStructSize;
cStructSize = sizeof(sB1);
F0013 C609FF MOV.B #09H,-1H[FB]
sB1.iWByte = 900;
F0016 75CF1C048403
MOV.W #0384H,041CH
sB1.cMSByte1 = 20;
F001C C7141E04 MOV.B #14H,041EH
sB1.iLSByte1 = 30;
F0020 75CF1F041E00
MOV.W #001EH,041FH
sB1.iDWByte = 5000;
F0026 75CF21048813
MOV.W #1388H,0421H
F002C D90F2304 MOV.W #0H,0423H
}
F0030 7DF2
EXITD
#pragma STRUCT sBuffer unpack
#pragma STRUCT sBuffer arrange
struct sBuffer {
int iWByte;
char cMSByte1;
int iLSByte1;
long iDWByte;
};
struct sBuffer sB1;
void main(void){
F0010 7CF201 _main ENTER #01H
unsigned char cStructSize;
cStructSize = sizeof(sB1);
F0013 C60AFF MOV.B #0AH,-1H[FB]
sB1.iWByte = 900;
F0016 75CF10048403
MOV.W #0384H,0410H
sB1.cMSByte1 = 20;
F001C C7141804
MOV.B #14H,0418H
sB1.iLSByte1 = 30;
F0020 75CF12041E00
MOV.W #001EH,0412H
sB1.iDWByte = 5000;
F0026 75CF14048813
MOV.W #1388H,0414H
F002C D90F1604 MOV.W #0H,0416H
}
F0030 7DF2
EXITD
Example 4 Structure Padding and Packing
Note:
The #pragma STRUCT definition is ineffective for the structure defined using typedef. As shown in the
example below, the compiler will not perform the padding and packing on structure members.
2
V1.03
#pragma STRUCT sBuffer unpack
#pragma STRUCT sBuffer arrange
typedef struct{
int iWByte;
char cMSByte1;
int iLSByte1;
long iDWByte;
} sBuffer;
sBuffer sB1;
void main(void){
F0010 7CF201
_main ENTER #01H
unsigned char cStructSize;
cStructSize = sizeof(sB1);
F0013 C609FF
MOV.B #09H,-1H[FB]
sB1.iWByte = 900;
F0016 75CF1C048403 MOV.W #0384H,041CH
sB1.cMSByte1 = 20;
F001C C7141E04
MOV.B #14H,041EH
sB1.iLSByte1 = 30;
F0020 75CF1F041E00 MOV.W #001EH,041FH
sB1.iDWByte = 5000;
F0026 75CF21048813 MOV.W #1388H,0421H
F002C D90F2304
MOV.W #0H,0423H
}
F0030 7DF2
EXITD
Example 5 Exception in #pragma struct
5. Specify the absolute address of the variable #pragma ADDRESS
Syntax: #pragma ADDRESS variable_name absolute_address
The variable defined with #pragma ADDRESS is treated as a volatile variable.
As shown in the example below, before using #pragma ADDRESS directive, the compiler allocates the
address to cIOPort variable. However, after defining the variable with #pragma ADDRESS directive, the
compiler allocates absolute address specified in #pragma ADDRESS to the variable cIOPort.
Code before using #pragma ADDRESS
Code after using #pragma ADDRESS
char cIOPort;
void main(void){
cIOPort = 0x02;
F0010 C7021C04 _main
MOV.B #02H,041CH
}
F0014 F3
RTS
#pragma ADDRESS cIOPort 24H
char cIOPort;
void main(void){
cIOPort = 0x02;
F0010 C7022400 _main
MOV.B #02H,0024H
}
F0014 F3 RTS
Example 6 Assigning the Address to a Variable
Note:
The #pragma ADDRESS is valid only for the variable declared outside the function. As shown in the
example below, the cIOPort variable is declared inside the function. Therefore, the compiler does not
assign an address 20h to the cIOPort variable.
#pragma ADDRESS cIOPort 20h
void main(void){
static char cIOPort;
cIOPort = 0x02;
F0010 C7021C04 _main MOV.B #02H,041CH
}
F0014 F3
RTS
Example 7 Exception in #pragma ADDRESS
3
V1.03
6. Assign the bit position to the variable #pragma BITADDRESS
Syntax: #pragma BITADDRESS variable_name bit_position, absolute_address
The _Bool variable defined with #pragma BITADDRESS is assigned to the specified bit position within the
absolute address.
In the example below, a _Bool variable IO is assigned to the bit position 1, in absolute address 100h using
#pragma BITADDRESS. Hence, the compiler uses a bit set instruction to set the bit in the absolute address.
_Bool IO;
#pragma BITADDRESS IO 1,100h
void main(void){
IO = 5;
F0010 7E9F0108 _main
BSET 1,0100H
}
F0014 F3
RTS
Example 8 Assigning the Bit Position to a Variable
Note:
#pragma BITADDRESS can only be assigned to _Bool type variables. If IO variable in Example 8 is an
unsigned char type, then the compiler will generate an error “[Error (ccom)] #pragma BITADDRESS
variable is not _Bool type”.
7. Declares the function called by software interrupt #pragma INTCALL
Syntax: #pragma INTCALL INT-No. C-function-name() – call the function using the INT instruction.
In the example mentioned below, before using #pragma INTCALL, the compiler calls the function c_func( )
using JSR.W instruction. However, after defining the function using #pragma INTCALL, the compiler calls
the function using an INT instruction.
Code before using #pragma INTCALL
Code after using #pragma INTCALL
char c_func(char);
void main(void){
c_func(1);
F0010 D812
_main MOV.B #1H,R1L
F0012 F50300 JSR.W $c_func F0016H
}
F0015 F3
RTS
char c_func(char cFlag)
{
F0016 7CF201 $c_func ENTER #01H
F0019 722BFF MOV.B R1L,-1H[FB]
return (cFlag);
F001C 0AFF
MOV.B -1H[FB],R0L
F001E 7DF2
EXITD
}
char c_func(char);
#pragma INTCALL 20 c_func();
void main(void){
c_func(1);
F0010 D812 _main MOV.B #1H,R1L
F0012 EBD4
INT
#20
}
F0014 F3
RTS
F0015 04
NOP
char c_func(char cFlag){
F0016 7CF201 $c_func ENTER #01H
F0019 722BFF MOV.B R1L,-1H[FB]
return (cFlag);
F001C 0AFF
MOV.B -1H[FB],R0L
F001E 7BF5
STC
FB,A1
F0020 7AD5
LDC
A1,SP
F0022 ED80
POPM FB
F0024 FB
REIT
}
Example 9 Defining Software Interrupt
Note:
The INT-no in #pragma INTCALL INT-no function_name cannot be greater than 63. If the interrupt
vector number in the above example is greater than 63, then the compiler generates an error message
compiling: “[Error(ccom)] Invalid #pragma INTCALL interrupt number”.
8. Declares a hardware interrupt handler #pragma INTERRUPT
Syntax:
4
V1.03
#pragma INTERRUPT interrupt_handler_name(vect=Vector_no) – define the interrupt handler with a
vector number.
#pragma INTERRUPT /B interrupt_handler_name (vect=Vect_no) - define the interrupt handler with a
vector number. Do not push the register onto the stack. Use a different set of registers in the ISR.
#pragma INTERRUPT /E interrupt_handler_name (vect=Vect_no) - define the interrupt handler with a
vector number. Enable multiple interrupts within the ISR.
In the example below, when the function timerA() is defined using #pragma INTERRUPT /B, the compiler
considers that function as an ISR and uses a different set of registers in processing the interrupt routine.
However, if the function timerA() is defined using only #pragma INTERRUPT, then the compiler pushes the
CPU registers onto the stack before processing the ISR which increases the interrupt latency. Interrupt
nesting is not possible in an interrupt that uses the /B directive.
Code with #pragma INTERRUPT
Code with #pragma INTERRUPT /B
int iCounter;
#pragma INTERRUPT timerA()
int iCounter;
#pragma INTERRUPT /B timerA()
void timerA(void){
void timerA(void){
F0010 ECFD _timerA
F0010 EB44 _timerA FSET B
PUSHM R0,R1,R2,R3,A0,A1,FB
iCounter += 1;
iCounter += 1;
F0012 C91F1004 ADD.W #1H,0410H
F0012 C91F1004 ADD.W #1H,0410H
}
}
F0016 FB
REIT
F0016 EDBF
F0017 04
NOP
POPM R0,R1,R2,R3,A0,A1,FB
void main(){
F0018 FB
REIT
iCounter = 0;
F0019 04
NOP
F0018 D90F1004 _main
void main(){
MOV.W #0H,0410H
iCounter = 0;
}
F001A D90F1004 _main
F001C F3
RTS
MOV.W #0H,0410H
}
F001E F3
RTS
Example 10 Declaring an ISR Using #pragma INTERRUPT /B
As shown in the example below, the function timerA() is defined using #pragma INTERRUPT /E. Hence, the
compiler enables the global interrupt flag using the FSET I instruction in the interrupt processing function,
that allows nested interrupt processing.
int iCounter;
#pragma INTERRUPT /E timerA()
void timerA(void){
F0010 EB64 _timerA FSET I
F0012 04
NOP
F0013 ECFD PUSHM R0,R1,R2,R3,A0,A1,FB
iCounter += 1;
F0015 C91F1004 ADD.W #1H,0410H
}
F0019 EDBF
POPM R0,R1,R2,R3,A0,A1,FB
F001B FB
REIT
void main(){
iCounter = 0;
F001C D90F1004 _main MOV.W #0H,0410H
}
F0020 F3
RTS
Example 11 Declaring ISR Using #pragma INTERRUPT /E
9. Use special page vector table to call the function
Syntax: #pragma SPECIAL number C-function-name() – stores the starting address of a function in a special
page vector table and calls the function using the JSRS instruction.
5
V1.03
As shown in the example below, the Function() is defined with #pragma SPECIAL. Hence, the compiler
stores the starting address of Function() in a special page vector table and uses JSRS instruction to call the
Function().
#pragma SPECIAL 25 Function()
int Function(int ,int );
void main(void){
F0010 7CF202
_main ENTER #02H
int i,j;
char cRetValue;
cRetValue = Function(i,j);
F0013 73B2FE MOV.W -2H[FB],R2
F0016 73B1FE MOV.W -2H[FB],R1
F0019 EF19
JSRS #25
F001B 02FE
MOV.B R0L,-2H[FB]
}
F001D 7DF2
EXITD
int Function(int i,int j){
F07E6 7CF204 __SPECIA ENTER #04H
F07E9 731BFE MOV.W R1,-2H[FB]
F07EC 732BFC MOV.W R2,-4H[FB]
return(i & j);
F07EF 73B0FE MOV.W -2H[FB],R0
F07F2 91B0FC AND.W -4H[FB],R0
F07F5 7DF2
EXITD
}
Example 12 Function Call Using Special Page Vector Table #pragma SPECIAL
Note:
The number in “#pragma SPECIAL number function_name” cannot be greater than 255. If the number
in Example 12 is greater than 255 then the compiler will generate an error message: “[Error(ccom)] Invalid
#pragma SPECIAL special page number”.
10. Declare and define a function by assembler macro #pragma __ASMMACRO
Syntax: #pragma __ASMMACRO function-name (arg1 = register name, …)
The compiler replaces the call to the assembler macro function with assembly language code. The
following rules define the assembler macro function in the application code.
Write the prototype declaration of assembler function before #pragma.
The storage class of assembler macro function must be static. Else, the compiler will generate an error
during compilation.
As shown in Example 13, define the assembler macro function using assembler directive .macro. The
function name must be preceded by an underbar ( _ ).
Pass the arguments to assembler macro function using appropriately sized CPU registers.
Use CPU registers shown in the table below for returning a value from an assembler macro function.
Type of Return Value
_Bool
Char
int
near pointer
float
long
far pointer
Rules
R0L Register
R0 Register
Least significant 16 bits returned by storing in R0 register.
Most significant 16 bits returned by storing in R2 register.
double
long double
Values are stored in 16 bits beginning with the high-order
bits sequentially in order of registers R3, R2, R1, and R0 as
they are returned.
Structure Type
Union Type
Do not use the structure and union for returning the values.
6
V1.03
As shown in the example below, the mul() is defined as an assembler macro function using #pragma
__ASMMACRO. Therefore, the compiler replaces mul() with an assembly code.
static long mul( int, int );
#pragma __ASMMACRO mul( R0, R2 )
#pragma ASM
_mul .macro
mul.w R2,R0
endm
#pragma ENDASM
void main( void ){
F0010 7CF204 _main ENTER
#04H
long lOperand;
lOperand = mul( 2, 3 );
F0013 D932
MOV.W #3H,R2
F0015 D920
MOV.W #2H,R0
F0017 7920
MUL.W R2,R0
F0019 730BFC MOV.W R0,-4H[FB]
F001C 732BFE MOV.W R2,-2H[FB]
}
F001F 7DF2
EXITD
Example 13 Calling an Assembler Macro Function From C Code
11. Specify assembly code in C #pragma ASM and #pragma ENDASM
Syntax: #pragma ASM
//Assembly statements
#pragma ENDASM
As shown in the example below, assembly code can be included in C code using #pragma ASM and
#pragma ENDASM directives.
void main(){
#pragma ASM
mov.w #00001H,R0
F001A D910 _main MOV.W #1H,R0
#pragma ENDASM
}
F001C F3
RTS
Example 14
Writing C Code Into Assembly Code
12. Call the function using the JSRA and JSRW instructions #pragma JSRA and #pragma JSRW
Syntax: #pragma JSRA function name – Call the function using JSR.A instruction
#pragma JSRW function name – Call the function using JSR.W instruction
Normally, the compiler calls the external function using JSR.A instruction. This results in an increase in
code size and decrease in execution speed. Therefore, as shown in Example 15, use #pragma JSRW
directive to make the compiler call the external function using JSR.W instruction.
The #pragma JSRA directive is useful when the code modification option [-fJSRW] is enabled. With the [fJSRW] option enabled, the compiler calls all functions using JSR.W instruction. However, if the body of
the function is located outside the range of JSR.W instruction, then an error occurs when compiling, that
can only be resolved by calling the function using JSR.A instruction.
void SemaphoreCapture();
void SemaphoreRelease();
#pragma JSRA SemaphoreCapture();
#pragma JSRW SemaphoreRelease();
void main(void){
SemaphoreCapture();
F0010 FD18000F _main
JSR.A _Semapho F0018H
SemaphoreRelease();
7
V1.03
F0014 F50D00
}
F0017 F3
JSR.W _Semapho F0022H
RTS
Calling the Functions using JSRA and JSRW instructions
Example 15
Note:
If the function defined with #pragma JSRW or #pragma JSRA is called indirectly (i.e. using the function
pointer), then pragma definition becomes ineffective. As shown in example below, the compiler calls
#pragma JSRW defined function pfunc() using JSRI.A instruction.
void SemaphoreRelease();
char cSemaphore;
#pragma JSRW SemaphoreRelease();
void (*pfunc)();
void main(void){
pfunc = SemaphoreRelease;
F0010 75CF10042400
_main MOV.W #0024H,0410H
F0016 75CF12040F00
MOV.W #000FH,0412H
SemaphoreRelease();
F001C F50700
JSR.W _Semapho F0024H
pfunc();
F001F 7D1F1004
JSRI.A 0410H
}
Example 16 Calling #pragma JSRW Specified Function Using Function Pointer
13. Reference
For more details, please refer to the Compiler User Manual (nc30ue.pdf).
8
V1.03
Revision History
Ver.
No.
Date
1.01
2007/08/0
7
1.02
1.03
2007/08/3
0
2008/01/10
Section No.
Changes
Reason for Changes
2,3,4,5,6,7,8,9,10,
11,12
Format and grammar
RTA and RSO comments
7,8,9
Change in variable names and
function names
KPIT review comments
2,3,4,5,6,7,8,9,10,
11
7
8
Format and grammar
Format and grammar.
KPIT review comments
RTA review
Included additional line “Interrupt
nesting is not possible in an interrupt
that uses the /B directive.”
Corrected section numbering
9
V1.03
Related documents