ARM Cortex-a9事件计数器返回0
我目前正在尝试使用Xilinx zynq EPP上ARM Cortex-a9上的事件计数器来计算周期。为此,我改编了一些来自ARM的ARM示例代码。我正在用GNU ARM EABI编译器对这个裸机进行编程 我对PMU使用的理解是,首先必须启用PMUARM Cortex-a9事件计数器返回0,arm,inline-assembly,performancecounter,Arm,Inline Assembly,Performancecounter,我目前正在尝试使用Xilinx zynq EPP上ARM Cortex-a9上的事件计数器来计算周期。为此,我改编了一些来自ARM的ARM示例代码。我正在用GNU ARM EABI编译器对这个裸机进行编程 我对PMU使用的理解是,首先必须启用PMU void enable_pmu (void){ asm volatile( "MRC p15, 0, r0, c9, c12, 0\n\t" "ORR r0, r0, #0x01\n
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"
);
}
然后将性能计数器配置为在此情况下对特定类型的事件0x11进行周期计数
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
}
然后启用事件计数器
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
}
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
}
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;
}
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
}
之后,立即重置事件计数器
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
}
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
}
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;
}
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
}
让应用程序运行并读取事件计数器
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
}
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
}
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;
}
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
}
然后禁用事件计数器
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
}
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
}
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;
}
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
}
还有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"
);
}
但是,当我尝试读取存储在事件计数器中的值时,得到0。我知道我的PMU配置正确,因为我能够毫无问题地读取周期计数器PMCCNTR。我配置计数器的方式或读取计数器的方式可能有问题。这种内联汇编对我来说是非常新的东西,因此如果有人能为我指出正确的方向,我将永远感激。第C.12.8.5节概述了所需的事件,我发现Zynq只支持最少的PMU事件。正如您所描述的,尝试使用不受支持的事件只会得到零计数
下面是如何操作协处理器15的寄存器以设置计数器并读取其值的一个小示例:
//我的系统有6个可配置计数器和一个单独的循环计数寄存器。
//这将为配置的计数器包含一个良好的可读名称。
const char*cpu_name[7]={,,,CCNT};
类型定义结构{
u32 reg[7];//6可配置文件和循环计数
}cpu性能;
内联u32\u读取\u cpu\u计数器r{
//读取PMXEVCNTR r
//这是通过首先将计数器编号写入PMSELR,然后读取PMXEVCNTR来完成的
u32-ret;
asm volatile MCR p15,0,%0,c9,c12,5\t\n::rr;//在PMSELR中选择事件计数器
asm易失性MRC p15,0,%0,c9,c13,2\t\n:=rret;//从PMXEVCNTR读取
返回ret;
}
内联无效\u设置\u cpu\u计数器u32 r,u32事件,常量字符*名称{
cpu_name[r]=名称;
//写入PMXEVTYPER
//这是通过首先将计数器编号写入PMSELR,然后写入PMXEVTYPER来完成的
asm volatile MCR p15,0,%0,c9,c12,5\t\n::rr;//在PMSELR中选择事件计数器
asm volatile MCR p15,0,%0,c9,c13,1\t\n::revent;//在PMXEVTYPER中设置事件编号
}
无效初始cpu性能{
//禁用配置PCMCNTECRL的所有计数器
asm易失性MCR p15,0,%0,c9,c12,2\t\n::r0x8000003f;
//禁用计数器溢出中断
asm易失性MCR p15,0,%0,c9,c14,2\n\t::r0x8000003f;
//在6个可配置计数器中选择要计数的事件
//请注意,这两个示例都来自所需事件的列表。
_设置cpu计数器0,0x04,L1DACC;
_设置cpu计数器1,0x03,L1DFILL;
}
内联无效重置\u cpu\u性能{
//禁用所有计数器PMCNTENCLR:
asm易失性MCR p15,0,%0,c9,c12,2\t\n::r0x8000003f;
u32 pmcr=0x1//启用计数器
|0x2//重置所有其他计数器
|0x4//重置周期计数器
|0x8//通过64除法器启用CCNT。
|0x10;//将事件导出到外部监视
//对性能计数器控制寄存器PMCR进行编程:
asm挥发性MCR p15,0,%0,c9,c12,0\t\n::rpmcr;
//清除溢出PMOVSR:
asm易失性MCR p15,0,%0,c9,c12,3\t\n::r0x8000003f;
//启用所有计数器PMCNTENSET:
asm易失性MCR p15,0,%0,c9,c12,1\t\n::r0x8000003f;
}
内联cpu性能获取cpu性能{
cpu性能;
INTR;
//读取可配置计数器
对于r=0;rSee和,它们可能会有帮助。而Linux应该是用于Cortex CPU afaik的。它可能很简单;我对MCR/MRC参数总是有问题。您也有一些关于内联汇编程序的问题。在很多情况下,您修改计数器,但不注释它。此外,您使用的是硬编码的r0、r1,但未指定此项。您可以在同一个asm语句中对多个asm操作代码进行分组。只需使用一个\n;您不需要多次指定参数,但要正确指定它们。另外