Verilog关键知识点

学Verilog必需掌握的关键知识点!速成必看!_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1bq4y1i7G9

几十年的学习经历让我总结出的一点学习心得就是:学习任何一门新的知识其实都是在学习一门新的语言,比如数学语言、计算机语言、各种行业术语等。而每一门行业的语言的背后都有着它的基本概念、底层逻辑,以及在我们大脑中与之相对应的思维方式。语言之间的不同本质上对应的是思维方式上的不同,学过英语的朋友都知道英文和中文有些组词造句的思维方式是不同的。学英语如果只是会记单词,但却没有通过大量的听读训练把自己大脑里的神经网络训练出来,让它适应英文的思维方式,那么遇到一些长句、从句,可能就会出现每个单词都认识,但搁一块就不知道这句话是啥意思的情况。这就是因为自己大脑里的思维方式没转变过来,语言中枢里的神经网络还缺乏训练。

学任何一门计算机语言也是一样,刚开始学C语言时也觉得有些难,直到我们学好了微机原理,懂了电脑的底层逻辑,学会像电脑一样思考时,原来按照我们默认的自然语言思维理解不了的C语言知识点就变得迎刃而解了。而跨跃这个难度障碍的关键就是要懂一些底层的微机原理,再加上多编程练习。只有在实际练习中我们才能训练大脑里的神经网络,只看书空想,不上手去编些程序,把它们调通是不行的。要知道我们调通的可不只有代码,还有脑子里的神经网络!

Verilog硬件描述语言比C语言又更底层一些,学好它又得多掌握一些更底层的、和数字电路相关的基础知识,以及其背后的思维方式。如果初学者抱着C语言的思维方式去理解Verilog,那这显然是不对的,会把自己整不会的。 我在初学Verilog时也有很多困惑,比如:啥叫RTL级电路?可综合的Verilog是啥意思?啥样的Verilog代码是可综合的,啥样的是不可综合的?阻塞和非阻塞赋值有啥区别?分别在啥时候用?

有这些困惑的根本原因也是因为对一些基本概念的了解还不够透彻,毕竟纸上得来终觉浅。如果要说客观原因就是也没有找到某本书或教程能把一些重要的底层概念串起来讲清楚。所以本集视频就是要尝试把一些关键的基本概念讲清楚。其实基本概念之所以叫“基本”“概念”,就是因为它们本应该都是像1+1 = 2这样好理解的,而我们理解一些新的基本概念有时会觉得困难,原因并不是因为这个概念有多难,而是我们不知道怎么把这个新概念和自己之前所学的概念联系起来。而现在的学科分科又导致了各学科中一些道理其实是相似的概念和知识被割裂了开来,我们认为这门学科的某个概念和别处的某个是不一样的,但其实是一样的。

大道至简,万法归一吗!我们的大脑皮层就是要通过建立更多的连接来更加深入的理解这个世界。我们对各学科知识的融汇贯通就是在让大脑里的神经网络建立更多的连接。现在把学科越分越细,让知识越来越不成体系,是造成大家觉得学习新知识越来越困难的一个重要原因!

好像有点扯远了,再回到Verilog,先来讲一下Verilog这门语言能描述的五个抽象层级:(1) 系统级;(2) 算法级;(3) RTL级;(4) 门级;(5) 开关级。一门语言纵跨五个抽象层级,看起来很厉害的样子。但其实平时我们做FPGA或芯片开发时会用到的只是中间的RTL级。上面的系统级和算法级我们一般都用C语言等高级语言写了,不会用Verilog。下面的门级假如你要写用与非门搭建寄存器的代码会用到,但我们在做开发时基本的寄存器、完成各种运算的门级电路都是FPGA或者芯片开发里的标准单元库提供好的,不需要我们从门级电路写起。所以我们搞FPGA开发,写的都是RTL级的电路功能描述代码。那RTL,Register Transfer Level,“寄存器传输级”又是啥意思呢?

要理解它需要的是数字时序电路的基本知识,而数电中最基本的知识又是什么呢?这样问吧,为啥数字电路里要有时钟?要有寄存器?寄存器是干啥的?它的主要功能是在时钟上升沿的时候采样数据,并把数据存储1到n个周期,是采样和存储数据用的。但它并没有改变数据哦,数字电路中真正起到运算作用的是组合逻辑电路。那既然寄存器并没有参与计算,又需要它干啥呢?

数电这个概念是和模电相对的, 本质上是离散和连续的相对,当我们把连续的模拟信号转变为数字信号时需要进行采样和量化,采样就得有采样率,量化会量化成二进制数字信号。那寄存器接的时钟频率其实就是采样率,存储的就是量化后的数字信号。在数字逻辑电路中,进行计算的逻辑门输出的信号也是需要寄存器进行采样的。时钟周期的大小,决定着两级寄存器之间信号能经过多少级的组合电路,也就是能进行多少的运算。这和绿灯周期长短决定着路口能过多少车道理一样。反过来说就是:组合电路级数带来的延时决定着电路能跑多高的频率。

上面就是理解RTL电路所需要的最基本概念,至于寄存器的建立时间和保持时间这些更细节的概念这里就不讲了,上面这个视频就讲的不错。其实寄存器所起的作用就是采样和量化我们以为它是连续的物理世界。其实我们能感知的物理世界并不是连续的啊,在物理世界中也有类似寄存器的东西帮我们采样和量化了可能是连续的能量流。而物理世界的这个寄存器可能就是原子,普朗克频率可能就是我们这个物理世界最基本的时钟频率。其实寄存器和原子之间是有相似之处的,寄存器为啥能存储数据呢,是因为它让电信号,也就是能量在它的几个门之间打转,形成了双稳态电路。也就是说它存储信息的方式是让能量打转。而物质则是被羁绊住的能量,我听有位科学家说过,光走直线时光就是光,光被掰弯旋转起来了就形成了原子。

好像又扯远了,我说这些就是想让大家明白学知识一定要融汇贯通,把你之前脑子里你以为都不相干的概念都使劲再深入的理解一下,找到其背后能相通和类比的地方,这样学起来才更容易,效率更高。认为学科间不能融汇贯通的想法都是愚蠢的,是水平还没到位的表现。

再回到RTL电路,寄存器传输级的意思就是,我们在写RTL代码时要把哪里有寄存器,以及寄存器之间信号是怎样传递的,也就是寄存器之间有哪些组合电路,要进行哪些计算都给写清楚。把这些都写清楚了,再由综合工具自动生成更底层的门级电路网表就容易了。因为啥会综合成啥已经写的很清楚了,寄存器就综合成寄存器,组合电路中加减就会综合成加法器,比较会综合成比较器,乘除也有相应的IP,乘法能自动综合,除法一般需要我们自己调用。if else语句会被综合成优先编码器,case语句大概也是被综合成编码器或是译码器。也就是只要我们把寄存器写清楚了,完成判断、运算的组合电路综合都有其对应的套路。

关键就是这个寄存器要写多少级,我们往往在一开始写RTL代码时是不知道的。这是得根据实际需求来的,达不到要求还需要进行调整。我们在开始写一个项目的Verilog代码时,它要完成的哪些计算我们是知道的,这个电路需要跑多高的频率我们也是知道的,但就是需要完成那些计算的组合电路中间需要插入多少寄存器是不大清楚的。

比如要写一个千兆以太网Mac层代码,Tx、Rx的时钟频率都是125兆,要做的事情就是数据包的解码,也就是时钟频率和计算需求都是知道的。再比如前面视频中讲的RGB转HSL这个例子,要干啥运算是知道的,C sharp代码是现成的。要跑的频率也大概是知道的,比如要处理1080p、60帧的视频流,像素时钟就是150兆,那这个转换电路就得跑到150兆才行。但从RGB输入,直到HSL输出,这中间需要多少级流水线寄存器呢?这在一开始是不知道的,一级都没有是不可能的,因为这里面的计算有好几步,还涉及到了除法,总的组合电路延时估计会比较长,不加流水线寄存器频率上不去。

Verilog关键知识点_第1张图片

我们在写FPGA代码时,首先从外部管脚的输入信号是会先直接输入到一级寄存器进行采样的,也就是在这最初一级的寄存器之前是不会加任何组合电路的。其次就是输出时也是要寄存器输出,也就是寄存器输出直接连管脚,中间不加任何组合电路。而在这一进一出两级寄存器之间写哪些寄存器,初学者往往会有些困惑。

Verilog关键知识点_第2张图片

RGB转HSL这个模块就是理解啥是RTL电路的一个非常好的例子。如上图所示,这个模块从RGB输入到HSL输出一共经历了23级寄存器,其中有20级是在除法器中,在这之前有两级,之后还有一级。电路最后综合一下在Artix 7系列FPGA里大概能跑160多兆。那如果没有这么多级寄存器,比如把最前面的两级去掉,让比较和加减法运算都在一个周期里完成也是可以的,但问题就是这样延时就大了,频率可能达不到要求。

那这时又一个问题来了,我怎么知道我写的运算电路延时到底是多少?这个是需要经验的,而经验来自于看综合后的时序报告,多看几次就会心里有数了,没估计准也没事,最终都是要根据时序约束是否满足来进行调整的。怎么看时序报告在RGB转HSL这个视频里讲过。让电路满足时序约束又是一个让初学者头疼的概念,而理解它所需要的基本概念就是建立、保持时间和上面我刚讲的这些内容。现在知道时序不满足时该咋办了吗?要加流水线寄存器啊,如果时序差了很多,比如要求10纳秒,结果却有14纳秒,那一般就是因为某两极寄存器之间你写的运算太多了。差多了肯定是要靠加流水线寄存器来解决的。差一点点可能还可以通过自己去约束后端布局布线的位置来解决,但这也很麻烦,又需要掌握一些后端布局布线的知识,还不如在代码里加流水线寄存器容易。

当我们掌握了上面这些基础知识之后再回头来看Verilog,就发现它比C语言多的也就上面这些东西。加减乘、与或非这些运算都是一样的,if else,switch case语句也基本是一样的,就是大括号换成了begin end。模块类似于C sharp里面的类,它们都需要例化,模块的输入输出就类似于类里面的公开成员。就是always块C语言里没有,但always @后面跟的敏感变量列表在高级语言里也是有对应概念的,对应的就是事件响应函数列表。

Verilog关键知识点_第3张图片

这样一说大家是不是就发现,当我们会了C语言之后,只需要再知道啥叫RTL,何时要写寄存器,该怎么写寄存器和组合电路,就基本上可以上手写Verilog代码了?这时再把我前几个视频里讲的例子拿来练习一下,很快就能变成熟练工。这时你不懂always是啥意思,不懂阻塞和非阻塞赋值是啥意思都是不要紧的。我到现在不去查一下都还不知道上面这两个等号哪个是阻塞赋值,哪个是非阻塞。但这没关系啊,我只需要知道always @ posedge clock语句块下面必须要用带箭头的等号,而这时等号左边,也就是被赋值的变量必须是reg,而且会被综合成寄存器就行了。带箭头的等号也只会出现在always @ posedge clock语句块中。

Verilog有一个让人困惑的地方,其实也是Verilog语法不严谨、不完善的地方。那就是wire型变量最后综合出来的肯定是线,也就是组合电路。但声明为reg型的变量却不一定都变成了寄存器,只有在前面说的always @ posedge clock语句块下的reg才会被综合成寄存器。写在always @ * 语句块下的还是被综合成了组合电路。因为Verilog语法规定了写在always块中的变量必须是reg,但@ posedge clock和@ *意义又是不一样的,只在上升沿时发生赋值的就是寄存器,敏感变量一变就会引发赋值的就是组合电路。

总结一下就是,要写寄存器就一种方法,要写组合电路似乎有assign和always @ *这两种写法,那这又该怎么选呢?assign适合写一些简单的逻辑和运算,也就是不需要写很多if else就能实现的功能。if else多了还是要放到always快中写,也只有在那里才能写。不过assign后面也可以写问号表达式,实现一些简单的逻辑判断功能。在声明wire变量之后可以直接写它要等于啥,这和assign语句是等价的,这样写可以让代码更加的简洁明了。省的老是忘了变量的位宽是多少,还要跑到前面去看。声明变量时忘写位宽也是初学经常犯的错误,跑仿真时也不报错,但就是结果里很多红叉,追踪了半天信号才发现是某个变量位宽忘写了,哈哈。

要讲的Verilog关键知识点也就这么多了。要想深入理解always和为啥要整出阻塞和非阻塞赋值这样的概念,还需要大家多思考一些问题。比如要让你写一个Verilog仿真器该怎么写?或者是让你写个模型模拟城市交通情况,那又该如何写代码能让串行执行的程序去仿真现实世界中的诸多并行事件呢?这里面问题的关键就是如何用串行仿真并行,其实就是量化了时空再加上事件触发。一个信号过来会导致门电路翻转就是事件触发,别人骂你、你骂会去也是事件触发,模拟这种立即触发的事件用的就是立即会改变左边值的阻塞赋值。而寄存器采样这种,并不是你输入变了我就变,我只等时钟上升沿来了才会采样的情况就用左边值不会立刻改变的非阻塞赋值来模拟。整出这些语法都是为了建模的需要,当我们自己想想该如何仿真建模这些问题时,就会明白这些语法的含义和目的。也没那么难,就是要让自己站在建模语言设计者的角度去多思考就能明白。

这里又引出了一个学习的诀窍,那就是不要只是听讲,跟在别人后面学,而是要多主动思考,想想当我要面对某个问题时该怎么办。你只有把当初这个语言的设计者,和某个学术概念的提出者在设计和提出这些东西时所思考的问题都再想一遍,才能深入彻底的理解它们,说不定还能有新的发现,超越前人。

经常看见11:11是咋回事?有啥意义? - 知乎我记得非常清楚,我是从2010年上半年开始总是在不经意间看见11:11。刚开始自然也没在意,后来发现经常不经意一扭头正好就看见11:11。于是终于觉得这个事情有点蹊跷了,当时我还在帝都某所实习,就和同学聊了这个事…https://zhuanlan.zhihu.com/p/523746992

你可能感兴趣的:(fpga开发,图像处理,人工智能,神经网络)