Synthesis support for SystemVerilog interfaces
authorRuben Undheim <ruben.undheim@gmail.com>
Thu, 11 Oct 2018 21:33:31 +0000 (23:33 +0200)
committerRuben Undheim <ruben.undheim@gmail.com>
Fri, 12 Oct 2018 19:11:36 +0000 (21:11 +0200)
This time doing the changes mostly in AST before RTLIL generation

frontends/ast/ast.cc
frontends/ast/ast.h
frontends/ast/genrtlil.cc
frontends/ast/simplify.cc
frontends/verilog/verilog_lexer.l
frontends/verilog/verilog_parser.y
kernel/rtlil.cc
kernel/rtlil.h
passes/hierarchy/hierarchy.cc
tests/simple/svinterface1.sv [new file with mode: 0644]

index e79be953accce78c9871acf8c0f8fb0736a393b3..256c08776b0c2970dddbf5bfc6b3caf063f59785 100644 (file)
@@ -905,7 +905,7 @@ RTLIL::Const AstNode::realAsConst(int width)
 // create a new AstModule from an AST_MODULE AST node
 static AstModule* process_module(AstNode *ast, bool defer)
 {
-       log_assert(ast->type == AST_MODULE);
+       log_assert(ast->type == AST_MODULE || ast->type == AST_INTERFACE);
 
        if (defer)
                log("Storing AST representation for module `%s'.\n", ast->str.c_str());
@@ -916,6 +916,7 @@ static AstModule* process_module(AstNode *ast, bool defer)
        current_module->ast = NULL;
        current_module->name = ast->str;
        current_module->attributes["\\src"] = stringf("%s:%d", ast->filename.c_str(), ast->linenum);
+       current_module->set_bool_attribute("\\cells_not_processed");
 
        current_ast_mod = ast;
        AstNode *ast_before_simplify = ast->clone();
@@ -989,6 +990,8 @@ static AstModule* process_module(AstNode *ast, bool defer)
                ignoreThisSignalsInInitial = RTLIL::SigSpec();
        }
 
+       if (ast->type == AST_INTERFACE)
+               current_module->set_bool_attribute("\\is_interface");
        current_module->ast = ast_before_simplify;
        current_module->nolatches = flag_nolatches;
        current_module->nomeminit = flag_nomeminit;
@@ -1031,7 +1034,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
        log_assert(current_ast->type == AST_DESIGN);
        for (auto it = current_ast->children.begin(); it != current_ast->children.end(); it++)
        {
-               if ((*it)->type == AST_MODULE)
+               if ((*it)->type == AST_MODULE || (*it)->type == AST_INTERFACE)
                {
                        for (auto n : design->verilog_globals)
                                (*it)->children.push_back(n->clone());
@@ -1083,8 +1086,123 @@ AstModule::~AstModule()
                delete ast;
 }
 
+void AstModule::reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module*> local_interfaces)
+{
+       bool is_top = false;
+       AstNode *new_ast = ast->clone();
+       for (auto &intf : local_interfaces) {
+               std::string intfname = intf.first.str();
+               RTLIL::Module *intfmodule = intf.second;
+               for (auto &wire_it : intfmodule->wires_){
+                       AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(wire_it.second->width -1, true), AstNode::mkconst_int(0, true)));
+                       std::string newname = log_id(wire_it.first);
+                       newname = intfname + "." + newname;
+                       wire->str = newname;
+                       new_ast->children.push_back(wire);
+               }
+       }
+       std::string original_name = this->name.str();
+       std::string changed_name = original_name + "_before_replacing_local_interfaces";
+       design->rename(this, changed_name);
+       this->set_bool_attribute("\\to_delete");
+       if (this->get_bool_attribute("\\initial_top")) {
+               this->attributes.erase("\\initial_top");
+               is_top = true;
+       }
+       AstModule *newmod = process_module(new_ast, false);
+       design->add(newmod);
+       RTLIL::Module* mod = design->module(original_name);
+       if (is_top)
+               mod->set_bool_attribute("\\top");
+       mod->set_bool_attribute("\\interfaces_replaced_in_module");
+}
+
+// create a new parametric module (when needed) and return the name of the generated module - WITH support for interfaces
+RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, bool mayfail)
+{
+       AstNode *new_ast = NULL;
+       std::string modname = derive_common(design, parameters, &new_ast, mayfail);
+
+       // Since interfaces themselves may be instantiated with different parameters,
+       // "modname" must also take those into account, so that unique modules
+       // are derived for any variant of interface connections:
+       std::string interf_info = "";
+
+       bool has_interfaces = false;
+       for(auto &intf : interfaces) {
+               interf_info += log_id(intf.second->name);
+               has_interfaces = true;
+       }
+
+       if (has_interfaces)
+               modname += "$interfaces$" + interf_info;
+
+
+       if (!design->has(modname)) {
+               new_ast->str = modname;
+               for(auto &intf : interfaces) {
+                       RTLIL::Module * intfmodule = intf.second;
+                       std::string intfname = intf.first.str();
+                       for (auto &wire_it : intfmodule->wires_){
+                               AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(wire_it.second->width -1, true), AstNode::mkconst_int(0, true)));
+                               std::string origname = log_id(wire_it.first);
+                               std::string newname = intfname + "." + origname;
+                               wire->str = newname;
+                               wire->is_input = true;
+                               wire->is_output = true;
+                               new_ast->children.push_back(wire);
+                       }
+               }
+
+               design->add(process_module(new_ast, false));
+               design->module(modname)->check();
+
+               RTLIL::Module* mod = design->module(modname);
+
+               for(auto &intf : interfaces) {
+                       if(mod->wires_.count(intf.first)) {
+                               mod->wires_.erase(intf.first);
+                               mod->fixup_ports();
+                               RTLIL::Cell * new_subcell = mod->addCell(intf.first, intf.second->name);
+                               new_subcell->set_bool_attribute("\\is_interface");
+                       }
+                       else {
+                               log_error("No port with matching name found (%s) in %s. Stopping\n", log_id(intf.first), modname);
+                       }
+               }
+
+               if (interfaces.size() > 0) {
+                       mod->set_bool_attribute("\\interfaces_replaced_in_module");
+               }
+
+       } else {
+               log("Found cached RTLIL representation for module `%s'.\n", modname.c_str());
+       }
+
+       delete new_ast;
+       return modname;
+}
+
+// create a new parametric module (when needed) and return the name of the generated module - without support for interfaces
+RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail)
+{
+       AstNode *new_ast = NULL;
+       std::string modname = derive_common(design, parameters, &new_ast, mayfail);
+
+       if (!design->has(modname)) {
+               new_ast->str = modname;
+               design->add(process_module(new_ast, false));
+               design->module(modname)->check();
+       } else {
+               log("Found cached RTLIL representation for module `%s'.\n", modname.c_str());
+       }
+
+       delete new_ast;
+       return modname;
+}
+
 // create a new parametric module (when needed) and return the name of the generated module
-RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool)
+std::string AstModule::derive_common(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, AstNode **new_ast_out, bool)
 {
        std::string stripped_name = name.str();
 
@@ -1156,15 +1274,8 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, R
        else
                modname = "$paramod" + stripped_name + para_info;
 
-       if (!design->has(modname)) {
-               new_ast->str = modname;
-               design->add(process_module(new_ast, false));
-               design->module(modname)->check();
-       } else {
-               log("Found cached RTLIL representation for module `%s'.\n", modname.c_str());
-       }
 
-       delete new_ast;
+       (*new_ast_out) = new_ast;
        return modname;
 }
 
index 7e97bdb3bdb3ebf1b23cb4344a6460d3c1c0bfe0..6b93832b42e74e9bba7cc71e674fdc7f2185e489 100644 (file)
@@ -142,6 +142,9 @@ namespace AST
                AST_NEGEDGE,
                AST_EDGE,
 
+               AST_INTERFACE,
+               AST_INTERFACEPORT,
+               AST_INTERFACEPORTTYPE,
                AST_PACKAGE
        };
 
@@ -284,6 +287,9 @@ namespace AST
                bool nolatches, nomeminit, nomem2reg, mem2reg, lib, noopt, icells, autowire;
                ~AstModule() YS_OVERRIDE;
                RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail) YS_OVERRIDE;
+               RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, bool mayfail) YS_OVERRIDE;
+               std::string derive_common(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, AstNode **new_ast_out, bool mayfail);
+               void reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module *> local_interfaces) YS_OVERRIDE;
                RTLIL::Module *clone() const YS_OVERRIDE;
        };
 
index c9345ff081a2a74efcf9e2598e5068d324108642..1dd1a913090fc686601c96812c50e795b9b33e05 100644 (file)
@@ -854,6 +854,22 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
        case AST_GENCASE:
        case AST_PACKAGE:
                break;
+       case AST_INTERFACEPORT: {
+               // If a port in a module with unknown type is found, mark it as "is_interface=true"
+               // This is used by the hierarchy pass to know when it can replace interface connection with the individual
+               // signals.
+               RTLIL::Wire *wire = current_module->addWire(str, 1);
+               wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
+               wire->start_offset = 0;
+               wire->port_id = port_id;
+               wire->port_input = true;
+               wire->port_output = true;
+               wire->set_bool_attribute("\\is_interface");
+               wire->upto = 0;
+               }
+               break;
+       case AST_INTERFACEPORTTYPE:
+               break;
 
        // remember the parameter, needed for example in techmap
        case AST_PARAMETER:
@@ -949,6 +965,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
                {
                        RTLIL::Wire *wire = NULL;
                        RTLIL::SigChunk chunk;
+                       bool is_interface = false;
 
                        int add_undef_bits_msb = 0;
                        int add_undef_bits_lsb = 0;
@@ -969,15 +986,41 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
                                chunk = RTLIL::Const(id2ast->children[0]->bits);
                                goto use_const_chunk;
                        }
-                       else if (!id2ast || (id2ast->type != AST_WIRE && id2ast->type != AST_AUTOWIRE &&
-                                       id2ast->type != AST_MEMORY) || current_module->wires_.count(str) == 0)
+                       else if (id2ast && (id2ast->type == AST_WIRE || id2ast->type == AST_AUTOWIRE || id2ast->type == AST_MEMORY) && current_module->wires_.count(str) != 0) {
+                               RTLIL::Wire *current_wire = current_module->wire(str);
+                               if (current_wire->get_bool_attribute("\\is_interface"))
+                                       is_interface = true;
+                               // Ignore
+                       }
+                       // If an identifier is found that is not already known, assume that it is an interface:
+                       else if (1) { // FIXME: Check if sv_mode first?
+                               is_interface = true;
+                       }
+                       else {
                                log_file_error(filename, linenum, "Identifier `%s' doesn't map to any signal!\n",
                                                str.c_str());
+                       }
 
                        if (id2ast->type == AST_MEMORY)
                                log_file_error(filename, linenum, "Identifier `%s' does map to an unexpanded memory!\n",
                                               str.c_str());
 
+                       // If identifier is an interface, create a RTLIL::SigSpec object and set is_interface to true.
+                       // This makes it possible for the hierarchy pass to see what are interface connections and then replace them
+                       // with the individual signals:
+                       if (is_interface) {
+                               RTLIL::Wire *dummy_wire;
+                               std::string dummy_wire_name = "$dummywireforinterface" + str;
+                               if (current_module->wires_.count(dummy_wire_name))
+                                       dummy_wire = current_module->wires_[dummy_wire_name];
+                               else {
+                                       dummy_wire = current_module->addWire(dummy_wire_name);
+                                       dummy_wire->set_bool_attribute("\\is_interface");
+                               }
+                               RTLIL::SigSpec tmp = RTLIL::SigSpec(dummy_wire);
+                               return tmp;
+                       }
+
                        wire = current_module->wires_[str];
                        chunk.wire = wire;
                        chunk.width = wire->width;
@@ -1423,6 +1466,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
 
                        RTLIL::Cell *cell = current_module->addCell(str, "");
                        cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
+                       cell->set_bool_attribute("\\module_not_derived");
 
                        for (auto it = children.begin(); it != children.end(); it++) {
                                AstNode *child = *it;
index 71eba547c33068e3114daa2a648e0466e68d31fa..2a561ea5fdb08cebc1b63a995fc83593bd4473a8 100644 (file)
@@ -71,7 +71,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
 
        if (stage == 0)
        {
-               log_assert(type == AST_MODULE);
+               log_assert(type == AST_MODULE || type == AST_INTERFACE);
                last_blocking_assignment_warn = pair<string, int>();
 
                deep_recursion_warning = true;
index 83921bf0be893641d42afc3e3a2bc3fee5d4c1cd..8808c2675cc27e829a89f95f76b39db536b727d7 100644 (file)
@@ -150,6 +150,9 @@ YOSYS_NAMESPACE_END
 "specparam"    { return TOK_SPECPARAM; }
 "package"      { SV_KEYWORD(TOK_PACKAGE); }
 "endpackage"   { SV_KEYWORD(TOK_ENDPACKAGE); }
+"interface"    { SV_KEYWORD(TOK_INTERFACE); }
+"endinterface" { SV_KEYWORD(TOK_ENDINTERFACE); }
+"modport"      { SV_KEYWORD(TOK_MODPORT); }
 "parameter"    { return TOK_PARAMETER; }
 "localparam"   { return TOK_LOCALPARAM; }
 "defparam"     { return TOK_DEFPARAM; }
@@ -295,6 +298,11 @@ supply1 { return TOK_SUPPLY1; }
        return TOK_ID;
 }
 
+[a-zA-Z_$][a-zA-Z0-9_$\.]* {
+       frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext);
+    return TOK_ID;
+}
+
 "/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" {
        static bool printed_warning = false;
        if (!printed_warning) {
index 16cac14609db3dcdc25707b196fbc60c5d4ff63e..0ff5d576e0d1b3286f677a2fad092000291ca98a 100644 (file)
@@ -106,6 +106,7 @@ static void free_attr(std::map<std::string, AstNode*> *al)
 %token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
 %token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
 %token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP
+%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT
 %token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG TOK_LOGIC
 %token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL
 %token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT
@@ -168,6 +169,7 @@ design:
        param_decl design |
        localparam_decl design |
        package design |
+       interface design |
        /* empty */;
 
 attr:
@@ -320,6 +322,21 @@ module_arg:
                }
                delete $1;
        } module_arg_opt_assignment |
+       TOK_ID {
+               astbuf1 = new AstNode(AST_INTERFACEPORT);
+               astbuf1->children.push_back(new AstNode(AST_INTERFACEPORTTYPE));
+               astbuf1->children[0]->str = *$1;
+               delete $1;
+       } TOK_ID {  /* SV interfaces */
+               if (!sv_mode)
+                       frontend_verilog_yyerror("Interface found in port list (%s). This is not supported unless read_verilog is called with -sv!", $3->c_str());
+               astbuf2 = astbuf1->clone(); // really only needed if multiple instances of same type.
+               astbuf2->str = *$3;
+               delete $3;
+               astbuf2->port_id = ++port_counter;
+               ast_stack.back()->children.push_back(astbuf2);
+               delete astbuf1; // really only needed if multiple instances of same type.
+       } module_arg_opt_assignment |
        attr wire_type range TOK_ID {
                AstNode *node = $2;
                node->str = *$4;
@@ -357,6 +374,33 @@ package_body:
 package_body_stmt:
        localparam_decl;
 
+interface:
+       TOK_INTERFACE TOK_ID {
+               do_not_require_port_stubs = false;
+               AstNode *intf = new AstNode(AST_INTERFACE);
+               ast_stack.back()->children.push_back(intf);
+               ast_stack.push_back(intf);
+               current_ast_mod = intf;
+               port_stubs.clear();
+               port_counter = 0;
+               intf->str = *$2;
+               delete $2;
+       } module_para_opt module_args_opt ';' interface_body TOK_ENDINTERFACE {
+               if (port_stubs.size() != 0)
+                       frontend_verilog_yyerror("Missing details for module port `%s'.",
+                               port_stubs.begin()->first.c_str());
+               ast_stack.pop_back();
+               log_assert(ast_stack.size() == 1);
+               current_ast_mod = NULL;
+       };
+
+interface_body:
+       interface_body interface_body_stmt |;
+
+interface_body_stmt:
+       param_decl | localparam_decl | defparam_decl | wire_decl | always_stmt | assign_stmt |
+       modport_stmt;
+
 non_opt_delay:
        '#' TOK_ID { delete $2; } |
        '#' TOK_CONSTVAL { delete $2; } |
@@ -1280,6 +1324,22 @@ opt_property:
 opt_stmt_label:
        TOK_ID ':' | /* empty */;
 
+modport_stmt:
+    TOK_MODPORT TOK_ID modport_args_opt ';'
+
+modport_args_opt:
+    '(' ')' | '(' modport_args optional_comma ')';
+
+modport_args:
+    modport_arg | modport_args ',' modport_arg;
+
+modport_arg:
+    modport_type_token TOK_ID |
+    TOK_ID
+
+modport_type_token:
+    TOK_INPUT | TOK_OUTPUT
+
 assert:
        opt_stmt_label TOK_ASSERT opt_property '(' expr ')' ';' {
                if (noassert_mode)
index a4fa2cf047224d57a13615a7e723f73b9d210cd7..fadac087228d317ca164d4b4cdd0a073b756d4eb 100644 (file)
@@ -639,6 +639,13 @@ RTLIL::Module::~Module()
                delete it->second;
 }
 
+void RTLIL::Module::reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module *> local_interfaces)
+{
+       log_error("Cannot reprocess_module module `%s' !\n", id2cstr(name));
+       (void)local_interfaces; // To remove build warning
+       (void)design;           // To remove build warning
+}
+
 RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, dict<RTLIL::IdString, RTLIL::Const>, bool mayfail)
 {
        if (mayfail)
@@ -646,6 +653,14 @@ RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, dict<RTLIL::IdString, RTLI
        log_error("Module `%s' is used with parameters but is not parametric!\n", id2cstr(name));
 }
 
+
+RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, dict<RTLIL::IdString, RTLIL::Const>, dict<RTLIL::IdString, RTLIL::Module*> , bool mayfail)
+{
+       if (mayfail)
+               return RTLIL::IdString();
+       log_error("Module `%s' is used with parameters but is not parametric!\n", id2cstr(name));
+}
+
 size_t RTLIL::Module::count_id(RTLIL::IdString id)
 {
        return wires_.count(id) + memories.count(id) + cells_.count(id) + processes.count(id);
index 027faf416e2b468072932143044e960f3fe191c2..8a2b0a4f3e7660df00009d633410c9c93d610bb9 100644 (file)
@@ -907,7 +907,9 @@ public:
        Module();
        virtual ~Module();
        virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail = false);
+       virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, bool mayfail = false);
        virtual size_t count_id(RTLIL::IdString id);
+       virtual void reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module *> local_interfaces);
 
        virtual void sort();
        virtual void check();
index 5df69848e490afaed4ff2742250146591b946a6f..dd43411272811d37307555442b4f7983112cc807 100644 (file)
@@ -145,9 +145,24 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
        std::map<RTLIL::Cell*, std::pair<int, int>> array_cells;
        std::string filename;
 
+       dict<RTLIL::IdString, RTLIL::Module*> 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<RTLIL::IdString> connections_to_remove;
+               std::vector<RTLIL::IdString> connections_to_add_name;
+               std::vector<RTLIL::SigSpec> 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<int, int>(idx, num);
                        cell->type = cell->type.str().substr(pos_type + 1);
                }
+               dict<RTLIL::IdString, RTLIL::Module*> 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 &param : 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;i<connections_to_add_name.size();i++) {
+                       cell->connections_[connections_to_add_name[i]] = connections_to_add_signal[i];
+               }
+               // Remove the connection for the interface itself:
+               for(unsigned int i=0;i<connections_to_remove.size();i++) {
+                       cell->connections_.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<Module*, int> &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<RTLIL::Module *> 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; i<modules_to_delete.size(); i++) {
+                               design->remove(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) {
diff --git a/tests/simple/svinterface1.sv b/tests/simple/svinterface1.sv
new file mode 100644 (file)
index 0000000..779d50c
--- /dev/null
@@ -0,0 +1,76 @@
+
+
+module TopModule(
+    input logic clk,
+    input logic rst,
+    input logic [1:0] sig,
+    output logic [1:0] sig_out);
+
+  MyInterface #(.WIDTH(4)) MyInterfaceInstance();
+
+  SubModule1 u_SubModule1 (
+    .clk(clk),
+    .rst(rst),
+    .u_MyInterface(MyInterfaceInstance),
+    .sig (sig)
+  );
+
+  assign sig_out = MyInterfaceInstance.mysig_out;
+
+
+  assign MyInterfaceInstance.setting = 1;
+  assign MyInterfaceInstance.other_setting[2:0] = 3'b101;
+
+endmodule
+
+interface MyInterface #(
+  parameter WIDTH = 3)(
+  );
+
+  logic setting;
+  logic [WIDTH-1:0] other_setting;
+
+  logic [1:0] mysig_out;
+
+endinterface
+
+
+module SubModule1(
+    input logic clk,
+    input logic rst,
+    MyInterface u_MyInterface,
+    input logic [1:0] sig
+
+  );
+
+  always_ff @(posedge clk or posedge rst)
+    if(rst)
+      u_MyInterface.mysig_out <= 0;
+    else begin
+      if(u_MyInterface.setting)
+        u_MyInterface.mysig_out <= sig;
+      else
+        u_MyInterface.mysig_out <= ~sig;
+    end
+
+  MyInterface #(.WIDTH(22)) MyInterfaceInstanceInSub();
+
+  SubModule2 u_SubModule2 (
+    .clk(clk),
+    .rst(rst),
+    .u_MyInterfaceInSub2(u_MyInterface),
+    .sig (sig)
+  );
+
+endmodule
+
+module SubModule2(
+
+    input logic clk,
+    input logic rst,
+    MyInterface u_MyInterfaceInSub2,
+    input logic [1:0] sig
+
+  );
+
+endmodule