cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Visitor
Visitor
606 Views
Registered: ‎05-11-2020

Enabling Event Counter to read L2D_Cache and other events

Jump to solution

Hi! 

I'm trying to enable some event counters to monitor L2D_Cache (0x16), L2D_Cache_Refill (0x17),  and L2D_Cache_WB(0x18). So far I was able to enable the event counters by writing 0x11 to the PMCR register (0x00003E04). I know I need to set the event type to monitor those events and I think I need to do that with PMCEID0 (0x00003E04) but I'm not sure. 

My code is very basic right now, all I have is: 

void enable_cache(){
	Xil_Out32(PMCR,0x00000011);//Enables all counters and exports of events are enable
	Xil_Out32(PMCEID0 + L2D_CACHE, 0xFFFFFFFF); //TODO: Make sure this is correct. I want to set it to monitor that




	//enable counter
	//set what they are counting
}

 But I'm not super confident that I have it correct. I have PMCR, PMCEID0, and L2D_CACHE defined in a header file to the values I mentioned previously. 

Would someone be able to tell me if I'm on the correct path? I've been using https://developer.arm.com/documentation/ddi0500/d/performance-monitor-unit/memory-mapped-register-summary?lang=en

and 

https://www.xilinx.com/html_docs/registers/ug1087/ug1087-zynq-ultrascale-registers.html

For the registers and addresses. 

I'm writing this for a ZCU106 Ultrascale+ board. 

Thanks in advance! 

Tags (2)
0 Kudos
Reply
1 Solution

Accepted Solutions
Visitor
Visitor
427 Views
Registered: ‎05-11-2020

I have figured out my problems with this question. 

For anyone who finds this forum later the general format, you need to follow are as follow: 

1) In the LAR register: write 0xFEC30FB0 to it (it will unlock writing to the registers). One thing I noticed is once it was unlocked it stayed unlocked. To know if yours is unlocked read from 0xFEC30FB4 and if it's 0x1 it's unlocked. 

2) In the CR_EL0 register read modify it. Or what you read it with 0x1. This will enable the counters. Write to CR_EL0 with that new value.

3) Read from EVTYPERN_EL0 (where N is the counter you're modifying).

4) Modify what you read by ANDing it with 0xFFFFFB00 (this will help you modify only the bottom 8 bits).

5) After you AND it OR that value with the EventID that you want to monitor (List can be found here: https://developer.arm.com/documentation/ddi0500/d/performance-monitor-unit/events?lang=en

6)  write that value back to EVTYPERN_EL0

7) repeat steps 3-6 for all counters you're using

Read from CNTENSET_EL0 

9) OR that value with however many counters you're using and write it back to CNTENSET_ELO.

10) Read from CR_EL0 again

11) OR that value with 0x2 and write it back to CR_EL0. This will clear all the counters. 

At this point, the counters will be enabled and monitoring the events. To read from the register do the following:

1) If you're done monitoring those events read from CNTENCLR_EL0 

2) OR that value with the same value you wrote to CNTENSET_EL0 and write that value to CNTENCLR_EL0

3) read from EVCNTRN_EL0 where N is the counter that you want to read. This is your result

if you don't want to disable the counter just do step 3

 

There's a possibility that you don't have to do all these steps but this is what worked for me. 

View solution in original post

3 Replies
Visitor
Visitor
516 Views
Registered: ‎05-11-2020

An update: I know this isn't correct at all now. All I was doing was setting the address and reading it. I found the type register but can't find the address for some reason. I know I need the type register so I can tell it what to monitor, but still confused on how to do everything. 

0 Kudos
Reply
Visitor
Visitor
449 Views
Registered: ‎05-11-2020

Another update and new problem. I found that I was using the wrong addresses. I should've been using absolute values as well as I should've been using all from the same "group". I was mixing from SMMU500 and A53_PMU_0, I should've just been using A53_PMU_0. So I changed that. My new problem is that it doesn't seem to be writing to the registers. 

 

void enable_cache(){
	uint32_t EVENT =0;
	uint32_t PMCR = Xil_In32(CR_ELO);
	printf("CR_ELO read: 0x%x\n",PMCR);
	printf("CR_ELO OR: 0x%x\n",(PMCR | 0x00000001));
	PMCR |= 0x00000001;
	Xil_Out32(CR_ELO, PMCR );//Enables all counters
	sleep(5);
	printf("CR_ELO Read after write: 0x%x\n",Xil_In32(CR_ELO));


	EVENT = Xil_In32(EVTYPER0_EL0);
	printf("EVTYPER0_EL0 read: 0x%x\n",EVENT);
	EVENT &= 0xFFFFFB00;
	printf("EVTYPER0_EL0 AND: 0x%x\n",EVENT);
	EVENT |= L2D_CACHE;
	printf("EVTYPER0_EL0 OR: 0x%x\n",EVENT);
	EVENT |= 0x50000000;
	printf("EVTYPER0_EL0 OR # 2: 0x%x\n",EVENT);
	Xil_Out32(EVTYPER0_EL0, EVENT);
	sleep(1); //sleep for 1 second
	printf("EVTYPER0_EL0 read after write: 0x%x\n",Xil_In32(EVTYPER0_EL0));


	printf("CR_ELO read: 0x%x\n",Xil_In32(CR_ELO));
	printf("CR_ELO OR (for clear): 0x%x\n",(Xil_In32(CR_ELO) | 0x00000010));
	Xil_Out32(CR_ELO,Xil_In32(CR_ELO) | 0x00000010);//Enables all counters
	printf("CR_ELO Read after write (for clear): 0x%x\n",Xil_In32(CR_ELO));
//	printf("Event Counter: 0x%x\n",Xil_In32(PMEVCNTR0));

}

 

The code above outputs: 

CR_ELO read: 0x0
CR_ELO OR: 0x1
CR_ELO Read after write: 0x0
EVTYPER0_EL0 read: 0x0
EVTYPER0_EL0 AND: 0x0
EVTYPER0_EL0 OR: 0x16
EVTYPER0_EL0 OR # 2: 0x50000016
EVTYPER0_EL0 read after write: 0x0
CR_ELO read: 0x0
CR_ELO OR (for clear): 0x10
CR_ELO Read after write (for clear): 0x0

 

My problem comes from the "CR_EL0 Read after write: 0x0" that shouldn't be that and I can't figure out why. 

As you can see in the code I put "sleep(5)" in case it needs some time to set everything. 

That didn't work either. 

I'm stuck on that problem does anyone know why? 

Thanks!  

 

0 Kudos
Reply
Visitor
Visitor
428 Views
Registered: ‎05-11-2020

I have figured out my problems with this question. 

For anyone who finds this forum later the general format, you need to follow are as follow: 

1) In the LAR register: write 0xFEC30FB0 to it (it will unlock writing to the registers). One thing I noticed is once it was unlocked it stayed unlocked. To know if yours is unlocked read from 0xFEC30FB4 and if it's 0x1 it's unlocked. 

2) In the CR_EL0 register read modify it. Or what you read it with 0x1. This will enable the counters. Write to CR_EL0 with that new value.

3) Read from EVTYPERN_EL0 (where N is the counter you're modifying).

4) Modify what you read by ANDing it with 0xFFFFFB00 (this will help you modify only the bottom 8 bits).

5) After you AND it OR that value with the EventID that you want to monitor (List can be found here: https://developer.arm.com/documentation/ddi0500/d/performance-monitor-unit/events?lang=en

6)  write that value back to EVTYPERN_EL0

7) repeat steps 3-6 for all counters you're using

Read from CNTENSET_EL0 

9) OR that value with however many counters you're using and write it back to CNTENSET_ELO.

10) Read from CR_EL0 again

11) OR that value with 0x2 and write it back to CR_EL0. This will clear all the counters. 

At this point, the counters will be enabled and monitoring the events. To read from the register do the following:

1) If you're done monitoring those events read from CNTENCLR_EL0 

2) OR that value with the same value you wrote to CNTENSET_EL0 and write that value to CNTENCLR_EL0

3) read from EVCNTRN_EL0 where N is the counter that you want to read. This is your result

if you don't want to disable the counter just do step 3

 

There's a possibility that you don't have to do all these steps but this is what worked for me. 

View solution in original post