2016-11-28 01:16:37 +01:00
|
|
|
// See LICENSE.SiFive for license details.
|
2016-08-26 23:15:37 +02:00
|
|
|
|
2017-07-07 19:48:16 +02:00
|
|
|
package freechips.rocketchip.regmapper
|
2016-08-26 23:15:37 +02:00
|
|
|
|
|
|
|
import Chisel._
|
2016-10-02 09:00:32 +02:00
|
|
|
import chisel3.util.{ReadyValidIO}
|
2017-07-07 19:48:16 +02:00
|
|
|
|
|
|
|
import freechips.rocketchip.util.{SimpleRegIO}
|
2016-09-09 05:01:03 +02:00
|
|
|
|
2018-01-08 20:20:37 +01:00
|
|
|
|
|
|
|
// 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,
|
2018-02-28 18:42:25 +01:00
|
|
|
enumerations: Map[BigInt, (String, String)] = Map()
|
2018-01-08 20:20:37 +01:00
|
|
|
){
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-30 00:33:10 +02:00
|
|
|
case class RegReadFn private(combinational: Boolean, fn: (Bool, Bool) => (Bool, Bool, UInt))
|
|
|
|
object RegReadFn
|
|
|
|
{
|
|
|
|
// (ivalid: Bool, oready: Bool) => (iready: Bool, ovalid: Bool, data: UInt)
|
|
|
|
// iready may combinationally depend on oready
|
|
|
|
// all other combinational dependencies forbidden (e.g. ovalid <= ivalid)
|
2016-09-03 06:42:37 +02:00
|
|
|
// effects must become visible on the cycle after ovalid && oready
|
2016-10-02 09:00:32 +02:00
|
|
|
// data is only inspected when ovalid && oready
|
2016-08-30 00:33:10 +02:00
|
|
|
implicit def apply(x: (Bool, Bool) => (Bool, Bool, UInt)) =
|
|
|
|
new RegReadFn(false, x)
|
2016-09-14 00:26:59 +02:00
|
|
|
implicit def apply(x: RegisterReadIO[UInt]): RegReadFn =
|
|
|
|
RegReadFn((ivalid, oready) => {
|
|
|
|
x.request.valid := ivalid
|
|
|
|
x.response.ready := oready
|
|
|
|
(x.request.ready, x.response.valid, x.response.bits)
|
|
|
|
})
|
2016-09-03 06:42:37 +02:00
|
|
|
// (ready: Bool) => (valid: Bool, data: UInt)
|
|
|
|
// valid must not combinationally depend on ready
|
|
|
|
// effects must become visible on the cycle after valid && ready
|
|
|
|
implicit def apply(x: Bool => (Bool, UInt)) =
|
2016-08-30 00:33:10 +02:00
|
|
|
new RegReadFn(true, { case (_, oready) =>
|
2016-09-03 06:42:37 +02:00
|
|
|
val (ovalid, data) = x(oready)
|
|
|
|
(Bool(true), ovalid, data)
|
2016-08-30 00:33:10 +02:00
|
|
|
})
|
2016-10-02 09:00:32 +02:00
|
|
|
// read from a ReadyValidIO (only safe if there is a consistent source of data)
|
|
|
|
implicit def apply(x: ReadyValidIO[UInt]):RegReadFn = RegReadFn(ready => { x.ready := ready; (x.valid, x.bits) })
|
2016-08-30 00:33:10 +02:00
|
|
|
// read from a register
|
2016-09-03 07:34:51 +02:00
|
|
|
implicit def apply(x: UInt):RegReadFn = RegReadFn(ready => (Bool(true), x))
|
2016-08-30 00:33:10 +02:00
|
|
|
// noop
|
2016-09-03 07:34:51 +02:00
|
|
|
implicit def apply(x: Unit):RegReadFn = RegReadFn(UInt(0))
|
2016-08-30 00:33:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
case class RegWriteFn private(combinational: Boolean, fn: (Bool, Bool, UInt) => (Bool, Bool))
|
|
|
|
object RegWriteFn
|
|
|
|
{
|
|
|
|
// (ivalid: Bool, oready: Bool, data: UInt) => (iready: Bool, ovalid: Bool)
|
|
|
|
// iready may combinationally depend on both oready and data
|
|
|
|
// all other combinational dependencies forbidden (e.g. ovalid <= ivalid)
|
2016-09-03 06:42:37 +02:00
|
|
|
// effects must become visible on the cycle after ovalid && oready
|
2016-10-02 09:00:32 +02:00
|
|
|
// data should only be used for an effect when ivalid && iready
|
2016-08-30 00:33:10 +02:00
|
|
|
implicit def apply(x: (Bool, Bool, UInt) => (Bool, Bool)) =
|
|
|
|
new RegWriteFn(false, x)
|
2016-09-14 00:26:59 +02:00
|
|
|
implicit def apply(x: RegisterWriteIO[UInt]): RegWriteFn =
|
|
|
|
RegWriteFn((ivalid, oready, data) => {
|
|
|
|
x.request.valid := ivalid
|
|
|
|
x.request.bits := data
|
|
|
|
x.response.ready := oready
|
|
|
|
(x.request.ready, x.response.valid)
|
|
|
|
})
|
2016-09-03 06:42:37 +02:00
|
|
|
// (valid: Bool, data: UInt) => (ready: Bool)
|
|
|
|
// ready may combinationally depend on data (but not valid)
|
|
|
|
// effects must become visible on the cycle after valid && ready
|
|
|
|
implicit def apply(x: (Bool, UInt) => Bool) =
|
|
|
|
// combinational => data valid on oready
|
2016-08-30 00:33:10 +02:00
|
|
|
new RegWriteFn(true, { case (_, oready, data) =>
|
2016-09-03 06:42:37 +02:00
|
|
|
(Bool(true), x(oready, data))
|
2016-08-30 00:33:10 +02:00
|
|
|
})
|
2016-10-02 09:00:32 +02:00
|
|
|
// write to a DecoupledIO (only safe if there is a consistent sink draining data)
|
|
|
|
// NOTE: this is not an IrrevocableIO (even on TL2) because other fields could cause a lowered valid
|
|
|
|
implicit def apply(x: DecoupledIO[UInt]): RegWriteFn = RegWriteFn((valid, data) => { x.valid := valid; x.bits := data; x.ready })
|
2016-09-08 22:46:56 +02:00
|
|
|
// updates a register (or adds a mux to a wire)
|
2016-09-03 07:34:51 +02:00
|
|
|
implicit def apply(x: UInt): RegWriteFn = RegWriteFn((valid, data) => { when (valid) { x := data }; Bool(true) })
|
2016-08-30 00:33:10 +02:00
|
|
|
// noop
|
2016-09-03 07:34:51 +02:00
|
|
|
implicit def apply(x: Unit): RegWriteFn = RegWriteFn((valid, data) => { Bool(true) })
|
2016-08-30 00:33:10 +02:00
|
|
|
}
|
|
|
|
|
2018-01-08 20:20:37 +01:00
|
|
|
case class RegField(width: Int, read: RegReadFn, write: RegWriteFn, desc: Option[RegFieldDesc])
|
2016-08-27 00:48:48 +02:00
|
|
|
{
|
2017-07-11 06:07:50 +02:00
|
|
|
require (width > 0, s"RegField width must be > 0, not $width")
|
2016-08-30 00:33:10 +02:00
|
|
|
def pipelined = !read.combinational || !write.combinational
|
2018-01-08 20:20:37 +01:00
|
|
|
def readOnly = this.copy(write = (), desc = this.desc.map(_.copy(access = RegFieldAccessType.R)))
|
2016-08-27 00:48:48 +02:00
|
|
|
}
|
|
|
|
|
2016-08-26 23:15:37 +02:00
|
|
|
object RegField
|
|
|
|
{
|
2016-09-23 04:49:29 +02:00
|
|
|
// Byte address => sequence of bitfields, lowest index => lowest address
|
2016-08-26 23:15:37 +02:00
|
|
|
type Map = (Int, Seq[RegField])
|
2016-09-23 04:49:29 +02:00
|
|
|
|
2018-01-08 20:20:37 +01:00
|
|
|
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)))
|
2016-09-08 22:46:56 +02:00
|
|
|
|
|
|
|
// 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.
|
2018-01-08 20:20:37 +01:00
|
|
|
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)})
|
2016-09-09 05:01:03 +02:00
|
|
|
|
|
|
|
// This RegField wraps an explicit register
|
|
|
|
// (e.g. Black-Boxed Register) to create a R/W register.
|
2018-01-08 20:20:37 +01:00
|
|
|
def rwReg(n: Int, bb: SimpleRegIO, desc: Option[RegFieldDesc] = None) : RegField =
|
2016-09-09 05:01:03 +02:00
|
|
|
RegField(n, bb.q, RegWriteFn((valid, data) => {
|
|
|
|
bb.en := valid
|
|
|
|
bb.d := data
|
|
|
|
Bool(true)
|
2018-01-08 20:20:37 +01:00
|
|
|
}), desc.map{_.copy(access = RegFieldAccessType.RW)})
|
2017-07-11 06:08:02 +02:00
|
|
|
|
|
|
|
// 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
|
2018-01-08 20:20:37 +01:00
|
|
|
// 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)
|
2017-12-01 01:38:45 +01:00
|
|
|
val oldBytes = Vec.tabulate(numBytes) { i => pad(8*(i+1)-1, 8*i) }
|
|
|
|
val newBytes = Wire(init = oldBytes)
|
2017-07-11 06:08:02 +02:00
|
|
|
val valids = Wire(init = Vec.fill(numBytes) { Bool(false) })
|
2017-12-01 01:38:45 +01:00
|
|
|
when (valids.reduce(_ || _)) { reg := newBytes.asUInt }
|
|
|
|
Seq.tabulate(numBytes) { i =>
|
2018-02-15 22:25:06 +01:00
|
|
|
val newDesc = desc.map {d => d.copy(name = d.name + s"_$i")}
|
2017-12-01 01:38:45 +01:00
|
|
|
RegField(8, oldBytes(i),
|
|
|
|
RegWriteFn((valid, data) => {
|
2017-07-11 06:08:02 +02:00
|
|
|
valids(i) := valid
|
2017-12-01 01:38:45 +01:00
|
|
|
when (valid) { newBytes(i) := data }
|
2017-07-11 06:08:02 +02:00
|
|
|
Bool(true)
|
2018-01-08 20:20:37 +01:00
|
|
|
}), newDesc)}}
|
2017-10-11 04:49:19 +02:00
|
|
|
|
2018-01-08 20:20:37 +01:00
|
|
|
def bytes(reg: UInt, desc: Option[RegFieldDesc]): Seq[RegField] = {
|
2017-10-11 04:49:19 +02:00
|
|
|
val width = reg.getWidth
|
|
|
|
require (width % 8 == 0, s"RegField.bytes must be called on byte-sized reg, not ${width} bits")
|
2018-01-08 20:20:37 +01:00
|
|
|
bytes(reg, width/8, desc)
|
2017-10-11 04:49:19 +02:00
|
|
|
}
|
2018-01-08 20:20:37 +01:00
|
|
|
|
|
|
|
def bytes(reg: UInt, numBytes: Int): Seq[RegField] = bytes(reg, numBytes, None)
|
|
|
|
def bytes(reg: UInt): Seq[RegField] = bytes(reg, None)
|
|
|
|
|
2016-08-26 23:15:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
trait HasRegMap
|
|
|
|
{
|
|
|
|
def regmap(mapping: RegField.Map*): Unit
|
2016-09-09 00:17:30 +02:00
|
|
|
val interrupts: Vec[Bool]
|
2016-08-26 23:15:37 +02:00
|
|
|
}
|
2016-08-30 00:33:10 +02:00
|
|
|
|
2018-01-08 20:20:37 +01:00
|
|
|
// See Example.scala for an example of how to use regmap
|