引言

之前,我们分析了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!

OpenRisc-45-or1200的ID模块分析的更多相关文章

  1. OpenRisc-43-or1200的IF模块分析

    引言 “喂饱饥饿的CPU”,是计算机体系结构设计者时刻要考虑的问题.要解决这个问题,方法大体可分为两部分,第一就是利用principle of locality而引进的cache技术,缩短取指时间,第 ...

  2. OpenRisc-40-or1200的MMU模块分析

    引言 MMU(memory management unit),无论对于computer architecture designer还是OS designer,都是至关重要的部分,设计和使用的好坏,对性 ...

  3. OpenRisc-48-or1200的SPRS模块分析

    引言 之前,我们在分析or1200的WB模块时(http://blog.csdn.net/rill_zhen/article/details/10220619),介绍了OpenRISC的GPRS(ge ...

  4. OpenRisc-47-or1200的WB模块分析

    引言 “善妖善老,善始善终”,说的是无论什么事情要从有头有尾,别三分钟热度. 对于or1200的流水线来说,MA阶段是最后一个阶段,也是整条流水线的收尾阶段,负责战场的清扫工作.比如,把运算指令的运算 ...

  5. OpenRisc-41-or1200的cache模块分析

    引言 为CPU提供足够的,稳定的指令流和数据流是计算机体系结构设计中两个永恒的话题.为了给CPU提供指令流,需要设计分支预测机构,为了给CPU提供数据流,就需要设计cache了.其实,无论是insn还 ...

  6. OpenRisc-50-or1200的freeze模块分析

    引言 之前,我们分析or1200的控制通路中的sprs模块和except模块,本小节,我们就分析一下or1200控制通路的最后一个模块,就是freeze模块. 1,整体分析 freeze模块,顾名思义 ...

  7. 【转】python模块分析之logging日志(四)

    [转]python模块分析之logging日志(四) python的logging模块是用来写日志的,是python的标准模块. 系列文章 python模块分析之random(一) python模块分 ...

  8. python模块分析之logging日志(四)

    前言 python的logging模块是用来设置日志的,是python的标准模块. 系列文章 python模块分析之random(一) python模块分析之hashlib加密(二) python模块 ...

  9. OpenRisc-42-or1200的ALU模块分析

    引言 computer(计算机),顾名思义,就是用来compute(计算)的.计算机体系结构在上世纪五六十年代的时候,主要就是研究如何设计运算部件,就是想办法用最少的元器件(那时元器件很贵),最快的速 ...

随机推荐

  1. hdu 5611 Baby Ming and phone number(模拟)

    Problem Description Baby Ming collected lots of cell phone numbers, and he wants to sell them for mo ...

  2. hdu 5433 Xiao Ming climbing(bfs+三维标记)

    Problem Description   Due to the curse made by the devil,Xiao Ming is stranded on a mountain and can ...

  3. java框架BeanUtils及路径问题练习

    内省----->一个变态的反射    BeanUtils主要解决 的问题: 把对象的属性数据封装 到对象中.  使从文件中读取的数据往对象中赋值更加简单:   BeanUtils的好处:  1. ...

  4. Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6633311 在上一篇文章中,我 们分析了And ...

  5. 黑马程序员 ——Java SE(1)

    ----<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培训 ...

  6. hdu120118岁生日

    Problem Description Gardon的18岁生日就要到了,他当然很开心,可是他突然想到一个问题,是不是每个人从出生开始,到达18岁生日时所经过的天数都是一样的呢?似乎并不全都是这样,所 ...

  7. UVA 11754 Code Feat (枚举,中国剩余定理)

    转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud C Code Feat   The government hackers at C ...

  8. windows在文件夹快速打开命令行

    普通打开方式 按住shift键,在指定的文件夹上右键,会发现有"在此处打开命令行窗口"的字样,选择该项,即可打开命令行,并且路径刚好是你刚才选择的文件夹路径 管理员方式打开 修改注 ...

  9. After a rest, go on

    busy during the whole May holiday. running between S and H, waste much time leaving things behind. t ...

  10. 多台服务之间共享Session

    一.问题:为了满足足够大的应用,满足更多的客户,就需要架设N台Web服务器(N>=2),在多台Web服务器的情况下,就会涉及到一个问题:用户登陆一台服务器以后,如果在跨越到另一台服务器的时候能够 ...