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多存点就好了吧

 

posted @ 2019-03-31 17:27  ray5wang  阅读(4213)  评论(0编辑  收藏  举报