Skip to content

Commit

Permalink
support importing functions into modport
Browse files Browse the repository at this point in the history
(refs: #732)
  • Loading branch information
taichi-ishitani committed May 30, 2024
1 parent c192eda commit 7408778
Show file tree
Hide file tree
Showing 22 changed files with 5,578 additions and 5,108 deletions.
4 changes: 2 additions & 2 deletions crates/analyzer/src/analyzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ fn is_assignable(direction: &Direction) -> bool {
fn must_be_assigned(kind: &SymbolKind) -> bool {
match kind {
SymbolKind::Port(x) => x.direction == Direction::Output,
SymbolKind::ModportMember(x) => x.direction == Direction::Output,
SymbolKind::ModportVariableMember(x) => x.direction == Direction::Output,
SymbolKind::Variable(_) => true,
SymbolKind::StructMember(_) => true,
_ => false,
Expand Down Expand Up @@ -378,7 +378,7 @@ fn traverse_type_symbol(id: SymbolId, path: &AssignPath) -> Vec<AssignPath> {
}
return ret;
}
SymbolKind::ModportMember(x) if is_assignable(&x.direction) => {
SymbolKind::ModportVariableMember(x) if is_assignable(&x.direction) => {
if let Ok(symbol) = symbol_table::resolve(&symbol.token) {
return traverse_type_symbol(symbol.found.id, path);
}
Expand Down
45 changes: 45 additions & 0 deletions crates/analyzer/src/analyzer_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,31 @@ pub enum AnalyzerError {
error_location: SourceSpan,
},

#[diagnostic(severity(Error), code(invalid_modport_port_item), help(""), url(""))]
#[error("#{identifier} is not a variable")]
InvalidModportPortItem {
identifier: String,
#[source_code]
input: NamedSource,
#[label("Error location")]
error_location: SourceSpan,
},

#[diagnostic(
severity(Error),
code(invalid_modport_function_item),
help(""),
url("")
)]
#[error("#{identifier} is not a function")]
InvalidModportFunctionItem {
identifier: String,
#[source_code]
input: NamedSource,
#[label("Error location")]
error_location: SourceSpan,
},

#[diagnostic(
severity(Error),
code(missing_default_argument),
Expand Down Expand Up @@ -855,6 +880,26 @@ impl AnalyzerError {
}
}

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

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

pub fn missing_default_argument(identifier: &str, source: &str, token: &TokenRange) -> Self {
AnalyzerError::MissingDefaultArgument {
identifier: identifier.into(),
Expand Down
6 changes: 6 additions & 0 deletions crates/analyzer/src/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub mod check_enum;
pub mod check_function;
pub mod check_identifier;
pub mod check_instance;
pub mod check_modport;
pub mod check_msb_lsb;
pub mod check_number;
pub mod check_statement;
Expand All @@ -21,6 +22,7 @@ use check_enum::*;
use check_function::*;
use check_identifier::*;
use check_instance::*;
use check_modport::*;
use check_msb_lsb::*;
use check_number::*;
use check_statement::*;
Expand Down Expand Up @@ -83,6 +85,7 @@ impl<'a> Pass1Handlers<'a> {

pub struct Pass2Handlers<'a> {
check_enum: CheckEnum<'a>,
check_modport: CheckModport<'a>,
check_function: CheckFunction<'a>,
check_instance: CheckInstance<'a>,
check_msb_lsb: CheckMsbLsb<'a>,
Expand All @@ -96,6 +99,7 @@ impl<'a> Pass2Handlers<'a> {
pub fn new(text: &'a str, _build_opt: &'a Build, _lint_opt: &'a Lint) -> Self {
Self {
check_enum: CheckEnum::new(text),
check_modport: CheckModport::new(text),
check_function: CheckFunction::new(text),
check_instance: CheckInstance::new(text),
check_msb_lsb: CheckMsbLsb::new(text),
Expand All @@ -109,6 +113,7 @@ impl<'a> Pass2Handlers<'a> {
pub fn get_handlers(&mut self) -> Vec<&mut dyn Handler> {
vec![
&mut self.check_enum as &mut dyn Handler,
&mut self.check_modport as &mut dyn Handler,
&mut self.check_function as &mut dyn Handler,
&mut self.check_instance as &mut dyn Handler,
&mut self.check_msb_lsb as &mut dyn Handler,
Expand All @@ -122,6 +127,7 @@ impl<'a> Pass2Handlers<'a> {
pub fn get_errors(&mut self) -> Vec<AnalyzerError> {
let mut ret = Vec::new();
ret.append(&mut self.check_enum.errors);
ret.append(&mut self.check_modport.errors);
ret.append(&mut self.check_function.errors);
ret.append(&mut self.check_instance.errors);
ret.append(&mut self.check_msb_lsb.errors);
Expand Down
6 changes: 3 additions & 3 deletions crates/analyzer/src/handlers/check_assignment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ fn can_assign(full_path: &[SymbolId]) -> bool {
SymbolKind::Port(x) if x.direction == Direction::Output => true,
SymbolKind::Port(x) if x.direction == Direction::Ref => true,
SymbolKind::Port(x) if x.direction == Direction::Inout => true,
SymbolKind::ModportMember(x) if x.direction == Direction::Output => true,
SymbolKind::ModportMember(x) if x.direction == Direction::Ref => true,
SymbolKind::ModportMember(x) if x.direction == Direction::Inout => true,
SymbolKind::ModportVariableMember(x) if x.direction == Direction::Output => true,
SymbolKind::ModportVariableMember(x) if x.direction == Direction::Ref => true,
SymbolKind::ModportVariableMember(x) if x.direction == Direction::Inout => true,
_ => false,
};
if can_assign {
Expand Down
25 changes: 20 additions & 5 deletions crates/analyzer/src/handlers/check_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,14 @@ impl<'a> VerylGrammarTrait for CheckFunction<'a> {
}

if let Ok(symbol) = symbol_table::resolve(arg.expression_identifier.as_ref()) {
if let SymbolKind::Function(x) = symbol.found.kind {
let function_symbol = match symbol.found.kind {
SymbolKind::Function(_) => symbol.found,
SymbolKind::ModportFunctionMember(x) => {
symbol_table::get(x.function_id).unwrap()
}
_ => return Ok(()),
};
if let SymbolKind::Function(x) = function_symbol.kind {
if x.ret.is_some() {
let name = format!(
"{}",
Expand Down Expand Up @@ -86,10 +93,18 @@ impl<'a> VerylGrammarTrait for CheckFunction<'a> {
}

if let Ok(symbol) = symbol_table::resolve(x.expression_identifier.as_ref()) {
let arity = if let SymbolKind::Function(x) = symbol.found.kind {
Some(x.ports.len())
} else {
None
let arity = match symbol.found.kind {
SymbolKind::Function(x) => Some(x.ports.len()),
SymbolKind::ModportFunctionMember(x) => {
if let SymbolKind::Function(x) =
symbol_table::get(x.function_id).unwrap().kind
{
Some(x.ports.len())
} else {
unreachable!();
}
}
_ => None,
};

let mut args = 0;
Expand Down
69 changes: 69 additions & 0 deletions crates/analyzer/src/handlers/check_modport.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use crate::analyzer_error::AnalyzerError;
use crate::symbol::SymbolKind;
use crate::symbol_table;
use veryl_parser::veryl_grammar_trait::*;
use veryl_parser::veryl_walker::{Handler, HandlerPoint};
use veryl_parser::ParolError;

pub struct CheckModport<'a> {
pub errors: Vec<AnalyzerError>,
text: &'a str,
point: HandlerPoint,
}

impl<'a> CheckModport<'a> {
pub fn new(text: &'a str) -> Self {
Self {
errors: Vec::new(),
text,
point: HandlerPoint::Before,
}
}
}

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

impl<'a> VerylGrammarTrait for CheckModport<'a> {
fn modport_item(&mut self, arg: &ModportItem) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
if let Ok(symbol) = symbol_table::resolve(arg.identifier.as_ref()) {
match &*arg.modport_item_group {
ModportItemGroup::Direction(_) => {
let is_variable = match symbol.found.kind {

Check failure on line 36 in crates/analyzer/src/handlers/check_modport.rs

View workflow job for this annotation

GitHub Actions / clippy

match expression looks like `matches!` macro
SymbolKind::Variable(_) => true,
_ => false,
};

if !is_variable {
self.errors.push(AnalyzerError::invalid_modport_port_item(
&arg.identifier.identifier_token.token.to_string(),
self.text,
&arg.identifier.as_ref().into(),
));
}
}
ModportItemGroup::Import(_) => {
let is_function = match symbol.found.kind {

Check failure on line 50 in crates/analyzer/src/handlers/check_modport.rs

View workflow job for this annotation

GitHub Actions / clippy

match expression looks like `matches!` macro
SymbolKind::Function(_) => true,
_ => false,
};

if !is_function {
self.errors
.push(AnalyzerError::invalid_modport_function_item(
&arg.identifier.identifier_token.token.to_string(),
self.text,
&arg.identifier.as_ref().into(),
));
}
}
}
}
}
Ok(())
}
}
66 changes: 50 additions & 16 deletions crates/analyzer/src/handlers/create_symbol_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ use crate::symbol::Direction as SymDirection;
use crate::symbol::Type as SymType;
use crate::symbol::{
ConnectTarget, DocComment, EnumMemberProperty, EnumProperty, FunctionProperty,
GenericParameterProperty, InstanceProperty, InterfaceProperty, ModportMemberProperty,
ModportProperty, ModuleProperty, PackageProperty, ParameterProperty, ParameterScope,
ParameterValue, PortProperty, StructMemberProperty, StructProperty, Symbol, SymbolId,
SymbolKind, TypeDefProperty, TypeKind, UnionMemberProperty, UnionProperty, VariableAffiniation,
VariableProperty,
GenericParameterProperty, InstanceProperty, InterfaceProperty, ModportFunctionMemberProperty,
ModportProperty, ModportVariableMemberProperty, ModuleProperty, PackageProperty,
ParameterProperty, ParameterScope, ParameterValue, PortProperty, StructMemberProperty,
StructProperty, Symbol, SymbolId, SymbolKind, TypeDefProperty, TypeKind, UnionMemberProperty,
UnionProperty, VariableAffiniation, VariableProperty,
};
use crate::symbol_path::{GenericSymbolPath, SymbolPath};
use crate::symbol_table;
Expand Down Expand Up @@ -50,6 +50,8 @@ pub struct CreateSymbolTable<'a> {
generic_references: Vec<GenericSymbolPath>,
default_clock_candidates: Vec<SymbolId>,
defualt_reset_candidates: Vec<SymbolId>,
modport_member_ids: Vec<SymbolId>,
function_ids: HashMap<StrId, SymbolId>,
}

#[derive(Clone)]
Expand Down Expand Up @@ -448,19 +450,28 @@ impl<'a> VerylGrammarTrait for CreateSymbolTable<'a> {
.push(arg.identifier.identifier_token.token.text);

for item in items {
let direction: crate::symbol::Direction = item.direction.as_ref().into();
let property = ModportMemberProperty { direction };
let id = self.insert_symbol(
&item.identifier.identifier_token.token,
SymbolKind::ModportMember(property),
false,
);
members.push(id);
let kind = match &*item.modport_item_group {
ModportItemGroup::Direction(x) => {
let direction: crate::symbol::Direction = x.direction.as_ref().into();
let property = ModportVariableMemberProperty { direction };
SymbolKind::ModportVariableMember(property)
}
ModportItemGroup::Import(_) => {
let function_id = SymbolId::default();
let property = ModportFunctionMemberProperty { function_id };
SymbolKind::ModportFunctionMember(property)
}
};
if let Some(id) =
self.insert_symbol(&item.identifier.identifier_token.token, kind, false)
{
members.push(id);
self.modport_member_ids.push(id);
}
}

self.namespace.pop();

let members: Vec<_> = members.into_iter().flatten().collect();
let property = ModportProperty { members };
let kind = SymbolKind::Modport(property);
self.insert_symbol(&arg.identifier.identifier_token.token, kind, false);
Expand Down Expand Up @@ -785,11 +796,15 @@ impl<'a> VerylGrammarTrait for CreateSymbolTable<'a> {
ports,
ret,
};
self.insert_symbol(

if let Some(id) = self.insert_symbol(
&arg.identifier.identifier_token.token,
SymbolKind::Function(property),
false,
);
) {
self.function_ids
.insert(arg.identifier.identifier_token.token.text, id);
}
}
}
Ok(())
Expand All @@ -802,6 +817,7 @@ impl<'a> VerylGrammarTrait for CreateSymbolTable<'a> {
self.namespace.push(name);
self.affiniation.push(VariableAffiniation::Module);
self.module_namspace_depth = self.namespace.depth();
self.function_ids.clear();
}
HandlerPoint::After => {
self.namespace.pop();
Expand Down Expand Up @@ -941,6 +957,8 @@ impl<'a> VerylGrammarTrait for CreateSymbolTable<'a> {
HandlerPoint::Before => {
self.namespace.push(name);
self.affiniation.push(VariableAffiniation::Intarface);
self.function_ids.clear();
self.modport_member_ids.clear();
}
HandlerPoint::After => {
self.namespace.pop();
Expand Down Expand Up @@ -975,6 +993,21 @@ impl<'a> VerylGrammarTrait for CreateSymbolTable<'a> {
SymbolKind::Interface(property),
public,
);

// link modport function
for id in &self.modport_member_ids {
let mut modport_symbol = symbol_table::get(*id).unwrap();
if let SymbolKind::ModportFunctionMember(_) = modport_symbol.kind {
if let Some(function_id) = self.function_ids.get(&modport_symbol.token.text)
{
let function_id = function_id.clone();

Check failure on line 1003 in crates/analyzer/src/handlers/create_symbol_table.rs

View workflow job for this annotation

GitHub Actions / clippy

using `clone` on type `SymbolId` which implements the `Copy` trait
let property = ModportFunctionMemberProperty { function_id };
let kind = SymbolKind::ModportFunctionMember(property);
modport_symbol.kind = kind;
symbol_table::update(modport_symbol);
}
}
}
}
}
Ok(())
Expand Down Expand Up @@ -1054,6 +1087,7 @@ impl<'a> VerylGrammarTrait for CreateSymbolTable<'a> {
HandlerPoint::Before => {
self.namespace.push(name);
self.affiniation.push(VariableAffiniation::Package);
self.function_ids.clear();
}
HandlerPoint::After => {
self.namespace.pop();
Expand Down
Loading

0 comments on commit 7408778

Please sign in to comment.