Merge pull request #1085 from YosysHQ/eddie/shregmap_improve
[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/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("\\gold");
43 RTLIL::Cell *cell = module->addCell("\\UUT", cell_type);
44 RTLIL::Wire *wire;
45
46 if (cell_type == "$mux" || cell_type == "$pmux")
47 {
48 int width = 1 + xorshift32(8);
49 int swidth = cell_type == "$mux" ? 1 : 1 + xorshift32(8);
50
51 wire = module->addWire("\\A");
52 wire->width = width;
53 wire->port_input = true;
54 cell->setPort("\\A", wire);
55
56 wire = module->addWire("\\B");
57 wire->width = width * swidth;
58 wire->port_input = true;
59 cell->setPort("\\B", wire);
60
61 wire = module->addWire("\\S");
62 wire->width = swidth;
63 wire->port_input = true;
64 cell->setPort("\\S", wire);
65
66 wire = module->addWire("\\Y");
67 wire->width = width;
68 wire->port_output = true;
69 cell->setPort("\\Y", wire);
70 }
71
72 if (cell_type == "$fa")
73 {
74 int width = 1 + xorshift32(8);
75
76 wire = module->addWire("\\A");
77 wire->width = width;
78 wire->port_input = true;
79 cell->setPort("\\A", wire);
80
81 wire = module->addWire("\\B");
82 wire->width = width;
83 wire->port_input = true;
84 cell->setPort("\\B", wire);
85
86 wire = module->addWire("\\C");
87 wire->width = width;
88 wire->port_input = true;
89 cell->setPort("\\C", wire);
90
91 wire = module->addWire("\\X");
92 wire->width = width;
93 wire->port_output = true;
94 cell->setPort("\\X", wire);
95
96 wire = module->addWire("\\Y");
97 wire->width = width;
98 wire->port_output = true;
99 cell->setPort("\\Y", wire);
100 }
101
102 if (cell_type == "$lcu")
103 {
104 int width = 1 + xorshift32(8);
105
106 wire = module->addWire("\\P");
107 wire->width = width;
108 wire->port_input = true;
109 cell->setPort("\\P", wire);
110
111 wire = module->addWire("\\G");
112 wire->width = width;
113 wire->port_input = true;
114 cell->setPort("\\G", wire);
115
116 wire = module->addWire("\\CI");
117 wire->port_input = true;
118 cell->setPort("\\CI", wire);
119
120 wire = module->addWire("\\CO");
121 wire->width = width;
122 wire->port_output = true;
123 cell->setPort("\\CO", wire);
124 }
125
126 if (cell_type == "$macc")
127 {
128 Macc macc;
129 int width = 1 + xorshift32(8);
130 int depth = 1 + xorshift32(6);
131 int mulbits_a = 0, mulbits_b = 0;
132
133 RTLIL::Wire *wire_a = module->addWire("\\A");
134 wire_a->width = 0;
135 wire_a->port_input = true;
136
137 for (int i = 0; i < depth; i++)
138 {
139 int size_a = xorshift32(width) + 1;
140 int size_b = depth > 4 ? 0 : xorshift32(width) + 1;
141
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;
145 } else
146 size_b = 0;
147
148 Macc::port_t this_port;
149
150 wire_a->width += size_a;
151 this_port.in_a = RTLIL::SigSpec(wire_a, wire_a->width - size_a, size_a);
152
153 wire_a->width += size_b;
154 this_port.in_b = RTLIL::SigSpec(wire_a, wire_a->width - size_b, size_b);
155
156 this_port.is_signed = xorshift32(2) == 1;
157 this_port.do_subtract = xorshift32(2) == 1;
158 macc.ports.push_back(this_port);
159 }
160
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;
165
166 wire = module->addWire("\\Y");
167 wire->width = width;
168 wire->port_output = true;
169 cell->setPort("\\Y", wire);
170
171 macc.to_cell(cell);
172 }
173
174 if (cell_type == "$lut")
175 {
176 int width = 1 + xorshift32(6);
177
178 wire = module->addWire("\\A");
179 wire->width = width;
180 wire->port_input = true;
181 cell->setPort("\\A", wire);
182
183 wire = module->addWire("\\Y");
184 wire->port_output = true;
185 cell->setPort("\\Y", wire);
186
187 RTLIL::SigSpec config;
188 for (int i = 0; i < (1 << width); i++)
189 config.append(xorshift32(2) ? RTLIL::S1 : RTLIL::S0);
190
191 cell->setParam("\\LUT", config.as_const());
192 }
193
194 if (cell_type == "$sop")
195 {
196 int width = 1 + xorshift32(8);
197 int depth = 1 + xorshift32(8);
198
199 wire = module->addWire("\\A");
200 wire->width = width;
201 wire->port_input = true;
202 cell->setPort("\\A", wire);
203
204 wire = module->addWire("\\Y");
205 wire->port_output = true;
206 cell->setPort("\\Y", wire);
207
208 RTLIL::SigSpec config;
209 for (int i = 0; i < width*depth; i++)
210 switch (xorshift32(3)) {
211 case 0:
212 config.append(RTLIL::S1);
213 config.append(RTLIL::S0);
214 break;
215 case 1:
216 config.append(RTLIL::S0);
217 config.append(RTLIL::S1);
218 break;
219 case 2:
220 config.append(RTLIL::S0);
221 config.append(RTLIL::S0);
222 break;
223 }
224
225 cell->setParam("\\DEPTH", depth);
226 cell->setParam("\\TABLE", config.as_const());
227 }
228
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);
234 }
235
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);
240 else
241 wire->width = 1 + xorshift32(8);
242 wire->port_input = true;
243 cell->setPort("\\B", wire);
244 }
245
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;
251 }
252
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;
258 }
259
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);
265 }
266
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);
272 }
273
274 if (cell_type == "$alu")
275 {
276 wire = module->addWire("\\CI");
277 wire->port_input = true;
278 cell->setPort("\\CI", wire);
279
280 wire = module->addWire("\\BI");
281 wire->port_input = true;
282 cell->setPort("\\BI", wire);
283
284 wire = module->addWire("\\X");
285 wire->width = GetSize(cell->getPort("\\Y"));
286 wire->port_output = true;
287 cell->setPort("\\X", wire);
288
289 wire = module->addWire("\\CO");
290 wire->width = GetSize(cell->getPort("\\Y"));
291 wire->port_output = true;
292 cell->setPort("\\CO", wire);
293 }
294
295 if (constmode)
296 {
297 auto conn_list = cell->connections();
298 for (auto &conn : conn_list)
299 {
300 RTLIL::SigSpec sig = conn.second;
301
302 if (GetSize(sig) == 0 || sig[0].wire == nullptr || sig[0].wire->port_output)
303 continue;
304
305 int n, m;
306 switch (xorshift32(5))
307 {
308 case 0:
309 n = xorshift32(GetSize(sig) + 1);
310 for (int i = 0; i < n; i++)
311 sig[i] = xorshift32(2) == 1 ? RTLIL::S1 : RTLIL::S0;
312 break;
313 case 1:
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;
317 break;
318 case 2:
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;
323 break;
324 }
325
326 cell->setPort(conn.first, sig);
327 }
328 }
329
330 module->fixup_ports();
331 cell->fixup_parameters();
332 cell->check();
333 }
334
335 static void run_edges_test(RTLIL::Design *design, bool verbose)
336 {
337 Module *module = *design->modules().begin();
338 Cell *cell = *module->cells().begin();
339
340 ezSatPtr ezptr;
341 ezSAT &ez = *ezptr.get();
342
343 SigMap sigmap(module);
344 SatGen satgen(&ez, &sigmap);
345
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");
349
350 dict<SigBit, pool<SigBit>> satgen_db;
351
352 satgen.setContext(&sigmap, "X:");
353 satgen.importCell(cell);
354
355 satgen.setContext(&sigmap, "Y:");
356 satgen.importCell(cell);
357
358 vector<tuple<SigBit, int, int>> input_db, output_db;
359
360 for (auto &conn : cell->connections())
361 {
362 SigSpec bits = sigmap(conn.second);
363
364 satgen.setContext(&sigmap, "X:");
365 std::vector<int> xbits = satgen.importSigSpec(bits);
366
367 satgen.setContext(&sigmap, "Y:");
368 std::vector<int> ybits = satgen.importSigSpec(bits);
369
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]);
373 else
374 output_db.emplace_back(bits[i], xbits[i], ybits[i]);
375 }
376
377 if (verbose)
378 log("\nSAT solving for all edges:\n");
379
380 for (int i = 0; i < GetSize(input_db); i++)
381 {
382 SigBit inbit = std::get<0>(input_db[i]);
383
384 if (verbose)
385 log(" Testing input signal %s:\n", log_signal(inbit));
386
387 vector<int> xinbits, yinbits;
388 for (int k = 0; k < GetSize(input_db); k++)
389 if (k != i) {
390 xinbits.push_back(std::get<1>(input_db[k]));
391 yinbits.push_back(std::get<2>(input_db[k]));
392 }
393
394 int xyinbit_ok = ez.vec_eq(xinbits, yinbits);
395
396 for (int k = 0; k < GetSize(output_db); k++)
397 {
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]);
401
402 bool is_edge = ez.solve(xyinbit_ok, ez.XOR(xoutbit, youtbit));
403
404 if (is_edge)
405 satgen_db[inbit].insert(outbit);
406
407 if (verbose) {
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");
410 }
411 }
412 }
413
414 if (satgen_db == edges_db.db)
415 log("PASS.\n");
416 else
417 log_error("SAT-based edge table does not match the database!\n");
418 }
419
420 static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::string uut_name, std::ofstream &vlog_file)
421 {
422 log("Eval testing:%c", verbose ? '\n' : ' ');
423
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);
427
428 ezSatPtr ez1, ez2;
429 SigMap sigmap(gold_mod);
430 SatGen satgen1(ez1.get(), &sigmap);
431 SatGen satgen2(ez2.get(), &sigmap);
432 satgen2.model_undef = true;
433
434 if (!nosat)
435 for (auto cell : gold_mod->cells()) {
436 satgen1.importCell(cell);
437 satgen2.importCell(cell);
438 }
439
440 if (vlog_file.is_open())
441 {
442 vlog_file << stringf("\nmodule %s;\n", uut_name.c_str());
443
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));
448 else
449 vlog_file << stringf(" wire [%d:0] %s_expr, %s_noexpr;\n", GetSize(wire)-1, log_id(wire), log_id(wire));
450 }
451
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");
457
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");
463
464 vlog_file << stringf(" task run;\n");
465 vlog_file << stringf(" begin\n");
466 vlog_file << stringf(" $display(\"%s\");\n", uut_name.c_str());
467 }
468
469 for (int i = 0; i < 64; i++)
470 {
471 log(verbose ? "\n" : ".");
472 gold_ce.clear();
473 gate_ce.clear();
474
475 RTLIL::SigSpec in_sig, in_val;
476 RTLIL::SigSpec out_sig, out_val;
477 std::string vlog_pattern_info;
478
479 for (auto port : gold_mod->ports)
480 {
481 RTLIL::Wire *gold_wire = gold_mod->wire(port);
482 RTLIL::Wire *gate_wire = gate_mod->wire(port);
483
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));
488
489 if (!gold_wire->port_input)
490 continue;
491
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);
495
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;
501 }
502
503 if (verbose)
504 log("%s: %s\n", log_id(gold_wire), log_signal(in_value));
505
506 in_sig.append(gold_wire);
507 in_val.append(in_value);
508
509 gold_ce.set(gold_wire, in_value);
510 gate_ce.set(gate_wire, in_value);
511
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));
517 }
518 }
519
520 if (vlog_file.is_open())
521 vlog_file << stringf(" #1;\n");
522
523 for (auto port : gold_mod->ports)
524 {
525 RTLIL::Wire *gold_wire = gold_mod->wire(port);
526 RTLIL::Wire *gate_wire = gate_mod->wire(port);
527
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));
532
533 if (!gold_wire->port_output)
534 continue;
535
536 RTLIL::SigSpec gold_outval(gold_wire);
537 RTLIL::SigSpec gate_outval(gate_wire);
538
539 if (!gold_ce.eval(gold_outval))
540 log_error("Failed to eval %s in gold module.\n", log_id(gold_wire));
541
542 if (!gate_ce.eval(gate_outval))
543 log_error("Failed to eval %s in gate module.\n", log_id(gate_wire));
544
545 bool gold_gate_mismatch = false;
546 for (int i = 0; i < GetSize(gold_wire); i++) {
547 if (gold_outval[i] == RTLIL::Sx)
548 continue;
549 if (gold_outval[i] == gate_outval[i])
550 continue;
551 gold_gate_mismatch = true;
552 break;
553 }
554
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));
557
558 if (verbose)
559 log("%s: %s\n", log_id(gold_wire), log_signal(gold_outval));
560
561 out_sig.append(gold_wire);
562 out_val.append(gold_outval);
563
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());
569 }
570 }
571
572 if (verbose)
573 log("EVAL: %s\n", out_val.as_string().c_str());
574
575 if (!nosat)
576 {
577 std::vector<int> sat1_in_sig = satgen1.importSigSpec(in_sig);
578 std::vector<int> sat1_in_val = satgen1.importSigSpec(in_val);
579
580 std::vector<int> sat1_model = satgen1.importSigSpec(out_sig);
581 std::vector<bool> sat1_model_value;
582
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");
585
586 if (verbose) {
587 log("SAT 1: ");
588 for (int i = GetSize(out_sig)-1; i >= 0; i--)
589 log("%c", sat1_model_value.at(i) ? '1' : '0');
590 log("\n");
591 }
592
593 for (int i = 0; i < GetSize(out_sig); i++) {
594 if (out_val[i] != RTLIL::S0 && out_val[i] != RTLIL::S1)
595 continue;
596 if (out_val[i] == RTLIL::S0 && sat1_model_value.at(i) == false)
597 continue;
598 if (out_val[i] == RTLIL::S1 && sat1_model_value.at(i) == true)
599 continue;
600 log_error("Mismatch in sat model 1 (no undef modeling) output!\n");
601 }
602
603 std::vector<int> sat2_in_def_sig = satgen2.importDefSigSpec(in_sig);
604 std::vector<int> sat2_in_def_val = satgen2.importDefSigSpec(in_val);
605
606 std::vector<int> sat2_in_undef_sig = satgen2.importUndefSigSpec(in_sig);
607 std::vector<int> sat2_in_undef_val = satgen2.importUndefSigSpec(in_val);
608
609 std::vector<int> sat2_model_def_sig = satgen2.importDefSigSpec(out_sig);
610 std::vector<int> sat2_model_undef_sig = satgen2.importUndefSigSpec(out_sig);
611
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());
615
616 std::vector<bool> sat2_model_value;
617
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");
620
621 if (verbose) {
622 log("SAT 2: ");
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');
625 log("\n");
626 }
627
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)
631 continue;
632 } else {
633 if (out_val[i] == RTLIL::S0 && sat2_model_value.at(i) == false)
634 continue;
635 if (out_val[i] == RTLIL::S1 && sat2_model_value.at(i) == true)
636 continue;
637 }
638 log_error("Mismatch in sat model 2 (undef modeling) output!\n");
639 }
640 }
641 }
642
643 if (vlog_file.is_open()) {
644 vlog_file << stringf(" end\n");
645 vlog_file << stringf(" endtask\n");
646 vlog_file << stringf("endmodule\n");
647 }
648
649 if (!verbose)
650 log(" ok.\n");
651 }
652
653 struct TestCellPass : public Pass {
654 TestCellPass() : Pass("test_cell", "automatically test the implementation of a cell type") { }
655 void help() YS_OVERRIDE
656 {
657 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
658 log("\n");
659 log(" test_cell [options] {cell-types}\n");
660 log("\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");
663 log("\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");
666 log("\n");
667 log(" -n {integer}\n");
668 log(" create this number of cell instances and test them (default = 100).\n");
669 log("\n");
670 log(" -s {positive_integer}\n");
671 log(" use this value as rng seed value (default = unix time).\n");
672 log("\n");
673 log(" -f {ilang_file}\n");
674 log(" don't generate circuits. instead load the specified ilang file.\n");
675 log("\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");
679 log("\n");
680 log(" -map {filename}\n");
681 log(" pass this option to techmap.\n");
682 log("\n");
683 log(" -simlib\n");
684 log(" use \"techmap -D SIMLIB_NOCHECKS -map +/simlib.v -max_iter 2 -autoproc\"\n");
685 log("\n");
686 log(" -aigmap\n");
687 log(" instead of calling \"techmap\", call \"aigmap\"\n");
688 log("\n");
689 log(" -muxdiv\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");
692 log("\n");
693 log(" -script {script_file}\n");
694 log(" instead of calling \"techmap\", call \"script {script_file}\".\n");
695 log("\n");
696 log(" -const\n");
697 log(" set some input bits to random constant values\n");
698 log("\n");
699 log(" -nosat\n");
700 log(" do not check SAT model or run SAT equivalence checking\n");
701 log("\n");
702 log(" -noeval\n");
703 log(" do not check const-eval models\n");
704 log("\n");
705 log(" -edges\n");
706 log(" test cell edges db creator against sat-based implementation\n");
707 log("\n");
708 log(" -v\n");
709 log(" print additional debug information to the console\n");
710 log("\n");
711 log(" -vlog {filename}\n");
712 log(" create a Verilog test bench to test simlib and write_verilog\n");
713 log("\n");
714 }
715 void execute(std::vector<std::string> args, RTLIL::Design*) YS_OVERRIDE
716 {
717 int num_iter = 100;
718 std::string techmap_cmd = "techmap -assert";
719 std::string ilang_file, write_prefix;
720 xorshift32_state = 0;
721 std::ofstream vlog_file;
722 bool muxdiv = false;
723 bool verbose = false;
724 bool constmode = false;
725 bool nosat = false;
726 bool noeval = false;
727 bool edges = false;
728
729 int argidx;
730 for (argidx = 1; argidx < GetSize(args); argidx++)
731 {
732 if (args[argidx] == "-n" && argidx+1 < GetSize(args)) {
733 num_iter = atoi(args[++argidx].c_str());
734 continue;
735 }
736 if (args[argidx] == "-s" && argidx+1 < GetSize(args)) {
737 xorshift32_state = atoi(args[++argidx].c_str());
738 continue;
739 }
740 if (args[argidx] == "-map" && argidx+1 < GetSize(args)) {
741 techmap_cmd += " -map " + args[++argidx];
742 continue;
743 }
744 if (args[argidx] == "-f" && argidx+1 < GetSize(args)) {
745 ilang_file = args[++argidx];
746 num_iter = 1;
747 continue;
748 }
749 if (args[argidx] == "-w" && argidx+1 < GetSize(args)) {
750 write_prefix = args[++argidx];
751 continue;
752 }
753 if (args[argidx] == "-script" && argidx+1 < GetSize(args)) {
754 techmap_cmd = "script " + args[++argidx];
755 continue;
756 }
757 if (args[argidx] == "-simlib") {
758 techmap_cmd = "techmap -D SIMLIB_NOCHECKS -map +/simlib.v -max_iter 2 -autoproc";
759 continue;
760 }
761 if (args[argidx] == "-aigmap") {
762 techmap_cmd = "aigmap";
763 continue;
764 }
765 if (args[argidx] == "-muxdiv") {
766 muxdiv = true;
767 continue;
768 }
769 if (args[argidx] == "-const") {
770 constmode = true;
771 continue;
772 }
773 if (args[argidx] == "-nosat") {
774 nosat = true;
775 continue;
776 }
777 if (args[argidx] == "-noeval") {
778 noeval = true;
779 continue;
780 }
781 if (args[argidx] == "-edges") {
782 edges = true;
783 continue;
784 }
785 if (args[argidx] == "-v") {
786 verbose = true;
787 continue;
788 }
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());
793 continue;
794 }
795 break;
796 }
797
798 if (xorshift32_state == 0) {
799 xorshift32_state = time(NULL) & 0x7fffffff;
800 log("Rng seed value: %d\n", int(xorshift32_state));
801 }
802
803 std::map<std::string, std::string> cell_types;
804 std::vector<std::string> selected_cell_types;
805
806 cell_types["$not"] = "ASY";
807 cell_types["$pos"] = "ASY";
808 cell_types["$neg"] = "ASY";
809
810 cell_types["$and"] = "ABSY";
811 cell_types["$or"] = "ABSY";
812 cell_types["$xor"] = "ABSY";
813 cell_types["$xnor"] = "ABSY";
814
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";
820
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";
827
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";
836
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";
843
844 cell_types["$logic_not"] = "ASY";
845 cell_types["$logic_and"] = "ABSY";
846 cell_types["$logic_or"] = "ABSY";
847
848 if (edges) {
849 cell_types["$mux"] = "*";
850 cell_types["$pmux"] = "*";
851 }
852
853 // cell_types["$slice"] = "A";
854 // cell_types["$concat"] = "A";
855
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"] = "*";
862
863 for (; argidx < GetSize(args); argidx++)
864 {
865 if (args[argidx].rfind("-", 0) == 0)
866 log_cmd_error("Unexpected option: %s\n", args[argidx].c_str());
867
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);
872 continue;
873 }
874
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);
881 continue;
882 }
883
884 if (cell_types.count(args[argidx]) == 0) {
885 std::string cell_type_list;
886 int charcount = 100;
887 for (auto &it : cell_types) {
888 if (charcount > 60) {
889 cell_type_list += "\n" + it.first;
890 charcount = 0;
891 } else
892 cell_type_list += " " + it.first;
893 charcount += GetSize(it.first);
894 }
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());
897 }
898
899 if (std::count(selected_cell_types.begin(), selected_cell_types.end(), args[argidx]) == 0)
900 selected_cell_types.push_back(args[argidx]);
901 }
902
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");
907 }
908
909 if (selected_cell_types.empty())
910 log_cmd_error("No cell type to test specified.\n");
911
912 std::vector<std::string> uut_names;
913
914 for (auto cell_type : selected_cell_types)
915 for (int i = 0; i < num_iter; i++)
916 {
917 RTLIL::Design *design = new RTLIL::Design;
918 if (cell_type == "ilang")
919 Frontend::frontend_call(design, NULL, std::string(), "ilang " + ilang_file);
920 else
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));
924 } else if (edges) {
925 Pass::call(design, "dump gold");
926 run_edges_test(design, verbose);
927 } else {
928 Pass::call(design, stringf("copy gold gate; cd gate; %s; cd ..; opt -fast gate", techmap_cmd.c_str()));
929 if (!nosat)
930 Pass::call(design, "miter -equiv -flatten -make_outputs -ignore_gold_x gold gate miter");
931 if (verbose)
932 Pass::call(design, "dump gate");
933 Pass::call(design, "dump gold");
934 if (!nosat)
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);
943 }
944 if (!noeval)
945 run_eval_test(design, verbose, nosat, uut_name, vlog_file);
946 }
947 delete design;
948 }
949
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";
959 }
960 }
961 } TestCellPass;
962
963 PRIVATE_NAMESPACE_END