JRR
JRR

Reputation: 6152

how can I implement unbounded loops in FPGA?

I understand that loops that run for predefined number of iterations are unrolled during HLS. But what about loops without predefined bounds? e.g.,

for (i = 0; i < j; i++) { ... }

How are such loops implemented in FPGAs?

Upvotes: 2

Views: 890

Answers (1)

PlayDough
PlayDough

Reputation: 1138

I'm not sure how this is VHDL or Verilog related, since you explicitly state HLS and give a C style question. But certainly in VHDL, unbound loops are not explicitly supported. There are cases where you can use unbounded loops, but they must terminate at some point.

As user1155120 pointed out, dynamic loop constraints are not supported. But to expand on that a bit.

Edit: Initially I used the term "unbounded" when I should have said "dynamic range" loops. I've updated the answer with that language.

So, first, some types of loops with pseudo-dynamic ranges are supported. For example:

for i in 0 to 7 loop
  for j in 0 to i loop
    ...
  end loop;
end loop;

This really isn't dynamic, since these are easily unrolled. The synthesizer can determine the bounds on this loop. Clearly j can only go from 0 to 7. But other kinds of dynamic loops are not supported:

signal a : natural;
...
for i in 0 to a loop
...
end loop;

In this case, the range of the loop is not known statically.

But there is a way to dynamically "bound" loops based on inputs, but it does require knowledge of the bounds of the input. One can do something like:

signal a : natural range 0 to 7;
...
for i in 0 to 7 loop
  if ( i < a ) then
    ...
  end if;
end loop;

Now the loop effectively only operates up to the value of a. (Some caution here. When doing this, memory--flops or latches depending on the context--may be inferred inside the if/end if for those cases where the the loop terminates early. There are ways to avoid it, but that's outside the scope of this answer.)

RTL cannot be synthesized to dynamic structures. So your design will have to be sized for the largest possible case, and then dynamically choose how many iterations up to the maximum supported will be done.

One final note. There is support for unbounded loops (while loops), though it does require that the loop be terminated. Let's take the typical free running counter example:

signal ctr : unsigned(31 downto 0) := (others => '0');
...
process(clk)
begin
  if ( rising_edge(clk) ) then
    ctr <= ctr + 1;
  end if;
end process;

This can also be expressed in another manner:

process
begin
  wait until rising_edge(clk);
  ctr <= ctr + 1;
end process;

And it is possible to use an unbounded loop, for example:

process
begin
  while true loop
    wait until rising_edge(clk);
    ctr <= ctr + 1;
  end loop;
end process;

All of these are synthesizable.

WARNING Discussion below is crazy stuff and should not be used as an example of code. The examples are for discussion purposes only.

And dynamic ranged loops are synthesizable, though their functionality isn't clear. For example:

signal a   : natural := 33;
signal ctr : natural := 0;
...
process
begin
  for i in 0 to a-1 loop
    wait until rising_edge(clk);
    ctr <= ctr + 1;
  end loop;
end process;

Or even an unbounded loop:

process
  variable i : natural := 0;
begin
  while i < a loop
    wait until rising_edge(clk);
    ctr <= ctr + 1;
  end loop;
end process;

These both synthesize. But the latter is especially problematic as it does not simulate well, especially when i >= a.

Upvotes: 5

Related Questions