Verilog寫一個對數計算模塊Log2(x)


網上一個能用的也沒有,自己寫一個把。

1.計算原理:

 整數部分

網上找到了一個c語言的計算方法如下:

int flog2(float x) {
    return ((unsigned&)x>>23&255)-127; }

用matlab測試了一下,得到的結果是一個log2的整數部分

小數部分

發現小數部分其實都是  1+一個小數  ,然后這個小數值其實可通過最高位是0.5 然后0.25,0.125.......這樣累加得到。

比如:

100 0000 0000 0000 0000 0000 ->  1+0.5

110 0000 0000 0000 0000 0000 ->  1+0.5+0.25

這樣我只要算出這個然后查表就好了。由於對精度要求不高,只取六位數字進行查表,matlab獲取表值的仿真程序如下:

for i = 0:31
    temp = i/32;
    templog = log2(1+temp);
    fprintf('the value of log is%6.2f\n',templog)
end

 至此,小數部分和整數部分就都得到了。 

2.開始寫Verilog:

電路結構:

 Verilog代碼

 其中用了3個IP核,包括ROM、定點轉浮點單元、浮點加法單元,不做詳述

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    10:20:43 03/29/2019 
// Design Name: 
// Module Name:    log2fun 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
module log2fun(
        input                            clk,
        input                            dataclk,
        input                            rst_n,
        input                            data_enable,
        input         [31:0]        log_input,
        output         [31:0]        log_output
    );

reg         [7:0]            exp_data;
reg         [31:0]        fix_data;
reg                         fix_enable;
wire         [31:0]        float_exp;
wire                         float_enable;

wire        [31:0]        point_float;
reg        [4:0]            point_addr;
wire        [4:0]            point_addwire;

wire                        result_enable;
//reg        [31:0]         Mem [3:0];
reg        [31:0]            fifo_data1;
reg        [31:0]            fifo_data2;

reg                            sign_flag;

always @(posedge clk or posedge rst_n)
begin
    if(!rst_n) begin 
        exp_data         <=         8'd127;
        sign_flag        <=         1'd0;
    end
    else begin        
        //fix_data            <=            log_input[30:23] > exp_data ? log_input[30:23]-exp_data:exp_data-log_input[30:23];
        fix_data            <=            log_input[30:23]     -    exp_data;
        point_addr        <=            log_input[22:18];
    end
end

always @(posedge dataclk or posedge rst_n)
begin
    if(!rst_n) begin 
        fifo_data2        <=            2'd0;
        fifo_data1        <=            2'd1;
    end
    else begin    
        if(data_enable)begin
            //Mem[fifo_addr1]        <=            point_float;
            //point_floatDelay        <=            Mem[fifo_addr2];
            fifo_data1        <=        point_float;
            fifo_data2        <=        fifo_data1;
        end
    end
end

    assign point_addwire        =        point_addr;

    int2float INTCONVERT(
        .aclk(clk), 
        .s_axis_a_tvalid(data_enable), 
        .m_axis_result_tvalid(float_enable), 
        .s_axis_a_tdata(fix_data), 
        .m_axis_result_tdata(float_exp)
    );

    log_sheet LOG_DATA (
        .clka (clk), 
        .addra(point_addwire), 
        .douta(point_float)
    );
    
    float_add ADD_FLOAT (
        .aclk(clk), 
        .s_axis_a_tvalid(float_enable), 
        .s_axis_b_tvalid(float_enable), 
        //.s_axis_a_tready(s_axis_a_tready), 
        //.s_axis_b_tready(s_axis_b_tready), 
        .m_axis_result_tvalid(result_enable), 
        .s_axis_a_tdata(float_exp), 
        .s_axis_b_tdata(fifo_data1), 
        .m_axis_result_tdata(log_output)
    );
endmodule

 

testbench

`timescale 1ns / 1ps

////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer:
//
// Create Date:   10:39:38 03/29/2019
// Design Name:   log2fun
// Module Name:   C:/Users/ray5w/OneDrive/benchmark/code/verylog_vad/verylog_vad/log2fun_tb.v
// Project Name:  verylog_vad
// Target Device:  
// Tool versions:  
// Description: 
//
// Verilog Test Fixture created by ISE for module: log2fun
//
// Dependencies:
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
////////////////////////////////////////////////////////////////////////////////
 
module log2fun_tb;
 
    // Outputs
    reg                                 clk;
    reg                                dataclk;
    reg                                 rst;
    reg                                 data_enable;
    reg                [31:0]         din;
    wire                 [31:0]         dout;
    
    // Instantiate the Unit Under Test (UUT)
    log2fun uut (
        .clk(clk),
        .dataclk(dataclk),
        .rst_n(rst),
        .log_input(din),
        .data_enable(data_enable),
        .log_output(dout)
    );

    initial begin
           data_enable         <=                1'b0; 
          rst                     <=                1'b1; 
          din                    <=                32'b0;
             #20
             rst                     <=                1'b0; 
             
          #100             
          rst                    <=                1'b1;         
             data_enable         <=                1'b1; 
             
          din                    <=                32'h3d23d70a;  //0.4
             #50
          din                    <=                32'h3e800000;    //0.25
             #50
          din                    <=                32'h3d23d70a;  //0.4
             #50
          din                    <=                32'h3e800000;    //0.25
             #50
          din                    <=                32'h3d23d70a;  //0.4
             #50
          din                    <=                32'h3e800000;    //0.25
             #50
          din                    <=                32'h3d23d70a;  //0.4
             #50
          din                    <=                32'h3e800000;    //0.25
             #50
          din                    <=                32'h3d23d70a;  //0.4
             #50
          din                    <=                32'h3e800000;    //0.25
             #50
          din                    <=                32'h3d23d70a;  //0.4
             #50
          din                    <=                32'h3e800000;    //0.25
             #50
          din                    <=                32'h3d23d70a;  //0.4
             #50
          din                    <=                32'h3e800000;    //0.25
             #50
          din                    <=                32'h3d23d70a;  //0.4
             #50
          din                    <=                32'h3e800000;    //0.25
             #50
          din                    <=                32'h3d23d70a;  //0.4
             #50
          din                    <=                32'h3e800000;    //0.25             
        // Add stimulus here
    end
      
    initial begin                                                  
        clk        = 1;
        forever
            #5 clk = !clk;
    end 
    
    initial begin
        dataclk        = 1;
            #15    
        dataclk        = 0;
        forever
            #25     dataclk = !dataclk;
    end 
endmodule

 

一個c代碼方便進行浮點核定點轉換的,用來看看最終結果是不是對的:

#include <stdio.h>
int float2int(float data);
int flog2(float x);
float int2float(int data);
float datasheet[] = {0.00,  0.04,  0.09,  0.13,  0.17,  0.21,  0.25,  0.29,  0.32,  0.36,  0.39,  0.43,  0.46,  0.49,  0.52,  0.55,  0.58,  0.61,  0.64,  0.67,  0.70,  0.73,  0.75,  0.78,  0.81,  0.83,  0.86,  0.88,  0.91,  0.93,  0.95,  0.98 };
int main(void) { 
    int i ;
    /*for(i=0;i<32;i++){
        printf("%x,\n",float2int(datasheet[i]));
    }*/
    printf("%d,\n",flog2(0.04));
    printf("%d,\n",flog2(0.25));
    
    printf("%f,\n",int2float(0x40a00000));
    return 0;
}
float int2float(int data){
    float *idata ; 
    int idata2 = data;
    idata =(float*)&idata2;
    return *idata;
}

int float2int(float data){
    int *idata ; 
    float idata2 = data;
    idata =(int*)&idata2;
    return *idata;
}

int flog2(float x){
     return ((unsigned&)x>>23&255)-127;
}

僅用作思路參考,我是Verilog菜鳥。

下面是實驗結果:

 matlab驗證一下,(3d23d70a就是0.04,輸出的e095c28f是-4.68)

 

有一定誤差,要提高精度只要查表那一步增大rom多存點就好了吧

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM