2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include "kernel/rtlil.h"
21 #include "kernel/satgen.h"
22 #include "kernel/sigtools.h"
23 #include "kernel/modwalker.h"
24 #include "kernel/register.h"
25 #include "kernel/log.h"
28 static bool memcells_cmp(RTLIL::Cell
*a
, RTLIL::Cell
*b
)
30 if (a
->type
== "$memrd" && b
->type
== "$memrd")
31 return a
->name
< b
->name
;
32 if (a
->type
== "$memrd" || b
->type
== "$memrd")
33 return (a
->type
== "$memrd") < (b
->type
== "$memrd");
34 return a
->parameters
.at("\\PRIORITY").as_int() < b
->parameters
.at("\\PRIORITY").as_int();
37 struct MemoryShareWorker
39 RTLIL::Design
*design
;
40 RTLIL::Module
*module
;
41 SigMap sigmap
, sigmap_xmux
;
45 std::map
<RTLIL::SigBit
, std::pair
<RTLIL::Cell
*, int>> sig_to_mux
;
46 std::map
<std::set
<std::map
<RTLIL::SigBit
, bool>>, RTLIL::SigBit
> conditions_logic_cache
;
49 // -----------------------------------------------------------------
50 // Converting feedbacks to async read ports to proper enable signals
51 // -----------------------------------------------------------------
53 bool find_data_feedback(const std::set
<RTLIL::SigBit
> &async_rd_bits
, RTLIL::SigBit sig
,
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
);
61 if (sig_to_mux
.count(sig
) == 0)
64 RTLIL::Cell
*cell
= sig_to_mux
.at(sig
).first
;
65 int bit_idx
= sig_to_mux
.at(sig
).second
;
67 std::vector
<RTLIL::SigBit
> sig_a
= sigmap(cell
->connections
.at("\\A"));
68 std::vector
<RTLIL::SigBit
> sig_b
= sigmap(cell
->connections
.at("\\B"));
69 std::vector
<RTLIL::SigBit
> sig_s
= sigmap(cell
->connections
.at("\\S"));
70 std::vector
<RTLIL::SigBit
> sig_y
= sigmap(cell
->connections
.at("\\Y"));
71 log_assert(sig_y
.at(bit_idx
) == sig
);
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
))
76 cell
->connections
.at("\\B").replace(bit_idx
+ i
*sig_y
.size(), RTLIL::State::Sx
);
81 for (int i
= 0; i
< int(sig_s
.size()); i
++)
83 if (state
.count(sig_s
[i
]) && state
.at(sig_s
[i
]) == false)
86 std::map
<RTLIL::SigBit
, bool> new_state
= state
;
87 new_state
[sig_s
[i
]] = true;
89 if (find_data_feedback(async_rd_bits
, sig_b
.at(bit_idx
+ i
*sig_y
.size()), new_state
, conditions
))
90 cell
->connections
.at("\\B").replace(bit_idx
+ i
*sig_y
.size(), RTLIL::State::Sx
);
93 std::map
<RTLIL::SigBit
, bool> new_state
= state
;
94 for (int i
= 0; i
< int(sig_s
.size()); i
++)
95 new_state
[sig_s
[i
]] = false;
97 if (find_data_feedback(async_rd_bits
, sig_a
.at(bit_idx
), new_state
, conditions
))
98 cell
->connections
.at("\\A").replace(bit_idx
, RTLIL::State::Sx
);
103 RTLIL::SigBit
conditions_to_logic(std::set
<std::map
<RTLIL::SigBit
, bool>> &conditions
, int &created_conditions
)
105 if (conditions_logic_cache
.count(conditions
))
106 return conditions_logic_cache
.at(conditions
);
108 RTLIL::SigSpec terms
;
109 for (auto &cond
: conditions
) {
110 RTLIL::SigSpec sig1
, sig2
;
111 for (auto &it
: cond
) {
112 sig1
.append_bit(it
.first
);
113 sig2
.append_bit(it
.second
? RTLIL::State::S1
: RTLIL::State::S0
);
115 terms
.append(module
->Ne(NEW_ID
, sig1
, sig2
));
116 created_conditions
++;
119 if (terms
.__width
> 1)
120 terms
= module
->ReduceAnd(NEW_ID
, terms
);
122 return conditions_logic_cache
[conditions
] = terms
;
125 void translate_rd_feedback_to_en(std::string memid
, std::vector
<RTLIL::Cell
*> &rd_ports
, std::vector
<RTLIL::Cell
*> &wr_ports
)
127 std::map
<RTLIL::SigSpec
, std::vector
<std::set
<RTLIL::SigBit
>>> async_rd_bits
;
128 std::map
<RTLIL::SigBit
, std::set
<RTLIL::SigBit
>> muxtree_upstream_map
;
129 std::set
<RTLIL::SigBit
> non_feedback_nets
;
131 for (auto wire_it
: module
->wires
)
132 if (wire_it
.second
->port_output
) {
133 std::vector
<RTLIL::SigBit
> bits
= RTLIL::SigSpec(wire_it
.second
);
134 non_feedback_nets
.insert(bits
.begin(), bits
.end());
137 for (auto cell_it
: module
->cells
)
139 RTLIL::Cell
*cell
= cell_it
.second
;
140 bool ignore_data_port
= false;
142 if (cell
->type
== "$mux" || cell
->type
== "$pmux")
144 std::vector
<RTLIL::SigBit
> sig_a
= sigmap(cell
->connections
.at("\\A"));
145 std::vector
<RTLIL::SigBit
> sig_b
= sigmap(cell
->connections
.at("\\B"));
146 std::vector
<RTLIL::SigBit
> sig_s
= sigmap(cell
->connections
.at("\\S"));
147 std::vector
<RTLIL::SigBit
> sig_y
= sigmap(cell
->connections
.at("\\Y"));
149 non_feedback_nets
.insert(sig_s
.begin(), sig_s
.end());
151 for (int i
= 0; i
< int(sig_y
.size()); i
++) {
152 muxtree_upstream_map
[sig_y
[i
]].insert(sig_a
[i
]);
153 for (int j
= 0; j
< int(sig_s
.size()); j
++)
154 muxtree_upstream_map
[sig_y
[i
]].insert(sig_b
[i
+ j
*sig_y
.size()]);
160 if ((cell
->type
== "$memwr" || cell
->type
== "$memrd") &&
161 cell
->parameters
.at("\\MEMID").decode_string() == memid
)
162 ignore_data_port
= true;
164 for (auto conn
: cell_it
.second
->connections
)
166 if (ignore_data_port
&& conn
.first
== "\\DATA")
168 std::vector
<RTLIL::SigBit
> bits
= sigmap(conn
.second
);
169 non_feedback_nets
.insert(bits
.begin(), bits
.end());
173 std::set
<RTLIL::SigBit
> expand_non_feedback_nets
= non_feedback_nets
;
174 while (!expand_non_feedback_nets
.empty())
176 std::set
<RTLIL::SigBit
> new_expand_non_feedback_nets
;
178 for (auto &bit
: expand_non_feedback_nets
)
179 if (muxtree_upstream_map
.count(bit
))
180 for (auto &new_bit
: muxtree_upstream_map
.at(bit
))
181 if (!non_feedback_nets
.count(new_bit
)) {
182 non_feedback_nets
.insert(new_bit
);
183 new_expand_non_feedback_nets
.insert(new_bit
);
186 expand_non_feedback_nets
.swap(new_expand_non_feedback_nets
);
189 for (auto cell
: rd_ports
)
191 if (cell
->parameters
.at("\\CLK_ENABLE").as_bool())
194 RTLIL::SigSpec sig_addr
= sigmap(cell
->connections
.at("\\ADDR"));
195 std::vector
<RTLIL::SigBit
> sig_data
= sigmap(cell
->connections
.at("\\DATA"));
197 for (int i
= 0; i
< int(sig_data
.size()); i
++)
198 if (non_feedback_nets
.count(sig_data
[i
]))
199 goto not_pure_feedback_port
;
201 async_rd_bits
[sig_addr
].resize(std::max(async_rd_bits
.size(), sig_data
.size()));
202 for (int i
= 0; i
< int(sig_data
.size()); i
++)
203 async_rd_bits
[sig_addr
][i
].insert(sig_data
[i
]);
205 not_pure_feedback_port
:;
208 if (async_rd_bits
.empty())
211 log("Populating enable bits on write ports of memory %s.%s with aync read feedback:\n", log_id(module
), log_id(memid
));
213 for (auto cell
: wr_ports
)
215 RTLIL::SigSpec sig_addr
= sigmap_xmux(cell
->connections
.at("\\ADDR"));
216 if (!async_rd_bits
.count(sig_addr
))
219 log(" Analyzing write port %s.\n", log_id(cell
));
221 std::vector
<RTLIL::SigBit
> cell_data
= cell
->connections
.at("\\DATA");
222 std::vector
<RTLIL::SigBit
> cell_en
= cell
->connections
.at("\\EN");
224 int created_conditions
= 0;
225 for (int i
= 0; i
< int(cell_data
.size()); i
++)
226 if (cell_en
[i
] != RTLIL::SigBit(RTLIL::State::S0
))
228 std::map
<RTLIL::SigBit
, bool> state
;
229 std::set
<std::map
<RTLIL::SigBit
, bool>> conditions
;
231 if (cell_en
[i
].wire
!= NULL
) {
232 state
[cell_en
[i
]] = false;
233 conditions
.insert(state
);
236 find_data_feedback(async_rd_bits
.at(sig_addr
).at(i
), cell_data
[i
], state
, conditions
);
237 cell_en
[i
] = conditions_to_logic(conditions
, created_conditions
);
240 if (created_conditions
) {
241 log(" Added enable logic for %d different cases.\n", created_conditions
);
242 cell
->connections
.at("\\EN") = cell_en
;
248 // ------------------------------------------------------
249 // Consolidate write ports that write to the same address
250 // ------------------------------------------------------
252 RTLIL::SigSpec
mask_en_naive(RTLIL::SigSpec do_mask
, RTLIL::SigSpec bits
, RTLIL::SigSpec mask_bits
)
254 // this is the naive version of the function that does not care about grouping the EN bits.
256 RTLIL::SigSpec inv_mask_bits
= module
->Not(NEW_ID
, mask_bits
);
257 RTLIL::SigSpec inv_mask_bits_filtered
= module
->Mux(NEW_ID
, RTLIL::SigSpec(RTLIL::State::S1
, bits
.__width
), inv_mask_bits
, do_mask
);
258 RTLIL::SigSpec result
= module
->And(NEW_ID
, inv_mask_bits_filtered
, bits
);
262 RTLIL::SigSpec
mask_en_grouped(RTLIL::SigSpec do_mask
, RTLIL::SigSpec bits
, RTLIL::SigSpec mask_bits
)
264 // this version of the function preserves the bit grouping in the EN bits.
266 std::vector
<RTLIL::SigBit
> v_bits
= bits
;
267 std::vector
<RTLIL::SigBit
> v_mask_bits
= mask_bits
;
269 std::map
<std::pair
<RTLIL::SigBit
, RTLIL::SigBit
>, std::pair
<int, std::vector
<int>>> groups
;
270 RTLIL::SigSpec grouped_bits
, grouped_mask_bits
;
272 for (int i
= 0; i
< bits
.__width
; i
++) {
273 std::pair
<RTLIL::SigBit
, RTLIL::SigBit
> key(v_bits
[i
], v_mask_bits
[i
]);
274 if (groups
.count(key
) == 0) {
275 groups
[key
].first
= grouped_bits
.__width
;
276 grouped_bits
.append_bit(v_bits
[i
]);
277 grouped_mask_bits
.append_bit(v_mask_bits
[i
]);
279 groups
[key
].second
.push_back(i
);
282 std::vector
<RTLIL::SigBit
> grouped_result
= mask_en_naive(do_mask
, grouped_bits
, grouped_mask_bits
);
283 RTLIL::SigSpec result
;
285 for (int i
= 0; i
< bits
.__width
; i
++) {
286 std::pair
<RTLIL::SigBit
, RTLIL::SigBit
> key(v_bits
[i
], v_mask_bits
[i
]);
287 result
.append_bit(grouped_result
.at(groups
.at(key
).first
));
293 void merge_en_data(RTLIL::SigSpec
&merged_en
, RTLIL::SigSpec
&merged_data
, RTLIL::SigSpec next_en
, RTLIL::SigSpec next_data
)
295 std::vector
<RTLIL::SigBit
> v_old_en
= merged_en
;
296 std::vector
<RTLIL::SigBit
> v_next_en
= next_en
;
298 // The new merged_en signal is just the old merged_en signal and next_en OR'ed together.
299 // But of course we need to preserve the bit grouping..
301 std::map
<std::pair
<RTLIL::SigBit
, RTLIL::SigBit
>, int> groups
;
302 std::vector
<RTLIL::SigBit
> grouped_old_en
, grouped_next_en
;
303 RTLIL::SigSpec new_merged_en
;
305 for (int i
= 0; i
< int(v_old_en
.size()); i
++) {
306 std::pair
<RTLIL::SigBit
, RTLIL::SigBit
> key(v_old_en
[i
], v_next_en
[i
]);
307 if (groups
.count(key
) == 0) {
308 groups
[key
] = grouped_old_en
.size();
309 grouped_old_en
.push_back(key
.first
);
310 grouped_next_en
.push_back(key
.second
);
314 std::vector
<RTLIL::SigBit
> grouped_new_en
= module
->Or(NEW_ID
, grouped_old_en
, grouped_next_en
);
316 for (int i
= 0; i
< int(v_old_en
.size()); i
++) {
317 std::pair
<RTLIL::SigBit
, RTLIL::SigBit
> key(v_old_en
[i
], v_next_en
[i
]);
318 new_merged_en
.append_bit(grouped_new_en
.at(groups
.at(key
)));
321 // Create the new merged_data signal.
323 RTLIL::SigSpec
new_merged_data(RTLIL::State::Sx
, merged_data
.__width
);
325 RTLIL::SigSpec old_data_set
= module
->And(NEW_ID
, merged_en
, merged_data
);
326 RTLIL::SigSpec old_data_unset
= module
->And(NEW_ID
, merged_en
, module
->Not(NEW_ID
, merged_data
));
328 RTLIL::SigSpec new_data_set
= module
->And(NEW_ID
, next_en
, next_data
);
329 RTLIL::SigSpec new_data_unset
= module
->And(NEW_ID
, next_en
, module
->Not(NEW_ID
, next_data
));
331 new_merged_data
= module
->Or(NEW_ID
, new_merged_data
, old_data_set
);
332 new_merged_data
= module
->And(NEW_ID
, new_merged_data
, module
->Not(NEW_ID
, old_data_unset
));
334 new_merged_data
= module
->Or(NEW_ID
, new_merged_data
, new_data_set
);
335 new_merged_data
= module
->And(NEW_ID
, new_merged_data
, module
->Not(NEW_ID
, new_data_unset
));
337 // Update merged_* signals
339 merged_en
= new_merged_en
;
340 merged_data
= new_merged_data
;
343 void consolidate_wr_by_addr(std::string memid
, std::vector
<RTLIL::Cell
*> &wr_ports
)
345 if (wr_ports
.size() <= 1)
348 log("Consolidating write ports of memory %s.%s by address:\n", log_id(module
), log_id(memid
));
350 std::map
<RTLIL::SigSpec
, int> last_port_by_addr
;
351 std::vector
<std::vector
<bool>> active_bits_on_port
;
353 bool cache_clk_enable
= false;
354 bool cache_clk_polarity
= false;
355 RTLIL::SigSpec cache_clk
;
357 for (int i
= 0; i
< int(wr_ports
.size()); i
++)
359 RTLIL::Cell
*cell
= wr_ports
.at(i
);
360 RTLIL::SigSpec addr
= sigmap_xmux(cell
->connections
.at("\\ADDR"));
362 if (cell
->parameters
.at("\\CLK_ENABLE").as_bool() != cache_clk_enable
||
363 (cache_clk_enable
&& (sigmap(cell
->connections
.at("\\CLK")) != cache_clk
||
364 cell
->parameters
.at("\\CLK_POLARITY").as_bool() != cache_clk_polarity
)))
366 cache_clk_enable
= cell
->parameters
.at("\\CLK_ENABLE").as_bool();
367 cache_clk_polarity
= cell
->parameters
.at("\\CLK_POLARITY").as_bool();
368 cache_clk
= sigmap(cell
->connections
.at("\\CLK"));
369 last_port_by_addr
.clear();
371 if (cache_clk_enable
)
372 log(" New clock domain: %s %s\n", cache_clk_polarity
? "posedge" : "negedge", log_signal(cache_clk
));
374 log(" New clock domain: unclocked\n");
377 log(" Port %d (%s) has addr %s.\n", i
, log_id(cell
), log_signal(addr
));
379 log(" Active bits: ");
380 std::vector
<RTLIL::SigBit
> en_bits
= sigmap(cell
->connections
.at("\\EN"));
381 active_bits_on_port
.push_back(std::vector
<bool>(en_bits
.size()));
382 for (int k
= int(en_bits
.size())-1; k
>= 0; k
--) {
383 active_bits_on_port
[i
][k
] = en_bits
[k
].wire
!= NULL
|| en_bits
[k
].data
!= RTLIL::State::S0
;
384 log("%c", active_bits_on_port
[i
][k
] ? '1' : '0');
388 if (last_port_by_addr
.count(addr
))
390 int last_i
= last_port_by_addr
.at(addr
);
391 log(" Merging port %d into this one.\n", last_i
);
393 bool found_overlapping_bits
= false;
394 for (int k
= 0; k
< int(en_bits
.size()); k
++) {
395 if (active_bits_on_port
[i
][k
] && active_bits_on_port
[last_i
][k
])
396 found_overlapping_bits
= true;
397 active_bits_on_port
[i
][k
] = active_bits_on_port
[i
][k
] || active_bits_on_port
[last_i
][k
];
400 // Force this ports addr input to addr directly (skip don't care muxes)
402 cell
->connections
.at("\\ADDR") = addr
;
404 // If any of the ports between `last_i' and `i' write to the same address, this
405 // will have priority over whatever `last_i` wrote. So we need to revisit those
406 // ports and mask the EN bits accordingly.
408 RTLIL::SigSpec merged_en
= sigmap(wr_ports
[last_i
]->connections
.at("\\EN"));
410 for (int j
= last_i
+1; j
< i
; j
++)
412 if (wr_ports
[j
] == NULL
)
415 for (int k
= 0; k
< int(en_bits
.size()); k
++)
416 if (active_bits_on_port
[i
][k
] && active_bits_on_port
[j
][k
])
417 goto found_overlapping_bits_i_j
;
420 found_overlapping_bits_i_j
:
421 log(" Creating collosion-detect logic for port %d.\n", j
);
422 RTLIL::SigSpec is_same_addr
= module
->addWire(NEW_ID
);
423 module
->addEq(NEW_ID
, addr
, wr_ports
[j
]->connections
.at("\\ADDR"), is_same_addr
);
424 merged_en
= mask_en_grouped(is_same_addr
, merged_en
, sigmap(wr_ports
[j
]->connections
.at("\\EN")));
428 // Then we need to merge the (masked) EN and the DATA signals.
430 RTLIL::SigSpec merged_data
= wr_ports
[last_i
]->connections
.at("\\DATA");
431 if (found_overlapping_bits
) {
432 log(" Creating logic for merging DATA and EN ports.\n");
433 merge_en_data(merged_en
, merged_data
, sigmap(cell
->connections
.at("\\EN")), sigmap(cell
->connections
.at("\\DATA")));
435 RTLIL::SigSpec cell_en
= sigmap(cell
->connections
.at("\\EN"));
436 RTLIL::SigSpec cell_data
= sigmap(cell
->connections
.at("\\DATA"));
437 for (int k
= 0; k
< int(en_bits
.size()); k
++)
438 if (!active_bits_on_port
[last_i
][k
]) {
439 merged_en
.replace(k
, cell_en
.extract(k
, 1));
440 merged_data
.replace(k
, cell_data
.extract(k
, 1));
442 merged_en
.optimize();
443 merged_data
.optimize();
446 // Connect the new EN and DATA signals and remove the old write port.
448 cell
->connections
.at("\\EN") = merged_en
;
449 cell
->connections
.at("\\DATA") = merged_data
;
451 module
->cells
.erase(wr_ports
[last_i
]->name
);
452 delete wr_ports
[last_i
];
453 wr_ports
[last_i
] = NULL
;
455 log(" Active bits: ");
456 std::vector
<RTLIL::SigBit
> en_bits
= sigmap(cell
->connections
.at("\\EN"));
457 active_bits_on_port
.push_back(std::vector
<bool>(en_bits
.size()));
458 for (int k
= int(en_bits
.size())-1; k
>= 0; k
--)
459 log("%c", active_bits_on_port
[i
][k
] ? '1' : '0');
463 last_port_by_addr
[addr
] = i
;
466 // Clean up `wr_ports': remove all NULL entries
468 std::vector
<RTLIL::Cell
*> wr_ports_with_nulls
;
469 wr_ports_with_nulls
.swap(wr_ports
);
471 for (auto cell
: wr_ports_with_nulls
)
473 wr_ports
.push_back(cell
);
477 // --------------------------------------------------------
478 // Consolidate write ports using sat-based resource sharing
479 // --------------------------------------------------------
481 void consolidate_wr_using_sat(std::string memid
, std::vector
<RTLIL::Cell
*> &wr_ports
)
483 if (wr_ports
.size() <= 1)
487 SatGen
satgen(&ez
, &modwalker
.sigmap
);
489 // find list of considered ports and port pairs
491 std::set
<int> considered_ports
;
492 std::set
<int> considered_port_pairs
;
494 for (int i
= 0; i
< int(wr_ports
.size()); i
++) {
495 std::vector
<RTLIL::SigBit
> bits
= modwalker
.sigmap(wr_ports
[i
]->connections
.at("\\EN"));
496 for (auto bit
: bits
)
497 if (bit
== RTLIL::State::S1
)
498 goto port_is_always_active
;
499 if (modwalker
.has_drivers(bits
))
500 considered_ports
.insert(i
);
501 port_is_always_active
:;
504 log("Consolidating write ports of memory %s.%s using sat-based resource sharing:\n", log_id(module
), log_id(memid
));
506 bool cache_clk_enable
= false;
507 bool cache_clk_polarity
= false;
508 RTLIL::SigSpec cache_clk
;
510 for (int i
= 0; i
< int(wr_ports
.size()); i
++)
512 RTLIL::Cell
*cell
= wr_ports
.at(i
);
514 if (cell
->parameters
.at("\\CLK_ENABLE").as_bool() != cache_clk_enable
||
515 (cache_clk_enable
&& (sigmap(cell
->connections
.at("\\CLK")) != cache_clk
||
516 cell
->parameters
.at("\\CLK_POLARITY").as_bool() != cache_clk_polarity
)))
518 cache_clk_enable
= cell
->parameters
.at("\\CLK_ENABLE").as_bool();
519 cache_clk_polarity
= cell
->parameters
.at("\\CLK_POLARITY").as_bool();
520 cache_clk
= sigmap(cell
->connections
.at("\\CLK"));
522 else if (i
> 0 && considered_ports
.count(i
-1) && considered_ports
.count(i
))
523 considered_port_pairs
.insert(i
);
525 if (cache_clk_enable
)
526 log(" Port %d (%s) on %s %s: %s\n", i
, log_id(cell
),
527 cache_clk_polarity
? "posedge" : "negedge", log_signal(cache_clk
),
528 considered_ports
.count(i
) ? "considered" : "not considered");
530 log(" Port %d (%s) unclocked: %s\n", i
, log_id(cell
),
531 considered_ports
.count(i
) ? "considered" : "not considered");
534 if (considered_port_pairs
.size() < 1) {
535 log(" No two subsequent ports in same clock domain considered -> nothing to consolidate.\n");
539 // create SAT representation of common input cone of all considered EN signals
541 std::set
<RTLIL::Cell
*> sat_cells
;
542 std::set
<RTLIL::SigBit
> bits_queue
;
543 std::map
<int, int> port_to_sat_variable
;
545 for (int i
= 0; i
< int(wr_ports
.size()); i
++)
546 if (considered_port_pairs
.count(i
) || considered_port_pairs
.count(i
+1))
548 RTLIL::SigSpec sig
= modwalker
.sigmap(wr_ports
[i
]->connections
.at("\\EN"));
549 port_to_sat_variable
[i
] = ez
.expression(ez
.OpOr
, satgen
.importSigSpec(sig
));
551 std::vector
<RTLIL::SigBit
> bits
= sig
;
552 bits_queue
.insert(bits
.begin(), bits
.end());
555 while (!bits_queue
.empty())
557 std::set
<ModWalker::PortBit
> portbits
;
558 modwalker
.get_drivers(portbits
, bits_queue
);
561 for (auto &pbit
: portbits
)
562 if (sat_cells
.count(pbit
.cell
) == 0 && cone_ct
.cell_known(pbit
.cell
->type
)) {
563 std::set
<RTLIL::SigBit
> &cell_inputs
= modwalker
.cell_inputs
[pbit
.cell
];
564 bits_queue
.insert(cell_inputs
.begin(), cell_inputs
.end());
565 sat_cells
.insert(pbit
.cell
);
569 log(" Common input cone for all EN signals: %d cells.\n", int(sat_cells
.size()));
571 for (auto cell
: sat_cells
)
572 satgen
.importCell(cell
);
574 log(" Size of unconstrained SAT problem: %d variables, %d clauses\n", ez
.numCnfVariables(), ez
.numCnfClauses());
576 // merge subsequent ports if possible
578 for (int i
= 0; i
< int(wr_ports
.size()); i
++)
580 if (!considered_port_pairs
.count(i
))
583 if (ez
.solve(port_to_sat_variable
.at(i
-1), port_to_sat_variable
.at(i
))) {
584 log(" According to SAT solver sharing of port %d with port %d is not possible.\n", i
-1, i
);
588 log(" Merging port %d into port %d.\n", i
-1, i
);
589 port_to_sat_variable
.at(i
) = ez
.OR(port_to_sat_variable
.at(i
-1), port_to_sat_variable
.at(i
));
591 RTLIL::SigSpec last_addr
= wr_ports
[i
-1]->connections
.at("\\ADDR");
592 RTLIL::SigSpec last_data
= wr_ports
[i
-1]->connections
.at("\\DATA");
593 std::vector
<RTLIL::SigBit
> last_en
= modwalker
.sigmap(wr_ports
[i
-1]->connections
.at("\\EN"));
595 RTLIL::SigSpec this_addr
= wr_ports
[i
]->connections
.at("\\ADDR");
596 RTLIL::SigSpec this_data
= wr_ports
[i
]->connections
.at("\\DATA");
597 std::vector
<RTLIL::SigBit
> this_en
= modwalker
.sigmap(wr_ports
[i
]->connections
.at("\\EN"));
599 RTLIL::SigBit this_en_active
= module
->ReduceOr(NEW_ID
, this_en
);
601 wr_ports
[i
]->connections
.at("\\ADDR") = module
->Mux(NEW_ID
, last_addr
, this_addr
, this_en_active
);
602 wr_ports
[i
]->connections
.at("\\DATA") = module
->Mux(NEW_ID
, last_data
, this_data
, this_en_active
);
604 std::map
<std::pair
<RTLIL::SigBit
, RTLIL::SigBit
>, int> groups_en
;
605 RTLIL::SigSpec grouped_last_en
, grouped_this_en
, en
;
606 RTLIL::Wire
*grouped_en
= module
->addWire(NEW_ID
, 0);
608 for (int j
= 0; j
< int(this_en
.size()); j
++) {
609 std::pair
<RTLIL::SigBit
, RTLIL::SigBit
> key(last_en
[j
], this_en
[j
]);
610 if (!groups_en
.count(key
)) {
611 grouped_last_en
.append_bit(last_en
[j
]);
612 grouped_this_en
.append_bit(this_en
[j
]);
613 groups_en
[key
] = grouped_en
->width
;
616 en
.append(RTLIL::SigSpec(grouped_en
, 1, groups_en
[key
]));
619 module
->addMux(NEW_ID
, grouped_last_en
, grouped_this_en
, this_en_active
, grouped_en
);
620 wr_ports
[i
]->connections
.at("\\EN") = en
;
622 module
->cells
.erase(wr_ports
[i
-1]->name
);
623 delete wr_ports
[i
-1];
624 wr_ports
[i
-1] = NULL
;
627 // Clean up `wr_ports': remove all NULL entries
629 std::vector
<RTLIL::Cell
*> wr_ports_with_nulls
;
630 wr_ports_with_nulls
.swap(wr_ports
);
632 for (auto cell
: wr_ports_with_nulls
)
634 wr_ports
.push_back(cell
);
642 MemoryShareWorker(RTLIL::Design
*design
, RTLIL::Module
*module
) :
643 design(design
), module(module
), sigmap(module
)
645 std::map
<std::string
, std::pair
<std::vector
<RTLIL::Cell
*>, std::vector
<RTLIL::Cell
*>>> memindex
;
647 sigmap_xmux
= sigmap
;
648 for (auto &it
: module
->cells
)
650 RTLIL::Cell
*cell
= it
.second
;
652 if (cell
->type
== "$memrd")
653 memindex
[cell
->parameters
.at("\\MEMID").decode_string()].first
.push_back(cell
);
655 if (cell
->type
== "$memwr")
656 memindex
[cell
->parameters
.at("\\MEMID").decode_string()].second
.push_back(cell
);
658 if (cell
->type
== "$mux")
660 RTLIL::SigSpec sig_a
= sigmap_xmux(cell
->connections
.at("\\A"));
661 RTLIL::SigSpec sig_b
= sigmap_xmux(cell
->connections
.at("\\B"));
663 if (sig_a
.is_fully_undef())
664 sigmap_xmux
.add(cell
->connections
.at("\\Y"), sig_b
);
665 else if (sig_b
.is_fully_undef())
666 sigmap_xmux
.add(cell
->connections
.at("\\Y"), sig_a
);
669 if (cell
->type
== "$mux" || cell
->type
== "$pmux")
671 std::vector
<RTLIL::SigBit
> sig_y
= sigmap(cell
->connections
.at("\\Y"));
672 for (int i
= 0; i
< int(sig_y
.size()); i
++)
673 sig_to_mux
[sig_y
[i
]] = std::pair
<RTLIL::Cell
*, int>(cell
, i
);
677 for (auto &it
: memindex
) {
678 std::sort(it
.second
.first
.begin(), it
.second
.first
.end(), memcells_cmp
);
679 std::sort(it
.second
.second
.begin(), it
.second
.second
.end(), memcells_cmp
);
680 translate_rd_feedback_to_en(it
.first
, it
.second
.first
, it
.second
.second
);
681 consolidate_wr_by_addr(it
.first
, it
.second
.second
);
684 cone_ct
.setup_internals();
685 cone_ct
.cell_types
.erase("$mul");
686 cone_ct
.cell_types
.erase("$mod");
687 cone_ct
.cell_types
.erase("$div");
688 cone_ct
.cell_types
.erase("$pow");
689 cone_ct
.cell_types
.erase("$shl");
690 cone_ct
.cell_types
.erase("$shr");
691 cone_ct
.cell_types
.erase("$sshl");
692 cone_ct
.cell_types
.erase("$sshr");
694 modwalker
.setup(design
, module
, &cone_ct
);
696 for (auto &it
: memindex
)
697 consolidate_wr_using_sat(it
.first
, it
.second
.second
);
701 struct MemorySharePass
: public Pass
{
702 MemorySharePass() : Pass("memory_share", "consolidate memory ports") { }
705 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
707 log(" memory_share [selection]\n");
709 log("This pass merges share-able memory ports into single memory ports.\n");
711 log("The following methods are used to consolidate the number of memory ports:\n");
713 log(" - When write ports are connected to async read ports accessing the same\n");
714 log(" address, then this feedback path is converted to a write port with\n");
715 log(" byte/part enable signals.\n");
717 log(" - When multiple write ports access the same adress then this is converted\n");
718 log(" to a single write port with a more complex data and/or enable logic path.\n");
720 log(" - When multiple write ports are never accessed at the same time (a SAT\n");
721 log(" solver is used to determine this), then the ports are merged into a single\n");
722 log(" write port.\n");
724 log("Note that in addition to the algorithms implemented in this pass, the $memrd\n");
725 log("and $memwr cells are also subject to generic resource sharing passes (and other\n");
726 log("optimizations) such as opt_share.\n");
729 virtual void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) {
730 log_header("Executing MEMORY_SHARE pass (consolidating $memrc/$memwr cells).\n");
731 extra_args(args
, 1, design
);
732 for (auto &mod_it
: design
->modules
)
733 if (design
->selected(mod_it
.second
))
734 MemoryShareWorker(design
, mod_it
.second
);