44b0启动代码详细解析
- 格式:docx
- 大小:26.49 KB
- 文档页数:20
ARM7(sc44b0)外部中断笔记对于sc44b0它也是一种单片机,一种比较高级的单片机而已,所以他也跟51单片机一样有外部中断,不同51单片机的是,他有8个外部中断源,对应的是8个管脚,(51只有两个,int0和int1,P3.3和P3.4),分别是Port G八个管脚。
而对于外部中断4 \5\6\7很多都是共用寄存器,他们是通过或逻辑公用一个中断请求线。
下面就具体来说说使用外部中断的一些必要的配置。
一,对管脚的配置,因为Port G有三种功能用法,要通过对rPCONG(端口G配置寄存器)的配置来选用Port G的外部中断的功能。
其配置表如下所以应该将其配置为11(设置为中断功能状态);二,中断模式的选择,中断模式有两种,FIQ(快速中断模式)和 IRQ(中断模式)两种,一般没有特殊要求都用IRQ模式即可。
可以通过对中断模式寄存器rINTMOD配置获得。
如表下三,是否允许中断,即中断使能位。
通过对中断控制寄存器INTCON的配置即可,如表下通过对中断控制寄存器的配置即可,可以看出只要让intcon的【1】位置零即可使中断使能。
四,外部中断方式的选择,低电平或上升沿触发呢,还是别的,这就要对外部中断方式寄存器(EXTINT)的配置,其表如下由上表可知,如果要用下降沿触发,就可将EXTINT 的值给0x22222222;将所有的外部中断都设置为下降沿触发。
五,当中断捕抓到以后,要引起什么变化呢?或者说用什么来捕抓呢?在sc44b0中用了两个寄存器来捕抓,一个中断挂起寄存器(INTPND),和外部中断挂起寄存器(EXINTPND),一开始不明白挂起是什么意思,后来才懂,差不多就相当与51单片机的标志位一样,当中断发生后,就将挂起寄存器的对应的某一位置一或置零,外部中断挂起寄存器如表下中断挂起寄存器:当中断产生后,是将INTPND的【21】位置一的;所以,判断有无外部中断,就可以通过读取挂起寄存器对应的为,即可知道是否有无中断。
44B0中断 BIOS分析2009-10-04 15:20一、44B0中断系统44B0 中断系统中有两张中断转移表,经过二重转移才跳到中断处理程序。
第一张中断向量表由硬件决定,所在区域为ROM(flash),地址空间从0X00开始,其中0X00-0X1C为异常向量入口地址,0X20-0XC0为中断向量入口地址。
另一张中断向量表在RAM 中,可以随便改,其位置在程序连接后才定。
由于 RAM 放在地址空间的高端(距离中断向量超过了 32M),为了从第一张中断向量表跳到第二张中断向量表,故在第一张中断向量表对应位置上写上 ldr PC,# interrupt_service 如:ldr PC,=HandlerEINT4567。
1、一级中断向量表(以下为汇编代码片断,详见44B0数据手册11章——中断控制器)AREA Init,CODE,READONLY;说明:关键字ENTRY告诉编译器保留这段代码;从代码看Init段就是要写入0x00地址的原始中断向量,因此把这个文件编译生成的44binit.O和Init填入ADS-Linker-Layout页对应项中。
【这样编译器会把该段代码编译到0X0地址。
】ENTRY ;ENTRY程序入口标号需要顶格式写,否则出错。
b ResetHandler ;复位异常 0x0000 0000b HandlerUndef ;未定义异常 0x0000 0004b HandlerSWI ;软件中断异常 0x0000 0008b HandlerPabort ;指令预取异常 0x0000 000Cb HandlerDabort ;数据预取异常 0x0000 0010b . ;保留 0x0000 0014b HandlerIRQ ;外部中断外设中断都是在这里扩展的 0x0000 0018b HandlerFIQ ;快速中断 0x0000 001C;***IMPORTANT NOTE***;If the H/W vectored interrutp mode is enabled, The above two instructions should;be changed like below, to work-around with H/W bug of S3C44B0X interrupt controller.; b HandlerIRQ -> subs pc,lr,#4; b HandlerIRQ -> subs pc,lr,#4;说明:原文注明当使用向量中断模式时,需用subs pc,lr,#4来代替前面的语句。
U-Boot编译过程与启动入口分析作者:zenf E-Mail: zenf_zhao@版权所有:作者保留文档中的任何文字和图片的版权,任何转载或者商业用途必须获得作者的许可和授权。
(2007 年9 月)说明:本文档基于hfrk 的S3C44B0 开发板配置平台1.1 U-BOOT的编译配置时采用make hfrks3c44b0_config配置,此时调用makefile中的配置功能:hfrks3c44b0_config : unconfig@./mkconfig $(@:_config=) arm s3c44b0 hfrks3c44b0 hfrk命令解析为: ./mkconfig hfrks3c44b0 arm s3c44b0 hfrks3c44b0 hfrk第一参数%1为板子;arm为参数%2 CPU类型;s3c44b0为%3的CPU型号; 后面分别板子名称和厂商。
再分析u-boot的目录中的mkconfig文件,其作用进入include目录,分别建立:asm 和asm-cpu/arch的库软链接,生成config.mk文件,生成config.h文件。
(分析该mkconfig,很简单)即:echo "#include <configs/$1.h>" >>config.h把用户配置的如hfrks3c44b0.h文件加入 config.h中,以被编译模块调用,从而实现自动配置功能。
主makefile的核心编译内容分析,内容如下:########################################################################## U-Boot objects....order is important (i.e. start must be first)OBJS = cpu/$(CPU)/start.oifeq ($(CPU),i386)OBJS += cpu/$(CPU)/start16.oOBJS += cpu/$(CPU)/reset.oendififeq ($(CPU),ppc4xx)OBJS += cpu/$(CPU)/resetvec.oendififeq ($(CPU),mpc85xx)OBJS += cpu/$(CPU)/resetvec.oEndifLIBS = lib_generic/libgeneric.aLIBS += board/$(BOARDDIR)/lib$(BOARD).aLIBS += cpu/$(CPU)/lib$(CPU).aLIBS += lib_$(ARCH)/lib$(ARCH).aLIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a fs/reiserfs/libreiserfs.aLIBS += net/libnet.aLIBS += disk/libdisk.aLIBS += rtc/librtc.aLIBS += dtt/libdtt.aLIBS += drivers/libdrivers.aLIBS += drivers/sk98lin/libsk98lin.aLIBS += post/libpost.a post/cpu/libcpu.aLIBS += common/libcommon.a.PHONY : $(LIBS)# Add GCC libPLATFORM_LIBS += --no-warn-mismatch -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) –lgccSUBDIRS = tools \examples \post \post/cpu.PHONY : $(SUBDIRS)ALL = u-boot.srec u-boot.bin System.mapall: $(ALL)u-boot.srec: u-boot$(OBJCOPY) ${OBJCFLAGS} -O srec $< $@u-boot.bin: u-boot$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@u-boot.img: u-boot.bin./tools/mkimage -A $(ARCH) -T firmware -C none \-a $(TEXT_BASE) -e 0 \-n $(shell sed -n -e 's/.*U_BOOT_VERSION//p' include/version.h | \ sed -e 's/"[ ]*$$/ for $(BOARD) board"/') \-d $< $@u-boot.dis: u-boot$(OBJDUMP) -d $< > $@u-boot: depend $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT)UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) |sed -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\$(LD) $(LDFLAGS) $$UNDEF_SYM $(OBJS) \--start-group $(LIBS) $(PLATFORM_LIBS) --end-group \-Map u-boot.map -o u-boot$(LIBS):$(MAKE) -C `dirname $@`$(SUBDIRS):$(MAKE) -C $@ allgdbtools:$(MAKE) -C tools/gdb || exit 1depend dep:@for dir in $(SUBDIRS) ; do $(MAKE) -C $$dir .depend ; donetags:ctags -w `find $(SUBDIRS) include \lib_generic board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) \fs/cramfs fs/fat fs/fdos fs/jffs2 \net disk rtc dtt drivers drivers/sk98lin common \\( -name CVS -prune \) -o \( -name '*.[ch]' -print \)`etags:etags -a `find $(SUBDIRS) include \\( -name CVS -prune \) -o \( -name '*.[ch]' -print \)`System.map: u-boot@$(NM) $< | \grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | \sort > System.map编译过程解析:先编译tools, examples, post, post/cpu 四个目录关联文件,即depend相关联的生成.depend。
S3C44B0的初始化程序的理解S3C44B0的初始化程序就是初始化各个关键的寄存器,建立中断向量,然后转移到主函数去执行程序。
不过S3C44B0不支持地址映射,所以程序不COPY到RAM种执行。
S3C44B0初始化对我们广大初学者来说,比较难理解的是中断的处理和一些少见的操作符号,S3C44B0的中断子程序地址存放在初始化程序最后就是HandleADC # 4HandleRTC # 4HandleUTXD1 # 4HandleUTXD0 # 4HandleSIO # 4HandleIIC # 4HandleURXD1 # 4HandleURXD0 # 4这一段,它的其实地址是ISR_STARTADDRESS,个人写中断程序的时候,子程序地址被编译器连放在相应的位置。
初始化完成后,程序转通过BL Main 转到用户定义的主程序上执行。
以下是我个人的一些理解,有错误的地方希望大家指出来。
GBLL THUMBCODE[ {CONFIG} = 16THUMBCODE SETL {TRUE}CODE32|THUMBCODE SETL {FALSE}][ THUMBCODECODE32 ;for start-up code for Thumb mode]×××××××××××&ti mes;××××××××××× ;其中[=IF ,|=ELSE ,]= ENDIF, CODE32 表明一下操作都在ARM状态。
44B0中断分析(二)1.文件描述和准备本文将试图讲述44B0X 处理器处理中断的具体过程,如果读者的中断执行不正常,请确保FLASH 中烧录了立宇泰ARMSys’s BootLoader for Linux V1.2,同时ADS 开发环境中的RO Base 为0x0c0008000,RW Base 为0xc5f0000。
本文采用的44BINIT.s 的自叙为:本程序以系统的Timer0 中断为例,中断初始化程序如下:2.调试程序装载后AXD 装载AXF 调试文件后,暂时不运行,PC 指针指示在bResetHandler 处,用右键菜单中的Disassembly,可以看出初始地址实际上指示在0x0c008000,即ADS 中设置的RO Base,表示程序即将从0x0c008000 开始运行。
3.非矢量模式下的执行过程经过以上准备工作,单击【运行】两次后Timer0 中断发生,通过事先设置好的断点捕捉中断,所有图中的红点即为运行前设置的断点:⑴PC-0x0c008000 转到PC-0x00000018 处,即转到Flash 中执行Bootloader 的代码。
猜测地址HandleTIMER0=_IRQ_BASEADDRESS+0x134=0x0c000134,下面来看看猜想对不对。
改rINTCON=0x1 进行矢量中断过程的观察,重新装载程序,再单击【运行】两次后,Time0 中断产生:⑴Timer0 中断产生,跳转到中断矢量地址0x00000060,而不是跳转到IRQ 中断入口0x00000018,这就是非矢量中断和矢量中断的本质区别。
⑵再跳转到0x00000334,注意还是在Flash 中,因此还得归功于Bootloader 黑体所选程序是类似宏调用HandlerTIMER0 HANDLER HandleTIMER0 产生的代码,由于这是在Flash 中,所以不可能是调试时下载进去的。
(不相信可以。
U-Boot 在44B0X 开发板上的移植以及代码分析 [转] 2006.11.16 15:46:01 标签:缩起正文字号:大小1. u-boot 介绍u-boot 是一个open source 的bootloader目前版本是0.4.0。
u-boot 是在pp cboot 以及armboot 的基础上发展而来,虽然宣称是0.4.0 版本,却相当的成熟和稳定,已经在许多嵌入式系统开发过程中被采用。
由于其开发源代码,其支持的开发板众多。
唯一遗憾的是并不支持我们现在学习所用samsung 44B0X 的开发板。
为什么我们需要u-boot?显然可以将ucLinux 直接烧入flash,从而不需要额外的引导装载程序(bootloader)。
但是从软件升级的角度以及程序修补的来说,软件的自动更新非常重要。
事实上,引导装载程序(bootloader)的用途不仅如此,但仅从软件的自动更新的需要就说明我们的开发是必要的。
同时,u-boot 移植的过程也是一个对嵌入式系统包括软硬件以及操作系统加深理解的一个过程。
2. u-boot 移植的框架移植u-boot 到新的开发板上仅需要修改和硬件相关的部分。
在代码结构上:1) 在board 目录下创建ev44b0ii 目录,创建ev44b0ii.c 以及flash.c,mems etup.S,u-boot.lds等。
不需要从零开始,可选择一个相似的目录,直接复制过来,修改文件名以及内容。
我在移植u-boot 过程中,选择的是ep7312 目录。
由于u-boot 已经包含基于s3c24b0 的开发板目录,作为参考,也可以复制相应的目录。
2) 在cpu 目录下创建arm7tdmi 目录,主要包含start.S,interrupts.c 以及c pu.c,serial.c几个文件。
同样不需要从零开始建立文件,直接从arm720t 复制,然后修改相应内容。
3) 在include/configs 目录下添加ev44b0ii.h,在这里放上全局的宏定义等。
44b0使用说明感谢您选择了本公司的产品,本44B0开发板是硬件开发人员参考了网上的许多44B0相关资料开发出来的,板子做工精良,功能强大,具有板载BIOS,极大地方便了调试。
比起其他44B0普通开发板功能大大加强了。
而且价格是相类似性能的开发板中最低的。
首先检查一下您的套件中器件是否齐全:1:开发板一块;2:JTAG仿真器一个;3:串口电缆一根;4:并口电缆一根;5:9V直流电源一个;软件配置:板子全部原理图,armbootload(BIN文件)、uClinux for 44B0(源码)、uCOS-II for 44B0(源码),TEST源码(含所有功能的测试源程序),TFTPD32.exe(TFTPD服务器)、FLUTED.EXE(JTAG烧写软件)。
加强版上可按用户要求配置相应液晶模块(标准配置为320*240; 16级灰度),并提供演示程序源码。
现在就让我们借助这开发板一起了解一下开发套件。
一:板子上电自检的判断:首先把开发板的串口0和计算机的串口相连,打开计算机的超级终端程序,按连接的串口进行相应设置:波特率:115200(如无特别说明,以下均是115200),数据位:8位,无奇偶校验,停止位:1位;数据流控制:无!!(注意!)(连接如图)然后给开发板上电,可以看到,板上的D1,D2,D3三个发光二极管依次闪动(在串口0下面)。
那么说明板载的BIOS已经开始运行了。
同时看计算机的超级终端出现ARMBOOT LOAD的字样,并且显示了RAM,FLASH的相应信息。
这时BIOS开始到计时,在其到0 前按回车键,进入命令模式。
(详情请看附件BIOS 的使用说明)二:看看网口的情况:先连上网线,注意和计算机直接连的话是交叉网线,和HUB相连的话是直连网线,请勿弄错!!如果计算机用的是 W2000,打开开发板的电源,倒计时就后就可以看到屏幕右下脚有网络连接的标志。
同时可以看到发光二极管D6(RJ45边上)闪动,表明正在通过网口下载指定程序。
电脑蓝屏代码大全编号代码含意0 0x00000000 作业完成。
1 0x00000001 不正确的函数。
2 0x00000002 系统找不到指定的档案。
3 0x00000003 系统找不到指定的路径。
4 0x00000004 系统无法开启档案。
5 0x00000005 拒绝存取。
6 0x00000006 无效的代码。
7 0x00000007 储存体控制区块已毁。
8 0x00000008 储存体空间不足,无法处理这个指令。
9 0x00000009 储存体控制区块地址无效。
10 0x0000000A 环境不正确。
11 0x0000000B 尝试加载一个格式错误的程序。
12 0x0000000C 存取码错误。
13 0x0000000D 资料错误。
14 0x0000000E 储存体空间不够,无法完成这项作业。
15 0x0000000F 系统找不到指定的磁盘驱动器。
16 0x00000010 无法移除目录。
16 0x00000010 无法移除目录。
17 0x00000011 系统无法将档案移到其它的磁盘驱动器。
18 0x00000012 没有任何档案。
19 0x00000013 储存媒体为写保护状态。
20 0x00000014 系统找不到指定的装置。
21 0x00000015 装置尚未就绪。
22 0x00000016 装置无法识别指令。
23 0x00000017 资料错误(cyclic redundancy check)24 0x00000018 程序发出一个长度错误的指令。
25 0x00000019 磁盘驱动器在磁盘找不到持定的扇区或磁道。
26 0x0000001A 指定的磁盘或磁盘无法存取。
27 0x0000001B 磁盘驱动器找不到要求的扇区。
28 0x0000001C 打印机没有纸。
29 0x0000001D 系统无法将资料写入指定的磁盘驱动器。
30 0x0000001E 系统无法读取指定的装置。
ADS开发ARM之44B0篇 陈猛(Meterchen)2004-2 meterchen@注:抛砖引玉,希望大家和我交流,多提意见,给我继续写作的动力ADS集成开发环境是ARM公司推出的一款比较好的针对基于ARM core的集成开发环境,主要由两个部分组成:一个是工程管理(编辑及设置)界面(CodeWarrior),一个是调试界面AXD。
之所以说它比较好,个人认为就是两个方面:一方面,ADS比它的前身SDT的编辑及设置界面要好用的多(用过SDT 的人会深有体会),第二个方面,虽然ADS使用的是Metrowerks公司的开发环境外壳,但是底层的汇编器/编译器还是ARM公司自己的,我想ARM公司出的编译器应该效率不会低吧(众所周知,RISC机器的效率很大程度上依赖于编译器的效率)。
由于三星公司的44B0大家都用得比较多,我个人也比较熟(我刚开始用的是44A0,呵呵),我就以44B0作为不具备REMAP功能的ARM芯片的典型代表,来SHOW一下怎么使用ADS来开发基于ARM的应用系统以及解释一下开发中的相关概念,是为抛砖引玉。
第一步,使用ADS建立一个工程,这个大家都会比较熟悉 这个步骤使用过其他集成开发环境的人应该都会比较熟悉,无非就是新建工程、创建文件、添加文件、文件浏览以及文件查找编辑等功能。
以图一所示的工程为例,里面包含了一个汇编文件和三个C文件。
至于其他的关于Project管理方面的高级功能,可以去查阅ADS的手册。
图一第二步,Build(make)这个新建立的工程,生成代码 工程创建后,需要对其进行MAKE操作,以得到可以运行的二进制代码。
Build的过程简单来说包含两个过程:一个是生成目标代码(对C程序是编译,对汇编文件是汇编过程),一个是连接并最终会生成我们的可执行文件(ELF格式)。
在MAKE之前,几个设置尤为重要,直接关系到我们生成的代码是否正确,现一一道来2.1汇编器设置 汇编器包含很多设置,幸运的是,大多数时候我们使用其默认设置即可。
ARM的裸跑试验差不多了,准备上操作系统,可是上操作系统之前还要先搞定Bootloader,Bootloader的第一部分就是汇编代码,也就是启动代码,其实一开始搞裸跑实验的就已经看过启动代码,看着那一句句都是由汇编语句构成的代码,感觉很难,再加上我是在Bootloader启动好得基础上去跑裸跑代码的,所以当时就没深究,可是这块总是一个空白,而现在学Bootloader的时候再次接触了它,于是下定决心一定要把它完全解析透彻,我用的S3C6410,但是6410这方面的资料很少,再加上以前并没有接触过ARM的汇编,对ARM的汇编指令不怎么了解,所以就准备先将最简单的44b0的启动代码搞定,在44b0的基础上在去解析6410的启动代码,经过了一周的奋战终于将44b0的启动代码解析完毕,在解析代码的过程中,学到了很多知识,首先然我熟悉了ARM的指令,比如LDR、STR、CMP等等,以前看到就晕的汇编在现在看来,变得可爱多了,并且顺带也掌握了ARM的指令编码方式,其实解析完44b0的启动代码后,回想一下,其中最难理解的地方就是中断,次之是代码的搬运,它和加载与运行时地址有关,下面准备开始看6410的启动代码,今天先将44b0的启动代码注释笔记贴出,有兴趣的朋友可以看看,呵呵!!; *******************************************************; * NAME : 44BINIT.S *; * Version : 10.JAn.2003 *; * Description: *; * C start up codes *; * Configure memory, Initialize ISR ,stacks *; * Initialize C-variables *; * Fill zeros into zero-initialized C-variables *; *******************************************************GET ..\inc\option.sGET ..\inc\memcfg.s;Interrupt Control 中断寄存器地址《田凯文》INTPND EQU 0x01e00004INTMOD EQU 0x01e00008INTMSK EQU 0x01e0000cI_ISPR EQU 0x01e00020I_CMST EQU 0x01e0001c;Watchdog timer 看门狗控制寄存器地址《田凯文》WTCON EQU 0x01d30000;Clock Controller时钟控制寄存器地址《田凯文》PLLCON EQU 0x01d80000CLKCON EQU 0x01d80004LOCKTIME EQU 0x01d8000c;Memory Controller 存储器寄存器地址《田凯文》REFRESH EQU 0x01c80024BWSCON EQU 0x01c80000;Pre-defined constants 处理器预定义常量《田凯文》USERMODE EQU 0x10FIQMODE EQU 0x11IRQMODE EQU 0x12SVCMODE EQU 0x13ABORTMODE EQU 0x17UNDEFMODE EQU 0x1bMODEMASK EQU 0x1fNOINT EQU 0xc0 ;IRQ、FIQ中断禁止《田凯文》;用来判断是用16位指令集还是32位指令集《田凯文》GBLL THUMBCODE[ {CONFIG} = 16THUMBCODE SETL {TRUE}CODE32|THUMBCODE SETL {FALSE}][ THUMBCODECODE32 ;for start-up code for Thumb mode]MACRO ;宏定义开始,P128《田凯文》;这个宏的功能就是先将r0寄存器中的值存入栈中,接着又将中断函数的入口地址《田凯文》;以r0为中转,存入数据栈中,再通过栈还原r0的值,接着将存入栈中的中断函数的入口地址《田凯文》;取出,送给PC,以实现中断函数的跳转《田凯文》;如果是IRQ中断并且是非向量中断,就会跳转到标号IsrIRQ处,然后再跳转到中断二级向量表《田凯文》;如果是向量中断则通过这一步,直接跳转到中断二级向量表《田凯文》;非向量中断跳转流程:b HandlerIRQ ->HandlerIRQ HANDLER HandleIRQ->IsrIRQ->^_ISR_STARTADDRESS 《田凯文》;向量中断跳转流程:VECTOR_BRANCH ->$HandlerLabel HANDLER $HandleLabel -> ^ _ISR_STARTADDRESS 《田凯文》;向量中断比非向量中断少了一个IsrIRQ《田凯文》$HandlerLabel HANDLER $HandleLabel ;宏名为HANDLER,参数为$HandleLabel《田凯文》$HandlerLabel ;这里定义了一个标号HandlerLabel ,是伪操作《田凯文》sub sp,sp,#4 ;减法指令,sp=sp-4,p66《田凯文》stmfd sp!,{r0} ;这是一个压栈操作,由于它是事先递减方式,所以sp的值先减4,即将r0寄存器中的数据《田凯文》;存入以sp-4的值为地址的内存单元,并且sp的值更新为sp-4《田凯文》;stmfd是对FD类型数据栈操作的指令,因为是FD类型的数据栈《田凯文》;所以栈的地址是递减的,而SP后面的!号,指的是,是否更新基地址寄存器《田凯文》;如果有!号,指令编码对应的W位置1,基地址寄存器,即sp更新,sp=sp-4《田凯文》;这条指令的目的是为了存储r0寄存器的值,因为后面要用到《田凯文》;现在存储,是为了后面的还原《田凯文》;这条指令没有目标寄存器,只有基址寄存器,所以sp代表的就是地址《田凯文》ldr r0,=$HandleLabel ;将标号$HandleLabel的值送给r0,$HandleLabel的值就是存放IsrIRQ的地址,在b ResetHandler 中已经定义过了《田凯文》ldr r0,[r0] ;将以r0的值为地址的内存单元中的数据取出,存入r0寄存器中,《田凯文》; 这条ldr 指令中基址寄存器为r0,即第二个操作数的内存地址为0,p34《田凯文》str r0,[sp,#4] ;将r0的值放入地址为sp+4的存储单元中,这就是前面sp-4的原因,《田凯文》;它是为了给这一步预留存储空间《田凯文》ldmfd sp!,{r0,pc} ;这是一个出栈操作,由于它是事后递增方式,即将以sp的值为地址的内存单元中《田凯文》;的值存入r0寄存器中,即还原r0寄存器中值,stmfd sp!,{r0}这条指令,就是为了这一刻《田凯文》;再将以sp+4的值为地址的内存单元中的数据取出,即[r0]里面的值,也就是中断函数的入口地址《田凯文》;送给PC寄存器,并且sp更新为sp+8,即sp=sp+8《田凯文》;这条指令没有目标寄存器,只有基址寄存器,所以sp代表的就是地址《田凯文》MEND ;宏定义结束《田凯文》IMPORT |Image$$RO$$Limit| ; End of ROM code (=start of ROM data)IMPORT |Image$$RW$$Base| ; Base of RAM to initialiseIMPORT |Image$$ZI$$Base| ; Base and limit of areaIMPORT |Image$$ZI$$Limit| ; to zero initialiseIMPORT Main ; The main entry of mon programAREA Init,CODE,READONLY ;定义一个名为Init的代码段,属性为READONLY《田凯文》ENTRY ;伪操作指定程序的入口点p136《田凯文》b ResetHandler ;for debugb HandlerUndef ;handlerUndefb HandlerSWI ;SWI interrupt handlerb HandlerPabort ;handlerPAbortb HandlerDabort ;handlerDAbortb . ;handlerReservedb HandlerIRQ ;非向量中断跳转到此处《田凯文》b HandlerFIQ;***IMPORTANT NOTE***;If the H/W vectored interrutp mode is enabled, The above two instructions should;be changed like below, to work-around with H/W bug of S3C44B0X interrupt controller. ; b HandlerIRQ -> subs pc,lr,#4; b HandlerIRQ -> subs pc,lr,#4VECTOR_BRANCH ;这是向量中断的入口地址《田凯文》ldr pc,=HandlerEINT0 ;mGA H/W interrupt vector tableldr pc,=HandlerEINT1 ;ldr pc,=HandlerEINT2 ;ldr pc,=HandlerEINT3 ;ldr pc,=HandlerEINT4567 ;ldr pc,=HandlerTICK ;mGAb .b .ldr pc,=HandlerZDMA0 ;mGBldr pc,=HandlerZDMA1 ;ldr pc,=HandlerBDMA0 ;ldr pc,=HandlerBDMA1 ;ldr pc,=HandlerWDT ;ldr pc,=HandlerUERR01 ;mGB b .b .ldr pc,=HandlerTIMER0 ;mGC ldr pc,=HandlerTIMER1 ;ldr pc,=HandlerTIMER2 ;ldr pc,=HandlerTIMER3 ;ldr pc,=HandlerTIMER4 ;ldr pc,=HandlerTIMER5 ;mGC b .b .ldr pc,=HandlerURXD0 ;mGD ldr pc,=HandlerURXD1 ;ldr pc,=HandlerIIC ;ldr pc,=HandlerSIO ;ldr pc,=HandlerUTXD0 ;ldr pc,=HandlerUTXD1 ;mGD b .b .ldr pc,=HandlerRTC ;mGKAb . ;b . ;b . ;b . ;b . ;mGKAb .b .ldr pc,=HandlerADC ;mGKBb . ;b . ;b . ;b . ;b . ;mGKBb .b .;0xe0=EnterPWDNldr pc,=EnterPWDNLTORG ;声明一个数据缓冲池的开始P120《田凯文》HandlerFIQ HANDLER HandleFIQHandlerIRQ HANDLER HandleIRQHandlerUndef HANDLER HandleUndef HandlerSWI HANDLER HandleSWI HandlerDabort HANDLER HandleDabort HandlerPabort HANDLER HandlePabortHandlerADC HANDLER HandleADCHandlerRTC HANDLER HandleRTC HandlerUTXD1 HANDLER HandleUTXD1 HandlerUTXD0 HANDLER HandleUTXD0 HandlerSIO HANDLER HandleSIOHandlerIIC HANDLER HandleIICHandlerURXD1 HANDLER HandleURXD1 HandlerURXD0 HANDLER HandleURXD0 HandlerTIMER5 HANDLER HandleTIMER5 HandlerTIMER4 HANDLER HandleTIMER4 HandlerTIMER3 HANDLER HandleTIMER3 HandlerTIMER2 HANDLER HandleTIMER2HandlerTIMER1 HANDLER HandleTIMER1HandlerTIMER0 HANDLER HandleTIMER0HandlerUERR01 HANDLER HandleUERR01HandlerWDT HANDLER HandleWDTHandlerBDMA1 HANDLER HandleBDMA1HandlerBDMA0 HANDLER HandleBDMA0HandlerZDMA1 HANDLER HandleZDMA1HandlerZDMA0 HANDLER HandleZDMA0HandlerTICK HANDLER HandleTICKHandlerEINT4567 HANDLER HandleEINT4567HandlerEINT3 HANDLER HandleEINT3HandlerEINT2 HANDLER HandleEINT2HandlerEINT1 HANDLER HandleEINT1HandlerEINT0 HANDLER HandleEINT0;One of the following two routines can be used for non-vectored interrupt.IsrIRQ ;using I_ISPR register.;IsrIRQ的作用是,计算出发生的中断,到底是什么中断《田凯文》;只有这样才能跳转到相应的中断服务子程序《田凯文》;仅当中断的类型为非向量中断时,才会跳转到该标号《田凯文》;而向量中断和非向量中断的根本性区别就在于,非向量中断《田凯文》;需要自己计算出到底是哪个中断源,发生的中断,所以非向量中断《田凯文》;要执行这一句,而向量中断是由硬件直接计算出发生中断的类型《田凯文》;所以就不需要执行这一步,直接跳到下一步《田凯文》;非向量中断是通过这一步,跳转到中断二级向量表《田凯文》sub sp,sp,#4 ;减法指令,sp=sp-4,p66《田凯文》stmfd sp!,{r8-r9} ;这是一个压栈操作,由于它是事先递减方式,所以sp的值先减4,即将r9寄存器中的数据《田凯文》;存入以sp-4的值为地址的内存单元,r8寄存器中的数据,存入以sp-8的值为地址的内存单元《田凯文》;并且sp的值更新为sp-8《田凯文》;stmfd是对FD类型数据栈操作的指令,因为是FD类型的数据栈《田凯文》;所以栈的地址是递减的,而SP后面的!号,指的是,是否更新基地址寄存器《田凯文》;如果有!号,指令编码对应的W位置1,基地址寄存器,即sp更新,sp=sp-8《田凯文》;这条指令的目的是为了存储r8,r9寄存器的值,因为后面要用到《田凯文》;现在存储,是为了后面的还原《田凯文》;这条指令没有目标寄存器,只有基址寄存器,所以sp代表的就是地址《田凯文》;IMPORTANT CAUTION;if I_ISPC isn''''t used properly, I_ISPR can be 0 in this routine.ldr r9,=I_ISPR ;将I_ISPR寄存器的地址赋给r9《田凯文》;I_ISPR是44b0中断标示寄存器,通过它可以知道,什么中断发生了《田凯文》;这个寄存器和ARM的种类有关,如果是2440就不是I_ISPR了《田凯文》ldr r9,[r9] ;将I_ISPR寄存器的值赋给r9《田凯文》mov r8,#0x0 ;将r8寄存器清零《田凯文》movs r9,r9,lsr #1 ;将r9寄存器的值左移1位,在赋值给r9,即r9=(r9<<1)《田凯文》;movs 可以分为mov和s,其中mov为传送指令,s指的是《田凯文》;该指令的执行结果会影响CPSR寄存器《田凯文》;由于该指令中包含移位运算,所以移位运算中溢出的值《田凯文》;即为CPSR寄存器中的C位的值,即溢出0,标志位C的值就为0《田凯文》;溢出1,标志位C的值就为1《田凯文》bcs %F1 ;判断条件标志位C的值是否为1,如果为1则执行跳转指令《田凯文》;bcs指令中的cs,是指令执行的条件码,《田凯文》;意思是如果条件标志位C的值是1,则执行跳转指令《田凯文》add r8,r8,#4 ;偏移量加4,执行下一个中断《田凯文》b %B0 ;跳转到标号0处继续执行,直到C值变为1《田凯文》1ldr r9,=HandleADC ;将标号HandleADC的地址送给r9《田凯文》add r9,r9,r8 ;再将r9的值加上偏移量r8,将得到的值送给r9《田凯文》;这个值,就是发生中断的服务程序,入口地址存放的地址《田凯文》ldr r9,[r9] ;将中断服务程序的入口地址,取出送给r9《田凯文》str r9,[sp,#8] ;将r9即中断服务程序的入口地址,送入栈中,[sp,#8]=r9 《田凯文》ldmfd sp!,{r8-r9,pc} ;将r8、r9寄存器中的值还原,并且PC指针指向存放中断函数《田凯文》;入口地址的地址《田凯文》;****************************************************;* START *;****************************************************ResetHandlerldr r0,=WTCON ;将WTCON这个值送给r0《田凯文》ldr r1,=0x0 ;r1寄存器清零《田凯文》str r1,[r0] ;将r1中得值,赋给存储地址为r0的区域,看门狗禁止《田凯文》;ldr为字数据加载指令《田凯文》;str为字数据存储指令《田凯文》ldr r0,=INTMSKldr r1,=0x07ffffffstr r1,[r0] ;禁止所有中断《田凯文》;****************************************************;* Set clock control registers *;****************************************************ldr r0,=LOCKTIMEldr r1,=800 ; count = t_lock * Fin (t_lock=200us, Fin=4MHz) = 800str r1,[r0][ PLLONSTART ;如果PLLONSTART为真《田凯文》ldr r0,=PLLCON ;temporary setting of PLLldr r1,=((M_DIV<<12)+(P_DIV<<4)+S_DIV) ;Fin=10MHz,Fout=66MHzstr r1,[r0] ;设定PCLL的输出时钟为66MHz《田凯文》]ldr r0,=CLKCONldr r1,=0x7ff8 ;All unit block CLK enable 0111 1111 1111 1000str r1,[r0];****************************************************;* Set memory control registers *;****************************************************ldr r0,=SMRDATAldmia r0,{r1-r13} ;加载R0指向的地址上的多字数据,保存到R1~R13中,R0的值更新(地址加1,即加4个字节)。