MightyPork
MightyPork

Reputation: 18881

Can't resolve multiple constant drivers - two triggers must change the same vector

I know what the error means and why it's bad, but can't figure out how to do it in other way.

Can't resolve multiple constant drivers for net "snake[17]" at snake_driver.

(and others the same)

The assignment is that we have a "moving snake" in a std_logic_vector, which goes end-to-end, and when you press a button (toggle signal), the snake changes it's length (2, 3, 4, 5, 6, 2, ...)

Obviously, the snake vector must therefore be changed by both a process listening for toggle, and the one listening for clock. When I put both in the same process, I got an error that two edge detects can't be in the same process.

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

Any ideas welcome.

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;

Upvotes: 1

Views: 680

Answers (1)

QuantumRipple
QuantumRipple

Reputation: 1159

How fast is your clock? Typically the clock in an FPGA is pretty fast (50MHz or higher). If it is fast, you will often sample your "toggle" signal on each clock edge with a delay element to detect edges. You can use this edge detect to increase the length of the snake. If you need to move the snake slowly enough for a human to detect it, you will typically only move a step every x number of clock edges (using a counter to generate a clock enable). This can all be done in a single process that is only reliant on your high speed clock edge.

If your toggle signal is sourced from a physical switch, however, you may want to be careful about about the physical phenomenon of switch bouncing. You can avoid most bouncing issues by ignoring positive edges for a certain number of counts after detecting a negative edge. This way only the first positive edge counts when you press the switch and none of the (bouncing) positive edges are used on releasing the switch.

If any of what I said above doesn't make sense I can go into more detail.

Here is an example of what I said above with a snake that always rotates right, begins 2 bits wide, and has no limit on the maximum size (warning: not tested):

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;

EDIT: with the situation you described in the comments, the best way would probably be to latch the event on the high speed clock and read it with the low speed clock. Below is an example how to do that. Note that your clock divider needs to give an output on the high speed clock for each rising edge of the divided clock (assuming a counter-based clock divider). For your project, you may want to do the high speed latching outside of the block that uses the slow speed clock - it can pass the event as an input.

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;

Upvotes: 2

Related Questions