From 6357db0b1234be00832e374e7768c5f7f9c17262 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Mon, 6 Nov 2017 16:39:02 -0800 Subject: [PATCH 1/6] Expose BusErrorUnit non-diplomatically for use as local interrupt --- src/main/scala/rocket/BusErrorUnit.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/scala/rocket/BusErrorUnit.scala b/src/main/scala/rocket/BusErrorUnit.scala index d3928fee..b2b95d2a 100644 --- a/src/main/scala/rocket/BusErrorUnit.scala +++ b/src/main/scala/rocket/BusErrorUnit.scala @@ -40,6 +40,7 @@ class BusErrorUnit[T <: BusErrors](t: => T, params: BusErrorUnitParams)(implicit lazy val module = new LazyModuleImp(this) { val io = IO(new Bundle { val errors = t.flip + val interrupt = Bool().asOutput }) val sources = io.errors.toErrorList @@ -61,7 +62,8 @@ class BusErrorUnit[T <: BusErrors](t: => T, params: BusErrorUnitParams)(implicit } val (int_out, _) = intNode.out(0) - int_out(0) := (accrued & interrupt).orR + io.interrupt := (accrued & interrupt).orR + int_out(0) := io.interrupt def reg(r: UInt) = RegField(regWidth, r) def maskedReg(r: UInt, m: UInt) = RegField(regWidth, r, RegWriteFn((v, d) => { when (v) { r := d & m }; true })) From ac096a89e78c192763db4b1e7fb747412c594b7e Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Mon, 6 Nov 2017 16:42:29 -0800 Subject: [PATCH 2/6] Make BusErrorUnit support 32-bit stores Otherwise it isn't too useful for RV32! --- src/main/scala/rocket/BusErrorUnit.scala | 46 ++++++++++++++---------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/src/main/scala/rocket/BusErrorUnit.scala b/src/main/scala/rocket/BusErrorUnit.scala index b2b95d2a..2c0d6e42 100644 --- a/src/main/scala/rocket/BusErrorUnit.scala +++ b/src/main/scala/rocket/BusErrorUnit.scala @@ -44,35 +44,43 @@ class BusErrorUnit[T <: BusErrors](t: => T, params: BusErrorUnitParams)(implicit }) val sources = io.errors.toErrorList - val mask = sources.map(_.nonEmpty.B).asUInt val cause = Reg(init = UInt(0, log2Ceil(sources.lastIndexWhere(_.nonEmpty) + 1))) val value = Reg(UInt(width = sources.flatten.map(_.bits.getWidth).max)) require(value.getWidth <= regWidth) - val enable = Reg(init = mask) - val interrupt = Reg(init = UInt(0, sources.size)) - val accrued = Reg(init = UInt(0, sources.size)) + val enable = Reg(init = Vec(sources.map(_.nonEmpty.B))) + val interrupt = Reg(init = Vec.fill(sources.size)(false.B)) + val accrued = Reg(init = Vec.fill(sources.size)(false.B)) - accrued := accrued | sources.map(_.map(_.valid).getOrElse(false.B)).asUInt - - for ((s, i) <- sources.zipWithIndex; if s.nonEmpty) { - when (s.get.valid && enable(i) && cause === 0) { - cause := i - value := s.get.bits + 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 + } } } val (int_out, _) = intNode.out(0) - io.interrupt := (accrued & interrupt).orR + io.interrupt := (accrued.asUInt & interrupt.asUInt).orR int_out(0) := io.interrupt - def reg(r: UInt) = RegField(regWidth, r) - def maskedReg(r: UInt, m: UInt) = RegField(regWidth, r, RegWriteFn((v, d) => { when (v) { r := d & m }; true })) + 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( - 0 -> Seq(reg(cause), - reg(value), - maskedReg(enable, mask), - maskedReg(interrupt, mask), - maskedReg(accrued, mask))) + node.regmap(numberRegs(Seq( + reg(cause), + reg(value), + reg(enable), + reg(interrupt), + reg(accrued))):_*) + + // hardwire mask bits for unsupported sources to 0 + for ((s, i) <- sources.zipWithIndex; if s.isEmpty) { + enable(i) := false + interrupt(i) := false + accrued(i) := false + } } } From be3a3e018714f45701217155bf1d691405f8af43 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Mon, 6 Nov 2017 16:54:21 -0800 Subject: [PATCH 3/6] Generate local interrupt #128 on bus errors It doesn't have a correpsonding bit in mip/mie, so it isn't individually maskable, nor is it delegable. --- src/main/scala/rocket/CSR.scala | 23 +++++++++++++---------- src/main/scala/tile/Core.scala | 6 +++++- src/main/scala/tile/RocketTile.scala | 1 + 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/main/scala/rocket/CSR.scala b/src/main/scala/rocket/CSR.scala index 86ede45b..29700bfd 100644 --- a/src/main/scala/rocket/CSR.scala +++ b/src/main/scala/rocket/CSR.scala @@ -121,6 +121,7 @@ object CSR def R = UInt(5,SZ) val ADDRSZ = 12 + def busErrorIntCause = 128 def debugIntCause = 14 // keep in sync with MIP.debug def debugTriggerCause = { val res = debugIntCause @@ -156,7 +157,7 @@ class TracedInstruction(implicit p: Parameters) extends CoreBundle { val priv = UInt(width = 3) val exception = 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) } @@ -172,7 +173,7 @@ class CSRDecodeIO extends Bundle { class CSRFileIO(implicit p: Parameters) extends CoreBundle with HasCoreParameters { - val interrupts = new TileInterrupts().asInput + val interrupts = new CoreInterrupts().asInput val hartid = UInt(INPUT, hartIdLen) val rw = new Bundle { val addr = UInt(INPUT, CSR.ADDRSZ) @@ -244,13 +245,14 @@ class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Param sup.debug := false sup.zero2 := false 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) del.msip := false del.mtip := false del.meip := false - (sup.asUInt, del.asUInt) + (sup.asUInt | supported_high_interrupts, del.asUInt) } val delegable_exceptions = UInt(Seq( 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(_) } mip.rocc := io.rocc_interrupt 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 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 (anyInterrupt, whichInterrupt) = chooseInterrupt(Seq(s_interrupts, m_interrupts, d_interrupts)) val interruptMSB = BigInt(1) << (xLen-1) @@ -633,7 +636,7 @@ class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Param when (decoded_addr(CSRs.mscratch)) { reg_mscratch := wdata } 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.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) } for (((e, c), i) <- (reg_hpmevent zip reg_hpmcounter) zipWithIndex) { @@ -778,14 +781,14 @@ class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Param 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 // MEI, MSI, MTI, SEI, SSI, STI, UEI, USI, UTI val standard = Seq(11, 3, 7, 9, 1, 5, 8, 0, 4) val priority = nonstandard ++ standard - val paddedMasks = masks.reverse.map(_.padTo(xLen)) - val any = paddedMasks.flatMap(m => priority.map(i => m(i))).reduce(_||_) - val which = PriorityMux(paddedMasks.flatMap(m => priority.map(i => (m(i), i.U)))) + val masks = masksIn.reverse + val any = masks.flatMap(m => priority.filter(_ < m.getWidth).map(i => m(i))).reduce(_||_) + val which = PriorityMux(masks.flatMap(m => priority.filter(_ < m.getWidth).map(i => (m(i), i.U)))) (any, which) } diff --git a/src/main/scala/tile/Core.scala b/src/main/scala/tile/Core.scala index 26e20647..57f28b1d 100644 --- a/src/main/scala/tile/Core.scala +++ b/src/main/scala/tile/Core.scala @@ -81,10 +81,14 @@ abstract class CoreModule(implicit val p: Parameters) extends Module abstract class CoreBundle(implicit val p: Parameters) extends ParameterizedBundle()(p) with HasCoreParameters +class CoreInterrupts(implicit p: Parameters) extends TileInterrupts()(p) { + val buserror = coreParams.tileControlAddr.map(a => Bool()) +} + trait HasCoreIO extends HasTileParameters { implicit val p: Parameters val io = new CoreBundle()(p) with HasExternallyDrivenTileConstants { - val interrupts = new TileInterrupts().asInput + val interrupts = new CoreInterrupts().asInput val imem = new FrontendIO val dmem = new HellaCacheIO val ptw = new DatapathPTWIO().flip diff --git a/src/main/scala/tile/RocketTile.scala b/src/main/scala/tile/RocketTile.scala index fbb0bf9c..cd8a9cea 100644 --- a/src/main/scala/tile/RocketTile.scala +++ b/src/main/scala/tile/RocketTile.scala @@ -150,6 +150,7 @@ class RocketTileModule(outer: RocketTile) extends BaseTileModule(outer, () => ne val uncorrectable = RegInit(Bool(false)) 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 io.trace.foreach { _ := core.io.trace } io.halt_and_catch_fire.foreach { _ := uncorrectable } From d8d45049959dcd05e95efcf0dcc0717ac924c5ff Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Mon, 6 Nov 2017 18:01:51 -0800 Subject: [PATCH 4/6] Provide separate masks for local & global BusErrorUnit interrupts --- src/main/scala/rocket/BusErrorUnit.scala | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/scala/rocket/BusErrorUnit.scala b/src/main/scala/rocket/BusErrorUnit.scala index 2c0d6e42..cb922ee2 100644 --- a/src/main/scala/rocket/BusErrorUnit.scala +++ b/src/main/scala/rocket/BusErrorUnit.scala @@ -48,8 +48,9 @@ class BusErrorUnit[T <: BusErrors](t: => T, params: BusErrorUnitParams)(implicit val value = Reg(UInt(width = sources.flatten.map(_.bits.getWidth).max)) require(value.getWidth <= regWidth) val enable = Reg(init = Vec(sources.map(_.nonEmpty.B))) - val interrupt = Reg(init = Vec.fill(sources.size)(false.B)) + val global_interrupt = Reg(init = Vec.fill(sources.size)(false.B)) val accrued = Reg(init = Vec.fill(sources.size)(false.B)) + val local_interrupt = Reg(init = Vec.fill(sources.size)(false.B)) for ((((s, en), acc), i) <- (sources zip enable zip accrued).zipWithIndex; if s.nonEmpty) { when (s.get.valid) { @@ -62,8 +63,8 @@ class BusErrorUnit[T <: BusErrors](t: => T, params: BusErrorUnitParams)(implicit } val (int_out, _) = intNode.out(0) - io.interrupt := (accrued.asUInt & interrupt.asUInt).orR - int_out(0) := io.interrupt + 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)) @@ -73,14 +74,16 @@ class BusErrorUnit[T <: BusErrors](t: => T, params: BusErrorUnitParams)(implicit reg(cause), reg(value), reg(enable), - reg(interrupt), - reg(accrued))):_*) + reg(global_interrupt), + reg(accrued), + reg(local_interrupt))):_*) // hardwire mask bits for unsupported sources to 0 for ((s, i) <- sources.zipWithIndex; if s.isEmpty) { enable(i) := false - interrupt(i) := false + global_interrupt(i) := false accrued(i) := false + local_interrupt(i) := false } } } From 6176b348dc2241aa80a0dc007c589b8032d417cd Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Tue, 7 Nov 2017 00:52:18 -0800 Subject: [PATCH 5/6] Invalidate TL error bit in D$ once progress is made --- src/main/scala/rocket/DCache.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/scala/rocket/DCache.scala b/src/main/scala/rocket/DCache.scala index 2f14660c..dfa58812 100644 --- a/src/main/scala/rocket/DCache.scala +++ b/src/main/scala/rocket/DCache.scala @@ -305,6 +305,7 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) { } when (lrscCount > 0) { lrscCount := lrscCount - 1 } 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 val s2_correct = s2_data_error && !any_pstore_valid && !RegNext(any_pstore_valid) && Bool(usingDataScratchpad) From 34f38b0fb1c052304dd2f08309241de8c8d6dca7 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Tue, 7 Nov 2017 01:59:30 -0800 Subject: [PATCH 6/6] Don't permit vectoring of high interrupts Send them to the base of the vector to obviate an adder --- src/main/scala/rocket/CSR.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/scala/rocket/CSR.scala b/src/main/scala/rocket/CSR.scala index 29700bfd..9ff2b3a9 100644 --- a/src/main/scala/rocket/CSR.scala +++ b/src/main/scala/rocket/CSR.scala @@ -482,7 +482,7 @@ class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Param val cause = Mux(insn_call, reg_mstatus.prv + Causes.user_ecall, 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 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) @@ -495,7 +495,8 @@ class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Param val base = Mux(delegate, reg_stvec.sextTo(vaddrBitsExtended), reg_mtvec) val interruptOffset = cause(mtvecInterruptAlign-1, 0) << mtvecBaseAlign 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) io.evec := tvec