VHDL: для цикла индексная арифметика не работает

Я пытаюсь настроить простой сверточный процессор грубой силы с моей платой DE0 Nano Altera FPGA. Вот как выглядит мой код:

LIBRARY ieee;
USE ieee.std_logic_1164.all;
use ieee.numeric_bit.all;

ENTITY Convolution IS
    PORT(   clock : IN std_logic;
            audio_in : IN unsigned(15 downto 0);
            audio_out : OUT unsigned(31 downto 0) );    
END Convolution;

ARCHITECTURE Convolution_Core OF Convolution IS

    constant impulse_length : integer := 10;

    type array16 is array(0 to impulse_length-1) of unsigned(15 downto 0);
    type array32 is array(0 to impulse_length-1) of unsigned(31 downto 0);

    constant impulse : array16 :=   (x"FFFF", x"FFFE", x"FFFD", x"FFFC", 
                                                 x"FFFB", x"FFFA", x"FFF9", x"FFF8",
                                                 x"FFF7", x"FFF6");

    signal audio_buffer : array16 := (others=> (others=>'0'));

    signal seq_buffer : unsigned(31 downto 0);

BEGIN
    process(clock)
    begin
        if rising_edge(clock) then
            -- buffer the audio input in audio_buffer
            for i in 0 to (impulse_length-2) loop
                audio_buffer(i) <= audio_buffer(i+1);
            end loop;
            audio_buffer(impulse_length-1) <= audio_in;

            for i in 0 to (impulse_length-1) loop
                if i = 0 then
                    seq_buffer <= audio_buffer(i) * impulse(impulse_length-1-i);
                else
                    seq_buffer <= seq_buffer + audio_buffer(i) * impulse(impulse_length-1-i);
                end if;
            end loop;
        end if;
    end process;

    audio_out <= seq_buffer;

END Convolution_Core;

Моя проблема: индекс импульса (impulse_length-1-i) не уменьшается во время последовательных циклов for, но индекс audio_buffer(i) уменьшается. Это то, что мне понравилось, моделируя код и выясняя, почему мои результаты неверны.

Я попытался поместить (impulse_length-1-i) в сигнал, чтобы иметь возможность наблюдать за ним в ModelSim, и он начинается с максимального/минимального 32-битного диапазона со знаком (+/- 2 147 483 647), а следующий цикл переходит к нулю и остается на нуль.

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

Может ли кто-нибудь объяснить мне, что я сделал неправильно?

Спасибо заранее.


person ricothebrol    schedule 03.10.2016    source источник
comment
См. также stackoverflow.com/questions/13954193 /   -  person user_1818839    schedule 03.10.2016


Ответы (2)


Основная проблема заключается в том, что вы не понимаете, как работают сигналы и циклы for, когда вы описываете оборудование, а не пишете программное обеспечение.

Каждая итерация второго цикла for присваивает значение одному и тому же сигналу. Внутри процесса имеет значение только последнее присвоение сигнала именованному сигналу, и все операции чтения сигнала используют значение, которое оно хранило до начала процесса. Это означает, что только (impulse_length-1) итерация вашего второго цикла for что-то делает.

Несколько лет назад я написал ответ о том, как сигналы и переменные работают в процессе VHDL, который может дать вам более подробную информацию об этом: https://stackoverflow.com/a/19234859/1360002

Если вы напишите его таким образом, что все 10 операций сложения/умножения происходят в одном и том же цикле (например, использование переменной вместо seq_buffer для вычисления значения, которое вы фактически присваиваете сигналу seq_buffer), вы описываете аппаратное обеспечение, которое будет иметь очень длинный логический путь и не будет работать, если ваша тактовая частота даже умеренно высока. Возможно, это не проблема для вашего случая.

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

person QuantumRipple    schedule 03.10.2016

Большое спасибо, что ответили мне!

Итак, если я правильно понимаю, использование цикла for с переменными внутри процесса приводит к такой же логической реализации, как и использование некоторых операторов «сгенерировать». Может быть, поэтому, когда я попробовал что-то подобное для своего алгоритма свертки, компиляция заняла целую вечность;)

Итак, я думаю, единственный способ сделать что-то похожее на цикл for в Java или C — это «вручную» синхронизировать каждую итерацию, переключать входные сигналы и буферизовать успешные результаты, верно?

Но тогда я должен сказать, что не понимаю, почему написанный мной процесс «буферизации звука» работает правильно, даже с временной симуляцией...

С наилучшими пожеланиями

person ricothebrol    schedule 03.10.2016
comment
Звуковая буферизация для цикла работает, потому что, когда цикл разворачивается, каждая итерация присваивает значение другому индексу в вашем сигнале. Это означает, что все они могут работать параллельно без конфликтов. Циклы for на самом деле не работают последовательно с сигналами. Операторы Generate работают так же, как и циклы for, но вместо того, чтобы иметь значение только окончательное присваивание, вы столкнетесь с многочисленными ошибками драйвера во время реализации. - person QuantumRipple; 03.10.2016
comment
Вы правы в том, что единственный способ реализовать по-настоящему последовательную логику — это иметь какой-то конечный автомат, который мультиплексирует входные данные в ваш математический блок, но если вы хотите получать новый вывод каждый цикл, представляющий собой комбинацию всех 10 значений, вам необходимо использовать переменную для создания длинного пути синхронизации с 10-кратным добавлением или конвейерной математикой (что не сэкономит ресурсы, но обеспечит более короткие логические пути). - person QuantumRipple; 03.10.2016
comment
Время компиляции, как правило, не имеет значения для того, насколько эффективен дизайн по времени или ресурсам. Это коррелирует с тем, сколько ресурсов используется в целом по сравнению с тем, сколько ресурсов существует в вашей целевой FPGA, но не с тем, сколько используется по сравнению с тем, сколько действительно необходимо (эффективность) для функции, которую вы пытаетесь реализовать. - person QuantumRipple; 03.10.2016
comment
Большое спасибо за то, что поделились своими знаниями! Еще один момент, который я нахожу удивительным, заключается в том, что когда я компилирую часть своего кода только для звукового буфера, Quartus II говорит, что использует 0 логических элементов. Я даже пытался сделать это с размером буфера в тысячу логических элементов... Реально ли это? Тогда есть ли смысл реализовывать кольцевой буфер с FPGA, если он может параллельно выполнять тысячи сдвигов? Надеюсь, мои вопросы не слишком глупы... Заранее спасибо - person ricothebrol; 03.10.2016
comment
Без математической части никакая часть вашего аудиобуфера не влияет на какие-либо выходные данные. Поэтому синтезатор будет оптимизировать его, независимо от размера. Если вы подключите audio_buffer(0) к младшим битам вашего audio_out, вы увидите фактический размер вашего сдвигового регистра. Обратите внимание, что в аппаратном обеспечении использование реальных сдвиговых регистров будет более эффективным, чем циклические буферы, пока ваш сдвиговый регистр не станет достаточно глубоким, чтобы его можно было реализовать с использованием усиленных блочных блоков. - person QuantumRipple; 04.10.2016
comment
На самом деле это хорошо, обращение к циклическому буферу кажется немного сложным;) Большое спасибо - person ricothebrol; 04.10.2016