From fee25585fc26d3336b0101c67bcf8a28f24304db Mon Sep 17 00:00:00 2001 From: sfencevma <15155930562@163.com> Date: Mon, 25 Nov 2024 12:34:33 +0800 Subject: [PATCH] feat(DCache RAS): add DCache RAS inject support --- src/main/scala/top/Configs.scala | 10 +- src/main/scala/xiangshan/L2Top.scala | 14 +- src/main/scala/xiangshan/Parameters.scala | 3 + src/main/scala/xiangshan/XSTile.scala | 2 +- .../scala/xiangshan/backend/MemBlock.scala | 8 + src/main/scala/xiangshan/backend/fu/PMA.scala | 5 +- .../xiangshan/cache/dcache/CtrlUnit.scala | 160 ++++++++++++++++++ .../cache/dcache/DCacheWrapper.scala | 58 ++++++- .../cache/dcache/data/BankedDataArray.scala | 71 +++++++- .../cache/dcache/loadpipe/LoadPipe.scala | 69 +++++--- .../cache/dcache/mainpipe/MainPipe.scala | 48 ++++-- 11 files changed, 396 insertions(+), 52 deletions(-) create mode 100644 src/main/scala/xiangshan/cache/dcache/CtrlUnit.scala diff --git a/src/main/scala/top/Configs.scala b/src/main/scala/top/Configs.scala index 4fd63c70f19..8e52419ff01 100644 --- a/src/main/scala/top/Configs.scala +++ b/src/main/scala/top/Configs.scala @@ -24,6 +24,7 @@ import utility._ import system._ import org.chipsalliance.cde.config._ import freechips.rocketchip.tile.{BusErrorUnit, BusErrorUnitParams, XLen} +import freechips.rocketchip.diplomacy._ import xiangshan.frontend.icache.ICacheParameters import freechips.rocketchip.devices.debug._ import freechips.rocketchip.tile.{MaxHartIdBits, XLen} @@ -35,7 +36,7 @@ import openLLC.{OpenLLCParam} import xiangshan._ import xiangshan.backend.dispatch.DispatchParameters import xiangshan.backend.regfile.{IntPregParams, VfPregParams} -import xiangshan.cache.DCacheParameters +import xiangshan.cache.{DCacheParameters, L1CacheCtrlParams} import xiangshan.cache.mmu.{L2TLBParameters, TLBParameters} import device.{EnableJtag, XSDebugModuleParams} import huancun._ @@ -128,6 +129,7 @@ class MinimalConfig(n: Int = 1) extends Config( nProbeEntries = 4, nReleaseEntries = 8, nMaxPrefetchEntry = 2, + cacheCtrlAddressOpt = Some(AddressSet(0x38022000, 0x7f)) )), // ============ BPU =============== EnableLoop = false, @@ -254,7 +256,8 @@ class MinimalSimConfig(n: Int = 1) extends Config( class WithNKBL1D(n: Int, ways: Int = 8) extends Config((site, here, up) => { case XSTileKey => val sets = n * 1024 / ways / 64 - up(XSTileKey).map(_.copy( + up(XSTileKey).map( + p => p.copy( dcacheParametersOpt = Some(DCacheParameters( nSets = sets, nWays = ways, @@ -265,6 +268,9 @@ class WithNKBL1D(n: Int, ways: Int = 8) extends Config((site, here, up) => { nProbeEntries = 8, nReleaseEntries = 18, nMaxPrefetchEntry = 6, + enableTagEcc = true, + enableDataEcc = true, + cacheCtrlAddressOpt = Some(AddressSet(0x38022000, 0x7f)) )) )) }) diff --git a/src/main/scala/xiangshan/L2Top.scala b/src/main/scala/xiangshan/L2Top.scala index 6b037aaacf5..8690aa6d6ce 100644 --- a/src/main/scala/xiangshan/L2Top.scala +++ b/src/main/scala/xiangshan/L2Top.scala @@ -132,11 +132,21 @@ class L2TopInlined()(implicit p: Parameters) extends LazyModule case None => memory_port.get := l1_xbar } - + mmio_xbar := TLBuffer.chainNode(2) := i_mmio_port mmio_xbar := TLBuffer.chainNode(2) := d_mmio_port beu.node := TLBuffer.chainNode(1) := mmio_xbar - mmio_port := TLBuffer() := mmio_xbar + + if (dcacheParameters.cacheCtrlAddressOpt.nonEmpty) { + mmio_port := + TLFilter(TLFilter.mSubtract(dcacheParameters.cacheCtrlAddressOpt.get)) := + TLBuffer() := + mmio_xbar + } else { + mmio_port := + TLBuffer() := + mmio_xbar + } class Imp(wrapper: LazyModule) extends LazyModuleImp(wrapper) { val io = IO(new Bundle { diff --git a/src/main/scala/xiangshan/Parameters.scala b/src/main/scala/xiangshan/Parameters.scala index f5d7f53f617..3ca180e0e14 100644 --- a/src/main/scala/xiangshan/Parameters.scala +++ b/src/main/scala/xiangshan/Parameters.scala @@ -345,6 +345,9 @@ case class XSCoreParameters nProbeEntries = 8, nReleaseEntries = 18, nMaxPrefetchEntry = 6, + enableTagEcc = true, + enableDataEcc = true, + cacheCtrlAddressOpt = Some(AddressSet(0x38022000, 0x7f)) )), L2CacheParamsOpt: Option[L2Param] = Some(L2Param( name = "l2", diff --git a/src/main/scala/xiangshan/XSTile.scala b/src/main/scala/xiangshan/XSTile.scala index 07776dd595e..f03830fbc76 100644 --- a/src/main/scala/xiangshan/XSTile.scala +++ b/src/main/scala/xiangshan/XSTile.scala @@ -102,7 +102,7 @@ class XSTile()(implicit p: Parameters) extends LazyModule // mmio l2top.inner.i_mmio_port := l2top.inner.i_mmio_buffer.node := memBlock.frontendBridge.instr_uncache_node - l2top.inner.d_mmio_port := memBlock.uncache.clientNode + l2top.inner.d_mmio_port := memBlock.uncache_port // =========== IO Connection ============ class XSTileImp(wrapper: LazyModule) extends LazyModuleImp(wrapper) { diff --git a/src/main/scala/xiangshan/backend/MemBlock.scala b/src/main/scala/xiangshan/backend/MemBlock.scala index 5d98400e34d..77bf3417e24 100644 --- a/src/main/scala/xiangshan/backend/MemBlock.scala +++ b/src/main/scala/xiangshan/backend/MemBlock.scala @@ -238,6 +238,8 @@ class MemBlockInlined()(implicit p: Parameters) extends LazyModule val dcache = LazyModule(new DCacheWrapper()) val uncache = LazyModule(new Uncache()) + val uncache_port = TLTempNode() + val uncache_xbar = TLXbar() val ptw = LazyModule(new L2TLBWrapper()) val ptw_to_l2_buffer = if (!coreParams.softPTW) LazyModule(new TLBuffer) else null val l1d_to_l2_buffer = if (coreParams.dcacheParametersOpt.nonEmpty) LazyModule(new TLBuffer) else null @@ -261,6 +263,12 @@ class MemBlockInlined()(implicit p: Parameters) extends LazyModule ptw_to_l2_buffer.node := ptw.node } + uncache_xbar := TLBuffer() := uncache.clientNode + if (dcache.uncacheNode.isDefined) { + dcache.uncacheNode.get := TLBuffer.chainNode(2) := uncache_xbar + } + uncache_port := TLBuffer.chainNode(2) := uncache_xbar + lazy val module = new MemBlockInlinedImp(this) } diff --git a/src/main/scala/xiangshan/backend/fu/PMA.scala b/src/main/scala/xiangshan/backend/fu/PMA.scala index 838daac2163..ed3402c2aae 100644 --- a/src/main/scala/xiangshan/backend/fu/PMA.scala +++ b/src/main/scala/xiangshan/backend/fu/PMA.scala @@ -110,7 +110,8 @@ trait PMAMethod extends PMAConst { MemMap("h00_3801_0000", "h00_3801_FFFF", "h0", "BEU", "RW"), MemMap("h00_3802_0000", "h00_3802_0FFF", "h0", "DebugModule", "RWX"), MemMap("h00_3802_1000", "h00_3802_1FFF", "h0", "MMPMA", "RW"), - MemMap("h00_3802_2000", "h00_3900_0000", "h0", "Reserved", ""), + MemMap("h00_3802_2000", "h00_3802_207F", "h0", "L1DCacheCtrl", "RW"), + MemMap("h00_3802_2080", "h00_38FF_FFFF", "h0", "Reserved", ""), MemMap("h00_3900_0000", "h00_3900_1FFF", "h0", "L3CacheCtrl", "RW"), MemMap("h00_3900_2000", "h00_39FF_FFFF", "h0", "Reserved", ""), MemMap("h00_3A00_0000", "h00_3FFF_FFFF", "h0", "", "RW), @@ -161,7 +162,7 @@ trait PMAMethod extends PMAConst { addPMA(PMPPmemLowBounds(0), a = 1, w = true, r = true) addPMA(0x3A000000L, a = 1) addPMA(0x39002000L, a = 1, w = true, r = true) - addPMA(0x39000000L, a = 1) + addPMA(0x39000000L, a = 1, w = true, r = true) addPMA(0x38022000L, a = 1, w = true, r = true) addPMA(0x38021000L, a = 1, x = true, w = true, r = true) addPMA(0x38020000L, a = 1, w = true, r = true) diff --git a/src/main/scala/xiangshan/cache/dcache/CtrlUnit.scala b/src/main/scala/xiangshan/cache/dcache/CtrlUnit.scala new file mode 100644 index 00000000000..119ff2184d1 --- /dev/null +++ b/src/main/scala/xiangshan/cache/dcache/CtrlUnit.scala @@ -0,0 +1,160 @@ +/*************************************************************************************** +* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences +* Copyright (c) 2020-2021 Peng Cheng Laboratory +* +* XiangShan is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* +* See the Mulan PSL v2 for more details. +***************************************************************************************/ + +package xiangshan.cache + +import org.chipsalliance.cde.config.Parameters +import chisel3._ +import chisel3.util._ +import freechips.rocketchip.subsystem._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.regmapper._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.interrupts._ +import freechips.rocketchip.util._ +import freechips.rocketchip.util.property +import chisel3.experimental.SourceInfo +import xiangshan._ + +case class L1CacheCtrlParams ( + address: AddressSet, + beatBytes: Int = 8, +) { + def maxBanks = 1 + def bankBytes = 128 + + def regWidth = 64 + def regBytes = regWidth / 8 + + def ctrlOffset = 0x0 + def delayOffset = ctrlOffset + regBytes + def maskOffset = delayOffset + regBytes + + def nSignalComps = 2 +} + +class CtrlUnitCtrlBundle(implicit p: Parameters) extends XSBundle with HasDCacheParameters { + val zero0 = UInt((60-DCacheBanks).W) // padding bits + val comp = UInt(2.W) // components: 2'b01 tag, 2'b10 data + val ede = Bool() // error delay enable + val ese = Bool() // error signaling enable +} + +class CtrlUnit(params: L1CacheCtrlParams)(implicit p: Parameters) extends LazyModule + with HasDCacheParameters +{ + val device: SimpleDevice = new SimpleDevice("L1DCacheCtrl", Seq("xiangshan,l1dcache_ctrl")) + + val node: TLRegisterNode = TLRegisterNode( + address = Seq(params.address), + device = device, + beatBytes = params.beatBytes, + concurrency = 1, + ) + + lazy val module = new CtrlUnitImp + + class CtrlUnitImp extends LazyModuleImp(this) { + val io_pseudoError = IO(Vec(params.nSignalComps, DecoupledIO(Vec(DCacheBanks, UInt(DCacheSRAMRowBits.W))))) + + require(params.maxBanks > 0, "At least one bank!") + require(params.maxBanks == 1, "Is it necessary to have more than 1 bank?") + require(params.regWidth == DCacheSRAMRowBits, "regWidth must be equal to DCacheSRAMRowBits!") + val ctrlRegs = RegInit(VecInit(Seq.fill(1)(0.U(params.regWidth.W)))) + val delayRegs = RegInit(VecInit(Seq.fill(1)(0.U(params.regWidth.W)))) + val maskRegs = RegInit(VecInit(Seq.fill(DCacheBanks)(0.U(DCacheSRAMRowBits.W)))) + + io_pseudoError.zipWithIndex.foreach { + case (pErr, i) => + val ctrlReg = ctrlRegs(0) + val ctrlRegBundle = ctrlRegs(0).asTypeOf(new CtrlUnitCtrlBundle) + val delayReg = delayRegs(0) + + require(io_pseudoError.length == ctrlRegBundle.comp.getWidth, "io_pseudoError must equal number of components!") + pErr.valid := ctrlRegBundle.ese && ctrlRegBundle.comp(i) && (!ctrlRegBundle.ede || delayReg === 0.U) + pErr.bits := maskRegs + + when (pErr.fire) { + val newCtrlReg = WireInit(0.U.asTypeOf(ctrlRegBundle)) + newCtrlReg := ctrlRegBundle + newCtrlReg.ese := false.B + + ctrlReg := newCtrlReg.asUInt + } + } + + ctrlRegs.map(_.asTypeOf(new CtrlUnitCtrlBundle)).zip(delayRegs).foreach { + case (ctl, delay) => + when (ctl.ese && ctl.ede && delay =/= 0.U) { + delay := delay - 1.U + } + } + + def ctrlRegDesc(i: Int) = + RegFieldDesc( + name = s"control_$i", + desc = s"Acting control of controller $i", + group = Some(s"controll_${i}"), + groupDesc = Some(s"Acting control of controller ${i}"), + reset = Some(0) + ) + + def delayRegDesc(i: Int) = + RegFieldDesc( + name = s"delay_$i", + desc = s"pseudo error delay $i", + group = Some(s"delay_${i}"), + groupDesc = Some(s"pseudo error delay ${i}"), + reset = Some(0) + ) + + def maskRegDesc(i: Int) = + RegFieldDesc( + name = s"mask_$i", + desc = s"pseudo error toggle mask$i", + group = Some(s"mask_${i}"), + groupDesc = Some(s"pseudo error toggle mask ${i}"), + reset = Some(0) + ) + + def ctrlRegField(x: UInt, i: Int) = { + RegField(params.regWidth, x, ctrlRegDesc(i)) + } + + def delayRegField(x: UInt, i: Int) = { + RegField(params.regWidth, x, delayRegDesc(i)) + } + + def maskRegField(x: UInt, i: Int) = { + RegField(params.regWidth, x, maskRegDesc(i)) + } + + val ctrlRegFields = ctrlRegs.zipWithIndex.map { + case (reg, i) => + params.ctrlOffset -> Seq(ctrlRegField(reg, i)) + } + val delayRegFields = delayRegs.zipWithIndex.map { + case (reg, i) => + params.delayOffset -> Seq(delayRegField(reg, i)) + } + val maskRegFields = maskRegs.zipWithIndex.map { + case (reg, i) => + (params.maskOffset + 8 * i) -> Seq(maskRegField(reg, i)) + } + + node.regmap((ctrlRegFields ++ delayRegFields ++ maskRegFields):_*) + } +} \ No newline at end of file diff --git a/src/main/scala/xiangshan/cache/dcache/DCacheWrapper.scala b/src/main/scala/xiangshan/cache/dcache/DCacheWrapper.scala index 8f827dfd486..e8194dc5d5f 100644 --- a/src/main/scala/xiangshan/cache/dcache/DCacheWrapper.scala +++ b/src/main/scala/xiangshan/cache/dcache/DCacheWrapper.scala @@ -22,7 +22,7 @@ import chisel3.util._ import coupledL2.VaddrField import coupledL2.IsKeywordField import coupledL2.IsKeywordKey -import freechips.rocketchip.diplomacy.{IdRange, LazyModule, LazyModuleImp, TransferSizes} +import freechips.rocketchip.diplomacy._ import freechips.rocketchip.tilelink._ import freechips.rocketchip.util.BundleFieldBase import huancun.{AliasField, PrefetchField} @@ -57,7 +57,8 @@ case class DCacheParameters alwaysReleaseData: Boolean = false, isKeywordBitsOpt: Option[Boolean] = Some(true), enableDataEcc: Boolean = false, - enableTagEcc: Boolean = false + enableTagEcc: Boolean = false, + cacheCtrlAddressOpt: Option[AddressSet] = None, ) extends L1CacheParameters { // if sets * blockBytes > 4KB(page size), // cache alias will happen, @@ -164,6 +165,12 @@ trait HasDCacheParameters extends HasL1CacheParameters with HasL1PrefetchSourceP val DCacheTagOffset = DCacheAboveIndexOffset min DCacheSameVPAddrLength val DCacheLineOffset = DCacheSetOffset + // L1 DCache controller + val cacheCtrlParamsOpt = OptionWrapper( + cacheParams.cacheCtrlAddressOpt.nonEmpty, + L1CacheCtrlParams(cacheParams.cacheCtrlAddressOpt.get) + ) + // uncache val uncacheIdxBits = log2Up(VirtualLoadQueueMaxStoreQueueSize + 1) // hardware prefetch parameters @@ -896,6 +903,7 @@ class DCache()(implicit p: Parameters) extends LazyModule with HasDCacheParamete ) val clientNode = TLClientNode(Seq(clientParameters)) + val cacheCtrlOpt = cacheCtrlParamsOpt.map(params => LazyModule(new CtrlUnit(params))) lazy val module = new DCacheImp(this) } @@ -988,6 +996,29 @@ class DCacheImp(outer: DCache) extends LazyModuleImp(outer) with HasDCacheParame mainPipe.io.sms_agt_evict_req <> io.sms_agt_evict_req io.memSetPattenDetected := missQueue.io.memSetPattenDetected + outer.cacheCtrlOpt.map(mod => mod.module.io_pseudoError.foreach { case x => x.ready := false.B }) + mainPipe.io.pseudo_error.valid := false.B + mainPipe.io.pseudo_error.bits := DontCare + ldu.map(mod => { mod.io.pseudo_error.valid := false.B; mod.io.pseudo_error.bits := DontCare; }) + bankedDataArray.io.pseudo_error.valid := false.B + bankedDataArray.io.pseudo_error.bits := DontCare + + // pseudo tag ecc error + if (outer.cacheCtrlOpt.nonEmpty && EnableTagEcc) { + val ctrlUnit = outer.cacheCtrlOpt.head.module + ldu.map(mod => mod.io.pseudo_error <> ctrlUnit.io_pseudoError(0)) + mainPipe.io.pseudo_error <> ctrlUnit.io_pseudoError(0) + ctrlUnit.io_pseudoError(0).ready := (mainPipe.io.pseudo_error.ready || ldu.map(_.io.pseudo_error.ready).reduce(_|_)) + } + + // pseudo data ecc error + if (outer.cacheCtrlOpt.nonEmpty && EnableDataEcc) { + val ctrlUnit = outer.cacheCtrlOpt.head.module + bankedDataArray.io.pseudo_error <> ctrlUnit.io_pseudoError(1) + ctrlUnit.io_pseudoError(1).ready := bankedDataArray.io.pseudo_error.ready && + (mainPipe.io.pseudo_error.ready || ldu.map(_.io.pseudo_error.ready).reduce(_|_)) + } + val errors = ldu.map(_.io.error) ++ // load error Seq(mainPipe.io.error) // store / misc error val error_valid = errors.map(e => e.valid).reduce(_|_) @@ -1114,7 +1145,7 @@ class DCacheImp(outer: DCache) extends LazyModuleImp(outer) with HasDCacheParame // refillPipe.io.access_flag_write ) access_flag_write_ports.zip(accessArray.io.write).foreach { case (p, w) => w <> p } - + //---------------------------------------- // tag array if(StorePrefetchL1Enabled) { @@ -1214,12 +1245,14 @@ class DCacheImp(outer: DCache) extends LazyModuleImp(outer) with HasDCacheParame bankedDataArray.io.readline <> mainPipe.io.data_readline bankedDataArray.io.readline_intend := mainPipe.io.data_read_intend mainPipe.io.readline_error_delayed := bankedDataArray.io.readline_error_delayed + mainPipe.io.readline_pseudo_error_delayed := bankedDataArray.io.readline_pseudo_error_delayed mainPipe.io.data_resp := bankedDataArray.io.readline_resp (0 until LoadPipelineWidth).map(i => { bankedDataArray.io.read(i) <> ldu(i).io.banked_data_read bankedDataArray.io.is128Req(i) <> ldu(i).io.is128Req bankedDataArray.io.read_error_delayed(i) <> ldu(i).io.read_error_delayed + bankedDataArray.io.read_pseudo_error_delayed(i) <> ldu(i).io.read_pseudo_error_delayed ldu(i).io.banked_data_resp := bankedDataArray.io.read_resp(i) @@ -1416,7 +1449,7 @@ class DCacheImp(outer: DCache) extends LazyModuleImp(outer) with HasDCacheParame wb.io.miss_req_conflict_check(3) := mainPipe.io.wbq_conflict_check mainPipe.io.wbq_block_miss_req := wb.io.block_miss_req(3) - + wb.io.miss_req_conflict_check(4).valid := missReqArb.io.out.valid wb.io.miss_req_conflict_check(4).bits := missReqArb.io.out.bits.addr missQueue.io.wbq_block_miss_req := wb.io.block_miss_req(4) @@ -1480,8 +1513,8 @@ class DCacheImp(outer: DCache) extends LazyModuleImp(outer) with HasDCacheParame val mpStatus = mainPipe.io.status mainPipe.io.refill_req <> missQueue.io.main_pipe_req - mainPipe.io.data_write_ready_dup := VecInit(Seq.fill(nDupDataWriteReady)(true.B)) - mainPipe.io.tag_write_ready_dup := VecInit(Seq.fill(nDupDataWriteReady)(true.B)) + mainPipe.io.data_write_ready_dup := VecInit(Seq.fill(nDupDataWriteReady)(true.B)) + mainPipe.io.tag_write_ready_dup := VecInit(Seq.fill(nDupDataWriteReady)(true.B)) mainPipe.io.wb_ready_dup := wb.io.req_ready_dup //---------------------------------------- @@ -1683,16 +1716,27 @@ class AMOHelper() extends ExtModule { val rdata = IO(Output(UInt(64.W))) } -class DCacheWrapper()(implicit p: Parameters) extends LazyModule with HasXSParameter { +class DCacheWrapper()(implicit p: Parameters) extends LazyModule + with HasXSParameter + with HasDCacheParameters +{ override def shouldBeInlined: Boolean = false val useDcache = coreParams.dcacheParametersOpt.nonEmpty val clientNode = if (useDcache) TLIdentityNode() else null + val uncacheNode = OptionWrapper(cacheCtrlParamsOpt.isDefined, TLIdentityNode()) val dcache = if (useDcache) LazyModule(new DCache()) else null if (useDcache) { clientNode := dcache.clientNode } + require( + (uncacheNode.isDefined && dcache.cacheCtrlOpt.isDefined) || + (!uncacheNode.isDefined && !dcache.cacheCtrlOpt.isDefined), "uncacheNode and ctrlUnitOpt are not match!") + if (uncacheNode.isDefined && dcache.cacheCtrlOpt.isDefined) { + dcache.cacheCtrlOpt.get.node := uncacheNode.get + } + class DCacheWrapperImp(wrapper: LazyModule) extends LazyModuleImp(wrapper) with HasPerfEvents { val io = IO(new DCacheIO) val perfEvents = if (!useDcache) { diff --git a/src/main/scala/xiangshan/cache/dcache/data/BankedDataArray.scala b/src/main/scala/xiangshan/cache/dcache/data/BankedDataArray.scala index 86d7287ce73..b323e860a95 100644 --- a/src/main/scala/xiangshan/cache/dcache/data/BankedDataArray.scala +++ b/src/main/scala/xiangshan/cache/dcache/data/BankedDataArray.scala @@ -77,11 +77,17 @@ class L1BankedDataReadResult(implicit p: Parameters) extends DCacheBundle // you can choose which bank to read to save power val ecc = Bits(eccBits.W) val raw_data = Bits(DCacheSRAMRowBits.W) + val pseudo_raw_data = Bits(DCacheSRAMRowBits.W) val error_delayed = Bool() // 1 cycle later than data resp + val pseudo_error_delayed = Bool() def asECCData() = { Cat(ecc, raw_data) } + + def asPseudoECCData() = { + Cat(ecc, pseudo_raw_data) + } } class DataSRAMBankWriteReq(implicit p: Parameters) extends DCacheBundle { @@ -253,8 +259,10 @@ abstract class AbstractBankedDataArray(implicit p: Parameters) extends DCacheMod // data for readline and loadpipe val readline_resp = Output(Vec(DCacheBanks, new L1BankedDataReadResult())) val readline_error_delayed = Output(Bool()) + val readline_pseudo_error_delayed = Output(Bool()) val read_resp = Output(Vec(LoadPipelineWidth, Vec(VLEN/DCacheSRAMRowBits, new L1BankedDataReadResult()))) val read_error_delayed = Output(Vec(LoadPipelineWidth,Vec(VLEN/DCacheSRAMRowBits, Bool()))) + val read_pseudo_error_delayed = Output(Vec(LoadPipelineWidth,Vec(VLEN/DCacheSRAMRowBits, Bool()))) // val nacks = Output(Vec(LoadPipelineWidth, Bool())) // val errors = Output(Vec(LoadPipelineWidth + 1, ValidIO(new L1CacheErrorInfo))) // read ports + readline port // when bank_conflict, read (1) port should be ignored @@ -264,6 +272,7 @@ abstract class AbstractBankedDataArray(implicit p: Parameters) extends DCacheMod val cacheOp = Flipped(new L1CacheInnerOpIO) val cacheOp_req_dup = Vec(DCacheDupNum, Flipped(Valid(new CacheCtrlReqInfo))) val cacheOp_req_bits_opCode_dup = Input(Vec(DCacheDupNum, UInt(XLEN.W))) + val pseudo_error = Flipped(DecoupledIO(Vec(DCacheBanks, UInt(DCacheSRAMRowBits.W)))) }) def pipeMap[T <: Data](f: Int => T) = VecInit((0 until LoadPipelineWidth).map(f)) @@ -428,8 +437,15 @@ class SramedDataArray(implicit p: Parameters) extends AbstractBankedDataArray { val read_result = Wire(Vec(DCacheSetDiv, Vec(DCacheBanks, Vec(DCacheWays,new L1BankedDataReadResult())))) val read_result_delayed = Wire(Vec(DCacheSetDiv, Vec(DCacheBanks, Vec(DCacheWays,new L1BankedDataReadResult())))) val read_error_delayed_result = Wire(Vec(DCacheSetDiv, Vec(DCacheBanks, Vec(DCacheWays, Bool())))) + val read_pseudo_error_delayed_result = Wire(Vec(DCacheSetDiv, Vec(DCacheBanks, Vec(DCacheWays, Bool())))) dontTouch(read_result) dontTouch(read_error_delayed_result) + dontTouch(read_pseudo_error_delayed_result) + val pseudo_data_toggle_mask = io.pseudo_error.bits.map { + case mask => + Mux(io.pseudo_error.valid, mask, 0.U) + } + io.pseudo_error.ready := false.B for (div_index <- 0 until DCacheSetDiv){ for (bank_index <- 0 until DCacheBanks) { for (way_index <- 0 until DCacheWays) { @@ -475,18 +491,36 @@ class SramedDataArray(implicit p: Parameters) extends AbstractBankedDataArray { } read_result(div_index)(bank_index)(way_index).raw_data := data_bank.io.r.data + if (cacheCtrlParamsOpt.nonEmpty && EnableDataEcc) { + read_result(div_index)(bank_index)(way_index).pseudo_raw_data := data_bank.io.r.data ^ pseudo_data_toggle_mask(bank_index) + } else { + read_result(div_index)(bank_index)(way_index).pseudo_raw_data := DontCare + } read_result_delayed(div_index)(bank_index)(way_index) := RegEnable(read_result(div_index)(bank_index)(way_index), RegNext(read_en)) // use ECC to check error ecc_banks match { case Some(_) => + // real ecc error val ecc_data = read_result(div_index)(bank_index)(way_index).asECCData() val ecc_data_delayed = RegEnable(ecc_data, RegNext(read_en)) read_result(div_index)(bank_index)(way_index).error_delayed := dcacheParameters.dataCode.decode(ecc_data_delayed).error read_error_delayed_result(div_index)(bank_index)(way_index) := read_result(div_index)(bank_index)(way_index).error_delayed + + // pseudo ecc error + val pseduo_ecc_data = read_result(div_index)(bank_index)(way_index).asPseudoECCData() + val pseduo_ecc_data_delayed = RegEnable(pseduo_ecc_data, RegNext(read_en)) + read_result(div_index)(bank_index)(way_index).pseudo_error_delayed := dcacheParameters.dataCode.decode(pseduo_ecc_data_delayed).error + read_pseudo_error_delayed_result(div_index)(bank_index)(way_index) := read_result(div_index)(bank_index)(way_index).pseudo_error_delayed + case None => + // real ecc error read_result(div_index)(bank_index)(way_index).error_delayed := false.B read_error_delayed_result(div_index)(bank_index)(way_index) := false.B + + // pseudo ecc error + read_result(div_index)(bank_index)(way_index).pseudo_error_delayed := false.B + read_pseudo_error_delayed_result(div_index)(bank_index)(way_index) := false.B } } } @@ -519,6 +553,7 @@ class SramedDataArray(implicit p: Parameters) extends AbstractBankedDataArray { // error detection // normal read ports io.read_error_delayed(i)(j) := rr_read_fire && read_error_delayed_result(rr_div_addr)(rr_bank_addr(j))(rr_way_addr) && !RegNext(io.bank_conflict_slow(i)) + io.read_pseudo_error_delayed(i)(j) := rr_read_fire && read_pseudo_error_delayed_result(rr_div_addr)(rr_bank_addr(j))(rr_way_addr) && !RegNext(io.bank_conflict_slow(i)) }) }) @@ -528,6 +563,8 @@ class SramedDataArray(implicit p: Parameters) extends AbstractBankedDataArray { }) io.readline_error_delayed := RegNext(RegNext(io.readline.fire)) && VecInit((0 until DCacheBanks).map(i => io.readline_resp(i).error_delayed)).asUInt.orR + io.readline_pseudo_error_delayed := RegNext(RegNext(io.readline.fire)) && + VecInit((0 until DCacheBanks).map(i => io.readline_resp(i).pseudo_error_delayed)).asUInt.orR // write data_banks & ecc_banks for (div_index <- 0 until DCacheSetDiv) { @@ -781,7 +818,11 @@ class BankedDataArray(implicit p: Parameters) extends AbstractBankedDataArray { // ready io.readline.ready := !(wrl_bank_conflict) io.read.zipWithIndex.map{case(x, i) => x.ready := !(wr_bank_conflict(i) || rrhazard)} - + val pseudo_data_toggle_mask = io.pseudo_error.bits.map { + case mask => + Mux(io.pseudo_error.valid, mask, 0.U) + } + io.pseudo_error.ready := RegNext(io.readline.fire) || io.read.zip(io.bank_conflict_slow).map(x => RegNext(x._1.fire) && !x._2).reduce(_|_) val perf_multi_read = PopCount(io.read.map(_.valid)) >= 2.U (0 until LoadPipelineWidth).foreach(i => { // remove fake rr_bank_conflict situation in s2 @@ -812,8 +853,10 @@ class BankedDataArray(implicit p: Parameters) extends AbstractBankedDataArray { val bank_result_delayed = Wire(Vec(DCacheSetDiv, Vec(DCacheBanks, Vec(DCacheWays, new L1BankedDataReadResult())))) val ecc_result = Wire(Vec(DCacheSetDiv, Vec(DCacheBanks, Vec(DCacheWays, UInt(eccBits.W))))) val read_bank_error_delayed = Wire(Vec(DCacheSetDiv, Vec(DCacheBanks, Vec(DCacheWays, Bool())))) + val read_bank_pseudo_error_delayed = Wire(Vec(DCacheSetDiv, Vec(DCacheBanks, Vec(DCacheWays, Bool())))) dontTouch(bank_result) dontTouch(read_bank_error_delayed) + dontTouch(read_bank_pseudo_error_delayed) for (div_index <- 0 until DCacheSetDiv) { for (bank_index <- 0 until DCacheBanks) { // Set Addr & Read Way Mask @@ -851,6 +894,11 @@ class BankedDataArray(implicit p: Parameters) extends AbstractBankedDataArray { data_bank.io.r.addr := bank_set_addr for (way_index <- 0 until DCacheWays) { bank_result(div_index)(bank_index)(way_index).raw_data := data_bank.io.r.data(way_index) + if (cacheCtrlParamsOpt.nonEmpty && EnableDataEcc) { + bank_result(div_index)(bank_index)(way_index).pseudo_raw_data := data_bank.io.r.data(way_index) ^ pseudo_data_toggle_mask(bank_index) + } else { + bank_result(div_index)(bank_index)(way_index).pseudo_raw_data := DontCare + } bank_result_delayed(div_index)(bank_index)(way_index) := RegEnable(bank_result(div_index)(bank_index)(way_index), RegNext(read_enable)) } @@ -875,15 +923,32 @@ class BankedDataArray(implicit p: Parameters) extends AbstractBankedDataArray { ecc_banks match { case Some(_) => for (way_index <- 0 until DCacheWays) { + // real ecc error val ecc_data = bank_result(div_index)(bank_index)(way_index).asECCData() val ecc_data_delayed = RegEnable(ecc_data, RegNext(read_enable)) bank_result(div_index)(bank_index)(way_index).error_delayed := dcacheParameters.dataCode.decode(ecc_data_delayed).error read_bank_error_delayed(div_index)(bank_index)(way_index) := bank_result(div_index)(bank_index)(way_index).error_delayed + + // pseudo ecc error + val pseudo_ecc_data = bank_result(div_index)(bank_index)(way_index).asPseudoECCData() + val pseudo_ecc_data_delayed = RegEnable(pseudo_ecc_data, RegNext(read_enable)) + if (cacheCtrlParamsOpt.nonEmpty && EnableDataEcc) { + bank_result(div_index)(bank_index)(way_index).pseudo_error_delayed := dcacheParameters.dataCode.decode(pseudo_ecc_data_delayed).error + read_bank_pseudo_error_delayed(div_index)(bank_index)(way_index) := bank_result(div_index)(bank_index)(way_index).pseudo_error_delayed + } else { + bank_result(div_index)(bank_index)(way_index).pseudo_error_delayed := false.B + read_bank_pseudo_error_delayed(div_index)(bank_index)(way_index) := false.B + } } case None => for (way_index <- 0 until DCacheWays) { + // real ecc error bank_result(div_index)(bank_index)(way_index).error_delayed := false.B read_bank_error_delayed(div_index)(bank_index)(way_index) := false.B + + // pseudo ecc error + bank_result(div_index)(bank_index)(way_index).pseudo_error_delayed := false.B + read_bank_pseudo_error_delayed(div_index)(bank_index)(way_index) := false.B } } } @@ -914,6 +979,7 @@ class BankedDataArray(implicit p: Parameters) extends AbstractBankedDataArray { io.read_resp(i)(j) := bank_result(r_div_addr)(r_bank_addr(j))(r_way_addr) // error detection io.read_error_delayed(i)(j) := rr_read_fire && read_bank_error_delayed(rr_div_addr)(rr_bank_addr(j))(rr_way_addr) && !RegNext(io.bank_conflict_slow(i)) + io.read_pseudo_error_delayed(i)(j) := rr_read_fire && read_bank_pseudo_error_delayed(rr_div_addr)(rr_bank_addr(j))(rr_way_addr) && !RegNext(io.bank_conflict_slow(i)) }) }) @@ -923,7 +989,8 @@ class BankedDataArray(implicit p: Parameters) extends AbstractBankedDataArray { }) io.readline_error_delayed := RegNext(RegNext(io.readline.fire)) && VecInit((0 until DCacheBanks).map(i => io.readline_resp(i).error_delayed)).asUInt.orR - + io.readline_pseudo_error_delayed := RegNext(RegNext(io.readline.fire)) && + VecInit((0 until DCacheBanks).map(i => io.readline_resp(i).pseudo_error_delayed)).asUInt.orR // write data_banks & ecc_banks for (div_index <- 0 until DCacheSetDiv) { for (bank_index <- 0 until DCacheBanks) { diff --git a/src/main/scala/xiangshan/cache/dcache/loadpipe/LoadPipe.scala b/src/main/scala/xiangshan/cache/dcache/loadpipe/LoadPipe.scala index 03224fd9fbe..83cdc07a110 100644 --- a/src/main/scala/xiangshan/cache/dcache/loadpipe/LoadPipe.scala +++ b/src/main/scala/xiangshan/cache/dcache/loadpipe/LoadPipe.scala @@ -53,6 +53,7 @@ class LoadPipe(id: Int)(implicit p: Parameters) extends DCacheModule with HasPer val is128Req = Output(Bool()) val banked_data_resp = Input(Vec(VLEN/DCacheSRAMRowBits, new L1BankedDataReadResult())) val read_error_delayed = Input(Vec(VLEN/DCacheSRAMRowBits, Bool())) + val read_pseudo_error_delayed = Input(Vec(VLEN/DCacheSRAMRowBits, Bool())) // access bit update val access_flag_write = DecoupledIO(new FlagMetaWriteReq) @@ -79,6 +80,7 @@ class LoadPipe(id: Int)(implicit p: Parameters) extends DCacheModule with HasPer // ecc error val error = Output(ValidIO(new L1CacheErrorInfo)) + val pseudo_error = Flipped(DecoupledIO(Vec(DCacheBanks, UInt(DCacheSRAMRowBits.W)))) val prefetch_info = new Bundle { val naive = new Bundle { @@ -190,14 +192,30 @@ class LoadPipe(id: Int)(implicit p: Parameters) extends DCacheModule with HasPer dump_pipeline_reqs("LoadPipe s1", s1_valid, s1_req) - // tag check - val meta_resp = io.meta_resp - val tag_resp = io.tag_resp.map(r => r(tagBits - 1, 0)) def wayMap[T <: Data](f: Int => T) = VecInit((0 until nWays).map(f)) + val s1_meta_resp = io.meta_resp + // tag check + // real enc ecc tag + val s1_tag_resp = io.tag_resp.map(r => r(tagBits - 1, 0)) + // pseudo enc ecc tag + val pseudo_tag_toggle_mask = Mux( + io.pseudo_error.valid, + io.pseudo_error.bits(0)(tagBits - 1, 0), + 0.U(tagBits.W) + ) + val s1_pseudo_tag_resp = Wire(io.tag_resp.cloneType) + s1_pseudo_tag_resp.zip(io.tag_resp).map { + case (pseudo_enc, real_enc) => + val ecc = real_enc(encTagBits - 1, tagBits) + pseudo_enc := Cat(ecc, real_enc(tagBits - 1, 0) ^ pseudo_tag_toggle_mask) + } + // resp in s1 - val s1_tag_match_way_dup_dc = wayMap((w: Int) => tag_resp(w) === get_tag(s1_paddr_dup_dcache) && meta_resp(w).coh.isValid()).asUInt - val s1_tag_match_way_dup_lsu = wayMap((w: Int) => tag_resp(w) === get_tag(s1_paddr_dup_lsu) && meta_resp(w).coh.isValid()).asUInt + val s1_tag_errors = wayMap((w: Int) => s1_meta_resp(w).coh.isValid() && dcacheParameters.tagCode.decode(io.tag_resp(w)).error).asUInt + val s1_pseudo_tag_errors = wayMap((w: Int) => s1_meta_resp(w).coh.isValid() && dcacheParameters.tagCode.decode(s1_pseudo_tag_resp(w)).error).asUInt + val s1_tag_match_way_dup_dc = wayMap((w: Int) => s1_tag_resp(w) === get_tag(s1_paddr_dup_dcache) && s1_meta_resp(w).coh.isValid()).asUInt + val s1_tag_match_way_dup_lsu = wayMap((w: Int) => s1_tag_resp(w) === get_tag(s1_paddr_dup_lsu) && s1_meta_resp(w).coh.isValid()).asUInt val s1_wpu_pred_valid = RegEnable(io.dwpu.resp(0).valid, s0_fire) val s1_wpu_pred_way_en = RegEnable(io.dwpu.resp(0).bits.s0_pred_way_en, s0_fire) @@ -224,7 +242,7 @@ class LoadPipe(id: Int)(implicit p: Parameters) extends DCacheModule with HasPer io.dwpu.cfpred(0).s0_vaddr := s0_vaddr io.dwpu.cfpred(0).s1_vaddr := s1_vaddr // whether direct_map_way miss with valid tag value - io.dwpu.cfpred(0).s1_dm_hit := wayMap((w: Int) => w.U === s1_direct_map_way_num && tag_resp(w) === get_tag(s1_paddr_dup_lsu) && meta_resp(w).coh.isValid()).asUInt.orR + io.dwpu.cfpred(0).s1_dm_hit := wayMap((w: Int) => w.U === s1_direct_map_way_num && s1_tag_resp(w) === get_tag(s1_paddr_dup_lsu) && s1_meta_resp(w).coh.isValid()).asUInt.orR }else{ io.dwpu.cfpred(0) := DontCare } @@ -252,7 +270,7 @@ class LoadPipe(id: Int)(implicit p: Parameters) extends DCacheModule with HasPer // when there are no tag match, we give it a Fake Meta // this simplifies our logic in s2 stage - val s1_hit_meta = ParallelMux(s1_tag_match_way_dup_dc.asBools, (0 until nWays).map(w => meta_resp(w))) + val s1_hit_meta = ParallelMux(s1_tag_match_way_dup_dc.asBools, (0 until nWays).map(w => s1_meta_resp(w))) val s1_hit_coh = s1_hit_meta.coh val s1_hit_error = ParallelMux(s1_tag_match_way_dup_dc.asBools, (0 until nWays).map(w => io.extra_meta_resp(w).error)) val s1_hit_prefetch = ParallelMux(s1_tag_match_way_dup_dc.asBools, (0 until nWays).map(w => io.extra_meta_resp(w).prefetch)) @@ -262,7 +280,7 @@ class LoadPipe(id: Int)(implicit p: Parameters) extends DCacheModule with HasPer io.replace_way.set.valid := false.B io.replace_way.set.bits := get_idx(s1_vaddr) io.replace_way.dmWay := get_direct_map_way(s1_vaddr) - val s1_invalid_vec = wayMap(w => !meta_resp(w).coh.isValid()) + val s1_invalid_vec = wayMap(w => !s1_meta_resp(w).coh.isValid()) val s1_have_invalid_way = s1_invalid_vec.asUInt.orR val s1_invalid_way_en = ParallelPriorityMux(s1_invalid_vec.zipWithIndex.map(x => x._1 -> UIntToOH(x._2.U(nWays.W)))) @@ -289,7 +307,6 @@ class LoadPipe(id: Int)(implicit p: Parameters) extends DCacheModule with HasPer io.is128Req := s1_load128Req // check ecc error - val s1_encTag = ParallelMux(s1_tag_match_way_dup_dc.asBools, (0 until nWays).map(w => io.tag_resp(w))) val s1_flag_error = Mux(s1_need_replacement, false.B, s1_hit_error) // error reported by exist dcache error bit // -------------------------------------------------------------------------------- @@ -307,6 +324,8 @@ class LoadPipe(id: Int)(implicit p: Parameters) extends DCacheModule with HasPer val s2_bank_oh = RegEnable(s1_bank_oh, s1_fire) val s2_bank_oh_dup_0 = RegEnable(s1_bank_oh, s1_fire) val s2_wpu_pred_fail = RegEnable(s1_wpu_pred_fail, s1_fire) + val s2_tag_errors = RegEnable(s1_tag_errors, s1_fire) + val s2_pseudo_tag_errors = RegEnable(s1_pseudo_tag_errors, s1_fire) val s2_real_way_en = RegEnable(s1_tag_match_way_dup_dc, s1_fire) val s2_pred_way_en = RegEnable(s1_pred_tag_match_way_dup_dc, s1_fire) val s2_dm_way_num = RegEnable(s1_direct_map_way_num, s1_fire) @@ -342,16 +361,11 @@ class LoadPipe(id: Int)(implicit p: Parameters) extends DCacheModule with HasPer // lsu side tag match val s2_hit_dup_lsu = RegNext(s1_tag_match_dup_lsu) - - io.lsu.s2_hit := s2_hit_dup_lsu && !s2_wpu_pred_fail - val s2_hit_meta = RegEnable(s1_hit_meta, s1_fire) val s2_hit_coh = RegEnable(s1_hit_coh, s1_fire) val s2_has_permission = s2_hit_coh.onAccess(s2_req.cmd)._1 // for write prefetch val s2_new_hit_coh = s2_hit_coh.onAccess(s2_req.cmd)._3 // for write prefetch - val s2_encTag = RegEnable(s1_encTag, s1_fire) - // when req got nacked, upper levels should replay this request // nacked or not val s2_nack_hit = RegEnable(s1_nack, s1_fire) @@ -371,6 +385,7 @@ class LoadPipe(id: Int)(implicit p: Parameters) extends DCacheModule with HasPer val s2_instrtype = s2_req.instrtype val s2_tag_error = WireInit(false.B) + val s2_pseudo_tag_error = WireInit(false.B) val s2_flag_error = RegEnable(s1_flag_error, s1_fire) val s2_hit_prefetch = RegEnable(s1_hit_prefetch, s1_fire) @@ -381,18 +396,18 @@ class LoadPipe(id: Int)(implicit p: Parameters) extends DCacheModule with HasPer val s2_data128bit = Cat(io.banked_data_resp(1).raw_data, io.banked_data_resp(0).raw_data) val s2_resp_data = s2_data128bit + if(EnableTagEcc) { + s2_tag_error := s2_tag_errors.orR + s2_pseudo_tag_error := s2_pseudo_tag_errors.orR + } + io.pseudo_error.ready := s2_fire && (s2_tag_error || s2_pseudo_tag_error || s2_hit && !io.bank_conflict_slow) + // only dump these signals when they are actually valid dump_pipeline_valids("LoadPipe s2", "s2_hit", s2_valid && s2_hit) dump_pipeline_valids("LoadPipe s2", "s2_nack", s2_valid && s2_nack) dump_pipeline_valids("LoadPipe s2", "s2_nack_hit", s2_valid && s2_nack_hit) dump_pipeline_valids("LoadPipe s2", "s2_nack_no_mshr", s2_valid && s2_nack_no_mshr) - if(EnableTagEcc) { - s2_tag_error := dcacheParameters.tagCode.decode(s2_encTag).error // error reported by tag ecc check - }else { - s2_tag_error := false.B - } - // send load miss to miss queue io.miss_req.valid := s2_miss_req_valid io.miss_req.bits := DontCare @@ -485,12 +500,12 @@ class LoadPipe(id: Int)(implicit p: Parameters) extends DCacheModule with HasPer when (resp.valid) { resp.bits.dump() } - io.lsu.debug_s1_hit_way := s1_tag_match_way_dup_dc io.lsu.s1_disable_fast_wakeup := io.disable_ld_fast_wakeup io.lsu.s2_bank_conflict := io.bank_conflict_slow io.lsu.s2_wpu_pred_fail := s2_wpu_pred_fail_and_real_hit io.lsu.s2_mq_nack := (resp.bits.miss && (!s2_miss_req_fire || s2_nack_no_mshr || io.mq_enq_cancel || io.wbq_block_miss_req)) + io.lsu.s2_hit := s2_hit_dup_lsu && !s2_wpu_pred_fail && !s2_tag_error assert(RegNext(s1_ready && s2_ready), "load pipeline should never be blocked") // -------------------------------------------------------------------------------- @@ -503,16 +518,18 @@ class LoadPipe(id: Int)(implicit p: Parameters) extends DCacheModule with HasPer val s3_vaddr = RegEnable(s2_vaddr, s2_fire) val s3_paddr = RegEnable(s2_paddr, s2_fire) val s3_hit = RegEnable(s2_hit, s2_fire) + val s3_tag_error = RegEnable(s2_tag_error, s2_fire) + val s3_pseudo_tag_error = RegEnable(s2_pseudo_tag_error, s2_fire) val s3_tag_match_way = RegEnable(s2_tag_match_way, s2_fire) val s3_req_instrtype = RegEnable(s2_req.instrtype, s2_fire) val s3_is_prefetch = s3_req_instrtype === DCACHE_PREFETCH_SOURCE.U val s3_banked_data_resp_word = RegEnable(s2_resp_data, s2_fire) val s3_data_error = Mux(s3_load128Req, io.read_error_delayed.asUInt.orR, io.read_error_delayed(0)) && s3_hit - val s3_tag_error = RegEnable(s2_tag_error, s2_fire) + val s3_pseudo_data_error = Mux(s3_load128Req, io.read_pseudo_error_delayed.asUInt.orR, io.read_pseudo_error_delayed(0)) && s3_hit val s3_flag_error = RegEnable(s2_flag_error, s2_fire) val s3_hit_prefetch = RegEnable(s2_hit_prefetch, s2_fire) - val s3_error = s3_tag_error || s3_flag_error || s3_data_error + val s3_error = s3_tag_error || s3_pseudo_tag_error || s3_flag_error || s3_data_error || s3_pseudo_data_error // error_delayed signal will be used to update uop.exception 1 cycle after load writeback resp.bits.error_delayed := s3_error && (s3_hit || s3_tag_error) && s3_valid @@ -521,10 +538,10 @@ class LoadPipe(id: Int)(implicit p: Parameters) extends DCacheModule with HasPer // report tag / data / l2 error (with paddr) to bus error unit io.error := 0.U.asTypeOf(ValidIO(new L1CacheErrorInfo)) - io.error.bits.report_to_beu := (s3_tag_error || s3_data_error) && s3_valid + io.error.bits.report_to_beu := (s3_tag_error || s3_pseudo_tag_error || s3_data_error || s3_pseudo_data_error) && s3_valid io.error.bits.paddr := s3_paddr - io.error.bits.source.tag := s3_tag_error - io.error.bits.source.data := s3_data_error + io.error.bits.source.tag := s3_tag_error || s3_pseudo_tag_error + io.error.bits.source.data := s3_data_error || s3_pseudo_data_error io.error.bits.source.l2 := s3_flag_error io.error.bits.opType.load := true.B // report tag error / l2 corrupted to CACHE_ERROR csr diff --git a/src/main/scala/xiangshan/cache/dcache/mainpipe/MainPipe.scala b/src/main/scala/xiangshan/cache/dcache/mainpipe/MainPipe.scala index f9b96f138ca..1913ac62789 100644 --- a/src/main/scala/xiangshan/cache/dcache/mainpipe/MainPipe.scala +++ b/src/main/scala/xiangshan/cache/dcache/mainpipe/MainPipe.scala @@ -143,6 +143,7 @@ class MainPipe(implicit p: Parameters) extends DCacheModule with HasPerfEvents w val data_readline = DecoupledIO(new L1BankedDataReadLineReq) val data_resp = Input(Vec(DCacheBanks, new L1BankedDataReadResult())) val readline_error_delayed = Input(Bool()) + val readline_pseudo_error_delayed = Input(Bool()) val data_write = DecoupledIO(new L1BankedDataWriteReq) val data_write_dup = Vec(DCacheBanks, Valid(new L1BankedDataWriteReqCtrl)) val data_write_ready_dup = Vec(nDupDataWriteReady, Input(Bool())) @@ -191,6 +192,7 @@ class MainPipe(implicit p: Parameters) extends DCacheModule with HasPerfEvents w // ecc error val error = Output(ValidIO(new L1CacheErrorInfo)) + val pseudo_error = Flipped(DecoupledIO(Vec(DCacheBanks, UInt(DCacheSRAMRowBits.W)))) // force write val force_write = Input(Bool()) @@ -321,10 +323,27 @@ class MainPipe(implicit p: Parameters) extends DCacheModule with HasPerfEvents w meta_resp := Mux(GatedValidRegNext(s0_fire), VecInit(io.meta_resp.map(_.asUInt)), RegEnable(meta_resp, s1_valid)) tag_resp := Mux(GatedValidRegNext(s0_fire), VecInit(io.tag_resp.map(r => r(tagBits - 1, 0))), RegEnable(tag_resp, s1_valid)) ecc_resp := Mux(GatedValidRegNext(s0_fire), VecInit(io.tag_resp.map(r => r(encTagBits - 1, tagBits))), RegEnable(ecc_resp, s1_valid)) + + // real ecc enc tag val enc_tag_resp = Wire(io.tag_resp.cloneType) enc_tag_resp := Mux(GatedValidRegNext(s0_fire), io.tag_resp, RegEnable(enc_tag_resp, s1_valid)) + // pseudo ecc enc tag + val pseudo_tag_toggle_mask = Mux( + io.pseudo_error.valid, + io.pseudo_error.bits(0)(tagBits - 1, 0), + 0.U(tagBits.W) + ) + val pseudo_enc_tag_resp = Wire(io.tag_resp.cloneType) + pseudo_enc_tag_resp.zip(enc_tag_resp).map { + case (pseudo_enc, real_enc) => + val ecc = real_enc(encTagBits - 1, tagBits) + pseudo_enc := Cat(ecc, real_enc(tagBits - 1, 0) ^ pseudo_tag_toggle_mask) + } + def wayMap[T <: Data](f: Int => T) = VecInit((0 until nWays).map(f)) + val s1_tag_errors = wayMap((w: Int) => Meta(meta_resp(w)).coh.isValid() && dcacheParameters.tagCode.decode(enc_tag_resp(w)).error).asUInt + val s1_pseudo_tag_errors = wayMap((w: Int) => Meta(meta_resp(w)).coh.isValid() && dcacheParameters.tagCode.decode(pseudo_enc_tag_resp(w)).error).asUInt val s1_tag_eq_way = wayMap((w: Int) => tag_resp(w) === get_tag(s1_req.addr)).asUInt val s1_tag_match_way = wayMap((w: Int) => s1_tag_eq_way(w) && Meta(meta_resp(w)).coh.isValid()).asUInt val s1_tag_match = ParallelORR(s1_tag_match_way) @@ -375,6 +394,8 @@ class MainPipe(implicit p: Parameters) extends DCacheModule with HasPerfEvents w // s2: select data, return resp if this is a store miss val s2_valid = RegInit(false.B) val s2_req = RegEnable(s1_req, s1_fire) + val s2_tag_errors = RegEnable(s1_tag_errors, s1_fire) + val s2_pseudo_tag_errors = RegEnable(s1_pseudo_tag_errors, s1_fire) val s2_tag_match = RegEnable(s1_tag_match, s1_fire) val s2_tag_match_way = RegEnable(s1_tag_match_way, s1_fire) val s2_hit_coh = RegEnable(s1_hit_coh, s1_fire) @@ -408,8 +429,9 @@ class MainPipe(implicit p: Parameters) extends DCacheModule with HasPerfEvents w val s2_banked_store_wmask = RegEnable(s1_banked_store_wmask, s1_fire) val s2_flag_error = RegEnable(s1_flag_error, s1_fire) val s2_tag_error = WireInit(false.B) + val s2_pseudo_tag_error = WireInit(false.B) val s2_l2_error = Mux(io.refill_info.valid, io.refill_info.bits.error, s2_req.error) - val s2_error = s2_flag_error || s2_tag_error || s2_l2_error // data_error not included + val s2_error = s2_flag_error || s2_tag_error || s2_pseudo_tag_error || s2_l2_error // data_error not included val s2_may_report_data_error = s2_need_data && s2_coh.state =/= ClientStates.Nothing @@ -417,11 +439,6 @@ class MainPipe(implicit p: Parameters) extends DCacheModule with HasPerfEvents w val s2_amo_hit = s2_hit && !s2_req.probe && !s2_req.miss && s2_req.isAMO val s2_store_hit = s2_hit && !s2_req.probe && !s2_req.miss && s2_req.isStore - if(EnableTagEcc) { - s2_tag_error := dcacheParameters.tagCode.decode(s2_encTag).error && s2_need_tag - }else { - s2_tag_error := false.B - } s2_s0_set_conlict := s2_valid_dup(0) && s0_idx === s2_idx s2_s0_set_conlict_store := s2_valid_dup(1) && store_idx === s2_idx @@ -471,6 +488,12 @@ class MainPipe(implicit p: Parameters) extends DCacheModule with HasPerfEvents w val s2_data_word = s2_store_data_merged(s2_req.word_idx) + if(EnableTagEcc) { + s2_tag_error := s2_tag_errors.orR && s2_need_tag + s2_pseudo_tag_error := s2_pseudo_tag_errors.orR && s2_need_tag + } + io.pseudo_error.ready := s2_fire_to_s3 && (s2_tag_error || s2_pseudo_tag_error || s2_hit && s2_may_report_data_error) + XSError(s2_valid && s2_can_go_to_s3 && s2_req.miss && !io.refill_info.valid, "MainPipe req can go to s3 but no refill data") // s3: write data, meta and tag @@ -498,9 +521,14 @@ class MainPipe(implicit p: Parameters) extends DCacheModule with HasPerfEvents w io.readline_error_delayed && RegNext(s2_may_report_data_error), RegNext(s3_data_error) // do not update s3_data_error if !s1_fire ) + val s3_pseudo_data_error = Wire(Bool()) + s3_pseudo_data_error := Mux(GatedValidRegNextN(s1_fire, 2), + io.readline_pseudo_error_delayed && RegNext(s2_may_report_data_error), + RegNext(s3_pseudo_data_error) + ) // error signal for amo inst // s3_error = s3_flag_error || s3_tag_error || s3_l2_error || s3_data_error - val s3_error = RegEnable(s2_error, 0.U.asTypeOf(s2_error), s2_fire_to_s3) || s3_data_error + val s3_error = RegEnable(s2_error, 0.U.asTypeOf(s2_error), s2_fire_to_s3) || s3_data_error || s3_pseudo_data_error val (_, _, probe_new_coh) = s3_coh.onProbe(s3_req.probe_param) val s3_need_replacement = RegEnable(s2_need_replacement, s2_fire_to_s3) @@ -1652,10 +1680,10 @@ class MainPipe(implicit p: Parameters) extends DCacheModule with HasPerfEvents w io.error.valid := s3_error && GatedValidRegNext(s2_fire) // only tag_error and data_error will be reported to beu // l2_error should not be reported (l2 will report that) - io.error.bits.report_to_beu := (RegEnable(s2_tag_error, s2_fire) || s3_data_error) && RegNext(s2_fire) + io.error.bits.report_to_beu := (RegEnable(s2_tag_error || s2_pseudo_tag_error, s2_fire) || s3_data_error || s3_pseudo_data_error) && RegNext(s2_fire) io.error.bits.paddr := RegEnable(s2_req.addr, s2_fire) - io.error.bits.source.tag := RegEnable(s2_tag_error, s2_fire) - io.error.bits.source.data := s3_data_error + io.error.bits.source.tag := RegEnable(s2_tag_error || s2_pseudo_tag_error, s2_fire) + io.error.bits.source.data := s3_data_error || s3_pseudo_data_error io.error.bits.source.l2 := RegEnable(s2_flag_error || s2_l2_error, s2_fire) io.error.bits.opType.store := RegEnable(s2_req.isStore && !s2_req.probe, s2_fire) io.error.bits.opType.probe := RegEnable(s2_req.probe, s2_fire)