上一节讲述了在没有MMU的CPU(如80251、MIPS M控制器系列、ARM cortex m系列)上实现虚拟内存管理的集成硬件设计方法,新设计的内存管理管理单元要实现虚拟内存管理还需要操作系统、代码分块(Bank)的支持,详见SoC嵌入式软件架构设计之二:没有MMU的CPU实现虚拟内存管理的设计方法。这里要阐述Bank设计的一些原则。
Bank设计是为了实现不同时刻运行的Bank(代码块)运行在同一块内存上,所以在运行之前操作系统需要将已存在内存的代码/数据进行缓存处理,并加载将要运行的Bank到该内存上。为了实现这个目的,需要明确以下要点:
1.为了提高效率,我们认为代码是不会自修改的,即代码是只读的,则在Bank切换的时候可以直接将已经存在内存的Bank代码丢弃。我们只需要将当前已经存在内存的Bank代码的Bank号入栈即可,新加载的代码可以直接覆盖该块内存。不同的Bank有不同的虚拟地址,为什么可以放到同样的物理内存?其实是新设计的内存管理单元的电路决定的。参考前一节的文章(SoC嵌入式软件架构设计之二:没有MMU的CPU实现虚拟内存管理的设计方法)介绍,关键是同一个Bank组的不同虚拟地址信号对应的物理输出信号是一样的。
2.程序调用后返回到一个Bank的某一行时同样需要加载该Bank代码,这时操作系统会将之前的Bank号出栈,并根据Bank号将对应的代码加载到该块内存。从1和2来看,调用Bank代码和返回一个Bank设计到Bank号的入栈和出栈,如果设计的Bank代码中的函数的虚拟运行地址带有明确的Bank号信息,那函数的调用和返回就是一个入栈和出栈过程,这样操作系统可以减少出入栈的工作,代码运行也更顺畅。
3.Bank代码中的变量数据处理:
1)全局变量。如果全局变量定义在公共区域,那Bank代码切换过程中不需对其进行处理。如果全局变量定义在Bank内存区域,则Bank切换时需要对这部分全局变量进行缓存处理。即在Bank号入栈之后,将Bank中的数据存到堆中,在Bank返回时除了从外存储设备加载对应的代码时,还要将其对应的数据从堆中恢复到Bank内存。为了加快数据的恢复,往往默认一个Bank数据空间的最大值,这样就不需要记录每个Bank的数据空间的大小。
2)静态变量。跟全局变量一样。
3)常量段。其是只读,跟代码一块处理。
4)局部变量。局部变量是在栈中分配空间的,所以不需要进行缓存。
5)buffer。假如该Buffer只是某个Bank调用,而该Bank除了代码还有剩余空间大于buffer大小,那将buffer设置在代码段之后,并定义一个指针局部变量,程序中直接指向该buffer的首地址。
如果我们将Bank内的全局变量全部转为局部变量,那操作系统就不需要对数据进行缓存管理,就不需要堆空间。但是局部变量对应的栈空间就加大了。一个Bank可能有多个函数,而多个函数是可能会用到同样的全局变量的。但这种情况需要的全局变量往往不大,可以考虑都转为局部变量。如果不需要进行数据缓存,那系统管理将会非常简单。
4.中断处理不能进行Bank切换。Bank切换需要进行读写外存储设备,会造成很大的延时,所以在中断里面不应该产生Bank切换。
5.操作系统、驱动、应用各层次频繁调用的代码应设置为常驻代码,如果发生切换会损失效率。如果频繁调用的代码很固定,如操作系统的调度管理等代码可以固化到ROM中,以减少成本。
6.Bank内存分块大小要适中,在保持切换性能的基础上选择较小的内存块。Bank块设置过小,就会导致Bank切换频繁,损失效率,Bank设置过大会造成内存浪费。
7.Bank内存的起始地址应该对齐扇区(512字节),这样读外存储设备能够达到最好的性能。
SoC嵌入式软件架构设计之三:代码分块(Bank)设计原则,布布扣,bubuko.com
原文:http://blog.csdn.net/yueqian_scut/article/details/24911021