顺序分裂verilog

时间:2013-11-15 05:29:50

标签: binary verilog division

任何人都可以告诉我在连续分割中应该分红和除数的宽度。截至目前,我已经设计了具有WIDTH_DIVID = 2 * wIDTH_DIVIS的分频器。如果我说出这种关系,我的分裂就会失败。谁能帮我这个 我的verilog代码如下所示

//  Description:  module for serial Divider
//  The dividend is loaded into the accumulator along with the guard bit.
//  Then the 2's complement of the divisor is added to the upperpart of the
//  accumulator along with the guard bit.Then the MSB of the accumulator is
//  tested.
//  1. If it is cleared then 1 bit left shift of the accumulator is done and 
//     one is concantinated to the LSB of the accumulator.
//  2. If is is not cleared then the accumulator contents are shifted 1 bit 
//     left.
//  After the division upper part of the accumulator contains the remainder 
//  and lower part contains the quotient.

// --------------------------------------------- -----------------------------

module division(//global inputs
        i_clk,i_rst,
        //outputs
        o_quotient,o_remainder,o_done,o_overflow,
        //input
        i_dividend,i_divisor,i_start
        );

   //parameter declarations 
   parameter DIVIS_WIDTH =2;        //width for divisor 
   parameter DIVID_WIDTH =2*DIVIS_WIDTH;       //width for dividend,DIVID_WIDTH=2*DIVIS_WIDTH
   localparam NPOWER = 6;                          //divisor width<=2**NPOWER  
   localparam NULL_VECTOR_S=32'h00000000;
   localparam S0= 2'd0;
   localparam S1= 2'd1;
   localparam S2= 2'd2;

   //global inputs
   input i_clk;
   input i_rst;

   //outputs
   output reg [DIVIS_WIDTH:0] o_quotient;
   output reg [DIVIS_WIDTH-1:0] o_remainder;
   output reg           o_overflow;
   output reg           o_done;


   //input           
   input [DIVID_WIDTH-1:0]  i_dividend;
   input [DIVIS_WIDTH-1:0]  i_divisor;
   input            i_start;      //indicates start of division

   // reg and wire declarations
   reg [DIVID_WIDTH:0]      dividend_i;    //Add extra guard bit
   reg [DIVIS_WIDTH:0]      divisor_i;    //Add extra guard bit
   reg [DIVIS_WIDTH-1:0]    divisor_rect_i;   //divisor used to check overflow
   wire             signquot_i;       //Sign of quotient
   wire             signremain_i;    //Sign of remainder
   reg [DIVID_WIDTH+DIVIS_WIDTH-1:0] accumulator_i;   // Shift register which holds both remainder and quotient
   reg [DIVIS_WIDTH:0]           aluout_i;        //Used to add the upperpart of the shift register and the divisor
   reg [NPOWER-1:0]              count_i;        //No.of iterations
   reg                   pos_i;
   reg                   neg_i;
   reg [2:0]                 state;
   reg [2:0]                 nextstate; 
   reg                   done_i;


   //Sign product of quotient and remainder
   assign   signquot_i=((i_dividend[DIVID_WIDTH-1] ^ i_divisor[DIVIS_WIDTH-1]));
   assign   signremain_i=(i_dividend[DIVID_WIDTH-1]);

  always@(posedge i_clk or posedge i_rst)
     begin 
    if(i_rst==1)begin 
       dividend_i<=0;
       divisor_i<=0;
       divisor_rect_i<=0;
    end else begin
       divisor_rect_i<=i_divisor;
           dividend_i<=({1'b0,i_dividend});
       divisor_i<=(~({1'b0,i_divisor})+1);  
    end
     end // else: !if(i_rst==1)


   //Sequential Division 
   always@(posedge i_clk or posedge i_rst)                         
     begin
    if (i_rst==1)                     
      accumulator_i <=0;
    else begin  
       if(i_start==1) 
         accumulator_i<={dividend_i[DIVID_WIDTH-1:0],1'b0};   // Load Dividend in shift register
       else if(pos_i==1)                                    
         accumulator_i<=({aluout_i[DIVIS_WIDTH-1:0],accumulator_i[DIVID_WIDTH-DIVIS_WIDTH-1:0],1'b1});//({newaccu_i[DIVID_WIDTH-1:0],1'b1});//shiting the new register value by one bit left and concantinatinf one at the LSB
       else if(neg_i==1)
         accumulator_i<=({accumulator_i[DIVID_WIDTH-1:0],1'b0});//Use the previous register value and shift 1 bit left
    end
     end // always@ (posedge i_clk or posedge i_rst or posedge i_start)

   //Adding the divisor to the upper part of the Shift register             
   always@(accumulator_i,divisor_i)
     begin 
    aluout_i<=accumulator_i[DIVID_WIDTH : DIVID_WIDTH-DIVIS_WIDTH]+ divisor_i; 
    //  newaccu_i<= ({aluout_i, accumulator_i[DIVID_WIDTH-DIVIS_WIDTH-1:0]}); 
     end

   //Control of states for division   
   always@(posedge i_clk or posedge i_rst)      
     begin
    if (i_rst == 1) begin      
       state   <= S0; 
       count_i <=0;             
    end  else begin     
       state <= nextstate;   
       if (state==S1)
         count_i <= count_i - 1;
       else if (state==S0)
         count_i <= (DIVIS_WIDTH); 
    end
     end // always@ (posedge i_clk or posedge i_rst)


   //generating the control signals pos_i and neg_i to control division 
   always@(state,i_start,aluout_i,count_i)
     begin  
    case (state)
      S0 :begin 
         pos_i <= 0;
         neg_i <= 0;
         if (i_start==1)
           nextstate <= S1; 
         else 
           nextstate <= S0;
      end 
      S1 : begin 
         neg_i <= aluout_i[DIVIS_WIDTH];      
         pos_i <= ~(aluout_i[DIVIS_WIDTH]); 
         if (count_i==NULL_VECTOR_S[NPOWER_WIDTH-1])
           nextstate <= S2; // Done 
         else 
           nextstate <= S1;// Next sub&shift
      end
      S2 : begin 
         pos_i <= 0;
         neg_i <= 0;                                           
         nextstate <= S0; 
      end 
      default: begin
         pos_i <= 0;
         neg_i <= 0;                                           
         nextstate <= S0;              
      end
    endcase // case (state)
     end // always@ (state,i_start,aluout_i,count_i)

   //done signal to indicate end of division   
   always@(posedge i_clk or posedge i_rst) 
     begin  
    if(i_rst==1) begin
       done_i<= 0;
    end else  begin 
       done_i <= (count_i==1)? 1'b1 : 1'b0;
    end
     end

   //Assigning the outputs for unsigned division   

   always@(accumulator_i,done_i)
     begin
    o_done<=done_i;
    o_remainder<=accumulator_i[DIVID_WIDTH:DIVID_WIDTH-DIVIS_WIDTH+1];
    o_quotient<=(accumulator_i[DIVIS_WIDTH:0]); 
    o_overflow<=(((accumulator_i[DIVID_WIDTH:DIVID_WIDTH-DIVIS_WIDTH+1])>=divisor_rect_i))? 1'b1 : 1'b0;     
     end 
endmodule // division

2 个答案:

答案 0 :(得分:1)

只是要明确使用的术语:

  

a÷b = c,a称为被除数或除数,b为除数或   分母和结果c称为商

来源Wikipedia

被除数(分子)和除数(分母)的输入宽度将决定商的大小。将lsbs(小数位)添加到输入将增加商的精度。

最终所需宽度应与使用/运算符相同。尝试在代码旁边运行此代码以帮助发现错误。对于所需的宽度计算,我强烈建议在纸上进行一些示例。首先划分4位数字,然后向上移动到更大的数字5,6位,以了解位增长的模式。

答案 1 :(得分:0)

这是系统verilog中的参数化串行分隔符。

// returns max value ('1) if divide by zero or overflow occurs.

module unsigned_serial_divide #(
   parameter N_WIDTH = 16       // Size of dividend
  ,parameter D_WIDTH = 16       // Size of divisor
  ,parameter Q_WIDTH = 16       // Size of quotient
  ,parameter F_WIDTH = 0        // Number of fractional bits in quotient.
  )(
   input wire clk
  ,input wire reset
  ,input wire go      // hold high for continuous calculation or stobe high for single calculation
  ,input wire [N_WIDTH-1:0] dividend
  ,input wire [D_WIDTH-1:0] divisor
  ,output reg [Q_WIDTH-1:0] quotient    // maintains last complete calculation.
  //,output wire overflow               // NOT IMPLEMENTED
  ,output wire done                         // stobes high if go is held high or indicated when single calculation complete
  );

  localparam COUNT_WIDTH = $clog2(Q_WIDTH);
  localparam [COUNT_WIDTH-1:0] DIVIDE_COUNTS = (COUNT_WIDTH)'(Q_WIDTH - 1'b1);

  localparam WN_WIDTH = N_WIDTH + F_WIDTH;
  localparam WD_WIDTH = D_WIDTH + DIVIDE_COUNTS;

  localparam CALC_WIDTH = ((WN_WIDTH > WD_WIDTH) ? WN_WIDTH : WD_WIDTH) + 1;

  reg  busy;
  reg  [COUNT_WIDTH-1:0]  divide_count;
  reg  [WN_WIDTH-1:0]       working_dividend;
  reg  [WD_WIDTH-1:0]       working_divisor;
  reg  [Q_WIDTH-1:0]      working_quotient;

  initial begin
    busy <= 0;    
    divide_count <= 0;  
    working_dividend <= 0;
    working_divisor <= 0;
    working_quotient <= 0;
    quotient <= 0;
  end

  // Subtract with sign bit
  wire [CALC_WIDTH-1:0] subtract_calc = {1'b0, working_dividend} - {1'b0, working_divisor};  

  // subtract_positive = (working_dividend > working_divisor);
  wire subtract_positive = ~subtract_calc[CALC_WIDTH-1];

  // if the next bit in quotient should be set then subtract working_divisor from working_dividend
  wire [WN_WIDTH-1:0] dividend_next = (subtract_positive) ? subtract_calc[WN_WIDTH-1:0] : working_dividend;

  wire [WD_WIDTH-1:0] divisor_next = working_divisor >> 1;   

  wire [Q_WIDTH-1:0] quotient_next = (working_quotient << 1) | (subtract_positive); 

  always @(posedge clk or posedge reset) begin
    if (reset) begin
      busy <= 0;
      divide_count <= 0;
      working_dividend <= 0;
      working_divisor <= 0;
      working_quotient <= 0;
      quotient <= 0;
    end else begin
      if (go & ~busy) begin
        busy <= 1;
        divide_count <= DIVIDE_COUNTS;              
        working_dividend <= dividend << F_WIDTH;                // scale the numerator up by the fractional bits
        working_divisor  <= divisor  << DIVIDE_COUNTS;  // align divisor to the quotient        
        working_quotient <= 0;
      end else begin            
        if (divide_count == 0) begin
          if (busy == 1) begin
            quotient <= quotient_next;
          end
          busy <= 0;
        end else begin
          divide_count <= divide_count - 1'b1;      
        end         
        working_dividend <= dividend_next;
        working_divisor <= divisor_next; 
        working_quotient <= quotient_next;                  
      end
    end
  end   

  assign done = ~busy;  

endmodule