From 609caa23b5e12547c043dc4a1827d1a531af1992 Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Sun, 24 Nov 2013 17:17:21 +0100
Subject: [PATCH] Implemented correct handling of signed module parameters

---
 frontends/ast/ast.cc          | 4 ++--
 frontends/ast/ast.h           | 2 +-
 frontends/ast/genrtlil.cc     | 4 ++++
 kernel/rtlil.cc               | 2 +-
 kernel/rtlil.h                | 3 ++-
 passes/hierarchy/hierarchy.cc | 2 +-
 passes/techmap/techmap.cc     | 2 +-
 tests/simple/hierarchy.v      | 8 +++++++-
 8 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index 29093b830..6423cae22 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -792,7 +792,7 @@ AstModule::~AstModule()
 }
 
 // create a new parametric module (when needed) and return the name of the generated module
-RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdString, RTLIL::Const> parameters)
+RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdString, RTLIL::Const> parameters, std::set<RTLIL::IdString> signed_parameters)
 {
 	log_header("Executing AST frontend in derive mode using pre-parsed AST for module `%s'.\n", name.c_str());
 
@@ -826,7 +826,7 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdStrin
 	rewrite_parameter:
 			para_info += stringf("%s=%s", child->str.c_str(), log_signal(RTLIL::SigSpec(parameters[para_id])));
 			delete child->children.at(0);
-			child->children[0] = AstNode::mkconst_bits(parameters[para_id].bits, child->is_signed);
+			child->children[0] = AstNode::mkconst_bits(parameters[para_id].bits, signed_parameters.count(para_id) > 0);
 			hash_data.insert(hash_data.end(), child->str.begin(), child->str.end());
 			hash_data.push_back(0);
 			hash_data.insert(hash_data.end(), parameters[para_id].bits.begin(), parameters[para_id].bits.end());
diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h
index de32a2bb9..f9f47f6a4 100644
--- a/frontends/ast/ast.h
+++ b/frontends/ast/ast.h
@@ -227,7 +227,7 @@ namespace AST
 		AstNode *ast;
 		bool nolatches, nomem2reg, mem2reg, lib, noopt;
 		virtual ~AstModule();
-		virtual RTLIL::IdString derive(RTLIL::Design *design, std::map<RTLIL::IdString, RTLIL::Const> parameters);
+		virtual RTLIL::IdString derive(RTLIL::Design *design, std::map<RTLIL::IdString, RTLIL::Const> parameters, std::set<RTLIL::IdString> signed_parameters);
 		virtual void update_auto_wires(std::map<RTLIL::IdString, int> auto_sizes);
 		virtual RTLIL::Module *clone() const;
 	};
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index e634a27a9..177c1ec59 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -1309,9 +1309,13 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
 					if (child->str.size() == 0) {
 						char buf[100];
 						snprintf(buf, 100, "$%d", ++para_counter);
+						if (child->children[0]->is_signed)
+							cell->signed_parameters.insert(buf);
 						cell->parameters[buf].str = child->children[0]->str;
 						cell->parameters[buf].bits = child->children[0]->bits;
 					} else {
+						if (child->children[0]->is_signed)
+							cell->signed_parameters.insert(child->str);
 						cell->parameters[child->str].str = child->children[0]->str;
 						cell->parameters[child->str].bits = child->children[0]->bits;
 					}
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index bd73fe538..afd7ca2f1 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -260,7 +260,7 @@ RTLIL::Module::~Module()
 		delete it->second;
 }
 
-RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, std::map<RTLIL::IdString, RTLIL::Const>)
+RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, std::map<RTLIL::IdString, RTLIL::Const>, std::set<RTLIL::IdString>)
 {
 	log_error("Module `%s' is used with parameters but is not parametric!\n", id2cstr(name));
 }
diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index c7f9cf122..a4c3008bc 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -264,7 +264,7 @@ struct RTLIL::Module {
 	std::vector<RTLIL::SigSig> connections;
 	RTLIL_ATTRIBUTE_MEMBERS
 	virtual ~Module();
-	virtual RTLIL::IdString derive(RTLIL::Design *design, std::map<RTLIL::IdString, RTLIL::Const> parameters);
+	virtual RTLIL::IdString derive(RTLIL::Design *design, std::map<RTLIL::IdString, RTLIL::Const> parameters, std::set<RTLIL::IdString> signed_parameters);
 	virtual void update_auto_wires(std::map<RTLIL::IdString, int> auto_sizes);
 	virtual size_t count_id(RTLIL::IdString id);
 	virtual void check();
@@ -300,6 +300,7 @@ struct RTLIL::Cell {
 	RTLIL::IdString type;
 	std::map<RTLIL::IdString, RTLIL::SigSpec> connections;
 	std::map<RTLIL::IdString, RTLIL::Const> parameters;
+	std::set<RTLIL::IdString> signed_parameters;
 	RTLIL_ATTRIBUTE_MEMBERS
 	void optimize();
 
diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index d9b52c6d0..291df184f 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -150,7 +150,7 @@ static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool fla
 		if (design->modules.at(cell->type)->get_bool_attribute("\\blackbox"))
 			continue;
 		RTLIL::Module *mod = design->modules[cell->type];
-		cell->type = mod->derive(design, cell->parameters);
+		cell->type = mod->derive(design, cell->parameters, cell->signed_parameters);
 		cell->parameters.clear();
 		did_something = true;
 	}
diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc
index 4f9d9c4e4..c3af697be 100644
--- a/passes/techmap/techmap.cc
+++ b/passes/techmap/techmap.cc
@@ -239,7 +239,7 @@ static bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::
 				tpl = techmap_cache[key];
 			} else {
 				if (cell->parameters.size() != 0) {
-					derived_name = tpl->derive(map, parameters);
+					derived_name = tpl->derive(map, parameters, cell->signed_parameters);
 					tpl = map->modules[derived_name];
 					log_continue = true;
 				}
diff --git a/tests/simple/hierarchy.v b/tests/simple/hierarchy.v
index 97612c74a..17888009f 100644
--- a/tests/simple/hierarchy.v
+++ b/tests/simple/hierarchy.v
@@ -4,14 +4,20 @@ module top(a, b, y1, y2, y3, y4);
 input [3:0] a;
 input signed [3:0] b;
 output [7:0] y1, y2, y3, y4;
+
+// this version triggers a bug in icarus verilog
+// submod #(-3'sd1, 3'b111 + 3'b001) foo (a, b, y1, y2, y3, y4);
+
+// this version is handled correctly by icarus verilog
 submod #(-3'sd1, -3'sd1) foo (a, b, y1, y2, y3, y4);
+
 endmodule
 
 (* gentb_skip *)
 module submod(a, b, y1, y2, y3, y4);
 parameter c = 0;
 parameter [7:0] d = 0;
-input [7:0] a, b;
+input [3:0] a, b;
 output [7:0] y1, y2, y3, y4;
 assign y1 = a;
 assign y2 = b;