eabd870ab715540072db1e35c87fe887663b2c09
2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 // [[CITE]] Btor2 , BtorMC and Boolector 3.0
21 // Aina Niemetz, Mathias Preiner, Clifford Wolf, Armin Biere
22 // Computer Aided Verification - 30th International Conference, CAV 2018
23 // https://cs.stanford.edu/people/niemetz/publication/2018/niemetzpreinerwolfbiere-cav18/
25 #include "kernel/rtlil.h"
26 #include "kernel/register.h"
27 #include "kernel/sigtools.h"
28 #include "kernel/celltypes.h"
29 #include "kernel/log.h"
33 PRIVATE_NAMESPACE_BEGIN
39 RTLIL::Module
*module
;
45 int initstate_nid
= -1;
48 dict
<int, int> sorts_bv
;
50 // (<address-width>, <data-width>) => <sid>
51 dict
<pair
<int, int>, int> sorts_mem
;
53 // SigBit => (<nid>, <bitidx>)
54 dict
<SigBit
, pair
<int, int>> bit_nid
;
57 dict
<int, int> nid_width
;
60 dict
<SigSpec
, int> sig_nid
;
62 // bit to driving cell
63 dict
<SigBit
, Cell
*> bit_cell
;
66 dict
<Const
, int> consts
;
68 // ff inputs that need to be evaluated (<nid>, <ff_cell>)
69 vector
<pair
<int, Cell
*>> ff_todo
;
71 pool
<Cell
*> cell_recursion_guard
;
72 vector
<int> bad_properties
;
73 dict
<SigBit
, bool> initbits
;
74 pool
<Wire
*> statewires
;
75 pool
<string
> srcsymbols
;
77 string indent
, info_filename
;
78 vector
<string
> info_lines
;
79 dict
<int, int> info_clocks
;
81 void btorf(const char *fmt
, ...)
85 f
<< indent
<< vstringf(fmt
, ap
);
89 void infof(const char *fmt
, ...)
93 info_lines
.push_back(vstringf(fmt
, ap
));
98 string
getinfo(T
*obj
, bool srcsym
= false)
100 string infostr
= log_id(obj
);
101 if (obj
->attributes
.count("\\src")) {
102 string src
= obj
->attributes
.at("\\src").decode_string().c_str();
103 if (srcsym
&& infostr
[0] == '$') {
104 std::replace(src
.begin(), src
.end(), ' ', '_');
105 if (srcsymbols
.count(src
) || module
->count_id("\\" + src
)) {
106 for (int i
= 1;; i
++) {
107 string s
= stringf("%s-%d", src
.c_str(), i
);
108 if (!srcsymbols
.count(s
) && !module
->count_id("\\" + s
)) {
114 srcsymbols
.insert(src
);
117 infostr
+= " ; " + src
;
123 void btorf_push(const string
&id
)
126 f
<< indent
<< stringf(" ; begin %s\n", id
.c_str());
131 void btorf_pop(const string
&id
)
134 indent
= indent
.substr(4);
135 f
<< indent
<< stringf(" ; end %s\n", id
.c_str());
139 int get_bv_sid(int width
)
141 if (sorts_bv
.count(width
) == 0) {
142 int nid
= next_nid
++;
143 btorf("%d sort bitvec %d\n", nid
, width
);
144 sorts_bv
[width
] = nid
;
146 return sorts_bv
.at(width
);
149 int get_mem_sid(int abits
, int dbits
)
151 pair
<int, int> key(abits
, dbits
);
152 if (sorts_mem
.count(key
) == 0) {
153 int addr_sid
= get_bv_sid(abits
);
154 int data_sid
= get_bv_sid(dbits
);
155 int nid
= next_nid
++;
156 btorf("%d sort array %d %d\n", nid
, addr_sid
, data_sid
);
157 sorts_mem
[key
] = nid
;
159 return sorts_mem
.at(key
);
162 void add_nid_sig(int nid
, const SigSpec
&sig
)
165 f
<< indent
<< stringf("; %d %s\n", nid
, log_signal(sig
));
167 for (int i
= 0; i
< GetSize(sig
); i
++)
168 bit_nid
[sig
[i
]] = make_pair(nid
, i
);
171 nid_width
[nid
] = GetSize(sig
);
174 void export_cell(Cell
*cell
)
176 if (cell_recursion_guard
.count(cell
)) {
178 for (auto c
: cell_recursion_guard
)
179 cell_list
+= stringf("\n %s", log_id(c
));
180 log_error("Found topological loop while processing cell %s. Active cells:%s\n", log_id(cell
), cell_list
.c_str());
183 cell_recursion_guard
.insert(cell
);
184 btorf_push(log_id(cell
));
186 if (cell
->type
.in("$add", "$sub", "$mul", "$and", "$or", "$xor", "$xnor", "$shl", "$sshl", "$shr", "$sshr", "$shift", "$shiftx",
187 "$concat", "$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_"))
190 if (cell
->type
== "$add") btor_op
= "add";
191 if (cell
->type
== "$sub") btor_op
= "sub";
192 if (cell
->type
== "$mul") btor_op
= "mul";
193 if (cell
->type
.in("$shl", "$sshl")) btor_op
= "sll";
194 if (cell
->type
== "$shr") btor_op
= "srl";
195 if (cell
->type
== "$sshr") btor_op
= "sra";
196 if (cell
->type
.in("$shift", "$shiftx")) btor_op
= "shift";
197 if (cell
->type
.in("$and", "$_AND_")) btor_op
= "and";
198 if (cell
->type
.in("$or", "$_OR_")) btor_op
= "or";
199 if (cell
->type
.in("$xor", "$_XOR_")) btor_op
= "xor";
200 if (cell
->type
== "$concat") btor_op
= "concat";
201 if (cell
->type
== "$_NAND_") btor_op
= "nand";
202 if (cell
->type
== "$_NOR_") btor_op
= "nor";
203 if (cell
->type
.in("$xnor", "$_XNOR_")) btor_op
= "xnor";
204 log_assert(!btor_op
.empty());
206 int width
= GetSize(cell
->getPort(ID::Y
));
207 width
= std::max(width
, GetSize(cell
->getPort(ID::A
)));
208 width
= std::max(width
, GetSize(cell
->getPort(ID::B
)));
210 bool a_signed
= cell
->hasParam("\\A_SIGNED") ? cell
->getParam("\\A_SIGNED").as_bool() : false;
211 bool b_signed
= cell
->hasParam("\\B_SIGNED") ? cell
->getParam("\\B_SIGNED").as_bool() : false;
213 if (btor_op
== "shift" && !b_signed
)
216 if (cell
->type
.in("$shl", "$sshl", "$shr", "$sshr"))
219 if (cell
->type
== "$sshr" && !a_signed
)
222 int sid
= get_bv_sid(width
);
225 if (btor_op
== "shift")
227 int nid_a
= get_sig_nid(cell
->getPort(ID::A
), width
, false);
228 int nid_b
= get_sig_nid(cell
->getPort(ID::B
), width
, b_signed
);
230 int nid_r
= next_nid
++;
231 btorf("%d srl %d %d %d\n", nid_r
, sid
, nid_a
, nid_b
);
233 int nid_b_neg
= next_nid
++;
234 btorf("%d neg %d %d\n", nid_b_neg
, sid
, nid_b
);
236 int nid_l
= next_nid
++;
237 btorf("%d sll %d %d %d\n", nid_l
, sid
, nid_a
, nid_b_neg
);
239 int sid_bit
= get_bv_sid(1);
240 int nid_zero
= get_sig_nid(Const(0, width
));
241 int nid_b_ltz
= next_nid
++;
242 btorf("%d slt %d %d %d\n", nid_b_ltz
, sid_bit
, nid_b
, nid_zero
);
245 btorf("%d ite %d %d %d %d %s\n", nid
, sid
, nid_b_ltz
, nid_l
, nid_r
, getinfo(cell
).c_str());
249 int nid_a
= get_sig_nid(cell
->getPort(ID::A
), width
, a_signed
);
250 int nid_b
= get_sig_nid(cell
->getPort(ID::B
), width
, b_signed
);
253 btorf("%d %s %d %d %d %s\n", nid
, btor_op
.c_str(), sid
, nid_a
, nid_b
, getinfo(cell
).c_str());
256 SigSpec sig
= sigmap(cell
->getPort(ID::Y
));
258 if (GetSize(sig
) < width
) {
259 int sid
= get_bv_sid(GetSize(sig
));
260 int nid2
= next_nid
++;
261 btorf("%d slice %d %d %d 0\n", nid2
, sid
, nid
, GetSize(sig
)-1);
265 add_nid_sig(nid
, sig
);
269 if (cell
->type
.in("$div", "$mod"))
272 if (cell
->type
== "$div") btor_op
= "div";
273 if (cell
->type
== "$mod") btor_op
= "rem";
274 log_assert(!btor_op
.empty());
276 int width
= GetSize(cell
->getPort(ID::Y
));
277 width
= std::max(width
, GetSize(cell
->getPort(ID::A
)));
278 width
= std::max(width
, GetSize(cell
->getPort(ID::B
)));
280 bool a_signed
= cell
->hasParam("\\A_SIGNED") ? cell
->getParam("\\A_SIGNED").as_bool() : false;
281 bool b_signed
= cell
->hasParam("\\B_SIGNED") ? cell
->getParam("\\B_SIGNED").as_bool() : false;
283 int nid_a
= get_sig_nid(cell
->getPort(ID::A
), width
, a_signed
);
284 int nid_b
= get_sig_nid(cell
->getPort(ID::B
), width
, b_signed
);
286 int sid
= get_bv_sid(width
);
287 int nid
= next_nid
++;
288 btorf("%d %c%s %d %d %d %s\n", nid
, a_signed
|| b_signed
? 's' : 'u', btor_op
.c_str(), sid
, nid_a
, nid_b
, getinfo(cell
).c_str());
290 SigSpec sig
= sigmap(cell
->getPort(ID::Y
));
292 if (GetSize(sig
) < width
) {
293 int sid
= get_bv_sid(GetSize(sig
));
294 int nid2
= next_nid
++;
295 btorf("%d slice %d %d %d 0\n", nid2
, sid
, nid
, GetSize(sig
)-1);
299 add_nid_sig(nid
, sig
);
303 if (cell
->type
.in("$_ANDNOT_", "$_ORNOT_"))
305 int sid
= get_bv_sid(1);
306 int nid_a
= get_sig_nid(cell
->getPort(ID::A
));
307 int nid_b
= get_sig_nid(cell
->getPort(ID::B
));
309 int nid1
= next_nid
++;
310 int nid2
= next_nid
++;
312 if (cell
->type
== "$_ANDNOT_") {
313 btorf("%d not %d %d\n", nid1
, sid
, nid_b
);
314 btorf("%d and %d %d %d %s\n", nid2
, sid
, nid_a
, nid1
, getinfo(cell
).c_str());
317 if (cell
->type
== "$_ORNOT_") {
318 btorf("%d not %d %d\n", nid1
, sid
, nid_b
);
319 btorf("%d or %d %d %d %s\n", nid2
, sid
, nid_a
, nid1
, getinfo(cell
).c_str());
322 SigSpec sig
= sigmap(cell
->getPort(ID::Y
));
323 add_nid_sig(nid2
, sig
);
327 if (cell
->type
.in("$_OAI3_", "$_AOI3_"))
329 int sid
= get_bv_sid(1);
330 int nid_a
= get_sig_nid(cell
->getPort(ID::A
));
331 int nid_b
= get_sig_nid(cell
->getPort(ID::B
));
332 int nid_c
= get_sig_nid(cell
->getPort("\\C"));
334 int nid1
= next_nid
++;
335 int nid2
= next_nid
++;
336 int nid3
= next_nid
++;
338 if (cell
->type
== "$_OAI3_") {
339 btorf("%d or %d %d %d\n", nid1
, sid
, nid_a
, nid_b
);
340 btorf("%d and %d %d %d\n", nid2
, sid
, nid1
, nid_c
);
341 btorf("%d not %d %d %s\n", nid3
, sid
, nid2
, getinfo(cell
).c_str());
344 if (cell
->type
== "$_AOI3_") {
345 btorf("%d and %d %d %d\n", nid1
, sid
, nid_a
, nid_b
);
346 btorf("%d or %d %d %d\n", nid2
, sid
, nid1
, nid_c
);
347 btorf("%d not %d %d %s\n", nid3
, sid
, nid2
, getinfo(cell
).c_str());
350 SigSpec sig
= sigmap(cell
->getPort(ID::Y
));
351 add_nid_sig(nid3
, sig
);
355 if (cell
->type
.in("$_OAI4_", "$_AOI4_"))
357 int sid
= get_bv_sid(1);
358 int nid_a
= get_sig_nid(cell
->getPort(ID::A
));
359 int nid_b
= get_sig_nid(cell
->getPort(ID::B
));
360 int nid_c
= get_sig_nid(cell
->getPort("\\C"));
361 int nid_d
= get_sig_nid(cell
->getPort("\\D"));
363 int nid1
= next_nid
++;
364 int nid2
= next_nid
++;
365 int nid3
= next_nid
++;
366 int nid4
= next_nid
++;
368 if (cell
->type
== "$_OAI4_") {
369 btorf("%d or %d %d %d\n", nid1
, sid
, nid_a
, nid_b
);
370 btorf("%d or %d %d %d\n", nid2
, sid
, nid_c
, nid_d
);
371 btorf("%d and %d %d %d\n", nid3
, sid
, nid1
, nid2
);
372 btorf("%d not %d %d %s\n", nid4
, sid
, nid3
, getinfo(cell
).c_str());
375 if (cell
->type
== "$_AOI4_") {
376 btorf("%d and %d %d %d\n", nid1
, sid
, nid_a
, nid_b
);
377 btorf("%d and %d %d %d\n", nid2
, sid
, nid_c
, nid_d
);
378 btorf("%d or %d %d %d\n", nid3
, sid
, nid1
, nid2
);
379 btorf("%d not %d %d %s\n", nid4
, sid
, nid3
, getinfo(cell
).c_str());
382 SigSpec sig
= sigmap(cell
->getPort(ID::Y
));
383 add_nid_sig(nid4
, sig
);
387 if (cell
->type
.in("$lt", "$le", "$eq", "$eqx", "$ne", "$nex", "$ge", "$gt"))
390 if (cell
->type
== "$lt") btor_op
= "lt";
391 if (cell
->type
== "$le") btor_op
= "lte";
392 if (cell
->type
.in("$eq", "$eqx")) btor_op
= "eq";
393 if (cell
->type
.in("$ne", "$nex")) btor_op
= "neq";
394 if (cell
->type
== "$ge") btor_op
= "gte";
395 if (cell
->type
== "$gt") btor_op
= "gt";
396 log_assert(!btor_op
.empty());
399 width
= std::max(width
, GetSize(cell
->getPort(ID::A
)));
400 width
= std::max(width
, GetSize(cell
->getPort(ID::B
)));
402 bool a_signed
= cell
->hasParam("\\A_SIGNED") ? cell
->getParam("\\A_SIGNED").as_bool() : false;
403 bool b_signed
= cell
->hasParam("\\B_SIGNED") ? cell
->getParam("\\B_SIGNED").as_bool() : false;
405 int sid
= get_bv_sid(1);
406 int nid_a
= get_sig_nid(cell
->getPort(ID::A
), width
, a_signed
);
407 int nid_b
= get_sig_nid(cell
->getPort(ID::B
), width
, b_signed
);
409 int nid
= next_nid
++;
410 if (cell
->type
.in("$lt", "$le", "$ge", "$gt")) {
411 btorf("%d %c%s %d %d %d %s\n", nid
, a_signed
|| b_signed
? 's' : 'u', btor_op
.c_str(), sid
, nid_a
, nid_b
, getinfo(cell
).c_str());
413 btorf("%d %s %d %d %d %s\n", nid
, btor_op
.c_str(), sid
, nid_a
, nid_b
, getinfo(cell
).c_str());
416 SigSpec sig
= sigmap(cell
->getPort(ID::Y
));
418 if (GetSize(sig
) > 1) {
419 int sid
= get_bv_sid(GetSize(sig
));
420 int nid2
= next_nid
++;
421 btorf("%d uext %d %d %d\n", nid2
, sid
, nid
, GetSize(sig
) - 1);
425 add_nid_sig(nid
, sig
);
429 if (cell
->type
.in("$not", "$neg", "$_NOT_"))
432 if (cell
->type
.in("$not", "$_NOT_")) btor_op
= "not";
433 if (cell
->type
== "$neg") btor_op
= "neg";
434 log_assert(!btor_op
.empty());
436 int width
= std::max(GetSize(cell
->getPort(ID::A
)), GetSize(cell
->getPort(ID::Y
)));
438 bool a_signed
= cell
->hasParam("\\A_SIGNED") ? cell
->getParam("\\A_SIGNED").as_bool() : false;
440 int sid
= get_bv_sid(width
);
441 int nid_a
= get_sig_nid(cell
->getPort(ID::A
), width
, a_signed
);
443 int nid
= next_nid
++;
444 btorf("%d %s %d %d\n", nid
, btor_op
.c_str(), sid
, nid_a
, getinfo(cell
).c_str());
446 SigSpec sig
= sigmap(cell
->getPort(ID::Y
));
448 if (GetSize(sig
) < width
) {
449 int sid
= get_bv_sid(GetSize(sig
));
450 int nid2
= next_nid
++;
451 btorf("%d slice %d %d %d 0\n", nid2
, sid
, nid
, GetSize(sig
)-1);
455 add_nid_sig(nid
, sig
);
459 if (cell
->type
.in("$logic_and", "$logic_or", "$logic_not"))
462 if (cell
->type
== "$logic_and") btor_op
= "and";
463 if (cell
->type
== "$logic_or") btor_op
= "or";
464 if (cell
->type
== "$logic_not") btor_op
= "not";
465 log_assert(!btor_op
.empty());
467 int sid
= get_bv_sid(1);
468 int nid_a
= get_sig_nid(cell
->getPort(ID::A
));
469 int nid_b
= btor_op
!= "not" ? get_sig_nid(cell
->getPort(ID::B
)) : 0;
471 if (GetSize(cell
->getPort(ID::A
)) > 1) {
472 int nid_red_a
= next_nid
++;
473 btorf("%d redor %d %d\n", nid_red_a
, sid
, nid_a
);
477 if (btor_op
!= "not" && GetSize(cell
->getPort(ID::B
)) > 1) {
478 int nid_red_b
= next_nid
++;
479 btorf("%d redor %d %d\n", nid_red_b
, sid
, nid_b
);
483 int nid
= next_nid
++;
484 if (btor_op
!= "not")
485 btorf("%d %s %d %d %d\n", nid
, btor_op
.c_str(), sid
, nid_a
, nid_b
, getinfo(cell
).c_str());
487 btorf("%d %s %d %d\n", nid
, btor_op
.c_str(), sid
, nid_a
, getinfo(cell
).c_str());
489 SigSpec sig
= sigmap(cell
->getPort(ID::Y
));
491 if (GetSize(sig
) > 1) {
492 int sid
= get_bv_sid(GetSize(sig
));
493 int zeros_nid
= get_sig_nid(Const(0, GetSize(sig
)-1));
494 int nid2
= next_nid
++;
495 btorf("%d concat %d %d %d\n", nid2
, sid
, zeros_nid
, nid
);
499 add_nid_sig(nid
, sig
);
503 if (cell
->type
.in("$reduce_and", "$reduce_or", "$reduce_bool", "$reduce_xor", "$reduce_xnor"))
506 if (cell
->type
== "$reduce_and") btor_op
= "redand";
507 if (cell
->type
.in("$reduce_or", "$reduce_bool")) btor_op
= "redor";
508 if (cell
->type
.in("$reduce_xor", "$reduce_xnor")) btor_op
= "redxor";
509 log_assert(!btor_op
.empty());
511 int sid
= get_bv_sid(1);
512 int nid_a
= get_sig_nid(cell
->getPort(ID::A
));
514 int nid
= next_nid
++;
516 if (cell
->type
== "$reduce_xnor") {
517 int nid2
= next_nid
++;
518 btorf("%d %s %d %d %s\n", nid
, btor_op
.c_str(), sid
, nid_a
, getinfo(cell
).c_str());
519 btorf("%d not %d %d %d\n", nid2
, sid
, nid
);
522 btorf("%d %s %d %d %s\n", nid
, btor_op
.c_str(), sid
, nid_a
, getinfo(cell
).c_str());
525 SigSpec sig
= sigmap(cell
->getPort(ID::Y
));
527 if (GetSize(sig
) > 1) {
528 int sid
= get_bv_sid(GetSize(sig
));
529 int zeros_nid
= get_sig_nid(Const(0, GetSize(sig
)-1));
530 int nid2
= next_nid
++;
531 btorf("%d concat %d %d %d\n", nid2
, sid
, zeros_nid
, nid
);
535 add_nid_sig(nid
, sig
);
539 if (cell
->type
.in("$mux", "$_MUX_", "$_NMUX_"))
541 SigSpec sig_a
= sigmap(cell
->getPort(ID::A
));
542 SigSpec sig_b
= sigmap(cell
->getPort(ID::B
));
543 SigSpec sig_s
= sigmap(cell
->getPort(ID::S
));
544 SigSpec sig_y
= sigmap(cell
->getPort(ID::Y
));
546 int nid_a
= get_sig_nid(sig_a
);
547 int nid_b
= get_sig_nid(sig_b
);
548 int nid_s
= get_sig_nid(sig_s
);
550 int sid
= get_bv_sid(GetSize(sig_y
));
551 int nid
= next_nid
++;
553 if (cell
->type
== "$_NMUX_") {
556 btorf("%d ite %d %d %d %d\n", tmp
, sid
, nid_s
, nid_b
, nid_a
);
557 btorf("%d not %d %d %s\n", nid
, sid
, tmp
, getinfo(cell
).c_str());
559 btorf("%d ite %d %d %d %d %s\n", nid
, sid
, nid_s
, nid_b
, nid_a
, getinfo(cell
).c_str());
562 add_nid_sig(nid
, sig_y
);
566 if (cell
->type
== "$pmux")
568 SigSpec sig_a
= sigmap(cell
->getPort(ID::A
));
569 SigSpec sig_b
= sigmap(cell
->getPort(ID::B
));
570 SigSpec sig_s
= sigmap(cell
->getPort(ID::S
));
571 SigSpec sig_y
= sigmap(cell
->getPort(ID::Y
));
573 int width
= GetSize(sig_a
);
574 int sid
= get_bv_sid(width
);
575 int nid
= get_sig_nid(sig_a
);
577 for (int i
= 0; i
< GetSize(sig_s
); i
++) {
578 int nid_b
= get_sig_nid(sig_b
.extract(i
*width
, width
));
579 int nid_s
= get_sig_nid(sig_s
.extract(i
));
580 int nid2
= next_nid
++;
581 if (i
== GetSize(sig_s
)-1)
582 btorf("%d ite %d %d %d %d %s\n", nid2
, sid
, nid_s
, nid_b
, nid
, getinfo(cell
).c_str());
584 btorf("%d ite %d %d %d %d\n", nid2
, sid
, nid_s
, nid_b
, nid
);
588 add_nid_sig(nid
, sig_y
);
592 if (cell
->type
.in("$dff", "$ff", "$_DFF_P_", "$_DFF_N_", "$_FF_"))
594 SigSpec sig_d
= sigmap(cell
->getPort("\\D"));
595 SigSpec sig_q
= sigmap(cell
->getPort("\\Q"));
597 if (!info_filename
.empty() && cell
->type
.in("$dff", "$_DFF_P_", "$_DFF_N_"))
599 SigSpec sig_c
= sigmap(cell
->getPort(cell
->type
== "$dff" ? "\\CLK" : "\\C"));
600 int nid
= get_sig_nid(sig_c
);
601 bool negedge
= false;
603 if (cell
->type
== "$_DFF_N_")
606 if (cell
->type
== "$dff" && !cell
->getParam("\\CLK_POLARITY").as_bool())
609 info_clocks
[nid
] |= negedge
? 2 : 1;
614 if (sig_q
.is_wire()) {
615 Wire
*w
= sig_q
.as_wire();
616 if (w
->port_id
== 0) {
617 statewires
.insert(w
);
623 for (int i
= 0; i
< GetSize(sig_q
); i
++)
624 if (initbits
.count(sig_q
[i
]))
625 initval
.bits
.push_back(initbits
.at(sig_q
[i
]) ? State::S1
: State::S0
);
627 initval
.bits
.push_back(State::Sx
);
629 int nid_init_val
= -1;
631 if (!initval
.is_fully_undef())
632 nid_init_val
= get_sig_nid(initval
, -1, false, true);
634 int sid
= get_bv_sid(GetSize(sig_q
));
635 int nid
= next_nid
++;
638 btorf("%d state %d\n", nid
, sid
);
640 btorf("%d state %d %s\n", nid
, sid
, log_id(symbol
));
642 if (nid_init_val
>= 0) {
643 int nid_init
= next_nid
++;
645 btorf("; initval = %s\n", log_signal(initval
));
646 btorf("%d init %d %d %d\n", nid_init
, sid
, nid
, nid_init_val
);
649 ff_todo
.push_back(make_pair(nid
, cell
));
650 add_nid_sig(nid
, sig_q
);
654 if (cell
->type
.in("$anyconst", "$anyseq"))
656 SigSpec sig_y
= sigmap(cell
->getPort(ID::Y
));
658 int sid
= get_bv_sid(GetSize(sig_y
));
659 int nid
= next_nid
++;
661 btorf("%d state %d\n", nid
, sid
);
663 if (cell
->type
== "$anyconst") {
664 int nid2
= next_nid
++;
665 btorf("%d next %d %d %d\n", nid2
, sid
, nid
, nid
);
668 add_nid_sig(nid
, sig_y
);
672 if (cell
->type
== "$initstate")
674 SigSpec sig_y
= sigmap(cell
->getPort(ID::Y
));
676 if (initstate_nid
< 0)
678 int sid
= get_bv_sid(1);
679 int one_nid
= get_sig_nid(State::S1
);
680 int zero_nid
= get_sig_nid(State::S0
);
681 initstate_nid
= next_nid
++;
682 btorf("%d state %d\n", initstate_nid
, sid
);
683 btorf("%d init %d %d %d\n", next_nid
++, sid
, initstate_nid
, one_nid
);
684 btorf("%d next %d %d %d\n", next_nid
++, sid
, initstate_nid
, zero_nid
);
687 add_nid_sig(initstate_nid
, sig_y
);
691 if (cell
->type
== "$mem")
693 int abits
= cell
->getParam("\\ABITS").as_int();
694 int width
= cell
->getParam("\\WIDTH").as_int();
695 int nwords
= cell
->getParam("\\SIZE").as_int();
696 int rdports
= cell
->getParam("\\RD_PORTS").as_int();
697 int wrports
= cell
->getParam("\\WR_PORTS").as_int();
699 Const wr_clk_en
= cell
->getParam("\\WR_CLK_ENABLE");
700 Const rd_clk_en
= cell
->getParam("\\RD_CLK_ENABLE");
702 bool asyncwr
= wr_clk_en
.is_fully_zero();
704 if (!asyncwr
&& !wr_clk_en
.is_fully_ones())
705 log_error("Memory %s.%s has mixed async/sync write ports.\n",
706 log_id(module
), log_id(cell
));
708 if (!rd_clk_en
.is_fully_zero())
709 log_error("Memory %s.%s has sync read ports.\n",
710 log_id(module
), log_id(cell
));
712 SigSpec sig_rd_addr
= sigmap(cell
->getPort("\\RD_ADDR"));
713 SigSpec sig_rd_data
= sigmap(cell
->getPort("\\RD_DATA"));
715 SigSpec sig_wr_addr
= sigmap(cell
->getPort("\\WR_ADDR"));
716 SigSpec sig_wr_data
= sigmap(cell
->getPort("\\WR_DATA"));
717 SigSpec sig_wr_en
= sigmap(cell
->getPort("\\WR_EN"));
719 int data_sid
= get_bv_sid(width
);
720 int bool_sid
= get_bv_sid(1);
721 int sid
= get_mem_sid(abits
, width
);
723 Const initdata
= cell
->getParam("\\INIT");
724 initdata
.exts(nwords
*width
);
725 int nid_init_val
= -1;
727 if (!initdata
.is_fully_undef())
729 bool constword
= true;
730 Const firstword
= initdata
.extract(0, width
);
732 for (int i
= 1; i
< nwords
; i
++) {
733 Const thisword
= initdata
.extract(i
*width
, width
);
734 if (thisword
!= firstword
) {
743 btorf("; initval = %s\n", log_signal(firstword
));
744 nid_init_val
= get_sig_nid(firstword
, -1, false, true);
748 nid_init_val
= next_nid
++;
749 btorf("%d state %d\n", nid_init_val
, sid
);
751 for (int i
= 0; i
< nwords
; i
++) {
752 Const thisword
= initdata
.extract(i
*width
, width
);
753 if (thisword
.is_fully_undef())
755 Const
thisaddr(i
, abits
);
756 int nid_thisword
= get_sig_nid(thisword
, -1, false, true);
757 int nid_thisaddr
= get_sig_nid(thisaddr
, -1, false, true);
758 int last_nid_init_val
= nid_init_val
;
759 nid_init_val
= next_nid
++;
761 btorf("; initval[%d] = %s\n", i
, log_signal(thisword
));
762 btorf("%d write %d %d %d %d\n", nid_init_val
, sid
, last_nid_init_val
, nid_thisaddr
, nid_thisword
);
768 int nid
= next_nid
++;
771 if (cell
->name
[0] == '$')
772 btorf("%d state %d\n", nid
, sid
);
774 btorf("%d state %d %s\n", nid
, sid
, log_id(cell
));
776 if (nid_init_val
>= 0)
778 int nid_init
= next_nid
++;
779 btorf("%d init %d %d %d\n", nid_init
, sid
, nid
, nid_init_val
);
784 for (int port
= 0; port
< wrports
; port
++)
786 SigSpec wa
= sig_wr_addr
.extract(port
*abits
, abits
);
787 SigSpec wd
= sig_wr_data
.extract(port
*width
, width
);
788 SigSpec we
= sig_wr_en
.extract(port
*width
, width
);
790 int wa_nid
= get_sig_nid(wa
);
791 int wd_nid
= get_sig_nid(wd
);
792 int we_nid
= get_sig_nid(we
);
794 int nid2
= next_nid
++;
795 btorf("%d read %d %d %d\n", nid2
, data_sid
, nid_head
, wa_nid
);
797 int nid3
= next_nid
++;
798 btorf("%d not %d %d\n", nid3
, data_sid
, we_nid
);
800 int nid4
= next_nid
++;
801 btorf("%d and %d %d %d\n", nid4
, data_sid
, nid2
, nid3
);
803 int nid5
= next_nid
++;
804 btorf("%d and %d %d %d\n", nid5
, data_sid
, wd_nid
, we_nid
);
806 int nid6
= next_nid
++;
807 btorf("%d or %d %d %d\n", nid6
, data_sid
, nid5
, nid4
);
809 int nid7
= next_nid
++;
810 btorf("%d write %d %d %d %d\n", nid7
, sid
, nid_head
, wa_nid
, nid6
);
812 int nid8
= next_nid
++;
813 btorf("%d redor %d %d\n", nid8
, bool_sid
, we_nid
);
815 int nid9
= next_nid
++;
816 btorf("%d ite %d %d %d %d\n", nid9
, sid
, nid8
, nid7
, nid_head
);
822 for (int port
= 0; port
< rdports
; port
++)
824 SigSpec ra
= sig_rd_addr
.extract(port
*abits
, abits
);
825 SigSpec rd
= sig_rd_data
.extract(port
*width
, width
);
827 int ra_nid
= get_sig_nid(ra
);
828 int rd_nid
= next_nid
++;
830 btorf("%d read %d %d %d\n", rd_nid
, data_sid
, nid_head
, ra_nid
);
832 add_nid_sig(rd_nid
, rd
);
837 ff_todo
.push_back(make_pair(nid
, cell
));
841 int nid2
= next_nid
++;
842 btorf("%d next %d %d %d\n", nid2
, sid
, nid
, nid_head
);
848 log_error("Unsupported cell type: %s (%s)\n", log_id(cell
->type
), log_id(cell
));
851 btorf_pop(log_id(cell
));
852 cell_recursion_guard
.erase(cell
);
855 int get_sig_nid(SigSpec sig
, int to_width
= -1, bool is_signed
= false, bool is_init
= false)
861 if (bit
== State::Sx
)
867 SigSpec sig_mask_undef
, sig_noundef
;
868 int first_undef
= -1;
870 for (int i
= 0; i
< GetSize(sig
); i
++)
871 if (sig
[i
] == State::Sx
) {
874 sig_mask_undef
.append(State::S1
);
875 sig_noundef
.append(State::S0
);
877 sig_mask_undef
.append(State::S0
);
878 sig_noundef
.append(sig
[i
]);
881 if (to_width
< 0 || first_undef
< to_width
)
883 int sid
= get_bv_sid(GetSize(sig
));
885 int nid_input
= next_nid
++;
887 btorf("%d state %d\n", nid_input
, sid
);
889 btorf("%d input %d\n", nid_input
, sid
);
891 int nid_masked_input
;
892 if (sig_mask_undef
.is_fully_ones()) {
893 nid_masked_input
= nid_input
;
895 int nid_mask_undef
= get_sig_nid(sig_mask_undef
);
896 nid_masked_input
= next_nid
++;
897 btorf("%d and %d %d %d\n", nid_masked_input
, sid
, nid_input
, nid_mask_undef
);
900 if (sig_noundef
.is_fully_zero()) {
901 nid
= nid_masked_input
;
903 int nid_noundef
= get_sig_nid(sig_noundef
);
905 btorf("%d or %d %d %d\n", nid
, sid
, nid_masked_input
, nid_noundef
);
914 if (sig_nid
.count(sig
) == 0)
917 vector
<pair
<int, int>> nidbits
;
920 for (int i
= 0; i
< GetSize(sig
); i
++)
924 if (bit_nid
.count(bit
) == 0)
926 if (bit
.wire
== nullptr)
930 while (i
+GetSize(c
) < GetSize(sig
) && sig
[i
+GetSize(c
)].wire
== nullptr)
931 c
.bits
.push_back(sig
[i
+GetSize(c
)].data
);
933 if (consts
.count(c
) == 0) {
934 int sid
= get_bv_sid(GetSize(c
));
935 int nid
= next_nid
++;
936 btorf("%d const %d %s\n", nid
, sid
, c
.as_string().c_str());
938 nid_width
[nid
] = GetSize(c
);
941 int nid
= consts
.at(c
);
943 for (int j
= 0; j
< GetSize(c
); j
++)
944 nidbits
.push_back(make_pair(nid
, j
));
951 if (bit_cell
.count(bit
) == 0)
955 while (i
+GetSize(s
) < GetSize(sig
) && sig
[i
+GetSize(s
)].wire
!= nullptr &&
956 bit_cell
.count(sig
[i
+GetSize(s
)]) == 0)
957 s
.append(sig
[i
+GetSize(s
)]);
959 log_warning("No driver for signal %s.\n", log_signal(s
));
961 int sid
= get_bv_sid(GetSize(s
));
962 int nid
= next_nid
++;
963 btorf("%d input %d\n", nid
, sid
);
964 nid_width
[nid
] = GetSize(s
);
966 for (int j
= 0; j
< GetSize(s
); j
++)
967 nidbits
.push_back(make_pair(nid
, j
));
974 export_cell(bit_cell
.at(bit
));
975 log_assert(bit_nid
.count(bit
));
980 nidbits
.push_back(bit_nid
.at(bit
));
986 // group bits and emit slice-concat chain
987 for (int i
= 0; i
< GetSize(nidbits
); i
++)
989 int nid2
= nidbits
[i
].first
;
990 int lower
= nidbits
[i
].second
;
993 while (i
+1 < GetSize(nidbits
) && nidbits
[i
+1].first
== nidbits
[i
].first
&&
994 nidbits
[i
+1].second
== nidbits
[i
].second
+1)
999 if (lower
!= 0 || upper
+1 != nid_width
.at(nid2
)) {
1000 int sid
= get_bv_sid(upper
-lower
+1);
1002 btorf("%d slice %d %d %d %d\n", nid3
, sid
, nid2
, upper
, lower
);
1008 int sid
= get_bv_sid(width
+upper
-lower
+1);
1010 btorf("%d concat %d %d %d\n", nid4
, sid
, nid3
, nid
);
1013 width
+= upper
-lower
+1;
1018 nid_width
[nid
] = width
;
1021 nid
= sig_nid
.at(sig
);
1024 if (to_width
>= 0 && to_width
!= GetSize(sig
))
1026 if (to_width
< GetSize(sig
))
1028 int sid
= get_bv_sid(to_width
);
1029 int nid2
= next_nid
++;
1030 btorf("%d slice %d %d %d 0\n", nid2
, sid
, nid
, to_width
-1);
1035 int sid
= get_bv_sid(to_width
);
1036 int nid2
= next_nid
++;
1037 btorf("%d %s %d %d %d\n", nid2
, is_signed
? "sext" : "uext",
1038 sid
, nid
, to_width
- GetSize(sig
));
1046 BtorWorker(std::ostream
&f
, RTLIL::Module
*module
, bool verbose
, bool single_bad
, bool cover_mode
, string info_filename
) :
1047 f(f
), sigmap(module
), module(module
), verbose(verbose
), single_bad(single_bad
), cover_mode(cover_mode
), info_filename(info_filename
)
1049 if (!info_filename
.empty())
1050 infof("name %s\n", log_id(module
));
1052 btorf_push("inputs");
1054 for (auto wire
: module
->wires())
1056 if (wire
->attributes
.count("\\init")) {
1057 Const attrval
= wire
->attributes
.at("\\init");
1058 for (int i
= 0; i
< GetSize(wire
) && i
< GetSize(attrval
); i
++)
1059 if (attrval
[i
] == State::S0
|| attrval
[i
] == State::S1
)
1060 initbits
[sigmap(SigBit(wire
, i
))] = (attrval
[i
] == State::S1
);
1063 if (!wire
->port_id
|| !wire
->port_input
)
1066 SigSpec sig
= sigmap(wire
);
1067 int sid
= get_bv_sid(GetSize(sig
));
1068 int nid
= next_nid
++;
1070 btorf("%d input %d %s\n", nid
, sid
, getinfo(wire
).c_str());
1071 add_nid_sig(nid
, sig
);
1074 btorf_pop("inputs");
1076 for (auto cell
: module
->cells())
1077 for (auto &conn
: cell
->connections())
1079 if (!cell
->output(conn
.first
))
1082 for (auto bit
: sigmap(conn
.second
))
1083 bit_cell
[bit
] = cell
;
1086 for (auto wire
: module
->wires())
1088 if (!wire
->port_id
|| !wire
->port_output
)
1091 btorf_push(stringf("output %s", log_id(wire
)));
1093 int nid
= get_sig_nid(wire
);
1094 btorf("%d output %d %s\n", next_nid
++, nid
, getinfo(wire
).c_str());
1096 btorf_pop(stringf("output %s", log_id(wire
)));
1099 for (auto cell
: module
->cells())
1101 if (cell
->type
== "$assume")
1103 btorf_push(log_id(cell
));
1105 int sid
= get_bv_sid(1);
1106 int nid_a
= get_sig_nid(cell
->getPort(ID::A
));
1107 int nid_en
= get_sig_nid(cell
->getPort("\\EN"));
1108 int nid_not_en
= next_nid
++;
1109 int nid_a_or_not_en
= next_nid
++;
1110 int nid
= next_nid
++;
1112 btorf("%d not %d %d\n", nid_not_en
, sid
, nid_en
);
1113 btorf("%d or %d %d %d\n", nid_a_or_not_en
, sid
, nid_a
, nid_not_en
);
1114 btorf("%d constraint %d\n", nid
, nid_a_or_not_en
);
1116 btorf_pop(log_id(cell
));
1119 if (cell
->type
== "$assert")
1121 btorf_push(log_id(cell
));
1123 int sid
= get_bv_sid(1);
1124 int nid_a
= get_sig_nid(cell
->getPort(ID::A
));
1125 int nid_en
= get_sig_nid(cell
->getPort("\\EN"));
1126 int nid_not_a
= next_nid
++;
1127 int nid_en_and_not_a
= next_nid
++;
1129 btorf("%d not %d %d\n", nid_not_a
, sid
, nid_a
);
1130 btorf("%d and %d %d %d\n", nid_en_and_not_a
, sid
, nid_en
, nid_not_a
);
1132 if (single_bad
&& !cover_mode
) {
1133 bad_properties
.push_back(nid_en_and_not_a
);
1136 infof("bad %d %s\n", nid_en_and_not_a
, getinfo(cell
, true).c_str());
1138 int nid
= next_nid
++;
1139 btorf("%d bad %d %s\n", nid
, nid_en_and_not_a
, getinfo(cell
, true).c_str());
1143 btorf_pop(log_id(cell
));
1146 if (cell
->type
== "$cover" && cover_mode
)
1148 btorf_push(log_id(cell
));
1150 int sid
= get_bv_sid(1);
1151 int nid_a
= get_sig_nid(cell
->getPort("\\A"));
1152 int nid_en
= get_sig_nid(cell
->getPort("\\EN"));
1153 int nid_en_and_a
= next_nid
++;
1155 btorf("%d and %d %d %d\n", nid_en_and_a
, sid
, nid_en
, nid_a
);
1158 bad_properties
.push_back(nid_en_and_a
);
1160 int nid
= next_nid
++;
1161 btorf("%d bad %d %s\n", nid
, nid_en_and_a
, getinfo(cell
, true).c_str());
1164 btorf_pop(log_id(cell
));
1168 for (auto wire
: module
->wires())
1170 if (wire
->port_id
|| wire
->name
[0] == '$')
1173 btorf_push(stringf("wire %s", log_id(wire
)));
1175 int sid
= get_bv_sid(GetSize(wire
));
1176 int nid
= get_sig_nid(sigmap(wire
));
1178 if (statewires
.count(wire
))
1181 int this_nid
= next_nid
++;
1182 btorf("%d uext %d %d %d %s\n", this_nid
, sid
, nid
, 0, getinfo(wire
).c_str());
1184 btorf_pop(stringf("wire %s", log_id(wire
)));
1188 while (!ff_todo
.empty())
1190 vector
<pair
<int, Cell
*>> todo
;
1193 for (auto &it
: todo
)
1196 Cell
*cell
= it
.second
;
1198 btorf_push(stringf("next %s", log_id(cell
)));
1200 if (cell
->type
== "$mem")
1202 int abits
= cell
->getParam("\\ABITS").as_int();
1203 int width
= cell
->getParam("\\WIDTH").as_int();
1204 int wrports
= cell
->getParam("\\WR_PORTS").as_int();
1206 SigSpec sig_wr_addr
= sigmap(cell
->getPort("\\WR_ADDR"));
1207 SigSpec sig_wr_data
= sigmap(cell
->getPort("\\WR_DATA"));
1208 SigSpec sig_wr_en
= sigmap(cell
->getPort("\\WR_EN"));
1210 int data_sid
= get_bv_sid(width
);
1211 int bool_sid
= get_bv_sid(1);
1212 int sid
= get_mem_sid(abits
, width
);
1215 for (int port
= 0; port
< wrports
; port
++)
1217 SigSpec wa
= sig_wr_addr
.extract(port
*abits
, abits
);
1218 SigSpec wd
= sig_wr_data
.extract(port
*width
, width
);
1219 SigSpec we
= sig_wr_en
.extract(port
*width
, width
);
1221 int wa_nid
= get_sig_nid(wa
);
1222 int wd_nid
= get_sig_nid(wd
);
1223 int we_nid
= get_sig_nid(we
);
1225 int nid2
= next_nid
++;
1226 btorf("%d read %d %d %d\n", nid2
, data_sid
, nid_head
, wa_nid
);
1228 int nid3
= next_nid
++;
1229 btorf("%d not %d %d\n", nid3
, data_sid
, we_nid
);
1231 int nid4
= next_nid
++;
1232 btorf("%d and %d %d %d\n", nid4
, data_sid
, nid2
, nid3
);
1234 int nid5
= next_nid
++;
1235 btorf("%d and %d %d %d\n", nid5
, data_sid
, wd_nid
, we_nid
);
1237 int nid6
= next_nid
++;
1238 btorf("%d or %d %d %d\n", nid6
, data_sid
, nid5
, nid4
);
1240 int nid7
= next_nid
++;
1241 btorf("%d write %d %d %d %d\n", nid7
, sid
, nid_head
, wa_nid
, nid6
);
1243 int nid8
= next_nid
++;
1244 btorf("%d redor %d %d\n", nid8
, bool_sid
, we_nid
);
1246 int nid9
= next_nid
++;
1247 btorf("%d ite %d %d %d %d\n", nid9
, sid
, nid8
, nid7
, nid_head
);
1252 int nid2
= next_nid
++;
1253 btorf("%d next %d %d %d %s\n", nid2
, sid
, nid
, nid_head
, getinfo(cell
).c_str());
1257 SigSpec sig
= sigmap(cell
->getPort("\\D"));
1258 int nid_q
= get_sig_nid(sig
);
1259 int sid
= get_bv_sid(GetSize(sig
));
1260 btorf("%d next %d %d %d %s\n", next_nid
++, sid
, nid
, nid_q
, getinfo(cell
).c_str());
1263 btorf_pop(stringf("next %s", log_id(cell
)));
1267 while (!bad_properties
.empty())
1270 bad_properties
.swap(todo
);
1272 int sid
= get_bv_sid(1);
1275 while (cursor
+1 < GetSize(todo
))
1277 int nid_a
= todo
[cursor
++];
1278 int nid_b
= todo
[cursor
++];
1279 int nid
= next_nid
++;
1281 bad_properties
.push_back(nid
);
1282 btorf("%d or %d %d %d\n", nid
, sid
, nid_a
, nid_b
);
1285 if (!bad_properties
.empty()) {
1286 if (cursor
< GetSize(todo
))
1287 bad_properties
.push_back(todo
[cursor
++]);
1288 log_assert(cursor
== GetSize(todo
));
1290 int nid
= next_nid
++;
1291 log_assert(cursor
== 0);
1292 log_assert(GetSize(todo
) == 1);
1293 btorf("%d bad %d\n", nid
, todo
[cursor
]);
1297 if (!info_filename
.empty())
1299 for (auto &it
: info_clocks
)
1304 infof("posedge %d\n", it
.first
);
1307 infof("negedge %d\n", it
.first
);
1310 infof("event %d\n", it
.first
);
1318 f
.open(info_filename
.c_str(), std::ofstream::trunc
);
1320 log_error("Can't open file `%s' for writing: %s\n", info_filename
.c_str(), strerror(errno
));
1321 for (auto &it
: info_lines
)
1328 struct BtorBackend
: public Backend
{
1329 BtorBackend() : Backend("btor", "write design to BTOR file") { }
1330 void help() YS_OVERRIDE
1332 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1334 log(" write_btor [options] [filename]\n");
1336 log("Write a BTOR description of the current design.\n");
1339 log(" Add comments and indentation to BTOR output file\n");
1342 log(" Output only a single bad property for all asserts\n");
1345 log(" Output cover properties using 'bad' statements instead of asserts\n");
1347 log(" -i <filename>\n");
1348 log(" Create additional info file with auxiliary information\n");
1351 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
1353 bool verbose
= false, single_bad
= false, cover_mode
= false;
1354 string info_filename
;
1356 log_header(design
, "Executing BTOR backend.\n");
1359 for (argidx
= 1; argidx
< args
.size(); argidx
++)
1361 if (args
[argidx
] == "-v") {
1365 if (args
[argidx
] == "-s") {
1369 if (args
[argidx
] == "-c") {
1373 if (args
[argidx
] == "-i" && argidx
+1 < args
.size()) {
1374 info_filename
= args
[++argidx
];
1379 extra_args(f
, filename
, args
, argidx
);
1381 RTLIL::Module
*topmod
= design
->top_module();
1383 if (topmod
== nullptr)
1384 log_cmd_error("No top module found.\n");
1386 *f
<< stringf("; BTOR description generated by %s for module %s.\n",
1387 yosys_version_str
, log_id(topmod
));
1389 BtorWorker(*f
, topmod
, verbose
, single_bad
, cover_mode
, info_filename
);
1391 *f
<< stringf("; end of yosys output\n");
1395 PRIVATE_NAMESPACE_END