如何在VHDL中实例化通用设计的参数化版本?

时间:2018-04-26 03:18:08

标签: vhdl

我试图理解VHDL中的泛型编程,并且我已经编写了一些简单的代码来实现这一点。我的目标是能够编写通用设计(在某些意义上是通用的,例如某个实体的输入/输出大小没有指定),然后在顶级模块中实例化它并在实例化时指定设计约束。这样,我可以根据用户的需要编写单个设计来满足许多不同的参数约束。否则,我需要为每个文件编写一个单独的设计,每个文件只进行一些修改。这种灵活性的一个明显用例是创建库。

这两个文件说明了我想要实现的目标:

-- array_adder.vhd
-- 
-- Computes and outputs the pointwise addition of two arrays.
library ieee;
use ieee.numeric_std.all;

package array_adder_pkg is
    generic (array_size     : integer;
             precision_size : integer
    );
    type array_type is array (0 to array_size-1) of signed(precision_size-1 downto 0);

    component array_adder is
        port (a   : in  array_type;
              b   : in  array_type;
              c   : out array_type
        );
    end component;
end package;
-----main code:-----------------------------------------------------------------
library ieee;
use ieee.numeric_std.all;
--------------------------------------------------------------------------------
entity array_adder is
    port (a : in  array_type;
          b : in  array_type;
          c : out array_type
    );
end entity;
--------------------------------------------------------------------------------
architecture fpga of array_adder is
begin
    comp: for i in 0 to array_size-1 generate
        c(i) <= a(i) + b(i);
    end generate;
end architecture;

-- top_level.vhd
--------------------------------------------------------------------------------
package small_pkg is new work.array_adder_pkg
    generic map (array_size     => 3,
                 precision_size => 5
    );
package large_pkg is new work.array_adder_pkg
    generic map (array_size     => 15,
                 precision_size => 9
    );
use work.small_pkg.all;
use work.large_pkg.all;

library ieee;
use ieee.numeric_std.all;
--------------------------------------------------------------------------------
entity top_level is
end entity;
--------------------------------------------------------------------------------
architecture fpga of top_level is
    signal small_ina : work.small_pkg.array_type :=
                (to_signed(1, work.small_pkg.precision_size),
                 to_signed(2, work.small_pkg.precision_size),
                 to_signed(3, work.small_pkg.precision_size));
    signal small_inb : work.small_pkg.array_type :=
                (to_signed(4, work.small_pkg.precision_size),
                 to_signed(5, work.small_pkg.precision_size),
                 to_signed(6, work.small_pkg.precision_size));
    signal small_out : work.small_pkg.array_type;

    signal large_ina : work.large_pkg.array_type :=
                (to_signed(100, work.large_pkg.precision_size),
                 to_signed(110, work.large_pkg.precision_size),
                 to_signed(120, work.large_pkg.precision_size));
    signal large_inb : work.large_pkg.array_type :=
                (to_signed(50, work.large_pkg.precision_size),
                 to_signed(30, work.large_pkg.precision_size),
                 to_signed(80, work.large_pkg.precision_size));
    signal large_out : work.large_pkg.array_type;
begin
    small_array_adder: work.small_pkg.array_adder
        port map (a => small_ina,
                  b => small_inb,
                  c => small_out);

    large_array_adder: work.large_pkg.array_adder
        port map (a => large_ina,
                  b => large_inb,
                  c => large_out);
end architecture;

第一套没有编译,因为array_adder并不知道array_type是什么。在ModelSim 10.4b中,我得到(vcom-1136) Unknown identifier "array_type".这并不奇怪,因为我从未实例化过array_adder_pkg

所以,我尝试在array_adder.vhd中实例化一个默认包,这个默认包大致相同,但我会将其包含在内。 top_level.vhd保持不变。

-- array_adder2.vhd
-- 
-- Computes and outputs the pointwise addition of two arrays.
library ieee;
use ieee.numeric_std.all;

package array_adder_pkg is
    generic (array_size     : integer;
             precision_size : integer
    );
    type array_type is array (0 to array_size-1) of signed(precision_size-1 downto 0);

    component array_adder is
        port (a   : in  array_type;
              b   : in  array_type;
              c   : out array_type
        );
    end component;
end package;
-----main code:-----------------------------------------------------------------
package default_array_adder_pkg is new work.array_adder_pkg
    generic map (array_size     => 3,
                 precision_size => 7
    );
use work.default_array_adder_pkg.all;

library ieee;
use ieee.numeric_std.all;
--------------------------------------------------------------------------------
entity array_adder is
    port (a : in  array_type;
          b : in  array_type;
          c : out array_type
    );
end entity;
--------------------------------------------------------------------------------
architecture fpga of array_adder is
begin
    comp: for i in 0 to array_size-1 generate
        c(i) <= a(i) + b(i);
    end generate;
end architecture;

现在两个文件都已编译,但是当我尝试在ModelSim中模拟top_level.vhd时,我得到错误Fatal: (vsim-3714) At array depth 1, array lengths do not match. Left is 15 (0 to 14). Right is 3 (0 to 2).,这似乎表明ModelSim在实例化大小不同于默认值时出现问题。为了进一步测试,我删除了第二个包实例化以及top_level.vhd中与之关联的所有代码(即所有large_pkg内容和与之关联的组件实例)。这一次,我将为您节省大部分冗余的代码。同样,这会按预期编译,但当我尝试模拟它时,我得到Fatal: (vsim-3807) Types do not match between component and entity for port "a".

我实际可以实现这一点的唯一方法是在顶层设计中使用默认包并放弃两个不同大小的实例,但这会破坏通用设计的要点,因为我需要编写一个单独的设计每组参数规范的文件。

还有其他方法可以解决这个问题吗?或者,这不是VHDL目前支持的东西吗?

1 个答案:

答案 0 :(得分:1)

您几乎就在那里,但需要为包中的组件指定默认值。

然后VHDL-2008允许无约束的数组,这可以帮助你。

见这个例子:

library ieee;
use ieee.numeric_std.all;

package array_pkg is
    type signed_array is array (natural range <>) of signed;
end package;


use work.array_pkg.signed_array;

package array_adder_pkg is
    generic(
        array_size     : positive;
        precision_size : positive
    );

    subtype array_type is signed_array(0 to array_size-1)(precision_size-1 downto 0);

    component array_adder is
        generic(
            array_size     : positive := array_size;
            precision_size : positive := precision_size
        );
        port (
            a : in  signed_array(0 to array_size-1)(precision_size-1 downto 0);
            b : in  signed_array(0 to array_size-1)(precision_size-1 downto 0);
            c : out signed_array(0 to array_size-1)(precision_size-1 downto 0)
        );
    end component;
end package;


use work.array_pkg.signed_array;

entity array_adder is
    generic(
        array_size     : positive;
        precision_size : positive
    );
    port (
        a : in  signed_array(0 to array_size-1)(precision_size-1 downto 0);
        b : in  signed_array(0 to array_size-1)(precision_size-1 downto 0);
        c : out signed_array(0 to array_size-1)(precision_size-1 downto 0)
    );
end entity;

library ieee;

architecture fpga of array_adder is
    use ieee.numeric_std.all;
begin
    comp: for i in 0 to array_size-1 generate
        c(i) <= a(i) + b(i);
    end generate;
end architecture;


entity top_level is end entity;

package small_pkg is new work.array_adder_pkg
    generic map (array_size     => 3,
                 precision_size => 5
    );
package large_pkg is new work.array_adder_pkg
    generic map (array_size     => 3,
                 precision_size => 9
    );

library ieee;

architecture fpga of top_level is
    use ieee.numeric_std.all;

    signal small_ina : work.small_pkg.array_type :=
                (to_signed(1, work.small_pkg.precision_size),
                 to_signed(2, work.small_pkg.precision_size),
                 to_signed(3, work.small_pkg.precision_size));
    signal small_inb : work.small_pkg.array_type :=
                (to_signed(4, work.small_pkg.precision_size),
                 to_signed(5, work.small_pkg.precision_size),
                 to_signed(6, work.small_pkg.precision_size));
    signal small_out : work.small_pkg.array_type;

    signal large_ina : work.large_pkg.array_type :=
                (to_signed(100, work.large_pkg.precision_size),
                 to_signed(110, work.large_pkg.precision_size),
                 to_signed(120, work.large_pkg.precision_size));
    signal large_inb : work.large_pkg.array_type :=
                (to_signed(50, work.large_pkg.precision_size),
                 to_signed(30, work.large_pkg.precision_size),
                 to_signed(80, work.large_pkg.precision_size));
    signal large_out : work.large_pkg.array_type;
begin
    small_array_adder: work.small_pkg.array_adder
        port map (a => small_ina,
                  b => small_inb,
                  c => small_out);

    large_array_adder: work.large_pkg.array_adder
        port map (a => large_ina,
                  b => large_inb,
                  c => large_out);
end architecture;

编辑:我想补充一点,您还可以生成架构本地的专用软件包。这样他们就不会被编译到你的库中。例如:

entity top_level is end entity;

library ieee;

architecture fpga of top_level is
    use ieee.numeric_std.all;

    package small_pkg is new work.array_adder_pkg
        generic map (array_size     => 3,
                     precision_size => 5
        );
    package large_pkg is new work.array_adder_pkg
        generic map (array_size     => 3,
                     precision_size => 9
        );

    signal small_ina : small_pkg.array_type :=
                (to_signed(1, small_pkg.precision_size),
                 to_signed(2, small_pkg.precision_size),
                 to_signed(3, small_pkg.precision_size));
    signal small_inb : small_pkg.array_type :=
                (to_signed(4, small_pkg.precision_size),
                 to_signed(5, small_pkg.precision_size),
                 to_signed(6, small_pkg.precision_size));
    signal small_out : small_pkg.array_type;

    signal large_ina : large_pkg.array_type :=
                (to_signed(100, large_pkg.precision_size),
                 to_signed(110, large_pkg.precision_size),
                 to_signed(120, large_pkg.precision_size));
    signal large_inb : large_pkg.array_type :=
                (to_signed(50, large_pkg.precision_size),
                 to_signed(30, large_pkg.precision_size),
                 to_signed(80, large_pkg.precision_size));
    signal large_out : large_pkg.array_type;
begin
    small_array_adder: small_pkg.array_adder
        port map (a => small_ina,
                  b => small_inb,
                  c => small_out);

    large_array_adder: large_pkg.array_adder
        port map (a => large_ina,
                  b => large_inb,
                  c => large_out);
end architecture;