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

Add dff-name-style #1983

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

IEncinas10
Copy link
Collaborator

Addresses #1913 with some minor changes

  • Suffixes are totally configurable, and different styles can be combined.
  • If a parameter (input/output) is set to "", no checks are performed. Basically, if we configure the rule with "input:;output:", nothing happens. This might be useful if anyone wants to check the naming conventions for just the output or the input.
  • I changed the rule from "dff-name-suffix" to "dff-name-style" to mimic other rules already implemented. I guess it does not matter too much, just pointing it out.

Unimplemented

logic data_d, data_q;
always_ff @(posedge clk) begin
    assign data_d <= a; // should be driven by assign or always_comb
end
assign data_q = b; // should be driven by always_ff

These kinds of checks are not implemented (yet?) although they should be fairly easy to add. My idea for it was:

I wasn't sure it was worth the possible performance downside (!?) (maybe I'm overly pessimistic) I would add it if it is considered relevant.


Pinging @sifferman. Let me know if you have any suggestions/complaints. Sorry for the delay 😄

- Added helpers to extract nonblocking assignments from a syntax tree
- Added helpers to extract left and right hand sides from a nonblocking
  assignment
dff-name-style-rule adds support for enforcing naming conventions for
registers.

It takes two parameters in the form of a comma separated list of
suffixes that are allowed for the input and output ports. If a list is
empty, it means that no checks will be performed in the respective
field.

In addition to checking suffixes, the rule also enforces that the base
(or prefix) is shared between the input and output of the register.

Furthermore, it also allows for numbered identifiers, where the number
means the pipeline stage where the signal originates from.
@codecov-commenter
Copy link

codecov-commenter commented Jul 26, 2023

Codecov Report

Patch coverage: 100.00% and project coverage change: +0.02% 🎉

Comparison is base (fa07295) 92.85% compared to head (d7fb78f) 92.88%.
Report is 14 commits behind head on master.

❗ Your organization is not using the GitHub App Integration. As a result you may experience degraded service beginning May 15th. Please install the Github App Integration for your organization. Read more.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1983      +/-   ##
==========================================
+ Coverage   92.85%   92.88%   +0.02%     
==========================================
  Files         355      356       +1     
  Lines       26272    26373     +101     
==========================================
+ Hits        24395    24496     +101     
  Misses       1877     1877              
Files Changed Coverage Δ
verilog/CST/statement.cc 97.85% <100.00%> (+0.06%) ⬆️
verilog/analysis/checkers/dff_name_style_rule.cc 100.00% <100.00%> (ø)

... and 4 files with indirect coverage changes

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@sifferman
Copy link

Wow! Really fantastic!

I looked through the tests you wrote, and they all look really good.

Though I was hoping for the checks that are unimplemented: that _q/_reg nets are only driven with <=, and that _d/_next nets are not driven with =.

I assume the performance wouldn't be terrible considering that this is a similar check to always-ff-non-blocking and always-comb-blocking.

@IEncinas10
Copy link
Collaborator Author

You're right! Let's see if #1912 lands. It introduces some helpers to handle blocking assignments that will be helpful.

For those extra checks I would appreciate a bit of help as I'm not too experienced in Verilog. We should detect wrong types of assignments to variables considering their suffixes, but I'm not sure if I'm aware of every possibility.

Using the following references and assuming "_q" and "_n" suffixes:

DFF Outputs

data_q = x; // Blocking assignment
assign data_q = x; // Continuous assignment
wire data_q = 1; // Net declaration assignment
data_q &= x; // Assign modify statements
data_q++; // Increment/decrement statements
  • Procedural continuous assignments
  • Procedural continuous deassignments
  • Procedural continuous force
  • Procedural continuous release

DFF Inputs

reg data_n = x; // Variable declaration assignment
data_n <= x; // Nonblocking assignment

@sifferman
Copy link

Hmm, I'm worried about trying to list all the combinational assignments. I feel like a better way is to:

  • ensure all occurrences of a LHS dff-output are assigned by <= inside an always_ff, and
  • ensure all nets driven by <= inside always_ff are dff-outputs

The only way to create DFFs are with always_ff blocks. Everything else is combinational

@sifferman
Copy link

Also, non-blocking assignments are generally only valid inside always_ff blocks anyways. So I bet you can just continue using <= as your check for DFFs

Thanks again!

@hzeller
Copy link
Collaborator

hzeller commented Jul 31, 2023

Also CC @fangism as he might be interested in this.
I'll review within the next couple of days as time permits.

What I can already say: there are a bunch of integration tests of lint rules in verilog/tools/lint/ , see the BUILD there and the testdata/ subdirectory. Please add a test there as well.

And, probably for a few of the other rules you have been working on recently, I might've forgotten to point that out then.

Copy link
Collaborator

@fangism fangism left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to say: incredible work so far!

verilog/analysis/checkers/dff_name_style_rule.cc Outdated Show resolved Hide resolved
verilog/analysis/checkers/dff_name_style_rule.cc Outdated Show resolved Hide resolved
//
// Under this convention, data_q3 should be driven by the
// previous stage data_q2
//
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about cases where LHS is a compound expression like:

{zz_q2, yy_q2} = ...

(It's ok to declare this as a TODO.)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would fail currently due to

https://github.com/IEncinas10/verible/blob/9ed09223b6df913140cbc0f4f3aac345ff4600cf/verilog/analysis/checkers/dff_name_style_rule.cc#L174

that was basically added to ease the check. It is not clear to me how to deal with all the possibilities consistently.

Maybe I could add a comment saying something like: "Currently this rule only allows for simple identifiers, but it could be expanded to handle more complex references"

Copy link
Collaborator

@hzeller hzeller left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks very nice. Haven't looked in full detail yet, so here just some first small nits.

verilog/analysis/checkers/dff_name_style_rule.cc Outdated Show resolved Hide resolved
verilog/analysis/checkers/dff_name_style_rule.cc Outdated Show resolved Hide resolved
@IEncinas10
Copy link
Collaborator Author

IEncinas10 commented Aug 1, 2023

Thanks for the reviews. I'll work on those integration tests.

Separately, I worked a bit on the extra checks, but I'm not sure how to proceed as I added some of the needed helper already in #1912. Should I just add them here? I got away with a cheap trick for most of the cases as a temporary fix. Should this extra check be hidden under another configuration file?

Added screenshot and diff for a quick overview.

image

diff --git a/verilog/analysis/checkers/BUILD b/verilog/analysis/checkers/BUILD
index 7fcfec0d..aeeabb07 100644
--- a/verilog/analysis/checkers/BUILD
+++ b/verilog/analysis/checkers/BUILD
@@ -2134,6 +2134,7 @@ cc_library(
         "//common/analysis:syntax-tree-lint-rule",
         "//common/analysis/matcher",
         "//common/analysis/matcher:bound-symbol-manager",
+        "//common/analysis/matcher:core-matchers",
         "//common/strings:naming-utils",
         "//common/text:config-utils",
         "//common/text:symbol",
diff --git a/verilog/analysis/checkers/dff_name_style_rule.cc b/verilog/analysis/checkers/dff_name_style_rule.cc
index ebcc757a..92d7b685 100644
--- a/verilog/analysis/checkers/dff_name_style_rule.cc
+++ b/verilog/analysis/checkers/dff_name_style_rule.cc
@@ -25,6 +25,7 @@
 #include "absl/strings/string_view.h"
 #include "common/analysis/lint_rule_status.h"
 #include "common/analysis/matcher/bound_symbol_manager.h"
+#include "common/analysis/matcher/core_matchers.h"
 #include "common/analysis/matcher/matcher.h"
 #include "common/strings/naming_utils.h"
 #include "common/text/config_utils.h"
@@ -76,8 +77,37 @@ static const Matcher &AlwaysFFMatcher() {
 void DffNameStyleRule::HandleSymbol(const verible::Symbol &symbol,
                                     const SyntaxTreeContext &context) {
   verible::matcher::BoundSymbolManager manager;
-  if (!AlwaysFFMatcher().Matches(symbol, &manager) ||
-      (valid_input_suffixes.empty() && valid_output_suffixes.empty())) {
+  if (valid_input_suffixes.empty() && valid_output_suffixes.empty()) return;
+
+  // Types of assignments intended for DFF inputs
+  static const Matcher matcher = verible::matcher::AnyOf(
+      NodekContinuousAssignmentStatement(), NodekNetVariableAssignment(),
+      NodekNetDeclarationAssignment(), NodekAssignModifyStatement(),
+      NodekIncrementDecrementExpression());
+  if (matcher.Matches(symbol, &manager)) {
+    const verible::SyntaxTreeNode &node = SymbolCastToNode(symbol);
+    if (node.children().empty()) return;
+    const verible::Symbol *lhs = node.children().front().get();
+    absl::string_view lhs_str = verible::StringSpanOfSymbol(*lhs);
+
+    //TODO: helpers. Also, ++data_ff doesnt work (not 1st child)
+    const bool found_id = std::any_of(valid_output_suffixes.cbegin(),
+                                      valid_output_suffixes.cend(),
+                                      [&](const std::string &suffix) -> bool {
+                                        return lhs_str.size() > suffix.size() &&
+                                               absl::EndsWith(lhs_str, suffix);
+                                      });
+
+    if (!found_id) return;
+    violations_.insert(LintViolation(
+        *lhs,
+        absl::StrCat(lhs_str,
+                     " should be driven by a nonblocking assignment "
+                     "inside an always_ff block"),
+        context));
+  }
+
+  if (!AlwaysFFMatcher().Matches(symbol, &manager)) {
     return;
   }

Add missing integration test for forbid-negative-array-dim rule.
Add missing test for dff-name-style rule
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants