以下内容摘自《步步惊芯——软核处理器内部设计分析》一书
前面两节以访问映射到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。
图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