使用现代CPU(例如ARM)进行周期计数


14

在许多应用中,其指令执行与预期的输入激励具有已知时序关系的CPU可以处理如果该关系未知则需要更快CPU的任务。例如,在我使用PSOC生成视频的项目中,我使用代码每16个CPU时钟输出一个字节的视频数据。由于测试SPI设备是否准备就绪,如果不进行分支转移,则IIRC将花费13个时钟,加载和存储输出数据将花费11个时钟,因此无法测试该设备在字节之间的准备情况;取而代之的是,我只是安排让处理器在第一个字节之后的每个字节上精确执行价值16个周期的代码(我相信我使用了实际索引加载,虚拟索引加载和存储)。每行的第一次SPI写操作发生在视频开始之前,对于随后的每次写操作,都有一个16周期的窗口,在该窗口中可以进行写操作而不会导致缓冲区溢出或欠载。分支循环生成了一个13周期的不确定性窗口,但是可预测的16周期执行意味着所有后续字节的不确定性都将适合相同的13周期窗口(又适合于当写入可接受时的16周期窗口内)发生)。

对于较旧的CPU,指令时序信息是清晰,可用且明确的。对于较新的ARM,时序信息似乎更加模糊。我了解从闪存执行代码时,缓存行为会使事情难以预测,因此我希望应该从RAM执行任何周期计数的代码。即使从RAM执行代码,规范也有些含糊。使用循环计数代码仍然是一个好主意吗?如果是这样,使它可靠工作的最佳技术是什么?可以安全地假设某个芯片供应商不会在某种程度上悄无声息地使用“新改进的”芯片,从而在某些情况下缩短了某些指令的执行周期的程度?

假设以下循环在一个字边界上开始,那么如何根据规范精确地确定将花费多长时间(假设具有零等待状态内存的Cortex-M3;对于该示例,与系统无关的其他内容)。

myloop:
  mov r0,r0; 简短的简单说明,可以预取更多说明
  mov r0,r0; 简短的简单说明,可以预取更多说明
  mov r0,r0; 简短的简单说明,可以预取更多说明
  mov r0,r0; 简短的简单说明,可以预取更多说明
  mov r0,r0; 简短的简单说明,可以预取更多说明
  mov r0,r0; 简短的简单说明,可以预取更多说明
  加r2,r1,#0x12000000; 2字指令
  ; 重复以下操作,可能使用不同的操作数
  ; 将继续增加价值直到发生进位
  itcc
  addcc r2,r2,#0x12000000; 2字指令,加上itcc的额外“字”
  itcc
  addcc r2,r2,#0x12000000; 2字指令,加上itcc的额外“字”
  itcc
  addcc r2,r2,#0x12000000; 2字指令,加上itcc的额外“字”
  itcc
  addcc r2,r2,#0x12000000; 2字指令,加上itcc的额外“字”
; ... etc,带有更多条件的两个单词的指令
  子R8,R8,#1
  bpl myloop

在执行前六个指令期间,内核将有时间获取六个字,其中三个将被执行,因此最多可以预取三个。接下来的指令每个都是三个字,因此内核不可能像执行指令一样快地获取指令。我希望某些“ it”指令可能需要一个周期,但是我不知道如何预测哪个指令。

如果ARM可以指定确定其“ it”指令时序的特定条件(例如,如果没有等待状态或代码总线争用,并且前面的两条指令是16位寄存器指令,等等),那将是很好的选择。但我还没有看到这样的规格。

样品申请

假设有人试图为Atari 2600设计一个子板,以生成480P的分量视频输出。2600具有3.579MHz像素时钟和1.19MHz CPU时钟(点时钟/ 3)。对于480P分量视频,每行必须输出两次,这意味着7.158MHz点时钟输出。由于Atari的视频芯片(TIA)使用3位亮度信号加上大约18ns分辨率的相位信号来输出128种颜色中的一种,因此仅通过查看输出就很难准确确定颜色。更好的方法是拦截对颜色寄存器的写入,观察写入的值,并将每个寄存器输入与寄存器编号相对应的TIA亮度值。

所有这些都可以通过FPGA来完成,但是与具有足够RAM来处理必要缓冲的FPGA相比,某些相当快的ARM设备可能要便宜得多(是的,我知道对于可能产生这种数量的产品,成本是“才是真正的因素)。但是,要求ARM监视输入的时钟信号将大大提高所需的CPU速度。可预测的周期数可以使环境更清洁。

相对简单的设计方法是让CPLD监视CPU和TIA并生成13位RGB + sync信号,然后让ARM DMA从一个端口获取16位值,然后以适当的时序将其写入另一个端口。但是,看看便宜的ARM是否可以完成所有工作,将是一个有趣的设计挑战。如果可以预测DMA对CPU周期数的影响(特别是如果DMA周期可以发生在内存总线空闲的周期中),则DMA可能是多合一方法的有用方面。 ARM将必须执行其表查找和总线监视功能。请注意,与许多在消隐间隔期间写入颜色寄存器的视频体系结构不同,Atari 2600在帧的显示部分经常将颜色寄存器写入颜色寄存器,

也许最好的方法是使用几个离散逻辑芯片来识别颜色写入并将颜色寄存器的低位强制为适当的值,然后使用两个DMA通道对传入的CPU总线和TIA输出数据进行采样,并且第三DMA通道以产生输出数据。然后,CPU将可以自由处理来自每个扫描线的两个来源的所有数据,执行必要的转换,并将其缓冲以进行输出。适配器职责的唯一方面必须“实时”发生,这将是重写写入COLUxx的数据,可以通过使用两个通用逻辑芯片来解决。

Answers:


7

我投票支持DMA。在Cortex-M3及更高版本中,它确实非常灵活-并且您可以做各种疯狂的事情,例如自动从一个地方获取数据并以指定的速率或在某些事件下输出到另一个地方而无需花费任何CPU周期。DMA更可靠。

但是,可能很难在细节上理解。

另一个选择是FPGA上的软核,这些硬核通过硬件实现。


1
我喜欢DMA的概念。我认为Cortex M3内核没有任何DMA,这是各个制造商的芯片的功能,而且它们似乎都以不同的方式实现它。我发现至少与我实际使用的一种实现(STM32L152)在一起令人讨厌,一件事是,当输出DMA数据时,我找不到任何使引脚选通的方法。还不清楚哪些因素可能影响DMA的及时性。
supercat

1
无论如何,关于我正在考虑进行精确循环敲打的第一个应用程序中,我在原始问题中发布了更多信息。我很好奇你的想法。我在考虑循环震动的另一种情况是将显示数据传送到彩色LCD。数据将使用8位颜色缓存在RAM中,但显示需要16位颜色。我想到的最快的输出数据的方法是使用硬件生成写选通脉冲,因此CPU只需输出数据。将8-> 16位转换为小缓冲区会更好...
supercat

1
...然后安排DMA进行传输,或者最好的方法是什么?
supercat

4

可以获取时序信息,但是,正如您所指出的那样,有时可能会含糊不清。例如,Cortex-M3 的《技术参考手册》的18.2节和表18.1中有很多时序信息,例如,(pdf此处),摘录如下:

摘录18.2

给出了最大时机的条件列表。许多指令的执行时间取决于外部因素,其中某些因素确实存在歧义。我已经强调了在该节的以下摘录中发现的每个歧义:

[1]分支需要一个周期的指令,然后对目标指令进行管线重载。未采用的分支总计1个周期。立即采取的分支通常是管道重新加载的1个周期(总共2个周期)。带有寄存器操作数的分支通常是 2个周期的管道重载(总共3个周期)。分支到未对齐的32位指令时,除了访问较慢的内存外,管线重新加载的时间更长 [要长得多?]。分支提示会发送到代码总线,从而允许较慢的系统 [慢多少?]进行预加载。这是否可以(是否可选)减少 [多少?]分支目标代价以降低内存速度,但绝不会低于此处显示的速度。

[2] 通常,加载存储指令的第一次访问需要两个周期,而每次其他访问都需要一个周期。具有立即偏移量的存储需要一个周期。

[3] UMULL / SMULL / UMLAL / SMLAL使用早期终止,具体取决于源值的大小 [什么大小?]。它们是可中断的(放弃/重新启动),最坏情况下延迟为一个周期。MLAL版本需要4到7个周期,而MULL版本需要3到5个周期。对于MLAL,签名版本比未签名版本长一个周期。

[4] IT指令可以折叠。[什么时候?看评论。]

[5] DIV的时间取决于除数和除数。[与MUL相同的问题] DIV可中断(放弃/重新启动),最坏情况下延迟为一个周期。当分红和除数的大小相似 [如何相似?]时,除法很快终止。对于除数大于除数和除数为零的情况,最短时间为。尽管调试陷阱可用于捕获这种情况,但除数为零将返回零(不是故障)。[MUL的范围是多少?]

[6]睡眠是指令的一个周期,加上相应的睡眠周期。事件过去后,WFE仅使用一个周期。WFI通常不止一个周期,除非进入WFI时恰好有一个中断挂起。

[7] ISB占用一个周期(充当分支)。除非数据在写缓冲区或LSU中挂起,否则DMB和DSB需要一个周期。如果在屏障期间发生中断,则将中断/重新启动它。

对于所有用例,它都比“此指令是一个周期,该指令是两个周期,这是一个周期...”要复杂得多,这在更简单,更慢,更旧的处理器中算是可能的。对于某些用例,您不会遇到任何歧义。如果确实遇到歧义,建议您:

  1. 请与您的供应商联系,并询问他们针对您的用例的指导时间是什么。
  2. 测试以指定歧义行为
  3. 重新测试任何处理器版本,尤其是在进行供应商更改时。

这些要求可能会回答您的问题:“不,除非遇到的困难值得付出代价,否则这不是一个好主意”-但您已经知道了。


1
我认为以下内容比较模糊:“当分支到未对齐的32位指令以及访问较慢的内存时,管道重新加载的时间会更长”,并没有说明它是否恰好增加了一个周期,而“ IT指令可以折叠”没有说明他们将在什么条件下或将不会。
超级猫

1
“ IT”时序似乎特别麻烦,因为这是一条经常在紧凑的循环计数循环中使用的指令,而且我敢肯定,它不能总是折叠的。我猜想,如果一个人总是跳转到一个对时间敏感的循环的开始,迫使该循环从一个字边界开始,避免在循环中进行任何有条件的加载或存储,并且不会立即放置任何“ IT”指令在加载或更新存储后,“ IT”时间将保持一致,但是规范并没有明确说明。
超级猫

1
我的猜测是,IT可能会(真实地)指出类似以下内容:“在没有等待状态或代码总线争用的情况下,如果(1)前一条指令是未访问的16位指令,则可以保证IT折叠内存或程序计数器;以及(2)下一条指令是16位指令,或者前一条指令不是“未对齐”分支的目标。在其他未指定的情况下,IT折叠也可能发生。这样的规范将允许通过确保代码按照指示的顺序编写具有可预测的IT指令时间的程序。
supercat

1
哇-我承认我只经历了最简单的最坏情况下的周期计数,而不是真正在桌子底下挣扎。我的最新答案突出了其他一些歧义。
凯文·维米尔

1
在很多情况下,一个人对最坏情况的计数感兴趣,而在很多情况下,一个人对最坏情况的计数感兴趣(例如,如果SPI端口每16个周期可以输出一个字节,则生成每个字节将花费14个周期)最佳情况,检查准备情况将花费5个周期,检查每个字节的准备情况将速度限制为每19个周期最佳情况一个字节;盲目写入两个添加的NOP将允许每16个周期速度一个字节)。需要精确定时的情况并不常见,但可能会出现。
supercat

3

解决此问题的一种方法是使用具有确定性或可预测时序的设备,例如Parallax Propeller和XMOS芯片:

http://www.parallaxsemiconductor.com/multicoreconcept

http://www.xmos.com/

周期计数与Propeller配合使用非常好(必须使用汇编语言),而XMOS器件具有非常强大的软件实用程序XMOS Timing Analyzer,它可以与以XC编程语言编写的应用程序一起使用:

https://www.xmos.com/download/public/XMOS-Timing-Analyzer-Whitepaper%281%29.pdf


1
我开始认为Leon拥有XMOS的股份... ;-)
Federico Russo

1
我只喜欢他们的筹码,以及在那里工作的人。Parallax也是一家拥有出色产品的优秀公司。
莱昂·海勒

1
是的,没有犯罪。令我惊讶的是,提到XMOS的所有答案(一个答案除外)均来自您。对某事充满热情并没有错。
Federico Russo

@ Federico,@ Leon-这正是让我担心XMOS的原因:为什么世界上只有1个用户(至少是它的样子)?如果真是太好了,那为什么不成为这座城市的话题呢?我从未听说过有人谈论它,少使用它。
stevenvh 2011年

试试XMOS论坛:xcore.com
Leon Heller

2

随着您从低级微控制器转移到更通用的计算处理器中,周期计数变得越来越麻烦。第一个通常确实有明确指定的授课时间,部分原因是您选择的原因。这也是因为它们的体系结构非常简单,所以指令时间是固定的并且是已知的。

大多数Microchip PIC就是一个很好的例子。10、12、16和18系列具有很好的记录和可预测的指令时序。在这些芯片打算用于的小型控制应用中,这可能是有用的功能。

随着您摆脱超低成本的束缚,设计人员可以花费更多的芯片面积来从更奇特的架构中获得更高的速度,同时您也无法获得可预测性。看一下现代x86变体作为极端示例。缓存有多个级别,内存的虚拟化,超前提取,流水线化等等,这使得对指令周期进行计数几乎变得不可能。在此应用中,这无关紧要,因为客户对高速而不是指令时序可预测性感兴趣。

您甚至可以在更高的Microchip模型中看到这种效果。24位内核(24、30和33系列)具有可预测的指令时序,除了寄存器总线争用时的少数例外。例如,在某些情况下,当下一条指令使用具有某些间接寻址模式的寄存器时,机器将插入停顿,其值在上一条指令中已更改。这种停顿在dsPIC上是不常见的,大多数时候您可以忽略它,但是它表明了由于设计人员试图为您提供更快,更强大的处理器而导致的这些情况的蔓延。

因此,基本答案是,这是您选择处理器时需要权衡的一部分。对于小型控制应用,您可以选择体积小,价格便宜,功耗低并且指令时序可预测的东西。当您需要更多处理能力时,架构会发生变化,因此您必须放弃可预测的指令时序。幸运的是,当您使用更多计算密集型和通用应用程序时,这不再是一个问题,因此,我认为折衷方案可以很好地解决。


我同意,通常来说,计算量大的应用程序对微观时序的敏感度降低,但是在某些情况下,可能需要比PIC-18多一些的处理能力,而且还需要可预测性。我想知道我应该在多大程度上努力学习诸如16位PIC架构之类的东西,或者在多大程度上我应该认为ARM可能足够了。
supercat

0

是的,即使在ARM上,您仍然可以这样做。ARM上最大的问题是ARM不出售芯片,而是出售内核,而且内核时序是已知的,但是芯片供应商所包装的内容因厂商而异,有时也因芯片家族而异。因此,来自特定供应商的特定芯片可能具有确定性(例如,如果您不使用缓存),但是移植起来会变得更加困难。当在这里处理5个时钟,在这里处理11个时钟时,使用计时器是有问题的,因为采样计时器并弄清楚超时是否过期需要花费大量指令。从您过去的编程经验来看,我敢打赌您可能会像我一样使用示波器进行调试,因此您可以尝试以时钟频率在芯片上进行紧密循环,查看spi或i2c或任何波形,然后添加或消除鼻息,通过循环更改次数并基本进行调整。与任何平台一样,不使用中断会大大有助于指令执行的确定性。

不,它不像PIC那样简单,但是仍然相当可行,特别是如果延迟/定时接近处理器的时钟速率。许多基于ARM的供应商都允许您倍增时钟速率,并从8MHz的参考中获得60MHz的折扣,因此,如果您需要2MHz的接口而不是每隔4条指令执行某项操作,则可以提高时钟频率(如果您有电源预算),然后使用计时器,并给自己安排很多时钟来做其他事情。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.