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