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