1.并发代码
VHDL代码按照执行顺序可以分为并发代码和顺序代码,即并行与串行
并发描述语句有when和generate,此外,仅包含and,not,+,*和sll等操作符的赋值语句也是并发执行的。在块(block)中的代码也是并发执行的
1.1when语句
when语句分为when/else(又称simple when)和when/select/when(又称select when)两种
--when/else
assignment when condition else
assignment when condition else
...;
--when/select/when
assignment when value,
assignment when value,
...;
--例
--when/else
outp <= "000" when (inp = '0' or reset = '1') else
"001" when ctl ='1' else
"010";
--when/select/when
--当使用with/select/when时,必须对所有可能出现的条件(condition)予以考虑,所以常使用关键字others。
with control select
output <= "000" when reset,
"111" when set,
unaffected when others; --如果在某些条件出现时不需要进行任何操作,可以使用UNAFFECTED
--当需要对多种情况进行判断时,when value的描述方式包括以下3种
when value --针对单个值进行判断
when value1 to value2 --针对取值范围进行判断,使用枚举类型
when value1 | value2 | ... --针对多个值进行判断
1.2generate语句
generate是另一种基本的并发现描述语句,它和顺序描述语句中的loop语句一样用于循环执行某项操作,通常与for一起使用
语法结构
--for/generate
label: for identifier in range generate
(condition, assignment)
end generate
--if/generate
--if/generate不允许使用else,可以与for/generate嵌套使用
label1: for idnetifier in range generate
...
label2: if condition generate
(condition assignment)
end generate;
...
end generate;
--例
signal x: bit_vector(7 downto 0);
signal y: bit_vector(15 downto 0);
signal z: bit_vector(7 downto 0);
...
g1: for i in x'range generate
z(i) <= x(i) and y (i+8);
end generate
generate中循环的上界和下界必须是静态的,如果上界或下界中的参数是非静态的,那么代码通常不可综合
1.3块语句
块语句分为简单块(simple block)和卫式块(guarded block)
simple block
simple block仅仅是一种对原有代码进行区域分割的方式
----------法结构如下----------
label: block
[declarative part]
begin
(concurrent statement)
end block label;
----------一个完整的block----------
b1: block
signal a: std_logic;
begin
a <= input_sig when ena = '1' else 'z';
end block b1;
----------利用block对构造体进行规整----------
architecture example ...
begin
...
block1: block
begin
...
end block block1;
...
block2: block
begin
...
end block block2;
...
end example;
----------simple block 与 guarded block可以相互嵌套----------
label1: block
[顶层block部分声明]
begin
(顶层block并发描述语言)
label2:block
[嵌套block部分声明]
begin
(嵌套block并发描述语言)
end block label2;
(顶层block其他并发描述语言)
end block label2;
guarded block
guarded block 与simple block 相比,多了一个卫式表达式。只有当卫式表达式值为真时,在guarded block中前面有关键词guarded的语句才会执行
语法结构如下
label: block(卫式表达式)
[声明部分]
begin
(卫式语句和其他并发描述语句)
end block label;
2.顺序代码
VHDL本质都是并发执行的代码,但是在PROCESS,FUNCTION和PROCEDURE内部的代码都是顺序执行的。当作为一个整体时,他们与外部的其他代码之间又都是并发执行的。
变量只能在顺序代码中使用,相对于信号而言,变量只能时局部的,所以他的值不能传递到process,function和procedure外部
2.1进程
进程(process)内部的语句是一种顺序描述语句,其内部经常使用if,wait,case或loop语句。
process具有敏感信号列表(sencitivity list),或者使用wait语句进行执行条件的判断。process必须包含在主代码段,当敏感信号列表中某个信号发生变化时(或当wait条件语句得到满足时),process内部代码就顺序执行一次。其语法结构如下
[label:]process (sensitivity list)
[variable name: type [range][:= initial_value;]]
begin
(顺序执行的代码)
end process [label];
其中变量声明部分是可选的,如果要process内部使用变量,则必须在关键字begin之前的变量声明部分对其进行定义。变量的初始值是不可综合的,只是在仿真过程中使用。
label也是可选的,使用label可增加代码的可读性。
2.2信号和变量
为了方便理解后面的内容,这里补充一点信号与变量的知识,信号与变量详细的讲解会在之后发布
在VHDL中,有两种方法进行动态的数值传递:信号和变量。其中,信号可以在package,entity和architecture中声明,而变量只能在一段顺序描述的代码中声明(比如在process内部进行信号声明)。因此,信号通常是全局的,而变量通常是局部的。
变量的值无法传递到process外的,如果需要进行变量值的传递,必须先把这个值赋给一个信号,然后由该信号将值传递到process外部。赋予变量的值是立即生效的,在此后的代码中,此变量将使用新的变量值。这一点和process中使用的信号不同,新的信号值通常只有在整个process运行完毕以后才开始生效。
2.3if语句
语法结构
if condition then assignments;
elsif conditions then assifnments;
...
else assignments;
end if;
--例
if (x<y) then temp := "11111111";
elsif (x=y and w='0') then temp := "11110000";
else temp := (other => '0');
end if;
2.4wait语句
如果process中使用了wait语句,就不能在使用敏感信号列表了。语法结构如下
--直到信号条件(signal_condition)满足时才进行后面的操作
--在使用wait until时,由于process没有敏感信号列表,所以它必须时process中的第一条语句
wait until signal_condition;
--当后面列出的信号有一个发生变化时,开始进行后面的操作
wait on [signal1,signal2,...];
--等待time所确定的时间后才开始进行后面的操作
wait for time;
--例
process --没有敏感信号列表
begin
wait until (clk'event and clk = '1');
if (rst = '1') then
output <= "00000000";
elsif (clk'event and clk = '1')then
output <=input;
end if;
end process;
2.5case语句
语法结构
case 表达式 is
when 条件表达式 => 顺序执行语句;
when 条件表达式 => 顺序执行语句;
...
end case;
--例
case control is
when"00" => x <= a; y <= b;
when"01" => NULL; --等同于unaffected,表示没有任何操作
when others => x <= "0000"; y <= "zzzz";
end case;
case语句允许在每个测试条件下执行多个赋值操作,而when语句只允许执行一个赋值操作
case与when语句对比
when | case | |
代码类型 | 并发代码 | 顺序代码 |
用法 | 在process,function和procedures外使用 | 在process,function和procedures内使用 |
必须列出所有可能的组合 | 是(对with/select/when来说) | 是 |
每个判断分支允许的最大赋值操作数量 | 1 | 任意 |
没有操作动作时使用的关键字 | unaffected | null |
--下面两端代码实现了同样的功能
--when语句
with sel select
x <= a when "000";
b when "001";
c when "010";
unaffected when others;
--case语句
case sel is
when "000" => x <= a;
when "001" => x <= b;
when "100" => x <= c;
when others => null;
end case
2.6loop语句
语法结构
--for/loop,循环固定次数
--与generate语句相似,for/loop语句中上下界必须是静态值,否则可能不可综合
[label:] for 循环变量 in 范围 loop
(顺序描述语句)
end loop [label];
--while/loop,循环执行直到条件不再满足
[label:] while 条件表达式 loop
(顺序描述语句)
end loop [label];
--exit,结束整个循环
[label:] exit [label] [when条件表达式];
--next,跳出本次循环
[label:] next [loop_label] [when条件表达式];
--例
for i in 0 to 5 loop
x(i) <= enable and w(i+2);
y(0,i) <= w(i);
end loop;
3.实例
3.1用guard block实现D触发器
用guard block实现一个带复位,上升沿触发的D触发器
library ieee;
use ieee.std_logic_1164.all;
entity dff is
port(d,clk,rst: in std_logic;
q: out std_logic);
end dff;
architecture dff of dff is
begin
b1: bolck(clk'event and clk = '1')
begin
q <= guard '0' when rst = '1' else d; //卫式语句,当卫士表达式位真,即rst为1时,q输出0,负责输出d值。
end block b1;
end dff;
3.2RAM模块
下面代码实现一个简易伪双端口RAM模块
library ieee;
use ieee.std_logic_1164.all;
entity ram is
generic(bits: integer := 8;
words: integer := 16);
port(wr_ena,clk; in std_logic;
addr: in integer range 0 to words-1;
data_in: in std_logic_vector(bits-1 downto 0);
data_out: out std_logic_vector(bits-1 downto 0));
end ram;
architecture ram of ram is
type vector_array is array(0 to words-1) of std_logic_vector(bits-1 downto 0);
signal memory: vector_array;
begin
process (clk,wr_ena)
begin
if(wr_ena = '1')then
if(clk'event and clk = '1')then
memory(addr) <= data_in;
end if;
end if
end process;
data_out <= memory(addr);
end ram;