From 6d64e242ba8214f7bceb35f688b544f56d49cea1 Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Wed, 19 Jun 2019 11:25:11 +0200
Subject: [PATCH 1/4] Fix handling of "logic" variables with initial value

Signed-off-by: Clifford Wolf <clifford@clifford.at>
---
 frontends/verilog/verilog_parser.y | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y
index ea8e457e8..5f3d713d3 100644
--- a/frontends/verilog/verilog_parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -345,7 +345,7 @@ module_arg_opt_assignment:
 		if (ast_stack.back()->children.size() > 0 && ast_stack.back()->children.back()->type == AST_WIRE) {
 			AstNode *wire = new AstNode(AST_IDENTIFIER);
 			wire->str = ast_stack.back()->children.back()->str;
-			if (ast_stack.back()->children.back()->is_reg)
+			if (ast_stack.back()->children.back()->is_reg || ast_stack.back()->children.back()->is_logic)
 				ast_stack.back()->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, wire, $2))));
 			else
 				ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, $2));
@@ -1360,7 +1360,7 @@ wire_name_and_opt_assign:
 	wire_name '=' expr {
 		AstNode *wire = new AstNode(AST_IDENTIFIER);
 		wire->str = ast_stack.back()->children.back()->str;
-		if (astbuf1->is_reg)
+		if (astbuf1->is_reg || astbuf1->is_logic)
 			ast_stack.back()->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, wire, $3))));
 		else
 			ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, $3));

From 8d0cd529c936b1c0a38d7a71a4457bd84c8b3efe Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Wed, 19 Jun 2019 11:37:11 +0200
Subject: [PATCH 2/4] Add defaultvalue attribute

Signed-off-by: Clifford Wolf <clifford@clifford.at>
---
 README.md                          |  4 ++++
 frontends/verilog/verilog_parser.y | 11 +++++++++++
 2 files changed, 15 insertions(+)

diff --git a/README.md b/README.md
index 94ea9538f..637703a7f 100644
--- a/README.md
+++ b/README.md
@@ -350,6 +350,10 @@ Verilog Attributes and non-standard features
   through the synthesis. When entities are combined, a new |-separated
   string is created that contains all the string from the original entities.
 
+- The ``defaultvalue`` attribute is used to store default values for
+  module inputs. The attribute is attached to the input wire by the HDL
+  front-end when the input is declared with a default value.
+
 - In addition to the ``(* ... *)`` attribute syntax, Yosys supports
   the non-standard ``{* ... *}`` attribute syntax to set default attributes
   for everything that comes after the ``{* ... *}`` statement. (Reset
diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y
index 5f3d713d3..ebb4369c3 100644
--- a/frontends/verilog/verilog_parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -345,6 +345,12 @@ module_arg_opt_assignment:
 		if (ast_stack.back()->children.size() > 0 && ast_stack.back()->children.back()->type == AST_WIRE) {
 			AstNode *wire = new AstNode(AST_IDENTIFIER);
 			wire->str = ast_stack.back()->children.back()->str;
+			if (ast_stack.back()->children.back()->is_input) {
+				AstNode *n = ast_stack.back()->children.back();
+				if (n->attributes.count("\\defaultvalue"))
+					delete n->attributes.at("\\defaultvalue");
+				n->attributes["\\defaultvalue"] = $2;
+			} else
 			if (ast_stack.back()->children.back()->is_reg || ast_stack.back()->children.back()->is_logic)
 				ast_stack.back()->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, wire, $2))));
 			else
@@ -1360,6 +1366,11 @@ wire_name_and_opt_assign:
 	wire_name '=' expr {
 		AstNode *wire = new AstNode(AST_IDENTIFIER);
 		wire->str = ast_stack.back()->children.back()->str;
+		if (astbuf1->is_input) {
+			if (astbuf1->attributes.count("\\defaultvalue"))
+				delete astbuf1->attributes.at("\\defaultvalue");
+			astbuf1->attributes["\\defaultvalue"] = $3;
+		} else
 		if (astbuf1->is_reg || astbuf1->is_logic)
 			ast_stack.back()->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, wire, $3))));
 		else

From 3da5288ce096befb844476907a2c6020aae62b8b Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Wed, 19 Jun 2019 11:49:20 +0200
Subject: [PATCH 3/4] Use input default values in hierarchy pass

Signed-off-by: Clifford Wolf <clifford@clifford.at>
---
 passes/hierarchy/hierarchy.cc | 38 +++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index 24e64a9b2..213437c01 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -591,6 +591,9 @@ struct HierarchyPass : public Pass {
 		log("        module instances when the width does not match the module port. This\n");
 		log("        option disables this behavior.\n");
 		log("\n");
+		log("    -nodefaults\n");
+		log("        do not resolve input port default values\n");
+		log("\n");
 		log("    -nokeep_asserts\n");
 		log("        per default this pass sets the \"keep\" attribute on all modules\n");
 		log("        that directly or indirectly contain one or more formal properties.\n");
@@ -645,6 +648,7 @@ struct HierarchyPass : public Pass {
 		bool generate_mode = false;
 		bool keep_positionals = false;
 		bool keep_portwidths = false;
+		bool nodefaults = false;
 		bool nokeep_asserts = false;
 		std::vector<std::string> generate_cells;
 		std::vector<generate_port_decl_t> generate_ports;
@@ -712,6 +716,10 @@ struct HierarchyPass : public Pass {
 				keep_portwidths = true;
 				continue;
 			}
+			if (args[argidx] == "-nodefaults") {
+				nodefaults = true;
+				continue;
+			}
 			if (args[argidx] == "-nokeep_asserts") {
 				nokeep_asserts = true;
 				continue;
@@ -940,6 +948,36 @@ struct HierarchyPass : public Pass {
 			}
 		}
 
+		if (!nodefaults)
+		{
+			dict<IdString, dict<IdString, Const>> defaults_db;
+
+			for (auto module : design->modules())
+				for (auto wire : module->wires())
+					if (wire->port_input && wire->attributes.count("\\defaultvalue"))
+						defaults_db[module->name][wire->name] = wire->attributes.at("\\defaultvalue");
+
+			for (auto module : design->modules())
+				for (auto cell : module->cells())
+				{
+					if (defaults_db.count(cell->type) == 0)
+						continue;
+
+					if (keep_positionals) {
+						bool found_positionals = false;
+						for (auto &conn : cell->connections())
+							if (conn.first[0] == '$' && '0' <= conn.first[1] && conn.first[1] <= '9')
+								found_positionals = true;
+						if (found_positionals)
+							continue;
+					}
+
+					for (auto &it : defaults_db.at(cell->type))
+						if (!cell->hasPort(it.first))
+							cell->setPort(it.first, it.second);
+				}
+		}
+
 		std::set<Module*> blackbox_derivatives;
 		std::vector<Module*> design_modules = design->modules();
 

From fa5fc3f6afd9eb27c1f52244b60cbeb77aa2e26c Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Wed, 19 Jun 2019 12:12:08 +0200
Subject: [PATCH 4/4] Add defvalue test, minor autotest fixes for .sv files

Signed-off-by: Clifford Wolf <clifford@clifford.at>
---
 tests/simple/defvalue.sv | 22 ++++++++++++++++++++++
 tests/tools/autotest.sh  | 29 +++++++++++++++--------------
 2 files changed, 37 insertions(+), 14 deletions(-)
 create mode 100644 tests/simple/defvalue.sv

diff --git a/tests/simple/defvalue.sv b/tests/simple/defvalue.sv
new file mode 100644
index 000000000..b0a087ecb
--- /dev/null
+++ b/tests/simple/defvalue.sv
@@ -0,0 +1,22 @@
+module top(input clock, input [3:0] delta, output [3:0] cnt1, cnt2);
+	cnt #(1) foo (.clock, .cnt(cnt1), .delta);
+	cnt #(2) bar (.clock, .cnt(cnt2));
+endmodule
+
+module cnt #(
+	parameter integer initval = 0
+) (
+	input clock,
+	output logic [3:0] cnt = initval,
+`ifdef __ICARUS__
+	input [3:0] delta
+`else
+	input [3:0] delta = 10
+`endif
+);
+`ifdef __ICARUS__
+	assign (weak0, weak1) delta = 10;
+`endif
+	always @(posedge clock)
+		cnt <= cnt + delta;
+endmodule
diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh
index 23964a751..96d9cdda9 100755
--- a/tests/tools/autotest.sh
+++ b/tests/tools/autotest.sh
@@ -89,8 +89,7 @@ done
 
 compile_and_run() {
 	exe="$1"; output="$2"; shift 2
-	ext=${1##*.}
-	if [ "$ext" == "sv" ]; then
+	if [ "${2##*.}" == "sv" ]; then
 		language_gen="-g2012"
 	else
 		language_gen="-g2005"
@@ -142,23 +141,25 @@ do
 		cd ${bn}.out
 		fn=$(basename $fn)
 		bn=$(basename $bn)
+		refext=v
 
 		rm -f ${bn}_ref.fir
 		if [[ "$ext" == "v" ]]; then
 			egrep -v '^\s*`timescale' ../$fn > ${bn}_ref.${ext}
 		elif [[ "$ext" == "aig" ]] || [[ "$ext" == "aag" ]]; then
-			"$toolsdir"/../../yosys-abc -c "read_aiger ../${fn}; write ${bn}_ref.v"
+			"$toolsdir"/../../yosys-abc -c "read_aiger ../${fn}; write ${bn}_ref.${refext}"
 		else
-			cp ../${fn} ${bn}_ref.${ext}
+			refext=$ext
+			cp ../${fn} ${bn}_ref.${refext}
 		fi
 
 		if [ ! -f ../${bn}_tb.v ]; then
-			"$toolsdir"/../../yosys -f "$frontend $include_opts" -b "test_autotb $autotb_opts" -o ${bn}_tb.v ${bn}_ref.v
+			"$toolsdir"/../../yosys -f "$frontend $include_opts" -b "test_autotb $autotb_opts" -o ${bn}_tb.v ${bn}_ref.${refext}
 		else
 			cp ../${bn}_tb.v ${bn}_tb.v
 		fi
 		if $genvcd; then sed -i 's,// \$dump,$dump,g' ${bn}_tb.v; fi
-		compile_and_run ${bn}_tb_ref ${bn}_out_ref ${bn}_tb.v ${bn}_ref.v $libs \
+		compile_and_run ${bn}_tb_ref ${bn}_out_ref ${bn}_tb.v ${bn}_ref.${refext} $libs \
 					"$toolsdir"/../../techlibs/common/simlib.v \
 					"$toolsdir"/../../techlibs/common/simcells.v
 		if $genvcd; then mv testbench.vcd ${bn}_ref.vcd; fi
@@ -175,25 +176,25 @@ do
 			test_count=$(( test_count + 1 ))
 		}
 
-		if [ "$frontend" = "verific" -o "$frontend" = "verific_gates" ] && grep -q VERIFIC-SKIP ${bn}_ref.v; then
+		if [ "$frontend" = "verific" -o "$frontend" = "verific_gates" ] && grep -q VERIFIC-SKIP ${bn}_ref.${refext}; then
 			touch ../${bn}.skip
 			return
 		fi
 
 		if [ -n "$scriptfiles" ]; then
-			test_passes -f "$frontend $include_opts" ${bn}_ref.v $scriptfiles
+			test_passes -f "$frontend $include_opts" ${bn}_ref.${refext} $scriptfiles
 		elif [ -n "$scriptopt" ]; then
-			test_passes -f "$frontend $include_opts" -p "$scriptopt" ${bn}_ref.v
+			test_passes -f "$frontend $include_opts" -p "$scriptopt" ${bn}_ref.${refext}
 		elif [ "$frontend" = "verific" ]; then
-			test_passes -p "verific -vlog2k ${bn}_ref.v; verific -import -all; opt; memory;;"
+			test_passes -p "verific -vlog2k ${bn}_ref.${refext}; verific -import -all; opt; memory;;"
 		elif [ "$frontend" = "verific_gates" ]; then
-			test_passes -p "verific -vlog2k ${bn}_ref.v; verific -import -gates -all; opt; memory;;"
+			test_passes -p "verific -vlog2k ${bn}_ref.${refext}; verific -import -gates -all; opt; memory;;"
 		else
-			test_passes -f "$frontend $include_opts" -p "hierarchy; proc; opt; memory; opt; fsm; opt -full -fine" ${bn}_ref.v
-			test_passes -f "$frontend $include_opts" -p "hierarchy; synth -run coarse; techmap; opt; abc -dff" ${bn}_ref.v
+			test_passes -f "$frontend $include_opts" -p "hierarchy; proc; opt; memory; opt; fsm; opt -full -fine" ${bn}_ref.${refext}
+			test_passes -f "$frontend $include_opts" -p "hierarchy; synth -run coarse; techmap; opt; abc -dff" ${bn}_ref.${refext}
 			if [ -n "$firrtl2verilog" ]; then
 			    if test -z "$xfirrtl" || ! grep "$fn" "$xfirrtl" ; then
-				"$toolsdir"/../../yosys -b "firrtl" -o ${bn}_ref.fir -f "$frontend $include_opts" -p "prep -nordff; proc; opt; memory; opt; fsm; opt -full -fine; pmuxtree" ${bn}_ref.v
+				"$toolsdir"/../../yosys -b "firrtl" -o ${bn}_ref.fir -f "$frontend $include_opts" -p "prep -nordff; proc; opt; memory; opt; fsm; opt -full -fine; pmuxtree" ${bn}_ref.${refext}
 				$firrtl2verilog -i ${bn}_ref.fir -o ${bn}_ref.fir.v
 				test_passes -f "$frontend $include_opts" -p "hierarchy; proc; opt; memory; opt; fsm; opt -full -fine" ${bn}_ref.fir.v
 			    fi