From 5c504c5ae676488f7e0b53f827f189fa7cacb2c8 Mon Sep 17 00:00:00 2001
From: Jim Lawson <ucbjrl@berkeley.edu>
Date: Fri, 15 Feb 2019 11:31:37 -0800
Subject: [PATCH 1/3] Define basic_cell_type() function and use it to derive
 the cell type for array references (instead of duplicating the code).

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

diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index 0e28dbca2..332ebdfbb 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -140,6 +140,23 @@ void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes,
 	}
 }
 
+// Return the "basic" type for an array item.
+std::string basic_cell_type(const std::string celltype, int pos[3] = nullptr) {
+	std::string basicType = celltype;
+	if (celltype.substr(0, 7) == "$array:") {
+		int pos_idx = celltype.find_first_of(':');
+		int pos_num = celltype.find_first_of(':', pos_idx + 1);
+		int pos_type = celltype.find_first_of(':', pos_num + 1);
+		basicType = celltype.substr(pos_type + 1);
+		if (pos != nullptr) {
+			pos[0] = pos_idx;
+			pos[1] = pos_num;
+			pos[2] = pos_type;
+		}
+	}
+	return basicType;
+}
+
 bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, bool flag_simcheck, std::vector<std::string> &libdirs)
 {
 	bool did_something = false;
@@ -178,9 +195,11 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
 		std::vector<RTLIL::SigSpec> connections_to_add_signal;
 
 		if (cell->type.substr(0, 7) == "$array:") {
-			int pos_idx = cell->type.str().find_first_of(':');
-			int pos_num = cell->type.str().find_first_of(':', pos_idx + 1);
-			int pos_type = cell->type.str().find_first_of(':', pos_num + 1);
+			int pos[3];
+			basic_cell_type(cell->type.str(), pos);
+			int pos_idx = pos[0];
+			int pos_num = pos[1];
+			int pos_type = pos[2];
 			int idx = atoi(cell->type.str().substr(pos_idx + 1, pos_num).c_str());
 			int num = atoi(cell->type.str().substr(pos_num + 1, pos_type).c_str());
 			array_cells[cell] = std::pair<int, int>(idx, num);
@@ -439,10 +458,7 @@ void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*, IdString::
 	for (auto cell : mod->cells()) {
 		std::string celltype = cell->type.str();
 		if (celltype.substr(0, 7) == "$array:") {
-			int pos_idx = celltype.find_first_of(':');
-			int pos_num = celltype.find_first_of(':', pos_idx + 1);
-			int pos_type = celltype.find_first_of(':', pos_num + 1);
-			celltype = celltype.substr(pos_type + 1);
+			celltype = basic_cell_type(celltype);
 		}
 		if (design->module(celltype))
 			hierarchy_worker(design, used, design->module(celltype), indent+4);
@@ -502,9 +518,23 @@ int find_top_mod_score(Design *design, Module *module, dict<Module*, int> &db)
 	if (db.count(module) == 0) {
 		int score = 0;
 		db[module] = 0;
-		for (auto cell : module->cells())
-			if (design->module(cell->type))
-				score = max(score, find_top_mod_score(design, design->module(cell->type), db) + 1);
+		for (auto cell : module->cells()) {
+			std::string celltype = cell->type.str();
+			// Is this an array instance
+			if (celltype.substr(0, 7) == "$array:") {
+				celltype = basic_cell_type(celltype);
+				// Is this cell is a module instance?
+				if (celltype[0] != '$') {
+					auto instModule = design->module(celltype);
+					// If there is no instance for this, issue a warning.
+					if (instModule == NULL) {
+						log_warning("find_top_mod_score: no instance for %s.%s\n", celltype.c_str(), cell->name.c_str());
+					}
+					if (instModule != NULL)
+						score = max(score, find_top_mod_score(design, instModule, db) + 1);
+				}
+			}
+		}
 		db[module] = score;
 	}
 	return db.at(module);

From 5c4a72c43ef61420b4b099d87949b0fdba0f4b55 Mon Sep 17 00:00:00 2001
From: Jim Lawson <ucbjrl@berkeley.edu>
Date: Tue, 19 Feb 2019 14:35:15 -0800
Subject: [PATCH 2/3] Fix normal (non-array) hierarchy -auto-top. Add simple
 test.

---
 passes/hierarchy/hierarchy.cc | 18 +++++------
 tests/various/hierarchy.sh    | 56 +++++++++++++++++++++++++++++++++++
 tests/various/run-test.sh     | 10 ++++++-
 3 files changed, 74 insertions(+), 10 deletions(-)
 create mode 100644 tests/various/hierarchy.sh

diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index 332ebdfbb..f112e969e 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -523,15 +523,15 @@ int find_top_mod_score(Design *design, Module *module, dict<Module*, int> &db)
 			// Is this an array instance
 			if (celltype.substr(0, 7) == "$array:") {
 				celltype = basic_cell_type(celltype);
-				// Is this cell is a module instance?
-				if (celltype[0] != '$') {
-					auto instModule = design->module(celltype);
-					// If there is no instance for this, issue a warning.
-					if (instModule == NULL) {
-						log_warning("find_top_mod_score: no instance for %s.%s\n", celltype.c_str(), cell->name.c_str());
-					}
-					if (instModule != NULL)
-						score = max(score, find_top_mod_score(design, instModule, db) + 1);
+			}
+			// Is this cell a module instance?
+			if (celltype[0] != '$') {
+				auto instModule = design->module(celltype);
+				// If there is no instance for this, issue a warning.
+				if (instModule == NULL) {
+					log_warning("find_top_mod_score: no instance for %s.%s\n", celltype.c_str(), cell->name.c_str());
+				} else {
+					score = max(score, find_top_mod_score(design, instModule, db) + 1);
 				}
 			}
 		}
diff --git a/tests/various/hierarchy.sh b/tests/various/hierarchy.sh
new file mode 100644
index 000000000..dcb4dc056
--- /dev/null
+++ b/tests/various/hierarchy.sh
@@ -0,0 +1,56 @@
+#!/usr/bin/env bash
+# Simple test of hierarchy -auto-top.
+
+set -e
+
+../../yosys -q -s - <<- EOY 2>&1 | grep "Automatically selected TOP as design top module"
+  read_verilog << EOV
+    module TOP(a, y);
+      input a;
+      output [31:0] y;
+
+      aoi12 p [31:0] (a, y);
+    endmodule
+
+    module aoi12(a, y);
+      input a;
+      output y;
+      assign y = ~a;
+    endmodule
+  EOV
+  hierarchy -auto-top
+EOY
+
+../../yosys -q -s - <<- EOY 2>&1 | grep "Automatically selected TOP as design top module"
+  read_verilog << EOV
+    module aoi12(a, y);
+      input a;
+      output y;
+      assign y = ~a;
+    endmodule
+
+    module TOP(a, y);
+      input a;
+      output [31:0] y;
+
+      aoi12 foo (a, y);
+    endmodule
+  EOV
+  hierarchy -auto-top
+EOY
+
+../../yosys -q -s - <<- EOY 2>&1 | grep "Automatically selected noTop as design top module."
+  read_verilog << EOV
+    module aoi12(a, y);
+      input a;
+      output y;
+      assign y = ~a;
+    endmodule
+
+    module noTop(a, y);
+      input a;
+      output [31:0] y;
+    endmodule
+  EOV
+  hierarchy -auto-top
+EOY
diff --git a/tests/various/run-test.sh b/tests/various/run-test.sh
index 67e1beb23..7cd1a8650 100755
--- a/tests/various/run-test.sh
+++ b/tests/various/run-test.sh
@@ -1,6 +1,14 @@
-#!/bin/bash
+#!/usr/bin/env bash
 set -e
 for x in *.ys; do
 	echo "Running $x.."
 	../../yosys -ql ${x%.ys}.log $x
 done
+# Run any .sh files in this directory (with the exception of the file - run-test.sh
+shell_tests=$(echo *.sh | sed -e 's/run-test.sh//')
+if [ "$shell_tests" ]; then
+    for s in $shell_tests; do
+        echo "Running $s.."
+        bash $s >& ${s%.sh}.log
+    done
+fi

From 71bcc4c644b0dafa760ff8b6d7bd1109836be621 Mon Sep 17 00:00:00 2001
From: Jim Lawson <ucbjrl@berkeley.edu>
Date: Fri, 22 Feb 2019 16:06:10 -0800
Subject: [PATCH 3/3] Address requested changes - don't require non-$ name.
 Suppress warning if name does begin with a `$`. Fix hierachy tests so they
 have something to grep. Announce hierarchy test types.

---
 passes/hierarchy/hierarchy.cc | 14 +++++++-------
 tests/various/hierarchy.sh    |  9 ++++++---
 tests/various/run-test.sh     |  2 +-
 3 files changed, 14 insertions(+), 11 deletions(-)

diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index f112e969e..cb54ffa58 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -525,14 +525,14 @@ int find_top_mod_score(Design *design, Module *module, dict<Module*, int> &db)
 				celltype = basic_cell_type(celltype);
 			}
 			// Is this cell a module instance?
-			if (celltype[0] != '$') {
-				auto instModule = design->module(celltype);
-				// If there is no instance for this, issue a warning.
-				if (instModule == NULL) {
+			auto instModule = design->module(celltype);
+			// If there is no instance for this, issue a warning.
+			if (instModule == NULL) {
+				//  but only if we're sure it is a reference to a module.
+				if (celltype[0] != '$')
 					log_warning("find_top_mod_score: no instance for %s.%s\n", celltype.c_str(), cell->name.c_str());
-				} else {
-					score = max(score, find_top_mod_score(design, instModule, db) + 1);
-				}
+			} else {
+				score = max(score, find_top_mod_score(design, instModule, db) + 1);
 			}
 		}
 		db[module] = score;
diff --git a/tests/various/hierarchy.sh b/tests/various/hierarchy.sh
index dcb4dc056..d33a247be 100644
--- a/tests/various/hierarchy.sh
+++ b/tests/various/hierarchy.sh
@@ -3,7 +3,8 @@
 
 set -e
 
-../../yosys -q -s - <<- EOY 2>&1 | grep "Automatically selected TOP as design top module"
+echo -n "  TOP first - "
+../../yosys -s - <<- EOY | grep "Automatically selected TOP as design top module"
   read_verilog << EOV
     module TOP(a, y);
       input a;
@@ -21,7 +22,8 @@ set -e
   hierarchy -auto-top
 EOY
 
-../../yosys -q -s - <<- EOY 2>&1 | grep "Automatically selected TOP as design top module"
+echo -n "  TOP last - "
+../../yosys -s - <<- EOY | grep "Automatically selected TOP as design top module"
   read_verilog << EOV
     module aoi12(a, y);
       input a;
@@ -39,7 +41,8 @@ EOY
   hierarchy -auto-top
 EOY
 
-../../yosys -q -s - <<- EOY 2>&1 | grep "Automatically selected noTop as design top module."
+echo -n "  no explicit top - "
+../../yosys -s - <<- EOY | grep "Automatically selected noTop as design top module."
   read_verilog << EOV
     module aoi12(a, y);
       input a;
diff --git a/tests/various/run-test.sh b/tests/various/run-test.sh
index 7cd1a8650..d49553ede 100755
--- a/tests/various/run-test.sh
+++ b/tests/various/run-test.sh
@@ -9,6 +9,6 @@ shell_tests=$(echo *.sh | sed -e 's/run-test.sh//')
 if [ "$shell_tests" ]; then
     for s in $shell_tests; do
         echo "Running $s.."
-        bash $s >& ${s%.sh}.log
+        bash $s
     done
 fi