2
votes

Background:

I have a type array of four 4-bit std_logic_vector's:

type my_arr_type is array (0 to 3) of std_logic_vector (3 downto 0);

and a corresponding signal:

signal my_signal : my_arr_type;

I also have a 2-bit vector to be used as an array index:

signal index : std_logic_vector (1 downto 0) := "00";

This allows me to access each 4-bit vector dynamically like so:

my_signal(to_integer(unsigned(index))) <= "0001";

In this case the indexed 4-bit vector will get the value b"0001".

The problem:

I would like to increment the value of the currently indexed 4-bit vector by 1, when some condition is true eg. switch is high.

I thought I could this with something like:

process(clk)
begin
  if(rising_edge(clk)) then
      if switch = '1' then --switch flicked (increment)
          my_signal(to_integer(unsigned(index)))
          <= std_logic_vector(unsigned( my_signal(to_integer(unsigned(index))) ) + 1);
      else --remain the same
          my_signal(to_integer(unsigned(index))) 
          <= my_signal(to_integer(unsigned(index)));
      end if;
   end if;
 end process;

However, I must be doing something wrong since passing the resulting signal to an output gives an error message - along the lines:

Signal X is connected to multiple drivers. ERROR:HDLCompiler:1401

The question:

What am I doing wrong in the above attempt? What would be a correct solution?

I cannot find any examples online which relate to incrementing cells in an indexed array.

(Designing for synthesis to Digilent Nexys 3 in ISE Proj Nav)

(edit)Longer code snippet for greater scrunity:

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

entity ui_top is
Port (  clk         : in    std_logic;
            buttons     : in    std_logic_vector (4 downto 0); -- centre, left, up, right, down
            switches    : in    std_logic_vector (7 downto 0);
            leds            : out std_logic_vector (7 downto 0);
            digit           : out std_logic_vector (3 downto 0) := "1110";
            segments    : out std_logic_vector (7 downto 0) := (others => '0');
            uart_tx     : out std_logic);
end ui_top;

architecture Behavioral of ui_top is

    type my_arr_type is array (0 to 3) of std_logic_vector(3 downto 0);

    signal my_signal : my_arr_type;
    signal index : std_logic_vector (1 downto 0) := "00";


begin

    -- send indexed signal to leds
    leds(3 downto 0) <= my_signal(to_integer(unsigned(index)));

    -- set other outputs arbitrarily
    leds(7 downto 4) <= (others => '1');
    uart_tx <= '1';
    digit <= "1110";
    segments <= (others => '0');

    -- set index
    index <= "00";

    process(clk)
    begin
        if (rising_edge(clk)) then
            if switches(1) = '1' then -- up
                my_signal(to_integer(unsigned(index)))
                <= std_logic_vector(unsigned( my_signal(to_integer(unsigned(index))) ) + 1);
            end if;
        end if; -- rising clock edge
    end process;

    -- set non indexed values arbitrarily
    my_signal(1) <= "0000";
    my_signal(2) <= "0000";
    my_signal(3) <= "0000";

end Behavioral;

edit: All answers and comments have been helpful. Thank you!

3
Your synthesis tool does not recognize that index is a constant value. So it calculates the multiple drivers on a per signal name not on a per index name. Please change your signal index to a constant and it should recognize it (it's just for testing). - Paebbels
@Paebbels Okay. That makes sense. And you are right - changing index to a constant value does make the code synthesis-able. Any advice on how to overcome this problem when index is not a constant? - Thomas McKay-Smith
Even with a constant index my tool stalls during 'Place & Route'. - Thomas McKay-Smith
Solution: Move the assignments to my_signal into the process. Assign only indices which are never addressed by index. - Paebbels
What tool do you use? - Paebbels

3 Answers

2
votes

This is associated with longest static prefix, it's not just a synthesis issue but is also reflected in simulation as well.

The drivers for my_signal in a process are determined by the longest static prefix of my_signal.

By using a non-static value for the index into the array you have created drivers for my_signal(0), my_signal(1), my_signal(2) and my_signal(3) in your unlabeled process.

Each of the concurrent signal assignments have an equivalent process, and these have a longest static prefix that includes the numeric literals uses as the index into your my_signal array.

The two drivers in common between the unlabeled process and each equivalent process for each concurrent assignment statement results in a resolved signal value, which in simulation will produce 'X' or 'U' values for conflicting values of std_logic elements. Your synthesis balks and reports you've shorted drivers together.

See IEEE Std 1076-2008 8. Names, 8.1 General (longest static prefix, para 8), 14.7 Execution of a Model, 14.7.2 Drivers para 1, 14.7.3 Propagation of signal values, 14.7.3.1 General, para 5.

If you used an unresolved element type (BIT, BIT_VECTOR) you'd get reports of one or more errors during elaboration for multiple drivers on a signal net. This is the equivalent of what your synthesis tool reports.

1
votes

Your problem is a multiple drive problem. This post and its answer may help understanding it. As you are using resolved types (std_logic) you will not get errors or warnings when compiling or simulating. The tool you are using (ISE) is a logic synthesizer. It tries to map the behaviour you described to existing hardware resources. As your hardware target does not support multiple drives, you get errors. My advices:

  • do not use resolved types when they are not necessary,
  • use appropriate types (as wisely suggested by Brian Drummond).

Something like the following code should be better. Adapt it to your specific needs. Note that the unsigned type of ieee.numeric_stdis, unfortunately, a resolved type. So, use it carefully and avoid multiple drive situations. Or, even better, if your tools support it, use unresolved_unsigned the unresolved version of unsigned.

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

entity ui_top is
  Port(clk         : in  std_ulogic;
       buttons     : in  std_ulogic_vector (4 downto 0); -- centre, left, up, right, down
       switches    : in  std_ulogic_vector (7 downto 0);
       leds        : out std_ulogic_vector (7 downto 0);
       digit       : out std_ulogic_vector (3 downto 0);
       segments    : out std_ulogic_vector (7 downto 0);
       uart_tx     : out std_ulogic);
end ui_top;

architecture Behavioral of ui_top is

  constant n: positive := 4;
  type my_arr_type is array (0 to 3) of unsigned(n-1 downto 0);
  -- type my_arr_type is array (0 to 3) of unresolved_unsigned(n-1 downto 0);

  signal my_signal : my_arr_type;
  signal index : natural range 0 to n-1;

begin

  -- send indexed signal to leds
  leds(n-1 downto 0) <= std_ulogic_vector(my_signal(index));

  -- set other outputs arbitrarily
  leds(7 downto n) <= (others => '1');
  uart_tx <= '1';
  digit <= "1110";
  segments <= (others => '0');
  -- set index
  index <= 0;

  process(clk)
  begin
    if (rising_edge(clk)) then
      -- set non indexed values arbitrarily
      for i in 0 to n-1 loop
        if i = index then
          if switches(1) = '1' then -- up
            my_signal(i) <= my_signal(i) + 1;
          end if;
        else
          my_signal(i) <= (others => '0');
        end if;
      end loop;
    end if; -- rising clock edge
  end process;

end Behavioral;
0
votes

Reason (probably) is that there is an another process or concurrent assign that drives (assigns to) my_signal, so look through your entire code, or post it here for further scrutiny.

Note that the driver (assign) may be to another index; take a look at this answer.

Btw. you can remove the

else --remain the same
    my_signal(to_integer(unsigned(index))) 
    <= my_signal(to_integer(unsigned(index)));

since my_signal will keep the current value until given a new.