opt_dff: Don't mutate muxes while ModWalker is active.
[yosys.git] / passes / tests / test_autotb.cc
index cf01074eaf0fe5d84a5ad2dd2dfe0ee356ae0e0e..404d1e48da56be4f1413bb89d925ee6dcf8690fc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  yosys -- Yosys Open SYnthesis Suite
  *
- *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *  Copyright (C) 2012  Claire Xenia Wolf <claire@yosyshq.com>
  *
  *  Permission to use, copy, modify, and/or distribute this software for any
  *  purpose with or without fee is hereby granted, provided that the above
@@ -71,21 +71,22 @@ static std::string idy(std::string str1, std::string str2 = std::string(), std::
        return id(str1);
 }
 
-static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
+static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter, int seed)
 {
-       f << stringf("`ifndef dmp_name\n");
-       f << stringf("\t`define dmp_name \"not_defined.dmp\"\n");
+       f << stringf("`ifndef outfile\n");
+       f << stringf("\t`define outfile \"/dev/stdout\"\n");
        f << stringf("`endif\n");
 
        f << stringf("module testbench;\n\n");
 
        f << stringf("integer i;\n");
        f << stringf("integer file;\n\n");
+       f << stringf("reg [1023:0] filename;\n\n");
 
        f << stringf("reg [31:0] xorshift128_x = 123456789;\n");
        f << stringf("reg [31:0] xorshift128_y = 362436069;\n");
        f << stringf("reg [31:0] xorshift128_z = 521288629;\n");
-       f << stringf("reg [31:0] xorshift128_w = %u; // <-- seed value\n", int(time(NULL)));
+       f << stringf("reg [31:0] xorshift128_w = %u; // <-- seed value\n", seed ? seed : int(time(nullptr)));
        f << stringf("reg [31:0] xorshift128_t;\n\n");
        f << stringf("task xorshift128;\n");
        f << stringf("begin\n");
@@ -97,29 +98,26 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
        f << stringf("end\n");
        f << stringf("endtask\n\n");
 
-       for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it)
+       for (auto mod : design->modules())
        {
                std::map<std::string, int> signal_in;
                std::map<std::string, std::string> signal_const;
                std::map<std::string, int> signal_clk;
                std::map<std::string, int> signal_out;
 
-               RTLIL::Module *mod = it->second;
-
-               if (mod->get_bool_attribute("\\gentb_skip"))
+               if (mod->get_bool_attribute(ID::gentb_skip))
                        continue;
 
                int count_ports = 0;
-               log("Generating test bench for module `%s'.\n", it->first.c_str());
-               for (auto it2 = mod->wires_.begin(); it2 != mod->wires_.end(); ++it2) {
-                       RTLIL::Wire *wire = it2->second;
+               log("Generating test bench for module `%s'.\n", mod->name.c_str());
+               for (auto wire : mod->wires()) {
                        if (wire->port_output) {
                                count_ports++;
                                signal_out[idy("sig", mod->name.str(), wire->name.str())] = wire->width;
                                f << stringf("wire [%d:0] %s;\n", wire->width-1, idy("sig", mod->name.str(), wire->name.str()).c_str());
                        } else if (wire->port_input) {
                                count_ports++;
-                               bool is_clksignal = wire->get_bool_attribute("\\gentb_clock");
+                               bool is_clksignal = wire->get_bool_attribute(ID::gentb_clock);
                                for (auto it3 = mod->processes.begin(); it3 != mod->processes.end(); ++it3)
                                for (auto it4 = it3->second->syncs.begin(); it4 != it3->second->syncs.end(); ++it4) {
                                        if ((*it4)->type == RTLIL::ST0 || (*it4)->type == RTLIL::ST1)
@@ -129,19 +127,18 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
                                                if (c.wire == wire)
                                                        is_clksignal = true;
                                }
-                               if (is_clksignal && wire->attributes.count("\\gentb_constant") == 0) {
+                               if (is_clksignal && wire->attributes.count(ID::gentb_constant) == 0) {
                                        signal_clk[idy("sig", mod->name.str(), wire->name.str())] = wire->width;
                                } else {
                                        signal_in[idy("sig", mod->name.str(), wire->name.str())] = wire->width;
-                                       if (wire->attributes.count("\\gentb_constant") != 0)
-                                               signal_const[idy("sig", mod->name.str(), wire->name.str())] = wire->attributes["\\gentb_constant"].as_string();
+                                       if (wire->attributes.count(ID::gentb_constant) != 0)
+                                               signal_const[idy("sig", mod->name.str(), wire->name.str())] = wire->attributes[ID::gentb_constant].as_string();
                                }
                                f << stringf("reg [%d:0] %s;\n", wire->width-1, idy("sig", mod->name.str(), wire->name.str()).c_str());
                        }
                }
                f << stringf("%s %s(\n", id(mod->name.str()).c_str(), idy("uut", mod->name.str()).c_str());
-               for (auto it2 = mod->wires_.begin(); it2 != mod->wires_.end(); ++it2) {
-                       RTLIL::Wire *wire = it2->second;
+               for (auto wire : mod->wires()) {
                        if (wire->port_output || wire->port_input)
                                f << stringf("\t.%s(%s)%s\n", id(wire->name.str()).c_str(),
                                                idy("sig", mod->name.str(), wire->name.str()).c_str(), --count_ports ? "," : "");
@@ -155,6 +152,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
                        f << stringf("\t%s <= #%d 0;\n", it->first.c_str(), ++delay_counter*2);
                for (auto it = signal_clk.begin(); it != signal_clk.end(); ++it)
                        f << stringf("\t%s <= #%d 0;\n", it->first.c_str(), ++delay_counter*2);
+               f << stringf("\t#%d;\n", ((2*delay_counter+99)/100)*100);
                for (auto it = signal_clk.begin(); it != signal_clk.end(); ++it) {
                        f << stringf("\t#100; %s <= 1;\n", it->first.c_str());
                        f << stringf("\t#100; %s <= 0;\n", it->first.c_str());
@@ -162,6 +160,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
                delay_counter = 0;
                for (auto it = signal_in.begin(); it != signal_in.end(); ++it)
                        f << stringf("\t%s <= #%d ~0;\n", it->first.c_str(), ++delay_counter*2);
+               f << stringf("\t#%d;\n", ((2*delay_counter+99)/100)*100);
                for (auto it = signal_clk.begin(); it != signal_clk.end(); ++it) {
                        f << stringf("\t#100; %s <= 1;\n", it->first.c_str());
                        f << stringf("\t#100; %s <= 0;\n", it->first.c_str());
@@ -172,6 +171,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
                                continue;
                        f << stringf("\t%s <= #%d 'b%s;\n", it->first.c_str(), ++delay_counter*2, signal_const[it->first].c_str());
                }
+               f << stringf("\t#%d;\n", ((2*delay_counter+99)/100)*100);
                f << stringf("end\n");
                f << stringf("endtask\n\n");
 
@@ -184,6 +184,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
                        f << stringf("\txorshift128;\n");
                        f << stringf("\t%s <= #%d { xorshift128_x, xorshift128_y, xorshift128_z, xorshift128_w };\n", it->first.c_str(), ++delay_counter*2);
                }
+               f << stringf("\t#%d;\n", ((2*delay_counter+99)/100)*100);
                f << stringf("end\n");
                f << stringf("endtask\n\n");
 
@@ -216,59 +217,65 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
                        for (auto it = signal_in.begin(); it != signal_in.end(); it++) {
                                f << stringf("%s %s", it == signal_in.begin() ? "" : ",", it->first.c_str());
                                int len = it->second;
+                               header2 += ", \"";
                                if (len > 1)
                                        header2 += "/", len--;
                                while (len > 1)
                                        header2 += "-", len--;
                                if (len > 0)
                                        header2 += shorthand, len--;
+                               header2 += "\"";
                                header1.push_back("    " + it->first);
                                header1.back()[0] = shorthand;
                                shorthand = shorthand == 'Z' ? 'A' : shorthand+1;
                        }
                else {
                        f << stringf(" 1'bx");
-                       header2 += "#";
+                       header2 += ", \"#\"";
                }
                f << stringf(" }, {");
-               header2 += " ";
+               header2 += ", \" \"";
                if (signal_clk.size()) {
                        for (auto it = signal_clk.begin(); it != signal_clk.end(); it++) {
                                f << stringf("%s %s", it == signal_clk.begin() ? "" : ",", it->first.c_str());
                                int len = it->second;
+                               header2 += ", \"";
                                if (len > 1)
                                        header2 += "/", len--;
                                while (len > 1)
                                        header2 += "-", len--;
                                if (len > 0)
                                        header2 += shorthand, len--;
+                               header2 += "\"";
                                header1.push_back("    " + it->first);
                                header1.back()[0] = shorthand;
                                shorthand = shorthand == 'Z' ? 'A' : shorthand+1;
                        }
                } else {
                        f << stringf(" 1'bx");
-                       header2 += "#";
+                       header2 += ", \"#\"";
                }
                f << stringf(" }, {");
-               header2 += " ";
+               header2 += ", \" \"";
                if (signal_out.size()) {
                        for (auto it = signal_out.begin(); it != signal_out.end(); it++) {
                                f << stringf("%s %s", it == signal_out.begin() ? "" : ",", it->first.c_str());
                                int len = it->second;
+                               header2 += ", \"";
                                if (len > 1)
                                        header2 += "/", len--;
                                while (len > 1)
                                        header2 += "-", len--;
                                if (len > 0)
                                        header2 += shorthand, len--;
+                               header2 += "\"";
                                header1.push_back("    " + it->first);
                                header1.back()[0] = shorthand;
                                shorthand = shorthand == 'Z' ? 'A' : shorthand+1;
                        }
                } else {
                        f << stringf(" 1'bx");
-                       header2 += "#";
+                       header2 += ", \"#\"";
                }
                f << stringf(" }, $time, i);\n");
                f << stringf("end\n");
@@ -280,7 +287,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
                for (auto &hdr : header1)
                        f << stringf("\t$fdisplay(file, \"#OUT#   %s\");\n", hdr.c_str());
                f << stringf("\t$fdisplay(file, \"#OUT#\");\n");
-               f << stringf("\t$fdisplay(file, \"#OUT# %s\");\n", header2.c_str());
+               f << stringf("\t$fdisplay(file, {\"#OUT# \"%s});\n", header2.c_str());
                f << stringf("end\n");
                f << stringf("endtask\n\n");
 
@@ -299,12 +306,18 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
        }
 
        f << stringf("initial begin\n");
-       f << stringf("\t// $dumpfile(\"testbench.vcd\");\n");
-       f << stringf("\t// $dumpvars(0, testbench);\n");
-       f << stringf("\tfile = $fopen(`dmp_name);\n");
-       for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it)
-               if (!it->second->get_bool_attribute("\\gentb_skip"))
-                       f << stringf("\t%s;\n", idy(it->first.str(), "test").c_str());
+       f << stringf("\tif ($value$plusargs(\"VCD=%%s\", filename)) begin\n");
+       f << stringf("\t\t$dumpfile(filename);\n");
+       f << stringf("\t\t$dumpvars(0, testbench);\n");
+       f << stringf("\tend\n");
+       f << stringf("\tif ($value$plusargs(\"OUT=%%s\", filename)) begin\n");
+       f << stringf("\t\tfile = $fopen(filename);\n");
+       f << stringf("\tend else begin\n");
+       f << stringf("\t\tfile = $fopen(`outfile);\n");
+       f << stringf("\tend\n");
+       for (auto module : design->modules())
+               if (!module->get_bool_attribute(ID::gentb_skip))
+                       f << stringf("\t%s;\n", idy(module->name.str(), "test").c_str());
        f << stringf("\t$fclose(file);\n");
        f << stringf("\t$finish;\n");
        f << stringf("end\n\n");
@@ -314,7 +327,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
 
 struct TestAutotbBackend : public Backend {
        TestAutotbBackend() : Backend("=test_autotb", "generate simple test benches") { }
-       virtual void help()
+       void help() override
        {
                //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
                log("\n");
@@ -335,13 +348,22 @@ struct TestAutotbBackend : public Backend {
                log("value after initialization. This can e.g. be used to force a reset signal\n");
                log("low in order to explore more inner states in a state machine.\n");
                log("\n");
+               log("The attribute 'gentb_skip' can be attached to modules to suppress testbench\n");
+               log("generation.\n");
+               log("\n");
                log("    -n <int>\n");
                log("        number of iterations the test bench should run (default = 1000)\n");
                log("\n");
+               log("    -seed <int>\n");
+               log("        seed used for pseudo-random number generation (default = 0).\n");
+               log("        a value of 0 will cause an arbitrary seed to be chosen, based on\n");
+               log("        the current system time.\n");
+               log("\n");
        }
-       virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+       void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override
        {
                int num_iter = 1000;
+               int seed = 0;
 
                log_header(design, "Executing TEST_AUTOTB backend (auto-generate pseudo-random test benches).\n");
 
@@ -352,11 +374,15 @@ struct TestAutotbBackend : public Backend {
                                num_iter = atoi(args[++argidx].c_str());
                                continue;
                        }
+                       if (args[argidx] == "-seed" && argidx+1 < GetSize(args)) {
+                               seed = atoi(args[++argidx].c_str());
+                               continue;
+                       }
                        break;
                }
 
                extra_args(f, filename, args, argidx);
-               autotest(*f, design, num_iter);
+               autotest(*f, design, num_iter, seed);
        }
 } TestAutotbBackend;