Merge pull request #843 from freechipsproject/tag-ecc
Add tag ECC to D$
This commit is contained in:
commit
ec9fbe26d8
@ -49,6 +49,13 @@ class DCacheDataArray(implicit p: Parameters) extends L1HellaCacheModule()(p) {
|
|||||||
(io.resp zip rdata.transpose).foreach { case (resp, data) => resp := data.asUInt }
|
(io.resp zip rdata.transpose).foreach { case (resp, data) => resp := data.asUInt }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DCacheMetadataReq(implicit p: Parameters) extends L1HellaCacheBundle()(p) {
|
||||||
|
val write = Bool()
|
||||||
|
val idx = UInt(width = idxBits)
|
||||||
|
val way_en = UInt(width = nWays)
|
||||||
|
val data = new L1Metadata
|
||||||
|
}
|
||||||
|
|
||||||
class DCache(hartid: Int, val scratch: () => Option[AddressSet] = () => None)(implicit p: Parameters) extends HellaCache(hartid)(p) {
|
class DCache(hartid: Int, val scratch: () => Option[AddressSet] = () => None)(implicit p: Parameters) extends HellaCache(hartid)(p) {
|
||||||
override lazy val module = new DCacheModule(this)
|
override lazy val module = new DCacheModule(this)
|
||||||
}
|
}
|
||||||
@ -59,16 +66,14 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
|
|||||||
val dECC = cacheParams.dataECC
|
val dECC = cacheParams.dataECC
|
||||||
val eccBytes = cacheParams.dataECCBytes
|
val eccBytes = cacheParams.dataECCBytes
|
||||||
val eccBits = eccBytes * 8
|
val eccBits = eccBytes * 8
|
||||||
require(tECC.isInstanceOf[IdentityCode])
|
|
||||||
require(isPow2(eccBytes) && eccBytes <= wordBytes)
|
require(isPow2(eccBytes) && eccBytes <= wordBytes)
|
||||||
require(eccBytes == 1 || !dECC.isInstanceOf[IdentityCode])
|
require(eccBytes == 1 || !dECC.isInstanceOf[IdentityCode])
|
||||||
val usingRMW = eccBytes > 1 || usingAtomics
|
val usingRMW = eccBytes > 1 || usingAtomics
|
||||||
|
|
||||||
// tags
|
// tags
|
||||||
val replacer = cacheParams.replacement
|
val replacer = cacheParams.replacement
|
||||||
def onReset = L1Metadata(UInt(0), ClientMetadata.onReset)
|
val metaArb = Module(new Arbiter(new DCacheMetadataReq, 8))
|
||||||
val metaReadArb = Module(new Arbiter(new L1MetaReadReq, 3))
|
val tag_array = SeqMem(nSets, Vec(nWays, UInt(width = tECC.width(metaArb.io.out.bits.data.getWidth))))
|
||||||
val metaWriteArb = Module(new Arbiter(new L1MetaWriteReq, 3))
|
|
||||||
|
|
||||||
// data
|
// data
|
||||||
val data = Module(new DCacheDataArray)
|
val data = Module(new DCacheDataArray)
|
||||||
@ -76,6 +81,7 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
|
|||||||
data.io.req <> dataArb.io.out
|
data.io.req <> dataArb.io.out
|
||||||
data.io.req.bits.wdata := encodeData(dataArb.io.out.bits.wdata(rowBits-1, 0))
|
data.io.req.bits.wdata := encodeData(dataArb.io.out.bits.wdata(rowBits-1, 0))
|
||||||
dataArb.io.out.ready := true
|
dataArb.io.out.ready := true
|
||||||
|
metaArb.io.out.ready := true
|
||||||
|
|
||||||
val rational = p(coreplex.RocketCrossing) match {
|
val rational = p(coreplex.RocketCrossing) match {
|
||||||
case coreplex.RationalCrossing(_) => true
|
case coreplex.RationalCrossing(_) => true
|
||||||
@ -93,9 +99,9 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
|
|||||||
val s1_valid_masked = s1_valid && !io.cpu.s1_kill
|
val s1_valid_masked = s1_valid && !io.cpu.s1_kill
|
||||||
val s1_valid_not_nacked = s1_valid && !s1_nack
|
val s1_valid_not_nacked = s1_valid && !s1_nack
|
||||||
val s1_req = Reg(io.cpu.req.bits)
|
val s1_req = Reg(io.cpu.req.bits)
|
||||||
when (metaReadArb.io.out.valid) {
|
when (metaArb.io.out.valid && !metaArb.io.out.bits.write) {
|
||||||
s1_req := io.cpu.req.bits
|
s1_req := io.cpu.req.bits
|
||||||
s1_req.addr := Cat(io.cpu.req.bits.addr >> untagBits, metaReadArb.io.out.bits.idx, io.cpu.req.bits.addr(blockOffBits-1,0))
|
s1_req.addr := Cat(io.cpu.req.bits.addr >> untagBits, metaArb.io.out.bits.idx, io.cpu.req.bits.addr(blockOffBits-1,0))
|
||||||
}
|
}
|
||||||
val s1_read = needsRead(s1_req)
|
val s1_read = needsRead(s1_req)
|
||||||
val s1_write = isWrite(s1_req.cmd)
|
val s1_write = isWrite(s1_req.cmd)
|
||||||
@ -103,7 +109,7 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
|
|||||||
val s1_sfence = s1_req.cmd === M_SFENCE
|
val s1_sfence = s1_req.cmd === M_SFENCE
|
||||||
val s1_flush_valid = Reg(Bool())
|
val s1_flush_valid = Reg(Bool())
|
||||||
|
|
||||||
val s_ready :: s_voluntary_writeback :: s_probe_rep_dirty :: s_probe_rep_clean :: s_probe_rep_miss :: s_voluntary_write_meta :: s_probe_write_meta :: Nil = Enum(UInt(), 7)
|
val s_ready :: s_voluntary_writeback :: s_probe_rep_dirty :: s_probe_rep_clean :: s_probe_retry :: s_probe_rep_miss :: s_voluntary_write_meta :: s_probe_write_meta :: Nil = Enum(UInt(), 8)
|
||||||
val cached_grant_wait = Reg(init=Bool(false))
|
val cached_grant_wait = Reg(init=Bool(false))
|
||||||
val release_ack_wait = Reg(init=Bool(false))
|
val release_ack_wait = Reg(init=Bool(false))
|
||||||
val release_state = Reg(init=s_ready)
|
val release_state = Reg(init=s_ready)
|
||||||
@ -125,10 +131,12 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
|
|||||||
dataArb.io.in(3).bits.wordMask := UIntToOH(io.cpu.req.bits.addr.extract(rowOffBits-1,offsetlsb))
|
dataArb.io.in(3).bits.wordMask := UIntToOH(io.cpu.req.bits.addr.extract(rowOffBits-1,offsetlsb))
|
||||||
dataArb.io.in(3).bits.way_en := ~UInt(0, nWays)
|
dataArb.io.in(3).bits.way_en := ~UInt(0, nWays)
|
||||||
when (!dataArb.io.in(3).ready && s0_read) { io.cpu.req.ready := false }
|
when (!dataArb.io.in(3).ready && s0_read) { io.cpu.req.ready := false }
|
||||||
metaReadArb.io.in(2).valid := io.cpu.req.valid
|
metaArb.io.in(7).valid := io.cpu.req.valid
|
||||||
metaReadArb.io.in(2).bits.idx := io.cpu.req.bits.addr(idxMSB, idxLSB)
|
metaArb.io.in(7).bits.write := false
|
||||||
metaReadArb.io.in(2).bits.way_en := ~UInt(0, nWays)
|
metaArb.io.in(7).bits.idx := io.cpu.req.bits.addr(idxMSB, idxLSB)
|
||||||
when (!metaReadArb.io.in(2).ready) { io.cpu.req.ready := false }
|
metaArb.io.in(7).bits.way_en := ~UInt(0, nWays)
|
||||||
|
metaArb.io.in(7).bits.data := metaArb.io.in(4).bits.data
|
||||||
|
when (!metaArb.io.in(7).ready) { io.cpu.req.ready := false }
|
||||||
|
|
||||||
// address translation
|
// address translation
|
||||||
val tlb = Module(new TLB(log2Ceil(coreDataBytes), nTLBEntries))
|
val tlb = Module(new TLB(log2Ceil(coreDataBytes), nTLBEntries))
|
||||||
@ -149,24 +157,27 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
|
|||||||
val s1_paddr = tlb.io.resp.paddr
|
val s1_paddr = tlb.io.resp.paddr
|
||||||
val s1_tag = Mux(s1_probe, probe_bits.address, s1_paddr) >> untagBits
|
val s1_tag = Mux(s1_probe, probe_bits.address, s1_paddr) >> untagBits
|
||||||
val s1_victim_way = Wire(init = replacer.way)
|
val s1_victim_way = Wire(init = replacer.way)
|
||||||
val (s1_hit_way, s1_hit_state, s1_victim_meta) =
|
val (s1_hit_way, s1_hit_state, s1_meta, s1_victim_meta) =
|
||||||
if (usingDataScratchpad) {
|
if (usingDataScratchpad) {
|
||||||
metaWriteArb.io.out.ready := true
|
|
||||||
metaReadArb.io.out.ready := !metaWriteArb.io.out.valid
|
|
||||||
val baseAddr = GetPropertyByHartId(p(coreplex.RocketTilesKey), _.dcache.flatMap(_.scratch.map(_.U)), io.hartid)
|
val baseAddr = GetPropertyByHartId(p(coreplex.RocketTilesKey), _.dcache.flatMap(_.scratch.map(_.U)), io.hartid)
|
||||||
val inScratchpad = s1_paddr >= baseAddr && s1_paddr < baseAddr + nSets * cacheBlockBytes
|
val inScratchpad = s1_paddr >= baseAddr && s1_paddr < baseAddr + nSets * cacheBlockBytes
|
||||||
val hitState = Mux(inScratchpad, ClientMetadata.maximum, ClientMetadata.onReset)
|
val hitState = Mux(inScratchpad, ClientMetadata.maximum, ClientMetadata.onReset)
|
||||||
(inScratchpad, hitState, L1Metadata(UInt(0), ClientMetadata.onReset))
|
val dummyMeta = L1Metadata(UInt(0), ClientMetadata.onReset)
|
||||||
|
(inScratchpad, hitState, Seq(tECC.encode(dummyMeta.asUInt)), dummyMeta)
|
||||||
} else {
|
} else {
|
||||||
val meta = Module(new L1MetadataArray(onReset _))
|
val metaReq = metaArb.io.out
|
||||||
meta.io.read <> metaReadArb.io.out
|
when (metaReq.valid && metaReq.bits.write) {
|
||||||
meta.io.write <> metaWriteArb.io.out
|
val wdata = tECC.encode(metaReq.bits.data.asUInt)
|
||||||
val s1_meta = meta.io.resp
|
val wmask = if (nWays == 1) Seq(true.B) else metaReq.bits.way_en.toBools
|
||||||
val s1_meta_hit_way = s1_meta.map(r => r.coh.isValid() && r.tag === s1_tag).asUInt
|
tag_array.write(metaReq.bits.idx, Vec.fill(nWays)(wdata), wmask)
|
||||||
|
}
|
||||||
|
val s1_meta = tag_array.read(metaReq.bits.idx, metaReq.valid && !metaReq.bits.write)
|
||||||
|
val s1_meta_uncorrected = s1_meta.map(tECC.decode(_).uncorrected.asTypeOf(new L1Metadata))
|
||||||
|
val s1_meta_hit_way = s1_meta_uncorrected.map(r => r.coh.isValid() && r.tag === s1_tag).asUInt
|
||||||
val s1_meta_hit_state = ClientMetadata.onReset.fromBits(
|
val s1_meta_hit_state = ClientMetadata.onReset.fromBits(
|
||||||
s1_meta.map(r => Mux(r.tag === s1_tag, r.coh.asUInt, UInt(0)))
|
s1_meta_uncorrected.map(r => Mux(r.tag === s1_tag, r.coh.asUInt, UInt(0)))
|
||||||
.reduce (_|_))
|
.reduce (_|_))
|
||||||
(s1_meta_hit_way, s1_meta_hit_state, s1_meta(s1_victim_way))
|
(s1_meta_hit_way, s1_meta_hit_state, s1_meta, s1_meta_uncorrected(s1_victim_way))
|
||||||
}
|
}
|
||||||
val s1_data_way = Mux(inWriteback, releaseWay, s1_hit_way)
|
val s1_data_way = Mux(inWriteback, releaseWay, s1_hit_way)
|
||||||
val s1_data = Mux1H(s1_data_way, data.io.resp) // retime into s2 if critical
|
val s1_data = Mux1H(s1_data_way, data.io.resp) // retime into s2 if critical
|
||||||
@ -188,7 +199,12 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
|
|||||||
val s2_read = isRead(s2_req.cmd)
|
val s2_read = isRead(s2_req.cmd)
|
||||||
val s2_write = isWrite(s2_req.cmd)
|
val s2_write = isWrite(s2_req.cmd)
|
||||||
val s2_readwrite = s2_read || s2_write
|
val s2_readwrite = s2_read || s2_write
|
||||||
val s2_flush_valid = RegNext(s1_flush_valid)
|
val s2_flush_valid_pre_tag_ecc = RegNext(s1_flush_valid)
|
||||||
|
val s2_meta = s1_meta.map(RegEnable(_, s1_valid_not_nacked || s1_flush_valid || s1_probe)).map(tECC.decode(_))
|
||||||
|
val s2_meta_corrected = s2_meta.map(_.corrected.asTypeOf(new L1Metadata))
|
||||||
|
val s2_meta_errors = s2_meta.map(_.error).asUInt
|
||||||
|
val s2_meta_error = s2_meta_errors.orR
|
||||||
|
val s2_flush_valid = s2_flush_valid_pre_tag_ecc && !s2_meta_error
|
||||||
val s2_data = RegEnable(s1_data, s1_valid || inWriteback)
|
val s2_data = RegEnable(s1_data, s1_valid || inWriteback)
|
||||||
val s2_probe_way = RegEnable(s1_hit_way, s1_probe)
|
val s2_probe_way = RegEnable(s1_hit_way, s1_probe)
|
||||||
val s2_probe_state = RegEnable(s1_hit_state, s1_probe)
|
val s2_probe_state = RegEnable(s1_hit_state, s1_probe)
|
||||||
@ -201,23 +217,38 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
|
|||||||
val s2_data_error = needsRead(s2_req) && (s2_data_decoded.map(_.error).grouped(wordBits/eccBits).map(_.reduce(_||_)).toSeq)(s2_word_idx)
|
val s2_data_error = needsRead(s2_req) && (s2_data_decoded.map(_.error).grouped(wordBits/eccBits).map(_.reduce(_||_)).toSeq)(s2_word_idx)
|
||||||
val s2_data_corrected = (s2_data_decoded.map(_.corrected): Seq[UInt]).asUInt
|
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_data_uncorrected = (s2_data_decoded.map(_.uncorrected): Seq[UInt]).asUInt
|
||||||
val s2_valid_hit_pre_data_ecc = s2_valid_masked && s2_readwrite && s2_hit
|
val s2_valid_hit_pre_data_ecc = s2_valid_masked && s2_readwrite && !s2_meta_error && s2_hit
|
||||||
val s2_valid_data_error = s2_valid_hit_pre_data_ecc && s2_data_error
|
val s2_valid_data_error = s2_valid_hit_pre_data_ecc && s2_data_error
|
||||||
val s2_valid_hit = s2_valid_hit_pre_data_ecc && !s2_data_error
|
val s2_valid_hit = s2_valid_hit_pre_data_ecc && !s2_data_error
|
||||||
val s2_valid_miss = s2_valid_masked && s2_readwrite && !s2_hit && !any_pstore_valid && !release_ack_wait
|
val s2_valid_miss = s2_valid_masked && s2_readwrite && !s2_meta_error && !s2_hit && !any_pstore_valid && !release_ack_wait
|
||||||
val s2_valid_cached_miss = s2_valid_miss && !s2_uncached && !uncachedInFlight.asUInt.orR
|
val s2_valid_cached_miss = s2_valid_miss && !s2_uncached && !uncachedInFlight.asUInt.orR
|
||||||
val s2_victimize = Bool(!usingDataScratchpad) && (s2_valid_cached_miss || s2_valid_data_error || s2_flush_valid)
|
val s2_victimize = Bool(!usingDataScratchpad) && (s2_valid_cached_miss || s2_valid_data_error || s2_flush_valid)
|
||||||
val s2_valid_uncached = s2_valid_miss && s2_uncached
|
val s2_valid_uncached = s2_valid_miss && s2_uncached
|
||||||
val s2_victim_way = Mux(s2_hit_valid && !s2_flush_valid, s2_hit_way, UIntToOH(RegEnable(s1_victim_way, s1_valid_not_nacked || s1_flush_valid)))
|
val s2_victim_way = Mux(s2_hit_valid && !s2_flush_valid_pre_tag_ecc, s2_hit_way, UIntToOH(RegEnable(s1_victim_way, s1_valid_not_nacked || s1_flush_valid)))
|
||||||
val s2_victim_tag = Mux(s2_valid_data_error, s2_req.addr >> untagBits, RegEnable(s1_victim_meta.tag, s1_valid_not_nacked || s1_flush_valid))
|
val s2_victim_tag = Mux(s2_valid_data_error, s2_req.addr >> untagBits, RegEnable(s1_victim_meta.tag, s1_valid_not_nacked || s1_flush_valid))
|
||||||
val s2_victim_state = Mux(s2_hit_valid && !s2_flush_valid, s2_hit_state, RegEnable(s1_victim_meta.coh, s1_valid_not_nacked || s1_flush_valid))
|
val s2_victim_state = Mux(s2_hit_valid && !s2_flush_valid, s2_hit_state, RegEnable(s1_victim_meta.coh, s1_valid_not_nacked || s1_flush_valid))
|
||||||
val s2_victim_valid = s2_victim_state.isValid()
|
|
||||||
val (s2_prb_ack_data, s2_report_param, probeNewCoh)= s2_probe_state.onProbe(probe_bits.param)
|
val (s2_prb_ack_data, s2_report_param, probeNewCoh)= s2_probe_state.onProbe(probe_bits.param)
|
||||||
val (s2_victim_dirty, s2_shrink_param, voluntaryNewCoh) = s2_victim_state.onCacheControl(M_FLUSH)
|
val (s2_victim_dirty, s2_shrink_param, voluntaryNewCoh) = s2_victim_state.onCacheControl(M_FLUSH)
|
||||||
val s2_update_meta = s2_hit_state =/= s2_new_hit_state
|
val s2_update_meta = s2_hit_state =/= s2_new_hit_state
|
||||||
io.cpu.s2_nack := s2_valid && !s2_valid_hit && !(s2_valid_uncached && tl_out_a.ready && !uncachedInFlight.asUInt.andR)
|
io.cpu.s2_nack := s2_valid && !s2_valid_hit && !(s2_valid_uncached && tl_out_a.ready && !uncachedInFlight.asUInt.andR)
|
||||||
when (io.cpu.s2_nack || (s2_valid_hit && s2_update_meta)) { s1_nack := true }
|
when (io.cpu.s2_nack || (s2_valid_hit && s2_update_meta)) { s1_nack := true }
|
||||||
|
|
||||||
|
// 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.idx := Mux(s2_probe, probe_bits.address, s2_req.addr)(idxMSB, idxLSB)
|
||||||
|
metaArb.io.in(1).bits.data := PriorityMux(s2_meta_errors, s2_meta_corrected)
|
||||||
|
|
||||||
|
// tag updates on hit/miss
|
||||||
|
metaArb.io.in(2).valid := (s2_valid_hit && s2_update_meta) || (s2_victimize && !s2_victim_dirty)
|
||||||
|
metaArb.io.in(2).bits.write := true
|
||||||
|
metaArb.io.in(2).bits.way_en := s2_victim_way
|
||||||
|
metaArb.io.in(2).bits.idx := s2_req.addr(idxMSB, idxLSB)
|
||||||
|
metaArb.io.in(2).bits.data.coh := Mux(s2_valid_hit, s2_new_hit_state, ClientMetadata.onReset)
|
||||||
|
metaArb.io.in(2).bits.data.tag := s2_req.addr >> untagBits
|
||||||
|
|
||||||
// load reservations
|
// load reservations
|
||||||
val s2_lr = Bool(usingAtomics && !usingDataScratchpad) && s2_req.cmd === M_XLR
|
val s2_lr = Bool(usingAtomics && !usingDataScratchpad) && s2_req.cmd === M_XLR
|
||||||
val s2_sc = Bool(usingAtomics && !usingDataScratchpad) && s2_req.cmd === M_XSC
|
val s2_sc = Bool(usingAtomics && !usingDataScratchpad) && s2_req.cmd === M_XSC
|
||||||
@ -281,12 +312,6 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
|
|||||||
(pstore2_valid && s1Depends(pstore2_addr, pstore2_storegen_mask)))
|
(pstore2_valid && s1Depends(pstore2_addr, pstore2_storegen_mask)))
|
||||||
when (s1_valid && s1_raw_hazard) { s1_nack := true }
|
when (s1_valid && s1_raw_hazard) { s1_nack := true }
|
||||||
|
|
||||||
metaWriteArb.io.in(0).valid := (s2_valid_hit && s2_update_meta) || (s2_victimize && !s2_victim_dirty)
|
|
||||||
metaWriteArb.io.in(0).bits.way_en := s2_victim_way
|
|
||||||
metaWriteArb.io.in(0).bits.idx := s2_req.addr(idxMSB, idxLSB)
|
|
||||||
metaWriteArb.io.in(0).bits.data.coh := Mux(s2_valid_hit, s2_new_hit_state, ClientMetadata.onReset)
|
|
||||||
metaWriteArb.io.in(0).bits.data.tag := s2_req.addr >> untagBits
|
|
||||||
|
|
||||||
// Prepare a TileLink request message that initiates a transaction
|
// Prepare a TileLink request message that initiates a transaction
|
||||||
val a_source = PriorityEncoder(~uncachedInFlight.asUInt << mmioOffset) // skip the MSHR
|
val a_source = PriorityEncoder(~uncachedInFlight.asUInt << mmioOffset) // skip the MSHR
|
||||||
val acquire_address = s2_req_block_addr
|
val acquire_address = s2_req_block_addr
|
||||||
@ -391,12 +416,13 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
|
|||||||
dataArb.io.in(1).bits.wordMask := ~UInt(0, rowBytes / wordBytes)
|
dataArb.io.in(1).bits.wordMask := ~UInt(0, rowBytes / wordBytes)
|
||||||
dataArb.io.in(1).bits.eccMask := ~UInt(0, wordBytes / eccBytes)
|
dataArb.io.in(1).bits.eccMask := ~UInt(0, wordBytes / eccBytes)
|
||||||
// tag updates on refill
|
// tag updates on refill
|
||||||
metaWriteArb.io.in(1).valid := grantIsCached && d_done
|
metaArb.io.in(3).valid := grantIsCached && d_done
|
||||||
assert(!metaWriteArb.io.in(1).valid || metaWriteArb.io.in(1).ready)
|
assert(!metaArb.io.in(3).valid || metaArb.io.in(3).ready)
|
||||||
metaWriteArb.io.in(1).bits.way_en := s2_victim_way
|
metaArb.io.in(3).bits.write := true
|
||||||
metaWriteArb.io.in(1).bits.idx := s2_req.addr(idxMSB, idxLSB)
|
metaArb.io.in(3).bits.way_en := s2_victim_way
|
||||||
metaWriteArb.io.in(1).bits.data.coh := s2_hit_state.onGrant(s2_req.cmd, tl_out.d.bits.param)
|
metaArb.io.in(3).bits.idx := s2_req.addr(idxMSB, idxLSB)
|
||||||
metaWriteArb.io.in(1).bits.data.tag := s2_req.addr >> untagBits
|
metaArb.io.in(3).bits.data.coh := s2_hit_state.onGrant(s2_req.cmd, tl_out.d.bits.param)
|
||||||
|
metaArb.io.in(3).bits.data.tag := s2_req.addr >> untagBits
|
||||||
// don't accept uncached grants if there's a structural hazard on s2_data...
|
// don't accept uncached grants if there's a structural hazard on s2_data...
|
||||||
val blockUncachedGrant = Reg(Bool())
|
val blockUncachedGrant = Reg(Bool())
|
||||||
blockUncachedGrant := dataArb.io.out.valid
|
blockUncachedGrant := dataArb.io.out.valid
|
||||||
@ -418,10 +444,12 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
|
|||||||
|
|
||||||
// Handle an incoming TileLink Probe message
|
// Handle an incoming TileLink Probe message
|
||||||
val block_probe = releaseInFlight || grantInProgress || blockProbeAfterGrantCount > 0 || lrscValid || (s2_valid_hit && s2_lr)
|
val block_probe = releaseInFlight || grantInProgress || blockProbeAfterGrantCount > 0 || lrscValid || (s2_valid_hit && s2_lr)
|
||||||
metaReadArb.io.in(1).valid := tl_out.b.valid && !block_probe
|
metaArb.io.in(6).valid := tl_out.b.valid && !block_probe
|
||||||
tl_out.b.ready := metaReadArb.io.in(1).ready && !block_probe && !s1_valid && (!s2_valid || s2_valid_hit)
|
tl_out.b.ready := metaArb.io.in(6).ready && !block_probe && !s1_valid && (!s2_valid || s2_valid_hit)
|
||||||
metaReadArb.io.in(1).bits.idx := tl_out.b.bits.address(idxMSB, idxLSB)
|
metaArb.io.in(6).bits.write := false
|
||||||
metaReadArb.io.in(1).bits.way_en := ~UInt(0, nWays)
|
metaArb.io.in(6).bits.idx := tl_out.b.bits.address(idxMSB, idxLSB)
|
||||||
|
metaArb.io.in(6).bits.way_en := ~UInt(0, nWays)
|
||||||
|
metaArb.io.in(6).bits.data := metaArb.io.in(4).bits.data
|
||||||
|
|
||||||
// release
|
// release
|
||||||
val (c_first, c_last, releaseDone, c_count) = edge.count(tl_out.c)
|
val (c_first, c_last, releaseDone, c_count) = edge.count(tl_out.c)
|
||||||
@ -430,29 +458,9 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
|
|||||||
val s2_release_data_valid = Reg(next = s1_release_data_valid && !releaseRejected)
|
val s2_release_data_valid = Reg(next = s1_release_data_valid && !releaseRejected)
|
||||||
val releaseDataBeat = Cat(UInt(0), c_count) + Mux(releaseRejected, UInt(0), s1_release_data_valid + Cat(UInt(0), s2_release_data_valid))
|
val releaseDataBeat = Cat(UInt(0), c_count) + Mux(releaseRejected, UInt(0), s1_release_data_valid + Cat(UInt(0), s2_release_data_valid))
|
||||||
|
|
||||||
val nackResponseMessage = edge.ProbeAck(
|
val nackResponseMessage = edge.ProbeAck(b = probe_bits, reportPermissions = TLPermissions.NtoN)
|
||||||
b = probe_bits,
|
val cleanReleaseMessage = edge.ProbeAck(b = probe_bits, reportPermissions = s2_report_param)
|
||||||
reportPermissions = TLPermissions.NtoN)
|
val dirtyReleaseMessage = edge.ProbeAck(b = probe_bits, reportPermissions = s2_report_param, data = 0.U)
|
||||||
|
|
||||||
val voluntaryReleaseMessage = if (edge.manager.anySupportAcquireB) {
|
|
||||||
edge.Release(
|
|
||||||
fromSource = UInt(0),
|
|
||||||
toAddress = probe_bits.address,
|
|
||||||
lgSize = lgCacheBlockBytes,
|
|
||||||
shrinkPermissions = s2_shrink_param,
|
|
||||||
data = 0.U)._2
|
|
||||||
} else {
|
|
||||||
Wire(new TLBundleC(edge.bundle))
|
|
||||||
}
|
|
||||||
|
|
||||||
val probeResponseMessage = Mux(!s2_prb_ack_data,
|
|
||||||
edge.ProbeAck(
|
|
||||||
b = probe_bits,
|
|
||||||
reportPermissions = s2_report_param),
|
|
||||||
edge.ProbeAck(
|
|
||||||
b = probe_bits,
|
|
||||||
reportPermissions = s2_report_param,
|
|
||||||
data = 0.U))
|
|
||||||
|
|
||||||
tl_out.c.valid := s2_release_data_valid
|
tl_out.c.valid := s2_release_data_valid
|
||||||
tl_out.c.bits := nackResponseMessage
|
tl_out.c.bits := nackResponseMessage
|
||||||
@ -465,29 +473,54 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
|
|||||||
probe_bits.address := Cat(s2_victim_tag, s2_req.addr(idxMSB, idxLSB)) << idxLSB
|
probe_bits.address := Cat(s2_victim_tag, s2_req.addr(idxMSB, idxLSB)) << idxLSB
|
||||||
}
|
}
|
||||||
when (s2_probe) {
|
when (s2_probe) {
|
||||||
when (s2_prb_ack_data) { release_state := s_probe_rep_dirty }
|
s1_nack := true
|
||||||
.elsewhen (s2_probe_state.isValid()) { release_state := s_probe_rep_clean }
|
when (s2_meta_error) {
|
||||||
.otherwise {
|
release_state := s_probe_retry
|
||||||
|
}.elsewhen (s2_prb_ack_data) {
|
||||||
|
release_state := s_probe_rep_dirty
|
||||||
|
}.elsewhen (s2_probe_state.isValid()) {
|
||||||
tl_out.c.valid := true
|
tl_out.c.valid := true
|
||||||
release_state := s_probe_rep_miss
|
tl_out.c.bits := cleanReleaseMessage
|
||||||
|
release_state := Mux(releaseDone, s_probe_write_meta, s_probe_rep_clean)
|
||||||
|
}.otherwise {
|
||||||
|
tl_out.c.valid := true
|
||||||
|
s1_nack := !releaseDone
|
||||||
|
release_state := Mux(releaseDone, s_ready, s_probe_rep_miss)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
when (release_state === s_probe_retry) {
|
||||||
|
metaArb.io.in(6).valid := true
|
||||||
|
metaArb.io.in(6).bits.idx := probe_bits.address(idxMSB, idxLSB)
|
||||||
|
when (metaArb.io.in(6).ready) {
|
||||||
|
release_state := s_ready
|
||||||
|
s1_probe := true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
when (release_state === s_probe_rep_miss) {
|
||||||
|
tl_out.c.valid := true
|
||||||
when (releaseDone) { release_state := s_ready }
|
when (releaseDone) { release_state := s_ready }
|
||||||
when (release_state.isOneOf(s_probe_rep_miss, s_probe_rep_clean)) {
|
|
||||||
tl_out.c.valid := true
|
|
||||||
}
|
}
|
||||||
when (release_state.isOneOf(s_probe_rep_clean, s_probe_rep_dirty)) {
|
when (release_state === s_probe_rep_clean) {
|
||||||
tl_out.c.bits := probeResponseMessage
|
tl_out.c.valid := true
|
||||||
|
tl_out.c.bits := cleanReleaseMessage
|
||||||
|
when (releaseDone) { release_state := s_probe_write_meta }
|
||||||
|
}
|
||||||
|
when (release_state === s_probe_rep_dirty) {
|
||||||
|
tl_out.c.bits := dirtyReleaseMessage
|
||||||
when (releaseDone) { release_state := s_probe_write_meta }
|
when (releaseDone) { release_state := s_probe_write_meta }
|
||||||
}
|
}
|
||||||
when (release_state.isOneOf(s_voluntary_writeback, s_voluntary_write_meta)) {
|
when (release_state.isOneOf(s_voluntary_writeback, s_voluntary_write_meta)) {
|
||||||
tl_out.c.bits := voluntaryReleaseMessage
|
if (edge.manager.anySupportAcquireB)
|
||||||
|
tl_out.c.bits := edge.Release(fromSource = 0.U,
|
||||||
|
toAddress = 0.U,
|
||||||
|
lgSize = lgCacheBlockBytes,
|
||||||
|
shrinkPermissions = s2_shrink_param,
|
||||||
|
data = 0.U)._2
|
||||||
newCoh := voluntaryNewCoh
|
newCoh := voluntaryNewCoh
|
||||||
releaseWay := s2_victim_way
|
releaseWay := s2_victim_way
|
||||||
when (releaseDone) { release_state := s_voluntary_write_meta }
|
when (releaseDone) { release_state := s_voluntary_write_meta }
|
||||||
when (tl_out.c.fire() && c_first) { release_ack_wait := true }
|
when (tl_out.c.fire() && c_first) { release_ack_wait := true }
|
||||||
}
|
}
|
||||||
when (s2_probe && !tl_out.c.fire()) { s1_nack := true }
|
|
||||||
tl_out.c.bits.address := probe_bits.address
|
tl_out.c.bits.address := probe_bits.address
|
||||||
tl_out.c.bits.data := s2_data_corrected
|
tl_out.c.bits.data := s2_data_corrected
|
||||||
|
|
||||||
@ -497,12 +530,13 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
|
|||||||
dataArb.io.in(2).bits.wordMask := ~UInt(0, rowBytes / wordBytes)
|
dataArb.io.in(2).bits.wordMask := ~UInt(0, rowBytes / wordBytes)
|
||||||
dataArb.io.in(2).bits.way_en := ~UInt(0, nWays)
|
dataArb.io.in(2).bits.way_en := ~UInt(0, nWays)
|
||||||
|
|
||||||
metaWriteArb.io.in(2).valid := release_state.isOneOf(s_voluntary_write_meta, s_probe_write_meta)
|
metaArb.io.in(4).valid := release_state.isOneOf(s_voluntary_write_meta, s_probe_write_meta)
|
||||||
metaWriteArb.io.in(2).bits.way_en := releaseWay
|
metaArb.io.in(4).bits.write := true
|
||||||
metaWriteArb.io.in(2).bits.idx := tl_out.c.bits.address(idxMSB, idxLSB)
|
metaArb.io.in(4).bits.way_en := releaseWay
|
||||||
metaWriteArb.io.in(2).bits.data.coh := newCoh
|
metaArb.io.in(4).bits.idx := tl_out.c.bits.address(idxMSB, idxLSB)
|
||||||
metaWriteArb.io.in(2).bits.data.tag := tl_out.c.bits.address >> untagBits
|
metaArb.io.in(4).bits.data.coh := newCoh
|
||||||
when (metaWriteArb.io.in(2).fire()) { release_state := s_ready }
|
metaArb.io.in(4).bits.data.tag := tl_out.c.bits.address >> untagBits
|
||||||
|
when (metaArb.io.in(4).fire()) { release_state := s_ready }
|
||||||
|
|
||||||
// cached response
|
// cached response
|
||||||
io.cpu.resp.valid := s2_valid_hit
|
io.cpu.resp.valid := s2_valid_hit
|
||||||
@ -558,9 +592,13 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
|
|||||||
when (s2_correct) { pstore1_storegen_data := s2_data_word_corrected }
|
when (s2_correct) { pstore1_storegen_data := s2_data_word_corrected }
|
||||||
|
|
||||||
// flushes
|
// flushes
|
||||||
|
val resetting = Reg(init=Bool(true))
|
||||||
val flushed = Reg(init=Bool(true))
|
val flushed = Reg(init=Bool(true))
|
||||||
val flushing = Reg(init=Bool(false))
|
val flushing = Reg(init=Bool(false))
|
||||||
val flushCounter = Counter(nSets * nWays)
|
val flushCounter = Reg(init=UInt(nSets * (nWays-1), log2Ceil(nSets * nWays)))
|
||||||
|
val flushCounterNext = flushCounter +& 1
|
||||||
|
val flushDone = (flushCounterNext >> log2Ceil(nSets)) === nWays
|
||||||
|
val flushCounterWrap = flushCounterNext(log2Ceil(nSets)-1, 0)
|
||||||
when (tl_out_a.fire() && !s2_uncached) { flushed := false }
|
when (tl_out_a.fire() && !s2_uncached) { flushed := false }
|
||||||
when (s2_valid_masked && s2_req.cmd === M_FLUSH_ALL) {
|
when (s2_valid_masked && s2_req.cmd === M_FLUSH_ALL) {
|
||||||
io.cpu.s2_nack := !flushed
|
io.cpu.s2_nack := !flushed
|
||||||
@ -568,21 +606,38 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
|
|||||||
flushing := !release_ack_wait && !uncachedInFlight.asUInt.orR
|
flushing := !release_ack_wait && !uncachedInFlight.asUInt.orR
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s1_flush_valid := metaReadArb.io.in(0).fire() && !s1_flush_valid && !s2_flush_valid && release_state === s_ready && !release_ack_wait
|
s1_flush_valid := metaArb.io.in(5).fire() && !s1_flush_valid && !s2_flush_valid_pre_tag_ecc && release_state === s_ready && !release_ack_wait
|
||||||
metaReadArb.io.in(0).valid := flushing
|
metaArb.io.in(5).valid := flushing
|
||||||
metaReadArb.io.in(0).bits.idx := flushCounter.value
|
metaArb.io.in(5).bits.write := false
|
||||||
metaReadArb.io.in(0).bits.way_en := ~UInt(0, nWays)
|
metaArb.io.in(5).bits.idx := flushCounter
|
||||||
|
metaArb.io.in(5).bits.way_en := ~UInt(0, nWays)
|
||||||
|
metaArb.io.in(5).bits.data := metaArb.io.in(4).bits.data
|
||||||
when (flushing) {
|
when (flushing) {
|
||||||
s1_victim_way := flushCounter.value >> log2Up(nSets)
|
s1_victim_way := flushCounter >> log2Up(nSets)
|
||||||
when (s2_flush_valid) {
|
when (s2_flush_valid) {
|
||||||
when (flushCounter.inc()) {
|
flushCounter := flushCounterNext
|
||||||
|
when (flushDone) {
|
||||||
flushed := true
|
flushed := true
|
||||||
|
if (!isPow2(nWays)) flushCounter := flushCounterWrap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
when (flushed && release_state === s_ready && !release_ack_wait) {
|
when (flushed && release_state === s_ready && !release_ack_wait) {
|
||||||
flushing := false
|
flushing := false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
metaArb.io.in(0).valid := resetting
|
||||||
|
metaArb.io.in(0).bits.idx := flushCounter
|
||||||
|
metaArb.io.in(0).bits.write := true
|
||||||
|
metaArb.io.in(0).bits.way_en := ~UInt(0, nWays)
|
||||||
|
metaArb.io.in(0).bits.data.coh := ClientMetadata.onReset
|
||||||
|
metaArb.io.in(0).bits.data.tag := s2_req.addr >> untagBits
|
||||||
|
when (resetting) {
|
||||||
|
flushCounter := flushCounterNext
|
||||||
|
when (flushDone) {
|
||||||
|
resetting := false
|
||||||
|
if (!isPow2(nWays)) flushCounter := flushCounterWrap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// performance events
|
// performance events
|
||||||
io.cpu.perf.acquire := edge.done(tl_out_a)
|
io.cpu.perf.acquire := edge.done(tl_out_a)
|
||||||
|
Loading…
Reference in New Issue
Block a user