朱老师笔记
1.8.5.1、像内存一样去访问异常向量表
(1)S5PV210的异常向量表可以改变(在CP15协处理器中),以适应操作系统的需求。但是目前系统刚启动时,此时DRAM尚未初始化,程序都在SRAM中运行。210在iRAM中设置了异常向量表,供暂时性使用。
(2)查210的iROM application note文档中iRAM的地址分配,可知,iRAM中的异常向量表起始地址为0xD0037400。知道了异常向量表的起始地址后,各个异常对应的入口就很好知道了。
1.8.5.2、函数名的实质就是函数的首地址
(1)函数名在C语言中的理解方法和变量名其实没区别。编译器会把这个函数的函数体对应的代码段和这个函数的函数名(实质是符号)对应起来,等我们在使用这个函数名符号时,编译器会将函数的函数体实际上做替换。因为函数体都不止4字节,而函数名这个符号只能对应1个地址,所以实际对应的是函数体那一个代码段的首地址。
(2)拿C语言中的语法来讲,函数名就是这个函数的函数指针。
总结:当我们将异常处理程序的首地址和异常向量表绑定起来后,异常处理初步阶段就完成了。到目前可以保证相应异常发生后,硬件自动跳转到对应异常向量表入口去执行时,可以执行到我们事先绑定的函数。
1.8.5.3、为什么中断处理要先在汇编中进行
(1)中断处理要注意保护现场(中断从SVC模式来,则保存SVC模式下的必要寄存器的值)和恢复现场(中断处理完成后,准备返回SVC模式前,要将保存的SVC模式下的必要寄存器的值恢复回去,不然到了SVC模式后寄存器的值乱了,SVC模式下原来正在进行的常规任务就被你搞坏了)
(2)保存现场包括:第一:设置IRQ栈;第二,保存LR;第三,保存R0~R12
(3)为什么要保存LR寄存器?要考虑中断返回的问题。中断ISR执行完后如何返回SVC模式下去接着执行原来的代码。中断返回其实取决于我们进入中断时如何保存现场。中断返回时关键的2个寄存器就是PC和CPSR。所以我们在进入IRQ模式时,应该将SVC模式下的下一句指令的地址(中断返回地址)和CPSR保存起来,将来恢复时才可以将中断返回地址给PC,将保存的CPSR给CPSR。
(4)中断返回地址就保存在LR中,而CPSR(自动)保存在(IRQ模式下的)SPSR中
1.8.5.4、汇编保存现场和恢复现场
(1)保护现场关键是保存:中断处理程序的返回地址,r0-r12(cpsr是自动保存的)
(2)恢复现场主要是恢复:r0-r12,pc,cpsr
《朱老师物联网大讲堂》学习笔记
学习地址:www.zhulaoshi.org
像内存一样去访问异常向量表。
在我们开发板中iRAM的向量异常表的起始地址为0xd0037400,
结合上节说的,相对地址是固定的,而这里起始地址又确定了,
各种异常对应的入口地址就很好知道了。
函数名的实质就是函数的首地址,拿C语言中的语言来讲,函数名就是这个函数的函数指针,
将异常向量表和异常处理程序的首地址绑定起来后,异常处理初步阶段就完成了,
目前如果相应异常发生后,硬件自动跳转到对应异常向量表入口去执行,进而执行我们事先绑定的函数。
第一眼看到下面的异常向量表绑定,会觉得不知所以,其实前面有宏定义,
#define exception_vector_table_base 0xD0037400
#define exception_reset (exception_vector_table_base + 0x00)
#define r_exception_reset (*(volatile unsigned int *)exception_reset)
[plain] view plain copy
- void system_init_exception(void)
- {
- r_exception_reset = (unsigned int)reset_exception;
- r_exception_undef = (unsigned int)undef_exception;
- r_exception_sotf_int = (unsigned int)sotf_int_exception;
- r_exception_prefetch = (unsigned int)prefetch_exception;
- r_exception_data = (unsigned int)data_exception;
- r_exception_irq = (unsigned int)IRQ_handle;
- r_exception_fiq = (unsigned int)IRQ_handle;
- intc_init();
- }
为什么中断处理要先在汇编中进行,
因为中断是从SVC模式开始的,要保存该模式下必要的寄存器值,
中断完成后返回SVC,恢复这些寄存器的值,
否则SVC模式寄存器的值就乱了,SVC模式下原来正在进行的常规任务就被你破坏了。
现场保存包括
1.设置IRQ栈,各个模式的栈不同,所以各自要单独设置,
ldr sp, IRQ_STACK
sp名字只有一个,不过在不同模式下会自动切换到对应的sp,
2.保存LR,中断返回时2个关键寄存器就是pc和CPSR,
在进入IRQ模式时,应该将SVC模式下的下一句指令的地址和CPSR保存起来,
将来恢复时将返回地址给PC,将保存的CPSR给CPSR,
中断返回地址就保存在LR中,而CPSR自动保存在IRQ的SPSR中,
3.保存R0~R12。
#define IRQ_STACK 0xd0037f80
[cpp] view plain copy
- IRQ_handle:
- ldr sp, IRQ_STACK
- sub lr, lr, #4
- //这里的4这样理解,+8-4,因为是3级指令,
- stmfd sp! {r0-r12, lr}
- bl irq_handler
- ldrfd sp! {r0-r12, pc}^