分类: LINUX
2011-01-16 20:47:48
理解好存储器的编址、映射和重新映射等问题,对于嵌入式编程和操作系统的理解等都有重大的帮助。所有的把嵌入式系统都可以看成一个“输入输出”系统。信息输入,经过处理,然后输出。那么输入都可以看做读存储单元,这个“存储单元”范围很广,RAM、ROM、寄存器等。可以从SDRAM中读,也可以从FLASH中读,还可以从UART的寄存器中读,有个重要的思想是,把所有设备看成同一性质,即这个设备都有地址,都可以进行读写,这就是统一编程的思想。那么嵌入式编程就可以归结为“读写”问题。
具体说一下编址。编址也就是给“内存单元”编号,而这个“内存单元”是多大呢?一般是8bit,即一个Byte,如x86和ARM;但也有其它的,如AVR单片机,就是以每2Byte来编址的。地址空间的大小一般取决于地址总线,32位机的地址总线一般是32bit的,2^32=4294967296,也就是说可以用来表示4294967296个Byte,也即4GB的地址空间;如果以2Byte来编址的话,那么就可以表示8GB的地址空间。
下面结合LPC210x来具体解释一下。我以前有个错误的理解就是boot block是个逻辑上的概念,就是存放bootloader的地方,一般应该在FLASH的起始端。但对于LPC210x来说,不是这样的,它固化 在片内的8K大小的存储区域。PHILIPS在芯片出厂时固化了IAP、ISP和RealMonitor程序在FLASH中,地址为0x7d000~0x7ffff。通常称该空间为boot block。boot程序功能:判断用户代码是否有效,有效执行用户代码;否则运行ISP程序。 (认为出厂时Flash顶端被地址译码为0x7d000~0x7ffff)
存储器映射(Memory Map):ARM处理器产生的地址叫虚拟地址,把这个地址按照某种规则转换到另一个物理地址去的方法称为地址映射。就是把芯片中或芯片外的FLASH,RAM,外设,BOOTBLOCK等进行统一编址。即用地址来表示对象。这个地址绝大多数是由厂家规定好的,用户只能用而不能改。用户只能在挂外部RAM或FLASH的情况下可进行自定义。“映射”这个概念体现了“一一对应”,可以说虚拟地址0x00000000~0x0001ffff到片内FLASH的映射,也可以说片内FLASH被映射到虚拟地址0x00000000~0x0001ffff。下图是LPC210x的存储器映射。
存储器重新映射(Memory Re-Map):存储器重新映射是将复位后用户可见的存储器中部分区域,再次映射到其他的地址上。对于LPC210x微控制器,存储器重新映射区域一共为64个字节,分别为异常向量区(32字节)和紧随其后的32字节。通俗的讲,就是虚拟地址0x00000000~0x0000003f本来是指向片内FLASH的,重新映射以后,当访问这段地址时,实际访问的就是boot block或者RAM。也就是把boot block或RAM的一部分映射到虚拟地址0x00000000~0x0000003f(异常向量和其后的32字节)。LPC210x存储器重新映射见下图。
那么为什么要重新映射呢?这得从ARM的7种异常说起,它们会使得ARM进入不同的工作模式,并执行不同特定地址的指令。如下图。
可以看出,每个异常向量的大小都是4字节,这是因为ARM处理器的ARM指令大小也是4字节,7个异常向量加上一个保留的,共8*4=32个字节,再加上其后的32个字节,就构成了我们要重新映射的区域。要特别注意的是,这里的“异常向量”不同与一般的“中断向量”,一般的中断向量,如UART、Timer中断等是划归到IRQ中断里面处理的,也就是系统进入到IRQ中断服务程序中以后,再跳转到具体的中断服务。这样看来,重新映射都是为了灵活的放置异常向量的物理位置。
对于第二个图。我们姑且把虚拟地址0x00000000-0x0000003c都称为异常向量表。
MEMMAP=0:开机默认值,Boot装载模式----异常向量表(0x00000000-0x0000003c)映射的是BootBlock中的0x7FFFE000-0x7FFFF03c中的值;芯片复位时,启动boot装载程序,boot装载程序检查P0.14口的状态和用户的异常向量,判断是进入ISP状态还是启动用户程序,若启动用户程序,则自动设置MEMMAP=1(片内flash启动)或3(片外程序存储器启动)。
MEMMAP=1:异常向量表就在片内flash中,地址就是0x00000000-0x0000003c,相当于没有映射;
MEMMAP=2:最为主要的设置,即是重映射的关键之所在,当设置MEMMAP=2 时,异常向量表(0x00000000-0x0000003c)映射的是片内SRAM中的0x40000000-0x4000003c中的值,而因为是SRAM,所以在程序运行的过程中是可以改变的,这样就可以达到重映射的目的啦(异常向量表可以随时修改)。
MEMMAP=3:异常向量表就在片外flash中,异常向量表(0x00000000-0x0000003c)映射到是片外flash中的0x80000000-0x8000003c中的值;功能上与MEMMAP=1时的差不多,因为一旦程序固化到flash中,即为只读,只是数值映射而已!
(首先分两种情况:1 用户程序代码已经固化到flash,执行用户代码时,memmap=1或3。当复位时为0,执行的是bootblock代码,复位完成后即为1或3,片内或外flash启动,执行用户代码)
2 当用户代码在ram区中时,memmap=2,一般为debug版本,开发过程中使用