From 86a29cb1b0c6a63497d295c085c31131658f0c35 Mon Sep 17 00:00:00 2001 From: Taichi Ishitani Date: Thu, 23 May 2024 23:20:15 +0900 Subject: [PATCH] allow to add prefix/suffix to clock/reset signals (refs: veryl-lang/veryl#623) --- Veryl.toml | 9 +- crates/analyzer/src/analyzer.rs | 16 +- crates/analyzer/src/handlers.rs | 8 +- .../src/handlers/create_symbol_table.rs | 53 ++++++- crates/analyzer/src/symbol.rs | 8 + crates/emitter/src/aligner.rs | 66 +++++++- crates/emitter/src/emitter.rs | 148 +++++++++++++++--- crates/metadata/src/build.rs | 8 + crates/metadata/src/tests.rs | 9 ++ crates/parser/src/stringifier.rs | 46 ++++++ crates/parser/src/veryl_token.rs | 14 +- testcases/sv/12_always.sv | 14 +- testcases/sv/29_allow.sv | 8 +- testcases/veryl/10_various_line_comment.veryl | 6 +- 14 files changed, 356 insertions(+), 57 deletions(-) diff --git a/Veryl.toml b/Veryl.toml index 1be4c2a7..76311579 100644 --- a/Veryl.toml +++ b/Veryl.toml @@ -7,10 +7,11 @@ license = "MIT" repository = "https://github.com/veryl-lang/veryl" [build] -clock_type = "posedge" -reset_type = "async_low" -filelist_type = "absolute" -target = {type = "directory", path = "testcases/sv"} +clock_type = "posedge" +reset_type = "async_low" +reset_low_suffix = "_n" +filelist_type = "absolute" +target = {type = "directory", path = "testcases/sv"} [format] indent_width = 4 diff --git a/crates/analyzer/src/analyzer.rs b/crates/analyzer/src/analyzer.rs index 35764b23..8e02bc10 100644 --- a/crates/analyzer/src/analyzer.rs +++ b/crates/analyzer/src/analyzer.rs @@ -15,7 +15,7 @@ use crate::symbol_table; use crate::type_dag; use itertools::Itertools; use std::path::Path; -use veryl_metadata::{Lint, Metadata}; +use veryl_metadata::{Build, Lint, Metadata}; use veryl_parser::resource_table; use veryl_parser::veryl_grammar_trait::*; use veryl_parser::veryl_token::{Token, TokenSource}; @@ -26,9 +26,9 @@ pub struct AnalyzerPass1<'a> { } impl<'a> AnalyzerPass1<'a> { - pub fn new(text: &'a str, lint_opt: &'a Lint) -> Self { + pub fn new(text: &'a str, build_opt: &'a Build, lint_opt: &'a Lint) -> Self { AnalyzerPass1 { - handlers: Pass1Handlers::new(text, lint_opt), + handlers: Pass1Handlers::new(text, build_opt, lint_opt), } } } @@ -44,9 +44,9 @@ pub struct AnalyzerPass2<'a> { } impl<'a> AnalyzerPass2<'a> { - pub fn new(text: &'a str, lint_opt: &'a Lint) -> Self { + pub fn new(text: &'a str, build_opt: &'a Build, lint_opt: &'a Lint) -> Self { AnalyzerPass2 { - handlers: Pass2Handlers::new(text, lint_opt), + handlers: Pass2Handlers::new(text, build_opt, lint_opt), } } } @@ -180,6 +180,7 @@ impl<'a> AnalyzerPass3<'a> { } pub struct Analyzer { + build_opt: Build, lint_opt: Lint, } @@ -216,6 +217,7 @@ impl Analyzer { } } Analyzer { + build_opt: metadata.build.clone(), lint_opt: metadata.lint.clone(), } } @@ -230,7 +232,7 @@ impl Analyzer { let mut ret = Vec::new(); namespace_table::set_default(&[project_name.into()]); - let mut pass1 = AnalyzerPass1::new(text, &self.lint_opt); + let mut pass1 = AnalyzerPass1::new(text, &self.build_opt, &self.lint_opt); pass1.veryl(input); ret.append(&mut pass1.handlers.get_errors()); @@ -247,7 +249,7 @@ impl Analyzer { let mut ret = Vec::new(); namespace_table::set_default(&[project_name.into()]); - let mut pass2 = AnalyzerPass2::new(text, &self.lint_opt); + let mut pass2 = AnalyzerPass2::new(text, &self.build_opt, &self.lint_opt); pass2.veryl(input); ret.append(&mut pass2.handlers.get_errors()); diff --git a/crates/analyzer/src/handlers.rs b/crates/analyzer/src/handlers.rs index de0f355b..c39bacf8 100644 --- a/crates/analyzer/src/handlers.rs +++ b/crates/analyzer/src/handlers.rs @@ -28,7 +28,7 @@ use create_reference::*; use create_symbol_table::*; use crate::analyzer_error::AnalyzerError; -use veryl_metadata::Lint; +use veryl_metadata::{Build, Lint}; use veryl_parser::veryl_walker::Handler; use self::{check_assignment::CheckAssignment, create_type_dag::CreateTypeDag}; @@ -44,7 +44,7 @@ pub struct Pass1Handlers<'a> { } impl<'a> Pass1Handlers<'a> { - pub fn new(text: &'a str, lint_opt: &'a Lint) -> Self { + pub fn new(text: &'a str, build_opt: &'a Build, lint_opt: &'a Lint) -> Self { Self { check_attribute: CheckAttribute::new(text), check_direction: CheckDirection::new(text), @@ -52,7 +52,7 @@ impl<'a> Pass1Handlers<'a> { check_identifier: CheckIdentifier::new(text, lint_opt), check_number: CheckNumber::new(text), check_statement: CheckStatement::new(text), - create_symbol_table: CreateSymbolTable::new(text), + create_symbol_table: CreateSymbolTable::new(text, build_opt), } } @@ -93,7 +93,7 @@ pub struct Pass2Handlers<'a> { } impl<'a> Pass2Handlers<'a> { - pub fn new(text: &'a str, _lint_opt: &'a Lint) -> Self { + pub fn new(text: &'a str, _build_opt: &'a Build, _lint_opt: &'a Lint) -> Self { Self { check_enum: CheckEnum::new(text), check_function: CheckFunction::new(text), diff --git a/crates/analyzer/src/handlers/create_symbol_table.rs b/crates/analyzer/src/handlers/create_symbol_table.rs index 64a45a53..5e8a163f 100644 --- a/crates/analyzer/src/handlers/create_symbol_table.rs +++ b/crates/analyzer/src/handlers/create_symbol_table.rs @@ -16,6 +16,8 @@ use crate::symbol::{ use crate::symbol_path::{GenericSymbolPath, SymbolPath}; use crate::symbol_table; use std::collections::{HashMap, HashSet}; +use veryl_metadata::ClockType; +use veryl_metadata::{Build, ResetType}; use veryl_parser::doc_comment_table; use veryl_parser::resource_table::{self, StrId}; use veryl_parser::veryl_grammar_trait::*; @@ -27,6 +29,7 @@ use veryl_parser::ParolError; pub struct CreateSymbolTable<'a> { pub errors: Vec, text: &'a str, + build_opt: Build, point: HandlerPoint, namespace: Namespace, module_namspace_depth: usize, @@ -55,9 +58,10 @@ enum StructOrUnion { } impl<'a> CreateSymbolTable<'a> { - pub fn new(text: &'a str) -> Self { + pub fn new(text: &'a str, build_opt: &'a Build) -> Self { Self { text, + build_opt: build_opt.clone(), ..Default::default() } } @@ -105,6 +109,37 @@ impl<'a> CreateSymbolTable<'a> { id } + fn get_signal_prefix_suffix(&self, kind: TypeKind) -> (Option, Option) { + match kind { + TypeKind::Clock => match self.build_opt.clock_type { + ClockType::PosEdge => { + let prefix = self.build_opt.clock_posedge_prefix.clone(); + let suffix = self.build_opt.clock_posedge_suffix.clone(); + return (prefix, suffix); + } + ClockType::NegEdge => { + let prefix = self.build_opt.clock_negedge_prefix.clone(); + let suffix = self.build_opt.clock_negedge_suffix.clone(); + return (prefix, suffix); + } + }, + TypeKind::Reset => match self.build_opt.reset_type { + ResetType::AsyncHigh | ResetType::SyncHigh => { + let prefix = self.build_opt.reset_high_prefix.clone(); + let suffix = self.build_opt.reset_high_suffix.clone(); + return (prefix, suffix); + } + ResetType::AsyncLow | ResetType::SyncLow => { + let prefix = self.build_opt.reset_low_prefix.clone(); + let suffix = self.build_opt.reset_low_suffix.clone(); + return (prefix, suffix); + } + }, + _ => {} + } + (None, None) + } + fn is_default_clock_candidate(&self, kind: SymbolKind) -> bool { if *self.affiniation.last().unwrap() != VariableAffiniation::Module || self.namespace.depth() != self.module_namspace_depth @@ -268,9 +303,12 @@ impl<'a> VerylGrammarTrait for CreateSymbolTable<'a> { if let HandlerPoint::Before = self.point { let r#type: SymType = arg.array_type.as_ref().into(); let affiniation = self.affiniation.last().cloned().unwrap(); + let (prefix, suffix) = self.get_signal_prefix_suffix(r#type.kind.clone()); let property = VariableProperty { r#type, affiniation, + prefix, + suffix, }; let kind = SymbolKind::Variable(property); @@ -300,6 +338,8 @@ impl<'a> VerylGrammarTrait for CreateSymbolTable<'a> { let property = VariableProperty { r#type, affiniation, + prefix: None, + suffix: None, }; let kind = SymbolKind::Variable(property); self.insert_symbol(&arg.identifier.identifier_token.token, kind, false); @@ -315,9 +355,12 @@ impl<'a> VerylGrammarTrait for CreateSymbolTable<'a> { if let HandlerPoint::Before = self.point { let r#type: SymType = arg.array_type.as_ref().into(); let affiniation = self.affiniation.last().cloned().unwrap(); + let (prefix, suffix) = self.get_signal_prefix_suffix(r#type.kind.clone()); let property = VariableProperty { r#type, affiniation, + prefix, + suffix, }; let kind = SymbolKind::Variable(property); @@ -338,9 +381,12 @@ impl<'a> VerylGrammarTrait for CreateSymbolTable<'a> { if let HandlerPoint::Before = self.point { let r#type: SymType = arg.array_type.as_ref().into(); let affiniation = self.affiniation.last().cloned().unwrap(); + let (prefix, suffix) = self.get_signal_prefix_suffix(r#type.kind.clone()); let property = VariableProperty { r#type, affiniation, + prefix, + suffix, }; let kind = SymbolKind::Variable(property); @@ -663,16 +709,21 @@ impl<'a> VerylGrammarTrait for CreateSymbolTable<'a> { PortDeclarationItemGroup::DirectionArrayType(x) => { let r#type: SymType = x.array_type.as_ref().into(); let direction: SymDirection = x.direction.as_ref().into(); + let (prefix, suffix) = self.get_signal_prefix_suffix(r#type.kind.clone()); PortProperty { token, r#type: Some(r#type), direction, + prefix, + suffix, } } PortDeclarationItemGroup::InterfacePortDeclarationItemOpt(_) => PortProperty { token, r#type: None, direction: SymDirection::Interface, + prefix: None, + suffix: None, }, }; let kind = SymbolKind::Port(property); diff --git a/crates/analyzer/src/symbol.rs b/crates/analyzer/src/symbol.rs index 46fc7628..d547600f 100644 --- a/crates/analyzer/src/symbol.rs +++ b/crates/analyzer/src/symbol.rs @@ -640,6 +640,8 @@ impl From<&syntax_tree::ArrayType> for Type { pub struct VariableProperty { pub r#type: Type, pub affiniation: VariableAffiniation, + pub prefix: Option, + pub suffix: Option, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -655,6 +657,8 @@ pub struct PortProperty { pub token: Token, pub r#type: Option, pub direction: Direction, + pub prefix: Option, + pub suffix: Option, } #[derive(Debug, Clone)] @@ -681,6 +685,8 @@ impl From<&syntax_tree::PortDeclarationItem> for Port { token, r#type: Some(r#type), direction, + prefix: None, + suffix: None, } } syntax_tree::PortDeclarationItemGroup::InterfacePortDeclarationItemOpt(_) => { @@ -688,6 +694,8 @@ impl From<&syntax_tree::PortDeclarationItem> for Port { token, r#type: None, direction: Direction::Interface, + prefix: None, + suffix: None, } } }; diff --git a/crates/emitter/src/aligner.rs b/crates/emitter/src/aligner.rs index 4ee94b56..1aec40cf 100644 --- a/crates/emitter/src/aligner.rs +++ b/crates/emitter/src/aligner.rs @@ -1,6 +1,6 @@ use crate::emitter::{symbol_string, SymbolContext}; use std::collections::HashMap; -use veryl_analyzer::symbol::GenericMap; +use veryl_analyzer::symbol::{GenericMap, SymbolKind}; use veryl_analyzer::symbol_table; use veryl_metadata::{Build, BuiltinType, Metadata}; use veryl_parser::resource_table::StrId; @@ -203,6 +203,20 @@ impl Aligner { .implicit_parameter_types .contains(&BuiltinType::Type) } + + fn identifier_with_prefix_suffix( + &mut self, + identifier: &Identifier, + prefix: &Option, + suffix: &Option, + ) { + if prefix.is_some() || suffix.is_some() { + let token = identifier.identifier_token.append(prefix, suffix); + self.veryl_token(&token); + } else { + self.veryl_token(&identifier.identifier_token); + } + } } impl VerylWalker for Aligner { @@ -293,6 +307,56 @@ impl VerylWalker for Aligner { self.veryl_token(&arg.u64_token.replace("longint unsigned")); } + /// Semantic action for non-terminal 'Identifier' + fn identifier(&mut self, arg: &Identifier) { + let (prefix, suffix) = if let Ok(found) = symbol_table::resolve(arg) { + match &found.found.kind { + SymbolKind::Port(x) => (x.prefix.clone(), x.suffix.clone()), + SymbolKind::Variable(x) => (x.prefix.clone(), x.suffix.clone()), + _ => (None, None), + } + } else { + (None, None) + }; + self.identifier_with_prefix_suffix(arg, &prefix, &suffix); + } + + /// Semantic action for non-terminal 'HierarchicalIdentifier' + fn hierarchical_identifier(&mut self, arg: &HierarchicalIdentifier) { + let list_len = &arg.hierarchical_identifier_list0.len(); + let (prefix, suffix) = if let Ok(found) = symbol_table::resolve(arg) { + match &found.found.kind { + SymbolKind::Port(x) => (x.prefix.clone(), x.suffix.clone()), + SymbolKind::Variable(x) => (x.prefix.clone(), x.suffix.clone()), + _ => (None, None), + } + } else { + unreachable!() + }; + + if *list_len == 0 { + self.identifier_with_prefix_suffix(&arg.identifier, &prefix, &suffix); + } else { + self.identifier(&arg.identifier); + } + + for x in &arg.hierarchical_identifier_list { + self.select(&x.select); + } + + for (i, x) in arg.hierarchical_identifier_list0.iter().enumerate() { + self.dot(&x.dot); + if (i + 1) == *list_len { + self.identifier_with_prefix_suffix(&x.identifier, &prefix, &suffix); + } else { + self.identifier(&x.identifier); + } + for x in &x.hierarchical_identifier_list0_list { + self.select(&x.select); + } + } + } + /// Semantic action for non-terminal 'ScopedIdentifier' fn scoped_identifier(&mut self, arg: &ScopedIdentifier) { if let Ok(symbol) = symbol_table::resolve(arg) { diff --git a/crates/emitter/src/emitter.rs b/crates/emitter/src/emitter.rs index 13c8c8f0..ed6af8c9 100644 --- a/crates/emitter/src/emitter.rs +++ b/crates/emitter/src/emitter.rs @@ -269,6 +269,20 @@ impl Emitter { self.process_token(x, false, Some(i)) } + fn identifier_with_prefix_suffix( + &mut self, + identifier: &Identifier, + prefix: &Option, + suffix: &Option, + ) { + if prefix.is_some() || suffix.is_some() { + let token = &identifier.identifier_token.append(prefix, suffix); + self.veryl_token(token); + } else { + self.veryl_token(&identifier.identifier_token); + } + } + fn always_ff_implicit_event_list(&mut self, arg: &AlwaysFfDeclaration) { self.str("("); self.always_ff_implicit_clock_event(); @@ -280,12 +294,16 @@ impl Emitter { fn always_ff_implicit_clock_event(&mut self) { let symbol = symbol_table::get(self.default_clock.unwrap()).unwrap(); - let clock = match symbol.kind { - SymbolKind::Port(x) => (x.r#type.clone().unwrap().kind, symbol.token), - SymbolKind::Variable(x) => (x.r#type.kind, symbol.token), + let (clock_kind, prefix, suffix) = match symbol.kind { + SymbolKind::Port(x) => ( + x.r#type.clone().unwrap().kind, + x.prefix.clone(), + x.suffix.clone(), + ), + SymbolKind::Variable(x) => (x.r#type.kind, x.prefix.clone(), x.suffix.clone()), _ => unreachable!(), }; - let clock_type = match clock.0 { + let clock_type = match clock_kind { TypeKind::ClockPosedge => ClockType::PosEdge, TypeKind::ClockNegedge => ClockType::NegEdge, TypeKind::Clock => self.build_opt.clock_type, @@ -297,7 +315,13 @@ impl Emitter { ClockType::NegEdge => self.str("negedge"), } self.space(1); - self.str(&clock.1.to_string()); + + if prefix.is_some() || suffix.is_some() { + let token = VerylToken::new(symbol.token).append(&prefix, &suffix); + self.str(&token.token.to_string()); + } else { + self.str(&symbol.token.to_string()); + } } fn always_ff_if_reset_exists(&mut self, arg: &AlwaysFfDeclaration) -> bool { @@ -310,12 +334,16 @@ impl Emitter { fn always_ff_implicit_reset_event(&mut self) { let symbol = symbol_table::get(self.default_reset.unwrap()).unwrap(); - let reset = match symbol.kind { - SymbolKind::Port(x) => (x.r#type.clone().unwrap().kind, symbol.token), - SymbolKind::Variable(x) => (x.r#type.kind, symbol.token), + let (reset_kind, prefix, suffix) = match symbol.kind { + SymbolKind::Port(x) => ( + x.r#type.clone().unwrap().kind, + x.prefix.clone(), + x.suffix.clone(), + ), + SymbolKind::Variable(x) => (x.r#type.kind, x.prefix.clone(), x.suffix.clone()), _ => unreachable!(), }; - let reset_type = match reset.0 { + let reset_type = match reset_kind { TypeKind::ResetAsyncHigh => ResetType::AsyncHigh, TypeKind::ResetAsyncLow => ResetType::AsyncLow, TypeKind::ResetSyncHigh => ResetType::SyncHigh, @@ -324,13 +352,19 @@ impl Emitter { _ => unreachable!(), }; - let prefix = match reset_type { + let token = if prefix.is_some() || suffix.is_some() { + VerylToken::new(symbol.token).append(&prefix, &suffix).token + } else { + symbol.token + }; + + let prefix_op = match reset_type { ResetType::AsyncHigh => { self.str(","); self.space(1); self.str("posedge"); self.space(1); - self.str(&reset.1.to_string()); + self.str(&token.to_string()); "" } ResetType::AsyncLow => { @@ -338,14 +372,14 @@ impl Emitter { self.space(1); self.str("negedge"); self.space(1); - self.str(&reset.1.to_string()); + self.str(&token.to_string()); "!" } ResetType::SyncHigh => "", ResetType::SyncLow => "!", }; - self.reset_signal = Some(format!("{}{}", prefix, reset.1)); + self.reset_signal = Some(format!("{}{}", prefix_op, token)); } fn always_ff_reset_exist_in_sensitivity_list(&mut self, arg: &AlwaysFfReset) -> bool { @@ -629,6 +663,56 @@ impl VerylWalker for Emitter { self.veryl_token(&arg.u64_token.replace("longint unsigned")); } + /// Semantic action for non-terminal 'Identifier' + fn identifier(&mut self, arg: &Identifier) { + let (prefix, suffix) = if let Ok(found) = symbol_table::resolve(arg) { + match &found.found.kind { + SymbolKind::Port(x) => (x.prefix.clone(), x.suffix.clone()), + SymbolKind::Variable(x) => (x.prefix.clone(), x.suffix.clone()), + _ => (None, None), + } + } else { + (None, None) + }; + self.identifier_with_prefix_suffix(arg, &prefix, &suffix); + } + + /// Semantic action for non-terminal 'HierarchicalIdentifier' + fn hierarchical_identifier(&mut self, arg: &HierarchicalIdentifier) { + let list_len = &arg.hierarchical_identifier_list0.len(); + let (prefix, suffix) = if let Ok(found) = symbol_table::resolve(arg) { + match &found.found.kind { + SymbolKind::Port(x) => (x.prefix.clone(), x.suffix.clone()), + SymbolKind::Variable(x) => (x.prefix.clone(), x.suffix.clone()), + _ => (None, None), + } + } else { + unreachable!() + }; + + if *list_len == 0 { + self.identifier_with_prefix_suffix(&arg.identifier, &prefix, &suffix); + } else { + self.identifier_with_prefix_suffix(&arg.identifier, &None, &None); + } + + for x in &arg.hierarchical_identifier_list { + self.select(&x.select); + } + + for (i, x) in arg.hierarchical_identifier_list0.iter().enumerate() { + self.dot(&x.dot); + if (i + 1) == *list_len { + self.identifier_with_prefix_suffix(&x.identifier, &prefix, &suffix); + } else { + self.identifier_with_prefix_suffix(&x.identifier, &None, &None); + } + for x in &x.hierarchical_identifier_list0_list { + self.select(&x.select); + } + } + } + /// Semantic action for non-terminal 'Operator07' fn operator07(&mut self, arg: &Operator07) { match arg.operator07_token.to_string().as_str() { @@ -1751,12 +1835,16 @@ impl VerylWalker for Emitter { /// Semantic action for non-terminal 'AlwaysFfReset' fn always_ff_reset(&mut self, arg: &AlwaysFfReset) { if let Ok(found) = symbol_table::resolve(arg.hierarchical_identifier.as_ref()) { - let reset = match found.found.kind { - SymbolKind::Port(x) => x.r#type.clone().unwrap().kind, - SymbolKind::Variable(x) => x.r#type.kind, + let (reset_kind, prefix, suffix) = match found.found.kind { + SymbolKind::Port(x) => ( + x.r#type.clone().unwrap().kind, + x.prefix.clone(), + x.suffix.clone(), + ), + SymbolKind::Variable(x) => (x.r#type.kind, x.prefix.clone(), x.suffix.clone()), _ => unreachable!(), }; - let reset_type = match reset { + let reset_type = match reset_kind { TypeKind::ResetAsyncHigh => ResetType::AsyncHigh, TypeKind::ResetAsyncLow => ResetType::AsyncLow, TypeKind::ResetSyncHigh => ResetType::SyncHigh, @@ -1764,7 +1852,7 @@ impl VerylWalker for Emitter { TypeKind::Reset => self.build_opt.reset_type, _ => unreachable!(), }; - let prefix = match reset_type { + let prefix_op = match reset_type { ResetType::AsyncHigh => { self.str("posedge"); self.space(1); @@ -1782,8 +1870,12 @@ impl VerylWalker for Emitter { }; let mut stringifier = Stringifier::new(); - stringifier.hierarchical_identifier(&arg.hierarchical_identifier); - self.reset_signal = Some(format!("{}{}", prefix, stringifier.as_str())); + stringifier.hierarchical_identifier_with_prefix_suffix( + &arg.hierarchical_identifier, + &prefix, + &suffix, + ); + self.reset_signal = Some(format!("{}{}", prefix_op, stringifier.as_str())); } else { unreachable!() } @@ -1903,7 +1995,11 @@ impl VerylWalker for Emitter { self.enum_member_prefix = Some(x.to_string()); } } - self.token(&arg.r#enum.enum_token.append("typedef ", "")); + self.token( + &arg.r#enum + .enum_token + .append(&Some(String::from("typedef ")), &None), + ); self.space(1); self.scalar_type(&arg.scalar_type); self.space(1); @@ -1951,7 +2047,7 @@ impl VerylWalker for Emitter { /// Semantic action for non-terminal 'EnumItem' fn enum_item(&mut self, arg: &EnumItem) { let prefix = format!("{}_", self.enum_member_prefix.clone().unwrap()); - self.token(&arg.identifier.identifier_token.append(&prefix, "")); + self.token(&arg.identifier.identifier_token.append(&Some(prefix), &None)); if let Some(ref x) = arg.enum_item_opt { self.space(1); self.equ(&x.equ); @@ -1973,10 +2069,14 @@ impl VerylWalker for Emitter { match &*arg.struct_union { StructUnion::Struct(ref x) => { - self.token(&x.r#struct.struct_token.append("typedef ", " packed")); + let prefix = Some(String::from("typedef ")); + let suffix = Some(String::from(" packed")); + self.token(&x.r#struct.struct_token.append(&prefix, &suffix)); } StructUnion::Union(ref x) => { - self.token(&x.union.union_token.append("typedef ", " packed")); + let prefix = Some(String::from("typedef ")); + let suffix = Some(String::from(" packed")); + self.token(&x.union.union_token.append(&prefix, &suffix)); } } self.space(1); diff --git a/crates/metadata/src/build.rs b/crates/metadata/src/build.rs index 49eead69..08f3baed 100644 --- a/crates/metadata/src/build.rs +++ b/crates/metadata/src/build.rs @@ -8,6 +8,14 @@ pub struct Build { pub clock_type: ClockType, #[serde(default)] pub reset_type: ResetType, + pub clock_posedge_prefix: Option, + pub clock_posedge_suffix: Option, + pub clock_negedge_prefix: Option, + pub clock_negedge_suffix: Option, + pub reset_high_prefix: Option, + pub reset_high_suffix: Option, + pub reset_low_prefix: Option, + pub reset_low_suffix: Option, #[serde(default)] pub filelist_type: FilelistType, #[serde(default)] diff --git a/crates/metadata/src/tests.rs b/crates/metadata/src/tests.rs index bebc5c84..57f09508 100644 --- a/crates/metadata/src/tests.rs +++ b/crates/metadata/src/tests.rs @@ -17,6 +17,7 @@ version = "0.1.0" [build] clock_type = "posedge" reset_type = "async_low" +reset_low_suffix = "_n" target = {type = "source"} #target = {type = "directory", path = "aaa"} @@ -131,6 +132,14 @@ fn check_toml() { assert_eq!(metadata.project.version, Version::parse("0.1.0").unwrap()); assert_eq!(metadata.build.clock_type, ClockType::PosEdge); assert_eq!(metadata.build.reset_type, ResetType::AsyncLow); + assert!(metadata.build.clock_posedge_prefix.is_none()); + assert!(metadata.build.clock_posedge_suffix.is_none()); + assert!(metadata.build.clock_negedge_prefix.is_none()); + assert!(metadata.build.clock_negedge_suffix.is_none()); + assert!(metadata.build.reset_high_prefix.is_none()); + assert!(metadata.build.reset_high_suffix.is_none()); + assert!(metadata.build.reset_low_prefix.is_none()); + assert_eq!(metadata.build.reset_low_suffix.unwrap(), "_n"); assert_eq!(metadata.format.indent_width, 4); } diff --git a/crates/parser/src/stringifier.rs b/crates/parser/src/stringifier.rs index cc4db6c4..b87d9be2 100644 --- a/crates/parser/src/stringifier.rs +++ b/crates/parser/src/stringifier.rs @@ -1,4 +1,5 @@ use crate::resource_table::StrId; +use crate::veryl_grammar_trait::{HierarchicalIdentifier, Identifier}; use crate::veryl_token::VerylToken; use crate::veryl_walker::VerylWalker; @@ -20,6 +21,51 @@ impl Stringifier { pub fn ids(&self) -> &[StrId] { &self.ids } + + pub fn hierarchical_identifier_with_prefix_suffix( + &mut self, + arg: &HierarchicalIdentifier, + prefix: &Option, + suffix: &Option, + ) { + let list_len = &arg.hierarchical_identifier_list0.len(); + + if *list_len == 0 { + self.identifier_with_prefix_suffix(&arg.identifier, prefix, suffix); + } else { + self.identifier(&arg.identifier); + } + + for x in &arg.hierarchical_identifier_list { + self.select(&x.select); + } + + for (i, x) in arg.hierarchical_identifier_list0.iter().enumerate() { + self.dot(&x.dot); + if (i + 1) == *list_len { + self.identifier_with_prefix_suffix(&x.identifier, prefix, suffix); + } else { + self.identifier(&x.identifier); + } + for x in &x.hierarchical_identifier_list0_list { + self.select(&x.select); + } + } + } + + fn identifier_with_prefix_suffix( + &mut self, + identifier: &Identifier, + prefix: &Option, + suffix: &Option, + ) { + if prefix.is_some() || suffix.is_some() { + let token = identifier.identifier_token.append(prefix, suffix); + self.veryl_token(&token); + } else { + self.veryl_token(&identifier.identifier_token); + } + } } impl VerylWalker for Stringifier { diff --git a/crates/parser/src/veryl_token.rs b/crates/parser/src/veryl_token.rs index d10b943d..9eb1f5dc 100644 --- a/crates/parser/src/veryl_token.rs +++ b/crates/parser/src/veryl_token.rs @@ -362,8 +362,18 @@ impl VerylToken { ret } - pub fn append(&self, prefix: &str, postfix: &str) -> Self { - let text = format!("{}{}{}", prefix, self.token.text, postfix); + pub fn append(&self, prefix: &Option, suffix: &Option) -> Self { + let prefix_str = if let Some(ref x) = prefix { + x.as_str() + } else { + "" + }; + let suffix_str = if let Some(ref x) = suffix { + x.as_str() + } else { + "" + }; + let text = format!("{}{}{}", prefix_str, self.token.text, suffix_str); let length = text.len(); let text = resource_table::insert_str(&text); let mut ret = self.clone(); diff --git a/testcases/sv/12_always.sv b/testcases/sv/12_always.sv index e328bce8..c0292efc 100644 --- a/testcases/sv/12_always.sv +++ b/testcases/sv/12_always.sv @@ -1,12 +1,12 @@ module veryl_testcase_Module12_1 ( - input logic i_clk, - input logic i_rst + input logic i_clk , + input logic i_rst_n ); logic a; logic b; - always_ff @ (posedge i_clk, negedge i_rst) begin - if (!i_rst) begin + always_ff @ (posedge i_clk, negedge i_rst_n) begin + if (!i_rst_n) begin a <= 0; end else begin a <= ~a; @@ -22,7 +22,7 @@ module veryl_testcase_Module12_2 ( input logic i_clk , input logic i_clk_p , input logic i_clk_n , - input logic i_rst , + input logic i_rst_n , input logic i_rst_ah, input logic i_rst_al, input logic i_rst_sh, @@ -36,8 +36,8 @@ module veryl_testcase_Module12_2 ( always_comb c = 1; // always_ff declaration with default polarity - always_ff @ (posedge i_clk, negedge i_rst) begin - if (!i_rst) begin + always_ff @ (posedge i_clk, negedge i_rst_n) begin + if (!i_rst_n) begin a <= b; end else if (a) begin a <= b[0]; diff --git a/testcases/sv/29_allow.sv b/testcases/sv/29_allow.sv index 3a4bbb9a..8e12d92e 100644 --- a/testcases/sv/29_allow.sv +++ b/testcases/sv/29_allow.sv @@ -1,6 +1,6 @@ module veryl_testcase_Module29 ( - input logic clk, - input logic rst + input logic clk , + input logic rst_n ); logic a; logic b; @@ -8,8 +8,8 @@ module veryl_testcase_Module29 ( logic c; always_comb c = 1; - always_ff @ (posedge clk, negedge rst) begin - if (!rst) begin + always_ff @ (posedge clk, negedge rst_n) begin + if (!rst_n) begin a <= 0; end else begin a <= 0; diff --git a/testcases/veryl/10_various_line_comment.veryl b/testcases/veryl/10_various_line_comment.veryl index f0419576..9be27a87 100644 --- a/testcases/veryl/10_various_line_comment.veryl +++ b/testcases/veryl/10_various_line_comment.veryl @@ -6,8 +6,8 @@ module //a input //a clock //a , - i_rst_n: input reset, - i_up : input logic, + i_rst: input reset, + i_up : input logic, i_down : input logic , o_count: output logic<8>, @@ -34,7 +34,7 @@ module //a always_ff // a (i_clk // a , // a - i_rst_n // a + i_rst // a ) // a { if_reset // a