verilog带符号除法器

matlab代码

%divide
clear;
close all;
clc;
WIDTH=16;
div_A=[20855,21855,15,1166,11665,1115,1180,32777];%WIDTH=16
div_B=[2,2,5,15,123,112,134,129];
for i=1:length(div_A)
    for j=1:length(div_B)
        div_rem_d=abs(div_A(i))*2;%高位补div_A位宽-1=(WIDTH-1)个0,低位补1个0;余数初值
        div_quo_d=0;%商位宽为WIDTH,
        div_C(i,j)=0;
        div_B_d=div_B(j)*2^(WIDTH);
        for k=1:WIDTH
            if div_rem_d>=div_B_d
                div_rem_d=(div_rem_d-div_B_d)*2+1;
                div_C(i,j)=div_C(i,j)*2+1;
            else
                div_rem_d=div_rem_d*2;
                div_C(i,j)=div_C(i,j)*2;
            end
        end
        div_rem_tmp2=floor(div_rem_d/2^(WIDTH+1));
            div_rem(i,j)= div_rem_tmp2;
       
    end
end

matlab统一按无符号数处理了,修改很简单,就没改

verilog代码

`timescale 1ns / 1ps
module divide#(parameter width_A=16,
               parameter width_B=8
)(
    input                         clk,
    input                         rst_n,
    input[width_A-1:0]            div_A,    //被除数
    input[width_B-1:0]            div_B,    //除数
    input                        valid_in,
    output reg                    valid_out,
    output reg [width_A-1:0]    div_C,    //
    output reg[width_A-1:0]        div_rem //余数,恒为正
);

  parameter DIV_IDLE = 2'd0;
  parameter DIV_BUSY = 2'd1;
  parameter DIV_DONE = 2'd2;
  parameter DIV_ACK = 2'd3;
  reg [1:0] next_state,state;

  // reg [7:0]    result;
  reg[width_A+width_B-1:0]    div_B_d;  
  reg[width_A+width_B-1:0]    div_B_d_tmp;
  reg[2*width_A-1:0]         div_rem_d;   
  reg [2*width_A-1:0]        div_rem_d_tmp; 
  
  reg[width_A-1:0]            div_quo; 
  reg [width_A-1:0]            div_quo_d; 
  reg[3:0]        cnt;
  wire [width_A-1:0]        abs_A;
  wire [width_B-1:0]        abs_B;

  wire [2*width_A-1:0]    div_rem_tmp;
  
  assign abs_A = div_A[width_A-1] ? ~div_A+1 : div_A;
  assign abs_B=div_B[width_B-1] ? ~div_B+1 : div_B;
  
  assign is_neg = div_A[width_A-1] ^ div_B[width_B-1];
  assign all_neg = div_A[width_A-1] & div_B[width_B-1];
  always@(*) begin
    case(state)
        DIV_IDLE:begin
            if(valid_in)
                next_state=DIV_BUSY;
            else     
                next_state=DIV_IDLE;
        end
        DIV_BUSY:begin
            if(cnt==width_A-1)
                next_state=DIV_DONE;
            else     
                next_state=DIV_BUSY;
        end
        DIV_DONE:begin
                next_state=DIV_ACK;
        end
        DIV_ACK    :begin
            next_state=DIV_IDLE;
        end    
        default: next_state=DIV_IDLE;
    endcase
  end    
  always@(posedge clk)
    if(~rst_n)
        state<=DIV_IDLE;
    else
        state<=next_state;
        

  always@(posedge clk)
    if(~rst_n)begin
        div_B_d<=0;//除数寄存器
        div_rem_d<=0;//余数寄存器
        // div_quo_d<=0;//商寄存器
        div_rem<=0;
        div_C<=0;
        cnt<=0;
        valid_out<=1'b0;
    end
    else begin
        case(state)
            DIV_IDLE :begin
                valid_out<=1'b0;
                if(valid_in)begin    
                    div_B_d<={abs_B,{(width_A)1'b0}};
                    div_rem_d<={{(width_A-1)1'b0},abs_A,1'b0};
                    // div_quo_d<=0;
                    cnt<=0;
                end
        end
            DIV_BUSY:begin    
                    div_rem_d<=div_rem_d_tmp;
                    // div_quo_d<=div_quo;
                    // div_B_d<=div_B_d;
                    cnt<=cnt+1;                            
            end
            DIV_DONE:begin
                valid_out<=1'b1;
                if(all_neg) begin    //A<0,B<0;
                    div_C<=div_rem_d[width_A-1:0]+1;
                    div_rem<=div_B_d[width_A+width_B-1:width_A]-{0,div_rem_d[2*width_A-1:width_A+1]};
                end
                else if(is_neg) begin    //A<0,B>0
                    // div_C<=~div_quo_d+1;
                    /* div_C<=~div_rem_d[15:0]+1; */
                    div_C<=~div_rem_d[width_A-1:0];
                    div_rem<=div_B_d[width_A+width_B-1:width_A]-{0,div_rem_d[2*width_A-1:width_A+1]}; //31:17
                end
                else begin //A>0,B>0
                    // div_C<=div_quo_d;
                    div_C<=div_rem_d[width_A-1:0];
                    div_rem<={0,div_rem_d[2*width_A-1:width_A+1]};
                end
            end
            DIV_ACK:
                valid_out<=1'b0;
        endcase
    end
  reg data_bit;    
  assign  div_rem_tmp=div_rem_d-div_B_d;
  always@(*)begin
    if(div_rem_d<div_B_d) begin
        div_rem_d_tmp={div_rem_d[2*width_A-2:0],1'b0};
        data_bit=0;
        // div_quo={div_quo_d,1'b0};
        
    end
    else begin
        div_rem_d_tmp={div_rem_tmp[2*width_A-2:0],1'b1};
        // div_quo={div_quo_d,1'b1};
        data_bit=1;
    end
    // div_B_d_tmp={1'b0,div_B_d[23:1]};
  end
endmodule

 

testbench

`timescale 1ns / 1ps
//
module tb_divide;

    reg clk;
    reg rst_n;
     
    reg start;
    reg [15:0]div_A;
    reg [7:0]div_B;

    wire done;
    wire [15:0]div_C;
     
   always #10 clk = ~clk;
    initial begin      
        rst_n = 0;         
        clk = 1;
        #10; 
        rst_n = 1;
     end
    
  divide u_divide(
    .clk(clk),
    .rst_n(rst_n),
    .div_A(div_A),
    .div_B(div_B),
    .valid_in(start),
    .valid_out(done),
    .div_C(div_C)
);    

     reg [3:0]i;
    always @ ( posedge clk or negedge rst_n )
        if( !rst_n ) begin
                i <= 4'd0;
                start <= 1'b0;
                div_A<= 16'd1;
                div_B<= 8'd1;             
        end                
        else begin
            case( i )
                0: 
                if( done ) begin 
                    start <= 1'b0; 
                    i <= i + 1'b1; 
                end
                else begin 
                    div_A<= 16'b1101_0101_0101_0101; 
                    div_B<= 8'd5; 
                    start <= 1'b1; 
                end
                
                1: // 
                if( done ) begin 
                    start <= 1'b0; 
                    i <= i + 1'b1; 
                end
                else begin 
                    div_A<= 16'd15; 
                    div_B<= 8'd5; 
                    start <= 1'b1; 
                end
                
                2: // 
                if( done ) begin 
                    start <= 1'b0; 
                    i <= i + 1'b1; 
                end
                else begin 
                    div_A<= 16'd1166; 
                    div_B<= 8'b11111011; //为了实验随手改成了负数
                    start <= 1'b1; 
                end
                
                3: // 
                if( done ) begin 
                    start <= 1'b0; 
                    i <= i + 1'b1; 
                end
                else begin 
                    div_A<= 16'd11665; 
                    div_B<= 8'd123; 
                    start <= 1'b1; 
                end
                4: //
                if( done ) begin 
                    start <= 1'b0; 
                    i <= i + 1'b1; 
                end
                else begin 
                    div_A<= 16'd11665; 
                    div_B<= 8'd1; 
                    start <= 1'b1; 
                end
                5: // 
                if( done ) begin 
                    start <= 1'b0; 
                    i <= i + 1'b1; 
                end
                else begin 
                    div_A<= 16'd15; 
                    div_B<= 8'd3; 
                    start <= 1'b1; 
                end
                6: // 
                if( done ) begin 
                    start <= 1'b0; 
                    i <= i + 1'b1; 
                end
                else begin 
                    div_A<= 16'b1111_1111_1111_0001;  //为了实验随手改成了二进制负数
                    div_B<= 8'b1111_1110; 
                    start <= 1'b1; 
                end
                7: begin 
                    i <= 4'd7; 
                    
                end
            endcase 
        end
 
 endmodule

单纯记录一下

posted @ 2021-07-08 14:42  luckylan  阅读(280)  评论(0)    收藏  举报