计算机组成原理

计算机组成原理

第一章 计算机系统概述

1.1 计算机的基本概念

电子计算机是一种可以存储程序,并且通过执行程序指令,可以自动、高速、精确地对数字信息进行各种复杂处理,然后输出运算结果的高科技智能电子设备。这一定义涵盖了计算机的核心特征:存储程序能力、自动执行能力、高速运算能力、精确处理能力和信息输出能力。计算机之所以能够实现如此强大的功能,其根本在于它将复杂的运算过程分解为一系列最基本的操作步骤,并通过程序来控制这些步骤的执行顺序和方式。

5 个逻辑模块:输入设备、存储器、输出设备、运算器、控制器。

(如今运算器和控制器已集成在 CPU 中)

这五大逻辑模块的划分最早源自1946年冯·诺依曼提出的存储程序思想。在实际的计算机硬件中,运算器和控制器被集成在同一块芯片上,形成了今天我们所熟知的中央处理器(Central Processing Unit,CPU)。这种集成方式不仅减少了芯片之间的信号传输延迟,还显著提高了系统的整体性能和可靠性。现代CPU内部还集成了高速缓存(Cache),进一步缩短了数据访问时间。五大模块之间的协同工作关系可以概括为:输入设备负责将外部信息转换为计算机可识别的数字信号并送入存储器;存储器负责保存程序和数据;运算器在控制器的指挥下对数据进行加工处理;控制器从存储器中取出指令并产生控制信号驱动各部件协调工作;输出设备将处理结果转换为人或其他设备可接受的形式输出。

1.1.1 信息的数字化表示

信息的数字化表示是计算机科学的基本前提,也是冯·诺依曼体系结构的根基。其核心思想包含以下三个层面:

  1. 在计算机中用数字代码(二进制代码)表示各种信息。无论是数值、文字、图像、声音还是视频,最终都要转换为二进制编码的形式才能被计算机识别和处理。这种统一的信息表示方式使得计算机能够用同一套硬件逻辑来处理各种不同类型的信息,极大地简化了计算机的硬件设计。例如,英文字母’A’用ASCII码表示为01000001,汉字”中”用Unicode编码表示为0100111000110110,一幅数字照片的每个像素点用若干位二进制数表示其颜色信息。
  2. 在物理机制上用数字信号(数字型电信号)表示数字代码。数字信号与模拟信号的根本区别在于:数字信号只有离散的高电平和低电平两种状态,分别对应二进制的1和0。这种双稳态的物理表示方式具有极高的可靠性——即使信号在传输过程中受到一定程度的干扰,只要干扰不超过阈值,接收端仍然能够正确地判断出信号的原始状态。这也是数字计算机比模拟计算机具有更高可靠性的根本原因。在具体的电路实现中,高电平通常对应3.3V或5V,低电平对应0V,两者之间存在明显的电压差,从而提供了充足的噪声容限。
  3. 信息数字化表示的优点:
    • 物理上易实现信息的表示与存储。二进制只需要两种稳定的物理状态,可以用开关的通断、电容的充放电、磁畴的极化方向等多种物理手段来实现。存储介质从早期的磁芯存储器、磁鼓,发展到半导体存储器(SRAM、DRAM)、磁盘和光盘,其基本原理都是利用某种物理现象来表示0和1两种状态。
    • 抗干扰能力强,可靠性高。由于数字信号只有高低两种状态,具有天然的噪声容限,即使信号在传输或存储过程中发生了畸变,只要畸变不超过判定阈值,仍然可以正确恢复原始信息。这一点在长距离通信和长期存储中尤为重要。
    • 数值表示范围大,精度高。通过增加二进制位数,可以表示任意大的数值和任意高的精度。例如,32位二进制可以表示0到约43亿的整数范围,64位二进制可以表示0到约1.8×10¹⁹的整数范围。浮点数表示更是能够覆盖从极小到极大的数值范围。
    • 可表示的信息类型广泛。通过不同的编码方案,二进制代码可以表示数值、字符、图像、声音、视频等几乎所有类型的信息。这种统一性是计算机成为通用信息处理工具的基础。
    • 能用数字逻辑技术进行处理。二进制运算可以通过逻辑门电路(与门、或门、非门、异或门等)来实现,而这些基本逻辑门又可以组合成加法器、移位器、比较器等复杂的功能电路,最终实现各种算术和逻辑运算。

1.1.2 存储程序工作方式

存储程序工作方式是冯·诺依曼体系结构的核心思想,也是现代计算机能够自动运行的根本保证。其工作流程可以概括为以下四个步骤:

  1. 编制程序。程序员根据需要解决的问题,用某种程序设计语言编写程序。程序是由一系列指令组成的指令序列,每条指令规定了计算机应执行的一种操作以及操作所需的操作数或操作数的地址。编制程序的过程实际上就是将人类的思维逻辑转化为计算机可执行的指令序列的过程。
  2. 存储程序。将编写好的程序和所需的数据通过输入设备送入计算机的存储器中保存。这一步是存储程序工作方式的关键所在——程序和数据一样,都以二进制代码的形式存储在存储器中,计算机在执行程序时可以自动地从存储器中依次取出指令并执行,而不需要人工干预。这种”程序存储”的思想使得计算机具备了自动、连续执行程序的能力,区别于早期的ENIAC那样需要人工接线来设置程序的方式。
  3. 自动、连续执行程序。计算机启动后,控制器从存储器中按顺序取出指令,对指令进行分析译码,产生相应的控制信号,驱动运算器、存储器等部件完成指令规定的操作,然后自动取下一条指令继续执行,如此反复,直到程序结束或遇到停机指令。整个过程不需要人工干预,实现了计算的自动化。指令的执行过程通常分为取指、译码、执行、访存、写回等阶段,现代CPU通过流水线技术使这些阶段重叠执行,从而大幅提高指令吞吐率。
  4. 输出结果。程序执行完毕后,将处理结果通过输出设备输出给用户。输出形式可以是数字、文字、图形、声音等。

计算机的工作流程:编写程序→输入程序→存储程序→转换为指令序列→执行指令→输出结果。这一工作流程体现了存储程序工作方式的本质——程序和数据统一存储在存储器中,计算机按照程序规定的顺序自动执行指令,无需人工干预。这一思想至今仍是绝大多数计算机系统的基本工作原理。

1.1.3 计算机的分类

计算机从总体上来说分为两大类:模拟计算机数字计算机

特点:

  • 模拟计算机:由模拟运算器件构成,处理在实践和数值上连续的模拟量(如:电压,电流等)。模拟计算机的运算速度极快,因为它直接利用物理量之间的数学关系进行运算,不需要进行数值计算。但模拟计算机的精度受限于物理器件的精度,难以实现高精度计算,且编程灵活性差。随着数字技术的发展,模拟计算机在大多数领域已经被数字计算机所取代,但在某些需要实时高速信号处理的场合(如模拟滤波器、模拟仿真)仍有应用。
  • 数字计算机:由数字逻辑器件构成,处理离散的数字量。数字计算机具有精度高、通用性强、存储容量大、逻辑判断能力强等优点,是目前主流的计算机类型。

其中数字计算机又可分为专用计算机通用计算机。专用计算机是为特定用途而设计的,其硬件和软件都是针对某一类应用问题优化的,如工业控制计算机、嵌入式处理器等。专用计算机的特点是结构紧凑、效率高、成本低,但灵活性差,只能执行特定的任务。通用计算机则能够运行各种不同的程序,解决各种不同类型的问题,具有广泛的适用性。我们日常使用的个人计算机、服务器等都属于通用计算机。

按照系统规模和计算能力,也可以分为:巨型机(超算),大型机,小型机,微型机等,随着超大规模集成电路技术的不断发展,类型的划分会动态变化。巨型机(超级计算机)是速度最快、性能最高的计算机,通常用于科学计算、气象预报、核模拟等需要大规模数值计算的领域,如我国的”神威·太湖之光”、”天河”系列超级计算机。大型机具有强大的数据处理能力和高可靠性,广泛应用于银行、航空、政府等大型机构的事务处理。小型机在性能上介于大型机和微型机之间,适合中小型企业的数据处理需求。微型机是以微处理器为核心的计算机,包括个人计算机(PC)、笔记本电脑、平板电脑等,是目前使用最广泛的计算机类型。随着集成电路技术的发展,今天的微型机在性能上已经超过了数十年前的大型机甚至巨型机,类型之间的界限也在不断变化。

1.2 计算机的诞生和发展

计算机之父——冯·诺依曼。

EDVAC(冯·诺依曼思想)。

第一台严格意义上的电子计算机(ENIAC,宾夕法尼亚大学,1946.2)。

ENIAC(Electronic Numerical Integrator and Computer,电子数值积分计算机)是世界上第一台通用电子数字计算机,于1946年2月在美国宾夕法尼亚大学诞生。ENIAC重达30吨,占地170平方米,使用了18000多个真空管,耗电150千瓦。它的运算速度为每秒5000次加法运算,虽然远不及今天的微型计算机,但在当时已经是划时代的突破。ENIAC最初是为了计算弹道轨迹而设计的,但它的通用性使其能够解决各种计算问题。然而,ENIAC的一个重大缺陷是它的程序需要通过人工接线来设置,每次更换程序都需要重新接线,费时费力。

冯·诺依曼在参与ENIAC的改进工作时,提出了存储程序的思想,并在EDVAC(Electronic Discrete Variable Automatic Computer)方案中系统阐述了这一思想。EDVAC的设计方案于1945年发表,这就是著名的”关于EDVAC的报告草案”,也被称为”冯·诺依曼报告”。该报告确立了现代计算机的基本结构和工作方式,即冯·诺依曼体系结构。虽然关于存储程序思想的优先权存在争议——实际上ENIAC的设计者J. Presper Eckert和John Mauchly也独立提出了类似的思想——但冯·诺依曼的报告因其系统性和影响力而被广泛认为是存储程序思想的正式提出。

1.2.1 冯·诺依曼体系

冯·诺依曼体系结构的核心思想可以归纳为以下三点:

  1. 用二进制代码表示程序和数据。任何复杂运算和操作都转换成二进制代码表示的指令,数据也用二进制代码来表示。选择二进制而非十进制,一方面是因为二进制的运算规则最简单,便于用电子器件实现(如开关的通断);另一方面是因为二进制与逻辑代数(布尔代数)天然对应,可以方便地用逻辑电路来实现各种运算功能。这一选择对计算机的发展产生了深远影响,至今所有数字计算机仍然采用二进制来表示和处理信息。
  2. 采用存储程序的工作方式。将程序和数据存储起来(存储程序),让计算机自动地执行指令,完成各种复杂的运算操作(核心思想)。存储程序思想的革命性在于:程序和数据在形式上没有区别,都是二进制编码,因此可以存储在同一个存储器中;计算机在执行程序时可以自动地从存储器中依次取出指令并执行,无需人工干预;程序本身也可以作为数据被处理和修改(这就是自我修改程序和编译器的理论基础)。存储程序思想使计算机从”计算工具”跃升为”通用信息处理机”。
  3. 新型的现代计算机硬件组成。存储器,运算器,控制器,输入设备和输出设备。奠定了现代电子计算机的理论基础。冯·诺依曼体系结构的硬件五大部件划分至今仍是理解计算机组成的基本框架。值得注意的是,冯·诺依曼体系结构的一个显著特征是”程序和数据共用同一个存储器”(即普林斯顿结构),与之相对的是哈佛结构,后者将程序存储器和数据存储器分开设置。哈佛结构的优势在于可以同时访问指令和数据,提高了执行效率,但硬件复杂度更高。现代CPU内部通常采用改进的哈佛结构(如L1 Cache分为指令Cache和数据Cache),而在芯片外部则采用冯·诺依曼结构(主存统一存放指令和数据),兼顾了两种结构的优点。

1.2.2 计算机的发展历程

计算机的发展历程通常按照所使用的电子器件来划分代际:

第一代(1946-1958年):电子管计算机。 采用电子管(真空管)作为基本电子器件,使用磁鼓或磁芯作为主存储器。代表机型有ENIAC、EDVAC、UNIVAC等。这一代计算机的特点是体积庞大、功耗高、可靠性差、价格昂贵,主要用于科学计算。编程使用机器语言或汇编语言,使用极不方便。尽管如此,电子管计算机开创了电子计算的新时代,证明了电子计算机的可行性和巨大潜力。

第二代(1958-1964年):晶体管计算机。 采用晶体管代替电子管作为基本电子器件。晶体管比电子管体积小、功耗低、可靠性高、寿命长,使得计算机的性能大幅提升,体积和功耗显著下降。这一时期出现了磁芯存储器和磁盘存储器,存储容量和可靠性都有很大提高。代表机型有IBM 7090、CDC 6600等。高级程序设计语言(如FORTRAN、COBOL)的出现,使得编程变得更加方便。计算机的应用范围也从科学计算扩展到数据处理和事务管理。

第三代(1964-1971年):集成电路计算机。 采用中小规模集成电路(IC)作为基本电子器件。集成电路将多个晶体管、电阻、电容等元件集成在一块半导体芯片上,进一步减小了体积、降低了功耗、提高了可靠性。这一时期出现了半导体存储器,逐步取代了磁芯存储器。代表机型有IBM System/360系列。操作系统的出现使得计算机资源管理更加高效,多道程序设计和分时系统成为可能。计算机的应用范围进一步扩大,出现了系列化、标准化的趋势。

第四代(1971年至今):大规模和超大规模集成电路计算机。 采用大规模集成电路(LSI)和超大规模集成电路(VLSI)作为基本电子器件。微处理器的诞生是这一代计算机的标志性事件——1971年,Intel公司推出了世界上第一款微处理器4004,将一个完整的CPU集成在一块芯片上。此后,微处理器的发展遵循摩尔定律(Moore’s Law),集成度大约每18-24个月翻一番,性能也相应提高。个人计算机(PC)的出现使计算机从实验室走向了普通家庭和办公室。计算机网络的发展使计算机之间的信息交换和资源共享成为可能。多媒体技术、图形用户界面等技术的发展使计算机的使用更加直观便捷。

1.2.3 未来的发展趋势

  1. 向巨型化方向。超级计算机的运算速度不断提高,从万亿次、千万亿次到百亿亿次(Exascale),正在向更高性能迈进。超算在气候模拟、药物研发、材料科学、人工智能训练等领域的应用需求持续增长。并行计算、异构计算(CPU+GPU+FPGA等)、量子计算等新技术正在推动计算性能的边界不断扩展。
  2. 向微型化方向。随着集成电路工艺的进步,计算机的体积不断缩小,从台式机到笔记本,从笔记本到智能手机,从智能手机到可穿戴设备,计算能力正在融入越来越多的便携设备中。嵌入式系统和片上系统(SoC)技术的发展使得计算机功能可以被集成到各种设备和物品中,形成物联网(IoT)。
  3. 向多媒体化方向。计算机处理的信息从单纯的数值和文字,发展到图形、图像、声音、视频等多种媒体形式的综合处理。虚拟现实(VR)、增强现实(AR)、3D渲染、高清视频编解码等多媒体应用对计算机的图形处理能力和数据吞吐能力提出了更高的要求,推动了GPU和专用加速器的发展。
  4. 向网络化方向。互联网的发展使全球计算机连接成一个庞大的信息网络,云计算、边缘计算、分布式系统等技术正在改变计算的模式。网络化使得计算资源可以按需分配和共享,也催生了大数据、区块链等新的计算范式。
  5. 向智能化方向。人工智能(AI)技术正在深刻改变计算机的应用方式和能力边界。从传统的规则推理到机器学习、深度学习,计算机正在获得越来越强的自主学习和决策能力。专用AI芯片(如NPU、TPU)的出现为智能化计算提供了硬件基础。未来的计算机可能具备更强的自主学习、自然语言理解、视觉感知和智能决策能力。

1.3 计算机系统的层次结构

硬件:是指构成计算机系统的实体和装置之类的有形设备,是组成计算机系统的物质基础。硬件包括CPU、存储器、输入输出设备、总线、接口等物理部件,它们构成了计算机系统的物理实体。

软件:是指硬件所表达的各种内在信息,包括数据与控制程序。因为它们是无形的东西,所以称为软件或软设备。软件决定了计算机做什么以及怎么做,是计算机系统的灵魂。没有软件的硬件只是一堆不能做任何有意义工作的电子器件。

硬件和软件的关系是相辅相成的:硬件是软件运行的物质基础,软件是硬件功能的扩展和延伸。好的硬件设计可以为软件提供更强大的运行平台,好的软件设计可以充分发挥硬件的性能潜力。计算机系统的性能不仅取决于硬件的性能指标,还取决于软件的设计质量。

1.3.1 计算机的硬件系统组成

  1. 硬件系统的基本组成模型

主要功能部件:

  • CPU:主要由运算器,控制器等部件组成。现代CPU内部还集成了高速缓存(Cache)、浮点运算单元(FPU)、分支预测器、乱序执行引擎等部件,其复杂程度远超早期的CPU。

    • 运算器

      • 功能:完成两类(算术和逻辑)运算。算术运算包括加、减、乘、除等基本运算,逻辑运算包括与、或、非、异或等逻辑操作。此外,运算器还能完成移位、循环、比较等操作。
      • 组成特点:
        • 主要有 ALU(算术逻辑单元)构成,执行算术,逻辑运算以及移位循环等操作,是 CPU 功能的主要执行部件。ALU是运算器的核心,它接收来自寄存器的操作数,在控制信号的控制下完成指定的运算,并将结果送回寄存器或写回存储器。
        • ALU 以全加器为核心,具有多种运算功能。全加器是完成一位二进制加法运算的基本电路,将多个全加器级联就可以构成多位加法器。通过补码运算和溢出检测,加法器可以扩展实现减法运算;通过移位和加法的组合,可以实现乘法运算;通过移位和减法的组合,可以实现除法运算。
        • 运算的位数越多,计算精度就越高,但期间也更复杂。8位ALU只能表示-128到+127的整数范围,而64位ALU可以表示约-9.2×10¹⁸到+9.2×10¹⁸的整数范围,精度和范围都有极大的提升,但硬件实现的复杂度也随之增加。
        • 运算器的数据宽度一般是:8/16/32/64 位。现代通用计算机主要采用32位或64位数据宽度,其中64位已成为主流。数据宽度的选择需要在精度、性能和成本之间进行权衡。
    • 控制器

      • 功能:产生控制命令(微命令),控制全机操作。控制器是计算机的”指挥中心”,它从存储器中取出指令,对指令进行分析译码,产生相应的控制信号序列,驱动运算器、存储器、输入输出设备等部件协调工作,完成指令规定的操作。
      • 基本组成:
      • 控制器的核心组成部分包括:程序计数器(PC),用于保存下一条要执行的指令的地址;指令寄存器(IR),用于保存当前正在执行的指令;指令译码器(ID),对指令的操作码进行译码,产生相应的控制信号;时序发生器,产生各种时序信号,控制操作的先后顺序;微操作信号发生器,根据指令译码结果和时序信号,产生各种微操作控制信号。按照微操作信号产生方式的不同,控制器可以分为硬布线控制器(组合逻辑控制器)和微程序控制器两种。硬布线控制器通过组合逻辑电路直接产生控制信号,速度快但设计复杂、不易修改;微程序控制器将每条指令的微操作序列编成微程序存放在控制存储器中,通过读取微程序来产生控制信号,设计灵活但速度稍慢。
  • 存储器:存储数据和数字化后的程序。存储器是计算机中用来存储程序和数据的部件,是冯·诺依曼体系结构的核心组成部分之一。

    • 存储单元。存储器由若干个存储单元组成,每个存储单元可以存放一个固定长度的数据(通常为一个字或一个字节)。每个存储单元都有一个唯一的编号,称为地址。CPU通过地址来访问存储器中的数据。
    • 地址。地址是用来标识存储单元位置的二进制编码。n位地址可以寻址2ⁿ个存储单元。例如,32位地址可以寻址4GB的存储空间,64位地址可以寻址的存储空间理论上达到16EB。
    • 存储容量。存储容量是衡量存储器大小的重要指标,通常用字节(Byte)来表示。常用单位有KB(2¹⁰B)、MB(2²⁰B)、GB(2³⁰B)、TB(2⁴⁰B)等。
    • 内存储器(主存)。主存是CPU可以直接访问的存储器,用来存放当前正在执行的程序和正在处理的数据。主存通常采用半导体存储器(DRAM),具有较快的访问速度,但容量相对有限,断电后信息丢失(易失性存储器)。
    • 外存储器(辅存)。辅存是CPU不能直接访问的存储器,用来存放暂时不用的程序和数据。辅存通常采用磁盘(HDD)、固态硬盘(SSD)、光盘等,具有大容量、非易失性的特点,但访问速度远慢于主存。
  • 输入输出设备。输入设备将外部信息转换为计算机可识别的数字信号并送入计算机,常见的输入设备有键盘、鼠标、触摸屏、扫描仪、麦克风、摄像头等。输出设备将计算机处理的结果转换为人或其他设备可接受的形式输出,常见的输出设备有显示器、打印机、扬声器等。输入输出设备是计算机与外部世界交互的桥梁。

  • 总线:能为多个部件分时共享的一组信息传送通路。总线是连接计算机各功能部件的公共信息通道,采用总线结构可以减少连线数量,便于系统的扩展和维护。

    • 数据总线。数据总线用于在各部件之间传送数据信息,其宽度决定了每次数据传输的位数。例如,32位数据总线每次可以传送32位数据。
    • 地址总线。地址总线用于传送地址信息,其宽度决定了系统的最大寻址空间。例如,32位地址总线可以寻址4GB的存储空间。
    • 控制总线。控制总线用于传送控制信号和状态信号,包括读/写信号、中断请求信号、总线请求信号、时钟信号等。
  • 接口:具有缓冲,转换,连接的功能的部件。I/O接口是连接主机与外部设备的逻辑电路,其作用是解决主机与外设之间在数据格式、传输速率、电气特性等方面的差异。接口内部通常包含数据缓冲寄存器、控制寄存器、状态寄存器等,可以实现数据的暂存、格式转换、时序协调等功能。

  1. 计算机硬件的典型架构
    • 微型计算机:南-北桥架构

南北桥架构是早期PC主板的主流架构。北桥芯片(MCH,Memory Controller Hub)负责连接CPU、主存和显卡等高速设备,处理高速数据传输;南桥芯片(ICH,I/O Controller Hub)负责连接硬盘、USB、网卡、声卡等低速外设,处理I/O数据传输。北桥与南桥之间通过专用总线连接。随着集成电路技术的发展,现代CPU已经将内存控制器和PCIe控制器集成到了CPU内部,北桥芯片的功能被CPU整合,因此南北桥架构逐渐演变为单芯片架构(PCH,Platform Controller Hub),简化了主板设计,降低了延迟。

  • 小型计算机:多处理器架构

小型计算机通常采用多处理器架构,通过多个处理器共享存储器和I/O设备来提高系统的处理能力。多处理器系统按照处理器之间的连接方式,可以分为对称多处理(SMP)和非对称多处理(AMP)等类型。SMP系统中所有处理器地位平等,共享同一主存和I/O设备,由操作系统负责调度和负载均衡;AMP系统中各处理器有主从之分,主处理器负责系统管理和任务分配,从处理器执行具体的计算任务。

  • 超级计算机(超算):集群式架构。超级计算机通常由大量计算节点通过网络互连组成集群,每个计算节点包含一个或多个处理器。节点之间通过高速网络(如InfiniBand、以太网)进行通信和协调。超算的并行计算能力来自于大量节点的协同工作,需要高效的并行算法和通信机制来支撑。我国的”神威·太湖之光”拥有40960个计算节点,峰值性能达到125PFLOPS。
  • 多处理机系统结构:用多处理器 CPU 构成。根据处理器之间连接的紧密程度,又分为:①紧密耦合型多机系统——各处理器共享主存储器,通过共享存储器进行通信,通信延迟低但存储器带宽可能成为瓶颈;②松散耦合型多机系统——各处理器拥有独立的本地存储器,通过消息传递进行通信,通信延迟较高但扩展性好。多核处理器是紧密耦合型多机系统的一种实现形式,在单个芯片上集成多个处理器核心,各核心共享片上Cache和主存接口。

1.3.2 软件系统

  1. 软件类别:系统程序应用程序
    • 系统程序:负责系统调度管理,提供运行和开发环境,各种服务,确保系统运行良好。系统程序包括操作系统、编译器、解释器、汇编器、链接器、调试器、设备驱动程序等。操作系统是最核心的系统程序,它负责管理计算机的硬件资源(CPU时间、存储空间、I/O设备等),为应用程序提供运行环境和服务接口。编译器和解释器负责将高级语言程序翻译成机器语言程序,使程序员能够用更接近人类思维的方式来编写程序。
    • 应用程序:利用计算机来解决应用问题所编制的程序,如工程设计程序,数据处理程序,自动控制程序,企业管理程序,情报检索程序,科学计算程序等等。应用程序直接面向用户的需求,种类繁多,从办公软件到游戏,从数据库管理系统到人工智能应用,都属于应用程序的范畴。

1.3.3 硬,软件系统层次结构

计算机系统是一个由多层次的软件和硬件组成的系统,基本结构如下图所示:

从底层到顶层,计算机系统可以分为以下几个层次:

  • 微程序机器层:由微程序实现的机器指令系统,是硬件与软件之间的最底层接口。微程序控制器将每条机器指令分解为一系列微操作,通过执行微程序来完成机器指令的功能。
  • 传统机器语言层:由机器指令组成的指令系统,是程序员(或编译器)看到的最底层接口。机器语言是计算机唯一能直接理解和执行的语言,每条机器指令都是一串二进制编码。
  • 操作系统层:操作系统在机器语言层之上,为上层软件提供系统调用接口,管理硬件资源,提供进程管理、存储管理、文件管理、设备管理等功能。
  • 汇编语言层:汇编语言是机器语言的符号化表示,用助记符代替二进制操作码,用符号地址代替数值地址,使得程序的编写和阅读更加方便。汇编语言需要通过汇编器翻译成机器语言才能执行。
  • 高级语言层:高级语言(如C、C++、Java、Python等)更接近人类的思维方式和数学表达,编写效率高,可移植性强。高级语言程序需要通过编译器或解释器翻译成机器语言才能执行。
  • 应用语言层:应用语言是面向特定应用领域的专用语言,如数据库查询语言SQL、网页描述语言HTML等。

这种层次结构使得各层之间相互独立,每层只需要了解其下层提供的接口,而不需要了解其内部的实现细节,从而降低了系统的复杂性,提高了可维护性和可移植性。

1.3.4 软件和硬件的逻辑等价性

  1. 软件的特点:易于实现各种逻辑与运算功能,但是常受到速度指标和软件容量的制约。软件的灵活性在于:修改软件只需要修改程序代码,不需要改变硬件电路;实现复杂逻辑只需要编写更复杂的程序,而不受硬件电路复杂度的限制。但软件执行需要经过取指、译码等步骤,速度通常比硬件实现慢几个数量级。
  2. 硬件的特点:可以高速实现逻辑和运算的功能,但是难以实现复杂功能或计算,受到控制复杂性指标的制约。硬件通过专用电路直接实现特定功能,省去了取指、译码等开销,速度极快。但硬件一旦设计制造完成就难以修改,实现复杂功能需要极其复杂的电路设计,成本高且灵活性差。
  3. 计算机中的软件,理论上都可以”固化”或”硬化”成硬件,以提高执行速度。这就是软硬件逻辑等价性的核心含义。例如,浮点运算既可以用软件子程序来实现(早期计算机的常见做法),也可以用硬件浮点运算单元来实现(现代CPU的标配);加密运算既可以用软件算法来实现,也可以用专用加密芯片(硬件加速器)来实现。软硬件的划分是一个设计决策问题,需要综合考虑性能需求、成本约束、灵活性要求等因素。随着集成电路技术的发展,越来越多的软件功能被硬化到芯片中,如网络协议处理、视频编解码、AI推理等专用加速器,这就是所谓的”软件硬化”趋势。反过来,也有一些硬件功能可以通过软件模拟来实现,如在虚拟机中模拟硬件设备,这就是”硬件软化”。

1.4 计算机系统的性能指标

  1. 基本字长

    • 指一次数据操作的基本位数。基本字长决定了计算机一次能处理的数据宽度,直接影响计算精度和指令功能。字长越长,能表示的数据范围越大、精度越高,指令中能包含的信息也越多(如更大的地址空间、更多的操作码)。常见的基本字长有8位、16位、32位和64位。现代通用计算机主流字长为64位,意味着CPU一次可以处理64位数据,通用寄存器的宽度也为64位。
    • 会影响计算的精度,指令的功能。例如,32位整数的表示范围约为-21亿到+21亿,而64位整数的表示范围约为-9.2×10¹⁸到+9.2×10¹⁸。对于浮点运算,32位单精度浮点数约有7位有效数字,64位双精度浮点数约有15-16位有效数字。
  2. 外频:外部频率或基频,也叫系统时钟频率。外频是主板为CPU提供的基础时钟频率,也是系统总线的工作频率。在早期的计算机中,CPU的主频就等于外频。随着技术的发展,CPU内部采用了倍频技术,使得CPU内部可以以更高的频率运行,而外部总线仍然以较低的频率运行,以降低信号传输的难度。外频通常在100MHz到400MHz之间。

  3. 常用的 CPU 性能指标

    • CPU 的主频 = 外频×倍频系数。主频是CPU内部的工作频率,也称为时钟频率,是衡量CPU速度的重要指标。例如,外频为100MHz,倍频系数为50,则主频为5GHz。主频越高,CPU在单位时间内执行的时钟周期数越多,理论上运算速度越快。但主频并不是衡量CPU性能的唯一指标,不同架构的CPU在每个时钟周期内能完成的工作量不同,因此主频相同的不同CPU,实际性能可能差异很大。
    • IPS,每秒执行指令数。IPS是衡量CPU速度的直接指标,但由于不同指令的执行时间不同,IPS通常只能给出一个平均值或峰值。早期常用MIPS(Million Instructions Per Second,每秒百万条指令)来衡量CPU性能。
    • CPI,每一个指令执行过程中所需的时钟周期数量。CPI是衡量指令执行效率的重要指标。不同类型的指令CPI不同,通常简单指令(如寄存器间的加法)CPI为1,而复杂指令(如除法)CPI可能达到数十。CPU的平均CPI取决于指令的构成比例和各指令的CPI值。CPI越低,说明CPU在每个时钟周期内能完成更多工作。现代CPU通过流水线、超标量、乱序执行等技术来降低有效CPI。
    • FLOPS,每秒执行浮点运算的次数。FLOPS是衡量科学计算能力的重要指标,特别适用于评估超级计算机和高性能计算系统的性能。常用单位有MFLOPS(10⁶)、GFLOPS(10⁹)、TFLOPS(10¹²)、PFLOPS(10¹⁵)、EFLOPS(10¹⁸)。
    • CPU 的功耗
      • 静态功耗是由于半导体电路自身的损耗造成的功耗。静态功耗主要来源于晶体管的漏电流,即使在晶体管处于关闭状态时也会有少量电流流过,造成能量损耗。随着集成电路工艺节点的缩小,漏电流问题越来越严重,静态功耗在总功耗中的占比不断增加。
      • 动态功耗是电路在开关切换过程中产生的功耗,与电压的平方、频率和负载电容成正比:P_dynamic = α·C·V²·f。动态功耗是CPU功耗的主要来源,降低工作电压和工作频率可以有效减少动态功耗,这也是现代CPU采用动态电压频率调节(DVFS)技术的原因。

    CPU执行时间的综合公式:CPU执行时间 = 指令数 × CPI × 时钟周期时间。这个公式揭示了影响CPU性能的三个关键因素:指令数(取决于编译器和指令集架构)、CPI(取决于CPU的微架构设计)和时钟周期时间(取决于制造工艺和电路设计)。提升CPU性能需要从这三个方面入手进行优化。

  4. 数据传输率

    • 带宽 =(位宽×工作频率)/8(B/S)。带宽是衡量数据传输能力的重要指标,表示单位时间内能够传输的数据量。例如,64位数据总线在工作频率为400MHz时,带宽 = (64×400×10⁶)/8 = 3.2GB/s。
    • 物理含义:单位时间内数据的传输量。带宽越大,数据传输速度越快,系统整体性能越好。但实际有效带宽还受到总线协议开销、数据编码方式、传输效率等因素的影响。
    • 注意:计算 PCI-E 总线的带宽时,一般还要考虑编码方式,单双工模式和通道路数等。例如,PCIe 3.0 x16的每通道带宽约为985MB/s,16通道的总带宽约为15.75GB/s,但需要扣除8b/10b或128b/130b编码的开销。
  5. 存储器的容量

    • 主存容量 = 存储单元个数 × 存储字长。主存容量决定了计算机能够同时运行的程序和数据的规模,是影响系统性能的重要因素。主存容量通常以字节为单位表示,如8GB、16GB、32GB等。
    • 存储器容量与地址线宽度的关系:n位地址线可以寻址2ⁿ个存储单元。例如,32位地址线可以寻址4GB(2³²字节)的存储空间。

第二章 数据的表示,运算与校验

2.1 数值及其相互转换

2.1.1 进位计数制

  1. 数值的基与权

    • 在任一数制中,每一数位上允许使用的计数符号的个数被称为该数制的基数。例如,十进制的基数为10(使用0-9十个符号),二进制的基数为2(使用0和1两个符号),八进制的基数为8(使用0-7八个符号),十六进制的基数为16(使用0-9和A-F共十六个符号)。
    • 每 1 位都对应 1 个表示该位在数码中的位置的值,这个值就称为数位的权值 w。在基数为R的数制中,第i位的权值为R^i(从小数点向左依次为R⁰、R¹、R²…,向右依次为R⁻¹、R⁻²、R⁻³…)。例如,十进制数123.45中,1的权值为10²=100,2的权值为10¹=10,3的权值为10⁰=1,4的权值为10⁻¹=0.1,5的权值为10⁻²=0.01。
    • 常用进位制:2进制,8进制,16进制。在计算机科学中,二进制是最基本的数制,因为计算机内部的信息表示和处理都基于二进制。但二进制数书写冗长、不便阅读,因此常用八进制和十六进制作为二进制的缩写形式。八进制和十六进制与二进制之间的转换非常方便——每3位二进制数对应1位八进制数,每4位二进制数对应1位十六进制数。
  2. 进制之间的转换

    • 十进制转换为 R 进制:

      • 整数部分:除 R 取余法。将十进制整数反复除以R,每次记录余数,直到商为0,然后将余数从最后一个到第一个排列,即得到R进制表示。例如,将十进制数43转换为二进制:43÷2=21…1, 21÷2=10…1, 10÷2=5…0, 5÷2=2…1, 2÷2=1…0, 1÷2=0…1,余数从后往前排列得101011。
      • 小数部分:乘 R 取整法。将十进制小数反复乘以R,每次取整数部分作为R进制数的位,直到小数部分为0或达到所需精度。需要注意的是,有些十进制小数无法精确转换为R进制小数(如0.1无法精确转换为二进制小数),这时会出现无限循环小数。
      • 例:将十进制数 43 转换为二进制、八进制、十六进制。
        • 二进制:101011。
        • 八进制:53。
        • 十六进制:2B。
    • R 进制转换为十进制:

      • 按权展开求和。将R进制数的每一位乘以对应的权值,然后求和,即得到十进制值。例如,二进制数101011 = 1×2⁵ + 0×2⁴ + 1×2³ + 0×2² + 1×2¹ + 1×2⁰ = 32 + 0 + 8 + 0 + 2 + 1 = 43。
      • 例:二进制数 101011 转换为十进制数:43。
    • 二进制与八进制、十六进制的转换:
      • 二进制转换为八进制:从右往左,每三位二进制数转换为一位八进制数。不足三位时,整数部分在左边补0,小数部分在右边补0。例如,二进制数101011分组为101 011,分别对应八进制5和3,结果为53。
      • 二进制转换为十六进制:从右往左,每四位二进制数转换为一位十六进制数。不足四位时补0。例如,二进制数101011分组为0010 1011,分别对应十六进制2和B,结果为2B。
      • 例:二进制数 101011 转换为八进制数:53,转换为十六进制数:2B。

2.2 带符号数的表示

在计算机中,数值数据有无符号数和带符号数之分。无符号数没有符号位,所有位都用于表示数值的大小,只能表示非负数。带符号数需要表示正负号,通常将最高位作为符号位(0表示正数,1表示负数),其余位表示数值的大小。

2.2.1 原码表示法

原码是最直观的带符号数表示方法。在原码表示中,最高位为符号位(0表示正,1表示负),其余位为数值位,直接表示数值的绝对值。

例如,8位原码表示中:+5的原码为00000101,-5的原码为10000101。

原码的优点是简单直观,与日常使用的十进制数表示方式一致,乘除运算也较为方便(符号位单独处理,数值位按绝对值进行乘除)。但原码有两个严重的缺陷:一是零有两种表示(+0=00000000,-0=10000000),给运算和判断带来不便;二是用原码进行加减运算时非常复杂——需要先判断两个数的符号和绝对值大小,再决定做加法还是减法,最后还要确定结果的符号。这些判断和操作使得原码加减运算的硬件实现非常复杂。

2.2.2 反码表示法

反码是原码和补码之间的一种过渡表示。正数的反码与原码相同;负数的反码符号位为1,数值位为原码数值位逐位取反。

例如,8位反码表示中:+5的反码为00000101,-5的反码为11111010。

反码解决了原码加减运算的部分问题,但零仍然有两种表示(+0=00000000,-0=11111111),且运算时可能需要循环进位(将最高位的进位加到最低位),不太方便。因此反码在实际计算机中很少直接用于运算,主要作为原码到补码转换的中间步骤。

2.2.3 补码表示法

补码是现代计算机中最常用的带符号数表示方法。正数的补码与原码相同;负数的补码符号位为1,数值位为反码加1(即原码数值位逐位取反再加1)。

例如,8位补码表示中:+5的补码为00000101,-5的补码为11111011。

补码的关键优势在于:补码的零只有一种表示(00000000),消除了原码和反码中零的歧义问题;更为重要的是,补码可以将减法运算转化为加法运算——两个补码数的加减运算可以统一用加法器完成,不需要判断符号和大小,符号位也参与运算,结果的符号自动正确。这极大简化了运算器的硬件设计。

补码的数学基础是模运算。在n位二进制系统中,模为2ⁿ。一个负数-x的补码就是2ⁿ-x,即它的补数。例如,8位系统中-5的补码为2⁸-5=256-5=251=11111011₂。由于运算结果对2ⁿ取模,超出n位的进位自然丢弃,因此补码运算无需特殊处理。

补码的表示范围:n位补码的表示范围为-2ⁿ⁻¹到+2ⁿ⁻¹-1。例如,8位补码的范围为-128到+127。注意负数比正数多一个(-128没有对应的+128),这是因为零占用了一个正数的位置。

2.2.4 移码表示法

移码(也叫增码或偏移码)主要用于浮点数的阶码表示。移码的表示方法是将补码的符号位取反,即:移码 = 补码 + 2ⁿ⁻¹(其中n为位数,含符号位)。

例如,8位移码表示中:+5的移码为10000101,-5的移码为01111011。

移码的特点是:移码的大小顺序与真值的大小顺序一致,即移码值越大,对应的真值也越大。这一特性使得移码非常适合用于浮点数阶码的比较操作——在进行浮点数对阶时,只需要比较移码的大小即可确定阶码的大小关系,简化了浮点运算的硬件实现。

2.3 定点数的运算

定点数是小数点位置固定的数。根据小数点的位置,定点数可以分为定点小数(小数点固定在符号位之后,纯小数)和定点整数(小数点固定在最低位之后,纯整数)。

2.3.1 定点数的加减运算

补码加减运算的基本规则:

  • 加法:[A+B]补 = [A]补 + [B]补
  • 减法:[A-B]补 = [A]补 + [-B]补

其中,[-B]补的求法是将[B]补的各位(含符号位)逐位取反,末位加1。

溢出判断:当运算结果超出了补码的表示范围时,就会发生溢出。溢出只可能发生在同号相加或异号相减的情况。常用的溢出判断方法有三种:

  1. 单符号位法:如果两个同号数相加,结果的符号与加数不同,则发生了溢出。即:溢出 = Aₙ ⊕ Bₙ ⊕ Sₙ(其中Aₙ、Bₙ为操作数符号位,Sₙ为结果符号位,⊕为异或)。
  2. 进位判断法:如果最高数值位向符号位的进位与符号位向外的进位不同,则发生了溢出。即:溢出 = Cₙ ⊕ Cₙ₋₁(其中Cₙ为符号位产生的进位,Cₙ₋₁为最高数值位向符号位的进位)。
  3. 双符号位法(变形补码):用两位符号位来表示符号,00表示正,11表示负。运算结果如果两位符号位不同(01或10),则发生了溢出。01为正溢出(上溢),10为负溢出(下溢)。

2.3.2 定点数的乘法运算

原码一位乘法:符号位单独运算(同号为正,异号为负),数值位按绝对值进行乘法。乘法过程类似于手工乘法:从乘数的最低位开始,如果当前位为1,则将被乘数的绝对值累加到部分积中;如果当前位为0,则不加。每判断一位,部分积右移一位。共进行n次(n为数值位数)判断和移位操作。

补码一位乘法(Booth算法):补码乘法不需要单独处理符号位,符号位参与运算,结果自动正确。Booth算法的基本思想是根据乘数相邻两位的差值来决定操作:如果当前位与上一位不同(从01或10的跳变),则加或减被乘数;如果相同(00或11),则不加不减。每次操作后部分积右移一位。

Booth算法的具体步骤:

  1. 在乘数末尾添加一位附加位Y₋₁=0。
  2. 根据乘数的最低位Y₀和附加位Y₋₁的值决定操作:01则加[X]补,10则加[-X]补,00或11则不加不减。
  3. 部分积和乘数右移一位(算术右移,符号位不变)。
  4. 重复步骤2-3,共n+1次(n为数值位数加符号位),最后一次不移位。

2.3.3 定点数的除法运算

原码恢复余数法:符号位单独运算,数值位按绝对值进行除法。基本思路是:先将被除数(或余数)减去除数,如果余数为正,则商上1;如果余数为负,则商上0,并恢复余数(加回除数)。然后余数左移一位,重复上述过程。

原码加减交替法(不恢复余数法):在恢复余数法中,当余数为负时需要恢复余数(加上除数),然后左移后再减除数,这两步可以合并为:余数左移后加除数。这样就避免了恢复余数的步骤,提高了运算效率。具体规则:余数为正,商上1,余数左移后减除数;余数为负,商上0,余数左移后加除数。

补码加减交替除法:补码除法不需要单独处理符号位,符号位参与运算。基本规则:被除数与除数同号,则减除数;异号,则加除数。余数与除数同号,商上1,余数左移后减除数;异号,商上0,余数左移后加除数。最后需要对商进行修正。

2.4 浮点数的表示与运算

2.4.1 浮点数的表示

浮点数是用科学计数法的方式来表示的数,其一般格式为:

N = M × R^E

其中M为尾数(mantissa),表示数的有效数字;R为基数(通常为2),是隐含约定的;E为阶码(exponent),表示小数点的位置。

浮点数的表示格式包含两个主要部分:阶码部分和尾数部分。阶码部分决定了浮点数的表示范围,尾数部分决定了浮点数的表示精度。阶码位数越多,表示范围越大;尾数位数越多,表示精度越高。在总位数一定的情况下,需要在阶码位数和尾数位数之间进行权衡,以兼顾范围和精度。

浮点数的规格化:为了充分利用尾数的有效位数,提高表示精度,浮点数通常采用规格化表示。对于基数R=2的浮点数,规格化的条件是尾数最高有效位为1(即1/2 ≤ |M| < 1)。规格化可以使尾数中不出现前导零,从而最大限度地利用尾数的位数来表示有效数字。

2.4.2 IEEE 754浮点数标准

IEEE 754是国际上通用的浮点数标准,由IEEE于1985年制定,目前绝大多数计算机系统都遵循该标准。IEEE 754定义了两种基本格式和两种扩展格式:

单精度浮点数(32位)

  • 符号位S:1位(第31位),0表示正数,1表示负数
  • 阶码E:8位(第23-30位),采用移码表示,偏移量为127
  • 尾数M:23位(第0-22位),采用原码表示,隐含最高位1

单精度浮点数的真值为:(-1)^S × 1.M × 2^(E-127)

其中”1.M”表示尾数有一个隐含的前导1(规格化数),因此23位尾数实际上可以表示24位有效数字。

双精度浮点数(64位)

  • 符号位S:1位(第63位)
  • 阶码E:11位(第52-62位),偏移量为1023
  • 尾数M:52位(第0-51位),隐含最高位1

双精度浮点数的真值为:(-1)^S × 1.M × 2^(E-1023)

IEEE 754的特殊值

  • 零:E=0, M=0,表示+0或-0(取决于符号位)
  • 非规格化数:E=0, M≠0,用于表示非常接近零的数,此时真值为(-1)^S × 0.M × 2^(-126)(单精度)
  • 无穷大:E=255(单精度)或E=2047(双精度),M=0,表示+∞或-∞
  • NaN(Not a Number):E=255(单精度)或E=2047(双精度),M≠0,表示非法运算结果(如0/0、∞-∞等)

IEEE 754标准的设计体现了精妙的工程权衡。移码的使用使得阶码的比较可以通过无符号整数比较来实现;隐含前导1的设计在不增加存储位数的情况下提高了一位精度;非规格化数的引入实现了”逐渐下溢”(gradual underflow),避免了从规格化数直接跳变到零的问题,保证了数值的连续性。

2.4.3 浮点数的加减运算

浮点数加减运算的一般步骤:

  1. 对阶:比较两个操作数的阶码大小,将阶码小的操作数的尾数右移,同时增大其阶码,使两个操作数的阶码相等。对阶的原则是”小阶向大阶看齐”,因为尾数右移舍去的是低位,损失的精度较小;而尾数左移会丢失高位,损失的是有效数字,精度损失更大。右移时需要进行舍入处理。

  2. 尾数加减:将对阶后的两个尾数进行加减运算。尾数通常采用补码或原码表示,运算方法与定点数加减相同。

  3. 规格化:运算结果可能不是规格化数,需要进行规格化处理。如果尾数出现溢出(即小数点前有两位有效数字),则需要尾数右移一位,阶码加1,这称为右规(向右规格化)。如果尾数出现前导零(即小数点后第一位为0),则需要尾数左移,直到最高有效位为1,同时阶码减去左移的位数,这称为左规(向左规格化)。

  4. 舍入:在对阶和右规时,尾数右移会丢失低位,需要进行舍入处理。IEEE 754定义了四种舍入模式:就近舍入(round to nearest,默认模式,0舍1入,当恰好在一半时舍入到偶数)、朝0舍入(截断)、朝+∞舍入、朝-∞舍入。

  5. 溢出判断:检查阶码是否溢出。如果阶码超过最大值,则为上溢(overflow),通常用无穷大表示;如果阶码小于最小值,则为下溢(underflow),通常用非规格化数或零来表示。

2.4.4 浮点数的乘除运算

浮点数乘法运算的步骤:

  1. 阶码相加:两个操作数的阶码相加,减去偏移量(因为两个移码相加多加了一个偏移量)。
  2. 尾数相乘:两个操作数的尾数相乘,得到双倍长度的乘积。
  3. 规格化:对乘积进行规格化处理。
  4. 舍入:对结果进行舍入处理。
  5. 溢出判断:检查阶码是否溢出。
  6. 符号位确定:同号为正,异号为负。

浮点数除法运算的步骤:

  1. 阶码相减:被除数的阶码减去除数的阶码,加上偏移量。
  2. 尾数相除:被除数的尾数除以除数的尾数。
  3. 规格化:对商进行规格化处理。
  4. 舍入:对结果进行舍入处理。
  5. 溢出判断:检查阶码是否溢出。
  6. 符号位确定:同号为正,异号为负。

2.5 非数值数据的表示

计算机不仅需要处理数值数据,还需要处理文字、图形、图像、声音等非数值数据。非数值数据在计算机中也是用二进制编码来表示的,只是编码方式不同。

2.5.1 字符编码

ASCII码(American Standard Code for Information Interchange,美国信息交换标准代码):使用7位二进制编码,可以表示128个字符,包括26个大写英文字母、26个小写英文字母、10个数字、32个控制字符和34个专用符号。在计算机中通常用一个字节(8位)存储一个ASCII字符,最高位为0或用作校验位。ASCII码是西文字符编码的基础,至今仍被广泛使用。

Unicode编码:为了解决ASCII码无法表示世界各国文字的问题,Unicode组织制定了统一的字符编码标准。Unicode为世界上几乎所有文字系统中的每个字符都分配了唯一的编码,目前收录的字符数已超过14万个。Unicode的编码方案有UTF-8、UTF-16、UTF-32等多种实现形式。UTF-8是最常用的实现形式,它使用1-4个字节的变长编码,兼容ASCII码(ASCII字符的UTF-8编码与ASCII码完全相同),对于常用汉字使用3个字节编码。

汉字编码:汉字编码包括输入码(用于输入汉字,如拼音码、五笔码等)、内码(计算机内部存储和处理汉字使用的编码,如GB2312、GBK、GB18030等)和字模码(用于显示和打印汉字的点阵或矢量信息)三个层面。从输入到显示,汉字需要经过”输入码→内码→字模码”的转换过程。

2.5.2 其他数据表示

  • 图像数据:图像可以看作是像素的集合,每个像素用若干位二进制数来表示其颜色信息。黑白图像每个像素用1位表示,灰度图像每个像素用8位表示256个灰度等级,真彩色图像每个像素用24位(RGB各8位)表示约1677万种颜色。
  • 音频数据:声音是连续的模拟信号,需要通过采样、量化、编码三个步骤将其转换为数字信号。采样频率决定了声音的频率范围(根据奈奎斯特定理,采样频率应不低于信号最高频率的2倍),量化位数决定了声音的动态范围,编码方式决定了数据的存储格式。
  • 视频数据:视频是连续的图像序列(帧),每秒通常包含24-60帧。由于视频数据量巨大,通常需要采用压缩编码(如H.264、H.265等)来减少存储和传输的开销。

2.6 数据校验码

数据在存储和传输过程中可能会因为噪声、干扰等原因而发生错误,校验码的作用就是检测甚至纠正这些错误。

2.6.1 奇偶校验码

奇偶校验码是最简单的检错码,通过在数据位后添加一个校验位,使得整个码字中”1”的个数为奇数(奇校验)或偶数(偶校验)。

  • 奇校验:数据位中”1”的个数加上校验位后为奇数。
  • 偶校验:数据位中”1”的个数加上校验位后为偶数。

例如,数据位为1011010,其中”1”的个数为4(偶数),则奇校验位为1,偶校验位为0。

奇偶校验码只能检测奇数个位的错误,无法检测偶数个位的错误,也无法确定错误的位置,因此不能纠错。但由于其实现简单、开销小,仍被广泛用于内存校验、串行通信等场景。

2.6.2 海明码(Hamming Code)

海明码是一种既能检错又能纠错的编码,由Richard Hamming于1950年提出。海明码的基本思想是在数据位中插入若干校验位,每个校验位负责校验一组特定的数据位,通过多重校验来定位错误。

海明码的编码规则:

  1. 校验位的位置:校验位放在2的幂次位置上(即第1、2、4、8、16…位),其余位置放数据位。
  2. 校验位的确定:每个校验位负责校验所有位置编号中对应位为1的数据位。例如,第1位校验位负责校验所有奇数位(位置编号的最低位为1的位),第2位校验位负责校验位置编号中第2位为1的位,以此类推。
  3. 校验位的值:根据所负责校验的数据位的异或结果来确定,使得该校验组中”1”的个数为偶数(偶校验方式)。

海明码的检错和纠错:接收端对每个校验组进行异或校验,得到一个校验子(syndrome)。如果所有校验子都为0,则没有错误;如果某个校验子不为0,则其组合值就是错误位的位置编号,将对应位取反即可纠正错误。

海明码的最小码距为3,可以检测2位错误或纠正1位错误。如果需要同时检测2位错误和纠正1位错误,需要增加一个总校验位(扩展海明码,最小码距为4)。

设数据位为k位,校验位为r位,则海明码必须满足:2^r ≥ k + r + 1。例如,8位数据需要4位校验位(2⁴=16 ≥ 8+4+1=13),16位数据需要5位校验位。

2.6.3 循环冗余校验码(CRC)

循环冗余校验码(Cyclic Redundancy Check,CRC)是一种基于多项式编码的检错码,广泛应用于数据通信和存储领域(如以太网、USB、磁盘存储等)。

CRC编码的基本原理:

  1. 将待发送的k位数据看作一个(k-1)次多项式M(x)。
  2. 发送方和接收方事先约定一个生成多项式G(x),其次数为r。
  3. 在数据多项式M(x)后面添加r个0,得到M(x)·x^r。
  4. 用M(x)·x^r对G(x)进行模2除法,得到余数R(x)(r位)。
  5. 将余数R(x)附加到数据后面发送,即发送的码字为M(x)·x^r + R(x)。

接收端收到码字后,用同一个生成多项式G(x)进行模2除法。如果余数为0,则认为没有错误;如果余数不为0,则检测到错误。

CRC的检错能力取决于生成多项式的选择。一个好的生成多项式可以检测所有奇数个错误、所有长度不超过r的突发错误、以及大部分更长的突发错误。常用的CRC生成多项式有CRC-16、CRC-32等,其中CRC-32可以检测所有32位以下的突发错误,误检率极低(约为2⁻³²)。

CRC码的名称中的”循环”来源于其代数性质:CRC码的任何循环移位仍然是合法的CRC码。这一性质使得CRC码在代数理论上具有优美的结构,也为高效的编解码算法提供了基础。

第三章 存储系统

3.1 存储系统概述

存储器是计算机系统中用来存放程序和数据的部件,是冯·诺依曼体系结构的核心组成部分。对存储器的核心要求是:容量大、速度快、成本低。然而,这三个目标往往是相互矛盾的——速度快的存储器通常容量小、成本高;容量大的存储器通常速度慢、成本低。为了解决这一矛盾,现代计算机系统采用层次化存储结构,通过不同层次存储器的配合来实现”速度接近最快的存储器、容量接近最大的存储器、成本接近最便宜的存储器”的目标。

3.2 存储器的层次结构

现代计算机系统的存储器通常按照以下层次组织(从上到下,速度递减、容量递增、成本递降):

  1. 寄存器:位于CPU内部,速度最快(访问时间约0.1-0.5ns),容量最小(通常几十到几百个),成本最高。寄存器是CPU内部的工作单元,直接参与运算和控制。
  2. 高速缓存(Cache):位于CPU与主存之间,速度很快(访问时间约1-10ns),容量较小(几KB到几十MB),成本较高。Cache利用程序的局部性原理,将主存中频繁访问的数据和指令缓存起来,减少CPU访问主存的次数,从而提高系统性能。现代CPU通常有多级Cache(L1、L2、L3),L1最快但容量最小,L3最慢但容量最大。
  3. 主存储器(Main Memory):也称内存,速度中等(访问时间约50-100ns),容量较大(几GB到几百GB),成本中等。主存是CPU可以直接访问的存储器,存放当前正在执行的程序和正在处理的数据。主存通常采用DRAM(动态随机存取存储器)芯片实现。
  4. 辅助存储器(Secondary Storage):也称外存,速度慢(访问时间约ms级),容量大(几百GB到几TB),成本低。辅存存放暂时不用的程序和数据,CPU不能直接访问辅存,需要将辅存中的数据调入主存后才能使用。辅存通常采用硬盘(HDD)、固态硬盘(SSD)等实现。

存储层次结构的设计基础是程序的局部性原理

  • 时间局部性(Temporal Locality):如果一个存储单元被访问,那么在不久的将来它很可能再次被访问。例如,循环体中的指令会被反复执行,累加变量会被反复读写。
  • 空间局部性(Spatial Locality):如果一个存储单元被访问,那么其附近的存储单元也很可能被访问。例如,数组元素通常被顺序访问,指令通常被顺序执行。

局部性原理使得层次化存储结构能够有效工作——虽然Cache的容量远小于主存,但由于局部性原理,CPU大部分时间都能在Cache中找到所需的数据(Cache命中率通常在90%以上),从而实现了接近Cache速度的平均访问时间。

3.3 半导体存储器

3.3.1 SRAM(静态随机存取存储器)

SRAM使用6个晶体管(6T)构成一个存储单元,利用双稳态触发器来存储一位信息。只要不断电,存储的信息就不会丢失,因此称为”静态”存储器。

SRAM的特点:

  • 速度快(访问时间约1-10ns),是所有半导体存储器中最快的。
  • 不需要刷新,控制简单。
  • 集成度低(每个存储单元需要6个晶体管),容量较小。
  • 功耗较高(静态功耗和动态功耗都较高)。
  • 成本高。

SRAM主要用于CPU的高速缓存(L1、L2、L3 Cache),对速度要求最高但对容量要求相对较小的场合。

3.3.2 DRAM(动态随机存取存储器)

DRAM使用1个晶体管和1个电容(1T1C)构成一个存储单元,利用电容的充放电状态来存储一位信息。由于电容会缓慢放电,存储的信息会随时间丢失,因此需要定期”刷新”(重新充电),因此称为”动态”存储器。

DRAM的特点:

  • 速度较慢(访问时间约50-100ns),比SRAM慢。
  • 需要定期刷新(通常每64ms刷新一次),控制较复杂。
  • 集成度高(每个存储单元只需要1个晶体管和1个电容),容量大。
  • 功耗较低(主要消耗在刷新操作上)。
  • 成本低。

DRAM主要用于计算机的主存储器。为了提高DRAM的访问速度,发展了多种改进型DRAM:

  • FPM DRAM(Fast Page Mode DRAM):快速页模式DRAM,允许对同一行中的多个列进行快速访问。
  • EDO DRAM(Extended Data Out DRAM):扩展数据输出DRAM,在输出数据的同时可以开始下一次访问。
  • SDRAM(Synchronous DRAM):同步DRAM,与系统时钟同步工作,提高了数据传输率。
  • DDR SDRAM(Double Data Rate SDRAM):双倍数据率SDRAM,在时钟的上升沿和下降沿都能传输数据,数据传输率翻倍。DDR2、DDR3、DDR4、DDR5等后续标准不断提高频率和降低功耗。

3.3.3 只读存储器(ROM)

ROM是一种非易失性存储器,断电后信息不会丢失,通常用于存储固件(如BIOS)、引导程序等不需要频繁修改的数据。

ROM的类型:

  • 掩膜式ROM(Mask ROM):在制造时将信息写入,之后不能修改。适合大批量生产,成本最低。
  • PROM(Programmable ROM):可编程ROM,用户可以使用专用设备写入一次,之后不能修改。
  • EPROM(Erasable Programmable ROM):可擦除可编程ROM,使用紫外线照射可以擦除全部内容,然后重新编程。擦除过程需要将芯片从电路板上取下,不太方便。
  • EEPROM(Electrically Erasable Programmable ROM):电可擦除可编程ROM,可以使用电信号擦除和重新编程,且可以按字节进行擦除和编程,使用方便。但集成度较低,容量较小。
  • Flash Memory(闪存):一种改进的EEPROM,以块为单位进行擦除,集成度高,容量大。闪存是目前最常用的非易失性存储器,广泛应用于U盘、固态硬盘(SSD)、手机存储等。闪存分为NOR Flash和NAND Flash两种类型:NOR Flash支持随机访问,适合存储代码;NAND Flash以页为单位读写、以块为单位擦除,集成度高、成本低,适合大容量数据存储。

3.4 高速缓存(Cache)

3.4.1 Cache的基本原理

Cache是位于CPU和主存之间的高速缓冲存储器,其目标是利用程序的局部性原理,使CPU尽可能在Cache中找到所需的数据,减少访问主存的次数,从而缩短平均访问时间。

Cache的基本工作原理:CPU访问存储器时,先在Cache中查找,如果找到则称为命中(hit),直接从Cache中读取数据;如果没找到则称为缺失(miss),需要从主存中读取数据,并将该数据所在的主存块调入Cache中,以便后续访问时命中。

Cache的性能指标:

  • 命中率(Hit Rate):CPU访问Cache时命中的比例,h = 命中次数 / 总访问次数。命中率是衡量Cache性能的最重要指标,通常在90%-99%之间。
  • 缺失率(Miss Rate):1 - h,通常在1%-10%之间。
  • 平均访问时间:t_a = h × t_c + (1-h) × t_m,其中t_c为Cache访问时间,t_m为主存访问时间。

3.4.2 Cache的映射方式

Cache的映射方式决定了主存块如何映射到Cache中的位置。主存和Cache都划分为大小相同的(block),主存块调入Cache时需要确定存放在Cache的哪个位置。

1. 直接映射(Direct Mapping)

每个主存块只能映射到Cache中的一个固定位置。映射关系为:Cache行号 = 主存块号 mod Cache行数。

主存地址格式:| Tag | Index | Offset |

直接映射的优点是地址映射简单、查找速度快(只需比较一个Tag),缺点是冲突概率高——如果两个频繁访问的主存块映射到同一个Cache行,就会反复替换(颠簸),导致命中率下降。

2. 全相联映射(Fully Associative Mapping)

每个主存块可以映射到Cache中的任意位置。当CPU访问一个主存块时,需要在Cache的所有行中同时查找。

全相联映射的优点是冲突概率最低(只有Cache满了才会冲突),空间利用率最高,缺点是查找需要将主存地址的Tag与Cache中所有行的Tag进行比较,硬件实现复杂、功耗高、速度慢。全相联映射通常只用于容量较小的Cache(如TLB)。

3. 组相联映射(Set Associative Mapping)

将Cache分成若干组,每组包含若干行(way)。每个主存块映射到Cache中一个固定的组,但在组内可以放在任意一行。映射关系为:Cache组号 = 主存块号 mod Cache组数。

如果每组有n行,则称为n路组相联映射。例如,4路组相联表示每组有4行,主存块可以放在该组的4个位置中的任意一个。查找时只需要在该组的n行中并行比较Tag。

组相联映射是直接映射和全相联映射的折中方案,兼具两者的优点:冲突概率比直接映射低,硬件复杂度比全相联映射低。现代CPU的L1 Cache通常采用2路或4路组相联,L2和L3 Cache通常采用4路、8路或16路组相联。

3.4.3 Cache的替换算法

当Cache缺失且需要调入新的主存块,但Cache中对应的行(或组)已满时,需要选择一个旧块替换出去。替换算法的目标是尽可能替换将来最长时间内不会被访问的块,以提高命中率。

  • 随机替换算法(Random):随机选择一个Cache行进行替换。实现简单,但命中率不稳定。
  • 先进先出算法(FIFO):替换最早调入Cache的块。实现较简单,但没有考虑块的访问频率,可能会替换掉频繁访问的块。
  • 最近最少使用算法(LRU,Least Recently Used):替换最近最长时间没有被访问的块。LRU基于时间局部性原理——最近被访问的块将来也最可能被访问,因此应该保留最近访问的块。LRU的命中率通常最高,但实现较复杂,需要记录每个块的访问顺序。对于n路组相联的Cache,精确实现LRU需要n!个状态,随着路数的增加,硬件开销急剧增大。因此,实际中通常采用近似LRU算法(如伪LRU),在保持较高命中率的同时降低硬件复杂度。
  • 最不经常使用算法(LFU,Least Frequently Used):替换访问次数最少的块。LFU考虑了块的长期访问频率,但需要为每个块维护访问计数器,且对早期的访问记录过于敏感,可能无法适应访问模式的变化。

3.4.4 Cache的写入策略

Cache中的数据是主存数据的副本,当CPU修改了Cache中的数据时,需要保证Cache和主存之间的数据一致性,这就是Cache的写入策略要解决的问题。

1. 写命中时的策略(CPU要写入的数据在Cache中):

  • 写直达法(Write Through):同时写入Cache和主存。优点是Cache和主存始终保持一致,实现简单;缺点是每次写操作都需要访问主存,速度慢,增加了总线带宽的压力。
  • 写回法(Write Back):只写入Cache,不立即写入主存,只有当该块被替换出Cache时才写回主存。为了标识哪些块被修改过,每个Cache行需要增加一个脏位(dirty bit),修改过的块脏位置1。写回法的优点是减少了写主存的次数,速度快;缺点是Cache和主存可能不一致,控制较复杂,且在替换时可能需要额外的时间写回脏块。

2. 写缺失时的策略(CPU要写入的数据不在Cache中):

  • 写分配法(Write Allocate):先将主存块调入Cache,然后在Cache中修改(通常配合写回法使用)。这样可以利用后续对该块其他字的访问,提高命中率。
  • 非写分配法(Not Write Allocate):直接写入主存,不将主存块调入Cache(通常配合写直达法使用)。这样可以避免不必要的Cache块调入,节省Cache空间。

3.5 虚拟存储器

虚拟存储器是主存和辅存之间的一种存储管理技术,它为每个进程提供一个统一的、连续的、私有的地址空间(虚拟地址空间),使得程序员可以按照虚拟地址来编写程序,而不需要考虑物理内存的大小和分配情况。

虚拟存储器的基本原理:

  1. 程序使用的地址是虚拟地址(逻辑地址),CPU发出的虚拟地址需要通过地址转换机制转换为物理地址(实地址),才能访问主存。
  2. 地址转换由内存管理单元(MMU,Memory Management Unit)硬件完成,使用页表(Page Table)来记录虚拟页到物理页的映射关系。
  3. 当访问的虚拟页不在主存中时,产生缺页异常(Page Fault),操作系统将所需的页从辅存调入主存,更新页表,然后重新执行该指令。
  4. 当主存空间不足时,操作系统使用页面替换算法(类似于Cache的替换算法)选择一个页面换出到辅存,腾出空间给新调入的页面。

虚拟存储器的优点:

  • 扩大了可用的地址空间:程序员可以使用比物理内存大得多的虚拟地址空间。
  • 方便了程序的编写和链接:每个进程有独立的地址空间,简化了内存管理。
  • 实现了内存保护:不同进程的地址空间相互隔离,防止了一个进程越界访问另一个进程的内存。
  • 提高了内存利用率:只有实际使用的页面才占用物理内存,不使用的页面可以换出到辅存。

快表(TLB,Translation Lookaside Buffer):为了加速虚拟地址到物理地址的转换,MMU中设置了TLB,这是一个小容量的、全相联或组相联映射的Cache,缓存了最近使用的页表项。地址转换时先查TLB,如果命中则直接获得物理页号;如果缺失则查页表,并将查到的页表项写入TLB。TLB的命中率通常在99%以上,极大地提高了地址转换的速度。

第四章 指令系统

4.1 指令系统概述

指令系统(Instruction Set Architecture,ISA)是计算机硬件和软件之间的接口,它定义了CPU能够执行的所有指令的集合,包括指令的格式、操作类型、寻址方式、寄存器组织等。指令系统是程序员(或编译器)所能看到的计算机的属性,是计算机体系结构的核心内容。

指令系统的设计需要在多个方面进行权衡:

  • 指令格式:指令的长度是固定还是可变?操作码和地址码如何分配?
  • 操作类型:支持哪些操作?算术运算、逻辑运算、数据传送、控制转移、输入输出等。
  • 寻址方式:如何确定操作数的地址?立即寻址、直接寻址、间接寻址、寄存器寻址等。
  • 寄存器组织:有多少个通用寄存器?有哪些专用寄存器?
  • 数据类型:支持哪些数据类型?整数、浮点数、字符串等。

4.2 指令格式

一条指令通常由两部分组成:操作码(Opcode)和地址码(Operand)。

  • 操作码:指定指令要执行的操作,如加法、减法、数据传送、跳转等。操作码的位数决定了指令系统中最多能支持的操作种类。n位操作码最多可以表示2ⁿ种操作。
  • 地址码:指定操作数的位置或操作数本身。地址码可以是操作数的地址、寄存器编号、立即数等。

根据地址码的数量,指令可以分为:

  • 三地址指令:OP A1, A2, A3 —— 执行(A1) OP (A2) → A3。三个地址分别指定两个源操作数和一个目的操作数。
  • 二地址指令:OP A1, A2 —— 执行(A1) OP (A2) → A1。一个源操作数同时作为目的操作数,执行后源操作数被覆盖。
  • 一地址指令:OP A1 —— 执行(Acc) OP (A1) → Acc。隐含使用累加器(Acc)作为另一个操作数和结果的目的地。
  • 零地址指令:OP —— 无地址码,用于不需要操作数的指令(如停机、空操作)或使用堆栈的指令(堆栈操作隐含使用栈顶元素)。

指令格式的设计需要考虑指令长度、操作码编码和地址码编码三个方面。指令长度可以是固定的(如RISC通常采用32位定长指令),也可以是可变的(如x86采用1-15字节变长指令)。定长指令的译码简单、执行效率高,但编码效率较低;变长指令编码效率高,但译码复杂。

操作码的编码方式有两种:

  • 固定长度操作码:所有指令的操作码长度相同,译码简单,但可能浪费编码空间。
  • 可变长度操作码(扩展操作码):不同指令的操作码长度不同,常用指令使用短操作码,不常用指令使用长操作码,可以提高编码效率。扩展操作码通过在地址码字段中借用位来扩展操作码的长度,实现灵活的编码方案。

4.3 寻址方式

寻址方式是指确定指令中操作数地址的方法。不同的寻址方式提供了不同级别的灵活性和效率。

  1. 立即寻址(Immediate Addressing):操作数直接包含在指令中。例如,ADD R1, #5(将5加到R1中)。优点是不需要访问存储器获取操作数,速度快;缺点是操作数的大小受指令地址码字段的限制,灵活性差。

  2. 直接寻址(Direct Addressing):指令中给出操作数的有效地址。例如,ADD R1, 1000(将地址1000中的内容加到R1中)。优点是简单直观,只需要一次访存;缺点是地址空间受指令地址码字段长度的限制,且地址是固定的,不方便程序的再定位。

  3. 间接寻址(Indirect Addressing):指令中给出操作数地址的地址。需要两次访存:第一次访问指令中给出的地址获取操作数的有效地址,第二次访问有效地址获取操作数。优点是扩大了寻址空间,提供了更大的灵活性;缺点是需要多次访存,速度慢。

  4. 寄存器寻址(Register Addressing):操作数存放在寄存器中,指令中给出寄存器编号。例如,ADD R1, R2(将R2的内容加到R1中)。优点是不需要访存,速度快,寄存器编号短,节省指令空间;缺点是寄存器数量有限。

  5. 寄存器间接寻址(Register Indirect Addressing):操作数的有效地址存放在寄存器中,指令中给出寄存器编号。例如,ADD R1, (R2)(将R2指向的存储单元的内容加到R1中)。优点是只需一次访存,且可以方便地实现数组、指针等数据结构的访问;缺点是需要额外的寄存器来存放地址。

  6. 偏移寻址(Displacement Addressing):有效地址 = 寄存器内容 + 指令中给出的偏移量。这是最常用的寻址方式之一,包括:

    • 基址寻址:基址寄存器 + 偏移量。基址寄存器通常由操作系统设置,用于实现程序的再定位。
    • 变址寻址:变址寄存器 + 偏移量。变址寄存器的内容可以自动递增或递减,适合数组访问和循环操作。
    • 相对寻址:PC(程序计数器) + 偏移量。偏移量是相对于当前指令位置的位移量,常用于条件转移指令,便于实现位置无关代码。
  7. 堆栈寻址(Stack Addressing):操作数存放在堆栈中,由堆栈指针(SP)隐含指定。堆栈操作(PUSH/POP)自动修改SP的值,不需要在指令中显式给出地址。

4.4 CISC与RISC

CISC(Complex Instruction Set Computer,复杂指令集计算机)和RISC(Reduced Instruction Set Computer,精简指令集计算机)是两种不同的指令系统设计哲学。

CISC的设计思想

  • 指令丰富,功能强大,每条指令可以执行复杂的操作。
  • 指令长度可变,格式多样。
  • 寻址方式多,灵活性强。
  • 微程序控制为主,便于实现复杂指令。
  • 代表:x86架构(Intel、AMD的处理器)。

CISC的设计初衷是在硬件层面提供尽可能多的功能,以减少软件的复杂度和代码量。但随着指令越来越复杂,指令的执行时间也越长,且很少有程序能用到所有指令。统计研究表明,80%的程序运行时间只使用了20%的指令(80/20法则),大量复杂指令的实际使用率极低,却增加了硬件的复杂度和设计成本。

RISC的设计思想

  • 指令精简,只保留最常用的简单指令,复杂功能通过简单指令的组合来实现。
  • 指令长度固定,格式规整,便于流水线执行。
  • 寻址方式少,只有Load/Store指令访问存储器,其余指令在寄存器之间操作(Load/Store架构)。
  • 硬布线控制为主,指令执行速度快。
  • 大量通用寄存器,减少访存次数。
  • 重视指令流水线的优化,力争一个时钟周期完成一条指令。
  • 代表:ARM、MIPS、RISC-V架构。

RISC的设计哲学是”简单就是快”——通过简化指令格式和寻址方式,使硬件设计更简单,从而提高时钟频率和流水线效率。虽然RISC完成同样功能可能需要更多的指令,但由于每条指令的执行速度更快,整体性能往往优于CISC。

CISC与RISC的比较

特性CISCRISC
指令数量多(通常200+)少(通常100左右)
指令长度可变固定
寻址方式
指令执行时间差异大大多数1个周期
控制器实现微程序为主硬布线为主
寄存器数量较少较多
流水线效率较低较高
编译优化较难较易

值得注意的是,现代CISC处理器(如Intel和AMD的x86处理器)在内部采用了RISC的设计思想——将复杂的x86指令翻译为简单的微操作(micro-ops),然后以RISC的方式来执行这些微操作,从而兼得CISC的软件兼容性和RISC的执行效率。因此,CISC和RISC的界限在当代已经变得模糊,两者正在走向融合。

4.5 指令集的发展

指令集架构的发展经历了以下几个重要阶段:

  1. 早期指令集:指令系统相对简单,主要用于科学计算,指令数量少,格式单一。

  2. CISC时代:随着计算机应用范围的扩大,指令系统不断扩充,加入了越来越多的复杂指令和寻址方式,以支持更高级的语言特性和更复杂的应用需求。VAX、x86等是CISC时代的代表。

  3. RISC革命:1980年代,UC Berkeley的David Patterson和Stanford的John Hennessy分别提出了RISC的设计思想,引发了指令集架构的革命。RISC的核心理念是简化指令系统,让硬件更高效地执行简单指令,将复杂度交给编译器处理。MIPS、SPARC、ARM等是RISC时代的代表。

  4. 后RISC时代:现代处理器在RISC的基础上增加了许多增强特性,如条件执行指令、SIMD指令(单指令多数据,用于多媒体和向量处理)、原子指令(用于多核同步)等,指令集再次变得复杂,但核心执行机制仍然是RISC的。

  5. 开源指令集:近年来,RISC-V作为一种开源的指令集架构受到了广泛关注。与ARM等商业指令集不同,RISC-V是完全开源和免费的,任何人都可以基于RISC-V设计和制造处理器,无需支付授权费用。RISC-V的模块化设计使得它可以根据不同的应用需求进行定制,从嵌入式系统到高性能计算都可以适用,被认为是指令集架构的未来发展方向之一。

第五章 中央处理器

5.1 CPU的基本结构

中央处理器(Central Processing Unit,CPU)是计算机系统的核心部件,负责执行指令、处理数据、控制整个计算机的运行。现代CPU的结构非常复杂,但其基本组成可以归纳为以下几个主要部分:

  1. 运算器(Datapath):负责执行各种算术和逻辑运算。主要包括ALU(算术逻辑单元)、通用寄存器组、累加器、程序状态字寄存器(PSW)等。ALU是运算器的核心,在控制信号的控制下完成加、减、与、或、异或、移位等基本运算。通用寄存器组用于暂存操作数和运算结果,访问速度最快。PSW(也称标志寄存器)保存运算结果的状态信息,如零标志(ZF)、进位标志(CF)、符号标志(SF)、溢出标志(OF)等,这些标志位用于条件转移指令的判断。

  2. 控制器(Control Unit):负责产生控制信号,驱动各部件协调工作。控制器从存储器中取出指令,对指令进行译码,产生相应的微操作控制信号序列,控制运算器、存储器、I/O设备等部件按照正确的时序完成指令规定的操作。控制器是CPU的”指挥中心”。

  3. 中断系统:负责处理各种中断请求。当CPU接收到中断请求时,在当前指令执行完毕后,暂停当前程序的执行,保存现场,转去执行中断服务程序,处理完毕后恢复现场,返回被中断的程序继续执行。中断系统使CPU能够及时响应外部事件和异常情况,提高了系统的实时性和可靠性。

  4. 总线接口:负责CPU与外部总线(系统总线)的连接,实现CPU与存储器、I/O设备之间的数据交换。总线接口包括地址驱动器、数据收发器、总线控制器等。

5.2 指令的执行过程

一条指令的执行过程通常分为以下几个阶段:

  1. 取指(Fetch):根据程序计数器(PC)的值,从存储器中取出当前要执行的指令,送到指令寄存器(IR)中。同时PC自动加1(或加上指令长度),指向下一条指令。

  2. 译码(Decode):对指令寄存器中的指令进行分析和译码,确定指令的操作类型、操作数来源和结果的去向。译码器根据操作码产生相应的控制信号,根据地址码确定操作数的地址或寄存器编号。

  3. 执行(Execute):根据译码结果,ALU执行指令规定的运算操作。不同类型的指令执行不同的操作:算术逻辑指令在ALU中执行运算,数据传送指令在寄存器和存储器之间传送数据,转移指令修改PC的值实现程序跳转。

  4. 访存(Memory Access):对于需要访问存储器的指令(如Load/Store指令),在执行阶段计算出的有效地址访问存储器,读取或写入数据。

  5. 写回(Write Back):将运算结果写回目的寄存器或存储单元。

上述五个阶段是典型的五段流水线划分,不同架构的CPU可能有不同的划分方式。对于非流水线CPU,一条指令完整执行完上述所有阶段后,才开始执行下一条指令。这种方式简单但效率低,因为每个时钟周期只有一个功能部件在工作,其他功能部件处于空闲状态。

5.3 指令流水线

5.3.1 流水线的基本原理

指令流水线是将指令的执行过程划分为多个阶段,每个阶段由不同的功能部件完成,多条指令的不同阶段可以重叠执行,从而提高指令吞吐率。

以经典的五段流水线为例(取指IF、译码ID、执行EX、访存MEM、写回WB),在没有流水线的情况下,每条指令需要5个时钟周期才能执行完,5条指令需要25个时钟周期。而在理想流水线中,每个时钟周期都有一条新指令进入流水线,经过5个周期的填充后,每个时钟周期都有一条指令完成,5条指令只需要9个时钟周期就能执行完(第一条指令5个周期,后续4条指令各1个周期),吞吐率提高了近5倍。

流水线的性能指标:

  • 吞吐率(Throughput):单位时间内完成的指令数。理想情况下,n段流水线的最大吞吐率为1/Δt(Δt为流水线各段时间中最长的一段),即每个时钟周期完成一条指令。
  • 加速比(Speedup):流水线方式与非流水线方式的执行时间之比。理想情况下,n段流水线的最大加速比为n。
  • 效率(Efficiency):流水线中各功能段的利用率。

5.3.2 流水线冲突(Hazard)

流水线的理想工作状态是每个时钟周期都有一条指令完成,但实际上流水线经常会遇到各种冲突,导致指令不能按预期执行,必须暂停等待。

1. 结构冲突(Structural Hazard)

当不同指令在同一时钟周期需要使用同一功能部件时,就会发生结构冲突。例如,如果指令存储器和数据存储器共用同一个存储器,那么取指阶段和访存阶段就可能同时需要访问存储器,产生冲突。

解决方法:

  • 增加硬件资源:如采用哈佛结构(独立的指令Cache和数据Cache),使取指和访存可以并行进行。
  • 采用暂停等待:让一条指令暂停一个周期,等冲突的部件空闲后再继续执行。

2. 数据冲突(Data Hazard)

当后续指令需要使用前面指令的运算结果,而前面指令的结果尚未产生时,就会发生数据冲突。数据冲突有三种类型:

  • 写后读冲突(RAW,Read After Write):最常见的数据冲突。后续指令需要读取前面指令写入的数据,但前面指令尚未完成写入。
  • 读后写冲突(WAR,Write After Read):前面指令需要读取数据,但后续指令已经写入了新值。在顺序流水线中不会发生,但在乱序执行中可能出现。
  • 写后写冲突(WAW,Write After Write):两条指令写入同一寄存器,但执行顺序与程序顺序不同。在顺序流水线中不会发生,但在乱序执行中可能出现。

解决方法:

  • 数据前推/旁路(Forwarding/Bypassing):将ALU的运算结果直接前推到后续指令的ALU输入端,而不需要等待写回寄存器后再读取,减少了等待周期。这是最有效的数据冲突解决方法,可以消除大部分RAW冲突。
  • 编译器调度:由编译器在不改变程序语义的前提下,调整指令的顺序,将不相关的指令插到有数据依赖的指令之间,避免冲突。
  • 插入气泡(Stall):在检测到数据冲突时,暂停流水线,插入空操作(气泡),等待前面指令完成后再继续执行。这是最简单但效率最低的方法。

3. 控制冲突(Control Hazard)

当遇到转移指令(条件跳转、无条件跳转、调用、返回等)时,在转移条件判断完成之前,流水线不知道下一条指令应该从哪里取指,就会发生控制冲突。特别是条件转移指令,需要等到执行阶段才能确定是否跳转,而此时流水线中已经取入了后续的若干条指令(这些指令可能是不应该执行的)。

解决方法:

  • 分支预测(Branch Prediction):预测分支的走向(跳转或不跳转),按预测方向取指执行。如果预测正确,则流水线不受影响;如果预测错误,则需要清空流水线中错误取入的指令,按正确方向重新取指,这称为预测失败惩罚。
    • 静态预测:根据固定规则预测,如”总是预测不跳转”或”总是预测跳转”。简单但准确率有限。
    • 动态预测:根据分支的历史执行情况进行预测。最常用的是分支目标缓冲器(BTB,Branch Target Buffer)和两位饱和计数器。动态预测的准确率可以达到90%以上,现代高性能处理器的分支预测准确率甚至可达97%-99%。
  • 延迟分支(Delayed Branch):由编译器在分支指令后面填充若干条与分支无关的指令(延迟槽),这些指令无论分支是否跳转都会执行。这样在分支判断期间,流水线不会空闲。这是一种软件方法,依赖于编译器的优化能力。
  • 提前判断:在流水线的更早阶段(如译码阶段)判断分支条件,减少预测失败时的惩罚。

5.3.3 超标量流水线

超标量(Superscalar)处理器在每个时钟周期可以发射多条指令,有多套功能部件可以并行执行多条指令。超标量处理器的指令级并行度(ILP)大于1,可以在不提高时钟频率的情况下提高性能。

超标量处理器的关键技术:

  • 指令发射策略:决定哪些指令可以同时发射执行。顺序发射按程序顺序发射指令;乱序发射可以打破程序顺序,先发射就绪的指令,提高并行度。
  • 指令调度:在硬件层面动态分析指令之间的依赖关系,将没有依赖关系的指令分配到不同的功能部件并行执行。
  • 寄存器重命名:消除伪依赖(WAR和WAW冲突),增加可用的并行度。伪依赖是由于寄存器数量有限导致的不同变量复用同一寄存器而产生的假依赖关系,通过寄存器重命名可以将它们映射到不同的物理寄存器,消除假依赖。
  • 重排序缓冲区(ROB,Reorder Buffer):乱序执行的指令虽然可以不按程序顺序完成,但必须按程序顺序提交结果,以保证程序的正确性。ROB负责维护指令的完成顺序,确保结果按程序顺序写回。

5.3.4 超流水线

超流水线(Superpipeline)是将流水线的每个阶段进一步细分,增加流水线的段数,使每个阶段的工作量更少,从而可以采用更高的时钟频率。例如,将经典的五段流水线细分为十段或更多段,每个子阶段的工作更简单,时钟周期可以更短。

超流水线的优势是可以提高时钟频率,从而提高性能。但流水线段数越多,流水线填充和排空的开销越大,分支预测失败时的惩罚也越大(需要清空更多的流水线段),功耗也越高。因此,流水线段数的增加有一个上限,超过这个上限性能反而会下降。现代处理器的流水线段数通常在10-20段之间。

5.3.5 超长指令字(VLIW)

超长指令字(Very Long Instruction Word,VLIW)是一种与超标量不同的指令级并行方法。在VLIW架构中,编译器负责找出可以并行执行的指令,将它们打包成一条超长指令字(通常128位或更长),每个字段对应一个功能部件的操作。处理器在每个时钟周期取出一条VLIW指令,直接发送到各个功能部件并行执行,不需要硬件进行动态调度。

VLIW的优点是硬件设计简单(不需要复杂的动态调度逻辑),功耗低。缺点是严重依赖编译器的优化能力,代码密度低(当没有足够的并行指令时,VLIW指令中会有很多空槽),且二进制代码与硬件强耦合(功能部件数量变化时需要重新编译)。VLIW主要用于嵌入式处理器和DSP,如TI的C6000系列、Intel的Itanium(IA-64)等。

5.4 中断系统

5.4.1 中断的基本概念

中断是CPU对系统中发生的某些事件的一种响应机制。当某个事件发生时(如I/O操作完成、定时器溢出、硬件故障等),向CPU发出中断请求,CPU在当前指令执行完毕后,暂停当前程序的执行,转去处理该事件(执行中断服务程序),处理完毕后返回被中断的程序继续执行。

中断的作用:

  • 提高了CPU的利用率:CPU不需要轮询等待I/O操作的完成,可以在等待I/O期间执行其他程序。
  • 实现了实时处理:CPU可以及时响应外部设备的请求和紧急事件。
  • 实现了多道程序并发:操作系统通过时钟中断实现进程切换,使多个程序可以”同时”运行。
  • 处理异常情况:当程序出现错误(如除零、非法地址访问等)时,通过中断机制进行异常处理。

5.4.2 中断的处理过程

中断处理的一般过程:

  1. 中断请求:中断源向CPU发出中断请求信号。
  2. 中断判优:当多个中断源同时发出请求时,根据优先级进行裁决,优先响应最高优先级的中断请求。
  3. 中断响应:CPU在当前指令执行完毕后,如果满足响应条件(中断允许标志为1),则响应中断请求。响应过程包括:关中断(防止在保存现场时被新的中断打断)、保存断点(将PC和PSW等关键寄存器的值压入堆栈)、获取中断服务程序入口地址(通过中断向量表或中断向量地址)。
  4. 保护现场:将中断服务程序中需要使用的寄存器的值保存到堆栈中,以免被覆盖。
  5. 中断服务:执行中断服务程序,处理中断事件。
  6. 恢复现场:将之前保存的寄存器值从堆栈中恢复。
  7. 中断返回:执行中断返回指令,从堆栈中弹出断点信息,恢复PC和PSW的值,返回被中断的程序继续执行,同时开中断。

5.4.3 中断的分类

  • 内中断(异常,Exception):由CPU内部产生,包括:

    • 陷阱(Trap):由程序有意产生的中断,如系统调用(SVC指令)。
    • 故障(Fault):由指令执行过程中可恢复的错误引起,如缺页异常、除零异常。
    • 终止(Abort):由严重的不可恢复的硬件错误引起,如存储器校验错误。
  • 外中断(中断,Interrupt):由CPU外部的设备产生,如I/O中断、定时器中断、电源故障中断等。

  • 可屏蔽中断:可以通过设置中断允许标志(IF)来屏蔽的中断,通常是普通的外部中断。

  • 不可屏蔽中断(NMI):不受中断允许标志控制的中断,用于处理紧急事件(如电源故障、存储器校验错误等),必须立即响应。

5.4.4 多重中断与中断嵌套

当CPU正在执行某个中断服务程序时,如果有新的更高优先级的中断请求到来,CPU可以暂停当前的中断服务程序,转去处理新的中断请求,处理完毕后返回继续执行原来的中断服务程序,这就是中断嵌套(或多重中断)。

实现中断嵌套的条件:

  • 在中断服务程序中开中断(允许响应更高优先级的中断请求)。
  • 有优先级更高的中断请求到来。
  • 有足够的堆栈空间来保存多层断点和现场信息。

中断嵌套的深度受到堆栈空间的限制,也受到中断优先级数量的限制。通常,中断嵌套的深度不超过几层。

第六章 总线系统

6.1 总线的基本概念

总线(Bus)是计算机系统中连接各功能部件的一组公共信息通路,它能为多个部件分时共享,实现部件之间的信息传送。采用总线结构的优点是:减少了各部件之间的连线数量,便于系统的扩展和维护,提高了系统的灵活性和可靠性。

总线的基本特性:

  • 物理特性:总线的物理连接方式,包括插头的形状、引脚数目、排列顺序等。
  • 功能特性:每根线的功能,如地址线、数据线、控制线等。
  • 电气特性:信号的传输方向、电平范围、驱动能力等。
  • 时间特性:信号的时序关系,即各信号在什么时间有效。

6.2 总线的分类

按功能层次分:

  • 片内总线:CPU芯片内部的总线,连接CPU内部的各功能部件(如ALU、寄存器组、Cache等)。
  • 系统总线:连接CPU、主存、I/O接口等主要功能部件的总线,也称为前端总线(FSB)或处理器总线。系统总线包括数据总线、地址总线和控制总线。
  • 通信总线:连接计算机系统之间或计算机与其他设备之间的总线,如USB、Ethernet等。

按数据传输方式分:

  • 并行总线:多位数据同时传输,传输速度快,但线数多、干扰大、不易提高频率,适合短距离高速传输。
  • 串行总线:数据逐位传输,线数少、干扰小、频率可以很高,适合长距离传输。随着技术的发展,高速串行总线(如PCIe、SATA、USB 3.0等)已经取代了大部分并行总线。

按信号传输方向分:

  • 单向总线:信号只能沿一个方向传输(单工)。
  • 双向总线:信号可以沿两个方向传输(半双工或全双工)。半双工同一时刻只能沿一个方向传输,全双工可以同时双向传输。

6.3 总线仲裁

总线是多个部件共享的公共通路,同一时刻只能有一个部件控制总线进行数据传输。当多个部件同时请求使用总线时,需要通过总线仲裁机制来决定哪个部件获得总线的控制权。

6.3.1 集中式仲裁

集中式仲裁由一个中央仲裁器(总线控制器)统一管理所有总线请求,决定优先级。

  • 链式查询方式(菊花链方式):所有总线请求通过一条公共请求线发送给仲裁器,仲裁器发出总线授权信号,授权信号沿菊花链依次传递给各设备。离仲裁器最近的设备优先级最高,如果它有请求则截获授权信号,获得总线控制权;否则将授权信号传递给下一个设备。链式查询的优点是结构简单、扩展方便;缺点是优先级固定(离仲裁器近的设备总是优先),可能造成低优先级设备”饥饿”,且对链路故障敏感(一个设备故障可能导致后续设备都无法获得授权)。

  • 计数器定时查询方式:仲裁器内有一个计数器,当接收到总线请求时,计数器从0开始(或从上次停止的位置开始)计数,将计数值发送给各设备,与计数值匹配的设备获得总线控制权。如果计数器每次从0开始,则优先级固定;如果从上次停止的位置开始,则优先级循环,较为公平。计数器定时查询的优先级设置灵活,但需要额外的计数器线和设备编号比较逻辑。

  • 独立请求方式:每个设备有独立的总线请求线和总线授权线,直接与仲裁器连接。仲裁器可以根据固定的优先级或动态策略来决定授权给哪个设备。独立请求方式的优点是响应速度快、优先级设置灵活;缺点是线数多、成本高。

6.3.2 分布式仲裁

分布式仲裁不需要中央仲裁器,每个设备都有自己的仲裁逻辑,通过竞争方式获得总线控制权。

  • 自举分布式仲裁:每个设备在请求总线时,同时检查比自己优先级高的设备是否也在请求。如果没有更高优先级的设备请求,则获得总线控制权。
  • 冲突检测分布式仲裁:每个设备可以自由发送请求,如果检测到冲突(多个设备同时发送),则各设备退避一段随机时间后重新请求。这种方式在以太网中使用。
  • 并行竞争分布式仲裁:每个设备有一个唯一的仲裁号,当多个设备同时请求时,通过比较仲裁号来决定哪个设备获得控制权。

6.4 总线定时

总线定时是指总线操作过程中各信号的时序关系,确保发送方和接收方之间正确地传送数据。

6.4.1 同步定时

同步定时方式使用统一的时钟信号来控制数据传送的时序。所有设备按照时钟信号的节拍进行操作,每个时钟周期完成一步操作。

同步定时的优点是控制简单、速度快;缺点是所有设备必须按照相同的时钟频率工作,灵活性差,且对时钟信号的偏移(skew)敏感。同步定时适合总线长度较短、设备速度接近的场景。

6.4.2 异步定时

异步定时方式不使用统一的时钟信号,而是通过”请求-应答”握手信号来协调数据传送。发送方发出数据后发送请求信号,接收方收到数据后发送应答信号,发送方收到应答后才能进行下一步操作。

异步定时的三种握手方式:

  • 不互锁方式:发送方发出请求信号后,经过一段固定时间后自动撤销请求信号,不等接收方的应答信号。接收方发出应答信号后,经过一段固定时间后自动撤销应答信号。速度最快但可靠性最低。
  • 半互锁方式:发送方发出请求信号后,必须等到接收方的应答信号才能撤销请求信号;接收方发出应答信号后,经过一段固定时间后自动撤销应答信号。可靠性中等。
  • 全互锁方式:发送方发出请求信号后,必须等到接收方的应答信号才能撤销请求信号;接收方发出应答信号后,必须等到发送方的请求信号撤销后才能撤销应答信号。可靠性最高但速度最慢。

异步定时的优点是灵活性高,可以适应不同速度的设备;缺点是控制较复杂,每次数据传送需要额外的握手信号开销。

6.4.3 半同步定时

半同步定时是同步和异步的折中方案。基本时序仍由时钟信号控制,但增加了等待信号(WAIT)。慢速设备可以通过发出WAIT信号来延长总线周期,使快速设备等待慢速设备完成操作。半同步定时在保持同步定时简洁性的同时,增加了对速度不同设备的适应性。

6.5 总线标准

总线标准是为了保证不同厂商生产的设备能够互连而制定的规范。总线标准规定了总线的物理特性、电气特性、功能特性和时间特性。

常见的总线标准:

  • ISA(Industry Standard Architecture):IBM PC/AT使用的总线,16位数据宽度,8MHz时钟频率,带宽约8MB/s。已被淘汰。
  • PCI(Peripheral Component Interconnect):Intel提出的32/64位总线标准,时钟频率33MHz/66MHz,带宽约132-528MB/s。在PC中已基本被PCIe取代。
  • PCIe(PCI Express):目前PC中最主流的扩展总线标准,采用点对点串行传输,每通道带宽约250MB/s(PCIe 1.0)到约4GB/s(PCIe 5.0),支持1-16通道配置。PCIe是全双工的,上下行带宽独立计算。
  • USB(Universal Serial Bus):通用串行总线,用于连接外部设备。USB 1.1带宽12Mbps,USB 2.0带宽480Mbps,USB 3.0带宽5Gbps,USB 3.1带宽10Gbps,USB4带宽40Gbps。USB支持热插拔和即插即用。
  • SATA(Serial ATA):串行ATA接口,用于连接硬盘等存储设备。SATA 3.0带宽6Gbps。
  • I²C(Inter-Integrated Circuit):两线制串行总线,用于连接低速外设(如传感器、EEPROM等),结构简单,适合嵌入式系统。
  • SPI(Serial Peripheral Interface):串行外设接口,用于连接高速外设,全双工通信,速度比I²C快。

第七章 输入输出系统

7.1 输入输出系统概述

输入输出系统(I/O系统)是计算机系统与外部世界进行信息交换的桥梁,包括I/O设备、I/O接口、I/O控制软件等。I/O系统的设计目标是在CPU尽可能少干预的情况下,高效地完成数据的输入输出操作。

I/O设备与主机之间的主要差异:

  • 速度差异:I/O设备的工作速度通常远低于CPU,有的设备(如键盘)速度极慢,有的(如磁盘)速度中等,有的(如网卡)速度较快,但总体都慢于CPU。
  • 数据格式差异:I/O设备的数据格式与主机内部的数据格式可能不同,需要进行转换。
  • 时序差异:I/O设备的工作时序与CPU的时序通常不同,需要进行协调。
  • 电气特性差异:I/O设备的电气特性(电压、电流、信号类型等)与主机可能不同。

I/O接口的作用就是解决这些差异,实现主机与I/O设备之间的协调工作。I/O接口包含数据缓冲寄存器、控制逻辑、状态寄存器等,实现数据的暂存、格式转换、时序协调、地址译码、中断控制等功能。

7.2 I/O接口

I/O接口是主机与I/O设备之间的逻辑界面,其基本功能包括:

  1. 数据缓冲:在接口中设置数据缓冲寄存器,暂存输入输出数据,解决主机与I/O设备之间的速度差异。当主机速度快于I/O设备时,输出数据先存入缓冲寄存器,I/O设备慢慢取走;当I/O设备速度快于主机时,输入数据先存入缓冲寄存器,等待主机读取。

  2. 设备选择:通过地址译码逻辑,确定CPU当前要访问的是哪个I/O设备(或设备的哪个端口)。

  3. 数据格式转换:将I/O设备的数据格式转换为主机内部的数据格式,或进行串并转换。例如,串行I/O设备需要将串行数据转换为并行数据后才能传送给主机。

  4. 命令译码:对CPU发出的I/O命令进行译码,产生控制I/O设备操作的控制信号。

  5. 状态反馈:将I/O设备的当前状态(如忙/闲、就绪/未就绪、出错等)通过状态寄存器反馈给CPU。

  6. 中断控制:当I/O设备完成操作或出现异常时,通过接口向CPU发出中断请求。

I/O端口的编址方式有两种:

  • 统一编址(Memory-Mapped I/O):将I/O端口与主存统一编址,I/O端口占用主存地址空间的一部分。CPU访问I/O端口与访问主存使用相同的指令(Load/Store指令)。优点是不需要专门的I/O指令,指令系统简单;缺点是I/O端口占用了主存地址空间,且访问I/O端口的指令较长。
  • 独立编址(Isolated I/O):I/O端口有独立的地址空间,与主存地址空间互不重叠。CPU需要使用专门的I/O指令(如IN、OUT指令)来访问I/O端口。优点是I/O端口不占用主存地址空间,I/O指令短、执行快;缺点是需要专门的I/O指令和控制信号。x86架构采用独立编址方式,ARM架构采用统一编址方式。

7.3 程序查询方式

程序查询方式是最简单的I/O方式。CPU通过不断查询I/O设备的状态寄存器,判断设备是否就绪,当设备就绪时进行数据传送。

程序查询方式的工作过程:

  1. CPU启动I/O设备。
  2. CPU反复读取设备的状态寄存器,判断设备是否就绪。
  3. 如果设备未就绪,则继续查询(等待);如果设备就绪,则进行数据传送。
  4. 传送完毕后,CPU继续执行后续程序或查询下一个设备。

程序查询方式的优点是实现简单,不需要额外的硬件支持。缺点是CPU在等待设备就绪期间一直处于忙等状态(独占查询)或需要频繁查询(定时查询),严重浪费CPU时间,尤其在设备速度远慢于CPU的情况下。程序查询方式只适合CPU任务单一、对实时性要求不高的简单系统。

7.4 程序中断方式

程序中断方式克服了程序查询方式中CPU忙等的问题。CPU启动I/O设备后,不再等待设备就绪,而是继续执行其他程序。当I/O设备完成操作并就绪时,向CPU发出中断请求,CPU响应中断,暂停当前程序,转去执行中断服务程序进行数据传送,传送完毕后返回被中断的程序继续执行。

程序中断方式的工作过程:

  1. CPU通过I/O指令启动I/O设备,设置中断允许标志。
  2. CPU继续执行其他程序(不等待I/O设备)。
  3. I/O设备完成操作后,通过接口向CPU发出中断请求。
  4. CPU在当前指令执行完毕后,如果中断允许,则响应中断请求。
  5. CPU保存断点,转去执行I/O中断服务程序,进行数据传送。
  6. 中断服务程序执行完毕后,CPU恢复断点,返回被中断的程序继续执行。

程序中断方式的优点是CPU不需要忙等,可以在等待I/O设备的同时执行其他程序,大大提高了CPU的利用率。缺点是每次数据传送都需要CPU介入(执行中断服务程序),对于高速I/O设备(如磁盘),频繁的中断会使CPU花费大量时间在中断处理上,影响系统性能。此外,中断方式的硬件实现比程序查询方式复杂。

7.5 DMA方式

DMA(Direct Memory Access,直接存储器存取)方式是为了解决程序中断方式在高速I/O设备数据传送中的效率问题而引入的。DMA方式下,I/O设备与主存之间的数据传送由DMA控制器直接控制,不需要CPU介入,数据直接在I/O设备和主存之间传送,CPU可以同时执行其他程序。

DMA控制器的基本组成:

  • 主存地址寄存器(MAR):存放主存中数据传送的起始地址。
  • 字计数器(WC):记录要传送的数据字数,每传送一个字,WC减1。
  • 数据缓冲寄存器(DBR):暂存I/O设备与主存之间传送的数据。
  • 设备地址寄存器(DAR):存放I/O设备的地址。
  • 控制/状态逻辑:控制DMA操作的进行,包括DMA请求、DMA响应、读写控制等。

DMA方式的工作过程:

  1. CPU通过程序对DMA控制器进行初始化:设置主存地址、传送字数、传送方向(读/写)、设备地址等参数。
  2. CPU启动I/O设备,然后继续执行其他程序。
  3. I/O设备准备好数据后,向DMA控制器发出DMA请求。
  4. DMA控制器向CPU发出总线请求(Hold Request),请求获得总线控制权。
  5. CPU在当前总线周期结束后,释放总线控制权,向DMA控制器发出总线授权(Hold Acknowledge)。
  6. DMA控制器获得总线控制权后,控制数据在I/O设备和主存之间直接传送。
  7. 每传送一个字,主存地址加1,字计数器减1。
  8. 当字计数器减到0时,数据传送完毕,DMA控制器向CPU发出中断请求,通知CPU传送结束。
  9. CPU响应中断,执行DMA结束中断服务程序(如校验数据、处理异常等),收回总线控制权。

DMA方式与中断方式的比较:

  • 数据传送:中断方式需要CPU介入每一次数据传送;DMA方式由DMA控制器直接控制数据传送,CPU只在初始化和结束时介入。
  • CPU利用率:DMA方式的CPU利用率远高于中断方式,因为CPU不需要参与数据传送过程。
  • 响应时间:中断方式在指令执行完毕后响应;DMA方式在总线周期结束后响应,响应更及时。
  • 适用场合:中断方式适合低速I/O设备(如键盘、鼠标);DMA方式适合高速I/O设备(如磁盘、网卡)的大批量数据传送。
  • 硬件复杂度:DMA控制器比中断控制器复杂,成本更高。

DMA传送方式的三种类型:

  • CPU暂停方式(周期挪用/窃取方式,Cycle Stealing):DMA每次传送一个数据字时,CPU暂停一个总线周期,让DMA控制器使用总线传送数据。传送完毕后CPU立即恢复使用总线。这种方式对CPU的影响最小,但每次只能传送一个字,效率较低。
  • CPU周期窃取方式:与周期挪用方式类似,但DMA在CPU不需要使用总线时(如CPU在内部进行运算时)”窃取”总线周期进行数据传送,对CPU的干扰更小。
  • DMA与CPU交替访存方式:将一个存储器周期分为两个子周期,一个供CPU访存,一个供DMA访存,交替进行。这种方式不需要申请和释放总线,效率最高,但需要存储器有双端口结构,硬件成本高。

7.6 通道方式

通道(Channel)是大型计算机中使用的一种I/O处理方式,可以看作是DMA方式的进一步发展。通道是一个专用的I/O处理器,它有自己的指令系统(通道指令),可以独立执行通道程序,控制I/O设备与主存之间的数据传送,进一步减轻CPU的I/O负担。

通道与DMA的区别:

  • DMA控制器只能控制一台或少数几台I/O设备的数据传送,且传送方式单一;通道可以控制多台I/O设备,且能执行通道程序实现复杂的I/O操作。
  • DMA方式下CPU需要参与初始化和错误处理;通道方式下,CPU只需启动通道,通道独立完成所有I/O操作后向CPU报告结果。
  • DMA控制器的功能是硬连线的,不可编程;通道是可编程的I/O处理器,灵活性更高。

通道的类型:

  • 字节多路通道(Byte Multiplexer Channel):以字节为单位交叉服务多台低速I/O设备。多个设备分时共享通道,每个设备每次传送一个字节。适合连接多台低速设备(如终端、打印机)。
  • 数组选择通道(Selector Channel):以块为单位为一台高速I/O设备服务。一次只为一台设备传送数据,传送完毕后才能切换到另一台设备。适合连接高速设备(如磁盘),但设备利用率低。
  • 数组多路通道(Block Multiplexer Channel):结合了字节多路通道和选择通道的优点,以块为单位交叉服务多台高速I/O设备。多个设备分时共享通道,每个设备每次传送一个数据块。适合连接多台高速设备,设备利用率高。

7.7 I/O方式的比较与总结

I/O方式CPU介入程度数据传送单位适用设备类型硬件复杂度
程序查询高(忙等)低速设备
程序中断中(中断处理)低-中速设备
DMA低(初始化+结束)高速设备
通道很低(仅启动)多种设备最高

从程序查询到通道方式,CPU的I/O负担逐步减轻,I/O系统的自治程度逐步提高,但硬件复杂度也随之增加。在实际系统中,通常根据I/O设备的特点选择不同的I/O方式:低速设备使用中断方式,高速设备使用DMA方式,大型系统使用通道方式,以实现CPU和I/O系统之间的最佳平衡。