From 75009ada3c2a4bcd38c52c8fb871c9e8c1f2e6b1 Mon Sep 17 00:00:00 2001 From: Ruben Undheim Date: Thu, 11 Oct 2018 23:33:31 +0200 Subject: Synthesis support for SystemVerilog interfaces This time doing the changes mostly in AST before RTLIL generation --- passes/hierarchy/hierarchy.cc | 172 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 165 insertions(+), 7 deletions(-) (limited to 'passes/hierarchy/hierarchy.cc') diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index 5df69848e..dd4341127 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -145,9 +145,24 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check std::map> array_cells; std::string filename; + dict interfaces_in_module; for (auto &cell_it : module->cells_) { RTLIL::Cell *cell = cell_it.second; + if(cell->get_bool_attribute("\\is_interface")) { + RTLIL::Module *intf_module = design->modules_[cell->type]; + interfaces_in_module[cell->name] = intf_module; + } + } + + for (auto &cell_it : module->cells_) + { + RTLIL::Cell *cell = cell_it.second; + bool has_interfaces_not_found = false; + + std::vector connections_to_remove; + std::vector connections_to_add_name; + std::vector connections_to_add_signal; if (cell->type.substr(0, 7) == "$array:") { int pos_idx = cell->type.str().find_first_of(':'); @@ -158,6 +173,7 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check array_cells[cell] = std::pair(idx, num); cell->type = cell->type.str().substr(pos_type + 1); } + dict interfaces_to_add_to_submodule; if (design->modules_.count(cell->type) == 0) { @@ -200,11 +216,61 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check if (design->modules_.count(cell->type) == 0) log_error("File `%s' from libdir does not declare module `%s'.\n", filename.c_str(), cell->type.c_str()); did_something = true; - } else + } else { + + RTLIL::Module *mod = design->module(cell->type); + + // Go over all connections and see if any of them are SV interfaces. If they are, then add the replacements to + // some lists, so that they can be replaced further down: + for (auto &conn : cell->connections()) { + if(mod->wires_.count(conn.first) != 0 && mod->wire(conn.first)->get_bool_attribute("\\is_interface")) { // Check if the connection is present as an interface in the sub-module's port list + if(conn.second.bits().size() == 1 && conn.second.bits()[0].wire->get_bool_attribute("\\is_interface")) { + std::string interface_name_str = conn.second.bits()[0].wire->name.str(); + interface_name_str.replace(0,23,""); + interface_name_str = "\\" + interface_name_str; + RTLIL::IdString interface_name = interface_name_str; + bool will_do_step = false; + if(module->get_bool_attribute("\\interfaces_replaced_in_module")) { + if (interfaces_in_module.count(interface_name) > 0) { // Check if the interface instance is present in module + RTLIL::Module *mod_replace_ports = interfaces_in_module.at(interface_name); + for (auto &mod_wire : mod_replace_ports->wires_) { + std::string signal_name1 = conn.first.str() + "." + log_id(mod_wire.first); + std::string signal_name2 = interface_name.str() + "." + log_id(mod_wire.first); + connections_to_add_name.push_back(RTLIL::IdString(signal_name1)); + if(module->wires_.count(signal_name2) == 0) { + log_error("Could not find signal '%s' in '%s'\n", signal_name2.c_str(), log_id(module->name)); + } + else { + RTLIL::Wire *wire_in_parent = module->wire(signal_name2); + connections_to_add_signal.push_back(wire_in_parent); + } + } + connections_to_remove.push_back(conn.first); + interfaces_to_add_to_submodule[conn.first] = interfaces_in_module.at(interface_name); + } + else will_do_step = true; + } + else will_do_step = true; + // If the interface instance has not already been derived in the module, we cannot complete at this stage. Set "has_interfaces_not_found" + // which will delay the expansion of this cell: + if (will_do_step) { + // If we have already gone over all cells in this module, and the interface has still not been found - flag it as an error: + if(!(module->get_bool_attribute("\\cells_not_processed"))) { + log_warning("Could not find interface instance for `%s' in `%s'\n", log_id(interface_name), log_id(module)); + } + else { + // Only set has_interfaces_not_found if it would be possible to find them, since otherwiser we will end up in an infinite loop: + has_interfaces_not_found = true; + } + } + } + } + } + // + if (flag_check || flag_simcheck) { - RTLIL::Module *mod = design->module(cell->type); - for (auto &conn : cell->connections()) + for (auto &conn : cell->connections()) { if (conn.first[0] == '$' && '0' <= conn.first[1] && conn.first[1] <= '9') { int id = atoi(conn.first.c_str()+1); if (id <= 0 || id > GetSize(mod->ports)) @@ -213,11 +279,15 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check } else if (mod->wire(conn.first) == nullptr || mod->wire(conn.first)->port_id == 0) log_error("Module `%s' referenced in module `%s' in cell `%s' does not have a port named '%s'.\n", log_id(cell->type), log_id(module), log_id(cell), log_id(conn.first)); + } for (auto ¶m : cell->parameters) if (mod->avail_parameters.count(param.first) == 0 && param.first[0] != '$' && strchr(param.first.c_str(), '.') == NULL) log_error("Module `%s' referenced in module `%s' in cell `%s' does not have a parameter named '%s'.\n", log_id(cell->type), log_id(module), log_id(cell), log_id(param.first)); + + } } + RTLIL::Module *mod = design->modules_[cell->type]; if (design->modules_.at(cell->type)->get_bool_attribute("\\blackbox")) { if (flag_simcheck) @@ -226,15 +296,59 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check continue; } - if (cell->parameters.size() == 0) + // If interface instances not yet found, skip cell for now, and say we did something, so that we will return back here: + if(has_interfaces_not_found) { + did_something = true; // waiting for interfaces to be handled continue; + } - RTLIL::Module *mod = design->modules_[cell->type]; - cell->type = mod->derive(design, cell->parameters); + // Do the actual replacements of the SV interface port connection with the individual signal connections: + for(unsigned int i=0;iconnections_[connections_to_add_name[i]] = connections_to_add_signal[i]; + } + // Remove the connection for the interface itself: + for(unsigned int i=0;iconnections_.erase(connections_to_remove[i]); + } + + // If there are no overridden parameters AND not interfaces, then we can use the existing module instance as the type + // for the cell: + if (cell->parameters.size() == 0 && (interfaces_to_add_to_submodule.size() == 0 || !(cell->get_bool_attribute("\\module_not_derived")))) { + // If the cell being processed is an the interface instance itself, go down to "handle_interface_instance:", + // so that the signals of the interface are added to the parent module. + if (mod->get_bool_attribute("\\is_interface")) { + goto handle_interface_instance; + } + continue; + } + + cell->type = mod->derive(design, cell->parameters, interfaces_to_add_to_submodule); cell->parameters.clear(); did_something = true; + + handle_interface_instance: + + // We add all the signals of the interface explicitly to the parent module. This is always needed when we encounter + // an interface instance: + if (mod->get_bool_attribute("\\is_interface") && cell->get_bool_attribute("\\module_not_derived")) { + cell->set_bool_attribute("\\is_interface"); + RTLIL::Module *derived_module = design->modules_[cell->type]; + interfaces_in_module[cell->name] = derived_module; + did_something = true; + } + // We unset 'module_not_derived' such that we will not rederive the cell again (needed when there are interfaces connected to the cell) + cell->attributes.erase("\\module_not_derived"); + } + // Setting a flag such that it can be known that we have been through all cells at least once, such that we can know whether to flag + // an error because of interface instances not found: + module->attributes.erase("\\cells_not_processed"); + + if (interfaces_in_module.size() > 0 && !module->get_bool_attribute("\\interfaces_replaced_in_module")) { + module->reprocess_module(design, interfaces_in_module); + return did_something; } + for (auto &it : array_cells) { RTLIL::Cell *cell = it.first; @@ -341,6 +455,20 @@ int find_top_mod_score(Design *design, Module *module, dict &db) return db.at(module); } +RTLIL::Module *check_if_top_has_changed(Design *design, Module *top_mod) +{ + if(top_mod != NULL && top_mod->get_bool_attribute("\\initial_top")) + return top_mod; + else { + for (auto mod : design->modules()) { + if (mod->get_bool_attribute("\\top")) { + return mod; + } + } + } + return NULL; +} + struct HierarchyPass : public Pass { HierarchyPass() : Pass("hierarchy", "check, expand and clean up design hierarchy") { } void help() YS_OVERRIDE @@ -568,6 +696,14 @@ struct HierarchyPass : public Pass { if (flag_simcheck && top_mod == nullptr) log_error("Design has no top module.\n"); + if (top_mod != NULL) { + for (auto &mod_it : design->modules_) + if (mod_it.second == top_mod) + mod_it.second->attributes["\\initial_top"] = RTLIL::Const(1); + else + mod_it.second->attributes.erase("\\initial_top"); + } + bool did_something = true; while (did_something) { @@ -586,19 +722,41 @@ struct HierarchyPass : public Pass { if (expand_module(design, module, flag_check, flag_simcheck, libdirs)) did_something = true; } + + + RTLIL::Module *tmp_top_mod = check_if_top_has_changed(design, top_mod); + if (tmp_top_mod != NULL) { + if (tmp_top_mod != top_mod){ + top_mod = tmp_top_mod; + did_something = true; + } + } + + std::vector modules_to_delete; + for(auto &mod_it : design->modules_) { + if (mod_it.second->get_bool_attribute("\\to_delete")) { + modules_to_delete.push_back(mod_it.second); + } + } + for(size_t i=0; iremove(modules_to_delete[i]); + } } + if (top_mod != NULL) { log_header(design, "Analyzing design hierarchy..\n"); hierarchy_clean(design, top_mod, purge_lib); } if (top_mod != NULL) { - for (auto &mod_it : design->modules_) + for (auto &mod_it : design->modules_) { if (mod_it.second == top_mod) mod_it.second->attributes["\\top"] = RTLIL::Const(1); else mod_it.second->attributes.erase("\\top"); + mod_it.second->attributes.erase("\\initial_top"); + } } if (!nokeep_asserts) { -- cgit v1.2.3 From 458a94059e6738d93a87ddb9af282d0e1d28791d Mon Sep 17 00:00:00 2001 From: Ruben Undheim Date: Fri, 12 Oct 2018 20:58:37 +0200 Subject: Support for 'modports' for System Verilog interfaces --- passes/hierarchy/hierarchy.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'passes/hierarchy/hierarchy.cc') diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index dd4341127..f2f0d6e5b 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -174,6 +174,7 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check cell->type = cell->type.str().substr(pos_type + 1); } dict interfaces_to_add_to_submodule; + dict modports_used_in_submodule; if (design->modules_.count(cell->type) == 0) { @@ -224,6 +225,14 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check // some lists, so that they can be replaced further down: for (auto &conn : cell->connections()) { if(mod->wires_.count(conn.first) != 0 && mod->wire(conn.first)->get_bool_attribute("\\is_interface")) { // Check if the connection is present as an interface in the sub-module's port list + //const pool &interface_type_pool = mod->wire(conn.first)->get_strpool_attribute("\\interface_type"); + //for (auto &d : interface_type_pool) { // TODO: Compare interface type to type in parent module + //} + const pool &interface_modport_pool = mod->wire(conn.first)->get_strpool_attribute("\\interface_modport"); + std::string interface_modport = ""; + for (auto &d : interface_modport_pool) { + interface_modport = "\\" + d; + } if(conn.second.bits().size() == 1 && conn.second.bits()[0].wire->get_bool_attribute("\\is_interface")) { std::string interface_name_str = conn.second.bits()[0].wire->name.str(); interface_name_str.replace(0,23,""); @@ -247,6 +256,9 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check } connections_to_remove.push_back(conn.first); interfaces_to_add_to_submodule[conn.first] = interfaces_in_module.at(interface_name); + if (interface_modport != "") { + modports_used_in_submodule[conn.first] = interface_modport; + } } else will_do_step = true; } @@ -322,7 +334,7 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check continue; } - cell->type = mod->derive(design, cell->parameters, interfaces_to_add_to_submodule); + cell->type = mod->derive(design, cell->parameters, interfaces_to_add_to_submodule, modports_used_in_submodule); cell->parameters.clear(); did_something = true; -- cgit v1.2.3 From c50afc4246d552db079aec303b0d79ae92107a67 Mon Sep 17 00:00:00 2001 From: Ruben Undheim Date: Sat, 13 Oct 2018 20:34:44 +0200 Subject: Documentation improvements etc. - Mention new feature in the SystemVerilog section in the README file - Commented changes much better - Rename a few signals to make it clearer - Prevent warning for unused signals in an easier way - Add myself as copyright holder to 2 files - Fix one potential memory leak (delete 'wire' if not in modport) --- passes/hierarchy/hierarchy.cc | 65 +++++++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 27 deletions(-) (limited to 'passes/hierarchy/hierarchy.cc') diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index f2f0d6e5b..7e93a6f9a 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -2,6 +2,7 @@ * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2018 Ruben Undheim * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -145,6 +146,7 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check std::map> array_cells; std::string filename; + // Always keep track of all derived interfaces available in the current module in 'interfaces_in_module': dict interfaces_in_module; for (auto &cell_it : module->cells_) { @@ -222,50 +224,54 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check RTLIL::Module *mod = design->module(cell->type); // Go over all connections and see if any of them are SV interfaces. If they are, then add the replacements to - // some lists, so that they can be replaced further down: + // some lists, so that the ports for sub-modules can be replaced further down: for (auto &conn : cell->connections()) { if(mod->wires_.count(conn.first) != 0 && mod->wire(conn.first)->get_bool_attribute("\\is_interface")) { // Check if the connection is present as an interface in the sub-module's port list //const pool &interface_type_pool = mod->wire(conn.first)->get_strpool_attribute("\\interface_type"); - //for (auto &d : interface_type_pool) { // TODO: Compare interface type to type in parent module + //for (auto &d : interface_type_pool) { // TODO: Compare interface type to type in parent module (not crucially important, but good for robustness) //} + + // Find if the sub-module has set a modport for the current interface connection: const pool &interface_modport_pool = mod->wire(conn.first)->get_strpool_attribute("\\interface_modport"); std::string interface_modport = ""; for (auto &d : interface_modport_pool) { interface_modport = "\\" + d; } - if(conn.second.bits().size() == 1 && conn.second.bits()[0].wire->get_bool_attribute("\\is_interface")) { + if(conn.second.bits().size() == 1 && conn.second.bits()[0].wire->get_bool_attribute("\\is_interface")) { // Check if the connected wire is a potential interface in the parent module std::string interface_name_str = conn.second.bits()[0].wire->name.str(); - interface_name_str.replace(0,23,""); + interface_name_str.replace(0,23,""); // Strip the prefix '$dummywireforinterface' from the dummy wire to get the name interface_name_str = "\\" + interface_name_str; RTLIL::IdString interface_name = interface_name_str; - bool will_do_step = false; - if(module->get_bool_attribute("\\interfaces_replaced_in_module")) { + bool not_found_interface = false; + if(module->get_bool_attribute("\\interfaces_replaced_in_module")) { // If 'interfaces' in the cell have not be been handled yet, there is no need to derive the sub-module either if (interfaces_in_module.count(interface_name) > 0) { // Check if the interface instance is present in module RTLIL::Module *mod_replace_ports = interfaces_in_module.at(interface_name); - for (auto &mod_wire : mod_replace_ports->wires_) { - std::string signal_name1 = conn.first.str() + "." + log_id(mod_wire.first); - std::string signal_name2 = interface_name.str() + "." + log_id(mod_wire.first); - connections_to_add_name.push_back(RTLIL::IdString(signal_name1)); - if(module->wires_.count(signal_name2) == 0) { - log_error("Could not find signal '%s' in '%s'\n", signal_name2.c_str(), log_id(module->name)); + for (auto &mod_wire : mod_replace_ports->wires_) { // Go over all wires in interface, and add replacements to lists. + std::string signal_name1 = conn.first.str() + "." + log_id(mod_wire.first); + std::string signal_name2 = interface_name.str() + "." + log_id(mod_wire.first); + connections_to_add_name.push_back(RTLIL::IdString(signal_name1)); + if(module->wires_.count(signal_name2) == 0) { + log_error("Could not find signal '%s' in '%s'\n", signal_name2.c_str(), log_id(module->name)); + } + else { + RTLIL::Wire *wire_in_parent = module->wire(signal_name2); + connections_to_add_signal.push_back(wire_in_parent); + } } - else { - RTLIL::Wire *wire_in_parent = module->wire(signal_name2); - connections_to_add_signal.push_back(wire_in_parent); + connections_to_remove.push_back(conn.first); + interfaces_to_add_to_submodule[conn.first] = interfaces_in_module.at(interface_name); + + // Add modports to a dict which will be passed to AstModule::derive + if (interface_modport != "") { + modports_used_in_submodule[conn.first] = interface_modport; } } - connections_to_remove.push_back(conn.first); - interfaces_to_add_to_submodule[conn.first] = interfaces_in_module.at(interface_name); - if (interface_modport != "") { - modports_used_in_submodule[conn.first] = interface_modport; - } - } - else will_do_step = true; + else not_found_interface = true; } - else will_do_step = true; + else not_found_interface = true; // If the interface instance has not already been derived in the module, we cannot complete at this stage. Set "has_interfaces_not_found" // which will delay the expansion of this cell: - if (will_do_step) { + if (not_found_interface) { // If we have already gone over all cells in this module, and the interface has still not been found - flag it as an error: if(!(module->get_bool_attribute("\\cells_not_processed"))) { log_warning("Could not find interface instance for `%s' in `%s'\n", log_id(interface_name), log_id(module)); @@ -348,13 +354,16 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check interfaces_in_module[cell->name] = derived_module; did_something = true; } - // We unset 'module_not_derived' such that we will not rederive the cell again (needed when there are interfaces connected to the cell) + // We clear 'module_not_derived' such that we will not rederive the cell again (needed when there are interfaces connected to the cell) cell->attributes.erase("\\module_not_derived"); } - // Setting a flag such that it can be known that we have been through all cells at least once, such that we can know whether to flag - // an error because of interface instances not found: + // Clear the attribute 'cells_not_processed' such that it can be known that we + // have been through all cells at least once, and that we can know whether + // to flag an error because of interface instances not found: module->attributes.erase("\\cells_not_processed"); + + // If any interface instances were found in the module, we need to rederive it completely: if (interfaces_in_module.size() > 0 && !module->get_bool_attribute("\\interfaces_replaced_in_module")) { module->reprocess_module(design, interfaces_in_module); return did_something; @@ -736,6 +745,7 @@ struct HierarchyPass : public Pass { } + // The top module might have changed if interface instances have been detected in it: RTLIL::Module *tmp_top_mod = check_if_top_has_changed(design, top_mod); if (tmp_top_mod != NULL) { if (tmp_top_mod != top_mod){ @@ -744,6 +754,7 @@ struct HierarchyPass : public Pass { } } + // Delete modules marked as 'to_delete': std::vector modules_to_delete; for(auto &mod_it : design->modules_) { if (mod_it.second->get_bool_attribute("\\to_delete")) { -- cgit v1.2.3