<?xml version="1.0" encoding="gbk"?> <rss version="2.0"><channel> <title>定阅帖子更新</title> <link>http://www.broadkey.com.cn/XML.ASP</link><description>TEAM Board - 意得法电子</description> <copyright>TEAM 2.0.5 Release</copyright><generator>TEAM Board by TEAM5.Cn Studio</generator> <ttl>30</ttl><item><link>http://www.broadkey.com.cn/Thread.asp?tid=152 </link><title>ARM的存储器映射与存储器重映射[转]</title><author>macro</author><pubDate>2009-11-30 16:50:58</pubDate><description><![CDATA[<p>&nbsp;存储器映射是指把芯片中或芯片外的FLASH，RAM，外设，BOOTBLOCK等进行统一编址。即用地址来表示对象。这个地址绝大多数是由厂家规定好的，用户只能用而不能改。用户只能在挂外部RAM或FLASH的情况下可进行自定义。</p>
<p>&nbsp;&nbsp;&nbsp; ARM7TDMI的存储器映射可以有0X00000000~0XFFFFFFFF的空间，即4G的映射空间，但所有器件加起来肯定是填不满的。一般来说， 0X00000000依次开始存放FLASH&mdash;&mdash;0X00000000，SRAM&mdash;&mdash;0X40000000，BOOTBLOCK，外部存储器 0X80000000，VPB（低速外设地址，如GPIO，UART）&mdash;&mdash;0XE0000000，AHB（高速外设：向量中断控制器，外部存储器控制器） &mdash;&mdash;从0XFFFFFFFF回头。他们都是从固定位置开始编址的，而占用空间又不大，如AHB只占2MB，所以从中间有很大部分是空白区域，用户若使用这些空白区域，或者定义野指针，就可能出现取指令中止或者取数据中止。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 由于系统在上电复位时要从0X00000000 开始运行，而第一要运行的就是厂家固化在片子里的BOOTBLOCK，这是判断运行哪个存储器上的程序，检查用户代码是否有效，判断芯片是否加密，芯片是否IAP（在应用编程），芯片是否ISP（在系统编程），所以这个BOOTBLOCK要首先执行。而芯片中的BOOTBLOCK不能放在FLASH的头部，因为那要存放用户的异常向量表的，以便在运行、中断时跳到这来找入口，所以BOOTBLOCK只能放在FLSAH尾部才能好找到，呵呵。而ARM7的各芯片的FLASH大小又不一致，厂家为了BOOTBLOCK在芯片中的位置固定，就在编址的2G靠前编址的位置虚拟划分一个区域作为BOOTBLOCK 区域，这就是重映射，这样访问&lt;2G即&lt;0X80000000的位置时，就可以访问到在FLASH尾部的BOOTBLOCK区了。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BOOTBLOCK运行完就是要运行用户自己写的启动代码了，而启动代码中最重要的就是异常向量表，这个表是放在FLASH的头部首先执行的，而异常向量表中要处理多方面的事情，包括复位、未定义指令、软中断、预取指中止、数据中止、IRQ（中断) ,FIQ (快速中断），而这个异常向量表是总表，还包括许多分散的异常向量表，比如在外部存储器，BOOTBLOCK，SRAM中固化的，不可能都由用户直接定义，所以还是需要重映射把那些异常向量表的地址映到总表中。</p>
<p>--------------------------------------------------------------------------------------------------------</p>
<p>为存储器分配地址的过程称为存储器映射，那么什么叫存储器重映射呢？为了增加系统的灵活性，系统中有部分地址可以同时出现在不同的地址上，这就叫做存储器重映射。重映射主要包括引导块&ldquo;Boot&nbsp; Block&rdquo;重映射和异常向量表的重映射。</p>
<p>&nbsp;1.引导块&ldquo;Boot&nbsp; Block&rdquo;及其重映射</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Boot&nbsp; Block是芯片设计厂商在LPC2000系列ARM内部固化的一段代码，用户无法对其进行修改或者删除。这段代码在复位时被首先运行，主要用来判断运行哪个存储器上面的程序，检查用户代码是否有效，判断芯片是否被加密，系统的在应用编程（IAP）以及在系统编程功能（ISP）等。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Boot Block存在于内部Flash，LPC2200系列大小为8kb，它占用了用户的Flash空间，但也有其他的LPC系列不占用FLash空间的，而部分没有内部Flash空间的ARM处理器仍然存在Boot&nbsp; Block。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 重映射的原因：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Boot&nbsp; Block中有些程序可被用户调用，如擦写片内Flash的IAP代码。为了增加用户代码的可移植性，所以最好把Boot&nbsp; Block的代码固定的某个地址上。但由于各芯片的片内Flash大小不尽相同，如果把Boot&nbsp; Block的地址安排在内部Flash结束的位置上，那就无法固定Boot&nbsp; Block的地址。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 为了解决上面的问题，于是芯片厂家将Boot&nbsp; Block的地址重映射到片内存储器空间的最高端，即接近2Gb的地方，这样无论片内存储器的大小如何，都不会影响Boot&nbsp; Block的地址。因此当Boot&nbsp; Block中包含可被用户调用的IAP操作的代码时，不用修改IAP的操作地址就可以在不同的LPC系列的ARM上运行了。</p>
<p>2.异常向量表及其重映射</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ARM内核在发生异常后，会使程序跳转到位于0x0000~0x001C的异常向量表处，再经过向量跳转到异常服务程序。但ARM单条指令的寻址范围有限，无法用一条指令实现4G范围的跳转，所以应在其后面的0x0020~0x003F地址上放置跳转目标，这样就可以实现4G范围内的任意跳转，因此一个异常向量表实际上占用了16个字的存储单元。以下为一张中断向量表：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LDR&nbsp;&nbsp;&nbsp;&nbsp; PC, ResetAddr<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LDR&nbsp;&nbsp;&nbsp;&nbsp; PC, UndefinedAddr&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LDR&nbsp;&nbsp;&nbsp;&nbsp; PC, SWI_Addr<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LDR&nbsp;&nbsp;&nbsp;&nbsp; PC, PrefetchAddr<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LDR&nbsp;&nbsp;&nbsp;&nbsp; PC, DataAbortAddr<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DCD&nbsp;&nbsp;&nbsp;&nbsp; 0xb9205f80<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LDR&nbsp;&nbsp;&nbsp;&nbsp; PC, [PC, #-0xff0]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LDR&nbsp;&nbsp;&nbsp;&nbsp; PC, FIQ_Addr</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ResetAddr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DCD&nbsp;&nbsp;&nbsp;&nbsp; ResetInit<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UndefinedAddr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DCD&nbsp;&nbsp;&nbsp;&nbsp; Undefined<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SWI_Addr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DCD&nbsp;&nbsp;&nbsp;&nbsp; SoftwareInterrupt<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PrefetchAddr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DCD&nbsp;&nbsp;&nbsp;&nbsp; PrefetchAbort<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DataAbortAddr&nbsp;&nbsp;&nbsp;&nbsp; DCD&nbsp;&nbsp;&nbsp;&nbsp; DataAbort<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Nouse&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DCD&nbsp;&nbsp;&nbsp;&nbsp; 0<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IRQ_Addr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DCD&nbsp;&nbsp;&nbsp;&nbsp; 0<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FIQ_Addr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DCD&nbsp;&nbsp;&nbsp;&nbsp; FIQ_Handler</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 重映射的原因：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 由于ARM处理器的存储器结构比较复杂，可能同时存在片内存储器和片外存储器等，他们在存储器映射上的起始地址都不一样，因此ARM内核要访问的中断向量表可能不在0x0000~0x003F地址上，因此采用了存储器重映射来实现将存在与不同地方的中断向量表都映射到0x0000~0x003F地址上。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注意：Boot&nbsp; Block 也存在中断向量表，而且复位后这段代码首先映射到 0x0000~0x003F地址上，也就是说复位后首先运行的是Boot Block程序。各个存储区域的中断向量表也不尽相同。</p>
<p><font color="#eeee11" size="3" face="仿宋_GB2312">&nbsp;Q:为什么在中断向量表中不直接LDR PC,&quot;异常地址&quot;.而是使用一个标号,然有再在后面使用DCD定义这个标号<br />
A:因为LDR指令只能跳到当前PC 4kB范围内,而B指令能跳转到32MB范围,而现在这样在LDR PC, &quot;xxxx&quot;这条指令不远处用&quot;xxxx&quot;DCD定义一个字,而这个字里面存放最终异常服务程序的地址,这样可以实现4GB全范围跳转.<br />
Q: LDR 不是可以全空间跳转的吗 《ARM微控制器基础与实战》程序清单5.3.<br />
A: LDR伪指令通过设置指令缓冲池才能实现全范围跳转,而LDR指令则只能实现4KB范围跳转.</font></p>
<p><font color="#09c7f7">&nbsp;内存地址和内存地址的值<br />
00000000<img src="http://bbs.weeqoo.com/editor/images/smilies/default/35.gif" alt="" />0000000<br />
表示在00000000这个地址放的是80000000这个值<br />
你LDR pc, 00000000<br />
是把80000000的值放到pc中<br />
ResetAddr相当于00000000<br />
ResetInit相当于80000000<br />
</font></p>]]></description></item></channel></rss>