ARM Cortex-a9事件计数器返回0

ARM 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

我目前正在尝试使用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\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;您不需要多次指定参数,但要正确指定它们。另外