VHDL语法入门 (三) 运算操作符与属性

1.运算操作符

VHDL提供了6种预定义的运算操作符:

  • 赋值运算符
  • 逻辑运算符
  • 算术运算符
  • 关系运算符
  • 移位运算符
  • 并置运算符

1.1赋值运算符

赋值运算符用于给信号,变量,常数赋值,有以下三种:

<=:用于对signal赋值

:=:用于variable,constant,generic赋值,也可以用来赋予初值

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

例:

--变量声明
signal x:std_logic;
variable y:std_logic_vector(3 downto 0);
signal z:std_logic_vector(0 to 7);
--赋值
x <= '1';
y := "0000";
z <= "10000000";    --最低位是1,其他位是0
z <= (0 => '1', others => '0');    --最低位是1,其他位是0

1.2逻辑运算符

逻辑运算符的操作数必须是bit,std_logic,std_ulogic类型数据,或是这些数据类型的拓展,即bit_vector,std_logic_vector,std_ulogic_vector等

  • not——取反
  • and——与
  • or——或
  • nand——与非
  • nor——或非
  • xor——异或
  • xnor——同或

这些运算符的优先级由上至下递减

1.3算术运算符

操作数可以是integer,signed,unsigned或是real,其中real类型不可综合

如果声明了ieee库中的包集std_logic_signed和std_logic_unsigned,即可对srd_logic_vector类型进行加法和减法运算

VHDL中有以下8中运算操作符

  • +         加
  • -          减
  • *          乘
  • /           除
  • **         指数运算
  • MOD   取模
  • REM    取余
  • ABS     取绝对值

上述运算符中,加法,减法,乘法运算符可以综合成逻辑电路。

对于除法运算,只有除数为2的n次幂时才可以进行综合,此时除法操作对于的时将被除数向右进行n次移位。

对于指数运算,只有当底数和指数都是静态数值(常量或是generic参数)时才是可综合的。

需要注意的是,y MOD x运算的结果是y除以x所得的模数,运算结果通过信号x返回,y REM x运算结果是y除以x所得的余数,结果通过信号y返回。MOD,REM,ABS通常是不可综合的

1.4关系运算符

  • =     等于
  • /=    不等于
  • <     小于
  • >     大于
  • <=   小于等于
  • >=   大于等于

关系运算符左右两边操作数必须相同

1.5移位运算符

语法结构:

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

左操作数必须是bit_vector类型的,右操作数必须是integer类型(前面可以加正负号)

VHDL中操作数有以下几种:

  • sll --逻辑左移,右端空出来的位置填充‘0’
  • srl --逻辑右移,左端空出来的位置填充‘0’
  • sla --算术左移,同时复制最右端的位,数据左移后填充到右端空出来的位置
  • sra --算术右移,同时复制最左端的位,数据右移后填充到左端空出来的位置
  • rol --循环逻辑左移,同时从左端的移位依次填充到右端空出来的位置
  • ror --循环逻辑右移,同时从右端的移位依次填充到左端空出来的位置

x <= "01001";

y <= x sll 2; --逻辑左移:y <= "00100"
y <= x sla 2; --算术左移:y <= "00111"
y <= x srl 3; --逻辑右移:y <= "00001"
y <= x sra 3; --算术右移:y <= "00001"
y <= x rol 2; --循环逻辑左移:y <= "00101"
y <= x srl -2; --循环逻辑右移,等同与循环逻辑左移:y <= "00101"

1.6并置运算符

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

并置运算符有以下两种:

  • &
  • (,,,)
z <= x & "1000000";    --如果x <= '1',那么z <= "11000000"
z <= ('1','1','0','0','0','0','0','0');    --z <= "11000000"

2.属性

VHDL中预定义的属性分为数值类属性和信号类属性

2.1数值类属性

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

VHDL中可综合的数值类属性如下(以某一数值d为例)

  • 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'reversr_range = (0 to 7);

对于枚举类型,VHDL定义了如下属性

  • d'VAL(pos) 返回指定位置(pos)的值
  • d'POS(value) 给出数值(value),返回其位置序号
  • d'LEFTOF(value) 给出数值(value),返回其左侧的值
  • d'VAL(row,column) 返回给定行/列位置对应的值

通常,枚举数据类型的属性不可综合

2.2信号类属性

对于信号s,有以下预定义的属性

  • s'EVENT 如果s的值发生了变化,则返回布尔TRUE,否则返回FALSE
  • s'STABLE 如果s稳定,没有变化发生,则返回布尔量TRUE,否则返回FALSE
  • s'ACTIVE 如果当前s=‘1’,则返回TRUE,否则返回FALSE
  • s'QUIET 如果指定时间内s没有发生变化,则返回TRUE,否则返回FALSE
  • s'LAST_EVENT 计算上一次事件发生变化到现在所经历的时间,并返回这个时间值
  • s'LAST_ACTIVE 返回最后一次s=‘1’到现在所经历的时间长度
  • s'LAST_VALUE 返回最后一次变化前s的值

其中,s'EVENT,s'STABLE是可综合的,其他仅适用于仿真

if (clk'event and clk = '1')...        --event搭配if使用
if (not clk'stable and clk = '1')...    --stable搭配if使用
wait until(clk'event and clk = '1')...    --event打配wait使用
if rising_edge(clk)...    --调用一个函数

2.3用户自定义属性

首先进行声明,然后进行属性描述,格式如下

ATTRIBUTE number_of_inputs : integer;    --属性声明
ATTRIBUTE number_of_inputs of nand3: signal is 3;    --属性描述
...
inputs <= nand3'number_of_inputs;    --属性调用,返回值为3

对于type state is (idle,forward,backward,stop);前面我们介绍过通常枚举类型的数据会自动进行编码,除非用户进行了特别声明。例如上述state类型中,“00”表示第一个状态(idle),“01”表示第二个状态(forward),“10”表示第三个状态(backward),“11”表示第三个状态(stop)。通过用户自定义属性,可以改变默认的编码次序。

attribute enum_endcoding of state:type is “11 00 10 01”;

此时,编码次序就会变为idle = “11”,forward=“00”,backward=“10”,stop=“01”

用户可以在除了包集之外的任何地方进行用户自定义属性的声明。

2.4操作符拓展

用户除了可以自定义属性,还可以自定义操作符,用户自定义的操作符可以和VHDL中预定义的操作符具有相同的名称,例如我们用“+”定义一种新的加法运算,其操作数作为BIT_VECTOR类型,这样就对原来的操作符进行了拓展

例(实现对一个整数和一个1位二进制数进行加法运算,这里构造了一个函数,关于函数部分之后会介绍)

--建立函数
function "+" (a: integer; b: bit) return integer is
begin
    if(b='1')then return a+1;
    else returna;
    end if;
end "+";
--调用函数
signal inp1,outp:integer range 0 to 15;
signal inp2:bit;
(...)
outp <= 3+inp1+inp2;    --第一个+是预定义的操作符,第二个+是用户自定义的操作符,能够对一个整数和一个一位bit类型数据进行加法运算
(...)

2.5通用属性语句

GENERIC(属性)语句提供了一种指定常规参数的方法,所指定的参数是静态的,设计人员可以根据设计需求进行参数修改。

GENERIC语句必须在ENTITY中进行声明,GENERIC语句指定的参数是全局的,不仅可以在ENTITY内部使用,可以在整个设计中使用

语法结构如下

        GENERIC (parameter_name: parameter_type := parameter_value);

例:

entity my_entity if
    generic(n: integer := 8; vector: bit_vector := "00001111");    --声明了两个参数,之后出现的n与vector其值为8和00001111
    port (...);
end my_entity;

3.实例

一个通用奇偶效验发生器电路,先对输入进行奇偶效验,然后根据效验结果在输入数据前补0或1然后输出

entity parity_gen is
    generic(n: integer := 7);
    port(
        input: in bit_vector(n-1 downto 0);
        output: out bit_vector(n downto 0));
end parity_gen;

architecture parity of parity_gen is
begin
    process(input)
        variable temp1: bit;
        variable temp2: bit_vector(output'range);
    begin
        temp1 := '0';
        for i in input'range loop
            temp1 := temp1 xor input(i);
            temp2(i) := input(i);
        end loop;
            temp2(output'high) := temp1;
            output <= temp2;
    end process;
end parity;

运行上面程序,当输入为"0000000"时,输出"00000000",输入为"0000001"时,输出为"10000001"

  • 25
    点赞
  • 66
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值