Naplespu微体系结构内多个插件融合分析(草稿)
http://www.naplespu.com/doc/index.php?title=Detailed_studies
介绍
打算展示替换链是如何相对于L2缓存发生的,观察目录控制器是如何演变以管理此类情况的发生的。主要目的是测试发生L2替换的所有情况,如图所示:
![](https://img2024.cnblogs.com/blog/1251718/202407/1251718-20240727070731731-780898566.png)
目录控制器中的内存
为了更好地理解替换机制的工作原理,有必要首先评估目录控制器管理的缓存的结构。以下描述表示用于所有实验的配置。如图所示,缓存由四种方式和64组组成,每种方式包含一个标签和一个数据(64位)。
![](https://img2024.cnblogs.com/blog/1251718/202407/1251718-20240727070731704-1862940775.png)
管理地址为32位,其组织方式如图所示:
![](https://img2024.cnblogs.com/blog/1251718/202407/1251718-20240727070731655-632660940.png)
然后,每个控制器目录可以处理有限数量的地址,例如,图块0可以处理从0x00000000到0x3ffffff的地址,图块1可以处理从0x4000000到0x7ffffff的地址,以此类推。实验中使用了四块分块进行处理。
更换工具链
为了进行替换,需要填写与给定集合相关的所有四种方式:在同一集合中插入新条目时,实现替换。为了简单起见,需要编写代码,以便在使用的内核中直接在Assembly中运行,从而更好地控制执行的操作和使用的内存地址。为了确定正在进行替换,有必要观察do_replacement信号。此信号仅在以下情况下为高。
do_replacement = dc2_message_valid && ((allocate_cache | | update_cache) && !deallocate_cache) && !is_replacement && !dc2_message_cache_hit && dc2_message_cache_valid;
因此,如果已经处理了替换以外的请求,并且没有导致缓存行被释放,那么如果缓存中没有命中,那么将需要执行替换。可以注意到,如果没有缓存释放,则会触发替换操作,这可能违反直觉。事实上,替换操作的管理方式是直接用要插入的新行替换条目LRU,而不会使执行替换的缓存行无效,将无效操作(针对缓存控制器)委托给稍后的阶段。在do_replacement信号断言后,通过dc3替换入队信号,触发相对队列中替换请求的入队,在该队列中还插入要执行替换的缓存行的内容:
dc3_replacement_enqueue = dc2_message_valid && do_replacement;
assign dc3_replacement_request.source = dc2_message_source,
dc3_replacement_request.memory_address.tag = dc2_message_cache_tag,
dc3_replacement_request.memory_address.index = dc2_message_address.index,
dc3_replacement_request.memory_address.offset = 0,
dc3_replacement_request.data = dc2_message_cache_data,
dc3_replacement_request.state = dc2_message_cache_state,
dc3_replacement_request.分享s_list = dc2_message_cache_分享s_list,
dc3_replacement_request.owner = dc2_message_cache_owner;
注意,dc2消息address.index包含从第2阶段获取的LRU索引。
如目录控制器文档中所述,第1阶段包含一个固定优先级的调度器,如果可以发出替换请求的条件得到验证,则该调度器涉及替换请求的最高优先级处理。除了通常的信号外,阶段1还向阶段2发送以下信号:
dc1_replacement_state <= output_replacement_state;
dc1_replacement_分享s_list <= output_replacement_分享s_list;
dc1_replacement_owner <= output_replacement_owner;
这些信号从阶段2转发到阶段3。在实际处理请求的状态3中,根据所在的状态,按照协议ROM中的定义进行替换。
更换一条线路
为了测试M状态下块的替换,并评估其文档中描述的主要信号,就目录控制器而言,构建了以下内核:
if(tile_id==0){
asm(
"moveih s20, 0x0000"
"moveil s20, 0x0000"
"store32 s21, (s20)"
"moveil s20, 0x1000"
"store32 s21, (s20)"
"moveil s20, 0x2000"
"store32 s21, (s20)"
);
}else if(tile_id==1){
asm(
"moveih s20, 0x0000"
"moveil s20, 0x4000"
"store32 s21, (s20)"
"moveil s20, 0x8000"
"store32 s21, (s20)"
);
}
在这种情况下,图块0运行三个存储,图块1运行两个存储。为了区分不同的请求,请观察图中的dc1消息有效信号,当固定优先级调度器从相应的队列中选择一个请求时,该信号被断言。
![](https://img2024.cnblogs.com/blog/1251718/202407/1251718-20240727070731655-1812886145.png)
从仿真中可以看出,目录控制器按以下顺序处理消息:
1.分块1存储0x00004000
2.分块0存储在0x00000000
3.分块1存储0x00008000
4.分块0存储在0x00001000
5.分块0存储在0x00002000
这些请求是以属于同一组的方式提出的,以便触发替换。
根据请求,缓存分配如下:
![](https://img2024.cnblogs.com/blog/1251718/202407/1251718-20240727070731627-1077857185.png)
为了获得上述信息,评估了dc3_update_cache_way信号,该信号允许在L2中写入条目。此信号直接取决于selected_way,如果是hit,则包含hit_index,否则包含lru_way(参阅与伪lru相关的部分)。
指定选定way = hit ? hit idx : lru_way;
或者,可以观察dc1_message_cache_state信号是如何演变的。详细看看在一个简单请求的情况下,会发生什么:
![](https://img2024.cnblogs.com/blog/1251718/202407/1251718-20240727070731762-806280461.png)
缓存是通过dc3_update_cache_state信号完成的。从下图中,可以看到如上所述,条目是如何以方式0分配的。
![](https://img2024.cnblogs.com/blog/1251718/202407/1251718-20240727070731656-1877701434.png)
在第五次存储时,L2缓存已满,替换机制开始。为了理解它的功能,可以从理论上观察哪些信息应该交换,然后获得实际反馈:
![](https://img2024.cnblogs.com/blog/1251718/202407/1251718-20240727070731605-469517977.png)
从下图可以观察到,请求被执行,缓存行被插入,而不是lru-way信号指示的条目;因此,可以检测到高do_replacement信号,从而也检测到do_replacement_enqueue信号),这涉及在替换队列中插入请求。
![](https://img2024.cnblogs.com/blog/1251718/202407/1251718-20240727070731681-1340997123.png)
此时,通过观察各阶段信号的递增顺序,检查管道内的更换操作是如何进行的。
阶段1:在图中,可以看到条件can_issue_replacement_request得到满足,因此请求从其队列中取出。此请求的类型为“c”,即替换。
![](https://img2024.cnblogs.com/blog/1251718/202407/1251718-20240727070731683-467347975.png)
此时发送的消息取决于协议ROM,可以从以下代码摘录中看到:
{STATE_S, REPLACEMENT, 1'b?, 1'b?} : begin // Replacement
// Send BACKINV To 分享s
dpr_output.message_forwarded_send = 1'b1;
dpr_output.message_forwarded_type = MESSAGE_BACKINV;
dpr_output.message_forwarded_to_分享s = 1'b1;
// Send WB To Memory Controller
dpr_output.message_response_send = 1'b1;
dpr_output.message_response_type = MESSAGE_WB;
dpr_output.message_response_has_data = 1'b1;
dpr_output.message_response_to_memory = 1'b1;
// Next State N
dpr_output.next_state = STATE_N;
end
首先,需要向分享发送BACK_INV消息,向内存控制器发送WB消息:
=======================
Directory Controller - [Time 12810] [TILE 0] - Message Sent
Forwarded Destinations: 0010
Source: 0
Address: 00004000
Requestor: DCACHE
Packet Type: BACK_INV
Uncoherent: 0
Response Destinations: 1000
Source: 0
From DC: 1
Address: 00004000
Requestor: DCACHE
Packet Type: WB
Data: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Uncoherent: 0
分享 Count: 1
=======================
Cache Controller - [Time 12890] [TILE 1] [Core 0]
Source: 0
Address: 00004000
Requestor: DCACHE
Packet Type: BACK_INV
Uncoherent: 0
与前面的示例不同,可以从状态S直接转换到状态N。
案例2:多个共享者
为了测试用单个分享替换S状态的块,并评估文档中描述的主要信号,就目录控制器而言,构建了以下内核:
if(tile_id==0){
asm( "moveih s20, 0x0000"
"moveil s20, 0x4000"
"load32 s22, (s20)"
"moveil s20, 0x0000"
"store32 s21, (s20)"
"moveil s20, 0x1000"
"store32 s21, (s20)"
"moveil s20, 0x2000"
"store32 s21, (s20)"
);
}else if(tile_id==1){
asm( "moveih s20, 0x0000"
"moveil s20, 0x4000"
"load32 s22, (s20)"
"moveil s20, 0x8000"
"store32 s21, (s20)"
);
}
在这种情况下,图块0执行加载和三个存储,图块1执行加载和一个存储。
![](https://img2024.cnblogs.com/blog/1251718/202407/1251718-20240727070731743-494737782.png)
为了区分不同的请求,观察dc2_message_valid信号,当固定优先级调度器从相应的队列中选择一个请求时,该信号会被断言。
从模拟中可以看出,目录控制器按以下顺序处理消息:
1.将分块1加载到地址0x00004000
2.将分块0加载到地址0x00004000
3.分块1存储0x00008000
4.分块0存储在0x00000000
5.分块0存储在0x00001000
6.分块0存储在0x00002000
随后在缓存中进行分配:
![](https://img2024.cnblogs.com/blog/1251718/202407/1251718-20240727070731682-2141346994.png)
这些请求是以属于同一组的方式提出的,以便触发替换。
从理论角度来看,观察针对不同共享者的BACK_INV消息很有趣:
![](https://img2024.cnblogs.com/blog/1251718/202407/1251718-20240727070731600-954547322.png)
可以通过提高细节级别来发现,参考消息日志,由文件display_coherence.txt表示:
=======================
Directory Controller - [Time 13980] [TILE 0] - Message Sent
Forwarded Destinations: 0011
Source: 0
Address: 00004000
Requestor: DCACHE
Packet Type: BACK_INV
Uncoherent: 0
Response Destinations: 1000
Source: 0
From DC: 1
Address: 00004000
Requestor: DCACHE
Packet Type: WB
Data: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Uncoherent: 0
分享 Count: 2
=======================
Cache Controller - [Time 14080] [TILE 1] [Core 0]
Source: 0
Address: 00004000
Requestor: DCACHE
Packet Type: BACK_INV
Uncoherent: 0
=======================
Cache Controller - [Time 15860] [TILE 0] [Core 0]
Source: 0
Address: 00004000
Requestor: DCACHE
Packet Type: BACK_INV
Uncoherent: 0
与单独分享情况的主要区别在于,需要向替换缓存行中的所有分享,发送无效消息。
替换一条线路
为了测试L2缓存状态中条目的替换,必须使用更复杂的内核,因为L1缓存大小与L2缓存大小相同,因此必须使用两个不同的目录控制器。
使用这种类型的实验,而不是增加L2缓存的大小,更具形成性,因为除了测试和理解所使用的PLRU算法外,可以观察到使用两个不同的DC来处理请求。此外,如引言中所述,有必要对所有实验保持相同的配置。
下面是使用的代码:
"moveih s20, 0x0000"
"moveil s20, 0x0000"
"store32 s21, (s20)"
"moveil s20, 0x1000"
"load32 s22, (s20)"
"moveil s20, 0x2000"
"load32 s22, (s20)"
"moveil s20, 0x4000"
"load32 s22, (s20)"
"moveih s20, 0x4000"
"moveil s20, 0x0000"
"store32 s21, (s20)"
"moveih s20, 0x0000"
"moveil s20, 0x1000"
"store32 s21, (s20)"
"moveil s20, 0x2000"
"store32 s21, (s20)"
"moveil s20, 0x4000"
"store32 s21, (s20)"
"moveil s20, 0x8000"
"store32 s21, (s20)"
由于希望完全控制收到到目录控制器的请求,因此使用了一个分块。这是因为系统使用确定性路由,并意味着请求将在发送方发送时到达目的地。
![](https://img2024.cnblogs.com/blog/1251718/202407/1251718-20240727070731681-1789391994.png)
从代码中可以看到,Tile 0生成了9个请求:
1.存储在0x00000000
2.加载到地址0x00001000
3.加载到地址0x00002000
4.加载到地址0x00004000
5.存储在0x40000000
6.存储在0x00001000
7.存储在0x00002000
8.存储在0x00004000
9.存储在0x00008000
如目录控制器中的内存部分所定义的,请求5是发往图块1的目录控制器的。
前4个请求需要填充L2缓存,如下所示:
![](https://img2024.cnblogs.com/blog/1251718/202407/1251718-20240727070731641-1331392870.png)
为了获得进入状态I的条目,上述缓存行的所有者缓存控制器必须替换它(L1)。对DC的额外请求将导致其中一条线路在L2级别被替换,因此为了触发整个过程,Tile 0缓存控制器将向Tile 1目录控制器发出请求(请求5)。
为了验证请求5,可以通过查看消息日志来移动到更高的抽象级别:
=======================
Cache Controller - [Time 13700] [TILE 0] [Core 0] - Message Request Sent
Directory Destinations: 1
Source: 0
Address: 40000000
Packet Type: GETM
Data: 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
=======================
Directory Controller - [Time 13780] [TILE 1] - Message Received
Source: 0
Address: 40000000
Packet Type: GETM
Data: 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
还要注意图\ref{fig:PUTM}和消息日志提取中L1替换后,Tile 0目录控制器收到的相对PUTM(类型3请求)。
![](https://img2024.cnblogs.com/blog/1251718/202407/1251718-20240727070731674-516275581.png)
=======================
Cache Controller - [Time 14470] [TILE 0] [Core 0] - Message Request Sent
Directory Destinations: 0
Source: 0
Address: 00000000
Packet Type: PUTM
Data: 44618020820180007600001411018640606403206164000060600330616000007608006820f3d00082f40000040000c04b0c2010600002e061000000xxxxxxxx
=======================
Directory Controller - [Time 14610] [TILE 0] - Message Received
Source: 0
Address: 00000000
Packet Type: PUTM
Data: 44618020820180007600001411018640606403206164000060600330616000007608006820f3d00082f40000040000c04b0c2010600002e061000000xxxxxxxx
=======================
Directory Controller - [Time 14630] [TILE 0] - Message Sent
Response Destinations: 0001
Source: 0
From DC: 1
Address: 00000000
Requestor: DCACHE
Packet Type: PUT_ACK
Data: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Uncoherent: 0
Sharer Count: 0
从下图中,可以通过信号dc1_message_cache_state(包含缓存行的状态)观察缓存的状态是如何演变的,状态3表示状态“I”:
![](https://img2024.cnblogs.com/blog/1251718/202407/1251718-20240727070731783-818294289.png)
图中表示的请求6、7、8是必要的,以便将selected_way与状态I中包含缓存行的方式相匹配,因为它不再是lru。
![](https://img2024.cnblogs.com/blog/1251718/202407/1251718-20240727070731707-1508502692.png)
请求更改LRU条目的状态如下:
![](https://img2024.cnblogs.com/blog/1251718/202407/1251718-20240727070731567-905347080.png)
下图显示了一个示例,说明在请求输入状态后,状态如何从S(2)更改为M(1),从而导致lru_way信号的演变:
![](https://img2024.cnblogs.com/blog/1251718/202407/1251718-20240727070731704-70993282.png)
此时,请求9生成替换:
![](https://img2024.cnblogs.com/blog/1251718/202407/1251718-20240727070731621-1572169713.png)
从理论上讲,可以观察到消息的交换(见下图),在这种情况下,这要简单得多,因为该块仅由目录控制器拥有。
![](https://img2024.cnblogs.com/blog/1251718/202407/1251718-20240727070731626-122887856.png)
在这一点上,检查更换操作是如何在管道内详细进行的,观察各阶段信号的演变情况,然后:
阶段1:在下图中,可以看到条件can_issue_replacement_request已满足,因此请求已从队列中取出。此请求的类型为“c”,即替换。
![](https://img2024.cnblogs.com/blog/1251718/202407/1251718-20240727070731683-1074386880.png)
第二阶段:请求被转发到第三阶段,可以检查所选的方式在未命中的情况下,如何与lru_way完全相等,即使它不会在第三阶段使用,因为会采用请求附带的方式。
第三阶段:is_replacement信号为高,因此它实际上是一个替换。
参阅图中触发替换的请求和替换本身的详细信息:
![](https://img2024.cnblogs.com/blog/1251718/202407/1251718-20240727070731546-529414952.png)
在下图中,可以详细看到与第一阶段进入状态I相关的状态变化。
![](https://img2024.cnblogs.com/blog/1251718/202407/1251718-20240727070731721-1047768636.png)
根据ROM协议的规定,它向存储器控制器生成WB:
{STATE_I, REPLACEMENT, 1'b?, 1'b?} : begin // Replacement
// Send WB To Memory Controller
dpr_output.message_response_send = 1'b1;
dpr_output.message_response_type = MESSAGE_WB;
dpr_output.message_response_has_data = 1'b1;
dpr_output.message_response_to_memory = 1'b1;
// Next State N
dpr_output.next_state = STATE_N;
end
可以通过提高细节级别来看到,参考消息日志,由文件display_coherence.txt表示:
=======================
Directory Controller - [Time 15940] [TILE 0] - Message Sent
Response Destinations: 1000
Source: 0
From DC: 1
Address: 00000000
Requestor: DCACHE
Packet Type: WB
Data: 618020820180007600001411018640606403206164000060600330616000007608006820f3d00082f40000040000c04b0c2010600002e061000000xxxxxxxx
Uncoherent: 0
Sharer Count: 0
=======================
Memory Controller - [Time 16360] [TILE 3] - Message Received
Source: 0
From DC: 1
Address: 00000000
Requestor: DCACHE
Packet Type: WB
Data: 618020820180007600001411018640606403206164000060600330616000007608006820f3d00082f40000040000c04b0c2010600002e061000000xxxxxxxx
Uncoherent: 0
Sharer Count: 0
不稳定状态下的更换
值得注意的是,不稳定的状态是无法测试的。这是由于观察了控制器目录的结构。为了处理替换,必须通过循环缓冲区将请求带入控制器,但由于缓存中只存储了稳定状态(N除外),因此无法评估稳定状态以外的状态。
参考文献链接
http://www.naplespu.com/doc/index.php?title=Detailed_studies