diff --git a/build.sbt b/build.sbt index 2fbb499d..f3cb18fd 100644 --- a/build.sbt +++ b/build.sbt @@ -15,6 +15,7 @@ lazy val commonSettings = Seq( traceLevel := 15, scalacOptions ++= Seq("-deprecation","-unchecked"), libraryDependencies ++= Seq("org.scala-lang" % "scala-reflect" % scalaVersion.value), + libraryDependencies ++= Seq("org.json4s" %% "json4s-jackson" % "3.5.0"), addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full) ) @@ -44,3 +45,4 @@ val chipSettings = Seq( s"make -C $makeDir -j $jobs $target".! } ) + diff --git a/src/main/scala/devices/tilelink/Clint.scala b/src/main/scala/devices/tilelink/Clint.scala index ecc6a49f..f4281417 100644 --- a/src/main/scala/devices/tilelink/Clint.scala +++ b/src/main/scala/devices/tilelink/Clint.scala @@ -83,9 +83,9 @@ class CoreplexLocalInterrupter(params: ClintParams)(implicit p: Parameters) exte */ node.regmap( - 0 -> RegFieldGroup ("msip", Some("MSIP Bits"), ipi.zipWithIndex.map{ case (r, i) => RegField(ipiWidth, r, RegFieldDesc(s"msip_$i", "MSIP bit for Hart $i", 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("mtimecmp_$i", "", reset=None))))}, + 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))))) ) } diff --git a/src/main/scala/devices/tilelink/Plic.scala b/src/main/scala/devices/tilelink/Plic.scala index 9ca39385..9de673d3 100644 --- a/src/main/scala/devices/tilelink/Plic.scala +++ b/src/main/scala/devices/tilelink/Plic.scala @@ -179,8 +179,8 @@ class TLPLIC(params: PLICParams)(implicit p: Parameters) extends LazyModule val enableRegFields = enables.zipWithIndex.map { case (e, i) => - PLICConsts.enableBase(i) -> RegFieldGroup("enable", Some("Enable bits for each interrupt source. 1 bit for each interrupt source."), - e.map(b => RegField(1, b, RegFieldDesc(s"enable_$i", "Enable interrupt and claim for source $i", reset=None)))) + PLICConsts.enableBase(i) -> RegFieldGroup(s"enables_${i}", Some(s"Enable bits for each interrupt source for target $i. 1 bit for each interrupt source."), + e.zipWithIndex.map{case (b, j) => RegField(1, b, RegFieldDesc(s"enable_${i}_${j}", s"Enable interrupt for source $j for target $i.", reset=None))}) } // When a hart reads a claim/complete register, then the @@ -232,8 +232,9 @@ class TLPLIC(params: PLICParams)(implicit p: Parameters) extends LazyModule completer(i) := valid && enables(i)(completerDev) Bool(true) }, - Some(RegFieldDesc(s"claim_complete_$i", ("Claim/Complete register for Target $i. Reading this register returns the claimed interrupt number and makes it no longer pending." + - "Writing the interrupt number back completes the interrupt."), + Some(RegFieldDesc(s"claim_complete_$i", + 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)) ) diff --git a/src/main/scala/regmapper/RegField.scala b/src/main/scala/regmapper/RegField.scala index 34e062b5..0f5e64cc 100644 --- a/src/main/scala/regmapper/RegField.scala +++ b/src/main/scala/regmapper/RegField.scala @@ -164,7 +164,7 @@ object RegField 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}]")} + val newDesc = desc.map {d => d.copy(name = d.name + s"[${(i+1)*8-1}:${i*8}]")} RegField(8, oldBytes(i), RegWriteFn((valid, data) => { valids(i) := valid diff --git a/src/main/scala/tilelink/RegisterRouter.scala b/src/main/scala/tilelink/RegisterRouter.scala index 44df9669..2d99a693 100644 --- a/src/main/scala/tilelink/RegisterRouter.scala +++ b/src/main/scala/tilelink/RegisterRouter.scala @@ -7,9 +7,12 @@ import freechips.rocketchip.config.Parameters import freechips.rocketchip.diplomacy._ import freechips.rocketchip.regmapper._ import freechips.rocketchip.interrupts._ -import freechips.rocketchip.util.HeterogeneousBag +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, @@ -80,6 +83,35 @@ case class TLRegisterNode( bundleIn.b.valid := Bool(false) bundleIn.c.ready := Bool(true) 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${i}") -> ( + ("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}) + )) + 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) + )) + ElaborationArtefacts.add(s"${base}.regmap.json", pretty(render(json))) } }