Вызов процедуры в цикле с нестатическим именем сигнала

В некотором коде тестового стенда я использую процедуру, чтобы что-то сделать с сигналом. Затем я последовательно использую эту процедуру несколько раз для разных сигналов. Это работает нормально, пока я явно определяю сигнал; как только я индексирую сигналы в цикле, он терпит неудачу с

(vcom-1450) Фактическое (индексированное имя) для формального "s" не является статическим именем сигнала.

Почему это невозможно и как я могу обойти это? Вероятно, я мог бы переместить это в for ... generate, но тогда я хочу, чтобы do_something вызывался в хорошо определенной последовательности.

library ieee;
use ieee.std_logic_1164.all;

entity test is
end test;

architecture tb of test is
    signal foo : std_logic_vector(1 downto 0);
begin
    dummy: process is
        procedure do_something (
            signal s : out std_logic
        ) is begin
            s <= '1';
            report "tic";
            wait for 1 ns;
            -- actually we would do something more interesting here
            s <= '0';
            report "toc";
        end procedure;
    begin
        -- This works well, but requires manual loop-unrolling
        do_something(foo(0));
        do_something(foo(1));

        -- This should do the same 
        for i in foo'range loop
            -- This is the offending line:
            do_something(foo(i));
        end loop;
        wait; -- for ever
    end process dummy;
end architecture tb;

Я использую ModelSim 10.4 PE.


person mbschenkel    schedule 25.06.2015    source источник


Ответы (2)


Интересно, что если foo является локальной переменной процесса (и s настроена соответствующим образом), ghdl компилирует это. Что подчеркивает проблему в исходной версии. Цикл «for» требуется для управления всем foo все время, потому что вы не можете заставить сигнальные драйверы появляться или исчезать по желанию — он не может быть амбивалентным в отношении того, какие биты он управляет (и, как вы можете видеть, процедура пытается управлять разными битами в разное время).

Поэтому, если вы можете перенастроить свое приложение, чтобы разрешить семантику обновления переменных, и сделать foo переменной локальной для процесса, это сработает. (Вам придется копировать его значение в сигнал перед каждым «ожиданием», если вы хотите увидеть эффект!)

В качестве альтернативы передайте весь сигнал foo и индекс подпрограмме, чтобы последняя всегда управляла всеми foo следующим образом... (Я также добавил недостающие биты и исправил ложное параллельное «ожидание»: в будущем ПОЖАЛУЙСТА проверьте, действительно ли ваш пример кода компилируется перед публикацией!)

library ieee;
use ieee.std_logic_1164.all;

entity test is
end test;

architecture tb of test is
    signal foo : std_logic_vector(1 downto 0);
begin
    dummy: process is
        procedure do_something (
            signal s : out std_logic_vector(1 downto 0); 
            constant i : in natural
        ) is begin
            s <= (others => '0');
            s(i) <= '1';
            report "tic";
            wait for 1 ns;
            -- actually we would do something more interesting here
            s(i) <= '0';
            report "toc";
        end procedure;

    begin
        -- This works well, but requires manual loop-unrolling
        do_something(foo,0);
        do_something(foo,1);

        -- This should do the same 
        for i in foo'range loop
            -- This is the offending line:
            do_something(foo,i);
        end loop;
        wait; -- for ever
    end process dummy;

end architecture tb;
person user_1818839    schedule 25.06.2015
comment
Извините за перетасовку исходных строк, вопрос исправлен. Ваше решение определенно сработает для простого примера, который я опубликовал, но на самом деле у меня менее однородные массивы структур, а не только один std_logic_vector. Также переменные не будут работать, потому что я намерен вернуть некоторые сигналы в процедуру проверки (не показано в вопросе). Мне, вероятно, придется отделить выбор сигнала от управления последовательностью и подойти к этому менее процедурно и более похоже на RTL. Однако я до сих пор не совсем понимаю, почему нестатический i не должен работать. - person mbschenkel; 25.06.2015
comment
i проблема не в том, что он нестатичен. foo(i) быть нестатичным. Я понимаю, что это в любом случае не поддается синтезу, но может помочь визуализировать здесь аппаратное обеспечение: оригинал повторно соединяет формальный s с другим фактическим в каждой итерации. Динамическое перемонтирование не является частью того, что позволяет язык. Измененная форма постоянно соединяет формальный s с одним и тем же сигналом (все foo). NB вы можете передавать массивы структур в качестве параметров; Вы можете заставить работать внутренний отбор? - person user_1818839; 25.06.2015
comment
Кажется, мне понадобится for ... generate внутри процесса, чтобы избежать "перемонтажа"... И, к сожалению, я планировал вызывать эту процедуру для членов довольно неправильной структуры, поэтому предложенный вами подход не может быть легко применил тогда. - person mbschenkel; 29.06.2015
comment
for ... generate - это параллельная конструкция, что означает, что она недоступна в последовательной области кода... то есть в процессе. Ожидайте обновления моего ответа. - person user_1818839; 29.06.2015
comment
... или не. Я не понимаю, что вы пытаетесь сделать достаточно хорошо, чтобы помочь. Ожидания в процедурах просто убили последнюю попытку, извините. Мне непонятно, почему передача всей процедуры foo не делает того, что вы хотите. - person user_1818839; 29.06.2015
comment
Ну, я пытаюсь возбудить ряд сигналов (некоторые из них в векторах и структурах) с заданным паттерном последовательно, по одному и записать эффект, который они оказывают на другой сигнал. И я знаю, что generate внутри в последовательном коде недоступен, поэтому и написал, что мне [это] понадобится. - person mbschenkel; 29.06.2015
comment
@BrianDrummond Обычно это не проблема, если процесс не постоянно явно управляет всем вектором. Вы можете условно управлять одним битом вектора, используя другой сигнал в качестве селектора без каких-либо проблем, также для синтеза. Остальные биты сохранят свои старые значения по умолчанию. Возможно, для этого ограничения есть несколько разумная причина, но это не так. - person pc3e; 04.03.2016
comment
@ pc3e: я подозреваю, что вы имеете в виду синхронизированный процесс, который управляет всем вектором (или статически определенным его подмножеством), но только обновляет выбранный бит в соответствии с сигналом. Там неуправляемые (в этом цикле) биты действительно сохраняют свое предыдущее значение. Но мне нужно увидеть пример, который вы имеете в виду, чтобы быть уверенным. - person user_1818839; 04.03.2016
comment
@BrianDrummond Если вы управляете элементом массива в процессе с помощью нестатического селектора, компилятор предположит, что весь вектор управляется процессом. Я не понимаю, почему это должно иметь какое-то значение, если сигнал передается непосредственно в процессе или через процедуру, как в исходном коде. Насколько я понимаю, процедуры — это просто расширения вызывающего процесса, так что копирование кода процедур в процесс всегда дает один и тот же результат. Пока это так, нет причин, по которым это нельзя допустить. - person pc3e; 04.03.2016
comment
@ pc3e Есть что-то (я не могу точно указать, какой именно банкомат) в передаче параметров процедурам, что мешает этому. Я согласен с тем, что это ограничение/упрощение языка, а не фундаментальное для дизайна HW (очевидно! Потому что простые модификации работают), но я не вижу, как ослабить правило, не нарушая нереализуемое. Поскольку я зарегистрировал ошибки в инструменте синтеза (ISE: в конечном итоге исправлено!) Именно в области передачи параметров процедурам, у них достаточно сложностей с существующими правилами, что заставляет меня быть осторожным. - person user_1818839; 04.03.2016

Я разделяю ваши чувства по поводу того, что это глупое ограничение языка. За вычетом операторов wait и report ваш пример, безусловно, имеет действительную аппаратную реализацию, не говоря уже о четко определенном поведении моделирования.

Я думаю, что в большинстве случаев этой ситуации можно избежать. Например, в вашем простом примере вы можете просто скопировать содержимое процедуры в тело процесса или передать весь вектор, как предложил Брайан. Если вам действительно нужно это сделать, это один из обходных путей:

architecture tb of test is
    signal foo : std_logic_vector(1 downto 0);
    signal t : std_logic;
    signal p : integer := 0;
begin
    foo(p) <= t;

    dummy: process is
        procedure do_something (
            signal s : out std_logic
        ) is begin
            s <= '1';
            wait for 1 ns;
            s <= '0';
        end procedure;
    begin
        for i in foo'range loop
            p <= idx;
            do_something(t);
            wait for 0 ns;
        end loop;
        wait;
    end process dummy;
end architecture tb;

Это работает только в моделировании и приведет к задержке одного дельта-цикла на итерацию по сравнению с развертыванием цикла, который завершается за нулевое время, когда процедура не содержит операторов ожидания.

person pc3e    schedule 04.03.2016
comment
Интересно ... но измененный объект немного не в foo, поэтому мне не ясно, как он отвечает на вопрос. - person user_1818839; 04.03.2016
comment
Кажется, я немного поспешил опубликовать этот ответ! В моей ситуации у меня была библиотечная процедура с сигналом направления in, что явно не подходило для данной ситуации. У меня также не было обновлений сигнала во время выполнения процедуры, что также нарушило бы решение. Я обновил свой ответ на то, что должно работать лучше для этого конкретного примера. - person pc3e; 06.03.2016