From 9a175b0fb12142408b61e44179029b80ea2099cb Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Fri, 15 Sep 2017 18:44:55 -0700 Subject: [PATCH 1/8] Statically report error correction/detection capability from ECC codes --- src/main/scala/util/ECC.scala | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/scala/util/ECC.scala b/src/main/scala/util/ECC.scala index 3912a644..b947f175 100644 --- a/src/main/scala/util/ECC.scala +++ b/src/main/scala/util/ECC.scala @@ -15,6 +15,9 @@ abstract class Decoding abstract class Code { + def canDetect: Boolean + def canCorrect: Boolean + def width(w0: Int): Int def encode(x: UInt): UInt def decode(x: UInt): Decoding @@ -29,6 +32,9 @@ abstract class Code class IdentityCode extends Code { + def canDetect = false + def canCorrect = false + def width(w0: Int) = w0 def encode(x: UInt) = x def swizzle(x: UInt) = x @@ -42,6 +48,9 @@ class IdentityCode extends Code class ParityCode extends Code { + def canDetect = true + def canCorrect = false + def width(w0: Int) = w0+1 def encode(x: UInt) = Cat(x.xorR, x) def swizzle(x: UInt) = Cat(false.B, x) @@ -55,6 +64,9 @@ class ParityCode extends Code class SECCode extends Code { + def canDetect = true + def canCorrect = true + def width(k: Int) = { val m = log2Floor(k) + 1 k + m + (if((1 << m) < m+k+1) 1 else 0) @@ -101,6 +113,9 @@ class SECCode extends Code class SECDEDCode extends Code { + def canDetect = true + def canCorrect = true + private val sec = new SECCode private val par = new ParityCode From 034ea722f47afdf370114ffc4c3a1df3c4ab21a2 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Fri, 15 Sep 2017 18:41:50 -0700 Subject: [PATCH 2/8] Report I$ errors --- src/main/scala/rocket/Frontend.scala | 2 ++ src/main/scala/rocket/ICache.scala | 36 +++++++++++++++++++++------- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/main/scala/rocket/Frontend.scala b/src/main/scala/rocket/Frontend.scala index c5ac2576..dd102957 100644 --- a/src/main/scala/rocket/Frontend.scala +++ b/src/main/scala/rocket/Frontend.scala @@ -70,6 +70,7 @@ class FrontendBundle(outer: Frontend) extends CoreBundle()(outer.p) val ptw = new TLBPTWIO() val tl_out = outer.masterNode.bundleOut val tl_in = outer.slaveNode.bundleIn + val errors = new ICacheErrors } class FrontendModule(outer: Frontend) extends LazyModuleImp(outer) @@ -286,6 +287,7 @@ class FrontendModule(outer: Frontend) extends LazyModuleImp(outer) // performance events io.cpu.perf := icache.io.perf io.cpu.perf.tlbMiss := io.ptw.req.fire() + io.errors := icache.io.errors def alignPC(pc: UInt) = ~(~pc | (coreInstBytes - 1)) } diff --git a/src/main/scala/rocket/ICache.scala b/src/main/scala/rocket/ICache.scala index a0e2d5e2..d8a07b49 100644 --- a/src/main/scala/rocket/ICache.scala +++ b/src/main/scala/rocket/ICache.scala @@ -36,6 +36,11 @@ class ICacheReq(implicit p: Parameters) extends CoreBundle()(p) with HasL1ICache val addr = UInt(width = vaddrBits) } +class ICacheErrors(implicit p: Parameters) extends CoreBundle()(p) with HasL1ICacheParameters { + val correctable = (cacheParams.tagECC.canDetect || cacheParams.dataECC.canDetect).option(Valid(UInt(width = paddrBits))) + val uncorrectable = (cacheParams.itimAddr.nonEmpty && cacheParams.dataECC.canDetect).option(Valid(UInt(width = paddrBits))) +} + class ICache(val icacheParams: ICacheParams, val hartid: Int)(implicit p: Parameters) extends LazyModule { lazy val module = new ICacheModule(this) val masterNode = TLClientNode(TLClientParameters( @@ -87,6 +92,7 @@ class ICacheBundle(outer: ICache) extends CoreBundle()(outer.p) { val tl_out = outer.masterNode.bundleOut val tl_in = outer.slaveNode.map(_.bundleIn) + val errors = new ICacheErrors val perf = new ICachePerfEvents().asOutput } @@ -116,10 +122,10 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer) val scratchpadOn = RegInit(false.B) val scratchpadMax = tl_in.map(tl => Reg(UInt(width = log2Ceil(nSets * (nWays - 1))))) def lineInScratchpad(line: UInt) = scratchpadMax.map(scratchpadOn && line <= _).getOrElse(false.B) - def addrMaybeInScratchpad(addr: UInt) = if (outer.icacheParams.itimAddr.isEmpty) false.B else { - val base = GetPropertyByHartId(p(RocketTilesKey), _.icache.flatMap(_.itimAddr.map(_.U)), io.hartid) - addr >= base && addr < base + outer.size + val scratchpadBase = outer.icacheParams.itimAddr.map { dummy => + GetPropertyByHartId(p(RocketTilesKey), _.icache.flatMap(_.itimAddr.map(_.U)), io.hartid) } + def addrMaybeInScratchpad(addr: UInt) = scratchpadBase.map(base => addr >= base && addr < base + outer.size).getOrElse(false.B) def addrInScratchpad(addr: UInt) = addrMaybeInScratchpad(addr) && lineInScratchpad(addr(untagBits+log2Ceil(nWays)-1, blockOffBits)) def scratchpadWay(addr: UInt) = addr.extract(untagBits+log2Ceil(nWays)-1, untagBits) def scratchpadWayValid(way: UInt) = way < nWays - 1 @@ -248,12 +254,15 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer) io.resp.valid := s1_valid && s1_hit case 2 => - val s2_tag_hit = RegEnable(s1_tag_hit, s1_valid || s1_slaveValid) - val s2_dout = RegEnable(s1_dout, s1_valid || s1_slaveValid) + val s1_clk_en = s1_valid || s1_slaveValid + val s2_tag_hit = RegEnable(s1_tag_hit, s1_clk_en) + val s2_hit_way = OHToUInt(s2_tag_hit) + val s2_scratchpad_word_addr = Cat(s2_hit_way, io.s2_vaddr(untagBits-1, log2Ceil(wordBits/8)), UInt(0, log2Ceil(wordBits/8))) + val s2_dout = RegEnable(s1_dout, s1_clk_en) val s2_way_mux = Mux1H(s2_tag_hit, s2_dout) - val s2_tag_disparity = RegEnable(s1_tag_disparity, s1_valid || s1_slaveValid).asUInt.orR - val s2_tl_error = RegEnable(s1_tl_error.asUInt.orR, s1_valid || s1_slaveValid) + val s2_tag_disparity = RegEnable(s1_tag_disparity, s1_clk_en).asUInt.orR + val s2_tl_error = RegEnable(s1_tl_error.asUInt.orR, s1_clk_en) val s2_data_decoded = dECC.decode(s2_way_mux) val s2_disparity = s2_tag_disparity || s2_data_decoded.error when (s2_valid && s2_disparity) { invalidate := true } @@ -263,6 +272,17 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer) io.resp.bits.replay := s2_disparity io.resp.valid := s2_valid && s2_hit + val s1_scratchpad_hit = Mux(s1_slaveValid, lineInScratchpad(scratchpadLine(s1s3_slaveAddr)), addrInScratchpad(io.s1_paddr)) + val s2_scratchpad_hit = RegEnable(s1_scratchpad_hit, s1_clk_en) + io.errors.correctable.foreach { c => + c.valid := s2_valid && Mux(s2_scratchpad_hit, s2_data_decoded.correctable, s2_disparity) + c.bits := 0.U + } + io.errors.uncorrectable.foreach { u => + u.valid := s2_valid && s2_scratchpad_hit && s2_data_decoded.uncorrectable + u.bits := scratchpadBase.get + s2_scratchpad_word_addr + } + tl_in.map { tl => val respValid = RegInit(false.B) tl.a.ready := !(tl_out.d.valid || s1_slaveValid || s2_slaveValid || s3_slaveValid || respValid) @@ -290,7 +310,7 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer) // a structural hazard on s1s3_slaveData/s1s3_slaveAddress). s3_slaveValid := true s1s3_slaveData := s2_data_decoded.corrected - s1s3_slaveAddr := Cat(OHToUInt(s2_tag_hit), io.s2_vaddr(untagBits-1, log2Ceil(wordBits/8)), s1s3_slaveAddr(log2Ceil(wordBits/8)-1, 0)) + s1s3_slaveAddr := s2_scratchpad_word_addr | s1s3_slaveAddr(log2Ceil(wordBits/8)-1, 0) } respValid := s2_slaveValid || (respValid && !tl.d.ready) From ed18acaae0eec22ae7de7d5132663666f8850026 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Fri, 15 Sep 2017 18:41:19 -0700 Subject: [PATCH 3/8] Report D$ errors --- src/main/scala/rocket/DCache.scala | 39 +++++++++++++++++++++++--- src/main/scala/rocket/HellaCache.scala | 1 + 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/main/scala/rocket/DCache.scala b/src/main/scala/rocket/DCache.scala index 62913f4b..dfc42aef 100644 --- a/src/main/scala/rocket/DCache.scala +++ b/src/main/scala/rocket/DCache.scala @@ -11,6 +11,11 @@ import freechips.rocketchip.tilelink._ import freechips.rocketchip.util._ import TLMessages._ +class DCacheErrors(implicit p: Parameters) extends L1HellaCacheBundle()(p) { + val correctable = (cacheParams.tagECC.canCorrect || cacheParams.dataECC.canCorrect).option(Valid(UInt(width = paddrBits))) + val uncorrectable = (cacheParams.tagECC.canDetect || cacheParams.dataECC.canDetect).option(Valid(UInt(width = paddrBits))) +} + class DCacheDataReq(implicit p: Parameters) extends L1HellaCacheBundle()(p) { val eccBytes = cacheParams.dataECCBytes val addr = Bits(width = untagBits) @@ -216,9 +221,11 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) { val s2_flush_valid_pre_tag_ecc = RegNext(s1_flush_valid) val s1_meta_decoded = s1_meta.map(tECC.decode(_)) val s1_meta_clk_en = s1_valid_not_nacked || s1_flush_valid || s1_probe - val s2_meta_errors = s1_meta_decoded.map(m => RegEnable(m.error, s1_meta_clk_en)).asUInt + val s2_meta_correctable_errors = s1_meta_decoded.map(m => RegEnable(m.correctable, s1_meta_clk_en)).asUInt + val s2_meta_uncorrectable_errors = s1_meta_decoded.map(m => RegEnable(m.uncorrectable, s1_meta_clk_en)).asUInt + val s2_meta_error_uncorrectable = s2_meta_uncorrectable_errors.orR val s2_meta_corrected = s1_meta_decoded.map(m => RegEnable(m.corrected, s1_meta_clk_en).asTypeOf(new L1Metadata)) - val s2_meta_error = s2_meta_errors.orR + val s2_meta_error = (s2_meta_uncorrectable_errors | s2_meta_correctable_errors).orR val s2_flush_valid = s2_flush_valid_pre_tag_ecc && !s2_meta_error val s2_data = { val en = s1_valid || inWriteback || tl_out.d.fire() @@ -242,6 +249,7 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) { val s2_word_idx = s2_req.addr.extract(log2Up(rowBits/8)-1, log2Up(wordBytes)) val s2_did_read = RegEnable(s1_did_read, s1_valid_not_nacked) val s2_data_error = s2_did_read && (s2_data_decoded.map(_.error).grouped(wordBits/eccBits).map(_.reduce(_||_)).toSeq)(s2_word_idx) + val s2_data_error_uncorrectable = (s2_data_decoded.map(_.uncorrectable).grouped(wordBits/eccBits).map(_.reduce(_||_)).toSeq)(s2_word_idx) val s2_data_corrected = (s2_data_decoded.map(_.corrected): Seq[UInt]).asUInt val s2_data_uncorrected = (s2_data_decoded.map(_.uncorrected): Seq[UInt]).asUInt val s2_valid_hit_pre_data_ecc = s2_valid_masked && s2_readwrite && !s2_meta_error && s2_hit @@ -264,9 +272,10 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) { // tag updates on ECC errors metaArb.io.in(1).valid := s2_meta_error && (s2_valid_masked || s2_flush_valid_pre_tag_ecc || s2_probe) metaArb.io.in(1).bits.write := true - metaArb.io.in(1).bits.way_en := PriorityEncoderOH(s2_meta_errors) + metaArb.io.in(1).bits.way_en := s2_meta_uncorrectable_errors | Mux(s2_meta_error_uncorrectable, 0.U, PriorityEncoderOH(s2_meta_correctable_errors)) metaArb.io.in(1).bits.addr := Cat(io.cpu.req.bits.addr >> untagBits, Mux(s2_probe, probe_bits.address, s2_req.addr)(idxMSB, 0)) - metaArb.io.in(1).bits.data := PriorityMux(s2_meta_errors, s2_meta_corrected) + metaArb.io.in(1).bits.data := PriorityMux(s2_meta_correctable_errors, s2_meta_corrected) + when (s2_meta_error_uncorrectable) { metaArb.io.in(1).bits.data.coh := ClientMetadata.onReset } // tag updates on hit/miss metaArb.io.in(2).valid := (s2_valid_hit && s2_update_meta) || (s2_victimize && !s2_victim_dirty) @@ -703,6 +712,28 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) { io.cpu.perf.release := edge.done(tl_out_c) io.cpu.perf.tlbMiss := io.ptw.req.fire() + // report errors + { + val (data_error, data_error_uncorrectable, data_error_addr) = + if (usingDataScratchpad) (s2_valid_data_error, s2_data_error_uncorrectable, s2_req.addr) else { + (tl_out_c.valid && edge.hasData(tl_out_c.bits) && s2_data_decoded.map(_.error).reduce(_||_), + s2_data_decoded.map(_.uncorrectable).reduce(_||_), + tl_out_c.bits.address) + } + val error_addr = + Mux(metaArb.io.in(1).valid, Cat(metaArb.io.in(1).bits.data.tag, metaArb.io.in(1).bits.addr(untagBits-1, idxLSB)), + data_error_addr >> idxLSB) << idxLSB + io.errors.uncorrectable.foreach { u => + u.valid := metaArb.io.in(1).valid && s2_meta_error_uncorrectable || data_error && data_error_uncorrectable + u.bits := error_addr + } + io.errors.correctable.foreach { c => + c.valid := metaArb.io.in(1).valid || data_error + c.bits := error_addr + io.errors.uncorrectable.foreach { u => when (u.valid) { c.valid := false } } + } + } + def encodeData(x: UInt) = x.grouped(eccBits).map(dECC.encode(_)).asUInt def dummyEncodeData(x: UInt) = x.grouped(eccBits).map(dECC.swizzle(_)).asUInt def decodeData(x: UInt) = x.grouped(dECC.width(eccBits)).map(dECC.decode(_)) diff --git a/src/main/scala/rocket/HellaCache.scala b/src/main/scala/rocket/HellaCache.scala index 60cc9086..a4253671 100644 --- a/src/main/scala/rocket/HellaCache.scala +++ b/src/main/scala/rocket/HellaCache.scala @@ -177,6 +177,7 @@ class HellaCacheBundle(outer: HellaCache)(implicit p: Parameters) extends CoreBu val cpu = (new HellaCacheIO).flip val ptw = new TLBPTWIO() val mem = outer.node.bundleOut + val errors = new DCacheErrors } class HellaCacheModule(outer: HellaCache) extends LazyModuleImp(outer) From 79dab487fcf52cef11a720f4ddbbe88af6d560d2 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Fri, 15 Sep 2017 18:46:19 -0700 Subject: [PATCH 4/8] Implement bus error unit --- src/main/scala/rocket/BusErrorUnit.scala | 75 ++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 src/main/scala/rocket/BusErrorUnit.scala diff --git a/src/main/scala/rocket/BusErrorUnit.scala b/src/main/scala/rocket/BusErrorUnit.scala new file mode 100644 index 00000000..76e40b61 --- /dev/null +++ b/src/main/scala/rocket/BusErrorUnit.scala @@ -0,0 +1,75 @@ +// 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._ + +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, + None, None, dcache.correctable, dcache.uncorrectable) +} + +class BusErrorUnit[T <: BusErrors](t: => T, addr: BigInt)(implicit p: Parameters) extends LazyModule { + val regWidth = 64 + val size = 64 + val device = new SimpleDevice("bus-error-unit", Seq("sifive,buserror0")) + val intNode = IntSourceNode(IntSourcePortSimple(resources = device.int)) + val node = TLRegisterNode( + address = Seq(AddressSet(addr, size-1)), + device = device, + beatBytes = p(XLen)/8) + + lazy val module = new LazyModuleImp(this) { + val io = new Bundle { + val tl = node.bundleIn + val interrupt = intNode.bundleOut + val errors = t.flip + } + + 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(_.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)) + + 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 + } + } + + io.interrupt.head(0) := (accrued & interrupt).orR + + 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 })) + + node.regmap( + 0 -> Seq(reg(cause), + reg(value), + maskedReg(enable, mask), + maskedReg(interrupt, mask), + maskedReg(accrued, mask))) + } +} From dbf599f6a1dfe941c48df4f00298a82dd5dafd96 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Tue, 19 Sep 2017 12:05:00 -0700 Subject: [PATCH 5/8] Support SynchronizerShiftReg(sync = 0) This makes it easier to parameterize code where the synchronizer might not always be needed. --- src/main/scala/util/ShiftReg.scala | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/scala/util/ShiftReg.scala b/src/main/scala/util/ShiftReg.scala index 917447f8..f8827c2d 100644 --- a/src/main/scala/util/ShiftReg.scala +++ b/src/main/scala/util/ShiftReg.scala @@ -125,8 +125,10 @@ class SynchronizerShiftReg(w: Int = 1, sync: Int = 3) extends AbstractPipelineRe object SynchronizerShiftReg { - def apply [T <: Chisel.Data](in: T, sync: Int = 3, name: Option[String] = None): T = - AbstractPipelineReg(new SynchronizerShiftReg(in.getWidth, sync), in, name) + def apply [T <: Chisel.Data](in: T, sync: Int = 3, name: Option[String] = None): T = { + if (sync == 0) in + else AbstractPipelineReg(new SynchronizerShiftReg(in.getWidth, sync), in, name) + } } class SyncResetSynchronizerShiftReg(w: Int = 1, sync: Int = 3, init: Int = 0) extends AbstractPipelineReg(w) { From afad25fcebc557e345f66e5ec8400c7f4f21279f Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Fri, 15 Sep 2017 18:49:40 -0700 Subject: [PATCH 6/8] Integrate L1 BusErrorUnit --- src/main/scala/coreplex/RocketCoreplex.scala | 2 ++ src/main/scala/rocket/BusErrorUnit.scala | 9 +++++---- src/main/scala/rocket/RocketCore.scala | 1 + src/main/scala/rocket/ScratchpadSlavePort.scala | 15 ++++++++++++++- src/main/scala/tile/Core.scala | 1 + src/main/scala/tile/RocketTile.scala | 16 ++++++++++++++++ 6 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/main/scala/coreplex/RocketCoreplex.scala b/src/main/scala/coreplex/RocketCoreplex.scala index f39f5db0..6bac3fd4 100644 --- a/src/main/scala/coreplex/RocketCoreplex.scala +++ b/src/main/scala/coreplex/RocketCoreplex.scala @@ -84,6 +84,8 @@ trait HasRocketTiles extends HasSystemBus lip.foreach { coreIntXbar.intnode := _ } // lip wrapper.coreIntNode := coreIntXbar.intnode + wrapper.intOutputNode.foreach { plic.intnode := _ } + wrapper } } diff --git a/src/main/scala/rocket/BusErrorUnit.scala b/src/main/scala/rocket/BusErrorUnit.scala index 76e40b61..45a75eeb 100644 --- a/src/main/scala/rocket/BusErrorUnit.scala +++ b/src/main/scala/rocket/BusErrorUnit.scala @@ -25,13 +25,14 @@ class L1BusErrors(implicit p: Parameters) extends CoreBundle()(p) with BusErrors None, None, dcache.correctable, dcache.uncorrectable) } -class BusErrorUnit[T <: BusErrors](t: => T, addr: BigInt)(implicit p: Parameters) extends LazyModule { +case class BusErrorUnitParams(addr: BigInt, size: Int = 4096) + +class BusErrorUnit[T <: BusErrors](t: => T, params: BusErrorUnitParams)(implicit p: Parameters) extends LazyModule { val regWidth = 64 - val size = 64 val device = new SimpleDevice("bus-error-unit", Seq("sifive,buserror0")) val intNode = IntSourceNode(IntSourcePortSimple(resources = device.int)) val node = TLRegisterNode( - address = Seq(AddressSet(addr, size-1)), + address = Seq(AddressSet(params.addr, params.size-1)), device = device, beatBytes = p(XLen)/8) @@ -45,7 +46,7 @@ class BusErrorUnit[T <: BusErrors](t: => T, addr: BigInt)(implicit p: Parameters 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(_.getWidth).max)) + 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)) diff --git a/src/main/scala/rocket/RocketCore.scala b/src/main/scala/rocket/RocketCore.scala index 15d2ac6e..898fa9b1 100644 --- a/src/main/scala/rocket/RocketCore.scala +++ b/src/main/scala/rocket/RocketCore.scala @@ -30,6 +30,7 @@ case class RocketCoreParams( fastLoadWord: Boolean = true, fastLoadByte: Boolean = false, jumpInFrontend: Boolean = true, + tileControlAddr: Option[BigInt] = None, mulDiv: Option[MulDivParams] = Some(MulDivParams()), fpu: Option[FPUParams] = Some(FPUParams()) ) extends CoreParams { diff --git a/src/main/scala/rocket/ScratchpadSlavePort.scala b/src/main/scala/rocket/ScratchpadSlavePort.scala index 2d27642c..201fb7d0 100644 --- a/src/main/scala/rocket/ScratchpadSlavePort.scala +++ b/src/main/scala/rocket/ScratchpadSlavePort.scala @@ -100,21 +100,29 @@ trait CanHaveScratchpad extends HasHellaCache with HasICacheFrontend { val module: CanHaveScratchpadModule val cacheBlockBytes = p(CacheBlockBytes) - val slaveNode = TLInputNode() // Up to two uses for this input node: + val intOutputNode = tileParams.core.tileControlAddr.map(dummy => IntOutputNode()) + val slaveNode = TLInputNode() // Up to three uses for this input node: // 1) Frontend always exists, but may or may not have a scratchpad node // 2) ScratchpadSlavePort always has a node, but only exists when the HellaCache has a scratchpad + // 3) BusErrorUnit sometimes has a node val fg = LazyModule(new TLFragmenter(tileParams.core.fetchBytes, cacheBlockBytes, earlyAck=true)) val ww = LazyModule(new TLWidthWidget(xBytes)) val scratch = tileParams.dcache.flatMap { d => d.scratch.map(s => LazyModule(new ScratchpadSlavePort(AddressSet(s, d.dataScratchpadBytes-1), xBytes, tileParams.core.useAtomics))) } + val busErrorUnit = tileParams.core.tileControlAddr map { a => + val beu = LazyModule(new BusErrorUnit(new L1BusErrors, BusErrorUnitParams(a))) + intOutputNode.get := beu.intNode + beu + } DisableMonitors { implicit p => frontend.slaveNode :*= fg.node fg.node :*= ww.node ww.node :*= slaveNode scratch foreach { lm => lm.node := TLFragmenter(xBytes, cacheBlockBytes, earlyAck=true)(slaveNode) } + busErrorUnit foreach { lm => lm.node := TLFragmenter(xBytes, cacheBlockBytes, earlyAck=true)(slaveNode) } } def findScratchpadFromICache: Option[AddressSet] = scratch.map { s => @@ -130,6 +138,7 @@ trait CanHaveScratchpad extends HasHellaCache with HasICacheFrontend { trait CanHaveScratchpadBundle extends HasHellaCacheBundle with HasICacheFrontendBundle { val outer: CanHaveScratchpad val slave = outer.slaveNode.bundleIn + val intOutput = outer.intOutputNode.map(_.bundleOut) } trait CanHaveScratchpadModule extends HasHellaCacheModule with HasICacheFrontendModule { @@ -137,4 +146,8 @@ trait CanHaveScratchpadModule extends HasHellaCacheModule with HasICacheFrontend val io: CanHaveScratchpadBundle outer.scratch.foreach { lm => dcachePorts += lm.module.io.dmem } + outer.busErrorUnit.foreach { lm => + lm.module.io.errors.dcache := outer.dcache.module.io.errors + lm.module.io.errors.icache := outer.frontend.module.io.errors + } } diff --git a/src/main/scala/tile/Core.scala b/src/main/scala/tile/Core.scala index a4133c8f..0662b678 100644 --- a/src/main/scala/tile/Core.scala +++ b/src/main/scala/tile/Core.scala @@ -27,6 +27,7 @@ trait CoreParams { val nLocalInterrupts: Int val nL2TLBEntries: Int val jumpInFrontend: Boolean + val tileControlAddr: Option[BigInt] def instBytes: Int = instBits / 8 def fetchBytes: Int = fetchWidth * instBytes diff --git a/src/main/scala/tile/RocketTile.scala b/src/main/scala/tile/RocketTile.scala index 72467826..1e2db5f6 100644 --- a/src/main/scala/tile/RocketTile.scala +++ b/src/main/scala/tile/RocketTile.scala @@ -168,6 +168,7 @@ abstract class RocketTileWrapper(rtp: RocketTileParams, hartid: Int)(implicit p: val rocket = LazyModule(new RocketTile(rtp, hartid)) val masterNode: OutputNode[_,_,_,_,_] val slaveNode: InputNode[_,_,_,_,_] + val intOutputNode = rocket.intOutputNode.map(dummy => IntOutputNode()) val asyncIntNode = IntInputNode() val periphIntNode = IntInputNode() val coreIntNode = IntInputNode() @@ -195,10 +196,19 @@ abstract class RocketTileWrapper(rtp: RocketTileParams, hartid: Int)(implicit p: } } + def outputInterruptXingLatency: Int + + rocket.intOutputNode.foreach { rocketIntOutputNode => + val outXing = LazyModule(new IntXing(outputInterruptXingLatency)) + intOutputNode.get := outXing.intnode + outXing.intnode := rocketIntOutputNode + } + lazy val module = new LazyModuleImp(this) { val io = new CoreBundle with HasExternallyDrivenTileConstants { val master = masterNode.bundleOut val slave = slaveNode.bundleIn + val outputInterrupts = intOutputNode.map(_.bundleOut) val asyncInterrupts = asyncIntNode.bundleIn val periphInterrupts = periphIntNode.bundleIn val coreInterrupts = coreIntNode.bundleIn @@ -224,6 +234,8 @@ class SyncRocketTile(rtp: RocketTileParams, hartid: Int)(implicit p: Parameters) intXbar.intnode := xing.intnode intXbar.intnode := periphIntNode intXbar.intnode := coreIntNode + + def outputInterruptXingLatency = 0 } class AsyncRocketTile(rtp: RocketTileParams, hartid: Int)(implicit p: Parameters) extends RocketTileWrapper(rtp, hartid) { @@ -251,6 +263,8 @@ class AsyncRocketTile(rtp: RocketTileParams, hartid: Int)(implicit p: Parameters intXbar.intnode := asyncXing.intnode intXbar.intnode := periphXing.intnode intXbar.intnode := coreIntNode + + def outputInterruptXingLatency = 3 } class RationalRocketTile(rtp: RocketTileParams, hartid: Int)(implicit p: Parameters) extends RocketTileWrapper(rtp, hartid) { @@ -279,4 +293,6 @@ class RationalRocketTile(rtp: RocketTileParams, hartid: Int)(implicit p: Paramet intXbar.intnode := asyncXing.intnode intXbar.intnode := periphXing.intnode intXbar.intnode := coreIntNode + + def outputInterruptXingLatency = 1 } From aaad73f01980063f1e47be14c9357d2d75ed8bf5 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Tue, 19 Sep 2017 17:49:27 -0700 Subject: [PATCH 7/8] Add an intra-tile xbar --- .../scala/rocket/ScratchpadSlavePort.scala | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/main/scala/rocket/ScratchpadSlavePort.scala b/src/main/scala/rocket/ScratchpadSlavePort.scala index 201fb7d0..08959679 100644 --- a/src/main/scala/rocket/ScratchpadSlavePort.scala +++ b/src/main/scala/rocket/ScratchpadSlavePort.scala @@ -100,29 +100,32 @@ trait CanHaveScratchpad extends HasHellaCache with HasICacheFrontend { val module: CanHaveScratchpadModule val cacheBlockBytes = p(CacheBlockBytes) - val intOutputNode = tileParams.core.tileControlAddr.map(dummy => IntOutputNode()) - val slaveNode = TLInputNode() // Up to three uses for this input node: - - // 1) Frontend always exists, but may or may not have a scratchpad node - // 2) ScratchpadSlavePort always has a node, but only exists when the HellaCache has a scratchpad - // 3) BusErrorUnit sometimes has a node - val fg = LazyModule(new TLFragmenter(tileParams.core.fetchBytes, cacheBlockBytes, earlyAck=true)) - val ww = LazyModule(new TLWidthWidget(xBytes)) val scratch = tileParams.dcache.flatMap { d => d.scratch.map(s => LazyModule(new ScratchpadSlavePort(AddressSet(s, d.dataScratchpadBytes-1), xBytes, tileParams.core.useAtomics))) } + + val intOutputNode = tileParams.core.tileControlAddr.map(dummy => IntOutputNode()) val busErrorUnit = tileParams.core.tileControlAddr map { a => val beu = LazyModule(new BusErrorUnit(new L1BusErrors, BusErrorUnitParams(a))) intOutputNode.get := beu.intNode beu } + // connect any combination of ITIM, DTIM, and BusErrorUnit + val slaveNode = TLInputNode() DisableMonitors { implicit p => - frontend.slaveNode :*= fg.node - fg.node :*= ww.node - ww.node :*= slaveNode - scratch foreach { lm => lm.node := TLFragmenter(xBytes, cacheBlockBytes, earlyAck=true)(slaveNode) } - busErrorUnit foreach { lm => lm.node := TLFragmenter(xBytes, cacheBlockBytes, earlyAck=true)(slaveNode) } + val xbarPorts = + scratch.map(lm => (lm.node, xBytes)) ++ + busErrorUnit.map(lm => (lm.node, xBytes)) ++ + tileParams.icache.flatMap(icache => icache.itimAddr.map(a => (frontend.slaveNode, tileParams.core.fetchBytes))) + + if (xbarPorts.nonEmpty) { + val xbar = LazyModule(new TLXbar) + xbar.node := TLFIFOFixer()(TLFragmenter(xBytes, cacheBlockBytes, earlyAck=true)(slaveNode)) + xbarPorts.foreach { case (port, bytes) => + port := (if (bytes == xBytes) xbar.node else TLFragmenter(bytes, xBytes, earlyAck=true)(TLWidthWidget(xBytes)(xbar.node))) + } + } } def findScratchpadFromICache: Option[AddressSet] = scratch.map { s => From db57e943f316c7576b08a8ae7c1d6e7031ab52eb Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Wed, 20 Sep 2017 00:04:33 -0700 Subject: [PATCH 8/8] Report TL errors into D$ --- src/main/scala/rocket/BusErrorUnit.scala | 2 +- src/main/scala/rocket/DCache.scala | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/scala/rocket/BusErrorUnit.scala b/src/main/scala/rocket/BusErrorUnit.scala index 45a75eeb..fb263db3 100644 --- a/src/main/scala/rocket/BusErrorUnit.scala +++ b/src/main/scala/rocket/BusErrorUnit.scala @@ -22,7 +22,7 @@ class L1BusErrors(implicit p: Parameters) extends CoreBundle()(p) with BusErrors def toErrorList = List(None, None, icache.correctable, icache.uncorrectable, - None, None, dcache.correctable, dcache.uncorrectable) + None, Some(dcache.bus), dcache.correctable, dcache.uncorrectable) } case class BusErrorUnitParams(addr: BigInt, size: Int = 4096) diff --git a/src/main/scala/rocket/DCache.scala b/src/main/scala/rocket/DCache.scala index dfc42aef..d703914e 100644 --- a/src/main/scala/rocket/DCache.scala +++ b/src/main/scala/rocket/DCache.scala @@ -14,6 +14,7 @@ import TLMessages._ class DCacheErrors(implicit p: Parameters) extends L1HellaCacheBundle()(p) { val correctable = (cacheParams.tagECC.canCorrect || cacheParams.dataECC.canCorrect).option(Valid(UInt(width = paddrBits))) val uncorrectable = (cacheParams.tagECC.canDetect || cacheParams.dataECC.canDetect).option(Valid(UInt(width = paddrBits))) + val bus = Valid(UInt(width = paddrBits)) } class DCacheDataReq(implicit p: Parameters) extends L1HellaCacheBundle()(p) { @@ -732,6 +733,8 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) { c.bits := error_addr io.errors.uncorrectable.foreach { u => when (u.valid) { c.valid := false } } } + io.errors.bus.valid := tl_out.d.fire() && tl_out.d.bits.error + io.errors.bus.bits := Mux(grantIsCached, s2_req.addr >> idxLSB << idxLSB, 0.U) } def encodeData(x: UInt) = x.grouped(eccBits).map(dECC.encode(_)).asUInt