0

I've now been a couple years working with VHDL in college and I've been using ModelSim to simulate my designs. Today, however, I noticed something I couldn't understand about for loops, so I thought I'd ask it here :)

When using two nested for loops with the same variable, such us:

for i in 0 to 9 loop
  for i in 0 to 7 loop
    mySignalVector(i)<=myOtherSignal;
  end loop
report integer'image(i);
end loop

This works perfectly, repeating the "father" loop 10 times (and therefore preserving the i value, so the reported messages are values from 0 to 10). I don't understand this, as it should replace the value for the ones in the nested for loop.

So the question is, how do for loops work in VHDL Testbench to produce this behaviour?

Thanks!

Voltage Spike
  • 75,799
  • 36
  • 80
  • 208
user90125
  • 3
  • 1
  • 3

2 Answers2

2

Many languages have scoping rules that treat variables defined in outer blocks as read-only in inner blocks. In the inner 'for', the attempt to write to a variable 'i' creates a new one that's in scope in the inner 'for' only. With a namespace per block, the compiler is not confused between outer.i and inner.i.

Even if it does work, it's certainly confusing for the programmer, and so should not be used. Is that report statement printing the final value from the inner loop, or the current value from the outer loop?

There's an annual competition to obfuscate C code, but just because you can write a program that works and looks wrong doesn't mean you should.

You will forget what you wrote in a few weeks' time, and anybody else seeing it will think 'wtf?'. If you write the hardware for a missile relying on this construct, and then the language gets updated at a later date to eliminate 'confusing' behaviour, then you'll be in trouble if it ever gets recompiled.

Neil_UK
  • 158,152
  • 3
  • 173
  • 387
  • Thanks for the answer! Thats kind of what I had thought, although I had never seen such behaviour in for loops (not that I'm an expert programmer either :P). I know it is a bad practice btw, I just wrote that by mistake and wanted to know why it worked. The report statement prints the outer loop values. – user90125 Oct 27 '15 at 23:03
1

(Reference IEEE Std 1076-2008)

  1. Scope and visibility, 12.1 Declarative region:

With two exceptions, a declarative region is a portion of the text of the description. A single declarative region is formed by the text of each of the following:
...
i) A loop statement
...

A loop statement is a declarative region.

12.3 Visibility:

A declaration is visible only within a certain part of its scope; this part starts at the end of the declaration except in the declaration of a design unit other than a PSL verification unit, a package declaration, or a protected type declaration, in which case it starts immediately after the reserved word is occurring after the identifier of the design unit, a package declaration, or protected type declaration. This rule applies to both explicit and implicit declarations. ...
Finally, within the declarative region associated with a construct other than a record type declaration or a protected type, any declaration that occurs immediately within the region and that also occurs textually within the construct is visible by selection at the place of the suffix of an expanded name whose prefix denotes the construct. ...
...
A declaration is said to be hidden within (part of) an inner declarative region if the inner region contains a homograph of this declaration; the outer declaration is then hidden within the immediate scope of the inner homograph. Each of two declarations is said to be a homograph of the other if and only if both declarations have the same designator, and they denote different named entities, and either overloading is allowed for at most one of the two, or overloading is allowed for both declarations and they have the same parameter and result type profile (see 4.5.1).

The i in the inner loop is a homograph of the i in the outer loop, and the outer loops i is not directly visible in the inner loop.

8.3 Selected names

A selected name is used to denote a named entity whose declaration appears either within the declaration of another named entity or within a design library. ...
The remaining forms of selected names are called expanded names. The prefix of an expanded name shall not be a function call.

An expanded name denotes a named entity declared immediately within a named construct if the prefix denotes a construct that is an entity declaration, an architecture body, a subprogram declaration, a subprogram body, a block statement, a process statement, a generate statement, a loop statement, or a protected type definition, and the suffix is the simple name, character literal, or operator symbol of a named entity whose declaration occurs immediately within that construct. This form of expanded name is only allowed within the construct itself, or if the prefix denotes an entity declaration and the expanded name occurs within an architecture body corresponding to the entity declaration.

So that leaves us asking how to construct an expanded name to denote a loop statement.

There's an example in 8.3 for a process statement (also shown in the LRM paragraph above):

P: process
    variable DATA: INTEGER;
begin
    -- Within process P, the name "P.DATA" denotes a named entity
    -- declared in process P. 
end process;

Statements aren't declared and don't have a name. The label serves to denote the prefix of the named entity who's simple name is the suffix.

So with a Minimal, Complete, and Verifiable example:

entity foo is
end entity;

architecture fum of foo is
    signal mySignalVector:  bit_vector (7 downto 0);
    signal myOtherSignal:   bit := '1';
begin
    process
    begin
L1:
        for i in 0 to 9 loop
            for i in 0 to 7 loop
                mySignalVector(i) <= myOtherSignal;
                report "outer loop i = " & integer'image(L1.i);
                report "inner loop i = " & integer'image(i);
            end loop;
        end loop;
        wait;
    end process;
end architecture;

Using type bit simply to avoid a context clause, we get:

ghdl -r foo
looplabel.vhdl:14:17:@0ms:(report note): outer loop i = 0 looplabel.vhdl:15:17:@0ms:(report note): inner loop i = 0 looplabel.vhdl:14:17:@0ms:(report note): outer loop i = 0 looplabel.vhdl:15:17:@0ms:(report note): inner loop i = 1 looplabel.vhdl:14:17:@0ms:(report note): outer loop i = 0 looplabel.vhdl:15:17:@0ms:(report note): inner loop i = 2 looplabel.vhdl:14:17:@0ms:(report note): outer loop i = 0 looplabel.vhdl:15:17:@0ms:(report note): inner loop i = 3 looplabel.vhdl:14:17:@0ms:(report note): outer loop i = 0 looplabel.vhdl:15:17:@0ms:(report note): inner loop i = 4 looplabel.vhdl:14:17:@0ms:(report note): outer loop i = 0 looplabel.vhdl:15:17:@0ms:(report note): inner loop i = 5 looplabel.vhdl:14:17:@0ms:(report note): outer loop i = 0 looplabel.vhdl:15:17:@0ms:(report note): inner loop i = 6 looplabel.vhdl:14:17:@0ms:(report note): outer loop i = 0 looplabel.vhdl:15:17:@0ms:(report note): inner loop i = 7 looplabel.vhdl:14:17:@0ms:(report note): outer loop i = 1 looplabel.vhdl:15:17:@0ms:(report note): inner loop i = 0
(lines omitted for brevity)
looplabel.vhdl:14:17:@0ms:(report note): outer loop i = 9 looplabel.vhdl:15:17:@0ms:(report note): inner loop i = 0 looplabel.vhdl:14:17:@0ms:(report note): outer loop i = 9 looplabel.vhdl:15:17:@0ms:(report note): inner loop i = 1 looplabel.vhdl:14:17:@0ms:(report note): outer loop i = 9 looplabel.vhdl:15:17:@0ms:(report note): inner loop i = 2 looplabel.vhdl:14:17:@0ms:(report note): outer loop i = 9 looplabel.vhdl:15:17:@0ms:(report note): inner loop i = 3 looplabel.vhdl:14:17:@0ms:(report note): outer loop i = 9 looplabel.vhdl:15:17:@0ms:(report note): inner loop i = 4 looplabel.vhdl:14:17:@0ms:(report note): outer loop i = 9 looplabel.vhdl:15:17:@0ms:(report note): inner loop i = 5 looplabel.vhdl:14:17:@0ms:(report note): outer loop i = 9 looplabel.vhdl:15:17:@0ms:(report note): inner loop i = 6 looplabel.vhdl:14:17:@0ms:(report note): outer loop i = 9 looplabel.vhdl:15:17:@0ms:(report note): inner loop i = 7

and we find we can distinguish between the two implicitly declared is by using expanded names where appropriate, hardly obfuscation at all.