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).
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?
>...>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.