1
0

Merge pull request #1183 from freechipsproject/regfield_descriptions

more detailed RegField descriptions
This commit is contained in:
Megan Wachs 2018-02-12 14:25:06 -08:00 committed by GitHub
commit e2e678d53d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 189 additions and 66 deletions

View File

@ -15,6 +15,7 @@ lazy val commonSettings = Seq(
traceLevel := 15, traceLevel := 15,
scalacOptions ++= Seq("-deprecation","-unchecked"), scalacOptions ++= Seq("-deprecation","-unchecked"),
libraryDependencies ++= Seq("org.scala-lang" % "scala-reflect" % scalaVersion.value), 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) addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full)
) )
@ -44,3 +45,4 @@ val chipSettings = Seq(
s"make -C $makeDir -j $jobs $target".! s"make -C $makeDir -j $jobs $target".!
} }
) )

View File

@ -89,7 +89,7 @@ import DebugModuleAccessType._
object DebugAbstractCommandError extends scala.Enumeration { object DebugAbstractCommandError extends scala.Enumeration {
type DebugAbstractCommandError = Value type DebugAbstractCommandError = Value
val None, ErrBusy, ErrNotSupported, ErrException, ErrHaltResume = Value val Success, ErrBusy, ErrNotSupported, ErrException, ErrHaltResume = Value
} }
import DebugAbstractCommandError._ 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. // Local reg mapper function : Notify when written, but give the value as well.
object WNotifyWire { 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) => { RegField(n, UInt(0), RegWriteFn((valid, data) => {
set := valid set := valid
value := data value := data
Bool(true) Bool(true)
})) }), Some(RegFieldDesc(name = name, desc = desc, access = RegFieldAccessType.WSPECIAL)))
} }
} }
// Local reg mapper function : Notify when accessed either as read or write. // Local reg mapper function : Notify when accessed either as read or write.
object RWNotify { 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, RegField(n,
RegReadFn ((ready) => {rNotify := ready ; (Bool(true), rVal)}), RegReadFn ((ready) => {rNotify := ready ; (Bool(true), rVal)}),
RegWriteFn((valid, data) => { RegWriteFn((valid, data) => {
@ -269,7 +269,7 @@ object RWNotify {
when (valid) {wVal := data} when (valid) {wVal := data}
Bool(true) 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. // DMCONTROL is the only register, so it's at offset 0.
dmiNode.regmap( dmiNode.regmap(
0 -> Seq(RWNotify(32, DMCONTROLRdData.asUInt(), 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) // Program Buffer Access (DMI ... System Bus can override)
//-------------------------------------------------------------- //--------------------------------------------------------------
dmiNode.regmap( 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, //TODO (DMI_CFGSTRADDR0 << 2) -> cfgStrAddrFields,
(DMI_HARTINFO << 2) -> Seq(RegField.r(32, HARTINFORdData.asUInt())), (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())), (DMI_HALTSUM << 2) -> Seq(RegField.r(32, HALTSUMRdData.asUInt(), RegFieldDesc("dmi_haltsum", ""))),
(DMI_ABSTRACTCS << 2) -> Seq(RWNotify(32, ABSTRACTCSRdData.asUInt(), ABSTRACTCSWrDataVal, ABSTRACTCSRdEn, ABSTRACTCSWrEnMaybe)), (DMI_ABSTRACTCS << 2) -> Seq(RWNotify(32, ABSTRACTCSRdData.asUInt(), ABSTRACTCSWrDataVal, ABSTRACTCSRdEn, ABSTRACTCSWrEnMaybe,
(DMI_ABSTRACTAUTO<< 2) -> Seq(RWNotify(32, ABSTRACTAUTORdData.asUInt(), ABSTRACTAUTOWrDataVal, ABSTRACTAUTORdEn, ABSTRACTAUTOWrEnMaybe)), Some(RegFieldDesc("dmi_abstractcs", "" /*, reset=Some(ABSTRACTCSReset.litValue)*/)))),
(DMI_COMMAND << 2) -> Seq(RWNotify(32, COMMANDRdData.asUInt(), COMMANDWrDataVal, COMMANDRdEn, COMMANDWrEnMaybe)), (DMI_ABSTRACTAUTO<< 2) -> Seq(RWNotify(32, ABSTRACTAUTORdData.asUInt(), ABSTRACTAUTOWrDataVal, ABSTRACTAUTORdEn, ABSTRACTAUTOWrEnMaybe,
(DMI_DATA0 << 2) -> abstractDataMem.zipWithIndex.map{case (x, i) => RWNotify(8, x, abstractDataNxt(i), 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), dmiAbstractDataRdEn(i),
dmiAbstractDataWrEnMaybe(i))}, dmiAbstractDataWrEnMaybe(i),
(DMI_PROGBUF0 << 2) -> programBufferMem.zipWithIndex.map{case (x, i) => RWNotify(8, x, programBufferNxt(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), dmiProgramBufferRdEn(i),
dmiProgramBufferWrEnMaybe(i))}, dmiProgramBufferWrEnMaybe(i),
(DMIConsts.dmi_haltStatusAddr << 2) -> haltedStatus.map(x => RegField.r(32, x)) 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) => abstractDataMem.zipWithIndex.foreach { case (x, i) =>
@ -880,20 +885,28 @@ class TLDebugModuleInner(device: Device, getNComponents: () => Int)(implicit p:
tlNode.regmap( tlNode.regmap(
// This memory is writable. // This memory is writable.
HALTED -> Seq(WNotifyWire(sbIdWidth, hartHaltedId, hartHaltedWrEn)), HALTED -> Seq(WNotifyWire(sbIdWidth, hartHaltedId, hartHaltedWrEn,
GOING -> Seq(WNotifyWire(sbIdWidth, hartGoingId, hartGoingWrEn)), "debug_hart_halted", "Debug ROM Causes hart to write its hartID here when it is in Debug Mode.")),
RESUMING -> Seq(WNotifyWire(sbIdWidth, hartResumingId, hartResumingWrEn)), GOING -> Seq(WNotifyWire(sbIdWidth, hartGoingId, hartGoingWrEn,
EXCEPTION -> Seq(WNotifyWire(sbIdWidth, hartExceptionId, hartExceptionWrEn)), "debug_hart_going", "Debug ROM causes hart to write 0 here when it begins executing Debug Mode instructions.")),
DATA -> abstractDataMem.map(x => RegField(8, x)), RESUMING -> Seq(WNotifyWire(sbIdWidth, hartResumingId, hartResumingWrEn,
PROGBUF(cfg)-> programBufferMem.map(x => RegField(8, x)), "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. // These sections are read-only.
IMPEBREAK(cfg)-> {if (cfg.hasImplicitEbreak) Seq(RegField.r(32, Instructions.EBREAK.value.U)) else Nil}, 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)), WHERETO -> Seq(RegField.r(32, jalAbstract.asUInt, RegFieldDesc("debug_whereto", "Instruction filled in by Debug Module to control hart in Debug Mode"))),
ABSTRACT(cfg) -> abstractGeneratedMem.map{x => RegField.r(32, x)}, ABSTRACT(cfg) -> RegFieldGroup("debug_abstract", Some("Instructions generated by Debug Module"),
FLAGS -> flags.map{x => RegField.r(8, x.asUInt())}, abstractGeneratedMem.zipWithIndex.map{ case (x,i) => RegField.r(32, x, RegFieldDesc(s"debug_abstract_$i", ""))}),
ROMBASE -> DebugRomContents().map(x => RegField.r(8, (x & 0xFF).U(8.W))) 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. // Override System Bus accesses with dmactive reset.

View File

@ -83,9 +83,11 @@ class CoreplexLocalInterrupter(params: ClintParams)(implicit p: Parameters) exte
*/ */
node.regmap( node.regmap(
0 -> ipi.map(r => RegField(ipiWidth, r)), 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.flatMap(RegField.bytes(_)), timecmpOffset(0) -> timecmp.zipWithIndex.flatMap{ case (t, i) =>
timeOffset -> RegField.bytes(time)) 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)))))
)
} }
} }

View File

@ -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) 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) def priorityRegDesc(i: Int) = RegFieldDesc(s"priority_$i", s"Acting priority of interrupt source $i", reset=if (nPriorities > 0) None else Some(1))
val priorityRegFields = Seq(PLICConsts.priorityBase -> priority.map(p => priorityRegField(p))) 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.")
val pendingRegFields = Seq(PLICConsts.pendingBase -> pending .map(b => RegField.r(1, b))) 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) => 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 // 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 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 => val hartRegFields = Seq.tabulate(nHarts) { i =>
PLICConsts.hartBase(i) -> Seq( PLICConsts.hartBase(i) -> Seq(
priorityRegField(threshold(i)), thresholdRegField(threshold(i), i),
RegField(32, RegField(32,
RegReadFn { valid => RegReadFn { valid =>
claimer(i) := valid claimer(i) := valid
@ -222,7 +231,12 @@ class TLPLIC(params: PLICParams)(implicit p: Parameters) extends LazyModule
completerDev := data.extract(log2Ceil(nDevices+1)-1, 0) completerDev := data.extract(log2Ceil(nDevices+1)-1, 0)
completer(i) := valid && enables(i)(completerDev) completer(i) := valid && enables(i)(completerDev)
Bool(true) 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))
) )
) )
} }

View File

@ -7,6 +7,46 @@ import chisel3.util.{ReadyValidIO}
import freechips.rocketchip.util.{SimpleRegIO} 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)) case class RegReadFn private(combinational: Boolean, fn: (Bool, Bool) => (Bool, Bool, UInt))
object RegReadFn object RegReadFn
{ {
@ -73,11 +113,11 @@ object RegWriteFn
implicit def apply(x: Unit): RegWriteFn = RegWriteFn((valid, data) => { Bool(true) }) 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") require (width > 0, s"RegField width must be > 0, not $width")
def pipelined = !read.combinational || !write.combinational 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 object RegField
@ -85,51 +125,62 @@ object RegField
// Byte address => sequence of bitfields, lowest index => lowest address // Byte address => sequence of bitfields, lowest index => lowest address
type Map = (Int, Seq[RegField]) type Map = (Int, Seq[RegField])
def apply(n: Int) : RegField = apply(n, (), (), "", "") def apply(n: Int) : RegField = apply(n, (), (),
def apply(n: Int, r: RegReadFn, w: RegWriteFn) : RegField = apply(n, r, w, "", "") Some(RegFieldDesc("reserved", "", access = RegFieldAccessType.R, reset = Some(0))))
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 apply(n: Int, r: RegReadFn, w: RegWriteFn) : RegField = apply(n, r, w, None)
def r(n: Int, r: RegReadFn, name: String = "", description: String = "") : RegField = apply(n, r, (), name, description) def apply(n: Int, r: RegReadFn, w: RegWriteFn, desc: RegFieldDesc) : RegField = apply(n, r, w, Some(desc))
def w(n: Int, w: RegWriteFn, name: String = "", description: String = "") : RegField = apply(n, (), w, name, description) 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'. // This RegField allows 'set' to set bits in 'reg'.
// and to clear bits when the bus writes bits of value 1. // and to clear bits when the bus writes bits of value 1.
// Setting takes priority over clearing. // Setting takes priority over clearing.
def w1ToClear(n: Int, reg: UInt, set: UInt): RegField = 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) })) 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 // This RegField wraps an explicit register
// (e.g. Black-Boxed Register) to create a R/W 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) => { RegField(n, bb.q, RegWriteFn((valid, data) => {
bb.en := valid bb.en := valid
bb.d := data bb.d := data
Bool(true) Bool(true)
}), name, description) }), desc.map{_.copy(access = RegFieldAccessType.RW)})
// Create byte-sized read-write RegFields out of a large UInt register. // 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 // 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 // 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). // than the intended bus width of the device (atomic updates are impossible).
def bytes(reg: UInt, numBytes: Int): Seq[RegField] = { def bytes(reg: UInt, numBytes: Int, desc: Option[RegFieldDesc]): Seq[RegField] = {
val pad = reg | UInt(0, width = 8*numBytes) val pad = reg | UInt(0, width = 8*numBytes)
val oldBytes = Vec.tabulate(numBytes) { i => pad(8*(i+1)-1, 8*i) } val oldBytes = Vec.tabulate(numBytes) { i => pad(8*(i+1)-1, 8*i) }
val newBytes = Wire(init = oldBytes) val newBytes = Wire(init = oldBytes)
val valids = Wire(init = Vec.fill(numBytes) { Bool(false) }) val valids = Wire(init = Vec.fill(numBytes) { Bool(false) })
when (valids.reduce(_ || _)) { reg := newBytes.asUInt } when (valids.reduce(_ || _)) { reg := newBytes.asUInt }
Seq.tabulate(numBytes) { i => 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), RegField(8, oldBytes(i),
RegWriteFn((valid, data) => { RegWriteFn((valid, data) => {
valids(i) := valid valids(i) := valid
when (valid) { newBytes(i) := data } when (valid) { newBytes(i) := data }
Bool(true) Bool(true)
}))}} }), newDesc)}}
def bytes(reg: UInt): Seq[RegField] = { def bytes(reg: UInt, desc: Option[RegFieldDesc]): Seq[RegField] = {
val width = reg.getWidth val width = reg.getWidth
require (width % 8 == 0, s"RegField.bytes must be called on byte-sized reg, not ${width} bits") 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 trait HasRegMap
@ -138,4 +189,4 @@ trait HasRegMap
val interrupts: Vec[Bool] 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

View File

@ -144,10 +144,13 @@ object RegMapper
val (f_wiready, f_wovalid) = field.write.fn(f_wivalid, f_woready, data(high, low)) val (f_wiready, f_wovalid) = field.write.fn(f_wivalid, f_woready, data(high, low))
// cover reads and writes to register // cover reads and writes to register
cover(f_rivalid && f_riready, field.name + "_Reg_read_start", field.description + " RegField Read Request Initiate") val fname = field.desc.map{_.name}.getOrElse("")
cover(f_rovalid && f_roready, field.name + "_Reg_read_out", field.description + " RegField Read Request Complete") val fdesc = field.desc.map{_.desc + ":"}.getOrElse("")
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") 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 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 // Add this field to the ready-valid signals for the register

View File

@ -20,7 +20,7 @@ trait ExampleModule extends HasRegMap
val io: ExampleBundle val io: ExampleBundle
val interrupts: Vec[Bool] val interrupts: Vec[Bool]
val state = RegInit(UInt(0)) val state = RegInit(UInt(0, width = params.num))
val pending = RegInit(UInt(0xf, width = 4)) val pending = RegInit(UInt(0xf, width = 4))
io.gpio := state io.gpio := state
@ -28,9 +28,15 @@ trait ExampleModule extends HasRegMap
regmap( regmap(
0 -> Seq( 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( 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 // Create a concrete TL2 version of the abstract Example slave

View File

@ -7,9 +7,12 @@ import freechips.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy._ import freechips.rocketchip.diplomacy._
import freechips.rocketchip.regmapper._ import freechips.rocketchip.regmapper._
import freechips.rocketchip.interrupts._ import freechips.rocketchip.interrupts._
import freechips.rocketchip.util.HeterogeneousBag import freechips.rocketchip.util.{HeterogeneousBag, ElaborationArtefacts}
import scala.math.{min,max} import scala.math.{min,max}
import org.json4s.JsonDSL._
import org.json4s.jackson.JsonMethods.{pretty, render}
case class TLRegisterNode( case class TLRegisterNode(
address: Seq[AddressSet], address: Seq[AddressSet],
device: Device, device: Device,
@ -80,6 +83,35 @@ case class TLRegisterNode(
bundleIn.b.valid := Bool(false) bundleIn.b.valid := Bool(false)
bundleIn.c.ready := Bool(true) bundleIn.c.ready := Bool(true)
bundleIn.e.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)))
} }
} }