Merge pull request #1279 from freechipsproject/ipxact_descs
More IP-XACT-like RegFieldDesc
This commit is contained in:
commit
78dad3e89b
@ -254,7 +254,8 @@ object WNotifyWire {
|
|||||||
set := valid
|
set := valid
|
||||||
value := data
|
value := data
|
||||||
Bool(true)
|
Bool(true)
|
||||||
}), Some(RegFieldDesc(name = name, desc = desc, access = RegFieldAccessType.WSPECIAL)))
|
}), Some(RegFieldDesc(name = name, desc = desc,
|
||||||
|
access = RegFieldAccessType.W)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -898,12 +899,13 @@ class TLDebugModuleInner(device: Device, getNComponents: () => Int, beatBytes: I
|
|||||||
programBufferMem.zipWithIndex.map {case (x, i) => RegField(8, x, RegFieldDesc(s"debug_progbuf_$i", ""))}),
|
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, RegFieldDesc("debug_impebreak", "Debug Implicit EBREAK"))) else Nil},
|
IMPEBREAK(cfg)-> {if (cfg.hasImplicitEbreak) Seq(RegField.r(32, Instructions.EBREAK.value.U,
|
||||||
WHERETO -> Seq(RegField.r(32, jalAbstract.asUInt, RegFieldDesc("debug_whereto", "Instruction filled in by Debug Module to control hart in Debug Mode"))),
|
RegFieldDesc("debug_impebreak", "Debug Implicit EBREAK", reset=Some(Instructions.EBREAK.value)))) else Nil},
|
||||||
|
WHERETO -> Seq(RegField.r(32, jalAbstract.asUInt, RegFieldDesc("debug_whereto", "Instruction filled in by Debug Module to control hart in Debug Mode", volatile = true))),
|
||||||
ABSTRACT(cfg) -> RegFieldGroup("debug_abstract", Some("Instructions generated by Debug Module"),
|
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", ""))}),
|
abstractGeneratedMem.zipWithIndex.map{ case (x,i) => RegField.r(32, x, RegFieldDesc(s"debug_abstract_$i", "", volatile=true))}),
|
||||||
FLAGS -> RegFieldGroup("debug_flags", Some("Memory region used to control hart going/resuming in Debug Mode"),
|
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", ""))}),
|
flags.zipWithIndex.map{case(x, i) => RegField.r(8, x.asUInt(), RegFieldDesc(s"debug_flags_$i", "", volatile=true))}),
|
||||||
ROMBASE -> RegFieldGroup("debug_rom", Some("Debug ROM"),
|
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)))})
|
DebugRomContents().zipWithIndex.map{case (x, i) => RegField.r(8, (x & 0xFF).U(8.W), RegFieldDesc(s"debug_rom_$i", "", reset=Some(x)))})
|
||||||
)
|
)
|
||||||
|
@ -82,10 +82,12 @@ class CLINT(params: CLINTParams, beatBytes: Int)(implicit p: Parameters) extends
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
node.regmap(
|
node.regmap(
|
||||||
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)))}),
|
0 -> RegFieldGroup ("msip", Some("MSIP Bits"), ipi.zipWithIndex.map{ case (r, i) =>
|
||||||
timecmpOffset(0) -> timecmp.zipWithIndex.flatMap{ case (t, i) =>
|
RegField(ipiWidth, r, RegFieldDesc(s"msip_$i", s"MSIP bit for Hart $i", reset=Some(0)))}),
|
||||||
RegFieldGroup(s"mtimecmp_$i", Some(s"MTIMECMP for hart $i"), RegField.bytes(t, Some(RegFieldDesc(s"mtimecmp_$i", "", reset=None))))},
|
timecmpOffset(0) -> timecmp.zipWithIndex.flatMap{ case (t, i) => RegFieldGroup(s"mtimecmp_$i", Some(s"MTIMECMP for hart $i"),
|
||||||
timeOffset -> RegFieldGroup("mtime", Some("Timer Register"), RegField.bytes(time, Some(RegFieldDesc("mtime", "", reset=Some(0)))))
|
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), volatile=true))))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,14 +170,16 @@ class TLPLIC(params: PLICParams, beatBytes: Int)(implicit p: Parameters) extends
|
|||||||
|
|
||||||
def priorityRegDesc(i: Int) = if (i > 0) {
|
def priorityRegDesc(i: Int) = if (i > 0) {
|
||||||
RegFieldDesc(s"priority_$i", s"Acting priority of interrupt source $i",
|
RegFieldDesc(s"priority_$i", s"Acting priority of interrupt source $i",
|
||||||
reset=if (nPriorities > 0) None else Some(1), access=RegFieldAccessType.RWSPECIAL)
|
reset=if (nPriorities > 0) None else Some(1),
|
||||||
|
wrType=Some(RegFieldWrType.MODIFY))
|
||||||
} else {
|
} else {
|
||||||
RegFieldDesc("reserved", "", reset=Some(0), access=RegFieldAccessType.R)
|
RegFieldDesc.reserved
|
||||||
}
|
}
|
||||||
def pendingRegDesc(i: Int) = if (i > 0) {
|
def pendingRegDesc(i: Int) = if (i > 0) {
|
||||||
RegFieldDesc(s"pending_$i", s"Set to 1 if interrupt source $i is pending, regardless of its enable or priority setting.")
|
RegFieldDesc(s"pending_$i", s"Set to 1 if interrupt source $i is pending, regardless of its enable or priority setting.",
|
||||||
|
volatile = true)
|
||||||
} else {
|
} else {
|
||||||
RegFieldDesc("reserved", "", reset=Some(0), access=RegFieldAccessType.R)
|
RegFieldDesc.reserved
|
||||||
}
|
}
|
||||||
|
|
||||||
def priorityRegField(x: UInt, i: Int) = if (nPriorities > 0) RegField(32, x, priorityRegDesc(i)) else RegField.r(32, x, priorityRegDesc(i))
|
def priorityRegField(x: UInt, i: Int) = if (nPriorities > 0) RegField(32, x, priorityRegDesc(i)) else RegField.r(32, x, priorityRegDesc(i))
|
||||||
@ -193,7 +195,7 @@ class TLPLIC(params: PLICParams, beatBytes: Int)(implicit p: Parameters) extends
|
|||||||
e.zipWithIndex.map{case (b, j) => if (j > 0) {
|
e.zipWithIndex.map{case (b, j) => if (j > 0) {
|
||||||
RegField(1, b, RegFieldDesc(s"enable_${i}_${j}", s"Enable interrupt for source $j for target $i.", reset=None))
|
RegField(1, b, RegFieldDesc(s"enable_${i}_${j}", s"Enable interrupt for source $j for target $i.", reset=None))
|
||||||
} else {
|
} else {
|
||||||
RegField(1, b, RegFieldDesc("reserved", "", reset=Some(0), access=RegFieldAccessType.R))
|
RegField(1, b, RegFieldDesc.reserved)
|
||||||
}})
|
}})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,7 +231,8 @@ class TLPLIC(params: PLICParams, beatBytes: Int)(implicit p: Parameters) extends
|
|||||||
}
|
}
|
||||||
|
|
||||||
def thresholdRegDesc(i: Int) = RegFieldDesc(s"threshold_$i", s"Interrupt & claim threshold for target $i. Maximum value is ${nPriorities}.",
|
def thresholdRegDesc(i: Int) = RegFieldDesc(s"threshold_$i", s"Interrupt & claim threshold for target $i. Maximum value is ${nPriorities}.",
|
||||||
reset=if (nPriorities > 0) None else Some(1), access=RegFieldAccessType.RWSPECIAL)
|
reset=if (nPriorities > 0) None else Some(1),
|
||||||
|
wrType=Some(RegFieldWrType.MODIFY))
|
||||||
def thresholdRegField(x: UInt, i: Int) = if (nPriorities > 0) RegField(32, x, thresholdRegDesc(i)) else RegField.r(32, x, thresholdRegDesc(i))
|
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 =>
|
||||||
@ -251,7 +254,9 @@ class TLPLIC(params: PLICParams, beatBytes: Int)(implicit p: Parameters) extends
|
|||||||
s"Claim/Complete register for Target $i. Reading this register returns the claimed interrupt number and makes it no longer pending." +
|
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.",
|
s"Writing the interrupt number back completes the interrupt.",
|
||||||
reset = None,
|
reset = None,
|
||||||
access = RegFieldAccessType.RWSPECIAL))
|
wrType = Some(RegFieldWrType.MODIFY),
|
||||||
|
rdAction = Some(RegFieldRdAction.MODIFY),
|
||||||
|
volatile = true))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
23
src/main/scala/regmapper/Annotation.scala
Normal file
23
src/main/scala/regmapper/Annotation.scala
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
|
package freechips.rocketchip.regmapper
|
||||||
|
|
||||||
|
import org.json4s.JsonDSL._
|
||||||
|
import org.json4s.jackson.JsonMethods.{pretty, render}
|
||||||
|
|
||||||
|
object RegMappingAnnotation {
|
||||||
|
def serialize(base: BigInt, name: String, mapping: RegField.Map*): String = {
|
||||||
|
val regDescs = mapping.flatMap { case (byte, seq) =>
|
||||||
|
seq.map(_.width).scanLeft(0)(_ + _).zip(seq).map { case (bit, f) =>
|
||||||
|
val anonName = s"unnamedRegField${byte.toHexString}_${bit}"
|
||||||
|
(f.desc.map{ _.name}.getOrElse(anonName)) -> f.toJson(byte, bit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pretty(render(
|
||||||
|
("peripheral" -> (
|
||||||
|
("displayName" -> name) ~
|
||||||
|
("baseAddress" -> s"0x${base.toInt.toHexString}") ~
|
||||||
|
("regfields" -> regDescs)))))
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,8 @@ import freechips.rocketchip.util.{AsyncResetRegVec, SimpleRegIO}
|
|||||||
|
|
||||||
object DescribedReg {
|
object DescribedReg {
|
||||||
import freechips.rocketchip.regmapper.RegFieldAccessType._
|
import freechips.rocketchip.regmapper.RegFieldAccessType._
|
||||||
|
import freechips.rocketchip.regmapper.RegFieldWrType._
|
||||||
|
import freechips.rocketchip.regmapper.RegFieldRdAction._
|
||||||
|
|
||||||
def apply[T <: Data](
|
def apply[T <: Data](
|
||||||
gen: => T,
|
gen: => T,
|
||||||
@ -15,9 +17,12 @@ object DescribedReg {
|
|||||||
desc: String,
|
desc: String,
|
||||||
reset: Option[T],
|
reset: Option[T],
|
||||||
access: RegFieldAccessType = RW,
|
access: RegFieldAccessType = RW,
|
||||||
|
wrType: Option[RegFieldWrType] = None,
|
||||||
|
rdAction: Option[RegFieldRdAction] = None,
|
||||||
|
volatile: Boolean = false,
|
||||||
enumerations: Map[BigInt, (String, String)] = Map()): (T, RegFieldDesc) = {
|
enumerations: Map[BigInt, (String, String)] = Map()): (T, RegFieldDesc) = {
|
||||||
val rdesc = RegFieldDesc(name, desc, None, None,
|
val rdesc = RegFieldDesc(name, desc, None, None,
|
||||||
access, reset.map{_.litValue}, enumerations)
|
access, wrType, rdAction, volatile, reset.map{_.litValue}, enumerations)
|
||||||
val reg = reset.map{i => RegInit(i)}.getOrElse(Reg(gen))
|
val reg = reset.map{i => RegInit(i)}.getOrElse(Reg(gen))
|
||||||
reg.suggestName(name + "_reg")
|
reg.suggestName(name + "_reg")
|
||||||
(reg, rdesc)
|
(reg, rdesc)
|
||||||
@ -29,9 +34,12 @@ object DescribedReg {
|
|||||||
desc: String,
|
desc: String,
|
||||||
reset: Int,
|
reset: Int,
|
||||||
access: RegFieldAccessType = RW,
|
access: RegFieldAccessType = RW,
|
||||||
|
wrType: Option[RegFieldWrType] = None,
|
||||||
|
rdAction: Option[RegFieldRdAction] = None,
|
||||||
|
volatile: Boolean = false,
|
||||||
enumerations: Map[BigInt, (String, String)] = Map()): (SimpleRegIO, RegFieldDesc) = {
|
enumerations: Map[BigInt, (String, String)] = Map()): (SimpleRegIO, RegFieldDesc) = {
|
||||||
val rdesc = RegFieldDesc(name, desc, None, None,
|
val rdesc = RegFieldDesc(name, desc, None, None,
|
||||||
access, Some(reset), enumerations)
|
access, wrType, rdAction, volatile, Some(reset), enumerations)
|
||||||
val reg = Module(new AsyncResetRegVec(w = width, init = reset))
|
val reg = Module(new AsyncResetRegVec(w = width, init = reset))
|
||||||
reg.suggestName(name + "_reg")
|
reg.suggestName(name + "_reg")
|
||||||
(reg.io, rdesc)
|
(reg.io, rdesc)
|
||||||
|
@ -5,8 +5,11 @@ package freechips.rocketchip.regmapper
|
|||||||
import Chisel._
|
import Chisel._
|
||||||
import chisel3.util.{ReadyValidIO}
|
import chisel3.util.{ReadyValidIO}
|
||||||
|
|
||||||
import freechips.rocketchip.util.{SimpleRegIO}
|
import org.json4s.JsonDSL._
|
||||||
|
import org.json4s.JsonAST.JValue
|
||||||
|
import org.json4s.jackson.JsonMethods.{pretty, render}
|
||||||
|
|
||||||
|
import freechips.rocketchip.util.{SimpleRegIO}
|
||||||
|
|
||||||
// This information is not used internally by the regmap(...) function.
|
// This information is not used internally by the regmap(...) function.
|
||||||
// However, the author of a RegField may be the best person to provide this
|
// However, the author of a RegField may be the best person to provide this
|
||||||
@ -15,26 +18,47 @@ import freechips.rocketchip.util.{SimpleRegIO}
|
|||||||
|
|
||||||
object RegFieldAccessType extends scala.Enumeration {
|
object RegFieldAccessType extends scala.Enumeration {
|
||||||
type RegFieldAccessType = Value
|
type RegFieldAccessType = Value
|
||||||
val R, W, RW, RSPECIAL, WSPECIAL, RWSPECIAL, OTHER = Value
|
val R, W, RW = Value
|
||||||
}
|
}
|
||||||
import RegFieldAccessType._
|
import RegFieldAccessType._
|
||||||
|
|
||||||
|
object RegFieldWrType extends scala.Enumeration {
|
||||||
|
type RegFieldWrType = Value
|
||||||
|
val ONE_TO_CLEAR, ONE_TO_SET, ONE_TO_TOGGLE, ZERO_TO_CLEAR,
|
||||||
|
ZERO_TO_SET, ZERO_TO_TOGGLE, CLEAR, SET, MODIFY = Value
|
||||||
|
}
|
||||||
|
import RegFieldWrType._
|
||||||
|
|
||||||
|
object RegFieldRdAction extends scala.Enumeration {
|
||||||
|
type RegFieldRdAction = Value
|
||||||
|
val CLEAR, SET, MODIFY = Value
|
||||||
|
}
|
||||||
|
import RegFieldRdAction._
|
||||||
|
|
||||||
case class RegFieldDesc (
|
case class RegFieldDesc (
|
||||||
name: String,
|
name: String,
|
||||||
desc: String,
|
desc: String,
|
||||||
group: Option[String] = None,
|
group: Option[String] = None,
|
||||||
groupDesc: Option[String] = None,
|
groupDesc: Option[String] = None,
|
||||||
access: RegFieldAccessType = RegFieldAccessType.RW,
|
access: RegFieldAccessType = RegFieldAccessType.RW,
|
||||||
|
wrType: Option[RegFieldWrType] = None,
|
||||||
|
rdAction: Option[RegFieldRdAction] = None,
|
||||||
|
volatile: Boolean = false,
|
||||||
|
// TODO: testable?
|
||||||
reset: Option[BigInt] = None,
|
reset: Option[BigInt] = None,
|
||||||
enumerations: Map[BigInt, (String, String)] = Map()
|
enumerations: Map[BigInt, (String, String)] = Map()
|
||||||
){
|
){
|
||||||
}
|
}
|
||||||
|
|
||||||
// Our descriptions are in terms of RegFields only, which is somewhat unusual for
|
object RegFieldDesc {
|
||||||
// developers who are used to things being defined as bitfields within registers.
|
def reserved: RegFieldDesc = RegFieldDesc("reserved", "", access=RegFieldAccessType.R, reset=Some(0))
|
||||||
// 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.
|
// 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 {
|
object RegFieldGroup {
|
||||||
def apply (name: String, desc: Option[String], regs: Seq[RegField], descFirstOnly: Boolean = true): Seq[RegField] = {
|
def apply (name: String, desc: Option[String], regs: Seq[RegField], descFirstOnly: Boolean = true): Seq[RegField] = {
|
||||||
@ -116,8 +140,29 @@ object RegWriteFn
|
|||||||
case class RegField(width: Int, read: RegReadFn, write: RegWriteFn, desc: Option[RegFieldDesc])
|
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 = (), desc = this.desc.map(_.copy(access = RegFieldAccessType.R)))
|
def readOnly = this.copy(write = (), desc = this.desc.map(_.copy(access = RegFieldAccessType.R)))
|
||||||
|
|
||||||
|
def toJson(byteOffset: Int, bitOffset: Int): JValue = {
|
||||||
|
( ("byteOffset" -> s"0x${byteOffset.toHexString}") ~
|
||||||
|
("bitOffset" -> bitOffset) ~
|
||||||
|
("bitWidth" -> width) ~
|
||||||
|
("name" -> desc.map(_.name)) ~
|
||||||
|
("description" -> desc.map{ d=> if (d.desc == "") None else Some(d.desc)}) ~
|
||||||
|
("resetValue" -> desc.map{_.reset}) ~
|
||||||
|
("group" -> desc.map{_.group}) ~
|
||||||
|
("groupDesc" -> desc.map{_.groupDesc}) ~
|
||||||
|
("accessType" -> desc.map {d => d.access.toString}) ~
|
||||||
|
("writeType" -> desc.map {d => d.wrType.map(_.toString)}) ~
|
||||||
|
("readAction" -> desc.map {d => d.rdAction.map(_.toString)}) ~
|
||||||
|
("volatile" -> desc.map {d => if (d.volatile) Some(true) else None}) ~
|
||||||
|
("enumerations" -> desc.map {d =>
|
||||||
|
Option(d.enumerations.map { case (key, (name, edesc)) =>
|
||||||
|
(("value" -> key) ~ ("name" -> name) ~ ("description" -> edesc))
|
||||||
|
}).filter(_.nonEmpty)}) )
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object RegField
|
object RegField
|
||||||
@ -125,8 +170,7 @@ 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, (), (), Some(RegFieldDesc.reserved))
|
||||||
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) : 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, r: RegReadFn, w: RegWriteFn, desc: RegFieldDesc) : RegField = apply(n, r, w, Some(desc))
|
||||||
@ -142,7 +186,7 @@ object RegField
|
|||||||
// Setting takes priority over clearing.
|
// Setting takes priority over clearing.
|
||||||
def w1ToClear(n: Int, reg: UInt, set: UInt, desc: Option[RegFieldDesc] = None): 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)})
|
desc.map{_.copy(access = RegFieldAccessType.RW, wrType=Some(RegFieldWrType.ONE_TO_CLEAR), volatile = true)})
|
||||||
|
|
||||||
// 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.
|
||||||
@ -151,26 +195,41 @@ object RegField
|
|||||||
bb.en := valid
|
bb.en := valid
|
||||||
bb.d := data
|
bb.d := data
|
||||||
Bool(true)
|
Bool(true)
|
||||||
}), desc.map{_.copy(access = RegFieldAccessType.RW)})
|
}), desc)
|
||||||
|
|
||||||
// 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 (implemented) bytes are written, the non-written
|
||||||
// are all byte-sized, this is also suitable when a register is larger
|
// bytes are just copied over from their current value.
|
||||||
|
// Because the RegField 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, desc: Option[RegFieldDesc]): Seq[RegField] = {
|
def bytes(reg: UInt, numBytes: Int, desc: Option[RegFieldDesc]): Seq[RegField] = {
|
||||||
val pad = reg | UInt(0, width = 8*numBytes)
|
require(reg.getWidth * 8 >= numBytes, "Can't break a ${reg.getWidth}-bit-wide register into only ${numBytes} bytes.")
|
||||||
|
val numFullBytes = reg.getWidth/8
|
||||||
|
val numPartialBytes = if ((reg.getWidth % 8) > 0) 1 else 0
|
||||||
|
val numPadBytes = numBytes - numFullBytes - numPartialBytes
|
||||||
|
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 =>
|
|
||||||
|
def wrFn(i: Int): RegWriteFn = RegWriteFn((valid, data) => {
|
||||||
|
valids(i) := valid
|
||||||
|
when (valid) {newBytes(i) := data}
|
||||||
|
Bool(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
val fullBytes = Seq.tabulate(numFullBytes) { i =>
|
||||||
val newDesc = desc.map {d => d.copy(name = d.name + s"_$i")}
|
val newDesc = desc.map {d => d.copy(name = d.name + s"_$i")}
|
||||||
RegField(8, oldBytes(i),
|
RegField(8, oldBytes(i), wrFn(i), newDesc)}
|
||||||
RegWriteFn((valid, data) => {
|
val partialBytes = if (numPartialBytes > 0) {
|
||||||
valids(i) := valid
|
val newDesc = desc.map {d => d.copy(name = d.name + s"_$numFullBytes")}
|
||||||
when (valid) { newBytes(i) := data }
|
Seq(RegField(reg.getWidth % 8, oldBytes(numFullBytes), wrFn(numFullBytes), newDesc),
|
||||||
Bool(true)
|
RegField(8 - (reg.getWidth % 8)))
|
||||||
}), newDesc)}}
|
} else Nil
|
||||||
|
val padBytes = Seq.fill(numPadBytes){RegField(8)}
|
||||||
|
fullBytes ++ partialBytes ++ padBytes
|
||||||
|
}
|
||||||
|
|
||||||
def bytes(reg: UInt, desc: Option[RegFieldDesc]): Seq[RegField] = {
|
def bytes(reg: UInt, desc: Option[RegFieldDesc]): Seq[RegField] = {
|
||||||
val width = reg.getWidth
|
val width = reg.getWidth
|
||||||
|
@ -54,27 +54,35 @@ class BusErrorUnit[T <: BusErrors](t: => T, params: BusErrorUnitParams)(implicit
|
|||||||
|
|
||||||
val causeWidth = log2Ceil(sources.lastIndexWhere(_.nonEmpty) + 1)
|
val causeWidth = log2Ceil(sources.lastIndexWhere(_.nonEmpty) + 1)
|
||||||
val (cause, cause_desc) = DescribedReg(UInt(causeWidth.W),
|
val (cause, cause_desc) = DescribedReg(UInt(causeWidth.W),
|
||||||
"cause", "Cause of error event", reset=Some(0.U(causeWidth.W)), enumerations=sources_enums.toMap)
|
"cause", "Cause of error event", reset=Some(0.U(causeWidth.W)), volatile=true, enumerations=sources_enums.toMap)
|
||||||
|
|
||||||
val (value, value_desc) = DescribedReg(UInt(width = sources.flatten.map(_.bits.getWidth).max),
|
val (value, value_desc) = DescribedReg(UInt(width = sources.flatten.map(_.bits.getWidth).max),
|
||||||
"value", "Physical address of error event", reset=None)
|
"value", "Physical address of error event", reset=None, volatile=true)
|
||||||
require(value.getWidth <= regWidth)
|
require(value.getWidth <= regWidth)
|
||||||
|
|
||||||
val enable = Reg(init = Vec(sources.map(_.nonEmpty.B)))
|
val enable = Reg(init = Vec(sources.map(_.nonEmpty.B)))
|
||||||
val enable_desc = sources.zipWithIndex.map { case (s, i) =>
|
val enable_desc = sources.zipWithIndex.map { case (s, i) =>
|
||||||
RegFieldDesc(s"enable_$i", "", reset=Some(if (s.nonEmpty) 1 else 0))}
|
if (s.nonEmpty) RegFieldDesc(s"enable_$i", "", reset=Some(1))
|
||||||
|
else RegFieldDesc.reserved
|
||||||
|
}
|
||||||
|
|
||||||
val global_interrupt = Reg(init = Vec.fill(sources.size)(false.B))
|
val global_interrupt = Reg(init = Vec.fill(sources.size)(false.B))
|
||||||
val global_interrupt_desc = sources.zipWithIndex.map { case (s, i) =>
|
val global_interrupt_desc = sources.zipWithIndex.map { case (s, i) =>
|
||||||
RegFieldDesc(s"plic_interrupt_$i", "", reset=Some(0))}
|
if (s.nonEmpty) RegFieldDesc(s"plic_interrupt_$i", "", reset=Some(0))
|
||||||
|
else RegFieldDesc.reserved
|
||||||
|
}
|
||||||
|
|
||||||
val accrued = Reg(init = Vec.fill(sources.size)(false.B))
|
val accrued = Reg(init = Vec.fill(sources.size)(false.B))
|
||||||
val accrued_desc = sources.zipWithIndex.map { case (s, i) =>
|
val accrued_desc = sources.zipWithIndex.map { case (s, i) =>
|
||||||
RegFieldDesc(s"accrued_$i", "", reset=Some(0))}
|
if (s.nonEmpty) RegFieldDesc(s"accrued_$i", "", reset=Some(0), volatile = true)
|
||||||
|
else RegFieldDesc.reserved
|
||||||
|
}
|
||||||
|
|
||||||
val local_interrupt = Reg(init = Vec.fill(sources.size)(false.B))
|
val local_interrupt = Reg(init = Vec.fill(sources.size)(false.B))
|
||||||
val local_interrupt_desc = sources.zipWithIndex.map { case (s, i) =>
|
val local_interrupt_desc = sources.zipWithIndex.map { case (s, i) =>
|
||||||
RegFieldDesc(s"local_interrupt_$i", "", reset=Some(0))}
|
if (s.nonEmpty) RegFieldDesc(s"local_interrupt_$i", "", reset=Some(0))
|
||||||
|
else RegFieldDesc.reserved
|
||||||
|
}
|
||||||
|
|
||||||
for ((((s, en), acc), i) <- (sources zip enable zip accrued).zipWithIndex; if s.nonEmpty) {
|
for ((((s, en), acc), i) <- (sources zip enable zip accrued).zipWithIndex; if s.nonEmpty) {
|
||||||
when (s.get.valid) {
|
when (s.get.valid) {
|
||||||
|
@ -35,7 +35,7 @@ trait ExampleModule extends HasRegMap
|
|||||||
Some(RegFieldDesc("pending", "Pending: Example of a special (W1ToC) Register. " +
|
Some(RegFieldDesc("pending", "Pending: Example of a special (W1ToC) Register. " +
|
||||||
"Writing a bit here causes it to be reset to 0. " +
|
"Writing a bit here causes it to be reset to 0. " +
|
||||||
"The bits are set when the corresponding bit in 'state' is high.",
|
"The bits are set when the corresponding bit in 'state' is high.",
|
||||||
reset=Some(0xF)))))
|
reset=Some(0xF), volatile=true))))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,9 +10,6 @@ import freechips.rocketchip.interrupts._
|
|||||||
import freechips.rocketchip.util.{HeterogeneousBag, ElaborationArtefacts}
|
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,
|
||||||
@ -85,44 +82,15 @@ case class TLRegisterNode(
|
|||||||
bundleIn.e.ready := Bool(true)
|
bundleIn.e.ready := Bool(true)
|
||||||
|
|
||||||
// Dump out the register map for documentation purposes.
|
// Dump out the register map for documentation purposes.
|
||||||
val regDescs = mapping.flatMap { case (offset, seq) =>
|
val base = address.head.base
|
||||||
var currentBitOffset = 0
|
val baseHex = s"0x${base.toInt.toHexString}"
|
||||||
seq.zipWithIndex.map { case (f, i) => {
|
val name = s"deviceAt${baseHex}" //TODO: It would be better to name this other than "Device at ...."
|
||||||
val tmp = (f.desc.map{ _.name}.getOrElse(s"unnamedRegField${offset.toHexString}_${currentBitOffset}") -> (
|
val json = RegMappingAnnotation.serialize(base, name, mapping:_*)
|
||||||
("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}) ~
|
|
||||||
("enumerations" -> f.desc.map {d =>
|
|
||||||
Option(d.enumerations.map { case (key, (name, desc)) =>
|
|
||||||
(("value" -> key) ~
|
|
||||||
("name" -> name) ~
|
|
||||||
("description" -> desc))
|
|
||||||
}).filter(_.nonEmpty)})
|
|
||||||
))
|
|
||||||
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)
|
|
||||||
))
|
|
||||||
|
|
||||||
var suffix = 0
|
var suffix = 0
|
||||||
while( ElaborationArtefacts.contains(s"${base}.${suffix}.regmap.json")){
|
while( ElaborationArtefacts.contains(s"${baseHex}.${suffix}.regmap.json")){
|
||||||
suffix = suffix + 1
|
suffix = suffix + 1
|
||||||
}
|
}
|
||||||
ElaborationArtefacts.add(s"${base}.${suffix}.regmap.json", pretty(render(json)))
|
ElaborationArtefacts.add(s"${baseHex}.${suffix}.regmap.json", json)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user