3

在用 VHDL 测试一个简单的生命游戏实现时,空测试台的 GHDL 模拟在打印出“测试结束”消息后以 100% 的 CPU 使用率挂起。

这是代码:

----- 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;
4

2 回答 2

5

de0生命中的进程既没有敏感列表,也没有等待语句,所以这个进程将永远运行,只是在同一模拟时间无限循环执行进程中的语句,因此模拟不会停止。

您可以通过添加敏感列表(matrix)或在某些条件下等待来解决此问题。

于 2013-07-25T10:34:02.990 回答
5

这补充了 MortenZdk 的好答案。评论太大了,不能改变答案。它确实演示了如何使您的模型计时以及如何阻止它连续运行。

放置矩阵是de0(life)中未标记过程的敏感度列表

            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 ns 的周期,第一个上升沿是 10 ns 进入模拟。

我们将时钟添加到生命端口:

    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 的断言语句之外,您无需修改​​原始代码,您就可以让您的模型停止模拟。您想使用运行时选项更改停止模拟的阈值(例如 --assert-level=warning,其中缺少矩阵事件的断言是警告。(并且断言将表示实际的结束的测试)。

正如他们所说,修复 cellValue 是留给读者的练习。(比如矩阵角是如何或为什么首先设置的?)

有趣的部分是告诉您的模型何时在计时时处于静止状态。您可以使用 matrix'event 切换信号(将其用作时钟)并使用时钟来测试该信号的相同值的两次连续出现。当然,该信号可以在具有断言级别的断言语句中使用,以在静止时结束模拟。

可合成的硬件涉及更多。

于 2013-07-26T01:57:38.523 回答