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/groundtest/TraceGen.scala b/src/main/scala/groundtest/TraceGen.scala index f9876c66..f1779776 100644 --- a/src/main/scala/groundtest/TraceGen.scala +++ b/src/main/scala/groundtest/TraceGen.scala @@ -65,6 +65,7 @@ case class TraceGenParams( memStart: BigInt, //p(ExtMem).base numGens: Int) extends GroundTestTileParams { def build(i: Int, p: Parameters): GroundTestTile = new TraceGenTile(i, this)(p) + val trace = false } trait HasTraceGenParams { diff --git a/src/main/scala/rocket/BusErrorUnit.scala b/src/main/scala/rocket/BusErrorUnit.scala new file mode 100644 index 00000000..fb263db3 --- /dev/null +++ b/src/main/scala/rocket/BusErrorUnit.scala @@ -0,0 +1,76 @@ +// 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, Some(dcache.bus), dcache.correctable, dcache.uncorrectable) +} + +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 device = new SimpleDevice("bus-error-unit", Seq("sifive,buserror0")) + val intNode = IntSourceNode(IntSourcePortSimple(resources = device.int)) + val node = TLRegisterNode( + address = Seq(AddressSet(params.addr, params.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(_.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)) + + 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))) + } +} diff --git a/src/main/scala/rocket/CSR.scala b/src/main/scala/rocket/CSR.scala index fefc41b5..17c35993 100644 --- a/src/main/scala/rocket/CSR.scala +++ b/src/main/scala/rocket/CSR.scala @@ -149,6 +149,16 @@ class PerfCounterIO(implicit p: Parameters) extends CoreBundle val inc = UInt(INPUT, log2Ceil(1+retireWidth)) } +class TracedInstruction(implicit p: Parameters) extends CoreBundle { + val valid = Bool() + val addr = UInt(width = coreMaxAddrBits) + val insn = UInt(width = iLen) + val priv = UInt(width = 3) + val exception = Bool() + val cause = UInt(width = 1 + log2Ceil(xLen)) + val tval = UInt(width = coreMaxAddrBits max iLen) +} + class CSRFileIO(implicit p: Parameters) extends CoreBundle with HasRocketCoreParameters { val interrupts = new TileInterrupts().asInput @@ -192,6 +202,8 @@ class CSRFileIO(implicit p: Parameters) extends CoreBundle val bp = Vec(nBreakpoints, new BP).asOutput val pmp = Vec(nPMPs, new PMP).asOutput val counters = Vec(nPerfCounters, new PerfCounterIO) + val inst = Vec(retireWidth, UInt(width = iLen)).asInput + val trace = Vec(retireWidth, new TracedInstruction).asOutput } class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Parameters) extends CoreModule()(p) @@ -506,15 +518,14 @@ class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Param assert(!io.singleStep || io.retire <= UInt(1)) assert(!reg_singleStepped || io.retire === UInt(0)) + val epc = ~(~io.pc | (coreInstBytes-1)) + val write_badaddr = cause isOneOf (Causes.illegal_instruction, Causes.breakpoint, + Causes.misaligned_load, Causes.misaligned_store, + Causes.load_access, Causes.store_access, Causes.fetch_access, + Causes.load_page_fault, Causes.store_page_fault, Causes.fetch_page_fault) + val badaddr_value = Mux(write_badaddr, io.badaddr, 0.U) + when (exception) { - val epc = ~(~io.pc | (coreInstBytes-1)) - - val write_badaddr = cause isOneOf (Causes.illegal_instruction, Causes.breakpoint, - Causes.misaligned_load, Causes.misaligned_store, - Causes.load_access, Causes.store_access, Causes.fetch_access, - Causes.load_page_fault, Causes.store_page_fault, Causes.fetch_page_fault) - val badaddr_value = Mux(write_badaddr, io.badaddr, 0.U) - when (trapToDebug) { when (!reg_debug) { reg_debug := true @@ -756,6 +767,16 @@ class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Param } } + for (((t, insn), i) <- (io.trace zip io.inst).zipWithIndex) { + t.exception := io.retire >= i && exception + t.valid := io.retire > i || t.exception + t.insn := insn + t.addr := io.pc + t.priv := Cat(reg_debug, reg_mstatus.prv) + t.cause := Cat(cause(xLen-1), cause(log2Ceil(xLen)-1, 0)) + t.tval := badaddr_value + } + def chooseInterrupt(masks: Seq[UInt]): (Bool, UInt) = { val nonstandard = supported_interrupts.getWidth-1 to 12 by -1 // MEI, MSI, MTI, SEI, SSI, STI, UEI, USI, UTI diff --git a/src/main/scala/rocket/DCache.scala b/src/main/scala/rocket/DCache.scala index 62913f4b..d703914e 100644 --- a/src/main/scala/rocket/DCache.scala +++ b/src/main/scala/rocket/DCache.scala @@ -11,6 +11,12 @@ 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))) + val bus = Valid(UInt(width = paddrBits)) +} + class DCacheDataReq(implicit p: Parameters) extends L1HellaCacheBundle()(p) { val eccBytes = cacheParams.dataECCBytes val addr = Bits(width = untagBits) @@ -216,9 +222,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 +250,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 +273,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 +713,30 @@ 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 } } + } + 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 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/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/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) diff --git a/src/main/scala/rocket/IBuf.scala b/src/main/scala/rocket/IBuf.scala index 4623b65b..b24002de 100644 --- a/src/main/scala/rocket/IBuf.scala +++ b/src/main/scala/rocket/IBuf.scala @@ -16,7 +16,6 @@ class Instruction(implicit val p: Parameters) extends ParameterizedBundle with H val rvc = Bool() val inst = new ExpandedInstruction val raw = UInt(width = 32) - val cinst = UInt(width = 32) require(coreInstBits == (if (usingCompressed) 16 else 32)) } @@ -96,7 +95,6 @@ class IBuf(implicit p: Parameters) extends CoreModule { exp.io.in := curInst io.inst(i).bits.inst := exp.io.out io.inst(i).bits.raw := curInst - io.inst(i).bits.cinst := Mux(exp.io.rvc, curInst & 0xFFFF, curInst) if (usingCompressed) { val replay = ic_replay(j) || (!exp.io.rvc && (btbHitMask(j) || ic_replay(j+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) diff --git a/src/main/scala/rocket/RocketCore.scala b/src/main/scala/rocket/RocketCore.scala index 15d2ac6e..9ed8fea9 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 { @@ -136,7 +137,7 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) val ex_reg_replay = Reg(Bool()) val ex_reg_pc = Reg(UInt()) val ex_reg_inst = Reg(Bits()) - val ex_reg_cinst = Reg(Bits()) + val ex_reg_raw_inst = Reg(UInt()) val mem_reg_xcpt_interrupt = Reg(Bool()) val mem_reg_valid = Reg(Bool()) @@ -153,7 +154,7 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) val mem_reg_sfence = Reg(Bool()) val mem_reg_pc = Reg(UInt()) val mem_reg_inst = Reg(Bits()) - val mem_reg_cinst = Reg(Bits()) + val mem_reg_raw_inst = Reg(UInt()) val mem_reg_wdata = Reg(Bits()) val mem_reg_rs2 = Reg(Bits()) val take_pc_mem = Wire(Bool()) @@ -167,7 +168,7 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) val wb_reg_sfence = Reg(Bool()) val wb_reg_pc = Reg(UInt()) val wb_reg_inst = Reg(Bits()) - val wb_reg_cinst = Reg(Bits()) + val wb_reg_raw_inst = Reg(UInt()) val wb_reg_wdata = Reg(Bits()) val wb_reg_rs2 = Reg(Bits()) val take_pc_wb = Wire(Bool()) @@ -178,7 +179,7 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) // decode stage val ibuf = Module(new IBuf) val id_expanded_inst = ibuf.io.inst.map(_.bits.inst) - val id_nonexpanded_inst = ibuf.io.inst.map(_.bits.cinst) + val id_raw_inst = ibuf.io.inst.map(_.bits.raw) val id_inst = id_expanded_inst.map(_.bits) ibuf.io.imem <> io.imem.resp ibuf.io.kill := take_pc @@ -335,7 +336,7 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) } } when (id_illegal_insn) { - val inst = Mux(ibuf.io.inst(0).bits.rvc, ibuf.io.inst(0).bits.raw(15, 0), ibuf.io.inst(0).bits.raw) + val inst = Mux(ibuf.io.inst(0).bits.rvc, id_raw_inst(0)(15, 0), id_raw_inst(0)) ex_reg_rs_bypass(0) := false ex_reg_rs_lsb(0) := inst(log2Ceil(bypass_sources.size)-1, 0) ex_reg_rs_msb(0) := inst >> log2Ceil(bypass_sources.size) @@ -344,7 +345,7 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) when (!ctrl_killd || csr.io.interrupt || ibuf.io.inst(0).bits.replay) { ex_reg_cause := id_cause ex_reg_inst := id_inst(0) - ex_reg_cinst := id_nonexpanded_inst(0) + ex_reg_raw_inst := id_raw_inst(0) ex_reg_pc := ibuf.io.pc ex_reg_btb_resp := ibuf.io.btb_resp } @@ -405,7 +406,7 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) mem_reg_cause := ex_cause mem_reg_inst := ex_reg_inst - mem_reg_cinst := ex_reg_cinst + mem_reg_raw_inst := ex_reg_raw_inst mem_reg_pc := ex_reg_pc mem_reg_wdata := alu.io.out @@ -453,7 +454,7 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) } wb_reg_cause := mem_cause wb_reg_inst := mem_reg_inst - wb_reg_cinst := mem_reg_cinst + wb_reg_raw_inst := mem_reg_raw_inst wb_reg_pc := mem_reg_pc } @@ -513,10 +514,11 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) when (rf_wen) { rf.write(rf_waddr, rf_wdata) } // hook up control/status regfile - csr.io.decode.csr := ibuf.io.inst(0).bits.raw(31,20) + csr.io.decode.csr := id_raw_inst(0)(31,20) csr.io.exception := wb_xcpt csr.io.cause := wb_cause csr.io.retire := wb_valid + csr.io.inst(0) := Cat(Mux(wb_reg_rvc, 0.U, wb_reg_inst >> 16), wb_reg_raw_inst(15, 0)) csr.io.interrupts := io.interrupts csr.io.hartid := io.hartid io.fpu.fcsr_rm := csr.io.fcsr_rm @@ -530,6 +532,7 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) csr.io.rw.addr := wb_reg_inst(31,20) csr.io.rw.cmd := Mux(wb_reg_valid, wb_ctrl.csr, CSR.N) csr.io.rw.wdata := wb_reg_wdata + io.trace := csr.io.trace val hazard_targets = Seq((id_ctrl.rxs1 && id_raddr1 =/= UInt(0), id_raddr1), (id_ctrl.rxs2 && id_raddr2 =/= UInt(0), id_raddr2), @@ -664,28 +667,24 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) csr.io.counters foreach { c => c.inc := RegNext(perfEvents.evaluate(c.eventSel)) } if (enableCommitLog) { - val pc = Wire(SInt(width=xLen)) - pc := wb_reg_pc.asSInt - val inst = wb_reg_inst - val cinst = wb_reg_cinst - val rd = RegNext(RegNext(RegNext(id_waddr))) + val t = csr.io.trace(0) + val rd = wb_waddr val wfd = wb_ctrl.wfd val wxd = wb_ctrl.wxd val has_data = wb_wen && !wb_set_sboard - val priv = csr.io.status.prv - when (wb_valid) { + when (t.valid) { when (wfd) { - printf ("%d 0x%x (0x%x) f%d p%d 0xXXXXXXXXXXXXXXXX\n", priv, pc, cinst, rd, rd+UInt(32)) + printf ("%d 0x%x (0x%x) f%d p%d 0xXXXXXXXXXXXXXXXX\n", t.priv, t.addr, t.insn, rd, rd+UInt(32)) } .elsewhen (wxd && rd =/= UInt(0) && has_data) { - printf ("%d 0x%x (0x%x) x%d 0x%x\n", priv, pc, cinst, rd, rf_wdata) + printf ("%d 0x%x (0x%x) x%d 0x%x\n", t.priv, t.addr, t.insn, rd, rf_wdata) } .elsewhen (wxd && rd =/= UInt(0) && !has_data) { - printf ("%d 0x%x (0x%x) x%d p%d 0xXXXXXXXXXXXXXXXX\n", priv, pc, cinst, rd, rd) + printf ("%d 0x%x (0x%x) x%d p%d 0xXXXXXXXXXXXXXXXX\n", t.priv, t.addr, t.insn, rd, rd) } .otherwise { - printf ("%d 0x%x (0x%x)\n", priv, pc, cinst) + printf ("%d 0x%x (0x%x)\n", t.priv, t.addr, t.insn) } } @@ -695,11 +694,11 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) } else { printf("C%d: %d [%d] pc=[%x] W[r%d=%x][%d] R[r%d=%x] R[r%d=%x] inst=[%x] DASM(%x)\n", - io.hartid, csr.io.time(31,0), wb_valid, wb_reg_pc, + io.hartid, csr.io.time(31,0), csr.io.trace(0).valid, csr.io.trace(0).addr(vaddrBitsExtended-1, 0), Mux(rf_wen && !(wb_set_sboard && wb_wen), rf_waddr, UInt(0)), rf_wdata, rf_wen, wb_reg_inst(19,15), Reg(next=Reg(next=ex_rs(0))), wb_reg_inst(24,20), Reg(next=Reg(next=ex_rs(1))), - wb_reg_cinst, wb_reg_cinst) + csr.io.trace(0).insn, csr.io.trace(0).insn) } val max_core_cycles = PlusArg("max-core-cycles", diff --git a/src/main/scala/rocket/ScratchpadSlavePort.scala b/src/main/scala/rocket/ScratchpadSlavePort.scala index 2d27642c..08959679 100644 --- a/src/main/scala/rocket/ScratchpadSlavePort.scala +++ b/src/main/scala/rocket/ScratchpadSlavePort.scala @@ -100,21 +100,32 @@ trait CanHaveScratchpad extends HasHellaCache with HasICacheFrontend { val module: CanHaveScratchpadModule val cacheBlockBytes = p(CacheBlockBytes) - val slaveNode = TLInputNode() // Up to two 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 - 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) } + 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 => @@ -130,6 +141,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 +149,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/BaseTile.scala b/src/main/scala/tile/BaseTile.scala index 89ac5168..644ccb6a 100644 --- a/src/main/scala/tile/BaseTile.scala +++ b/src/main/scala/tile/BaseTile.scala @@ -21,6 +21,7 @@ trait TileParams { val dcache: Option[DCacheParams] val rocc: Seq[RoCCParams] val btb: Option[BTBParams] + val trace: Boolean } trait HasTileParameters { @@ -37,6 +38,7 @@ trait HasTileParameters { def xLen: Int = p(XLen) def xBytes: Int = xLen / 8 + def iLen: Int = 32 def pgIdxBits: Int = 12 def pgLevelBits: Int = 10 - log2Ceil(xLen / 32) def vaddrBits: Int = pgIdxBits + pgLevels * pgLevelBits @@ -92,6 +94,10 @@ trait HasExternallyDrivenTileConstants extends Bundle with HasTileParameters { val reset_vector = UInt(INPUT, resetVectorLen) } +trait CanHaveInstructionTracePort extends Bundle with HasTileParameters { + val trace = tileParams.trace.option(Vec(tileParams.core.retireWidth, new TracedInstruction).asOutput) +} + /** Base class for all Tiles that use TileLink */ abstract class BaseTile(tileParams: TileParams)(implicit p: Parameters) extends BareTile with HasTileParameters @@ -102,6 +108,7 @@ abstract class BaseTile(tileParams: TileParams)(implicit p: Parameters) extends class BaseTileBundle[+L <: BaseTile](_outer: L) extends BareTileBundle(_outer) with HasTileLinkMasterPortBundle with HasExternallyDrivenTileConstants + with CanHaveInstructionTracePort class BaseTileModule[+L <: BaseTile, +B <: BaseTileBundle[L]](_outer: L, _io: () => B) extends BareTileModule(_outer, _io) with HasTileParameters diff --git a/src/main/scala/tile/Core.scala b/src/main/scala/tile/Core.scala index a4133c8f..da400df9 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 @@ -75,5 +76,6 @@ trait HasCoreIO extends HasTileParameters { val ptw = new DatapathPTWIO().flip val fpu = new FPUCoreIO().flip val rocc = new RoCCCoreIO().flip + val trace = Vec(coreParams.retireWidth, new TracedInstruction).asOutput } } diff --git a/src/main/scala/tile/RocketTile.scala b/src/main/scala/tile/RocketTile.scala index 72467826..f36dbdc0 100644 --- a/src/main/scala/tile/RocketTile.scala +++ b/src/main/scala/tile/RocketTile.scala @@ -19,6 +19,7 @@ case class RocketTileParams( btb: Option[BTBParams] = Some(BTBParams()), dataScratchpadBytes: Int = 0, boundaryBuffers: Boolean = false, + trace: Boolean = false, name: Option[String] = Some("tile"), externalMasterBuffers: Int = 0, externalSlaveBuffers: Int = 0) extends TileParams { @@ -139,6 +140,7 @@ class RocketTileModule(outer: RocketTile) extends BaseTileModule(outer, () => ne val core = Module(p(BuildCore)(outer.p)) decodeCoreInterrupts(core.io.interrupts) // Decode the interrupt vector core.io.hartid := io.hartid // Pass through the hartid + io.trace.foreach { _ := core.io.trace } outer.frontend.module.io.cpu <> core.io.imem outer.frontend.module.io.reset_vector := io.reset_vector outer.frontend.module.io.hartid := io.hartid @@ -168,6 +170,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 +198,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 io = new CoreBundle with HasExternallyDrivenTileConstants with CanHaveInstructionTracePort { 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 @@ -206,6 +218,7 @@ abstract class RocketTileWrapper(rtp: RocketTileParams, hartid: Int)(implicit p: // signals that do not change based on crossing type: rocket.module.io.hartid := io.hartid rocket.module.io.reset_vector := io.reset_vector + io.trace.foreach { _ := rocket.module.io.trace.get } } } @@ -224,6 +237,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 +266,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 +296,6 @@ class RationalRocketTile(rtp: RocketTileParams, hartid: Int)(implicit p: Paramet intXbar.intnode := asyncXing.intnode intXbar.intnode := periphXing.intnode intXbar.intnode := coreIntNode + + def outputInterruptXingLatency = 1 } 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 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) {