GHDL вешает работающий тестовый стенд

При тестировании простой реализации жизненной игры в VHDL имитация GHDL пустого тестового стенда зависает при 100% -ной загрузке ЦП после вывода сообщения "Конец теста".

Вот код:

----- Package ------------------------------
library ieee;
use ieee.std_logic_1164.all;

package data_types is
    type array2D is array (0 to 10, 0 to 10) of std_logic;
end data_types;


----- Main Code ----------------------------
library ieee;
use ieee.std_logic_1164.all;
use work.data_types.all;

entity de0 is
    port (matrix : inout array2D);
end de0;


architecture life of de0 is

    -- Return the integer value of a cell, treating all out of bounds as 0
    function cellValue (matrix : array2D; x, y : integer) return integer is 
    begin
        if (y < 0 or y > matrix'high(1) or x < 0 or x > matrix'high(2) or matrix(y, x) = '0') then
            return 0;
        else
            return 1;
        end if;
    end cellValue;

begin

    -- Iterate over all cells
    row: for y in matrix'range(1) generate
        column: for x in matrix'range(2) generate

            process

                variable neighbours : integer := cellValue(matrix, x - 1, y - 1) +
                                                cellValue(matrix, x - 1, y) +
                                                cellValue(matrix, x - 1, y + 1) +
                                                cellValue(matrix, x, y - 1) +
                                                cellValue(matrix, x, y + 1) +
                                                cellValue(matrix, x + 1, y - 1) +
                                                cellValue(matrix, x + 1, y) +
                                                cellValue(matrix, x + 1, y + 1);

            begin

                -- Update the cell value according to the game of life rules
                if (neighbours = 2 or neighbours = 3) then
                    matrix(y, x) <= '1';
                else
                    matrix(y, x) <= '0';
                end if;

            end process;

        end generate;
    end generate;

end life;

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

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

entity life_tb is
end life_tb;

architecture behaviour of life_tb is
    component life
        port (matrix : inout array2D);
    end component;

    for test: life use entity work.de0;
    signal matrix : array2D;

begin

    test: life port map (matrix => matrix);

    process
    begin
            assert false
                report "End of test" severity note;

            wait;

    end process;
end behaviour;

2 ответа

Решение

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

Вы можете исправить это, добавив список чувствительности (matrix)или ожидание с некоторым условием.

Это дополняет прекрасный ответ MortenZdk. Это просто слишком большой, чтобы идти в комментариях и не меняет этот ответ. Он демонстрирует, как сделать вашу модель синхронизированной, а также как остановить ее непрерывную работу.

Матрица размещения - это список чувствительности немеченого процесса в de0 (жизнь)

            process (matrix)

дает:

ghdl -a de0.vhdl
ghdl -a life_tb.vhdl
ghdl -e life_tb
ghdl -r life_tb
life_tb.vhdl:22:13:@0ms:(assertion note): End of test

Тест подтверждения выполняется только один раз и сразу, он не сигнализирует об окончании теста.

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

Добавление часов к симуляции:

В декларативной области архитектуры мы объявляем тактовый сигнал:

    signal clk: std_logic;

Вы можете добавить новый процесс для генерации часов в своем тестовом стенде (life_tb.vhdl):

CLOCK:
    process 
    begin
        wait for 10 ns;
        clk <= '0';
        wait for 10 ns;
        clk <= '1';
    end process;

Он имеет период 20 нс, и первый положительный фронт в моделировании составляет 10 нс.

Добавляем часы в порт по жизни:

    component life
        port (
            matrix :    inout   array2D;
            clk:        in      std_logic
    );
    end component;

Мы обновляем сущность de0 для использования clk:

entity de0 is
port (
    matrix : inout array2D;
    clk:      in   std_logic
);

Мы обновляем процесс, чтобы быть чувствительным к clk и быть рассчитанным по времени:

            process (clk)

            variable neighbours : integer := cellValue(matrix, x - 1, y - 1) +
                                            cellValue(matrix, x - 1, y) +
                                            cellValue(matrix, x - 1, y + 1) +
                                            cellValue(matrix, x, y - 1) +
                                            cellValue(matrix, x, y + 1) +
                                            cellValue(matrix, x + 1, y - 1) +
                                            cellValue(matrix, x + 1, y) +
                                            cellValue(matrix, x + 1, y + 1);

        begin
            if clk'event and clk = '1' then
            -- Update the cell value according to the game of life rules
                if (neighbours = 2 or neighbours = 3) then
                    matrix(y, x) <= '1';
                else
                    matrix(y, x) <= '0';
                end if;
            end if;

Теперь, поскольку clk является свободно работающим осциллятором, нам нужно использовать время остановки:

ghdl -a de0.vhdl
ghdl -a life_tb.vhdl
ghdl -e life_tb
ghdl -r life_tb --stop-time=100ns --wave=life_tb.ghw
life_tb.vhdl:35:13:@0ms:(assertion note): End of test
ghdl:info: simulation stopped by --stop-time

тактовая симуляция жизни

Если вы прокрутите элементы maxtrix, мы обнаружим, что четыре угла матрицы установлены в "1" при первом событии синхронизации. Все остальные элементы установлены в "0".

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

Если бы матрица была в списке чувствительности процесса, то ваша симуляция остановилась бы через второй раз (без синхронизации).

И смысл временной симуляции в том, что она позволяет вам заглянуть в симуляцию, изучая осциллограммы, в данном случае с помощью gtkwave. Альтернативой являются операторы утверждений и / или отчетов, но при несвоевременном моделировании они будут происходить на границах цикла, и нет гарантии порядка, если они не являются последовательными утверждениями в одном и том же процессе.

И вы могли бы заметить, не изменяя свой исходный код, кроме утверждения утверждения, оценивающего Matrix'event в testbench, вы можете заставить свою модель прекратить симуляцию. Вы бы хотели изменить порог для остановки симуляции с помощью параметра времени выполнения (например, --assert-level=warning, где утверждение об отсутствии matrix'event является предупреждением. (И утверждение будет означать фактический конец испытания).

Исправление cellValue - это, как говорят, упражнение, оставленное читателю. (Как и как или почему углы матрицы были установлены в первую очередь?)

Интересная часть рассказывает, когда ваша модель находится в покое, когда рассчитано время. Вы можете использовать matrix'event для переключения сигнала (используйте его в качестве часов) и использовать часы для проверки двух последовательных вхождений одного и того же значения этого сигнала. И, конечно, сигнал может быть использован в операторе утверждения с уровнем утверждения для завершения симуляции в состоянии покоя.

Синтезируемое оборудование немного сложнее.

Другие вопросы по тегам