这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 综合技术 » 基础知识 » 详解FPGA定点数计算方法

共1条 1/1 1 跳转至

详解FPGA定点数计算方法

高工
2025-12-02 19:04:30     打赏

前言

FPGA定点数计算在高效资源利用、运算速度优势、硬件可预测性和成本效益等方面发挥着重要作用。它能节省逻辑和存储资源,实现更快速的运算和更高的时钟频率,保证行为可预测且易于硬件实现和验证,同时降低硬件和开发成本,广泛应用于数字信号处理、工业控制通信系统等领域。

基本定义

定义有符号写法和无符号数写法,其中定义和说明如下所示

符号类型有符号定点数无符号定点数
简写F/Q10.6UF/UQ10.6
数据位宽10+6=16bit1+9+6=16bit
符号位最高位
说明其中前10位表示整数位宽,后6位为小数位宽。其中整数的取值范围0−450-4^50−45,小数位的精度为(1/(26))(1/(2^6))(1/(26))。其中最高位为符号位,之后的9位表示整数位宽,最后后6位为小数位宽。
其中整数的取值范围0−290-2^90−29,小数位的精度为(1/(26))(1/(2^6))(1/(26))。

计算方式

计算流程

将两个相乘实数RA RB数据转化成对应=>UFa.b/Fa.b 格式数据: 先乘小数2b2^b2b

将转化后的两个定点数进行相乘

将相乘的结果进行位移操作,换算QA QB格式数据

在将QA QB定点数据格式进行移位得到实数RA RB,这个实数会损失精度

任意无符号定点数与任意无符号定点数相乘(无符号)

无符号定点数无符号定点数
QA=UFa.bQB=UFn.m
QA=UF9.7QB=UF1.15
RA=5.3RB=0.2
下面是计算过程
流程定点数计算过程实数计算数值
开始RA=5.3 RB=0.2
1QA=RA×2b=QAQA={RA×2^b=QA}QA=RA×2b=QA |QB=RB×2m=QBQB= {RB×2^m = QB}QB=RB×2m=QBQA=678 QB=6553
2(UQ(a+n).(b+m))=QA∗QB(UQ(a+n).(b+m))=QA*QB(UQ(a+n).(b+m))=QA∗QBQA×QB=8×6553.6=52428
3QA=QA∗QB>>mQA=QA*QB>>mQA=QA∗QB>>m |QB=QA∗QB>>bQB=QA*QB>>bQB=QA∗QB>>bQA=QAQB>>15=135 QB=QAQB>>7=34734
4RA=(UQa.b)>>bRA=(UQa.b)>>bRA=(UQa.b)>>b |RB=(UQn.m)>>mRB=(UQn.m)>>mRB=(UQn.m)>>mRA=(QA=UQ9.7)>>7=1 |RB=(QB=UQ1.15)>>15=1

任意有符号定点数与任意有符号定点数相乘

有符号定点数有符号定点数
QA=Fa.bQB=Fn.m
QA=F3.4QB=F2.3
RA=1.5RB=-2.25
下面是计算过程
实数计算中,若数据为负数,数据左移后将最高位补1,
流程定点数计算过程实数计算数值
开始RA=1.5 RB=-2.25
1QA=RA×2b=QAQA={RA×2^b=QA}QA=RA×2b=QA |QB=RB×2m=QBQB= {RB×2^m = QB}QB=RB×2m=QBQA=24 QB=46
2(Q(a+n).(b+m))=QA∗QB(Q(a+n).(b+m))=QA*QB(Q(a+n).(b+m))=QA∗QBQA×QB=15952
3QA=QA∗QB>>mQA=QA*QB>>mQA=QA∗QB>>m |QB=QA∗QB>>bQB=QA*QB>>bQB=QA∗QB>>bQA=QAQB>3=202 QB=QAQB>>4=37
4RA=(Qa.b)>>bRA=(Qa.b)>>bRA=(Qa.b)>>b |RB=(Qn.m)>>mRB=(Qn.m)>>mRB=(Qn.m)>>mRA=QA>>4=-3.375| RB=QB>>3=-3.375

小技巧

注意整数损失和小数精度损失
在进行定点数据计算前,需要人为考虑定点数计算后数据损失情况,若F(16.0)与F(1,15)相乘,如果使用F(17.15)数据不会损失太多信息
如果将F(17.15)=>F(16.0)则会损失小数精度。
如果将F(17.15)=>F(1.15)则会损失整数16位信息。

小数符号位的计算方法
在整个有符号数据计算时,所有的数据按照补码来计算,其中含负数和符号位乘法如下图所示。
4f38da00-ce8c-11f0-8c8f-92fbcf53809c.png

FPGA中截断定点数位宽
在进行定点数据计算时,有可能会出现输出不同精度数据情况,例如若F(8.8)与F(5,11)相乘,产生F(13,19),但是我需要输出F(6,10)这种精度。一般操作过程如下所示
如果将F(13,19)左移9位,变成F(13.9),在截断整数位,变成F(6,10)。
有符号定点数进行截位后注意符号位

FPGA中扩展定点数位宽
在进行定点数据计算时,有可能会出现将低精度数据扩展到高精度数据情况操作,例如若F(8.8)不通过乘法转换成F(9,13)。
整数部分:如果为负数,最高位补1,如果为正数,最高位补0。
小数部分:小数只需要补0即可。
有符号定点数进行截位后注意符号位

无符号与有符号数据实现
1在信号输入端,人为将无符号数通过assign或者always将无符号数据转换成有符号数,在进行运算。

无符号定点数乘法模块
4f933766-ce8c-11f0-8c8f-92fbcf53809c.png

//无符号数据乘法模块

module unsigned_fixed_point_multiplication#(

parameter P_A_DATA_DW = 16,

P_A_POINT_DW = 8,

P_B_DATA_DW = 16,

P_B_POINT_DW = 8 ,

P_Q_DW =P_A_DATA_DW +P_B_DATA_DW

)

(

input i_clk , // 时钟

input i_rst , // 复位

input wire [P_A_DATA_DW - 1:0] i_unsgined_a , // 第一个无符号定点数

input wire [P_B_DATA_DW - 1:0] i_unsgined_b , // 第二个无符号定点数

input wire i_unsgined_ab_vld , // 数据有效位

output wire [P_A_DATA_DW - 1:0] o_unsgined_cov_a , // 第一个无符号定点数类型结果

output wire [P_B_DATA_DW - 1:0] o_unsgined_cov_b , // 第二个无符号定点数类型结果

output wire o_unsgined_ab_vld , // 数据输出有效位

output wire [P_Q_DW - 1 :0] o_unsgined_c , // 不做删减的数据输出

output wire o_unsgined_c_vld // 数据输出有效位

);

localparam P_POINT_DW = P_A_POINT_DW + P_B_POINT_DW ;

reg [P_A_DATA_DW - 1:0] ri_unsgined_a ;

reg [P_B_DATA_DW - 1:0] ri_unsgined_b ;

reg ri_unsgined_ab_vld ;

reg [P_A_DATA_DW - 1:0] ro_unsgined_cov_a ;

reg [P_B_DATA_DW - 1:0] ro_unsgined_cov_b ;

reg ro_unsgined_ab_vld ;

reg [P_Q_DW - 1 :0] ro_unsgined_c ;

reg ro_unsgined_c_vld ;

assign o_unsgined_cov_a = ro_unsgined_cov_a ;

assign o_unsgined_cov_b = ro_unsgined_cov_b ;

assign o_unsgined_ab_vld = ro_unsgined_ab_vld ;

assign o_unsgined_c = ro_unsgined_c ;

assign o_unsgined_c_vld = ro_unsgined_c_vld ;

//数据暂存

always @(posedge i_clk or posedge i_rst) begin

if (i_rst) begin

ri_unsgined_a <= 'd0;

ri_unsgined_b <= 'd0;

ri_unsgined_ab_vld <= 'd0;

end else begin

ri_unsgined_a <= i_unsgined_a       ;

ri_unsgined_b <= i_unsgined_b       ;

ri_unsgined_ab_vld <= i_unsgined_ab_vld  ;

end

end

// 执行乘法运算

always @(posedge i_clk or posedge i_rst) begin

if (i_rst) begin

ro_unsgined_c <= 'd0;

ro_unsgined_c_vld <= 'd0;

end else if(ri_unsgined_ab_vld)begin

ro_unsgined_c <= ri_unsgined_a * ri_unsgined_b;

ro_unsgined_c_vld <= ri_unsgined_ab_vld;

end else begin

ro_unsgined_c <= ro_unsgined_c; 

ro_unsgined_c_vld <=  1'd0;

end

end

// 调整小数点位置

// 注意:这里没有进行舍入处理,根据需要可能需要添加

// 执行乘法运算

always @(posedge i_clk or posedge i_rst) begin

if (i_rst) begin

ro_unsgined_cov_a <= 'd0;

ro_unsgined_cov_b <= 'd0;

ro_unsgined_ab_vld <= 'd0;

end else if(ro_unsgined_c_vld)begin

ro_unsgined_cov_a <= ro_unsgined_c>>P_B_POINT_DW;

ro_unsgined_cov_b <= ro_unsgined_c>>P_A_POINT_DW;

ro_unsgined_ab_vld <= ro_unsgined_c_vld;

end else begin

ro_unsgined_cov_a <= ro_unsgined_cov_a; 

ro_unsgined_cov_b <=ro_unsgined_cov_b;

ro_unsgined_ab_vld <=  1'd0;

end

end

endmodule

有符号定点数乘法模块
4feb60a8-ce8c-11f0-8c8f-92fbcf53809c.png

//有符号数据乘法模块

module signed_fixed_point_multiplication#(

parameter P_A_DATA_DW = 8,

P_A_POINT_DW = 4,

P_B_DATA_DW = 6,

P_B_POINT_DW = 3 ,

P_Q_DW =P_A_DATA_DW +P_B_DATA_DW

)

(

input i_clk ,

input i_rst ,

input wire signed [P_A_DATA_DW - 1:0] i_sgined_a ,

input wire signed [P_B_DATA_DW - 1:0] i_sgined_b ,

input wire i_sgined_ab_vld ,

output wire signed [P_A_DATA_DW - 1:0] o_sgined_cov_a ,

output wire signed [P_B_DATA_DW - 1:0] o_sgined_cov_b ,

output wire o_sgined_ab_vld ,

output wire signed [P_Q_DW - 1 :0] o_sgined_c ,

output wire o_sgined_c_vld

);

reg signed [P_A_DATA_DW - 1:0] ri_sgined_a ;

reg signed [P_B_DATA_DW - 1:0] ri_sgined_b ;

reg ri_sgined_ab_vld ;

reg signed [P_A_DATA_DW - 1:0] ro_sgined_cov_a ;

reg signed [P_B_DATA_DW - 1:0] ro_sgined_cov_b ;

reg ro_sgined_ab_vld ;

reg signed [P_Q_DW - 1 :0] ro_sgined_c ;

reg ro_sgined_c_vld ;

assign o_sgined_cov_a = ro_sgined_cov_a ;

assign o_sgined_cov_b = ro_sgined_cov_b ;

assign o_sgined_ab_vld = ro_sgined_ab_vld ;

assign o_sgined_c = ro_sgined_c ;

assign o_sgined_c_vld = ro_sgined_c_vld ;

//数据暂存

always @(posedge i_clk or posedge i_rst) begin

if (i_rst) begin

ri_sgined_a <= 'd0;

ri_sgined_b <= 'd0;

ri_sgined_ab_vld <= 'd0;

end else begin

ri_sgined_a <= i_sgined_a       ;

ri_sgined_b <= i_sgined_b       ;

ri_sgined_ab_vld <= i_sgined_ab_vld  ;

end

end

// 执行乘法运算

always @(posedge i_clk or posedge i_rst) begin

if (i_rst) begin

ro_sgined_c <= 'd0;

ro_sgined_c_vld <= 'd0;

end else if(ri_sgined_ab_vld)begin

ro_sgined_c <= ri_sgined_a * ri_sgined_b;

ro_sgined_c_vld <= ri_sgined_ab_vld;

end else begin

ro_sgined_c <= ro_sgined_c; 

ro_sgined_c_vld <=  1'd0;

end

end

// 调整小数点位置

// 注意:这里没有进行舍入处理,根据需要可能需要添加

// 执行乘法运算

always @(posedge i_clk or posedge i_rst) begin

if (i_rst) begin

ro_sgined_cov_a <= 'd0;

ro_sgined_cov_b <= 'd0;

ro_sgined_ab_vld <= 'd0;

end else if(ro_sgined_c_vld)begin

ro_sgined_cov_a <= ro_sgined_c>>P_B_POINT_DW;

ro_sgined_cov_b <= ro_sgined_c>>P_A_POINT_DW;

ro_sgined_ab_vld <= ro_sgined_c_vld;

end else begin

ro_sgined_cov_a <= ro_sgined_cov_a; 

ro_sgined_cov_b <=ro_sgined_cov_b;

ro_sgined_ab_vld <=  1'd0;

end

end

endmodule



共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]