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.