From 1fdb3fc98cdbd7126f07778397e3c334f45945df Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Wed, 28 Aug 2019 19:58:58 -0700
Subject: [PATCH 1/9] Add failing test

---
 tests/various/hierarchy_defer.ys | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
 create mode 100644 tests/various/hierarchy_defer.ys

diff --git a/tests/various/hierarchy_defer.ys b/tests/various/hierarchy_defer.ys
new file mode 100644
index 000000000..170bb8c5f
--- /dev/null
+++ b/tests/various/hierarchy_defer.ys
@@ -0,0 +1,18 @@
+read -vlog2k <<EOT
+module first;
+endmodule
+
+(* top *)
+module top(input i, output o);
+sub s0(i, o);
+endmodule
+
+module sub(input i, output o);
+assign o = ~i;
+endmodule
+EOT
+
+hierarchy -auto-top
+select -assert-any top
+select -assert-any sub
+select -assert-none foo

From 34ae29295db53289e786c0279ed00474cf0294d3 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Wed, 28 Aug 2019 19:59:09 -0700
Subject: [PATCH 2/9] read_verilog -defer should still populate module
 attributes

---
 frontends/ast/ast.cc | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index 82283fb5b..6a91c418b 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -1073,11 +1073,6 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
 
 		ignoreThisSignalsInInitial = RTLIL::SigSpec();
 
-		for (auto &attr : ast->attributes) {
-			if (attr.second->type != AST_CONSTANT)
-				log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
-			current_module->attributes[attr.first] = attr.second->asAttrConst();
-		}
 		for (size_t i = 0; i < ast->children.size(); i++) {
 			AstNode *node = ast->children[i];
 			if (node->type == AST_WIRE || node->type == AST_MEMORY)
@@ -1100,6 +1095,12 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
 		ignoreThisSignalsInInitial = RTLIL::SigSpec();
 	}
 
+	for (auto &attr : ast->attributes) {
+		if (attr.second->type != AST_CONSTANT)
+			log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
+		current_module->attributes[attr.first] = attr.second->asAttrConst();
+	}
+
 	if (ast->type == AST_INTERFACE)
 		current_module->set_bool_attribute("\\is_interface");
 	current_module->ast = ast_before_simplify;

From 116c2496011aeeac9847d69af597a0db58209793 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Wed, 28 Aug 2019 19:59:25 -0700
Subject: [PATCH 3/9] -auto-top should check $abstract (deferred) modules with
 (* top *)

---
 passes/hierarchy/hierarchy.cc | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index fd95b94b2..ad795c69f 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -808,6 +808,37 @@ struct HierarchyPass : public Pass {
 				if (mod_it.second->get_bool_attribute("\\top"))
 					top_mod = mod_it.second;
 
+		if (top_mod != nullptr && auto_top_mode) {
+			IdString abstract_id = top_mod->name;
+			IdString top_name = abstract_id;
+			if (top_name.begins_with("$abstract"))
+				top_name = top_name.substr(strlen("$abstract"));
+			top_mod = design->module(top_name);
+
+			dict<RTLIL::IdString, RTLIL::Const> top_parameters;
+			for (auto &para : parameters) {
+				SigSpec sig_value;
+				if (!RTLIL::SigSpec::parse(sig_value, NULL, para.second))
+					log_cmd_error("Can't decode value '%s'!\n", para.second.c_str());
+				top_parameters[RTLIL::escape_id(para.first)] = sig_value.as_const();
+			}
+
+			if (top_mod == nullptr && design->module(abstract_id))
+				top_mod = design->module(design->module(abstract_id)->derive(design, top_parameters));
+			else if (top_mod != nullptr && !top_parameters.empty())
+				top_mod = design->module(top_mod->derive(design, top_parameters));
+
+			if (top_mod != nullptr && top_mod->name != top_name) {
+				Module *m = top_mod->clone();
+				m->name = top_name;
+				Module *old_mod = design->module(top_name);
+				if (old_mod)
+					design->remove(old_mod);
+				design->add(m);
+				top_mod = m;
+			}
+		}
+
 		if (top_mod == nullptr && auto_top_mode) {
 			log_header(design, "Finding top of design hierarchy..\n");
 			dict<Module*, int> db;

From 6510297712729f9742d00f6a4cd4fc3a0e530758 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Thu, 29 Aug 2019 09:02:10 -0700
Subject: [PATCH 4/9] Restore non-deferred code, deferred case to ignore non
 constant attr

---
 frontends/ast/ast.cc | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index 6a91c418b..01e865557 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -1073,6 +1073,12 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
 
 		ignoreThisSignalsInInitial = RTLIL::SigSpec();
 
+		for (auto &attr : ast->attributes) {
+			if (attr.second->type != AST_CONSTANT)
+				log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
+			current_module->attributes[attr.first] = attr.second->asAttrConst();
+		}
+
 		for (size_t i = 0; i < ast->children.size(); i++) {
 			AstNode *node = ast->children[i];
 			if (node->type == AST_WIRE || node->type == AST_MEMORY)
@@ -1094,11 +1100,12 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
 
 		ignoreThisSignalsInInitial = RTLIL::SigSpec();
 	}
-
-	for (auto &attr : ast->attributes) {
-		if (attr.second->type != AST_CONSTANT)
-			log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
-		current_module->attributes[attr.first] = attr.second->asAttrConst();
+	else {
+		for (auto &attr : ast->attributes) {
+			if (attr.second->type != AST_CONSTANT)
+				continue;
+			current_module->attributes[attr.first] = attr.second->asAttrConst();
+		}
 	}
 
 	if (ast->type == AST_INTERFACE)

From 83ffec26cbda434b31a2bbd004213a538bf3e6e6 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Thu, 29 Aug 2019 09:08:58 -0700
Subject: [PATCH 5/9] Remove newline

---
 frontends/ast/ast.cc | 1 -
 1 file changed, 1 deletion(-)

diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index 01e865557..a3a78e414 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -1078,7 +1078,6 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
 				log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
 			current_module->attributes[attr.first] = attr.second->asAttrConst();
 		}
-
 		for (size_t i = 0; i < ast->children.size(); i++) {
 			AstNode *node = ast->children[i];
 			if (node->type == AST_WIRE || node->type == AST_MEMORY)

From 67587bad7fb1adf14ca9598bb1a01d0ffda6a018 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Thu, 29 Aug 2019 09:10:20 -0700
Subject: [PATCH 6/9] Add constant expression attribute to test

---
 tests/various/hierarchy_defer.ys | 1 +
 1 file changed, 1 insertion(+)

diff --git a/tests/various/hierarchy_defer.ys b/tests/various/hierarchy_defer.ys
index 170bb8c5f..0bf4de44e 100644
--- a/tests/various/hierarchy_defer.ys
+++ b/tests/various/hierarchy_defer.ys
@@ -7,6 +7,7 @@ module top(input i, output o);
 sub s0(i, o);
 endmodule
 
+(* constant_expression=1+1?2*2:3/3 *)
 module sub(input i, output o);
 assign o = ~i;
 endmodule

From 81247168302a578add43e3e856eb74868dc5a1ba Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Tue, 3 Sep 2019 10:52:34 -0700
Subject: [PATCH 7/9] Add `read -noverific` before read

---
 tests/various/hierarchy_defer.ys | 1 +
 1 file changed, 1 insertion(+)

diff --git a/tests/various/hierarchy_defer.ys b/tests/various/hierarchy_defer.ys
index 0bf4de44e..baec52c9d 100644
--- a/tests/various/hierarchy_defer.ys
+++ b/tests/various/hierarchy_defer.ys
@@ -1,3 +1,4 @@
+read -noverific
 read -vlog2k <<EOT
 module first;
 endmodule

From 0ca070663091ec0eecd089801f37339feb7813c8 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Tue, 3 Sep 2019 12:17:26 -0700
Subject: [PATCH 8/9] Expand test with `hierarchy' without -auto-top

---
 tests/various/hierarchy_defer.ys | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/tests/various/hierarchy_defer.ys b/tests/various/hierarchy_defer.ys
index baec52c9d..70f5b70a3 100644
--- a/tests/various/hierarchy_defer.ys
+++ b/tests/various/hierarchy_defer.ys
@@ -13,8 +13,15 @@ module sub(input i, output o);
 assign o = ~i;
 endmodule
 EOT
+design -save read
 
 hierarchy -auto-top
 select -assert-any top
 select -assert-any sub
 select -assert-none foo
+
+design -load read
+hierarchy
+select -assert-any top
+select -assert-any sub
+select -assert-none foo

From d2306d7b1d9725fef2d1db4e205c1b0cb6c84715 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Tue, 3 Sep 2019 12:18:50 -0700
Subject: [PATCH 9/9] Adopt @cliffordwolf's suggestion

---
 passes/hierarchy/hierarchy.cc | 13 +++----------
 1 file changed, 3 insertions(+), 10 deletions(-)

diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index ad795c69f..d8a628448 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -808,12 +808,8 @@ struct HierarchyPass : public Pass {
 				if (mod_it.second->get_bool_attribute("\\top"))
 					top_mod = mod_it.second;
 
-		if (top_mod != nullptr && auto_top_mode) {
-			IdString abstract_id = top_mod->name;
-			IdString top_name = abstract_id;
-			if (top_name.begins_with("$abstract"))
-				top_name = top_name.substr(strlen("$abstract"));
-			top_mod = design->module(top_name);
+		if (top_mod != nullptr && top_mod->name.begins_with("$abstract")) {
+			IdString top_name = top_mod->name.substr(strlen("$abstract"));
 
 			dict<RTLIL::IdString, RTLIL::Const> top_parameters;
 			for (auto &para : parameters) {
@@ -823,10 +819,7 @@ struct HierarchyPass : public Pass {
 				top_parameters[RTLIL::escape_id(para.first)] = sig_value.as_const();
 			}
 
-			if (top_mod == nullptr && design->module(abstract_id))
-				top_mod = design->module(design->module(abstract_id)->derive(design, top_parameters));
-			else if (top_mod != nullptr && !top_parameters.empty())
-				top_mod = design->module(top_mod->derive(design, top_parameters));
+			top_mod = design->module(top_mod->derive(design, top_parameters));
 
 			if (top_mod != nullptr && top_mod->name != top_name) {
 				Module *m = top_mod->clone();