arm remap
LPC2000系列ARM处理器重映射原理的分析与实现(转)??摘要: There are some very imp Keywords boot co 多数嵌入式系统中,在进入主程序main之前,需要执行初始化序列对应用程序的运行环境进行配置。启动代码一般用汇编语言来编写,它主要对关键的设备进行初始化和配置,为应用程序的运行创造条件。在整个启动过程中,重映射是其中重要一环,正确的理解和实现重映射对于理解系统的工作原理极为重要。 本文的实验平台是EasyARM2210开发板,处理器为Philips LPC2210,它的片内只集成了一块位于0x40000000~0x40004000,大小为16K的SRAM,同时还扩展了一块位于0x80000000~0x801FFFFF,大小为8M字节的Flash。虽然本文的内容都是以LPC2100处理器为例来进行说明的,但对其它ARM系列的处理器来说也是适用的。 1 ???? 整个初始化序列可以分为两个大的部分,用户代码和C库。C库初始化代码是由集成开发环境(这里使用的是ADS1.2)自动生成的,在完成任务之后,它最终将控制权转交给用户代码。__scatterload部分的作用相当于通常所说的bootloader,它会根据应用程序的设置(比如,我们可以通过分散加载文件精确的指定代码和数据在加载时和运行时的位置)自动生成代码将程序装载到用户希望的地址。__rt_entry部分的作用是执行运行时库的初始化工作。我们需要编码的是用户代码部分:首先设置各个模式的堆栈指针(由于LPC2210中没有MMU/MPU、缓存和TCM,因此这里只需要设置各个模式的堆栈指针即可,程序如list 1所示);其次,如果你使用了分散加载描述文件(由于实际系统中存储器类型的多样性,这几乎总是事实),那么必须实现函数__user_initial_stackheap( );最后是启用中断。 //list 1: 设置各种模式的堆栈指针值 Reset_Handler ??????????????IMP ??????????????LDR?? r0,=stack_base ?????????????? ??????????????MSR?? CPSR_c,#Mode_FIQ|I_Bit|F_Bit ??????????????SUB?? sp,r0,#offset_FIQ_Stack ??????????????MSR?? CPSR_c,#Mode_IRQ|I_Bit|F_Bit ??????????????SUB?? sp,#offset_IRQ_Stack ??????????????//…设置其它模式的堆栈指针 设置完各个模式的堆栈指针之后,要对关键的I/O设备进行初始化,对处理器时钟、存储器加速模块以及外部存储器模块进行设置。然后跳转到C库的__main,首先由C库代码按照分散加载文件的描述将代码和数据从加载地址拷贝到运行地址并对未初始化数据进行清零,然后跳转到__rt_entry对C运行时库进行初始化,最后将控制权转交给用户代码(即主程序main)。 2 ?????? 分散加载文件能够准确的将某个源文件编译后生成的目标文件加载到一个确定的内存位置,它同时指定了目标文件的加载地址和执行地址。每个目标文件都有一个唯一的加载地址和一个唯一的运行地址。如果一个目标文件的加载地址和执行地址不同,那么C库的__scatterload部分负责将它复制到执行地址处。 2.2 LPC2210处理器的重映射机制 所有的ARM系统都有一个异常向量表,它是跳转到各种异常处理程序的跳转指令列表。由于普通的跳转指令B label的跳转范围只有32M,为了实现4G范围内的任意跳转,可以采用指令LDR PC,target_addr,它将target_addr的值看作是一个地址值装载到PC中,于是跳转到那个地址处继续执行。这样向量表通常包括32字节的相对PC的跳转指令和32字节的异常处理程序地址。 通常系统对异常向量表的访问最为频繁,为了尽可能快的响应各种异常,必须考虑将异常向量表装载到何种类型的存储器中。片内RAM的访问速度最快,而且可以运行时对向量表进行修改,它无疑是向量表的理想选择。但是考虑到RAM不属于非易失性存储器,在掉电后不能保存它的内容,因此只能在系统启动后,将向量表复制到片内RAM中,并利用存储器重映射机制使向量表从片内RAM重新映射。在LPC2210中,重映射是通过寄存器MEMMAP来控制的,其用法如图2所示: MEMMAP 描述 1:0 MAP1:0 00:Boot装载程序模式。异常向量从bootblock重新映射。 01:保留。该选项不使用。 10:用户RAM模式。异常向量从片内RAM重新映射。 11:用户外部存储器模式。异常向量从外部存储器重新映射。 7:2 保留 保留,不要向其写入1。 图2: MEMAP寄存器 2.3 存储器重映射的实现 2.3.1 将复位处理程序放在片外Flash存储器最低地址处,将异常向量表放在片内RAM的最低地址处,使用的分散加载文件如list 2所示。在系统复位后,外部存储器底部64个字节重新映射到地址0x0,并从中取出第一条指令 LDR??pc,=Instruct_2 于是控制流跳转到真实的ROM中继续执行。紧接着访问存储器控制寄存器使MEMMAP[1:0]=10,这样片内RAM中的异常向量表就映射到地址0x0。整个过程如图3所示。 //list 2:分散加载文件――异常向量从片内RAM重新映射 ROM_LOAD 0x80000000 { ????ROM_EXEC 0x80000000 ????{?? ????????init.o(Init,+First) ????????* (+RO) ????} ????IRAM 0x40000000 ????{ ????????vectors.o (Vect,+First) ????????* (+RW,+ZI) ????} ????//... } 2.3.2 上面的方法虽然能够正确的实现从RAM中重新映射异常向量,但是由于在系统复位或掉电重启后,RAM中的内容会丢失,导致程序不能运行,于是为了使程序能够正常运行,必须将异常向量表加载到非易失性存储器如Flash中。由于LPC2210处理器没有片内Flash存储器,必须正确的配置引脚13和16使系统从外部存储器启动。启动代码如list 3所示,系统启动后首先从标号Instruct_2开始执行,然后修改MEMMAP寄存器的内容(其中CM_ctl_reg等于MEMMAP寄存器的地址),于是异常向量表从片内RAM重新映射,最后将异常向量表从片外Flash拷贝到片内Flash。此后在发生异常后,处理器就自动从片内RAM取出异常处理程序的地址,从而能够显著提高程序的性能。 //list 3:部分启动代码 CM_ctl_reg??????EQU???? 0xE01FC040 RAM???????????? EQU???? 0x2 Reset_Handler ????LDR???? pc,???? =Instruct_2???????? Instruct_2 ????LDR???? r1,?? =CM_ctl_reg ????LDR???? r0,?? [r1] ????AND???? r0,?? r0,#RemapMask ????ORR???? r0,#RAM ????STR???? r0,?? [r1] ????MOV???? r9??,#0x80000000 ????MOV???? r10,#0x40000000 ????LDMIA?? r9!,{r0-r7} ????STMIA?? r10!,{r0-r7} ????LDMIA?? r9!,{r0-r7} 在上面的复制完成之后,异常向量表就会同时出现在地址0x0、0x40000000以及0x80000000。描述映像布局的分散加载文件如列表list 4所示。注意执行区IRAM的基址不是0x40000000,而是0x40000040,因为起始的64字节是为异常向量表预留的。整个过程如果图4所示。 //list 4:分散加载文件―将异常向量 //从ROM拷贝到RAM中,并从片内RAM重新映射 ROM_LOAD 0x80000000 { ????ROM_EXEC 0x80000000 ????{?? ????????vectors.o (Vect,+First)?? ????????* (+RO) ????} ????IRAM 0x40000040 ????{ ????????* (+RW,+ZI) ????} ????HEAP +0 UNINIT ????{ ????????heap.o(+ZI) ????} ????STACKS 0x40004000 UNINIT ????{ LPC2000系列ARM处理器重映射原理的分析与实现(转)??2010-09-09 15:37:47|??分类: 嵌入式 |??标签:嵌入式?? |字号大中小?订阅 摘要: There are some very imp Keywords boot co 多数嵌入式系统中,在进入主程序main之前,需要执行初始化序列对应用程序的运行环境进行配置。启动代码一般用汇编语言来编写,它主要对关键的设备进行初始化和配置,为应用程序的运行创造条件。在整个启动过程中,重映射是其中重要一环,正确的理解和实现重映射对于理解系统的工作原理极为重要。 本文的实验平台是EasyARM2210开发板,处理器为Philips LPC2210,它的片内只集成了一块位于0x40000000~0x40004000,大小为16K的SRAM,同时还扩展了一块位于0x80000000~0x801FFFFF,大小为8M字节的Flash。虽然本文的内容都是以LPC2100处理器为例来进行说明的,但对其它ARM系列的处理器来说也是适用的。 1 ???? 整个初始化序列可以分为两个大的部分,用户代码和C库。C库初始化代码是由集成开发环境(这里使用的是ADS1.2)自动生成的,在完成任务之后,它最终将控制权转交给用户代码。__scatterload部分的作用相当于通常所说的bootloader,它会根据应用程序的设置(比如,我们可以通过分散加载文件精确的指定代码和数据在加载时和运行时的位置)自动生成代码将程序装载到用户希望的地址。__rt_entry部分的作用是执行运行时库的初始化工作。我们需要编码的是用户代码部分:首先设置各个模式的堆栈指针(由于LPC2210中没有MMU/MPU、缓存和TCM,因此这里只需要设置各个模式的堆栈指针即可,程序如list 1所示);其次,如果你使用了分散加载描述文件(由于实际系统中存储器类型的多样性,这几乎总是事实),那么必须实现函数__user_initial_stackheap( );最后是启用中断。 //list 1: 设置各种模式的堆栈指针值 Reset_Handler ??????????????IMP ??????????????LDR?? r0,=stack_base ?????????????? ??????????????MSR?? CPSR_c,#Mode_FIQ|I_Bit|F_Bit ??????????????SUB?? sp,#offset_FIQ_Stack ??????????????MSR?? CPSR_c,#Mode_IRQ|I_Bit|F_Bit ??????????????SUB?? sp,#offset_IRQ_Stack ??????????????//…设置其它模式的堆栈指针 设置完各个模式的堆栈指针之后,要对关键的I/O设备进行初始化,对处理器时钟、存储器加速模块以及外部存储器模块进行设置。然后跳转到C库的__main,首先由C库代码按照分散加载文件的描述将代码和数据从加载地址拷贝到运行地址并对未初始化数据进行清零,然后跳转到__rt_entry对C运行时库进行初始化,最后将控制权转交给用户代码(即主程序main)。 2 ?????? 分散加载文件能够准确的将某个源文件编译后生成的目标文件加载到一个确定的内存位置,它同时指定了目标文件的加载地址和执行地址。每个目标文件都有一个唯一的加载地址和一个唯一的运行地址。如果一个目标文件的加载地址和执行地址不同,那么C库的__scatterload部分负责将它复制到执行地址处。 2.2 LPC2210处理器的重映射机制 所有的ARM系统都有一个异常向量表,它是跳转到各种异常处理程序的跳转指令列表。由于普通的跳转指令B label的跳转范围只有32M,为了实现4G范围内的任意跳转,可以采用指令LDR PC,target_addr,它将target_addr的值看作是一个地址值装载到PC中,于是跳转到那个地址处继续执行。这样向量表通常包括32字节的相对PC的跳转指令和32字节的异常处理程序地址。 通常系统对异常向量表的访问最为频繁,为了尽可能快的响应各种异常,必须考虑将异常向量表装载到何种类型的存储器中。片内RAM的访问速度最快,而且可以运行时对向量表进行修改,它无疑是向量表的理想选择。但是考虑到RAM不属于非易失性存储器,在掉电后不能保存它的内容,因此只能在系统启动后,将向量表复制到片内RAM中,并利用存储器重映射机制使向量表从片内RAM重新映射。在LPC2210中,重映射是通过寄存器MEMMAP来控制的,其用法如图2所示: MEMMAP 描述 1:0 MAP1:0 00:Boot装载程序模式。异常向量从bootblock重新映射。 01:保留。该选项不使用。 10:用户RAM模式。异常向量从片内RAM重新映射。 11:用户外部存储器模式。异常向量从外部存储器重新映射。 7:2 保留 保留,不要向其写入1。 图2: MEMAP寄存器 2.3 存储器重映射的实现 2.3.1 将复位处理程序放在片外Flash存储器最低地址处,将异常向量表放在片内RAM的最低地址处,使用的分散加载文件如list 2所示。在系统复位后,外部存储器底部64个字节重新映射到地址0x0,并从中取出第一条指令 LDR??pc,=Instruct_2 于是控制流跳转到真实的ROM中继续执行。紧接着访问存储器控制寄存器使MEMMAP[1:0]=10,这样片内RAM中的异常向量表就映射到地址0x0。整个过程如图3所示。 //list 2:分散加载文件――异常向量从片内RAM重新映射 ROM_LOAD 0x80000000 { ????ROM_EXEC 0x80000000 ????{?? ????????init.o(Init,+First) ????????* (+RO) ????} ????IRAM 0x40000000 ????{ ????????vectors.o (Vect,+First) ????????* (+RW,+ZI) ????} ????//... } 2.3.2 上面的方法虽然能够正确的实现从RAM中重新映射异常向量,但是由于在系统复位或掉电重启后,RAM中的内容会丢失,导致程序不能运行,于是为了使程序能够正常运行,必须将异常向量表加载到非易失性存储器如Flash中。由于LPC2210处理器没有片内Flash存储器,必须正确的配置引脚13和16使系统从外部存储器启动。启动代码如list 3所示,系统启动后首先从标号Instruct_2开始执行,然后修改MEMMAP寄存器的内容(其中CM_ctl_reg等于MEMMAP寄存器的地址),于是异常向量表从片内RAM重新映射,最后将异常向量表从片外Flash拷贝到片内Flash。此后在发生异常后,处理器就自动从片内RAM取出异常处理程序的地址,从而能够显著提高程序的性能。 //list 3:部分启动代码 CM_ctl_reg??????EQU???? 0xE01FC040 RAM???????????? EQU???? 0x2 Reset_Handler ????LDR???? pc,???? =Instruct_2???????? Instruct_2 ????LDR???? r1,?? =CM_ctl_reg ????LDR???? r0,?? [r1] ????AND???? r0,#RemapMask ????ORR???? r0,#RAM ????STR???? r0,?? [r1] ????MOV???? r9??,#0x80000000 ????MOV???? r10,#0x40000000 ????LDMIA?? r9!,{r0-r7} ????STMIA?? r10!,{r0-r7} ????LDMIA?? r9!,{r0-r7} 在上面的复制完成之后,异常向量表就会同时出现在地址0x0、0x40000000以及0x80000000。描述映像布局的分散加载文件如列表list 4所示。注意执行区IRAM的基址不是0x40000000,而是0x40000040,因为起始的64字节是为异常向量表预留的。整个过程如果图4所示。 //list 4:分散加载文件―将异常向量 //从ROM拷贝到RAM中,并从片内RAM重新映射 ROM_LOAD 0x80000000 { ????ROM_EXEC 0x80000000 ????{?? ????????vectors.o (Vect,+First)?? ????????* (+RO) ????} ????IRAM 0x40000040 ????{ ????????* (+RW,+ZI) ????} ????HEAP +0 UNINIT ????{ ????????heap.o(+ZI) ????} ????STACKS 0x40004000 UNINIT ????{ ????????stack.o(+ZI) ????} } 3 结论 参考文献 2.?????? LPC2210 User Manual-Preliminary Release,Philips Semiconductors. 3.?????? 杜春雷. ARM体系结构与编程. 清华大学出版社,2003. ????????stack.o(+ZI) ????} } 3 结论 参考文献 2.?????? LPC2210 User Manual-Preliminary Release,Philips Semiconductors. 3.?????? 杜春雷. ARM体系结构与编程. 清华大学出版社,2003. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |