试商法除法器

一、原理介绍

过程类似于十进制除法。
对于32位的除法,至少需要32个时钟周期,才能得到除法的结果。
在这里插入图片描述
设被除数是m, 除数是n, 商保存在s中, 被除数的位数是k, 计算步骤如下:

  1. 取出被除数的最高位m[k], 使用被除数的最高位减去除数n ,如果结果大于等于0, 则商的s[k] 为1,反之为0
  2. 如果上一步得到的结果为0,表示当前被减数小于除数,则取出被除数剩下的值的最高位m[k-1],与当前被减数组合作为下一轮被减数。如果上一轮得到的结果是1,表示当前被减数大于除数,则利用上一轮中减法的结果与被除数剩下的值的最高位m[k-1]组合作为下一轮的被减数。然后,设置k等于k-1。
  3. 新的被减数减去除数,如果结果大于等于0,则商的s[k]为1,否则s[k]为0,后面的步骤依次重复,直到k等于0。

二、状态机实现

2.1 状态转移图

在这里插入图片描述
部分状态介绍:

  1. idle
  2. divbyzero: 除数为0。
  3. divinit: 进行有符号相关的处理,以及相关信号初始化赋值。
  4. divon: 进行试商法除法。
  5. divend: 除法运算结束。

2.2 代码

2.2.1 div.sv

/**************************************
@ filename    : div.sv
@ author      : yyrwkk
@ create time : 2024/09/09 11:18:46
@ version     : v1.0.0
**************************************/
module div # (
    parameter N_WIDTH  =  32  
)(
    input  logic                  i_clk          ,
    input  logic                  i_rst_n        ,
 
    input  logic                  i_divsigned    ,

    input  logic                  i_divstart     ,
    input  logic [N_WIDTH-1:0]    i_dividend     ,
    input  logic [N_WIDTH-1:0]    i_divisor      ,

    output logic [N_WIDTH-1:0]    o_quotient     ,
    output logic [N_WIDTH-1:0]    o_remainder    ,
    output logic                  o_done_vld     ,

    output logic                  o_ready             
);

localparam s_idle      = 3'd0;
localparam s_divinit   = 3'd1;
localparam s_divbyzero = 3'd2;
localparam s_divon     = 3'd3;
localparam s_divend    = 3'd4;

logic [2:0]  curr_state       ;
logic [2:0]  next_state       ;

logic [4:0]  cnt              ;

logic [31:0] dividend_temp    ;
logic [31:0] divisor_temp     ;

logic [31:0] dividend         ;
logic [31:0] divisor          ;
logic        div_signed       ;
logic        dividend_signed  ;
logic        divisor_signed   ;

logic [31:0] div_temp         ;
logic [32:0] div_sub          ;

logic [31:0] quotient         ;
logic [31:0] remainder        ;


assign dividend_temp = (i_divsigned & i_dividend[31]) ? (~i_dividend + 1'b1) : i_dividend;
assign divisor_temp  = (i_divsigned & i_divisor[31]) ? (~i_divisor + 1'b1) : i_divisor;


always_ff @( posedge i_clk or negedge i_rst_n ) begin
    if(!i_rst_n ) begin
        dividend   <= 'b0;
        divisor    <= 'b0;
        div_signed <= 'b0;
    end else begin
        if( (o_ready == 1'b1 ) && (i_divstart == 1'b1 ) ) begin
            dividend   <= dividend_temp;
            divisor    <= divisor_temp;
            div_signed <= i_divsigned;
            dividend_signed <= i_dividend[31];
            divisor_signed  <= i_divisor[31];
        end else begin
            dividend   <= dividend   ;
            divisor    <= divisor    ;
            div_signed <= div_signed ;
            dividend_signed <= dividend_signed;
            divisor_signed  <= divisor_signed ;
        end
    end
end

always_ff@(posedge i_clk or negedge i_rst_n ) begin
    if( !i_rst_n ) begin
        curr_state <= s_idle;
    end else begin
        curr_state <= next_state;
    end
end

always_comb begin
    case(curr_state )
    s_idle     : begin
        if( (o_ready == 1'b1 ) && (i_divstart == 1'b1 )) begin
            if( i_divisor == 'b0 ) begin
                next_state = s_divbyzero;
            end else begin
                next_state = s_divinit;
            end
        end else begin
            next_state = s_idle;
        
`include "defines.v" module div ( input wire clk, input wire rst, // 是否是有符号除法 input wire signed_div_i, // 被除数,除数 input wire[31:0] opdata1_i, input wire[31:0] opdata2_i, // 开始,取消信号 input wire start_i, input wire annul_i, output reg[63:0] result_o, output reg ready_o ); reg[64:0] dividend; // 低32位保存被除数[31:k+1],中间结果[k:0] // 高32位[63:32]保存被减数 reg[31:0] divisor; // 除数 wire[32:0] div_temp; // 被减数 - 除数 reg[1:0] state; reg[5:0] cnt; // 商法进行了几轮,32结束 reg[31:0] temp_op1; reg[31:0] temp_op2; assign div_temp = {1'b0,dividend[63:32]} - {1'b0,divisor}; // 状态机 Divfree:空闲 DivByZero:除数是0 DivOn:除法运算进行中 DivEnd:除法运算结束 always @(posedge clk ) begin if (rst == `RstEnable) begin state <= `DivFree; ready_o <= `DivResultNotReady; result_o <= {`ZeroWord,`ZeroWord}; end else begin case (state) `DivFree: begin if (start_i == `DivStart && annul_i == 1'b0) begin if (opdata2_i == `ZeroWord) begin state <= `DivByZero; end else begin state <= `DivOn; cnt <= 5'b00000; if (signed_div_i == 1'b1 && opdata1_i[31] == 1'b1) begin temp_op1 = ~opdata1_i + 1; end else begin temp_op1 = opdata1_i; end if (signed_div_i == 1'b1 && opdata2_i[31] == 1'b1) begin temp_op2 = ~opdata2_i + 1; end else begin temp_op2 = opdata2_i; end dividend <= {`ZeroWord,`ZeroWord}; dividend[32:1] <= temp_op1; divisor <= temp_op2; end end else begin // 没开始除法运算 ready_o <= `DivResultNotReady; result_o <= {`ZeroWord,`ZeroWord}; end end `DivByZero: begin dividend <= {`ZeroWord,`ZeroWord}; state <= `DivEnd; end `DivOn: begin if (annul_i == 1'b0) begin if (cnt != 6'b100000) begin if (div_temp[32] == 1'b1) begin // 结果小于 0,将dividend左移一位,将除数中没有参与运算的最高位加入被减数中,同时将0加入结果 dividend <= {dividend[63:0],1'b0}; end else begin // 结果大于 0,将减法结果和被除数中没有参与运算的最高位加入到下一次迭代的被减数中,同时将1加入结果 dividend <= {div_temp[31:0],dividend[31:0],1'b1}; end cnt <= cnt + 1; end else begin // 商法结束 if (signed_div_i == 1'b1 && opdata1_i[31] ^ opdata2_i[31] == 1'b1) begin dividend[31:0] <= ~dividend[31:0] + 1; end if(signed_div_i == 1'b1 && opdata1_i[31] ^ dividend[64] == 1'b1) begin dividend[64:33] <= ~dividend[64:33] + 1; end state <= `DivEnd; cnt <= 6'b000000; end end else begin //取消除法 state <= `DivFree; end end `DivEnd: begin result_o <= {dividend[64:33],dividend[31:0]}; ready_o <= `DivResultReady; if (start_i == `DivStop) begin state <= `DivFree; ready_o <= `DivResultNotReady; result_o <= {`ZeroWord,`ZeroWord}; end end endcase end end endmodule
最新发布
03-11
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

暴风雨中的白杨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值