打造IC人才
科技生态圈

verilog怎么写才能做到心中有电路?

发布时间:2023-06-09

来源:IC修真院

verilog语言是我们数字IC工程师必用的语言,在日常工作中我们需要做到心中有电路。一定要清楚HDL设计的是硬件电路,要有设计电路模块再通过线网(导线)互连起来的整体思维,还要有数字逻辑的基础,以及使用逻辑函数和状态函数的思维,不要把软件思维带进来,特别是不要把Verilog当C语言用。

大约二十多年前,高校BBS的时代,曾有一个“用各种编程语言炒鱼香肉丝”的笑话,假设要用VHDL语言“炒”一盘鱼香肉丝,“炒制”过程如下:

你规定了香料,肉丝和笋子的特性,确定了锅的存储特性,然后决定了用火的上升沿做触发,你小心地写了调料的激励文件,然后打开模拟~~~~轰!你的鱼香肉丝……成了不确定状态?! 记住, VHDL不是顺序执行的,是并发的呀,写程序小心了哦。

这虽然是一个笑话,但也生动点明了VHDL、Verilog、ABEL等硬件描述语言(HDL)的核心特性——并发(并行)执行, 因为硬件本来就是从上电开始,各部件就同时开始工作的,因此用于描述硬件的HDL,对应着硬件电路部件的各语句(块)自然也应该是并行执行的,这是HDL的基本特性,也是HDL执行机制与软件编程语言执行机制的本质差异。

虽然目前VHDL、Verilog等HDL,都支持顺序执行的语句块,例如VHDL中的process,Verilog中的always块等,但HDL执行机制的基础是并行执行,如果一定要实现顺序执行的语句,综合器在实现顺序执行语句时,特别是在顺序执行语句中实现条件分支(即if...else...等结构)时,必然会出现类似CPU控制单元(CU)的设计,即通过多路选择器或者多个三态输出缓冲器的组合,根据一定的条件,产生硬件信号去控制多路选择器或者各三态输出缓冲器,将顺序执行语句对应的硬件电路根据特定条件,依次连接到输入、输出或者“总线”上,这种综合实现是因为硬件并行执行的基础,与需要顺序执行的语句存在不相容造成的,这种根本性的不相容不是通过综合器的“优化”能够彻底解决的,换而言之,顺序执行的HDL语句从根本上改变了综合结果的电路结构,几乎必然带来综合结果的复杂性。目前可编程逻辑器件的逻辑单元一般都设计有可控的输出缓冲器或者多路选择器,一个原因也是为了适应顺序执行语句的综合实现。

对于综合器而言,逻辑表达式、真值表、状态表等的简化是有着逻辑代数数学基础的,因此逻辑函数、状态机等的综合优化很容易做到,而且可以优化得很彻底,但顺序执行语句的综合优化就没有那么简单了。由于顺序执行的HDL语句从根本上改变了综合结果的电路结构,从逻辑函数、状态函数等对应的门电路、触发器等小规模单元提升到了多路选择器等中规模单元,算术运算符、关系运算符等的使用又带来了加法器、比较器等中规模单元,这些中规模单元本身是很难与小规模单元一起优化的,尽管中规模单元最终也是用门电路实现的,但很难与小规模单元一起优化到最简逻辑函数实现这个程度了,因此从理论上说,顺序执行的HDL语句很难优化彻底,难于避免中规模单元的使用。为了缩小顺序执行HDL语句与逻辑函数、状态函数等的性能差距,除了综合器优化在不断提升之外,可编程逻辑器件也在配合改进,例如目前FPGA的LUT中基本都实现了多路选择器,部分评论者提到目前中高性能FPGA在LE、SLICE等逻辑单元实现中已经实现了比较器、加法器、乘法器甚至DSP单元等硬件单元,可在综合实现中直接使用,这都是事实,但这不能说明这种优化一定能够超越建模到逻辑函数和状态函数一级,这种观点甚至比软件高级语言编译器优化一定能够优于针对特定CPU的汇编语言编程还要无理,因为高级语言与汇编语言之间并不存在顺序执行与并行执行的不相容性。

因此,顺序执行的HDL语句,最好尽量少在设计中使用,特别是最好不要Verilog当C语言用,像写软件算法一样直接写顺序执行Verilog语句,Verilog中能用“<=”的,就少用“=”。

众所周知,数字电路可分为组合逻辑电路和时序逻辑电路(一般考虑同步时序逻辑电路),组合逻辑的基础是逻辑函数(方程),时序逻辑的基础是状态函数(方程),而状态函数=激励函数(逻辑函数)+基本触发器(R-S、D、JK和T)的状态函数,虽然R-S触发器电路最为基本,但在基本触发器的状态函数中,D触发器的状态函数最为简单。因此,实际可编程逻辑器件的逻辑单元实现,一般都是在实现组合逻辑逻辑函数(CPLD相当于使用与—或式或者最小项实现、FPGA相当于使用真值表实现)的基础上,加上D触发器(或者理解成寄存器),这样理论上逻辑单元就可以实现任何组合逻辑或者时序逻辑,逻辑单元的结构决定了正确设计组合逻辑或者时序逻辑,能够在具体器件逻辑单元实现这些设计时,优化实现。

举一个笔者在培训教学中使用过的极简单实例:设计1位十进制计数器,器件是Altera Cyclone II系列FPGA中的EP2C8Q208C8,综合器是Quartus II 8.0。

一般习惯软件思维的学员通常这样设计:

image

这种思路是典型的软件思维,或者说尽量使用行为建模方法,使用if...else...结构,看似源代码简单,综合(这里不宜称为编译)后的RTL如下:

image

可见综合结果使用了加法器、比较器和多路选择器,当然也使用了D触发器(或者说寄存器),这是使用if...else...结构后的一般综合结果。

而笔者在培训教学时,则讲述给学员,要尽量使用硬件思维(即“心中有电路”),比较好的设计方法是:

1、设计一个同步清零4位二进制计数器,而且使用一组状态函数实现。先确定这是Moore型同步时序逻辑电路,再使用状态转移真值表(或者状态表、状态图等)、卡诺图等工具,得到一组简化的状态函数,每一位输出对应一个状态函数,最后每个always块里面只有一条状态函数,多个always块并行执行,或者一个always块中写多条状态函数,但全部使用非阻塞赋值,相当于并行执行。

2、在上述同步清零4位二进制计数器的基础上,附加一个门电路组成的外部清零电路,计数到1001B(即十进制数9)时准备好清零信号,下次时钟脉冲边沿到来时清零4位二进制计数器,即可实现1位十进制计数器。

3、将外部清零电路与同步清零4位二进制计数器通过适当的线网类型相连。

笔者讲述的代码如下:image

image

或者写成:

image

综合后的RTL如下:

image

可见源代码和RTL看似复杂一些,但综合结果只有门电路和D触发器,实际器件逻辑单元实现综合结果时容易实现得多,延迟也容易控制。

很多优秀IP核,内部结构是多个模块,再通过线网类型互连,每个模块往往只有几行十几行代码,真正直接对应逻辑函数或者状态函数,而一些质量不好的IP核或者HDL代码(国内HDL代码中常见)里面全是一层套一层的if语句,综合后RTL过于复杂,消耗大量逻辑单元,延迟难于控制,甚至随处出现干扰脉冲(可能是竞争冒险导致的)等,明显开发人员带进来了软件思维,没有正确应用硬件思维,或者说:“心中没有电路,Verilog当成C语言用。”

综合器优化能力再强,本事再大,开发者要有电路整体结构的设计理念和数字逻辑的基础。人在机器面前未必“弱爆”,综合器的优化也未必一定优于整体结构和设计思路的优化,门级建模不一定是需要的,但设计到组合逻辑的逻辑函数一级,或者时序逻辑的状态函数一级,有时仍然是必要的,实际到了逻辑函数和状态函数一级,基本也就对应门电路和触发器了。

备注:作者—Studio TBsoft

链接:https://www.zhihu.com/question/429037239/answer/1573527358

来源:知乎。著作权归作者所有。

相关推荐:

verilog语法基本知识_如何写好verilog代码?

IC设计|verilog语法基本知识(一)

FPGA还是ASIC?都是写Verilog,到底哪个好?

立即下载

推荐阅读

换一换