x86中的IN&OUT指令用于什么?

cla*_*aws 55 x86 assembly linux-kernel

在阅读"理解Linux内核"一书的同时,我已经在IN&OUT中遵循了这些指令.我查阅了参考手册.

5.1.9 I/O指令

这些指令在处理器的I/O端口和寄存器或存储器之间移动数据.

IN    Read from a port
OUT   Write to a port
INS/INSB  Input string from port/Input byte string from port 
INS/INSW  Input string from port/Input word string from port 
INS/INSD  Input string from port/Input doubleword string from port
OUTS/OUTSB    Output string to port/Output byte string to port 
OUTS/OUTSW    Output string to port/Output word string to port 
OUTS/OUTSD    Output string to port/Output doubleword string to port
Run Code Online (Sandbox Code Playgroud)

我没有得到一些东西:

  1. "处理器的I/O端口".这些是什么?为什么我们要在这些端口上读取和写入"字符串"?
  2. 我从来没有遇到过需要使用这些说明的场景.我什么时候需要这些?
  3. 举一些实际的例子.

Car*_*icz 88

您知道内存寻址的工作原理吗?有地址总线,数据总线和一些控制线.CPU将地址总线的字节(或起始字节)的地址放在地址总线上,然后提高READ信号,一些RAM芯片希望通过升高或降低单个行(对应于位)返回该地址的存储器内容在数据总线上的字节中.这适用于RAM和ROM.

但此外还有I/O设备:串行和并行端口,PC微型内置扬声器的驱动程序,磁盘控制器,声音芯片等.这些设备也可以读取和写入.它们还需要被寻址,以便CPU访问正确的设备和(通常)给定设备中的正确数据位置.

对于某些CPU型号,包括大多数"现代"PC中的xxx86系列,I/O设备与内存共享地址空间.RAM/ROM和IO设备都连接到相同的地址,数据和控制线.例如,COM1的串行端口从(hex)03F8开始寻址.但几乎可以肯定的是同一地址的记忆.

这是一个非常简单的图表:

[https://qph.ec.quoracdn.net/main-qimg-e510d81162f562d8f671d5900da84d68-c?convert_to_webp=true]

显然,CPU需要与内存或I/O设备通信,而不是两者都要.为区分这两者,称为"M /#IO"的控制线之一断言CPU是否要与存储器(线路=高电平)或I/O设备(线路=低电平)通信.

IN指令从I/O设备读取,OUT写入.当您使用IN或OUT指令时,M /#IO未置位(保持低电平),因此存储器不响应而I/O芯片也会响应.对于面向内存的指令,M /#IO被置位,因此CPU与RAM通信,IO设备不通信.

在某些条件下,IO设备可以驱动数据线,RAM可以同时读取它们.反之亦然.它叫做DMA.

传统上,串行和打印机端口,以及键盘,鼠标,温度传感器等都是I/O设备.盘子介于两者之间; 数据传输将由I/O命令启动,但磁盘控制器通常会将其数据直接存入系统内存.

在Windows或Linux等现代操作系统中,对"I/O端口"的访问远离"普通"用户程序,并且存在多层软件,特权指令和驱动程序来处理硬件.所以在本世纪,大多数程序员都没有处理这些指令.

  • 你能推荐一本我可以阅读更多相关内容的书吗?你的回答很好,谢谢! (4认同)
  • 做得好。感谢您的解释。由于我接受的严格的 MMIO 教学,长期以来我一直对 IO 空间的概念感到困惑。内存和 IO 可以被认为是可以自行寻址的,这一事实让我因为没有早点理解这一点而感到有点尴尬。 (2认同)
  • 我不知道这个答案对于 8086 PC/AT 或其他东西可能是准确的。但没有提及 MMIO 似乎是一个疏忽。另外,“*与内存共享地址空间*”与您的观点相反:I/O 空间和内存空间是“不同的”地址空间,但对它们的访问恰好共享物理总线。我不会尝试编辑,因为我想重写其中的大部分内容:/ (2认同)

old*_*mer 24

从这样的事情开始:

http://www.cpu-world.com/info/Pinouts/8088.html

您正在学习非常古老的技术芯片/架构的说明.当处理器核心以外的所有东西都在芯片外时.查看地址线和数据线,还有RD读取线和WR写入线以及IO/M线?

有两种类型的指令基于内存和基于I/O,因为有可寻址的空间,可以通过IO/M IO或内存轻松解码.

记住你有74LSxx胶合逻辑,大量的电线和大量的芯片将内存连接到处理器.而记忆就是内存,昂贵的芯片.如果你有一个需要的外围设备做任何有用的事情你也有控制寄存器,内存可能是像素数据,但你需要设置水平和垂直扫描时钟限制,这些可能是单独的74LSxx锁存器,而不是存储器,有我/ O映射I/O保存在两个胶合逻辑上,从程序员的角度来看,它也很有意义,它也避免了改变你的段寄存器来瞄准你的64K内存窗口,等等.内存地址空间是一个神圣的资源,尤其是当你想要将地址解码限制为几位,因为每一个位都会花费你很多芯片和线路.

像大端和小端内存映射I/O与I/O映射I/O是一场宗教战争.你将在你的问题中看到的一些回应将反映出现在仍然存在的强烈意见.现实情况是,目前市场上的每个芯片都有多种功能,你不要用ddr存储器总线将实时时钟与地址解码器挂起.有些甚至还有完全独立的指令和数据总线.在某种意义上,英特尔赢得了针对不同类别事物的单独地址空间概念的战争,即使术语I/O端口是邪恶和坏的,并且不应该说20-30年多.在战争真正结束之前,你需要我这个年龄相仿的人退休或离开.甚至术语内存映射I/O也已成为过去.

实际上就是这一切,通过使用特定指令控制的intel芯片外部的单个地址解码位.使用一组指令,该位正在使用一组指令,该位已关闭.想看看有趣的东西看看xmos xcore处理器的指令集,它们有许多指令而不是内存映射寄存器,它将这个I/O映射的I/O事物带到一个全新的水平.

在我使用的地方就像我上面所描述的那样,你可以放置有意义的东西,你可以为像视频像素,网络数据包内存(可能),声卡内存一样烧掉内存地址空间(不是你可能有的)并且控制寄存器,相对于数据的地址空间非常小,可能只有少数寄存器,在I/O空间中被解码和使用.显而易见的是串行端口和并行端口,它们几乎没有任何存储空间,如果有的话,你可能在串口上有一个小的fifo.

因为地址空间很少,所以现在仍然可以看到内存隐藏在两个寄存器后面的地址寄存器和一个数据寄存器,这个存储器只能通过这两个寄存器使用,它不是存储器映射的.因此,您将偏移量写入地址寄存器中的此隐藏存储器,并读取或写入数据寄存器以访问存储器的内容.现在因为intel有rep指令,你可以将它与insb/w outsb/w结合起来,硬件解码器会(如果你有好的/友好的硬件人员与你一起工作),每当你进行I/O循环时自动增加地址.因此,您可以在地址寄存器中写入起始地址并执行转发操作,而无需在处理器和内存总线上刻录获取和解码时钟周期,您可以将数据快速移入或移出外设.由于具有基于分支预测的提取的现代超级标量处理器,这种事情现在被认为是设计缺陷,您的硬件可以随时体验与执行代码无关的读取,因此您不应该自动增加地址寄存器中的地址或清除位,或者由于读取地址而修改任何内容.

内置于386和现在的保护机制实际上使得从用户空间访问I/O变得非常容易.取决于你的生活,你公司生产的东西等等.你绝对可以使用来自用户空间(Windows和Linux等应用程序)或内核/驱动程序空间的进出系列指令,这是你的选择.你也可以做一些有趣的事情,比如利用虚拟机并使用I/O指令与驱动程序交谈,但这可能会惹恼Windows和Linux世界中的人,驱动程序/应用程序不会让它变得很远.其他海报是正确的,除非您正在编写驱动程序,否则您可能永远不需要使用这些指令,并且您可能永远不会为使用I/O映射I/O的设备编写驱动程序,因为您知道... 这些遗留设备的驱动程序已经编写完成.现代设计绝对有I/O但它是所有内存映射(从程序员的角度来看)并使用内存指令而不是I/O指令.现在其他方面,如果这是DOS肯定没有死,取决于你可能正在建立投票机或加油泵或收银机或一长串基于DOS的设备.事实上,如果您在某个地方构建基于PC或PC的外围设备或主板,基于DOS的工具仍然广泛用于测试和分发BIOS更新和其他类似的东西.我仍然遇到了必须从当前的dos测试程序中获取代码来编写linux驱动程序的情况.就像不是每个人都能在NFL中投掷或接球一样,百分比方面很少涉及这种东西的软件工作.因此,您可以安全地说出您发现的这些说明可能不会比历史课更多.


Cir*_*四事件 14

举一些实际的例子.

首先学习如何:

  • 创建一个最小的引导加载程序操作系统并在QEMU和真实硬件上运行它,如我在此解释的那样:https://stackoverflow.com/a/32483545/895245
  • 做一些BIOS调用来做一些快速而脏的IO

然后:

  1. PS/2控制器:获取键盘上键入的最后一个字符的扫描码ID al:

    in $0x60, %al
    
    Run Code Online (Sandbox Code Playgroud)

    最小的例子

  2. 实时时钟(RTC):获取定义秒数的挂起时间:

    .equ RTCaddress, 0x70
    .equ RTCdata, 0x71
    
    /* al contains seconds. */
    mov $0, %al
    out %al, $RTCaddress
    in $RTCdata, %al
    
    /* al contains minutes. */
    mov $0x02, %al
    out %al, $RTCaddress
    in $RTCdata, %al
    
    /* al contains hour. */
    mov $0x04, %al
    out %al, $RTCaddress
    
    Run Code Online (Sandbox Code Playgroud)

    最小的例子

  3. 可编程间隔定时器(PIT):每秒产生一个中断号8 0x1234 / 1193181:

    mov $0b00110100, %al
    outb %al, $0x43
    mov $0xFF, %al
    out %al, $0x34
    out %al, $0x12
    
    Run Code Online (Sandbox Code Playgroud)

    最小的例子

    一个Linux内核4.2的使用.还有其他人.

测试:QEMU 2.0.0 Ubuntu 14.04,以及真正的硬件联想ThinkPad T400.

如何查找端口号:是否有x86 I/O端口分配的规范?

https://github.com/torvalds/linux/blob/v4.2/arch/x86/kernel/setup.c#L646列出了Linux内核使用的许多端口.

其他架构

并非所有架构都具有此类IO专用指令.

例如,在ARM中,IO只需写入魔术硬件定义的内存地址即可完成.

我认为这就是/sf/answers/225528761/的意思是"内存映射I/O与I/O映射I/O".

从程序员的角度来看,我更喜欢ARM方式,因为IO指令已经需要魔术地址来操作,并且我们在64位寻址中有大量未使用的地址空间.

有关具体的ARM示例,请参阅/sf/answers/2804412271/.


sup*_*cat 5

在硬件级别,大多数微处理器没有内置或几乎没有内置I / O功能。一些处理器具有一个或多个可以使用特殊指令打开和关闭的引脚,和/或一个或多个可以使用特殊指令测试的引脚。分支指令,但是这种功能很少见。取而代之的是,通常通过连接系统来处理I / O,以便对一系列内存地址的访问将触发某种效果,或者包括“ in”和“ out”指令,它们的行为类似于内存加载/存储操作,但特殊信号除外输出说“这是一个I / O操作,而不是存储操作”。在16位处理器时代,拥有专门的输入/输出指令曾经有一些真正的优势。如今,这种优势在很大程度上尚无定论,因为一个人可以简单地分配一大笔钱。

由于程序可能通过不适当地执行I / O指令(例如,此类指令可能执行任意磁盘访问)而对系统造成巨大破坏,因此所有现代操作系统都禁止在用户级代码中使用此类指令。某些系统可能允许将此类指令虚拟化。例如,如果用户代码试图写入I / O端口0x3D4和0x3D5,则操作系统可能会将其解释为试图设置一些视频控制寄存器来移动闪烁的光标。每次用户程序执行OUT指令时,操作系统将接管工作,查看用户程序试图执行的操作并采取适当的措施。

在大多数情况下,即使操作系统将IN或OUT指令转换为合适的指令,直接向操作系统请求适当的操作也会更有效。


Chr*_*ine 5

使用诸如“I/O 信号”和“内存映射”之类的名称,一切都比实际情况复杂得多,因此给人的印象是它还有更多内容,并且涵盖了高级主题。现在的趋势是人们将其视为新事物。但事实并非如此。即使是 1830 年代的巴贝奇也驾驶着他的打印机,这需要 I/O 信号,尽管是通过轴和齿轮完成的。例如,在2000年前的亚历山大英雄的机器中或在希腊时代的剧院中,他们总是从一组不同的绳子中拉出一根绳子来控制灯光或布景,每根绳子就像一条输入和输出线,就像就这么简单,地址是“哪一行”,即我们选择的东西、内存或设备,数据是您传递到该内存或设备或从该内存或设备读回的信息。

尽管建筑物中充满机柜的大型主机在 40 年代就使用了 64 位之类的东西,因此很久以前就以相同的方式处理 I/O 映射,例如 Konrad Zuse 和他的房间大小的计算机使用浮动在 1930 年代,这个点的十进制数大约为 20 位,并且必须驱动打印机、各种灯泡指示器和开关等设备。但在微型微处理器上,情况就不同了,直到 60 年代才被设想,直到 1971 年才被构建。所有这些技术在 80 年代使用 8 位逻辑,在 70 年代用于 4 位微处理器,在 60 年代用于 2 位微处理器,并被使用在 90 年代的 16 位时代,当时每个人都开始拥有计算机,因此因为它现在摆在他们面前,所以第一次开始讨论这个 I/O 和内存映射主题,它似乎是随着计算机的出现而出现的新事物互联网的;然后我们在 00 年代有了 32 位计算机,在 10 年代有了 64 位计算机,这导致了对数据线内存的无休止的讨论。为了回答你的问题,我将谈论 30-40 年前电子爱好者购买的芯片,就像我当时所做的那样,因为后来,事情变得如此先进,我无法用后来的芯片来构建,但是现在的原理是一样的,门只是隐藏在更大的黑盒芯片内,这些芯片包含其他引脚,这些引脚处理更多并行进行的这些操作(例如,启用许多八进制锁存器,同时启用许多芯片),并且数据和地址总线有更多的线,这是唯一的区别。

好吧,我对所有新语言一无所知,也不知道它在现代 PC 上的情况如何,但我可以告诉你过去我用芯片构建计算机时的情况。

所有 I/O 映射和内存映射的意思简单来说,就是如果您为了某种庆祝而挂起一堆灯泡,并用电线连接每个灯泡并称为内存位置(即灯泡代表 RAM 中的内存,或者开或关,如果您选择位置 0,您将得到电线 0、位置 1、电线 1、位置 2 电线 2 等等)如果您添加了更多电线,例如一根电线是铃,则该特定位置不是内存是一个设备,您可以使用 OUT 命令将其输出到该设备,以使其响铃。但从计算机的角度来看,它被视为内存位置,因为它同样作为连接 MPU 的线路。如果添加另一根电线,即您在外部操作的开关,则这是一个 I/O 设备,这将是一条到 PC 的 IN 指令。所以这称为 I/O 映射 I/O。

现在在计算机上,总线上的电线代表地址线或数据线,但它们是二进制的,即用2条线你可以有00 01 10 11即4个组合2^2,所以用8条线2^8=256种可能性, 20 行 2^20=1048576 30 行 2^30=1073741824 (1 gig) 30 行的可能性。因此,这就是为什么它被称为 MAPPED,而不仅仅是说 I/O 和内存,而是说 I/O 映射和内存映射,因为您将电线映射为二进制编码的组合。因此,如果说你有 2 根线,4 种组合,它们不能只连接到灯泡(更不用说 MPU 的微小电压所需的电流放大,以及防止反馈电流),但是 2 根线有通过解码器(我们过去使用 138 将 3 行解码为 8 行,使用 164 将 4 个二进制行解码为 16 行。)一旦通过解码器,这 2 行例如 A0 和 A1(地址 0 和地址 1(行) )),对于您正在驱动的特定灯泡(在计算机上的情况下,内存)变成 4 条线(开或关),但在某些情况下,这些位置而是选择一些输入/输出设备,并说“使用我”相反,即像存储器一样,一旦定位,数据就会通过数据总线 D0..7 或 D0..31 或其他任何方式以一种方式或另一种方式传递(使用巧妙的三态逻辑来切断每次路上的电压)计算机上数据的大小(您有一台 2 位、4 位、8 位、16 位、32 位、64 位、128 位、256 位计算机,无论您正在构建什么计算机)。因此,数据自然地从数据线传入或传出到内存或 I/O 设备(如果它是内存映射的),但这不应该与 IN/OUT 指令混淆,这个 IN 和 OUT 意味着来自某些其他 I/O 内存块,MPU 内专门为 I/O 分配的特殊 I/O 内存块,即(不是内存映射),这个 I/O 空间在某些微处理器上并不总是获得,例如我不我认为 6502 上没有,但 z80 上有。更多艺术芯片仅使用内存映射,例如在游戏机等中,更明智但无趣(留在书中)的芯片也用于 I/O 空间。内存映射 I/O 速度极快,因为它包含内存寻址(对于 RAM 来说速度超快),因此图形类型计算机仅使用 I/O 内存映射来获得速度。I/O 映射 I/O 分配给慢速端口,例如 rs232 或并行端口,并使用 IN OUT 命令。

现在,如果不是添加两根电线,而是实际上更换了最初连接灯泡的两根电线,并取出其中一些灯泡并用其他东西替换它们,例如一根电线上的铃和另一根电线上的开关,那么现在不会引用这些电线(选择) )分别使用 IN 和 OUT 指令,通过访问选择这些电线(最初是灯泡)的特定内存位置来引用它们。这就是内存映射 I/O。

内存映射 I/O 意味着通常连接到内存(RAM)的实际地址总线也连接到其他解码器(逻辑解码器),当它感测到地址信号的特定二进制组合时,它会产生一个输出高电平,(例如,如果您有一个与和非门的负载,并且您说,如果这个而不是那个等等,使用引脚A0..A20或您的地址总线的任何大小),那么这个高信号启用锁存器, (对于特定设备,如串行端口、并行端口),该锁存器将数据总线上的数据传递到 I/O 设备。这是为了写入 I/O 设备。读取的工作方式相反,I/O 设备将数据传回,如果我没记错的话,它将完全相同的地址代码组合发送到地址线上。

我想,今天它也必须以同样的方式工作,只不过它们只是更多的数据和地址线。

您实际上是将 I/O 连接到地址线。因此,I/O 被有效地映射到内存空间,就好像它是内存一样。但另一个锁存器会禁止地址引脚同时访问RAM,这样您就不会在同一行上获得两个地址或数据源的电压,这会损坏芯片。

40 年前,我们在 z80 芯片上就有了 IN 和 OUT 指令。这是针对芯片实际上以不同方式处理 I/O 本身的特殊情况,即它不是内存映射的。(即,使用内存映射时,您只需读取或写入内存位置,但使用 IN 和 OUT 时,您已经告诉 CPU 这是一个 I/O 信号而不是内存)。因此,对于 IN/OUT 指令,它有自己的 I/O 地址空间(这是 RAM 内存的额外部分),这个 I/O Ram,正如它看起来的那样,有一组相同的地址,除非您通过附加到这些 I/O 地址的解码器直接访问设备,并且您不是从标准地址引脚访问 I/O 设备,这是针对 IN/OUT 指令的。

当您输入和输出字符串时,我不知道 x86,但这可能意味着您正在数据总线上多次发送或接收数据(使用所有数据引脚 D0..D15 或数据总线的任何大小)以该特定 I/O 设备可能的最大数据速率(也许要执行此操作,它使用某种握手信号,您必须查找它。)因此,D0..63 线路(或 D0.63 线路)上的数据。旧电脑上的 .31 或 80 年代末 90 年代初电脑上的 D0..15,或 D0..7 或 80 年代和 80 年代前的电脑,是一个接一个的系列,而不是仅一次与 IN 和 OUT。即 INSTR 和OUTSTR 只是在某个定义的数据速率下的多个 IN 和 OUT。例如,如果您正在访问互联网,您每次都希望输入和输出大量信息,因此您将使用输入和输出数据字节,这对于这种情况,最好将字母和数字作为 ASCII 代码字符串传递。这些命令与在循环中使用 IN 和 OUT 指令完全相同,其中计数是字符串长度。

如果您正在访问例如电脑扬声器,您只需使用 OUT 一次传递一项数据。

如果您从并行端口读取数据,则需要执行 IN 操作,并使用端口 I/O 地址的代码。写入它,例如通过电子信号驱动旧打印机或机器人,您可以使用 OUT 命令。并行端口和串行端口(旧的RS232)是使用的典型端口。RS232 是串行数据,只允许输入或输出一位,因此如果您从 rs232 读取数据,则只有 1 位相关的字节,与输出相同。rs232 的波特率最大约为 17kHz,但它们经常用于驱动电子设备,以前,我曾经构建 rs232 电路,例如读取电压或驱动 PIC 微控制器。每个端口被命名为 COM1 COM2 COM3 COM4,并且它们具有 I/O 地址。我不确定这里,但它们类似于例如 3F8h 378h (h=十六进制地址)

我不确定现代端口,但如果您要写入 USB,这很可能是内存映射 I/O 以提高速度。

PS/2键盘端口,我认为这个使用IN指令,从键盘读取数据。它取代了旧的 RS232,但我认为规格略有不同。

磁盘驱动器通常是内存映射的,大概现在仍然如此,即您不使用 IN/out 指令驱动磁盘驱动器,它们会太慢。但端口无论如何都很慢,所以没关系,例如,与硬盘所需的极好的数据速率(例如200兆字节/秒)相比,打印机所需的数据速率很慢。一个扬声器,它只需要声音频率的10或20倍左右,比如20kHz对于蜂鸣器来说就足够了,因此它是I/O。慢速事物使用 I/O、IN/OUT 指令。因此,USB 现在可能已映射内存,您必须对其进行检查。

更好的理解方式是这样的。在 80 年代的旧计算机上,有时您想要控制自己构建的某些设备,并且没有输出端口的规格(因为当时制造商将其隐藏起来,以便某些公司(例如操纵杆和卡带公司)可以在市场通过一些商业交易)。您所要做的就是打开计算机,并将电线焊接到地址总线上的某些点,例如,您将三根电线焊接到电路中的某些点,保持安全距离(以免热量损坏芯片),这些通过电路板布局将点连接到例如微处理器上的引脚A15、A7和A1。而且您通常还必须连接一条 MREQ 线(一条内存请求线和/或 RD/WR 线以产生更整齐的信号,并将其添加到与或非逻辑中,但如果您很聪明,您可以这样做它与地址线)然后连接这三根线+这个额外的就绪类型信号(例如MREQ RD或WR线以给出一些有效的低或高(这里可能需要一个额外的非门)来表示数据已准备好现在的线)通过4输入与门,通过200欧姆电阻向LED提供输出,您拥有将自己的内存映射到LED灯的高速I/O,您可以通过SR锁存器锁存该灯或D型锁存器将其存储在某些电路板上外部的1位存储器中。这里 15 是 32K 行,7 是 64 行,1 是 2 行(二进制以 2 的幂计算,所以 A1 是 2^1,A7 是 2^7,A15 是 2^15),所以如果你寻址位置 32768+64+2=32834 = F041(十六进制),在汇编器中的旧 MPU 上使用 LDA 或 STA 或 LD,您将输出到此 LED,如果电阻约为 100 欧姆,它会亮起。现在您已经完成了内存映射 I/O,尽管很简单,您今天也可以通过同样焊接到您的 MPU 地址线来完成。但由于电路的精密性,你现在不会这样做。但您也可以加入数据线 D0..7(过去)或在旧的 486 PC 上为 32 位添加 d0..31。然后,如果您通过加载值 8(现在为 mov ax,8)的累加器来寻址机器代码中的该位置,或者将该累加器值存储到地址位置(mov F041h,ax 累加器,您甚至今天也会得到导致请注意,示例中的 8 是数据总线上的内容,在这种特殊情况下,我们不传递数据,我们只是启用特定设备(LED 亮起,如果我们选择了该 I/O 设备,这里,只是一个 LED),所以在这个例子中,MOV ax,8 指令的数字并不重要,它可能是例如 mov ax,243,并且当我们仍然启用 F041h 行上的 LED 时,然后我们执行mov F041h,因为我们使用相同的地址。你看,有地址线和数据线。所以当你在COM1中寻址3F8或任何地址时,I/O内存映射只是发送输出到端口的信号,例如 ps/2,与门正在检查行上是否有 1110000100,即 11 是 3,1000 是 F,0100 是 8,请参阅二进制到十六进制转换。如果高电压出现在有 1 的位位置,则端口(例如 rs232 或 ps/2)被设置为活动状态,即已启用,这将通过 CE 芯片启用信号或 CS 芯片启用锁存器选择简单。

在锁存器上,它是 E 使能引脚或 OE 低电平有效输出使能。即,在上面描述的示例中,我们使用地址来选择(通过解码)我们想要使用哪个 I/O 设备(即,在示例中,如果选择了该 I/O 设备,则 LED 亮起。所以这是启用线.然后,一旦选择了I/O设备,那么数据就会从数据总线(过去的D0..7,或者现在64位计算机的D0..63)传递,通过旧的八进制锁存器373这些是D型触发器电路,它们将数据存储在触发器内部。在高电平有效的时钟沿下,数据通过并被存储。该时钟沿将来自数据信号上的“DATA RDY”信号,这个有各种各样的名字,我现在不知道名字是什么。所以对于64位,我们有8个八进制锁存器。它们使用双向锁存器来控制数据的任一方式或三态,这样当我/O 设备未使用,数据线处于高阻状态,因此您可以通过地址线上的组合来选择 I/O 设备,这是数字,例如 OUT 3F8h 中的 3f8h,7,数据在示例 7 中, 是在数据线上传递的内容,在 OUT 命令中,数据将 OUT 传递到数据锁存器,然后传递到 I/O 设备。如果你有 IN,你会执行一个命令,例如 IN 3f8h,800h,(我期望,但我不知道 x86 汇编器的语法),我的意思是,对于 IN,你正在输入来自数据线(在选择地址后,例如这里的 3f7h,它选择那个 I/O 设备),该数据来自 I/O 设备,通过数据锁存器中的 D 型触发器(一个对应于数据锁存器中的每一位)数据总线),并输入到 MPU 微处理单元上的 D0..7 或(现代 PC 上的 D0..63)引脚。在此示例中,我输入 IN 3f8h, 800h,以表明数据进入后将存储到地址 800h 中。我认为x86的语法是不同的,你可能必须做 IN 3f8h, ah 或类似的事情,即首先将数据输入到寄存器中,然后你会 MOV 800h, ah 即将数据移动到内存中RAM 中的位置(如果您想存储它),或者使用 ah 等执行其他操作。 ah 是一个示例寄存器,它可以是任何、al、bh、bl 等,但检查语法,每个汇编系统都是略有不同,我不是x86专家。再次,我使用 3f8h 作为示例 I/O 地址,有数百个,可能数千个这样的地址,例如 378h。有关完整列表,请参阅 IBM PC 的 I/O 内存映射。

而当您访问内存时(RAM,例如 70 年代的 64 字节静态 RAM 和动态 RAM,80 年代的 8K SRAM 和 DRAM,90 年代和现在的 SIMMS 行每行都有几兆字节(单行内存模块)是包含 DIMM 的 DDR 模块、双列直插内存模块的形式,我还没有检查过,但最新的可能无疑每个小芯片上都有几 GB),如果它不是 I/O 地址(非常很少有地址是 I/O 地址,如今内存是现代 PC 上 I/O 地址空间的数百万倍或更可能),您仍然使用相同的读写数据指令到内存,但您不是驱动一些寻找这些位的外部逻辑电路,而不是将这些地址和数据引脚直接连接到 RAM 芯片。

在机器代码中,I/O 和内存寻址看起来是相同的,就好像它们都是内存访问一样,但在实际电子电路中物理上发生的情况完全不同。