探索定点数实验

  • 使用二进制表示数字,是计算机科学中最基本的问题之一。
  • 使用FPGA进行数学运算,本质上是把数学模型、公式、映射成数字电路。
  • 用FPGA实现定点数运算,对于设计运算单元电路很重要。
  • 请自行设计若干实验,实现和验证课堂上讲过的关于定点数的知识,例如:
    • 2补码的溢出回绕特性
    • 不同长度的2补码数据进行运算时,先进行符号扩展和数据对齐,然后再进行加、减法运算
    • 乘法和加法对字长的影响,验证2补码整数的乘法和加法运算
    • 定点数实验,验证带小数位的定点数的乘加运算
  • 仿真工具,可以使用Modelsim,或是Quartus的波形仿真,也可以使用Matlab辅助。
  • 仿真验证通过之后,在Quartus里面编译一下电路,关注你的电路消耗了多少FPGA资源,这是很有用的经验。
  • 请把完成的所有实验内容写在一篇博客里,文档尽量条理清楚,便于教师阅读。

实验一 2补码的溢出回绕特性

  • 知识背景:
    在有符号数中,最小值-1=最大值,最大值-1=最小值。我们称之为回绕wrap around。
    为什么最小值-1=最大值?这要从计算机内部数字表示形式开始,都是采用补码表示。
    补码表示有一些好处:
    1、 统一了0([0]补=0000;).
    2、 把减法都可以转换为加法。
    3、 良好的溢出性质
    补码加法:
    [x]补+[y]补=[x+y]补
    例:x=+1011;y=-0101;求x+y;
    解:[x]补=01011;[y]补=11011;
    [x]补   01011
    [y]补   11011
    [x+y]补 (进位1丢掉)00110
    结果为x+y=+0110;
    补码加法的特点:1是符号位要作为数的一部分参与运算,而是要在模2^(n+1)的意义下相加,即超过2^(n+1)要丢掉。
    实验验证2补码的溢出回绕特性
    先令两个有符号四位二进制数相加溢出,再将结果减去一个有符号四位二进制数,的最终运算结果,观察验证结果是否正确。

  • quartus代码片:

module lab1(a,b,c,sum);
input  signed [4-1:0] a,b,c;
output signed [4-1:0] sum;
assign sum = a + b + c;
endmodule
  • modelsim代码片
`timescale 1 ps/ 1 ps
module lab1_vlg_tst();
reg eachvec;
reg [3:0] a;
reg [3:0] b;
reg [3:0] c;                                           
wire [3:0] sum;                      
lab1 i1 ( 
    .a(a),
    .b(b),
    .c(c),
    .sum(sum)
);
initial                                                
begin                                                  
a=1;
b=1;
c=1;                    
end                                                    
always                                                                
begin
#10 a=a+1;
b=b+2;
c=c+3;                                                                                                                                                 
end                                                    
endmodule
  • Modelsim仿真图

这里写图片描述

  • 实验分析:

    有符号四位的范围为-8~7;由modelsim仿真图可以看出,4+7=11(溢出),4+7-6=5,结果正确,由此有验证了2补码的溢出回绕特性。

  • 占用资源图

这里写图片描述

实验二 不同长度的2补码数据运算

  • 实验验证:
    先设计一个无符号的三位二进制数a和一个有符号的四位二进制数b,a补一位和b相加得sum1,a补两位,b补一位,两者此时数据对齐,相加得sum2,观察sum1和sum2是否和正确一致。

  • quartus代码片:

module lab_2(a,b,c,sum1,sum2);
input           [2:0]a;
input  signed   [3:0]b;
output signed   [4:0]c;
output          [3:0]sum1;
output          [4:0]sum2;
reg             [4:0]c;
reg             [3:0]sum1;
reg             [4:0]sum2;

always@(a or b or c  )
begin
c={2'b0,a};
sum1={1'b0,a}+b;
if(b[3]==0)
sum2=c+{1'b0,b};
else
sum2=c+{1'b1,b};
end

endmodule

  • modelsim代码片:
module lab_2_vlg_tst();
reg eachvec;
reg       [2:0] a;
reg signed[3:0] b;                                            
wire [3:0] sum1;
wire [4:0] sum2;
wire [4:0] c;

lab_2 i1 ( 
    .a(a),
    .b(b),
    .c(c),
    .sum1(sum1),
    .sum2(sum2)
);
initial                                                
begin                                                  
a=0;
b=4'b1001;                     
end                                                    
always                                                               
begin                                                  
#10
a=a+1;
if(b==4'b0111)
b=4'b1001;
else
b=b+1;                                         
end                                                    
endmodule
  • Modelsim仿真图
    这里写图片描述

  • 实验分析

    由modelsim仿真图可知,sum1部分结果正确,sum2结果完全正确,由此可知不同长度的2补码数据进行运算时,先进行符号扩展和数据对齐,然后再进行加、减法运算。

  • 占用资源图
    这里写图片描述

实验三 2补码整数的乘法和加法运算

  • 实验验证
    有符号的三位二进制数a和有符号的四位二进制数b相加得四位的二进制数s1;
    有符号的四位二进制数b和有符号的四位二进制数c相加得四位的二进制数s2和四位的二进制数s3;
    有符号的四位二进制数b和有符号的四位二进制数c相乘得四位二进制数m1,七位二进制数m2以及八位二进制数m3;

  • quartus代码片

module lab_3(a,b,s1,s2,s3,m1,m2,m3);
input  signed [2:0]a;
input  signed [3:0]b;
output signed [3:0]s1;
output signed [3:0]s2;
output signed [4:0]s3;
output        [5:0]m1;
output        [6:0]m2;
output        [7:0]m3;
reg           [3:0]s1;
reg           [3:0]s2;
reg           [4:0]s3;
reg           [3:0]m1;
reg           [6:0]m2;
reg           [7:0]m3;
parameter   signed  [3:0]c=4'b1001;


always@(a or b )
begin
s1=a+b;
s2=b+c;
s3=b+c;
m1=b*c;
m2=b*c;
m3=b*c;
end

endmodule
  • modelsim代码片
module lab_3_vlg_tst();
reg eachvec;
reg [2:0] a;
reg [3:0] b;                                              
wire [3:0] m1;
wire [6:0] m2;
wire [7:0] m3;
wire [3:0] s1;
wire [3:0] s2;
wire [4:0] s3;

lab_3 i1 (  
    .a(a),
    .b(b),
    .m1(m1),
    .m2(m2),
    .m3(m3),
    .s1(s1),
    .s2(s2),
    .s3(s3)
);
initial                                                
begin                                                  
a=0;
b=4'b1001;                     
end                                                    
always                                                                
begin                                                  
#10
a=a+1;
if(b==4'b0111)
b=4'b1001;
else
b=b+2;                                         
end                                                    
endmodule
  • modelsim仿真图
    这里写图片描述
  • 实验分析

    通过modelsim仿真结果可看出,s2结果有错误,s3结果正确,这是因为两数相加可能会溢出,所以字长的选择应为字长长的被加数的字长加一; m1结果错误,m2和m3结果正确,两数相乘字长的选择为两个被乘数字长相加再减一;

  • 占用资源图
    这里写图片描述

实验四 小数位的定点数的乘加运算

  • 知识背景
    定点小数,就是小数点是固定的。我们要用整数来表示定点小数,由于小数点的位置是固定的,所以就没有必要存储它们(如果存储了小数点的位置,那就是浮点数)。既然没有存储小数点的位置,那么计算机就不知道小数点的位置,所以小数点的位置是写程序的人自己需要牢记的。
    定点小数运算,实际上1就是用整数来进行小数运算。如果我们能够计算12+34=46的话,当然也就能够计算1.2+3.4 或者 0.12+0.34了。所以定点小数的加减法和整数的相同,并且和小数点的位置无关。乘法就不同了。 12*34=408,而1.2*3.4=4.08。这里1.2的小数点在第1位之前,而4.08的小数点在第2位之前,小数点发生了移动。所以在做乘法的时候,需要对小数点的位置进行调整?!可是既然我们是做定点小数运算,那就说小数点的位置不能动!!怎么解决这个矛盾呢,那就是舍弃最低位。 也就说1.2*3.4=4.1,这样我们就得到正确的定点运算的结果了。所以在做定点小数运算的时候不仅需要牢记小数点的位置,还需要记住表达定点小数的有效位数。

  • 实验验证
    八位无符号二进制数00110111,假设这个数的整数部分为四位,小数部分为四位,那么它所表示的十进制数为3.4375。
    num1和num2相加得八位二进制数t1;
    num1和num2相乘得九位二进制数t2;
    num1和num2相乘得十位二进制数t3;
    num1和num2相乘得十一位二进制数t4;
    num1和num2相乘得十二位二进制数t5;
    num1和num2相乘得十三位二进制数t6;

  • quartus代码片

module lab_4(t1,t2,t3,t4,t5,t6);
output [7:0]t1;
output [8:0]t2;
output [9:0]t3;
output [10:0]t4;
output [11:0]t5;
output [12:0]t6;
reg    [7:0]t1;
reg    [8:0]t2;
reg    [9:0]t3;
reg    [10:0]t4;
reg    [11:0]t5;
reg    [12:0]t6;

parameter num1=8'b00110111;//num1=8'b0011.0111=3.4375
parameter num2=8'b00110111;//num2=8'b0011.0111=3.4375

always@(t1 or t2 or t3 or t4 or t5 or t6)
begin
t1=num1+num2;
t2=num1*num2;
t3=num1*num2;
t4=num1*num2;
t5=num1*num2;
t6=num1*num2;

end
endmodule
  • 波形仿真图
    这里写图片描述

  • 实验分析
    通过观察结果可知,t1、t5、t6结果正确,t2、t3、t4结果错误。从t2到t5,随着字长的增加,低位的数值没有变,高位的数值逐渐趋于正确值。所以在进行定点小数运算时,需提前预估好的字长。3.4375的整数部分是两位,两数相乘之后最多为4位,小数部分为4位,两数相乘后最多为8位,所以结果所以需的字长最少应为12位,即有效位数位12位,然后通过小数点的位置,便可得到正确的结果。而实验结果刚好得到印证上述这一点。

  • 占用资源图
    这里写图片描述
### FPGA定点数乘法的实现方法与优化 #### 定点数表示的重要性 在FPGA设计中,定点数是一种非常重要的数值表示方式。通过使用定点数可以显著降低硬件复杂度和减少计算量,从而更好地满足实时应用和数字信号处理领域的需求[^1]。 #### 定点数乘法的三种常见写法及其优缺点分析 对于FPGA中的定点数乘法操作,通常有以下三种不同的实现方法: 1. **直接乘法** 使用标准的乘法指令来完成运算。这种方法的优点在于其实现简单直观,但在资源消耗方面表现较差。例如,在某些情况下,直接乘法会占用更多的查找表(LUTs),达到252个单位[^2]。 2. **移位操作替代乘法** 利用二进制特性,将部分乘法转换为简单的移位操作。这种方式能够有效减少组合逻辑资源的消耗,其LUT需求仅为217个单位,并且具有更好的时序性能(最差路径延迟为-0.630 ns)。 3. **位拼接加法** 将复杂的乘法分解成多个较小规模的加法以及相应的位拼接操作。此方案同样能大幅削减所需的LUT数目至217个单位并改善时序违例状况到-0.630 ns级别。然而需要注意的是,当涉及较多级联加法器时(如`a × 15 = a × (8 + 4 + 2 + 1)`),实际效果可能因增加过多加法器而导致新的瓶颈问题出现。 #### 正负数之间的定点小数乘法规则 针对正数与负数之间或者两个负数间的定点小数乘法,遵循如下步骤执行: 1. 若存在负数参与运算,则先将其转为对应的正值形式(采用补码机制:按位取反后再加一)。 2. 接下来按照常规两正整数相乘的方式开展具体计算过程(忽略符号位的影响)。 3. 计算所得结果的符号由原始输入数据的符号位异或决定。 4. 如果最终得出的结果符号位为“1”,那么需补充高位填充“1”直至满足目标精度下的总宽度要求;反之亦然。 5. 整合以上各环节成果形成完整的输出值,其中最高一位代表整体符号状态,其余低位构成具体的数值信息[^3]。 #### 示例代码展示 以下是基于Verilog HDL的一个简化版定点数乘法模块实例: ```verilog module fixed_point_multiplier ( input signed [9:0] multiplicand, // 被乘数 input signed [9:0] multiplier, // 乘数 output reg signed [10:0] product // 结果 ); always @(*) begin product = multiplicand * multiplier; end endmodule ``` 该模块接受两位十比特带符号输入参数,并返回它们积作为十一比特长度的数据流。 #### 浮点数对比及应用场景考量 相较于浮点数而言,尽管后者提供了更高的动态范围灵活性,但由于内部结构更加繁琐,往往伴随着更大的面积开销与时钟频率限制等问题。相比之下,合理配置后的定点算法能够在许多特定场合下提供更为优越的整体性价比表现[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值