From f1764b4fe99807c445526774563a98224b642766 Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Mon, 8 Dec 2014 10:50:19 +0100
Subject: [PATCH] Added $dffe cell type

---
 kernel/rtlil.cc             | 11 +++++++++++
 passes/techmap/simplemap.cc | 23 +++++++++++++++++++++++
 techlibs/common/simlib.v    | 19 +++++++++++++++++++
 techlibs/common/techmap.v   |  2 +-
 4 files changed, 54 insertions(+), 1 deletion(-)

diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index 321c39e10..b1bf43941 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -752,6 +752,17 @@ namespace {
 				return;
 			}
 
+			if (cell->type == "$dffe") {
+				param_bool("\\CLK_POLARITY");
+				param_bool("\\EN_POLARITY");
+				port("\\CLK", 1);
+				port("\\EN", 1);
+				port("\\D", param("\\WIDTH"));
+				port("\\Q", param("\\WIDTH"));
+				check_expected();
+				return;
+			}
+
 			if (cell->type == "$dffsr") {
 				param_bool("\\CLK_POLARITY");
 				param_bool("\\SET_POLARITY");
diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc
index c3ca29e50..2dcb5f3eb 100644
--- a/passes/techmap/simplemap.cc
+++ b/passes/techmap/simplemap.cc
@@ -302,6 +302,28 @@ static void simplemap_dff(RTLIL::Module *module, RTLIL::Cell *cell)
 	}
 }
 
+static void simplemap_dffe(RTLIL::Module *module, RTLIL::Cell *cell)
+{
+	int width = cell->parameters.at("\\WIDTH").as_int();
+	char clk_pol = cell->parameters.at("\\CLK_POLARITY").as_bool() ? 'P' : 'N';
+	char en_pol = cell->parameters.at("\\EN_POLARITY").as_bool() ? 'P' : 'N';
+
+	RTLIL::SigSpec sig_clk = cell->getPort("\\CLK");
+	RTLIL::SigSpec sig_en = cell->getPort("\\EN");
+	RTLIL::SigSpec sig_d = cell->getPort("\\D");
+	RTLIL::SigSpec sig_q = cell->getPort("\\Q");
+
+	std::string gate_type = stringf("$_DFFE_%c%c_", clk_pol, en_pol);
+
+	for (int i = 0; i < width; i++) {
+		RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
+		gate->setPort("\\C", sig_clk);
+		gate->setPort("\\E", sig_en);
+		gate->setPort("\\D", sig_d[i]);
+		gate->setPort("\\Q", sig_q[i]);
+	}
+}
+
 static void simplemap_dffsr(RTLIL::Module *module, RTLIL::Cell *cell)
 {
 	int width = cell->parameters.at("\\WIDTH").as_int();
@@ -399,6 +421,7 @@ void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTL
 	mappers["$concat"]      = simplemap_concat;
 	mappers["$sr"]          = simplemap_sr;
 	mappers["$dff"]         = simplemap_dff;
+	mappers["$dffe"]        = simplemap_dffe;
 	mappers["$dffsr"]       = simplemap_dffsr;
 	mappers["$adff"]        = simplemap_adff;
 	mappers["$dlatch"]      = simplemap_dlatch;
diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v
index 2d8088adb..e241cd3ce 100644
--- a/techlibs/common/simlib.v
+++ b/techlibs/common/simlib.v
@@ -1216,6 +1216,25 @@ end
 
 endmodule
 
+// --------------------------------------------------------
+
+module \$dffe (CLK, EN, D, Q);
+
+parameter WIDTH = 0;
+parameter CLK_POLARITY = 1'b1;
+parameter EN_POLARITY = 1'b1;
+
+input CLK, EN;
+input [WIDTH-1:0] D;
+output reg [WIDTH-1:0] Q;
+wire pos_clk = CLK == CLK_POLARITY;
+
+always @(posedge pos_clk) begin
+	if (EN == EN_POLARITY) Q <= D;
+end
+
+endmodule
+
 // --------------------------------------------------------
 `ifndef SIMLIB_NOSR
 
diff --git a/techlibs/common/techmap.v b/techlibs/common/techmap.v
index b6c075b67..cb39fb4b2 100644
--- a/techlibs/common/techmap.v
+++ b/techlibs/common/techmap.v
@@ -59,7 +59,7 @@ module _90_simplemap_various;
 endmodule
 
 (* techmap_simplemap *)
-(* techmap_celltype = "$sr $dff $adff $dffsr $dlatch" *)
+(* techmap_celltype = "$sr $dff $dffe $adff $dffsr $dlatch" *)
 module _90_simplemap_registers;
 endmodule