CPU 速通系列 2-1:ID 模块
代码
1`include "defines.svh"
2
3module id (
4
5 input logic rst,
6 input logic [`InstAddrBus] pc_i,
7 input logic [ `InstBus] inst_i,
8
9 //处于执行阶段的指令要写入的目的寄存器信息
10 input logic ex_wreg_i,
11 input logic [ `RegBus] ex_wdata_i,
12 input logic [`RegAddrBus] ex_wd_i,
13
14 //处于访存阶段的指令要写入的目的寄存器信息
15 input logic mem_wreg_i,
16 input logic [ `RegBus] mem_wdata_i,
17 input logic [`RegAddrBus] mem_wd_i,
18
19 input logic [`RegBus] reg1_data_i,
20 input logic [`RegBus] reg2_data_i,
21
22 //如果上一条指令是转移指令,那么下一条指令在译码的时候is_in_delayslot为true
23 input logic is_in_delayslot_i,
24
25 //送到regfile的信息
26 output logic reg1_read_o,
27 output logic reg2_read_o,
28 output logic [`RegAddrBus] reg1_addr_o,
29 output logic [`RegAddrBus] reg2_addr_o,
30
31 //送到执行阶段的信息
32 output logic [ `AluOpBus] aluop_o,
33 output logic [ `AluSelBus] alusel_o,
34 output logic [ `RegBus] reg1_o,
35 output logic [ `RegBus] reg2_o,
36 output logic [`RegAddrBus] wd_o,
37 output logic wreg_o,
38
39 output logic next_inst_in_delayslot_o,
40
41 output logic branch_flag_o,
42 output logic [`RegBus] branch_target_address_o,
43 output logic [`RegBus] link_addr_o,
44 output logic is_in_delayslot_o,
45
46 output logic stallreq
47);
48
49 logic [5:0] op;
50 logic [4:0] op2;
51 logic [5:0] op3;
52 logic [4:0] op4;
53 logic [`RegBus] imm;
54 logic instvalid;
55 logic [`RegBus] pc_plus_8;
56 logic [`RegBus] pc_plus_4;
57 logic [`RegBus] imm_sll2_signedext;
58
59 assign op = inst_i[31:26];
60 assign op2 = inst_i[10:6];
61 assign op3 = inst_i[5:0];
62 assign op4 = inst_i[20:16];
63 assign pc_plus_8 = pc_i + 8;
64 assign pc_plus_4 = pc_i + 4;
65 assign imm_sll2_signedext = {{14{inst_i[15]}}, inst_i[15:0], 2'b00};
66 assign stallreq = `NoStop;
67
68 always_comb begin
69 if (rst == `RstEnable) begin
70 aluop_o = `EXE_NOP_OP;
71 alusel_o = `EXE_RES_NOP;
72 wd_o = `NOPRegAddr;
73 wreg_o = `WriteDisable;
74 instvalid = `InstValid;
75 reg1_read_o = 1'b0;
76 reg2_read_o = 1'b0;
77 reg1_addr_o = `NOPRegAddr;
78 reg2_addr_o = `NOPRegAddr;
79 imm = 32'h0;
80 link_addr_o = `ZeroWord;
81 branch_target_address_o = `ZeroWord;
82 branch_flag_o = `NotBranch;
83 next_inst_in_delayslot_o = `NotInDelaySlot;
84 end else begin
85 aluop_o = `EXE_NOP_OP;
86 alusel_o = `EXE_RES_NOP;
87 wd_o = inst_i[15:11];
88 wreg_o = `WriteDisable;
89 instvalid = `InstInvalid;
90 reg1_read_o = 1'b0;
91 reg2_read_o = 1'b0;
92 reg1_addr_o = inst_i[25:21];
93 reg2_addr_o = inst_i[20:16];
94 imm = `ZeroWord;
95 link_addr_o = `ZeroWord;
96 branch_target_address_o = `ZeroWord;
97 branch_flag_o = `NotBranch;
98 next_inst_in_delayslot_o = `NotInDelaySlot;
99 case (op)
100 `EXE_SPECIAL_INST: begin
101 case (op2)
102 5'b00000: begin
103 case (op3)
104 `EXE_OR: begin
105 ...
106 end
107 `EXE_AND: begin
108 ...
109 end
110 `EXE_XOR: begin
111 ...
112 end
113 `EXE_NOR: begin
114 ...
115 instvalid = `InstValid;
116 end
117 `EXE_SLLV: begin
118 ...
119 instvalid = `InstValid;
120 end
121 `EXE_SRLV: begin
122 ...
123 instvalid = `InstValid;
124 end
125 `EXE_SRAV: begin
126 ...
127 instvalid = `InstValid;
128 end
129 `EXE_MFHI: begin
130 ...
131 instvalid = `InstValid;
132 end
133 `EXE_MFLO: begin
134 ...
135 instvalid = `InstValid;
136 end
137 `EXE_MTHI: begin
138 ...
139 end
140 `EXE_MTLO: begin
141 ...
142 end
143 `EXE_MOVN: begin
144 ...
145 end
146 `EXE_MOVZ: begin
147 ...
148 end
149 `EXE_SLT: begin
150 ...
151 end
152 `EXE_SLTU: begin
153 ...
154 end
155 `EXE_ADD: begin
156 ...
157 end
158 `EXE_ADDU: begin
159 ...
160 end
161 `EXE_SUB: begin
162 ...
163 end
164 `EXE_SUBU: begin
165 ...
166 end
167 `EXE_MULT: begin
168 ...
169 end
170 `EXE_MULTU: begin
171 ...
172 end
173 `EXE_DIV: begin
174 ...
175 end
176 `EXE_DIVU: begin
177 ...
178 end
179 `EXE_JR: begin
180 ...
181 end
182 `EXE_JALR: begin
183 wreg_o = `WriteEnable;
184 aluop_o = `EXE_JALR_OP;
185 alusel_o = `EXE_RES_JUMP_BRANCH;
186 reg1_read_o = 1'b1;
187 reg2_read_o = 1'b0;
188 wd_o = inst_i[15:11];
189 link_addr_o = pc_plus_8;
190
191 branch_target_address_o = reg1_o;
192 branch_flag_o = `Branch;
193
194 next_inst_in_delayslot_o = `InDelaySlot;
195 instvalid = `InstValid;
196 end
197 default: begin
198 end
199 endcase
200 end
201 default: begin
202 end
203 endcase
204 end
205 `EXE_ORI: begin //ORI指令
206 ...
207 end
208 `EXE_ANDI: begin
209 ...
210 end
211 `EXE_XORI: begin
212 ...
213 end
214 `EXE_LUI: begin
215 ...
216 end
217 `EXE_SLTI: begin
218 ...
219 end
220 `EXE_SLTIU: begin
221 ...
222 end
223 `EXE_ADDI: begin
224 ...
225 end
226 `EXE_ADDIU: begin
227 ...
228 end
229 `EXE_J: begin
230 ...
231 end
232 `EXE_JAL: begin
233 ...
234 end
235 `EXE_BEQ: begin
236 ...
237 end
238 `EXE_BGTZ: begin
239 ...
240 end
241 `EXE_BLEZ: begin
242 ...
243 end
244 `EXE_BNE: begin
245 wreg_o = `WriteDisable;
246 aluop_o = `EXE_BLEZ_OP;
247 alusel_o = `EXE_RES_JUMP_BRANCH;
248 reg1_read_o = 1'b1;
249 reg2_read_o = 1'b1;
250 instvalid = `InstValid;
251 if (reg1_o != reg2_o) begin
252 branch_target_address_o = pc_plus_4 + imm_sll2_signedext;
253 branch_flag_o = `Branch;
254 next_inst_in_delayslot_o = `InDelaySlot;
255 end
256 end
257 `EXE_REGIMM_INST: begin
258 case (op4)
259 `EXE_BGEZ: begin
260 ...
261 end
262 `EXE_BGEZAL: begin
263 ...
264 end
265 `EXE_BLTZ: begin
266 ...
267 end
268 `EXE_BLTZAL: begin
269 ...
270 end
271 default: begin
272 end
273 endcase
274 end
275 `EXE_SPECIAL2_INST: begin
276 case (op3)
277 `EXE_CLZ: begin
278 wreg_o = `WriteEnable;
279 aluop_o = `EXE_CLZ_OP;
280 alusel_o = `EXE_RES_ARITHMETIC;
281 reg1_read_o = 1'b1;
282 reg2_read_o = 1'b0;
283 instvalid = `InstValid;
284 end
285 `EXE_CLO: begin
286 ...
287 end
288 `EXE_MUL: begin
289 ...
290 end
291 `EXE_MADD: begin
292 ...
293 end
294 `EXE_MADDU: begin
295 ...
296 end
297 `EXE_MSUB: begin
298 ...
299 end
300 `EXE_MSUBU: begin
301 ...
302 end
303 default: begin
304 end
305 endcase //EXE_SPECIAL_INST2 case
306 end
307 default: begin
308 end
309 endcase //case op
310
311 if (inst_i[31:21] == 11'b00000000000) begin
312 if (op3 == `EXE_SLL) begin
313 wreg_o = `WriteEnable;
314 aluop_o = `EXE_SLL_OP;
315 alusel_o = `EXE_RES_SHIFT;
316 reg1_read_o = 1'b0;
317 reg2_read_o = 1'b1;
318 imm[4:0] = inst_i[10:6];
319 wd_o = inst_i[15:11];
320 instvalid = `InstValid;
321 end else if (op3 == `EXE_SRL) begin
322 ...
323 end else if (op3 == `EXE_SRA) begin
324 ...
325 end
326 end
327
328 end //if
329 end //always
330
331
332 always_comb begin
333 if (rst == `RstEnable) begin
334 reg1_o = `ZeroWord;
335 end else if ((reg1_read_o == 1'b1) && (ex_wreg_i == 1'b1) && (ex_wd_i == reg1_addr_o)) begin
336 reg1_o = ex_wdata_i;
337 end else if((reg1_read_o == 1'b1) && (mem_wreg_i == 1'b1) && (mem_wd_i == reg1_addr_o)) begin
338 reg1_o = mem_wdata_i;
339 end else if (reg1_read_o == 1'b1) begin
340 reg1_o = reg1_data_i;
341 end else if (reg1_read_o == 1'b0) begin
342 reg1_o = imm;
343 end else begin
344 reg1_o = `ZeroWord;
345 end
346 end
347
348 always_comb begin
349 if (rst == `RstEnable) begin
350 reg2_o = `ZeroWord;
351 end else if ((reg2_read_o == 1'b1) && (ex_wreg_i == 1'b1) && (ex_wd_i == reg2_addr_o)) begin
352 reg2_o = ex_wdata_i;
353 end else if((reg2_read_o == 1'b1) && (mem_wreg_i == 1'b1) && (mem_wd_i == reg2_addr_o)) begin
354 reg2_o = mem_wdata_i;
355 end else if (reg2_read_o == 1'b1) begin
356 reg2_o = reg2_data_i;
357 end else if (reg2_read_o == 1'b0) begin
358 reg2_o = imm;
359 end else begin
360 reg2_o = `ZeroWord;
361 end
362 end
363
364 always_comb begin
365 if (rst == `RstEnable) begin
366 is_in_delayslot_o = `NotInDelaySlot;
367 end else begin
368 is_in_delayslot_o = is_in_delayslot_i;
369 end
370 end
371
372endmodule
解读
实现了指令译码模块。
设计意图
该模块的设计目的是将输入的指令进行译码,并根据指令类型生成相应的控制信号。
具体而言,该模块的主要任务如下:
-
对输入指令进行解析,提取操作码和操作数等信息。
-
根据操作码和操作数生成相应的控制信号,包括ALU操作类型、ALU选择类型、寄存器读取地址、写入寄存器控制信号等。
-
根据指令类型和操作数进行条件判断和分支处理,生成分支目标地址、分支标志等控制信号。
-
处理特殊指令,如移位指令、逻辑操作指令等。
端口
-
clk
:输入时钟信号 -
…
实现思路
该模块首先通过assign语句从输入的指令中提取出操作码和操作数等信息,然后使用always_comb块对这些信息进行处理和判断,生成相应的控制信号。
在always_comb块中,首先根据复位信号rst的状态进行初始化操作,设置默认的控制信号和状态。然后根据操作码op的不同取值,进一步判断指令的类型和具体操作,并生成相应的控制信号。
对于特殊指令,如移位指令、逻辑操作指令等,使用case语句进行处理,并根据操作结果设置相应的控制信号。
最后,根据生成的控制信号,将其赋值给输出端口,完成指令译码过程。
整体上,该模块通过解析指令并生成控制信号,实现了对指令进行译码的功能,为后续的执行阶段提供必要的控制信息。
伪代码
以下是一个示例的指令译码模块的伪代码实现,用于展示思路和代码框架结构。
1module InstructionDecoder(
2 input clk,
3 input reset,
4 input [31:0] instruction,
5 output reg [2:0] aluOp,
6 output reg [1:0] aluSel,
7 output reg [4:0] regReadAddr,
8 output reg [4:0] regWriteAddr,
9 output reg regWriteEnable,
10 output reg branchFlag,
11 output reg [31:0] branchTarget
12);
13
14 always @(posedge clk or posedge reset) begin
15 if (reset) begin
16 // 初始化操作
17 aluOp <= 0;
18 aluSel <= 0;
19 regReadAddr <= 0;
20 regWriteAddr <= 0;
21 regWriteEnable <= 0;
22 branchFlag <= 0;
23 branchTarget <= 0;
24 end else begin
25 // 解析指令
26 assign opcode = instruction[31:26];
27 assign rs = instruction[25:21];
28 assign rt = instruction[20:16];
29 assign rd = instruction[15:11];
30 assign funct = instruction[5:0];
31
32 // 生成控制信号
33 case (opcode)
34 'b000000: begin
35 // R-type指令
36 aluOp <= funct;
37 aluSel <= 0;
38 regReadAddr <= rs;
39 regWriteAddr <= rd;
40 regWriteEnable <= 1;
41 branchFlag <= 0;
42 branchTarget <= 0;
43 end
44 'b100011: begin
45 // LW指令
46 aluOp <= 0;
47 aluSel <= 0;
48 regReadAddr <= rs;
49 regWriteAddr <= rt;
50 regWriteEnable <= 1;
51 branchFlag <= 0;
52 branchTarget <= 0;
53 end
54 'b101011: begin
55 // SW指令
56 aluOp <= 0;
57 aluSel <= 0;
58 regReadAddr <= rs;
59 regWriteAddr <= 0;
60 regWriteEnable <= 0;
61 branchFlag <= 0;
62 branchTarget <= 0;
63 end
64 'b000100: begin
65 // BEQ指令
66 aluOp <= 1;
67 aluSel <= 1;
68 regReadAddr <= rs;
69 regWriteAddr <= 0;
70 regWriteEnable <= 0;
71 branchFlag <= 1;
72 branchTarget <= instruction[15:0];
73 end
74 // 其他指令的处理...
75 endcase
76 end
77 end
78
79endmodule
上述伪代码展示了一个简化的指令译码模块,使用了always块来处理时钟和复位信号,通过assign语句解析指令并生成相应的控制信号。对于不同的指令类型,使用case语句进行处理,并将生成的控制信号赋值给输出端口。