FPGA快速入门3——verilog可编程进阶

前两节主要介绍了Verilog一些基础的知识点,本节给大家介绍一些高级的进阶知识点。高级进阶知识点包括阻塞赋值和非阻塞赋值、assign和always语句差异、什么是锁存器、状态机、模块化设计等。

阻塞赋值和非阻塞赋值

在Verilog中有两种类型的赋值语句:阻塞赋值语句(“=”)和非阻塞赋值语句(“<=”)。正确地使用这两种赋值语句对于Verilog的设计和仿真非常重要。

Verilog语言中讲的阻塞赋值与非阻塞赋值,但从字面意思来看,阻塞就是执行的时候在某个地方卡住了,等这个操作执行完在继续执行下面的语句,而非阻塞就是不管执行完没有,我不管执行的结果是什么,反正我继续下面的事情。而Verilog中的阻塞赋值与非阻塞赋值正好也是这个意思,通过执行一个例子,就可以简单地明白了:

1、阻塞赋值可以理解为语句的顺序执行,因此语句的执行顺序很重要;

2、非阻塞赋值可以理解为语句的并行执行,所以语句的执行不考虑顺序;

3、在assign的结构中,必须使用的是阻塞赋值。

也就是说:

阻塞:在本语句中“右式计算”和“左式更新”完全完成之后,才开始执行下一条语句;

非阻塞:当前语句的执行不会阻塞下一语句的执行。

阻塞语句的时序:

 

 

 

非阻塞语句

 

 

 

 

阻塞语句的使用

(1)在时序逻辑电路中一般使用非阻塞赋值。

     非阻塞赋值在块结束后才完成赋值操作,此赋值方式可以避免在仿真出现冒险和竞争现象。

(2)在组合逻辑电路中一般使用阻塞赋值。

     使用阻塞方式对一个变量进行赋值时,此变量的值在在赋值语句执行完后就立即改变。

(3)在assign语句中必须使用阻塞赋值语句。

 

assign和always区别 

assign语句和always语句是Verilog中的两个基本语句,这两个都是经常使用的语句。

assign语句使用时不能带时钟。always语句可以带时钟,也可以不带时钟。在always不带时钟时,逻辑功能和assign完全一致,都是只产生组合逻辑。比较简单的组合逻辑推荐使用assign语句,比较复杂的组合逻辑推荐使用always语句。示例如下:

 

​​​​​​​什么是latch?

 

latch是指锁存器,是一种对脉冲电平敏感的存储单元电路。锁存器和寄存器都是基本存储单元。

锁存器是电平触发的存储器,是组合逻辑产生的。

寄存器是边沿触发的存储器,是在时序电路中使用,由时钟触发产生的。

latch的主要危害的是会产生毛刺(glitch),这种毛刺对下一级电路是很危险的。并且其隐蔽性很强,不易查出。因此,在设计中,应尽量避免latch的使用。

出现latch的原因:代码里面出现latch的两个原因是在组合逻辑中,if或者case语句不完整的描述,比如if缺少else分支,case缺少default分支,导致代码在综合过程中出现了latch。

解决办法就是if必须带else分支,case必须带default分支。

 

大家需要注意下,只有不带时钟的always语句if或者case语句不完整才会产生latch,带时钟的语句if或者case语句不完整描述不会产生latch。下面为缺少else分支的带时钟的always语句和不带时钟的always语句,通过实际产生的电路图可以看到第二个是有一个latch的,第一个仍然是普通的带有时钟的寄存器。

寄存器的电路示意图:

锁存器的电路示意图:

 

​​​​​​​状态机

 

Verilog是硬件描述语言,硬件电路是并行执行的,当需要按照流程或者步骤来完成某个功能时,代码中通常会使用很多个if嵌套语句来实现,这样就增加了代码的复杂度,以及降低了代码的可读性,这个时候就可以使用状态机来编写代码。状态机相当于一个控制器,它将一项功能的完成分解为若干步,每一步对应于二进制的一个状态,通过预先设计的顺序在各状态之间进行转换,状态转换的过程就是实现逻辑功能的过程。

状态机,全称是有限状态机(Finite State Machine,缩写为FSM),是一种在有限个状态之间按一定规律转换的时序电路,可以认为是组合逻辑和时序逻辑的一种组合。状态机通过控制各个状态的跳转来控制流程,使得整个代码看上去更加清晰易懂,在控制复杂流程的时候,状态机优势明显,因此基本上都会用到状态机,如SDRAM控制器等。

根据状态机的输出是否与输入条件相关,可将状态机分为两大类,即摩尔(Moore)型状态机和米勒(Mealy)型状态机。

Ø Mealy状态机:组合逻辑的输出不仅取决于当前状态,还取决于输入状态。

Moore状态机:组合逻辑的输出只取决于当前状态。

三段式状态机

 

根据状态机的实际写法,状态机还可以分为一段式、二段式和三段式状态机。

一段式:整个状态机写到一个always模块里面,在该模块中既描述状态转移,又描述状态的输入和输出。不推荐采用这种状态机,因为从代码风格方面来讲,一般都会要求把组合逻辑和时序逻辑分开;从代码维护和升级来说,组合逻辑和时序逻辑混合在一起不利于代码维护和修改,也不利于约束。

二段式:用两个always模块来描述状态机,其中一个always模块采用同步时序描述状态转移;另一个模块采用组合逻辑判断状态转移条件,描述状态转移规律以及输出。不同于一段式状态机的是,它需要定义两个状态,现态和次态,然后通过现态和次态的转换来实现时序逻辑。

三段式:在两个always模块描述方法基础上,使用三个always模块,一个always模块采用同步时序描述状态转移,一个always采用组合逻辑判断状态转移条件,描述状态转移规律,另一个always模块描述状态输出(可以用组合电路输出,也可以时序电路输出)

 

推荐使用三段式状态机

实际应用中三段式状态机使用最多,因为三段式状态机将组合逻辑和时序分开,有利于综合器分析优化以及程序的维护;

并且三段式状态机将状态转移与状态输出分开,使代码看上去更加清晰易懂,提高了代码的可读性,推荐大家使用三段式状态机,本文也着重讲解三段式。

三段式状态机的基本格式是:

第一个always语句实现同步状态跳转;

第二个always语句采用组合逻辑判断状态转移条件;

第三个always语句描述状态输出(可以用组合电路输出,也可以时序电路输出)。

在开始编写状态机代码之前,一般先画出状态跳转图,这样在编写代码时思路会比较清晰,下面以一个7分频为例(对于分频等较简单的功能,可以不使用状态机,这里只是演示状态机编写的方法),状态跳转图如下图所示。

这里是使用独热码的方式来定义状态机,每个状态只有一位为1,当然也可以直接定义成十进制的0,1,2……7。

因为我们定义成独热码的方式,每一个状态的位宽为7位,接下来还需要定义两个7位的寄存器,一个用来表示当前状态,另一个用来表示下一个状态;

parameter S0 = 7'b0000001; //独热码定义方式
parameter S1 = 7'b0000010;
parameter S2 = 7'b0000100;
parameter S3 = 7'b0001000;
parameter S4 = 7'b0010000;
parameter S5 = 7'b0100000;
parameter S6 = 7'b1000000;

reg [6:0] curr_st ; //当前状态
reg [6:0] nextst ; //下一个状态

接下来就可以使用三个always语句来开始编写状态机的代码,第一个always采用同步时序描述状态转移;

第二个always采用组合逻辑判断状态转移条件;

第三个always是描述状态输出;

 

 

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值