首页 > 代码库 > 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在各种使用情景下的工作过程。