debug: Breaking change until FESVR is updated as well.
* Replace v11 Debug Module with v13 module. * Correct all instantiating interfaces. * Rename "Debug Bus" to "DMI" (Debug Module Interface) * Use Diplomacy interrupts for DebugInterrupt * Seperate device for TLDebugROM
This commit is contained in:
		| @@ -22,7 +22,7 @@ class BaseCoreplexConfig extends Config ((site, here, up) => { | ||||
|   case BuildCore => (p: Parameters) => new Rocket()(p) | ||||
|   case RocketCrossing => Synchronous | ||||
|   case RocketTilesKey =>  Nil | ||||
|   case DMKey => new DefaultDebugModuleConfig(site(NTiles), site(XLen)) | ||||
|   case DMKey => new DefaultDebugModuleConfig(site(XLen)) | ||||
|   case NTiles => site(RocketTilesKey).size | ||||
|   case CBusConfig => TLBusConfig(beatBytes = site(XLen)/8) | ||||
|   case L1toL2Config => TLBusConfig(beatBytes = site(XLen)/8) // increase for more PCIe bandwidth | ||||
|   | ||||
| @@ -15,10 +15,12 @@ trait CoreplexRISCVPlatform extends CoreplexNetwork { | ||||
|   val module: CoreplexRISCVPlatformModule | ||||
|  | ||||
|   val debug = LazyModule(new TLDebugModule()) | ||||
|   val debug_rom = LazyModule(new TLDebugModuleROM()) | ||||
|   val plic  = LazyModule(new TLPLIC(maxPriorities = 7)) | ||||
|   val clint = LazyModule(new CoreplexLocalInterrupter) | ||||
|  | ||||
|   debug.node := TLFragmenter(cbus_beatBytes, cbus_lineBytes)(cbus.node) | ||||
|   debug_rom.node := TLFragmenter(cbus_beatBytes, cbus_lineBytes)(cbus.node) | ||||
|   plic.node  := TLFragmenter(cbus_beatBytes, cbus_lineBytes)(cbus.node) | ||||
|   clint.node := TLFragmenter(cbus_beatBytes, cbus_lineBytes)(cbus.node) | ||||
|  | ||||
| @@ -32,7 +34,7 @@ trait CoreplexRISCVPlatform extends CoreplexNetwork { | ||||
| trait CoreplexRISCVPlatformBundle extends CoreplexNetworkBundle { | ||||
|   val outer: CoreplexRISCVPlatform | ||||
|  | ||||
|   val debug = new AsyncDebugBusIO().flip | ||||
|   val debug = new ClockedDMIIO().flip | ||||
|   val rtcToggle = Bool(INPUT) | ||||
|   val resetVector = UInt(INPUT, p(XLen)) | ||||
| } | ||||
| @@ -41,8 +43,14 @@ trait CoreplexRISCVPlatformModule extends CoreplexNetworkModule { | ||||
|   val outer: CoreplexRISCVPlatform | ||||
|   val io: CoreplexRISCVPlatformBundle | ||||
|  | ||||
|   // Synchronize the debug bus into the coreplex | ||||
|   outer.debug.module.io.db <> FromAsyncDebugBus(io.debug) | ||||
|   outer.debug.module.io.dmi  <> io.debug | ||||
|   // TODO in inheriting traits: Set this to something meaningful, e.g. "component is in reset or powered down" | ||||
|   val nDebugComponents = outer.debug.intnode.bundleOut.size | ||||
|   outer.debug.module.io.ctrl.debugUnavail := Vec.fill(nDebugComponents){Bool(false)} | ||||
|   // TODO in inheriting traits: Use these values in your power and reset controls. | ||||
|   // TODO Or move these signals to Coreplex Top Level | ||||
|   // ... := outer.debug.module.io.ctrl.dmactive | ||||
|   // ... := outer.debug.module.io.ctrl.ndreset | ||||
|  | ||||
|   // Synchronize the rtc into the coreplex | ||||
|   val rtcSync = ShiftRegister(io.rtcToggle, 3) | ||||
|   | ||||
| @@ -33,11 +33,8 @@ trait HasRocketTiles extends CoreplexRISCVPlatform { | ||||
|       case SharedMemoryTLEdge => l1tol2.node.edgesIn(0) | ||||
|     } | ||||
|  | ||||
|     // Hack debug interrupt into a node (future debug module should use diplomacy) | ||||
|     val debugNode = IntInternalInputNode(IntSourcePortSimple()) | ||||
|  | ||||
|     val intBar = LazyModule(new IntXbar) | ||||
|     intBar.intnode := debugNode | ||||
|     intBar.intnode := debug.intnode // Debug Interrupt | ||||
|     intBar.intnode := clint.intnode // msip+mtip | ||||
|     intBar.intnode := plic.intnode // meip | ||||
|     if (c.core.useVM) intBar.intnode := plic.intnode // seip | ||||
| @@ -56,7 +53,6 @@ trait HasRocketTiles extends CoreplexRISCVPlatform { | ||||
|           // leave clock as default (simpler for hierarchical PnR) | ||||
|           wrapper.module.io.hartid := UInt(i) | ||||
|           wrapper.module.io.resetVector := io.resetVector | ||||
|           debugNode.bundleOut(0)(0) := debug.module.io.debugInterrupts(i) | ||||
|         } | ||||
|       } | ||||
|       case Asynchronous(depth, sync) => { | ||||
| @@ -75,7 +71,6 @@ trait HasRocketTiles extends CoreplexRISCVPlatform { | ||||
|           wrapper.module.reset := io.tcrs(i).reset | ||||
|           wrapper.module.io.hartid := UInt(i) | ||||
|           wrapper.module.io.resetVector := io.resetVector | ||||
|           debugNode.bundleOut(0)(0) := debug.module.io.debugInterrupts(i) | ||||
|         } | ||||
|       } | ||||
|       case Rational => { | ||||
| @@ -94,7 +89,6 @@ trait HasRocketTiles extends CoreplexRISCVPlatform { | ||||
|           wrapper.module.reset := io.tcrs(i).reset | ||||
|           wrapper.module.io.hartid := UInt(i) | ||||
|           wrapper.module.io.resetVector := io.resetVector | ||||
|           debugNode.bundleOut(0)(0) := debug.module.io.debugInterrupts(i) | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   | ||||
| @@ -36,6 +36,7 @@ class BasePlatformConfig extends Config((site, here, up) => { | ||||
|   case PeripheryBusArithmetic => true | ||||
|   // Note that PLIC asserts that this is > 0. | ||||
|   case IncludeJtagDTM => false | ||||
|   case JtagDTMKey => new JtagDTMKeyDefault() | ||||
|   case ZeroConfig => ZeroConfig(base=0xa000000L, size=0x2000000L, beatBytes=8) | ||||
|   case ExtMem => MasterConfig(base=0x80000000L, size=0x10000000L, beatBytes=8, idBits=4) | ||||
|   case ExtBus => MasterConfig(base=0x60000000L, size=0x20000000L, beatBytes=8, idBits=4) | ||||
|   | ||||
| @@ -3,78 +3,227 @@ | ||||
| package rocketchip | ||||
|  | ||||
| import Chisel._ | ||||
| import uncore.devices._ | ||||
| import junctions._ | ||||
| import util._ | ||||
| import config._ | ||||
| import jtag._ | ||||
| import uncore.devices.{DMIConsts, DMIIO, DMIReq, DMIResp} | ||||
|  | ||||
| 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 JTAG implementation | ||||
|  *  of the Debug Transport Module. | ||||
|  *  This is black-boxed because | ||||
|  *  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 'TRST' input is used to asynchronously | ||||
|  *  reset the Debug Transport Module and the | ||||
|  *  DTM side of the synchronizer. | ||||
|  *  This design requires that TRST be | ||||
|  *  synchronized to TCK (for de-assert) outside | ||||
|  *  of this module. Your top level code should ensure | ||||
|  *  that TRST is asserted before the rocket-chip core | ||||
|  *  comes out of reset. | ||||
|  *  Note that TRST is an optional | ||||
|  *  part of the JTAG protocol, but it is not | ||||
|  *  optional for interfacing with this logic. | ||||
|  *  | ||||
|  */ | ||||
| case class JtagDTMConfig ( | ||||
|   idcodeVersion    : Int,      // chosen by manuf. | ||||
|   idcodePartNum    : Int,      // Chosen by manuf. | ||||
|   idcodeManufId    : Int,      // Assigned by JEDEC | ||||
|   debugIdleCycles  : Int) | ||||
|  | ||||
| class JtagDTMWithSync(implicit val p: Parameters) extends Module { | ||||
|   // io.DebugBusIO <-> Sync <-> DebugBusIO <-> UInt <-> DTM Black Box | ||||
| case object JtagDTMKey extends Field[JtagDTMConfig] | ||||
|  | ||||
|   val io = new Bundle { | ||||
|     val jtag = new JTAGIO(true).flip | ||||
|     val debug = new AsyncDebugBusIO | ||||
|   } | ||||
| class JtagDTMKeyDefault extends JtagDTMConfig( | ||||
|   idcodeVersion = 0, | ||||
|   idcodePartNum = 0, | ||||
|   idcodeManufId = 0, | ||||
|   debugIdleCycles = 5) // Reasonable guess for synchronization. | ||||
|  | ||||
|   val req_width = io.debug.req.mem(0).getWidth | ||||
|   val resp_width = io.debug.resp.mem(0).getWidth | ||||
|  | ||||
|   val jtag_dtm = Module(new DebugTransportModuleJtag(req_width, resp_width)) | ||||
|   jtag_dtm.io.jtag <> io.jtag | ||||
|  | ||||
|   val io_debug_bus = Wire (new DebugBusIO) | ||||
|   io.debug <> ToAsyncDebugBus(io_debug_bus) | ||||
|  | ||||
|   val dtm_req = jtag_dtm.io.dtm_req | ||||
|   val dtm_resp = jtag_dtm.io.dtm_resp | ||||
|  | ||||
|   // 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 | ||||
| object dtmJTAGAddrs { | ||||
|   def IDCODE       = 0x1 | ||||
|   def DTM_INFO     = 0x10 | ||||
|   def DMI_ACCESS = 0x11 | ||||
| } | ||||
|  | ||||
| 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 DMIAccessUpdate(addrBits: Int) extends Bundle { | ||||
|   val addr = UInt(width = addrBits) | ||||
|   val data = UInt(width = DMIConsts.dmiDataSize) | ||||
|   val op = UInt(width = DMIConsts.dmiOpSize) | ||||
|  | ||||
|   override def cloneType = new DMIAccessUpdate(addrBits).asInstanceOf[this.type] | ||||
| } | ||||
|  | ||||
| class DMIAccessCapture(addrBits: Int) extends Bundle { | ||||
|   val addr = UInt(width = addrBits) | ||||
|   val data = UInt(width = DMIConsts.dmiDataSize) | ||||
|   val resp = UInt(width = DMIConsts.dmiRespSize) | ||||
|  | ||||
|   override def cloneType = new DMIAccessCapture(addrBits).asInstanceOf[this.type] | ||||
|  | ||||
| } | ||||
|  | ||||
| class DTMInfo extends Bundle { | ||||
|   val reserved1 = UInt(15.W) | ||||
|   val dmireset = Bool() | ||||
|   val reserved0 = UInt(1.W) | ||||
|   val dmiIdleCycles = UInt(3.W) | ||||
|   val dmiStatus = UInt(2.W) | ||||
|   val debugAddrBits = UInt(6.W) | ||||
|   val debugVersion = UInt(4.W) | ||||
| } | ||||
|  | ||||
| class DebugTransportModuleJTAG(debugAddrBits: Int, c: JtagDTMConfig) | ||||
|   (implicit val p: Parameters) extends Module  { | ||||
|  | ||||
|   val io = new Bundle { | ||||
|     val dmi = new DMIIO()(p) | ||||
|     val jtag = Flipped(new JTAGIO(hasTRSTn = false)) | ||||
|     val jtag_reset = Bool(INPUT) | ||||
|     val fsmReset = Bool(OUTPUT) | ||||
|   } | ||||
|  | ||||
|   //-------------------------------------------------------- | ||||
|   // Reg and Wire Declarations | ||||
|  | ||||
|   val dtmInfo = Wire(new DTMInfo) | ||||
|  | ||||
|   val busyReg = RegInit(Bool(false)) | ||||
|   val stickyBusyReg = RegInit(Bool(false)) | ||||
|   val stickyNonzeroRespReg = RegInit(Bool(false)) | ||||
|  | ||||
|   val skipOpReg = Reg(init = Bool(false)) // Skip op because we're busy | ||||
|   val downgradeOpReg = Reg(init = Bool(false)) // downgrade op because prev. failed. | ||||
|  | ||||
|   val busy = Wire(Bool()) | ||||
|   val nonzeroResp = Wire(Bool()) | ||||
|  | ||||
|   val busyResp = Wire(new DMIAccessCapture(debugAddrBits)) | ||||
|   val nonbusyResp = Wire(new DMIAccessCapture(debugAddrBits)) | ||||
|  | ||||
|   val dmiReqReg  = Reg(new DMIReq(debugAddrBits)) | ||||
|   val dmiReqValidReg = Reg(init = Bool(false)); | ||||
|  | ||||
|   val dmiStatus = Wire(UInt(width = 2)) | ||||
|  | ||||
|   //-------------------------------------------------------- | ||||
|   // DTM Info Chain Declaration | ||||
|  | ||||
|   dmiStatus := Cat(stickyNonzeroRespReg, stickyNonzeroRespReg | stickyBusyReg) | ||||
|  | ||||
|   dtmInfo.debugVersion   := 1.U // This implements version 1 of the spec. | ||||
|   dtmInfo.debugAddrBits  := UInt(debugAddrBits) | ||||
|   dtmInfo.dmiStatus     := dmiStatus | ||||
|   dtmInfo.dmiIdleCycles := UInt(c.debugIdleCycles) | ||||
|   dtmInfo.reserved0      := 0.U | ||||
|   dtmInfo.dmireset      := false.B // This is write-only | ||||
|   dtmInfo.reserved1      := 0.U | ||||
|  | ||||
|   val dtmInfoChain = Module (CaptureUpdateChain(gen = new DTMInfo())) | ||||
|   dtmInfoChain.io.capture.bits := dtmInfo | ||||
|  | ||||
|   //-------------------------------------------------------- | ||||
|   // Debug Access Chain Declaration | ||||
|  | ||||
|    val dmiAccessChain = Module(CaptureUpdateChain(genCapture = new DMIAccessCapture(debugAddrBits), | ||||
|      genUpdate = new DMIAccessUpdate(debugAddrBits))) | ||||
|  | ||||
|   //-------------------------------------------------------- | ||||
|   // Debug Access Support | ||||
|  | ||||
|   // Busy Register. We become busy when we first try to send a request. | ||||
|   // We stop being busy when we accept a response. | ||||
|  | ||||
|   when (io.dmi.req.valid) { | ||||
|     busyReg := Bool(true) | ||||
|   } | ||||
|   when (io.dmi.resp.fire()) { | ||||
|     busyReg := Bool(false) | ||||
|   } | ||||
|  | ||||
|   // We are busy during a given CAPTURE | ||||
|   // if we haven't received a valid response yet or if we | ||||
|   // were busy last time without a reset. | ||||
|   // busyReg will still be set when we check it, | ||||
|   // so the logic for checking busy looks ahead. | ||||
|   busy := (busyReg & !io.dmi.resp.valid) | stickyBusyReg; | ||||
|  | ||||
|   // Downgrade/Skip. We make the decision to downgrade or skip | ||||
|   // during every CAPTURE_DR, and use the result in UPDATE_DR. | ||||
|   // The sticky versions are reset by write to dmiReset in DTM_INFO. | ||||
|   when (dmiAccessChain.io.update.valid) { | ||||
|     skipOpReg := Bool(false) | ||||
|     downgradeOpReg := Bool(false) | ||||
|   } | ||||
|   when (dmiAccessChain.io.capture.capture) { | ||||
|     skipOpReg := busy | ||||
|     downgradeOpReg := (!busy & nonzeroResp) | ||||
|     stickyBusyReg := busy | ||||
|     stickyNonzeroRespReg := nonzeroResp | ||||
|   } | ||||
|   when (dtmInfoChain.io.update.valid) { | ||||
|     when (dtmInfoChain.io.update.bits.dmireset) { | ||||
|       stickyNonzeroRespReg := Bool(false) | ||||
|       stickyBusyReg := Bool(false) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Especially for the first request, we must consider dtmResp.valid, | ||||
|   // so that we don't consider junk in the FIFO to be an error response. | ||||
|   // The current specification says that any non-zero response is an error. | ||||
|   nonzeroResp := stickyNonzeroRespReg | (io.dmi.resp.valid & (io.dmi.resp.bits.resp != UInt(0))) | ||||
|  | ||||
|   busyResp.addr  := UInt(0) | ||||
|   busyResp.resp  := UInt(0) | ||||
|   busyResp.data  := UInt(0) | ||||
|  | ||||
|   nonbusyResp.addr := dmiReqReg.addr | ||||
|   nonbusyResp.resp := io.dmi.resp.bits.resp | ||||
|   nonbusyResp.data := io.dmi.resp.bits.data | ||||
|  | ||||
|   //-------------------------------------------------------- | ||||
|   // Debug Access Chain Implementation | ||||
|  | ||||
|   dmiAccessChain.io.capture.bits := Mux(busy, busyResp, nonbusyResp) | ||||
|   when (dmiAccessChain.io.update.valid) { | ||||
|     skipOpReg := Bool(false) | ||||
|     downgradeOpReg := Bool(false) | ||||
|   } | ||||
|   when (dmiAccessChain.io.capture.capture) { | ||||
|     skipOpReg := busy | ||||
|     downgradeOpReg := (!busy & nonzeroResp) | ||||
|       stickyBusyReg := busy | ||||
|     stickyNonzeroRespReg := nonzeroResp | ||||
|   } | ||||
|  | ||||
|   //-------------------------------------------------------- | ||||
|   // Drive Ready Valid Interface | ||||
|  | ||||
|   when (dmiAccessChain.io.update.valid) { | ||||
|     when (skipOpReg) { | ||||
|       // Do Nothing | ||||
|     }.otherwise { | ||||
|       when (downgradeOpReg) { | ||||
|         dmiReqReg.addr := UInt(0) | ||||
|         dmiReqReg.data := UInt(0) | ||||
|         dmiReqReg.op   := UInt(0) | ||||
|       }.otherwise { | ||||
|         dmiReqReg := dmiAccessChain.io.update.bits | ||||
|       } | ||||
|       dmiReqValidReg := Bool(true) | ||||
|     } | ||||
|   }.otherwise { | ||||
|     when (io.dmi.req.ready) { | ||||
|       dmiReqValidReg := Bool(false) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   io.dmi.resp.ready := dmiAccessChain.io.capture.capture | ||||
|   io.dmi.req.valid := dmiReqValidReg | ||||
|  | ||||
|   // This is a name-based, not type-based assignment. Do these still work? | ||||
|   io.dmi.req.bits := dmiReqReg | ||||
|  | ||||
|   //-------------------------------------------------------- | ||||
|   // Actual JTAG TAP | ||||
|  | ||||
|   val tapIO = JtagTapGenerator(irLength = 5, | ||||
|     instructions = Map(dtmJTAGAddrs.DMI_ACCESS -> dmiAccessChain, | ||||
|       dtmJTAGAddrs.DTM_INFO   -> dtmInfoChain), | ||||
|     idcode = Some((dtmJTAGAddrs.IDCODE, JtagIdcode(c.idcodeVersion, c.idcodePartNum, c.idcodeManufId)))) | ||||
|  | ||||
|   tapIO.jtag <> io.jtag | ||||
|  | ||||
|   tapIO.control.jtag_reset := io.jtag_reset | ||||
|  | ||||
|   //-------------------------------------------------------- | ||||
|   // Reset Generation (this is fed back to us by the instantiating module, | ||||
|   // and is used to reset the debug registers). | ||||
|  | ||||
|   io.fsmReset := tapIO.output.reset | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -8,55 +8,64 @@ import diplomacy._ | ||||
| import uncore.tilelink2._ | ||||
| import uncore.devices._ | ||||
| import util._ | ||||
| import junctions.JTAGIO | ||||
| import jtag.JTAGIO | ||||
| import coreplex._ | ||||
|  | ||||
| /// Core with JTAG for debug only | ||||
| // System with JTAG DTM Instantiated inside. JTAG interface is | ||||
| // exported outside. | ||||
|  | ||||
| trait PeripheryJTAG extends HasTopLevelNetworks { | ||||
|   val module: PeripheryJTAGModule | ||||
| trait PeripheryJTAGDTM extends HasTopLevelNetworks { | ||||
|   val module: PeripheryJTAGDTMModule | ||||
|   val coreplex: CoreplexRISCVPlatform | ||||
| } | ||||
|  | ||||
| trait PeripheryJTAGBundle extends HasTopLevelNetworksBundle { | ||||
|   val outer: PeripheryJTAG | ||||
| trait PeripheryJTAGDTMBundle extends HasTopLevelNetworksBundle { | ||||
|   val outer: PeripheryJTAGDTM | ||||
|  | ||||
|   val jtag = new JTAGIO(hasTRSTn = false).flip | ||||
|   val jtag_reset = Bool(INPUT) | ||||
|  | ||||
|   val jtag = new JTAGIO(true).flip | ||||
| } | ||||
|  | ||||
| trait PeripheryJTAGModule extends HasTopLevelNetworksModule { | ||||
|   val outer: PeripheryJTAG | ||||
|   val io: PeripheryJTAGBundle | ||||
| trait PeripheryJTAGDTMModule extends HasTopLevelNetworksModule { | ||||
|   val outer: PeripheryJTAGDTM | ||||
|   val io: PeripheryJTAGDTMBundle | ||||
|  | ||||
|   val dtm = Module (new JtagDTMWithSync) | ||||
|   val dtm = Module (new DebugTransportModuleJTAG(p(DMKey).nDMIAddrSize, p(JtagDTMKey))) | ||||
|   dtm.io.jtag <> io.jtag | ||||
|   outer.coreplex.module.io.debug <> dtm.io.debug | ||||
|    | ||||
|   dtm.clock             := io.jtag.TCK | ||||
|   dtm.io.jtag_reset     := io.jtag_reset | ||||
|   dtm.reset             := dtm.io.fsmReset | ||||
|  | ||||
|   outer.coreplex.module.io.debug.dmi <> dtm.io.dmi | ||||
|   outer.coreplex.module.io.debug.dmiClock := io.jtag.TCK | ||||
|   outer.coreplex.module.io.debug.dmiReset := ResetCatchAndSync(io.jtag.TCK, io.jtag_reset, "dmiResetCatch") | ||||
|  | ||||
|   dtm.clock := io.jtag.TCK | ||||
|   dtm.reset := io.jtag.TRST | ||||
| } | ||||
|  | ||||
| /// Core with DTM for debug only | ||||
| // System with Debug Module Interface Only. Any sort of DTM | ||||
| // can be connected outside. DMI Clock and Reset must be provided. | ||||
|  | ||||
| trait PeripheryDTM extends HasTopLevelNetworks { | ||||
|   val module: PeripheryDTMModule | ||||
| trait PeripheryDMI extends HasTopLevelNetworks { | ||||
|   val module: PeripheryDMIModule | ||||
|   val coreplex: CoreplexRISCVPlatform | ||||
| } | ||||
|  | ||||
| trait PeripheryDTMBundle extends HasTopLevelNetworksBundle { | ||||
|   val outer: PeripheryDTM | ||||
| trait PeripheryDMIBundle extends HasTopLevelNetworksBundle { | ||||
|   val outer: PeripheryDMI | ||||
|  | ||||
|   val debug = new DebugBusIO().flip | ||||
|   val debug = new ClockedDMIIO().flip | ||||
| } | ||||
|  | ||||
| trait PeripheryDTMModule extends HasTopLevelNetworksModule { | ||||
|   val outer: PeripheryDTM | ||||
|   val io: PeripheryDTMBundle | ||||
| trait PeripheryDMIModule extends HasTopLevelNetworksModule { | ||||
|   val outer: PeripheryDMI | ||||
|   val io: PeripheryDMIBundle | ||||
|  | ||||
|   outer.coreplex.module.io.debug <> ToAsyncDebugBus(io.debug) | ||||
|   outer.coreplex.module.io.debug <> io.debug | ||||
| } | ||||
|  | ||||
| /// Core with DTM or JTAG based on a parameter | ||||
| // System with DMI or JTAG interface based on a parameter | ||||
|  | ||||
| trait PeripheryDebug extends HasTopLevelNetworks { | ||||
|   val module: PeripheryDebugModule | ||||
| @@ -66,21 +75,30 @@ trait PeripheryDebug extends HasTopLevelNetworks { | ||||
| trait PeripheryDebugBundle extends HasTopLevelNetworksBundle { | ||||
|   val outer: PeripheryDebug | ||||
|  | ||||
|   val debug = (!p(IncludeJtagDTM)).option(new DebugBusIO().flip) | ||||
|   val jtag = (p(IncludeJtagDTM)).option(new JTAGIO(true).flip) | ||||
|   val debug = (!p(IncludeJtagDTM)).option(new ClockedDMIIO().flip) | ||||
|  | ||||
|   val jtag        = (p(IncludeJtagDTM)).option(new JTAGIO(hasTRSTn = false).flip) | ||||
|   val jtag_reset  = (p(IncludeJtagDTM)).option(Bool(INPUT)) | ||||
|  | ||||
| } | ||||
|  | ||||
| trait PeripheryDebugModule extends HasTopLevelNetworksModule { | ||||
|   val outer: PeripheryDebug | ||||
|   val io: PeripheryDebugBundle | ||||
|  | ||||
|   io.debug.foreach { dbg => outer.coreplex.module.io.debug <> ToAsyncDebugBus(dbg) } | ||||
|   io.jtag.foreach { jtag => | ||||
|     val dtm = Module (new JtagDTMWithSync) | ||||
|     dtm.clock := jtag.TCK | ||||
|     dtm.reset := jtag.TRST | ||||
|     dtm.io.jtag <> jtag | ||||
|     outer.coreplex.module.io.debug <> dtm.io.debug | ||||
|   io.debug.foreach { dbg => outer.coreplex.module.io.debug <> dbg } | ||||
|  | ||||
|   val dtm = if (io.jtag.isDefined) Some[DebugTransportModuleJTAG](Module (new DebugTransportModuleJTAG(p(DMKey).nDMIAddrSize, p(JtagDTMKey)))) else None | ||||
|   dtm.foreach { dtm => | ||||
|     dtm.io.jtag <> io.jtag.get | ||||
|  | ||||
|     dtm.clock          := io.jtag.get.TCK | ||||
|     dtm.io.jtag_reset  := io.jtag_reset.get | ||||
|     dtm.reset          := dtm.io.fsmReset | ||||
|  | ||||
|     outer.coreplex.module.io.debug.dmi <> dtm.io.dmi | ||||
|     outer.coreplex.module.io.debug.dmiClock := io.jtag.get.TCK | ||||
|     outer.coreplex.module.io.debug.dmiReset := ResetCatchAndSync(io.jtag.get.TCK, io.jtag_reset.get, "dmiResetCatch") | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -8,6 +8,7 @@ import junctions._ | ||||
| import diplomacy._ | ||||
| import coreplex._ | ||||
| import uncore.axi4._ | ||||
| import jtag.JTAGIO | ||||
|  | ||||
| class TestHarness()(implicit p: Parameters) extends Module { | ||||
|   val io = new Bundle { | ||||
| @@ -23,7 +24,7 @@ class TestHarness()(implicit p: Parameters) extends Module { | ||||
|   if (!p(IncludeJtagDTM)) { | ||||
|     val dtm = Module(new SimDTM).connect(clock, reset, dut.io.debug.get, io.success) | ||||
|   } else { | ||||
|      val jtag = Module(new JTAGVPI).connect(dut.io.jtag.get, reset, io.success)		 | ||||
|     val jtag = Module(new JTAGVPI).connect(dut.io.jtag.get, dut.io.jtag_reset.get, reset, io.success) | ||||
|   } | ||||
|  | ||||
|   val mmio_sim = Module(LazyModule(new SimAXIMem(1, 4096)).module) | ||||
| @@ -62,14 +63,16 @@ class SimDTM(implicit p: Parameters) extends BlackBox { | ||||
|   val io = new Bundle { | ||||
|     val clk = Clock(INPUT) | ||||
|     val reset = Bool(INPUT) | ||||
|     val debug = new uncore.devices.DebugBusIO | ||||
|     val debug = new uncore.devices.DMIIO | ||||
|     val exit = UInt(OUTPUT, 32) | ||||
|   } | ||||
|  | ||||
|   def connect(tbclk: Clock, tbreset: Bool, dutio: uncore.devices.DebugBusIO, tbsuccess: Bool) = { | ||||
|   def connect(tbclk: Clock, tbreset: Bool, dutio: uncore.devices.ClockedDMIIO, tbsuccess: Bool) = { | ||||
|     io.clk := tbclk | ||||
|     io.reset := tbreset | ||||
|     dutio <> io.debug | ||||
|     dutio.dmiClock := tbclk | ||||
|     dutio.dmiReset := tbreset | ||||
|  | ||||
|     tbsuccess := io.exit === UInt(1) | ||||
|     when (io.exit >= UInt(2)) { | ||||
| @@ -81,23 +84,18 @@ class SimDTM(implicit p: Parameters) extends BlackBox { | ||||
|  | ||||
| class JTAGVPI(implicit val p: Parameters) extends BlackBox { | ||||
|   val io = new Bundle { | ||||
|     val jtag = new JTAGIO(false) | ||||
|     val jtag = new JTAGIO(hasTRSTn = false) | ||||
|     val enable = Bool(INPUT) | ||||
|     val init_done = Bool(INPUT) | ||||
|   } | ||||
|  | ||||
|   def connect(dutio: JTAGIO, tbreset: Bool, tbsuccess: Bool) = { | ||||
|   def connect(dutio: JTAGIO, jtag_reset: Bool, tbreset: Bool, tbsuccess: Bool) = { | ||||
|     dutio <> 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. | ||||
|     dutio.TRSTn.foreach{ _:= false.B} | ||||
|     jtag_reset := tbreset | ||||
|  | ||||
|     dutio.TRST := tbreset | ||||
|     io.enable := ~tbreset | ||||
|     io.enable    := ~tbreset | ||||
|     io.init_done := ~tbreset | ||||
|  | ||||
|     // Success is determined by the gdbserver | ||||
|   | ||||
| @@ -1,887 +0,0 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| package uncore.devices | ||||
|  | ||||
| import Chisel._ | ||||
| import junctions._ | ||||
| import util._ | ||||
| import regmapper._ | ||||
| import tile.XLen | ||||
| import uncore.tilelink2._ | ||||
| import config._ | ||||
|  | ||||
| // ***************************************** | ||||
| // Constants which are interesting even | ||||
| // outside of this module | ||||
| // ***************************************** | ||||
|  | ||||
| object DbRegAddrs{ | ||||
|  | ||||
|   def DMRAMBASE    = UInt(0x0) | ||||
|   def DMCONTROL    = UInt(0x10) | ||||
|  | ||||
|   def DMINFO       = UInt(0x11) | ||||
|   def AUTHDATA0    = UInt(0x12) | ||||
|   def AUTHDATA1    = UInt(0x13) | ||||
|   def SERDATA      = UInt(0x14) | ||||
|   def SERSTATUS    = UInt(0x15) | ||||
|   def SBUSADDRESS0 = UInt(0x16) | ||||
|   def SBUSADDRESS1 = UInt(0x17) | ||||
|   def SBDATA0      = UInt(0x18) | ||||
|   def SBDATA1      = UInt(0x19) | ||||
|   //1a | ||||
|   def HALTSUM      = UInt(0x1B) | ||||
|   //1c - 3b are the halt notification registers. | ||||
|   def SBADDRESS2    = UInt(0x3d) | ||||
|   // 3c | ||||
|   def SBDATA2       = UInt(0x3e) | ||||
|   def SBDATA3       = UInt(0x3f) | ||||
| } | ||||
|  | ||||
| /** Constant values used by both Debug Bus Response & Request | ||||
|   */ | ||||
|  | ||||
| object DbBusConsts{ | ||||
|  | ||||
|   def dbDataSize = 34 | ||||
|  | ||||
|   def dbRamWordBits = 32 | ||||
|  | ||||
|   def dbOpSize = 2 | ||||
|   def db_OP_NONE            = UInt("b00") | ||||
|   def db_OP_READ            = UInt("b01") | ||||
|   def db_OP_READ_WRITE      = UInt("b10") | ||||
|   def db_OP_READ_COND_WRITE = UInt("b11") | ||||
|  | ||||
|   def dbRespSize = 2 | ||||
|   def db_RESP_SUCCESS     = UInt("b00") | ||||
|   def db_RESP_FAILURE     = UInt("b01") | ||||
|   def db_RESP_HW_FAILURE  = UInt("b10") | ||||
|   // This is used outside this block | ||||
|   // to indicate 'busy'. | ||||
|   def db_RESP_RESERVED    = UInt("b11") | ||||
|  | ||||
| } | ||||
|  | ||||
| object DsbBusConsts { | ||||
|  | ||||
|   def sbAddrWidth = 12 | ||||
|   def sbIdWidth   = 10  | ||||
|  | ||||
|   //These are the default ROM contents, which support RV32 and RV64. | ||||
|   // See $RISCV/riscv-tools/riscv-isa-sim/debug_rom/debug_rom.h/S | ||||
|   // The code assumes 64 bytes of Debug RAM. | ||||
|  | ||||
|   def xlenAnyRomContents : Array[Byte] = Array( | ||||
|     0x6f, 0x00, 0xc0, 0x04, 0x6f, 0x00, 0xc0, 0x00, 0x13, 0x04, 0xf0, 0xff, | ||||
|     0x6f, 0x00, 0x80, 0x00, 0x13, 0x04, 0x00, 0x00, 0x0f, 0x00, 0xf0, 0x0f, | ||||
|     0xf3, 0x24, 0x00, 0xf1, 0x63, 0xc6, 0x04, 0x00, 0x83, 0x24, 0xc0, 0x43, | ||||
|     0x6f, 0x00, 0x80, 0x00, 0x83, 0x34, 0x80, 0x43, 0x23, 0x2e, 0x80, 0x42, | ||||
|     0x73, 0x24, 0x40, 0xf1, 0x23, 0x20, 0x80, 0x10, 0x73, 0x24, 0x00, 0x7b, | ||||
|     0x13, 0x74, 0x84, 0x00, 0x63, 0x12, 0x04, 0x04, 0x73, 0x24, 0x20, 0x7b, | ||||
|     0x73, 0x00, 0x20, 0x7b, 0x73, 0x10, 0x24, 0x7b, 0x73, 0x24, 0x00, 0x7b, | ||||
|     0x13, 0x74, 0x04, 0x1c, 0x13, 0x04, 0x04, 0xf4, 0x63, 0x1e, 0x04, 0x00, | ||||
|     0x73, 0x24, 0x00, 0xf1, 0x63, 0x46, 0x04, 0x00, 0x23, 0x2e, 0x90, 0x42, | ||||
|     0x67, 0x00, 0x00, 0x40, 0x23, 0x3c, 0x90, 0x42, 0x67, 0x00, 0x00, 0x40, | ||||
|     0x73, 0x24, 0x40, 0xf1, 0x23, 0x26, 0x80, 0x10, 0x73, 0x60, 0x04, 0x7b, | ||||
|     0x73, 0x24, 0x00, 0x7b, 0x13, 0x74, 0x04, 0x02, 0xe3, 0x0c, 0x04, 0xfe, | ||||
|     0x6f, 0xf0, 0x1f, 0xfd).map(_.toByte) | ||||
|  | ||||
|   // These ROM contents support only RV32  | ||||
|   // See $RISCV/riscv-tools/riscv-isa-sim/debug_rom/debug_rom.h/S | ||||
|   // The code assumes only 28 bytes of Debug RAM. | ||||
|  | ||||
|   def xlen32OnlyRomContents : Array[Byte] = Array( | ||||
|     0x6f, 0x00, 0xc0, 0x03, 0x6f, 0x00, 0xc0, 0x00, 0x13, 0x04, 0xf0, 0xff, | ||||
|     0x6f, 0x00, 0x80, 0x00, 0x13, 0x04, 0x00, 0x00, 0x0f, 0x00, 0xf0, 0x0f, | ||||
|     0x83, 0x24, 0x80, 0x41, 0x23, 0x2c, 0x80, 0x40, 0x73, 0x24, 0x40, 0xf1, | ||||
|     0x23, 0x20, 0x80, 0x10, 0x73, 0x24, 0x00, 0x7b, 0x13, 0x74, 0x84, 0x00, | ||||
|     0x63, 0x1a, 0x04, 0x02, 0x73, 0x24, 0x20, 0x7b, 0x73, 0x00, 0x20, 0x7b, | ||||
|     0x73, 0x10, 0x24, 0x7b, 0x73, 0x24, 0x00, 0x7b, 0x13, 0x74, 0x04, 0x1c, | ||||
|     0x13, 0x04, 0x04, 0xf4, 0x63, 0x16, 0x04, 0x00, 0x23, 0x2c, 0x90, 0x40, | ||||
|     0x67, 0x00, 0x00, 0x40, 0x73, 0x24, 0x40, 0xf1, 0x23, 0x26, 0x80, 0x10, | ||||
|     0x73, 0x60, 0x04, 0x7b, 0x73, 0x24, 0x00, 0x7b, 0x13, 0x74, 0x04, 0x02, | ||||
|     0xe3, 0x0c, 0x04, 0xfe, 0x6f, 0xf0, 0x1f, 0xfe).map(_.toByte) | ||||
|  | ||||
|   // These ROM contents support only RV64 | ||||
|   // See $RISCV/riscv-tools/riscv-isa-sim/debug_rom/debug_rom.h/S | ||||
|   // The code assumes 64 bytes of Debug RAM. | ||||
|  | ||||
|   def xlen64OnlyRomContents : Array[Byte] = Array( | ||||
|     0x6f, 0x00, 0xc0, 0x03, 0x6f, 0x00, 0xc0, 0x00, 0x13, 0x04, 0xf0, 0xff, | ||||
|     0x6f, 0x00, 0x80, 0x00, 0x13, 0x04, 0x00, 0x00, 0x0f, 0x00, 0xf0, 0x0f, | ||||
|     0x83, 0x34, 0x80, 0x43, 0x23, 0x2e, 0x80, 0x42, 0x73, 0x24, 0x40, 0xf1, | ||||
|     0x23, 0x20, 0x80, 0x10, 0x73, 0x24, 0x00, 0x7b, 0x13, 0x74, 0x84, 0x00, | ||||
|     0x63, 0x1a, 0x04, 0x02, 0x73, 0x24, 0x20, 0x7b, 0x73, 0x00, 0x20, 0x7b, | ||||
|     0x73, 0x10, 0x24, 0x7b, 0x73, 0x24, 0x00, 0x7b, 0x13, 0x74, 0x04, 0x1c, | ||||
|     0x13, 0x04, 0x04, 0xf4, 0x63, 0x16, 0x04, 0x00, 0x23, 0x3c, 0x90, 0x42, | ||||
|     0x67, 0x00, 0x00, 0x40, 0x73, 0x24, 0x40, 0xf1, 0x23, 0x26, 0x80, 0x10, | ||||
|     0x73, 0x60, 0x04, 0x7b, 0x73, 0x24, 0x00, 0x7b, 0x13, 0x74, 0x04, 0x02, | ||||
|     0xe3, 0x0c, 0x04, 0xfe, 0x6f, 0xf0, 0x1f, 0xfe).map(_.toByte) | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| object DsbRegAddrs{ | ||||
|  | ||||
|   def CLEARDEBINT  = 0x100 | ||||
|   def SETHALTNOT   = 0x10C | ||||
|   def SERINFO      = 0x110 | ||||
|   def SERBASE      = 0x114 | ||||
|   // For each serial, there are | ||||
|   // 3 registers starting here: | ||||
|   // SERSEND0 | ||||
|   // SERRECEIVE0 | ||||
|   // SERSTATUS0 | ||||
|   // ... | ||||
|   // SERSTATUS7 | ||||
|   def SERTX_OFFSET   = 0 | ||||
|   def SERRX_OFFSET   = 4 | ||||
|   def SERSTAT_OFFSET = 8 | ||||
|   def RAMBASE      = 0x400 | ||||
|   def ROMBASE      = 0x800 | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| // ***************************************** | ||||
| // Configuration & Parameters for this Module | ||||
| //  | ||||
| // ***************************************** | ||||
|  | ||||
| /** Enumerations used both in the hardware | ||||
|   * and in the configuration specification. | ||||
|   */ | ||||
|  | ||||
| object DebugModuleAuthType extends scala.Enumeration { | ||||
|   type DebugModuleAuthType = Value | ||||
|   val None, Password, ChallengeResponse, Reserved = Value | ||||
| } | ||||
| import DebugModuleAuthType._ | ||||
|  | ||||
| object DebugModuleAccessType extends scala.Enumeration { | ||||
|   type DebugModuleAccessType = Value | ||||
|   val Access8Bit, Access16Bit, Access32Bit, Access64Bit, Access128Bit = Value | ||||
| } | ||||
| import DebugModuleAccessType._ | ||||
|  | ||||
|  | ||||
| /** Parameters exposed to the top-level design, set based on | ||||
|   * external requirements, etc. | ||||
|   * | ||||
|   *  This object checks that the parameters conform to the  | ||||
|   *  full specification. The implementation which receives this | ||||
|   *  object can perform more checks on what that implementation | ||||
|   *  actually supports. | ||||
|   *  nComponents : The number of components to support debugging. | ||||
|   *  nDebugBusAddrSize : Size of the Debug Bus Address | ||||
|   *  nDebugRam Bytes: Size of the Debug RAM (depends on the XLEN of the machine). | ||||
|   *  debugRomContents: Optional Sequence of bytes which form the Debug ROM contents.  | ||||
|   *  hasBusMaster: Whether or not a bus master should be included | ||||
|   *    The size of the accesses supported by the Bus Master.  | ||||
|   *  nSerialPorts : Number of serial ports to instantiate | ||||
|   *  authType : The Authorization Type | ||||
|   *  Number of cycles to assert ndreset when pulsed.  | ||||
|   **/ | ||||
|  | ||||
|  | ||||
| case class DebugModuleConfig ( | ||||
|   nComponents       : Int, | ||||
|   nDebugBusAddrSize : Int, | ||||
|   nDebugRamBytes    : Int, | ||||
|   debugRomContents  : Option[Seq[Byte]], | ||||
|   hasBusMaster : Boolean, | ||||
|   hasAccess128 : Boolean, | ||||
|   hasAccess64  : Boolean, | ||||
|   hasAccess32  : Boolean, | ||||
|   hasAccess16  : Boolean, | ||||
|   hasAccess8   : Boolean, | ||||
|   nSerialPorts : Int, | ||||
|   authType : DebugModuleAuthType, | ||||
|   nNDResetCycles : Int | ||||
| ) { | ||||
|  | ||||
|   if (hasBusMaster == false){ | ||||
|     require (hasAccess128 == false) | ||||
|     require (hasAccess64  == false) | ||||
|     require (hasAccess32  == false) | ||||
|     require (hasAccess16  == false) | ||||
|     require (hasAccess8   == false) | ||||
|   } | ||||
|  | ||||
|   require (nSerialPorts <= 8) | ||||
|  | ||||
|   require ((nDebugBusAddrSize >= 5) && (nDebugBusAddrSize <= 7)) | ||||
|  | ||||
|   private val maxComponents = nDebugBusAddrSize match { | ||||
|     case 5 => (32*4) | ||||
|     case 6 => (32*32) | ||||
|     case 7 => (32*32) | ||||
|   } | ||||
|   require (nComponents > 0 && nComponents <= maxComponents) | ||||
|  | ||||
|   private val maxRam = nDebugBusAddrSize match { | ||||
|     case 5 => (4 * 16) | ||||
|     case 6 => (4 * 16) | ||||
|     case 7 => (4 * 64) | ||||
|   } | ||||
|  | ||||
|   require (nDebugRamBytes > 0 && nDebugRamBytes <= maxRam) | ||||
|  | ||||
|   val hasHaltSum = (nComponents > 64) || (nSerialPorts > 0) | ||||
|  | ||||
|   val hasDebugRom = debugRomContents.nonEmpty | ||||
|  | ||||
|   if (hasDebugRom) { | ||||
|     require (debugRomContents.get.size > 0) | ||||
|     require (debugRomContents.get.size <= 512) | ||||
|   } | ||||
|  | ||||
|   require (nNDResetCycles > 0) | ||||
|  | ||||
| } | ||||
|  | ||||
| class DefaultDebugModuleConfig (val ncomponents : Int, val xlen:Int) | ||||
|     extends DebugModuleConfig( | ||||
|       nComponents = ncomponents, | ||||
|       nDebugBusAddrSize = 5, | ||||
|       // While smaller numbers are theoretically | ||||
|       // possible as noted in the Spec, | ||||
|       // the ROM image would need to be | ||||
|       // adjusted accordingly. | ||||
|       nDebugRamBytes = xlen match{ | ||||
|         case 32  => 28  | ||||
|         case 64  => 64 | ||||
|         case 128 => 64 | ||||
|       }, | ||||
|       debugRomContents = xlen match { | ||||
|         case 32  => Some(DsbBusConsts.xlen32OnlyRomContents) | ||||
|         case 64  => Some(DsbBusConsts.xlen64OnlyRomContents) | ||||
|       }, | ||||
|       hasBusMaster = false, | ||||
|       hasAccess128 = false,  | ||||
|       hasAccess64 = false,  | ||||
|       hasAccess32 = false,  | ||||
|       hasAccess16 = false,  | ||||
|       hasAccess8 = false,  | ||||
|       nSerialPorts = 0, | ||||
|       authType = DebugModuleAuthType.None, | ||||
|       nNDResetCycles = 1) | ||||
|  | ||||
| case object DMKey extends Field[DebugModuleConfig] | ||||
|  | ||||
| // ***************************************** | ||||
| // Module Interfaces | ||||
| //  | ||||
| // ***************************************** | ||||
|  | ||||
|  | ||||
| /** Structure to define the contents of a Debug Bus Request | ||||
|   */ | ||||
|  | ||||
| class DebugBusReq(addrBits : Int) extends Bundle { | ||||
|   val addr = UInt(width = addrBits) | ||||
|   val data = UInt(width = DbBusConsts.dbDataSize) | ||||
|   val op   = UInt(width = DbBusConsts.dbOpSize) | ||||
|  | ||||
|   override def cloneType = new DebugBusReq(addrBits).asInstanceOf[this.type] | ||||
| } | ||||
|  | ||||
|  | ||||
| /** Structure to define the contents of a Debug Bus Response | ||||
|   */ | ||||
| class DebugBusResp( ) extends Bundle { | ||||
|   val data = UInt(width = DbBusConsts.dbDataSize) | ||||
|   val resp = UInt(width = DbBusConsts.dbRespSize) | ||||
|  | ||||
| } | ||||
|  | ||||
| /** Structure to define the top-level DebugBus interface  | ||||
|   *  of DebugModule. | ||||
|   *  DebugModule is the consumer of this interface. | ||||
|   *  Therefore it has the 'flipped' version of this. | ||||
|   */ | ||||
|  | ||||
| class DebugBusIO(implicit val p: Parameters) extends ParameterizedBundle()(p) { | ||||
|   val req = new  DecoupledIO(new DebugBusReq(p(DMKey).nDebugBusAddrSize)) | ||||
|   val resp = new DecoupledIO(new DebugBusResp).flip() | ||||
| } | ||||
|  | ||||
| class AsyncDebugBusIO(implicit val p: Parameters) extends ParameterizedBundle()(p) { | ||||
|   val req  = new AsyncBundle(1, new DebugBusReq(p(DMKey).nDebugBusAddrSize)) | ||||
|   val resp = new AsyncBundle(1, new DebugBusResp).flip | ||||
| } | ||||
|  | ||||
| object FromAsyncDebugBus | ||||
| { | ||||
|   def apply(x: AsyncDebugBusIO) = { | ||||
|     val out = Wire(new DebugBusIO()(x.p)) | ||||
|     out.req <> FromAsyncBundle(x.req) | ||||
|     x.resp <> ToAsyncBundle(out.resp, 1) | ||||
|     out | ||||
|   } | ||||
| } | ||||
|  | ||||
| object ToAsyncDebugBus | ||||
| { | ||||
|   def apply(x: DebugBusIO) = { | ||||
|     val out = Wire(new AsyncDebugBusIO()(x.p)) | ||||
|     out.req <> ToAsyncBundle(x.req, 1) | ||||
|     x.resp <> FromAsyncBundle(out.resp) | ||||
|     out | ||||
|   } | ||||
| } | ||||
|  | ||||
| trait HasDebugModuleParameters { | ||||
|   implicit val p: Parameters | ||||
|   val cfg = p(DMKey) | ||||
| } | ||||
|  | ||||
| /** Debug Module I/O, with the exclusion of the RegisterRouter | ||||
|   *  Access interface. | ||||
|   */ | ||||
|  | ||||
| trait DebugModuleBundle extends Bundle with HasDebugModuleParameters { | ||||
|   val db = new DebugBusIO()(p).flip() | ||||
|   val debugInterrupts = Vec(cfg.nComponents, Bool()).asOutput | ||||
|   val ndreset    = Bool(OUTPUT) | ||||
|   val fullreset  = Bool(OUTPUT) | ||||
| } | ||||
|  | ||||
|  | ||||
| // ***************************************** | ||||
| // The Module  | ||||
| //  | ||||
| // ***************************************** | ||||
|  | ||||
| /** Parameterized version of the Debug Module defined in the | ||||
|   *  RISC-V Debug Specification  | ||||
|   *   | ||||
|   *  DebugModule is a slave to two masters: | ||||
|   *    The Debug Bus -- implemented as a generic Decoupled IO with request | ||||
|   *                   and response channels | ||||
|   *    The System Bus -- implemented as generic RegisterRouter | ||||
|   *   | ||||
|   *  DebugModule is responsible for holding registers, RAM, and ROM | ||||
|   *      to support debug interactions, as well as driving interrupts | ||||
|   *      to a configurable number of components in the system. | ||||
|   *      It is also responsible for some reset lines. | ||||
|   */ | ||||
|  | ||||
| trait DebugModule extends Module with HasDebugModuleParameters with HasRegMap { | ||||
|  | ||||
|   val io: DebugModuleBundle | ||||
|  | ||||
|   //-------------------------------------------------------------- | ||||
|   // Import constants for shorter variable names | ||||
|   //-------------------------------------------------------------- | ||||
|  | ||||
|   import DbRegAddrs._ | ||||
|   import DsbRegAddrs._ | ||||
|   import DsbBusConsts._ | ||||
|   import DbBusConsts._ | ||||
|  | ||||
|   //-------------------------------------------------------------- | ||||
|   // Sanity Check Configuration For this implementation. | ||||
|   //-------------------------------------------------------------- | ||||
|  | ||||
|   require (cfg.nComponents <= 128) | ||||
|   require (cfg.nSerialPorts == 0) | ||||
|   require (cfg.hasBusMaster == false) | ||||
|   require (cfg.nDebugRamBytes <= 64) | ||||
|   require (cfg.authType == DebugModuleAuthType.None) | ||||
|   require((DbBusConsts.dbRamWordBits % 8) == 0) | ||||
|  | ||||
|   //-------------------------------------------------------------- | ||||
|   // Private Classes (Register Fields) | ||||
|   //-------------------------------------------------------------- | ||||
|  | ||||
|   class RAMFields() extends Bundle { | ||||
|     val interrupt     = Bool() | ||||
|     val haltnot       = Bool() | ||||
|     val data          = Bits(width = 32) | ||||
|  | ||||
|     override def cloneType = new RAMFields().asInstanceOf[this.type]     | ||||
|   } | ||||
|  | ||||
|   class CONTROLFields() extends Bundle { | ||||
|     val interrupt     = Bool() | ||||
|     val haltnot       = Bool() | ||||
|     val reserved0     = Bits(width = 31-22 + 1) | ||||
|     val buserror      = Bits(width = 3) | ||||
|     val serial        = Bits(width = 3) | ||||
|     val autoincrement = Bool() | ||||
|     val access        = UInt(width = 3)  | ||||
|     val hartid        = Bits(width = 10) | ||||
|     val ndreset       = Bool()          | ||||
|     val fullreset     = Bool() | ||||
|  | ||||
|     override def cloneType = new CONTROLFields().asInstanceOf[this.type] | ||||
|      | ||||
|   } | ||||
|  | ||||
|   class DMINFOFields() extends Bundle { | ||||
|     val reserved0     = Bits(width = 2) | ||||
|     val abussize      = UInt(width = 7) | ||||
|     val serialcount   = UInt(width = 4) | ||||
|     val access128     = Bool() | ||||
|     val access64      = Bool() | ||||
|     val access32      = Bool() | ||||
|     val access16      = Bool() | ||||
|     val accesss8      = Bool() | ||||
|     val dramsize      = UInt(width = 6) | ||||
|     val haltsum       = Bool() | ||||
|     val reserved1     = Bits(width = 3) | ||||
|     val authenticated = Bool() | ||||
|     val authbusy      = Bool() | ||||
|     val authtype      = UInt(width = 2) | ||||
|     val version       = UInt(width = 2) | ||||
|  | ||||
|     override def cloneType = new DMINFOFields().asInstanceOf[this.type] | ||||
|      | ||||
|   } | ||||
|  | ||||
|   class HALTSUMFields() extends Bundle { | ||||
|     val serialfull     = Bool() | ||||
|     val serialvalid    = Bool() | ||||
|     val acks           = Bits(width = 32) | ||||
|  | ||||
|     override def cloneType = new HALTSUMFields().asInstanceOf[this.type] | ||||
|      | ||||
|   } | ||||
|  | ||||
|  | ||||
|   //-------------------------------------------------------------- | ||||
|   // Register & Wire Declarations | ||||
|   //-------------------------------------------------------------- | ||||
|  | ||||
|   // --- Debug Bus Registers | ||||
|   val CONTROLReset = Wire(new CONTROLFields()) | ||||
|   val CONTROLWrEn = Wire(Bool()) | ||||
|   val CONTROLReg = Reg(new CONTROLFields()) | ||||
|   val CONTROLWrData = Wire (new CONTROLFields()) | ||||
|   val CONTROLRdData = Wire (new CONTROLFields()) | ||||
|   val ndresetCtrReg = Reg(UInt(cfg.nNDResetCycles)) | ||||
|  | ||||
|   val DMINFORdData = Wire (new DMINFOFields()) | ||||
|  | ||||
|   val HALTSUMRdData = Wire (new HALTSUMFields()) | ||||
|  | ||||
|   val RAMWrData = Wire (new RAMFields()) | ||||
|   val RAMRdData = Wire (new RAMFields()) | ||||
|  | ||||
|   // --- System Bus Registers | ||||
|    | ||||
|   val SETHALTNOTWrEn = Wire(Bool()) | ||||
|   val SETHALTNOTWrData = Wire(UInt(width = sbIdWidth)) | ||||
|   val CLEARDEBINTWrEn = Wire(Bool()) | ||||
|   val CLEARDEBINTWrData = Wire(UInt(width = sbIdWidth)) | ||||
|  | ||||
|   // --- Interrupt & Halt Notification Registers | ||||
|  | ||||
|   val interruptRegs = Reg(init=Vec.fill(cfg.nComponents){Bool(false)}) | ||||
|  | ||||
|   val haltnotRegs     = Reg(init=Vec.fill(cfg.nComponents){Bool(false)}) | ||||
|   val numHaltnotStatus = ((cfg.nComponents - 1) / 32) + 1 | ||||
|  | ||||
|   val haltnotStatus = Wire(Vec(numHaltnotStatus, Bits(width = 32))) | ||||
|   val rdHaltnotStatus = Wire(Bits(width = 32)) | ||||
|  | ||||
|   val haltnotSummary = Cat(haltnotStatus.map(_.orR).reverse) | ||||
|  | ||||
|   // --- Debug RAM | ||||
|  | ||||
|   val ramDataWidth    = DbBusConsts.dbRamWordBits | ||||
|   val ramDataBytes    = ramDataWidth / 8; | ||||
|   val ramAddrWidth    = log2Up(cfg.nDebugRamBytes / ramDataBytes) | ||||
|  | ||||
|   val ramMem    = Reg(init = Vec.fill(cfg.nDebugRamBytes){UInt(0, width = 8)}) | ||||
|  | ||||
|   val dbRamAddr   = Wire(UInt(width=ramAddrWidth)) | ||||
|   val dbRamAddrValid   = Wire(Bool()) | ||||
|   val dbRamRdData = Wire (UInt(width=ramDataWidth)) | ||||
|   val dbRamWrData = Wire(UInt(width=ramDataWidth)) | ||||
|   val dbRamWrEn   = Wire(Bool()) | ||||
|   val dbRamRdEn   = Wire(Bool()) | ||||
|   val dbRamWrEnFinal   = Wire(Bool()) | ||||
|   val dbRamRdEnFinal   = Wire(Bool()) | ||||
|   require((cfg.nDebugRamBytes % ramDataBytes) == 0) | ||||
|   val dbRamDataOffset = log2Up(ramDataBytes) | ||||
|  | ||||
|  | ||||
|   // --- Debug Bus Accesses | ||||
|  | ||||
|   val dbRdEn   = Wire(Bool()) | ||||
|   val dbWrEn   = Wire(Bool()) | ||||
|   val dbRdData = Wire(UInt(width = DbBusConsts.dbDataSize)) | ||||
|  | ||||
|   val s_DB_READY :: s_DB_RESP :: Nil = Enum(Bits(), 2) | ||||
|   val dbStateReg = Reg(init = s_DB_READY) | ||||
|  | ||||
|   val dbResult  = Wire(io.db.resp.bits) | ||||
|  | ||||
|   val dbReq     = Wire(io.db.req.bits) | ||||
|   val dbRespReg = Reg(io.db.resp.bits)  | ||||
|  | ||||
|   val rdCondWrFailure = Wire(Bool()) | ||||
|   val dbWrNeeded = Wire(Bool()) | ||||
|  | ||||
|   //-------------------------------------------------------------- | ||||
|   // Interrupt Registers | ||||
|   //-------------------------------------------------------------- | ||||
|    | ||||
|   for (component <- 0 until cfg.nComponents) { | ||||
|     io.debugInterrupts(component) := interruptRegs(component) | ||||
|   } | ||||
|  | ||||
|   // Interrupt Registers are written by write to CONTROL or debugRAM addresses | ||||
|   // for Debug Bus, and cleared by writes to CLEARDEBINT by System Bus. | ||||
|   // It is "unspecified" what should happen if both | ||||
|   // SET and CLEAR happen at the same time. In this | ||||
|   // implementation, the SET wins. | ||||
|  | ||||
|   for (component <- 0 until cfg.nComponents) { | ||||
|     when (CONTROLWrEn) { | ||||
|       when (CONTROLWrData.hartid === UInt(component)) { | ||||
|         interruptRegs(component) := interruptRegs(component) | CONTROLWrData.interrupt | ||||
|       } | ||||
|     }.elsewhen (dbRamWrEn) { | ||||
|       when (CONTROLReg.hartid === UInt(component)){ | ||||
|         interruptRegs(component) := interruptRegs(component)  | RAMWrData.interrupt | ||||
|       } | ||||
|     }.elsewhen (CLEARDEBINTWrEn){ | ||||
|       when (CLEARDEBINTWrData === UInt(component, width = sbIdWidth)) { | ||||
|         interruptRegs(component) := Bool(false) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   //-------------------------------------------------------------- | ||||
|   // Halt Notification Registers | ||||
|   //-------------------------------------------------------------- | ||||
|  | ||||
|   // Halt Notifications Registers are cleared by zero write to CONTROL or debugRAM addresses | ||||
|   // for Debug Bus, and set by write to SETHALTNOT by System Bus. | ||||
|   // It is "unspecified" what should happen if both | ||||
|   // SET and CLEAR happen at the same time. In this | ||||
|   // implementation, the SET wins. | ||||
|    | ||||
|   for (component <- 0 until cfg.nComponents) { | ||||
|     when (SETHALTNOTWrEn){ | ||||
|       when (SETHALTNOTWrData === UInt(component, width = sbIdWidth)) { | ||||
|         haltnotRegs(component) := Bool(true) | ||||
|       } | ||||
|     } .elsewhen (CONTROLWrEn) { | ||||
|       when (CONTROLWrData.hartid === UInt(component)) { | ||||
|         haltnotRegs(component) := haltnotRegs(component) &  CONTROLWrData.haltnot | ||||
|       } | ||||
|     }.elsewhen (dbRamWrEn) { | ||||
|       when (CONTROLReg.hartid === UInt(component)){ | ||||
|         haltnotRegs(component) := haltnotRegs(component)  &  RAMWrData.haltnot | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   for (ii <- 0 until numHaltnotStatus) { | ||||
|     haltnotStatus(ii) := Cat(haltnotRegs.slice(ii * 32, (ii + 1) * 32).reverse) | ||||
|   } | ||||
|  | ||||
|   //-------------------------------------------------------------- | ||||
|   // Other Registers  | ||||
|   //-------------------------------------------------------------- | ||||
|  | ||||
|   CONTROLReset.interrupt     := Bool(false)  | ||||
|   CONTROLReset.haltnot       := Bool(false)  | ||||
|   CONTROLReset.reserved0     := Bits(0)      | ||||
|   CONTROLReset.buserror      := Bits(0) | ||||
|   CONTROLReset.serial        := Bits(0) | ||||
|   CONTROLReset.autoincrement := Bool(false) | ||||
|   CONTROLReset.access        := UInt(DebugModuleAccessType.Access32Bit.id) | ||||
|   CONTROLReset.hartid        := Bits(0) | ||||
|   CONTROLReset.ndreset       := Bool(false) | ||||
|   CONTROLReset.fullreset     := Bool(false) | ||||
|  | ||||
|   // Because this version of DebugModule doesn't | ||||
|   // support authentication, this entire register is | ||||
|   // Read-Only constant wires.  | ||||
|   DMINFORdData.reserved0     := Bits(0) | ||||
|   DMINFORdData.abussize      := UInt(0) // Not Implemented. | ||||
|   DMINFORdData.serialcount   := UInt(cfg.nSerialPorts) | ||||
|   DMINFORdData.access128     := Bool(cfg.hasAccess128) | ||||
|   DMINFORdData.access64      := Bool(cfg.hasAccess64) | ||||
|   DMINFORdData.access32      := Bool(cfg.hasAccess32) | ||||
|   DMINFORdData.access16      := Bool(cfg.hasAccess16) | ||||
|   DMINFORdData.accesss8      := Bool(cfg.hasAccess8) | ||||
|   DMINFORdData.dramsize      := Bits((cfg.nDebugRamBytes >> 2) - 1) // Size in 32-bit words minus 1. | ||||
|   DMINFORdData.haltsum       := Bool(cfg.hasHaltSum) | ||||
|   DMINFORdData.reserved1     := Bits(0) | ||||
|   DMINFORdData.authenticated := Bool(true)  // Not Implemented. | ||||
|   DMINFORdData.authbusy      := Bool(false) // Not Implemented. | ||||
|   DMINFORdData.authtype      := UInt(cfg.authType.id) | ||||
|   DMINFORdData.version       := UInt(1)     // Conforms to RISC-V Debug Spec | ||||
|  | ||||
|   HALTSUMRdData.serialfull  := Bool(false) // Not Implemented | ||||
|   HALTSUMRdData.serialvalid := Bool(false) // Not Implemented | ||||
|   HALTSUMRdData.acks        := haltnotSummary | ||||
|  | ||||
|   //-------------------------------------------------------------- | ||||
|   // Debug RAM Access (Debug Bus ... System Bus can override) | ||||
|   //-------------------------------------------------------------- | ||||
|  | ||||
|   dbReq := io.db.req.bits | ||||
|   // Debug Bus RAM Access | ||||
|   // From Specification: Debug RAM is 0x00 - 0x0F | ||||
|   //                                  0x40 - 0x6F Not Implemented | ||||
|   dbRamAddr   := dbReq.addr( ramAddrWidth-1 , 0) | ||||
|   dbRamWrData := dbReq.data | ||||
|   dbRamAddrValid := (dbReq.addr(3,0) <= UInt((cfg.nDebugRamBytes/ramDataBytes))) | ||||
|  | ||||
|   val dbRamRdDataFields = List.tabulate(cfg.nDebugRamBytes / ramDataBytes) { ii => | ||||
|     val slice = ramMem.slice(ii * ramDataBytes, (ii+1)*ramDataBytes) | ||||
|     slice.reduce[UInt]{ case (x: UInt, y: UInt) => Cat(y, x)} | ||||
|   } | ||||
|  | ||||
|   dbRamRdData := dbRamRdDataFields(dbRamAddr) | ||||
|  | ||||
|   when (dbRamWrEnFinal) { | ||||
|     for (ii <- 0 until ramDataBytes) { | ||||
|       ramMem((dbRamAddr << UInt(dbRamDataOffset)) + UInt(ii)) := dbRamWrData((8*(ii+1)-1), (8*ii)) | ||||
|     } | ||||
|   } | ||||
|    | ||||
|   //-------------------------------------------------------------- | ||||
|   // Debug Bus Access | ||||
|   //-------------------------------------------------------------- | ||||
|  | ||||
|   // 0x00 - 0x0F Debug RAM | ||||
|   // 0x10 - 0x1B Registers | ||||
|   // 0x1C - 0x3B Halt Notification Registers | ||||
|   // 0x3C - 0x3F Registers | ||||
|   // 0x40 - 0x6F Debug RAM | ||||
|  | ||||
|  | ||||
|   // ----------------------------------------- | ||||
|   // DB Access Write Decoder | ||||
|  | ||||
|   CONTROLWrData := new CONTROLFields().fromBits(dbReq.data) | ||||
|   RAMWrData     := new RAMFields().fromBits(dbReq.data) | ||||
|  | ||||
|   dbRamWrEn       := Bool(false) | ||||
|   dbRamWrEnFinal  := Bool(false) | ||||
|   CONTROLWrEn     := Bool(false) | ||||
|   when ((dbReq.addr >> 4) === Bits(0)) {  // 0x00 - 0x0F Debug RAM | ||||
|     dbRamWrEn := dbWrEn | ||||
|     when (dbRamAddrValid) { | ||||
|       dbRamWrEnFinal := dbWrEn | ||||
|     } | ||||
|   }.elsewhen (dbReq.addr === DMCONTROL) { | ||||
|     CONTROLWrEn  := dbWrEn | ||||
|   }.otherwise { | ||||
|     //Other registers/RAM are Not Implemented. | ||||
|   } | ||||
|  | ||||
|   when (reset) { | ||||
|     CONTROLReg := CONTROLReset | ||||
|     ndresetCtrReg := UInt(0) | ||||
|   }.elsewhen (CONTROLWrEn) { | ||||
|     // interrupt handled in other logic | ||||
|     // haltnot   handled in other logic | ||||
|     if (cfg.hasBusMaster){ | ||||
|       // buserror is set 'until 0 is written to any bit in this field'.  | ||||
|       CONTROLReg.buserror      := Mux(CONTROLWrData.buserror.andR, CONTROLReg.buserror, UInt(0)) | ||||
|       CONTROLReg.autoincrement := CONTROLWrData.autoincrement | ||||
|       CONTROLReg.access        := CONTROLWrData.access | ||||
|     } | ||||
|     if (cfg.nSerialPorts > 0){ | ||||
|       CONTROLReg.serial        := CONTROLWrData.serial | ||||
|     } | ||||
|     CONTROLReg.hartid        := CONTROLWrData.hartid | ||||
|     CONTROLReg.fullreset     := CONTROLReg.fullreset | CONTROLWrData.fullreset | ||||
|     when (CONTROLWrData.ndreset){ | ||||
|       ndresetCtrReg := UInt(cfg.nNDResetCycles) | ||||
|     }.otherwise { | ||||
|       ndresetCtrReg := Mux(ndresetCtrReg === UInt(0) , UInt(0), ndresetCtrReg - UInt(1))  | ||||
|     } | ||||
|   }.otherwise { | ||||
|     ndresetCtrReg := Mux(ndresetCtrReg === UInt(0) , UInt(0), ndresetCtrReg - UInt(1)) | ||||
|   } | ||||
|  | ||||
|   // ----------------------------------------- | ||||
|   // DB Access Read Mux | ||||
|   | ||||
|   CONTROLRdData := CONTROLReg; | ||||
|   CONTROLRdData.interrupt := interruptRegs(CONTROLReg.hartid) | ||||
|   CONTROLRdData.haltnot   := haltnotRegs(CONTROLReg.hartid) | ||||
|   CONTROLRdData.ndreset   := ndresetCtrReg.orR | ||||
|  | ||||
|   RAMRdData.interrupt := interruptRegs(CONTROLReg.hartid) | ||||
|   RAMRdData.haltnot   := haltnotRegs(CONTROLReg.hartid) | ||||
|   RAMRdData.data      := dbRamRdData | ||||
|  | ||||
|   dbRdData := UInt(0) | ||||
|  | ||||
|   // Higher numbers of numHaltnotStatus Not Implemented. | ||||
|   // This logic assumes only up to 128 components. | ||||
|   rdHaltnotStatus := Bits(0) | ||||
|   for (ii <- 0 until numHaltnotStatus) { | ||||
|     when (dbReq.addr(1, 0) === UInt(ii)) { | ||||
|       rdHaltnotStatus := haltnotStatus(ii) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   dbRamRdEn      := Bool(false) | ||||
|   dbRamRdEnFinal := Bool(false) | ||||
|   when ((dbReq.addr >> 4) === Bits(0)) { // 0x00 - 0x0F Debug RAM | ||||
|     dbRamRdEn := dbRdEn | ||||
|     when (dbRamAddrValid) { | ||||
|       dbRdData  := RAMRdData.asUInt | ||||
|       dbRamRdEnFinal := dbRdEn | ||||
|     } | ||||
|   }.elsewhen (dbReq.addr === DMCONTROL) { | ||||
|     dbRdData := CONTROLRdData.asUInt | ||||
|   }.elsewhen (dbReq.addr === DMINFO) { | ||||
|     dbRdData := DMINFORdData.asUInt | ||||
|   }.elsewhen (dbReq.addr === HALTSUM) { | ||||
|     if (cfg.hasHaltSum){ | ||||
|       dbRdData := HALTSUMRdData.asUInt | ||||
|     } else { | ||||
|       dbRdData := UInt(0) | ||||
|     } | ||||
|   }.elsewhen ((dbReq.addr >> 2) === UInt(7)) { // 0x1C - 0x1F Haltnot | ||||
|     dbRdData := rdHaltnotStatus | ||||
|   } .otherwise { | ||||
|     //These Registers are not implemented in this version of DebugModule: | ||||
|     // AUTHDATA0 | ||||
|     // AUTHDATA1 | ||||
|     // SERDATA | ||||
|     // SERSTATUS | ||||
|     // SBUSADDRESS0 | ||||
|     // SBUSADDRESS1 | ||||
|     // SBDATA0      | ||||
|     // SBDATA1      | ||||
|     // SBADDRESS2   | ||||
|     // SBDATA2      | ||||
|     // SBDATA3 | ||||
|     // 0x20 - 0x3B haltnot | ||||
|     // Upper bytes of Debug RAM. | ||||
|     dbRdData := UInt(0) | ||||
|   } | ||||
|      | ||||
|   // Conditional write fails if MSB is set of the read data. | ||||
|   rdCondWrFailure := dbRdData(dbDataSize - 1 ) && | ||||
|   (dbReq.op === db_OP_READ_COND_WRITE) | ||||
|  | ||||
|   dbWrNeeded := (dbReq.op === db_OP_READ_WRITE) || | ||||
|   ((dbReq.op === db_OP_READ_COND_WRITE) && ~rdCondWrFailure) | ||||
|  | ||||
|   // This is only relevant at end of s_DB_READ. | ||||
|   dbResult.resp := Mux(rdCondWrFailure, | ||||
|     db_RESP_FAILURE, | ||||
|     db_RESP_SUCCESS) | ||||
|   dbResult.data := dbRdData | ||||
|  | ||||
|   // ----------------------------------------- | ||||
|   // DB Access State Machine Decode (Combo) | ||||
|   io.db.req.ready := (dbStateReg === s_DB_READY) || | ||||
|   (dbStateReg === s_DB_RESP && io.db.resp.fire()) | ||||
|  | ||||
|   io.db.resp.valid := (dbStateReg === s_DB_RESP) | ||||
|   io.db.resp.bits  := dbRespReg | ||||
|  | ||||
|   dbRdEn := io.db.req.fire() | ||||
|   dbWrEn := dbWrNeeded && io.db.req.fire() | ||||
|  | ||||
|   // ----------------------------------------- | ||||
|   // DB Access State Machine Update (Seq) | ||||
|  | ||||
|   when (dbStateReg === s_DB_READY){ | ||||
|     when (io.db.req.fire()){ | ||||
|       dbStateReg := s_DB_RESP | ||||
|       dbRespReg := dbResult | ||||
|     } | ||||
|   } .elsewhen (dbStateReg === s_DB_RESP){ | ||||
|     when (io.db.req.fire()){ | ||||
|       dbStateReg := s_DB_RESP | ||||
|       dbRespReg := dbResult | ||||
|     }.elsewhen (io.db.resp.fire()){ | ||||
|       dbStateReg := s_DB_READY | ||||
|     } | ||||
|   } | ||||
|  | ||||
|    | ||||
|   //-------------------------------------------------------------- | ||||
|   // Debug ROM | ||||
|   //-------------------------------------------------------------- | ||||
|  | ||||
|   val romRegFields  =  if (cfg.hasDebugRom) { | ||||
|     cfg.debugRomContents.get.map( x => RegField.r(8, UInt(x.toInt & 0xFF))) | ||||
|   } else { | ||||
|     Seq(RegField(8)) | ||||
|   } | ||||
|  | ||||
|   //-------------------------------------------------------------- | ||||
|   // System Bus Access | ||||
|   //-------------------------------------------------------------- | ||||
|  | ||||
|   // Local reg mapper function : Notify when written, but give the value. | ||||
|   def wValue (n: Int, value: UInt, set: Bool) : RegField = { | ||||
|     RegField(n, value, RegWriteFn((valid, data) => {set := valid ; value := data; Bool(true)})) | ||||
|   } | ||||
|  | ||||
|   regmap( | ||||
|     CLEARDEBINT -> Seq(wValue(sbIdWidth, CLEARDEBINTWrData, CLEARDEBINTWrEn)), | ||||
|     SETHALTNOT  -> Seq(wValue(sbIdWidth, SETHALTNOTWrData, SETHALTNOTWrEn)), | ||||
|     RAMBASE     -> ramMem.map(x => RegField(8, x)), | ||||
|     ROMBASE     -> romRegFields | ||||
|   ) | ||||
|  | ||||
|   //-------------------------------------------------------------- | ||||
|   // Misc. Outputs | ||||
|   //-------------------------------------------------------------- | ||||
|  | ||||
|   io.ndreset   := ndresetCtrReg.orR | ||||
|   io.fullreset := CONTROLReg.fullreset | ||||
|  | ||||
| } | ||||
|  | ||||
| /** Create a concrete TL2 Slave for the DebugModule RegMapper interface. | ||||
|   *   | ||||
|   */ | ||||
|  | ||||
| class TLDebugModule(address: BigInt = 0)(implicit p: Parameters) | ||||
|   extends TLRegisterRouter(address, "debug", Nil, beatBytes=p(XLen)/8, executable=true)( | ||||
|   new TLRegBundle((), _ )    with DebugModuleBundle)( | ||||
|   new TLRegModule((), _, _)  with DebugModule) | ||||
|  | ||||
|  | ||||
| /** Synchronizers for DebugBus | ||||
|   *   | ||||
|   */ | ||||
|  | ||||
|  | ||||
| object AsyncDebugBusCrossing { | ||||
|   // takes from_source from the 'from' clock domain to the 'to' clock domain | ||||
|   def apply(from_clock: Clock, from_reset: Bool, from_source: DebugBusIO, to_clock: Clock, to_reset: Bool, depth: Int = 1, sync: Int = 3) = { | ||||
|     val to_sink = Wire(new DebugBusIO()(from_source.p)) | ||||
|     to_sink.req <> AsyncDecoupledCrossing(from_clock, from_reset, from_source.req, to_clock, to_reset, depth, sync) | ||||
|     from_source.resp <> AsyncDecoupledCrossing(to_clock, to_reset, to_sink.resp, from_clock, from_reset, depth, sync) | ||||
|     to_sink // is now to_source | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| object AsyncDebugBusFrom { // OutsideClockDomain | ||||
|   // takes from_source from the 'from' clock domain and puts it into your clock domain | ||||
|   def apply(from_clock: Clock, from_reset: Bool, from_source: DebugBusIO, depth: Int = 1, sync: Int = 3): DebugBusIO = { | ||||
|     val scope = AsyncScope() | ||||
|     AsyncDebugBusCrossing(from_clock, from_reset, from_source, scope.clock, scope.reset, depth, sync) | ||||
|   } | ||||
| } | ||||
|  | ||||
| object AsyncDebugBusTo { // OutsideClockDomain | ||||
|   // takes source from your clock domain and puts it into the 'to' clock domain | ||||
|   def apply(to_clock: Clock, to_reset: Bool, source: DebugBusIO, depth: Int = 1, sync: Int = 3): DebugBusIO = { | ||||
|     val scope = AsyncScope() | ||||
|     AsyncDebugBusCrossing(scope.clock, scope.reset, source, to_clock, to_reset, depth, sync) | ||||
|   } | ||||
| } | ||||
							
								
								
									
										1177
									
								
								src/main/scala/uncore/devices/debug/Debug.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1177
									
								
								src/main/scala/uncore/devices/debug/Debug.scala
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -45,13 +45,14 @@ module JTAGVPI | ||||
|         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); | ||||
| 	output jtag_TMS, | ||||
| 	output jtag_TCK, | ||||
| 	output jtag_TDI, | ||||
| 	input  jtag_TDO_data, | ||||
|         input  jtag_TDO_driven, | ||||
|  | ||||
| 	input  enable, | ||||
| 	input  init_done); | ||||
|  | ||||
|    reg                  tms; | ||||
|    reg                  tck; | ||||
| @@ -61,9 +62,8 @@ module JTAGVPI | ||||
|    assign jtag_TMS = tms; | ||||
|    assign jtag_TCK = tck; | ||||
|    assign jtag_TDI = tdi; | ||||
|    assign tdo = jtag_TDO; | ||||
|      | ||||
|     | ||||
|    assign tdo = jtag_TDO_driven ? jtag_TDO_data : 1'bz; | ||||
|        | ||||
| integer		cmd; | ||||
| integer		length; | ||||
| integer		nb_bits; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user