Closed veripoolbot closed 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?
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.
Original Redmine Comment Author Name: Wilson Snyder (@wsnyder) Original Date: 2008-10-12T17:15:44Z
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).
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++.
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.
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).
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.
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...)".
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
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?
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.
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.
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:
Any inout ports get expanded as in and out signals (no __en signals initially)
For any signal that drives a Z, create an __en signal as initially suggested.
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"
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.
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.
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?