Add support for multi-threaded verilator

This commit is contained in:
abejgonzalez
2020-08-20 23:37:17 -07:00
parent fd0bbb479a
commit 425b8ce850
5 changed files with 161 additions and 48 deletions

View File

@@ -1,11 +1,15 @@
// See LICENSE.SiFive for license details.
// See LICENSE.Berkeley for license details.
#include "verilated.h"
#if VM_TRACE
#include <memory>
#if CY_FST_TRACE
#include "verilated_fst_c.h"
#else
#include "verilated.h"
#include "verilated_vcd_c.h"
#endif
#endif // CY_FST_TRACE
#endif // VM_TRACE
#include <fesvr/dtm.h>
#include <fesvr/tsi.h>
#include "remote_bitbang.h"
@@ -16,6 +20,8 @@
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
// needed for s_vpi_vlog_info, which is needed for multithreading
#include <vpi_user.h>
// For option parsing, which is split across this file, Verilog, and
// FESVR's HTIF, a few external files must be pulled in. The list of
@@ -35,6 +41,7 @@
extern tsi_t* tsi;
extern dtm_t* dtm;
extern remote_bitbang_t * jtag;
extern int dramsim;
static uint64_t trace_count = 0;
bool verbose = false;
@@ -50,6 +57,18 @@ double sc_time_stamp()
return trace_count;
}
// need to pull htif_argc/htif_argv out here so the thread that calls tick()
// for the HTIF device can initialize properly with the cmdline args. this
// was pulled out here for multithreading to work
static int htif_argc;
static char **htif_argv = NULL;
extern "C" int vpi_get_vlog_info(s_vpi_vlog_info *vlog_info_s)
{
vlog_info_s->argc = htif_argc;
vlog_info_s->argv = htif_argv;
return 1;
}
static void usage(const char * program_name)
{
printf("Usage: %s [EMULATOR OPTION]... [VERILOG PLUSARG]... [HOST OPTION]... BINARY [TARGET OPTION]...\n",
@@ -113,34 +132,34 @@ int main(int argc, char** argv)
// Port numbers are 16 bit unsigned integers.
uint16_t rbb_port = 0;
#if VM_TRACE
const char* vcdfile_name = NULL;
FILE * vcdfile = NULL;
uint64_t start = 0;
#endif
int verilog_plusargs_legal = 1;
opterr = 1;
dramsim = 0;
while (1) {
static struct option long_options[] = {
{"cycle-count", no_argument, 0, 'c' },
{"help", no_argument, 0, 'h' },
{"max-cycles", required_argument, 0, 'm' },
{"seed", required_argument, 0, 's' },
{"rbb-port", required_argument, 0, 'r' },
{"verbose", no_argument, 0, 'V' },
{"permissive", no_argument, 0, 'p' },
{"permissive-off", no_argument, 0, 'o' },
{"cycle-count", no_argument, 0, 'c' },
{"help", no_argument, 0, 'h' },
{"max-cycles", required_argument, 0, 'm' },
{"seed", required_argument, 0, 's' },
{"rbb-port", required_argument, 0, 'r' },
{"verbose", no_argument, 0, 'V' },
{"dramsim", no_argument, 0, 'D' },
#if VM_TRACE
{"vcd", required_argument, 0, 'v' },
{"dump-start", required_argument, 0, 'x' },
{"vcd", required_argument, 0, 'v' },
{"dump-start", required_argument, 0, 'x' },
#endif
HTIF_LONG_OPTIONS
};
int option_index = 0;
#if VM_TRACE
int c = getopt_long(argc, argv, "-chm:s:r:v:Vx:po", long_options, &option_index);
int c = getopt_long(argc, argv, "-chm:s:r:v:Vx:D", long_options, &option_index);
#else
int c = getopt_long(argc, argv, "-chm:s:r:Vpo", long_options, &option_index);
int c = getopt_long(argc, argv, "-chm:s:r:VD", long_options, &option_index);
#endif
if (c == -1) break;
retry:
@@ -153,10 +172,10 @@ int main(int argc, char** argv)
case 's': random_seed = atoi(optarg); break;
case 'r': rbb_port = atoi(optarg); break;
case 'V': verbose = true; break;
case 'p': opterr = 0; break;
case 'o': opterr = 1; break;
case 'D': dramsim = 1; break;
#if VM_TRACE
case 'v': {
vcdfile_name = optarg;
vcdfile = strcmp(optarg, "-") == 0 ? stdout : fopen(optarg, "w");
if (!vcdfile) {
std::cerr << "Unable to open " << optarg << " for VCD write\n";
@@ -188,10 +207,8 @@ int main(int argc, char** argv)
#endif
else if (arg.substr(0, 12) == "+cycle-count")
c = 'c';
else if (arg == "+permissive")
c = 'p';
else if (arg == "+permissive-off")
c = 'o';
else if (arg == "+dramsim")
c = 'D';
// If we don't find a legacy '+' EMULATOR argument, it still could be
// a VERILOG_PLUSARG and not an error.
else if (verilog_plusargs_legal) {
@@ -223,13 +240,9 @@ int main(int argc, char** argv)
}
htif_option++;
}
if(opterr) {
std::cerr << argv[0] << ": invalid plus-arg (Verilog or HTIF) \""
<< arg << "\"\n";
c = '?';
} else {
c = 'p';
}
std::cerr << argv[0] << ": invalid plus-arg (Verilog or HTIF) \""
<< arg << "\"\n";
c = '?';
}
goto retry;
}
@@ -251,6 +264,10 @@ done_processing:
usage(argv[0]);
return 1;
}
htif_argc = 1 + argc - optind;
htif_argv = (char **) malloc((htif_argc) * sizeof (char *));
htif_argv[0] = argv[0];
for (int i = 1; optind < argc;) htif_argv[i++] = argv[optind++];
if (verbose)
fprintf(stderr, "using random seed %u\n", random_seed);
@@ -264,17 +281,17 @@ done_processing:
#if VM_TRACE
Verilated::traceEverOn(true); // Verilator must compute traced signals
#if CY_FST_TRACE
std::unique_ptr<VerilatedFstC> tfp(new VerilatedFstC);
#else
std::unique_ptr<VerilatedVcdFILE> vcdfd(new VerilatedVcdFILE(vcdfile));
std::unique_ptr<VerilatedVcdC> tfp(new VerilatedVcdC(vcdfd.get()));
if (vcdfile) {
#endif // CY_FST_TRACE
if (vcdfile_name) {
tile->trace(tfp.get(), 99); // Trace 99 levels of hierarchy
tfp->open("");
tfp->open(vcdfile_name);
}
#endif
jtag = new remote_bitbang_t(rbb_port);
dtm = new dtm_t(argc, argv);
tsi = new tsi_t(argc, argv);
#endif // VM_TRACE
signal(SIGTERM, handle_sigterm);
@@ -304,8 +321,7 @@ done_processing:
tile->reset = 0;
done_reset = true;
while (!dtm->done() && !jtag->done() && !tsi->done() &&
!tile->io_success && trace_count < max_cycles) {
do {
tile->clock = 0;
tile->eval();
#if VM_TRACE
@@ -322,6 +338,13 @@ done_processing:
#endif
trace_count++;
}
// for verilator multithreading. need to do 1 loop before checking if
// tsi exists, since tsi is created by verilated thread on the first
// serial_tick.
while ((!dtm || !dtm->done()) &&
(!jtag || !jtag->done()) &&
(!tsi || !tsi->done()) &&
!tile->io_success && trace_count < max_cycles);
#if VM_TRACE
if (tfp)
@@ -330,17 +353,17 @@ done_processing:
fclose(vcdfile);
#endif
if (dtm->exit_code())
if (dtm && dtm->exit_code())
{
fprintf(stderr, "*** FAILED *** via dtm (code = %d, seed %d) after %ld cycles\n", dtm->exit_code(), random_seed, trace_count);
ret = dtm->exit_code();
}
else if (tsi->exit_code())
else if (tsi && 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 (jtag->exit_code())
else if (jtag && jtag->exit_code())
{
fprintf(stderr, "*** FAILED *** via jtag (code = %d, seed %d) after %ld cycles\n", jtag->exit_code(), random_seed, trace_count);
ret = jtag->exit_code();
@@ -359,5 +382,6 @@ done_processing:
if (tsi) delete tsi;
if (jtag) delete jtag;
if (tile) delete tile;
if (htif_argv) free(htif_argv);
return ret;
}