verilog 实现8位无符号除法器

本文介绍了如何使用Verilog HDL语言实现8位无符号除法器,由于Verilog中的除法运算符限制,通常通过减法算法来实现除法。文章详细阐述了除法器的工作原理,类似于手算除法过程,并提供了组合逻辑和时序逻辑两种实现方式的代码,分别展示了无延时和存在延时的仿真结果。
摘要由CSDN通过智能技术生成
一、算法(非原创)

在Verilog HDL语言中虽然有除的运算指令,但是除运算符中的除数必须是2的幂,因此无法实现除数为任意整数的除法,很大程度上限制了它的使用领域。并且多数综合工具对于除运算指令不能综合出令人满意的结果,有些甚至不能给予综合。即使可以综合,也需要比较多的资源。

最简单的方法就是减法实现除法器(比如十进制中的a/b,可先比较a与b的大小,如果a>b,则商加1,a<=a-b,再进行比较大小,直到a<b,商不变,余数为a)。但这种方式通常速度比较慢,实际上更快速的方法是模拟手算除法的过程:
在这里插入图片描述
实际上上图演示的是二进制除法运算,跟十进制的没多大区别,只不过十进制的除法商的每一位都有0-9十种可能,因此如果采用十进制来编写除法器需要采用二分法逐个判断商的每一位上的数字,而二进制因为只有两种可能所以不需要那么麻烦(但其实两者的本质是一样的,算法的时间复杂度相同)
流程图:
在这里插入图片描述
根据以上所述的32位除法器的算法原理,下面来实现一下8位除法器。

二、代码实现

1、组合逻辑方式实现

  • RTL代码
module div1  
#(
parameter DATAWIDTH=8
)
(  
        a,   
        b,  
        enable,
        shang,  
        yushu
);  
 
 input [DATAWIDTH-1:0] a;            
 input [DATAWIDTH-1:0] b;            
 input enable;       
 output  shang;      
 output  yushu;            
             
wire enable;                
reg [DATAWIDTH-1:0] shang;    
reg [DATAWIDTH-1:0] yushu;                

reg [DATAWIDTH-1:0] tempa;  
reg [DATAWIDTH-1:0] tempb;  
reg [2*DATAWIDTH-1:0] temp_a;  
reg [2*DATAWIDTH-1:0] temp_b;  
  
integer i;  
  
always @(a or b)  
begin  
    tempa <= a;  
    tempb <= b;  
end  
  
always @(tempa or tempb)  
begin  
if(enable)
  begin
    temp_a = {{DATAWIDTH{1'b0}},tempa};  
    temp_b = {tempb,{DATAWIDTH{1'b0}}};  
    for(i = 0;i < DATAWIDTH;i = i + 1)  
        begin  
            temp_a = temp_a<<1;
            if(temp_a>= temp_b)  
                temp_a = temp_a - temp_b + 1'b1;  
            else  
                temp_a = temp_a;  
        end  
  
    shang = temp_a[DATAWIDTH-1:0];  
    yushu = temp_a[DATAWIDTH*2-1:DATAWIDTH]; 
  end
end  
  
endmodule
  • 仿真程序
`timescale 1ns/1ns  
  
module tb_div1();  
  
    parameter DATAWIDTH = 8;
    reg [DATAWIDTH-1:0] a;  
    reg [DATAWIDTH-1:0] b; 
    reg enable; 
    wire [DATAWIDTH-1:0] shang;  
    wire [DATAWIDTH-1:0] yushu;  

initial  
begin  
    enable=1;
    #10 a = 15;  
            b = 6;  
          
    #10 a = 165;  
        b = 30;  
          
    #10 a = 250;  
        b =60;     
     
     #10 a = 63;      
             b = 7;   
                      
     #10 a = 80;     
         b = 9;      
                      
     #10 a = 130;     
         b =50; 
         
      $stop;       
end  
  
div1 #(
    .DATAWIDTH  ( DATAWIDTH  ))
u1 (  
    .a (a),  
    .b (b),  
    .enable(enable), 
    .shang (shang),  
    .yushu (yushu)
);  
  
endmodule
  • 仿真结果

在这里插入图片描述
可以看出,由于是组合逻辑,因此输入与输出数据之间没有延时!!!

2、时序逻辑方式实现

  • RTL代码

`timescale 1ns/1ps


module div_fsm 
#(
parameter DATAWIDTH=8
)
(
  input                       clk      ,
  input                       rstn    ,
  input                       en   ,
  output  wire                ready    ,
  input  [DATAWIDTH-1:0]      dividend ,
  input  [DATAWIDTH-1:0]      divisor  ,
  output wire [DATAWIDTH-1:0] quotient ,
  output wire [DATAWIDTH-1:0] remainder,
  output wire                 vld_out
);

parameter IDLE =0;
parameter SUB  =1;
parameter SHIFT=2 ;
parameter DONE =3;

reg [DATAWIDTH*2-1:0] dividend_e ;
reg [DATAWIDTH*2-1:0] divisor_e  ;
reg [DATAWIDTH-1:0]   quotient_e ;
reg [DATAWIDTH-1:0]   remainder_e;


reg [1:0] current_state,next_state;

reg [DATAWIDTH-1:0] count;





always@(posedge clk or negedge rstn)
  if(!rstn) current_state <= IDLE;
  else current_state <= next_state;

always @(*) begin
  next_state <= 2'bx;
  case(current_state)
    IDLE: if(en) next_state <= SUB;
	      else next_state <= IDLE;
    SUB:  next_state <= SHIFT;
    SHIFT:if(count < DATAWIDTH) next_state <= SUB;
          else next_state <= DONE;
    DONE: next_state <= IDLE;
  endcase
end

 
always@(posedge clk or negedge rstn) begin
 if(!rstn)begin
   dividend_e  <= 0;
   divisor_e   <= 0;
   quotient_e  <= 0;
   remainder_e <= 0;
   count       <= 0;
 end 
 else begin 
  case(current_state)
  IDLE:begin
         dividend_e <= {{DATAWIDTH{1'b0}},dividend};
	     divisor_e  <= {divisor,{DATAWIDTH{1'b0}}};
       end
  SUB:begin
        if(dividend_e>=divisor_e)begin
		   dividend_e <= dividend_e-divisor_e+1'b1;
         end
	    else begin
		   dividend_e <= dividend_e;
        end
      end
  SHIFT:begin
	   if(count<DATAWIDTH)begin
	     dividend_e <= dividend_e<<1;
	     count      <= count+1;		 
       end
	   else begin
	     quotient_e<= dividend_e[DATAWIDTH-1:0];
		 remainder_e <= dividend_e[DATAWIDTH*2-1:DATAWIDTH];
       end
     end
  DONE:begin
		count       <= 0;
  end	 
  endcase
 end
end
  
assign quotient  = quotient_e;
assign remainder = remainder_e;

assign ready=(current_state==IDLE)? 1'b1:1'b0;
assign vld_out=(current_state==DONE)? 1'b1:1'b0;
	       
endmodule
  • 仿真程序
`timescale 1ns/1ps

module div_fsm_tb();

parameter DATAWIDTH = 8;

reg  clk;
reg  rstn;       
reg  en;    
wire ready; 
wire vld_out;    
reg  [DATAWIDTH-1:0]    dividend; 
reg  [DATAWIDTH-1:0]    divisor;
wire [DATAWIDTH-1:0]    quotient;
wire [DATAWIDTH-1:0]    remainder;

always #1 clk = ~clk;

integer i;

initial begin
  clk = 1;
  rstn = 1;
  en = 0;
  #2 rstn = 0; 
  #2 rstn = 1;
  repeat(2) @(posedge clk);

  for(i=0;i<10;i=i+1) begin
        en <= 1;
        dividend <= $urandom()%200;
        divisor  <= $urandom()%100;
        wait (ready == 1);
        wait (vld_out == 1);
  end


end


div_fsm #(
    .DATAWIDTH                     ( DATAWIDTH  ))
     u1(
            .clk                   ( clk        ),
            .rstn                  ( rstn       ),
            .en                    ( en         ),
            .ready                 ( ready      ),
            .dividend              ( dividend   ),
            .divisor               ( divisor    ),
            .quotient              ( quotient   ),
            .remainder             ( remainder  ),
            .vld_out               ( vld_out    )
);


endmodule
  • 仿真结果

在这里插入图片描述
可以看出,由于使用的是时序逻辑,因此输出与输入数据之间有一定的延时,该程序中,延时为20个时钟周期!!!

### 回答1: 32位无符号除法器是一种用于计算器、数字信号处理器等电子工程中的数字芯片。它可以执行32位数的无符号除法运算,无符号表示运算中不考虑正负号。在Verilog实现32位无符号除法器需要以下步骤: 第一步是输入寄存器,并设置初始值。在该寄存器中输入需要进行除法运算的两个32位无符号整数B和A,其中被除数A为32位,除数B为32位。 第二步是进行除法操作,可以使用“非规范化除法法”或“高精度除法法”等算法。这里我们以“非规范化除法法”为例进行说明。首先将余数寄存器初始化为被除数A的值,然后除以除数B,如果余数寄存器的值小于除数B,则继续左移一位,将除数B左移一位,然后再次减去除数B。一直重复这个过程,直到余数寄存器的值大于等于除数B为止,此时将商寄存器的值左移一位,最后将商寄存器加上1。 第三步是输出商寄存器的结果。商寄存器存储的即为除法运算的结果,是32位无符号整数。 综上所述,我们可以在Verilog实现32位无符号除法器,它能够进行32位无符号整数A/B的除法操作,并输出商寄存器的结果。这种除法器可以用于数字计算器、数字信号处理器等电子工程中的数字芯片中。 ### 回答2: 32位无符号除法器是一种数字电路设计,可以将32位无符号整数除以任意不为零的32位无符号数。在Verilog语言中,可以使用模块化方法实现32位无符号除法器。 首先,需要定义输入输出端口,包括32位除数dividend、32位除数divisor和32位商quotient。接着,使用Verilog代码实现除法运算的算法,例如时间复杂度为O(n)的16位位移除法算法。在该算法中,先将除数左移直至其最高位小于等于被除数的最高位,然后将被除数减去左移后的除数,直到被除数小于除数,商的每一位由减法的次数确定。 最后,需要注意除数不能为零的情况,可以使用if语句判断并将商赋值为全零。此外,在实现中需要注意数据类型的选择,整数需要用无符号类型表示,如"reg [31:0] dividend"。 ### 回答3: 32位无符号除法器是一种能够将两个32位无符号整数相除的硬件电路。相对于软件实现,在硬件中实现除法运算可以获得更高的速度和性能,适用于需要快速且高效处理除法运算的场合。 在verilog语言中实现32位无符号除法器,需要写出divisor、dividend、quotient和remainder四个信号的代码,并通过实例化模块实现调用和传输数据。在计算机底层结构中,实现方式主要是通过作差减法和移位右移的方式将除数和被除数逐渐逼近相等,并通过商和余数的累计得出最终结果。 具体实现过程中,可以使用类似于Booth算法或者类似于龙皮递归算法的递归结构来进行除法计算。此外,在代码实现中还需要注意一些细节问题,如除数为0的特殊情况、被除数小于除数的情况等,需要考虑如何解决或者报错提示。 总的来说,32位无符号除法器是一种实现除法运算的高效且可靠的方法。在硬件实现中可以使用verilog语言进行代码编写,并通过递归算法实现高效的除法运算。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值