Separate tag ECC and data ECC options (#761)
This commit is contained in:
parent
940614625e
commit
b2b4c1abcd
@ -44,7 +44,9 @@ class DCache(val scratch: () => Option[AddressSet] = () => None)(implicit p: Par
|
|||||||
}
|
}
|
||||||
|
|
||||||
class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
|
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
|
// tags
|
||||||
val replacer = cacheParams.replacement
|
val replacer = cacheParams.replacement
|
||||||
|
@ -10,7 +10,7 @@ import diplomacy._
|
|||||||
import tile._
|
import tile._
|
||||||
import uncore.constants._
|
import uncore.constants._
|
||||||
import uncore.tilelink2._
|
import uncore.tilelink2._
|
||||||
import uncore.util.Code
|
import uncore.util.{Code, IdentityCode}
|
||||||
import util.{ParameterizedBundle, RandomReplacement}
|
import util.{ParameterizedBundle, RandomReplacement}
|
||||||
import scala.collection.mutable.ListBuffer
|
import scala.collection.mutable.ListBuffer
|
||||||
import scala.math.max
|
import scala.math.max
|
||||||
@ -20,7 +20,8 @@ case class DCacheParams(
|
|||||||
nWays: Int = 4,
|
nWays: Int = 4,
|
||||||
rowBits: Int = 64,
|
rowBits: Int = 64,
|
||||||
nTLBEntries: Int = 32,
|
nTLBEntries: Int = 32,
|
||||||
ecc: Option[Code] = None,
|
tagECC: Code = new IdentityCode,
|
||||||
|
dataECC: Code = new IdentityCode,
|
||||||
nMSHRs: Int = 1,
|
nMSHRs: Int = 1,
|
||||||
nSDQ: Int = 17,
|
nSDQ: Int = 17,
|
||||||
nRPQ: Int = 16,
|
nRPQ: Int = 16,
|
||||||
@ -55,7 +56,7 @@ trait HasL1HellaCacheParameters extends HasL1CacheParameters with HasCoreParamet
|
|||||||
def offsetlsb = wordOffBits
|
def offsetlsb = wordOffBits
|
||||||
def rowWords = rowBits/wordBits
|
def rowWords = rowBits/wordBits
|
||||||
def doNarrowRead = coreDataBits * nWays % rowBits == 0
|
def doNarrowRead = coreDataBits * nWays % rowBits == 0
|
||||||
def encDataBits = code.width(coreDataBits)
|
def encDataBits = cacheParams.dataECC.width(coreDataBits)
|
||||||
def encRowBits = encDataBits*rowWords
|
def encRowBits = encDataBits*rowWords
|
||||||
def lrscCycles = 32 // ISA requires 16-insn LRSC sequences to succeed
|
def lrscCycles = 32 // ISA requires 16-insn LRSC sequences to succeed
|
||||||
def lrscBackoff = 3 // disallow LRSC reacquisition briefly
|
def lrscBackoff = 3 // disallow LRSC reacquisition briefly
|
||||||
|
@ -8,7 +8,7 @@ import config._
|
|||||||
import diplomacy._
|
import diplomacy._
|
||||||
import tile._
|
import tile._
|
||||||
import uncore.tilelink2._
|
import uncore.tilelink2._
|
||||||
import uncore.util.Code
|
import uncore.util._
|
||||||
import util._
|
import util._
|
||||||
import Chisel.ImplicitConversions._
|
import Chisel.ImplicitConversions._
|
||||||
|
|
||||||
@ -18,7 +18,8 @@ case class ICacheParams(
|
|||||||
rowBits: Int = 128,
|
rowBits: Int = 128,
|
||||||
nTLBEntries: Int = 32,
|
nTLBEntries: Int = 32,
|
||||||
cacheIdBits: Int = 0,
|
cacheIdBits: Int = 0,
|
||||||
ecc: Option[Code] = None,
|
tagECC: Code = new IdentityCode,
|
||||||
|
dataECC: Code = new IdentityCode,
|
||||||
itimAddr: Option[BigInt] = None,
|
itimAddr: Option[BigInt] = None,
|
||||||
blockBytes: Int = 64) extends L1CacheParams {
|
blockBytes: Int = 64) extends L1CacheParams {
|
||||||
def replacement = new RandomReplacement(nWays)
|
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 edge_in = outer.slaveNode.map(_.edgesIn.head)
|
||||||
val tl_in = io.tl_in.map(_.head)
|
val tl_in = io.tl_in.map(_.head)
|
||||||
|
|
||||||
|
val tECC = cacheParams.tagECC
|
||||||
|
val dECC = cacheParams.dataECC
|
||||||
|
|
||||||
require(isPow2(nSets) && isPow2(nWays))
|
require(isPow2(nSets) && isPow2(nWays))
|
||||||
require(isPow2(coreInstBytes))
|
require(isPow2(coreInstBytes))
|
||||||
require(!usingVM || pgIdxBits >= untagBits)
|
require(!usingVM || pgIdxBits >= untagBits)
|
||||||
@ -141,11 +145,10 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
|
|||||||
v
|
v
|
||||||
}
|
}
|
||||||
|
|
||||||
val entagbits = code.width(tagBits)
|
val tag_array = SeqMem(nSets, Vec(nWays, Bits(width = tECC.width(tagBits))))
|
||||||
val tag_array = SeqMem(nSets, Vec(nWays, Bits(width = entagbits)))
|
|
||||||
val tag_rdata = tag_array.read(s0_vaddr(untagBits-1,blockOffBits), !refill_done && s0_valid)
|
val tag_rdata = tag_array.read(s0_vaddr(untagBits-1,blockOffBits), !refill_done && s0_valid)
|
||||||
when (refill_done) {
|
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 === _))
|
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 s1_tag_disparity = Wire(Vec(nWays, Bool()))
|
||||||
val wordBits = coreInstBits * fetchWidth
|
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 s0_slaveAddr = tl_in.map(_.a.bits.address).getOrElse(0.U)
|
||||||
val s1s3_slaveAddr = Reg(UInt(width = log2Ceil(outer.size)))
|
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,
|
lineInScratchpad(scratchpadLine(s1s3_slaveAddr)) && scratchpadWay(s1s3_slaveAddr) === i,
|
||||||
addrInScratchpad(io.s1_paddr) && scratchpadWay(io.s1_paddr) === i)
|
addrInScratchpad(io.s1_paddr) && scratchpadWay(io.s1_paddr) === i)
|
||||||
val s1_vb = vb_array(Cat(UInt(i), s1_idx)) && !s1_slaveValid
|
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_disparity(i) := s1_vb && tECC.decode(tag_rdata(i)).error
|
||||||
s1_tag_hit(i) := scratchpadHit || (s1_vb && code.decode(tag_rdata(i)).uncorrected === s1_tag)
|
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)
|
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)
|
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) {
|
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 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))
|
def row(addr: UInt) = addr(untagBits-1, blockOffBits-log2Ceil(refillCycles))
|
||||||
@ -195,7 +198,7 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
|
|||||||
when (wen) {
|
when (wen) {
|
||||||
val data = Mux(s3_slaveValid, s1s3_slaveData, tl_out.d.bits.data(wordBits*(i+1)-1, wordBits*i))
|
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)
|
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)
|
val dout = data_array.read(mem_idx, !wen && s0_ren)
|
||||||
when (wordMatch(Mux(s1_slaveValid, s1s3_slaveAddr, io.s1_paddr))) {
|
when (wordMatch(Mux(s1_slaveValid, s1s3_slaveAddr, io.s1_paddr))) {
|
||||||
@ -206,7 +209,8 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
|
|||||||
// output signals
|
// output signals
|
||||||
outer.latency match {
|
outer.latency match {
|
||||||
case 1 =>
|
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)
|
require(outer.icacheParams.itimAddr.isEmpty)
|
||||||
io.resp.bits := Mux1H(s1_tag_hit, s1_dout)
|
io.resp.bits := Mux1H(s1_tag_hit, s1_dout)
|
||||||
io.resp.valid := s1_hit
|
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_way_mux = Mux1H(s2_tag_hit, s2_dout)
|
||||||
|
|
||||||
val s2_tag_disparity = RegEnable(s1_tag_disparity, s1_valid || s1_slaveValid).asUInt.orR
|
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
|
val s2_disparity = s2_tag_disparity || s2_data_decoded.error
|
||||||
when (s2_valid && s2_disparity) { invalidate := true }
|
when (s2_valid && s2_disparity) { invalidate := true }
|
||||||
|
|
||||||
|
@ -669,6 +669,10 @@ class NonBlockingDCacheModule(outer: NonBlockingDCache) extends HellaCacheModule
|
|||||||
require(isPow2(nWays)) // TODO: relax this
|
require(isPow2(nWays)) // TODO: relax this
|
||||||
require(dataScratchpadSize == 0)
|
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 wb = Module(new WritebackUnit)
|
||||||
val prober = Module(new ProbeUnit)
|
val prober = Module(new ProbeUnit)
|
||||||
val mshrs = Module(new MSHRFile)
|
val mshrs = Module(new MSHRFile)
|
||||||
@ -759,7 +763,7 @@ class NonBlockingDCacheModule(outer: NonBlockingDCache) extends HellaCacheModule
|
|||||||
data.io.write.valid := writeArb.io.out.valid
|
data.io.write.valid := writeArb.io.out.valid
|
||||||
writeArb.io.out.ready := data.io.write.ready
|
writeArb.io.out.ready := data.io.write.ready
|
||||||
data.io.write.bits := writeArb.io.out.bits
|
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
|
data.io.write.bits.data := wdata_encoded.asUInt
|
||||||
|
|
||||||
// tag read for new requests
|
// tag read for new requests
|
||||||
@ -822,7 +826,7 @@ class NonBlockingDCacheModule(outer: NonBlockingDCache) extends HellaCacheModule
|
|||||||
s2_data(w) := regs.asUInt
|
s2_data(w) := regs.asUInt
|
||||||
}
|
}
|
||||||
val s2_data_muxed = Mux1H(s2_tag_match_way, s2_data)
|
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_corrected = s2_data_decoded.map(_.corrected).asUInt
|
||||||
val s2_data_uncorrected = s2_data_decoded.map(_.uncorrected).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))
|
val s2_word_idx = if(doNarrowRead) UInt(0) else s2_req.addr(log2Up(rowWords*coreDataBytes)-1,log2Up(wordBytes))
|
||||||
|
@ -15,7 +15,6 @@ trait L1CacheParams {
|
|||||||
def nWays: Int
|
def nWays: Int
|
||||||
def rowBits: Int
|
def rowBits: Int
|
||||||
def nTLBEntries: Int
|
def nTLBEntries: Int
|
||||||
def ecc: Option[Code]
|
|
||||||
def blockBytes: Int
|
def blockBytes: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,7 +35,6 @@ trait HasL1CacheParameters {
|
|||||||
def rowBits = cacheParams.rowBits
|
def rowBits = cacheParams.rowBits
|
||||||
def rowBytes = rowBits/8
|
def rowBytes = rowBits/8
|
||||||
def rowOffBits = log2Up(rowBytes)
|
def rowOffBits = log2Up(rowBytes)
|
||||||
def code = cacheParams.ecc.getOrElse(new IdentityCode)
|
|
||||||
def nTLBEntries = cacheParams.nTLBEntries
|
def nTLBEntries = cacheParams.nTLBEntries
|
||||||
|
|
||||||
def cacheDataBits = p(SharedMemoryTLEdge).bundle.dataBits
|
def cacheDataBits = p(SharedMemoryTLEdge).bundle.dataBits
|
||||||
|
Loading…
Reference in New Issue
Block a user