我正在使用带有Cortex M4的STM32F407,我正在通过在调用我在汇编中实现的函数(在C中)之前和之后直接读取(mkv|avi|mpe?g|wmv|flv)
来测量函数的循环计数。我想了解我得到的结果。
[.]\w{3,4}$
执行上述(包括函数调用)需要21个周期。当我添加一条DWT_CYCCNT
指令时:
08000610 <my_function>:
8000610: f04f 20ff mov.w r0, #4278255360 ; 0xff00ff00
8000614: f04f 11ff mov.w r1, #16711935 ; 0xff00ff
8000618: ea81 0100 eor.w r1, r1, r0
800061c: ea81 0100 eor.w r1, r1, r0
8000620: ea81 0100 eor.w r1, r1, r0
8000624: ea81 0100 eor.w r1, r1, r0
8000628: 4770 bx lr
800062a: bf00 nop
这突然变成了28个周期。
添加另一个eor
不会改变周期数(仍为28)。再添加一个会使循环计数器按预期增加1(所以29)。
为什么?
08000610 <my_function>:
8000610: f04f 20ff mov.w r0, #4278255360 ; 0xff00ff00
8000614: f04f 11ff mov.w r1, #16711935 ; 0xff00ff
8000618: ea81 0100 eor.w r1, r1, r0
800061c: ea81 0100 eor.w r1, r1, r0
8000620: ea81 0100 eor.w r1, r1, r0
8000624: ea81 0100 eor.w r1, r1, r0
8000628: ea81 0100 eor.w r1, r1, r0
800062c: 4770 bx lr
800062e: bf00 nop
应始终为1个周期。有什么想法吗? :)
(此问题与#18960524有些相似,但没有eor
和加载指令可能会搞砸。)
答案 0 :(得分:4)
核心没有缓存 * ,但系统肯定有 - 即ST&#39;&# 34; ART Accelerator&#34;。
如the TRM第3.5.2节所述,这个东西位于总线路径中,从闪存中进行全宽(128位)提取,然后将这些指令提供给内核的ICode接口,因为它要求他们。
第3.5.1节记录了闪存等待状态的数量与时钟速度和电压配置的关系,对于STM32F407,这意味着7个周期的最坏情况。我可以从问题的本质中猜测你可能还没有启用加速器的预取或指令缓存功能,这意味着每个16字节的指令都是你的。当从闪存中拖入下一个块时,将暂停 n 周期等待那些等待状态。
数学比我现在想要解决的问题更加尴尬,但足以说21个周期是至少7个执行周期的重叠组合,2个管道补充(每个1-3个循环用于调用和返回)以及至少2 * n 等待状态从闪存中获取至少2个块。
现在,需要注意的一点是,第一个函数是28个字节长,而第二个函数是32个 - 即恰好是两个16字节的块。第二个注意事项:M4的ICode接口只执行32位读取,然后从中读取管道的提取阶段(我假设当管道仅消耗前半个字时,它只是将其拇指旋转一个周期)。我非常有信心你在第二个例子中看到的是两者之间令人不快的互动 - 有一些有根据的猜测我想象这种情况:
bx lr
并从相同的指令字中取出0x800062e时,ICode接口会暂时停止,但加速器正在等待闪存以传递读取0x8000630-0x8000640。lr
地址(然后等待另一个 n 周期来实际获取它)。 看起来像FLASH_ACR应该更准确地了解你的配置是什么,如果你真的想尝试计算每个周期 - 除非你将整个事情计时到ARM的零等待状态配置#39;核心时间假定(note the first paragraph),您将不得不考虑的不仅仅是核心。更一般地说,我建议在不彻底研究供应商的文档的情况下对微控制器进行编程&#34;就在那里&#34;只需走进Mordor&#34; ;)
* Cortex-M7是ARM实际拥有自己的内部缓存的M级核心中的第一个。