当前位置:文档之家› 我的Verilog学习笔记..

我的Verilog学习笔记..

Verilog学习笔记1.我的第一个verilog程序:三态门module three_status_device(in,out,oe);input in,oe;output out;assign out = (oe)? in : 1'bz;endmodule其中oe为输出有效端,当oe置高则输入能顺利通过,否则输出高阻态。

查看Technology Schematic后可知three_status_device模块使用的FPGA内部资源:分别是输入缓冲器IBUF,非门INV和三态缓冲器OBUFT。

我们还可以通过View Synthesis Report来观察到底使用了多少资源:我们可以看出所选的芯片类型为V5系列的fx100,SPEED等级为-2,使用了1个查找表,1个Flip Flop触发器和3个IO口。

由于模块比较简单,我们直接进入后仿真阶段;最后,我们可以通过中的View HDL InstantiationTemplate看到生成的HDL模板供我们调用实例:three_status_device instance_name (.in(in),.out(out),.oe(oe));小结:通过设计三态门,熟悉了verilog开发的主要流程和ise中的常用工具。

反思:对于高阻态,一般FPGA内部是不支持判断的。

现在有些比较新的FPGA内部已经带有BUFT三态门让用户直接调用(在IOB中),而对于市面上常用的FPGA则无法做到,因为内部并没有BUFT三态门,所以就需要用到slice资源中的MUX复用器,用MUX除了多占用LC/LE的资源以外,受控信号(如数据总线等)会随着驱动源的增加而使延时加大。

也有说法是使用RAM或ROM的总线结构提供高阻态的输出。

在FPGA开发时,一般将不用的IO口设置为三态状态,如果IO口较多的时候既占用连线资源也占用slice资源,对系统产生延迟。

2.组合逻辑:有毛刺怎么办?引用《数字电路基础》的描述,当一个逻辑门的两个输入端的信号同时向相反方向变化,而变化的时间有差异的现象,称为竞争。

由竞争而可能产生的输出干扰脉冲的现象就叫做冒险,也就是通俗上说的毛刺。

书上还给出了常用的消除竞争冒险的方法:○1消除互补相乘项:通过人为优化逻辑表达式,消去同一信号的同反相同时存在项,降低竞争的发生几率。

○2增加乘积项避免互补项相加:若组合逻辑表达式中,在某些信号取一定值的情况下,表达式可化为一个信号的同反相同时相乘或相加时,则需要人为加入相乘项以确保此时输出状态的稳定。

那么在verilog如何实现消除毛刺呢?信号在fpga器件中通过逻辑单元连线时,一定存在延时。

延时的大小不仅和连线的长短和逻辑单元的数目有关,而且也和器件的制造工艺、工作环境等有关。

因此,信号在器件中传输的时候,所需要的时间是不能精确估计的,当多路信号同时发生跳变的瞬间,就产生了“竞争冒险”。

这时,往往会出现一些不正确的尖峰信号,这些尖峰信号就是“毛刺”。

另外,由于fpga以及其它的cpld器件内部的分布电容和电感对电路中的毛刺基本没有什么过滤作用,因此这些毛刺信号就会被“保留”并传递到后一级,从而使得毛刺问题更加突出。

尽管毛刺持续时间很短,但在高速电路中,这样的毛刺足以使后一级电路产生“误动作”。

要消除毛刺,我们先要了解FPGA内部毛刺的具体特点:由于布线延迟,和器件延迟,取决于FPGA内部结构,这个涉及到约束问题,/shineboy19850420/blog/09-10/178252_efbd3.html,由于接触不多,不在此进行讨论。

通过阅读资料,可以知道大多数毛刺都比较短(大概几个纳秒),只要毛刺不出现在时钟跳变沿,毛刺信号就不会对系统造成危害。

FPGA中消除毛刺的常用方法是:1.触发器输出通过添加触发器,使输出信号在clk跳变沿进行读取,并输出,能有效地降低毛刺的发生几率。

但这样的话,延时也就增大。

但是,毛刺的产生是不定时的,如果毛刺在时钟跳变时期产生,则使用触发器的方法无法解决问题。

2.信号延时法信号延时法,顾名思义,延时信号处理时期,等待信号稳定时再对数据进行处理。

它的具体做法有很多:○1信号延时检测信号延时方法很多,如使用门级电路延时,fpga的专用延时单元lcell,毛刺的产生随机性,单凭延时是无法解决问题的。

○2时钟延时像使用触发器的原理类似,通过增加时钟计数器,对时钟进行分频,加大时钟间隔,来保证对信号进行处理的时候信号已经稳定;或者为防止在信号检测时钟跳变时,信号发生变化,延时对信号检测时间,比如加入标志位寄存器,信号跳变后的下一个检测时钟对其检测。

这针对检测时期瞬变信号导致检测错误的方法。

○3状态机检测使用状态机对信号进行多次检测,首先第一次检测信号,进入下一状态,再次检测信号并与前面进行比较,如果不同则重新开始检测知道检测一定次数后确定信号不变动后,进行数据处理。

这种方法结合了上述方法,极好地消除了竞争冒险。

信号延时法缺点是用速度换取电路的稳定性,我们只能择优而取。

下面我们来看一些例子:按照设想out=abc+bde;其时序图要求如下:(用TimingDesigner画图)下面我们一一验证一下不同方法所实现的逻辑组合的效果。

//方法一,直接使用assign语句(数据流)assign out = a&b&c|d&e&b;类似的描述组合逻辑方法还有:always @ (a or b or c or d or e)begintemp1 = a&c|d&e; out = temp1&b;end wire temp1,temp2;and myand1(temp1,a,b,c); and myand2(temp2,d,e,b); or myor(out,temp1,temp2);由于表达式out=abc+bde可转换成out=b(ac+de),因此b的取值至关重要,当输入信号b变为0时,输出即变为0,所以上述语句一般写成:wire temp;assign temp = a&c|d&e;assign out = temp&b;这样一来,当b变为0,输出立即变化,这就是关键路径的选取。

关键路径所生成的RTL结构如下:与没有选取关键路径相比:由行为仿真波形可以看出,这样的逻辑设计与设想相同:我们通过修改仿真文件.twf 对某些输入信号进行人为的延时,观察加入延时后出来的效果:输入信号波形代码段均写在Initial段中:(我们就在这里修改),为了保持毛刺持续时间尽量满足实际情况(一般为十几ns)所以这里设置延时均为10ns,即在`timescale 1ns/1ps 情况下,使用#10;语句进行延时动作。

initial begin// ------------- Current Time: 490ns#490;a = 1'b1;b = 1'b1;c = 1'b1;d = 1'b1;// -------------------------------------// ------------- Current Time: 1090ns#600; a = 1'b0; c = 1'b0;#10; e = 1'b1;#10; b = 1'b0;// -------------------------------------// ------------- Current Time: 1690ns#600; b = 1'b1;#10; e = 1'b0;// -------------------------------------// ------------- Current Time: 2290ns#600; e = 1'b1;// -------------------------------------// ------------- Current Time: 2690ns#400; e = 1'b0;// -------------------------------------// ------------- Current Time: 3090ns#400; e = 1'b1;#10; b = 1'b0; c = 1'b1;// -------------------------------------// ------------- Current Time: 3690ns#600; b = 1'b1;#10; d = 1'b0;#10; a = 1'b1;// -------------------------------------end仿真出来的效果(毛刺出现了)可见,尽管做出了关键路径的选取,组合逻辑电路还是非常容易产生毛刺。

下面我们使用上面的说法,加入寄存器后观察结果。

reg out; wire temp;assign temp = a&b&c|d&e&b;always @ (posedge clk)out = temp;从RTL结构图中可以直观看到加入D触发器(即寄存器)输出:依旧采用改动后的仿真文件,所得出的仿真波形如下:可见,上面的毛刺完全被消除了,而且不留一点痕迹。

由于使用触发器免不了使用时钟,详细的使用放到后面的时序电路学习一节中。

小结:从本节中,实现了简单的逻辑组合,并透过阅读修改仿真文件,了解毛刺的产生;通过观察RTL结构图,了解到代码风格与生成的模型之间的联系,并通过使用D触发器消除毛刺。

反思:如果外部情况比较恶劣,延时级别大于ns级,或者输入信号的跳变在时钟跳变时期发生,会产生什么效果,这需要在后面的学习中逐步体会。

3.使用组合逻辑:加法器的设计一个设计,其实现方案多样,而且不同的实现方案,电路结构是不一样的,这将导致速度或使用资源的差异。

所以,在学习过程中,需要对不同的方法进行比较,了解各种编码风格实现的差别,对将来的系统设计有极大的帮助。

下面我们以加法器的设计为引导,延伸本节的讨论。

首先,我们要知道一个加法器模型应该有的端口,他们分别为:加数,被加数,上级进位,和,进位这几个端口。

注意verilog的编码规范,模块端口有高位至低位,从输出到输入进行描述:module adder(cout,sum,clk,rst,a,b,cin);(1)实现方法一assign { cout, sum } = a + b + cin;这样看来,加法器的实现非常简单,从结构上看,它直接调用了一个加法器(如图):但是对于“+”号的综合,FPGA内部是采用查找表所实现的,下面是由上述语句生成的二级查找表结构:(查找表的级数是延时的主要因素,降低查找表级数是代码优化的首要任务)其中LUT3_E8表示3输入查找表,E8指查找表内部真值表的结果值。

相关主题