提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
对于FPGA而言,其对对数运算是十分有限的,但在某些特殊场景种,需要进行精度不高但快速的对数运算,FPGA就体现了他计算速度的优势,本文主要介绍采用Verilog实现对数运算的原理及实现方法。
一、理论基础
对数换底公式:
log
2
A
\log_2A
log2A计算变换:
A =
∑
i
=
0
N
−
1
a
i
2
i
\sum_{i=0}^{N-1} a_i2^i
∑i=0N−1ai2i ,其中N为A的bit位宽,
a
i
a_i
ai为各bit的数据(0或1)
若A中不为0的最高bit位为k,即
a
k
a_k
ak=1,
a
i
a_i
ai(i>k)均为0,则:
因
A
/
2
k
A/2^k
A/2k < 2,则0<
log
2
(
A
/
2
k
)
\log_2(A/2^k)
log2(A/2k) <1,那么就将
log
2
A
\log_2A
log2A的运算分为2个部分:整数部分k和小数部分
log
2
(
A
/
2
k
)
\log_2(A/2^k)
log2(A/2k)。
因1/
log
2
D
\log_2D
log2D位固定值,故采用乘法器可计算出最终的
二、Verilog实现方法
提供一种Verilog计算log2的计算方法,最终计算
log
D
A
\log_DA
logDA需增加乘法,实际应用中,受底数和其它影响,乘法器设计较为灵活,所以不提供乘法器设计,仅仅提供log2的计算方法。
1、查找不为0的最高bit位k,查找方法可开用bit轮询查找或case查找。bit轮询查找每次只能查找1个bit,耗时较长,case查找可在最短1个时钟找到。
2、小数位计算,从k-1bit位开始,依次向后取m个bit数据,m的大小影响计算精度,m越大,精度越高。最终得到mbit的数据,将该数据作为查找表的索引即地址,查询查找表的数据即小数部分F。
3、定点即运算
如最终结果定点位Fix16_8,8位小数位,则查找表中的数据位宽位8,均为小数。7位整数,将K右移8位并扩展到16位即可得到整数位数据,整数位数据和小数位数据相加即为最终
log
2
A
\log_2A
log2A的值。
因1/
log
2
D
\log_2D
log2D位固定值,故采用乘法器可计算出最终的
log
D
A
\log_DA
logDA
4、查找表制定
查找表通过matlab制定,并定点后写入文件存储,如采用m=8,数据为8位数据
m = 8;
a = log2(1+(0:2^m-1)/2^m);
a_fix_hex = dec2hex(fi(a,1,9,8)*2^m,2);
%%将a_fix_hex写入文件即可
三、Verilog实现代码
根据以上设计,提供32bit数据log2的计算方式,以做参考,其中输出数据小数位宽位8bit,小数位计算精度为8bit。
接口
module log # (
parameter O_WIDTH_F = 8, //output 小数位宽
localparam I_WIDTH = 32, //input width (固定32bit,不足32bit输入高位补0)
localparam O_WIDTH = O_WIDTH_F + $clog2(I_WIDTH) //output width,O_WIDTH >= O_WIDTH_F + $clog2(I_WIDTH)
)(
input clk,
input [I_WIDTH-1 : 0] i_data,
output reg [O_WIDTH-1 : 0] o_data
);
计算整数位及小数位索引
该计算采用case实现,可减少计算时间,1个时钟周期即可完成整数位计算和小数位索引计算。
always @ (posedge clk) begin
casez(r_i_data)
{{00{1'b0}},1'b1,{(I_WIDTH-01){1'b?}}}: begin int_d <= I_WIDTH - 01; fra_index <= (PRECISION_W <= 31)? r_i_data[30 -: PRECISION_W] : {r_i_data[30 -: 31],{(PRECISION_W-31){1'b0}}}; end
{{01{1'b0}},1'b1,{(I_WIDTH-02){1'b?}}}: begin int_d <= I_WIDTH - 02; fra_index <= (PRECISION_W <= 30)? r_i_data[29 -: PRECISION_W] : {r_i_data[29 -: 30],{(PRECISION_W-30){1'b0}}}; end
{{02{1'b0}},1'b1,{(I_WIDTH-03){1'b?}}}: begin int_d <= I_WIDTH - 03; fra_index <= (PRECISION_W <= 29)? r_i_data[28 -: PRECISION_W] : {r_i_data[28 -: 29],{(PRECISION_W-29){1'b0}}}; end
{{03{1'b0}},1'b1,{(I_WIDTH-04){1'b?}}}: begin int_d <= I_WIDTH - 04; fra_index <= (PRECISION_W <= 28)? r_i_data[27 -: PRECISION_W] : {r_i_data[27 -: 28],{(PRECISION_W-28){1'b0}}}; end
{{04{1'b0}},1'b1,{(I_WIDTH-05){1'b?}}}: begin int_d <= I_WIDTH - 05; fra_index <= (PRECISION_W <= 27)? r_i_data[26 -: PRECISION_W] : {r_i_data[26 -: 27],{(PRECISION_W-27){1'b0}}}; end
{{05{1'b0}},1'b1,{(I_WIDTH-06){1'b?}}}: begin int_d <= I_WIDTH - 06; fra_index <= (PRECISION_W <= 26)? r_i_data[25 -: PRECISION_W] : {r_i_data[25 -: 26],{(PRECISION_W-26){1'b0}}}; end
{{06{1'b0}},1'b1,{(I_WIDTH-07){1'b?}}}: begin int_d <= I_WIDTH - 07; fra_index <= (PRECISION_W <= 25)? r_i_data[24 -: PRECISION_W] : {r_i_data[24 -: 25],{(PRECISION_W-25){1'b0}}}; end
{{07{1'b0}},1'b1,{(I_WIDTH-08){1'b?}}}: begin int_d <= I_WIDTH - 08; fra_index <= (PRECISION_W <= 24)? r_i_data[23 -: PRECISION_W] : {r_i_data[23 -: 24],{(PRECISION_W-24){1'b0}}}; end
{{08{1'b0}},1'b1,{(I_WIDTH-09){1'b?}}}: begin int_d <= I_WIDTH - 09; fra_index <= (PRECISION_W <= 23)? r_i_data[22 -: PRECISION_W] : {r_i_data[22 -: 23],{(PRECISION_W-23){1'b0}}}; end
{{09{1'b0}},1'b1,{(I_WIDTH-10){1'b?}}}: begin int_d <= I_WIDTH - 10; fra_index <= (PRECISION_W <= 22)? r_i_data[21 -: PRECISION_W] : {r_i_data[21 -: 22],{(PRECISION_W-22){1'b0}}}; end
{{10{1'b0}},1'b1,{(I_WIDTH-11){1'b?}}}: begin int_d <= I_WIDTH - 11; fra_index <= (PRECISION_W <= 21)? r_i_data[20 -: PRECISION_W] : {r_i_data[20 -: 21],{(PRECISION_W-21){1'b0}}}; end
{{11{1'b0}},1'b1,{(I_WIDTH-12){1'b?}}}: begin int_d <= I_WIDTH - 12; fra_index <= (PRECISION_W <= 20)? r_i_data[19 -: PRECISION_W] : {r_i_data[19 -: 20],{(PRECISION_W-20){1'b0}}}; end
{{12{1'b0}},1'b1,{(I_WIDTH-13){1'b?}}}: begin int_d <= I_WIDTH - 13; fra_index <= (PRECISION_W <= 19)? r_i_data[18 -: PRECISION_W] : {r_i_data[18 -: 19],{(PRECISION_W-19){1'b0}}}; end
{{13{1'b0}},1'b1,{(I_WIDTH-14){1'b?}}}: begin int_d <= I_WIDTH - 14; fra_index <= (PRECISION_W <= 18)? r_i_data[17 -: PRECISION_W] : {r_i_data[17 -: 18],{(PRECISION_W-18){1'b0}}}; end
{{14{1'b0}},1'b1,{(I_WIDTH-15){1'b?}}}: begin int_d <= I_WIDTH - 15; fra_index <= (PRECISION_W <= 17)? r_i_data[16 -: PRECISION_W] : {r_i_data[16 -: 17],{(PRECISION_W-17){1'b0}}}; end
{{15{1'b0}},1'b1,{(I_WIDTH-16){1'b?}}}: begin int_d <= I_WIDTH - 16; fra_index <= (PRECISION_W <= 16)? r_i_data[15 -: PRECISION_W] : {r_i_data[15 -: 16],{(PRECISION_W-16){1'b0}}}; end
{{16{1'b0}},1'b1,{(I_WIDTH-17){1'b?}}}: begin int_d <= I_WIDTH - 17; fra_index <= (PRECISION_W <= 15)? r_i_data[14 -: PRECISION_W] : {r_i_data[14 -: 15],{(PRECISION_W-15){1'b0}}}; end
{{17{1'b0}},1'b1,{(I_WIDTH-18){1'b?}}}: begin int_d <= I_WIDTH - 18; fra_index <= (PRECISION_W <= 14)? r_i_data[13 -: PRECISION_W] : {r_i_data[13 -: 14],{(PRECISION_W-14){1'b0}}}; end
{{18{1'b0}},1'b1,{(I_WIDTH-19){1'b?}}}: begin int_d <= I_WIDTH - 19; fra_index <= (PRECISION_W <= 13)? r_i_data[12 -: PRECISION_W] : {r_i_data[12 -: 13],{(PRECISION_W-13){1'b0}}}; end
{{19{1'b0}},1'b1,{(I_WIDTH-20){1'b?}}}: begin int_d <= I_WIDTH - 20; fra_index <= (PRECISION_W <= 12)? r_i_data[11 -: PRECISION_W] : {r_i_data[11 -: 12],{(PRECISION_W-12){1'b0}}}; end
{{20{1'b0}},1'b1,{(I_WIDTH-21){1'b?}}}: begin int_d <= I_WIDTH - 21; fra_index <= (PRECISION_W <= 11)? r_i_data[10 -: PRECISION_W] : {r_i_data[10 -: 11],{(PRECISION_W-11){1'b0}}}; end
{{21{1'b0}},1'b1,{(I_WIDTH-22){1'b?}}}: begin int_d <= I_WIDTH - 22; fra_index <= (PRECISION_W <= 10)? r_i_data[09 -: PRECISION_W] : {r_i_data[09 -: 10],{(PRECISION_W-10){1'b0}}}; end
{{22{1'b0}},1'b1,{(I_WIDTH-23){1'b?}}}: begin int_d <= I_WIDTH - 23; fra_index <= (PRECISION_W <= 09)? r_i_data[08 -: PRECISION_W] : {r_i_data[08 -: 09],{(PRECISION_W-09){1'b0}}}; end
{{23{1'b0}},1'b1,{(I_WIDTH-24){1'b?}}}: begin int_d <= I_WIDTH - 24; fra_index <= (PRECISION_W <= 08)? r_i_data[07 -: PRECISION_W] : {r_i_data[07 -: 08],{(PRECISION_W-08){1'b0}}}; end
{{24{1'b0}},1'b1,{(I_WIDTH-25){1'b?}}}: begin int_d <= I_WIDTH - 25; fra_index <= (PRECISION_W <= 07)? r_i_data[06 -: PRECISION_W] : {r_i_data[06 -: 07],{(PRECISION_W-07){1'b0}}}; end
{{25{1'b0}},1'b1,{(I_WIDTH-26){1'b?}}}: begin int_d <= I_WIDTH - 26; fra_index <= (PRECISION_W <= 06)? r_i_data[05 -: PRECISION_W] : {r_i_data[05 -: 06],{(PRECISION_W-06){1'b0}}}; end
{{26{1'b0}},1'b1,{(I_WIDTH-27){1'b?}}}: begin int_d <= I_WIDTH - 27; fra_index <= (PRECISION_W <= 05)? r_i_data[04 -: PRECISION_W] : {r_i_data[04 -: 05],{(PRECISION_W-05){1'b0}}}; end
{{27{1'b0}},1'b1,{(I_WIDTH-28){1'b?}}}: begin int_d <= I_WIDTH - 28; fra_index <= (PRECISION_W <= 04)? r_i_data[03 -: PRECISION_W] : {r_i_data[03 -: 04],{(PRECISION_W-04){1'b0}}}; end
{{28{1'b0}},1'b1,{(I_WIDTH-29){1'b?}}}: begin int_d <= I_WIDTH - 29; fra_index <= (PRECISION_W <= 03)? r_i_data[02 -: PRECISION_W] : {r_i_data[02 -: 03],{(PRECISION_W-03){1'b0}}}; end
{{29{1'b0}},1'b1,{(I_WIDTH-30){1'b?}}}: begin int_d <= I_WIDTH - 30; fra_index <= (PRECISION_W <= 02)? r_i_data[01 -: PRECISION_W] : {r_i_data[01 -: 02],{(PRECISION_W-02){1'b0}}}; end
{{30{1'b0}},1'b1,{(I_WIDTH-31){1'b?}}}: begin int_d <= I_WIDTH - 31; fra_index <= (PRECISION_W <= 01)? r_i_data[00 -: PRECISION_W] : {r_i_data[00 -: 01],{(PRECISION_W-01){1'b0}}}; end
{{31{1'b0}},1'b1,{(I_WIDTH-32){1'b?}}}: begin int_d <= I_WIDTH - 32; fra_index <= (PRECISION_W <= 00)? r_i_data[00 -: PRECISION_W] :{(PRECISION_W-00){1'b0}}; end
default:begin int_d <= {$clog2(I_WIDTH){1'b0}}; fra_index <= {PRECISION_W{1'b0}};end
endcase
end
ROM设计及读取
(* rom_style="{distributed | block}" *)
reg [O_WIDTH_F-1:0] log_rom [(2**PRECISION_W)-1:0];
reg [O_WIDTH_F-1:0] fra_data;
initial
$readmemh("log2_f.txt", log_rom, 0, (2**PRECISION_W)-1);
always @(posedge clk) fra_data <= log_rom[fra_index];
log2结果输出
always @(posedge clk) o_data <= {int_d_c0,fra_data};
四、仿真
仿真tb比较简单,建立时钟及32bit输入数据即可
module tb_log(
);
reg clk = 1'b0;
reg [31:0] i_data = 32'd0;
wire [12:0] o_data;
always #5 clk <=~clk;
always @(posedge clk) i_data <= i_data + 1'b1;
log DUT(
.clk(clk),
.i_data(i_data),
.o_data(o_data)
);
endmodule
最终仿真结果如下
五、典型工程应用
计算功率:
将3中
log
2
A
\log_2A
log2A的结果乘以6即可得到最后的功率,乘以6可采用
log
2
A
\log_2A
log2A<<2 +
log
2
A
\log_2A
log2A<<1;
将3中 log 2 A \log_2A log2A的结果乘以3即可得到最后的功率,乘以3可采用 log 2 A \log_2A log2A<<1 + log 2 A \log_2A log2A;
定点数log计算:
以上的计算均是以A为整数计算的,得到的结果全为正,在实际应用中,可能A为定点小数,得到的结果可能为正也可能为负。此时在设计时需要将A做一个变式,即可转化为整数的log计算和加法。如定义B为Fix16_8的无符号定点数(分辨率为0.00390625),则:
令
A
=
B
∗
2
8
A =B*2^8
A=B∗28,A为整数,则:
这样就将定点小数的对数运算转换为定点整数的对数运算。文章来源:https://www.toymoban.com/news/detail-758372.html
源文件参考
https://download.csdn.net/download/u014035968/88311247文章来源地址https://www.toymoban.com/news/detail-758372.html
到了这里,关于Verilog实现对数运算log的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!