Merge pull request #1036 from freechipsproject/l1-cover
Add some covers for L1 memory system
This commit is contained in:
commit
50429daef4
@ -9,6 +9,8 @@ import freechips.rocketchip.coreplex.{RationalCrossing, RocketCrossing, RocketTi
|
|||||||
import freechips.rocketchip.diplomacy.{AddressSet, RegionType}
|
import freechips.rocketchip.diplomacy.{AddressSet, RegionType}
|
||||||
import freechips.rocketchip.tilelink._
|
import freechips.rocketchip.tilelink._
|
||||||
import freechips.rocketchip.util._
|
import freechips.rocketchip.util._
|
||||||
|
import freechips.rocketchip.util.property._
|
||||||
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
import TLMessages._
|
import TLMessages._
|
||||||
|
|
||||||
class DCacheErrors(implicit p: Parameters) extends L1HellaCacheBundle()(p)
|
class DCacheErrors(implicit p: Parameters) extends L1HellaCacheBundle()(p)
|
||||||
@ -325,6 +327,9 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
|
|||||||
val pstore_drain_structural = pstore1_valid && pstore2_valid && ((s1_valid && s1_write) || pstore1_rmw)
|
val pstore_drain_structural = pstore1_valid && pstore2_valid && ((s1_valid && s1_write) || pstore1_rmw)
|
||||||
val pstore_drain_opportunistic = !(io.cpu.req.valid && s0_needsRead)
|
val pstore_drain_opportunistic = !(io.cpu.req.valid && s0_needsRead)
|
||||||
val pstore_drain_on_miss = releaseInFlight || (s2_valid && !s2_valid_hit && !s2_valid_uncached_pending)
|
val pstore_drain_on_miss = releaseInFlight || (s2_valid && !s2_valid_hit && !s2_valid_uncached_pending)
|
||||||
|
ccover(pstore_drain_structural, "STORE_STRUCTURAL_HAZARD", "D$ read-modify-write structural hazard")
|
||||||
|
ccover(pstore1_valid && pstore_drain_on_miss, "STORE_DRAIN_ON_MISS", "D$ store buffer drain on miss")
|
||||||
|
ccover(s1_valid_not_nacked && s1_waw_hazard, "WAW_HAZARD", "D$ write-after-write hazard")
|
||||||
val pstore_drain = !pstore1_merge &&
|
val pstore_drain = !pstore1_merge &&
|
||||||
(Bool(usingRMW) && pstore_drain_structural ||
|
(Bool(usingRMW) && pstore_drain_structural ||
|
||||||
(((pstore1_valid && !pstore1_rmw) || pstore2_valid) && (pstore_drain_opportunistic || pstore_drain_on_miss)))
|
(((pstore1_valid && !pstore1_rmw) || pstore2_valid) && (pstore_drain_opportunistic || pstore_drain_on_miss)))
|
||||||
@ -350,14 +355,15 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
|
|||||||
}
|
}
|
||||||
mask
|
mask
|
||||||
}
|
}
|
||||||
s2_store_merge := {
|
s2_store_merge := (if (eccBytes == 1) false.B else {
|
||||||
|
ccover(pstore1_merge, "STORE_MERGED", "D$ store merged")
|
||||||
// only merge stores to ECC granules that are already stored-to, to avoid
|
// only merge stores to ECC granules that are already stored-to, to avoid
|
||||||
// WAW hazards
|
// WAW hazards
|
||||||
val wordMatch = (eccMask(pstore2_storegen_mask) | ~eccMask(pstore1_mask)).andR
|
val wordMatch = (eccMask(pstore2_storegen_mask) | ~eccMask(pstore1_mask)).andR
|
||||||
val idxMatch = s2_req.addr(untagBits-1, log2Ceil(wordBytes)) === pstore2_addr(untagBits-1, log2Ceil(wordBytes))
|
val idxMatch = s2_req.addr(untagBits-1, log2Ceil(wordBytes)) === pstore2_addr(untagBits-1, log2Ceil(wordBytes))
|
||||||
val tagMatch = (s2_hit_way & pstore2_way).orR
|
val tagMatch = (s2_hit_way & pstore2_way).orR
|
||||||
Bool(eccBytes > 1) && pstore2_valid && wordMatch && idxMatch && tagMatch
|
pstore2_valid && wordMatch && idxMatch && tagMatch
|
||||||
}
|
})
|
||||||
dataArb.io.in(0).valid := pstore_drain
|
dataArb.io.in(0).valid := pstore_drain
|
||||||
dataArb.io.in(0).bits.write := true
|
dataArb.io.in(0).bits.write := true
|
||||||
dataArb.io.in(0).bits.addr := Mux(pstore2_valid, pstore2_addr, pstore1_addr)
|
dataArb.io.in(0).bits.addr := Mux(pstore2_valid, pstore2_addr, pstore1_addr)
|
||||||
@ -374,7 +380,10 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
|
|||||||
(pstore1_valid && s1Depends(pstore1_addr, pstore1_mask)) ||
|
(pstore1_valid && s1Depends(pstore1_addr, pstore1_mask)) ||
|
||||||
(pstore2_valid && s1Depends(pstore2_addr, pstore2_storegen_mask))
|
(pstore2_valid && s1Depends(pstore2_addr, pstore2_storegen_mask))
|
||||||
val s1_raw_hazard = s1_read && s1_hazard
|
val s1_raw_hazard = s1_read && s1_hazard
|
||||||
s1_waw_hazard := Bool(eccBytes > 1) && s1_write && (s1_hazard || needsRead(s1_req) && !s1_did_read)
|
s1_waw_hazard := (if (eccBytes == 1) false.B else {
|
||||||
|
ccover(s1_valid_not_nacked && s1_waw_hazard, "WAW_HAZARD", "D$ write-after-write hazard")
|
||||||
|
s1_write && (s1_hazard || needsRead(s1_req) && !s1_did_read)
|
||||||
|
})
|
||||||
when (s1_valid && s1_raw_hazard) { s1_nack := true }
|
when (s1_valid && s1_raw_hazard) { s1_nack := true }
|
||||||
|
|
||||||
// Prepare a TileLink request message that initiates a transaction
|
// Prepare a TileLink request message that initiates a transaction
|
||||||
@ -384,6 +393,7 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
|
|||||||
val a_size = mtSize(s2_req.typ)
|
val a_size = mtSize(s2_req.typ)
|
||||||
val a_data = Fill(beatWords, pstore1_data)
|
val a_data = Fill(beatWords, pstore1_data)
|
||||||
val acquire = if (edge.manager.anySupportAcquireB) {
|
val acquire = if (edge.manager.anySupportAcquireB) {
|
||||||
|
ccover(tl_out.b.valid && !tl_out.b.ready, "BLOCK_B", "D$ B-channel blocked")
|
||||||
edge.AcquireBlock(UInt(0), acquire_address, lgCacheBlockBytes, s2_grow_param)._2 // Cacheability checked by tlb
|
edge.AcquireBlock(UInt(0), acquire_address, lgCacheBlockBytes, s2_grow_param)._2 // Cacheability checked by tlb
|
||||||
} else {
|
} else {
|
||||||
Wire(new TLBundleA(edge.bundle))
|
Wire(new TLBundleA(edge.bundle))
|
||||||
@ -513,6 +523,7 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
|
|||||||
blockUncachedGrant := !dataArb.io.in(1).ready
|
blockUncachedGrant := !dataArb.io.in(1).ready
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ccover(tl_out.d.valid && !tl_out.d.ready, "BLOCK_D", "D$ D-channel blocked")
|
||||||
|
|
||||||
// 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)
|
||||||
@ -629,6 +640,7 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
|
|||||||
val s1_xcpt_valid = tlb.io.req.valid && !s1_nack
|
val s1_xcpt_valid = tlb.io.req.valid && !s1_nack
|
||||||
val s1_xcpt = tlb.io.resp
|
val s1_xcpt = tlb.io.resp
|
||||||
io.cpu.s2_xcpt := Mux(RegNext(s1_xcpt_valid), RegEnable(s1_xcpt, s1_valid_not_nacked), 0.U.asTypeOf(s1_xcpt))
|
io.cpu.s2_xcpt := Mux(RegNext(s1_xcpt_valid), RegEnable(s1_xcpt, s1_valid_not_nacked), 0.U.asTypeOf(s1_xcpt))
|
||||||
|
ccover(s2_valid_pre_xcpt && s2_tl_error, "D_ERROR_REPORTED", "D$ reported TL error to processor")
|
||||||
when (s2_valid_pre_xcpt && s2_tl_error) {
|
when (s2_valid_pre_xcpt && s2_tl_error) {
|
||||||
assert(!s2_valid_hit && !s2_uncached)
|
assert(!s2_valid_hit && !s2_uncached)
|
||||||
when (s2_write) { io.cpu.s2_xcpt.ae.st := true }
|
when (s2_write) { io.cpu.s2_xcpt.ae.st := true }
|
||||||
@ -755,6 +767,9 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
|
|||||||
}
|
}
|
||||||
io.errors.bus.valid := tl_out.d.fire() && tl_out.d.bits.error
|
io.errors.bus.valid := tl_out.d.fire() && tl_out.d.bits.error
|
||||||
io.errors.bus.bits := Mux(grantIsCached, s2_req.addr >> idxLSB << idxLSB, 0.U)
|
io.errors.bus.bits := Mux(grantIsCached, s2_req.addr >> idxLSB << idxLSB, 0.U)
|
||||||
|
|
||||||
|
ccover(io.errors.bus.valid && grantIsCached, "D_ERROR_CACHED", "D$ D-channel error, cached")
|
||||||
|
ccover(io.errors.bus.valid && !grantIsCached, "D_ERROR_UNCACHED", "D$ D-channel error, uncached")
|
||||||
}
|
}
|
||||||
|
|
||||||
def encodeData(x: UInt) = x.grouped(eccBits).map(dECC.encode(_)).asUInt
|
def encodeData(x: UInt) = x.grouped(eccBits).map(dECC.encode(_)).asUInt
|
||||||
@ -766,4 +781,7 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
|
|||||||
def needsRead(req: HellaCacheReq) =
|
def needsRead(req: HellaCacheReq) =
|
||||||
isRead(req.cmd) ||
|
isRead(req.cmd) ||
|
||||||
(isWrite(req.cmd) && (req.cmd === M_PWR || mtSize(req.typ) < log2Ceil(eccBytes)))
|
(isWrite(req.cmd) && (req.cmd === M_PWR || mtSize(req.typ) < log2Ceil(eccBytes)))
|
||||||
|
|
||||||
|
def ccover(cond: Bool, label: String, desc: String)(implicit sourceInfo: SourceInfo) =
|
||||||
|
cover(cond, s"DCACHE_$label", "MemorySystem;;" + desc)
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,8 @@ import freechips.rocketchip.diplomacy._
|
|||||||
import freechips.rocketchip.tile._
|
import freechips.rocketchip.tile._
|
||||||
import freechips.rocketchip.tilelink._
|
import freechips.rocketchip.tilelink._
|
||||||
import freechips.rocketchip.util._
|
import freechips.rocketchip.util._
|
||||||
|
import freechips.rocketchip.util.property._
|
||||||
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
|
|
||||||
case class ICacheParams(
|
case class ICacheParams(
|
||||||
nSets: Int = 64,
|
nSets: Int = 64,
|
||||||
@ -326,6 +328,11 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
|
|||||||
tl.b.valid := false
|
tl.b.valid := false
|
||||||
tl.c.ready := true
|
tl.c.ready := true
|
||||||
tl.e.ready := true
|
tl.e.ready := true
|
||||||
|
|
||||||
|
ccover(s0_valid && s1_slaveValid, "CONCURRENT_ITIM_ACCESS_1", "ITIM accessed, then I$ accessed next cycle")
|
||||||
|
ccover(s0_valid && s2_slaveValid, "CONCURRENT_ITIM_ACCESS_2", "ITIM accessed, then I$ accessed two cycles later")
|
||||||
|
ccover(tl.d.valid && !tl.d.ready, "ITIM_D_STALL", "ITIM response blocked by D-channel")
|
||||||
|
ccover(tl_out.d.valid && !tl_out.d.ready, "ITIM_BLOCK_D", "D-channel blocked by ITIM access")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,6 +365,11 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
|
|||||||
lgSize = lgCacheBlockBytes,
|
lgSize = lgCacheBlockBytes,
|
||||||
param = TLHints.PREFETCH_READ)._2
|
param = TLHints.PREFETCH_READ)._2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ccover(send_hint && !tl_out.a.ready, "PREFETCH_A_STALL", "I$ prefetch blocked by A-channel")
|
||||||
|
ccover(refill_valid && (tl_out.d.fire() && !refill_one_beat), "PREFETCH_D_BEFORE_MISS_D", "I$ prefetch resolves before miss")
|
||||||
|
ccover(!refill_valid && (tl_out.d.fire() && !refill_one_beat), "PREFETCH_D_AFTER_MISS_D", "I$ prefetch resolves after miss")
|
||||||
|
ccover(tl_out.a.fire() && hint_outstanding, "PREFETCH_D_AFTER_MISS_A", "I$ prefetch resolves after second miss")
|
||||||
}
|
}
|
||||||
tl_out.b.ready := Bool(true)
|
tl_out.b.ready := Bool(true)
|
||||||
tl_out.c.valid := Bool(false)
|
tl_out.c.valid := Bool(false)
|
||||||
@ -369,4 +381,10 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
|
|||||||
when (refill_done) { refill_valid := false.B}
|
when (refill_done) { refill_valid := false.B}
|
||||||
|
|
||||||
io.perf.acquire := refill_fire
|
io.perf.acquire := refill_fire
|
||||||
|
|
||||||
|
ccover(!send_hint && (tl_out.a.valid && !tl_out.a.ready), "MISS_A_STALL", "I$ miss blocked by A-channel")
|
||||||
|
ccover(invalidate && refill_valid, "FLUSH_DURING_MISS", "I$ flushed during miss")
|
||||||
|
|
||||||
|
def ccover(cond: Bool, label: String, desc: String)(implicit sourceInfo: SourceInfo) =
|
||||||
|
cover(cond, s"ICACHE_$label", "MemorySystem;;" + desc)
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,8 @@ import freechips.rocketchip.coreplex.CacheBlockBytes
|
|||||||
import freechips.rocketchip.tile._
|
import freechips.rocketchip.tile._
|
||||||
import freechips.rocketchip.tilelink._
|
import freechips.rocketchip.tilelink._
|
||||||
import freechips.rocketchip.util._
|
import freechips.rocketchip.util._
|
||||||
|
import freechips.rocketchip.util.property._
|
||||||
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
import scala.collection.mutable.ListBuffer
|
import scala.collection.mutable.ListBuffer
|
||||||
|
|
||||||
class PTWReq(implicit p: Parameters) extends CoreBundle()(p) {
|
class PTWReq(implicit p: Parameters) extends CoreBundle()(p) {
|
||||||
@ -131,6 +133,9 @@ class PTW(n: Int)(implicit edge: TLEdgeOut, p: Parameters) extends CoreModule()(
|
|||||||
when (hit && state === s_req) { plru.access(OHToUInt(hits)) }
|
when (hit && state === s_req) { plru.access(OHToUInt(hits)) }
|
||||||
when (io.dpath.sfence.valid && !io.dpath.sfence.bits.rs1) { valid := 0 }
|
when (io.dpath.sfence.valid && !io.dpath.sfence.bits.rs1) { valid := 0 }
|
||||||
|
|
||||||
|
for (i <- 0 until pgLevels-1)
|
||||||
|
ccover(hit && state === s_req && count === i, s"PTE_CACHE_HIT_L$i", s"PTE cache hit, level $i")
|
||||||
|
|
||||||
(hit && count < pgLevels-1, Mux1H(hits, data))
|
(hit && count < pgLevels-1, Mux1H(hits, data))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,6 +197,8 @@ class PTW(n: Int)(implicit edge: TLEdgeOut, p: Parameters) extends CoreModule()(
|
|||||||
s2_pte.g := s2_g
|
s2_pte.g := s2_g
|
||||||
s2_pte.v := true
|
s2_pte.v := true
|
||||||
|
|
||||||
|
ccover(s2_hit, "L2_TLB_HIT", "L2 TLB hit")
|
||||||
|
|
||||||
(s2_hit, s2_valid && s2_valid_bit, s2_pte, Some(ram))
|
(s2_hit, s2_valid && s2_valid_bit, s2_pte, Some(ram))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -271,6 +278,12 @@ class PTW(n: Int)(implicit edge: TLEdgeOut, p: Parameters) extends CoreModule()(
|
|||||||
r_pte := l2_pte
|
r_pte := l2_pte
|
||||||
count := pgLevels-1
|
count := pgLevels-1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ccover(io.mem.s2_nack, "NACK", "D$ nacked page-table access")
|
||||||
|
ccover(io.mem.resp.valid && io.mem.s2_xcpt.ae.ld, "AE", "access exception while walking page table")
|
||||||
|
|
||||||
|
def ccover(cond: Bool, label: String, desc: String)(implicit sourceInfo: SourceInfo) =
|
||||||
|
cover(cond, s"PTW_$label", "MemorySystem;;" + desc)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Mix-ins for constructing tiles that might have a PTW */
|
/** Mix-ins for constructing tiles that might have a PTW */
|
||||||
|
@ -12,6 +12,8 @@ import freechips.rocketchip.diplomacy.RegionType
|
|||||||
import freechips.rocketchip.tile.{XLen, CoreModule, CoreBundle}
|
import freechips.rocketchip.tile.{XLen, CoreModule, CoreBundle}
|
||||||
import freechips.rocketchip.tilelink._
|
import freechips.rocketchip.tilelink._
|
||||||
import freechips.rocketchip.util._
|
import freechips.rocketchip.util._
|
||||||
|
import freechips.rocketchip.util.property._
|
||||||
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
|
|
||||||
case object PgLevels extends Field[Int](2)
|
case object PgLevels extends Field[Int](2)
|
||||||
case object ASIdBits extends Field[Int](0)
|
case object ASIdBits extends Field[Int](0)
|
||||||
@ -26,7 +28,6 @@ class SFenceReq(implicit p: Parameters) extends CoreBundle()(p) {
|
|||||||
class TLBReq(lgMaxSize: Int)(implicit p: Parameters) extends CoreBundle()(p) {
|
class TLBReq(lgMaxSize: Int)(implicit p: Parameters) extends CoreBundle()(p) {
|
||||||
val vaddr = UInt(width = vaddrBitsExtended)
|
val vaddr = UInt(width = vaddrBitsExtended)
|
||||||
val passthrough = Bool()
|
val passthrough = Bool()
|
||||||
val instruction = Bool()
|
|
||||||
val sfence = Valid(new SFenceReq)
|
val sfence = Valid(new SFenceReq)
|
||||||
val size = UInt(width = log2Ceil(lgMaxSize + 1))
|
val size = UInt(width = log2Ceil(lgMaxSize + 1))
|
||||||
val cmd = Bits(width = M_SZ)
|
val cmd = Bits(width = M_SZ)
|
||||||
@ -263,5 +264,17 @@ class TLB(instruction: Boolean, lgMaxSize: Int, nEntries: Int)(implicit edge: TL
|
|||||||
when (multipleHits) {
|
when (multipleHits) {
|
||||||
valid := 0
|
valid := 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ccover(io.ptw.req.fire(), "MISS", "TLB miss")
|
||||||
|
ccover(io.ptw.req.valid && !io.ptw.req.ready, "PTW_STALL", "TLB miss, but PTW busy")
|
||||||
|
ccover(state === s_wait_invalidate, "SFENCE_DURING_REFILL", "flush TLB during TLB refill")
|
||||||
|
ccover(sfence && !io.req.bits.sfence.bits.rs1 && !io.req.bits.sfence.bits.rs2, "SFENCE_ALL", "flush TLB")
|
||||||
|
ccover(sfence && !io.req.bits.sfence.bits.rs1 && io.req.bits.sfence.bits.rs2, "SFENCE_ASID", "flush TLB ASID")
|
||||||
|
ccover(sfence && io.req.bits.sfence.bits.rs1 && !io.req.bits.sfence.bits.rs2, "SFENCE_LINE", "flush TLB line")
|
||||||
|
ccover(sfence && io.req.bits.sfence.bits.rs1 && io.req.bits.sfence.bits.rs2, "SFENCE_LINE_ASID", "flush TLB line/ASID")
|
||||||
|
ccover(multipleHits, "MULTIPLE_HITS", "Two matching translations in TLB")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def ccover(cond: Bool, label: String, desc: String)(implicit sourceInfo: SourceInfo) =
|
||||||
|
cover(cond, s"${if (instruction) "I" else "D"}TLB_$label", "MemorySystem;;" + desc)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user