Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
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