authors: Djordje Kovacevi

gem5 内存系统

本文档描述了 gem5 中的内存子系统,重点关注 CPU 简单内存事务(读取或写入)期间的程序流程。

模型层次结构

本文档中使用的模型由两个乱序 (O3) ARM v7 CPU 以及相应的 L1 数据缓存和简单内存组成。它是通过使用以下参数运行 gem5 创建的:

configs/example/fs.py –-caches –-cpu-type=arm_detailed –-num-cpus=2

Gem5 使用 Simulation Objects 派生对象作为构建内存系统的基本块。它们通过已建立主/从层次结构的端口连接。数据流在主端口上启动,而响应消息和 snoop 查询出现在从端口上。

模型的模拟对象层次结构

CPU

Data Cache 对象实现了标准缓存结构:

DCache Simulation Objet

详细描述 O3 CPU 模型不在本文档的范围内,因此这里仅提供有关该模型的几条相关说明:

读取访问 通过向 DCache 对象发送消息来启动。如果 DCache 拒绝该消息(因为被阻塞或忙碌),CPU 将刷新流水线,稍后将重新尝试访问。访问在收到来自 DCache 的回复消息 (ReadRep) 时完成。

写入访问 通过将请求存储到存储缓冲区来启动,该缓冲区的上下文在每个 tick 被清空并发送到 DCache。DCache 也可能拒绝该请求。当收到来自 DCache 的写入回复 (WriteRep) 消息时,写入访问完成。

加载和存储缓冲区(用于读取和写入访问)不对活动内存访问的数量施加任何限制。因此,未完成的 CPU 内存访问请求的最大数量不受 CPU 模拟对象的限制,而是受底层内存系统模型的限制。

拆分内存访问 已实现。

CPU 发送的消息包含访问区域的内存类型(Normal, Device, Strongly Ordered 和 cachebility)。但是,采用更简化的内存类型方法的模型的其余部分并未使用此信息。

数据缓存对象

Data Cache 对象实现了标准缓存结构:

与特定缓存标记匹配(设置了 Valid 和 Read 标志)的 缓存内存读取 将在可配置的时间后完成(通过向 CPU 发送 ReadResp)。否则,请求将转发到 Miss Status and Handling Register (MSHR) 块。

与特定缓存标记匹配(设置了 Valid、Read 和 Write 标志)的 缓存内存写入 将在相同的可配置时间后完成(通过向 CPU 发送 WriteResp)。否则,请求将转发到 Miss Status and Handling Register (MSHR) 块。

未缓存的内存读取 转发到 MSHR 块。

未缓存的内存写入 转发到 WriteBuffer 块。

被驱逐的(和脏的)缓存行 转发到 WriteBuffer 块。

如果以下任何一项为真,则 CPU 对 Data Cache 的访问将被阻止:

处于阻塞状态的 Data Cache 将拒绝来自从端口(来自 CPU)的任何请求,无论它会导致缓存命中还是未命中。请注意,主端口上的传入消息(响应消息和 snoop 请求)永远不会被拒绝。

未缓存内存区域上的 Cache 命中(根据 ARM ARM 是不可预测的行为)将使缓存行无效并从内存中获取数据。

标记和数据块

Cache 行(在源代码中称为块)被组织成具有可配置关联性和大小的集合。它们具有以下状态标志:

如果地址标记匹配并且设置了 Valid 和 Read 标志,则读取访问将命中缓存行。如果地址标记匹配并且设置了 Valid、Read 和 Write 标志,则写入访问将命中缓存行。

MSHR 和写缓冲区队列

Miss Status and Handling Register (MSHR) 队列保存 CPU 的未完成内存请求列表,这些请求需要对较低内存级别进行读取访问。它们是:

WriteBuffer 队列保存以下内存请求:

MSHR 和写缓冲区块

每个内存请求都被分配给相应的 MSHR 对象(上图中的 READ 或 WRITE),该对象代表必须读取或写入以完成命令的特定内存块(缓存行)。如上图所示,针对同一缓存行的缓存读/写共享一个公共 MSHR 对象,并将通过单个内存访问完成。

块的大小(以及对较低内存的读/写访问的大小)是:

通常,Data Cache 模型仅区分两种内存类型:

内存访问排序

每个 CPU 读/写请求(当它们出现在从端口时)都被分配一个唯一的序列号。MSHR 对象的序列号是从第一个分配的读/写复制的。

来自这两个队列中每一个的内存读/写都是按顺序执行的(根据分配的序列号)。当两个队列都不为空时,模型将执行来自 MSHR 块的内存读取,除非 WriteBuffer 已满。但是,它将始终保留同一(或重叠)内存缓存行(块)上的读/写顺序。

总之:

一致性总线对象

一致性总线对象

Coherent Bus 对象为 snoop 协议提供基本支持:

从端口上的所有请求都转发到相应的主端口。 对缓存内存区域的请求也转发到其他从端口(作为 snoop 请求)。

主端口回复转发到相应的从端口。

主端口 snoop 请求转发到所有从端口。

从端口 snoop 回复转发到作为请求源的端口。(请注意,snoop 请求的源可以是主端口或从端口。)

在发生以下任何事件后,总线会在可配置的时间段内声明自己处于阻塞状态:

处于阻塞状态的总线拒绝以下传入消息:

简单内存对象

它从不阻止从端口上的访问。

内存读/写立即生效。(收到请求时执行读取或写入)。

回复消息在可配置的时间段后发送。

消息流

内存访问排序

下图显示了命中具有 Valid 和 Read 标志的 Data Cache 行的读取访问:

Read Hit (必须在缓存行中设置 Read 标志)

缓存未命中读取访问将生成以下消息序列:

Read Miss with snoop reply

请注意,总线对象永远不会从 DCache2 和 Memory 对象都获得响应。它将完全相同的 ReadReq 包(消息)对象发送到内存和数据缓存。当 Data Cache 想要回复 snoop 请求时,它会用 MEM_INHIBIT 标志标记消息,该标志告诉 Memory 对象不要处理该消息。

内存访问排序

下图显示了命中具有 Valid 和 Write 标志的 DCache1 缓存行的写入访问:

Write Hit (缓存行中设置了 Write 标志)

下图显示了命中具有 Valid 但没有 Write 标志的 DCache1 缓存行的写入访问——这符合写入未命中的条件。DCache1 发出 UpgradeReq 以获得写入权限。DCache2::snoopTiming 将使被命中的缓存行无效。请注意,UpgradeResp 消息不携带数据。

Write Miss – 匹配标记但没有 Write 标志

下图显示了 DCache 中的写入未命中。ReadExReq 使 DCache2 中的缓存行无效。ReadExResp 携带内存缓存行的内容。

Miss - 没有匹配的标记