Resolution func in the initialization

V

valtih1978

--- begin code ---

architecture ARCH of TOP is

type int_vector is array (integer range<>) of integer;
function driver_counter( values : int_vector ) return integer is
variable result : integer := 0;
variable l: line;
begin
for index in values'range loop
if values(index) /= 0 then
result := result + 1;
write (l, integer'image(values(index)) & ",");
end if;
end loop;
report l.all & " count resolved => " & integer'image(result);
return result;
end function;

signal S1: driver_counter integer := 6;

begin
-- s1 <= 1;
end architecture;

-- end code ---

In Modelsim, the driver_counter does not print any reports, which means
that resolution is not executed on S1, despite it is resolved and
Ashenden says

--- begin quote ---
The resolution function for a resolved signal is also invoked to
initialize the signal. At the start of a simulation, the drivers for the
signal are initialized to the expression included in the signal
declaration, or to the default initial value for the signal type if no
initialization expression is given. The resolution function is then
invoked using these driver values to determine the initial value for the
signal. In this way, the signal always has a properly resolved value,
right from the start of the simulation.

--- end quote ---


If, however, I uncomment the last line, assignment s1 <= 1, the
driver_counter is executed twice, reporting that there is only one driver.

Is everything ok? Why the resolution is not invoked when drivers are
disconnected?
 
D

Dio Gratia

The resolution function calls are caused by transactions on drivers.

No drivers, no transactions.

I added std.textio in a use clause, an entity declaration for top with no ports.

The only way I know of to get two resolution function calls would be to have S1 be evaluated in an expression after it's active (and the default valuecauses a transaction, followed by the 0 time concurrent signal assignment):

signal S1: driver_counter integer := 6;
signal S2: driver_counter integer := 0;

begin
-- s1 <= 1 ;

CONC_SIGNAL_ASSIGN_EQUIV:
process
begin
s1 <= 1;
wait; -- only a static expression on the right hand side, executes once.
end process;
s2 <= s1;

ghdl -r top
top.vhdl:19:17:mad:0ms:(report note): 6, count resolved => 1
top.vhdl:19:17:mad:0ms:(report note): 1, count resolved => 1
top.vhdl:19:17:mad:0ms:(report note): 1, count resolved => 1

The first one is for S2 following the default value assignment to S1, the second one is S1 assigned 1, the third one is for S2 being assigned S1 after an S1 transaction.

Otherwise there should be only one transaction during a simulation cycle, and without S1 appearing on the right hand side of an assignment (or in a sensitivity list) there would be only one time 0 delta cycle (and one transaction on S1, to 1).

It sounds like Modelsim is doing something you've managed to catch them outat that wouldn't otherwise matter (an extra delta cycle just for default values), or what you've presented as the behavior isn't complete. With your architecture unmodified ghdl only reports one invocation of the resolution function. (One transaction for one simulation cycle at time 0, the resolved driver value of 1):

ghdl -r top
top.vhdl:19:17:mad:0ms:(report note): 1, count resolved => 1

See IEEE Std 1076-1993, 12.4.4 (Elaboration) Other concurrent statements,
12.6.1 Drivers (Execution of a model) Drivers, and 12.6.2 (Execution of a model) Propagation of signal values. (Or equivalent sections in -2008, -2002 should match -1993).

This was done with ghdl-0.31 date stamped 20140108, gcc version.
 
V

valtih1978

Wait, I do not understand.

Is Modelsim wrong generating a transaction with single assignment S1 <=
1 but no S2 <= 1?

I expected to catch the modelsim on the resolution invocation even
without a transaction. I do not understand why do you refer me to the
IEEE sections. Do you mean that Ashenden is wrong or not absolutely
certain in the cited quote?
 
D

Dio Gratia

Wait, I do not understand.

I can short circuit all this by stating my understanding was flawed (the standard is a bit big to hold entirely in your head).

I did an email exchange with Tristan Gingold the author of ghdl overnight and he demonstrated fairly conclusively ghdl should have reported two resolution function calls:
Looks like this following patch fixes the issue:

--- a/translate/grt/grt-signals.adb Tue Jan 14 04:28:23 2014 +0100
+++ b/translate/grt/grt-signals.adb Tue Jan 14 16:50:52 2014 +0100
@@ -3257,7 +3257,7 @@

when Net_One_Resolved =>
Sig.Has_Active := True;
- if Sig.Nbr_Ports > 0 then
+ if Sig.S.Nbr_Drivers + Sig.Nbr_Ports > 0 then
Compute_Resolved_Signal (Sig.S.Resolv);
Sig.Value := Sig.Driving_Value;
end if;


I now get:

$ ghdl_mcode -c driver1.vhdl -r top
driver1.vhdl:18:5:mad:0ms:(report note): 6, count resolved => 1
driver1.vhdl:18:5:mad:0ms:(report note): 1, count resolved => 1

He found there was a missing resolution function call during the initial transaction in procedure Init_Signals (in grt-signals.adb) ignoring drivers for a resolved signal unless they were ports.

It would appear Modelsim is indeed correct reporting two resolution function call occurrences.

(The fix will show up in in ghdl-0.32, and it would appear it takes multiple drivers or a resolution function that reports like driver_counter in top.vhdl to show the problem. You've contributed indirectly to making ghdl a better VHDL tool.)
 
A

Andy

Many simulators will not call the resolution function if there is only one driver for a signal in the model. There are probably simulator settings to disable that optimization.

Andy
 
V

valtih1978

My question was about "specified behaviour in case of no drivers". Can I
remind you about that?
 
V

valtih1978

My question was about "specified behaviour in case of no drivers". Can I
remind you about that?
 
A

Andy

My question was about "specified behaviour in case of no drivers". Can I
remind you about that?

Have you contacted Modelsim about this? If so, what did they say?

While Ashenden is a recognized expert in VHDL, and IINM actually wrote partof the LRM, the LRM is the authoratative definition of the language, not Ashenden. Modelsim should follow the LRM, not Ashenden, if the two conflict.Therefore, we generally refer to the LRM when trying to figure out how a VHDL simulator should behave.

My speculation (since I am only a user of Modelsim, that's all it is, speculation) is that with no drivers, there is no reason to call a resolution function. With what argument would it be called, a null vector?

Given that your resolution function changes the value even if only one driver is used, does the signal actually get initialized to 6, or to 1 (with the concurrent assignment statement uncommented)?

If the resolution function were called with no drivers, the resolved value would be 0, not 6. Would we expect the initial value of the signal to then be 0, or 6? LRM 6.4.2.3 indicates that the value provided by the initialization expression is the initial value of the signal, but later in the same section:

"The default value associated with a scalar signal defines the value component of a transaction that is the initial contents of each driver (if any) of that signal. The time component of the transaction is not defined, but the transaction is understood to have already occurred by the start of simulation."

For most cases (wierd resolution functions excluded), there is no difference.

From the LRM descriptions, I might expect that with no drivers, the signal is initialized to 6. With one driver, the signal would have an initial value of 1 (regardless of the value assigned by the concurrent assignment, it is the resolved value of all drivers, which are initialized to 6).

Interesting test case...

Andy
 
V

valtih1978

Have you contacted Modelsim about this? If so, what did they say?

Here is a special group to ask details about VHDL. Why should we do it
in private conversation with Modelsim? We may contract Modelsim only
after we establish that their simulator is bad.

My speculation (since I am only a user of Modelsim, that's all it is,
speculation) is that with no drivers, there is no reason to call a
resolution function. With what argument would it be called, a null vector?

Yes, the fact that VHDL specification mandates the default value,
mentioned by Ashenden, means that there is no value for the function to
operate on.

From the LRM descriptions, I might expect that with no drivers, the
signal is initialized to 6.

Why not null?
With one driver, the signal would have an initial value of 1

That is clear. But why is the second call of the resolution function?
For most cases (wierd resolution functions excluded), there is no
difference.

I suspect that Ashenden precisely stipulates the wired cases that you
exclude. If there is no differece, there is no need to make the
stipulation made by Ashenden.
 
V

valtih1978

In the case of

signal UResOfRes: (or_bits) bit_vector(1 to 4) := "0111";
begin
UResOfRes <= "1111";
-- UResOfRes <= "0011";

resolutions are not invoked even with single vector. I must to enable
the second driver in order to for the resolutions to start invoking. I
always call vsim with -nvopt.
 
V

valtih1978

Curiously,

signal UResOfRes: (or_bits) bit_vector(1 to 1) := "0";
begin
UResOfRes <= "1";
UResOfRes <= "0" after 2 ns;

Calls the resolution twice, with (0,0) and (0,1) at time 0 ns whereas
the same with init value := "0" in place of "1", calls the resolution
with (1,1) at time 0 and (0,1) at time 2 ns.
 
V

valtih1978

Ok, this helped me to figure out the logic. No resolution function is
called on the signal if there are no drivers. Otherwise, the resolution
function is called to initialize the signal where the signal initial
value is used as the initial driver value. This particularly means that
resolution function

function sum(integers: integer_array) return integer
result := 0
foreach I in integers, result += I

for the signal s3 : sum integer := 3 will initialize the signal to 6
instead of 3 if there are two drivers because we have two drivers and
each contributes 3, and to 3 if there is one driver or no drivers.
 
A

Andy

There is a difference between a null vector and "no value". No value would be an error since it violates the type check on the input parameter. Calling your driver_counter() function with a null vector is completely legal (but I doubt it happens as a resolution function). The function would return avalue of 0, because the result variable is initialized to 0, and never altered if the input argument is a null vector.
Why not null?

Because null is not a legal integer value.
But why the second call of the resolution function?

Because the transaction from the concurrent assignment statement happens attime 0 plus 1 delta, whereas the initialization call happens at 0+0.
I suspect that Ashenden precisely stipulates the wired cases that you
exclude.

Semantics: "stipulate" = "explicitly state". Ashenden did not explicitly state the wierd cases. Perhaps he had them in mind, since they are one of the few ways his case could be demonstrated.

Andy
 
A

Andy

...will initialize the signal to 6 instead of 3 if there are two drivers because we have two drivers and each contributes 3, and to 3 if there is one driver or no drivers.

Did you test this, or is this what you expect will happen?

I believe you are correct, but I have not tried it.

Thanks for the info.

Andy
 
P

Paul Uiterlinden

valtih1978 said:
--- begin code ---

architecture ARCH of TOP is

type int_vector is array (integer range<>) of integer;
function driver_counter( values : int_vector ) return integer is
variable result : integer := 0;
variable l: line;
begin
for index in values'range loop
if values(index) /= 0 then
result := result + 1;
write (l, integer'image(values(index)) & ",");
end if;
end loop;
report l.all & " count resolved => " & integer'image(result);
return result;
end function;

When using access types (which "line" is), one always must be careful not to
create a memory leak. The above code contains a memory leak. A string is
allocated by calling "write". The return from the function where the
allocation took place results in loss of the "pointer" (l) to the string.
The memory used by the sting is not freed, there is no automatic garbage
collection in VHDL.

The solution is to place a deallocate statement between the report and
return statement:

deallocate(l);

Even if the procedure writeline was used (instead of report), deallocate
would be necessary. The writeline procedure leaves l pointing to an empty
string. Even an empty string uses a non-zero amount of memory.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,540
Members
45,025
Latest member
KetoRushACVFitness

Latest Threads

Top