1
0

Combine Coreplex and System Module Hierarchies (#875)

* coreplex collapse: peripherals now in coreplex

* coreplex: better factoring of TLBusWrapper attachement points

* diplomacy: allow monitorless :*= and :=*

* rocket: don't connect monitors to tile tim slave ports

* rename chip package to system

* coreplex: only sbus has a splitter

* TLFragmenter: Continuing my spot battles on requires without explanatory strings

* pbus: toFixedWidthSingleBeatSlave

* tilelink: more verbose requires

* use the new system package for regression

* sbus: add more explicit FIFO attachment points

* delete leftover top-level utils

* cleanup ResetVector and RTC
This commit is contained in:
Henry Cook
2017-07-23 08:31:04 -07:00
committed by Yunsup Lee
parent f2002839eb
commit 01ca3efc2b
59 changed files with 1536 additions and 1632 deletions

View File

@ -61,11 +61,11 @@ object DsbRegAddrs{
// We want DATA to immediately follow PROGBUF so that we can
// use them interchangeably.
def PROGBUF(cfg:DebugModuleConfig) = {DATA - (cfg.nProgramBufferWords * 4)}
def PROGBUF(cfg:DebugModuleParams) = {DATA - (cfg.nProgramBufferWords * 4)}
// We want abstract to be immediately before PROGBUF
// because we auto-generate 2 instructions.
def ABSTRACT(cfg:DebugModuleConfig) = PROGBUF(cfg) - 8
def ABSTRACT(cfg:DebugModuleParams) = PROGBUF(cfg) - 8
def FLAGS = 0x400
def ROMBASE = 0x800
@ -112,7 +112,7 @@ import DebugAbstractCommandType._
* supportHartArray : Whether or not to implement the hart array register.
**/
case class DebugModuleConfig (
case class DebugModuleParams (
nDMIAddrSize : Int = 7,
nProgramBufferWords: Int = 16,
nAbstractDataWords : Int = 4,
@ -152,17 +152,17 @@ case class DebugModuleConfig (
}
object DefaultDebugModuleConfig {
object DefaultDebugModuleParams {
def apply(xlen:Int /*TODO , val configStringAddr: Int*/): DebugModuleConfig = {
new DebugModuleConfig().copy(
def apply(xlen:Int /*TODO , val configStringAddr: Int*/): DebugModuleParams = {
new DebugModuleParams().copy(
nAbstractDataWords = (if (xlen == 32) 1 else if (xlen == 64) 2 else 4)
)
}
}
case object DMKey extends Field[DebugModuleConfig]
case object DebugModuleParams extends Field[DebugModuleParams]
// *****************************************
// Module Interfaces
@ -192,7 +192,7 @@ class DMIResp( ) extends Bundle {
* Therefore it has the 'flipped' version of this.
*/
class DMIIO(implicit val p: Parameters) extends ParameterizedBundle()(p) {
val req = new DecoupledIO(new DMIReq(p(DMKey).nDMIAddrSize))
val req = new DecoupledIO(new DMIReq(p(DebugModuleParams).nDMIAddrSize))
val resp = new DecoupledIO(new DMIResp).flip()
}
@ -443,7 +443,7 @@ class TLDebugModuleInner(device: Device, getNComponents: () => Int)(implicit p:
lazy val module = new LazyModuleImp(this){
val cfg = p(DMKey)
val cfg = p(DebugModuleParams)
val nComponents = getNComponents()

View File

@ -0,0 +1,262 @@
// See LICENSE.SiFive for license details.
package freechips.rocketchip.devices.debug
import Chisel._
import freechips.rocketchip.config._
import freechips.rocketchip.jtag._
import freechips.rocketchip.util._
case class JtagDTMConfig (
idcodeVersion : Int, // chosen by manuf.
idcodePartNum : Int, // Chosen by manuf.
idcodeManufId : Int, // Assigned by JEDEC
// Note: the actual manufId is passed in through a wire.
// Do not forget to wire up io.jtag_mfr_id through your top-level to set the
// mfr_id for this core.
// If you wish to use this field in the config, you can obtain it along
// the lines of p(JtagDTMKey).idcodeManufId.U(11.W).
debugIdleCycles : Int)
case object JtagDTMKey extends Field[JtagDTMConfig]
class JtagDTMKeyDefault extends JtagDTMConfig(
idcodeVersion = 0,
idcodePartNum = 0,
idcodeManufId = 0,
debugIdleCycles = 5) // Reasonable guess for synchronization.
object dtmJTAGAddrs {
def IDCODE = 0x1
def DTM_INFO = 0x10
def DMI_ACCESS = 0x11
}
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)
}
/** A wrapper around JTAG providing a reset signal and manufacturer id. */
class SystemJTAGIO extends Bundle {
val jtag = new JTAGIO(hasTRSTn = false).flip
val reset = Bool(INPUT)
val mfr_id = UInt(INPUT, 11)
}
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)) // TODO: re-use SystemJTAGIO here?
val jtag_reset = Bool(INPUT)
val jtag_mfr_id = UInt(INPUT, 11)
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 dmiResp = Wire(new DMIAccessCapture(debugAddrBits))
val nopResp = 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.
// But there is actually no case in the current design where you SHOULD get an error,
// as we haven't implemented Bus Masters or Serial Ports, which are the only cases errors
// can occur.
nonzeroResp := stickyNonzeroRespReg | (io.dmi.resp.valid & (io.dmi.resp.bits.resp != UInt(0)))
assert(!nonzeroResp, "There is no reason to get a non zero response in the current system.");
assert(!stickyNonzeroRespReg, "There is no reason to have a sticky non zero response in the current system.");
busyResp.addr := UInt(0)
busyResp.resp := Fill(DMIConsts.dmiRespSize, 1.U) // Generalizing busy to 'all-F'
busyResp.data := UInt(0)
dmiResp.addr := dmiReqReg.addr
dmiResp.resp := io.dmi.resp.bits.resp
dmiResp.data := io.dmi.resp.bits.data
nopResp.addr := UInt(0)
nopResp.resp := UInt(0)
nopResp.data := UInt(0)
//--------------------------------------------------------
// Debug Access Chain Implementation
dmiAccessChain.io.capture.bits := Mux(busy, busyResp, Mux(io.dmi.resp.valid, dmiResp, nopResp))
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
val dmiReqValidCheck = Wire(init = Bool(false))
assert(!(dmiReqValidCheck && io.dmi.req.fire()), "Conflicting updates for dmiReqValidReg, should not happen.");
when (dmiAccessChain.io.update.valid) {
when (skipOpReg) {
// Do Nothing
}.elsewhen (downgradeOpReg || (dmiAccessChain.io.update.bits.op === DMIConsts.dmi_OP_NONE)) {
//Do Nothing
dmiReqReg.addr := UInt(0)
dmiReqReg.data := UInt(0)
dmiReqReg.op := UInt(0)
}.otherwise {
dmiReqReg := dmiAccessChain.io.update.bits
dmiReqValidReg := Bool(true)
dmiReqValidCheck := Bool(true)
}
}
when (io.dmi.req.fire()) {
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 idcode = Wire(init = new JTAGIdcodeBundle().fromBits(0.U))
idcode.always1 := 1.U
idcode.version := c.idcodeVersion.U
idcode.partNumber := c.idcodePartNum.U
idcode.mfrId := io.jtag_mfr_id
val tapIO = JtagTapGenerator(irLength = 5,
instructions = Map(dtmJTAGAddrs.DMI_ACCESS -> dmiAccessChain,
dtmJTAGAddrs.DTM_INFO -> dtmInfoChain),
icode = Some(dtmJTAGAddrs.IDCODE)
)
tapIO.idcode.get := idcode
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
}

View File

@ -0,0 +1,123 @@
// See LICENSE.SiFive for license details.
package freechips.rocketchip.devices.debug
import Chisel._
import freechips.rocketchip.config.{Field, Parameters}
import freechips.rocketchip.coreplex.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]
/** A wrapper bundle containing one of the two possible debug interfaces */
class DebugIO(implicit p: Parameters) extends ParameterizedBundle()(p) {
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())
debug.node := pbus.toVariableWidthSlaves
}
trait HasPeripheryDebugBundle {
implicit val p: Parameters
val debug: DebugIO
def connectDebug(c: Clock, r: Bool, out: Bool) {
debug.clockeddmi.foreach { d =>
val dtm = Module(new SimDTM).connect(c, r, d, out)
}
debug.systemjtag.foreach { sj =>
val jtag = Module(new JTAGVPI).connect(sj.jtag, sj.reset, r, out)
sj.mfr_id := p(JtagDTMKey).idcodeManufId.U(11.W)
}
}
}
trait HasPeripheryDebugModuleImp extends LazyMultiIOModuleImp 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
outer.debug.module.io.dmi.dmiReset := ResetCatchAndSync(sj.jtag.TCK, sj.reset, "dmiResetCatch")
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 JTAGVPI(implicit val p: Parameters) extends BlackBox {
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)
}
}