Verilog无符号除法器-状态机实现


 在FPGA的开发过程当中,常见的加,减,乘都可以直接用对应的符号表示,用时序逻辑实现,而除法的运算不能直接使用" /" 符号,基于当除数为2的幂次方时,可以用简单的移位符号 " >>"实现,当除数任意时,就需要使用额外的IP模块,固定的算法实现了,除法算法分为两类,分别是基于减法操作和基于乘法操作的算法。此处使用基于减法操作实现除法。

1、除法原理

 对于位宽为N位的无符号除法,被除数a除以除数b,他们的商和余数一定不会超过N位。除法计算的步骤如下:

  1. 当信号使能信号为高,将a转换成高N位为0,低N位为a的temp_a;把b转换成高N位为b,低N位为0的temp_b。初始化迭代次数i=0,进入步骤2。
  2. 当迭代次数i<N时,将temp_a左移一位,末尾补0;否则,结束迭代运算。
  3. 将左移后的temp_a与b比较,是否大于b,是则temp_a减去temp_b将且加上1,否则继续往下执行,回到步骤2,继续迭代。
  4. 将输出使能 信号置1,商为temp_a的高N位,余数为temp_a的低N位。

 将上述的四个步骤分别用状态机实现。

2、除法代码

/*******************************************************************
* -------------------  Module Specification ------------------------
    *
    *  * Name     :divider
    *
    *  * Function :无符号除法,状态机实现
    优点:可以更给数据位宽来实现不同位宽的除法运算,代码复用性高
    缺点,运算速度较慢,
    *
    *  * Input    :
    *
    *  * Output   :
    *
    *  * author   :彧芯
    *
    *  * Edit time:2021/04/25/17:01:56
    *
    *  *************************************************************/

module divider #( 
parameter N=8
)(
input clk,
input rst, 
input enable,
input [N-1:0] a,
input [N-1:0] b, 
output reg [N-1:0] yshang,
output reg [N-1:0] yyushu, 
output reg done
);
parameter S=(N<<1); 
reg[N-1:0] tempa;
reg[N-1:0] tempb;
reg[S-1:0] temp_a;
reg[S-1:0] temp_b;
reg [5:0] status;
parameter s_idle = 6'b000000;
parameter s_init = 6'b000001;
parameter s_calc1 = 6'b000010;
parameter s_calc2 = 6'b000100;
parameter s_done = 6'b001000;
 
reg [N-1:0] i;
 
always @(posedge clk)
begin
    if(rst)
        begin
            i <= 0;
            tempa <= 0;
            tempb <= 1;
            yshang <= 0;
            yyushu <= 1;
            done <= 1'b0;
            temp_a <= 0;
            temp_b <= 0;
            status <= s_idle;
        end
    else
        begin
            case (status)
            s_idle:
                begin
                    if(enable)
                        begin
                            tempa <= a;
                            tempb <= b;
                            status <= s_init;
                        end
                    else
                        begin
                            i <= 0;
                            tempa <= 0;
                            tempb <= 1;
                            yshang <= 0;
                            yyushu <= 1;
                            done <= 1'b0;
                            status <= s_idle;
                        end
                end
                
            s_init:
                begin
                    temp_a <= {{N{1'b0}},tempa}; //此处0的个数和数据位宽一样
                    temp_b <= {tempb,{N{1'b0}}};
                    status <= s_calc1;
                end
                
            s_calc1:
                begin
                    if(i < N)
                        begin
                            temp_a <= {temp_a[S-2:0],1'b0};
                            status <= s_calc2;
                        end
                    else
                        begin
                            status <= s_done;
                        end
                    
                end
                
            s_calc2:
                begin
                    if(temp_a[S-1:N] >= temp_b[S-1:N])
                        begin
                            temp_a <= temp_a - temp_b + 1'b1;
                        end
                    else
                        begin
                            temp_a <= temp_a;
                        end
                    i <= i + 1'b1;    
                    status <= s_calc1;
                end
            
            s_done:
                begin
                    yshang <= temp_a[N-1:0];
                    yyushu <= temp_a[S-1:N];
                    done <= 1'b1;
                    
                    status <= s_idle;
                end
            
            default:
                begin
                    status <= s_idle;
                end
            endcase
        end
   
end
 
 
endmodule

3、测试代码及结果

`timescale 1 ns/1 ns
module tb();

//parameters
parameter CYCLE    = 20; //!Clock cycle, 20ns, where the clock cycle can be modified
parameter RST_TIME = 3 ; //Reset time, at this point represents the reset time of 3 clock cycles
localparam N = 8;
//Clock and reset signals
reg clk  ;
reg rst_n;

//The input signal of the instantiate module
reg enable; 
reg [N-1:0] a;
reg [N-1:0] b;

//The output signal of the instantiate module
wire [N-1:0] yshang;
wire [N-1:0] yyushu; 
wire done;

//Instantiate the modules to be tested
divider#(
    .N( N )
)u_divider(
    .clk    ( clk    ),
    .rst    ( rst    ),
    .enable ( enable ),
    .a      ( a      ),
    .b      ( b      ),
    .yshang ( yshang ),
    .yyushu ( yyushu ),
    .done   ( done   )
);

//Generate the local clock, at 50MHz here
initial begin
    clk = 0;
    forever
    #(CYCLE/2)
    clk=~clk;
end

//Generate the reset signal
initial begin
    rst_n = 1;
    #2;
    rst_n = 0;
    #(CYCLE*RST_TIME);
    rst_n = 1;
end

//Assign a value to the input signal din0
integer i,j;
integer wrong_timer=0;
integer txt_file;
initial begin
    #1;
    //initialise
    enable =0;
    a = 0;
    b = 0;
    #(10.5*CYCLE);
    #(CYCLE*RST_TIME);
    //Start the assignment
    enable =1;
    a = 201;
    b = 20;
    #(CYCLE);
    enable =0;
    #(30*CYCLE);

    enable =1;
    a = 101;
    b = 13;
    #(CYCLE);
    enable =0;
    #(30*CYCLE);

    enable =1;
    a = 34;
    b = 3;
    #(CYCLE);
    enable =0;
    #(30*CYCLE);

    enable =1;
    a = 34;
    b = 100;
    #(CYCLE);
    enable =0;
    #(30*CYCLE);

    $stop();
end


endmodule

仿真结果如下:
在这里插入图片描述

4、总结

 除法器模块是FPGA应用中应用最广泛之一,该本模块采用状态机实现了位宽可定义的除法器模块,通用性较好。缺点是采用状态机实现,速度较慢,算是面积换速度的一个例子,想要实现快速的除法器,可用流水线的方式实现,后续更新。
 另外,就有无符号而言,实现的是无符号除法,有符号除法在获取到除数和被除数后,转化成无符号实现即可。

  • 2
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值