2012年(11)
分类: 嵌入式
2012-09-16 23:25:04
• 流水线和延迟槽(delay slot)
IF—instruction fetch
RD—read register,读寄存器和指令译码
ALU—arithmetic/logic unit,运算
MEM—从D-cache上读写数据
WB—write back,回写寄存器
branch delay:jump指令后面的一条指令一定会在branch分支的第一条指令前得以执行。
load delay:加载数据指令后面的一条指令不能用需要加载的数据,因为这个数据还没有加载到寄存器。
• 地址空间
访问kuseg和kseg2的两部分空间需要先设置TLB/MMU。
kseg0和kseg1的两部分空间映射到同一块物理空间,一般是物理内存的底512MB,比如0xA0000000对应物理内存的0地址。除了物理内存,通常这个512MB地址还包含了FLASH/ROM地址、IO寄存器地址等,映射方式取决于不同系统。
kseg0是cachable地址,kseg1是non-cachable。
内 核空间处于kseg0/kseg1区域,用户空间处于kuseg区域。简单的系统不区分内核空间或者用户空间,所以代码都在kseg0/kseg1区域。
MIPS上电第一条指令的地址是0xBFC0000,这个地址通常是FLASH/ROM空间。
下面一张图应该更清楚:
所以MIPS的内核空间可以有2G,但用户空间为2G。而且访问512MB以上的物理地址空间只能通过TLB进行访问。
• 协处理器
CP0的作用:MIPS芯片配置、cache管理、异常中断管理、TLB/MMU管理等。
CP1通常是浮点数协处理器。
count以流水线的频率的一半计数,用于需要精确计时的场合。
读写协处理器有专门的指令mfc/mtc。
• 异常和中断
常见的异常有:中断、内存地址转换、非法操作、系统调用等等。
MIPS的异常入口点有:
对于异常来说,在开始处理异常以前,会完成当异常发生时处于MEM阶段的指令。
异常返回地址保存在EPC寄存器中,eret指令用于异常返回,它还会清楚SR(EXL)位。
MIPS的外部中断(硬件中断)和系统调用(软件中断)都属于最后一条异常。
异常处理
1.将EPC寄存器赋值为被打断的指令地址
2.CPU变为核心态,禁止异常(通过SR[EXL]置位)
3.对Cause寄存器赋值,判断是何种异常,如果是TLB miss/refill,也会把错误的地址赋值给相应的寄存器
4.CPU跳转到相应的异常入口
5.执行异常处理程序,异常处理程序要保存寄存器,保存在打断进程的内核栈里(linux 2.6有中断专用的栈),包括协处理器的寄存器等。如果要支持嵌套异常,需要清楚SR[EXL],并保存EPC的值。(不清除SR[EXL]的话,若在处理一个异常的时候,一个更高的异常发生,会处理那个异常,但是EPC不会更新?)
(既然将中断现场保存在内核栈上,所以事先应该完成了内核栈的切换,内核栈切换不需要用寄存器吗?没保存的寄存器能用吗?或许用的是k0、k1寄存器,它们专供内核态使用)
6.返回异常,返回用的是eret指令
硬件做的事情:CPU状态设置、CAUSE寄存器、EPC寄存器等、CPU跳转到异常入口
软件做的事情:切换到内核态(包括栈指针指向内核栈)、保存现场(通用寄存器等)
所以,和异常中断息息相关的MIPS寄存器为SR[EXL]、SR[IE]、EPC、Cause。解释一下Cause寄存器,它的[6:2]为ExcCode,用于描述异常类型,[15:8]为IP,用于判断中断来源。
中断初始化代码片段(/arch/mips/kernel/traps.c):
• Cache
cache由很多cache line组成,一条cache line由多个字节组成,比如32bytes。
访问内存时(kseg0区域地址),内存地址若在cache中存在,称为hit,直接读写cache即可;若不在cache中,称为miss,则需要在内存中读取。
假设cache line是32字节,内存以32字节对齐的方式加载到cache,但是加载到哪条cache line呢?有基本的两种做法:
1.内存可以加载到任意一条cache line,称为“全相联”
2.内存只能加载特定的cache line,比如一共512条cache line,内存加载到address%512条cache line,称为“直接相连”
第一种方法的缺点是,每次访问内存的时候,需要查找所有的cache line,速度慢。
第二种方法的缺点是,不同地址更有可能加载到同一条cache line,cache数据进出频繁,命中率低。
为此,有一种称为“N路组相连”的方式,即把所有的cache line分组,每组由N条cache line。内存只能被加载到特定的组(直接相联),但在组内可以选择任意的cache line(全相联)。所以N路组相连的方式集合了“全相联”和“直接相连”的优点。
假设有16384(128×128)组cache line,每组4路32字节的cache line,总cache为4MB。若要加载第0个内存页面(4KB),则会加载到0~127组的第一条cache line(假定cache为空,每组一次只用一line);第1个内存页面会加载到128~255组的第一条cache line;第128个内存页面又会加载到0~127组,但用第二条cache line,若4条cache line全部占用,则会替换掉先前的某一条。
更详细的说明搜一篇Comcat写的The MIPS Cache Architecture.pdf,感谢作者
为保证内存与cache之间的一致性(cache-coherent),有几种做法:
write-back:当cache的数据被CPU更改之后,这个数据就标致为dirty,需要回写至内存;
write-through:每次CPU更改了cache中的数据,也会自动回写至内存(一般都用write-back吧);
invalid:当内存的数据更新,需要将cache置为invalid;
说下使用场合,假设一个网卡通过DMA和内存传输数据,CPU发数据的时候,现在cache中构造网络报文,它用的当然是kseg0的地址(小于0xa0000000),然后触发DMA将数据传输至网卡,但是在触发DMA之前,一定要有一个cache write-back的操作;当网卡接收到数据,要传输给内存,CPU会给DMA控制器一个内存地址,这个地址应该是kseg1的地址(大于0xa0000000,其实DMA可能只认总线地址或者说实际的物理内存的地址,就不一定是大于0xa0000000了),anyway,假设地址是0xa345000,0然后网卡ISR中递交给协议栈的地址应该是kseg0地址,即0x83450000,但是在递交之前一定要有一个cache invalid的操作。当然递交协议栈可以用0xa3450000,但是这会非常慢。
总结下来就是:在DMA输出之前要write-back,在DMA输入之后要invalid。
• TLB/MMU
MMU用处有:
每个用户进程都可以有独立的地址,尽管这些地址看着相同
32位上也有4GB地址空间,即使实际的物理内存没那么大
不连续的物理内存可以变成连续的虚拟地址
有助于隐藏和保护地址空间
BTW:内核是一个多线程的,只有单一地址空间
4KB的页是一个折中的结果
TLB(translation lookaside buffer)是一个硬件储存器,它起到cache作用,它储存着虚拟地址和物理地址的对应关系。普通的TLB可能储存着16/32/64项这种地址对应关系,容量比较小,所以不可能储存所有虚拟地址和物理地址的对应关系,转换内存还需要依靠软件的协助(TLB异常)。
上图TLB中的每一项为:
VPN2 为虚拟内存页号,PFN 为物理内存页号
一次可以对应两个物理内存页,也就是假设TLB有16项,它可以查找32个物理内存页,当然VPN2是按双页地址输入的。EntryLo0对应偶数物理页,EntryLo1对应奇数。
ASID是进程号,即PID。PageMask指明页大小。
所以,ASID和VPN2构成了TLB查找的key。
在内存中,软件还要维护一个表(page table)用以描述所有的虚拟地址和物理地址的转换。现代操作系统中,当CPU访问某个地址时,这个地址是虚拟地址,首先TLB会检查它有没有这个虚拟地址(全相联的方式),若有的话,则返回物理地址;这个物理地址会给cache模块,cache会检查它有没有这个物理地址(N路组相连的方式),若有则返回数据;若cache没有,则读取物理内存;
若TLB中没有这个虚拟地址,则会发生TLB refill的异常,异常处理程序中会从内存维护的表中返回物理地址,再将这个物理地址随机写入TLB,然后TLB refill异常返回(异常返回后,重新访问这个虚拟地址,TLB就会返回其物理地址),之后cache会做同样的处理流程。这种方式就是Virtually Indexed, Physically tagged。
BTW,page table一般是一个多级表(前一张表是后一张的目录)。
TLB refill的处理
通过查找page table看是否有正确的转换地址,没有的话,则调用处理地址错误的程序
有正确的转换地址的话,构造一个TLB项(ASID、VPN、PFN、flags等组成)
将新建的一项随机写入TLB即可
TLB有专门的读写指令,比如tlbwi就是写一个entry到TLB的第index项,tlbwr是写一个entry到TLB的随机项。
异常发生的时候,EntryHi的VPN2自动装入访问失败的地址。
• 参考
see mips run
Dajie Tan写的MIPS Linux异常中断代码分析.pdf
Comcat写的The MIPS Cache Architecture.pdf