mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-23 09:05:32 +00:00
Merge pull request #1603 from whitequark/ice40-ram_style
ice40/ecp5: add support for both 1364.1 and Synplify/LSE RAM/ROM attributes
This commit is contained in:
commit
93ef516d91
12 changed files with 837 additions and 51 deletions
|
@ -137,9 +137,26 @@ struct rules_t
|
|||
vector<vector<std::tuple<bool,IdString,Const>>> attributes;
|
||||
};
|
||||
|
||||
bool attr_icase;
|
||||
dict<IdString, vector<bram_t>> brams;
|
||||
vector<match_t> matches;
|
||||
|
||||
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::ifstream infile;
|
||||
vector<string> tokens;
|
||||
vector<string> labels;
|
||||
|
@ -337,7 +354,7 @@ struct rules_t
|
|||
IdString key = RTLIL::escape_id(tokens[idx].substr(c1, c2));
|
||||
Const val = c2 != std::string::npos ? tokens[idx].substr(c2+1) : RTLIL::Const(1);
|
||||
|
||||
data.attributes.back().emplace_back(exists, key, val);
|
||||
data.attributes.back().emplace_back(exists, key, map_case(val));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -351,6 +368,7 @@ struct rules_t
|
|||
rewrite_filename(filename);
|
||||
infile.open(filename);
|
||||
linecount = 0;
|
||||
attr_icase = false;
|
||||
|
||||
if (infile.fail())
|
||||
log_error("Can't open rules file `%s'.\n", filename.c_str());
|
||||
|
@ -360,6 +378,11 @@ struct rules_t
|
|||
if (!labels.empty())
|
||||
syntax_error();
|
||||
|
||||
if (GetSize(tokens) == 2 && tokens[0] == "attr_icase") {
|
||||
attr_icase = atoi(tokens[1].c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tokens[0] == "bram") {
|
||||
parse_bram();
|
||||
continue;
|
||||
|
@ -843,7 +866,7 @@ grow_read_ports:;
|
|||
}
|
||||
else if (!exists)
|
||||
continue;
|
||||
if (it->second != value)
|
||||
if (rules.map_case(it->second) != value)
|
||||
continue;
|
||||
found = true;
|
||||
break;
|
||||
|
@ -855,7 +878,7 @@ grow_read_ports:;
|
|||
ss << "!";
|
||||
IdString key = std::get<1>(sums.front());
|
||||
ss << log_id(key);
|
||||
const Const &value = std::get<2>(sums.front());
|
||||
const Const &value = rules.map_case(std::get<2>(sums.front()));
|
||||
if (exists && value != Const(1))
|
||||
ss << "=\"" << value.decode_string() << "\"";
|
||||
|
||||
|
@ -1167,7 +1190,7 @@ void handle_cell(Cell *cell, const rules_t &rules)
|
|||
}
|
||||
else if (!exists)
|
||||
continue;
|
||||
if (it->second != value)
|
||||
if (rules.map_case(it->second) != value)
|
||||
continue;
|
||||
found = true;
|
||||
break;
|
||||
|
@ -1179,7 +1202,7 @@ void handle_cell(Cell *cell, const rules_t &rules)
|
|||
ss << "!";
|
||||
IdString key = std::get<1>(sums.front());
|
||||
ss << log_id(key);
|
||||
const Const &value = std::get<2>(sums.front());
|
||||
const Const &value = rules.map_case(std::get<2>(sums.front()));
|
||||
if (exists && value != Const(1))
|
||||
ss << "=\"" << value.decode_string() << "\"";
|
||||
|
||||
|
@ -1252,8 +1275,13 @@ struct MemoryBramPass : public Pass {
|
|||
log("The given rules file describes the available resources and how they should be\n");
|
||||
log("used.\n");
|
||||
log("\n");
|
||||
log("The rules file contains a set of block ram description and a sequence of match\n");
|
||||
log("rules. A block ram description looks like this:\n");
|
||||
log("The rules file contains configuration options, a set of block ram description\n");
|
||||
log("and a sequence of match rules.\n");
|
||||
log("\n");
|
||||
log("The option 'attr_icase' configures how attribute values are matched. The value 0\n");
|
||||
log("means case-sensitive, 1 means case-insensitive.\n");
|
||||
log("\n");
|
||||
log("A block ram description looks like this:\n");
|
||||
log("\n");
|
||||
log(" bram RAMB1024X32 # name of BRAM cell\n");
|
||||
log(" init 1 # set to '1' if BRAM can be initialized\n");
|
||||
|
|
|
@ -28,11 +28,32 @@ PRIVATE_NAMESPACE_BEGIN
|
|||
|
||||
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;
|
||||
|
@ -98,6 +119,36 @@ struct MemoryMapWorker
|
|||
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(ID::WR_CLK);
|
||||
RTLIL::Const clocks_pol = cell->parameters[ID::WR_CLK_POLARITY];
|
||||
|
@ -339,7 +390,7 @@ struct MemoryMapWorker
|
|||
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())
|
||||
|
@ -356,17 +407,73 @@ struct MemoryMapPass : public Pass {
|
|||
{
|
||||
// |---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;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue