RE: [sv-ec] fork..join_none/join_any and automatic variables


Subject: RE: [sv-ec] fork..join_none/join_any and automatic variables
From: Jay Lawrence (lawrence@cadence.com)
Date: Thu May 22 2003 - 05:20:18 PDT


As pointed out by Vassilios below, I did participate in the testbench
enhancments and so I'll throw in my $.02.

First of all, we did object to adding automatic variables in static
contexts such as named blocks because it creates just this sort of
confusion and no expressive power. We lost that vote ....

We voted for fork/join_{none,any,all} only because all other forms of
process control had been eliminated. We actually preferred a different
syntax (i.e. join (<expression>)), but consensus drove us to agree on
this one amoung about 5 choices. We also preferred the versions that
gave a handle to the process so more control was possible, but this was
deemed too difficult and no firm proposal arose.

Secondly, I think the original question here was about how automatic
variables behave in the presense of fork/join_none, not 1364
compatibility. The compatibility question only comes up because
SystemVerilog is silent on the topic. I completely agree with Mac and
Steve that the lifetime of a variable in a named block is completely a
function of the named block and has nothing to do with a fork/join.

Let's work through a few small examples to build up to it:

        reg [7:0] count;

        ...
        begin : name
                automatic reg [7:0] prev;

                prev = count;
                @(count)
                if (count !== (prev + 1))
                        $error("Counter didn't count\n");
        end
        ...

There is no question. The automatic variable 'prev' is allocated on each
entry to the block. It is then assigned count, the test is performed and
then it goes away after the 'end'.

Now, lets put a regular fork/join in the block:

        begin : name
                automatic reg [7:0] prev;

                fork
                        F1 : prev = count;

                        F2 : begin
                                @(count)
                                if (count !== (prev + 1))
                                        $error("Counter didn't
count\n");
                        end
                join
        end

Again, there is no issue here. The variable 'prev' is allocated upon
entry to the block 'name' and is visible to both subprocess of the
fork/join. It is critical that this is the same 'prev' in both processes
because it is set in one and tested in the other. Upon completion of the
named block this copy of 'prev' no longer exists because the block has
exited. This behavior doesn't change just because there is a fork/join
inside the block.

Now let's change it to a fork/join_none.

        ...
        begin : name
                automatic reg [7:0] prev;

                fork
                        F1 : prev = count;

                        F2 : begin
                                @(count)
                                if (count !== (prev + 1))
                                        $error("Counter didn't
count\n");
                        end
                join_none
        end
        ...

Upon entry to the 'name' block a new copy of 'prev' is created.
 
Upon entry of the fork/join_none, 2 subprocess are spawned F1 and F2,
this has no effect on the allocation of 'prev'.

There are now 3 things that must happen in a non-deterministic fashion.
- The block 'name' must continue execution in this cycle
- The subprocess F1 must run
- The subprocess F2 must run

As soon as 'name' continues, it exits the block and the variable 'prev'
is no longer valid. If either F1 or F2 executes after this continuation
then 'prev' no longer exists. Note, that it is guaranteed that F2 at
least will attempt to access 'prev' after the block has exited because
the @clock will cause it to block for at least one cycle.

Although the SystemVerilog LRM is silent on this topic I believe there
is no choice but to have some sort of runtime error when F1 or F2
attempt to reference 'prev'.

Jay

> -----Original Message-----
> From: Vassilios.Gerousis@Infineon.Com
> [mailto:Vassilios.Gerousis@Infineon.Com]
> Sent: Thursday, May 22, 2003 2:10 AM
> To: mac@verisity.com; ram@Model.com
> Cc: Steven Sharp; David.Rich@synopsys.com; sv-ec@eda.org
> Subject: RE: [sv-ec] fork..join_none/join_any and automatic variables
>
>
> Dear Mac And Steven,
> Neither of you have participated in SystemVerilog Testbench
> development. This topic was discussed in length. Keyword
> Additions were also
> discussed in lengths. This committee have spent more than two
> months hashing
> these issues. Many of those items have been debated,
> discussed and voted
> including the participation of a Cadence representative (Jay
> Lawrence) and
> also participation of IEEE members. (Mac) Verisity did not
> participate in
> this activity due to concerns about e and SystemVerilog Testbench.
> LRM 3.1 has been developed, reviewed and approved.
> Neither you Mac
> and you Steven provided any feedback during this period. LRM 3.1 is a
> technically approved standard. If you want to file an issue
> list you can do
> that formally and add it to the issue list. We will address
> all issues and
> enhancements post 3.1 activities. At that point of time,
> both of you are
> welcome to debate this issue.
>
>
> Best Regards
>
> Vassilios
>
> -----Original Message-----
> From: Michael McNamara [mailto:mac@verisity.com]
> Sent: Thursday, May 22, 2003 3:13 AM
> To: Randy Misustin
> Cc: mac@verisity.com; Steven Sharp; David.Rich@synopsys.com;
> sv-ec@eda.org
> Subject: Re: [sv-ec] fork..join_none/join_any and automatic variables
>
>
>
>
> Randy Misustin writes:
> > Mac & Steve,
> >
> > Truly, your attempts to educate me are appreciated. Alas,
> though, all
> > this is unnecessary. I understand extremely well how
> traditional Verilog
> > works, I've got a pretty solid grasp of Verilog 2001, and an
> > ever-expanding appreciation of SystemVerilog's additions
> to the fray.
> > The semantics of fork-join in a static environment are very well
> > understood by customers and vendors, alike. The entire
> discussion/debate
> > I intended to launch is limited to semantic quirks around
> forks in the
> > presence of automatic variables and then whether SystemVerilog's
> > introduction of a fork-join_none has any bearing on all
> this. I don't
> > believe the discussions about how static variables interact with
> > fork-join are pertinent, except to indicate the probable
> expectations of
> > a user coming from a long history of Verilog.
> >
> > -randy.
>
> Great, I am glad we are in sync, and hop our comentary help some folks
> lurking on this list.
>
> Where I am coming from, and I believe Steve as well, and
> perhaps you as
> well, is a basic premise that additions to a living language should be
> evaluated against three directives. They must:
>
> a) be backwards compatible.
> b) produce few surprizes.
> c) add useful value.
>
> So now that we've all convinced each other that we understand
> the semantics
> of fork and join, and static variables, and that automatic
> variables cease
> to exist when their enclosing scope is exited, we can step to
> the next page.
>
>
> Part of the Accellera proposed addition to the language is
> the introduction
> of a fork .. join_none construct; which from the context I
> assume (correct
> me if I am wrong or it has changed) is that it initiates the various
> enclosed statements, each in their own flow of control, and
> then immediately
> passes execution to the statement after the join_none. An example:
>
> initial begin : a
> automatic reg [7:0] auto;
> reg [7:0] static;
> fork : f
> task_a;
> task_b;
> join_none
> statement_a;
> statement_b;
> statement_c;
> end
>
>
> In my mind this is equivalent to:
>
> initial begin : a
> automatic reg [7:0] auto;
> reg [7:0] static;
> fork : f
> task_a;
> task_b;
> begin
> statement_a;
> statement_b;
> statement_c;
> end
> join
> end
>
> with perhaps the distinction that a disable of 'f' would kill
> execution of
> task_a, task_b and which ever of statement_{a,b,c} was
> executing in example
> two; however would only get task_a and task_b with example 1.
>
> There is no other difference in my mind.
>
> You are concerned with what would happen if there was an
> automatic variable
> in the scope 'a', and statement_{a,b,c} completed before one
> or more of
> task_a and task_b completed.
>
> This question is a very useful way to test whether my
> assumption of the
> mapping of fork..join_none to fork..join is correct.
>
> I believe that what would be most backwards compatible, least
> surprising,
> and most useful would be for the scope named 'a' to exist and
> be active
> until each statement in the fork..join_none has completed, and each
> statement in the blocks of code after the join_none have completed.
>
> Hence any automatics declared in the scope 'a' would continue
> to exist for
> the entire life of each and every thread initiated from the scope has
> completed (which could be never), as well as the lives of the
> subsequent
> statements.
>
> If the flow of control multiply enters the scope 'a', then these
> silmultaneously active 'a's will each have their own copy of
> the variable
> 'auto', but will share access to the variable named 'static'.
>
> I fully recognize that this then reduces the join_none to be
> just a very
> slight semantic enhancement over the existing fork..join.
>
> I expressed this analysis to Peter Flake and Simon when I was on the
> CoDesign technical advisory board many years ago; however it
> seems that the
> constructs lived on.
>
> Don't get me wrong, I do feel that the fork..join_any is a
> useful shorthand
> for:
>
> fork : f
> begin
> task_a;
> disable f;
> end
>
> begin
> task_b;
> disable f;
> end
>
> ...
>
> begin
> task_z;
> disable f;
> end
> join
>
> to
>
> fork
> task_a;
> task_b;
> ...
> task_z;
> join_any
>
> and think it is a good addition, even though it uses up a keyword.
>
>
> However, in my opinion the join_none adds no value. I
> believe it is only
> there due to a misguided sense of completion; one has a join
> which waits for
> all; one has a join that waits for the first; why not add a
> join that waits
> for no one?
>
> I ask, why add such a thing?
>
> It uses up name space (breaking backwards compatibility),
> adds no modeling
> value (breaking requirement to add value), and is difficult
> to understand
> (provides surprise).
>
> -mac
>
>



This archive was generated by hypermail 2b28 : Thu May 22 2003 - 05:23:17 PDT