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
|
||||
value := data
|
||||
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", ""))}),
|
||||
|
||||
// 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},
|
||||
WHERETO -> Seq(RegField.r(32, jalAbstract.asUInt, RegFieldDesc("debug_whereto", "Instruction filled in by Debug Module to control hart in Debug Mode"))),
|
||||
IMPEBREAK(cfg)-> {if (cfg.hasImplicitEbreak) Seq(RegField.r(32, Instructions.EBREAK.value.U,
|
||||
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"),
|
||||
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.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"),
|
||||
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(
|
||||
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.zipWithIndex.flatMap{ case (t, i) =>
|
||||
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)))))
|
||||
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.zipWithIndex.flatMap{ case (t, i) => 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), volatile=true))))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -170,14 +170,16 @@ class TLPLIC(params: PLICParams, beatBytes: Int)(implicit p: Parameters) extends
|
||||
|
||||
def priorityRegDesc(i: Int) = if (i > 0) {
|
||||
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 {
|
||||
RegFieldDesc("reserved", "", reset=Some(0), access=RegFieldAccessType.R)
|
||||
RegFieldDesc.reserved
|
||||
}
|
||||
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 {
|
||||
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))
|
||||
@ -193,7 +195,7 @@ class TLPLIC(params: PLICParams, beatBytes: Int)(implicit p: Parameters) extends
|
||||
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))
|
||||
} 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}.",
|
||||
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))
|
||||
|
||||
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"Writing the interrupt number back completes the interrupt.",
|
||||
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 {
|
||||
import freechips.rocketchip.regmapper.RegFieldAccessType._
|
||||
import freechips.rocketchip.regmapper.RegFieldWrType._
|
||||
import freechips.rocketchip.regmapper.RegFieldRdAction._
|
||||
|
||||
def apply[T <: Data](
|
||||
gen: => T,
|
||||
@ -15,9 +17,12 @@ object DescribedReg {
|
||||
desc: String,
|
||||
reset: Option[T],
|
||||
access: RegFieldAccessType = RW,
|
||||
wrType: Option[RegFieldWrType] = None,
|
||||
rdAction: Option[RegFieldRdAction] = None,
|
||||
volatile: Boolean = false,
|
||||
enumerations: Map[BigInt, (String, String)] = Map()): (T, RegFieldDesc) = {
|
||||
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))
|
||||
reg.suggestName(name + "_reg")
|
||||
(reg, rdesc)
|
||||
@ -29,9 +34,12 @@ object DescribedReg {
|
||||
desc: String,
|
||||
reset: Int,
|
||||
access: RegFieldAccessType = RW,
|
||||
wrType: Option[RegFieldWrType] = None,
|
||||
rdAction: Option[RegFieldRdAction] = None,
|
||||
volatile: Boolean = false,
|
||||
enumerations: Map[BigInt, (String, String)] = Map()): (SimpleRegIO, RegFieldDesc) = {
|
||||
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))
|
||||
reg.suggestName(name + "_reg")
|
||||
(reg.io, rdesc)
|
||||
|
@ -5,8 +5,11 @@ package freechips.rocketchip.regmapper
|
||||
import Chisel._
|
||||
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.
|
||||
// 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 {
|
||||
type RegFieldAccessType = Value
|
||||
val R, W, RW, RSPECIAL, WSPECIAL, RWSPECIAL, OTHER = Value
|
||||
val R, W, RW = Value
|
||||
}
|
||||
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 (
|
||||
name: String,
|
||||
desc: String,
|
||||
group: Option[String] = None,
|
||||
groupDesc: Option[String] = None,
|
||||
access: RegFieldAccessType = RegFieldAccessType.RW,
|
||||
wrType: Option[RegFieldWrType] = None,
|
||||
rdAction: Option[RegFieldRdAction] = None,
|
||||
volatile: Boolean = false,
|
||||
// TODO: testable?
|
||||
reset: Option[BigInt] = None,
|
||||
enumerations: Map[BigInt, (String, String)] = 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 RegFieldDesc {
|
||||
def reserved: RegFieldDesc = RegFieldDesc("reserved", "", access=RegFieldAccessType.R, reset=Some(0))
|
||||
}
|
||||
|
||||
// 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] = {
|
||||
@ -116,8 +140,29 @@ object RegWriteFn
|
||||
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 = (), 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
|
||||
@ -125,8 +170,7 @@ object RegField
|
||||
// Byte address => sequence of bitfields, lowest index => lowest address
|
||||
type Map = (Int, Seq[RegField])
|
||||
|
||||
def apply(n: Int) : RegField = apply(n, (), (),
|
||||
Some(RegFieldDesc("reserved", "", access = RegFieldAccessType.R, reset = Some(0))))
|
||||
def apply(n: Int) : RegField = apply(n, (), (), Some(RegFieldDesc.reserved))
|
||||
|
||||
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))
|
||||
@ -142,7 +186,7 @@ object RegField
|
||||
// Setting takes priority over clearing.
|
||||
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)})
|
||||
desc.map{_.copy(access = RegFieldAccessType.RW, wrType=Some(RegFieldWrType.ONE_TO_CLEAR), volatile = true)})
|
||||
|
||||
// This RegField wraps an explicit register
|
||||
// (e.g. Black-Boxed Register) to create a R/W register.
|
||||
@ -151,26 +195,41 @@ object RegField
|
||||
bb.en := valid
|
||||
bb.d := data
|
||||
Bool(true)
|
||||
}), desc.map{_.copy(access = RegFieldAccessType.RW)})
|
||||
}), desc)
|
||||
|
||||
// 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
|
||||
// It is updated when any of the (implemented) bytes are written, the non-written
|
||||
// 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).
|
||||
def bytes(reg: UInt, numBytes: Int, desc: Option[RegFieldDesc]): Seq[RegField] = {
|
||||
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 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")}
|
||||
RegField(8, oldBytes(i),
|
||||
RegWriteFn((valid, data) => {
|
||||
|
||||
def wrFn(i: Int): RegWriteFn = RegWriteFn((valid, data) => {
|
||||
valids(i) := valid
|
||||
when (valid) {newBytes(i) := data}
|
||||
Bool(true)
|
||||
}), newDesc)}}
|
||||
})
|
||||
|
||||
val fullBytes = Seq.tabulate(numFullBytes) { i =>
|
||||
val newDesc = desc.map {d => d.copy(name = d.name + s"_$i")}
|
||||
RegField(8, oldBytes(i), wrFn(i), newDesc)}
|
||||
val partialBytes = if (numPartialBytes > 0) {
|
||||
val newDesc = desc.map {d => d.copy(name = d.name + s"_$numFullBytes")}
|
||||
Seq(RegField(reg.getWidth % 8, oldBytes(numFullBytes), wrFn(numFullBytes), newDesc),
|
||||
RegField(8 - (reg.getWidth % 8)))
|
||||
} else Nil
|
||||
val padBytes = Seq.fill(numPadBytes){RegField(8)}
|
||||
fullBytes ++ partialBytes ++ padBytes
|
||||
}
|
||||
|
||||
def bytes(reg: UInt, desc: Option[RegFieldDesc]): Seq[RegField] = {
|
||||
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 (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),
|
||||
"value", "Physical address of error event", reset=None)
|
||||
"value", "Physical address of error event", reset=None, volatile=true)
|
||||
require(value.getWidth <= regWidth)
|
||||
|
||||
val enable = Reg(init = Vec(sources.map(_.nonEmpty.B)))
|
||||
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_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_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_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) {
|
||||
when (s.get.valid) {
|
||||
|
@ -35,7 +35,7 @@ trait ExampleModule extends HasRegMap
|
||||
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)))))
|
||||
reset=Some(0xF), volatile=true))))
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -10,9 +10,6 @@ import freechips.rocketchip.interrupts._
|
||||
import freechips.rocketchip.util.{HeterogeneousBag, ElaborationArtefacts}
|
||||
import scala.math.{min,max}
|
||||
|
||||
import org.json4s.JsonDSL._
|
||||
import org.json4s.jackson.JsonMethods.{pretty, render}
|
||||
|
||||
case class TLRegisterNode(
|
||||
address: Seq[AddressSet],
|
||||
device: Device,
|
||||
@ -85,44 +82,15 @@ case class TLRegisterNode(
|
||||
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${offset.toHexString}_${currentBitOffset}") -> (
|
||||
("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)
|
||||
))
|
||||
|
||||
val base = address.head.base
|
||||
val baseHex = s"0x${base.toInt.toHexString}"
|
||||
val name = s"deviceAt${baseHex}" //TODO: It would be better to name this other than "Device at ...."
|
||||
val json = RegMappingAnnotation.serialize(base, name, mapping:_*)
|
||||
var suffix = 0
|
||||
while( ElaborationArtefacts.contains(s"${base}.${suffix}.regmap.json")){
|
||||
while( ElaborationArtefacts.contains(s"${baseHex}.${suffix}.regmap.json")){
|
||||
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