MDK S3C2440启动代码简单研究
发布时间:2021-11-23 15:07:49 所属栏目:教程 来源:互联网
导读:ARM启动代码相当于我们电脑的BIOS,也就是ARM启动时对处理器的一些初始化及嵌入式系统硬件的一些初始化。由于它直接面对处理器内核和硬件控制器进行编程,一般都是用汇编语言。 一般包括:中断向量表,初始化存储器系统,初始化堆栈,初始化有特殊要求的断口
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]得来的, ;比如这里的用户模式,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 isdisabled) ;F_Bit -- 如果F位被置1,则快速中断被禁止(FIQ isdisabled) ;;---------------------------------------------------------------------- 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 Ibit is set, IRQ is disabled F_Bit EQU 0x40 ; 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 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字节对齐。 ;ATPCS规定数据栈必须为FD类型,并且对数据栈的操作时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 ; WatchdogTimer Base Address WTCON_OFS EQU 0x00 ; Watchdog Timer Control RegisterOffset WTDAT_OFS EQU 0x04 ; Watchdog Timer DataRegister Offset WTCNT_OFS EQU 0x08 ; Watchdog Timer CountRegister Offset WT_SETUP EQU 0 WTCON_Val EQU 0x00000000 WTDAT_Val EQU 0x00008000 ;----------------------------时钟与电源管理定义------------------------- ;S3C2440A中的时钟控制逻辑可以产生必须的时钟信号,包括CPU的FCLK,AHB总线的 ;HCLK以及APB总线外设的PCLK?3C2440A内部有两个锁相环(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 ; ClockBase Address LOCKTIME_OFS EQU 0x00 ; PLL Lock Time CountRegister Offset MPLLCON_OFS EQU 0x04 ; MPLL ConfigurationRegister Offset UPLLCON_OFS EQU 0x08 ; UPLL ConfigurationRegister Offset CLKCON_OFS EQU 0x0C ; ClockGenerator Control Reg Offset CLKSLOW_OFS EQU 0x10 ; Clock SlowControl Register Offset CLKDIVN_OFS EQU 0x14 ; Clock Divider ControlRegister 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 ; MemoryController Base Address BWSCON_OFS EQU 0x00 ; Bus Width and WaitStatus Ctrl Offset BANKCON0_OFS EQU 0x04 ; Bank 0 ControlRegister Offset BANKCON1_OFS EQU 0x08 ; Bank 1 ControlRegister Offset BANKCON2_OFS EQU 0x0C ; Bank 2 ControlRegister Offset BANKCON3_OFS EQU 0x10 ; Bank 3Control Register Offset BANKCON4_OFS EQU 0x14 ; Bank 4Control Register Offset BANKCON5_OFS EQU 0x18 ;Bank 5 Control Register Offset BANKCON6_OFS EQU 0x1C ; Bank 6Control Register Offset BANKCON7_OFS EQU 0x20 ;Bank 7 Control Register Offset REFRESH_OFS EQU 0x24 ; SDRAM RefreshControl Register Offset BANKSIZE_OFS EQU 0x28 ; Flexible Bank Size Register Offset MRSRB6_OFS EQU 0x2C ; Bank 6 ModeRegister Offset MRSRB7_OFS EQU 0x30 ; Bank 7Mode 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 BaseAddress GPB_BASE EQU 0x56000010 ; GPB BaseAddress GPC_BASE EQU 0x56000020 ; GPC BaseAddress GPD_BASE EQU 0x56000030 ; GPD BaseAddress GPE_BASE EQU 0x56000040 ; GPE BaseAddress GPF_BASE EQU 0x56000050 ; GPF BaseAddress GPG_BASE EQU 0x56000060 ; GPG BaseAddress GPH_BASE EQU 0x56000070 ; GPH BaseAddress GPJ_BASE EQU 0x560000D0 ; GPJ BaseAddress GPCON_OFS EQU 0x00 ;Control Register Offset GPDAT_OFS EQU 0x04 ; DataRegister 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-relatedsymbols这一节。 ;----------------------------------------------------------------------- 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,但没有FRAMEPUSH 或FRAME POP,则堆栈作用量 ;假定为0.这意味着无需手动添加FRAMEPUSH 0或FRAMEPOP 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 ;----------------------------------------------------------------------- ;配置时钟 ;如果逻辑上没有定义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 STR R1, [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_SETUP且CLOCK_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 STR R1, [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功能 LDR R1, =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] LDR R1, =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 ) ;下面这一段主要是设置各个异常模式的堆栈,注意在设置的时候需要禁止IRQ和FIQ. ;这段代码也是系统复位后执行的第一段代码。执行完这段代码后系统处于系统模 ;式,并且IRQ和FIQ都是禁止的。 ;----------------------------------------------------------------------- LDR R0, =Stack_Top ;加载栈顶指针地址 ;----------------------------------------------------------------------- ;进入未定义模式,并设定其栈指针 ;----------------------------------------------------------------------- ;将(Mode_UND| I_Bit | F_Bit)赋值给CPSR_c即CPSR[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 函数入口地址 BX R0 ;跳转到__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 BX LR ;子程序返回 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已定义,则结果为真,否则为假 (编辑:东莞站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |