gem5内存系统

gem5内存系统

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

模型层次

本文档使用的模型包括两个超标量(O3)ARM v7 CPU,每个CPU配有相应的L1数据缓存和简单内存。该模型是通过以下参数运行gem5创建的:

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

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

CPU

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

本文件并不详细描述O3 CPU模型,因此仅提供一些关于该模型的相关说明:

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

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

加载和存储缓冲区(用于读写访问)对活动内存访问的数量没有限制。因此,CPU的最大内存访问请求数量不受CPU仿真对象的限制,而是由底层内存系统模型决定。

分裂内存访问(Split memory access) 已实现。

CPU发送的消息包含所访问区域的内存类型(普通、设备、强序和缓存性)。然而,模型的其余部分并没有使用这些信息,而是对内存类型采取了更简化的方法。

数据缓存对象

数据 Cache 对象实现了标准的缓存结构:

缓存内存读取 如果匹配特定的缓存标签(带有有效和读取标志),将在配置的时间后完成(通过向CPU发送ReadResp)。否则,请求将转发到未命中状态和处理寄存器(MSHR)块。

缓存内存写入 如果匹配特定的缓存标签(带有有效、读取和写入标志),将在相同的配置时间后完成(通过向CPU发送WriteResp)。否则,请求将转发到未命中状态和处理寄存器(MSHR)块。

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

未缓存内存写入 将转发到写缓冲区块。

驱逐(且脏)缓存行 将转发到写缓冲区块。

如果以下任何条件为真,则CPU对数据 Cache 的访问将被阻塞:

  • MSHR 块已满。(MSHR缓冲区的大小是可配置的。)

  • 写回块已满。(该块缓冲区的大小是可配置的。)

  • 针对相同内存缓存行的未完成内存访问数量已达到配置的阈值——有关详细信息,请参见 MSHR 和写缓冲区。

数据 Cache 在块状态下将拒绝来自从端口(来自CPU)的任何请求,无论是否会导致缓存命中或未命中。注意,主端口上的传入消息(响应消息和监听请求)永远不会被拒绝。

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

标签(Tags)与数据块

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

  • 有效(Valid)。表示缓存行持有数据,地址标签是有效的。

  • 读取(Read)。没有此标志设置的情况下,不会接受读取请求。例如,缓存行在等待写标志完成写入访问时,是有效但不可读的。

  • 写入(Write)。可能接受写入。具有写入标志的缓存行表示唯一状态——没有其他缓存内存持有该副本。

  • 脏(Dirty)。在驱逐时需要写回。

如果地址标签匹配且有效和读取标志被设置,则读取访问会命中缓存行。如果地址标签匹配且有效、读取和写入标志被设置,则写入访问会命中缓存行。

MSHR和写缓冲队列

未命中状态和处理寄存器(MSHR)队列持有需要访问下一级内存的CPU未完成内存请求列表。这些请求包括:

  • 缓存读取未命中。

  • 缓存写入未命中。

  • 未缓存的读取。

写缓冲区队列持有以下内存请求:

  • 未缓存的写入。

  • 从驱逐(且脏)缓存行的写回。

每个内存请求被分配到相应的 MSHR 对象(如图中所示的READ或WRITE),该对象代表必须读取或写入的特定内存块(缓存行),以完成命令。当对同一缓存行进行缓存读取/写入时,它们会共享一个 MSHR 对象,并通过一次内存访问完成。

块的大小(因此读取/写入访问下一级内存的大小)为:

  • 对于缓存访问和写回,大小等于缓存行的大小;

  • 对于未缓存访问,根据 CPU 指令指定的大小。

通常,数据 Cache 模型区分两种内存类型:

  • 普通缓存内存(Normal Cached memory)。总是视为写回、读取和写入分配。

  • 普通未缓存内存(Normal uncached)、设备(Device)和强排序(Strongly Ordered)类型被同等对待(视为未缓存内存)。

内存访问顺序

每个CPU读取/写入请求(在从属端口上出现时)会被分配一个唯一的顺序号。 MSHR 对象的顺序号从第一次分配的读取/写入请求中复制。

来自这些两个队列的内存读/写操作按顺序执行(根据分配的顺序号)。当两个队列都不为空时,模型将执行来自 MSHR 块的内存读取,除非写缓冲区已满。然而,模型将始终保持对同一(或重叠)内存缓存行(块)的读/写顺序。

总结:

  • 对于缓存内存的访问顺序,除非它们针对同一缓存行,否则不会被保留。例如,访问#1、#5和#10将在同一时钟周期内同时完成(仍然按照顺序)。访问#5将在#3之前完成。

  • 所有未缓存内存写入的顺序会被保留。Write#6始终在Write#13之前完成。

  • 所有未缓存内存读取的顺序会被保留。Read#2始终在Read#8之前完成。

  • 对未缓存内存的读取和写入访问的顺序不一定会被保留,除非它们的访问区域重叠。因此,Write#6 始终在 Read#8 之前完成(它们针对同一内存块)。然而,Write#13可能会在Read#8之前完成。

一致性总线对象

一致性总线对象

一致性总线对象提供了对snoop协议的基本支持:

  • 所有在从属端口的请求都被转发到相应的主端口。对于缓存内存区域的请求,还会将其转发到其他从属端口(作为snoop请求)。

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

  • 主端口的snoop请求会被转发到所有从属端口。

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

总线在以下事件发生后会在可配置的时间内进入阻塞状态:

  • 将数据包发送(或尝试发送)到从属端口。

  • 向主端口发送回复消息。

  • 从一个从属端口发送到另一个从属端口的snoop响应。

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

  • 从属端口的请求。

  • 主端口的回复。

  • 主端口的snoop请求。

简单内存对象

简单内存对象不会阻塞从属端口的访问。

内存的读取/写入会立即生效。(在接收到请求时会执行读取或写入操作。)

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

消息流

内存读访问顺序

以下图示显示了命中的Data Cache行的读取访问,其中包含有效(Valid)和读取(Read)标志:

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

请注意,总线对象不会从DCache2和内存对象处获得回复。它将相同的ReadReq数据包(消息)发送给内存和数据缓存。当数据缓存要回复snoop请求时,它会将消息标记为MEM_INHIBIT标志,告知内存对象不要处理该消息。

内存写访问顺序

以下图示展示了写访问命中DCache1缓存行的情况,该缓存行具有有效(Valid)和写入(Write)标志:

Write Hit (with Write flag set in cache line)

下一个图示展示了写访问命中DCache1缓存行的情况,该缓存行具有有效(Valid)标志但没有写入(Write)标志——这被视为写未命中。DCache1会发出UpgradeReq请求以获取写权限。DCache2::snoopTiming将使已命中的缓存行失效。请注意,UpgradeResp消息不携带数据。

下一个图示展示了DCache中的写未命中。ReadExReq会使DCache2中的缓存行失效。ReadExResp携带了内存缓存行的内容。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值