在VHDL语言中没有类似C语言中的#define语句定义宏来实现字符常量(用字符代替常数)。但VHDL语言中也有类似的机制实现常量的定义和使用,一般有两种方法实现,一种为。参数、常量的定义和使用也预编译的一种,即在VHDL语言工程在真正编译前先扫描各个VHDL文件,将参数和符号常量替换成常数才进行真正的编译。使用符号常量代替常数有诸多优点:
(1)语义比直接使用常数更加清晰;
(2)容易修改和替换;
比如在一个设计多出使用了4位位宽数据或地址总线,如data( 3 downto 0)。但后续设计时如果想修改为8位总线接口,就要找到每一个相关的4位接口并逐一修改,不仅费时费力,还容易出错。但如果采用参数化设计,或利用constant声明符号常量,只要在声明处修改一处即可。
(3)利用Generic实现参数传递,可在元件声明时重新设置参数值达到最大限度重用代码的效果。
例1 利用Generic设计参数化奇偶校验码。
(1)设计实体程序
entity even_odd is generic ( WIDTH : integer := 4 ); Port ( a : in bit_vector( WIDTH-1 downto 0); c : out bit_vector( WIDTH downto 0) ); end even_odd; architecture arch_even_odd of even_odd is signal cal_odd: bit ; begin cal_odd <= xor a; --reduction xor operator c <= cal_odd & a ; end arch_even_odd;
实体设计程序中利用generic声明了整形参数WIDTH,初值为4。 在构造体的行为逻辑区,利用缩减运算符(reduction operator)XOR实现了信号a(位矢量)中所有位中’1’的数量奇偶统计。如果a中’1’的数量为奇数,则表达式XOR a返回’1′,否则返回’0’。如:
cal_odd <= xor a; –reduction xor operator
但需要注意,该语句是VHDL 2008语法格式。在Vivado中使用时需要在文件属性里指定为VHDL 2008 才能正确编译。如图1所示,
图1
语句 c <= cal_odd & a ; 采用并位操作符将,将xor a的计算结果并位到a的左边形成偶校验码。
(2)仿真程序
entity tb_odd_gen is -- Port ( ); end tb_odd_gen; architecture Behavioral of tb_odd_gen is constant tb_WIDTH :integer :=8; signal tb_a : bit_vector (tb_WIDTH-1 downto 0); signal even_out: bit_vector (tb_WIDTH downto 0); component even_odd generic ( WIDTH : integer ); port ( a : in bit_vector(WIDTH-1 downto 0); c : out bit_vector(WIDTH downto 0) ); end component; begin odd_gen: even_odd generic map ( WIDTH => tb_WIDTH ) port map( a => tb_a, c =>even_out ); --tb_a<= B"0000_0000", B"0000_0001" after 10 ns , B"0000_0010" after 20 ns, B"0010_0011" after 30 ns, -- B"0011_0111" after 40 ns, B"1000_1000" after 50 ns; tb_a<= "00000000", "00000001" after 10 ns , "00000010" after 20 ns, "00100011" after 30 ns, "00110111" after 40 ns, "10001000" after 50 ns; end Behavioral;
仿真程序中给出部分位矢量的,并没有给出全部的检查。 有两种格式可以使用,如:
tb_a<= B”0000_0000″, B”0000_0001″ after 10 ns , B”0000_0010″ after 20 ns, B”0010_0011″ after 30 ns, — B”0011_0111″ after 40 ns, B”1000_1000″ after 50 ns;
第一种格式明确指出数据的进位格式B表示二进制格式,此时可以使用”_”分割二进制数据,提高数据的可读性。
tb_a<= “00000000”, “00000001” after 10 ns , “00000010” after 20 ns, “00100011” after 30 ns, “00110111” after 40 ns, “10001000” after 50 ns;
第二种格式没有明确指出数据的进位格式,此时编译器根据赋值语句左右的类型进行匹配,但此时不可以使用”_”分割二进制数据。
利用语句constant tb_WIDTH :integer :=8; 将tb_WIDTH设为常量8,并修改设计实体的参数,实现8位参数传递。
(3)仿真波形
图2
从图2的波形可以看出,even_out实行了偶校验结果。