-
Notifications
You must be signed in to change notification settings - Fork 141
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
slang-netlist new feature: Detect combinatorial loops #984
slang-netlist new feature: Detect combinatorial loops #984
Conversation
2. Added original author's license file.
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #984 +/- ##
==========================================
+ Coverage 94.01% 94.21% +0.20%
==========================================
Files 189 191 +2
Lines 48479 46903 -1576
==========================================
- Hits 45576 44189 -1387
+ Misses 2903 2714 -189 see 147 files with indirect coverage changes Continue to review full report in Codecov by Sentry.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good.
I'm not sure about including code with a different license that's not explicitly 'third party' but @MikePopoloski can comment.
Also - can you add a unit test for the change?
@@ -3,7 +3,8 @@ | |||
# SPDX-License-Identifier: MIT | |||
# ~~~ | |||
|
|||
add_executable(slang_netlist netlist.cpp source/Netlist.cpp) | |||
add_executable(slang_netlist netlist.cpp source/Netlist.cpp | |||
source/CombLoops.cpp) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be better to include this source in the netlist library, so that the functionality is not only bound to the command-line tool.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand what you mean.
The file is already under tools\netlist\source
, the same place Netlist.cpp
is in, and all its functionality is only included in the command-line tools, not part of libsvlang.a
, and I don't see you're building any standalone Netlist library either.
Feel free to fix this file, or show me what you mean.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ignore me, I thought that I had set up a library!
auto& edge = netlist.addEdge(sourceVarNode, targetVarNode); | ||
targetVarNode.edgeKind = edgeKind; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be neater to extend the method to include edgeKind as an argument.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addEdge
is currently a DirectedGraph
method, that has nothing to do with EdgeKind.
Do you want me to override this with a new Netlist::addEdge(NetlistNode& sourceNode, NetlistNode& targetNode, ast::EdgeKind edgeKind)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was a minor point so it's up to you. But that sounds reasonable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added it anyway, learning on the way the importance of using
when redefining functions on derived classes, and still wanting to call the base class version on the default function signature.
At the moment I'm also debugging another issue. I use ultraembedded's JPEG core for tests. I can run it against the whole core, or subsets of it. One subset with <700 nodes passes almost immediately. When I moved to a different subtree with ~2000 nodes, the program dies after a few minutes with a segmentation fault. I don't know if this is a complexity issue, or a deadlock triggered by the specific netlist, because it jumps from a sub-second run, to dying after a few minutes. |
I noticed while looking at #985 that it takes a long time to process the netlist, so this may be related.
If you run with
It needs some more investigation as to why there are so many edges being created. |
…ath instead. At the moment we dump the 1st cycle element again at the end of the loop just to close it, but we will probably drop it.
2. Decided not to print 1st element again at the end (it was supposed to close the cycle, but looks redunant).
I just added a test (a single one, at least for the moment) to cover CombLoops. |
As proof of concept is good but i suppose that analysis is need to be more conservative. It seems to me that checking the graph on presence of cycles (without outermost For example in this simple code sample there is no combinational logic at all. It follows that there are also no combinational cycles (but PR solution reports that there is at least one combinational loop): module top (input clk);
reg a;
reg b;
test t1(.x(a), .y(b), .clk(clk));
test t2(.x(b), .y(a), .clk(clk));
endmodule
module test(input reg x, output reg y, input clk);
always_latch begin
if (clk)
y <= x;
end
endmodule Build succeeded: 0 errors, 0 warnings
Nodes: 30
Actual active Nodes: 30
Detected 1 combinatorial loop:
Path length: 8
1.sv:5:13: note: variable a assigned to
test t1(.x(a), .y(b), .clk(clk));
^
1.sv:13:9: note: variable x read from
y <= x;
^
1.sv:13:4: note: variable y assigned to
y <= x;
^
1.sv:5:20: note: variable b read from
test t1(.x(a), .y(b), .clk(clk));
^
1.sv:6:13: note: variable b assigned to
test t2(.x(b), .y(a), .clk(clk));
^
1.sv:13:9: note: variable x read from
y <= x;
^
1.sv:13:4: note: variable y assigned to
y <= x;
^
1.sv:6:20: note: variable a read from
test t2(.x(b), .y(a), .clk(clk)); I think it needs to be determined first which assignments are related to combinational logic but which aren't to make analysis more context sensitivity. |
From a practical point of view, since I cannot safely determine when a latch is safe, I would rather have a false positive I can waive (we'll have to add a mechanism for that) rather than skip a warning. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is pretty cool, thanks for the contribution. I'd like the slang library to properly have support for comb loop detection at some point in the future but it first needs to gain another layer of lowering support (possibly to something MLIR based) before it will be feasible to implement. In the meantime it seems good to experiment with doing it in slang-netlist.
#ifndef COMBLOOPS_H | ||
#define COMBLOOPS_H | ||
|
||
/* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IANAL but: I think it's good to leave the original license here but since you translated the source it's now also copyrighted by you and so it's fine to also put the standard license header on this file (and we don't need to put it in external/).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I gave this a lot of thought, and it's like the Ship of Theseus. The original code is not here, but the class names, internal functions and their internal structures (loops, branches, etc.) is mostly the same. Given the similarity between Java and C++ this is even more obvious.
Since the original code was governed by a very permissive BSD-2 clause license, I didn't find this an issue.
Apparently, the original code is really from here: http://www.normalisiert.de/ .
In any case, the code is recursive, and I found that for some cases it dies even for a small number of nodes.
I wish to investigate this for a few more days. From a quick peek at the offending function, I think it might be not too complex to remove the recursion.
Let me know when you think this is ready to land. |
Modern designs are't use latches it's true but what about D-triggers/flip-flops (which widely used in modern designs to separate combinational logic) and other sequential logics? Provided solution also warns on it. For example there is simple flip-flop without comb loops: module top (input rst, input clk);
wire D;
wire Q;
wire Qn;
dff d1(D, clk, rst, Q, Qn);
dff d2(Q, clk, rst, D, Qn);
endmodule
module dff (
input logic D, clk, rst,
output logic Q, Qn
);
always_ff @(posedge clk, posedge rst) begin
if (rst) begin
Q <= 0;
Qn <= 1;
end else begin
Q <= D;
Qn <= ~D;
end
end
endmodule |
This is simple - your example simply triggered a bug. This was not supposed to happen... However, I have found more serious false positive issues:
This will also trigger a comb loop warning. While this specific one might be solved (at the cost of complicating the netlist logic) It looks like the general problem will not be solved without a full synthesis engine. For example:
It remains to be seen if the scope of this feature would be useful given the current limitations (known possible false positives). |
I would expect the netlist graph for I see your point though and agree that without full synthesis it's not possible to determine a true combinatorial loop. The class of loops that |
A combinatorial loop is reported because each of the Maybe we should rename the option name to |
Apologies - I thought I had implemented that. My aim for With regards to combinatorial loops, how about just calling the option |
But I'm not merely reporting cycles - I'm actively ignoring netlist edges that terminate on a posedge/negedge nodes. BTW, another feature I would like to implement at a later stage is an improvement to the path reporting mode, that will also report the number of clock edges between the source and destination paths. It would require defining the clock signals, and keeping a table of clock aliases, either those directly connected, or those passing through a clock gating module (you would define the clock gating module name, and the input/output ports). |
Marking sequential edges is a generally useful feature of the tool, since it allows the netlist to be constrained to find combinatorial paths. This is how I implemented a previous similar tool.
Nice, that would be useful. (Btw. I've got no objections to this landing! We can always iron details out later.) |
We still detect "posedge x or negedge x" as edge even though this is effecetively combinatorial, because we are lazy.
And renamed previous templates to be more consistent
…g constant expressions out of loops
I've fixed the bug, but I still got 2 issues:
It will take me a few more days to resolve these. |
1. Removed dynamic allocation (new/delete) and replaced it by 1 static buffer 2. Removed tail recursion and replaced it by a loop 3. Removed default namespace std and added explicit std:: prefixes
At the moment, My code works great under clang-sanitize, where I've debugged it, but for some reasons fails under gcc-11, where there seems to be a memory corruption causing a segment violation as well as locking up the watch windows on vscode. |
While I've fixed the crashes, it seems there are still other issues (lockups on some examples). |
False alarm, I was just being impatient and stopped the test after a few seconds. It ended up taking a few more seconds than what I estimated.
@MikePopoloski @jameshanlon I think it is ready from my side. |
The following PR adds combinatorial loop detection to
slang-netlist
.The original algorithm can be found here:
https://epubs.siam.org/doi/10.1137/0204007
Finding All the Elementary Circuits of a Directed Graph
Johnson, Donald B
SIAM Journal on Computing Vol. 4, Issue. 1 Mar 1975
I have taken a Java implementation from https://github.com/josch/cycles_johnson_meyer , forked it to modernize the Java, then ported the code to C++ and finally modified my generic C++ code to work with @jameshanlon 's code.
While the basic code works, there are lots of things that can be improved:
SourceLocation
andSourceManager
classes.Here is a sample input and output: