869b741a6507e57684b68f431e880e102f264c35
[yosys.git] / backends / aiger / xaiger.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 * 2019 Eddie Hung <eddie@fpgeh.com>
6 *
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.
10 *
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.
18 *
19 */
20
21 // https://stackoverflow.com/a/46137633
22 #ifdef _MSC_VER
23 #include <stdlib.h>
24 #define __builtin_bswap32 _byteswap_ulong
25 #elif defined(__APPLE__)
26 #include <libkern/OSByteOrder.h>
27 #define __builtin_bswap32 OSSwapInt32
28 #elif !defined(__GNUC__)
29 #include <cstdint>
30 inline uint32_t __builtin_bswap32(uint32_t x)
31 {
32 // https://stackoverflow.com/a/27796212
33 register uint32_t value = number_to_be_reversed;
34 uint8_t lolo = (value >> 0) & 0xFF;
35 uint8_t lohi = (value >> 8) & 0xFF;
36 uint8_t hilo = (value >> 16) & 0xFF;
37 uint8_t hihi = (value >> 24) & 0xFF;
38 return (hihi << 24)
39 | (hilo << 16)
40 | (lohi << 8)
41 | (lolo << 0);
42 }
43 #endif
44
45 #include "kernel/yosys.h"
46 #include "kernel/sigtools.h"
47 #include "kernel/utils.h"
48
49 USING_YOSYS_NAMESPACE
50 PRIVATE_NAMESPACE_BEGIN
51
52 inline int32_t to_big_endian(int32_t i32) {
53 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
54 return __builtin_bswap32(i32);
55 #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
56 return i32;
57 #else
58 #error "Unknown endianness"
59 #endif
60 }
61
62 void aiger_encode(std::ostream &f, int x)
63 {
64 log_assert(x >= 0);
65
66 while (x & ~0x7f) {
67 f.put((x & 0x7f) | 0x80);
68 x = x >> 7;
69 }
70
71 f.put(x);
72 }
73
74 struct XAigerWriter
75 {
76 Module *module;
77 SigMap sigmap;
78
79 pool<SigBit> input_bits, output_bits;
80 dict<SigBit, SigBit> not_map, alias_map;
81 dict<SigBit, pair<SigBit, SigBit>> and_map;
82 vector<std::tuple<SigBit,RTLIL::Cell*,RTLIL::IdString,int>> ci_bits;
83 vector<std::tuple<SigBit,RTLIL::Cell*,RTLIL::IdString,int,int>> co_bits;
84
85 vector<pair<int, int>> aig_gates;
86 vector<int> aig_outputs;
87 int aig_m = 0, aig_i = 0, aig_l = 0, aig_o = 0, aig_a = 0;
88
89 dict<SigBit, int> aig_map;
90 dict<SigBit, int> ordered_outputs;
91
92 vector<Cell*> box_list;
93 bool omode = false;
94
95 int mkgate(int a0, int a1)
96 {
97 aig_m++, aig_a++;
98 aig_gates.push_back(a0 > a1 ? make_pair(a0, a1) : make_pair(a1, a0));
99 return 2*aig_m;
100 }
101
102 int bit2aig(SigBit bit)
103 {
104 auto it = aig_map.find(bit);
105 if (it != aig_map.end()) {
106 log_assert(it->second >= 0);
107 return it->second;
108 }
109
110 // NB: Cannot use iterator returned from aig_map.insert()
111 // since this function is called recursively
112
113 int a = -1;
114 if (not_map.count(bit)) {
115 a = bit2aig(not_map.at(bit)) ^ 1;
116 } else
117 if (and_map.count(bit)) {
118 auto args = and_map.at(bit);
119 int a0 = bit2aig(args.first);
120 int a1 = bit2aig(args.second);
121 a = mkgate(a0, a1);
122 } else
123 if (alias_map.count(bit)) {
124 a = bit2aig(alias_map.at(bit));
125 }
126
127 if (bit == State::Sx || bit == State::Sz) {
128 log_debug("Design contains 'x' or 'z' bits. Treating as 1'b0.\n");
129 a = aig_map.at(State::S0);
130 }
131
132 log_assert(a >= 0);
133 aig_map[bit] = a;
134 return a;
135 }
136
137 XAigerWriter(Module *module, bool holes_mode=false) : module(module), sigmap(module)
138 {
139 pool<SigBit> undriven_bits;
140 pool<SigBit> unused_bits;
141 pool<SigBit> keep_bits;
142
143 // promote public wires
144 for (auto wire : module->wires())
145 if (wire->name[0] == '\\')
146 sigmap.add(wire);
147
148 // promote input wires
149 for (auto wire : module->wires())
150 if (wire->port_input)
151 sigmap.add(wire);
152
153 // promote output wires
154 for (auto wire : module->wires())
155 if (wire->port_output)
156 sigmap.add(wire);
157
158 for (auto wire : module->wires())
159 {
160 bool keep = wire->attributes.count("\\keep");
161
162 for (int i = 0; i < GetSize(wire); i++)
163 {
164 SigBit wirebit(wire, i);
165 SigBit bit = sigmap(wirebit);
166
167 if (bit.wire) {
168 undriven_bits.insert(bit);
169 unused_bits.insert(bit);
170 }
171
172 if (keep)
173 keep_bits.insert(bit);
174
175 if (wire->port_input || keep) {
176 if (bit != wirebit)
177 alias_map[bit] = wirebit;
178 input_bits.insert(wirebit);
179 }
180
181 if (wire->port_output || keep) {
182 if (bit != RTLIL::Sx) {
183 if (bit != wirebit)
184 alias_map[wirebit] = bit;
185 output_bits.insert(wirebit);
186 }
187 else
188 log_debug("Skipping PO '%s' driven by 1'bx\n", log_signal(wirebit));
189 }
190 }
191 }
192
193 for (auto bit : input_bits)
194 undriven_bits.erase(sigmap(bit));
195 for (auto bit : output_bits)
196 if (!bit.wire->port_input)
197 unused_bits.erase(bit);
198
199 // TODO: Speed up toposort -- ultimately we care about
200 // box ordering, but not individual AIG cells
201 dict<SigBit, pool<IdString>> bit_drivers, bit_users;
202 TopoSort<IdString, RTLIL::sort_by_id_str> toposort;
203 bool abc_box_seen = false;
204
205 for (auto cell : module->selected_cells()) {
206 if (cell->type == "$_NOT_")
207 {
208 SigBit A = sigmap(cell->getPort("\\A").as_bit());
209 SigBit Y = sigmap(cell->getPort("\\Y").as_bit());
210 unused_bits.erase(A);
211 undriven_bits.erase(Y);
212 not_map[Y] = A;
213 if (!holes_mode) {
214 toposort.node(cell->name);
215 bit_users[A].insert(cell->name);
216 bit_drivers[Y].insert(cell->name);
217 }
218 continue;
219 }
220
221 if (cell->type == "$_AND_")
222 {
223 SigBit A = sigmap(cell->getPort("\\A").as_bit());
224 SigBit B = sigmap(cell->getPort("\\B").as_bit());
225 SigBit Y = sigmap(cell->getPort("\\Y").as_bit());
226 unused_bits.erase(A);
227 unused_bits.erase(B);
228 undriven_bits.erase(Y);
229 and_map[Y] = make_pair(A, B);
230 if (!holes_mode) {
231 toposort.node(cell->name);
232 bit_users[A].insert(cell->name);
233 bit_users[B].insert(cell->name);
234 bit_drivers[Y].insert(cell->name);
235 }
236 continue;
237 }
238
239 log_assert(!holes_mode);
240
241 RTLIL::Module* inst_module = module->design->module(cell->type);
242 if (inst_module && inst_module->attributes.count("\\abc_box_id")) {
243 abc_box_seen = true;
244
245 if (!holes_mode) {
246 toposort.node(cell->name);
247 for (const auto &conn : cell->connections()) {
248 if (cell->input(conn.first)) {
249 // Ignore inout for the sake of topographical ordering
250 if (cell->output(conn.first)) continue;
251 for (auto bit : sigmap(conn.second))
252 bit_users[bit].insert(cell->name);
253 }
254
255 if (cell->output(conn.first))
256 for (auto bit : sigmap(conn.second))
257 bit_drivers[bit].insert(cell->name);
258 }
259 }
260 }
261 else {
262 bool cell_known = cell->known();
263 for (const auto &c : cell->connections()) {
264 if (c.second.is_fully_const()) continue;
265 auto is_input = !cell_known || cell->input(c.first);
266 auto is_output = !cell_known || cell->output(c.first);
267 if (!is_input && !is_output)
268 log_error("Connection '%s' on cell '%s' (type '%s') not recognised!\n", log_id(c.first), log_id(cell), log_id(cell->type));
269
270 if (is_input) {
271 for (auto b : c.second.bits()) {
272 Wire *w = b.wire;
273 if (!w) continue;
274 if (!w->port_output || !cell_known) {
275 SigBit I = sigmap(b);
276 if (I != b)
277 alias_map[b] = I;
278 output_bits.insert(b);
279 unused_bits.erase(b);
280
281 if (!cell_known)
282 keep_bits.insert(b);
283 }
284 }
285 }
286 if (is_output) {
287 for (auto b : c.second.bits()) {
288 Wire *w = b.wire;
289 if (!w) continue;
290 input_bits.insert(b);
291 SigBit O = sigmap(b);
292 if (O != b)
293 alias_map[O] = b;
294 undriven_bits.erase(O);
295 }
296 }
297 }
298 }
299
300 //log_warning("Unsupported cell type: %s (%s)\n", log_id(cell->type), log_id(cell));
301 }
302
303 if (abc_box_seen) {
304 for (auto &it : bit_users)
305 if (bit_drivers.count(it.first))
306 for (auto driver_cell : bit_drivers.at(it.first))
307 for (auto user_cell : it.second)
308 toposort.edge(driver_cell, user_cell);
309
310 #if 0
311 toposort.analyze_loops = true;
312 #endif
313 bool no_loops = toposort.sort();
314 #if 0
315 unsigned i = 0;
316 for (auto &it : toposort.loops) {
317 log(" loop %d\n", i++);
318 for (auto cell_name : it) {
319 auto cell = module->cell(cell_name);
320 log_assert(cell);
321 log("\t%s (%s @ %s)\n", log_id(cell), log_id(cell->type), cell->get_src_attribute().c_str());
322 }
323 }
324 #endif
325 log_assert(no_loops);
326
327 pool<IdString> seen_boxes;
328 for (auto cell_name : toposort.sorted) {
329 RTLIL::Cell *cell = module->cell(cell_name);
330 log_assert(cell);
331
332 RTLIL::Module* box_module = module->design->module(cell->type);
333 if (!box_module || !box_module->attributes.count("\\abc_box_id"))
334 continue;
335
336 if (seen_boxes.insert(cell->type).second) {
337 auto it = box_module->attributes.find("\\abc_carry");
338 if (it != box_module->attributes.end()) {
339 RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr;
340 auto carry_in_out = it->second.decode_string();
341 auto pos = carry_in_out.find(',');
342 if (pos == std::string::npos)
343 log_error("'abc_carry' attribute on module '%s' does not contain ','.\n", log_id(cell->type));
344 auto carry_in_name = RTLIL::escape_id(carry_in_out.substr(0, pos));
345 carry_in = box_module->wire(carry_in_name);
346 if (!carry_in || !carry_in->port_input)
347 log_error("'abc_carry' on module '%s' contains '%s' which does not exist or is not an input port.\n", log_id(cell->type), carry_in_name.c_str());
348
349 auto carry_out_name = RTLIL::escape_id(carry_in_out.substr(pos+1));
350 carry_out = box_module->wire(carry_out_name);
351 if (!carry_out || !carry_out->port_output)
352 log_error("'abc_carry' on module '%s' contains '%s' which does not exist or is not an output port.\n", log_id(cell->type), carry_out_name.c_str());
353
354 auto &ports = box_module->ports;
355 for (auto jt = ports.begin(); jt != ports.end(); ) {
356 RTLIL::Wire* w = box_module->wire(*jt);
357 log_assert(w);
358 if (w == carry_in || w == carry_out) {
359 jt = ports.erase(jt);
360 continue;
361 }
362 if (w->port_id > carry_in->port_id)
363 --w->port_id;
364 if (w->port_id > carry_out->port_id)
365 --w->port_id;
366 log_assert(w->port_input || w->port_output);
367 log_assert(ports[w->port_id-1] == w->name);
368 ++jt;
369 }
370 ports.push_back(carry_in->name);
371 carry_in->port_id = ports.size();
372 ports.push_back(carry_out->name);
373 carry_out->port_id = ports.size();
374 }
375 }
376
377 // Fully pad all unused input connections of this box cell with S0
378 // Fully pad all undriven output connections of this box cell with anonymous wires
379 // NB: Assume box_module->ports are sorted alphabetically
380 // (as RTLIL::Module::fixup_ports() would do)
381 for (const auto &port_name : box_module->ports) {
382 RTLIL::Wire* w = box_module->wire(port_name);
383 log_assert(w);
384 auto it = cell->connections_.find(port_name);
385 if (w->port_input) {
386 RTLIL::SigSpec rhs;
387 if (it != cell->connections_.end()) {
388 if (GetSize(it->second) < GetSize(w))
389 it->second.append(RTLIL::SigSpec(RTLIL::S0, GetSize(w)-GetSize(it->second)));
390 rhs = it->second;
391 }
392 else {
393 rhs = RTLIL::SigSpec(RTLIL::S0, GetSize(w));
394 cell->setPort(port_name, rhs);
395 }
396
397 int offset = 0;
398 for (auto b : rhs.bits()) {
399 SigBit I = sigmap(b);
400 if (b == RTLIL::Sx)
401 b = RTLIL::S0;
402 else if (I != b) {
403 if (I == RTLIL::Sx)
404 alias_map[b] = RTLIL::S0;
405 else
406 alias_map[b] = I;
407 }
408 co_bits.emplace_back(b, cell, port_name, offset++, 0);
409 unused_bits.erase(b);
410 }
411 }
412 if (w->port_output) {
413 RTLIL::SigSpec rhs;
414 auto it = cell->connections_.find(w->name);
415 if (it != cell->connections_.end()) {
416 if (GetSize(it->second) < GetSize(w))
417 it->second.append(module->addWire(NEW_ID, GetSize(w)-GetSize(it->second)));
418 rhs = it->second;
419 }
420 else {
421 rhs = module->addWire(NEW_ID, GetSize(w));
422 cell->setPort(port_name, rhs);
423 }
424
425 int offset = 0;
426 for (const auto &b : rhs.bits()) {
427 ci_bits.emplace_back(b, cell, port_name, offset++);
428 SigBit O = sigmap(b);
429 if (O != b)
430 alias_map[O] = b;
431 undriven_bits.erase(O);
432
433 auto jt = input_bits.find(b);
434 if (jt != input_bits.end()) {
435 log_assert(keep_bits.count(O));
436 input_bits.erase(b);
437 }
438 }
439 }
440 }
441 box_list.emplace_back(cell);
442 }
443
444 // TODO: Free memory from toposort, bit_drivers, bit_users
445 }
446
447 for (auto bit : input_bits) {
448 if (!output_bits.count(bit))
449 continue;
450 RTLIL::Wire *wire = bit.wire;
451 // If encountering an inout port, or a keep-ed wire, then create a new wire
452 // with $inout.out suffix, make it a PO driven by the existing inout, and
453 // inherit existing inout's drivers
454 if ((wire->port_input && wire->port_output && !undriven_bits.count(bit))
455 || keep_bits.count(bit)) {
456 RTLIL::IdString wire_name = wire->name.str() + "$inout.out";
457 RTLIL::Wire *new_wire = module->wire(wire_name);
458 if (!new_wire)
459 new_wire = module->addWire(wire_name, GetSize(wire));
460 SigBit new_bit(new_wire, bit.offset);
461 module->connect(new_bit, bit);
462 if (not_map.count(bit)) {
463 auto a = not_map.at(bit);
464 not_map[new_bit] = a;
465 }
466 else if (and_map.count(bit)) {
467 auto a = and_map.at(bit);
468 and_map[new_bit] = a;
469 }
470 else if (alias_map.count(bit)) {
471 auto a = alias_map.at(bit);
472 alias_map[new_bit] = a;
473 }
474 else
475 alias_map[new_bit] = bit;
476 output_bits.erase(bit);
477 output_bits.insert(new_bit);
478 }
479 }
480
481 for (auto bit : unused_bits)
482 undriven_bits.erase(bit);
483
484 if (!undriven_bits.empty() && !holes_mode) {
485 undriven_bits.sort();
486 for (auto bit : undriven_bits) {
487 log_warning("Treating undriven bit %s.%s like $anyseq.\n", log_id(module), log_signal(bit));
488 input_bits.insert(bit);
489 }
490 log_warning("Treating a total of %d undriven bits in %s like $anyseq.\n", GetSize(undriven_bits), log_id(module));
491 }
492
493 if (holes_mode) {
494 struct sort_by_port_id {
495 bool operator()(const RTLIL::SigBit& a, const RTLIL::SigBit& b) const {
496 return a.wire->port_id < b.wire->port_id;
497 }
498 };
499 input_bits.sort(sort_by_port_id());
500 output_bits.sort(sort_by_port_id());
501 }
502 else {
503 input_bits.sort();
504 output_bits.sort();
505 }
506
507 not_map.sort();
508 and_map.sort();
509
510 aig_map[State::S0] = 0;
511 aig_map[State::S1] = 1;
512
513 for (auto bit : input_bits) {
514 aig_m++, aig_i++;
515 log_assert(!aig_map.count(bit));
516 aig_map[bit] = 2*aig_m;
517 }
518
519 for (auto &c : ci_bits) {
520 RTLIL::SigBit bit = std::get<0>(c);
521 aig_m++, aig_i++;
522 aig_map[bit] = 2*aig_m;
523 }
524
525 for (auto &c : co_bits) {
526 RTLIL::SigBit bit = std::get<0>(c);
527 std::get<4>(c) = ordered_outputs[bit] = aig_o++;
528 aig_outputs.push_back(bit2aig(bit));
529 }
530
531 for (auto bit : output_bits) {
532 ordered_outputs[bit] = aig_o++;
533 aig_outputs.push_back(bit2aig(bit));
534 }
535
536 if (output_bits.empty()) {
537 aig_o++;
538 aig_outputs.push_back(0);
539 omode = true;
540 }
541 }
542
543 void write_aiger(std::ostream &f, bool ascii_mode)
544 {
545 int aig_obc = aig_o;
546 int aig_obcj = aig_obc;
547 int aig_obcjf = aig_obcj;
548
549 log_assert(aig_m == aig_i + aig_l + aig_a);
550 log_assert(aig_obcjf == GetSize(aig_outputs));
551
552 f << stringf("%s %d %d %d %d %d", ascii_mode ? "aag" : "aig", aig_m, aig_i, aig_l, aig_o, aig_a);
553 f << stringf("\n");
554
555 if (ascii_mode)
556 {
557 for (int i = 0; i < aig_i; i++)
558 f << stringf("%d\n", 2*i+2);
559
560 for (int i = 0; i < aig_obc; i++)
561 f << stringf("%d\n", aig_outputs.at(i));
562
563 for (int i = aig_obc; i < aig_obcj; i++)
564 f << stringf("1\n");
565
566 for (int i = aig_obc; i < aig_obcj; i++)
567 f << stringf("%d\n", aig_outputs.at(i));
568
569 for (int i = aig_obcj; i < aig_obcjf; i++)
570 f << stringf("%d\n", aig_outputs.at(i));
571
572 for (int i = 0; i < aig_a; i++)
573 f << stringf("%d %d %d\n", 2*(aig_i+aig_l+i)+2, aig_gates.at(i).first, aig_gates.at(i).second);
574 }
575 else
576 {
577 for (int i = 0; i < aig_obc; i++)
578 f << stringf("%d\n", aig_outputs.at(i));
579
580 for (int i = aig_obc; i < aig_obcj; i++)
581 f << stringf("1\n");
582
583 for (int i = aig_obc; i < aig_obcj; i++)
584 f << stringf("%d\n", aig_outputs.at(i));
585
586 for (int i = aig_obcj; i < aig_obcjf; i++)
587 f << stringf("%d\n", aig_outputs.at(i));
588
589 for (int i = 0; i < aig_a; i++) {
590 int lhs = 2*(aig_i+aig_l+i)+2;
591 int rhs0 = aig_gates.at(i).first;
592 int rhs1 = aig_gates.at(i).second;
593 int delta0 = lhs - rhs0;
594 int delta1 = rhs0 - rhs1;
595 aiger_encode(f, delta0);
596 aiger_encode(f, delta1);
597 }
598 }
599
600 f << "c";
601
602 if (!box_list.empty()) {
603 auto write_buffer = [](std::stringstream &buffer, int i32) {
604 int32_t i32_be = to_big_endian(i32);
605 buffer.write(reinterpret_cast<const char*>(&i32_be), sizeof(i32_be));
606 };
607
608 std::stringstream h_buffer;
609 auto write_h_buffer = std::bind(write_buffer, std::ref(h_buffer), std::placeholders::_1);
610 write_h_buffer(1);
611 log_debug("ciNum = %zu\n", input_bits.size() + ci_bits.size());
612 write_h_buffer(input_bits.size() + ci_bits.size());
613 log_debug("coNum = %zu\n", output_bits.size() + co_bits.size());
614 write_h_buffer(output_bits.size() + co_bits.size());
615 log_debug("piNum = %zu\n", input_bits.size());
616 write_h_buffer(input_bits.size());
617 log_debug("poNum = %zu\n", output_bits.size());
618 write_h_buffer(output_bits.size());
619 log_debug("boxNum = %zu\n", box_list.size());
620 write_h_buffer(box_list.size());
621
622 RTLIL::Module *holes_module = nullptr;
623 holes_module = module->design->addModule("$__holes__");
624 log_assert(holes_module);
625
626 int port_id = 1;
627 int box_count = 0;
628 for (auto cell : box_list) {
629 RTLIL::Module* box_module = module->design->module(cell->type);
630 int box_inputs = 0, box_outputs = 0;
631 Cell *holes_cell = nullptr;
632 if (box_module->get_bool_attribute("\\whitebox")) {
633 holes_cell = holes_module->addCell(cell->name, cell->type);
634 holes_cell->parameters = cell->parameters;
635 }
636
637 // NB: Assume box_module->ports are sorted alphabetically
638 // (as RTLIL::Module::fixup_ports() would do)
639 for (const auto &port_name : box_module->ports) {
640 RTLIL::Wire *w = box_module->wire(port_name);
641 log_assert(w);
642 RTLIL::Wire *holes_wire;
643 RTLIL::SigSpec port_wire;
644 if (w->port_input) {
645 for (int i = 0; i < GetSize(w); i++) {
646 box_inputs++;
647 holes_wire = holes_module->wire(stringf("\\i%d", box_inputs));
648 if (!holes_wire) {
649 holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs));
650 holes_wire->port_input = true;
651 holes_wire->port_id = port_id++;
652 holes_module->ports.push_back(holes_wire->name);
653 }
654 if (holes_cell)
655 port_wire.append(holes_wire);
656 }
657 if (!port_wire.empty())
658 holes_cell->setPort(w->name, port_wire);
659 }
660 if (w->port_output) {
661 box_outputs += GetSize(w);
662 for (int i = 0; i < GetSize(w); i++) {
663 if (GetSize(w) == 1)
664 holes_wire = holes_module->addWire(stringf("%s.%s", cell->name.c_str(), w->name.c_str()));
665 else
666 holes_wire = holes_module->addWire(stringf("%s.%s[%d]", cell->name.c_str(), w->name.c_str(), i));
667 holes_wire->port_output = true;
668 holes_wire->port_id = port_id++;
669 holes_module->ports.push_back(holes_wire->name);
670 if (holes_cell)
671 port_wire.append(holes_wire);
672 else
673 holes_module->connect(holes_wire, RTLIL::S0);
674 }
675 if (!port_wire.empty())
676 holes_cell->setPort(w->name, port_wire);
677 }
678 }
679
680 write_h_buffer(box_inputs);
681 write_h_buffer(box_outputs);
682 write_h_buffer(box_module->attributes.at("\\abc_box_id").as_int());
683 write_h_buffer(box_count++);
684 }
685
686 f << "h";
687 std::string buffer_str = h_buffer.str();
688 int32_t buffer_size_be = to_big_endian(buffer_str.size());
689 f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be));
690 f.write(buffer_str.data(), buffer_str.size());
691
692 std::stringstream r_buffer;
693 auto write_r_buffer = std::bind(write_buffer, std::ref(r_buffer), std::placeholders::_1);
694 write_r_buffer(0);
695
696 f << "r";
697 buffer_str = r_buffer.str();
698 buffer_size_be = to_big_endian(buffer_str.size());
699 f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be));
700 f.write(buffer_str.data(), buffer_str.size());
701
702 if (holes_module) {
703 log_push();
704
705 // NB: fixup_ports() will sort ports by name
706 //holes_module->fixup_ports();
707 holes_module->check();
708
709 holes_module->design->selection_stack.emplace_back(false);
710 RTLIL::Selection& sel = holes_module->design->selection_stack.back();
711 sel.select(holes_module);
712
713 // TODO: Should not need to opt_merge if we only instantiate
714 // each box type once...
715 Pass::call(holes_module->design, "opt_merge -share_all");
716
717 Pass::call(holes_module->design, "flatten -wb");
718
719 // TODO: Should techmap/aigmap/check all lib_whitebox-es just once,
720 // instead of per write_xaiger call
721 Pass::call(holes_module->design, "techmap");
722 Pass::call(holes_module->design, "aigmap");
723 for (auto cell : holes_module->cells())
724 if (!cell->type.in("$_NOT_", "$_AND_"))
725 log_error("Whitebox contents cannot be represented as AIG. Please verify whiteboxes are synthesisable.\n");
726
727 Pass::call(holes_module->design, "clean -purge");
728
729 std::stringstream a_buffer;
730 XAigerWriter writer(holes_module, true /* holes_mode */);
731 writer.write_aiger(a_buffer, false /*ascii_mode*/);
732
733 holes_module->design->selection_stack.pop_back();
734
735 f << "a";
736 std::string buffer_str = a_buffer.str();
737 int32_t buffer_size_be = to_big_endian(buffer_str.size());
738 f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be));
739 f.write(buffer_str.data(), buffer_str.size());
740 holes_module->design->remove(holes_module);
741
742 log_pop();
743 }
744 }
745
746 f << stringf("Generated by %s\n", yosys_version_str);
747 }
748
749 void write_map(std::ostream &f, bool verbose_map)
750 {
751 dict<int, string> input_lines;
752 dict<int, string> output_lines;
753 dict<int, string> wire_lines;
754
755 for (auto wire : module->wires())
756 {
757 //if (!verbose_map && wire->name[0] == '$')
758 // continue;
759
760 SigSpec sig = sigmap(wire);
761
762 for (int i = 0; i < GetSize(wire); i++)
763 {
764 RTLIL::SigBit b(wire, i);
765 if (input_bits.count(b)) {
766 int a = aig_map.at(b);
767 log_assert((a & 1) == 0);
768 input_lines[a] += stringf("input %d %d %s\n", (a >> 1)-1, i, log_id(wire));
769 }
770
771 if (output_bits.count(b)) {
772 int o = ordered_outputs.at(b);
773 output_lines[o] += stringf("output %lu %d %s\n", o - co_bits.size(), i, log_id(wire));
774 continue;
775 }
776
777 if (verbose_map) {
778 if (aig_map.count(sig[i]) == 0)
779 continue;
780
781 int a = aig_map.at(sig[i]);
782 wire_lines[a] += stringf("wire %d %d %s\n", a, i, log_id(wire));
783 }
784 }
785 }
786
787 input_lines.sort();
788 for (auto &it : input_lines)
789 f << it.second;
790 log_assert(input_lines.size() == input_bits.size());
791
792 int box_count = 0;
793 for (auto cell : box_list)
794 f << stringf("box %d %d %s\n", box_count++, 0, log_id(cell->name));
795
796 output_lines.sort();
797 for (auto &it : output_lines)
798 f << it.second;
799 log_assert(output_lines.size() == output_bits.size());
800 if (omode && output_bits.empty())
801 f << "output " << output_lines.size() << " 0 $__dummy__\n";
802
803 wire_lines.sort();
804 for (auto &it : wire_lines)
805 f << it.second;
806 }
807 };
808
809 struct XAigerBackend : public Backend {
810 XAigerBackend() : Backend("xaiger", "write design to XAIGER file") { }
811 void help() YS_OVERRIDE
812 {
813 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
814 log("\n");
815 log(" write_xaiger [options] [filename]\n");
816 log("\n");
817 log("Write the current design to an XAIGER file. The design must be flattened and\n");
818 log("all unsupported cells will be converted into psuedo-inputs and pseudo-outputs.\n");
819 log("\n");
820 log(" -ascii\n");
821 log(" write ASCII version of AIGER format\n");
822 log("\n");
823 log(" -map <filename>\n");
824 log(" write an extra file with port and latch symbols\n");
825 log("\n");
826 log(" -vmap <filename>\n");
827 log(" like -map, but more verbose\n");
828 log("\n");
829 }
830 void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
831 {
832 bool ascii_mode = false;
833 bool verbose_map = false;
834 std::string map_filename;
835
836 log_header(design, "Executing XAIGER backend.\n");
837
838 size_t argidx;
839 for (argidx = 1; argidx < args.size(); argidx++)
840 {
841 if (args[argidx] == "-ascii") {
842 ascii_mode = true;
843 continue;
844 }
845 if (map_filename.empty() && args[argidx] == "-map" && argidx+1 < args.size()) {
846 map_filename = args[++argidx];
847 continue;
848 }
849 if (map_filename.empty() && args[argidx] == "-vmap" && argidx+1 < args.size()) {
850 map_filename = args[++argidx];
851 verbose_map = true;
852 continue;
853 }
854 break;
855 }
856 extra_args(f, filename, args, argidx);
857
858 Module *top_module = design->top_module();
859
860 if (top_module == nullptr)
861 log_error("Can't find top module in current design!\n");
862
863 XAigerWriter writer(top_module);
864 writer.write_aiger(*f, ascii_mode);
865
866 if (!map_filename.empty()) {
867 std::ofstream mapf;
868 mapf.open(map_filename.c_str(), std::ofstream::trunc);
869 if (mapf.fail())
870 log_error("Can't open file `%s' for writing: %s\n", map_filename.c_str(), strerror(errno));
871 writer.write_map(mapf, verbose_map);
872 }
873 }
874 } XAigerBackend;
875
876 PRIVATE_NAMESPACE_END