由于片面问题,所以可能会看起来不太美观,可以看附件中的内容。
ARM启动代码相当于我们电脑的BIOS,也就是ARM启动时对处理器的一些初始化及嵌入式系统硬件的一些初始化。由于它直接面对处理器内核和硬件控制器进行编程,一般都是用汇编语言。一般包括:中断向量表,初始化存储器系统,初始化堆栈,初始化有特殊要求的断口,设备初始化,变量初始化等。这几天对着RealView MDK-ARM中自带的启动代码研究了一下,遇到问题又对着数据手册和指令表看了一下,总算对S3C2440A的硬件有了一个大致的了解。学习嵌入式系统重在系统,学习ARM只是为学习嵌入式系统铺路,懒猫比较笨可能在上系统之前要裸奔几天以强化以下对S3C2440A内部结构的了解。
把MDK自带的S3C2440A.S文件的注释发一下,这些是懒猫结合数据手册与ARM指令表理解了,可能会有错误,放在这里只是引导一下像我一样还没有入门的兄弟们,希望你们不要害怕ARM害怕嵌入式,老毛他老人家说的对,世上无难事,只怕有心人,ARM指令就那么多,看一遍不会就多看几遍,还有一定要学习看软件自带的帮助文件.
;/*****************************************************************************/
;/* S3C2440.S: Startup file for Samsung S3C440 */
;/*****************************************************************************/
;/* <<< Use Configuration Wizard in Context Menu >>> */
;/*****************************************************************************/
;/* This file is part of the uVision/ARM development tools. */
;/* Copyright (c) 2005-2008 Keil Software. All rights reserved. */
;/* This software may only be used under the terms of a valid, current, */
;/* end user licence from KEIL for a compatible version of KEIL software */
;/* development tools. Nothing else gives you the right to use this software. */
;/*****************************************************************************/
;下面这些参数是与CPSR状态寄存器有关
;参数的由来:这里各个模式的参数是由寄存器CPSR的模式位设置M[4:0]得来的,
;比如这里的用户模式,CPSR的M[4:0]设置为10000就是0x10。
;
;Mode_USR -- 用户模式,正常程序执行模式,用于应用程序
;Mode_FIQ -- 快速中断模式,用于高速数据传输和通道处理。
;Mode_IRQ -- 外部中断模式,用于通用的中断处理。
;Mode_SVC -- 管理模式,使用的一种保护模式。
;Mode_ABT -- 数据访问中止模式,用于虚拟存储用存储保护
;Mode_UND -- 未定义指令中止模式,当未定义指令执行时进入此模式。
;Mode_SYS -- 系统模式,用于特权级的操作系统任务。
;I_Bit -- 如果I位被置1,则外部中断被禁止(IRQ is disabled)
;F_Bit -- 如果F位被置1,则快速中断被禁止(FIQ is disabled)
;
;----------------------------------------------------------------------
Mode_USR EQU 0x10
Mode_FIQ EQU 0x11
Mode_IRQ EQU 0x12
Mode_SVC EQU 0x13
Mode_ABT EQU 0x17
Mode_UND EQU 0x1B
Mode_SYS EQU 0x1F
I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled
F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled
;-----------------------------栈初始化定义-----------------------------------
;下面这些主要是栈配置,系统的栈空间设定
;
;UND_Stack_Size -- 未定义模式的栈大小
;SVC_Stack_Size -- 超级用户模式的栈大小
;ABT_Stack_Size -- 数据访问终止模式的栈大小
;FIQ_Stack_Size -- 快速中断模式的栈大小
;IRQ_Stack_Size -- 外部中断模式的栈大小
;USR_Stack_Size -- 用户模式的栈大小
;ISR_Stack_Size -- 总堆栈的大小,也就是也有模式下堆栈相加
;
;-----------------------------------------------------------------------
UND_Stack_Size EQU 0x00000000
SVC_Stack_Size EQU 0x00000008
ABT_Stack_Size EQU 0x00000000
FIQ_Stack_Size EQU 0x00000000
IRQ_Stack_Size EQU 0x00000080
USR_Stack_Size EQU 0x00000400
ISR_Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size +
FIQ_Stack_Size + IRQ_Stack_Size)
;-----------------------------------------------------------------------
;AREA -- 是一个伪指令,用于段定义。ARM的汇编程序由段组成,段是相对独立
; 的指令或数据单位,每个段由AREA伪指令定义,并定义段的属性。
; STACK -- AREA指令的一个参数,定义段名称
; NOINIT -- AREA指令的一个参数,指定本数据段仅仅保留了内在单元,而
; 将句初始值写入内存单元,也即将内存单元值初始化为0
; READWRITE -- 指定本段为可读可写,数据段默认为READWRITE。
; READWRITE(读写)、READONLY(只读)
;ALIGN -- 也是一个伪指令,指定对齐方式。ALIGN n 指令的对齐值有两种方案
; 即n 或 2^n,这里采用第二种方案即指定后面的指令8字节对齐。
;
;下面这句话的意思是:
;开辟一个堆栈段,段名字为STACK,定义为可读可写,将内存单元初始化为0,
;-----------------------------------------------------------------------
AREA STACK, NOINIT, READWRITE, ALIGN=3
;-----------------------------------------------------------------------
;SPACE -- 伪指令,用于分配一块内存单元,并用0初始化,与%同义
;其指令格式为:
; {lable} SPACE expr
;lable -- 内存起始地址标号 expr -- 所要分配的内存字节数
;-----------------------------------------------------------------------
Stack_Mem SPACE USR_Stack_Size ;堆栈内存起始地址标号
__initial_sp SPACE ISR_Stack_Size ;汇编代码的地址标号
Stack_Top ;堆栈段内容结束, 在这里放个标号,用来获得堆栈顶部地址
Heap_Size EQU 0x00000000 ;定义堆大小设置
;开辟一个名字为HEAP可读可写,不初始化内存单的内存单元。
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base ;堆的基址
Heap_Mem SPACE Heap_Size ;堆内存起始地址标号
__heap_limit ;堆结束
;----------------------------内存初始化定义-----------------------------
;在一些应用系统中除了扩展Flash,RAM挂接在外部存储器接口上外,可能还有其它
;的外设挂接在外部存储器接口上,不同外设的操作时序什么的都是不一样的,所以
;在使用这些外设之前必须初始化连接这些外设存储器接口。这里因为没扩展,所以
;只定义一个片上内存基地址。
;-----------------------------------------------------------------------
IRAM_BASE EQU 0x40000000 ;片上SRAM的基地址,即内存基地址
;-------------------------看门狗初始化定义------------------------------
;看门狗在防止程序跑飞,进入无限死循环时起着重要作用。有些应用可能用不上
;看门狗功能,也可能有些应用会用到外部看门狗。在这个时候内部看门狗必须禁
;止,所以有时候会在初始化时将内部看门狗禁止,当以后应用用到时再开启它。
;看门狗定时器包括三个寄存器:
;WTCON -- 看门狗控制寄存器,设定看门狗定时器模式
;WTDAT -- 看门狗数据寄存器,用于设定超时宽度
;WTCNT -- 看门狗计数寄存器,里面存放的是看门狗定时器当前值
;
;WT_BASE -- 看门狗定时器基地址
;WTCON_OFS -- 看门狗控制寄存器偏移地址,相对于基址
;WTDAT_OFS -- 看门狗数据寄存器偏移地址,相对于基址
;WTCNT_OFS -- 看门狗计数寄存器偏移地址,相对于基址
;WT_SETUP -- 看门狗设置
;WTCON_Val -- 看门狗控制寄存器设置,关闭看门狗
;WTDAT_Val -- 看门狗数据寄存器设置,初始值即为0x8000
;-----------------------------------------------------------------------
WT_BASE EQU 0x53000000 ; Watchdog Timer Base Address
WTCON_OFS EQU 0x00 ; Watchdog Timer Control Register Offset
WTDAT_OFS EQU 0x04 ; Watchdog Timer Data Register Offset
WTCNT_OFS EQU 0x08 ; Watchdog Timer Count Register Offset
WT_SETUP EQU 0
WTCON_Val EQU 0x00000000
WTDAT_Val EQU 0x00008000
;----------------------------时钟与电源管理定义-------------------------
;S3C2440A中的时钟控制逻辑可以产生必须的时钟信号,包括CPU的FCLK,AHB总线的
;HCLK 以及APB总线外设的PCLK3C2440A内部有两个锁相环(PLL):一个提供FCLK,
;HCLK及PCLK,另一个专用于USB模块(48MHz).
;
;CLOCK_BASE -- 时钟基地址
;LOCKTIME_OFS -- 锁相环锁定时间计数寄存器偏移地址,相对于基址
;MPLLCON_OFS -- MPLL配置寄存器偏移地址,相对于基址,主时钟源PLL
;UPLLCON_OFS -- UPLL配置寄存器偏移地址,相对于基址,USB时钟源PLL
;CLKCON_OFS -- 时钟控制寄存器偏移地址,相对于基址
;CLKSLOW_OFS -- 时钟减慢控制寄存器偏移地址,相对于基址
;CLKDIVN_OFS -- 时钟分频器控制寄存器偏移地址,相对于基址
;CAMDIVN_OFS -- 摄像头时钟分频器控制寄存器偏移地址,相对于基址,UPLL提供
;
;CLOCK_SETUP -- 时钟设置
;LOCKTIME_Val -- PLL锁定时间计数器值
;MPLLCON_Val -- MPLL配置寄存器值
;UPLLCON_Val -- UPLL配置寄存器值
;CLKCON_Val -- 时钟配置寄存器值
;CLKSLOW_Val -- 时钟减慢控制寄存器值
;CLKDIVN_Val -- 时钟分频控制寄存器值
;CAMDIVN_Val -- 摄像头分频控制寄存器值
;-----------------------------------------------------------------------
CLOCK_BASE EQU 0x4C000000 ; Clock Base Address
LOCKTIME_OFS EQU 0x00 ; PLL Lock Time Count Register Offset
MPLLCON_OFS EQU 0x04 ; MPLL Configuration Register Offset
UPLLCON_OFS EQU 0x08 ; UPLL Configuration Register Offset
CLKCON_OFS EQU 0x0C ; Clock Generator Control Reg Offset
CLKSLOW_OFS EQU 0x10 ; Clock Slow Control Register Offset
CLKDIVN_OFS EQU 0x14 ; Clock Divider Control Register Offset
CAMDIVN_OFS EQU 0x18 ; Camera Clock Divider Register Offset
CLOCK_SETUP EQU 0
LOCKTIME_Val EQU 0x0FFF0FFF
MPLLCON_Val EQU 0x00043011
UPLLCON_Val EQU 0x00038021
CLKCON_Val EQU 0x001FFFF0
CLKSLOW_Val EQU 0x00000004
CLKDIVN_Val EQU 0x0000000F
CAMDIVN_Val EQU 0x00000000
;--------------------存储控制器设置定义---------------------------------
;下面这些都是一些关于存储控制器的地址宏定义
;
;MC_BASE -- 存储控制器基地址
;BWSCON_OFS -- 总线宽度和等待控制寄存器偏移地址
;BANKCON0_OFS -- BANK1控制寄存器偏移地址
; .
; .
;BANKCON7_OFS -- BANK7控制寄存器偏移地址
;REFRESH_OFS -- DRAM/SDRAM刷新控制寄存器偏移地址
;BANKSIZE_OFS -- 可调的bank大小寄存器偏移地址
;MRSRB6_OFS -- bank6模式控制寄存器偏移地址
;MRSRB7_OFS -- bank7模式控制寄存器偏移地址
;
;MC_SETUP -- 存储器控制寄存器设置
;BWSCON_Val -- 写入总线宽度和等待控制寄存值
;BANKCON0_Val -- 写入Blank0的值
; .
; .
;BANKCON7_Val -- 写入BANK7 的值
;REFRESH_Val -- 写入DRAM/SDRAM刷新控制寄存的值
;BANKSIZE_Val -- 写入可调的bank大小寄存的值
;MRSRB6_Val -- 写入bank6模式控制寄存器的值
;MRSRB7_Val -- 写入bank7模式控制寄存器的值
;-----------------------------------------------------------------------
MC_BASE EQU 0x48000000 ; Memory Controller Base Address
BWSCON_OFS EQU 0x00 ; Bus Width and Wait Status Ctrl Offset
BANKCON0_OFS EQU 0x04 ; Bank 0 Control Register Offset
BANKCON1_OFS EQU 0x08 ; Bank 1 Control Register Offset
BANKCON2_OFS EQU 0x0C ; Bank 2 Control Register Offset
BANKCON3_OFS EQU 0x10 ; Bank 3 Control Register Offset
BANKCON4_OFS EQU 0x14 ; Bank 4 Control Register Offset
BANKCON5_OFS EQU 0x18 ; Bank 5 Control Register Offset
BANKCON6_OFS EQU 0x1C ; Bank 6 Control Register Offset
BANKCON7_OFS EQU 0x20 ; Bank 7 Control Register Offset
REFRESH_OFS EQU 0x24 ; SDRAM Refresh Control Register Offset
BANKSIZE_OFS EQU 0x28 ; Flexible Bank Size Register Offset
MRSRB6_OFS EQU 0x2C ; Bank 6 Mode Register Offset
MRSRB7_OFS EQU 0x30 ; Bank 7 Mode Register Offset
MC_SETUP EQU 1
BWSCON_Val EQU 0x22000000
BANKCON0_Val EQU 0x00000700
BANKCON1_Val EQU 0x00000700
BANKCON2_Val EQU 0x00000700
BANKCON3_Val EQU 0x00000700
BANKCON4_Val EQU 0x00000700
BANKCON5_Val EQU 0x00000700
BANKCON6_Val EQU 0x00018005
BANKCON7_Val EQU 0x00018005
REFRESH_Val EQU 0x008404F3
BANKSIZE_Val EQU 0x00000032
MRSRB6_Val EQU 0x00000020
MRSRB7_Val EQU 0x00000020
;---------------------I/O端口宏定义--------------------------------------
;GPA_BASE -- 端口A基地址
; .
;GPJ_BASE -- 端口J基地址
;GPCON_OFS -- 端口配置寄存器偏移地址
;GPDAT_OFS -- 端口数据寄存器偏移地址
;GPUP_OFS -- 端口上拉寄存器偏移地址
;GP_SETUP -- 端口设置
;GPA_SETUP -- 端口A配置
;GPACON_Val -- 写入端口A配置寄存器的值
; .
; .
;GPJ_SETUP -- 端口J配置
;GPJCON_Val -- 写入端口J配置寄存器的值
;GPJUP_Val -- 写入端口J上拉寄存器的值
;-----------------------------------------------------------------------
GPA_BASE EQU 0x56000000 ; GPA Base Address
GPB_BASE EQU 0x56000010 ; GPB Base Address
GPC_BASE EQU 0x56000020 ; GPC Base Address
GPD_BASE EQU 0x56000030 ; GPD Base Address
GPE_BASE EQU 0x56000040 ; GPE Base Address
GPF_BASE EQU 0x56000050 ; GPF Base Address
GPG_BASE EQU 0x56000060 ; GPG Base Address
GPH_BASE EQU 0x56000070 ; GPH Base Address
GPJ_BASE EQU 0x560000D0 ; GPJ Base Address
GPCON_OFS EQU 0x00 ; Control Register Offset
GPDAT_OFS EQU 0x04 ; Data Register Offset
GPUP_OFS EQU 0x08 ; Pull-up Disable Register Offset
GP_SETUP EQU 1
;-----------------------------------------------------------------------
;端口A配置
;-----------------------------------------------------------------------
GPA_SETUP EQU 0
GPACON_Val EQU 0x000003FF
;-----------------------------------------------------------------------
;端口B配置
;-----------------------------------------------------------------------
GPB_SETUP EQU 0
GPBCON_Val EQU 0x00000000
GPBUP_Val EQU 0x00000000
;-----------------------------------------------------------------------
;端口C配置
;-----------------------------------------------------------------------
GPC_SETUP EQU 0
GPCCON_Val EQU 0x00000000
GPCUP_Val EQU 0x00000000
;-----------------------------------------------------------------------
;端口D配置
;-----------------------------------------------------------------------
GPD_SETUP EQU 0
GPDCON_Val EQU 0x00000000
GPDUP_Val EQU 0x00000000
;-----------------------------------------------------------------------
;端口E配置
;-----------------------------------------------------------------------
GPE_SETUP EQU 0
GPECON_Val EQU 0x00000000
GPEUP_Val EQU 0x00000000
;-----------------------------------------------------------------------
;端口F配置
;-----------------------------------------------------------------------
GPF_SETUP EQU 0
GPFCON_Val EQU 0x00000000
GPFUP_Val EQU 0x00000000
;-----------------------------------------------------------------------
;端口G配置
;-----------------------------------------------------------------------
GPG_SETUP EQU 0
GPGCON_Val EQU 0x00000000
GPGUP_Val EQU 0x00000000
;-----------------------------------------------------------------------
;端口H配置
;-----------------------------------------------------------------------
GPH_SETUP EQU 0
GPHCON_Val EQU 0x00000000
GPHUP_Val EQU 0x00000000
;-----------------------------------------------------------------------
;端口J配置
;-----------------------------------------------------------------------
GPJ_SETUP EQU 0
GPJCON_Val EQU 0x00000000
GPJUP_Val EQU 0x00000000
;-----------------------------------------------------------------------
;PRESERVE8 -- 伪指令,指示当前文件请求堆栈为8字节对齐。
; 汇编程序数据8字节对齐,c和汇编有8位对齐的要求.
;-----------------------------------------------------------------------
PRESERVE8
;-----------------------------------------------------------------------
;存储区设定和程序入口点
;启动代码必须连接到第一个地址才能运行
;下面这句话的意思是:
; 声明一个名为RESET的代码段,属性为只读
;-----------------------------------------------------------------------
AREA RESET, CODE, READONLY
ARM ;ARM模式运行程序
;-----------------------------------------------------------------------
;IMPORT -- 相当于C语言中的关键字extern
; 指当前的符号在其他源文件中定义的,在本源文件中可能引用该符号.
;EXPORT -- 相当于C语言中的关键字global
; 声明一个符号可以被其它文件引用.相当于声明了一个全局变量
;下面这几句话是的意思是:
; 如果定义了_EVAL这个变量,引用RO输出区的字节长度与RW输出区的字节长度
;注意:
;ARM连接器定义了一些包含$$的符号。这些符号及其他所有包含$$的名称都是ARM的
;保留字。这些符号被用于指定域的基地址,输出段的基地址和输入段的基地址及其
;大小。我们可以自己的汇编语言程序中引用这些符号地址,把它们用作可重定位的
;地址,也可能在C或C++代码中使用extern关键字来引用它们。这个可以查看uVision
;Help 的Region-related symbols这一节。
;-----------------------------------------------------------------------
IF :LNOT::DEF:__EVAL ;逻辑判断是否定义了_EVAL这个变量
IMPORT ||Image$$ER_ROM1$$RO$$Length||
IMPORT ||Image$$RW_RAM1$$RW$$Length||
ENDIF
;-----------------------------------------------------------------------
; 异常向量,映射到地址0,必须使用绝对寻址方式,子程序用无限循环方式
;实现可以被修改。
;-----------------------------------------------------------------------
Vectors LDR PC, Reset_Addr ;将复位地址装载到程序指针,即复位
LDR PC, Undef_Addr ;未定义指令
LDR PC, SWI_Addr ;软件中断
LDR PC, PAbt_Addr ;中止(预取)
LDR PC, DAbt_Addr ;中止(数据)
IF :DEF:__EVAL ;如果定义了__EVAL 变量
DCD 0x4000 ;分配2k空间
ELSE ;否则分配空间大小为RO输出区的字节
;长度与RW输出区的字节长度之和
DCD ||Image$$ER_ROM1$$RO$$Length||+
||Image$$RW_RAM1$$RW$$Length||
ENDIF
LDR PC, IRQ_Addr ;外部中断
LDR PC, FIQ_Addr ;快速中断
IF :DEF:__RTX ;如果定义了__RTX
IMPORT SWI_Handler ;则定义中断子程序
IMPORT IRQ_Handler_RTX ;定义快速中断子程序
ENDIF
;-----------------------------------------------------------------------
;下面这几句的任务是把各个子程序的入口地址分配给相应的地址变量
;-----------------------------------------------------------------------
Reset_Addr DCD Reset_Handler ;复位子程序入口地址赋值给Reset_Addr
Undef_Addr DCD Undef_Handler ;未定义子程序入口地址赋值给Undef_Addr
SWI_Addr DCD SWI_Handler ;中断子程序入口地址赋值给SWI_Addr
PAbt_Addr DCD PAbt_Handler ;中止(预存)子程序入口地址赋给PAbt_Addr
DAbt_Addr DCD DAbt_Handler ;中止(数据)子程序入口地址赋给DAbt_Addr
DCD 0 ;保留地址
IF :DEF:__RTX ;如果定义了__RTX
IRQ_Addr DCD IRQ_Handler_RTX ;快速中断子程序入口地址给IRQ_Addr
ELSE
IRQ_Addr DCD IRQ_Handler ;否则把IRQ_Handler入口地址给IRQ_Addr
ENDIF
FIQ_Addr DCD FIQ_Handler ;快速中断入口地址给FIQ_Addr
;-----------------------------------------------------------------------
;这些子程序都是用无限循环方式实现的可以被修改。
;-----------------------------------------------------------------------
Undef_Handler
B Undef_Handler ;跳转到Undef_Handler,还是在这个地方
IF :DEF:__RTX ;如果定义了DEF:__RTX,在此等待中断
ELSE
SWI_Handler
B SWI_Handler ;否则跳转到软件中断
ENDIF
PAbt_Handler
B PAbt_Handler ;中止(预存)子程
DAbt_Handler
B DAbt_Handler ;中止(数据)子程
;-----------------------------------------------------------------------
;外部中断子程序
; 如果函数标有PROC与ENDP,但没有FRAME PUSH 或 FRAME POP,则堆栈作用量
;假定为0.这意味着无需手动添加FRAME PUSH 0或FRAME POP 0
;-----------------------------------------------------------------------
IRQ_Handler
PROC
EXPORT IRQ_Handler [WEAK] ;声明一个全局变量,并且其它
;同名符优先于本符号被引用
B . ;跳转到当前地址即在此等待“.”代表当前指令地址
ENDP
FIQ_Handler ;快速中断子程序
B FIQ_Handler
;-----------------------------------------------------------------------
;复位子程序
;-----------------------------------------------------------------------
EXPORT Reset_Handler ; 声明一个全局变量
Reset_Handler
;-----------------------------------------------------------------------
;配置看门狗
;前面已经初始化 WT_SETUP == 0,要想执行下面的程序需将WT_SETUP置1
;-----------------------------------------------------------------------
IF WT_SETUP != 0
LDR R0, =WT_BASE ;加载看门狗基址
LDR R1, =WTCON_Val ;加载看门狗控制寄存器数据
LDR R2, =WTDAT_Val ;加载看门狗数据寄存器数据
STR R2, [R0, #WTCNT_OFS] ;将WTDAT_Val配置给看门狗
;计数寄存器
STR R2, [R0, #WTDAT_OFS] ;将WTDAT_Val 配置给看门狗
;数据寄存器
STR R1, [R0, #WTCON_OFS] ;将WTCON_Val配置给看门狗
;控制寄存器
ENDIF
|
0
|
|
|
|