包集和元件
元件(component),函数(function)以及过程(procedure)等部分的使用往往是为了实现常用代码的共享。这些代码一般都被放在包集(package),然后编译到目标库文件(library)中。设计者可以将自己设计的一些常用代码段添加到library中,有利于使一个复杂设计具有更加清晰的结构。
包集
除了component,function和procedure之外,package中还包括类型(type)和常量(constant)的定义
--格式
PACKAGE package_name is
(declaration)
end package_name;
[package body package_name id
(function和procedure描述)
end package_name;]
上面语法结构中主要包含两个部分:package和package body。第一部分是必须的,包括声明语句。如果第一部分中有一个或多个function或procedure声明,那么在package body中一定要存在对于的描述代码。package和package body的名称必须相同。
package的声明部分包括以下内容:元件,函数,过程,类型和常量说明等
library ieee;
use ieee.std_logic_1164.all;
package my_package is
type state is(st1,st2,st3,st4);
type color is(red,green,blue);
constant vec: std_logic_vector(7 downto 0) := "11111111";
function positive_edge(signal s: std_logic)return boolean;
end my_package;
package body my_package is
function positive_edge(signal s: std_logic)return boolean is
begin
return(s'event and clk = '1');
end positive_edge;
end my_package;
--调用上面的package时,需要进行如下声明
library ieee;
use work.my_package.all;
元件
一个元件(component)是一段结构完整的常用代码(包括库声明,实体和结构体这些基本组成部分)。然而,如果将这些代码声明为component,就可以被其他电路调用,从而使代码具有层次化的结构。
--元件的声明
component component_name is
port(
port_name: signal_mode signal_type;
port_name: signal_mode signal_type;
...
);
end component;
--元件实例化
label: component_name port map (port_list);
component和entity的声明格式一样,必须指出端口名称以及端口模式(in,out,buffer或inout)以及数据类型(std_logic_vector,interger和boolean等)。为了实例化元件,在元件名和端口映射声明的前面还需要加入一个符号。端口列表将元件预定义的端口和实例化时的端口关联起来。
声明一个元件有两种基本方法。一旦将元件设计完成并放到目标库中,就可以采用下图所示方法进行声明
此外还可以使用包集的方式进行声明,可以避免每次元件实例化时都需要重复声明。
下面将分别通过这两种方法实现如图所示电路结构
-------------------在主代码中声明元件------------------------
--------file inverter.vhd--------
library ieee;
use ieee.std_logic_1164.all;
entity inverter is
port (a: in std_logic;
b: out std_logic
);
end inverter;
architecture inverter of inverter is
begin
b <= not a;
end inverter
--------file nand_2.vhd--------
library ieee;
use ieee.std_logic_1164.all;
entity nand_2 is
port (a,b: in std_logic;
c: out std_logic
);
end nand_2;
architecture nand_2 of nand_2 is
begin
c <= not (a and b);
end and_2;
--------file nand_3.vhd--------
library ieee;
use ieee.std_logic_1164.all;
entity nand_3 is
port (a,b,c: in std_logic;
d: out std_logic
);
end nand_3;
architecture nand_3 of nand_3 is
begin
d <= not (a and b and c);
end and_3;
--------file project.vhd--------
library ieee;
use ieee.std_logic_1164.all;
entity project is
port(a,b,c,d: in std_logic;
x,y: out std_logic
);
end project;
architecture structural of project is
component inverter is
port(a: in std_logic; b: out std_logic);
end component;
component nand_2 is
port(a,b: in std_logic; c: out std_logic);
end component;
component nand_3 is
port(a,b,c: in std_logic; d: out std_logic);
end component;
signal w: std_logic;
begin
u1: inverter port map(b,w);
u2: nand_2 port map(a,b,x);
u3: nand_3 port map(a,b,c,y);
end structure;
-------------------在包集中声明元件------------------------
--------file inverter.vhd--------
library ieee;
use ieee.std_logic_1164.all;
entity inverter is
port (a: in std_logic;
b: out std_logic
);
end inverter;
architecture inverter of inverter is
begin
b <= not a;
end inverter
--------file nand_2.vhd--------
library ieee;
use ieee.std_logic_1164.all;
entity nand_2 is
port (a,b: in std_logic;
c: out std_logic
);
end nand_2;
architecture nand_2 of nand_2 is
begin
c <= not (a and b);
end and_2;
--------file nand_3.vhd--------
library ieee;
use ieee.std_logic_1164.all;
entity nand_3 is
port (a,b,c: in std_logic;
d: out std_logic
);
end nand_3;
architecture nand_3 of nand_3 is
begin
d <= not (a and b and c);
end and_3;
--------file nand_3.vhd--------
library ieee;
use ieee.std_logic_1164.all;
package my_component is
component inverter is
port(a: in std_logic; b: out std_logic);
end component
component nand_2 is
port(a,b: in std_logic; c: out std_logic);
end component
component nand_3 is
port(a,b,c: in std_logic; d: out std_logic);
end component
end my_component;
--------file project.vhd--------
library ieee;
use ieee.std_logic_1164.all;
use work.my_components.all;
entity project is
port(a,b,c,d: in std_logic;
x,y: out std_logic
);
end project;
architecture structural of project is
signal w: std_logic;
begin
u1: inverter port map(b,w);
u2: nand_2 port map(a,b,x);
u3: nand_3 port map(a,b,c,y);
end structure;
端口映射
对端口的映射有位置映射和名称映射两种方式。位置映射书写比较简单,但名称映射的方法不容易出错。对于不需要使用的端口可以使用关键词OPEN断开
--位置映射
component inverter is
port(a: in std_logic; b: out std_logic);
end component;
...
u1: inverter port map(x,y); --此处x,y对应a,b
--名称映射
u1: inverter port map(x => a, y => b);
--使用open断开映射
u2:my_circuit port map(x => a, y => b, w => open, z =>d);
generic参数的映射
如果元件实例化需要通过generic传递参数,那么一定需要进行generic参数的映射。此时,元件实例化的格式需要进行如下更新:
label: compon_name generic map(param.list)port map(port list);
实例
1.奇偶效验器
下面的代码实现一个通用奇偶效验产生器,当输入矢量中‘1’的数量位偶数时,在输入矢量中插入一个‘0’,当输入矢量中‘1’的个数为奇数时,则插入一个‘1’,从而使输出矢量中始终包含偶数个‘1’
这段代码通用性较强,因为输入矢量的宽度n使generic参数,可以取任意整数。
-------------这一部分是对电路的描述,后面作为包集调用------------------
library ieee;
use ieee.std_logic_1164.all;
entity parity_gen is
generic (n: integer := 7); --默认矢量宽度为7,该值会在后面实例化时被覆盖
port (input: in bit_vector(n downto 0);
output: out bit_vector(n_1 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;
-------------这一部分是对电路的引用------------------
library ieee;
use ieee.std_logic_1164.all;
entity my_code is
generic(n: positive := 2); --这里的2在实例化前面的电路时会覆盖默认值7
port (inp: in bit_vector(n downto 0);
outp: out bit_vector(n+1 downto 0));
end my_code;
architecture my_arch of my_code is
component parity_gen is
generic(n: positive);
port (input: in bit_vector(n downto 0);
output: out bit_vector(n+1 downto 0));
end component;
begin
c1: parity_gen genric map (n) port map (inp,outp);
end my_arch;
2.算术逻辑单元
下面代码实现了通过元件实例化设计ALU(算术逻辑单元),在这个例子中,假设文件中包含了构建ALU的3个元件:逻辑单元,算术单元和多路选择器
-------------arith_unit component------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity arith_unit is
port(a,b: in std_logic_vector(7 downto 0 )
sel: in std_logic_vector(2 downto 0)
cin: in std_logic;
x: out std_logic_vector(7 downto 0));
end arith_unit;
architecture arith_unit of arith_unit is
signal arith, logic: std_logic_vector(7 downto 0);
begin
with sel select
x <= a when "000",
a+1 when "001",
a-1 when "010",
b when "011",
b+1 when "100",
b-1 when "101",
a+b when "110",
a+b+cin when others;
end arith_unit;
-------------logic_unit component------------------
library ieee;
use ieee.std_logic_1164.all;
entity logic_unit is
port(a,b: in std_logic_vector(7 downto 0);
sel: in std_logic_vector(2 downto 0);
x: out std_logic_vector(7 downto 0));
end logic_unit;
architecture logic_unit of logic_unit is
begin
with sel secect
x <= not a when "000",
not b when "001",
a and b when "010",
a or b when "011",
a nand b when "100",
a nor b when "101",
a xor b when " 110",
not(a nxor b) when others;
end logic_unit;
-------------mux component------------------
library ieee;
use ieee.std_logic_1164.all;
entity mux is
port(a, b: in std_logic_vector(7 downto 0);
sel: in std_logic;
x:out std_logic_vector(7 downto 0));
end mux;
architecture mux of mux is
begin
with sel select
x <= a when '0'
b when others;
end mux;
-------------main code------------------
library ieee;
use ieee.std_logic_1164.all;
entity alu is
port(a, b: in std_logic_vector(7 downto 0);
cin: in std_logic;
sel: in std_logic_vector(3 downto 0);
y: out std_logic_vector(7 downto 0));
end alu;
architecture alu of alu is
component arith_unit is
port (a, b: in std_logic_vector(7 downto 0);
cin: in std_logic;
sel: in std_logic_vector(2 downto 0);
x: out std_logic_vector(7 downto 0));
end component;
component logic_unit is
port(a,b: in std_logic_vector(7 downto 0);
sel: in std_logic_vector(2 downto 0);
x: out std_logic_vector(7 downto 0));
end component;
component mux is
port(a,b: in std_logic_vector(7 downto 0);
sel: in std_logic;
x: out std_logic_vector(7 downto 0));
end component;
signal x1, x2: std_logic_vector(7 downto 0);
begin
u1: arith_unit port map(a,b,cin,sel(2downto 0),x1);
u2: logic_unit port map(a,b,sel(2 downto 0),x2);
u3: mux port map(x1,x2,sel(3),y);
end alu;