【问题标题】:Big-little endian details when reading bytes (memory location)读取字节时的大小字节序细节(内存位置)
【发布时间】:2019-09-24 06:06:17
【问题描述】:

假设使用这个 32 位数字 66 DD FA EB。

小端序

0 x 100 ---> 66 (MSB)

0 x 99 ---> DD

0 x 98 ---> FA

0 x 97 ---> EB (LSB)

大端序

0 x 100 ---> EB (LSB)

0 x 99 ---> FA

0 x 98 ---> DD

0 x 97 ---> 66 (MSB)

我相信已经理解了存储字节的正确顺序。

但是我的问题是,访问这个 4 字节字时首先读取哪个字节?

总是首先读取具有最低地址的字节,然后根据计算机的字节序将其定位为最高有效或最低有效?

我试图更好地解释自己。 以上面的 LITTLE ENDIAN 为例。

我想要的正确顺序是 66 DD FA EB

现在要实现这一点,我可以读取地址最低的字节并将其放在页面的右侧,然后继续向左读取以下字节。

         EB 

      FA EB

   DD FA EB

66 DD FA EB

结果是 66 DD FA EB,这是正确的。

或者我可以从地址最高的字节读取,将其放在页面的左侧,然后继续向右读取以下字节

66

66 DD

66 DD FA

66 DD FA EB

结果总是 66 DD FA EB,这是正确的。

由于字的内存地址是第一个字节的地址(最低地址),与字节序无关,我假设总是先读取第一个字节(最低地址),然后定位到正确的顺序。

所以我的最后一个问题是,

我之前展示的两种模式中的哪一种被小端序的计算机用来读取建议示例中的 4 字节字?

【问题讨论】:

  • 这是一个理论问题,cpus 不是这样工作的。他们读取单词甚至更大的单元(缓存行)。但第一个版本更有意义。正如你所说,你从低地址开始。
  • 感谢您的回答。作为一个字一组字节,就算一次性读完,我想总有一个起点可以开始读吧?
  • 0x99之后的地址不是0x100;它是 0x9a。 32 位值通常从 4 的倍数的地址开始放置,而不是奇数地址,例如 0x97。使用字节地址 0x100、0x101、0x102 和 0x103 的示例(对我来说)会更清楚。
  • 没有先读取。它们都被同时读取。除非您谈论的是带有小型(16 或 8 位数据总线)的非常旧的 CPU,否则它取决于 CPU。通常先读取低字节,但不一定如此。
  • 再次嗨 :) 不,你的理解是错误的——在 32 位/64 位 CPU 上,如果 CPU 读取一个单词——它会将整个单词作为一个单元读取。没有“从哪个字节开始”的概念。当你拿一盒火柴时——你拿整盒火柴,你不会从一个单独的火柴开始这样做。

标签: assembly cpu-architecture endianness


【解决方案1】:

正如在 cmets 中多次提到的那样,一件事与另一件事无关。主内存总线至少 32 位宽,但更常见的是 64 位,所有事务都是这些大小。好吧,这也不是真的,这更重要。有很多总线,在处理器内核的边缘有一个/一些,然后您通过 mmus 和缓存进入芯片级总线,然后进入芯片级总线。在芯片上,您至少有 32 位宽,但更可能是 64 位或两倍的幂。当您将芯片放入系统内存时,通常是 DRAM,这取决于技术。高速缓存和外部接口之间的控制器和各种总线管理每一层的总线事务数。在服务器或桌面上,您可能有 64 位或 72 位接口(后者带有 ecc)。对于电话来说,ddr4 是一个 16 位总线,因此您的缓存线被分成许多 16 位事务或 32 个自 ddr (任何半个时钟周期上的数据,而不仅仅是每个时钟周期一位,因此得名)。所以你可以把它算作 16 或 32。你的笔记本电脑可能有一个 32/40 位的记忆棒,但我有一段时间没有数过针脚了。

根据您的问题,尽管如果您返回回程机器,这仍然取决于,32 位事务可能由 32 位总线和 32 位内存处理,无论是 4 个 8 位总线或 2 个 16 位还是32. 但即使不匹配,也取决于系统设计人员,因为我们没有很多片上系统,所以它是一个 cpu,然后是外围设备等其他芯片。因此内存控制器设计人员可以选择首先执行哪个字节事务。而且通常是任意的。

对于小端也是如此。如果您对大与小的定义是什么,就会出现问题。你如何打开你的问题对我来说毫无意义...... 0x11223344 32 位值 0x44 是最低有效字节,这总是正确的,字节顺序与它无关。现在,当以字节可寻址方式考虑时,它的地址可能以 2b00 或 2b11 结尾,这就是您的字节序。但是我们有字节不变的处理器 be8 和字不变的 be32 处理器,这是您通常想到的,但是 arm 已切换到字节不变,因此交换了字,但字节位于同一地址(取决于事务大小)。疯了吧?那么当然有位排序,其中 0x44 可能是位 7..0,一些 CPU 认为 0x44 位是 24..31。

最重要的是没有固定的答案,这完全取决于系统级设计人员,这并不意味着 CPU 人员,您可以使用 68K 并将其连接到 8 位内存并拉出一个字大小以您喜欢的任何顺序进行交易 A[1:0] = 2b11, 2b10, 2b01, 2b00 或 2b00, 2b01, 2b10 2b11,由您决定并不重要,也不会影响处理器本身,因为您将其提供完整收集字节后的单词。

设计或在 8 位总线时代设计的系统不一定具有 32 位事务。也许是 16,但您更有可能将两个 8 位部件放在那里并控制输出和写入启用,而不是添加等待状态,尤其是在那个时代。因此是 8088 与 8086。一个用于 8 位宽的内存,可能是单个部分,另一个用于 16 位宽的系统,最初两个 8 位宽的部分随着需求的增加演变为 16 位宽的部分。

这个问题没有单一的答案。

【讨论】:

    【解决方案2】:

    现代 CPU 通常从缓存或足够宽的外部数据总线一次读取所有 4 个字节。

    当他们读取整个缓存行时,有一个相关的“关键word优先”概念,即从内存中以包含您实际数据的 8 字节块开始的流数据等待(缓存中错过的需求加载),因此加载可以完成并将数据转发到下一条等待它的指令。

    但这仍然假设总线宽度/传输块大小至少与负载一样宽,因此如果您的总线较窄(例如例如在 386 SX 上)。

    现代 CPU 具有高达 64字节 宽的内部总线(例如 Skylake 中的 L2 和 L1d 缓存之间,以及 Skylake-avx512 和更高版本的 Intel CPU 中的 SIMD 加载/存储单元和 L1d 缓存之间)。 DDR SDRAM 通过 64 位外部总线以 8x 8 字节传输方式传输 64 字节。


    有趣的是,little-endian 最初是由英特尔为 8008发明的,它将成为或将取代具有位串行 ALU 和地址计算功能的 CPU。由于进位在进行加法/减法时从低位传播到高位,因此位串行机器需要先从低位开始。对于包含绝对地址(以及操作码?)的指令,这意味着将低位放在第一个字节中,将高位放在下一个字节中,因此它可以将 ALU / 地址计算周期与读取一个位的周期重叠一次。

    8008 最终不是是位串行设计,但 ISA 旨在让该选项保持打开状态。请参阅Why is x86 little endian? 获取一些报价。

    但是无论如何,位串行机器想先加载低位。 (通过 1 位总线,使用移位寄存器而不是普通 RAM 进行存储)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多