diff options
author | Eddie Hung <eddie@fpgeh.com> | 2019-12-16 12:07:49 -0800 |
---|---|---|
committer | Eddie Hung <eddie@fpgeh.com> | 2019-12-16 12:07:49 -0800 |
commit | 952d62991fcdb3d5eb55eb5647cda3b4b285bfe2 (patch) | |
tree | f8452a91984358d4dc27e98e823bf81a0433f575 /passes | |
parent | 6d4b6b1e69b2e332d512ed151398bb6bd8e3f3c7 (diff) | |
parent | 87e21b0122bd682db8aeffae3e1ac503c9cea2d2 (diff) | |
download | yosys-952d62991fcdb3d5eb55eb5647cda3b4b285bfe2.tar.gz yosys-952d62991fcdb3d5eb55eb5647cda3b4b285bfe2.tar.bz2 yosys-952d62991fcdb3d5eb55eb5647cda3b4b285bfe2.zip |
Merge branch 'diego/memattr' of https://github.com/dh73/yosys into diego/memattr
Diffstat (limited to 'passes')
-rw-r--r-- | passes/memory/memory_bram.cc | 91 |
1 files changed, 90 insertions, 1 deletions
diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc index aa8f94149..703e87f05 100644 --- a/passes/memory/memory_bram.cc +++ b/passes/memory/memory_bram.cc @@ -134,6 +134,9 @@ struct rules_t dict<string, int> min_limits, max_limits; bool or_next_if_better, make_transp, make_outreg; char shuffle_enable; + dict<IdString, vector<pair<IdString, Const>>> attr_match; + pair<IdString, Const> attr_val; + dict<IdString, Const> attr_unmatch; }; dict<IdString, vector<bram_t>> brams; @@ -327,6 +330,32 @@ struct rules_t continue; } + if (GetSize(tokens) >= 2 && tokens[0] == "attribute") { + if (GetSize(tokens) <=2) { + size_t notval = tokens[1].find("!"); + size_t val = tokens[1].find("="); + + if (notval != std::string::npos) { + if (val != std::string::npos) + data.attr_unmatch[RTLIL::escape_id(tokens[1].substr(1, val-1))] = tokens[1].substr(val+1); + else + data.attr_unmatch[RTLIL::escape_id(tokens[1].substr(notval+1))] = RTLIL::Const('1'); + } + continue; + } + + else if (GetSize(tokens) > 2) { + for (int idx=1; idx<= GetSize(tokens)-1; idx++) { + size_t val = tokens[idx].find("="); + if (val != std::string::npos) { + data.attr_val = make_pair(RTLIL::escape_id(tokens[idx].substr(0, val)), tokens[idx].substr(val+1)); + data.attr_match[RTLIL::escape_id(tokens[0])].push_back(data.attr_val); + } + } + continue; + } + } + syntax_error(); } } @@ -724,7 +753,7 @@ grow_read_ports:; if (match.make_transp && wr_ports <= 1) { pi.make_transp = true; if (pi.clocks != 0) { - if (wr_ports == 1 && wr_clkdom != clkdom) { + if (wr_ports == 1 && wr_clkdom != clkdom) { log(" Bram port %c%d.%d cannot have soft transparency logic added as read and write clock domains differ.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1); goto skip_bram_rport; } @@ -792,6 +821,27 @@ grow_read_ports:; log(" Updated properties: dups=%d waste=%d efficiency=%d\n", match_properties["dups"], match_properties["waste"], match_properties["efficiency"]); + for (auto iter: match.attr_match) { + for (auto iter: iter.second) { + auto it = cell->attributes.find(iter.first); + + if (iter.second.empty()) { + log(" Rule for bram type %s is rejected: requirement 'attribute %s=\"%s\"' not met.\n", + log_id(match.name), log_id(iter.first), iter.second.decode_string().c_str()); + return false; + } + + if (it != cell->attributes.end()) { + if (it->second == iter.second) + continue; + log(" Rule for bram type %s is rejected: requirement 'attribute %s=\"%s\"' not met.\n", + log_id(match.name), log_id(iter.first), iter.second.decode_string().c_str()); + return false; + } + return true; + } + } + for (auto it : match.min_limits) { if (!match_properties.count(it.first)) log_error("Unknown property '%s' in match rule for bram type %s.\n", @@ -1074,6 +1124,39 @@ void handle_cell(Cell *cell, const rules_t &rules) goto next_match_rule; } + for (auto iter: match.attr_match) { + for (auto iter: iter.second) { + auto it = cell->attributes.find(iter.first); + + if (it != cell->attributes.end()) { + if (!it->second.empty()) { + if (it->second.decode_string().length() == 1) + it->second = it->second.as_string().back(); + if (!it->second.decode_string().compare(iter.second.decode_string())) + goto attribute_matched; + else + log(" Rule for bram type %s is rejected: requirement 'attribute %s=\"%s\"' not met.\n", + log_id(match.name), log_id(iter.first), iter.second.decode_string().c_str()); + } + } + } + } + + for (auto& iter: match.attr_unmatch) { + auto it = cell->attributes.find(iter.first); + + if (it != cell->attributes.end()) { + if (!it->second.empty()) { + if (it->second.decode_string().length() == 1) + it->second = it->second.as_string().back(); + if (!it->second.decode_string().compare(iter.second.decode_string())) + goto next_match_rule; + log(" Rule for bram type %s is rejected: requirement 'attribute %s=\"%s\"' not met.\n", + log_id(match.name), log_id(iter.first), iter.second.decode_string().c_str()); + } + } + } + for (auto it : match.min_limits) { if (it.first == "waste" || it.first == "dups" || it.first == "acells" || it.first == "dcells" || it.first == "cells") continue; @@ -1100,6 +1183,7 @@ void handle_cell(Cell *cell, const rules_t &rules) goto next_match_rule; } + attribute_matched: log(" Rule #%d for bram type %s (variant %d) accepted.\n", i+1, log_id(bram.name), bram.variant); if (or_next_if_better || !best_rule_cache.empty()) @@ -1225,6 +1309,11 @@ struct MemoryBramPass : public Pass { log(" dcells ....... number of cells in 'data-direction'\n"); log(" cells ........ total number of cells (acells*dcells*dups)\n"); log("\n"); + log("A match containing the condition 'attribute' followed by a name and optional\n"); + log("value requires that the memory contains the given attribute name and value\n"); + log("(if specified) or that the attribute is not present (prepending a '!')\n"); + log("or the value is empty (if value is not specified\n)."); + log("\n"); log("The interface for the created bram instances is derived from the bram\n"); log("description. Use 'techmap' to convert the created bram instances into\n"); log("instances of the actual bram cells of your target architecture.\n"); |