摘要:本文是对实验课上讲解的面向硬件电路的设计思维的总结,结合数字逻辑课本,进行提炼和整理。可见阻塞赋值描述时序电路有风险。
本文是对实验课上讲解的“面向硬件电路的设计思维”的总结,结合数字逻辑课本,进行提炼和整理。
主要来源是课件与本人整理,部分参考了网络大佬的博客。
本文主要介绍不同于之前软件设计思维的硬件设计思维,从非阻塞赋值、并行、面积速度转换、同步电路设计原则、模块划分设计、if-case对比等方面进行整理。
内容太多,我整理了好几天,在浩如烟海的网络前有点无力,想想是自己的实践不够,有一些问题没有亲身体验;也不能一蹴而就,得久久为功。所以这篇文章就当作一个Verilog学习与FPGA设计的总述性文章,后续继续学习我会加深对这些知识的理解。
回忆一下课本上的相关内容。
阻塞赋值:
"="
Verilog编译器按照这些语句在always块中的先后顺序依次执行。
如果一个变量通过阻塞赋值语句赋值,则这个新赋的值会在这个block中的后续语句中使用。
相当于串行
非阻塞赋值:
"<="
always块中所有非阻塞赋值的语句在求值时所用的值是最初进入always时各个变量已经具有的值。
换一个角度讲,"<="左侧的被赋值变量,只在always结束时统一被更新。
相当于并行
先来看一看这段代码:
1 module example5_5 (x1, x2, x3, Clock, f, g);2 input x1, x2, x3, Clock;3 output reg f, g;4 always @(posedgeClock)5 begin6 f=x1 & x2;7 g=f | x3;8end9endmodule
可以看到关键点是g的表达式,由于是阻塞赋值,所以相当于:
g=(x1 & x2) | x3;
综合出的电路如图:
1 module example5_6 (x1, x2, x3, Clock, f, g);2 input x1, x2, x3, Clock;3 output reg f, g;4 always @(posedge Clock)5 begin6 f <=x1 &x2;7 g <=f | x3;8 end9 endmodule
这个区别之处就在于这个g,是x3与前一个 f 进行"|"运算。
将阻塞赋值的示例代码中的两个执行语句互换位置,会发生什么情况?
可以料见影响比较大。
可见阻塞赋值描述时序电路有风险。
相反的,如果我们要实现 f=a1a0 + a2a1这样一个函数;
1 always @(A)2 begin3 f=A[1] & A[0];4 f=f | (A[2] & A[1]);5 end
1 always @(A)2 begin3 f <=A[1] & A[0];4 f <=f | (A[2] & A[1]);5 end
可见这段代码有两个特征;
非阻塞赋值的结果在always结束后才可以看到
多次赋值时,后覆盖前。
这两个特征使得第二个f语句出现问题,因为第二个语句
f <=f | (A[2] & A[1]);
右侧的f的值是不可见的。
对组合逻辑建模采用阻塞赋值
对时序逻辑建模采用非阻塞赋值
用多个always块分别对组合和时序逻辑建模
尽量不要在一个always块里面混合使用阻塞赋值和非阻塞赋值。如果在同一个块即为组合逻辑又为时序逻辑,应使用“非阻塞赋值”
这里给的例子没怎么看懂。自己查了一下。
先说结论:
各个always块是并行执行的,
always块和initial块之间是并行执行的,
begin-end块内是顺序执行的,
但是非阻塞赋值(<=)是并行执行的,阻塞赋值(=)是顺序执行的,这条优先。且硬件思想的集中体现就是前面提到过的非阻塞赋值带来的并行执行语句。
再回去看例子:
1 module test ( clk, reset, a, b ); 2 input clk; 3 input reset; 4 input [3:0 ] a; 5 output [ 3:0 ] b; 6 7 reg [ 3:0] tempa1, tempa2, b; 8 9 always @ ( posedge clk ) begin10 if ( ! reset ) begin11 tempa1<=0;12tempa2<=0;13 b<=0;14 end15 elsebegin16 tempa1<=a + 1’b1;17tempa2<=tempa1 + 1’b1;18 b<=tempa2 + 1’b1;19 end20 end21 endmodule
可以料见实现的电路:
下面借鉴了这篇文章
波形图:
可以看到强调的还是上面说过的非阻塞赋值的特点。
实验任务里总有这么一句:“用可综合的代码......”
什么是可综合性,什么又是不可综合性呢?
下面学习了这篇文章
这篇文章讲的挺多,但是我现在这个RTL级还没搞明白的菜鸟用不到这么多,基本筛选如下:
不可综合的Verilog语句:
initial
只能在test bench中使用,不能综合。
assign 和deassign
不支持对reg 数据类型的assign或deassign进行综合,支持对wire数据类型的assign或deassign进行综合。
fork join 不可综合,可以使用非块语句达到同样的效果。
这个块是并行执行的,但是不可综合。
敏感列表里同时带有posedge和negedge 如:(现在也碰不到
1 always@(posedge clk or negedge clk) 2 begin3 ...4 end
这里我们说的面积:设计所占用的FPGA逻辑资源数目,一般用所消耗的触发器和查找表(还没学)来衡量。
速度:是指在芯片上可以稳定运行时能达到的最高频率
两者性能上的调配方法:
模块复用
串并变换
可以看到这种串并转换,用更大的面积(即多个子模块并行),达到高频率的效果。这一点后面还会再提到。
流水线
同步设计的优点:
可以有效避免毛刺的影响,提高设计的可靠性
可以简化时序分析过程
可以减少工作环境对设计的影响
设计原则:
(由于应用还不多,对这些体会还不深刻,简单记录:
单时钟
全局时钟网络的时钟是性能最优,最便于预测的时钟,具有最强的驱动能力
单时钟沿
混合时钟会使时序分析复杂、电路工作频率降低
避免使用门控时钟
即时钟不要与组合逻辑再进行组合,如下:
可能引起毛刺、偏移
在模块内部不要再产生时钟了。
这有点像C++的封装。
上一层模块只负责下一层模块的依据(即原材料),而具体行为互不相关。
这样就保证了各个模块的相对独立性和内部结构的合理性,便于维护,也使得相同逻辑可以复用同一模块。
在设计时,应尽量将模块中的同步时序逻辑输出信号以寄存器的形式送出,以便于综合工具区分时序和组合逻辑;
并且时序输出的寄存器应符合流水线设计思路,能工作在更高的频率,以极大地提高模块吞吐量。
流水线设计思路是什么?
就是将组合逻辑系统地分割,并在各个部分(分级)之间插入寄存器,并暂存中间数据的方法。 目的是将一个大操作分解成若干的小操作,每一步小操作的时间较小,所以能提高频率,各小操作能并行执行,所以能提高数据吞吐率(提高处理速度)。
对于我这个初学者来说,逻辑复用和逻辑复制十分相似,了解后就知道确实不同,主要是涉及性能衡量尺度:速度和面积的统筹。
逻辑复用是通过提高工作频率来节省面积的优化方法,经常用于存在多个资源可共享单元的设计中。
PS:相当于为了节省人力,而让一个人干三个人的活。
10MHZ乘法器
两个5MHZ乘法器
逻辑复制——面积换速度
逻辑复用是通过增加面积而改善设计时序的优化方法,经常用于调整信号的扇出。
举例就类似于上面的面积换速度
链状结构
树状结构
If语句指定了一个有优先级的编码逻辑,
而case语句生成的逻辑是并行的,不具有优先级。
这里的if的优先级就引起一些其他问题:
1 always@(in0,in1,in2,in3) 2 begin 3 sel=2’b00 ; 4 if(in0) sel=2’b00 ; 5 else if(in1) sel=2’b01 ; 6 elseif(in2) sel=2’b10 ; 7 else if(in3) sel=2’b11 ; 8end 9//当这里in0和in1都==1时,se1=2b00而不是2b01;10 //这就是if-else的优先逻辑。
而case是并行的,没有优先级。
if语句可以包含一系列的表达式;/有时甚至一个else就可以是一个二路选择器。
而case语句比较的是一个公共的控制表达式。整个语句块一起构成了一个多路选择器。
这个很好理解。
通常if-else结构速度较慢,但占用的面积小;
case语句结构速度较快,但占用的面积较大。
嵌套的if语句如果使用不当,就会导致设计的更长延时。
如果想利用if语句来实现那些对延时要求苛刻的路径,应将最高优先级给最迟到达的关键信号。(最小生成树思想)。
有时为了兼顾面积和速度,可以将if和case语句合用。
1 //if-else实现四选一 2 module sdata_if (clk, reset, x, s, y); 3 input clk; 4 input reset; 5 input[3:0] x; 6 input [1:0] s; 7 output y; 8 9 reg y;10 always@(posedge clk)begin11 if(!reset)begin12 y<=0;13 end14 else begin15 if(s==2b00)16 y<=x[0];17 else if (s==2b01)18 y<=x[1];19 else if (s==2b10)20 y<=x[2];21 else 22 y<=x[3];23 end24 end25 endmodule
想象一下是什么电路?
就是一个四选一,需要两位的控制信号,这个控制信号就正好是s。
1 //case语句 2module sdata_if (clk, reset, x, s, y); 3 input clk; 4 input reset; 5 input[3:0] x; 6 input [1:0] s; 7 output y; 8 9 reg y;10 always@(posedge clk)begin11 if(!reset)begin12 y<=0;13 end14 else begin15 case(s)16 2b00: y<=x[0];17 2b01: y<=x[1];18 2b10: y<=x[2];19 2b11: y<=x[3];20 end21 end22 endmodule2324
实现电路也是类似上面的电路。
锁存器在课本里学过,是用于存储一位数据的元件,电平触发。
其特点是:锁存器在不锁存数据时,输出随输入变化;但一旦数据锁存时,输入对输出不产生任何影响。
而我们在设计电路时,应该避免无意之间产生这种锁存器,否则会导致一些逻辑上的错误。
引起意外锁存器的原因
翻阅了很多网上的总结。有一些规则比较复杂,考虑到我现在的水平,我只记录对初入门水平够用且好理解的方面。后续继续学习可以深入了解更多。
if……else……结构中缺少else
case结构中的分支没有包含所有情况且没有default语句。
如果使用if语句,最好写上else分支;
如果使用case语句,最好写上default语句。
即使需要锁存器,也通过else分支或default分支来显式说明。而不要利用语言特性触发生成(因为不可控)
内容真的好多,一时间难以完全消化...
上传于2021年11月25日23时
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/125363.html
摘要:将经过仿真的设计下载到硬件实验箱进行验证。流水灯控制电路仿真如图所示实验引脚锁定八个按键按键分别对应上的引脚。 一、实验目的 (1)学习并掌握Quartus II的...
摘要:本章我们将使用高速芯片实现数模转换,产生正弦波模拟电压信号。实验任务本节实验任务是使用新起点开发板及双路高速扩展模块模块实现数模转换。下载验证将双路高速模块插入新起点开发板的扩展口,连接时注意扩展口电源引脚方向和开发板电源引脚方向一致。 ...
摘要:本文就关于电子元件国产化的一些交流内容进行介绍。一些重要的工业领域的国产化要求越来越高,也会对高端的需求增加。 前几天发表的工业控制领域电子元件全国产化替代解读文章也有一些关注与讨论,这个文章有人说是软文,想想也像是软文,不过里边提到的任一个厂家都没有给赞助,也是很无奈。文章主要目的是把我接...
摘要:为了应对计算多元化的需求,越来越多的场景开始引入等硬件进行加速,异构计算应运而生。众所周知,意味着对计算力的超高要求,目前以为代表的异构计算已成为加速创新的新一代计算架构。目前异构计算使用最多的是利用来加速。在互联网行业,随着信息化的普及,数据量的暴增使得人们对存储空间又有了新要求,同时,机器学习、人工智能、无人驾驶、工业仿真等领域的崛起,使得通用CPU在处理海量计算、海量数据/图片时遇到越...
阅读 682·2023-04-25 19:43
阅读 3855·2021-11-30 14:52
阅读 3729·2021-11-30 14:52
阅读 3795·2021-11-29 11:00
阅读 3745·2021-11-29 11:00
阅读 3812·2021-11-29 11:00
阅读 3528·2021-11-29 11:00
阅读 6009·2021-11-29 11:00