Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interface getter functions for interface parameters return default (not overridden) value #996

Closed
veripoolbot opened this issue Nov 6, 2015 · 13 comments
Assignees
Labels
resolution: fixed Closed; fixed

Comments

@veripoolbot
Copy link
Contributor


Author Name: Todd Strader (@toddstrader)
Original Redmine Issue: 996 from https://www.veripool.org

Original Assignee: Todd Strader (@toddstrader)


https://github.com/toddstrader/verilator-dev/tree/intf_param_getter

See: t_interface_parameter_getter

The test doesn't work with ModelSim (at least the crusty, old version I'm stuck on right now), but I can confirm that this functionality works in Quartus. In any case, I believe it's clear that the function should return the overridden value. I'll start looking into the solution.

@veripoolbot
Copy link
Contributor Author


Original Redmine Comment
Author Name: Wilson Snyder (@wsnyder)
Original Date: 2015-11-10T00:32:23Z


Good hunting.

@veripoolbot
Copy link
Contributor Author


Original Redmine Comment
Author Name: Todd Strader (@toddstrader)
Original Date: 2015-11-11T01:19:31Z


This works and doesn't break anything else:

https://github.com/toddstrader/verilator-dev/tree/intf_param_getter

I can clean it up, but I first wanted to discuss to see if there was a more elegant way to do this. Some things I have learned along the way:

  • This only affects constified function calls
  • linkDotParamed() re-points all (remaining) function calls from the default interface to the paramed one (when needed)
  • This is too late for constified function calls because that must happen earlier in param()
  • At the point which the function call in question is constified, both versions of the interface exist (default and paramed)
  • The interface in the port map of the module also already points to the paramed interface at this point

Using all of this, the solution just tries to connect the dots. Is there something simpler that could be done here?

If not, I'll clean this up and re-post.

@veripoolbot
Copy link
Contributor Author


Original Redmine Comment
Author Name: Wilson Snyder (@wsnyder)
Original Date: 2015-11-12T01:57:58Z


The test doesn't work even with the 2015.09 version of VCS, which is generally fairly aggressive language wise. Are you sure this is legal syntax according to IEEE? I'm generally reluctant to support stuff that is only in a single commercial simulator.

Error-[FNLD] Function not locally declared
t/t_interface_parameter_getter.v, 49
  Following XMR function call has no locally declared target.
  Source info: i.getFoo()

Error-[FNLD] Function not locally declared
t/t_interface_parameter_getter.v, 50
  Following XMR function call has no locally declared target.
  Source info: i_no_mp.getFoo()

@veripoolbot
Copy link
Contributor Author


Original Redmine Comment
Author Name: Todd Strader (@toddstrader)
Original Date: 2015-11-12T11:07:52Z


I'm not entirely sure. Sometimes the LRM reads more like a story than a spec. I think this is one of those instances. Section 13.4.3 gives a list of rules for a constant function. getFoo() abides by all these rules, except for the fact that getFoo() isn't in the module's scope that is calling it. This detail isn't explicitly mentioned in section 13.4.3, but the general case is obvious. Clearly you can't have two modules, each with localparams that are defined using hierarchical references to each other. If you did this you'd have an elaboration loop.

Interfaces create scope in the same way that modules do (section 23.9), so it would stand to reason that you couldn't treat i.getFoo() as a constant function. And sadly, section 25 on interfaces doesn't discuss the possibility of using interface functions to define parameters or localparams. However, I'd argue that this information can already be leaked from the interface by declaring a signal in the interface like so:

logic [ FOO - 1 : 0 ] FOO_sized;

And then doing this in a module which gets the interface:

$bits(FOO_sized)

Which is effectively the same thing as i.getFoo(). It side-steps the rule about constification of hierarchical references, but it does so because with interfaces, the constant values are already paramed by the time we get to the module which refers to an interface.

Of course, this is more an argument for the LRM working group, rather than you.

Instead of all this, we can take this direction:

http://www.edaplayground.com/x/UWi

Which works with VCS and ModelSim. There's still the question of function constification, but now we have two commercial simulators that agree on this. Verilator appears to have two problems with this:

  • Non-modported interfaces toss an unlinked varref when trying to access i_no_mp.FOO
  • Modported interfaces say they can't find FOO in i.FOO (see section 25.10 on this one, which does have a clear example)

What do you think? Would you prefer i.FOO over i.getFoo()? I can switch gears and implement the former which agrees with more EDA tools.

@veripoolbot
Copy link
Contributor Author


Original Redmine Comment
Author Name: Wilson Snyder (@wsnyder)
Original Date: 2015-11-13T03:36:56Z


I'd suggest we should side with the majority and use the eda playground example.

@veripoolbot
Copy link
Contributor Author


Original Redmine Comment
Author Name: Todd Strader (@toddstrader)
Original Date: 2015-11-13T10:13:17Z


Sounds like a plan. I'll start working on it.

@veripoolbot
Copy link
Contributor Author


Original Redmine Comment
Author Name: Todd Strader (@toddstrader)
Original Date: 2015-11-13T12:33:28Z


One other thing. We should probably make interface functions non-constible outside of the interface to match the other simulators' behavior as well. The current always-constifies-to-default behavior is confusing. Wilson, do you agree?

I'll probably break this issue up into a few tasks.

@veripoolbot
Copy link
Contributor Author


Original Redmine Comment
Author Name: Wilson Snyder (@wsnyder)
Original Date: 2015-11-13T14:40:13Z


Yes, but that's a separate mostly orthogonal task, as you noted.

@veripoolbot
Copy link
Contributor Author


Original Redmine Comment
Author Name: Todd Strader (@toddstrader)
Original Date: 2017-05-11T16:03:34Z


Looking at this again:
https://github.com/toddstrader/verilator-dev/tree/intf_parameter_const_access

When I run t_interface_parameter_access.pl as-is, I get:

%Error: t/t_interface_parameter_access.v:52: Parameter-resolved constants must not use dotted references: FOO

This happens because during param(), VarXRef varps are nuked:
https://github.com/toddstrader/verilator-dev/blob/intf_parameter_const_access/src/V3Param.cpp#L286

First off, I don't follow the comment "// Needs relink, as may remove pointed-to var". Can you explain why the VarXRef varps are being removed at this stage?

Secondly, I guess I could try to preserve the varps for VarXRefs that are only pointing into interfaces. I don't know what side effects that might have, but even if that were benign, we still wouldn't have all the information we need. This is because the VarXRef we're assigning to THE_FOO

     1:2: VAR 0xb0ad50 <e182> {e52} @dt=0@  THE_FOO LPARAM
     1:2:1: BASICDTYPE 0xb0ac70 <e100> {e52} @dt=this@(nw0)  LOGIC_IMPLICIT kwd=LOGIC_IMPLICIT
     1:2:3: VARXREF 0xadf480 <e221> {e52} @dt=0@  FOO [RV] <- intf. - VAR 0xadca90 <e10> {e8} @dt=0@  FOO GPARAM

currently points at the interface's parameter (0xadca90)

     1: IFACE 0xadd690 <e194> {e8}  test_if  L4 [LIB]
     1:2: VAR 0xadca90 <e10> {e8} @dt=0@  FOO GPARAM
     1:2:1: BASICDTYPE 0xadb950 <e11> {e8} @dt=this@(sw32)  integer kwd=integer range=[31:0]
     1:2:3: CONST 0xadb070 <e12> {e8} @dt=0xadbe50@(G/swu32/1)  ?32?sh1

not the parameter from the the_interface cell (0xae2b00).

     1:2: CELL 0xae2d80 <e53> {e32}  the_interface -> IFACE 0xadd690 <e194> {e8}  test_if  L4 [LIB]
     1:2:2: PIN 0xae2b00 <e46> {e32}  FOO -> VAR 0xadca90 <e10> {e8} @dt=0@  FOO GPARAM
     1:2:2:1: CONST 0xae2c40 <e47> {e32} @dt=0xae27f0@(G/swu32/3)  ?32?sh5

Which means that best case scenario, we'd still be getting the default parameter value and not the value from the specific interface we're referencing. I'm still digging, but any advice on how to proceed would be appreciated.

Also, as a side note, I noticed that Riviera likes i.getFoo() and does not like i.FOO:
https://www.edaplayground.com/x/UWi#

While I believe the two are morally equivalent, I do agree that i.FOO is probably more defensible per the LRM. But if all else fails, maybe we can consider i.getFoo() again.

@veripoolbot
Copy link
Contributor Author


Original Redmine Comment
Author Name: Todd Strader (@toddstrader)
Original Date: 2017-05-11T22:21:41Z


OK, I think I just rubber ducked this. Please ignore the previous post. I've got something which is passing now. I need to spend some time cleaning up the mess I made, but I think it's pretty close.

@veripoolbot
Copy link
Contributor Author


Original Redmine Comment
Author Name: Todd Strader (@toddstrader)
Original Date: 2017-05-12T14:39:12Z


Ready to go:
https://github.com/toddstrader/verilator-dev/tree/intf_parameter_const_access

Passes all Verilator tests and our internal tests.

@veripoolbot
Copy link
Contributor Author


Original Redmine Comment
Author Name: Wilson Snyder (@wsnyder)
Original Date: 2017-05-19T02:49:49Z


Great! Thanks again for good work.

Pushed to git towards 3.903.

@veripoolbot
Copy link
Contributor Author


Original Redmine Comment
Author Name: Wilson Snyder (@wsnyder)
Original Date: 2017-05-31T02:07:08Z


In 3.904.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
resolution: fixed Closed; fixed
Projects
None yet
Development

No branches or pull requests

2 participants