老师说没电路就不要写代码,但我写个乘法器在综合前都想不出它电路啥样,全加器还行。


首先,你们老师说的是正确的,但可能是说的不够详细,或者你表达的不全。

准确的说,在写Verilog前,要做到心中有数字电路。

数字电路设计主要就是,选择器、全加器、比较器,乘法器,几个常用逻辑门,再加个D触发器,电路基本都能实现了。这些器作为基本单元,对于工程设计来说,并不需要过多的关注它更底层的门或晶体管的样子。

我在学生时代刚开始学数字电路设计的时候,很长一段时间都是眼里只有代码和功能时序,没有一个良好的正向设计思路。比如,知道要实现的功能,二话不说开始新建.v写代码,边写边想,这样导致的结果,准确的来说时序都是调出来的,而不是设计出来的。

写的代码几乎全使用

always @(posedge clk or negedge rst_n)

从不考虑消耗的资源和面积,学生阶段的项目用FPGA也很难把晶元资源用爆,全用的寄存器肯定不会出现时序不满足的情况。

而实际上做设计最应该关注的是PPA(Performance, Power, Area),寄存器多面积必然大,处理必然延时大,功耗怎么小。寄存器打拍是因为组合逻辑路径过长,才往中间插一拍,而不是随便打。

在写Verilog前,不光要心中有电路,还要有关键时序图,有一个硬体的详细设计方案。而且不光在心里,还得写下来,画下来,整理成文档。在动手写代码前,心中就有了谱,清楚的知道,我这个设计能成。

而一个正确的正向设计流程应该是,首先确定设计模块的功能需求,划分整体的硬体结构,可以大致分为几个部分。每一个部分实现一个独立的功能,不同部分之间介面交互确定。

设计分为数据通路和控制通路。

数据通路决定了整体数据流的走向,整个模块计算分为哪几部分,哪些是可以排成流水线,中间的数据流是否需要断掉,用RAM存还是RegFile存储。数据通路中数乘法器单元的面积最大,一般都是采用的是分时复用的方式。整个数据通路的计算流整理出来后,基本上乘法的最大个数也统计出来,然后控制计算模块在不同的时间复用。乘法器的数量和复用程度决定了一个设计是否更优,好的设计是整个数据通路中乘法器几乎空闲不下来。

到了单个计算模块,每个模块都能画出一个简单的计算电路图,

上面这个图的意思是,a * b或c * d的结果进行累加,最后饱和截位进行输出。

画出了电路图,就可以大体估算出,整个设计需要的寄存器的数量,乘法器的数据。乘法器和寄存器的量级估算基本上就可以确定整个设计的面积单位量级。

控制通路就是玩时序设计,画出时序图,具体的实现就是各种大大小小的计数器、enable、start、end、valid、flag信号。系统整体的调度,就记住一句话,状态机大法好。当然虽然说状态机可以实现一切时序电路,但并不是所以时序功能都适合用状态机。比如,整个设计的处理都是连续流水处理,那么对于状态机的来说就是一个状态,不需要用状态机了。

控制通路的设计就不是画电路图了,而是画时序图,状态机的跳转,各种控制信号的时序交互,握手,ram的读写控制等等关键时序图,都需要画出来。控制通路上的资源占比很少,一个10bit的计数器就可以计到1023,一个数据打拍就32bit,各种flag就1bit,更不值一提。所以设计中评估资源和优化主要关注的数据通路。

数据通路和控制通路整理完成后,整个设计的处理时间和占用资源基本上就可以估算出来。上面的工作都完成后,然后就是照图施工,你会发现,写代码就完全是个体力活的事情。只要你方案设计的好,图画的好,文档写的清晰,随便找几个会写Verilog的代码都能写出来(夸张的表述)。

回到我们说的Verilog HDL的HDL的全称是Hardware Description language,是硬体描述语言,不是design,是在描述之前,你就得想好要描述的东西。做设计的时候按照这样的思路和套路去想,去做。

再来说说做设计时的描述方式,一些更底层的描述方式,比如

sel[1:0] 等效于 sel[1:0] == 2b11
~(|sel[1:0])等效于 sel[1:0] == 2b0
~a[3:0] + 1b1 等效于 -a[3:0]
c[4:0] = {a[3], a[3:0]} + {b[3], b[3:0]}等效于c[4:0] = $signed(a[3:0]+b[3:0])

变数乘以一个常数用移位加

assign data_out[5:0] = ({6{data_vld0}} data0[5:0])
| ({6{data_vld1}} data1[5:0])
| ({6{data_vld2}} data2[5:0])
| ({6{data_vld3}} data3[5:0]);

这是一个4选1的数据选择器,并且要求四个vld不能同时为1。

实际上,抛开代码的可读性,很多代码的写法,并不需要多此一举用更底层的描述方法,高级的描述只要语法和工具支持,就可以直接使用,更底层的描述,我们以为会用更少逻辑,但是工具可能也会优化的更好,比如,变数乘以常数,a * 2『d3,工具会帮你优化成 a &

当然也不能过分依赖工具,能复用的逻辑尽量复用,先选后比,先选后加,先选后乘。毕竟自己写出来的逻辑是确定的,而交给工具并不一定会按你想的方向去优化综合。而做一个设计在确保代码功能实现的前提下,还需要考虑的是代码可调试性和可维护性。

最后再扯一段我用过好几次的话

学习Verilog的五个阶段

00:心中无电路,代码无电路

01:心中有电路,代码无电路

10:心中有电路,代码有电路

11:心中无电路,代码有电路

00:心中无电路,代码无电路

达到10就可以了,这时候你就是高手了,再往后就开始玩玄学了。

欢迎纠正,欢迎补充。


不太同意那个说不需要深入到逻辑门的答案。对于一般的开发者来说,如果仅是希望能够比较快速顺利的完成功能,确实EDA能够完成不少优化工作。但EDA不是万能的,有许多EDA解决不了,只有对底层电路了如指掌的开发者才能完成的设计。举一个个人认为比较有代表性的例子,5g nr ldpc 的提升值(lifting size)设计成如今这种 [公式] 形式,一个很重要的因素是设计准循环电路中,如果是 [公式] 的形式可以使用banyan switch+QSN的电路结构,比单纯QC-LDPC shift network(QSN)(提升值可以为任意值),要节约大概30%的2-1MUX。这一改动在保证了LDPC码的灵活性的前提下节约了相当数量的晶元面积,顺带简化了之后LDPC矩阵的设计,这种结合了演算法和实现的优化不是靠EDA能够做到的。高端的晶元,比拼的就是这一点一滴的细节,对于一个追求卓越的工程师来说,满足于rtl层的设计是远远不够的


主要是「电路」这个概念现在被异化得比较严重。传统上电路应该是电感、电阻、电容、导线再加上晶体管等。而数字电路出来以后,就直接从晶体管级抽象成逻辑门,再进一步抽象成各种中规模集成电路级别的模块。虽然也可以把这些个模块称为电路,但其实更多的是关心它们的逻辑功能而已。

其实对于使用Verilog来描述硬体,基本上是在RTL这一层做的。除非你特定情况需要自己从门级甚至晶体管级自己定义一个特殊的电路结构。所以在大多数时候根本不用关心那么底层,别说晶体管了,门级结构也不用想。这也是很多搞模拟/射频电路的老师认为我们这些「搞数字的」根本不算「搞电路的」。

在RTL这一层做事,没必要去想最后门级电路长什么样,不然就如同 @Podes 知友说的,失去了使用Verilog的意义。不过,熟悉常见的中规模集成电路级别的基本功能以及利用这些经典模块来构建小系统的能力要具备,尤其是对于入门的新手而言。不然就成了脚踩西瓜皮,滑到哪里算哪里。

至于什么乘法器之类的,有学生来问我我一律回答直接调用IP核,根据需求看IP核的手册加以设置。重点不在这里。

最后说一句:要么是你的老师没有教过你们从功能分析到Spec/架构定义再到RTL建模/编码的全流程,要么就是你那节课逃掉了没去。前者,锅由你的老师背;后者,自己好好反省,错过了最重要的一课。如果没有这一课,讲再多的什么语法细节之类的,都是浪费时间。


你老师的确是对的。

只是表述方式有问题,我如果带小朋友是不会说这些话的,因为我知道他很容易像题主一样曲解或者压根理解不了,这些都是些正确的废话。

在我看来,这句话有极强的误导性

图片来自于网路

先声明一下,作为一个人,我们大多数人的脑子在计算时都比不上电脑CPU,是不可能在你设计数字电路的时候完整的描绘出每个与非门的,如果你能做到的话,建议直接把自己脑子license给S家让他们研究下看能不能产生技术突破,因为你是「行走的VCS/DC」。

如果让我比喻,数字电路就是一栋精巧的超大建筑,数字电路设计师的工作,是描述这个建筑里面那个房间是什么功能,通往各个房间的路是怎么样排列的,哪里有个楼梯,哪里不能拐弯(Design Proposal).......而类似于VCS这样的模拟工具,相当于是先帮你虚构了这个建筑(编译),然后虚构了一群人去使用这个建筑(激励),并且报告给你,让你确认是不是达到了你的设计目的(模拟)。DC这样的工具就是把最后的建筑图纸交给建筑公司直到最终成为晶元。

图片来自于网路

所以你老师的意思是让你先画出这个结构图,并不是要你精准的想到每个房间哪里用什么材料(逻辑门)。类似于这样:

另外,描述本身还是有一些小技巧的,我看来这本书里面比较详细吧,供君参考。

Verilog编程艺术京东¥ 75.80去购买?


这是要害死人的节奏啊。

你应该反问一句:「老师,您说的电路具体是什么意思?」不知道这里的「电路」是指什么,就不要人云亦云什么「心中有电路」啦。

一个数字逻辑里面最基本的反相器的电路是什么?或者一个最简单的时序部件 D触发器的电路是怎样的?能回答出来吗?32bit的全加器的电路你能在脑袋中想像出来吗?是个正常的人都无法做到心中有这种「电路」!

所谓写Verilog做数字逻辑设计要做到「心中有电路」,这个电路是指:RTL寄存器传输级这一个抽象层次的电路结构,或者说是以时序、节拍为核心要素的电路结构。绝对不是指组合逻辑电路,更不是指晶体管、R、L、C等这种物理层的circuit。

所有复杂的数字逻辑系统都可以归一化为:1、不同层次的有限状态机结构组合;2、或者时序逻辑和组合逻辑的组合;3、或者时序控制部件与运算部件的组合。

以上三种说法既代表著构建数字系统的不同思维方式,也直观地表达了三种不同的verilog描述风格。任何一个基于标准单元库的数字电路都可以使用三种方式之一描述出来。三种方式不是互斥的,各自都是完备的,只是解析问题的角度不同。这个跟软体开发里面的「设计模式」概念有点类似。

三种模式可以单独使用也可以混合使用。不同的数字功能模块适合不同的描述风格。比如,一个IIC协议解析使用状态机描述方式很容易理解也很容易写出来,使用另外两种方式就比较麻烦;一个指令系统或者数据流使用控制+运算的风格来描述比较顺手,其他的方式就非常痛苦;等等。

所以,结论是:你在设计数字电路时需要想到的是怎么把时序结构排好,如何把过于复杂的运算逻辑分到不同节拍里面去,从而达成PPA(Performance,Power,Area)优化和折中。思考的起点就是RTL级而不是门级的结构。

当然,有人会跟我杠说:现实中还是有人基于基本门单元用verilog来做结构化电路描述啊。当然有。但是写这种电路结构的估计只有两类人:1. 做全定制设计宏单元库的人;2.做模拟电路的人。这两类人都实质上在设计晶体管级电路,他关注的是circuit的特性,比如电流(功耗)和电容(速度)这些参数。这样做的人还有一种可能是学生吧,我估计他也只是为了完成数字逻辑设计课程题目。

如果你认为自己脑容量足够大,我做大规模数字系统设计时偏要关注到组合逻辑电路的结构细节,那我只能认为你太自信了,自信到觉得EDA后端工具比你还蠢。记住一点:在RTL抽象级以下的电路优化方面,人在机器面前弱爆了。


推荐阅读:
相关文章