文档库 最新最全的文档下载
当前位置:文档库 › 设计与验证:Verilog HDL 学习笔记

设计与验证:Verilog HDL 学习笔记

连接操作符:
{m,n} :将m和n连接起来,产生更大的向量
{n{m}} :将m重复n次

-----------------------------------------------
P36:基数格式的整数为无符号数,如-4'd12=4294967284, 把-12的二进制数看成了无符号数。

-----------------------------------------------
由于连续赋值语句中被赋值的变量在仿真器中不会存储其值,因此该变量是线网类型
(Net) 的,而不是寄存器类塑的。
另外,线网类型的变量可以被多重驱动,也就是说可以在多个连续赋值语句中驱动同一
个线网。
但是寄存器变量就不同了,它不能被不同的行为进程(例如always 语句块)驱动。

-----------------------------------------------
建议使用asslgn 对组合逻辑建模,这是因为assign 语句的连续驱动特点与组合逻辑的行
为非常相似,而且在assign 语句中加延时可以非常精确地模拟组合逻辑的惯性延时。

----------------------------------------------
需要注意的是,连续赋值语句中的延时具有硬件电路中惯性延时的特性,也就是说任何
小于其延时的信号变化脉冲将被滤除掉,不会体现在输出端口「。关于这部分内容将在本书
第8 章中详细介绍。
另外. assign 语句中的延时特性通常是被逻辑综合工具忽略的,因为综合工具要将
Verilog 语言模塑综合成逻辑电路,而逻辑电路的延时又是由基本的单元库和走线延时决定
的。用户无法对逻辑单元指定延时,但是可以在综合和实现工具中添加时序约束,让工具尽
量满足设计的时序要求。

-----------------------------------------------
RTL 仿真器严格按照Verilog 的仿真语义执行RTL 的仿真过程,而综合工具通常只是根
据代码推断设计者的意图,然后生成相应的电路结构,因此,综合的过程有一定的主观推断
性,并不严格遵守Verilog 语义,另外不同综合工具的判决标准也不一样。
如果仿真和综合结果不一致,就说明源代码中很可能存在隐患,不符合Verilog 的语
义,会错过许多bug ,增加设计的不稳定性,这种情况是每个设计都应该尽量避免的。

-----------------------------------------------
三、过程连续赋值
在Verilog 语言中还有一种过程赋值语句,叫作"过程连续赋值"它们也出现在always
和initial 语句块中。
过程连续赋值的类型主要有以下两种。
1 assign 与deassign: 在过程语句块中强制为寄存器变量赋值并释放;
2 force 与release: 在过程语句块中对寄存器和线网进行强制赋值和释放。

--------------------------------------------------
三、语旬组的标识符
语句组既可以有标识符,也可以没有标识符。
当→个语句组有标识符时,在语句组内部可以定义局部变量,而不会传递到语句组的外
部。然而

在仿真语义上,这个变量是静态变量,它的值在整个仿真运行周期中是不变的,而
且也不会与其他语句组中同一个名称的变量发生冲突。
例如:
integer i; //always 语旬以外的i 变量
always @ (_..)
begin: SORT
inteqer i; //语句组内部的主变量
for (i=0;i<=7;i=i+1)
end
在always 以外定义的i 变量和在always 里面定义的i 变量属于两个不同的变量,并不
冲突。在仿真的时候它们将占用两块不同的内存,类似于C 语言中的静态局部变量。

----------------------------------------------------
在l~例中实际t使用了if-else 优先级编码的特点, sela 的判断优先级最高,因此在逻辑
中的级数要明显少→些,参考图3-11 。如果sela 为关键路径的话,就可以利用这样的优先
级编码提高设计的性能。
在使用i f.. .else 语句时,尤其是当该语句被用在组合逻辑中时,需要注意不要引入
Latch 电路。
在数字同步逻辑设计中应该尽量避免产生锁存器,肉为锁存器容易引起竞争冒险,同时
静态时序分析工具也很难分析穿过锁存器的路径。

----------------------------------------------------
参数化模块
参数的用户定制方法有以下两种:
1. 通过defparam 关键宇重新定义模块中的参数:

altsyncram component 是实例名称" "后面是参数的名称" "后面是被重新定义的
参数值,有的是字符串,有的是整数。
defparam 关键字后面是参数重定义语句:
altsyncram_compo口ent.width a 8 , //8 位宽的数据
其结果是将"altsyncram_component" 中的参数"width a" 重新定义为8 。
使用defparam 的方法重新定义参数时,可以根据需要重新定义部分参数,而其他参数
将保留缺省值。

2. 直接在实例化模块时代入参数。
格式: 模块名 #(参数1,参数2,...) 实例名(输入输出端口表);
使用上面这种参数直接代入法时需要注意一点,即所有的参数都要按顺序列出来,不能
遗漏,也不能颠倒顺序,否则就会对应不上。

-----------------------------------------------------
所谓寄存器传输级(RTL 级)就是在描述电路的时候,只需要关注寄存器本身,以及
寄存器到寄存器之间的逻辑功能,而不用关心寄存器和组合逻辑的实现细节(具体用了多少
逻辑门等)。
Verilog 设计中最常用的设计层次就是RTL 级。在RTL 描述时,设计者需要关注寄存器
的行为,其中保存着数据:同时需要关注寄存器和寄存器之间的组合逻辑功能是否能满足功
能需求和时序需求。RTL 级模型是严格精确到时钟周期的模型。

----------------------------------------------------
"cnt = cnt + 1" 这样会产组合逻辑环。
组合逻辑环是同步时序逻辑设计中要尽量避免的设计方式。它会使得时序
路径无法被工具所分

析,不同芯片的延时不同,会造成逻辑功能不稳定.有些已经完成很
久的设计,在换了芯片批次后,逻辑功能不正确,大多数都是由组合逻辑环造成的.

---------------------------------------------------
同时使用时钟上升沿和下降沿的问题: 有时因为数据采样或调整数据相位等
需求,设计者会在一个always 的敏感表中同时使用时钟的posedge 和
negedge ,或者在两个always 的敏感表中分别使用时钟的posedge 和negedge ,
对某些寄存器电路进行操作(在这两种描述下,当时钟上升沿或时钟下降沿到
达时,该寄存器电路都会做相应的操作. 这个双沿电路往往可以等同于使用了
原时钟的倍频时钟的单沿操作电路).对于PLD 设计而言,不推荐同时使用时
钟的上升沿、下降沿,因为PLD 内嵌的PLLIDLL 和一些时钟电路往往只能对
时钟的一个沿保证非常好的指标,而另一个沿的抖动、偏斜、斜率等指标不见
得非常优化,有时同时使用时钟的正、负沿会因时钟的抖动、偏斜、占空比、
斜率等问题而造成一定的性能恶化.因此笔者推荐的做法是,将原时钟通过
PLLIDLL 倍频,然后使用倍频时钟的单沿(如上升沿)进行操作.

通过这个例子说明某些使用双沿操作的电路等价于使用倍频时钟的单沿电路,也就是
说,这些电路使用了时钟的双沿触发寄存器,则相当于提高了设计频率,提高了设计要求的
时序难度。对于这些电路,在附加时序约束和进行时序分析时一定要考虑充分。

-----------------------------------------------------
4.3.4 双向端口与三态信号建模
前面谈到的双向总线(既做输入又做输出的总线)应该在顶层模块中实例化三态信号,
而不能在顶层以外的其他子层次中实例化三态信号。某些早期的EDA 软件和器件支持在子
模块中定义双向总线,实例化三态信号。其实从理论七讲,任何子模块中定义的三态信号都
可以迁移到顶层中。实际t二,很多综合工具也默认将子模块中定义的三态信号综合为选择
器,并将子模块中三态信号的实例化迁移到顶层模块中去。
为了避免仿真和综合实现的结果不一致,并且为了便于维护,笔者强烈建议仅在顶层定
义双向总线和实例化的三态信号,禁止在除顶层以外的其他层次赋值高阻态"z" ,在顶层
将双向信号分为输入信号和输出信号两种类型,然后根据需要分别传递到不同的子模块中。
这样做的另一个好处在于便于描述仿真激励。

-----------------------------------------------------
Verilog 语法中基本的存储单元定义格式如下。
reg [datawidth] MemoryName [addresswidth];
例如定义一个数据位宽为他ít ,地址为63 位的RAM8x64 ,则可定义为:
reg [7 0] RAM8x64 [

0 63];
在使用存储单元时,不能直接引用存储器某地址的某比特位值,如想对地址为"32 "的
第2bit 和高2bit 的值进行操作,则下面这两种描述都是错误的。
RAM8x64 [32] [2]
RAM8x64 [32] [6:7]
正确的操作方法是,先将存储单元赋值给某个寄存器,然后在对该寄存器的某位进行相
关操作,如下例所示。

--------------------------------------------------------
上面讲解的仅仅是Verilog 语法建模存储单元的→般方法。而对于PLD 设计而言,由于
儿乎所有的FPGA 都内嵌有RAM 资源,所以并不推荐使用Verilog 直接建模RAMo FPGA
内嵌的RAM 资源大致分为两类:块RAM (Block RAM) 资源和分布式RAM 资源
(Distributed RAM ,是一种基于特殊底层逻辑单元,通过查找表和触发器实现的RAM 结
构)。在PLD 中使用存储结构的基本方法如下。
? 第一种方法:通过器件商的开发平台中内嵌的IP 生成器,在图形化界面中直
接选择存储器类型(如双口RAM 、单口也气M 、ROM 和分布式此也M 等),配
置存储器参数,生产相应IP ,然后在用户逻辑中直接调用该IP 。这种设计方
法是PLD 设计中推荐的方法,因为器件商最了解PLD 的底层硬件结构,通过
IP 生成器,可以自动地选择使用PLD 内嵌的R灿4 资源,并生成存储器的粘
合逻辑( glue logic ),方便、高效、可靠。
? 第二种方法:直接根据上面的描述用Verilog 语言建模存储器,由综合器根据
代码描述类推并优化存储器结构,调用器件内嵌的硬件存储器资源。这种方法
有两个问题,一是要清晰合理地在代码中描述存储器,有一定的设计难度;二
是最终实现的结果在很大的程度上取决于综合器的类推算法,有一定的不确定
性。这种方法经常用在两个场合,一是PLD 本身没有块RAM 或分布式RAM
等专用存储单元(如CPLD 等);二是用户非常熟悉综合器的类推算法,并能
通过综合器的相关约束属性,指定所需使用的底层硬件RAM 资源。

---------------------------------------------------------------
【例4-14 】将'个200kHz 时钟做2 分频、4 分频、8 分频,要求分频后的3 个时钟同
相,而且与源时钟近似同相。在这个设计中,因为输入时钟速率很低,仅有
200KHz ,而)般PLD 内嵌的PLL 的输入频率下限都在MHz级,所以无法使
用PLL 完成分频与相位调整要求。另外对于低速时钟的分颇,使用计数器既
能满足时序要求,也比较节约器件资源,代码参见随书光盘中"
reg [2: O] cnt;
always @ (posedge clk_200K or negedge rst)
if (!rst)
cnt <= 3'bOOO;
else
cnt <= cnt + 1;
assign clk_100K = ~cnt[0];
assign clk_50K =~cnt[1];
assign c1k_25K =~cnt[2];
这个设计的难点在于如何调整所有时钟的相位关系。本例巧妙地通过对计数器每个bit
的反向

处理,完成了所有分频后时钟的相位调整,保证了3 个分频后时钟的相位严格同相。
这3 个派生时钟与源时钟相比有一个非常小的相位差,这个相位差是由寄存器的固有Tco
(Clock to OUtput 延时)和计数器累加的组合逻辑造成的。→般来说在PLD 中寄存器固有
Tco 的典型值为1 ~2ns ,而简单加法运算的组合逻辑门延时也约为ns 级,这两个延时的总
和与时钟周期相比微乎其微。如果忽略这个ns 级的延时,则可以认为通过每个分频时钟的
反向,使3 个分频时钟与源时钟同相,也就是说这4 个时钟拥有共同的上升沿。



相关文档