FIQ和IRQ中断系统有什么区别?


Answers:


63

现代ARM CPU(和其他一些CPU)的功能。

来自专利:

提供了一种在数字数据处理器中执行快速中断的方法,该方法具有处理多个中断的能力。接收到快速中断请求时,将设置一个标志,并将程序计数器和条件代码寄存器存储在堆栈中。在中断服务程序结束时,从中断指令返回将检索条件代码寄存器,其中包含数字数据处理器的状态,并检查是否已设置该标志。如果设置了该标志,则表明已处理了一个快速中断,因此仅取消了程序计数器的堆栈。

换句话说,FIQ只是更高优先级的中断请求,通过在请求服务期间禁用IRQ和其他FIQ处理程序来优先处理FIQ。因此,在处理活动FIQ中断期间不会发生其他中断。


1
不能无视答案,但是专利中的内容并不一定说明已实施的内容,因此我不会真正将其视为权威参考。
abc

166

ARM调用FIQ快速中断,与寓意IRQ正常优先级。在任何实际的系统中,将有不仅两个设备更多的中断源,因此将有一些外部硬件中断控制器允许这些多个源的屏蔽,优先级等,并将中断请求线驱动到处理器。

在某种程度上,这使得两个中断模式之间的区别变得多余,并且许多系统根本不使用nFIQ或以类似于NMI其他处理器上的非可屏蔽()中断的方式使用它(尽管FIQ大多数ARM软件都可屏蔽)处理器)。

那么,ARM为什么将FIQ称为“快速”?

  1. FIQ模式具有其专用的存储寄存器r8-r14。R14是链接寄存器,用于保存FIQ的返回地址(+4)。但是,如果您的FIQ处理程序能够被编写为仅使用r8-r13,则可以通过两种方式利用这些存储区寄存器:
    • 一种是它不会产生推入和弹出中断服务例程(ISR)使用的任何寄存器的开销。这样可以节省进入和退出ISR的大量周期。
    • 而且,处理程序可以依赖于从一个调用到下一个调用的持久化在寄存器中的值,因此例如r8可以用作指向硬件设备的指针,并且处理程序可以依赖于r8下次调用时的相同值。
  2. FIQ在异常向量表(0x1C)末尾的位置意味着,如果FIQ处理程序代码直接放置在向量表的末尾,则不需要分支-该代码可以直接从执行0x1C。这样可以节省进入ISR的几个周期。
  3. FIQ的优先级高于IRQ。这意味着,当核心发生FIQ异常时,它将自动屏蔽掉IRQ。IRQ不能中断FIQ处理程序。反之则不成立-IRQ不会屏蔽FIQ,因此FIQ处理程序(如果使用)可以中断IRQ。此外,如果IRQ和FIQ请求同时发生,则内核将首先处理FIQ。

那么为什么许多系统不使用FIQ?

  1. FIQ处理程序代码通常不能用C编写-需要直接用汇编语言编写。如果您充分关心ISR性能以使用FIQ,则无论如何都可能不想通过用C编码在表上留下一些循环,但更重要的是C编译器不会产生遵循以下限制的代码仅使用寄存器r8-r13。由符合ARM的ATPCS过程调用标准的C编译器生成的代码将改用寄存器r0-r3作为暂存值,并且不会cpsr在函数末尾生成正确的恢复返回代码。
  2. 所有的中断控制器硬件通常都在IRQ引脚上。仅当将单个最高优先级中断源连接到nFIQ输入并且许多系统没有单个永久最高优先级源时,才使用FIQ才有意义。将多个来源连接到FIQ,然后在它们之间设置软件优先级是没有价值的,因为这消除了FIQ与IRQ相比几乎具有的所有优势。

3
FIQ在ARM TrustZone实现中用于“安全世界”,以区分中断与“安全”中断源。对什么是安全中断源以及如何与正常中断进行不同处理的精确确定取决于威胁和实施模型。
divegeek 2014年

1
GCC和LLVM都缺少FIQ代码所需的优化。他们将继续使用寄存器r0至r7而不是r8及更高版本。因此,生成的代码将它们压入/弹出堆栈。同样,在调用函数时,编译器将继续使用标准ABI(函数可能会将r0更改为r3)。很快,生成的程序集成为标准组件并且效率很低。
斯文,

73

在某些ARM参考中,FIQ快速中断通常称为软DMA
的特点FIQ是,

  1. 带有堆栈寄存器的独立模式,包括堆栈,链接寄存器和R8-R12。
  2. 单独的FIQ启用/禁用位。
  3. 向量表的尾部(始终在高速缓存中并由MMU映射)。

与必须分支的IRQ相比,最后一个功能还具有一点优势。

“ C”中的速度演示

一些人引用了在汇编器中编码以处理FIQ的困难。 gcc具有注释以编码FIQ处理程序。这是一个例子

void  __attribute__ ((interrupt ("FIQ"))) fiq_handler(void)
{
    /* registers set previously by FIQ setup. */
    register volatile char *src asm ("r8");  /* A source buffer to transfer. */
    register char *uart asm ("r9");          /* pointer to uart tx register. */
    register int size asm ("r10");           /* Size of buffer remaining. */
    if(size--) {
        *uart = *src++;
    }
}

这相当于以下几乎很好的汇编器,

00000000 <fiq_handler>:
   0:   e35a0000        cmp     sl, #0
   4:   e52d3004        push    {r3}            ; use r11, r12, etc as scratch.
   8:   15d83000        ldrbne  r3, [r8]
   c:   15c93000        strbne  r3, [r9]
  10:   e49d3004        pop     {r3}            ; same thing.
  14:   e25ef004        subs    pc, lr, #4

的汇编程序0x1c可能看起来像这样,

   tst     r10, #0    ; counter zero?
   ldrbne  r11, [r8]  ; get character.
   subne   r10, #1    ; decrement count
   strbne  r11, [r9]  ; write to uart
   subs    pc, lr, #4 ; return from FIQ.

真正的UART可能有一个就绪位,但是使用FIQ生成高速软DMA的代码仅为10-20条指令。主代码需要轮询FIQ,r10以确定缓冲区何时结束。Main(非中断代码)可通过使用指令切换到FIQ模式并将非存储区R0-R7传输到存储区R8-R13寄存器来转移和设置存储区FIQ寄存器。msr

通常,RTOS中断等待时间为500-1000条指令。对于Linux,它可能是2000-10000条指令。始终最好使用实数DMA,但是,对于高频简单中断(如缓冲区传输),FIQ可以提供解决方案。

由于FIQ与速度有关,因此如果您不确定汇编程序中的编码(或愿意花时间),就不应该考虑它。由无限运行的程序员编写的汇编程序比编译器要快。在GCC协助下可以帮助新手。

潜伏

由于FIQ具有单独的屏蔽位,因此几乎无处不在。在较早的ARM CPU(例如ARM926EJ)上,某些原子操作必须通过屏蔽中断来实现。即使使用最先进的Cortex CPU,在某些情况下OS也会屏蔽中断。通常,服务时间对于中断而言并不重要,但在信号通知和服务之间的时间并不重要。在这里,FIQ也有优势。

弱点

FIQ是不可扩展的。为了使用多个FIQ源,必须在中断例程之间共享存储区寄存器。另外,必须添加代码以确定是什么原因导致了中断/ FIQ。该FIQ一般是一招的小马

如果您的中断非常复杂(网络驱动程序,USB等),则FIQ可能毫无意义。这基本上与多路复用中断相同。该编组寄存器产生6-自由变量来使用它永远不会从内存中加载。寄存器比内存快。寄存器比L2缓存快。寄存器比L1缓存快。注册速度很快。如果您不能编写运行6个变量的例程,则FIQ不适合。注意:如果使用16位值,则可以对某些寄存器进行移位循环加倍,而移位旋转在ARM上是免费的。

显然,FIQ更复杂。操作系统开发人员希望支持多个中断源。客户对FIQ的要求会有所不同,他们通常会意识到,他们应该让客户自己动手做。通常对FIQ的支持是有限的,因为任何支持都可能会损害主要收益SPEED

概要

不要抨击我朋友的FIQ。它是系统程序员针对愚蠢的硬件的一个绝招。它不适合每个人,但有它的位置。当其他所有尝试减少延迟和增加ISR服务频率的尝试均告失败时,FIQ可能是您唯一的选择(或更好的硬件团队)。

在某些安全关键型应用程序中,也可以用作紧急中断。


1
作为附录,安全世界OS(ARM TrustZone)使用FIQ几乎是强制性的。但是,在这种情况下,它充当普通的中断处理程序,而不是传统的SoftDMA角色。在正常的世界使用正常的IRQ机制和安全使用的FIQ
artless噪音

只是想知道为什么不读取ACK并在处理程序中发送EOI
Charvak 2014年

@Charvak这是特定于中断控制器的;您在考虑GIC。某些中断控制器将自动清除(即,写入字符时uart ready尚未准备就绪)。这是一个假设的示例(用于通用答案; OP具有ARM926),而不是实际的工作示例。将GIC基数放在FIQ寄存器中,然后执行ACKEOI,如果那是您拥有的控制器。
无声的噪音

本地寄存器变量不会执行您可能认为的操作。他们不为特定变量保留寄存器。实际上,当执行具有指定变量作为输入或输出参数的内联汇编时,gcc仅保证变量的值在指定的注册表中。在任何其他时间,该寄存器可用于其他数据。特别是,我相信gcc不能理解函数返回时src必须在寄存器中注册r8的内容。但是,全局寄存器变量在这里似乎很合适,因为它们确实保留了寄存器。
Sven 2014年

1
众所周知,即使可以使用r8和friends,GCC仍倾向于使用寄存器r0至r7。遗憾的是,GCC并不是编写FIQ处理程序IMHO的最佳选择。供参考:gcc.gnu.org/bugzilla/show_bug.cgi?id=48429
Sven,

6

混沌已经很好地回答了,但是到目前为止还没有涉及的另一点是FIQ在向量表的末尾,因此通常从那里开始执行例程是传统的/传统的方法,而IRQ向量通常就是这样。(即跳到其他地方)。在完全隐藏和上下文切换后立即避免额外的分支,这会略有提高速度。


5

另一个原因是在FIQ情况下,需要较少数量的寄存器来压入堆栈,FIQ模式具有R8至R14_fiq寄存器


3

FIQ是较高的优先级,可以在处理另一个IRQ时引入。最重要的资源由FIQ处理,其余资源由IRQ处理。



1

毫无疑问,FIQ的优先级更高,我不确定..... FIQ将支持高速数据传输(或)通道处理,在需要高速数据处理的情况下,我们使用FIQ,通常将IRQ用于常规中断处理。


0

FIQ没有任何魔力。FIQ可以中断正在服务的任何其他IRQ,这就是为什么它被称为“快速”的原因。系统对这些中断的反应更快,但其余部分相同。


0

这取决于我们设计中断处理程序的方式,因为FIQ最后可能不需要一条分支指令,而且它具有唯一的r8-r14寄存器集,因此下一次我们回到FIQ中断时,我们无需压入/弹出堆栈。当然,这样可以节省一些周期,但是要让更多的处理程序为一个FIQ服务也是不明智的,而且FIQ具有更高的优先级,但是没有理由说它可以更快地处理中断,因为两个IRQ / FIQ都以相同的CPU频率运行,因此,它们必须以相同的速度运行。


-5

这可能是错误的。我所知道的是FIQ代表快速中断请求,IRQ代表中断请求。从这些名称来看,我猜想FIQ的处理(抛出)速度要比IRQ更快。FIQ将比IRQ更快地中断进程,这可能与处理器的设计有关。如果我错了,我深表歉意,但是我通常会进行更高级别的编程,我只是在猜测。

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.