FIQ或者快速中断,在一些ARM参考文献中被称为软DMA。 FIQ的特点包括:
独立模式,具有存储器区和堆栈、链接寄存器以及R8-R12。
独立的FIQ使能/禁用位。
向量表的尾部(始终在缓存中,并由MMU映射)。
最后一个特点也比IRQ稍微具有一些优势,因为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
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可能会有一个准备位,但用于实现高速软件DMA和FIQ的代码通常只需要10-20条指令。主要代码需要轮询FIQ r10 来确定缓冲区何时完成。主(非中断)代码可以通过使用msr指令切换到FIQ模式并将非分行的R0-R7转移到分行的R8-R13寄存器来传输和设置分行的FIQ寄存器。
通常RTOS中断延迟为500-1000条指令。对于Linux, 可能是2000-10000条指令。实际DMA总是更可取的,但对于高频简单中断(如缓冲区传输),FIQ可以提供解决方案。
由于FIQ是关于速度的,如果你不确定自己能否在汇编语言中编码(或愿意投入时间),则不应考虑它。由无限运行的程序员编写的汇编程序比编译器更快。使用GCC可以帮助新手。
延迟
由于FIQ有一个单独的掩码位,因此几乎普遍启用。在早期的ARM CPU(如ARM926EJ)中,一些原子操作必须通过屏蔽中断来实现。即使是最先进的Cortex CPU,仍有时候操作系统会屏蔽中断。通常服务时间对于中断并不重要,但信号和服务之间的时间很重要。在这里,FIQ也具有优势。
弱点
FIQ不可扩展。为了使用多个FIQ源,分行寄存器必须在中断例程之间共享。还必须添加代码以确定引起中断/FIQ的原因。 FIQ通常是一个“万能选手”。
如果你的中断非常复杂(网络驱动程序、USB等),那么FIQ可能就没有意义了。这与多路复用中断的说法基本相同。分行寄存器提供了6个免费变量可供使用,它们不需要从内存中读取。寄存器比内存快。寄存器比L2缓存快。寄存器比L1缓存快。寄存器很快。如果你无法编写一个使用6个变量运行的例程,那么FIQ就不适合。注意:如果使用16位值,可以使用移位和旋转来同时双重处理某些寄存器。
显然,FIQ更为复杂。操作系统开发人员希望支持多个中断源。客户对FIQ的要求也各不相同,他们往往意识到应该让客户自己去实现。通常,对FIQ的支持是有限的,因为任何支持都可能削弱其主要优势——速度。
总结
不要抨击我的朋友FIQ。它是系统程序员对付愚蠢硬件的一个技巧。它并不适用于每个人