Added "test_cell -const"
[yosys.git] / passes / tests / test_cell.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2014 Clifford Wolf <clifford@clifford.at>
5 * Copyright (C) 2014 Johann Glaser <Johann.Glaser@gmx.at>
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 *
19 */
20
21 #include "kernel/yosys.h"
22 #include "kernel/satgen.h"
23 #include "kernel/consteval.h"
24 #include "kernel/macc.h"
25 #include <algorithm>
26
27 static uint32_t xorshift32_state = 123456789;
28
29 static uint32_t xorshift32(uint32_t limit) {
30 xorshift32_state ^= xorshift32_state << 13;
31 xorshift32_state ^= xorshift32_state >> 17;
32 xorshift32_state ^= xorshift32_state << 5;
33 return xorshift32_state % limit;
34 }
35
36 static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type, std::string cell_type_flags, bool constmode)
37 {
38 RTLIL::Module *module = design->addModule("\\gold");
39 RTLIL::Cell *cell = module->addCell("\\UUT", cell_type);
40 RTLIL::Wire *wire;
41
42 if (cell_type == "$macc")
43 {
44 Macc macc;
45 int width = 1 + xorshift32(8);
46 int depth = 1 + xorshift32(6);
47 int mulbits_a = 0, mulbits_b = 0;
48
49 RTLIL::Wire *wire_a = module->addWire("\\A");
50 wire_a->width = 0;
51 wire_a->port_input = true;
52
53 for (int i = 0; i < depth; i++)
54 {
55 int size_a = xorshift32(width) + 1;
56 int size_b = depth > 4 ? 0 : xorshift32(width) + 1;
57
58 if (mulbits_a + size_a*size_b <= 96 && mulbits_b + size_a + size_b <= 16 && xorshift32(2) == 1) {
59 mulbits_a += size_a * size_b;
60 mulbits_b += size_a + size_b;
61 } else
62 size_b = 0;
63
64 Macc::port_t this_port;
65
66 wire_a->width += size_a;
67 this_port.in_a = RTLIL::SigSpec(wire_a, wire_a->width - size_a, size_a);
68
69 wire_a->width += size_b;
70 this_port.in_b = RTLIL::SigSpec(wire_a, wire_a->width - size_b, size_b);
71
72 this_port.is_signed = xorshift32(2) == 1;
73 this_port.do_subtract = xorshift32(2) == 1;
74 macc.ports.push_back(this_port);
75 }
76
77 wire = module->addWire("\\B");
78 wire->width = xorshift32(mulbits_a ? xorshift32(4)+1 : xorshift32(16)+1);
79 wire->port_input = true;
80 macc.bit_ports = wire;
81
82 wire = module->addWire("\\Y");
83 wire->width = width;
84 wire->port_output = true;
85 cell->setPort("\\Y", wire);
86
87 macc.to_cell(cell);
88 }
89
90 if (cell_type == "$lut")
91 {
92 int width = 1 + xorshift32(6);
93
94 wire = module->addWire("\\A");
95 wire->width = width;
96 wire->port_input = true;
97 cell->setPort("\\A", wire);
98
99 wire = module->addWire("\\Y");
100 wire->port_output = true;
101 cell->setPort("\\Y", wire);
102
103 RTLIL::SigSpec config;
104 for (int i = 0; i < (1 << width); i++)
105 config.append(xorshift32(2) ? RTLIL::S1 : RTLIL::S0);
106
107 cell->setParam("\\LUT", config.as_const());
108 }
109
110 if (cell_type_flags.find('A') != std::string::npos) {
111 wire = module->addWire("\\A");
112 wire->width = 1 + xorshift32(8);
113 wire->port_input = true;
114 cell->setPort("\\A", wire);
115 }
116
117 if (cell_type_flags.find('B') != std::string::npos) {
118 wire = module->addWire("\\B");
119 if (cell_type_flags.find('h') != std::string::npos)
120 wire->width = 1 + xorshift32(6);
121 else
122 wire->width = 1 + xorshift32(8);
123 wire->port_input = true;
124 cell->setPort("\\B", wire);
125 }
126
127 if (cell_type_flags.find('S') != std::string::npos && xorshift32(2)) {
128 if (cell_type_flags.find('A') != std::string::npos)
129 cell->parameters["\\A_SIGNED"] = true;
130 if (cell_type_flags.find('B') != std::string::npos)
131 cell->parameters["\\B_SIGNED"] = true;
132 }
133
134 if (cell_type_flags.find('s') != std::string::npos) {
135 if (cell_type_flags.find('A') != std::string::npos && xorshift32(2))
136 cell->parameters["\\A_SIGNED"] = true;
137 if (cell_type_flags.find('B') != std::string::npos && xorshift32(2))
138 cell->parameters["\\B_SIGNED"] = true;
139 }
140
141 if (cell_type_flags.find('Y') != std::string::npos) {
142 wire = module->addWire("\\Y");
143 wire->width = 1 + xorshift32(8);
144 wire->port_output = true;
145 cell->setPort("\\Y", wire);
146 }
147
148 if (cell_type == "$alu")
149 {
150 wire = module->addWire("\\CI");
151 wire->port_input = true;
152 cell->setPort("\\CI", wire);
153
154 wire = module->addWire("\\BI");
155 wire->port_input = true;
156 cell->setPort("\\BI", wire);
157
158 wire = module->addWire("\\X");
159 wire->width = SIZE(cell->getPort("\\Y"));
160 wire->port_output = true;
161 cell->setPort("\\X", wire);
162
163 wire = module->addWire("\\CO");
164 wire->width = SIZE(cell->getPort("\\Y"));
165 wire->port_output = true;
166 cell->setPort("\\CO", wire);
167 }
168
169 if (constmode)
170 {
171 auto conn_list = cell->connections();
172 for (auto &conn : conn_list)
173 {
174 RTLIL::SigSpec sig = conn.second;
175
176 if (SIZE(sig) == 0 || sig[0].wire == nullptr || sig[0].wire->port_output)
177 continue;
178
179 int n, m;
180 switch (xorshift32(5))
181 {
182 case 0:
183 n = xorshift32(SIZE(sig) + 1);
184 for (int i = 0; i < n; i++)
185 sig[i] = xorshift32(2) == 1 ? RTLIL::S1 : RTLIL::S0;
186 break;
187 case 1:
188 n = xorshift32(SIZE(sig) + 1);
189 for (int i = n; i < SIZE(sig); i++)
190 sig[i] = xorshift32(2) == 1 ? RTLIL::S1 : RTLIL::S0;
191 break;
192 case 2:
193 n = xorshift32(SIZE(sig));
194 m = xorshift32(SIZE(sig));
195 for (int i = std::min(n, m); i < std::max(n, m); i++)
196 sig[i] = xorshift32(2) == 1 ? RTLIL::S1 : RTLIL::S0;
197 break;
198 }
199
200 cell->setPort(conn.first, sig);
201 }
202 }
203
204 module->fixup_ports();
205 cell->fixup_parameters();
206 cell->check();
207 }
208
209 static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::string uut_name, std::ofstream &vlog_file)
210 {
211 log("Eval testing:%c", verbose ? '\n' : ' ');
212
213 RTLIL::Module *gold_mod = design->module("\\gold");
214 RTLIL::Module *gate_mod = design->module("\\gate");
215 ConstEval gold_ce(gold_mod), gate_ce(gate_mod);
216
217 ezDefaultSAT ez1, ez2;
218 SigMap sigmap(gold_mod);
219 SatGen satgen1(&ez1, &sigmap);
220 SatGen satgen2(&ez2, &sigmap);
221 satgen2.model_undef = true;
222
223 if (!nosat)
224 for (auto cell : gold_mod->cells()) {
225 satgen1.importCell(cell);
226 satgen2.importCell(cell);
227 }
228
229 if (vlog_file.is_open())
230 {
231 vlog_file << stringf("\nmodule %s;\n", uut_name.c_str());
232
233 for (auto port : gold_mod->ports) {
234 RTLIL::Wire *wire = gold_mod->wire(port);
235 if (wire->port_input)
236 vlog_file << stringf(" reg [%d:0] %s;\n", SIZE(wire)-1, log_id(wire));
237 else
238 vlog_file << stringf(" wire [%d:0] %s_expr, %s_noexpr;\n", SIZE(wire)-1, log_id(wire), log_id(wire));
239 }
240
241 vlog_file << stringf(" %s_expr uut_expr(", uut_name.c_str());
242 for (int i = 0; i < SIZE(gold_mod->ports); i++)
243 vlog_file << stringf("%s.%s(%s%s)", i ? ", " : "", log_id(gold_mod->ports[i]), log_id(gold_mod->ports[i]),
244 gold_mod->wire(gold_mod->ports[i])->port_input ? "" : "_expr");
245 vlog_file << stringf(");\n");
246
247 vlog_file << stringf(" %s_expr uut_noexpr(", uut_name.c_str());
248 for (int i = 0; i < SIZE(gold_mod->ports); i++)
249 vlog_file << stringf("%s.%s(%s%s)", i ? ", " : "", log_id(gold_mod->ports[i]), log_id(gold_mod->ports[i]),
250 gold_mod->wire(gold_mod->ports[i])->port_input ? "" : "_noexpr");
251 vlog_file << stringf(");\n");
252
253 vlog_file << stringf(" task run;\n");
254 vlog_file << stringf(" begin\n");
255 vlog_file << stringf(" $display(\"%s\");\n", uut_name.c_str());
256 }
257
258 for (int i = 0; i < 64; i++)
259 {
260 log(verbose ? "\n" : ".");
261 gold_ce.clear();
262 gate_ce.clear();
263
264 RTLIL::SigSpec in_sig, in_val;
265 RTLIL::SigSpec out_sig, out_val;
266 std::string vlog_pattern_info;
267
268 for (auto port : gold_mod->ports)
269 {
270 RTLIL::Wire *gold_wire = gold_mod->wire(port);
271 RTLIL::Wire *gate_wire = gate_mod->wire(port);
272
273 log_assert(gold_wire != nullptr);
274 log_assert(gate_wire != nullptr);
275 log_assert(gold_wire->port_input == gate_wire->port_input);
276 log_assert(SIZE(gold_wire) == SIZE(gate_wire));
277
278 if (!gold_wire->port_input)
279 continue;
280
281 RTLIL::Const in_value;
282 for (int i = 0; i < SIZE(gold_wire); i++)
283 in_value.bits.push_back(xorshift32(2) ? RTLIL::S1 : RTLIL::S0);
284
285 if (xorshift32(4) == 0) {
286 int inv_chance = 1 + xorshift32(8);
287 for (int i = 0; i < SIZE(gold_wire); i++)
288 if (xorshift32(inv_chance) == 0)
289 in_value.bits[i] = RTLIL::Sx;
290 }
291
292 if (verbose)
293 log("%s: %s\n", log_id(gold_wire), log_signal(in_value));
294
295 in_sig.append(gold_wire);
296 in_val.append(in_value);
297
298 gold_ce.set(gold_wire, in_value);
299 gate_ce.set(gate_wire, in_value);
300
301 if (vlog_file.is_open() && SIZE(in_value) > 0) {
302 vlog_file << stringf(" %s = 'b%s;\n", log_id(gold_wire), in_value.as_string().c_str());
303 if (!vlog_pattern_info.empty())
304 vlog_pattern_info += " ";
305 vlog_pattern_info += stringf("%s=%s", log_id(gold_wire), log_signal(in_value));
306 }
307 }
308
309 if (vlog_file.is_open())
310 vlog_file << stringf(" #1;\n");
311
312 for (auto port : gold_mod->ports)
313 {
314 RTLIL::Wire *gold_wire = gold_mod->wire(port);
315 RTLIL::Wire *gate_wire = gate_mod->wire(port);
316
317 log_assert(gold_wire != nullptr);
318 log_assert(gate_wire != nullptr);
319 log_assert(gold_wire->port_output == gate_wire->port_output);
320 log_assert(SIZE(gold_wire) == SIZE(gate_wire));
321
322 if (!gold_wire->port_output)
323 continue;
324
325 RTLIL::SigSpec gold_outval(gold_wire);
326 RTLIL::SigSpec gate_outval(gate_wire);
327
328 if (!gold_ce.eval(gold_outval))
329 log_error("Failed to eval %s in gold module.\n", log_id(gold_wire));
330
331 if (!gate_ce.eval(gate_outval))
332 log_error("Failed to eval %s in gate module.\n", log_id(gate_wire));
333
334 bool gold_gate_mismatch = false;
335 for (int i = 0; i < SIZE(gold_wire); i++) {
336 if (gold_outval[i] == RTLIL::Sx)
337 continue;
338 if (gold_outval[i] == gate_outval[i])
339 continue;
340 gold_gate_mismatch = true;
341 break;
342 }
343
344 if (gold_gate_mismatch)
345 log_error("Mismatch in output %s: gold:%s != gate:%s\n", log_id(gate_wire), log_signal(gold_outval), log_signal(gate_outval));
346
347 if (verbose)
348 log("%s: %s\n", log_id(gold_wire), log_signal(gold_outval));
349
350 out_sig.append(gold_wire);
351 out_val.append(gold_outval);
352
353 if (vlog_file.is_open()) {
354 vlog_file << stringf(" $display(\"[%s] %s expected: %%b, expr: %%b, noexpr: %%b\", %d'b%s, %s_expr, %s_noexpr);\n",
355 vlog_pattern_info.c_str(), log_id(gold_wire), SIZE(gold_outval), gold_outval.as_string().c_str(), log_id(gold_wire), log_id(gold_wire));
356 vlog_file << stringf(" if (%s_expr !== %d'b%s) begin $display(\"ERROR\"); $finish; end\n", log_id(gold_wire), SIZE(gold_outval), gold_outval.as_string().c_str());
357 vlog_file << stringf(" if (%s_noexpr !== %d'b%s) begin $display(\"ERROR\"); $finish; end\n", log_id(gold_wire), SIZE(gold_outval), gold_outval.as_string().c_str());
358 }
359 }
360
361 if (verbose)
362 log("EVAL: %s\n", out_val.as_string().c_str());
363
364 if (!nosat)
365 {
366 std::vector<int> sat1_in_sig = satgen1.importSigSpec(in_sig);
367 std::vector<int> sat1_in_val = satgen1.importSigSpec(in_val);
368
369 std::vector<int> sat1_model = satgen1.importSigSpec(out_sig);
370 std::vector<bool> sat1_model_value;
371
372 if (!ez1.solve(sat1_model, sat1_model_value, ez1.vec_eq(sat1_in_sig, sat1_in_val)))
373 log_error("Evaluating sat model 1 (no undef modeling) failed!\n");
374
375 if (verbose) {
376 log("SAT 1: ");
377 for (int i = SIZE(out_sig)-1; i >= 0; i--)
378 log("%c", sat1_model_value.at(i) ? '1' : '0');
379 log("\n");
380 }
381
382 for (int i = 0; i < SIZE(out_sig); i++) {
383 if (out_val[i] != RTLIL::S0 && out_val[i] != RTLIL::S1)
384 continue;
385 if (out_val[i] == RTLIL::S0 && sat1_model_value.at(i) == false)
386 continue;
387 if (out_val[i] == RTLIL::S1 && sat1_model_value.at(i) == true)
388 continue;
389 log_error("Mismatch in sat model 1 (no undef modeling) output!\n");
390 }
391
392 std::vector<int> sat2_in_def_sig = satgen2.importDefSigSpec(in_sig);
393 std::vector<int> sat2_in_def_val = satgen2.importDefSigSpec(in_val);
394
395 std::vector<int> sat2_in_undef_sig = satgen2.importUndefSigSpec(in_sig);
396 std::vector<int> sat2_in_undef_val = satgen2.importUndefSigSpec(in_val);
397
398 std::vector<int> sat2_model_def_sig = satgen2.importDefSigSpec(out_sig);
399 std::vector<int> sat2_model_undef_sig = satgen2.importUndefSigSpec(out_sig);
400
401 std::vector<int> sat2_model;
402 sat2_model.insert(sat2_model.end(), sat2_model_def_sig.begin(), sat2_model_def_sig.end());
403 sat2_model.insert(sat2_model.end(), sat2_model_undef_sig.begin(), sat2_model_undef_sig.end());
404
405 std::vector<bool> sat2_model_value;
406
407 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)))
408 log_error("Evaluating sat model 2 (undef modeling) failed!\n");
409
410 if (verbose) {
411 log("SAT 2: ");
412 for (int i = SIZE(out_sig)-1; i >= 0; i--)
413 log("%c", sat2_model_value.at(SIZE(out_sig) + i) ? 'x' : sat2_model_value.at(i) ? '1' : '0');
414 log("\n");
415 }
416
417 for (int i = 0; i < SIZE(out_sig); i++) {
418 if (sat2_model_value.at(SIZE(out_sig) + i)) {
419 if (out_val[i] != RTLIL::S0 && out_val[i] != RTLIL::S1)
420 continue;
421 } else {
422 if (out_val[i] == RTLIL::S0 && sat2_model_value.at(i) == false)
423 continue;
424 if (out_val[i] == RTLIL::S1 && sat2_model_value.at(i) == true)
425 continue;
426 }
427 log_error("Mismatch in sat model 2 (undef modeling) output!\n");
428 }
429 }
430 }
431
432 if (vlog_file.is_open()) {
433 vlog_file << stringf(" end\n");
434 vlog_file << stringf(" endtask\n");
435 vlog_file << stringf("endmodule\n");
436 }
437
438 if (!verbose)
439 log(" ok.\n");
440 }
441
442 struct TestCellPass : public Pass {
443 TestCellPass() : Pass("test_cell", "automatically test the implementation of a cell type") { }
444 virtual void help()
445 {
446 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
447 log("\n");
448 log(" test_cell [options] {cell-types}\n");
449 log("\n");
450 log("Tests the internal implementation of the given cell type (for example '$mux')\n");
451 log("by comparing SAT solver, EVAL and TECHMAP implementations of the cell types..\n");
452 log("\n");
453 log("Run with 'all' instead of a cell type to run the test on all supported\n");
454 log("cell types.\n");
455 log("\n");
456 log(" -n {integer}\n");
457 log(" create this number of cell instances and test them (default = 100).\n");
458 log("\n");
459 log(" -s {positive_integer}\n");
460 log(" use this value as rng seed value (default = unix time).\n");
461 log("\n");
462 log(" -f {ilang_file}\n");
463 log(" don't generate circuits. instead load the specified ilang file.\n");
464 log("\n");
465 log(" -map {filename}\n");
466 log(" pass this option to techmap.\n");
467 log("\n");
468 log(" -simplib\n");
469 log(" use \"techmap -map +/simlib.v -max_iter 2 -autoproc\"\n");
470 log("\n");
471 log(" -script {script_file}\n");
472 log(" instead of calling \"techmap\", call \"script {script_file}\".\n");
473 log("\n");
474 log(" -const\n");
475 log(" set some input bits to random constant values\n");
476 log("\n");
477 log(" -nosat\n");
478 log(" do not check SAT model or run SAT equivalence checking\n");
479 log("\n");
480 log(" -v\n");
481 log(" print additional debug information to the console\n");
482 log("\n");
483 log(" -vlog {filename}\n");
484 log(" create a verilog test bench to test simlib and write_verilog\n");
485 log("\n");
486 }
487 virtual void execute(std::vector<std::string> args, RTLIL::Design*)
488 {
489 int num_iter = 100;
490 std::string techmap_cmd = "techmap -assert";
491 std::string ilang_file;
492 xorshift32_state = 0;
493 std::ofstream vlog_file;
494 bool verbose = false;
495 bool constmode = false;
496 bool nosat = false;
497
498 int argidx;
499 for (argidx = 1; argidx < SIZE(args); argidx++)
500 {
501 if (args[argidx] == "-n" && argidx+1 < SIZE(args)) {
502 num_iter = atoi(args[++argidx].c_str());
503 continue;
504 }
505 if (args[argidx] == "-s" && argidx+1 < SIZE(args)) {
506 xorshift32_state = atoi(args[++argidx].c_str());
507 continue;
508 }
509 if (args[argidx] == "-map" && argidx+1 < SIZE(args)) {
510 techmap_cmd += " -map " + args[++argidx];
511 continue;
512 }
513 if (args[argidx] == "-f" && argidx+1 < SIZE(args)) {
514 ilang_file = args[++argidx];
515 num_iter = 1;
516 continue;
517 }
518 if (args[argidx] == "-script" && argidx+1 < SIZE(args)) {
519 techmap_cmd = "script " + args[++argidx];
520 continue;
521 }
522 if (args[argidx] == "-simlib") {
523 techmap_cmd = "techmap -map +/simlib.v -max_iter 2 -autoproc";
524 continue;
525 }
526 if (args[argidx] == "-const") {
527 constmode = true;
528 continue;
529 }
530 if (args[argidx] == "-nosat") {
531 nosat = true;
532 continue;
533 }
534 if (args[argidx] == "-v") {
535 verbose = true;
536 continue;
537 }
538 if (args[argidx] == "-vlog" && argidx+1 < SIZE(args)) {
539 vlog_file.open(args[++argidx], std::ios_base::trunc);
540 if (!vlog_file.is_open())
541 log_cmd_error("Failed to open output file `%s'.\n", args[argidx].c_str());
542 continue;
543 }
544 break;
545 }
546
547 if (xorshift32_state == 0) {
548 xorshift32_state = time(NULL) & 0x7fffffff;
549 log("Rng seed value: %d\n", int(xorshift32_state));
550 }
551
552 std::map<std::string, std::string> cell_types;
553 std::vector<std::string> selected_cell_types;
554
555 cell_types["$not"] = "ASY";
556 cell_types["$pos"] = "ASY";
557 cell_types["$neg"] = "ASY";
558
559 cell_types["$and"] = "ABSY";
560 cell_types["$or"] = "ABSY";
561 cell_types["$xor"] = "ABSY";
562 cell_types["$xnor"] = "ABSY";
563
564 cell_types["$reduce_and"] = "ASY";
565 cell_types["$reduce_or"] = "ASY";
566 cell_types["$reduce_xor"] = "ASY";
567 cell_types["$reduce_xnor"] = "ASY";
568 cell_types["$reduce_bool"] = "ASY";
569
570 cell_types["$shl"] = "ABshY";
571 cell_types["$shr"] = "ABshY";
572 cell_types["$sshl"] = "ABshY";
573 cell_types["$sshr"] = "ABshY";
574 cell_types["$shift"] = "ABshY";
575 cell_types["$shiftx"] = "ABshY";
576
577 cell_types["$lt"] = "ABSY";
578 cell_types["$le"] = "ABSY";
579 cell_types["$eq"] = "ABSY";
580 cell_types["$ne"] = "ABSY";
581 // cell_types["$eqx"] = "ABSY";
582 // cell_types["$nex"] = "ABSY";
583 cell_types["$ge"] = "ABSY";
584 cell_types["$gt"] = "ABSY";
585
586 cell_types["$add"] = "ABSY";
587 cell_types["$sub"] = "ABSY";
588 cell_types["$mul"] = "ABSY";
589 cell_types["$div"] = "ABSY";
590 cell_types["$mod"] = "ABSY";
591 // cell_types["$pow"] = "ABsY";
592
593 cell_types["$logic_not"] = "ASY";
594 cell_types["$logic_and"] = "ABSY";
595 cell_types["$logic_or"] = "ABSY";
596
597 // cell_types["$mux"] = "A";
598 // cell_types["$pmux"] = "A";
599 // cell_types["$slice"] = "A";
600 // cell_types["$concat"] = "A";
601 // cell_types["$assert"] = "A";
602
603 cell_types["$lut"] = "*";
604 cell_types["$alu"] = "ABSY";
605 cell_types["$macc"] = "*";
606
607 for (; argidx < SIZE(args); argidx++)
608 {
609 if (args[argidx].rfind("-", 0) == 0)
610 log_cmd_error("Unexpected option: %s\n", args[argidx].c_str());
611
612 if (args[argidx] == "all") {
613 for (auto &it : cell_types)
614 if (std::count(selected_cell_types.begin(), selected_cell_types.end(), it.first) == 0)
615 selected_cell_types.push_back(it.first);
616 continue;
617 }
618
619 if (cell_types.count(args[argidx]) == 0) {
620 std::string cell_type_list;
621 int charcount = 100;
622 for (auto &it : cell_types) {
623 if (charcount > 60) {
624 cell_type_list += "\n" + it.first;
625 charcount = 0;
626 } else
627 cell_type_list += " " + it.first;
628 charcount += SIZE(it.first);
629 }
630 log_cmd_error("The cell type `%s' is currently not supported. Try one of these:%s\n",
631 args[argidx].c_str(), cell_type_list.c_str());
632 }
633
634 if (std::count(selected_cell_types.begin(), selected_cell_types.end(), args[argidx]) == 0)
635 selected_cell_types.push_back(args[argidx]);
636 }
637
638 if (!ilang_file.empty()) {
639 if (!selected_cell_types.empty())
640 log_cmd_error("Do not specify any cell types when using -f.\n");
641 selected_cell_types.push_back("ilang");
642 }
643
644 if (selected_cell_types.empty())
645 log_cmd_error("No cell type to test specified.\n");
646
647 std::vector<std::string> uut_names;
648
649 for (auto cell_type : selected_cell_types)
650 for (int i = 0; i < num_iter; i++)
651 {
652 RTLIL::Design *design = new RTLIL::Design;
653 if (cell_type == "ilang")
654 Frontend::frontend_call(design, NULL, std::string(), "ilang " + ilang_file);
655 else
656 create_gold_module(design, cell_type, cell_types.at(cell_type), constmode);
657 Pass::call(design, stringf("copy gold gate; cd gate; %s; cd ..; opt -fast gate", techmap_cmd.c_str()));
658 if (!nosat)
659 Pass::call(design, "miter -equiv -flatten -make_outputs -ignore_gold_x gold gate miter");
660 if (verbose)
661 Pass::call(design, "dump gate");
662 Pass::call(design, "dump gold");
663 if (!nosat)
664 Pass::call(design, "sat -verify -enable_undef -prove trigger 0 -show-inputs -show-outputs miter");
665 std::string uut_name = stringf("uut_%s_%d", cell_type.substr(1).c_str(), i);
666 if (vlog_file.is_open()) {
667 Pass::call(design, stringf("copy gold %s_expr; select %s_expr", uut_name.c_str(), uut_name.c_str()));
668 Backend::backend_call(design, &vlog_file, "<test_cell -vlog>", "verilog -selected");
669 Pass::call(design, stringf("copy gold %s_noexpr; select %s_noexpr", uut_name.c_str(), uut_name.c_str()));
670 Backend::backend_call(design, &vlog_file, "<test_cell -vlog>", "verilog -selected -noexpr");
671 uut_names.push_back(uut_name);
672 }
673 run_eval_test(design, verbose, nosat, uut_name, vlog_file);
674 delete design;
675 }
676
677 if (vlog_file.is_open()) {
678 vlog_file << "\nmodule testbench;\n";
679 for (auto &uut : uut_names)
680 vlog_file << stringf(" %s %s ();\n", uut.c_str(), uut.c_str());
681 vlog_file << " initial begin\n";
682 for (auto &uut : uut_names)
683 vlog_file << " " << uut << ".run;\n";
684 vlog_file << " end\n";
685 vlog_file << "endmodule\n";
686 }
687 }
688 } TestCellPass;
689