Verilog学习总结

15b88e68b3287c60e11b9327636ac2d0.png

94a16029209044005f19b21b3183b65c.png

一、阻塞赋值和非阻塞赋值问题;

1.1 阻塞赋值,即“=”。用于组合逻辑的设计中,例如:

1)连续赋值语句:

8d16e625e4e1f788257f7310ed521411.png

2)在always模块中设计的组合逻辑电路:

128899b9e63fdc4b330f238af60acc87.png

1.2 非阻塞赋值,即“<=”。用于时序逻辑设计。例如:

0353bd6dccb7e3945cbd58aef02558ab.png

1.3 两者的区别:

a.阻塞赋值先赋值,always块才会结束,即在阻塞赋值过程中不允许其他指令的插入,直到完成赋值为止;

b. 而非阻塞赋值在赋值的过程中可以插入其他指令,在块结束之后才赋值;

导致结果的不同:

a. test1模块得到的结果是当时钟的上升沿到来时b的值为a的值,而c的值也为a的值,因为a的值送给b之后,才实行c=b操作,此时b已经变为a的,所以c也为a的值;

b. test2中的结果为b等于a,而c等于b原来的值,因为在模块结束后才将a值送给b,而c=b操作在模块结束之前就完成了,所以c为b的值。

所以可以看到在相同的环境下,不同的幅值方式产生了很大的差别,所以为了达到设计的要求,避免冒险竞争问题,应按下列要求进行设计:

1)在设计时序电路建模和锁存器建模时,用非阻塞赋值;

2)在电平触发的always块和连续赋值语句设计的组合逻辑电路时,用阻塞赋值;

3)在时钟边沿触发的always块中设计组合和时序逻辑电路时,用非阻塞赋值;

4)不能在同一个always块中同时出现阻塞赋值和非阻塞赋值。

.

.

.

二、同步复位和异步复位的问题

2.1 首先是同步复位,详细如下:

185bf9de9b528f464768f1f482007f51.png

具体为:在always块的条件中不加入复位信号rst,此时只有当clk的上升沿到来时,才能进入always块中实现复位,即与时钟同步,所以称为同步复位。

2.2 其次是异步复位,详细如下:

d621a996090983502ef570ec6683ef93.png

具体为:在always块的条件中加入复位信号rst,此时不只有当clk的上升沿到来时,才能进入always块中实现复位,rst的下降沿到来时也能实现复位,即可以不与时钟同步,所以称为异步复位。

2.3 各自的优缺点

1)同步复位的优点:

a. 可以实现系统的100%的同步,方便时钟分析;

b. 可以防止复位信号的突变,以为即使复位信号有突变,此时时钟信号的上升沿没有到来,也不能实现复位;

2)同步复位的缺点:

a. 复位信号的有效时间必须大于一个时钟周期才能反映,如果复位信号延时过短就不能实现复位;

b. 在逻辑器件中的所有触发器都是异步复位的,所以在使用同步复位时,在每一个触发器的输入端都需添加一个寄存器,这样就无形中消耗了资源;

3)异步复位的优点:

a. 可以实现全局随时复位,操作简单;

b. 在每个触发器前不需要多余的寄存器,减少资源消耗;

4)异步复位的缺点:

a. 如果复位信号出现尖刺,容易导致异常复位,影响系统正常运作;

所以各有千秋,推荐使用异步复位,因为尖刺并不会容易产生,不必过于担心,而且能够实现随时手动复位,减少资源消耗。

.

.

.

三、状态机的设计流程及其注意事项

3.1 状态机设计步骤

a. 捋清事件的来龙去脉,事件原因即为逻辑输入,结果即为逻辑输出,输入输出的关系即为逻辑关系;

b. 将实际的逻辑关系用逻辑函数表示,然后将函数化简,函数越简单,电路实现就越简单,利用的资源也就越少;

c. 列出状态转换表或状态转换图;

d. 状态编码,即选择gray编码或独热编码,如果FPGA器件的触发器资源丰富,推荐使用独热编码,即使电路的复杂度会增高,但能提高电路的性能;

e. 捋清每一个状态下,相应值的赋值情况,即将某些状态符置高或置低;

f. 捋清状态转换的条件;

g. 选择case语句或if-else语句实现代码描述。

3.2 状态机设计注意事项

a. 在描述多状态转换时,推荐利用case语句实现代码描述,并且添加default选项,让状态机回到初始状态,防止出现锁存状态;

b. 为了能综合出有效地电路,状态机中必须明确的由唯一时钟触发,即同步状态机;

c. 状态机应该有一个同步或异步复位端,推荐使用异步复位端;

d. 在设置编码状态的名称时,要按相应的功能命名,方便代码理解与维护。

.

.

.

四、task和function说明语句

1)任务和函数的不同点:

a. 任务可以调取其它的任务或函数,函数不能调取任务;

b. 任务可以具有自己的仿真时间,但是函数只能和主module的仿真时间相同;

c. 任务可以有任何类型的变量或者没有,但是函数至少有一个输入变量;

d. 任务不返回值,只是执行某操作,而函数有返回值。

2)task的说明

a. 任务的定义:

b4d7f74425f5f74a1f52b7280be7aeb4.png

b. 任务的调用:

直接在需要执行任务中的功能的地方写上任务名即可,如果有端口,把端口写上:

<任务名>(端口1,端口2,…,端口n);

下面是一个具体的例子用来说明怎样在模块的设计中使用任务,使程序容易读懂:

ff8e84b8fb7439442edadd0bdf6d8f86.png

这个例子描述了一个简单的交通灯的时序控制,并且该交通灯有它自己的时钟产生器。

3) function说明语句

函数的目的是返回一个用于表达式的值。

a. 定义函数的语法:

731e953d31b6c8d495c824842918f055.png

其中<返回值的类型或范围>可以缺省,缺省状态下默认为一位的寄存器类型。例子如下所示:

4d5f83811edf34f68330e970f63cf42f.png

从上例子中可以看出,函数的返回值就是函数名,函数名同时代表着一个寄存器,此寄存器的类型或范围与定义的<返回值的类型或范围>相同。

b. 函数的调用

函数的调用是通过将函数作为表达式中的操作数来实现的。

其调用格式如下:

<函数名> (<表达式>,<表达式>)

其中函数名作为确认符。

下面这句表达式调用了getaddr函数实现地址高低位拼接功能。

72043c090a725bd5de0b025670c69636.png

c. 函数的使用规则

除了前面与任务比较时提到的函数规则之外,另添加如下两条:

函数的定义不能包含有任何的时间控制语句,即任何用#、@、或wait来标识的语句。

在函数的定义中必须有一条赋值语句给函数中的一个内部变量(即函数名)赋以函数的结果值。

d. 举例说明

下面的例子中定义了一个可进行阶乘运算的名为fact的函数,该函数返回一个32位的寄存器类型的值,该函数可后向调用自身,并且打印出部分结果值。

189b19685391d6c127fc879ef1d898d6.png

dde2ce036e7bc2f83aa49f641a66e131.png

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值