diff --git a/uncore/src/main/scala/cache.scala b/uncore/src/main/scala/cache.scala index 75bb9e1f..4adb09a3 100644 --- a/uncore/src/main/scala/cache.scala +++ b/uncore/src/main/scala/cache.scala @@ -338,10 +338,6 @@ class L2DataArray(delay: Int) extends L2HellaCacheModule { io.write.ready := Bool(true) } -class L2SecondaryMissInfo extends TLBundle - with HasTileLinkBeatId - with HasClientTransactionId - class L2HellaCacheBank extends HierarchicalCoherenceAgent with L2HellaCacheParameters { require(isPow2(nSets)) @@ -617,10 +613,7 @@ class L2AcquireTracker(trackerId: Int) extends L2XactTracker { val pending_coh = Reg{ xact_old_meta.coh.clone } // Secondary miss queue - val ignt_q = Module(new Queue(new L2SecondaryMissInfo, nSecondaryMisses))(innerTLParams) - ignt_q.io.enq.bits.client_xact_id := io.iacq().client_xact_id - ignt_q.io.enq.bits.addr_beat := io.iacq().addr_beat - // TODO add ignt.dst <- iacq.src + val ignt_q = Module(new Queue(new SecondaryMissInfo, nSecondaryMisses))(innerTLParams) // State holding progress made on processing this transaction val iacq_data_done = connectIncomingDataBeatCounter(io.inner.acquire) @@ -741,6 +734,12 @@ class L2AcquireTracker(trackerId: Int) extends L2XactTracker { can_merge_iacq_put || can_merge_iacq_get + // Enqueue secondary miss information + ignt_q.io.enq.valid := iacq_data_done + ignt_q.io.enq.bits.client_xact_id := io.iacq().client_xact_id + ignt_q.io.enq.bits.addr_beat := io.iacq().addr_beat + // TODO add ignt.dst <- iacq.src + // Track whether any beats are missing from a PutBlock pending_puts := (pending_puts & dropPendingBitWhenBeatHasData(io.inner.acquire)) @@ -792,22 +791,20 @@ class L2AcquireTracker(trackerId: Int) extends L2XactTracker { addPendingBitWhenBeatHasData(io.inner.release) | addPendingBitWhenBeatHasData(io.outer.grant) | addPendingBitInternal(io.data.resp) - ignt_q.io.enq.valid := iacq_data_done ignt_q.io.deq.ready := ignt_data_done - // Make the Grant message using the data stored in the secondary miss queue io.inner.grant.valid := state === s_busy && ignt_q.io.deq.valid && (!io.ignt().hasData() || pending_ignt_data(ignt_data_idx)) + // Make the Grant message using the data stored in the secondary miss queue io.inner.grant.bits := pending_coh.inner.makeGrant( - dst = xact.client_id, // TODO: ignt_q.io.deq.bits.src - acq = xact, - client_xact_id = ignt_q.io.deq.bits.client_xact_id, + pri = xact, + sec = ignt_q.io.deq.bits, manager_xact_id = UInt(trackerId), - addr_beat = ignt_data_idx, data = Mux(xact.is(Acquire.putAtomicType), amo_result, data_buffer(ignt_data_idx))) + io.inner.grant.bits.addr_beat := ignt_data_idx // override based on outgoing counter val pending_coh_on_ignt = HierarchicalMetadata( pending_coh.inner.onGrant(io.ignt()), diff --git a/uncore/src/main/scala/metadata.scala b/uncore/src/main/scala/metadata.scala index f91035f4..74e410c6 100644 --- a/uncore/src/main/scala/metadata.scala +++ b/uncore/src/main/scala/metadata.scala @@ -3,7 +3,7 @@ package uncore import Chisel._ -// Classes to represent coherence information in clients and managers +/** Base class to represent coherence information in clients and managers */ abstract class CoherenceMetadata extends Bundle { val co = params(TLCoherencePolicy) val id = params(TLId) @@ -15,21 +15,35 @@ abstract class CoherenceMetadata extends Bundle { * memory operations or [[uncore.Probe]] messages. */ class ClientMetadata extends CoherenceMetadata { + /** Actual state information stored in this bundle */ val state = UInt(width = co.clientStateWidth) + /** Metadata equality */ def ===(rhs: ClientMetadata): Bool = this.state === rhs.state def !=(rhs: ClientMetadata): Bool = !this.===(rhs) + /** Is the block's data present in this cache */ def isValid(dummy: Int = 0): Bool = co.isValid(this) - def isHit(cmd: UInt): Bool = co.isHit(cmd, this) - def isMiss(cmd: UInt): Bool = !co.isHit(cmd, this) - def requiresAcquireOnSecondaryMiss(first_cmd: UInt, second_cmd: UInt): Bool = - co.requiresAcquireOnSecondaryMiss(first_cmd, second_cmd, this) - def requiresReleaseOnCacheControl(cmd: UInt): Bool = - co.requiresReleaseOnCacheControl(cmd: UInt, this) + /** Does this cache have permissions on this block sufficient to perform op */ + def isHit(op_code: UInt): Bool = co.isHit(op_code, this) + /** Does this cache lack permissions on this block sufficient to perform op */ + def isMiss(op_code: UInt): Bool = !co.isHit(op_code, this) + /** Does a secondary miss on the block require another Acquire message */ + def requiresAcquireOnSecondaryMiss(first_op: UInt, second_op: UInt): Bool = + co.requiresAcquireOnSecondaryMiss(first_op, second_op, this) + /** Does op require a Release to be made to outer memory */ + def requiresReleaseOnCacheControl(op_code: UInt): Bool = + co.requiresReleaseOnCacheControl(op_code: UInt, this) + /** Does an eviction require a Release to be made to outer memory */ def requiresVoluntaryWriteback(dummy: Int = 0): Bool = co.requiresReleaseOnCacheControl(M_FLUSH, this) + /** Constructs an Acquire message based on this metdata and a memory operation + * + * @param client_xact_id client's transaction id + * @param addr_block address of the cache block + * @param op_code a memory operation from [[uncore.MemoryOpConstants]] + */ def makeAcquire( client_xact_id: UInt, addr_block: UInt, @@ -43,6 +57,13 @@ class ClientMetadata extends CoherenceMetadata { { case TLId => id }) } + /** Constructs a Release message based on this metadata on an eviction + * + * @param client_xact_id client's transaction id + * @param addr_block address of the cache block + * @param addr_beat sub-block address (which beat) + * @param data data being written back + */ def makeVoluntaryWriteback( client_xact_id: UInt, addr_block: UInt, @@ -57,6 +78,12 @@ class ClientMetadata extends CoherenceMetadata { data = data), { case TLId => id }) } + /** Constructs a Release message based on this metadata and a [[uncore.Probe]] + * + * @param the incoming [[uncore.Probe]] + * @param addr_beat sub-block address (which beat) + * @param data data being released + */ def makeRelease( prb: Probe, addr_beat: UInt = UInt(0), @@ -70,16 +97,37 @@ class ClientMetadata extends CoherenceMetadata { data = data), { case TLId => id }) } + /** New metadata after receiving a [[uncore.Grant]] + * + * @param incoming the incoming [[uncore.Grant]] + * @param pending the mem op that triggered this transaction + */ def onGrant(incoming: Grant, pending: UInt): ClientMetadata = Bundle(co.clientMetadataOnGrant(incoming, pending, this), { case TLId => id }) + + /** New metadata after receiving a [[uncore.Probe]] + * + * @param incoming the incoming [[uncore.Probe]] + */ def onProbe(incoming: Probe): ClientMetadata = Bundle(co.clientMetadataOnProbe(incoming, this), { case TLId => id }) - def onHit(cmd: UInt): ClientMetadata = - Bundle(co.clientMetadataOnHit(cmd, this), { case TLId => id }) - def onCacheControl(cmd: UInt): ClientMetadata = - Bundle(co.clientMetadataOnCacheControl(cmd, this), { case TLId => id }) + + /** New metadata after a op_code hits this block + * + * @param op_code a memory operation from [[uncore.MemoryOpConstants]] + */ + def onHit(op_code: UInt): ClientMetadata = + Bundle(co.clientMetadataOnHit(op_code, this), { case TLId => id }) + + /** New metadata after receiving a [[uncore.Probe]] + * + * @param op_code a memory operation from [[uncore.MemoryOpConstants]] + */ + def onCacheControl(op_code: UInt): ClientMetadata = + Bundle(co.clientMetadataOnCacheControl(op_code, this), { case TLId => id }) } +/** Factories for ClientMetadata, including on reset */ object ClientMetadata { def apply(state: UInt) = { val meta = new ClientMetadata @@ -89,33 +137,64 @@ object ClientMetadata { def onReset = new ClientMetadata().co.clientMetadataOnReset } -/* The ManagerMetadata stores manager-side information about the status - of a cache block, including whether it has any known sharers. Its - API can be used to create Probe and Grant TileLink messages. -*/ +/** Stores manager-side information about the status + * of a cache block, including whether it has any known sharers. + * + * Its API can be used to create [[uncore.Probe]] and [[uncore.Grant]] messages. + */ class ManagerMetadata extends CoherenceMetadata { + // Currently no coherence policies assume manager-side state information // val state = UInt(width = co.masterStateWidth) TODO: Fix 0-width wires in Chisel + + /** The directory information for this block */ val sharers = UInt(width = co.dir.width) + /** Metadata equality */ def ===(rhs: ManagerMetadata): Bool = //this.state === rhs.state && TODO: Fix 0-width wires in Chisel this.sharers === rhs.sharers def !=(rhs: ManagerMetadata): Bool = !this.===(rhs) - def full(dummy: Int = 0) = co.dir.full(this.sharers) + /** Converts the directory info into an N-hot sharer bitvector (i.e. full representation) */ + def full(dummy: Int = 0): UInt = co.dir.full(this.sharers) + + /** Does this [[uncore.Acquire]] require [[uncore.Probes]] to be sent */ def requiresProbes(acq: Acquire): Bool = co.requiresProbes(acq, this) - def requiresProbes(cmd: UInt): Bool = co.requiresProbes(cmd, this) + /** Does this memory op require [[uncore.Probes]] to be sent */ + def requiresProbes(op_code: UInt): Bool = co.requiresProbes(op_code, this) + /** Does an eviction require [[uncore.Probes]] to be sent */ def requiresProbesOnVoluntaryWriteback(dummy: Int = 0): Bool = co.requiresProbes(M_FLUSH, this) - def makeProbe(dst: UInt, cmd: UInt, addr_block: UInt): ProbeToDst = - Bundle(Probe(dst, co.getProbeType(cmd, this), addr_block), { case TLId => id }) - + /** Construct an appropriate [[uncore.ProbeToDst]] for a given [[uncore.Acquire]] + * + * @param dst Destination client id for this Probe + * @param acq Acquire message triggering this Probe + */ def makeProbe(dst: UInt, acq: Acquire): ProbeToDst = Bundle(Probe(dst, co.getProbeType(acq, this), acq.addr_block), { case TLId => id }) + /** Construct an appropriate [[uncore.ProbeToDst]] for a given mem op + * + * @param dst Destination client id for this Probe + * @param op_code memory operation triggering this Probe + * @param addr_block address of the cache block being probed + */ + def makeProbe(dst: UInt, op_code: UInt, addr_block: UInt): ProbeToDst = + Bundle(Probe(dst, co.getProbeType(op_code, this), addr_block), { case TLId => id }) + + /** Construct an appropriate [[uncore.ProbeToDst]] for an eviction + * + * @param dst Destination client id for this Probe + * @param addr_block address of the cache block being probed prior to eviction + */ def makeProbeForVoluntaryWriteback(dst: UInt, addr_block: UInt): ProbeToDst = makeProbe(dst, M_FLUSH, addr_block) + /** Construct an appropriate [[uncore.GrantToDst]] to acknowledge an [[uncore.Release]] + * + * @param rel Release message being acknowledged by this Grant + * @param manager_xact_id manager's transaction id + */ def makeGrant(rel: ReleaseFromSrc, manager_xact_id: UInt): GrantToDst = { Bundle(Grant( dst = rel.client_id, @@ -125,6 +204,15 @@ class ManagerMetadata extends CoherenceMetadata { manager_xact_id = manager_xact_id), { case TLId => id }) } + /** Construct an appropriate [[uncore.GrantToDst]] to respond to an [[uncore.Acquire]] + * + * May contain single or multiple beats of data, or just be a permissions upgrade. + * + * @param acq Acquire message being responded to by this Grant + * @param manager_xact_id manager's transaction id + * @param addr_beat beat id of the data + * @param data data being refilled to the original requestor + */ def makeGrant( acq: AcquireFromSrc, manager_xact_id: UInt, @@ -142,26 +230,42 @@ class ManagerMetadata extends CoherenceMetadata { data = data), { case TLId => id }) } + /** Construct an [[uncore.GrantToDst]] to respond to an [[uncore.Acquire]] with some overrides + * + * Used to respond to secondary misses merged into this transaction. + * May contain single or multiple beats of data. + * + * @param pri Primary miss's Acquire message, used to get g_type and dst + * @param sec Secondary miss info, used to get beat and client_xact_id + * @param manager_xact_id manager's transaction id + * @param data data being refilled to the original requestor + */ def makeGrant( - dst: UInt, - acq: AcquireFromSrc, - client_xact_id: UInt, + pri: AcquireFromSrc, + sec: SecondaryMissInfo, manager_xact_id: UInt, - addr_beat: UInt, data: UInt): GrantToDst = { - val g = makeGrant(acq, manager_xact_id, addr_beat, data) - g.client_id := dst - g.client_xact_id := client_xact_id + val g = makeGrant(pri, manager_xact_id, sec.addr_beat, data) + g.client_xact_id := sec.client_xact_id g } + /** New metadata after receiving a [[uncore.ReleaseFromSrc]] + * + * @param incoming the incoming [[uncore.ReleaseFromSrc]] + */ def onRelease(incoming: ReleaseFromSrc): ManagerMetadata = Bundle(co.managerMetadataOnRelease(incoming, incoming.client_id, this), { case TLId => id }) + /** New metadata after sending a [[uncore.GrantToDst]] + * + * @param outgoing the outgoing [[uncore.GrantToDst]] + */ def onGrant(outgoing: GrantToDst): ManagerMetadata = Bundle(co.managerMetadataOnGrant(outgoing, outgoing.client_id, this), { case TLId => id }) } +/** Factories for ManagerMetadata, including on reset */ object ManagerMetadata { def apply(sharers: UInt, state: UInt = UInt(width = 0)) = { val meta = new ManagerMetadata @@ -178,10 +282,14 @@ object ManagerMetadata { def onReset = new ManagerMetadata().co.managerMetadataOnReset } -/* HierarchicalMetadata is used in a cache in a multi-level memory hierarchy - that is a Manager with respect to some inner caches and a Client with - respect to some outer cache. -*/ +/** HierarchicalMetadata is used in a cache in a multi-level memory hierarchy + * that is a manager with respect to some inner caches and a client with + * respect to some outer cache. + * + * This class makes use of two different sets of TileLink parameters, which are + * applied by contextually mapping [[uncore.TLId]] to one of + * [[uncore.InnerTLId]] or [[uncore.OuterTLId]]. + */ class HierarchicalMetadata extends CoherenceMetadata { val inner: ManagerMetadata = Bundle(new ManagerMetadata, {case TLId => params(InnerTLId)}) val outer: ClientMetadata = Bundle(new ClientMetadata, {case TLId => params(OuterTLId)}) @@ -190,6 +298,7 @@ class HierarchicalMetadata extends CoherenceMetadata { def !=(rhs: HierarchicalMetadata): Bool = !this.===(rhs) } +/** Factories for HierarchicalMetadata, including on reset */ object HierarchicalMetadata { def apply(inner: ManagerMetadata, outer: ClientMetadata): HierarchicalMetadata = { val m = new HierarchicalMetadata @@ -200,5 +309,7 @@ object HierarchicalMetadata { def onReset: HierarchicalMetadata = apply(ManagerMetadata.onReset, ClientMetadata.onReset) } +/** Identifies the TLId of the inner network in a hierarchical cache controller */ case object InnerTLId extends Field[String] +/** Identifies the TLId of the outer network in a hierarchical cache controller */ case object OuterTLId extends Field[String] diff --git a/uncore/src/main/scala/tilelink.scala b/uncore/src/main/scala/tilelink.scala index b759d48b..1c1c2bb4 100644 --- a/uncore/src/main/scala/tilelink.scala +++ b/uncore/src/main/scala/tilelink.scala @@ -785,6 +785,13 @@ class ClientTileLinkIOWrapper extends TLModule { io.out.release.valid := Bool(false) } +/** Used to track metadata for transactions where multiple secondary misses have been merged + * and handled by a single transaction tracker. + */ +class SecondaryMissInfo extends TLBundle // TODO: add a_type to merge e.g. Get+GetBlocks, and/or HasClientId + with HasTileLinkBeatId + with HasClientTransactionId + /** A helper module that automatically issues [[uncore.Finish]] messages in repsonse * to [[uncore.Grant]] that it receives from a manager and forwards to a client */