c语言常量0x33FF,S3C2440中断跳转分析

2440init.s中断跳转分析

最近准备自己写一个S3C2440的启动代码。参阅了一下2440init.s这一启动代码。发现有很多人对于这个启动代码中的异常,特别是像外部中断这样的异常,到底在2440init.s中是如何实现跳转的这一问题有很大的疑惑。现在就我的理解对这个过程做一下解说。说的不一定很好,呵呵,权当消遣吧。另外,这里面的错误肯定会有,大家尽管给我提吧。

首先要大家要明白,特别是初学者,当S3C2440发生异常时,其程序指针是会被强制转换的,这个是硬件自己完成的,不需要我们的干涉。下面这个表格就是具体的强制指针转化表。

地址

异常名称

2440init.s 中的指令

0x00

复位异常

b   ResetHandler

0x04

未定义指令异常

b   HandlerUndef

0x08

软件中断异常

b HandlerSWI

0x0c

指令预取异常

b HandlerPabort

0x10

数据预取异常

b HandlerDabort

0x14

保留

b .

0x18

IRQ中断异常

b HandlerIRQ

0x1c

FIQ中断异常

b HandlerFIQ

现在可以很清楚的知道了。如果S3C2440刚上电或者是复位,那么pc指针被硬件强制转换到0x00地址处,那么按照2440init.s中的指令“b   ResetHandler”,pc会跳转到ResetHandler处继续执行程序。同样,当发生外部中断时,pc指针会被强制转换到0x18处,执行“b HandlerIRQ”这条指令。

接下去,便是讨论程序跳转之后如何运行的了。首先,我们做一个设想,假设S3C 2440只有一个中断(当然这是不可能的了,就连51也有5个中断源。),那么可想而知,程序跳转到HandlerIRQ处就应该执行中断处理函数了。也就是说,我们在C语言中写的中断处理函数的地址应该就是HandlerIRQ的内容了。虽然这个假设不可能,但它可以帮助我们理解。本质上其实就是类似于这样的一个过程,只不过因为S3C2440有那么多的中断源,所以不可能把中断函数的地址直接赋给HandlerIRQ就行了。这中间应该还有一个转换。就是根据不同的、具体的中断源,让HandlerIRQ对应于不同的中断处理函数的地址。

那么接下来看看HandlerIRQ标号后面的内容吧。

HandlerIRQ      HANDLER HandleIRQ

很明显,这里还有一个宏定义在里面,要知道HANDLER的内容,我们可以在2440init.s中查到:

MACRO

$HandlerLabel HANDLER $HandleLabel

$HandlerLabel

sub sp,sp,#4

stmfd sp!,{r0}

ldr     r0,=$HandleLabel

ldr     r0,[r0]

str     r0,[sp,#4]

ldmfd   sp!,{r0,pc}

MEND

下面对这个宏定义做一下说明。首先是MACRO表明了宏定义的开始,MEND则表示了宏定义的结束。这个宏的作用其实就是在不改变任何寄存器的前提下,把pc指针指向$HandleLabel。

明白了这个以后,我们就可以把这个宏去掉再来理解一遍:

首先是当S3C2440发生外部中断时,pc指针被强制指向了0x18处:

b HandlerIRQ

……

HandlerIRQ

sub sp,sp,#4

stmfd sp!,{r0}

ldr     r0,=HandleIRQ

ldr     r0,[r0]

str     r0,[sp,#4]

ldmfd   sp!,{r0,pc}

经过上面的程序后,此时的pc指针已经指向了HandleIRQ处。呵呵,挺简单的吧。然后

呢。我们就得关注一下HandleIRQ这个标号了。它在2440init.s中设这样定义的:

^   _ISR_STARTADDRESS ; _ISR_STARTADDRESS=0x33FF_FF00

HandleReset  #   4

HandleUndef  #   4

HandleSWI #   4

HandlePabort    #   4

HandleDabort    #   4

HandleReserved  #   4

HandleIRQ #   4

HandleFIQ #   4

HandleEINT0 #   4

HandleEINT1 #   4

HandleEINT2 #   4

HandleEINT3 #   4

……

很简单,这里定义了一个文字池,首地址:_ISR_STARTADDRESS代表了地址为0x33FF_FF00的内存区域,每隔4个字节,定义一个标号。很很容易就找到了 HandleIRQ这个我们需要找的标号。那么它所代表的内存区域自然就是0x33FF_FF00+0x04*6的内存地址了。那么接下来的工作就是要把真正的、具体的中断处理函数的地址赋给HandleIRQ了。这里大家先看一下下面的两端代码:

(1):

ldr r0,=HandleIRQ       ;This routine is needed

ldr r1,=IsrIRQ   ;if there isn't 'subs pc,lr,#4' at 0x18, 0x1c

str r1,[r0]

(2):

IsrIRQ

sub sp,sp,#4       ;reserved for PC

stmfd sp!,{r8-r9}

ldr r9,=INTOFFSET

ldr r9,[r9]

ldr r8,=HandleEINT0

add r8,r8,r9,lsl #2

ldr r8,[r8]

str r8,[sp,#8]

ldmfd sp!,{r8-r9,pc}

首先我们来看一下第(1)段程序,前面已经提到,此时的的pc已经指向了HandeIRQ所表示的内存了,但是现在该内存还是空的,pc跳转到这里也不能接着往下运行了。所以才有了第1段代码,它的作用就是给HandleIRQ安装句柄了,把IsrIRQ的入口地址填充到了HandeIRQ里面了。所以程序接着就会跳转到IsrIRQ处执行。也就是上面的第(2)段程序了。这段程序具体讲解我就不说了,跟最上面的宏定义很类似,其实就是让PC跳转到另外一个地方(pc=HandleEINT0+INTOFFSET*4)。而那个地方正是真正的中断函数。那我们再来看看这个地址是怎么算出来的。首先HandleEINT0就是上面那个MAP定义里面的一个内存区域,有没有发现它是第一个中断源,紧接着它,就是其它各种类型的中断源了。而INTOFFSET则是S3C2440的一个特殊功能寄存器了,某个类型的中断发生了,它的值就会发生变化。而后面为什么要乘以4呢,因为文字池中定义的标号都是4字节的,其实是因为S3C2440中指针变量就是占据4个字节的,这个可以用sizeof(*p)来验证。所以此时pc指针就指向了另外一个地方,那就是刚才说的中断表了。而在c语言中,我们通常会有这样的中断函数句柄安装语句:pISR_EINTn = (unsigned int )key_interrupt;

这里的pISR_EINTn其实是有定义的,我们以pISR_EINT0为例,宏定义如下:

#define pISR_EINT0    _ISR_STARTADDRESS+0X20

看这个地址,其实就是上面那个中断表里面的:

^   _ISR_STARTADDRESS ; _ISR_STARTADDRESS=0x33FF_FF00

……

HandleEINT0 #   4

HandleEINT1 #   4

HandleEINT2 #   4

HandleEINT3 #   4

……

大家发现了吧,HandleEINT0的地址是不是就是 _ISR_STARTADDRESS+0X20,所以说c语言中我们写的中断函数安装句柄,就是这个作用。

好的,现在让我们来总结一下吧。(以外部中断0为例)

首先是在c语言的函数中,我们已经执行了这样一条语句pISR_EINTn = (unsigned int )key_interrupt;它的作用是把中断处理函数key_interrupt的地址赋给了中断表中的HandleEINT0。

然后当某个时刻,发生了外部中断0,那么pc指针被强制指向了0x18处,执行指令:

b  HandlerIRQ

跳转到HandlerIRQ之后,执行如下代码:(已经把宏定义屏蔽)

HandlerIRQ

sub sp,sp,#4

stmfd sp!,{r0}

ldr     r0,=HandleIRQ

ldr     r0,[r0]

str     r0,[sp,#4]

ldmfd   sp!,{r0,pc}

然后pc之争有指向了HandleIRQ这个内存区域。而又由于HandlerIRQ已经被安装了IsrIRQ的句柄,所以紧接着pc又跳转到IsrIRQ处执行如下程序:

IsrIRQ

sub sp,sp,#4       ;reserved for PC

stmfd sp!,{r8-r9}

ldr r9,=INTOFFSET

ldr r9,[r9]

ldr r8,=HandleEINT0

add r8,r8,r9,lsl #2

ldr r8,[r8]

str r8,[sp,#8]

ldmfd sp!,{r8-r9,pc}

它的作用是让pc指针根据INTOFFSET的值跳转到中断向量表中的HandleEINT0处。而在此处已经被安装了c语言中的中断处理函数的句柄,所以pc又跳到了中断处理函数中区执行中断函数了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值