diff --git a/verisim/Makefile b/verisim/Makefile index 73a92e90..d4ca59a1 100644 --- a/verisim/Makefile +++ b/verisim/Makefile @@ -31,7 +31,7 @@ sim_vsrcs = \ $(testchip_vsrcs) sim_csrcs = \ - $(testchip_dir)/csrc/verilator-harness.cc \ + $(sim_dir)/csrc/verilator-harness.cc \ $(testchip_csrcs) model_dir = $(build_dir)/$(long_name) diff --git a/verisim/csrc/verilator-harness.cc b/verisim/csrc/verilator-harness.cc new file mode 100644 index 00000000..475123c3 --- /dev/null +++ b/verisim/csrc/verilator-harness.cc @@ -0,0 +1,167 @@ +// See LICENSE for license details. + +#include "verilated.h" +#if VM_TRACE +#include "verilated_vcd_c.h" +#endif +#include +#include +#include +#include +#include +#include +#include + +extern tsi_t* tsi; +static uint64_t trace_count = 0; +bool verbose; +bool done_reset; + +void handle_sigterm(int sig) +{ + tsi->stop(); +} + +double sc_time_stamp() +{ + return trace_count; +} + +extern "C" int vpi_get_vlog_info(void* arg) +{ + return 0; +} + +static inline int copy_argv(int argc, char **argv, char **new_argv) +{ + int optind = 1; + int new_argc = argc; + + new_argv[0] = argv[0]; + + for (int i = 1; i < argc; i++) { + if (argv[i][0] != '+' && argv[i][0] != '-') { + optind = i - 1; + new_argc = argc - i + 1; + break; + } + } + + for (int i = 1; i < new_argc; i++) + new_argv[i] = argv[i + optind]; + + return new_argc; +} + +int main(int argc, char** argv) +{ + unsigned random_seed = (unsigned)time(NULL) ^ (unsigned)getpid(); + uint64_t max_cycles = -1; + uint64_t start = 0; + int ret = 0; + FILE *vcdfile = NULL; + bool print_cycles = false; + char *new_argv[argc]; + int new_argc; + + for (int i = 1; i < argc; i++) { + std::string arg = argv[i]; + if (arg.substr(0, 2) == "-v") { + const char* filename = argv[i]+2; + vcdfile = strcmp(filename, "-") == 0 ? stdout : fopen(filename, "w"); + if (!vcdfile) + abort(); + } else if (arg.substr(0, 2) == "-s") + random_seed = atoi(argv[i]+2); + else if (arg == "+verbose") + verbose = true; + else if (arg.substr(0, 12) == "+max-cycles=") + max_cycles = atoll(argv[i]+12); + else if (arg.substr(0, 7) == "+start=") + start = atoll(argv[i]+7); + else if (arg.substr(0, 12) == "+cycle-count") + print_cycles = true; + } + + if (verbose) + fprintf(stderr, "using random seed %u\n", random_seed); + + srand(random_seed); + srand48(random_seed); + + Verilated::randReset(2); + Verilated::commandArgs(argc, argv); + VTestHarness *tile = new VTestHarness; + +#if VM_TRACE + Verilated::traceEverOn(true); // Verilator must compute traced signals + std::unique_ptr vcdfd(new VerilatedVcdFILE(vcdfile)); + std::unique_ptr tfp(new VerilatedVcdC(vcdfd.get())); + if (vcdfile) { + tile->trace(tfp.get(), 99); // Trace 99 levels of hierarchy + tfp->open(""); + } +#endif + + new_argc = copy_argv(argc, argv, new_argv); + tsi = new tsi_t(new_argc, new_argv); + + signal(SIGTERM, handle_sigterm); + + // reset for several cycles to handle pipelined reset + for (int i = 0; i < 10; i++) { + tile->reset = 1; + tile->clock = 0; + tile->eval(); + tile->clock = 1; + tile->eval(); + tile->reset = 0; + } + done_reset = true; + + while (!tsi->done() && !tile->io_success && trace_count < max_cycles) { + tile->clock = 0; + tile->eval(); +#if VM_TRACE + bool dump = tfp && trace_count >= start; + if (dump) + tfp->dump(static_cast(trace_count * 2)); +#endif + + tile->clock = 1; + tile->eval(); +#if VM_TRACE + if (dump) + tfp->dump(static_cast(trace_count * 2 + 1)); +#endif + trace_count++; + } + +#if VM_TRACE + if (tfp) + tfp->close(); +#endif + + if (vcdfile) + fclose(vcdfile); + + if (tsi->exit_code()) + { + fprintf(stderr, "*** FAILED *** (code = %d, seed %d) after %ld cycles\n", tsi->exit_code(), random_seed, trace_count); + ret = tsi->exit_code(); + } + else if (trace_count == max_cycles) + { + fprintf(stderr, "*** FAILED *** (timeout, seed %d) after %ld cycles\n", random_seed, trace_count); + ret = 2; + } + else if (verbose || print_cycles) + { + fprintf(stderr, "Completed after %ld cycles\n", trace_count); + } + + delete tsi; + delete tile; + + return ret; +}