Merge pull request #1183 from freechipsproject/regfield_descriptions
more detailed RegField descriptions
This commit is contained in:
commit
e2e678d53d
@ -15,6 +15,7 @@ lazy val commonSettings = Seq(
|
||||
traceLevel := 15,
|
||||
scalacOptions ++= Seq("-deprecation","-unchecked"),
|
||||
libraryDependencies ++= Seq("org.scala-lang" % "scala-reflect" % scalaVersion.value),
|
||||
libraryDependencies ++= Seq("org.json4s" %% "json4s-jackson" % "3.5.0"),
|
||||
addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full)
|
||||
)
|
||||
|
||||
@ -44,3 +45,4 @@ val chipSettings = Seq(
|
||||
s"make -C $makeDir -j $jobs $target".!
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -89,7 +89,7 @@ import DebugModuleAccessType._
|
||||
|
||||
object DebugAbstractCommandError extends scala.Enumeration {
|
||||
type DebugAbstractCommandError = Value
|
||||
val None, ErrBusy, ErrNotSupported, ErrException, ErrHaltResume = Value
|
||||
val Success, ErrBusy, ErrNotSupported, ErrException, ErrHaltResume = Value
|
||||
}
|
||||
import DebugAbstractCommandError._
|
||||
|
||||
@ -250,18 +250,18 @@ class DebugCtrlBundle (nComponents: Int)(implicit val p: Parameters) extends Par
|
||||
|
||||
// Local reg mapper function : Notify when written, but give the value as well.
|
||||
object WNotifyWire {
|
||||
def apply(n: Int, value: UInt, set: Bool) : RegField = {
|
||||
def apply(n: Int, value: UInt, set: Bool, name: String, desc: String) : RegField = {
|
||||
RegField(n, UInt(0), RegWriteFn((valid, data) => {
|
||||
set := valid
|
||||
value := data
|
||||
Bool(true)
|
||||
}))
|
||||
}), Some(RegFieldDesc(name = name, desc = desc, access = RegFieldAccessType.WSPECIAL)))
|
||||
}
|
||||
}
|
||||
|
||||
// Local reg mapper function : Notify when accessed either as read or write.
|
||||
object RWNotify {
|
||||
def apply (n: Int, rVal: UInt, wVal: UInt, rNotify: Bool, wNotify: Bool) : RegField = {
|
||||
def apply (n: Int, rVal: UInt, wVal: UInt, rNotify: Bool, wNotify: Bool, desc: Option[RegFieldDesc] = None): RegField = {
|
||||
RegField(n,
|
||||
RegReadFn ((ready) => {rNotify := ready ; (Bool(true), rVal)}),
|
||||
RegWriteFn((valid, data) => {
|
||||
@ -269,7 +269,7 @@ object RWNotify {
|
||||
when (valid) {wVal := data}
|
||||
Bool(true)
|
||||
}
|
||||
))
|
||||
), desc)
|
||||
}
|
||||
}
|
||||
|
||||
@ -344,7 +344,7 @@ class TLDebugModuleOuter(device: Device)(implicit p: Parameters) extends LazyMod
|
||||
// DMCONTROL is the only register, so it's at offset 0.
|
||||
dmiNode.regmap(
|
||||
0 -> Seq(RWNotify(32, DMCONTROLRdData.asUInt(),
|
||||
DMCONTROLWrDataVal, DMCONTROLRdEn, DMCONTROLWrEn))
|
||||
DMCONTROLWrDataVal, DMCONTROLRdEn, DMCONTROLWrEn, Some(RegFieldDesc("dmi_dmcontrol", "", reset=Some(0)))))
|
||||
)
|
||||
|
||||
//--------------------------------------------------------------
|
||||
@ -726,20 +726,25 @@ class TLDebugModuleInner(device: Device, getNComponents: () => Int)(implicit p:
|
||||
// Program Buffer Access (DMI ... System Bus can override)
|
||||
//--------------------------------------------------------------
|
||||
dmiNode.regmap(
|
||||
(DMI_DMSTATUS << 2) -> Seq(RegField.r(32, DMSTATUSRdData.asUInt())),
|
||||
(DMI_DMSTATUS << 2) -> Seq(RegField.r(32, DMSTATUSRdData.asUInt(), RegFieldDesc("dmi_dmstatus", ""))),
|
||||
//TODO (DMI_CFGSTRADDR0 << 2) -> cfgStrAddrFields,
|
||||
(DMI_HARTINFO << 2) -> Seq(RegField.r(32, HARTINFORdData.asUInt())),
|
||||
(DMI_HALTSUM << 2) -> Seq(RegField.r(32, HALTSUMRdData.asUInt())),
|
||||
(DMI_ABSTRACTCS << 2) -> Seq(RWNotify(32, ABSTRACTCSRdData.asUInt(), ABSTRACTCSWrDataVal, ABSTRACTCSRdEn, ABSTRACTCSWrEnMaybe)),
|
||||
(DMI_ABSTRACTAUTO<< 2) -> Seq(RWNotify(32, ABSTRACTAUTORdData.asUInt(), ABSTRACTAUTOWrDataVal, ABSTRACTAUTORdEn, ABSTRACTAUTOWrEnMaybe)),
|
||||
(DMI_COMMAND << 2) -> Seq(RWNotify(32, COMMANDRdData.asUInt(), COMMANDWrDataVal, COMMANDRdEn, COMMANDWrEnMaybe)),
|
||||
(DMI_DATA0 << 2) -> abstractDataMem.zipWithIndex.map{case (x, i) => RWNotify(8, x, abstractDataNxt(i),
|
||||
(DMI_HARTINFO << 2) -> Seq(RegField.r(32, HARTINFORdData.asUInt(), RegFieldDesc("dmi_hartinfo", "" /*, reset=Some(HARTINFORdData.litValue)*/))),
|
||||
(DMI_HALTSUM << 2) -> Seq(RegField.r(32, HALTSUMRdData.asUInt(), RegFieldDesc("dmi_haltsum", ""))),
|
||||
(DMI_ABSTRACTCS << 2) -> Seq(RWNotify(32, ABSTRACTCSRdData.asUInt(), ABSTRACTCSWrDataVal, ABSTRACTCSRdEn, ABSTRACTCSWrEnMaybe,
|
||||
Some(RegFieldDesc("dmi_abstractcs", "" /*, reset=Some(ABSTRACTCSReset.litValue)*/)))),
|
||||
(DMI_ABSTRACTAUTO<< 2) -> Seq(RWNotify(32, ABSTRACTAUTORdData.asUInt(), ABSTRACTAUTOWrDataVal, ABSTRACTAUTORdEn, ABSTRACTAUTOWrEnMaybe,
|
||||
Some(RegFieldDesc("dmi_abstractauto", "", reset=Some(0))))),
|
||||
(DMI_COMMAND << 2) -> Seq(RWNotify(32, COMMANDRdData.asUInt(), COMMANDWrDataVal, COMMANDRdEn, COMMANDWrEnMaybe,
|
||||
Some(RegFieldDesc("dmi_command", "", reset=Some(0))))),
|
||||
(DMI_DATA0 << 2) -> RegFieldGroup("dmi_data", None, abstractDataMem.zipWithIndex.map{case (x, i) => RWNotify(8, x, abstractDataNxt(i),
|
||||
dmiAbstractDataRdEn(i),
|
||||
dmiAbstractDataWrEnMaybe(i))},
|
||||
(DMI_PROGBUF0 << 2) -> programBufferMem.zipWithIndex.map{case (x, i) => RWNotify(8, x, programBufferNxt(i),
|
||||
dmiAbstractDataWrEnMaybe(i),
|
||||
Some(RegFieldDesc(s"dmi_data_$i", "", reset = Some(0))))}),
|
||||
(DMI_PROGBUF0 << 2) -> RegFieldGroup("dmi_progbuf", None, programBufferMem.zipWithIndex.map{case (x, i) => RWNotify(8, x, programBufferNxt(i),
|
||||
dmiProgramBufferRdEn(i),
|
||||
dmiProgramBufferWrEnMaybe(i))},
|
||||
(DMIConsts.dmi_haltStatusAddr << 2) -> haltedStatus.map(x => RegField.r(32, x))
|
||||
dmiProgramBufferWrEnMaybe(i),
|
||||
Some(RegFieldDesc(s"dmi_progbuf_$i", "", reset = Some(0))))}),
|
||||
(DMIConsts.dmi_haltStatusAddr << 2) -> RegFieldGroup("dmi_halt_status", None, haltedStatus.zipWithIndex.map{case (x, i) => RegField.r(32, x, RegFieldDesc(s"halt_status_$i", ""))})
|
||||
)
|
||||
|
||||
abstractDataMem.zipWithIndex.foreach { case (x, i) =>
|
||||
@ -880,20 +885,28 @@ class TLDebugModuleInner(device: Device, getNComponents: () => Int)(implicit p:
|
||||
|
||||
tlNode.regmap(
|
||||
// This memory is writable.
|
||||
HALTED -> Seq(WNotifyWire(sbIdWidth, hartHaltedId, hartHaltedWrEn)),
|
||||
GOING -> Seq(WNotifyWire(sbIdWidth, hartGoingId, hartGoingWrEn)),
|
||||
RESUMING -> Seq(WNotifyWire(sbIdWidth, hartResumingId, hartResumingWrEn)),
|
||||
EXCEPTION -> Seq(WNotifyWire(sbIdWidth, hartExceptionId, hartExceptionWrEn)),
|
||||
DATA -> abstractDataMem.map(x => RegField(8, x)),
|
||||
PROGBUF(cfg)-> programBufferMem.map(x => RegField(8, x)),
|
||||
HALTED -> Seq(WNotifyWire(sbIdWidth, hartHaltedId, hartHaltedWrEn,
|
||||
"debug_hart_halted", "Debug ROM Causes hart to write its hartID here when it is in Debug Mode.")),
|
||||
GOING -> Seq(WNotifyWire(sbIdWidth, hartGoingId, hartGoingWrEn,
|
||||
"debug_hart_going", "Debug ROM causes hart to write 0 here when it begins executing Debug Mode instructions.")),
|
||||
RESUMING -> Seq(WNotifyWire(sbIdWidth, hartResumingId, hartResumingWrEn,
|
||||
"debug_hart_resuming", "Debug ROM causes hart to write 0 here when it leaves Debug Mode.")),
|
||||
EXCEPTION -> Seq(WNotifyWire(sbIdWidth, hartExceptionId, hartExceptionWrEn,
|
||||
"debug_hart_exception", "Debug ROM causes hart to write 0 here if it gets an exception in Debug Mode.")),
|
||||
DATA -> RegFieldGroup("debug_data", Some("Data used to communicate with Debug Module"),
|
||||
abstractDataMem.zipWithIndex.map {case (x, i) => RegField(8, x, RegFieldDesc(s"debug_data_$i", ""))}),
|
||||
PROGBUF(cfg)-> RegFieldGroup("debug_progbuf", Some("Program buffer used to communicate with Debug Module"),
|
||||
programBufferMem.zipWithIndex.map {case (x, i) => RegField(8, x, RegFieldDesc(s"debug_progbuf_$i", ""))}),
|
||||
|
||||
// These sections are read-only.
|
||||
IMPEBREAK(cfg)-> {if (cfg.hasImplicitEbreak) Seq(RegField.r(32, Instructions.EBREAK.value.U)) else Nil},
|
||||
WHERETO -> Seq(RegField.r(32, jalAbstract.asUInt)),
|
||||
ABSTRACT(cfg) -> abstractGeneratedMem.map{x => RegField.r(32, x)},
|
||||
FLAGS -> flags.map{x => RegField.r(8, x.asUInt())},
|
||||
ROMBASE -> DebugRomContents().map(x => RegField.r(8, (x & 0xFF).U(8.W)))
|
||||
|
||||
IMPEBREAK(cfg)-> {if (cfg.hasImplicitEbreak) Seq(RegField.r(32, Instructions.EBREAK.value.U, RegFieldDesc("debug_impebreak", "Debug Implicit EBREAK"))) else Nil},
|
||||
WHERETO -> Seq(RegField.r(32, jalAbstract.asUInt, RegFieldDesc("debug_whereto", "Instruction filled in by Debug Module to control hart in Debug Mode"))),
|
||||
ABSTRACT(cfg) -> RegFieldGroup("debug_abstract", Some("Instructions generated by Debug Module"),
|
||||
abstractGeneratedMem.zipWithIndex.map{ case (x,i) => RegField.r(32, x, RegFieldDesc(s"debug_abstract_$i", ""))}),
|
||||
FLAGS -> RegFieldGroup("debug_flags", Some("Memory region used to control hart going/resuming in Debug Mode"),
|
||||
flags.zipWithIndex.map{case(x, i) => RegField.r(8, x.asUInt(), RegFieldDesc(s"debug_flags_$i", ""))}),
|
||||
ROMBASE -> RegFieldGroup("debug_rom", Some("Debug ROM"),
|
||||
DebugRomContents().zipWithIndex.map{case (x, i) => RegField.r(8, (x & 0xFF).U(8.W), RegFieldDesc(s"debug_rom_$i", "", reset=Some(x)))})
|
||||
)
|
||||
|
||||
// Override System Bus accesses with dmactive reset.
|
||||
|
@ -83,9 +83,11 @@ class CoreplexLocalInterrupter(params: ClintParams)(implicit p: Parameters) exte
|
||||
*/
|
||||
|
||||
node.regmap(
|
||||
0 -> ipi.map(r => RegField(ipiWidth, r)),
|
||||
timecmpOffset(0) -> timecmp.flatMap(RegField.bytes(_)),
|
||||
timeOffset -> RegField.bytes(time))
|
||||
0 -> RegFieldGroup ("msip", Some("MSIP Bits"), ipi.zipWithIndex.map{ case (r, i) => RegField(ipiWidth, r, RegFieldDesc(s"msip_$i", s"MSIP bit for Hart $i", reset=Some(0)))}),
|
||||
timecmpOffset(0) -> timecmp.zipWithIndex.flatMap{ case (t, i) =>
|
||||
RegFieldGroup(s"mtimecmp_$i", Some(s"MTIMECMP for hart $i"), RegField.bytes(t, Some(RegFieldDesc(s"mtimecmp_$i", "", reset=None))))},
|
||||
timeOffset -> RegFieldGroup("mtime", Some("Timer Register"), RegField.bytes(time, Some(RegFieldDesc("mtime", "", reset=Some(0)))))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,12 +169,18 @@ class TLPLIC(params: PLICParams)(implicit p: Parameters) extends LazyModule
|
||||
harts(hart) := ShiftRegister(Reg(next = maxPri) > Cat(UInt(1), threshold(hart)), params.intStages)
|
||||
}
|
||||
|
||||
def priorityRegField(x: UInt) = if (nPriorities > 0) RegField(32, x) else RegField.r(32, x)
|
||||
val priorityRegFields = Seq(PLICConsts.priorityBase -> priority.map(p => priorityRegField(p)))
|
||||
val pendingRegFields = Seq(PLICConsts.pendingBase -> pending .map(b => RegField.r(1, b)))
|
||||
def priorityRegDesc(i: Int) = RegFieldDesc(s"priority_$i", s"Acting priority of interrupt source $i", reset=if (nPriorities > 0) None else Some(1))
|
||||
def pendingRegDesc(i: Int) = RegFieldDesc(s"pending_$i", s"Set to 1 if interrupt source $i is pending, regardless of its enable or priority setting.")
|
||||
def priorityRegField(x: UInt, i: Int) = if (nPriorities > 0) RegField(32, x, priorityRegDesc(i)) else RegField.r(32, x, priorityRegDesc(i))
|
||||
val priorityRegFields = Seq(PLICConsts.priorityBase -> RegFieldGroup("priority", Some("Acting priorities of each interrupt source. 32 bits for each interrupt source."),
|
||||
priority.zipWithIndex.map{case (p, i) => priorityRegField(p, i)}))
|
||||
val pendingRegFields = Seq(PLICConsts.pendingBase -> RegFieldGroup("pending", Some("Pending Bit Array. 1 Bit for each interrupt source."),
|
||||
pending.zipWithIndex.map{case (b, i) => RegField.r(1, b, pendingRegDesc(i))}))
|
||||
|
||||
|
||||
val enableRegFields = enables.zipWithIndex.map { case (e, i) =>
|
||||
PLICConsts.enableBase(i) -> e.map(b => RegField(1, b))
|
||||
PLICConsts.enableBase(i) -> RegFieldGroup(s"enables_${i}", Some(s"Enable bits for each interrupt source for target $i. 1 bit for each interrupt source."),
|
||||
e.zipWithIndex.map{case (b, j) => RegField(1, b, RegFieldDesc(s"enable_${i}_${j}", s"Enable interrupt for source $j for target $i.", reset=None))})
|
||||
}
|
||||
|
||||
// When a hart reads a claim/complete register, then the
|
||||
@ -208,9 +214,12 @@ class TLPLIC(params: PLICParams)(implicit p: Parameters) extends LazyModule
|
||||
g.complete := c
|
||||
}
|
||||
|
||||
def thresholdRegDesc(i: Int) = RegFieldDesc(s"threshold_$i", s"Interrupt & claim threshold for target $i", reset=if (nPriorities > 0) None else Some(1))
|
||||
def thresholdRegField(x: UInt, i: Int) = if (nPriorities > 0) RegField(32, x, thresholdRegDesc(i)) else RegField.r(32, x, thresholdRegDesc(i))
|
||||
|
||||
val hartRegFields = Seq.tabulate(nHarts) { i =>
|
||||
PLICConsts.hartBase(i) -> Seq(
|
||||
priorityRegField(threshold(i)),
|
||||
thresholdRegField(threshold(i), i),
|
||||
RegField(32,
|
||||
RegReadFn { valid =>
|
||||
claimer(i) := valid
|
||||
@ -222,10 +231,15 @@ class TLPLIC(params: PLICParams)(implicit p: Parameters) extends LazyModule
|
||||
completerDev := data.extract(log2Ceil(nDevices+1)-1, 0)
|
||||
completer(i) := valid && enables(i)(completerDev)
|
||||
Bool(true)
|
||||
}
|
||||
},
|
||||
Some(RegFieldDesc(s"claim_complete_$i",
|
||||
s"Claim/Complete register for Target $i. Reading this register returns the claimed interrupt number and makes it no longer pending." +
|
||||
s"Writing the interrupt number back completes the interrupt.",
|
||||
reset = None,
|
||||
access = RegFieldAccessType.RWSPECIAL))
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
node.regmap((priorityRegFields ++ pendingRegFields ++ enableRegFields ++ hartRegFields):_*)
|
||||
|
||||
|
@ -7,6 +7,46 @@ import chisel3.util.{ReadyValidIO}
|
||||
|
||||
import freechips.rocketchip.util.{SimpleRegIO}
|
||||
|
||||
|
||||
// This information is not used internally by the regmap(...) function.
|
||||
// However, the author of a RegField may be the best person to provide this
|
||||
// information which is likely to be needed by downstream SW and Documentation
|
||||
// tools.
|
||||
|
||||
object RegFieldAccessType extends scala.Enumeration {
|
||||
type RegFieldAccessType = Value
|
||||
val R, W, RW, RSPECIAL, WSPECIAL, RWSPECIAL, OTHER = Value
|
||||
}
|
||||
import RegFieldAccessType._
|
||||
|
||||
case class RegFieldDesc (
|
||||
name: String,
|
||||
desc: String,
|
||||
group: Option[String] = None,
|
||||
groupDesc: Option[String] = None,
|
||||
access: RegFieldAccessType = RegFieldAccessType.RW,
|
||||
reset: Option[BigInt] = None,
|
||||
enumerations: Map[String, BigInt] = Map()
|
||||
){
|
||||
}
|
||||
|
||||
// Our descriptions are in terms of RegFields only, which is somewhat unusual for
|
||||
// developers who are used to things being defined as bitfields within registers.
|
||||
// The "Group" allows a string & (optional) description to be added which describes the conceptual "Group"
|
||||
// the RegField belongs to. This can be used by downstream flows as they see fit to
|
||||
// present the information.
|
||||
|
||||
object RegFieldGroup {
|
||||
def apply (name: String, desc: Option[String], regs: Seq[RegField], descFirstOnly: Boolean = true): Seq[RegField] = {
|
||||
regs.zipWithIndex.map {case (r, i) =>
|
||||
val gDesc = if ((i > 0) & descFirstOnly) None else desc
|
||||
r.desc.map { d =>
|
||||
r.copy(desc = Some(d.copy(group = Some(name), groupDesc = gDesc)) )
|
||||
}.getOrElse(r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case class RegReadFn private(combinational: Boolean, fn: (Bool, Bool) => (Bool, Bool, UInt))
|
||||
object RegReadFn
|
||||
{
|
||||
@ -73,11 +113,11 @@ object RegWriteFn
|
||||
implicit def apply(x: Unit): RegWriteFn = RegWriteFn((valid, data) => { Bool(true) })
|
||||
}
|
||||
|
||||
case class RegField(width: Int, read: RegReadFn, write: RegWriteFn, name: String, description: String)
|
||||
case class RegField(width: Int, read: RegReadFn, write: RegWriteFn, desc: Option[RegFieldDesc])
|
||||
{
|
||||
require (width > 0, s"RegField width must be > 0, not $width")
|
||||
def pipelined = !read.combinational || !write.combinational
|
||||
def readOnly = this.copy(write = ())
|
||||
def readOnly = this.copy(write = (), desc = this.desc.map(_.copy(access = RegFieldAccessType.R)))
|
||||
}
|
||||
|
||||
object RegField
|
||||
@ -85,51 +125,62 @@ object RegField
|
||||
// Byte address => sequence of bitfields, lowest index => lowest address
|
||||
type Map = (Int, Seq[RegField])
|
||||
|
||||
def apply(n: Int) : RegField = apply(n, (), (), "", "")
|
||||
def apply(n: Int, r: RegReadFn, w: RegWriteFn) : RegField = apply(n, r, w, "", "")
|
||||
def apply(n: Int, rw: UInt) : RegField = apply(n, rw, rw, "", "")
|
||||
def apply(n: Int, rw: UInt, name: String, description: String) : RegField = apply(n, rw, rw, name, description)
|
||||
def r(n: Int, r: RegReadFn, name: String = "", description: String = "") : RegField = apply(n, r, (), name, description)
|
||||
def w(n: Int, w: RegWriteFn, name: String = "", description: String = "") : RegField = apply(n, (), w, name, description)
|
||||
def apply(n: Int) : RegField = apply(n, (), (),
|
||||
Some(RegFieldDesc("reserved", "", access = RegFieldAccessType.R, reset = Some(0))))
|
||||
|
||||
def apply(n: Int, r: RegReadFn, w: RegWriteFn) : RegField = apply(n, r, w, None)
|
||||
def apply(n: Int, r: RegReadFn, w: RegWriteFn, desc: RegFieldDesc) : RegField = apply(n, r, w, Some(desc))
|
||||
def apply(n: Int, rw: UInt) : RegField = apply(n, rw, rw, None)
|
||||
def apply(n: Int, rw: UInt, desc: RegFieldDesc) : RegField = apply(n, rw, rw, Some(desc))
|
||||
def r(n: Int, r: RegReadFn) : RegField = apply(n, r, (), None)
|
||||
def r(n: Int, r: RegReadFn, desc: RegFieldDesc) : RegField = apply(n, r, (), Some(desc.copy(access = RegFieldAccessType.R)))
|
||||
def w(n: Int, w: RegWriteFn) : RegField = apply(n, (), w, None)
|
||||
def w(n: Int, w: RegWriteFn, desc: RegFieldDesc) : RegField = apply(n, (), w, Some(desc.copy(access = RegFieldAccessType.W)))
|
||||
|
||||
// This RegField allows 'set' to set bits in 'reg'.
|
||||
// and to clear bits when the bus writes bits of value 1.
|
||||
// Setting takes priority over clearing.
|
||||
def w1ToClear(n: Int, reg: UInt, set: UInt): RegField =
|
||||
RegField(n, reg, RegWriteFn((valid, data) => { reg := ~(~reg | Mux(valid, data, UInt(0))) | set; Bool(true) }))
|
||||
def w1ToClear(n: Int, reg: UInt, set: UInt, desc: Option[RegFieldDesc] = None): RegField =
|
||||
RegField(n, reg, RegWriteFn((valid, data) => { reg := ~(~reg | Mux(valid, data, UInt(0))) | set; Bool(true) }),
|
||||
desc.map{_.copy(access = RegFieldAccessType.RWSPECIAL)})
|
||||
|
||||
// This RegField wraps an explicit register
|
||||
// (e.g. Black-Boxed Register) to create a R/W register.
|
||||
def rwReg(n: Int, bb: SimpleRegIO, name: String = "", description: String = "") : RegField =
|
||||
def rwReg(n: Int, bb: SimpleRegIO, desc: Option[RegFieldDesc] = None) : RegField =
|
||||
RegField(n, bb.q, RegWriteFn((valid, data) => {
|
||||
bb.en := valid
|
||||
bb.d := data
|
||||
Bool(true)
|
||||
}), name, description)
|
||||
}), desc.map{_.copy(access = RegFieldAccessType.RW)})
|
||||
|
||||
// Create byte-sized read-write RegFields out of a large UInt register.
|
||||
// It is updated when any of the bytes are written. Because the RegFields
|
||||
// are all byte-sized, this is also suitable when a register is larger
|
||||
// than the intended bus width of the device (atomic updates are impossible).
|
||||
def bytes(reg: UInt, numBytes: Int): Seq[RegField] = {
|
||||
val pad = reg | UInt(0, width = 8*numBytes)
|
||||
// than the intended bus width of the device (atomic updates are impossible).
|
||||
def bytes(reg: UInt, numBytes: Int, desc: Option[RegFieldDesc]): Seq[RegField] = {
|
||||
val pad = reg | UInt(0, width = 8*numBytes)
|
||||
val oldBytes = Vec.tabulate(numBytes) { i => pad(8*(i+1)-1, 8*i) }
|
||||
val newBytes = Wire(init = oldBytes)
|
||||
val valids = Wire(init = Vec.fill(numBytes) { Bool(false) })
|
||||
when (valids.reduce(_ || _)) { reg := newBytes.asUInt }
|
||||
Seq.tabulate(numBytes) { i =>
|
||||
val newDesc = desc.map {d => d.copy(name = d.name + s"[${(i+1)*8-1}:${i*8}]")}
|
||||
RegField(8, oldBytes(i),
|
||||
RegWriteFn((valid, data) => {
|
||||
valids(i) := valid
|
||||
when (valid) { newBytes(i) := data }
|
||||
Bool(true)
|
||||
}))}}
|
||||
}), newDesc)}}
|
||||
|
||||
def bytes(reg: UInt): Seq[RegField] = {
|
||||
def bytes(reg: UInt, desc: Option[RegFieldDesc]): Seq[RegField] = {
|
||||
val width = reg.getWidth
|
||||
require (width % 8 == 0, s"RegField.bytes must be called on byte-sized reg, not ${width} bits")
|
||||
bytes(reg, width/8)
|
||||
bytes(reg, width/8, desc)
|
||||
}
|
||||
|
||||
def bytes(reg: UInt, numBytes: Int): Seq[RegField] = bytes(reg, numBytes, None)
|
||||
def bytes(reg: UInt): Seq[RegField] = bytes(reg, None)
|
||||
|
||||
}
|
||||
|
||||
trait HasRegMap
|
||||
@ -138,4 +189,4 @@ trait HasRegMap
|
||||
val interrupts: Vec[Bool]
|
||||
}
|
||||
|
||||
// See GPIO.scala for an example of how to use regmap
|
||||
// See Example.scala for an example of how to use regmap
|
||||
|
@ -144,10 +144,13 @@ object RegMapper
|
||||
val (f_wiready, f_wovalid) = field.write.fn(f_wivalid, f_woready, data(high, low))
|
||||
|
||||
// cover reads and writes to register
|
||||
cover(f_rivalid && f_riready, field.name + "_Reg_read_start", field.description + " RegField Read Request Initiate")
|
||||
cover(f_rovalid && f_roready, field.name + "_Reg_read_out", field.description + " RegField Read Request Complete")
|
||||
cover(f_wivalid && f_wiready, field.name + "_Reg_write_start", field.description + " RegField Write Request Initiate")
|
||||
cover(f_wovalid && f_woready, field.name + "_Reg_write_out", field.description + " RegField Write Request Complete")
|
||||
val fname = field.desc.map{_.name}.getOrElse("")
|
||||
val fdesc = field.desc.map{_.desc + ":"}.getOrElse("")
|
||||
|
||||
cover(f_rivalid && f_riready, fname + "_Reg_read_start", fdesc + " RegField Read Request Initiate")
|
||||
cover(f_rovalid && f_roready, fname + "_Reg_read_out", fdesc + " RegField Read Request Complete")
|
||||
cover(f_wivalid && f_wiready, fname + "_Reg_write_start", fdesc + " RegField Write Request Initiate")
|
||||
cover(f_wovalid && f_woready, fname + "_Reg_write_out", fdesc + " RegField Write Request Complete")
|
||||
|
||||
def litOR(x: Bool, y: Bool) = if (x.isLit && x.litValue == 1) Bool(true) else x || y
|
||||
// Add this field to the ready-valid signals for the register
|
||||
|
@ -20,7 +20,7 @@ trait ExampleModule extends HasRegMap
|
||||
val io: ExampleBundle
|
||||
val interrupts: Vec[Bool]
|
||||
|
||||
val state = RegInit(UInt(0))
|
||||
val state = RegInit(UInt(0, width = params.num))
|
||||
val pending = RegInit(UInt(0xf, width = 4))
|
||||
|
||||
io.gpio := state
|
||||
@ -28,9 +28,15 @@ trait ExampleModule extends HasRegMap
|
||||
|
||||
regmap(
|
||||
0 -> Seq(
|
||||
RegField(params.num, state)),
|
||||
RegField(params.num, state,
|
||||
RegFieldDesc("state", "State: Example of a R/W Register with description.", reset = Some(0)))),
|
||||
4 -> Seq(
|
||||
RegField.w1ToClear(4, pending, state)))
|
||||
RegField.w1ToClear(4, pending, state,
|
||||
Some(RegFieldDesc("pending", "Pending: Example of a special (W1ToC) Register. " +
|
||||
"Writing a bit here causes it to be reset to 0. " +
|
||||
"The bits are set when the corresponding bit in 'state' is high.",
|
||||
reset=Some(0xF)))))
|
||||
)
|
||||
}
|
||||
|
||||
// Create a concrete TL2 version of the abstract Example slave
|
||||
|
@ -7,9 +7,12 @@ import freechips.rocketchip.config.Parameters
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.regmapper._
|
||||
import freechips.rocketchip.interrupts._
|
||||
import freechips.rocketchip.util.HeterogeneousBag
|
||||
import freechips.rocketchip.util.{HeterogeneousBag, ElaborationArtefacts}
|
||||
import scala.math.{min,max}
|
||||
|
||||
import org.json4s.JsonDSL._
|
||||
import org.json4s.jackson.JsonMethods.{pretty, render}
|
||||
|
||||
case class TLRegisterNode(
|
||||
address: Seq[AddressSet],
|
||||
device: Device,
|
||||
@ -80,6 +83,35 @@ case class TLRegisterNode(
|
||||
bundleIn.b.valid := Bool(false)
|
||||
bundleIn.c.ready := Bool(true)
|
||||
bundleIn.e.ready := Bool(true)
|
||||
|
||||
// Dump out the register map for documentation purposes.
|
||||
val regDescs = mapping.flatMap { case (offset, seq) =>
|
||||
var currentBitOffset = 0
|
||||
seq.zipWithIndex.map { case (f, i) => {
|
||||
val tmp = (f.desc.map{ _.name}.getOrElse(s"unnamedRegField${i}") -> (
|
||||
("byteOffset" -> s"0x${offset.toHexString}") ~
|
||||
("bitOffset" -> currentBitOffset) ~
|
||||
("bitWidth" -> f.width) ~
|
||||
("name" -> f.desc.map(_.name)) ~
|
||||
("description" -> f.desc.map{ d=> if (d.desc == "") None else Some(d.desc)}) ~
|
||||
("resetValue" -> f.desc.map{_.reset}) ~
|
||||
("group" -> f.desc.map{_.group}) ~
|
||||
("groupDesc" -> f.desc.map{_.groupDesc}) ~
|
||||
("accessType" -> f.desc.map {d => d.access.toString})
|
||||
))
|
||||
currentBitOffset = currentBitOffset + f.width
|
||||
tmp
|
||||
}}
|
||||
}
|
||||
|
||||
//TODO: It would be better to name this other than "Device at ...."
|
||||
val base = s"0x${address.head.base.toInt.toHexString}"
|
||||
val json = ("peripheral" -> (
|
||||
("displayName" -> s"deviceAt${base}") ~
|
||||
("baseAddress" -> base) ~
|
||||
("regfields" -> regDescs)
|
||||
))
|
||||
ElaborationArtefacts.add(s"${base}.regmap.json", pretty(render(json)))
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user