Support wire assignment in entity

This commit is contained in:
Guojie Luo 2022-04-10 17:04:28 +08:00
parent 848d9e48a8
commit 6c87b4d5f7
7 changed files with 249 additions and 201 deletions

View File

@ -2,7 +2,7 @@ use crate::cst::{Expression, ModuleContext, Statement, SymbolKind, Tag, Tools, U
use json::JsonValue;
use linked_hash_map::LinkedHashMap as HashMap;
use llhd::{
ir::{Block, Inst, Opcode, Signature, UnitId, UnitKind, UnitName, Value},
ir::{Signature, UnitId, UnitKind, UnitName, Value},
ty::{int_ty, signal_ty},
};
@ -111,95 +111,12 @@ impl AlwaysStatement {
Self::gen_event_expression_list(json_event_expression_list, context);
Statement::codegen(json_statement, context);
Self::beautify(context);
Tools::beautify(&mut context.unit_ctx);
context.unit_ctx.clear();
context.module.add_unit(context.unit_ctx.drop_data())
}
fn beautify(context: &mut ModuleContext) {
let unit_ctx = &mut context.unit_ctx;
let mut builder = UnitContext::builder(&mut unit_ctx.data);
let bb_first = builder.unit().first_block().unwrap();
let bb_last = builder.unit().last_block().unwrap();
builder.set_block_name(bb_last, String::from("end"));
builder.append_to(bb_last);
builder.ins().br(bb_first);
// remove blocks with a single jump
{
let single_inst_blocks: Vec<Block> = builder
.unit()
.blocks()
.filter(|&x| builder.unit().insts(x).count() == 1)
.collect();
for block in single_inst_blocks {
let inst = builder.unit().insts(block).last().unwrap();
let inst_data = &builder[inst];
if inst_data.opcode() == Opcode::Br {
assert!(inst_data.args().len() == 0 && inst_data.blocks().len() == 1);
let to_block = inst_data.blocks()[0];
builder.replace_block_use(block, to_block);
builder.delete_block(block);
}
}
}
// remove empty blocks
{
let empty_blocks: Vec<Block> = builder
.unit()
.blocks()
.filter(|&x| builder.unit().insts(x).count() == 0)
.collect();
for block in empty_blocks {
let next_block = builder.unit().next_block(block);
assert!(next_block.is_some());
builder.replace_block_use(block, next_block.unwrap());
builder.delete_block(block);
}
}
// name values for 'prb' and 'ld' instructions
{
let mut prb_count = HashMap::<String, usize>::new();
let mut ld_count = HashMap::<String, usize>::new();
let get_name = |base_name: &String, count: &mut HashMap<String, usize>| -> String {
if count.contains_key(base_name) {
count.insert(base_name.clone(), count[base_name] + 1);
format!("{}{}", base_name, count[base_name])
} else {
count.insert(base_name.clone(), 0);
base_name.clone()
}
};
let insts: Vec<Inst> = builder.unit().all_insts().collect();
for inst in insts {
let inst_data = &builder[inst];
let output = builder.get_inst_result(inst);
match inst_data.opcode() {
Opcode::Prb => {
let input = inst_data.args()[0];
let input_name = builder.unit().get_name(input).unwrap();
let skip = unit_ctx.raw_name_to_shadow.contains_key(input_name);
if !skip {
// skip shadows
let base_name = &format!("{}.prb", input_name);
builder.set_name(output.unwrap(), get_name(base_name, &mut prb_count));
}
}
Opcode::Ld => {
let input = inst_data.args()[0];
let base_name = &format!("{}.ld", builder.unit().get_name(input).unwrap());
builder.set_name(output.unwrap(), get_name(base_name, &mut ld_count));
}
_ => {}
}
}
}
}
fn gen_event_expression_list(json: &JsonValue, context: &mut ModuleContext) {
let mut sensitivity_list = HashMap::new();

View File

@ -123,7 +123,7 @@ impl Expression {
assert_eq!(symbol_info.kind, SymbolKind::Param);
builder.ins().const_int(symbol_info.value.clone())
} else {
panic!("unknown error at CST node {}", json);
panic!("unknown error at CST node '{}'", json);
};
if range.is_some() {

View File

@ -1,9 +1,10 @@
use crate::cst::{
AlwaysStatement, ModuleContext, SymbolDeclaration, SymbolKind, Tag, Tools, UnitContext,
AlwaysStatement, ModuleContext, NetVariableAssignment, SymbolDeclaration, SymbolKind, Tag,
Tools, UnitContext,
};
use json::JsonValue;
use llhd::{
ir::{ExtUnit, Module, Signature, UnitBuilder, UnitData, UnitId, UnitKind, Value},
ir::{ExtUnit, Module, Signature, UnitId, UnitKind, UnitName, Value},
ty::{int_ty, signal_ty},
};
use std::collections::HashMap;
@ -17,12 +18,48 @@ impl ModuleDeclaration {
pub fn codegen(json: &JsonValue) -> Module {
let mut context = ModuleContext::new();
SymbolDeclaration::gen_port_info(json, &mut context);
SymbolDeclaration::gen_reg_info(json, &mut context);
SymbolDeclaration::gen_wire_info(json, &mut context);
SymbolDeclaration::gen_param_info(json, &mut context);
SymbolDeclaration::declare_port(json, &mut context);
SymbolDeclaration::declare_reg(json, &mut context);
SymbolDeclaration::declare_wire(json, &mut context);
SymbolDeclaration::declare_param(json, &mut context);
Self::gen_entity_data(json, &mut context);
Self::set_port_names(&mut context);
Self::init_regs_and_wires(&mut context);
Self::gen_assignment(json, &mut context);
let mut entity_ctx = context.unit_ctx.drop(); // clear UnitContext before declare processes
Self::gen_always(json, &mut entity_ctx, &mut context);
Tools::beautify(&mut entity_ctx);
context.module.add_unit(entity_ctx.data.take().unwrap());
debug!(
">>>>>>>>>{0}>>>>>>>>>\n{1}<<<<<<<<<{0}<<<<<<<<<",
" module-codegen ",
context.module.dump()
);
context.module
}
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()
};
let entity_name = UnitName::global(context.name.clone());
let entity_name = SymbolDeclaration::gen_entity_name(json, &mut context);
let entity_signature = {
let mut signature = Signature::new();
let raw_name_to_arg = &mut context.unit_ctx.raw_name_to_arg;
@ -44,24 +81,29 @@ impl ModuleDeclaration {
signature
};
let mut entity_data = UnitData::new(UnitKind::Entity, entity_name, entity_signature);
// build entity
{
let mut entity_builder = UnitBuilder::new_anonymous(&mut entity_data);
context
.unit_ctx
.new_data(UnitKind::Entity, entity_name, entity_signature);
}
fn set_port_names(context: &mut ModuleContext) {
let mut builder = UnitContext::builder(&mut context.unit_ctx.data);
// set input/output port names
for (raw_name, &arg) in &context.unit_ctx.raw_name_to_arg {
let arg_value = entity_builder.arg_value(arg);
entity_builder.set_name(arg_value, raw_name.clone());
let arg_value = builder.arg_value(arg);
builder.set_name(arg_value, raw_name.clone());
context
.unit_ctx
.raw_name_to_value
.insert(raw_name.clone(), arg_value);
debug!("found I/O port {}", raw_name);
trace!("found I/O port {}", raw_name);
}
}
// initialize reg and wire
fn init_regs_and_wires(context: &mut ModuleContext) {
let mut builder = UnitContext::builder(&mut context.unit_ctx.data);
let mut zeros = HashMap::new();
for (name, symbol) in &context.symbol {
let width = symbol.value.width;
@ -72,48 +114,47 @@ impl ModuleDeclaration {
let zero = if zeros.contains_key(&w) {
zeros[&w]
} else {
let z = entity_builder.ins().const_zero(&int_ty(w));
let z = builder.ins().const_zero(&int_ty(w));
zeros.insert(w, z);
z
};
let value = entity_builder.ins().sig(zero);
entity_builder.set_name(value, n);
let value = builder.ins().sig(zero);
builder.set_name(value, n);
context
.unit_ctx
.raw_name_to_value
.insert(name.clone(), value);
debug!("found {} {}", symbol.kind, name);
trace!("found {} {}", symbol.kind, name);
}
_ => {}
}
}
// clear UnitContext before declare processes
let entity_ctx = context.unit_ctx.drop();
// declare and instantiate processes
Self::instantiate_processes(json, &mut entity_builder, &entity_ctx, &mut context);
entity_builder.finish();
}
context.module.add_unit(entity_data);
debug!(
">>>>>>>>>{0}>>>>>>>>>\n{1}<<<<<<<<<{0}<<<<<<<<<",
" module-codegen ",
context.module.dump()
fn gen_assignment(json: &JsonValue, context: &mut ModuleContext) {
let json_wire_assignments = &Tools::match_tags(
vec![json],
vec![
Tag::MODULE_DECLARATION,
Tag::MODULE_ITEM_LIST,
Tag::CONTINUOUS_ASSIGNMENT_STATEMENT,
Tag::ASSIGNMENT_LIST,
Tag::NET_VARIABLE_ASSIGNMENT,
],
);
context.module
let builder = UnitContext::builder(&mut context.unit_ctx.data);
context.unit_ctx.bb_head.push(builder.unit().entry());
for json_wire_assignment in json_wire_assignments {
NetVariableAssignment::codegen(json_wire_assignment, context);
}
fn instantiate_processes(
json: &JsonValue,
entity_builder: &mut UnitBuilder,
entity_ctx: &UnitContext,
context: &mut ModuleContext,
) {
let json_always_statement = &Tools::match_tags(
context.unit_ctx.bb_head.pop();
}
fn gen_always(json: &JsonValue, entity_ctx: &mut UnitContext, context: &mut ModuleContext) {
let json_always_statements = &Tools::match_tags(
vec![json],
vec![
Tag::MODULE_DECLARATION,
@ -122,17 +163,22 @@ impl ModuleDeclaration {
],
);
let mut builder = UnitContext::builder(&mut entity_ctx.data);
let raw_name_to_value = &entity_ctx.raw_name_to_value;
// declare processes
let ext_to_proc: Vec<(ExtUnit, UnitId)> = json_always_statement
let ext_to_proc: Vec<(ExtUnit, UnitId)> = json_always_statements
.iter()
.map(|&x| {
let proc_id = AlwaysStatement::codegen(x, context).unwrap();
let proc = context.module.unit(proc_id);
let ext_proc = entity_builder.add_extern(proc.name().clone(), proc.sig().clone());
let ext_proc = builder.add_extern(proc.name().clone(), proc.sig().clone());
(ext_proc, proc_id)
})
.collect();
builder.append_to(builder.unit().entry());
// instantiate processes
for (ext_proc, proc_id) in ext_to_proc {
let proc = &context.module.unit(proc_id);
@ -141,7 +187,7 @@ impl ModuleDeclaration {
.into_iter()
.map(|x| {
let name = &proc.get_name(x).unwrap().to_string();
entity_ctx.raw_name_to_value[name]
raw_name_to_value[name]
})
.collect();
let outputs: Vec<Value> = proc
@ -149,10 +195,10 @@ impl ModuleDeclaration {
.into_iter()
.map(|x| {
let name = &proc.get_name(x).unwrap().to_string();
entity_ctx.raw_name_to_value[name]
raw_name_to_value[name]
})
.collect();
entity_builder.ins().inst(ext_proc, inputs, outputs);
builder.ins().inst(ext_proc, inputs, outputs);
}
}
}

View File

@ -1,6 +1,9 @@
use crate::cst::{Expression, ModuleContext, Tag, Tools, UnitContext};
use json::JsonValue;
use llhd::{ir::Block, value::TimeValue};
use llhd::{
ir::{Block, UnitKind},
value::TimeValue,
};
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
@ -13,9 +16,12 @@ impl NetVariableAssignment {
assert_eq!(json["tag"], Tag::NET_VARIABLE_ASSIGNMENT);
let json_children = &json["children"];
assert_eq!(json_children.len(), 4);
assert!(json_children.len() >= 3);
assert_eq!(json_children[1]["tag"], "=");
if json_children.len() > 3 {
assert_eq!(json_children.len(), 4);
assert_eq!(json_children[3]["tag"], ";");
}
let json_symbol_identifier = Tools::match_tags(
vec![&json_children[0]],
@ -35,14 +41,26 @@ impl NetVariableAssignment {
let lvalue_name = &json_lpvalue["text"].to_string();
context.unit_ctx.lvalues.insert(lvalue_name.clone());
if context.unit_ctx.raw_name_to_value.contains_key(lvalue_name) {
assert!(context.unit_ctx.raw_name_to_arg.contains_key(lvalue_name));
let lvalue = context.unit_ctx.raw_name_to_value.get(lvalue_name);
if lvalue.is_some() {
assert!(context.unit_ctx.data.is_some());
let arg = context.unit_ctx.raw_name_to_arg[lvalue_name];
let builder = &UnitContext::builder(&mut context.unit_ctx.data);
match builder.unit().kind() {
UnitKind::Process => {
assert!(context.unit_ctx.raw_name_to_arg.contains_key(lvalue_name));
let arg = context.unit_ctx.raw_name_to_arg[lvalue_name];
// set active Type
context.unit_ctx.ty_active = Some(builder.unit().sig().arg_type(arg));
}
UnitKind::Entity => {
// set active Type
context.unit_ctx.ty_active = Some(builder.unit().value_type(*lvalue.unwrap()));
}
_ => {
panic!("unknown error at CST node '{}'", json_lpvalue);
}
}
}
let opt_expr = Expression::codegen(json_expression, context);

View File

@ -1,6 +1,6 @@
use crate::cst::{ModuleContext, Number, SymbolInfo, SymbolKind, Tag, Tools};
use json::JsonValue;
use llhd::{ir::UnitName, value::IntValue};
use llhd::value::IntValue;
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
@ -8,24 +8,7 @@ use log::{debug, error, info, trace, warn};
pub struct SymbolDeclaration {}
impl SymbolDeclaration {
pub fn gen_entity_name(json: &JsonValue, context: &mut ModuleContext) -> UnitName {
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()
};
UnitName::global(context.name.to_string())
}
pub fn gen_port_info(json: &JsonValue, context: &mut ModuleContext) {
pub fn declare_port(json: &JsonValue, context: &mut ModuleContext) {
let base_path_2001 = [
Tag::MODULE_DECLARATION,
Tag::MODULE_ITEM_LIST,
@ -174,7 +157,7 @@ impl SymbolDeclaration {
gen_port_info(json_output_ports, SymbolKind::Output);
}
pub fn gen_reg_info(json: &JsonValue, context: &mut ModuleContext) {
pub fn declare_reg(json: &JsonValue, context: &mut ModuleContext) {
let base_path = [
Tag::MODULE_DECLARATION,
Tag::MODULE_ITEM_LIST,
@ -224,7 +207,7 @@ impl SymbolDeclaration {
);
}
pub fn gen_wire_info(json: &JsonValue, context: &mut ModuleContext) {
pub fn declare_wire(json: &JsonValue, context: &mut ModuleContext) {
let base_path = [
Tag::MODULE_DECLARATION,
Tag::MODULE_ITEM_LIST,
@ -304,7 +287,7 @@ impl SymbolDeclaration {
}
}
pub fn gen_param_info(json: &JsonValue, context: &mut ModuleContext) {
pub fn declare_param(json: &JsonValue, context: &mut ModuleContext) {
let base_path = [
Tag::MODULE_DECLARATION,
Tag::MODULE_ITEM_LIST,
@ -341,7 +324,7 @@ impl SymbolDeclaration {
let name = json_names[0]["text"].to_string();
let symbol = SymbolInfo::new(SymbolKind::Param, v);
debug!("found {} {}", SymbolKind::Param, name);
trace!("found {} {}", SymbolKind::Param, name);
context.symbol.insert(name, symbol);
}

View File

@ -80,9 +80,12 @@ impl Tag {
pub const SEQ_BLOCK: &'static str = "kSeqBlock";
pub const BLOCK_ITEM_STATEMENT_LIST: &'static str = "kBlockItemStatementList";
pub const NONBLOCKING_ASSIGNMENT_STATEMENT: &'static str = "kNonblockingAssignmentStatement";
pub const CONTINUOUS_ASSIGNMENT_STATEMENT: &'static str = "kContinuousAssignmentStatement";
pub const ASSIGNMENT_LIST: &'static str = "kAssignmentList";
pub const NET_VARIABLE_ASSIGNMENT: &'static str = "kNetVariableAssignment";
pub const NONBLOCKING_ASSIGNMENT_STATEMENT: &'static str = "kNonblockingAssignmentStatement";
pub const CONDITIONAL_STATEMENT: &'static str = "kConditionalStatement";
pub const IF_CLAUSE: &'static str = "kIfClause";
pub const IF_HEADER: &'static str = "kIfHeader";
@ -95,10 +98,6 @@ impl Tag {
pub const CASE_ITEM: &'static str = "kCaseItem";
pub const DEFAULT_ITEM: &'static str = "kDefaultItem";
/*
pub const CONTINUOUS_ASSIGNMENT_STATEMENT: &'static str = "kContinuousAssignmentStatement";
*/
pub const INPUT: &'static str = "input";
pub const OUTPUT: &'static str = "output";
pub const REG: &'static str = "reg";

View File

@ -1,5 +1,8 @@
use crate::cst::UnitContext;
use json::JsonValue;
use llhd::ir::{Block, Inst, Opcode};
use std::{
collections::HashMap,
fs::File,
io::{BufRead, BufReader},
};
@ -18,6 +21,88 @@ impl Tools {
.flatten()
.collect()
}
pub fn beautify(unit_ctx: &mut UnitContext) {
let mut builder = UnitContext::builder(&mut unit_ctx.data);
let bb_first = builder.unit().first_block().unwrap();
let bb_last = builder.unit().last_block().unwrap();
builder.set_block_name(bb_last, String::from("end"));
builder.append_to(bb_last);
builder.ins().br(bb_first);
// remove blocks with a single jump
{
let single_inst_blocks: Vec<Block> = builder
.unit()
.blocks()
.filter(|&x| builder.unit().insts(x).count() == 1)
.collect();
for block in single_inst_blocks {
let inst = builder.unit().insts(block).last().unwrap();
let inst_data = &builder[inst];
if inst_data.opcode() == Opcode::Br {
assert!(inst_data.args().len() == 0 && inst_data.blocks().len() == 1);
let to_block = inst_data.blocks()[0];
builder.replace_block_use(block, to_block);
builder.delete_block(block);
}
}
}
// remove empty blocks
{
let empty_blocks: Vec<Block> = builder
.unit()
.blocks()
.filter(|&x| builder.unit().insts(x).count() == 0)
.collect();
for block in empty_blocks {
let next_block = builder.unit().next_block(block);
assert!(next_block.is_some());
builder.replace_block_use(block, next_block.unwrap());
builder.delete_block(block);
}
}
// name values for 'prb' and 'ld' instructions
{
let mut prb_count = HashMap::<String, usize>::new();
let mut ld_count = HashMap::<String, usize>::new();
let get_name = |base_name: &String, count: &mut HashMap<String, usize>| -> String {
if count.contains_key(base_name) {
count.insert(base_name.clone(), count[base_name] + 1);
format!("{}{}", base_name, count[base_name])
} else {
count.insert(base_name.clone(), 0);
base_name.clone()
}
};
let insts: Vec<Inst> = builder.unit().all_insts().collect();
for inst in insts {
let inst_data = &builder[inst];
let output = builder.get_inst_result(inst);
match inst_data.opcode() {
Opcode::Prb => {
let input = inst_data.args()[0];
let input_name = builder.unit().get_name(input).unwrap();
let skip = unit_ctx.raw_name_to_shadow.contains_key(input_name);
if !skip {
// skip shadows
let base_name = &format!("{}.prb", input_name);
builder.set_name(output.unwrap(), get_name(base_name, &mut prb_count));
}
}
Opcode::Ld => {
let input = inst_data.args()[0];
let base_name = &format!("{}.ld", builder.unit().get_name(input).unwrap());
builder.set_name(output.unwrap(), get_name(base_name, &mut ld_count));
}
_ => {}
}
}
}
}
}
pub struct CodeReporter {