From e82328336e5c68c3de74dbfce05411c67d4e5305 Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Tue, 11 Apr 2017 20:03:34 -0700 Subject: [PATCH] Add in a SimJTAG to connect to OpenOCD's remote-bitbang interface. This is simpler than JTAGVPI and is supported better by Verilor. It is also the same thing Spike uses. --- csrc/SimJTAG.cc | 32 +++++ csrc/emulator.cc | 14 +- csrc/remote_bitbang.cc | 196 ++++++++++++++++++++++++++++ csrc/remote_bitbang.h | 59 +++++++++ emulator/Makefile | 2 +- regression/Makefile | 65 ++++++--- src/main/scala/system/Configs.scala | 2 + vsim/Makefrag | 4 +- vsrc/SimJTAG.v | 79 +++++++++++ 9 files changed, 430 insertions(+), 23 deletions(-) create mode 100644 csrc/SimJTAG.cc create mode 100644 csrc/remote_bitbang.cc create mode 100644 csrc/remote_bitbang.h create mode 100644 vsrc/SimJTAG.v diff --git a/csrc/SimJTAG.cc b/csrc/SimJTAG.cc new file mode 100644 index 00000000..5f0a2c77 --- /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..f23f1b4c 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 @@ -15,6 +16,8 @@ #include extern dtm_t* dtm; +extern remote_bitbang_t * jtag; + static uint64_t trace_count = 0; bool verbose; bool done_reset; @@ -169,6 +172,8 @@ done_processing: #endif dtm = new dtm_t(to_dtm); + //TODO: Specify port. + jtag = new remote_bitbang_t(0); signal(SIGTERM, handle_sigterm); @@ -183,7 +188,8 @@ done_processing: } 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 @@ -213,6 +219,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 +235,7 @@ done_processing: } if (dtm) delete dtm; + if (jtag) delete jtag; if (tile) delete tile; return ret; } diff --git a/csrc/remote_bitbang.cc b/csrc/remote_bitbang.cc new file mode 100644 index 00000000..bdd83bfb --- /dev/null +++ b/csrc/remote_bitbang.cc @@ -0,0 +1,196 @@ +// 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("Listening on port %d\n", + ntohs(addr.sin_port)); + fflush(stdout); +} + +void remote_bitbang_t::accept() +{ + + fprintf(stderr,"Attempting to accept client socket\n"); + + client_fd = ::accept(socket_fd, NULL, NULL); + if (client_fd == -1) { + if (errno == EAGAIN) { + // No client waiting to connect right now. + fprintf(stderr, "Not Accepted: Received EAGAIN error\n"); + } else { + fprintf(stderr, "failed to accept on socket: %s (%d)\n", strerror(errno), + errno); + abort(); + } + } else { + fcntl(client_fd, F_SETFL, O_NONBLOCK); + fprintf(stderr, "Accepted successfully."); + } +} + +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; + + 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"); + return; + } else { + fprintf(stderr, "remote_bitbang failed to read on socket: %s (%d)\n", + strerror(errno), errno); + abort(); + } + } + + if (num_read == 0) { + fprintf(stderr, "No Command Received.\n"); + return; + } + + 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..62c861d7 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,68 @@ 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 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 +stamps/%/vsim-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 \ + --sim_cmd="$(abspath $(TOP))/vsim/simv-$(PROJECT)-$*$(JTAG_DEBUG_SUFFIX) +verbose $(VSIM_JTAG_VCDPLUS_32)" \ + --server_cmd="$(RISCV)/bin/openocd $(OPENOCD_DEBUG) \ + --s $(RISCV)/share/openocd/scripts" \ + $(abspath $(TOP))/scripts/FreedomSim.py \ $(JTAG_DTM_TEST) date > $@ -stamps/%/jtag-dtm-64-$(JTAG_DTM_TEST).stamp: stamps/%/vsim$(JTAG_STAMP_SUFFIX).stamp +stamps/%/vsim-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)" \ + --sim_cmdrun "$(abspath $(TOP))/vsim/simv-$(PROJECT)-$*$(JTAG_DEBUG_SUFFIX) +verbose $(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 \ + $(abspath $(TOP))/scripts/FreedomSim.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 + export RISCV=$(RISCV) && $(abspath $(TOP))/riscv-tools/riscv-tests/debug/gdbserver.py \ + --sim_cmd "$(abspath $(TOP))/emulator/emulator-$(PROJECT)-$*$(JTAG_DEBUG_SUFFIX) +verbose $(EMULATOR_JTAG_VCDPLUS_32) dummybin | tee emulator.log" \ + --server_cmd="$(RISCV)/bin/openocd $(OPENOCD_DEBUG) \ + --s $(RISCV)/share/openocd/scripts" \ + $(abspath $(TOP))/scripts/FreedomSim.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 + export RISCV=$(RISCV) && $(abspath $(TOP))/riscv-tools/riscv-tests/debug/gdbserver.py \ + --sim_cmd "$(abspath $(TOP))/emulator/emulator-$(PROJECT)-$*$(JTAG_DEBUG_SUFFIX) +verbose $(EMULATOR_JTAG_VCDPLUS_64) dummybin | tee emulator.log" \ + --server_cmd="$(RISCV)/bin/openocd $(OPENOCD_DEBUG) \ + --s $(RISCV)/share/openocd/scripts" \ + $(abspath $(TOP))/scripts/FreedomSim.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/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/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