package rocketchip import Chisel._ import uncore.devices.{DebugBusIO, AsyncDebugBusTo, AsyncDebugBusFrom, DebugBusReq, DebugBusResp, DMKey} import junctions._ 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. val io = new Crossing(UInt(width=64)) }