Verilog学习笔记

Verilog学习笔记

本文根据学习菜鸟教程下Verilog教程总结得到,主要记载一些硬件语言描述下的骚操作,仅供学习。

归约操作符
归约操作符包括:归约与(&),归约与非( ~ &),归约或(|),归约或非(~ |),归约异或(^ ),归约同或(~^)。
归约操作符只有一个操作数,它对这个向量操作数逐位进行操作,最终产生一个 1bit 结果。
逻辑操作符、按位操作符和归约操作符都使用相同的符号表示,因此有时候容易混淆。
A = 4’b1010 ;
&A ; //结果为 1 & 0 & 1 & 0 = 1’b0,可用来判断变量A是否全1
~|A ; //结果为 ~(1 | 0 | 1 | 0) = 1’b0, 可用来判断变量A是否为全0
^A ; //结果为 1 ^ 0 ^ 1 ^ 0 = 1’b0

移位操作符
移位操作符包括左移(<<),右移(>>),算术左移(<<<),算术右移(>>>)。
移位操作符是双目操作符,两个操作数分别表示要进行移位的向量信号(操作符左侧)与移动的位数(操作符右侧)。
算术左移和逻辑左移时,右边低位会补 0。
逻辑右移时,左边高位会补 0;而算术右移时,左边高位会补充符号位,以保证数据缩小后值的正确性。
A = 4’b1100 ;
B = 4’b0010 ;
A = A >> 2 ; //结果为 4’b0011
A = A << 1; //结果为 4’b1000
A = A <<< 1 ; //结果为 4’b1000
C = B + (A>>>2); //结果为 2 + (-4/4) = 1, 4’b0001
具备数字芯片综合(SYN)/时序分析(STA)经验;
(3)了解芯片设计基本知识,如代码规范、工作环境和工具、典型电路(异步、状态机、FIFO、时钟复位、memory、缓存管理等);
(4)接触过多种验证工具,了解一种或多种验证方法,并根据项目的特点制定不同的验证策略、方案,搭建验证环境,完成验证执行和Debug。

在编译过程中,timescale 指令会影响后面所有模块中的时延值,直至遇到另一个 timescale 指令或 resetall 指令。
由于在 Verilog 中没有默认的 timescale,如果没有指定 timescale,Verilog 模块就有会继承前面编译模块的 timescale 参数。有可能导致设计出错。
如果一个设计中的多个模块都带有 timescale 时,模拟器总是定位在所有模块的最小时延精度上,并且所有时延都相应地换算为最小时延精度,时延单位并不受影响。

全加器
下面采用数据流描述方式,来设计一个 1bit 全加器。
设 Ai,Bi,Ci 分别为被加数、加数和相邻低位的进位数,So, Co 分别为本位和与向相邻高位的进位数。
真值表如下:
在这里插入图片描述
全加器的表达式为:

So = Ai ⊕ Bi ⊕ Ci ;
Co = AiBi + Ci(Ai+Bi)
RTL代码如下:
module full_adder1(
input Ai, Bi, Ci,
output So, Co);
assign So = Ai ^ Bi ^ Ci ;
assign Co = (Ai & Bi) | (Ci & (Ai | Bi));
endmodule

automatic 函数
在 Verilog 中,一般函数的局部变量是静态的,即函数的每次调用,函数的局部变量都会使用同一个存储空间。若某个函数在两个不同的地方同时并发的调用,那么两个函数调用行为同时对同一块地址进行操作,会导致不确定的函数结果。
Verilog 用关键字 automatic 来对函数进行说明,此类函数在调用时是可以自动分配新的内存空间的,也可以理解为是可递归的。因此,automatic 函数中声明的局部变量不能通过层次命名进行访问,但是 automatic 函数本身可以通过层次名进行调用。
下面用 automatic 函数,实现阶乘计算:
Verilog实现阶乘
wire [31:0] results3 = factorial(4);
function automatic integer factorial ;
input integer data ;
integer i ;
begin
factorial = (data>=2)? data * factorial(data-1) : 1 ;
end
endfunction // factorial

状态机

竞争与冒险
产生原因
数字电路中,信号传输与状态变换时都会有一定的延时。
在组合逻辑电路中,不同路径的输入信号变化传输到同一点门级电路时,在时间上有先有后,这种先后所形成的时间差称为竞争(Competition)。
由于竞争的存在,输出信号需要经过一段时间才能达到期望状态,过渡时间内可能产生瞬间的错误输出,例如尖峰脉冲。这种现象被称为冒险(Hazard)。
竞争不一定有冒险,但冒险一定会有竞争。
判断方法
1.代数法
在逻辑表达式,保持一个变量固定不动,将剩余其他变量用 0 或 1 代替,如果最后逻辑表达式能化简成
Y = A + A'Y = A · A'
的形式,则可判定此逻辑存在竞争与冒险。
例如逻辑表达式Y = AB + A'C,在 B=C=1 的情况下,可化简为 Y = A + A'。显然,A 状态的改变,势必会造成电路存在竞争冒险。
2.卡诺图法
有两个相切的卡诺圈,并且相切处没有其他卡诺圈包围,可能会出现竞争与冒险现象。
例如左下图所存在竞争与冒险,右下图则没有。
在这里插入图片描述
其实,卡诺图本质上还是对逻辑表达式的一个分析,只是可以进行直观的判断。
例如,左上图逻辑表达式可以简化为Y = A'B' + AC,当 B=0 且 C=1 时,此逻辑表达式又可以表示为Y = A' + A。所以肯定会存在竞争与冒险。
右上图逻辑表达式可以简化为 Y = A'B' + AB,显然 B 无论等于 1 还是 0,此式都不会化简成 Y = A' + A。所以此逻辑不存在竞争与冒险。
需要注意的是,卡诺图是首尾相临的。如下图所示,虽然看起来两个卡诺圈并没有相切,但实际上,m6 与 m4 也是相邻的,所以下面卡诺图所代表的数字逻辑也会产生竞争与冒险。
在这里插入图片描述
其他较为复杂的情况,可能需要采用 “计算机辅助分析 + 实验” 的方法。
消除方法
对数字电路来说,常见的避免竞争与冒险的方法主要有 4 种。

1)增加滤波电容,滤除窄脉冲
此种方法需要在输出端并联一个小电容,将尖峰脉冲的幅度削弱至门电路阈值以下。
此方法虽然简单,但是会增加输出电压的翻转时间,易破坏波形。
2)修改逻辑,增加冗余项
利用卡诺图,在两个相切的圆之间,增加一个卡诺圈,并加在逻辑表达式之中。
如下图所示,对数字逻辑 Y = A'B' + AC 增加冗余项 B’C,则此电路逻辑可以表示为Y = A'B' + AC + B'C。此时电路就不会再存在竞争与冒险。
在这里插入图片描述
3)使用时钟同步电路,利用触发器进行打拍延迟
同步电路信号的变化都发生在时钟边沿。对于触发器的 D 输入端,只要毛刺不出现在时钟的上升沿并且不满足数据的建立和保持时间,就不会对系统造成危害,因此可认为 D 触发器的 D 输入端对毛刺不敏感。 利用此特性,在时钟边沿驱动下,对一个组合逻辑信号进行延迟打拍,可消除竞争冒险。
延迟一拍时钟时,会一定概率的减少竞争冒险的出现。实验表明,最安全的打拍延迟周期是 3 拍,可有效减少竞争冒险的出现。
当然,最终还是需要根据自己的设计需求,对信号进行合理的打拍延迟。
4)采用格雷码计数器

小结
一般来说,为消除竞争冒险,增加滤波电容和逻辑冗余,都不是 Verilog 设计所考虑的。
计数采用格雷码计数器,大多数也是应用在高速时钟下减少信号翻转率来降低功耗的场合。
利用触发器在时钟同步电路下对异步信号进行打拍延时,是 Verilog 设计中经常用到的方法。

流水线
也许有人会问,直接用乘号 * 来完成 2 个数的相乘不是更快更简单吗?

如果你有这个疑问,说明你对硬件描述语言的认知还有所不足。就像之前所说,Verilog 描述的是硬件电路,直接用乘号完成相乘过程,编译器在编译的时候也会把这个乘法表达式映射成默认的乘法器,但其构造不得而知。

例如,在 FPGA 设计中,可以直接调用 IP 核来生成一个高性能的乘法器。在位宽较小的时候,一个周期内就可以输出结果,位宽较大时也可以流水输出。在能满足要求的前提下,可以谨慎的用 * 或直接调用 IP 来完成乘法运算。

但乘法器 IP 也有很多的缺陷,例如位宽的限制,未知的时序等。尤其使用乘号,会为数字设计的不确定性埋下很大的隐瞒。

很多时候,常数的乘法都会用移位相加的形式实现,例如:

实例
A = A<<1 ; //完成A * 2
A = (A<<1) + A ; //对应A * 3
A = (A<<3) + (A<<2) + (A<<1) + A ; //对应A * 15
用一个移位寄存器和一个加法器就能完成乘以 3 的操作。但是乘以 15 时就需要 3 个移位寄存器和 3 个加法器(当然乘以 15 可以用移位相减的方式)。

有时候数字电路在一个周期内并不能够完成多个变量同时相加的操作。所以数字设计中,最保险的加法操作是同一时刻只对 2 个数据进行加法运算,最差设计是同一时刻对 4 个及以上的数据进行加法运算。

如果设计中有同时对 4 个数据进行加法运算的操作设计,那么此部分设计就会有危险,可能导致时序不满足。

此时,设计参数可配、时序可控的流水线式乘法器就显得有必要了。
流水线乘法器实现
除法器实现
假设4bit的两数相除 a/b,商和余数最多只有4位 (假设1101/0010也就是13除以2得6余1)
我们先自己做二进制除法,则首先看a的MSB,若比除数小则看前两位,大则减除数,然后看余数,以此类推直到最后看到LSB;而上述算法道理一样,a左移进前四位目的就在于从a本身的MSB开始看起,移4次则是看到LSB为止,期间若比除数大,则减去除数,注意减完以后正是此时所剩的余数。而商呢则加到了这个数的末尾,因为只要比除数大,商就是1,而商0则是直接左移了,因为会自动补0。这里比较巧因为商可以随此时的a继续左移,然后新的商会继续加到末尾。经过比对会发现移4位后左右两边分别就是余数和商。

画个简单的图:
在这里插入图片描述
绝对值
求 dbin 的绝对值逻辑如下:

dbin_abs = (dbin[DW-1]? ~dbin : dbin) + 1’b1 ;
例如,4bit 数字 -6 的补码为 4’b1010,取反加 1 后的值为 4’b0110(6),即为 -6 的绝对值。

但如果 dbin 为正数,加 1 后的值比其真正的绝对值要大 1,此步操作只是为了让正数部分的绝对值数量与负数部分一致。因为一定位宽下,由于 0 值的存在,有符号数表示的负数数量会比正数多 1 个。

有符号数转无符号数
将有符号数扩展成为无符号数的逻辑如下:

dbin_unsigned = {!dbin[DW-1], dbin[DW-2:0]) ;
例如:

4’b1010 (-6) -> 4’b0010 (2),4’b0010 (2) -> 4’b1010 (10)
其实转换原则是将数据代表的数值范围移动到 0 以上,有符号数转换成无符号数之后,数据相对间的差并没有改变。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值