Merge pull request #1093 from freechipsproject/local-error-interrupt
generate local interrupts on bus/ecc errors
This commit is contained in:
commit
4514adb77c
@ -40,37 +40,50 @@ class BusErrorUnit[T <: BusErrors](t: => T, params: BusErrorUnitParams)(implicit
|
|||||||
lazy val module = new LazyModuleImp(this) {
|
lazy val module = new LazyModuleImp(this) {
|
||||||
val io = IO(new Bundle {
|
val io = IO(new Bundle {
|
||||||
val errors = t.flip
|
val errors = t.flip
|
||||||
|
val interrupt = Bool().asOutput
|
||||||
})
|
})
|
||||||
|
|
||||||
val sources = io.errors.toErrorList
|
val sources = io.errors.toErrorList
|
||||||
val mask = sources.map(_.nonEmpty.B).asUInt
|
|
||||||
val cause = Reg(init = UInt(0, log2Ceil(sources.lastIndexWhere(_.nonEmpty) + 1)))
|
val cause = Reg(init = UInt(0, log2Ceil(sources.lastIndexWhere(_.nonEmpty) + 1)))
|
||||||
val value = Reg(UInt(width = sources.flatten.map(_.bits.getWidth).max))
|
val value = Reg(UInt(width = sources.flatten.map(_.bits.getWidth).max))
|
||||||
require(value.getWidth <= regWidth)
|
require(value.getWidth <= regWidth)
|
||||||
val enable = Reg(init = mask)
|
val enable = Reg(init = Vec(sources.map(_.nonEmpty.B)))
|
||||||
val interrupt = Reg(init = UInt(0, sources.size))
|
val global_interrupt = Reg(init = Vec.fill(sources.size)(false.B))
|
||||||
val accrued = Reg(init = UInt(0, sources.size))
|
val accrued = Reg(init = Vec.fill(sources.size)(false.B))
|
||||||
|
val local_interrupt = Reg(init = Vec.fill(sources.size)(false.B))
|
||||||
|
|
||||||
accrued := accrued | sources.map(_.map(_.valid).getOrElse(false.B)).asUInt
|
for ((((s, en), acc), i) <- (sources zip enable zip accrued).zipWithIndex; if s.nonEmpty) {
|
||||||
|
when (s.get.valid) {
|
||||||
for ((s, i) <- sources.zipWithIndex; if s.nonEmpty) {
|
acc := true
|
||||||
when (s.get.valid && enable(i) && cause === 0) {
|
when (en && cause === 0) {
|
||||||
cause := i
|
cause := i
|
||||||
value := s.get.bits
|
value := s.get.bits
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val (int_out, _) = intNode.out(0)
|
val (int_out, _) = intNode.out(0)
|
||||||
int_out(0) := (accrued & interrupt).orR
|
io.interrupt := (accrued.asUInt & local_interrupt.asUInt).orR
|
||||||
|
int_out(0) := (accrued.asUInt & global_interrupt.asUInt).orR
|
||||||
|
|
||||||
def reg(r: UInt) = RegField(regWidth, r)
|
def reg(r: UInt) = RegField.bytes(r, (r.getWidth + 7)/8)
|
||||||
def maskedReg(r: UInt, m: UInt) = RegField(regWidth, r, RegWriteFn((v, d) => { when (v) { r := d & m }; true }))
|
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(
|
node.regmap(numberRegs(Seq(
|
||||||
0 -> Seq(reg(cause),
|
reg(cause),
|
||||||
reg(value),
|
reg(value),
|
||||||
maskedReg(enable, mask),
|
reg(enable),
|
||||||
maskedReg(interrupt, mask),
|
reg(global_interrupt),
|
||||||
maskedReg(accrued, mask)))
|
reg(accrued),
|
||||||
|
reg(local_interrupt))):_*)
|
||||||
|
|
||||||
|
// hardwire mask bits for unsupported sources to 0
|
||||||
|
for ((s, i) <- sources.zipWithIndex; if s.isEmpty) {
|
||||||
|
enable(i) := false
|
||||||
|
global_interrupt(i) := false
|
||||||
|
accrued(i) := false
|
||||||
|
local_interrupt(i) := false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,6 +121,7 @@ object CSR
|
|||||||
def R = UInt(5,SZ)
|
def R = UInt(5,SZ)
|
||||||
|
|
||||||
val ADDRSZ = 12
|
val ADDRSZ = 12
|
||||||
|
def busErrorIntCause = 128
|
||||||
def debugIntCause = 14 // keep in sync with MIP.debug
|
def debugIntCause = 14 // keep in sync with MIP.debug
|
||||||
def debugTriggerCause = {
|
def debugTriggerCause = {
|
||||||
val res = debugIntCause
|
val res = debugIntCause
|
||||||
@ -156,7 +157,7 @@ class TracedInstruction(implicit p: Parameters) extends CoreBundle {
|
|||||||
val priv = UInt(width = 3)
|
val priv = UInt(width = 3)
|
||||||
val exception = Bool()
|
val exception = Bool()
|
||||||
val interrupt = Bool()
|
val interrupt = Bool()
|
||||||
val cause = UInt(width = log2Ceil(xLen))
|
val cause = UInt(width = log2Ceil(1 + CSR.busErrorIntCause))
|
||||||
val tval = UInt(width = coreMaxAddrBits max iLen)
|
val tval = UInt(width = coreMaxAddrBits max iLen)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,7 +173,7 @@ class CSRDecodeIO extends Bundle {
|
|||||||
|
|
||||||
class CSRFileIO(implicit p: Parameters) extends CoreBundle
|
class CSRFileIO(implicit p: Parameters) extends CoreBundle
|
||||||
with HasCoreParameters {
|
with HasCoreParameters {
|
||||||
val interrupts = new TileInterrupts().asInput
|
val interrupts = new CoreInterrupts().asInput
|
||||||
val hartid = UInt(INPUT, hartIdLen)
|
val hartid = UInt(INPUT, hartIdLen)
|
||||||
val rw = new Bundle {
|
val rw = new Bundle {
|
||||||
val addr = UInt(INPUT, CSR.ADDRSZ)
|
val addr = UInt(INPUT, CSR.ADDRSZ)
|
||||||
@ -244,13 +245,14 @@ class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Param
|
|||||||
sup.debug := false
|
sup.debug := false
|
||||||
sup.zero2 := false
|
sup.zero2 := false
|
||||||
sup.lip foreach { _ := true }
|
sup.lip foreach { _ := true }
|
||||||
|
val supported_high_interrupts = if (io.interrupts.buserror.nonEmpty) UInt(BigInt(1) << CSR.busErrorIntCause) else 0.U
|
||||||
|
|
||||||
val del = Wire(init=sup)
|
val del = Wire(init=sup)
|
||||||
del.msip := false
|
del.msip := false
|
||||||
del.mtip := false
|
del.mtip := false
|
||||||
del.meip := false
|
del.meip := false
|
||||||
|
|
||||||
(sup.asUInt, del.asUInt)
|
(sup.asUInt | supported_high_interrupts, del.asUInt)
|
||||||
}
|
}
|
||||||
val delegable_exceptions = UInt(Seq(
|
val delegable_exceptions = UInt(Seq(
|
||||||
Causes.misaligned_fetch,
|
Causes.misaligned_fetch,
|
||||||
@ -313,10 +315,11 @@ class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Param
|
|||||||
io.interrupts.seip.foreach { mip.seip := reg_mip.seip || RegNext(_) }
|
io.interrupts.seip.foreach { mip.seip := reg_mip.seip || RegNext(_) }
|
||||||
mip.rocc := io.rocc_interrupt
|
mip.rocc := io.rocc_interrupt
|
||||||
val read_mip = mip.asUInt & supported_interrupts
|
val read_mip = mip.asUInt & supported_interrupts
|
||||||
|
val high_interrupts = io.interrupts.buserror.map(_ << CSR.busErrorIntCause).getOrElse(0.U)
|
||||||
|
|
||||||
val pending_interrupts = read_mip & reg_mie
|
val pending_interrupts = high_interrupts | (read_mip & reg_mie)
|
||||||
val d_interrupts = io.interrupts.debug << CSR.debugIntCause
|
val d_interrupts = io.interrupts.debug << CSR.debugIntCause
|
||||||
val m_interrupts = Mux(reg_mstatus.prv <= PRV.S || (reg_mstatus.prv === PRV.M && reg_mstatus.mie), pending_interrupts & ~reg_mideleg, UInt(0))
|
val m_interrupts = Mux(reg_mstatus.prv <= PRV.S || reg_mstatus.mie, ~(~pending_interrupts | reg_mideleg), UInt(0))
|
||||||
val s_interrupts = Mux(reg_mstatus.prv < PRV.S || (reg_mstatus.prv === PRV.S && reg_mstatus.sie), pending_interrupts & reg_mideleg, UInt(0))
|
val s_interrupts = Mux(reg_mstatus.prv < PRV.S || (reg_mstatus.prv === PRV.S && reg_mstatus.sie), pending_interrupts & reg_mideleg, UInt(0))
|
||||||
val (anyInterrupt, whichInterrupt) = chooseInterrupt(Seq(s_interrupts, m_interrupts, d_interrupts))
|
val (anyInterrupt, whichInterrupt) = chooseInterrupt(Seq(s_interrupts, m_interrupts, d_interrupts))
|
||||||
val interruptMSB = BigInt(1) << (xLen-1)
|
val interruptMSB = BigInt(1) << (xLen-1)
|
||||||
@ -479,7 +482,7 @@ class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Param
|
|||||||
val cause =
|
val cause =
|
||||||
Mux(insn_call, reg_mstatus.prv + Causes.user_ecall,
|
Mux(insn_call, reg_mstatus.prv + Causes.user_ecall,
|
||||||
Mux[UInt](insn_break, Causes.breakpoint, io.cause))
|
Mux[UInt](insn_break, Causes.breakpoint, io.cause))
|
||||||
val cause_lsbs = cause(log2Up(xLen)-1,0)
|
val cause_lsbs = cause(io.trace.head.cause.getWidth-1, 0)
|
||||||
val causeIsDebugInt = cause(xLen-1) && cause_lsbs === CSR.debugIntCause
|
val causeIsDebugInt = cause(xLen-1) && cause_lsbs === CSR.debugIntCause
|
||||||
val causeIsDebugTrigger = !cause(xLen-1) && cause_lsbs === CSR.debugTriggerCause
|
val causeIsDebugTrigger = !cause(xLen-1) && cause_lsbs === CSR.debugTriggerCause
|
||||||
val causeIsDebugBreak = !cause(xLen-1) && insn_break && Cat(reg_dcsr.ebreakm, reg_dcsr.ebreakh, reg_dcsr.ebreaks, reg_dcsr.ebreaku)(reg_mstatus.prv)
|
val causeIsDebugBreak = !cause(xLen-1) && insn_break && Cat(reg_dcsr.ebreakm, reg_dcsr.ebreakh, reg_dcsr.ebreaks, reg_dcsr.ebreaku)(reg_mstatus.prv)
|
||||||
@ -492,7 +495,8 @@ class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Param
|
|||||||
val base = Mux(delegate, reg_stvec.sextTo(vaddrBitsExtended), reg_mtvec)
|
val base = Mux(delegate, reg_stvec.sextTo(vaddrBitsExtended), reg_mtvec)
|
||||||
val interruptOffset = cause(mtvecInterruptAlign-1, 0) << mtvecBaseAlign
|
val interruptOffset = cause(mtvecInterruptAlign-1, 0) << mtvecBaseAlign
|
||||||
val interruptVec = Cat(base >> (mtvecInterruptAlign + mtvecBaseAlign), interruptOffset)
|
val interruptVec = Cat(base >> (mtvecInterruptAlign + mtvecBaseAlign), interruptOffset)
|
||||||
Mux(base(0) && cause(cause.getWidth-1), interruptVec, base)
|
val doVector = base(0) && cause(cause.getWidth-1) && (cause_lsbs >> mtvecInterruptAlign) === 0
|
||||||
|
Mux(doVector, interruptVec, base)
|
||||||
}
|
}
|
||||||
val tvec = Mux(trapToDebug, debugTVec, notDebugTVec)
|
val tvec = Mux(trapToDebug, debugTVec, notDebugTVec)
|
||||||
io.evec := tvec
|
io.evec := tvec
|
||||||
@ -633,7 +637,7 @@ class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Param
|
|||||||
when (decoded_addr(CSRs.mscratch)) { reg_mscratch := wdata }
|
when (decoded_addr(CSRs.mscratch)) { reg_mscratch := wdata }
|
||||||
if (mtvecWritable)
|
if (mtvecWritable)
|
||||||
when (decoded_addr(CSRs.mtvec)) { reg_mtvec := ~(~wdata | 2.U | Mux(wdata(0), UInt(((BigInt(1) << mtvecInterruptAlign) - 1) << mtvecBaseAlign), 0.U)) }
|
when (decoded_addr(CSRs.mtvec)) { reg_mtvec := ~(~wdata | 2.U | Mux(wdata(0), UInt(((BigInt(1) << mtvecInterruptAlign) - 1) << mtvecBaseAlign), 0.U)) }
|
||||||
when (decoded_addr(CSRs.mcause)) { reg_mcause := wdata & UInt((BigInt(1) << (xLen-1)) + 31) /* only implement 5 LSBs and MSB */ }
|
when (decoded_addr(CSRs.mcause)) { reg_mcause := wdata & UInt((BigInt(1) << (xLen-1)) + (BigInt(1) << whichInterrupt.getWidth) - 1) }
|
||||||
when (decoded_addr(CSRs.mbadaddr)) { reg_mbadaddr := wdata(vaddrBitsExtended-1,0) }
|
when (decoded_addr(CSRs.mbadaddr)) { reg_mbadaddr := wdata(vaddrBitsExtended-1,0) }
|
||||||
|
|
||||||
for (((e, c), i) <- (reg_hpmevent zip reg_hpmcounter) zipWithIndex) {
|
for (((e, c), i) <- (reg_hpmevent zip reg_hpmcounter) zipWithIndex) {
|
||||||
@ -778,14 +782,14 @@ class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Param
|
|||||||
t.tval := badaddr_value
|
t.tval := badaddr_value
|
||||||
}
|
}
|
||||||
|
|
||||||
def chooseInterrupt(masks: Seq[UInt]): (Bool, UInt) = {
|
def chooseInterrupt(masksIn: Seq[UInt]): (Bool, UInt) = {
|
||||||
val nonstandard = supported_interrupts.getWidth-1 to 12 by -1
|
val nonstandard = supported_interrupts.getWidth-1 to 12 by -1
|
||||||
// MEI, MSI, MTI, SEI, SSI, STI, UEI, USI, UTI
|
// MEI, MSI, MTI, SEI, SSI, STI, UEI, USI, UTI
|
||||||
val standard = Seq(11, 3, 7, 9, 1, 5, 8, 0, 4)
|
val standard = Seq(11, 3, 7, 9, 1, 5, 8, 0, 4)
|
||||||
val priority = nonstandard ++ standard
|
val priority = nonstandard ++ standard
|
||||||
val paddedMasks = masks.reverse.map(_.padTo(xLen))
|
val masks = masksIn.reverse
|
||||||
val any = paddedMasks.flatMap(m => priority.map(i => m(i))).reduce(_||_)
|
val any = masks.flatMap(m => priority.filter(_ < m.getWidth).map(i => m(i))).reduce(_||_)
|
||||||
val which = PriorityMux(paddedMasks.flatMap(m => priority.map(i => (m(i), i.U))))
|
val which = PriorityMux(masks.flatMap(m => priority.filter(_ < m.getWidth).map(i => (m(i), i.U))))
|
||||||
(any, which)
|
(any, which)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,6 +305,7 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
|
|||||||
}
|
}
|
||||||
when (lrscCount > 0) { lrscCount := lrscCount - 1 }
|
when (lrscCount > 0) { lrscCount := lrscCount - 1 }
|
||||||
when ((s2_valid_masked && lrscCount > 0) || io.cpu.invalidate_lr) { lrscCount := 0 }
|
when ((s2_valid_masked && lrscCount > 0) || io.cpu.invalidate_lr) { lrscCount := 0 }
|
||||||
|
when (s2_valid_masked || io.cpu.invalidate_lr) { tl_error_valid := false }
|
||||||
|
|
||||||
// don't perform data correction if it might clobber a recent store
|
// don't perform data correction if it might clobber a recent store
|
||||||
val s2_correct = s2_data_error && !any_pstore_valid && !RegNext(any_pstore_valid) && Bool(usingDataScratchpad)
|
val s2_correct = s2_data_error && !any_pstore_valid && !RegNext(any_pstore_valid) && Bool(usingDataScratchpad)
|
||||||
|
@ -81,10 +81,14 @@ abstract class CoreModule(implicit val p: Parameters) extends Module
|
|||||||
abstract class CoreBundle(implicit val p: Parameters) extends ParameterizedBundle()(p)
|
abstract class CoreBundle(implicit val p: Parameters) extends ParameterizedBundle()(p)
|
||||||
with HasCoreParameters
|
with HasCoreParameters
|
||||||
|
|
||||||
|
class CoreInterrupts(implicit p: Parameters) extends TileInterrupts()(p) {
|
||||||
|
val buserror = coreParams.tileControlAddr.map(a => Bool())
|
||||||
|
}
|
||||||
|
|
||||||
trait HasCoreIO extends HasTileParameters {
|
trait HasCoreIO extends HasTileParameters {
|
||||||
implicit val p: Parameters
|
implicit val p: Parameters
|
||||||
val io = new CoreBundle()(p) with HasExternallyDrivenTileConstants {
|
val io = new CoreBundle()(p) with HasExternallyDrivenTileConstants {
|
||||||
val interrupts = new TileInterrupts().asInput
|
val interrupts = new CoreInterrupts().asInput
|
||||||
val imem = new FrontendIO
|
val imem = new FrontendIO
|
||||||
val dmem = new HellaCacheIO
|
val dmem = new HellaCacheIO
|
||||||
val ptw = new DatapathPTWIO().flip
|
val ptw = new DatapathPTWIO().flip
|
||||||
|
@ -150,6 +150,7 @@ class RocketTileModule(outer: RocketTile) extends BaseTileModule(outer, () => ne
|
|||||||
val uncorrectable = RegInit(Bool(false))
|
val uncorrectable = RegInit(Bool(false))
|
||||||
|
|
||||||
decodeCoreInterrupts(core.io.interrupts) // Decode the interrupt vector
|
decodeCoreInterrupts(core.io.interrupts) // Decode the interrupt vector
|
||||||
|
outer.busErrorUnit.foreach { beu => core.io.interrupts.buserror.get := beu.module.io.interrupt }
|
||||||
core.io.hartid := io.hartid // Pass through the hartid
|
core.io.hartid := io.hartid // Pass through the hartid
|
||||||
io.trace.foreach { _ := core.io.trace }
|
io.trace.foreach { _ := core.io.trace }
|
||||||
io.halt_and_catch_fire.foreach { _ := uncorrectable }
|
io.halt_and_catch_fire.foreach { _ := uncorrectable }
|
||||||
|
Loading…
Reference in New Issue
Block a user