From 9c397ea78b759e60928a1595c4df10aaf6107788 Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Sun, 14 May 2017 13:14:49 +0200
Subject: [PATCH] Improve simplec back-end

---
 backends/simplec/simplec.cc   | 37 +++++++++++++++++++++++++++++++++++
 backends/simplec/test00_tb.c  | 11 ++++++++++-
 backends/simplec/test00_uut.v |  4 ++--
 3 files changed, 49 insertions(+), 3 deletions(-)

diff --git a/backends/simplec/simplec.cc b/backends/simplec/simplec.cc
index 49d8b8537..1308947ff 100644
--- a/backends/simplec/simplec.cc
+++ b/backends/simplec/simplec.cc
@@ -34,6 +34,7 @@ struct HierDirtyFlags
 	HierDirtyFlags *parent;
 	pool<SigBit> dirty_bits;
 	pool<Cell*> dirty_cells;
+	pool<SigBit> sticky_dirty_bits;
 	dict<IdString, HierDirtyFlags*> children;
 
 	HierDirtyFlags(Module *module, IdString hiername, HierDirtyFlags *parent) : dirty(0), module(module), hiername(hiername), parent(parent)
@@ -56,6 +57,7 @@ struct HierDirtyFlags
 			return;
 
 		dirty_bits.insert(bit);
+		sticky_dirty_bits.insert(bit);
 
 		HierDirtyFlags *p = this;
 		while (p != nullptr) {
@@ -573,6 +575,40 @@ struct SimplecWorker
 		}
 	}
 
+	void eval_sticky_dirty(HierDirtyFlags *work, const string &prefix, const string &log_prefix)
+	{
+		Module *mod = work->module;
+
+		for (Wire *w : mod->wires())
+		for (SigBit bit : SigSpec(w))
+		{
+			SigBit canonical_bit = sigmaps.at(mod)(bit);
+
+			if (canonical_bit == bit)
+				continue;
+
+			if (work->sticky_dirty_bits.count(canonical_bit) == 0)
+				continue;
+
+			log_assert(bit.wire && canonical_bit.wire);
+			funct_declarations.push_back(stringf("  %s(&%s, %s(&%s));",
+					util_set_bit(bit.wire->width, bit.offset).c_str(),
+					(prefix + cid(bit.wire->name)).c_str(),
+					util_get_bit(canonical_bit.wire->width, canonical_bit.offset).c_str(),
+					(prefix + cid(canonical_bit.wire->name)).c_str()));
+
+			if (verbose)
+				log("  Propagating alias %s.%s[%d] -> %s.%s[%d].\n",
+						log_prefix.c_str(), log_id(canonical_bit.wire), canonical_bit.offset,
+						log_prefix.c_str(), log_id(bit.wire), bit.offset);
+		}
+
+		work->sticky_dirty_bits.clear();
+
+		for (auto &child : work->children)
+			eval_sticky_dirty(child.second, prefix + cid(child.first) + ".", log_prefix + "." + cid(child.first));
+	}
+
 	void make_func(HierDirtyFlags *work, const string &func_name)
 	{
 		log("Generating function %s():\n", func_name.c_str());
@@ -584,6 +620,7 @@ struct SimplecWorker
 		funct_declarations.push_back(stringf("static void %s(struct %s_state_t *state)", func_name.c_str(), cid(work->module->name).c_str()));
 		funct_declarations.push_back("{");
 		eval_dirty(work, "state->", log_id(work->module->name), "", "");
+		eval_sticky_dirty(work, "state->", log_id(work->module->name));
 		funct_declarations.push_back("}");
 
 		log("  Activated %d cells (%d activated more than once).\n", GetSize(activated_cells), GetSize(reactivated_cells));
diff --git a/backends/simplec/test00_tb.c b/backends/simplec/test00_tb.c
index 9b3ae00e0..7d86d0d91 100644
--- a/backends/simplec/test00_tb.c
+++ b/backends/simplec/test00_tb.c
@@ -14,7 +14,7 @@ uint32_t xorshift32()
 int main()
 {
 	struct test_state_t state;
-	uint32_t a, b, c, x, y, z;
+	uint32_t a, b, c, x, y, z, w;
 
 	for (int i = 0; i < 10; i++)
 	{
@@ -25,6 +25,7 @@ int main()
 		x = (a & b) | c;
 		y = a & (b | c);
 		z = a ^ b ^ c;
+		w = z;
 
 		state.a.value_7_0   = a;
 		state.a.value_15_8  = a >> 8;
@@ -61,6 +62,12 @@ int main()
 		uut_z |= (uint32_t)state.z.value_23_16 << 16;
 		uut_z |= (uint32_t)state.z.value_31_24 << 24;
 
+		uint32_t uut_w = 0;
+		uut_w |= (uint32_t)state.w.value_7_0;
+		uut_w |= (uint32_t)state.w.value_15_8  << 8;
+		uut_w |= (uint32_t)state.w.value_23_16 << 16;
+		uut_w |= (uint32_t)state.w.value_31_24 << 24;
+
 		printf("---\n");
 		printf("A: 0x%08x\n", a);
 		printf("B: 0x%08x\n", b);
@@ -68,10 +75,12 @@ int main()
 		printf("X: 0x%08x 0x%08x\n", x, uut_x);
 		printf("Y: 0x%08x 0x%08x\n", y, uut_y);
 		printf("Z: 0x%08x 0x%08x\n", z, uut_z);
+		printf("W: 0x%08x 0x%08x\n", w, uut_w);
 
 		assert(x == uut_x);
 		assert(y == uut_y);
 		assert(z == uut_z);
+		assert(w == uut_w);
 	}
 
 	return 0;
diff --git a/backends/simplec/test00_uut.v b/backends/simplec/test00_uut.v
index fd634cf82..744dbe9e3 100644
--- a/backends/simplec/test00_uut.v
+++ b/backends/simplec/test00_uut.v
@@ -1,7 +1,7 @@
-module test(input [31:0] a, b, c, output [31:0] x, y, z);
+module test(input [31:0] a, b, c, output [31:0] x, y, z, w);
   unit_x unit_x_inst (.a(a), .b(b), .c(c), .x(x));
   unit_y unit_y_inst (.a(a), .b(b), .c(c), .y(y));
-  assign z = a ^ b ^ c;
+  assign z = a ^ b ^ c, w = z;
 endmodule
   
 module unit_x(input [31:0] a, b, c, output [31:0] x);