diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index e79be953a..256c08776 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -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;
 }
 
diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h
index 7e97bdb3b..6b93832b4 100644
--- a/frontends/ast/ast.h
+++ b/frontends/ast/ast.h
@@ -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;
 	};
 
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index c9345ff08..1dd1a9130 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -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;
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index 71eba547c..2a561ea5f 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -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;
diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l
index 83921bf0b..8808c2675 100644
--- a/frontends/verilog/verilog_lexer.l
+++ b/frontends/verilog/verilog_lexer.l
@@ -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) {
diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y
index 16cac1460..0ff5d576e 100644
--- a/frontends/verilog/verilog_parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -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)
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index a4fa2cf04..fadac0872 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -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);
diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index 027faf416..8a2b0a4f3 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -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();
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<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,14 +296,58 @@ 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)
 	{
@@ -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
index 000000000..779d50c14
--- /dev/null
+++ b/tests/simple/svinterface1.sv
@@ -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