Merge pull request #3310 from robinsonb5-PRs/master
[yosys.git] / passes / tests / test_cell.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2014 Claire Xenia Wolf <claire@yosyshq.com>
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/celledges.h"
25 #include "kernel/macc.h"
26 #include <algorithm>
27
28 USING_YOSYS_NAMESPACE
29 PRIVATE_NAMESPACE_BEGIN
30
31 static uint32_t xorshift32_state = 123456789;
32
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;
38 }
39
40 static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type, std::string cell_type_flags, bool constmode, bool muxdiv)
41 {
42 RTLIL::Module *module = design->addModule(ID(gold));
43 RTLIL::Cell *cell = module->addCell(ID(UUT), cell_type);
44 RTLIL::Wire *wire;
45
46 if (cell_type.in(ID($mux), ID($pmux)))
47 {
48 int width = 1 + xorshift32(8);
49 int swidth = cell_type == ID($mux) ? 1 : 1 + xorshift32(8);
50
51 wire = module->addWire(ID::A);
52 wire->width = width;
53 wire->port_input = true;
54 cell->setPort(ID::A, wire);
55
56 wire = module->addWire(ID::B);
57 wire->width = width * swidth;
58 wire->port_input = true;
59 cell->setPort(ID::B, wire);
60
61 wire = module->addWire(ID::S);
62 wire->width = swidth;
63 wire->port_input = true;
64 cell->setPort(ID::S, wire);
65
66 wire = module->addWire(ID::Y);
67 wire->width = width;
68 wire->port_output = true;
69 cell->setPort(ID::Y, wire);
70 }
71
72 if (cell_type == ID($bmux))
73 {
74 int width = 1 + xorshift32(8);
75 int swidth = 1 + xorshift32(4);
76
77 wire = module->addWire(ID::A);
78 wire->width = width << swidth;
79 wire->port_input = true;
80 cell->setPort(ID::A, wire);
81
82 wire = module->addWire(ID::S);
83 wire->width = swidth;
84 wire->port_input = true;
85 cell->setPort(ID::S, wire);
86
87 wire = module->addWire(ID::Y);
88 wire->width = width;
89 wire->port_output = true;
90 cell->setPort(ID::Y, wire);
91 }
92
93 if (cell_type == ID($demux))
94 {
95 int width = 1 + xorshift32(8);
96 int swidth = 1 + xorshift32(6);
97
98 wire = module->addWire(ID::A);
99 wire->width = width;
100 wire->port_input = true;
101 cell->setPort(ID::A, wire);
102
103 wire = module->addWire(ID::S);
104 wire->width = swidth;
105 wire->port_input = true;
106 cell->setPort(ID::S, wire);
107
108 wire = module->addWire(ID::Y);
109 wire->width = width << swidth;
110 wire->port_output = true;
111 cell->setPort(ID::Y, wire);
112 }
113
114 if (cell_type == ID($fa))
115 {
116 int width = 1 + xorshift32(8);
117
118 wire = module->addWire(ID::A);
119 wire->width = width;
120 wire->port_input = true;
121 cell->setPort(ID::A, wire);
122
123 wire = module->addWire(ID::B);
124 wire->width = width;
125 wire->port_input = true;
126 cell->setPort(ID::B, wire);
127
128 wire = module->addWire(ID::C);
129 wire->width = width;
130 wire->port_input = true;
131 cell->setPort(ID::C, wire);
132
133 wire = module->addWire(ID::X);
134 wire->width = width;
135 wire->port_output = true;
136 cell->setPort(ID::X, wire);
137
138 wire = module->addWire(ID::Y);
139 wire->width = width;
140 wire->port_output = true;
141 cell->setPort(ID::Y, wire);
142 }
143
144 if (cell_type == ID($lcu))
145 {
146 int width = 1 + xorshift32(8);
147
148 wire = module->addWire(ID::P);
149 wire->width = width;
150 wire->port_input = true;
151 cell->setPort(ID::P, wire);
152
153 wire = module->addWire(ID::G);
154 wire->width = width;
155 wire->port_input = true;
156 cell->setPort(ID::G, wire);
157
158 wire = module->addWire(ID::CI);
159 wire->port_input = true;
160 cell->setPort(ID::CI, wire);
161
162 wire = module->addWire(ID::CO);
163 wire->width = width;
164 wire->port_output = true;
165 cell->setPort(ID::CO, wire);
166 }
167
168 if (cell_type == ID($macc))
169 {
170 Macc macc;
171 int width = 1 + xorshift32(8);
172 int depth = 1 + xorshift32(6);
173 int mulbits_a = 0, mulbits_b = 0;
174
175 RTLIL::Wire *wire_a = module->addWire(ID::A);
176 wire_a->width = 0;
177 wire_a->port_input = true;
178
179 for (int i = 0; i < depth; i++)
180 {
181 int size_a = xorshift32(width) + 1;
182 int size_b = depth > 4 ? 0 : xorshift32(width) + 1;
183
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;
187 } else
188 size_b = 0;
189
190 Macc::port_t this_port;
191
192 wire_a->width += size_a;
193 this_port.in_a = RTLIL::SigSpec(wire_a, wire_a->width - size_a, size_a);
194
195 wire_a->width += size_b;
196 this_port.in_b = RTLIL::SigSpec(wire_a, wire_a->width - size_b, size_b);
197
198 this_port.is_signed = xorshift32(2) == 1;
199 this_port.do_subtract = xorshift32(2) == 1;
200 macc.ports.push_back(this_port);
201 }
202
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;
207
208 wire = module->addWire(ID::Y);
209 wire->width = width;
210 wire->port_output = true;
211 cell->setPort(ID::Y, wire);
212
213 macc.to_cell(cell);
214 }
215
216 if (cell_type == ID($lut))
217 {
218 int width = 1 + xorshift32(6);
219
220 wire = module->addWire(ID::A);
221 wire->width = width;
222 wire->port_input = true;
223 cell->setPort(ID::A, wire);
224
225 wire = module->addWire(ID::Y);
226 wire->port_output = true;
227 cell->setPort(ID::Y, wire);
228
229 RTLIL::SigSpec config;
230 for (int i = 0; i < (1 << width); i++)
231 config.append(xorshift32(2) ? State::S1 : State::S0);
232
233 cell->setParam(ID::LUT, config.as_const());
234 }
235
236 if (cell_type == ID($sop))
237 {
238 int width = 1 + xorshift32(8);
239 int depth = 1 + xorshift32(8);
240
241 wire = module->addWire(ID::A);
242 wire->width = width;
243 wire->port_input = true;
244 cell->setPort(ID::A, wire);
245
246 wire = module->addWire(ID::Y);
247 wire->port_output = true;
248 cell->setPort(ID::Y, wire);
249
250 RTLIL::SigSpec config;
251 for (int i = 0; i < width*depth; i++)
252 switch (xorshift32(3)) {
253 case 0:
254 config.append(State::S1);
255 config.append(State::S0);
256 break;
257 case 1:
258 config.append(State::S0);
259 config.append(State::S1);
260 break;
261 case 2:
262 config.append(State::S0);
263 config.append(State::S0);
264 break;
265 }
266
267 cell->setParam(ID::DEPTH, depth);
268 cell->setParam(ID::TABLE, config.as_const());
269 }
270
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);
276 }
277
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);
282 else
283 wire->width = 1 + xorshift32(8);
284 wire->port_input = true;
285 cell->setPort(ID::B, wire);
286 }
287
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;
293 }
294
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;
300 }
301
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);
307 }
308
309 if (cell_type.in(ID($shiftx))) {
310 cell->parameters[ID::A_SIGNED] = false;
311 }
312
313 if (cell_type.in(ID($shl), ID($shr), ID($sshl), ID($sshr))) {
314 cell->parameters[ID::B_SIGNED] = false;
315 }
316
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);
322 }
323
324 if (cell_type == ID($alu))
325 {
326 wire = module->addWire(ID::CI);
327 wire->port_input = true;
328 cell->setPort(ID::CI, wire);
329
330 wire = module->addWire(ID::BI);
331 wire->port_input = true;
332 cell->setPort(ID::BI, wire);
333
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);
338
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);
343 }
344
345 if (constmode)
346 {
347 auto conn_list = cell->connections();
348 for (auto &conn : conn_list)
349 {
350 RTLIL::SigSpec sig = conn.second;
351
352 if (GetSize(sig) == 0 || sig[0].wire == nullptr || sig[0].wire->port_output)
353 continue;
354
355 int n, m;
356 switch (xorshift32(5))
357 {
358 case 0:
359 n = xorshift32(GetSize(sig) + 1);
360 for (int i = 0; i < n; i++)
361 sig[i] = xorshift32(2) == 1 ? State::S1 : State::S0;
362 break;
363 case 1:
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;
367 break;
368 case 2:
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;
373 break;
374 }
375
376 cell->setPort(conn.first, sig);
377 }
378 }
379
380 module->fixup_ports();
381 cell->fixup_parameters();
382 cell->check();
383 }
384
385 static void run_edges_test(RTLIL::Design *design, bool verbose)
386 {
387 Module *module = *design->modules().begin();
388 Cell *cell = *module->cells().begin();
389
390 ezSatPtr ezptr;
391 ezSAT &ez = *ezptr.get();
392
393 SigMap sigmap(module);
394 SatGen satgen(&ez, &sigmap);
395
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");
399
400 dict<SigBit, pool<SigBit>> satgen_db;
401
402 satgen.setContext(&sigmap, "X:");
403 satgen.importCell(cell);
404
405 satgen.setContext(&sigmap, "Y:");
406 satgen.importCell(cell);
407
408 vector<tuple<SigBit, int, int>> input_db, output_db;
409
410 for (auto &conn : cell->connections())
411 {
412 SigSpec bits = sigmap(conn.second);
413
414 satgen.setContext(&sigmap, "X:");
415 std::vector<int> xbits = satgen.importSigSpec(bits);
416
417 satgen.setContext(&sigmap, "Y:");
418 std::vector<int> ybits = satgen.importSigSpec(bits);
419
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]);
423 else
424 output_db.emplace_back(bits[i], xbits[i], ybits[i]);
425 }
426
427 if (verbose)
428 log("\nSAT solving for all edges:\n");
429
430 for (int i = 0; i < GetSize(input_db); i++)
431 {
432 SigBit inbit = std::get<0>(input_db[i]);
433
434 if (verbose)
435 log(" Testing input signal %s:\n", log_signal(inbit));
436
437 vector<int> xinbits, yinbits;
438 for (int k = 0; k < GetSize(input_db); k++)
439 if (k != i) {
440 xinbits.push_back(std::get<1>(input_db[k]));
441 yinbits.push_back(std::get<2>(input_db[k]));
442 }
443
444 int xyinbit_ok = ez.vec_eq(xinbits, yinbits);
445
446 for (int k = 0; k < GetSize(output_db); k++)
447 {
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]);
451
452 bool is_edge = ez.solve(xyinbit_ok, ez.XOR(xoutbit, youtbit));
453
454 if (is_edge)
455 satgen_db[inbit].insert(outbit);
456
457 if (verbose) {
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");
460 }
461 }
462 }
463
464 if (satgen_db == edges_db.db)
465 log("PASS.\n");
466 else
467 log_error("SAT-based edge table does not match the database!\n");
468 }
469
470 static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::string uut_name, std::ofstream &vlog_file)
471 {
472 log("Eval testing:%c", verbose ? '\n' : ' ');
473
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);
477
478 ezSatPtr ez1, ez2;
479 SigMap sigmap(gold_mod);
480 SatGen satgen1(ez1.get(), &sigmap);
481 SatGen satgen2(ez2.get(), &sigmap);
482 satgen2.model_undef = true;
483
484 if (!nosat)
485 for (auto cell : gold_mod->cells()) {
486 satgen1.importCell(cell);
487 satgen2.importCell(cell);
488 }
489
490 if (vlog_file.is_open())
491 {
492 vlog_file << stringf("\nmodule %s;\n", uut_name.c_str());
493
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));
498 else
499 vlog_file << stringf(" wire [%d:0] %s_expr, %s_noexpr;\n", GetSize(wire)-1, log_id(wire), log_id(wire));
500 }
501
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");
507
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");
513
514 vlog_file << stringf(" task run;\n");
515 vlog_file << stringf(" begin\n");
516 vlog_file << stringf(" $display(\"%s\");\n", uut_name.c_str());
517 }
518
519 for (int i = 0; i < 64; i++)
520 {
521 log(verbose ? "\n" : ".");
522 gold_ce.clear();
523 gate_ce.clear();
524
525 RTLIL::SigSpec in_sig, in_val;
526 RTLIL::SigSpec out_sig, out_val;
527 std::string vlog_pattern_info;
528
529 for (auto port : gold_mod->ports)
530 {
531 RTLIL::Wire *gold_wire = gold_mod->wire(port);
532 RTLIL::Wire *gate_wire = gate_mod->wire(port);
533
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));
538
539 if (!gold_wire->port_input)
540 continue;
541
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);
545
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;
551 }
552
553 if (verbose)
554 log("%s: %s\n", log_id(gold_wire), log_signal(in_value));
555
556 in_sig.append(gold_wire);
557 in_val.append(in_value);
558
559 gold_ce.set(gold_wire, in_value);
560 gate_ce.set(gate_wire, in_value);
561
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));
567 }
568 }
569
570 if (vlog_file.is_open())
571 vlog_file << stringf(" #1;\n");
572
573 for (auto port : gold_mod->ports)
574 {
575 RTLIL::Wire *gold_wire = gold_mod->wire(port);
576 RTLIL::Wire *gate_wire = gate_mod->wire(port);
577
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));
582
583 if (!gold_wire->port_output)
584 continue;
585
586 RTLIL::SigSpec gold_outval(gold_wire);
587 RTLIL::SigSpec gate_outval(gate_wire);
588
589 if (!gold_ce.eval(gold_outval))
590 log_error("Failed to eval %s in gold module.\n", log_id(gold_wire));
591
592 if (!gate_ce.eval(gate_outval))
593 log_error("Failed to eval %s in gate module.\n", log_id(gate_wire));
594
595 bool gold_gate_mismatch = false;
596 for (int i = 0; i < GetSize(gold_wire); i++) {
597 if (gold_outval[i] == RTLIL::Sx)
598 continue;
599 if (gold_outval[i] == gate_outval[i])
600 continue;
601 gold_gate_mismatch = true;
602 break;
603 }
604
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));
607
608 if (verbose)
609 log("%s: %s\n", log_id(gold_wire), log_signal(gold_outval));
610
611 out_sig.append(gold_wire);
612 out_val.append(gold_outval);
613
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());
619 }
620 }
621
622 if (verbose)
623 log("EVAL: %s\n", out_val.as_string().c_str());
624
625 if (!nosat)
626 {
627 std::vector<int> sat1_in_sig = satgen1.importSigSpec(in_sig);
628 std::vector<int> sat1_in_val = satgen1.importSigSpec(in_val);
629
630 std::vector<int> sat1_model = satgen1.importSigSpec(out_sig);
631 std::vector<bool> sat1_model_value;
632
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");
635
636 if (verbose) {
637 log("SAT 1: ");
638 for (int i = GetSize(out_sig)-1; i >= 0; i--)
639 log("%c", sat1_model_value.at(i) ? '1' : '0');
640 log("\n");
641 }
642
643 for (int i = 0; i < GetSize(out_sig); i++) {
644 if (out_val[i] != State::S0 && out_val[i] != State::S1)
645 continue;
646 if (out_val[i] == State::S0 && sat1_model_value.at(i) == false)
647 continue;
648 if (out_val[i] == State::S1 && sat1_model_value.at(i) == true)
649 continue;
650 log_error("Mismatch in sat model 1 (no undef modeling) output!\n");
651 }
652
653 std::vector<int> sat2_in_def_sig = satgen2.importDefSigSpec(in_sig);
654 std::vector<int> sat2_in_def_val = satgen2.importDefSigSpec(in_val);
655
656 std::vector<int> sat2_in_undef_sig = satgen2.importUndefSigSpec(in_sig);
657 std::vector<int> sat2_in_undef_val = satgen2.importUndefSigSpec(in_val);
658
659 std::vector<int> sat2_model_def_sig = satgen2.importDefSigSpec(out_sig);
660 std::vector<int> sat2_model_undef_sig = satgen2.importUndefSigSpec(out_sig);
661
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());
665
666 std::vector<bool> sat2_model_value;
667
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");
670
671 if (verbose) {
672 log("SAT 2: ");
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');
675 log("\n");
676 }
677
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)
681 continue;
682 } else {
683 if (out_val[i] == State::S0 && sat2_model_value.at(i) == false)
684 continue;
685 if (out_val[i] == State::S1 && sat2_model_value.at(i) == true)
686 continue;
687 }
688 log_error("Mismatch in sat model 2 (undef modeling) output!\n");
689 }
690 }
691 }
692
693 if (vlog_file.is_open()) {
694 vlog_file << stringf(" end\n");
695 vlog_file << stringf(" endtask\n");
696 vlog_file << stringf("endmodule\n");
697 }
698
699 if (!verbose)
700 log(" ok.\n");
701 }
702
703 struct TestCellPass : public Pass {
704 TestCellPass() : Pass("test_cell", "automatically test the implementation of a cell type") { }
705 void help() override
706 {
707 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
708 log("\n");
709 log(" test_cell [options] {cell-types}\n");
710 log("\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");
713 log("\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");
716 log("\n");
717 log(" -n {integer}\n");
718 log(" create this number of cell instances and test them (default = 100).\n");
719 log("\n");
720 log(" -s {positive_integer}\n");
721 log(" use this value as rng seed value (default = unix time).\n");
722 log("\n");
723 log(" -f {rtlil_file}\n");
724 log(" don't generate circuits. instead load the specified RTLIL file.\n");
725 log("\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");
729 log("\n");
730 log(" -map {filename}\n");
731 log(" pass this option to techmap.\n");
732 log("\n");
733 log(" -simlib\n");
734 log(" use \"techmap -D SIMLIB_NOCHECKS -map +/simlib.v -max_iter 2 -autoproc\"\n");
735 log("\n");
736 log(" -aigmap\n");
737 log(" instead of calling \"techmap\", call \"aigmap\"\n");
738 log("\n");
739 log(" -muxdiv\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");
742 log("\n");
743 log(" -script {script_file}\n");
744 log(" instead of calling \"techmap\", call \"script {script_file}\".\n");
745 log("\n");
746 log(" -const\n");
747 log(" set some input bits to random constant values\n");
748 log("\n");
749 log(" -nosat\n");
750 log(" do not check SAT model or run SAT equivalence checking\n");
751 log("\n");
752 log(" -noeval\n");
753 log(" do not check const-eval models\n");
754 log("\n");
755 log(" -edges\n");
756 log(" test cell edges db creator against sat-based implementation\n");
757 log("\n");
758 log(" -v\n");
759 log(" print additional debug information to the console\n");
760 log("\n");
761 log(" -vlog {filename}\n");
762 log(" create a Verilog test bench to test simlib and write_verilog\n");
763 log("\n");
764 }
765 void execute(std::vector<std::string> args, RTLIL::Design*) override
766 {
767 int num_iter = 100;
768 std::string techmap_cmd = "techmap -assert";
769 std::string rtlil_file, write_prefix;
770 xorshift32_state = 0;
771 std::ofstream vlog_file;
772 bool muxdiv = false;
773 bool verbose = false;
774 bool constmode = false;
775 bool nosat = false;
776 bool noeval = false;
777 bool edges = false;
778
779 int argidx;
780 for (argidx = 1; argidx < GetSize(args); argidx++)
781 {
782 if (args[argidx] == "-n" && argidx+1 < GetSize(args)) {
783 num_iter = atoi(args[++argidx].c_str());
784 continue;
785 }
786 if (args[argidx] == "-s" && argidx+1 < GetSize(args)) {
787 xorshift32_state = atoi(args[++argidx].c_str());
788 continue;
789 }
790 if (args[argidx] == "-map" && argidx+1 < GetSize(args)) {
791 techmap_cmd += " -map " + args[++argidx];
792 continue;
793 }
794 if (args[argidx] == "-f" && argidx+1 < GetSize(args)) {
795 rtlil_file = args[++argidx];
796 num_iter = 1;
797 continue;
798 }
799 if (args[argidx] == "-w" && argidx+1 < GetSize(args)) {
800 write_prefix = args[++argidx];
801 continue;
802 }
803 if (args[argidx] == "-script" && argidx+1 < GetSize(args)) {
804 techmap_cmd = "script " + args[++argidx];
805 continue;
806 }
807 if (args[argidx] == "-simlib") {
808 techmap_cmd = "techmap -D SIMLIB_NOCHECKS -map +/simlib.v -max_iter 2 -autoproc";
809 continue;
810 }
811 if (args[argidx] == "-aigmap") {
812 techmap_cmd = "aigmap";
813 continue;
814 }
815 if (args[argidx] == "-muxdiv") {
816 muxdiv = true;
817 continue;
818 }
819 if (args[argidx] == "-const") {
820 constmode = true;
821 continue;
822 }
823 if (args[argidx] == "-nosat") {
824 nosat = true;
825 continue;
826 }
827 if (args[argidx] == "-noeval") {
828 noeval = true;
829 continue;
830 }
831 if (args[argidx] == "-edges") {
832 edges = true;
833 continue;
834 }
835 if (args[argidx] == "-v") {
836 verbose = true;
837 continue;
838 }
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());
843 continue;
844 }
845 break;
846 }
847
848 if (xorshift32_state == 0) {
849 xorshift32_state = time(NULL) & 0x7fffffff;
850 log("Rng seed value: %d\n", int(xorshift32_state));
851 }
852
853 std::map<IdString, std::string> cell_types;
854 std::vector<IdString> selected_cell_types;
855
856 cell_types[ID($not)] = "ASY";
857 cell_types[ID($pos)] = "ASY";
858 cell_types[ID($neg)] = "ASY";
859
860 cell_types[ID($and)] = "ABSY";
861 cell_types[ID($or)] = "ABSY";
862 cell_types[ID($xor)] = "ABSY";
863 cell_types[ID($xnor)] = "ABSY";
864
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";
870
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";
877
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";
886
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";
895
896 cell_types[ID($logic_not)] = "ASY";
897 cell_types[ID($logic_and)] = "ABSY";
898 cell_types[ID($logic_or)] = "ABSY";
899
900 cell_types[ID($mux)] = "*";
901 cell_types[ID($bmux)] = "*";
902 cell_types[ID($demux)] = "*";
903 if (edges) {
904 cell_types[ID($pmux)] = "*";
905 }
906
907 // cell_types[ID($slice)] = "A";
908 // cell_types[ID($concat)] = "A";
909
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)] = "*";
916
917 for (; argidx < GetSize(args); argidx++)
918 {
919 if (args[argidx].rfind("-", 0) == 0)
920 log_cmd_error("Unexpected option: %s\n", args[argidx].c_str());
921
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);
926 continue;
927 }
928
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);
935 continue;
936 }
937
938 if (cell_types.count(args[argidx]) == 0) {
939 std::string cell_type_list;
940 int charcount = 100;
941 for (auto &it : cell_types) {
942 if (charcount > 60) {
943 cell_type_list += stringf("\n%s", + log_id(it.first));
944 charcount = 0;
945 } else
946 cell_type_list += stringf(" %s", log_id(it.first));
947 charcount += GetSize(it.first);
948 }
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());
951 }
952
953 if (std::count(selected_cell_types.begin(), selected_cell_types.end(), args[argidx]) == 0)
954 selected_cell_types.push_back(args[argidx]);
955 }
956
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));
961 }
962
963 if (selected_cell_types.empty())
964 log_cmd_error("No cell type to test specified.\n");
965
966 std::vector<std::string> uut_names;
967
968 for (auto cell_type : selected_cell_types)
969 for (int i = 0; i < num_iter; i++)
970 {
971 RTLIL::Design *design = new RTLIL::Design;
972 if (cell_type == ID(rtlil))
973 Frontend::frontend_call(design, NULL, std::string(), "rtlil " + rtlil_file);
974 else
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));
978 } else if (edges) {
979 Pass::call(design, "dump gold");
980 run_edges_test(design, verbose);
981 } else {
982 Pass::call(design, stringf("copy gold gate; cd gate; %s; cd ..; opt -fast gate", techmap_cmd.c_str()));
983 if (!nosat)
984 Pass::call(design, "miter -equiv -flatten -make_outputs -ignore_gold_x gold gate miter");
985 if (verbose)
986 Pass::call(design, "dump gate");
987 Pass::call(design, "dump gold");
988 if (!nosat)
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);
997 }
998 if (!noeval)
999 run_eval_test(design, verbose, nosat, uut_name, vlog_file);
1000 }
1001 delete design;
1002 }
1003
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";
1013 }
1014 }
1015 } TestCellPass;
1016
1017 PRIVATE_NAMESPACE_END