CodeAnotomy on TL Broadcast Hub #3072
DecodeTheEncoded
started this conversation in
Show and tell
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
The broadcast hub is the builtin cache coherence manager of RockectChip if there is no l2 cache(for example, the si-five inclusive cache) is present in the system. It uses snooping scheme instead of directory to maintain cache coherence among different clients, although you can implement a directory based scheme using the scaffolding
ProbeFilter
by storing directory info there.The bird view of broadcast hub is pretty straightforward. When an original request comes from one client at channel A, the broadcast hub should probe all other possible clients to let them drop the permission(more precisely, the expected permission the broadcast hub wants a specific client to change to after accepting an A-channel message is determined by
probe_perms
, normallytoN
is expected, but for A channel messages that does not imply a write op, it'stoB
meaning that probed client can read the specific cache block) or dirty data they already possessed. After all other clients respond to the probe request withprobeAck
orprobeAckData
, the original A channel message is good to go, and that A channel message will flow downwards to lower memory hierarchy. When the D channel response comes back, and is sent back to the initiator(sent_d
), unless that D response needs to have an E channel ack(got_e
), this marks end of an A-channel transaction. The broadcast hub has configurable number oftracker
sub-modules, and eachtracker
traces whether all probes has been done for an initiated A channel transaction so that it can flow that A channel message downwards(io.out_a.valid
oftracker
), each tracker is identified by thesource
(from which client) andline
(to which cache block) pair fields, thesource
is used to route a downward D-channel response(d_trackerOH
) to that tracker while theline
is used to route C-channel probeAcks(c_trackerOH
). There are some detailed insights to note here:Since broadcast hub is the lowest cache coherent layer, therefore some TL-C message needs to be converted to TL-UH ones. Specifically, the tracker module converts every
val acquire = opcode === TLMessages.AcquireBlock || opcode === TLMessages.AcquirePerm
messages toTLMessages.Get
and all other A-channel messages are bypassed:What's worth noting here is that the tracker also add extra MSBs to the A channel source field:
io.out_a.bits.source := Cat(Mux(acquire, transform, PASS), source)
. Since all A channelAcquire
are converted toGet
, therefore the available messages coming from out.d channel are allAccessAck(Data)
(and of courseHIntAck
forHint
messages), consequently we need to differ differentAccessAck
s so that we know one AccessAck is actually responding to previous Acquire so that we can sendGrantAck
back to the client instead ofAccessAck
.When a probed client has dirty data and therefore sends ProbeAckData to the broadcast hub, the broadcast hub will simply just
put
that dirty data back to lower memory hierarchy, therefore initiate an out A channel transaction. This is also true for the voluntary giving away of data for a specific client, if a client initiates ReleaseData, the broadcast hub willput
that block back by initiating thePUT
in out channel A. This brings complexity of distinguishing different D channel responses, since some of theAccessAck
may be responding to theProbeAckData
orReleaseData
, and therefore needs further process, see code below:The bits added to the
putfull.bits.source
isval put_what = Mux(c_releasedata, TRANSFORM_B, DROP)
. With this info added, we can exactly tell what specifically D channel responseAccessAck
is for:out.d.bits.source
(d_what
) areDROP
, meaning that thisAccessAck
is responding to thePut
initiated byProbeAckData
. Since theProbeAckData
doesn't need response, therefore thisAccessAck
should be literally dropped.d_what
istrue.B
(TRANSFORM_B
orTRANSFORM_T
), it means this D response is for aGet
that itself converted from an originalAcquire
, or a PUT that originates from aReleaseData
, Ack infos should be sent back to the client under both these two scenarios. ForReleaseData
case, it'sReleaseAck
, while forAcquire
, it'sGrantData
. The difference between these twoAccessAck
s is thatAccessAck
forAcquire
will haved_hasData
asserted.My confusion on code above is if the original A channel transaction is
AcquirePerm
, the 2MSBs ofout.d.bits.source
isTRANSFORM_B
orTRANSFORM_T
(in tracker logic:val transform = Mux(shared, TRANSFORM_B, TRANSFORM_T)
), and thed_hasData
isfalse.B
, fromd_normal.bits.opcode := Mux(d_hasData, TLMessages.GrantData, TLMessages.ReleaseAck)
, seems that the ack info sent back to client isTLMessages.ReleaseAck
instead of theTLMessages.Grant
, this is clearly wrong. Am I miss something here?Also note that the data-free version of
ProbeAck
andRelease
will not initiate any out A channel transactions. ThatProbeAck
will only cause the corresponding tracker's probe counter decremented. TheRelease
however needs to initiate aReleaseAck
back to the client according to the Tilelink protocol. It's wroth noting that theProbeAckData
will only decrement the probe counter whenAccessAck
for thatProbeAckData
is received(whenprobedack
is asserted), while theProbeAck
decrements the counter immediately(fbfa15e)Since the
Release
will combinationally cause the in.D channelReleaseAck
being initiated and Release event is somehow async to the out.D channel response(which will combinationally causeGrantData
orReleaseAck
in in.D channel being initiated), it's necessary therefore to arbitrate among these two signals. And theReleaseAck
for data-freeRelease
wins arbitration. Arbitration is also needed between the out.A transactions initiated by effective tracker module and aProbeAckData
orReleaseData
.Also note that each
Grant(Data)
inin.d
channel needs an accompanyingGrantAck
in in.e channel. The sink fields ind(e).bits
should beid
of the select tracker, so that when that tracker sees the ack coming back, it can assert thegot_e
signal, make this tracker idle and ready to accept new transactions. Extra Note: got_e is introduced in this commit, the dcache had been modified to support early grant ack in this commit . Early grant ack means that the e channel message will be sent in the very first beat of D channel grant. Therefore, once a grantAck is received by the broadcast hub, this does not mark the end of an acquire transaction. An acquire operation is finished successfully only when all the d channel grantAck beats has been sent(marked by sent_d). So, the idle-ness of a tracker is combinationally decided by val idle = got_e && sent_d.The broadcast hub also supports plugable Probe filters(introduced in this pr), for now the default implementation is just nothing(in<->out). From the filter io I can guess that the effect of this module is for literally filtering out some of the probes sending to each clients based on specific criteria, when a out.d transaction happens(a tracker will be idle again), the filter should be updated in some way.
This is a short anatomy but I guess this is useful to grasp a holistic understanding of the broadcast hub. Anyone who wants to dive into details definitely should read this unmerged commit from Sequencer to learn about the further details.
Beta Was this translation helpful? Give feedback.
All reactions