从 01 开始 从 01 开始
首页
  • 计算机简史
  • 数字电路
  • 计算机组成原理
  • 操作系统
  • Linux
  • Docker
  • 计算机网络
  • 计算机常识
  • Git
  • 数据库
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Node
  • Windows 使用技巧
  • 最全面的输入法教程
  • 浏览器
  • 终端软件
  • 装机
  • 笔记类软件
  • Markdown
  • 各大平台
  • 远程控制
  • RSS
  • 图片类工具
  • Office
  • 手机
  • 校招
  • 五险一金等
  • 职场规划
  • 关于离职
  • 杂谈
  • 教程简介
  • 英语学习方法论
  • 字母
  • 音标
  • 单词
  • 语法
  • 英语兔的相关视频
  • Larry 想做技术大佬的相关视频
  • 驾驶技能
  • 住房相关
  • 厨艺
  • 关于税
  • 理财
  • 睡眠
  • 皮肤
  • 口腔健康
  • 学会呼吸
  • 健身日志
  • 电影

    • 电影推荐
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 反腐
  • GFW
  • 404 内容
  • 审查与自我审查
  • 互联网
  • 2022
  • 2023
  • 2024
  • 2025
  • 关于本站
  • 关于博主
  • 网站动态
  • 公告栏
  • 友人帐
  • 从零开始搭建一个博客
  • 搭建邮件服务器
  • 本站分享
  • 文章分类
  • 文章归档

晓林

程序猿,自由职业者,博主,英语爱好者,健身达人
首页
  • 计算机简史
  • 数字电路
  • 计算机组成原理
  • 操作系统
  • Linux
  • Docker
  • 计算机网络
  • 计算机常识
  • Git
  • 数据库
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Node
  • Windows 使用技巧
  • 最全面的输入法教程
  • 浏览器
  • 终端软件
  • 装机
  • 笔记类软件
  • Markdown
  • 各大平台
  • 远程控制
  • RSS
  • 图片类工具
  • Office
  • 手机
  • 校招
  • 五险一金等
  • 职场规划
  • 关于离职
  • 杂谈
  • 教程简介
  • 英语学习方法论
  • 字母
  • 音标
  • 单词
  • 语法
  • 英语兔的相关视频
  • Larry 想做技术大佬的相关视频
  • 驾驶技能
  • 住房相关
  • 厨艺
  • 关于税
  • 理财
  • 睡眠
  • 皮肤
  • 口腔健康
  • 学会呼吸
  • 健身日志
  • 电影

    • 电影推荐
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 反腐
  • GFW
  • 404 内容
  • 审查与自我审查
  • 互联网
  • 2022
  • 2023
  • 2024
  • 2025
  • 关于本站
  • 关于博主
  • 网站动态
  • 公告栏
  • 友人帐
  • 从零开始搭建一个博客
  • 搭建邮件服务器
  • 本站分享
  • 文章分类
  • 文章归档
  • 计算机历史

  • 数字电路

  • 计算机组成原理

    • 网课-计算机组成原理(北大-陆俊林)

      • 概述-计算机组成原理(北大-陆俊林)
      • 第1周-计算机组成章节视频简介
      • 101-电子计算机的兴起
      • 102-冯·诺依曼结构的要点
      • 103-冯·诺依曼结构的小故事
      • 104-计算机结构的简化模型
      • 105-计算机执行指令的过程
      • 106-计算机输入和输出
      • 107-冯诺依曼结构和具体实现
      • 201-设计自己的计算机
      • 202-x86 体系结构
      • 203-x86 指令简介
      • 204-复杂的 x86 指令举例
      • 205-MIPS 体系结构
      • 206-MIPS 指令简介
      • 301-算术运算和逻辑运算
      • 302-门电路的基本原理
      • 303-寄存器的基本原理
      • 304-逻辑运算的实现
      • 305-加法和减法的实现
      • 306-加法器的优化
      • 401-乘法的运算过程
      • 402-乘法器的实现
      • 403-乘法器的优化 1
      • 404-乘法器的优化 2
      • 405-除法的运算过程
      • 406-除法器的实现
      • 407-除法器的优化
      • 501-处理器的设计步骤
      • 502-数据通路的建立
      • 503-运算指令的控制信号
      • 504-访存指令的控制信号
      • 505-分支指令的控制信号
      • 506-控制信号的集成
      • 601-流水线的基本原理
      • 602-流水线的优化
      • 603-超标量流水线
      • 604-流水线的冒险
      • 605-数据冒险的处理
      • 606-控制冒险的处理
      • 701-存储层次结构概况
      • 702-DRAM 和 SRAM
      • 703-主存的工作原理
      • 704-主存技术的发展
      • 705-高速缓存的工作原理
      • 706-高速缓存的组织结构
      • 707-存储容量的计算
      • 801-中断和异常的来源
      • 802-中断向量表的结构
      • 803-中断向量表的发展
      • 804-中断的处理过程
      • 805-内部中断分类说明
      • 806-基于中断的功能调用
      • 901-输入输出接口的基本功能
      • 902-输入输出接口的编址方式
        • 编址方式
        • 分开编址
        • 统一编制
        • 统一编址方式的优缺点
        • 小结
      • 903-输入输出的控制方式
      • 904-中断控制方式
      • 905-外部中断的处理过程
      • 906-直接存储器访问方式
  • 操作系统

  • Linux

  • 计算机网络

  • Git

  • 计算机小知识

  • 数据库

  • 计算机基础
  • 计算机组成原理
  • 网课-计算机组成原理(北大-陆俊林)
2023-06-13
目录

902-输入输出接口的编址方式

# 902-输入输出接口的编址方式

CPU 的运算能力很强, 但它与外界沟通交流的手段却非常地单一, 它总是希望有这样“我给你一个地址,你就给我一个数据”非常直白的沟通方法。 所以它平时也只能和存储器这样胸怀宽广,但是同样头脑简单的家伙在一起玩了。

然而现在它需要面对外界那么多的朋友,各个都非常复杂,有时还经常捣些乱, 那它恐怕就应付不了了,所以它就找了 I/O 接口这样的帮手帮它打理外部的世界, 而它呢还是希望能够用一个简单的方式和 I/O 接口进行交互和沟通。 所以我们就来看一看 CPU 是怎么和 I/O 接口进行沟通的。

‍‍

‍

这是 I/O 接口在计算机系统当中的位置, 和访问存储器中的单元一样,我们想要 CPU 访问 I/O 接口当中的这些寄存器,也是需要通过编写指令来实现,那问题就是,I/O 接口里面的这些寄存器的地址究竟是什么?

​

‍

‍

我们先来看几个基本概念,在系统当中通常会有多个 I/O 接口, 每个 I/O 接口内部都有若干个寄存器,这些寄存器一般被称为 I/O 端口, 我们不要被这个词的字面意义所迷惑, 这个端口指的并不是我们计算机上的 USB 接口、网线接口这样实实在在的接口, 而是一个抽象的概念, 它实际上指的就是这些在 I/O 接口芯片内部的寄存器,它们就像在存储器当中的一个个存储单元一样,CPU 要访问它们,就得有特定的地址, 因此每个寄存器,也就是每个 I/O 端口都需要有自己的地址,这称为端口地址,也叫做端口号。那在计算机系统中, 如何去设定这些端口号就称为 I/O 端口的编址方式。

​

# 编址方式

常见的 I/O 端口编址方式有两种: 第一种是 I/O 端口和存储器分开编址, 又被称为 I/O 映像的方式,x86 体系结构就采用了这种方式。 另一种常见的方式是 I/O 端口和存储器统一编址, 又称为存储器映像的 I/O 方式。 ARM、MIPS、PowerPC 等体系结构都采用了这样的方式。

​

‍

# 分开编址

那我们先来看分开编址的方式。我们假设这个体系结构地址的宽度为 3, 那它一共可以访问的地址单元就是 2 的三次方,总共 8 个, 如果每个单元是一个字节,那它的存储器最大就是 8 个字节

然后我们需要在这个计算机系统当中增加一些 I/O 端口, 那 I/O 端口的地址是重新编排的,和存储器地址无关。 一般情况下,我们需要的 I/O 端口的数量都比存储器单元要少得多, 比如在这个示例的系统当中,我们需要四个 I/O 端口, 那我们就给它分配四个端口号,0、1、2、3,这样的编址方式就称为分开编址。

​

‍

在这种编址方式下,要访问 I/O 端口需要用特殊的指令, x86 提供了 IN 和 OUT 这两条指令, IN 指令用于把 I/O 端口的内容输入到 CPU 当中的寄存器, 而 OUT 指令则是把 CPU 寄存器当中的内容输出到 I/O 端口中。

​

‍

那我们来看一看 IN 和 OUT 指令应该如何书写。 如果要访问的端口地址在 0 到 255 之间,那可以采用两种方式。 一是叫直接寻址,也就是写一个立即数指定端口地址, 例如这条指令,这个 80H 就是一个端口号,那这条指令说的是 从 80H 这个端口读出一个字节的内容,并存放到 AL 寄存器当中去,

而这条指令则是说,将 AX 当中的两个字节的内容,传送到 80H 所指定的 I/O 端口中,当然这个 I/O 端口对应的应该是一个两字节的寄存器。

​

‍

而如果端口地址大于 255,则需要将这个地址先保存到 DX 寄存器当中, 然后再执行 IN 和 OUT 的操作。我们也来看一个例子, 假如我们要访问第 288 号端口, 这时候就需要先把这个端口号存到 DX 寄存器当中, 然后在 IN 和 OUT 指令当中,使用 DX 寄存器来指定端口号,这样就是对 288 号端口地址进行操作。

​

‍

‍

当然,对于端口地址在 0 到 255 之间的,也可以使用间接寻址的方式,那么 x86 为什么要设定这两种方式呢? 主要还是为了指令的长度, 我们看到在直接寻址的情况下,我们需要有一个字节的操作码, 还需要有一个字节保存这个端口号,那么一个字节所能表达的范围就是 0 到 255, 如果端口地址大于 255,那原本就需要再增加一个字节来记录端口号,但这样指令就太长了,为了缩短指令长度,宁可多增加一个指令,这也是 CISC 的特点。

​

‍

所以对于间接寻址,有另外一个操作码, 这条指令只有一个字节,既没有立即数,也没有寄存器的编号, 所以它是默认地采用 DX 寄存器来保存端口地址, 这样在访问更大的端口地址时,指令的长度反而可以更短一些。 那这里就有一个问题,既然用这个方式能访问的地址范围更大,指令长度还更短, 那我们为什么不只用这一种方式呢?还需要去直接寻址这样的方式? 这个问题就留给你自己思考。

‍

‍

‍

那我们再通过一个例子来看一看这样的指令的操作过程。 这条指令是 AL 寄存器当中的一个字节,传送到 21H 这个端口号, 那么当 CPU 从存储器当中取回了这条指令,通过译码发现是一条 OUT 指令, 那它就会将 AL 寄存器当中的内容取出来,放到数据总线上,并将 21H 放到地址总线上, 那么这时候系统总线应该怎么办呢?

我们不妨把系统总线看成城市中的一条街道,而把系统总线所连接的存储器 I/O 接口看成街道两旁的一些建筑,每个建筑里面还有很多个单位,每个单位都有一个门牌号, 那现在就好像有一个快递员接收了一个任务,要把一个包裹送到 21H 这个地址, 于是他就在这个街道上走,查看着每个大楼的门牌号

然后他发现,这两个存储器地址范围,一个是从 0 到 7FFF, 一个是从 80000 到 5 个 F。那么在存储器 1 当中,实际上是包含了 21H 这个地址的, 但他接着再看,这个 I/O 接口 1 当中的地址是 00 到 1F, 而 I/O 接口 2 当中的地址是 20 到 3F,I/O 接口 3 的地址是 40 到 5F,所以在 I/O 接口 2 当中,也包含了 21H 这个地址。 那这个包裹应该送到哪儿呢? 所以单凭这个地址,系统总线是无法判定要访问哪个设备的。

​

‍

因此,CPU 发出的信号中, 除了地址,还应该有一个别的信号,这个信号指明了当天要访问的是存储器还是 I/O 接口。 在 x86 的 CPU 当中,这个信号叫做 M/IO, 当这个信号为 0 的时候,表明当前在访问 I/O 接口,而这个信号为 1 的时候,表明在访问存储器,这样系统总线就知道该怎么办了,它会在所有的 I/O 接口当中, 寻找这个地址所对应的端口,那么这就发现是在 I/O 接口 2 中, 所以系统总线会把这个传输传到 I/O 接口 2,I/O 接口 2 可能是一个独立的芯片, 当它在系统总线上采样到这个地址和一个数据之后,就会在内部找到对应的端口号。

​

‍

我们要注意的一点是,这些 I/O 接口内部一般只有 少数几个端口,所以它只会采样地址的低几位, 然后用这个低位在内部进行索引。在这个例子当中,21H 的这个 2 是系统总线用来找到这个 I/O 接口的,而这个 I/O 接口只用接收到地址的低位这个 1,然后在内部找到对应的端口就可以了。 最后这个 I/O 接口将从数据总线上采样到数据,也就是 AL 寄存器当中的内容, 保存到它内部的数据输出寄存器中,这就完成了这条 OUT 指令所需的操作。至于这个数据输出寄存器它外面是连接到了几个小灯泡,还是一个数码管, 那就是这个 I/O 接口和外射的连接情况了。

​

# 统一编制

然后我们再来看一看 I/O 端口和存储器统一编址的情况。 还是假设地址宽度为 3,那我们在这个统一编址的体系结构当中,总共就只有 8 个单元, 然后根据需要,其中有一部分用来作为 I/O 端口的地址,其他部分用来作为存储单元的地址。

​

‍

那我们之前介绍的模型机就采用了统一编址的方式, 它的地址总线宽度为 4 位,这样一共就有 16 个单元, 而存储器当中用了的地址是 0 到 7,一共 8 个单元。 而输入、输出设备则用了 15 和 16 这两个地址, 另外还有一些地址在这个系统当中没有使用, 那在之后扩展中,可以增加一些存储器,或者增加一些输入、输出端口, 但是总共只有这 16 个,是不可以重复的。

当然,因为它是统一编址的,所以给出任意一个地址,只有唯一的一个单元与之对应, 所以也就不需要刚才 x86 当中使用的 M/IO 这样的信号来指定当前的地址 到底是 I/O 地址还是存储器地址。

​

‍

‍

# 统一编址方式的优缺点

那我们来看一看统一编址方式的优缺点。

首先来看优点。因为在统一编址的情况下,是不区分存储器地址和 I/O 端口地址的, 所以我们就可以直接用访问存储器的指令来访问 I/O 端口,而访问存储器的指令功能通常比较丰富,比如数据可以有各种的宽度,地址也有多种的产生方式,可以是立即数,可以是寄存器,也可以是寄存器加立即数,甚至还可以放在存储器当中, 所以这样就比较方便对 I/O 端口进行处理。

另外,如果要涉及单独的 I/O 操作的指令,无论它做得怎么简单,也是需要额外的一套硬件逻辑, 而采用统一编址的方式,CPU 中只需要有一套对外部总线的控制逻辑就可以了, 内部结构简单,对外的引脚数目也会少一些。

但是统一编址也有它的缺点,由于 I/O 端口占用了 一部分地址空间,从而使用于存储器的地址空间变小了, 这个问题对于早期的处理器影响还是非常大的, 我们想一想,x86 的早期只有 16 位宽的地址,按说只能访问 64KB 的存储器, 它为了有更多的存储器空间,还设计了一个非常复杂的 段加偏移的方式,才能访问一兆的地址空间, 如果在这个时候还要为了 I/O 端口占用了一部分地址空间,那就很难接受了, 这也是 x86 选用了分开编址方式的一个重要原因。

​

‍

‍

而当 CPU 的字长到了 32 位之后, 在很长一段时间,地址空间都不是一个问题, 所以那个时候直接从 32 位起步的 MIPS 就采用了统一编址的方式, 当然现在到了 64 位之后,物理的存储器远远用不了这么大的地址空间, 所以地址空间被挤占这个因素现在已经不成问题了。另外,如果要用访问存储器的指令来进行 I/O 操作,那这些指令往往比单独设计的 I/O 指令要长,而且因为这些指令比较复杂,执行的时间可能也会长一些。这也是 risk 为什么普遍采用了统一编址方式的原因,因为 risk 的指令都是固定长度的, 所以即使设计单独的 I/O 指令,也不会比普通的访存指令更短一些,而 x86 这样的 cisc 采用了变长的指令, 所以就可以设计出更短的专门用于 I/O 的指令,从而提高指令的密度。

‍

‍

# 小结

那么了解了统一编址的特点、分开编址的特点,我们也就清楚了他们的优缺点刚好是相对的,在分开编址的情况下,I/O 端口不会挤占存储器的地址空间, 而且因为涉及了单独的 I/O 指令,它的指令编码可以做得很短,执行速度也比较快, 而 I/O 地址空间一般是远远小于存储器地址空间的, 所以独立的 I/O 指令可以使用较短的地址编码,从而让地址译码变得更为方便。 另外从软件编程的角度来看, 有了单独的 IN 和 OUT 指令,可以很清晰地看出哪些是 I/O 操作, 哪些是存储器操作,让程序的结构变得清晰易懂。 而分开编址的缺点,我们刚才也都已经说完了,就不再重复了。

​

‍

现在 CPU 可以用它习惯的方式和 I/O 接口进行交互, 这确实让事情变得简单了很多,但是这并不意味着 CPU 就可以做甩手掌柜了。 其实 I/O 接口只能帮 CPU 解决一些沟通交互上的琐碎细节, 真正的沟通的核心内容还得 CPU 自己来做。

上次更新: 2024/9/29 12:08:10
901-输入输出接口的基本功能
903-输入输出的控制方式

← 901-输入输出接口的基本功能 903-输入输出的控制方式→

最近更新
01
2025 年 2 月记
02-28
02
最全面的浏览器教程-完结撒花
02-16
03
这个工具可以轻松搞到你的浏览器账户密码!
02-15
更多文章>
Theme by Vdoing | Copyright © 2022-2025 | 粤 ICP 备 2022067627 号 -1 | 粤公网安备 44011302003646 号 | 点击查看十年之约
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式