30 if (a->
type ==
"$memrd" && b->
type ==
"$memrd")
32 if (a->
type ==
"$memrd" || b->
type ==
"$memrd")
33 return (a->
type ==
"$memrd") < (b->
type ==
"$memrd");
45 std::map<RTLIL::SigBit, std::pair<RTLIL::Cell*, int>>
sig_to_mux;
54 std::map<RTLIL::SigBit, bool> &state, std::set<std::map<RTLIL::SigBit, bool>> &conditions)
56 if (async_rd_bits.count(sig)) {
57 conditions.insert(state);
67 std::vector<RTLIL::SigBit> sig_a =
sigmap(cell->
getPort(
"\\A"));
68 std::vector<RTLIL::SigBit> sig_b =
sigmap(cell->
getPort(
"\\B"));
69 std::vector<RTLIL::SigBit> sig_s =
sigmap(cell->
getPort(
"\\S"));
70 std::vector<RTLIL::SigBit> sig_y =
sigmap(cell->
getPort(
"\\Y"));
73 for (
int i = 0; i < int(sig_s.size()); i++)
74 if (state.count(sig_s[i]) && state.at(sig_s[i]) ==
true) {
75 if (
find_data_feedback(async_rd_bits, sig_b.at(bit_idx + i*sig_y.size()), state, conditions)) {
84 for (
int i = 0; i < int(sig_s.size()); i++)
86 if (state.count(sig_s[i]) && state.at(sig_s[i]) ==
false)
89 std::map<RTLIL::SigBit, bool> new_state = state;
90 new_state[sig_s[i]] =
true;
92 if (
find_data_feedback(async_rd_bits, sig_b.at(bit_idx + i*sig_y.size()), new_state, conditions)) {
99 std::map<RTLIL::SigBit, bool> new_state = state;
100 for (
int i = 0; i < int(sig_s.size()); i++)
101 new_state[sig_s[i]] =
false;
118 for (
auto &cond : conditions) {
120 for (
auto &it : cond) {
125 created_conditions++;
128 if (terms.
size() > 1)
136 std::map<RTLIL::SigSpec, std::vector<std::set<RTLIL::SigBit>>> async_rd_bits;
137 std::map<RTLIL::SigBit, std::set<RTLIL::SigBit>> muxtree_upstream_map;
138 std::set<RTLIL::SigBit> non_feedback_nets;
141 if (wire_it.second->port_output) {
143 non_feedback_nets.insert(bits.begin(), bits.end());
149 bool ignore_data_port =
false;
151 if (cell->
type ==
"$mux" || cell->
type ==
"$pmux")
153 std::vector<RTLIL::SigBit> sig_a =
sigmap(cell->
getPort(
"\\A"));
154 std::vector<RTLIL::SigBit> sig_b =
sigmap(cell->
getPort(
"\\B"));
155 std::vector<RTLIL::SigBit> sig_s =
sigmap(cell->
getPort(
"\\S"));
156 std::vector<RTLIL::SigBit> sig_y =
sigmap(cell->
getPort(
"\\Y"));
158 non_feedback_nets.insert(sig_s.begin(), sig_s.end());
160 for (
int i = 0; i < int(sig_y.size()); i++) {
161 muxtree_upstream_map[sig_y[i]].insert(sig_a[i]);
162 for (
int j = 0; j < int(sig_s.size()); j++)
163 muxtree_upstream_map[sig_y[i]].insert(sig_b[i + j*sig_y.size()]);
169 if ((cell->
type ==
"$memwr" || cell->
type ==
"$memrd") &&
170 cell->
parameters.at(
"\\MEMID").decode_string() == memid)
171 ignore_data_port =
true;
173 for (
auto conn : cell_it.second->connections())
175 if (ignore_data_port && conn.first ==
"\\DATA")
177 std::vector<RTLIL::SigBit> bits =
sigmap(conn.second);
178 non_feedback_nets.insert(bits.begin(), bits.end());
182 std::set<RTLIL::SigBit> expand_non_feedback_nets = non_feedback_nets;
183 while (!expand_non_feedback_nets.empty())
185 std::set<RTLIL::SigBit> new_expand_non_feedback_nets;
187 for (
auto &bit : expand_non_feedback_nets)
188 if (muxtree_upstream_map.count(bit))
189 for (
auto &new_bit : muxtree_upstream_map.at(bit))
190 if (!non_feedback_nets.count(new_bit)) {
191 non_feedback_nets.insert(new_bit);
192 new_expand_non_feedback_nets.insert(new_bit);
195 expand_non_feedback_nets.swap(new_expand_non_feedback_nets);
198 for (
auto cell : rd_ports)
200 if (cell->parameters.at(
"\\CLK_ENABLE").as_bool())
204 std::vector<RTLIL::SigBit> sig_data =
sigmap(cell->getPort(
"\\DATA"));
206 for (
int i = 0; i < int(sig_data.size()); i++)
207 if (non_feedback_nets.count(sig_data[i]))
208 goto not_pure_feedback_port;
210 async_rd_bits[sig_addr].resize(std::max(async_rd_bits.size(), sig_data.size()));
211 for (
int i = 0; i < int(sig_data.size()); i++)
212 async_rd_bits[sig_addr][i].insert(sig_data[i]);
214 not_pure_feedback_port:;
217 if (async_rd_bits.empty())
220 log(
"Populating enable bits on write ports of memory %s.%s with aync read feedback:\n",
log_id(
module),
log_id(memid));
222 for (
auto cell : wr_ports)
225 if (!async_rd_bits.count(sig_addr))
228 log(
" Analyzing write port %s.\n",
log_id(cell));
230 std::vector<RTLIL::SigBit> cell_data = cell->getPort(
"\\DATA");
231 std::vector<RTLIL::SigBit> cell_en = cell->getPort(
"\\EN");
233 int created_conditions = 0;
234 for (
int i = 0; i < int(cell_data.size()); i++)
237 std::map<RTLIL::SigBit, bool> state;
238 std::set<std::map<RTLIL::SigBit, bool>> conditions;
240 if (cell_en[i].wire !=
NULL) {
241 state[cell_en[i]] =
false;
242 conditions.insert(state);
245 find_data_feedback(async_rd_bits.at(sig_addr).at(i), cell_data[i], state, conditions);
249 if (created_conditions) {
250 log(
" Added enable logic for %d different cases.\n", created_conditions);
251 cell->setPort(
"\\EN", cell_en);
275 std::vector<RTLIL::SigBit> v_bits = bits;
276 std::vector<RTLIL::SigBit> v_mask_bits = mask_bits;
278 std::map<std::pair<RTLIL::SigBit, RTLIL::SigBit>, std::pair<int, std::vector<int>>> groups;
281 for (
int i = 0; i < bits.
size(); i++) {
282 std::pair<RTLIL::SigBit, RTLIL::SigBit> key(v_bits[i], v_mask_bits[i]);
283 if (groups.count(key) == 0) {
284 groups[key].first = grouped_bits.
size();
288 groups[key].second.push_back(i);
291 std::vector<RTLIL::SigBit> grouped_result =
mask_en_naive(do_mask, grouped_bits, grouped_mask_bits);
294 for (
int i = 0; i < bits.
size(); i++) {
295 std::pair<RTLIL::SigBit, RTLIL::SigBit> key(v_bits[i], v_mask_bits[i]);
296 result.
append_bit(grouped_result.at(groups.at(key).first));
304 std::vector<RTLIL::SigBit> v_old_en = merged_en;
305 std::vector<RTLIL::SigBit> v_next_en = next_en;
310 std::map<std::pair<RTLIL::SigBit, RTLIL::SigBit>,
int> groups;
311 std::vector<RTLIL::SigBit> grouped_old_en, grouped_next_en;
314 for (
int i = 0; i < int(v_old_en.size()); i++) {
315 std::pair<RTLIL::SigBit, RTLIL::SigBit> key(v_old_en[i], v_next_en[i]);
316 if (groups.count(key) == 0) {
317 groups[key] = grouped_old_en.size();
318 grouped_old_en.push_back(key.first);
319 grouped_next_en.push_back(key.second);
323 std::vector<RTLIL::SigBit> grouped_new_en =
module->
Or(
NEW_ID, grouped_old_en, grouped_next_en);
325 for (
int i = 0; i < int(v_old_en.size()); i++) {
326 std::pair<RTLIL::SigBit, RTLIL::SigBit> key(v_old_en[i], v_next_en[i]);
327 new_merged_en.
append_bit(grouped_new_en.at(groups.at(key)));
340 new_merged_data =
module->
Or(
NEW_ID, new_merged_data, old_data_set);
343 new_merged_data =
module->
Or(
NEW_ID, new_merged_data, new_data_set);
348 merged_en = new_merged_en;
349 merged_data = new_merged_data;
354 if (wr_ports.size() <= 1)
359 std::map<RTLIL::SigSpec, int> last_port_by_addr;
360 std::vector<std::vector<bool>> active_bits_on_port;
362 bool cache_clk_enable =
false;
363 bool cache_clk_polarity =
false;
366 for (
int i = 0; i < int(wr_ports.size()); i++)
371 if (cell->
parameters.at(
"\\CLK_ENABLE").as_bool() != cache_clk_enable ||
372 (cache_clk_enable && (
sigmap(cell->
getPort(
"\\CLK")) != cache_clk ||
373 cell->
parameters.at(
"\\CLK_POLARITY").as_bool() != cache_clk_polarity)))
375 cache_clk_enable = cell->
parameters.at(
"\\CLK_ENABLE").as_bool();
376 cache_clk_polarity = cell->
parameters.at(
"\\CLK_POLARITY").as_bool();
378 last_port_by_addr.
clear();
380 if (cache_clk_enable)
381 log(
" New clock domain: %s %s\n", cache_clk_polarity ?
"posedge" :
"negedge",
log_signal(cache_clk));
383 log(
" New clock domain: unclocked\n");
388 log(
" Active bits: ");
389 std::vector<RTLIL::SigBit> en_bits =
sigmap(cell->
getPort(
"\\EN"));
390 active_bits_on_port.push_back(std::vector<bool>(en_bits.size()));
391 for (
int k =
int(en_bits.size())-1; k >= 0; k--) {
393 log(
"%c", active_bits_on_port[i][k] ?
'1' :
'0');
397 if (last_port_by_addr.count(addr))
399 int last_i = last_port_by_addr.at(addr);
400 log(
" Merging port %d into this one.\n", last_i);
402 bool found_overlapping_bits =
false;
403 for (
int k = 0; k < int(en_bits.size()); k++) {
404 if (active_bits_on_port[i][k] && active_bits_on_port[last_i][k])
405 found_overlapping_bits =
true;
406 active_bits_on_port[i][k] = active_bits_on_port[i][k] || active_bits_on_port[last_i][k];
419 for (
int j = last_i+1; j < i; j++)
421 if (wr_ports[j] ==
NULL)
424 for (
int k = 0; k < int(en_bits.size()); k++)
425 if (active_bits_on_port[i][k] && active_bits_on_port[j][k])
426 goto found_overlapping_bits_i_j;
429 found_overlapping_bits_i_j:
430 log(
" Creating collosion-detect logic for port %d.\n", j);
440 if (found_overlapping_bits) {
441 log(
" Creating logic for merging DATA and EN ports.\n");
446 for (
int k = 0; k < int(en_bits.size()); k++)
447 if (!active_bits_on_port[last_i][k]) {
449 merged_data.
replace(k, cell_data.extract(k, 1));
455 cell->
setPort(
"\\EN", merged_en);
456 cell->
setPort(
"\\DATA", merged_data);
459 wr_ports[last_i] =
NULL;
461 log(
" Active bits: ");
462 std::vector<RTLIL::SigBit> en_bits =
sigmap(cell->
getPort(
"\\EN"));
463 active_bits_on_port.push_back(std::vector<bool>(en_bits.size()));
464 for (
int k =
int(en_bits.size())-1; k >= 0; k--)
465 log(
"%c", active_bits_on_port[i][k] ?
'1' :
'0');
469 last_port_by_addr[addr] = i;
474 std::vector<RTLIL::Cell*> wr_ports_with_nulls;
475 wr_ports_with_nulls.swap(wr_ports);
477 for (
auto cell : wr_ports_with_nulls)
479 wr_ports.push_back(cell);
489 if (wr_ports.size() <= 1)
497 std::set<int> considered_ports;
498 std::set<int> considered_port_pairs;
500 for (
int i = 0; i < int(wr_ports.size()); i++) {
501 std::vector<RTLIL::SigBit> bits =
modwalker.
sigmap(wr_ports[i]->getPort(
"\\EN"));
502 for (
auto bit : bits)
504 goto port_is_always_active;
506 considered_ports.insert(i);
507 port_is_always_active:;
510 log(
"Consolidating write ports of memory %s.%s using sat-based resource sharing:\n",
log_id(
module),
log_id(memid));
512 bool cache_clk_enable =
false;
513 bool cache_clk_polarity =
false;
516 for (
int i = 0; i < int(wr_ports.size()); i++)
520 if (cell->
parameters.at(
"\\CLK_ENABLE").as_bool() != cache_clk_enable ||
521 (cache_clk_enable && (
sigmap(cell->
getPort(
"\\CLK")) != cache_clk ||
522 cell->
parameters.at(
"\\CLK_POLARITY").as_bool() != cache_clk_polarity)))
524 cache_clk_enable = cell->
parameters.at(
"\\CLK_ENABLE").as_bool();
525 cache_clk_polarity = cell->
parameters.at(
"\\CLK_POLARITY").as_bool();
528 else if (i > 0 && considered_ports.count(i-1) && considered_ports.count(i))
529 considered_port_pairs.insert(i);
531 if (cache_clk_enable)
532 log(
" Port %d (%s) on %s %s: %s\n", i,
log_id(cell),
533 cache_clk_polarity ?
"posedge" :
"negedge",
log_signal(cache_clk),
534 considered_ports.count(i) ?
"considered" :
"not considered");
536 log(
" Port %d (%s) unclocked: %s\n", i,
log_id(cell),
537 considered_ports.count(i) ?
"considered" :
"not considered");
540 if (considered_port_pairs.size() < 1) {
541 log(
" No two subsequent ports in same clock domain considered -> nothing to consolidate.\n");
547 std::set<RTLIL::Cell*> sat_cells;
548 std::set<RTLIL::SigBit> bits_queue;
549 std::map<int, int> port_to_sat_variable;
551 for (
int i = 0; i < int(wr_ports.size()); i++)
552 if (considered_port_pairs.count(i) || considered_port_pairs.count(i+1))
555 port_to_sat_variable[i] = ez.expression(ez.OpOr, satgen.
importSigSpec(sig));
557 std::vector<RTLIL::SigBit> bits = sig;
558 bits_queue.insert(bits.begin(), bits.end());
561 while (!bits_queue.empty())
563 std::set<ModWalker::PortBit> portbits;
567 for (
auto &pbit : portbits)
570 bits_queue.insert(cell_inputs.begin(), cell_inputs.end());
571 sat_cells.insert(pbit.cell);
575 log(
" Common input cone for all EN signals: %d cells.\n",
int(sat_cells.size()));
577 for (
auto cell : sat_cells)
580 log(
" Size of unconstrained SAT problem: %d variables, %d clauses\n", ez.numCnfVariables(), ez.numCnfClauses());
584 for (
int i = 0; i < int(wr_ports.size()); i++)
586 if (!considered_port_pairs.count(i))
589 if (ez.solve(port_to_sat_variable.at(i-1), port_to_sat_variable.at(i))) {
590 log(
" According to SAT solver sharing of port %d with port %d is not possible.\n", i-1, i);
594 log(
" Merging port %d into port %d.\n", i-1, i);
595 port_to_sat_variable.at(i) = ez.OR(port_to_sat_variable.at(i-1), port_to_sat_variable.at(i));
599 std::vector<RTLIL::SigBit> last_en =
modwalker.
sigmap(wr_ports[i-1]->getPort(
"\\EN"));
603 std::vector<RTLIL::SigBit> this_en =
modwalker.
sigmap(wr_ports[i]->getPort(
"\\EN"));
607 wr_ports[i]->setPort(
"\\ADDR",
module->
Mux(
NEW_ID, last_addr, this_addr, this_en_active));
608 wr_ports[i]->setPort(
"\\DATA",
module->
Mux(
NEW_ID, last_data, this_data, this_en_active));
610 std::map<std::pair<RTLIL::SigBit, RTLIL::SigBit>,
int> groups_en;
614 for (
int j = 0; j < int(this_en.size()); j++) {
615 std::pair<RTLIL::SigBit, RTLIL::SigBit> key(last_en[j], this_en[j]);
616 if (!groups_en.count(key)) {
619 groups_en[key] = grouped_en->
width;
626 wr_ports[i]->
setPort(
"\\EN", en);
629 wr_ports[i-1] =
NULL;
634 std::vector<RTLIL::Cell*> wr_ports_with_nulls;
635 wr_ports_with_nulls.swap(wr_ports);
637 for (
auto cell : wr_ports_with_nulls)
639 wr_ports.push_back(cell);
648 design(design), module(module),
sigmap(module)
650 std::map<std::string, std::pair<std::vector<RTLIL::Cell*>, std::vector<RTLIL::Cell*>>> memindex;
653 for (
auto &it : module->
cells_)
657 if (cell->
type ==
"$memrd")
658 memindex[cell->
parameters.at(
"\\MEMID").decode_string()].first.push_back(cell);
660 if (cell->
type ==
"$memwr")
661 memindex[cell->
parameters.at(
"\\MEMID").decode_string()].second.push_back(cell);
663 if (cell->
type ==
"$mux")
670 else if (sig_b.is_fully_undef())
674 if (cell->
type ==
"$mux" || cell->
type ==
"$pmux")
676 std::vector<RTLIL::SigBit> sig_y =
sigmap(cell->
getPort(
"\\Y"));
677 for (
int i = 0; i < int(sig_y.size()); i++)
678 sig_to_mux[sig_y[i]] = std::pair<RTLIL::Cell*, int>(cell, i);
682 for (
auto &it : memindex) {
703 for (
auto &it : memindex)
714 log(
" memory_share [selection]\n");
716 log(
"This pass merges share-able memory ports into single memory ports.\n");
718 log(
"The following methods are used to consolidate the number of memory ports:\n");
720 log(
" - When write ports are connected to async read ports accessing the same\n");
721 log(
" address, then this feedback path is converted to a write port with\n");
722 log(
" byte/part enable signals.\n");
724 log(
" - When multiple write ports access the same address then this is converted\n");
725 log(
" to a single write port with a more complex data and/or enable logic path.\n");
727 log(
" - When multiple write ports are never accessed at the same time (a SAT\n");
728 log(
" solver is used to determine this), then the ports are merged into a single\n");
729 log(
" write port.\n");
731 log(
"Note that in addition to the algorithms implemented in this pass, the $memrd\n");
732 log(
"and $memwr cells are also subject to generic resource sharing passes (and other\n");
733 log(
"optimizations) such as opt_share.\n");
737 log_header(
"Executing MEMORY_SHARE pass (consolidating $memrc/$memwr cells).\n");
USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN bool memcells_cmp(RTLIL::Cell *a, RTLIL::Cell *b)
void translate_rd_feedback_to_en(std::string memid, std::vector< RTLIL::Cell * > &rd_ports, std::vector< RTLIL::Cell * > &wr_ports)
bool is_fully_undef() const
virtual void execute(std::vector< std::string > args, RTLIL::Design *design)
void sort(T *array, int size, LessThan lt)
RTLIL::SigSpec Ne(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed=false)
void consolidate_wr_using_sat(std::string memid, std::vector< RTLIL::Cell * > &wr_ports)
void log_header(const char *format,...)
bool has_drivers(const T &sig) const
RTLIL::SigSpec mask_en_naive(RTLIL::SigSpec do_mask, RTLIL::SigSpec bits, RTLIL::SigSpec mask_bits)
std::map< RTLIL::IdString, RTLIL::Wire * > wires_
const char * log_signal(const RTLIL::SigSpec &sig, bool autoint)
void setPort(RTLIL::IdString portname, RTLIL::SigSpec signal)
RTLIL::SigSpec Mux(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s)
RTLIL::Cell * addEq(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed=false)
std::vector< int > importSigSpec(RTLIL::SigSpec sig, int timestep=-1)
std::map< RTLIL::IdString, RTLIL::Const > parameters
bool get_drivers(std::set< PortBit > &result, RTLIL::SigBit bit) const
MemorySharePass MemorySharePass
RTLIL::SigSpec Or(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed=false)
bool find_data_feedback(const std::set< RTLIL::SigBit > &async_rd_bits, RTLIL::SigBit sig, std::map< RTLIL::SigBit, bool > &state, std::set< std::map< RTLIL::SigBit, bool >> &conditions)
MemoryShareWorker(RTLIL::Design *design, RTLIL::Module *module)
YOSYS_NAMESPACE_BEGIN typedef ezMiniSAT ezDefaultSAT
std::map< RTLIL::IdString, CellType > cell_types
bool cell_known(RTLIL::IdString type)
void append_bit(const RTLIL::SigBit &bit)
#define PRIVATE_NAMESPACE_BEGIN
const RTLIL::SigSpec & getPort(RTLIL::IdString portname) const
#define log_assert(_assert_expr_)
RTLIL::Wire * addWire(RTLIL::IdString name, int width=1)
std::map< RTLIL::Cell *, std::set< RTLIL::SigBit > > cell_inputs
#define PRIVATE_NAMESPACE_END
void consolidate_wr_by_addr(std::string memid, std::vector< RTLIL::Cell * > &wr_ports)
#define USING_YOSYS_NAMESPACE
void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with)
void setup(RTLIL::Design *design, RTLIL::Module *module, CellTypes *filter_ct=NULL)
std::map< RTLIL::IdString, RTLIL::Cell * > cells_
void remove(const std::set< RTLIL::Wire * > &wires)
RTLIL::SigSpec ReduceOr(RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed=false)
RTLIL::Cell * addMux(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s, RTLIL::SigSpec sig_y)
void log(const char *format,...)
RTLIL::SigSpec mask_en_grouped(RTLIL::SigSpec do_mask, RTLIL::SigSpec bits, RTLIL::SigSpec mask_bits)
bool importCell(RTLIL::Cell *cell, int timestep=-1)
RTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other=NULL) const
RTLIL::SigSpec And(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed=false)
void append(const RTLIL::SigSpec &signal)
std::vector< RTLIL::Module * > selected_modules() const
void add(RTLIL::SigSpec from, RTLIL::SigSpec to)
std::map< RTLIL::SigBit, std::pair< RTLIL::Cell *, int > > sig_to_mux
void merge_en_data(RTLIL::SigSpec &merged_en, RTLIL::SigSpec &merged_data, RTLIL::SigSpec next_en, RTLIL::SigSpec next_data)
void extra_args(std::vector< std::string > args, size_t argidx, RTLIL::Design *design, bool select=true)
RTLIL::SigBit conditions_to_logic(std::set< std::map< RTLIL::SigBit, bool >> &conditions, int &created_conditions)
RTLIL::SigSpec Not(RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed=false)
const char * log_id(RTLIL::IdString str)
RTLIL::SigSpec ReduceAnd(RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed=false)
std::map< std::set< std::map< RTLIL::SigBit, bool > >, RTLIL::SigBit > conditions_logic_cache