2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2014 Clifford Wolf <clifford@clifford.at>
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("\\gold");
43 RTLIL::Cell
*cell
= module
->addCell("\\UUT", cell_type
);
46 if (cell_type
== "$mux" || cell_type
== "$pmux")
48 int width
= 1 + xorshift32(8);
49 int swidth
= cell_type
== "$mux" ? 1 : 1 + xorshift32(8);
51 wire
= module
->addWire("\\A");
53 wire
->port_input
= true;
54 cell
->setPort("\\A", wire
);
56 wire
= module
->addWire("\\B");
57 wire
->width
= width
* swidth
;
58 wire
->port_input
= true;
59 cell
->setPort("\\B", wire
);
61 wire
= module
->addWire("\\S");
63 wire
->port_input
= true;
64 cell
->setPort("\\S", wire
);
66 wire
= module
->addWire("\\Y");
68 wire
->port_output
= true;
69 cell
->setPort("\\Y", wire
);
72 if (cell_type
== "$fa")
74 int width
= 1 + xorshift32(8);
76 wire
= module
->addWire("\\A");
78 wire
->port_input
= true;
79 cell
->setPort("\\A", wire
);
81 wire
= module
->addWire("\\B");
83 wire
->port_input
= true;
84 cell
->setPort("\\B", wire
);
86 wire
= module
->addWire("\\C");
88 wire
->port_input
= true;
89 cell
->setPort("\\C", wire
);
91 wire
= module
->addWire("\\X");
93 wire
->port_output
= true;
94 cell
->setPort("\\X", wire
);
96 wire
= module
->addWire("\\Y");
98 wire
->port_output
= true;
99 cell
->setPort("\\Y", wire
);
102 if (cell_type
== "$lcu")
104 int width
= 1 + xorshift32(8);
106 wire
= module
->addWire("\\P");
108 wire
->port_input
= true;
109 cell
->setPort("\\P", wire
);
111 wire
= module
->addWire("\\G");
113 wire
->port_input
= true;
114 cell
->setPort("\\G", wire
);
116 wire
= module
->addWire("\\CI");
117 wire
->port_input
= true;
118 cell
->setPort("\\CI", wire
);
120 wire
= module
->addWire("\\CO");
122 wire
->port_output
= true;
123 cell
->setPort("\\CO", wire
);
126 if (cell_type
== "$macc")
129 int width
= 1 + xorshift32(8);
130 int depth
= 1 + xorshift32(6);
131 int mulbits_a
= 0, mulbits_b
= 0;
133 RTLIL::Wire
*wire_a
= module
->addWire("\\A");
135 wire_a
->port_input
= true;
137 for (int i
= 0; i
< depth
; i
++)
139 int size_a
= xorshift32(width
) + 1;
140 int size_b
= depth
> 4 ? 0 : xorshift32(width
) + 1;
142 if (mulbits_a
+ size_a
*size_b
<= 96 && mulbits_b
+ size_a
+ size_b
<= 16 && xorshift32(2) == 1) {
143 mulbits_a
+= size_a
* size_b
;
144 mulbits_b
+= size_a
+ size_b
;
148 Macc::port_t this_port
;
150 wire_a
->width
+= size_a
;
151 this_port
.in_a
= RTLIL::SigSpec(wire_a
, wire_a
->width
- size_a
, size_a
);
153 wire_a
->width
+= size_b
;
154 this_port
.in_b
= RTLIL::SigSpec(wire_a
, wire_a
->width
- size_b
, size_b
);
156 this_port
.is_signed
= xorshift32(2) == 1;
157 this_port
.do_subtract
= xorshift32(2) == 1;
158 macc
.ports
.push_back(this_port
);
161 wire
= module
->addWire("\\B");
162 wire
->width
= xorshift32(mulbits_a
? xorshift32(4)+1 : xorshift32(16)+1);
163 wire
->port_input
= true;
164 macc
.bit_ports
= wire
;
166 wire
= module
->addWire("\\Y");
168 wire
->port_output
= true;
169 cell
->setPort("\\Y", wire
);
174 if (cell_type
== "$lut")
176 int width
= 1 + xorshift32(6);
178 wire
= module
->addWire("\\A");
180 wire
->port_input
= true;
181 cell
->setPort("\\A", wire
);
183 wire
= module
->addWire("\\Y");
184 wire
->port_output
= true;
185 cell
->setPort("\\Y", wire
);
187 RTLIL::SigSpec config
;
188 for (int i
= 0; i
< (1 << width
); i
++)
189 config
.append(xorshift32(2) ? RTLIL::S1
: RTLIL::S0
);
191 cell
->setParam("\\LUT", config
.as_const());
194 if (cell_type
== "$sop")
196 int width
= 1 + xorshift32(8);
197 int depth
= 1 + xorshift32(8);
199 wire
= module
->addWire("\\A");
201 wire
->port_input
= true;
202 cell
->setPort("\\A", wire
);
204 wire
= module
->addWire("\\Y");
205 wire
->port_output
= true;
206 cell
->setPort("\\Y", wire
);
208 RTLIL::SigSpec config
;
209 for (int i
= 0; i
< width
*depth
; i
++)
210 switch (xorshift32(3)) {
212 config
.append(RTLIL::S1
);
213 config
.append(RTLIL::S0
);
216 config
.append(RTLIL::S0
);
217 config
.append(RTLIL::S1
);
220 config
.append(RTLIL::S0
);
221 config
.append(RTLIL::S0
);
225 cell
->setParam("\\DEPTH", depth
);
226 cell
->setParam("\\TABLE", config
.as_const());
229 if (cell_type_flags
.find('A') != std::string::npos
) {
230 wire
= module
->addWire("\\A");
231 wire
->width
= 1 + xorshift32(8);
232 wire
->port_input
= true;
233 cell
->setPort("\\A", wire
);
236 if (cell_type_flags
.find('B') != std::string::npos
) {
237 wire
= module
->addWire("\\B");
238 if (cell_type_flags
.find('h') != std::string::npos
)
239 wire
->width
= 1 + xorshift32(6);
241 wire
->width
= 1 + xorshift32(8);
242 wire
->port_input
= true;
243 cell
->setPort("\\B", wire
);
246 if (cell_type_flags
.find('S') != std::string::npos
&& xorshift32(2)) {
247 if (cell_type_flags
.find('A') != std::string::npos
)
248 cell
->parameters
["\\A_SIGNED"] = true;
249 if (cell_type_flags
.find('B') != std::string::npos
)
250 cell
->parameters
["\\B_SIGNED"] = true;
253 if (cell_type_flags
.find('s') != std::string::npos
) {
254 if (cell_type_flags
.find('A') != std::string::npos
&& xorshift32(2))
255 cell
->parameters
["\\A_SIGNED"] = true;
256 if (cell_type_flags
.find('B') != std::string::npos
&& xorshift32(2))
257 cell
->parameters
["\\B_SIGNED"] = true;
260 if (cell_type_flags
.find('Y') != std::string::npos
) {
261 wire
= module
->addWire("\\Y");
262 wire
->width
= 1 + xorshift32(8);
263 wire
->port_output
= true;
264 cell
->setPort("\\Y", wire
);
267 if (muxdiv
&& (cell_type
== "$div" || cell_type
== "$mod")) {
268 auto b_not_zero
= module
->ReduceBool(NEW_ID
, cell
->getPort("\\B"));
269 auto div_out
= module
->addWire(NEW_ID
, GetSize(cell
->getPort("\\Y")));
270 module
->addMux(NEW_ID
, RTLIL::SigSpec(0, GetSize(div_out
)), div_out
, b_not_zero
, cell
->getPort("\\Y"));
271 cell
->setPort("\\Y", div_out
);
274 if (cell_type
== "$alu")
276 wire
= module
->addWire("\\CI");
277 wire
->port_input
= true;
278 cell
->setPort("\\CI", wire
);
280 wire
= module
->addWire("\\BI");
281 wire
->port_input
= true;
282 cell
->setPort("\\BI", wire
);
284 wire
= module
->addWire("\\X");
285 wire
->width
= GetSize(cell
->getPort("\\Y"));
286 wire
->port_output
= true;
287 cell
->setPort("\\X", wire
);
289 wire
= module
->addWire("\\CO");
290 wire
->width
= GetSize(cell
->getPort("\\Y"));
291 wire
->port_output
= true;
292 cell
->setPort("\\CO", wire
);
297 auto conn_list
= cell
->connections();
298 for (auto &conn
: conn_list
)
300 RTLIL::SigSpec sig
= conn
.second
;
302 if (GetSize(sig
) == 0 || sig
[0].wire
== nullptr || sig
[0].wire
->port_output
)
306 switch (xorshift32(5))
309 n
= xorshift32(GetSize(sig
) + 1);
310 for (int i
= 0; i
< n
; i
++)
311 sig
[i
] = xorshift32(2) == 1 ? RTLIL::S1
: RTLIL::S0
;
314 n
= xorshift32(GetSize(sig
) + 1);
315 for (int i
= n
; i
< GetSize(sig
); i
++)
316 sig
[i
] = xorshift32(2) == 1 ? RTLIL::S1
: RTLIL::S0
;
319 n
= xorshift32(GetSize(sig
));
320 m
= xorshift32(GetSize(sig
));
321 for (int i
= min(n
, m
); i
< max(n
, m
); i
++)
322 sig
[i
] = xorshift32(2) == 1 ? RTLIL::S1
: RTLIL::S0
;
326 cell
->setPort(conn
.first
, sig
);
330 module
->fixup_ports();
331 cell
->fixup_parameters();
335 static void run_edges_test(RTLIL::Design
*design
, bool verbose
)
337 Module
*module
= *design
->modules().begin();
338 Cell
*cell
= *module
->cells().begin();
341 ezSAT
&ez
= *ezptr
.get();
343 SigMap
sigmap(module
);
344 SatGen
satgen(&ez
, &sigmap
);
346 FwdCellEdgesDatabase
edges_db(sigmap
);
347 if (!edges_db
.add_edges_from_cell(cell
))
348 log_error("Creating edge database failed for this cell!\n");
350 dict
<SigBit
, pool
<SigBit
>> satgen_db
;
352 satgen
.setContext(&sigmap
, "X:");
353 satgen
.importCell(cell
);
355 satgen
.setContext(&sigmap
, "Y:");
356 satgen
.importCell(cell
);
358 vector
<tuple
<SigBit
, int, int>> input_db
, output_db
;
360 for (auto &conn
: cell
->connections())
362 SigSpec bits
= sigmap(conn
.second
);
364 satgen
.setContext(&sigmap
, "X:");
365 std::vector
<int> xbits
= satgen
.importSigSpec(bits
);
367 satgen
.setContext(&sigmap
, "Y:");
368 std::vector
<int> ybits
= satgen
.importSigSpec(bits
);
370 for (int i
= 0; i
< GetSize(bits
); i
++)
371 if (cell
->input(conn
.first
))
372 input_db
.emplace_back(bits
[i
], xbits
[i
], ybits
[i
]);
374 output_db
.emplace_back(bits
[i
], xbits
[i
], ybits
[i
]);
378 log("\nSAT solving for all edges:\n");
380 for (int i
= 0; i
< GetSize(input_db
); i
++)
382 SigBit inbit
= std::get
<0>(input_db
[i
]);
385 log(" Testing input signal %s:\n", log_signal(inbit
));
387 vector
<int> xinbits
, yinbits
;
388 for (int k
= 0; k
< GetSize(input_db
); k
++)
390 xinbits
.push_back(std::get
<1>(input_db
[k
]));
391 yinbits
.push_back(std::get
<2>(input_db
[k
]));
394 int xyinbit_ok
= ez
.vec_eq(xinbits
, yinbits
);
396 for (int k
= 0; k
< GetSize(output_db
); k
++)
398 SigBit outbit
= std::get
<0>(output_db
[k
]);
399 int xoutbit
= std::get
<1>(output_db
[k
]);
400 int youtbit
= std::get
<2>(output_db
[k
]);
402 bool is_edge
= ez
.solve(xyinbit_ok
, ez
.XOR(xoutbit
, youtbit
));
405 satgen_db
[inbit
].insert(outbit
);
408 bool is_ref_edge
= edges_db
.db
.count(inbit
) && edges_db
.db
.at(inbit
).count(outbit
);
409 log(" %c %s %s\n", is_edge
? 'x' : 'o', log_signal(outbit
), is_edge
== is_ref_edge
? "OK" : "ERROR");
414 if (satgen_db
== edges_db
.db
)
417 log_error("SAT-based edge table does not match the database!\n");
420 static void run_eval_test(RTLIL::Design
*design
, bool verbose
, bool nosat
, std::string uut_name
, std::ofstream
&vlog_file
)
422 log("Eval testing:%c", verbose
? '\n' : ' ');
424 RTLIL::Module
*gold_mod
= design
->module("\\gold");
425 RTLIL::Module
*gate_mod
= design
->module("\\gate");
426 ConstEval
gold_ce(gold_mod
), gate_ce(gate_mod
);
429 SigMap
sigmap(gold_mod
);
430 SatGen
satgen1(ez1
.get(), &sigmap
);
431 SatGen
satgen2(ez2
.get(), &sigmap
);
432 satgen2
.model_undef
= true;
435 for (auto cell
: gold_mod
->cells()) {
436 satgen1
.importCell(cell
);
437 satgen2
.importCell(cell
);
440 if (vlog_file
.is_open())
442 vlog_file
<< stringf("\nmodule %s;\n", uut_name
.c_str());
444 for (auto port
: gold_mod
->ports
) {
445 RTLIL::Wire
*wire
= gold_mod
->wire(port
);
446 if (wire
->port_input
)
447 vlog_file
<< stringf(" reg [%d:0] %s;\n", GetSize(wire
)-1, log_id(wire
));
449 vlog_file
<< stringf(" wire [%d:0] %s_expr, %s_noexpr;\n", GetSize(wire
)-1, log_id(wire
), log_id(wire
));
452 vlog_file
<< stringf(" %s_expr uut_expr(", uut_name
.c_str());
453 for (int i
= 0; i
< GetSize(gold_mod
->ports
); i
++)
454 vlog_file
<< stringf("%s.%s(%s%s)", i
? ", " : "", log_id(gold_mod
->ports
[i
]), log_id(gold_mod
->ports
[i
]),
455 gold_mod
->wire(gold_mod
->ports
[i
])->port_input
? "" : "_expr");
456 vlog_file
<< stringf(");\n");
458 vlog_file
<< stringf(" %s_expr uut_noexpr(", uut_name
.c_str());
459 for (int i
= 0; i
< GetSize(gold_mod
->ports
); i
++)
460 vlog_file
<< stringf("%s.%s(%s%s)", i
? ", " : "", log_id(gold_mod
->ports
[i
]), log_id(gold_mod
->ports
[i
]),
461 gold_mod
->wire(gold_mod
->ports
[i
])->port_input
? "" : "_noexpr");
462 vlog_file
<< stringf(");\n");
464 vlog_file
<< stringf(" task run;\n");
465 vlog_file
<< stringf(" begin\n");
466 vlog_file
<< stringf(" $display(\"%s\");\n", uut_name
.c_str());
469 for (int i
= 0; i
< 64; i
++)
471 log(verbose
? "\n" : ".");
475 RTLIL::SigSpec in_sig
, in_val
;
476 RTLIL::SigSpec out_sig
, out_val
;
477 std::string vlog_pattern_info
;
479 for (auto port
: gold_mod
->ports
)
481 RTLIL::Wire
*gold_wire
= gold_mod
->wire(port
);
482 RTLIL::Wire
*gate_wire
= gate_mod
->wire(port
);
484 log_assert(gold_wire
!= nullptr);
485 log_assert(gate_wire
!= nullptr);
486 log_assert(gold_wire
->port_input
== gate_wire
->port_input
);
487 log_assert(GetSize(gold_wire
) == GetSize(gate_wire
));
489 if (!gold_wire
->port_input
)
492 RTLIL::Const in_value
;
493 for (int i
= 0; i
< GetSize(gold_wire
); i
++)
494 in_value
.bits
.push_back(xorshift32(2) ? RTLIL::S1
: RTLIL::S0
);
496 if (xorshift32(4) == 0) {
497 int inv_chance
= 1 + xorshift32(8);
498 for (int i
= 0; i
< GetSize(gold_wire
); i
++)
499 if (xorshift32(inv_chance
) == 0)
500 in_value
.bits
[i
] = RTLIL::Sx
;
504 log("%s: %s\n", log_id(gold_wire
), log_signal(in_value
));
506 in_sig
.append(gold_wire
);
507 in_val
.append(in_value
);
509 gold_ce
.set(gold_wire
, in_value
);
510 gate_ce
.set(gate_wire
, in_value
);
512 if (vlog_file
.is_open() && GetSize(in_value
) > 0) {
513 vlog_file
<< stringf(" %s = 'b%s;\n", log_id(gold_wire
), in_value
.as_string().c_str());
514 if (!vlog_pattern_info
.empty())
515 vlog_pattern_info
+= " ";
516 vlog_pattern_info
+= stringf("%s=%s", log_id(gold_wire
), log_signal(in_value
));
520 if (vlog_file
.is_open())
521 vlog_file
<< stringf(" #1;\n");
523 for (auto port
: gold_mod
->ports
)
525 RTLIL::Wire
*gold_wire
= gold_mod
->wire(port
);
526 RTLIL::Wire
*gate_wire
= gate_mod
->wire(port
);
528 log_assert(gold_wire
!= nullptr);
529 log_assert(gate_wire
!= nullptr);
530 log_assert(gold_wire
->port_output
== gate_wire
->port_output
);
531 log_assert(GetSize(gold_wire
) == GetSize(gate_wire
));
533 if (!gold_wire
->port_output
)
536 RTLIL::SigSpec
gold_outval(gold_wire
);
537 RTLIL::SigSpec
gate_outval(gate_wire
);
539 if (!gold_ce
.eval(gold_outval
))
540 log_error("Failed to eval %s in gold module.\n", log_id(gold_wire
));
542 if (!gate_ce
.eval(gate_outval
))
543 log_error("Failed to eval %s in gate module.\n", log_id(gate_wire
));
545 bool gold_gate_mismatch
= false;
546 for (int i
= 0; i
< GetSize(gold_wire
); i
++) {
547 if (gold_outval
[i
] == RTLIL::Sx
)
549 if (gold_outval
[i
] == gate_outval
[i
])
551 gold_gate_mismatch
= true;
555 if (gold_gate_mismatch
)
556 log_error("Mismatch in output %s: gold:%s != gate:%s\n", log_id(gate_wire
), log_signal(gold_outval
), log_signal(gate_outval
));
559 log("%s: %s\n", log_id(gold_wire
), log_signal(gold_outval
));
561 out_sig
.append(gold_wire
);
562 out_val
.append(gold_outval
);
564 if (vlog_file
.is_open()) {
565 vlog_file
<< stringf(" $display(\"[%s] %s expected: %%b, expr: %%b, noexpr: %%b\", %d'b%s, %s_expr, %s_noexpr);\n",
566 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
));
567 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());
568 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());
573 log("EVAL: %s\n", out_val
.as_string().c_str());
577 std::vector
<int> sat1_in_sig
= satgen1
.importSigSpec(in_sig
);
578 std::vector
<int> sat1_in_val
= satgen1
.importSigSpec(in_val
);
580 std::vector
<int> sat1_model
= satgen1
.importSigSpec(out_sig
);
581 std::vector
<bool> sat1_model_value
;
583 if (!ez1
->solve(sat1_model
, sat1_model_value
, ez1
->vec_eq(sat1_in_sig
, sat1_in_val
)))
584 log_error("Evaluating sat model 1 (no undef modeling) failed!\n");
588 for (int i
= GetSize(out_sig
)-1; i
>= 0; i
--)
589 log("%c", sat1_model_value
.at(i
) ? '1' : '0');
593 for (int i
= 0; i
< GetSize(out_sig
); i
++) {
594 if (out_val
[i
] != RTLIL::S0
&& out_val
[i
] != RTLIL::S1
)
596 if (out_val
[i
] == RTLIL::S0
&& sat1_model_value
.at(i
) == false)
598 if (out_val
[i
] == RTLIL::S1
&& sat1_model_value
.at(i
) == true)
600 log_error("Mismatch in sat model 1 (no undef modeling) output!\n");
603 std::vector
<int> sat2_in_def_sig
= satgen2
.importDefSigSpec(in_sig
);
604 std::vector
<int> sat2_in_def_val
= satgen2
.importDefSigSpec(in_val
);
606 std::vector
<int> sat2_in_undef_sig
= satgen2
.importUndefSigSpec(in_sig
);
607 std::vector
<int> sat2_in_undef_val
= satgen2
.importUndefSigSpec(in_val
);
609 std::vector
<int> sat2_model_def_sig
= satgen2
.importDefSigSpec(out_sig
);
610 std::vector
<int> sat2_model_undef_sig
= satgen2
.importUndefSigSpec(out_sig
);
612 std::vector
<int> sat2_model
;
613 sat2_model
.insert(sat2_model
.end(), sat2_model_def_sig
.begin(), sat2_model_def_sig
.end());
614 sat2_model
.insert(sat2_model
.end(), sat2_model_undef_sig
.begin(), sat2_model_undef_sig
.end());
616 std::vector
<bool> sat2_model_value
;
618 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
)))
619 log_error("Evaluating sat model 2 (undef modeling) failed!\n");
623 for (int i
= GetSize(out_sig
)-1; i
>= 0; i
--)
624 log("%c", sat2_model_value
.at(GetSize(out_sig
) + i
) ? 'x' : sat2_model_value
.at(i
) ? '1' : '0');
628 for (int i
= 0; i
< GetSize(out_sig
); i
++) {
629 if (sat2_model_value
.at(GetSize(out_sig
) + i
)) {
630 if (out_val
[i
] != RTLIL::S0
&& out_val
[i
] != RTLIL::S1
)
633 if (out_val
[i
] == RTLIL::S0
&& sat2_model_value
.at(i
) == false)
635 if (out_val
[i
] == RTLIL::S1
&& sat2_model_value
.at(i
) == true)
638 log_error("Mismatch in sat model 2 (undef modeling) output!\n");
643 if (vlog_file
.is_open()) {
644 vlog_file
<< stringf(" end\n");
645 vlog_file
<< stringf(" endtask\n");
646 vlog_file
<< stringf("endmodule\n");
653 struct TestCellPass
: public Pass
{
654 TestCellPass() : Pass("test_cell", "automatically test the implementation of a cell type") { }
655 void help() YS_OVERRIDE
657 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
659 log(" test_cell [options] {cell-types}\n");
661 log("Tests the internal implementation of the given cell type (for example '$add')\n");
662 log("by comparing SAT solver, EVAL and TECHMAP implementations of the cell types..\n");
664 log("Run with 'all' instead of a cell type to run the test on all supported\n");
665 log("cell types. Use for example 'all /$add' for all cell types except $add.\n");
667 log(" -n {integer}\n");
668 log(" create this number of cell instances and test them (default = 100).\n");
670 log(" -s {positive_integer}\n");
671 log(" use this value as rng seed value (default = unix time).\n");
673 log(" -f {ilang_file}\n");
674 log(" don't generate circuits. instead load the specified ilang file.\n");
676 log(" -w {filename_prefix}\n");
677 log(" don't test anything. just generate the circuits and write them\n");
678 log(" to ilang files with the specified prefix\n");
680 log(" -map {filename}\n");
681 log(" pass this option to techmap.\n");
684 log(" use \"techmap -D SIMLIB_NOCHECKS -map +/simlib.v -max_iter 2 -autoproc\"\n");
687 log(" instead of calling \"techmap\", call \"aigmap\"\n");
690 log(" when creating test benches with dividers, create an additional mux\n");
691 log(" to mask out the division-by-zero case\n");
693 log(" -script {script_file}\n");
694 log(" instead of calling \"techmap\", call \"script {script_file}\".\n");
697 log(" set some input bits to random constant values\n");
700 log(" do not check SAT model or run SAT equivalence checking\n");
703 log(" do not check const-eval models\n");
706 log(" test cell edges db creator against sat-based implementation\n");
709 log(" print additional debug information to the console\n");
711 log(" -vlog {filename}\n");
712 log(" create a Verilog test bench to test simlib and write_verilog\n");
715 void execute(std::vector
<std::string
> args
, RTLIL::Design
*) YS_OVERRIDE
718 std::string techmap_cmd
= "techmap -assert";
719 std::string ilang_file
, write_prefix
;
720 xorshift32_state
= 0;
721 std::ofstream vlog_file
;
723 bool verbose
= false;
724 bool constmode
= false;
730 for (argidx
= 1; argidx
< GetSize(args
); argidx
++)
732 if (args
[argidx
] == "-n" && argidx
+1 < GetSize(args
)) {
733 num_iter
= atoi(args
[++argidx
].c_str());
736 if (args
[argidx
] == "-s" && argidx
+1 < GetSize(args
)) {
737 xorshift32_state
= atoi(args
[++argidx
].c_str());
740 if (args
[argidx
] == "-map" && argidx
+1 < GetSize(args
)) {
741 techmap_cmd
+= " -map " + args
[++argidx
];
744 if (args
[argidx
] == "-f" && argidx
+1 < GetSize(args
)) {
745 ilang_file
= args
[++argidx
];
749 if (args
[argidx
] == "-w" && argidx
+1 < GetSize(args
)) {
750 write_prefix
= args
[++argidx
];
753 if (args
[argidx
] == "-script" && argidx
+1 < GetSize(args
)) {
754 techmap_cmd
= "script " + args
[++argidx
];
757 if (args
[argidx
] == "-simlib") {
758 techmap_cmd
= "techmap -D SIMLIB_NOCHECKS -map +/simlib.v -max_iter 2 -autoproc";
761 if (args
[argidx
] == "-aigmap") {
762 techmap_cmd
= "aigmap";
765 if (args
[argidx
] == "-muxdiv") {
769 if (args
[argidx
] == "-const") {
773 if (args
[argidx
] == "-nosat") {
777 if (args
[argidx
] == "-noeval") {
781 if (args
[argidx
] == "-edges") {
785 if (args
[argidx
] == "-v") {
789 if (args
[argidx
] == "-vlog" && argidx
+1 < GetSize(args
)) {
790 vlog_file
.open(args
[++argidx
], std::ios_base::trunc
);
791 if (!vlog_file
.is_open())
792 log_cmd_error("Failed to open output file `%s'.\n", args
[argidx
].c_str());
798 if (xorshift32_state
== 0) {
799 xorshift32_state
= time(NULL
) & 0x7fffffff;
800 log("Rng seed value: %d\n", int(xorshift32_state
));
803 std::map
<std::string
, std::string
> cell_types
;
804 std::vector
<std::string
> selected_cell_types
;
806 cell_types
["$not"] = "ASY";
807 cell_types
["$pos"] = "ASY";
808 cell_types
["$neg"] = "ASY";
810 cell_types
["$and"] = "ABSY";
811 cell_types
["$or"] = "ABSY";
812 cell_types
["$xor"] = "ABSY";
813 cell_types
["$xnor"] = "ABSY";
815 cell_types
["$reduce_and"] = "ASY";
816 cell_types
["$reduce_or"] = "ASY";
817 cell_types
["$reduce_xor"] = "ASY";
818 cell_types
["$reduce_xnor"] = "ASY";
819 cell_types
["$reduce_bool"] = "ASY";
821 cell_types
["$shl"] = "ABshY";
822 cell_types
["$shr"] = "ABshY";
823 cell_types
["$sshl"] = "ABshY";
824 cell_types
["$sshr"] = "ABshY";
825 cell_types
["$shift"] = "ABshY";
826 cell_types
["$shiftx"] = "ABshY";
828 cell_types
["$lt"] = "ABSY";
829 cell_types
["$le"] = "ABSY";
830 cell_types
["$eq"] = "ABSY";
831 cell_types
["$ne"] = "ABSY";
832 // cell_types["$eqx"] = "ABSY";
833 // cell_types["$nex"] = "ABSY";
834 cell_types
["$ge"] = "ABSY";
835 cell_types
["$gt"] = "ABSY";
837 cell_types
["$add"] = "ABSY";
838 cell_types
["$sub"] = "ABSY";
839 cell_types
["$mul"] = "ABSY";
840 cell_types
["$div"] = "ABSY";
841 cell_types
["$mod"] = "ABSY";
842 // cell_types["$pow"] = "ABsY";
844 cell_types
["$logic_not"] = "ASY";
845 cell_types
["$logic_and"] = "ABSY";
846 cell_types
["$logic_or"] = "ABSY";
849 cell_types
["$mux"] = "*";
850 cell_types
["$pmux"] = "*";
853 // cell_types["$slice"] = "A";
854 // cell_types["$concat"] = "A";
856 cell_types
["$lut"] = "*";
857 cell_types
["$sop"] = "*";
858 cell_types
["$alu"] = "ABSY";
859 cell_types
["$lcu"] = "*";
860 cell_types
["$macc"] = "*";
861 cell_types
["$fa"] = "*";
863 for (; argidx
< GetSize(args
); argidx
++)
865 if (args
[argidx
].rfind("-", 0) == 0)
866 log_cmd_error("Unexpected option: %s\n", args
[argidx
].c_str());
868 if (args
[argidx
] == "all") {
869 for (auto &it
: cell_types
)
870 if (std::count(selected_cell_types
.begin(), selected_cell_types
.end(), it
.first
) == 0)
871 selected_cell_types
.push_back(it
.first
);
875 if (args
[argidx
].substr(0, 1) == "/") {
876 std::vector
<std::string
> new_selected_cell_types
;
877 for (auto it
: selected_cell_types
)
878 if (it
!= args
[argidx
].substr(1))
879 new_selected_cell_types
.push_back(it
);
880 new_selected_cell_types
.swap(selected_cell_types
);
884 if (cell_types
.count(args
[argidx
]) == 0) {
885 std::string cell_type_list
;
887 for (auto &it
: cell_types
) {
888 if (charcount
> 60) {
889 cell_type_list
+= "\n" + it
.first
;
892 cell_type_list
+= " " + it
.first
;
893 charcount
+= GetSize(it
.first
);
895 log_cmd_error("The cell type `%s' is currently not supported. Try one of these:%s\n",
896 args
[argidx
].c_str(), cell_type_list
.c_str());
899 if (std::count(selected_cell_types
.begin(), selected_cell_types
.end(), args
[argidx
]) == 0)
900 selected_cell_types
.push_back(args
[argidx
]);
903 if (!ilang_file
.empty()) {
904 if (!selected_cell_types
.empty())
905 log_cmd_error("Do not specify any cell types when using -f.\n");
906 selected_cell_types
.push_back("ilang");
909 if (selected_cell_types
.empty())
910 log_cmd_error("No cell type to test specified.\n");
912 std::vector
<std::string
> uut_names
;
914 for (auto cell_type
: selected_cell_types
)
915 for (int i
= 0; i
< num_iter
; i
++)
917 RTLIL::Design
*design
= new RTLIL::Design
;
918 if (cell_type
== "ilang")
919 Frontend::frontend_call(design
, NULL
, std::string(), "ilang " + ilang_file
);
921 create_gold_module(design
, cell_type
, cell_types
.at(cell_type
), constmode
, muxdiv
);
922 if (!write_prefix
.empty()) {
923 Pass::call(design
, stringf("write_ilang %s_%s_%05d.il", write_prefix
.c_str(), cell_type
.c_str()+1, i
));
925 Pass::call(design
, "dump gold");
926 run_edges_test(design
, verbose
);
928 Pass::call(design
, stringf("copy gold gate; cd gate; %s; cd ..; opt -fast gate", techmap_cmd
.c_str()));
930 Pass::call(design
, "miter -equiv -flatten -make_outputs -ignore_gold_x gold gate miter");
932 Pass::call(design
, "dump gate");
933 Pass::call(design
, "dump gold");
935 Pass::call(design
, "sat -verify -enable_undef -prove trigger 0 -show-inputs -show-outputs miter");
936 std::string uut_name
= stringf("uut_%s_%d", cell_type
.substr(1).c_str(), i
);
937 if (vlog_file
.is_open()) {
938 Pass::call(design
, stringf("copy gold %s_expr; select %s_expr", uut_name
.c_str(), uut_name
.c_str()));
939 Backend::backend_call(design
, &vlog_file
, "<test_cell -vlog>", "verilog -selected");
940 Pass::call(design
, stringf("copy gold %s_noexpr; select %s_noexpr", uut_name
.c_str(), uut_name
.c_str()));
941 Backend::backend_call(design
, &vlog_file
, "<test_cell -vlog>", "verilog -selected -noexpr");
942 uut_names
.push_back(uut_name
);
945 run_eval_test(design
, verbose
, nosat
, uut_name
, vlog_file
);
950 if (vlog_file
.is_open()) {
951 vlog_file
<< "\nmodule testbench;\n";
952 for (auto &uut
: uut_names
)
953 vlog_file
<< stringf(" %s %s ();\n", uut
.c_str(), uut
.c_str());
954 vlog_file
<< " initial begin\n";
955 for (auto &uut
: uut_names
)
956 vlog_file
<< " " << uut
<< ".run;\n";
957 vlog_file
<< " end\n";
958 vlog_file
<< "endmodule\n";
963 PRIVATE_NAMESPACE_END