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 // https://stackoverflow.com/a/46137633
24 #define bswap32 _byteswap_ulong
25 #elif defined(__APPLE__)
26 #include <libkern/OSByteOrder.h>
27 #define bswap32 OSSwapInt32
28 #elif defined(__GNUC__)
29 #define bswap32 __builtin_bswap32
32 inline static uint32_t bswap32(uint32_t x
)
34 // https://stackoverflow.com/a/27796212
35 register uint32_t value
= number_to_be_reversed
;
36 uint8_t lolo
= (value
>> 0) & 0xFF;
37 uint8_t lohi
= (value
>> 8) & 0xFF;
38 uint8_t hilo
= (value
>> 16) & 0xFF;
39 uint8_t hihi
= (value
>> 24) & 0xFF;
47 #include "kernel/yosys.h"
48 #include "kernel/sigtools.h"
49 #include "kernel/utils.h"
52 PRIVATE_NAMESPACE_BEGIN
54 inline int32_t to_big_endian(int32_t i32
) {
55 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
57 #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
60 #error "Unknown endianness"
64 void aiger_encode(std::ostream
&f
, int x
)
69 f
.put((x
& 0x7f) | 0x80);
81 pool
<SigBit
> input_bits
, output_bits
;
82 dict
<SigBit
, SigBit
> not_map
, alias_map
;
83 dict
<SigBit
, pair
<SigBit
, SigBit
>> and_map
;
84 vector
<SigBit
> ci_bits
, co_bits
;
85 dict
<SigBit
, Cell
*> ff_bits
;
86 dict
<SigBit
, float> arrival_times
;
88 vector
<pair
<int, int>> aig_gates
;
89 vector
<int> aig_outputs
;
90 int aig_m
= 0, aig_i
= 0, aig_l
= 0, aig_o
= 0, aig_a
= 0;
92 dict
<SigBit
, int> aig_map
;
93 dict
<SigBit
, int> ordered_outputs
;
95 vector
<Cell
*> box_list
;
96 dict
<IdString
, std::vector
<IdString
>> box_ports
;
98 int mkgate(int a0
, int a1
)
101 aig_gates
.push_back(a0
> a1
? make_pair(a0
, a1
) : make_pair(a1
, a0
));
105 int bit2aig(SigBit bit
)
107 auto it
= aig_map
.find(bit
);
108 if (it
!= aig_map
.end()) {
109 log_assert(it
->second
>= 0);
113 // NB: Cannot use iterator returned from aig_map.insert()
114 // since this function is called recursively
117 if (not_map
.count(bit
)) {
118 a
= bit2aig(not_map
.at(bit
)) ^ 1;
120 if (and_map
.count(bit
)) {
121 auto args
= and_map
.at(bit
);
122 int a0
= bit2aig(args
.first
);
123 int a1
= bit2aig(args
.second
);
126 if (alias_map
.count(bit
)) {
127 a
= bit2aig(alias_map
.at(bit
));
130 if (bit
== State::Sx
|| bit
== State::Sz
) {
131 log_debug("Design contains 'x' or 'z' bits. Treating as 1'b0.\n");
132 a
= aig_map
.at(State::S0
);
140 XAigerWriter(Module
*module
, bool holes_mode
=false) : module(module
), sigmap(module
)
142 pool
<SigBit
> undriven_bits
;
143 pool
<SigBit
> unused_bits
;
145 // promote public wires
146 for (auto wire
: module
->wires())
147 if (wire
->name
[0] == '\\')
150 // promote input wires
151 for (auto wire
: module
->wires())
152 if (wire
->port_input
)
155 // promote keep wires
156 for (auto wire
: module
->wires())
157 if (wire
->get_bool_attribute(ID::keep
))
161 for (auto wire
: module
->wires())
162 for (int i
= 0; i
< GetSize(wire
); i
++)
164 SigBit
wirebit(wire
, i
);
165 SigBit bit
= sigmap(wirebit
);
167 if (bit
.wire
== nullptr) {
168 if (wire
->port_output
) {
169 aig_map
[wirebit
] = (bit
== State::S1
) ? 1 : 0;
170 output_bits
.insert(wirebit
);
175 undriven_bits
.insert(bit
);
176 unused_bits
.insert(bit
);
178 if (wire
->port_input
)
179 input_bits
.insert(bit
);
181 if (wire
->port_output
) {
183 alias_map
[wirebit
] = bit
;
184 output_bits
.insert(wirebit
);
188 // TODO: Speed up toposort -- ultimately we care about
189 // box ordering, but not individual AIG cells
190 dict
<SigBit
, pool
<IdString
>> bit_drivers
, bit_users
;
191 TopoSort
<IdString
, RTLIL::sort_by_id_str
> toposort
;
192 bool abc9_box_seen
= false;
194 for (auto cell
: module
->selected_cells()) {
195 if (cell
->type
== "$_NOT_")
197 SigBit A
= sigmap(cell
->getPort("\\A").as_bit());
198 SigBit Y
= sigmap(cell
->getPort("\\Y").as_bit());
199 unused_bits
.erase(A
);
200 undriven_bits
.erase(Y
);
202 toposort
.node(cell
->name
);
203 bit_users
[A
].insert(cell
->name
);
204 bit_drivers
[Y
].insert(cell
->name
);
208 if (cell
->type
== "$_AND_")
210 SigBit A
= sigmap(cell
->getPort("\\A").as_bit());
211 SigBit B
= sigmap(cell
->getPort("\\B").as_bit());
212 SigBit Y
= sigmap(cell
->getPort("\\Y").as_bit());
213 unused_bits
.erase(A
);
214 unused_bits
.erase(B
);
215 undriven_bits
.erase(Y
);
216 and_map
[Y
] = make_pair(A
, B
);
217 toposort
.node(cell
->name
);
218 bit_users
[A
].insert(cell
->name
);
219 bit_users
[B
].insert(cell
->name
);
220 bit_drivers
[Y
].insert(cell
->name
);
224 if (cell
->type
== "$__ABC9_FF_" &&
225 // The presence of an abc9_mergeability attribute indicates
226 // that we do want to pass this flop to ABC
227 cell
->attributes
.count("\\abc9_mergeability"))
229 SigBit D
= sigmap(cell
->getPort("\\D").as_bit());
230 SigBit Q
= sigmap(cell
->getPort("\\Q").as_bit());
231 unused_bits
.erase(D
);
232 undriven_bits
.erase(Q
);
234 auto r
YS_ATTRIBUTE(unused
) = ff_bits
.insert(std::make_pair(D
, cell
));
235 log_assert(r
.second
);
239 RTLIL::Module
* inst_module
= module
->design
->module(cell
->type
);
241 bool abc9_box
= inst_module
->attributes
.count("\\abc9_box_id");
242 bool abc9_flop
= inst_module
->get_bool_attribute("\\abc9_flop");
243 if (abc9_box
&& cell
->get_bool_attribute("\\abc9_keep"))
246 for (const auto &conn
: cell
->connections()) {
247 auto port_wire
= inst_module
->wire(conn
.first
);
250 // Ignore inout for the sake of topographical ordering
251 if (port_wire
->port_input
&& !port_wire
->port_output
)
252 for (auto bit
: sigmap(conn
.second
))
253 bit_users
[bit
].insert(cell
->name
);
254 if (port_wire
->port_output
)
255 for (auto bit
: sigmap(conn
.second
))
256 bit_drivers
[bit
].insert(cell
->name
);
262 if (port_wire
->port_output
) {
264 auto it
= port_wire
->attributes
.find("\\abc9_arrival");
265 if (it
!= port_wire
->attributes
.end()) {
266 if (it
->second
.flags
!= 0)
267 log_error("Attribute 'abc9_arrival' on port '%s' of module '%s' is not an integer.\n", log_id(port_wire
), log_id(cell
->type
));
268 arrival
= it
->second
.as_int();
271 for (auto bit
: sigmap(conn
.second
))
272 arrival_times
[bit
] = arrival
;
277 abc9_box_seen
= true;
278 toposort
.node(cell
->name
);
283 bool cell_known
= inst_module
|| cell
->known();
284 for (const auto &c
: cell
->connections()) {
285 if (c
.second
.is_fully_const()) continue;
286 auto port_wire
= inst_module
? inst_module
->wire(c
.first
) : nullptr;
287 auto is_input
= (port_wire
&& port_wire
->port_input
) || !cell_known
|| cell
->input(c
.first
);
288 auto is_output
= (port_wire
&& port_wire
->port_output
) || !cell_known
|| cell
->output(c
.first
);
289 if (!is_input
&& !is_output
)
290 log_error("Connection '%s' on cell '%s' (type '%s') not recognised!\n", log_id(c
.first
), log_id(cell
), log_id(cell
->type
));
293 for (auto b
: c
.second
) {
296 if (!w
->port_output
|| !cell_known
) {
297 SigBit I
= sigmap(b
);
300 output_bits
.insert(b
);
305 //log_warning("Unsupported cell type: %s (%s)\n", log_id(cell->type), log_id(cell));
309 for (auto &it
: bit_users
)
310 if (bit_drivers
.count(it
.first
))
311 for (auto driver_cell
: bit_drivers
.at(it
.first
))
312 for (auto user_cell
: it
.second
)
313 toposort
.edge(driver_cell
, user_cell
);
316 toposort
.analyze_loops
= true;
318 bool no_loops
YS_ATTRIBUTE(unused
) = toposort
.sort();
321 for (auto &it
: toposort
.loops
) {
322 log(" loop %d\n", i
++);
323 for (auto cell_name
: it
) {
324 auto cell
= module
->cell(cell_name
);
326 log("\t%s (%s @ %s)\n", log_id(cell
), log_id(cell
->type
), cell
->get_src_attribute().c_str());
330 log_assert(no_loops
);
332 for (auto cell_name
: toposort
.sorted
) {
333 RTLIL::Cell
*cell
= module
->cell(cell_name
);
336 RTLIL::Module
* box_module
= module
->design
->module(cell
->type
);
337 if (!box_module
|| !box_module
->attributes
.count("\\abc9_box_id"))
340 bool blackbox
= box_module
->get_blackbox_attribute(true /* ignore_wb */);
342 auto r
= box_ports
.insert(cell
->type
);
344 // Make carry in the last PI, and carry out the last PO
345 // since ABC requires it this way
346 IdString carry_in
, carry_out
;
347 for (const auto &port_name
: box_module
->ports
) {
348 auto w
= box_module
->wire(port_name
);
350 if (w
->get_bool_attribute("\\abc9_carry")) {
352 if (carry_in
!= IdString())
353 log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(box_module
));
354 carry_in
= port_name
;
356 if (w
->port_output
) {
357 if (carry_out
!= IdString())
358 log_error("Module '%s' contains more than one 'abc9_carry' output port.\n", log_id(box_module
));
359 carry_out
= port_name
;
363 r
.first
->second
.push_back(port_name
);
366 if (carry_in
!= IdString() && carry_out
== IdString())
367 log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(box_module
));
368 if (carry_in
== IdString() && carry_out
!= IdString())
369 log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(box_module
));
370 if (carry_in
!= IdString()) {
371 r
.first
->second
.push_back(carry_in
);
372 r
.first
->second
.push_back(carry_out
);
376 // Fully pad all unused input connections of this box cell with S0
377 // Fully pad all undriven output connections of this box cell with anonymous wires
378 for (auto port_name
: r
.first
->second
) {
379 auto w
= box_module
->wire(port_name
);
381 auto it
= cell
->connections_
.find(port_name
);
384 if (it
!= cell
->connections_
.end()) {
385 if (GetSize(it
->second
) < GetSize(w
))
386 it
->second
.append(RTLIL::SigSpec(State::S0
, GetSize(w
)-GetSize(it
->second
)));
390 rhs
= RTLIL::SigSpec(State::S0
, GetSize(w
));
391 cell
->setPort(port_name
, rhs
);
395 SigBit I
= sigmap(b
);
400 alias_map
[b
] = State::S0
;
404 co_bits
.emplace_back(b
);
405 unused_bits
.erase(I
);
408 if (w
->port_output
) {
410 auto it
= cell
->connections_
.find(port_name
);
411 if (it
!= cell
->connections_
.end()) {
412 if (GetSize(it
->second
) < GetSize(w
))
413 it
->second
.append(module
->addWire(NEW_ID
, GetSize(w
)-GetSize(it
->second
)));
417 Wire
*wire
= module
->addWire(NEW_ID
, GetSize(w
));
419 wire
->set_bool_attribute(ID(abc9_padding
));
421 cell
->setPort(port_name
, rhs
);
424 for (const auto &b
: rhs
.bits()) {
425 SigBit O
= sigmap(b
);
428 ci_bits
.emplace_back(b
);
429 undriven_bits
.erase(O
);
434 // Connect <cell>.abc9_ff.Q (inserted by abc9_map.v) as the last input to the flop box
435 if (box_module
->get_bool_attribute("\\abc9_flop")) {
436 SigSpec rhs
= module
->wire(stringf("%s.abc9_ff.Q", cell
->name
.c_str()));
438 log_error("'%s.abc9_ff.Q' is not a wire present in module '%s'.\n", log_id(cell
), log_id(module
));
441 SigBit I
= sigmap(b
);
446 alias_map
[b
] = State::S0
;
450 co_bits
.emplace_back(b
);
451 unused_bits
.erase(I
);
455 box_list
.emplace_back(cell
);
458 // TODO: Free memory from toposort, bit_drivers, bit_users
461 for (auto bit
: input_bits
)
462 undriven_bits
.erase(bit
);
463 for (auto bit
: output_bits
)
464 unused_bits
.erase(sigmap(bit
));
465 for (auto bit
: unused_bits
)
466 undriven_bits
.erase(bit
);
468 // Make all undriven bits a primary input
469 for (auto bit
: undriven_bits
) {
470 input_bits
.insert(bit
);
471 undriven_bits
.erase(bit
);
475 struct sort_by_port_id
{
476 bool operator()(const RTLIL::SigBit
& a
, const RTLIL::SigBit
& b
) const {
477 return a
.wire
->port_id
< b
.wire
->port_id
||
478 (a
.wire
->port_id
== b
.wire
->port_id
&& a
.offset
< b
.offset
);
481 input_bits
.sort(sort_by_port_id());
482 output_bits
.sort(sort_by_port_id());
485 aig_map
[State::S0
] = 0;
486 aig_map
[State::S1
] = 1;
488 for (const auto &bit
: input_bits
) {
490 log_assert(!aig_map
.count(bit
));
491 aig_map
[bit
] = 2*aig_m
;
494 for (const auto &i
: ff_bits
) {
495 const Cell
*cell
= i
.second
;
496 const SigBit
&q
= sigmap(cell
->getPort("\\Q"));
498 log_assert(!aig_map
.count(q
));
499 aig_map
[q
] = 2*aig_m
;
502 for (auto &bit
: ci_bits
) {
504 log_assert(!aig_map
.count(bit
));
505 aig_map
[bit
] = 2*aig_m
;
508 for (auto bit
: co_bits
) {
509 ordered_outputs
[bit
] = aig_o
++;
510 aig_outputs
.push_back(bit2aig(bit
));
513 for (const auto &bit
: output_bits
) {
514 ordered_outputs
[bit
] = aig_o
++;
515 aig_outputs
.push_back(bit2aig(bit
));
518 for (auto &i
: ff_bits
) {
519 const SigBit
&d
= i
.first
;
521 aig_outputs
.push_back(aig_map
.at(d
));
525 void write_aiger(std::ostream
&f
, bool ascii_mode
)
528 int aig_obcj
= aig_obc
;
529 int aig_obcjf
= aig_obcj
;
531 log_assert(aig_m
== aig_i
+ aig_l
+ aig_a
);
532 log_assert(aig_obcjf
== GetSize(aig_outputs
));
534 f
<< stringf("%s %d %d %d %d %d", ascii_mode
? "aag" : "aig", aig_m
, aig_i
, aig_l
, aig_o
, aig_a
);
539 for (int i
= 0; i
< aig_i
; i
++)
540 f
<< stringf("%d\n", 2*i
+2);
542 for (int i
= 0; i
< aig_obc
; i
++)
543 f
<< stringf("%d\n", aig_outputs
.at(i
));
545 for (int i
= aig_obc
; i
< aig_obcj
; i
++)
548 for (int i
= aig_obc
; i
< aig_obcj
; i
++)
549 f
<< stringf("%d\n", aig_outputs
.at(i
));
551 for (int i
= aig_obcj
; i
< aig_obcjf
; i
++)
552 f
<< stringf("%d\n", aig_outputs
.at(i
));
554 for (int i
= 0; i
< aig_a
; i
++)
555 f
<< stringf("%d %d %d\n", 2*(aig_i
+aig_l
+i
)+2, aig_gates
.at(i
).first
, aig_gates
.at(i
).second
);
559 for (int i
= 0; i
< aig_obc
; i
++)
560 f
<< stringf("%d\n", aig_outputs
.at(i
));
562 for (int i
= aig_obc
; i
< aig_obcj
; i
++)
565 for (int i
= aig_obc
; i
< aig_obcj
; i
++)
566 f
<< stringf("%d\n", aig_outputs
.at(i
));
568 for (int i
= aig_obcj
; i
< aig_obcjf
; i
++)
569 f
<< stringf("%d\n", aig_outputs
.at(i
));
571 for (int i
= 0; i
< aig_a
; i
++) {
572 int lhs
= 2*(aig_i
+aig_l
+i
)+2;
573 int rhs0
= aig_gates
.at(i
).first
;
574 int rhs1
= aig_gates
.at(i
).second
;
575 int delta0
= lhs
- rhs0
;
576 int delta1
= rhs0
- rhs1
;
577 aiger_encode(f
, delta0
);
578 aiger_encode(f
, delta1
);
584 auto write_buffer
= [](std::stringstream
&buffer
, int i32
) {
585 int32_t i32_be
= to_big_endian(i32
);
586 buffer
.write(reinterpret_cast<const char*>(&i32_be
), sizeof(i32_be
));
588 std::stringstream h_buffer
;
589 auto write_h_buffer
= std::bind(write_buffer
, std::ref(h_buffer
), std::placeholders::_1
);
591 log_debug("ciNum = %d\n", GetSize(input_bits
) + GetSize(ff_bits
) + GetSize(ci_bits
));
592 write_h_buffer(input_bits
.size() + ff_bits
.size() + ci_bits
.size());
593 log_debug("coNum = %d\n", GetSize(output_bits
) + GetSize(ff_bits
) + GetSize(co_bits
));
594 write_h_buffer(output_bits
.size() + GetSize(ff_bits
) + GetSize(co_bits
));
595 log_debug("piNum = %d\n", GetSize(input_bits
) + GetSize(ff_bits
));
596 write_h_buffer(input_bits
.size() + ff_bits
.size());
597 log_debug("poNum = %d\n", GetSize(output_bits
) + GetSize(ff_bits
));
598 write_h_buffer(output_bits
.size() + ff_bits
.size());
599 log_debug("boxNum = %d\n", GetSize(box_list
));
600 write_h_buffer(box_list
.size());
602 auto write_buffer_float
= [](std::stringstream
&buffer
, float f32
) {
603 buffer
.write(reinterpret_cast<const char*>(&f32
), sizeof(f32
));
605 std::stringstream i_buffer
;
606 auto write_i_buffer
= std::bind(write_buffer_float
, std::ref(i_buffer
), std::placeholders::_1
);
607 for (auto bit
: input_bits
)
608 write_i_buffer(arrival_times
.at(bit
, 0));
609 //std::stringstream o_buffer;
610 //auto write_o_buffer = std::bind(write_buffer_float, std::ref(o_buffer), std::placeholders::_1);
611 //for (auto bit : output_bits)
612 // write_o_buffer(0);
614 if (!box_list
.empty() || !ff_bits
.empty()) {
615 RTLIL::Module
*holes_module
= module
->design
->addModule("$__holes__");
616 log_assert(holes_module
);
618 dict
<IdString
, std::tuple
<Cell
*,int,int,int>> cell_cache
;
622 for (auto cell
: box_list
) {
623 RTLIL::Module
* orig_box_module
= module
->design
->module(cell
->type
);
624 log_assert(orig_box_module
);
625 IdString derived_name
= orig_box_module
->derive(module
->design
, cell
->parameters
);
626 RTLIL::Module
* box_module
= module
->design
->module(derived_name
);
628 auto r
= cell_cache
.insert(derived_name
);
629 auto &v
= r
.first
->second
;
631 if (box_module
->has_processes())
632 Pass::call_on_module(module
->design
, box_module
, "proc");
634 int box_inputs
= 0, box_outputs
= 0;
635 if (box_module
->get_bool_attribute("\\whitebox")) {
636 auto holes_cell
= holes_module
->addCell(cell
->name
, derived_name
);
637 for (auto port_name
: box_ports
.at(cell
->type
)) {
638 RTLIL::Wire
*w
= box_module
->wire(port_name
);
640 log_assert(!w
->port_input
|| !w
->port_output
);
641 auto &conn
= holes_cell
->connections_
[port_name
];
643 for (int i
= 0; i
< GetSize(w
); i
++) {
645 RTLIL::Wire
*holes_wire
= holes_module
->wire(stringf("\\i%d", box_inputs
));
647 holes_wire
= holes_module
->addWire(stringf("\\i%d", box_inputs
));
648 holes_wire
->port_input
= true;
649 holes_wire
->port_id
= port_id
++;
650 holes_module
->ports
.push_back(holes_wire
->name
);
652 conn
.append(holes_wire
);
655 else if (w
->port_output
) {
656 box_outputs
+= GetSize(w
);
657 conn
= holes_module
->addWire(stringf("%s.%s", derived_name
.c_str(), log_id(port_name
)), GetSize(w
));
661 // For flops only, create an extra 1-bit input that drives a new wire
662 // called "<cell>.abc9_ff.Q" that is used below
663 if (box_module
->get_bool_attribute("\\abc9_flop")) {
665 Wire
*holes_wire
= holes_module
->wire(stringf("\\i%d", box_inputs
));
667 holes_wire
= holes_module
->addWire(stringf("\\i%d", box_inputs
));
668 holes_wire
->port_input
= true;
669 holes_wire
->port_id
= port_id
++;
670 holes_module
->ports
.push_back(holes_wire
->name
);
672 Wire
*Q
= holes_module
->addWire(stringf("%s.abc9_ff.Q", cell
->name
.c_str()));
673 holes_module
->connect(Q
, holes_wire
);
676 std::get
<0>(v
) = holes_cell
;
679 for (auto port_name
: box_ports
.at(cell
->type
)) {
680 RTLIL::Wire
*w
= box_module
->wire(port_name
);
682 log_assert(!w
->port_input
|| !w
->port_output
);
684 box_inputs
+= GetSize(w
);
685 else if (w
->port_output
)
686 box_outputs
+= GetSize(w
);
688 log_assert(std::get
<0>(v
) == nullptr);
691 std::get
<1>(v
) = box_inputs
;
692 std::get
<2>(v
) = box_outputs
;
693 std::get
<3>(v
) = box_module
->attributes
.at("\\abc9_box_id").as_int();
696 auto holes_cell
= std::get
<0>(v
);
697 for (auto port_name
: box_ports
.at(cell
->type
)) {
698 RTLIL::Wire
*w
= box_module
->wire(port_name
);
702 Wire
*holes_wire
= holes_module
->addWire(stringf("$abc%s.%s", cell
->name
.c_str(), log_id(port_name
)), GetSize(w
));
703 holes_wire
->port_output
= true;
704 holes_wire
->port_id
= port_id
++;
705 holes_module
->ports
.push_back(holes_wire
->name
);
706 if (holes_cell
) // whitebox
707 holes_module
->connect(holes_wire
, holes_cell
->getPort(port_name
));
709 holes_module
->connect(holes_wire
, Const(State::S0
, GetSize(w
)));
712 write_h_buffer(std::get
<1>(v
));
713 write_h_buffer(std::get
<2>(v
));
714 write_h_buffer(std::get
<3>(v
));
715 write_h_buffer(box_count
++);
718 std::stringstream r_buffer
;
719 auto write_r_buffer
= std::bind(write_buffer
, std::ref(r_buffer
), std::placeholders::_1
);
720 log_debug("flopNum = %d\n", GetSize(ff_bits
));
721 write_r_buffer(ff_bits
.size());
723 std::stringstream s_buffer
;
724 auto write_s_buffer
= std::bind(write_buffer
, std::ref(s_buffer
), std::placeholders::_1
);
725 write_s_buffer(ff_bits
.size());
727 for (const auto &i
: ff_bits
) {
728 const SigBit
&d
= i
.first
;
729 const Cell
*cell
= i
.second
;
731 int mergeability
= cell
->attributes
.at(ID(abc9_mergeability
)).as_int();
732 log_assert(mergeability
> 0);
733 write_r_buffer(mergeability
);
735 Const init
= cell
->attributes
.at(ID(abc9_init
));
736 log_assert(GetSize(init
) == 1);
737 if (init
== State::S1
)
739 else if (init
== State::S0
)
742 log_assert(init
== State::Sx
);
746 write_i_buffer(arrival_times
.at(d
, 0));
751 std::string buffer_str
= r_buffer
.str();
752 int32_t buffer_size_be
= to_big_endian(buffer_str
.size());
753 f
.write(reinterpret_cast<const char*>(&buffer_size_be
), sizeof(buffer_size_be
));
754 f
.write(buffer_str
.data(), buffer_str
.size());
757 buffer_str
= s_buffer
.str();
758 buffer_size_be
= to_big_endian(buffer_str
.size());
759 f
.write(reinterpret_cast<const char*>(&buffer_size_be
), sizeof(buffer_size_be
));
760 f
.write(buffer_str
.data(), buffer_str
.size());
765 // NB: fixup_ports() will sort ports by name
766 //holes_module->fixup_ports();
767 holes_module
->check();
769 // Cannot techmap/aigmap/check all lib_whitebox-es outside of write_xaiger
770 // since boxes may contain parameters in which case `flatten` would have
771 // created a new $paramod ...
772 Pass::call_on_module(holes_module
->design
, holes_module
, "flatten -wb; techmap; aigmap");
774 dict
<SigSpec
, SigSpec
> replace
;
775 for (auto it
= holes_module
->cells_
.begin(); it
!= holes_module
->cells_
.end(); ) {
776 auto cell
= it
->second
;
777 if (cell
->type
.in("$_DFF_N_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_",
778 "$_DFF_P_", "$_DFF_PN0_", "$_DFF_PN1", "$_DFF_PP0_", "$_DFF_PP1_")) {
779 SigBit D
= cell
->getPort("\\D");
780 SigBit Q
= cell
->getPort("\\Q");
781 // Remove the $_DFF_* cell from what needs to be a combinatorial box
782 it
= holes_module
->cells_
.erase(it
);
784 if (GetSize(Q
.wire
) == 1)
785 port
= holes_module
->wire(stringf("$abc%s", Q
.wire
->name
.c_str()));
787 port
= holes_module
->wire(stringf("$abc%s[%d]", Q
.wire
->name
.c_str(), Q
.offset
));
789 // Prepare to replace "assign <port> = $_DFF_*.Q;" with "assign <port> = $_DFF_*.D;"
790 // in order to extract just the combinatorial control logic that feeds the box
791 // (i.e. clock enable, synchronous reset, etc.)
792 replace
.insert(std::make_pair(Q
,D
));
793 // Since `flatten` above would have created wires named "<cell>.Q",
794 // extract the pre-techmap cell name
795 auto pos
= Q
.wire
->name
.str().rfind(".");
796 log_assert(pos
!= std::string::npos
);
797 IdString driver
= Q
.wire
->name
.substr(0, pos
);
798 // And drive the signal that was previously driven by "DFF.Q" (typically
799 // used to implement clock-enable functionality) with the "<cell>.abc9_ff.Q"
800 // wire (which itself is driven by an input port) we inserted above
801 Wire
*currQ
= holes_module
->wire(stringf("%s.abc9_ff.Q", driver
.c_str()));
803 holes_module
->connect(Q
, currQ
);
806 else if (!cell
->type
.in("$_NOT_", "$_AND_"))
807 log_error("Whitebox contents cannot be represented as AIG. Please verify whiteboxes are synthesisable.\n");
811 SigMap
holes_sigmap(holes_module
);
812 for (auto &conn
: holes_module
->connections_
) {
813 auto it
= replace
.find(sigmap(conn
.second
));
814 if (it
!= replace
.end())
815 conn
.second
= it
->second
;
818 // Move into a new (temporary) design so that "clean" will only
819 // operate (and run checks on) this one module
820 RTLIL::Design
*holes_design
= new RTLIL::Design
;
821 module
->design
->modules_
.erase(holes_module
->name
);
822 holes_design
->add(holes_module
);
823 Pass::call(holes_design
, "opt -purge");
825 std::stringstream a_buffer
;
826 XAigerWriter
writer(holes_module
, true /* holes_mode */);
827 writer
.write_aiger(a_buffer
, false /*ascii_mode*/);
831 std::string buffer_str
= a_buffer
.str();
832 int32_t buffer_size_be
= to_big_endian(buffer_str
.size());
833 f
.write(reinterpret_cast<const char*>(&buffer_size_be
), sizeof(buffer_size_be
));
834 f
.write(buffer_str
.data(), buffer_str
.size());
841 std::string buffer_str
= h_buffer
.str();
842 int32_t buffer_size_be
= to_big_endian(buffer_str
.size());
843 f
.write(reinterpret_cast<const char*>(&buffer_size_be
), sizeof(buffer_size_be
));
844 f
.write(buffer_str
.data(), buffer_str
.size());
847 buffer_str
= i_buffer
.str();
848 buffer_size_be
= to_big_endian(buffer_str
.size());
849 f
.write(reinterpret_cast<const char*>(&buffer_size_be
), sizeof(buffer_size_be
));
850 f
.write(buffer_str
.data(), buffer_str
.size());
852 //buffer_str = o_buffer.str();
853 //buffer_size_be = to_big_endian(buffer_str.size());
854 //f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be));
855 //f.write(buffer_str.data(), buffer_str.size());
857 f
<< stringf("Generated by %s\n", yosys_version_str
);
859 module
->design
->scratchpad_set_int("write_xaiger.num_ands", and_map
.size());
860 module
->design
->scratchpad_set_int("write_xaiger.num_wires", aig_map
.size());
861 module
->design
->scratchpad_set_int("write_xaiger.num_inputs", input_bits
.size());
862 module
->design
->scratchpad_set_int("write_xaiger.num_outputs", output_bits
.size());
865 void write_map(std::ostream
&f
)
867 dict
<int, string
> input_lines
;
868 dict
<int, string
> output_lines
;
870 for (auto wire
: module
->wires())
872 SigSpec sig
= sigmap(wire
);
874 for (int i
= 0; i
< GetSize(wire
); i
++)
876 RTLIL::SigBit
b(wire
, i
);
877 if (input_bits
.count(b
)) {
878 int a
= aig_map
.at(b
);
879 log_assert((a
& 1) == 0);
880 input_lines
[a
] += stringf("input %d %d %s\n", (a
>> 1)-1, i
, log_id(wire
));
883 if (output_bits
.count(b
)) {
884 int o
= ordered_outputs
.at(b
);
886 output_lines
[o
] += stringf("output %d %d %s %d\n", o
- GetSize(co_bits
), i
, log_id(wire
), init
);
893 for (auto &it
: input_lines
)
895 log_assert(input_lines
.size() == input_bits
.size());
898 for (auto cell
: box_list
)
899 f
<< stringf("box %d %d %s\n", box_count
++, 0, log_id(cell
->name
));
902 for (auto &it
: output_lines
)
904 log_assert(output_lines
.size() == output_bits
.size());
908 struct XAigerBackend
: public Backend
{
909 XAigerBackend() : Backend("xaiger", "write design to XAIGER file") { }
910 void help() YS_OVERRIDE
912 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
914 log(" write_xaiger [options] [filename]\n");
916 log("Write the top module (according to the (* top *) attribute or if only one module\n");
917 log("is currently selected) to an XAIGER file. Any non $_NOT_, $_AND_, $_ABC9_FF_, or");
918 log("non (* abc9_box_id *) cells will be converted into psuedo-inputs and\n");
919 log("pseudo-outputs.\n");
922 log(" write ASCII version of AIGER format\n");
924 log(" -map <filename>\n");
925 log(" write an extra file with port and box symbols\n");
928 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
930 bool ascii_mode
= false;
931 std::string map_filename
;
933 log_header(design
, "Executing XAIGER backend.\n");
936 for (argidx
= 1; argidx
< args
.size(); argidx
++)
938 if (args
[argidx
] == "-ascii") {
942 if (map_filename
.empty() && args
[argidx
] == "-map" && argidx
+1 < args
.size()) {
943 map_filename
= args
[++argidx
];
948 extra_args(f
, filename
, args
, argidx
, !ascii_mode
);
950 Module
*top_module
= design
->top_module();
952 if (top_module
== nullptr)
953 log_error("Can't find top module in current design!\n");
955 if (!design
->selected_whole_module(top_module
))
956 log_cmd_error("Can't handle partially selected module %s!\n", log_id(top_module
));
958 if (!top_module
->processes
.empty())
959 log_error("Found unmapped processes in module %s: unmapped processes are not supported in XAIGER backend!\n", log_id(top_module
));
960 if (!top_module
->memories
.empty())
961 log_error("Found unmapped memories in module %s: unmapped memories are not supported in XAIGER backend!\n", log_id(top_module
));
963 XAigerWriter
writer(top_module
);
964 writer
.write_aiger(*f
, ascii_mode
);
966 if (!map_filename
.empty()) {
968 mapf
.open(map_filename
.c_str(), std::ofstream::trunc
);
970 log_error("Can't open file `%s' for writing: %s\n", map_filename
.c_str(), strerror(errno
));
971 writer
.write_map(mapf
);
976 PRIVATE_NAMESPACE_END