完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
5.2 时序逻辑实现的加法器 我们分析下面这段代码
我们仍然从语法上,分析该段代码的功能。该段代码总是在“时钟clk上升沿或者复位rst_n下降沿”的时候执行一次。怎样执行呢? 1. 如果复位rst_n=0,则q的值为0; 2. 如果复位rst_n=1,则将(a+d)的结果赋给q(注意,前提条件是时钟上升沿的时候)。 假设用信号c表示a+d的结果,则第2点可改为:如果复位rst_n=1,则将c的值赋给q(注意,前提条件是时钟上升沿的时候)。这很明显就是一个D触发器,输入信号为d,输出为q,时钟为clk,复位为rst_n。 图 40 c是怎么来的?c是a+d的结果,自然是一个加法器,所以可以画出上面代码所对应的电路结构图,可以看出在D触发器的基础上增加了一个加法器。 图 41 很容易分析出上面电路的功能:信号a和信号b相加得到c,c连到D触发器的输入端。当clk出现上升沿时,将c的值传给q。这与代码功能是一致的。 下面是代码和硬件所对应的波形图。 图 42 先看信号c的波形,c的产生只有与a和b有关,与rst_n和clk无关。c是a+d的结果,按照二进制加法:0+0=0,0+1=1,1+1=0。就可以画出c的波形。
再看信号q的波形。q是D触发器的输出,它只在rst_n的下降沿或者clk的上升沿才变化,其他时候不变化,也就是a、b、c有变化时,q都不会立刻变。 图 43
读者有没有发现,在讨论时序逻辑的加法器时,我们是分开讨论加法器的输出c和D触发器的输出q,这就像两块独立的电路。那我们Verilog代码,是否也可以分开来写呢?当然是可以的。 我们可以先将下面的硬件电路用Verilog描述出来。 图 44 该电路对应的电路,可以写成:
也可以写成
上面的两段代码,都是描述同一硬件电路,并且是加法器。 其次,我们再用Verilog描述一下触发器。 图 45 其代码的写法如下:
最后,我们可以看到,两段代码都有信号c,说明这两个是相连的,因此硬件连接起来,变成下面电路。 图 46 由此可见,下面两段代码所对应的硬件电路是一模一样的。
这两种代码哪种比较好?答案是一样好。因为它们的硬件是相同的,这就是评估verilog代码好不好的最基本标准,不是看代码行数,而是看硬件。 6 时钟的重要性 时钟信号是每隔固定时间上下变化的信号。本次上升沿和上次上升沿占用的时间,就是时钟周期,它的倒数就是时钟频率。高电平占整个时钟周期的时间,称之为占空比。 FPGA中的时钟,占空比一般是50%,即高电平时间和低电平时间一样。其实占空比在FPGA内部没有太大的意义,因为我们使用的是时钟上升沿来触发,更加关心的是时钟频率。 如果时钟的上升沿每秒出现一次,说明时钟的时钟周期为1秒,时钟频率为1Hz。如果时钟的上升沿每1毫秒出现一次,说明时钟的时钟周期为1毫秒,时钟频率为1000Hz,或写成1kHz。 现在普通的FPGA器件,所支持的时钟频率范围一般不超过150M,高端器件可能不超过700M(经验值,实际能跑多愉,取决于器件、设计的电路有相当大的关系)。反对应的时钟周期在纳秒级范围。所以本教材里,所有案例的时钟频率一般都是几十到一百多M。 下面列出本教材常用到的时钟频率以及所对应的时钟周期,方便读者进行换算。
时钟是FPGA最重要的信号,所有的其他信号在时钟的上升沿统一变化,这就像军队里的令旗,所有军队在看到令旗到来的时刻,执行已经设定好的命令。 时钟这块令旗影响着整体电路的稳定。首先,时钟要非常地稳定跳动。就如军队令旗,时快时慢,就会让人无所适从,容易出错。而如果令旗非常稳定,每个人都知道令旗什么时候过来,在令旗到来前能不能完成任务,不能就通知改正(修改代码),避免系统出错。 其次,一个高效的军队,令旗越少越好,不同部队看不同的令旗,那么部队协作就容易出现问题,整个军队必定做不到高效,或者容易出错。同样道理,FPGA系统的时钟,必定是越少越好,最好就是一个时钟。这也是要求读者,不要把信号放在时序逻辑敏感列表的原因。 7 模块7.1 模块结构 模块(module)是Verilog 的基本描述单位,用于描述某个设计的功能或结构及与其他模块通信的外部端口。 模块在概念上可等同一个器件就如我们调用通用器件(与门、三态门等)或通用宏单元(计数器、ALU、CPU)等,因此,一个模块可在另一个模块中调用。一个电路设计可由多个模块组合而成,因此一个模块的设计只是一个系统设计中的某个层次设计,模块设计可采用多种建模方式。 每个模块实现特定的功能,模块可进行层次的嵌套,因此可以将大型的数字电路设计分割成大小不一的小模块来实现特定的功能,最后通过由顶层模块调用子模块来实现整体功能,这就是Top-Down的设计思想, Verilog 的基本设计单元是“模块”。采用模块化的设计使系统看起来更有条理也便于仿真和测试,那么整个项目的设计思想就是模块套模块,自顶向下依次展开。 本书主要以verilog硬件描述语言为主,模块是Verilog的基本描述单位,用于描述每个设计的功能和结构,以及其他模块通信的外部接口。 模块有五个主要部分:端口定义、参数定义(可选)、 I/O说明、内部信号声明、功能定义。且模块总是以关键词module开始,以关键词endmodule结尾。它的一般语法结构如下所示: 下面我们来详细分析一下这段代码: 7.2 模块的端口定义 第1至5行声明了模块的名字和输入输出口。其格式如下: module 模块名(端口 1,端口 2,端口 3,……); 其中模块是以module开始,以endmodule结束。模块名是模块唯一的标识符,我们建议模块名尽量用能够描述其功能的名字来命名,并且模块名和文件名相同。 模块的端口表示的是模块的输入和输出口名,也就是它与别的模块联系端口的标识。 7.3 参数定义第7行参数定义是将常量用符号代替,以增加代码可读性和可修改性,是一个可选择的语句,用不到可以省略,参数定义一般格式如下: parameter DATA_W = x; 7.4 I/O 说明7.5 信号类型 第16至18行定义了信号的类型。在模块内用到的和与端口有关的 wire 和 reg 类型变量的声明。如: reg [width-1 : 0] R 变量 1, R 变量 2 ……; wire [width-1 : 0] W 变量 1,W 变量 2……; 如果不写,默认是wire型,并且信号位宽为1。 7.6 功能描述第21至31行是功能描述部分。模块中最重要的部分是逻辑功能定义部分。有三种方法可在模块中产生逻辑。 1. 用“assign”声明语句,如描述一个两输入与门:assign a = b & c。 2. 用“always”块。即前面介绍的时序逻辑和组合逻辑。 3. 模块例化。 7.6.1 例化对一个数字系统的设计,我们采用的是自顶向下的设计方式。可把系统划分成几个功能模块,每个功能模块再划分成下一层的子模块。每个模块的设计对应一个module ,一个module 设计成一个verilog HDL 程序文件。因此,对一个系统的顶层模块,我们采用结构化的设计,即顶层模块分别调用了各个功能模块。 一个模块能够在另外一个模块中被引用,这样就建立了描述的层次。模块实例化语句形式如下: module_name instance_name(port_associations) ; 信号端口可以通过位置或名称关联;但是关联方式不能够混合使用。端口关联形式如下: port_expr / /通过位置。 .PortName (port_expr) / /通过名称。
建议:在例化的端口映射中请采用名字关联,这样,当被调用的模块管脚改变时不易出错。 在我们的实例化中,可能有些管脚没用到,可在映射中采用空白处理,如:
对输入管脚悬空的,则该管脚输入为高阻 Z,输出管脚被悬空的,该输出管脚废弃不用。 下面以一个实例(一个频率计数器系统)说明如何用HDL进行系统设计。 在该系统中,我们划分成如下三个部分:2输入与门模块,LED显示模块,4位计数器模块。系统的层次描述如下: 图 47 顶层模块CNT_BCD,文件名CNT_BCD.v,该模块调用了低层模块 AND2、CNT_4b和 HEX2LED 。系统的电路结构图如下: 图 48 顶层模块CNT_BCD对应的设计文件 CNT_BCD.v 内容为:
注意:这里的AND2是为了举例说明,在实际设计中,对门级不要重新设计成一个模块,同时对涉及保留字的(不管大小写)相类似的标识符最好不用。 7.7 模块案例 下面先介绍几个简单的Verilog HDL程序。 例[1] 加法器
该例描述一个3位加法器,从例子可看出整个模块是以module 开始,endmodule 结束。 例[2] 比较器
该例描述一个比较器,从上可看到,/* .... */ 和 // ... 表示注释部分。注释只是为了方便设计者读懂代码,对编译并不起作用。 例[3] 三态驱动器
该例描述了一个三态驱动器。其中三态驱动门在模块 mytri 中描述,而在模块trist 中调用了模块mytri 。模块mytri 对trist 而言相当于一个已存在的器件,在trist 模块中对该器件进行实例化,实例化名 u_mytri 。 8 可综合设计 Verilog硬件描述语言有很完整的语法结构和系统,类似高级语言,这些语法结构的应用给我们的设计描述带来很多方便。但是,Verilog是描述硬件电路的,它是建立在硬件电路的基础上的。有些语法结构只是为了仿真测试目的,是不能与实际硬件电路对应起来的,也就是说我们在把一个语言描述的程序映射成实际硬件电路中的结构时是不能实现的。 综合就是把你写的rtl代码转换成对应的实际电路。 比如你写代码assign a=b&c; EDA综合工具就会去元件库里拿一个二输入与门出来,然后输入端分别接上b和c,输出端接上a 假如你写了很多这样的语句
综合工具就会像搭积木一样的把你这些“逻辑”电路用一些“门”电路来搭起来。当然,工具会对必要的地方做一些优化,比如你写一个电路assing a=b&~b,这样工具就吧a恒接为0了,而不会去给你找一个与门来搭这个电路。 所以,“综合”要做的事情有:编译rtl代码,从库里选择用到的门器件,把这些器件按照“逻辑”搭建成“门”电路。 不可综合,是指找不到对应的“门”器件来实现相应的代码。比如#100之类的延时功能,简单的门器件是无法实现延时100个单元的。还有打印语句等,也是门器件无法实现的。 我们在设计的时候,要确保所写的代码是可以综合的,这一个是依赖于设计者的能力,知道什么是可综合的代码,什么是不可综合的代码。对于初学者来说,最好是先记住规则,遵守规则,先按规则来设计电路。在这一过程中,逐渐理解,这是一个最好的学习路径。 下面表格,列出了不可综合或者不推荐使用的代码。 表不可综合或不推荐使用的代码
下表是明德扬推荐使用的设计。 表明德扬规范推荐使用的代码及其说明
|
|
|
|
1226 浏览 1 评论
助力AIoT应用:在米尔FPGA开发板上实现Tiny YOLO V4
1027 浏览 0 评论
2292 浏览 1 评论
2008 浏览 0 评论
矩阵4x4个按键,如何把识别结果按编号01-16(十进制)显示在两个七段数码管上?
2263 浏览 0 评论
1776 浏览 47 评论
6000 浏览 113 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-19 02:46 , Processed in 0.519336 second(s), Total 64, Slave 47 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号