diff --git a/src/main/scala/regmapper/DescribedReg.scala b/src/main/scala/regmapper/DescribedReg.scala new file mode 100644 index 00000000..59be4a27 --- /dev/null +++ b/src/main/scala/regmapper/DescribedReg.scala @@ -0,0 +1,39 @@ +// See LICENSE for license details. +package freechips.rocketchip.regmapper + +import Chisel._ +import chisel3.experimental._ +import chisel3.{Input, Output} +import freechips.rocketchip.util.{AsyncResetRegVec, SimpleRegIO} + +object DescribedReg { + import freechips.rocketchip.regmapper.RegFieldAccessType._ + + def apply[T <: Data]( + gen: => T, + name: String, + desc: String, + reset: Option[T], + access: RegFieldAccessType = RW, + enumerations: Map[BigInt, (String, String)] = Map()): (T, RegFieldDesc) = { + val rdesc = RegFieldDesc(name, desc, None, None, + access, reset.map{_.litValue}, enumerations) + val reg = reset.map{i => RegInit(i)}.getOrElse(Reg(gen)) + reg.suggestName(name + "_reg") + (reg, rdesc) + } + + def async( + width: Int, + name: String, + desc: String, + reset: Int, + access: RegFieldAccessType = RW, + enumerations: Map[BigInt, (String, String)] = Map()): (SimpleRegIO, RegFieldDesc) = { + val rdesc = RegFieldDesc(name, desc, None, None, + access, 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/rocket/BusErrorUnit.scala b/src/main/scala/rocket/BusErrorUnit.scala index b9834d70..38d1ccd7 100644 --- a/src/main/scala/rocket/BusErrorUnit.scala +++ b/src/main/scala/rocket/BusErrorUnit.scala @@ -15,16 +15,20 @@ import freechips.rocketchip.interrupts._ import freechips.rocketchip.util.property._ trait BusErrors extends Bundle { - def toErrorList: List[Option[Valid[UInt]]] + def toErrorList: List[Option[(Valid[UInt], String, String)]] } class L1BusErrors(implicit p: Parameters) extends CoreBundle()(p) with BusErrors { val icache = new ICacheErrors val dcache = new DCacheErrors - def toErrorList = - List(None, None, icache.correctable, icache.uncorrectable, - None, Some(dcache.bus), dcache.correctable, dcache.uncorrectable) + def toErrorList = List(None, None, + icache.correctable.map((_, "I_CORRECTABLE", "Instruction cache or ITIM correctable ECC error ")), + icache.uncorrectable.map((_, "I_UNCORRECTABLE", "ITIM uncorrectable ECC error")), + None, + Some((dcache.bus, "DBUS", "Load or store TileLink bus error")), + dcache.correctable.map((_, "D_CORRECTABLE", "Data cache correctable ECC error")), + dcache.uncorrectable.map((_, "D_UNCORRECTABLE", "Data cache uncorrectable ECC error"))) } case class BusErrorUnitParams(addr: BigInt, size: Int = 4096) @@ -44,14 +48,33 @@ class BusErrorUnit[T <: BusErrors](t: => T, params: BusErrorUnitParams)(implicit val interrupt = Bool().asOutput }) - val sources = io.errors.toErrorList - val cause = Reg(init = UInt(0, log2Ceil(sources.lastIndexWhere(_.nonEmpty) + 1))) - val value = Reg(UInt(width = sources.flatten.map(_.bits.getWidth).max)) + val sources_and_desc = io.errors.toErrorList + val sources = sources_and_desc.map(_.map(_._1)) + val sources_enums = sources_and_desc.zipWithIndex.flatMap{case (s, i) => s.map {e => (BigInt(i) -> (e._2, e._3))}} + + 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) + + val (value, value_desc) = DescribedReg(UInt(width = sources.flatten.map(_.bits.getWidth).max), + "value", "Physical address of error event", reset=None) 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))} + 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))} + 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))} + 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))} for ((((s, en), acc), i) <- (sources zip enable zip accrued).zipWithIndex; if s.nonEmpty) { when (s.get.valid) { @@ -68,17 +91,18 @@ class BusErrorUnit[T <: BusErrors](t: => T, params: BusErrorUnitParams)(implicit io.interrupt := (accrued.asUInt & local_interrupt.asUInt).orR int_out(0) := (accrued.asUInt & global_interrupt.asUInt).orR - def reg(r: UInt) = RegField.bytes(r, (r.getWidth + 7)/8) - def reg(v: Vec[Bool]) = v.map(r => RegField(1, r)) - def numberRegs(x: Seq[Seq[RegField]]) = x.zipWithIndex.map { case (f, i) => (i * regWidth / 8) -> f } + def reg(r: UInt, gn: String, d: RegFieldDesc) = RegFieldGroup(gn, None, RegField.bytes(r, (r.getWidth + 7)/8, Some(d))) + def reg(v: Vec[Bool], gn: String, gd: String, d: Seq[RegFieldDesc]) = + RegFieldGroup(gn, Some(gd), (v zip d).map {case (r, rd) => RegField(1, r, rd)}) + def numberRegs(x: Seq[Seq[RegField]]) = x.zipWithIndex.map {case (f, i) => (i * regWidth / 8) -> f } node.regmap(numberRegs(Seq( - reg(cause), - reg(value), - reg(enable), - reg(global_interrupt), - reg(accrued), - reg(local_interrupt))):_*) + reg(cause, "cause", cause_desc), + reg(value, "value", value_desc), + reg(enable, "enable", "Event enable mask", enable_desc), + reg(global_interrupt, "plic_interrupt", "Platform-level interrupt enable mask", global_interrupt_desc), + reg(accrued, "accrued", "Accrued event mask" ,accrued_desc), + reg(local_interrupt, "local_interrupt", "Hart-local interrupt-enable mask", local_interrupt_desc))):_*) // hardwire mask bits for unsupported sources to 0 for ((s, i) <- sources.zipWithIndex; if s.isEmpty) {