16位实模式下的物理地址公式:为什么段乘以16?

发布于 2024-09-06 11:04:08 字数 56 浏览 12 评论 0原文

物理地址=16*选择器+偏移量
但我不知道为什么选择器乘以16?

physical address=16*selector+offset
but i don't know why multiplying 16 by selector?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

江挽川 2024-09-13 11:04:09

为了与 Z80 实现“程序员兼容”,同时仍能够使用超过 64 kiB 的内存,早期的英特尔处理器引入了内存分段。 16 位段在添加到 16 位偏移量之前将左移 4 位(意味着乘以 16,而不是您的问题声称的 64),从而产生 20 位地址。

对于习惯了 Z80 的程序员来说,所需要的只是使用操作系统提供的段,并且他们可以随心所欲地使用给定的 64 KB 偏移量。新程序员可以对段进行更复杂的操作,从而允许他们访问 1 MiB 的地址空间(IBM PC 将其减少到 640 kiB,但出于他们自己的原因)。

In order to be "programmer-compatible" with the Z80, yet still be able to use more than 64 kiB of memory, early Intel processors introduced memory segmentation. The 16-bit segment would be shifted left 4 bits (meaning multiplication by 16, and not 64 as your question claims) before being added to the 16-bit offset, resulting in a 20-bit address.

For programmers accustomed to the Z80, all that was required was to use the segments provided by the OS, and they would be able to use the given 64 kilobyte offset as they pleased. New programmers could do more sophisticated manipulation of the segments, allowing them to access 1 MiB of address space (the IBM PC cut it down to 640 kiB, but for their own reason).

最近可好 2024-09-13 11:04:09

8088/8086 的目标是提供一种方法,使 16 位处理器可以拥有 1 MB 的寻址空间,而程序员不必将地址空间划分为 64K 块,并担心地址是否跨越它们之间的边界。尽管它饱受诟病,但它实际上比我见过的处理超​​出寄存器大小的地址的任何其他方法都要好。当数据自然地细分为 64K 或更少的项目,并且可以接受填充项目以从 16 字节边界开始时,它通常可以相对轻松地工作。乘以 16(而不是某个更大或更小的数字)可能是任意的,但是当以十六进制表示法列出事物时,它很方便,并且它是使用两个小数字(这会将地址空间限制为半兆或更少)或太大(这将需要更多代码来处理分配块的任意偏移,或者浪费更多内存填充块到更大的倍数)。

实际上,8088 的分段设计中唯一的主要缺陷是:

  1. 两个通用分段寄存器“完全”不够。一种常见的模式是“将数据从一个对象复制到另一个对象,使用第三个对象对其进行转换”;只有当其中一个对象位于代码段或堆栈中时,才能有效地实现该模式。不幸的是,这个问题直到 80386 才得到修复,其中常见的做法是忽略段。
  2. 没有任何好的方法可以在段寄存器上进行任何类型的算术。从 DS 或 ES(或 FS 或 GS​​)中添加或减去 0x1000 的指令,无论是设置进位还是无条件进位(总共八个(或十六个)操作码)都将极大地方便段处理。
  3. 应该有“mov seg,immediate”指令。

尽管程序员在当时经常抱怨 8088/8086,但它比我当时或之后见过的任何其他 16 位处理器都要好得多(注意:我认为 68000 是 32 位处理器)。

The goal with the 8088/8086 was to provide a means by which a 16-bit processor could have a 1-megabyte addressing space, without programmers having to divide the address space into 64K chunks and worry about whether addresses crossed the boundaries between them. Though it has been much maligned, it is actually better than any other approach I've seen for working with addresses that exceed the register size. It often works relatively effortlessly in cases where data are naturally subdivided into items are 64K or less, and where it is acceptable to pad items to begin on 16-byte boundaries. The multiplication by 16 (instead of some larger or smaller number) was probably arbitrary, but it works out conveniently when listing things in hexadecimal notation, and it was a good compromise between using two small a number (which would have limited the address space to half a meg or less) or too large a number (which would have required more code to either deal with arbitrary offsets for allocated blocks, or else waste more memory padding blocks to a larger multiple).

The only major deficiencies in the 8088's segmentation design, really, are:

  1. Two general-purpose segmentation registers aren't "quite" enough. A common pattern is "copy data from one object to another object, using a third object to translate it"; that pattern can only be implemented efficiently if one of the objects lives in either the code segment or on the stack. It's unfortunate this wasn't fixed until the 80386, where common practice was to ignore segments.
  2. There wasn't any nice way to do any sort of arithmetic on segment registers. Instructions to add or subtract 0x1000 from DS or ES (or FS or GS), either if carry was set or unconditionally--eight (or sixteen) opcodes total--would have greatly facilitated segment handling.
  3. There should have been "mov seg,immediate" instructions.

Even though programmers often grumbled about the 8088/8086 back in the day, it was far better than any other 16-bit processor I've seen then or since (nb: I consider the 68000 a 32-bit processor).

耶耶耶 2024-09-13 11:04:09

64?当然?阅读例如维基百科。乘以 64 就像左移 6 位(维基百科说它应该是 4,即 *16),即就像说选择器代表 22 位地址的最高有效 16 位(维基百科报告为 20)。这也是维基百科中描述的实模式(比我能做的更好)。

64? Sure? Read e.g. wikipedia. Multiplying by 64 is like shifting left by 6 bits (wikipedia says it should be 4, i.e. *16), i.e. is like saying the selector represents the most significant 16 bits of a 22 bits address (wikipedia reports 20). This is real mode as decribed in wikipedia too (better than I can do).

少女七分熟 2024-09-13 11:04:09

我不知道为什么要用选择器乘以 64?

16 位指针可以轻松寻址 64 KB。

CPU 设计者希望能够寻址 1 MB。

因此,他们没有使用单个 16 位指针,而是指定指针将由两个寄存器实现,即段加偏移量,其中“段”是一个 16 位寄存器,其值乘以 16 以寻址1MB。

值 (16) 来自所需地址范围 (1 MB) 除以 16 位寄存器大小 (64 KB) 的自然寻址能力...即 16 来自 1 MB / 64 KB。

i don't know why multiplying 64 by selector?

A 16-bit pointer can easily address 64 KB.

The CPU designers wanted to be able to address 1 MB.

So instead of using a single 16-bit pointer, they specified that a pointer would be implemented by two registers, i.e. segment-plus-offset, where 'segment' is a 16-bit register whose value is multiplied by 16 in order to address the 1 MB.

The value (16) comes from dividing the desired address range (1 MB) by the natural addressibility of the 16-bit register size (64 KB) ... i.e. 16 come from 1 MB / 64 KB.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文