ARM7 启动代码
- 格式:doc
- 大小:56.50 KB
- 文档页数:25
如何编写ARM7的启动代码(LPC2119为例)随着生活水平的提高和IT技术的进步,8位处理器的处理能力已经不能满足嵌入式系统的需要了;而16位处理器在性能和成本上都没有很大的突破。
并且在8位机的开发中,大多使用汇编语言来编写用户程序。
这使得程序的可维护性、易移植性等都受到了极大的挑战。
正是基于此,ARM 公司适时的推出了一系列的32位嵌入式微控制器。
目前广泛使用的是ARM7和ARM9系列,ARM7TDMI内核的ARM7处理器广泛应用于工业控制、仪器仪表、汽车电子、通讯、消费电子等嵌入式设备。
本文主要以philips 公司ARM7TDMI核的LPC2119为例来分析如何编写ARM7的启动代码。
1、启动代码在嵌入式系统软件的开发中,应用程序通常是在嵌入式操作系统的开发平台上采用C语言编写的。
然而,在ARM系统上电复位后,需要设置中断向量表、初始化各模式堆栈、设置系统时钟频率等,而这些过程都是针对ARM内部寄存器结构的操作,用C语言编程是很难实现的。
因此在转到应用程序的c/c++编写之前,需要用ARM的汇编语言编写启动代码,由启动代码完成系统初始化以及跳转到用户C程序。
在ARM设计开发中,启动代码的编写是一个极重要的过程。
然而启动代码随具体的目标系统和开发系统有所区别,但通常包含以下部分:·向量表定义·地址重映射及中断向量表的转移·堆栈初始化·设置系统时钟频率·中断寄存器的初始化·进入C应用程序下面就结合PHILIPS的LPC2119的启动代码来分析与说明ARM7处理器的启动代码的编写。
1.1向量表定义ARM芯片上电或复位后,系统进入管理模式、ARM状态、PC(R15)指向0x00000000地址处。
中断向量表为每一个中断设置1个字的存储空间,存放一条跳转指令,通过这条指令使PC指针指向相应的中断服务程序入口,继而执行相应的中断处理程序。
LPC2219的中断向量表和其它基于ARM核的芯片中断向量表较类似,只要注意LPC2219要使向量表所有数据32位累加和为零(0x00000000-0x0000001C的8个字的机器码累加), 才能使用户的程序脱机运行。
Embedded Seminar“PC ”hello worldARMARM IDE“HELLO WORLD ”Simulator-CEmbedded SeminarARMARMARMARMARMEmbedded SeminarARM Architecture4THalfword and signed halfword / byte support System modeThumbinstruction set4Improved ARM/Thumb Interworking CLZ5TESaturated arithmetic DSP multiply-accumulate instructions5TEJJazelleJava bytecode execution6SIMD InstructionsMulti-processing V6 Memory architecture (VMSA)Unaligned data support6T26ZThumb-2instruction setTrustZoneAOS extensions(v6k)7A7R7MApplications profileReal-Time profileMicrocontroller profileEmbedded SeminarARM32.ARM:Byte8 bitsHalfword16 bits(2 bytes)Word32 bits (4 bytes)ARM coreARM32-bitThumb16-bitJazelle cores Java byteEmbedded SeminarARMxyz Application codeOSS/W Interrupt (SWI)Undefined Instruction PrivilegedmodesUser modeMemoryInstructions & Data Aborts Interrupts ResetEmbedded SeminarARM 7:User :FIQ :fast) IRQ :normal)Supervisor :Abort :(memory access violations)Undef :System :UserPrivilegedUn-privilegedARM Embedded SeminarARM3732-Bits.1PC (program counter)1CPSR (current program status register)5SPSR (saved program status registers)30.r0-r12r13(the stack pointer, sp) and r14(the link register,lr)r15(the program counter,pc)CPSR (current program status register, cpsr)(system)SPSR(saved program status register)Embedded SeminarARMr0r1r2r3r4r5r6r7r8r9r10r11r12r15 (pc)cpsrr13 (sp)r14 (lr)User modespsr r13 (sp)r14 (lr)IRQFIQr8r9r10r11r12r13 (sp)r14 (lr)spsr spsr r13 (sp)r14 (lr)Undefspsr r13 (sp)r14 (lr)Abortspsrr13 (sp)r14 (lr)SVCCurrent mode Banked out registersNote: System mode uses the User mode register set.Embedded SeminarN =N egative result from ALU Z = Z ero result from ALUC = ALU operation C arried out V = ALU operation o V erflowedQARM 5TE/JJARM 5TE/J J = 1:JazelleI = 1: IRQ.F = 1: FIQ.T BitARM xT T = 0: ARM T = 1:ThumbModeIT[7:2]IT[1:0]27312867I F T mode16238155424fsxcJGE[3:0]E A N Z V C Q 26251091920v6GE[3:0: ]: SIMD E:endian A:AbortIF[7:0]: Thumb-2ITv6undefined.Embedded SeminarARM ARM ARM ARM ARMTM1111Embedded SeminarROM or RAM at 0x0?0x0 ROM at 0x0 ROM/RAM Remapping0x180000x18000RAM0x10000ROMReset Handler 0x100000x40000x4000 Reset Handler Vectors 0x0000ROM0x0000Aliased RAM ROMReset Handler VectorsRESET HANDLER ……TM1212Embedded Seminar-GCC_start• • •main { } __gccmain()•CTM1313Embedded Seminar-ARMC Library__maincopy code and data zero uninitialized dataUser Codemain( ) __rt_entryset up application stack and heap initialize library functions call top-level constructors (C++) Exit from application causes the linker to pull in library initialization codeTM1414Embedded SeminarARM ARM ARM ARM ARMTM1515Embedded SeminarARM0x1C 0x18 0x14 0x10 0x0C 0x08 0x04 0x00FIQ IRQ (Reserved) Data Abort Prefetch AbortSoftware Interrupt Undefined InstructionResetVector TableVector table can be at 0xFFFF0000 on ARM720T and on ARM9/10 family devicesTM1616Embedded SeminarThe Vector TableAREA Vectors, CODE, READONLY IMPORT Reset_Handler ; import other exception handlers ; … ENTRY B Reset_Handler B Undefined_Handler B SWI_Handler B Prefetch_Handler B Data_Handler NOP ; Reserved vector B IRQ_Handler ; FIQ_Handler will follow directly ENDscatterloading+FIRST ENTRY0X00xFFFF0000TM1717Embedded SeminarARM ARM ARM ARM ARMTM1818Embedded SeminarTM1919Embedded Seminar• char • short • int • long • float • double • pointer • long long • bool • wchar_t • char pointer8 bit byte 16 bit half-word 32 bit word 32 bit integer 32 bit IEEE 64 bit IEEE 32 bits 64 bit integer 8 bit byte 32 bit wordTM2020Embedded SeminarCPCTM2121Embedded Seminarstack model)heap (two-region model)SB(one-regionStack Heapheap is checked against stack pointerheap is checked against heap limitHLHB SBStack HB (SL)HeapOne region modelTwo region modeluse_two_region_memory-apcs /swst ( two-region)TM2222Embedded Seminar--ARMStack0x8000 heapHeap (malloc,alloc)C Startup Code ARMulator => from configuration file (peripherals.ami)default = 0x08000000 Multi-ICE => from debugger internal variable $top_of_memory default = 0x80000ZI RWRO 0x8000TM2323Embedded Seminar--GCC.STACK .TEXT .DATA .BSS .BSS .RODATARAM/DRAM/SDRAM.DATA .DATA’.TEXTROTM2424Embedded SeminarCODE :RO RW RW CODE , ARMLINKeg: armlink file1.o file2.o …DATAZI DATAsection A ZI RO -DATA RW RO -CODE CODE B section A from file2.oAfrom file1.oROTM2525Embedded SeminarScatter Loading0x8000eg: armlink program.o -scatter scatter.scf -o program.axfTM2626Embedded SeminarLoad View0x18000Execute View0x18000RAM0x10000Fill with zerosZI RWRAM0x10000Copy0x4000 0x4000ROM0x0000RW RO ROROM0x0000ROM CROM RAM RW ZI(__main)RAM:TM2727Embedded Seminar0x40000000 0x28000000 RO Flash 0x24000000 0x18000 16 bit RAM 0x10000 0x4000 Fast 32 bit RAM 0x0000 Stack Exception Handlers Vector Table Heap Reset HandlerPeripheralsFLASH16RW & ZIRAMHEAPRAMTM2828Embedded SeminarIMPORT ||Image$$RO$$Base|| IMPORT ||Image$$STACK$$ZI$$Base|| IMPORT ||Image$$RW$$Base|| IMPORT ||Image$$RW$$Limit||.extern .extern .extern .extern .externImage_RO_Base Image_RO_Limit Image_RW_Base Image_ZI_Base Image_ZI_Limitcode_baseDCD ||Image$$RO$$Base||.equ code_base,Image_RO_Base .equ stack_base, Image_ZI_Limit .equ data_base, Image_RW_Base .equ data_limit, Image_ZI_Limitstack_base DCD ||Image$$STACK$$ZI$$Base|| data_base DCD ||Image$$RW$$Base ||data_limit DCD ||Image$$RW$$Limit ||ldr ldrr1,=code_base r3,=data_limitTM2929Embedded SeminarARM ARM ARM ARM ARMTM3030Embedded Seminarreset handler cachesreset handler CIMPORT __mainB __mainEmbedded SeminarEmbedded SeminarMain( )Rtos_Init( )MyRoot( )……Embedded SeminarBootloader1-2BSP (Board Support Package)BIOSEmbedded Seminar C Library User Code__maincopy code and data zero uninitialized data __rt_entryinitialize library functions call top-level constructors (C++)Exit from application main( )tells linker to link in library initialization codeImage Entry Point__user_initial_stackheap( )set up stack & heapreset handlerinitialize stack pointers configure MMU/MPU setup cache/enable TCM $Sub$$main( )enable caches & interruptsEmbedded SeminarARMARMARMARMARMEmbedded Seminar。
arm启动代码详细分析所谓启动代码,就是处理器在启动的时候执行的一段代码,主要任务是初始化处理器模式,设置堆栈,初始化变量等等.由于以上的操作均与处理器体系结构和系统配置密切相关,所以一般由汇编来编写.具体到S64,启动代码分成两部分,一是与ARM7TDMI内核相关的部分,包括处理器各异常向量的配置,各处理器模式的堆栈设置,如有必要,复制向量到RAM,以便remap之后处理器正确处理异常,初始化数据(包括RW与ZI),最后跳转到Main.二是与处理器外部设备相关的部分,这和厂商的联系比较大.虽然都采用了ARM7TDMI的内核,但是不同的厂家整合了不同的片上外设,需要不同的初始化,其中比较重要的是初始化WDT,初始化各子系统时钟,有必要的话,进行remap.这一部分与一般控制器的初始化类似,因此,本文不作重点描述.在进行分析之前,请确认如下相关概念:S64片上FLASH起始于0x100000,共64kB,片上RAM起始于0x200000,共16kB.S64复位之后,程序会从0开始执行,此时FLASH被映射到0地址,因此,S64可以取得指令并执行.显然,此时还是驻留在0x100000地址.如果使用remap命令,将会把RAM映射到0地址,同样的这时0地址的内容也只是RAM的镜像.S64的FLASH可以保证在最差情况时以30MHz进行单周期访问,而RAM可以保证在最大速度时的单周期访问.OK,以下开始分析启动代码.一,处理器异常S64将异常向量至于0地址开始的几个直接,这些是必需要处理的.由于复位向量位于0,也需要一条跳转指令.具体代码如下:RESETB SYSINIT ; ResetB UDFHANDLER ; UNDEFINEDB SWIHANDLER ; SWIB PABTHANDLER ; PREFETCH ABORTB DABTHANDLER ; DATA ABORTB . ; RESERVEDB VECTORED_IRQ_HANDLERB . ; ADD FIQ CODE HEREUDFHANDLERB .SWIHANDLERB .PABTHANDLERB .DABTHANDLERB .请注意,B指令经汇编后会替换为当前PC值加上一个修正值(+/-),所以这条指令是代码位置无关的,也就是不管这条指令是在0地址还是在0x100000执行,都能跳转到指定的位置,而LDR PC,=???将向PC直接装载一个标号的值,请注意,标号在编译过后将被替换为一个与RO相对应的值,也就是说,这样的指令无论在哪里执行,都只会跳转到一个指定的位置.下面举一个具体的例子来说明两者的区别:假定有如下程序:RESETB INIT 或者LDR PC,=INIT…INIT…其中RESET为起始时的代码,也就是这条代码的偏移为0,设INIT的偏移量为offset.如果将这段程序按照RO=0x1000000编译, 那么B INIT可理解为ADD PC, PC, #offset,而LDR PC,=INIT可被理解为MOV PC,#(RO+offset) .显然当系统复位时,程序从0开始运行,而0地址有FLASH的副本,执行B INIT将把PC指向位于0地址处的镜像代码位置,也即INIT;如果执行LDR PC,=INIT将会将PC直接指向位于FLASH中的原始代码.因此以上两者都能正确运行.下面将RO设置为0x200000,编译后生成代码,还是得烧写到FLASH 中,也就是还是0x100000,系统复位后从0地址执行,还是FLASH的副本,此时执行B INIT,将跳到副本中的INIT位置执行,此处有对应的代码;但是如果执行LDR PC,=INIT,将向PC 加载0x200000+offset,这将使得PC跳到RAM中,而此时由于代码没有复制,RAM中的指定位置并没有代码,程序无法运行.二,处理器模式ARM的处理器可工作于多种模式,不同模式有不同的堆栈,以下设置各模式及其堆栈.预定义一些参数:MODUSR EQU 0x10MODSYS EQU 0x1FMODSVC EQU 0x13MODABT EQU 0x17MODUDF EQU 0x1BMODIRQ EQU 0x12MODFIQ EQU 0x11IRQBIT EQU 0x80FIQBIT EQU 0x40RAMEND EQU 0x00204000 ; S64 : 16KB RAMVECTSIZE EQU 0x100 ;UsrStkSz EQU 8 ; size of USR stackSysStkSz EQU 128 ; size of SYS stackSvcStkSz EQU 8 ; size of SVC stackUdfStkSz EQU 8 ; size of UDF stackAbtStkSz EQU 8 ; size of ABT stackIrqStkSz EQU 128 ; size of IRQ stackFiqStkSz EQU 16 ; size of FIQ stack修改这些值即可修改相应模式堆栈的尺寸.以下为各模式代码:SYSINIT;MRS R0,CPSRBIC R0,R0,#0x1FMOV R2,#RAMENDORR R1,R0,#(MODSVC :OR: IRQBIT :OR: FIQBIT) MSR cpsr_cxsf,R1 ; ENTER SVC MODEMOV sp,R2SUB R2,R2,#SvcStkSzORR R1,R0,#(MODFIQ :OR: IRQBIT :OR: FIQBIT)MSR CPSR_cxsf,R1 ; ENTER FIQ MODEMOV sp,R2SUB R2,R2,#FiqStkSzORR R1,R0,#(MODIRQ :OR: IRQBIT :OR: FIQBIT)MSR CPSR_cxsf,R1 ; ENTER IRQ MODEMOV sp,R2SUB R2,R2,#IrqStkSzORR R1,R0,#(MODUDF :OR: IRQBIT :OR: FIQBIT) MSR CPSR_cxsf,R1 ; ENTER UDF MODEMOV sp,R2SUB R2,R2,#UdfStkSzORR R1,R0,#(MODABT :OR: IRQBIT :OR: FIQBIT)MSR CPSR_cxsf,R1 ; ENTER ABT MODEMOV sp,R2SUB R2,R2,#AbtStkSz;ORR R1,R0,#(MODUSR :OR: IRQBIT :OR: FIQBIT) ;MSR CPSR_cxsf,R1 ; ENTER USR MODE;MOV sp,R2;SUB R2,R2,#UsrStkSzORR R1,R0,#(MODSYS :OR: IRQBIT :OR: FIQBIT)MSR CPSR_cxsf,R1 ; ENTER SYS MODEMOV sp,R2 ;三,初始化变量编译完成之后,连接器会生成三个基本的段,分别是RO,RW,ZI,并会在image中顺序摆放.显然,RW,ZI在运行开始时并不位于指定的RW位置,因此必须初始化LDR R0,=|Image$$RO$$Limit|LDR R1,=|Image$$RW$$Base|LDR R2,=|Image$$ZI$$Base|1CMP R1,R2LDRLO R3,[R0],#4STRLO R3,[R1],#4BLO %B1MOV R3,#0LDR R1,=|Image$$ZI$$Limit|2CMP R2,R1STRLO R3,[R2],#4BLO %B2四,复制异常向量由于代码于RAM运行时,有明显的速度优势,而且变量可以动态配置,因此可以通过re map将RAM映射到0,使得出现异常时ARM从RAM中取得向量.IMPORT |Image$$RO$$Base|IMPORT |Image$$RO$$Limit|IMPORT |Image$$RW$$Base|IMPORT |Image$$RW$$Limit|IMPORT |Image$$ZI$$Base|IMPORT |Image$$ZI$$Limit|COPY_VECT_TO_RAMLDR R0,=|Image$$RO$$Base|LDR R1,=SYSINITLDR R2,=0x200000 ; RAM STARTCMP R0,R1LDRLO R3,[R0],#4STRLO R3,[R2],#4BLO %B0这段程序将SYSINIT之前的代码,也就是异常处理函数,全部复制到RAM中, 这就意味着不能将RW设置为0x200000,这样会使得向量被冲掉.四,在RAM中运行如果有必要,且代码足够小,可以将代码置于RAM中运行,由于RAM中本身没有代码,就需要将代码复制到RAM中:COPY_BEGINLDR R0,=0x200000LDR R1,=RESET ; =|Image$$RO$$Base|CMP R1,R0 ;BLO COPY_END ;ADR R0,RESETADR R2,COPY_ENDSUB R0,R2,R0ADD R1,R1,R0LDR R3,=|Image$$RO$$Limit|3CMP R1,R3LDRLO R4,[R2],#4STRLO R4,[R1],#4BLO %B3LDR PC,=COPY_ENDCOPY_END程序首先取得RESET的连接地址,判断程序是否时是在RAM中运行,方法是与RAM起始地址比较,如果小于,那么就跳过代码复制.在复制代码的时候需要注意,在这段程序结束之前的代码没有必要复制,因为这些代码都已经执行过了,所以,先取得COPY_END,作为复制起始地址,然后计算其相对RESET的偏移,然后以RO的值加上这个偏移,就是复制目的地的起始地址,然后开始复制.五,开始主程序以上步骤完成,就可以跳转到main运行IMPORT MainLDR PC,=MainB .六,器件初始化主程序首先要进行器件的初始化,对S64而言,应该先初始化WDT,因为默认情况下,W DT是打开的,然后是各设备的时钟分配,最后应该remapiar下.s79的分析BSP目录中的是和硬件平台代码相关的函数和定义。
ARM7启动代码的分析与设计
王小良;吴言荪;刘世宇
【期刊名称】《电子测量技术》
【年(卷),期】2008(31)1
【摘要】ARM处理器正逐步成为嵌入式系统的主力军。
ARM处理器启动代码的
编写必然成为嵌入式系统开发人员必备的能力。
本文首先简单介绍了编写ARM处理器启动代码的必要性及启动代码的一般组成,然后结合ARM7TDMI核的
LPC2119,重点阐述了ARM7处理器启动程序底层的组成结构和各部分的具体内容。
【总页数】3页(P1-2)
【关键词】ARM7TDMI核;启动代码;中断向量表;堆栈
【作者】王小良;吴言荪;刘世宇
【作者单位】重庆大学电气工程学院
【正文语种】中文
【中图分类】TP273.5
【相关文献】
1.ARM处理器启动代码的分析与设计 [J], 甘泉;杨健;陈永泰
2.ARM处理器启动代码的分析与设计 [J], 甘泉;杨健;陈永泰
3.ARM处理器启动代码的分析与设计 [J], 邓丽芳
4.ARM处理器启动代码分析与设计 [J], 梁斌;司扬;张爱军
5.ARM7启动代码设计方法与流程 [J], 姜京梅; 郭树旭
因版权原因,仅展示原文概要,查看原文内容请购买。
实验三C语言启动代码与Keil5程序调试实验实验步骤:1.创建项目。
(1)选择处理器芯片型号:NXP--->LPC2103。
(2)选择创建启动代码。
(4)把main.c文件添加到项目中。
(6)把MyAsmFun.s文件添加到项目中。
2.编译项目3.启动调试项目(1)点击DEBUG--->Start/Stop Debug Session(2)在main.c的第16行程序处,设置一个断点;(3)Debug--->Run;(4)View--->{。
},打开各类观察窗口,跟踪程序运行。
(5)DEBUG--- > {Step over /Step in/Step out},观察程序运行结果:变量i、s、sum1/2/3等值的变化。
(6)调试汇编时,可观察CPU内核寄存器值、存储器内容、反汇编窗口等。
语言表达是一种特殊的社会实践活动,有着源远流长的历史,如果说书面语言是人类语言的第二种基本形态,那么口语便是第一种基本形态,它能够更直接更感性的表情达意,所以重新认识和掌握语言的表达艺术与技巧,是我们每一位渴望成功的人所必须的技能。
你认识自己的声音吗?你会说话吗?你能准确达意吗?你知道什么是说的比唱的好听吗?要做到这些,我们就要学会了解“语言表达艺术”这一有声音语言创作形式的规律,掌握其要领及技巧。
在本讲座中我们将从语言表达艺术的特性、语言表达的个性风格、语言表达的基本技巧、以及对声音的认识等方面进行分析,并结合自身特点掌握训练方法。
一、声音的认知</P> 人类没有单独的发音器官,而是利用呼吸器官、消化器官作为自己的发音器官。
其作用原理是: (1)呼吸——气乃声之本。
气息是发声的动力,储藏和控制运用气息是表达发声的基本训练。
(2)声带——靠气息震动发出声音,但这只是基本音源,声带产生的音量只占讲话音量的5%。
(3)共鸣——是通过头腔、口腔、咽腔、鼻腔、胸腔把声带的音量放大美化的过程,其作用占音量的95%。
ARM启动代码详细注释syd168 2009-07-232410Init.s包括了板子上电后的初始化过程,具体有以下几个步骤:1.屏蔽所有中断,关看门狗。
2.根据工作频率设置PLL寄存器3.初始化存储控制相关寄存器4.初始化各模式下的栈指针5.设置缺省中断处理函数6.将数据段拷贝到RAM中,将零初始化数据段清零7.跳转到C语言Main入口函数中;=========================================; NAME: 2410INIT.S; DESC: C start up codes; Configure memory, ISR ,stacks; Initialize C-variables; HISTORY:; 2002.02.25:kwtark: ver 0.0; 2002.03.20:purnnamu: Add some functions for testing STOP,POWER_OFF mode; 2002.04.10:SJS:sub interrupt disable 0x3ff -> 0x7ff;=========================================GET option.s ;GET相当INCLUDE 将一个源文件包含到当前源文件,这里表示包含option.s,并在当前位置进行汇编GET memcfg.sGET 2410addr.sBIT_SELFREFRESH EQU (1<<22);SDRAM/DRAM 刷新控制器bit22 REFMD位0:CBR/AUTO REFRESH 1:SHIF REFRESH;下面是对arm处理器模式寄存器对应值的常数定义,arm处理器中有一个CPSR程序状态寄存器,后五位决定目前的处理器模式。
;Pre-defined constants ;PSR 模式位USERMODE EQU 0x10 ;用户模式FIQMODE EQU 0x11 ;FIQ快速中断模式IRQMODE EQU 0x12 ;中断模式SVCMODE EQU 0x13 ;超级用户模式ABORTMODE EQU 0x17 ;中止模式UNDEFMODE EQU 0x1b ;未定义指令模式MODEMASK EQU 0x1f ;系统模式NOINT EQU 0xc0 ;禁止IRQ和FIQ中断在option.s中, _STACK_BASEADDRESS EQU (SDRAM_END-0x8000) ;0x33ff8000;;定义各模式堆栈地址_STACK_BASEADDRESSUserStack EQU (_STACK_BASEADDRESS-0x3800) ;0x33ff4800 ~ ; 用户模式堆栈SVCStack EQU (_STACK_BASEADDRESS-0x2800) ;0x33ff5800 ~0x3ff47ff ; 超级用户模式堆栈4kUndefStack EQU (_STACK_BASEADDRESS-0x2400) ;0x33ff5c00 ~0x3ff57ff ; 未定义指令模式堆栈1kAbortStack EQU (_STACK_BASEADDRESS-0x2000) ;0x33ff6000 ~0x3ff5bff ; 中止模式堆栈1kIRQStack EQU (_STACK_BASEADDRESS-0x1000) ;0x33ff7000 ~0x3ff5fff ; 中断模式堆栈4kFIQStack EQU (_STACK_BASEADDRESS-0x0) ;0x33ff8000 ~0x33ff6fff ; 快速中断模式堆栈4k;arm处理器有两种工作状态;1.arm:32位这种工作状态下执行字对齐的arm指令;2.Thumb:16位这种工作状;态执行半字对齐的Thumb指令;因为处理器分为16位32位两种工作状态程序的编译器也是分16位和32两种编译方式;所以下面的程序用于根据处理器工作状态确定编译器编译方式;code16伪指令指示汇编编译器,后面的指令为16位的thumb指令;code32伪指令指示汇编编译器,后面的指令为32位的arm指令;这段是为了统一目前的处理器工作状态和软件编译方式(16位编译环境使用tasm.exe编译);===========================================================================================;Check if tasm.exe(armasm -16 ...@ADS 1.0) is used. 检查是否是用tasm.exe进行16位编译GBLL THUMBCODE ;声明一个全局变量并初始化为{FALSE}[ {CONFIG} = 16 ;if config=16这里表示用16位编译方式THUMBCODE SETL {TRUE} ;SETL 给全局变量赋值,;设置THUMBCODE 为true CODE32 ;转入32位编译模式| ; | 等同ELSETHUMBCODE SETL {FALSE} ;设置THUMBCODE 为false] ; ] 等同ENDIF;========================================================================================== MACRO ;MACRO 定义宏MOV_PC_LR ;宏名MOV_PC_LR[ THUMBCODE ;if THUMBCODE=truebx lr ;THUMBCODE 模式上返回ARM状态| ;elsemov pc,lr ;ARM状态下返回] ;end ifMEND ;宏结束;================================================================MACRO ;宏定义开始MOVEQ_PC_LR ;宏名为MOVEQ_PC_LR[ THUMBCODE ;if THUMBCODE=truebxeq lr ;EQ 相等则跳转回ARM状态| ;elsemoveq pc,lr ;????] ;end ifMEND ;宏结束;==================================================================;注意下面这段程序是个宏定义;下面包含的HandlerXXX HANDLER HandleXXX将都被下面这段程序展开;这段程序用于把中断服务程序的首地址装载到pc中,有人称之为“加载程序”。
from:/116243391.html网上已经有人做了一个周立功lpc2000(ARM7TDMI)启动代码分析的文章,我本来想做一个s3c2410(ARM920T)的启动代码分析的, 但是看来了一下2410的启动代码,发现有些东西还不是理解的很清楚, 我ARM9的经验比较少.ARM7的启动代码分析网上那一份相比,我这个主要关注startup.s文件.网上那个startup.s几乎是一笔带过的.红色标记的是源码.SVC_STACK_LEGTH EQU 0FIQ_STACK_LEGTH EQU 0IRQ_STACK_LEGTH EQU 256ABT_STACK_LEGTH EQU 0UND_STACK_LEGTH EQU 0NoInt EQU 0x80USR32Mode EQU 0x10SVC32Mode EQU 0x13SYS32Mode EQU 0x1fIRQ32Mode EQU 0x12FIQ32Mode EQU 0x11上面几行代码,不用过多分析, 定义几个符号而已, 把EQU想像成C中的#define就可以了. 具体定义的数值,下面的代码用到我再解释.IMPORT __use_no_semihosting_swi上面这一句的作用是在代码中禁用 semihosting 机制. 到底什么是semihostiong这里不多说, 网上有很多. 这里只说明Semihosting主要用来调试, 在release版本的代码中一般是要禁用的.IMPORT FIQ_ExceptionIMPORT __mainIMPORT TargetResetInit上面三行是把要引入的外部标号声明一下,以便下面使用.EXPORT bottom_of_heapEXPORT StackUsrEXPORT ResetEXPORT __user_initial_stackheap上面四行是把要给其它文件使用的标号声明AREA vectors,CODE,READONLYENTRY上面这一行声明汇编文件的入口, 整个文件是从这里开始执行的.ResetLDR PC, ResetAddrLDR PC, UndefinedAddrLDR PC, SWI_AddrLDR PC, PrefetchAddrLDR PC, DataAbortAddrDCD 0xb9205f80LDR PC, [PC, #-0xff0]LDR PC, FIQ_Addr上面几行是配置中断向量表. 中断向量表的顺序是不能变的,因为这是ARM7规定的,可以参考相关书籍. 这里有几个问题要说明一下.第一, 关于DCD 0xb9205f80, 按照ARM7的中断向量表分布图, 这个位置是个保留位. 但是究竟为什么要用0xb9205f80这个数值呢.根据周立功的说法, nxp系列的lpc21xx,lpc22xx片子要求"中断向量表中所有数据32位累加和为0,否则程序不能脱机运行", 我在AXD反汇编了一下(如下图),把中断向量表中的8个机器码累加了一下:0xe59ff018*6+0xe51ffff0+0xb9205f80,没错, 结果是零. 但是我遇到一个问题, 就是我在实验中,把0xb9205f80这个数值改成任何值,程序运行都没问题. 头大了, 这个问题待解决中……(希望高手看到了可以指点一二).第二, 关于LDR PC, [PC, #-0xff0]. 这里本应该放IRQ中断的, 为什么是这么一句话. 其实在我blog的其中一篇文章里有提到过这一点.ARM7的三级流水线结构导致了PC指向的是当前指令的后8个字节. 本来IRQ是应该放在0x00000018处的. LDR PC, [PC, #-0xff0]这条语句执行后, PC的当前值就是0x00000018+8-0xff0. 很容易计算出它的结果是0xfffff030. 看一下lpc22xx的手册就知道. 这个地址就是VICVectAddr. 也就是说本来这个地址是应该放IRQ服务程序的入口地址的,但是这个地址被放在了VICVectAddr 这个寄存器里. 英文手册里有一段对VICVectAddr 描述. 看了之后就容易明白是怎么回事了: Vector Address Register. When an IRQ interrupt occurs, the IRQ service routine can read this register and jump to the value readResetAddr DCD ResetInitUndefinedAddr DCD UndefinedSWI_Addr DCD SoftwareInterruptPrefetchAddr DCD PrefetchAbortDataAbortAddr DCD DataAbortNouse DCD 0IRQ_Addr DCD 0FIQ_Addr DCD FIQ_Handler这几行是为上面中断向量表中的中断标号分配内存空间, 也就是它们的执行地址. 一开始我有个疑问, 为什么不直接用LDR PC, ResetInit,还要用DCD中转一下, 后来上网查了一下,才恍然大悟, ldr指令中的地址必须为当前指令地址是4KB范围内, 用DCD中转一下就可以在整个程序空间寻址.UndefinedB UndefinedSoftwareInterruptB SoftwareInterruptPrefetchAbortB PrefetchAbortDataAbortB DataAbortFIQ_HandlerSTMFD SP!, {R0-R3, LR}BL FIQ_ExceptionLDMFD SP!, {R0-R3, LR}SUBS PC, LR, #4这几行不用过多解释, 只是说明上面几个异常如何执行.InitStackMOV R0, LR;设置管理模式堆栈MSR CPSR_c, #0xd3LDR SP, StackSvc;设置中断模式堆栈MSR CPSR_c, #0xd2LDR SP, StackIrq;设置快速中断模式堆栈MSR CPSR_c, #0xd1LDR SP, StackFiq;设置中止模式堆栈MSR CPSR_c, #0xd7LDR SP, StackAbt;设置未定义模式堆栈MSR CPSR_c, #0xdbLDR SP, StackUnd;设置系统模式堆栈MSR CPSR_c, #0xdfLDR SP, =StackUsrMOV PC, R0上面是一个子函数, 函数名为InitStack. 顾名思意, 这个函数设置ARM七种工作模式下的堆栈. 关于这一段代码有三点要说.第一, MSR CPSR_c, #0xdf, 这一句把ARM的工作模式设置为系统模式,或者也可以说是用户模式, 因为系统模式与用户模式是共享相同的寄存器组. 用0xdf对CPSR寄存器赋值,就把IRQ中断关闭了(可以查一下CRSR的详细说明), 代码正常执行时处理器是处在用户模式的,所以IRQ中断是不会执行的. 所以,如果用周立功的这个启动代码,当你的程序中需要中断时,要把0xdf改成0x5f. 之前看到很多人在网上说用周立功的ADS工程模板,进不了中断,很多情况下是这个原因.第二, 并不是每一种模式下的堆栈都用设置的, 比如说如果你的程序中不会用到FIQ,就可以不用设置快速中断下的堆栈.第三, 注意LDR SP, =StackUsr这个语句, 其它都是没有=号的, 为什么这个要用等号呢? 这就是LDR伪指令与LDR指令的区别了, LDR SP, =StackUsr是把StackUsr表示的地址装载到sp, LDR SP, StackUnd是把StackUnd表示地址的内容装载到sp,注意下面几句StackSvc DCD SvcStackSpace + (SVC_STACK_LEGTH - 1)* 4StackIrq DCD IrqStackSpace + (IRQ_STACK_LEGTH - 1)* 4StackFiq DCD FiqStackSpace + (FIQ_STACK_LEGTH - 1)* 4StackAbt DCD AbtStackSpace + (ABT_STACK_LEGTH - 1)* 4StackUnd DCD UndtStackSpace + (UND_STACK_LEGTH - 1)* 4可以看到,没有”=”的标号都已经用DCD初始化了, 而StackUsr到底是什么呢, 它是由下面的语句决定的(startup.s文件)AREA Stacks, DATA, NOINITStackUsr(分散加载文件)STACKS 0x40002000 UNINIT{Startup.o (Stacks)}这样就明白了, StackUsr肯定是0x40000000~0x400020000之间的某个数. 用户模式下的堆栈空间就是它了.ResetInitBL InitStackBL TargetResetInitB __main处理器上电复位后通过中断向量表进入该函数,__main函数主要工作是初始化C的库函数, 并由它进入C的main函数.__user_initial_stackheapLDR r0,=bottom_of_heap; LDR r1,=StackUsrMOV pc,lr__user_initial_stackheap函数是ADS的一个库函数, 如果程序中用到的分散加载文件, 这个函数必须要被实现. 应用程序的栈和heap是在C库函数初始化过程中建立起来的。
ARM7TDMI-S在嵌入式系统中的Bootloader代码设计摘要:ARM7TDMI-S是ARM公司设计的一款32位精简指令集处理器内核,LPC210x系列是飞利浦半导体公司生产的基于ARM7TDMI-S内核的芯片。
在嵌入式系统设计中,针对嵌入式处理器和操作系统的Bootloader代码的设计是一个难点。
本文根据用LPC2106进行嵌入式系统设计的实际经验,>"/">总结出基于ARM7TDMI-S内核的嵌入式处理器芯片的Bootloader代码设计的一般流程;给出LPC2106芯片在基于μC/OS-II操作系统的嵌入式应用中,BootLoader程序的详细设计流程及其中的一些关键技术和代码。
关键词:ARM7TDMI-S嵌入式系统 BootLoader代码 LPC2106 μC/OS-II引言芯片的Bootloader代码(即启动代码)就是芯片复位后进入操作系统之前执行的一段代码,主要是为运行操作系统提供基本的运行环境,如初始化CPU 堆栈、初始化存储器系统等。
Bootloader代码与CPU芯片的内核结构、具体芯片和使用的操作系统等因素有关。
其功能有点类似于PC机的BIOS(Basic Input/Output System,基本输入输出系统)程序,但是由于嵌入式系统的软硬件都要比PC机的简单,所以它的Bootloader代码要比BIOS程序简单得多。
嵌入式系统被定义为:以应用中为心,以计算机技术为基础,软件硬件可裁剪,适用于系统对功能、可靠性、成本、何种、功耗有严格要求的专用计算机系统。
嵌入式系统的核心部件是嵌入式处理器。
随着嵌入式系统在人们日常生活中的广泛运用,嵌入式处理器得到前所未有的飞速发展。
基于ARM核的嵌入式处理器芯片种类繁多。
由于ARM公司只设计内核的不生产具体的芯片,即便是基于同一种内核,不同厂家生产的芯片差别很大,因此不易编写出统一的Bootloader代码。
SAMSUNG公司推出的16、32位RISC处理器S3C44BOX为手持设备和一般类型应用提供了高性价比和高性能的微控制器解决方案。
为了降低成本,S3C44BOX提供了丰富的内置部件,包括8KBCache和内部SRAM,LCD控制器,带自动握手的2通道UART,4通道DMA,系统管理器(片选逻辑,FP/EDO/SDRAM控制器)。
带PWM功能的5通道定时器和一个内部定时器,I/O端口,RTC,8通道10位ADC,IIC_BUS 接口,IIS_BUS接口,同步SIO接口和PLL倍频器。
这里是一般的44BINIT.S,即其启动代码如下:; *******************************************************; * NAME : 44BINIT.S *; * Version : 10.JAn.2003 *; * Description: *; * C start up codes *; * Configure memory, Initialize ISR ,stacks *; * Initialize C-variables *; * Fill zeros into zero-initialized C-variables *; *******************************************************GET ..\inc\option.sGET ..\inc\memcfg.s;Interrupt ControlINTPND EQU 0x01e00004INTMOD EQU 0x01e00008INTMSK EQU 0x01e0000cI_ISPR EQU 0x01e00020I_CMST EQU 0x01e0001c;Watchdog timerWTCON EQU 0x01d30000;Clock ControllerPLLCON EQU 0x01d80000CLKCON EQU 0x01d80004LOCKTIME EQU 0x01d8000c;Memory ControllerREFRESH EQU 0x01c80024;Pre-defined constantsUSERMODE EQU 0x10FIQMODE EQU 0x11IRQMODE EQU 0x12SVCMODE EQU 0x13ABORTMODE EQU 0x17UNDEFMODE EQU 0x1bMODEMASK EQU 0x1fNOINT EQU 0xc0;check if tasm.exe is used.GBLL THUMBCODE[ {CONFIG} = 16THUMBCODE SETL {TRUE}CODE32|THUMBCODE SETL {FALSE}][ THUMBCODECODE32 ;for start-up code for Thumb mode]MACRO$HandlerLabel HANDLER $HandleLabel$HandlerLabelsub sp,sp,#4 ;decrement sp(to store jump address)stmfd sp!,{r0} ;PUSH the work register to stack(lr doest push because it return to original address)ldr r0,=$HandleLabel;load the address of HandleXXX to r0ldr r0,[r0] ;load the contents(service routine start address) of HandleXXXstr r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stackldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR)MENDIMPORT |Image$$RO$$Limit| ; End of ROM code (=start of ROM data)IMPORT |Image$$RW$$Base| ; Base of RAM to initialiseIMPORT |Image$$ZI$$Base| ; Base and limit of areaIMPORT |Image$$ZI$$Limit| ; to zero initialiseIMPORT Main ; The main entry of mon programAREA Init,CODE,READONLYENTRYb ResetHandler ;for debugb HandlerUndef ;handlerUndefb HandlerSWI ;SWI interrupt handlerb HandlerPabort ;handlerPAbortb HandlerDabort ;handlerDAbortb . ;handlerReservedb HandlerIRQb HandlerFIQ;***IMPORTANT NOTE***;If the H/W vectored interrutp mode is enabled, The above two instructions should ;be changed like below, to work-around with H/W bug of S3C44B0X interrupt controller.; b HandlerIRQ -> subs pc,lr,#4; b HandlerIRQ -> subs pc,lr,#4VECTOR_BRANCHldr pc,=HandlerEINT0 ;mGA H/W interrupt vector tableldr pc,=HandlerEINT1 ;ldr pc,=HandlerEINT2 ;ldr pc,=HandlerEINT3 ;ldr pc,=HandlerEINT4567 ;ldr pc,=HandlerTICK ;mGAb .b .ldr pc,=HandlerZDMA0 ;mGBldr pc,=HandlerZDMA1 ;ldr pc,=HandlerBDMA0 ;ldr pc,=HandlerBDMA1 ;ldr pc,=HandlerWDT ;ldr pc,=HandlerUERR01 ;mGBb .b .ldr pc,=HandlerTIMER0 ;mGCldr pc,=HandlerTIMER1 ;ldr pc,=HandlerTIMER2 ;ldr pc,=HandlerTIMER3 ;ldr pc,=HandlerTIMER4 ;ldr pc,=HandlerTIMER5 ;mGCb .b .ldr pc,=HandlerURXD0 ;mGDldr pc,=HandlerURXD1 ;ldr pc,=HandlerIIC ;ldr pc,=HandlerSIO ;ldr pc,=HandlerUTXD0 ;ldr pc,=HandlerUTXD1 ;mGDb .b .ldr pc,=HandlerRTC ;mGKAb . ;b . ;b . ;b . ;b . ;mGKAb .b .ldr pc,=HandlerADC ;mGKBb . ;b . ;b . ;b . ;b . ;mGKBb .b .ldr pc,=EnterPWDNEXPORT outportwoutportw strh r0, [r1]mov pc, lrEXPORT outportloutportl str r0, [r1]mov pc, lrEXPORT inportwinportw ldrh r0, [r0]mov pc, lrEXPORT inportlinportl ldr r0, [r0]mov pc, lrLTORGHandlerFIQ HANDLER HandleFIQ HandlerIRQ HANDLER HandleIRQ HandlerUndef HANDLER HandleUndef HandlerSWI HANDLER HandleSWI HandlerDabort HANDLER HandleDabortHandlerPabort HANDLER HandlePabortHandlerADC HANDLER HandleADCHandlerRTC HANDLER HandleRTCHandlerUTXD1 HANDLER HandleUTXD1HandlerUTXD0 HANDLER HandleUT XD0HandlerSIO HANDLER HandleSIOHandlerIIC HANDLER HandleIICHandlerURXD1 HANDLER HandleURXD1HandlerURXD0 HANDLER HandleURXD0HandlerTIMER5 HANDLER HandleTIMER5HandlerTIMER4 HANDLER HandleTIMER4HandlerTIMER3 HANDLER HandleTIMER3HandlerTIMER2 HANDLER HandleTIMER2HandlerTIMER1 HANDLER HandleTIMER1HandlerTIMER0 HANDLER HandleTIMER0HandlerUERR01 HANDLER HandleUERR01HandlerWDT HANDLER HandleWDTHandlerBDMA1 HANDLER HandleBDMA1HandlerBDMA0 HANDLER HandleBDMA0HandlerZDMA1 HANDLER HandleZDMA1HandlerZDMA0 HANDLER HandleZDMA0HandlerTICK HANDLER HandleTICKHandlerEINT4567 HANDLER HandleEINT4567HandlerEINT3 HANDLER HandleEINT3HandlerEINT2 HANDLER HandleEINT2HandlerEINT1 HANDLER HandleEINT1HandlerEINT0 HANDLER HandleEINT0;One of the following two routines can be used for non-vectored interrupt. IsrIRQ ;using I_ISPR register.sub sp,sp,#4 ;reserved for PCstmfd sp!,{r8-r9};IMPORTANT CAUTION;if I_ISPC isnt used properly, I_ISPR can be 0 in this routine.ldr r9,=I_ISPRldr r9,[r9]mov r8,#0x0movs r9,r9,lsr #1bcs %F1add r8,r8,#4b %B01ldr r9,=HandleADCadd r9,r9,r8ldr r9,[r9]str r9,[sp,#8]ldmfd sp!,{r8-r9,pc};****************************************************;* START *;****************************************************ResetHandlerldr r0,=WTCON ;watch dog disableldr r1,=0x0str r1,[r0]ldr r0,=INTMSKldr r1,=0x07ffffff ;all interrupt disablestr r1,[r0];****************************************************;* Set clock control registers *;****************************************************ldr r0,=LOCKTIMEldr r1,=800 ; count = t_lock * Fin (t_lock=200us, Fin=4MHz) = 800str r1,[r0][ PLLONSTARTldr r0,=PLLCON ;temporary setting of PLLldr r1,=((M_DIV<<12)+(P_DIV<<4)+S_DIV) ;Fin=10MHz,Fout=40MHz str r1,[r0]]ldr r0,=CLKCONldr r1,=0x7ff8 ;All unit block CLK enablestr r1,[r0];****************************************************;* Set memory control registers *;****************************************************ldr r0,=SMRDATAldmia r0,{r1-r13}ldr r0,=0x01c80000 ;BWSCON Addressstmia r0,{r1-r13};****************************************************;* Initialize stacks *;****************************************************ldr sp, =SVCStack ;Why?bl InitStacks;****************************************************;* Setup IRQ handler *;****************************************************ldr r0,=HandleIRQ ;This routine is neededldr r1,=IsrIRQ ;if there isn't 'subs pc,lr,#4 at 0x18, 0x1c str r1,[r0];********************************************************;* Copy and paste RW data/zero initialized data *;********************************************************ldr r0, =|Image$$RO$$Limit| ; Get pointer to ROM data ldr r1, =|Image$$RW$$Base| ; and RAM copyldr r3, =|Image$$ZI$$Base|;Zero init base => top of initialised datacmp r0, r1 ; Check that they are differentbeq %F1cmp r1, r3 ; Copy init dataldrcc r2, [r0], #4 ;--> LDRCC r2, [r0] + ADD r0, r0, #4 strcc r2, [r1], #4 ;--> STRCC r2, [r1] + ADD r1, r1, #4 bcc %B01ldr r1, =|Image$$ZI$$Limit| ; Top of zero init segment mov r2, #02cmp r3, r1 ; Zero initstrcc r2, [r3], #4bcc %B2[ :LNOT:THUMBCODEBL Main ;Dont use main()B .][ THUMBCODE ;for start-up code for Thumb modeorr lr,pc,#1bx lrCODE16bl Main ;Dont use main()b .CODE32];****************************************************;* The function for initializing stack *;****************************************************InitStacks;Dont use DRAM,such as stmfd,ldmfd......;SVCstack is initialized before;Under toolkit ver 2.50, 'msr cpsr,r1' can be used instead of 'msr cpsr_cxsf,r1' mrs r0,cpsrbic r0,r0,#MODEMASKorr r1,r0,#UNDEFMODE|NOINTmsr cpsr_cxsf,r1 ;UndefModeldr sp,=UndefStackorr r1,r0,#ABORTMODE|NOINTmsr cpsr_cxsf,r1 ;AbortModeldr sp,=AbortStackorr r1,r0,#IRQMODE|NOINTmsr cpsr_cxsf,r1 ;IRQModeldr sp,=IRQStackorr r1,r0,#FIQMODE|NOINTmsr cpsr_cxsf,r1 ;FIQModeldr sp,=FIQStackbic r0,r0,#MODEMASK|NOINTorr r1,r0,#SVCMODEmsr cpsr_cxsf,r1 ;SVCModeldr sp,=SVCStack;USER mode is not initialized.mov pc,lr ;The LR register may be not valid for the mode changes.;****************************************************;* The function for entering power down mode *;****************************************************;void EnterPWDN(int CLKCON);EnterPWDNmov r2,r0 ;r0=CLKCONldr r0,=REFRESHldr r3,[r0]mov r1, r3orr r1, r1, #0x400000 ;self-refresh enablestr r1, [r0]nop ;Wait until self-refresh is issued. May not be needed.nop ;If the other bus master holds the bus, ...nop ; mov r0, r0nopnopnopnop;enter POWERDN modeldr r0,=CLKCONstr r2,[r0];wait until enter SL_IDLE,STOP mode and until wake-upmov r0,#0xff0 subs r0,r0,#1bne %B0;exit from DRAM/SDRAM self refresh mode.ldr r0,=REFRESHstr r3,[r0]mov pc,lrLTORGSMRDATA DATA;*****************************************************************;* Memory configuration has to be optimized for best performance *;* The following parameter is not optimized. *;*****************************************************************;*** memory access cycle parameter strategy ***; 1) Even FP-DRAM, EDO setting has more late fetch point by half-clock; 2) The memory settings,here, are made the safe parameters even at 66Mhz.; 3) FP-DRAM Parameters:tRCD=3 for tRAC, tcas=2 for pad delay, tcp=2 for bus load.; 4) DRAM refresh rate is for 40Mhz.DCD 0x11001101 ;Bank0=OM[1:0], Bank1~Bank7=16bit, bank235=8bit;DCD((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tac p<<2)+(B0_PMC)) ;GCS0DCD((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tac p<<2)+(B1_PMC)) ;GCS1DCD((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tac p<<2)+(B2_PMC)) ;GCS2DCD((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tac p<<2)+(B3_PMC)) ;GCS3DCD((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tac p<<2)+(B4_PMC)) ;GCS4DCD((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tac p<<2)+(B5_PMC)) ;GCS5DCD ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN)) ;GCS6DCD ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN)) ;GCS7DCD((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT) ;REFRES H RFEN=1, TREFMD=0, trp=3clk, trc=5clk, tchr=3clk,count=1019DCD 0x16 ;SCLK power mode, BANKSIZE 32M/32MDCD 0x20 ;MRSR6 CL=2clkDCD 0x20 ;MRSR7ALIGNAREA RamData, DATA, READWRITE^ (_ISR_STARTADDRESS-0x500)UserStack # 256 ;c1(c7)ffa00SVCStack # 256 ;c1(c7)ffb00UndefStack # 256 ;c1(c7)ffc00AbortStack # 256 ;c1(c7)ffd00IRQStack # 256 ;c1(c7)ffe00FIQStack # 0 ;c1(c7)fff00^ _ISR_STARTADDRESSHandleReset # 4HandleUndef # 4HandleSWI # 4HandlePabort # 4HandleDabort # 4HandleReserved # 4HandleIRQ # 4HandleFIQ # 4;Don't use the label 'IntVectorTable',;because armasm.exe cann't recognize this label correctly. ;the value is different with an address you think it may be. ;IntVectorTableHandleADC # 4HandleRTC # 4HandleUTXD1 # 4HandleUTXD0 # 4HandleSIO # 4HandleIIC # 4HandleURXD1 # 4HandleURXD0 # 4HandleTIMER5 # 4HandleTIMER4 # 4HandleTIMER3 # 4HandleTIMER2 # 4HandleTIMER1 # 4HandleTIMER0 # 4HandleUERR01 # 4HandleWDT # 4HandleBDMA1 # 4HandleBDMA0 # 4HandleZDMA1 # 4HandleZDMA0 # 4HandleTICK # 4HandleEINT4567 # 4HandleEINT3 # 4HandleEINT2 # 4HandleEINT1 # 4HandleEINT0 # 4 ;0xc1(c7)fff84END。
ARM启动代码解析ARM启动代码解析1:PRESERVE8:Reguire8和Preserve8C和汇编有8位对齐的要求,这两个伪指令可以满足此要求,存在REQUIRE8<——> PRESERVE8的对应关系,但不是说有一个REQUIRE8就要有一个 PRESERVE8,如果是一个c文件和一个汇编文件的调用,也就涉及一个PRESERVE8或者是一个REQUIRE8.另外,REQUIRE8和PRESERVE8并不完成8 byte 对齐的操作,对齐由ALIGN完成。
将ADS的代码移植到KEIL MDK上需要做的修改:当用户拥有ADS遗留工程的所有源代码时,使用MDK重新编译链接全部代码是最好的解决方法,MDK中的新版本编译工具会重新生成满足堆栈8BYTE对齐要求的目标文件,避免由于堆栈不对齐引起的链接错误.从ADS到KEIL很重要的一个修改的地方就是这里的8BYTE对齐,想要编译通过,在startup.s里面我们必须加入PRESERVE8指令,使得寄存器8BYTE对齐.代码:CODE32PRESERVE8 ;这个在KEIL里面是必须的,要求8BYTE对齐.在ADS的启动代码中就没有.AREA vectors,CODE,READONLY2: ARM的处理器可工作于多种模式,下面设置个模式的一些参数.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 系统模式参数的由来:这里各个模式的参数是由寄存器CPSR的模式位设置M[4:0]得来的,比如这里的用户模式,CPSR的M[4:0]设置为10000就是0x10,同理其他.详见<<ARM嵌入式系统基础教程>>P47页,CPSR设置很关键!3:I_Bit EQU 0x80 ; when I bit is set, IRQ is disabledF_Bit EQU 0x40 ; when F bit is set, FIQ is disabled也和CPSR寄存器的设置有关,这里两位是禁止/开启快速中断和一般中断的设置.4: 各模式下定义的堆栈地址.UND_Stack_Size EQU 0x00000000SVC_Stack_Size EQU 0x00000100ABT_Stack_Size EQU 0x00000000FIQ_Stack_Size EQU 0x00000000IRQ_Stack_Size EQU 0x00000100USR_Stack_Size EQU 0x00000200设置堆栈大小Stack_Size EQU (UND_Stack_Size +SVC_Stack_Size + ABT_Stack_Size +FIQ_Stack_Size +IRQ_Stack_Size + USR_Stack_Size)AREA STACK, NOINIT, READWRITE, ALIGN=3Stack_Mem SPACE Stack_SizeStack_Top EQU Stack_Mem + Stack_Size堆栈大小的设置,各公司写的启动代码有所不同,但是不影响大局,可以借鉴一些你认为比较简单的启动代码,然后写自己的堆栈地址和大小设置程序.5:堆的设置Heap_Size EQU 0x00000000AREA HEAP, NOINIT, READWRITE, ALIGN=3Heap_Mem SPACE Heap_SizeAREA Init,CODE,READONLY,ALIGN=3 //指定后面的指令为8位对齐(2的3次方)align n它的含义就是使得下面的代码按一定规则对齐,.align n 指令的对齐值有两种方案,n 或 2^n ,各种平台最初的汇编器一般都不是gas,采取方案1或2的都很多,gas的目标是取代原来的汇编器,必然要保持和原来汇编器的兼容,因此在gas中如何解释 .align指令会显得有些混乱,原因在于保持兼容。
arm-linux是按照2^n的方案对齐的. ARM 的.align 5就是2的5次方(32位)对齐,也就是4字节(32位)对齐.6: AREA RESET, CODE, READONLYARM下面的是ARM的代码,不是THUMB.7: 中断向量表ResetLDR PC, ResetAddrLDR PC, UndefinedAddrLDR PC, SWI_AddrLDR PC, PrefetchAddrLDR PC, DataAbortAddrDCD 0xb9205f80LDR PC, [PC, #-0xff0]LDR PC, FIQ_AddrResetAddr DCD ResetInit UndefinedAddr DCD UndefinedSWI_Addr DCD SoftwareInterrupt PrefetchAddr DCD PrefetchAbort DataAbortAddr DCD DataAbortNouse DCD 0IRQ_Addr DCD 0FIQ_Addr DCD FIQ_Handler;未定义指令UndefinedB Undefined;软中断SoftwareInterruptB SoftwareInterrupt ;取指令中止PrefetchAbortB PrefetchAbort;取数据中止DataAbortB DataAbort;快速中断FIQ_HandlerSTMFD SP!, {R0-R3, LR} BL FIQ_ExceptionLDMFD SP!, {R0-R3, LR} SUBS PC, LR, #48: InitStackMOV R0, LR;Build the SVC stack;设置管理模式堆栈MSR CPSR_c, #0xd3LDR SP, StackSvc;Build the IRQ stack;设置中断模式堆栈MSR CPSR_c, #0xd2LDR SP, StackIrq;Build the FIQ stack;设置快速中断模式堆栈MSR CPSR_c, #0xd1LDR SP, StackFiq;Build the DATAABORT stack;设置中止模式堆栈MSR CPSR_c, #0xd7LDR SP, StackAbt;Build the UDF stack;设置未定义模式堆栈MSR CPSR_c, #0xdbLDR SP, StackUnd;Build the SYS stack;设置系统模式堆栈MSR CPSR_c, #0x5f ;#0xdf LDR SP, =StackUsrMOV PC, R09: BL InitStack ;初始化堆栈 Initialize the stackBL TargetResetIni;目标板基本初始化 ;跳转到c语言入口 Jump to the entry point of C programB __main周立功启动代码:;/****************************************Copyright (c)************************************************** ;** Guangzou ZLG-MCU Development Co.,LTD.;** graduate school;** http://www.zlgmcu.c om;**;**--------------FileInfo-------------------------------------------------------------------------------;** File name: Startup.s;** Last modified Date: 2004-09-17;** Last Version: 1.0;** Descriptions: The start up codes for LPC2100, including the initializing codes for the entry point of exceptions and the stacks of user tasks.;** Every project should have a independent copy of this file for related modifications;**------------------------------------------------------------------------------------------------------;** Created by: Chenmingji;** Created date: 2004-02-02;** Version: 1.0;** Descriptions: The original version//原著;**;**------------------------------------------------------------------------------------------------------;** Modified by: Chenmingji;** Modified date: 2004-09-17;** Version: 1.01;** Descriptions: Modified the bus setting to adapt for many common situations;** //改进了总线,可以根据这里的更改来控制总线的速率;**------------------------------------------------------------------------------------------------------;** Modified by: Chenmingji;** Modified date: 2004-09-17;** Version: 1.02;** Descriptions: Added codes to support the enciphering of the chip;** //增加了芯片加密;**------------------------------------------------------------------------------------------------------;** Modified by: Chenmingji;** Modified date: 2004-09-17;** Version: 1.04;** Descriptions: Renewed the template, added codes to support more compilers;** //重建模板,加入更多代码来支持更多的编译;**------------------------------------------------------------------------------------------------------;** Modified by:;** Modified date:;** Version:;** Descriptions:;**;****************************************************** **************************************************/;define the stack size;定义堆栈的大小SVC_STACK_LEGTH EQU 0FIQ_STACK_LEGTH EQU 0IRQ_STACK_LEGTH EQU 256ABT_STACK_LEGTH EQU 0UND_STACK_LEGTH EQU 0NoInt EQU 0x80;定义处理器模式,用户/管理/系统/中断USR32Mode EQU 0x10SVC32Mode EQU 0x13SYS32Mode EQU 0x1fIRQ32Mode EQU 0x12FIQ32Mode EQU 0x11PINSEL2 EQU 0xE002C014//定义PINSEL2地址,这个地址的值一般用户不需要改变,和芯片的加密有关//更改后有可能使得JTAG调试失效,进入芯片加密状态.BCFG0 EQU 0xFFE00000BCFG1 EQU 0xFFE00004BCFG2 EQU 0xFFE00008BCFG3 EQU 0xFFE0000C//定义存储器组配置寄存器BCFG_16DEF EQU 0x10000400 ;// 16Bit BusBCFG_CS3 EQU (BCFG_16DEF | (0x01<<00) | (0x07<<05) | (0x07<<11)) ;// 分别是IDCY/WST1/WST2对应读写速率等;//从第0位开始对其写入0001,;//从第5位开始写入0111;//从11位开始写入0111(0x07)/11111(0x1f)IMPORT __use_no_semihosting_swi;The imported labels;引入的外部标号在这声明IMPORT FIQ_Exception ;Fast interrupt exceptions handler 快速中断异常处理程序IMPORT __main ;The entry point to the main function C语言主程序入口IMPORT TargetResetInit ;initialize the target board 目标板基本初始化;The emported labels;给外部使用的标号在这声明EXPORT bottom_of_heapEXPORT StackUsrEXPORT ResetEXPORT __user_initial_stackheapCODE32AREA vectors,CODE,READONLYENTRY;interrupt vectors;中断向量表ResetLDR PC, ResetAddrLDR PC, UndefinedAddrLDR PC, SWI_AddrLDR PC, PrefetchAddrLDR PC, DataAbortAddrDCD 0xb9205f80LDR PC, [PC, #-0xff0]LDR PC, FIQ_AddrResetAddr DCD ResetInit UndefinedAddr DCD UndefinedSWI_Addr DCD SoftwareInterrupt PrefetchAddr DCD PrefetchAbort DataAbortAddr DCD DataAbortNouse DCD 0IRQ_Addr DCD 0FIQ_Addr DCD FIQ_Handler;未定义指令UndefinedB Undefined;软中断SoftwareInterruptB SoftwareInterrupt;取指令中止PrefetchAbortB PrefetchAbort;取数据中止DataAbortB DataAbort;快速中断FIQ_HandlerSTMFD SP!, {R0-R3, LR}BL FIQ_ExceptionLDMFD SP!, {R0-R3, LR}SUBS PC, LR, #4;/***************************************************** ****************************************************;** unction name 函数名称: InitStack;** Descriptions 功能描述: Initialize the stacks 初始化堆栈;** input parameters 输入: None 无;** Returned value 输出 : None 无;** Used global variables 全局变量: None 无;** Calling modules 调用模块: None 无;**;** Created by 作者: Chenmingji 陈明计;** Created Date 日期: 2004/02/02 2004年2月2日;**-------------------------------------------------------------------------------------------------------;** Modified by 修改:;** Modified date 日期:;**-------------------------------------------------------------------------------------------------------;****************************************************** **************************************************/ InitStackMOV R0, LR;Build the SVC stack;设置管理模式堆栈MSR CPSR_c, #0xd3LDR SP, StackSvc;Build the IRQ stack;设置中断模式堆栈MSR CPSR_c, #0xd2LDR SP, StackIrq;Build the FIQ stack;设置快速中断模式堆栈MSR CPSR_c, #0xd1LDR SP, StackFiq;Build the DATAABORT stack;设置中止模式堆栈MSR CPSR_c, #0xd7LDR SP, StackAbt;Build the UDF stack;设置未定义模式堆栈MSR CPSR_c, #0xdbLDR SP, StackUnd;Build the SYS stack;设置系统模式堆栈MSR CPSR_c, #0x5f ;#0xdf LDR SP, =StackUsrMOV PC, R0;/***************************************************** **************************************************** ;** unction name 函数名称: ResetInit;** Descriptions 功能描述: RESET 复位入口;** input parameters 输入: None 无;** Returned value 输出 : None 无;** Used global variables 全局变量: None 无;** Calling modules 调用模块: None 无;**;** Created by 作者: Chenmingji 陈明计;** Created Date 日期: 2004/02/02 2004年2月2日;**-------------------------------------------------------------------------------------------------------;** Modified by 修改: Chenmingji 陈明计;** Modified date 日期: 2004/02/02 2004年3月3日;**-------------------------------------------------------------------------------------------------------;****************************************************** **************************************************/ResetInit;初始化外部总线控制器,根据目标板决定配置;; LDR R0, =PINSEL2; IF :DEF: EN_CRP; LDR R1, =0x0f814910; ELSE; LDR R1, =0x0f814914; ENDIF; STR R1, [R0]LDR R0, =BCFG0LDR R1, =0x1000ffef ;0x00001046 STR R1, [R0]LDR R0, =BCFG1LDR R1,=BCFG_CS3 ;0x1000ffef ;0x1000ffe f;;STR R1, [R0]LDR R0, =BCFG2LDR R1, =0x2000ffefSTR R1, [R0]; LDR R0, =BCFG3; LDR R1, =0x00000CA0 ;0x2000ffef ; STR R1, [R0]BL InitStack ;初始化堆栈Initialize the stackBL TargetResetInit ;目标板基本初始化 Initialize the target board;跳转到c语言入口 Jump to the entry point of C programB __main;/***************************************************** ****************************************************;** unction name 函数名称: __user_initial_stackheap;** Descriptions 功能描述: Initial the function library stacks and heaps, can not deleted! 库函数初始化堆和栈,不能删除;** input parameters 输入: reference by function library 参考库函数手册;** Returned value 输出 : reference by function library 参考库函数手册;** Used global variables 全局变量: None 无;** Calling modules 调用模块: None 无;**;** Created by 作者: Chenmingji 陈明计;** Created Date 日期: 2004/02/02 2004年2月2日;**-------------------------------------------------------------------------------------------------------;** Modified by;** Modified date;**-------------------------------------------------------------------------------------------------------;****************************************************** **************************************************/__user_initial_stackheapLDR r0,=bottom_of_heap; LDR r1,=StackUsrMOV pc,lrStackSvc DCD SvcStackSpace +(SVC_STACK_LEGTH - 1)* 4StackIrq DCD IrqStackSpace +(IRQ_STACK_LEGTH - 1)* 4StackFiq DCD FiqStackSpace +(FIQ_STACK_LEGTH - 1)* 4StackAbt DCD AbtStackSpace +(ABT_STACK_LEGTH - 1)* 4StackUnd DCD UndtStackSpace +(UND_STACK_LEGTH - 1)* 4;/***************************************************** **************************************************** ;** unction name 函数名称: CrpData;** Descriptions 功能描述: encrypt the chip;** input parameters 输入: None 无;** Returned value 输出 : None 无;** Used global variables 全局变量: None 无;** Calling modules 调用模块: None 无;**;** Created by 作者: Chenmingji 陈明计;** Created Date 日期: 2004/03/27 2004年3月27日;**-------------------------------------------------------------------------------------------------------;** Modified by 修改:;** Modified date 日期:;**-------------------------------------------------------------------------------------------------------;****************************************************** **************************************************/IF :DEF: EN_CRPIF . >= 0x1fcINFO 1," The data at 0x000001fc must be0x87654321. Please delete some source before this line." ENDIFCrpDataWHILE . < 0x1fcNOPWENDCrpData1DCD 0x87654321 ;/*When the Data is 为0x87654321,user code be protected. 当此数为0x87654321时,用户程序被保护 */ENDIF;/* 分配堆栈空间 */AREA MyStacks, DATA, NOINIT, ALIGN=2 SvcStackSpace SPACE SVC_STACK_LEGTH * 4 ;Stack spaces for Administration Mode 管理模式堆栈空间IrqStackSpace SPACE IRQ_STACK_LEGTH * 4 ;Stack spaces for Interrupt ReQuest Mode 中断模式堆栈空间FiqStackSpace SPACE FIQ_STACK_LEGTH * 4 ;Stack spaces for Fast Interrupt reQuest Mode 快速中断模式堆栈空间AbtStackSpace SPACE ABT_STACK_LEGTH * 4 ;Stack spaces for Suspend Mode 中止义模式堆栈空间UndtStackSpace SPACE UND_STACK_LEGTH * 4 ;Stack spaces for Undefined Mode 未定义模式堆栈AREA Heap, DATA, NOINITbottom_of_heap SPACE 1AREA Stacks, DATA, NOINITStackUsrEND;/***************************************************** **************************************************** ;** End Of File;****************************************************** **************************************************/。