2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2014 Claire Xenia Wolf <claire@yosyshq.com>
5 * Copyright (C) 2014 Johann Glaser <Johann.Glaser@gmx.at>
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 #include "kernel/yosys.h"
22 #include "kernel/satgen.h"
23 #include "kernel/consteval.h"
24 #include "kernel/celledges.h"
25 #include "kernel/macc.h"
29 PRIVATE_NAMESPACE_BEGIN
31 static uint32_t xorshift32_state
= 123456789;
33 static uint32_t xorshift32(uint32_t limit
) {
34 xorshift32_state
^= xorshift32_state
<< 13;
35 xorshift32_state
^= xorshift32_state
>> 17;
36 xorshift32_state
^= xorshift32_state
<< 5;
37 return xorshift32_state
% limit
;
40 static void create_gold_module(RTLIL::Design
*design
, RTLIL::IdString cell_type
, std::string cell_type_flags
, bool constmode
, bool muxdiv
)
42 RTLIL::Module
*module
= design
->addModule(ID(gold
));
43 RTLIL::Cell
*cell
= module
->addCell(ID(UUT
), cell_type
);
46 if (cell_type
.in(ID($mux
), ID($pmux
)))
48 int width
= 1 + xorshift32(8);
49 int swidth
= cell_type
== ID($mux
) ? 1 : 1 + xorshift32(8);
51 wire
= module
->addWire(ID::A
);
53 wire
->port_input
= true;
54 cell
->setPort(ID::A
, wire
);
56 wire
= module
->addWire(ID::B
);
57 wire
->width
= width
* swidth
;
58 wire
->port_input
= true;
59 cell
->setPort(ID::B
, wire
);
61 wire
= module
->addWire(ID::S
);
63 wire
->port_input
= true;
64 cell
->setPort(ID::S
, wire
);
66 wire
= module
->addWire(ID::Y
);
68 wire
->port_output
= true;
69 cell
->setPort(ID::Y
, wire
);
72 if (cell_type
== ID($bmux
))
74 int width
= 1 + xorshift32(8);
75 int swidth
= 1 + xorshift32(4);
77 wire
= module
->addWire(ID::A
);
78 wire
->width
= width
<< swidth
;
79 wire
->port_input
= true;
80 cell
->setPort(ID::A
, wire
);
82 wire
= module
->addWire(ID::S
);
84 wire
->port_input
= true;
85 cell
->setPort(ID::S
, wire
);
87 wire
= module
->addWire(ID::Y
);
89 wire
->port_output
= true;
90 cell
->setPort(ID::Y
, wire
);
93 if (cell_type
== ID($demux
))
95 int width
= 1 + xorshift32(8);
96 int swidth
= 1 + xorshift32(6);
98 wire
= module
->addWire(ID::A
);
100 wire
->port_input
= true;
101 cell
->setPort(ID::A
, wire
);
103 wire
= module
->addWire(ID::S
);
104 wire
->width
= swidth
;
105 wire
->port_input
= true;
106 cell
->setPort(ID::S
, wire
);
108 wire
= module
->addWire(ID::Y
);
109 wire
->width
= width
<< swidth
;
110 wire
->port_output
= true;
111 cell
->setPort(ID::Y
, wire
);
114 if (cell_type
== ID($fa
))
116 int width
= 1 + xorshift32(8);
118 wire
= module
->addWire(ID::A
);
120 wire
->port_input
= true;
121 cell
->setPort(ID::A
, wire
);
123 wire
= module
->addWire(ID::B
);
125 wire
->port_input
= true;
126 cell
->setPort(ID::B
, wire
);
128 wire
= module
->addWire(ID::C
);
130 wire
->port_input
= true;
131 cell
->setPort(ID::C
, wire
);
133 wire
= module
->addWire(ID::X
);
135 wire
->port_output
= true;
136 cell
->setPort(ID::X
, wire
);
138 wire
= module
->addWire(ID::Y
);
140 wire
->port_output
= true;
141 cell
->setPort(ID::Y
, wire
);
144 if (cell_type
== ID($lcu
))
146 int width
= 1 + xorshift32(8);
148 wire
= module
->addWire(ID::P
);
150 wire
->port_input
= true;
151 cell
->setPort(ID::P
, wire
);
153 wire
= module
->addWire(ID::G
);
155 wire
->port_input
= true;
156 cell
->setPort(ID::G
, wire
);
158 wire
= module
->addWire(ID::CI
);
159 wire
->port_input
= true;
160 cell
->setPort(ID::CI
, wire
);
162 wire
= module
->addWire(ID::CO
);
164 wire
->port_output
= true;
165 cell
->setPort(ID::CO
, wire
);
168 if (cell_type
== ID($macc
))
171 int width
= 1 + xorshift32(8);
172 int depth
= 1 + xorshift32(6);
173 int mulbits_a
= 0, mulbits_b
= 0;
175 RTLIL::Wire
*wire_a
= module
->addWire(ID::A
);
177 wire_a
->port_input
= true;
179 for (int i
= 0; i
< depth
; i
++)
181 int size_a
= xorshift32(width
) + 1;
182 int size_b
= depth
> 4 ? 0 : xorshift32(width
) + 1;
184 if (mulbits_a
+ size_a
*size_b
<= 96 && mulbits_b
+ size_a
+ size_b
<= 16 && xorshift32(2) == 1) {
185 mulbits_a
+= size_a
* size_b
;
186 mulbits_b
+= size_a
+ size_b
;
190 Macc::port_t this_port
;
192 wire_a
->width
+= size_a
;
193 this_port
.in_a
= RTLIL::SigSpec(wire_a
, wire_a
->width
- size_a
, size_a
);
195 wire_a
->width
+= size_b
;
196 this_port
.in_b
= RTLIL::SigSpec(wire_a
, wire_a
->width
- size_b
, size_b
);
198 this_port
.is_signed
= xorshift32(2) == 1;
199 this_port
.do_subtract
= xorshift32(2) == 1;
200 macc
.ports
.push_back(this_port
);
203 wire
= module
->addWire(ID::B
);
204 wire
->width
= xorshift32(mulbits_a
? xorshift32(4)+1 : xorshift32(16)+1);
205 wire
->port_input
= true;
206 macc
.bit_ports
= wire
;
208 wire
= module
->addWire(ID::Y
);
210 wire
->port_output
= true;
211 cell
->setPort(ID::Y
, wire
);
216 if (cell_type
== ID($lut
))
218 int width
= 1 + xorshift32(6);
220 wire
= module
->addWire(ID::A
);
222 wire
->port_input
= true;
223 cell
->setPort(ID::A
, wire
);
225 wire
= module
->addWire(ID::Y
);
226 wire
->port_output
= true;
227 cell
->setPort(ID::Y
, wire
);
229 RTLIL::SigSpec config
;
230 for (int i
= 0; i
< (1 << width
); i
++)
231 config
.append(xorshift32(2) ? State::S1
: State::S0
);
233 cell
->setParam(ID::LUT
, config
.as_const());
236 if (cell_type
== ID($sop
))
238 int width
= 1 + xorshift32(8);
239 int depth
= 1 + xorshift32(8);
241 wire
= module
->addWire(ID::A
);
243 wire
->port_input
= true;
244 cell
->setPort(ID::A
, wire
);
246 wire
= module
->addWire(ID::Y
);
247 wire
->port_output
= true;
248 cell
->setPort(ID::Y
, wire
);
250 RTLIL::SigSpec config
;
251 for (int i
= 0; i
< width
*depth
; i
++)
252 switch (xorshift32(3)) {
254 config
.append(State::S1
);
255 config
.append(State::S0
);
258 config
.append(State::S0
);
259 config
.append(State::S1
);
262 config
.append(State::S0
);
263 config
.append(State::S0
);
267 cell
->setParam(ID::DEPTH
, depth
);
268 cell
->setParam(ID::TABLE
, config
.as_const());
271 if (cell_type_flags
.find('A') != std::string::npos
) {
272 wire
= module
->addWire(ID::A
);
273 wire
->width
= 1 + xorshift32(8);
274 wire
->port_input
= true;
275 cell
->setPort(ID::A
, wire
);
278 if (cell_type_flags
.find('B') != std::string::npos
) {
279 wire
= module
->addWire(ID::B
);
280 if (cell_type_flags
.find('h') != std::string::npos
)
281 wire
->width
= 1 + xorshift32(6);
283 wire
->width
= 1 + xorshift32(8);
284 wire
->port_input
= true;
285 cell
->setPort(ID::B
, wire
);
288 if (cell_type_flags
.find('S') != std::string::npos
&& xorshift32(2)) {
289 if (cell_type_flags
.find('A') != std::string::npos
)
290 cell
->parameters
[ID::A_SIGNED
] = true;
291 if (cell_type_flags
.find('B') != std::string::npos
)
292 cell
->parameters
[ID::B_SIGNED
] = true;
295 if (cell_type_flags
.find('s') != std::string::npos
) {
296 if (cell_type_flags
.find('A') != std::string::npos
&& xorshift32(2))
297 cell
->parameters
[ID::A_SIGNED
] = true;
298 if (cell_type_flags
.find('B') != std::string::npos
&& xorshift32(2))
299 cell
->parameters
[ID::B_SIGNED
] = true;
302 if (cell_type_flags
.find('Y') != std::string::npos
) {
303 wire
= module
->addWire(ID::Y
);
304 wire
->width
= 1 + xorshift32(8);
305 wire
->port_output
= true;
306 cell
->setPort(ID::Y
, wire
);
309 if (cell_type
.in(ID($shiftx
))) {
310 cell
->parameters
[ID::A_SIGNED
] = false;
313 if (cell_type
.in(ID($shl
), ID($shr
), ID($sshl
), ID($sshr
))) {
314 cell
->parameters
[ID::B_SIGNED
] = false;
317 if (muxdiv
&& cell_type
.in(ID($div
), ID($mod
), ID($divfloor
), ID($modfloor
))) {
318 auto b_not_zero
= module
->ReduceBool(NEW_ID
, cell
->getPort(ID::B
));
319 auto div_out
= module
->addWire(NEW_ID
, GetSize(cell
->getPort(ID::Y
)));
320 module
->addMux(NEW_ID
, RTLIL::SigSpec(0, GetSize(div_out
)), div_out
, b_not_zero
, cell
->getPort(ID::Y
));
321 cell
->setPort(ID::Y
, div_out
);
324 if (cell_type
== ID($alu
))
326 wire
= module
->addWire(ID::CI
);
327 wire
->port_input
= true;
328 cell
->setPort(ID::CI
, wire
);
330 wire
= module
->addWire(ID::BI
);
331 wire
->port_input
= true;
332 cell
->setPort(ID::BI
, wire
);
334 wire
= module
->addWire(ID::X
);
335 wire
->width
= GetSize(cell
->getPort(ID::Y
));
336 wire
->port_output
= true;
337 cell
->setPort(ID::X
, wire
);
339 wire
= module
->addWire(ID::CO
);
340 wire
->width
= GetSize(cell
->getPort(ID::Y
));
341 wire
->port_output
= true;
342 cell
->setPort(ID::CO
, wire
);
347 auto conn_list
= cell
->connections();
348 for (auto &conn
: conn_list
)
350 RTLIL::SigSpec sig
= conn
.second
;
352 if (GetSize(sig
) == 0 || sig
[0].wire
== nullptr || sig
[0].wire
->port_output
)
356 switch (xorshift32(5))
359 n
= xorshift32(GetSize(sig
) + 1);
360 for (int i
= 0; i
< n
; i
++)
361 sig
[i
] = xorshift32(2) == 1 ? State::S1
: State::S0
;
364 n
= xorshift32(GetSize(sig
) + 1);
365 for (int i
= n
; i
< GetSize(sig
); i
++)
366 sig
[i
] = xorshift32(2) == 1 ? State::S1
: State::S0
;
369 n
= xorshift32(GetSize(sig
));
370 m
= xorshift32(GetSize(sig
));
371 for (int i
= min(n
, m
); i
< max(n
, m
); i
++)
372 sig
[i
] = xorshift32(2) == 1 ? State::S1
: State::S0
;
376 cell
->setPort(conn
.first
, sig
);
380 module
->fixup_ports();
381 cell
->fixup_parameters();
385 static void run_edges_test(RTLIL::Design
*design
, bool verbose
)
387 Module
*module
= *design
->modules().begin();
388 Cell
*cell
= *module
->cells().begin();
391 ezSAT
&ez
= *ezptr
.get();
393 SigMap
sigmap(module
);
394 SatGen
satgen(&ez
, &sigmap
);
396 FwdCellEdgesDatabase
edges_db(sigmap
);
397 if (!edges_db
.add_edges_from_cell(cell
))
398 log_error("Creating edge database failed for this cell!\n");
400 dict
<SigBit
, pool
<SigBit
>> satgen_db
;
402 satgen
.setContext(&sigmap
, "X:");
403 satgen
.importCell(cell
);
405 satgen
.setContext(&sigmap
, "Y:");
406 satgen
.importCell(cell
);
408 vector
<tuple
<SigBit
, int, int>> input_db
, output_db
;
410 for (auto &conn
: cell
->connections())
412 SigSpec bits
= sigmap(conn
.second
);
414 satgen
.setContext(&sigmap
, "X:");
415 std::vector
<int> xbits
= satgen
.importSigSpec(bits
);
417 satgen
.setContext(&sigmap
, "Y:");
418 std::vector
<int> ybits
= satgen
.importSigSpec(bits
);
420 for (int i
= 0; i
< GetSize(bits
); i
++)
421 if (cell
->input(conn
.first
))
422 input_db
.emplace_back(bits
[i
], xbits
[i
], ybits
[i
]);
424 output_db
.emplace_back(bits
[i
], xbits
[i
], ybits
[i
]);
428 log("\nSAT solving for all edges:\n");
430 for (int i
= 0; i
< GetSize(input_db
); i
++)
432 SigBit inbit
= std::get
<0>(input_db
[i
]);
435 log(" Testing input signal %s:\n", log_signal(inbit
));
437 vector
<int> xinbits
, yinbits
;
438 for (int k
= 0; k
< GetSize(input_db
); k
++)
440 xinbits
.push_back(std::get
<1>(input_db
[k
]));
441 yinbits
.push_back(std::get
<2>(input_db
[k
]));
444 int xyinbit_ok
= ez
.vec_eq(xinbits
, yinbits
);
446 for (int k
= 0; k
< GetSize(output_db
); k
++)
448 SigBit outbit
= std::get
<0>(output_db
[k
]);
449 int xoutbit
= std::get
<1>(output_db
[k
]);
450 int youtbit
= std::get
<2>(output_db
[k
]);
452 bool is_edge
= ez
.solve(xyinbit_ok
, ez
.XOR(xoutbit
, youtbit
));
455 satgen_db
[inbit
].insert(outbit
);
458 bool is_ref_edge
= edges_db
.db
.count(inbit
) && edges_db
.db
.at(inbit
).count(outbit
);
459 log(" %c %s %s\n", is_edge
? 'x' : 'o', log_signal(outbit
), is_edge
== is_ref_edge
? "OK" : "ERROR");
464 if (satgen_db
== edges_db
.db
)
467 log_error("SAT-based edge table does not match the database!\n");
470 static void run_eval_test(RTLIL::Design
*design
, bool verbose
, bool nosat
, std::string uut_name
, std::ofstream
&vlog_file
)
472 log("Eval testing:%c", verbose
? '\n' : ' ');
474 RTLIL::Module
*gold_mod
= design
->module(ID(gold
));
475 RTLIL::Module
*gate_mod
= design
->module(ID(gate
));
476 ConstEval
gold_ce(gold_mod
), gate_ce(gate_mod
);
479 SigMap
sigmap(gold_mod
);
480 SatGen
satgen1(ez1
.get(), &sigmap
);
481 SatGen
satgen2(ez2
.get(), &sigmap
);
482 satgen2
.model_undef
= true;
485 for (auto cell
: gold_mod
->cells()) {
486 satgen1
.importCell(cell
);
487 satgen2
.importCell(cell
);
490 if (vlog_file
.is_open())
492 vlog_file
<< stringf("\nmodule %s;\n", uut_name
.c_str());
494 for (auto port
: gold_mod
->ports
) {
495 RTLIL::Wire
*wire
= gold_mod
->wire(port
);
496 if (wire
->port_input
)
497 vlog_file
<< stringf(" reg [%d:0] %s;\n", GetSize(wire
)-1, log_id(wire
));
499 vlog_file
<< stringf(" wire [%d:0] %s_expr, %s_noexpr;\n", GetSize(wire
)-1, log_id(wire
), log_id(wire
));
502 vlog_file
<< stringf(" %s_expr uut_expr(", uut_name
.c_str());
503 for (int i
= 0; i
< GetSize(gold_mod
->ports
); i
++)
504 vlog_file
<< stringf("%s.%s(%s%s)", i
? ", " : "", log_id(gold_mod
->ports
[i
]), log_id(gold_mod
->ports
[i
]),
505 gold_mod
->wire(gold_mod
->ports
[i
])->port_input
? "" : "_expr");
506 vlog_file
<< stringf(");\n");
508 vlog_file
<< stringf(" %s_expr uut_noexpr(", uut_name
.c_str());
509 for (int i
= 0; i
< GetSize(gold_mod
->ports
); i
++)
510 vlog_file
<< stringf("%s.%s(%s%s)", i
? ", " : "", log_id(gold_mod
->ports
[i
]), log_id(gold_mod
->ports
[i
]),
511 gold_mod
->wire(gold_mod
->ports
[i
])->port_input
? "" : "_noexpr");
512 vlog_file
<< stringf(");\n");
514 vlog_file
<< stringf(" task run;\n");
515 vlog_file
<< stringf(" begin\n");
516 vlog_file
<< stringf(" $display(\"%s\");\n", uut_name
.c_str());
519 for (int i
= 0; i
< 64; i
++)
521 log(verbose
? "\n" : ".");
525 RTLIL::SigSpec in_sig
, in_val
;
526 RTLIL::SigSpec out_sig
, out_val
;
527 std::string vlog_pattern_info
;
529 for (auto port
: gold_mod
->ports
)
531 RTLIL::Wire
*gold_wire
= gold_mod
->wire(port
);
532 RTLIL::Wire
*gate_wire
= gate_mod
->wire(port
);
534 log_assert(gold_wire
!= nullptr);
535 log_assert(gate_wire
!= nullptr);
536 log_assert(gold_wire
->port_input
== gate_wire
->port_input
);
537 log_assert(GetSize(gold_wire
) == GetSize(gate_wire
));
539 if (!gold_wire
->port_input
)
542 RTLIL::Const in_value
;
543 for (int i
= 0; i
< GetSize(gold_wire
); i
++)
544 in_value
.bits
.push_back(xorshift32(2) ? State::S1
: State::S0
);
546 if (xorshift32(4) == 0) {
547 int inv_chance
= 1 + xorshift32(8);
548 for (int i
= 0; i
< GetSize(gold_wire
); i
++)
549 if (xorshift32(inv_chance
) == 0)
550 in_value
.bits
[i
] = RTLIL::Sx
;
554 log("%s: %s\n", log_id(gold_wire
), log_signal(in_value
));
556 in_sig
.append(gold_wire
);
557 in_val
.append(in_value
);
559 gold_ce
.set(gold_wire
, in_value
);
560 gate_ce
.set(gate_wire
, in_value
);
562 if (vlog_file
.is_open() && GetSize(in_value
) > 0) {
563 vlog_file
<< stringf(" %s = 'b%s;\n", log_id(gold_wire
), in_value
.as_string().c_str());
564 if (!vlog_pattern_info
.empty())
565 vlog_pattern_info
+= " ";
566 vlog_pattern_info
+= stringf("%s=%s", log_id(gold_wire
), log_signal(in_value
));
570 if (vlog_file
.is_open())
571 vlog_file
<< stringf(" #1;\n");
573 for (auto port
: gold_mod
->ports
)
575 RTLIL::Wire
*gold_wire
= gold_mod
->wire(port
);
576 RTLIL::Wire
*gate_wire
= gate_mod
->wire(port
);
578 log_assert(gold_wire
!= nullptr);
579 log_assert(gate_wire
!= nullptr);
580 log_assert(gold_wire
->port_output
== gate_wire
->port_output
);
581 log_assert(GetSize(gold_wire
) == GetSize(gate_wire
));
583 if (!gold_wire
->port_output
)
586 RTLIL::SigSpec
gold_outval(gold_wire
);
587 RTLIL::SigSpec
gate_outval(gate_wire
);
589 if (!gold_ce
.eval(gold_outval
))
590 log_error("Failed to eval %s in gold module.\n", log_id(gold_wire
));
592 if (!gate_ce
.eval(gate_outval
))
593 log_error("Failed to eval %s in gate module.\n", log_id(gate_wire
));
595 bool gold_gate_mismatch
= false;
596 for (int i
= 0; i
< GetSize(gold_wire
); i
++) {
597 if (gold_outval
[i
] == RTLIL::Sx
)
599 if (gold_outval
[i
] == gate_outval
[i
])
601 gold_gate_mismatch
= true;
605 if (gold_gate_mismatch
)
606 log_error("Mismatch in output %s: gold:%s != gate:%s\n", log_id(gate_wire
), log_signal(gold_outval
), log_signal(gate_outval
));
609 log("%s: %s\n", log_id(gold_wire
), log_signal(gold_outval
));
611 out_sig
.append(gold_wire
);
612 out_val
.append(gold_outval
);
614 if (vlog_file
.is_open()) {
615 vlog_file
<< stringf(" $display(\"[%s] %s expected: %%b, expr: %%b, noexpr: %%b\", %d'b%s, %s_expr, %s_noexpr);\n",
616 vlog_pattern_info
.c_str(), log_id(gold_wire
), GetSize(gold_outval
), gold_outval
.as_string().c_str(), log_id(gold_wire
), log_id(gold_wire
));
617 vlog_file
<< stringf(" if (%s_expr !== %d'b%s) begin $display(\"ERROR\"); $finish; end\n", log_id(gold_wire
), GetSize(gold_outval
), gold_outval
.as_string().c_str());
618 vlog_file
<< stringf(" if (%s_noexpr !== %d'b%s) begin $display(\"ERROR\"); $finish; end\n", log_id(gold_wire
), GetSize(gold_outval
), gold_outval
.as_string().c_str());
623 log("EVAL: %s\n", out_val
.as_string().c_str());
627 std::vector
<int> sat1_in_sig
= satgen1
.importSigSpec(in_sig
);
628 std::vector
<int> sat1_in_val
= satgen1
.importSigSpec(in_val
);
630 std::vector
<int> sat1_model
= satgen1
.importSigSpec(out_sig
);
631 std::vector
<bool> sat1_model_value
;
633 if (!ez1
->solve(sat1_model
, sat1_model_value
, ez1
->vec_eq(sat1_in_sig
, sat1_in_val
)))
634 log_error("Evaluating sat model 1 (no undef modeling) failed!\n");
638 for (int i
= GetSize(out_sig
)-1; i
>= 0; i
--)
639 log("%c", sat1_model_value
.at(i
) ? '1' : '0');
643 for (int i
= 0; i
< GetSize(out_sig
); i
++) {
644 if (out_val
[i
] != State::S0
&& out_val
[i
] != State::S1
)
646 if (out_val
[i
] == State::S0
&& sat1_model_value
.at(i
) == false)
648 if (out_val
[i
] == State::S1
&& sat1_model_value
.at(i
) == true)
650 log_error("Mismatch in sat model 1 (no undef modeling) output!\n");
653 std::vector
<int> sat2_in_def_sig
= satgen2
.importDefSigSpec(in_sig
);
654 std::vector
<int> sat2_in_def_val
= satgen2
.importDefSigSpec(in_val
);
656 std::vector
<int> sat2_in_undef_sig
= satgen2
.importUndefSigSpec(in_sig
);
657 std::vector
<int> sat2_in_undef_val
= satgen2
.importUndefSigSpec(in_val
);
659 std::vector
<int> sat2_model_def_sig
= satgen2
.importDefSigSpec(out_sig
);
660 std::vector
<int> sat2_model_undef_sig
= satgen2
.importUndefSigSpec(out_sig
);
662 std::vector
<int> sat2_model
;
663 sat2_model
.insert(sat2_model
.end(), sat2_model_def_sig
.begin(), sat2_model_def_sig
.end());
664 sat2_model
.insert(sat2_model
.end(), sat2_model_undef_sig
.begin(), sat2_model_undef_sig
.end());
666 std::vector
<bool> sat2_model_value
;
668 if (!ez2
->solve(sat2_model
, sat2_model_value
, ez2
->vec_eq(sat2_in_def_sig
, sat2_in_def_val
), ez2
->vec_eq(sat2_in_undef_sig
, sat2_in_undef_val
)))
669 log_error("Evaluating sat model 2 (undef modeling) failed!\n");
673 for (int i
= GetSize(out_sig
)-1; i
>= 0; i
--)
674 log("%c", sat2_model_value
.at(GetSize(out_sig
) + i
) ? 'x' : sat2_model_value
.at(i
) ? '1' : '0');
678 for (int i
= 0; i
< GetSize(out_sig
); i
++) {
679 if (sat2_model_value
.at(GetSize(out_sig
) + i
)) {
680 if (out_val
[i
] != State::S0
&& out_val
[i
] != State::S1
)
683 if (out_val
[i
] == State::S0
&& sat2_model_value
.at(i
) == false)
685 if (out_val
[i
] == State::S1
&& sat2_model_value
.at(i
) == true)
688 log_error("Mismatch in sat model 2 (undef modeling) output!\n");
693 if (vlog_file
.is_open()) {
694 vlog_file
<< stringf(" end\n");
695 vlog_file
<< stringf(" endtask\n");
696 vlog_file
<< stringf("endmodule\n");
703 struct TestCellPass
: public Pass
{
704 TestCellPass() : Pass("test_cell", "automatically test the implementation of a cell type") { }
707 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
709 log(" test_cell [options] {cell-types}\n");
711 log("Tests the internal implementation of the given cell type (for example '$add')\n");
712 log("by comparing SAT solver, EVAL and TECHMAP implementations of the cell types..\n");
714 log("Run with 'all' instead of a cell type to run the test on all supported\n");
715 log("cell types. Use for example 'all /$add' for all cell types except $add.\n");
717 log(" -n {integer}\n");
718 log(" create this number of cell instances and test them (default = 100).\n");
720 log(" -s {positive_integer}\n");
721 log(" use this value as rng seed value (default = unix time).\n");
723 log(" -f {rtlil_file}\n");
724 log(" don't generate circuits. instead load the specified RTLIL file.\n");
726 log(" -w {filename_prefix}\n");
727 log(" don't test anything. just generate the circuits and write them\n");
728 log(" to RTLIL files with the specified prefix\n");
730 log(" -map {filename}\n");
731 log(" pass this option to techmap.\n");
734 log(" use \"techmap -D SIMLIB_NOCHECKS -map +/simlib.v -max_iter 2 -autoproc\"\n");
737 log(" instead of calling \"techmap\", call \"aigmap\"\n");
740 log(" when creating test benches with dividers, create an additional mux\n");
741 log(" to mask out the division-by-zero case\n");
743 log(" -script {script_file}\n");
744 log(" instead of calling \"techmap\", call \"script {script_file}\".\n");
747 log(" set some input bits to random constant values\n");
750 log(" do not check SAT model or run SAT equivalence checking\n");
753 log(" do not check const-eval models\n");
756 log(" test cell edges db creator against sat-based implementation\n");
759 log(" print additional debug information to the console\n");
761 log(" -vlog {filename}\n");
762 log(" create a Verilog test bench to test simlib and write_verilog\n");
765 void execute(std::vector
<std::string
> args
, RTLIL::Design
*) override
768 std::string techmap_cmd
= "techmap -assert";
769 std::string rtlil_file
, write_prefix
;
770 xorshift32_state
= 0;
771 std::ofstream vlog_file
;
773 bool verbose
= false;
774 bool constmode
= false;
780 for (argidx
= 1; argidx
< GetSize(args
); argidx
++)
782 if (args
[argidx
] == "-n" && argidx
+1 < GetSize(args
)) {
783 num_iter
= atoi(args
[++argidx
].c_str());
786 if (args
[argidx
] == "-s" && argidx
+1 < GetSize(args
)) {
787 xorshift32_state
= atoi(args
[++argidx
].c_str());
790 if (args
[argidx
] == "-map" && argidx
+1 < GetSize(args
)) {
791 techmap_cmd
+= " -map " + args
[++argidx
];
794 if (args
[argidx
] == "-f" && argidx
+1 < GetSize(args
)) {
795 rtlil_file
= args
[++argidx
];
799 if (args
[argidx
] == "-w" && argidx
+1 < GetSize(args
)) {
800 write_prefix
= args
[++argidx
];
803 if (args
[argidx
] == "-script" && argidx
+1 < GetSize(args
)) {
804 techmap_cmd
= "script " + args
[++argidx
];
807 if (args
[argidx
] == "-simlib") {
808 techmap_cmd
= "techmap -D SIMLIB_NOCHECKS -map +/simlib.v -max_iter 2 -autoproc";
811 if (args
[argidx
] == "-aigmap") {
812 techmap_cmd
= "aigmap";
815 if (args
[argidx
] == "-muxdiv") {
819 if (args
[argidx
] == "-const") {
823 if (args
[argidx
] == "-nosat") {
827 if (args
[argidx
] == "-noeval") {
831 if (args
[argidx
] == "-edges") {
835 if (args
[argidx
] == "-v") {
839 if (args
[argidx
] == "-vlog" && argidx
+1 < GetSize(args
)) {
840 vlog_file
.open(args
[++argidx
], std::ios_base::trunc
);
841 if (!vlog_file
.is_open())
842 log_cmd_error("Failed to open output file `%s'.\n", args
[argidx
].c_str());
848 if (xorshift32_state
== 0) {
849 xorshift32_state
= time(NULL
) & 0x7fffffff;
850 log("Rng seed value: %d\n", int(xorshift32_state
));
853 std::map
<IdString
, std::string
> cell_types
;
854 std::vector
<IdString
> selected_cell_types
;
856 cell_types
[ID($
not)] = "ASY";
857 cell_types
[ID($pos
)] = "ASY";
858 cell_types
[ID($neg
)] = "ASY";
860 cell_types
[ID($
and)] = "ABSY";
861 cell_types
[ID($
or)] = "ABSY";
862 cell_types
[ID($
xor)] = "ABSY";
863 cell_types
[ID($xnor
)] = "ABSY";
865 cell_types
[ID($reduce_and
)] = "ASY";
866 cell_types
[ID($reduce_or
)] = "ASY";
867 cell_types
[ID($reduce_xor
)] = "ASY";
868 cell_types
[ID($reduce_xnor
)] = "ASY";
869 cell_types
[ID($reduce_bool
)] = "ASY";
871 cell_types
[ID($shl
)] = "ABshY";
872 cell_types
[ID($shr
)] = "ABshY";
873 cell_types
[ID($sshl
)] = "ABshY";
874 cell_types
[ID($sshr
)] = "ABshY";
875 cell_types
[ID($shift
)] = "ABshY";
876 cell_types
[ID($shiftx
)] = "ABshY";
878 cell_types
[ID($lt
)] = "ABSY";
879 cell_types
[ID($le
)] = "ABSY";
880 cell_types
[ID($eq
)] = "ABSY";
881 cell_types
[ID($ne
)] = "ABSY";
882 // cell_types[ID($eqx)] = "ABSY";
883 // cell_types[ID($nex)] = "ABSY";
884 cell_types
[ID($ge
)] = "ABSY";
885 cell_types
[ID($gt
)] = "ABSY";
887 cell_types
[ID($add
)] = "ABSY";
888 cell_types
[ID($sub
)] = "ABSY";
889 cell_types
[ID($mul
)] = "ABSY";
890 cell_types
[ID($div
)] = "ABSY";
891 cell_types
[ID($mod
)] = "ABSY";
892 cell_types
[ID($divfloor
)] = "ABSY";
893 cell_types
[ID($modfloor
)] = "ABSY";
894 // cell_types[ID($pow)] = "ABsY";
896 cell_types
[ID($logic_not
)] = "ASY";
897 cell_types
[ID($logic_and
)] = "ABSY";
898 cell_types
[ID($logic_or
)] = "ABSY";
900 cell_types
[ID($mux
)] = "*";
901 cell_types
[ID($bmux
)] = "*";
902 cell_types
[ID($demux
)] = "*";
904 cell_types
[ID($pmux
)] = "*";
907 // cell_types[ID($slice)] = "A";
908 // cell_types[ID($concat)] = "A";
910 cell_types
[ID($lut
)] = "*";
911 cell_types
[ID($sop
)] = "*";
912 cell_types
[ID($alu
)] = "ABSY";
913 cell_types
[ID($lcu
)] = "*";
914 cell_types
[ID($macc
)] = "*";
915 cell_types
[ID($fa
)] = "*";
917 for (; argidx
< GetSize(args
); argidx
++)
919 if (args
[argidx
].rfind("-", 0) == 0)
920 log_cmd_error("Unexpected option: %s\n", args
[argidx
].c_str());
922 if (args
[argidx
] == "all") {
923 for (auto &it
: cell_types
)
924 if (std::count(selected_cell_types
.begin(), selected_cell_types
.end(), it
.first
) == 0)
925 selected_cell_types
.push_back(it
.first
);
929 if (args
[argidx
].compare(0, 1, "/") == 0) {
930 std::vector
<IdString
> new_selected_cell_types
;
931 for (auto it
: selected_cell_types
)
932 if (it
!= args
[argidx
].substr(1))
933 new_selected_cell_types
.push_back(it
);
934 new_selected_cell_types
.swap(selected_cell_types
);
938 if (cell_types
.count(args
[argidx
]) == 0) {
939 std::string cell_type_list
;
941 for (auto &it
: cell_types
) {
942 if (charcount
> 60) {
943 cell_type_list
+= stringf("\n%s", + log_id(it
.first
));
946 cell_type_list
+= stringf(" %s", log_id(it
.first
));
947 charcount
+= GetSize(it
.first
);
949 log_cmd_error("The cell type `%s' is currently not supported. Try one of these:%s\n",
950 args
[argidx
].c_str(), cell_type_list
.c_str());
953 if (std::count(selected_cell_types
.begin(), selected_cell_types
.end(), args
[argidx
]) == 0)
954 selected_cell_types
.push_back(args
[argidx
]);
957 if (!rtlil_file
.empty()) {
958 if (!selected_cell_types
.empty())
959 log_cmd_error("Do not specify any cell types when using -f.\n");
960 selected_cell_types
.push_back(ID(rtlil
));
963 if (selected_cell_types
.empty())
964 log_cmd_error("No cell type to test specified.\n");
966 std::vector
<std::string
> uut_names
;
968 for (auto cell_type
: selected_cell_types
)
969 for (int i
= 0; i
< num_iter
; i
++)
971 RTLIL::Design
*design
= new RTLIL::Design
;
972 if (cell_type
== ID(rtlil
))
973 Frontend::frontend_call(design
, NULL
, std::string(), "rtlil " + rtlil_file
);
975 create_gold_module(design
, cell_type
, cell_types
.at(cell_type
), constmode
, muxdiv
);
976 if (!write_prefix
.empty()) {
977 Pass::call(design
, stringf("write_rtlil %s_%s_%05d.il", write_prefix
.c_str(), cell_type
.c_str()+1, i
));
979 Pass::call(design
, "dump gold");
980 run_edges_test(design
, verbose
);
982 Pass::call(design
, stringf("copy gold gate; cd gate; %s; cd ..; opt -fast gate", techmap_cmd
.c_str()));
984 Pass::call(design
, "miter -equiv -flatten -make_outputs -ignore_gold_x gold gate miter");
986 Pass::call(design
, "dump gate");
987 Pass::call(design
, "dump gold");
989 Pass::call(design
, "sat -verify -enable_undef -prove trigger 0 -show-inputs -show-outputs miter");
990 std::string uut_name
= stringf("uut_%s_%d", cell_type
.substr(1).c_str(), i
);
991 if (vlog_file
.is_open()) {
992 Pass::call(design
, stringf("copy gold %s_expr; select %s_expr", uut_name
.c_str(), uut_name
.c_str()));
993 Backend::backend_call(design
, &vlog_file
, "<test_cell -vlog>", "verilog -selected");
994 Pass::call(design
, stringf("copy gold %s_noexpr; select %s_noexpr", uut_name
.c_str(), uut_name
.c_str()));
995 Backend::backend_call(design
, &vlog_file
, "<test_cell -vlog>", "verilog -selected -noexpr");
996 uut_names
.push_back(uut_name
);
999 run_eval_test(design
, verbose
, nosat
, uut_name
, vlog_file
);
1004 if (vlog_file
.is_open()) {
1005 vlog_file
<< "\nmodule testbench;\n";
1006 for (auto &uut
: uut_names
)
1007 vlog_file
<< stringf(" %s %s ();\n", uut
.c_str(), uut
.c_str());
1008 vlog_file
<< " initial begin\n";
1009 for (auto &uut
: uut_names
)
1010 vlog_file
<< " " << uut
<< ".run;\n";
1011 vlog_file
<< " end\n";
1012 vlog_file
<< "endmodule\n";
1017 PRIVATE_NAMESPACE_END