From 327a5d42b6b396f1c210f1579d03a0806a261d84 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 31 Dec 2014 22:50:08 +0100 Subject: [PATCH] Progress in memory_bram --- kernel/rtlil.h | 10 +-- kernel/yosys.h | 4 ++ passes/memory/memory_bram.cc | 122 +++++++++++++++++++++++++++++++++-- techlibs/xilinx/brams.txt | 6 +- 4 files changed, 127 insertions(+), 15 deletions(-) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index c40af88aa..7618780b0 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -250,14 +250,14 @@ namespace RTLIL // of cell types). the following functions helps with that. template - bool in(T first, Args... rest) { + bool in(T first, Args... rest) const { return in(first) || in(rest...); } - bool in(IdString rhs) { return *this == rhs; } - bool in(const char *rhs) { return *this == rhs; } - bool in(const std::string &rhs) { return *this == rhs; } - bool in(const pool &rhs) { return rhs.count(*this) != 0; } + bool in(IdString rhs) const { return *this == rhs; } + bool in(const char *rhs) const { return *this == rhs; } + bool in(const std::string &rhs) const { return *this == rhs; } + bool in(const pool &rhs) const { return rhs.count(*this) != 0; } }; static inline std::string escape_id(std::string str) { diff --git a/kernel/yosys.h b/kernel/yosys.h index 88f060a52..d1e01b19c 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -137,6 +137,8 @@ YOSYS_NAMESPACE_BEGIN using std::vector; using std::string; +using std::pair; + using hashlib::mkhash; using hashlib::mkhash_init; using hashlib::mkhash_add; @@ -221,6 +223,8 @@ YOSYS_NAMESPACE_END YOSYS_NAMESPACE_BEGIN +using RTLIL::State; + namespace hashlib { template<> struct hash_ops : hash_ops {}; } diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc index 9c02866e9..1d50a9bea 100644 --- a/passes/memory/memory_bram.cc +++ b/passes/memory/memory_bram.cc @@ -24,10 +24,33 @@ PRIVATE_NAMESPACE_BEGIN struct rules_t { + struct portinfo_t { + int group, index; + int wrmode, enable, transp, clocks, clkpol; + }; + struct bram_t { IdString name; int groups, abits, dbits, init; - vector wports, rports, wenabl, transp, clocks, clkpol; + vector ports, wrmode, enable, transp, clocks, clkpol; + + vector make_portinfos() const + { + vector portinfos; + for (int i = 0; i < groups && i < GetSize(ports); i++) + for (int j = 0; j < ports[i]; j++) { + portinfo_t pi; + pi.group = i; + pi.index = j; + pi.wrmode = i < GetSize(wrmode) ? wrmode[i] : 0; + pi.enable = i < GetSize(enable) ? enable[i] : 0; + pi.transp = i < GetSize(transp) ? transp[i] : 0; + pi.clocks = i < GetSize(clocks) ? clocks[i] : 0; + pi.clkpol = i < GetSize(clkpol) ? clkpol[i] : 0; + portinfos.push_back(pi); + } + return portinfos; + } }; struct match_t { @@ -80,7 +103,7 @@ struct rules_t if (GetSize(tokens) >= 2 && tokens[0] == stmt) { value.resize(GetSize(tokens)-1); for (int i = 1; i < GetSize(tokens); i++) - value[i] = atoi(tokens[i].c_str()); + value[i-1] = atoi(tokens[i].c_str()); return true; } return false; @@ -113,13 +136,13 @@ struct rules_t if (parse_single_int("init", data.init)) continue; - if (parse_int_vect("wports", data.wports)) + if (parse_int_vect("ports", data.ports)) continue; - if (parse_int_vect("rports", data.rports)) + if (parse_int_vect("wrmode", data.wrmode)) continue; - if (parse_int_vect("wenabl", data.wenabl)) + if (parse_int_vect("enable", data.enable)) continue; if (parse_int_vect("transp", data.transp)) @@ -187,9 +210,85 @@ struct rules_t } }; -void replace_cell(Cell*, const rules_t::bram_t&, const rules_t::match_t&) +bool replace_cell(Cell *cell, const rules_t::bram_t &bram, const rules_t::match_t&) { + auto portinfos = bram.make_portinfos(); + dict> clock_domains; + vector mapped_wr_ports; + + log(" Mapping to bram type %s:\n", log_id(bram.name)); + + int wr_ports_n = cell->getParam("\\WR_PORTS").as_int(); + auto wr_clken = SigSpec(cell->getParam("\\WR_CLK_ENABLE")); + auto wr_clkpol = SigSpec(cell->getParam("\\WR_CLK_POLARITY")); + wr_clken.extend_u0(wr_ports_n); + wr_clkpol.extend_u0(wr_ports_n); + + SigSpec wr_clk = cell->getPort("\\WR_CLK"); + SigSpec wr_en = cell->getPort("\\WR_EN"); + + for (int cell_port_i = 0, bram_port_i = 0; cell_port_i < wr_ports_n; cell_port_i++) + { + bool clken = wr_clken[cell_port_i] == State::S1; + auto clkpol = wr_clkpol[cell_port_i] == State::S1; + auto clksig = wr_clk[cell_port_i]; + + pair clkdom(clksig, clkpol); + if (!clken) + clkdom = pair(State::S1, false); + + log(" Write port #%d is in clock domain %s%s.\n", + cell_port_i, clkdom.second ? "" : "!", + clken ? log_signal(clkdom.first) : "~async~"); + + for (; bram_port_i < GetSize(portinfos); bram_port_i++) + { + auto &pi = portinfos[bram_port_i]; + + if (pi.wrmode != 1) + skip_bram_wport: + continue; + + if (clken) { + if (pi.clocks == 0) { + log(" Bram port %c%d has incompatible clock type.\n", pi.group + 'A', pi.index + 1); + goto skip_bram_wport; + } + if (clock_domains.count(pi.clocks) && clock_domains.at(pi.clocks) != clkdom) { + log(" Bram port %c%d is in a different clock domain.\n", pi.group + 'A', pi.index + 1); + goto skip_bram_wport; + } + } else { + if (pi.clocks != 0) { + log(" Bram port %c%d has incompatible clock type.\n", pi.group + 'A', pi.index + 1); + goto skip_bram_wport; + } + } + + SigBit last_en_bit = State::S1; + for (int i = 0; i < bram.dbits; i++) { + if (pi.enable && i % (bram.dbits / pi.enable) == 0) + last_en_bit = wr_en[i]; + if (last_en_bit != wr_en[i]) { + log(" Bram port %c%d has incompatible enable structure.\n", pi.group + 'A', pi.index + 1); + goto skip_bram_wport; + } + } + + log(" Mapped to bram port %c%d.\n", pi.group + 'A', pi.index + 1); + if (clken) + clock_domains[pi.clocks] = clkdom; + mapped_wr_ports.push_back(bram_port_i); + goto mapped_port; + } + + log(" Failed to map write port #%d.\n", cell_port_i); + return false; + mapped_port:; + } + log(" FIXME: The core of memory_bram is not implemented yet.\n"); + return false; } void handle_cell(Cell *cell, const rules_t &rules) @@ -210,8 +309,13 @@ void handle_cell(Cell *cell, const rules_t &rules) log(" %s=%d", it.first.c_str(), it.second); log("\n"); + pool failed_brams; + for (int i = 0; i < GetSize(rules.matches); i++) { + if (rules.matches[i].name.in(failed_brams)) + continue; + for (auto it : rules.matches[i].min_limits) { if (!mem_properties.count(it.first)) log_error("Unknown property '%s' in match rule for bram type %s.\n", @@ -237,7 +341,11 @@ void handle_cell(Cell *cell, const rules_t &rules) if (!rules.brams.count(rules.matches[i].name)) log_error("No bram description for resource %s found!\n", log_id(rules.matches[i].name)); - replace_cell(cell, rules.brams.at(rules.matches[i].name), rules.matches[i]); + if (!replace_cell(cell, rules.brams.at(rules.matches[i].name), rules.matches[i])) { + log(" Mapping to bram type %s failed.\n", log_id(rules.matches[i].name)); + failed_brams.insert(rules.matches[i].name); + goto next_match_rule; + } return; next_match_rule:; diff --git a/techlibs/xilinx/brams.txt b/techlibs/xilinx/brams.txt index 03bd2b2b3..e5652eabf 100644 --- a/techlibs/xilinx/brams.txt +++ b/techlibs/xilinx/brams.txt @@ -7,9 +7,9 @@ bram XILINX_RAMB36_SDP32 abits 10 dbits 32 groups 2 - wports 1 0 - rports 0 1 - wenabl 2 0 + ports 1 1 + wrmode 1 0 + enable 4 0 transp 0 2 clocks 1 2 endbram -- 2.30.2