or1200中IMMU分析(再续)

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

ITLB代码分析

ITLB是IMMU中的主要模块,其实现也相对独立、简单。本节对ITLB的代码进行分析。ITLB的输入输出接口如图10.10所示,图中左边是输入接口,右边是输出接口。

因为在ITLB中实现了第2组特殊寄存器,所以有spr_cs、spr_write、spr_addr、spr_dat_i、spr_dat_o等接口,这些接口的含义在分析特殊寄存器类指令的时候已经学习过,应该是非常熟悉的。剩下的输入输出接口含义如下:

  • tlb_en:输入的ITLB使能信号
  • vaddr:输入的有效地址
  • hit:表示ITLB是否命中
  • ppn:如果命中,那么ppn输出物理地址的13-31位
  • uxe:如果命中,那么uxe就是TR_RAM表中uxe属性位的值
  • sxe:如果命中,那么sxe就是TR_RAM表中sxe属性位的值
  • ci:如果命中,那么ci就是TR_RAM表中ci属性位的值

ITLB内部有MR_RAM、TR_RAM两个表,这两个表都是通过单口RAM实现的,单口RAM的代码如下:

or1200_spram.v
module or1200_spram  (   clk, ce, we, addr, di, doq   );

   parameter aw = 10;                           //地址线、数据线的宽度都可配置
   parameter dw = 32;

   input 				  clk;	               //时钟输入
   input 				  ce;	               //片选信号
   input 				  we;	               //写使能信号
   input [aw-1:0] 		  addr;	               //输入地址
   input [dw-1:0] 		  di;	               //输入数据
   output [dw-1:0] 	  doq;	               //输出数据

   reg [dw-1:0] 			  mem [(1<<aw)-1:0]
   reg [aw-1:0] 			  addr_reg;		 //地址寄存器

   // Data output drivers
  assign doq = mem[addr_reg];                   //输出数据

   //
  always @(posedge clk)
     if (ce)
       addr_reg <=  addr;                       //寄存地址变量到addr_reg

   //
  always @(posedge clk)
     if (we && ce)
       mem[addr] <=  di;                        //写入RAM

endmodule // or1200_spram

代码很明了,就是使用数组实现了一个RAM,FPGA综合工具会自动选择芯片的存储单元实现这个RAM。在ITLB中例化了两个单口RAM,分别作为MR_RAM表、TR_RAM表。MR_RAM表的表项对应ITLBW0MRx寄存器,TR_RAM表的表项对应ITLBW0TRx寄存器。在五种情况下会使用到ITLB:

(1)地址翻译

(2)使用指令l.mfspr读取ITLBW0MRx

(3)使用指令l.mfspr读取ITLBW0TRx

(4)使用指令l.mtspr写ITLBW0MRx

(5)使用指令l.mtspr写ITLBW0TRx

读者需要结合这五种情况理解ITLB代码,代码如下(为了便于说明,笔者改变了代码的顺序):

or1200_immu_itlb.v
module or1200_immu_tlb(  clk,  rst,  tlb_en,  vaddr,  hit,  ppn,  uxe,
                         sxe,  ci,   spr_cs,  spr_write,  spr_addr,
                         spr_dat_i,  spr_dat_o
);

parameter dw = `OR1200_OPERAND_WIDTH;
parameter aw = `OR1200_OPERAND_WIDTH;

input				clk;
input				rst;
input				tlb_en;
input	[aw-1:0]		vaddr;
output				hit;
output	[31:`OR1200_IMMU_PS]	ppn;
output				uxe;
output				sxe;
output				ci;
input				spr_cs;
input				spr_write;
input	[31:0]			spr_addr;
input	[31:0]			spr_dat_i;
output	[31:0]			spr_dat_o;

//######################          MR_RAM         #######################
//例化MR_RAM表,因为有64项,所以地址的宽度是6;另外数据宽度是14,在之前已有说明
   or1200_spram #
     (.aw(6),    .dw(14))
   itlb_mr_ram
     ( .clk(clk),   .ce(tlb_mr_en),  .we(tlb_mr_we),   .addr(tlb_index),
      .di(tlb_mr_ram_in),  .doq(tlb_mr_ram_out)  );

//MR_RAM使能的情况有两种:(1)要进行地址翻译,此时tlb_en为1;(2)使用l.mfspr、
//l.mtspr访问ITLBW0MRx寄存器。对于第二种情况的判断条件就是spr_addr[7]是否为0,
//如果为0那么就是ITLBW0MRx寄存器,反之是ITLBW0TRx寄存器
assign tlb_mr_en = tlb_en | (spr_cs & !spr_addr[`OR1200_ITLB_TM_ADDR]);

//如果是使用指令l.mtspr写ITLBW0MRx寄存器,那么tlb_mr_we为1
assign tlb_mr_we = spr_cs & spr_write & !spr_addr[`OR1200_ITLB_TM_ADDR];

//如果是使用指令l.mtspr写ITLBW0MRx寄存器,那么tlb_mr_ram_in就是要写入的值
//可见只取了spr_dat_i的[31:19]、spr_dat_i[0],参考表10.2可知,spr_dat_i[31:19]
//就是有效地址的19-31位,spr_dat_i[0]正是标志位V
assign tlb_mr_ram_in = {spr_dat_i[`OR1200_ITLB_TAG],
                        spr_dat_i[`OR1200_ITLBMR_V_BITS]};

//MR_RAM、TR_RAM的访问地址,分两种情况:(1)要进行地址翻译,此时需要读取的
//MR_RAM、TR_RAM的地址就是提供的有效地址的13-18位,即vaddr[18:13];(2)使用
//指令l.mfspr、l.mtspr访问ITLBW0MRx、ITLBW0TRx寄存器,此时需要读取的MR_RAM、
//TR_RAM的地址就是spr_addr[5:0]
assign tlb_index = spr_cs ? spr_addr[`OR1200_ITLB_INDXW-1:0] :
                            vaddr[`OR1200_ITLB_INDX];

//MR_RAM的输出,将高13bit赋值给vpn,最低bit赋值给v,参考图10.7可以理解
assign {vpn, v} = tlb_mr_ram_out;

//将查询得到的vpn与CPU提供的有效地址的19-31位作比较,如果相等,且v等于1,那么
//ITLB命中,hit为1,反之ITLB失靶,hit为0
assign hit = (vpn == vaddr[`OR1200_ITLB_TAG]) & v;

//#######################          TR_RAM           #########################

//例化TR_RAM表,因为有64项,所以地址的宽度是6;另外数据宽度是22,在之前已说明
or1200_spram #
     (.aw(6),  .dw(22))
  itlb_tr_ram
     (.clk(clk),   ce(tlb_tr_en),   .we(tlb_tr_we),   .addr(tlb_index),
      .di(tlb_tr_ram_in), .doq(tlb_tr_ram_out)  );  

//MR_RAM使能的情况有两种:(1)要进行地址翻译,此时tlb_en为1;(2)使用l.mfspr、
//l.mtspr访问ITLBW0TRx寄存器
assign tlb_tr_en = tlb_en | (spr_cs & spr_addr[`OR1200_ITLB_TM_ADDR]);

//如果是使用指令l.mtspr写ITLBW0TRx寄存器,那么tlb_tr_we为1
assign tlb_tr_we = spr_cs & spr_write & spr_addr[`OR1200_ITLB_TM_ADDR];

//如果是使用指令l.mtspr写ITLBW0TRx寄存器,那么tlb_tr_ram_in就是要写入的值
//可见只取了spr_dat_i的[31:13]、spr_dat_i[7]、spr_dat_i[6]、spr_dat_i[1],
//参考10.3.3节
assign tlb_tr_ram_in = {spr_dat_i[31:`OR1200_IMMU_PS],
                        spr_dat_i[`OR1200_ITLBTR_UXE_BITS],
			                  spr_dat_i[`OR1200_ITLBTR_SXE_BITS],
			                  spr_dat_i[`OR1200_ITLBTR_CI_BITS]};

//TR_RAM的输出,将高19bit赋值给ppn,剩下的3bit分别赋值给uxe、sxe、ci,参考
//图10.7可以理解
assign {ppn, uxe, sxe, ci} = tlb_tr_ram_out;

//###################          读出的特殊寄存器的值        ###############
//如果使用指令l.mfspr读取ITLBW0MRx,实际就是从MR_RAM中对应的地址读出数据,将该
//数据按照ITLBW0MRx的格式变换,作为spr_dat_o的值输出;如果使用指令l.mfspr读取
//ITLBW0TRx,实际就是从TR_RAM中对应的地址读出数据,将该数据按照ITLBW0TRx的格式
//变换,作为spr_dat_o的值输出;
assign spr_dat_o = (!spr_write & !spr_addr[`OR1200_ITLB_TM_ADDR]) ?   //读ITLBW0MRx
                    {vpn, tlb_index, {`OR1200_ITLB_TAGW-7{1'b0}}, 1'b0, 5'b00000, v} :
		               (!spr_write & spr_addr[`OR1200_ITLB_TM_ADDR]) ?    //读ITLBW0TRx
			              {ppn, {`OR1200_IMMU_PS-8{1'b0}}, uxe, sxe, {4{1'b0}}, ci, 1'b0} :32'h00000000;

endmodule

从ITLB的代码可知,ITLB并不判断异常,在IMMU模块中会例化ITLB,同时使用ITLB的输出hit、sxe、uxe判断是否命中或者是否违反页保护策略,这一点会在后面进一步分析。

在IMMU模块内部例化ITLB的代码如下:

or1200_immu_top.v
……
or1200_immu_tlb or1200_immu_tlb(
	.clk(clk),
	.rst(rst),

  .tlb_en(itlb_en),	      .vaddr(icpu_adr_i),
  .hit(itlb_hit),	        .ppn(itlb_ppn),
  .uxe(itlb_uxe),   	    .sxe(itlb_sxe),
  .ci(itlb_ci),           .spr_cs(itlb_spr_access),
  .spr_write(spr_write),	.spr_addr(spr_addr),
  .spr_dat_i(spr_dat_i),	.spr_dat_o(itlb_dat_o)
);

or1200中IMMU分析(再续)

时间: 2024-10-04 18:42:35

or1200中IMMU分析(再续)的相关文章

or1200中IMMU分析(续)

以下内容摘自<步步惊芯--软核处理器内部设计分析>一书 2 IMMU中的特殊寄存器 OR1200处理器中的IMMU包含第2组特殊寄存器,如表10.1所示. ITLBW0MRx是指令TLB匹配寄存器,其格式如表10.2所示. 表10.2是OpenRISC 1000规范中的定义,实际在OR1200处理器中只实现了其中一部分字段,包括VPN(Virtual Page Number)的一部分.V(Valid标志位).ITLBW0MRx对应图10.7中MR_RAM的表项,每一个表项对应一个ITLBW0M

or1200中IMMU分析

以下内容摘自<步步惊芯--软核处理器内部设计分析>一书 1 IMMU结构 OR1200中实现IMMU的文件有or1200_immu_top.v.or1200_immu_tlb.v.or1200_spram.v,其中使用or1200_immu_top.v实现了IMMU模块,使用or1200_immu_tlb.v实现了ITLB模块,or1200_spram.v是一个单口RAM,使用其实现了ITLB的表项.如图10.5所示.本小节将分别介绍IMMU模块与其余模块的连接关系.ITLB结构. 1.1 I

Or1200中IMMU使用举例

以下内容摘自<步步惊芯--软核处理器内部设计分析>一书 5 IMMU使用情景 前几章通过对OR1200处理器中各类指令执行过程的分析,实现了对CPU模块的剖析,本章将采用情景分析法,通过对使用IMMU的各种情景的分析以实现对IMMU模块剖析.使用IMMU的情景有如下几种: (1)使用IMMU进行地址翻译,同时ITLB命中,且没有违反页保护策略 (2)使用IMMU进行地址翻译,但是ITLB未命中 (3)使用IMMU进行地址翻译,虽然ITLB命中,但是违反了页保护策略 (4)l.mtspr指令写特

or1200于IMMU分析

以下摘录<步骤吓得核心--软-core处理器的室内设计与分析>一本书 1 IMMU结构 OR1200中实现IMMU的文件有or1200_immu_top.v.or1200_immu_tlb.v.or1200_spram.v,当中使用or1200_immu_top.v实现了IMMU模块,使用or1200_immu_tlb.v实现了ITLB模块,or1200_spram.v是一个单口RAM.使用事实上现了ITLB的表项.如图10.5所看到的. 本小节将分别介绍IMMU模块与其余模块的连接关系.IT

OR1200中数据Cache的使用情景分析

以下内容摘自<步步惊芯--软核处理器内部设计分析>一书 13.7DCache使用情景之一--存储指令执行阶段DCache失靶 存储指令执行阶段DCache失靶这种情景在通写法.回写法策略下有不同的执行过程,在通写法策略下直接写存储器中对应的地址,不操作DCache.在回写法策略下,首先判断目的地址对应的DCache中目录表的line是否被修改,如果是(Dirty为1),则将该line写回到内存,然后将目的地址所在的内存块读入DCache,填充到对应line,然后再修改DCache中对应目的地址

OR1200中指令Cache的结构

以下内容摘自<步步惊芯--软核处理器内部设计分析>一书 12.3 ICache结构 OR1200中实现ICache的文件有or1200_ic_top.v.or1200_ic_fsm.v.or1200_ic_tag.v.or1200_ic_ram.v.or1200_spram.v,分别实现了ICache模块.IC_FSM模块.IC_TAG模块.IC_RAM模块.单口RAM.在ICache中例化了IC_FSM.IC_TAG.IC_RAM模块,在IC_TAG.IC_RAM模块中例化了单口RAM.如图

Cache基本知识与OR1200中ICache简介

以下内容摘自<步步惊芯--软核处理器内部设计分析>一书 12.1 Cache基本知识 12.1.1 Cache的作用 处理器的设计者一般会声称其设计的处理器一秒钟能做多少次乘法.每条指令只占用xx个时钟周期,可是当我们实际使用处理器时,就会发现并不是那么回事,比如在第11章,从图11.8中可以发现,当程序运行在简单SOPC上时,原先设计在执行阶段只需要一个时钟周期的指令l.movhi却使用了6个时钟周期才完成执行,造成实际情况与设计不符的原因是由于实际情况是一个由多个模块.设备组成的系统,读者

or1200中乘法除法指令说明

以下内容摘自<步步惊芯--软核处理器内部设计分析>一书 OR1200中乘法除法类指令共有9条,表8.3给出了所有的乘法除法类指令的作用及说明. 说明:表8.3是ORBIS32中给出的指令用法,但是通过分析OR1200的代码,发现有些指令并没有按照ORBIS32实现,如:l.mac.l.maci.l.msb,这三条指令有一个共同点就是涉及到乘法结果的低32位与{MACHI,MACLO}的运算,比如l.mac指令需要乘法结果的低32位加上{MACHI,MACLO},但是在OR1200实现中并没有只

or1200中加载存储类指令说明

以下内容摘自<步步惊芯--软核处理器内部设计分析>一书 OR1200中实现的加载存储类指令有8条,每条指令的作用与说明如表9.1所示. 说明一点:在第2章建立的最小系统没有配置使用MMU,所以有效地址等于物理地址. 加载存储类指令的助记符也很好理解记忆,第一位是's'表示存储指令,'l'表示加载指令:第二位是'b'表示对字节操作,'h'表示对半字操作,'w'表示对字操作:第三位是'z'表示零扩展,'s'表示符号扩展.据此可以对指令进行简称,如:l.sb指令可以简称为存储字节指令.l.lwz指令