原本预备总结一下ARM1176JZF-S/S3C6410处理器的反常处理进程,可是发现《嵌入式体系Linux内核开发实战攻略》一书中的这一部分解说得十分简明和清楚。所以就不再重复创造轮子,不过我会在以下的引证中做一些弥补。
进入反常间断处理
ARM处理器产生反常间断,则ARM处理器进入如下反常间断主动处理进程(假定产生的反常间断对应的形式为mode):
- 将当时程序状况寄存器CPSR的值保存到SPSR_mode中;
- 将CPSR中的形式位设置成mode形式,将CPSR中的bit7(I)设置为1,制止IRQ间断,假如是FIQ间断,则再将CPSR中的bit6(F)设置为1,制止FIQ间断;
- 将回来地址传给lr_mode;
- 将该反常间断的向量地址传给程序计数器pc,然后进入反常间断处理程序。
退出反常间断处理
当要从反常间断处理程序中回来时,要做以下两步操作(假定产生的反常间断对应的形式为mode):
- 将保存在SPSR_mode中的值康复到当时程序状况寄存器CPSR中;
- 回来到产生反常间断的指令的下一条指令处履行,也便是将lr_mode寄存器的值适当地回来到程序计数器pc中。
但程序员只需做好上述第二步即可,第一步在完结第二步的一起由处理器主动完结,所以咱们下面解说从各种反常间断处理回来的编程接口。
退出复位反常间断处理(Reset)
复位反常间断处理程序不需求回来,所以不需求这个接口。
退出未界说指令反常间断处理(Undefined Instruction)
未界说指令反常间断由当时履行的指令本身产生,当未界说指令反常间断产生时,程序计数器pc的值还未更新,它指向当时指令后边第2条指令(关于ARM指令,它指向当时指令地址加8字节的方位;关于Thumb指令,它指向当时指令地址加4字节的方位),当未界说指令反常间断产生时,处理器将值(pc-4)保存到lr_und中,此刻(pc-4)指向当时指令的下一条指令,所以从未界说指令反常间断回来能够经过如下指令来完结:
mov pc, lr
该指令将寄存器lr_mode中的值到程序计数器pc中,完结程序回来,一起将SPSR_mode寄存器中的值到当时程序状况寄存器CPSR中。
假如要在反常间断处理中运用数据栈,那么能够在进入反常间断处理程序时保存被间断程序的履行现场,在退出反常间断处理程序时康复被间断程序的履行现场,编程如下:
stmfd sp!, {register_list, lr} ;保存被间断程序的履行现场
; . . .
ldmfd sp!, {register_list, pc}^ ;康复被间断程序的履行现场
上面的register_list,是反常间断处理程序中运用的寄存器列表,标识符^表明要将SPSR_mode寄存器中的值到当时程序状况寄存器CPSR中。
退出软间断指令(SWI)反常间断处理(Undefined Instruction)
SWI反常间断和未界说反常间断指令相同,也是由当时履行的指令本身产生,当SWI指令履行时,pc的值还未更新,它指向当时指令后边第2条指令(关于ARM指令,它指向当时指令地址加8字节的方位;关于Thumb指令,它指向当时指令地址加4字节的方位),当未界说指令反常间断产生时,处理器将值(pc-4)保存到lr_svc中,此刻(pc-4)指向当时指令的下一条指令,所以从SWI反常间断处理回来的完结办法与从未界说指令反常间断处理回来相同:
mov pc, lr
运用数据栈的办法与未界说指令反常间断处理中的办法也相同:
stmfd sp!, {register_list, lr} ;保存被间断程序的履行现场
; . . .
ldmfd sp!, {register_list, pc}^ ;康复被间断程序的履行现场
退出指令预取间断反常间断处理(Prefetch Abort)
在指令预取时,假如方针地址是不合法的,该指令被标记成有问题的指令,这时,流水线上该指令之前的指令持续履行,当履行到该被标记成有问题的指令时,处理器产生指令预取间断反常间断。产生指令预取反常间断时,程序要回来到该有问题的指令处,从头读取并履行该指令,因而指令预取间断反常间断应该回来到产生该指令预取间断反常间断的指令处,而不是当时指令的下一条指令。
指令预取间断反常间断由当时履行的指令本身产生,当指令预取间断反常间断产生时,程序计数器pc的值还未更新,它指向当时指令后边第2条指令(关于ARM指令,它指向当时指令地址加8字节的方位;关于Thumb指令,它指向当时指令地址加4字节的方位)。此刻处理器将值(pc-4)保存到lr_abt中,它指向当时指令的下一条指令,所以回来操作能够经过下面指令完结:
subs pc, lr, #4
该指令将lr中的值减4后传给程序计数器pc中,完结程序回来,一起将SPSR_abt寄存器的内容到当时程序状况寄存器CPSR中。
假如要在指令预取间断反常间断处理中运用数据栈,能够用以下办法维护、康复被间断程序的履行现场:
subs lr, lr, #4
stmfd sp!, {register_list, lr} ;保存被间断程序的履行现场
; . . .
ldmfd sp!, {register_list, pc}^ ;康复被间断程序的履行现场
上面的register_list是反常间断处理程序中运用的寄存器列表,标识符^表明要将SPSR_abt寄存器中的值到当时程序状况寄存器CPSR中。
退出数据拜访间断反常间断处理(Data Abort)
产生数据拜访反常间断时,程序要回来到该有问题的指令处,从头拜访该数据,因而数据拜访反常间断应该回来到产生该数据拜访间断反常间断的指令处,而不是当时指令的下一条指令。
数据拜访反常间断由当时履行的指令本身产生,当数据拜访反常间断产生时,程序计数器pc的值现已更新,它指向当时指令后边第3条指令(关于ARM指令,它指向当时指令地址加12字节的方位;关于Thumb指令,它指向当时指令地址加6字节的方位)。此刻处理器将值(pc-4)保存到lr_abt中,它指向当时指令后边第2条指令,所以回来操作能够经过下面指令完结:
subs pc, lr, #8
该指令将lr中的值减8后传给程序计数器pc中,完结程序回来,一起将SPSR_abt寄存器内容到当时程序状况寄存器CPSR中;
假如要在数据拜访反常间断处理中运用数据栈,能够用以下办法维护、康复被间断程序的履行现场:
subs lr, lr, #8
stmfd sp!, {register_list, lr} ;保存被间断程序的履行现场;
; . . .
ldmfd sp!, {register_list, pc}^ ;康复被间断程序的履行现场;
上面的register_list是反常间断处理程序中运用的寄存器列表,标识符^表明要将SPSR_abt寄存器中的值到当时程序状况寄存器CPSR中。
退出IRQ反常间断处理程序(IRQ)
一般处理器履行完当时指令后,查询IRQ间断引脚,并检查是否答应IRQ间断,假如某个间断引脚有用,而且体系答应该间断产生,处理器将产生IRQ反常间断,当IRQ反常间断产生时,程序计数器pc的值现已更新,它指向当时指令后边第3条指令(关于ARM指令,它指向当时指令地址加12字节的方位;关于Thumb指令,它指向当时指令地址加6字节的方位),当IRQ反常间断产生时,处理器将值(pc-4)保存到IRQ反常形式下的寄存器lr_irq中,它指向当时指令之后的第2条指令,因而回来操作能够经过下面指令完结:
subs pc, lr, #4
该指令将lr中的值减4后传给程序计数器pc中,完结程序回来,一起将SPSR_irq寄存器的内容到当时程序状况寄存器CPSR中。
假如要在IRQ反常间断处理中运用数据栈,能够用以下办法维护、康复被间断程序的履行现场:
subs lr, lr, #4
stmfd sp!, {register_list, lr} ;保存被间断程序的履行现场
; . . .
ldmfd sp!, {register_list, pc}^ ;康复被间断程序的履行现场
上面的register_list是反常间断处理程序中运用的寄存器列表,标识符^表明要将SPSR_irq寄存器中的值到当时程序状况寄存器CPSR中。
退出FIQ反常间断处理程序(FIQ)
与IRQ反常间断相同,处理器履行完当时指令后,查询FIQ间断引脚,并检查是否答应FIQ间断,假如间断引脚有用,而且体系答应该间断产生,处理器将产生FIQ反常间断,当FIQ反常间断产生时,程序计数器pc的值现已更新,它指向当时指令后边第3条指令(关于ARM指令,它指向当时指令地址加12字节的方位;关于Thumb指令,它指向当时指令地址加6字节的方位),当FIQ反常间断产生时,处理器将值(pc-4)保存到IRQ反常形式下的寄存器lr_fiq中,它指向当时指令之后的第2条指令,因而回来操作能够经过下面指令完结:
subs pc, lr, #4
该指令将lr中的值减4后传给程序计数器pc中,完结程序回来,一起将SPSR_fiq寄存器的内容到当时程序状况寄存器CPSR中。
假如要在FIQ反常间断处理中运用数据栈,能够用以下办法维护、康复被间断程序的履行现场:
subs lr, lr, #4
stmfd sp!, {register_list, lr} ;保存被间断程序的履行现场
; . . .
ldmfd sp!, {register_list, pc}^ ;康复被间断程序的履行现场
上面的register_list是反常间断处理程序中运用的寄存器列表,标识符^表明要将SPSR_fiq寄存器中的值到当时程序状况寄存器CPSR中。
弥补:关于程序回来地址(PC)的取值
上文中说到,在进入反常处理之后,CPU会主动依据pc的值来设置lr的值(一般是减4),而关于不同各类的反常来说,这个值还不能直接用做反常的回来地址,或许还需求再减4或减8等等,这样做的原因是什么呢?
答案在于ARM处理器在处理指令时所运用的三级流水线机制。
CPU履行一条指令的进程能够分为三个过程:取指令、翻译和履行。履行每一个过程都需求一个指令周期的时刻,所以完整地履行完一条指令实际上就需求3个周期。为了加速程序的运转,现代CPU都会选用多级流程线的技能。以三级流水线为例,一条专门担任取指,一条专门翻译,还有一条担任履行,三条流水线并行作业,每一条流水线在每一个周期内都不会闲暇,所以均匀来看,履行每条指令都只需一个周期的时刻。
从二进制指令的视点来看,当时指令在履行的时分,下一条指令现已在被翻译,再下一条指令现已正在被读取。留意pc寄存器总是指向正在被读取的那条指令,而不是正在被履行的指令。如下图所示:
箭头方向是指令运转的方向,左边是低地址,右侧是高地址,当A指令是正在运转的指令,pc寄存器现在正指向C指令的方位。
下面,别离以软间断反常和数据反常为例来解释一下上文中所讲的内容:
在软间断产生时,指令流水线的结构与上图彻底相同。软间断是由正在履行的指令A触发的,它的使命现已完结,所以在间断处理完毕之后,A指令不需求再被履行一次,应该直接履行B指令。而在进入间断处理程序之前,CPU现已主动将(pc-4)的值存入lr,这正是B指定的方位。所以在间断回来时,直接把lr的值赋给pc就行了。
在数据拜访反常产生时,指令流水线的结构与上图不太相同,正在履行的指令仍然是A,pc现已更新,即指向了D指令。在间断处理完毕时,数据的问题现已处理(能够拜访),A指令还需求再从头履行一次,所以pc需求指向A指令处。而在进入间断处理程序之前,CPU现已主动将(pc-4)的值存入lr,这是C指令的方位,所以咱们需求手动调整pc的方位,把它再减8,这才是A指令的方位。