2016-11-28 01:16:37 +01:00
|
|
|
// See LICENSE.SiFive for license details.
|
|
|
|
// See LICENSE.Berkeley for license details.
|
2014-09-12 19:15:04 +02:00
|
|
|
|
2016-06-08 10:39:40 +02:00
|
|
|
#include "verilated.h"
|
|
|
|
#if VM_TRACE
|
|
|
|
#include "verilated_vcd_c.h"
|
|
|
|
#endif
|
2016-06-23 09:17:29 +02:00
|
|
|
#include <fesvr/dtm.h>
|
2017-04-12 05:03:34 +02:00
|
|
|
#include "remote_bitbang.h"
|
2016-06-08 10:39:40 +02:00
|
|
|
#include <iostream>
|
2013-01-25 08:56:45 +01:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2013-03-26 01:01:13 +01:00
|
|
|
#include <unistd.h>
|
2016-12-13 23:29:57 +01:00
|
|
|
#include <getopt.h>
|
2012-10-02 04:30:11 +02:00
|
|
|
|
2016-08-16 07:03:03 +02:00
|
|
|
extern dtm_t* dtm;
|
2017-04-12 05:03:34 +02:00
|
|
|
extern remote_bitbang_t * jtag;
|
|
|
|
|
2016-06-23 21:17:26 +02:00
|
|
|
static uint64_t trace_count = 0;
|
2016-06-18 06:09:08 +02:00
|
|
|
bool verbose;
|
2016-09-09 19:57:10 +02:00
|
|
|
bool done_reset;
|
2016-06-18 06:09:08 +02:00
|
|
|
|
2013-01-25 08:56:45 +01:00
|
|
|
void handle_sigterm(int sig)
|
2012-11-20 14:40:44 +01:00
|
|
|
{
|
2016-06-23 09:17:29 +02:00
|
|
|
dtm->stop();
|
2012-11-20 14:40:44 +01:00
|
|
|
}
|
|
|
|
|
2016-06-23 21:17:26 +02:00
|
|
|
double sc_time_stamp()
|
|
|
|
{
|
|
|
|
return trace_count;
|
|
|
|
}
|
|
|
|
|
2016-08-16 07:03:03 +02:00
|
|
|
extern "C" int vpi_get_vlog_info(void* arg)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-03-20 05:16:18 +01:00
|
|
|
static void usage(const char * program_name)
|
|
|
|
{
|
|
|
|
printf("Usage: %s [EMULATOR OPTION]... [HOST OPTION]... BINARY [TARGET OPTION]...\n",
|
|
|
|
program_name);
|
2016-12-13 23:29:57 +01:00
|
|
|
fputs("\
|
|
|
|
Run a BINARY on the Rocket Chip emulator.\n\
|
|
|
|
\n\
|
|
|
|
Mandatory arguments to long options are mandatory for short options too.\n\
|
2017-03-20 05:16:18 +01:00
|
|
|
\n\
|
|
|
|
EMULATOR OPTIONS\n\
|
2017-11-19 01:20:44 +01:00
|
|
|
-c, --cycle-count Print the cycle count before exiting\n\
|
2016-12-13 23:29:57 +01:00
|
|
|
+cycle-count\n\
|
2017-11-19 01:20:44 +01:00
|
|
|
-h, --help Display this help and exit\n\
|
|
|
|
-m, --max-cycles=CYCLES Kill the emulation after CYCLES\n\
|
|
|
|
+max-cycles=CYCLES\n\
|
|
|
|
-s, --seed=SEED Use random number seed SEED\n\
|
|
|
|
-V, --verbose Enable all Chisel printfs (cycle-by-cycle info)\n\
|
2016-12-13 23:29:57 +01:00
|
|
|
+verbose\n\
|
|
|
|
", stdout);
|
2017-11-19 01:20:44 +01:00
|
|
|
#if VM_TRACE == 0
|
2016-12-13 23:29:57 +01:00
|
|
|
fputs("\
|
2017-03-20 05:16:18 +01:00
|
|
|
\n\
|
2017-11-19 01:20:44 +01:00
|
|
|
EMULATOR OPTIONS (only supported in debug build -- try `make debug`)\n",
|
|
|
|
stdout);
|
2017-03-20 05:16:18 +01:00
|
|
|
#endif
|
2016-12-13 23:29:57 +01:00
|
|
|
fputs("\
|
2017-11-19 01:20:44 +01:00
|
|
|
-v, --vcd=FILE, Write vcd trace to FILE (or '-' for stdout)\n\
|
|
|
|
-x, --dump-start=CYCLE Start VCD tracing at CYCLE\n\
|
|
|
|
+dump-start\n\
|
2016-12-13 23:29:57 +01:00
|
|
|
", stdout);
|
2017-11-19 01:20:44 +01:00
|
|
|
fputs("\n" HTIF_USAGE_OPTIONS, stdout);
|
|
|
|
printf("\n"
|
|
|
|
"EXAMPLES\n"
|
|
|
|
" - run a bare metal test:\n"
|
2017-11-30 18:41:23 +01:00
|
|
|
" %s $RISCV/riscv64-unknown-elf/share/riscv-tests/isa/rv64ui-p-add\n"
|
2017-11-19 01:20:44 +01:00
|
|
|
" - run a bare metal test showing cycle-by-cycle information:\n"
|
2017-11-30 18:41:23 +01:00
|
|
|
" %s +verbose $RISCV/riscv64-unknown-elf/share/riscv-tests/isa/rv64ui-p-add 2>&1 | spike-dasm\n"
|
2017-11-19 01:20:44 +01:00
|
|
|
#if VM_TRACE
|
|
|
|
" - run a bare metal test to generate a VCD waveform:\n"
|
2017-11-30 18:41:23 +01:00
|
|
|
" %s -v rv64ui-p-add.vcd $RISCV/riscv64-unknown-elf/share/riscv-tests/isa/rv64ui-p-add\n"
|
2017-11-19 01:20:44 +01:00
|
|
|
#endif
|
2017-11-30 18:41:23 +01:00
|
|
|
" - run an ELF (you wrote, called 'hello') using the proxy kernel:\n"
|
2017-11-19 01:20:44 +01:00
|
|
|
" %s pk hello\n",
|
|
|
|
program_name, program_name, program_name, program_name);
|
2016-12-13 23:29:57 +01:00
|
|
|
}
|
|
|
|
|
2012-10-02 04:30:11 +02:00
|
|
|
int main(int argc, char** argv)
|
|
|
|
{
|
|
|
|
unsigned random_seed = (unsigned)time(NULL) ^ (unsigned)getpid();
|
2013-10-29 21:24:09 +01:00
|
|
|
uint64_t max_cycles = -1;
|
|
|
|
int ret = 0;
|
2015-12-04 21:04:13 +01:00
|
|
|
bool print_cycles = false;
|
2016-12-13 23:29:57 +01:00
|
|
|
#if VM_TRACE
|
|
|
|
FILE * vcdfile = NULL;
|
|
|
|
uint64_t start = 0;
|
|
|
|
#endif
|
2017-03-20 05:16:18 +01:00
|
|
|
char ** htif_argv = NULL;
|
2012-11-20 14:40:44 +01:00
|
|
|
|
2016-12-13 23:29:57 +01:00
|
|
|
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' },
|
|
|
|
{"verbose", no_argument, 0, 'V' },
|
|
|
|
#if VM_TRACE
|
|
|
|
{"vcd", required_argument, 0, 'v' },
|
2017-03-31 20:38:29 +02:00
|
|
|
{"dump-start", required_argument, 0, 'x' },
|
2016-12-13 23:29:57 +01:00
|
|
|
#endif
|
2017-03-20 05:16:18 +01:00
|
|
|
HTIF_LONG_OPTIONS
|
2016-12-13 23:29:57 +01:00
|
|
|
};
|
|
|
|
int option_index = 0;
|
|
|
|
#if VM_TRACE
|
|
|
|
int c = getopt_long(argc, argv, "-chm:s:v:Vx:", long_options, &option_index);
|
|
|
|
#else
|
|
|
|
int c = getopt_long(argc, argv, "-chm:s:V", long_options, &option_index);
|
|
|
|
#endif
|
|
|
|
if (c == -1) break;
|
2017-03-20 05:16:18 +01:00
|
|
|
retry:
|
2016-12-13 23:29:57 +01:00
|
|
|
switch (c) {
|
2017-03-20 05:16:18 +01:00
|
|
|
// Process long and short EMULATOR options
|
2016-12-13 23:29:57 +01:00
|
|
|
case '?': usage(argv[0]); return 1;
|
|
|
|
case 'c': print_cycles = true; break;
|
|
|
|
case 'h': usage(argv[0]); return 0;
|
|
|
|
case 'm': max_cycles = atoll(optarg); break;
|
|
|
|
case 's': random_seed = atoi(optarg); break;
|
|
|
|
case 'V': verbose = true; break;
|
|
|
|
#if VM_TRACE
|
|
|
|
case 'v': {
|
|
|
|
vcdfile = strcmp(optarg, "-") == 0 ? stdout : fopen(optarg, "w");
|
|
|
|
if (!vcdfile) {
|
|
|
|
std::cerr << "Unable to open " << optarg << " for VCD write\n";
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'x': start = atoll(optarg); break;
|
|
|
|
#endif
|
2017-03-20 05:16:18 +01:00
|
|
|
// Process legacy '+' EMULATOR arguments by replacing them with
|
|
|
|
// their getopt equivalents
|
2016-12-13 23:29:57 +01:00
|
|
|
case 1: {
|
|
|
|
std::string arg = optarg;
|
2017-03-20 05:16:18 +01:00
|
|
|
if (arg.substr(0, 1) != "+") {
|
|
|
|
optind--;
|
|
|
|
goto done_processing;
|
|
|
|
}
|
2016-12-13 23:29:57 +01:00
|
|
|
if (arg == "+verbose")
|
2017-03-20 05:16:18 +01:00
|
|
|
c = 'V';
|
|
|
|
else if (arg.substr(0, 12) == "+max-cycles=") {
|
|
|
|
c = 'm';
|
|
|
|
optarg = optarg+12;
|
|
|
|
}
|
2016-12-13 23:29:57 +01:00
|
|
|
#if VM_TRACE
|
2017-11-19 01:20:44 +01:00
|
|
|
else if (arg.substr(0, 12) == "+dump-start=") {
|
2017-03-20 05:16:18 +01:00
|
|
|
c = 'x';
|
|
|
|
optarg = optarg+12;
|
|
|
|
}
|
2016-12-13 23:29:57 +01:00
|
|
|
#endif
|
|
|
|
else if (arg.substr(0, 12) == "+cycle-count")
|
2017-03-20 05:16:18 +01:00
|
|
|
c = 'c';
|
|
|
|
// If we don't find a legacy '+' argument, it still could be
|
|
|
|
// an HTIF (HOST) argument and not an error. If this is the
|
2017-11-19 01:20:44 +01:00
|
|
|
// case, then we're done processing EMULATOR arguments.
|
2016-12-13 23:29:57 +01:00
|
|
|
else {
|
2017-03-20 05:16:18 +01:00
|
|
|
static struct option htif_long_options [] = { HTIF_LONG_OPTIONS };
|
|
|
|
struct option * htif_option = &htif_long_options[0];
|
|
|
|
while (htif_option->name) {
|
|
|
|
if (arg.substr(1, strlen(htif_option->name)) == htif_option->name) {
|
|
|
|
optind--;
|
|
|
|
goto done_processing;
|
|
|
|
}
|
|
|
|
htif_option++;
|
|
|
|
}
|
|
|
|
std::cerr << argv[0] << ": invalid HTIF legacy plus-arg \"" << arg << "\"\n";
|
|
|
|
c = '?';
|
2016-12-13 23:29:57 +01:00
|
|
|
}
|
2017-03-20 05:16:18 +01:00
|
|
|
goto retry;
|
2016-12-13 23:29:57 +01:00
|
|
|
}
|
2017-03-20 05:16:18 +01:00
|
|
|
// Realize that we've hit HTIF (HOST) arguments or error out
|
|
|
|
default:
|
|
|
|
if (c >= HTIF_LONG_OPTIONS_OPTIND) {
|
|
|
|
optind--;
|
|
|
|
goto done_processing;
|
|
|
|
}
|
|
|
|
c = '?';
|
|
|
|
goto retry;
|
2016-12-13 23:29:57 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
done_processing:
|
2017-03-20 05:16:18 +01:00
|
|
|
if (optind == argc) {
|
2016-12-13 23:29:57 +01:00
|
|
|
std::cerr << "No binary specified for emulator\n";
|
|
|
|
usage(argv[0]);
|
|
|
|
return 1;
|
2013-01-25 08:56:45 +01:00
|
|
|
}
|
2017-03-20 05:16:18 +01:00
|
|
|
int 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++];
|
2012-10-02 04:30:11 +02:00
|
|
|
|
2016-10-05 07:27:28 +02:00
|
|
|
if (verbose)
|
|
|
|
fprintf(stderr, "using random seed %u\n", random_seed);
|
|
|
|
|
2016-07-09 11:37:39 +02:00
|
|
|
srand(random_seed);
|
|
|
|
srand48(random_seed);
|
2016-06-08 10:39:40 +02:00
|
|
|
|
2016-07-09 11:37:39 +02:00
|
|
|
Verilated::randReset(2);
|
2017-05-19 07:49:59 +02:00
|
|
|
Verilated::commandArgs(argc, argv);
|
2017-03-29 20:27:33 +02:00
|
|
|
TEST_HARNESS *tile = new TEST_HARNESS;
|
2016-07-09 11:37:39 +02:00
|
|
|
|
2016-06-08 10:39:40 +02:00
|
|
|
#if VM_TRACE
|
2016-07-09 11:37:39 +02:00
|
|
|
Verilated::traceEverOn(true); // Verilator must compute traced signals
|
|
|
|
std::unique_ptr<VerilatedVcdFILE> vcdfd(new VerilatedVcdFILE(vcdfile));
|
|
|
|
std::unique_ptr<VerilatedVcdC> tfp(new VerilatedVcdC(vcdfd.get()));
|
|
|
|
if (vcdfile) {
|
2016-08-16 23:50:40 +02:00
|
|
|
tile->trace(tfp.get(), 99); // Trace 99 levels of hierarchy
|
2016-07-09 11:37:39 +02:00
|
|
|
tfp->open("");
|
2016-06-08 10:39:40 +02:00
|
|
|
}
|
|
|
|
#endif
|
2013-05-02 13:58:43 +02:00
|
|
|
|
2017-04-12 05:03:34 +02:00
|
|
|
jtag = new remote_bitbang_t(0);
|
2017-03-20 05:16:18 +01:00
|
|
|
dtm = new dtm_t(htif_argc, htif_argv);
|
2013-01-25 08:56:45 +01:00
|
|
|
|
|
|
|
signal(SIGTERM, handle_sigterm);
|
|
|
|
|
2017-12-02 02:07:28 +01:00
|
|
|
bool dump;
|
2016-06-23 09:17:29 +02:00
|
|
|
// reset for several cycles to handle pipelined reset
|
|
|
|
for (int i = 0; i < 10; i++) {
|
2016-08-16 23:50:40 +02:00
|
|
|
tile->reset = 1;
|
2016-09-22 01:16:47 +02:00
|
|
|
tile->clock = 0;
|
2016-08-16 23:50:40 +02:00
|
|
|
tile->eval();
|
2017-12-02 02:07:28 +01:00
|
|
|
#if VM_TRACE
|
|
|
|
dump = tfp && trace_count >= start;
|
|
|
|
if (dump)
|
|
|
|
tfp->dump(static_cast<vluint64_t>(trace_count * 2));
|
|
|
|
#endif
|
2016-09-22 01:16:47 +02:00
|
|
|
tile->clock = 1;
|
2016-08-16 23:50:40 +02:00
|
|
|
tile->eval();
|
2017-12-02 02:07:28 +01:00
|
|
|
#if VM_TRACE
|
|
|
|
if (dump)
|
|
|
|
tfp->dump(static_cast<vluint64_t>(trace_count * 2 + 1));
|
|
|
|
#endif
|
|
|
|
trace_count ++;
|
2016-06-23 09:17:29 +02:00
|
|
|
}
|
2017-12-02 02:07:28 +01:00
|
|
|
tile->reset = 0;
|
2016-09-09 19:57:10 +02:00
|
|
|
done_reset = true;
|
2016-06-08 10:39:40 +02:00
|
|
|
|
2017-04-12 05:03:34 +02:00
|
|
|
while (!dtm->done() && !jtag->done() &&
|
|
|
|
!tile->io_success && trace_count < max_cycles) {
|
2016-09-22 01:16:47 +02:00
|
|
|
tile->clock = 0;
|
2016-08-16 23:50:40 +02:00
|
|
|
tile->eval();
|
2016-06-08 10:39:40 +02:00
|
|
|
#if VM_TRACE
|
2017-12-02 02:07:28 +01:00
|
|
|
dump = tfp && trace_count >= start;
|
2016-08-16 07:03:03 +02:00
|
|
|
if (dump)
|
2016-09-14 20:36:47 +02:00
|
|
|
tfp->dump(static_cast<vluint64_t>(trace_count * 2));
|
2016-06-08 10:39:40 +02:00
|
|
|
#endif
|
2016-06-23 09:17:29 +02:00
|
|
|
|
2016-09-22 01:16:47 +02:00
|
|
|
tile->clock = 1;
|
2016-08-16 23:50:40 +02:00
|
|
|
tile->eval();
|
2016-06-08 10:39:40 +02:00
|
|
|
#if VM_TRACE
|
2016-08-16 07:03:03 +02:00
|
|
|
if (dump)
|
2016-09-14 20:36:47 +02:00
|
|
|
tfp->dump(static_cast<vluint64_t>(trace_count * 2 + 1));
|
2016-06-08 10:39:40 +02:00
|
|
|
#endif
|
2012-10-02 04:30:11 +02:00
|
|
|
trace_count++;
|
|
|
|
}
|
|
|
|
|
2016-06-08 10:39:40 +02:00
|
|
|
#if VM_TRACE
|
2016-07-09 11:37:39 +02:00
|
|
|
if (tfp)
|
|
|
|
tfp->close();
|
|
|
|
if (vcdfile)
|
|
|
|
fclose(vcdfile);
|
2016-12-13 23:29:57 +01:00
|
|
|
#endif
|
2016-07-09 11:37:39 +02:00
|
|
|
|
2016-06-23 09:17:29 +02:00
|
|
|
if (dtm->exit_code())
|
2012-10-02 04:30:11 +02:00
|
|
|
{
|
2016-06-23 21:17:26 +02:00
|
|
|
fprintf(stderr, "*** FAILED *** (code = %d, seed %d) after %ld cycles\n", dtm->exit_code(), random_seed, trace_count);
|
2016-06-23 09:17:29 +02:00
|
|
|
ret = dtm->exit_code();
|
2012-10-02 04:30:11 +02:00
|
|
|
}
|
2017-04-12 05:03:34 +02:00
|
|
|
else if (jtag->exit_code())
|
|
|
|
{
|
|
|
|
fprintf(stderr, "*** FAILED *** (code = %d, seed %d) after %ld cycles\n", jtag->exit_code(), random_seed, trace_count);
|
|
|
|
ret = jtag->exit_code();
|
|
|
|
}
|
2016-06-23 21:17:26 +02:00
|
|
|
else if (trace_count == max_cycles)
|
2013-10-29 21:24:09 +01:00
|
|
|
{
|
2016-06-23 21:17:26 +02:00
|
|
|
fprintf(stderr, "*** FAILED *** (timeout, seed %d) after %ld cycles\n", random_seed, trace_count);
|
2013-10-29 21:24:09 +01:00
|
|
|
ret = 2;
|
|
|
|
}
|
2016-06-18 06:09:08 +02:00
|
|
|
else if (verbose || print_cycles)
|
2015-09-19 03:02:03 +02:00
|
|
|
{
|
2016-06-23 21:17:26 +02:00
|
|
|
fprintf(stderr, "Completed after %ld cycles\n", trace_count);
|
2015-09-19 03:02:03 +02:00
|
|
|
}
|
2013-10-29 21:24:09 +01:00
|
|
|
|
2016-12-13 23:29:57 +01:00
|
|
|
if (dtm) delete dtm;
|
2017-04-12 05:03:34 +02:00
|
|
|
if (jtag) delete jtag;
|
2016-12-13 23:29:57 +01:00
|
|
|
if (tile) delete tile;
|
2017-03-20 05:16:18 +01:00
|
|
|
if (htif_argv) free(htif_argv);
|
2013-10-29 21:24:09 +01:00
|
|
|
return ret;
|
2012-10-02 04:30:11 +02:00
|
|
|
}
|