数字信号处理基础----xilinx除法器IP使用

前言

在进行数字信号处理的时候,计算是必不可少的,通常情况下,能够不用乘法器和除法器就不用乘除法器,可以采用移位和加减法的方式来完成计算。但在一些特殊情况下,希望采用乘除法,这时候在FPGA当中就需要专用的IP了。乘除法在FPGA当中实现起来是比较困难的一件事情。若直接在verilog 代码中使用了乘法或者除法,其实最终对应到电路中,要么是采用大量的block ram来实现,要么是占用DSP资源。这种情况下,对资源的占用是拿捏不准确。因此需要使用专用的乘除法器来实现乘除法。

1. 数据的表示

1.1原码,反码,补码

在进行数字信号处理的时候,这三个码首先得搞清楚了。例如

数据源码反码补码
65010000010100000101000001
-65110000011011111010111111

正数的源码补码,反码都是它本身。但是负数就需要注意了,关于如何来计算源码反码补码,其实也比较简单。

  • 首先最高位为符号位,余下的都是数据位。
  • 求得数据的绝对值,然后根据数据的正负,在最高位填0或1。正数填0,负数填1,就得到了数据的源码。
  • 若数据是负数
    • 那么保持最高位不变,其余位按位取反,就得到了数据的反码。
    • 保持高位不变,在反码的基础上加1就成了数据的补码。
      举几个简单例子。就用自带的计算器这个软件,调到程序员模式就开始计算。

首先是正数:例如100,那么它的二进制表示就是8’b0110_0100。
在这里插入图片描述
如果是负数:例如-100,那么他的二进制补码的表示就是 8’b1001_1100
在这里插入图片描述
在FPGA当中,数据都是以补码的形式存在的,知道了这个,就能够很好对数据进行运算了。

1.2 对数据求绝对值

由于在FPGA当中,数据都是以补码的形式存在的,因此对数据进行求绝对值的时候,就比较好操作了。如果一个数是正数,那么这个数据绝对值就是它本身。如果一个数是负数,那么直接按位取反再加一就可以了。

数据类型求绝对值方法
正数绝对值就是数据本身
负数按位取反再加一

还是上面的例子,-100的补码是8’1001_1100
在这里插入图片描述
它的绝对值是100。也就是8’b0110_0100。也就是由负数的补码,按位取反(包含符号位)再加一得到。
在这里插入图片描述

1.3 数据位宽的扩展与缩小

在进行数据位宽的扩展的时候,对于有符号数的处理,得格外的小心,最高位一定不能给搞忘了。
举个简单的例子:
用8bit表示一个正数100
在这里插入图片描述
现在用16bit来表示这个数,现在多了8bit,因此多出的高位的8bit,需要用原始数据的最高位来填充,也就是最高位全部填充0。
在这里插入图片描述
若用8bit数据表示一个负数 -100;
在这里插入图片描述
现在用16bit来表示这个数,现在多了8bit,因此多出的高位的8bit,需要用原始数据的最高位来填充,也就是最高位全部填充1。
在这里插入图片描述

1.4 定点数

前面写的都是整数,在FPGA当中如何来表示小数呢。这里就涉及到一个量化的问题,就是用一个整数来表示小数。在FPGA中常用的就是定点数来表示小数。所谓定点就是指小数点的位置是固定的。比如一个数用8位表示,符号位1位,整数位1位,小数位4位。那么如何使用定点数来表示一个这样的数呢。
比如4.5,按照上面的方式进行定点化。
4.5 × 2 4 = 72 4.5\times 2^{4}= 72 4.5×24=72
可以看到定点化之后的结果是72。其中符号位1位,整数位3位,小数位4位。
在这里插入图片描述
负数的定点化和正数类似。比如:
− 4.5 × 2 4 = − 72 -4.5\times 2^{4}= -72 4.5×24=72
在这里插入图片描述
个人在识别负数的时候,有个个人的小喜好。那就是符号位为1表示这个数是负数,那么最大的负数表示范围就是-2N-1(N是数据的位宽),那么用补码表示这个数据的时候,就是最大的负数表示范围加上后面的数。就比如这个 -72。最大的负数表示范围是-128,再加上后面的符号位后面的数就是结果。(歪门邪道,不可信)
其实可以看作: − 72 = − 2 7 + 2 5 + 2 4 + 2 3 -72 = -2^{7} + 2^{5}+2^{4}+2^{3} 72=27+25+24+23

1.4.1 量化误差

在使用定点数的时候,不可避免地会引入量化误差。这个量化误差的精度是由需要量化的小数的位宽决定的。比如一个8bit数,最高位符号位,3位整数位,4位小数位。那么量化位宽就是4位。因此量化的最小精度是1/24,也就是0.0625。
在这里举一个简单的例子。

对于1.0625在不同情况下,进行定点数的转化。
case(1) : 8bit数,最高位为符号位,3位整数位,4位小数位
case(2): 8bit数,最高位为符号位,4位位整数, 3位小数位

对于第一种情况:量化的结果为: 1.0625 × 2 4 = 17 1.0625\times 2^{4} = 17 1.0625×24=17
能够完整地表达出原始的数据,1.0625
在这里插入图片描述

对于第二种情况:量化的结果为: 1.0625 × 2 3 = 8.5 ≅ 8 1.0625\times 2^{3} = 8.5\cong 8 1.0625×23=8.58
此时由于量化,导致量化后的数据相较于原始数据有了误差,能表达的数据是1。
在这里插入图片描述
对比上面两种情况可以看出,当小数位为3位的时候,对1.0625进行量化的时候,就出现了量化的误差。这个就是由量化的位宽(量化精度)引起的。

1.4.2 负数的定点化

负数的定点化其实和前面正数的定点化是类似的。只是最终需要取补码。
例如: 最高位为符号位,3位整数位,4位小数位
− 1.0625 × 2 4 = − 17 -1.0625\times 2^{4} = -17 1.0625×24=17
在这里插入图片描述
其实和前面一样的,最高位符号位为1,最大负数表示范围:-8。因此
− 8 + 2 2 + 2 1 + 2 − 1 + 2 − 2 + 2 − 3 + 2 − 4 = − 1.0625 -8+2^{2}+2^{1}+2^{-1}+2^{-2}+2^{-3}+2^{-4}= -1.0625 8+22+21+21+22+23+24=1.0625(歪门邪道,且不可信233333333)

2. xilinx除法器IP使用

IP的配置界面如下啦:

  • 设置除法器的类型,基二还是还是查找表。
  • 然后是被除数和除数的位宽。
  • 然后数余数类型。
  • 可以选择小数和余数。
  • 小数的部分的位宽

在左边可以看到输入输出信号的在总线上所占据的bit。
在这里插入图片描述

简简单单仿个真

// -----------------------------------------------------------------------------
// Copyright (c) 2014-2020 All rights reserved
// -----------------------------------------------------------------------------
// Author 	 : WCC 1530604142@qq.com
// File   	 : tb_divider_sim
// Create 	 : 2020-12-24
// Revise 	 : 2020-
// Editor 	 : Vscode, tab size (4)
// Functions : divider test
// 			   
// -----------------------------------------------------------------------------
`timescale 1ns / 1ps
module tb_divider_sim();

reg                 clk             ;
reg signed [15:0]   divisor         ;
reg signed [15:0]   dividend        ;
reg                 data_in_tvalid  ;

wire                div_valid       ;
wire signed [31:0]  div_data        ;


div_gen_0 inst_divider (
    .aclk(clk),                             // input wire aclk
    .s_axis_divisor_tvalid(data_in_tvalid), // input wire s_axis_divisor_tvalid
    .s_axis_divisor_tdata(divisor),         // input wire [15 : 0] s_axis_divisor_tdata
    .s_axis_dividend_tvalid(data_in_tvalid),// input wire s_axis_dividend_tvalid
    .s_axis_dividend_tdata(dividend),       // input wire [15 : 0] s_axis_dividend_tdata
    .m_axis_dout_tvalid(div_valid),         // output wire m_axis_dout_tvalid
    .m_axis_dout_tdata(div_data)            // output wire [31 : 0] m_axis_dout_tdata
);

initial begin
    clk = 0;
    forever #(10) clk = ~clk;
end

initial begin
    data_in_tvalid = 0;
    dividend = 0;
    divisor = 0;
    repeat(100)@(posedge clk);

    data_in_tvalid = 1;
    divisor = 16'd5;
    dividend = 16'd25;
    
    repeat(30)@(posedge clk);
    divisor = 16'd5;
    dividend = -16'd25;

    repeat(30)@(posedge clk);
    divisor = 16'd5;
    dividend = 16'd12;

    repeat(30)@(posedge clk);
    divisor = 16'd5;
    dividend = -16'd12;

    repeat(30)@(posedge clk);
    divisor = 16'd5;
    dividend = -16'd4;

    repeat(30)@(posedge clk);
    divisor = 16'd5;
    dividend = -16'd4;
end
endmodule

2.3 仿真结果

从输入的激励来看,前两个是能够被整除的,后面几个是不能被整除的。
在这里插入图片描述
这里看一下不能被整除的这几个。

  • 12/5

    这个得到的结果该是2.4,可以看到整数部分是2,小数部分是0.4。
    在前面设置IP的时候,可以看到,指示小数部分的数据位宽16bit,其中符号位1位,所以量化精度就是1/215
    在这里插入图片描述
    于是可以计算一下,用15位去量化这个小数的时候,计算出来的结果
    0.4 × 2 15 = 13107.2 ≅ 13107 0.4\times 2^{15}= 13107.2\cong 13107 0.4×215=13107.213107
    量化后的结果是13107,16进制就是16’h3333。而这也正好是上面仿真的到的结果。
    在这里插入图片描述在这里插入图片描述
  • -12/5

    这个结果得到的是-2.4,整数部分是-2,小数部分是-0.4。
    小数部分量化得到的结果是:
    在这里插入图片描述
    换成16进制表示:
    在这里插入图片描述
    与仿真得到的结果一致,简直是nice

2.4 除法器IP的总结

可以看到除法器IP的使用,需要指定除法器的基于类型,除数和被除数的位宽,得到结果的余数类型需要指定。然后还需要注意的是,除法器使用的接口是axis接口的,只有在valid有效的时候,才会开始计算。
同时也还要注意到,除法器得到结果是需要很长的latency的。这个latency可以设置。合适的才是最好的

  • 14
    点赞
  • 64
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值