CPU 速通系列 3-2:DIV 模块

代码

Path src/cpu/div.sv

  1`include "defines.svh"
  2
  3module div (
  4
  5    input logic clk,
  6    input logic rst,
  7
  8    input logic        signed_div_i,
  9    input logic [31:0] opdata1_i,
 10    input logic [31:0] opdata2_i,
 11    input logic        start_i,
 12    input logic        annul_i,
 13
 14    output logic [63:0] result_o,
 15    output logic        ready_o
 16);
 17
 18    logic [32:0] div_temp;
 19    logic [ 5:0] cnt;
 20    logic [64:0] dividend;
 21    logic [ 1:0] state;
 22    logic [31:0] divisor;
 23    logic [31:0] temp_op1;
 24    logic [31:0] temp_op2;
 25
 26    assign div_temp = {1'b0, dividend[63:32]} - {1'b0, divisor};
 27
 28    always_ff @(posedge clk) begin
 29        if (rst == `RstEnable) begin
 30            state    <= `DivFree;
 31            ready_o  <= `DivResultNotReady;
 32            result_o <= {`ZeroWord, `ZeroWord};
 33        end else begin
 34            case (state)
 35                `DivFree: begin  //DivFree状态
 36                    if (start_i == `DivStart && annul_i == 1'b0) begin
 37                        if (opdata2_i == `ZeroWord) begin
 38                            state <= `DivByZero;
 39                        end else begin
 40                            state <= `DivOn;
 41                            cnt   <= 6'b000000;
 42                            if (signed_div_i == 1'b1 && opdata1_i[31] == 1'b1) begin
 43                                temp_op1 <= ~opdata1_i + 1;
 44                            end else begin
 45                                temp_op1 <= opdata1_i;
 46                            end
 47                            if (signed_div_i == 1'b1 && opdata2_i[31] == 1'b1) begin
 48                                temp_op2 <= ~opdata2_i + 1;
 49                            end else begin
 50                                temp_op2 <= opdata2_i;
 51                            end
 52                            dividend       <= {`ZeroWord, `ZeroWord};
 53                            dividend[32:1] <= temp_op1;
 54                            divisor        <= temp_op2;
 55                        end
 56                    end else begin
 57                        ready_o  <= `DivResultNotReady;
 58                        result_o <= {`ZeroWord, `ZeroWord};
 59                    end
 60                end
 61                `DivByZero: begin  //DivByZero状态
 62                    dividend <= {`ZeroWord, `ZeroWord};
 63                    state    <= `DivEnd;
 64                end
 65                `DivOn: begin  //DivOn状态
 66                    if (annul_i == 1'b0) begin
 67                        if (cnt != 6'b100000) begin
 68                            if (div_temp[32] == 1'b1) begin
 69                                dividend <= {dividend[63:0], 1'b0};
 70                            end else begin
 71                                dividend <= {div_temp[31:0], dividend[31:0], 1'b1};
 72                            end
 73                            cnt <= cnt + 1;
 74                        end else begin
 75                            if ((signed_div_i == 1'b1) && ((opdata1_i[31] ^ opdata2_i[31]) == 1'b1)) begin
 76                                dividend[31:0] <= (~dividend[31:0] + 1);
 77                            end
 78                            if ((signed_div_i == 1'b1) && ((opdata1_i[31] ^ dividend[64]) == 1'b1)) begin
 79                                dividend[64:33] <= (~dividend[64:33] + 1);
 80                            end
 81                            state <= `DivEnd;
 82                            cnt   <= 6'b000000;
 83                        end
 84                    end else begin
 85                        state <= `DivFree;
 86                    end
 87                end
 88                `DivEnd: begin  //DivEnd状态
 89                    result_o <= {dividend[64:33], dividend[31:0]};
 90                    ready_o  <= `DivResultReady;
 91                    if (start_i == `DivStop) begin
 92                        state    <= `DivFree;
 93                        ready_o  <= `DivResultNotReady;
 94                        result_o <= {`ZeroWord, `ZeroWord};
 95                    end
 96                end
 97            endcase
 98        end
 99    end
100
101endmodule

解读

实现了一个除法模块。

设计意图

简要而言,该模块旨在实现一个有符号除法器,用于执行两个32位有符号操作数的除法运算。


具体而言,该模块需要完成以下任务:

  • 接收时钟信号和复位信号

  • 接收有关除法运算的输入信号,包括被除数、除数、有符号除法标志、启动信号和终止信号

  • 根据输入信号的控制,执行除法运算

  • 输出除法运算的结果和准备信号

端口

  • clk:输入时钟信号

  • rst:输入复位信号

  • signed_div_i:输入有符号除法标志

  • opdata1_i:输入操作数1(被除数)

  • opdata2_i:输入操作数2(除数)

  • start_i:输入启动信号

  • annul_i:输入终止信号

  • result_o:输出结果

  • ready_o:输出准备信号

实现思路

这个除法模块使用了有限状态机(FSM)来执行除法运算。模块内部包含以下变量:

  • div_temp:用于存储部分商的临时变量

  • cnt:用于计数

  • dividend:存储被除数

  • state:表示当前状态

  • divisor:存储除数

  • temp_op1:临时存储操作数1

  • temp_op2:临时存储操作数2

模块在时钟上升沿时进行状态转换和计算。当复位信号为有效时,将模块状态初始化为DivFree,结果和准备信号初始化为未就绪状态,并将临时变量和寄存器清零。在其他情况下,根据当前状态进行相应的操作。

DivFree状态下,如果收到启动信号且终止信号未激活,执行以下操作:

  • 检查除数是否为零,如果是,则进入DivByZero状态,表示除以零错误。

  • 否则,进入DivOn状态,设置计数器为0,并根据有符号除法标志对操作数1和操作数2进行调整,将调整后的值存储到临时变量中,并将被除数和除数初始化为零,然后将调整后的操作数1存储到被除数中,将操作数2存储到除数中。

DivByZero状态下,将被除数设置为零,并将状态转换为DivEnd

DivOn状态下,如果终止信号未激活,执行以下操作:

  • 如果计数器不等于最大计数值(6’b100

000),执行以下操作:

  • 检查部分商的最高位是否为1,如果是,则将被除数左移一位并在最低位补零,否则,将临时变量的低32位存储到被除数的低32位,并将被除数的最高位置为1。

  • 计数器加1。

  • 否则,执行以下操作:

    • 如果是有符号除法且操作数1的符号位与操作数2的符号位不同,将被除数的低32位取反加1。

    • 如果是有符号除法且操作数1的符号位与被除数的最高位不同,将被除数的高32位取反加1。

    • 将状态转换为DivEnd,计数器清零。

DivEnd状态下,输出除法运算的结果和准备信号。如果收到终止信号,则将状态转换为DivFree,结果和准备信号重新初始化为未就绪状态。

这样,该除法模块能够根据输入的操作数和控制信号执行有符号除法运算,并输出运算结果和准备信号。

参考资料

本文与 AI 合作完成。