Added support for initialized brams

This commit is contained in:
Clifford Wolf 2015-04-06 17:06:15 +02:00
parent d19866615b
commit 169d1c4711
2 changed files with 45 additions and 9 deletions

View File

@ -474,7 +474,16 @@ struct RTLIL::Const
std::string decode_string() const; std::string decode_string() const;
inline int size() const { return bits.size(); } inline int size() const { return bits.size(); }
inline RTLIL::State operator[](int index) { return bits.at(index); } inline RTLIL::State &operator[](int index) { return bits.at(index); }
inline const RTLIL::State &operator[](int index) const { return bits.at(index); };
inline RTLIL::Const extract(int offset, int len = 1, RTLIL::State padding = RTLIL::State::S0) const {
RTLIL::Const ret;
ret.bits.reserve(len);
for (int i = offset; i < offset + len; i++)
ret.bits.push_back(i < GetSize(bits) ? bits[i] : padding);
return ret;
}
inline unsigned int hash() const { inline unsigned int hash() const {
unsigned int h = mkhash_init; unsigned int h = mkhash_init;

View File

@ -393,6 +393,16 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
int mem_width = cell->getParam("\\WIDTH").as_int(); int mem_width = cell->getParam("\\WIDTH").as_int();
// int mem_offset = cell->getParam("\\OFFSET").as_int(); // int mem_offset = cell->getParam("\\OFFSET").as_int();
bool cell_init = !SigSpec(cell->getParam("\\INIT")).is_fully_undef();
vector<Const> initdata;
if (cell_init) {
Const initparam = cell->getParam("\\INIT");
initdata.reserve(mem_size);
for (int i=0; i < mem_size; i++)
initdata.push_back(initparam.extract(mem_width*i, mem_width, State::Sx));
}
int wr_ports = cell->getParam("\\WR_PORTS").as_int(); int wr_ports = cell->getParam("\\WR_PORTS").as_int();
auto wr_clken = SigSpec(cell->getParam("\\WR_CLK_ENABLE")); auto wr_clken = SigSpec(cell->getParam("\\WR_CLK_ENABLE"));
auto wr_clkpol = SigSpec(cell->getParam("\\WR_CLK_POLARITY")); auto wr_clkpol = SigSpec(cell->getParam("\\WR_CLK_POLARITY"));
@ -789,6 +799,22 @@ grow_read_ports:;
for (auto &vp : variant_params) for (auto &vp : variant_params)
c->setParam(vp.first, vp.second); c->setParam(vp.first, vp.second);
if (cell_init) {
int init_offset = grid_a*(1 << bram.abits);
int init_shift = grid_d*bram.dbits;
int init_size = (1 << bram.abits);
Const initparam(State::Sx, init_size*bram.dbits);
for (int i = 0; i < init_size; i++) {
State padding = State::Sx;
for (int j = 0; j < bram.dbits; j++)
if (init_offset+i < GetSize(initdata) && init_shift+j < GetSize(initdata[init_offset+i]))
padding = initparam[i*bram.dbits+j] = initdata[init_offset+i][init_shift+j];
else
initparam[i*bram.dbits+j] = padding;
}
c->setParam("\\INIT", initparam);
}
for (auto &pi : portinfos) for (auto &pi : portinfos)
{ {
if (pi.dupidx != dupidx) if (pi.dupidx != dupidx)
@ -905,10 +931,7 @@ void handle_cell(Cell *cell, const rules_t &rules)
{ {
log("Processing %s.%s:\n", log_id(cell->module), log_id(cell)); log("Processing %s.%s:\n", log_id(cell->module), log_id(cell));
if (!SigSpec(cell->getParam("\\INIT")).is_fully_undef()) { bool cell_init = !SigSpec(cell->getParam("\\INIT")).is_fully_undef();
log(" initialized memories are not supported yet.");
return;
}
dict<string, int> match_properties; dict<string, int> match_properties;
match_properties["words"] = cell->getParam("\\SIZE").as_int(); match_properties["words"] = cell->getParam("\\SIZE").as_int();
@ -980,6 +1003,12 @@ void handle_cell(Cell *cell, const rules_t &rules)
log(" Metrics for %s: awaste=%d dwaste=%d bwaste=%d waste=%d efficiency=%d\n", log(" Metrics for %s: awaste=%d dwaste=%d bwaste=%d waste=%d efficiency=%d\n",
log_id(match.name), awaste, dwaste, bwaste, waste, efficiency); log_id(match.name), awaste, dwaste, bwaste, waste, efficiency);
if (cell_init && bram.init == 0) {
log(" Rule #%d for bram type %s (variant %d) rejected: cannot be initialized.\n",
i+1, log_id(bram.name), bram.variant);
goto next_match_rule;
}
for (auto it : match.min_limits) { for (auto it : match.min_limits) {
if (it.first == "waste" || it.first == "dups" || it.first == "acells" || it.first == "dcells" || it.first == "cells") if (it.first == "waste" || it.first == "dups" || it.first == "acells" || it.first == "dcells" || it.first == "cells")
continue; continue;
@ -992,6 +1021,7 @@ void handle_cell(Cell *cell, const rules_t &rules)
i+1, log_id(bram.name), bram.variant, it.first.c_str(), it.second); i+1, log_id(bram.name), bram.variant, it.first.c_str(), it.second);
goto next_match_rule; goto next_match_rule;
} }
for (auto it : match.max_limits) { for (auto it : match.max_limits) {
if (it.first == "acells" || it.first == "dcells" || it.first == "cells") if (it.first == "acells" || it.first == "dcells" || it.first == "cells")
continue; continue;
@ -1021,9 +1051,6 @@ void handle_cell(Cell *cell, const rules_t &rules)
log(" Storing for later selection.\n"); log(" Storing for later selection.\n");
best_rule_cache[pair<int, int>(i, vi)] = std::tuple<int, int, int>(match_properties["efficiency"], -match_properties["cells"], -match_properties["acells"]); best_rule_cache[pair<int, int>(i, vi)] = std::tuple<int, int, int>(match_properties["efficiency"], -match_properties["cells"], -match_properties["acells"]);
if (or_next_if_better)
goto next_match_rule;
next_match_rule: next_match_rule:
if (or_next_if_better || best_rule_cache.empty()) if (or_next_if_better || best_rule_cache.empty())
continue; continue;
@ -1075,7 +1102,7 @@ struct MemoryBramPass : public Pass {
log("rules. A block ram description looks like this:\n"); log("rules. A block ram description looks like this:\n");
log("\n"); log("\n");
log(" bram RAMB1024X32 # name of BRAM cell\n"); log(" bram RAMB1024X32 # name of BRAM cell\n");
// log(" init 1 # set to '1' if BRAM can be initialized\n"); log(" init 1 # set to '1' if BRAM can be initialized\n");
log(" abits 10 # number of address bits\n"); log(" abits 10 # number of address bits\n");
log(" dbits 32 # number of data bits\n"); log(" dbits 32 # number of data bits\n");
log(" groups 2 # number of port groups\n"); log(" groups 2 # number of port groups\n");