1、存储系统功能概览
Cortext-M3储存器有如下特点:
存储器映射是预定义的,并且还规定好了哪个位置使用哪条总线。
存储器系统支持所谓的“位带”(bit-band)操作。通过它,实现了对单一比特的原子操作,位带操作仅适用于一些特殊的存储器区域中。
存储器系统支持非对齐访问和互斥访问。
存储器系统小端配置和大端配置均支持。
2、存储器映射
M3内核只有一个单一固定的存储器映射,地址空间大小是4GB,M3内核允许芯片制造商灵活地分配存储器空间。存储空间的一些位置用于调试组件等私有外设,这个地址段被称为“私有外设区”。私有外设区的组件包括:闪存地址重载及断点单元(FPB)、数据观察点单元(DWT) 、 仪器化跟踪宏单元(ITM) 、嵌入式跟踪宏单元(ETM) 、跟踪端口接口单元(TPIU) 、ROM表。
程序可以在代码区,内部SRAM区以及外部RAM区中执行。但是因为指令总线与数据总线是分开的,最理想的是把程序放到代码区,从而使取指和数据访问各自使用自己的总线。
内部SRAM区的大小是512MB,用于让芯片制造商连接片上的SRAM,这个区通过系统总线来访问。在这个区的下部,有一个1MB的区间,被称为“位带区”。该位带区还有一个对应的32 MB的“位带别名(alias)区”,容纳了8M个“位变量”。位带区对应的是最低的1MB地址范围,而位带别名区里面的每个字对应位带区的一个比特。位带操作只适用于数据访问,不适用于取指。通过位带的功能,可以把多个布尔型数据打包在单一的字中,却依然可以从位带别名区中,像访问普通内存一样地使用它们。位带别名区中的访问操作是原子的。
地址空间的另一个512MB范围由片上外设寄存器使用。这个区中也有一条32MB的位带别名,以便于快捷地访问外设寄存器,用法与内部SRAM区中的位带相同。例如,可以方便地访问各种控制位和状态位。要注意的是,外设区内不允许执行指令。 还有两个1GB的范围,分别用于连接外部RAM和外部设备,它们之中没有位带。两者的区别在于外部RAM区允许执行指令,而外部设备区则不允许。
最后还剩下0.5GB的空间,包括了系统级组件,内部私有外设总线,外部私有外设总线,以及由芯片厂家定义的系统外设。私有外设总线有两条: AHB私有外设总线,只用于CM3内部的AHB外设,它们是:NVIC, FPB, DWT和ITM。 APB私有外设总线,既用于CM3内部的APB设备,也用于外部设备(这里的“外部”是对内核而言)。CM3允许器件制造商再添加一些片上APB外设到APB私有总线上,它们通过APB接口来访问。 NVIC所处的区域叫做“系统控制空间(SCS)”,在SCS里的除了NVIC外,还有SysTick、MPU以及代码调试控制所用的寄存器。
最后,未用的提供商指定区也通过系统总线来访问,但是不允许在其中执行指令。M3内核中的MPU是选配的,由芯片制造商决定是否配上。
3、存储器的各种访问属性
M3在定义了存储器映射之外,还为存储器的访问规定了4种属性,分别是:可否缓冲(Bufferable)、可否缓存(Cacheable)、可否执行(Executable)、可否共享(Sharable)
如果配了MPU,则可以通过它配置不同的存储区,并且覆盖缺省的访问属性。CM3片内没有配备缓存,也没有缓存控制器,但是允许在外部添加缓存。通常,如果提供了外部内存,芯片制造商还要附加一个内存控制器,它可以根据可否缓存的设置,来管理对片内和片外RAM的访问操作。
地址空间可以通过另一种方式分为8个512MB等份:
1、代码区(0x0000_0000-0x1FFF_FFFF)
该区是可以执行指令的,缓存属性为WT(“写通”,Write Through),即不可以缓存。此区亦允许布设数据存储器。在此区上的数据操作是通过数据总线接口的(估计读数据使用D-Code,写数据使用System),且在此区上的写操作是缓冲的。
2、SRAM区(0x2000_0000–0x3FFF_FFFF)
此区用于片内SRAM,写操作是缓冲的,并且可以选择WB-WA(Write Back, Write Allocated)缓存属性。此区亦可以执行指令,以允许把代码拷贝到内存中执行——常用于固件升级等维护工作。
3、片上外设区(0x4000_0000–0x5FFF_FFFF)
该区用于片上外设,因此是不可缓存的,也不可以在此区执行指令(这也称为eXecute Never, XN。ARM的参考手册大量使用此术语)。
4、外部RAM区的前半段(0x6000_0000-0x7FFF_FFFF)
该区可用于布设片上RAM或片外RAM,可缓存(缓存属性为WB-WA),并且可以执行指令。
5、外部RAM区的后半段(0x8000_0000–0x9FFF_FFFF)
除了不可缓存(WT)外,同前半段。 6、外部外设区的前半段(0xA000_0000–0xBFFF_FFFF)。用于片外外设的寄存器,也用于多核系统中的共享内存(需要严格按顺序操作,即不可缓冲)。该区也是个不可执行区。
7、外部外设区的后半段(0xC000_0000–0xDFFF_FFFF)
目前与前半段的功能完全一致。 8、外统区(0xE000_0000–0xFFFF_FFFF)。此区是私有外设和供应商指定功能区。此区不可执行代码。系统区涉及到很多关键部位,因此访问都是严格序列化的(不可缓存,不可缓冲)。而供应商指定功能区则是可以缓存和缓冲的。
注:这里解释下写回、写通、写时分配三者的区别
写回(Write Back):写入的数据先逗留在缓存中,待到必要时再落实到最终内存中,这也是cache的最基本职能,用于改善数据传送的效率,减少对访问主存储器的访问操作。
写通(Write Through):写操作“穿透”中间的缓存,直接落入最终的存储器目的地址中。可见,写通操作架空了cache,但它使写操作的结果立即生效。这常用于和片上外设或其它处理器共享的内存中,如显卡的显存,片上外设寄存器,以及双核系统中的共享内存。写通操作和C中的“volatile”可以配合使用——带volatile属性的变量往往放到写通型地址区间中。
写时申请:写入时若是miss,则先把写入的数据存入缓存中,再通过flush方式写入内存。
4、存储器的缺省访问许可
M3有一个缺省的存储访问许可,它能防止使用户代码访问系统控制存储空间,保护NVIC、MPU等关键部件。缺省访问许可在下列条件时生效:没有配备MPU、配备了MPU,但是MPU被除能 如果启用了MPU,则MPU可以在地址空间中划出若干个regions,并为不同的region规定不同的访问许可权限。当一个用户级访问被阻止时,会立即产生一个总线fault。储存器的缺省访问许可如图所示。
5、位带操作
支持了位带操作后,可以使用普通的加载/存储指令来对单一的比特进行读写。在CM3中,有两个区中实现了位带。其中一个是SRAM区的最低1MB范围,第二个则是片内外设区的最低1MB范围。这两个位带中的地址除了可以像普通的RAM一样使用外,它们还都有自己的“位带别名区”,位带别名区把每个比特膨胀成一个32位的字。当你通过位带别名区访问这些字时,就可以达到访问原始比特的目的。位带区与位带别名区的膨胀关系图。
6、非对齐数据传送
M3支持在单一的访问中使用非(地址)对齐的传送,数据存储器的访问无需对齐。CM3中,非对齐的数据传送只发生在常规的数据传送指令中,如LDR/LDRH/LDRSH。其它指令则不支持,包括:多个数据的加载/存储(LDM/STM)、堆栈操作PUSH/POP、互斥访问(LDREX/STREX)。如果非对齐会导致一个用法fault位带操作。因为只有LSB有效,非对齐的访问会导致不可预料的结果。
事实上,在内部是把非对齐的访问转换成若干个对齐的访问的,这种转换动作由处理器总线单元来完成。这个转换过程对程序员是透明的,因此写程序时不必操心。但是,因为它通过若干个对齐的访问来实现一个非对齐的访问,会需要更多的总线周期。事实上,节省内存有很多方法,但没有一个是通过压缩数据的地址,不惜破坏对齐性的这种旁门左道。因此,应养成好习惯,总是保证地址对齐,这也是让程序可以移植到其它ARM芯片上的必要条件。
为此,可以编程NVIC,使之监督地址对齐。当发现非对齐访问时触发一个fault。具体的办法是设置“配置控制寄存器”中的UNALIGN_TRP位。这样,在整个调试期间就可以保证非对齐访问能当场被发现。
7、互斥访问
CM3中没有类似“SWP”的指令。在传统的ARM处理器中,SWP指令是实现互斥体所必需的。到了CM3,由所谓的互斥访问取代了SWP指令,以实现更加老练的共享资源访问保护机制。 互斥体在多任务环境中使用,也在中断服务例程和主程序之间使用,用于给任务申请共享资源(如一块共享内存)。在某个(排他型)共享资源被一个任务拥有后,直到这个任务释放它之前,其它任务是不得再访问它的。为建立一个互斥体,需要定义一个标志变量,用来指示其对应的共享资源是否已经被某任务拥有。当另一个任务欲取得此共享资源时,它要先检查这个互斥体,以获知共享资源是否无人使用。在传统的ARM处理器中,这种检查操作是通过SWP指令来实现的。SWP保证互斥体检查是原子操作的,从而避免了一个共享资源同时被两个任务占有(这是紊乱危象的一种常见表现形式)。
在新版的ARM处理器中,读/写访问往往使用不同的总线,导致SWP无法再保证操作的原子性,因为只有在同一条总线上的读/写能实现一个互锁的传送。因此,互锁传送必须用另外的机制实现,这就引入了“互斥访问”。互斥访问的理念同SWP非常相似,不同点在于:在互斥访问操作下,允许互斥体所在的地址被其它总线master访问,也允许被其它运行在本机上的任务访问,但是CM3能够“驳回”有可能导致竞态条件的互斥写操作。 互斥访问分为加载和存储,相应的指令对子为LDREX/STREX, LDREXH/STREXH,LDREXB/STREXB,分别对应于字/半字/字节。为了介绍方便,以LDREX/STREX为例讲述它们的使用方式。LDREX/STREX的语法格式为:
LDREX的语法同LDR相同,这里不再赘述。而STREX则不同。STREX指令的执行是可以被“驳回”的。当处理器同意执行STREX时,Rxf的值被存储到(Rn+offset)处,并且把Rd的值更新为0。但若处理器驳回了STREX的执行,则不会发生存储动作,并且把Rd的值更新为1。
其实,奥妙就在于这个“驳回”的规则上。规则可宽可严,最严格的规则是:当遇到STREX指令时,仅当在它之前执行过LDREX指令,且在最近的一条LDREX指令执行后,没有执行过其它的STR/STREX指令,才允许执行本条STREX指令——也就是说只有在LDREX执行后,从时间上与之距离最近的一条STREX才能成功执行。 其它情况下,驳回此STREX。包括:中途有其它的STR指令执行、中途有其它的STREX指令执行。 这种最严格的规则也是最容易实现的规则。在CM3的技术参考手册中,推荐实现者标记出一段有限的地址,只在这段地址中适用互斥访问的规则,而不要对所有4GB都限制住。这段地址通常是从LDREX指令族给出的地址开始,长度在16字节至4K字节范围内。但芯片制造商可能更倾向严格的规则。在使用互斥访问时,LDREX/STREX必须成对使用。
执行STREX时,会先检查有没有做出过标记,如果有,还要检查存储地址是否落在标记范围内。只有通过了这两个关卡,STREX才会执行。否则,就驳回STREX。 当使用互斥访问时,在CM3总线接口上的内部写缓冲会被旁路,即使是MPU规定此区是可以缓冲的也不行。这保证了互斥体的更新总能在第一时间内完成,从而保证数据在各个总线主机(master)之间是一致的。So系统的设计师如果设计多核系统,则必须保证各核之间看到的数据也是一致的。
8、端模式
CM3支持小端模式和大端模式。但是,单片机其它部分的设计,包括总线的连接,内存控制器以及外设的性质等,也共同决定可以支持的内存类型。所以在设计软件之前,一定要先在单片机的数据手册上查清楚可以使用的端。在绝大多数情况下,基于CM3的单片机都使用小端模式——为了避免不必要的麻烦,在这里推荐读者清一色地使用小端模式。
在CM3中,是在复位时确定使用哪种端模式的,且运行时不得更改。指令预取永远使用小端模式,在配置控制存储空间的访问也永远使用小端模式(包括NVIC, FPB等)。另外,外部私有总线地址区0xE0000000至0xE00FFFFF也永远使用小端模式。 当使用的Soc设计不支持大端模式,却有一些外设包含了大端模式时,可以使用REV/REVH指令来完成端模式的转换。