OpenRisc-45-or1200的ID模块分析
引言
之前,我们分析了or1200流水线的整体结构,也分析了流水线中IF级,EX级,本小节我们来分析ID(insn decode)级的一些细节。
1,基础
or1200的pipeline的ID阶段包含一个模块,就是ctrl模块,其对应的文件是or1200_ctrl.v。ID,就是instruction decode,顾名思义,其主要任务就是对从IF阶段取得的指令进行解析,产生各种控制信号。
在分析本模块之前,我们有必要先了解几个相关的概念,这对后面的RTL的分析会有很大帮助。
1>forwording & bypassing
forwording(前递) 和 bypassing(旁路)技术,是现在流水线中非常常见的技术,其作用主要是消除由于数据相关造成的流水线阻塞。什么意思呢?假如某个流水线有5 stages,指令A和指令B在流水线中执行,A在B前面,指令B需要指令A的运算结果,指令A的运算结果在EX阶段就能算出。如果不用forwording & bypassing技术,指令B要等到指令A完成WB阶段的操作之后才能执行,也就是说指令B在指令A完成WB阶段之前必须阻塞。这显然会降低流水线的效率,怎么办呢?就是引进forwording & bypassing技术,将指令A在EX阶段算出结果之后直接送给指令B,而不需要等到WB阶段。
为了便于理解,我们在举一个通俗点的例子,假如现在是8月份,小张(在北京)有一本书被小王(在上海)借走了,小张出差了,到10月份才能回来,小王到9月份就能把书看完,但是如果要归还的话,只能等到10月份,现在呢,小李(也在上海)又想借这本书,怎么办?如果一定要小王把书从上海寄回北京,然后等到小张10月份出差回来,再把书寄回上海的小李。这样做显然是太愚蠢了,直接打个电话让小王看完之后给小李就可以了嘛。那个电话,就是forwording & bypassing。
关于forwording & bypassing,如有兴趣,请参考:http://en.wikipedia.org/wiki/Hazard_(computer_architecture)#Register_forwarding
2>pipeline bubble
pipeline bubble(流水线气泡),如果一切顺利,所有指令没有任何相关,也没有什么branch/jump指令的话。流水线的所有阶段在任何时刻都会正常工作,不会闲置。
但“人生不如意十之八九”,没有一帆风顺的事情,加入出现branch/jump的话,分支地址又不是紧跟后面的指令的话,那么紧跟后面的指令的所有流水线处理就是无效的,为了避免这种情况的出现,一般在branch/jump指令后面增加一条甚至多条NOP指令,即所谓的延迟槽,这时,流水线在某个时刻,有的流水线阶段就是空闲的,也就是出现了流水线气泡。关于pipeline bubble,如有兴趣,请参考:http://en.wikipedia.org/wiki/Bubble_(computing)
3>其他
关于分支预测(branch prediction),动态调度(dynamic schedule),循环展开(loop unrolling)等等这些技术,我们之前都介绍过了,这里不再赘述,如有疑问,请参考之前的blog内容。
2,or1200的ID模块
1>整体分析
前面我们说过,or1200采用的是5 stages integer static pipeline。ID(指令解码)是其中的第二个阶段,对应的是ctrl模块,这个阶段的任务大体可分为两个方面:
第一个方面是根据其他模块的控制,产生更详细的控制信号,来完成其他模块交给的任务,比如except模块捕获到了一个异常,想让流水线刷新,那么except模块送给ctrl模块一个信号,然后由ctrl模块产生相应的控制信号,刷新整条流水线。
第二个方面就是将F阶段送来的指令,根据指令的定义,而完成对所有指令的解析,解析的结果就是产生不同的控制信号。比如,如果是一条运算指令,那么就把操作数a和操作数b都取出来,送到rf_a和rf_b里面(关于rf模块,我们前面提到过,如有疑问请参考:http://blog.csdn.net/rill_zhen/article/details/9769937),并根据运算类型,产生对应的操作信号(如果是alu运算,就产生alu_op信号,如果是mac运算,就产生mac_op信号)。
ID阶段的整体结构简图,如下所示:
2>模块分析
了解了ctrl模块的大体功能是远远不够的,我们还需要知道其工作细节,下面我们就分析一下ctrl的内部情况。
1》流水线刷新信号的产生
这个部分工作,一共有4个信号,分别是if_flushpipe:刷新IF阶段;id_flushpipe,刷新ID阶段;ex_flushpipe,刷新EX阶段;wb_flushpipe,刷新WB阶段。
这几个信号是怎么产生的呢?代码实现如下:
// // Flush pipeline // assign if_flushpipe = except_flushpipe | pc_we | extend_flush; assign id_flushpipe = except_flushpipe | pc_we | extend_flush; assign ex_flushpipe = except_flushpipe | pc_we | extend_flush; assign wb_flushpipe = except_flushpipe | pc_we | extend_flush;
2》id_insn,流水线正在解码的指令暂时保存
在ctrl模块内部,有一个寄存器来保存从IF阶段传来的指令(if_insn),这个寄存器就是id_insn.它又是如何使用的呢,如下所示:
// // Instruction latch in id_insn // always @(posedge clk or `OR1200_RST_EVENT rst) begin if (rst == `OR1200_RST_VALUE) id_insn <= {`OR1200_OR32_NOP, 26'h041_0000}; else if (id_flushpipe) id_insn <= {`OR1200_OR32_NOP, 26'h041_0000}; // NOP -> id_insn[16] must be 1 else if (!id_freeze) begin id_insn <= if_insn; end end
3》ex_insn,给外部的信号
表示当前正在处理的指令,这个信号最终会送到du模块,用来调试时,可以知道当前正在解码的指令是什么。
代码如下:
// // Instruction latch in ex_insn // always @(posedge clk or `OR1200_RST_EVENT rst) begin if (rst == `OR1200_RST_VALUE) ex_insn <= {`OR1200_OR32_NOP, 26'h041_0000}; else if (!ex_freeze & id_freeze | ex_flushpipe) ex_insn <= {`OR1200_OR32_NOP, 26'h041_0000}; // NOP -> ex_insn[16] must be 1 else if (!ex_freeze) begin ex_insn <= id_insn; end end
4》ex_branch_op,表示分支指令的操作
这个信号送给了genpc模块和外部的du模块,宽度为3-bit。
代码如下:
// // Generation of ex_branch_op // always @(posedge clk or `OR1200_RST_EVENT rst) if (rst == `OR1200_RST_VALUE) ex_branch_op <= `OR1200_BRANCHOP_NOP; else if (!ex_freeze & id_freeze | ex_flushpipe) ex_branch_op <= `OR1200_BRANCHOP_NOP; else if (!ex_freeze) ex_branch_op <= id_branch_op;
5》id_branch_op,表示PC的偏移的低3-bit
这个信号送给了genpc模块。我们前面说过,在进行分支预测时需要PC的偏移值,这个信号就是。
代码如下:
// // Decode of id_branch_op // always @(posedge clk or `OR1200_RST_EVENT rst) begin if (rst == `OR1200_RST_VALUE) id_branch_op <= `OR1200_BRANCHOP_NOP; else if (id_flushpipe) id_branch_op <= `OR1200_BRANCHOP_NOP; else if (!id_freeze) begin case (if_insn[31:26]) // synopsys parallel_case // l.j `OR1200_OR32_J: id_branch_op <= `OR1200_BRANCHOP_J; // j.jal `OR1200_OR32_JAL: id_branch_op <= `OR1200_BRANCHOP_J; // j.jalr `OR1200_OR32_JALR: id_branch_op <= `OR1200_BRANCHOP_JR; // l.jr `OR1200_OR32_JR: id_branch_op <= `OR1200_BRANCHOP_JR; // l.bnf `OR1200_OR32_BNF: id_branch_op <= `OR1200_BRANCHOP_BNF; // l.bf `OR1200_OR32_BF: id_branch_op <= `OR1200_BRANCHOP_BF; // l.rfe `OR1200_OR32_RFE: id_branch_op <= `OR1200_BRANCHOP_RFE; // Non branch instructions default: id_branch_op <= `OR1200_BRANCHOP_NOP; endcase end end
6》rf_addrw,表示要向rf模块写入的地址
代码如下:
// // Register file write address // always @(posedge clk or `OR1200_RST_EVENT rst) begin if (rst == `OR1200_RST_VALUE) rf_addrw <= 5'd0; else if (!ex_freeze & id_freeze) rf_addrw <= 5'd00; else if (!ex_freeze) case (id_insn[31:26]) // synopsys parallel_case `OR1200_OR32_JAL, `OR1200_OR32_JALR: rf_addrw <= 5'd09; // link register r9 default: rf_addrw <= id_insn[25:21]; endcase end
7》rf_addra,rf_addrb,rf_rda,rf_rdb,这个四个信号表示从rf模块读的地址
代码如下:
// // Register file read addresses // assign rf_addra = if_insn[20:16]; assign rf_addrb = if_insn[15:11]; assign rf_rda = if_insn[31] || if_maci_op; assign rf_rdb = if_insn[30];
8》alu_op,ALU操作码的解析
这个信号是从各个运算指令中解析出的ALU运算的操作码。
代码如下:
// // Decode of alu_op // always @(posedge clk or `OR1200_RST_EVENT rst) begin if (rst == `OR1200_RST_VALUE) alu_op <= `OR1200_ALUOP_NOP; else if (!ex_freeze & id_freeze | ex_flushpipe) alu_op <= `OR1200_ALUOP_NOP; else if (!ex_freeze) begin case (id_insn[31:26]) // synopsys parallel_case // l.movhi `OR1200_OR32_MOVHI: alu_op <= `OR1200_ALUOP_MOVHI; // l.addi `OR1200_OR32_ADDI: alu_op <= `OR1200_ALUOP_ADD; // l.addic `OR1200_OR32_ADDIC: alu_op <= `OR1200_ALUOP_ADDC; // l.andi `OR1200_OR32_ANDI: alu_op <= `OR1200_ALUOP_AND; // l.ori `OR1200_OR32_ORI: alu_op <= `OR1200_ALUOP_OR; // l.xori `OR1200_OR32_XORI: alu_op <= `OR1200_ALUOP_XOR; // l.muli `ifdef OR1200_MULT_IMPLEMENTED `OR1200_OR32_MULI: alu_op <= `OR1200_ALUOP_MUL; `endif // Shift and rotate insns with immediate `OR1200_OR32_SH_ROTI: alu_op <= `OR1200_ALUOP_SHROT; // SFXX insns with immediate `OR1200_OR32_SFXXI: alu_op <= `OR1200_ALUOP_COMP; // ALU instructions except the one with immediate `OR1200_OR32_ALU: alu_op <= {1'b0,id_insn[3:0]}; // SFXX instructions `OR1200_OR32_SFXX: alu_op <= `OR1200_ALUOP_COMP; `ifdef OR1200_IMPL_ALU_CUST5 // l.cust5 `OR1200_OR32_CUST5: alu_op <= `OR1200_ALUOP_CUST5; `endif // Default default: begin alu_op <= `OR1200_ALUOP_NOP; end endcase end end
9》alu_op2,特殊情况下ALU操作码的输出
代码如下:
// // Decode of second ALU operation field [9:6] // always @(posedge clk or `OR1200_RST_EVENT rst) begin if (rst == `OR1200_RST_VALUE) alu_op2 <= 0; else if (!ex_freeze & id_freeze | ex_flushpipe) alu_op2 <= 0; else if (!ex_freeze) begin alu_op2 <= id_insn[`OR1200_ALUOP2_POS]; end end
10》mac_op,id_mac_op,mac运算的操作码解析
在=解析过程中使用了ex_mac_op中间临时寄存器,代码如下:
// // Decode of mac_op // `ifdef OR1200_MAC_IMPLEMENTED always @(id_insn) begin case (id_insn[31:26]) // synopsys parallel_case // l.maci `OR1200_OR32_MACI: id_mac_op = `OR1200_MACOP_MAC; // l.mac, l.msb `OR1200_OR32_MACMSB: id_mac_op = id_insn[2:0]; // Illegal and OR1200 unsupported instructions default: id_mac_op = `OR1200_MACOP_NOP; endcase end always @(posedge clk or `OR1200_RST_EVENT rst) begin if (rst == `OR1200_RST_VALUE) ex_mac_op <= `OR1200_MACOP_NOP; else if (!ex_freeze & id_freeze | ex_flushpipe) ex_mac_op <= `OR1200_MACOP_NOP; else if (!ex_freeze) ex_mac_op <= id_mac_op; end assign mac_op = abort_mvspr ? `OR1200_MACOP_NOP : ex_mac_op; `else assign id_mac_op = `OR1200_MACOP_NOP; assign mac_op = `OR1200_MACOP_NOP; `endif
11》rfwb_op,rf(register file)的write back操作码的解析
代码如下:
// // Decode of rfwb_op // always @(posedge clk or `OR1200_RST_EVENT rst) begin if (rst == `OR1200_RST_VALUE) rfwb_op <= `OR1200_RFWBOP_NOP; else if (!ex_freeze & id_freeze | ex_flushpipe) rfwb_op <= `OR1200_RFWBOP_NOP; else if (!ex_freeze) begin case (id_insn[31:26]) // synopsys parallel_case // j.jal `OR1200_OR32_JAL: rfwb_op <= {`OR1200_RFWBOP_LR, 1'b1}; // j.jalr `OR1200_OR32_JALR: rfwb_op <= {`OR1200_RFWBOP_LR, 1'b1}; // l.movhi `OR1200_OR32_MOVHI: rfwb_op <= {`OR1200_RFWBOP_ALU, 1'b1}; // l.mfspr `OR1200_OR32_MFSPR: rfwb_op <= {`OR1200_RFWBOP_SPRS, 1'b1}; // l.lwz `OR1200_OR32_LWZ: rfwb_op <= {`OR1200_RFWBOP_LSU, 1'b1}; // l.lbz `OR1200_OR32_LBZ: rfwb_op <= {`OR1200_RFWBOP_LSU, 1'b1}; // l.lbs `OR1200_OR32_LBS: rfwb_op <= {`OR1200_RFWBOP_LSU, 1'b1}; // l.lhz `OR1200_OR32_LHZ: rfwb_op <= {`OR1200_RFWBOP_LSU, 1'b1}; // l.lhs `OR1200_OR32_LHS: rfwb_op <= {`OR1200_RFWBOP_LSU, 1'b1}; // l.addi `OR1200_OR32_ADDI: rfwb_op <= {`OR1200_RFWBOP_ALU, 1'b1}; // l.addic `OR1200_OR32_ADDIC: rfwb_op <= {`OR1200_RFWBOP_ALU, 1'b1}; // l.andi `OR1200_OR32_ANDI: rfwb_op <= {`OR1200_RFWBOP_ALU, 1'b1}; // l.ori `OR1200_OR32_ORI: rfwb_op <= {`OR1200_RFWBOP_ALU, 1'b1}; // l.xori `OR1200_OR32_XORI: rfwb_op <= {`OR1200_RFWBOP_ALU, 1'b1}; // l.muli `ifdef OR1200_MULT_IMPLEMENTED `OR1200_OR32_MULI: rfwb_op <= {`OR1200_RFWBOP_ALU, 1'b1}; `endif // Shift and rotate insns with immediate `OR1200_OR32_SH_ROTI: rfwb_op <= {`OR1200_RFWBOP_ALU, 1'b1}; // ALU instructions except the one with immediate `OR1200_OR32_ALU: rfwb_op <= {`OR1200_RFWBOP_ALU, 1'b1}; `ifdef OR1200_ALU_IMPL_CUST5 // l.cust5 instructions `OR1200_OR32_CUST5: rfwb_op <= {`OR1200_RFWBOP_ALU, 1'b1}; `endif `ifdef OR1200_FPU_IMPLEMENTED // FPU instructions, lf.XXX.s, except sfxx `OR1200_OR32_FLOAT: rfwb_op <= {`OR1200_RFWBOP_FPU,!id_insn[3]}; `endif // Instructions w/o register-file write-back default: rfwb_op <= `OR1200_RFWBOP_NOP; endcase end end
12》fpu_op,float point process运算的操作码解析
代码如下,需要说明的是ORPSoC的FPU模块并没有实现。
// // Decode of FPU ops // `ifdef OR1200_FPU_IMPLEMENTED assign fpu_op = {(id_insn[31:26] == `OR1200_OR32_FLOAT), id_insn[`OR1200_FPUOP_WIDTH-2:0]}; `else assign fpu_op = {`OR1200_FPUOP_WIDTH{1'b0}}; `endif
13》wb_insn
代码如下,需要注意的是这个信号不能被异常所修改。
wb_insn should not be changed by exceptions due to correct recording of display_arch_state in the or1200_monitor! wb_insn changed by exception is not used elsewhere!
// // Instruction latch in wb_insn // always @(posedge clk or `OR1200_RST_EVENT rst) begin if (rst == `OR1200_RST_VALUE) wb_insn <= {`OR1200_OR32_NOP, 26'h041_0000}; else if (!wb_freeze) begin wb_insn <= ex_insn; end end
14》id_branch_addrtarget,分支指令跳转地址
代码如下:
// // ID Sign extension of branch offset // assign id_branch_addrtarget = {{4{id_insn[25]}}, id_insn[25:0]} + id_pc[31:2];
15》ex_branch_addrtarget
是id_branch_addrtarget信号的备份,留给debug使用
代码如下:
// pipeline ID and EX branch target address always @(posedge clk or `OR1200_RST_EVENT rst) begin if (rst == `OR1200_RST_VALUE) ex_branch_addrtarget <= 0; else if (!ex_freeze) ex_branch_addrtarget <= id_branch_addrtarget; end
16》sel_a,sel_b,选择要处理的操作码
这两个信号送给了operandmuxes模块,每个信号为2-bit.,表示操作数是来自于哪里,有4中可能:通用寄存器,wb会写数据,ex的执行结果(forword而来),立即数。
代码如下:
// // Generation of sel_a // always @(rf_addrw or id_insn or rfwb_op or wbforw_valid or wb_rfaddrw) if ((id_insn[20:16] == rf_addrw) && rfwb_op[0]) sel_a = `OR1200_SEL_EX_FORW; else if ((id_insn[20:16] == wb_rfaddrw) && wbforw_valid) sel_a = `OR1200_SEL_WB_FORW; else sel_a = `OR1200_SEL_RF; // // Generation of sel_b // always @(rf_addrw or sel_imm or id_insn or rfwb_op or wbforw_valid or wb_rfaddrw) if (sel_imm) sel_b = `OR1200_SEL_IMM; else if ((id_insn[15:11] == rf_addrw) && rfwb_op[0]) sel_b = `OR1200_SEL_EX_FORW; else if ((id_insn[15:11] == wb_rfaddrw) && wbforw_valid) sel_b = `OR1200_SEL_WB_FORW; else sel_b = `OR1200_SEL_RF;
17》id_lsu_op,load/store指令的操作码解析
代码如下:
// // Decode of id_lsu_op // always @(id_insn) begin case (id_insn[31:26]) // synopsys parallel_case // l.lwz `OR1200_OR32_LWZ: id_lsu_op = `OR1200_LSUOP_LWZ; // l.lbz `OR1200_OR32_LBZ: id_lsu_op = `OR1200_LSUOP_LBZ; // l.lbs `OR1200_OR32_LBS: id_lsu_op = `OR1200_LSUOP_LBS; // l.lhz `OR1200_OR32_LHZ: id_lsu_op = `OR1200_LSUOP_LHZ; // l.lhs `OR1200_OR32_LHS: id_lsu_op = `OR1200_LSUOP_LHS; // l.sw `OR1200_OR32_SW: id_lsu_op = `OR1200_LSUOP_SW; // l.sb `OR1200_OR32_SB: id_lsu_op = `OR1200_LSUOP_SB; // l.sh `OR1200_OR32_SH: id_lsu_op = `OR1200_LSUOP_SH; // Non load/store instructions default: id_lsu_op = `OR1200_LSUOP_NOP; endcase end
18》comp_op,比较指令的操作码解析,送给ALU单元
代码如下:
// // Decode of comp_op // always @(posedge clk or `OR1200_RST_EVENT rst) begin if (rst == `OR1200_RST_VALUE) begin comp_op <= 4'd0; end else if (!ex_freeze & id_freeze | ex_flushpipe) comp_op <= 4'd0; else if (!ex_freeze) comp_op <= id_insn[24:21]; end
19》multicycle,根据指令类型,判断是否是多个cycle完成还是单个cycle完成。
这个信号送给freeze模块,代码如下:
// // Decode of multicycle // always @(id_insn) begin case (id_insn[31:26]) // synopsys parallel_case // l.rfe `OR1200_OR32_RFE, // l.mfspr `OR1200_OR32_MFSPR: multicycle = `OR1200_TWO_CYCLES; // to read from ITLB/DTLB (sync RAMs) // Single cycle instructions default: begin multicycle = `OR1200_ONE_CYCLE; end endcase end
20》wait_on,流水线等待的周期数
这个信号也是送给了freeze模块,代码如下:
// // Encode wait_on signal // always @(id_insn) begin case (id_insn[31:26]) // synopsys parallel_case `OR1200_OR32_ALU: wait_on = ( 1'b0 `ifdef OR1200_DIV_IMPLEMENTED | (id_insn[4:0] == `OR1200_ALUOP_DIV) | (id_insn[4:0] == `OR1200_ALUOP_DIVU) `endif `ifdef OR1200_MULT_IMPLEMENTED | (id_insn[4:0] == `OR1200_ALUOP_MUL) | (id_insn[4:0] == `OR1200_ALUOP_MULU) `endif ) ? `OR1200_WAIT_ON_MULTMAC : `OR1200_WAIT_ON_NOTHING; `ifdef OR1200_MULT_IMPLEMENTED `ifdef OR1200_MAC_IMPLEMENTED `OR1200_OR32_MACMSB, `OR1200_OR32_MACI, `endif `OR1200_OR32_MULI: wait_on = `OR1200_WAIT_ON_MULTMAC; `endif `ifdef OR1200_MAC_IMPLEMENTED `OR1200_OR32_MACRC: wait_on = id_insn[16] ? `OR1200_WAIT_ON_MULTMAC : `OR1200_WAIT_ON_NOTHING; `endif `ifdef OR1200_FPU_IMPLEMENTED `OR1200_OR32_FLOAT: begin wait_on = id_insn[`OR1200_FPUOP_DOUBLE_BIT] ? 0 : `OR1200_WAIT_ON_FPU; end `endif `ifndef OR1200_DC_WRITEHROUGH // l.mtspr `OR1200_OR32_MTSPR: begin wait_on = `OR1200_WAIT_ON_MTSPR; end `endif default: begin wait_on = `OR1200_WAIT_ON_NOTHING; end endcase // case (id_insn[31:26]) end
21》cust5_op,cust5_limm这两个信号是对cust5运算的操作码的解析
代码如下:
// // cust5_op, cust5_limm (L immediate) // assign cust5_op = ex_insn[4:0]; assign cust5_limm = ex_insn[10:5];
22》id_simm,ex_simm
id_simm是运算指令中的立即数的解析,ex_simm是id_simm的备份,供调试使用。
代码如下:
// // EX Sign/Zero extension of immediates // always @(posedge clk or `OR1200_RST_EVENT rst) begin if (rst == `OR1200_RST_VALUE) ex_simm <= 32'h0000_0000; else if (!ex_freeze) begin ex_simm <= id_simm; end end // // ID Sign/Zero extension of immediate // always @(id_insn) begin case (id_insn[31:26]) // synopsys parallel_case // l.addi `OR1200_OR32_ADDI: id_simm = {{16{id_insn[15]}}, id_insn[15:0]}; // l.addic `OR1200_OR32_ADDIC: id_simm = {{16{id_insn[15]}}, id_insn[15:0]}; // l.lxx (load instructions) `OR1200_OR32_LWZ, `OR1200_OR32_LBZ, `OR1200_OR32_LBS, `OR1200_OR32_LHZ, `OR1200_OR32_LHS: id_simm = {{16{id_insn[15]}}, id_insn[15:0]}; // l.muli `ifdef OR1200_MULT_IMPLEMENTED `OR1200_OR32_MULI: id_simm = {{16{id_insn[15]}}, id_insn[15:0]}; `endif // l.maci `ifdef OR1200_MAC_IMPLEMENTED `OR1200_OR32_MACI: id_simm = {{16{id_insn[15]}}, id_insn[15:0]}; `endif // l.mtspr `OR1200_OR32_MTSPR: id_simm = {16'b0, id_insn[25:21], id_insn[10:0]}; // l.sxx (store instructions) `OR1200_OR32_SW, `OR1200_OR32_SH, `OR1200_OR32_SB: id_simm = {{16{id_insn[25]}}, id_insn[25:21], id_insn[10:0]}; // l.xori `OR1200_OR32_XORI: id_simm = {{16{id_insn[15]}}, id_insn[15:0]}; // l.sfxxi (SFXX with immediate) `OR1200_OR32_SFXXI: id_simm = {{16{id_insn[15]}}, id_insn[15:0]}; // Instructions with no or zero extended immediate default: id_simm = {{16'b0}, id_insn[15:0]}; endcase end
23》sig_syscall,对系统调用指令的解析
我们都知道,现在一般的CPU指令集中会设计专门设计OS系统调用的指令,以加快系统调用的执行速度。
代码如下:
// // Decode of l.sys // always @(posedge clk or `OR1200_RST_EVENT rst) begin if (rst == `OR1200_RST_VALUE) sig_syscall <= 1'b0; else if (!ex_freeze & id_freeze | ex_flushpipe) sig_syscall <= 1'b0; else if (!ex_freeze) begin sig_syscall <= (id_insn[31:23] == {`OR1200_OR32_XSYNC, 3'b000}); end end
24》sig_trap,陷入指令的解析
与系统调用功能类似,用来处理软中断,比如著名的0x80中断。
代码如下:
// // Decode of l.trap // always @(posedge clk or `OR1200_RST_EVENT rst) begin if (rst == `OR1200_RST_VALUE) sig_trap <= 1'b0; else if (!ex_freeze & id_freeze | ex_flushpipe) sig_trap <= 1'b0; else if (!ex_freeze) begin sig_trap <= (id_insn[31:23] == {`OR1200_OR32_XSYNC, 3'b010})| du_hwbkpt; end end
25》force_dslot_fetch,no_more_dslot,延迟槽控制信号
代码如下:
// // Force fetch of delay slot instruction when jump/branch is preceeded by // load/store instructions // assign force_dslot_fetch = 1'b0; assign no_more_dslot = (|ex_branch_op & !id_void & ex_branch_taken) | (ex_branch_op == `OR1200_BRANCHOP_RFE);
26》对NOP指令的解析
对于NOP指令,判断当前的指令是否为NOP,产生标示三个信号给其它的流水阶段。
代码如下,需要说明的是wb-void信号并未引出来。
assign id_void = (id_insn[31:26] == `OR1200_OR32_NOP) & id_insn[16]; assign ex_void = (ex_insn[31:26] == `OR1200_OR32_NOP) & ex_insn[16]; assign wb_void = (wb_insn[31:26] == `OR1200_OR32_NOP) & wb_insn[16];
27》ex_spr_write,ex_spr_read产生对sprs的读写信号
代码如下:
assign ex_spr_write = spr_write && !abort_mvspr; assign ex_spr_read = spr_read && !abort_mvspr;
28》id_macrc_op,ex_macrc_op,ID阶段和EX阶段的mac运算的操作码解析
代码如下:
// // l.macrc in ID stage // `ifdef OR1200_MAC_IMPLEMENTED assign id_macrc_op = (id_insn[31:26] == `OR1200_OR32_MACRC) & id_insn[16]; `else assign id_macrc_op = 1'b0; `endif // // l.macrc in EX stage // `ifdef OR1200_MAC_IMPLEMENTED always @(posedge clk or `OR1200_RST_EVENT rst) begin if (rst == `OR1200_RST_VALUE) ex_macrc_op <= 1'b0; else if (!ex_freeze & id_freeze | ex_flushpipe) ex_macrc_op <= 1'b0; else if (!ex_freeze) ex_macrc_op <= id_macrc_op; end `else assign ex_macrc_op = 1'b0; `endif
29》rfe,是异常返回指示信号
代码如下:
assign rfe = (id_branch_op == `OR1200_BRANCHOP_RFE) | (ex_branch_op == `OR1200_BRANCHOP_RFE);
这个信号送给了if模块,if模块的使用方法如下,如果是异常返回,并且之前保存过,则不用重新从cache里面取指了。
assign if_insn = no_more_dslot | rfe | if_bypass ? {`OR1200_OR32_NOP, 26'h041_0000} : saved ? insn_saved : icpu_ack_i ? icpu_dat_i : {`OR1200_OR32_NOP, 26'h061_0000};
30》except_illegal,非法指令异常信号
将当前指令和指令集中所有指令进行比较,如果不是,则拉高本信号。
代码如下:
// // Decode of except_illegal // always @(posedge clk or `OR1200_RST_EVENT rst) begin if (rst == `OR1200_RST_VALUE) except_illegal <= 1'b0; else if (!ex_freeze & id_freeze | ex_flushpipe) except_illegal <= 1'b0; else if (!ex_freeze) begin case (id_insn[31:26]) // synopsys parallel_case `OR1200_OR32_J, `OR1200_OR32_JAL, `OR1200_OR32_JALR, `OR1200_OR32_JR, `OR1200_OR32_BNF, `OR1200_OR32_BF, `OR1200_OR32_RFE, `OR1200_OR32_MOVHI, `OR1200_OR32_MFSPR, `OR1200_OR32_XSYNC, `ifdef OR1200_MAC_IMPLEMENTED `OR1200_OR32_MACI, `endif `OR1200_OR32_LWZ, `OR1200_OR32_LBZ, `OR1200_OR32_LBS, `OR1200_OR32_LHZ, `OR1200_OR32_LHS, `OR1200_OR32_ADDI, `OR1200_OR32_ADDIC, `OR1200_OR32_ANDI, `OR1200_OR32_ORI, `OR1200_OR32_XORI, `ifdef OR1200_MULT_IMPLEMENTED `OR1200_OR32_MULI, `endif `OR1200_OR32_SH_ROTI, `OR1200_OR32_SFXXI, `OR1200_OR32_MTSPR, `ifdef OR1200_MAC_IMPLEMENTED `OR1200_OR32_MACMSB, `endif `OR1200_OR32_SW, `OR1200_OR32_SB, `OR1200_OR32_SH, `OR1200_OR32_SFXX, `ifdef OR1200_IMPL_ALU_CUST5 `OR1200_OR32_CUST5, `endif `OR1200_OR32_NOP: except_illegal <= 1'b0; `ifdef OR1200_FPU_IMPLEMENTED `OR1200_OR32_FLOAT: // Check it's not a double precision instruction except_illegal <= id_insn[`OR1200_FPUOP_DOUBLE_BIT]; `endif `OR1200_OR32_ALU: except_illegal <= 1'b0 `ifdef OR1200_MULT_IMPLEMENTED `ifdef OR1200_DIV_IMPLEMENTED `else | (id_insn[4:0] == `OR1200_ALUOP_DIV) | (id_insn[4:0] == `OR1200_ALUOP_DIVU) `endif `else | (id_insn[4:0] == `OR1200_ALUOP_DIV) | (id_insn[4:0] == `OR1200_ALUOP_DIVU) | (id_insn[4:0] == `OR1200_ALUOP_MUL) `endif `ifdef OR1200_IMPL_ADDC `else | (id_insn[4:0] == `OR1200_ALUOP_ADDC) `endif `ifdef OR1200_IMPL_ALU_FFL1 `else | (id_insn[4:0] == `OR1200_ALUOP_FFL1) `endif `ifdef OR1200_IMPL_ALU_ROTATE `else | ((id_insn[4:0] == `OR1200_ALUOP_SHROT) & (id_insn[9:6] == `OR1200_SHROTOP_ROR)) `endif `ifdef OR1200_IMPL_SUB `else | (id_insn[4:0] == `OR1200_ALUOP_SUB) `endif `ifdef OR1200_IMPL_ALU_EXT `else | (id_insn[4:0] == `OR1200_ALUOP_EXTHB) | (id_insn[4:0] == `OR1200_ALUOP_EXTW) `endif ; // Illegal and OR1200 unsupported instructions default: except_illegal <= 1'b1; endcase end // if (!ex_freeze) end
31》dc_no_writethrough
解析load/store指令中读写data cache的寄存器地址是来自r1(stack register)还是r2(frame pointer register)。
代码如下:
// Decode destination register address for data cache to check if store ops // are being done from the stack register (r1) or frame pointer register (r2) `ifdef OR1200_DC_NOSTACKWRITETHROUGH always @(posedge clk or `OR1200_RST_EVENT rst) begin if (rst == `OR1200_RST_VALUE) dc_no_writethrough <= 0; else if (!ex_freeze) dc_no_writethrough <= (id_insn[20:16] == 5'd1) | (id_insn[20:16] == 5'd2); end `else assign dc_no_writethrough = 0; `endif
3,小结
本小节我们分析了or1200的ID级的具体实现,至此,or1200的五级流水,我们已经分析了IF,ID,EX三级,还有MA和WB两级,那是future work了。
ctrl模块虽然看起来代码比较多,但内部却没有FSM,所以各个子模块都是相互独立的,所以没有想象的那么复杂。
enjoy!