Improve the parsing of I/O ports

This commit is contained in:
Guojie Luo 2022-02-14 20:04:27 +08:00
parent 2bb1ff9f45
commit 427b47d602
7 changed files with 199 additions and 146 deletions

7
src/cst/context.rs Normal file
View File

@ -0,0 +1,7 @@
pub struct Context {}
impl Context {
pub fn new() -> Self {
Self {}
}
}

View File

@ -1,20 +1,17 @@
use crate::cst::{ModuleDeclaration, Tag};
use crate::cst::{ModuleDeclaration, Tag, Tools};
use json::JsonValue;
use llhd::ir::Module;
pub struct DescriptionList {}
impl DescriptionList {
pub fn codegen(json: &JsonValue) {
assert!(json["tag"] == Tag::DESCRIPTION_LIST);
for member in json["children"].members() {
if member["tag"] == Tag::MODULE_DECLARATION {
ModuleDeclaration::codegen(member);
} else {
println!(
r#"tag "{}" under "{}" not yet supported"#,
member["tag"], json["tag"]
);
}
}
pub fn codegen(json: &JsonValue) -> Vec<Module> {
Tools::extract(
vec![json],
vec![Tag::DESCRIPTION_LIST, Tag::MODULE_DECLARATION],
)
.iter()
.map(|&x| ModuleDeclaration::codegen(x))
.collect()
}
}

View File

@ -1,7 +1,11 @@
pub mod context;
pub mod description_list;
pub mod module_declaration;
pub mod tags;
pub mod tools;
pub use context::Context;
pub use description_list::DescriptionList;
pub use module_declaration::ModuleDeclaration;
pub use tags::Tag;
pub use tools::Tools;

View File

@ -1,6 +1,6 @@
use crate::cst::Tag;
use crate::cst::{Tag, Tools};
use json::JsonValue;
use llhd::ir::{Arg, InstBuilder, Module, Signature, UnitBuilder, UnitData, UnitKind, UnitName};
use llhd::ir::{InstBuilder, Module, Signature, UnitBuilder, UnitData, UnitKind, UnitName};
use llhd::ty::{int_ty, signal_ty};
use std::collections::HashMap;
@ -8,126 +8,51 @@ pub struct ModuleDeclaration {}
impl ModuleDeclaration {
pub fn codegen(json: &JsonValue) -> Module {
assert!(json["tag"] == Tag::MODULE_DECLARATION);
let json_module = &json["children"];
let mut module = Module::new();
let entity_name = UnitName::global(
ModuleDeclaration::extract_node(
json_module,
vec![Tag::MODULE_HEADER, Tag::SYMBOL_IDENTIFIER],
)["text"]
.to_string(),
);
let entity_name = UnitName::global({
let json_symbol_identifier = Tools::extract(
vec![json],
vec![
Tag::MODULE_DECLARATION,
Tag::MODULE_HEADER,
Tag::SYMBOL_IDENTIFIER,
],
);
assert_eq!(json_symbol_identifier.len(), 1);
json_symbol_identifier[0]["text"].to_string()
});
let mut entity_signature = Signature::new();
let json_ports = ModuleDeclaration::extract_children(
json_module,
vec![Tag::MODULE_ITEM_LIST, Tag::MODULE_PORT_DECLARATION],
let json_ports = &Tools::extract(
vec![json],
vec![
Tag::MODULE_DECLARATION,
Tag::MODULE_ITEM_LIST,
Tag::MODULE_PORT_DECLARATION,
],
);
let json_input_ports: Vec<&JsonValue> = json_ports
.iter()
.filter(|&x| x[0]["tag"] == Tag::INPUT)
.cloned()
.collect();
let input_info = &Self::get_tagged_info(json_ports, Tag::INPUT);
let output_info = &Self::get_tagged_info(json_ports, Tag::OUTPUT);
let input_bits_name: Vec<String> = json_input_ports
.iter()
.map(|&x| {
[
ModuleDeclaration::extract(
&x,
vec![
Tag::IDENTIFIER_LIST,
Tag::IDENTIFIER_UNPACKED_DIMENSIONS,
Tag::UNQUALIFIED_ID,
Tag::SYMBOL_IDENTIFIER,
],
),
ModuleDeclaration::extract(
&x,
vec![
Tag::IDENTIFIER_LIST,
Tag::IDENTIFIER_UNPACKED_DIMENSIONS,
Tag::SYMBOL_IDENTIFIER,
],
),
]
.concat()
})
.reduce(|x, y| [x, y].concat())
.unwrap()
.iter()
.map(|&x| x["text"].to_string())
.collect();
let input_vec_name: Vec<String> = json_input_ports
.iter()
.map(|&x| {
ModuleDeclaration::extract(
&x,
vec![
Tag::IDENTIFIER_UNPACKED_DIMENSIONS_LIST,
Tag::IDENTIFIER_UNPACKED_DIMENSIONS,
Tag::SYMBOL_IDENTIFIER,
],
)
})
.reduce(|x, y| [x, y].concat())
.unwrap()
.iter()
.map(|&x| x["text"].to_string())
.collect();
let input_vec_dim: Vec<String> = json_input_ports
.iter()
.map(|&x| {
ModuleDeclaration::extract(
&x,
vec![
Tag::PACKED_DIMENSIONS,
Tag::DECLARATION_DIMENSIONS,
Tag::DIMENSION_RANGE,
Tag::EXPRESSION,
Tag::NUMBER,
Tag::DEC_NUMBER,
],
)
})
.reduce(|x, y| [x, y].concat())
.unwrap()
.iter()
.map(|&x| x["text"].to_string())
.collect();
assert_eq!(input_vec_name.len() * 2, input_vec_dim.len());
let input_vec_info = input_vec_name
.iter()
.zip(input_vec_dim.iter().zip(input_vec_dim[1..].iter()));
let mut var_name: HashMap<Arg, String> = HashMap::new();
for bit_name in input_bits_name {
let arg = entity_signature.add_input(signal_ty(int_ty(1)));
var_name.insert(arg, bit_name);
let mut arg_table = HashMap::new();
for (name, width) in input_info {
let arg = entity_signature.add_input(signal_ty(int_ty(width.clone())));
arg_table.insert(arg, name.to_string());
}
for (name, (hi, lo)) in input_vec_info {
let hi_bit = hi.parse::<usize>().unwrap();
let lo_bit = lo.parse::<usize>().unwrap();
let arg = entity_signature.add_input(signal_ty(int_ty(hi_bit - lo_bit + 1)));
var_name.insert(arg, name.to_string());
for (name, width) in output_info {
let arg = entity_signature.add_output(signal_ty(int_ty(width.clone())));
arg_table.insert(arg, name.to_string());
}
let mut entity_data = UnitData::new(UnitKind::Entity, entity_name, entity_signature);
let mut entity_builder = UnitBuilder::new_anonymous(&mut entity_data);
for (arg, name) in var_name.iter() {
for (arg, name) in arg_table.iter() {
let value = entity_builder.arg_value(*arg);
entity_builder.set_name(value, name.to_owned());
entity_builder.set_name(value, name.to_string());
}
let mut inst_builder = InstBuilder::new(&mut entity_builder);
@ -136,38 +61,134 @@ impl ModuleDeclaration {
module.add_unit(entity_data);
println!("{}", module.dump());
module
}
fn extract<'a>(json: &'a JsonValue, path: Vec<&str>) -> Vec<&'a JsonValue> {
let mut ret = Vec::new();
for member in json.members() {
let path_name = path.first().unwrap();
let json_name = &member["tag"].as_str().unwrap();
if path_name == json_name {
if path.len() == 1 {
ret.push(member);
} else {
ret = [
ret,
ModuleDeclaration::extract(&member["children"], path[1..].to_vec()),
]
.concat();
}
}
}
ret
}
fn get_bit_names(json_io_ports: &Vec<&JsonValue>) -> Vec<String> {
// note: possible improvement by merging common path segments
let paths = vec![
vec![
Tag::MODULE_PORT_DECLARATION,
Tag::IDENTIFIER_LIST,
Tag::IDENTIFIER_UNPACKED_DIMENSIONS,
Tag::UNQUALIFIED_ID,
Tag::SYMBOL_IDENTIFIER,
],
vec![
Tag::MODULE_PORT_DECLARATION,
Tag::IDENTIFIER_LIST,
Tag::IDENTIFIER_UNPACKED_DIMENSIONS,
Tag::SYMBOL_IDENTIFIER,
],
];
assert_eq!(paths.len(), 2); // remember to modify coherently
fn extract_children<'a>(json: &'a JsonValue, path: Vec<&str>) -> Vec<&'a JsonValue> {
ModuleDeclaration::extract(json, path)
json_io_ports
.iter()
.map(|&x| &x["children"])
.map(|&x| {
[
Tools::extract(vec![&x], paths[0].to_vec()),
Tools::extract(vec![&x], paths[1].to_vec()),
]
.concat()
})
.flatten()
.map(|x| x["text"].to_string())
.collect()
}
fn extract_node<'a>(json: &'a JsonValue, path: Vec<&str>) -> &'a JsonValue {
ModuleDeclaration::extract(json, path).first().unwrap()
fn get_vec_names(json_io_ports: &Vec<&JsonValue>) -> Vec<String> {
// note: possible improvement by merging common path segments
let paths = vec![
vec![
Tag::MODULE_PORT_DECLARATION,
Tag::IDENTIFIER_UNPACKED_DIMENSIONS_LIST,
Tag::IDENTIFIER_UNPACKED_DIMENSIONS,
Tag::SYMBOL_IDENTIFIER,
],
vec![
Tag::MODULE_PORT_DECLARATION,
Tag::PORT_IDENTIFIER_LIST,
Tag::PORT_IDENTIFIER,
Tag::SYMBOL_IDENTIFIER,
],
];
assert_eq!(paths.len(), 2); // remember to modify coherently
json_io_ports
.iter()
.map(|&x| {
[
Tools::extract(vec![&x], paths[0].to_vec()),
Tools::extract(vec![&x], paths[1].to_vec()),
]
.concat()
})
.flatten()
.map(|x| x["text"].to_string())
.collect()
}
fn get_vec_dims(json_io_ports: &Vec<&JsonValue>) -> Vec<(String, String)> {
// note: possible improvement by merging common path segments
let path = vec![
Tag::MODULE_PORT_DECLARATION,
Tag::PACKED_DIMENSIONS,
Tag::DECLARATION_DIMENSIONS,
Tag::DIMENSION_RANGE,
Tag::EXPRESSION,
Tag::NUMBER,
Tag::DEC_NUMBER,
];
let raw_vec_dims: Vec<String> = json_io_ports
.iter()
.map(|&x| Tools::extract(vec![&x], path.to_vec()))
.flatten()
.map(|x| x["text"].to_string())
.collect();
let num_ports = raw_vec_dims.len() / 2;
let vec_dims: Vec<(String, String)> = raw_vec_dims
.iter()
.step_by(2)
.into_iter()
.zip(raw_vec_dims[1..].iter().step_by(2).into_iter())
.map(|(x, y)| (x.to_string(), y.to_string()))
.collect();
assert_eq!(vec_dims.len(), num_ports);
vec_dims
}
fn get_tagged_info(json_ports: &Vec<&JsonValue>, tag: &str) -> Vec<(String, usize)> {
let json_tagged_ports = &json_ports
.iter()
.filter(|&x| x["children"].members().filter(|&x| x["tag"] == tag).count() > 0)
.map(|&x| x)
.collect::<Vec<&JsonValue>>();
let bit_names = &Self::get_bit_names(json_tagged_ports);
let vec_names = &Self::get_vec_names(json_tagged_ports);
let vec_dims = &Self::get_vec_dims(json_tagged_ports);
let tagged_info = [
bit_names
.iter()
.map(|x| (x.to_string(), 1))
.collect::<Vec<(String, usize)>>(),
vec_names
.iter()
.zip(vec_dims.iter())
.map(|(name, (hi, lo))| {
let hi_bit = hi.parse::<usize>().unwrap();
let lo_bit = lo.parse::<usize>().unwrap();
(name.to_string(), hi_bit - lo_bit + 1)
})
.collect::<Vec<(String, usize)>>(),
]
.concat();
tagged_info
}
}

View File

@ -8,6 +8,9 @@ impl Tag {
pub const MODULE_ITEM_LIST: &'static str = "kModuleItemList";
pub const MODULE_PORT_DECLARATION: &'static str = "kModulePortDeclaration";
pub const INPUT: &'static str = "input";
pub const OUTPUT: &'static str = "output";
pub const PORT_IDENTIFIER_LIST: &'static str = "kPortIdentifierList";
pub const PORT_IDENTIFIER: &'static str = "kPortIdentifier";
pub const IDENTIFIER_LIST: &'static str = "kIdentifierList";
pub const IDENTIFIER_UNPACKED_DIMENSIONS_LIST: &'static str =
"kIdentifierUnpackedDimensionsList";

17
src/cst/tools.rs Normal file
View File

@ -0,0 +1,17 @@
use json::JsonValue;
pub struct Tools {}
impl Tools {
pub fn extract<'a>(json: Vec<&'a JsonValue>, path: Vec<&str>) -> Vec<&'a JsonValue> {
assert!(path.len() > 0);
json.iter()
.filter(|&x| x["tag"] == path[0])
.map(|&x| match path.len() {
1 => vec![x],
_ => Tools::extract(x["children"].members().collect(), path[1..].to_vec()),
})
.flatten()
.collect()
}
}

View File

@ -44,7 +44,11 @@ fn main_inner() -> Result<(), String> {
let json_tree = &json_top[sv_file_name]["tree"];
assert!(json_tree["tag"] == cst::Tag::DESCRIPTION_LIST);
cst::DescriptionList::codegen(json_tree);
let module_list = cst::DescriptionList::codegen(json_tree);
for module in module_list {
println!("{}===", module.dump());
println!("");
}
Ok(())
}