7f3bbc7ad56c65f598669119cdfba86d0c871323
2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 * 2019 Eddie Hung <eddie@fpgeh.com>
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 #include "kernel/register.h"
22 #include "kernel/sigtools.h"
23 #include "kernel/utils.h"
24 #include "kernel/celltypes.h"
26 #define ABC9_DELAY_BASE_ID 9000
29 PRIVATE_NAMESPACE_BEGIN
33 inline std::string
remap_name(RTLIL::IdString abc9_name
)
35 return stringf("$abc$%d$%s", map_autoidx
, abc9_name
.c_str()+1);
38 void check(RTLIL::Design
*design
)
40 dict
<IdString
,IdString
> box_lookup
;
41 for (auto m
: design
->modules()) {
42 auto flop
= m
->get_bool_attribute(ID(abc9_flop
));
43 auto it
= m
->attributes
.find(ID(abc9_box_id
));
44 if (it
== m
->attributes
.end()) {
46 log_error("Module '%s' contains (* abc9_flop *) but not (* abc9_box_id=<int> *).\n", log_id(m
));
49 if (m
->name
.begins_with("$paramod"))
51 auto id
= it
->second
.as_int();
52 auto r
= box_lookup
.insert(std::make_pair(stringf("$__boxid%d", id
), m
->name
));
54 log_error("Module '%s' has the same abc9_box_id = %d value as '%s'.\n",
55 log_id(m
), id
, log_id(r
.first
->second
));
57 // Make carry in the last PI, and carry out the last PO
58 // since ABC requires it this way
59 IdString carry_in
, carry_out
;
60 for (const auto &port_name
: m
->ports
) {
61 auto w
= m
->wire(port_name
);
63 if (w
->get_bool_attribute("\\abc9_carry")) {
65 if (carry_in
!= IdString())
66 log_error("Module '%s' contains more than one (* abc9_carry *) input port.\n", log_id(m
));
70 if (carry_out
!= IdString())
71 log_error("Module '%s' contains more than one (* abc9_carry *) output port.\n", log_id(m
));
72 carry_out
= port_name
;
77 if (carry_in
!= IdString() && carry_out
== IdString())
78 log_error("Module '%s' contains an (* abc9_carry *) input port but no output port.\n", log_id(m
));
79 if (carry_in
== IdString() && carry_out
!= IdString())
80 log_error("Module '%s' contains an (* abc9_carry *) output port but no input port.\n", log_id(m
));
84 for (auto port_name
: m
->ports
) {
85 auto wire
= m
->wire(port_name
);
86 if (wire
->port_output
) num_outputs
++;
89 log_error("Module '%s' with (* abc_flop *) has %d outputs (expect 1).\n", log_id(m
), num_outputs
);
94 void break_scc(RTLIL::Module
*module
)
96 // For every unique SCC found, (arbitrarily) find the first
97 // cell in the component, and convert all wires driven by
98 // its output ports into a new PO, and drive its previous
99 // sinks with a new PI
100 pool
<RTLIL::Const
> ids_seen
;
101 for (auto cell
: module
->cells()) {
102 auto it
= cell
->attributes
.find(ID(abc9_scc_id
));
103 if (it
== cell
->attributes
.end())
105 auto r
= ids_seen
.insert(it
->second
);
106 cell
->attributes
.erase(it
);
109 for (auto &c
: cell
->connections_
) {
110 if (c
.second
.is_fully_const()) continue;
111 if (cell
->output(c
.first
)) {
112 SigBit b
= c
.second
.as_bit();
115 // In this case, hopefully the loop break has been already created
116 // Get the non-prefixed wire
117 Wire
*wo
= module
->wire(stringf("%s.abco", b
.wire
->name
.c_str()));
118 log_assert(wo
!= nullptr);
119 log_assert(wo
->port_output
);
120 log_assert(b
.offset
< GetSize(wo
));
121 c
.second
= RTLIL::SigBit(wo
, b
.offset
);
124 // Create a new output/input loop break
125 w
->port_input
= true;
126 w
= module
->wire(stringf("%s.abco", w
->name
.c_str()));
128 w
= module
->addWire(stringf("%s.abco", b
.wire
->name
.c_str()), GetSize(b
.wire
));
129 w
->port_output
= true;
132 log_assert(w
->port_input
);
133 log_assert(b
.offset
< GetSize(w
));
135 w
->set_bool_attribute(ID(abc9_scc_break
));
136 c
.second
= RTLIL::SigBit(w
, b
.offset
);
142 module
->fixup_ports();
145 void unbreak_scc(RTLIL::Module
*module
)
147 // Now 'unexpose' those wires by undoing
148 // the expose operation -- remove them from PO/PI
149 // and re-connecting them back together
150 for (auto wire
: module
->wires()) {
151 auto it
= wire
->attributes
.find(ID(abc9_scc_break
));
152 if (it
!= wire
->attributes
.end()) {
153 wire
->attributes
.erase(it
);
154 log_assert(wire
->port_output
);
155 wire
->port_output
= false;
156 std::string name
= wire
->name
.str();
157 RTLIL::Wire
*i_wire
= module
->wire(name
.substr(0, GetSize(name
) - 5));
159 log_assert(i_wire
->port_input
);
160 i_wire
->port_input
= false;
161 module
->connect(i_wire
, wire
);
164 module
->fixup_ports();
167 void prep_dff(RTLIL::Module
*module
)
169 auto design
= module
->design
;
172 SigMap
assign_map(module
);
174 typedef SigSpec clkdomain_t
;
175 dict
<clkdomain_t
, int> clk_to_mergeability
;
177 for (auto cell
: module
->cells()) {
178 if (cell
->type
!= "$__ABC9_FF_")
181 Wire
*abc9_clock_wire
= module
->wire(stringf("%s.clock", cell
->name
.c_str()));
182 if (abc9_clock_wire
== NULL
)
183 log_error("'%s.clock' is not a wire present in module '%s'.\n", cell
->name
.c_str(), log_id(module
));
184 SigSpec abc9_clock
= assign_map(abc9_clock_wire
);
186 clkdomain_t
key(abc9_clock
);
188 auto r
= clk_to_mergeability
.insert(std::make_pair(abc9_clock
, clk_to_mergeability
.size() + 1));
189 auto r2
YS_ATTRIBUTE(unused
) = cell
->attributes
.insert(std::make_pair(ID(abc9_mergeability
), r
.first
->second
));
190 log_assert(r2
.second
);
192 Wire
*abc9_init_wire
= module
->wire(stringf("%s.init", cell
->name
.c_str()));
193 if (abc9_init_wire
== NULL
)
194 log_error("'%s.init' is not a wire present in module '%s'.\n", cell
->name
.c_str(), log_id(module
));
195 log_assert(GetSize(abc9_init_wire
) == 1);
196 SigSpec abc9_init
= assign_map(abc9_init_wire
);
197 if (!abc9_init
.is_fully_const())
198 log_error("'%s.init' is not a constant wire present in module '%s'.\n", cell
->name
.c_str(), log_id(module
));
199 r2
= cell
->attributes
.insert(std::make_pair(ID(abc9_init
), abc9_init
.as_const()));
200 log_assert(r2
.second
);
203 RTLIL::Module
*holes_module
= design
->module(stringf("%s$holes", module
->name
.c_str()));
205 SigMap
sigmap(holes_module
);
207 dict
<SigSpec
, SigSpec
> replace
;
208 for (auto it
= holes_module
->cells_
.begin(); it
!= holes_module
->cells_
.end(); ) {
209 auto cell
= it
->second
;
210 if (cell
->type
.in("$_DFF_N_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_",
211 "$_DFF_P_", "$_DFF_PN0_", "$_DFF_PN1", "$_DFF_PP0_", "$_DFF_PP1_")) {
212 SigBit D
= cell
->getPort("\\D");
213 SigBit Q
= cell
->getPort("\\Q");
214 // Remove the $_DFF_* cell from what needs to be a combinatorial box
215 it
= holes_module
->cells_
.erase(it
);
217 if (GetSize(Q
.wire
) == 1)
218 port
= holes_module
->wire(stringf("$abc%s", Q
.wire
->name
.c_str()));
220 port
= holes_module
->wire(stringf("$abc%s[%d]", Q
.wire
->name
.c_str(), Q
.offset
));
222 // Prepare to replace "assign <port> = $_DFF_*.Q;" with "assign <port> = $_DFF_*.D;"
223 // in order to extract just the combinatorial control logic that feeds the box
224 // (i.e. clock enable, synchronous reset, etc.)
225 replace
.insert(std::make_pair(Q
,D
));
226 // Since `flatten` above would have created wires named "<cell>.Q",
227 // extract the pre-techmap cell name
228 auto pos
= Q
.wire
->name
.str().rfind(".");
229 log_assert(pos
!= std::string::npos
);
230 IdString driver
= Q
.wire
->name
.substr(0, pos
);
231 // And drive the signal that was previously driven by "DFF.Q" (typically
232 // used to implement clock-enable functionality) with the "<cell>.$abc9_currQ"
233 // wire (which itself is driven an by input port) we inserted above
234 Wire
*currQ
= holes_module
->wire(stringf("%s.abc9_ff.Q", driver
.c_str()));
236 holes_module
->connect(Q
, currQ
);
242 for (auto &conn
: holes_module
->connections_
)
243 conn
.second
= replace
.at(sigmap(conn
.second
), conn
.second
);
247 void prep_holes(RTLIL::Module
*module
, bool dff
)
249 auto design
= module
->design
;
252 SigMap
sigmap(module
);
254 dict
<SigBit
, pool
<IdString
>> bit_drivers
, bit_users
;
255 TopoSort
<IdString
, RTLIL::sort_by_id_str
> toposort
;
256 bool abc9_box_seen
= false;
258 for (auto cell
: module
->cells()) {
259 if (cell
->type
== "$__ABC9_FF_")
262 auto inst_module
= module
->design
->module(cell
->type
);
263 bool abc9_box
= inst_module
&& inst_module
->attributes
.count("\\abc9_box_id");
264 bool abc9_flop
= false;
266 abc9_flop
= inst_module
->get_bool_attribute("\\abc9_flop");
267 if (abc9_flop
&& !dff
)
269 abc9_box_seen
= abc9_box
;
271 else if (!yosys_celltypes
.cell_known(cell
->type
))
274 for (auto conn
: cell
->connections()) {
275 if (cell
->input(conn
.first
))
276 for (auto bit
: sigmap(conn
.second
))
277 bit_users
[bit
].insert(cell
->name
);
279 if (cell
->output(conn
.first
) && !abc9_flop
)
280 for (auto bit
: sigmap(conn
.second
))
281 bit_drivers
[bit
].insert(cell
->name
);
284 toposort
.node(cell
->name
);
290 for (auto &it
: bit_users
)
291 if (bit_drivers
.count(it
.first
))
292 for (auto driver_cell
: bit_drivers
.at(it
.first
))
293 for (auto user_cell
: it
.second
)
294 toposort
.edge(driver_cell
, user_cell
);
297 toposort
.analyze_loops
= true;
299 bool no_loops
YS_ATTRIBUTE(unused
) = toposort
.sort();
303 for (auto &it
: toposort
.loops
) {
304 log(" loop %d\n", i
++);
305 for (auto cell_name
: it
) {
306 auto cell
= module
->cell(cell_name
);
308 log("\t%s (%s @ %s)\n", log_id(cell
), log_id(cell
->type
), cell
->get_src_attribute().c_str());
313 log_assert(no_loops
);
315 vector
<Cell
*> box_list
;
316 for (auto cell_name
: toposort
.sorted
) {
317 RTLIL::Cell
*cell
= module
->cell(cell_name
);
320 RTLIL::Module
* box_module
= design
->module(cell
->type
);
321 if (!box_module
|| !box_module
->attributes
.count("\\abc9_box_id"))
324 bool blackbox
= box_module
->get_blackbox_attribute(true /* ignore_wb */);
326 // Fully pad all unused input connections of this box cell with S0
327 // Fully pad all undriven output connections of this box cell with anonymous wires
328 for (const auto &port_name
: box_module
->ports
) {
329 RTLIL::Wire
* w
= box_module
->wire(port_name
);
331 auto it
= cell
->connections_
.find(port_name
);
334 if (it
!= cell
->connections_
.end()) {
335 if (GetSize(it
->second
) < GetSize(w
))
336 it
->second
.append(RTLIL::SigSpec(State::S0
, GetSize(w
)-GetSize(it
->second
)));
340 rhs
= RTLIL::SigSpec(State::S0
, GetSize(w
));
341 cell
->setPort(port_name
, rhs
);
344 if (w
->port_output
) {
346 auto it
= cell
->connections_
.find(w
->name
);
347 if (it
!= cell
->connections_
.end()) {
348 if (GetSize(it
->second
) < GetSize(w
))
349 it
->second
.append(module
->addWire(NEW_ID
, GetSize(w
)-GetSize(it
->second
)));
353 Wire
*wire
= module
->addWire(NEW_ID
, GetSize(w
));
355 wire
->set_bool_attribute(ID(abc9_padding
));
357 cell
->setPort(port_name
, rhs
);
362 cell
->attributes
["\\abc9_box_seq"] = box_list
.size();
363 //log_debug("%s.%s is box %d\n", log_id(module), log_id(cell), box_list.size());
364 box_list
.emplace_back(cell
);
366 log_assert(!box_list
.empty());
368 RTLIL::Module
*holes_module
= design
->addModule(stringf("%s$holes", module
->name
.c_str()));
369 log_assert(holes_module
);
370 holes_module
->set_bool_attribute("\\abc9_holes");
372 dict
<IdString
, Cell
*> cell_cache
;
373 dict
<IdString
, std::vector
<IdString
>> box_ports
;
376 for (auto cell
: box_list
) {
377 RTLIL::Module
* orig_box_module
= design
->module(cell
->type
);
378 log_assert(orig_box_module
);
379 IdString derived_name
= orig_box_module
->derive(design
, cell
->parameters
);
380 RTLIL::Module
* box_module
= design
->module(derived_name
);
381 //cell->type = derived_name;
382 //cell->parameters.clear();
384 auto r
= cell_cache
.insert(derived_name
);
385 auto &holes_cell
= r
.first
->second
;
387 auto r2
= box_ports
.insert(cell
->type
);
389 // Make carry in the last PI, and carry out the last PO
390 // since ABC requires it this way
391 IdString carry_in
, carry_out
;
392 for (const auto &port_name
: box_module
->ports
) {
393 auto w
= box_module
->wire(port_name
);
395 if (w
->get_bool_attribute("\\abc9_carry")) {
397 carry_in
= port_name
;
399 carry_out
= port_name
;
402 r2
.first
->second
.push_back(port_name
);
405 if (carry_in
!= IdString()) {
406 r2
.first
->second
.push_back(carry_in
);
407 r2
.first
->second
.push_back(carry_out
);
411 if (box_module
->get_bool_attribute("\\whitebox")) {
412 holes_cell
= holes_module
->addCell(cell
->name
, derived_name
);
414 if (box_module
->has_processes())
415 Pass::call_on_module(design
, box_module
, "proc");
418 for (auto port_name
: box_ports
.at(cell
->type
)) {
419 RTLIL::Wire
*w
= box_module
->wire(port_name
);
421 log_assert(!w
->port_input
|| !w
->port_output
);
422 auto &conn
= holes_cell
->connections_
[port_name
];
424 for (int i
= 0; i
< GetSize(w
); i
++) {
426 RTLIL::Wire
*holes_wire
= holes_module
->wire(stringf("\\i%d", box_inputs
));
428 holes_wire
= holes_module
->addWire(stringf("\\i%d", box_inputs
));
429 holes_wire
->port_input
= true;
430 holes_wire
->port_id
= port_id
++;
431 holes_module
->ports
.push_back(holes_wire
->name
);
433 conn
.append(holes_wire
);
436 else if (w
->port_output
)
437 conn
= holes_module
->addWire(stringf("%s.%s", derived_name
.c_str(), log_id(port_name
)), GetSize(w
));
440 // For flops only, create an extra 1-bit input that drives a new wire
441 // called "<cell>.abc9_ff.Q" that is used below
442 if (box_module
->get_bool_attribute("\\abc9_flop")) {
444 Wire
*holes_wire
= holes_module
->wire(stringf("\\i%d", box_inputs
));
446 holes_wire
= holes_module
->addWire(stringf("\\i%d", box_inputs
));
447 holes_wire
->port_input
= true;
448 holes_wire
->port_id
= port_id
++;
449 holes_module
->ports
.push_back(holes_wire
->name
);
451 Wire
*Q
= holes_module
->addWire(stringf("%s.abc9_ff.Q", cell
->name
.c_str()));
452 holes_module
->connect(Q
, holes_wire
);
455 else // box_module is a blackbox
456 log_assert(holes_cell
== nullptr);
459 for (auto port_name
: box_ports
.at(cell
->type
)) {
460 RTLIL::Wire
*w
= box_module
->wire(port_name
);
464 Wire
*holes_wire
= holes_module
->addWire(stringf("$abc%s.%s", cell
->name
.c_str(), log_id(port_name
)), GetSize(w
));
465 holes_wire
->port_output
= true;
466 holes_wire
->port_id
= port_id
++;
467 holes_module
->ports
.push_back(holes_wire
->name
);
468 if (holes_cell
) // whitebox
469 holes_module
->connect(holes_wire
, holes_cell
->getPort(port_name
));
471 holes_module
->connect(holes_wire
, Const(State::S0
, GetSize(w
)));
476 void prep_times(RTLIL::Design
*design
)
478 std::set
<int> delays
;
480 std::vector
<Cell
*> boxes
;
481 std::map
<int,std::vector
<int>> requireds
;
482 for (auto module
: design
->selected_modules()) {
483 if (module
->processes
.size() > 0) {
484 log("Skipping module %s as it contains processes.\n", log_id(module
));
489 for (auto cell
: module
->cells()) {
490 if (cell
->type
.in(ID($_AND_
), ID($_NOT_
), ID($__ABC9_FF_
), ID($__ABC9_DELAY
)))
493 RTLIL::Module
* inst_module
= module
->design
->module(cell
->type
);
496 if (!inst_module
->get_blackbox_attribute())
498 if (inst_module
->get_bool_attribute(ID(abc9_flop
))) {
499 flops
.insert(inst_module
);
502 // All remaining boxes are combinatorial and cannot
503 // contain a required time
504 if (inst_module
->attributes
.count(ID(abc9_box_id
)))
506 boxes
.emplace_back(cell
);
511 for (auto cell
: boxes
) {
512 RTLIL::Module
* inst_module
= module
->design
->module(cell
->type
);
513 log_assert(inst_module
);
514 for (auto &conn
: cell
->connections_
) {
515 auto port_wire
= inst_module
->wire(conn
.first
);
516 if (!port_wire
->port_input
)
519 auto it
= port_wire
->attributes
.find("\\abc9_required");
520 if (it
== port_wire
->attributes
.end())
525 if (it
->second
.flags
== 0) {
527 requireds
[it
->second
.as_int()].push_back(0);
530 for (const auto &tok
: split_tokens(it
->second
.decode_string()))
531 requireds
[atoi(tok
.c_str())].push_back(count
++);
532 if (count
> 1 && count
!= GetSize(port_wire
))
533 log_error("%s.%s is %d bits wide but abc9_required = %s has %d value(s)!\n", log_id(cell
->type
), log_id(conn
.first
),
534 GetSize(port_wire
), log_signal(it
->second
), count
);
536 SigSpec O
= module
->addWire(NEW_ID
, GetSize(conn
.second
));
537 for (const auto &i
: requireds
) {
540 static std::set
<std::pair
<IdString
,IdString
>> seen
;
541 if (seen
.emplace(cell
->type
, conn
.first
).second
) log("%s.%s abc9_required = %d\n", log_id(cell
->type
), log_id(conn
.first
), i
.first
);
544 delays
.insert(i
.first
);
545 for (auto offset
: i
.second
) {
546 auto box
= module
->addCell(NEW_ID
, ID($__ABC9_DELAY
));
547 box
->setPort(ID(I
), conn
.second
[offset
]);
548 box
->setPort(ID(O
), O
[offset
]);
549 box
->setParam(ID(DELAY
), i
.first
);
550 conn
.second
[offset
] = O
[offset
];
556 std::stringstream ss
;
558 for (auto d
: delays
) {
565 module
->attributes
[ID(abc9_delays
)] = ss
.str();
568 std::stringstream ss
;
569 for (auto flop_module
: flops
) {
570 // Skip parameterised flop_modules for now (since we do not
571 // dynamically generate the abc9_box_id)
572 if (flop_module
->name
.begins_with("$paramod"))
575 int num_inputs
= 0, num_outputs
= 0;
576 for (auto port_name
: flop_module
->ports
) {
577 auto wire
= flop_module
->wire(port_name
);
578 if (wire
->port_input
) num_inputs
++;
579 if (wire
->port_output
) num_outputs
++;
581 log_assert(num_outputs
== 1);
583 ss
<< log_id(flop_module
) << " " << flop_module
->attributes
.at(ID(abc9_box_id
)).as_int();
584 ss
<< " 1 " << num_inputs
+1 << " " << num_outputs
<< std::endl
;
586 for (auto port_name
: flop_module
->ports
) {
587 auto wire
= flop_module
->wire(port_name
);
588 if (!wire
->port_input
)
594 ss
<< wire
->attributes
.at("\\abc9_required", 0).as_int();
596 // Last input is 'abc9_ff.Q'
597 ss
<< " 0" << std::endl
<< std::endl
;
599 design
->scratchpad_set_string("abc9_ops.box.flops", ss
.str());
602 void write_box(RTLIL::Module
*module
, const std::string
&src
, const std::string
&dst
) {
603 std::ofstream
ofs(dst
);
604 log_assert(ofs
.is_open());
606 // Since ABC can only accept one box file, we have to copy
607 // over the existing box file
608 if (src
!= "(null)") {
609 std::ifstream
ifs(src
);
610 ofs
<< ifs
.rdbuf() << std::endl
;
614 ofs
<< module
->design
->scratchpad_get_string("abc9_ops.box.flops");
616 auto it
= module
->attributes
.find(ID(abc9_delays
));
617 if (it
!= module
->attributes
.end()) {
618 for (const auto &tok
: split_tokens(it
->second
.decode_string())) {
619 int d
= atoi(tok
.c_str());
620 ofs
<< "$__ABC9_DELAY@" << d
<< " " << ABC9_DELAY_BASE_ID
+ d
<< " 0 1 1" << std::endl
;
621 ofs
<< d
<< std::endl
;
623 module
->attributes
.erase(it
);
629 void reintegrate(RTLIL::Module
*module
)
631 auto design
= module
->design
;
634 map_autoidx
= autoidx
++;
636 RTLIL::Module
*mapped_mod
= design
->module(stringf("%s$abc9", module
->name
.c_str()));
637 if (mapped_mod
== NULL
)
638 log_error("ABC output file does not contain a module `%s$abc'.\n", log_id(module
));
640 for (auto w
: mapped_mod
->wires())
641 module
->addWire(remap_name(w
->name
), GetSize(w
));
643 dict
<IdString
,IdString
> box_lookup
;
644 for (auto m
: design
->modules()) {
645 auto it
= m
->attributes
.find(ID(abc9_box_id
));
646 if (it
== m
->attributes
.end())
648 if (m
->name
.begins_with("$paramod"))
650 auto id
= it
->second
.as_int();
651 auto r
YS_ATTRIBUTE(unused
) = box_lookup
.insert(std::make_pair(stringf("$__boxid%d", id
), m
->name
));
652 log_assert(r
.second
);
655 pool
<IdString
> delay_boxes
;
656 std::vector
<Cell
*> boxes
;
657 for (auto cell
: module
->cells().to_vector()) {
658 if (cell
->type
.in(ID($_AND_
), ID($_NOT_
), ID($__ABC9_FF_
)))
659 module
->remove(cell
);
660 else if (cell
->type
.begins_with("$paramod$__ABC9_DELAY\\DELAY=")) {
661 delay_boxes
.insert(cell
->name
);
662 module
->remove(cell
);
664 else if (cell
->attributes
.erase("\\abc9_box_seq"))
665 boxes
.emplace_back(cell
);
668 dict
<SigBit
, pool
<IdString
>> bit_drivers
, bit_users
;
669 TopoSort
<IdString
, RTLIL::sort_by_id_str
> toposort
;
670 dict
<RTLIL::Cell
*,RTLIL::Cell
*> not2drivers
;
671 dict
<SigBit
, std::vector
<RTLIL::Cell
*>> bit2sinks
;
673 dict
<IdString
,std::vector
<IdString
>> box_ports
;
674 std::map
<IdString
, int> cell_stats
;
675 for (auto mapped_cell
: mapped_mod
->cells())
677 toposort
.node(mapped_cell
->name
);
679 if (mapped_cell
->type
== ID($_NOT_
)) {
680 RTLIL::SigBit a_bit
= mapped_cell
->getPort(ID::A
);
681 RTLIL::SigBit y_bit
= mapped_cell
->getPort(ID::Y
);
682 bit_users
[a_bit
].insert(mapped_cell
->name
);
683 bit_drivers
[y_bit
].insert(mapped_cell
->name
);
686 mapped_cell
->setPort(ID::Y
, module
->addWire(NEW_ID
));
687 RTLIL::Wire
*wire
= module
->wire(remap_name(y_bit
.wire
->name
));
689 module
->connect(RTLIL::SigBit(wire
, y_bit
.offset
), State::S1
);
692 RTLIL::Cell
* driver_lut
= nullptr;
693 // ABC can return NOT gates that drive POs
694 if (!a_bit
.wire
->port_input
) {
695 // If it's not a NOT gate that that comes from a PI directly,
696 // find the driver LUT and clone that to guarantee that we won't
697 // increase the max logic depth
698 // (TODO: Optimise by not cloning unless will increase depth)
699 RTLIL::IdString driver_name
;
700 if (GetSize(a_bit
.wire
) == 1)
701 driver_name
= stringf("%s$lut", a_bit
.wire
->name
.c_str());
703 driver_name
= stringf("%s[%d]$lut", a_bit
.wire
->name
.c_str(), a_bit
.offset
);
704 driver_lut
= mapped_mod
->cell(driver_name
);
708 // If a driver couldn't be found (could be from PI or box CI)
709 // then implement using a LUT
710 RTLIL::Cell
*cell
= module
->addLut(remap_name(stringf("%s$lut", mapped_cell
->name
.c_str())),
711 RTLIL::SigBit(module
->wires_
.at(remap_name(a_bit
.wire
->name
)), a_bit
.offset
),
712 RTLIL::SigBit(module
->wires_
.at(remap_name(y_bit
.wire
->name
)), y_bit
.offset
),
713 RTLIL::Const::from_string("01"));
714 bit2sinks
[cell
->getPort(ID::A
)].push_back(cell
);
715 cell_stats
[ID($lut
)]++;
718 not2drivers
[mapped_cell
] = driver_lut
;
723 if (mapped_cell
->type
.in(ID($lut
), ID($__ABC9_FF_
))) {
724 RTLIL::Cell
*cell
= module
->addCell(remap_name(mapped_cell
->name
), mapped_cell
->type
);
725 cell
->parameters
= mapped_cell
->parameters
;
726 cell
->attributes
= mapped_cell
->attributes
;
728 for (auto &mapped_conn
: mapped_cell
->connections()) {
729 RTLIL::SigSpec newsig
;
730 for (auto c
: mapped_conn
.second
.chunks()) {
733 //log_assert(c.width == 1);
735 c
.wire
= module
->wires_
.at(remap_name(c
.wire
->name
));
738 cell
->setPort(mapped_conn
.first
, newsig
);
740 if (cell
->input(mapped_conn
.first
)) {
741 for (auto i
: newsig
)
742 bit2sinks
[i
].push_back(cell
);
743 for (auto i
: mapped_conn
.second
)
744 bit_users
[i
].insert(mapped_cell
->name
);
746 if (cell
->output(mapped_conn
.first
))
747 for (auto i
: mapped_conn
.second
)
748 bit_drivers
[i
].insert(mapped_cell
->name
);
751 else if (delay_boxes
.count(mapped_cell
->name
)) {
752 SigBit I
= mapped_cell
->getPort(ID(i
));
753 SigBit O
= mapped_cell
->getPort(ID(o
));
755 I
.wire
= module
->wires_
.at(remap_name(I
.wire
->name
));
757 O
.wire
= module
->wires_
.at(remap_name(O
.wire
->name
));
758 module
->connect(O
, I
);
762 RTLIL::Cell
*existing_cell
= module
->cell(mapped_cell
->name
);
763 log_assert(existing_cell
);
764 log_assert(mapped_cell
->type
.begins_with("$__boxid"));
766 auto type
= box_lookup
.at(mapped_cell
->type
, IdString());
767 if (type
== IdString())
768 log_error("No module with abc9_box_id = %s found.\n", mapped_cell
->type
.c_str() + strlen("$__boxid"));
769 mapped_cell
->type
= type
;
771 RTLIL::Cell
*cell
= module
->addCell(remap_name(mapped_cell
->name
), mapped_cell
->type
);
772 cell
->parameters
= existing_cell
->parameters
;
773 cell
->attributes
= existing_cell
->attributes
;
774 module
->swap_names(cell
, existing_cell
);
776 auto it
= mapped_cell
->connections_
.find("\\i");
777 log_assert(it
!= mapped_cell
->connections_
.end());
778 SigSpec inputs
= std::move(it
->second
);
779 mapped_cell
->connections_
.erase(it
);
780 it
= mapped_cell
->connections_
.find("\\o");
781 log_assert(it
!= mapped_cell
->connections_
.end());
782 SigSpec outputs
= std::move(it
->second
);
783 mapped_cell
->connections_
.erase(it
);
785 RTLIL::Module
* box_module
= design
->module(mapped_cell
->type
);
786 auto abc9_flop
= box_module
->attributes
.count("\\abc9_flop");
788 for (const auto &i
: inputs
)
789 bit_users
[i
].insert(mapped_cell
->name
);
790 for (const auto &i
: outputs
)
791 bit_drivers
[i
].insert(mapped_cell
->name
);
794 auto r2
= box_ports
.insert(cell
->type
);
796 // Make carry in the last PI, and carry out the last PO
797 // since ABC requires it this way
798 IdString carry_in
, carry_out
;
799 for (const auto &port_name
: box_module
->ports
) {
800 auto w
= box_module
->wire(port_name
);
802 if (w
->get_bool_attribute("\\abc9_carry")) {
804 carry_in
= port_name
;
806 carry_out
= port_name
;
809 r2
.first
->second
.push_back(port_name
);
812 if (carry_in
!= IdString()) {
813 r2
.first
->second
.push_back(carry_in
);
814 r2
.first
->second
.push_back(carry_out
);
818 int input_count
= 0, output_count
= 0;
819 for (const auto &port_name
: box_ports
.at(cell
->type
)) {
820 RTLIL::Wire
*w
= box_module
->wire(port_name
);
825 sig
= inputs
.extract(input_count
, GetSize(w
));
826 input_count
+= GetSize(w
);
828 if (w
->port_output
) {
829 sig
= outputs
.extract(output_count
, GetSize(w
));
830 output_count
+= GetSize(w
);
834 for (auto c
: sig
.chunks()) {
837 //log_assert(c.width == 1);
839 c
.wire
= module
->wires_
.at(remap_name(c
.wire
->name
));
843 auto it
= existing_cell
->connections_
.find(port_name
);
844 if (it
== existing_cell
->connections_
.end())
846 if (GetSize(newsig
) > GetSize(it
->second
))
847 newsig
= newsig
.extract(0, GetSize(it
->second
));
849 log_assert(GetSize(newsig
) == GetSize(it
->second
));
851 cell
->setPort(port_name
, newsig
);
853 if (w
->port_input
&& !abc9_flop
)
854 for (const auto &i
: newsig
)
855 bit2sinks
[i
].push_back(cell
);
859 cell_stats
[mapped_cell
->type
]++;
862 for (auto cell
: boxes
)
863 module
->remove(cell
);
865 // Copy connections (and rename) from mapped_mod to module
866 for (auto conn
: mapped_mod
->connections()) {
867 if (!conn
.first
.is_fully_const()) {
868 auto chunks
= conn
.first
.chunks();
869 for (auto &c
: chunks
)
870 c
.wire
= module
->wires_
.at(remap_name(c
.wire
->name
));
871 conn
.first
= std::move(chunks
);
873 if (!conn
.second
.is_fully_const()) {
874 auto chunks
= conn
.second
.chunks();
875 for (auto &c
: chunks
)
877 c
.wire
= module
->wires_
.at(remap_name(c
.wire
->name
));
878 conn
.second
= std::move(chunks
);
880 module
->connect(conn
);
883 for (auto &it
: cell_stats
)
884 log("ABC RESULTS: %15s cells: %8d\n", it
.first
.c_str(), it
.second
);
885 int in_wires
= 0, out_wires
= 0;
887 // Stitch in mapped_mod's inputs/outputs into module
888 for (auto port
: mapped_mod
->ports
) {
889 RTLIL::Wire
*w
= mapped_mod
->wire(port
);
890 RTLIL::Wire
*wire
= module
->wire(port
);
892 RTLIL::Wire
*remap_wire
= module
->wire(remap_name(port
));
893 RTLIL::SigSpec
signal(wire
, 0, GetSize(remap_wire
));
894 log_assert(GetSize(signal
) >= GetSize(remap_wire
));
897 if (w
->port_output
) {
899 conn
.second
= remap_wire
;
901 module
->connect(conn
);
903 else if (w
->port_input
) {
904 conn
.first
= remap_wire
;
905 conn
.second
= signal
;
907 module
->connect(conn
);
911 for (auto &it
: bit_users
)
912 if (bit_drivers
.count(it
.first
))
913 for (auto driver_cell
: bit_drivers
.at(it
.first
))
914 for (auto user_cell
: it
.second
)
915 toposort
.edge(driver_cell
, user_cell
);
916 bool no_loops
YS_ATTRIBUTE(unused
) = toposort
.sort();
917 log_assert(no_loops
);
919 for (auto ii
= toposort
.sorted
.rbegin(); ii
!= toposort
.sorted
.rend(); ii
++) {
920 RTLIL::Cell
*not_cell
= mapped_mod
->cell(*ii
);
921 log_assert(not_cell
);
922 if (not_cell
->type
!= ID($_NOT_
))
924 auto it
= not2drivers
.find(not_cell
);
925 if (it
== not2drivers
.end())
927 RTLIL::Cell
*driver_lut
= it
->second
;
928 RTLIL::SigBit a_bit
= not_cell
->getPort(ID::A
);
929 RTLIL::SigBit y_bit
= not_cell
->getPort(ID::Y
);
930 RTLIL::Const driver_mask
;
932 a_bit
.wire
= module
->wires_
.at(remap_name(a_bit
.wire
->name
));
933 y_bit
.wire
= module
->wires_
.at(remap_name(y_bit
.wire
->name
));
935 auto jt
= bit2sinks
.find(a_bit
);
936 if (jt
== bit2sinks
.end())
939 for (auto sink_cell
: jt
->second
)
940 if (sink_cell
->type
!= ID($lut
))
943 // Push downstream LUTs past inverter
944 for (auto sink_cell
: jt
->second
) {
945 SigSpec A
= sink_cell
->getPort(ID::A
);
946 RTLIL::Const mask
= sink_cell
->getParam(ID(LUT
));
948 for (; index
< GetSize(A
); index
++)
949 if (A
[index
] == a_bit
)
951 log_assert(index
< GetSize(A
));
953 while (i
< GetSize(mask
)) {
954 for (int j
= 0; j
< (1 << index
); j
++)
955 std::swap(mask
[i
+j
], mask
[i
+j
+(1 << index
)]);
959 sink_cell
->setPort(ID::A
, A
);
960 sink_cell
->setParam(ID(LUT
), mask
);
963 // Since we have rewritten all sinks (which we know
964 // to be only LUTs) to be after the inverter, we can
965 // go ahead and clone the LUT with the expectation
966 // that the original driving LUT will become dangling
967 // and get cleaned away
969 driver_mask
= driver_lut
->getParam(ID(LUT
));
970 for (auto &b
: driver_mask
.bits
) {
971 if (b
== RTLIL::State::S0
) b
= RTLIL::State::S1
;
972 else if (b
== RTLIL::State::S1
) b
= RTLIL::State::S0
;
974 auto cell
= module
->addLut(NEW_ID
,
975 driver_lut
->getPort(ID::A
),
978 for (auto &bit
: cell
->connections_
.at(ID::A
)) {
979 bit
.wire
= module
->wires_
.at(remap_name(bit
.wire
->name
));
980 bit2sinks
[bit
].push_back(cell
);
984 //log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires);
985 log("ABC RESULTS: input signals: %8d\n", in_wires
);
986 log("ABC RESULTS: output signals: %8d\n", out_wires
);
988 design
->remove(mapped_mod
);
991 struct Abc9OpsPass
: public Pass
{
992 Abc9OpsPass() : Pass("abc9_ops", "helper functions for ABC9") { }
993 void help() YS_OVERRIDE
995 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
997 log(" abc9_ops [options] [selection]\n");
1000 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
1002 log_header(design
, "Executing ABC9_OPS pass (helper functions for ABC9).\n");
1004 bool check_mode
= false;
1005 bool prep_times_mode
= false;
1006 bool break_scc_mode
= false;
1007 bool unbreak_scc_mode
= false;
1008 bool prep_holes_mode
= false;
1009 bool prep_dff_mode
= false;
1010 std::string write_box_src
, write_box_dst
;
1011 bool reintegrate_mode
= false;
1012 bool dff_mode
= false;
1015 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
1016 std::string arg
= args
[argidx
];
1017 if (arg
== "-check") {
1021 if (arg
== "-break_scc") {
1022 break_scc_mode
= true;
1025 if (arg
== "-unbreak_scc") {
1026 unbreak_scc_mode
= true;
1029 if (arg
== "-prep_dff") {
1030 prep_dff_mode
= true;
1033 if (arg
== "-prep_holes") {
1034 prep_holes_mode
= true;
1037 if (arg
== "-prep_times") {
1038 prep_times_mode
= true;
1041 if (arg
== "-write_box" && argidx
+2 < args
.size()) {
1042 write_box_src
= args
[++argidx
];
1043 write_box_dst
= args
[++argidx
];
1044 rewrite_filename(write_box_src
);
1045 rewrite_filename(write_box_dst
);
1048 if (arg
== "-reintegrate") {
1049 reintegrate_mode
= true;
1052 if (arg
== "-dff") {
1058 extra_args(args
, argidx
, design
);
1060 if (!(check_mode
|| break_scc_mode
|| unbreak_scc_mode
|| prep_times_mode
|| prep_holes_mode
|| prep_dff_mode
|| !write_box_src
.empty() || reintegrate_mode
))
1061 log_cmd_error("At least one of -check, -{,un}break_scc, -prep_{times,holes,dff}, -write_box, -reintegrate must be specified.\n");
1063 if (dff_mode
&& !prep_holes_mode
)
1064 log_cmd_error("'-dff' option is only relevant for -prep_holes.\n");
1068 if (prep_times_mode
)
1071 for (auto mod
: design
->selected_modules()) {
1072 if (mod
->get_bool_attribute("\\abc9_holes"))
1075 if (mod
->processes
.size() > 0) {
1076 log("Skipping module %s as it contains processes.\n", log_id(mod
));
1080 if (!design
->selected_whole_module(mod
))
1081 log_error("Can't handle partially selected module %s!\n", log_id(mod
));
1085 if (unbreak_scc_mode
)
1087 if (prep_holes_mode
)
1088 prep_holes(mod
, dff_mode
);
1091 if (!write_box_src
.empty())
1092 write_box(mod
, write_box_src
, write_box_dst
);
1093 if (reintegrate_mode
)
1099 PRIVATE_NAMESPACE_END