Added eval testing to test_cell
[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/consteval.h"
23 #include <algorithm>
24
25 static uint32_t xorshift32_state = 123456789;
26
27 static uint32_t xorshift32(uint32_t limit) {
28 xorshift32_state ^= xorshift32_state << 13;
29 xorshift32_state ^= xorshift32_state >> 17;
30 xorshift32_state ^= xorshift32_state << 5;
31 return xorshift32_state % limit;
32 }
33
34 static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type, std::string cell_type_flags)
35 {
36 RTLIL::Module *module = design->addModule("\\gold");
37 RTLIL::Cell *cell = module->addCell("\\UUT", cell_type);
38 RTLIL::Wire *wire;
39
40 if (cell_type == "$lut")
41 {
42 int width = 1 + xorshift32(6);
43
44 wire = module->addWire("\\A");
45 wire->width = width;
46 wire->port_input = true;
47 cell->setPort("\\A", wire);
48
49 wire = module->addWire("\\Y");
50 wire->port_output = true;
51 cell->setPort("\\Y", wire);
52
53 RTLIL::SigSpec config;
54 for (int i = 0; i < (1 << width); i++)
55 config.append(xorshift32(2) ? RTLIL::S1 : RTLIL::S0);
56
57 cell->setParam("\\LUT", config.as_const());
58 }
59
60 if (cell_type_flags.find('A') != std::string::npos) {
61 wire = module->addWire("\\A");
62 wire->width = 1 + xorshift32(8);
63 wire->port_input = true;
64 cell->setPort("\\A", wire);
65 }
66
67 if (cell_type_flags.find('B') != std::string::npos) {
68 wire = module->addWire("\\B");
69 if (cell_type_flags.find('h') != std::string::npos)
70 wire->width = 1 + xorshift32(6);
71 else
72 wire->width = 1 + xorshift32(8);
73 wire->port_input = true;
74 cell->setPort("\\B", wire);
75 }
76
77 if (cell_type_flags.find('S') != std::string::npos && xorshift32(2)) {
78 if (cell_type_flags.find('A') != std::string::npos)
79 cell->parameters["\\A_SIGNED"] = true;
80 if (cell_type_flags.find('B') != std::string::npos)
81 cell->parameters["\\B_SIGNED"] = true;
82 }
83
84 if (cell_type_flags.find('s') != std::string::npos) {
85 if (cell_type_flags.find('A') != std::string::npos && xorshift32(2))
86 cell->parameters["\\A_SIGNED"] = true;
87 if (cell_type_flags.find('B') != std::string::npos && xorshift32(2))
88 cell->parameters["\\B_SIGNED"] = true;
89 }
90
91 if (cell_type_flags.find('Y') != std::string::npos) {
92 wire = module->addWire("\\Y");
93 wire->width = 1 + xorshift32(8);
94 wire->port_output = true;
95 cell->setPort("\\Y", wire);
96 }
97
98 module->fixup_ports();
99 cell->fixup_parameters();
100 cell->check();
101 }
102
103 static void run_eval_test(RTLIL::Design *design)
104 {
105 RTLIL::Module *gold_mod = design->module("\\gold");
106 RTLIL::Module *gate_mod = design->module("\\gate");
107 ConstEval gold_ce(gold_mod), gate_ce(gate_mod);
108
109 log("Eval testing: ");
110
111 for (int i = 0; i < 64; i++)
112 {
113 log(".");
114 gold_ce.clear();
115 gate_ce.clear();
116
117 for (auto port : gold_mod->ports)
118 {
119 RTLIL::Wire *gold_wire = gold_mod->wire(port);
120 RTLIL::Wire *gate_wire = gate_mod->wire(port);
121
122 log_assert(gold_wire != nullptr);
123 log_assert(gate_wire != nullptr);
124 log_assert(gold_wire->port_input == gate_wire->port_input);
125 log_assert(SIZE(gold_wire) == SIZE(gate_wire));
126
127 if (!gold_wire->port_input)
128 continue;
129
130 RTLIL::Const in_value;
131 for (int i = 0; i < SIZE(gold_wire); i++)
132 in_value.bits.push_back(xorshift32(2) ? RTLIL::S1 : RTLIL::S0);
133
134 if (xorshift32(4) == 0) {
135 int inv_chance = 1 + xorshift32(8);
136 for (int i = 0; i < SIZE(gold_wire); i++)
137 if (xorshift32(inv_chance) == 0)
138 in_value.bits[i] = RTLIL::Sx;
139 }
140
141 // log("%s: %s\n", log_id(gold_wire), log_signal(in_value));
142
143 gold_ce.set(gold_wire, in_value);
144 gate_ce.set(gate_wire, in_value);
145 }
146
147 for (auto port : gold_mod->ports)
148 {
149 RTLIL::Wire *gold_wire = gold_mod->wire(port);
150 RTLIL::Wire *gate_wire = gate_mod->wire(port);
151
152 log_assert(gold_wire != nullptr);
153 log_assert(gate_wire != nullptr);
154 log_assert(gold_wire->port_output == gate_wire->port_output);
155 log_assert(SIZE(gold_wire) == SIZE(gate_wire));
156
157 if (!gold_wire->port_output)
158 continue;
159
160 RTLIL::SigSpec gold_outval(gold_wire);
161 RTLIL::SigSpec gate_outval(gate_wire);
162
163 if (!gold_ce.eval(gold_outval))
164 log_error("Failed to eval %s in gold module.\n", log_id(gold_wire));
165
166 if (!gate_ce.eval(gate_outval))
167 log_error("Failed to eval %s in gate module.\n", log_id(gate_wire));
168
169 bool gold_gate_mismatch = false;
170 for (int i = 0; i < SIZE(gold_wire); i++) {
171 if (gold_outval[i] == RTLIL::Sx)
172 continue;
173 if (gold_outval[i] == gate_outval[i])
174 continue;
175 gold_gate_mismatch = true;
176 break;
177 }
178
179 if (gold_gate_mismatch)
180 log_error("Mismatch in output %s: gold:%s != gate:%s\n", log_id(gate_wire), log_signal(gold_outval), log_signal(gate_outval));
181
182 // log("%s: %s\n", log_id(gold_wire), log_signal(gold_outval));
183 }
184 }
185
186 log(" ok.\n");
187 }
188
189 struct TestCellPass : public Pass {
190 TestCellPass() : Pass("test_cell", "automatically test the implementation of a cell type") { }
191 virtual void help()
192 {
193 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
194 log("\n");
195 log(" test_cell [options] {cell-types}\n");
196 log("\n");
197 log("Tests the internal implementation of the given cell type (for example '$mux')\n");
198 log("by comparing SAT solver, EVAL and TECHMAP implementations of the cell types..\n");
199 log("\n");
200 log("Run with 'all' instead of a cell type to run the test on all supported\n");
201 log("cell types.\n");
202 log("\n");
203 log(" -n {integer}\n");
204 log(" create this number of cell instances and test them (default = 100).\n");
205 log("\n");
206 log(" -s {positive_integer}\n");
207 log(" use this value as rng seed value (default = unix time).\n");
208 log("\n");
209 log(" -f {ilang_file}\n");
210 log(" don't generate circuits. instead load the specified ilang file.\n");
211 log("\n");
212 log(" -map {filename}\n");
213 log(" pass this option to techmap.\n");
214 log("\n");
215 }
216 virtual void execute(std::vector<std::string> args, RTLIL::Design*)
217 {
218 int num_iter = 100;
219 std::string techmap_cmd = "techmap -assert";
220 std::string ilang_file;
221 xorshift32_state = 0;
222
223 int argidx;
224 for (argidx = 1; argidx < SIZE(args); argidx++)
225 {
226 if (args[argidx] == "-n" && argidx+1 < SIZE(args)) {
227 num_iter = atoi(args[++argidx].c_str());
228 continue;
229 }
230 if (args[argidx] == "-s" && argidx+1 < SIZE(args)) {
231 xorshift32_state = atoi(args[++argidx].c_str());
232 continue;
233 }
234 if (args[argidx] == "-map" && argidx+1 < SIZE(args)) {
235 techmap_cmd += " -map " + args[++argidx];
236 continue;
237 }
238 if (args[argidx] == "-f" && argidx+1 < SIZE(args)) {
239 ilang_file = args[++argidx];
240 num_iter = 1;
241 continue;
242 }
243 break;
244 }
245
246 if (xorshift32_state == 0)
247 xorshift32_state = time(NULL);
248
249 std::map<std::string, std::string> cell_types;
250 std::vector<std::string> selected_cell_types;
251
252 cell_types["$not"] = "ASY";
253 cell_types["$pos"] = "ASY";
254 cell_types["$bu0"] = "ASY";
255 cell_types["$neg"] = "ASY";
256
257 cell_types["$and"] = "ABSY";
258 cell_types["$or"] = "ABSY";
259 cell_types["$xor"] = "ABSY";
260 cell_types["$xnor"] = "ABSY";
261
262 cell_types["$reduce_and"] = "ASY";
263 cell_types["$reduce_or"] = "ASY";
264 cell_types["$reduce_xor"] = "ASY";
265 cell_types["$reduce_xnor"] = "ASY";
266 cell_types["$reduce_bool"] = "ASY";
267
268 cell_types["$shl"] = "ABshY";
269 cell_types["$shr"] = "ABshY";
270 cell_types["$sshl"] = "ABshY";
271 cell_types["$sshr"] = "ABshY";
272 cell_types["$shift"] = "ABshY";
273 cell_types["$shiftx"] = "ABshY";
274
275 cell_types["$lt"] = "ABSY";
276 cell_types["$le"] = "ABSY";
277 cell_types["$eq"] = "ABSY";
278 cell_types["$ne"] = "ABSY";
279 // cell_types["$eqx"] = "ABSY";
280 // cell_types["$nex"] = "ABSY";
281 cell_types["$ge"] = "ABSY";
282 cell_types["$gt"] = "ABSY";
283
284 cell_types["$add"] = "ABSY";
285 cell_types["$sub"] = "ABSY";
286 cell_types["$mul"] = "ABSY";
287 cell_types["$div"] = "ABSY";
288 cell_types["$mod"] = "ABSY";
289 // cell_types["$pow"] = "ABsY";
290
291 cell_types["$logic_not"] = "ASY";
292 cell_types["$logic_and"] = "ABSY";
293 cell_types["$logic_or"] = "ABSY";
294
295 // cell_types["$mux"] = "A";
296 // cell_types["$pmux"] = "A";
297 // cell_types["$slice"] = "A";
298 // cell_types["$concat"] = "A";
299 // cell_types["$assert"] = "A";
300
301 cell_types["$lut"] = "*";
302 // cell_types["$alu"] = "*";
303
304 for (; argidx < SIZE(args); argidx++)
305 {
306 if (args[argidx].rfind("-", 0) == 0)
307 log_cmd_error("Unexpected option: %s\n", args[argidx].c_str());
308
309 if (args[argidx] == "all") {
310 for (auto &it : cell_types)
311 if (std::count(selected_cell_types.begin(), selected_cell_types.end(), it.first) == 0)
312 selected_cell_types.push_back(it.first);
313 continue;
314 }
315
316 if (cell_types.count(args[argidx]) == 0) {
317 std::string cell_type_list;
318 int charcount = 100;
319 for (auto &it : cell_types) {
320 if (charcount > 60) {
321 cell_type_list += "\n" + it.first;
322 charcount = 0;
323 } else
324 cell_type_list += " " + it.first;
325 charcount += SIZE(it.first);
326 }
327 log_cmd_error("The cell type `%s' is currently not supported. Try one of these:%s\n",
328 args[argidx].c_str(), cell_type_list.c_str());
329 }
330
331 if (std::count(selected_cell_types.begin(), selected_cell_types.end(), args[argidx]) == 0)
332 selected_cell_types.push_back(args[argidx]);
333 }
334
335 if (!ilang_file.empty()) {
336 if (!selected_cell_types.empty())
337 log_cmd_error("Do not specify any cell types when using -f.\n");
338 selected_cell_types.push_back("ilang");
339 }
340
341 if (selected_cell_types.empty())
342 log_cmd_error("No cell type to test specified.\n");
343
344 for (auto cell_type : selected_cell_types)
345 for (int i = 0; i < num_iter; i++)
346 {
347 RTLIL::Design *design = new RTLIL::Design;
348 if (cell_type == "ilang")
349 Frontend::frontend_call(design, NULL, std::string(), "ilang " + ilang_file);
350 else
351 create_gold_module(design, cell_type, cell_types.at(cell_type));
352 Pass::call(design, stringf("copy gold gate; %s gate; opt gate", techmap_cmd.c_str()));
353 Pass::call(design, "miter -equiv -flatten -make_outputs -ignore_gold_x gold gate miter; dump gold");
354 Pass::call(design, "sat -verify -enable_undef -prove trigger 0 -show-inputs -show-outputs miter");
355 run_eval_test(design);
356 delete design;
357 }
358 }
359 } TestCellPass;
360