網上一個能用的也沒有,自己寫一個把。
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多存點就好了吧