配色: 字号:
FPGA入门教程
2012-02-20 | 阅:  转:  |  分享 
  




FPGA入门教程









1.数字电路设计入门

2.FPGA简介

3.FPGA开发流程

4.RTL设计

5.QuartusⅡ设计实例

6.ModelSim和Testbench















1.数字电路设计入门

1.1数字电路设计

数字电路设计的核心是逻辑设计。通常,数字电路的逻辑值只有‘1’和‘0’,表征的是模拟

电压或电流的离散值,一般‘1’代表高电平,‘0’代表低电平。

高低电平的含义可以理解为,存在一个判决电平,当信号的电压值高于判决电平时,我

们就认为该信号表征高电平,即为‘1’。反之亦然。

当前的数字电路中存在许多种电平标准,比较常见的有TTL、CMOS、LVTTL、LVCMOS、

ECL、PECL、LVDS、HSTL、SSTL等。这些电平的详细指标请见《补充教程1:电平标准》。

数字电路设计大致可分为组合逻辑电路和时序逻辑电路。

一般的数字设计的教材中对组合逻辑电路和时序逻辑电路的定义分别为:组合逻辑电

路的输出仅与当前的输入有关,而时序逻辑电路的输出不但与输入有关,还和系统上一个

状态有关。

但是在设计中,我们一般以时钟的存在与否来区分该电路的性质。由时钟沿驱动工作

的电路为时序逻辑电路。大家注意,这两种电路并不是独立存在的,他们相互交错存在于整

个电路系统的设计中。

1.1.1组合逻辑电路

组合逻辑电路由任意数目的逻辑门电路组成,一般包括与门、或门、非门、

异或门、与非门、或非门等。一般的组合逻辑电路如下图:







其中A,B,C,D,E,F为输入,G为输出。





1.1.2时序逻辑电路

时序逻辑电路由时钟的上升沿或下降沿驱动工作,其实真正被时钟沿驱动的是电路中的

触发器(Register),也称为寄存器。触发器的工作原理和参数如下图:

Register的原理和参数

D

Clk

Q

D

Q

Clk

t

c-q

t

hold

T

t

su

tsu:建立时间,在时钟有效沿到来之前触发器数据输入应保持稳定的时间,如果建立时

间不够,数据将不能在这个时钟沿被打入触发器。它间接约束了组合逻辑的最大延时。

thold:保持时间,在触发器数据输入引脚的数据在系统有效时钟沿到来后,需要保持稳

定的时间,如果保持时间不够,数据同样不能被打入触发器。它间接约束了组合逻辑的最

小延时.

tc-q:触发器从有效时钟沿到来到输出有效的最大时间。

下面是两个简单的时序逻辑电路例子:

(1)、时钟分频电路



该时序电路的功能为实现对时钟’clk’的4分频,其中’clk_2’为2分频时钟,’clk_4’为4

分频时钟,’enable’为该电路的使能信号。其功能仿真波形如下图所示:

(2)、序列检测器

该时序电路实现了一个序列检测器,当输入序列‘datain’中出现‘101’时,标志位F将输

出‘1’,其他时刻输出‘0’。电路中‘clk’为时钟信号,‘D1’,‘D2’,‘D3’为移位寄存器的输出,’enable’

为该电路的使能信号。其功能仿真波形如下图所示:

可见,时序电路设计的核心是时钟和触发器,这两者也是我们设计电路时需重点关注的。

1.2毛刺的产生与消除

1.2.1竞争与冒险

当一个逻辑门的输入有两个或两个以上的变量发生改变时,由于这些变量是经过不同路

径产生的,使得它们状态改变的时刻有先有后,这种时差引起的现象称为竞争(Race)。竞

争的结果将很可能导致冒险(Hazard)发生(例如产生毛刺),造成错误的后果,并影响系

统的工作。

组合逻辑电路的冒险仅在信号状态改变的时刻出现毛刺,这种冒险是过渡性的,它不会

使稳态值偏离正常值,但在时序电路中,冒险是本质的,可导致电路的输出值永远偏离正常

值或者发生振荡。

避免冒险的最简单的方法是同一时刻只允许单个输入变量发生变化,或者使用寄存器采

样的办法。

1.2.2毛刺的产生与危害

信号在FPGA器件中通过逻辑单元连线时,一定存在延时。延时的大小不仅和连线的长

短和逻辑单元的数目有关,而且也和器件的制造工艺、工作环境等有关。因此,信号在器件

中传输的时候,所需要的时间是不能精确估计的,当多路信号同时发生跳变的瞬间,就产生

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

让我们来具体看一下毛刺是如何产生的。下图是一个与门电路,

我们期望的设计是,a和b信号同时变化,这样输出OUT将一直为0,但是实际中OUT

产生了毛刺,它的仿真波形如下所示:



可见,即使是在最简单的逻辑运算中,如果出现多路信号同时跳变的情况,在通过内部

走线之后,就一定会产生毛刺。而现在数字电路设计中的信号往往是由时钟控制的,如果将

带有毛刺的输出信号直接连接到时钟输入端、清零或置位端口的设计,可能会导致严重的后

果;此外对于多数据输入的复杂运算系统,每个数据都由相当多的位数组成。这时,每一级

的毛刺都会对结果有严重的影响,如果是多级的设计,那么毛刺累加后甚至会影响整个设计

的可靠性和精确性。

判断一个逻辑电路在某些输入信号发生变化时是否会产生毛刺,首先要判断信号是否会

同时变化,然后判断在信号同时变化的时候,是否会产生毛刺,这可以通过逻辑函数的卡诺

图或逻辑函数表达式来进行判断。

1.2.3毛刺的消除



毛刺是数字电路设计中的棘手问题,它的出现会影响电路工作的稳定性、可靠性,严重

时会导致整个数字系统的误动作和逻辑紊乱。

可以通过以下几种方法来消除毛刺:

1、输出加D触发器

这是一种比较传统的去除毛刺的方法。原理就是用一个D触发器去读带毛刺的信号,

利用D触发器对输入信号的毛刺不敏感的特点,去除信号中的毛刺。在实际中,对于简单

的逻辑电路,尤其是对信号中发生在非时钟跳变沿的毛刺信号,去除效果非常的明显。

但是如果毛刺信号发生在时钟信号的跳变沿,D触发器的效果就没有那么明显了(加D

触发器以后的输出q,仍含有毛刺)。另外,D触发器的使用还会给系统带来一定的延时,

特别是在系统级数较多的情况下,延时也将变大,因此在使用D触发器去除毛刺的时候,

一定要视情况而定,并不是所有的毛刺都可以用D触发器来消除。

2、信号同步法

设计数字电路的时候采用同步电路可以大大减少毛刺。由于大多数毛刺都比较短(大

概几个纳秒),只要毛刺不出现在时钟跳变沿,毛刺信号就不会对系统造成危害了。因此一

般认为,只要在整个系统中使用同一个时钟就可以实现系统同步。但是,时钟信号在FPGA

器件中传递时是有延时的,我们无法预知时钟跳变沿的精确位置。也就是说我们无法保证在

某个时钟的跳变沿读取的数据是一个稳定的数据,尤其是在多级设计中,这个问题就更加突

出。因此,做到真正的"同步"就是去除毛刺信号的关键问题。所以同步的关键就是保证在时

钟的跳变沿读取的数据是稳定的数据而不是毛刺数据。以下为两种具体的信号同步方法。

(1)信号延时同步法

信号延时法,它的原理就是在两级信号传递的过程中加一个延时环节,从而保证在下一

个模块中读取到的数据是稳定后的数据,即不包含毛刺信号。这里所指的信号延时可以是数

据信号的延时,也可以是时钟信号的延时。

(2)状态机控制

使用状态机也可以实现信号的同步和消除毛刺的目的。在数据传递比较复杂的多模块系

统中,由状态机在特定的时刻分别发出控制特定模块的时钟信号或者模块使能信号,状态机

的循环控制就可以使得整个系统协调运作,同时减少毛刺信号。那么只要我们在状态机的触

发时间上加以处理,就可以避免竞争冒险,从而抑制毛刺的产生。

3、格雷码计数器

对于一般的二进制或十进制计数器,在计数时,将有多位信号同时跳变。例如一个3bit

二进制计数器,由’111’转换为’000’时,必将产生毛刺。此时,使用格雷码计数器将避免毛

刺的出现,因为格雷码计数器的输出每次只有一位跳变。

其他关于毛刺的详细讨论,请见补充教程2:关于毛刺问题的探讨。



1.3同步电路设计

同步电路是指所有电路在同一个公共时钟的上升沿或下降沿的触发下同步地工作。但在

实际系统中,往往存在多时钟域的情况,这时同步的概念有所延伸,不再专指整个设计同步

于同一时钟沿,而是指设计应该做到局部同步,在每个时钟域内的电路要同步于同一时钟沿。

1.3.1同步电路设计的优点:

1.同步设计能有效地避免毛刺的影响,使得设计更可靠;

2.同步设计易于添加异步复位reset,以使整个电路有一个确定的初始状态;

3.同步设计可以减小环境对芯片的影响,避免器件受温度,电压,工艺的影响;

4.同步设计可以使静态时序分析变得简单和可靠;

5.同步设计可以很容易地组织流水线,提高芯片的运行速度。

1.3.2同步电路的设计准则:

1.尽可能在设计中使用同一时钟,时钟走全局时钟网络。走全局时钟网络的时钟是

最简单、最可预测的时钟,它具有很强的驱动能力,可以驱动FPGA内部中的所有触发器,

并保证Clockskew可以小到忽略的地步。

2.避免使用混合时钟沿采样数据,即避免在设计中同时使用时钟的上升沿和下降沿。

3.尽量少在模块内部使用计数器分频所产生的时钟。计数器分频时钟需完成的逻辑

功能完全可由PLL锁相环或时钟使能电路替代。计数器分频时钟的缺点是使得系统内时钟

不可控,并产生较大的Clockskew,还使静态时序分析变得复杂。

4.避免使用门控时钟。因为经组合逻辑产生的门控时钟极可能产生毛刺,使D触发

器误动作。

5.当整个电路需要多个时钟来实现,则可以将整个电路分成若干局部同步电路(尽

量以同一个时钟为一个模块),局部同步电路之间接口当作异步接口考虑,而且每个时钟信

号的时钟偏差(△T)要严格控制。

6.电路的实际最高工作频率不应大于理论最高工作频率,留有设计余量,保证芯片

可靠工作。

7.电路中所有寄存器、状态机在系统被reset复位时应处在一个已知的状态。

关于同步电路设计中的其他问题请详见补充教程3:华为同步电路设计规范。

1.3.3关于时钟设计的讨论

目前的工程设计中一般使用同步时序电路来完成整个系统的设计,由上一节可见,时钟

在同步电路设计中起着至关重要的作用。那么,我们在设计时首先要完成的是对时钟的设计。

如今在设计中常见的时钟类型包括:全局时钟、内部逻辑时钟和门控时钟。

1.全局时钟

全局时钟即同步时钟,它通过FPGA芯片内的全局时钟布线网络或区域时钟网络来驱

动,全局时钟具有高扇出、高精度、低Jitter和低Skew的特点,它到芯片中的每一个寄存

器的延迟最短,且该延迟可被认为是固定值。所以我们推荐在所有的设计中的时钟都使用全

局时钟。全局时钟的设计有以下几种方法:

(1).由PLL锁相环来产生全局时钟。

(2).将FPGA芯片内部逻辑产生的时钟分配至全局时钟布线网络。

(3).将外部时钟通过专用的全局时钟输入引脚引入FPGA。

在我们的设计中,一般推荐电路中的所有的时钟都由PLL锁相环产生。一方面,PLL

锁相环可实现倍频和移相的操作,使我们很方便地获得所需频率和相位的时钟;另一方面,

PLL锁相环默认将其驱动的时钟分配至全局时钟网络或区域时钟网络,Jitter和Skew都很小。

下图取自我们项目中的一个PLL锁相环设计,该PLL用于驱动DDR的接口模块。因为

功能所需,DDR接口需要三个133MHz的时钟,相位分别是‘-90’、‘0’、‘-180’,图中所示

即为该时钟的产生模块。我们使用QuartusⅡ的Megawizard生成PLL锁相环的IPcore。其

中‘inclk_66’为PLL锁相环的输入时钟,由外部的66MHz晶振提供,经过PLL倍频和移相

后得到所需的三个全局时钟。

ooo



2.内部逻辑时钟

内部逻辑时钟即指由芯片内部的组合逻辑或计数器分频产生的时钟。

对于组合逻辑时钟,特别是由多级组合逻辑产生的时钟,是要被严格禁止使用的,因

为一方面组合逻辑极容易产生毛刺,特别是对多级组合逻辑;另一方面组合逻辑电路的Jitter

和Skew比较大,这将恶化时钟的质量。所以,一般组合逻辑产生的内部时钟仅仅适用于时

钟频率较低、时钟精度要求不高的情况。

对于计数器分频产生的时钟,也应该尽量少地使用,因为这种时钟会带来比较大的延

迟,降低设计的可靠性,也使得静态时序分析变得复杂。计数器分频时钟需完成的逻辑功能

完全可由PLL锁相环或时钟使能电路替代。

还有一种由触发器产生的时钟—行波时钟,即一个触发器的输出用作另一个触发器的

时钟输入。文中1.1.2节描述的时钟分频电路就是一种行波时钟。因为各触发器的时钟之间

产生较大的时间偏移,很容易就会违反建立时间、保持时间的要求,导致亚稳态的发生。所

以,这种行波时钟要被严格禁止使用。

3.门控时钟

一般情况下,应该避免使用门控时钟。因为经组合逻辑产生的门控时钟极可能产生毛

刺,对系统造成很大危害。但对于某些功耗很大的系统而言,需要使用门控时钟来降低功耗。

我们推荐使用右图中描述的门控时钟的设

计,该设计一般不会产生毛刺和亚稳态的问题。

因为触发器避免了毛刺的产生,而亚稳态只可能

出现在源时钟的下降沿,但是随后它与源时钟低

相位相与,最后不会产生影响。

D

source_clk

clk_en

gated_clk

qout

source_clk

clk_en

qout

gated_clk

门控时钟最好只在顶层模块中出现,并将其分离到一个在顶层的独立模块中。这同时保

证了底层的每个模块有单一的时钟,且在本模块中的时钟不进行门控。

在补充教程4和补充教程5中,我们对时钟和时序的设计进行了更详细的讨论。

1.3.4亚稳态

在同步电路或异步电路中,如果触发器的setup时间或hold时间不能得到满足,就可

能产生亚稳态,此时触发器输出端Q在有效时钟沿之后比较长的一段时间处于不确定的状

态,在这段时间里Q端将会产生毛刺并不断振荡、最终固定在某一电压值上,此电压值并

不一定等于原来数据输入端D

的值。这段时间称为决断时间

(resolutiontime)。经过决断

时间之后,Q端将稳定到0或

1上,但是究竟是0还是1,

这是随机的,与输入没有必然

的关系。

亚稳态的危害主要体

现在破坏系统得稳定性上,由于输出在稳定下来之前可能是毛刺、振荡、固定的某一电压值,

因此亚稳态除了导致逻辑误判之外,严重情况下输出0~1之间的中间电压值还会使下一级

产生亚稳态(即导致亚稳态的传播)。逻辑误判将导致功能性错误,而亚稳态的传播则扩

大了故障面,严重时将导致系统崩溃。

在异步时序电路中更容易发生亚稳态,因为异步电路一般具有多个时钟域,数据在两个

时钟域间传递时,非常容易导致setup时间或hold时间不满足而发生亚稳态。在同步时序

电路中,当两个触发器间的组合逻辑延迟过大时,会导致setup时间不满足而发生亚稳态。

1.3.5对跨时钟域数据的处理

对跨时钟域数据的处理的核心就是要保证下级时钟对上级数据采样的setup时间或

hold时间满足要求,即尽量避免亚稳态的发生和传播。但是,我们知道,只要系统中有异

步元件,亚稳态就是无法避免的,因此设计的电路首先要减少亚稳态导致错误的发生,其次

要使系统对产生的错误不敏感。我们推荐使用以下方法来解决异步时钟域数据同步问题。

1.用触发器打两拍

如下图,左边为异步输入端,经过两级触发器同步,在右边的输出将是同步的,而且

该输出基本不存在亚稳态。其原理是即使第一个触发器的输出端存在亚稳态,经过一个CLK

周期后,第二个触发器D端的电平仍未稳定的概率非常小,因此第二个触发器Q端基本不

会产生亚稳态。然而,亚稳态是无法被根除的,一旦亚稳态发生,后果的严重程度依赖于你

设计系统对产生的错误是否敏感。



2.异步FIFO或DPRAM

因为异步FIFO或DPRAM使用格雷码计数器设计读写地址的指针,所以它可以很

好地避免亚稳态的发生。使用方法如下,将上级芯片提供的数据随路时钟作为写信号,将数

据写入异步FIFO或DPRAM,然后使用本级的采样时钟将数据读出即可。唯一需要注意的

是,当两级时钟频率不同时,需要设计好缓冲区,并通过监控full、half、empty、useword

3.调整时钟相位

信号,保证数据不会溢出,也不会被读空。

而且适用面有限。首先需对跨时钟域数据的路径进行详

细的静态时序分析,然后将违反setup时间和hold时间的情况一一列出,在不影响其它设

计性能的前提下,综合考虑调整两级时钟的相位关系,最终使其setup时间和hold时间满

足要求。



这种方法的设计难度较大,













2.FPGA简介

2.1什么是FPGA

mableGateArray的缩写,即现场可编程门阵列,是一种可编程的IC

以下是目前项目中使用的几种FPGA芯片:



FPGA是FieldProgram

芯片(集成电路芯片),



2.2FPGA的结构与组成

的可编程逻辑单元构成阵列,又由可编程I/O单元围绕阵

排成阵列的逻辑单元由布线通道中的可编程内连线连接起来实现一定的逻

辑功能。

FPGA的可编程逻辑单元一般由查找表和触发器构成。下图所示即

为Cyclone系列FPGA芯LE)组成。

图左边所示的电路,查找表是这样实现的:首先FPGA开发软件会自动计算逻辑电路的所有

等于输入一个地址进行查表,找出地址对应的内容后输出,即实现了该逻辑功能。



通常FPGA由布线资源分隔

列构成整个芯片,

目前我们使用的

片的逻辑单元(



查找表(Look-Up-Table)简称为LUT,其本质上就是一个静态存储器SRAM。对于下

可能的结果,然后把结果事先写入查找表中,FPGA工作时,输入信号所进行的逻辑运算就

实际逻辑电路LUT的实现方式





a,b,c,d输入逻辑输出地址RAM中存储的内容

0000000000

0001000010

....0...0

1111111111

如果所设计的是时序电路,需要触发器,则FPGA开发软件会自动将触发器配置在查

找表的后面,实现组合逻辑时就将触发器旁路掉。

当然,对于复杂的设计,一个LUT是无法完成的,FPGA可以通过进位逻辑将多个LUT

相连起来,实现n输入的查找表,实现设计要求。

表、触发器和布线资源组成。下图

内部结构,其中一对查找表和触发

器构成逻辑单元LE,LE组

各种布线资源,就是一个FPGA

详细的介绍请见:补充教程

2.3FPGA与ASIC设计的区别

ASIC和FPGA

个发展方向,两者唯一的区别在于,ASIC的逻

FPGA。

设计的代

码风格有明显差异,特别是在功耗、速度、时序等要求上。例如

意识地采用某些组合逻辑、门控时钟等,以降低功耗或提高速度。

通俗地说,FPGA就是由查找

是一个Cyclone系列FPGA芯片的

若干个

成逻辑阵列块LAB,最后再配上



片了。

6FPGAPLD结构与原理。



ASIC是ApplicationSpecificIntegratedCircuit的缩写,即专用集成电路。

属于SOC(Systemonachip片上系统)的两

辑电路是固化在其芯片中的,我们可以将ASIC理解为不可编程的

由于FPGA设计是基于固有的硬件结构(如逻辑单元、块RAM、PLL/DLL、时钟资源

等)的;而ASIC设计结构灵活,目标多样,所以ASIC设计的代码风格和FPGA

ASIC设计中根据要求会有

3.FPGA开发流程

HDL(HardwareDesignLanguage)和原理图是两种最常用的数字硬件电路描述方法,

HDL设计法具有更好的可移植性、通用性和模块划分与重用性的特点,在目前的工程设计

开发流程是基于HDL的。



中被广泛使用。所以,我们在使用FPGA设计数字电路时,其

需求定义(功能定义)

pecDesignSification

RTL级HDL描述

RTLDesignEntry

功能仿真(前仿真)

RTLSimulation

管脚分配与设计约束

AssignPins&Settings

综合

Synthesis

门级仿真(综合后仿真)

GateLevelSimulation

布局布线

Place&Route

时序/时延分析

TimingAnalysis

Pre-synthesisSimulation

Tools:ModelSim

SynopsysVCS,ActiveHDL

RegisterTransferLevel寄存器传输级

Tools:HDL编译器,TextEditor

Block&Symbol(QuartusⅡ)

Tools:AssignmentEditor(QuartusⅡ)

PinPlanner(QuartusⅡ)

Settings

Tools:SynplifySynplifyPro

SynopsysDC

Analysis&Synthesis(QuartusⅡ)

Tools:Fitter(QuartusⅡ)



Post-synthesisSimulation

Tools:SynopsysDC,PrimeTime

ModelSim

Simulation(QuartusⅡ)

Tools:ByteBlasterⅡ(QuartusⅡ)

配置与下载

Configuration.Download

Tools:TimingAnalyzer(QuartusⅡ)

设计修改

DesignModification

3.1需求定义(功能定义)

设计和实现一个系统的第一步,是明确整个系统的性能指标,然后进一步将系统功能划

分为可实现的具体功能模块,同时明确各模块的功能与基本时序,还可大致确定模块间的接

口,如时钟、读写信号、数据流和控制信号等。

3.2RTL级HDL描述

RTL级(寄存器传输级)指不关注寄存器和组合逻辑的细节(如使用了多少逻辑门、逻

辑门的连接拓扑结构等),通过描述寄存器到寄存器之间的逻辑功能的HDL设计方法。RTL

级比门级更抽象,同时也更简单和高效。RTL级的最大特点是可以直接用综合工具将其综

合为门级网表。RTL级设计直接决定着系统的功能和效率。我们使用的HDL语言是verilog。

3.3功能仿真(前仿真)

功能仿真也称综合前仿真,其目的是验证RTL级描述是否与设计意图一致。为了提高效

率,功能仿真需要建立testbench,其测试激励一般使用行为级HDL语言描述。

3.4管脚分配与设计约束

无论是RTL级还是门级的HDL设计方法,在实现该逻辑时都需要与实际的FPGA芯片

相匹配。管脚分配是指将设计文件的输入输出信号指定到器件的某个管脚,设置此管脚的电

平标准、电流强度等。设计约束指对设计的时序约束和在综合、布局布线阶段附加的约束等。

3.5综合

将RTL级HDL语言翻译成由与、或、非门等基本逻辑单元组成的门级连接(网表),并

根据设计目标与要求(约束条件)优化所生成的逻辑连接,输出门级网表文件。

3.6门级仿真(综合后仿真)

在综合后通过后仿真来检查综合结果是否与原设计一致。一般,综合后仿真和功能仿真

的测试激励相同。由于综合工具日益完善,在目前的FPGA设计中,这一步骤被省略掉。

3.7布局布线

配。也可以简单地将布局布线理解为对FPGA内部查找表和寄存器资源的合理配置,那么‘布

布局布线就是使用综合后的网表文件,将工程的逻辑与时序要求与器件的可用资源相匹

局’可以被理解挑选可实现设计网表的最优的资源组合,‘布线’就是将这些查找表和寄存器

通过时序/时延分析获得布局布线后系统的延时信息,不仅包括门延时,而且还有实际的

lation),即不满足时序约束条件或者器件固有时序规则(建立



局布线后的配置文件下载至FPGA中,对其硬件进行编

配置文件一般为.pof或.sof式,下载方式包括AS(主动)、PS(被动)、(边

界扫描)等方式。











资源以最优方式连接起来。

3.8时序/时延分析

布线延时。时序/时延分析的时序仿真是最准确的,能较好地反映芯片的实际工作情况,同

时发现时序违规(TimingVio

时间、保持时间)的情况。

3.9配置与下载

通过编程器(programmer)将布

程。文件格JTAG











4.RTL设计

4.1使用verilog进行RTL设计

TL设计一般可归纳为3种基本的描述方式:

2、行为描述:使用always语句或initial语句块的过程赋值语句。

3、结构化描述:实例化已有的功能模块或原语,即平常所说的元件例化和IPcore。

其中,连续赋值语句是连续驱动的,也就是说只要输入变化,都会导致该语句的重新计

。其被赋值的变量不会被电路寄存。过程赋值语句包括非阻塞过程赋值、阻塞过程赋值和

连续过程赋值。对于这些抽象的概念,我们将在其后的实际例子中详细解释。

4.1.1硬件设计意识

RTL设计其实就是用语描述硬件电路行为的过程。这同一般的软件设计有

很大区别,因为对于很多的软件代码,硬件电路是无法实现的(即无法综合,从语言到硬件

电路的解析过程称为综合)。我们只能使用可综合的代码结构来实现我们所需的硬件电路。

首先,我们需要建立硬件设计的意识,硬件意识是RTL级设计的基础。

1.电路在物理上是并行工作的。其含义是,一旦接通电源,所有电路都同时工作。

2.电路行为的先后顺序通过时钟节拍得顺序来体现。

4.1.2RLT级设计时需注意的问题:

1.凡是在always或initial语句中赋值的变量,一定是reg类型变量;凡是在assign语

句中赋值的变量,一定是wire类型变量;

2.定义存储器:reg[3]MEMORY[0:7];地址为0~7,每个存储单元都是4bit;

3.由于硬件是并行工作的,在Verilog语言的module中,所有描述语句(包括连续赋

值语句assign、行为语句块ways和initial语句块以及模块实例化)都是并发执行的。

4.使用完备的if…else语句,使用条件完备的case语句并设置default操作,以防止产

生锁存器latch,因为锁存器对毛刺敏

5.严禁设计组合逻辑反馈环路,它最容易引起振荡、毛刺、时序违规等问题。

6.不要在两个或两个以上的语句块(always或initial)中对同一个信号赋值。

使用verilog进行R

1、数据流描述:采用assign连续赋值语句





言的方式去

:0

al

感。



4.1.3阻塞赋值与非阻塞赋值

在中,有两种过程性赋值方式,即阻塞赋值(VerilogHDLblockingassignment)和非

阻塞(non-blockingassignment)。这两种赋值方式有着根本的区别,如果使用不当,赋值

综合出来的结果会和设计的期望结果相去甚远。

1.阻塞赋值的操作符为“=”。它的含义是在计算等式右侧表达式值及完成其赋值时不

会被其他的verilog语句打断,就是说,在当前赋值没有完成之前,它阻塞了其他verilog

语句的执行。

例如:begin



end

语句2的,它"阻塞"语句2的执行。这里说的"执行完"指的是在本时刻计算完y+c的值,并

赋给y=5(旧值),c=4,a=3,b=1,则x=9,y=4。

的两个always语句块。

过程2:

always@(posedgeclkornegedgerst_n)always@(posedgeclkornegedgerst_n)

begi

if(rst_n==1''b0)

y=1''b0;x=1''b1;





endend



则在复位完后,x、y1;如果先执行过程1,则x、0。

的标准,上例中两个always块是并行执

行的,与书写的前后顺序无关,但是,verilog标准没有规定在这种特殊情况下的执行顺序。

所以,这需要我们在编程时避免这样的代码。



<=”。它的含义是在赋值操作时刻开始时计算等式右

边,赋值操作时刻结束时更新等式左边。在这期间,可以执行其它塞

例如:begin

x=y+c;//语句1

y=a+b;//语句2

语句1和语句2都要求在同一仿真时刻执行,但在语句1没有执行完之前,是不会执行

y。若该仿真时刻

还有下面的情况,过程1和过程2是同一个module中

过程1:

nbegin

if(rst_n==1''b0)

elseelse

y=x;x=y;

仿真开始时,两个always语句块将并行地同时执行。如果仿真器先执行过程2的话

的值最终都会变为y的值最终都会变为

为什么会出现这种情况呢?因为按照Verilog

2.非阻塞赋值的操作符为“

verilog语句,也不阻

其它verilog语句的执行。



y<=a+b;//语句2

的在语句2之前,但是由于是非阻塞赋值,语句1的执行不影响语句2的执

时刻完了后,才更新左端的值。若该仿真时刻y=5(旧值),c=4,a=3,b=1,则

同样,对于下面的情况,过程1和过程2是同一个module中的两个always语句块。

过程:过程2:

if(rst_n==1''b0)if(rst_n==1''b0)





将最终形成一反馈移位寄

2.在组合逻辑中,使用阻塞赋值;

always

4.在同一个always块中,如果既有组合逻辑又有时序逻辑,使用非阻塞赋值;

5.always模块的敏感表为电平敏感信号时,使用阻塞赋值;

7.不要在阻塞赋值中使用时延语句。

另外一点需注意的就是,阻塞赋值是相对时间赋值,非阻塞赋值是绝对时间赋值。

码的可综合性

码都是对硬件行为的一种描述,但不一定是可直接对应成

电路的设计信息。行为描述可以基于不同的层次,如系统级,算法级,寄存器传输级(RTL)、

RTL的模式来编写代码,而不能随心所欲得

x<=y+c;//语句1

end

虽然语句1

行,在该仿真

x=8,y=4。

1

always@(posedgeclkornegedgerst_n)always@(posedgeclkornegedgerst_n)

beginbegin

y=1''b0;x=1''b1;

elseelse

y=x;x=y;

endend

由于仿真时刻完了后才会去更新左端的值,所以上面两个过程

存器。

在实际使用中,我们需要遵循以下的原则:

1.在时序逻辑中,使用非阻塞赋值;

3.在同一个块中,不要混合使用阻塞赋值和非阻塞赋值;



6.不要使用#0时延进行赋值。

8.在行为级描述中,若语句间是顺序执行的关系,使用阻塞赋值。

4.2HDL代

任何符合HDL语法标准的代

门级等等。以目前大部分EDA软件的综合能力来说,只有RTL或更低层次的行为描述才能

保证是可综合的。绝大部分电路设计必须遵循

写仅

4.2.

,我们举几个例子来说明这个问题:

的延迟语句(如:#delay)、

,他们所描述的功能对硬件而言是不

。比如,实现两个变量相除运算的代码:

c<=A/B;

我们将发现这句代码只能在前仿真中正确执行,在QuartusⅡ和其他EDA软件中都不

能将其综合成硬件。

除、求余、移位。试除和求余需要减法器,商数和余数的中间结果必须有寄存器存储;而这

些运算显然不能在一完成,它需要一个状态机来控制时序,经过多个时钟周期才

能得出结果。

次描述的EDA(注:有些FPGA的配套软件提供乘除法的运算模块,

但也只能支持直接调用,不支持把形如C=A/B的语句综合成除法模块)。

3.对于不定次数的循环运算是不可综合的,比如对于如下的代码段:

是有限的、固定的。当综合软件遇到循环语句时,总是将其展开成若干条顺序执行的语句,

是常数,则展开的语句数是确定的,具有可综合性;而

对应的硬件电路数量也不能确定,无法被综合。这样

的语句还包括while,repeat,forever等,他们都不可综合。

通常EDA软件对HDL代码的综合能力总是比人的思维差。也就是说,对于一段代码,

那EDA软件肯定也不行。比如说,加法器、

,所以类似A+B-C,(A>B)?C:D这样的运算一定可以综

合。实

仅符合语法的HDL代码。

1哪些是不可综合的代码

我们不可能将所有不可综合的代码都一一列出

1.对于一些抽象的行为描述代码是不可综合的。比如我们常见

初始化语句initial以及等待语句wait都是不可综合的

可实现的。

2.对于一些抽象的运算代码也是不可综合的

always@(posedgeclk)

试想一下,如果我们自己用笔算除法是怎么做的?从高位到低位逐次试

个时钟延上

一句简单的C=A/B同所有这些相比显得太抽象,对于只能接受RTL或更低层

软件来说确实太难实现。

for(i=0;i
parity=parityxordata[i];

当wordlength为变量时,任何EDA软件都不能综合这个代码。这是因为硬件规模必须

然后再综合成电路。若wordlength

若它是变量时,展开的语句数不确定,

4.2.2如何判断自己写的代码是可综合的

如果你不能想象出一个较直观的硬件实现方法,

多路选择器是大家都很熟悉的电路

而除法、开根、对数等等较复杂的运算,必须通过一定的算法实现,没有直观简单的

现方法,则可以判断那些计算式是不能综合的,必须按它们的算法写出更具体的代码才能实

现。此外,硬件无法支持的抽象行为描述,当然也不能被综合。

不过,这样的判断标准非常主观模糊,

时延较大的

组合逻辑

a_rega_pipea_int

z_reg

a_rega_pipea_intz_reg

HDL描述的结构

遇到具体情况还得按设计人员自己的经验来判断。

如果

以及他们的有限次组合,基本上是可综合的,否则就有无法综合的可能性。当然,这样的标

准仍

4.3RTL代码的优化

求一个设计同时

具备要求和最高频

率要求的前提下,占用最小的芯片面积,或者在所规定的面积下,使设计的时序余量更大,

频率

Pipelining,即流水线时序优化方法,其本质是调整一个较大的组合逻辑路径中的寄存

Clock-To-Output和Setup等时

间参数的要求,达到提高设计频率的目的。

的组合逻辑,在它旁边加上若干个需优

化的









要一个相对客观的标准,一般来说:在RTL级的描述中,所有逻辑运算和加减法运算、

然有缺陷,所以,正确的判断仍然要靠实践来积累经验。当你可以较准确判断代码的可

综合性的时候,你对HDL的掌握就算完全入门了。

优化RTL代码追求的最终目标是面积或者速度,或者是两者的平衡。面积和速度是

FPGA设计的两个基本标准。“面积”是指一个设计所消耗FPGA的逻辑资源数量,“速度”

指设计在芯片上稳定运行所能够达到的最高频率。两者是对立统一的,即要

面积最小、速度最高时不现实的。我们的设计目标应该是在满足设计时序

更高。

4.3.1Pipelining技术

器位置,用寄存器合理分割该组合逻辑路径,从而降低路径

具体实现可通过下图的方法,首先对时延较大

寄存器,然后运用优化工具自动将大组合逻辑拆分为几个小的组合逻辑,同时将寄存器

放在小组合逻辑在中间。

















工具自动优化之后的结构

4.3.2模块复用与资源共享

模块复FPGA的逻辑资源,即节约面积。我们通过下面

如果需要实现一个补码平方器,输入是8bit补码,求其平方和。因为输入是补码,所

示原值是正数,直接求平方。下面是两种RTL设计实现方式:

第一种RTL设计实现:

moduleresource_share1(data_in,square);

data_in;//输入是补码

output[15:0]square;

assigndata_bar=~data_in+1;

第二种RTL设计实现:

moduleresource_share2(data_in,square);

are;

wire[7:0]data_tmp;

assigndata_tmp=(data_in[7])?(~data_in+1):data_in;

assignsquare=data_tmpdata_tmp;

endmodule

可以发现,第一种RTL设计需要两个16bit乘法器,同时平方;而第二种RTL设计只

用了一个乘法器。我们使用SynplifyPro对两个RTL设计分别进行综合,结果第一种RTL

计所占用的逻辑资源为140个LUTs,第二种RTL设计为75个LUTs。下图是两个设计的

现结果:

第一种RTL设计,占用140个LUTs

用与资源共享的目的在于节约

这个例子来说明这个优化方法。

以当最高位是1时,表示原值是负数,需要按位取反,加1后再平方;当最高位是0时,表

input[7:0]

wire[7:0]data_bar;

assignsquare=(data_in[7])?(data_bardata_bar):(data_indata_in);

endmodule

input[7:0]data_in;//输入是补码

output[15:0]squ

使





第计,占用75个LUTs

逻辑复而改善时序条件的优化手段。逻辑复制最常使用的场合是

调整信号的buffer来满足信号的驱动能力的要求,在复

制了一条路径后,就可减轻这条路径的驱动能力,同时路径的延时也同时减小了。

二种RTL设

4.3.3逻辑复制

制是一种通过增加面积

扇出。如下图,FPGA一般通过插入



4.4状态机的设计

我们推荐在状态机的设计中采用两段式写法(2个always模块)或三段式写法(3个

always模块)。

两段式写法的核心思想是,一个always模块采用同步时序描述状态转移;另一个always

模块采用组合逻辑方式判断状态转移条件,描述状态转移规律。其结构如下图:

状态转移

条件判断

组合逻辑

当前状态

时序逻辑

组合逻辑输

出,若时序允

许,尽量插入

寄存器输出

输入

下一状态

状态

时钟

状态输出

组合逻辑时序逻辑组合逻辑

三段式写法的核心思想是,一个always模块采用同步时序的方式描述状态转移,一个

时序电路描述每个状态的输出。其结构如下图:

我们归纳出状态机设计的其它技巧和准则:

1.状态机的编码最好使用one-hot(独热码)。

2.一个完备的状态机应该具备初始化状态和默认状态。



4.时序逻辑always模块使用非阻塞赋值“<=“,组合逻辑模块使用阻塞赋值“=”。

m

inp

inp

outputo1,o2,err;

parameter[2:0]//onehotwithzeroidle

IDLE=3''b000,

S1=3''b001,

S2=3''b010,

ERROR=3''b100;



采用组合逻辑的方式判断状态转移条件,描述状态转移规律,第三个always模块使用同步





3.状态机的编码可以用parameter定义,不推荐使用define宏定义。

5.使用完备的if…else语句和case语句。

6.case语句需具备full_case和parallel_case属性。full_case定义了所有可能的输

入模式,parallel_case定义了case项是不重复的。

下面是一个状态机的例子,它采用了三段式写法,one-hot编码,并且符合其它状态机

的设计准则。

odulestate(nrst,clk,i1,i2,o1,o2,err);

utnrst,clk;

uti1,i2;

rego1,o2,err;

reg[2:0]NS,CS;

状态转移

条件判断

组合逻辑

组合逻辑

当前状态

时序逻辑

时序逻辑

状态转移

条件判断

组合逻辑

组合逻辑

当前状态

时序逻辑

时序逻辑

输入

状态

当前状态

时钟

下一状态

下一状态

下一状态

输出

输出

always@(posedgeclkornegedgenrst)//1stalwaysblock,sequentialstatetransition

if(!nrst)

CS<=IDLE;

else

CS<=NS;



always@(nrstorCSori1ori2)//2ndalwaysblock,combinationalconditionjudgment

begin

NS=3''bx;

case(CS)

IDLE:begin

if(~i1)NS=IDLE;

if(i1&&i2)NS=S1;

~i2)NS=ERROR;

end



;

if(i2&&i1)NS=S2;





S2:begin

NS=S2;



if(~i2&&(~i1))NS=ERROR;





if(i1)NS=ERROR;

if(~i1)NS=IDLE;



ult:begin

NS=IDLE;

end







gedgenrst)//3rdalwaysblock,thesequentialFSMoutput

0;

begin

3''b000;

3''b100;

if(i1&&

S1:begin

if(~i2)NS=S1

if(i2&&(~i1))NS=ERROR;

end

if(i2)

if(~i2&&i1)NS=IDLE;

end

ERROR:begin



end

defa





endcase

end

always@(posedgeclkorne

if(!nrst)

{o1,o2,err}<=3''b00

else



{o1,o2,err}<=3''b000;

case(NS)

IDLE:{o1,o2,err}<=

S1:{o1,o2,err}<=

S2:{o1,o2,err}<=3''b010;

ERROR:{o1,o2,err}<=3''b111;

plifyPro分析该状态机,可以使用专用的FSM观察器(FSM

息显示选项卡。左





















endcase

end

endmodule

我们推荐使用工具Syn

Viewer)进行分析。下图为在FSMViewer中得到的状态转移图和FSM信

图中被选中的状态和转移路径,将在右图中同时被标示出。



5.QuartusⅡ设计实例

该实例设计实现一个简单的DDS正

模块,地址产生模块,ROM

40MHz的时钟到FPGA内部,进入时

定精确的120MHz的系统时钟。然后,

累加寄存器输出的数据进行累加,

ROM查找表模块在每个系统时钟的上升沿,

点数据并输出,该数

据就是最终的DDS

信号。那么下面我们

就来开始设计这个

DDS正弦波发生器。



5.1新建project

首先,建立一个QuartusⅡ工程,点击file→在弹出的对话

框中输入工程目录和工程名,然后在器件选择框中选择FPGA芯片的型号。我们在这里假

定使用cyclone系列的EP1C6Q240C8。

5.2设计输入

下面我们将通过一个QuartusⅡ设计实例来向大家介绍如何进行实际的FPGA设计开

发。

弦波发生器。它可分解为3个部分来设计:时钟产生

查找表模块。整个系统实现的思路是:首先,由外部晶振引入

钟产生模块,对时钟进行处理并3倍频后,得到一个稳

地址产生模块在系统时钟的激励下,将频率控制字与

然后把累加结果作为地址输出给ROM查找表模块。最后,

按照地址来读取ROM查找表中相应的波形采样

40MHz时钟

时钟产生模块

120MHz时钟

地址产生模块

ROM查找表

DDS波形信号

address

频率控制字

设计输入的第一步,是建立顶层设计文件:点击file→NEW→这

样就

点击tools

建立一个新的原理图文件,我们将这个原理图文件作为顶层文件。

对于时钟产生模块,我们打算用PLL锁相环来实现,所以可以使用QuartusⅡ自带的IPcore

调用工具Megafunction来产生PLL锁相环的。

→或者

右键选择newInsert→Symbol;选择createa

custommegafunctionvariation,然后选择

下的,接着按照要求配置

PLL模块。

实现地址产生模块,点击file→NEW→

各项参数,最后得到

下一步是建立一个新的verilog文件,

然后输入RTL代码:

`timescale1ns

moduleaddress_gen

ble;

input[5:0]control_word;

output[11:0]address;

always@(posedgeclkornegedgereset)













else

gin

address<=address;



/10ps

(clk,reset,enable,control_word,address);

inputclk,reset,ena

reg[11:0]address;

begin

if(reset==1''b0)

begin

address<=12''h000;

end

elseif(enable==1''b1)

begin

address<=address+{6''b0,control_word};

end

be

end

end

endmodule

接着我们将这些RTL代码生成为一个子模块,以方便将

Update→其加入到顶层文件中。点击file→Create/

即生成了该模块,

右键选择Insert→Symbol,引用该模块至原理图中

然后点击





最后一步,是实现ROM查找表模块。我们同样可以调用QuartusⅡ的IPcore来实现,

tools→因为在Megafunction中提供了专用的ROM模块。点击

然后选择下的,设置ROM容量为4096×12bit,最后还需要指

如下左图。正弦查找表的初始值一般由matlab产生,然后存储成.hex

系统就设计完成了,下图显示的就是整个设计的顶层文件。在设计的最后,

我们应该确保设计中没有语法错误和设计违规,可以使用Processing→Start→

定ROM的初始值,

或.mif文件。这样就得到了ROM查找表模块。



这样,整个

来检查。



5.3管脚分配与设计约束

在顶层文件设计完后,我们需要将project中涉及到的引脚分配至指定的

步就将我们逻辑设计和实际的FPGA硬件联系起来了,因为管脚分配同PCB

pin上,这一

板上的硬件设

PCB板前需验证管脚分配是否能够通过。计必须是一一对应的,在某些特殊情况下,绘制

点击Assignments→,进入管脚分配的界面。下图是FPGA芯片的管脚分

布图,每个管脚对应其相应的功能,如pin28是专用的时钟输入引脚。









在管脚分配时,需注意我们在逻辑设计中定义的引脚功能是否被FPGA硬件允许,其

次是电平标准要选择正确,这一点也是和硬件相关的。下图显示的是这个中引脚的

分配情况,电平标准为LVTTL。



最后,对管脚分配进行验证,点击Processing→Start→



project



设计约束指对设计的时序约束和在综合、布局布线阶段附加的约束等。因为对每个

project,约束是不同的,所以我们这里只举例说明。

比如对这个project,我们希望系统的最高

工作频率为z,那么我们点击120MH

Assignments→,

在窗口中可以设置:



又比如,我们希望节省FPGA芯片资源,那么就可以在综



AssignmentsEditor对话框来

合时对面积进行优化,还是在刚才的窗口中设置:





此外,如果需要对某个信号进行单独的约束时,就要进入

添加约束,点击Assignments→,按下图的显示来选择约束

信号、约束种类和约束值,即设置完毕。









至于具体施加何种设计约束,就只有等待大家在实践中慢慢掌握了,可以查阅其他书籍

或QuartusⅡ使用手册,更多的还是依靠经验。

5.4全编译

在以上步骤都完成后,我们将对整个project进行全编译(Compilation)。点击Processing











全编译主要包括四步操作:分析综合(Analysis&Synthesis)、布局布线(Fitter)、

编程配置(Assembler)、时序时延分析(TimingAnalyzer),这些操作都是一次性完成的,

无需





全编译的同时还生成了一份编译报告,这个报告中包含了许多重要信息。尤其是时序分

选择约束信号约束种类约束值

干预。



析报告,如果设计中有时序违规的情况发生,报告中的那一项将被显示为红色。一般来说,

我们必须保证项目中没有任何时序违规的情况。





仿真文件,点击file→NEW→

5.5时序仿真

了验证设计的正确性,必须进行时序仿真。

首先建立,即得到仿真波形文件。然后

NodeorBus→导入需要仿真的信号。



















然后就是绘制仿真波形。大家要明白这一点,我们对设计进行仿真,无非是施加激励,

右键→Insert



然后观察输出(即响应)是否符合我们的设计要求。绘制波形就是施加激励的一种方式。下

图是仿真之前的波形图,暂时将频率控制字设置为1。

运行仿真。点击Processing→,得到下图的仿真结果:

结果:

可以看FPGA

中进行调试了。

后仿真,

产生了竞争。

修改频率控制字为3,得到下图的仿真

出,仿真波形都是正确的,满足我们的设计要求,这样,就可以下载至



补充一点:大家可以清晰地看到波形仿真中的毛刺,这是因为QuartusⅡ的仿真是综合

就是说是带有延时信息的。毛刺产生的原因是因为组合逻辑在系统工作频率很高时



5.6下载编程

最后一步就是将全编译产生的编程文件(.pof或.sof文件)下载至FPGA中。

首先,我们需要设置配置方式和配置芯片,点击Assignments→Device→





在设置完成后,需要重新运行全编译。

然后,点击Tools→,进入下载编程配置窗口。

下载电缆

配置方式

.pof编程文件配置芯片



我们使用的下载电缆是ByteBlasterⅡ,如右图。

安装下载电缆的驱动请见补充教程7:安装QuartusII下载电

缆。



最后,在硬件连接正常的情况下,点击即完成

配置。需要注意的是,在任何情况下插拔下载电缆,都必须关电。











6.ModelSim和Testbench

我们在进行功能仿真时,经常需要用到ModelSim和Testbench。由于篇幅的限制,这里

只做简要的介绍。

ModelSim的使用请见补充教程8:modelsim使用教程。

Testbench,其实就是测试平台的意思,一般Testbench的结构如下:









一个用原理图方式描述的文件(格式为.bdf),我们可以点击fi

测试平台Testbench

激励

被验证设计

响应检查



Testbench的编写一般使用行为级语法,因为它不需要被综合。而且一般使用元件例化

的方法将被验证设计例化至Testbench文件中。下面结合DDS正弦波发生器的设计列举一个

testbench的实例。

首先,我们要得到“被验证设计”文件。我们设计的DDS正弦波发生器的顶层文件是

le→Create/Update→

,得到verilog描述方式的顶层文件,如下:

_DATA);

putinclk;

putreset;

inputenable;

iresys_clk;

ire[11:0]SYNTHESIZED_WIRE_0;

wireSYNTHESIZED_WIRE_1;



altpll0Ualtpll0(.inclk0(inclk),

.areset(reset),

.c0

lpm_rom0Ulpm_rom0(.clock(sys_clk),

moduleDDS_generater(inclk,reset,enable,control_word,DDS

in

in

input[5:0]control_word;

output[11:0]DDS_DATA;



w

w

(sys_clk));

.clken(enable),

.aclr(reset),

.q(DDS_DATA));

assignSYNTHESIZED_WIRE_1=~reset;

address

ndmodule



然后设计testbench,testbench包括两部分,一是激励,二是被验证设计的元件例

激励源。那么具体的testbench设计如下:

moduleTestbench;

parameterCLK_PERIOD=20;

regclk;

regword;

产生周期为20ns,即频率为50MHz的时钟)

foreverbegin

(CLK_PERIOD/2)clk=~clk;

end



initial//Reset激励(产生5个周期长度低电平的reset信号)

rst=1;

#CLK_PERI

#(5CLK_PERIOD)rst=1;



initial//enable激励(等待复位操作结束后,对enable信号置位)

.address(SYNTHESIZED_WIRE_0),

_genUaddress_gen(.clk(sys_clk),

.reset(SYNTHESIZED_WIRE_1),

.enable(enable),.control_word(control_word),

.address(SYNTHESIZED_WIRE_0));

e

化。对于DDS正弦波发生器,我们共需要时钟inclk,复位reset,使能enable和频率控制字

control_word这四个

`timescale1ns/10ps





regrst;

regenable;

regdds_dataout;



initial//时钟激励(

begin

clk=0;

#

end

begin

ODrst=0;

end

begin

enable=0;

#(3CLK_PERIOD)

@(rst)enable=1;

1,在1000个周期后变为3)

begin

word=6’b1;

#(1000CLK_PERIOD)w

display("SimulationFinished!");//显示"SimulationFinished!"

$sto



证设计的元件例化

.reset(rst),

.enable(enable),

.control_word(word),

.DDS_DATA(dds_dataout));

也可以将这两个文件DDS_generater和Testbench添加至ModelSim中进行

功能

希望这个教程能给大家提供帮助,也希望大家在实际

的项目中不断体会、总结、提高,最终成为一位FPGA高手。



416教研室杨威)

il:lowy@163.com

参考

1、AlteraFPGA/CPLD)EDA先锋工作室

2、AlteraEDA先锋工作室

3、基erilogHDL的数字系统应用设计王钿卓兴旺编著

4、设

enable=0;

end



initial//频率控制字激励(先将频率控制字设置为

ord=6’3;

end



$

p;//停止仿真

end

DDS_generaterUDDS_generater(.inclk(clk),//被验

endmodule

同时,我们

仿真。



至此,本教程就全部书写完毕了,

(本教程作者:电子科技大学

如有问题,请发emavsno

书籍:

设计(基础篇

FPGA/CPLD设计(高级篇)

于V

计与验证VeirlogHDLEDA先锋工作室

献花(0)
+1
(本文系高强的图书...首藏)