2013-11-15 4 views
-1

Может ли кто-нибудь сказать мне, какая должна быть ширина дивиденда и делителя в последовательном делении. На данный момент я разработал разделитель с WIDTH_DIVID = 2 * wIDTH_DIVIS. Если я отключу это отношение, мое разделение не удастся. Может кто-нибудь помочь мне с этим Мой Verilog код, как показано нижеSequential Division 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]); 

    [email protected](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 
    [email protected](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 // [email protected] (posedge i_clk or posedge i_rst or posedge i_start) 

    //Adding the divisor to the upper part of the Shift register    
    [email protected](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 
    [email protected](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 // [email protected] (posedge i_clk or posedge i_rst) 


    //generating the control signals pos_i and neg_i to control division 
    [email protected](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 // [email protected] (state,i_start,aluout_i,count_i) 

    //done signal to indicate end of division 
    [email protected](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 

    [email protected](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 

ответ

1

Просто чтобы быть ясно, на условиях, используемых:

A ÷ B = C, а называется делимое или числитель, а делитель или знаменатель и результат с называется фактор

Источник Wikipedia.

Ширина входного сигнала делителя (числителя) и делителя (знаменателя) будет определять размер частного. Добавление lsbs (дробных битов) к входам увеличит точность частного.

Конечная требуемая ширина должна быть такой же, как с использованием оператора /. Попробуйте выполнить это вместе со своим кодом, чтобы помочь выявить ошибки. Для расчета требуемой ширины я настоятельно рекомендую использовать некоторые примеры на бумаге. Начните с деления 4-битных чисел и увеличьте число до 5,6 бит, чтобы понять структуру роста бит.

0

Вот параметризованный последовательный разделитель в системном верилоге.

// 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