1

我知道错误的含义以及错误的原因,但无法弄清楚如何以其他方式进行。

无法在 snake_driver 解析网络“snake[17]”的多个常量驱动程序。

(和其他人一样)

任务是我们在 std_logic_vector 中有一条“移动的蛇”,它是端到端的,当你按下按钮(切换信号)时,蛇会改变它的长度(2、3、4、5、6, 2, ...)

显然,蛇向量因此必须由监听切换的进程和监听时钟的进程来改变。当我将两者放在同一个进程中时,我得到一个错误,两个边缘检测不能在同一个进程中。

/\____    +--------------------+
toggle ---->  change length    |
          |          v         |
          |  [snake register] =====> snake 17 downto 0
\/\/\/    |          ^         |
clock  ---->  move one step    |
          +--------------------+

欢迎任何想法。

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

entity snake_driver is
    generic
    (
        LEN : integer := 18;
        MAX_SNAKE_LEN : integer := 6
    );

    port
    (
        clk : in std_logic;
        change : in std_logic;
        output : out std_logic_vector(LEN-1 downto 0)
    );
end snake_driver;

architecture Anaconda of snake_driver is
signal snake : std_logic_vector(LEN-1 downto 0) := (0 => '1', 1 => '1', others => '0'); -- two snake pieces
signal dir_right : boolean := FALSE; -- start left
begin


    process(change)

        variable data : std_logic_vector(LEN-1 downto 0); -- two snake pieces

        variable snake_len : integer := 2; -- snake 2 long
    begin

        if rising_edge(change) then -- change snake length
            -- add snake piece based on direction

            data := snake; -- <-- here I tried to avoid the problem
                           -- by caching snake data. To no avail.

            if snake_len = MAX_SNAKE_LEN then

                snake_len := 2;

                -- shorten to 2 len

                if dir_right then
                    -- moving right, remove from left
                    data := std_logic_vector(unsigned(data) and shift_right(unsigned(data), MAX_SNAKE_LEN-2));
                else
                    -- moving left, remove from right
                    data := std_logic_vector(unsigned(data) and shift_left(unsigned(data), MAX_SNAKE_LEN-2));
                end if;
            else

                -- add one at the end
                if dir_right then
                    -- moving right, add on left
                    data := std_logic_vector(unsigned(data) or shift_left(unsigned(data), 1));
                else
                    -- moving left, add on right
                    data := std_logic_vector(unsigned(data) or shift_right(unsigned(data), 1));
                end if;

            end if;


            snake <= data;
        end if;

    end process;




    -- move snake on clock
    process(clk)
        -- variables in the process
        variable data : std_logic_vector(LEN-1 downto 0);

    begin
        -- shift the snake
        if rising_edge(clk) then

            data := snake;

            if dir_right then
                -- right move
                data(LEN-2 downto 0) := data(LEN-1 downto 1);

                if data(0) = '1' then
                    dir_right <= FALSE; -- change direction
                end if;             
            else
                -- left move
                data(LEN-1 downto 1) := data(LEN-2 downto 0);

                if data(LEN-1) = '1' then
                    dir_right <= TRUE; -- change direction
                end if;

            end if;

            snake <= data;

        end if;

    end process;


    -- send changed data to output
    output <= snake;    

end Anaconda;
4

1 回答 1

2

你的时钟有多快?通常,FPGA 中的时钟非常快(50MHz 或更高)。如果速度很快,您通常会在每个时钟边沿对“切换”信号进行采样,并使用延迟元件来检测边沿。您可以使用此边缘检测来增加蛇的长度。如果您需要足够慢地移动蛇以使人类能够检测到它,您通常只会每 x 个时钟沿移动一步(使用计数器生成时钟启用)。这一切都可以在一个仅依赖于您的高速时钟边沿的单一进程中完成。

但是,如果您的切换信号来自物理开关,您可能需要注意开关弹跳的物理现象。您可以通过在检测到负边缘后忽略一定数量的计数的正边缘来避免大多数弹跳问题。这样,当您按下开关时,只有第一个上升沿计数,并且在释放开关时不使用任何(弹跳)上升沿。

如果我上面所说的任何内容都没有意义,我可以更详细地介绍。

这是我上面所说的一个例子,一条蛇总是向右旋转,开始 2 位宽,并且对最大尺寸没有限制(警告:未测试):

architecture behav of snake is

signal clk       : std_logic; --actually an input. 50MHz
signal toggle    : std_logic := '0'; --actually an input, not an internal signal
signal toggle_d  : std_logic := '0';
signal snake_vec : std_logic_vector(17 downto 0) := "000000000000000011";
signal disable_count : unsigned(20 downto 0):=(others => '0'); --about 50ms to cycle through full range
signal step_count    : unsigned(24 downto 0):=(others => '0'); --about 0.7s to cycle through full range

begin
  process(clk)
    if (clk = '1' and clk'event) then
      toggle_d <= toggle; --store previous value of toggle
      if (toggle_d = '1' and toggle = '0') then --trigger blocking counter on negative edges of toggle
        disable_count <= (others => '1');
      elsif (disable_count /= 0) then --count down if blocking counter is enabled
        disable_count <= disable_count-1;
      end if;

      if (toggle_d = '0' and toggle = '1' and disable_count = 0) then --extend on allowed rising edges of toggle
        snake_vec <= snake_vec or (snake_vec(0) & snake_vec(17 downto 1); --extend the snake by 1
      else
        step_count <= step_count-1; --this could be + or -
        if (step_count = 0) then --functions as a clock enable every 1 in 33.5 million cycles
          snake_vec <= snake_vec(0) & snake_vec(17 downto 0); --rotate snake
        end if;
      end if;      
    end if;
  end process;
end behav;

编辑:根据您在评论中描述的情况,最好的方法可能是在高速时钟上锁定事件并用低速时钟读取它。下面是一个如何做到这一点的例子。请注意,您的时钟分频器需要为分频时钟的每个上升沿提供高速时钟输出(假设基于计数器的时钟分频器)。对于您的项目,您可能希望在使用低速时钟的模块之外进行高速锁存 - 它可以将事件作为输入传递。

architecture behav of snake is

signal clk       : std_logic; --50MHz
signal divide_event : std_logic; --on the 50MHz domain, single clock wide pulse every rising edge of 4Hz clock, sourced from clock divider
signal clk_slow  : std_logic; --4Hz
signal toggle    : std_logic := '0'; --actually an input, not an internal signal
signal toggle_d  : std_logic := '0';
signal snake_vec : std_logic_vector(17 downto 0) := "000000000000000011";

begin
  process(clk)
    if (clk = '1' and clk'event) then
      toggle_d <= toggle; --store previous value of toggle
      if (toggle_d = '0' and toggle = '1') then
        extend_event <= '1';
      elsif divide_event = '1' then
        extend_event <= '0';
      end if;
  end process;

  process(clk_slow)
    if (clk_slow = '1' and clk_slow'event) then
      if (extend_event = '1') then
        snake_vec <= snake_vec or (snake_vec(0) & snake_vec(17 downto 1); --extend the snake by 1
      else
        snake_vec <= snake_vec(0) & snake_vec(17 downto 0); --rotate snake
      end if;
    end if;  
  end process
end behav;
于 2014-11-08T00:38:11.743 回答