Skip to content

Commit

Permalink
refactor msb check and emittion
Browse files Browse the repository at this point in the history
  • Loading branch information
taichi-ishitani committed Dec 18, 2024
1 parent 031842b commit 174aa87
Show file tree
Hide file tree
Showing 7 changed files with 201 additions and 32 deletions.
58 changes: 45 additions & 13 deletions crates/analyzer/src/handlers/check_msb_lsb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::msb_table;
use crate::namespace::Namespace;
use crate::namespace_table;
use crate::symbol::Type as SymType;
use crate::symbol::{SymbolKind, TypeKind};
use crate::symbol::{Direction, SymbolKind, TypeKind};
use crate::symbol_path::{SymbolPath, SymbolPathNamespace};
use crate::symbol_table;
use veryl_parser::veryl_grammar_trait::*;
Expand Down Expand Up @@ -40,10 +40,11 @@ impl Handler for CheckMsbLsb<'_> {
}
}

fn trace_type(r#type: &SymType, namespace: &Namespace) -> Vec<SymType> {
let mut ret = vec![r#type.clone()];
fn trace_type(r#type: &SymType, namespace: &Namespace) -> Vec<(SymType, Option<SymbolKind>)> {
let mut ret = vec![(r#type.clone(), None)];
if let TypeKind::UserDefined(ref x) = r#type.kind {
if let Ok(symbol) = symbol_table::resolve((&SymbolPath::new(x), namespace)) {
ret.last_mut().unwrap().1 = Some(symbol.found.kind.clone());
if let SymbolKind::TypeDef(ref x) = symbol.found.kind {
ret.append(&mut trace_type(&x.r#type, namespace));
}
Expand Down Expand Up @@ -73,32 +74,63 @@ impl VerylGrammarTrait for CheckMsbLsb<'_> {
{
let namespace = &x.found.namespace;

let r#type = match x.found.kind {
SymbolKind::Variable(x) => Some(x.r#type),
SymbolKind::Port(x) => x.r#type,
_ => None,
let via_interface = x.full_path.iter().any(|path| {
let symbol = symbol_table::get(*path).unwrap();
match symbol.kind {
SymbolKind::Port(x) => {
matches!(x.direction, Direction::Interface | Direction::Modport)
}
SymbolKind::Instance(_) => true,
_ => false,
}
});
let r#type = if !via_interface {
match x.found.kind {
SymbolKind::Variable(x) => Some(x.r#type),
SymbolKind::Port(x) => x.r#type,
SymbolKind::Parameter(x) => Some(x.r#type),
SymbolKind::StructMember(x) => Some(x.r#type),
SymbolKind::UnionMember(x) => Some(x.r#type),
_ => None,
}
} else {
None
};

if let Some(x) = r#type {
let types = trace_type(&x, namespace);
let mut select_dimension = *self.select_dimension.last().unwrap();

let mut expression = None;
for t in types {
let mut demension_number = None;
for (i, (t, k)) in types.iter().enumerate() {
if select_dimension < t.array.len() {
expression = t.array.get(select_dimension).cloned();
demension_number = Some(select_dimension + 1);
break;
}
select_dimension -= t.array.len();

if select_dimension < t.width.len() {
expression = t.width.get(select_dimension).cloned();
demension_number = Some(select_dimension + 1);
break;
}
select_dimension -= t.width.len();

if select_dimension == 0
&& (i + 1) == types.len()
&& matches!(
k,
Some(SymbolKind::Enum(_))
| Some(SymbolKind::Struct(_))
| Some(SymbolKind::Union(_))
)
{
demension_number = Some(0);
break;
}
}

if let Some(expression) = expression {
msb_table::insert(arg.msb_token.token.id, &expression);
if let Some(demension_number) = demension_number {
msb_table::insert(arg.msb_token.token.id, demension_number);
true
} else {
false
Expand Down
15 changes: 7 additions & 8 deletions crates/analyzer/src/msb_table.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
use std::cell::RefCell;
use std::collections::HashMap;
use veryl_parser::resource_table::TokenId;
use veryl_parser::veryl_grammar_trait::Expression;

#[derive(Clone, Default, Debug)]
pub struct MsbTable {
table: HashMap<TokenId, Expression>,
table: HashMap<TokenId, usize>,
}

impl MsbTable {
pub fn insert(&mut self, id: TokenId, expression: &Expression) {
self.table.insert(id, expression.clone());
pub fn insert(&mut self, id: TokenId, dimension_number: usize) {
self.table.insert(id, dimension_number);
}

pub fn get(&self, id: TokenId) -> Option<&Expression> {
pub fn get(&self, id: TokenId) -> Option<&usize> {
self.table.get(&id)
}

Expand All @@ -24,11 +23,11 @@ impl MsbTable {

thread_local!(static MSB_TABLE: RefCell<MsbTable> = RefCell::new(MsbTable::default()));

pub fn insert(id: TokenId, expression: &Expression) {
MSB_TABLE.with(|f| f.borrow_mut().insert(id, expression))
pub fn insert(id: TokenId, dimension_number: usize) {
MSB_TABLE.with(|f| f.borrow_mut().insert(id, dimension_number))
}

pub fn get(id: TokenId) -> Option<Expression> {
pub fn get(id: TokenId) -> Option<usize> {
MSB_TABLE.with(|f| f.borrow().get(id).cloned())
}

Expand Down
56 changes: 56 additions & 0 deletions crates/analyzer/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1771,6 +1771,62 @@ fn unknown_msb() {

let errors = analyze(code);
assert!(matches!(errors[0], AnalyzerError::UnknownMsb { .. }));

let code = r#"
interface InterfaceA {
var a: logic<2>;
modport mp {
a: input
}
}
module ModuleA (
if_a: modport InterfaceA::mp
) {
let a: logic = if_a.a[msb];
}
"#;

let errors = analyze(code);
assert!(matches!(errors[0], AnalyzerError::UnknownMsb { .. }));

let code = r#"
interface InterfaceA #(
param W: u32 = 2
){
var a: logic<W>;
}
module ModuleA {
inst if_a: InterfaceA;
assign if_a.a = 0;
let a: logic = if_a.a[msb];
}
"#;

let errors = analyze(code);
assert!(matches!(errors[0], AnalyzerError::UnknownMsb { .. }));

let code = r#"
package PackageA::<W: const> {
struct StructA {
a: logic<W>,
}
}
package PackageB {
const B: u32 = 2;
}
package PackageC {
const C: bit<2> = 0;
}
module ModuleA {
var a: PackageA::<PackageB::B>::StructA;
assign a.a = 0;
let _b: logic = a.a[msb];
let _c: logic = PackageC::C[msb];
}
"#;

let errors = analyze(code);
assert!(errors.is_empty());
}

#[test]
Expand Down
36 changes: 31 additions & 5 deletions crates/emitter/src/emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ pub struct Emitter {
assignment_lefthand_side: Option<ExpressionIdentifier>,
generic_map: Vec<GenericMap>,
source_map: Option<SourceMap>,
resolved_identifier: Vec<String>,
}

impl Default for Emitter {
Expand Down Expand Up @@ -108,6 +109,7 @@ impl Default for Emitter {
assignment_lefthand_side: None,
generic_map: Vec::new(),
source_map: None,
resolved_identifier: Vec::new(),
}
}
}
Expand Down Expand Up @@ -900,6 +902,12 @@ impl Emitter {
(None, prefix.is_some())
}
}

fn push_resolved_identifier(&mut self, x: &str) {
if let Some(identifier) = self.resolved_identifier.last_mut() {
identifier.push_str(x);
}
}
}

fn is_var_declaration(arg: &StatementBlockItem) -> bool {
Expand Down Expand Up @@ -1057,10 +1065,15 @@ impl VerylWalker for Emitter {

/// Semantic action for non-terminal 'Msb'
fn msb(&mut self, arg: &Msb) {
let expression = msb_table::get(arg.msb_token.token.id).unwrap();
self.str("((");
self.expression(&expression);
self.str(") - 1)");
let identifier = self.resolved_identifier.last().unwrap();
let demension_number = msb_table::get(arg.msb_token.token.id).unwrap();

let text = if demension_number == 0 {
format!("($bits({}) - 1)", identifier)
} else {
format!("($size({}, {}) - 1)", identifier, demension_number)
};
self.token(&arg.msb_token.replace(&text));
}

/// Semantic action for non-terminal 'Param'
Expand All @@ -1085,7 +1098,9 @@ impl VerylWalker for Emitter {

/// Semantic action for non-terminal 'Identifier'
fn identifier(&mut self, arg: &Identifier) {
self.veryl_token(&emitting_identifier(arg));
let text = emitting_identifier(arg);
self.veryl_token(&text);
self.push_resolved_identifier(&text.to_string());
}

/// Semantic action for non-terminal 'HierarchicalIdentifier'
Expand Down Expand Up @@ -1166,26 +1181,37 @@ impl VerylWalker for Emitter {
let context: SymbolContext = self.into();
let text = symbol_string(arg.identifier(), &symbol.found, &context);
self.veryl_token(&arg.identifier().replace(&text));
self.push_resolved_identifier(&text);
} else if !path.is_resolvable() {
// emit literal by generics
let text = path.base_path(0).0[0].to_string();
self.veryl_token(&arg.identifier().replace(&text));
self.push_resolved_identifier(&text);
}
}

/// Semantic action for non-terminal 'ExpressionIdentifier'
fn expression_identifier(&mut self, arg: &ExpressionIdentifier) {
self.resolved_identifier.push("".to_string());
self.scoped_identifier(&arg.scoped_identifier);
for x in &arg.expression_identifier_list {
self.select(&x.select);
}
for _x in &arg.expression_identifier_list {
self.push_resolved_identifier("[0]");
}
for x in &arg.expression_identifier_list0 {
self.dot(&x.dot);
self.push_resolved_identifier(".");
self.identifier(&x.identifier);
for x in &x.expression_identifier_list0_list {
self.select(&x.select);
}
for _x in &x.expression_identifier_list0_list {
self.push_resolved_identifier("[0]");
}
}
self.resolved_identifier.pop();
}

/// Semantic action for non-terminal 'Expression'
Expand Down
2 changes: 1 addition & 1 deletion testcases/map/testcases/sv/28_msblsb.sv.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 34 additions & 4 deletions testcases/sv/28_msblsb.sv
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module veryl_testcase_Module28 (
module veryl_testcase_Module28A (
input logic [30-1:0][40-1:0] c
);
localparam int unsigned WIDTH0 = 10;
Expand All @@ -10,10 +10,40 @@ module veryl_testcase_Module28 (
always_comb b = 1;

logic _x;
always_comb _x = a[((10) - 1)][((20) - 1):0 + 1];
always_comb _x = a[($size(a, 1) - 1)][($size(a, 2) - 1):0 + 1];
logic _y;
always_comb _y = b[((WIDTH0 + 10) - 1) - 3][((WIDTH1) - 1) + 5:0];
always_comb _y = b[($size(b, 1) - 1) - 3][($size(b, 2) - 1) + 5:0];
logic _z;
always_comb _z = c[((30) - 1)][((40) - 1)];
always_comb _z = c[($size(c, 1) - 1)][($size(c, 2) - 1)];
endmodule

package veryl_testcase___Package28A__Package28B_B;
typedef struct packed {
logic [veryl_testcase_Package28B::B-1:0] a;
} StructA;
endpackage

package veryl_testcase_Package28B;
localparam int unsigned B = 2;
endpackage

package veryl_testcase_Package28C;
localparam int unsigned W = 2;
localparam int unsigned N = 3;
localparam bit [N-1:0][W-1:0] C = 0;
endpackage

module veryl_testcase_ModuleB;
veryl_testcase___Package28A__Package28B_B::StructA a ;
always_comb a.a = 0;

logic _w;
always_comb _w = a[($bits(a) - 1)];
logic _x;
always_comb _x = a.a[($size(a.a, 1) - 1)];
logic _y;
always_comb _y = veryl_testcase_Package28C::C[($size(veryl_testcase_Package28C::C, 1) - 1)];
logic _z;
always_comb _z = veryl_testcase_Package28C::C[0][($size(veryl_testcase_Package28C::C, 2) - 1)];
endmodule
//# sourceMappingURL=../map/testcases/sv/28_msblsb.sv.map
28 changes: 27 additions & 1 deletion testcases/veryl/28_msblsb.veryl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module Module28 (
module Module28A (
c: input logic<30, 40>,
) {
const WIDTH0: u32 = 10;
Expand All @@ -11,3 +11,29 @@ module Module28 (
let _y: logic = b[msb - 3][msb + 5:lsb];
let _z: logic = c[msb][msb];
}

package Package28A::<W: const> {
struct StructA {
a: logic<W>,
}
}

package Package28B {
const B: u32 = 2;
}

package Package28C {
const W: u32 = 2;
const N: u32 = 3;
const C: bit<N, W> = 0;
}

module ModuleB {
var a : Package28A::<Package28B::B>::StructA;
assign a.a = 0;

let _w: logic = a[msb];
let _x: logic = a.a[msb];
let _y: logic = Package28C::C[msb];
let _z: logic = Package28C::C[0][msb];
}

0 comments on commit 174aa87

Please sign in to comment.