nvmjom  

1. 背景

​ 前导0检测是浮点乘法运算中常用的计算,其目的是对前导0进行计数,以二进制数输出前导零个数。使用多路选择器直接从所有可能结果中选出是比较直观的实现方法,但如果直接使用多路选择器进行枚举与选择,代码实现比较复杂,面积和延时也都比较大。而如果采用按位检测与计数,则需要引入时钟,这将会导致不确定的执行延时。

​ 事实上,前导0检测可以通过少量逻辑门(\(O(log_2n)\)级别)完成。

2. 原理

2.1 LZD定义

我们先将前导零检测部件(LZD)的端口定义如下:

  • A[7:0]:输入数据
  • B[2:0]:前导0计数
  • full:A全部为0

功能的伪码表示如下:

if A == 8'b0
    B = 3'b0
    full = 1
else
	B = A的前导0数量
	full = 0

2.2 理论推导

​ 首先我们考虑一种简单的情况,前导0之后全部为1,例如对一个8bits数据A=00000111,前导0检测的结果应为:B=101,怎么理解这个结果呢?

​ 从高位至低位考虑:

  • B的最高位为1,代表结果大于等于4,即第一个1在A[3:0](低4位)中;
  • B的下一位为0,代表结果小于\(4 * B[2] + 2 = 6\),即第一个1在A[3:2](低4位的高2位);
  • B的最后一位为1,代表最终确定结果等于5,即第一个1在A[2](低4位的高2位的低1位)

​ 可以发现,从高位至低位考虑,第n位为0/1,代表第一个1出现在A的剩余可能区间的高/低2n位。反过来,从长度为1位的小区间到长度为2m的大区间,第一个1可以依次从低位至高位确定B。

2.3 硬件结构

​ 怎么实现呢?我们可以通过建立一棵二叉树进行实现,以期达到\(O(log_2n)\)的延时。

​ 考虑A的特征,我们发现,第一个1往前都是0,往后都是1,我们需要两种基本操作来完成上面推理出的二分的LZD:

  • “保留”第一个1的位置信息,对应或运算;
  • 决定第一个1是在左侧还是在右侧,对应异或运算。

2.3.1建立二叉树

​ 还是以A=00000111,B=101为例,第一步,建立二叉树,先看下图:

LZDTree1

​ 我们发现,从上往下,每一个节点分别代表8bits、4bits、2bits、1bit的数据,如果该节点的值为1,则代表这一段区间中有1,否则全为0。父节点的值由子节点通过或运算得到。

2.3.2 分析第一个1的位置

​ 我们还希望从中提取出第一个1是左区间还是右区间。由于0一定在1的左侧,我们可以用异或运算来提取:

  • 当左为0,右为1,异或得到1,代表第一个1在右区间;
  • 当左为1,右为1,异或得到0,代表第一个1在左区间;
  • 当左右都为0,我们不在乎得到什么,姑且与第二种情况合并。

​ 如下图所示:

LZDTree2

两个兄弟节点之间的数字代表了异或运算的结果,1代表第一个1在右边,0代表第一个1在左边或者不存在第一个1。

2.3.3 传递有效结果

尽管每对兄弟节点都会产生一个判断值,但大多数值都是无效的,我们希望只提取出有效的值。我们自顶向下考虑,还是分三种情况:

  • 左、右节点均为1:这种情况下,第一个1在左子树,所以B的更低位应采用左子树的异或结果,对应本级的异或结果为0;
  • 左节点为0右节点为1:这种情况下,第一个1在右子树,所以B的更低位应采用右子树的异或结果,对应本级的异或结果为1;
  • 左、右节点均为0:这种情况下,左右区间都没有1,无论哪一边子树的异或结果都是无效的,为了实现简单,我们不妨归类为本级异或结果同样为1的第一种情况。

那么效果如下:LZDTree3

​ 橙色标注的是第一个1的传递路径,蓝色标注的是B的逐位逐级的选择,绿色标注的是本级异或结果对下一级异或结果的选择。

2.4 一般情况

​ 这种方法看起来好像很不错,不过到这里还没有结束。还记得吗,我们在开始的时候做了一个假设,从第一个1往后都是1,但这显然不是一般情况。

​ 更一般的情况是有可能出现左节点为1,右节点为0。这种情况下显然第一个1在左区间,但按现在的方法会将其归到右区间。不过不用担心,这不是什么大问题,我们只需要将它修正为左右节点都为1的情况即可。方法是将右节点用于异或运算的值进行修正:

\[Before: B[i] = XOR(Left, Right) \\ Now: B[i] = XOR(Left, OR(Left,Right) ) \]

只有左节点为1,右节点为0的情况会受到这种修正的影响。至此,我们已经从理论上完成了\(O(log_2n)\)的前导零检测,下面附上verilog实现.

3. 代码

LZD——verilog

4. 评估

4.1 延时

每一级生成下一级节点的值的延时为1个或门的延时;

每一级生成本级异或值的延时为1个或门与1个异或门的延时,选择下一级异或值的延时为1个MUX的延时;

综上,对2n位的数据进行前导零检测,生成B的第i位的延时为:

\[Delay_i = i * Delay(OR) + Delay(OR) + Delay(XOR) + Delay(MUX) \]

总的延时为:

\[Delay = (n + 1) * Delay(OR) + Delay(XOR) + Delay(MUX) \]

4.2 面积

对2n位的数据进行前导零检测,生成B的第i位所需的硬件结构为:

\[\begin{align} Area_i &= 2^{n-i}*(Area(OR) + Area(XOR) + Area(1\ bit\ MUX) * i)\\ &= 2^{n-i}*Area(OR) + 2^{n-i}*Area(XOR) + i*2^{n-i}*Area(1\ bit\ MUX) \end{align} \]

总的面积为:

\[Area =(2^{n+1}-1)(Area(OR) + Area(XOR))+(2^{n+1}-2-n)Area(1\ bit\ MUX) \]

可见,面积和延时都是\(O(log_2n)\)级别的。

转载请注明出处: 原文地址

posted on 2022-12-06 15:52  nvmjom  阅读(1648)  评论(0编辑  收藏  举报