试商法除法器

一、原理介绍

过程类似于十进制除法。
对于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
<think>好的,我现在需要分析用户提供的Verilog代码,这是一个除法器模块。首先,我得理解代码的结构和功能。用户希望我详细介绍这个模块,所以我要逐步拆解各部分的作用。 首先,模块的输入输出端口。模块名为div,包含时钟clk和复位rst,这两个是常见的控制信号。接下来是signed_div_i,表示是否为有符号除法,然后是两个32位的操作数opdata1_i和opdata2_i,即被除数和除数。start_i和annul_i用于控制运算的开始和取消。输出是64位的result_o和就绪信号ready_o。 接下来是内部寄存器。dividend是65位,看起来用于存储中间结果,可能包括余数和商。divisor保存除数。div_temp是33位,可能是用于临时存储减法结果。状态机state控制模块的状态,cnt是计数器,temp_op1和temp_op2可能是处理有符号数时的临时操作数。 然后看assign语句,div_temp的计算是dividend的高32位(可能作为余数)减去divisor,这里用拼接操作符将高位补0,可能是为了处理符号扩展或者防止溢出。 状态机部分有四个状态:DivFree(空闲)、DivByZero(除零错误)、DivOn(运算中)、DivEnd(结束)。在复位时,状态初始化为DivFree,输出复位。 在DivFree状态下,当收到start信号且除数非零时,进入DivOn,开始处理操作数。这里处理有符号数,如果是有符号除法且操作数为负,则取补码转换为正数。然后将temp_op1加载到dividend的中间位,divisor加载除数。 DivOn状态下,进行商法的迭代。cnt从0到32次循环,每次根据div_temp的符号位决定下一步操作。如果div_temp为负(最高位为1),左移并补0;否则,将减法结果存入高位,左移并补1。这可能是在恢复余数法的步骤,逐位计算商。 迭代结束后,处理结果的符号。如果有符号且操作数符号不同,商取补码;余数的符号可能需要调整,根据被除数的符号和余数的符号是否一致。 最后,DivEnd状态下输出结果,商和余数组合成64位结果,并置位ready_o。当收到停止信号时,回到DivFree。 需要验证状态转移是否正确,特别是符号处理和余数调整部分。检查在DivOn状态下,cnt是否正确计数到32次,因为32位除法需要32次迭代。同时,确认有符号数的补码转换和结果符号的处理是否符合二进制补码规则。 另外,div_temp的计算是否正确,是否考虑了足够的位数避免溢出。在恢复余数法中,每次迭代需要将余数左移,然后减去除数,根据结果的正负决定商位,这里可能使用了不恢复余数法(加减交替法),需要确认代码中的步骤是否符合该算法的逻辑。 最后,检查输出结果是否正确拼接商和余数,以及ready_o信号何时有效。可能存在的风险是符号处理时的边界情况,如被除数为最小负数时取补码是否正确,但代码中使用的是32位取反加1,这可能适用于补码表示。 总结,该模块实现了一个基于状态机的迭代除法器,支持有符号和无符号除法,使用商法逐位计算商和余数,处理了除零错误和运算取消的情况,并在完成后输出结果。</think>这个Verilog模块实现了一个支持有符号/无符号的32位除法器,采用状态机控制运算流程。以下是逐步解析: $$ \begin{aligned} &\text{模块接口定义} \\ &\text{输入:clk, rst, 符号标志, 被除数, 除数, 启动/取消信号} \\ &\text{输出:64位结果(高32位余数,低32位商),就绪信号} \end{aligned} $$ ### 核心组件解析 1. **寄存器定义** - `dividend[64:0]`:65位复合寄存器 - 低32位:存储中间结果 - 高32位:存储当前余数 - 最高位(64):符号位存储 2. **关键运算单元** ```verilog assign div_temp = {1'b0, dividend[63:32]} - {1'b0, divisor}; ``` 实现余数减操作,扩展1位防止溢出 3. **状态机流程** ```mermaid graph TD A[DivFree] -->|启动&除数≠0| B[DivOn] A -->|除数为0| C[DivByZero] B -->|完成32次迭代| D[DivEnd] C --> D D -->|收到停止信号| A ``` ### 运算步骤详解 1. **预处理阶段** - 符号处理:若为有符号除法且操作数为负 $$ \text{负数转换:} temp = \sim op + 1 $$ - 初始化被除数寄存器 $$ dividend[32:1] \leftarrow temp\_op1 $$ 2. **迭代计算(32周期)** - **商判断**: $$ \text{if } div\_temp[32] = 1 \text{(差值为负)} $$ - 左移补0:`dividend <= {dividend[63:0], 1'b0}` $$ \text{else} $$ - 更新余数并左移补1:`dividend <= {div_temp, dividend[31:0], 1'b1}` 3. **后处理阶段** - **符号修正**: $$ \text{商符号:} (op1\_sign \oplus op2\_sign) \Rightarrow 取补码 $$ $$ \text{余数符号:} (op1\_sign \oplus rem\_sign) \Rightarrow 取补码 $$ ### 重要特性说明 1. **异常处理** - 除零异常直接跳转结束状态 - 支持运算中途取消(`annul_i`信号) 2. **时序控制** - 每个时钟周期完成1位计算 - 32位除法需32周期+预处理周期 3. **结果输出** ```verilog {dividend[64:33], dividend[31:0]} // 高位余数,低位商 ``` ### 应用场景示例 假设执行有符号除法 $-15/4$(补码表示): 1. 预处理:将-15转换为15,4保持原值 2. 迭代计算得到商3(0011),余数3 3. 符号修正:商符号位1(负),余数符号与被除数一致 4. 最终结果: $$ \text{商:} 1111\ 1101_2(-3), \text{余数:} 1111\ 1101_2(-3) $$ 该设计通过状态机精确控制运算流程,兼顾了有符号运算的特殊处理,是典型的硬件除法器实现方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

暴风雨中的白杨

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

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

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

打赏作者

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

抵扣说明:

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

余额充值