diff --git a/src/main/scala/devices/debug/Debug.scala b/src/main/scala/devices/debug/Debug.scala index f29e8af3..e333567e 100644 --- a/src/main/scala/devices/debug/Debug.scala +++ b/src/main/scala/devices/debug/Debug.scala @@ -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)))}) ) diff --git a/src/main/scala/devices/tilelink/CLINT.scala b/src/main/scala/devices/tilelink/CLINT.scala index 5c9d3358..cb1f340b 100644 --- a/src/main/scala/devices/tilelink/CLINT.scala +++ b/src/main/scala/devices/tilelink/CLINT.scala @@ -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)))) ) } } diff --git a/src/main/scala/devices/tilelink/Plic.scala b/src/main/scala/devices/tilelink/Plic.scala index eca0bc1d..cd1cf3d3 100644 --- a/src/main/scala/devices/tilelink/Plic.scala +++ b/src/main/scala/devices/tilelink/Plic.scala @@ -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)) ) ) } diff --git a/src/main/scala/regmapper/Annotation.scala b/src/main/scala/regmapper/Annotation.scala new file mode 100644 index 00000000..20ff902b --- /dev/null +++ b/src/main/scala/regmapper/Annotation.scala @@ -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))))) + } +} diff --git a/src/main/scala/regmapper/DescribedReg.scala b/src/main/scala/regmapper/DescribedReg.scala index 59be4a27..658539c8 100644 --- a/src/main/scala/regmapper/DescribedReg.scala +++ b/src/main/scala/regmapper/DescribedReg.scala @@ -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) diff --git a/src/main/scala/regmapper/RegField.scala b/src/main/scala/regmapper/RegField.scala index b814732b..b5a47332 100644 --- a/src/main/scala/regmapper/RegField.scala +++ b/src/main/scala/regmapper/RegField.scala @@ -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] = { - 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 newBytes = Wire(init = oldBytes) val valids = Wire(init = Vec.fill(numBytes) { Bool(false) }) 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")} - RegField(8, oldBytes(i), - RegWriteFn((valid, data) => { - valids(i) := valid - when (valid) { newBytes(i) := data } - Bool(true) - }), newDesc)}} + 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 diff --git a/src/main/scala/rocket/BusErrorUnit.scala b/src/main/scala/rocket/BusErrorUnit.scala index 38d1ccd7..8c4cfaee 100644 --- a/src/main/scala/rocket/BusErrorUnit.scala +++ b/src/main/scala/rocket/BusErrorUnit.scala @@ -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) { diff --git a/src/main/scala/tilelink/Example.scala b/src/main/scala/tilelink/Example.scala index e5f3104c..bfd85b14 100644 --- a/src/main/scala/tilelink/Example.scala +++ b/src/main/scala/tilelink/Example.scala @@ -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)))) ) } diff --git a/src/main/scala/tilelink/RegisterRouter.scala b/src/main/scala/tilelink/RegisterRouter.scala index c4b4d42c..fb74591e 100644 --- a/src/main/scala/tilelink/RegisterRouter.scala +++ b/src/main/scala/tilelink/RegisterRouter.scala @@ -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) } }