🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] # 说明 使用FPGA进行AD采样,得到的数据都是整数或者有符号整数,引入浮点数处理模块,然后利用流水线的思想,可以比较快速的处理一些实际问题,比如检测相位差。 因此需要一个模块将有符号数转换为单精度的浮点数的编码,这里使用了两种方式来实现,一种直接使用逻辑实现,另一种使用查找表来实现。 # 逻辑运算实现 ```verilog `timescale 1ns / 1ps // ******************************************************************** // FileName : Int2Float.v // Author :hpy // Email :yuan_hp@qq.com // Date :2020年12月10日 // Description :有符号数转单精度浮点数。注意 N<=24 ,太大会损失精度 // -------------------------------------------------------------------- /*---------------------------------------- Int2Float #( .N(8) //表示整数的位宽 ) u1 ( .din() , .o_f () //浮点数编码输出 ); -----------------------------------------*/ module Int2Float #( parameter N = 8 //表示整数的位宽 )( input signed [N-1 : 0] din , output reg [31:0] o_f //浮点数编码输出 ); wire signed [N-1:0] in=din[N-1] ==1? -din:din; //----------- 观察变量 -------------- wire sig=o_f[31]; wire [7:0]e=o_f[30:23]; wire [22:0]M=o_f[22:0]; integer i; reg[22:0]m; reg [7:0]cnt; always @( * ) begin o_f[31] = din[N-1] ; cnt = 8'd0; if(N<=24) m={in[N-2:0],{(24-N){1'b0}}} ; else m=in[N-2:N-2-22]; for(i=0;i<N-1;i=i+1) begin if(m[22]==0) begin m = m<<1; cnt = cnt + 1; end end m=m<<1; o_f[22:0] = m; o_f[30:23] = N-1-cnt-1 + 127; end endmodule ``` ```tb `timescale 1ns / 1ps module tb ; reg clk,rst_n; //生成始时钟 parameter NCLK = 20; //此时时钟为50MHz initial begin clk=0; forever clk=#(NCLK/2) ~clk; end /****************** ADD module inst ******************/ localparam WIDTH =16; reg signed [WIDTH - 1 : 0] din; Int2Float #( .N(WIDTH) //表示整数的位宽 ) u1 ( .din(din) ); integer fid; initial begin fid=$fopen("../data.txt","w"); //把数据写入文件,便于观察 #100; repeat(100) @(posedge clk) begin if(rst_n) begin $fwrite(fid,"%d,%b,%d,%d\n",din, u1.sig, u1.e, (u1.M>>(23-u1.e))+(1<<u1.e)); end end $fclose(fid); end /****************** --- module inst ******************/ initial begin $dumpfile("wave.lxt2"); $dumpvars(0, tb); //dumpvars(深度, 实例化模块1,实例化模块2,.....) end reg [31:0] mem1[0:99]; integer i; initial begin rst_n = 0; i=0; //$readmemh("../mem1.txt",mem1); #(NCLK) rst_n=0; #(NCLK) rst_n=1; //复位信号 repeat(100) @(posedge clk)begin //# 1 ; //作为延时时间 din = $random; i=i+1; end $display("运行结束!"); $dumpflush; $finish; $stop; end endmodule ``` ![](https://img.kancloud.cn/c8/34/c8347d0f01c3889ae04b1230c255b0b4_1814x223.png) # 查找表实现 查找表实现,我是用`lua`写了一个自动生成的脚本,脚本如下: ```lua #!/usr/bin/env lua ------------------------------------------------------ --函数名 : make_lut --功能 :生成整数转浮点数的查找表verilog模块 --@param1 :有符号整数的长度 ------------------------------------------------------ function make_lut(len) print("module Int2Float_lut"..(len).."(") print(" input signed ["..(len-1)..": "..(0).."] din ,") print(" output [31:0] o_f //浮点数编码输出") print(");") print("wire signed ["..(len-1)..":"..(0).."] in=din["..(len-1).."] ==1? -din:din; //将数据转为无符号数") print("reg [7:0] e; //指数部分") print("reg [22:0] m ; //尾数部分") print("assign o_f={din["..(len-1).."], e, m};") print("always @(*) begin") if(len<=24) then print(" m={ {"..(24-len).."{1'b0}},in["..(len-2)..":0]} ;") else print(" m=in["..(len-2)..":"..(len-2-22).."];") end print(" casex(in)") for i=2,len do local s=" "..len.."'b0" for j=2,len do if(j<i) then s=s.."0" elseif(j==i) then s=s.."1" else s=s.."?" end end if(len <= 24) then s=s.." : begin e= 8'd"..(len-i).." + 8'd127 ; m = m<<"..(24-len).."+"..(i-1).."; end" else s=s.." : begin e= 8'd"..(len-i).." + 8'd127 ; m = m<<"..(i-1).."; end" end print(s) end print(" default: begin e=e; m=m; end ") print(" endcase") print(" end") print("endmodule") end make_lut(16) ``` 比如生成的16位有符号数转单精度浮点数的verilog模块: ```verilog module Int2Float_lut16( input signed [15: 0] din , output [31:0] o_f //浮点数编码输出 ); wire signed [15:0] in=din[15] ==1? -din:din; //将数据转为无符号数 reg [7:0] e; //指数部分 reg [22:0] m ; //尾数部分 assign o_f={din[15], e, m}; always @(*) begin m={ {8{1'b0}},in[14:0]} ; casex(in) 16'b01?????????????? : begin e= 8'd14 + 8'd127 ; m = m<<8+1; end 16'b001????????????? : begin e= 8'd13 + 8'd127 ; m = m<<8+2; end 16'b0001???????????? : begin e= 8'd12 + 8'd127 ; m = m<<8+3; end 16'b00001??????????? : begin e= 8'd11 + 8'd127 ; m = m<<8+4; end 16'b000001?????????? : begin e= 8'd10 + 8'd127 ; m = m<<8+5; end 16'b0000001????????? : begin e= 8'd9 + 8'd127 ; m = m<<8+6; end 16'b00000001???????? : begin e= 8'd8 + 8'd127 ; m = m<<8+7; end 16'b000000001??????? : begin e= 8'd7 + 8'd127 ; m = m<<8+8; end 16'b0000000001?????? : begin e= 8'd6 + 8'd127 ; m = m<<8+9; end 16'b00000000001????? : begin e= 8'd5 + 8'd127 ; m = m<<8+10; end 16'b000000000001???? : begin e= 8'd4 + 8'd127 ; m = m<<8+11; end 16'b0000000000001??? : begin e= 8'd3 + 8'd127 ; m = m<<8+12; end 16'b00000000000001?? : begin e= 8'd2 + 8'd127 ; m = m<<8+13; end 16'b000000000000001? : begin e= 8'd1 + 8'd127 ; m = m<<8+14; end 16'b0000000000000001 : begin e= 8'd0 + 8'd127 ; m = m<<8+15; end default: begin e=e; m=m; end endcase end endmodule ```