From b2b4c1abcd6526ed8aa44579ae71cda9bc16bb6e Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Tue, 23 May 2017 12:51:48 -0700 Subject: [PATCH] Separate tag ECC and data ECC options (#761) --- src/main/scala/rocket/DCache.scala | 4 +++- src/main/scala/rocket/HellaCache.scala | 7 ++++--- src/main/scala/rocket/ICache.scala | 28 +++++++++++++++----------- src/main/scala/rocket/NBDcache.scala | 8 ++++++-- src/main/scala/tile/L1Cache.scala | 2 -- 5 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/main/scala/rocket/DCache.scala b/src/main/scala/rocket/DCache.scala index 8e08b8d6..8d8e0cb4 100644 --- a/src/main/scala/rocket/DCache.scala +++ b/src/main/scala/rocket/DCache.scala @@ -44,7 +44,9 @@ class DCache(val scratch: () => Option[AddressSet] = () => None)(implicit p: Par } class DCacheModule(outer: DCache) extends HellaCacheModule(outer) { - require(rowBits == encRowBits) // no ECC + // no ECC support + require(cacheParams.tagECC.isInstanceOf[IdentityCode]) + require(cacheParams.dataECC.isInstanceOf[IdentityCode]) // tags val replacer = cacheParams.replacement diff --git a/src/main/scala/rocket/HellaCache.scala b/src/main/scala/rocket/HellaCache.scala index 6b3ce443..e27ec11a 100644 --- a/src/main/scala/rocket/HellaCache.scala +++ b/src/main/scala/rocket/HellaCache.scala @@ -10,7 +10,7 @@ import diplomacy._ import tile._ import uncore.constants._ import uncore.tilelink2._ -import uncore.util.Code +import uncore.util.{Code, IdentityCode} import util.{ParameterizedBundle, RandomReplacement} import scala.collection.mutable.ListBuffer import scala.math.max @@ -20,7 +20,8 @@ case class DCacheParams( nWays: Int = 4, rowBits: Int = 64, nTLBEntries: Int = 32, - ecc: Option[Code] = None, + tagECC: Code = new IdentityCode, + dataECC: Code = new IdentityCode, nMSHRs: Int = 1, nSDQ: Int = 17, nRPQ: Int = 16, @@ -55,7 +56,7 @@ trait HasL1HellaCacheParameters extends HasL1CacheParameters with HasCoreParamet def offsetlsb = wordOffBits def rowWords = rowBits/wordBits def doNarrowRead = coreDataBits * nWays % rowBits == 0 - def encDataBits = code.width(coreDataBits) + def encDataBits = cacheParams.dataECC.width(coreDataBits) def encRowBits = encDataBits*rowWords def lrscCycles = 32 // ISA requires 16-insn LRSC sequences to succeed def lrscBackoff = 3 // disallow LRSC reacquisition briefly diff --git a/src/main/scala/rocket/ICache.scala b/src/main/scala/rocket/ICache.scala index bba36801..7bca2c78 100644 --- a/src/main/scala/rocket/ICache.scala +++ b/src/main/scala/rocket/ICache.scala @@ -8,7 +8,7 @@ import config._ import diplomacy._ import tile._ import uncore.tilelink2._ -import uncore.util.Code +import uncore.util._ import util._ import Chisel.ImplicitConversions._ @@ -18,7 +18,8 @@ case class ICacheParams( rowBits: Int = 128, nTLBEntries: Int = 32, cacheIdBits: Int = 0, - ecc: Option[Code] = None, + tagECC: Code = new IdentityCode, + dataECC: Code = new IdentityCode, itimAddr: Option[BigInt] = None, blockBytes: Int = 64) extends L1CacheParams { def replacement = new RandomReplacement(nWays) @@ -84,6 +85,9 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer) val edge_in = outer.slaveNode.map(_.edgesIn.head) val tl_in = io.tl_in.map(_.head) + val tECC = cacheParams.tagECC + val dECC = cacheParams.dataECC + require(isPow2(nSets) && isPow2(nWays)) require(isPow2(coreInstBytes)) require(!usingVM || pgIdxBits >= untagBits) @@ -141,11 +145,10 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer) v } - val entagbits = code.width(tagBits) - val tag_array = SeqMem(nSets, Vec(nWays, Bits(width = entagbits))) + val tag_array = SeqMem(nSets, Vec(nWays, Bits(width = tECC.width(tagBits)))) val tag_rdata = tag_array.read(s0_vaddr(untagBits-1,blockOffBits), !refill_done && s0_valid) when (refill_done) { - val tag = code.encode(refill_tag) + val tag = tECC.encode(refill_tag) tag_array.write(refill_idx, Vec.fill(nWays)(tag), Vec.tabulate(nWays)(repl_way === _)) } @@ -162,7 +165,7 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer) val s1_tag_disparity = Wire(Vec(nWays, Bool())) val wordBits = coreInstBits * fetchWidth - val s1_dout = Wire(Vec(nWays, UInt(width = code.width(wordBits)))) + val s1_dout = Wire(Vec(nWays, UInt(width = dECC.width(wordBits)))) val s0_slaveAddr = tl_in.map(_.a.bits.address).getOrElse(0.U) val s1s3_slaveAddr = Reg(UInt(width = log2Ceil(outer.size))) @@ -176,13 +179,13 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer) lineInScratchpad(scratchpadLine(s1s3_slaveAddr)) && scratchpadWay(s1s3_slaveAddr) === i, addrInScratchpad(io.s1_paddr) && scratchpadWay(io.s1_paddr) === i) val s1_vb = vb_array(Cat(UInt(i), s1_idx)) && !s1_slaveValid - s1_tag_disparity(i) := s1_vb && code.decode(tag_rdata(i)).error - s1_tag_hit(i) := scratchpadHit || (s1_vb && code.decode(tag_rdata(i)).uncorrected === s1_tag) + s1_tag_disparity(i) := s1_vb && tECC.decode(tag_rdata(i)).error + s1_tag_hit(i) := scratchpadHit || (s1_vb && tECC.decode(tag_rdata(i)).uncorrected === s1_tag) } assert(!(s1_valid || s1_slaveValid) || PopCount(s1_tag_hit zip s1_tag_disparity map { case (h, d) => h && !d }) <= 1) require(tl_out.d.bits.data.getWidth % wordBits == 0) - val data_arrays = Seq.fill(tl_out.d.bits.data.getWidth / wordBits) { SeqMem(nSets * refillCycles, Vec(nWays, UInt(width = code.width(wordBits)))) } + val data_arrays = Seq.fill(tl_out.d.bits.data.getWidth / wordBits) { SeqMem(nSets * refillCycles, Vec(nWays, UInt(width = dECC.width(wordBits)))) } for ((data_array, i) <- data_arrays zipWithIndex) { def wordMatch(addr: UInt) = addr.extract(log2Ceil(tl_out.d.bits.data.getWidth/8)-1, log2Ceil(wordBits/8)) === i def row(addr: UInt) = addr(untagBits-1, blockOffBits-log2Ceil(refillCycles)) @@ -195,7 +198,7 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer) when (wen) { val data = Mux(s3_slaveValid, s1s3_slaveData, tl_out.d.bits.data(wordBits*(i+1)-1, wordBits*i)) val way = Mux(s3_slaveValid, scratchpadWay(s1s3_slaveAddr), repl_way) - data_array.write(mem_idx, Vec.fill(nWays)(code.encode(data)), (0 until nWays).map(way === _)) + data_array.write(mem_idx, Vec.fill(nWays)(dECC.encode(data)), (0 until nWays).map(way === _)) } val dout = data_array.read(mem_idx, !wen && s0_ren) when (wordMatch(Mux(s1_slaveValid, s1s3_slaveAddr, io.s1_paddr))) { @@ -206,7 +209,8 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer) // output signals outer.latency match { case 1 => - require(code.isInstanceOf[uncore.util.IdentityCode]) + require(tECC.isInstanceOf[uncore.util.IdentityCode]) + require(dECC.isInstanceOf[uncore.util.IdentityCode]) require(outer.icacheParams.itimAddr.isEmpty) io.resp.bits := Mux1H(s1_tag_hit, s1_dout) io.resp.valid := s1_hit @@ -219,7 +223,7 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer) 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_data_decoded = code.decode(s2_way_mux) + 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 } diff --git a/src/main/scala/rocket/NBDcache.scala b/src/main/scala/rocket/NBDcache.scala index b03361b2..30a4e672 100644 --- a/src/main/scala/rocket/NBDcache.scala +++ b/src/main/scala/rocket/NBDcache.scala @@ -669,6 +669,10 @@ class NonBlockingDCacheModule(outer: NonBlockingDCache) extends HellaCacheModule require(isPow2(nWays)) // TODO: relax this require(dataScratchpadSize == 0) + // ECC is only supported on the data array + require(cacheParams.tagECC.isInstanceOf[IdentityCode]) + val dECC = cacheParams.dataECC + val wb = Module(new WritebackUnit) val prober = Module(new ProbeUnit) val mshrs = Module(new MSHRFile) @@ -759,7 +763,7 @@ class NonBlockingDCacheModule(outer: NonBlockingDCache) extends HellaCacheModule data.io.write.valid := writeArb.io.out.valid writeArb.io.out.ready := data.io.write.ready data.io.write.bits := writeArb.io.out.bits - val wdata_encoded = (0 until rowWords).map(i => code.encode(writeArb.io.out.bits.data(coreDataBits*(i+1)-1,coreDataBits*i))) + val wdata_encoded = (0 until rowWords).map(i => dECC.encode(writeArb.io.out.bits.data(coreDataBits*(i+1)-1,coreDataBits*i))) data.io.write.bits.data := wdata_encoded.asUInt // tag read for new requests @@ -822,7 +826,7 @@ class NonBlockingDCacheModule(outer: NonBlockingDCache) extends HellaCacheModule s2_data(w) := regs.asUInt } val s2_data_muxed = Mux1H(s2_tag_match_way, s2_data) - val s2_data_decoded = (0 until rowWords).map(i => code.decode(s2_data_muxed(encDataBits*(i+1)-1,encDataBits*i))) + val s2_data_decoded = (0 until rowWords).map(i => dECC.decode(s2_data_muxed(encDataBits*(i+1)-1,encDataBits*i))) val s2_data_corrected = s2_data_decoded.map(_.corrected).asUInt val s2_data_uncorrected = s2_data_decoded.map(_.uncorrected).asUInt val s2_word_idx = if(doNarrowRead) UInt(0) else s2_req.addr(log2Up(rowWords*coreDataBytes)-1,log2Up(wordBytes)) diff --git a/src/main/scala/tile/L1Cache.scala b/src/main/scala/tile/L1Cache.scala index 21b31425..8839a705 100644 --- a/src/main/scala/tile/L1Cache.scala +++ b/src/main/scala/tile/L1Cache.scala @@ -15,7 +15,6 @@ trait L1CacheParams { def nWays: Int def rowBits: Int def nTLBEntries: Int - def ecc: Option[Code] def blockBytes: Int } @@ -36,7 +35,6 @@ trait HasL1CacheParameters { def rowBits = cacheParams.rowBits def rowBytes = rowBits/8 def rowOffBits = log2Up(rowBytes) - def code = cacheParams.ecc.getOrElse(new IdentityCode) def nTLBEntries = cacheParams.nTLBEntries def cacheDataBits = p(SharedMemoryTLEdge).bundle.dataBits