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"
25 #include "kernel/timinginfo.h"
28 PRIVATE_NAMESPACE_BEGIN
32 inline std::string
remap_name(RTLIL::IdString abc9_name
)
34 return stringf("$abc$%d$%s", map_autoidx
, abc9_name
.c_str()+1);
37 void check(RTLIL::Design
*design
)
39 dict
<IdString
,IdString
> box_lookup
;
40 for (auto m
: design
->modules()) {
41 if (m
->name
.begins_with("$paramod"))
44 auto flop
= m
->get_bool_attribute(ID(abc9_flop
));
45 auto it
= m
->attributes
.find(ID(abc9_box_id
));
47 if (it
== m
->attributes
.end())
49 auto id
= it
->second
.as_int();
50 auto r
= box_lookup
.insert(std::make_pair(stringf("$__boxid%d", id
), m
->name
));
52 log_error("Module '%s' has the same abc9_box_id = %d value as '%s'.\n",
53 log_id(m
), id
, log_id(r
.first
->second
));
56 // Make carry in the last PI, and carry out the last PO
57 // since ABC requires it this way
58 IdString carry_in
, carry_out
;
59 for (const auto &port_name
: m
->ports
) {
60 auto w
= m
->wire(port_name
);
62 if (w
->get_bool_attribute("\\abc9_carry")) {
64 if (carry_in
!= IdString())
65 log_error("Module '%s' contains more than one (* abc9_carry *) input port.\n", log_id(m
));
69 if (carry_out
!= IdString())
70 log_error("Module '%s' contains more than one (* abc9_carry *) output port.\n", log_id(m
));
71 carry_out
= port_name
;
76 if (carry_in
!= IdString() && carry_out
== IdString())
77 log_error("Module '%s' contains an (* abc9_carry *) input port but no output port.\n", log_id(m
));
78 if (carry_in
== IdString() && carry_out
!= IdString())
79 log_error("Module '%s' contains an (* abc9_carry *) output port but no input port.\n", log_id(m
));
83 for (auto port_name
: m
->ports
) {
84 auto wire
= m
->wire(port_name
);
85 if (wire
->port_output
) num_outputs
++;
88 log_error("Module '%s' with (* abc9_flop *) has %d outputs (expect 1).\n", log_id(m
), num_outputs
);
93 void mark_scc(RTLIL::Module
*module
)
95 // For every unique SCC found, (arbitrarily) find the first
96 // cell in the component, and convert all wires driven by
97 // its output ports into a new PO, and drive its previous
98 // sinks with a new PI
99 pool
<RTLIL::Const
> ids_seen
;
100 for (auto cell
: module
->cells()) {
101 auto it
= cell
->attributes
.find(ID(abc9_scc_id
));
102 if (it
== cell
->attributes
.end())
104 auto id
= it
->second
;
105 auto r
= ids_seen
.insert(id
);
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();
114 w
->set_bool_attribute(ID::keep
);
115 w
->attributes
[ID(abc9_scc_id
)] = id
.as_int();
120 module
->fixup_ports();
123 void prep_dff(RTLIL::Module
*module
)
125 auto design
= module
->design
;
128 SigMap
assign_map(module
);
130 typedef SigSpec clkdomain_t
;
131 dict
<clkdomain_t
, int> clk_to_mergeability
;
133 for (auto cell
: module
->cells()) {
134 if (cell
->type
!= "$__ABC9_FF_")
137 Wire
*abc9_clock_wire
= module
->wire(stringf("%s.clock", cell
->name
.c_str()));
138 if (abc9_clock_wire
== NULL
)
139 log_error("'%s.clock' is not a wire present in module '%s'.\n", cell
->name
.c_str(), log_id(module
));
140 SigSpec abc9_clock
= assign_map(abc9_clock_wire
);
142 clkdomain_t
key(abc9_clock
);
144 auto r
= clk_to_mergeability
.insert(std::make_pair(abc9_clock
, clk_to_mergeability
.size() + 1));
145 auto r2
= cell
->attributes
.insert(ID(abc9_mergeability
));;
146 log_assert(r2
.second
);
147 r2
.first
->second
= r
.first
->second
;
150 RTLIL::Module
*holes_module
= design
->module(stringf("%s$holes", module
->name
.c_str()));
152 SigMap
sigmap(holes_module
);
154 dict
<SigSpec
, SigSpec
> replace
;
155 for (auto cell
: holes_module
->cells().to_vector()) {
156 if (!cell
->type
.in("$_DFF_N_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_",
157 "$_DFF_P_", "$_DFF_PN0_", "$_DFF_PN1", "$_DFF_PP0_", "$_DFF_PP1_"))
159 SigBit D
= cell
->getPort("\\D");
160 SigBit Q
= cell
->getPort("\\Q");
161 // Emulate async control embedded inside $_DFF_* cell with mux in front of D
162 if (cell
->type
.in("$_DFF_NN0_", "$_DFF_PN0_"))
163 D
= holes_module
->MuxGate(NEW_ID
, State::S0
, D
, cell
->getPort("\\R"));
164 else if (cell
->type
.in("$_DFF_NN1_", "$_DFF_PN1_"))
165 D
= holes_module
->MuxGate(NEW_ID
, State::S1
, D
, cell
->getPort("\\R"));
166 else if (cell
->type
.in("$_DFF_NP0_", "$_DFF_PP0_"))
167 D
= holes_module
->MuxGate(NEW_ID
, D
, State::S0
, cell
->getPort("\\R"));
168 else if (cell
->type
.in("$_DFF_NP1_", "$_DFF_PP1_"))
169 D
= holes_module
->MuxGate(NEW_ID
, D
, State::S1
, cell
->getPort("\\R"));
170 // Remove the $_DFF_* cell from what needs to be a combinatorial box
171 holes_module
->remove(cell
);
173 if (GetSize(Q
.wire
) == 1)
174 port
= holes_module
->wire(stringf("$abc%s", Q
.wire
->name
.c_str()));
176 port
= holes_module
->wire(stringf("$abc%s[%d]", Q
.wire
->name
.c_str(), Q
.offset
));
178 // Prepare to replace "assign <port> = $_DFF_*.Q;" with "assign <port> = $_DFF_*.D;"
179 // in order to extract just the combinatorial control logic that feeds the box
180 // (i.e. clock enable, synchronous reset, etc.)
181 replace
.insert(std::make_pair(Q
,D
));
182 // Since `flatten` above would have created wires named "<cell>.Q",
183 // extract the pre-techmap cell name
184 auto pos
= Q
.wire
->name
.str().rfind(".");
185 log_assert(pos
!= std::string::npos
);
186 IdString driver
= Q
.wire
->name
.substr(0, pos
);
187 // And drive the signal that was previously driven by "DFF.Q" (typically
188 // used to implement clock-enable functionality) with the "<cell>.$abc9_currQ"
189 // wire (which itself is driven an by input port) we inserted above
190 Wire
*currQ
= holes_module
->wire(stringf("%s.abc9_ff.Q", driver
.c_str()));
192 holes_module
->connect(Q
, currQ
);
195 for (auto &conn
: holes_module
->connections_
)
196 conn
.second
= replace
.at(sigmap(conn
.second
), conn
.second
);
200 void prep_xaiger(RTLIL::Module
*module
, bool dff
)
202 auto design
= module
->design
;
205 SigMap
sigmap(module
);
207 dict
<SigBit
, pool
<IdString
>> bit_drivers
, bit_users
;
208 TopoSort
<IdString
, RTLIL::sort_by_id_str
> toposort
;
209 dict
<IdString
, std::vector
<IdString
>> box_ports
;
211 for (auto cell
: module
->cells()) {
212 if (cell
->type
== "$__ABC9_FF_")
214 if (cell
->has_keep_attr())
217 auto inst_module
= module
->design
->module(cell
->type
);
218 bool abc9_flop
= inst_module
&& inst_module
->get_bool_attribute("\\abc9_flop");
219 if (abc9_flop
&& !dff
)
222 if ((inst_module
&& inst_module
->get_bool_attribute("\\abc9_box")) || abc9_flop
) {
223 auto r
= box_ports
.insert(cell
->type
);
225 // Make carry in the last PI, and carry out the last PO
226 // since ABC requires it this way
227 IdString carry_in
, carry_out
;
228 for (const auto &port_name
: inst_module
->ports
) {
229 auto w
= inst_module
->wire(port_name
);
231 if (w
->get_bool_attribute("\\abc9_carry")) {
232 log_assert(w
->port_input
!= w
->port_output
);
234 carry_in
= port_name
;
235 else if (w
->port_output
)
236 carry_out
= port_name
;
239 r
.first
->second
.push_back(port_name
);
241 if (carry_in
!= IdString()) {
242 r
.first
->second
.push_back(carry_in
);
243 r
.first
->second
.push_back(carry_out
);
247 else if (!yosys_celltypes
.cell_known(cell
->type
))
250 // TODO: Speed up toposort -- we care about box ordering only
251 for (auto conn
: cell
->connections()) {
252 if (cell
->input(conn
.first
))
253 for (auto bit
: sigmap(conn
.second
))
254 bit_users
[bit
].insert(cell
->name
);
256 if (cell
->output(conn
.first
) && !abc9_flop
)
257 for (auto bit
: sigmap(conn
.second
))
258 bit_drivers
[bit
].insert(cell
->name
);
260 toposort
.node(cell
->name
);
263 if (box_ports
.empty())
266 for (auto &it
: bit_users
)
267 if (bit_drivers
.count(it
.first
))
268 for (auto driver_cell
: bit_drivers
.at(it
.first
))
269 for (auto user_cell
: it
.second
)
270 toposort
.edge(driver_cell
, user_cell
);
273 toposort
.analyze_loops
= true;
275 bool no_loops
YS_ATTRIBUTE(unused
) = toposort
.sort();
279 for (auto &it
: toposort
.loops
) {
280 log(" loop %d\n", i
++);
281 for (auto cell_name
: it
) {
282 auto cell
= module
->cell(cell_name
);
284 log("\t%s (%s @ %s)\n", log_id(cell
), log_id(cell
->type
), cell
->get_src_attribute().c_str());
289 log_assert(no_loops
);
291 RTLIL::Module
*holes_module
= design
->addModule(stringf("%s$holes", module
->name
.c_str()));
292 log_assert(holes_module
);
293 holes_module
->set_bool_attribute("\\abc9_holes");
295 dict
<IdString
, Cell
*> cell_cache
;
297 int port_id
= 1, box_count
= 0;
298 for (auto cell_name
: toposort
.sorted
) {
299 RTLIL::Cell
*cell
= module
->cell(cell_name
);
302 RTLIL::Module
* box_module
= design
->module(cell
->type
);
303 if (!box_module
|| (!box_module
->get_bool_attribute("\\abc9_box") && !box_module
->get_bool_attribute("\\abc9_flop")))
306 cell
->attributes
["\\abc9_box_seq"] = box_count
++;
308 IdString derived_type
= box_module
->derive(design
, cell
->parameters
);
309 box_module
= design
->module(derived_type
);
311 auto r
= cell_cache
.insert(derived_type
);
312 auto &holes_cell
= r
.first
->second
;
314 if (box_module
->has_processes())
315 Pass::call_on_module(design
, box_module
, "proc");
317 if (box_module
->get_bool_attribute("\\whitebox")) {
318 holes_cell
= holes_module
->addCell(cell
->name
, derived_type
);
320 if (box_module
->has_processes())
321 Pass::call_on_module(design
, box_module
, "proc");
324 for (auto port_name
: box_ports
.at(cell
->type
)) {
325 RTLIL::Wire
*w
= box_module
->wire(port_name
);
327 log_assert(!w
->port_input
|| !w
->port_output
);
328 auto &conn
= holes_cell
->connections_
[port_name
];
330 for (int i
= 0; i
< GetSize(w
); i
++) {
332 RTLIL::Wire
*holes_wire
= holes_module
->wire(stringf("\\i%d", box_inputs
));
334 holes_wire
= holes_module
->addWire(stringf("\\i%d", box_inputs
));
335 holes_wire
->port_input
= true;
336 holes_wire
->port_id
= port_id
++;
337 holes_module
->ports
.push_back(holes_wire
->name
);
339 conn
.append(holes_wire
);
342 else if (w
->port_output
)
343 conn
= holes_module
->addWire(stringf("%s.%s", derived_type
.c_str(), log_id(port_name
)), GetSize(w
));
346 // For flops only, create an extra 1-bit input that drives a new wire
347 // called "<cell>.abc9_ff.Q" that is used below
348 if (box_module
->get_bool_attribute("\\abc9_flop")) {
350 Wire
*holes_wire
= holes_module
->wire(stringf("\\i%d", box_inputs
));
352 holes_wire
= holes_module
->addWire(stringf("\\i%d", box_inputs
));
353 holes_wire
->port_input
= true;
354 holes_wire
->port_id
= port_id
++;
355 holes_module
->ports
.push_back(holes_wire
->name
);
357 Wire
*Q
= holes_module
->addWire(stringf("%s.abc9_ff.Q", cell
->name
.c_str()));
358 holes_module
->connect(Q
, holes_wire
);
361 else // box_module is a blackbox
362 log_assert(holes_cell
== nullptr);
365 for (auto port_name
: box_ports
.at(cell
->type
)) {
366 RTLIL::Wire
*w
= box_module
->wire(port_name
);
370 Wire
*holes_wire
= holes_module
->addWire(stringf("$abc%s.%s", cell
->name
.c_str(), log_id(port_name
)), GetSize(w
));
371 holes_wire
->port_output
= true;
372 holes_wire
->port_id
= port_id
++;
373 holes_module
->ports
.push_back(holes_wire
->name
);
374 if (holes_cell
) // whitebox
375 holes_module
->connect(holes_wire
, holes_cell
->getPort(port_name
));
377 holes_module
->connect(holes_wire
, Const(State::S0
, GetSize(w
)));
382 void prep_delays(RTLIL::Design
*design
, bool dff_mode
)
384 // Derive all Yosys blackbox modules that are not combinatorial abc9 boxes
385 // (e.g. DSPs, RAMs, etc.) nor abc9 flops and collect all such instantiations
387 std::vector
<Cell
*> cells
;
388 for (auto module
: design
->selected_modules()) {
389 if (module
->processes
.size() > 0) {
390 log("Skipping module %s as it contains processes.\n", log_id(module
));
394 for (auto cell
: module
->cells()) {
395 if (cell
->type
.in(ID($_AND_
), ID($_NOT_
), ID($__ABC9_FF_
), ID($__ABC9_DELAY
)))
398 RTLIL::Module
* inst_module
= module
->design
->module(cell
->type
);
401 if (!inst_module
->get_blackbox_attribute())
403 if (inst_module
->attributes
.count(ID(abc9_box
)))
405 IdString blackboxes_type
= inst_module
->derive(design
, cell
->parameters
);
406 inst_module
= design
->module(blackboxes_type
);
407 log_assert(inst_module
);
409 if (dff_mode
&& inst_module
->get_bool_attribute(ID(abc9_flop
))) {
410 flops
.insert(inst_module
);
411 continue; // do not add $__ABC9_DELAY boxes to flops
412 // as delays will be captured in the flop box
415 cells
.emplace_back(cell
);
419 const TimingInfo
timing(design
);
421 // Transform all $specify3 and $specrule to abc9_{arrival,required} attributes
424 std::stringstream ss
;
425 for (auto module
: design
->modules()) {
427 auto it
= timing
.find(module
->name
);
428 if (it
== timing
.end())
431 const auto &t
= it
->second
;
432 if (t
.arrival
.empty() && t
.required
.empty())
435 const auto &arrival
= t
.arrival
;
436 const auto &required
= t
.required
;
439 for (const auto &i
: arrival
)
440 ports
.insert(i
.first
.wire
);
441 for (auto wire
: ports
) {
442 log_assert(wire
->port_output
);
444 if (GetSize(wire
) == 1)
445 wire
->attributes
[ID(abc9_arrival
)] = arrival
.at(SigBit(wire
,0));
448 for (auto b
: SigSpec(wire
)) {
453 ss
<< arrival
.at(b
, 0);
455 wire
->attributes
[ID(abc9_arrival
)] = ss
.str();
460 for (const auto &i
: required
)
461 ports
.insert(i
.first
.wire
);
462 for (auto wire
: ports
) {
463 log_assert(wire
->port_input
);
465 if (GetSize(wire
) == 1)
466 wire
->attributes
[ID(abc9_required
)] = required
.at(SigBit(wire
,0));
469 for (auto b
: SigSpec(wire
)) {
474 ss
<< required
.at(b
, 0);
476 wire
->attributes
[ID(abc9_required
)] = ss
.str();
481 // Insert $__ABC9_DELAY cells on all cells that instantiate blackboxes
482 // with (* abc9_required *) attributes
483 dict
<IdString
,dict
<IdString
,std::vector
<int>>> requireds_cache
;
484 for (auto cell
: cells
) {
485 auto module
= cell
->module
;
486 RTLIL::Module
* inst_module
= module
->design
->module(cell
->type
);
487 log_assert(inst_module
);
488 IdString derived_type
= inst_module
->derive(design
, cell
->parameters
);
489 inst_module
= design
->module(derived_type
);
490 log_assert(inst_module
);
492 auto &cell_requireds
= requireds_cache
[derived_type
];
493 for (auto &conn
: cell
->connections_
) {
494 auto port_wire
= inst_module
->wire(conn
.first
);
495 if (!port_wire
->port_input
)
498 auto r
= cell_requireds
.insert(conn
.first
);
499 auto &requireds
= r
.first
->second
;
501 auto it
= port_wire
->attributes
.find("\\abc9_required");
502 if (it
== port_wire
->attributes
.end())
504 if (it
->second
.flags
== 0) {
505 int delay
= it
->second
.as_int();
506 requireds
.emplace_back(delay
);
509 for (const auto &tok
: split_tokens(it
->second
.decode_string())) {
510 int delay
= atoi(tok
.c_str());
511 requireds
.push_back(delay
);
515 if (requireds
.empty())
518 SigSpec O
= module
->addWire(NEW_ID
, GetSize(conn
.second
));
519 auto it
= requireds
.begin();
520 for (int i
= 0; i
< GetSize(conn
.second
); ++i
) {
523 static std::set
<std::pair
<IdString
,IdString
>> seen
;
524 if (seen
.emplace(derived_type
, conn
.first
).second
) log("%s.%s abc9_required = '%s'\n", log_id(cell
->type
), log_id(conn
.first
),
525 port_wire
->attributes
.at("\\abc9_required").decode_string().c_str());
528 auto box
= module
->addCell(NEW_ID
, ID($__ABC9_DELAY
));
529 box
->setPort(ID(I
), conn
.second
[i
]);
530 box
->setPort(ID(O
), O
[i
]);
531 box
->setParam(ID(DELAY
), *it
);
532 if (requireds
.size() > 1)
534 conn
.second
[i
] = O
[i
];
540 void prep_lut(RTLIL::Design
*design
, int maxlut
)
542 const TimingInfo
timing(design
);
544 std::vector
<std::tuple
<int, IdString
, int, std::vector
<int>>> table
;
545 for (auto module
: design
->modules()) {
546 auto it
= module
->attributes
.find(ID(abc9_lut
));
547 if (it
== module
->attributes
.end())
550 auto jt
= timing
.find(module
->name
);
551 if (jt
== timing
.end())
555 std::vector
<int> specify
;
556 auto &t
= jt
->second
;
557 for (const auto &i
: t
.comb
) {
558 auto &d
= i
.first
.second
;
563 log_error("(* abc9_lut *) module '%s' with has more than one output.\n", log_id(module
));
564 specify
.push_back(i
.second
);
567 if (maxlut
&& GetSize(specify
) > maxlut
)
569 // ABC requires non-decreasing LUT input delays
570 std::sort(specify
.begin(), specify
.end());
571 table
.emplace_back(GetSize(specify
), module
->name
, it
->second
.as_int(), std::move(specify
));
573 // ABC requires ascending size
574 std::sort(table
.begin(), table
.end());
576 std::stringstream ss
;
577 const auto &first
= table
.front();
578 // If the first entry does not start from a 1-input LUT,
579 // (as ABC requires) crop the first entry to do so
580 for (int i
= 1; i
< std::get
<0>(first
); i
++) {
581 ss
<< "# $__ABC9_LUT" << i
<< std::endl
;
582 ss
<< i
<< " " << std::get
<2>(first
);
583 for (int j
= 0; j
< i
; j
++)
584 ss
<< " " << std::get
<3>(first
)[j
];
587 for (const auto &i
: table
) {
588 ss
<< "# " << log_id(std::get
<1>(i
)) << std::endl
;
589 ss
<< std::get
<0>(i
) << " " << std::get
<2>(i
);
590 for (const auto &j
: std::get
<3>(i
))
594 design
->scratchpad_set_string("abc9_ops.lut_library", ss
.str());
597 void write_lut(RTLIL::Module
*module
, const std::string
&dst
) {
598 std::ofstream
ofs(dst
);
599 log_assert(ofs
.is_open());
600 ofs
<< module
->design
->scratchpad_get_string("abc9_ops.lut_library");
604 void prep_box(RTLIL::Design
*design
, bool dff_mode
)
606 const TimingInfo
timing(design
);
608 std::stringstream ss
;
610 for (auto module
: design
->modules()) {
611 auto it
= module
->attributes
.find(ID(abc9_box_id
));
612 if (it
== module
->attributes
.end())
614 abc9_box_id
= std::max(abc9_box_id
, it
->second
.as_int());
617 dict
<IdString
,std::vector
<IdString
>> box_ports
;
618 for (auto module
: design
->modules()) {
619 auto abc9_flop
= module
->get_bool_attribute(ID(abc9_flop
));
621 auto r
= module
->attributes
.insert(ID(abc9_box_id
));
624 r
.first
->second
= abc9_box_id
++;
627 int num_inputs
= 0, num_outputs
= 0;
628 for (auto port_name
: module
->ports
) {
629 auto wire
= module
->wire(port_name
);
630 log_assert(GetSize(wire
) == 1);
631 if (wire
->port_input
) num_inputs
++;
632 if (wire
->port_output
) num_outputs
++;
634 log_assert(num_outputs
== 1);
636 ss
<< log_id(module
) << " " << r
.first
->second
.as_int();
637 ss
<< " " << (module
->get_bool_attribute(ID::whitebox
) ? "1" : "0");
638 ss
<< " " << num_inputs
+1 << " " << num_outputs
<< std::endl
;
642 for (auto port_name
: module
->ports
) {
643 auto wire
= module
->wire(port_name
);
644 if (!wire
->port_input
)
652 ss
<< " abc9_ff.Q" << std::endl
;
655 for (auto port_name
: module
->ports
) {
656 auto wire
= module
->wire(port_name
);
657 if (!wire
->port_input
)
663 auto it
= wire
->attributes
.find("\\abc9_required");
664 if (it
== wire
->attributes
.end())
667 log_assert(it
->second
.flags
== 0);
668 ss
<< it
->second
.as_int();
672 static std::set
<std::pair
<IdString
,IdString
>> seen
;
673 if (seen
.emplace(module
->name
, port_name
).second
) log("%s.%s abc9_required = %d\n", log_id(module
),
674 log_id(port_name
), it
->second
.as_int());
680 // Last input is 'abc9_ff.Q'
681 ss
<< " 0" << std::endl
<< std::endl
;
686 if (!module
->attributes
.erase(ID(abc9_box
)))
689 auto r
= module
->attributes
.insert(ID(abc9_box_id
));
692 r
.first
->second
= abc9_box_id
++;
695 auto r
= box_ports
.insert(module
->name
);
697 // Make carry in the last PI, and carry out the last PO
698 // since ABC requires it this way
699 IdString carry_in
, carry_out
;
700 for (const auto &port_name
: module
->ports
) {
701 auto w
= module
->wire(port_name
);
703 if (w
->get_bool_attribute("\\abc9_carry")) {
704 log_assert(w
->port_input
!= w
->port_output
);
706 carry_in
= port_name
;
707 else if (w
->port_output
)
708 carry_out
= port_name
;
711 r
.first
->second
.push_back(port_name
);
714 if (carry_in
!= IdString()) {
715 r
.first
->second
.push_back(carry_in
);
716 r
.first
->second
.push_back(carry_out
);
720 std::vector
<SigBit
> inputs
;
721 std::vector
<SigBit
> outputs
;
722 for (auto port_name
: r
.first
->second
) {
723 auto wire
= module
->wire(port_name
);
724 if (wire
->port_input
)
725 for (int i
= 0; i
< GetSize(wire
); i
++)
726 inputs
.emplace_back(wire
, i
);
727 if (wire
->port_output
)
728 for (int i
= 0; i
< GetSize(wire
); i
++)
729 outputs
.emplace_back(wire
, i
);
732 ss
<< log_id(module
) << " " << module
->attributes
.at(ID(abc9_box_id
)).as_int();
733 ss
<< " " << (module
->get_bool_attribute(ID::whitebox
) ? "1" : "0");
734 ss
<< " " << GetSize(inputs
) << " " << GetSize(outputs
) << std::endl
;
738 for (const auto &i
: inputs
) {
743 if (GetSize(i
.wire
) == 1)
744 ss
<< log_id(i
.wire
);
746 ss
<< log_id(i
.wire
) << "[" << i
.offset
<< "]";
750 auto it
= timing
.find(module
->name
);
751 if (it
== timing
.end())
752 log_error("(* abc9_box *) module '%s' has no timing information.\n", log_id(module
));
754 const auto &t
= it
->second
.comb
;
755 for (const auto &o
: outputs
) {
757 for (const auto &i
: inputs
) {
762 auto jt
= t
.find(std::make_pair(i
,o
));
769 if (GetSize(o
.wire
) == 1)
770 ss
<< log_id(o
.wire
);
772 ss
<< log_id(o
.wire
) << "[" << o
.offset
<< "]";
779 // ABC expects at least one box
781 ss
<< "(dummy) 1 0 0 0";
783 design
->scratchpad_set_string("abc9_ops.box_library", ss
.str());
786 void write_box(RTLIL::Module
*module
, const std::string
&dst
) {
787 std::ofstream
ofs(dst
);
788 log_assert(ofs
.is_open());
789 ofs
<< module
->design
->scratchpad_get_string("abc9_ops.box_library");
793 void reintegrate(RTLIL::Module
*module
)
795 auto design
= module
->design
;
798 map_autoidx
= autoidx
++;
800 RTLIL::Module
*mapped_mod
= design
->module(stringf("%s$abc9", module
->name
.c_str()));
801 if (mapped_mod
== NULL
)
802 log_error("ABC output file does not contain a module `%s$abc'.\n", log_id(module
));
804 for (auto w
: mapped_mod
->wires())
805 module
->addWire(remap_name(w
->name
), GetSize(w
));
807 dict
<IdString
,std::vector
<IdString
>> box_ports
;
809 for (auto m
: design
->modules()) {
810 if (!m
->attributes
.count(ID(abc9_box_id
)))
813 auto r
= box_ports
.insert(m
->name
);
817 // Make carry in the last PI, and carry out the last PO
818 // since ABC requires it this way
819 IdString carry_in
, carry_out
;
820 for (const auto &port_name
: m
->ports
) {
821 auto w
= m
->wire(port_name
);
823 if (w
->get_bool_attribute("\\abc9_carry")) {
824 log_assert(w
->port_input
!= w
->port_output
);
826 carry_in
= port_name
;
827 else if (w
->port_output
)
828 carry_out
= port_name
;
831 r
.first
->second
.push_back(port_name
);
834 if (carry_in
!= IdString()) {
835 r
.first
->second
.push_back(carry_in
);
836 r
.first
->second
.push_back(carry_out
);
840 std::vector
<Cell
*> boxes
;
841 for (auto cell
: module
->cells().to_vector()) {
842 if (cell
->has_keep_attr())
844 if (cell
->type
.in(ID($_AND_
), ID($_NOT_
), ID($__ABC9_FF_
)))
845 module
->remove(cell
);
846 else if (cell
->attributes
.erase("\\abc9_box_seq"))
847 boxes
.emplace_back(cell
);
850 dict
<SigBit
, pool
<IdString
>> bit_drivers
, bit_users
;
851 TopoSort
<IdString
, RTLIL::sort_by_id_str
> toposort
;
852 dict
<RTLIL::Cell
*,RTLIL::Cell
*> not2drivers
;
853 dict
<SigBit
, std::vector
<RTLIL::Cell
*>> bit2sinks
;
855 std::map
<IdString
, int> cell_stats
;
856 for (auto mapped_cell
: mapped_mod
->cells())
858 // TODO: Speed up toposort -- we care about NOT ordering only
859 toposort
.node(mapped_cell
->name
);
861 if (mapped_cell
->type
== ID($_NOT_
)) {
862 RTLIL::SigBit a_bit
= mapped_cell
->getPort(ID::A
);
863 RTLIL::SigBit y_bit
= mapped_cell
->getPort(ID::Y
);
864 bit_users
[a_bit
].insert(mapped_cell
->name
);
865 // Ignore inouts for topo ordering
866 if (y_bit
.wire
&& !(y_bit
.wire
->port_input
&& y_bit
.wire
->port_output
))
867 bit_drivers
[y_bit
].insert(mapped_cell
->name
);
870 mapped_cell
->setPort(ID::Y
, module
->addWire(NEW_ID
));
871 RTLIL::Wire
*wire
= module
->wire(remap_name(y_bit
.wire
->name
));
873 module
->connect(RTLIL::SigBit(wire
, y_bit
.offset
), State::S1
);
876 RTLIL::Cell
* driver_lut
= nullptr;
877 // ABC can return NOT gates that drive POs
878 if (!a_bit
.wire
->port_input
) {
879 // If it's not a NOT gate that that comes from a PI directly,
880 // find the driver LUT and clone that to guarantee that we won't
881 // increase the max logic depth
882 // (TODO: Optimise by not cloning unless will increase depth)
883 RTLIL::IdString driver_name
;
884 if (GetSize(a_bit
.wire
) == 1)
885 driver_name
= stringf("$lut%s", a_bit
.wire
->name
.c_str());
887 driver_name
= stringf("$lut%s[%d]", a_bit
.wire
->name
.c_str(), a_bit
.offset
);
888 driver_lut
= mapped_mod
->cell(driver_name
);
892 // If a driver couldn't be found (could be from PI or box CI)
893 // then implement using a LUT
894 RTLIL::Cell
*cell
= module
->addLut(remap_name(stringf("$lut%s", mapped_cell
->name
.c_str())),
895 RTLIL::SigBit(module
->wires_
.at(remap_name(a_bit
.wire
->name
)), a_bit
.offset
),
896 RTLIL::SigBit(module
->wires_
.at(remap_name(y_bit
.wire
->name
)), y_bit
.offset
),
897 RTLIL::Const::from_string("01"));
898 bit2sinks
[cell
->getPort(ID::A
)].push_back(cell
);
899 cell_stats
[ID($lut
)]++;
902 not2drivers
[mapped_cell
] = driver_lut
;
907 if (mapped_cell
->type
.in(ID($lut
), ID($__ABC9_FF_
))) {
908 RTLIL::Cell
*cell
= module
->addCell(remap_name(mapped_cell
->name
), mapped_cell
->type
);
909 cell
->parameters
= mapped_cell
->parameters
;
910 cell
->attributes
= mapped_cell
->attributes
;
912 for (auto &mapped_conn
: mapped_cell
->connections()) {
913 RTLIL::SigSpec newsig
;
914 for (auto c
: mapped_conn
.second
.chunks()) {
917 //log_assert(c.width == 1);
919 c
.wire
= module
->wires_
.at(remap_name(c
.wire
->name
));
922 cell
->setPort(mapped_conn
.first
, newsig
);
924 if (cell
->input(mapped_conn
.first
)) {
925 for (auto i
: newsig
)
926 bit2sinks
[i
].push_back(cell
);
927 for (auto i
: mapped_conn
.second
)
928 bit_users
[i
].insert(mapped_cell
->name
);
930 if (cell
->output(mapped_conn
.first
))
931 for (auto i
: mapped_conn
.second
)
932 // Ignore inouts for topo ordering
933 if (i
.wire
&& !(i
.wire
->port_input
&& i
.wire
->port_output
))
934 bit_drivers
[i
].insert(mapped_cell
->name
);
938 RTLIL::Cell
*existing_cell
= module
->cell(mapped_cell
->name
);
940 log_error("Cannot find existing box cell with name '%s' in original design.\n", log_id(mapped_cell
));
942 if (existing_cell
->type
== ID($__ABC9_DELAY
)) {
943 SigBit I
= mapped_cell
->getPort(ID(i
));
944 SigBit O
= mapped_cell
->getPort(ID(o
));
946 I
.wire
= module
->wires_
.at(remap_name(I
.wire
->name
));
948 O
.wire
= module
->wires_
.at(remap_name(O
.wire
->name
));
949 module
->connect(O
, I
);
953 RTLIL::Module
* box_module
= design
->module(existing_cell
->type
);
954 IdString derived_type
= box_module
->derive(design
, existing_cell
->parameters
);
955 RTLIL::Module
* derived_module
= design
->module(derived_type
);
956 log_assert(derived_module
);
957 log_assert(mapped_cell
->type
== stringf("$__boxid%d", derived_module
->attributes
.at("\\abc9_box_id").as_int()));
958 mapped_cell
->type
= existing_cell
->type
;
960 RTLIL::Cell
*cell
= module
->addCell(remap_name(mapped_cell
->name
), mapped_cell
->type
);
961 cell
->parameters
= existing_cell
->parameters
;
962 cell
->attributes
= existing_cell
->attributes
;
963 module
->swap_names(cell
, existing_cell
);
965 auto jt
= mapped_cell
->connections_
.find("\\i");
966 log_assert(jt
!= mapped_cell
->connections_
.end());
967 SigSpec inputs
= std::move(jt
->second
);
968 mapped_cell
->connections_
.erase(jt
);
969 jt
= mapped_cell
->connections_
.find("\\o");
970 log_assert(jt
!= mapped_cell
->connections_
.end());
971 SigSpec outputs
= std::move(jt
->second
);
972 mapped_cell
->connections_
.erase(jt
);
974 auto abc9_flop
= box_module
->attributes
.count("\\abc9_flop");
976 for (const auto &i
: inputs
)
977 bit_users
[i
].insert(mapped_cell
->name
);
978 for (const auto &i
: outputs
)
979 // Ignore inouts for topo ordering
980 if (i
.wire
&& !(i
.wire
->port_input
&& i
.wire
->port_output
))
981 bit_drivers
[i
].insert(mapped_cell
->name
);
984 int input_count
= 0, output_count
= 0;
985 for (const auto &port_name
: box_ports
.at(derived_type
)) {
986 RTLIL::Wire
*w
= box_module
->wire(port_name
);
991 sig
= inputs
.extract(input_count
, GetSize(w
));
992 input_count
+= GetSize(w
);
994 if (w
->port_output
) {
995 sig
= outputs
.extract(output_count
, GetSize(w
));
996 output_count
+= GetSize(w
);
1000 for (auto c
: sig
.chunks()) {
1003 //log_assert(c.width == 1);
1005 c
.wire
= module
->wires_
.at(remap_name(c
.wire
->name
));
1008 cell
->setPort(port_name
, newsig
);
1010 if (w
->port_input
&& !abc9_flop
)
1011 for (const auto &i
: newsig
)
1012 bit2sinks
[i
].push_back(cell
);
1016 cell_stats
[mapped_cell
->type
]++;
1019 for (auto cell
: boxes
)
1020 module
->remove(cell
);
1022 // Copy connections (and rename) from mapped_mod to module
1023 for (auto conn
: mapped_mod
->connections()) {
1024 if (!conn
.first
.is_fully_const()) {
1025 auto chunks
= conn
.first
.chunks();
1026 for (auto &c
: chunks
)
1027 c
.wire
= module
->wires_
.at(remap_name(c
.wire
->name
));
1028 conn
.first
= std::move(chunks
);
1030 if (!conn
.second
.is_fully_const()) {
1031 auto chunks
= conn
.second
.chunks();
1032 for (auto &c
: chunks
)
1034 c
.wire
= module
->wires_
.at(remap_name(c
.wire
->name
));
1035 conn
.second
= std::move(chunks
);
1037 module
->connect(conn
);
1040 for (auto &it
: cell_stats
)
1041 log("ABC RESULTS: %15s cells: %8d\n", it
.first
.c_str(), it
.second
);
1042 int in_wires
= 0, out_wires
= 0;
1044 // Stitch in mapped_mod's inputs/outputs into module
1045 for (auto port
: mapped_mod
->ports
) {
1046 RTLIL::Wire
*mapped_wire
= mapped_mod
->wire(port
);
1047 RTLIL::Wire
*wire
= module
->wire(port
);
1049 if (wire
->attributes
.erase(ID(abc9_scc_id
))) {
1050 auto r
YS_ATTRIBUTE(unused
) = wire
->attributes
.erase(ID::keep
);
1053 RTLIL::Wire
*remap_wire
= module
->wire(remap_name(port
));
1054 RTLIL::SigSpec
signal(wire
, 0, GetSize(remap_wire
));
1055 log_assert(GetSize(signal
) >= GetSize(remap_wire
));
1058 if (mapped_wire
->port_output
) {
1059 conn
.first
= signal
;
1060 conn
.second
= remap_wire
;
1062 module
->connect(conn
);
1064 else if (mapped_wire
->port_input
) {
1065 conn
.first
= remap_wire
;
1066 conn
.second
= signal
;
1068 module
->connect(conn
);
1072 // ABC9 will return $_NOT_ gates in its mapping (since they are
1073 // treated as being "free"), in particular driving primary
1074 // outputs (real primary outputs, or cells treated as blackboxes)
1075 // or driving box inputs.
1076 // Instead of just mapping those $_NOT_ gates into 2-input $lut-s
1077 // at an area and delay cost, see if it is possible to push
1078 // this $_NOT_ into the driving LUT, or into all sink LUTs.
1079 // When this is not possible, (i.e. this signal drives two primary
1080 // outputs, only one of which is complemented) and when the driver
1081 // is a LUT, then clone the LUT so that it can be inverted without
1082 // increasing depth/delay.
1083 for (auto &it
: bit_users
)
1084 if (bit_drivers
.count(it
.first
))
1085 for (auto driver_cell
: bit_drivers
.at(it
.first
))
1086 for (auto user_cell
: it
.second
)
1087 toposort
.edge(driver_cell
, user_cell
);
1088 bool no_loops
YS_ATTRIBUTE(unused
) = toposort
.sort();
1089 log_assert(no_loops
);
1091 for (auto ii
= toposort
.sorted
.rbegin(); ii
!= toposort
.sorted
.rend(); ii
++) {
1092 RTLIL::Cell
*not_cell
= mapped_mod
->cell(*ii
);
1093 log_assert(not_cell
);
1094 if (not_cell
->type
!= ID($_NOT_
))
1096 auto it
= not2drivers
.find(not_cell
);
1097 if (it
== not2drivers
.end())
1099 RTLIL::Cell
*driver_lut
= it
->second
;
1100 RTLIL::SigBit a_bit
= not_cell
->getPort(ID::A
);
1101 RTLIL::SigBit y_bit
= not_cell
->getPort(ID::Y
);
1102 RTLIL::Const driver_mask
;
1104 a_bit
.wire
= module
->wires_
.at(remap_name(a_bit
.wire
->name
));
1105 y_bit
.wire
= module
->wires_
.at(remap_name(y_bit
.wire
->name
));
1107 auto jt
= bit2sinks
.find(a_bit
);
1108 if (jt
== bit2sinks
.end())
1111 for (auto sink_cell
: jt
->second
)
1112 if (sink_cell
->type
!= ID($lut
))
1115 // Push downstream LUTs past inverter
1116 for (auto sink_cell
: jt
->second
) {
1117 SigSpec A
= sink_cell
->getPort(ID::A
);
1118 RTLIL::Const mask
= sink_cell
->getParam(ID(LUT
));
1120 for (; index
< GetSize(A
); index
++)
1121 if (A
[index
] == a_bit
)
1123 log_assert(index
< GetSize(A
));
1125 while (i
< GetSize(mask
)) {
1126 for (int j
= 0; j
< (1 << index
); j
++)
1127 std::swap(mask
[i
+j
], mask
[i
+j
+(1 << index
)]);
1128 i
+= 1 << (index
+1);
1131 sink_cell
->setPort(ID::A
, A
);
1132 sink_cell
->setParam(ID(LUT
), mask
);
1135 // Since we have rewritten all sinks (which we know
1136 // to be only LUTs) to be after the inverter, we can
1137 // go ahead and clone the LUT with the expectation
1138 // that the original driving LUT will become dangling
1139 // and get cleaned away
1141 driver_mask
= driver_lut
->getParam(ID(LUT
));
1142 for (auto &b
: driver_mask
.bits
) {
1143 if (b
== RTLIL::State::S0
) b
= RTLIL::State::S1
;
1144 else if (b
== RTLIL::State::S1
) b
= RTLIL::State::S0
;
1146 auto cell
= module
->addLut(NEW_ID
,
1147 driver_lut
->getPort(ID::A
),
1150 for (auto &bit
: cell
->connections_
.at(ID::A
)) {
1151 bit
.wire
= module
->wires_
.at(remap_name(bit
.wire
->name
));
1152 bit2sinks
[bit
].push_back(cell
);
1156 //log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires);
1157 log("ABC RESULTS: input signals: %8d\n", in_wires
);
1158 log("ABC RESULTS: output signals: %8d\n", out_wires
);
1160 design
->remove(mapped_mod
);
1163 struct Abc9OpsPass
: public Pass
{
1164 Abc9OpsPass() : Pass("abc9_ops", "helper functions for ABC9") { }
1165 void help() YS_OVERRIDE
1167 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1169 log(" abc9_ops [options] [selection]\n");
1171 log("This pass contains a set of supporting operations for use during ABC technology\n");
1172 log("mapping, and is expected to be called in conjunction with other operations from\n");
1173 log("the `abc9' script pass. Only fully-selected modules are supported.\n");
1176 log(" check that the design is valid, e.g. (* abc9_box_id *) values are unique,\n");
1177 log(" (* abc9_carry *) is only given for one input/output port, etc.\n");
1179 log(" -prep_delays\n");
1180 log(" insert `$__ABC9_DELAY' blackbox cells into the design to account for\n");
1181 log(" certain delays, e.g. (* abc9_required *) values.\n");
1183 log(" -mark_scc\n");
1184 log(" for an arbitrarily chosen cell in each unique SCC of each selected module\n");
1185 log(" (tagged with an (* abc9_scc_id = <int> *) attribute), temporarily mark all\n");
1186 log(" wires driven by this cell's outputs with a (* keep *) attribute in order\n");
1187 log(" to break the SCC. this temporary attribute will be removed on -reintegrate.\n");
1189 log(" -prep_xaiger\n");
1190 log(" prepare the design for XAIGER output. this includes computing the\n");
1191 log(" topological ordering of ABC9 boxes, as well as preparing the\n");
1192 log(" '<module-name>$holes' module that contains the logic behaviour of ABC9\n");
1193 log(" whiteboxes.\n");
1196 log(" consider flop cells (those instantiating modules marked with (* abc9_flop *))\n");
1197 log(" during -prep_{delays,xaiger,box}.\n");
1199 log(" -prep_dff\n");
1200 log(" compute the clock domain and initial value of each flop in the design.\n");
1201 log(" process the '$holes' module to support clock-enable functionality.\n");
1203 log(" -prep_lut <maxlut>\n");
1204 log(" pre-compute the lut library by analysing all modules marked with\n");
1205 log(" (* abc9_lut=<area> *).\n");
1207 log(" -write_lut <dst>\n");
1208 log(" write the pre-computed lut library to <dst>.\n");
1210 log(" -prep_box\n");
1211 log(" pre-compute the box library by analysing all modules marked with\n");
1212 log(" (* abc9_box *).\n");
1214 log(" -write_box <dst>\n");
1215 log(" write the pre-computed box library to <dst>.\n");
1217 log(" -reintegrate\n");
1218 log(" for each selected module, re-intergrate the module '<module-name>$abc9'\n");
1219 log(" by first recovering ABC9 boxes, and then stitching in the remaining primary\n");
1220 log(" inputs and outputs.\n");
1223 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
1225 log_header(design
, "Executing ABC9_OPS pass (helper functions for ABC9).\n");
1227 bool check_mode
= false;
1228 bool prep_delays_mode
= false;
1229 bool mark_scc_mode
= false;
1230 bool prep_dff_mode
= false;
1231 bool prep_xaiger_mode
= false;
1232 bool prep_lut_mode
= false;
1233 bool prep_box_mode
= false;
1234 bool reintegrate_mode
= false;
1235 bool dff_mode
= false;
1236 std::string write_lut_dst
;
1238 std::string write_box_dst
;
1241 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
1242 std::string arg
= args
[argidx
];
1243 if (arg
== "-check") {
1247 if (arg
== "-mark_scc") {
1248 mark_scc_mode
= true;
1251 if (arg
== "-prep_dff") {
1252 prep_dff_mode
= true;
1255 if (arg
== "-prep_xaiger") {
1256 prep_xaiger_mode
= true;
1259 if (arg
== "-prep_delays") {
1260 prep_delays_mode
= true;
1263 if (arg
== "-prep_lut" && argidx
+1 < args
.size()) {
1264 prep_lut_mode
= true;
1265 maxlut
= atoi(args
[++argidx
].c_str());
1268 if (arg
== "-maxlut" && argidx
+1 < args
.size()) {
1271 if (arg
== "-write_lut" && argidx
+1 < args
.size()) {
1272 write_lut_dst
= args
[++argidx
];
1273 rewrite_filename(write_lut_dst
);
1276 if (arg
== "-prep_box") {
1277 prep_box_mode
= true;
1280 if (arg
== "-write_box" && argidx
+1 < args
.size()) {
1281 write_box_dst
= args
[++argidx
];
1282 rewrite_filename(write_box_dst
);
1285 if (arg
== "-reintegrate") {
1286 reintegrate_mode
= true;
1289 if (arg
== "-dff") {
1295 extra_args(args
, argidx
, design
);
1297 if (!(check_mode
|| mark_scc_mode
|| prep_delays_mode
|| prep_xaiger_mode
|| prep_dff_mode
|| prep_lut_mode
|| prep_box_mode
|| !write_lut_dst
.empty() || !write_box_dst
.empty() || reintegrate_mode
))
1298 log_cmd_error("At least one of -check, -mark_scc, -prep_{delays,xaiger,dff,lut,box}, -write_{lut,box}, -reintegrate must be specified.\n");
1300 if (dff_mode
&& !prep_delays_mode
&& !prep_xaiger_mode
&& !prep_box_mode
)
1301 log_cmd_error("'-dff' option is only relevant for -prep_{delay,xaiger,box}.\n");
1305 if (prep_delays_mode
)
1306 prep_delays(design
, dff_mode
);
1308 prep_lut(design
, maxlut
);
1310 prep_box(design
, dff_mode
);
1312 for (auto mod
: design
->selected_modules()) {
1313 if (mod
->get_bool_attribute("\\abc9_holes"))
1316 if (mod
->processes
.size() > 0) {
1317 log("Skipping module %s as it contains processes.\n", log_id(mod
));
1321 if (!design
->selected_whole_module(mod
))
1322 log_error("Can't handle partially selected module %s!\n", log_id(mod
));
1324 if (!write_lut_dst
.empty())
1325 write_lut(mod
, write_lut_dst
);
1326 if (!write_box_dst
.empty())
1327 write_box(mod
, write_box_dst
);
1332 if (prep_xaiger_mode
)
1333 prep_xaiger(mod
, dff_mode
);
1334 if (reintegrate_mode
)
1340 PRIVATE_NAMESPACE_END