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"
25 PRIVATE_NAMESPACE_BEGIN
27 static bool memcells_cmp(RTLIL::Cell
*a
, RTLIL::Cell
*b
)
29 if (a
->type
== "$memrd" && b
->type
== "$memrd")
30 return a
->name
< b
->name
;
31 if (a
->type
== "$memrd" || b
->type
== "$memrd")
32 return (a
->type
== "$memrd") < (b
->type
== "$memrd");
33 return a
->parameters
.at("\\PRIORITY").as_int() < b
->parameters
.at("\\PRIORITY").as_int();
36 struct MemoryShareWorker
38 RTLIL::Design
*design
;
39 RTLIL::Module
*module
;
40 SigMap sigmap
, sigmap_xmux
;
44 std::map
<RTLIL::SigBit
, std::pair
<RTLIL::Cell
*, int>> sig_to_mux
;
45 std::map
<std::set
<std::map
<RTLIL::SigBit
, bool>>, RTLIL::SigBit
> conditions_logic_cache
;
48 // -----------------------------------------------------------------
49 // Converting feedbacks to async read ports to proper enable signals
50 // -----------------------------------------------------------------
52 bool find_data_feedback(const std::set
<RTLIL::SigBit
> &async_rd_bits
, RTLIL::SigBit sig
,
53 std::map
<RTLIL::SigBit
, bool> &state
, std::set
<std::map
<RTLIL::SigBit
, bool>> &conditions
)
55 if (async_rd_bits
.count(sig
)) {
56 conditions
.insert(state
);
60 if (sig_to_mux
.count(sig
) == 0)
63 RTLIL::Cell
*cell
= sig_to_mux
.at(sig
).first
;
64 int bit_idx
= sig_to_mux
.at(sig
).second
;
66 std::vector
<RTLIL::SigBit
> sig_a
= sigmap(cell
->getPort("\\A"));
67 std::vector
<RTLIL::SigBit
> sig_b
= sigmap(cell
->getPort("\\B"));
68 std::vector
<RTLIL::SigBit
> sig_s
= sigmap(cell
->getPort("\\S"));
69 std::vector
<RTLIL::SigBit
> sig_y
= sigmap(cell
->getPort("\\Y"));
70 log_assert(sig_y
.at(bit_idx
) == sig
);
72 for (int i
= 0; i
< int(sig_s
.size()); i
++)
73 if (state
.count(sig_s
[i
]) && state
.at(sig_s
[i
]) == true) {
74 if (find_data_feedback(async_rd_bits
, sig_b
.at(bit_idx
+ i
*sig_y
.size()), state
, conditions
)) {
75 RTLIL::SigSpec new_b
= cell
->getPort("\\B");
76 new_b
.replace(bit_idx
+ i
*sig_y
.size(), RTLIL::State::Sx
);
77 cell
->setPort("\\B", new_b
);
83 for (int i
= 0; i
< int(sig_s
.size()); i
++)
85 if (state
.count(sig_s
[i
]) && state
.at(sig_s
[i
]) == false)
88 std::map
<RTLIL::SigBit
, bool> new_state
= state
;
89 new_state
[sig_s
[i
]] = true;
91 if (find_data_feedback(async_rd_bits
, sig_b
.at(bit_idx
+ i
*sig_y
.size()), new_state
, conditions
)) {
92 RTLIL::SigSpec new_b
= cell
->getPort("\\B");
93 new_b
.replace(bit_idx
+ i
*sig_y
.size(), RTLIL::State::Sx
);
94 cell
->setPort("\\B", new_b
);
98 std::map
<RTLIL::SigBit
, bool> new_state
= state
;
99 for (int i
= 0; i
< int(sig_s
.size()); i
++)
100 new_state
[sig_s
[i
]] = false;
102 if (find_data_feedback(async_rd_bits
, sig_a
.at(bit_idx
), new_state
, conditions
)) {
103 RTLIL::SigSpec new_a
= cell
->getPort("\\A");
104 new_a
.replace(bit_idx
, RTLIL::State::Sx
);
105 cell
->setPort("\\A", new_a
);
111 RTLIL::SigBit
conditions_to_logic(std::set
<std::map
<RTLIL::SigBit
, bool>> &conditions
, int &created_conditions
)
113 if (conditions_logic_cache
.count(conditions
))
114 return conditions_logic_cache
.at(conditions
);
116 RTLIL::SigSpec terms
;
117 for (auto &cond
: conditions
) {
118 RTLIL::SigSpec sig1
, sig2
;
119 for (auto &it
: cond
) {
120 sig1
.append_bit(it
.first
);
121 sig2
.append_bit(it
.second
? RTLIL::State::S1
: RTLIL::State::S0
);
123 terms
.append(module
->Ne(NEW_ID
, sig1
, sig2
));
124 created_conditions
++;
127 if (terms
.size() > 1)
128 terms
= module
->ReduceAnd(NEW_ID
, terms
);
130 return conditions_logic_cache
[conditions
] = terms
;
133 void translate_rd_feedback_to_en(std::string memid
, std::vector
<RTLIL::Cell
*> &rd_ports
, std::vector
<RTLIL::Cell
*> &wr_ports
)
135 std::map
<RTLIL::SigSpec
, std::vector
<std::set
<RTLIL::SigBit
>>> async_rd_bits
;
136 std::map
<RTLIL::SigBit
, std::set
<RTLIL::SigBit
>> muxtree_upstream_map
;
137 std::set
<RTLIL::SigBit
> non_feedback_nets
;
139 for (auto wire_it
: module
->wires_
)
140 if (wire_it
.second
->port_output
) {
141 std::vector
<RTLIL::SigBit
> bits
= RTLIL::SigSpec(wire_it
.second
);
142 non_feedback_nets
.insert(bits
.begin(), bits
.end());
145 for (auto cell_it
: module
->cells_
)
147 RTLIL::Cell
*cell
= cell_it
.second
;
148 bool ignore_data_port
= false;
150 if (cell
->type
== "$mux" || cell
->type
== "$pmux")
152 std::vector
<RTLIL::SigBit
> sig_a
= sigmap(cell
->getPort("\\A"));
153 std::vector
<RTLIL::SigBit
> sig_b
= sigmap(cell
->getPort("\\B"));
154 std::vector
<RTLIL::SigBit
> sig_s
= sigmap(cell
->getPort("\\S"));
155 std::vector
<RTLIL::SigBit
> sig_y
= sigmap(cell
->getPort("\\Y"));
157 non_feedback_nets
.insert(sig_s
.begin(), sig_s
.end());
159 for (int i
= 0; i
< int(sig_y
.size()); i
++) {
160 muxtree_upstream_map
[sig_y
[i
]].insert(sig_a
[i
]);
161 for (int j
= 0; j
< int(sig_s
.size()); j
++)
162 muxtree_upstream_map
[sig_y
[i
]].insert(sig_b
[i
+ j
*sig_y
.size()]);
168 if ((cell
->type
== "$memwr" || cell
->type
== "$memrd") &&
169 cell
->parameters
.at("\\MEMID").decode_string() == memid
)
170 ignore_data_port
= true;
172 for (auto conn
: cell_it
.second
->connections())
174 if (ignore_data_port
&& conn
.first
== "\\DATA")
176 std::vector
<RTLIL::SigBit
> bits
= sigmap(conn
.second
);
177 non_feedback_nets
.insert(bits
.begin(), bits
.end());
181 std::set
<RTLIL::SigBit
> expand_non_feedback_nets
= non_feedback_nets
;
182 while (!expand_non_feedback_nets
.empty())
184 std::set
<RTLIL::SigBit
> new_expand_non_feedback_nets
;
186 for (auto &bit
: expand_non_feedback_nets
)
187 if (muxtree_upstream_map
.count(bit
))
188 for (auto &new_bit
: muxtree_upstream_map
.at(bit
))
189 if (!non_feedback_nets
.count(new_bit
)) {
190 non_feedback_nets
.insert(new_bit
);
191 new_expand_non_feedback_nets
.insert(new_bit
);
194 expand_non_feedback_nets
.swap(new_expand_non_feedback_nets
);
197 for (auto cell
: rd_ports
)
199 if (cell
->parameters
.at("\\CLK_ENABLE").as_bool())
202 RTLIL::SigSpec sig_addr
= sigmap(cell
->getPort("\\ADDR"));
203 std::vector
<RTLIL::SigBit
> sig_data
= sigmap(cell
->getPort("\\DATA"));
205 for (int i
= 0; i
< int(sig_data
.size()); i
++)
206 if (non_feedback_nets
.count(sig_data
[i
]))
207 goto not_pure_feedback_port
;
209 async_rd_bits
[sig_addr
].resize(std::max(async_rd_bits
.size(), sig_data
.size()));
210 for (int i
= 0; i
< int(sig_data
.size()); i
++)
211 async_rd_bits
[sig_addr
][i
].insert(sig_data
[i
]);
213 not_pure_feedback_port
:;
216 if (async_rd_bits
.empty())
219 log("Populating enable bits on write ports of memory %s.%s with aync read feedback:\n", log_id(module
), log_id(memid
));
221 for (auto cell
: wr_ports
)
223 RTLIL::SigSpec sig_addr
= sigmap_xmux(cell
->getPort("\\ADDR"));
224 if (!async_rd_bits
.count(sig_addr
))
227 log(" Analyzing write port %s.\n", log_id(cell
));
229 std::vector
<RTLIL::SigBit
> cell_data
= cell
->getPort("\\DATA");
230 std::vector
<RTLIL::SigBit
> cell_en
= cell
->getPort("\\EN");
232 int created_conditions
= 0;
233 for (int i
= 0; i
< int(cell_data
.size()); i
++)
234 if (cell_en
[i
] != RTLIL::SigBit(RTLIL::State::S0
))
236 std::map
<RTLIL::SigBit
, bool> state
;
237 std::set
<std::map
<RTLIL::SigBit
, bool>> conditions
;
239 if (cell_en
[i
].wire
!= NULL
) {
240 state
[cell_en
[i
]] = false;
241 conditions
.insert(state
);
244 find_data_feedback(async_rd_bits
.at(sig_addr
).at(i
), cell_data
[i
], state
, conditions
);
245 cell_en
[i
] = conditions_to_logic(conditions
, created_conditions
);
248 if (created_conditions
) {
249 log(" Added enable logic for %d different cases.\n", created_conditions
);
250 cell
->setPort("\\EN", cell_en
);
256 // ------------------------------------------------------
257 // Consolidate write ports that write to the same address
258 // ------------------------------------------------------
260 RTLIL::SigSpec
mask_en_naive(RTLIL::SigSpec do_mask
, RTLIL::SigSpec bits
, RTLIL::SigSpec mask_bits
)
262 // this is the naive version of the function that does not care about grouping the EN bits.
264 RTLIL::SigSpec inv_mask_bits
= module
->Not(NEW_ID
, mask_bits
);
265 RTLIL::SigSpec inv_mask_bits_filtered
= module
->Mux(NEW_ID
, RTLIL::SigSpec(RTLIL::State::S1
, bits
.size()), inv_mask_bits
, do_mask
);
266 RTLIL::SigSpec result
= module
->And(NEW_ID
, inv_mask_bits_filtered
, bits
);
270 RTLIL::SigSpec
mask_en_grouped(RTLIL::SigSpec do_mask
, RTLIL::SigSpec bits
, RTLIL::SigSpec mask_bits
)
272 // this version of the function preserves the bit grouping in the EN bits.
274 std::vector
<RTLIL::SigBit
> v_bits
= bits
;
275 std::vector
<RTLIL::SigBit
> v_mask_bits
= mask_bits
;
277 std::map
<std::pair
<RTLIL::SigBit
, RTLIL::SigBit
>, std::pair
<int, std::vector
<int>>> groups
;
278 RTLIL::SigSpec grouped_bits
, grouped_mask_bits
;
280 for (int i
= 0; i
< bits
.size(); i
++) {
281 std::pair
<RTLIL::SigBit
, RTLIL::SigBit
> key(v_bits
[i
], v_mask_bits
[i
]);
282 if (groups
.count(key
) == 0) {
283 groups
[key
].first
= grouped_bits
.size();
284 grouped_bits
.append_bit(v_bits
[i
]);
285 grouped_mask_bits
.append_bit(v_mask_bits
[i
]);
287 groups
[key
].second
.push_back(i
);
290 std::vector
<RTLIL::SigBit
> grouped_result
= mask_en_naive(do_mask
, grouped_bits
, grouped_mask_bits
);
291 RTLIL::SigSpec result
;
293 for (int i
= 0; i
< bits
.size(); i
++) {
294 std::pair
<RTLIL::SigBit
, RTLIL::SigBit
> key(v_bits
[i
], v_mask_bits
[i
]);
295 result
.append_bit(grouped_result
.at(groups
.at(key
).first
));
301 void merge_en_data(RTLIL::SigSpec
&merged_en
, RTLIL::SigSpec
&merged_data
, RTLIL::SigSpec next_en
, RTLIL::SigSpec next_data
)
303 std::vector
<RTLIL::SigBit
> v_old_en
= merged_en
;
304 std::vector
<RTLIL::SigBit
> v_next_en
= next_en
;
306 // The new merged_en signal is just the old merged_en signal and next_en OR'ed together.
307 // But of course we need to preserve the bit grouping..
309 std::map
<std::pair
<RTLIL::SigBit
, RTLIL::SigBit
>, int> groups
;
310 std::vector
<RTLIL::SigBit
> grouped_old_en
, grouped_next_en
;
311 RTLIL::SigSpec new_merged_en
;
313 for (int i
= 0; i
< int(v_old_en
.size()); i
++) {
314 std::pair
<RTLIL::SigBit
, RTLIL::SigBit
> key(v_old_en
[i
], v_next_en
[i
]);
315 if (groups
.count(key
) == 0) {
316 groups
[key
] = grouped_old_en
.size();
317 grouped_old_en
.push_back(key
.first
);
318 grouped_next_en
.push_back(key
.second
);
322 std::vector
<RTLIL::SigBit
> grouped_new_en
= module
->Or(NEW_ID
, grouped_old_en
, grouped_next_en
);
324 for (int i
= 0; i
< int(v_old_en
.size()); i
++) {
325 std::pair
<RTLIL::SigBit
, RTLIL::SigBit
> key(v_old_en
[i
], v_next_en
[i
]);
326 new_merged_en
.append_bit(grouped_new_en
.at(groups
.at(key
)));
329 // Create the new merged_data signal.
331 RTLIL::SigSpec
new_merged_data(RTLIL::State::Sx
, merged_data
.size());
333 RTLIL::SigSpec old_data_set
= module
->And(NEW_ID
, merged_en
, merged_data
);
334 RTLIL::SigSpec old_data_unset
= module
->And(NEW_ID
, merged_en
, module
->Not(NEW_ID
, merged_data
));
336 RTLIL::SigSpec new_data_set
= module
->And(NEW_ID
, next_en
, next_data
);
337 RTLIL::SigSpec new_data_unset
= module
->And(NEW_ID
, next_en
, module
->Not(NEW_ID
, next_data
));
339 new_merged_data
= module
->Or(NEW_ID
, new_merged_data
, old_data_set
);
340 new_merged_data
= module
->And(NEW_ID
, new_merged_data
, module
->Not(NEW_ID
, old_data_unset
));
342 new_merged_data
= module
->Or(NEW_ID
, new_merged_data
, new_data_set
);
343 new_merged_data
= module
->And(NEW_ID
, new_merged_data
, module
->Not(NEW_ID
, new_data_unset
));
345 // Update merged_* signals
347 merged_en
= new_merged_en
;
348 merged_data
= new_merged_data
;
351 void consolidate_wr_by_addr(std::string memid
, std::vector
<RTLIL::Cell
*> &wr_ports
)
353 if (wr_ports
.size() <= 1)
356 log("Consolidating write ports of memory %s.%s by address:\n", log_id(module
), log_id(memid
));
358 std::map
<RTLIL::SigSpec
, int> last_port_by_addr
;
359 std::vector
<std::vector
<bool>> active_bits_on_port
;
361 bool cache_clk_enable
= false;
362 bool cache_clk_polarity
= false;
363 RTLIL::SigSpec cache_clk
;
365 for (int i
= 0; i
< int(wr_ports
.size()); i
++)
367 RTLIL::Cell
*cell
= wr_ports
.at(i
);
368 RTLIL::SigSpec addr
= sigmap_xmux(cell
->getPort("\\ADDR"));
370 if (cell
->parameters
.at("\\CLK_ENABLE").as_bool() != cache_clk_enable
||
371 (cache_clk_enable
&& (sigmap(cell
->getPort("\\CLK")) != cache_clk
||
372 cell
->parameters
.at("\\CLK_POLARITY").as_bool() != cache_clk_polarity
)))
374 cache_clk_enable
= cell
->parameters
.at("\\CLK_ENABLE").as_bool();
375 cache_clk_polarity
= cell
->parameters
.at("\\CLK_POLARITY").as_bool();
376 cache_clk
= sigmap(cell
->getPort("\\CLK"));
377 last_port_by_addr
.clear();
379 if (cache_clk_enable
)
380 log(" New clock domain: %s %s\n", cache_clk_polarity
? "posedge" : "negedge", log_signal(cache_clk
));
382 log(" New clock domain: unclocked\n");
385 log(" Port %d (%s) has addr %s.\n", i
, log_id(cell
), log_signal(addr
));
387 log(" Active bits: ");
388 std::vector
<RTLIL::SigBit
> en_bits
= sigmap(cell
->getPort("\\EN"));
389 active_bits_on_port
.push_back(std::vector
<bool>(en_bits
.size()));
390 for (int k
= int(en_bits
.size())-1; k
>= 0; k
--) {
391 active_bits_on_port
[i
][k
] = en_bits
[k
].wire
!= NULL
|| en_bits
[k
].data
!= RTLIL::State::S0
;
392 log("%c", active_bits_on_port
[i
][k
] ? '1' : '0');
396 if (last_port_by_addr
.count(addr
))
398 int last_i
= last_port_by_addr
.at(addr
);
399 log(" Merging port %d into this one.\n", last_i
);
401 bool found_overlapping_bits
= false;
402 for (int k
= 0; k
< int(en_bits
.size()); k
++) {
403 if (active_bits_on_port
[i
][k
] && active_bits_on_port
[last_i
][k
])
404 found_overlapping_bits
= true;
405 active_bits_on_port
[i
][k
] = active_bits_on_port
[i
][k
] || active_bits_on_port
[last_i
][k
];
408 // Force this ports addr input to addr directly (skip don't care muxes)
410 cell
->setPort("\\ADDR", addr
);
412 // If any of the ports between `last_i' and `i' write to the same address, this
413 // will have priority over whatever `last_i` wrote. So we need to revisit those
414 // ports and mask the EN bits accordingly.
416 RTLIL::SigSpec merged_en
= sigmap(wr_ports
[last_i
]->getPort("\\EN"));
418 for (int j
= last_i
+1; j
< i
; j
++)
420 if (wr_ports
[j
] == NULL
)
423 for (int k
= 0; k
< int(en_bits
.size()); k
++)
424 if (active_bits_on_port
[i
][k
] && active_bits_on_port
[j
][k
])
425 goto found_overlapping_bits_i_j
;
428 found_overlapping_bits_i_j
:
429 log(" Creating collosion-detect logic for port %d.\n", j
);
430 RTLIL::SigSpec is_same_addr
= module
->addWire(NEW_ID
);
431 module
->addEq(NEW_ID
, addr
, wr_ports
[j
]->getPort("\\ADDR"), is_same_addr
);
432 merged_en
= mask_en_grouped(is_same_addr
, merged_en
, sigmap(wr_ports
[j
]->getPort("\\EN")));
436 // Then we need to merge the (masked) EN and the DATA signals.
438 RTLIL::SigSpec merged_data
= wr_ports
[last_i
]->getPort("\\DATA");
439 if (found_overlapping_bits
) {
440 log(" Creating logic for merging DATA and EN ports.\n");
441 merge_en_data(merged_en
, merged_data
, sigmap(cell
->getPort("\\EN")), sigmap(cell
->getPort("\\DATA")));
443 RTLIL::SigSpec cell_en
= sigmap(cell
->getPort("\\EN"));
444 RTLIL::SigSpec cell_data
= sigmap(cell
->getPort("\\DATA"));
445 for (int k
= 0; k
< int(en_bits
.size()); k
++)
446 if (!active_bits_on_port
[last_i
][k
]) {
447 merged_en
.replace(k
, cell_en
.extract(k
, 1));
448 merged_data
.replace(k
, cell_data
.extract(k
, 1));
452 // Connect the new EN and DATA signals and remove the old write port.
454 cell
->setPort("\\EN", merged_en
);
455 cell
->setPort("\\DATA", merged_data
);
457 module
->remove(wr_ports
[last_i
]);
458 wr_ports
[last_i
] = NULL
;
460 log(" Active bits: ");
461 std::vector
<RTLIL::SigBit
> en_bits
= sigmap(cell
->getPort("\\EN"));
462 active_bits_on_port
.push_back(std::vector
<bool>(en_bits
.size()));
463 for (int k
= int(en_bits
.size())-1; k
>= 0; k
--)
464 log("%c", active_bits_on_port
[i
][k
] ? '1' : '0');
468 last_port_by_addr
[addr
] = i
;
471 // Clean up `wr_ports': remove all NULL entries
473 std::vector
<RTLIL::Cell
*> wr_ports_with_nulls
;
474 wr_ports_with_nulls
.swap(wr_ports
);
476 for (auto cell
: wr_ports_with_nulls
)
478 wr_ports
.push_back(cell
);
482 // --------------------------------------------------------
483 // Consolidate write ports using sat-based resource sharing
484 // --------------------------------------------------------
486 void consolidate_wr_using_sat(std::string memid
, std::vector
<RTLIL::Cell
*> &wr_ports
)
488 if (wr_ports
.size() <= 1)
492 SatGen
satgen(&ez
, &modwalker
.sigmap
);
494 // find list of considered ports and port pairs
496 std::set
<int> considered_ports
;
497 std::set
<int> considered_port_pairs
;
499 for (int i
= 0; i
< int(wr_ports
.size()); i
++) {
500 std::vector
<RTLIL::SigBit
> bits
= modwalker
.sigmap(wr_ports
[i
]->getPort("\\EN"));
501 for (auto bit
: bits
)
502 if (bit
== RTLIL::State::S1
)
503 goto port_is_always_active
;
504 if (modwalker
.has_drivers(bits
))
505 considered_ports
.insert(i
);
506 port_is_always_active
:;
509 log("Consolidating write ports of memory %s.%s using sat-based resource sharing:\n", log_id(module
), log_id(memid
));
511 bool cache_clk_enable
= false;
512 bool cache_clk_polarity
= false;
513 RTLIL::SigSpec cache_clk
;
515 for (int i
= 0; i
< int(wr_ports
.size()); i
++)
517 RTLIL::Cell
*cell
= wr_ports
.at(i
);
519 if (cell
->parameters
.at("\\CLK_ENABLE").as_bool() != cache_clk_enable
||
520 (cache_clk_enable
&& (sigmap(cell
->getPort("\\CLK")) != cache_clk
||
521 cell
->parameters
.at("\\CLK_POLARITY").as_bool() != cache_clk_polarity
)))
523 cache_clk_enable
= cell
->parameters
.at("\\CLK_ENABLE").as_bool();
524 cache_clk_polarity
= cell
->parameters
.at("\\CLK_POLARITY").as_bool();
525 cache_clk
= sigmap(cell
->getPort("\\CLK"));
527 else if (i
> 0 && considered_ports
.count(i
-1) && considered_ports
.count(i
))
528 considered_port_pairs
.insert(i
);
530 if (cache_clk_enable
)
531 log(" Port %d (%s) on %s %s: %s\n", i
, log_id(cell
),
532 cache_clk_polarity
? "posedge" : "negedge", log_signal(cache_clk
),
533 considered_ports
.count(i
) ? "considered" : "not considered");
535 log(" Port %d (%s) unclocked: %s\n", i
, log_id(cell
),
536 considered_ports
.count(i
) ? "considered" : "not considered");
539 if (considered_port_pairs
.size() < 1) {
540 log(" No two subsequent ports in same clock domain considered -> nothing to consolidate.\n");
544 // create SAT representation of common input cone of all considered EN signals
546 std::set
<RTLIL::Cell
*> sat_cells
;
547 std::set
<RTLIL::SigBit
> bits_queue
;
548 std::map
<int, int> port_to_sat_variable
;
550 for (int i
= 0; i
< int(wr_ports
.size()); i
++)
551 if (considered_port_pairs
.count(i
) || considered_port_pairs
.count(i
+1))
553 RTLIL::SigSpec sig
= modwalker
.sigmap(wr_ports
[i
]->getPort("\\EN"));
554 port_to_sat_variable
[i
] = ez
.expression(ez
.OpOr
, satgen
.importSigSpec(sig
));
556 std::vector
<RTLIL::SigBit
> bits
= sig
;
557 bits_queue
.insert(bits
.begin(), bits
.end());
560 while (!bits_queue
.empty())
562 std::set
<ModWalker::PortBit
> portbits
;
563 modwalker
.get_drivers(portbits
, bits_queue
);
566 for (auto &pbit
: portbits
)
567 if (sat_cells
.count(pbit
.cell
) == 0 && cone_ct
.cell_known(pbit
.cell
->type
)) {
568 std::set
<RTLIL::SigBit
> &cell_inputs
= modwalker
.cell_inputs
[pbit
.cell
];
569 bits_queue
.insert(cell_inputs
.begin(), cell_inputs
.end());
570 sat_cells
.insert(pbit
.cell
);
574 log(" Common input cone for all EN signals: %d cells.\n", int(sat_cells
.size()));
576 for (auto cell
: sat_cells
)
577 satgen
.importCell(cell
);
579 log(" Size of unconstrained SAT problem: %d variables, %d clauses\n", ez
.numCnfVariables(), ez
.numCnfClauses());
581 // merge subsequent ports if possible
583 for (int i
= 0; i
< int(wr_ports
.size()); i
++)
585 if (!considered_port_pairs
.count(i
))
588 if (ez
.solve(port_to_sat_variable
.at(i
-1), port_to_sat_variable
.at(i
))) {
589 log(" According to SAT solver sharing of port %d with port %d is not possible.\n", i
-1, i
);
593 log(" Merging port %d into port %d.\n", i
-1, i
);
594 port_to_sat_variable
.at(i
) = ez
.OR(port_to_sat_variable
.at(i
-1), port_to_sat_variable
.at(i
));
596 RTLIL::SigSpec last_addr
= wr_ports
[i
-1]->getPort("\\ADDR");
597 RTLIL::SigSpec last_data
= wr_ports
[i
-1]->getPort("\\DATA");
598 std::vector
<RTLIL::SigBit
> last_en
= modwalker
.sigmap(wr_ports
[i
-1]->getPort("\\EN"));
600 RTLIL::SigSpec this_addr
= wr_ports
[i
]->getPort("\\ADDR");
601 RTLIL::SigSpec this_data
= wr_ports
[i
]->getPort("\\DATA");
602 std::vector
<RTLIL::SigBit
> this_en
= modwalker
.sigmap(wr_ports
[i
]->getPort("\\EN"));
604 RTLIL::SigBit this_en_active
= module
->ReduceOr(NEW_ID
, this_en
);
606 wr_ports
[i
]->setPort("\\ADDR", module
->Mux(NEW_ID
, last_addr
, this_addr
, this_en_active
));
607 wr_ports
[i
]->setPort("\\DATA", module
->Mux(NEW_ID
, last_data
, this_data
, this_en_active
));
609 std::map
<std::pair
<RTLIL::SigBit
, RTLIL::SigBit
>, int> groups_en
;
610 RTLIL::SigSpec grouped_last_en
, grouped_this_en
, en
;
611 RTLIL::Wire
*grouped_en
= module
->addWire(NEW_ID
, 0);
613 for (int j
= 0; j
< int(this_en
.size()); j
++) {
614 std::pair
<RTLIL::SigBit
, RTLIL::SigBit
> key(last_en
[j
], this_en
[j
]);
615 if (!groups_en
.count(key
)) {
616 grouped_last_en
.append_bit(last_en
[j
]);
617 grouped_this_en
.append_bit(this_en
[j
]);
618 groups_en
[key
] = grouped_en
->width
;
621 en
.append(RTLIL::SigSpec(grouped_en
, groups_en
[key
]));
624 module
->addMux(NEW_ID
, grouped_last_en
, grouped_this_en
, this_en_active
, grouped_en
);
625 wr_ports
[i
]->setPort("\\EN", en
);
627 module
->remove(wr_ports
[i
-1]);
628 wr_ports
[i
-1] = NULL
;
631 // Clean up `wr_ports': remove all NULL entries
633 std::vector
<RTLIL::Cell
*> wr_ports_with_nulls
;
634 wr_ports_with_nulls
.swap(wr_ports
);
636 for (auto cell
: wr_ports_with_nulls
)
638 wr_ports
.push_back(cell
);
646 MemoryShareWorker(RTLIL::Design
*design
, RTLIL::Module
*module
) :
647 design(design
), module(module
), sigmap(module
)
649 std::map
<std::string
, std::pair
<std::vector
<RTLIL::Cell
*>, std::vector
<RTLIL::Cell
*>>> memindex
;
651 sigmap_xmux
= sigmap
;
652 for (auto &it
: module
->cells_
)
654 RTLIL::Cell
*cell
= it
.second
;
656 if (cell
->type
== "$memrd")
657 memindex
[cell
->parameters
.at("\\MEMID").decode_string()].first
.push_back(cell
);
659 if (cell
->type
== "$memwr")
660 memindex
[cell
->parameters
.at("\\MEMID").decode_string()].second
.push_back(cell
);
662 if (cell
->type
== "$mux")
664 RTLIL::SigSpec sig_a
= sigmap_xmux(cell
->getPort("\\A"));
665 RTLIL::SigSpec sig_b
= sigmap_xmux(cell
->getPort("\\B"));
667 if (sig_a
.is_fully_undef())
668 sigmap_xmux
.add(cell
->getPort("\\Y"), sig_b
);
669 else if (sig_b
.is_fully_undef())
670 sigmap_xmux
.add(cell
->getPort("\\Y"), sig_a
);
673 if (cell
->type
== "$mux" || cell
->type
== "$pmux")
675 std::vector
<RTLIL::SigBit
> sig_y
= sigmap(cell
->getPort("\\Y"));
676 for (int i
= 0; i
< int(sig_y
.size()); i
++)
677 sig_to_mux
[sig_y
[i
]] = std::pair
<RTLIL::Cell
*, int>(cell
, i
);
681 for (auto &it
: memindex
) {
682 std::sort(it
.second
.first
.begin(), it
.second
.first
.end(), memcells_cmp
);
683 std::sort(it
.second
.second
.begin(), it
.second
.second
.end(), memcells_cmp
);
684 translate_rd_feedback_to_en(it
.first
, it
.second
.first
, it
.second
.second
);
685 consolidate_wr_by_addr(it
.first
, it
.second
.second
);
688 cone_ct
.setup_internals();
689 cone_ct
.cell_types
.erase("$mul");
690 cone_ct
.cell_types
.erase("$mod");
691 cone_ct
.cell_types
.erase("$div");
692 cone_ct
.cell_types
.erase("$pow");
693 cone_ct
.cell_types
.erase("$shl");
694 cone_ct
.cell_types
.erase("$shr");
695 cone_ct
.cell_types
.erase("$sshl");
696 cone_ct
.cell_types
.erase("$sshr");
697 cone_ct
.cell_types
.erase("$shift");
698 cone_ct
.cell_types
.erase("$shiftx");
700 modwalker
.setup(design
, module
, &cone_ct
);
702 for (auto &it
: memindex
)
703 consolidate_wr_using_sat(it
.first
, it
.second
.second
);
707 struct MemorySharePass
: public Pass
{
708 MemorySharePass() : Pass("memory_share", "consolidate memory ports") { }
711 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
713 log(" memory_share [selection]\n");
715 log("This pass merges share-able memory ports into single memory ports.\n");
717 log("The following methods are used to consolidate the number of memory ports:\n");
719 log(" - When write ports are connected to async read ports accessing the same\n");
720 log(" address, then this feedback path is converted to a write port with\n");
721 log(" byte/part enable signals.\n");
723 log(" - When multiple write ports access the same address then this is converted\n");
724 log(" to a single write port with a more complex data and/or enable logic path.\n");
726 log(" - When multiple write ports are never accessed at the same time (a SAT\n");
727 log(" solver is used to determine this), then the ports are merged into a single\n");
728 log(" write port.\n");
730 log("Note that in addition to the algorithms implemented in this pass, the $memrd\n");
731 log("and $memwr cells are also subject to generic resource sharing passes (and other\n");
732 log("optimizations) such as opt_share.\n");
735 virtual void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) {
736 log_header("Executing MEMORY_SHARE pass (consolidating $memrc/$memwr cells).\n");
737 extra_args(args
, 1, design
);
738 for (auto module
: design
->selected_modules())
739 MemoryShareWorker(design
, module
);
743 PRIVATE_NAMESPACE_END