我正在编写raspbery pi model b ARM1176 bare metal
(在程序集和c
中)。我需要计算用于执行汇编代码的时钟周期。
我正在使用以下代码用于PMU计数器:
mov r0,#1
MCR p15, 0, r0, c15, c12, 0 ; Write Performance Monitor Control Register
/* Reset Cycle Counter */
mov r0,#5
MCR p15, 0, r0, c15, c12, 0 ; Write Performance Monitor Control Register
/* Meaure */
MRC p15, 0, r0, c15, c12, 1 @ Read Cycle Counter Register
<MY CODES>
MRC p15, 0, r1, c15, c12, 1 @ Read Cycle Counter Register
如果我有
add r3,#3
代替我的代码我得到r1=8
和r0=0
,这似乎是正确的,因为arm11有8个流水线阶段,执行它需要8个时钟周期。
但是当我添加更多指令时,我会得到像
这样荒谬的结果add r3,#3
add r4,#1
r0=0,r1=97/96/94 (the result of r1 should also be constant!!!)
我正在使用uart
查看minicom上的寄存器结果。
答案 0 :(得分:0)
好的,看到同样的事情,这很有趣。
@ nop
.globl test
test:
mov r0,#1
MCR p15, 0, r0, c15, c12, 0
mov r0,#5
MCR p15, 0, r0, c15, c12, 0
MRC p15, 0, r0, c15, c12, 1
add r3,#3
add r2,#1
MRC p15, 0, r1, c15, c12, 1
sub r0,r1,r0
bx lr
我从C中调用它,所以如果我在测试代码中使用r4进行捣乱,则必须将其保存在堆栈中,因此与r2混淆。如果没有添加r2行,则返回值为8,使用add r2行返回值为0x68然后为0x65。注意这是pi 0。所以有些时钟比你的快一点。
请记住,这是从dram和dram运行非常缓慢。所以你可能会看到其中的一些。
代码的初始对齐:
00008024 <test>:
8024: e3a00001 mov r0, #1
8028: ee0f0f1c mcr 15, 0, r0, cr15, cr12, {0}
802c: e3a00005 mov r0, #5
8030: ee0f0f1c mcr 15, 0, r0, cr15, cr12, {0}
8034: ee1f0f3c mrc 15, 0, r0, cr15, cr12, {1}
8038: e2833003 add r3, r3, #3
803c: e2822001 add r2, r2, #1
8040: ee1f1f3c mrc 15, 0, r1, cr15, cr12, {1}
8044: e0410000 sub r0, r1, r0
8048: e12fff1e bx lr
是的,如果我在.globl测试前取消注释nop,并且我注释掉了添加r2我只有添加r3作为测试中的代码,但是nop推动了整个代码块的对齐。添加r3并且没有nop我使用add r3得到8个计数而nop得到0x67计数。
所以我认为这只是一个测量获取的情况。我没有启用arm缓存,但可能有更深的缓存或mmu或其他,因为这个ram在arm和gpu之间共享。
如果我更进一步并取消注释nop同时添加r3和add r2则为0x69计数。或者基本上是平均值或者只是比一条指令长,所以我们强制在那里取一个。
所以我的情况如果我添加更多的nops,所以计数的初始读取在8字边界上对齐,并且我有两个指令被测量
00008030 <test>:
8030: e3a00001 mov r0, #1
8034: ee0f0f1c mcr 15, 0, r0, cr15, cr12, {0}
8038: e3a00005 mov r0, #5
803c: ee0f0f1c mcr 15, 0, r0, cr15, cr12, {0}
8040: ee1f0f3c mrc 15, 0, r0, cr15, cr12, {1}
8044: e2833003 add r3, r3, #3
8048: e2822001 add r2, r2, #1
804c: ee1f1f3c mrc 15, 0, r1, cr15, cr12, {1}
8050: e0410000 sub r0, r1, r0
8054: e12fff1e bx lr
我得到了8.我在那里添加了第三条指令,添加了r3和两条添加r2。仍然算是8。
如果我回到这里,其中至少有一部分位于不同的获取行中。
00008024 <test>:
8024: e3a00001 mov r0, #1
8028: ee0f0f1c mcr 15, 0, r0, cr15, cr12, {0}
802c: e3a00005 mov r0, #5
8030: ee0f0f1c mcr 15, 0, r0, cr15, cr12, {0}
8034: ee1f0f3c mrc 15, 0, r0, cr15, cr12, {1}
8038: e2833003 add r3, r3, #3
803c: e2822001 add r2, r2, #1
8040: ee1f1f3c mrc 15, 0, r1, cr15, cr12, {1}
8044: e0410000 sub r0, r1, r0
8048: e12fff1e bx lr
我做了三次运行而没有改变任何东西,然后启用l1缓存(指令)并再做三次运行
00000068
0000001D
0000001D
0000001F
00000008
00000008
所以我认为你正在处理dram,这是缓慢的,获取行,缓存未命中和命中以及产生的缓存行提取。
如果您希望看到执行指令所花费的时钟数,那么除非您可以将整个代码保留在l1缓存中,否则您将没有零等待状态内存。
我不认为芯片sram你可以用于这种芯片/板的这种东西,你最终会击中dram并且dram与gpu共享。因此,基本上程序执行时间预计不会是确定性的,并且与您的计算机或电话或其他cpu不是瓶颈并不是很长一段时间,它坐在那里等待提供数据或指令。