xilinxfpga设计基础

xilinxfpga设计基础
xilinxfpga设计基础

第一章开发软件ISE与开发流程

LUT主要适合SRAM工艺生产,因此FPGA都是基于SRAM工艺的,掉电就会丢失。

设计输入

除了常见的文本输入,还可以采用图形输入方式:

单击Design Utilities->Creat Schematic Symbol,则会在工程文件夹下生成一个文件,同时这个生成的符号被加入到符号库中。这样可以添加元件。

用户约束文件UCF的编写:

管脚约束:如NET “” LOC = ; --将信号锁定到fpga的管脚。

时钟约束:如NET “” PERIOD = period {HIGH/LOW}[high or low time]。

采用图形化方法输入约束文件:

创建ucf文件,选择ucf文件,然后点击Processes->User Constrains->Create Timing Constraints添加时序约束;点击Processes->User Constrains->I/O Pin Planning添加管脚约束。

设计综合(Synthesize)

综合将概念性硬件描述语言HDL的设计定义转换成针对目标器件的逻辑或者物理表示。

XST(Xilinx Synthesis Tools)就是综合工具,其输出为Xilinx特有的NGC网表文件,NGC包含转化后的逻辑数据和约束信息。

综合是设计流程中的基本步骤,它将概念性硬件描述语言的设计定义转换为针对器件的逻辑或物理表示。在综合过程中,状态机是单独处理、独立分析的,根据综合的选项,综合器选择状态机在综合过程中选用的实现算法。

综合完成后,综合器会根据综合选项和XCF(XST Constraint File, 综合约束文件),对综合结果做一些基础的优化。

HDL文件

语法分析

检查语法错误

HDL综合

宏识别、优先状态机展开资源共享技术

底层优化

宏实现、时序优化映射、复制寄存器

NGR文件NGC文件LOG文件

功能仿真(Simulation->behavioral)

功能仿真可以对工程设计文件进行初步的功能验证。仿真软件将HDL语言转换为抽象的逻辑电路,忽略信号在逻辑器件和传输线上的延时,并对应各种可能的输入信号仿真得到设计工程的输出信号,检验输出信号是否满足预期的要求。

功能仿真需要创建Test Bench文件。

工程实现(Implementation)

工程实现包含以下四个步骤:

Translate—将综合后的网表文件NGC和约束文件UCF融合到同一个Xilinx的设计

文件PCF中。

Map—将设计中的功能器件映射到工程设计的目标器件资源中。

Place and Route—对映射后的目标器件资源进行布局和布线,满足时序约束。

Generate Programming File—生成可以下载到器件中的比特流文件,对器件进行

编程配置。

时序仿真(Simulation->Post Route)

对经过布局布线后的仿真模型加入延时文件进行仿真的过程,他将最基本的门级延时计算在内,模拟工程设计在FPGA器件内的实现过程。经过时序仿真后的设计基本上与实际电路是一致的。

时序仿真的基本参数:

时钟周期Period:最小时钟周期是指信号从一个触发器或锁存器的输入端,经过

一系列的组合逻辑单元和信号线,到达下一个同步器件,所用的最长时间。

端口到建立时间(Pad to setup time):信号从进入fpga芯片,经过一系列的逻

辑元件和连线,到达一个同步器件(触发器、锁存器或存储器)的输入端所用的最

长时间。

时钟到端口时间(Clock to pad time):数据信号从触发器或锁存器的输入端口,经过逻辑单元和连线时延,到达fpga芯片的输出管脚的最长时间。这个时间在约

束文件中称为OFFSET OUT AFTER约束。

端口到端口时间(Pad to pad time):数据信号从输入端口进入fpga芯片,经过

一系列逻辑元件和连线延时后到达fpga的输出端口的最大时间。

器件配置

利用iMPACT工具将比特流文件编程到fpga中。

第二章 VHDL硬件描述语言

基础知识

fpga电路设计的四个层次:行为层次(Behavioral)、寄存器传输层次(RTL, Register Transfer Level)、逻辑门层次(Logic)和布图层次(Layout)。

行为层次主要关注模块的功能描述和仿真验证,寄存器传输层次要关注模块的可综合电路的实现,逻辑门层次考虑如何用门级电路实现给定功能,布图层次考虑如何将电路适配到fpga的资源中。

2.2VHDL基本结构

实体与构造体

实体与C++中的类相似。

构造体的行为描述通常采用process进程语句实现。

构造体的数据流描述方式主要使用VHDL语言中的标准布尔函数,将信号之间的布尔代数关系用布尔方程式来表示。

结构体的结构描述主要通过下层模块的声明和调用及端口映射将下层模块相连。

Generic参数声明类似于C++语言中的类属参数声明。

library IEEE;

use COUNTER is

generic( COUNT_WIDTH :INTEGER:=7);

port( RST, SET, CLR :in STD_LOGIC;

SETVALUE :in STD_LOGIC_VECTOR(COUNT_WIDTH downto0);

COUNTOUT :out STD_LOGIC_VECTOR(COUNT_WIDTH downto0) );

end COUNTER;

用户自定义库时,先用关键字library说明要引用的库名,然后用use语句打开库中程序包。在计算机中新建一个文件夹,将文件夹名改为用户自定义“库名”,将编辑的程序包等以文件形式存在该文件下,此时该文件夹即为用户自定义库。

在ise中自定义library时,首先要新建library,然后编写相应的程序包,并将程序包移到(move to library)该library中,然后就可以使用use <库名>之类的语句了。

程序包

程序包的作用是收集被多个VHDL实体共享的数据类型、子程序或数据对象,使其适用于更一般的访问和调用范围。

配置

一个实体可以声明多个构造体,但形成最终电路时,只能使用一种结构体作为功能实现的描述,这时就需要使用配置将实体与结构体连接起来。配置不是从属单元,可以独立存在。通常在使用时都会将配置单独写入一个文件中。

1、默认配置语法如下。当实体选择的结构体中,不包含BLOCK语句和COMPONENT语句时,可采用默认配置为实体选择不同的结构体和对VHDL程序的性能评估。

2、元件配置。在层次化设计中,应用库中的元件是设计人员经常采用的一种效率比较高的工作方式。引用元件的方法有两种:使用元件例化语句;使用元件配置。元件配置语句的语法结构有两种形式,分别是低层次的配置和实体—结构体对的配置。

低层次的配置语法为:

实体—结构体对的配置的语法结构如下:

显然,实体—结构体对比低层次的配置要好。

3、结构体配置。虽然元件配置语句配置实体具有一定的优势,这种方法易写也易懂;但是书写过于臃肿,于是引出了第三种配置语句—结构体配置语句。

结构体配置语句必须放在所要配置的实体中的结构体中。其语法如下:

【举例】采用结构体配置实现全加器

y :out std_logic);

end component;

signal tmp1, tmp2, tmp3 :std_logic;

for U1, U2 : add use entity(xor_str);

for U3, U4 : add use entity(and_str);

for U5 : add use entity(or_str);

begin

U1 : add port map(A,B,tmp1);

U2 : add port map(tmp1,Cin,S);

U3 : add port map(tmp1,Cin,tmp2);

U4 : add port map(A,B,tmp3);

U5 : add port map(tmp2,tmp3,Co);

end structure;

语法要素

对象类型Port、Constant、Signal、Variable

变量在综合后可以是一个连线(wire),也可以是一个寄存器(register),综合的结果取决于变量在时序电路中是否用于保存信号值。变量虽然可以赋初始值,但是在综合时,综合器会忽略掉。

信号在声明结构中被赋予的初始值,与变量相同,在综合时也会被忽略。

信号的赋值可以加入延时,如 A <= B after5 ns;但是,延时语句只在行为建模时起作用,而在综合时也会被完全忽略。

数据类型

标量类型

1、bit类型是二值系统中的最基本单元,分别表示低电平和高电平。

2、Boolean类型没有数值的含义,也不能进行算术运算,只能作为关系运算的结果,在判断语句中判断使用。

3、 Integer类型的数据在底层电路中用一系列二进制位表示。使用时要指定range范围,这样综合器才能综合。

4、real类型的数据很多公司的综合工具不支持。

5、物理类型用于表示一些物理量,完整的物理数据类型包含数值和单位两部分。定义物理类型时必须先给出一个基准单位。如VHDL只定义了一个物理类型:

type TIME is range-47to47

units

fs;

ps =1000 fs;

ns =1000 ps;

us =1000 ns;

ms =1000 us;

sec =1000 ms;

min =60 sec;

hr =60 min;

end units

6、符号类型character通常用单引号括起来,如’Z’。

7、标准逻辑类型STD_LOGIC与bit类型相似,也是表示单个数字信号逻辑的,每个STD_LOGIC都有9种不同的状态。

8、枚举类型enumerate在状态机和复杂系统的描述中尤其有用。

9、错误等级severity_level共有四种状态可用:note、warning、error、failure。错误等级通常与assert语句配合使用。

复合类型

1、位矢量类型BIT_VECTOR是由多个位型数据组合起来的一组数据。例子如下:signal A_WORD :bit_vector(7downto0);

A_WORD <= X"0101_1100";

2、标准逻辑矢量型STD_LOGIC_VECTOR是由多个标准逻辑数据组合起来的。

3、字符串类型是由多个字符类型的数据组合起来的。

4、数组array是由多个相同类型的数据组成的集合。VHDL中有两种定义矩阵的方法,一种称为Constrained,另一种称为Unconstrained,两者之间的不同在于定义数组时索引值的范围不同。Constrained在数组定义时就已经确定了索引值的取值范围,例如:

type WORD is ARRAY(3downto0)of STD_LOGIC;

Unconstrained类型在定义数组时不给定具体的取值范围,而是在用数组类型定义一个对象时才给定索引范围,例如:

type BIT_VECTOR is ARRAY(NATURAL range<>)of BIT;

type STD_LOGIC_VECTOR is ARRAY(NATURAL range<>)of STD_LOGIC;

type STRING is ARRAY(POSITIVE range<>)of CHARACTER;

在工程中,大型的数组一般用变量或常量定义,用信号定义时,会影响仿真速度。

在VHDL做工程仿真时,经常会用ARRAY类型对存储器进行建模。

多维数组没有对应的底层硬件逻辑,因此多用于仿真和建模。

数组的赋值方法为:

signal H_BYTE :STD_LOGIC_VECTOR(0to7);

H_BYTE <=(7|6|0|1=> '1',2to5=> '0');

5、记录型RECORD

并不是所有综合器都支持记录类型,组成集合的数据至少要有两种以上不同的类型。文件类型(File)

目前常用的文件类型只有TEXT类型,IEEE的TEXTIO包集合中包含了TEXT文件常用的一些读写函数,方便设计者在开发时调用。综合器不支持,只能用于仿真。

(1).首先需要声明TextIO的包集

use声明输入、输出文件

file stim_a:text open read_mode is"";

file resp_out:text open write_mode is"";

variable line_in : line;

variable line_out :line;

(4).声明用于保存行变量中值的数据变量

variable a_tmp :integer;

variable rsp_tmp :integer;

(5).最后进行文件的读写。读文件时,先从文件中按行读出一行数据,再将行中的数据读到数据变量中。写文件时,先将数据变量组合成一行,再将行变量中的数据写入文件。需要注意的是只有variable型才是文件存取类型,不能使用signal型。TextIO包集中定义了一些常用的文件操作过程:

readline(file_var, line_var); --用于从文件file_var中读取一行数据到line_var read(line_var, data_var); --用于从line_var中读取数据保存到data_var中writeline(file_var, line_var); --用于将line_var写入到file_var中

write(line_var, data_var); --用于将data_var写入到line_var中

endfile(file_var); --判断file_var是否已经到文件末尾

属性

属性是指实体、结构体、类型及信号的一些表现特征。大部分信号类属性仅用于仿真,只有两个信号类属性(EVENT和STABLE)是可以综合的。

运算符

类型符号支持的数据对象类型

逻辑运算符AND, OR, NAND, NOR, XOR, XNOR, NOT BIT, BOOLEAN, STD_LOGIC

关系运算符=, /=任何数据类型

<, >, <=, >=枚举和整数类型以及对应的一维数组

算术运算符+, -, **, ABS整数类型

*, /, MOD, REM整数类型,操作数必须是2的乘方

移位运算符SLL, SRL, SLA, SRA, ROL, ROR BIT型一维数组或布尔型一维数组

并置运算符&, (,,,)BIT或一维数组

符号运算符正负:+, -整数类型

关系运算符返回值一定是BOOLEAN类型。关系运算的比较按以下方式进行:从最左

边按位比较,直到发现不相等的元素(位),长数组大于短数组。如:"1011">"10101";

"101"<"1010";

IEEE中只定义了SIGNED和UNSIGNED类型的移位运算,其他类型可以换一种写法

实现:

A sll2描述为 A <= A(5downto0)&"00";

算术运算符中真正能够综合的只有“+”、“-”、和“*”,对于“/”、“mod”、“rem”,在分母为2的乘方次常数时,可以将这些操作用位运算实现,因此是可以综合的。

VHDL的结构体描述方式

行为描述方式是从功能或算法方面对结构体进行描述,不需要包含任何结构信息。

其抽象程度高,主要采用函数、过程、进程语句的形式来表示。

数据流方式源于传统的布尔表达式设计思想,通过逻辑或算术表达式对信号或变量

赋值,表示信号在电路中的流动方向。数据流描述主要建立在并行信号赋值语句基

础上。这种方式对硬件水平要求高,易于综合,但不利于描述复杂逻辑事件。

结构化方式类似于文本方式的原理图设计。

Fpga相对于CPU模式的信号处理,最大的优势在于它能够并行地处理信号,而并发描述语句是实现并行信号处理的主要底层描述方法。

如果信号在多个进程中被赋值,这些驱动器的结果将会被连接在一起,形成多驱动的情况,应避免出现此情况。

Rtl级的VHDL也就是我们常说的可综合的那部分,所谓的rtl级建模,其实也就是用VHDL语言去描述实时电路的行为。在该层次上,最重要的思想就是“硬件意识”。

VHDL典型语句

赋值语句中的延时

在VHDL中存在惯性延时和传输延时两种类型。惯性延时的特性与信号脉冲持续时间有关,当信号持续时间小于惯性延时,输出信号将忽略该脉冲的存在。

传输延时不是默认的,必须用关键词TRANSPORT明确说明。传输延时常用于描述总线延时、连接线的延时及ASIC芯片中的路径延时。

不管哪种延时,都是电路固有的特性,与电路的材料、生产工艺、制作温度等相关。带入语句中的延时子句只能根据这些条件去模拟电路的延迟特性,而不能根据语句中的延时时间参数去综合生成具有指定延迟时间的电路。

换言之,延迟子句是不可综合的,综合器会忽略掉该延时。如a <=not b,a <=not b after 2ns, a <=transport not b after2ns这三条语句最后生成的电路完全一样。

顺序语句

1、使用不带else子句的if语句时,电路可能会引入锁存器。

2、Case语句没有优先级,其when后面的选择值可以选择并列数值,如3|5。

3、For…loop循环语句中,循环变量在使用前不需要声明。循环可以采用递增模式、递减模式以及循环次数范围三种方式。如:

for循环变量in x'RANGE loop

顺序语句;

end loop;

4、Wait语句的综合:wait on、wait for和wait语句是不可综合的。Wait until语句只有在条件表达式为时钟的边缘时,如wait until CLOCK = ‘1’时,是可综合的,否则也不可综合。由于在使用wait until语句时,process没有敏感信号列表,所以它必须是process的第一条语句。ISE中的XST,不支持任何wait语句的综合。

5、空操作NULL语句类似于计算机汇编语句中的NOP指令,执行该语句不进行任何操作,只是使程序执行下一个操作。

6、变量的综合:根据变量在程序中的使用情况的不同,变量综合后的结果可能是连线(wire)、锁存器(Latch)或寄存器(Register)。在时序电路的顺序描述语句中,如果变量在被赋值之前被读取,那么综合后将产生一个寄存器;如果这种情况发生在组合逻辑电路中,那么综合后将会产生一个锁存器。

7、断言语句(ASSERT):VHDL的断言语句类似于C语言中的断言语句,它是人机对话的一种重要手段。语法结构为:

assert条件表达式[report字符串信息][severity级别];

assert语句不描述任何硬件逻辑,通常综合器都会将其忽略,或给出一个警告,但它

在系统调试时很有用,可以帮助设计者很快找到设计中出现的问题。

并发语句

1、进程语句

一个进程语句只允许描述对应于一个时钟信号的同步时序逻辑。一个进程中只能描述针对于同一时钟的同步时序逻辑,而异步时序逻辑必须由多个进程来表达。

同步电路可由结构体中的多个进程描述,这是因为进程之间的通信可以通过传递信号和共享变量值来实现。

除非使用决断函数,否则在多个进程中,不允许对同一个信号赋值,但在同一个进程中可以对一个信号多次赋值。

进程内部是顺序语句,但进程语句本身是并行语句。

2、并行信号赋值语句

每一个信号赋值语句都相当于一条缩写的进程语句,而这条语句的所有输入信号都被隐性地列入此过程的敏感信号表中。

条件式信号代入语句是有优先级的,即使有多个条件为真,也只有第一个满足条件的表达式会被执行。条件信号赋值语句虽然可以写的很长,实际上是一条语句。

选择式信号代入语句,多路信号之间是并行的,没有优先级别。

3、元件说明和元件例化语句

元件说明语句的功能是将一个现成的设计实体定义或声明为一个元件;元件例化语句,它的功能是将调用的元件或模块的端口信号与结构体中的相应端口信号进行正确的连接,从而达到引用元件的目的。其中标号名(也称为例化名)相当于电路板中的一个插座名。

4、生成语句

生成语句的典型应用是生成存储器阵列和寄存器阵列。从软件运行结果来看,for…generate语句的循环变量虽然有顺序性,但最终结果是完全并行的。

5、块语句

块语句主要用于参数定义和信号的映射,包括Generic和Generic Map语句以及Port 和Port Map语句。

使用VHDL进行建模时,一般设计者很少使用块语句,尤其是卫式表达式语句,而且很多商用的综合器不支持块语句。通常情况下,选用进程语句更加高效。从综合的角度看,block 语句的存在毫无意义,因为将设计实体划分为多个块,只是形式上的改变并非功能上的改变。

并发语句的仿真模型

虽然并发语句在综合成底层电路后是并行的,但是并发语句的仿真是使用类似于PC机的处理器进行的,因此,理解并发语句的仿真模型,有助于更好的理解并发语句的执行过程。

VHDL的仿真器是由事件触发的,敏感信号列表中任一信号发生变化,并且变化信号满足触发条件时,仿真器就响应一次事件的处理。

事件的处理一般在离散的仿真时间点开始,仿真器将两个离散的时间点之间的间隔划分为多个增量时间,如图,每个增量时间内安排一个任务,一个任务即一个并发描述语句或一个进程语句。这样,设计中的每一个并发描述语句或进程都被安排在一个增量时间中。

离散仿真时间点当前时间点的并发操作

当前时间点内的增量时间当前时间点内的增量时间

9989991000D1D2D3Dn D1D2D3

……

图 1 离散仿真时间

事件处理的过程为:

按照增量时间顺序,对所有分配好的任务进行运算,但不进行最终的信号赋值,直

到全部并发语句都处于挂起状态。

更新全部信号的值。

信号发生变化后,对信号敏感的进程会重新被触发,仿真器在下一个离散时间点进

行事件的处理。

因此,虽然在仿真过程中,任务的处理是按照顺序进行的,但在用户看来,这些处理都是并行完成的。

子程序

子程序包含函数(Function)和过程(Procedure)两种,可以被反复调用,但是是非重入的程序。并且支持重载。子程序中出现的wait语句、信号声明和元件调用语句是不可综合的。

过程容易引起一些副作用,而且包含过程语句的工程也很难调试和维护,一般不用。

状态机FSM (Finite State Machine)

Moore型状态机的输出只与模块的当前状态有关;Mealy型状态机的输出与模块的当前状态和当前的输入信号都有关系。

工程设计中,建议使用枚举的方式定义状态机工作的不同状态,以便增强可读性。

编码的过程中要注意,用枚举方式定义的状态只能用同类型的枚举数据赋值,而不

能直接用数值赋值。采用枚举时,FPGA的综合器通常采用独热编码OHE(One Hot Encoding)的方式对枚举量进行编码。

通常建议工程师选用多进程的描述方式,而不是单进程的方式。多进程的描述结构

通常将时序逻辑、组合逻辑甚至输出逻辑分布在不同的进程中描述。这种结构可以

减少代码长度、增强代码的可读性,同时省去不必要的寄存器输出。

如果Moore型状态机的输出要寄存,则需要将输出控制语句用一个时序进程描述,但是要注意,寄存输出信号会增加一个周期的时延,如果要去除这一个周期的延时,则在进程中

可以使用NEXT_STATE代替CURR_STATE做控制。

如果Mealy型状态机的输出要寄存,则需要保证输出信号的逻辑是完全同步的。一种好的方法是,在结构体中定义一组信号,用这一组信号将输出值传递到输出端口。

相关主题
相关文档
最新文档