2017-09-16 03:46:19 +02:00
|
|
|
// See LICENSE.SiFive for license details.
|
|
|
|
|
|
|
|
package freechips.rocketchip.rocket
|
|
|
|
|
|
|
|
import Chisel._
|
|
|
|
import Chisel.ImplicitConversions._
|
|
|
|
import chisel3.util.Valid
|
|
|
|
import freechips.rocketchip.config.Parameters
|
|
|
|
import freechips.rocketchip.util._
|
|
|
|
import freechips.rocketchip.tile._
|
|
|
|
import freechips.rocketchip.diplomacy._
|
|
|
|
import freechips.rocketchip.regmapper._
|
|
|
|
import freechips.rocketchip.tilelink._
|
2017-10-20 05:44:54 +02:00
|
|
|
import freechips.rocketchip.interrupts._
|
2018-01-16 03:00:29 +01:00
|
|
|
import freechips.rocketchip.util.property._
|
2017-09-16 03:46:19 +02:00
|
|
|
|
|
|
|
trait BusErrors extends Bundle {
|
|
|
|
def toErrorList: List[Option[Valid[UInt]]]
|
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
2017-09-20 09:04:33 +02:00
|
|
|
None, Some(dcache.bus), dcache.correctable, dcache.uncorrectable)
|
2017-09-16 03:46:19 +02:00
|
|
|
}
|
|
|
|
|
2017-09-16 03:49:40 +02:00
|
|
|
case class BusErrorUnitParams(addr: BigInt, size: Int = 4096)
|
|
|
|
|
|
|
|
class BusErrorUnit[T <: BusErrors](t: => T, params: BusErrorUnitParams)(implicit p: Parameters) extends LazyModule {
|
2017-09-16 03:46:19 +02:00
|
|
|
val regWidth = 64
|
|
|
|
val device = new SimpleDevice("bus-error-unit", Seq("sifive,buserror0"))
|
|
|
|
val intNode = IntSourceNode(IntSourcePortSimple(resources = device.int))
|
|
|
|
val node = TLRegisterNode(
|
2017-09-16 03:49:40 +02:00
|
|
|
address = Seq(AddressSet(params.addr, params.size-1)),
|
2017-09-16 03:46:19 +02:00
|
|
|
device = device,
|
|
|
|
beatBytes = p(XLen)/8)
|
|
|
|
|
|
|
|
lazy val module = new LazyModuleImp(this) {
|
2017-09-14 03:06:03 +02:00
|
|
|
val io = IO(new Bundle {
|
2017-09-16 03:46:19 +02:00
|
|
|
val errors = t.flip
|
2017-11-07 01:39:02 +01:00
|
|
|
val interrupt = Bool().asOutput
|
2017-09-14 03:06:03 +02:00
|
|
|
})
|
2017-09-16 03:46:19 +02:00
|
|
|
|
|
|
|
val sources = io.errors.toErrorList
|
|
|
|
val cause = Reg(init = UInt(0, log2Ceil(sources.lastIndexWhere(_.nonEmpty) + 1)))
|
2017-09-16 03:49:40 +02:00
|
|
|
val value = Reg(UInt(width = sources.flatten.map(_.bits.getWidth).max))
|
2017-09-16 03:46:19 +02:00
|
|
|
require(value.getWidth <= regWidth)
|
2017-11-07 01:42:29 +01:00
|
|
|
val enable = Reg(init = Vec(sources.map(_.nonEmpty.B)))
|
2017-11-07 03:01:51 +01:00
|
|
|
val global_interrupt = Reg(init = Vec.fill(sources.size)(false.B))
|
2017-11-07 01:42:29 +01:00
|
|
|
val accrued = Reg(init = Vec.fill(sources.size)(false.B))
|
2017-11-07 03:01:51 +01:00
|
|
|
val local_interrupt = Reg(init = Vec.fill(sources.size)(false.B))
|
2017-09-16 03:46:19 +02:00
|
|
|
|
2017-11-07 01:42:29 +01:00
|
|
|
for ((((s, en), acc), i) <- (sources zip enable zip accrued).zipWithIndex; if s.nonEmpty) {
|
|
|
|
when (s.get.valid) {
|
|
|
|
acc := true
|
|
|
|
when (en && cause === 0) {
|
|
|
|
cause := i
|
|
|
|
value := s.get.bits
|
|
|
|
}
|
2018-01-16 03:00:29 +01:00
|
|
|
cover(en, s"BusErrorCause_$i", s"Core;;BusErrorCause $i covered")
|
2017-09-16 03:46:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-14 03:06:03 +02:00
|
|
|
val (int_out, _) = intNode.out(0)
|
2017-11-07 03:01:51 +01:00
|
|
|
io.interrupt := (accrued.asUInt & local_interrupt.asUInt).orR
|
|
|
|
int_out(0) := (accrued.asUInt & global_interrupt.asUInt).orR
|
2017-09-16 03:46:19 +02:00
|
|
|
|
2017-11-07 01:42:29 +01:00
|
|
|
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 }
|
|
|
|
|
|
|
|
node.regmap(numberRegs(Seq(
|
|
|
|
reg(cause),
|
|
|
|
reg(value),
|
|
|
|
reg(enable),
|
2017-11-07 03:01:51 +01:00
|
|
|
reg(global_interrupt),
|
|
|
|
reg(accrued),
|
|
|
|
reg(local_interrupt))):_*)
|
2017-09-16 03:46:19 +02:00
|
|
|
|
2017-11-07 01:42:29 +01:00
|
|
|
// hardwire mask bits for unsupported sources to 0
|
|
|
|
for ((s, i) <- sources.zipWithIndex; if s.isEmpty) {
|
|
|
|
enable(i) := false
|
2017-11-07 03:01:51 +01:00
|
|
|
global_interrupt(i) := false
|
2017-11-07 01:42:29 +01:00
|
|
|
accrued(i) := false
|
2017-11-07 03:01:51 +01:00
|
|
|
local_interrupt(i) := false
|
2017-11-07 01:42:29 +01:00
|
|
|
}
|
2017-09-16 03:46:19 +02:00
|
|
|
}
|
|
|
|
}
|