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:
		| @@ -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*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 | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user