2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2014 Clifford Wolf <clifford@clifford.at>
5 * Copyright (C) 2014 Johann Glaser <Johann.Glaser@gmx.at>
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.
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.
21 #include "kernel/yosys.h"
22 #include "kernel/consteval.h"
25 static uint32_t xorshift32_state
= 123456789;
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
;
34 static void create_gold_module(RTLIL::Design
*design
, RTLIL::IdString cell_type
, std::string cell_type_flags
)
36 RTLIL::Module
*module
= design
->addModule("\\gold");
37 RTLIL::Cell
*cell
= module
->addCell("\\UUT", cell_type
);
40 if (cell_type
== "$lut")
42 int width
= 1 + xorshift32(6);
44 wire
= module
->addWire("\\A");
46 wire
->port_input
= true;
47 cell
->setPort("\\A", wire
);
49 wire
= module
->addWire("\\Y");
50 wire
->port_output
= true;
51 cell
->setPort("\\Y", wire
);
53 RTLIL::SigSpec config
;
54 for (int i
= 0; i
< (1 << width
); i
++)
55 config
.append(xorshift32(2) ? RTLIL::S1
: RTLIL::S0
);
57 cell
->setParam("\\LUT", config
.as_const());
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
);
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);
72 wire
->width
= 1 + xorshift32(8);
73 wire
->port_input
= true;
74 cell
->setPort("\\B", wire
);
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;
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;
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
);
98 module
->fixup_ports();
99 cell
->fixup_parameters();
103 static void run_eval_test(RTLIL::Design
*design
)
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
);
109 log("Eval testing: ");
111 for (int i
= 0; i
< 64; i
++)
117 for (auto port
: gold_mod
->ports
)
119 RTLIL::Wire
*gold_wire
= gold_mod
->wire(port
);
120 RTLIL::Wire
*gate_wire
= gate_mod
->wire(port
);
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
));
127 if (!gold_wire
->port_input
)
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
);
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
;
141 // log("%s: %s\n", log_id(gold_wire), log_signal(in_value));
143 gold_ce
.set(gold_wire
, in_value
);
144 gate_ce
.set(gate_wire
, in_value
);
147 for (auto port
: gold_mod
->ports
)
149 RTLIL::Wire
*gold_wire
= gold_mod
->wire(port
);
150 RTLIL::Wire
*gate_wire
= gate_mod
->wire(port
);
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
));
157 if (!gold_wire
->port_output
)
160 RTLIL::SigSpec
gold_outval(gold_wire
);
161 RTLIL::SigSpec
gate_outval(gate_wire
);
163 if (!gold_ce
.eval(gold_outval
))
164 log_error("Failed to eval %s in gold module.\n", log_id(gold_wire
));
166 if (!gate_ce
.eval(gate_outval
))
167 log_error("Failed to eval %s in gate module.\n", log_id(gate_wire
));
169 bool gold_gate_mismatch
= false;
170 for (int i
= 0; i
< SIZE(gold_wire
); i
++) {
171 if (gold_outval
[i
] == RTLIL::Sx
)
173 if (gold_outval
[i
] == gate_outval
[i
])
175 gold_gate_mismatch
= true;
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
));
182 // log("%s: %s\n", log_id(gold_wire), log_signal(gold_outval));
189 struct TestCellPass
: public Pass
{
190 TestCellPass() : Pass("test_cell", "automatically test the implementation of a cell type") { }
193 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
195 log(" test_cell [options] {cell-types}\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");
200 log("Run with 'all' instead of a cell type to run the test on all supported\n");
201 log("cell types.\n");
203 log(" -n {integer}\n");
204 log(" create this number of cell instances and test them (default = 100).\n");
206 log(" -s {positive_integer}\n");
207 log(" use this value as rng seed value (default = unix time).\n");
209 log(" -f {ilang_file}\n");
210 log(" don't generate circuits. instead load the specified ilang file.\n");
212 log(" -map {filename}\n");
213 log(" pass this option to techmap.\n");
216 virtual void execute(std::vector
<std::string
> args
, RTLIL::Design
*)
219 std::string techmap_cmd
= "techmap -assert";
220 std::string ilang_file
;
221 xorshift32_state
= 0;
224 for (argidx
= 1; argidx
< SIZE(args
); argidx
++)
226 if (args
[argidx
] == "-n" && argidx
+1 < SIZE(args
)) {
227 num_iter
= atoi(args
[++argidx
].c_str());
230 if (args
[argidx
] == "-s" && argidx
+1 < SIZE(args
)) {
231 xorshift32_state
= atoi(args
[++argidx
].c_str());
234 if (args
[argidx
] == "-map" && argidx
+1 < SIZE(args
)) {
235 techmap_cmd
+= " -map " + args
[++argidx
];
238 if (args
[argidx
] == "-f" && argidx
+1 < SIZE(args
)) {
239 ilang_file
= args
[++argidx
];
246 if (xorshift32_state
== 0)
247 xorshift32_state
= time(NULL
);
249 std::map
<std::string
, std::string
> cell_types
;
250 std::vector
<std::string
> selected_cell_types
;
252 cell_types
["$not"] = "ASY";
253 cell_types
["$pos"] = "ASY";
254 cell_types
["$bu0"] = "ASY";
255 cell_types
["$neg"] = "ASY";
257 cell_types
["$and"] = "ABSY";
258 cell_types
["$or"] = "ABSY";
259 cell_types
["$xor"] = "ABSY";
260 cell_types
["$xnor"] = "ABSY";
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";
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";
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";
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";
291 cell_types
["$logic_not"] = "ASY";
292 cell_types
["$logic_and"] = "ABSY";
293 cell_types
["$logic_or"] = "ABSY";
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";
301 cell_types
["$lut"] = "*";
302 // cell_types["$alu"] = "*";
304 for (; argidx
< SIZE(args
); argidx
++)
306 if (args
[argidx
].rfind("-", 0) == 0)
307 log_cmd_error("Unexpected option: %s\n", args
[argidx
].c_str());
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
);
316 if (cell_types
.count(args
[argidx
]) == 0) {
317 std::string cell_type_list
;
319 for (auto &it
: cell_types
) {
320 if (charcount
> 60) {
321 cell_type_list
+= "\n" + it
.first
;
324 cell_type_list
+= " " + it
.first
;
325 charcount
+= SIZE(it
.first
);
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());
331 if (std::count(selected_cell_types
.begin(), selected_cell_types
.end(), args
[argidx
]) == 0)
332 selected_cell_types
.push_back(args
[argidx
]);
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");
341 if (selected_cell_types
.empty())
342 log_cmd_error("No cell type to test specified.\n");
344 for (auto cell_type
: selected_cell_types
)
345 for (int i
= 0; i
< num_iter
; i
++)
347 RTLIL::Design
*design
= new RTLIL::Design
;
348 if (cell_type
== "ilang")
349 Frontend::frontend_call(design
, NULL
, std::string(), "ilang " + ilang_file
);
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
);