将陆续上传本人写的新书《自己动手写CPU》(尚未出版),今天是第22篇,我尽量每周四篇
6.3 修改OpenMIPS以实现移动操作指令
6.3.1 HI、LO寄存器的实现
在HILO模块中实现HI、LO寄存器,HILO模块的接口描述如表6-1所示。
HILO模块的代码如下,源文件是本书附带光盘Code\Chapter6目录下的hilo_reg.v。整个代码很简单:在时钟上升沿,如果复位信号无效,那么就判断输入的写使能信号we是否为WriteEnable,如果是WriteEnable,那么就将输入的hi_i、lo_i的值,作为HI、LO寄存器的新值,并通过hi_o、lo_o接口输出。
module hilo_reg(
input wire clk,
input wire rst,
// 写端口
input wire we,
input wire[`RegBus] hi_i,
input wire[`RegBus] lo_i,
// 读端口
output reg[`RegBus] hi_o,
output reg[`RegBus] lo_o
);
always @ (posedge clk) begin
if (rst == `RstEnable) begin
hi_o <= `ZeroWord;
lo_o <= `ZeroWord;
end else if((we == `WriteEnable)) begin
hi_o <= hi_i;
lo_o <= lo_i;
end
end
endmodule
6.3.2 修改译码阶段的ID模块
在译码阶段要增加对移动操作指令的分析,根据图6-1给出的移动操作指令格式可知,这6条指令都是SPECIAL类指令,且6-10bit均为0,需要依据0-5bit的功能码确定指令,确定指令的过程如图6-6所示。
其中涉及的宏定义如下,正是图6-1中各个指令的功能码。在本书附带光盘Code\Chapter6目录下的defines.v文件可以找到这些宏定义。
`define EXE_MOVZ 6'b001010
`define EXE_MOVN 6'b001011
`define EXE_MFHI 6'b010000
`define EXE_MTHI 6'b010001
`define EXE_MFLO 6'b010010
`define EXE_MTLO 6'b010011
译码阶段的ID模块主要修改如下。完整代码位于本书附带光盘Code\Chapter6目录下的id.v文件。
module id(
......
);
wire[5:0] op = inst_i[31:26];
wire[4:0] op2 = inst_i[10:6];
wire[5:0] op3 = inst_i[5:0];
wire[4:0] op4 = inst_i[20:16];
......
always @ (*) begin
......
aluop_o <= `EXE_NOP_OP;
alusel_o <= `EXE_RES_NOP;
wd_o <= inst_i[15:11]; // 默认目的寄存器地址wd_o
wreg_o <= `WriteDisable;
instvalid <= `InstInvalid;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b0;
reg1_addr_o <= inst_i[25:21]; // 默认的reg1_addr_o
reg2_addr_o <= inst_i[20:16]; // 默认的reg2_addr_o
imm <= `ZeroWord;
case (op)
`EXE_SPECIAL_INST: begin // 是SPECIAL类指令
case (op2)
5'b00000: begin // op2为5'b00000
case (op3)
......
`EXE_MFHI: begin // mfhi指令
wreg_o <= `WriteEnable;
aluop_o <= `EXE_MFHI_OP;
alusel_o <= `EXE_RES_MOVE;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
end
`EXE_MFLO: begin // mflo指令
wreg_o <= `WriteEnable;
aluop_o <= `EX E_MFLO_OP;
alusel_o <= `EXE_RES_MOVE;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
end
`EXE_MTHI: begin // mthi指令
wreg_o <= `WriteDisable;
aluop_o <= `EXE_MTHI_OP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
end
`EXE_MTLO: begin // mtlo指令
wreg_o <= `WriteD