直接映射如何缓存return数据?

How does the direct mapped cache return data?

我正在学习 Patterson & Hennessey 编写的计算机组织与设计教科书的第一个 class 计算机体系结构和装配。我目前正在学习缓存。我知道 cpu 将检查缓存 1. 缓存块的索引,2. 该块中的有效位,3. 有效标记。如果数据有效,则从那里将数据发送到处理器。

虽然我无法将其想象成真实的东西。例如,我们可能想将单词从 $x 加载到 $y。处理器得到一个地址 0x12345670 来表示 $x。那么“0”就是偏移量,“67”就是索引,剩下的就是标签。我们从缓存中获得了命中,但数据在哪里?有问题的地址是数据吗?缓存中是否有更多 space 来保存我们需要的数据?它会直接将您发送到内存中的那个位置吗?假设它在那里,我们如何通过缓存从 $x 获取数据。

同时假设字长为 32 位,您将地址发送到缓存并得到一个完整的字或仅返回足够的位?

PS。从真实的例子中学习对我来说是最有帮助的,所以如果你有这方面的练习资源(以及 mips 编程,特别是非叶函数),我也会非常感激。

缓存不是编程的东西,如果你想要一些真实的例子,请看 openocores.org 那里至少有几个内核有缓存。 (你必须阅读 vhdl/verilog)。这不一定是您在 mips 程序中看到的东西。

关于这一点,请理解这本教科书是教科书 mips,其他人也没有制造出遵循该确切模型的处理器,其设计与从未发生过或不久前停止发生的完全一样。许多人从那本书中学到了东西,所以我们经常使用这些术语。但管道更深且不同,缓存大部分相同,但大小和宽度可能不同,并且确定如何确定谁丢失和被驱逐。

缓存通常被描述为具有一些字节数的 64Kbyte 缓存。这些是保存数据的字节。从慢端读取的数据,dram/main内存被缓存或存储在缓存中。那就是它住的地方。

当您读取 0x12345670 处的一个字节时,假设缓存行为 256 字节,那么如果未命中,则从 slow/dram 侧读取的内容相当于 0x12345600。如果您未命中,则缓存旨在确定该缓存中的何处存储包含您的字节的缓存行。如果有其他人蹲在那里,那么他们的数据需要被驱逐。如果该数据比 dram 中的数据更新(一些写入发生在它上面),那么该数据会在将您的缓存行读取到缓存之前写入 dram,然后最终将您的字节发送给您(更可能是总线宽度,32或 64 位发送给您,处理器将字节通道与其隔离)。如果缓存行是空的,或者那里的数据不需要写回 dram,那么缓存只是从 dram/slow 内存端读取包含您的字节的行并传送您的字节。

写入非常相似,但正如上面所暗示的那样,如果命中则发生读取-修改-写入,然后您就完成了。如果有未命中,则必须驱逐某些东西,然后从慢速内存中读取,然后发生读取-修改-写入。理想一点 somewhere 由缓存设置,以便它知道此缓存行比 dram 中的副本更新,并且当被驱逐时需要将其写入 dram 它不能被丢弃。

缓存还可以方便地存储和转发到较慢的内存。你想限制不必要的 dram 访问,如果你想写一个字节到 dram 你不想读一个 dram memory/bus 宽度修改字节并以这些速度写回,你想在 sram 中这样做缓存。缓存允许较慢的一侧将其所有事务都设置为最佳大小。处理器内核和系统内存之间可以有多个缓存,因此并非所有缓存都会或必须执行此操作,但理想情况下最后一个缓存会执行此操作。

如果我有一个带有 256 字节缓存行的缓存,那么低 8 位是缓存行的偏移量,您不会将它们用于剩余的寻址。如果我有一个 128Kbyte 缓存和 256byte 缓存行,这意味着我可以容纳 512 个东西。我需要 9 位来从 512 的东西中挑选。其中一些位来自剩余的地址位 (0x123456)。这样我就可以确切地知道这是内存中的哪 256 个字节 space 地址的任何剩余位都必须与我的缓存行一起存储。所以一个超级简单的是 4 的低位和 0x56 用于查找 512 行中的哪一行和剩余的 0x1234 减去 lsbit 0b000100100011010 必须作为查找的一部分存储在缓存中(实际标签) .所以我需要 512 * 15 位的 ram 用于标签本身加上一些更多的位来标记 valid/invalid 和 dirty/clean.

缓存行大小和开销之间存在微妙的平衡。就性能而言,缓存是一场赌博,您总是可以打败它们并找到一个使缓存比没有缓存更糟糕的基准。缓存行越小,每个事务的浪费越少,如果你在内存中的随机位置读取单个字节,这意味着缓存为你的每个字节读取 256 个字节,效率不高,所以每行 64 位到你的8的痛苦要小得多。但是,如果您的程序是更线性的、字符串副本、分支不多的程序,那么更大的缓存行可能会有用。缓存行越大,您必须存储的标签越小,内存越少,一般开销也越少。

除了上面我的缓存中有 512 256 字节缓存行之外,您还可以有多种方式。我可能会选择使用 7 个地址位而不是 8 个地址位,并且有 4 种方式。如果我有一个每次读取都跳转 0x100 字节的程序,那么一个缓存行将受到冲击,而其他 511 个缓存行则不会使用太多。但是相反,我从地址中获取更少的位(7),并且有一些方法(关联性?)。那个地址有四个可能的着陆点之一,逻辑会在这四个位置寻找命中,如果它们都未命中,那么其中任何一个都未被使用,如果没有,则有一种算法来确定谁被驱逐(最后一个或随机发生器,或循环法等)。如果我跳到 0x100 一点,那么至少使用了 4 行而不是 1 行。希望赌博得到回报,程序回来使用其中的一些行。

这些都应该以某种形式使用某种语言出现在你的教科书中。

一个简单的例子,并没有涵盖整个现实情况。你正在为某家公司回答 phone,老板疯了,规定你在任何时候都不能超过 16 messages/notes,然后你必须把它们交给员工。您接听电话,记下员工姓名和留言。重复。在您达到 16 岁时或之前,您必须通过运动鞋网(步行)将该信息传达给员工。如果您达到 16 个,您将无法接听更多电话,直到您至少发送一个电话并腾出一个空位。假设它就像过去一样,phone 一直响到你拿起它(你是接听电话的 machine)。如果您在将便条交给他们之前接到该员工的第二个电话,您可以在同一张便条上写下第二条消息,这不算两次。注释是缓存行。员工姓名是标签,消息是缓存行中的字节。 16 是我可以在此缓存中存储的缓存行总数。你的眼睛是逻辑,它会查看笔记以查看是否有命中或未命中,同样地,你会在时机成熟时确定驱逐。而且您可以在办公桌上每次旅行交付不止一个。所以你要设计你的 phone 缓存来确定你是否要一直等到你有 16 张纸条才发送 one/some 希望在有人收到不止一条消息时减少行程,或者如果你发送一旦你得到它们。或者介于两者之间。您无法预测电话何时会来,因此您无法完美地设计解决方案,但目标是改善某人(您)接听电话之前的响铃次数,并改善消息向员工的传递。请注意,在这个幻想中,员工不关心从发生呼叫到收到消息的延迟是多少,只要所有消息最终都被传递即可。没有涵盖真正的内存缓存问题和解决方案,但也许可以帮助您思考它,也许会让您的理解变得更糟,如果实在抱歉。

一般来说,作为程序员,缓存只是让您的计算机工作的内存系统的一部分,您实际上并没有与它交谈,您通常是在使用分配给您的程序的处理器的内存 space做东西。想要一个字符串并对其进行操作,您就可以这样做。您的程序本身最有可能作用于缓存,通常您不需要纠结于循环的位置或它们的对齐方式。而且您可能也没有考虑 MMU,它 can/does 使您认为是操作系统给您的线性地址 space 实际上在物理内存中碎片化,然后这些碎片如何进入缓存不在您的直接控制之下。如果您通常在 windows 或 linux 或 mac 或 ios 或 android 上编写 运行 的程序,您不知道 MMU/cache 位于高级程序后面的配置。裸机确保您处于控制之中,并且可以转动可以转动的旋钮(mmu,代码和数据对齐和条带化)。有些 systems/chips 你可以读取缓存的尺寸,有些你可以弄乱参数。在 that/those 情况下,您可以从中获得乐趣要么显示缓存有很大帮助 and/or 显示缓存使代码 运行 变慢。

编辑:

'67' would be the index

我会拒绝,但如果你认为那是对的,那很好。

but where is the data?

在缓存里,google单词缓存或者查字典。缓存保存数据。

Is the address in question the data?

相关地址全部或部分成为标签。

Is there more space in the cache that holds the data we need? 

数据在缓存中。

Does it send you directly to that location in memory?

如果未命中,则从主内存中读取数据并存储在缓存中,然后至少将您要求的部分发送给您。

Also assuming 32bit word length, you send the address to the cache and get a full word back or just the bits that are enough?

由总线设计和实现决定。读取像 32 位或 64 位这样的单元并且处理器从中提取字节或它正在寻找的任何内容并不少见。这并不是低效的,它通常在现代处理器上更有效率,在这些类型的单元中尽可能多地做,使用字节大小的变量会降低你的性能,从技术上讲它可能会节省你的内存,但 1970 年代很久以前你就结束了有足够的内存。通常写入是大小很重要的那些,通常有一个字节掩码指示总线的哪些字节具有必须存储的真实数据或大小并且总线使用数据总线位 0 到 N-1。

PS. it is most helpful for me to learn from real examples, so if You have resources on practice for this (and mips programming particularly non leaf functions) I would really appreciate that as well.

Opencores.org 有几个带有高速缓存的处理器。