Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
9 years ago

Problem with while loop in an array

I need to check how many cells in an array are "filled" and how many are zeroed.

The array is a one-dimensional array of 64 bits vector.

Declaration in package:

package my_pack is
    type commands_array is array (natural range <>) of std_logic_vector(63 downto 0);
end package;

Declaration in entity port:

packets_in         : in commands_array(0 to 17);

This is the while loop:

    process(packets_in)
    Begin
        while (packets_in(num_packets) /= X"00000000") loop
            num_packets <= num_packets + 1;
        end loop;
    end process;

This is the declaration of the signal num_packets:

signal num_packets         : integer range 0 to 20:= 0;

So the logic behind this is that I have several functions that fill the array with packets (each of 64 bits, as I've stated before). Initially, each function zeroes all cells of the array.

Theoretically this array can have 18 packets, but in truth each function inserts between 10-12 packets into the array.

The array is an output from one module and an input in the next one (where the while loop is).

I want the while loop to understand on it's own how many cells were filled with packets and insert the number into num_packets.

I'm getting this error:

Error (10536): VHDL Loop Statement error at <vhdl file>: loop must terminate within 10,000 iterations

I'm not sure why the loop doesn't terminate within 10,000 iterations, it should terminate after 18, the way I see it.

I've thought about having the clock in my sensitivity list and doing a simple counter, but I don't want it to be clock dependent, and thought this could be a chance to learn about while loops in VHDL.

Any help would be appreciated, thank you.

Edit: another question, if I had a much larger vector, say 128 bits - is there a way to check if it is completely zeroed by doing something like this?

if (my_vector = (others => '0'))

6 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    The error is pretty normal because the while termination condition is indeed undefined.

    You should use a FOR loop to loop on the 18 packets and then an IF statement to test the zero condition and increment num_packets.

    But first of all, consider if your code would be really synthesizable in your device logic: it seems you are using VHDL (which is a logic description language) as a sequential programming language.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Thank you.

    1. Wouldn't a while loop be more efficient? True, it's only 18 iterations, but if I can make them 10 iterations, for example, wouldn't it be better?

    2. Any reason why it wouldn't be synthesizable? VHDL supports while loop, and it's a small loop made to determine a number.

    3. Would also love an answer for the final post edit question :)
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Using a while loop implies you think VHDL is a programming language - it is not. It is a Hardware Description Language.

    What circuit do you expect the synthesisor to implement using your while loop? if you are not sure then you should go back and review your circuit design BEFORE you write any VHDL. If you dont know what circuit you're expecting, then describing it in VHDL is quite hard. Using programming concepts in synthesised vhdl will lead to poor or non-functioning circuits.

    While loops are really used in testbenches where programming style code is acceptable, with caveats.

    answer to your questions:

    1. You need an exit condition for the while loop. Currently it will only exit when the input is 0. The synthesisor has to assume the input is anything, so has no way of knowing when the input will be 0.

    2. Because loops have to be unrolled in synthesis into parrallel/sequential circuits. As the exit condition has 2^64 different possibilities, thats a lot of logic to create. While loops are supported but should only be used in testbenches.

    3. make a ZERO constant, its the easiest to understand and code.

    
    constant ZERO_128 : std_logic_vector(127 downto 0) := (others => '0');
    ...
    if something = ZERO_128 then
    
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Also, you need a clock for counters. Logic in FPGAs really needs to be fully synchronous or you are going to have problems.

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Thanks Tricky. As an almost (:)) graduated electrical engineer I fully understand how important it is to differentiate VHDL from a programming language (I did the same mistake many years ago). Believe me that the design I am working on is much larger than what you see here and is fully synchronous.

    The reason I wanted to use a while loop was because I saw it as being efficient (the loop should execute in zero time, am I right?), or in other words didn't want to wait 18 or less clock cycles until the number num_packets is determined (though I guess it doesn't matter that much since it's a 1MHz clock). I think most importantly, I just wanted to learn new things (haven't used while loops before).

    I'll certainly take your advice and avoid using the while loop unless writing a test bench. Some final questions though:

    1. Should I do what Cris72 suggested and use a for loop with an if? It seems harmless enough, then again maybe I don't understand how it will be implemented in a circuit. in that case, should the array packets_in really be in the sensitivity list, or should only the clock be there? Both? Currently all the processes in my design have only clock in their sensitivity lists.

    2. OR, should I just do it with a simple counter and a clock?

    I know (or at least, assume) that the way to do it doesn't really matter (as the array is small), but I've written a lot of code with clocks and counters and just wanted to try new things. Another reason is, like I said, I'm looking for efficiency.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    A for loop will work in your case, as you're only going through every entry in the table. With the while loop, imagine what would happen if no entries are 0? it will just loop forever, in 0 time. The synthesisor has no way of knowing that some entries will always be zero.

    You just need a for loop that updates a counter.

    
    process(clk)
      variable num_packets : integer;
    begin
      if rising_edge(clk) begin
        num_packets := 0;
        for i in packets_in'range loop
          if packets_in(i) /= ZERO_64 then
            num_packets := num_packets + 1;
          end if;
        end loop;
        output <= num_packets;
      end if;
    end process;
    

    Here, the compiler knows exacly how many loop iterations there are, and can generate the adder circuit required.