Skip to content

Commit

Permalink
introduce clock_* and reset_* types
Browse files Browse the repository at this point in the history
(refs: #622)
  • Loading branch information
taichi-ishitani committed May 8, 2024
1 parent 5543e86 commit 3303ec7
Show file tree
Hide file tree
Showing 25 changed files with 18,273 additions and 17,288 deletions.
36 changes: 36 additions & 0 deletions crates/analyzer/src/analyzer_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,26 @@ pub enum AnalyzerError {
error_location: SourceSpan,
},

#[diagnostic(severity(Error), code(invalid_clock), help(""), url(""))]
#[error("#{identifier} can't be used as a clock because it is not 'clock' type nor a single bit signal")]
InvalidClock {
identifier: String,
#[source_code]
input: NamedSource,
#[label("Error location")]
error_location: SourceSpan,
},

#[diagnostic(severity(Error), code(invalid_reset), help(""), url(""))]
#[error("#{identifier} can't be used as a reset because it is not 'reset' type nor a single bit signal")]
InvalidReset {
identifier: String,
#[source_code]
input: NamedSource,
#[label("Error location")]
error_location: SourceSpan,
},

#[diagnostic(
severity(Error),
code(mismatch_arity),
Expand Down Expand Up @@ -761,6 +781,22 @@ impl AnalyzerError {
}
}

pub fn invalid_clock(identifier: &str, token: &TokenRange) -> Self {
AnalyzerError::InvalidClock {
identifier: identifier.into(),
input: AnalyzerError::named_source(identifier, token),
error_location: token.into(),
}
}

pub fn invalid_reset(identifier: &str, token: &TokenRange) -> Self {
AnalyzerError::InvalidReset {
identifier: identifier.into(),
input: AnalyzerError::named_source(identifier, token),
error_location: token.into(),
}
}

pub fn mismatch_arity(
name: &str,
arity: usize,
Expand Down
12 changes: 6 additions & 6 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_reset;
pub mod check_direction;
pub mod check_embed_include;
pub mod check_enum;
Expand All @@ -8,12 +9,12 @@ pub mod check_identifier;
pub mod check_instance;
pub mod check_msb_lsb;
pub mod check_number;
pub mod check_reset;
pub mod check_statement;
pub mod create_reference;
pub mod create_symbol_table;
pub mod create_type_dag;
use check_attribute::*;
use check_clock_reset::*;
use check_direction::*;
use check_embed_include::*;
use check_enum::*;
Expand All @@ -22,7 +23,6 @@ use check_identifier::*;
use check_instance::*;
use check_msb_lsb::*;
use check_number::*;
use check_reset::*;
use check_statement::*;
use create_reference::*;
use create_symbol_table::*;
Expand All @@ -39,7 +39,6 @@ pub struct Pass1Handlers<'a> {
check_embed_include: CheckEmbedInclude<'a>,
check_identifier: CheckIdentifier<'a>,
check_number: CheckNumber<'a>,
check_reset: CheckReset<'a>,
check_statement: CheckStatement<'a>,
create_symbol_table: CreateSymbolTable<'a>,
}
Expand All @@ -52,7 +51,6 @@ impl<'a> Pass1Handlers<'a> {
check_embed_include: CheckEmbedInclude::new(text),
check_identifier: CheckIdentifier::new(text, lint_opt),
check_number: CheckNumber::new(text),
check_reset: CheckReset::new(text),
check_statement: CheckStatement::new(text),
create_symbol_table: CreateSymbolTable::new(text),
}
Expand All @@ -65,7 +63,6 @@ impl<'a> Pass1Handlers<'a> {
&mut self.check_embed_include as &mut dyn Handler,
&mut self.check_identifier as &mut dyn Handler,
&mut self.check_number as &mut dyn Handler,
&mut self.check_reset as &mut dyn Handler,
&mut self.check_statement as &mut dyn Handler,
&mut self.create_symbol_table as &mut dyn Handler,
]
Expand All @@ -78,7 +75,6 @@ impl<'a> Pass1Handlers<'a> {
ret.append(&mut self.check_embed_include.errors);
ret.append(&mut self.check_identifier.errors);
ret.append(&mut self.check_number.errors);
ret.append(&mut self.check_reset.errors);
ret.append(&mut self.check_statement.errors);
ret.append(&mut self.create_symbol_table.errors);
ret
Expand All @@ -91,6 +87,7 @@ pub struct Pass2Handlers<'a> {
check_instance: CheckInstance<'a>,
check_msb_lsb: CheckMsbLsb<'a>,
check_assignment: CheckAssignment<'a>,
check_clock_reset: CheckClockReset<'a>,
create_reference: CreateReference<'a>,
create_type_dag: CreateTypeDag<'a>,
}
Expand All @@ -103,6 +100,7 @@ impl<'a> Pass2Handlers<'a> {
check_instance: CheckInstance::new(text),
check_msb_lsb: CheckMsbLsb::new(text),
check_assignment: CheckAssignment::new(text),
check_clock_reset: CheckClockReset::new(text),
create_reference: CreateReference::new(text),
create_type_dag: CreateTypeDag::new(text),
}
Expand All @@ -115,6 +113,7 @@ impl<'a> Pass2Handlers<'a> {
&mut self.check_instance as &mut dyn Handler,
&mut self.check_msb_lsb as &mut dyn Handler,
&mut self.check_assignment as &mut dyn Handler,
&mut self.check_clock_reset as &mut dyn Handler,
&mut self.create_reference as &mut dyn Handler,
&mut self.create_type_dag as &mut dyn Handler,
]
Expand All @@ -127,6 +126,7 @@ impl<'a> Pass2Handlers<'a> {
ret.append(&mut self.check_instance.errors);
ret.append(&mut self.check_msb_lsb.errors);
ret.append(&mut self.check_assignment.errors);
ret.append(&mut self.check_clock_reset.errors);
ret.append(&mut self.create_reference.errors);
ret.append(&mut self.create_type_dag.errors);
ret
Expand Down
210 changes: 210 additions & 0 deletions crates/analyzer/src/handlers/check_clock_reset.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
use crate::analyzer_error::AnalyzerError;
use crate::symbol::{SymbolKind, TypeKind};
use crate::symbol_table;
use veryl_parser::veryl_grammar_trait::*;
use veryl_parser::veryl_walker::{Handler, HandlerPoint};
use veryl_parser::ParolError;

#[derive(Default)]
pub struct CheckClockReset<'a> {
pub errors: Vec<AnalyzerError>,
text: &'a str,
point: HandlerPoint,
in_always_ff: bool,
in_if_reset: bool,
if_reset_brace: usize,
if_reset_exist: bool,
n_of_select: usize,
}

impl<'a> CheckClockReset<'a> {
pub fn new(text: &'a str) -> Self {
Self {
text,
..Default::default()
}
}
}

impl<'a> Handler for CheckClockReset<'a> {
fn set_point(&mut self, p: HandlerPoint) {
self.point = p;
}
}

impl<'a> VerylGrammarTrait for CheckClockReset<'a> {
fn l_brace(&mut self, _arg: &LBrace) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
if self.in_if_reset {
self.if_reset_brace += 1;
}
}
Ok(())
}

fn r_brace(&mut self, _arg: &RBrace) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
if self.in_if_reset {
self.if_reset_brace -= 1;
if self.if_reset_brace == 0 {
self.in_if_reset = false;
}
}
}
Ok(())
}

fn if_reset(&mut self, _arg: &IfReset) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
self.if_reset_exist = true;
self.in_if_reset = true;
}
Ok(())
}

fn always_ff_declaration(&mut self, arg: &AlwaysFfDeclaration) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
// Check first if_reset when reset signel exists
let if_reset_required = if arg.always_ff_declaration_opt.is_some() {
if let Some(x) = arg.always_ff_declaration_list.first() {
!matches!(&*x.statement, Statement::IfResetStatement(_))
} else {
true
}
} else {
false
};
if if_reset_required {
self.errors
.push(AnalyzerError::missing_if_reset(self.text, &arg.into()));
}

self.in_always_ff = true;
}
HandlerPoint::After => {
// Check reset signal when if_reset exists
if self.if_reset_exist && arg.always_ff_declaration_opt.is_none() {
self.errors
.push(AnalyzerError::missing_reset_signal(self.text, &arg.into()));
}

self.in_always_ff = false;
self.if_reset_exist = false;
}
}
Ok(())
}

fn always_ff_clock(&mut self, arg: &AlwaysFfClock) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => self.n_of_select = 0,
HandlerPoint::After => {
if let Ok(found) = symbol_table::resolve(arg.hierarchical_identifier.as_ref()) {
let symbol = found.found;
let valid_clock = match symbol.kind {
SymbolKind::Port(x) => {
let clock = x.r#type.clone().unwrap();
let n_of_select = clock.width.len() + clock.array.len();
match clock.kind {
TypeKind::Clock
| TypeKind::ClockPosedge
| TypeKind::ClockNegedge => n_of_select == self.n_of_select,
_ => false,
}
}
SymbolKind::Variable(x) => {
let clock = x.r#type;
let n_of_select = clock.width.len() + clock.array.len();
match clock.kind {
TypeKind::Clock
| TypeKind::ClockPosedge
| TypeKind::ClockNegedge => n_of_select == self.n_of_select,
_ => false,
}
}
_ => false,
};

if !valid_clock {
let token = &arg
.hierarchical_identifier
.identifier
.identifier_token
.token;
self.errors.push(AnalyzerError::invalid_clock(
&token.to_string(),
&arg.hierarchical_identifier.as_ref().into(),
));
}
}
}
}
Ok(())
}

fn always_ff_reset(&mut self, arg: &AlwaysFfReset) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => self.n_of_select = 0,
HandlerPoint::After => {
if let Ok(found) = symbol_table::resolve(arg.hierarchical_identifier.as_ref()) {
let symbol = found.found;
let valid_reset = match symbol.kind {
SymbolKind::Port(x) => {
let reset = x.r#type.clone().unwrap();
let n_of_select = reset.width.len() + reset.array.len();
match reset.kind {
TypeKind::Reset
| TypeKind::ResetAsyncHigh
| TypeKind::ResetAsyncLow
| TypeKind::ResetSyncHigh
| TypeKind::ResetSyncLow => n_of_select == self.n_of_select,
_ => false,
}
}
SymbolKind::Variable(x) => {
let reset = x.r#type;
let n_of_select = reset.width.len() + reset.array.len();
match reset.kind {
TypeKind::Reset
| TypeKind::ResetAsyncHigh
| TypeKind::ResetAsyncLow
| TypeKind::ResetSyncHigh
| TypeKind::ResetSyncLow => n_of_select == self.n_of_select,
_ => false,
}
}
_ => false,
};

if !valid_reset {
let token = &arg
.hierarchical_identifier
.identifier
.identifier_token
.token;
self.errors.push(AnalyzerError::invalid_reset(
&token.to_string(),
&arg.hierarchical_identifier.as_ref().into(),
));
}
}
}
}
Ok(())
}

fn select(&mut self, _arg: &Select) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
self.n_of_select += 1;
}
Ok(())
}

fn dot(&mut self, _arg: &Dot) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
self.n_of_select = 0;
}
Ok(())
}
}
Loading

0 comments on commit 3303ec7

Please sign in to comment.