将陆续上传新书《自己动手写CPU》,今天是第41篇,我尽量每周四篇,但是最近已经很久没有实现这个目标了,一直都有事,不好意思哈。
开展晒书评送书活动,在亚马逊、京东、当当三大图书网站上,发表《自己动手写CPU》书评的前十名读者,均可获赠《步步惊芯——软核处理器内部设计分析》一书,大家踊跃参与吧!活动时间:2014-9-11至2014-10-30
1、修改ID模块
参考图9-19可知,ID模块要增加接口inst_o,如表9-1所示。
在ID模块还要增加对加载存储指令的分析,根据图9-1、9-2、9-6、9-12给出的加载存储指令的格式可知,这些指令的指令码都是不同的,所以可以直接依据指令码确定是哪一种指令,确定指令的过程如图9-20所示。
其中涉及的宏定义如下,正是各个加载存储指令的指令码,在本书附带光盘Code\Chapter9_1目录下的defines.v文件可以找到这些定义。
`define EXE_LB 6'b100000 `define EXE_LBU 6'b100100 `define EXE_LH 6'b100001 `define EXE_LHU 6'b100101 `define EXE_LW 6'b100011 `define EXE_LWL 6'b100010 `define EXE_LWR 6'b100110 `define EXE_SB 6'b101000 `define EXE_SH 6'b101001 `define EXE_SW 6'b101011 `define EXE_SWL 6'b101010 `define EXE_SWR 6'b101110
修改译码阶段的ID模块如下。完整代码请参考本书附带光盘Code\Chapter9_1目录下的id.v文件。
module id(
......
output wire[`RegBus] inst_o, // 新增加的输出接口
......
);
......
assign inst_o = inst_i; // inst_o的值就是译码阶段的指令
always @ (*) begin
if (rst == `RstEnable) begin
......
end else 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_LB: begin // lb指令
wreg_o <= `WriteEnable;
aluop_o <= `EXE_LB_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_LBU: begin // lbu指令
wreg_o <= `WriteEnable;
aluop_o <= `EXE_LBU_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_LH: begin // lh指令
wreg_o <= `WriteEnable;
aluop_o <= `EXE_LH_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_LHU: begin // lhu指令
wreg_o <= `WriteEnable;
aluop_o <= `EXE_LHU_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_LW: begin // lw指令
wreg_o <= `WriteEnable;
aluop_o <= `EXE_LW_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_LWL: begin // lwl指令
wreg_o <= `WriteEnable;
aluop_o <= `EXE_LWL_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_LWR: begin // lwr指令
wreg_o <= `WriteEnable;
aluop_o <= `EXE_LWR_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_SB: begin // sb指令
wreg_o <= `WriteDisable;
aluop_o <= `EXE_SB_OP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
alusel_o <= `EXE_RES_LOAD_STORE;
end
`EXE_SH: begin // sh指令
wreg_o <= `WriteDisable;
aluop_o <= `EXE_SH_OP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
alusel_o <= `EXE_RES_LOAD_STORE;
end
`EXE_SW: begin // sw指令
wreg_o <= `WriteDisable;
aluop_o <= `EXE_SW_OP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
alusel_o <= `EXE_RES_LOAD_STORE;
end
`EXE_SWL: begin // swl指令
wreg_o <= `WriteDisable;
aluop_o <= `EXE_SWL_OP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
alusel_o <= `EXE_RES_LOAD_STORE;
end
`EXE_SWR: begin // swr指令
wreg_o <= `WriteDisable;
aluop_o <= `EXE_SWR_OP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
alusel_o <= `EXE_RES_LOAD_STORE;
end
......
译码工作主要是确定要写的目的寄存器、要读取的寄存器、要执行的运算等三个方面。以下对几个有代表性的指令的译码过程进行说明。
(1)lb指令
(2)lwl指令
lwr指令与lwl指令的译码过程类似,只是aluop_o的值不同。
(3)sb指令
sh、sw、swr、swl指令与sb指令的译码过程类似,只是aluop_o的值不同。
2、修改ID/EX模块
参考图9-19可知,ID/EX模块需要增加部分接口,用于将ID模块新增加的输出信号inst_o传递到执行阶段的EX模块。如表9-2所示。
修改译码阶段的ID/EX模块如下。完整代码位于本书附带光盘Code\Chapter9_1目录下的id_ex.v文件。
module id_ex(
......
input wire[`RegBus] id_inst, // 来自ID模块的信号
......
output reg[`RegBus] ex_inst // 传递到EX模块
);
always @ (posedge clk) begin
if (rst == `RstEnable) begin
......
ex_inst <= `ZeroWord;
end else if(stall[2] == `Stop && stall[3] == `NoStop) begin
......
ex_inst <= `ZeroWord;
end else if(stall[2] == `NoStop) begin
......
//在译码阶段没有暂停的情况下,直接将ID模块的输入通过接口ex_inst输出
ex_inst <= id_inst;
end
end
endmodule下一步将修改执行阶段
自己动手写CPU之第九阶段(5)——实现加载存储指令1(修改译码阶段)
原文:http://blog.csdn.net/leishangwen/article/details/40273717