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
== ID($memrd
) && b
->type
== ID($memrd
))
31 return a
->name
< b
->name
;
32 if (a
->type
== ID($memrd
) || b
->type
== ID($memrd
))
33 return (a
->type
== ID($memrd
)) < (b
->type
== ID($memrd
));
34 return a
->parameters
.at(ID::PRIORITY
).as_int() < b
->parameters
.at(ID::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
<pair
<std::set
<std::map
<SigBit
, bool>>, SigBit
>, 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(ID::A
));
68 std::vector
<RTLIL::SigBit
> sig_b
= sigmap(cell
->getPort(ID::B
));
69 std::vector
<RTLIL::SigBit
> sig_s
= sigmap(cell
->getPort(ID::S
));
70 std::vector
<RTLIL::SigBit
> sig_y
= sigmap(cell
->getPort(ID::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(ID::B
);
77 new_b
.replace(bit_idx
+ i
*sig_y
.size(), RTLIL::State::Sx
);
78 cell
->setPort(ID::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(ID::B
);
94 new_b
.replace(bit_idx
+ i
*sig_y
.size(), RTLIL::State::Sx
);
95 cell
->setPort(ID::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(ID::A
);
105 new_a
.replace(bit_idx
, RTLIL::State::Sx
);
106 cell
->setPort(ID::A
, new_a
);
112 RTLIL::SigBit
conditions_to_logic(std::set
<std::map
<RTLIL::SigBit
, bool>> &conditions
, SigBit olden
, int &created_conditions
)
114 auto key
= make_pair(conditions
, olden
);
116 if (conditions_logic_cache
.count(key
))
117 return conditions_logic_cache
.at(key
);
119 RTLIL::SigSpec terms
;
120 for (auto &cond
: conditions
) {
121 RTLIL::SigSpec sig1
, sig2
;
122 for (auto &it
: cond
) {
123 sig1
.append(it
.first
);
124 sig2
.append(it
.second
? RTLIL::State::S1
: RTLIL::State::S0
);
126 terms
.append(module
->Ne(NEW_ID
, sig1
, sig2
));
127 created_conditions
++;
130 if (olden
.wire
!= nullptr || olden
!= State::S1
)
133 if (GetSize(terms
) == 0)
136 if (GetSize(terms
) > 1)
137 terms
= module
->ReduceAnd(NEW_ID
, terms
);
139 return conditions_logic_cache
[key
] = terms
;
142 void translate_rd_feedback_to_en(std::string memid
, std::vector
<RTLIL::Cell
*> &rd_ports
, std::vector
<RTLIL::Cell
*> &wr_ports
)
144 std::map
<RTLIL::SigSpec
, std::vector
<std::set
<RTLIL::SigBit
>>> async_rd_bits
;
145 std::map
<RTLIL::SigBit
, std::set
<RTLIL::SigBit
>> muxtree_upstream_map
;
146 std::set
<RTLIL::SigBit
> non_feedback_nets
;
148 for (auto wire
: module
->wires())
149 if (wire
->port_output
) {
150 std::vector
<RTLIL::SigBit
> bits
= sigmap(wire
);
151 non_feedback_nets
.insert(bits
.begin(), bits
.end());
154 for (auto cell
: module
->cells())
156 bool ignore_data_port
= false;
158 if (cell
->type
.in(ID($mux
), ID($pmux
)))
160 std::vector
<RTLIL::SigBit
> sig_a
= sigmap(cell
->getPort(ID::A
));
161 std::vector
<RTLIL::SigBit
> sig_b
= sigmap(cell
->getPort(ID::B
));
162 std::vector
<RTLIL::SigBit
> sig_s
= sigmap(cell
->getPort(ID::S
));
163 std::vector
<RTLIL::SigBit
> sig_y
= sigmap(cell
->getPort(ID::Y
));
165 non_feedback_nets
.insert(sig_s
.begin(), sig_s
.end());
167 for (int i
= 0; i
< int(sig_y
.size()); i
++) {
168 muxtree_upstream_map
[sig_y
[i
]].insert(sig_a
[i
]);
169 for (int j
= 0; j
< int(sig_s
.size()); j
++)
170 muxtree_upstream_map
[sig_y
[i
]].insert(sig_b
[i
+ j
*sig_y
.size()]);
176 if (cell
->type
.in(ID($memwr
), ID($memrd
)) &&
177 cell
->parameters
.at(ID::MEMID
).decode_string() == memid
)
178 ignore_data_port
= true;
180 for (auto conn
: cell
->connections())
182 if (ignore_data_port
&& conn
.first
== ID::DATA
)
184 std::vector
<RTLIL::SigBit
> bits
= sigmap(conn
.second
);
185 non_feedback_nets
.insert(bits
.begin(), bits
.end());
189 std::set
<RTLIL::SigBit
> expand_non_feedback_nets
= non_feedback_nets
;
190 while (!expand_non_feedback_nets
.empty())
192 std::set
<RTLIL::SigBit
> new_expand_non_feedback_nets
;
194 for (auto &bit
: expand_non_feedback_nets
)
195 if (muxtree_upstream_map
.count(bit
))
196 for (auto &new_bit
: muxtree_upstream_map
.at(bit
))
197 if (!non_feedback_nets
.count(new_bit
)) {
198 non_feedback_nets
.insert(new_bit
);
199 new_expand_non_feedback_nets
.insert(new_bit
);
202 expand_non_feedback_nets
.swap(new_expand_non_feedback_nets
);
205 for (auto cell
: rd_ports
)
207 if (cell
->parameters
.at(ID::CLK_ENABLE
).as_bool())
210 RTLIL::SigSpec sig_addr
= sigmap(cell
->getPort(ID::ADDR
));
211 std::vector
<RTLIL::SigBit
> sig_data
= sigmap(cell
->getPort(ID::DATA
));
213 for (int i
= 0; i
< int(sig_data
.size()); i
++)
214 if (non_feedback_nets
.count(sig_data
[i
]))
215 goto not_pure_feedback_port
;
217 async_rd_bits
[sig_addr
].resize(max(async_rd_bits
.size(), sig_data
.size()));
218 for (int i
= 0; i
< int(sig_data
.size()); i
++)
219 async_rd_bits
[sig_addr
][i
].insert(sig_data
[i
]);
221 not_pure_feedback_port
:;
224 if (async_rd_bits
.empty())
227 log("Populating enable bits on write ports of memory %s.%s with aync read feedback:\n", log_id(module
), log_id(memid
));
229 for (auto cell
: wr_ports
)
231 RTLIL::SigSpec sig_addr
= sigmap_xmux(cell
->getPort(ID::ADDR
));
232 if (!async_rd_bits
.count(sig_addr
))
235 log(" Analyzing write port %s.\n", log_id(cell
));
237 std::vector
<RTLIL::SigBit
> cell_data
= cell
->getPort(ID::DATA
);
238 std::vector
<RTLIL::SigBit
> cell_en
= cell
->getPort(ID::EN
);
240 int created_conditions
= 0;
241 for (int i
= 0; i
< int(cell_data
.size()); i
++)
242 if (cell_en
[i
] != RTLIL::SigBit(RTLIL::State::S0
))
244 std::map
<RTLIL::SigBit
, bool> state
;
245 std::set
<std::map
<RTLIL::SigBit
, bool>> conditions
;
247 find_data_feedback(async_rd_bits
.at(sig_addr
).at(i
), cell_data
[i
], state
, conditions
);
248 cell_en
[i
] = conditions_to_logic(conditions
, cell_en
[i
], created_conditions
);
251 if (created_conditions
) {
252 log(" Added enable logic for %d different cases.\n", created_conditions
);
253 cell
->setPort(ID::EN
, cell_en
);
259 // ------------------------------------------------------
260 // Consolidate write ports that write to the same address
261 // ------------------------------------------------------
263 RTLIL::SigSpec
mask_en_naive(RTLIL::SigSpec do_mask
, RTLIL::SigSpec bits
, RTLIL::SigSpec mask_bits
)
265 // this is the naive version of the function that does not care about grouping the EN bits.
267 RTLIL::SigSpec inv_mask_bits
= module
->Not(NEW_ID
, mask_bits
);
268 RTLIL::SigSpec inv_mask_bits_filtered
= module
->Mux(NEW_ID
, RTLIL::SigSpec(RTLIL::State::S1
, bits
.size()), inv_mask_bits
, do_mask
);
269 RTLIL::SigSpec result
= module
->And(NEW_ID
, inv_mask_bits_filtered
, bits
);
273 RTLIL::SigSpec
mask_en_grouped(RTLIL::SigSpec do_mask
, RTLIL::SigSpec bits
, RTLIL::SigSpec mask_bits
)
275 // this version of the function preserves the bit grouping in the EN bits.
277 std::vector
<RTLIL::SigBit
> v_bits
= bits
;
278 std::vector
<RTLIL::SigBit
> v_mask_bits
= mask_bits
;
280 std::map
<std::pair
<RTLIL::SigBit
, RTLIL::SigBit
>, std::pair
<int, std::vector
<int>>> groups
;
281 RTLIL::SigSpec grouped_bits
, grouped_mask_bits
;
283 for (int i
= 0; i
< bits
.size(); i
++) {
284 std::pair
<RTLIL::SigBit
, RTLIL::SigBit
> key(v_bits
[i
], v_mask_bits
[i
]);
285 if (groups
.count(key
) == 0) {
286 groups
[key
].first
= grouped_bits
.size();
287 grouped_bits
.append(v_bits
[i
]);
288 grouped_mask_bits
.append(v_mask_bits
[i
]);
290 groups
[key
].second
.push_back(i
);
293 std::vector
<RTLIL::SigBit
> grouped_result
= mask_en_naive(do_mask
, grouped_bits
, grouped_mask_bits
);
294 RTLIL::SigSpec result
;
296 for (int i
= 0; i
< bits
.size(); i
++) {
297 std::pair
<RTLIL::SigBit
, RTLIL::SigBit
> key(v_bits
[i
], v_mask_bits
[i
]);
298 result
.append(grouped_result
.at(groups
.at(key
).first
));
304 void merge_en_data(RTLIL::SigSpec
&merged_en
, RTLIL::SigSpec
&merged_data
, RTLIL::SigSpec next_en
, RTLIL::SigSpec next_data
)
306 std::vector
<RTLIL::SigBit
> v_old_en
= merged_en
;
307 std::vector
<RTLIL::SigBit
> v_next_en
= next_en
;
309 // The new merged_en signal is just the old merged_en signal and next_en OR'ed together.
310 // But of course we need to preserve the bit grouping..
312 std::map
<std::pair
<RTLIL::SigBit
, RTLIL::SigBit
>, int> groups
;
313 std::vector
<RTLIL::SigBit
> grouped_old_en
, grouped_next_en
;
314 RTLIL::SigSpec new_merged_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 if (groups
.count(key
) == 0) {
319 groups
[key
] = grouped_old_en
.size();
320 grouped_old_en
.push_back(key
.first
);
321 grouped_next_en
.push_back(key
.second
);
325 std::vector
<RTLIL::SigBit
> grouped_new_en
= module
->Or(NEW_ID
, grouped_old_en
, grouped_next_en
);
327 for (int i
= 0; i
< int(v_old_en
.size()); i
++) {
328 std::pair
<RTLIL::SigBit
, RTLIL::SigBit
> key(v_old_en
[i
], v_next_en
[i
]);
329 new_merged_en
.append(grouped_new_en
.at(groups
.at(key
)));
332 // Create the new merged_data signal.
334 RTLIL::SigSpec
new_merged_data(RTLIL::State::Sx
, merged_data
.size());
336 RTLIL::SigSpec old_data_set
= module
->And(NEW_ID
, merged_en
, merged_data
);
337 RTLIL::SigSpec old_data_unset
= module
->And(NEW_ID
, merged_en
, module
->Not(NEW_ID
, merged_data
));
339 RTLIL::SigSpec new_data_set
= module
->And(NEW_ID
, next_en
, next_data
);
340 RTLIL::SigSpec new_data_unset
= module
->And(NEW_ID
, next_en
, module
->Not(NEW_ID
, next_data
));
342 new_merged_data
= module
->Or(NEW_ID
, new_merged_data
, old_data_set
);
343 new_merged_data
= module
->And(NEW_ID
, new_merged_data
, module
->Not(NEW_ID
, old_data_unset
));
345 new_merged_data
= module
->Or(NEW_ID
, new_merged_data
, new_data_set
);
346 new_merged_data
= module
->And(NEW_ID
, new_merged_data
, module
->Not(NEW_ID
, new_data_unset
));
348 // Update merged_* signals
350 merged_en
= new_merged_en
;
351 merged_data
= new_merged_data
;
354 void consolidate_wr_by_addr(std::string memid
, std::vector
<RTLIL::Cell
*> &wr_ports
)
356 if (wr_ports
.size() <= 1)
359 log("Consolidating write ports of memory %s.%s by address:\n", log_id(module
), log_id(memid
));
361 std::map
<RTLIL::SigSpec
, int> last_port_by_addr
;
362 std::vector
<std::vector
<bool>> active_bits_on_port
;
364 bool cache_clk_enable
= false;
365 bool cache_clk_polarity
= false;
366 RTLIL::SigSpec cache_clk
;
368 for (int i
= 0; i
< int(wr_ports
.size()); i
++)
370 RTLIL::Cell
*cell
= wr_ports
.at(i
);
371 RTLIL::SigSpec addr
= sigmap_xmux(cell
->getPort(ID::ADDR
));
373 if (cell
->parameters
.at(ID::CLK_ENABLE
).as_bool() != cache_clk_enable
||
374 (cache_clk_enable
&& (sigmap(cell
->getPort(ID::CLK
)) != cache_clk
||
375 cell
->parameters
.at(ID::CLK_POLARITY
).as_bool() != cache_clk_polarity
)))
377 cache_clk_enable
= cell
->parameters
.at(ID::CLK_ENABLE
).as_bool();
378 cache_clk_polarity
= cell
->parameters
.at(ID::CLK_POLARITY
).as_bool();
379 cache_clk
= sigmap(cell
->getPort(ID::CLK
));
380 last_port_by_addr
.clear();
382 if (cache_clk_enable
)
383 log(" New clock domain: %s %s\n", cache_clk_polarity
? "posedge" : "negedge", log_signal(cache_clk
));
385 log(" New clock domain: unclocked\n");
388 log(" Port %d (%s) has addr %s.\n", i
, log_id(cell
), log_signal(addr
));
390 log(" Active bits: ");
391 std::vector
<RTLIL::SigBit
> en_bits
= sigmap(cell
->getPort(ID::EN
));
392 active_bits_on_port
.push_back(std::vector
<bool>(en_bits
.size()));
393 for (int k
= int(en_bits
.size())-1; k
>= 0; k
--) {
394 active_bits_on_port
[i
][k
] = en_bits
[k
].wire
!= NULL
|| en_bits
[k
].data
!= RTLIL::State::S0
;
395 log("%c", active_bits_on_port
[i
][k
] ? '1' : '0');
399 if (last_port_by_addr
.count(addr
))
401 int last_i
= last_port_by_addr
.at(addr
);
402 log(" Merging port %d into this one.\n", last_i
);
404 bool found_overlapping_bits
= false;
405 for (int k
= 0; k
< int(en_bits
.size()); k
++) {
406 if (active_bits_on_port
[i
][k
] && active_bits_on_port
[last_i
][k
])
407 found_overlapping_bits
= true;
408 active_bits_on_port
[i
][k
] = active_bits_on_port
[i
][k
] || active_bits_on_port
[last_i
][k
];
411 // Force this ports addr input to addr directly (skip don't care muxes)
413 cell
->setPort(ID::ADDR
, addr
);
415 // If any of the ports between `last_i' and `i' write to the same address, this
416 // will have priority over whatever `last_i` wrote. So we need to revisit those
417 // ports and mask the EN bits accordingly.
419 RTLIL::SigSpec merged_en
= sigmap(wr_ports
[last_i
]->getPort(ID::EN
));
421 for (int j
= last_i
+1; j
< i
; j
++)
423 if (wr_ports
[j
] == NULL
)
426 for (int k
= 0; k
< int(en_bits
.size()); k
++)
427 if (active_bits_on_port
[i
][k
] && active_bits_on_port
[j
][k
])
428 goto found_overlapping_bits_i_j
;
431 found_overlapping_bits_i_j
:
432 log(" Creating collosion-detect logic for port %d.\n", j
);
433 RTLIL::SigSpec is_same_addr
= module
->addWire(NEW_ID
);
434 module
->addEq(NEW_ID
, addr
, wr_ports
[j
]->getPort(ID::ADDR
), is_same_addr
);
435 merged_en
= mask_en_grouped(is_same_addr
, merged_en
, sigmap(wr_ports
[j
]->getPort(ID::EN
)));
439 // Then we need to merge the (masked) EN and the DATA signals.
441 RTLIL::SigSpec merged_data
= wr_ports
[last_i
]->getPort(ID::DATA
);
442 if (found_overlapping_bits
) {
443 log(" Creating logic for merging DATA and EN ports.\n");
444 merge_en_data(merged_en
, merged_data
, sigmap(cell
->getPort(ID::EN
)), sigmap(cell
->getPort(ID::DATA
)));
446 RTLIL::SigSpec cell_en
= sigmap(cell
->getPort(ID::EN
));
447 RTLIL::SigSpec cell_data
= sigmap(cell
->getPort(ID::DATA
));
448 for (int k
= 0; k
< int(en_bits
.size()); k
++)
449 if (!active_bits_on_port
[last_i
][k
]) {
450 merged_en
.replace(k
, cell_en
.extract(k
, 1));
451 merged_data
.replace(k
, cell_data
.extract(k
, 1));
455 // Connect the new EN and DATA signals and remove the old write port.
457 cell
->setPort(ID::EN
, merged_en
);
458 cell
->setPort(ID::DATA
, merged_data
);
460 module
->remove(wr_ports
[last_i
]);
461 wr_ports
[last_i
] = NULL
;
463 log(" Active bits: ");
464 std::vector
<RTLIL::SigBit
> en_bits
= sigmap(cell
->getPort(ID::EN
));
465 active_bits_on_port
.push_back(std::vector
<bool>(en_bits
.size()));
466 for (int k
= int(en_bits
.size())-1; k
>= 0; k
--)
467 log("%c", active_bits_on_port
[i
][k
] ? '1' : '0');
471 last_port_by_addr
[addr
] = i
;
474 // Clean up `wr_ports': remove all NULL entries
476 std::vector
<RTLIL::Cell
*> wr_ports_with_nulls
;
477 wr_ports_with_nulls
.swap(wr_ports
);
479 for (auto cell
: wr_ports_with_nulls
)
481 wr_ports
.push_back(cell
);
485 // --------------------------------------------------------
486 // Consolidate write ports using sat-based resource sharing
487 // --------------------------------------------------------
489 void consolidate_wr_using_sat(std::string memid
, std::vector
<RTLIL::Cell
*> &wr_ports
)
491 if (wr_ports
.size() <= 1)
495 SatGen
satgen(ez
.get(), &modwalker
.sigmap
);
497 // find list of considered ports and port pairs
499 std::set
<int> considered_ports
;
500 std::set
<int> considered_port_pairs
;
502 for (int i
= 0; i
< int(wr_ports
.size()); i
++) {
503 std::vector
<RTLIL::SigBit
> bits
= modwalker
.sigmap(wr_ports
[i
]->getPort(ID::EN
));
504 for (auto bit
: bits
)
505 if (bit
== RTLIL::State::S1
)
506 goto port_is_always_active
;
507 if (modwalker
.has_drivers(bits
))
508 considered_ports
.insert(i
);
509 port_is_always_active
:;
512 log("Consolidating write ports of memory %s.%s using sat-based resource sharing:\n", log_id(module
), log_id(memid
));
514 bool cache_clk_enable
= false;
515 bool cache_clk_polarity
= false;
516 RTLIL::SigSpec cache_clk
;
518 for (int i
= 0; i
< int(wr_ports
.size()); i
++)
520 RTLIL::Cell
*cell
= wr_ports
.at(i
);
522 if (cell
->parameters
.at(ID::CLK_ENABLE
).as_bool() != cache_clk_enable
||
523 (cache_clk_enable
&& (sigmap(cell
->getPort(ID::CLK
)) != cache_clk
||
524 cell
->parameters
.at(ID::CLK_POLARITY
).as_bool() != cache_clk_polarity
)))
526 cache_clk_enable
= cell
->parameters
.at(ID::CLK_ENABLE
).as_bool();
527 cache_clk_polarity
= cell
->parameters
.at(ID::CLK_POLARITY
).as_bool();
528 cache_clk
= sigmap(cell
->getPort(ID::CLK
));
530 else if (i
> 0 && considered_ports
.count(i
-1) && considered_ports
.count(i
))
531 considered_port_pairs
.insert(i
);
533 if (cache_clk_enable
)
534 log(" Port %d (%s) on %s %s: %s\n", i
, log_id(cell
),
535 cache_clk_polarity
? "posedge" : "negedge", log_signal(cache_clk
),
536 considered_ports
.count(i
) ? "considered" : "not considered");
538 log(" Port %d (%s) unclocked: %s\n", i
, log_id(cell
),
539 considered_ports
.count(i
) ? "considered" : "not considered");
542 if (considered_port_pairs
.size() < 1) {
543 log(" No two subsequent ports in same clock domain considered -> nothing to consolidate.\n");
547 // create SAT representation of common input cone of all considered EN signals
549 pool
<Wire
*> one_hot_wires
;
550 std::set
<RTLIL::Cell
*> sat_cells
;
551 std::set
<RTLIL::SigBit
> bits_queue
;
552 std::map
<int, int> port_to_sat_variable
;
554 for (int i
= 0; i
< int(wr_ports
.size()); i
++)
555 if (considered_port_pairs
.count(i
) || considered_port_pairs
.count(i
+1))
557 RTLIL::SigSpec sig
= modwalker
.sigmap(wr_ports
[i
]->getPort(ID::EN
));
558 port_to_sat_variable
[i
] = ez
->expression(ez
->OpOr
, satgen
.importSigSpec(sig
));
560 std::vector
<RTLIL::SigBit
> bits
= sig
;
561 bits_queue
.insert(bits
.begin(), bits
.end());
564 while (!bits_queue
.empty())
566 for (auto bit
: bits_queue
)
567 if (bit
.wire
&& bit
.wire
->get_bool_attribute(ID::onehot
))
568 one_hot_wires
.insert(bit
.wire
);
570 pool
<ModWalker::PortBit
> portbits
;
571 modwalker
.get_drivers(portbits
, bits_queue
);
574 for (auto &pbit
: portbits
)
575 if (sat_cells
.count(pbit
.cell
) == 0 && cone_ct
.cell_known(pbit
.cell
->type
)) {
576 pool
<RTLIL::SigBit
> &cell_inputs
= modwalker
.cell_inputs
[pbit
.cell
];
577 bits_queue
.insert(cell_inputs
.begin(), cell_inputs
.end());
578 sat_cells
.insert(pbit
.cell
);
582 for (auto wire
: one_hot_wires
) {
583 log(" Adding one-hot constraint for wire %s.\n", log_id(wire
));
584 vector
<int> ez_wire_bits
= satgen
.importSigSpec(wire
);
585 for (int i
: ez_wire_bits
)
586 for (int j
: ez_wire_bits
)
587 if (i
!= j
) ez
->assume(ez
->NOT(i
), j
);
590 log(" Common input cone for all EN signals: %d cells.\n", int(sat_cells
.size()));
592 for (auto cell
: sat_cells
)
593 satgen
.importCell(cell
);
595 log(" Size of unconstrained SAT problem: %d variables, %d clauses\n", ez
->numCnfVariables(), ez
->numCnfClauses());
597 // merge subsequent ports if possible
599 for (int i
= 0; i
< int(wr_ports
.size()); i
++)
601 if (!considered_port_pairs
.count(i
))
604 if (ez
->solve(port_to_sat_variable
.at(i
-1), port_to_sat_variable
.at(i
))) {
605 log(" According to SAT solver sharing of port %d with port %d is not possible.\n", i
-1, i
);
609 log(" Merging port %d into port %d.\n", i
-1, i
);
610 port_to_sat_variable
.at(i
) = ez
->OR(port_to_sat_variable
.at(i
-1), port_to_sat_variable
.at(i
));
612 RTLIL::SigSpec last_addr
= wr_ports
[i
-1]->getPort(ID::ADDR
);
613 RTLIL::SigSpec last_data
= wr_ports
[i
-1]->getPort(ID::DATA
);
614 std::vector
<RTLIL::SigBit
> last_en
= modwalker
.sigmap(wr_ports
[i
-1]->getPort(ID::EN
));
616 RTLIL::SigSpec this_addr
= wr_ports
[i
]->getPort(ID::ADDR
);
617 RTLIL::SigSpec this_data
= wr_ports
[i
]->getPort(ID::DATA
);
618 std::vector
<RTLIL::SigBit
> this_en
= modwalker
.sigmap(wr_ports
[i
]->getPort(ID::EN
));
620 RTLIL::SigBit this_en_active
= module
->ReduceOr(NEW_ID
, this_en
);
622 if (GetSize(last_addr
) < GetSize(this_addr
))
623 last_addr
.extend_u0(GetSize(this_addr
));
625 this_addr
.extend_u0(GetSize(last_addr
));
627 wr_ports
[i
]->setParam(ID::ABITS
, GetSize(this_addr
));
628 wr_ports
[i
]->setPort(ID::ADDR
, module
->Mux(NEW_ID
, last_addr
, this_addr
, this_en_active
));
629 wr_ports
[i
]->setPort(ID::DATA
, module
->Mux(NEW_ID
, last_data
, this_data
, this_en_active
));
631 std::map
<std::pair
<RTLIL::SigBit
, RTLIL::SigBit
>, int> groups_en
;
632 RTLIL::SigSpec grouped_last_en
, grouped_this_en
, en
;
633 RTLIL::Wire
*grouped_en
= module
->addWire(NEW_ID
, 0);
635 for (int j
= 0; j
< int(this_en
.size()); j
++) {
636 std::pair
<RTLIL::SigBit
, RTLIL::SigBit
> key(last_en
[j
], this_en
[j
]);
637 if (!groups_en
.count(key
)) {
638 grouped_last_en
.append(last_en
[j
]);
639 grouped_this_en
.append(this_en
[j
]);
640 groups_en
[key
] = grouped_en
->width
;
643 en
.append(RTLIL::SigSpec(grouped_en
, groups_en
[key
]));
646 module
->addMux(NEW_ID
, grouped_last_en
, grouped_this_en
, this_en_active
, grouped_en
);
647 wr_ports
[i
]->setPort(ID::EN
, en
);
649 module
->remove(wr_ports
[i
-1]);
650 wr_ports
[i
-1] = NULL
;
653 // Clean up `wr_ports': remove all NULL entries
655 std::vector
<RTLIL::Cell
*> wr_ports_with_nulls
;
656 wr_ports_with_nulls
.swap(wr_ports
);
658 for (auto cell
: wr_ports_with_nulls
)
660 wr_ports
.push_back(cell
);
668 MemoryShareWorker(RTLIL::Design
*design
) : design(design
), modwalker(design
) {}
670 void operator()(RTLIL::Module
* module
)
672 std::map
<std::string
, std::pair
<std::vector
<RTLIL::Cell
*>, std::vector
<RTLIL::Cell
*>>> memindex
;
674 this->module
= module
;
677 conditions_logic_cache
.clear();
679 sigmap_xmux
= sigmap
;
680 for (auto cell
: module
->cells())
682 if (cell
->type
== ID($memrd
))
683 memindex
[cell
->parameters
.at(ID::MEMID
).decode_string()].first
.push_back(cell
);
685 if (cell
->type
== ID($memwr
))
686 memindex
[cell
->parameters
.at(ID::MEMID
).decode_string()].second
.push_back(cell
);
688 if (cell
->type
== ID($mux
))
690 RTLIL::SigSpec sig_a
= sigmap_xmux(cell
->getPort(ID::A
));
691 RTLIL::SigSpec sig_b
= sigmap_xmux(cell
->getPort(ID::B
));
693 if (sig_a
.is_fully_undef())
694 sigmap_xmux
.add(cell
->getPort(ID::Y
), sig_b
);
695 else if (sig_b
.is_fully_undef())
696 sigmap_xmux
.add(cell
->getPort(ID::Y
), sig_a
);
699 if (cell
->type
.in(ID($mux
), ID($pmux
)))
701 std::vector
<RTLIL::SigBit
> sig_y
= sigmap(cell
->getPort(ID::Y
));
702 for (int i
= 0; i
< int(sig_y
.size()); i
++)
703 sig_to_mux
[sig_y
[i
]] = std::pair
<RTLIL::Cell
*, int>(cell
, i
);
707 for (auto &it
: memindex
) {
708 std::sort(it
.second
.first
.begin(), it
.second
.first
.end(), memcells_cmp
);
709 std::sort(it
.second
.second
.begin(), it
.second
.second
.end(), memcells_cmp
);
710 translate_rd_feedback_to_en(it
.first
, it
.second
.first
, it
.second
.second
);
711 consolidate_wr_by_addr(it
.first
, it
.second
.second
);
714 cone_ct
.setup_internals();
715 cone_ct
.cell_types
.erase(ID($mul
));
716 cone_ct
.cell_types
.erase(ID($mod
));
717 cone_ct
.cell_types
.erase(ID($div
));
718 cone_ct
.cell_types
.erase(ID($pow
));
719 cone_ct
.cell_types
.erase(ID($shl
));
720 cone_ct
.cell_types
.erase(ID($shr
));
721 cone_ct
.cell_types
.erase(ID($sshl
));
722 cone_ct
.cell_types
.erase(ID($sshr
));
723 cone_ct
.cell_types
.erase(ID($shift
));
724 cone_ct
.cell_types
.erase(ID($shiftx
));
726 modwalker
.setup(module
, &cone_ct
);
728 for (auto &it
: memindex
)
729 consolidate_wr_using_sat(it
.first
, it
.second
.second
);
733 struct MemorySharePass
: public Pass
{
734 MemorySharePass() : Pass("memory_share", "consolidate memory ports") { }
735 void help() YS_OVERRIDE
737 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
739 log(" memory_share [selection]\n");
741 log("This pass merges share-able memory ports into single memory ports.\n");
743 log("The following methods are used to consolidate the number of memory ports:\n");
745 log(" - When write ports are connected to async read ports accessing the same\n");
746 log(" address, then this feedback path is converted to a write port with\n");
747 log(" byte/part enable signals.\n");
749 log(" - When multiple write ports access the same address then this is converted\n");
750 log(" to a single write port with a more complex data and/or enable logic path.\n");
752 log(" - When multiple write ports are never accessed at the same time (a SAT\n");
753 log(" solver is used to determine this), then the ports are merged into a single\n");
754 log(" write port.\n");
756 log("Note that in addition to the algorithms implemented in this pass, the $memrd\n");
757 log("and $memwr cells are also subject to generic resource sharing passes (and other\n");
758 log("optimizations) such as \"share\" and \"opt_merge\".\n");
761 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
{
762 log_header(design
, "Executing MEMORY_SHARE pass (consolidating $memrd/$memwr cells).\n");
763 extra_args(args
, 1, design
);
764 MemoryShareWorker
msw(design
);
766 for (auto module
: design
->selected_modules())
771 PRIVATE_NAMESPACE_END