zoukankan      html  css  js  c++  java
  • Verilog -- 无符号整数除法器(二)

    Verilog -- 无符号整数除法器(二)

    在 Verilog -- 任意整数除法器(一)中已经给出了一种除法器的组合逻辑实现,但是实际使用中可能还是需要讲组合逻辑插拍才能得到更好的性能。下面给出一种基于状态机的时序逻辑除法器实现。

    这边先上一下算法流程图,跟之前的一样:

    graph LR id0(32位整数a除以b)-->id1(a的高位扩展32位) id0(32位整数a除以b)-->id2(b的低位扩展32位) id1 --> id3(a左移一位) id2 --> id4{a>=b?} id3 --> id4 id4 -- 是 --> id5(a = a-b+1) id5 -->id6{移位次数<32} id4 --否-->id6 id6 --是--> id3 id6 --否--> id7(输出a)

    下面是verilog代码:

    
    `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
    );
    
    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;
    
    parameter IDLE =2'b00   ,
              SUB  =2'b01   ,
    		  SHIFT=2'b10   ,
    		  DONE =2'b11   ;
    
    
    
    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
               quotient_e <= {quotient_e[DATAWIDTH-2:0],1'b1};
    		   dividend_e <= dividend_e-divisor_e;
             end
    	    else begin
    	       quotient_e <= {quotient_e[DATAWIDTH-2:0],1'b0};
    		   dividend_e <= dividend_e;
            end
          end
      SHIFT:begin
    	   if(count<DATAWIDTH)begin
    	     dividend_e <= dividend_e<<1;
    	     count      <= count+1;		 
           end
    	   else begin
    		 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
    
    

    testbench:

    `timescale 1ns/1ps
    
    module div_fsm_tb();
    
    parameter DATAWIDTH = 16;
    
    reg  clk;
    reg  rstn;       
    reg  en;    
    wire ready;     
    reg  [DATAWIDTH-1:0]    dividend; 
    reg  [DATAWIDTH-1:0]    divisor;
    wire [DATAWIDTH-1:0]    quotient;
    wire [DATAWIDTH-1:0]    remainder;
    wire                    vld_out;
    
    wire [DATAWIDTH-1:0]    quotient_ref; // true result
    wire [DATAWIDTH-1:0]    remainder_ref; 
    assign quotient_ref = dividend/divisor;
    assign remainder_ref = dividend%divisor;
    
    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()%1000;
        divisor  <= $urandom()%100;
        wait (ready == 1);
        wait (vld_out == 1);
      end
    
    
    end
    
    
    initial begin
        $fsdbDumpvars();
        $fsdbDumpMDA();
        $dumpvars();
        #1000 $finish;
     end
    
    div_fsm #(
        .DATAWIDTH                      ( DATAWIDTH  ))
    U_DIV_FSM_0(
        .clk                            ( clk        ),
        .rstn                           ( rstn       ),
        .en                             ( en         ),
        .ready                          ( ready      ),
        .dividend                       ( dividend   ),
        .divisor                        ( divisor    ),
        .quotient                       ( quotient   ),
        .remainder                      ( remainder  ),
        .vld_out                        ( vld_out    )
    );
    
    
    endmodule
    
    
    
    

    仿真波形

    对于16位的数据,计算周期为36。

  • 相关阅读:
    Spark入门实战系列--1.Spark及其生态圈简介
    理解JavaScript的原型链
    为什么overflow:hidden能达到清除浮动的目的?
    JavaScript中为什么需要!!?
    CSS品控与流程
    CSS高级特效(下)
    CSS高级特效(上)
    CSS变化、过渡与动画
    CSS表单与数据表(下)
    CSS表单与数据表(上)
  • 原文地址:https://www.cnblogs.com/lyc-seu/p/12864956.html
Copyright © 2011-2022 走看看