GNU μC/OS-II 在 S3C2440 上中断的实现

时间:2025-05-06 12:32:50

上一篇文章介绍了S3c2440的中断体系结构,今天我们来分析一下GNU-uC/OS-II在S3c2440上中断的实现。

首先找到IRQ的中断的向量,位于 2440init.S :

GNU μC/OS-II 在 S3C2440 上中断的实现

OK ,我们通过名字找到了这个函数:

OS_CPU_IRQ_ISR:

	STMFD   SP!, {R1-R3}
MOV R1, SP
ADD SP, SP, #12
SUB R2, LR, #4 MRS R3, SPSR MSR CPSR_cxsf, #SVCMODE|NOINT STMFD SP!, {R2}
STMFD SP!, {R4-R12, LR} LDMFD R1!, {R4-R6}
STMFD SP!, {R4-R6}
STMFD SP!, {R0} STMFD SP!, {R3}
LDR R0,=OSIntNesting
LDRB R1,[R0]
ADD R1,R1,#1
STRB R1,[R0] CMP R1,#1
BNE 1f LDR R4,=OSTCBCur
LDR R5,[R4]
STR SP,[R5]
1:
MSR CPSR_c,#IRQMODE|NOINT
LDR R0, =INTOFFSET
LDR R0, [R0]
LDR R1, =INTMSK
LDR R1, [R1]
MOV R3, #1
LSL R4, R3,R0
TST R4, R1
BNE 2f LDR R1, =IRQ_STARTADDRESS
MOV LR, PC
LDR PC, [R1, R0, LSL #2] 2:
LDR R0, =INTOFFSET
LDR R0, [R0]
MOV R1, #1
MOV R1, R1, LSL R0
LDR R0, =SRCPND
LDR R2, [R0]
ORR R2, R1,R2
STR R2, [R0] LDR R0, =INTPND
LDR R2, [R0]
ORR R2, R1,R2
STR R2, [R0] MSR CPSR_c,#SVCMODE|NOINT
BL OSIntExit LDMFD SP!,{R4}
MSR SPSR_cxsf,R4
LDMFD SP!,{R0-R12,LR,PC}^

有点长,我们挑关键的部分分析。

看这三行代码:

LDR     R1, =IRQ_STARTADDRESS
MOV LR, PC
LDR PC, [R1, R0, LSL #2]

IRQ_STARTADDRESS 是这样定义的:

.equ IRQ_STARTADDRESS , 0x33ffff00

当前PC保存到LR,然后PC直接跳到了 R1 + R0 * 4 这个地址处(LSL #2 代表左移2位,相当于 *4)。

R0的值来自这个寄存器:

LDR     R0, =INTOFFSET
LDR R0, [R0]

上一篇文章中我们也说过了,INTOFFSET 这个寄存器可以查出当前是哪个中断源在发生请求。

假如现在Timer1请求中断,那么 INTOFFSET 的值就是 11.

R1 + R0 * 4 的结果计算得出就是 0x33FFFF2C 。

这个地址处是什么数据呢?

我们在Timer初始化程序中找到了这个:

pIRQ_TIMER1 = (uint32)OSTickISR;

头文件中找到了这个:

GNU μC/OS-II 在 S3C2440 上中断的实现

OK,这样就在 0x33FFFF2C 地址处存储了 OSTickISR 的入口地址,从而就执行了Timer1的中断服务程序。

执行完ISR之后,汇编的那段程序之后又完成了清中断的操作。

其实在这个过程中有一个要点容易被忽视,IRQ异常发生时,PC跳转到异常向量处,那么IRQ异常向量应该存储在 0x18 这个位置处的啊,可我们一开始说到的是执行 "b OS_CPU_IRQ_ISR" 这条语句,它的地址应该是0x30000018呀(我们的程序在SDRAM中运行,如图定义):

GNU μC/OS-II 在 S3C2440 上中断的实现

可为什么执行的是它呢?

这个时候MMU这位大将就要派上用场了,程序中通过这条语句将地址做了映射,

MMU_SetMTT(0x00000000,0x03f00000,(uint32)_start,RW_CB)

所以找到的就是0x30000018位置处的向量啦。

相关文章