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 #include "kernel/rtlil.h"
21 #include "kernel/register.h"
22 #include "kernel/sigtools.h"
23 #include "kernel/celltypes.h"
24 #include "kernel/log.h"
28 PRIVATE_NAMESPACE_BEGIN
34 RTLIL::Module
*module
;
39 int initstate_nid
= -1;
42 dict
<int, int> sorts_bv
;
44 // (<address-width>, <data-width>) => <sid>
45 dict
<pair
<int, int>, int> sorts_mem
;
47 // SigBit => (<nid>, <bitidx>)
48 dict
<SigBit
, pair
<int, int>> bit_nid
;
51 dict
<int, int> nid_width
;
54 dict
<SigSpec
, int> sig_nid
;
56 // bit to driving cell
57 dict
<SigBit
, Cell
*> bit_cell
;
60 dict
<Const
, int> consts
;
62 // ff inputs that need to be evaluated (<nid>, <ff_cell>)
63 vector
<pair
<int, Cell
*>> ff_todo
;
65 pool
<Cell
*> cell_recursion_guard
;
66 vector
<int> bad_properties
;
67 dict
<SigBit
, bool> initbits
;
68 pool
<Wire
*> statewires
;
71 void btorf(const char *fmt
, ...)
75 f
<< indent
<< vstringf(fmt
, ap
);
79 void btorf_push(const string
&id
)
82 f
<< indent
<< stringf(" ; begin %s\n", id
.c_str());
87 void btorf_pop(const string
&id
)
90 indent
= indent
.substr(4);
91 f
<< indent
<< stringf(" ; end %s\n", id
.c_str());
95 int get_bv_sid(int width
)
97 if (sorts_bv
.count(width
) == 0) {
99 btorf("%d sort bitvec %d\n", nid
, width
);
100 sorts_bv
[width
] = nid
;
102 return sorts_bv
.at(width
);
105 int get_mem_sid(int abits
, int dbits
)
107 pair
<int, int> key(abits
, dbits
);
108 if (sorts_mem
.count(key
) == 0) {
109 int addr_sid
= get_bv_sid(abits
);
110 int data_sid
= get_bv_sid(dbits
);
111 int nid
= next_nid
++;
112 btorf("%d sort array %d %d\n", nid
, addr_sid
, data_sid
);
113 sorts_mem
[key
] = nid
;
115 return sorts_mem
.at(key
);
118 void add_nid_sig(int nid
, const SigSpec
&sig
)
121 f
<< indent
<< stringf("; %d %s\n", nid
, log_signal(sig
));
123 for (int i
= 0; i
< GetSize(sig
); i
++)
124 bit_nid
[sig
[i
]] = make_pair(nid
, i
);
127 nid_width
[nid
] = GetSize(sig
);
130 void export_cell(Cell
*cell
)
132 log_assert(cell_recursion_guard
.count(cell
) == 0);
133 cell_recursion_guard
.insert(cell
);
134 btorf_push(log_id(cell
));
136 if (cell
->type
.in("$add", "$sub", "$mul", "$and", "$or", "$xor", "$xnor", "$shl", "$sshl", "$shr", "$sshr", "$shift", "$shiftx",
137 "$concat", "$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_"))
140 if (cell
->type
== "$add") btor_op
= "add";
141 if (cell
->type
== "$sub") btor_op
= "sub";
142 if (cell
->type
== "$mul") btor_op
= "mul";
143 if (cell
->type
.in("$shl", "$sshl")) btor_op
= "sll";
144 if (cell
->type
== "$shr") btor_op
= "srl";
145 if (cell
->type
== "$sshr") btor_op
= "sra";
146 if (cell
->type
.in("$shift", "$shiftx")) btor_op
= "shift";
147 if (cell
->type
.in("$and", "$_AND_")) btor_op
= "and";
148 if (cell
->type
.in("$or", "$_OR_")) btor_op
= "or";
149 if (cell
->type
.in("$xor", "$_XOR_")) btor_op
= "xor";
150 if (cell
->type
== "$concat") btor_op
= "concat";
151 if (cell
->type
== "$_NAND_") btor_op
= "nand";
152 if (cell
->type
== "$_NOR_") btor_op
= "nor";
153 if (cell
->type
.in("$xnor", "$_XNOR_")) btor_op
= "xnor";
154 log_assert(!btor_op
.empty());
156 int width
= GetSize(cell
->getPort("\\Y"));
157 width
= std::max(width
, GetSize(cell
->getPort("\\A")));
158 width
= std::max(width
, GetSize(cell
->getPort("\\B")));
160 bool a_signed
= cell
->hasParam("\\A_SIGNED") ? cell
->getParam("\\A_SIGNED").as_bool() : false;
161 bool b_signed
= cell
->hasParam("\\B_SIGNED") ? cell
->getParam("\\B_SIGNED").as_bool() : false;
163 if (btor_op
== "shift" && !b_signed
)
166 if (cell
->type
.in("$shl", "$sshl", "$shr", "$sshr"))
169 if (cell
->type
== "$sshr" && !a_signed
)
172 int sid
= get_bv_sid(width
);
175 if (btor_op
== "shift")
177 int nid_a
= get_sig_nid(cell
->getPort("\\A"), width
, false);
178 int nid_b
= get_sig_nid(cell
->getPort("\\B"), width
, b_signed
);
180 int nid_r
= next_nid
++;
181 btorf("%d srl %d %d %d\n", nid_r
, sid
, nid_a
, nid_b
);
183 int nid_b_neg
= next_nid
++;
184 btorf("%d neg %d %d\n", nid_b_neg
, sid
, nid_b
);
186 int nid_l
= next_nid
++;
187 btorf("%d sll %d %d %d\n", nid_l
, sid
, nid_a
, nid_b_neg
);
189 int sid_bit
= get_bv_sid(1);
190 int nid_zero
= get_sig_nid(Const(0, width
));
191 int nid_b_ltz
= next_nid
++;
192 btorf("%d slt %d %d %d\n", nid_b_ltz
, sid_bit
, nid_b
, nid_zero
);
195 btorf("%d ite %d %d %d %d\n", nid
, sid
, nid_b_ltz
, nid_l
, nid_r
);
199 int nid_a
= get_sig_nid(cell
->getPort("\\A"), width
, a_signed
);
200 int nid_b
= get_sig_nid(cell
->getPort("\\B"), width
, b_signed
);
203 btorf("%d %s %d %d %d\n", nid
, btor_op
.c_str(), sid
, nid_a
, nid_b
);
206 SigSpec sig
= sigmap(cell
->getPort("\\Y"));
208 if (GetSize(sig
) < width
) {
209 int sid
= get_bv_sid(GetSize(sig
));
210 int nid2
= next_nid
++;
211 btorf("%d slice %d %d %d 0\n", nid2
, sid
, nid
, GetSize(sig
)-1);
215 add_nid_sig(nid
, sig
);
219 if (cell
->type
.in("$div", "$mod"))
222 if (cell
->type
== "$div") btor_op
= "div";
223 if (cell
->type
== "$mod") btor_op
= "rem";
224 log_assert(!btor_op
.empty());
226 int width
= GetSize(cell
->getPort("\\Y"));
227 width
= std::max(width
, GetSize(cell
->getPort("\\A")));
228 width
= std::max(width
, GetSize(cell
->getPort("\\B")));
230 bool a_signed
= cell
->hasParam("\\A_SIGNED") ? cell
->getParam("\\A_SIGNED").as_bool() : false;
231 bool b_signed
= cell
->hasParam("\\B_SIGNED") ? cell
->getParam("\\B_SIGNED").as_bool() : false;
233 int nid_a
= get_sig_nid(cell
->getPort("\\A"), width
, a_signed
);
234 int nid_b
= get_sig_nid(cell
->getPort("\\B"), width
, b_signed
);
236 int sid
= get_bv_sid(width
);
237 int nid
= next_nid
++;
238 btorf("%d %c%s %d %d %d\n", nid
, a_signed
|| b_signed
? 's' : 'u', btor_op
.c_str(), sid
, nid_a
, nid_b
);
240 SigSpec sig
= sigmap(cell
->getPort("\\Y"));
242 if (GetSize(sig
) < width
) {
243 int sid
= get_bv_sid(GetSize(sig
));
244 int nid2
= next_nid
++;
245 btorf("%d slice %d %d %d 0\n", nid2
, sid
, nid
, GetSize(sig
)-1);
249 add_nid_sig(nid
, sig
);
253 if (cell
->type
.in("$_ANDNOT_", "$_ORNOT_"))
255 int sid
= get_bv_sid(1);
256 int nid_a
= get_sig_nid(cell
->getPort("\\A"));
257 int nid_b
= get_sig_nid(cell
->getPort("\\B"));
259 int nid1
= next_nid
++;
260 int nid2
= next_nid
++;
262 if (cell
->type
== "$_ANDNOT_") {
263 btorf("%d not %d %d\n", nid1
, sid
, nid_b
);
264 btorf("%d and %d %d %d\n", nid2
, sid
, nid_a
, nid1
);
267 if (cell
->type
== "$_ORNOT_") {
268 btorf("%d not %d %d\n", nid1
, sid
, nid_b
);
269 btorf("%d or %d %d %d\n", nid2
, sid
, nid_a
, nid1
);
272 SigSpec sig
= sigmap(cell
->getPort("\\Y"));
273 add_nid_sig(nid2
, sig
);
277 if (cell
->type
.in("$_OAI3_", "$_AOI3_"))
279 int sid
= get_bv_sid(1);
280 int nid_a
= get_sig_nid(cell
->getPort("\\A"));
281 int nid_b
= get_sig_nid(cell
->getPort("\\B"));
282 int nid_c
= get_sig_nid(cell
->getPort("\\C"));
284 int nid1
= next_nid
++;
285 int nid2
= next_nid
++;
286 int nid3
= next_nid
++;
288 if (cell
->type
== "$_OAI3_") {
289 btorf("%d or %d %d %d\n", nid1
, sid
, nid_a
, nid_b
);
290 btorf("%d and %d %d %d\n", nid2
, sid
, nid1
, nid_c
);
291 btorf("%d not %d %d\n", nid3
, sid
, nid2
);
294 if (cell
->type
== "$_AOI3_") {
295 btorf("%d and %d %d %d\n", nid1
, sid
, nid_a
, nid_b
);
296 btorf("%d or %d %d %d\n", nid2
, sid
, nid1
, nid_c
);
297 btorf("%d not %d %d\n", nid3
, sid
, nid2
);
300 SigSpec sig
= sigmap(cell
->getPort("\\Y"));
301 add_nid_sig(nid3
, sig
);
305 if (cell
->type
.in("$_OAI4_", "$_AOI4_"))
307 int sid
= get_bv_sid(1);
308 int nid_a
= get_sig_nid(cell
->getPort("\\A"));
309 int nid_b
= get_sig_nid(cell
->getPort("\\B"));
310 int nid_c
= get_sig_nid(cell
->getPort("\\C"));
311 int nid_d
= get_sig_nid(cell
->getPort("\\D"));
313 int nid1
= next_nid
++;
314 int nid2
= next_nid
++;
315 int nid3
= next_nid
++;
316 int nid4
= next_nid
++;
318 if (cell
->type
== "$_OAI4_") {
319 btorf("%d or %d %d %d\n", nid1
, sid
, nid_a
, nid_b
);
320 btorf("%d or %d %d %d\n", nid2
, sid
, nid_c
, nid_d
);
321 btorf("%d and %d %d %d\n", nid3
, sid
, nid1
, nid2
);
322 btorf("%d not %d %d\n", nid4
, sid
, nid3
);
325 if (cell
->type
== "$_AOI4_") {
326 btorf("%d and %d %d %d\n", nid1
, sid
, nid_a
, nid_b
);
327 btorf("%d and %d %d %d\n", nid2
, sid
, nid_c
, nid_d
);
328 btorf("%d or %d %d %d\n", nid3
, sid
, nid1
, nid2
);
329 btorf("%d not %d %d\n", nid4
, sid
, nid3
);
332 SigSpec sig
= sigmap(cell
->getPort("\\Y"));
333 add_nid_sig(nid4
, sig
);
337 if (cell
->type
.in("$lt", "$le", "$eq", "$eqx", "$ne", "$nex", "$ge", "$gt"))
340 if (cell
->type
== "$lt") btor_op
= "lt";
341 if (cell
->type
== "$le") btor_op
= "lte";
342 if (cell
->type
.in("$eq", "$eqx")) btor_op
= "eq";
343 if (cell
->type
.in("$ne", "$nex")) btor_op
= "ne";
344 if (cell
->type
== "$ge") btor_op
= "gte";
345 if (cell
->type
== "$gt") btor_op
= "gt";
346 log_assert(!btor_op
.empty());
349 width
= std::max(width
, GetSize(cell
->getPort("\\A")));
350 width
= std::max(width
, GetSize(cell
->getPort("\\B")));
352 bool a_signed
= cell
->hasParam("\\A_SIGNED") ? cell
->getParam("\\A_SIGNED").as_bool() : false;
353 bool b_signed
= cell
->hasParam("\\B_SIGNED") ? cell
->getParam("\\B_SIGNED").as_bool() : false;
355 int sid
= get_bv_sid(1);
356 int nid_a
= get_sig_nid(cell
->getPort("\\A"), width
, a_signed
);
357 int nid_b
= get_sig_nid(cell
->getPort("\\B"), width
, b_signed
);
359 int nid
= next_nid
++;
360 if (cell
->type
.in("$lt", "$le", "$ge", "$gt")) {
361 btorf("%d %c%s %d %d %d\n", nid
, a_signed
|| b_signed
? 's' : 'u', btor_op
.c_str(), sid
, nid_a
, nid_b
);
363 btorf("%d %s %d %d %d\n", nid
, btor_op
.c_str(), sid
, nid_a
, nid_b
);
366 SigSpec sig
= sigmap(cell
->getPort("\\Y"));
368 if (GetSize(sig
) > 1) {
369 int sid
= get_bv_sid(GetSize(sig
));
370 int nid2
= next_nid
++;
371 btorf("%d uext %d %d %d\n", nid2
, sid
, nid
, GetSize(sig
) - 1);
375 add_nid_sig(nid
, sig
);
379 if (cell
->type
.in("$not", "$neg", "$_NOT_"))
382 if (cell
->type
.in("$not", "$_NOT_")) btor_op
= "not";
383 if (cell
->type
== "$neg") btor_op
= "neg";
384 log_assert(!btor_op
.empty());
386 int width
= GetSize(cell
->getPort("\\Y"));
387 width
= std::max(width
, GetSize(cell
->getPort("\\A")));
389 bool a_signed
= cell
->hasParam("\\A_SIGNED") ? cell
->getParam("\\A_SIGNED").as_bool() : false;
391 int sid
= get_bv_sid(width
);
392 int nid_a
= get_sig_nid(cell
->getPort("\\A"), width
, a_signed
);
394 int nid
= next_nid
++;
395 btorf("%d %s %d %d\n", nid
, btor_op
.c_str(), sid
, nid_a
);
397 SigSpec sig
= sigmap(cell
->getPort("\\Y"));
399 if (GetSize(sig
) < width
) {
400 int sid
= get_bv_sid(GetSize(sig
));
401 int nid2
= next_nid
++;
402 btorf("%d slice %d %d %d 0\n", nid2
, sid
, nid
, GetSize(sig
)-1);
406 add_nid_sig(nid
, sig
);
410 if (cell
->type
.in("$logic_and", "$logic_or", "$logic_not"))
413 if (cell
->type
== "$logic_and") btor_op
= "and";
414 if (cell
->type
== "$logic_or") btor_op
= "or";
415 if (cell
->type
== "$logic_not") btor_op
= "not";
416 log_assert(!btor_op
.empty());
418 int sid
= get_bv_sid(1);
419 int nid_a
= get_sig_nid(cell
->getPort("\\A"));
420 int nid_b
= btor_op
!= "not" ? get_sig_nid(cell
->getPort("\\B")) : 0;
422 if (GetSize(cell
->getPort("\\A")) > 1) {
423 int nid_red_a
= next_nid
++;
424 btorf("%d redor %d %d\n", nid_red_a
, sid
, nid_a
);
428 if (btor_op
!= "not" && GetSize(cell
->getPort("\\B")) > 1) {
429 int nid_red_b
= next_nid
++;
430 btorf("%d redor %d %d\n", nid_red_b
, sid
, nid_b
);
434 int nid
= next_nid
++;
435 if (btor_op
!= "not")
436 btorf("%d %s %d %d %d\n", nid
, btor_op
.c_str(), sid
, nid_a
, nid_b
);
438 btorf("%d %s %d %d\n", nid
, btor_op
.c_str(), sid
, nid_a
);
440 SigSpec sig
= sigmap(cell
->getPort("\\Y"));
442 if (GetSize(sig
) > 1) {
443 int sid
= get_bv_sid(GetSize(sig
));
444 int zeros_nid
= get_sig_nid(Const(0, GetSize(sig
)-1));
445 int nid2
= next_nid
++;
446 btorf("%d concat %d %d %d\n", nid2
, sid
, zeros_nid
, nid
);
450 add_nid_sig(nid
, sig
);
454 if (cell
->type
.in("$reduce_and", "$reduce_or", "$reduce_bool", "$reduce_xor", "$reduce_xnor"))
457 if (cell
->type
== "$reduce_and") btor_op
= "redand";
458 if (cell
->type
.in("$reduce_or", "$reduce_bool")) btor_op
= "redor";
459 if (cell
->type
.in("$reduce_xor", "$reduce_xnor")) btor_op
= "redxor";
460 log_assert(!btor_op
.empty());
462 int sid
= get_bv_sid(1);
463 int nid_a
= get_sig_nid(cell
->getPort("\\A"));
465 int nid
= next_nid
++;
466 btorf("%d %s %d %d\n", nid
, btor_op
.c_str(), sid
, nid_a
);
468 if (cell
->type
== "$reduce_xnor") {
469 int nid2
= next_nid
++;
470 btorf("%d not %d %d %d\n", nid2
, sid
, nid
);
474 SigSpec sig
= sigmap(cell
->getPort("\\Y"));
476 if (GetSize(sig
) > 1) {
477 int sid
= get_bv_sid(GetSize(sig
));
478 int zeros_nid
= get_sig_nid(Const(0, GetSize(sig
)-1));
479 int nid2
= next_nid
++;
480 btorf("%d concat %d %d %d\n", nid2
, sid
, zeros_nid
, nid
);
484 add_nid_sig(nid
, sig
);
488 if (cell
->type
.in("$mux", "$_MUX_"))
490 SigSpec sig_a
= sigmap(cell
->getPort("\\A"));
491 SigSpec sig_b
= sigmap(cell
->getPort("\\B"));
492 SigSpec sig_s
= sigmap(cell
->getPort("\\S"));
493 SigSpec sig_y
= sigmap(cell
->getPort("\\Y"));
495 int nid_a
= get_sig_nid(sig_a
);
496 int nid_b
= get_sig_nid(sig_b
);
497 int nid_s
= get_sig_nid(sig_s
);
499 int sid
= get_bv_sid(GetSize(sig_y
));
500 int nid
= next_nid
++;
501 btorf("%d ite %d %d %d %d\n", nid
, sid
, nid_s
, nid_b
, nid_a
);
503 add_nid_sig(nid
, sig_y
);
507 if (cell
->type
== "$pmux")
509 SigSpec sig_a
= sigmap(cell
->getPort("\\A"));
510 SigSpec sig_b
= sigmap(cell
->getPort("\\B"));
511 SigSpec sig_s
= sigmap(cell
->getPort("\\S"));
512 SigSpec sig_y
= sigmap(cell
->getPort("\\Y"));
514 int width
= GetSize(sig_a
);
515 int sid
= get_bv_sid(width
);
516 int nid
= get_sig_nid(sig_a
);
518 for (int i
= 0; i
< GetSize(sig_s
); i
++) {
519 int nid_b
= get_sig_nid(sig_b
.extract(i
*width
, width
));
520 int nid_s
= get_sig_nid(sig_s
.extract(i
));
521 int nid2
= next_nid
++;
522 btorf("%d ite %d %d %d %d\n", nid2
, sid
, nid_s
, nid_b
, nid
);
526 add_nid_sig(nid
, sig_y
);
530 if (cell
->type
.in("$dff", "$ff", "$_DFF_P_", "$_DFF_N", "$_FF_"))
532 SigSpec sig_d
= sigmap(cell
->getPort("\\D"));
533 SigSpec sig_q
= sigmap(cell
->getPort("\\Q"));
537 if (sig_q
.is_wire()) {
538 Wire
*w
= sig_q
.as_wire();
539 if (w
->port_id
== 0) {
540 statewires
.insert(w
);
546 for (int i
= 0; i
< GetSize(sig_q
); i
++)
547 if (initbits
.count(sig_q
[i
]))
548 initval
.bits
.push_back(initbits
.at(sig_q
[i
]) ? State::S1
: State::S0
);
550 initval
.bits
.push_back(State::Sx
);
552 int nid_init_val
= -1;
554 if (!initval
.is_fully_undef())
555 nid_init_val
= get_sig_nid(initval
);
557 int sid
= get_bv_sid(GetSize(sig_q
));
558 int nid
= next_nid
++;
561 btorf("%d state %d\n", nid
, sid
);
563 btorf("%d state %d %s\n", nid
, sid
, log_id(symbol
));
565 if (nid_init_val
>= 0) {
566 int nid_init
= next_nid
++;
568 btorf("; initval = %s\n", log_signal(initval
));
569 btorf("%d init %d %d %d\n", nid_init
, sid
, nid
, nid_init_val
);
572 ff_todo
.push_back(make_pair(nid
, cell
));
573 add_nid_sig(nid
, sig_q
);
577 if (cell
->type
.in("$anyconst", "$anyseq"))
579 SigSpec sig_y
= sigmap(cell
->getPort("\\Y"));
581 int sid
= get_bv_sid(GetSize(sig_y
));
582 int nid
= next_nid
++;
584 btorf("%d state %d\n", nid
, sid
);
586 if (cell
->type
== "$anyconst") {
587 int nid2
= next_nid
++;
588 btorf("%d next %d %d %d\n", nid2
, sid
, nid
, nid
);
591 add_nid_sig(nid
, sig_y
);
595 if (cell
->type
== "$initstate")
597 SigSpec sig_y
= sigmap(cell
->getPort("\\Y"));
599 if (initstate_nid
< 0)
601 int sid
= get_bv_sid(1);
602 int one_nid
= get_sig_nid(Const(1, 1));
603 int zero_nid
= get_sig_nid(Const(0, 1));
604 initstate_nid
= next_nid
++;
605 btorf("%d state %d\n", initstate_nid
, sid
);
606 btorf("%d init %d %d %d\n", next_nid
++, sid
, initstate_nid
, one_nid
);
607 btorf("%d next %d %d %d\n", next_nid
++, sid
, initstate_nid
, zero_nid
);
610 add_nid_sig(initstate_nid
, sig_y
);
614 if (cell
->type
== "$mem")
616 int abits
= cell
->getParam("\\ABITS").as_int();
617 int width
= cell
->getParam("\\WIDTH").as_int();
618 int nwords
= cell
->getParam("\\SIZE").as_int();
619 int rdports
= cell
->getParam("\\RD_PORTS").as_int();
620 int wrports
= cell
->getParam("\\WR_PORTS").as_int();
622 Const wr_clk_en
= cell
->getParam("\\WR_CLK_ENABLE");
623 Const rd_clk_en
= cell
->getParam("\\RD_CLK_ENABLE");
625 bool asyncwr
= wr_clk_en
.is_fully_zero();
627 if (!asyncwr
&& !wr_clk_en
.is_fully_ones())
628 log_error("Memory %s.%s has mixed async/sync write ports.\n",
629 log_id(module
), log_id(cell
));
631 if (!rd_clk_en
.is_fully_zero())
632 log_error("Memory %s.%s has sync read ports.\n",
633 log_id(module
), log_id(cell
));
635 SigSpec sig_rd_addr
= sigmap(cell
->getPort("\\RD_ADDR"));
636 SigSpec sig_rd_data
= sigmap(cell
->getPort("\\RD_DATA"));
638 SigSpec sig_wr_addr
= sigmap(cell
->getPort("\\WR_ADDR"));
639 SigSpec sig_wr_data
= sigmap(cell
->getPort("\\WR_DATA"));
640 SigSpec sig_wr_en
= sigmap(cell
->getPort("\\WR_EN"));
642 int data_sid
= get_bv_sid(width
);
643 int bool_sid
= get_bv_sid(1);
644 int sid
= get_mem_sid(abits
, width
);
646 Const initdata
= cell
->getParam("\\INIT");
647 initdata
.exts(nwords
*width
);
648 int nid_init_val
= -1;
650 if (!initdata
.is_fully_undef())
652 bool constword
= true;
653 Const firstword
= initdata
.extract(0, width
);
655 for (int i
= 1; i
< nwords
; i
++) {
656 Const thisword
= initdata
.extract(i
*width
, width
);
657 if (thisword
!= firstword
) {
666 btorf("; initval = %s\n", log_signal(firstword
));
667 nid_init_val
= get_sig_nid(firstword
);
671 int nid_init_val
= next_nid
++;
672 btorf("%d state %d\n", nid_init_val
, sid
);
674 for (int i
= 0; i
< nwords
; i
++) {
675 Const thisword
= initdata
.extract(i
*width
, width
);
676 if (thisword
.is_fully_undef())
678 Const
thisaddr(i
, abits
);
679 int nid_thisword
= get_sig_nid(thisword
);
680 int nid_thisaddr
= get_sig_nid(thisaddr
);
681 int last_nid_init_val
= nid_init_val
;
682 nid_init_val
= next_nid
++;
684 btorf("; initval[%d] = %s\n", i
, log_signal(thisword
));
685 btorf("%d write %d %d %d %d\n", nid_init_val
, sid
, last_nid_init_val
, nid_thisaddr
, nid_thisword
);
691 int nid
= next_nid
++;
694 if (cell
->name
[0] == '$')
695 btorf("%d state %d\n", nid
, sid
);
697 btorf("%d state %d %s\n", nid
, sid
, log_id(cell
));
699 if (nid_init_val
>= 0)
701 int nid_init
= next_nid
++;
702 btorf("%d init %d %d %d\n", nid_init
, sid
, nid
, nid_init_val
);
707 for (int port
= 0; port
< wrports
; port
++)
709 SigSpec wa
= sig_wr_addr
.extract(port
*abits
, abits
);
710 SigSpec wd
= sig_wr_data
.extract(port
*width
, width
);
711 SigSpec we
= sig_wr_en
.extract(port
*width
, width
);
713 int wa_nid
= get_sig_nid(wa
);
714 int wd_nid
= get_sig_nid(wd
);
715 int we_nid
= get_sig_nid(we
);
717 int nid2
= next_nid
++;
718 btorf("%d read %d %d %d\n", nid2
, data_sid
, nid_head
, wa_nid
);
720 int nid3
= next_nid
++;
721 btorf("%d not %d %d\n", nid3
, data_sid
, we_nid
);
723 int nid4
= next_nid
++;
724 btorf("%d and %d %d %d\n", nid4
, data_sid
, nid2
, nid3
);
726 int nid5
= next_nid
++;
727 btorf("%d and %d %d %d\n", nid5
, data_sid
, wd_nid
, we_nid
);
729 int nid6
= next_nid
++;
730 btorf("%d or %d %d %d\n", nid6
, data_sid
, nid5
, nid4
);
732 int nid7
= next_nid
++;
733 btorf("%d write %d %d %d %d\n", nid7
, sid
, nid_head
, wa_nid
, nid6
);
735 int nid8
= next_nid
++;
736 btorf("%d redor %d %d\n", nid8
, bool_sid
, we_nid
);
738 int nid9
= next_nid
++;
739 btorf("%d ite %d %d %d %d\n", nid9
, sid
, nid8
, nid7
, nid_head
);
745 for (int port
= 0; port
< rdports
; port
++)
747 SigSpec ra
= sig_rd_addr
.extract(port
*abits
, abits
);
748 SigSpec rd
= sig_rd_data
.extract(port
*width
, width
);
750 int ra_nid
= get_sig_nid(ra
);
751 int rd_nid
= next_nid
++;
753 btorf("%d read %d %d %d\n", rd_nid
, data_sid
, nid_head
, ra_nid
);
755 add_nid_sig(rd_nid
, rd
);
760 ff_todo
.push_back(make_pair(nid
, cell
));
764 int nid2
= next_nid
++;
765 btorf("%d next %d %d %d\n", nid2
, sid
, nid
, nid_head
);
771 log_error("Unsupported cell type: %s (%s)\n", log_id(cell
->type
), log_id(cell
));
774 btorf_pop(log_id(cell
));
775 cell_recursion_guard
.erase(cell
);
778 int get_sig_nid(SigSpec sig
, int to_width
= -1, bool is_signed
= false)
784 if (bit
== State::Sx
)
790 SigSpec sig_mask_undef
, sig_noundef
;
791 int first_undef
= -1;
793 for (int i
= 0; i
< GetSize(sig
); i
++)
794 if (sig
[i
] == State::Sx
) {
797 sig_mask_undef
.append(State::S1
);
798 sig_noundef
.append(State::S0
);
800 sig_mask_undef
.append(State::S0
);
801 sig_noundef
.append(sig
[i
]);
804 if (to_width
< 0 || first_undef
< to_width
)
806 int sid
= get_bv_sid(GetSize(sig
));
808 int nid_input
= next_nid
++;
809 btorf("%d input %d\n", nid_input
, sid
);
811 int nid_masked_input
;
812 if (sig_mask_undef
.is_fully_ones()) {
813 nid_masked_input
= nid_input
;
815 int nid_mask_undef
= get_sig_nid(sig_mask_undef
);
816 nid_masked_input
= next_nid
++;
817 btorf("%d and %d %d %d\n", nid_masked_input
, sid
, nid_input
, nid_mask_undef
);
820 if (sig_noundef
.is_fully_zero()) {
821 nid
= nid_masked_input
;
823 int nid_noundef
= get_sig_nid(sig_noundef
);
825 btorf("%d or %d %d %d\n", nid
, sid
, nid_masked_input
, nid_noundef
);
834 if (sig_nid
.count(sig
) == 0)
837 vector
<pair
<int, int>> nidbits
;
840 for (int i
= 0; i
< GetSize(sig
); i
++)
844 if (bit_nid
.count(bit
) == 0)
846 if (bit
.wire
== nullptr)
850 while (i
+GetSize(c
) < GetSize(sig
) && sig
[i
+GetSize(c
)].wire
== nullptr)
851 c
.bits
.push_back(sig
[i
+GetSize(c
)].data
);
853 if (consts
.count(c
) == 0) {
854 int sid
= get_bv_sid(GetSize(c
));
855 int nid
= next_nid
++;
856 btorf("%d const %d %s\n", nid
, sid
, c
.as_string().c_str());
858 nid_width
[nid
] = GetSize(c
);
861 int nid
= consts
.at(c
);
863 for (int j
= 0; j
< GetSize(c
); j
++)
864 nidbits
.push_back(make_pair(nid
, j
));
871 if (bit_cell
.count(bit
) == 0)
872 log_error("No driver for signal bit %s.\n", log_signal(bit
));
873 export_cell(bit_cell
.at(bit
));
874 log_assert(bit_nid
.count(bit
));
878 nidbits
.push_back(bit_nid
.at(bit
));
884 // group bits and emit slice-concat chain
885 for (int i
= 0; i
< GetSize(nidbits
); i
++)
887 int nid2
= nidbits
[i
].first
;
888 int lower
= nidbits
[i
].second
;
891 while (i
+1 < GetSize(nidbits
) && nidbits
[i
+1].first
== nidbits
[i
].first
&&
892 nidbits
[i
+1].second
== nidbits
[i
].second
+1)
897 if (lower
!= 0 || upper
+1 != nid_width
.at(nid2
)) {
898 int sid
= get_bv_sid(upper
-lower
+1);
900 btorf("%d slice %d %d %d %d\n", nid3
, sid
, nid2
, upper
, lower
);
906 int sid
= get_bv_sid(width
+upper
-lower
+1);
908 btorf("%d concat %d %d %d\n", nid4
, sid
, nid3
, nid
);
911 width
+= upper
-lower
+1;
916 nid_width
[nid
] = width
;
919 nid
= sig_nid
.at(sig
);
922 if (to_width
>= 0 && to_width
!= GetSize(sig
))
924 if (to_width
< GetSize(sig
))
926 int sid
= get_bv_sid(to_width
);
927 int nid2
= next_nid
++;
928 btorf("%d slice %d %d %d 0\n", nid2
, sid
, nid
, to_width
-1);
933 int sid
= get_bv_sid(to_width
);
934 int nid2
= next_nid
++;
935 btorf("%d %s %d %d %d\n", nid2
, is_signed
? "sext" : "uext",
936 sid
, nid
, to_width
- GetSize(sig
));
944 BtorWorker(std::ostream
&f
, RTLIL::Module
*module
, bool verbose
, bool single_bad
) :
945 f(f
), sigmap(module
), module(module
), verbose(verbose
), single_bad(single_bad
)
947 btorf_push("inputs");
949 for (auto wire
: module
->wires())
951 if (wire
->attributes
.count("\\init")) {
952 Const attrval
= wire
->attributes
.at("\\init");
953 for (int i
= 0; i
< GetSize(wire
) && i
< GetSize(attrval
); i
++)
954 if (attrval
[i
] == State::S0
|| attrval
[i
] == State::S1
)
955 initbits
[sigmap(SigBit(wire
, i
))] = (attrval
[i
] == State::S1
);
958 if (!wire
->port_id
|| !wire
->port_input
)
961 SigSpec sig
= sigmap(wire
);
962 int sid
= get_bv_sid(GetSize(sig
));
963 int nid
= next_nid
++;
965 btorf("%d input %d %s\n", nid
, sid
, log_id(wire
));
966 add_nid_sig(nid
, sig
);
971 for (auto cell
: module
->cells())
972 for (auto &conn
: cell
->connections())
974 if (!cell
->output(conn
.first
))
977 for (auto bit
: sigmap(conn
.second
))
978 bit_cell
[bit
] = cell
;
981 for (auto wire
: module
->wires())
983 if (!wire
->port_id
|| !wire
->port_output
)
986 btorf_push(stringf("output %s", log_id(wire
)));
988 int nid
= get_sig_nid(wire
);
989 btorf("%d output %d %s\n", next_nid
++, nid
, log_id(wire
));
991 btorf_pop(stringf("output %s", log_id(wire
)));
994 for (auto cell
: module
->cells())
996 if (cell
->type
== "$assume")
998 btorf_push(log_id(cell
));
1000 int sid
= get_bv_sid(1);
1001 int nid_a
= get_sig_nid(cell
->getPort("\\A"));
1002 int nid_en
= get_sig_nid(cell
->getPort("\\EN"));
1003 int nid_not_en
= next_nid
++;
1004 int nid_a_or_not_en
= next_nid
++;
1005 int nid
= next_nid
++;
1007 btorf("%d not %d %d\n", nid_not_en
, sid
, nid_en
);
1008 btorf("%d or %d %d %d\n", nid_a_or_not_en
, sid
, nid_a
, nid_not_en
);
1009 btorf("%d constraint %d\n", nid
, nid_a_or_not_en
);
1011 btorf_pop(log_id(cell
));
1014 if (cell
->type
== "$assert")
1016 btorf_push(log_id(cell
));
1018 int sid
= get_bv_sid(1);
1019 int nid_a
= get_sig_nid(cell
->getPort("\\A"));
1020 int nid_en
= get_sig_nid(cell
->getPort("\\EN"));
1021 int nid_not_a
= next_nid
++;
1022 int nid_en_and_not_a
= next_nid
++;
1024 btorf("%d not %d %d\n", nid_not_a
, sid
, nid_a
);
1025 btorf("%d and %d %d %d\n", nid_en_and_not_a
, sid
, nid_en
, nid_not_a
);
1028 bad_properties
.push_back(nid_en_and_not_a
);
1030 int nid
= next_nid
++;
1031 btorf("%d bad %d\n", nid
, nid_en_and_not_a
);
1034 btorf_pop(log_id(cell
));
1038 for (auto wire
: module
->wires())
1040 if (wire
->port_id
|| wire
->name
[0] == '$')
1043 btorf_push(stringf("wire %s", log_id(wire
)));
1045 int sid
= get_bv_sid(GetSize(wire
));
1046 int nid
= get_sig_nid(sigmap(wire
));
1048 if (statewires
.count(wire
))
1051 int this_nid
= next_nid
++;
1052 btorf("%d uext %d %d %d %s\n", this_nid
, sid
, nid
, 0, log_id(wire
));
1054 btorf_pop(stringf("wire %s", log_id(wire
)));
1058 while (!ff_todo
.empty())
1060 vector
<pair
<int, Cell
*>> todo
;
1063 for (auto &it
: todo
)
1066 Cell
*cell
= it
.second
;
1068 btorf_push(stringf("next %s", log_id(cell
)));
1070 if (cell
->type
== "$mem")
1072 int abits
= cell
->getParam("\\ABITS").as_int();
1073 int width
= cell
->getParam("\\WIDTH").as_int();
1074 int wrports
= cell
->getParam("\\WR_PORTS").as_int();
1076 SigSpec sig_wr_addr
= sigmap(cell
->getPort("\\WR_ADDR"));
1077 SigSpec sig_wr_data
= sigmap(cell
->getPort("\\WR_DATA"));
1078 SigSpec sig_wr_en
= sigmap(cell
->getPort("\\WR_EN"));
1080 int data_sid
= get_bv_sid(width
);
1081 int bool_sid
= get_bv_sid(1);
1082 int sid
= get_mem_sid(abits
, width
);
1085 for (int port
= 0; port
< wrports
; port
++)
1087 SigSpec wa
= sig_wr_addr
.extract(port
*abits
, abits
);
1088 SigSpec wd
= sig_wr_data
.extract(port
*width
, width
);
1089 SigSpec we
= sig_wr_en
.extract(port
*width
, width
);
1091 int wa_nid
= get_sig_nid(wa
);
1092 int wd_nid
= get_sig_nid(wd
);
1093 int we_nid
= get_sig_nid(we
);
1095 int nid2
= next_nid
++;
1096 btorf("%d read %d %d %d\n", nid2
, data_sid
, nid_head
, wa_nid
);
1098 int nid3
= next_nid
++;
1099 btorf("%d not %d %d\n", nid3
, data_sid
, we_nid
);
1101 int nid4
= next_nid
++;
1102 btorf("%d and %d %d %d\n", nid4
, data_sid
, nid2
, nid3
);
1104 int nid5
= next_nid
++;
1105 btorf("%d and %d %d %d\n", nid5
, data_sid
, wd_nid
, we_nid
);
1107 int nid6
= next_nid
++;
1108 btorf("%d or %d %d %d\n", nid6
, data_sid
, nid5
, nid4
);
1110 int nid7
= next_nid
++;
1111 btorf("%d write %d %d %d %d\n", nid7
, sid
, nid_head
, wa_nid
, nid6
);
1113 int nid8
= next_nid
++;
1114 btorf("%d redor %d %d\n", nid8
, bool_sid
, we_nid
);
1116 int nid9
= next_nid
++;
1117 btorf("%d ite %d %d %d %d\n", nid9
, sid
, nid8
, nid7
, nid_head
);
1122 int nid2
= next_nid
++;
1123 btorf("%d next %d %d %d\n", nid2
, sid
, nid
, nid_head
);
1127 SigSpec sig
= sigmap(cell
->getPort("\\D"));
1128 int nid_q
= get_sig_nid(sig
);
1129 int sid
= get_bv_sid(GetSize(sig
));
1130 btorf("%d next %d %d %d\n", next_nid
++, sid
, nid
, nid_q
);
1133 btorf_pop(stringf("next %s", log_id(cell
)));
1137 while (!bad_properties
.empty())
1140 bad_properties
.swap(todo
);
1142 int sid
= get_bv_sid(1);
1145 while (cursor
+1 < GetSize(todo
))
1147 int nid_a
= todo
[cursor
++];
1148 int nid_b
= todo
[cursor
++];
1149 int nid
= next_nid
++;
1151 bad_properties
.push_back(nid
);
1152 btorf("%d or %d %d %d\n", nid
, sid
, nid_a
, nid_b
);
1155 if (!bad_properties
.empty()) {
1156 if (cursor
< GetSize(todo
))
1157 bad_properties
.push_back(todo
[cursor
++]);
1158 log_assert(cursor
== GetSize(todo
));
1160 int nid
= next_nid
++;
1161 log_assert(cursor
== 0);
1162 log_assert(GetSize(todo
) == 1);
1163 btorf("%d bad %d\n", nid
, todo
[cursor
]);
1169 struct BtorBackend
: public Backend
{
1170 BtorBackend() : Backend("btor", "write design to BTOR file") { }
1171 void help() YS_OVERRIDE
1173 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1175 log(" write_btor [options] [filename]\n");
1177 log("Write a BTOR description of the current design.\n");
1180 log(" Add comments and indentation to BTOR output file\n");
1183 log(" Output only a single bad property for all asserts\n");
1186 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
1188 bool verbose
= false, single_bad
= false;
1190 log_header(design
, "Executing BTOR backend.\n");
1193 for (argidx
= 1; argidx
< args
.size(); argidx
++)
1195 if (args
[argidx
] == "-v") {
1199 if (args
[argidx
] == "-s") {
1205 extra_args(f
, filename
, args
, argidx
);
1207 RTLIL::Module
*topmod
= design
->top_module();
1209 if (topmod
== nullptr)
1210 log_cmd_error("No top module found.\n");
1212 *f
<< stringf("; BTOR description generated by %s for module %s.\n",
1213 yosys_version_str
, log_id(topmod
));
1215 BtorWorker(*f
, topmod
, verbose
, single_bad
);
1217 *f
<< stringf("; end of yosys output\n");
1221 PRIVATE_NAMESPACE_END