此博客为个人博客,不涉及商业用途,仅提供学习参考,内容均来自个人原创以及互联网转载和摘录。
此博客上带有原创标识的文章、图片、文件等,未经本人允许,不得用于商业用途以及传统媒体。
本文首发于CSDN,其他网站均为转载。网络媒体或个人转载请注明出处和链接,否则属于侵权行为。
原博客链接:https://blog.csdn.net/qq_38305370
原博主昵称:城外南风起
————————————————
MIPS指令分为R型、I型和J型,这里不讨论J型(后面可能会补)。R型指令比I型指令常见,这就导致在设计处理器时,默认实现R型指令,只有当检测到I型指令时,才做调整。即对I型指令有偏见,优先照顾R型指令。
R型字段:
I型字段:
可以看到,R型和I型共同拥有的字段为op、rs、rt。其中rt在I型指令中为目标寄存器地址,而在R型指令中为源操作数寄存器地址。R型指令的目标寄存器地为rd。所以,在告诉执行阶段目标寄存器地址时,默认告诉其rd,即[15:11]位;只有检测到I型指令时,才修改为rt,即[20:16]位。
那么,是如何检测I型指令的呢?
根据op确定指令类型,就能确定目标寄存器地址是取rt(I型)还是rd(R型)。
以ori指令译码为例:
//acquire fields
//note rd, shamt and funct only exist in R-type and I-type instruction
wire [5:0] op = inst_i[31:26];
wire [5:0] rs = inst_i[25:21];
wire [5:0] rt = inst_i[20:16];
wire [5:0] rd = inst_i[15:11];
wire [4:0] shamt = inst_i[10:6];
wire [5:0] funct = inst_i[5:0];
wire [15:0] imm_value = inst_i[15:0];
//save extended immediate
reg [`RegBus] imm;
//instruction valid
reg instvalid;
/* decode */
always @ (*) begin
if(rst == `RstEnable) begin
aluop_o <= `EXE_NOP_OP;
alusel_o <= `EXE_RES_NOP;
waddr_o <= `NOPRegAddr;
wreg_o <= `WriteDisable;
instvalid <= `InstValid;
re1_o <= `ReadDisable;
re2_o <= `ReadDisable;
raddr1_o <= `NOPRegAddr;
raddr2_o <= `NOPRegAddr;
imm <= `ZeroWord;
end
else begin
aluop_o <= `EXE_NOP_OP;
alusel_o <= `EXE_RES_NOP;
waddr_o <= rd; //default R-type
wreg_o <= `WriteDisable;
instvalid <= `InstValid;
re1_o <= `ReadDisable;
re2_o <= `ReadDisable;
raddr1_o <= rs;
raddr2_o <= rt;
imm <= `ZeroWord;
end
case(op)
`EXE_ORI: begin //determine whether or not it is an ori instruction by op
we <= `WriteEnable; //result after ori should be written into regfile
alusel_o <= `EXE_OR_OP; //or operation
alusel_sel <= `EXE_RES_LOGIC; //logic operation
re1_o <= `ReadEnable; //read port 1
re2_o <= `ReadDisable; //not read port 2
imm <= {16'h0, imm_value}//extend immediate
waddr_o <= rt; //I-type
instvalid <= `InstValid;
end
default: begin
end
endcase
end
复位后目标寄存器地址默认为rd(R型),即waddr_o <= rd。当检测到ori指令后,再修改为rt(I型),即waddr_o <= rt。
与此同时,还会对寄存器堆栈中的两个读端口使能信号进行修改。I型指令只读取一个端口(只有一个源操作数),另一个输出给执行阶段的操作数为扩展后的立即数(imm),实现代码如下:
/* determine source operand 1 */
always @ (*) begin
if(rst == `RstEnable) begin
op_reg1_o <= `ZeroWord;
end
else if(re1 == `ReadEnable) begin
op_reg1_o <= rdata1_i;
end
else if(re1 == `ReadDisable) begin //use immediate if not read register
op_reg1_o <= imm;
end
else begin
op_reg1_o <= `ZeroWord;
end
end
/* determine source operand 1 */
always @ (*) begin
if(rst == `RstEnable) begin
op_reg2_o <= `ZeroWord;
end
else if(re2 == `ReadEnable) begin
op_reg2_o <= rdata2_i;
end
else if(re2 == `ReadDisable) begin //use immediate if not read register
op_reg2_o <= imm;
end
else begin
op_reg2_o <= `ZeroWord;
end
end
参考:
1.雷思磊著.自己动手写CPU[M].电子工业出版社,2014.
2.(美)帕特森,(美)亨尼斯著.计算机组成与设计 硬件/软件接口 原书第5版[M].机械工业出版社,2015.
————————————————
感谢您的阅读,如果您有收获,请给我一个三连吧!
如果您觉得这还不够,可以点击 打赏 按钮,告诉我: 你币有了!