210中的异常中的中断实现过程:
首先异常分为很多种,异常中包含了中断异常,有一个东西叫做异常向量表,在异常向量表中有很多相应异常的的地址。异常向量表中的所有异常中断的地址是不会变化的。地址都是固定的,但这些地址都是一个基于基地址的一个地址。不同的CPU中,基地址是不同的。
在210中,CPU内部给了一个发生异常时的异常向量的基地址,查阅官方资料知道,这个基地址为0XD0037400,所以我们需要自己把异常向量表中的地址加在210给的发生异常时的异常向量的基地址上。比如:reset(复位异常)在异常向量表中的地址是0x00,中断(IRQ)在异常向量表中的地址是0x18,所以我们需要把这两个异常向量表的地址加在210给的异常时的基地址上,也就是210对应的真正发生复位异常时地址为0XD0037400+0x00,210对应的真正发生中断(IRQ)普通中断时对应的地址为0xD0037400+0X18。现在举例说明,比如如果210发生了中断,CPU的硬件会自动的帮我们跳转到中断异常的地址中去执行0xD0037400+0X18,但是这个地址中只有四个字节的空间给我们用,所以我们会在这个地址中,用软件写一个函数将函数名(函数名就是一段代码的首地址,这里可以把函数名理解成一个函数指针,因为都是符号,所以这个函数名只有四个字节)(irq),写入到这个地址中去,这时当CPU发生中断硬件自动跳转到这个地址执行时,会发现这里是一个函数名(可以理解为函数指针),所以就会去这个函数对应的地址去执行那段函数体。这个函数真正的位置可能在内存中的其他地方,所以就解决了那个地方为四个字节的问题,用函数指针解决的。以上这个阶段可以称为第一个阶段。但是这一个阶段中,当CPU跳转到这里这个函数irq时,我们要保护现场,首先要设置IRQ模式下的栈,再将r0~r12中的内容保存到SPSR中,同时保存lr-4的地址(为什么是lr-4呢,因为cpu在工作时,因为流水线的原因,所以 PC的值会超前当前的值,这个值时多少取决于流水线,详细的并不清楚还待了解),这个地址用于从中断处理完时,在IRQ模式下回复到SVC模式,因为210裸机中上电默认的就是SVC模式。这一切做完以后,我们在跳转到irq这个函数中去。这些就称异常中的中断处理的第一个阶段(也叫异常向量表阶段)。
第二个阶段:当我们进入到这个irq函数时,我们要去看是哪一个中断发生了,要去哪一个中断处理函数去执行处理,所以这里有很多中断寄存器,在这一阶段,210里面有四个寄存器,每个寄存器32位,一位对应一个中断,有的位没有中断,是闲置的。同时处了这些含有中断源的寄存器外,210为我们提供了很多寄存器去解决中断源对应哪一个中断处理程序(isr)的问题。硬件会自动把相应的中断源的编号去对应上相应的中断处理函数(isr)的寄存器中,我们只需要把相应的中断处理函数写到这个寄存器中就行。CPU自动的把相应的中断源对应的isr对应的寄存器中的值设定。
总结: 对于所有CPU而言第一阶段基本上都是相同的,不同的地方是在第二个阶段。因为不同的CPU支持的中断多少不同,对实时性的要求不同所以会有不同方法去解决第二阶段查询是哪个中断源触发了哪一个中断处理函数的问题。对于SC2440而言,因为2440支持的中断较少只有30多个,中断源中只有一个32位的寄存器去存放,并且寄存器有的一位中对应了两个中断源,当这一位置1后,会有一个子中断源寄存器去让我们判断到底是这两个中断源的中的哪一个中断触发了,并且给一个编号,我们需要在事先用一个数组去编写每一个编号对应的相应的中断处理函数,将中断源的编号,在数组去查询这个编号所对应的中断处理函数名(也就是函数指针)。相比之下2440在实时性上面没有210好,并且中断支持的量也没有210的多。
210的主要的中断处理寄存器:
VICnINTENABLE(n:0,1,2,3)和VICnINTENCLEAN : 这两个寄存器一个interrupt enable 一个是interrupt enable clean,使能和禁止,这两个寄存器没个有四个寄存器,对应的都是一样的。根据中断编号,找到属于四个寄存器中的哪一个寄存器中的哪一位,我们要将相应的去给他写1才能表示使能中断,这样当CPU发生中断时,在这里就可以通过,如果你写0,则CPU发生中断时,到了这里这道门,因为这里是禁止的,所以CPU就会不做处理。这个这个寄存器只能写1,写0是没有反应的,方便我们直接32位直接操作。想使能哪一个中断,就使能哪一个中断。
VICnINTSELECT: 设置中断模式的,是IRQ模式(普通中断)还是FRQ模式(快速中断),一共四组,没一组32位,每一位对应一个中断源的编号,可以设置这个中断源触发的中断为两种方式的哪种方式。FRQ模式非常快,实时性非常好,但是只能有一个中断源可以设置为FRQ。 因为210支持的中断很多,所以有四个寄存器,没个寄存器的32对应相应的中断源,所以配置控制相应的中断处理寄存器就有4组,每一组中的相应为对应相应的中断源编号。
为什么FRQ比IRQ快:原因主要有两个:一个就是因为FRQ模式下下,FRQ有专用的r8~r12寄存器,而IRQ模式下用的是供用的r1~r12.所以可以不用保存r1~r12,FRQ直接使用自己专用的r8~r12.第二个原因:异常向量表的原因,因为在异常向量表中FRQ在最后一个地方0x1c处,而他的后面就没有东西了,不想reset等异常,他在0x00,但他的后面还紧挨着其他的异常向量。所以在FRQ模式下,我们可以直接把中断处理函数写在0x1c处,而不用将函数指针放在这里去跳转,所以更省时间。
VICnIRQSTATUS和VICnFRQSTATUS: 中断状态寄存器,看中断是否发生。只读的。当发生中断时,硬件会自动的将相对应的寄存器位置1,表示中断发生了,我们软件就可以读取这个寄存器中的某一位。查询中断得到中断编号就是靠这个得到的。
VICnVECTPRIORITY0~VICnVECTPRIORITY31:
中断优先级设置寄存器,设置多个中断同时发生时先处理谁后处理谁的问题。一般来说高优先级的中断可以打断低优先级的中断,从而嵌套处理中断。当然了有些硬件/软件可以设置不支持中断嵌套。
VICnVECTADDR0~VICnVECTADDR31、VICnADDR:
(1)这三个寄存器和210中断处理第二阶段的第二阶段有关。
(2)VICnVECTADDR0到31这32个寄存器分别用来存放真正的各个中断对应的isr的函数地址。相当于每一个中断源都有一个VECTADDR寄存器,程序员在设置中断的时候,把这个中断的isr地址直接放入这个中断对应的VECTADDR寄存器即可。
(3)VICnADDR这个寄存器是只需要读的,它里面的内容是由硬件自动设置的。当发生了相应中断时,硬件会自动识别中断编号,并且会自动找到这个中断的VECTADDR寄存器,然后将其读出复制到VICnADDR中,供我们使用。这样的设计避免了软件查找中断源和isr,节省了时间,提高了210的中断响应速度。
210中中断实现的过程:
首先在开始执行的函数中初始化中断控制器,包括将异常向量表与我们自己写的异常向量处理进行绑定,如IRQ/FIQ函数进行绑定。使能或者禁止相应的中断源,将我们自己写的中断处理程序跟相应的VICnVECTEADDR进行绑定(也就是将函数指针绑定到相应中断源的编号处),以便发生中断时,硬件自动的将相应VICnVECTEADDR中的函数指针推向VICnADDR中,方便我们去VICnADDR中读。
其次在汇编中要写一个IRQ或FIQ等函数,在其中进行现场的保护,包括保护r1~r12的寄存器,保存现在的地址到lr-4中,还有CPSR到SPSR中,以便中断返回。当这些写完后,在写一个正真的中断处理程序函数。当发生中断时,硬件会首先找到异常向量表去执行,但是异常向量表那个位置,我们绑定了一个我们自己写的异常处理函数,所以就会到这个异常处理函数去执行IRQ,FIQ,因为这个函数在汇编中,所以就会到汇编中去逐步执行,首先保护现场等,直到执行到调用这个函数isr,转去这个函数中执行真正的中断处理程序,到了这个程序中就会去在VICnADDR中找相应的函数指针去触发中断处理程序。