1
0
rocket-chip/src/main/scala/rocketchip/DebugTransport.scala

126 lines
4.0 KiB
Scala
Raw Normal View History

package rocketchip
import Chisel._
import uncore.devices.{DebugBusIO, AsyncDebugBusTo, AsyncDebugBusFrom, DebugBusReq, DebugBusResp, DMKey}
import junctions._
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
2016-08-19 23:01:33 +02:00
import cde.{Parameters, Field}
case object IncludeJtagDTM extends Field[Boolean]
/* 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 := io.jtag.TCK
req_sync.io.enq_reset := io.jtag.TRST
req_sync.io.deq_clock := clock
req_sync.io.deq_reset := reset
dtm_req := req_sync.io.deq
jtag_dtm.io.dtm_resp := resp_sync.io.deq
resp_sync.io.deq_clock := io.jtag.TCK
resp_sync.io.deq_reset := io.jtag.TRST
resp_sync.io.enq_clock := clock
resp_sync.io.enq_reset := 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.
2016-09-14 00:34:56 +02:00
val io = new CrossingIO(UInt(width=64))
}