向大佬们请教一下针对这类问题有没有什么套路,或者可以分享下经验


巧了,我是一名数字前端IP设计工程师,方向为通信晶元IP设计,我的主要工作就是「翻译」演算法代码。

经典的ASIC开发流程主要有:

  • 以演算法设计为主导
  • 演算法C代码手工转换为RTL
  • RTL与演算法C代码生成的测试向量对比进行验证
  • 依赖FPGA做大量实时、现场测试
  • 适合通信信号处理,音视频处理或图像处理等产品

我的工作主要就是将演算法C代码手工转换为RTL,尤其是通信晶元的设计,演算法主要是将浮点运算近似成定点运算,定点的精度决定了系统的性能,所以一种开发模式就是,用C平台生成的case数据和RTL模拟的数据进行对比,保证定点化后的模拟性能。

所以对於单个计算模块的开发来说,可以说就是体力活了,演算法的计算过程已经摆在那里,单就是纯翻译。

然而再复杂的演算法,在设计工程师的眼里,也就是一堆数学公式,演算法设计者也应该尽量做简单的演算法实现,比如除法,求幂次方、开平方等复杂运算到了设计工程师这里都已经转化成了简单的乘法和加法运算。更复杂的就是累加、累乘(我所能接触到的)。

做晶元第一应该关注的是晶元的PPA(Performance, Power, Area),如何设计的出更高性能的电路,占用更少的资源/面积,更低的功耗。这才是我们的专业知识。

通过学习演算法代码和文档以及协议,了解演算法的计算意图。然后进行数据通路的分析,整体的数据流走向。哪些需要计算的数据可以用寄存器存储,哪些数据需要用RAM存储。模块的划分可拆解,哪些计算单元是功能类似的,可以做成一个小IP,乘法器同时使用的最大数量,是否能在整个大模块中分时复用。

演算法的设计中没有时序的概念,也没有计算时间的长短。需要设计工程师去整理整个模块的计算流水,流水线排的时间长,需要的计算逻辑就越少,反之,面积越大。面积与速度互换思想,贯穿始终。现成乘法器的数量有限,是否能加上几个乘法器而获得模块整体运算速度提高30%的收益,都需要去折中(Trade off)考虑。

排好计算流水,控制通路,一般都使用状态机去做,当然,状态机怎么设计演算法可不会教你。整个模块与更高层模块的交互,介面控制时序需要讨论确定。数据通路可能还需要用到RAM/Regfile去缓存中间数据的结果,RAM/Regfile的读写地址控制也是常见设计。数据通路的运算,是主要消耗资源的部分,所以一个好的详细设计方案非常重要,同样的设计,别人可以用比你小30%的面积和少30%的时间来实现。这可能就是设计工程师真正的价值体现之处。

对于通信演算法中,矩阵运算也是比较常见的,复杂矩阵的运算是最耗费资源的,矩阵运算的拆解也需要很多技巧,比如矩阵的乘法是A的第一行乘以B的第一列,累加得到第一个元素,这部分的运算电路可以复用流水起来做。一个矩阵需要拆解合并成数个小矩阵,想要保持并行,用寄存器存储,就会消耗的资源多。存在RAM中就是串列流水做会消耗的时间长,所以这都需要在模块架构设计阶段去计算处理时间和评估消耗资源、折中是否采取(Trade off)。

这种大型矩阵运算动辄几百上千bit的寄存器输出,连线选择运算,可能会造成后端congestion问题,所以方案设计的重要性又体现出来了。组合逻辑的运算,如果路径过长,时序会出现问题,插寄存器的位置也非常重要,消耗的寄存器的数量也是不同的,甚至可以通过手动retimming,找个寄存器把打拍的位置换一下,消耗的资源还是相同的。

对于晶元的功耗前端能做的就是,去加一些时钟门控,模块不用时候可以关掉,组合逻辑计算单元不用的时候避免翻转,乘法器的使能信号的控制,避免无效翻转,数据通路寄存器带著使能打拍,工具也会自动插时钟门控,这些就和演算法没关系了。

至于演算法,当然不同领域的相关知识不同,虽然设计方法是完全类似的,但是在一个领域深扎,成为这个领域的专业的人,可以更好的理解演算法到硬体的实现。

IP设计工程师经常调侃自己是演算法「翻译官」,其实也没什么问题,但是自嘲归自嘲,如果感兴趣的话,还是应该去想著如何更好的做好自己的设计,做好晶元。即使是「翻译官」也是一个十分有价值的「翻译官」。。

实现详细设计方案设计好后,具体的代码实现的技巧。

Verilog 有什么奇技淫巧??

www.zhihu.com图标

先扯皮这么多,后面再更新。


不知道你指什么样的演算法。

我做过一些无线通信行业的演算法模块,这样的演算法通常具有很强的专业性,我作为一个纯ICer看设计文档是完全懵逼的,通常是演算法工程师使用matlab把演算法过程完整写出来,我再照著matlab程序代码翻译成verilog代码,然后模拟结果和simulate结果对比确认。有答主说matlab程序可以转RTL,不会,没用过,都是手写verilog。

还做过一些软体工程范畴里的演算法,树,图,网路相关这些,没有太多数学上的东西,这就好办得多,把文档翻来覆去看,讨论,搞清楚了就直接撸代码。

如果FPGA的话,一些专业领域的常用演算法都有现成的,但我做ASIC很少有,除非花钱找专业公司定制IP,老板通常不干,所以绝大部分是手撸代码。我觉得关键在于理解了演算法的本质和实现过程,其它就是码代码的功夫了,目前没有碰到搞不定的,也许我做的演算法都不够高级复杂的缘故。


看了各位的回答,感觉都很有道理。但是多是口头描述,我手工摘抄一下《基于FPGA的数字图像处理原理及应用》的描述,大家共同学习一下。(可能稍微偏图像一点儿,但是道理还是相通的)

FPGA映射是将软体演算法转换为FPGA设计的过程。 这个过程并不是直接简单地把操作级演算法移植到FPGA ( 除非这些演算法是用硬体的方式开发的) , 而是把软体的功能通过修改演算法映射到硬体上面。

映射在不同抽象层上需要进行不同的考虑。在较高级上,应用级演算法在映射到硬体之前应该全部在基于软体的平台上进行测试。 在一些情况下 , 也许需要修改不同的图像处理操作来获得统一的计算结构。 通常情况下 , 应用级演算法在映射过程中不应该改变很多。

映射个别的图像处理操作又是另一种过程。利用并行性操作演算法可以改变很多。对于一些操作,从串列到并行演算法的转换是直接的,然而对.于其他操作完全是一个崭新的方法并且演算法去可能需要重新开发。

在映射过程中,不仅考虑操作本身,有时候也需要将它们作为一个序列来考虑,通过合成邻近的操作并且开发一个演算法去来实现这个合成操作有可能简化处理过程。在其他实例中通过将一个操作分肉成一系列简单的操作有可能简化处理过程。例如,将一个可分离的滤波器分离成两个简单的滤波器。在一些情况下,交换操作的顺序可以减少硬体需求。例如,与等价的先完成阈值操作再使用过值形态学滤波器相比,由阈值处理跟随的灰度形态学滤波器需要一个史复杂的滤波器。

任何实时应用都有时序约束问题。这个约束分为两类:吞叶量和延迟,流操作有吞吐量约束,通常每个时钟周期处理一个像素。如果不能维持这个速度,那么从相机流出的数据可能丢失,或者流向显示器的数据可能错过。由于处理操作每个像素所用的时间要远远长于一个时钟周期,因此,有必要采用流水线结构来保持吞吐量。另外一个时序约束是延迟。这是指从采集图像到输出结果或者完成一个动作的最大可容许空间。延迟对于使用图像处理结果反馈以控制状态的实时控制应用来讲尤为重要。控制系统反馈的延迟会影响闭环系统的响应时间,并且使得控制困难,过长的延时还会影响系统的稳定性。

与时序约束紧密相关的是存储器带宽约束,每个时钟周期仅能访问一个存储器埠。片上存储器遇到这样的问题通常会少一点,因为这些存储器包括很多相当小的模块,每个模块都能独立访问。但是片外存储器的访问一般都在较大的整片模块上进行,对于计算顺序和操作窗口顺序不相关的操作通常需要缓存整帧图像。大尺寸的图像缓存通常放在片外。因此,每个时钟要读取多于一个的像素是很难的。流水线式的存储结构更为复杂,其中在数据可用之前,地址需要提前几个时钟周期提供。由于片上存储器的带宽约束比较宽松,因此,将片外存储器的数据转移到片上的多个模块通常是很有必要的。

此外,还有一个约束与FPGA上可利用的资源有关。一个FPGA的成本通常是随著尺寸的增加而增加的,因此,充分利用资源是十分必要的。使用较少的资源可以通过两个方案提高时序。第一个方案,也是较明显的方案,是使用较少资源的演算法,由于其较窄的逻辑深度因而通常有较短的延迟。第二个方案是采用较规律的设计以便在 FPGA上更容易地布线,并且获得较短的布线延迟。随著设计的深入,FPGA的容量逐渐用完,有效布线变得越来越难,并且所设计的最大时钟也会变得越来越低。

与资源有关的第二个问题是共享资源之间的竞争。一个并行的实现会有多个并行的模块同时工作。尤其是,在任何一个时钟周期,只有一个过程能够访问存储器或者写入存储器。 对共享资源的同时访问必须规划好以避免冲突 , 或者可以设计额外的仲裁电路来限制对一个操作的访问。 仲裁设计会延迟一些操作 , 使得确定任务的延时变得更难。

在FPGA映射之后 , 接下来的重点工作是对设计的系统进行模拟和验证。 在FPGA 代码撰写完毕时对其进行功能测试是十分有必要的。 我们将在模拟测试章节详细介绍功能模拟。

在硬体中的在线调试也是十分必要的。最简单的方法是将主信号布线到不用的IO口上,使得它们从FPGA外部是可观测的,在外部使用一个示波器或是逻辑分析仪来监控信号。此外,Xilinx和Altera厂商提供的IDE中也提供了虚拟的逻辑分析仪来辅助调试。不过,辅助调试手段需要占用片内的存储器资源。


我目前的阶段是:

Step1将演算法写成乘加运算,包括各类激活函数基础函数都是用乘加运算去逼近

Step2由于Quartus Modelsim debug时间较长,先在Matlab模拟这一乘加过程,最起码可以判断你的结果是否收敛

Step3基于已写好的32定点或浮点加减乘模块复现上一步的过程,看rtl写好testbench看wave

再下一步也是我要学习的了,欢迎大佬补充。我的思路是基于较大的fpga继续学习(比如zcu系列,资源肯定用不完,所以演算法肯定可以综合出来),针对具体演算法的资源占用选晶元(最起码占用率要上90)画电路板。


第一种,目前Xilinx和Altera都有hls工具,直接将cC++算发转化为rtl代码,目前很多做神经网路加速器都是这么做的。

第二种,研究演算法结构,直接用rtl代码实现,这个要求很强的FPGA能力,一般需要2年以上的经验才能做到。

第三种,类似第一种,使用MATLAB演算法转化为rtl代码,操作比hls复杂点。

目前我知道这些,应该还有其他的。


推荐阅读:
相关文章