首页 > 代码库 > Or1200中IMMU使用举例
Or1200中IMMU使用举例
以下内容摘自《步步惊芯——软核处理器内部设计分析》一书
5 IMMU使用情景
前几章通过对OR1200处理器中各类指令执行过程的分析,实现了对CPU模块的剖析,本章将采用情景分析法,通过对使用IMMU的各种情景的分析以实现对IMMU模块剖析。使用IMMU的情景有如下几种:
(1)使用IMMU进行地址翻译,同时ITLB命中,且没有违反页保护策略
(2)使用IMMU进行地址翻译,但是ITLB未命中
(3)使用IMMU进行地址翻译,虽然ITLB命中,但是违反了页保护策略
(4)l.mtspr指令写特殊寄存器ITLBW0MRx、ITLBW0TRx
(5)l.mfspr指令读取特殊寄存器ITLBW0MRx、ITLBW0TRx
上述五种情景中,情景(1)、(2)、(3)在流水线的取指阶段使用到了IMMU,情景(4)、(5)在流水线的执行阶段使用到了IMMU。本章在后续部分将给出一个示例程序,其中涉及了IMMU的大部分使用情景,结合该示例程序分析在上述几种情景下IMMU的工作过程,从而理解IMMU的代码与原理。
6 分析用例
1、修改最小系统
为了使读者朋友对IMMU的作用有一个直观的认识,本节将给出一个示例程序,该示例程序展示了IMMU初始化、IMMU地址翻译、ITLB失靶异常、违反页保护策略而引发指令页失效异常等多种情况。在使用该示例程序之前,需要修改or1200_defines.v文件中的如下定义以启用IMMU:
or1200_defines.v //`define OR1200_NO_IMMU 注释掉此处的宏定义,表示需要IMMU
这样我们的最小系统就修改成如图10.11所示,在CPU与QMEM模块之间添加了IMMU模块。CPU模块的指令Wishbone总线接口分为两部分:一部分在CPU与IMMU之间,一部分在CPU与QMEM之间,参考图3.7可以更加清晰的了解这一点。
此外,使用IMMU进行地址翻译时,由于地址翻译是以页为单位的(查询页表),页的大小是8KB,而QMEM中RAM的默认大小就是8KB,也就是只有1页,无法进行仿真,为此需要改变QMEM中RAM的大小。修改步骤如下:
(1)修改or1200_spram_2048x32.v中的地址宽度参数aw,修改为13,使得QMEM中RAM的大小变为32KB,共4页。
or1200_spram_2048x32.v parameter aw = 13; //地址线的宽度,原值为11,新值为13 parameter dw = 32;
(2)修改QMEM中or1200_spram_2048x32的例化代码,如下:
or1200_qmem_top.v or1200_spram_2048x32 or1200_qmem_ram( .clk(clk), .rst(rst), `ifdef OR1200_BIST .mbist_si_i(mbist_si_i), .mbist_so_o(mbist_so_o), .mbist_ctrl_i(mbist_ctrl_i), `endif `ifdef OR1200_QMEM_BSEL .sel(qmem_sel), `endif `ifdef OR1200_QMEM_ACK .ack(qmem_ack), `endif //将.addr(qmem_addr[12:2])改为.addr(qmem_addr[14:2]) .addr(qmem_addr[14:2]), .ce(qmem_en), .we(qmem_we), .oe(1'b1), .di(qmem_di), .doq(qmem_do) );
修改结束后,需要在ModelSim中重新编译才可进行仿真。
2、示例程序
本节将给出一个示例程序,该程序涉及了IMMU的大部分使用情景,包括:ITLB命中且无页错误、ITLB失靶、ITLB命中但是有页错误、指令l.mtspr写IMMU中特殊寄存器等,读者借助于该程序可以更加具体的认识IMMU。
示例程序如下,共分为8步,读者朋友可以按照第1步、第2步、第3步……第8步这样的顺序阅读,便于理解:
.section .text,"ax" .global _start ####################### 第7步 ######################## .org 0x000C l.movhi r1,0x12 l.movhi r1,0x13 #第6步修改ITLB后,有效地址0x6010被翻译为0x0010 l.movhi r1,0x14 l.movhi r1,0x15 l.ori r2,r0,0x8040 #r2=0x8040 l.movhi r1,0x9 l.mtspr r0,r2,0x0011 #将0x8040写入SR,从而使得处理器进入用户模式 l.movhi r1,0x16 #在设置处理器进入用户模式之前已经读取到本指令进入 #流水线,所以不受影响 l.movhi r1,0x17 #在设置处理器进入用户模式之前已经读取到本指令进入 #流水线,所以不受影响 l.movhi r1,0x18 #读取指令时ITLBW0TR3的标志位uxe是0,所以本指令会引 #发指令页失效异常,转移至指令页失效异常处理例程入口 #地址0x400处 l.movhi r1,0x19 #上一条指令引发指令页失效异常,所以不会执行本指令 l.movhi r1,0x20 #不会执行本指令 ###################### 第1步 ######################## .org 0x100 _start: l.andi r0,r0,0 #初始化r0-r4,都设置为0 l.extwz r1,r0 l.extwz r2,r0 l.extwz r3,r0 l.extwz r4,r0 ##################### 第2步 ########################### ###### 初始化ITLB,初始化的方法就是使用l.mtspr写ITLBW0MRx、ITLBW0TRx #### l.ori r3,r0,0x1 #设置寄存器r3为0x1 l.mtspr r0,r3,0x1200 #向地址0x1200的SPR写入0x1,0x1200对应的SPR #就是ITLBW0MR0,所以此处就是设置ITLBW0MR0, #对应MR表的第0项放置0x1,其中VPN为0,Valid为1 l.ori r3,r0,0x20C0 #设置寄存器r3为0x20C0 l.mtspr r0,r3,0x1280 #向地址0x1280的SPR写入0x20C0,0x1280对应的 #SPR就是ITLBW0TR0,所以此处就是设置ITLBW0TR0, #对应TR表的第0项放置0x20C0,其中PPN为0x1, #sxe为1,uxe为1,ci为0 #上述两项设置使得有效地址0x0-0x01FFF被翻译为物理地址0x2000-0x3FFF l.ori r3,r0,0x0 #设置寄存器r3为0x0 l.mtspr r0,r3,0x1203 #向地址0x1203的SPR写入0x1,0x1203对应的SPR #就是ITLBW0MR3,所以此处就是设置ITLBW0MR3, #对应MR表的第3项放置0x0,其中VPN为0, # Valid为0,即ILTBW0MR3无效 l.ori r3,r0,0x40C0 #设置寄存器r3为0x40C0 l.mtspr r0,r3,0x1283 #向地址0x1283的SPR写入0x40C0,0x1283对应的 #SPR就是ITLBW0TR3,所以此处就是设置ITLBW0TR3, #对应TR表的第3项放置0x40C0,其中PPN为0x2, # sxe为1,uxe为1,ci为0 #上述两项设置使得有效地址0x6000-0x7FFF被翻译为物理地址0x4000-0x5FFF,但 #是由于标志位V设置为0,所以使用该表项翻译时会出现ITLB失靶异常 ################### 第3步 ######################## l.mfspr r1,r0,0x0011 #读取SR到寄存器r1,SR初始化时的值为0x8001, #可知SR[IME]为0表示IMMU禁用 l.ori r1,r1,0x40 #修改r1为(0x8001 | 0x40)=0x8041 l.ori r2,r2,0x0 #设置寄存器r2为0x0 l.mtspr r0,r1,0x0011 #将0x8041写入SR,从而修改SR[IME]为1,使能IMMU, #本指令执行时,下面的一条指令已经被取出,并进 #入流水线 l.jr r2 #在使能IMMU时,本指令已经被取出并进入流水线, #所以会得到执行,该指令的作用是转移到有效地址 #0x0处,但是由于已经使能IMMU,所以转移物理地 #址对应就是0x2000 l.movhi r1,0x1 #延迟槽指令,使能IMMU的时候,本指令已经被取出 #并进入流水线,所以会得到执行 l.movhi r1,0x2 #不会执行本条指令,因为IMMU已使能,将从0x2000 #处读取指令 ################### 第8步 ########################## .org 0x400 #指令页失效处理例程 l.movhi r1,0x15 #设置r1为0x15000 l.movhi r1,0x16 #设置r1为0x16000,这两条指令的作用是验证处理器 #最终是否转移到指令页失效异常处理例程 l.nop 0x0001 #结束 ################### 第5步 ########################### .org 0xA00 #ITLB失靶异常处理例程 l.ori r3,r0,0x1 #设置寄存器r3为0x1 l.mtspr r0,r3,0x1203 #向地址0x1203的SPR写入0x1,0x1203对应的SPR就是 #ITLBW0MR3,所以此处就是设置ITLBW0MR3,对应MR表 #的第3项放置0x1,其中VPN为0,Valid为1 l.ori r3,r0,0x4040 #设置寄存器r3为0x4040 l.mtspr r0,r3,0x1283 #向地址0x1283的SPR写入0x4040,0x1283对应的SPR就 #是ITLBW0TR3,所以此处就是设置ITLBW0TR3,对应TR #表的第3项放置0x4040,其中PPN为0x2, # sxe为1,uxe为0,ci为0 #上述两项设置使得有效地址0x6000-0x7FFF被翻译为物理地址0x4000-0x5FFF l.rfe #ITLB失靶异常返回,回到有效地址0x6000处,此时 #0x6000被翻译到物理地址0x4000 #################### 第4步 ########################### .org 0x2000 #这几条指令没有特殊目的,只是用于验证处理器在此处执行过 l.movhi r1,0x3 l.movhi r1,0x4 l.movhi r1,0x5 l.ori r2,r0,0x6000 l.jr r2 #转移到有效地址0x6000处,该有效地址对应的就是 #ITLBW0MR3,但是由于ITLBW0MR3的标志位V为0,即 #该ITLB表项无效,所以会引发ITLB失靶异常,转移 #至ITLB失靶异常处理例程入口地址0xA00处执行 l.movhi r1,0x6 #延迟槽指令会得到执行 l.movhi r1,0x7 #不会执行本指令 l.movhi r1,0x8 #不会执行本指令 ##################### 第6步 ########################### .org 0x4000 #从失靶异常返回后,会转移到有效地址0x6000处, #对应的物理地址就是0x4000 l.ori r3,r0,0x0040 #设置寄存器r3为0x0040 l.mtspr r0,r3,0x1283 #向地址0x1283的SPR写入0x0040,0x1283对应的SPR #就是ITLBW0TR3,所以此处就是设置ITLBW0TR3,对 #应TR表的第3项放置0x0040,其中PPN为0x0, # sxe为1,uxe为0,ci为0 #上述两项设置使得有效地址0x6000-0x7FFF被翻译为物理地址0x0000-0x1FFFF l.movhi r1,0x9 #修改ITLB时本指令处于流水线取指阶段,所以本 #指令会得到执行 l.movhi r1,0x10 #修改ITLB时本指令处于流水线取指阶段,所以本 #指令会得到执行 l.movhi r1,0x11 #本指令不会得到执行,会重新翻译地址,有效地 #址0x6010被翻译为0x0010 ###################### 结 束 ##########################
示例程序比较长,可以分为8步,每一步涉及到的代码在上面使用注释符分隔开,读者朋友需要借助本章前面几节介绍的ITLB知识仔细体会,执行流程如下:
第1步:初始化r0-r4,都设置为0。
第2步:初始化ITLB中的表项,主要是两个表项,对应图10.7中的第0、3项,初始化的方法就是使用指令l.mtspr写ITLBW0MR0、ITLBW0TR0、ITLBW0MR3、ITLBW0TR3。此处设置ITLBW0MR0为0x1、ITLBW0TR0为0x20C0,这样IMMU会将有效地址0x0-0x01FFF翻译为物理地址0x2000-0x3FFF;设置ITLBW0MR3为0x0、ITLBW0TR3为0x40C0,原计划是使得IMMU将有效地址0x6000-0x7FFF翻译为物理地址0x4000-0x5FFF,但是由于此处设置ITLBW0MR3为0x0,也就是设置ITLBW0MR3的标志位V为0,所以当IMMU翻译有效地址0x6000-0x7FFF时,会出现ITLB失靶异常。初始化结束后ITLB内容如图10.12所示。
第3步:设置特殊寄存器SR的标志位IME为1,从而使能IMMU,然后转移到有效地址0x0处。有效地址0x0被翻译为物理地址0x2000,所以会转移到0x2000处执行。
第4步:从物理地址0x2000处读取代码并执行,其中会使用指令l.jr转移到有效地址0x6000,由于翻译有效地址0x6000时会使用ITLBW0MR3,而此时ITLBW0MR3为0,其中标志位V为0,也就是0x6000对应的ITLB表项无效,所以会引发ITLB失靶异常,转移到ITLB失靶异常处理例程入口地址0xA00处执行。如图10.13所示。
第5步:执行ITLB失靶异常处理例程,其中设置ITLBW0MR3为0x1,使得ITLB第3个表项有效。ITLB失靶异常处理例程会使用指令l.rfe从异常返回,返回地址是0x6000,但0x6000是有效地址,此时通过IMMU翻译得到对应物理地址是0x4000,所以会从物理地址0x4000处取得指令并执行。
第6步:执行物理地址0x4000处的代码,其中设置ITLBW0TR3为0x0040,使得IMMU将有效地址0x6000-0x7FFF翻译为物理地址0x0000-0x1FFF。指令l.mtspr r0,r3,0x1283修改ITLBW0TR3时,其后面两条指令已经进入流水线,所以会得到执行,但是在取l.mtsprr0,r3,0x1283后面的第三条指令时(有效地址为0x6010)会被翻译为0x0010,也就是从物理地址0x0010处取指,如图10.14所示。同时需要注意,ITLBW0TR3为0x0040,对应的标志位UXE为0,表示该页代码在用户模式下不可执行。
第7步:此处设置SR[SM]为0,使得处理器进入用户模式,而此时ITLBW0TR3[UXE]为0,表示对应页在用户模式下不可执行,所以再取指令的时候会引发指令页失效异常,转移到ITLB指令页失效异常处理例程入口地址0x400处执行。如图10.15所示。
第8步:进入ITLB指令页失效异常处理例程,程序结束。
上述流程可以使用图10.16表示,该图是按照内存中代码存放顺序排列各个步骤的。
在Ubuntu中新建一个文件,命名为Example.S,内容就是上述代码,拷贝ram.ld、Makefile、Bin2Mem.exe到Example.S所在目录,但是笔者在实验中发现,由于OR1KSim模拟器本身的一些问题,导致模拟器不能完全正确地按照程序设计的流程执行,所以本章不使用OR1KSim模拟器执行示例程序,而只在ModelSim中仿真验证。为此,修改Makefile文件如下:
Makefile all: Example.or32 mem.data //去掉模拟器执行目标Example.trace
此时再打开终端,调整路径到上述文件所在目录,输入“make all”得到可以在ModelSim仿真中使用的存储器初始化文件mem.data,为了便于知道仿真波形中if_insn、id_insn、ex_insn等信号对应的指令,下面列出指令与其对应的二进制,分为三列,分别是指令地址、指令、指令对应的二进制。
############################## 第7步 ################ 指令地址 指令 指令对应的二进制 0x0000000C: l.movhi r1,0x12 0x18200012 0x00000010: l.movhi r1,0x13 0x18200013 0x00000014: l.movhi r1,0x14 0x18200014 0x00000018: l.movhi r1,0x15 0x18200015 0x0000001C: l.ori r2,r0,0x8040 0xa8408040 0x00000020: l.movhi r1,0x9 0x18200009 0x00000024: l.mtspr r0,r2,0x0011 0xc0001011 0x00000028: l.movhi r1,0x16 0x18200016 0x0000002C: l.movhi r1,0x17 0x18200017 0x00000030: l.movhi r1,0x18 0x18200018 0x00000034: l.movhi r1,0x19 0x18200019 0x00000038: l.movhi r1,0x20 0x18200020 ############################## 第1步 ################# 指令地址 指令 指令对应的二进制 0x00000100: l.andi r0,r0,0 0xa4000000 0x00000104: l.extwz r1,r0 0xe020004d 0x00000108: l.extwz r2,r0 0xe040004d 0x0000010C: l.extwz r3,r0 0xe060004d 0x00000110: l.extwz r4,r0 0xe080004d ############################## 第2步 ################## 指令地址 指令 指令对应的二进制 0x00000114: l.ori r3,r0,0x1 0xa8600001 0x00000118: l.mtspr r0,r3,0x1200 0xc0401a00 0x0000011C: l.ori r3,r0,0x20C0 0xa86020c0 0x00000120: l.mtspr r0,r3,0x1280 0xc0401a80 0x00000124: l.ori r3,r0,0x0 0xa8600000 0x00000128: l.mtspr r0,r3,0x1203 0xc0401a03 0x0000012C: l.ori r3,r0,0x40C0 0xa86040c0 0x00000130: l.mtspr r0,r3,0x1283 0xc0401a83 ############################## 第3步 ################# 指令地址 指令 指令对应的二进制 0x00000134: l.mfspr r1,r0,0x0011 0xb4200011 0x00000138: l.ori r1,r1,0x40 0xa8210040 0x0000013C: l.ori r2,r2,0x0 0xa8420000 0x00000140: l.mtspr r0,r1,0x0011 0xc0000811 0x00000144: l.jr r2 0x44001000 0x00000148: l.movhi r1,0x1 0x18200001 0x0000014C: l.movhi r1,0x2 0x18200002 ############################## 第8步 ################## 指令地址 指令 指令对应的二进制 .org 0x400 0x00000400: l.movhi r1,0x15 0x18200015 0x00000404: l.movhi r1,0x16 0x18200016 0x00000408: l.nop 0x0001 0x15000001 ############################## 第5步 ################## 指令地址 指令 指令对应的二进制 .org 0xA00 0x00000A00: l.ori r3,r0,0x1 0xa8600001 0x00000A04: l.mtspr r0,r3,0x1203 0xc0401a03 0x00000A08: l.ori r3,r0,0x4040 0xa8604040 0x00000A0C: l.mtspr r0,r3,0x1283 0xc0401a83 0x00000A10: l.rfe 0x24000000 ############################## 第4步 ################## 指令地址 指令 指令对应的二进制 .org 0x2000 0x00002000: l.movhi r1,0x3 0x18200003 0x00002004: l.movhi r1,0x4 0x18200004 0x00002008: l.movhi r1,0x5 0x18200005 0x0000200C: l.ori r2,r0,0x6000 0xa8406000 0x00002010: l.jr r2 0x44001000 0x00002014: l.movhi r1,0x6 0x18200006 0x00002018: l.movhi r1,0x7 0x18200007 0x0000201C: l.movhi r1,0x8 0x18200008 ############################## 第6步 ################### 指令地址 指令 指令对应的二进制 .org 0x4000 0x00004000: l.ori r3,r0,0x0040 0xa8600040 0x00004004: l.mtspr r0,r3,0x1283 0xc0401a83 0x00004008: l.movhi r1,0x9 0x18200009 0x0000400C: l.movhi r1,0x10 0x18200010 0x00004010: l.movhi r1,0x11 0x18200011 ############################## 结 束 ##################
ModelSim仿真波形如图10.17-10.21所示。从仿真结果可知程序是按照预期运行的。本书光盘的Chapter10目录下包括本章使用的ModelSim仿真工程,Chapter10/Code目录下包括示例程序源代码。
本章后续部分将借助该程序分析IMMU在各种使用情景下的工作过程。