Hi all I want to write a program containing a main.c and pmu.h and definition of header file in assembly called pmu.s, i wrote these file in this way: main.c #include <stdio.h> #include "pmu.h" int main(void) { enable_pmu(); // Enable the PMU printf("hello world\n"); return 0; } pmu.h #ifndef _PMU_h #define _PMU_h void enable_pmu(void); #endif pmu.s PRESERVE8 AREA v6_pmu, CODE,READONLY ARM EXPORT enable_pmu enable_pmu PROC MRC p15, 0, r0, c15, c12, 0 ORR r0, r0, #0x01 MCR p15, 0, r0, c15, c12, 0 BX lr ENDP END when i build this program with eclipse and codesourcery i got this error: Description Resource Path Location Type undefined reference to `enable_pmu' main.c /test2 line 7 C/C++ Problem this problem looks simple but i searched a lot about that and i cann't find the problem could you please help me? thanks
Your pmu.s is in ARM assembler format but not in GNU assembler for ARM format. You should rewrite it I have no GNU ARM toolchain installed, but for AVR it would look like: pmu.S
1 | #if 0 |
2 | PRESERVE8 |
3 | AREA v6_pmu, CODE,READONLY |
4 | ARM |
5 | EXPORT enable_pmu |
6 | enable_pmu PROC |
7 | MRC p15, 0, r0, c15, c12, 0 |
8 | ORR r0, r0, #0x01 |
9 | MCR p15, 0, r0, c15, c12, 0 |
10 | BX lr |
11 | ENDP |
12 | END |
13 | #else |
14 | .global enable_pmu |
15 | .type enable_pmu, @function |
16 | enable_pmu: |
17 | ret |
18 | #endif |
File extension is .S (uppercase) in order to indicate that tis is a assembler source file and not an intermediate assembler file from the toolchain (.s in lowercase).
Sorry the last answer is related to "Forum: ARM programming with GCC/GNU tools". For Codesourcery i don't know the assembler syntax.
thanks dear Krapao for your reply, this assemble code was part of a sample code i found in http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka4237.html for using performance monitoring unit of arm 11. i will search for how to rewrite it.
Can anyone help me to rewrite this assemble code to GNU assemble? pmu.s PRESERVE8 AREA v6_pmu, CODE,READONLY ARM EXPORT enable_pmu enable_pmu PROC MRC p15, 0, r0, c15, c12, 0 ORR r0, r0, #0x01 MCR p15, 0, r0, c15, c12, 0 BX lr ENDP END i have changed it in this way: .global enable_pmu enable_pmu: MRC p15, 0, r0, c15, c12, 0 ORR r0, r0, #0x01 MCR p15, 0, r0, c15, c12, 0 BX lr and it builds with no error but when i run it on my board(OK6410 with Linux OS) it says "Illegal Instruction" does anybody have any idea what the problem is? thanks
Now i understand what you try to do. You try to worl with your toolchain, what is called with KEIL ARM toolchain "Compiler support for accessing registers using named register variables" http://www.keil.com/support/man/docs/armcc/armcc_CHDHCIEE.htm In detail you try something like example 6, but for understanding i include example 5 too: [citation] You can also use named register variables to access registers within a coprocessor. The string syntax within the declaration corresponds to how you intend to use the variable. For example, to declare a variable that you intend to use with the MCR instruction, look up the instruction syntax for this instruction and use this syntax when you declare your variable. See Example 5. Example 5. Setting bits in a coprocessor register using a named register variable register unsigned int PMCR __asm(”cp15:0:c9:c12:0”); __inline void __reset_cycle_counter(void) { PMCR = 4; } Disassembly: __reset_cycle_counter PROC MOV r0,#4 MCR p15,#0x0,r0,c9,c12,#0 ; move from r0 to c9 BX lr ENDP In Example 5, PMCR is declared as a register variable of type unsigned int, that is associated with the cp15 coprocessor, with CRn = c9, CRm = c12, opcode1 = 0, and opcode2 = 0 in an MCR or MRC instruction. The MCR encoding in the disassembly corresponds with the register variable declaration. The physical coprocessor register is specified with a combination of the two register numbers, CRn and CRm, and two opcode numbers. This maps to a single physical register. The same principle applies if you want to manipulate individual bits in a register, but you write normal variable arithmetic in C, and the compiler does a read-modify-write of the coprocessor register. See Example 6. Example 6. Manipulating bits in a coprocessor register using a named register variable register unsigned int SCTLR __asm(”cp15:0:c1:c0:0”); /* Set bit 11 of the system control register */ void enable_branch_prediction(void) { SCTLR |= (1 << 11); } Disassembly: __enable_branch_prediction PROC MRC p15,#0x0,r0,c1,c0,#0 ORR r0,r0,#0x800 MCR p15,#0x0,r0,c1,c0,#0 BX lr ENDP [/citation] Unfortuantely i can not check your link in detail. [citation] Basic example code used to be available as a download from the ARM website. An improved version is now shipped as part of DS-5 (from version 5.8 onwards). Within the DS-5 Bare-metal example package, the code is included as part of the "optimization3" example. [/citation] I don't find "Basic example code" and DS-5 website is currenty down. Questions: 1/ Is enable_pmu allowed on OK6410 with Linux OS? The code from your first post would work on your board when translated with KEIL? 2/ Is r0 a register you can use in GNU toolchain freely? The code before and after the call to enable_pmu doesn't depend on r0? 4/ Did you check whether GNU toolchain allows "named registers" too, so you can write enable_pmu in C only instead in KEIL-Disassembly-transferred-in-GNU-Assembly-linked-with-GNU-C?
Add: GNU GCC doc may help esp. http://gcc.gnu.org/onlinedocs/gcc/Explicit-Reg-Vars.html#Explicit-Reg-Vars
>... >AREA v6_pmu, CODE,READONLY >... See AREA in the Realview Assembler documentation in ARM's infocenter and the about the SECTION-instruction in the GNU Manuals (GNU-Assembler, GNU-Linker part of the binutils). You may also have to check the scatter-load file in the example from ARM and modify your linker-script to reflect the functionality. It seems the instructions for the procedure are expected at a special memory-location. It's difficult to help without a minimal but complete example.
Hi Krapao, I attached Performance Monitor Unit example code for ARM11 and Cortex-A/R , that I found on http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka4237.html 1/ Is enable_pmu allowed on OK6410 with Linux OS? The code from your first post would work on your board when translated with KEIL? I will appreciate if I could run these samples on OK6410 with Linux OS and it’s my goal now. But I don’t know whether its possible or not. I didn’t test translating with KEIL, if I’m right KEIL is used for bare-metal devices and does not support GNU assemblers!?!? 4/ Did you check whether GNU toolchain allows "named registers" too, so you can write enable_pmu in C only instead in KEIL-Disassembly-transferred-in-GNU-Assembly-linked-with-GNU-C? Based on your advice I wrote a test program for named register variables, my test program was: #include <stdio.h> int main(void) { register unsigned int APSR __asm("apsr"); APSR = ~(~APSR | 0x40); register unsigned int SCTLR __asm("cp15:0:c1:c0:0"); void enable_branch_prediction(void) { SCTLR |= (1 << 11); } register unsigned int PMCR __asm("cp15:0:c9:c12:0"); __inline void __reset_cycle_counter(void) { PMCR = 4; } register unsigned int cp15_control __asm("cp15:0:c1:c0:0"); cp15_control |= 0x1; printf("Before call function\n"); enable_branch_prediction(); __reset_cycle_counter(); printf("after call function\n"); return 0; } I used Eclipse IDE for C/C++ Developers(Indigo Service Release 1) and Sorcery Codebench lite(arm-2011.09-70-arm-none-linux-gnueabi) But there are some build errors: invalid register name for 'apsr' invalid register name for 'APSR' invalid register name for 'cp15_control' invalid register name for 'PMCR' invalid register name for 'SCTLR' make: *** [main.o] Error 1 do you think these errors says that GNU toolchain doesn’t allows "named registers"?
dear mthomas thanks for reply, unfortunately I can’t get your main idea, could you please clarify your purpose with the steps that I should done. When you want to write a program for a device that has OS (same as my board that has linux), is it possible for you to manage the memory location that your program runs or operating system got the management? In my case I only want to config performance monitoring registers of ARM1176jzf-s processor with c and assembly programs that runs on linux OS. thanks
In your case (OK6410 AND GNU toolchain AND coprocessor use) you are about to enter a unknown continent. You are amoung the first maybe this very first explorer of this new land. Your tools are the description of the GNU tools and your processor manual and the way others took with KEIL toolchain. > In my case I only want to config performance monitoring registers of > ARM1176jzf-s processor with c and assembly programs that runs on linux > OS. > if I’m right KEIL is used for bare-metal devices Then... In Linux access to some registers is possible only in privileged modes. "Bare-metal" access like in the KEIL examples is not possible. So you have to throw away "maps" from KEIL explorers and you have to find another way... Under Linux there can be a special v6 PMU driver together with a Performance Events library (perfevents). Does your Linux on OK6410 has this library enabled? If yes then look i the source and examples for this library. I'll stop here, because this is way to far away for me from initial question. I'm guessing only and can't give much input now.
dear Krapao thanks for your advices and hints, it was so useful for me! ;-)
Please log in before posting. Registration is free and takes only a minute.
Existing account
Do you have a Google/GoogleMail account? No registration required!
Log in with Google account
Log in with Google account
No account? Register here.