Partly support ExtUnits initiation

This commit is contained in:
Guojie Luo 2022-05-10 11:33:22 +08:00
parent 3d3ed5e4d1
commit 2c654b2b65
6 changed files with 307 additions and 146 deletions

View File

@ -3,8 +3,12 @@ extern crate clap;
extern crate json;
use clap::Arg;
use cst_to_llhd::cst::{DescriptionList, Tag};
use std::{fs::File, io::Read, result::Result};
use cst_to_llhd::cst::{Tag, Tools};
use json::JsonValue;
use std::{collections::HashMap, fs::File, io::Read, result::Result};
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
fn main() {
match main_inner() {
@ -36,16 +40,23 @@ fn main_inner() -> Result<(), String> {
let json_top = json::parse(contents.as_str()).unwrap();
assert!(json_top.len() == 1);
let sv_file_name = json_top.entries().next().unwrap().0;
println!(r#"codegen from CST to LLHD for "{}" ..."#, sv_file_name);
println!("");
let ref json_modules: HashMap<String, &JsonValue> = {
let sv_file_name = json_top.entries().next().unwrap().0;
info!(r#"codegen from CST to LLHD for "{}" ..."#, sv_file_name);
let json_tree = &json_top[sv_file_name]["tree"];
let json_tree = &json_top[sv_file_name]["tree"];
assert!(json_tree["tag"] == Tag::DESCRIPTION_LIST);
Tools::match_tags(
vec![json_tree],
vec![Tag::DESCRIPTION_LIST, Tag::MODULE_DECLARATION],
)
.iter()
.map(|&json| (Tools::module_name(json), json))
.collect()
};
let module_list = DescriptionList::codegen(json_tree);
for (module, _) in module_list {
println!("{}", module.dump());
for (_, context_ref) in Tools::resolve_dependencies(json_modules) {
let context = context_ref.as_ref().borrow();
println!("{}", context.module.dump());
}
Ok(())

View File

@ -3,12 +3,10 @@ extern crate clap;
extern crate json;
use clap::Arg;
use cst_to_llhd::cst::{DescriptionList, Tag};
use cst_to_llhd::cst::{Tag, Tools};
use json::JsonValue;
use llhd::opt::{Pass, PassContext};
use std::{
process::{Command, Stdio},
result::Result,
};
use std::{collections::HashMap, iter::FromIterator, result::Result};
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
@ -31,72 +29,48 @@ fn main_inner() -> Result<(), std::io::Error> {
.arg(
Arg::with_name("input")
.help("the Verilog file to convert")
.multiple(true)
.required(true),
)
.get_matches();
let json_raw = {
let mut ret = String::new();
let json_top_list: Vec<_> = matches
.values_of("input")
.unwrap()
.map(|input| {
let json_raw = Tools::json_raw(input);
let json_top = json::parse(json_raw.as_str()).unwrap();
assert!(json_top.len() == 1);
json_top
})
.collect();
let input = matches.value_of("input").unwrap();
let ref json_modules: HashMap<String, &JsonValue> =
HashMap::from_iter(json_top_list.iter().flat_map(|json_top| {
let json_modules: Vec<_> = {
let sv_file_name = json_top.entries().next().unwrap().0;
let json_tree = &json_top[sv_file_name]["tree"];
Tools::match_tags(
vec![json_tree],
vec![Tag::DESCRIPTION_LIST, Tag::MODULE_DECLARATION],
)
.iter()
.map(|&json| (Tools::module_name(json), json))
.collect()
};
let cmd_verible = "verible-verilog-syntax";
let cmd_tr = "tr";
let cmd_sed = "sed";
json_modules
}));
let mut verible_output_child = Command::new(cmd_verible)
.args(&["--printtree", "--export_json", input])
.stdout(Stdio::piped())
.spawn()
.expect(cmd_not_found(cmd_verible).as_str());
if let Some(verible_output) = verible_output_child.stdout.take() {
let mut tr_output_child = Command::new(cmd_tr)
.args(&["-d", r#"' \t\n'"#])
.stdin(verible_output)
.stdout(Stdio::piped())
.spawn()
.expect(cmd_not_found(cmd_tr).as_str());
if let Some(tr_output) = tr_output_child.stdout.take() {
let sed_output_child = Command::new(cmd_sed)
.args(&["-e", r#"s/,null//g"#, "-e", r#"s/null,//g"#])
.stdin(tr_output)
.stdout(Stdio::piped())
.spawn()
.expect(cmd_not_found(cmd_sed).as_str());
let sed_output = sed_output_child.wait_with_output()?;
ret = String::from_utf8(sed_output.stdout).unwrap();
}
}
ret
};
let json_top = json::parse(json_raw.as_str()).unwrap();
assert!(json_top.len() == 1);
let sv_file_name = json_top.entries().next().unwrap().0;
let json_tree = &json_top[sv_file_name]["tree"];
assert!(json_tree["tag"] == Tag::DESCRIPTION_LIST);
let module_list = DescriptionList::codegen(json_tree);
for (mut module, syntax_table) in module_list {
let contexts = Tools::resolve_dependencies(json_modules);
for (_, context_ref) in contexts {
let mut context = context_ref.borrow_mut();
let pass_ctx = PassContext;
trace!("syntax_table.values {:?}", syntax_table.values);
trace!("syntax_table.insts {:?}", syntax_table.insts);
llhd::pass::GlobalCommonSubexprElim::run_on_module(&pass_ctx, &mut module);
llhd::pass::GlobalCommonSubexprElim::run_on_module(&pass_ctx, &mut context.module);
//llhd::pass::InstSimplification::run_on_module(&pass_ctx, &mut module);
llhd::assembly::write_module(std::io::stdout(), &module);
llhd::assembly::write_module(std::io::stdout(), &context.module);
println!();
}
Ok(())
}
fn cmd_not_found(cmd: &str) -> String {
format!(r#"command "{}" not found"#, cmd)
}

View File

@ -1,17 +0,0 @@
use crate::cst::{ModuleDeclaration, SyntaxTable, Tag, Tools};
use json::JsonValue;
use llhd::ir::Module;
pub struct DescriptionList {}
impl DescriptionList {
pub fn codegen(json: &JsonValue) -> Vec<(Module, SyntaxTable)> {
Tools::match_tags(
vec![json],
vec![Tag::DESCRIPTION_LIST, Tag::MODULE_DECLARATION],
)
.iter()
.map(|&x| ModuleDeclaration::codegen(x))
.collect()
}
}

View File

@ -2,7 +2,6 @@ mod always_statement;
mod case_statement;
mod conditional_statement;
mod context;
mod description_list;
mod expression;
mod module_declaration;
mod net_variable_assignment;
@ -16,7 +15,7 @@ mod tools;
use always_statement::AlwaysStatement;
use case_statement::CaseStatement;
use conditional_statement::ConditionalStatement;
use context::{ModuleContext, SymbolInfo, SymbolKind, UnitContext};
use context::{SymbolInfo, SymbolKind, UnitContext};
use expression::Expression;
use net_variable_assignment::NetVariableAssignment;
use nonblocking_assignment_statement::NonblockingAssignmentStatement;
@ -24,8 +23,8 @@ use number::Number;
use statement::Statement;
use symbol_declaration::SymbolDeclaration;
pub use context::ModuleContext;
pub use context::SyntaxTable;
pub use description_list::DescriptionList;
pub use module_declaration::ModuleDeclaration;
pub use tags::Tag;
pub use tools::{CodeReporter, Tools};

View File

@ -1,37 +1,43 @@
use crate::cst::{
AlwaysStatement, ModuleContext, NetVariableAssignment, SymbolDeclaration, SymbolKind,
SyntaxTable, Tag, Tools, UnitContext,
AlwaysStatement, Expression, ModuleContext, NetVariableAssignment, SymbolDeclaration,
SymbolKind, Tag, Tools, UnitContext,
};
use json::JsonValue;
use llhd::{
ir::{ExtUnit, Module, Signature, UnitId, UnitKind, UnitName, Value},
ir::{ExtUnit, Signature, UnitId, UnitKind, UnitName, Value},
ty::{int_ty, signal_ty},
};
use std::collections::HashMap;
use std::{cell::RefCell, collections::HashMap, rc::Rc};
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
pub struct ModuleDeclaration {}
impl ModuleDeclaration {
pub fn codegen(json: &JsonValue) -> (Module, SyntaxTable) {
let mut context = ModuleContext::new(json);
impl<'a> ModuleDeclaration {
pub fn codegen(json: &'a JsonValue, context: &mut ModuleContext<'a>) {
Self::codegen_with_ext(json, context, Vec::new());
}
SymbolDeclaration::declare_port(json, &mut context);
SymbolDeclaration::declare_reg(json, &mut context);
SymbolDeclaration::declare_wire(json, &mut context);
SymbolDeclaration::declare_param(json, &mut context);
pub fn codegen_with_ext(
json: &'a JsonValue,
context: &mut ModuleContext<'a>,
ext_modules: Vec<Rc<RefCell<ModuleContext>>>,
) {
SymbolDeclaration::declare_port(json, context);
SymbolDeclaration::declare_reg(json, context);
SymbolDeclaration::declare_wire(json, context);
SymbolDeclaration::declare_param(json, context);
Self::gen_entity_data(json, &mut context);
Self::gen_port_names(&mut context);
Self::gen_regs_and_wires(&mut context);
Self::gen_assignment(json, &mut context);
Self::gen_instances(json, &mut context);
Self::gen_entity_data(json, context);
Self::gen_port_names(context);
Self::gen_regs_and_wires(context);
Self::gen_assignment(json, context);
Self::gen_instances(json, context, ext_modules);
let mut entity_ctx = context.unit_ctx.drop(); // clear UnitContext before declare processes
Self::gen_always(json, &mut entity_ctx, &mut context);
Self::gen_always(json, &mut entity_ctx, context);
Tools::beautify(&mut entity_ctx);
context.module.add_unit(entity_ctx.data.take().unwrap());
@ -41,23 +47,10 @@ impl ModuleDeclaration {
" module-codegen ",
context.module.dump()
);
(context.module, context.syntax_table)
}
fn gen_entity_data(json: &JsonValue, context: &mut ModuleContext) {
context.name = {
let json_symbol_identifier = Tools::match_tags(
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()
};
context.name = Tools::module_name(json);
let entity_name = UnitName::global(context.name.clone());
let entity_signature = {
@ -136,7 +129,7 @@ impl ModuleDeclaration {
}
}
fn gen_assignment<'a>(json: &'a JsonValue, context: &mut ModuleContext<'a>) {
fn gen_assignment(json: &'a JsonValue, context: &mut ModuleContext<'a>) {
let json_wire_assignments = &Tools::match_tags(
vec![json],
vec![
@ -158,7 +151,11 @@ impl ModuleDeclaration {
context.unit_ctx.bb_head.pop();
}
fn gen_instances<'a>(json: &'a JsonValue, _context: &mut ModuleContext<'a>) {
fn gen_instances(
json: &'a JsonValue,
context: &mut ModuleContext<'a>,
ext_modules: Vec<Rc<RefCell<ModuleContext>>>,
) {
let base_path = [
Tag::MODULE_DECLARATION,
Tag::MODULE_ITEM_LIST,
@ -166,6 +163,7 @@ impl ModuleDeclaration {
];
let type_path = [
Tag::DATA_DECLARATION,
Tag::INSTANTIATION_BASE,
Tag::INSTANTIATION_TYPE,
Tag::DATA_TYPE,
Tag::UNQUALIFIED_ID,
@ -181,32 +179,85 @@ impl ModuleDeclaration {
Tag::ACTUAL_NAMED_PORT,
];
let port_name = [Tag::ACTUAL_NAMED_PORT, Tag::SYMBOL_IDENTIFIER];
let port_expr = [Tag::ACTUAL_NAMED_PORT, Tag::PAREN_GROUP, Tag::EXPRESSION];
let port_expr = [
Tag::ACTUAL_NAMED_PORT,
Tag::PAREN_GROUP,
Tag::EXPRESSION,
Tag::REFERENCE_CALL_BASE,
];
warn!("FIXME: ExtUnit only supports named ports and direct arguments");
let _json_instances: Vec<_> = Tools::match_tags(vec![json], base_path.to_vec())
let instances: HashMap<String, HashMap<String, &JsonValue>> =
Tools::match_tags(vec![json], base_path.to_vec())
.iter()
.flat_map(|&x| {
let json_types = Tools::match_tags(vec![x], type_path.to_vec());
if json_types.len() == 1 {
let name = json_types[0]["text"].to_string();
let json_ports = &Tools::match_tags(vec![x], port_path.to_vec());
let json_port_names =
Tools::match_tags(json_ports.clone(), port_name.to_vec());
let json_port_exprs =
Tools::match_tags(json_ports.clone(), port_expr.to_vec());
let port_list: HashMap<String, _> = json_port_names
.into_iter()
.map(|x| x["text"].to_string())
.zip(json_port_exprs.into_iter())
.collect();
Some((name, port_list))
} else {
None
}
})
.collect();
let name_to_ext: HashMap<String, Rc<RefCell<ModuleContext>>> = ext_modules
.iter()
.flat_map(|&x| {
let json_types = Tools::match_tags(vec![x], type_path.to_vec());
if json_types.len() == 1 {
let json_type = json_types[0];
let json_ports = &Tools::match_tags(vec![x], port_path.to_vec());
let json_port_names = Tools::match_tags(json_ports.clone(), port_name.to_vec());
let json_port_exprs = Tools::match_tags(json_ports.clone(), port_expr.to_vec());
let json_port_list: Vec<_> = json_port_names
.into_iter()
.zip(json_port_exprs.into_iter())
.collect();
Some((json_type, json_port_list))
} else {
None
}
})
.map(|x| (x.as_ref().borrow().name.clone(), x.clone()))
.collect();
warn!("FIXME: gen_instances() work-in-progress");
context.unit_ctx.bb_head.push({
let builder = UnitContext::builder(&mut context.unit_ctx.data);
builder.unit().entry()
});
debug!("#instances = {}", instances.len());
for (name, port_list) in instances {
debug!("ext_name {}", name);
let ext_context = name_to_ext[&name].as_ref().borrow();
let ext_entity = ext_context.module.entities().next().unwrap();
let inputs: Vec<_> = ext_entity
.sig()
.inputs()
.map(|arg| {
let sig_name = ext_entity.get_name(ext_entity.arg_value(arg)).unwrap();
let json_expr = port_list[sig_name];
let symbol = &Expression::gen_reference_name(json_expr, context);
context.unit_ctx.raw_name_to_value[symbol]
})
.collect();
let outputs: Vec<_> = ext_entity
.sig()
.outputs()
.map(|arg| {
let sig_name = ext_entity.get_name(ext_entity.arg_value(arg)).unwrap();
let json_expr = port_list[sig_name];
let symbol = &Expression::gen_reference_name(json_expr, context);
context.unit_ctx.raw_name_to_value[symbol]
})
.collect();
let mut builder = UnitContext::builder(&mut context.unit_ctx.data);
let ext_unit = builder.add_extern(ext_entity.name().clone(), ext_entity.sig().clone());
builder.ins().inst(ext_unit, inputs, outputs);
}
context.unit_ctx.bb_head.pop();
warn!("FIXME: gen_instances() for ExtUnit, work-in-progress");
}
fn gen_always<'a>(
fn gen_always(
json: &'a JsonValue,
entity_ctx: &mut UnitContext,
context: &mut ModuleContext<'a>,

View File

@ -1,12 +1,19 @@
use crate::cst::UnitContext;
use crate::cst::{ModuleContext, ModuleDeclaration, Tag, UnitContext};
use json::JsonValue;
use llhd::ir::{Block, Inst, Opcode};
use std::{
collections::HashMap,
cell::RefCell,
collections::{HashMap, HashSet, VecDeque},
fs::File,
io::{BufRead, BufReader},
iter::FromIterator,
process::{Command, Stdio},
rc::Rc,
};
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
pub struct Tools {}
impl Tools {
@ -116,6 +123,142 @@ impl Tools {
}
}
}
pub fn json_raw(verilog_file_name: &str) -> String {
let mut ret = String::new();
let cmd_verible = "verible-verilog-syntax";
let cmd_tr = "tr";
let cmd_sed = "sed";
let cmd_not_found = |cmd: &str| -> String { format!(r#"command "{}" not found"#, cmd) };
let mut verible_output_child = Command::new(cmd_verible)
.args(&["--printtree", "--export_json", verilog_file_name])
.stdout(Stdio::piped())
.spawn()
.expect(cmd_not_found(cmd_verible).as_str());
if let Some(verible_output) = verible_output_child.stdout.take() {
let mut tr_output_child = Command::new(cmd_tr)
.args(&["-d", r#"' \t\n'"#])
.stdin(verible_output)
.stdout(Stdio::piped())
.spawn()
.expect(cmd_not_found(cmd_tr).as_str());
if let Some(tr_output) = tr_output_child.stdout.take() {
let sed_output_child = Command::new(cmd_sed)
.args(&["-e", r#"s/,null//g"#, "-e", r#"s/null,//g"#])
.stdin(tr_output)
.stdout(Stdio::piped())
.spawn()
.expect(cmd_not_found(cmd_sed).as_str());
let sed_output = sed_output_child.wait_with_output().unwrap();
ret = String::from_utf8(sed_output.stdout).unwrap();
}
}
ret
}
pub fn module_name(json: &JsonValue) -> String {
let json_symbol_identifier = {
let j = Tools::match_tags(
vec![json],
vec![
Tag::MODULE_DECLARATION,
Tag::MODULE_HEADER,
Tag::SYMBOL_IDENTIFIER,
],
);
assert_eq!(j.len(), 1, "{}", json);
j[0]
};
json_symbol_identifier["text"].to_string()
}
pub fn module_references(json: &JsonValue) -> HashSet<String> {
let path = [
Tag::MODULE_DECLARATION,
Tag::MODULE_ITEM_LIST,
Tag::DATA_DECLARATION,
Tag::INSTANTIATION_BASE,
Tag::INSTANTIATION_TYPE,
Tag::DATA_TYPE,
Tag::UNQUALIFIED_ID,
Tag::SYMBOL_IDENTIFIER,
];
HashSet::from_iter(
Tools::match_tags(vec![json], path.to_vec())
.into_iter()
.map(|x| x["text"].to_string()),
)
}
pub fn resolve_dependencies<'a>(
json_modules: &HashMap<String, &'a JsonValue>,
) -> HashMap<String, Rc<RefCell<ModuleContext<'a>>>> {
let mut queue = VecDeque::new();
let mut successors = HashMap::new();
let mut predecessors = HashMap::new();
let mut pred_count = HashMap::new();
for (name, json_module) in json_modules {
let preds = &Tools::module_references(json_module);
if preds.len() == 0 {
queue.push_back(name.clone());
} else {
pred_count.insert(name.clone(), preds.len());
for pred in preds {
if !successors.contains_key(pred) {
successors.insert(pred.clone(), Vec::new());
}
if let Some(successors) = successors.get_mut(pred) {
successors.push(name.clone());
}
}
}
predecessors.insert(name.clone(), preds.clone());
}
info!("dep-resolver: init_queue {:?}", queue);
info!("dep-resolver: successors {:?}", successors);
info!("dep-resolver: predecessors {:?}", predecessors);
info!("dep-resolver: pred_count {:?}", pred_count);
let modules: HashMap<String, Rc<RefCell<ModuleContext>>> =
HashMap::from_iter(json_modules.iter().map(|(name, json)| {
(
name.clone(),
Rc::new(RefCell::new(ModuleContext::new(json))),
)
}));
while let Some(name) = queue.pop_front() {
let json_module = json_modules[&name];
let context = &mut modules[&name].borrow_mut();
let ext_modules: Vec<_> = predecessors[&name]
.iter()
.map(|x| modules[x].clone())
.collect();
debug!("#ext_modules = {}", ext_modules.len());
ModuleDeclaration::codegen_with_ext(json_module, context, ext_modules);
for succr in successors.get(&name).unwrap_or(&Vec::new()) {
if let Some(count) = pred_count.get_mut(succr) {
*count -= 1;
if *count == 0 {
queue.push_back(succr.clone())
}
}
}
}
modules
}
}
pub struct CodeReporter {