45 if (cell_type ==
"$fa")
75 if (cell_type ==
"$lcu")
99 if (cell_type ==
"$macc")
104 int mulbits_a = 0, mulbits_b = 0;
110 for (
int i = 0; i < depth; i++)
113 int size_b = depth > 4 ? 0 :
xorshift32(width) + 1;
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;
123 wire_a->
width += size_a;
126 wire_a->
width += size_b;
131 macc.
ports.push_back(this_port);
147 if (cell_type ==
"$lut")
161 for (
int i = 0; i < (1 << width); i++)
167 if (cell_type_flags.find(
'A') != std::string::npos) {
174 if (cell_type_flags.find(
'B') != std::string::npos) {
176 if (cell_type_flags.find(
'h') != std::string::npos)
184 if (cell_type_flags.find(
'S') != std::string::npos &&
xorshift32(2)) {
185 if (cell_type_flags.find(
'A') != std::string::npos)
187 if (cell_type_flags.find(
'B') != std::string::npos)
191 if (cell_type_flags.find(
's') != std::string::npos) {
192 if (cell_type_flags.find(
'A') != std::string::npos &&
xorshift32(2))
194 if (cell_type_flags.find(
'B') != std::string::npos &&
xorshift32(2))
198 if (cell_type_flags.find(
'Y') != std::string::npos) {
205 if (cell_type ==
"$alu")
207 wire = module->
addWire(
"\\CI");
211 wire = module->
addWire(
"\\BI");
220 wire = module->
addWire(
"\\CO");
229 for (
auto &conn : conn_list)
241 for (
int i = 0; i <
n; i++)
246 for (
int i = n; i <
GetSize(sig); i++)
252 for (
int i = std::min(n, m); i < std::max(n, m); i++)
257 cell->
setPort(conn.first, sig);
268 log(
"Eval testing:%c", verbose ?
'\n' :
' ');
272 ConstEval gold_ce(gold_mod), gate_ce(gate_mod);
276 SatGen satgen1(&ez1, &sigmap);
277 SatGen satgen2(&ez2, &sigmap);
281 for (
auto cell : gold_mod->
cells()) {
286 if (vlog_file.is_open())
288 vlog_file <<
stringf(
"\nmodule %s;\n", uut_name.c_str());
290 for (
auto port : gold_mod->
ports) {
298 vlog_file <<
stringf(
" %s_expr uut_expr(", uut_name.c_str());
304 vlog_file <<
stringf(
" %s_expr uut_noexpr(", uut_name.c_str());
310 vlog_file <<
stringf(
" task run;\n");
311 vlog_file <<
stringf(
" begin\n");
312 vlog_file <<
stringf(
" $display(\"%s\");\n", uut_name.c_str());
315 for (
int i = 0; i < 64; i++)
317 log(verbose ?
"\n" :
".");
323 std::string vlog_pattern_info;
325 for (
auto port : gold_mod->
ports)
339 for (
int i = 0; i <
GetSize(gold_wire); i++)
344 for (
int i = 0; i <
GetSize(gold_wire); i++)
355 gold_ce.set(gold_wire, in_value);
356 gate_ce.
set(gate_wire, in_value);
358 if (vlog_file.is_open() &&
GetSize(in_value) > 0) {
360 if (!vlog_pattern_info.empty())
361 vlog_pattern_info +=
" ";
366 if (vlog_file.is_open())
367 vlog_file <<
stringf(
" #1;\n");
369 for (
auto port : gold_mod->
ports)
385 if (!gold_ce.eval(gold_outval))
388 if (!gate_ce.
eval(gate_outval))
391 bool gold_gate_mismatch =
false;
392 for (
int i = 0; i <
GetSize(gold_wire); i++) {
395 if (gold_outval[i] == gate_outval[i])
397 gold_gate_mismatch =
true;
401 if (gold_gate_mismatch)
407 out_sig.
append(gold_wire);
408 out_val.
append(gold_outval);
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",
413 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());
414 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());
423 std::vector<int> sat1_in_sig = satgen1.
importSigSpec(in_sig);
424 std::vector<int> sat1_in_val = satgen1.
importSigSpec(in_val);
426 std::vector<int> sat1_model = satgen1.
importSigSpec(out_sig);
427 std::vector<bool> sat1_model_value;
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");
434 for (
int i =
GetSize(out_sig)-1; i >= 0; i--)
435 log(
"%c", sat1_model_value.at(i) ?
'1' :
'0');
439 for (
int i = 0; i <
GetSize(out_sig); i++) {
442 if (out_val[i] ==
RTLIL::S0 && sat1_model_value.at(i) ==
false)
444 if (out_val[i] ==
RTLIL::S1 && sat1_model_value.at(i) ==
true)
446 log_error(
"Mismatch in sat model 1 (no undef modeling) output!\n");
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());
462 std::vector<bool> sat2_model_value;
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");
469 for (
int i =
GetSize(out_sig)-1; i >= 0; i--)
470 log(
"%c", sat2_model_value.at(GetSize(out_sig) + i) ?
'x' : sat2_model_value.at(i) ?
'1' :
'0');
474 for (
int i = 0; i <
GetSize(out_sig); i++) {
475 if (sat2_model_value.at(GetSize(out_sig) + i)) {
479 if (out_val[i] ==
RTLIL::S0 && sat2_model_value.at(i) ==
false)
481 if (out_val[i] ==
RTLIL::S1 && sat2_model_value.at(i) ==
true)
484 log_error(
"Mismatch in sat model 2 (undef modeling) output!\n");
489 if (vlog_file.is_open()) {
490 vlog_file <<
stringf(
" end\n");
491 vlog_file <<
stringf(
" endtask\n");
492 vlog_file <<
stringf(
"endmodule\n");
500 TestCellPass() :
Pass(
"test_cell",
"automatically test the implementation of a cell type") { }
505 log(
" test_cell [options] {cell-types}\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");
510 log(
"Run with 'all' instead of a cell type to run the test on all supported\n");
511 log(
"cell types.\n");
513 log(
" -n {integer}\n");
514 log(
" create this number of cell instances and test them (default = 100).\n");
516 log(
" -s {positive_integer}\n");
517 log(
" use this value as rng seed value (default = unix time).\n");
519 log(
" -f {ilang_file}\n");
520 log(
" don't generate circuits. instead load the specified ilang file.\n");
522 log(
" -map {filename}\n");
523 log(
" pass this option to techmap.\n");
526 log(
" use \"techmap -map +/simlib.v -max_iter 2 -autoproc\"\n");
528 log(
" -script {script_file}\n");
529 log(
" instead of calling \"techmap\", call \"script {script_file}\".\n");
532 log(
" set some input bits to random constant values\n");
535 log(
" do not check SAT model or run SAT equivalence checking\n");
538 log(
" print additional debug information to the console\n");
540 log(
" -vlog {filename}\n");
541 log(
" create a verilog test bench to test simlib and write_verilog\n");
547 std::string techmap_cmd =
"techmap -assert";
548 std::string ilang_file;
550 std::ofstream vlog_file;
551 bool verbose =
false;
552 bool constmode =
false;
556 for (argidx = 1; argidx <
GetSize(args); argidx++)
558 if (args[argidx] ==
"-n" && argidx+1 <
GetSize(args)) {
559 num_iter = atoi(args[++argidx].c_str());
562 if (args[argidx] ==
"-s" && argidx+1 <
GetSize(args)) {
566 if (args[argidx] ==
"-map" && argidx+1 <
GetSize(args)) {
567 techmap_cmd +=
" -map " + args[++argidx];
570 if (args[argidx] ==
"-f" && argidx+1 <
GetSize(args)) {
571 ilang_file = args[++argidx];
575 if (args[argidx] ==
"-script" && argidx+1 <
GetSize(args)) {
576 techmap_cmd =
"script " + args[++argidx];
579 if (args[argidx] ==
"-simlib") {
580 techmap_cmd =
"techmap -map +/simlib.v -max_iter 2 -autoproc";
583 if (args[argidx] ==
"-const") {
587 if (args[argidx] ==
"-nosat") {
591 if (args[argidx] ==
"-v") {
595 if (args[argidx] ==
"-vlog" && argidx+1 <
GetSize(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());
609 std::map<std::string, std::string> cell_types;
610 std::vector<std::string> selected_cell_types;
612 cell_types[
"$not"] =
"ASY";
613 cell_types[
"$pos"] =
"ASY";
614 cell_types[
"$neg"] =
"ASY";
616 cell_types[
"$and"] =
"ABSY";
617 cell_types[
"$or"] =
"ABSY";
618 cell_types[
"$xor"] =
"ABSY";
619 cell_types[
"$xnor"] =
"ABSY";
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";
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";
634 cell_types[
"$lt"] =
"ABSY";
635 cell_types[
"$le"] =
"ABSY";
636 cell_types[
"$eq"] =
"ABSY";
637 cell_types[
"$ne"] =
"ABSY";
640 cell_types[
"$ge"] =
"ABSY";
641 cell_types[
"$gt"] =
"ABSY";
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";
650 cell_types[
"$logic_not"] =
"ASY";
651 cell_types[
"$logic_and"] =
"ABSY";
652 cell_types[
"$logic_or"] =
"ABSY";
660 cell_types[
"$lut"] =
"*";
661 cell_types[
"$alu"] =
"ABSY";
662 cell_types[
"$lcu"] =
"*";
663 cell_types[
"$macc"] =
"*";
664 cell_types[
"$fa"] =
"*";
666 for (; argidx <
GetSize(args); argidx++)
668 if (args[argidx].rfind(
"-", 0) == 0)
669 log_cmd_error(
"Unexpected option: %s\n", args[argidx].c_str());
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);
678 if (cell_types.count(args[argidx]) == 0) {
679 std::string cell_type_list;
681 for (
auto &it : cell_types) {
682 if (charcount > 60) {
683 cell_type_list +=
"\n" + it.first;
686 cell_type_list +=
" " + it.first;
687 charcount +=
GetSize(it.first);
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());
693 if (std::count(selected_cell_types.begin(), selected_cell_types.end(), args[argidx]) == 0)
694 selected_cell_types.push_back(args[argidx]);
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");
703 if (selected_cell_types.empty())
706 std::vector<std::string> uut_names;
708 for (
auto cell_type : selected_cell_types)
709 for (
int i = 0; i < num_iter; i++)
712 if (cell_type ==
"ilang")
716 Pass::call(design,
stringf(
"copy gold gate; cd gate; %s; cd ..; opt -fast gate", techmap_cmd.c_str()));
718 Pass::call(design,
"miter -equiv -flatten -make_outputs -ignore_gold_x gold gate miter");
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()));
728 Pass::call(design,
stringf(
"copy gold %s_noexpr; select %s_noexpr", uut_name.c_str(), uut_name.c_str()));
730 uut_names.push_back(uut_name);
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";
void to_cell(RTLIL::Cell *cell) const
void fixup_parameters(bool set_a_signed=false, bool set_b_signed=false)
RTLIL::Wire * wire(RTLIL::IdString id)
std::string stringf(const char *fmt,...)
RTLIL::Cell * addCell(RTLIL::IdString name, RTLIL::IdString type)
void setParam(RTLIL::IdString paramname, RTLIL::Const value)
RTLIL::Const as_const() const
const char * log_signal(const RTLIL::SigSpec &sig, bool autoint)
static void frontend_call(RTLIL::Design *design, std::istream *f, std::string filename, std::string command)
void setPort(RTLIL::IdString portname, RTLIL::SigSpec signal)
bool eval(RTLIL::Cell *cell, RTLIL::SigSpec &undef)
std::vector< int > importSigSpec(RTLIL::SigSpec sig, int timestep=-1)
std::vector< port_t > ports
void log_error(const char *format,...)
std::map< RTLIL::IdString, RTLIL::Const > parameters
std::vector< int > importUndefSigSpec(RTLIL::SigSpec sig, int timestep=-1)
USING_YOSYS_NAMESPACE static PRIVATE_NAMESPACE_BEGIN uint32_t xorshift32_state
YOSYS_NAMESPACE_BEGIN typedef ezMiniSAT ezDefaultSAT
static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::string uut_name, std::ofstream &vlog_file)
std::vector< RTLIL::IdString > ports
static void backend_call(RTLIL::Design *design, std::ostream *f, std::string filename, std::string command)
std::vector< int > importDefSigSpec(RTLIL::SigSpec sig, int timestep=-1)
std::string as_string() const
#define PRIVATE_NAMESPACE_BEGIN
const RTLIL::SigSpec & getPort(RTLIL::IdString portname) const
static uint32_t xorshift32(uint32_t limit)
int GetSize(RTLIL::Wire *wire)
#define log_assert(_assert_expr_)
RTLIL::Wire * addWire(RTLIL::IdString name, int width=1)
#define PRIVATE_NAMESPACE_END
void log_cmd_error(const char *format,...)
virtual void execute(std::vector< std::string > args, RTLIL::Design *)
RTLIL::Module * addModule(RTLIL::IdString name)
RTLIL::Module * module(RTLIL::IdString name)
#define USING_YOSYS_NAMESPACE
RTLIL::ObjRange< RTLIL::Cell * > cells()
static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type, std::string cell_type_flags, bool constmode)
void log(const char *format,...)
bool importCell(RTLIL::Cell *cell, int timestep=-1)
std::vector< RTLIL::State > bits
std::string as_string() const
void append(const RTLIL::SigSpec &signal)
TestCellPass TestCellPass
void set(RTLIL::SigSpec sig, RTLIL::Const value)
static void call(RTLIL::Design *design, std::string command)
const std::map< RTLIL::IdString, RTLIL::SigSpec > & connections() const
const char * log_id(RTLIL::IdString str)