struct MemoryMapWorker
{
+ bool attr_icase = false;
+ dict<RTLIL::IdString, std::vector<RTLIL::Const>> attributes;
+
RTLIL::Design *design;
RTLIL::Module *module;
std::map<std::pair<RTLIL::SigSpec, RTLIL::SigSpec>, RTLIL::SigBit> decoder_cache;
+ MemoryMapWorker(RTLIL::Design *design, RTLIL::Module *module) : design(design), module(module) {}
+
+ std::string map_case(std::string value) const
+ {
+ if (attr_icase) {
+ for (char &c : value)
+ c = tolower(c);
+ }
+ return value;
+ }
+
+ RTLIL::Const map_case(RTLIL::Const value) const
+ {
+ if (value.flags & RTLIL::CONST_FLAG_STRING)
+ return map_case(value.decode_string());
+ return value;
+ }
+
std::string genid(RTLIL::IdString name, std::string token1 = "", int i = -1, std::string token2 = "", int j = -1, std::string token3 = "", int k = -1, std::string token4 = "")
{
std::stringstream sstr;
return;
}
+ // check if attributes allow us to infer FFRAM for this cell
+ for (const auto &attr : attributes) {
+ if (cell->attributes.count(attr.first)) {
+ const auto &cell_attr = cell->attributes[attr.first];
+ if (attr.second.empty()) {
+ log("Not mapping memory cell %s in module %s (attribute %s is set).\n",
+ cell->name.c_str(), module->name.c_str(), attr.first.c_str());
+ return;
+ }
+
+ bool found = false;
+ for (auto &value : attr.second) {
+ if (map_case(cell_attr) == map_case(value)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ if (cell_attr.flags & RTLIL::CONST_FLAG_STRING) {
+ log("Not mapping memory cell %s in module %s (attribute %s is set to \"%s\").\n",
+ cell->name.c_str(), module->name.c_str(), attr.first.c_str(), cell_attr.decode_string().c_str());
+ } else {
+ log("Not mapping memory cell %s in module %s (attribute %s is set to %d).\n",
+ cell->name.c_str(), module->name.c_str(), attr.first.c_str(), cell_attr.as_int());
+ }
+ return;
+ }
+ }
+ }
+
// all write ports must share the same clock
RTLIL::SigSpec clocks = cell->getPort("\\WR_CLK");
RTLIL::Const clocks_pol = cell->parameters["\\WR_CLK_POLARITY"];
module->remove(cell);
}
- MemoryMapWorker(RTLIL::Design *design, RTLIL::Module *module) : design(design), module(module)
+ void run()
{
std::vector<RTLIL::Cell*> cells;
for (auto cell : module->selected_cells())
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" memory_map [selection]\n");
+ log(" memory_map [options] [selection]\n");
log("\n");
log("This pass converts multiport memory cells as generated by the memory_collect\n");
log("pass to word-wide DFFs and address decoders.\n");
log("\n");
+ log(" -attr !<name>\n");
+ log(" do not map memories that have attribute <name> set.\n");
+ log("\n");
+ log(" -attr <name>[=<value>]\n");
+ log(" for memories that have attribute <name> set, only map them if its value\n");
+ log(" is a string <value> (if specified), or an integer 1 (otherwise). if this\n");
+ log(" option is specified multiple times, map the memory if the attribute is\n");
+ log(" to any of the values.\n");
+ log("\n");
+ log(" -iattr\n");
+ log(" for -attr, ignore case of <value>.\n");
+ log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE {
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ bool attr_icase = false;
+ dict<RTLIL::IdString, std::vector<RTLIL::Const>> attributes;
+
log_header(design, "Executing MEMORY_MAP pass (converting $mem cells to logic and flip-flops).\n");
- extra_args(args, 1, design);
- for (auto mod : design->selected_modules())
- MemoryMapWorker(design, mod);
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-attr" && argidx + 1 < args.size())
+ {
+ std::string attr_arg = args[++argidx];
+ std::string name;
+ RTLIL::Const value;
+ size_t eq_at = attr_arg.find('=');
+ if (eq_at != std::string::npos) {
+ name = attr_arg.substr(0, eq_at);
+ value = attr_arg.substr(eq_at + 1);
+ } else {
+ name = attr_arg;
+ value = RTLIL::Const(1);
+ }
+ if (attr_arg.size() > 1 && attr_arg[0] == '!') {
+ if (value != RTLIL::Const(1)) {
+ --argidx;
+ break; // we don't support -attr !<name>=<value>
+ }
+ attributes[RTLIL::escape_id(name.substr(1))].clear();
+ } else {
+ attributes[RTLIL::escape_id(name)].push_back(value);
+ }
+ continue;
+ }
+ if (args[argidx] == "-iattr")
+ {
+ attr_icase = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto mod : design->selected_modules()) {
+ MemoryMapWorker worker(design, mod);
+ worker.attr_icase = attr_icase;
+ worker.attributes = attributes;
+ worker.run();
+ }
}
} MemoryMapPass;