集成电路技术分享

 找回密码
 我要注册

QQ登录

只需一步,快速开始

搜索
查看: 946|回复: 1

VHDL语法小结

[复制链接]
fpga_feixiang 发表于 2018-8-7 17:43:55 | 显示全部楼层 |阅读模式
一个VHDL程序代码包含实体(entity)、结构体(architecture)、配置(configuration)、程序包(package)、库(library)等。

一、数据类型

1.用户自定义数据类型

使用关键字TYPE,例如:

TYPEmy_integer IS RANGE -32 TO 32;

–用户自定义的整数类型的子集

TYPEstudent_grade IS RANGE 0 TO 100;

–用户自定义的自然数类型的子集

TYPEstate IS (idle, forward, backward, stop);

–枚举数据类型,常用于有限状态机的状态定义

一般来说,枚举类型的数据自动按顺序依次编码。

2.子类型

在原有已定义数据类型上加一些约束条件,可以定义该数据类型的子类型。VHDL不允许不同类型的数据直接进行操作运算,而某个数据类型的子类型则可以和原有类型数据直接进行操作运算。

子类型定义使用SUBTYPE关键字。

3.数组(ARRAY)

ARRAY是将相同数据类型的数据集合在一起形成的一种新的数据类型。

TYPEtype_name IS ARRAY (specification) OF data_type;

–定义新的数组类型语法结构

SIGNALsignal_name: type_name [:= initial_value];

–使用新的数组类型对SIGNAL,CONSTANT, VARIABLE进行声明

例如:

TYPEdelay_lines IS ARRAY (L-2 DOWNTO 0) OF SIGNED (W_IN-1 DOWNTO 0);

–滤波器输入延迟链类型定义

TYPEcoeffs IS ARRAY (L-1 DOWNTO 0) OF SIGNED (W_COEF-1 DOWNTO 0);

–滤波器系数类型定义

SIGNALdelay_regs: delay_lines;  – 信号延迟寄存器声明

CONSTANTcoef: coeffs := (    ); –常量系数声明并赋初值

4.端口数组

在定义电路的输入/输出端口时,有时需把端口定义为矢量阵列,而在ENTITY中不允许使用TYPE进行类型定义,所以必须在包集(PACKAGE)中根据端口的具体信号特征建立用户自定义的数据类型,该数据类型可以供包括ENTITY在内的整个设计使用。

—————————————PACKAGE———————————-

libraryieee;

useieee.std_logic_1164.all;

——————————————

PACKAGEmy_data_types IS

     TYPE vector_array IS ARRAY (natural range<>) OF STD_LOGIC_VECTOR(7 DOWNTO 0); –声明8位的数组

ENDmy_data_types;

———————————–MainCode—————————————

libraryieee;

useieee.std_logic_1164.all;

usework.my_data_types.all; –用户自定义包集

——————————————————————

ENTITYmux IS

PORT(inp: IN vector_array(0 to 3);

ENDmux;

——————————————————————————-

5.有符号数和无符号数

要使用SIGNED和UNSIGNED类型数据,必须在代码开始部分声明ieee库中的包集std_logic_arith。它们支持算术运算但不支持逻辑运算。

libraryieee;

useieee.std_logic_1164.all;

useieee.std_logic_arith.all;

……

SIGNALa: IN SIGNED (7 DOWNTO 0);

SIGNALb: IN SIGNED (7 DOWNTO 0);

SIGNALx: IN SIGNED (7 DOWNTO 0);

……

v<= a + b;

w<= a AND b;  –非法(不支持逻辑运算)

——————————————————————————-

STD_LOGIC_VECTOR类型的数据不能直接进行算术运算,只有声明了std_logic_signed和std_logic_unsigned两个包集后才可以像SIGNED和UNSIGNED类型的数据一样进行算术运算。

6.数据类型转换

在ieee库的std_logic_arith包集中提供了许多数据类型转换函数:

1.conv_integer(p): 将数据类型为INTEGER,UNSIGNED,SIGNED,STD_ULOGIC或STD_LOGIC的操作数p转换成INTEGER类型。不包含STD_LOGIC_VECTOR。

2. conv_unsigned(p,b):将数据类型为INTEGER,UNSIGNED,SIGNED或STD_ULOGIC的操作数p转换成位宽为b的UNSIGNED类型数据。

3. conv_signed(p,b):将数据类型为INTEGER, UNSIGNED,SIGNED或STD_ULOGIC的操作数p转换成位宽为b的SIGNED类型的数据。

4.conv_std_logic_vector(p, b):将数据类型为INTEGER,UNSIGNED, SIGNED或STD_LOGIC的操作数p转换成位宽为b的STD_LOGIC_VECTOR类型的数据。

二、运算操作符和属性

.运算操作符

赋值运算符

赋值运算符用来给信号、变量和常数赋值。

<=    用于对SIGNAL类型赋值;

:=     用于对VARIABLE,CONSTANT和GENERIC赋值,也可用于赋初始值;

=>    用于对矢量中的某些位赋值,或对某些位之外的其他位赋值(常用OTHERS表示)。

例:

SIGNALx: STD_LOGIC;

VARIABLEy: STD_LOGIC_VECTOR(3 DOWNTO 0);  –最左边的位是MSB

SIGNALw: STD_LOGIC_VECTOR(0 TO 7);  –最右边的位是MSB

x<= ‘1’;

y:= “0000”;

w<= “1000_0000”;  – LSB位为1,其余位为0

w<= (0 => ‘1’, OTHERS => ‘0’);  –LSB位是1, 其他位是0

逻辑运算符

操作数必须是BIT, STD_LOGIC或STD_ULOGIC类型的数据或者是这些数据类型的扩展,即BIT_VECTOR,STD_LOGIC_VECTOR,STD_ULOGIC_VECTOR。

VHDL的逻辑运算符有以下几种:(优先级递减)

&#376;   NOT —— 取反

&#376;   AND —— 与

&#376;   OR —— 或

&#376;   NAND —— 与非

&#376;   NOR —— 或非

&#376;   XOR —— 异或

算术运算符

操作数可以是INTEGER, SIGNED,UNSIGNED, 如果声明了std_logic_signed或std_logic_unsigned,可对STD_LOGIC_VECTOR类型的数据进行加法或减法运算。

+—— 加

-          —— 减

*—— 乘

/—— 除

**—— 指数运算

MOD—— 取模

REM—— 取余

ABS—— 取绝对值

加,减,乘是可以综合成逻辑电路的;除法运算只在除数为2的n次幂时才能综合,此时相当于对被除数右移n位;对于指数运算,只有当底数和指数都是静态数值(常量或GENERIC参数)时才是可综合的;对于MOD运算,结果的符号同第二个参数的符号相同,对于REM运算,结果的符号同第一个参数符号相同。

关系运算符

=,/=, <, >, <=, >=

左右两边操作数的类型必须相同。

l  移位操作符

<左操作数> <移位操作符> <右操作数>

其中左操作数必须是BIT_VECTOR类型的,右操作数必须是INTEGER类型的(可以为正数或负数)。

VHDL中移位操作符有以下几种:

u  sll  逻辑左移  – 数据左移,右端补0;

u  srl  逻辑右移  – 数据右移,左端补0;

u  sla  算术左移  – 数据左移,同时复制最右端的位,填充在右端空出的位置;

u  sra  算术右移  – 数据右移,同时复制最左端的位,填充在左端空出的位置;

u  rol  循环逻辑左移 — 数据左移,从左端移出的位填充到右端空出的位置上;

u  ror  循环逻辑右移 – 数据右移,从右端移出的位填充到左端空出的位置上。

例:x <= “01001”,那么:

y<= x sll 2;  – 逻辑左移2位,y<=”00100”

y<= x sla 2;  – 算术左移2位,y<=”00111”

y<= x srl 3;  – 逻辑右移3位,y<=”00001”

y<= x sra 3;  – 算术右移3位,y<=”00001”

y<= x rol 2;  – 循环左移2位,y<=”00101”

y<= x srl -2;  –相当于逻辑左移2位

并置运算符

用于位的拼接,操作数可以是支持逻辑运算的任何数据类型。有以下两种:

  &

(, , , )

与Verilog中{}的功能一样。

2. 属性(ATTRIBUTE)

数值类属性

数值类属性用来得到数组、块或一般数据的相关信息,例如可用来获取数组的长度和数值范围等。

以下是VHDL中预定义的可综合的数值类属性:

d’LOW             –返回数组索引的下限值

d’HIGH            –返回数组索引的上限值

d’LEFT             –返回数组索引的左边界值

d’RIGHT            –返回数组索引的右边界值

d’LENGTH       –返回矢量的长度值

d’RANGE          –返回矢量的位宽范围

d’REVERSE_RANGE   –按相反的次序返回矢量的位宽范围

例:定义信号 SIGNAL d:STD_LOGIC_VECTOR(7 DOWNTO 0);

则有:d’LOW = 0, d’HIGH = 7,d’LEFT = 7, d’RIGHT = 0, d’LENGTH = 8, d’RANGE = (7 DOWNTO 0), d’REVERSE_RANGE= (0 TO 7).

信号类属性

对于信号s,有以下预定义的属性(可综合的):

s’EVENT            若s的值发生变化,则返回布尔量TRUE,否则返回FALSE

s’STABLE          若s保持稳定,则返回TRUE,否则返回FALSE

例:clk的上升沿判断

IF(clk’EVENT AND clk = ‘1’)

IF(NOT clk’STABLE AND clk = ‘1’)

WAITUNTIL (clk’EVENT AND clk = ‘1’)

3. 通用属性语句

GENERIC语句提供了一种指定常规参数的方法,所指定的参数是静态的,增加了代码的可重用性,类似于Verilog中的parameter与defparam。GENERIC语句必须在ENTITY中进行声明,由GENERIC语句指定的参数是全局的,不仅可在ENTITY内部使用,也可在后面的整个设计中使用。语法结构如下:

GENERIC(parameter_name: parameter_type := parameter_value);

用GENERIC语句指定多个参数:

GENERIC(n: INTEGER := 8; vector: BIT_VECTOR := “0000_1111”);

三、并发代码

VHDL中并发描述语句有WHEN和GENERATE。除此之外,仅包含AND, NOT, +, *和sll等逻辑、算术运算操作符的赋值语句也是并发执行的。在BLOCK中的代码也是并发执行的。

从本质上讲,VHDL代码是并行执行的。只有PROCESS, FUNCTION,PROCEDURE内部的代码才是顺序执行的。但是当它们作为一个整体时,与其他模块之间又是并行执行的。并发代码称为“数据流”代码。

通常我们只能用并发描述语句来实现组合逻辑电路,为了实现时序逻辑电路,必须使用顺序描述语句。事实上,使用顺序描述语句可以同时实现组合逻辑电路和时序逻辑电路。

在并发代码中可以使用以下各项:

&#216;  运算操作符

&#216;  WHEN语句(WHEN/ELSE或WITH/SELECT/WHEN)

&#216;  GENERATE语句

&#216;  BLOCK语句

使用运算操作符

运算类型

运算操作符

操作数类型

逻辑运算

NOT, AND, NAND,OR

NOR, XOR, XNOR

BIT, BIT_VECTOR,STD_LOGIC, STD_LOGIC_VECTOR

STD_ULOGIC,STD_ULOGIC_VECTOR

算术运算符

+, —, *, /, **

INTEGER, SIGNED,UNSIGNED

比较运算符

=, /=, <, >, <=, >=

任意数据类型

移位运算符

sll, srl, sla, sra,rol, ror

BIT_VECTOR

并置运算符

&,(, , ,)

STD_LOGIC,STD_LOGIC_VECTOR, STD_ULOGIC

STD_ULOGIC_VECTOR,SIGNED, UNSIGNED

WHEN语句

WHEN语句是一种基本的并发描述语句,有两种形式:WHEN/ELSE和WITH/SELECT/WHEN。

WHEN/ELSE语法结构:

assignmentWHEN condition ELSE

assignmentWHEN condition ELSE

…;

WITH/SELECT/WHEN语法结构

WITHidentifier SELECT

assignmentWHEN value,

assignemntWHEN value,

…;

当使用WITH/SELECT/WHEN时,必须对所有可能出现的条件给予考虑,使用关键字OTHERS,如果在某些条件出现时不需要进行任何操作,那应该使用UNAFFECTED。

例:



————————————-withWHEN/ELSE——————————————-

Output<= “000” WHEN (inp = ‘0’ OR reset = ‘1’) ELSE

                “001” WHEN ctl = ‘1’ ELSE

                “010”;

———————————–withWITH/SELECT/WHEN——————————–

WITHcontrol SELECT

       Output <= “000” WHEN reset,

                       “111” WHEN set,

                       UNAFFECTED WHEN OTHERS;

对于WHEN语句,WHEN value的描述方式有以下几种:

WHENvalue                           –针对单个值进行判断

WHENvalue1 to value2          –针对取值范围进行判断

WHENvalue1 | value2 | …      –针对多个值进行判断

GENERATE语句

GENERATE语句和顺序描述语句中的LOOP语句一样用于循环执行某项操作,通常与FOR一起使用。语法结构如下:

label:FOR identifier IN range GENERATE

       (concurrent assignments)

ENDGENERATE

GENERATE语句还有另一种形式:IF/GENERATE,此处不允许使用ELSE。IF/GENERATE可以嵌套在FOR/GENERATE内部使用。反之亦然。

Label1:FOR identifier IN range GENERATE

……

       Label2: IF condition GENERATE

              (concurrent assignments)

       END GENERATE;

……

ENDGENERATE;

例:

SIGNALx: BIT_VECTOR(7 DOWNTO 0);

SIGNALy: BIT_VECTOR(15 DOWNTO 0);

SIGNALz: BIT_VECTOR(7 DOWNTO 0);

……

G1:FOR i IN x’RANGE GENERATE
zhangyukun 发表于 2018-8-8 09:24:34 | 显示全部楼层
VHDL语法小结
您需要登录后才可以回帖 登录 | 我要注册

本版积分规则

关闭

站长推荐上一条 /1 下一条

QQ|小黑屋|手机版|Archiver|fpga论坛|fpga设计论坛 ( 京ICP备20003123号-1 )

GMT+8, 2025-5-1 23:57 , Processed in 0.064485 second(s), 20 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表