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模块的实现思路可以根据具体的操作码来进行解释。以下是一些可能的操作码和对应的实现思路:

  1. 加法(Addition):当aluop_i为加法操作码时,将reg1_ireg2_i相加,并将结果输出到wdata_o

  2. 减法(Subtraction):当aluop_i为减法操作码时,将reg1_i减去reg2_i,并将结果输出到wdata_o

  3. 与门(AND):当aluop_i为与门操作码时,将reg1_ireg2_i进行逻辑与操作,并将结果输出到wdata_o

  4. 或门(OR):当aluop_i为或门操作码时,将reg1_ireg2_i进行逻辑或操作,并将结果输出到wdata_o

  5. 异或门(XOR):当aluop_i为异或门操作码时,将reg1_ireg2_i进行逻辑异或操作,并将结果输出到wdata_o

  6. 移位(Shift):当aluop_i为移位操作码时,根据移位方向和位数对reg1_i进行左移或右移操作,并将结果输出到wdata_o

  7. 比较(Comparison):当aluop_i为比较操作码时,将reg1_ireg2_i进行比较,并根据比较结果设置条件码寄存器。

  8. 乘法(Multiplication):当aluop_i为乘法操作码时,使用乘法器模块进行乘法计算,并将结果输出到hilo_temp_o

  9. 除法(Division):当aluop_i为除法操作码时,将reg1_ireg2_i作为操作数传递给除法器模块,并将启动信号发送给除法器模块,获取除法的结果。

  10. 条件分支(Conditional Branch):当aluop_i为条件分支操作码时,根据比较结果和条件码寄存器来确定是否进行分支跳转。

  11. 无条件跳转(Unconditional Jump):当aluop_i为无条件跳转操作码时,将link_address_i作为目标地址进行跳转。

  12. 数据存储(Data Store):当aluop_i为数据存储操作码时,将reg1_i的值写入内存或其他存储单元。

  13. 数据加载(Data Load):当aluop_i为数据加载操作码时,从内存或其他存储单元中加载数据,并将结果输出到wdata_o

这只是一些可能的操作码和对应的实现思路,具体的实现细节还需要根据具体的处理器架构和指令集来确定。实际

的ALU模块可能会包括更多的操作码,并且需要考虑处理器的时钟周期、数据通路、数据宽度等因素。

参考资料

本文与 AI 合作完成。