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

Public signal driven by C++ not propagating as expected #622

Closed
veripoolbot opened this issue Feb 21, 2013 · 5 comments
Closed

Public signal driven by C++ not propagating as expected #622

veripoolbot opened this issue Feb 21, 2013 · 5 comments

Comments

@veripoolbot
Copy link

@veripoolbot veripoolbot commented Feb 21, 2013


Author Name: Jie Xu (@jiexu)
Original Redmine Issue: 622 from https://www.veripool.org


For our simulation we need to drive/change some signals using C++ code. We do this both by change the c++ signal directly and/or using DPI functions.

However, we notice that sometimes the change of signal by C++ code do NOT take further effect to change other signals.

For example, for the following verilog code:

`begin_keywords "1800-2005"
module sim_top( clk, res);

input wire clk;
output wire res;

reg we_a; // even not working with /*verilator public*/

always@(we_a)  
// works if replaced upper line with always@(posedge clk)
begin
     res = we_a;
end
// NOT working if replace above block as   assign res = we_a;

export "DPI-C" task write_we;
task    write_we;
     input   bit in;
     we_a = in;
endtask

endmodule

If we change the value of @we_a@ during simulation using the @write_we@ function, the value of @res@ will NOT changed.

The main reason here is that the signal @we_a@ was NOT driven by any other signals in the verilog code except the task. Then I guess Verilator will only initialize its value and further signal driven by @we_a@ in the beginning of simulation. No further updates are necessary for further simulation.

However, this is not true if we change the value of @we_a@ using C++ code.

Possible improvement to Verilator could be automatically detecting these signals:

  1. signal marked by /verilator public/;

  2. signal driven by exported verilog-tasks,

and treating them just like input signals to the module.

The full test case is attached.

@veripoolbot

This comment has been minimized.

Copy link
Author

@veripoolbot veripoolbot commented Feb 22, 2013


Original Redmine Comment
Author Name: Wilson Snyder (@wsnyder)
Original Date: 2013-02-22T11:52:09Z


Verilator is a (mostly) statically scheduled simulator and at present any continuous assignments such as this

always@(we_a) res = we_a;

are equivalent to what synthesis would do, namely a buffer that is always driven with we_a (on whatever clock edge we_a is driven by). Thus that buffer will always override a manual update.

Adding posedge lets it be overriden, until the next posedge anyways.

A fix would requires edge sensitivity which is not in the medium term (and would be much slower).

Sorry.

@veripoolbot

This comment has been minimized.

Copy link
Author

@veripoolbot veripoolbot commented Feb 22, 2013


Original Redmine Comment
Author Name: Jie Xu (@jiexu)
Original Date: 2013-02-22T14:02:27Z


Hi Wilson,

Your synthesis buffer explanation makes sense. But I am not sure verilator treat this correctly or not.

I have investigated into the generated c++ codes. The reason why

always@(we_a) res = we_a;

is not working is basically because the @comb_@ function for updating this is taken out from @eval_@. However, if the signal is a input, the the @comb_@ function still exists and everything works if we poke a value using c++.

In general cases, this is OK. However, if the signal is declared as @/verilator public/@ or driven by a exported task, then perhaps Verilator shall NOT take out the @comb_*@ function.

I actually found out where we can easily patch verilator for this purpose. I have tested the following codes works if we define the signal as @/verilator public/@:

--- a/src/V3Order.cpp
+++ b/src/V3Order.cpp
@@ -1085,6 +1085,9 @@ void OrderVisitor::processDomainsIterate(OrderEitherVertex* vertexp) {
      if (vvertexp && vvertexp->varScp()->varp()->isInput()) {
         domainp = m_comboDomainp;
      }
+    if (vvertexp && vvertexp->varScp()->varp()->isSigPublic()) {
+       domainp = m_comboDomainp;
+    }
 #endif
      if (vvertexp && vvertexp->varScp()->isCircular()) {
         domainp = m_comboDomainp;

But I am not sure how this patch will affect other processing of Verilator. Could you please have a check and give some suggestions? Thanks.

@veripoolbot

This comment has been minimized.

Copy link
Author

@veripoolbot veripoolbot commented Feb 23, 2013


Original Redmine Comment
Author Name: Wilson Snyder (@wsnyder)
Original Date: 2013-02-23T00:26:24Z


Good job tracking that down, I'm impressed. However if you add some more complicated logic downstream I don't think it will propagate. I'm also nervous making all public signals combo as that has major implications to clocking and performance.

I'm curious if using the dpi routine is working correctly for you, and if so why you would not always use that method? That's really what I would like to support long term as it's cross-simulator compatible.

@veripoolbot

This comment has been minimized.

Copy link
Author

@veripoolbot veripoolbot commented Feb 23, 2013


Original Redmine Comment
Author Name: Jie Xu (@jiexu)
Original Date: 2013-02-23T20:36:38Z


HI Wilson,

We are actually use DPI routine for our purpose now. This is how we expose/access/manipulate some registers in our design for simulation. While this method normally works, we are really worried if we had some places in our RTL code similar as the test case. As you can see from the test case, we can set the value of @we_a@ using exported DPI-C functions. The problem is that the further signals @res@ driven by @we_a@ is not updated even the value of @we_a@ has been changed by DPI-C functions.

Of course in the testcase the signal @we_a@ is not driven by any other signal (which is rare) except the DPI task. I guess this is why Verilator takes out the @comb_*@ function as it assumes the @we_a@ will not be changed later. But the assumption made by Verilator is not quite valid if the signal is used in an exported task/function or it is @/verilator publick/@ since these indicate the signal could be changed by C++ code.

@veripoolbot

This comment has been minimized.

Copy link
Author

@veripoolbot veripoolbot commented Mar 21, 2017


Original Redmine Comment
Author Name: Wilson Snyder (@wsnyder)
Original Date: 2017-03-21T23:32:21Z


The last comment (years ago) suggested a different technique was being used, so believe there's nothing left required to do here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
1 participant
You can’t perform that action at this time.