verilator / verilator

Verilator open-source SystemVerilog simulator and lint system
https://verilator.org
GNU Lesser General Public License v3.0
2.19k stars 531 forks source link

Question: Support for tri-state #1658

Closed veripoolbot closed 15 years ago

veripoolbot commented 15 years ago

Author Name: Lane Brooks Original Redmine Message: 16 from https://www.veripool.org


I have been evaluating verilator and find the approach exactly what I want. My only issue with it is the lack of tri-state support. I see that in the TODO file it is a long-term feature. Can you provide me a status update on tristate support? Has there been any work on it yet? Is it a natural extension or does it require a lot of re-architecting?

veripoolbot commented 15 years ago

Original Redmine Comment Author Name: Wilson Snyder (@wsnyder) Original Date: 2008-10-12T01:06:26Z


Those notes are from Verilator 1.x about 5 years ago, unfortunately nothing has been done in this area. Unfortunately this is a fairly major project I don't think I have time for now, would you be interested in doing some of the work?

There's two levels of possible support, first would be tri-states that are all internal to the module being Verilated, after that would be adding pins that support tri-states. Which is interesting to you?

veripoolbot commented 15 years ago

Original Redmine Comment Author Name: Lane Brooks Original Date: 2008-10-12T01:17:43Z


My main interest is enabling tri-state pins so that I can implement logic that talks to an external tri-state bus. I2C is the type of bus I most frequently use. I do also have interest, however, in internal tri-state to implement switch logic. I will often put custom logic in our analog blocks that typically extract and simulate in the digital domain using switches.

I would love to do the work to implement tristate but am rather limited on time as well. Can you estimate how long it would you to implement such a feature? That would help me know how big of a project it is provide me a minimum bound on how long it would take me.

veripoolbot commented 15 years ago

Original Redmine Comment Author Name: Wilson Snyder (@wsnyder) Original Date: 2008-10-12T17:15:44Z


General scheme

Here's the scheme that Verilator used in version 1, and I've also used manually when I wanted to remove a few tristate signals in my designs (such as for I2C and DDR.) Others are possible, but this is simple to implement and performs well (esp compared to what most Verilog simulators do!)

For

     inout [BITS] x;

Convert this into

     output [BITS] x__out;   // Resolved value
     output [BITS] x__outen; // Resolved != Z
     input  [BITS] x__in;    // Input
     input  [BITS] x__inen;  // Input != Z

Then we create the output value by resolving all of the multiple drivers.

For example if there's two internal drivers plus one external one (the input statement):

     assign x = x1en ? x1value : 'bz;
     assign x = x2en ? x2value : 'bz;

This first gets converted to a _in & _inen unique for each drive point.

     assign x1__in = x1value;
     assign x1__inen = x1en;
     assign x2__in = x2value;
     assign x2__inen = x2en;

Then the output value resolves based on each inen

  assign x__outen = x1__inen | x2__inen | x__inen;

  assign x__out = (  (x1__inen & x1_in)
                   | (x2__inen & x2_in)
                   | (x__inen & x_in)
                   | (~x1__inen & ~x2__inen & ~x__inen & 'bX);

where the last term is what to do when there are no drivers; this value should use the --x-assign option to determine what to do; Xs is safest but 0 is fastest. Also this would be replaced by a constant if there are pullup/pulldowns on the net (and __outen would always be high).

Also any "x <= " delayed assignments need to be similarly expanded into setting a in/inen and a resolution stage.

The final complication is the resolution must be cross-module, so can be done only at one point in the hierarchy - presumably the top level of the Verilated module, though it's better to do it at the lowest possible module that sees all the drivers (better because if it's instantiated multiple times the logic will only occur once).

Exterior Inouts

For C++, expose the in, inen, out, outen signals generated above to the top level ports. The in and inen signals from outside feed into the resolution steps above.

For SystemC, we could use SystemC tristate types, but as we need to expand C++ types, it seems easier just to have SystemC get split just as with C++.

Tasks

I'd estimate this as a two week task. It's probably a week of coding, plus testing and time for you'd need to get to know the code, etc.

Write tests

This will help scope the problem and aid later debug. It's best to do this up front. Also as problems are found in larger tests, add new small tests to show the problems.

     Test 1: Inout 64/32/16/8 bits all interior to module.
     Test 2: Inout 64/32/16/8 bits crossing into top module.
     Test 3: Inout functions/tasks and public func/tasks (if needed).

Major source edits

V3Unknown needs to be greatly extended, or a new V3Tristate step added which requests some help from V3Unknown. This will perform the __inen expansion described above.

Other source edits

I made this list with a grep for "AstVar", "varp" - where variables are used. Also "isIn", "isOut", "isTristate" as many probably need editing as they didn't assume tristates when written.

V3AstNodes.cpp, V3AstNodes.h
     Probably some minor changes as driven by other source changes.

V3Const.cpp:
     Some additional optimizations involving tristates
     may be desirable, but not required.

V3EmitC.cpp:
     Add any additional output rules.  If follow the
     __en above this should be minimal.

V3Gate.cpp:
     Probably no change.  May want to further optimize
     tristates later here, but if convert them to __en in
     V3Unknown should be ok without changes.

V3Trace.cpp:
     For now, tracing a tristate could simply trace all
     of the generated __in, __out, __inen and __outen
     signals.  Later it would be nicer to fix this trace
     them as normal 4-state signals, probably another few
     days effort.  This will require also adding tristate
     support to SystemPerl's trace functions (what
     Verilator calls to create traces.)

V3LinkLValue.cpp:
     Assignments to inouts need to be marked as lvalues.

V3Inline.cpp:
     Need to understand how to inline modules with inout pins.
     This should be very easy; inouts of the submodule can just be
     substituted for the pin name of the instantiating module.

V3Inst.cpp:
     Need to connect inout pins; similar code to V3Inline.

V3Link.cpp:
V3LinkResolve.cpp:
     No obvious change. May need to add code to promote
     some wires to tristates as discussed in the TODO.

V3Task.cpp:
     Some major changes are needed to add "inout" support
     for functions and tasks.  For now it may be acceptable
     to simply make func/task inout's be unsupported.

V3Width.cpp:
     Fix width resolution of tristates (search for
     isTristate) - just make concats on tristate pins
     unsupported?

V3Delayed.cpp:
     None - Assuming earlier step pre-converts "tristate
     <= x;" to "temp_sig# <= x;" then does tristate
     resolution "always @* tristate =
     resolve(temp_sig1,temp_sig2...)".

No source change, or minimal

    V3Active.cpp:        None
    V3ActiveTop.cpp:     None
    V3Begin.cpp:         None
    V3Branch.cpp:        None
    V3Cast.cpp:          None
    V3Changed.cpp:       Prob none - post _en
    V3Clock.cpp:         Raise unsupported error if clock var is a tristate
    V3Combine.cpp:       None
    V3Dead.cpp:          None
    V3Depth.cpp:         None
    V3DepthBlock.cpp:    None
    V3Descope.cpp:       None
    V3EmitV.cpp:         None
    V3Expand.cpp:        None
    V3GenClk.cpp:        Raise unsupported error if clock var is a tristate
    V3Life.cpp:          Prob none - post _en
    V3LifePost.cpp:      Prob none - post _en
    V3LinkCells.cpp:     None
    V3LinkDot.cpp:       None
    V3LinkLevel.cpp:     When build wrapper, make wrap pin be inout if top pin is inout
    V3LinkParse.cpp:     None
    V3Localize.cpp:      None
    V3Name.cpp:          None
    V3Order.cpp:         Assumes primary IOs are inputs or outputs, but will be after __inen, so ok
    V3Param.cpp:         None
    V3Premit.cpp:        None
    V3Scope.cpp:         None
    V3Signed.cpp:        None
    V3Split.cpp:         None
    V3SplitAs.cpp:       None
    V3Stats.cpp:         None
    V3Subst.cpp:         None
    V3Table.cpp:         Disable table opt if any tristates - one line add
    V3TraceDecl.cpp:     None
    V3Unroll.cpp:        Raise unsupported error if for variable is tristate variable
veripoolbot commented 15 years ago

Original Redmine Comment Author Name: Lane Brooks Original Date: 2008-10-12T18:16:43Z


Wow. Thanks for such a thorough responce. How does bus conflict get handled under this approach?

veripoolbot commented 15 years ago

Original Redmine Comment Author Name: Wilson Snyder (@wsnyder) Original Date: 2008-10-12T20:18:46Z


Good point about bus conflict, I'd say if -x-assign=0 then you're accepting the hazards and just wire OR it as shown, but otherwise it should drive Xs. Furthermore it seems good to add an assertion error on bus conflict iff --assert is set.

BTW, just getting a few tests (that will fail) would be a fine start.

veripoolbot commented 15 years ago

Original Redmine Comment Author Name: Lane Brooks Original Date: 2008-10-12T23:22:18Z


This is great information. Since I am new to verilator, I have a lot to learn before I will be able to contribute anything on this matter. I will use your method as suggested above manually for now. Perhaps after some more experience with verilator I can help contribute some of your suggestions. As I am still evaluating verilator, tristate was my biggest obstacle. It is still an obstacle, but I feel I can work around it. Now I need to take a shot at implementing behavioral C++ models for our low-level analog black boxes.

veripoolbot commented 15 years ago

Original Redmine Comment Author Name: Lane Brooks Original Date: 2008-11-06T10:16:00Z


Wilson,

I think there is an issue with your original proposed solution. You can actually create tristates without having any inouts. For example consider a mux as follows:

assign X = (SEL==0) ? A0 : 1'bz;
assign X = (SEL==1) ? A1 : 1'bz;
assign X = (SEL==2) ? A2 : 1'bz;

Or equivalently, you can create the same logic in a hierarchical fashion as follows:

mux u_mux[2:0](.A({A2,A1,A0}),
                .OE({SEL==2, SEL==1, SEL==0}),
                .O(X));

module mux(input A, input OE, output O);
  assign O = (OE) ? A : 1'bz;
endmodule

Observe this netlist has tristates but no inouts. I use this sort of structure quite frequently in custom design when designing large decoders. As such, I would propose an alternative algorithm for tristate expansion:

  1. Any inout ports get expanded as in and out signals (no __en signals initially)

  2. For any signal that drives a Z, create an __en signal as initially suggested.

  3. At each level in the hierarchy, create the en expansion logic initially suggested for any signals (VarRefs) that have multiple LV drivers and mark the en signal as "used"

  4. Any unused __en signals get passed up the hierarchy one level and the previous step is repeated.

The change can be summarized such that inouts just expand as in and out signals. It is the presence of a Z that triggers the creation of a en signal. That en signal then propigates up the hierarchy until it is terminated at the level where multiple LV varref's drive the corresponding net.

veripoolbot commented 15 years ago

Original Redmine Comment Author Name: Wilson Snyder (@wsnyder) Original Date: 2008-11-06T23:32:41Z


I like your approach.

It also occurs to me that the Verilog PLI standard using two vectors a,b is

0 a=0 b=0 1 a=1 b=0 Z a=0 b=1 X a=1 b=1

This suggests we may want an tri instead that's the inverse of en. This has the advantage that loading "enable" is simply loading 0, but I think the resolution logic gets more complicated. It's easy enough to try both once there's working code and let some benchmarks decide.