CPU 如何确定将数据放入 L1i 还是 L1d

CPU 如何确定将数据放入 L1i 还是 L1d

CPU 如何决定使用哪个缓存来存储刚从内存中检索的数据?

据我所知,CPU 可以访问(读取或写入)的最小内存单位是 64 字节(x86_64、DDR3/DDR4),以 8 次传输(64 位 x 8 次)突发传输。这个 64B 单元称为缓存行,因为它一到达就立即存储到 L1 中(每个条目为 64B + 标签)。

编译后的代码充满了交错的指令和数据 - 许多指令将数据作为指令本身的一部分 - 操作码后面跟着立即数据。这是否被视为完整的指令并因此存储在 L1i 中?L1i 和 L1d 条目都是 64B 宽吗?整个缓存行是存储在 L1i 还是 L1d 中?或者 CPU 知道 C 的 .data 段,并且只有来自该部分程序的数据存储在 L1d 中?如果是这样,它是如何知道的?

答案1

CPU 如何决定使用哪个缓存来存储刚从内存中检索的数据?

CPU 不必“决定”使用哪个缓存。缓存分配与处理器缓存逻辑有关。CPU 知道每次内存访问的原因和目的。

编译后的代码充满了交错的指令和数据......

这是一个错误的断言。
我曾经使用过混合了代码和数据部分的计算机,但那是在微处理器出现之前。
现代 CPU 架构使用硬件堆栈来促进递归和串行可重入代码。
现代工具链生成单独的文本(即代码)和数据部分以促进代码共享。

哈佛计算机架构的一个显著特点是代码和数据采用独立的内存。
虽然大多数广泛使用的计算机都遵循普林斯顿或冯·诺依曼架构,但现代趋势是融入哈佛架构的某些方面。
对指令和数据使用单独的缓存(但使用单个主内存地址空间)就是一个明显的例子。

...许多指令都将数据作为指令本身的一部分 - 操作码后面跟着立即数据。

这是对指令格式的不准确描述。CPU
指令由操作码和零个或多个操作数组成。

  • 诸如 HALT 之类的操作码没有操作数。
  • 操作数可以是对寄存器内容的引用,也可以是操作数本身的值(又称立即数或文字值)。这样的指令不会生成(数据)内存操作。
  • 操作数可以是内存地址,也可以是寄存器内容作为内存地址的引用,或者是地址偏移量。地址模式和/或寄存器可以有其他操作数来指定内存地址计算。这样的指令将生成(数据)内存操作,执行

这是否被视为一条完整的指令并因此存储在 L1i 中?

指令由一个操作码和零个或多个操作数组成。
直到指令被解码(特别是对于定长与 RISC 指令不同,指令的操作数部分是一个谜,无法通过任何缓存逻辑进行分离。
因此,整个指令当然必须作为一个整体保存,并且与数据缓存无关(直到执行该指令为止)。

指令缓存仅保存作为指令提取的内存位置。
这些指令的内存地址将由 PC(程序计数器寄存器)指定。
如果 CPU 采用分支预测逻辑,那么这可能是指令地址的另一个来源。

所有其他内存引用都将被视为数据访问。


据我所知,CPU 可以访问(读取或写入)的最小内存单位是 64 字节(x86_64、DDR3/DDR4),以 8 次传输(64 位 x 8 次)突发传输。这个 64B 单位称为缓存行,因为它到达后立即存储到 L1(每个条目为 64B + 标签)。...
L1i
和 L1d 条目都是 64B 宽吗?整个缓存行是存储在 L1i 还是 L1d 中?

缓存大小取决于 CPU 实现。
您试图概括此类规范是不准确的。
还有许多其他(现代)CPU 架构和实现与您描述或声称的并不相似“知道”


还是说 CPU 知道 C 的 .data 段,并且只有该部分程序的数据存储在 L1d 中?如果是这样,它是如何知道的?

不,CPU 不知道内存组织,但知道内存访问的原因和目的。
使用程序计数器 (PC) 寄存器(和其他可能的逻辑)中的地址的内存访问用于指令,并利用指令缓存
执行指令的执行可以生成对数据的内存访问,并且该内存访问将利用数据缓存。
即使软件生成工具没有将代码和数据分开,CPU 仍然能够使用单独的代码和数据缓存,尽管当读/写数据缓存与只读指令缓存重叠时会产生不可预测的结果。

答案2

数据和指令可能会在总线和更高级别的缓存上交错,但 CPU 知道在任何给定时刻它正在处理的数据类型。

字节将从 L2 缓存中流出,并且可以识别和监控指令类型。可以推断、监视和调整程序流,并可以根据需要刷新缓存。从 CPU 执行的第一条指令开始,它就可以看到“指令流”,从而知道需要进入指令缓存的内容。

是什么给了它第一个指令?

在任何计算机中,它获得的第一件事就是指令。CPU 要做的第一件事就是转到特定地址并获取一些字节。从历史上看,这将是一个 ROM 设备,但它也可以很容易地成为 PCH 中的内存映射设备,向 CPU 传递其启动指令和微代码。

当前(因此很可能是下一条)指令的指针是 CPU 中的一个寄存器,称为程序计数器. 随着指令的执行,它会不断更新。

实际上,前几条指令可以简单地“将程序计数器设置为 xxxxxxxxx”,此时处理器将切换到从该位置抓取指令,另一个存储设备可能位于该位置。

从那里,CPU 始终可以看到指令流。它可以看到一条又一条的指令、分支、检查等等。当操作系统暂停 CPU 并重新启动 CPU 时,它会将要开始执行的指令的确切位置加载到程序计数器中。

从那里,CPU 可以再次向前查看指令流以及需要加载到指令缓存中的内容。

对于剩下的所有内容,都有数据缓存。

答案3

需要非常仔细地区分数据和代码:考虑这个代码片段:

i=i+10;

这将使变量增加 10。现在重要的是,无论值为多少i,增量始终为10。这意味着,我们应该将i数据视为在程序执行期间可能发生变化的数据,但10将其视为代码的一部分(因为它不会发生变化)。

这意味着,编译该代码片段后生成的机器代码将被i引用为寄存器或内存位置,但10作为直接数据。由于我们认为该直接数据是代码的一部分,因此我们将其放入指令缓存中。

相关内容