MDK S3C2440启动代码简单分析


ARM启动代码相当于我们电脑的BIOS,也就是ARM启动时对处理器的一些初始化及嵌入式系统硬件的一些初始化。由于它直接面对处理器内核和硬件控制器进行编程,一般都是用汇编语言。

一般包括:中断向量表,初始化存储器系统,初始化堆栈,初始化有特殊要求的断口,设备初始化,变量初始化等

;/*****************************************************************************/

;/*S3C2440A.S: Startup file for Samsung S3C440A */

;/*****************************************************************************/

;/*<<< Use Configuration Wizard in Context Menu >>> */

;/*****************************************************************************/

;/*This file is part of the uVision/ARM development tools. */

;/*Copyright (c) 2005-2006 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]得来的,

;比如这里的用户模式,CPSRM[4:0]设置为10000就是0x10

;Mode_USR -- 用户模式,正常程序执行模式,用于应用程序

;Mode_FIQ --快速中断模式,一般用于高速数据传输和通道处理。

;Mode_IRQ --外部中断模式,一般用于通用的中断处理。

;Mode_SVC -- 管理模式,供操作系统使用的一种保护模式。

;Mode_ABT -- 数据访问中止模式,用于虚拟存储用存储保护

;Mode_UND -- 未定义指令中止模式,当未定义指令执行时进入此模式。

;Mode_SYS -- 系统模式,用于特权级的操作系统任务。

;I_Bit --如果I位被置1,则外部中断被禁止(IRQ isdisabled)

;F_Bit -- 如果F位被置1,则快速中断被禁止(FIQ isdisabled)

;;----------------------------------------------------------------------

Mode_USR EQU0x10

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 EQU0x80 ; when Ibit is set, IRQ is disabled

F_Bit EQU0x40 ; when Fbit is set, FIQ is disabled

;----------------------------- Stack Configuration-----------------------------------

;下面这些主要是栈配置,系统的栈空间设定

;

;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 EQU0x00000008

ABT_Stack_Size EQU 0x00000000

FIQ_Stack_Size EQU0x00000000

IRQ_Stack_Size EQU0x00000080

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字节对齐。

;ATPCS规定数据栈必须为FD类型,并且对数据栈的操作时8字节对齐的

;下面这句话意思是:开辟一个堆栈段,段名字为STACK,定义为可读可写,将内存单元初始化为0,

;-----------------------------------------------------------------------

AREA STACK, NOINIT, READWRITE, ALIGN=3

;-----------------------------------------------------------------------

;SPACE-- 伪指令,用于分配一块内存单元,并用0初始化,与%同义

;其指令格式为:

;{lable} SPACE expr

;lable-- 内存起始地址标号expr -- 所要分配的内存字节数

;-----------------------------------------------------------------------

Stack_MemSPACE USR_Stack_Size ;堆栈内存起始地址标号

__initial_spSPACE ISR_Stack_Size ;汇编代码的地址标号

Stack_Top;堆栈段内容结束,在这里放个标号,用来获得堆栈顶部地址

Heap_SizeEQU 0x00000000 ;定义堆大小设置

;开辟一个名字为HEAP可读可写,不初始化内存单的内存单元。

AREA HEAP, NOINIT, READWRITE, ALIGN=3

__heap_base;堆的基址

Heap_MemSPACE Heap_Size ;堆内存起始地址标号

__heap_limit;堆结束

;----------------------------内存初始化定义-----------------------------

;在一些应用系统中除了扩展Flash,RAM挂接在外部存储器接口上外,可能还有其它

;的外设挂接在外部存储器接口上,不同外设的操作时序什么的都是不一样的,所以

;在使用这些外设之前必须初始化连接这些外设存储器接口。这里因为没扩展,所以

;只定义一个片上内存基地址。

;-----------------------------------------------------------------------

IRAM_BASEEQU 0x40000000 ;片上SRAM的基地址,即内存基地址

;-------------------------看门狗初始化定义------------------------------

;看门狗在防止程序跑飞,进入无限死循环时起着重要作用。有些应用可能用不上

;看门狗功能,也可能有些应用会用到外部看门狗。在这个时候内部看门狗必须禁

;止,所以有时候会在初始化时将内部看门狗禁止,当以后应用用到时再开启它。

;看门狗定时器包括三个寄存器:

;WTCON-- 看门狗控制寄存器,设定看门狗定时器模式

;WTDAT-- 看门狗数据寄存器,用于设定超时宽度

;WTCNT-- 看门狗计数寄存器,里面存放的是看门狗定时器当前值

;

;WT_BASE-- 看门狗定时器基地址

;WTCON_OFS-- 看门狗控制寄存器偏移地址,相对于基址

;WTDAT_OFS-- 看门狗数据寄存器偏移地址,相对于基址

;WTCNT_OFS-- 看门狗计数寄存器偏移地址,相对于基址

;WT_SETUP-- 看门狗设置

;WTCON_Val-- 看门狗控制寄存器设置,关闭看门狗

;WTDAT_Val-- 看门狗数据寄存器设置,初始值即为0x8000

;-----------------------------------------------------------------------

WT_BASEEQU 0x53000000 ; WatchdogTimer Base Address

WTCON_OFSEQU0x00; Watchdog Timer Control RegisterOffset

WTDAT_OFSEQU0x04; Watchdog Timer DataRegister Offset

WTCNT_OFSEQU0x08; Watchdog Timer CountRegister Offset

WT_SETUPEQU 0

WTCON_ValEQU 0x00000000

WTDAT_ValEQU 0x00008000

;----------------------------时钟与电源管理定义-------------------------

;S3C2440A中的时钟控制逻辑可以产生必须的时钟信号,包括CPUFCLK,AHB总线的

;HCLK以及APB总线外设的PCLK3C2440A内部有两个锁相环(PLL):一个提供FCLK,

;HCLKPCLK,另一个专用于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_BASEEQU 0x4C000000 ; ClockBase Address

LOCKTIME_OFSEQU 0x00 ; PLL Lock Time CountRegister Offset

MPLLCON_OFSEQU 0x04; MPLL ConfigurationRegister Offset

UPLLCON_OFSEQU 0x08 ; UPLL ConfigurationRegister Offset

CLKCON_OFSEQU 0x0C; ClockGenerator Control Reg Offset

CLKSLOW_OFSEQU 0x10; Clock SlowControl Register Offset

CLKDIVN_OFSEQU0x14; Clock Divider ControlRegister Offset

CAMDIVN_OFSEQU 0x18;Camera Clock Divider Register Offset

CLOCK_SETUPEQU 0

LOCKTIME_ValEQU 0x0FFF0FFF

MPLLCON_ValEQU 0x00043011

UPLLCON_ValEQU 0x00038021

CLKCON_ValEQU 0x001FFFF0

CLKSLOW_ValEQU 0x00000004

CLKDIVN_ValEQU 0x0000000F

CAMDIVN_ValEQU 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_BASEEQU 0x48000000 ; MemoryController Base Address

BWSCON_OFSEQU 0x00 ; Bus Width and WaitStatus Ctrl Offset

BANKCON0_OFSEQU 0x04; Bank 0 ControlRegister Offset

BANKCON1_OFSEQU 0x08; Bank 1 ControlRegister Offset

BANKCON2_OFSEQU 0x0C ; Bank 2 ControlRegister Offset

BANKCON3_OFSEQU 0x10; Bank 3Control Register Offset

BANKCON4_OFSEQU 0x14; Bank 4Control Register Offset

BANKCON5_OFSEQU 0x18;Bank 5 Control Register Offset

BANKCON6_OFSEQU 0x1C ; Bank 6Control Register Offset

BANKCON7_OFSEQU 0x20 ;Bank 7 Control Register Offset

REFRESH_OFSEQU0x24 ; SDRAM RefreshControl Register Offset

BANKSIZE_OFSEQU 0x28; Flexible Bank Size Register Offset

MRSRB6_OFSEQU0x2C ; Bank 6 ModeRegister Offset

MRSRB7_OFSEQU0x30; Bank 7Mode RegisterOffset

MC_SETUPEQU 1

BWSCON_ValEQU 0x22000000

BANKCON0_ValEQU 0x00000700

BANKCON1_ValEQU 0x00000700

BANKCON2_ValEQU 0x00000700

BANKCON3_ValEQU 0x00000700

BANKCON4_ValEQU 0x00000700

BANKCON5_ValEQU 0x00000700

BANKCON6_ValEQU 0x00018005

BANKCON7_ValEQU 0x00018005

REFRESH_ValEQU 0x008404F3

BANKSIZE_ValEQU 0x00000032

MRSRB6_ValEQU 0x00000020

MRSRB7_ValEQU 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_BASEEQU 0x56000000 ; GPA BaseAddress

GPB_BASEEQU 0x56000010 ; GPB BaseAddress

GPC_BASEEQU 0x56000020 ; GPC BaseAddress

GPD_BASEEQU 0x56000030 ; GPD BaseAddress

GPE_BASEEQU 0x56000040 ; GPE BaseAddress

GPF_BASEEQU 0x56000050 ; GPF BaseAddress

GPG_BASEEQU 0x56000060 ; GPG BaseAddress

GPH_BASEEQU 0x56000070 ; GPH BaseAddress

GPJ_BASEEQU 0x560000D0 ; GPJ BaseAddress

GPCON_OFSEQU0x00 ;Control Register Offset

GPDAT_OFSEQU0x04 ; DataRegister Offset

GPUP_OFSEQU0x08 ;Pull-up Disable Register Offset

GP_SETUPEQU 1

;-----------------------------------------------------------------------

;端口A配置

;-----------------------------------------------------------------------

GPA_SETUPEQU 0

GPACON_ValEQU 0x000003FF

;-----------------------------------------------------------------------

;端口B配置

;-----------------------------------------------------------------------

GPB_SETUPEQU 0

GPBCON_ValEQU 0x00000000

GPBUP_ValEQU 0x00000000

;-----------------------------------------------------------------------

;端口C配置

;-----------------------------------------------------------------------

GPC_SETUPEQU 0

GPCCON_ValEQU 0x00000000

GPCUP_ValEQU 0x00000000

;-----------------------------------------------------------------------

;端口D配置

;-----------------------------------------------------------------------

GPD_SETUPEQU 0

GPDCON_ValEQU 0x00000000

GPDUP_ValEQU 0x00000000

;-----------------------------------------------------------------------

;端口E配置

;-----------------------------------------------------------------------

GPE_SETUPEQU 0

GPECON_ValEQU 0x00000000

GPEUP_ValEQU 0x00000000

;-----------------------------------------------------------------------

;端口F配置

;-----------------------------------------------------------------------

GPF_SETUPEQU 0

GPFCON_ValEQU 0x00000000

GPFUP_ValEQU 0x00000000

;-----------------------------------------------------------------------

;端口G配置

;-----------------------------------------------------------------------

GPG_SETUPEQU 0

GPGCON_ValEQU 0x00000000

GPGUP_ValEQU 0x00000000

;-----------------------------------------------------------------------

;端口H配置

;-----------------------------------------------------------------------

GPH_SETUPEQU 0

GPHCON_ValEQU 0x00000000

GPHUP_ValEQU 0x00000000

;-----------------------------------------------------------------------

;端口J配置

;-----------------------------------------------------------------------

GPJ_SETUPEQU 0

GPJCON_ValEQU 0x00000000

GPJUP_ValEQU 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

;保留字。这些符号被用于指定域的基地址,输出段的基地址和输入段的基地址及其

;大小。我们可以自己的汇编语言程序中引用这些符号地址,把它们用作可重定位的

;地址,也可能在CC++代码中使用extern关键字来引用它们。这个可以查看uVision

;HelpRegion-relatedsymbols这一节。

;-----------------------------------------------------------------------

IF :LNOT::DEF:__EVAL ;逻辑判断是否定义了_EVAL这个变量

IMPORT ||Image$$ER_ROM1$$RO$$Length||

IMPORT ||Image$$RW_RAM1$$RW$$Length||

ENDIF

;-----------------------------------------------------------------------

;异常向量,映射到地址0,必须使用绝对寻址方式,子程序用无限循环方式

;实现可以被修改。

;-----------------------------------------------------------------------

VectorsLDR 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_AddrDCD Reset_Handler ;复位子程序入口地址赋值给Reset_Addr

Undef_AddrDCD Undef_Handler ;未定义子程序入口地址赋值给Undef_Addr

SWI_AddrDCD SWI_Handler ;中断子程序入口地址赋值给SWI_Addr

PAbt_AddrDCD PAbt_Handler ;中止(预存)子程序入口地址赋给PAbt_Addr

DAbt_AddrDCD DAbt_Handler ;中止(数据)子程序入口地址赋给DAbt_Addr

DCD0 ;保留地址

IF :DEF:__RTX ;如果定义了__RTX

IRQ_AddrDCD IRQ_Handler_RTX ;快速中断子程序入口地址给IRQ_Addr

ELSE

IRQ_AddrDCD IRQ_Handler ;否则把IRQ_Handler入口地址给IRQ_Addr

ENDIF

FIQ_AddrDCD 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 ;中止(数据)子程

;-----------------------------------------------------------------------

;外部中断子程序

;如果函数标有PROCENDP,但没有FRAMEPUSH FRAME POP,则堆栈作用量

;假定为0.这意味着无需手动添加FRAMEPUSH 0FRAMEPOP 0

;-----------------------------------------------------------------------

IRQ_Handler

PROC

EXPORT IRQ_Handler [WEAK] ;声明一个全局变量,并且其它

;同名符优先于本符号被引用

B . ;跳转到当前地址即在此等待“.”代表当前指令地址

ENDP

FIQ_Handler;快速中断子程序

B FIQ_Handler

;-----------------------------------------------------------------------

;复位子程序

;-----------------------------------------------------------------------

EXPORT Reset_Handler ; 声明一个全局变量

Reset_Handler

;-----------------------------------------------------------------------

;配置看门狗

;前面已经初始化WT_SETUP == 0,要想执行下面的程序需将WT_SETUP1

;-----------------------------------------------------------------------

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

;-----------------------------------------------------------------------

;配置时钟

;如果逻辑上没有定义NO_CLOCK_SETUP并且CLOCK_SETUP != 0执行下面程序

;-----------------------------------------------------------------------

IF(:LNOT:(:DEF:NO_CLOCK_SETUP)):LAND:(CLOCK_SETUP != 0)

LDR R0,=CLOCK_BASE ;加载时钟基址

LDR R1,=LOCKTIME_Val ;加载PLL锁定时间计数值

STR R1, [R0, #LOCKTIME_OFS] ;并将该值配置到PLL锁定时间计数器

MOV R1,#CLKDIVN_Val

STR R1, [R0, #CLKDIVN_OFS] ;配置时钟分频器

LDR R1, =CAMDIVN_Val

STRR1, [R0, #CAMDIVN_OFS] ;配置摄像头分频控制寄存器

LDR R1, =MPLLCON_Val

STR R1, [R0, #MPLLCON_OFS] ;配置MPLL配置寄存器

LDR R1, =UPLLCON_Val

STR R1, [R0, #UPLLCON_OFS] ;配置UPLL配置寄存器

MOV R1, #CLKSLOW_Val

STR R1, [R0, #CLKSLOW_OFS] ;配置时钟减慢控制寄存器

LDR R1, =CLKCON_Val

STR R1, [R0, #CLKCON_OFS] ;配置时钟配控制寄存器

ENDIF

;-----------------------------------------------------------------------

;存储器设定

;如果没有定义NO_MC_SETUPCLOCK_SETUP!= 0则执行下面的程序

;-----------------------------------------------------------------------

IF (:LNOT:(:DEF:NO_MC_SETUP)):LAND:(CLOCK_SETUP!= 0)

LDR R0, =MC_BASE ;加载存储控制器基址

LDR R1, =BWSCON_Val

STR R1, [R0, #BWSCON_OFS] ;配置总线宽度和等待控制寄存器

LDR R1, =BANKCON0_Val

STR R1, [R0, #BANKCON0_OFS] ;配置BLANK0控制寄存器

LDR R1, =BANKCON1_Val

STR R1, [R0, #BANKCON1_OFS] ;配置BLANK1控制寄存器

LDR R1, =BANKCON2_Val

STRR1, [R0, #BANKCON2_OFS] ;配置BLANK2控制寄存器

LDR R1, =BANKCON3_Val

STR R1, [R0, #BANKCON3_OFS] ;配置BLANK3控制寄存器

LDR R1, =BANKCON4_Val

STR R1, [R0, #BANKCON4_OFS] ;配置BLANK4控制寄存器

LDR R1, =BANKCON5_Val

STR R1, [R0, #BANKCON5_OFS] ;配置BLANK5控制寄存器

LDR R1, =BANKCON6_Val

STR R1, [R0, #BANKCON6_OFS] ;配置BLANK6控制寄存器

LDR R1, =BANKCON7_Val

STR R1, [R0, #BANKCON7_OFS] ;配置BLANK7控制寄存器

LDR R1, =REFRESH_Val

STR R1, [R0, #REFRESH_OFS] ;配置DRAM/SDRAM刷新控制寄存器

MOV R1, #BANKSIZE_Val

STR R1, [R0, #BANKSIZE_OFS] ;配置可调的bank大小寄存器

MOV R1, #MRSRB6_Val

STR R1, [R0, #MRSRB6_OFS] ;配置bank6模式控制寄存器

MOV R1, #MRSRB7_Val

STR R1, [R0, #MRSRB7_OFS] ;配置bank7模式控制寄存器

ENDIF

;-----------------------------------------------------------------------

;IO端口配置

;如果没有定义NO_GP_SETUP并且GP_SETUP!= 0则执行下面的程序

;-----------------------------------------------------------------------

IF (:LNOT:(:DEF:NO_GP_SETUP)):LAND:(GP_SETUP !=0)

IF GPA_SETUP != 0

LDR R0, =GPA_BASE ;配置端口A功能

LDRR1, =GPACON_Val ;A口有25个口,做IO时只能做输出口

STR R1, [R0, #GPCON_OFS]

ENDIF

IF GPB_SETUP != 0

LDR R0, =GPB_BASE ;配置端口B功能

LDR R1, =GPBCON_Val

STR R1, [R0, #GPCON_OFS]

LDR R1, =GPBUP_Val ;配置端口B上拉寄存器

STR R1, [R0, #GPUP_OFS]

ENDIF

IF GPC_SETUP != 0

LDR R0, =GPC_BASE ;配置端口C功能

LDR R1, =GPCCON_Val

STR R1, [R0, #GPCON_OFS]

LDR R1, =GPCUP_Val ;配置端口C上拉寄存器

STR R1, [R0, #GPUP_OFS]

ENDIF

IF GPD_SETUP != 0

LDR R0, =GPD_BASE ;配置端口D功能

LDR R1, =GPDCON_Val

STR R1, [R0, #GPCON_OFS]

LDR R1, =GPDUP_Val ;配置端口D上位寄存器

STR R1, [R0, #GPUP_OFS]

ENDIF

IF GPE_SETUP != 0

LDR R0, =GPE_BASE

LDR R1, =GPECON_Val ;配置端口E功能

STR R1, [R0, #GPCON_OFS]

LDR R1, =GPEUP_Val ;配置端口E上位寄存器

STR R1, [R0, #GPUP_OFS]

ENDIF

IF GPF_SETUP != 0

LDR R0, =GPF_BASE

LDR R1, =GPFCON_Val ;配置端口F功能

STR R1, [R0, #GPCON_OFS]

LDR R1, =GPFUP_Val ;配置端口F上位寄存器

STR R1, [R0, #GPUP_OFS]

ENDIF

IF GPG_SETUP != 0

LDR R0, =GPG_BASE

LDR R1, =GPGCON_Val ;配置端口G功能

STR R1, [R0, #GPCON_OFS]

LDRR1, =GPGUP_Val ;配置端口G上位寄存器

STR R1, [R0, #GPUP_OFS]

ENDIF

IF GPH_SETUP != 0

LDR R0, =GPH_BASE

LDR R1, =GPHCON_Val ;配置端口H

STR R1, [R0, #GPCON_OFS]

LDR R1, =GPHUP_Val ;配置端口H上位寄存器

STR R1, [R0, #GPUP_OFS]

ENDIF

IF GPJ_SETUP != 0

LDR R0, =GPJ_BASE

LDR R1, =GPJCON_Val ;配置端口J

STR R1, [R0, #GPCON_OFS]

LDR R1, =GPJUP_Val ;配置端口J上位寄存

STR R1, [R0, #GPUP_OFS]

ENDIF

ENDIF

;-----------------------------------------------------------------------

;拷贝异常向量到内部RAM

;如果定义了RAM_INTVEC就执行下面一段程序

;-----------------------------------------------------------------------

IF :DEF:RAM_INTVEC

ADR R8, Vectors ; 读取向量源地址

LDR R9, =IRAM_BASE ; 读取片上SRAM的基地址

LDMIA R8!, {R0-R7} ; 批量加载异常向量

STMIA R9!, {R0-R7} ; 批量存储向量

LDMIA R8!, {R0-R7} ; 加载程序入口地址(LoadHandler Addresses )

STMIA R9!, {R0-R7} ; 存储程序入口地址(StoreHandler Addresses)

ENDIF

;-----------------------------------------------------------------------

;配置相应模式栈的大小(SetupStack for each mode )

;下面这一段主要是设置各个异常模式的堆栈,注意在设置的时候需要禁止IRQFIQ.

;这段代码也是系统复位后执行的第一段代码。执行完这段代码后系统处于系统模

;式,并且IRQFIQ都是禁止的。

;-----------------------------------------------------------------------

LDR R0, =Stack_Top ;加载栈顶指针地址

;-----------------------------------------------------------------------

;进入未定义模式,并设定其栈指针

;-----------------------------------------------------------------------

;(Mode_UND| I_Bit | F_Bit)赋值给CPSR_cCPSR[7:0]

MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit

MOV SP, R0 ;栈顶指针地址赋值给SP指针

SUB R0, R0, #UND_Stack_Size ;分其栈指针

;-----------------------------------------------------------------------

;进入异常中断模式,并设定其栈指针

;下面这三句话与上面原理一样

;-----------------------------------------------------------------------

MSR CPSR_c,#Mode_ABT:OR:I_Bit:OR:F_Bit

MOV SP, R0

SUB R0, R0, #ABT_Stack_Size

;-----------------------------------------------------------------------

;进入FIQ模式,并设定其栈指针

;下面这三句话与上面原理一样

;-----------------------------------------------------------------------

MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit

MOV SP, R0

SUB R0, R0, #FIQ_Stack_Size

;-----------------------------------------------------------------------

;进入IRQ模式,并设定其栈指针

;下面这三句话与上面原理一样

;-----------------------------------------------------------------------

MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit

MOV SP, R0

SUB R0, R0, #IRQ_Stack_Size

;-----------------------------------------------------------------------

;进入Supervisor模式,并设定其栈指针

;下面这三句话与上面原理一样

;-----------------------------------------------------------------------

MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit

MOV SP, R0

SUB R0, R0, #SVC_Stack_Size

;-----------------------------------------------------------------------

;进入用户模式,并设定其栈指针

;下面这三句话与上面原理一样

;-----------------------------------------------------------------------

;Enter User Mode and set its Stack Pointer

MSR CPSR_c, #Mode_USR

MOV SP, R0

SUB SL, SP, #USR_Stack_Size

;-----------------------------------------------------------------------

;进入用户模式

;-----------------------------------------------------------------------

MSR CPSR_c, #Mode_USR

IF :DEF:__MICROLIB ;如果定义了__MICROLIB

EXPORT __initial_sp ;那么就声明__initial_sp

ELSE

MOV SP,R0 ;否则就设定用户模式栈指针

SUB SL, SP, #USR_Stack_Size

ENDIF

;-----------------------------------------------------------------------

;些处开始正式进入C代码区

;反汇编以后C程序中的main函数名就变成了__main

;-----------------------------------------------------------------------

IMPORT __main ;声明__main 函数

LDR R0, =__main ;加载__main 函数入口地址

BXR0 ;跳转到__main

IF :DEF:__MICROLIB ;如果定义了__MICROLIB

EXPORT __heap_base ;则声明__heap_base

EXPORT __heap_limit ;声明__heap_limit

ELSE

;-----------------------------------------------------------------------

;用户初始化堆与栈,用于动态申请内存使用

;__use_two_region_memory这是MDK的库函

;__user_initial_stackheap也是一个库函数,它的返回值有

;* 堆基址(heapbase) --> R0

;* 栈基址(stackbase) --> R1 一般为栈的最高地址

;* 堆顶(heaplimit) --> R2

;* 栈顶(stacklimit) --> R3

;

;-----------------------------------------------------------------------

AREA |.text|, CODE, READONLY

IMPORT __use_two_region_memory

EXPORT __user_initial_stackheap

__user_initial_stackheap

LDR R0, =Heap_Mem ;堆内存起始地址-->R0

LDR R1, =(Stack_Mem + USR_Stack_Size) ;栈起始地址-->R1

LDR R2, = (Heap_Mem + Heap_Size);堆顶-->R2

LDR R3, = Stack_Mem ;栈顶地址 -->R3

BXLR;子程序返回

ENDIF

END

//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\//\\\\\\\\\\

:LEN:X返回字符串X的长度(字符数)
:CHR:M将0~255之间的整数转换为一个字符
:STR:X将一个数字表达式或逻辑表达式转换为一个字符串.对于数字表达式,STR运算符将其转换为一个以十六进制组成的字符串;对于逻辑表达式,STR运算符将其转换为字符串T或F.
X:LEFT:Y返回某个字符串左端的一个子串.X为源字符串,Y表示返回的个数
X:RIGHT:Y与LEFT对应
X:CC:Y将Y连接到X的后面
:BASE:X返回基于寄存器的表达式中寄存器的编号
:INDEX:X返回基于寄存器的表达式中相对于其基址寄存器的偏移量
?X返回定义符号X的代码行所生成的可执行代码的字节数
:DEF:X如果符号X已定义,则结果为真,否则为假

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值