✎ 编 者 按
目前看到的实现前导 0 电路的最优设计,在 SpinalHDL 中通过递归的形式来实现前导 0 电路。
前导 0 计算
对于一个具有 N 位位宽的二进制比特数,前导 0 计算用于计算前从最高 bit 开始第一个非 0 比特前的 1 的个数。在之前的一些应用场景里,对于一些小位宽的数据,往往可能就写一个 casez 来实现了,也并未深究过其逻辑级数和资源开销。而对于一些大位宽的场景,这里的考虑就十分必要了。
在 SpinalHDL Lib 里,看到一个关于计算前导 0 电路的一个实现,综合对比起来看在资源&逻辑级数上还是设计的比较优秀的。
前导 0 计算原理
SpinalHDL Lib 中的前导 0 计算采用递归的方式进行实现,其实现代码如下:
其最终代码映射电路为树形结构,其思路非常简单。对于一个 N 比特的数据(N 满足 2 的 N 次方),其求前导 0 计算时可以先对其左右两半部分分别进行前导 0 的计算:
对于 N 比特的数据,计算其前导 0 的结果位宽为 log2(N)+1 bits,那么对于其左右半步的计算结果为分别为 log2(N)比特。对于其计算结果,存在三种情况:
- 左右半部分均为 0。
- 左半部分均为 0,右半部分非全 0。
- 左半部分不全为 0。
针对第一种情况,如果左右两半部分均全为 0,那么 N 比特计算前导 0 的计算结果应为最高比特为 1,其余比特均为 0。而此时 clz_l 和 clz_r 也满足最高比特为 1,其余比特为 0。
针对第二种情况,左半部分均为 0,有半部分非全 0,N 比特计算前导 0 的计算结果应为最高比特应为 0。此时前导 0 计算结果应为 clz_l+clz_r。由于在这种情况下 clz_l 最高比特为 1,其余比特为 0。故此时计算结果可以写为{0,clz_l.msb,clz_r[log2(N)-1:0]}。
针对第三种情况,N 比特计算结果应为 clz_l,此时计算结果前 2 比特应均为 0,此时计算结果可以写为{0,0,clz_r[log2(N)-1:0]}。
将上面三种情况进行汇聚,即可得到最终的表达式:
result[log2(N)]=clz_l[log2(N)-1] & clz_r[log2(N)-1]
result[log2(N)-1]=clz_l[log2(N)-1]?(!clz_r[log2(N)-1]):1'b0
result[log2(N)-2]=clz_l[log2(N)-1]?clz_r[log2(N)-2:0]:clz_l[log2(N)-2:0]
如此即可将一个求 N 比特前导 0 计算转换为求 N/2 比特的前导 0 计算。通过递归即可最终实现求 N 比特前导 0 计算任务。
SystemVeriilog 中的实现
上面的代码通过 SystemVerilog 也可以进行实现,在原文链接中有放置采用 SystemVerilog 的实现。其实现也是采用递归的方式,虽然代码是可以描述的但对于部分综合器可能因为不识别递归存在无法综合的情况。这也就体现了 SpinalHDL 的优势,其在生成 Verilog 代码时是直接展开的形式。
END
作者:玉骐
文章来源:Spinal FPGA
推荐阅读
- 一文搞懂 CRC 的并行实现
- 浅谈 PCIe PHY:Original 与 SerDes PIPE Architecture 对比
- 用“北京地铁图”看懂 SoC 设计
- cocotb——一文看懂 stream lib
- ICCAD-Expo 2024 魏少军教授官方报告:中国芯片设计业要自强不息
更多 IC 设计干货请关注IC设计专栏。欢迎添加极术小姐姐微信(id:aijishu20)加入技术交流群,请备注研究方向。