Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] Using loops to access sections of 2D arrays in VHDL

Status
Not open for further replies.

maciej

Newbie level 2
Newbie level 2
Joined
Nov 13, 2013
Messages
2
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Visit site
Activity points
38
Since this is my first post here I say hello.

Now to the point. I have a 2-dimensional array 256x60 (256-bits of data from each sensor, maximum of 60 sensors are read in parallel). I would like to save it to FPGA's internal RAM as 16-bit words. It seemed easiest to split data stream from each sensor into 16 bits x 16 words. Now the question is how to do it?

First I have tried the following way:


Code VHDL - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
--type and signal definitions
type SED_BUF_ARRAY_TYPE is array(255 downto 0, 59 downto 0) of std_logic;
signal SED_BUF      : SED_BUF_ARRAY_TYPE;
signal WordNumber   : natural range 0 to 31;
--[...]
process(clk)
    variable startBit : natural range 255 downto 0;
begin
    if(clk'event and clk = '1') then
        if wordNumber < 16 then
            wordNumber <= wordNumber + 1;
 
            startBit := wordNumber*16;
 
            for bitInChainCnt in startBit to (startBit+15) loop
                meb_dti(bitInChainCnt - startBit)   <= SED_BUF(bitInChainCnt, 0);
            end loop;
        else
            wordNumber <= 0;
        end if;
    end if;
end process;



This method fails because for loop requires constants as range parameters. And annoyingly synthesis doesn't give warnings (Quartus II), it just assumes startBit is always 0.

So the result here is:
Code:
After  1'st rising edge of clk: meb_dti(15 downto 0) is equal to SED_BUF(15 downto 0, 0)
After  2'nd rising edge of clk: meb_dti(15 downto 0) is equal to SED_BUF(15 downto 0, 0)
...
After 16'th rising edge of clk: meb_dti(15 downto 0) is equal to SED_BUF(15 downto 0, 0)

While I would like to get the following result:
Code:
After  1'st rising edge of clk: meb_dti(15 downto 0) is equal to SED_BUF(15 downto 0, 0)
After  2'nd rising edge of clk: meb_dti(15 downto 0) is equal to SED_BUF(31 downto 16, 0)
...
After 16'th rising edge of clk: meb_dti(15 downto 0) is equal to SED_BUF(255 downto 240, 0)

Any ideas how to approach the problem (short of copy-pasting the for loop 16 times with fixed numerical ranges)?

Just a few comments:
- A second index of SED_BUF is 0 at the moment to simplify the problem (I will assign a signal to it later). And synthesis is much shorter this way.
- I know that I could use the bit shift instead of multiplying by 16, but it is not the point here ;)
 

Personally, I would just store 256-bit words and let the tools figure out how to allocate the RAM. If you think you're smarter than the tool, then by all means go ahead, but depending on the chip you are using, 16-bit words may not be optimal since some FPGAs use 18-bit wide RAM.

But all that aside, I think your code is more complex than you want, unless you really need to store one bit at a time. What about something like:

Code:
type SED_BUF_ARRAY_TYPE is array (59 downto 0) of std_logic_vector(255 downto 0)
 
  • Like
Reactions: maciej

    maciej

    Points: 2
    Helpful Answer Positive Rating
This method fails because for loop requires constants as range parameters. And annoyingly synthesis doesn't give warnings (Quartus II), it just assumes startBit is always 0.
Strange. I wasn't yet able to compile any code in Quartus that obviously violates VHDL syntax rules, neither it worked for the present code. Which Quartus version?

As you already know that it's no legal VHDL, why didn't you refer to on easy workaround?

In the present case, run the loop over 0 to 15 and do the index calculation later.
 

Without the full code, its diffucult to really know whats going on. Also, a for loop does NOT require constant parameters, but as quartus needs to unroll loops for parrallel hardware, it has to assume worst case, which is why it will always start at 0.

Using arrays like this may also be problematic. In the past I have tried to make quartus infer mutliple rams from arrays of arrays and generate loops. but it wouldnt work. Enhancement requests were raised, but as ever, Quartus VHDL support moves forward at a glacial pace.
 

Also, a for loop does NOT require constant parameters.
As far as I'm aware of, the VHDL requirement that range bounds (e.g. for i in <somerange> loop) must be constant hasn't been suspended in VHDL 2008. Please correct me if I'm wrong. And Quartus 13 still flags an error.
 

That requirement may be true for synthesis, but as an LRM rule, loops do not need constant ranges. This works perfectly fine in modelsim (and Ive used many similar things in testbenches - most often for modelling random timings on busses).


Code VHDL - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
entity test2 is
end entity test2;
 
architecture sim of test2 is
begin
 
  process
    variable a : integer;
  begin
    
    a := 10;
    
    for i in 0 to a loop
      report integer'image(i) severity NOTE;
    end loop;
    
    wait;
    
  end process;
  
end architecture sim;

 
  • Like
Reactions: FvM

    FvM

    Points: 2
    Helpful Answer Positive Rating
You are right, the VHDL LRM doesn't require a static (constant) iteration range. IEEE 1076.6 (RTL synthesis) however does.
 

-> barry
Thanks for the suggestion. It is quite obvious now it is much easier to use array of vectors instead of 2D arrays of std_logic. Still one sometimes gets stuck and doesn't see the simple way out. (And I know I am definitely not smarter than a tool ;)).
-> FvM
I use an ancient version 10.1. I need support also for an older CPLD and it's not present in the further versions.
-> TrickyDicky
Sure I know full code would be useful, but it is long and messy, I just wanted to focus on this particular problem.
The project's background is such that I get 256 bits of data from existing physical device and I need to forward it to another entity, which accepts only 16-bit words (I can't modify the width of it's data bus). So in short I am working on a kind of interface/buffer entity.

Anyway if someone stumbles upon a similar problem I put a workaround solution which works fine for me (no need for for loop anymore):


Code VHDL - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
type SED_BUF_ARRAY_TYPE is array (59 downto 0) of std_logic_vector(255 downto 0);
signal SED_BUF      : SED_BUF_ARRAY_TYPE;
signal WordNumber   : natural range 0 to 31 := 0;
--[...]
process(clk)
    variable startBit : natural range 255 downto 0;
begin
    if(clk'event and clk = '1') then
 
        if WordNumber < 16 then
            WordNumber  <= WordNumber + 1;
            startBit    := WordNumber * 16;
 
            meb_dti(15 downto 0) <= SED_BUF(0)(startBit+15 downto startBit);
        else
            WordNumber <= 0;
        end if;
    end if;
end process;

 

I get the feeling you're approaching this problem via the code, rather than thinking about the architecture. The code has to map to something, and if you draw out the underlying memories and interfaces before going to code, you'll probably have an easier time of it (and may be easier for the next engineer to understand).
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top