码迷,mamicode.com
首页 > 其他好文 > 详细

OR1200数据Cache介绍

时间:2014-06-22 20:20:42      阅读:353      评论:0      收藏:0      [点我收藏+]

标签:or1200 软核处理器   cache   处理器   软核   or1200 openrisc 软核处理   

以下内容摘自《步步惊芯——软核处理器内部设计分析》一书

 

上一章剖析了ICache模块。本章将剖析DCache模块,首先指出DCache模块相比ICache的特别之处,因为这些不同,所以DCache的分析相对复杂。接着分析了OR1200DCache的结构,给出了构成DCache的四个模块的关系,将这四个模块分为数据部分、控制部分,介绍了数据部分的工作过程。13.3节说明了DCache中特殊寄存器的作用与格式。13.4节指出使用到DCache7种情景,13.5节给出一个示例程序,其中涉及了DCache的大部分使用情景,之后,重点分析了在其中3种情景下DCache的工作过程。

13.1 DCache的特别之处

      DCache中缓存的是数据,而ICache中缓存的是指令,这就是DCacheICache的根本区别,由此也决定了DCache的特别之处。指令存储在指令存储器中,且指令存储器是只读的,对应只有一个取指操作,但是数据存储在数据存储器中,且数据存储器是可读、可写的,对应加载、存储两个操作。一般情况下,指令存储器、数据存储器都属于内存的一部分,有时就是内存中同样的地址空间。

      当向数据存储器中存储数据且DCache命中时,称之为写命中,可以采用两种策略:

  •   通写法(Write through):不仅把数据写入DCache中相应的块,而且也写入数据存储器中相应的块。
  •   回写法(Write back):只把数据写入DCache中相应的块,并不会立即更新数据存储器中的内容,而是等到DCache中相应的块因为某种原因需要从DCache中移出时,才更新数据存储器中的内容。

      通写法与回写法各有特点,回写法的优点是速度快,写操作能以DCache的速度进行,而且对于同一个内存块的多次写操作只需最后进行一次内存写操作,通写法的优点是易于实现,而且内存与DCache的数据总是保持一致。

      当向数据存储器中存储数据且DCache失靶时,称之为写不命中,也可以采用两种策略:

  •   按写分配法(Write allocate):先把要写数据所在的存储块调入DCache,然后再进行写入。
  •   不按写分配法(no-Write allocate):直接写数据存储器中的目的地址,而不将要写数据所在的存储块调入DCache

      一般采用通写法时使用不按写分配法,采用回写法时使用按写分配法。在OR1200中可以配置DCache使用通写法还是回写法,采用通写法时就与不按写分配法结合使用,采用回写法时就与按写分配法结合使用,所以后面在分析的时候只是说明通写法、回写法,而不再说明按写分配法、不按写分配法。

or1200_defines.v
//不注释下面的宏定义,就是采用“通写法+不按写分配法”,
//注释掉下面的宏定义,就是采用“回写法+按写分配法”
`define OR1200_DC_WRITETHROUGH


      OR1200中关于DCache的宏定义如下,从中可知,DCache能够配置为512B4KB8KB16KB32KB,默认是8KB,本章采用默认配置,后面分析时不再重复说明。此时内存块的大小是16字节,采用直接映射,DCache目录表有512 line,因此使用地址的4-12bit作为DCache目录表的查找索引。

or1200_defines.v
//`define OR1200_NO_DC            //是否有DCache,默认是注释掉,也就是有DCache

//`define OR1200_DC_1W_4KB
`define OR1200_DC_1W_8KB
//`define OR1200_DC_1W_16KB
//`define OR1200_DC_1W_32KB

`ifdef OR1200_DC_1W_32KB
 `define OR1200_DCLS		5         //如果DCache配置为32KB,则内存块的大小是32字节
`else
 `define OR1200_DCLS		4         //否则都是16字节
`endif

`define OR1200_SPRGRP_DC_ADR_WIDTH 3         //特殊寄存器对应索引的宽度

//特殊寄存器DCBFR在第3组特殊寄存器中的索引是2
`define OR1200_SPRGRP_DC_DCBFR		3'd2           

//特殊寄存器DCBIR在第3组特殊寄存器中的索引是3  
`define OR1200_SPRGRP_DC_DCBIR		3'd3             

//特殊寄存器DCBWR在第3组特殊寄存器中的索引是4
`define OR1200_SPRGRP_DC_DCBWR		3'd4             

`ifdef OR1200_DC_1W_8KB          //如果配置DCache为8KB,那么一些宏定义如下
`define OR1200_DCSIZE			13   //DCache是8KB,所以地址宽度是13

`define OR1200_DCINDX			`OR1200_DCSIZE-2	     // 11
`define OR1200_DCINDXH			`OR1200_DCSIZE-1	   // 12
`define OR1200_DCTAGL			`OR1200_DCINDXH+1	     // 13

//13位地址中的高9位是DCache目录表的索引
`define	OR1200_DCTAG			`OR1200_DCSIZE-`OR1200_DCLS	

//标识的宽度,包括地址的高19位、有效标志位V
`define	OR1200_DCTAG_W			20                     

`endif

13.2 DCache结构

      与ICache对应,OR1200中实现DCache的文件有or1200_dc_top.vor1200_dc_fsm.vor1200_dc_tag.vor1200_dc_ram.vor1200_spram.vor1200_spram_32_bw.v,分别实现了DCache模块、DC_FSM模块、DC_TAG模块、DC_RAM模块、单口RAM、可按字节写的单口RAM模块。在DCache中例化了DC_FSMDC_TAGDC_RAM模块,在DC_TAG模块中例化了单口RAM,在DC_RAM模块中例化了可按字节写的单口RAM。如图13.1所示。其中DC_TAGDC_RAM可以称为数据部分,DC_FSM可以称为控制部分,在数据部分进行查找操作,将查找结果(DCache命中或失靶)送到控制部分,由控制部分依据查找结果进行下一步的操作,如果是写操作,那么下一步的操作还需参考当前配置的写策略。本节将介绍DCache中的数据部分、控制部分。

bubuko.com,布布扣

13.2.1 DCache模块与其余模块的连接关系

      在介绍DCache数据部分、控制部分之前,先给出DCache模块与其余模块之间的连接关系,有助于后面的分析。在第3章介绍QMEM时,已经给出了DCacheQMEMSB之间的连接关系,从中可知DCache与两者之间都是通过Wishbone总线接口连接的,参考本书光盘中的or1200_top.vsd可以得到DCache模块完整的对外连接关系,如图13.2所示。

bubuko.com,布布扣

      有以下几点说明:

      (1)从图中可知DCache除了具有Wishbone总线接口外还具有特殊寄存器访问接口:spr_csspr_writespr_dat_i,与ICache一样,这说明DCache中有特殊寄存器,但是该特殊寄存器不可以读(没有spr_dat_o接口),只能写(有spr_dat_i接口),与ICache不同之处在于DCache还有spr_addr接口,说明DCache中的特殊寄存器是有地址要求的,也就是有索引,而在ICache中只有一个特殊寄存器,所以其索引可以任意,参考表12.1

      (2)相比CPUICache之间的接口,CPUDCache之间还增加了dc_no_writethroughmtspr_dc_done两个接口,其作用会在后面的分析中介绍。

      (3QMEM的输出中有接口dcqmem_ci_o,该信号实际直接来自DMMU,回忆一下DTLB中每个表项都有一个标志位CI,表示对应的页是否可以被缓存,通过QMEMdcqmem_ci_o输出到DCache中,如果要访问一个内存块的内容,但是该内存块所在页的dcqmem_ci_o值为1,那么该内存块是不可能在DCache中,无需查找DCache,直接从内存中访问,反之,如果dcqmem_ci_o的值为0,还要首先在DCache中进行查找。

      (4)相比QMEMICache之间的Wishbone总线接口,QMEMDCache之间的Wishbone总线接口多了两个输入dcqmem_dat_idcqmem_we_i,这是与存储操作有关的接口信号。

      (5DCache并没有与WB_BIU模块直接连接,而是在DCacheWB_BIU之间放置了一个SBStore Buffer)模块,后者与DCache之间的接口也符合Wishbone总线规范,该模块的作用将在下一章分析。

     (6DCacheSB之间的接口名称都是dcsb_xxx_x的形式,DCacheQMEM之间的接口名称都是dcqmem_xxx_x的形式,因此通过名称就可以知道这个接口的位置。

13.2.2 DCache中数据部分

      DCache的数据部分包括DC_TAGDC_RAM,其主体分别是单口RAM、可按字节写的单口RAM。两者共同组成了图12.2中的目录表。查找方法如图13.3所示。

bubuko.com,布布扣

      此处采用的是OR1200默认的DCache设置,即总容量是8KB,内存块大小为16字节,目录表有512 line。图13.3的解释请参考对ICache中数据部分的解释,需要注意一点:DC_TAG每个表项包含标识、VDirty,比IC_TAG多了一个Dirty标志位,该位为1表示当前line对应的缓存数据被修改了但是对应内存块没有修改,也就是缓存与内存不一致,反之表示line对应的缓存与内存一致。参考通写法、回写法的定义可知:只有在使用回写法策略时,才可能存在Dirty1的情况,在使用通写法策略时,Dirty标志位始终为0

      DC_TAG是通过单口RAM实现的,其主要代码如下,注意一点:其数据宽度是21,比ICache中的IC_TAG多了一位用来保存Dirty的值。

or1200_dc_tag.v
module or1200_dc_tag(                        //DC_TAG

	clk, rst,	addr, en, we, datain, tag_v, tag, dirty
);
……

//OR1200_DCTAG_W为20,所以dw为21,增加的1位是Dirty位
parameter dw = `OR1200_DCTAG_W + 1;       

//地址宽度为9        
parameter aw = `OR1200_DCTAG;                     

or1200_spram #                 //例化单口RAM
     (   .aw(`OR1200_DCTAG),      .dw(`OR1200_DCTAG_W + 1)  )
   
   //从单口RAM中读出的数据doq包括标识、有效位V、是否修改位Dirty
   dc_tag0                    
     (   .clk(clk),    .ce(en),    .we(we),    .addr(addr),    
         .di(datain),  .doq({tag, tag_v, dirty})   );
                                       
endmodule 


 

      DC_RAM也是通过单口RAM实现的,但是可按字节写的单口RAM,回忆一下OR1200中的存储指令l.sbl.sh,都是只修改一个字中的一部分,所以需要这样设计。DC_RAM的主要代码如下:

or1200_dc_ram.v
module or1200_dc_ram(                       //DC_RAM
	clk, rst,	addr, en, we, datain, dataout
);

parameter dw = `OR1200_OPERAND_WIDTH;              //数据宽度是32bit
parameter aw = `OR1200_DCINDX;                     //地址宽度是11
……
   or1200_spram_32_bw #             //例化单口RAM,此处的单口RAM可以按字节写
     (    .aw(`OR1200_DCINDX),  .dw(dw)   )
   dc_ram                                          //注意变量we的宽度为4
     (    .clk(clk),      .ce(en),    .we(we),    .addr(addr),    
          .di(datain),    .doq(dataout)   );
endmodule 


 

      其中可以按字节写的单口RAM是使用48bit宽度的数组实现的,主要代码如下:

or1200_spram_32_bw.v
module or1200_spram_32_bw  (   clk, ce, we, addr, di, doq   );
  
   parameter aw = 10;
   parameter dw = 32;                        //数据宽度是32
   
   ……
   input [3:0]				  we;	   // 注意此处的写使能信号we的宽度是4
 
   reg [7:0] 				  mem0 [(1<<aw)-1:0];    //定义了4个8位数组
   reg [7:0] 				  mem1 [(1<<aw)-1:0];
   reg [7:0] 				  mem2 [(1<<aw)-1:0];
   reg [7:0] 				  mem3 [(1<<aw)-1:0];
   ……
   
   //分别从4个8位数组中读出对应的数据组成一个//32位的数作为要读取的数
   assign doq = {mem0[addr_reg], mem1[addr_reg], mem2[addr_reg], mem3[addr_reg]};
                                                              
   always @(posedge clk)
     if (ce)
       addr_reg <=  addr;                     //寄存地址信号
   
   always @(posedge clk)
     if (ce) begin
       if (we[3])                   //如果we[3]为1表示要写目的地址的最高位字节
         mem0[addr] <=  di[31:24];
       if (we[2])                   //如果we[2]为1表示要写目的地址的次高位字节
         mem1[addr] <=  di[23:16];
       if (we[1])                   //如果we[1]为1表示要写目的地址的次低位字节
         mem2[addr] <=  di[15:08];
       if (we[0])                   //如果we[0]为1表示要写目的地址的最低位字节
         mem3[addr] <=  di[07:00];
     end
   
endmodule // or1200_spram


 

13.2.3 DCache中控制部分

      DCache会依据DC_RAMDC_TAG的查找结果,以及当前的写策略决定下一步的操作。DCache中的控制部分主要在DC_FSM模块中实现,其主体是一个状态机,有IDLECLOADSTORELOOP2LOOP3LOOP4FLUSH5INV6WAITSPRCS78个状态,定义如下:

or1200_fsm.v
`define OR1200_DCFSM_IDLE	3'd0
`define OR1200_DCFSM_CLOADSTORE	3'd1
`define OR1200_DCFSM_LOOP2	3'd2
`define OR1200_DCFSM_LOOP3	3'd3
`define OR1200_DCFSM_LOOP4	3'd4
`define OR1200_DCFSM_FLUSH5	3'd5
`define OR1200_DCFSM_INV6	3'd6
`define OR1200_DCFSM_WAITSPRCS7	3'd7


 

      由于有两种写策略,在不同的写策略下,DCache有不同的工作过程,状态转换也不同,比较复杂,所以本章将在分析DCache过程中逐步给出状态之间转换关系。

13.2.4 DCache数据部分与控制部分的对外接口

      DC_FSMDC_TAGDC_RAM模块都在DCache中例化,例化语句如下:

or1200_dc_top.v
……
or1200_dc_fsm or1200_dc_fsm(                       //例化DC_FSM
	.clk(clk),         
	.rst(rst),          
	.dc_en(dc_en),            
	.dcqmem_cycstb_i(dcqmem_cycstb_i),
         .dirty(dirty),     
         .tag(tag),         
         .tag_v(tag_v),             
         .dcqmem_ci_i(dcqmem_ci_i),
         .burst(dcfsm_burst),         
         .tag_we(dcfsm_tag_we),              
         .dc_addr(dc_addr),
         .dcqmem_we_i(dcqmem_we_i),	 
         .dcqmem_sel_i(dcqmem_sel_i),        
         .tagcomp_miss(tagcomp_miss),
	.biudata_valid(dcsb_ack_i),	 
	.biudata_error(dcsb_err_i),  	    
	.lsu_addr(dcqmem_adr_i),
	.dcram_we(dcram_we),	      
	.biu_read(dcfsm_biu_read), 	    
	.biu_write(dcfsm_biu_write),
	.dcram_di_sel(dcfsm_dcram_di_sel),	     
	.biu_do_sel(dcfsm_biu_do_sel),
	.first_hit_ack(dcfsm_first_hit_ack),  	
	.first_miss_ack(dcfsm_first_miss_ack),
	.first_miss_err(dcfsm_first_miss_err),    
	.dc_no_writethrough(dc_no_writethrough),
         .tag_valid(dcfsm_tag_valid),	         
         .tag_dirty(dcfsm_tag_dirty),	
         .dc_block_flush(dc_block_flush),         
         .mtspr_dc_done(mtspr_dc_done),
	.dc_block_writeback(dc_block_writeback),	
	.spr_dat_i(spr_dat_i),	
	.spr_cswe(spr_cs & spr_write)
);

or1200_dc_ram or1200_dc_ram(                      //例化DC_RAM
	.clk(clk),	
	.rst(rst),
	.addr(dc_addr[`OR1200_DCINDXH:2]),	
	.en(dc_en),	
	.we(dcram_we),
	.datain(to_dcram),    	
	.dataout(from_dcram)
);

or1200_dc_tag or1200_dc_tag(                       //例化DC_TAG
	.clk(clk),	
	.rst(rst),
	.addr(dctag_addr),	
	.en(dctag_en),	
	.we(dctag_we),    
	.tag_v(tag_v),	
	.tag(tag),   
	.dirty(dirty)
	.datain({dc_addr[31:`OR1200_DCTAGL], dctag_v, dctag_dirty}),
);
……

      参考上述例化语句得到图13.4,其中给出了DC_FSMDC_TAGDC_RAM模块的接口,以及各个接口连接到DCache的对应变量,每个模块的左边是输入接口,右边是输出接口,每个模块内部是接口名,外部引脚上的名称代表DCache中的对应变量。本章在后面分析DCache时需要经常参考该图,各个接口的含义也留在使用到该接口的时候再作说明。

bubuko.com,布布扣


 

 

 

 

 

 

 


 

 

OR1200数据Cache介绍,布布扣,bubuko.com

OR1200数据Cache介绍

标签:or1200 软核处理器   cache   处理器   软核   or1200 openrisc 软核处理   

原文地址:http://blog.csdn.net/leishangwen/article/details/32108443

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!