ARM9学习4-S3C2410的启动代码分析-For ADSv1.2

2019-11-08来源: 51hei关键字:ARM9  S3C2410  启动代码  ADSv1  2

通常,启动代码是指CPU复位后到进入C语言的main函数之前需要执行的那段汇编代码.这是由于C语言程序的运行需要具备一定的条件,比如:分配好外部数据空闿堆栈空间和中断入口等筿另外汇编代码可以更直接的对硬件进行操使效率更高. 通常启动代码是放在2410init.s汇编文件;特殊功能寄存器定义在2410addr.s;Memory Bank 配置在mencfg.s;还有系统的选项等在option.s文件;2410init.s不仅包括复位后执行的代码,还包括CPU进入掉电模式,产生中断等和处理器直接相关的,用汇编实现的代码.
;=========================================
; NAME: 2410INIT.S
; DESC: C start up codes
;       Configure memory, ISR ,stacks
; Initialize C-variables
; HISTORY:
; 2002.02.25:kwtark: ver 0.0
; 2002.03.20:purnnamu: Add some functions for testing STOP,POWER_OFF mode
; 2003.05.19:jcs:Configure UPLL in init.s not usbmain.c
;=========================================
  //首先,启动代码定义了一些常量 ,相当于C中的INCLUDE
GET option.inc
GET memcfg.inc
GET 2410addr.inc

BIT_SELFREFRESH EQU (1<<22) //自刷新常量
//;;处理器模式常量 
USERMODE    EQU  0x10
FIQMODE     EQU  0x11
IRQMODE     EQU  0x12
SVCMODE     EQU  0x13
ABORTMODE   EQU  0x17
UNDEFMODE   EQU  0x1b
MODEMASK    EQU  0x1f  //系统模式
NOINT           EQU  0xc0  //屏蔽所有的中断,即置位I,F位
//;The location of stacks 定义处理器各模式下堆栈地址常量 
UserStack        EQU (_STACK_BASEADDRESS-0x3800) ;0x33ff4800 ~ 
SVCStack        EQU (_STACK_BASEADDRESS-0x2800)  ;0x33ff5800 ~
UndefStack      EQU (_STACK_BASEADDRESS-0x2400)  ;0x33ff5c00 ~
AbortStack       EQU (_STACK_BASEADDRESS-0x2000)  ;0x33ff6000 ~
IRQStack         EQU (_STACK_BASEADDRESS-0x1000)  ;0x33ff7000 ~
FIQStack         EQU (_STACK_BASEADDRESS-0x0)        ;0x33ff8000 ~ 
;check if tasm.exe is used.
;arm处理器有两种工作状态 1.arm:32位 这种工作状态下执行字对准的arm指令 2.Thumb:16位 这种工作状态执行半字对准的Thumb指令
;因为处理器分为16位 32位两种工作状态程序的编译器也是分16位和32两种编译方式 所以下面的程序用于根据处理器工作状态确定编译器编译方式
;code16伪指令指示汇编编译器后面的指令为16位的thumb指令
;code32伪指令指示汇编编译器后面的指令为32位的arm指令
;这段是为了统一目前的处理器工作状态和软件编译方式(16位编译环境使用tasm.exe编译)
GBLL THUMBCODE ;设置一个全局逻辑变量
[ {CONFIG} = 16 ;if config==16 这里表示你的目前处于领先地16位编译方式,{CONFIG}为汇编器内置变量
THUMBCODE SETL {TRUE} ;设置THUMBCODE 为 true
CODE32 ;转入32位编译模式
|      ;else
THUMBCODE SETL {FALSE} ;设置THUMBCODE 为 false

[ THUMBCODE     ;if THUMBCODE==TRUE
CODE32          ;for start-up code for Thumb mode;转入32位编译方式
]

;注意下面这段程序是个宏定义 很多人对这段程序不理解 我再次强调这是一个宏定义 所以大家要注意了下面包含的HandlerXXX HANDLER HandleXXX将都被下面这段程序展开。

;这段程序用于把中断服务程序的首地址装载到pc中,有人称之为“加载程序”。其大致作用是把宏的第一个参数$HandlerLabel转变为一个标号,然后让程序跳转到第二个参数 $HandleLabel(第二个参数应该为一个地址)对应的值的地址去。可以分析出,sp和r0在执行前后都没有变化,程序就实现了跳转

;本初始化程序定义了一个数据区(在文件最后),34个字空间,存放相应中断服务程序的首地址。每个字空间都有一个标号,以Handle***命名。

;在向量中断模式下使用“加载程序”来执行中断服务程序。

;这里就必须讲一下向量中断模式和非向量中断模式的概念

;向量中断模式是当cpu读取位于0x18处的IRQ中断指令的时候,系统自动读取对应于该中断源确定地址上的指令取代0x18处的指令,通过跳转指令系统就直接跳转到对应地址

;函数中 节省了中断处理时间提高了中断处理速度标 例如 ADC中断的向量地址为0xC0,则在0xC0处放如下代码:ldr PC,=HandlerADC 当ADC中断产生的时候系统会

;自动跳转到HandlerADC函数中

;非向量中断模式处理方式是一种传统的中断处理方法,当系统产生中断的时候,系统将interrupt pending寄存器中对应标志位置位 然后跳转到位于0x18处的统一中断

;函数中 该函数通过读取interrupt pending寄存器中对应标志位 来判断中断源 并根据优先级关系再跳到对应中断源的处理代码中

MACRO 
$HandlerLabel HANDLER $HandleLabel    //
$HandlerLabel 
sub sp,sp,#4                     ;减少sp(预留一个字,用于存放转跳地址) 
stmfd sp!,{r0}                    ;把工作寄存器压入栈(lr does not push because it return to original address) 
ldr     r0,=$HandleLabel    ;将HandleXXX的址址放入r0 
ldr     r0,[r0]                       ;把HandleXXX所指向的内容(也就是中断程序的入口)放入r0 
str     r0,[sp,#4]                  ;把中断服务程序(ISR)压入栈,保存在高一个地址预留的空间中,但SP没变。 
ldmfd   sp!,{r0,pc}              ;用出栈的方式恢复r0的原值和为pc设定新值(也就完成了到ISR的转跳) ;

                   ADS仅支持FD(满递减)型堆栈,故只能用stmfd和ldmfd
MEND

;========================================================================================
//在这里用IMPORT伪指令(和c语言的extren一样)引入|Image$$RO$$Base|,|Image$$RO$$Limit|...
//这些变量是通过ADS的工程设置里面设定的RO Base和RW Base设定的,最终由编译脚本和连接程序导入程序. 
//那为什么要引入这玩意呢,最简单的用处是可以根据它们拷贝自已 ,从把RW和ZI变量从加载域中复制到运行域中
//一个arm由RO,RW,ZI三个断组成 其中RO为代码段,RW是已经初始化的全局变量,ZI是未初始化的全局变量(对于GNU工具 对应的概念是TEXT ,DATA,BSS)。

;========================================================================================
IMPORT  |Image$$RO$$Base|    ; ROM code(也就是代码)的开始地址 
IMPORT  |Image$$RO$$Limit|    ; ROM code的结束地址 (也就是RW在加载域中的起始地址) 
IMPORT  |Image$$RW$$Base|   ; 在运行域中要初始化的RAM的开始地址 
IMPORT  |Image$$ZI$$Base|      ; area(需要清零的RAM区域)的开始地址 
IMPORT  |Image$$ZI$$Limit|       ; area的结束地址 

;这里引入一些在其它文件中实现在函数,包括为我们所熟知的main函数
IMPORT  Main    ; The main entry of mon program 
;从这里开始就是正真的代码入口了! 
AREA    Init,CODE,READONLY       ;这表明下面的是一个名为Init的代码段 
ENTRY                                            ;定义程序的入口(调试用) 其中关键字ENTRY是指定编译器保留这段代码,因为
                                                       编译器可能会认为这是一段亢余代码而加以优化。链接的时候要确保这段代码
                                                         被链接在0地址处,并且作为整个程序的入口 
;1)The code, which converts to Big-endian, should be in little endian code. 
;2)The following little endian code will be compiled in Big-Endian mode. 
;  The code byte order should be changed as the memory bus width. 
;3)The pseudo instruction,DCD can not be used here because the linker generates error. 
ASSERT :DEF:ENDIAN_CHANGE 
[ ENDIAN_CHANGE                         ;下面是大小端的一个判断,在Option.inc里已经设为FALSE 
     ASSERT  :DEF:ENTRY_BUS_WIDTH 
     [ ENTRY_BUS_WIDTH=32          //‘[’=IF
      b ChangeBigEndian                  ;DCD 0xea000007 
     ] 

     [ ENTRY_BUS_WIDTH=16            
      andeq r14,r7,r0,lsl #20              ;DCD 0x0007ea00 
     ] 

     [ ENTRY_BUS_WIDTH=8 
      streq r0,[r0,-r10,ror #1]             ;DCD 0x070000ea 
     ] 

     b ResetHandler ;因为设成FALSE,所以系统复位后就来到这了,转跳到复位程序入口 
    ] 
//=====================================================================================
;ARM要求中断向量表必须放置在仿地址开始,连续8X4字节的空间内.每当一个中断发生以后,ARM处理器便强制把PC指针置为向量表中对应中断类型的地址值。因为每个中断只占据向量表中1个字的存储空间,只能放置一条ARM指令,使程序跳转到存储器的其他地方,再执行中断处理 
//=====================================================================================
b HandlerUndef           ;转跳到Undefined mode程序入口 
b HandlerSWI              ;转跳到SWI 中断程序入口 
b HandlerPabort          ;转跳到PAbort(指令异常)程序入口 
b HandlerDabort          ;转跳到DAbort(数据异常)程序入口 
b .                                ;保留 
b HandlerIRQ              ;转跳到IRQ 中断程序入口 
b HandlerFIQ              ;转跳到FIQ 中断程序入口 
;@0x20 不知道是什么意思,地址?
b EnterPWDN ; Must be @0x20.
;================================================================================== 
;下面是改变大小端的程序,这里采用直接定义机器码的方式,至说为什么这么做就得问三星了 
;反正我们程序里这段代码也不会去执行,不用去管它 
;================================================================================== 
ChangeBigEndian    //通过设置CP15中的C1的位7来设置存储格式为大端模式。
;@0x24 
[ ENTRY_BUS_WIDTH=32 
     DCD 0xee110f10 ;0xee110f10 => mrc p15,0,r0,c1,c0,0 
     DCD 0xe3800080 ;0xe3800080 => orr r0,r0,#0x80;  //Big-endian 
     DCD 0xee010f10 ;0xee010f10 => mcr p15,0,r0,c1,c0,0 

[ ENTRY_BUS_WIDTH=16 
     DCD 0x0f10ee11 
     DCD 0x0080e380 
     DCD 0x0f10ee01 

[ ENTRY_BUS_WIDTH=8 
     DCD 0x100f11ee 
     DCD 0x800080e3 
     DCD 0x100f01ee 
    ] 
DCD 0xffffffff  ;swinv 0xffffff is similar with NOP and run well in both endian mode. 
DCD 0xffffffff 
DCD 0xffffffff 
DCD 0xffffffff 
DCD 0xffffffff 
b ResetHandler 
;Function for entering power down mode,下面这段程序为进入掉电模式及从掉电模式中唤醒的相关设置和处理
; 1. SDRAM should be in self-refresh mode. SDRAm应该设置为自刷新的模式
; 2. All interrupt should be maksked for SDRAM/DRAM self-refresh. 所有中断必须屏蔽 for SDRAM/DRAM self-ref
; 3. LCD controller should be disabled for SDRAM/DRAM self-refresh. LCD 控制器关闭
; 4. The I-cache may have to be turned on.   
; 5. The location of the following code may have not to be changed.
//;void EnterPWDN(int CLKCON);           //PWDN:powerdown
EnterPWDN   
mov r2,r0  ;r2=rCLKCON                 //rCLKCONr [3;2]位为电源模式标置位。若[3]为1,表示转为了掉电模式
tst r0,#0x8  ;POWER_OFF mode?   //按位与判断,若[3]为1则跳转到ENTER_POWER_OFF
bne ENTER_POWER_OFF
ENTER_STOP                              //进入停止模式相关处理
ldr r0,=REFRESH  
ldr r3,[r0]  ;r3=rREFRESH 
mov r1, r3
orr r1, r1, #BIT_SELFREFRESH
str r1, [r0]                                      ;Enable SDRAM self-refresh
mov r1,#16                                   ;wait until self-refresh is issued. may not be needed.等待自刷新生效
0 subs r1,r1,#1
bne %B0                                     //表示不相等则往回跳转到标号为0的位置,在此为上一句。
ldr r0,=CLKCON                         ;enter STOP mode.
str r2,[r0]    
mov r1,#32
0 subs r1,r1,#1                           ;1) wait until the STOP mode is in effect.
bne %B0                                   ;2) Or wait here until the CPU&Peripherals will be turned-off
                                                 ;   Entering POWER_OFF mode, only the reset by wake-up is available.
                                                   //进入掉电 模式后,仅唤醒中断有效
ldr r0,=REFRESH                       ;exit from SDRAM self refresh mode.
str r3,[r0]

MOV_PC_LR                            //开始处定义的返回跳转宏
ENTER_POWER_OFF 
;NOTE.注意在rGSTATUS3寄存器中应该保存掉电模式唤醒的返回地址,rGSTATUS3,4可在掉电下保存信息
;1) rGSTATUS3 should have the return address after wake-up from POWER_OFF mode.

ldr r0,=REFRESH  
ldr r1,[r0]  ;r1=rREFRESH 
orr r1, r1, #BIT_SELFREFRESH
str r1, [r0]  ;Enable SDRAM self-refresh
mov r1,#16     ;Wait until self-refresh is issued,which may not be needed.
0 subs r1,r1,#1
bne %B0
ldr  r1,=MISCCR
ldr r0,[r1]
orr r0,r0,#(7<<17)  ;Make sure that SCLK0:SCLK->0, SCLK1:SCLK->0, SCKE=L during boot-up 
str r0,[r1]
ldr r0,=CLKCON
str r2,[r0]    
b .   ;CPU will die here.

;=================================================================================

[1] [2]
关键字:ARM9  S3C2410  启动代码  ADSv1  2 编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic479386.html 本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:对于51单片机和arm9开发板串口通信问题的分析
下一篇:ARM9学习3-调试第一个ARM汇编程序

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

几乎是每个arm程序必备的启动代码
启动代码是几乎是每个arm程序程序必备的,刚开始看的时候看别人的启动代码时感觉云里雾里,所以懒惰的想法浮现脑中:别人都写好了我还写什么,直接拿来用不就行了,对在我懂得情况下,我一定会拿来就用,但是现在我还不懂,一切就要从头开始,经过几天的努力,现在的感觉是启动代码不过如此 :) ,呵呵。 ;--------------------------------------------------------------------- ;startup.s ;系统启动代码 ;起始时间 : 2009.5.7 ----->2009.5.11 
发表于 2019-11-11
几乎是每个arm程序必备的启动代码
多年来苹果基于ARM的Mac并不遥远
今日,外媒MacRumors发文表示,苹果公司目前在Mac系列产品中使用的处理器都依赖于英特尔,但这种情况可能很快会改变。ARM与Intel目前,苹果在所有Mac产品中都使用了Intel的x86芯片,iPhone和iPad则使用基于Arm的芯片。x86芯片和Arm芯片使用了不同的架构。英特尔的芯片是CISC(复杂指令集)架构,而Arm芯片是RISC(精简指令集)架构。顾名思义,RISC指令比CISC指令更小、更简单。这也意味着Arm处理器所需的功率更少,且执行计算任务的效率更高。从历史上看,Arm芯片的功能并不强大,因为x86芯片是为台式机设计,而Arm芯片则是为低功耗应用(如移动设备)设计的。过去,Arm一直专注于电源效率
发表于 2019-11-08
S3C2410启动代码从ADSv1.2移植到KEIL For ARM uV4的方法
深圳旋极ARM9实验箱上面的ARM9实验教程是基于ADSv1.2 和 Mult-ICE2.2并口仿真器的,大概是04~09年期间流行的开发方式。目前ARM公司主推RVMDK(KEIL For ARM uVsion4)和ULINK(中国ARM玩家主要是JLINK V8)仿真器了,怎么把原来的ADS程序移植到KEIL上面呢?经过分析ADS工程下面的文件,可以看到,原来的工程文件主程序是main.C,其他必须的汇编文件、C头文件、C源文件都放在common和include目录下。首先我们需要把这些工程都需要的基本文件都copy出来,放到一个“基本文件”目录下。里面的“DebugInRAM.ini“文件,是通过JTAG将镜像文件下载
发表于 2019-11-08
S3C2410启动代码从ADSv1.2移植到KEIL For ARM uV4的方法
ARM9学习2-ARM镜像文件和Scatter文件
ARM映像文件什么是arm的映像文件    arm映像文件其实就是可执行文件,包括bin或hex两种格式,可以直接烧到rom里执行。在axd调试过程中,我们调试的是axf文件,其实这也是一种映像文件,它只是在bin文件中加了一个文件头和一些调试信息。映像文件的组成ARM映像文件是一个层次性结构的文件,包括了域(region),输出段(output section)和输入段(input section)。所谓域,指的就是整个bin映像文件所处在的区域,它又分为加载域和运行域。加载域就是映像文件被静态存放的工作区域,一般来说flash里的 整个bin文件所在的地址空间就是加载域,当然在程序一般都不会放在
发表于 2019-11-08
ARM9学习2-ARM镜像文件和Scatter文件
ARM9学习3-调试第一个ARM汇编程序
调试第一个ARM汇编程序1.双击KEIL uVision4图标,打开RVMDK uVision4集成开发环境。2.通过菜单“projectnew uvision project…”,新建一个工程,选择要存放的位置和工程文件名“Test001”,点击“保存按钮”。3.CPU选型,选择三星的S3C2410A,继续点击“OK”按钮。4.不添加启动代码,所以选择“否”5.点击工具栏上的“”New 图标,新建一个文件,键入汇编源代码。6.点击工具栏上的“”Save 图标,保存该汇编源文件,命名为:Test001.s7.在左边的“Project”目录结构中,右击“Source Group 1”,选择“Add Files to Group
发表于 2019-11-08
ARM9学习3-调试第一个ARM汇编程序
STM8S003的GPIO模拟I2C切换输入输出的解决办法
刚开始学STM8,很多东西刚了解,正在做一个温湿度显示小板,就是使用I2C驱动SHT20传感器,并显示到数码管,数码管用的四位一体共阴数码管,STM8管脚有限,添加了一片TM1650做驱动,不过SHT20和TM1650都是用的I2C接口,由于对STM8硬件I2C还不了解,先打算用软件模拟,这就涉及到需要对GPIO做输入输出切换处理来检测ACK响应,刚开始,直接操作DDR寄存器,但是出现从输出切换到输入就会出现单片机死机,不解,查资料,得到一个解决办法,在输出状态时,可以不用切换到输入,我使用管脚D4,D5这两个管脚,这两个管脚比较特殊,就是真正开漏,在管脚描述为T,其它描述为HS(高吸收电流)。解决办法,将IO设置为开漏输出,外部
发表于 2019-11-11
小广播
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2019 EEWORLD.com.cn, Inc. All rights reserved