1

エラーが何を意味し、なぜそれが悪いのかはわかっていますが、他の方法でそれを行う方法がわかりません。

snake_driver で、ネット "snake[17]" の複数の定数ドライバーを解決できません。

(その他も同様)

割り当ては、端から端まで移動する std_logic_vector に「動くスネーク」があり、ボタンを押すと (トグル信号)、スネークは長さを変更します (2、3、4、5、6、 2, ...)

したがって、トグルをリッスンするプロセスとクロックをリッスンするプロセスの両方でスネーク ベクトルを変更する必要があることは明らかです。両方を同じプロセスに入れると、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 クロック エッジごとに 1 ステップだけ移動します (カウンターを使用してクロック イネーブルを生成します)。これはすべて、高速クロック エッジのみに依存する 1 つのプロセスで実行できます。

ただし、トグル信号が物理スイッチから供給されている場合は、スイッチ バウンスの物理現象に注意する必要があります。負のエッジを検出した後、特定の数のカウントで正のエッジを無視することで、ほとんどのバウンスの問題を回避できます。この方法では、スイッチを押したときに最初の正のエッジのみがカウントされ、スイッチを離すときに (バウンスする) 正のエッジは使用されません。

上で述べたことのいずれかが意味をなさない場合は、さらに詳しく説明できます。

これは、常に右に回転し、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 に答える