Как создать компонент, который принимает стандартный пакет c? - PullRequest
0 голосов
/ 28 марта 2020

У меня следующая ситуация: в моей конструкции VHDL есть модули X и Y, которые можно настраивать в соответствии с большим набором параметров. Для этого я включаю эти параметры как Generics, которые являются частью объявлений X и Y. Более того, X должен быть создан внутри Y.

Однако, поскольку этот список параметров довольно большой, я подумал, что лучше заключите их в общий пакет c, и вот тут начинается проблема. Все идет хорошо, когда я пытаюсь скомпилировать модуль X с пакетом generi c. Однако, когда я пытаюсь скомпилировать модуль Y (и создать экземпляр модуля X внутри), я не могу найти способ сопоставить пакет generi c верхнего уровня в Y с модулем X.

Для пояснения, вот MWE моего сценария:

Пакет:

package generic_parameters is
    Generic(
        PARAM_A : natural;
        PARAM_B : natural);

end package generic_parameters;

Модуль X:

library ieee;
use ieee.std_logic_1164.all;

entity module_X is
    generic(package p is new work.generic_parameters generic map (<>));
    port(
        A : in std_logic_vector(p.PARAM_A-1 downto 0);
        B : out std_logic_vector(p.PARAM_A-1 downto 0));
end entity module_X;

architecture RTL of module_X is

begin

    B <= not(A);

end architecture RTL;

Модуль Y:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity module_Y is
    generic(package p is new work.generic_parameters generic map (<>));
    port(
        A : in std_logic_vector(p.PARAM_A-1 downto 0);
        B : out std_logic_vector(p.PARAM_A-1 downto 0));
end entity module_Y;

architecture RTL of module_Y is

begin

    instance_X: entity work.module_X
        generic map(p => p)
        port map(
            A => A,
            B => B);

end architecture RTL;

Две ошибки Я получаю (ModelSim 2020.1, в файле module_Y.vhd):

  • Неправильное выражение в фактической части элемента ассоциации 'p'.
  • Фактический параметр для объявления пакета интерфейса 'p' это не пакетная реализация.

Неужели то, что я пытаюсь выполнить sh, невозможно? Какая альтернатива есть?

1 Ответ

2 голосов
/ 30 марта 2020

Не имея доступа к игровой площадке Modelsim или EDA, образец кода был проанализирован с помощью ghd, который выдает ошибки, аналогичные описанным Modelsim, которые случайно описывают реальную проблему:

ghdl -a --std=08 mbrandalero.vhdl
mbrandalero.vhdl:14:35:error: no declaration for "param_a" in package interface "p"
mbrandalero.vhdl:15:36:error: no declaration for "param_a" in package interface "p"
mbrandalero.vhdl:18:14:error: entity 'module_x' was not analyzed
mbrandalero.vhdl:33:35:error: no declaration for "param_a" in package interface "p"
mbrandalero.vhdl:34:36:error: no declaration for "param_a" in package interface "p"
mbrandalero.vhdl:37:14:error: entity 'module_y' was not analyed
ghdl:error: compilation error

(Все единицы дизайна объединены в один файл с ошибки, возникающие для объявлений сигналов портов в зависимости от PARAM_A в Module_X и Module_Y.)

Проблема видимости указана в стандарте IEEE 1076-2008:

4.7 Объявления пакета

Элементы, объявленные немедленно в простом или обобщенном объявлении пакета с отображением c, становятся видимыми при выборе в пределах заданной единицы дизайна везде, где имя этого пакета видно в данной единице. Такие предметы также могут быть сделаны непосредственно видимыми с помощью соответствующего условия использования (см. 12.4). Элементы, объявленные сразу в объявлении пакета без проверки, не могут быть видны за пределами пакета.

Здесь дженерики объявляются немедленно в пакете с неустановленным экземпляром, который не был создан до разработки. Имя экземпляра пакета (p) является видимым, но не является универсальными c константами (PARAM_A и PARAM_B) до разработки экземпляра компонента instance_X в Module_Y и предположительно entity work.Module_Y в более высокая точка в иерархии дизайна. Это включает в себя видимость путем использования выбранных имен.

Очевидно, что экземпляры обобщенных c экземпляров не предназначены для использования в объявлениях предложений порта.

Существует ли альтернатива сопоставлению инстанцированный пакет как универсальный c?

Да. Решая проблему, показанную в примере кода, и отмечая, что вы пытаетесь использовать один и тот же экземплярный пакет вниз по иерархии дизайна, вы можете создать экземпляр пакета p в качестве основного модуля проектирования и добавить этот модуль проектирования в различные контекстные предложения (Module_X, Module_Y, следующий более высокий уровень в иерархии дизайна):

package generic_parameters is
    generic (PARAM_A: natural; PARAM_B: natural);
end package generic_parameters;

package p is new work.generic_parameters  -- ADDED primary unit declaration
    generic map (PARAM_A => 4, PARAM_B => 2);

library ieee;
use ieee.std_logic_1164.all;
use work.p.all;  -- ADDED use clause

entity module_X is
    -- generic (package p is new work.generic_parameters generic map (<>));
    port (
        A:  in  std_logic_vector(PARAM_A - 1 downto 0); -- WAS p.PARAM_A
        B:  out std_logic_vector(PARAM_A - 1 downto 0)  -- WAS p.PARAM_A
    );
end entity module_X;

architecture RTL of module_X is
begin
    B <= not(A);
end architecture RTL;

library ieee;
use ieee.std_logic_1164.all;
-- use ieee.numeric_std.all;    -- NOT USED
use work.p.all;                 -- ADDED USE CLAUSE

entity module_Y is
    -- generic (package p is new work.generic_parameters generic map (<>));
    port (
        A:  in  std_logic_vector(PARAM_A - 1 downto 0); -- WAS p.PARAM_A
        B:  out std_logic_vector(PARAM_A - 1 downto 0)  -- WAS p.PARAM_A
    );
end entity module_Y;

architecture RTL of module_Y is
begin
instance_X:
    entity work.module_X
        -- generic map (p => p)
        port map (
            A => A,
            B => B
        );
end architecture RTL;

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.p.all;

entity module_y_tb is
end entity;

architecture foo of module_y_tb is
    signal A: std_logic_vector (PARAM_A - 1 downto 0);
    signal B: std_logic_vector (PARAM_A - 1 downto 0);
begin
UUT:
    entity work.module_y
        port map (
            A => A,
            B => B
        );
STIMULUS:
    process
    begin
        for i in 0 to 15 loop
            A <= std_logic_vector (to_unsigned(i, A'LENGTH));
            wait for 10 ns;
        end loop;
        wait;
    end process;
end architecture;

Ввиду того, что здесь не было обобщенных предложений c, они были просто закомментированы, экземпляры пакета были элементом.

Испытательный стенд выдает:

module_y_tb.jpg

Единственный недостаток состоит в том, что все различные первичные блоки зависят от одной и той же анализируемой библиотечной единицы (пакета *) 1045 *) заключается в том, что если это изменяет все расчетные единицы с зависимостями порядка анализа от него, требуется повторный анализ.

Существует несколько способов справиться с этим:

  • Предоставить несколько пакетов, чтобы уменьшить зависимость порядка анализа.

  • Использовать константу generi c типа записи (где su перенесено на всю цепочку инструментов). Можно добавить «запасные» элементы для использования перед повторным анализом всей затронутой части иерархии проекта. Передайте константу generi c типа записи, чтобы уменьшить сложность текста в выражениях generi c.

  • Значение константы записи может быть определено с использованием нечистой функции, читающей файл через текст. Это происходит во время разработки и широко поддерживается поставщиками синтеза и моделирования.

Вопросы об этих потенциальных решениях могут касаться определенных проблем c. Модифицированный пример кода, показанный выше, отвечает требованиям этого вопроса, который не требует привязки ко времени разработки. Все экземпляры пакета будут использовать пакет верхнего уровня.

Использование константы записи вместо экземпляра пакета

package generic_parameters is
    generic (PARAM_A: natural; PARAM_B: natural);
    type param_rec is record   -- list of parameters
        A: natural;
        B: natural;
    end record;
    constant PARAM: param_rec := (PARAM_A, PARAM_B);
end package generic_parameters;

package p is new work.generic_parameters
    generic map (PARAM_A => 4, PARAM_B => 2);

library ieee;
use ieee.std_logic_1164.all;
use work.p.all;

entity module_X is
    generic (param: param_rec);
    port (
        A:  in  std_logic_vector(param.A - 1 downto 0);
        B:  out std_logic_vector(param.A - 1 downto 0)
    );
end entity module_X;

architecture RTL of module_X is
begin
    B <= not A;
end architecture RTL;

library ieee;
use ieee.std_logic_1164.all;
use work.p.all;

entity module_Y is
    generic (param: param_rec);
    port (
        A:  in  std_logic_vector(param.A - 1 downto 0);
        B:  out std_logic_vector(param.A - 1 downto 0)
    );
end entity module_Y;

architecture RTL of module_Y is
begin
instance_X:
    entity work.module_X
        generic map (param => param)
        port map (
            A => A,
            B => B
        );
end architecture RTL;

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.p.all;

entity module_y_tb is   -- TOP LEVEL of design hierarch
end entity;

architecture foo of module_y_tb is
    signal A: std_logic_vector (PARAM_A - 1 downto 0);
    signal B: std_logic_vector (PARAM_A - 1 downto 0);
    constant tb_param: param_rec := (A => 4, B => 2);
begin
UUT:
    entity work.module_y
        generic map (param => param)
        port map (
            A => A,
            B => B
        );
STIMULUS:
    process
    begin
        for i in 0 to 15 loop
            A <= std_logic_vector (to_unsigned(i, A'LENGTH));
            wait for 10 ns;
        end loop;
        wait;
    end process;
end architecture;

Это позволит выполнять замены для каждого родового c отображать так же, как при создании экземпляра пакета, с учетом ограничений, требующих сопоставления элементов между формальными и фактическими значениями в списках ассоциаций портов.

...