xilinx: Add URAM288 mapping for xcup

Signed-off-by: David Shah <dave@ds0.me>
diff --git a/techlibs/xilinx/Makefile.inc b/techlibs/xilinx/Makefile.inc
index 6fc41f5..debe8a6 100644
--- a/techlibs/xilinx/Makefile.inc
+++ b/techlibs/xilinx/Makefile.inc
@@ -37,6 +37,8 @@
 $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_brams_bb.v))
 $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xcu_brams_map.v))
 $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xcu_brams_bb.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xcup_urams.txt))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xcup_urams_map.v))
 $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lutrams.txt))
 $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lutrams_map.v))
 $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/arith_map.v))
diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc
index 825addf..69b071d 100644
--- a/techlibs/xilinx/synth_xilinx.cc
+++ b/techlibs/xilinx/synth_xilinx.cc
@@ -93,6 +93,9 @@
 		log("    -noclkbuf\n");
 		log("        disable automatic clock buffer insertion\n");
 		log("\n");
+		log("    -uram\n");
+		log("        infer URAM288s for large memories (xcup only)\n");
+		log("\n");
 		log("    -widemux <int>\n");
 		log("        enable inference of hard multiplexer resources (MUXF[78]) for muxes at or\n");
 		log("        above this number of inputs (minimum value 2, recommended value >= 5).\n");
@@ -119,7 +122,7 @@
 	}
 
 	std::string top_opt, edif_file, blif_file, family;
-	bool flatten, retime, vpr, ise, iopad, noiopad, noclkbuf, nobram, nolutram, nosrl, nocarry, nowidelut, nodsp, abc9;
+	bool flatten, retime, vpr, ise, iopad, noiopad, noclkbuf, nobram, nolutram, nosrl, nocarry, nowidelut, nodsp, uram, abc9;
 	bool flatten_before_abc;
 	int widemux;
 
@@ -143,6 +146,7 @@
 		nocarry = false;
 		nowidelut = false;
 		nodsp = false;
+		uram = false;
 		abc9 = false;
 		flatten_before_abc = false;
 		widemux = 0;
@@ -248,6 +252,10 @@
 				nodsp = true;
 				continue;
 			}
+			if (args[argidx] == "-uram") {
+				uram = true;
+				continue;
+			}
 			break;
 		}
 		extra_args(args, argidx, design);
@@ -410,6 +418,20 @@
 			run("opt_clean");
 		}
 
+		if (check_label("map_uram", "(only if '-uram')")) {
+			if (help_mode) {
+				run("memory_bram -rules +/xilinx/{family}_urams.txt");
+				run("techmap -map +/xilinx/{family}_urams_map.v");
+			} else if (uram) {
+				if (family == "xcup") {
+					run("memory_bram -rules +/xilinx/xcup_urams.txt");
+					run("techmap -map +/xilinx/xcup_urams_map.v");
+				} else {
+					log_warning("UltraRAM inference not supported for family %s.\n", family.c_str());
+				}
+			}
+		}
+
 		if (check_label("map_bram", "(skip if '-nobram')")) {
 			if (help_mode) {
 				run("memory_bram -rules +/xilinx/{family}_brams.txt");
diff --git a/techlibs/xilinx/xcu_brams_bb.v b/techlibs/xilinx/xcu_brams_bb.v
index f3e43d0..cc70ce3 100644
--- a/techlibs/xilinx/xcu_brams_bb.v
+++ b/techlibs/xilinx/xcu_brams_bb.v
@@ -402,4 +402,4 @@
     input SLEEP;
     input [3:0] WEA;
     input [7:0] WEBWE;
-endmodule
\ No newline at end of file
+endmodule
diff --git a/techlibs/xilinx/xcup_urams.txt b/techlibs/xilinx/xcup_urams.txt
new file mode 100644
index 0000000..40c4742
--- /dev/null
+++ b/techlibs/xilinx/xcup_urams.txt
@@ -0,0 +1,19 @@
+bram $__XILINX_URAM288
+  init 0
+  abits 12
+  dbits 72
+  groups 2
+  ports  1 1
+  wrmode 0 1
+  enable 1 9
+  transp 0 0
+  clocks 2 2
+  clkpol 2 2
+endbram
+
+match $__XILINX_URAM288
+  min bits 131072
+  min efficiency 15
+  shuffle_enable B
+  make_transp
+endmatch
diff --git a/techlibs/xilinx/xcup_urams_map.v b/techlibs/xilinx/xcup_urams_map.v
new file mode 100644
index 0000000..f15211b
--- /dev/null
+++ b/techlibs/xilinx/xcup_urams_map.v
@@ -0,0 +1,47 @@
+module \$__XILINX_URAM288 (CLK2, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
+	parameter CLKPOL2 = 1;
+
+	input CLK2;
+
+	input [11:0] A1ADDR;
+	output [71:0] A1DATA;
+	input A1EN;
+
+	input [11:0] B1ADDR;
+	input [71:0] B1DATA;
+	input [8:0] B1EN;
+
+
+	URAM288 #(
+		.BWE_MODE_A("PARITY_INDEPENDENT"),
+		.BWE_MODE_B("PARITY_INDEPENDENT"),
+		.EN_AUTO_SLEEP_MODE("FALSE"),
+		.IREG_PRE_A("FALSE"),
+		.IREG_PRE_B("FALSE"),
+		.IS_CLK_INVERTED(!CLKPOL2),
+		.OREG_A("FALSE"),
+		.OREG_B("FALSE")
+	) _TECHMAP_REPLACE_ (
+		.ADDR_A({11'b0, A1ADDR}),
+		.BWE_A(9'b0),
+		.DIN_A(72'b0),
+		.EN_A(A1EN),
+		.RDB_WR_A(1'b0),
+		.INJECT_DBITERR_A(1'b0),
+		.INJECT_SBITERR_A(1'b0),
+		.RST_A(1'b0),
+		.DOUT_A(A1DATA),
+
+		.ADDR_B({11'b0, B1ADDR}),
+		.BWE_B(B1EN),
+		.DIN_B(B1DATA),
+		.EN_B(|B1EN),
+		.RDB_WR_B(1'b1),
+		.INJECT_DBITERR_B(1'b0),
+		.INJECT_SBITERR_B(1'b0),
+		.RST_B(1'b0),
+
+		.CLK(CLK2),
+		.SLEEP(1'b0)
+	);
+endmodule