169 lines
5.3 KiB
Scala
169 lines
5.3 KiB
Scala
// See LICENSE.SiFive for license details.
|
|
|
|
package freechips.rocketchip.devices.debug
|
|
|
|
import Chisel._
|
|
import chisel3.core.{IntParam, Input, Output}
|
|
import freechips.rocketchip.config.{Field, Parameters}
|
|
import freechips.rocketchip.subsystem.HasPeripheryBus
|
|
import freechips.rocketchip.devices.tilelink._
|
|
import freechips.rocketchip.diplomacy._
|
|
import freechips.rocketchip.jtag._
|
|
import freechips.rocketchip.util._
|
|
|
|
/** A knob selecting one of the two possible debug interfaces */
|
|
case object IncludeJtagDTM extends Field[Boolean](false)
|
|
|
|
/** A wrapper bundle containing one of the two possible debug interfaces */
|
|
|
|
class DebugIO(implicit val p: Parameters) extends ParameterizedBundle()(p) with CanHavePSDTestModeIO {
|
|
val clockeddmi = (!p(IncludeJtagDTM)).option(new ClockedDMIIO().flip)
|
|
val systemjtag = (p(IncludeJtagDTM)).option(new SystemJTAGIO)
|
|
val ndreset = Bool(OUTPUT)
|
|
val dmactive = Bool(OUTPUT)
|
|
}
|
|
|
|
/** Either adds a JTAG DTM to system, and exports a JTAG interface,
|
|
* or exports the Debug Module Interface (DMI), based on a global parameter.
|
|
*/
|
|
trait HasPeripheryDebug extends HasPeripheryBus {
|
|
val module: HasPeripheryDebugModuleImp
|
|
|
|
val debug = LazyModule(new TLDebugModule(pbus.beatBytes))
|
|
|
|
pbus.toVariableWidthSlave(Some("Debug")){ debug.node }
|
|
}
|
|
|
|
trait HasPeripheryDebugBundle {
|
|
implicit val p: Parameters
|
|
|
|
val debug: DebugIO
|
|
|
|
def connectDebug(c: Clock,
|
|
r: Bool,
|
|
out: Bool,
|
|
tckHalfPeriod: Int = 2,
|
|
cmdDelay: Int = 2,
|
|
psd: PSDTestMode = new PSDTestMode().fromBits(0.U)): Unit = {
|
|
debug.clockeddmi.foreach { d =>
|
|
val dtm = Module(new SimDTM).connect(c, r, d, out)
|
|
}
|
|
debug.systemjtag.foreach { sj =>
|
|
//val jtag = Module(new JTAGVPI(tckHalfPeriod = tckHalfPeriod, cmdDelay = cmdDelay)).connect(sj.jtag, sj.reset, r, out)
|
|
val jtag = Module(new SimJTAG(tickDelay=3)).connect(sj.jtag, sj.reset, c, r, out)
|
|
sj.mfr_id := p(JtagDTMKey).idcodeManufId.U(11.W)
|
|
}
|
|
debug.psd.foreach { _ <> psd }
|
|
}
|
|
}
|
|
|
|
trait HasPeripheryDebugModuleImp extends LazyModuleImp with HasPeripheryDebugBundle {
|
|
val outer: HasPeripheryDebug
|
|
|
|
val debug = IO(new DebugIO)
|
|
|
|
debug.clockeddmi.foreach { dbg => outer.debug.module.io.dmi <> dbg }
|
|
|
|
val dtm = debug.systemjtag.map { sj =>
|
|
|
|
val dtm = Module(new DebugTransportModuleJTAG(p(DebugModuleParams).nDMIAddrSize, p(JtagDTMKey)))
|
|
dtm.io.jtag <> sj.jtag
|
|
|
|
dtm.clock := sj.jtag.TCK
|
|
dtm.io.jtag_reset := sj.reset
|
|
dtm.io.jtag_mfr_id := sj.mfr_id
|
|
dtm.reset := dtm.io.fsmReset
|
|
|
|
outer.debug.module.io.dmi.dmi <> dtm.io.dmi
|
|
outer.debug.module.io.dmi.dmiClock := sj.jtag.TCK
|
|
|
|
val psd = debug.psd.getOrElse(Wire(new PSDTestMode).fromBits(0.U))
|
|
outer.debug.module.io.psd <> psd
|
|
outer.debug.module.io.dmi.dmiReset := ResetCatchAndSync(sj.jtag.TCK, sj.reset, "dmiResetCatch", psd)
|
|
dtm
|
|
}
|
|
|
|
debug.ndreset := outer.debug.module.io.ctrl.ndreset
|
|
debug.dmactive := outer.debug.module.io.ctrl.dmactive
|
|
|
|
// TODO in inheriting traits: Set this to something meaningful, e.g. "component is in reset or powered down"
|
|
outer.debug.module.io.ctrl.debugUnavail.foreach { _ := Bool(false) }
|
|
}
|
|
|
|
class SimDTM(implicit p: Parameters) extends BlackBox {
|
|
val io = new Bundle {
|
|
val clk = Clock(INPUT)
|
|
val reset = Bool(INPUT)
|
|
val debug = new DMIIO
|
|
val exit = UInt(OUTPUT, 32)
|
|
}
|
|
|
|
def connect(tbclk: Clock, tbreset: Bool, dutio: ClockedDMIIO, tbsuccess: Bool) = {
|
|
io.clk := tbclk
|
|
io.reset := tbreset
|
|
dutio.dmi <> io.debug
|
|
dutio.dmiClock := tbclk
|
|
dutio.dmiReset := tbreset
|
|
|
|
tbsuccess := io.exit === UInt(1)
|
|
when (io.exit >= UInt(2)) {
|
|
printf("*** FAILED *** (exit code = %d)\n", io.exit >> UInt(1))
|
|
stop(1)
|
|
}
|
|
}
|
|
}
|
|
|
|
class SimJTAG(tickDelay: Int = 50) extends BlackBox(Map("TICK_DELAY" -> IntParam(tickDelay))) {
|
|
val io = new Bundle {
|
|
val clock = Clock(INPUT)
|
|
val reset = Bool(INPUT)
|
|
val jtag = new JTAGIO(hasTRSTn = true)
|
|
val enable = Bool(INPUT)
|
|
val init_done = Bool(INPUT)
|
|
val exit = UInt(OUTPUT, 32)
|
|
}
|
|
|
|
def connect(dutio: JTAGIO, jtag_reset: Bool, tbclock: Clock, tbreset: Bool, tbsuccess: Bool) = {
|
|
dutio <> io.jtag
|
|
jtag_reset := tbreset
|
|
|
|
io.clock := tbclock
|
|
io.reset := tbreset
|
|
|
|
io.enable := PlusArg("jtag_rbb_enable", 0, "Enable SimJTAG for JTAG Connections. Simulation will pause until connection is made.")
|
|
io.init_done := ~tbreset
|
|
|
|
// Success is determined by the gdbserver
|
|
// which is controlling this simulation.
|
|
tbsuccess := io.exit === UInt(1)
|
|
when (io.exit >= UInt(2)) {
|
|
printf("*** FAILED *** (exit code = %d)\n", io.exit >> UInt(1))
|
|
stop(1)
|
|
}
|
|
}
|
|
}
|
|
|
|
class JTAGVPI(tckHalfPeriod: Int = 2, cmdDelay: Int = 2)(implicit val p: Parameters)
|
|
extends BlackBox ( Map ("TCK_HALF_PERIOD" -> IntParam(tckHalfPeriod),
|
|
"CMD_DELAY" -> IntParam(cmdDelay))) {
|
|
val io = new Bundle {
|
|
val jtag = new JTAGIO(hasTRSTn = false)
|
|
val enable = Bool(INPUT)
|
|
val init_done = Bool(INPUT)
|
|
}
|
|
|
|
def connect(dutio: JTAGIO, jtag_reset: Bool, tbreset: Bool, tbsuccess: Bool) = {
|
|
dutio <> io.jtag
|
|
|
|
dutio.TRSTn.foreach{ _:= false.B}
|
|
jtag_reset := tbreset
|
|
|
|
io.enable := ~tbreset
|
|
io.init_done := ~tbreset
|
|
|
|
// Success is determined by the gdbserver
|
|
// which is controlling this simulation.
|
|
tbsuccess := Bool(false)
|
|
}
|
|
}
|