重映射

摘要:重映射是ARM嵌人式软件开发中一个非常重要的概念,它是

系统初始化过程中一个重要的环节。本文详细论述了什么是重映射,

为什么要进行重映射,以及怎样实现重映射,并以LPC2210处理器

为例给出了从片外Flash启动和重映射的实现方法。同时对在ARM

嵌入式软件开发过程中经常遇到一些基本概念,比如存储器映射、分

散加载文件等进行了详细的解释。实验证明在采用存储器重映射后可

以显著提高系统的运行效率,同时此方法还具有不增加代码量的优点。

关t词:启动代码;重映射;分散加载文件;ARM 

0 引言

引言引言

引言

多数嵌入式系统中,在进入主程序main之前,需要执行初始化序列

对应用程序的运行环境进行配置。启动代码一般用汇编语言来编写,

它主要对关键设备进行初始化和配置,为应用程序的运行创造条件。

在整个启动过程中,重映射是其中重要一环,正确地理解和实现重映

射有助于深入理解系统的工作原理。

本文使用的处理器为PhilipsLPC2210,由于它的片内只集成了一块

位于0x40000000~0x40004000,大小为16K的SRAM,因此扩展

了一块位于0x80000000~0x801FFFFF,大小为2M字节的Flash。

在实验中,程序将首先从外部Flash启动,然后将异常向量表从Flash

存储器复制到片内SRAM中,并进行存储器重映射将异常向量表映

射到片内SRAM。虽然本文的内容都是以LPC2210处理器为例来进

行说明的,但对其他ARM系列的处理器来说也是适用的。 

l 复位和初始化

复位和初始化复位和初始化

复位和初始化

ARM处理器在复位后处于SVC模式,中断是禁止的,并且处于ARM

状态。必须设置好各个异常模式堆栈的位置和大小,应用程序运行时

所在的处理器模式和状态,并为它分配合适的堆栈和空间,以及使能

中断和启用缓存(如果有的话)的时机。一般来说,总是需要按照一个

合理的顺序来初始化系统,图1从总体上描述了一个适用于ARM嵌

入式系统的可能的初始化序列。

 

 

可以看出,整个初始化序列可以分为2大的部分:用户代码和C库。

C库初始化代码是由集成开发环境(这里使用的是ADS1.2)自动生成

的,在完成任务之后,它最终将控制权转交给用户代码。 __scatterload的主要作用是复制代码和数据,它会根据应用程序的

设置(比如,可以通过分散加载文件精确地指定各部分代码或者数据

在加载时和运行时的位置)自动生成代码将程序装载到用户希望的地

址。

rt_entry部分的作用是执行运行时库的初始化工作。

需要编码的是用户代码部分:

首先设置各个模式的堆栈指针(由于LPC2210中没有MMU/MPU、

缓存和TCM,因此这里只需要设置各个模式的堆栈指针即可,程序

如list1所示);

//list 1:设置各种模式的堆栈指针值

Reset_Handler

 IMPORT stack_base  //stack_base的值在分散加载文件中设置

 LDR r0,=stackbase

 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,r0,  #offset_IRQ_Stack

//?设置其它模式的堆栈指针 其次,如果使用了分散加载描述文件(由于实际系统中存储器类型的

多样性),那么必须实现函数user_initial_stackheap();最后是启用中

断。

设置完各个模式的堆栈指针之后,要对关键的I/O设备进行初始化,

对处理器时钟、存储器加速模块,以及外部存储器模块进行设置。然

后跳转到C库的main,首先由C库代码按照分散加载文件的描述将

代码和数据从加载地址拷贝到运行地址并对未初始化数据进行清零,

然后跳转到rt_entry对C运行时库进行初始化,最后将控制权转交给

用户代码(即主程序main)。

 

2 存储器重映射

存储器重映射存储器重映射

存储器重映射

2.1存储器映射与分散加载文件

存储器映射与分散加载文件存储器映射与分散加载文件

存储器映射与分散加载文件

嵌入式系统中经常同时存在多种不同类型的存储介质,从访问速度比

较快的SRAM、DRAM到比较慢的Flash ROM、EEPROM等。

嵌入式系统通常对实时性的要求很高,因此希望合理地分配存储空间。

在ADS1.2中,是通过编写分散加载文件进行描述的。分散加载文件

描述了源文件编译后生成的目标文件在存储器中的位置,它同时指定

了目标文件的加载地址和执行地址。每个目标文件都有一个唯一的加

载地址和一个唯一的运行地址。如果一个目标文件的加载地址和执行

地址不同,那么C库的scatterload部分负责将它从加载地址处复制

到执行地址处。 2.2为什么引入重映射机制

为什么引入重映射机制为什么引入重映射机制

为什么引入重映射机制

重映射与处理器的异常处理机制密切相关。

当异常产生时,CPU会从预先设定好的内存地址中取出异常处理程

序的入口地址,并跳转到异常处理程序。不同型号的处理器的异常处

理机制一般也会不同,ARM系列处理器将所有异常处理程序的地址

都保存在一个连续的存储器空间中,位于这个存储器空间上的异常入

口的集合就称为“异常向量表”。由于普通的跳转指令B label的跳转

范围只有32M,为了实现4G范围内的任意跳转,可以采用指令LDR

PC,target_addr,它将target_addr的值看作是一个地址值装载到

PC中,于是跳转到那个地址处继续执行。

这样异常向量表通常包括32字节的相对PC的跳转指令和32字节的

异常处理程序地址。

为了在系统掉电后能够重新建立异常向量表,必须将其存储在非易失

性存储器中,但是非易失性存储器的访问速度非常慢,使得处理器只

能插入多个空闲周期来等待它,特别是在一些需要频繁调用异常处理

程序的场合,这种负面影响很容易成为系统的瓶颈,于是引入了重映

射机制来提高系统对异常的实时响应能力。

重映射一般是在系统初始化过程中完成的。由于处理器对片内RAM

的访问速度最快,因此片内RAM成为存放异常向量表的首选位置。

整个重映射的过程非常简单,首先将异常向量从非易失性存储器中拷

贝到片内RAM中,然后执行重映射命令,将位于片内RAM中的异常向量块映射到异常向量地址空间中。此后,系统若产生异常,处理

器将从已映射到异常向量地址空间的片内RAM中读取异常向量。

2.3 LPC2210处理器的重映射机制

处理器的重映射机制处理器的重映射机制

处理器的重映射机制

在LPC2210中,重映射是通过寄存器MEMMAP来控制的,其用法

如表1所示。

 

在LPC2000中,存储器重映射的部分包括异常向量区(32Byte)和额

外的32Byte,一共是64Byte,重新映射的代码位置与地址

0x0~0x0000003F重叠。也就是说,当处于用户RAM模式时,如果

访问0x0~0x3F的数据,实际上是在对0x40000000~0x4000003F进

行访问。同样如果切换到外部存储器模式,并且同样对0x0~0x3F进

行访问,就变成访问0x80000000~0x8000003F中的数据/指令了。

 2.4 存储器重映射的实现

存储器重映射的实现存储器重映射的实现

存储器重映射的实现

为了实现对系统启动过程的精确控制,最好把与异常向量和启动代码相关的程序分别放在vectors.s和init.s这2个文件中,这样可以使用

分散加载机制精确的控制代码在内存中的布局。为了在系统复位或掉

电重启后,程序能够正常运行,必须将异常向量表加载到非易失性存

储器Flash中,而且必须位于从0开始的地址处。由于LPC2210处

理器没有片内Flash存储器,必须正确的配置引脚13和16使系统

从外部存储器启动。启动代码如list2所示,系统启动后首先从标号

Instruct_2开始执行,然后修改MEMMAP寄存器的内容(其中

CM_ctl_reg等于MEMMAP寄存器的地址),于是异常向量表从片内

RAM重新映射,最后将异常向量表从片外Flash拷贝到片内Flash。

此后在发生异常后,处理器就自动从片内RAM取出异常处理程序的

地址,从而能够显著提高程序的性能。

//list2:部分启动代码

CM_ctl_reg EQU 0xE01FCO4O

RAM        EQU 0x2

Reset_Handler

 LDR pc,=Instruct_2

Instruct_2

 LDR rl,=CM_ctl_reg

 LDR r0,[r1]

 AND r0,r0,#RemapMask

 0RR r0,r0,#RAM  STR rO,[r1]

 MOV r9,#0x80000000

 MOV r10,#0x40000000

 LDMIA r9!,{r0-r7}

 STMIA r10!,{r0-r7}

 LDMIA r9!,{r0-r7}

 STMIA r10!,{r0-r7}

在上面的复制完成之后,异常向量表就会同时出现在地址0x0、

0x40000000以及0x80000000。注意执行区IRAM的基址不是

0x40000000,而是0x40000040,因为起始的64Byte是为异常向量表

预留的。整个过程如果图2所示。

 

总结:

(略) 备注:这篇文章其实讲的是异常向量表的重映射。。。

==================================================

==================================================

==

地址映射

把芯片里和芯片外的FLASH、RAM、BootBlock和外设进行统一编

址。一般来说,芯片厂商都把这些地址分好了,搞清楚在哪里,使用

就行了。外扩FLASH和RAM的时候,需要进行地址映射。使用ADS

编译器的时候,有一个scf文件,用来描述地址映射的。而比较新的

Keil MDK 采用的可视化的方法。

ARM7TDMI的地址映射位置:ARM7TDMI采用32位寻址,4G的地

址空间。一般而言。在0x0000000放FLASH、0x40000000放RAM、

0x80000000以上是外部存储器、0xE0000000向上是APB(低速外

设,如GPIO、UART等)、0xFFFFFFFF向下是APB(高速设备,

如USB,向量中断控制器)。一个比较怪异的地址是BootBlock的,

单独来说。

BootBlock:

ARM芯片厂商提供的芯片引导程序,判断用户代码是否有效、芯片

是否加密,芯片是否工作在ISP状态、芯片是否工作在IAP状态。

这段代码在芯片启动的时候用,生产芯片的时候,厂商已经固化进去了,用户不用管。比较难搞的事情是这段芯片的地址,这段代码一般

是放在FLASH中的,放在地址0x00000000似乎最合理,但是这个

地址,中断向量表已经用了,于是干脆放到FLASH的尾部了。另一

个问题出来了,不同的芯片,内部的FLASH不一样大,这段代码的

地址该怎么定哪?办法就是重映射。

BootBlock的重映射:

BootBlock的实际位置在片内FLASH的尾部,但是编地址的时候,

重新映射到地址0x80000000向下的地方。这样以来,编程的时候采

用的地址是固定在接近0x80000000地方的,而实际的位置是在

FLASH的尾部。地址重映射:通过芯片的存储器管理部件,把不同

的程序可见地址映射到同一个物理位置。还有一种更加实用的地址重

映射叫异常向量表重映射。

异常向量表重映射:

异常向量表在0x00000000的位置,BootBlock启动完之后,就到这

里开始程序的运行,分别对应ARM的7种异常状态进行处理。 

存储器映射:

为存储器分配地址的过程称为存储器映射,那么什么叫存储器重映射

呢?为了增加系统的灵活性,系统中有部分地址可以同时出现在不同

的地址上,这就叫做存储器重映射。重映射主要包括引导块

“Boot  Block”重映射和异常向量表的重映射。

1.引导块

引导块引导块

引导块“Boot  Block”及其重映射

及其重映射及其重映射

及其重映射        Boot  Block是芯片设计厂商在LPC2000系列ARM内部固化的

一段代码,用户无法对其进行修改或者删除。这段代码在复位时被首

先运行,主要用来判断运行哪个存储器上面的程序,检查用户代码是

否有效,判断芯片是否被加密,系统的在应用编程(IAP)以及在系

统编程功能(ISP)等。

       Boot Block存在于内部Flash,LPC2200系列大小为8kb,它

占用了用户的Flash空间,但也有其他的LPC系列不占用FLash空

间的,而部分没有内部Flash空间的ARM处理器仍然存在

Boot  Block。

       重映射的原因:

       Boot  Block中有些程序可被用户调用,如擦写片内Flash的IAP

代码。为了增加用户代码的可移植性,所以最好把Boot  Block的代

码固定的某个地址上。但由于各芯片的片内Flash大小不尽相同,如

果把Boot  Block的地址安排在内部Flash结束的位置上,那就无法

固定Boot  Block的地址。

       为了解决上面的问题,于是芯片厂家将Boot  Block的地址重映

射到片内存储器空间的最高端,即接近2Gb的地方,这样无论片内

存储器的大小如何,都不会影响Boot  Block的地址。因此当

Boot  Block中包含可被用户调用的IAP操作的代码时,不用修改IAP

的操作地址就可以在不同的LPC系列的ARM上运行了。 2.异常向量表及其重映射

      ARM内核在发生异常后,会使程序跳转到位于0x0000~0x001C

的异常向量表处,再经过向量跳转到异常服务程序。但ARM单条指

令的寻址范围有限,无法用一条指令实现4G范围的跳转,所以应在

其后面的0x0020~0x003F地址上放置跳转目标,这样就可以实现4G

范围内的任意跳转,因此一个异常向量表实际上占用了16个字的存

储单元。以下为一张中断向量表:

                                    LDR     PC, ResetAddr

                                    LDR     PC, UndefinedAddr  

                                    LDR     PC, SWI_Addr

                                    LDR     PC, PrefetchAddr

                                    LDR     PC, DataAbortAddr

                                    DCD     0xb9205f80

                                    LDR     PC, [PC, #-0xff0]

                                    LDR     PC, FIQ_Addr

                    ResetAddr            DCD     ResetInit

                    UndefinedAddr      DCD     Undefined                     SWI_Addr            DCD     SoftwareInterrupt

                    PrefetchAddr        DCD     PrefetchAbort

                    DataAbortAddr     DCD     DataAbort

                    Nouse                  DCD     0

                    IRQ_Addr             DCD     0

                    FIQ_Addr             DCD     FIQ_Handler

      重映射的原因:

      由于ARM处理器的存储器结构比较复杂,可能同时存在片内存

储器和片外存储器等,他们在存储器映射上的起始地址都不一样,因

此ARM内核要访问的中断向量表可能不在0x0000~0x003F地址上,

因此采用了存储器重映射来实现将存在与不同地方的中断向量表都

映射到0x0000~0x003F地址上。

      注意:Boot  Block 也存在中断向量表,而且复位后这段代码首

先映射到 0x0000~0x003F地址上,也就是说复位后首先运行的是

Boot Block程序。各个存储区域的中断向量表也不尽相同。

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值