I'm currently trying to use the event counters on an ARM Cortex-a9 (on a Xilinx zynq EPP) to count cycles. I've adapted some ARM example code from ARM for this purpose. I'm programming this bare-metal with the GNU ARM EABI compiler.
The way I understand the use of the PMU is that you first have to enable the PMU.
void enable_pmu (void){
asm volatile( "MRC p15, 0, r0, c9, c12, 0\n\t"
"ORR r0, r0, #0x01\n\t"
"MCR p15, 0, r0, c9, c12, 0\n\t"
);
}
then you configure the performance counter to count a certain type of event (0x11 for cycles in this case)
void config_pmn(unsigned counter,int event){
asm volatile( "AND %[counter], %[counter], #0x1F\n\t" :: [counter] "r" (counter)); //Mask to leave only bits 4:0
asm volatile( "MCR p15, 0, %[counter], c9, c12, 5\n\t" :: [counter] "r" (counter)); //Write PMSELR Register
asm volatile( "ISB\n\t"); //Synchronize context
asm volatile( "MCR p15, 0, %[event], c9, c13, 1\n\t" :: [event] "r" (counter)); //Write PMXEVTYPER Register
}
Then you enable the event counter
void enable_pmn(int counter){
asm volatile( "MOV r1, #0x1\n\t");
asm volatile( "MOV r1, r1, LSL %[counter]\n\t" :: [counter] "r" (counter));
asm volatile( "MCR p15, 0, r1, c9, c12, 1\n\t"); //Write PMCNTENSET Register
}
after this you immediately reset the event counter
void reset_pmn(void){
asm volatile( "MRC p15, 0, r0, c9, c12, 0\n\t"); //Read PMCR
asm volatile( "ORR r0, r0, #0x2\n\t"); //Set P bit (Event counter reset)
asm volatile( "MCR p15, 0, r0, c9, c12, 0\n\t"); //Write PMCR
}
you let your application run and read the event counter
int read_pmn(int counter){
int value;
asm volatile( "AND %0,%0, #0x1F\n\t" :: "r" (counter)); //Mask to leave only bits 4:0
asm volatile( "MCR p15, 0, %[counter], c9, c12, 5\n\t" ::[counter] "r" (counter)); //Write PMSELR Register
asm volatile( "ISB\n\t"); //Synchronize context
asm volatile( "MRC p15, 0,%[value] , c9, c13, 2\n\t" : [value] "=r" (value)); //Read current PMNx Register
return value;
}
and then you disable the event counter
void disable_pmn(int counter){
asm volatile( "MOV r1, #0x1\n\t");
asm volatile( "MOV r1, r1, LSL %[counter] \n\t":: [counter] "r" (counter));
asm volatile( "MCR p15, 0, r1, c9, c12, 2\n\t"); //Write PMCNTENCLR Register
}
and the pmu.
void disable_pmu (void){
asm volatile( "MRC p15, 0, r0, c9, c12, 0\n\t"
"BIC r0, r0, #0x01\n\t"
"MCR p15, 0, r0, c9, c12, 0\n\t"
);
}
However when I try to read the value stored in the event counter I get 0. I know my PMU is configured correctly because I'm able to read the cycle counter (PMCCNTR) without a problem. Probably there is a problem with the way I configure the counter or the way I read it. This inline assembly stuff is pretty new to me so if somebody can point me in the right direction I would be forever grateful.
MCR/MRCparameters. - artless noisecounter, but don't annotate this. Also, you are using a hard-codedr0,r1, but didn't specify this. You can group multiple asm op-codes in the sameasmstatement. Just use a\n; you don't need to specify the parameters so many times then, but get them right. Also A8 A8-2 - artless noise