From 8fe9cdf36428b07ab22e9f831470e7e4c37978e2 Mon Sep 17 00:00:00 2001
From: Robert Ou <rqou@robertou.com>
Date: Sat, 31 Mar 2018 02:54:26 -0700
Subject: coolrunner2: Add extraction for TFFs

---
 techlibs/coolrunner2/Makefile.inc         |  1 +
 techlibs/coolrunner2/synth_coolrunner2.cc | 12 +++++++++
 techlibs/coolrunner2/tff_extract.v        | 41 +++++++++++++++++++++++++++++++
 3 files changed, 54 insertions(+)
 create mode 100644 techlibs/coolrunner2/tff_extract.v

diff --git a/techlibs/coolrunner2/Makefile.inc b/techlibs/coolrunner2/Makefile.inc
index 96bbb0f47..d62c9960c 100644
--- a/techlibs/coolrunner2/Makefile.inc
+++ b/techlibs/coolrunner2/Makefile.inc
@@ -4,4 +4,5 @@ OBJS += techlibs/coolrunner2/coolrunner2_sop.o
 
 $(eval $(call add_share_file,share/coolrunner2,techlibs/coolrunner2/cells_latch.v))
 $(eval $(call add_share_file,share/coolrunner2,techlibs/coolrunner2/cells_sim.v))
+$(eval $(call add_share_file,share/coolrunner2,techlibs/coolrunner2/tff_extract.v))
 $(eval $(call add_share_file,share/coolrunner2,techlibs/coolrunner2/xc2_dff.lib))
diff --git a/techlibs/coolrunner2/synth_coolrunner2.cc b/techlibs/coolrunner2/synth_coolrunner2.cc
index 183282629..5d9e3cc90 100644
--- a/techlibs/coolrunner2/synth_coolrunner2.cc
+++ b/techlibs/coolrunner2/synth_coolrunner2.cc
@@ -149,6 +149,16 @@ struct SynthCoolrunner2Pass : public ScriptPass
 			run("dfflibmap -prepare -liberty +/coolrunner2/xc2_dff.lib");
 		}
 
+		if (check_label("map_tff"))
+		{
+			// This is quite hacky. By telling abc that it can only use AND and XOR gates, abc will try and use XOR
+			// gates "whenever possible." This will hopefully cause toggle flip-flop structures to turn into an XOR
+			// connected to a D flip-flop. We then match on these and convert them into XC2 TFF cells.
+			run("abc -g AND,XOR");
+			run("clean");
+			run("extract -map +/coolrunner2/tff_extract.v");
+		}
+
 		if (check_label("map_pla"))
 		{
 			run("abc -sop -I 40 -P 56");
@@ -160,6 +170,8 @@ struct SynthCoolrunner2Pass : public ScriptPass
 			run("dfflibmap -liberty +/coolrunner2/xc2_dff.lib");
 			run("dffinit -ff FDCP Q INIT");
 			run("dffinit -ff FDCP_N Q INIT");
+			run("dffinit -ff FTCP Q INIT");
+			run("dffinit -ff FTCP_N Q INIT");
 			run("dffinit -ff LDCP Q INIT");
 			run("dffinit -ff LDCP_N Q INIT");
 			run("coolrunner2_sop");
diff --git a/techlibs/coolrunner2/tff_extract.v b/techlibs/coolrunner2/tff_extract.v
new file mode 100644
index 000000000..b4237dd18
--- /dev/null
+++ b/techlibs/coolrunner2/tff_extract.v
@@ -0,0 +1,41 @@
+module FTCP (C, PRE, CLR, T, Q);
+	input C, PRE, CLR, T;
+	output wire Q;
+
+	wire xorout;
+
+	$_XOR_ xorgate (
+		.A(T),
+		.B(Q),
+		.Y(xorout),
+	);
+
+	$_DFFSR_PPP_ dff (
+		.C(C),
+		.D(xorout),
+		.Q(Q),
+		.S(PRE),
+		.R(CLR),
+	);
+endmodule
+
+module FTCP_N (C, PRE, CLR, T, Q);
+	input C, PRE, CLR, T;
+	output wire Q;
+
+	wire xorout;
+
+	$_XOR_ xorgate (
+		.A(T),
+		.B(Q),
+		.Y(xorout),
+	);
+
+	$_DFFSR_NPP_ dff (
+		.C(C),
+		.D(xorout),
+		.Q(Q),
+		.S(PRE),
+		.R(CLR),
+	);
+endmodule
-- 
cgit v1.2.3


From cfa3753b89c684b66e2cb164226a3358493e5232 Mon Sep 17 00:00:00 2001
From: Robert Ou <rqou@robertou.com>
Date: Sat, 31 Mar 2018 02:56:11 -0700
Subject: coolrunner2: Split multi-bit nets

The PAR tool doesn't expect any "dangling" nets with no drivers nor
sinks. By splitting the nets, clean removes them.
---
 techlibs/coolrunner2/synth_coolrunner2.cc | 1 +
 1 file changed, 1 insertion(+)

diff --git a/techlibs/coolrunner2/synth_coolrunner2.cc b/techlibs/coolrunner2/synth_coolrunner2.cc
index 5d9e3cc90..2e94c3449 100644
--- a/techlibs/coolrunner2/synth_coolrunner2.cc
+++ b/techlibs/coolrunner2/synth_coolrunner2.cc
@@ -178,6 +178,7 @@ struct SynthCoolrunner2Pass : public ScriptPass
 			run("iopadmap -bits -inpad IBUF O:I -outpad IOBUFE I:IO -inoutpad IOBUFE O:IO -toutpad IOBUFE E:I:IO -tinoutpad IOBUFE E:O:I:IO");
 			run("attrmvcp -attr src -attr LOC t:IOBUFE n:*");
 			run("attrmvcp -attr src -attr LOC -driven t:IBUF n:*");
+			run("splitnets");
 			run("clean");
 		}
 
-- 
cgit v1.2.3


From 14e49fb05737cfb02217b2aaf14d9f5d9e1859da Mon Sep 17 00:00:00 2001
From: Robert Ou <rqou@robertou.com>
Date: Sat, 31 Mar 2018 03:54:48 -0700
Subject: coolrunner2: Add an ANDTERM/XOR between chained FFs

In some cases (e.g. the low bits of counters) the design might end up
with a flip-flop whose input is directly driven by another flip-flop.
This isn't possible in the Coolrunner-II architecture, so add a single
AND term and XOR in this case.
---
 techlibs/coolrunner2/coolrunner2_sop.cc | 58 +++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git a/techlibs/coolrunner2/coolrunner2_sop.cc b/techlibs/coolrunner2/coolrunner2_sop.cc
index b57214ccb..431e0a127 100644
--- a/techlibs/coolrunner2/coolrunner2_sop.cc
+++ b/techlibs/coolrunner2/coolrunner2_sop.cc
@@ -250,6 +250,64 @@ struct Coolrunner2SopPass : public Pass {
 				}
 			}
 
+			// In some cases we can get a FF feeding straight into an FF. This is not possible, so we need to insert
+			// some AND/XOR cells in the middle to make it actually work.
+
+			// Find all the FF outputs
+			pool<SigBit> sig_fed_by_ff;
+			for (auto cell : module->selected_cells())
+			{
+				if (cell->type == "\\FDCP" || cell->type == "\\FDCP_N" || cell->type == "\\FDDCP" ||
+					cell->type == "\\LDCP" || cell->type == "\\LDCP_N" ||
+					cell->type == "\\FTCP" || cell->type == "\\FTCP_N" || cell->type == "\\FTDCP" ||
+					cell->type == "\\FDCPE" || cell->type == "\\FDCPE_N" || cell->type == "\\FDDCPE")
+				{
+					auto output = sigmap(cell->getPort("\\Q")[0]);
+					sig_fed_by_ff.insert(output);
+				}
+			}
+
+			// Look at all the FF inputs
+			for (auto cell : module->selected_cells())
+			{
+				if (cell->type == "\\FDCP" || cell->type == "\\FDCP_N" || cell->type == "\\FDDCP" ||
+					cell->type == "\\LDCP" || cell->type == "\\LDCP_N" ||
+					cell->type == "\\FTCP" || cell->type == "\\FTCP_N" || cell->type == "\\FTDCP" ||
+					cell->type == "\\FDCPE" || cell->type == "\\FDCPE_N" || cell->type == "\\FDDCPE")
+				{
+					SigBit input;
+					if (cell->type == "\\FTCP" || cell->type == "\\FTCP_N" || cell->type == "\\FTDCP")
+						input = sigmap(cell->getPort("\\T")[0]);
+					else
+						input = sigmap(cell->getPort("\\D")[0]);
+
+					if (sig_fed_by_ff[input])
+					{
+						printf("Buffering input to \"%s\"\n", cell->name.c_str());
+
+						auto and_to_xor_wire = module->addWire(NEW_ID);
+						auto xor_to_ff_wire = module->addWire(NEW_ID);
+
+						auto and_cell = module->addCell(NEW_ID, "\\ANDTERM");
+						and_cell->setParam("\\TRUE_INP", 1);
+						and_cell->setParam("\\COMP_INP", 0);
+						and_cell->setPort("\\OUT", and_to_xor_wire);
+						and_cell->setPort("\\IN", input);
+						and_cell->setPort("\\IN_B", SigSpec());
+
+						auto xor_cell = module->addCell(NEW_ID, "\\MACROCELL_XOR");
+						xor_cell->setParam("\\INVERT_OUT", false);
+						xor_cell->setPort("\\IN_PTC", and_to_xor_wire);
+						xor_cell->setPort("\\OUT", xor_to_ff_wire);
+
+						if (cell->type == "\\FTCP" || cell->type == "\\FTCP_N" || cell->type == "\\FTDCP")
+							cell->setPort("\\T", xor_to_ff_wire);
+						else
+							cell->setPort("\\D", xor_to_ff_wire);
+					}
+				}
+			}
+
 			// Actually do the removal now that we aren't iterating
 			for (auto cell : cells_to_remove)
 			{
-- 
cgit v1.2.3