Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 手臂皮质m4周期计数有点奇怪_Assembly_Arm_Cortex M_Lpc - Fatal编程技术网

Assembly 手臂皮质m4周期计数有点奇怪

Assembly 手臂皮质m4周期计数有点奇怪,assembly,arm,cortex-m,lpc,Assembly,Arm,Cortex M,Lpc,我最近使用了一块板(LPCXpresso 5411x)来进行一些计算,我们试图尽可能减少周期,以节省运行时间满足特定需求,因此我需要对cortex-m4指令如何循环进行一些研究。我发现了很多奇怪的事情(这是我在互联网上发现的无法解释的) 我使用了DWT->CYCCNT来计算我想要测试的函数所消耗的周期 int start_cycle, end_cycle; __asm volatile ( "LDR %[s1], [%[a]], #0\n\t" :[s1] "=&r"(star

我最近使用了一块板(LPCXpresso 5411x)来进行一些计算,我们试图尽可能减少周期,以节省运行时间满足特定需求,因此我需要对cortex-m4指令如何循环进行一些研究。我发现了很多奇怪的事情(这是我在互联网上发现的无法解释的)

我使用了DWT->CYCCNT来计算我想要测试的函数所消耗的周期

int start_cycle, end_cycle;

__asm volatile (
  "LDR %[s1], [%[a]], #0\n\t"
  :[s1] "=&r"(start_cycle): [a] "r"(&(DWT->CYCCNT)):);

AddrSumTest();
__asm volatile (
  "LDR %[s1], [%[a]], #0\n\t"
  :[s1] "=&r"(end_cycle): [a] "r"(&(DWT->CYCCNT)):);

printf("inside the func() cycles: %d\n",end_cycle - start_cycle);
下面是我的函数的定义:

__attribute__( ( always_inline )) static inline void AddrSumTest(){
    uint32_t x, y, i, q;

    __asm volatile (
        "nop\n\t"
        :[x] "=r" (x), [y] "=r" (y), [i] "=r" (i), [q] "=r" (q):);
    }
}
  • 根据,指令MOV应该花费一个周期,但我发现
以下指令需要8个周期(不是3个周期,因为从DWT->CYCCNT读取需要额外的周期)

添加另一条MOV指令后,接下来的周期需要10个周期(为什么不是9个周期)

后一种情况的装配代码为

4000578:    f853 4b00   ldr.w   r4, [r3], #0
400057c:    bf00        nop
400057e:    f04f 0502   mov.w   r5, #2
4000582:    f04f 0603   mov.w   r6, #3
4000586:    bf00        nop
4000588:    f853 1b00   ldr.w   r1, [r3], #0
400058c:    4805        ldr r0, [pc, #20]   ;(40005a4<test_AddrSum+0x30>)
400058e:    1b09        subs    r1, r1, r4
4000590:    f000 f80e   bl  40005b0 <__printf_veneer>
4000578:f853 4b00 ldr.w r4,[r3],#0
400057c:bf00 nop
400057e:f04f 0502 mov.w r5,#2
4000582:f04f 0603 mov.w r6,#3
4000586:bf00 nop
4000588:f853 1b00 ldr.w r1,[r3],#0
400058c:4805 ldr r0,[pc,#20];(40005a4)
400058e:1b09接头r1、r1、r4
4000590:f000 f80e bl 40005b0
这两个ldr是从DWT->CYCCNT读取的,此外,奇怪的是为什么这将花费10个周期,我估计是2(从ldr)+4=6

顺便说一下,该板没有任何缓存,我在sramx中存储代码,堆栈在sram2中


我是否错过了一些东西,并且以任何方式我都可以找出每个周期是如何消耗的?此外,我还对cortex-m4的数据依赖性感到困惑

换一种,我没有那种芯片,但有其他芯片。在这种情况下,使用ti cortex-m4。st部件在闪存前面有这个缓存,我认为您无法关闭它,并且(按照设计)会影响性能

00000082 <test>:
  82:   f3bf 8f4f   dsb sy
  86:   f3bf 8f6f   isb sy
  8a:   6802        ldr r2, [r0, #0]
  8c:   46c0        nop         ; (mov r8, r8)
  8e:   46c0        nop         ; (mov r8, r8)
  90:   46c0        nop         ; (mov r8, r8)
  92:   46c0        nop         ; (mov r8, r8)
  94:   46c0        nop         ; (mov r8, r8)
  96:   46c0        nop         ; (mov r8, r8)
  98:   f240 0102   movw    r1, #2
  9c:   f240 0103   movw    r1, #3
  a0:   46c0        nop         ; (mov r8, r8)
  a2:   46c0        nop         ; (mov r8, r8)
  a4:   46c0        nop         ; (mov r8, r8)
  a6:   46c0        nop         ; (mov r8, r8)
  a8:   46c0        nop         ; (mov r8, r8)
  aa:   46c0        nop         ; (mov r8, r8)
  ac:   46c0        nop         ; (mov r8, r8)
  ae:   6803        ldr r3, [r0, #0]
  b0:   1ad0        subs    r0, r2, r3
  b2:   4770        bx  lr
使用thumb2扩展名0xf240、0x0102

00000000 20001016 00000010 
00000002 20001018 00000011 
00000004 2000101A 00000010 
00000006 2000101C 00000011 
使用thumb2扩展名0xf240、0x0102、0xf240、0x0103

00000000 20001016 00000012 
00000002 20001018 00000013 
00000004 2000101A 00000012 
00000006 2000101C 00000013 
这并不奇怪,可能与抓取有关。这些微控制器比全尺寸的手臂简单得多。完整大小的缓存每次提取8条指令,这取决于提取行中的内容可能会影响性能,尤其是循环和分支在提取行中的位置(无论缓存是打开还是关闭)。分支也有分支预测器,您可以打开和关闭,并且可以在设计上有所不同

这个特殊的芯片说,在40Mhz以上,它可以实现一个预取,即取一个字,这意味着在它下面取一个半字(总线很可能是一个字宽,所以读取同一地址两次,以获取那里的两条指令…为什么?)

其他芯片(cortex ms以及其他芯片)您必须控制闪存上的等待状态,有时闪存的速度只有ram的一半,并且相同的代码、相同的机器代码在ram上运行得更快,即使在低速下,也会随着时钟的增加和闪存上等待状态的增加而变得更糟,以保持其速度可控

特别是ST系列,它有一些营销术语,用来指预取缓存(prefetch cache),它们放在里面的东西是无法禁用的。您可以在测试代码之前执行dsb/isb,例如查看等待状态对单个过程的影响,但如果执行测试循环

test_loop: sub r3,#1
bne test_loop
运行它很多次,开始时的几个时钟被反射,但是很小,就像使用缓存一样,但是如果处理器允许您看到这些,您仍然应该看到缓存的获取线效果

有些芯片有一个可以启用或禁用的闪存预取功能,特别是在循环中,如果您将事情调整得恰到好处,使预取器的读数远远超过循环的末尾,那么闪存预取功能可能会损害性能,而不是帮助性能

ARM ip停在核心边缘的ARM总线上(AXI、AMBA、AHB、APB等),一般来说,您可能有用于二级缓存的ARM ip(不在这些微控制器中),您可以购买一些ARM ip来帮助您使用总线,但最终芯片中有特定于芯片的东西,哪个arm与芯片供应商无关,也不一致,尤其是闪存和sram接口

首先,没有理由期望流水线处理器会产生可预测的结果,如上图所示,而且很容易通过两个指令循环显示,同一机器代码的性能可能会有很大的差异,这不仅是因为对齐本身,还因为您可以直接或间接地控制闪存等待状态,时钟与闪光灯的相对速度。如果我们的设备上N和N+1等待状态之间的边界是24Mhz,那么N等待状态下的24Mhz比N+1等待状态下的24Mhz快得多。28Mhz(N+1等待状态)在N+1等待状态下比24Mhz快,但最终cpu时钟可能会克服等待状态,您可以找到一个cpu速度优于24Mhz N+1等待状态,就整体墙上时钟计时性能而言,而不是cpu时钟计数而言,如果受到闪存等待状态的影响,则计数的cpu时钟应始终受到闪存等待状态的影响

SRAM往往没有等待状态,运行速度与CPU一样快,但可能有例外。毫无疑问,外设是有限制的,很多厂商都有关于外设时钟的规定,这个不能超过32mhz,即使部分达到48,诸如此类,所以访问外设的基准测试将在不同的cpu/系统速度设置下采用不同数量的cpu时钟

处理器中还有可配置选项,基本上是编译时选项。cortex-m4不宣传这一点,但cortex-m0+可以配置为16或32位指令提取宽度。我对源代码没有可见性,所以它可能是编译时的代码,或者如果您选择的话,您可以设置一个控制寄存器并让它运行
00000000 20001016 00000010 
00000002 20001018 00000011 
00000004 2000101A 00000010 
00000006 2000101C 00000011 
00000000 20001016 00000012 
00000002 20001018 00000013 
00000004 2000101A 00000012 
00000006 2000101C 00000013 
test_loop: sub r3,#1
bne test_loop