CPU 速通系列 3-1:EX 模块
代码
Path src/cpu/ex.sv
1`include "defines.svh"
2
3module ex (
4
5 input logic rst,
6
7 //送到执行阶段的信息
8 input logic [ `AluOpBus] aluop_i,
9 input logic [ `AluSelBus] alusel_i,
10 input logic [ `RegBus] reg1_i,
11 input logic [ `RegBus] reg2_i,
12 input logic [`RegAddrBus] wd_i,
13 input logic wreg_i,
14
15 //HI、LO寄存器的值
16 input logic [`RegBus] hi_i,
17 input logic [`RegBus] lo_i,
18
19 //回写阶段的指令是否要写HI、LO,用于检测HI、LO的数据相关
20 input logic [`RegBus] wb_hi_i,
21 input logic [`RegBus] wb_lo_i,
22 input logic wb_whilo_i,
23
24 //访存阶段的指令是否要写HI、LO,用于检测HI、LO的数据相关
25 input logic [`RegBus] mem_hi_i,
26 input logic [`RegBus] mem_lo_i,
27 input logic mem_whilo_i,
28
29 input logic [`DoubleRegBus] hilo_temp_i,
30 input logic [ 1:0] cnt_i,
31
32 //与除法模块相连
33 input logic [`DoubleRegBus] div_result_i,
34 input logic div_ready_i,
35
36 //是否转移、以及link address
37 input logic [`RegBus] link_address_i,
38 input logic is_in_delayslot_i,
39
40 output logic [`RegAddrBus] wd_o,
41 output logic wreg_o,
42 output logic [ `RegBus] wdata_o,
43
44 output logic [`RegBus] hi_o,
45 output logic [`RegBus] lo_o,
46 output logic whilo_o,
47
48 output logic [`DoubleRegBus] hilo_temp_o,
49 output logic [ 1:0] cnt_o,
50
51 output logic [`RegBus] div_opdata1_o,
52 output logic [`RegBus] div_opdata2_o,
53 output logic div_start_o,
54 output logic signed_div_o,
55
56 output logic stallreq
57
58);
59
60 logic [`RegBus] logicout;
61 logic [`RegBus] shiftres;
62 logic [`RegBus] moveres;
63 logic [`RegBus] arithmeticres;
64 logic [`DoubleRegBus] mulres;
65 logic [`RegBus] HI;
66 logic [`RegBus] LO;
67 logic [`RegBus] reg2_i_mux;
68 logic [`RegBus] reg1_i_not;
69 logic [`RegBus] result_sum;
70 logic ov_sum;
71 logic reg1_eq_reg2;
72 logic reg1_lt_reg2;
73 logic [`RegBus] opdata1_mult;
74 logic [`RegBus] opdata2_mult;
75 logic [`DoubleRegBus] hilo_temp;
76 logic [`DoubleRegBus] hilo_temp1;
77 logic stallreq_for_madd_msub;
78 logic stallreq_for_div;
79
80 always_comb begin
81 if (rst == `RstEnable) begin
82 logicout = `ZeroWord;
83 end else begin
84 case (aluop_i)
85 `EXE_OR_OP: begin
86 logicout = reg1_i | reg2_i;
87 end
88 `EXE_AND_OP: begin
89 logicout = reg1_i & reg2_i;
90 end
91 `EXE_NOR_OP: begin
92 logicout = ~(reg1_i | reg2_i);
93 end
94 `EXE_XOR_OP: begin
95 logicout = reg1_i ^ reg2_i;
96 end
97 default: begin
98 logicout = `ZeroWord;
99 end
100 endcase
101 end //if
102 end //always
103
104 always_comb begin
105 if (rst == `RstEnable) begin
106 shiftres = `ZeroWord;
107 end else begin
108 case (aluop_i)
109 `EXE_SLL_OP: begin
110 shiftres = reg2_i << reg1_i[4:0];
111 end
112 `EXE_SRL_OP: begin
113 shiftres = reg2_i >> reg1_i[4:0];
114 end
115 `EXE_SRA_OP: begin
116 shiftres = ({32{reg2_i[31]}} << (6'd32 - {1'b0, reg1_i[4:0]})) | reg2_i >> reg1_i[4:0];
117 end
118 default: begin
119 shiftres = `ZeroWord;
120 end
121 endcase
122 end //if
123 end //always
124
125 assign reg2_i_mux = ((aluop_i == `EXE_SUB_OP) || (aluop_i == `EXE_SUBU_OP) || (aluop_i == `EXE_SLT_OP) ) ? (~reg2_i)+1 : reg2_i;
126
127 assign result_sum = reg1_i + reg2_i_mux;
128
129 assign ov_sum = ((!reg1_i[31] && !reg2_i_mux[31]) && result_sum[31]) || ((reg1_i[31] && reg2_i_mux[31]) && (!result_sum[31]));
130
131 assign reg1_lt_reg2 = ((aluop_i == `EXE_SLT_OP)) ? ((reg1_i[31] && !reg2_i[31]) || (!reg1_i[31] && !reg2_i[31] && result_sum[31])|| (reg1_i[31] && reg2_i[31] && result_sum[31])) : (reg1_i < reg2_i);
132
133 assign reg1_i_not = ~reg1_i;
134
135 always_comb begin
136 if (rst == `RstEnable) begin
137 arithmeticres = `ZeroWord;
138 end else begin
139 case (aluop_i)
140 `EXE_SLT_OP, `EXE_SLTU_OP: begin
141 arithmeticres = reg1_lt_reg2;
142 end
143 `EXE_ADD_OP, `EXE_ADDU_OP, `EXE_ADDI_OP, `EXE_ADDIU_OP: begin
144 arithmeticres = result_sum;
145 end
146 `EXE_SUB_OP, `EXE_SUBU_OP: begin
147 arithmeticres = result_sum;
148 end
149 `EXE_CLZ_OP: begin
150 arithmeticres = reg1_i[31] ? 0 : reg1_i[30] ? 1 : reg1_i[29] ? 2 : reg1_i[28] ? 3 : reg1_i[27] ? 4 : reg1_i[26] ? 5 : reg1_i[25] ? 6 : reg1_i[24] ? 7 : reg1_i[23] ? 8 : reg1_i[22] ? 9 : reg1_i[21] ? 10 : reg1_i[20] ? 11 : reg1_i[19] ? 12 : reg1_i[18] ? 13 : reg1_i[17] ? 14 : reg1_i[16] ? 15 : reg1_i[15] ? 16 : reg1_i[14] ? 17 : reg1_i[13] ? 18 : reg1_i[12] ? 19 : reg1_i[11] ? 20 : reg1_i[10] ? 21 : reg1_i[9] ? 22 : reg1_i[8] ? 23 : reg1_i[7] ? 24 : reg1_i[6] ? 25 : reg1_i[5] ? 26 : reg1_i[4] ? 27 : reg1_i[3] ? 28 : reg1_i[2] ? 29 : reg1_i[1] ? 30 : reg1_i[0] ? 31 : 32 ;
151 end
152 `EXE_CLO_OP: begin
153 arithmeticres = (reg1_i_not[31] ? 0 : reg1_i_not[30] ? 1 : reg1_i_not[29] ? 2 : reg1_i_not[28] ? 3 : reg1_i_not[27] ? 4 : reg1_i_not[26] ? 5 : reg1_i_not[25] ? 6 : reg1_i_not[24] ? 7 : reg1_i_not[23] ? 8 : reg1_i_not[22] ? 9 : reg1_i_not[21] ? 10 : reg1_i_not[20] ? 11 : reg1_i_not[19] ? 12 : reg1_i_not[18] ? 13 : reg1_i_not[17] ? 14 : reg1_i_not[16] ? 15 : reg1_i_not[15] ? 16 : reg1_i_not[14] ? 17 : reg1_i_not[13] ? 18 : reg1_i_not[12] ? 19 : reg1_i_not[11] ? 20 : reg1_i_not[10] ? 21 : reg1_i_not[9] ? 22 : reg1_i_not[8] ? 23 : reg1_i_not[7] ? 24 : reg1_i_not[6] ? 25 : reg1_i_not[5] ? 26 : reg1_i_not[4] ? 27 : reg1_i_not[3] ? 28 : reg1_i_not[2] ? 29 : reg1_i_not[1] ? 30 : reg1_i_not[0] ? 31 : 32) ;
154 end
155 default: begin
156 arithmeticres = `ZeroWord;
157 end
158 endcase
159 end
160 end
161
162 //取得乘法操作的操作数,如果是有符号除法且操作数是负数,那么取反加一
163 assign opdata1_mult = (((aluop_i == `EXE_MUL_OP) || (aluop_i == `EXE_MULT_OP) || (aluop_i == `EXE_MADD_OP) || (aluop_i == `EXE_MSUB_OP)) && (reg1_i[31] == 1'b1)) ? (~reg1_i + 1) : reg1_i;
164
165 assign opdata2_mult = (((aluop_i == `EXE_MUL_OP) || (aluop_i == `EXE_MULT_OP) || (aluop_i == `EXE_MADD_OP) || (aluop_i == `EXE_MSUB_OP)) && (reg2_i[31] == 1'b1)) ? (~reg2_i + 1) : reg2_i;
166
167 assign hilo_temp = opdata1_mult * opdata2_mult;
168
169 always_comb begin
170 if (rst == `RstEnable) begin
171 mulres = {`ZeroWord, `ZeroWord};
172 end else if ((aluop_i == `EXE_MULT_OP) || (aluop_i == `EXE_MUL_OP) || (aluop_i == `EXE_MADD_OP) || (aluop_i == `EXE_MSUB_OP))begin
173 if (reg1_i[31] ^ reg2_i[31] == 1'b1) begin
174 mulres = ~hilo_temp + 1;
175 end else begin
176 mulres = hilo_temp;
177 end
178 end else begin
179 mulres = hilo_temp;
180 end
181 end
182
183 //得到最新的HI、LO寄存器的值,此处要解决指令数据相关问题
184 always_comb begin
185 if (rst == `RstEnable) begin
186 {HI, LO} = {`ZeroWord, `ZeroWord};
187 end else if (mem_whilo_i == `WriteEnable) begin
188 {HI, LO} = {mem_hi_i, mem_lo_i};
189 end else if (wb_whilo_i == `WriteEnable) begin
190 {HI, LO} = {wb_hi_i, wb_lo_i};
191 end else begin
192 {HI, LO} = {hi_i, lo_i};
193 end
194 end
195
196 always_comb begin
197 stallreq = stallreq_for_madd_msub || stallreq_for_div;
198 end
199
200 //MADD、MADDU、MSUB、MSUBU指令
201 ...
202
203 //DIV、DIVU指令
204 ...
205
206 //MFHI、MFLO、MOVN、MOVZ指令
207 ...
208
209 always_comb begin
210 wd_o = wd_i;
211
212 if(((aluop_i == `EXE_ADD_OP) || (aluop_i == `EXE_ADDI_OP) || (aluop_i == `EXE_SUB_OP)) && (ov_sum == 1'b1)) begin
213 wreg_o = `WriteDisable;
214 end else begin
215 wreg_o = wreg_i;
216 end
217
218 case (alusel_i)
219 `EXE_RES_LOGIC: begin
220 wdata_o = logicout;
221 end
222 `EXE_RES_SHIFT: begin
223 wdata_o = shiftres;
224 end
225 `EXE_RES_MOVE: begin
226 wdata_o = moveres;
227 end
228 `EXE_RES_ARITHMETIC: begin
229 wdata_o = arithmeticres;
230 end
231 `EXE_RES_MUL: begin
232 wdata_o = mulres[31:0];
233 end
234 `EXE_RES_JUMP_BRANCH: begin
235 wdata_o = link_address_i;
236 end
237 default: begin
238 wdata_o = `ZeroWord;
239 end
240 endcase
241 end
242
243 always_comb begin
244 if (rst == `RstEnable) begin
245 whilo_o = `WriteDisable;
246 hi_o = `ZeroWord;
247 lo_o = `ZeroWord;
248 end else if ((aluop_i == `EXE_MULT_OP) || (aluop_i == `EXE_MULTU_OP)) begin
249 whilo_o = `WriteEnable;
250 hi_o = mulres[63:32];
251 lo_o = mulres[31:0];
252 end else if ((aluop_i == `EXE_MADD_OP) || (aluop_i == `EXE_MADDU_OP)) begin
253 whilo_o = `WriteEnable;
254 hi_o = hilo_temp1[63:32];
255 lo_o = hilo_temp1[31:0];
256 end else if ((aluop_i == `EXE_MSUB_OP) || (aluop_i == `EXE_MSUBU_OP)) begin
257 whilo_o = `WriteEnable;
258 hi_o = hilo_temp1[63:32];
259 lo_o = hilo_temp1[31:0];
260 end else if ((aluop_i == `EXE_DIV_OP) || (aluop_i == `EXE_DIVU_OP)) begin
261 whilo_o = `WriteEnable;
262 hi_o = div_result_i[63:32];
263 lo_o = div_result_i[31:0];
264 end else if (aluop_i == `EXE_MTHI_OP) begin
265 whilo_o = `WriteEnable;
266 hi_o = reg1_i;
267 lo_o = LO;
268 end else if (aluop_i == `EXE_MTLO_OP) begin
269 whilo_o = `WriteEnable;
270 hi_o = HI;
271 lo_o = reg1_i;
272 end else begin
273 whilo_o = `WriteDisable;
274 hi_o = `ZeroWord;
275 lo_o = `ZeroWord;
276 end
277 end
278
279endmodule
解读
实现了执行阶段的ALU(算术逻辑单元)功能。此外还进行内存操作。
设计意图
简要而言,这个模块的设计目的是实现CPU执行阶段的算术和逻辑运算操作。
具体而言,根据给定的操作码(aluop_i
)和操作数,对输入的寄存器值进行相应的算术和逻辑运算,并产生运算结果。
端口
-
rst
:输入复位信号 -
aluop_i
:输入的操作码 -
alusel_i
:输入的结果选择信号 -
reg1_i
:输入的第一个寄存器值 -
reg2_i
:输入的第二个寄存器值 -
wd_i
:输入的写寄存器地址 -
wreg_i
:输入的写使能信号 -
hi_i
:输入的HI寄存器值 -
lo_i
:输入的LO寄存器值 -
wb_hi_i
:回写阶段的HI寄存器值 -
wb_lo_i
:回写阶段的LO寄存器值 -
wb_whilo_i
:回写阶段的写使能信号 -
mem_hi_i
:访存阶段的HI寄存器值 -
mem_lo_i
:访存阶段的LO寄存器值 -
mem_whilo_i
:访存阶段的写使能信号 -
hilo_temp_i
:乘法操作的临时结果 -
cnt_i
:输入的计数器值 -
div_result_i
:除法模块的输出结果 -
div_ready_i
:除法模块的就绪信号 -
link_address_i
:转移指令的链接地址 -
is_in_delayslot_i
:是否处于延迟槽中 -
wd_o
:输出的写寄存器地址 -
wreg_o
:输出的写使能信号 -
wdata_o
:输出的写入寄存器的数据 -
hi_o
:输出的HI寄存器值 -
lo_o
:输出的LO寄存器值 -
whilo_o
:输出的写使能信号 -
hilo_temp_o
:输出的乘法操作的临时结果 -
cnt_o
:输出的计数器值 -
div_opdata1_o
:输出给除法模块的操作数1 -
div_opdata2_o
:输出给除法模块的操作数2 -
div_start_o
:输出的除法模块启动信号 -
signed_div_o
:输出的有符号除法信号 -
stallreq
:输出的流水线暂停请求信号
实现思路
该模块根据给定的操作码(aluop_i
)和操作数,使用组合逻辑实现了不同的算术和逻辑运算。
这个ALU模块的实现思路可以根据具体的操作码来进行解释。以下是一些可能的操作码和对应的实现思路:
-
加法(Addition):当
aluop_i
为加法操作码时,将reg1_i
和reg2_i
相加,并将结果输出到wdata_o
。 -
减法(Subtraction):当
aluop_i
为减法操作码时,将reg1_i
减去reg2_i
,并将结果输出到wdata_o
。 -
与门(AND):当
aluop_i
为与门操作码时,将reg1_i
和reg2_i
进行逻辑与操作,并将结果输出到wdata_o
。 -
或门(OR):当
aluop_i
为或门操作码时,将reg1_i
和reg2_i
进行逻辑或操作,并将结果输出到wdata_o
。 -
异或门(XOR):当
aluop_i
为异或门操作码时,将reg1_i
和reg2_i
进行逻辑异或操作,并将结果输出到wdata_o
。 -
移位(Shift):当
aluop_i
为移位操作码时,根据移位方向和位数对reg1_i
进行左移或右移操作,并将结果输出到wdata_o
。 -
比较(Comparison):当
aluop_i
为比较操作码时,将reg1_i
和reg2_i
进行比较,并根据比较结果设置条件码寄存器。 -
乘法(Multiplication):当
aluop_i
为乘法操作码时,使用乘法器模块进行乘法计算,并将结果输出到hilo_temp_o
。 -
除法(Division):当
aluop_i
为除法操作码时,将reg1_i
和reg2_i
作为操作数传递给除法器模块,并将启动信号发送给除法器模块,获取除法的结果。 -
条件分支(Conditional Branch):当
aluop_i
为条件分支操作码时,根据比较结果和条件码寄存器来确定是否进行分支跳转。 -
无条件跳转(Unconditional Jump):当
aluop_i
为无条件跳转操作码时,将link_address_i
作为目标地址进行跳转。 -
数据存储(Data Store):当
aluop_i
为数据存储操作码时,将reg1_i
的值写入内存或其他存储单元。 -
数据加载(Data Load):当
aluop_i
为数据加载操作码时,从内存或其他存储单元中加载数据,并将结果输出到wdata_o
。
这只是一些可能的操作码和对应的实现思路,具体的实现细节还需要根据具体的处理器架构和指令集来确定。实际
的ALU模块可能会包括更多的操作码,并且需要考虑处理器的时钟周期、数据通路、数据宽度等因素。
参考资料
本文与 AI 合作完成。