VHDL提供了6种预定义的运算操作符:
赋值运算符用于给信号,变量,常数赋值,有以下三种:
<=:用于对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
逻辑运算符的操作数必须是bit,std_logic,std_ulogic类型数据,或是这些数据类型的拓展,即bit_vector,std_logic_vector,std_ulogic_vector等
这些运算符的优先级由上至下递减
操作数可以是integer,signed,unsigned或是real,其中real类型不可综合
如果声明了ieee库中的包集std_logic_signed和std_logic_unsigned,即可对srd_logic_vector类型进行加法和减法运算
VHDL中有以下8中运算操作符
上述运算符中,加法,减法,乘法运算符可以综合成逻辑电路。
对于除法运算,只有除数为2的n次幂时才可以进行综合,此时除法操作对于的时将被除数向右进行n次移位。
对于指数运算,只有当底数和指数都是静态数值(常量或是generic参数)时才是可综合的。
需要注意的是,y MOD x运算的结果是y除以x所得的模数,运算结果通过信号x返回,y REM x运算结果是y除以x所得的余数,结果通过信号y返回。MOD,REM,ABS通常是不可综合的
关系运算符左右两边操作数必须相同
语法结构:
<左操作数><移位操作符><右操作数>
左操作数必须是bit_vector类型的,右操作数必须是integer类型(前面可以加正负号)
VHDL中操作数有以下几种:
例
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"
用于位的拼接,操作数可以是支持逻辑运算的任何数据类型。
并置运算符有以下两种:
z <= x & "1000000"; --如果x <= '1',那么z <= "11000000"
z <= ('1','1','0','0','0','0','0','0'); --z <= "11000000"
VHDL中预定义的属性分为数值类属性和信号类属性
数值类属性用来得到数值,块或一般数据的相关信息,例如可用来获取数组的长度和数值范围等
VHDL中可综合的数值类属性如下(以某一数值d为例)
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定义了如下属性
通常,枚举数据类型的属性不可综合
对于信号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)... --调用一个函数
首先进行声明,然后进行属性描述,格式如下
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”
用户可以在除了包集之外的任何地方进行用户自定义属性的声明。
用户除了可以自定义属性,还可以自定义操作符,用户自定义的操作符可以和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类型数据进行加法运算
(...)
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;
一个通用奇偶效验发生器电路,先对输入进行奇偶效验,然后根据效验结果在输入数据前补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"