0

I am trying to write a block of data (16 bytes, 4 words) from my entity cache to my other entity memory.

The memory is byte addressable, so I can write only 1 byte at a time. The memory will update mem_done to 1 when a byte has been written.

To write a block, I need to:

  • write one byte,

  • wait for mem_done to be set (by memory entity),

  • increment mem_address (next address to give to memory), byte_count, and each 4 bytes increment word_offset (offset of the word in cache).

  • loop until all the words have been written (word_offset = words_per_block-1).

On synthesis with Xilinx, I get an error "Non-static loop limit exceeded" for wait_loop.

  • I can't use wait until statement in a loop (error: multiple wait statements not allowed).

  • I can't use an FSM because transitions of state will waste one clock cyle (and I have timing constraints).

How can I do it otherwise without breaking the loop limit ?

-- block dirty in memory, write cache block back to memory
mem_enable   <= '1';      -- out to memory, enable memory transfer
mem_rw       <= '1';      -- out to memory. read/write bit
mem_addr_tmp <= cpu_addr; -- internal, address to write to
word_offset  <= 0;        -- internal, offset in cache
byte_count   <= 31;

burst_loop: loop
    -- Transfer 1 byte of data
    mem_data     <= CACHE(index).data(word_offset)(byte_count downto byte_count-7);
    mem_addr     <= mem_addr_tmp;
    wait_loop: loop
        if mem_done = '1' then  -- mem_done comes from memory entity
            exit wait_loop;
        end if;
    end loop wait_loop;

    -- Update address, word offset, byte count
    mem_addr_tmp <= std_logic_vector(to_unsigned(to_integer(unsigned(mem_addr_tmp)) + 1, mem_addr_tmp'length));
    if (byte_count mod 4 = 0) then -- a word has been transfered, increment word_offset
        word_offset  <= word_offset + 1;
        byte_count   <= 31;
    else                           -- a byte of a word has been transfered
        byte_count   <= byte_count - 7;
    end if;
    exit burst_loop when (mem_done = '1' and word_offset = words_per_block-1);
end loop burst_loop;    
mem_enable <= '0';
JahMyst
  • 1,616
  • 3
  • 20
  • 39
  • In a clocked process. Assuming you want hardware, you'll have to rewrite this as a state machine, that (when it's in the waiting state) tests mem_done and advances to the next state when it's '1'. –  Mar 29 '15 at 22:34
  • Ok but this way I lose 1 clock cycle to advance to the next state. I have timing constraints and this add an undesired cycle to it. – JahMyst Mar 30 '15 at 23:12
  • Not necessarily, because you can do something in parallel with that state transition, i.e. do it in the `if mem_done='1' then ...` clause where you update the state variable. –  Mar 30 '15 at 23:49

1 Answers1

2
wait_loop: loop
    if mem_done = '1' then  -- mem_done comes from memory entity
        exit wait_loop;
    end if;
end loop wait_loop;

This is an infinite loop when mem_done = '0'. In VHDL, a statement's execution time is instantaneous, with the very important exception of wait statements. Thus, if mem_done is '0' when the loop is entered, it will never exit since time will never advance.

Furthermore, wait statements are generally not synthesisable. We use state machines to yield sequential statements in VHDL (otherwise, statements are executed in parallel).

Finally, loops in VHDL (for synthesis) are used to represent spatial looping, you used them for temporal looping, as you would in a programming language (VHDL is an hardware description language). If you will, loops are always unrolled and only offer a neater way to write multiple similar statements. In simulation, you can use loops as you do in programming languages through the use of wait statements.

Jonathan Drolet
  • 3,318
  • 1
  • 12
  • 23