Register Field: Add a more verbose description object
Add versions of the RegField functions to take it in, and update Example device to use it.
This commit is contained in:
parent
1bfdfacda0
commit
4ab1585a78
@ -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*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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user