From dd4a50c4529b16669a498ac76dba9b049888bd41 Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Fri, 19 Aug 2016 09:46:43 -0700 Subject: [PATCH 1/9] Add JTAG DTM and test support in simulation Initial cut checkpoint which compiles and runs but there is some off-by-1 in the protocol Debugging the clock crossing logic checkpoint which works Clean up the AsyncMailbox black box --- .gitmodules | 3 + csrc/jtag_vpi.c | 419 ++++++++++++++++++++ openocd | 1 + src/main/scala/DebugTransport.scala | 124 ++++++ src/main/scala/rocketchip/Configs.scala | 17 +- src/main/scala/rocketchip/RocketChip.scala | 21 +- src/main/scala/rocketchip/TestHarness.scala | 58 ++- src/main/scala/uncore/devices/Debug.scala | 11 +- vsim/Makefrag | 13 +- vsrc/AsyncFifo.v | 271 +++++++++++++ vsrc/DebugTransportModuleJtag.v | 301 ++++++++++++++ vsrc/jtag_vpi.tab | 2 + vsrc/jtag_vpi.v | 302 ++++++++++++++ vsrc/rocketDTMTestHarness.v | 293 ++++++++++++++ 14 files changed, 1813 insertions(+), 23 deletions(-) create mode 100644 csrc/jtag_vpi.c create mode 160000 openocd create mode 100644 src/main/scala/DebugTransport.scala create mode 100644 vsrc/AsyncFifo.v create mode 100755 vsrc/DebugTransportModuleJtag.v create mode 100644 vsrc/jtag_vpi.tab create mode 100644 vsrc/jtag_vpi.v create mode 100644 vsrc/rocketDTMTestHarness.v diff --git a/.gitmodules b/.gitmodules index 50163ec5..89e53c38 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,3 +16,6 @@ [submodule "firrtl"] path = firrtl url = https://github.com/ucb-bar/firrtl.git +[submodule "openocd"] + path = openocd + url = http://github.com/sifive/openocd.git diff --git a/csrc/jtag_vpi.c b/csrc/jtag_vpi.c new file mode 100644 index 00000000..9c6198ad --- /dev/null +++ b/csrc/jtag_vpi.c @@ -0,0 +1,419 @@ +/* + * TCP/IP controlled VPI JTAG Interface. + * Based on Julius Baxter's work on jp_vpi.c + * + * Copyright (C) 2012 Franck Jullien, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of any + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define RSP_SERVER_PORT 5555 +#define XFERT_MAX_SIZE 512 + +const char * cmd_to_string[] = {"CMD_RESET", + "CMD_TMS_SEQ", + "CMD_SCAN_CHAIN"}; + +struct vpi_cmd { + int cmd; + unsigned char buffer_out[XFERT_MAX_SIZE]; + unsigned char buffer_in[XFERT_MAX_SIZE]; + int length; + int nb_bits; +}; + +int listenfd = 0; +int connfd = 0; + +int init_jtag_server(int port) +{ + struct sockaddr_in serv_addr; + int flags; + + printf("Listening on port %d\n", port); + + listenfd = socket(AF_INET, SOCK_STREAM, 0); + memset(&serv_addr, '0', sizeof(serv_addr)); + + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); + serv_addr.sin_port = htons(port); + + bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); + + listen(listenfd, 10); + + printf("Waiting for client connection..."); + connfd = accept(listenfd, (struct sockaddr*)NULL, NULL); + printf("ok\n"); + + flags = fcntl(listenfd, F_GETFL, 0); + fcntl(listenfd, F_SETFL, flags | O_NONBLOCK); + + return 0; +} + +// See if there's anything on the FIFO for us + +void check_for_command(char *userdata) +{ + vpiHandle systfref, args_iter, argh; + struct t_vpi_value argval; + struct vpi_cmd vpi; + int nb; + int loaded_words = 0; + + (void)userdata; + + // Get the command from TCP server + if(!connfd) + init_jtag_server(RSP_SERVER_PORT); + nb = read(connfd, &vpi, sizeof(struct vpi_cmd)); + + if (((nb < 0) && (errno == EAGAIN)) || (nb == 0)) { + // Nothing in the fifo this time, let's return + return; + } else { + if (nb < 0) { + // some sort of error + perror("check_for_command"); + exit(1); + } + } + +/************* vpi.cmd to VPI ******************************/ + + // Obtain a handle to the argument list + systfref = vpi_handle(vpiSysTfCall, NULL); + // Now call iterate with the vpiArgument parameter + args_iter = vpi_iterate(vpiArgument, systfref); + // get a handle on the variable passed to the function + argh = vpi_scan(args_iter); + // now store the command value back in the sim + argval.format = vpiIntVal; + // Now set the command value + vpi_get_value(argh, &argval); + + argval.value.integer = (uint32_t)vpi.cmd; + + // And vpi_put_value() it back into the sim + vpi_put_value(argh, &argval, NULL, vpiNoDelay); + +/************* vpi.length to VPI ******************************/ + + // now get a handle on the next object (memory array) + argh = vpi_scan(args_iter); + // now store the command value back in the sim + argval.format = vpiIntVal; + // Now set the command value + vpi_get_value(argh, &argval); + + argval.value.integer = (uint32_t)vpi.length; + + // And vpi_put_value() it back into the sim + vpi_put_value(argh, &argval, NULL, vpiNoDelay); + +/************* vpi.nb_bits to VPI ******************************/ + + // now get a handle on the next object (memory array) + argh = vpi_scan(args_iter); + // now store the command value back in the sim + argval.format = vpiIntVal; + // Now set the command value + vpi_get_value(argh, &argval); + + argval.value.integer = (uint32_t)vpi.nb_bits; + + // And vpi_put_value() it back into the sim + vpi_put_value(argh, &argval, NULL, vpiNoDelay); + +/*****************vpi.buffer_out to VPI ********/ + + // now get a handle on the next object (memory array) + argh = vpi_scan(args_iter); + vpiHandle array_word; + + // Loop to load the words + while (loaded_words < vpi.length) { + // now get a handle on the current word we want in the array that was passed to us + array_word = vpi_handle_by_index(argh, loaded_words); + + if (array_word != NULL) { + argval.value.integer = (uint32_t)vpi.buffer_out[loaded_words]; + // And vpi_put_value() it back into the sim + vpi_put_value(array_word, &argval, NULL, vpiNoDelay); + } else + return; + + loaded_words++; + } + +/*******************************************/ + + // Cleanup and return + vpi_free_object(args_iter); +} + +void send_result_to_server(char *userdata) +{ + vpiHandle systfref, args_iter, argh; + struct t_vpi_value argval; + ssize_t n; + struct vpi_cmd vpi; + + int32_t length; + int sent_words; + + vpiHandle array_word; + + (void)userdata; + + // Now setup the handles to verilog objects and check things + // Obtain a handle to the argument list + systfref = vpi_handle(vpiSysTfCall, NULL); + + // Now call iterate with the vpiArgument parameter + args_iter = vpi_iterate(vpiArgument, systfref); + + // get a handle on the length variable + argh = vpi_scan(args_iter); + + argval.format = vpiIntVal; + + // get the value for the length object + vpi_get_value(argh, &argval); + + // now set length + length = argval.value.integer; + + // now get a handle on the next object (memory array) + argh = vpi_scan(args_iter); + + // check we got passed a memory (array of regs) + if (!((vpi_get(vpiType, argh) == vpiMemory) +#ifdef MODELSIM_VPI + || (vpi_get(vpiType, argh) == vpiRegArray) +#endif +#ifdef VCS_VPI + || (vpi_get(vpiType, argh) == vpiRegArray) +#endif + )) { + vpi_printf("jtag_vpi: ERROR: did not pass a memory to get_command_block_data\n"); + vpi_printf("jtag_vpi: ERROR: was passed type %d\n", (int)vpi_get(vpiType, argh)); + return; + } + + // check the memory we're writing into is big enough + if (vpi_get(vpiSize, argh) < length ) { + vpi_printf("jtag_vpi: ERROR: buffer passed to get_command_block_data too small. size is %d words, needs to be %d\n", + vpi_get(vpiSize, argh), length); + return; + } + + // Loop to load the words + sent_words = 0; + while (sent_words < length) { + // Get a handle on the current word we want in the array that was passed to us + array_word = vpi_handle_by_index(argh, sent_words); + + if (array_word != NULL) { + vpi_get_value(array_word, &argval); + vpi.buffer_in[sent_words] = (uint32_t) argval.value.integer; + } else + return; + + sent_words++; + } + + n = write(connfd, &vpi, sizeof(struct vpi_cmd)); + if (n < (ssize_t)sizeof(struct vpi_cmd)) + vpi_printf("jtag_vpi: ERROR: error during write to server\n"); + + // Cleanup and return + vpi_free_object(args_iter); +} + +void register_check_for_command(void) +{ + s_vpi_systf_data data = { + vpiSysTask, + 0, + "$check_for_command", + (void *)check_for_command, + 0, + 0, + 0 + }; + + vpi_register_systf(&data); +} + +void register_send_result_to_server(void) +{ + s_vpi_systf_data data = { + vpiSysTask, + 0, + "$send_result_to_server", + (void *)send_result_to_server, + 0, + 0, + 0 + }; + + vpi_register_systf(&data); +} + +void sim_reset_callback(void) +{ + // nothing to do! +} + +void setup_reset_callbacks(void) +{ + // here we setup and install callbacks for + // the setup and management of connections to + // the simulator upon simulation start and + // reset + + static s_vpi_time time_s = {vpiScaledRealTime, 0, 0, 0}; + static s_vpi_value value_s = {.format = vpiBinStrVal}; + + static s_cb_data cb_data_s = { + cbEndOfReset, // or start of simulation - initing socket fds etc + (void *)sim_reset_callback, + NULL, + &time_s, + &value_s, + 0, + NULL + }; + + cb_data_s.obj = NULL; /* trigger object */ + + cb_data_s.user_data = NULL; + + // actual call to register the callback + vpi_register_cb(&cb_data_s); +} + +void sim_endofcompile_callback(void) +{ + +} + +void setup_endofcompile_callbacks(void) +{ + // here we setup and install callbacks for + // simulation finish + + static s_vpi_time time_s = {vpiScaledRealTime, 0, 0, 0}; + static s_vpi_value value_s = {.format = vpiBinStrVal}; + + static s_cb_data cb_data_s = { + cbEndOfCompile, // end of compile + (void *)sim_endofcompile_callback, + NULL, + &time_s, + &value_s, + 0, + NULL + }; + + cb_data_s.obj = NULL; /* trigger object */ + + cb_data_s.user_data = NULL; + + // actual call to register the callback + vpi_register_cb(&cb_data_s); +} + +void sim_finish_callback(void) +{ + if(connfd) + printf("Closing RSP server\n"); + close(connfd); + close(listenfd); +} + +void setup_finish_callbacks(void) +{ + // here we setup and install callbacks for + // simulation finish + + static s_vpi_time time_s = {vpiScaledRealTime, 0, 0, 0}; + static s_vpi_value value_s = {.format = vpiBinStrVal}; + + static s_cb_data cb_data_s = { + cbEndOfSimulation, // end of simulation + (void *)sim_finish_callback, + NULL, + &time_s, + &value_s, + 0, + NULL + }; + + cb_data_s.obj = NULL; /* trigger object */ + cb_data_s.user_data = NULL; + + // actual call to register the callback + vpi_register_cb(&cb_data_s); +} + +#ifndef VCS_VPI +// Register the new system task here +void (*vlog_startup_routines[])(void) = { +#ifdef CDS_VPI + // this installs a callback on simulator reset - something which + // icarus does not do, so we only do it for cadence currently + setup_reset_callbacks, +#endif + setup_endofcompile_callbacks, + setup_finish_callbacks, + register_check_for_command, + register_send_result_to_server, + 0 // last entry must be 0 +}; + +// Entry point for testing development of the vpi functions +int main(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + + return 0; +} +#endif diff --git a/openocd b/openocd new file mode 160000 index 00000000..e70bd48b --- /dev/null +++ b/openocd @@ -0,0 +1 @@ +Subproject commit e70bd48baa604ca7e823e87c18fb5f366de9c607 diff --git a/src/main/scala/DebugTransport.scala b/src/main/scala/DebugTransport.scala new file mode 100644 index 00000000..199b6809 --- /dev/null +++ b/src/main/scala/DebugTransport.scala @@ -0,0 +1,124 @@ +package rocketchip + +import Chisel._ +import uncore.devices.{DebugBusIO, AsyncDebugBusTo, AsyncDebugBusFrom, DebugBusReq, DebugBusResp, DMKey} +import junctions._ +import cde.{Parameters} + +/* JTAG-based Debug Transport Module + * and synchronization logic. + * + * This implements JTAG interface described + * in the RISC-V Debug Specification + * + * This Module is currently a + * wrapper around a number of black-boxed + * modules. The black-boxing is due to the fact that + * Chisel doesn't currently support: + * - Negative Edge Clocking + * - Asynchronous Resets + * (The tristate requirements of JTAG are exported from the + * Chisel domain with the DRV_TDO signal). + * + * The AsyncDebugBus parameter here is overloaded. + * The DebugTransportModule JTAG definately needs a synchronizer, + * the parameter just currently selects whether the Chisel-generated + * crossing is used or the black-boxed crossing is used. + * Although Top is also capable of generating the + * Chisel sychnronizers, it is done here for consistency + * of keeping the synchronizers in one place when + * instantiating the DTM. + * + */ + +class JtagDTMWithSync(implicit val p: Parameters) extends Module { + + // IO <-> [Chisel Sync?] <-> [DebugBusIO<->UInt] <-> [Black Box Sync?] <-> DTM Black Box + + val io = new Bundle { + + val jtag = new JtagIO(true).flip() + val debug = new DebugBusIO()(p) + + } + + val req_width = io.debug.req.bits.getWidth + val resp_width = io.debug.resp.bits.getWidth + + val jtag_dtm = Module (new DebugTransportModuleJtag(req_width, resp_width)) + + jtag_dtm.io.jtag <> io.jtag + + val dtm_req = Wire(new DecoupledIO(UInt(width = req_width))) + val dtm_resp = Wire(new DecoupledIO(UInt(width = resp_width))) + + val io_debug_bus = Wire (new DebugBusIO) + + // Optionally instantiate the Chisel synchronizers. + // These go on this side of the DebugBusIO->UInt translation + // because the Chisel synchronizers understand these data structures. + if (p(AsyncDebugBus)){ + io.debug <> AsyncDebugBusFrom(io.jtag.TCK, io.jtag.TRST, io_debug_bus) + } else { + io.debug <> io_debug_bus + } + + // Translate from straight 'bits' interface of the blackboxes + // into the Resp/Req data structures. + io_debug_bus.req.valid := dtm_req.valid + io_debug_bus.req.bits := new DebugBusReq(p(DMKey).nDebugBusAddrSize).fromBits(dtm_req.bits) + dtm_req.ready := io_debug_bus.req.ready + + dtm_resp.valid := io_debug_bus.resp.valid + dtm_resp.bits := io_debug_bus.resp.bits.asUInt + io_debug_bus.resp.ready := dtm_resp.ready + + // Optionally instantiate the black-box synchronizers + // instead of the chisel ones. + // These go on this side of the DebugBusIO->UInt translation + // because they do not understand the DebugBusIO data structures. + + if (p(AsyncDebugBus)) { + dtm_req <> jtag_dtm.io.dtm_req + jtag_dtm.io.dtm_resp <> dtm_resp + } else { + val req_sync = Module (new AsyncMailbox()) + val resp_sync = Module (new AsyncMailbox()) + req_sync.io.enq := jtag_dtm.io.dtm_req + req_sync.io.enq_clock.get := io.jtag.TCK + req_sync.io.enq_reset.get := io.jtag.TRST + req_sync.io.deq_clock.get := clock + req_sync.io.deq_reset.get := reset + dtm_req := req_sync.io.deq + + jtag_dtm.io.dtm_resp := resp_sync.io.deq + resp_sync.io.deq_clock.get := io.jtag.TCK + resp_sync.io.deq_reset.get := io.jtag.TRST + resp_sync.io.enq_clock.get := clock + resp_sync.io.enq_reset.get := reset + resp_sync.io.enq := dtm_resp + } +} + +class DebugTransportModuleJtag(reqSize : Int, respSize : Int)(implicit val p: Parameters) extends BlackBox { + + val io = new Bundle { + val jtag = new JtagIO(true).flip() + + val dtm_req = new DecoupledIO(UInt(width = reqSize)) + + val dtm_resp = new DecoupledIO(UInt(width = respSize)).flip() + + } + +} + +class AsyncMailbox extends BlackBox { + + // This Verilog module is parameterized, but until this is supported by Chisel, + // this mailbox just has a fixed width of 64 bits, which is enough + // for our specific purpose here. + + val io = new Crossing(UInt(width=64), true, true) + +} diff --git a/src/main/scala/rocketchip/Configs.scala b/src/main/scala/rocketchip/Configs.scala index 9b425b1a..30aef92e 100644 --- a/src/main/scala/rocketchip/Configs.scala +++ b/src/main/scala/rocketchip/Configs.scala @@ -122,6 +122,7 @@ class BasePlatformConfig extends Config ( case BuildCoreplex => (p: Parameters) => Module(new DefaultCoreplex(p)) case NExtInterrupts => 2 case AsyncDebugBus => false + case IncludeJtagDTM => false case AsyncMMIOChannels => false case ExtraDevices => Nil case ExtraTopPorts => (p: Parameters) => new Bundle @@ -277,4 +278,18 @@ class WithTestRAM extends Config( } Seq(new TestRAMDevice) } - }) + } +) + +class WithAsyncDebug extends Config ( + (pname, site, here) => pname match { + case AsyncDebugBus => true + } +) + + +class WithJtagDTM extends Config ( + (pname, site, here) => pname match { + case IncludeJtagDTM => true + } +) diff --git a/src/main/scala/rocketchip/RocketChip.scala b/src/main/scala/rocketchip/RocketChip.scala index ce7cb4ba..d22e1609 100644 --- a/src/main/scala/rocketchip/RocketChip.scala +++ b/src/main/scala/rocketchip/RocketChip.scala @@ -87,9 +87,10 @@ class TopIO(implicit p: Parameters) extends BasicTopIO()(p) { val mmio_axi = Vec(p(NExtMMIOAXIChannels), new NastiIO) val mmio_ahb = Vec(p(NExtMMIOAHBChannels), new HastiMasterIO) val mmio_tl = Vec(p(NExtMMIOTLChannels), new ClientUncachedTileLinkIO()(outermostMMIOParams)) - val debug_clk = if (p(AsyncDebugBus)) Some(Clock(INPUT)) else None - val debug_rst = if (p(AsyncDebugBus)) Some(Bool(INPUT)) else None - val debug = new DebugBusIO()(p).flip + val debug_clk = if (p(AsyncDebugBus) & !p(IncludeJtagDTM)) Some(Clock(INPUT)) else None + val debug_rst = if (p(AsyncDebugBus) & !p(IncludeJtagDTM)) Some(Bool(INPUT)) else None + val debug = if (!p(IncludeJtagDTM)) Some(new DebugBusIO()(p).flip) else None + val jtag = if ( p(IncludeJtagDTM)) Some(new JtagIO(true).flip) else None val extra = p(ExtraTopPorts)(p) } @@ -137,10 +138,18 @@ class Top(topParams: Parameters) extends Module with HasTopLevelParameters { periphery.io.mem_in <> coreplex.io.mem coreplex.io.ext_clients <> periphery.io.clients_out - coreplex.io.debug <> + if (p(IncludeJtagDTM)) { + // JtagDTMWithSync is a wrapper which + // handles the synchronization as well. + val jtag_dtm = Module (new JtagDTMWithSync()(p)) + jtag_dtm.io.jtag <> io.jtag.get + coreplex.io.debug <> jtag_dtm.io.debug + } else { + coreplex.io.debug <> (if (p(AsyncDebugBus)) - AsyncDebugBusFrom(io.debug_clk.get, io.debug_rst.get, io.debug) - else io.debug) + AsyncDebugBusFrom(io.debug_clk.get, io.debug_rst.get, io.debug.get) + else io.debug.get) + } def asyncAxiTo(clocks: Seq[Clock], resets: Seq[Bool], inner_axis: Seq[NastiIO]): Seq[NastiIO] = (clocks, resets, inner_axis).zipped.map { diff --git a/src/main/scala/rocketchip/TestHarness.scala b/src/main/scala/rocketchip/TestHarness.scala index c976f4eb..fcc6833f 100644 --- a/src/main/scala/rocketchip/TestHarness.scala +++ b/src/main/scala/rocketchip/TestHarness.scala @@ -6,6 +6,7 @@ import Chisel._ import cde.{Parameters, Field} import rocket.Util._ import junctions._ +import uncore.devices.{IncludeJtagDTM} class TestHarness(implicit p: Parameters) extends Module { val io = new Bundle { @@ -26,9 +27,6 @@ class TestHarness(implicit p: Parameters) extends Module { require(dut.io.mmio_axi.isEmpty) require(dut.io.mmio_ahb.isEmpty) require(dut.io.mmio_tl.isEmpty) - require(dut.io.debug_clk.isEmpty) - require(dut.io.debug_rst.isEmpty) - require(dut.io.debug_rst.isEmpty) require(dut.io.extra.elements.isEmpty) for (int <- dut.io.interrupts) @@ -41,14 +39,42 @@ class TestHarness(implicit p: Parameters) extends Module { Module(new SimAXIMem(memSize / dut.io.mem_axi.size)).io.axi <> axi } - val dtm = Module(new SimDTM) - dut.io.debug <> dtm.io.debug - dtm.io.clk := clock - dtm.io.reset := reset - io.success := dut.io.success.getOrElse(dtm.io.exit === 1) - when (dtm.io.exit >= 2) { - printf("*** FAILED *** (exit code = %d)\n", dtm.io.exit >> 1) - stop(1) + if (p(IncludeJtagDTM)) { + val jtag_vpi = Module (new JtagVpi) + dut.io.jtag.get <> jtag_vpi.io.jtag + + // To be proper, + // TRST should really be synchronized + // with TCK. But this is a fairly + // accurate representation of how + // HW may drive this signal. + // Neither OpenOCD nor JtagVPI drive TRST. + + dut.io.jtag.get.TRST := reset + jtag_vpi.io.enable := ~reset + jtag_vpi.io.init_done := ~reset + io.success := Bool(false) + } + else { + val dtm = Module(new SimDTM) + dut.io.debug.get <> dtm.io.debug + + // Todo: enable the usage of different clocks. + + val dtm_clock = clock + val dtm_reset = reset + dtm.io.clk := dtm_clock + dtm.io.reset := dtm_reset + if (dut.io.debug_clk.isDefined) + dut.io.debug_clk.get := dtm_clock + if (dut.io.debug_rst.isDefined) + dut.io.debug_rst.get := dtm_reset + + io.success := dut.io.success.getOrElse(dtm.io.exit === 1) + when (dtm.io.exit >= 2) { + printf("*** FAILED *** (exit code = %d)\n", dtm.io.exit >> 1) + stop(1) + } } } @@ -114,3 +140,13 @@ class SimDTM(implicit p: Parameters) extends BlackBox { val exit = UInt(OUTPUT, 32) } } + + +class JtagVpi(implicit val p: Parameters) extends BlackBox { + + val io = new Bundle { + val jtag = new JtagIO(false) + val enable = Bool(INPUT) + val init_done = Bool(INPUT) + } +} diff --git a/src/main/scala/uncore/devices/Debug.scala b/src/main/scala/uncore/devices/Debug.scala index 531fa6a1..cc787f30 100644 --- a/src/main/scala/uncore/devices/Debug.scala +++ b/src/main/scala/uncore/devices/Debug.scala @@ -8,7 +8,7 @@ import uncore.util._ import junctions._ import cde.{Parameters, Config, Field} -// ***************************************** +// *****************************************r // Constants which are interesting even // outside of this module // ***************************************** @@ -264,7 +264,7 @@ class DefaultDebugModuleConfig (val ncomponents : Int, val xlen:Int) nNDResetCycles = 1) case object DMKey extends Field[DebugModuleConfig] - +case object IncludeJtagDTM extends Field[Boolean] // ***************************************** // Module Interfaces @@ -277,8 +277,8 @@ case object DMKey extends Field[DebugModuleConfig] class DebugBusReq(addrBits : Int) extends Bundle { val addr = UInt(width = addrBits) - val op = UInt(width = DbBusConsts.dbOpSize) val data = UInt(width = DbBusConsts.dbDataSize) + val op = UInt(width = DbBusConsts.dbOpSize) override def cloneType = new DebugBusReq(addrBits).asInstanceOf[this.type] } @@ -287,8 +287,9 @@ class DebugBusReq(addrBits : Int) extends Bundle { /** Structure to define the contents of a Debug Bus Response */ class DebugBusResp( ) extends Bundle { - val resp = UInt(width = DbBusConsts.dbRespSize) val data = UInt(width = DbBusConsts.dbDataSize) + val resp = UInt(width = DbBusConsts.dbRespSize) + } /** Structure to define the top-level DebugBus interface @@ -999,3 +1000,5 @@ object AsyncDebugBusTo { // OutsideClockDomain sink } } + + diff --git a/vsim/Makefrag b/vsim/Makefrag index 2a129ee8..0461ef5f 100644 --- a/vsim/Makefrag +++ b/vsim/Makefrag @@ -4,16 +4,22 @@ # Verilog sources +bb_vsrcs = $(base_dir)/vsrc/DebugTransportModuleJtag.v \ + $(base_dir)/vsrc/jtag_vpi.v \ + $(base_dir)/vsrc/AsyncMailbox.v + sim_vsrcs = \ $(generated_dir)/$(MODEL).$(CONFIG).v \ $(generated_dir)/consts.$(CONFIG).vh \ - $(base_dir)/vsrc/$(TB).v \ + $(base_dir)/vsrc/$(TB).v \ $(base_dir)/vsrc/SimDTM.v \ + $(bb_vsrcs) # C sources sim_csrcs = \ $(base_dir)/csrc/SimDTM.cc \ + $(base_dir)/csrc/jtag_vpi.c #-------------------------------------------------------------------- # Build Verilog @@ -45,6 +51,11 @@ VCS_OPTS = -notice -line +lint=all,noVCDE,noONGS,noUI -error=PCWM-L -timescale=1 +define+RANDOMIZE \ +libext+.v \ +VCS_OPTS += +vpi +VCS_OPTS += -P $(base_dir)/vsrc/jtag_vpi.tab +VCS_OPTS += -CC "-DVCS_VPI" + + #-------------------------------------------------------------------- # Build the simulator #-------------------------------------------------------------------- diff --git a/vsrc/AsyncFifo.v b/vsrc/AsyncFifo.v new file mode 100644 index 00000000..4539b843 --- /dev/null +++ b/vsrc/AsyncFifo.v @@ -0,0 +1,271 @@ + + +module AsyncFifo ( + // Write Interface + + enq_clock + , enq_reset + , enq_ready + , enq_valid + , enq_bits + + // Read Interface + , deq_clock + , deq_reset + , deq_ready + , deq_valid + , deq_bits + + ); + + + //-------------------------------------------------------- + // Parameter Declarations + + parameter DEPTH_LG_2 = 0; // default is 'mailbox'. + parameter WIDTH = 64; + + localparam DEPTH = 2**DEPTH_LG_2; + + //-------------------------------------------------------- + // I/O Declarations + + // Write Interface + input enq_clock; + wire w_clock = enq_clock; + + input enq_reset; + wire w_reset = enq_reset; + + output enq_ready; + wire w_ready; + assign enq_ready = w_ready; + + input enq_valid; + wire w_valid = enq_valid; + + input [WIDTH - 1 : 0 ] enq_bits; + wire [WIDTH - 1 : 0 ] w_bits = enq_bits; + + // Read Interface + input deq_clock; + wire r_clock = deq_clock; + + input deq_reset; + wire r_reset = deq_reset; + + output deq_valid; + wire r_valid; + assign deq_valid = r_valid; + + input deq_ready; + wire r_ready = deq_ready; + + output [WIDTH - 1 : 0] deq_bits; + wire [WIDTH - 1 : 0] r_bits; + assign deq_bits = r_bits; + + //-------------------------------------------------------- + // FIFO Memory Declaration + + generate + if (DEPTH > 1) begin : mem1_scope + reg [WIDTH - 1 : 0] fifoMem [ 0 : DEPTH - 1]; + end else begin : mem2_scope + reg [WIDTH - 1 :0] fifoMem; + end + endgenerate + + //-------------------------------------------------------- + // Reg and Wire Declarations + + wire w_full; + wire w_fire; + + wire r_empty; + wire r_fire; + + + // Read & Write Address Pointers + generate + if (DEPTH_LG_2 > 0) begin : reg1_scope + reg [DEPTH_LG_2 : 0 ] w_wrAddrReg; + wire [DEPTH_LG_2 : 0] w_wrAddrNxt; + reg [DEPTH_LG_2 : 0 ] w_wrAddrGrayReg; + wire [DEPTH_LG_2 : 0] w_wrAddrGrayNxt; + + reg [DEPTH_LG_2 : 0 ] r_rdAddrReg; + wire [DEPTH_LG_2 : 0] r_rdAddrNxt; + reg [DEPTH_LG_2 : 0 ] r_rdAddrGrayReg; + wire [DEPTH_LG_2 : 0] r_rdAddrGrayNxt; + + reg [DEPTH_LG_2 : 0 ] wrAddrGrayReg_sync; + reg [DEPTH_LG_2 : 0 ] rdAddrGrayReg_sync; + + reg [DEPTH_LG_2 : 0 ] r_wrAddrGrayReg; + reg [DEPTH_LG_2 : 0 ] w_rdAddrGrayReg; + end else begin : reg2_scope + + reg w_wrAddrReg; + wire w_wrAddrNxt; + reg r_rdAddrReg; + wire r_rdAddrNxt; + + + reg wrAddrReg_sync; + reg rdAddrReg_sync; + + reg r_wrAddrReg; + reg w_rdAddrReg; + end + endgenerate + + //-------------------------------------------------------- + // Reg and Wire Declarations + + + // Pointer Logic + generate + if (DEPTH_LG_2 > 0) begin : ptr_logic_scope + assign w_full = ~(reg1_scope.w_wrAddrGrayReg[DEPTH_LG_2] == reg1_scope.w_rdAddrGrayReg[DEPTH_LG_2]) & + (reg1_scope.w_wrAddrGrayReg[DEPTH_LG_2 - 1 : 0] == reg1_scope.w_rdAddrGrayReg[DEPTH_LG_2 - 1 : 0 ]); + + assign reg1_scope.w_wrAddrNxt = reg1_scope.w_wrAddrReg + 1'b1; // OK / expected to overflow + assign reg1_scope.w_wrAddrGrayNext = reg1_scope.w_wrAddrNxt ^ (reg1_scope.w_wrAddrNxt >> 1); + + assign reg1_scope.r_rdAddrNxt = reg1_scope.r_rdAddrReg + 1'b1; // OK / expected to overflow + assign reg1_scope.r_rdAddrGrayNext = reg1_scope.r_rdAddrNxt ^ (reg1_scope.r_rdAddrNxt >> 1); + + assign r_empty = (reg1_scope.r_wrAddrGrayReg == reg1_scope.r_rdAddrGrayReg); + + end else begin : ptr_logic_scope + assign w_full = ~(reg2_scope.w_wrAddrReg == reg2_scope.r_rdAddrReg); + + assign reg2_scope.w_wrAddrNxt = ~reg2_scope.w_wrAddrReg ; + + assign reg2_scope.r_rdAddrNxt = ~reg2_scope.r_rdAddrReg; + + assign r_empty = (reg2_scope.r_wrAddrReg == reg2_scope.r_rdAddrReg); + + end + endgenerate + + assign w_ready = ~w_full; + assign w_fire = w_ready & w_valid; + + // Read Logic + assign r_valid = ~r_empty; + assign r_fire = r_ready & r_valid; + + generate + if (DEPTH > 1) begin : rw_scope1 + if (DEPTH > 2) begin : rw_scope2 + + assign r_bits = mem1_scope.fifoMem[reg1_scope.r_rdAddrReg[DEPTH_LG_2-1:0]]; + + always @(posedge w_clock) begin + if (w_fire) begin + mem1_scope.fifoMem[reg1_scope.w_wrAddrReg[DEPTH_LG_2-1:0]] <= w_bits; + end + end + + end else begin + + assign r_bits = mem1_scope.fifoMem[reg1_scope.r_rdAddrReg[0]]; + + always @(posedge w_clock) begin + if (w_fire) begin + mem1_scope.fifoMem[reg1_scope.w_wrAddrReg[0]] <= w_bits; + end + end + + end + end else begin + + assign r_bits = mem2_scope.fifoMem; + + always @(posedge w_clock) begin + if (w_fire) begin + mem2_scope.fifoMem <= w_bits; + end + end + + end + endgenerate + + //-------------------------------------------------------- + // Sequential logic + // + generate + if (DEPTH_LG_2 > 0) begin : seq1_scope + always @(posedge w_clock or posedge w_reset) begin + if (w_reset) begin + reg1_scope.w_wrAddrReg <= 'b0; + reg1_scope.w_wrAddrGrayReg <= 'b0; + + reg1_scope.rdAddrGrayReg_sync <= 'b0; + reg1_scope.w_rdAddrGrayReg <= 'b0; + end else begin + if (w_fire) begin + reg1_scope.w_wrAddrReg <= reg1_scope.w_wrAddrNxt; + reg1_scope.w_wrAddrGrayReg <= reg1_scope.w_wrAddrGrayNxt; + end + reg1_scope.rdAddrGrayReg_sync <= reg1_scope.r_rdAddrGrayReg; + reg1_scope.w_rdAddrGrayReg <= reg1_scope.rdAddrGrayReg_sync; + end + end + + always @(posedge r_clock or posedge r_reset) begin + if (r_reset) begin + reg1_scope.r_rdAddrReg <= 'b0; + reg1_scope.r_rdAddrGrayReg <= 'b0; + + reg1_scope.reg1_scope.wrAddrGrayReg_sync <= 'b0; + reg1_scope.reg1_scope.r_wrAddrGrayReg <= 'b0; + end else begin + if (r_fire) begin + reg1_scope.r_rdAddrReg <= reg1_scope.r_rdAddrNxt; + reg1_scope.r_rdAddrGrayReg <= reg1_scope.r_rdAddrGrayNxt; + end + reg1_scope.wrAddrGrayReg_sync <= reg1_scope.w_wrAddrGrayReg; + reg1_scope.r_wrAddrGrayReg <= reg1_scope.wrAddrGrayReg_sync; + end + end // always @ (posedge r_clock) + + end else begin : seq2_scope // block: seq1_scope + always @(posedge w_clock or posedge w_reset) begin + if (w_reset ) begin + reg2_scope.w_wrAddrReg <= 1'b0; + + reg2_scope.rdAddrReg_sync <= 1'b0; + reg2_scope.w_rdAddrReg <= 1'b0; + end else begin + if (w_fire) begin + reg2_scope.w_wrAddrReg <= reg2_scope.w_wrAddrNxt; + end + reg2_scope.rdAddrReg_sync <= reg2_scope.r_rdAddrReg; + reg2_scope.w_rdAddrReg <= reg2_scope.rdAddrReg_sync; + end + end + + always @(posedge r_clock or posedge r_reset) begin + if (r_reset) begin + reg2_scope.r_rdAddrReg <= 1'b0; + + reg2_scope.wrAddrReg_sync <= 1'b0; + reg2_scope.r_wrAddrReg <= 1'b0; + end else begin + if (r_fire) begin + reg2_scope.r_rdAddrReg <= reg2_scope.r_rdAddrNxt; + end + reg2_scope.wrAddrReg_sync <= reg2_scope.w_wrAddrReg; + reg2_scope.r_wrAddrReg <= reg2_scope.wrAddrReg_sync; + end + end // always @ (posedge r_clock) + end // block: seq2_scope + +endgenerate + + + +endmodule // AsyncFifo diff --git a/vsrc/DebugTransportModuleJtag.v b/vsrc/DebugTransportModuleJtag.v new file mode 100755 index 00000000..0c8a07b0 --- /dev/null +++ b/vsrc/DebugTransportModuleJtag.v @@ -0,0 +1,301 @@ + + +module DebugTransportModuleJtag ( + + //JTAG Interface + + jtag_TDI, + jtag_TDO, + jtag_TCK, + jtag_TMS, + jtag_TRST, + + jtag_DRV_TDO, + + dtm_req_valid, + dtm_req_ready, + dtm_req_bits, + + dtm_resp_valid, + dtm_resp_ready, + dtm_resp_bits + + ); + //-------------------------------------------------------- + // Parameter Declarations + + parameter DEBUG_DATA_BITS = 34; + parameter DEBUG_ADDR_BITS = 5; // Spec allows values are 5-7 + parameter DEBUG_OP_BITS = 2; // OP and RESP are the same size. + + parameter JTAG_VERSION = 4'h1; + parameter JTAG_PART_NUM = 16'h0E31; // E31 + parameter JTAG_MANUF_ID = 11'h489; // As Assigned by JEDEC + + localparam IR_BITS = 5; + + localparam DEBUG_VERSION = 0; + + // JTAG State Machine + localparam TEST_LOGIC_RESET = 4'h0; + localparam RUN_TEST_IDLE = 4'h1; + localparam SELECT_DR = 4'h2; + localparam CAPTURE_DR = 4'h3; + localparam SHIFT_DR = 4'h4; + localparam EXIT1_DR = 4'h5; + localparam PAUSE_DR = 4'h6; + localparam EXIT2_DR = 4'h7; + localparam UPDATE_DR = 4'h8; + localparam SELECT_IR = 4'h9; + localparam CAPTURE_IR = 4'hA; + localparam SHIFT_IR = 4'hB; + localparam EXIT1_IR = 4'hC; + localparam PAUSE_IR = 4'hD; + localparam EXIT2_IR = 4'hE; + localparam UPDATE_IR = 4'hF; + + //RISCV DTM Registers (see RISC-V Debug Specification) + // All others are treated as 'BYPASS'. + localparam REG_BYPASS = 5'b11111; + localparam REG_IDCODE = 5'b00001; + localparam REG_DEBUG_ACCESS = 5'b10001; + localparam REG_DTM_INFO = 5'b10000; + + localparam DBUS_REG_BITS = DEBUG_OP_BITS + DEBUG_ADDR_BITS + DEBUG_DATA_BITS; + localparam DBUS_REQ_BITS = DEBUG_OP_BITS + DEBUG_ADDR_BITS + DEBUG_DATA_BITS; + localparam DBUS_RESP_BITS = DEBUG_OP_BITS + DEBUG_DATA_BITS; + + + localparam SHIFT_REG_BITS = DBUS_REG_BITS; + + //-------------------------------------------------------- + // I/O Declarations + + //JTAG SIDE + input jtag_TDI; + output reg jtag_TDO; + input jtag_TCK; + input jtag_TMS; + input jtag_TRST; + + + // To allow tri-state outside of this block. + output reg jtag_DRV_TDO; + + // RISC-V Core Side + + output dtm_req_valid; + input dtm_req_ready; + output [DBUS_REQ_BITS - 1 :0] dtm_req_bits; + + input dtm_resp_valid; + output dtm_resp_ready; + input [DBUS_RESP_BITS - 1 : 0] dtm_resp_bits; + + //-------------------------------------------------------- + // Reg and Wire Declarations + + reg [IR_BITS -1 : 0 ] irReg; + + wire [31:0] idcode; + wire [31:0] dtminfo; + reg [DBUS_REG_BITS - 1 : 0] dbusReg; + reg dbusValidReg; + + reg [3:0] jtagStateReg; + + reg [SHIFT_REG_BITS -1 : 0] shiftReg; + + reg doDbusWriteReg; + reg doDbusReadReg; + + reg busyReg; + reg skipOpReg; // Skip op because we're busy. + reg downgradeOpReg; // Downgrade op because prev. op failed. + + + wire busy; + wire nonzeroResp; + + wire [SHIFT_REG_BITS -1 : 0] busyResponse; + wire [SHIFT_REG_BITS -1 : 0] nonbusyResponse; + + //-------------------------------------------------------- + // Combo Logic + + assign idcode = {JTAG_VERSION, JTAG_PART_NUM, JTAG_MANUF_ID, 1'h1}; + + wire [3:0] debugAddrBits = DEBUG_ADDR_BITS; + wire [3:0] debugVersion = DEBUG_VERSION; + + assign dtminfo = {24'b0, debugAddrBits, debugVersion}; + + //busy, dtm_resp* is only valid during CAPTURE_DR, + // so these signals should only be used at that time. + // This assumes there is only one transaction in flight at a time. + assign busy = busyReg & ~dtm_resp_valid; + // This is needed especially for the first request. + assign nonzeroResp = dtm_resp_valid ? |{dtm_resp_bits[DEBUG_OP_BITS-1:0]} : 1'b0; + + // Interface to DM. + // Note that this means dtm_resp_bits must only be used during CAPTURE_DR. + assign dtm_resp_ready = (jtagStateReg == CAPTURE_DR) && + (irReg == REG_DEBUG_ACCESS) && + dtm_resp_valid; + + assign dtm_req_valid = dbusValidReg; + assign dtm_req_bits = dbusReg; + + assign busyResponse = {{(DEBUG_ADDR_BITS + DEBUG_DATA_BITS){1'b0}}, + {(DEBUG_OP_BITS){1'b1}}}; // Generalizing 'busy' to 'all-1' + + assign nonbusyResponse = {dbusReg[(DEBUG_DATA_BITS + DEBUG_OP_BITS) +: DEBUG_ADDR_BITS] , // retain address bits from Req. + dtm_resp_bits[DEBUG_OP_BITS +: DEBUG_DATA_BITS] , // data + dtm_resp_bits[0 +: DEBUG_OP_BITS] // response + }; + + //-------------------------------------------------------- + // Sequential Logic + + // JTAG STATE MACHINE + + always @(posedge jtag_TCK or posedge jtag_TRST) begin + if (jtag_TRST) begin + jtagStateReg <= TEST_LOGIC_RESET; + end else begin + case (jtagStateReg) + TEST_LOGIC_RESET : jtagStateReg <= jtag_TMS ? TEST_LOGIC_RESET : RUN_TEST_IDLE; + RUN_TEST_IDLE : jtagStateReg <= jtag_TMS ? SELECT_DR : RUN_TEST_IDLE; + SELECT_DR : jtagStateReg <= jtag_TMS ? SELECT_IR : CAPTURE_DR; + CAPTURE_DR : jtagStateReg <= jtag_TMS ? EXIT1_DR : SHIFT_DR; + SHIFT_DR : jtagStateReg <= jtag_TMS ? EXIT1_DR : SHIFT_DR; + EXIT1_DR : jtagStateReg <= jtag_TMS ? UPDATE_DR : PAUSE_DR; + PAUSE_DR : jtagStateReg <= jtag_TMS ? EXIT2_DR : PAUSE_DR; + EXIT2_DR : jtagStateReg <= jtag_TMS ? UPDATE_DR : SHIFT_DR; + UPDATE_DR : jtagStateReg <= jtag_TMS ? SELECT_DR : RUN_TEST_IDLE; + SELECT_IR : jtagStateReg <= jtag_TMS ? TEST_LOGIC_RESET : CAPTURE_IR; + CAPTURE_IR : jtagStateReg <= jtag_TMS ? EXIT1_IR : SHIFT_IR; + SHIFT_IR : jtagStateReg <= jtag_TMS ? EXIT1_IR : SHIFT_IR; + EXIT1_IR : jtagStateReg <= jtag_TMS ? UPDATE_IR : PAUSE_IR; + PAUSE_IR : jtagStateReg <= jtag_TMS ? EXIT2_IR : PAUSE_IR; + EXIT2_IR : jtagStateReg <= jtag_TMS ? UPDATE_IR : SHIFT_IR; + UPDATE_IR : jtagStateReg <= jtag_TMS ? SELECT_DR : RUN_TEST_IDLE; + endcase // case (jtagStateReg) + end // else: !if(jtag_TRST) + end // always @ (posedge jtag_TCK or posedge jtag_TRST) + + // SHIFT REG + always @(posedge jtag_TCK) begin + case (jtagStateReg) + CAPTURE_IR : shiftReg <= {{(SHIFT_REG_BITS-1){1'b0}}, 1'b1}; //JTAG spec only says must end with 'b01. + SHIFT_IR : shiftReg <= {{(SHIFT_REG_BITS-IR_BITS){1'b0}}, jtag_TDI, shiftReg[IR_BITS-1 : 1]}; + CAPTURE_DR : case (irReg) + REG_BYPASS : shiftReg <= {(SHIFT_REG_BITS){1'b0}}; + REG_IDCODE : shiftReg <= {{(SHIFT_REG_BITS-32){1'b0}}, idcode}; + REG_DTM_INFO : shiftReg <= {{(SHIFT_REG_BITS-32){1'b0}}, dtminfo}; + REG_DEBUG_ACCESS : shiftReg <= busy ? busyResponse : nonbusyResponse; + default : //BYPASS + shiftReg <= {(SHIFT_REG_BITS){1'b0}}; + endcase + SHIFT_DR : case (irReg) + REG_BYPASS : shiftReg <= {{(SHIFT_REG_BITS- 1){1'b0}}, jtag_TDI}; + REG_IDCODE : shiftReg <= {{(SHIFT_REG_BITS-32){1'b0}}, jtag_TDI, shiftReg[31:1]}; + REG_DTM_INFO : shiftReg <= {{(SHIFT_REG_BITS-32){1'b0}}, jtag_TDI, shiftReg[31:1]}; + REG_DEBUG_ACCESS : shiftReg <= {jtag_TDI, shiftReg[SHIFT_REG_BITS -1 : 1 ]}; + default: // BYPASS + shiftReg <= {{(SHIFT_REG_BITS- 1){1'b0}} , jtag_TDI}; + endcase // case (irReg) + endcase // case (jtagStateReg) + end + + // IR + always @(negedge jtag_TCK or posedge jtag_TRST) begin + if (jtag_TRST) begin + irReg <= REG_IDCODE; + end else if (jtagStateReg == TEST_LOGIC_RESET) begin + irReg <= REG_IDCODE; + end else if (jtagStateReg == UPDATE_IR) begin + irReg <= shiftReg[IR_BITS-1:0]; + end + end + + // Busy. We become busy when we first try to send a request. + // We stop being busy when we accept a response. + // This means that busyReg will still be set when we check it, + // so the logic for checking busy looks ahead. + + always @(posedge jtag_TCK or posedge jtag_TRST) begin + if (jtag_TRST) begin + busyReg <= 1'b0; + end else if (dtm_req_valid) begin //UPDATE_DR onwards + busyReg <= 1'b1; + end else if (dtm_resp_valid & dtm_resp_ready) begin //only in CAPTURE_DR + busyReg <= 1'b0; + end + end // always @ (posedge jtag_TCK or posedge jtag_TRST) + + + // Downgrade/Skip. We make the decision to downgrade or skip + // during every CAPTURE_DR, and use the result in UPDATE_DR. + always @(posedge jtag_TCK or posedge jtag_TRST) begin + if (jtag_TRST) begin + skipOpReg <= 1'b0; + downgradeOpReg <= 1'b0; + end else if (irReg == REG_DEBUG_ACCESS) begin + case(jtagStateReg) + CAPTURE_DR: begin + skipOpReg <= busy; + downgradeOpReg <= (~busy & nonzeroResp); + end + UPDATE_DR: begin + skipOpReg <= 1'b0; + downgradeOpReg <= 1'b0; + end + endcase // case (jtagStateReg) + end + end // always @ (posedge jtag_TCK or posedge jtag_TRST) + + + //dbusReg, dbusValidReg. + always @(posedge jtag_TCK or posedge jtag_TRST) begin + if (jtag_TRST) begin + dbusReg <= {(DBUS_REG_BITS) {1'b0}}; + dbusValidReg <= 1'b0; + end else if (jtagStateReg == UPDATE_DR) begin + if (irReg == REG_DEBUG_ACCESS) begin + if (skipOpReg) begin + // do nothing. + end else if (downgradeOpReg) begin + dbusReg <= {(DBUS_REG_BITS){1'b0}}; // NOP has encoding 2'b00. + dbusValidReg <= 1'b1; + end else begin + dbusReg <= shiftReg[DBUS_REG_BITS-1:0]; + dbusValidReg <= 1'b1; + end + end + end else if (dtm_req_ready) begin + dbusValidReg <= 1'b0; + end + end // always @ (negedge jtag_TCK or posedge jtag_TRST) + + //TDO + always @(negedge jtag_TCK or posedge jtag_TRST) begin + if (jtag_TRST) begin + jtag_TDO <= 1'b0; + jtag_DRV_TDO <= 1'b0; + end else if (jtagStateReg == SHIFT_IR) begin + jtag_TDO <= shiftReg[0]; + jtag_DRV_TDO <= 1'b1; + end else if (jtagStateReg == SHIFT_DR) begin + jtag_TDO <= shiftReg[0]; + jtag_DRV_TDO <= 1'b1; + end else begin + jtag_TDO <= 1'b0; + jtag_DRV_TDO <= 1'b0; + end + end // always @ (negedge jtag_TCK or posedge jtag_TRST) + + +endmodule + + diff --git a/vsrc/jtag_vpi.tab b/vsrc/jtag_vpi.tab new file mode 100644 index 00000000..c042ce05 --- /dev/null +++ b/vsrc/jtag_vpi.tab @@ -0,0 +1,2 @@ +$send_result_to_server call=send_result_to_server +$check_for_command call=check_for_command \ No newline at end of file diff --git a/vsrc/jtag_vpi.v b/vsrc/jtag_vpi.v new file mode 100644 index 00000000..78571153 --- /dev/null +++ b/vsrc/jtag_vpi.v @@ -0,0 +1,302 @@ +/* + * TCP/IP controlled VPI JTAG Interface. + * Based on Julius Baxter's work on jp_vpi.c + * + * Copyright (C) 2012 Franck Jullien, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of any + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +`define CMD_RESET 0 +`define CMD_TMS_SEQ 1 +`define CMD_SCAN_CHAIN 2 +`define CMD_SCAN_CHAIN_FLIP_TMS 3 +`define CMD_STOP_SIMU 4 + +module JtagVpi +#( parameter DEBUG_INFO = 0, + parameter TP = 1, + parameter TCK_HALF_PERIOD = 2,// 50, // Clock half period (Clock period = 100 ns => 10 MHz) + parameter CMD_DELAY = 2 // 1000 +) +( + output jtag_TMS, + output jtag_TCK, + output jtag_TDI, + input jtag_TDO, + input jtag_TRST, // unused + input enable, + input init_done); + + reg tms; + reg tck; + reg tdi; + wire tdo; + + assign jtag_TMS = tms; + assign jtag_TCK = tck; + assign jtag_TDI = tdi; + assign tdo = jtag_TDO; + + +integer cmd; +integer length; +integer nb_bits; + +reg [31:0] buffer_out [0:4095]; // Data storage from the jtag server +reg [31:0] buffer_in [0:4095]; // Data storage to the jtag server + +integer flip_tms; + +reg [31:0] data_out; +reg [31:0] data_in; + +integer debug; + +assign tms_o = tms; +assign tck_o = tck; +assign tdi_o = tdi; + +initial +begin + tck <= #TP 1'b0; + tdi <= #TP 1'bz; + tms <= #TP 1'b0; + + data_out <= 32'h0; + data_in <= 32'h0; + + // Insert a #delay here because we need to + // wait until the PC isn't pointing to flash anymore + // (this is around 20k ns if the flash_crash boot code + // is being booted from, else much bigger, around 10mil ns) + wait(init_done) + if($test$plusargs("jtag_vpi_enable")) main; +end + +task main; +begin + $display("JTAG debug module with VPI interface enabled\n"); + + reset_tap; + goto_run_test_idle_from_reset; + + while (1) begin + + // Check for incoming command + // wait until a command is sent + // poll with a delay here + cmd = -1; + + while (cmd == -1) + begin + #CMD_DELAY $check_for_command(cmd, length, nb_bits, buffer_out); + end + + // now switch on the command + case (cmd) + + `CMD_RESET : + begin + if (DEBUG_INFO) + $display("%t ----> CMD_RESET %h\n", $time, length); + reset_tap; + goto_run_test_idle_from_reset; + end + + `CMD_TMS_SEQ : + begin + if (DEBUG_INFO) + $display("%t ----> CMD_TMS_SEQ\n", $time); + do_tms_seq; + end + + `CMD_SCAN_CHAIN : + begin + if (DEBUG_INFO) + $display("%t ----> CMD_SCAN_CHAIN\n", $time); + flip_tms = 0; + do_scan_chain; + $send_result_to_server(length, buffer_in); + end + + `CMD_SCAN_CHAIN_FLIP_TMS : + begin + if(DEBUG_INFO) + $display("%t ----> CMD_SCAN_CHAIN\n", $time); + flip_tms = 1; + do_scan_chain; + $send_result_to_server(length, buffer_in); + end + + `CMD_STOP_SIMU : + begin + if(DEBUG_INFO) + $display("%t ----> End of simulation\n", $time); + $finish(); + end + + default: + begin + $display("Somehow got to the default case in the command case statement."); + $display("Command was: %x", cmd); + $display("Exiting..."); + $finish(); + end + + endcase // case (cmd) + + end // while (1) +end + +endtask // main + + +// Generation of the TCK signal +task gen_clk; +input [31:0] number; +integer i; + +begin + for (i = 0; i < number; i = i + 1) + begin + #TCK_HALF_PERIOD tck <= 1; + #TCK_HALF_PERIOD tck <= 0; + end +end + +endtask + +// TAP reset +task reset_tap; +begin + if (DEBUG_INFO) + $display("(%0t) Task reset_tap", $time); + tms <= #1 1'b1; + gen_clk(5); +end + +endtask + + +// Goes to RunTestIdle state +task goto_run_test_idle_from_reset; +begin + if (DEBUG_INFO) + $display("(%0t) Task goto_run_test_idle_from_reset", $time); + tms <= #1 1'b0; + gen_clk(1); +end + +endtask + +// +task do_tms_seq; + +integer i,j; +reg [31:0] data; +integer nb_bits_rem; +integer nb_bits_in_this_byte; + +begin + if (DEBUG_INFO) + $display("(%0t) Task do_tms_seq of %d bits (length = %d)", $time, nb_bits, length); + + // Number of bits to send in the last byte + nb_bits_rem = nb_bits % 8; + + for (i = 0; i < length; i = i + 1) + begin + // If we are in the last byte, we have to send only + // nb_bits_rem bits. If not, we send the whole byte. + nb_bits_in_this_byte = (i == (length - 1)) ? nb_bits_rem : 8; + + data = buffer_out[i]; + for (j = 0; j < nb_bits_in_this_byte; j = j + 1) + begin + tms <= #1 1'b0; + if (data[j] == 1) begin + tms <= #1 1'b1; + end + gen_clk(1); + end + end + + tms <= #1 1'b0; +end + +endtask + + +// +task do_scan_chain; + +integer _bit; +integer nb_bits_rem; +integer nb_bits_in_this_byte; +integer index; + +begin + if(DEBUG_INFO) + $display("(%0t) Task do_scan_chain of %d bits (length = %d)", $time, nb_bits, length); + + // Number of bits to send in the last byte + nb_bits_rem = nb_bits % 8; + + for (index = 0; index < length; index = index + 1) + begin + // If we are in the last byte, we have to send only + // nb_bits_rem bits if it's not zero. + // If not, we send the whole byte. + nb_bits_in_this_byte = (index == (length - 1)) ? ((nb_bits_rem == 0) ? 8 : nb_bits_rem) : 8; + + data_out = buffer_out[index]; + for (_bit = 0; _bit < nb_bits_in_this_byte; _bit = _bit + 1) + begin + tdi <= 1'b0; + if (data_out[_bit] == 1'b1) begin + tdi <= 1'b1; + end + + // On the last bit, set TMS to '1' + if (((_bit == (nb_bits_in_this_byte - 1)) && (index == (length - 1))) && (flip_tms == 1)) begin + tms <= 1'b1; + end + + #TCK_HALF_PERIOD tck <= 1; + data_in[_bit] <= tdo; + #TCK_HALF_PERIOD tck <= 0; + end + buffer_in[index] = data_in; + end + + tdi <= 1'b0; + tms <= 1'b0; +end + +endtask + +endmodule diff --git a/vsrc/rocketDTMTestHarness.v b/vsrc/rocketDTMTestHarness.v new file mode 100644 index 00000000..db72cd7c --- /dev/null +++ b/vsrc/rocketDTMTestHarness.v @@ -0,0 +1,293 @@ +// See LICENSE for license details. + +extern "A" void memory_tick +( + input reg [31:0] channel, + + input reg ar_valid, + output reg ar_ready, + input reg [`MEM_ADDR_BITS-1:0] ar_addr, + input reg [`MEM_ID_BITS-1:0] ar_id, + input reg [2:0] ar_size, + input reg [7:0] ar_len, + + input reg aw_valid, + output reg aw_ready, + input reg [`MEM_ADDR_BITS-1:0] aw_addr, + input reg [`MEM_ID_BITS-1:0] aw_id, + input reg [2:0] aw_size, + input reg [7:0] aw_len, + + input reg w_valid, + output reg w_ready, + input reg [`MEM_STRB_BITS-1:0] w_strb, + input reg [`MEM_DATA_BITS-1:0] w_data, + input reg w_last, + + output reg r_valid, + input reg r_ready, + output reg [1:0] r_resp, + output reg [`MEM_ID_BITS-1:0] r_id, + output reg [`MEM_DATA_BITS-1:0] r_data, + output reg r_last, + + output reg b_valid, + input reg b_ready, + output reg [1:0] b_resp, + output reg [`MEM_ID_BITS-1:0] b_id +); + +module rocketDTMTestHarness; + + reg [31:0] seed; + initial seed = $get_initial_random_seed(); + + //----------------------------------------------- + // Instantiate the processor + + reg clk = 1'b0; + reg reset = 1'b1; + reg r_reset = 1'b1; + reg start = 1'b0; + + always #`CLOCK_PERIOD clk = ~clk; + + reg [ 31:0] n_mem_channel = `N_MEM_CHANNELS; + reg [ 31:0] mem_width = `MEM_DATA_BITS; + reg [ 63:0] max_cycles = 0; + reg [ 63:0] trace_count = 0; + reg [1023:0] loadmem = 0; + reg [1023:0] vcdplusfile = 0; + reg [1023:0] vcdfile = 0; + reg verbose = 0; + wire printf_cond = verbose && !reset; + integer stderr = 32'h80000002; + +`include `TBVFRAG + + + + always @(posedge clk) + begin + r_reset <= reset; + end + + reg [31:0] exit = 0; + + //----------------------------------------------- + // Instantiate DTM and Synchronizers + + // JTAG Interface + + wire debug_TDI; + wire debug_TDO; + wire debug_TCK; + wire debug_TMS; + wire debug_TRST; + wire debug_DRV_TDO; + + //================================================= + // JTAG VPI Server + + wire cheater_TCK; + + + jtag_vpi #( + .DEBUG_INFO(0), + //parameter TP = 1, + .TCK_HALF_PERIOD(5), + .CMD_DELAY(10) +) // Clock half period (Clock period = 10 ns => 100 MHz) + jtag_vpi ( + .tms(debug_TMS), + .tck(debug_TCK), + .tdi(debug_TDI), + .tdo(debug_TDO), + .enable(~reset), + .init_done(~reset) + ); + + + //================================================= + // DTM <-> Synchronizers Interface + + localparam DEBUG_ADDR_BITS = 5; + localparam DEBUG_DATA_BITS = 34; + localparam DEBUG_OP_BITS = 2; + + + wire dtm_req_ready; + wire dtm_req_valid; + wire [DEBUG_OP_BITS + DEBUG_ADDR_BITS + DEBUG_DATA_BITS - 1 : 0 ] dtm_req_data; + + wire dtm_resp_ready; + wire dtm_resp_valid; + wire [DEBUG_OP_BITS + DEBUG_DATA_BITS - 1 :0 ] dtm_resp_data; + + + DebugTransportModuleJtag #(.DEBUG_OP_BITS(DEBUG_OP_BITS), + .DEBUG_ADDR_BITS(DEBUG_ADDR_BITS), + .DEBUG_DATA_BITS(DEBUG_DATA_BITS) + ) debugTransportModuleJtag0 ( + + //JTAG Interface + + .TDI(debug_TDI), + .TDO(debug_TDO), + .TCK(debug_TCK), + .TMS(debug_TMS), + .TRST(debug_TRST), + + .DRV_TDO(debug_DRV_TDO), + + .dtm_req_ready(dtm_req_ready), + .dtm_req_valid(dtm_req_valid), + .dtm_req_data(dtm_req_data), + + .dtm_resp_ready(dtm_resp_ready), + .dtm_resp_valid(dtm_resp_valid), + .dtm_resp_data(dtm_resp_data) + + ); + +`ifdef VERILOG_DEBUG_SYNC + + AsyncFifo #(.DEPTH_LG_2(0), + .WIDTH(DEBUG_OP_BITS + DEBUG_ADDR_BITS + DEBUG_DATA_BITS)) + debugBusReqFifo( + // Write Interface + + .clk_w(~debug_TCK), + .reset_w(debug_TRST), + .ready_w(dtm_req_ready), + .valid_w(dtm_req_valid), + .data_w(dtm_req_data), + + .clk_r(clk), + .reset_r(reset), + .ready_r(debug_req_ready), + .valid_r(debug_req_valid), + .data_r({debug_req_bits_addr, debug_req_bits_data, debug_req_bits_op}) + + ); + + AsyncFifo #(.DEPTH_LG_2(0), + .WIDTH(DEBUG_OP_BITS + DEBUG_DATA_BITS)) + debugBusRespFifo( + .clk_w(clk), + .reset_w(reset), + .ready_w(debug_resp_ready), + .valid_w(debug_resp_valid), + .data_w({debug_resp_bits_data, debug_resp_bits_resp}), + + .clk_r(debug_TCK), + .reset_r(debug_TRST), + .ready_r(dtm_resp_ready), + .valid_r(dtm_resp_valid), + .data_r(dtm_resp_data) + ); + + + // This is cheating / potentially incorrect!!! It needs to be more + // clearly specified as to what the behavior of TRST is. + assign debug_TRST = reset; + + // The TCK cheat is not needed for this side of the ifdef + // because both DTM and synchronizer + // logic is asynchronously reset as needed. + +`else // !`ifdef VERILOG_DEBUG_SYNC + + // This is cheating / potentially incorrect!!! It needs to be more + // clearly specified as to what the behavior of TRST is. + assign debug_TRST = reset; + + // This is TOTAL cheating!!! The synchronizer + // logic should be asynchronously reset, or we should + // specify the TCK/TRST requirements for a synchronous reset. + assign debug_clk = reset ? clk : debug_TCK; + + assign debug_reset = debug_TRST; + + assign debug_req_valid = dtm_req_valid; + assign {debug_req_bits_addr, debug_req_bits_data, debug_req_bits_op} = dtm_req_data; + + assign dtm_req_ready = debug_req_ready; + + assign dtm_resp_valid = debug_resp_valid; + assign dtm_resp_data = {debug_resp_bits_data, debug_resp_bits_resp}; + + assign debug_resp_ready = dtm_resp_ready; + +`endif // !`ifdef VERILOG_DEBUG_SYNC + + + + //----------------------------------------------- + // Start the simulation + + // Read input arguments and initialize + initial + begin + $value$plusargs("max-cycles=%d", max_cycles); + verbose = $test$plusargs("verbose"); +`ifdef DEBUG + if ($value$plusargs("vcdplusfile=%s", vcdplusfile)) + begin + $vcdplusfile(vcdplusfile); + $vcdpluson(0); + $vcdplusmemon(0); + end + + if ($value$plusargs("vcdfile=%s", vcdfile)) + begin + $dumpfile(vcdfile); + $dumpvars(0, dut); + $dumpon; + end +`define VCDPLUSCLOSE $vcdplusclose; $dumpoff; +`else +`define VCDPLUSCLOSE +`endif + + // Strobe reset + #777.7 reset = 0; + + end + + reg [255:0] reason = 0; + always @(posedge clk) + begin + if (max_cycles > 0 && trace_count > max_cycles) + reason = "timeout"; + if (exit > 1) + $sformat(reason, "tohost = %d", exit >> 1); + + if (reason) + begin + $fdisplay(stderr, "*** FAILED *** (%s) after %d simulation cycles", reason, trace_count); + `VCDPLUSCLOSE + $fatal; + end + + if (exit == 1) + begin + if (verbose) + $fdisplay(stderr, "Completed after %d simulation cycles", trace_count); + `VCDPLUSCLOSE + $finish; + end + end + + always @(posedge clk) + begin + trace_count = trace_count + 1; +`ifdef GATE_LEVEL + if (verbose) + begin + $fdisplay(stderr, "C: %10d", trace_count-1); + end +`endif + end + +endmodule From 3dd51ff7341a99a9b26f7341a63fb92a8748f42a Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Fri, 19 Aug 2016 14:01:33 -0700 Subject: [PATCH 2/9] This commit adds Logic & test support for JTAG implementation of Debug Transport Module. - The DebugTransportModuleJtag is written in Verilog. It probably could be written in Chisel except for some negative edge clocking requirement. - For real implementations, the AsyncDebugBusTo/From is insufficient. This commit includes cases where they are used, but because they are not reset asynchronously, a Verilog 'AsyncMailbox' is used when p(AsyncDebug) is false. - This commit differs significantly from the earlier attempt. Now, the DTM and synchronizer is instantiated within Top, as it is a real piece of hardware (vs. test infrastructure). -TestHarness takes a parameter vs. creating an entirely new TestHarness class. It does not make sense to instantiate TestHarness when p(IncludeJtagDTM) is false, and it would not make sense to insantiate some other TestHarness if p(IncludeJtagDTM) is true. To build Verilog which includes the JtagDTM within Top: make CONFIG=WithJtagDTM_... To test using gdb->OpenOCD->jtag_vpi->Verilog: First, install openocd (included in this commit) ./bootstrap ./configure --prefix=$OPENOCD --enable-jtag-vpi make make install Then to run a simulation: On a 32-bit core: $(ROCKETCHIP)/riscv-tools/riscv-tests/debug/gdbserver.py \ --run ./simv-TestHarness-WithJtagDTM_... \ --cmd="$OPENOCD/bin/openocd --s $OPENOCD/share/openocd/scripts/" \ --freedom-e300-sim \ SimpleRegisterTest.test_s0 On a 64-bit core: $(ROCKETCHIP)/riscv-tools/riscv-tests/debug/gdbserver.py \ --run ./simv-TestHarness-WithJtagDTM_... \ --cmd="$OPENOCD/bin/openocd --s $OPENOCD/share/openocd/scripts/" \ --freedom-u500-sim \ SimpleRegisterTest.test_s0 --- src/main/scala/DebugTransport.scala | 4 +- src/main/scala/rocketchip/TestHarness.scala | 9 +- src/main/scala/uncore/devices/Debug.scala | 3 +- vsrc/AsyncFifo.v | 271 -------------------- vsrc/AsyncMailbox.v | 154 +++++++++++ 5 files changed, 164 insertions(+), 277 deletions(-) delete mode 100644 vsrc/AsyncFifo.v create mode 100644 vsrc/AsyncMailbox.v diff --git a/src/main/scala/DebugTransport.scala b/src/main/scala/DebugTransport.scala index 199b6809..169cf6f2 100644 --- a/src/main/scala/DebugTransport.scala +++ b/src/main/scala/DebugTransport.scala @@ -3,7 +3,9 @@ package rocketchip import Chisel._ import uncore.devices.{DebugBusIO, AsyncDebugBusTo, AsyncDebugBusFrom, DebugBusReq, DebugBusResp, DMKey} import junctions._ -import cde.{Parameters} +import cde.{Parameters, Field} + +case object IncludeJtagDTM extends Field[Boolean] /* JTAG-based Debug Transport Module * and synchronization logic. diff --git a/src/main/scala/rocketchip/TestHarness.scala b/src/main/scala/rocketchip/TestHarness.scala index fcc6833f..e51fa03e 100644 --- a/src/main/scala/rocketchip/TestHarness.scala +++ b/src/main/scala/rocketchip/TestHarness.scala @@ -6,7 +6,6 @@ import Chisel._ import cde.{Parameters, Field} import rocket.Util._ import junctions._ -import uncore.devices.{IncludeJtagDTM} class TestHarness(implicit p: Parameters) extends Module { val io = new Bundle { @@ -53,16 +52,20 @@ class TestHarness(implicit p: Parameters) extends Module { dut.io.jtag.get.TRST := reset jtag_vpi.io.enable := ~reset jtag_vpi.io.init_done := ~reset + + // Success is determined by the gdbserver + // which is controlling this simulation. io.success := Bool(false) } else { val dtm = Module(new SimDTM) dut.io.debug.get <> dtm.io.debug - // Todo: enable the usage of different clocks. - + // Todo: enable the usage of different clocks + // to test the synchronizer more aggressively. val dtm_clock = clock val dtm_reset = reset + dtm.io.clk := dtm_clock dtm.io.reset := dtm_reset if (dut.io.debug_clk.isDefined) diff --git a/src/main/scala/uncore/devices/Debug.scala b/src/main/scala/uncore/devices/Debug.scala index cc787f30..7443c9ac 100644 --- a/src/main/scala/uncore/devices/Debug.scala +++ b/src/main/scala/uncore/devices/Debug.scala @@ -8,7 +8,7 @@ import uncore.util._ import junctions._ import cde.{Parameters, Config, Field} -// *****************************************r +// ***************************************** // Constants which are interesting even // outside of this module // ***************************************** @@ -264,7 +264,6 @@ class DefaultDebugModuleConfig (val ncomponents : Int, val xlen:Int) nNDResetCycles = 1) case object DMKey extends Field[DebugModuleConfig] -case object IncludeJtagDTM extends Field[Boolean] // ***************************************** // Module Interfaces diff --git a/vsrc/AsyncFifo.v b/vsrc/AsyncFifo.v deleted file mode 100644 index 4539b843..00000000 --- a/vsrc/AsyncFifo.v +++ /dev/null @@ -1,271 +0,0 @@ - - -module AsyncFifo ( - // Write Interface - - enq_clock - , enq_reset - , enq_ready - , enq_valid - , enq_bits - - // Read Interface - , deq_clock - , deq_reset - , deq_ready - , deq_valid - , deq_bits - - ); - - - //-------------------------------------------------------- - // Parameter Declarations - - parameter DEPTH_LG_2 = 0; // default is 'mailbox'. - parameter WIDTH = 64; - - localparam DEPTH = 2**DEPTH_LG_2; - - //-------------------------------------------------------- - // I/O Declarations - - // Write Interface - input enq_clock; - wire w_clock = enq_clock; - - input enq_reset; - wire w_reset = enq_reset; - - output enq_ready; - wire w_ready; - assign enq_ready = w_ready; - - input enq_valid; - wire w_valid = enq_valid; - - input [WIDTH - 1 : 0 ] enq_bits; - wire [WIDTH - 1 : 0 ] w_bits = enq_bits; - - // Read Interface - input deq_clock; - wire r_clock = deq_clock; - - input deq_reset; - wire r_reset = deq_reset; - - output deq_valid; - wire r_valid; - assign deq_valid = r_valid; - - input deq_ready; - wire r_ready = deq_ready; - - output [WIDTH - 1 : 0] deq_bits; - wire [WIDTH - 1 : 0] r_bits; - assign deq_bits = r_bits; - - //-------------------------------------------------------- - // FIFO Memory Declaration - - generate - if (DEPTH > 1) begin : mem1_scope - reg [WIDTH - 1 : 0] fifoMem [ 0 : DEPTH - 1]; - end else begin : mem2_scope - reg [WIDTH - 1 :0] fifoMem; - end - endgenerate - - //-------------------------------------------------------- - // Reg and Wire Declarations - - wire w_full; - wire w_fire; - - wire r_empty; - wire r_fire; - - - // Read & Write Address Pointers - generate - if (DEPTH_LG_2 > 0) begin : reg1_scope - reg [DEPTH_LG_2 : 0 ] w_wrAddrReg; - wire [DEPTH_LG_2 : 0] w_wrAddrNxt; - reg [DEPTH_LG_2 : 0 ] w_wrAddrGrayReg; - wire [DEPTH_LG_2 : 0] w_wrAddrGrayNxt; - - reg [DEPTH_LG_2 : 0 ] r_rdAddrReg; - wire [DEPTH_LG_2 : 0] r_rdAddrNxt; - reg [DEPTH_LG_2 : 0 ] r_rdAddrGrayReg; - wire [DEPTH_LG_2 : 0] r_rdAddrGrayNxt; - - reg [DEPTH_LG_2 : 0 ] wrAddrGrayReg_sync; - reg [DEPTH_LG_2 : 0 ] rdAddrGrayReg_sync; - - reg [DEPTH_LG_2 : 0 ] r_wrAddrGrayReg; - reg [DEPTH_LG_2 : 0 ] w_rdAddrGrayReg; - end else begin : reg2_scope - - reg w_wrAddrReg; - wire w_wrAddrNxt; - reg r_rdAddrReg; - wire r_rdAddrNxt; - - - reg wrAddrReg_sync; - reg rdAddrReg_sync; - - reg r_wrAddrReg; - reg w_rdAddrReg; - end - endgenerate - - //-------------------------------------------------------- - // Reg and Wire Declarations - - - // Pointer Logic - generate - if (DEPTH_LG_2 > 0) begin : ptr_logic_scope - assign w_full = ~(reg1_scope.w_wrAddrGrayReg[DEPTH_LG_2] == reg1_scope.w_rdAddrGrayReg[DEPTH_LG_2]) & - (reg1_scope.w_wrAddrGrayReg[DEPTH_LG_2 - 1 : 0] == reg1_scope.w_rdAddrGrayReg[DEPTH_LG_2 - 1 : 0 ]); - - assign reg1_scope.w_wrAddrNxt = reg1_scope.w_wrAddrReg + 1'b1; // OK / expected to overflow - assign reg1_scope.w_wrAddrGrayNext = reg1_scope.w_wrAddrNxt ^ (reg1_scope.w_wrAddrNxt >> 1); - - assign reg1_scope.r_rdAddrNxt = reg1_scope.r_rdAddrReg + 1'b1; // OK / expected to overflow - assign reg1_scope.r_rdAddrGrayNext = reg1_scope.r_rdAddrNxt ^ (reg1_scope.r_rdAddrNxt >> 1); - - assign r_empty = (reg1_scope.r_wrAddrGrayReg == reg1_scope.r_rdAddrGrayReg); - - end else begin : ptr_logic_scope - assign w_full = ~(reg2_scope.w_wrAddrReg == reg2_scope.r_rdAddrReg); - - assign reg2_scope.w_wrAddrNxt = ~reg2_scope.w_wrAddrReg ; - - assign reg2_scope.r_rdAddrNxt = ~reg2_scope.r_rdAddrReg; - - assign r_empty = (reg2_scope.r_wrAddrReg == reg2_scope.r_rdAddrReg); - - end - endgenerate - - assign w_ready = ~w_full; - assign w_fire = w_ready & w_valid; - - // Read Logic - assign r_valid = ~r_empty; - assign r_fire = r_ready & r_valid; - - generate - if (DEPTH > 1) begin : rw_scope1 - if (DEPTH > 2) begin : rw_scope2 - - assign r_bits = mem1_scope.fifoMem[reg1_scope.r_rdAddrReg[DEPTH_LG_2-1:0]]; - - always @(posedge w_clock) begin - if (w_fire) begin - mem1_scope.fifoMem[reg1_scope.w_wrAddrReg[DEPTH_LG_2-1:0]] <= w_bits; - end - end - - end else begin - - assign r_bits = mem1_scope.fifoMem[reg1_scope.r_rdAddrReg[0]]; - - always @(posedge w_clock) begin - if (w_fire) begin - mem1_scope.fifoMem[reg1_scope.w_wrAddrReg[0]] <= w_bits; - end - end - - end - end else begin - - assign r_bits = mem2_scope.fifoMem; - - always @(posedge w_clock) begin - if (w_fire) begin - mem2_scope.fifoMem <= w_bits; - end - end - - end - endgenerate - - //-------------------------------------------------------- - // Sequential logic - // - generate - if (DEPTH_LG_2 > 0) begin : seq1_scope - always @(posedge w_clock or posedge w_reset) begin - if (w_reset) begin - reg1_scope.w_wrAddrReg <= 'b0; - reg1_scope.w_wrAddrGrayReg <= 'b0; - - reg1_scope.rdAddrGrayReg_sync <= 'b0; - reg1_scope.w_rdAddrGrayReg <= 'b0; - end else begin - if (w_fire) begin - reg1_scope.w_wrAddrReg <= reg1_scope.w_wrAddrNxt; - reg1_scope.w_wrAddrGrayReg <= reg1_scope.w_wrAddrGrayNxt; - end - reg1_scope.rdAddrGrayReg_sync <= reg1_scope.r_rdAddrGrayReg; - reg1_scope.w_rdAddrGrayReg <= reg1_scope.rdAddrGrayReg_sync; - end - end - - always @(posedge r_clock or posedge r_reset) begin - if (r_reset) begin - reg1_scope.r_rdAddrReg <= 'b0; - reg1_scope.r_rdAddrGrayReg <= 'b0; - - reg1_scope.reg1_scope.wrAddrGrayReg_sync <= 'b0; - reg1_scope.reg1_scope.r_wrAddrGrayReg <= 'b0; - end else begin - if (r_fire) begin - reg1_scope.r_rdAddrReg <= reg1_scope.r_rdAddrNxt; - reg1_scope.r_rdAddrGrayReg <= reg1_scope.r_rdAddrGrayNxt; - end - reg1_scope.wrAddrGrayReg_sync <= reg1_scope.w_wrAddrGrayReg; - reg1_scope.r_wrAddrGrayReg <= reg1_scope.wrAddrGrayReg_sync; - end - end // always @ (posedge r_clock) - - end else begin : seq2_scope // block: seq1_scope - always @(posedge w_clock or posedge w_reset) begin - if (w_reset ) begin - reg2_scope.w_wrAddrReg <= 1'b0; - - reg2_scope.rdAddrReg_sync <= 1'b0; - reg2_scope.w_rdAddrReg <= 1'b0; - end else begin - if (w_fire) begin - reg2_scope.w_wrAddrReg <= reg2_scope.w_wrAddrNxt; - end - reg2_scope.rdAddrReg_sync <= reg2_scope.r_rdAddrReg; - reg2_scope.w_rdAddrReg <= reg2_scope.rdAddrReg_sync; - end - end - - always @(posedge r_clock or posedge r_reset) begin - if (r_reset) begin - reg2_scope.r_rdAddrReg <= 1'b0; - - reg2_scope.wrAddrReg_sync <= 1'b0; - reg2_scope.r_wrAddrReg <= 1'b0; - end else begin - if (r_fire) begin - reg2_scope.r_rdAddrReg <= reg2_scope.r_rdAddrNxt; - end - reg2_scope.wrAddrReg_sync <= reg2_scope.w_wrAddrReg; - reg2_scope.r_wrAddrReg <= reg2_scope.wrAddrReg_sync; - end - end // always @ (posedge r_clock) - end // block: seq2_scope - -endgenerate - - - -endmodule // AsyncFifo diff --git a/vsrc/AsyncMailbox.v b/vsrc/AsyncMailbox.v new file mode 100644 index 00000000..4460e9bf --- /dev/null +++ b/vsrc/AsyncMailbox.v @@ -0,0 +1,154 @@ + + +module AsyncMailbox ( + // Write Interface + + enq_clock + , enq_reset + , enq_ready + , enq_valid + , enq_bits + + // Read Interface + , deq_clock + , deq_reset + , deq_ready + , deq_valid + , deq_bits + + ); + + + //-------------------------------------------------------- + // Parameter Declarations + + parameter WIDTH = 64; + + //-------------------------------------------------------- + // I/O Declarations + + // Write Interface + input enq_clock; + wire w_clock = enq_clock; + + input enq_reset; + wire w_reset = enq_reset; + + output enq_ready; + wire w_ready; + assign enq_ready = w_ready; + + input enq_valid; + wire w_valid = enq_valid; + + input [WIDTH - 1 : 0 ] enq_bits; + wire [WIDTH - 1 : 0 ] w_bits = enq_bits; + + // Read Interface + input deq_clock; + wire r_clock = deq_clock; + + input deq_reset; + wire r_reset = deq_reset; + + output deq_valid; + wire r_valid; + assign deq_valid = r_valid; + + input deq_ready; + wire r_ready = deq_ready; + + output [WIDTH - 1 : 0] deq_bits; + wire [WIDTH - 1 : 0] r_bits; + assign deq_bits = r_bits; + + //-------------------------------------------------------- + // FIFO Memory Declaration + + reg [WIDTH - 1 :0] mailboxReg; + + //-------------------------------------------------------- + // Reg and Wire Declarations + + wire w_full; + wire w_fire; + + wire r_empty; + wire r_fire; + + + // Read & Write Address Pointers + reg w_wrAddrReg; + wire w_wrAddrNxt; + reg r_rdAddrReg; + wire r_rdAddrNxt; + + + reg wrAddrReg_sync; + reg rdAddrReg_sync; + + reg r_wrAddrReg; + reg w_rdAddrReg; + + //-------------------------------------------------------- + // Reg and Wire Declarations + + assign w_full = ~(w_wrAddrReg == r_rdAddrReg); + + assign w_wrAddrNxt = ~w_wrAddrReg ; + + assign r_rdAddrNxt = ~r_rdAddrReg; + + assign r_empty = (r_wrAddrReg == r_rdAddrReg); + + assign w_ready = ~w_full; + assign w_fire = w_ready & w_valid; + + // Read Logic + assign r_valid = ~r_empty; + assign r_fire = r_ready & r_valid; + + + assign r_bits = mailboxReg; + + always @(posedge w_clock) begin + if (w_fire) begin + mailboxReg <= w_bits; + end + end + + //-------------------------------------------------------- + // Sequential logic + // + + always @(posedge w_clock or posedge w_reset) begin + if (w_reset ) begin + w_wrAddrReg <= 1'b0; + + rdAddrReg_sync <= 1'b0; + w_rdAddrReg <= 1'b0; + end else begin + if (w_fire) begin + w_wrAddrReg <= w_wrAddrNxt; + end + rdAddrReg_sync <= r_rdAddrReg; + w_rdAddrReg <= rdAddrReg_sync; + end + end + + always @(posedge r_clock or posedge r_reset) begin + if (r_reset) begin + r_rdAddrReg <= 1'b0; + + wrAddrReg_sync <= 1'b0; + r_wrAddrReg <= 1'b0; + end else begin + if (r_fire) begin + r_rdAddrReg <= r_rdAddrNxt; + end + wrAddrReg_sync <= w_wrAddrReg; + r_wrAddrReg <= wrAddrReg_sync; + end + end // always @ (posedge r_clock) + +endmodule // AsyncMailbox From 66a253a0db93802367850ff779bce8dd8dd4771a Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Fri, 19 Aug 2016 14:18:51 -0700 Subject: [PATCH 3/9] Remove unncessary file --- vsrc/rocketDTMTestHarness.v | 293 ------------------------------------ 1 file changed, 293 deletions(-) delete mode 100644 vsrc/rocketDTMTestHarness.v diff --git a/vsrc/rocketDTMTestHarness.v b/vsrc/rocketDTMTestHarness.v deleted file mode 100644 index db72cd7c..00000000 --- a/vsrc/rocketDTMTestHarness.v +++ /dev/null @@ -1,293 +0,0 @@ -// See LICENSE for license details. - -extern "A" void memory_tick -( - input reg [31:0] channel, - - input reg ar_valid, - output reg ar_ready, - input reg [`MEM_ADDR_BITS-1:0] ar_addr, - input reg [`MEM_ID_BITS-1:0] ar_id, - input reg [2:0] ar_size, - input reg [7:0] ar_len, - - input reg aw_valid, - output reg aw_ready, - input reg [`MEM_ADDR_BITS-1:0] aw_addr, - input reg [`MEM_ID_BITS-1:0] aw_id, - input reg [2:0] aw_size, - input reg [7:0] aw_len, - - input reg w_valid, - output reg w_ready, - input reg [`MEM_STRB_BITS-1:0] w_strb, - input reg [`MEM_DATA_BITS-1:0] w_data, - input reg w_last, - - output reg r_valid, - input reg r_ready, - output reg [1:0] r_resp, - output reg [`MEM_ID_BITS-1:0] r_id, - output reg [`MEM_DATA_BITS-1:0] r_data, - output reg r_last, - - output reg b_valid, - input reg b_ready, - output reg [1:0] b_resp, - output reg [`MEM_ID_BITS-1:0] b_id -); - -module rocketDTMTestHarness; - - reg [31:0] seed; - initial seed = $get_initial_random_seed(); - - //----------------------------------------------- - // Instantiate the processor - - reg clk = 1'b0; - reg reset = 1'b1; - reg r_reset = 1'b1; - reg start = 1'b0; - - always #`CLOCK_PERIOD clk = ~clk; - - reg [ 31:0] n_mem_channel = `N_MEM_CHANNELS; - reg [ 31:0] mem_width = `MEM_DATA_BITS; - reg [ 63:0] max_cycles = 0; - reg [ 63:0] trace_count = 0; - reg [1023:0] loadmem = 0; - reg [1023:0] vcdplusfile = 0; - reg [1023:0] vcdfile = 0; - reg verbose = 0; - wire printf_cond = verbose && !reset; - integer stderr = 32'h80000002; - -`include `TBVFRAG - - - - always @(posedge clk) - begin - r_reset <= reset; - end - - reg [31:0] exit = 0; - - //----------------------------------------------- - // Instantiate DTM and Synchronizers - - // JTAG Interface - - wire debug_TDI; - wire debug_TDO; - wire debug_TCK; - wire debug_TMS; - wire debug_TRST; - wire debug_DRV_TDO; - - //================================================= - // JTAG VPI Server - - wire cheater_TCK; - - - jtag_vpi #( - .DEBUG_INFO(0), - //parameter TP = 1, - .TCK_HALF_PERIOD(5), - .CMD_DELAY(10) -) // Clock half period (Clock period = 10 ns => 100 MHz) - jtag_vpi ( - .tms(debug_TMS), - .tck(debug_TCK), - .tdi(debug_TDI), - .tdo(debug_TDO), - .enable(~reset), - .init_done(~reset) - ); - - - //================================================= - // DTM <-> Synchronizers Interface - - localparam DEBUG_ADDR_BITS = 5; - localparam DEBUG_DATA_BITS = 34; - localparam DEBUG_OP_BITS = 2; - - - wire dtm_req_ready; - wire dtm_req_valid; - wire [DEBUG_OP_BITS + DEBUG_ADDR_BITS + DEBUG_DATA_BITS - 1 : 0 ] dtm_req_data; - - wire dtm_resp_ready; - wire dtm_resp_valid; - wire [DEBUG_OP_BITS + DEBUG_DATA_BITS - 1 :0 ] dtm_resp_data; - - - DebugTransportModuleJtag #(.DEBUG_OP_BITS(DEBUG_OP_BITS), - .DEBUG_ADDR_BITS(DEBUG_ADDR_BITS), - .DEBUG_DATA_BITS(DEBUG_DATA_BITS) - ) debugTransportModuleJtag0 ( - - //JTAG Interface - - .TDI(debug_TDI), - .TDO(debug_TDO), - .TCK(debug_TCK), - .TMS(debug_TMS), - .TRST(debug_TRST), - - .DRV_TDO(debug_DRV_TDO), - - .dtm_req_ready(dtm_req_ready), - .dtm_req_valid(dtm_req_valid), - .dtm_req_data(dtm_req_data), - - .dtm_resp_ready(dtm_resp_ready), - .dtm_resp_valid(dtm_resp_valid), - .dtm_resp_data(dtm_resp_data) - - ); - -`ifdef VERILOG_DEBUG_SYNC - - AsyncFifo #(.DEPTH_LG_2(0), - .WIDTH(DEBUG_OP_BITS + DEBUG_ADDR_BITS + DEBUG_DATA_BITS)) - debugBusReqFifo( - // Write Interface - - .clk_w(~debug_TCK), - .reset_w(debug_TRST), - .ready_w(dtm_req_ready), - .valid_w(dtm_req_valid), - .data_w(dtm_req_data), - - .clk_r(clk), - .reset_r(reset), - .ready_r(debug_req_ready), - .valid_r(debug_req_valid), - .data_r({debug_req_bits_addr, debug_req_bits_data, debug_req_bits_op}) - - ); - - AsyncFifo #(.DEPTH_LG_2(0), - .WIDTH(DEBUG_OP_BITS + DEBUG_DATA_BITS)) - debugBusRespFifo( - .clk_w(clk), - .reset_w(reset), - .ready_w(debug_resp_ready), - .valid_w(debug_resp_valid), - .data_w({debug_resp_bits_data, debug_resp_bits_resp}), - - .clk_r(debug_TCK), - .reset_r(debug_TRST), - .ready_r(dtm_resp_ready), - .valid_r(dtm_resp_valid), - .data_r(dtm_resp_data) - ); - - - // This is cheating / potentially incorrect!!! It needs to be more - // clearly specified as to what the behavior of TRST is. - assign debug_TRST = reset; - - // The TCK cheat is not needed for this side of the ifdef - // because both DTM and synchronizer - // logic is asynchronously reset as needed. - -`else // !`ifdef VERILOG_DEBUG_SYNC - - // This is cheating / potentially incorrect!!! It needs to be more - // clearly specified as to what the behavior of TRST is. - assign debug_TRST = reset; - - // This is TOTAL cheating!!! The synchronizer - // logic should be asynchronously reset, or we should - // specify the TCK/TRST requirements for a synchronous reset. - assign debug_clk = reset ? clk : debug_TCK; - - assign debug_reset = debug_TRST; - - assign debug_req_valid = dtm_req_valid; - assign {debug_req_bits_addr, debug_req_bits_data, debug_req_bits_op} = dtm_req_data; - - assign dtm_req_ready = debug_req_ready; - - assign dtm_resp_valid = debug_resp_valid; - assign dtm_resp_data = {debug_resp_bits_data, debug_resp_bits_resp}; - - assign debug_resp_ready = dtm_resp_ready; - -`endif // !`ifdef VERILOG_DEBUG_SYNC - - - - //----------------------------------------------- - // Start the simulation - - // Read input arguments and initialize - initial - begin - $value$plusargs("max-cycles=%d", max_cycles); - verbose = $test$plusargs("verbose"); -`ifdef DEBUG - if ($value$plusargs("vcdplusfile=%s", vcdplusfile)) - begin - $vcdplusfile(vcdplusfile); - $vcdpluson(0); - $vcdplusmemon(0); - end - - if ($value$plusargs("vcdfile=%s", vcdfile)) - begin - $dumpfile(vcdfile); - $dumpvars(0, dut); - $dumpon; - end -`define VCDPLUSCLOSE $vcdplusclose; $dumpoff; -`else -`define VCDPLUSCLOSE -`endif - - // Strobe reset - #777.7 reset = 0; - - end - - reg [255:0] reason = 0; - always @(posedge clk) - begin - if (max_cycles > 0 && trace_count > max_cycles) - reason = "timeout"; - if (exit > 1) - $sformat(reason, "tohost = %d", exit >> 1); - - if (reason) - begin - $fdisplay(stderr, "*** FAILED *** (%s) after %d simulation cycles", reason, trace_count); - `VCDPLUSCLOSE - $fatal; - end - - if (exit == 1) - begin - if (verbose) - $fdisplay(stderr, "Completed after %d simulation cycles", trace_count); - `VCDPLUSCLOSE - $finish; - end - end - - always @(posedge clk) - begin - trace_count = trace_count + 1; -`ifdef GATE_LEVEL - if (verbose) - begin - $fdisplay(stderr, "C: %10d", trace_count-1); - end -`endif - end - -endmodule From 48c5ec3551afe12bb74937e749425991fd3397f8 Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Fri, 19 Aug 2016 15:28:53 -0700 Subject: [PATCH 4/9] add missing jtag file --- junctions/src/main/scala/jtag.scala | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 junctions/src/main/scala/jtag.scala diff --git a/junctions/src/main/scala/jtag.scala b/junctions/src/main/scala/jtag.scala new file mode 100644 index 00000000..aa05c00a --- /dev/null +++ b/junctions/src/main/scala/jtag.scala @@ -0,0 +1,16 @@ +package junctions +import Chisel._ +import cde.{Parameters} + +class JtagIO(drvTdo : Boolean = false) extends Bundle { + + val TCK = Clock(OUTPUT) + val TMS = Bool(OUTPUT) + val TDI = Bool(OUTPUT) + val TDO = Bool(INPUT) + val TRST = Bool(OUTPUT) + + val DRV_TDO = if (drvTdo) Some(Bool(OUTPUT)) else None + override def cloneType = new JtagIO(drvTdo).asInstanceOf[this.type] + +} From 723cc063cb29a52764e7cee5e039a5090210aeab Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Fri, 19 Aug 2016 16:11:41 -0700 Subject: [PATCH 5/9] Move files after the file reorganization --- {junctions/src/main/scala => src/main/scala/junctions}/jtag.scala | 0 src/main/scala/{ => rocketchip}/DebugTransport.scala | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {junctions/src/main/scala => src/main/scala/junctions}/jtag.scala (100%) rename src/main/scala/{ => rocketchip}/DebugTransport.scala (100%) diff --git a/junctions/src/main/scala/jtag.scala b/src/main/scala/junctions/jtag.scala similarity index 100% rename from junctions/src/main/scala/jtag.scala rename to src/main/scala/junctions/jtag.scala diff --git a/src/main/scala/DebugTransport.scala b/src/main/scala/rocketchip/DebugTransport.scala similarity index 100% rename from src/main/scala/DebugTransport.scala rename to src/main/scala/rocketchip/DebugTransport.scala From 75efc7dee779f1c08d5c22575df61b1f707b3660 Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Fri, 19 Aug 2016 16:38:03 -0700 Subject: [PATCH 6/9] JtagIO's DRV_TDO should be an INPUT --- src/main/scala/junctions/jtag.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/junctions/jtag.scala b/src/main/scala/junctions/jtag.scala index aa05c00a..b022ed6e 100644 --- a/src/main/scala/junctions/jtag.scala +++ b/src/main/scala/junctions/jtag.scala @@ -10,7 +10,7 @@ class JtagIO(drvTdo : Boolean = false) extends Bundle { val TDO = Bool(INPUT) val TRST = Bool(OUTPUT) - val DRV_TDO = if (drvTdo) Some(Bool(OUTPUT)) else None + val DRV_TDO = if (drvTdo) Some(Bool(INPUT)) else None override def cloneType = new JtagIO(drvTdo).asInstanceOf[this.type] } From c22c77c7a4ea6fd9d3efe27c7812173c09a66d15 Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Tue, 23 Aug 2016 07:35:48 -0700 Subject: [PATCH 7/9] remove pointer to openOCD --- openocd | 1 - 1 file changed, 1 deletion(-) delete mode 160000 openocd diff --git a/openocd b/openocd deleted file mode 160000 index e70bd48b..00000000 --- a/openocd +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e70bd48baa604ca7e823e87c18fb5f366de9c607 From 32118269c102d45693094ad1ab50132f81940c27 Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Tue, 23 Aug 2016 08:20:52 -0700 Subject: [PATCH 8/9] Remove } introduced in merge --- src/main/scala/rocketchip/TestHarness.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/scala/rocketchip/TestHarness.scala b/src/main/scala/rocketchip/TestHarness.scala index 6a6bb9b7..3e598625 100644 --- a/src/main/scala/rocketchip/TestHarness.scala +++ b/src/main/scala/rocketchip/TestHarness.scala @@ -91,7 +91,6 @@ class TestHarness(implicit p: Parameters) extends Module { slave.io <> mmio_axi } - } } class SimAXIMem(size: BigInt)(implicit p: Parameters) extends Module { From 67467c65f52b23e48ed108cfa6b0559253a962a4 Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Tue, 23 Aug 2016 16:53:50 -0700 Subject: [PATCH 9/9] Add a jtag-dtm-regression target to the regression This doesn't get added to Travis, but this target can be used by other automated testing tools which may want to do further testing on rocket-chip. --- regression/Makefile | 61 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/regression/Makefile b/regression/Makefile index db9e4bea..0b4f34c5 100644 --- a/regression/Makefile +++ b/regression/Makefile @@ -49,6 +49,13 @@ CONFIGS=MemtestConfig MemtestBufferlessConfig MemtestStatelessConfig FancyMemtes UnitTestConfig endif +ifeq ($(SUITE), JtagDtmSuite) +CONFIGS_32=WithJtagDTM_DefaultRV32Config +CONFIGS_64=WithJtagDTM_DefaultConfig +CONFIGS += $(CONFIGS_32) +CONFIGS += $(CONFIGS_64) +endif + # These are the named regression targets. While it's expected you run them in # this order, since there's dependencies for everything it doesn't actually # matter. They're here to make running the various targets from the @@ -182,3 +189,57 @@ stamps/%/emulator-torture-$(TORTURE_CONFIG).stamp: stamps/%/emulator-debug.stamp mkdir -p $(dir $@) $(MAKE) -C $(abspath $(TOP))/torture cnight RTL_CONFIG=$* RISCV=$(abspath $(RISCV)) PATH="$(abspath $(RISCV)/bin:$(PATH))" OPTIONS="-C $(abspath $(TOP)/torture/config/$(TORTURE_CONFIG).config) -p $(abspath $(TORTURE_SAVE_DIR)) -m 30 -t 10" date > $@ + + +# Targets for JTAG DTM full-chain simulation + +OPENOCD_HEAD ?= riscv +OPENOCD_INSTALL ?= $(abspath $(TOP))/openocd-install +OPENOCD_VERSION = $(shell git ls-remote http://github.com/sifive/openocd.git $(OPENOCD_HEAD) | awk '{print $$1}') +OPENOCD_DIR = $(OPENOCD_INSTALL)_$(OPENOCD_VERSION)/ + +$(OPENOCD_DIR)/bin/openocd: + rm -rf openocd + git clone http://github.com/sifive/openocd.git + cd openocd ; \ + git checkout $(OPENOCD_VERSION) ; \ + ./bootstrap ; \ + ./configure --enable-jtag-vpi --prefix=$(OPENOCD_INSTALL)_$(OPENOCD_VERSION) ; \ + make ; \ + make install + +install_openocd: $(OPENOCD_DIR)/bin/openocd + +# If this is defined empty, then all tests would run. +# Running a list of tests is not supported. +JTAG_DTM_TEST ?= SimpleRegisterTest.test_s0 + +stamps/%/jtag-dtm-32-$(JTAG_DTM_TEST).stamp: install_openocd stamps/%/vsim-ndebug.stamp + $(abspath $(TOP))/riscv-tools/riscv-tests/debug/gdbserver.py \ + --run $(abspath $(TOP))/vsim/simv-TestHarness-$* \ + --cmd="$(OPENOCD_DIR)/bin/openocd \ + --s $(OPENOCD_DIR)/share/openocd/scripts" \ + --freedom-e300-sim \ + $(JTAG_DTM_TEST) + date > $@ + +stamps/%/jtag-dtm-64-$(JTAG_DTM_TEST).stamp: install_openocd stamps/%/vsim-ndebug.stamp + $(abspath $(TOP))/riscv-tools/riscv-tests/debug/gdbserver.py \ + --run $(abspath $(TOP))/vsim/simv-TestHarness-$* \ + --cmd="$(OPENOCD_INSTALL)_$(OPENOCD_VERSION)/bin/openocd \ + --s $(OPENOCD_INSTALL)_$(OPENOCD_VERSION)/share/openocd/scripts" \ + --freedom-u500-sim \ + $(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) + +jtag-dtm-tests-32 : $(JTAG_DTM_32_TEST_STAMPS) +jtag-dtm-tests-64 : $(JTAG_DTM_64_TEST_STAMPS) + +# Targets for JTAG DTM full-chain simulation +jtag-dtm-regression: jtag-dtm-tests-32 jtag-dtm-tests-64 + + +