文章翻译自 VHDL-2008: Easier to use。如有错误,请指出
引言:VHDL-2008中的增强是为了让VHDL用起来更简单。这些(增强)都是对语言的少量添加或对语法的细微更改,但它们将对VHDL的设计产生实质上的影响。
1. 新的条件运算符
在VHDL-2008之前,VHDL的if语句要求的是布尔表达式,如果A和B的类型是std_logic,那我们必须写成:
if A = '1' and B = '1' then
...
VHDL-2008引入了一个新的运算符:??,称为条件运算符,可以将一个std_logic类型转为布尔表达式(boolean),‘1’和‘H’表示为TRUE,其余为FALSE(它同样可以将bit转化为boolean)。所以,现在代码可以写成这样:
if ?? A and B then
...
或者更简洁,在某些情况下,?? 是可以省略的。if语句就是其中一种情况,所以代码也可以写成这样:
if A and B then
...
2. 增强的位字符串(Enhanced bit string literals)
你可能使用string literals作为std_logic_vector或者其他类似的类型的值,例如:
signal count : unsigned(7 downto 0);
...
count <= "00000000"
在VHDL-1987中,string literals实际上提供了一种将向量表示转为二进制的方法。VHDL-1993则引入了二进制、八进制和十六进制位字符串(bit string literals)
count <= B"0000_0000"; -- "_" 仅为了提高可读性
count <= X"00"; -- X是十六进制,O是八进制
VHDL-1993中的一个限制是十六进制的位字符串始终是4 bits的倍数,而八进制位字符串始终是3 bits的倍数。例如,它不能有10位十六进制位字符串,也不能包含0、1或_以外的值。
在VHDL-2008中,位字符串得到了加强:
- 可以有明确的位宽
- 可以声明为signed和unsigned类型
- 可以包含meta-values(‘U’,'X’等)
例子如下:
variable S : std_logic_vector(5 downto 0);
begin
S := 6x"0f"; -- specify width 6
S := 6x"XF"; -- means "XX1111"
S := 6SX"F"; -- "111111" (sign extension)
S := 6Ux"f"; -- "001111" (zero extension)
S := 6sb"11"; -- "111111" (binary format)
S := 6uO"7"; -- "000111" (octal format)
注意,在位字符串中,允许使用大写或小写字幕,如F和f
3. 层级名称(Hierarchical names)
VHDL-2008中的部分新功能仅用于验证,而不是设计。验证工程师总是希望编写self-checking测试环境,这在VHDL中很难办到,因为没有一个简单的办法从验证环境的顶层直接访问设计层级中的signal和variable。
VHDL-2008通过引入外部名称(external names)来解决此问题。外部名称可能指位于设计层级结构另一部分的(共享)variable、signal或常量。外部名称嵌于双尖括号中<< >>
特殊字符可用于向上移动层级(比如 ^ )或是去到package的根路径(比如@),举个例子:
<< signal .tb.uut.o_n : std_logic >> -- hierarchical signal name
<< signal ^.^.a : std_logic >> -- signal a two levels above
<< variable @lib.pack.v : bit >> -- variable in a package pack
外部名称的其他用途包括在测试环境中注入错误(injecting error)以及forcing or release value(见后文)。
4. 集合中的向量(Vectors in aggregates)
VHDL集合允许将一组单独的数组(array)或元素构成一个值,对于数组,VHDL1076-2002的版本允许语法像下面这样:
variable V : std_logic_vector(7 downto 0);
begin
V := (others => '0'); -- "00000000"
V := ('1', '0', others => '0'); -- "10000000"
V := (4 => '1', others => '0'); -- "00010000"
V := (3 downto 0 => '0', others => '1'); -- "11110000"
-- V := ("0000", others => '1'); -- illegal!
VHDL-2008允许数组集合中使用切片(slice),即上个例子可以写成这样:(注意第二和第五个赋值的变化)
V := (others => '0'); -- "00000000"
V := ("10", others => '0'); -- "10000000"
V := (4 => '1', others => '0'); -- "00010000"
V := (3 downto 0 => '0', others => '1'); -- "11110000"
V := ("0000", others => '1'); -- "00001111"
当然,你也可以使用集合作为赋值的目标,比如:
( S(3 downto 0), S(7 downto 4)) <= S; -- swap nibbles
( 3 downto 0 => S, 7 downto 4 => S) <= S; -- using named association
5. 条件语句和顺序选择语句(Conditional and selected sequential statements)
VHDL语法有两种执行风格:并发执行和顺序执行。你无法对signal使用条件赋值语句如:
z <= x when x > y else y;
VHDL-2008放宽了这个限制,并允许在process中像下面这样生成一个触发器:
process(clock)
begin
if rising_edge(clock) then
q <= '0' when reset else d; -- not allowed in VHDL 2002
end if;
end process;
它还允许在process中使用selected信号赋值:
process(clock)
begin
if rising_edge(clock) then
with s select -- equivalent to a case statement
q <= a when "00",
b when "01",
c when "10",
d when "11";
end if;
end process;
6. generate 的拓展(Extensions to generate)
VHDL-2008使‘generate’语句更加灵活,他现在允许使用‘else’和‘elseif’。此外还有使用case的‘generate’
这使得‘generate’更便于使用。你不必再写成这样:
g1: if mode = 0 generate
c1 : entity work.comp(rtl1)
port map (a => a, b => b);
end generate;
g2: if mode = 1 generate
c1 : entity work.comp(rtl2)
port map (a => a, b => b);
end generate;
g3: if mode = 2 generate
c1 : entity work.comp(rtl3)
port map (a => a, b => b);
end generate;
而是可以写成case…generate
g1: case mode generate
when 0 =>
c1 : entity work.comp(rtl1)
port map (a => a, b => b);
when 1 =>
c1 : entity work.comp(rtl2)
port map (a => a, b => b);
when 2 =>
c1 : entity work.comp(rtl3)
port map (a => a, b => b);
when others =>
end generate;
或者if…elsif…else generate
g1: if mode = 0 generate
c1 : entity work.comp(rtl1)
port map (a => a, b => b);
elsif mode = 1 generate
c1 : entity work.comp(rtl2)
port map (a => a, b => b);
elsif mode = 2 generate
c1 : entity work.comp(rtl3)
port map (a => a, b => b);
else generate
end generate;
注意,在每个分支中,你可以声明不与其他分支名称冲突本地名称(比如上面的c1),且仍可以用 begin-end 在分支中声明本地对象。when others和else generate分支可以是空的(不做任何事)或是像其他分支一样包含语句。
7. 简化的敏感信号列(Simplified sensitivity lists.)
当关键词‘all’被用于灵敏度的上下文中,便意味着process中的所有signals都被添加到了sensitivity list中,如:
process(all)
begin
case state is
when idle =>
if in1 then
nextState <= Go1;
end if;
when Go1 =>
nextState <= Go2;
when Go2 =>
nextState <= Idle;
end case;
end process;
这避免了作者在修改组合逻辑的process后忘记更新sensitivity list,从而导致模拟/合成不匹配的常见问题
8. 在std_logic_vector上做算术运算(Arithmetic on std_logic_vector)
VHDL有一个写的很好的package:IEEE.Numeric_std,里面创建了两种新的数据类型:unsigned和signed。然而,有时直接对 std_logic_vector 进行算术运算会更方便——将其视为二进制补码或无符号数。
在之前这主要通过两个非标准的包(std_logic_unsigned和std_logic_signed)来实现。而VHDL-2008通过添加两个新的标准算数包IEEEN.Numeric_std_Unsigned和IEEE.Numeric_std_signed来实现。