这一篇在干嘛?

FPGA 里怎么”算数”:定点数/浮点数的表示、加法器/乘法器/除法器的电路实现、CORDIC 算开方与三角函数——一切 DSP 运算的地基。 原书代码为 VHDL,本篇所有代码已改写为 Verilog。

  • 计算机算法
  • 2.1 计算机算法概述
  • 2.2 数字表示法
    1. 无符号整数(Unsigned Integer)
    1. 有符号数值(Signed-Magnitude, SM)
    1. 二进制补码(Two’s Complement, 2C)
    1. 二进制反码(也称作1的补码,One’s Complement, 1C)
    1. 减 1 系统(Diminished one System, D1)
    1. 偏差系统(Bias System)
    1. 有符号数字(Signed Digit Number, SD)
  • 例2.1 SD编码
  • 算法 2.1: 经典 CSD 编码
  • 例2.2 经典CSD编码
  • 算法 2.2: 最佳 CSD 编码
    1. 分数(CSD)编码
  • 例2.3 分数CSD编码
    1. 自由进位加法器
    1. 乘法器-加法器图(Multiplier Adder Graph, MAG)
    1. 对数系统(Logarithmic Number System, LNS)
  • 例2.5 LNS编码
    1. 余数系统(Residue Number System, RNS)
  • 例2.6 RNS算法
    1. 索引乘法器(Index Multiplier)
  • 例2.7 索引编码
  • 例2.8 索引乘法
    1. 索引域中的加法
  • 定义 2.9: Zech 对数
  • 例2.10 Zech对数
    1. 利用 QRNS 计算复数乘法
  • 例2.12 QRNS乘法
  • 例 2.13 (1,6,5) 浮点格式
  • 例2.14 12位浮点数和定点数表示方法
  • 2.3 二进制加法器
  • 例 2.15 31 位流水线加法器的 VHDL 设计
  • 2.4 二进制乘法器
    1. 半分方形乘法器
    1. 四分之一平方乘法器
  • 2.5 二进制除法器
  • 例 2.16 8 位还原除法器
  • 例2.17 牛顿算法
  • 算法 2.18: 收敛除法
  • 例 2.19 Anderson-Earle-Goldschmidt-Powers 算法
  • 2.6 定点算法的实现
  • 2.7 浮点算法的实现
  • 例2.20:一个32位浮点运算单元
  • 2.8 MAC与SOP
  • 例 2.22 无符号 DA 卷积
  • 例2.23 有符号DA的内积
  • 2.9 利用CORDIC计算特殊函数
  • CORDIC 体系结构
  • 例 2.25 向量化模式中的圆周 CORDIC
  • 2.10 用MAC调用计算特殊函数
  • 例2.26 函数的逼近
  • 算法2.27:切比雪夫函数逼近
  • 例 2.28 函数的逼近
  • 例2.29 平方根函数的逼近
  • 2.11 快速幅度逼近
  • 练习

自测一下

计算机算法

2.1 计算机算法概述

在用 FPGA 实现数字信号处理之前,必须先回答一个问题:数字在硬件里到底怎么表示?运算又怎么实现? 这就是”计算机算法”要解决的两条基本设计准则——数字表示法(定点数还是浮点数)和代数运算的实现(加法器、乘法器,以及求平方根、CORDIC、MAC 计算三角函数等更复杂运算的高效实现)。

为什么 FPGA 在这件事上有优势?因为 FPGA 是位级可编程的结构,你可以为每个信号单独选择合适的位宽:一个滤波器系数可能 12 位就够了,而累加器可能需要 20 位,位宽按需分配,一点不浪费。这恰好与 PDSP(可编程数字信号处理器)相反——PDSP 的乘累加内核位宽是出厂固定的(比如 16×16→40 位),你只能迁就它。如果在 FPGA 设计中仔细选择位宽,就能从本质上节约资源(LE、布线、功耗都省下来)。反过来想:如果不去管位宽,一律用最宽的位宽”图省事”,资源消耗会成倍增长,时钟频率也会因进位链变长而下降——这就是”不用会怎样”的代价。

2.2 数字表示法

项目的早期阶段就要决定:用定点数还是浮点数?一般的经验是:

  • 定点数:速度更快、成本更低,但动态范围小,而且设计者要自己操心”换算”(缩放)问题;
  • 浮点数:动态范围大、不需要换算,对复杂算法有吸引力,但速度慢、硬件开销大。

图 2-1 给出了传统和非传统定点数、浮点数表示法的整体框架。两套系统各自涵盖多种标准,必要时也可以定义专有格式。


图 2-1 数字表示法的框架

2.2.1 定点数

定点数家族里最常用的是整数表示法。表 2-1 用 3 位编码对比了 5 种有符号整数的表示方法,下面逐个展开。

表 2-1 有符号二进制数的常规编码

二进制数2C1CD1SM偏差
01133430
0102232-1
0011121-2
0000010-3
111-1-0-1-34
110-2-1-2-23
101-3-2-3-12
100-4-3-4-01
1000--0--

1. 无符号整数(Unsigned Integer)

位无符号数的取值范围是 ,表示方法为:

是最低有效位(LSB),权重相当于”个位”; 是最高有效位(MSB),权重是 。

代入算一遍:3 位无符号数 ,。范围是 。

2. 有符号数值(Signed-Magnitude, SM)

SM 就是”原码”:MSB 单独当符号位,剩下 位表示数值大小:

范围是 。优点是直观、对称( 之外没有多余的负数),有助于防止溢出;致命缺点是加法麻烦:两个异号数相加时,硬件必须先比较谁的绝对值大,再用大的减去小的,还要判断结果符号——加减法器要分成两套逻辑,这就是为什么实际 DSP 系统几乎不用它。

3. 二进制补码(Two’s Complement, 2C)

位二进制补码的定义是:

范围是 。它是 DSP 领域最流行的有符号数系统,核心原因是:累加多个有符号数时,只要最终结果落在 位范围内,中间过程的溢出可以完全忽略——所有运算都是模 意义下的。

计算示例:3 位数 :

注意 ,共 4 位,最高位的进位 1 被丢掉(“1.”表示丢弃的进位),剩下 ,正好是 。溢出被忽略了,结果正确。

再看一个”中间值溢出但最终结果正确”的例子:计算 。第一步 ,按补码解读这是 ——中间值已经”错”了!但继续算 ,丢掉进位得 ,即 ,结果正确。这就是模 运算的魅力:中间值可能无法正确表示,但只要最终值有效,结果就一定对。这个性质在设计 CIC 滤波器(第 5 章)时会被直接利用,算法不需要做任何改动。

4. 二进制反码(One’s Complement, 1C)

位反码的范围是 。负数就是正数”按位取反”,因此 0 有两种表示( 和 ,即 和 ),这是它的冗余缺陷。定义如下:

计算示例: 在反码下进行:

直接相加得 并产生一个最高位进位。反码的规则是**“进位回绕”**:把最高位冒出来的进位再绕回来加到最低位上,,即 ,正确。

虽然多了一步回绕,但反码能不做任何校正地实现模 运算。因此在特定 DSP 算法(例如整数环 上的 Mersenne 变换)中,反码有特殊价值。

5. 减 1 系统(Diminished One System, D1)

D1 是一种”有偏差”的系统:正整数比补码表示少 1(即存的是”真值减 1”)。 位 D1 数的范围是 ,不含 0——0 用专门的编码 (如 )表示。编码规则:

验证一下: 的 4 位 D1 编码是 ?按书中的 3 位有效写法是 (内部存 ); 存 ,即 。

计算示例:D1 加法需要”取反进位”处理:

与反码类似,但这里最高位进位取反后再加到最低位。D1 数同样能不加改动地实现模 运算,第 7 章将据此在 计算环中实现费尔马 NTT。

6. 偏差系统(Bias System)

偏差系统给所有数统一加一个偏差。偏差通常取范围中点:偏差 。对 3 位数,偏差 。 位偏差数的范围是 ,0 的编码恰好就是偏差本身。定义:

计算示例:,先各自加偏差编码:(),()。两码直接相加:,解读为 ——比真值 多了一个偏差!所以必须再减一次偏差:,即 ,正确。

规律总结:每次加法要多减一个偏差,每次减法要多加一个偏差。偏差系统的最大好处是让”数值比较”变成简单的无符号比较(编码顺序与真值顺序一致),这一性质被用来编码浮点数的指数(见 2.2.3 节)。

2.2.2 非传统定点数