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/yosys.h"
21 #include "kernel/satgen.h"
22 #include "kernel/sigtools.h"
23 #include "kernel/modtools.h"
26 PRIVATE_NAMESPACE_BEGIN
28 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
->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"));
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 RTLIL::SigSpec new_b
= cell
->getPort("\\B");
77 new_b
.replace(bit_idx
+ i
*sig_y
.size(), RTLIL::State::Sx
);
78 cell
->setPort("\\B", new_b
);
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
)) {
93 RTLIL::SigSpec new_b
= cell
->getPort("\\B");
94 new_b
.replace(bit_idx
+ i
*sig_y
.size(), RTLIL::State::Sx
);
95 cell
->setPort("\\B", new_b
);
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;
103 if (find_data_feedback(async_rd_bits
, sig_a
.at(bit_idx
), new_state
, conditions
)) {
104 RTLIL::SigSpec new_a
= cell
->getPort("\\A");
105 new_a
.replace(bit_idx
, RTLIL::State::Sx
);
106 cell
->setPort("\\A", new_a
);
112 RTLIL::SigBit
conditions_to_logic(std::set
<std::map
<RTLIL::SigBit
, bool>> &conditions
, int &created_conditions
)
114 if (conditions_logic_cache
.count(conditions
))
115 return conditions_logic_cache
.at(conditions
);
117 RTLIL::SigSpec terms
;
118 for (auto &cond
: conditions
) {
119 RTLIL::SigSpec sig1
, sig2
;
120 for (auto &it
: cond
) {
121 sig1
.append_bit(it
.first
);
122 sig2
.append_bit(it
.second
? RTLIL::State::S1
: RTLIL::State::S0
);
124 terms
.append(module
->Ne(NEW_ID
, sig1
, sig2
));
125 created_conditions
++;
128 if (terms
.size() == 0)
131 if (terms
.size() > 1)
132 terms
= module
->ReduceAnd(NEW_ID
, terms
);
134 return conditions_logic_cache
[conditions
] = terms
;
137 void translate_rd_feedback_to_en(std::string memid
, std::vector
<RTLIL::Cell
*> &rd_ports
, std::vector
<RTLIL::Cell
*> &wr_ports
)
139 std::map
<RTLIL::SigSpec
, std::vector
<std::set
<RTLIL::SigBit
>>> async_rd_bits
;
140 std::map
<RTLIL::SigBit
, std::set
<RTLIL::SigBit
>> muxtree_upstream_map
;
141 std::set
<RTLIL::SigBit
> non_feedback_nets
;
143 for (auto wire_it
: module
->wires_
)
144 if (wire_it
.second
->port_output
) {
145 std::vector
<RTLIL::SigBit
> bits
= RTLIL::SigSpec(wire_it
.second
);
146 non_feedback_nets
.insert(bits
.begin(), bits
.end());
149 for (auto cell_it
: module
->cells_
)
151 RTLIL::Cell
*cell
= cell_it
.second
;
152 bool ignore_data_port
= false;
154 if (cell
->type
== "$mux" || cell
->type
== "$pmux")
156 std::vector
<RTLIL::SigBit
> sig_a
= sigmap(cell
->getPort("\\A"));
157 std::vector
<RTLIL::SigBit
> sig_b
= sigmap(cell
->getPort("\\B"));
158 std::vector
<RTLIL::SigBit
> sig_s
= sigmap(cell
->getPort("\\S"));
159 std::vector
<RTLIL::SigBit
> sig_y
= sigmap(cell
->getPort("\\Y"));
161 non_feedback_nets
.insert(sig_s
.begin(), sig_s
.end());
163 for (int i
= 0; i
< int(sig_y
.size()); i
++) {
164 muxtree_upstream_map
[sig_y
[i
]].insert(sig_a
[i
]);
165 for (int j
= 0; j
< int(sig_s
.size()); j
++)
166 muxtree_upstream_map
[sig_y
[i
]].insert(sig_b
[i
+ j
*sig_y
.size()]);
172 if ((cell
->type
== "$memwr" || cell
->type
== "$memrd") &&
173 cell
->parameters
.at("\\MEMID").decode_string() == memid
)
174 ignore_data_port
= true;
176 for (auto conn
: cell_it
.second
->connections())
178 if (ignore_data_port
&& conn
.first
== "\\DATA")
180 std::vector
<RTLIL::SigBit
> bits
= sigmap(conn
.second
);
181 non_feedback_nets
.insert(bits
.begin(), bits
.end());
185 std::set
<RTLIL::SigBit
> expand_non_feedback_nets
= non_feedback_nets
;
186 while (!expand_non_feedback_nets
.empty())
188 std::set
<RTLIL::SigBit
> new_expand_non_feedback_nets
;
190 for (auto &bit
: expand_non_feedback_nets
)
191 if (muxtree_upstream_map
.count(bit
))
192 for (auto &new_bit
: muxtree_upstream_map
.at(bit
))
193 if (!non_feedback_nets
.count(new_bit
)) {
194 non_feedback_nets
.insert(new_bit
);
195 new_expand_non_feedback_nets
.insert(new_bit
);
198 expand_non_feedback_nets
.swap(new_expand_non_feedback_nets
);
201 for (auto cell
: rd_ports
)
203 if (cell
->parameters
.at("\\CLK_ENABLE").as_bool())
206 RTLIL::SigSpec sig_addr
= sigmap(cell
->getPort("\\ADDR"));
207 std::vector
<RTLIL::SigBit
> sig_data
= sigmap(cell
->getPort("\\DATA"));
209 for (int i
= 0; i
< int(sig_data
.size()); i
++)
210 if (non_feedback_nets
.count(sig_data
[i
]))
211 goto not_pure_feedback_port
;
213 async_rd_bits
[sig_addr
].resize(max(async_rd_bits
.size(), sig_data
.size()));
214 for (int i
= 0; i
< int(sig_data
.size()); i
++)
215 async_rd_bits
[sig_addr
][i
].insert(sig_data
[i
]);
217 not_pure_feedback_port
:;
220 if (async_rd_bits
.empty())
223 log("Populating enable bits on write ports of memory %s.%s with aync read feedback:\n", log_id(module
), log_id(memid
));
225 for (auto cell
: wr_ports
)
227 RTLIL::SigSpec sig_addr
= sigmap_xmux(cell
->getPort("\\ADDR"));
228 if (!async_rd_bits
.count(sig_addr
))
231 log(" Analyzing write port %s.\n", log_id(cell
));
233 std::vector
<RTLIL::SigBit
> cell_data
= cell
->getPort("\\DATA");
234 std::vector
<RTLIL::SigBit
> cell_en
= cell
->getPort("\\EN");
236 int created_conditions
= 0;
237 for (int i
= 0; i
< int(cell_data
.size()); i
++)
238 if (cell_en
[i
] != RTLIL::SigBit(RTLIL::State::S0
))
240 std::map
<RTLIL::SigBit
, bool> state
;
241 std::set
<std::map
<RTLIL::SigBit
, bool>> conditions
;
243 if (cell_en
[i
].wire
!= NULL
) {
244 state
[cell_en
[i
]] = false;
245 conditions
.insert(state
);
248 find_data_feedback(async_rd_bits
.at(sig_addr
).at(i
), cell_data
[i
], state
, conditions
);
249 cell_en
[i
] = conditions_to_logic(conditions
, created_conditions
);
252 if (created_conditions
) {
253 log(" Added enable logic for %d different cases.\n", created_conditions
);
254 cell
->setPort("\\EN", cell_en
);
260 // ------------------------------------------------------
261 // Consolidate write ports that write to the same address
262 // ------------------------------------------------------
264 RTLIL::SigSpec
mask_en_naive(RTLIL::SigSpec do_mask
, RTLIL::SigSpec bits
, RTLIL::SigSpec mask_bits
)
266 // this is the naive version of the function that does not care about grouping the EN bits.
268 RTLIL::SigSpec inv_mask_bits
= module
->Not(NEW_ID
, mask_bits
);
269 RTLIL::SigSpec inv_mask_bits_filtered
= module
->Mux(NEW_ID
, RTLIL::SigSpec(RTLIL::State::S1
, bits
.size()), inv_mask_bits
, do_mask
);
270 RTLIL::SigSpec result
= module
->And(NEW_ID
, inv_mask_bits_filtered
, bits
);
274 RTLIL::SigSpec
mask_en_grouped(RTLIL::SigSpec do_mask
, RTLIL::SigSpec bits
, RTLIL::SigSpec mask_bits
)
276 // this version of the function preserves the bit grouping in the EN bits.
278 std::vector
<RTLIL::SigBit
> v_bits
= bits
;
279 std::vector
<RTLIL::SigBit
> v_mask_bits
= mask_bits
;
281 std::map
<std::pair
<RTLIL::SigBit
, RTLIL::SigBit
>, std::pair
<int, std::vector
<int>>> groups
;
282 RTLIL::SigSpec grouped_bits
, grouped_mask_bits
;
284 for (int i
= 0; i
< bits
.size(); i
++) {
285 std::pair
<RTLIL::SigBit
, RTLIL::SigBit
> key(v_bits
[i
], v_mask_bits
[i
]);
286 if (groups
.count(key
) == 0) {
287 groups
[key
].first
= grouped_bits
.size();
288 grouped_bits
.append_bit(v_bits
[i
]);
289 grouped_mask_bits
.append_bit(v_mask_bits
[i
]);
291 groups
[key
].second
.push_back(i
);
294 std::vector
<RTLIL::SigBit
> grouped_result
= mask_en_naive(do_mask
, grouped_bits
, grouped_mask_bits
);
295 RTLIL::SigSpec result
;
297 for (int i
= 0; i
< bits
.size(); i
++) {
298 std::pair
<RTLIL::SigBit
, RTLIL::SigBit
> key(v_bits
[i
], v_mask_bits
[i
]);
299 result
.append_bit(grouped_result
.at(groups
.at(key
).first
));
305 void merge_en_data(RTLIL::SigSpec
&merged_en
, RTLIL::SigSpec
&merged_data
, RTLIL::SigSpec next_en
, RTLIL::SigSpec next_data
)
307 std::vector
<RTLIL::SigBit
> v_old_en
= merged_en
;
308 std::vector
<RTLIL::SigBit
> v_next_en
= next_en
;
310 // The new merged_en signal is just the old merged_en signal and next_en OR'ed together.
311 // But of course we need to preserve the bit grouping..
313 std::map
<std::pair
<RTLIL::SigBit
, RTLIL::SigBit
>, int> groups
;
314 std::vector
<RTLIL::SigBit
> grouped_old_en
, grouped_next_en
;
315 RTLIL::SigSpec new_merged_en
;
317 for (int i
= 0; i
< int(v_old_en
.size()); i
++) {
318 std::pair
<RTLIL::SigBit
, RTLIL::SigBit
> key(v_old_en
[i
], v_next_en
[i
]);
319 if (groups
.count(key
) == 0) {
320 groups
[key
] = grouped_old_en
.size();
321 grouped_old_en
.push_back(key
.first
);
322 grouped_next_en
.push_back(key
.second
);
326 std::vector
<RTLIL::SigBit
> grouped_new_en
= module
->Or(NEW_ID
, grouped_old_en
, grouped_next_en
);
328 for (int i
= 0; i
< int(v_old_en
.size()); i
++) {
329 std::pair
<RTLIL::SigBit
, RTLIL::SigBit
> key(v_old_en
[i
], v_next_en
[i
]);
330 new_merged_en
.append_bit(grouped_new_en
.at(groups
.at(key
)));
333 // Create the new merged_data signal.
335 RTLIL::SigSpec
new_merged_data(RTLIL::State::Sx
, merged_data
.size());
337 RTLIL::SigSpec old_data_set
= module
->And(NEW_ID
, merged_en
, merged_data
);
338 RTLIL::SigSpec old_data_unset
= module
->And(NEW_ID
, merged_en
, module
->Not(NEW_ID
, merged_data
));
340 RTLIL::SigSpec new_data_set
= module
->And(NEW_ID
, next_en
, next_data
);
341 RTLIL::SigSpec new_data_unset
= module
->And(NEW_ID
, next_en
, module
->Not(NEW_ID
, next_data
));
343 new_merged_data
= module
->Or(NEW_ID
, new_merged_data
, old_data_set
);
344 new_merged_data
= module
->And(NEW_ID
, new_merged_data
, module
->Not(NEW_ID
, old_data_unset
));
346 new_merged_data
= module
->Or(NEW_ID
, new_merged_data
, new_data_set
);
347 new_merged_data
= module
->And(NEW_ID
, new_merged_data
, module
->Not(NEW_ID
, new_data_unset
));
349 // Update merged_* signals
351 merged_en
= new_merged_en
;
352 merged_data
= new_merged_data
;
355 void consolidate_wr_by_addr(std::string memid
, std::vector
<RTLIL::Cell
*> &wr_ports
)
357 if (wr_ports
.size() <= 1)
360 log("Consolidating write ports of memory %s.%s by address:\n", log_id(module
), log_id(memid
));
362 std::map
<RTLIL::SigSpec
, int> last_port_by_addr
;
363 std::vector
<std::vector
<bool>> active_bits_on_port
;
365 bool cache_clk_enable
= false;
366 bool cache_clk_polarity
= false;
367 RTLIL::SigSpec cache_clk
;
369 for (int i
= 0; i
< int(wr_ports
.size()); i
++)
371 RTLIL::Cell
*cell
= wr_ports
.at(i
);
372 RTLIL::SigSpec addr
= sigmap_xmux(cell
->getPort("\\ADDR"));
374 if (cell
->parameters
.at("\\CLK_ENABLE").as_bool() != cache_clk_enable
||
375 (cache_clk_enable
&& (sigmap(cell
->getPort("\\CLK")) != cache_clk
||
376 cell
->parameters
.at("\\CLK_POLARITY").as_bool() != cache_clk_polarity
)))
378 cache_clk_enable
= cell
->parameters
.at("\\CLK_ENABLE").as_bool();
379 cache_clk_polarity
= cell
->parameters
.at("\\CLK_POLARITY").as_bool();
380 cache_clk
= sigmap(cell
->getPort("\\CLK"));
381 last_port_by_addr
.clear();
383 if (cache_clk_enable
)
384 log(" New clock domain: %s %s\n", cache_clk_polarity
? "posedge" : "negedge", log_signal(cache_clk
));
386 log(" New clock domain: unclocked\n");
389 log(" Port %d (%s) has addr %s.\n", i
, log_id(cell
), log_signal(addr
));
391 log(" Active bits: ");
392 std::vector
<RTLIL::SigBit
> en_bits
= sigmap(cell
->getPort("\\EN"));
393 active_bits_on_port
.push_back(std::vector
<bool>(en_bits
.size()));
394 for (int k
= int(en_bits
.size())-1; k
>= 0; k
--) {
395 active_bits_on_port
[i
][k
] = en_bits
[k
].wire
!= NULL
|| en_bits
[k
].data
!= RTLIL::State::S0
;
396 log("%c", active_bits_on_port
[i
][k
] ? '1' : '0');
400 if (last_port_by_addr
.count(addr
))
402 int last_i
= last_port_by_addr
.at(addr
);
403 log(" Merging port %d into this one.\n", last_i
);
405 bool found_overlapping_bits
= false;
406 for (int k
= 0; k
< int(en_bits
.size()); k
++) {
407 if (active_bits_on_port
[i
][k
] && active_bits_on_port
[last_i
][k
])
408 found_overlapping_bits
= true;
409 active_bits_on_port
[i
][k
] = active_bits_on_port
[i
][k
] || active_bits_on_port
[last_i
][k
];
412 // Force this ports addr input to addr directly (skip don't care muxes)
414 cell
->setPort("\\ADDR", addr
);
416 // If any of the ports between `last_i' and `i' write to the same address, this
417 // will have priority over whatever `last_i` wrote. So we need to revisit those
418 // ports and mask the EN bits accordingly.
420 RTLIL::SigSpec merged_en
= sigmap(wr_ports
[last_i
]->getPort("\\EN"));
422 for (int j
= last_i
+1; j
< i
; j
++)
424 if (wr_ports
[j
] == NULL
)
427 for (int k
= 0; k
< int(en_bits
.size()); k
++)
428 if (active_bits_on_port
[i
][k
] && active_bits_on_port
[j
][k
])
429 goto found_overlapping_bits_i_j
;
432 found_overlapping_bits_i_j
:
433 log(" Creating collosion-detect logic for port %d.\n", j
);
434 RTLIL::SigSpec is_same_addr
= module
->addWire(NEW_ID
);
435 module
->addEq(NEW_ID
, addr
, wr_ports
[j
]->getPort("\\ADDR"), is_same_addr
);
436 merged_en
= mask_en_grouped(is_same_addr
, merged_en
, sigmap(wr_ports
[j
]->getPort("\\EN")));
440 // Then we need to merge the (masked) EN and the DATA signals.
442 RTLIL::SigSpec merged_data
= wr_ports
[last_i
]->getPort("\\DATA");
443 if (found_overlapping_bits
) {
444 log(" Creating logic for merging DATA and EN ports.\n");
445 merge_en_data(merged_en
, merged_data
, sigmap(cell
->getPort("\\EN")), sigmap(cell
->getPort("\\DATA")));
447 RTLIL::SigSpec cell_en
= sigmap(cell
->getPort("\\EN"));
448 RTLIL::SigSpec cell_data
= sigmap(cell
->getPort("\\DATA"));
449 for (int k
= 0; k
< int(en_bits
.size()); k
++)
450 if (!active_bits_on_port
[last_i
][k
]) {
451 merged_en
.replace(k
, cell_en
.extract(k
, 1));
452 merged_data
.replace(k
, cell_data
.extract(k
, 1));
456 // Connect the new EN and DATA signals and remove the old write port.
458 cell
->setPort("\\EN", merged_en
);
459 cell
->setPort("\\DATA", merged_data
);
461 module
->remove(wr_ports
[last_i
]);
462 wr_ports
[last_i
] = NULL
;
464 log(" Active bits: ");
465 std::vector
<RTLIL::SigBit
> en_bits
= sigmap(cell
->getPort("\\EN"));
466 active_bits_on_port
.push_back(std::vector
<bool>(en_bits
.size()));
467 for (int k
= int(en_bits
.size())-1; k
>= 0; k
--)
468 log("%c", active_bits_on_port
[i
][k
] ? '1' : '0');
472 last_port_by_addr
[addr
] = i
;
475 // Clean up `wr_ports': remove all NULL entries
477 std::vector
<RTLIL::Cell
*> wr_ports_with_nulls
;
478 wr_ports_with_nulls
.swap(wr_ports
);
480 for (auto cell
: wr_ports_with_nulls
)
482 wr_ports
.push_back(cell
);
486 // --------------------------------------------------------
487 // Consolidate write ports using sat-based resource sharing
488 // --------------------------------------------------------
490 void consolidate_wr_using_sat(std::string memid
, std::vector
<RTLIL::Cell
*> &wr_ports
)
492 if (wr_ports
.size() <= 1)
496 SatGen
satgen(ez
.get(), &modwalker
.sigmap
);
498 // find list of considered ports and port pairs
500 std::set
<int> considered_ports
;
501 std::set
<int> considered_port_pairs
;
503 for (int i
= 0; i
< int(wr_ports
.size()); i
++) {
504 std::vector
<RTLIL::SigBit
> bits
= modwalker
.sigmap(wr_ports
[i
]->getPort("\\EN"));
505 for (auto bit
: bits
)
506 if (bit
== RTLIL::State::S1
)
507 goto port_is_always_active
;
508 if (modwalker
.has_drivers(bits
))
509 considered_ports
.insert(i
);
510 port_is_always_active
:;
513 log("Consolidating write ports of memory %s.%s using sat-based resource sharing:\n", log_id(module
), log_id(memid
));
515 bool cache_clk_enable
= false;
516 bool cache_clk_polarity
= false;
517 RTLIL::SigSpec cache_clk
;
519 for (int i
= 0; i
< int(wr_ports
.size()); i
++)
521 RTLIL::Cell
*cell
= wr_ports
.at(i
);
523 if (cell
->parameters
.at("\\CLK_ENABLE").as_bool() != cache_clk_enable
||
524 (cache_clk_enable
&& (sigmap(cell
->getPort("\\CLK")) != cache_clk
||
525 cell
->parameters
.at("\\CLK_POLARITY").as_bool() != cache_clk_polarity
)))
527 cache_clk_enable
= cell
->parameters
.at("\\CLK_ENABLE").as_bool();
528 cache_clk_polarity
= cell
->parameters
.at("\\CLK_POLARITY").as_bool();
529 cache_clk
= sigmap(cell
->getPort("\\CLK"));
531 else if (i
> 0 && considered_ports
.count(i
-1) && considered_ports
.count(i
))
532 considered_port_pairs
.insert(i
);
534 if (cache_clk_enable
)
535 log(" Port %d (%s) on %s %s: %s\n", i
, log_id(cell
),
536 cache_clk_polarity
? "posedge" : "negedge", log_signal(cache_clk
),
537 considered_ports
.count(i
) ? "considered" : "not considered");
539 log(" Port %d (%s) unclocked: %s\n", i
, log_id(cell
),
540 considered_ports
.count(i
) ? "considered" : "not considered");
543 if (considered_port_pairs
.size() < 1) {
544 log(" No two subsequent ports in same clock domain considered -> nothing to consolidate.\n");
548 // create SAT representation of common input cone of all considered EN signals
550 pool
<Wire
*> one_hot_wires
;
551 std::set
<RTLIL::Cell
*> sat_cells
;
552 std::set
<RTLIL::SigBit
> bits_queue
;
553 std::map
<int, int> port_to_sat_variable
;
555 for (int i
= 0; i
< int(wr_ports
.size()); i
++)
556 if (considered_port_pairs
.count(i
) || considered_port_pairs
.count(i
+1))
558 RTLIL::SigSpec sig
= modwalker
.sigmap(wr_ports
[i
]->getPort("\\EN"));
559 port_to_sat_variable
[i
] = ez
->expression(ez
->OpOr
, satgen
.importSigSpec(sig
));
561 std::vector
<RTLIL::SigBit
> bits
= sig
;
562 bits_queue
.insert(bits
.begin(), bits
.end());
565 while (!bits_queue
.empty())
567 for (auto bit
: bits_queue
)
568 if (bit
.wire
&& bit
.wire
->get_bool_attribute("\\onehot"))
569 one_hot_wires
.insert(bit
.wire
);
571 pool
<ModWalker::PortBit
> portbits
;
572 modwalker
.get_drivers(portbits
, bits_queue
);
575 for (auto &pbit
: portbits
)
576 if (sat_cells
.count(pbit
.cell
) == 0 && cone_ct
.cell_known(pbit
.cell
->type
)) {
577 pool
<RTLIL::SigBit
> &cell_inputs
= modwalker
.cell_inputs
[pbit
.cell
];
578 bits_queue
.insert(cell_inputs
.begin(), cell_inputs
.end());
579 sat_cells
.insert(pbit
.cell
);
583 for (auto wire
: one_hot_wires
) {
584 log(" Adding one-hot constraint for wire %s.\n", log_id(wire
));
585 vector
<int> ez_wire_bits
= satgen
.importSigSpec(wire
);
586 for (int i
: ez_wire_bits
)
587 for (int j
: ez_wire_bits
)
588 if (i
!= j
) ez
->assume(ez
->NOT(i
), j
);
591 log(" Common input cone for all EN signals: %d cells.\n", int(sat_cells
.size()));
593 for (auto cell
: sat_cells
)
594 satgen
.importCell(cell
);
596 log(" Size of unconstrained SAT problem: %d variables, %d clauses\n", ez
->numCnfVariables(), ez
->numCnfClauses());
598 // merge subsequent ports if possible
600 for (int i
= 0; i
< int(wr_ports
.size()); i
++)
602 if (!considered_port_pairs
.count(i
))
605 if (ez
->solve(port_to_sat_variable
.at(i
-1), port_to_sat_variable
.at(i
))) {
606 log(" According to SAT solver sharing of port %d with port %d is not possible.\n", i
-1, i
);
610 log(" Merging port %d into port %d.\n", i
-1, i
);
611 port_to_sat_variable
.at(i
) = ez
->OR(port_to_sat_variable
.at(i
-1), port_to_sat_variable
.at(i
));
613 RTLIL::SigSpec last_addr
= wr_ports
[i
-1]->getPort("\\ADDR");
614 RTLIL::SigSpec last_data
= wr_ports
[i
-1]->getPort("\\DATA");
615 std::vector
<RTLIL::SigBit
> last_en
= modwalker
.sigmap(wr_ports
[i
-1]->getPort("\\EN"));
617 RTLIL::SigSpec this_addr
= wr_ports
[i
]->getPort("\\ADDR");
618 RTLIL::SigSpec this_data
= wr_ports
[i
]->getPort("\\DATA");
619 std::vector
<RTLIL::SigBit
> this_en
= modwalker
.sigmap(wr_ports
[i
]->getPort("\\EN"));
621 RTLIL::SigBit this_en_active
= module
->ReduceOr(NEW_ID
, this_en
);
623 wr_ports
[i
]->setPort("\\ADDR", module
->Mux(NEW_ID
, last_addr
, this_addr
, this_en_active
));
624 wr_ports
[i
]->setPort("\\DATA", module
->Mux(NEW_ID
, last_data
, this_data
, this_en_active
));
626 std::map
<std::pair
<RTLIL::SigBit
, RTLIL::SigBit
>, int> groups_en
;
627 RTLIL::SigSpec grouped_last_en
, grouped_this_en
, en
;
628 RTLIL::Wire
*grouped_en
= module
->addWire(NEW_ID
, 0);
630 for (int j
= 0; j
< int(this_en
.size()); j
++) {
631 std::pair
<RTLIL::SigBit
, RTLIL::SigBit
> key(last_en
[j
], this_en
[j
]);
632 if (!groups_en
.count(key
)) {
633 grouped_last_en
.append_bit(last_en
[j
]);
634 grouped_this_en
.append_bit(this_en
[j
]);
635 groups_en
[key
] = grouped_en
->width
;
638 en
.append(RTLIL::SigSpec(grouped_en
, groups_en
[key
]));
641 module
->addMux(NEW_ID
, grouped_last_en
, grouped_this_en
, this_en_active
, grouped_en
);
642 wr_ports
[i
]->setPort("\\EN", en
);
644 module
->remove(wr_ports
[i
-1]);
645 wr_ports
[i
-1] = NULL
;
648 // Clean up `wr_ports': remove all NULL entries
650 std::vector
<RTLIL::Cell
*> wr_ports_with_nulls
;
651 wr_ports_with_nulls
.swap(wr_ports
);
653 for (auto cell
: wr_ports_with_nulls
)
655 wr_ports
.push_back(cell
);
663 MemoryShareWorker(RTLIL::Design
*design
, RTLIL::Module
*module
) :
664 design(design
), module(module
), sigmap(module
)
666 std::map
<std::string
, std::pair
<std::vector
<RTLIL::Cell
*>, std::vector
<RTLIL::Cell
*>>> memindex
;
668 sigmap_xmux
= sigmap
;
669 for (auto &it
: module
->cells_
)
671 RTLIL::Cell
*cell
= it
.second
;
673 if (cell
->type
== "$memrd")
674 memindex
[cell
->parameters
.at("\\MEMID").decode_string()].first
.push_back(cell
);
676 if (cell
->type
== "$memwr")
677 memindex
[cell
->parameters
.at("\\MEMID").decode_string()].second
.push_back(cell
);
679 if (cell
->type
== "$mux")
681 RTLIL::SigSpec sig_a
= sigmap_xmux(cell
->getPort("\\A"));
682 RTLIL::SigSpec sig_b
= sigmap_xmux(cell
->getPort("\\B"));
684 if (sig_a
.is_fully_undef())
685 sigmap_xmux
.add(cell
->getPort("\\Y"), sig_b
);
686 else if (sig_b
.is_fully_undef())
687 sigmap_xmux
.add(cell
->getPort("\\Y"), sig_a
);
690 if (cell
->type
== "$mux" || cell
->type
== "$pmux")
692 std::vector
<RTLIL::SigBit
> sig_y
= sigmap(cell
->getPort("\\Y"));
693 for (int i
= 0; i
< int(sig_y
.size()); i
++)
694 sig_to_mux
[sig_y
[i
]] = std::pair
<RTLIL::Cell
*, int>(cell
, i
);
698 for (auto &it
: memindex
) {
699 std::sort(it
.second
.first
.begin(), it
.second
.first
.end(), memcells_cmp
);
700 std::sort(it
.second
.second
.begin(), it
.second
.second
.end(), memcells_cmp
);
701 translate_rd_feedback_to_en(it
.first
, it
.second
.first
, it
.second
.second
);
702 consolidate_wr_by_addr(it
.first
, it
.second
.second
);
705 cone_ct
.setup_internals();
706 cone_ct
.cell_types
.erase("$mul");
707 cone_ct
.cell_types
.erase("$mod");
708 cone_ct
.cell_types
.erase("$div");
709 cone_ct
.cell_types
.erase("$pow");
710 cone_ct
.cell_types
.erase("$shl");
711 cone_ct
.cell_types
.erase("$shr");
712 cone_ct
.cell_types
.erase("$sshl");
713 cone_ct
.cell_types
.erase("$sshr");
714 cone_ct
.cell_types
.erase("$shift");
715 cone_ct
.cell_types
.erase("$shiftx");
717 modwalker
.setup(design
, module
, &cone_ct
);
719 for (auto &it
: memindex
)
720 consolidate_wr_using_sat(it
.first
, it
.second
.second
);
724 struct MemorySharePass
: public Pass
{
725 MemorySharePass() : Pass("memory_share", "consolidate memory ports") { }
728 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
730 log(" memory_share [selection]\n");
732 log("This pass merges share-able memory ports into single memory ports.\n");
734 log("The following methods are used to consolidate the number of memory ports:\n");
736 log(" - When write ports are connected to async read ports accessing the same\n");
737 log(" address, then this feedback path is converted to a write port with\n");
738 log(" byte/part enable signals.\n");
740 log(" - When multiple write ports access the same address then this is converted\n");
741 log(" to a single write port with a more complex data and/or enable logic path.\n");
743 log(" - When multiple write ports are never accessed at the same time (a SAT\n");
744 log(" solver is used to determine this), then the ports are merged into a single\n");
745 log(" write port.\n");
747 log("Note that in addition to the algorithms implemented in this pass, the $memrd\n");
748 log("and $memwr cells are also subject to generic resource sharing passes (and other\n");
749 log("optimizations) such as \"share\" and \"opt_merge\".\n");
752 virtual void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) {
753 log_header("Executing MEMORY_SHARE pass (consolidating $memrc/$memwr cells).\n");
754 extra_args(args
, 1, design
);
755 for (auto module
: design
->selected_modules())
756 MemoryShareWorker(design
, module
);
760 PRIVATE_NAMESPACE_END