Skip to content

Commit

Permalink
Merge pull request #789 from veryl-lang/clock_domain
Browse files Browse the repository at this point in the history
Clock domain annotation support
  • Loading branch information
dalance authored Jun 21, 2024
2 parents e88c944 + 15282be commit d39923b
Show file tree
Hide file tree
Showing 43 changed files with 21,211 additions and 18,954 deletions.
3 changes: 2 additions & 1 deletion crates/analyzer/src/analyzer/check_variable_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ impl<'a> VerylWalker for CheckVariableType<'a> {

/// Semantic action for non-terminal 'PortDeclarationItem'
fn port_declaration_item(&mut self, arg: &PortDeclarationItem) {
if let PortDeclarationItemGroup::DirectionArrayType(x) = &*arg.port_declaration_item_group {
if let PortDeclarationItemGroup::PortTypeConcrete(x) = &*arg.port_declaration_item_group {
let x = x.port_type_concrete.as_ref();
let is_modport = matches!(&*x.direction, Direction::Modport(_));
if !is_modport {
self.array_type(&x.array_type);
Expand Down
57 changes: 57 additions & 0 deletions crates/analyzer/src/analyzer_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,24 @@ pub enum AnalyzerError {
error_location: SourceSpan,
},

#[diagnostic(
severity(Error),
code(mismatch_clock_domain),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#mismatch_clock_domain")
)]
#[error("Clock domain crossing is detected")]
MismatchClockDomain {
clock_domain: String,
other_domain: String,
#[source_code]
input: NamedSource<String>,
#[label("clock domain {clock_domain}")]
error_location: SourceSpan,
#[label("clock domain {other_domain}")]
other_location: SourceSpan,
},

#[diagnostic(
severity(Error),
code(missing_if_reset),
Expand Down Expand Up @@ -675,6 +693,21 @@ pub enum AnalyzerError {
error_location: SourceSpan,
},

#[diagnostic(
severity(Error),
code(unknown_unsafe),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#unknown_unsafe")
)]
#[error("\"{name}\" is not valid unsafe identifier")]
UnknownUnsafe {
name: String,
#[source_code]
input: NamedSource<String>,
#[label("Error location")]
error_location: SourceSpan,
},

#[diagnostic(
severity(Error),
code(private_member),
Expand Down Expand Up @@ -1111,6 +1144,22 @@ impl AnalyzerError {
}
}

pub fn mismatch_clock_domain(
clock_domain: &str,
other_domain: &str,
source: &str,
token: &TokenRange,
other_token: &TokenRange,
) -> Self {
AnalyzerError::MismatchClockDomain {
clock_domain: clock_domain.to_string(),
other_domain: other_domain.to_string(),
input: AnalyzerError::named_source(source, token),
error_location: token.into(),
other_location: other_token.into(),
}
}

pub fn missing_clock_signal(source: &str, token: &TokenRange) -> Self {
AnalyzerError::MissingClockSignal {
input: AnalyzerError::named_source(source, token),
Expand Down Expand Up @@ -1273,6 +1322,14 @@ impl AnalyzerError {
}
}

pub fn unknown_unsafe(name: &str, source: &str, token: &TokenRange) -> Self {
AnalyzerError::UnknownUnsafe {
name: name.to_string(),
input: AnalyzerError::named_source(source, token),
error_location: token.into(),
}
}

pub fn private_member(name: &str, source: &str, token: &TokenRange) -> Self {
AnalyzerError::PrivateMember {
name: name.to_string(),
Expand Down
127 changes: 10 additions & 117 deletions crates/analyzer/src/attribute_table.rs
Original file line number Diff line number Diff line change
@@ -1,123 +1,16 @@
use crate::attribute::Attribute;
use crate::range_table::RangeTable;
use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt;
use veryl_parser::resource_table::PathId;
use veryl_parser::veryl_token::{Token, TokenRange, TokenSource};
use veryl_parser::veryl_token::{Token, TokenRange};

#[derive(Clone, Debug, Default)]
pub struct AttributeTable {
table: HashMap<PathId, Vec<(TokenRange, Attribute)>>,
temporary: Vec<(Token, Option<Attribute>)>,
}

impl AttributeTable {
pub fn insert(&mut self, range: TokenRange, attr: Attribute) {
if let TokenSource::File(path) = range.beg.source {
self.table
.entry(path)
.and_modify(|x| x.push((range, attr)))
.or_insert(vec![(range, attr)]);
} else {
unreachable!();
}
}

pub fn begin(&mut self, token: Token, attr: Option<Attribute>) {
self.temporary.push((token, attr));
}

pub fn end(&mut self, token: Token) {
let (beg, attr) = self.temporary.pop().unwrap();
if let Some(attr) = attr {
let range = TokenRange { beg, end: token };
self.insert(range, attr);
}
}

pub fn get(&self, token: &Token) -> Vec<Attribute> {
let mut ret = Vec::new();

if let TokenSource::File(path) = token.source {
if let Some(attrs) = self.table.get(&path) {
for (range, attr) in attrs {
if range.include(path, token.line, token.column) {
ret.push(*attr);
}
}
}
}

// Append attributes which are not closed
for (_, t) in &self.temporary {
if let Some(t) = t {
ret.push(*t);
}
}

ret
}

pub fn contains(&self, token: &Token, attr: Attribute) -> bool {
let attrs = self.get(token);
attrs.contains(&attr)
}

pub fn dump(&self) -> String {
format!("{self}")
}

pub fn get_all(&self) -> Vec<(TokenRange, Attribute)> {
self.table.values().flat_map(|x| x.clone()).collect()
}

pub fn clear(&mut self) {
self.table.clear()
}
}

impl fmt::Display for AttributeTable {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "AttributeTable [")?;
let mut attr_width = 0;
let mut vec: Vec<_> = self.table.iter().collect();
vec.sort_by(|x, y| format!("{}", x.0).cmp(&format!("{}", y.0)));
for (_, v) in &vec {
for (_, attr) in v.iter() {
attr_width = attr_width.max(format!("{attr}").len());
}
}

for (_, v) in &vec {
for (range, attr) in v.iter() {
writeln!(
f,
" {:attr_width$} @ {}: {}:{} - {}:{},",
attr,
range.beg.source,
range.beg.line,
range.beg.column,
range.end.line,
range.end.column,
attr_width = attr_width,
)?;
}
}

writeln!(f, "]")?;

Ok(())
}
}

thread_local!(static ATTRIBUTE_TABLE: RefCell<AttributeTable> = RefCell::new(AttributeTable::default()));
thread_local!(static ATTRIBUTE_TABLE: RefCell<RangeTable<Attribute>> = RefCell::new(RangeTable::default()));

pub fn insert(range: TokenRange, attr: Attribute) {
ATTRIBUTE_TABLE.with(|f| f.borrow_mut().insert(range, attr))
pub fn insert(range: TokenRange, value: Attribute) {
ATTRIBUTE_TABLE.with(|f| f.borrow_mut().insert(range, value))
}

pub fn begin(token: Token, attr: Option<Attribute>) {
ATTRIBUTE_TABLE.with(|f| f.borrow_mut().begin(token, attr))
pub fn begin(token: Token, value: Option<Attribute>) {
ATTRIBUTE_TABLE.with(|f| f.borrow_mut().begin(token, value))
}

pub fn end(token: Token) {
Expand All @@ -128,12 +21,12 @@ pub fn get(token: &Token) -> Vec<Attribute> {
ATTRIBUTE_TABLE.with(|f| f.borrow().get(token))
}

pub fn contains(token: &Token, attr: Attribute) -> bool {
ATTRIBUTE_TABLE.with(|f| f.borrow().contains(token, attr))
pub fn contains(token: &Token, value: Attribute) -> bool {
ATTRIBUTE_TABLE.with(|f| f.borrow().contains(token, &value))
}

pub fn dump() -> String {
ATTRIBUTE_TABLE.with(|f| f.borrow().dump())
ATTRIBUTE_TABLE.with(|f| format!("AttributeTable {}", f.borrow().dump()))
}

pub fn get_all() -> Vec<(TokenRange, Attribute)> {
Expand Down
12 changes: 12 additions & 0 deletions crates/analyzer/src/handlers.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod check_assignment;
pub mod check_attribute;
pub mod check_clock_domain;
pub mod check_clock_reset;
pub mod check_direction;
pub mod check_embed_include;
Expand All @@ -12,10 +13,12 @@ pub mod check_modport;
pub mod check_msb_lsb;
pub mod check_number;
pub mod check_statement;
pub mod check_unsafe;
pub mod create_reference;
pub mod create_symbol_table;
pub mod create_type_dag;
use check_attribute::*;
use check_clock_domain::*;
use check_clock_reset::*;
use check_direction::*;
use check_embed_include::*;
Expand All @@ -28,6 +31,7 @@ use check_modport::*;
use check_msb_lsb::*;
use check_number::*;
use check_statement::*;
use check_unsafe::*;
use create_reference::*;
use create_symbol_table::*;

Expand All @@ -44,6 +48,7 @@ pub struct Pass1Handlers<'a> {
check_identifier: CheckIdentifier<'a>,
check_number: CheckNumber<'a>,
check_statement: CheckStatement<'a>,
check_unsafe: CheckUnsafe<'a>,
create_symbol_table: CreateSymbolTable<'a>,
}

Expand All @@ -56,6 +61,7 @@ impl<'a> Pass1Handlers<'a> {
check_identifier: CheckIdentifier::new(text, lint_opt),
check_number: CheckNumber::new(text),
check_statement: CheckStatement::new(text),
check_unsafe: CheckUnsafe::new(text),
create_symbol_table: CreateSymbolTable::new(text, build_opt),
}
}
Expand All @@ -68,6 +74,7 @@ impl<'a> Pass1Handlers<'a> {
&mut self.check_identifier as &mut dyn Handler,
&mut self.check_number as &mut dyn Handler,
&mut self.check_statement as &mut dyn Handler,
&mut self.check_unsafe as &mut dyn Handler,
&mut self.create_symbol_table as &mut dyn Handler,
]
}
Expand All @@ -80,6 +87,7 @@ impl<'a> Pass1Handlers<'a> {
ret.append(&mut self.check_identifier.errors);
ret.append(&mut self.check_number.errors);
ret.append(&mut self.check_statement.errors);
ret.append(&mut self.check_unsafe.errors);
ret.append(&mut self.create_symbol_table.errors);
ret
}
Expand All @@ -96,6 +104,7 @@ pub struct Pass2Handlers<'a> {
create_reference: CreateReference<'a>,
create_type_dag: CreateTypeDag<'a>,
check_expression: CheckExpression<'a>,
check_clock_domain: CheckClockDomain<'a>,
}

impl<'a> Pass2Handlers<'a> {
Expand All @@ -111,6 +120,7 @@ impl<'a> Pass2Handlers<'a> {
create_reference: CreateReference::new(text),
create_type_dag: CreateTypeDag::new(text),
check_expression: CheckExpression::new(text),
check_clock_domain: CheckClockDomain::new(text),
}
}

Expand All @@ -126,6 +136,7 @@ impl<'a> Pass2Handlers<'a> {
&mut self.create_reference as &mut dyn Handler,
&mut self.create_type_dag as &mut dyn Handler,
&mut self.check_expression as &mut dyn Handler,
&mut self.check_clock_domain as &mut dyn Handler,
]
}

Expand All @@ -141,6 +152,7 @@ impl<'a> Pass2Handlers<'a> {
ret.append(&mut self.create_reference.errors);
ret.append(&mut self.create_type_dag.errors);
ret.append(&mut self.check_expression.errors);
ret.append(&mut self.check_clock_domain.errors);
ret
}
}
2 changes: 1 addition & 1 deletion crates/analyzer/src/handlers/check_assignment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ impl<'a> VerylGrammarTrait for CheckAssignment<'a> {
match x.found.kind {
SymbolKind::Module(ref x) => {
for port in &x.ports {
dirs.insert(port.name, port.property.direction);
dirs.insert(port.name, port.property().direction);
}
}
SymbolKind::SystemVerilog => dir_unknown = true,
Expand Down
Loading

0 comments on commit d39923b

Please sign in to comment.