首页 > 其他 > 详细

or1200处理器的SPRS模块详细分析

时间:2014-04-17 05:15:12      阅读:785      评论:0      收藏:0      [点我收藏+]

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


      前面两节以访问映射到SPR地址空间的通用寄存器为例分别介绍了l.mfspr、l.mtspr指令的一般过程,访问其余特殊寄存器的取指、译码阶段与上述都是一样的,只是执行阶段与特殊寄存器所在模块有关,将在分析具体模块的时候再行分析,但是无论访问哪个模块中的特殊寄存器,都涉及到SPRS模块。SPRS在指令l.mfspr、l.mtspr的执行过程中起一个仲裁器的作用,本节将对SPRS模块进行深入分析。

      在本书光盘的or1200_cpu.vsd、or1200_top.vsd两张图中可以发现有很多模块的输入输出接口的名称是以“spr_”开始的,这是与特殊寄存器访问有关的信号,表示该模块存在特殊寄存器,并且这些信号都连接到SPRS模块, SPRS模块与具有特殊寄存器的模块的连接关系如图5.4所示,这里还是采用模块左边是输入接口,右边是输出接口的绘制方式。SPRS输出片选信号spr_cs、地址信号spr_addr,以及SPR写信号spr_we、要写入的数据spr_dat_o,这四个信号连接到大多数具有SPR的模块,类似于总线。由于页面限制,图5.4没有将所有具有特殊寄存器的模块列出,读者可以在or1200_cpu.vsd、or1200_top.vsd中查看完整的连接关系。图5.4中的CFGR是CPU配置模块,其中实现了OR1200第0组特殊寄存器中的VR、UPC、CPUCFGR、DMMUCFGR、IMMUCFGR、DCCFGR、ICCFGR、DCFGR等寄存器。EXCEPTION是异常模块,其中实现了异常发生时需要的EPCR0、EEAR0、ESR等寄存器,以及NPC、PPC寄存器。IMMU模块是指令MMU,其中实现了与IMMU有关的寄存器。其余的DMMU、PIC、PM、MULTI_MAC、DCache、ICache模块也都分别实现了与自身有关的特殊寄存器。图5.4中显示DCache只有输入接口spr_dat_i,没有输出接口spr_dat_o,这表明DCache中的特殊寄存器不可以读,只能写。IMMU既有输入接口spr_dat_i,又有输出接口spr_dat_i,这表明IMMU中有可以读的SPR,也有可以写的SPR。


bubuko.com,布布扣

图5.4 SPRS在特殊寄存器访问中起仲裁器的作用


      CTRL模块的输出ex_spr_write、ex_spr_read连接到SPRS的ex_spr_write、ex_spr_read,形成SPR写信号spr_we;OPERAND_MUX模块的输出operand_b连接到SPRS的dat_i,作为要写入的数据spr_dat_o;CTRL模块的输出ex_simm连接到SPRS模块的addrofs,OPERAND_MUX模块的输出operand_a连接到SPRS的addrbase,两者组成要访问的特殊寄存器地址,SPRS依据该地址形成片选信号spr_cs、地址信号spr_addr,被选中的模块执行SPR访问操作:

  •  如果是读SPR,那么被选中的模块将要读取的SPR值送入SPRS的对应输入接口,如:选中IMMU模块,那么IMMU将读出的数据通过spr_dat_immu送入SPRS模块;选中DMMU模块,那么DMMU将读出的数据通过spr_dat_dmmu送入SPRS模块。SPRS模块依据SPR地址选择对应模块的输入,也就是读取到的SPR值,将其通过to_wbmux接口送入WB_MUX模块,最终会将该值写入目的寄存器,从而实现了读特殊寄存器。所以SPRS在特殊寄存器访问类指令的执行过程中起仲裁器的作用。
  •  如果是写SPR,那么被选中的模块会将SPRS的输出spr_dat_o写入其内部的相应地址。

      在SPRS模块中还实现了SR寄存器,所以对SPRS模块代码的分析可以分为两部分进行:特殊寄存器访问控制、SR寄存器。


1、特殊寄存器访问控制

      SPRS模块中特殊寄存器访问控制部分涉及到的代码如下:


or1200_sprs.v
//给出SPR的地址spr_addr、要写入的数据spr_dat_o、SPR写使能信号spr_we、
//此处均不考虑调试单元的影响。所以上述信号的值实际只取决于名称加粗的部分
assign spr_addr = du_access ? du_addr : (addrbase | {16‘h0000, addrofs});
assign spr_dat_o = du_write ? du_dat_du : dat_i;
assign spr_we = du_write | ( ex_spr_write & !du_access );

//依据spr_addr的高5bit,即特殊寄存器所在的组号得到unqualified_cs的值,
//如果特殊寄存器位于第n组,那么//unqualified_cs[n]为1
always @(spr_addr)
     case (spr_addr[`OR1200_SPR_GROUP_BITS])	          
       `OR1200_SPR_GROUP_WIDTH‘d00: unqualified_cs 
	 = 32‘b00000000_00000000_00000000_00000001;
       `OR1200_SPR_GROUP_WIDTH‘d01: unqualified_cs 
	 = 32‘b00000000_00000000_00000000_00000010;
       `OR1200_SPR_GROUP_WIDTH‘d02: unqualified_cs 
	 = 32‘b00000000_00000000_00000000_00000100;
       `OR1200_SPR_GROUP_WIDTH‘d03: unqualified_cs 
	 ……
       `OR1200_SPR_GROUP_WIDTH‘d29: unqualified_cs 
	 = 32‘b00100000_00000000_00000000_00000000;
       `OR1200_SPR_GROUP_WIDTH‘d30: unqualified_cs 
	 = 32‘b01000000_00000000_00000000_00000000;
       `OR1200_SPR_GROUP_WIDTH‘d31: unqualified_cs 
	 = 32‘b10000000_00000000_00000000_00000000;
     endcase

//得到片选信号spr_cs,这里不考虑调试单元的影响,同时注意如果是写SPR,
那么需要SR[SM]为1,也就是处于特权用户模式才可以写SPR,而读SPR没有
//这个要求。当ex_spr_read或者(ex_spr_write & sr[`OR1200_SR_SM])为1时,
//spr_cs就等于unqualified_cs,也就是如果访问的特殊寄存器位于第n组,那么
//spr_cs[n]为1,若第n组寄存器在模块M中,那么spr_cs[n]就输出到模块M的输
//入接口spr_cs,这样就是模块M的片选信号。比如:如果访问IMMU中的寄存器,
//那么spr_cs[2]为1,而IMMU模块的输入接口spr_cs的值就是SPRS模块的输出
// spr_cs[2],此时的值就是1,这样就实现了片选
assign spr_cs = unqualified_cs & {32{du_read | du_write | ex_spr_read | 
                 (ex_spr_write & sr[`OR1200_SR_SM])}};

//在or1200_defines.v中有如下宏定义:
//`define OR1200_SPR_CFGR	7‘d0     CFGR包括了第0组特殊寄存器中序号在16以下
//                                 的寄存器
//`define OR1200_SPR_RF		6‘d32	   RF中的寄存器地址是从1024开始的,
//                                 所以spr_addr[10:5]应该为32
//`define OR1200_SPR_NPC	11‘d16   NPC的地址是16
//`define OR1200_SPR_SR		11‘d17   SR的地址是17
//`define OR1200_SPR_PPC	11‘d18   PPC的地址是18
//`define OR1200_SPR_FPCSR  11‘d20
//`define OR1200_SPR_EPCR	11‘d32   EPCR0的地址是32
//`define OR1200_SPR_EEAR	11‘d48   EEAR0的地址是48
//`define OR1200_SPR_ESR	11‘d64   ESR的地址是64
//下面代码中OR1200_SPR_GROUP_SYS为0,所以spr_cs[OR1200_SPR_GROUP_SYS]就是
//判断spr_cs的第0位是否为1,即是否选择第0组特殊寄存器。在此基础上依据
//spr_addr的低11位,判断是第0组特殊寄存器中的哪个寄存器。

//cfgr_sel为1表示要访问的是第0组特殊寄存器中序号在16以下的寄存器,
//这些寄存器都在CFGR模块中实现
   assign cfgr_sel = (spr_cs[`OR1200_SPR_GROUP_SYS] && 
                     (spr_addr[10:4] == `OR1200_SPR_CFGR));

//rf_sel为1表示要访问的是RF中的通用寄存器
   assign rf_sel = (spr_cs[`OR1200_SPR_GROUP_SYS] && (
                    spr_addr[10:5] == `OR1200_SPR_RF));

//npc_sel为1表示要访问的是NPC
   assign npc_sel = (spr_cs[`OR1200_SPR_GROUP_SYS] && 
                     (spr_addr[10:0] == `OR1200_SPR_NPC));

//ppc_sel为1表示要访问的是PPC
   assign ppc_sel = (spr_cs[`OR1200_SPR_GROUP_SYS] && 
                      (spr_addr[10:0] == `OR1200_SPR_PPC));

//sr_sel为1表示要访问的是SR
   assign sr_sel = (spr_cs[`OR1200_SPR_GROUP_SYS] && 
                    (spr_addr[10:0] == `OR1200_SPR_SR));

//epcr_sel为1表示要访问的是EPCR0
   assign epcr_sel = (spr_cs[`OR1200_SPR_GROUP_SYS] && 
                      (spr_addr[10:0] == `OR1200_SPR_EPCR));

//eear_sel为1表示要访问的是EEAR0
   assign eear_sel = (spr_cs[`OR1200_SPR_GROUP_SYS] && 
                      (spr_addr[10:0] == `OR1200_SPR_EEAR));

//esr_sel为1表示要访问的是ESR
   assign esr_sel = (spr_cs[`OR1200_SPR_GROUP_SYS] && 
                      (spr_addr[10:0] == `OR1200_SPR_ESR));

//fpcsr_sel为1表示要访问的是FPCSR
   assign fpcsr_sel = (spr_cs[`OR1200_SPR_GROUP_SYS] &&
                       (spr_addr[10:0] == `OR1200_SPR_FPCSR));

//sr_we为1表示需要写SR,发生下面5种情况之一时,会写SR:
//(1)l.mtspr指令写SR;
//(2)异常返回指令l.rfe执行时,该指令会将保存的在ESR中的值写到SR;
//(3)指令执行需要写F位;
//(4)指令执行需要写CY位;
//(5)指令执行需要写OV位
   assign sr_we = (spr_we && sr_sel) | 
                  (branch_op == `OR1200_BRANCHOP_RFE) | 
                   flag_we | 
                   cy_we | 
                   ov_we;

//pc_we为1,表示需要写NPC或PPC
   assign pc_we = (du_write && (npc_sel | ppc_sel));

//epcr_we为1,表示需要写EPCR0
   assign epcr_we = (spr_we && epcr_sel);

//eear_we为1,表示需要写EEAR0
   assign eear_we = (spr_we && eear_sel);

//esr_we为1,表示需要写ESR
   assign esr_we = (spr_we && esr_sel);

//fpcsr_we为1,表示需要写FPCSR
   assign fpcsr_we = (spr_we && fpcsr_sel);

//sys_data是读取到的第0组寄存器中某个寄存器的值,
//此处依据不同的xxx_sel,选择不同的输入赋值给sys_data
   assign sys_data = (spr_dat_cfgr & {32{cfgr_sel}}) | 
(spr_dat_rf & {32{rf_sel}}) |
		            (spr_dat_npc & {32{npc_sel}}) | 
 (spr_dat_ppc & {32{ppc_sel}}) |
		            ({{32-`OR1200_SR_WIDTH{1‘b0}},sr} & {32{sr_sel}}) | 
(epcr & {32{epcr_sel}}) |
		            (eear & {32{eear_sel}}) | 
({{32-`OR1200_FPCSR_WIDTH{1‘b0}},fpcsr} & {32{fpcsr_sel}}) |
		            ({{32-`OR1200_SR_WIDTH{1‘b0}},esr} & {32{esr_sel}});

//to_wbmux输出到WB_MUX中,作为指令l.mfspr要写入目的寄存器的数据,
//此处依据要读取的SPR所在的组号,选择相应的输入数据赋值给to_wbmux,
//该输入数据就是读入的SPR的值,比如:读取IMMU中的寄存器时,位于第2组,
//所以spr_addr[`OR1200_SPR_GROUP_BITS]等于2,也就是OR1200_SPR_GROUP_IMMU,
//从而to_wbmux等于spr_dat_IMMU,其中spr_dat_IMMU来自IMMU模块的
//输出信号spr_dat_o
   always @(spr_addr or sys_data or spr_dat_mac or spr_dat_pic or spr_dat_pm 
       or spr_dat_fpu or
	    spr_dat_dmmu or spr_dat_immu or spr_dat_du or spr_dat_tt) begin
    casez (spr_addr[`OR1200_SPR_GROUP_BITS])
	`OR1200_SPR_GROUP_SYS:        // `define OR1200_SPR_GROUP_SYS	5‘d00
	  to_wbmux = sys_data;
	`OR1200_SPR_GROUP_TT:        // `define OR1200_SPR_GROUP_TT	5‘d10
	  to_wbmux = spr_dat_tt;
	`OR1200_SPR_GROUP_PIC:       // `define OR1200_SPR_GROUP_PIC	5‘d09
	  to_wbmux = spr_dat_pic;
	`OR1200_SPR_GROUP_PM:        // `define OR1200_SPR_GROUP_PM	5‘d08
	  to_wbmux = spr_dat_pm;
	`OR1200_SPR_GROUP_DMMU:     // `define OR1200_SPR_GROUP_DMMU	5‘d01
	  to_wbmux = spr_dat_dmmu;
	`OR1200_SPR_GROUP_IMMU:      // `define OR1200_SPR_GROUP_IMMU	5‘d02
	  to_wbmux = spr_dat_immu;
	`OR1200_SPR_GROUP_MAC:      // `define OR1200_SPR_GROUP_MAC	5‘d05
	  to_wbmux = spr_dat_mac;
	`OR1200_SPR_GROUP_FPU:      //`define OR1200_SPR_GROUP_FPU    5‘d11
	  to_wbmux = spr_dat_fpu;
	default: //`OR1200_SPR_GROUP_DU: // `define OR1200_SPR_GROUP_DU	5‘d06
	  to_wbmux = spr_dat_du;
      endcase
   end

2、SR寄存器

      SPRS模块中涉及到SR寄存器实现的代码如下:


or1200_sprs.v
//在or1200_defines.v中有如下定义:
//`define OR1200_SR_WIDTH 17    SR寄存器有用的bit宽度,只使用低17bit
//`define OR1200_SR_SM   0      下面的宏定义均是SR中的标志位
//`define OR1200_SR_TEE  1
//`define OR1200_SR_IEE  2
//`define OR1200_SR_DCE  3
//`define OR1200_SR_ICE  4
//`define OR1200_SR_DME  5
//`define OR1200_SR_IME  6
//`define OR1200_SR_LEE  7
//`define OR1200_SR_CE   8
//`define OR1200_SR_F    9
//`define OR1200_SR_CY   10	// Optional
//`define OR1200_SR_OV   11	// Optional
//`define OR1200_SR_OVE  12	// Optional
//`define OR1200_SR_DSX  13	// Unused
//`define OR1200_SR_EPH  14
//`define OR1200_SR_FO   15
//`define OR1200_SR_TED  16       // OR1200_SR_RED就是SR定义中的SUMRA位
//`define OR1200_SR_CID  31:28	// Unimplemented

//写SR,下面几个表达式决定了SR中低17bit的值,基本都是相同的:
//(1)except_started为1表示异常发生,那么对于一些需要改变的bit,
//     按照异常发生时的要求去变化,其他bit不需要变化;
//(2)branch_op等于`OR1200_BRANCHOP_RFE表示从异常返回,那么将esr
//     中对应的bit赋值给to_sr中对应的bit;
//(3)spr_we && sr_sel等于1表示是写sr,那么将要写的值赋值给to_sr;
//(4)cy_we、ov_we、flag_we为1分别表示写CY、OV,F这三个bit;
//(5)如果都不是,那么将sr赋值给to_sr

//异常发生时,设置OR1200_SR_OVE为0;如果是写SR,那么需要单独将第15位设置为1
   assign to_sr[`OR1200_SR_FO:`OR1200_SR_OVE] 
	    = (except_started) ? {sr[`OR1200_SR_FO:`OR1200_SR_DSX],1‘b0}:
	      (branch_op == `OR1200_BRANCHOP_RFE) ? 
	       esr[`OR1200_SR_FO:`OR1200_SR_OVE] : (spr_we && sr_sel) ? 
         {1‘b1, spr_dat_o[`OR1200_SR_FO-1:`OR1200_SR_OVE]} :
	      sr[`OR1200_SR_FO:`OR1200_SR_OVE];

//异常发生时设置OR1200_SR_TED为1
   assign to_sr[`OR1200_SR_TED] 
	    = (except_started) ? 1‘b1 :
	      (branch_op == `OR1200_BRANCHOP_RFE) ? esr[`OR1200_SR_TED] :
	      (spr_we && sr_sel) ? spr_dat_o[`OR1200_SR_TED] :
	      sr[`OR1200_SR_TED];

//依据运算情况,可以单独写SR的OV位
   assign to_sr[`OR1200_SR_OV] 
	    = (except_started) ? sr[`OR1200_SR_OV] :
	      (branch_op == `OR1200_BRANCHOP_RFE) ? esr[`OR1200_SR_OV] :
	      ov_we ? ovforw :
	      (spr_we && sr_sel) ? spr_dat_o[`OR1200_SR_OV] :
	      sr[`OR1200_SR_OV];

//依据运算情况,可以单独写SR的CY位
   assign to_sr[`OR1200_SR_CY] 
	    = (except_started) ? sr[`OR1200_SR_CY] :
	      (branch_op == `OR1200_BRANCHOP_RFE) ? esr[`OR1200_SR_CY] :
	      cy_we ? cyforw :
	      (spr_we && sr_sel) ? spr_dat_o[`OR1200_SR_CY] :
	      sr[`OR1200_SR_CY];

//依据运算情况,可以单独写SR的F位
   assign to_sr[`OR1200_SR_F] 
	    = (except_started) ? sr[`OR1200_SR_F] :
	      (branch_op == `OR1200_BRANCHOP_RFE) ? esr[`OR1200_SR_F] :
	      flag_we ? flagforw :
	      (spr_we && sr_sel) ? spr_dat_o[`OR1200_SR_F] :
	      sr[`OR1200_SR_F];

//异常发生时设置SR[DME]、SR[IME]、SR[IEE]、SR[TEE]为0,分别表示禁用DMMU、
//禁用IMMU、外部中断禁止、计时器中//断禁止,此外还要设置SR[SM]为1,
//表示进入特权模式。
   assign to_sr[`OR1200_SR_CE:`OR1200_SR_SM] 
	    = (except_started) ? {sr[`OR1200_SR_CE:`OR1200_SR_LEE], 2‘b00, 
				  sr[`OR1200_SR_ICE:`OR1200_SR_DCE], 3‘b001} :
	      (branch_op == `OR1200_BRANCHOP_RFE) ? 
	      esr[`OR1200_SR_CE:`OR1200_SR_SM] : (spr_we && sr_sel) ? 
	      spr_dat_o[`OR1200_SR_CE:`OR1200_SR_SM] :
	      sr[`OR1200_SR_CE:`OR1200_SR_SM];

//SPRS模块的输出,分别是SR的F、CY位
   assign flag = sr[`OR1200_SR_F];
   assign carry = sr[`OR1200_SR_CY];

//复位的时候sr_reg设置中三个位置要注意:(1)第15位固定为1;(2)第14位
//是OR1200_SR_EPH_DEF的值,该值在or1200_defines.v中定义,EPH是
//Exception Prefix High的简称,为0时表示异常处理例程入口地址从0x0处开始,
//反之从0xF0000000处开始,默认为0;(3)第0位设置为1,表示处于特权用户模式。
   always @(posedge clk or `OR1200_RST_EVENT rst)
     if (rst == `OR1200_RST_VALUE)
       sr_reg <=  {2‘b01,`OR1200_SR_EPH_DEF, {`OR1200_SR_WIDTH-4{1‘b0}}, 1‘b1};
     else if (except_started)
       //异常发生时或者要写SR时,都会将to_sr赋值给sr_reg
       sr_reg <=  to_sr[`OR1200_SR_WIDTH-1:0]; 
     else if (sr_we)
       sr_reg <=  to_sr[`OR1200_SR_WIDTH-1:0];

//下面的代码设置sr_reg_bit_eph_muxed的值,该值就是SR[EPH]的值,其含义上文已述
   always @(posedge clk or `OR1200_RST_EVENT rst)
        if (rst == `OR1200_RST_VALUE) begin
          //宏定义OR1200_SR_EPH_DEF为0
	        sr_reg_bit_eph <=  `OR1200_SR_EPH_DEF;     
          sr_reg_bit_eph_select <=  1‘b1;	
     end
        else if (sr_reg_bit_eph_select) begin
          //boot_adr_sel_i就是OR1200_SR_EPH_DEF的值,为0
		      sr_reg_bit_eph <=  boot_adr_sel_i;    
	        sr_reg_bit_eph_select <=  1‘b0;
     end
     else if (sr_we) begin
          //如果是写SR,那么可能会改变sr_reg_bit_eph的值
	        sr_reg_bit_eph <=  to_sr[`OR1200_SR_EPH];  
     end

// sr_reg_bit_eph_select自复位后就一直为0,所以在正常运行的时候
//sr_reg_bit_eph_muxed等于sr_reg_bit_eph
   assign	sr_reg_bit_eph_muxed = (sr_reg_bit_eph_select) ? 
                                      boot_adr_sel_i : sr_reg_bit_eph;

//将sr_reg的值赋值给SR,其中SR[EPH]的值来自sr_reg_bit_eph_muxed
   always @(sr_reg or sr_reg_bit_eph_muxed)
     sr = {sr_reg[`OR1200_SR_WIDTH-1:`OR1200_SR_WIDTH-2], 
           sr_reg_bit_eph_muxed,
	         sr_reg[`OR1200_SR_WIDTH-4:0]};





or1200处理器的SPRS模块详细分析,布布扣,bubuko.com

or1200处理器的SPRS模块详细分析

原文:http://blog.csdn.net/leishangwen/article/details/23837671

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!