Merge branch 'diego/memattr' of https://github.com/dh73/Yosys into diego/memattr
diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc
index aa8f941..2d2897e 100644
--- a/passes/memory/memory_bram.cc
+++ b/passes/memory/memory_bram.cc
@@ -134,6 +134,7 @@
 		dict<string, int> min_limits, max_limits;
 		bool or_next_if_better, make_transp, make_outreg;
 		char shuffle_enable;
+		std::string memattr;
 	};
 
 	dict<IdString, vector<bram_t>> brams;
@@ -327,6 +328,11 @@
 				continue;
 			}
 
+			if (GetSize(tokens) == 3 && tokens[0] == "attribute") {
+				data.memattr = tokens[2].c_str();
+				continue;
+			}
+
 			syntax_error();
 		}
 	}
@@ -362,6 +368,20 @@
 	}
 };
 
+bool check_memory_attribute(Cell *cell, std::string match)
+{
+	std::string memory_attribute = cell->attributes["\\ram_style"].decode_string();
+	bool attribute_set_match = 0;
+
+	if (memory_attribute != "")
+	{
+		attribute_set_match = match.compare(memory_attribute);
+		if (!attribute_set_match)
+			return true;
+	}
+	return false;
+}
+
 bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram, const rules_t::match_t &match, dict<string, int> &match_properties, int mode)
 {
 	Module *module = cell->module;
@@ -788,7 +808,6 @@
 		match_properties["dcells"] = ((mem_width + bram.dbits - 1) / bram.dbits);
 		match_properties["acells"] = ((mem_size + (1 << bram.abits) - 1) / (1 << bram.abits));
 		match_properties["cells"] = match_properties["dcells"] *  match_properties["acells"] * match_properties["dups"];
-
 		log("      Updated properties: dups=%d waste=%d efficiency=%d\n",
 				match_properties["dups"], match_properties["waste"], match_properties["efficiency"]);
 
@@ -798,6 +817,8 @@
 						it.first.c_str(), log_id(match.name));
 			if (match_properties[it.first] >= it.second)
 				continue;
+			if (check_memory_attribute(cell, match.memattr))
+				continue;
 			log("    Rule for bram type %s rejected: requirement 'min %s %d' not met.\n",
 					log_id(match.name), it.first.c_str(), it.second);
 			return false;
@@ -997,6 +1018,7 @@
 	log("Processing %s.%s:\n", log_id(cell->module), log_id(cell));
 
 	bool cell_init = !SigSpec(cell->getParam("\\INIT")).is_fully_undef();
+	std::string cell_attribute = cell->attributes["\\ram_style"].decode_string();
 
 	dict<string, int> match_properties;
 	match_properties["words"]  = cell->getParam("\\SIZE").as_int();
@@ -1015,6 +1037,10 @@
 	pool<pair<IdString, int>> failed_brams;
 	dict<pair<int, int>, tuple<int, int, int>> best_rule_cache;
 
+	if (cell_attribute != "")
+		log("  Found memory attribute '%s' in object %s.\n", cell_attribute.c_str(), 
+			cell->name.c_str());
+
 	for (int i = 0; i < GetSize(rules.matches); i++)
 	{
 		auto &match = rules.matches.at(i);
@@ -1082,6 +1108,8 @@
 							it.first.c_str(), log_id(match.name));
 				if (match_properties[it.first] >= it.second)
 					continue;
+				if (check_memory_attribute(cell, match.memattr))
+					continue;
 				log("    Rule #%d for bram type %s (variant %d) rejected: requirement 'min %s %d' not met.\n",
 						i+1, log_id(bram.name), bram.variant, it.first.c_str(), it.second);
 				goto next_match_rule;
@@ -1242,6 +1270,9 @@
 		log("A match containing the command 'shuffle_enable A' will re-organize\n");
 		log("the data bits to accommodate the enable pattern of port A.\n");
 		log("\n");
+		log("A match containing the command 'attribute' will bypass min bits/efficiency\n");
+		log("to select the type of memory.\n");
+		log("\n");
 	}
 	void execute(vector<string> args, Design *design) YS_OVERRIDE
 	{
diff --git a/techlibs/xilinx/xc7_xcu_brams.txt b/techlibs/xilinx/xc7_xcu_brams.txt
index f116111..da663ce 100644
--- a/techlibs/xilinx/xc7_xcu_brams.txt
+++ b/techlibs/xilinx/xc7_xcu_brams.txt
@@ -85,6 +85,7 @@
   min efficiency 5
   shuffle_enable B
   make_transp
+  attribute ram_style block
   or_next_if_better
 endmatch