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语句进行处理,并将生成的控制信号赋值给输出端口。