diff --git a/.travis.yml b/.travis.yml index 9f29b739..57602988 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,7 @@ git: submodules: false language: scala -# run on new infrastructure -sudo: false +sudo: required cache: apt: true directories: @@ -32,6 +31,7 @@ addons: - texinfo - device-tree-compiler - libusb-1.0-0-dev + - python-pexpect # blacklist private branches @@ -69,6 +69,11 @@ jobs: - export CXX=g++-4.8 CC=gcc-4.8 - &test stage: Test + script: + - travis_wait 80 make emulator-ndebug -C regression SUITE=JtagDtmSuite JVM_MEMORY=3G + - travis_wait 80 make emulator-jtag-dtm-tests-32 -C regression SUITE=JtagDtmSuite JVM_MEMORY=3G + - travis_wait 80 make emulator-jtag-dtm-tests-64 -C regression SUITE=JtagDtmSuite JVM_MEMORY=3G + - <<: *test script: - travis_wait 80 make emulator-ndebug -C regression SUITE=UnittestSuite JVM_MEMORY=3G - travis_wait 80 make emulator-regression-tests -C regression SUITE=UnittestSuite JVM_MEMORY=3G @@ -83,4 +88,4 @@ jobs: - <<: *test script: - travis_wait 80 make emulator-ndebug -C regression SUITE=RocketSuiteA JVM_MEMORY=3G - - travis_wait 80 make emulator-regression-tests -C regression SUITE=RocketSuiteA JVM_MEMORY=3G + - travis_wait 80 make emulator-regression-tests -C regression SUITE=RocketSuiteA JVM_MEMORY=3G \ No newline at end of file diff --git a/csrc/SimDTM.cc b/csrc/SimDTM.cc index 0688c0df..aee4edd2 100644 --- a/csrc/SimDTM.cc +++ b/csrc/SimDTM.cc @@ -6,27 +6,6 @@ dtm_t* dtm; - -namespace { - - // Remove args that will confuse dtm, such as those that require two tokens, like VCS code coverage "-cm line+cond" -std::vector filter_argv_for_dtm(int argc, char** argv) -{ - std::vector out; - for (int i = 1; i < argc; ++i) { // start with 1 to skip my executable name - if (!strncmp(argv[i], "-cm", 3)) { - ++i; // skip this one and the next one - } - else { - out.push_back(argv[i]); - } - } - return out; -} - -} - - extern "C" int debug_tick ( unsigned char* debug_req_valid, @@ -44,7 +23,7 @@ extern "C" int debug_tick s_vpi_vlog_info info; if (!vpi_get_vlog_info(&info)) abort(); - dtm = new dtm_t(filter_argv_for_dtm(info.argc, info.argv)); + dtm = new dtm_t(info.argc, info.argv); } dtm_t::resp resp_bits; diff --git a/csrc/SimJTAG.cc b/csrc/SimJTAG.cc new file mode 100644 index 00000000..e7c4c44d --- /dev/null +++ b/csrc/SimJTAG.cc @@ -0,0 +1,32 @@ +// See LICENSE.SiFive for license details. + +#include +#include +#include +#include "remote_bitbang.h" + +remote_bitbang_t* jtag; + +extern "C" int jtag_tick +( + unsigned char * jtag_TCK, + unsigned char * jtag_TMS, + unsigned char * jtag_TDI, + unsigned char * jtag_TRSTn, + unsigned char jtag_TDO +) +{ + if (!jtag) { + s_vpi_vlog_info info; + if (!vpi_get_vlog_info(&info)) { + abort(); + } + // TODO: Pass in real port number + jtag = new remote_bitbang_t(0); + } + + jtag->tick(jtag_TCK, jtag_TMS, jtag_TDI, jtag_TRSTn, jtag_TDO); + + return jtag->done() ? (jtag->exit_code() << 1 | 1) : 0; + +} diff --git a/csrc/emulator.cc b/csrc/emulator.cc index 46841617..bbba3c61 100644 --- a/csrc/emulator.cc +++ b/csrc/emulator.cc @@ -6,6 +6,7 @@ #include "verilated_vcd_c.h" #endif #include +#include "remote_bitbang.h" #include #include #include @@ -14,7 +15,16 @@ #include #include +//TODO: GENERATE THESE AUTOMATICALLY! +static const char * verilog_plusargs [] = { "max-core-cycles", + "jtag_rbb_enable", + "tilelink_timeout", + 0}; + + extern dtm_t* dtm; +extern remote_bitbang_t * jtag; + static uint64_t trace_count = 0; bool verbose; bool done_reset; @@ -34,33 +44,58 @@ extern "C" int vpi_get_vlog_info(void* arg) return 0; } -static void usage(const char * program_name) { - printf("Usage: %s [OPTION]... BINARY [BINARY ARGS]\n", program_name); +static void usage(const char * program_name) +{ + printf("Usage: %s [EMULATOR OPTION]... [VERILOG PLUSARG]... [HOST OPTION]... BINARY [TARGET OPTION]...\n", + program_name); fputs("\ Run a BINARY on the Rocket Chip emulator.\n\ \n\ Mandatory arguments to long options are mandatory for short options too.\n\ - -c, --cycle-count print the cycle count before exiting\n\ +\n\ +EMULATOR OPTIONS\n\ + -c, --cycle-count Print the cycle count before exiting\n\ +cycle-count\n\ - -h, --help display this help and exit\n\ - -m, --max-cycles=CYCLES kill the emulation after CYCLES\n\ + -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\n\ + -s, --seed=SEED Use random number seed SEED\n\ + -V, --verbose Enable all Chisel printfs (cycle-by-cycle info)\n\ +verbose\n\ ", stdout); -#if VM_TRACE +#if VM_TRACE == 0 fputs("\ - -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\ -", stdout); -#else - fputs("\ -VCD options (e.g., -v, +dump-start) require a debug-enabled emulator.\n\ -Try `make debug`.\n\ -", stdout); +\n\ +EMULATOR OPTIONS (only supported in debug build -- try `make debug`)\n", + stdout); #endif + fputs("\ + -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\ +", stdout); + fputs("\ +\n\ +VERILOG PLUSARGS (accepted by the Verilog itself):\n" , stdout); + const char ** vpa = &verilog_plusargs[0]; + while (*vpa) { + fprintf(stdout, " +%s=...\n", *vpa); + vpa ++; + } + fputs("\n" HTIF_USAGE_OPTIONS, stdout); + printf("\n" +"EXAMPLES\n" +" - run a bare metal test:\n" +" %s $RISCV/riscv64-unknown-elf/share/riscv-tests/isa/rv64ui-p-add\n" +" - run a bare metal test showing cycle-by-cycle information:\n" +" %s +verbose $RISCV/riscv64-unknown-elf/share/riscv-tests/isa/rv64ui-p-add 2>&1 | spike-dasm\n" +#if VM_TRACE +" - run a bare metal test to generate a VCD waveform:\n" +" %s -v rv64ui-p-add.vcd $RISCV/riscv64-unknown-elf/share/riscv-tests/isa/rv64ui-p-add\n" +#endif +" - run an ELF (you wrote, called 'hello') using the proxy kernel:\n" +" %s pk hello\n", + program_name, program_name, program_name, program_name); } int main(int argc, char** argv) @@ -73,8 +108,9 @@ int main(int argc, char** argv) FILE * vcdfile = NULL; uint64_t start = 0; #endif - - std::vector to_dtm; + char ** htif_argv = NULL; + int verilog_plusargs_legal = 1; + while (1) { static struct option long_options[] = { {"cycle-count", no_argument, 0, 'c' }, @@ -86,7 +122,7 @@ int main(int argc, char** argv) {"vcd", required_argument, 0, 'v' }, {"dump-start", required_argument, 0, 'x' }, #endif - {0, 0, 0, 0} + HTIF_LONG_OPTIONS }; int option_index = 0; #if VM_TRACE @@ -95,8 +131,9 @@ int main(int argc, char** argv) int c = getopt_long(argc, argv, "-chm:s:V", long_options, &option_index); #endif if (c == -1) break; + retry: switch (c) { - // Process "normal" options with '--' long options or '-' short options + // Process long and short EMULATOR options case '?': usage(argv[0]); return 1; case 'c': print_cycles = true; break; case 'h': usage(argv[0]); return 0; @@ -114,39 +151,86 @@ int main(int argc, char** argv) } case 'x': start = atoll(optarg); break; #endif - // Processing of legacy '+' options and recognition of when - // we've hit the binary. The binary is expected to be a - // non-option and not start with '-' or '+'. + // Process legacy '+' EMULATOR arguments by replacing them with + // their getopt equivalents case 1: { std::string arg = optarg; - if (arg == "+verbose") - verbose = true; - else if (arg.substr(0, 12) == "+max-cycles=") - max_cycles = atoll(optarg+12); -#if VM_TRACE - else if (arg.substr(0, 12) == "+dump-start=") - start = atoll(optarg+12); -#endif - else if (arg.substr(0, 12) == "+cycle-count") - print_cycles = true; - else { - to_dtm.push_back(optarg); + if (arg.substr(0, 1) != "+") { + optind--; goto done_processing; } - break; + if (arg == "+verbose") + c = 'V'; + else if (arg.substr(0, 12) == "+max-cycles=") { + c = 'm'; + optarg = optarg+12; + } +#if VM_TRACE + else if (arg.substr(0, 12) == "+dump-start=") { + c = 'x'; + optarg = optarg+12; + } +#endif + else if (arg.substr(0, 12) == "+cycle-count") + c = 'c'; + // 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) { + const char ** plusarg = &verilog_plusargs[0]; + int legal_verilog_plusarg = 0; + while (*plusarg && (legal_verilog_plusarg == 0)){ + if (arg.substr(1, strlen(*plusarg)) == *plusarg) { + legal_verilog_plusarg = 1; + } + plusarg ++; + } + if (!legal_verilog_plusarg) { + verilog_plusargs_legal = 0; + } else { + c = 'P'; + } + goto retry; + } + // If we STILL don't find a legacy '+' argument, it still could be + // an HTIF (HOST) argument and not an error. If this is the case, then + // we're done processing EMULATOR and VERILOG arguments. + else { + 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 = '?'; + } + goto retry; } + case 'P': break; // Nothing to do here, Verilog PlusArg + // 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; } } done_processing: - if (optind < argc) - while (optind < argc) - to_dtm.push_back(argv[optind++]); - if (!to_dtm.size()) { + if (optind == argc) { std::cerr << "No binary specified for emulator\n"; usage(argv[0]); return 1; } + 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++]; if (verbose) fprintf(stderr, "using random seed %u\n", random_seed); @@ -168,26 +252,39 @@ done_processing: } #endif - dtm = new dtm_t(to_dtm); + jtag = new remote_bitbang_t(0); + dtm = new dtm_t(htif_argc, htif_argv); signal(SIGTERM, handle_sigterm); + bool dump; // reset for several cycles to handle pipelined reset for (int i = 0; i < 10; i++) { tile->reset = 1; tile->clock = 0; tile->eval(); +#if VM_TRACE + dump = tfp && trace_count >= start; + if (dump) + tfp->dump(static_cast(trace_count * 2)); +#endif tile->clock = 1; tile->eval(); - tile->reset = 0; +#if VM_TRACE + if (dump) + tfp->dump(static_cast(trace_count * 2 + 1)); +#endif + trace_count ++; } + tile->reset = 0; done_reset = true; - while (!dtm->done() && !tile->io_success && trace_count < max_cycles) { + while (!dtm->done() && !jtag->done() && + !tile->io_success && trace_count < max_cycles) { tile->clock = 0; tile->eval(); #if VM_TRACE - bool dump = tfp && trace_count >= start; + dump = tfp && trace_count >= start; if (dump) tfp->dump(static_cast(trace_count * 2)); #endif @@ -213,6 +310,11 @@ done_processing: fprintf(stderr, "*** FAILED *** (code = %d, seed %d) after %ld cycles\n", dtm->exit_code(), random_seed, trace_count); ret = dtm->exit_code(); } + 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(); + } else if (trace_count == max_cycles) { fprintf(stderr, "*** FAILED *** (timeout, seed %d) after %ld cycles\n", random_seed, trace_count); @@ -224,6 +326,8 @@ done_processing: } if (dtm) delete dtm; + if (jtag) delete jtag; if (tile) delete tile; + if (htif_argv) free(htif_argv); return ret; } diff --git a/csrc/remote_bitbang.cc b/csrc/remote_bitbang.cc new file mode 100644 index 00000000..07dc6e01 --- /dev/null +++ b/csrc/remote_bitbang.cc @@ -0,0 +1,202 @@ +// See LICENSE.Berkeley for license details. + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "remote_bitbang.h" + +/////////// remote_bitbang_t + +remote_bitbang_t::remote_bitbang_t(uint16_t port) : + socket_fd(0), + client_fd(0), + recv_start(0), + recv_end(0) +{ + socket_fd = socket(AF_INET, SOCK_STREAM, 0); + if (socket_fd == -1) { + fprintf(stderr, "remote_bitbang failed to make socket: %s (%d)\n", + strerror(errno), errno); + abort(); + } + + fcntl(socket_fd, F_SETFL, O_NONBLOCK); + int reuseaddr = 1; + if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, + sizeof(int)) == -1) { + fprintf(stderr, "remote_bitbang failed setsockopt: %s (%d)\n", + strerror(errno), errno); + abort(); + } + + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = htons(port); + + if (bind(socket_fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) { + fprintf(stderr, "remote_bitbang failed to bind socket: %s (%d)\n", + strerror(errno), errno); + abort(); + } + + if (listen(socket_fd, 1) == -1) { + fprintf(stderr, "remote_bitbang failed to listen on socket: %s (%d)\n", + strerror(errno), errno); + abort(); + } + + socklen_t addrlen = sizeof(addr); + if (getsockname(socket_fd, (struct sockaddr *) &addr, &addrlen) == -1) { + fprintf(stderr, "remote_bitbang getsockname failed: %s (%d)\n", + strerror(errno), errno); + abort(); + } + + tck = 1; + tms = 1; + tdi = 1; + trstn = 1; + quit = 0; + + printf ("This emulator compiled with JTAG Remote Bitbang client. To enable, use +jtag_rbb_enable=1.\n"); + printf("Listening on port %d\n", + ntohs(addr.sin_port)); + fflush(stdout); +} + +void remote_bitbang_t::accept() +{ + + fprintf(stderr,"Attempting to accept client socket\n"); + int again = 1; + while (again != 0) { + client_fd = ::accept(socket_fd, NULL, NULL); + if (client_fd == -1) { + if (errno == EAGAIN) { + // No client waiting to connect right now. + } else { + fprintf(stderr, "failed to accept on socket: %s (%d)\n", strerror(errno), + errno); + again = 0; + abort(); + } + } else { + fcntl(client_fd, F_SETFL, O_NONBLOCK); + fprintf(stderr, "Accepted successfully."); + again = 0; + } + } +} + +void remote_bitbang_t::tick( + unsigned char * jtag_tck, + unsigned char * jtag_tms, + unsigned char * jtag_tdi, + unsigned char * jtag_trstn, + unsigned char jtag_tdo + ) +{ + if (client_fd > 0) { + tdo = jtag_tdo; + execute_command(); + } else { + this->accept(); + } + + * jtag_tck = tck; + * jtag_tms = tms; + * jtag_tdi = tdi; + * jtag_trstn = trstn; + +} + +void remote_bitbang_t::reset(){ + //trstn = 0; +} + +void remote_bitbang_t::set_pins(char _tck, char _tms, char _tdi){ + tck = _tck; + tms = _tms; + tdi = _tdi; +} + +void remote_bitbang_t::execute_command() +{ + char command; + int again = 1; + while (again) { + ssize_t num_read = read(client_fd, &command, sizeof(command)); + if (num_read == -1) { + if (errno == EAGAIN) { + // We'll try again the next call. + fprintf(stderr, "Received no command. Will try again on the next call\n"); + } else { + fprintf(stderr, "remote_bitbang failed to read on socket: %s (%d)\n", + strerror(errno), errno); + again = 0; + abort(); + } + } else if (num_read == 0) { + fprintf(stderr, "No Command Received.\n"); + again = 1; + } else { + again = 0; + } + } + + fprintf(stderr, "Received a command %c\n", command); + + int dosend = 0; + + char tosend = '?'; + + switch (command) { + case 'B': /* fprintf(stderr, "*BLINK*\n"); */ break; + case 'b': /* fprintf(stderr, "_______\n"); */ break; + case 'r': reset(); break; // This is wrong. 'r' has other bits that indicated TRST and SRST. + case '0': set_pins(0, 0, 0); break; + case '1': set_pins(0, 0, 1); break; + case '2': set_pins(0, 1, 0); break; + case '3': set_pins(0, 1, 1); break; + case '4': set_pins(1, 0, 0); break; + case '5': set_pins(1, 0, 1); break; + case '6': set_pins(1, 1, 0); break; + case '7': set_pins(1, 1, 1); break; + case 'R': dosend = 1; tosend = tdo ? '1' : '0'; break; + case 'Q': quit = 1; break; + default: + fprintf(stderr, "remote_bitbang got unsupported command '%c'\n", + command); + } + + if (dosend){ + while (1) { + ssize_t bytes = write(client_fd, &tosend, sizeof(tosend)); + if (bytes == -1) { + fprintf(stderr, "failed to write to socket: %s (%d)\n", strerror(errno), errno); + abort(); + } + if (bytes > 0) { + break; + } + } + } + + if (quit) { + // The remote disconnected. + fprintf(stderr, "Remote end disconnected\n"); + close(client_fd); + client_fd = 0; + } +} diff --git a/csrc/remote_bitbang.h b/csrc/remote_bitbang.h new file mode 100644 index 00000000..6d7c2469 --- /dev/null +++ b/csrc/remote_bitbang.h @@ -0,0 +1,59 @@ +// See LICENSE.Berkeley for license details. + +#ifndef REMOTE_BITBANG_H +#define REMOTE_BITBANG_H + +#include +#include + +class remote_bitbang_t +{ +public: + // Create a new server, listening for connections from localhost on the given + // port. + remote_bitbang_t(uint16_t port); + + // Do a bit of work. + void tick(unsigned char * jtag_tck, + unsigned char * jtag_tms, + unsigned char * jtag_tdi, + unsigned char * jtag_trstn, + unsigned char jtag_tdo); + + unsigned char done() {return quit;} + + int exit_code() {return err;} + + private: + + int err; + + unsigned char tck; + unsigned char tms; + unsigned char tdi; + unsigned char trstn; + unsigned char tdo; + unsigned char quit; + + int socket_fd; + int client_fd; + + static const ssize_t buf_size = 64 * 1024; + char recv_buf[buf_size]; + ssize_t recv_start, recv_end; + + // Check for a client connecting, and accept if there is one. + void accept(); + // Execute any commands the client has for us. + // But we only execute 1 because we need time for the + // simulation to run. + void execute_command(); + + // Reset. Currently does nothing. + void reset(); + + void set_pins(char _tck, char _tms, char _tdi); + +}; + +#endif diff --git a/emulator/Makefile b/emulator/Makefile index a0a854c7..86597fb1 100644 --- a/emulator/Makefile +++ b/emulator/Makefile @@ -8,7 +8,7 @@ output_dir = $(sim_dir)/output include $(base_dir)/Makefrag -CXXSRCS := emulator SimDTM +CXXSRCS := emulator SimDTM SimJTAG remote_bitbang CXXFLAGS := $(CXXFLAGS) -std=c++11 -I$(RISCV)/include -I$(base_dir)/csrc LDFLAGS := $(LDFLAGS) -L$(RISCV)/lib -Wl,-rpath,$(RISCV)/lib -L$(abspath $(sim_dir)) -lfesvr -lpthread diff --git a/regression/Makefile b/regression/Makefile index 6c011f92..76411e18 100644 --- a/regression/Makefile +++ b/regression/Makefile @@ -62,8 +62,9 @@ CONFIGS=AMBAUnitTestConfig TLSimpleUnitTestConfig TLWidthUnitTestConfig endif ifeq ($(SUITE), JtagDtmSuite) -CONFIGS_32=WithJtagDTM_DefaultRV32Config -CONFIGS_64=WithJtagDTM_DefaultConfig +PROJECT=freechips.rocketchip.system +CONFIGS_32=WithJtagDTMSystem_DefaultRV32Config +CONFIGS_64=WithJtagDTMSystem_DefaultConfig CONFIGS += $(CONFIGS_32) CONFIGS += $(CONFIGS_64) endif @@ -208,44 +209,87 @@ stamps/%/emulator-torture-$(TORTURE_CONFIG).stamp: stamps/%/emulator-debug.stamp # Targets for JTAG DTM full-chain simulation -OPENOCD_DIR ?= $(RISCV) - # If this is defined empty, then all tests would run. JTAG_DTM_TEST ?= MemTest64 +GDBSERVER = $(abspath $(TOP))/riscv-tools/riscv-tests/debug/gdbserver.py \ + --print-failures \ + --print-log-names ifdef DEBUG JTAG_STAMP_SUFFIX=-debug JTAG_DEBUG_SUFFIX=-debug -JTAG_VCDPLUS_32= +vcdplusfile=regression32.vcd -JTAG_VCDPLUS_64= +vcdplusfile=regression64.vcd +VSIM_JTAG_VCDPLUS_32= +vcdplusfile=regression32.vcd +VSIM_JTAG_VCDPLUS_64= +vcdplusfile=regression64.vcd +EMULATOR_JTAG_VCDPLUS_32= -v regression32.vcd +EMULATOR_JTAG_VCDPLUS_64= -v regression64.vcd OPENOCD_DEBUG= -d else JTAG_STAMP_SUFFIX=-ndebug endif -stamps/%/jtag-dtm-32-$(JTAG_DTM_TEST).stamp: stamps/%/vsim$(JTAG_STAMP_SUFFIX).stamp - export RISCV=$(RISCV) && $(abspath $(TOP))/riscv-tools/riscv-tests/debug/gdbserver.py \ - --sim_cmd "$(abspath $(TOP))/vsim/simv-$(PROJECT)-$*$(JTAG_DEBUG_SUFFIX) +verbose $(JTAG_VCDPLUS_32)" \ - --server_cmd="$(OPENOCD_DIR)/bin/openocd $(OPENOCD_DEBUG) \ - --s $(OPENOCD_DIR)/share/openocd/scripts" \ - --freedom-e300-sim \ +ifdef SEED +SEED_ARG = --seed $(SEED) +endif + +JTAG_DTM_SIM_ARGS = +verbose +jtag_rbb_enable=1 $(SEED_ARG) + +stamps/riscv-tests.stamp: + git -C $(abspath $(TOP)) submodule update --init riscv-tools + git -C $(abspath $(TOP))/riscv-tools submodule update --init --recursive riscv-tests + date > $@ + +stamps/%/vsim-jtag-dtm-32-$(JTAG_DTM_TEST).stamp: stamps/%/vsim$(JTAG_STAMP_SUFFIX).stamp stamps/riscv-tests.stamp + RISCV=$(RISCV) $(GDBSERVER) \ + --sim_cmd="$(abspath $(TOP))/vsim/simv-$(PROJECT)-$*$(JTAG_DEBUG_SUFFIX) $(JTAG_DTM_SIM_ARGS) $(VSIM_JTAG_VCDPLUS_32)" \ + --server_cmd="$(RISCV)/bin/openocd $(OPENOCD_DEBUG) \ + -s $(RISCV)/share/openocd/scripts" \ + --32 \ + $(abspath $(TOP))/scripts/RocketSim32.py \ $(JTAG_DTM_TEST) date > $@ -stamps/%/jtag-dtm-64-$(JTAG_DTM_TEST).stamp: stamps/%/vsim$(JTAG_STAMP_SUFFIX).stamp - export RISCV=$(RISCV) && $(abspath $(TOP))/riscv-tools/riscv-tests/debug/gdbserver.py \ - --sim_cmd "$(abspath $(TOP))/vsim/simv-$(PROJECT)-$*$(JTAG_DEBUG_SUFFIX) +verbose $(JTAG_VCDPLUS_64)" \ +stamps/%/vsim-jtag-dtm-64-$(JTAG_DTM_TEST).stamp: stamps/%/vsim$(JTAG_STAMP_SUFFIX).stamp stamps/riscv-tests.stamp + RISCV=$(RISCV) $(GDBSERVER) \ + --sim_cmd="$(abspath $(TOP))/vsim/simv-$(PROJECT)-$*$(JTAG_DEBUG_SUFFIX) $(JTAG_DTM_SIM_ARGS) $(VSIM_JTAG_VCDPLUS_64)" \ --server_cmd="$(OPENOCD_INSTALL)_$(OPENOCD_VERSION)/bin/openocd $(OPENOCD_DEBUG) \ - --s $(OPENOCD_INSTALL)_$(OPENOCD_VERSION)/share/openocd/scripts" \ - --freedom-u500-sim \ + -s $(OPENOCD_INSTALL)_$(OPENOCD_VERSION)/share/openocd/scripts" \ + --64 \ + $(abspath $(TOP))/scripts/RocketSim64.py \ $(JTAG_DTM_TEST) date > $@ -JTAG_DTM_32_TEST_STAMPS=$(foreach config,$(CONFIGS_32),stamps/$(config)/jtag-dtm-32-$(JTAG_DTM_TEST).stamp) -JTAG_DTM_64_TEST_STAMPS=$(foreach config,$(CONFIGS_64),stamps/$(config)/jtag-dtm-64-$(JTAG_DTM_TEST).stamp) +stamps/%/emulator-jtag-dtm-32-$(JTAG_DTM_TEST).stamp: stamps/%/emulator$(JTAG_STAMP_SUFFIX).stamp stamps/riscv-tests.stamp + RISCV=$(RISCV) $(GDBSERVER) \ + --sim_cmd="$(abspath $(TOP))/emulator/emulator-$(PROJECT)-$*$(JTAG_DEBUG_SUFFIX) $(JTAG_DTM_SIM_ARGS) $(EMULATOR_JTAG_VCDPLUS_32) dummybin" \ + --server_cmd="$(RISCV)/bin/openocd $(OPENOCD_DEBUG) \ + -s $(RISCV)/share/openocd/scripts" \ + --32 \ + $(abspath $(TOP))/scripts/RocketSim32.py \ + $(JTAG_DTM_TEST) + date > $@ -jtag-dtm-tests-32 : $(JTAG_DTM_32_TEST_STAMPS) -jtag-dtm-tests-64 : $(JTAG_DTM_64_TEST_STAMPS) +stamps/%/emulator-jtag-dtm-64-$(JTAG_DTM_TEST).stamp: stamps/%/emulator$(JTAG_STAMP_SUFFIX).stamp stamps/riscv-tests.stamp + RISCV=$(RISCV) $(GDBSERVER) \ + --sim_cmd="$(abspath $(TOP))/emulator/emulator-$(PROJECT)-$*$(JTAG_DEBUG_SUFFIX) $(JTAG_DTM_SIM_ARGS) $(EMULATOR_JTAG_VCDPLUS_64) dummybin" \ + --server_cmd="$(RISCV)/bin/openocd $(OPENOCD_DEBUG) \ + -s $(RISCV)/share/openocd/scripts" \ + --64 \ + $(abspath $(TOP))/scripts/RocketSim64.py \ + $(JTAG_DTM_TEST) + date > $@ + +VSIM_JTAG_DTM_32_TEST_STAMPS=$(foreach config,$(CONFIGS_32),stamps/$(config)/vsim-jtag-dtm-32-$(JTAG_DTM_TEST).stamp) +VSIM_JTAG_DTM_64_TEST_STAMPS=$(foreach config,$(CONFIGS_64),stamps/$(config)/vsim-jtag-dtm-64-$(JTAG_DTM_TEST).stamp) + +EMULATOR_JTAG_DTM_32_TEST_STAMPS=$(foreach config,$(CONFIGS_32),stamps/$(config)/emulator-jtag-dtm-32-$(JTAG_DTM_TEST).stamp) +EMULATOR_JTAG_DTM_64_TEST_STAMPS=$(foreach config,$(CONFIGS_64),stamps/$(config)/emulator-jtag-dtm-64-$(JTAG_DTM_TEST).stamp) + +vsim-jtag-dtm-tests-32 : $(VSIM_JTAG_DTM_32_TEST_STAMPS) +vsim-jtag-dtm-tests-64 : $(VSIM_JTAG_DTM_64_TEST_STAMPS) + +emulator-jtag-dtm-tests-32 : $(EMULATOR_JTAG_DTM_32_TEST_STAMPS) +emulator-jtag-dtm-tests-64 : $(EMULATOR_JTAG_DTM_64_TEST_STAMPS) # Targets for JTAG DTM full-chain simulation -jtag-dtm-regression: jtag-dtm-tests-32 jtag-dtm-tests-64 +vsim-jtag-dtm-regression: vsim-jtag-dtm-tests-32 vsim-jtag-dtm-tests-64 +emulator-jtag-dtm-regression: emulator-jtag-dtm-tests-32 emulator-jtag-dtm-tests-64 diff --git a/riscv-tools b/riscv-tools index 09a1ffe5..98682995 160000 --- a/riscv-tools +++ b/riscv-tools @@ -1 +1 @@ -Subproject commit 09a1ffe5afb57673e0641a86cdb94347056c5c06 +Subproject commit 98682995dc4a1ab8777ff45ba673cf2658e54ae2 diff --git a/scripts/RocketSim.cfg b/scripts/RocketSim.cfg new file mode 100644 index 00000000..fd6575c2 --- /dev/null +++ b/scripts/RocketSim.cfg @@ -0,0 +1,19 @@ +adapter_khz 10000 + +interface remote_bitbang +remote_bitbang_host localhost +#$::env(REMOTE_BITBANG_HOST) +remote_bitbang_port $::env(JTAG_VPI_PORT) + +set _CHIPNAME riscv +jtag newtap $_CHIPNAME cpu -irlen 5 + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME riscv -chain-position $_TARGETNAME -rtos riscv + +riscv set_reset_timeout_sec 120 +riscv set_command_timeout_sec 120 + +init +halt +echo "Ready for Remote Connections" diff --git a/scripts/RocketSim.py b/scripts/RocketSim.py new file mode 100644 index 00000000..7309911c --- /dev/null +++ b/scripts/RocketSim.py @@ -0,0 +1,21 @@ +import targets +import testlib + +class RocketSimHart(targets.Hart): + # This isn't generically true, but it's true enough for the Default*Configs in this code for now. + # to get these tests to pass. + ram = 0x80000000 + ram_size = 0x4000 + instruction_hardware_breakpoint_count = 2 + pass + +class RocketSim(targets.Target): + harts = [RocketSimHart()] + timeout_sec = 6000 + server_timeout_sec = 60*60 + openocd_config_path = "RocketSim.cfg" + + def create(self): + print "STARTING A SIMULATION" + print self.sim_cmd + return testlib.VcsSim(sim_cmd=self.sim_cmd, debug=False) diff --git a/scripts/RocketSim32.py b/scripts/RocketSim32.py new file mode 100644 index 00000000..55482121 --- /dev/null +++ b/scripts/RocketSim32.py @@ -0,0 +1,22 @@ +import targets +import testlib + +class RocketSimHart(targets.Hart): + xlen = 32 + # This isn't generically true, but it's true enough for the Default*Configs in this code for now. + # to get these tests to pass. + ram = 0x80000000 + ram_size = 0x4000 + instruction_hardware_breakpoint_count = 2 + pass + +class RocketSim(targets.Target): + harts = [RocketSimHart()] + timeout_sec = 6000 + server_timeout_sec = 60*60 + openocd_config_path = "RocketSim.cfg" + + def create(self): + print "STARTING A SIMULATION" + print self.sim_cmd + return testlib.VcsSim(sim_cmd=self.sim_cmd, debug=False) diff --git a/scripts/RocketSim64.py b/scripts/RocketSim64.py new file mode 100644 index 00000000..0e89a51c --- /dev/null +++ b/scripts/RocketSim64.py @@ -0,0 +1,22 @@ +import targets +import testlib + +class RocketSimHart(targets.Hart): + # This isn't generically true, but it's true enough for the Default*Configs in this code for now. + # to get these tests to pass. + xlen = 64 + ram = 0x80000000 + ram_size = 0x4000 + instruction_hardware_breakpoint_count = 2 + pass + +class RocketSim(targets.Target): + harts = [RocketSimHart()] + timeout_sec = 6000 + server_timeout_sec = 60*60 + openocd_config_path = "RocketSim.cfg" + + def create(self): + print "STARTING A SIMULATION" + print self.sim_cmd + return testlib.VcsSim(sim_cmd=self.sim_cmd, debug=False) diff --git a/src/main/scala/devices/debug/Periphery.scala b/src/main/scala/devices/debug/Periphery.scala index 128fc128..3cec79e2 100644 --- a/src/main/scala/devices/debug/Periphery.scala +++ b/src/main/scala/devices/debug/Periphery.scala @@ -49,7 +49,8 @@ trait HasPeripheryDebugBundle { val dtm = Module(new SimDTM).connect(c, r, d, out) } debug.systemjtag.foreach { sj => - val jtag = Module(new JTAGVPI(tckHalfPeriod = tckHalfPeriod, cmdDelay = cmdDelay)).connect(sj.jtag, sj.reset, r, out) + //val jtag = Module(new JTAGVPI(tckHalfPeriod = tckHalfPeriod, cmdDelay = cmdDelay)).connect(sj.jtag, sj.reset, r, out) + val jtag = Module(new SimJTAG(tickDelay=3)).connect(sj.jtag, sj.reset, c, r, out) sj.mfr_id := p(JtagDTMKey).idcodeManufId.U(11.W) } debug.psd.foreach { _ <> psd } @@ -112,6 +113,36 @@ class SimDTM(implicit p: Parameters) extends BlackBox { } } +class SimJTAG(tickDelay: Int = 50) extends BlackBox(Map("TICK_DELAY" -> IntParam(tickDelay))) { + val io = new Bundle { + val clock = Clock(INPUT) + val reset = Bool(INPUT) + val jtag = new JTAGIO(hasTRSTn = true) + val enable = Bool(INPUT) + val init_done = Bool(INPUT) + val exit = UInt(OUTPUT, 32) + } + + def connect(dutio: JTAGIO, jtag_reset: Bool, tbclock: Clock, tbreset: Bool, tbsuccess: Bool) = { + dutio <> io.jtag + jtag_reset := tbreset + + io.clock := tbclock + io.reset := tbreset + + io.enable := PlusArg("jtag_rbb_enable", 0, "Enable SimJTAG for JTAG Connections. Simulation will pause until connection is made.") + io.init_done := ~tbreset + + // Success is determined by the gdbserver + // which is controlling this simulation. + tbsuccess := io.exit === UInt(1) + when (io.exit >= UInt(2)) { + printf("*** FAILED *** (exit code = %d)\n", io.exit >> UInt(1)) + stop(1) + } + } +} + class JTAGVPI(tckHalfPeriod: Int = 2, cmdDelay: Int = 2)(implicit val p: Parameters) extends BlackBox ( Map ("TCK_HALF_PERIOD" -> IntParam(tckHalfPeriod), "CMD_DELAY" -> IntParam(cmdDelay))) { diff --git a/src/main/scala/system/Configs.scala b/src/main/scala/system/Configs.scala index f120964f..5aab4f1f 100644 --- a/src/main/scala/system/Configs.scala +++ b/src/main/scala/system/Configs.scala @@ -9,6 +9,8 @@ import freechips.rocketchip.coreplex._ import freechips.rocketchip.devices.debug.{IncludeJtagDTM, JtagDTMKey} import freechips.rocketchip.diplomacy._ +class WithJtagDTMSystem extends freechips.rocketchip.coreplex.WithJtagDTM + class BaseConfig extends Config(new BaseCoreplexConfig().alter((site,here,up) => { // DTS descriptive parameters case DTSModel => "freechips,rocketchip-unknown" diff --git a/vsim/Makefrag b/vsim/Makefrag index 2fd3b076..db0e6d4c 100644 --- a/vsim/Makefrag +++ b/vsim/Makefrag @@ -16,13 +16,15 @@ sim_vsrcs = \ $(generated_dir)/$(long_name).behav_srams.v \ $(base_dir)/vsrc/$(TB).v \ $(base_dir)/vsrc/SimDTM.v \ + $(base_dir)/vsrc/SimJTAG.v \ $(bb_vsrcs) # C sources sim_csrcs = \ $(base_dir)/csrc/SimDTM.cc \ - $(base_dir)/csrc/jtag_vpi.c + $(base_dir)/csrc/SimJTAG.cc \ + $(base_dir)/csrc/remote_bitbang.cc \ #-------------------------------------------------------------------- # Build Verilog diff --git a/vsrc/AsyncResetReg.v b/vsrc/AsyncResetReg.v index aee4b639..f34f4fa9 100644 --- a/vsrc/AsyncResetReg.v +++ b/vsrc/AsyncResetReg.v @@ -45,30 +45,37 @@ module AsyncResetReg ( input clk, input rst); -`ifdef RANDOMIZE - integer initvar; - reg [31:0] _RAND; initial begin -`ifndef verilator - #0.002 begin end -`endif -`ifdef RANDOMIZE_REG_INIT +`ifdef RANDOMIZE + integer initvar; + reg [31:0] _RAND; _RAND = {1{$random}}; - if (~rst) begin +`endif + if (rst) begin +`ifdef verilator + q = 1'b0; +`endif + end +`ifdef RANDOMIZE + `ifndef verilator + `endif + `ifdef RANDOMIZE_REG_INIT + else begin + #0.002 begin end q = _RAND[0]; end -`endif + `endif +`endif // `ifdef RANDOMIZE end -`endif // `ifdef RANDOMIZE always @(posedge clk or posedge rst) begin - + if (rst) begin q <= 1'b0; end else if (en) begin q <= d; end end - + endmodule // AsyncResetReg diff --git a/vsrc/SimJTAG.v b/vsrc/SimJTAG.v new file mode 100644 index 00000000..fbc19d9e --- /dev/null +++ b/vsrc/SimJTAG.v @@ -0,0 +1,79 @@ +// See LICENSE.SiFive for license details. + +import "DPI-C" function int jtag_tick +( + output bit jtag_TCK, + output bit jtag_TMS, + output bit jtag_TDI, + output bit jtag_TRSTn, + + input bit jtag_TDO +); + +module SimJTAG #( + parameter TICK_DELAY = 50 + )( + + input clock, + input reset, + + input enable, + input init_done, + + output jtag_TCK, + output jtag_TMS, + output jtag_TDI, + output jtag_TRSTn, + + input jtag_TDO_data, + input jtag_TDO_driven, + + output [31:0] exit + ); + + reg [31:0] tickCounterReg; + wire [31:0] tickCounterNxt; + + assign tickCounterNxt = (tickCounterReg == 0) ? TICK_DELAY : (tickCounterReg - 1); + + bit r_reset; + + wire [31:0] random_bits = $random; + + wire #0.1 __jtag_TDO = jtag_TDO_driven ? + jtag_TDO_data : random_bits[0]; + + bit __jtag_TCK; + bit __jtag_TMS; + bit __jtag_TDI; + bit __jtag_TRSTn; + int __exit; + + assign #0.1 jtag_TCK = __jtag_TCK; + assign #0.1 jtag_TMS = __jtag_TMS; + assign #0.1 jtag_TDI = __jtag_TDI; + assign #0.1 jtag_TRSTn = __jtag_TRSTn; + + assign #0.1 exit = __exit; + + always @(posedge clock) begin + r_reset <= reset; + if (reset || r_reset) begin + __exit = 0; + tickCounterReg <= TICK_DELAY; + end else begin + if (enable && init_done) begin + tickCounterReg <= tickCounterNxt; + if (tickCounterReg == 0) begin + __exit = jtag_tick( + __jtag_TCK, + __jtag_TMS, + __jtag_TDI, + __jtag_TRSTn, + __jtag_TDO); + end + end // if (enable && init_done) + end // else: !if(reset || r_reset) + end // always @ (posedge clock) + +endmodule