网上一个能用的也没有,自己写一个把。
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多存点就好了吧