;/*****************************************************************************/ ;/* S3C2440A.S: Startup file for Samsung S3C440A */ ;/* 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. */ ;/*****************************************************************************/
;elementary avocationA AND 水友 (rework:2008.09.15) /**************************************************************************** ;/欢迎各位大峡更详细的注解和改错;;(越详细越好!目标每行注解) 参与的水友如下: 【虚处理(子程序)是用一个无限循环实现的, 它是可修改的..//(11942295)翻译】 【galaxy9229 发表于www.21ic 2008-9-25 16:51 ARM程序分析与设计】
参考:【龙啸九天】【飘零天堂】【METAL MAX】 /****************************************************************************/ ;***启动代码(执行复位后)*** ; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs//;向量中断模式/非向量中断模式 在PSRs设置(猜的)
; 系统的工作模式设定 Mode_USR EQU 0x10 ; 定义用户模式标志代码;// 用户模式的CPSR代码 Mode_FIQ EQU 0x11 ; 定义快速中断模式标志代码;// 快中断模式的CPSR代码 Mode_IRQ EQU 0x12 ; 定义普通中断模式标志代码;// 中断模式的CPSR代码 Mode_SVC EQU 0x13 ; 定义管理模式标志代码;// 管理模式的CPSR代码 Mode_ABT EQU 0x17 ; 定义中止模式标志代码;// 中止模式的CPSR代码 Mode_UND EQU 0x1B ; 定义未定义模式标志代码 ;// 未定义模式的CPSR代码 Mode_SYS EQU 0x1F ; 定义系统模式(特权模式)标志代码;// 系统(特权)模式的CPSR代码
I_Bit EQU 0x80 ;// 普通中断开关(0×80:打开;0×00:关闭) F_Bit EQU 0x40 ;// 快速中断开关(0×40:打开;0×00:关闭)
;//栈配置()
;系统的栈空间设定
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);所有的堆栈大小进行相加,得到总堆栈大小 /********************************************************************************************** ;//arm的汇编程序由段组成,段是相对独立的指令或数据单位,每个段由AREA伪指令定义,并定义段的属性: ;//READWRITE(读写)READONLY(只读) **********************************************************************************************/ AREA STACK, NOINIT, READWRITE, ALIGN=3 ;开辟端栈段,段名(STACK)定义为可读可写,不初始化内存单元或将内存写0,字节对齐
Stack_Mem SPACE USR_Stack_Size ;//申请栈内存空间 __initial_sp SPACE ISR_Stack_Size
Stack_Top EQU Stack_Mem + ISR_Stack_Size ;//定义堆栈开始地址(最大地址,堆栈向下访问)
;//堆配置 ;//堆大小 (单位字节)// Heap_Size EQU 0x00000000 ;系统的堆空间设定//定义堆空间大小(配合最后的动态内存申请使用)
AREA HEAP, NOINIT, READWRITE, ALIGN=3 ;//段名(HEAP)声明堆代码段(不初始化内存,可读写,字节对齐) Heap_Mem SPACE Heap_Size ;//申请堆的内存空间
;时钟管理定义 CLK_BASE EQU 0x4C000000 ; 时钟基地址 LOCKTIME_OFS EQU 0x00 ; PLL锁定时间计数器对应基地址的偏移值 MPLLCON_OFS EQU 0x04 ; MPLL控制 对应基地址的偏移值//认为MPLL分出三种模式:FCLK、HCLK、PCLK UPLLCON_OFS EQU 0X08 ; UPLL控制 对应基地址的偏移值//用于USB设备 CLKCON_OFS EQU 0x0C ; 时钟生成控制 对应基地址的偏移值 CLKSLOW_OFS EQU 0x10 ; 慢时钟控制 对应基地址的偏移值 CLKDIVN_OFS EQU 0X14 ; 时钟除法器控制 对应基地址的偏移值 CAMDIVN_OFS EQU 0X18 ; 摄象时钟除法器控制 对应基地址的偏移值//UPLL提供
CLOCK_SETUP EQU 1 ; 时钟设置 LOCKTIME_Val EQU 0x0FFF0FFF ; PLL锁定时间计数器 值 MPLLCON_Val EQU 0x00043011 ; MPLL控制 值 UPLLCON_Val EQU 0x00038021 ; UPLL控制 值 CLKCON_Val EQU 0x001FFFF0 ; 时钟生成控制 值 CLKSLOW_Val EQU 0x00000004 ; 慢时钟控制 值 CLKDIVN_Val EQU 0x0000000F ; 时钟除法器控制 值 CAMDIVN_Val EQU 0x00000000 ; 摄象时钟除法器控制 值
;Interrupt definitions ;中断定义 INTOFFSET EQU 0X4A000014 ;中断请求源偏移 地址
;//中断向量表 ;// 中断向量地址 <0x20-0x3fffff78> ;// 中断向量表地址必须字对齐 ;//</e> IntVT_SETUP EQU 1 ;中断向量设置 IntVTAddress EQU 0x33ffff20 ;中断向量地址
;----------------------- 存储器设定 ------------------------------------
IRAM_BASE EQU 0x40000000 ; //内存基地址
; //看门狗定义 WT_BASE EQU 0x53000000 ; 看门狗基地址 WTCON_OFS EQU 0x00 ; 看门狗控制 对应基地址的偏移值 WTDAT_OFS EQU 0x04 ; 看门狗数据 对应基地址的偏移值 WTCNT_OFS EQU 0x08 ; 看门狗记数 对应基地址的偏移值
WT_SETUP EQU 1 ; 看门狗设置 WTCON_Val EQU 0x00000000 ; 看门狗控制 WTDAT_Val EQU 0x00008000 ; 看门狗数据
; 存储控制器设定 MC_BASE EQU 0x48000000 ;存储控制器基地址
MC_SETUP EQU 0 ;存储控制器设定
BWSCON_Val EQU 0x22000000 ;总线宽度和等待控制 BANKCON0_Val EQU 0x00000700 ;Boot ROM 控制 BANKCON1_Val EQU 0x00000700 ;BANK1 控制 BANKCON2_Val EQU 0x00000700 ;BANK2 控制 BANKCON3_Val EQU 0x00000700 ;BANK3 控制 BANKCON4_Val EQU 0x00000700 ;BANK4 控制 BANKCON5_Val EQU 0x00000700 ;BANK5 控制 BANKCON6_Val EQU 0x00018005 ;BANK6 控制 BANKCON7_Val EQU 0x00018005 ;BANK7 控制 REFRESH_Val EQU 0x008404F3 ;DRAM/SDRAM 刷新 控制 BANKSIZE_Val EQU 0x00000032 ;存储器大小 控制 MRSRB6_Val EQU 0x00000020 ;SDRAM 的模式设置寄存器 控制 MRSRB7_Val EQU 0x00000020 ;SDRAM 的模式设置寄存器 控制
; 存储控制器设定结束
; I/O 口设定 PIO_BASE EQU 0x56000000 ; 端口基地址 PCONA_OFS EQU 0x00 ; 端口A控制 对应基地址的偏移值 PCONB_OFS EQU 0x10 ; 端口B控制 对应基地址的偏移值 PCONC_OFS EQU 0x20 ; 端口C控制 对应基地址的偏移值 PCOND_OFS EQU 0x30 ; 端口D控制 对应基地址的偏移值 PCONE_OFS EQU 0x40 ; 端口E控制 对应基地址的偏移值 PCONF_OFS EQU 0x50 ; 端口F控制 对应基地址的偏移值 PCONG_OFS EQU 0x60 ; 端口G控制 对应基地址的偏移值 PCONH_OFS EQU 0x70 ; 端口H控制 对应基地址的偏移值 PCONJ_OFS EQU 0xD0 ; 端口J控制 对应基地址的偏移值 PUPB_OFS EQU 0x18 ; 端口B上拉控制 对应基地址的偏移值 PUPC_OFS EQU 0x28 ; 端口C上拉控制 对应基地址的偏移值 PUPD_OFS EQU 0x38 ; 端口D上拉控制 对应基地址的偏移值 PUPE_OFS EQU 0x48 ; 端口E上拉控制 对应基地址的偏移值 PUPF_OFS EQU 0x58 ; 端口F上拉控制 对应基地址的偏移值 PUPG_OFS EQU 0x68 ; 端口G上拉控制 对应基地址的偏移值 PUPH_OFS EQU 0x78 ; 端口H上拉控制 对应基地址的偏移值 PUPJ_OFS EQU 0xD8 ; 端口J上拉控制 对应基地址的偏移值
;--------端口 配置-------------- PIO_SETUP EQU 0
;端口A PIOA_SETUP EQU 0 PCONA_Val EQU 0x000003FF ;端口B PIOB_SETUP EQU 0 PCONB_Val EQU 0x00000000 ; PUPB_Val EQU 0x00000000 ;端口B上拉开启 ;端口C PIOC_SETUP EQU 1 PCONC_Val EQU 0x00001401 ; PUPC_Val EQU 0x00000000 ;端口C上拉开启 ;端口D PIOD_SETUP EQU 0 PCOND_Val EQU 0x00000000 ; PUPD_Val EQU 0x00000000 ;端口D上拉开启 ;端口E PIOE_SETUP EQU 0 PCONE_Val EQU 0x00000000 ; PUPE_Val EQU 0x00000000 ;端口E上拉开启
;端口F PIOF_SETUP EQU 0 PCONF_Val EQU 0x00000000 ; PUPF_Val EQU 0x00000000 ;端口F上拉开启 ;端口G PIOG_SETUP EQU 0 PCONG_Val EQU 0x00000000 ; PUPG_Val EQU 0x00000000 ;端口G上拉开启 ;端口H PIOH_SETUP EQU 0 PCONH_Val EQU 0x000007FF PUPH_Val EQU 0x00000000 ;端口H上拉开启 ;端口J PIOJ_SETUP EQU 0 PCONJ_Val EQU 0x00000000 ; PUPJ_Val EQU 0x00000000 ;端口J上拉开启
; 汇编程序数据 8 字节对齐 PRESERVE8 ;c和汇编有8位对齐的要求,这个伪指令可以满足此要求 ;//存储区设定和程序入口点 ;//启动代码必须连接到第一个地址才能运行。 AREA RESET, CODE, READONLY ;//开辟端栈段,段名(RESET)定义RESET代码段为只读 ARM ;//ARM 模式运行程序 ;//异常向量 ;//影射到地址0
;//必须使用,绝对寻址方式。 ;//虚处理(子程序)是用一个无限循环实现的, 它是可修改的..//(11942295)翻译 Vectors LDR PC, Reset_Addr ; 复位 LDR PC, Undef_Addr ; 未定义指令 LDR PC, SWI_Addr ; 软件中断 LDR PC, PAbt_Addr ; 中止(预取) LDR PC, DAbt_Addr ; 中止(数据) NOP ; 保留向量 LDR PC, IRQ_Addr ; 普通 LDR PC, FIQ_Addr ; 快速中断
IF IntVT_SETUP <> 0
;//中断向量表地址 HandleEINT0 EQU IntVTAddress HandleEINT1 EQU IntVTAddress +4 HandleEINT2 EQU IntVTAddress +4*2 HandleEINT3 EQU IntVTAddress +4*3 HandleEINT4_7 EQU IntVTAddress +4*4 HandleEINT8_23 EQU IntVTAddress +4*5 HandleCAM EQU IntVTAddress +4*6 HandleBATFLT EQU IntVTAddress +4*7 HandleTICK EQU IntVTAddress +4*8 HandleWDT EQU IntVTAddress +4*9 HandleTIMER0 EQU IntVTAddress +4*10 HandleTIMER1 EQU IntVTAddress +4*11 HandleTIMER2 EQU IntVTAddress +4*12 HandleTIMER3 EQU IntVTAddress +4*13 HandleTIMER4 EQU IntVTAddress +4*14 HandleUART2 EQU IntVTAddress +4*15 HandleLCD EQU IntVTAddress +4*16 HandleDMA0 EQU IntVTAddress +4*17 HandleDMA1 EQU IntVTAddress +4*18 HandleDMA2 EQU IntVTAddress +4*19 HandleDMA3 EQU IntVTAddress +4*20 HandleMMC EQU IntVTAddress +4*21 HandleSPI0 EQU IntVTAddress +4*22 HandleUART1 EQU IntVTAddress +4*23 HandleNFCON EQU IntVTAddress +4*24 HandleUSBD EQU IntVTAddress +4*25 HandleUSBH EQU IntVTAddress +4*26 HandleIIC EQU IntVTAddress +4*27 HandleUART0 EQU IntVTAddress +4*28 HandleSPI1 EQU IntVTAddress +4*39 HandleRTC EQU IntVTAddress +4*30 HandleADC EQU IntVTAddress +4*31
/********************************************************************* sub sp,sp,#4 ; 计算返回地址 //进入中断后,它的返回地址该怎么计算呢,可以这样来理解,因为它的指令流水线是3级的, //即执行进入中断函数时,PC已经指向欲取值的指令即当前执行的地址+8;当已进入中断时, LR里面装的是PC,所以要想中断返回到正确的地址处,就必须把LR-4。 【galaxy9229 发表于www.21ic 2008-9-25 16:51 ARM程序分析与设计】 /**********************************************************************/ IRQ_Entry sub sp,sp,#4 ;//保留PC值//; 计算返回地址 stmfd sp!,{r8-r9} ldr r9,=INTOFFSET ldr r9,[r9] ldr r8,=HandleEINT0 ;读入中断偏移码 add r8,r8,r9,lsl #2 ;二级跳转表的首地址 ldr r8,[r8] str r8,[sp,#8] ;中断入口地址送进SP(第一个代码留出的4字节空间) ldmfd sp!,{r8-r9,pc} ENDIF
Reset_Addr DCD Reset_Handler ;定义中断的入口地址 Undef_Addr DCD Undef_Handler SWI_Addr DCD SWI_Handler PAbt_Addr DCD PAbt_Handler DAbt_Addr DCD DAbt_Handler DCD 0 ;//保留地址 IRQ_Addr DCD IRQ_Handler FIQ_Addr DCD FIQ_Handler
Undef_Handler B Undef_Handler ;中断处理程序的入口地址//B为跳转指令|| ??自己跳转到自己?? SWI_Handler B SWI_Handler PAbt_Handler B PAbt_Handler DAbt_Handler B DAbt_Handler IF IntVT_SETUP <> 1 IRQ_Handler B IRQ_Handler ENDIF IF IntVT_SETUP <> 0 IRQ_Handler B IRQ_Entry ENDIF FIQ_Handler B FIQ_Handler
;//存储控制器配制 IF MC_SETUP <> 0 MC_CFG DCD BWSCON_Val DCD BANKCON0_Val DCD BANKCON1_Val DCD BANKCON2_Val DCD BANKCON3_Val DCD BANKCON4_Val DCD BANKCON5_Val DCD BANKCON6_Val DCD BANKCON7_Val DCD REFRESH_Val DCD BANKSIZE_Val DCD MRSRB6_Val DCD MRSRB7_Val ENDIF
;//时钟管理配置 IF CLOCK_SETUP <> 0 CLK_CFG DCD LOCKTIME_Val DCD CLKDIVN_Val DCD UPLLCON_Val DCD MPLLCON_Val DCD CLKSLOW_Val DCD CLKCON_Val DCD CAMDIVN_Val ENDIF
;//I/O 配置 IF PIO_SETUP <> 0 PIOA_CFG DCD PCONA_Val PIOB_CFG DCD PCONB_Val DCD PUPB_Val PIOC_CFG DCD PCONC_Val DCD PUPC_Val PIOD_CFG DCD PCOND_Val DCD PUPD_Val PIOE_CFG DCD PCONE_Val DCD PUPE_Val PIOF_CFG DCD PCONF_Val DCD PUPF_Val PIOG_CFG DCD PCONG_Val DCD PUPG_Val PIOH_CFG DCD PCONH_Val DCD PUPH_Val PIOJ_CFG DCD PCONJ_Val DCD PUPJ_Val ENDIF
; //复位处理模块 ;//下面是重起时的中断处理函数 EXPORT Reset_Handler ;//定义一个全局函数名变量 Reset_Handler
IF WT_SETUP <> 0 ;//看门狗处理;若WT_SETUP为1,则执行下一个语句 LDR R0, =WT_BASE LDR R1, =WTCON_Val LDR R2, =WTDAT_Val STR R2, [R0, #WTCNT_OFS] STR R2, [R0, #WTDAT_OFS] STR R1, [R0, #WTCON_OFS] ENDIF IF CLOCK_SETUP <> 0 ;//时钟处理;若CLOCK_SETUP为1,则执行下一个语句 LDR R0, =CLK_BASE ADR R8, CLK_CFG LDMIA R8, {R1-R7} STR R1, [R0, #LOCKTIME_OFS] STR R2, [R0, #CLKDIVN_OFS] STR R3, [R0, #UPLLCON_OFS] nop nop nop nop nop nop nop STR R4, [R0, #MPLLCON_OFS] STR R5, [R0, #CLKSLOW_OFS] STR R6, [R0, #CLKCON_OFS] STR R7, [R0, #CAMDIVN_OFS] ENDIF IF MC_SETUP <> 0 ;//存储控制器处理;若MC_SETUP为1,则执行下一个语句 ADR R13, MC_CFG LDMIA R13, {R0-R12} LDR R13, =MC_BASE STMIA R13, {R0-R12} ENDIF IF PIO_SETUP <> 0 ;//IO处理;若PIO_SETUP为1,则执行下一个语句 LDR R13, =PIO_BASE
IF PIOA_SETUP <> 0 ;//端口A处理;若PIOA_SETUP为1,则执行下一个语句 ADR R0, PIOA_CFG STR R0, [R13, #PCONA_OFS] ENDIF
IF PIOB_SETUP <> 0 ;//端口B处理 ADR R0, PIOB_CFG LDR R1, [R0,#4] STR R0, [R13, #PCONB_OFS] STR R1, [R13, #PUPB_OFS] ENDIF
IF PIOC_SETUP <> 0 ;//端口C处理 ADR R0, PIOC_CFG LDR R1, [R0,#4] STR R0, [R13, #PCONC_OFS] STR R1, [R13, #PUPC_OFS] ENDIF
IF PIOD_SETUP <> 0 ;//端口D处理 ADR R0, PIOD_CFG LDR R1, [R0,#4] STR R0, [R13, #PCOND_OFS] STR R1, [R13, #PUPD_OFS] ENDIF
IF PIOE_SETUP <> 0 ;//端口E处理 ADR R0, PIOE_CFG LDR R1, [R0,#4] STR R0, [R13, #PCONE_OFS] STR R1, [R13, #PUPE_OFS] ENDIF
IF PIOF_SETUP <> 0 ;//端口F处理 ADR R0, PIOF_CFG LDR R1, [R0,#4] STR R0, [R13, #PCONF_OFS] STR R1, [R13, #PUPF_OFS] ENDIF
IF PIOG_SETUP <> 0 ;//端口G处理 ADR R0, PIOG_CFG LDR R1, [R0,#4] STR R0, [R13, #PCONG_OFS] STR R1, [R13, #PUPG_OFS] ENDIF IF PIOH_SETUP <> 0 ;//端口H处理 ADR R0, PIOH_CFG LDR R1, [R0,#4] STR R0, [R13, #PCONH_OFS] STR R1, [R13, #PUPH_OFS] ENDIF IF PIOJ_SETUP <> 0 ;//端口J处理 ADR R0, PIOJ_CFG LDR R1, [R0,#4] STR R0, [R13, #PCONJ_OFS] STR R1, [R13, #PUPJ_OFS] ENDIF
ENDIF ;;以下函数为进入相应的模式,并定义相应模式的端栈大小 ;//为每个模式设置栈 LDR R0, =Stack_Top
;//进入未定义指令模式并设定其栈指针 MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit MOV SP, R0 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 ; IMPORT MMU_EnableICache ; bl MMU_EnableICache
;//进入 用户 模式,并设定其栈指针 //;最后进入用户模式 MSR CPSR_c, #Mode_USR MOV SP, R0 SUB SL, SP, #USR_Stack_Size
;//进入C代码 ; IMPORT __main LDR R0, =__main BX R0
;//用护初始堆与栈 ;//用户设置堆栈程序(C外部接口:用于动态申请内存使用)
AREA |.text|, CODE, READONLY
; IMPORT __use_two_region_memory
EXPORT __user_initial_stackheap __user_initial_stackheap /********************************************************************** //__user_initial_stackheap 库函数用法翻译 用法: __user_initial_stackheap 返回这些值: 1. 堆基址(heap base) ---> RO 2. 栈基址(stack base,一般为栈的最高地址) ---> R1 |