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

Merged
merged 6 commits into from
Oct 7, 2024
Merged

Add dff-name-style #1983

merged 6 commits into from
Oct 7, 2024

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 😄

@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;
   }

@hzeller
Copy link
Collaborator

hzeller commented May 27, 2024

What is the last status here ?

@IEncinas10
Copy link
Collaborator Author

IEncinas10 commented May 28, 2024

What is the last status here ?

If I remember correctly everything was looking good. I had a local stash implementing some extra checks (basically, the diff I posted above) but that required some helpers also introduced here: #1912

I think the other PR will require more time to review and is less useful, so I could introduce the helpers here and later rebase that other PR and eventually get back at it.

Therefore, I will:

  1. Clean up the fixup! commits
  2. Bring the helpers I needed for the extra checks from the other PR
  3. Commit and push the extra checks from the diff I posted
  4. See if there are missing tests and things like that

EDIT:
I spent some time in this mainly reorganizing the code a bit and finishing the "extra checks". Changes won't be too big so feel free to do a quick review pass or suggest changes.

After I clean things up, I'll push and work on trying to support things like flop_array_q[i] and perhaps struct.whatever_q as LHS on nonblocking assignments.

@IEncinas10
Copy link
Collaborator Author

A couple of "minor" TODOs left but should be somewhat stable

@IEncinas10 IEncinas10 force-pushed the dff-name-style branch 2 times, most recently from f2a2c75 to e41c293 Compare June 2, 2024 21:40
@sifferman
Copy link

Thanks for all your work on this! I am excited for this to be merged.

I found a few small issues, sorted by most to least importance.

Params also flag the warning. Is it possible to only raise the warning on a non-constant expression?

localparam DataResetValue = 4;
always_ff @(posedge clk_i) begin
  if (!rst_ni) begin
    data_q <= DataResetValue;
  end else begin
    data_q <= data_d;
  end
end

RAMs flag the warning, though this can realistically be corrected with a waiver.

logic [7:0] MEM [256];
always_ff @(posedge clk_i) begin
  if (we_i)
    MEM[waddr_i] <= wdata_i;
end

Nets with dff suffix should be only driven by always_ff block. Possibly not a big deal.

logic data_q;
assign data_q = data_d;

@IEncinas10
Copy link
Collaborator Author

Thanks for all your work on this! I am excited for this to be merged.

I found a few small issues, sorted by most to least importance.

Thanks for providing feedback!

Params also flag the warning. Is it possible to only raise the warning on a non-constant expression?

localparam DataResetValue = 4;
always_ff @(posedge clk_i) begin
  if (!rst_ni) begin
    data_q <= DataResetValue;
  end else begin
    data_q <= data_d;
  end
end

Sadly we can't know that DataResetValue is a constant. The best I can come up with is
approximating it from the name (which can be made configurable). For example, given:

data_q <= RHS and RHS isn't lower snake case, assume that RHS is a constant and skip the warning

RAMs flag the warning, though this can realistically be corrected with a waiver.

logic [7:0] MEM [256];
always_ff @(posedge clk_i) begin
  if (we_i)
    MEM[waddr_i] <= wdata_i;
end

Sadly, same as above. The best thing we can do right now is inferring stuff from name formatting

Nets with dff suffix should be only driven by always_ff block. Possibly not a big deal.

logic data_q;
assign data_q = data_d;

This one should be flagged, could you double-check?

@sifferman
Copy link

Params also flag the warning. Is it possible to only raise the warning on a non-constant expression?

localparam DataResetValue = 4;
always_ff @(posedge clk_i) begin
  if (!rst_ni) begin
    data_q <= DataResetValue;
  end else begin
    data_q <= data_d;
  end
end

Sadly we can't know that DataResetValue is a constant. The best I can come up with is approximating it from the name (which can be made configurable). For example, given:

data_q <= RHS and RHS isn't lower snake case, assume that RHS is a constant and skip the warning

Unfortunate, maybe this could be opened as another issue. I assume checking whether an expression is constant would be a useful metric in general.

I don't think checking the capitalization of the label is a universal solution, but it could possibly be a good parameter of the rule. By the way, here are a few unique cases for resets that CVA6 uses:

  • '{default: '0} (link)
  • ariane_pkg::FE_NONE (link)
  • WIDTH'(Seed) (link)
  • '{free: 1'b1, default: '0} (link)
  • {STAGES{ResetValue}} (link)
  • '{default: sb_mem_t'(0)} (link)

RAMs flag the warning, though this can realistically be corrected with a waiver.

logic [7:0] MEM [256];
always_ff @(posedge clk_i) begin
  if (we_i)
    MEM[waddr_i] <= wdata_i;
end

Sadly, same as above. The best thing we can do right now is inferring stuff from name formatting

LowRISC expects snake case for memories, so this doesn't seem like a good option. But it could potentially be another parameter?

Nets with dff suffix should be only driven by always_ff block. Possibly not a big deal.

logic data_q;
assign data_q = data_d;

This one should be flagged, could you double-check?

My mistake, yes this is flagged.

@IEncinas10
Copy link
Collaborator Author

Params also flag the warning. Is it possible to only raise the warning on a non-constant expression?

localparam DataResetValue = 4;
always_ff @(posedge clk_i) begin
  if (!rst_ni) begin
    data_q <= DataResetValue;
  end else begin
    data_q <= data_d;
  end
end

Sadly we can't know that DataResetValue is a constant. The best I can come up with is approximating it from the name (which can be made configurable). For example, given:
data_q <= RHS and RHS isn't lower snake case, assume that RHS is a constant and skip the warning

Unfortunate, maybe this could be opened as another issue. I assume checking whether an expression is constant would be a useful metric in general.

I agree it would be great, but I think it would require a lot of effort. It would be somewhat feasible to do for variables defined in the same .sv file you're linting, but it wouldn't be easy to do with includes.

I don't think checking the capitalization of the label is a universal solution, but it could possibly be a good parameter of the rule. By the way, here are a few unique cases for resets that CVA6 uses:

  • '{default: '0} (link)
  • ariane_pkg::FE_NONE (link)
  • WIDTH'(Seed) (link)
  • '{free: 1'b1, default: '0} (link)
  • {STAGES{ResetValue}} (link)
  • '{default: sb_mem_t'(0)} (link)

Thanks!

RAMs flag the warning, though this can realistically be corrected with a waiver.

logic [7:0] MEM [256];
always_ff @(posedge clk_i) begin
  if (we_i)
    MEM[waddr_i] <= wdata_i;
end

Sadly, same as above. The best thing we can do right now is inferring stuff from name formatting

LowRISC expects snake case for memories, so this doesn't seem like a good option. But it could potentially be another parameter?

Yes, that's what I meant.

Nets with dff suffix should be only driven by always_ff block. Possibly not a big deal.

logic data_q;
assign data_q = data_d;

This one should be flagged, could you double-check?

My mistake, yes this is flagged.

To summarize:

  • Think how to solve the lint on data_q <= CONSTANT problem using a parameter. We could 1) try to detect "constants" from their style/formatting 2) perhaps define the reset signal style: rst_ni and ignore nonblocking assignments under those ifs
  • Think about the memories. Add a parameter to specify how memories are formatted to avoid complaining about them: memory_regex: "mem*"

Thanks again for the feedback, and feel free to suggest more things.

@sifferman
Copy link

  • Think how to solve the lint on data_q <= CONSTANT problem using a parameter. We could 1) try to detect "constants" from their style/formatting 2) perhaps define the reset signal style: rst_ni and ignore nonblocking assignments under those ifs

I think the current implementation is quite good and works well enough. In most RTL I've seen, reset just sets the net to 0 90% of the time. The other 10% can probably just be put in a waiver.

I feel like the best long-term solution would be a check if an expression is constant, which could probably be put in another issue.

  • Think about the memories. Add a parameter to specify how memories are formatted to avoid complaining about them: memory_regex: "mem*"

A memory regex sounds like a fantastic solution! With that logic, should the _d/_q names also use a regex?

@IEncinas10
Copy link
Collaborator Author

  • Think how to solve the lint on data_q <= CONSTANT problem using a parameter. We could 1) try to detect "constants" from their style/formatting 2) perhaps define the reset signal style: rst_ni and ignore nonblocking assignments under those ifs

I think the current implementation is quite good and works well enough. In most RTL I've seen, reset just sets the net to 0 90% of the time. The other 10% can probably just be put in a waiver.

Okay. I'll keep in mind to try something to make the problem less annoying anyway, waiving is never fun.

  • Think about the memories. Add a parameter to specify how memories are formatted to avoid complaining about them: memory_regex: "mem*"

A memory regex sounds like a fantastic solution! With that logic, should the _d/_q names also use a regex?

I thought about it but I don't see much use for it in this particular rule as as we're always matching the suffix and we have to manually check the pipeline stage data_q3 <= data_q2 ...

@sifferman
Copy link

Any update? My students would greatly benefit from this being merged in the next week or two.

@IEncinas10
Copy link
Collaborator Author

Any update? My students would greatly benefit from this being merged in the next week or two.

I hacked the stuff we discussed but didn't clean it up. I'll try to get it done. I have no control on whether this is merged or not, the best I can do is offer an up-to-date branch w.r.t master.

Just to clarify, the actual solutions to the problems you posed a time ago are the following:

  1. The user can provide if expressions that will make the rule ignore whatever is inside it:
if(!rst_ni) begin
  // the rule will not care about anything in this begin-end block
end 

This workaround has important issues because we can't perform logic analysis, so we are left without string-matching the if conditions. As a best effort given the situation, leading/trailing whitespaces will be taken care of. In other words, the user has to configure
the ~exact conditions that don't require checking. By default they are !rst_ni, flush_i, !rst_ni || flush_i, flush_i || !rst_ni

  1. The memory problem is solved with a regex. By default (?i)mem.*
mem[whatever] <= 1; // OK

@IEncinas10 IEncinas10 force-pushed the dff-name-style branch 4 times, most recently from 89c93e5 to 2f84922 Compare September 28, 2024 16:40
@IEncinas10
Copy link
Collaborator Author

@hzeller This should be somewhat "final". It has some downsides, specially the waive_conditions part, but I can't come up with anything better.

@hzeller
Copy link
Collaborator

hzeller commented Sep 30, 2024

Sorry, that must've slipped under my radar. I try to carve out some time today or tomorrow to review to get this in quickly.

@sifferman
Copy link

Thanks for the hard work! Do you have an example of how to change the regexes? Are they parameterizable?

@IEncinas10
Copy link
Collaborator Author

IEncinas10 commented Oct 1, 2024

Thanks for the hard work! Do you have an example of how to change the regexes? Are they parameterizable?

+dff-name-style=input:next,n,d;output:reg,r,ff,q;waive_conditions:!rst_ni,flush_i,!rst_ni || flush_i,flush_i || !rst_ni;waive_regex:(?i)mem.* in your .rules.verible_lint More info here gives you the current defaults.

You can manually set it using similar syntax for verible-verilog-lint

Right now the only regex is waive_regex, the waive_conditions does exact checking (more info in the source code and tests).

@sifferman
Copy link

Thanks! It seems to be working very well!

Can you add some documentation on the usage?

Also, the names "waive_conditions" and "waive_regex" are a bit unclear. Maybe instead "waive_ifs_with_conditions" and "waive_lhs_regex"?

@IEncinas10
Copy link
Collaborator Author

I take note about the name change. Let's see if there any other suggestions, otherwise I'll use yours.

I'm not sure that you mean by documentation. The only "official documentation" is the one you get by doing verible-verilog-lint --help_rules=dff-name-style that comes from the GetDescriptor() function inside the .cc file for the rule. More information can be found reading the source code (the header file for the rule usually contains a description). Tests provide more concrete examples too.

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.

Very cool. Approved, and essentially ready to merge but I am holding off in case you want to consider the name changes discussed above (because once we have the names it is harder to fix later).
Also consider moving more documentation (essentially what now mostly lives in a comment) into the description part of the configuration (if there are documentation rendering issues, we can fix that later).

namespace verilog {
namespace analysis {

// DffNameStyleRule checks that D flip flops use appropriate naming conventions
Copy link
Collaborator

Choose a reason for hiding this comment

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

To increase user-visible documentation, maybe add this, or a good chunk into the .desc part of the description of the rule ? That way, it will show up in the auto-generated output and discoverable. I suspect this might cover @sifferman request for documentation ?

Yes, it is all in the source, but we also probably can't expect all Verible users read the source and the test cases :)

(Maybe not all formatting will work well initially and we might need a .long_desc at some point, but that is a start. But don't worry about that, that can be fixed afterwards).
(I am debating if we should even have an .examples section in the config, but that is also something for later)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Makes sense. I thought rule descriptions were in generall very short but that's not the case. I'll add more information.

Long descriptions are already a problem, perhaps we should preprocess the descriptions and add newlines every X characters. I'll eventually open an issue/PR to address this.

I like the .examples thing, perhaps hidden other another flag that is set to false by default?

verible-verilog-lint --help_rules=all --provide-rule-examples

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
{"module m; always_ff @(posedge c) if(flush_i || !rst_ni) begin a_reg <= "
"0; end; "
"endmodule "},
{"module m; always_ff @(posedge c) if(reset) begin a_reg <= ",
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'd also add a test-case with a space between if and the open-(. It will work as test is post-tokenization, but it is a good documentation.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Added

{"module m; always_ff @(posedge c) if ( reset  ) begin a_reg <= ",
 {TK_DecNumber, "0"},
 "; end; endmodule"},

@IEncinas10
Copy link
Collaborator Author

I basically did git show --stat --format="" --name-only | xargs sed -i "s|waive_conditions|waive_ifs_with_conditions|g" (and the same with waive_regex) and extended a bit the documentation.

@sifferman given how much you have guided this, do you mind double-checking so that the rule can go in as you want it? Thanks for the feedback :)

The help message would be the following:

dff-name-style                     Checks that D Flip-Flops use appropiate naming conventions in both input and output ports. The left hand side (output) and right hand side (input) will be checked against a set of valid suffixes. Exceptions to this rule can be configured using a regular expression or waiving whole `if` blocks
                                   Parameters:
                                       * `input` Default: `next,n,d` Comma separated list of allowed suffixes for the input port. Suffixes should not include the preceding "_". Empty field means no checks for the input port
                                       * `output` Default: `reg,r,ff,q` Comma separated list of allowed suffixes for the output port. Should not include the preceding "_". Empty field means no checks for the output port
                                       * `waive_ifs_with_conditions` Default: `!rst_ni,flush_i,!rst_ni || flush_i,flush_i || !rst_ni` Comma separated list of conditions that will disable the rule inside the `if`s they are evaluated in
                                       * `waive_lhs_regex` Default: `(?i)mem.*` Nonblocking assigments whose lhs match the regex will not be evaluated
                                   Enabled by default: false

@sifferman
Copy link

The new documentation looks really good! Though could you also add this example?

+dff-name-style=input:next,n,d;output:reg,r,ff,q;waive_conditions:!rst_ni,flush_i,!rst_ni || flush_i,flush_i || !rst_ni;waive_regex:(?i)mem.*

Also, for q, q2, q3..., could q be changed to also work with q1? It's not in the lowrisc style guide, but I like this syntax more:

q1 <= d;
q2 <= q1;
q3 <= q2;
...

@IEncinas10
Copy link
Collaborator Author

The new documentation looks really good! Though could you also add this example?

+dff-name-style=input:next,n,d;output:reg,r,ff,q;waive_conditions:!rst_ni,flush_i,!rst_ni || flush_i,flush_i || !rst_ni;waive_regex:(?i)mem.*

If by example you mean the default configuration, it can be obtained by verible-verilog-lint --print_rules_file

Also, for q, q2, q3..., could q be changed to also work with q1? It's not in the lowrisc style guide, but I like this syntax more:

q1 <= d;
q2 <= q1;
q3 <= q2;
...

I'll have a look, but do you want this over what's currently implemented or both things?
Do you want a_q <= a_d to be valid? Or should only a_q1 <= a_d be acceptable?

@sifferman
Copy link

...it can be obtained by verible-verilog-lint --print_rules_file

Oh, thank you for that. Yes, that is a good solution.

Do you want a_q <= a_d to be valid? Or should only a_q1 <= a_d be acceptable?

I was thinking both. a_q <= a_d should definitely be allowed still.

@IEncinas10
Copy link
Collaborator Author

...it can be obtained by verible-verilog-lint --print_rules_file

Oh, thank you for that. Yes, that is a good solution.

Do you want a_q <= a_d to be valid? Or should only a_q1 <= a_d be acceptable?

I was thinking both. a_q <= a_d should definitely be allowed still.

Done! I updated the tests accordingly. Hopefully I didn't miss anything stupid.

I don't see how I can document this feature of the pipelined flop, so let's leave it until there is better infrastructure around it and we can print examples or larger descriptions in the --help_rules flag.

Please double check, once you're happy this should go in. Feel free to open issues if you come up with more suggestions :)

@sifferman
Copy link

sifferman commented Oct 6, 2024

It seems to be working for all the solutions to my course's lab assignments. Very soon I will have 120 beta testers all using this functionality and I will follow up if we find anything weird. :)

For the pipelined documentation, you can try the following wording:

Additionally, you may append a number to the end of your register name to denote the pipeline stage index. For output:q, _q/_q1 is one cycle of latency, _q2 is two cycles, _q3 is three, etc.

That is probably all that is needed.

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.

There are other two parameters meant to restrict the rule in some
common corner-cases:

  1. Common reset/flush blocks where default values might be assigned
     can be waived using their `if` condition

  2. Variables on which we don't want the rule to act can be waived
     using a regular expression.
@IEncinas10
Copy link
Collaborator Author

Ready to go @hzeller :)

@fangism
Copy link
Collaborator

fangism commented Oct 7, 2024

I just wanted to say I really appreciate the effort that went into this. Thanks for being patient with our reviews too.

@hzeller
Copy link
Collaborator

hzeller commented Oct 7, 2024

Very cool. Thank you!

@hzeller hzeller merged commit 32b2456 into chipsalliance:master Oct 7, 2024
34 checks passed
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.

5 participants