以下内容摘自《步步惊芯——软核处理器内部设计分析》一书
前面两节以访问映射到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访问操作:
在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
原文:http://blog.csdn.net/leishangwen/article/details/23837671