0
\$\begingroup\$

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
93.1k53 gold badges93 silver badges243 bronze badges
asked Oct 27, 2015 at 9:03
\$\endgroup\$
0

2 Answers 2

2
\$\begingroup\$

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.

answered Oct 27, 2015 at 9:49
\$\endgroup\$
1
  • \$\begingroup\$ 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. \$\endgroup\$ Commented Oct 27, 2015 at 23:03
1
\$\begingroup\$

(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.

answered Oct 28, 2015 at 6:17
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.