Verilog写一个对数计算模块Log2(x)

时间:2023-11-22 21:48:20

网上一个能用的也没有,自己写一个把。

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 = :
temp = i/;
templog = log2(+temp);
fprintf('the value of log is%6.2f\n',templog)
end

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

2.开始写Verilog:

电路结构:

Verilog写一个对数计算模块Log2(x)

 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 [:] log_input,
output [:] log_output
); reg [:] exp_data;
reg [:] fix_data;
reg fix_enable;
wire [:] float_exp;
wire float_enable; wire [:] point_float;
reg [:] point_addr;
wire [:] point_addwire; wire result_enable;
//reg [31:0] Mem [3:0];
reg [:] fifo_data1;
reg [:] fifo_data2; reg sign_flag; always @(posedge clk or posedge rst_n)
begin
if(!rst_n) begin
exp_data <= 'd127;
sign_flag <= '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[:] - exp_data;
point_addr <= log_input[:];
end
end always @(posedge dataclk or posedge rst_n)
begin
if(!rst_n) begin
fifo_data2 <= 'd0;
fifo_data1 <= '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 [:] din;
wire [:] 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 <= 'b0;
rst <= 'b1;
din <= 'b0;
#
rst <= 'b0; #
rst <= 'b1;
data_enable <= 'b1; din <= 'h3d23d70a; //0.4
#
din <= 'h3e800000; //0.25
#
din <= 'h3d23d70a; //0.4
#
din <= 'h3e800000; //0.25
#
din <= 'h3d23d70a; //0.4
#
din <= 'h3e800000; //0.25
#
din <= 'h3d23d70a; //0.4
#
din <= 'h3e800000; //0.25
#
din <= 'h3d23d70a; //0.4
#
din <= 'h3e800000; //0.25
#
din <= 'h3d23d70a; //0.4
#
din <= 'h3e800000; //0.25
#
din <= 'h3d23d70a; //0.4
#
din <= 'h3e800000; //0.25
#
din <= 'h3d23d70a; //0.4
#
din <= 'h3e800000; //0.25
#
din <= 'h3d23d70a; //0.4
#
din <= 'h3e800000; //0.25
// Add stimulus here
end initial begin
clk = ;
forever
# clk = !clk;
end initial begin
dataclk = ;
#
dataclk = ;
forever
# 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 ;
}
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>>&)-;
}

仅用作思路参考,我是Verilog菜鸟。

下面是实验结果:

Verilog写一个对数计算模块Log2(x)

matlab验证一下,(3d23d70a就是0.04,输出的e095c28f是-4.68)

Verilog写一个对数计算模块Log2(x)

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