From 546873f9a02fed9b94f6d5073dcab0b2e9dd6be8 Mon Sep 17 00:00:00 2001 From: Ronit Nallagatla Date: Thu, 22 Feb 2024 21:12:38 -0500 Subject: [PATCH 1/2] New Rule: implicit_case_default -- basic implementation --- src/syntaxrules/implicit_case_default.rs | 92 ++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 src/syntaxrules/implicit_case_default.rs diff --git a/src/syntaxrules/implicit_case_default.rs b/src/syntaxrules/implicit_case_default.rs new file mode 100644 index 0000000..9b480a5 --- /dev/null +++ b/src/syntaxrules/implicit_case_default.rs @@ -0,0 +1,92 @@ +use crate::config::ConfigOption; +use crate::linter::{SyntaxRule, SyntaxRuleResult}; +use sv_parser::{unwrap_node, Locate, NodeEvent, RefNode, SyntaxTree}; + +#[derive(Default)] +pub struct ImplicitCaseDefault { + under_always_construct: bool, + lhs_variables: Vec, +} + +impl SyntaxRule for ImplicitCaseDefault { + fn check( + &mut self, + syntax_tree: &SyntaxTree, + event: &NodeEvent, + _option: &ConfigOption, + ) -> SyntaxRuleResult { + // println!("Syntax Tree: {}", syntax_tree); + + let node = match event { + NodeEvent::Enter(x) => { + match x { + RefNode::AlwaysConstruct(_) => { + self.under_always_construct = true; + } + + RefNode::BlockItemDeclaration(x) => { + let var = unwrap_node!(*x, VariableDeclAssignment).unwrap(); + let id = get_identifier(var); + let id = syntax_tree.get_str(&id).unwrap(); + + self.lhs_variables.push(String::from(id)); + + println!("LHS Variables: {:?}", self.lhs_variables); + } + + _ => (), + } + x + } + NodeEvent::Leave(x) => { + if let RefNode::AlwaysConstruct(_) = x { + self.under_always_construct = false; + } + return SyntaxRuleResult::Pass; + } + }; + match (self.under_always_construct, node) { + (true, RefNode::CaseStatementNormal(x)) => { + let a = unwrap_node!(*x, CaseItemDefault); + if a.is_some() { + SyntaxRuleResult::Pass + } else { + // check if lvalues of case statement have an implicit definition + let var = unwrap_node!(*x, VariableLvalueIdentifier).unwrap(); + let id = get_identifier(var); + let id = syntax_tree.get_str(&id).unwrap(); + + println!("Case variable: {id}"); + + // check if id is in lhs_variables + if self.lhs_variables.contains(&id.to_string()) { + SyntaxRuleResult::Pass + } else { + SyntaxRuleResult::Fail + } + } + } + _ => SyntaxRuleResult::Pass, + } + } + + fn name(&self) -> String { + String::from("implicit_case_default") + } + + fn hint(&self, _option: &ConfigOption) -> String { + String::from("Signal driven in `case` statement does not have a default value.") + } + + fn reason(&self) -> String { + String::from("Default values ensure that signals are always driven.") + } +} + +fn get_identifier(node: RefNode) -> Option { + match unwrap_node!(node, SimpleIdentifier, EscapedIdentifier) { + Some(RefNode::SimpleIdentifier(x)) => Some(x.nodes.0), + Some(RefNode::EscapedIdentifier(x)) => Some(x.nodes.0), + _ => None, + } +} From 68f609bed1b9cf21362cf98a266b27cab94ec01a Mon Sep 17 00:00:00 2001 From: ronitnallagatla Date: Fri, 23 Feb 2024 02:15:19 +0000 Subject: [PATCH 2/2] Commit from GitHub Actions (Run mdgen) --- MANUAL.md | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/MANUAL.md b/MANUAL.md index 5685047..9027970 100644 --- a/MANUAL.md +++ b/MANUAL.md @@ -2030,6 +2030,89 @@ The most relevant clauses of IEEE1800-2017 are: +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +## Syntax Rule: `implicit_case_default` + +### Hint + +Signal driven in `case` statement does not have a default value. + +### Reason + +Default values ensure that signals are always driven. + +### Pass Example (1 of 2) +```systemverilog +module M; + always_comb + y = 0; + case(x) + 1: y = 1; // case default is implicit + endcase +endmodule +``` + +### Pass Example (2 of 2) +```systemverilog +module M; + always_comb + case(x) + 1: y = 1; + default: y = 0; + endcase +endmodule +``` + +### Fail Example (1 of 2) +```systemverilog +module M; + always_comb + case (x) + 1: a = 0; // No implicit or explicit case default + endcase +endmodule +``` + +### Fail Example (2 of 2) +```systemverilog +module M; + always_comb begin + a = 0; + + case(x) + 1: b = 0; + endcase + end +endmodule +``` + +### Explanation + +This rule is an extension of the **case_default** rule that allows the case default to be implicitly defined. +Case statements without a `default` branch can cause signals to be undriven. Setting default values of signals at the top of an `always` procedures is good practice and ensures that signals are never metastable when a case match fails. For example, +```sv +always_comb begin + y = 0; + case(x) + 1: y = 1; + endcase +end + +``` +If the case match fails, `y` wouldn't infer memory or be undriven because the default value is defined before the `case`. + +See also: + - **case_default** + - **explicit_case_default** + +The most relevant clauses of IEEE1800-2017 are: + +- 12.5 Case statement + + + + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ## Syntax Rule: `inout_with_tri`