上电开机:上电能跑就行,可知程序从哪开始执行

讨论问题:

  1. CPU/MCU在设备开机后是如何执行到硬件初始化程序。
  2. 整个固件程序的入口在哪里,是main函数吗?

1.2. 程序从哪开始跑

1.2.1 异常向量表

如果有分析过u-boot 源码,应该对异常向量表不会陌生,但是如果没有分析过u-boot源码,那么51单片机和stm32有异常向量表的说法吗?

stm32是有异常向量表的,对于51单片机相对应的有中断向量。异常向量表就是将各种异常向量和中断向量按序排列组成的一张表。通过这张表找到对应异常或者中断的处理程序入口,每种芯片的异常向量表的异常和中断的类别和排序不一定相同,下图是exynos4412的异常向量表。
图1 exynos4412的异常向量表

1.2.2 为什么需要预定义这些异常和中断向量呢?

试想一下,假如没有预定义这些向量,当CPU在执行的过程中有中断发生,那么CPU该如何去处理中断响应程序。这个中断响应程序位于哪,这都是未知的。而如果预定义了这些向量,那么CPU就可以根据异常或中断的类型,执行该向量地址的指令来响应中断。

1.2.3 程序入口

程序的入口是指程序的第一条指令的地址,而异常向量表一般存放在程序的入口地址。这样设备一上电就执行到复位异常指令,从而去执行编写好的初始化程序。

当然并不是每款芯片的异常向量表的0x00地址偏移量处存放的都是复位指令。就stm32F4xx而言,它的异常向量表的0x00地址偏移量存放的是栈初始化值的地址,而0x04地址偏移量存放的才是复位的入口地址。stm32F4xx在上电后,先从地址 0x00000000 地址取出 MSP 的初始值。再从地址0x00000004取出 PC 的初始值,取出的是复位的入口地址,从这个地址开始执行复位处理程序。

而对于51单片,它的入口地址处的第一条指令又是什么呢?

相信写过51单片机程序的都对主函数main不陌生,经常会听到入口函数就是main函数,那么main函数是否是位于程序的入口地址处呢?

答案是否定的,代码清单1是一段简短的51单片机程序的反汇编和C语言实现。通过汇编指令,不难发现这段程序的第一条指令是LJMP实现的转移指令,将0x0003地址装入PC寄存器;并且在执行主函数main之前还执行了其他指令,例如初始化堆栈寄存器。

/* 代码清单1 */
/* C语言程序 */
#include sbit LED1 = P1^0;
void main()
{
LED1 = 0;
while(1);
}

/* 反汇编程序 */
C:0x0000    020003   LJMP     C:0003
C:0x0003    787F     MOV      R0,#0x7F
C:0x0005    E4       CLR      A
C:0x0006    F6       MOV      @R0,A
C:0x0007    D8FD     DJNZ     R0,C:0006
C:0x0009    758107   MOV      SP(0x81),#0x07
C:0x000C    02000F   LJMP     main(C:000F)

 void main():
C:0x000F     C290     CLR      LED1(0x90.0)
……

那么执行主函数之前的这些指令是怎么来的呢?是集成环境的编译器帮你做的。可能你还会说那主函数不还是main函数;其实不然,函数名main只是汇编语言编写的启动文件中定义的一个符号标签而已。

假如你自己重写底层的汇编启动文件,那么你可以将这个函数名设置成任何你喜欢的名称,这个可以结合前面讲的异常向量表来理解其中的实现原理。

虽然51单片机没有设置异常向量表,但是在启用定时器或者中断时,预定义的中断向量的地址一定是存放着中断响应处理程序的入口地址(代码清单2)。通过这些预定义的中断号,CPU可以很方便的找到中断处理响应程序。

/* 代码清单2 */
/* 中断程序--c语言程序 */
void main()
{
  while(1) {
    P1 = 0xff;
  }
}
void timer0() interrupt 1
{
}

/* 定时器0中断程序--反汇编程序;中断号:0x000BH */
C:0x0000    02000E   LJMP     C:000E
C:0x0003    80FE     SJMP     main(C:0003)
……   
C:0x000B    020005   LJMP     timer0(C:0005)
C:0x000E    787F     MOV      R0,#0x7F
C:0x0010    E4       CLR      A
C:0x0011    F6       MOV      @R0,A
C:0x0012    D8FD     DJNZ     R0,C:0011
C:0x0014    758107   MOV      SP(0x81),#0x07
C:0x0017    020003   LJMP     main(C:0003)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值