本文共 6880 字,大约阅读时间需要 22 分钟。
TLBroadcast实现的是TL-C等级,支持Transfer操作。主要功能是根据输入的请求类型,广播Probe请求进行权限调整,维持缓存一致性(cache coherency)。 跟踪为了实现缓存一致性而发出的Probe请求的过程。Tracker根据配置参数bufferless,决定是否保存上游节点下发的请求。 用于与其他diplomacy节点连接并协商传递参数的diplomacy节点。 因为要对source增加两位进行编码,所以这里乘以4。 a. endSinkId = numTrackers; b. 限定下游节点不能支持Acquire操作,即下游节点不支持TL-C: c. 只处理区域类型为UNCACHED的manager,把UNCACHED转换为TRACKED。即我们看到的下游节点的区间类型为UNCACHED,而上游节点看到的我们支持的这个区间的类型为TRACKED。因为我们做了TRACK的工作。 所谓UNCACHED区间类型,是指当前节点对该区间的支持不包含CACHE,但不妨碍上游节点为之添加缓存的功能。 这里not cached yet,不是指时间上,而是指结构上。 就时间上而言,一个区域是否缓存是一个动态的过程。而这里区域类型是一个静态的属性,不会随时间的变化而变化。即某个节点对某个区域的支持是否可缓存,不随时间的变化而变化。 但可以随结构的变化而变化。节点不是鼓励的节点,而是DAG中的一个节点。DAG中某个节点对某个区域的支持是不缓存,不代表其上游的节点不可以代为缓存。 UNCACHED:当前节点没为之缓存,上游节点可为之缓存; TRACKED:当前节点为下游节点增加了缓存的支持; UNCACHEABLE:不可缓存,当前节点不缓存,上游节点也不可以缓存,因为内容会变(比如IO编址区间)。这样的区间每次使用都要重新读取; e. 响应不必FIFO顺序返回,也就是说先来的请求的响应可以后面才返回; 因为所有节点组成的是DAG,所以只有上游节点可以缓存下游节点的数据,兄弟节点不能缓存。所以当上游节点发起的请求触发权限相关的Probe操作时,只需要向上游节点(通过node.in)发出Probe请求即可。 取出这一条线上的clients/managers: 用于处理地址,因为缓存的数据大小为lineBytes,所以地址相应的低位可以忽略: 其中:log2Up(caches.size + 1)为记录probe个数所需要的比特数。 channel e只有1种message,即GrantAck: b. 选择与in.e.bits.sink对应的tracker,输入e_last的值; i. NtoB:从None提升到Branch,Branch节点具有只读权限,所以向其他缓存了数据的节点发送Probe请求,把权限设定为Branch,即只读权限,超过的需要降权。 i. NtoT:从None提升到Trunk,Trunk节点可读,Trunk节点具有读权限,并且缓存了可能是脏数据的数据。所以如果一个节点要提升至Trunk节点,需要向其他节点发送Probe请求,把权限设定为None,以促使其把数据回写。 i. PutFullData:上游节点发来写数据请求,需要其他cache节点回写数据,若有需要之后再重新缓存。所以Probe其他cache节点的权限至None; i. PutPartialData:同PutFullData; i. ArithmeticData:需要先读、计算、再回写,同PutFullData; i. LogicalData:同PutFullData; i. Get:为了读取到最新数据,需要回写脏数据,如果没有脏数据则直接从缓存中返回即可。即如果是Trunk权限,则需要降权为Branch。如果是Branch权限,则无需再降权。 i. freeTrackers:各个tracker是否空闲的标志; i. freeTrack:是否存在空闲的Tracker; i. matchTrackers:各个tracker跟踪的是否是当前访问的地址的标志; i. matchTracker:是否有一个tracker跟踪者当前访问的地址; i. allocTracker:从空闲的tracker中分配一个tracker用于跟踪当前访问的地址; i. selectTracker:如果有tracker正在跟踪当前访问的地址,则仍然使用这个tracker。否则,使用重新分配的新tracker; trackerReady是各个tracker是否可以接收输入的标志: 是否接收channel a的请求,取决于如下条件: i. 选中的tracker可以接收:(selectTracker & trackerReady).orR(); i. burst请求的后续beat(!a_first)或者已经全部probe完成; 其中:t.probe表示要probe的client的个数。如果没有caches则为0。否则要看请求是否来自于某一个cache节点,如果是则为caches.size - 1,如果不是则为caches.size。 channel b用于向上游节点发送Probe请求: i. probe_todo:待probe的cache节点; i. probe_line:probe的address; i. probe_perms:param中cap的权限; i. probe_next:下一个要probe的对象; i. probe_busy:是否probe完所有要probe的cache节点; i. probe_target:当前要probe的对象; i. in.b.fire()时切换下一个probe对象; i. ProbeAck:我方发出Proe的响应消息,说明某client Probe完成。递减tracker中的Probe计数器。DROP是指收到ProbeAck无需其他动作。 i. ProbeAckData:除了递减计数器之外,还需要把返回的数据回写。即通过out.a发出PutFull消息。DROP是指无需再有其他动作。 i. ReleaseData:不同于ProbeAckData的地方在于,ReleaseData是上游节点发起,是一个请求消息,需要我方回复。回复的动作需要在PutFull完成之后,把PutFull的响应消息即AccessAck转换(transform)成为ReleaseAck返回给上游节点。 i. Release:直接使用in.d回复ReleaseAck即可。 针对Release消息的回复ReleaseAck: i. valid:channel c发送release时回复; i. 使用in.c.bits组装releaseack; 针对ProbeAckData和ReleaseData消息,需要把Data回写: i. put_what:标识PutFull是为了ReleaseData还是为了ProbeAckData,如果是ReleaseData,就标识为TRANSFORM_B,如果是ProbeAckData就标识为DROP。 i. put_who:如果是ReleaseData消息,那么source在in.c.bits.source;如果是ProbeAckData,这里source使用的是tracker中存着的in.a中取的source,与ProbeAckData中的Source即Probe消息的目标不一样,后续并没有使用这个source,用意不做分析。 i. Cat(put_what, put_who):修改Put操作的source,以方便响应消息AccessAck返回时处理;因为put_what有四种可能(TRANS_B/TRANS_T/DROP/PASS)占两位,所以下游节点看到的client的endSourceId相比Broadcast节点看到的上游节点cliet的endSourceId,扩大了四倍。这就是diplomacy node的clientFn中cp.endSourceId乘以4的原因: 如果in.c返回ProbeAck消息,则告诉tracker递减probe计数器: 如何根据out.d生成in.d要回复的消息。channel d支持的消息类型如下: b. 判断是否ProbeAckData消息衍生成出的Put消息的响应消息AccessAck: d. d_normal:使用out.d生成的消息,发往in.d 这意味着d_normal中各个域的位宽与in.d一致,而不是out.d。 实际上,out.d的source域比in.d的source域多两位,所以把out.d连接到d_normal时,会把这两位丢掉: TRANSFORM的信息从out.d.bits.source中取出,即do_what。 - ReleaseData需要把Put的响应消息AccessAck变换为ReleaseAck; - ProbeAckData需要把Put的响应消息AccessAck丢弃; in.a发出的Acquire消息,会被转换为Get消息,从下游节点请求数据,然后返回给上游节点。 c) do_what(1):TRANSFORM_B/TRANSFORM_T 如果do_what(1)为真,那么编码在source中的信息是TRANSFORM_B/TRANSFORM_T: 进而表明tracker中跟踪的是一个Acquire消息或ReleaseData消息。 如果d_hasData为真,out.d返回的是Acquire变换成的Get消息的响应消息AccessAckData,应该被转换为GrantData消息返回; 如果d_hasData为假,out.d返回的是ReleaseData变换成的Put消息的响应消息AccessAck,应该被转换为ReleaseAck消息返回; 如果ProbeAckData衍生的Put消息返回,则ProbeAckData消息处理完成。 d_normal.fire() && d_last代表d_normal发送完成。 d_response指除ProbeAckData的AccessAck消息和ReleaseData的ReleaseAck消息之外的其他消息。 因为这两个消息的响应消息虽然都是从channel d返回,但他们都是从channel c发送的请求消息。而tracker跟踪的是channel a发出的请求消息。 b. lineBytes:tracker缓存的字节数; c. probeCountBites:需要probe的cache节点计数所需的比特位数; d. bufferless:是否保存上游节点下发的请求; a. in_a_first:是否in_a的第一个beat; c. out_a:向channel d输出的信号; d. probe:要probe的cache节点的数目; e. probenack:处理完成一个ProbeAck消息; f. probedack:处理完成一个ProbeAckData消息; g. d_last:是否channel d的最后一个beat; h. e_last:是否channel e的最后一个beat; i. source:提取in_a中的source域,输出用于比对; j. line:提取in_a中的address域,处理后输出用于比对; a. idle = got_e && sent_d:表示已经完成全部消息交互:channel d已经发送完成,并收到了channel e的消息。 a. sent_d:假,刚收到in.a的消息,还没有返回响应消息; b. got_e:只有Acquire/Grant/GrantAck交互需要用到channel e置为假,其他用不到的置为真。 当channel d的最后一个beat发出后,sent_d置为真: channel d的响应消息已发出,则不再需要channel d: 当channel e的最后一个beat(实际上channel e有且只有一个beat)发出后,got_e置为真: 根据存的数据大小,地址的低若干位没有意义可以移除: 9) probe_done:标志着probe已经完成: a. Acquire消息被转换为Get消息,其余透传; b. source进行编码,Acquire消息对应的source编入transform信息,其他的透传(PASS=0b00); 3) 向上游回复transform后的ReleaseAck消息; 4) 向下游发出transform后的Get消息; 5) 向下游发出transform后的Put消息; 除Acquire需要transform外,其余的都会透传。 转载于:https://www.cnblogs.com/wjcdx/p/11265568.html