首页 > 代码库 > OR1200数据Cache的通写、回写应用举例
OR1200数据Cache的通写、回写应用举例
以下内容摘自《步步惊芯——软核处理器内部设计分析》一书
13.3 DCache中的特殊寄存器
在DCache中定义了三个特殊寄存器:DCBFR、 DCBIR、DCBWR,这三个寄存器都是只可写寄存器,即只能使用指令l.mtspr操作这三个特殊寄存器。其中在通写法策略下只能使用DCBIR、DCBFR,在回写法策略下可以使用全部三个特殊寄存器。各特殊寄存器的含义如表13.1所示,格式都如表13.2所示。
- 当使用指令l.mtspr向数据缓存块刷新寄存器DCBFR中写入地址时,有如下几种情况:
- 如果该地址对应DCache目录表中line的标志位Dirty为0、V为1,那么直接设置该line标志位V为0
- 如果该地址对应DCache目录表中line的标志位Dirty为1,、V为1,那么首先把该line中的16个字节写回内存,然后设置该line的标志位V为0
- 其余情况没有操作
- 当使用指令l.mtspr向数据缓存块无效寄存器DCBIR中写入地址时,那么直接设置该地址对应DCache目录表中line的标志位V为0
- 当使用指令l.mtspr向数据缓存块回写寄存器DCBWR中写入地址时,有如下几种情况:
- 如果该地址对应DCache目录表中line的标志位Dirty为1、V为1,那么需要把该line中的16个字节写回内存
- 其余情况没有操作
从指令l.mtspr对这三个寄存器操作的工作过程可知,其中很重要的影响因素就是标志位Dirty的值,而采用通写法时,DCache目录表中每一个line的Dirty标志位始终为0,所以在通写法策略下,寄存器DCBWR没有作用,并且此时DCBFR、DCBIR的作用是一样的,在后面的代码分析中也可以发现在通写法策略下,DCache处理指令l.mtspr写DCBFR与DCBIR的过程是一样的。
13.4 DCache使用情景
第12章通过对使用ICache各种情景的分析实现了对ICache模块的剖析,本章采用同样的方法,通过对使用DCache各种情景的分析以实现对DCache模块的剖析,使用到DCache的情景有如下几种:
(1)l.mtspr指令写DCache中的特殊寄存器(分通写法、回写法)
(2)存储指令执行阶段DCache失靶(分通写法、回写法)
(3)加载指令执行阶段DCache失靶(分通写法、回写法)
(4)存储指令执行阶段DCache命中(分通写法、回写法)
(5)加载指令执行阶段DCache命中(DCache的工作过程在通写法、回写法下是一样的)
(6)存储指令执行阶段内存页禁止缓存(DCache的工作过程在通写法、回写法下是一样的)
(7)加载指令执行阶段内存页禁止缓存(DCache的工作过程在通写法、回写法下是一样的)
上述各种情景都是在指令的流水线执行阶段使用到DCache,并且前四种情景在不同的写策略下DCache有不同的工作过程,因此需要区分通写法、回写法两种情况。后三种情景在使用通写法、回写法策略时,DCache的工作过程是一样的,因此不用区分。下一节将给出一个示例程序,其中涉及到DCache的大多数使用情景,本章后续部分将结合该示例程序详细分析在(1)、(2)、(4)三种情景下DCache的工作过程,其余情景的分析与此是类似的,限于篇幅,本书不再详细分析,有兴趣的读者可以自行分析。
13.5 分析用例
13.5.1 修改已有的简单SOPC
在分析CPU内部的工作过程时,我们将程序放在QMEM中,这样就避免了由于等待指令取到而使处理器暂停的情况,使得可以在一个时钟周期取到指令,排除了取指过程的影响,从而可以更加精确的分析CPU中指令的执行过程。同样,本章主要是分析DCache,所以也希望排除取指过程的影响,这样可以更加准确的观察到添加DCache后,加载存储指令的处理过程。为此,需要修改简单SOPC,可以有两种方法:
方法一:在QMEM中存储代码,在RAM的0x100处存储一条转移指令,使得处理器复位后转移到QMEM中的代码执行。
方法二:修改简单SOPC的配置,使得处理器复位后直接从QMEM中的代码开始执行。
本章采用的是方法二,因为这样可以使读者切身体会到:学习了OR1200源代码后,可以十分灵活的使用OR1200。本章的示例程序还是运行在简单SOPC之上,所以也就是修改简单SOPC。修改步骤如下:
(1)修改or1200_defines.v中有关复位地址的宏定义,使得处理器复位后从QMEM中读取指令,如下:
or1200_defines.v原值:`define OR1200_BOOT_PCREG_DEFAULT 30'h0000003f `define OR1200_BOOT_ADR 32'h00000100新值:`define OR1200_BOOT_PCREG_DEFAULT 30'h001fffff //等于(OR1200_BOOT_ADR/4)-1 `define OR1200_BOOT_ADR 32'h00800000 //因为QMEM的起始地址0x00800000
(2)修改or1200_defines.v中关于QMEM的设置,如下:
or1200_defines.v//默认是没有Implement QMEM,此处需要取消掉注释符`define OR1200_QMEM_IMPLEMENTED
(3)修改QMEM中存储器的代码,目的是使用编译得到的存储器初始化文件mem.data初始化QMEM,如下:
or1200_spram_2048x32.vinitial $readmemh ( "mem.data", mem );
13.5.2 分析用例
示例程序代码如下:
.section .text,"ax" .global _start #因为指令存放在QMEM中,而且复位后从QMEM的0x0地址处执行,所以此处设置为0x0, #而不再是以前的0x100 .org 0x0 ###################### 第1步 ############################_start: l.movhi r0,0x0 #r0-r3寄存器清零 l.addi r1,r0,0x0 l.addi r2,r0,0x0 l.addi r3,r0,0x0###################### 第2步 #############################_DC_Init: #初始化DCache中的line0、line1,没有初始化整个DCache,这样节约时间,而且 #后面的程序也只使用到这两个line #初始化的方法与ICache一样,向特殊寄存器DCBIR中写入地址0x0、0x10 l.mtspr r0,r1,0x1803 l.addi r1,r1,0x10 l.mtspr r0,r1,0x1803 ###################### 第3步 ############################ l.addi r1,r0,0x0 #设置r1为0x0_RAM_Init1: #初始化RAM中地址0x0-0xC的内容,0x0处存储0x0,0x4处存储0x4,0x8处存储0x8, #0xC处存储0xC l.sw 0x0(r1),r1 l.sfeqi r1,0xC l.bnf _RAM_Init1 l.addi r1,r1,0x4 ###################### 第4步 ########################### l.addi r1,r0,0x10 #设置r1为0x10_RAM_Init2: #初始化RAM中地址0x10-0x1C的内容,0x10、0x14、0x18、0x1C处都存储0 l.sw 0x0(r1),r0 l.sfeqi r1,0x1C l.bnf _RAM_Init2 l.addi r1,r1,0x4 ###################### 第5步 ########################## l.addi r1,r0,0x0 #设置r1为0x0_RAM_Read: #加载RAM中0x0、0x4、0x8、0xC处的字 l.lwz r2,0x0(r1) l.sfeqi r1,0xC l.bnf _RAM_Read l.addi r1,r1,0x4 ###################### 第6步 ########################### l.addi r1,r0,0x0 #设置r1为0x0 #向地址0x0A00的SPR写入0x1,0x0A00对应的SPR就是DTLBW0MR0, #所以此处就是设置DTLBW0MR0,对应MR表的第0项放置0x1, #其中VPN为0,Valid为1 l.ori r3,r0,0x1 l.mtspr r0,r3,0x0A00 #向地址0x0A80的SPR写入0x00C0,0x0A80对应的SPR就是DTLBW0TR0, #所以此处就是设置DTLBW0TR0,对应TR表的第0项放置0x03C0, #其中PPN为0x0,swe、sre、uwe、ure都为1,ci为0 l.ori r3,r0,0x03C0 l.mtspr r0,r3,0x0A80 #上述设置使得有效地址0x0-0x1fff被翻译为物理地址0x0-0x1fff,两者相等 ###################### 第7步 ########################### #设置SR寄存器为0x8029,即SR[DME]、SR[DCE]都为1,使能DCache、DMMU l.ori r3,r0,0x8029 l.mtspr r0,r3,0x11 l.nop ###################### 第8步 ############################ l.addi r1,r0,0x10 #设置r1为0x10 #存储数据到RAM中,0x10处存储0x10、0x14处存储0x14、0x18处存储0x18、0x1C处存储0x1C_loop1: l.sw 0x0(r1),r1 l.sfeqi r1,0x1C l.bnf _loop1 l.addi r1,r1,0x4 ###################### 第9步 ############################# l.addi r1,r0,0x0 #设置r1为0x0_loop2: l.lwz r2,0x0(r1) #加载RAM中地址0x0、0x4、0x8、0xC处的数据 l.sfeqi r1,0xC l.bnf _loop2 l.addi r1,r1,0x4 ###################### 第10步 ############################# l.addi r3,r0,0xF l.sw 0x0(r0),r3 #存储0xF到RAM中0x0处###################### 第11步 ############################## l.mtspr r0,r0,0x1804 #将0x0写入DCBWR寄存器###################### 第12步 ############################# l.addi r3,r0,0xFF l.sw 0x0(r0),r3 #存储0xFF到RAM中0x0处###################### 第13步 ############################# l.mtspr r0,r0,0x1802 #将0x0写入DCBFR寄存器###################### 第14步 ############################# l.ori r3,r0,0x03C2 l.mtspr r0,r3,0x0A80 #0x0-0x1fff对应内存页缓存禁止###################### 第15步 ############################# l.addi r3,r0,0x55 l.sw 0x0(r0),r3 #存储0x55到RAM中0x0处 l.lwz r2,0x0(r0) #从RAM中0x0处加载数据
示例程序比较长,共有15步,但过程还是比较简单的,其中第1-7步说明如下:
第1步:寄存器r0-r3清零。
第2步:初始化DCache,因为DCache中DC_TAG、DC_RAM实现主体就是单口RAM,在系统启动的时候,RAM中的内容是不确定的,所以需要初始化DCache,初始化的方法就是依次设置DC_TAG中每个表项的V为0,表示该表项无效。参考之前对DCBIR的介绍,指令l.mtspr向特殊寄存器ICBIR中依次写入0x10、0x20……0x2000,就会依次设置DC_TAG中每个表项的V为0。但是由于示例程序只使用了DCache中的line 0、line 1,所以没有必要设置DC_TAG中每个表项,只需设置前2个即可,即使用指令l.mtspr向ICBIR中依次写入0x0、0x10。
第3步:初始化RAM中地址0x0-0xC的内容,使得0x0处存储0x0、0x4处存储0x4、0x8处存储0x8、0xC处存储0xC,通过这一步,可以观察没有DCache时,存储指令执行完毕需要使用的时钟周期。
第4步:初始化RAM中地址0x10-0x1C的内容,使得0x10、0x14、0x18、0x1C处都存放0x0。
第5步:加载RAM中0x0、0x4、0x8、0xC处的字,通过这一步,可以观察没有DCache时,加载指令执行完毕需要使用的时钟周期。
第6步:设置DTLB的第一个表项,使得数据的有效地址0x0-0x1fff被翻译为物理地址0x0-0x1fff,实际就是有效地址等于物理地址,示例程序中加载、存储的数据地址都位于0x0-0x1fff范围内,所以在示例程序运行的时候,DMMU地址翻译的结果就是物理地址与有效地址相等,DMMU的作用在第14步中会有所体现。
第7步:设置SR寄存器,使得SR[DCE]为1、SR[DME]为1,使能DCache、DMMU。
在第7步中已经使能DCache,后面步骤的执行过程在使用通写法、回写法时会有所不同,如表13.3所示。
在Ubuntu中新建文件Example.S,内容就是上述代码,拷贝ram.ld、Makefile、Bin2Mem.exe到Example.S所在目录,此处的Makefile选择在10章中修改过后的Makefile,也就是不会使用OR1KSim进行模拟。此时再打开终端,调整路径到上述文件所在目录,输入“make all”得到可以在ModelSim仿真中使用的存储器初始化文件mem.data。修改后的简单SOPC就使用该文件初始化QMEM。为了便于知道仿真波形中if_insn、id_insn、ex_insn等信号对应的指令,下面列出指令与其对应的二进制,分为三列,分别是指令地址、指令、指令对应的二进制。
############################## 第1步 ##############################指令地址 指令 指令对应的二进制 _start:0x800000 l.movhi r0,0x0 0x180000000x800004 l.addi r1,r0,0x0 0x9c2000000x800008 l.addi r2,r0,0x0 0x9c4000000x80000C l.addi r3,r0,0x0 0x9c600000############################## 第2步 ##############################指令地址 指令 指令对应的二进制 _DC_Init: 0x800010 l.mtspr r0,r1,0x1803 0xc06008030x800014 l.addi r1,r1,0x10 0x9c2100100x800018 l.mtspr r0,r1,0x1803 0xc06008030x80001C l.addi r1,r0,0x0 0x9c200000############################## 第3步 ##############################指令地址 指令 指令对应的二进制_RAM_Init1: 0x800020 l.sw 0x0(r1),r1 0xd40108000x800024 l.sfeqi r1,0xC 0xbc01000c0x800028 l.bnf _RAM_Init1 0x0ffffffe0x80002C l.addi r1,r1,0x4 0x9c210004############################## 第4步 ##############################指令地址 指令 指令对应的二进制0x800030 l.addi r1,r0,0x10 0x9c200010_RAM_Init2: 0x800034 l.sw 0x0(r1),r0 0xd40100000x800038 l.sfeqi r1,0x1C 0xbc01001c0x80003C l.bnf _RAM_Init2 0x0ffffffe0x800040 l.addi r1,r1,0x4 0x9c210004############################## 第5步 ##############################指令地址 指令 指令对应的二进制0x800044 l.addi r1,r0,0x0 0x9c200000_RAM_Read: 0x800048 l.lwz r2,0x0(r1) 0x844100000x80004C l.sfeqi r1,0xC 0xbc01000c0x800050 l.bnf _RAM_Read 0x0ffffffe0x800054 l.addi r1,r1,0x4 0x9c210004############################## 第6步 ##############################指令地址 指令 指令对应的二进制0x800058 l.addi r1,r0,0x0 0x9c2000000x80005C l.ori r3,r0,0x1 0xa8600001 0x800060 l.mtspr r0,r3,0x0A00 0xc0201a00 0x800064 l.ori r3,r0,0x03C0 0xa86003c00x800068 l.mtspr r0,r3,0x0A80 0xc0201a80############################## 第7步 ##############################指令地址 指令 指令对应的二进制0x80006C l.ori r3,r0,0x8029 0xa86080290x800070 l.mtspr r0,r3,0x11 0xc00018110x800074 l.nop 0x15000000############################## 第8步 ##############################指令地址 指令 指令对应的二进制0x800078 l.addi r1,r0,0x10 0x9c200010_loop1:0x80007C l.sw 0x0(r1),r1 0xd4010800 0x800080 l.sfeqi r1,0x1C 0xbc01001c0x800084 l.bnf _loop1 0x0ffffffe0x800088 l.addi r1,r1,0x4 0x9c210004############################## 第9步 ##############################指令地址 指令 指令对应的二进制0x80008C l.addi r1,r0,0x0 0x9c200000_loop2:0x800090 l.lwz r2,0x0(r1) 0x84410000 0x800094 l.sfeqi r1,0xC 0xbc01000c0x800098 l.bnf _loop2 0x0ffffffe0x80009C l.addi r1,r1,0x4 0x9c210004############################## 第10步 ##############################指令地址 指令 指令对应的二进制0x8000A0 l.addi r3,r0,0xF 0x9c60000f0x8000A4 l.sw 0x0(r0),r3 0xd4001800 ############################## 第11步 ##############################指令地址 指令 指令对应的二进制0x8000A8 l.mtspr r0,r0,0x1804 0xc0600004 ############################## 第12步 ##############################指令地址 指令 指令对应的二进制0x8000AC l.addi r3,r0,0xFF 0x9c6000ff0x8000B0 l.sw 0x0(r0),r3 0xd4001800 ############################## 第13步 ##############################指令地址 指令 指令对应的二进制0x8000B4 l.mtspr r0,r0,0x1802 0xc0600002 ############################## 第14步 ##############################指令地址 指令 指令对应的二进制0x8000B8 l.ori r3,r0,0x03C2 0xa86003c20x8000BC l.mtspr r0,r3,0x0A80 0xc0201a80 ############################## 第15步 ##############################指令地址 指令 指令对应的二进制0x8000C0 l.addi r3,r0,0x55 0x9c6000550x8000C4 l.sw 0x0(r0),r3 0xd4001800 0x8000C8 l.lwz r2,0x0(r0) 0x84400000
不注释掉or1200_defines.v中的宏定义OR1200_DC_WRITETHROUGH表示当前使用的是通写法,反之,表示当前使用的是回写法,分别在这两种策略下使用ModelSim仿真得到仿真结果,在后面针对具体情况分析时会给出仿真结果,本节只是讨论DCache对处理器执行效率的影响,如图13.5所示,这是第5步中在没有使用DCache时加载指令的执行过程,从中可知此时加载指令在流水线的执行阶段需要很多个时钟周期,这是因为DCache没有使能,所以会直接从RAM读取,由于等待RAM读取结束,所以lsu_stall为1(参考加载存储类指令的分析过程),lsu_stall为1又使得xx_freeze为1,从而流水线暂停,直到RAM完成了读取操作,lsu_stall、xx_freeze恢复为0,流水线继续运行。图13.6是第9步中使能DCache且DCache命中情况下加载指令的执行过程,从中可知此时加载指令在流水线执行阶段需要的时钟周期数减少了许多,这是由于直接从DCache中读取数据,减少了读取所需的时间。
本书光盘的Chapter13目录下包括ModelSim仿真工程,Chapter13/Code目录下包括示例程序源代码。本章后续部分将借助该程序分析DCache在各种使用情景下的工作过程。