computer organization and embedded systems, sixth edition...

23
3 Computer Organization and Embedded Systems, Sixth Edition 基本输入 / 输出 本章目标 在本章中你将学习以下内容: 处理器与输入 / 输出(I/O)设备之间的数据传输 从程序员的角度看 I/O 传输 如何使用轮询方式执行程序来控制 I/O 如何在 I/O 传输中使用中断 计算机的一个基本特性是具有与其他设备交换信息的能力。这一通信能力使操作员可以 完成很多操作,例如用键盘和显示屏幕来处理文本和图形。实际中,我们广泛地使用计算机 通过 Internet 与其他计算机通信并访问全球信息。此外,在其他应用中,计算机虽然不是很明 显,但仍有着同等重要的作用。它们是构成家用电器、制造设备、运输系统、银行和销售点终 端所必需的一部分。在这些应用中,计算机的输入可能来自传感器开关、数字照相机、麦克风 或火警报警器 ;输出可能是发送给扬声器的声音信号或者是用来改变发动机速度、打开阀门或 使机器人按指定方式移动的数字编码指令。简而言之,计算机应具有在不同环境下与多种设备 交换数字信息或模拟信息的能力。 在本章中,我们将从程序员的角度来分析计算机的输入 / 输出(I/O)功能。我们只介绍 所有计算机都提供的基本 I/O 操作,这将使读者可以在典型的教学实验环境中的设备上完成有 趣并有用的练习。更复杂的 I/O 方案,以及实现 I/O 功能所需要的硬件将在第 7 章中讨论。 3.1 访问 I/O 设备 计算机系统的部件之间通过互连网络进行通信,如图 3-1 所示。互连网络包含了在处理 器、存储器和一些 I/O 设备之间进行信息传输所需的电路。 在第 2 章中,我们描述了地址空间的概念 以及处理器如何访问地址空间中独立的存储单 元。Load Store 指令使用寻址方式来产生识别 所需单元的有效地址。这种使用地址来访问存储 器中不同单元的思想也可以扩展到 I/O 设备的处 理上。为此,每个 I/O 设备在处理器看来必须包 括一些可寻址的单元,就像存储器一样。处理器 将地址空间中的一些地址分配给这些 I/O 单元, 而不是主存储器。这些单元通常以寄存器的形式 组织成位存储电路(触发器),习惯上把它们称 I/O 寄存器I/O register)。由于 I/O 设备和存 储器共享同一个地址空间,所以这种方式被称为存储器映射 I/Omemory-mapped I/O)。大多 数计算机都使用了这种组织方式。 使用存储器映射 I/O 时,任何可以访问存储器的机器指令也都可以用来与 I/O 设备进行数 据传送。比如,如果 DATAIN 是输入设备中一个寄存器的地址,那么指令 95 96 I/O 设备 1 I/O 设备 n 处理器 存储器 互连网络 3-1 计算机系统

Upload: others

Post on 01-Mar-2021

10 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Computer Organization and Embedded Systems, Sixth Edition ...images.china-pub.com/ebook3765001-3770000/3768724/ch03.pdf第3 章 Computer Organization and Embedded Systems, Sixth Edition

第 3章Computer Organization and Embedded Systems, Sixth Edition

基本输入 /输出

本章目标

在本章中你将学习以下内容:

处理器与输入 / 输出(I/O)设备之间的数据传输 ●从程序员的角度看 I/O 传输 ●如何使用轮询方式执行程序来控制 I/O ●如何在 I/O 传输中使用中断 ●

计算机的一个基本特性是具有与其他设备交换信息的能力。这一通信能力使操作员可以

完成很多操作,例如用键盘和显示屏幕来处理文本和图形。实际中,我们广泛地使用计算机

通过 Internet 与其他计算机通信并访问全球信息。此外,在其他应用中,计算机虽然不是很明

显,但仍有着同等重要的作用。它们是构成家用电器、制造设备、运输系统、银行和销售点终

端所必需的一部分。在这些应用中,计算机的输入可能来自传感器开关、数字照相机、麦克风

或火警报警器;输出可能是发送给扬声器的声音信号或者是用来改变发动机速度、打开阀门或

使机器人按指定方式移动的数字编码指令。简而言之,计算机应具有在不同环境下与多种设备

交换数字信息或模拟信息的能力。

在本章中,我们将从程序员的角度来分析计算机的输入 / 输出(I/O)功能。我们只介绍

所有计算机都提供的基本 I/O 操作,这将使读者可以在典型的教学实验环境中的设备上完成有

趣并有用的练习。更复杂的 I/O 方案,以及实现 I/O 功能所需要的硬件将在第 7 章中讨论。

3.1 访问 I/O 设备

计算机系统的部件之间通过互连网络进行通信,如图 3-1 所示。互连网络包含了在处理

器、存储器和一些 I/O 设备之间进行信息传输所需的电路。

在第 2 章中,我们描述了地址空间的概念

以及处理器如何访问地址空间中独立的存储单

元。Load 和 Store 指令使用寻址方式来产生识别

所需单元的有效地址。这种使用地址来访问存储

器中不同单元的思想也可以扩展到 I/O 设备的处

理上。为此,每个 I/O 设备在处理器看来必须包

括一些可寻址的单元,就像存储器一样。处理器

将地址空间中的一些地址分配给这些 I/O 单元,

而不是主存储器。这些单元通常以寄存器的形式

组织成位存储电路(触发器),习惯上把它们称

为 I/O 寄存器(I/O register)。由于 I/O 设备和存

储器共享同一个地址空间,所以这种方式被称为存储器映射 I/O(memory-mapped I/O)。大多

数计算机都使用了这种组织方式。

使用存储器映射 I/O 时,任何可以访问存储器的机器指令也都可以用来与 I/O 设备进行数

据传送。比如,如果 DATAIN 是输入设备中一个寄存器的地址,那么指令

95

96

I/O 设备 1 I/O 设备 n

处理器 存储器

互连网络

图 3-1 计算机系统

Page 2: Computer Organization and Embedded Systems, Sixth Edition ...images.china-pub.com/ebook3765001-3770000/3768724/ch03.pdf第3 章 Computer Organization and Embedded Systems, Sixth Edition

64  ·  第 3 章 基本输入 / 输出

Load R2, DATAIN将从 DATAIN 寄存器中读取数据并将其装入寄存器 R2 中。类似地,指令

Store R2, DATAOUT将寄存器 R2 的内容发送到 DATAOUT 单元中,DATAOUT 单元是输出设备中的一个寄存器。

3.1.1 I/O 设备接口

一个 I/O 设备通过一个称为设备接口(device interface)的电路连接到互连网络中,这个

电路提供了便于数据传输和管理设备操作所需的数据传输方法以及状态和控制信息的交换方

法。这个接口包括一些可以被处理器访问的寄存器,一个寄存器可作为数据传输的缓冲区,另

一个可以保存关于设备当前状态的信息,还有一个则可以存储控制设备操作行为的信息。这些

数据(data)、状态(status)和控制(control)寄存器是通过程序指令来访问的,就好像它们

是存储单元一样。典型的信息传输是在 I/O 寄存器和处理器寄存器之间发生的。图 3-2 说明了

从软件的角度来看,键盘和显示设备是如何连接到处理器上的。

DATA

STATUS

CONTROL

DATA

STATUS

CONTROL

接口

显示器

互连网络

通用寄存器

控制寄存器

处理器接口

键盘

图 3-2 处理器、键盘和显示器之间的连接

3.1.2 程序控制 I/O

让我们从两个基本的人机交互 I/O 设备——键盘和显示器开始讨论输入 / 输出方面的问

题。考虑这样一个任务:读取键盘上键入的字符,并将这些数据存储在存储器中,然后再在显

示屏幕上显示这些字符。实现这个任务的一种简单方法就是写一个程序,让它来执行实现所需

动作的所有功能,这种方法被称为程序控制 I/O(program-controlled I/O)。

除了把每个字符从键盘传输到存储器中然后再传输到显示器之外,还需要保证这一切都

要在正确的时刻发生。在一个键被按下的时候必须读取输入的字符。对于输出来说,只有当显

示设备能够接受一个字符的时候才能将该字符发送给显示器。从键盘到计算机的数据传输速度

是受用户打字速度的限制的,打字速度不可能超过每秒几个字符。而从计算机到显示器的输出

传输速度要高得多,输出速度是由字符被传输到显示设备并显示出来的速度决定的,显示速度

通常是每秒几千个字符。但是,这还是比每秒可执行数十亿条指令的处理器速度要慢得多。这

种处理器和 I/O 设备之间的速度差异使得在它们之间进行数据传输需要有同步机制的支持。

该问题的一种解决方案是利用信号协议。在输出时,处理器发送第一个字符,然后就等

待来自于显示器的表示可以发送下一个字符的信号。然后处理器再发送第二个字符,依次类

Page 3: Computer Organization and Embedded Systems, Sixth Edition ...images.china-pub.com/ebook3765001-3770000/3768724/ch03.pdf第3 章 Computer Organization and Embedded Systems, Sixth Edition

第 3 章 基本输入 / 输出  ·  65

推。从键盘获得输入字符使用类似的方法。处理器等待着一个信号,该信号表示一个键被按

下,并且相应字符的二进制码已经保存在一个与键盘相关联的 I/O 寄存器中,然后处理器开始

读取该二进制码。

在一个键被按下的时候,键盘中的一个电路会对其进行响应,为对应字符产生计算机所

使用的代码。我们假定计算机使用的是 ASCII 码(表 1-1),其中每个字符代码占用一个字节。

令 KBD_DATA 表示一个用于存放生成字符的 8 位寄存器的地址标签。另外,假设有一个信

号,可以通过将一个称为 KIN 的触发器置为 1 来表示一个键被按下,其中 KIN 是一个 8 位状

态寄存器 KBD_STATUS 中的一部分。处理器可以读取状态标志(status flag)KIN 来确定一个

字符代码是否已被放置在 KBD_DATA 内。当处理器读取状态标志以确定其状态的时候,我们

说处理器正在轮询(poll)该 I/O 设备。

显示器则包含一个叫做 DISP_DATA 的 8 位寄存器,用于从处理器接收字符。而且它还

必须能够表明它已准备好接收下一个字符,这可以通过一个叫做 DOUT 的状态标志来完成,

DOUT 是一个状态寄存器 DISP_STATUS 中的一位。

KIN

KIE

01234567

0x4000

0x4004

0x4008

KBD_DATA

KBD_STATUS

KBD_CONT

DOUT

DIE

01234567

0x4010

0x4014

0x4018

DISP_DATA

DISP_STATUS

DISP_CONT

KIRQ

DIRQ

a)键盘接口

地址

b)显示器接口

图 3-3 键盘和显示器接口中的寄存器

图 3-3 说明了这些寄存器是如何组织的。每个设备的接口中还包括一个控制寄存器,我们

将在 3.2 节中讨论。我们只列举了寄存器中与本章所讨论的内容有关的一些位。寄存器中的其

他位可以用于其他用途,或者可能被简单地忽略掉。

如果需要像访问存储单元一样访问 I/O 接口中的寄存器,则必须给每个寄存器分配一个能

被接口电路识别的特定地址。在图 3-3 中,我们分别为键盘和显示器分配了十六进制数 4000和 4010 作为其基本地址,这两个数是数据寄存器的地址。状态寄存器的地址比数据寄存器的

地址高 4 个字节,控制寄存器的地址则比数据寄存器的地址高 8 个字节。这使得一台 32 位字

长的计算机中的所有地址都可以实现字对齐,在实际的应用中通常也是这么做的。以这种方式

给寄存器分配地址使得在处理器执行的程序中可以访问 I/O 寄存器。这也是从程序员角度所看

到的设备。

我们需要一个程序来执行下面的任务:读取键盘所产生的字符,并把这些字符存储在存储

97

~

98

Page 4: Computer Organization and Embedded Systems, Sixth Edition ...images.china-pub.com/ebook3765001-3770000/3768724/ch03.pdf第3 章 Computer Organization and Embedded Systems, Sixth Edition

66  ·  第 3 章 基本输入 / 输出

器中,最后将它们发送到显示器上。为了执行 I/O 传输,处理器必须执行检查状态标志和在处

理器与 I/O 设备之间传输数据的机器指令。

我们研究一下输入过程的细节。当一个键被按下时,键盘电路把 ASCII 编码的字符放

到 KBD_DATA 寄存器中。在同一时间,键盘电路将 KIN 标志设置为 1。同时处理器正在执

行一个 I/O 程序,它会不断地检查 KIN 标志的状态。当它检测到 KIN 被设置为 1 时,它就把

KBD_DATA 的内容传送到一个处理器寄存器中。一旦 KBD_DATA 的内容被读出,KIN 就必

须被清除为 0,这通常是由接口电路自动完成的。如果在键盘上输入第二个字符,KIN 再次被

置成 1,并重复上述过程。所需的动作可通过执行以下操作来实现: READWAIT 读取 KIN 标志

当 KIN = 0 时转移到 READWAIT将数据从 KBD_DATA 传输到 R5

这些操作将字符读到处理器寄存器 R5 中。

当字符从处理器传送到显示器时,会发生类似的处理过程。当 DOUT 等于 1 时,表示显

示器已经准备好接收一个字符了。在程序的控制下,处理器监控 DOUT,并且当 DOUT 等于

1 时,处理器就将一个 ASCII 编码字符传送到 DISP_DATA 中。字符被传送到 DISP_DATA 后

DOUT 被清为 0。当显示设备准备好接收第二个字符时,DOUT 再次被置成 1。这可以通过执

行以下操作来实现:

WRITEWAIT 读取 DOUT 标志

当 DOUT = 0 时转移到 WRITEWAIT将数据从 R5 传输到 DISP_DATA

重复执行该等待循环,直到状态标志 DOUT 被显示器置成 1,这表示显示器此时是空闲的,可

以接收一个字符了。然后 R5 中的字符被传输到 DISP_DATA 中准备显示,这个操作也将把

DOUT 清除为 0。我们假设 KIN 的初始状态是 0,DOUT 的初始状态是 1。在接通电源的时候,通常由设备

控制电路来执行这个初始化操作。

在使用存储器映射 I/O 的计算机中,其中一些地址被用来表示 I/O 接口中的寄存器,这样

就可以使用像 Load、Store 和 Move 这样的指令在寄存器和处理器之间传输数据。例如,用下

面这条指令可以将键盘字符缓冲区 KBD_DATA 中的内容传送到处理器寄存器 R5 中:

LoadByte R5, KBD_DATA类似地,使用下面的指令可以将寄存器 R5 中的内容传输到 DISP_DATA 中:

StoreByte R5, DISP_DATA区别于作用在字操作数上的 Load 和 Store 操作码,LoadByte 和 StoreByte 操作码表示操作数的

大小是一个字节。

上面描述的读操作可以用如下 RISC 风格的指令来实现:

READWAIT:LoadByte R4, KBD_STATUSAnd R4, R4, #2Branch_if_[R4]=0 READWAITLoadByte R5, KBD_DATA

And 指令用来测试 KIN 标志,也就是从寄存器 KBD_STATUS 中读取到 R4 中的状态信息的位

b1。只要 b1= 0,AND 操作的结果就会使得 R4 的值等于零,该 READWAIT 循环就会继续执行。

同样,写操作可以用如下指令实现:

99

100

Page 5: Computer Organization and Embedded Systems, Sixth Edition ...images.china-pub.com/ebook3765001-3770000/3768724/ch03.pdf第3 章 Computer Organization and Embedded Systems, Sixth Edition

第 3 章 基本输入 / 输出  ·  67

WRITEWAIT: LoadByte R4, DISP_STATUSAnd R4, R4, #4Branch_if_[R4]=0 WRITEWAITStoreByte R5, DISP_DATA

我们可以看到,在这种情况下,And 指令使用立即值 4 来测试显示器的状态位 b2。

3.1.3 一个 RISC 风格的 I/O 程序示例

如图 3-4 所示,我们现在有了一个可以执行典型的 I/O 任务的完整程序。该程序使用了上

面描述的程序控制 I/O 的方法来读取、存储以及显示在键盘上键入的一行字符。当字符一个个

地被读入时,它们被存储在存储器中,然后回显(echo)到显示器上。当遇到回车符 CR 时,

这个程序结束。存储器中将要存储该行字符的第一个字节单元的地址是 LOC。寄存器 R2 用来

指向这一部分的存储器,程序中第一条指令用地址 LOC 对其进行了初始化设置。每读取和显

示一个字符,R2 就递增一次。

Move R2, #LOC

MoveByte R3, #CRREAD: LoadByte R4, KBD_STATUS

And R4, R4, #2Branch_if_[R4]=0 READLoadByte R5, KBD_DATA

StoreByte R5, (R2)Add R2, R2, #1

ECHO: LoadByte R4, DISP_STATUSAnd R4, R4, #4Branch_if_[R4]=0 ECHOStoreByte R5, DISP_DATA

Branch_if_[R5] [R3] READ=

初始化指针寄存器 R2,使其指向主存中存储字符的第一个单元的地址

将回车符的 ASCII 码装入 R3 中等待一个字符的键入检查标志 KIN

从 KBD_DATA 中读取字符(这将把 KIN清为 0)

将字符写入到主存中并递增指向主存的指针

等待显示器准备就绪检查 DOUT 标志

将刚读入的字符移到显示器缓冲寄存器中(这将 DOUT 清为 0)

检查刚读入的字符是否为回车符,如果不是,则转移回去读取另一个字符

图 3-4 一个读取并显示一行字符的 RISC 风格的程序

3.1.4 一个 CISC 风格的 I/O 程序示例

我们使用 CISC 风格的指令来完成同样的任务。在 CISC 指令集中我们可以直接对存储器

中的操作数执行一些算术和逻辑运算。所以可能会有如下的指令:

TestBit destination, #k这条指令测试目的操作数的 bk 位,如果 bk=0,则将条件标志 Z(Zero)设置为 1,反之则设置

为 0。因为操作数可以在一个存储单元中,所以我们可以使用指令

TestBit KBD_STATUS, #1来测试键盘接口中 KIN 标志的状态。然后可以使用一条能够检查 Z 标志状态的 Branch(转移)

指令来跳转到等待循环的开始部分。

图 3-5 给出了一个读取并显示一行字符的 CISC 风格的程序。我们可以看到,第一条

MoveByte 指令将每个字符从 KBD_DATA 直接传输到 R2 指向的存储单元。一条 Compare(比

Page 6: Computer Organization and Embedded Systems, Sixth Edition ...images.china-pub.com/ebook3765001-3770000/3768724/ch03.pdf第3 章 Computer Organization and Embedded Systems, Sixth Edition

68  ·  第 3 章 基本输入 / 输出

较)指令

Compare destination, source将目的操作数的内容减去源操作数的内容来进行比较,然后根据比较的结果来设置状态标志。

这个操作并不会改变源或者目的操作数的内容。注意图 3-5 中的 CompareByte 指令使用了自

动增量的寻址方式,这种寻址方式会在比较操作结束后自动递增指针 R2 的值。而在图 3-4 中

RISC 风格的程序中,指针必须使用一条单独的 Add(加法)指令来进行递增。

Move R2, #LOC

READ: TestBit KBD_STATUS, #1Branch=0 READMoveByte (R2), KBD_DATA

ECHO: TestBit DISP_STATUS, #2Branch=0 ECHOMoveByte DISP_DATA, (R2)

CompareByte (R2)+ , #CR

Branch≠0 READ

初始化指针寄存器 R2,使其指向主存中存储字符的第一个单元的地址

等待一个字符被输入到键盘缓冲区KBD_DATA 中

将字符从 KBD_DATA 传送到主存中(这将 KIN 清为 0)

等待显示器准备就绪

把刚读入的字符移到显示器缓冲寄存器中(这将 DOUT 清为 0)

检查刚读入的字符是否为 CR(回车符),如果不是,则转移回去读取另一个字符。同时,递增指针以存储下一个字符

图 3-5 一个读取并显示一行字符的 CISC 风格的程序

我们已经讨论了在大多数计算机中所使用的存储器映射 I/O 方案。在一些处理器中还可以

找到一种替代方案,这些处理器中存在特殊的 In 和 Out 指令来执行 I/O 传输。在这种情况下,

存在一个只被这些指令使用的单独的 I/O 地址空间。当搭建使用这类处理器的计算机系统时,

设计者可以选择将 I/O 设备连接起来以使用特殊的 I/O 地址空间,或简单地将它们整合为存储

器地址空间的一部分。

程序控制 I/O 方式需要处理器连续地参与到 I/O 活动中。在图 3-4 和 3-5 的程序中几乎所

有的执行时间都花费在等待一个键被按下或显示器变为可用的循环中了。为了避免处理器的执

行时间浪费在这些等待循环上,我们可以使用中断的概念。

3.2 中断

在图 3-4 和图 3-5 的例子中,当程序进入等待循环后,不停地重复测试设备状态。这期

间,处理器不进行任何有效的计算。但在很多情况下,处理器在等待 I/O 设备就绪期间可以执

行其他的任务。为此,我们安排 I/O 设备在准备就绪时主动通知处理器,这可以通过发送一个

称为中断请求(interrupt request)的硬件信号给处理器来实现。既然处理器不再需要连续地轮

询 I/O 设备的状态,那么便可以利用等待时间来执行其他有用的任务。实际上,使用中断可以

很理想地消除这些等待时间。

例 3.1我们来看一项任务,它需要进行大量连续的计算,并将结果在显示设备上显示出来。显

示结果必须每 10 秒更新一次。10 秒的时间间隔可以由一个简单的定时器电路来确定,该电路

产生一个合适的信号。处理器将定时器电路作为一个输入设备,它产生可被查询的信号。如果

这通过轮询的方式进行,处理器将大量的时间浪费在检查信号的状态上。一个更好的解决方案

是让定时器电路每 10 秒钟产生一个中断请求。作为响应,处理器显示最新的结果。

101

~

102

103

Page 7: Computer Organization and Embedded Systems, Sixth Edition ...images.china-pub.com/ebook3765001-3770000/3768724/ch03.pdf第3 章 Computer Organization and Embedded Systems, Sixth Edition

第 3 章 基本输入 / 输出  ·  69

该任务可以使用一个包括两个子程序 COMPUTE 和 DISPLAY 的程序来实现。处理器连续

地执行 COMPUTE 子程序。当它从定时器接收到中断请求时,将暂停 COMPUTE 子程序的执

行,转去执行将最新结果发送到显示设备的 DISPLAY 子程序。DISPLAY 子程序完成后,处理

器恢复 COMPUTE 子程序的执行。由于将结果发送到显示设备所需的时间与 10 秒钟的时间间

隔相比是非常小的,所以实际上处理器几乎所有的时间都花费在执行 COMPUTE 子程序上。

这个例子阐明了中断的概念。响应中断请求时执行的程序称为中断服务程序(interrupt-service routine),该例子中的 DISPLAY 程序便是中断服务程序。中断与子程序调用十分相似。

假设在执行图 3-6 中的指令 i 时有一个中断请求到达。那么处理器先执行完指令 i,然后将中

断服务程序的第一条指令地址装入程序计数器中。这里,我们不妨假设该地址就在处理器中。

执行完中断服务程序后,处理器返回到指令 i+1 处。因此,当发生中断时,当前 PC 的内容指

向第 i+1 条指令,这个值必须暂时保存到一个已知区域中。在中断服务程序结束后,其末尾的

Return-from-interrupt(中断返回指令)将从暂时的存储区域取出存储的内容并重新装入 PC 中,

处理器便可从第 i+1 条指令处恢复执行。返回地址(return address)必须被保存在一个指定的

通用寄存器中或者处理器堆栈中。

应该注意的是,作为中断处理的一部分,处理器必须通知设备它的请求已经被识别,使

得该设备撤销它的中断请求信号。这可以由一个通过互连网络发送给设备的专门的控制信号来

实现,该控制信号被称为中断确认(interrupt acknowledge)信号。另一种方法是通过在处理器

与 I/O 设备接口之间传输数据来达到相同的目的。在中断服务程序中,当执行访问设备接口的

状态或数据寄存器的指令时,也就相当于通知该设备其中断请求已经被识别了。

M

i

2

1

i 1+

程序 2DISPLAY 程序

中断在这里发生

程序 1COMPUTE 程序

图 3-6 使用中断方式转移控制

从目前来看,对中断程序的处理和子程序十分相似。但需要注意的是二者有着重要的区

别。子程序被调用时执行的是调用程序请求的功能,因此,对状态信息和寄存器内容的潜在改

变是可以预期的。而中断服务程序可能与收到中断请求时正在执行的程序毫不相关。因此在开

始执行中断服务程序之前,必须将该中断服务程序执行期间可能会改变的状态信息和处理器寄

存器的内容都保存起来。这些保存的信息在被中断的程序重新开始执行前必须被重新装入。这

样,原来的程序就可以继续执行,除了时间延迟以外不受中断的任何影响。

保存和恢复信息的任务可以由处理器自动完成,也可以由程序指令完成。大部分现代处

理器只保存能保持程序完整执行的最小信息量。这是因为保存和恢复寄存器的过程中包括存储

器传递,它将增加总的执行时间,因而增加执行开销。并且,保存寄存器也会增加从接收中断

请求到开始执行中断服务程序之间的时间延迟。这一延迟被称为中断等待(interrupt latency)。

104

Page 8: Computer Organization and Embedded Systems, Sixth Edition ...images.china-pub.com/ebook3765001-3770000/3768724/ch03.pdf第3 章 Computer Organization and Embedded Systems, Sixth Edition

70  ·  第 3 章 基本输入 / 输出

在一些应用中,过长的中断等待是不可接受的。所以,当收到中断请求时,应尽量减少处理器

自动保存的信息量。通常,处理器只保存程序计数器和处理器状态寄存器的内容。任何需要保

存的额外信息都必须由显式的指令在中断服务程序开始时保存起来,在中断服务程序结束时进

行恢复。在一些早期的处理器中,尤其是在那些只有很少寄存器的处理器中,收到中断请求时

所有寄存器都被处理器硬件自动保存起来。而中断返回指令的执行会将这些保存的数据恢复到

各自的寄存器中。

有一些计算机提供了两种类型的中断,其中一种需要保存所有寄存器的内容,而另一种

不需要。一个特定的 I/O 设备可以选择任何一种类型的中断,这取决于它对响应时间的要求。

还有一种方式是复制处理器的寄存器组。在这种方式中,中断服务程序可以使用另一个不同的

寄存器组,不需要保存和恢复寄存器。这些重复的寄存器有时候也被称为影子寄存器(shadow register)。

中断要比简单的程序控制能更好地协调 I/O 传输。从一般意义上说,中断能够由计算机外

部的事件引起控制权从一个程序到另一个程序的转移。被中断的程序在中断服务程序执行完后

接着继续执行。在操作系统和很多其他控制应用中都使用了中断的概念,在这些应用中,特定

程序的运行必须与外部事件严格同步,这通常称为实时处理(real-time processing)。

3.2.1 中断的允许与禁止

计算机所提供的设施必须使程序员能够完全控制程序执行期间发生的事件。当外部设备

的中断请求到达时,处理器将中止一个程序的执行转而去启动另一个程序。由于随时都可能出

现,所以中断有可能改变程序员预先设定的事件顺序。因此,必须谨慎处理程序执行中的中

断。计算机的一个基本功能就是能按照需要允许和禁止中断。

在很多情况下处理器需要忽略中断请求。例如,例 3.1 的定时器电路,只有在 COMPUTE子程序执行的时候才能提出中断请求,在其他任务正在执行的时候应当阻止其发出中断请求。

在有些情况下,可能需要保证特定的指令序列没有中断地执行下去,因为中断服务程序可能会

改变序列中某些指令所需要的数据。出于这些原因,我们必须提供一些允许和禁止中断的方法

供程序员使用。

在处理器和 I/O 设备端都可以很方便地允许和禁止中断。处理器可以接受或忽略中断请

求,I/O 设备也可以被允许或被禁止提出中断请求。实现这一点的一种常用机制是使用一些可

以被程序指令访问的寄存器控制位。

处理器中有一个状态寄存器(status register, PS),其中包含有关其当前操作状态的信息。

该寄存器的一个位 IE 被分配用于允许 / 禁止中断。然后程序员可以设置或清除 IE 位来执行所

需的动作。当 IE = 1 时,I/O 设备的中断请求被处理器接受并处理。当 IE= 0 时,处理器就简

单地忽略所有 I/O 设备的中断请求。

I/O 设备的接口包括一个控制寄存器,其中包含可以管理设备操作模式的信息。该寄存器

的一个位可以专门用于中断控制。只有在该位被设置为 1 时 I/O 设备才能被允许发出中断请

求。我们将在 3.2.3 节中讨论这个方法。

现在让我们考虑只有一台设备的单一中断请求的特殊情况。当一台设备激活中断请求信

号时,它保持这个信号直到确认处理器已经接收了该中断请求。这就是说中断请求信号在中断

服务程序执行期间将保持有效,也许要持续到访问该设备的指令到达。另一方面也要保证这个

有效的请求信号不会导致连续的中断,而使系统进入一个无法恢复的死循环。

一个不错的方法是使处理器在开始执行中断服务程序之前自动禁止中断。处理器保存程

105

106

Page 9: Computer Organization and Embedded Systems, Sixth Edition ...images.china-pub.com/ebook3765001-3770000/3768724/ch03.pdf第3 章 Computer Organization and Embedded Systems, Sixth Edition

第 3 章 基本输入 / 输出  ·  71

序计数器和处理器状态寄存器的内容。将 PS 寄存器的内容保存后,此时 IE 位的 1 也被保存

了下来,之后处理器将 PS 寄存器中的 IE 位清 0,从而禁止新的中断发生。然后处理器开始执

行中断服务程序。当执行中断返回指令时,PS 寄存器恢复之前保存的内容,IE 位被重置为 1。这样,中断被重新允许。

在继续学习更复杂的中断内容前,我们总结一下处理来自单一设备的中断请求时所包含

的事件序列。假设在处理器和设备端都是允许中断的,下面是一个一般的过程:

1)设备发出一个中断请求。

2)处理器中止当前正在执行的程序并保存 PC 与 PS 寄存器中的内容。

3)将 PS 寄存器中的 IE 位清零来禁止中断。

4)中断服务程序执行中断所请求的操作。在此期间,通知设备其中断请求已经被识别,

然后设备撤销中断请求信号。

5)中断服务程序执行结束后, PC 与 PS 寄存器恢复之前保存的内容(IE 位随着 PS 的恢

复也被恢复为 1 而允许中断),被中断的程序继续执行。

3.2.2 处理多台设备

现在我们考虑一个情况,处理器上连接了多台能够发出中断请求的设备。因为在操作上

这些设备是相互独立的,所以没有固定的中断发生顺序。例如,正在处理设备 Y 引起的中断

时设备 X 可能又发出中断请求,或者几台设备都刚好在同一时间发出中断请求。这导致了一

系列的问题:

1)处理器如何确定哪个设备发出了中断请求? 2)如果不同的设备要求不同的中断服务程序,在每一种情况下处理器怎样获取适当的程

序起始地址?

3)当有中断正在被处理时,另一台设备是否可以中断处理器?

4)怎样处理两个或更多个同时产生的中断请求?

不同的计算机处理这些问题的方法各不相同,采用何种方法解决上述问题对于确定计算

机与特定应用是否匹配是非常重要的。

当收到一个中断请求时,需要识别是哪一台设备发出的中断请求。而且,如果有两台设

备同时发出中断请求,必须选择其中一个进行处理。执行完选中设备的中断服务程序后,处理

器才可以响应第二个中断请求。

读取设备的状态寄存器中的信息可以确定一个设备是否正在请求中断。当设备发出中断

请求后,它的状态寄存器中的一位被置成 1,这一位称为 IRQ 位。最简单的识别中断设备的方

法就是用中断服务程序去轮询系统中所有的 I/O 设备。查询到的第一个 IRQ 位被置 1 的设备就

是发出中断请求的设备,然后调用相应的处理子程序来提供所请求的服务。

轮询方式非常容易实现。它的主要缺点是:设备即使没有发出任何服务请求,系统也要花

费时间去检查其 IRQ 位。另一种可供选择的方法是使用向量中断,我们将在下面进行描述。

1.向量中断

为了减少轮询过程所花费的时间,请求中断的设备可以直接向处理器标明它自己。然后,

处理器就可以立即开始执行相应的中断服务程序。术语向量中断(vectored interrupt)指的就是

基于这种方法的中断处理方式。

如果请求中断的设备有它自己的中断请求信号,就可以利用中断请求信号来标识自己,

或者它可以通过互连网络向处理器发送一个专门的代码来标识自己。处理器的电路会确定所请

107

Page 10: Computer Organization and Embedded Systems, Sixth Edition ...images.china-pub.com/ebook3765001-3770000/3768724/ch03.pdf第3 章 Computer Organization and Embedded Systems, Sixth Edition

72  ·  第 3 章 基本输入 / 输出

求的中断服务程序的存储器地址。一个常用的方案是在存储器中永久地分配一个区域来保存中

断服务程序的地址。这些地址通常被称为中断向量(interrupt vector),而中断向量构成一个中

断向量表(interrupt-vector table)。例如,可以分配 128 个字节来保存一个包含 32 个中断向量

的表。通常情况下,中断向量表会保存在最低的地址范围内。中断服务程序则可能位于存储器

中的任何位置。当一个中断请求到达时,发出请求的设备所提供的信息用来作为中断向量表中

的一个指针,相应的中断向量地址会被自动地加载到程序计数器中。

2.中断嵌套

在 3.2.1 节中我们提到在执行中断服务程序期间应该禁止中断,以保证同一设备的中断请

求不会导致多次中断。这一方式还常用于多台设备的情况,在这种情况下一个特定的中断服务

程序一旦开始执行,处理器就必须等到该服务程序执行完毕才能接受第二个设备的中断请求。

但中断服务程序一般都很短,所导致的延迟对于大部分简单设备来说都是可以接受的。

然而,对于某些设备,响应中断请求时过长的延迟将会导致错误的操作。例如,有一台

使用实时时钟记录日常时间的计算机。实时时钟在固定的时间间隔内向处理器发送中断请求。

对每一个请求,处理器执行一个简短的中断服务程序来增加存储器中的一组计数器,这些计数

器用秒、分等来记录时间。正确的操作要求响应实时时钟中断请求的延迟必须小于两个连续请

求之间的时间间隔。为了确保在存在其他中断设备的情况下满足这一条件,需要在执行其他设

备的中断服务程序时接收时钟的中断请求。这就是中断嵌套。

这个例子表明 I/O 设备需要按照一定的优先级结构组织起来。在处理低优先级设备的中断

请求时,高优先级设备的中断请求应该被接受。

多优先级结构意味着在执行一个中断服务程序期间,一些设备的中断请求可以被接受,

而其他一些设备的请求不可以被接受,这取决于设备的优先级。为了实现这种方式,我们可以

给处理器分配一个优先级,它可以在程序的控制下改变。处理器的优先级就是当前正在执行程

序的优先级,处理器只接受优先级高于它自己的设备的中断。在某台设备的中断服务程序开始

执行时,处理器的优先级自动地或者由专门的指令提升为该设备的优先级。这一操作将禁止来

自同一优先级或较低优先级设备的中断,而来自更高优先级设备的中断请求将继续被接受。处

理器的优先级可以编码在处理器状态寄存器的某一些位中。在某些处理器中会使用这种方法,

在后面的例子中我们将使用一种更简单的方法。

最后我们需要指出,如果允许嵌套的中断,则每一个中断服务程序都必须把程序计数器

和状态寄存器中的内容保存到堆栈中。这必须在中断服务程序把状态寄存器中的 IE 位设置为

1 以允许嵌套之前完成。

3.同时请求

我们还需要考虑两台或多台设备的中断请求同时到达的问题,处理器必须能够决定哪个

请求最先被服务。轮询 I/O 设备的状态寄存器是最简单的方法。这种方式下,优先级由轮询设

备的顺序来决定。当使用向量中断时,必须保证只有一台设备被选定发送它的中断向量代码。

这是在硬件中通过使用仲裁电路来完成的,我们将在第 7 章中介绍仲裁电路。

3.2.3 控制 I/O 设备行为

确保中断请求只来自那些处理器愿意处理的 I/O 设备是非常重要的。因此,我们需要在每

台设备的接口电路中建立一种机制,来控制该设备是否允许中断处理器。这一控制在设备的接

口电路中通常以中断允许位(interrupt-enable,IE)的形式提供。

I/O 设备的复杂性各不相同,从简单到复杂。简单的设备,如键盘,只需要很少的控制。

108

Page 11: Computer Organization and Embedded Systems, Sixth Edition ...images.china-pub.com/ebook3765001-3770000/3768724/ch03.pdf第3 章 Computer Organization and Embedded Systems, Sixth Edition

第 3 章 基本输入 / 输出  ·  73

复杂的设备可能有很多种可能的操作模式需要进行控制。一种常用的方法是在设备接口中提供

一个控制寄存器,其中包含控制设备行为所需的信息。就像我们之前讨论过的数据寄存器和状

态寄存器一样,该寄存器也作为一个可寻址的单元进行访问。寄存器中的一位作为中断允许位

IE。当中断允许位被一条将新信息写到控制寄存器的指令置为 1 时,只要该设备已为 I/O 传输

做好准备它就可以随时中断处理器。

图 3-3 展示了在键盘和显示设备的接口中使用的寄存器。由于这些设备传输基于字符的数

据,每次只处理一个字符,所以在这里使用 8 位的数据寄存器是合适的。我们假定状态寄存器

和控制寄存器的长度也是 8 位的。这些寄存器中只需要一位或两位来处理 I/O 传输。剩余的位

可以用来指定设备操作的其他方面,如果不需要的话就可以忽略掉。键盘状态寄存器包括 KIN位和 KIRQ 位。我们已经在 3.1.2 节中讨论了 KIN 位的用途。如果中断请求已经发出但尚未被

处理,则 KIRQ 位被置为 1。只有当其控制寄存器中的中断允许位 KIE 被置为 1 时,键盘才可

以发出中断请求。因此,当 KIE 位与 KIN 位都等于 1 时,键盘发出中断请求,并且 KIRQ 位

被置为 1。同样,显示器接口的状态寄存器中的 DIRQ 位可以表示显示器是否已经发出中断请

求。该接口的控制寄存器中的 DIE 位用来表示是否允许中断。可以观察到我们已经把 KIN 位

和 KIE 位放置在位位置 1 上,把 DOUT 和 DIE 位放置在位位置 2 上。这种设置不是绝对的,

只是为了使接下来的程序实例更容易理解。

3.2.4 处理器控制寄存器

我们已经讨论了处理器中设置状态寄存器的必要性。为了处理中断,引入一些其他的控

制寄存器是非常有用的。图 3-7 描述了一种可能的方案,其中有 4 个处理器控制寄存器。状态

寄存器 PS 中包含中断允许位 IE,除此之外还有一些其他的状态信息。只有当 IE 位被置为 1时,处理器才能接受中断。当收到一个中断请求并接受该请求时,IPS 寄存器将自动保存 PS的内容。在中断服务程序结束时,通过把 IPS 的内容传输到 PS 中,处理器就会自动恢复为以

前的状态。由于只有一个寄存器被用于存储以前的状态信息,所以,如果允许中断嵌套的话,

那么在堆栈中保存 IPS 的内容将会变得很有必要。

01234

PS

IENABLE

IPENDING

31

IPS

IE

IE

DISP KBD

DISP KBD

TIM

TIM

图 3-7 处理器中的控制寄存器

IENABLE 寄存器可以使处理器有选择地响应每个 I/O 设备。可以在 IENABLE 寄存器中

为每个设备分配一位,如图中所示的为键盘、显示器以及我们将在后面的例子中使用的定时器

电路各分配了一位。当某位被置为 1 时,处理器将接受所对应设备的中断请求。IPENDING 寄

存器指示活跃的中断请求。当多个设备同时发出请求时这将是非常方便的。然后,程序可以决

定哪个中断应该首先被服务。

109

110

Page 12: Computer Organization and Embedded Systems, Sixth Edition ...images.china-pub.com/ebook3765001-3770000/3768724/ch03.pdf第3 章 Computer Organization and Embedded Systems, Sixth Edition

74  ·  第 3 章 基本输入 / 输出

在一个 32 位的处理器中,控制寄存器的长度为 32 位。使用图 3-7 中的结构,将可以用一

种直接的方式来表示 32 个 I/O 设备。

汇编语言指令可以用图 3-7 中那样的名字来使用处理器控制寄存器。但是不能使用访问通

用寄存器的方式来访问这些寄存器。它们不能被算术和逻辑指令访问,也不能被使用图 2-32c所示编码格式的 Load 和 Store 指令访问,因为在这些指令中用一个 5 位的字段来指定源寄存

器或目的寄存器,这使得它只能够指定 32 个通用寄存器。可以提供专门的指令或专门的寻址

方式来访问处理器控制寄存器。在 RISC 风格的处理器中,专门的指令可以是如下类型的

MoveControl R2, PS这个指令把程序状态寄存器的内容装入寄存器 R2 中,而指令

MoveControl IENABLE, R3则把 R3 的内容放入 IENABLE 寄存器中。这些指令完成控制寄存器与通用寄存器之间的数据

传输操作。

3.2.5 中断程序示例

我们已经描述了中断的基本知识,现在给出一些说明性的例子。我们将使用具有图 3-3 所

示寄存器结构的键盘和显示设备来展示这些例子。

例 3.2我们再来看一下这个任务:读取键盘上键入的一行字符,并把字符存储在主存中,然后在

显示设备上显示这些字符。在图 3-4 和 3-5 中,我们使用轮询法来检测 I/O 设备是否做好数据

传输的准备,以此来展示这个任务是如何执行的。现在,我们将对键盘使用中断方式,而对显

示器使用轮询方式。

现在假设一个特定的存储单元 ILOC 专门用于处理中断,并假设它包含了中断服务程序的

第一条指令。每当一个中断请求到达处理器,并且处理器中断被允许时,处理器将自动完成以

下工作:

将程序计数器的内容存储在用于保存返回地址的处理器寄存器中或者存储在处理器堆 ●栈中。

将状态寄存器 PS 的内容转移到 IPS 寄存器中保存起来,并清除 PS 中的 IE 位。 ●将地址 ILOC 装入程序计数器中。 ●

假设我们希望在主程序中从键盘读取一行字符,并存储到存储器中从 LINE 单元开始的连

续字节区域中。另外,假设中断服务程序已经装入存储器中从 ILOC 单元开始的区域中。则主

程序必须按如下步骤来初始化中断过程:

1)将地址 LINE 装入存储单元 PNTR 中。中断服务程序把该单元作为一个指针来将输入

字符存储到存储器中。

2)通过将 KBD_CONT 寄存器中的 KIE 位置 1,以允许键盘中断。

3)通过将控制寄存器 IENABLE 中的 KBD 位置 1,以使处理器能够接受键盘中断。

4)通过将处理器状态寄存器 PS 中的 IE 位置 1,以使处理器能够响应中断。

该初始化过程完成后,从键盘输入一个字符就会导致键盘接口产生一个中断请求。此时正

在执行的程序将被中断,转去执行键盘输入中断服务程序。该中断服务程序必须执行以下任务:

1)从键盘的输入数据寄存器中读取输入字符。然后,键盘接口电路撤销中断请求。

2)将字符存储到 PNTR 指向的存储单元中,并递增 PNTR。

3)使用轮询方式显示该字符。

4)当达到行尾时,禁止键盘中断并通知主程序。

111

Page 13: Computer Organization and Embedded Systems, Sixth Edition ...images.china-pub.com/ebook3765001-3770000/3768724/ch03.pdf第3 章 Computer Organization and Embedded Systems, Sixth Edition

第 3 章 基本输入 / 输出  ·  75

5)从中断返回。

执行这些任务的 RISC 风格的程序如图 3-8 所示。程序中的注释已经解释了相关的细节。

当检测到输入行的末端时,中断服务程序将 KBD_CONT 寄存器中的 KIE 位清除,表示不期望

更多的输入了。同时也将变量 EOL(End Of Line)置为 1,它在初始时被清为 0。假设主程序

用周期性的查询来确定输入行是否准备好进行处理。EOL 变量提供了一种在主程序和中断服

务程序之间发送信号的方法。

ILOC: Subtract SP, SP, #8Store R2, 4(SP)Store R3, (SP)Load R2, PNTRLoadByte R3, KBD_DATAStoreByte R3, (R2)Add R2, R2, #1Store R2, PNTR

ECHO: LoadByte R2, DISP_STATUSAnd R2, R2, #4Branch_if_[R2]=0 ECHOStoreByte R3, DISP_DATAMove R2, #CRBranch_if_[R3]≠[R2] RTRNMove R2, #1Store R2, EOLClear R2StoreByte R2, KBD_CONT

RTRN: Load R3, (SP)Load R2, 4(SP)Add SP, SP, #8Return-from-interrupt

START: Move R2, #LINEStore R2, PNTRClear R2Store R2, EOLMove R2, #2StoreByte R2, KBD_CONTMoveControl R2, IENABLEOr R2, R2, #2MoveControl IENABLE, R2MoveControl R2, PSOr R2, R2, #1MoveControl PS, R2next instruction

保存寄存器

载入地址指针从键盘读入字符将字符写入存储器递增指针更新存储器中的指针等待显示器准备就绪

显示刚读入的字符回车符的 ASCII 码如果不是 CR,则返回

指示行的结束禁止键盘中断

恢复寄存器

初始化缓冲区指针

清除行结束指示变量允许键盘中断

在处理器控制寄存器中允许键盘中断

设置 PS 中的中断允许位

中断服务程序

主程序

图 3-8 一个使用中断方式读取一行字符,并使用轮询方式显示该行字符的 RISC 风格的程序

观察可知主程序的最后三条指令被用来将 PS 中的中断允许位置 1。由于只有

MoveControl 指令可以访问控制寄存器的内容,所以 PS 的内容被装入通用寄存器 R2 中,修改

后又写回到 PS 中。使用 Or 指令修改内容只会影响 IE 位,而 PS 中的其余位则保持不变。

当多个 I/O 设备提出中断请求时,需要确定是哪个设备请求了中断。这可以通过使用软件

去检查 IPENDING 控制寄存器中的信息,并选择应执行的中断服务程序来实现。

例 3.3在例 3.2 中,我们只对键盘使用了中断方式,但显示设备也可以使用中断方式。假设一个

程序需要显示存储在存储器中的一页文本。这可以通过如下的方式来完成:当显示器接口通过

112

113

Page 14: Computer Organization and Embedded Systems, Sixth Edition ...images.china-pub.com/ebook3765001-3770000/3768724/ch03.pdf第3 章 Computer Organization and Embedded Systems, Sixth Edition

76  ·  第 3 章 基本输入 / 输出

一个中断请求来表示它已准备就绪时处理器就发送一个字符。假设该程序使用显示器和键盘,

并且允许两者发出中断请求。使用图 3-3 和 3-7 中的寄存器结构,中断的初始化和中断请求的

处理都可以用图 3-9 所示的方法来完成。

ILOC: Subtract SP, SP, #12Store LINK_reg, 8(SP)Store R2, 4(SP)Store R3, (SP)MoveControl R2, IPENDINGAnd R3, R2, #4Branch_if_[R3] 0 TESTKBDCall DISR

TESTKBD: And R3, R2, #2Branch_if_[R3] 0 NEXTCall KISR

NEXT: ˙˙˙

Load R3, (SP)Load R2, 4(SP)Load LINK_reg, 8(SP)Add SP, SP, #12Return-from-interrupt

START: ˙˙˙Move R2, #2StoreByte R2, KBD_CONTMove R2, #4StoreByte R2, DISP_CONTMoveControl R2, IENABLEOr R2, R2, #6MoveControl IENABLE, R2MoveControl R2, PSOr R2, R2, #1MoveControl PS, R2

KISR: ˙˙˙...Return

DISR: ˙˙˙...Return

保存寄存器

检查 IPENDING 的内容检查显示器是否发出请求如果没有,则检查键盘是否发出请求调用显示器中断服务程序(ISR)检查键盘是否发出请求如果没有,则检查下一个设备调用键盘中断服务程序(ISR)检查其他中断

恢复寄存器

为 ISR 建立参数表允许键盘中断允许显示器中断

在处理器控制寄存器中允许中断

设置 PS 中的中断允许位

中断处理程序

主程序

键盘中断服务程序

显示器中断服务程序

下一条指令

图 3-9 一个初始化并处理中断的 RISC 风格的程序

主程序必须初始化中断服务程序所需的任何变量,如存储器缓冲区指针。然后主程序允

许键盘和显示器中断。接下来主程序在处理器控制寄存器 IENABLE 中允许中断。注意,装入

这个寄存器的立即值 6 将 KBD 和 DISP 位都置为 1。最后通过将处理器状态寄存器 PS 中的 IE位置为 1,使处理器能够响应中断。

我们再假设当一个中断请求到达时,处理器将自动保存程序计数器(PC)的内容,然后

将地址 ILOC 装入 PC 中。它同时也将把状态寄存器(PS)中的内容转移到 IPS 寄存器中保

存起来,并禁止中断。与只有一个设备能够提出中断请求的例 3.2 不同,现在我们不能直接

进入所需的中断服务程序。首先,需要确定发出中断的设备。我们可以在处理器控制寄存器

Page 15: Computer Organization and Embedded Systems, Sixth Edition ...images.china-pub.com/ebook3765001-3770000/3768724/ch03.pdf第3 章 Computer Organization and Embedded Systems, Sixth Edition

第 3 章 基本输入 / 输出  ·  77

IPENDING 中找到所需要的信息。由于中断服务程序在这个过程中使用寄存器 R2 和 R3,所以

这两个寄存器的内容必须被保存在堆栈中以便以后能够恢复。子程序链接寄存器 LINK_reg 的

内容也需要保存,因为当某个子程序正在执行时可能会发生一个中断,而该中断的中断服务程

序可能调用另一个子程序。检测中断的电路将 IPENDING 中与每一个待处理的请求相对应的

位置为 1。在图 3-9 中,IPENDING 的内容被装入通用寄存器 R2 中,然后再检查它来确定哪

些中断正在等待处理。如果显示器有一个待处理的中断,那么它的中断服务程序将被执行。如

果没有,则再检查键盘。接下来可能还将检查任何可能有待处理请求的其他设备。在同时请求

的情况下,IPENDING 中的位的检查顺序,确立了中断设备的优先级。

处理中断请求并为提出请求的设备提供相应服务的程序通常称为中断处理程序(interrupt handler)。注意,当中断处理程序在一个固定的地址 ILOC 处开始时,单独的中断服务程序就

只是可以放在存储器中任意位置的子程序而已。

在图 3-9 中,我们使用软件的方法来确定发出中断请求的设备。在使用向量中断的处理器

中,检测中断请求的电路会为每一个在中断向量表中分配了具体位置的中断自动加载一个不同

的地址到程序计数器中。对于每个待处理的请求,会有一个单独的中断服务程序一直执行到结

束,即使有多个中断请求在同一时间提出。

CISC 风格的中断示例

使用与前面类似方法的 CISC 风格的指令也可以实现上述任务。主要区别在于某些操作,

如测试 I/O 寄存器中的某个位,可以直接执行。例 3.2 和例 3.3 中的任务可分别用图 3-10 和

图 3-11 中的程序实现。TestBit 指令用来测试状态标志。SetBit 和 ClearBit 指令分别用来将 I/O寄存器中的某位置为 1 或 0。程序中的注释解释了如何实现所需的任务。

计算机系统中所包含的输入 / 输出操作通常要比这些简单例子中的多得多。正如我们将在

第 4 章中描述的,计算机操作系统将代表用户程序执行这些操作。在第 7 章中,我们将详细讨

论 I/O 操作中所使用的硬件。

ILOC: Move – (SP), R2Move R2, PNTRMoveByte (R2), KBD_DATAAdd PNTR, #1

ECHO: TestBit DISP_STATUS, #2Branch=0 ECHOMoveByte DISP_DATA, (R2)CompareByte (R2), #CRBranch 0 RTRNMove EOL, #1ClearBit KBD_CONT, #1

RTRN: Move R2, (SP)+Return-from-interrupt

START: Move PNTR, #LINEClear EOLSetBit KBD_CONT, #1Move R2, #2MoveControl IENABLE, R2MoveControl R2, PSOr R2, #1MoveControl PS, R2

保存寄存器载入地址指针将字符写入存储器并递增指针

等待显示器准备就绪

显示刚读入的字符检查刚读入的字符是否为回车符(CR)如果不是 CR 则返回指示行的结束禁止键盘中断恢复寄存器

初始化缓冲区指针清除行结束指示变量允许键盘中断在处理器控制寄存器中允许键盘中断

设置 PS 中的中断允许位

中断服务程序

主程序

下一条指令

图 3-10 使用中断方式读取一行字符并使用轮询方式显示该行字符的 CISC 风格的程序

114

~

115

Page 16: Computer Organization and Embedded Systems, Sixth Edition ...images.china-pub.com/ebook3765001-3770000/3768724/ch03.pdf第3 章 Computer Organization and Embedded Systems, Sixth Edition

78  ·  第 3 章 基本输入 / 输出

ILOC: Move – (SP), R2Move – (SP), LINK_regMoveControl R2, IPENDINGTestBit R2, #2Branch 0 TESTKBDCall DISR

TESTKBD: TestBit R2, #1Branch 0 NEXTCall KISR

NEXT: ˙˙˙

Move LINK_reg, (SP)+Move R2, (SP)+Return-from-interrupt

START: ˙˙˙SetBit KBD_CONT, #1SetBit DISP_CONT, #2MoveControl R2, IENABLEOr R2, #6MoveControl IENABLE, R2MoveControl R2, PSOr R2, #1MoveControl PS, R2

KISR: ˙˙˙...Return

DISR: ˙˙˙...Return

保存寄存器

检查 IPENDING 的内容检查显示器是否发出请求如果没有,则检查键盘是否发出请求调用显示器的中断服务程序(ISR)检查键盘是否发出请求如果没有,则检查下一个设备调用键盘的中断服务程序(ISR)检查其他中断

恢复寄存器

为 ISR 建立参数表允许键盘中断允许显示器中断

在处理器控制寄存器中允许中断

设置 PS 中的中断允许位

中断处理程序

主程序

下一条指令

键盘中断服务程序

显示器中断服务程序

图 3-11 初始化并处理中断的 CISC 风格的程序

3.2.6 异常

中断是导致一个程序的执行被中止、另一个程序的执行开始的事件。到目前为止,我们

处理的中断只是由那些与 I/O 数据传输有关的事件引起的。然而,中断机制还可以用在许多其

他的情形下。

术语异常(exception)通常用来指任何引起中断的事件。因此,I/O 中断是异常的一种。

现在我们来讲述几种其他类型的异常。

1.错误恢复

计算机使用大量的技术来确保所有硬件都能正确工作。例如,许多计算机在主存中都包

含有错误校验码,它可以对存储的数据进行错误检测。如果出现了错误,控制硬件就会检测到

并产生中断通知处理器。

当处理器正在执行某个程序的指令时,如果检测到错误或不正常的情况,它也会中断该

Page 17: Computer Organization and Embedded Systems, Sixth Edition ...images.china-pub.com/ebook3765001-3770000/3768724/ch03.pdf第3 章 Computer Organization and Embedded Systems, Sixth Edition

第 3 章 基本输入 / 输出  ·  79

程序。例如,一条指令的 OP 码字段有可能不对应任何合法指令,或一条算术指令试图除以 0。当这些错误引发异常时,处理器按照与处理 I/O 中断请求相同的方式进行处理,中止正在

执行的程序并启动异常服务程序,该异常服务程序进行适当的操作,尽可能从错误中恢复过

来,或将该错误通知给用户。回想一下 I/O 中断时的情形,我们假设处理器在接受中断前必须

完成正在执行的指令。然而,当中断是由与当前指令有关的错误引起的时候,通常不等那条指

令执行完,处理器就立即开始异常处理。

2.调试

另一种非常重要的异常是用于帮助调试程序的。系统软件通常包括一个调试器

(debugger)程序,它用来帮助程序员找出程序中的错误。调试器使用异常来提供两项重要的

功能:跟踪模式和断点。这些功能将在第 4 章中详细描述。

3.异常在操作系统中的使用

操作系统(OS)软件的职责是协调计算机内部的活动。它使用异常来与用户程序通信并

控制用户程序的执行,使用硬件中断来执行 I/O 操作。这部分内容将在第 4 章中进行讨论。

3.3 结束语

在这一章中,我们讨论了两种基本的 I/O 传输方式。最简单的技术是程序控制 I/O,在这

种技术中,处理器在程序指令的直接控制下执行所有必要的功能。第二种方式是基于中断

的,这种机制可以中断程序的正常执行,转去服务需要迫切关注的、具有更高优先级的请

求。虽然所有的计算机都有处理这种情况的机制,但是不同计算机的中断处理方案的复杂程

度各不相同。

我们是从程序员的角度来处理 I/O 问题的。在第 7 章中,我们将介绍硬件方面的内容以及

一些常用的 I/O 标准。

3.4 问题解析

本节将介绍一些可能要求学生解决的典型问题实例,并分析说明如何解决这样的问题。

例 3.4问题:假定一个存储单元 BINARY 包含一个 32 位的模式。要求在具有图 3-3 所示接口的显示设备

上把这些位显示为 8 个十六进制数字。写一个程序完成 这个任务。

解答:首先,需要把 32 位的模式转换成可表示为 ASCII 编码字符的十六进制数字。一个简单的转

换方法是使用查表(table-lookup)法。建立一个包含 16 个表项的表,为每一个可能的 16 进制数字提供

ASCII 码。然后,我们将 BINARY 中的模式分成 4 位一组的段,可以在表中查出相应的字符,并将其存

储在从 HEX 单元开始的存储器字节块中。最后,将从 HEX 开始的 8 个字符发送给显示器。

图 3-12 和图 3-13 分别给出了完成所需任务的 RISC 风格和 CISC 风格的程序。程序中的注释详细描

述了每行代码的行为。

例 3.5问题:思考例 3.1 中描述的任务。假设定时器电路包括一个 32 位的向上 / 向下计数器,它由

100MHz 的时钟驱动。该计数器可以设定为从一个特定的初始计数值开始计数。定时器的 I/O 接口如图

3-14 所示,其中包括 4 个寄存器。

TIM_STATUS 指示定时器当前的状态,其中: ●当计数器运行时 TON 位被置为 1。 ■当计数器达到零时 ZERO 位被置为 1。 ■当计数器内容达到零而且定时器中断被允许时,定时器发出中断请求,此时,TIRQ 位被置为 1。 ■

116

~

118

119

Page 18: Computer Organization and Embedded Systems, Sixth Edition ...images.china-pub.com/ebook3765001-3770000/3768724/ch03.pdf第3 章 Computer Organization and Embedded Systems, Sixth Edition

80  ·  第 3 章 基本输入 / 输出

Load R2, BINARYMove R3, #8Move R4, #HEX

LOOP: RotateL R2, R2, #4

And R5, R2, #0xFLoadByte R6, TABLE(R5)StoreByte R6, (R4)Subtract R3, R3, #1Add R4, R4, #1Branch_if_[R3]> 0 LOOP

DISPLAY: Move R3, #8Move R4, #HEX

DLOOP: LoadByte R5, DISP_STATUSAnd R5, R5, #4Branch_if_[R5] 0 DLOOPLoadByte R6, (R4)StoreByte R6, DISP_DATASubtract R3, R3, #1Add R4, R4, #1Branch_if_[R3]> 0 DLOOP

ORIGIN 1000HEX: RESERVE 8TABLE: DATABYTE 0x30,0x31,0x32,0x33

DATABYTE 0x34,0x35,0x36,0x37DATABYTE 0x38,0x39,0x41,0x42DATABYTE 0x43,0x44,0x45,0x46

载入二进制数R3 是一个被设置为 8 的数字计数器R4 指向十六进制数字把高位数字循环移位到低位

提取下一个数字获取数字的 ASCII 码将其存储在 HEX 单元中递减数字计数器递增指向十六进制数字的指针

如果不是最后一位数字则返回循环等待显示器准备就绪检查 DOUT 标识

获取下一个 ASCII 字符将其发送到显示器上递减计数器递增字符指针循环,直到所有字符都显示完毕

ASCII 编码数字的存储空间ASCII 码转换表

下一条指令

图 3-12 例 3.4 的 RISC 风格的程序

Move R2, BINARYMove R3, #8Move R4, #HEX

LOOP: RotateL R2, #4

Move R5, R2And R5, #0xFMoveByte (R4)+, TABLE(R5)

Subtract R3, #1Branch> 0 LOOP

DISPLAY: Move R3, #8Move R4, #HEX

DLOOP: TestBit DISP_STATUS, #2Branch 0 DLOOPMoveByte DISP_DATA, (R4)+Subtract R3, #1Branch> 0 DLOOP

ORIGIN 1000HEX: RESERVE 8TABLE: DATABYTE 0x30,0x31,0x32,0x33

DATABYTE 0x34,0x35,0x36,0x37DATABYTE 0x38,0x39,0x41,0x42DATABYTE 0x43,0x44,0x45,0x46

载入二进制数R3 是一个被设置为 8 的数字计数器R4 指向十六进制数字把高位数字循环移位到低位

提取下一个数字获取数字的 ASCII 码并将其存储在

HEX 单元中递减数字计数器如果不是最后一位数字则返回循环

等待显示器准备就绪

将下一个字符发送到显示器上递减计数器循环,直到所有字符都显示完毕

ASCII 编码数字的存储空间ASCII 码转换表

下一条指令

图 3-13 例 3.4 的 CISC 风格的程序

Page 19: Computer Organization and Embedded Systems, Sixth Edition ...images.china-pub.com/ebook3765001-3770000/3768724/ch03.pdf第3 章 Computer Organization and Embedded Systems, Sixth Edition

第 3 章 基本输入 / 输出  ·  81

读取这个状态寄存器的动作会自动将 ZERO 和 TIRQ 位清 0。TIM_CONT 控制操作模式,其中: ●

UP 位被置为 1 时,计数器递增计数;当 UP 位被清为 0 时,计数器递减计数。 ■FREE 位被置为 1 时,计数器进入持续运行模式,此时,当实际计数达到 0 时会自动将初始 ■计数值重新装入计数器中。

RUN 位被置为 1 时,计数器开始计数;RUN 位被清 0 时计数器停止计数。 ■TIE 位被置为 1 时,允许定时器中断。 ■

TIM_INIT 保存初始计数值。 ●TIM_COUNT 保存当前的计数值。 ●

写一个程序来实现所需的任务,使用图 3-7 中所描述的处理器控制寄存器。

ZERO

RUN

01234731

0x4020

0x4024

TIM_STATUS

TIM_CONT

TIRQTON

TIEFREEUP

TIM_INIT

TIM_COUNT

0x4028

0x402C 当前计数值

地址

初始计数值

图 3-14 定时器接口中的寄存器

解答:为了每 10 秒钟能获得一个中断请求,需要计数 109 个时钟周期。可以这样实现:将这个值写

入 TIM_INIT 寄存器,然后递减计数器的计数,当计数达到 0 时发出中断请求。109 这个值可以用十六进

制数 3B9ACA00 来表示。为了实现所需的操作,FREE、RUN 和 TIE 位必须被置为 1,而 UP 位则必须被

置为 0。使用图 3-9 中概述的方法,我们可以用图 3-15 所示的 RISC 风格的程序来实现所需的任务。注意,

初始计数值是一个 32 位的立即值,可以用 2.9 节中给出的方法将其装入 R2 中。

图 3-16 给出了用图 3-11 概述的方法实现所需任务的 CISC 风格的程序。在这里, 32 位的立即数操作

数可以在一条单一的指令中指定。

例 3.6问题:数字系统中有一种常用的输出设备七段显示器,如图 3-17 所示。该设备包括七个独立的数码

管段,给它们加上电信号的时候它们可以被点亮。假设每一段在施加逻辑值 1 的时候被点亮。图中给出

了显示数字 0 到 9 所需的位模式。

写一个程序,显示用 ASCII 编码字符表示的数,该 ASCII 编码字符存储在地址为 0x800 的存储单

元 DIGIT 中。假设显示器有一个 I/O 接口,它包含一个 8 位的数据寄存器 SEVEN,其中 a 段至 g 段分

别连接到 SEVEN 的第 6 至第 0 位上。设 SEVEN 的第 7 位等于 0。另外,假设寄存器 SEVEN 的地址为

0x4030。如果 DIGIT 单元中的 ASCII 码表示的字符不是 0 到 9 范围内的数,则显示器是空白的,所有的

段都被关闭。

解答:可以使用一个查找表 TABLE 来保存与数字 0 到 9 相对应的七段位模式。通过使用 AND(与)

操作,可以将 ASCII 编码的数字转换为可作为表索引的 4 位数。此外,需要检查 ASCII 码的高 4 位是否

是 0011。注意,DIGIT、SEVEN 和 TABLE 这三个地址可以用 16 位来表示。

图 3-18 和图 3-19 分别给出了可能的 RISC 风格和 CISC 风格的程序。

120

~

121

122

Page 20: Computer Organization and Embedded Systems, Sixth Edition ...images.china-pub.com/ebook3765001-3770000/3768724/ch03.pdf第3 章 Computer Organization and Embedded Systems, Sixth Edition

82  ·  第 3 章 基本输入 / 输出

ILOC: Subtract SP, SP, #8Store LINK_reg, 4(SP)Store R2, (SP)MoveControl R2, IPENDINGAnd R2, R2, #8Branch_if_[R2]=0 NEXTLoadByte R2, TIM_STATUSCall DISPLAY

NEXT: ˙˙˙

Load R2, (SP)Load LINK_reg, 4(SP)Add SP, SP, #8Return-from-interrupt

START: ˙˙˙OrHigh R2, R0, #0x3B9AOr R2, R2, #0xCA00Store R2, TIM_INITMove R2, #7StoreByte R2, TIM_CONTMoveControl R2, IENABLEOr R2, R2, #8MoveControl IENABLE, R2MoveControl R2, PSOr R2, R2, #1MoveControl PS, R2

COMPUTE:

保存寄存器

检查 IPENDING 的内容检查是否是定时器的请求

清除 TIRQ 和 ZERO 位调用 DISPLAY 程序检查其他中断

恢复寄存器

为 ISR 建立参数表准备初始计数值

设置初始计数值将定时器设置为持续运行

模式,并允许中断

在处理器控制寄存器中允许定时器中断

设置 PS 中的中断允许位

中断处理程序

主程序

下一条指令

图 3-15 例 3.5 的 RISC 风格的程序一

ILOC: Move – (SP), R2Move – (SP), LINK_regMoveControl R2, IPENDINGTestBit R2, #3Branch 0 NEXTMoveByte R2, TIM_STATUSCall DISPLAY

NEXT: ˙˙˙

Move LINK_reg, (SP)+Move R2, (SP)+Return-from-interrupt

START: ˙˙˙Move TIM_INIT, #0x3B9ACA00MoveByte TIM_CON, #7

MoveControl R2, IENABLEOr R2, #8MoveControl IENABLE, R2MoveControl R2, PSOr R2, #1MoveControl PS, R2

COMPUTE:

保存寄存器

检查 IPENDING 的内容检查是否是定时器的请求

清除 TIRQ 和 ZERO 位调用 DISPLAY 程序检查其他中断

恢复寄存器

为 ISR 建立参数表设置初始计数值将定时器设置为持续运行模

式,并允许中断

在处理器控制寄存器中允许定时器中断

设置 PS 中的中断允许位

中断处理程序

主程序

下一条指令

图 3-16 例 3.5 的 CISC 风格的程序

一  即将 TIM_CONT 寄存器的 FREE、RUN 和 TIE 位都置为 1。——译者注

Page 21: Computer Organization and Embedded Systems, Sixth Edition ...images.china-pub.com/ebook3765001-3770000/3768724/ch03.pdf第3 章 Computer Organization and Embedded Systems, Sixth Edition

第 3 章 基本输入 / 输出  ·  83

ce

1011

111

a

1

b

0 1

11

1

01

123

0

4

c

56789

1111

011

0

1 1

11

1

11

011

1

d

0

10

0

10

e

101

1

1

01

0

01

000

1

f

1

00

1

11

g

101

1

1

11

1

01

a

g

bf

d

数字

图 3-17 七段显示器

DIGIT EQU 0x800SEVEN EQU 0x4030

LoadByte R2, DIGITAnd R3, R2, #0xF0And R2, R2, #0x0FMove R4, #0x30Branch_if_[R3] [R4] HIGH3Move R2, #0x0F

HIGH3: LoadByte R5, TABLE(R2)StoreByte R5, SEVEN

ORIGIN 0x1000TABLE: DATABYTE 0x7E,0x30,0x6D,0x79

DATABYTE 0x33,0x5B,0x5F,0x70DATABYTE 0x7F,0x7B,0x00,0x00DATABYTE 0x00,0x00,0x00,0x00

ASCII 编码数字的位置七段显示器的地址载入 ASCII 编码的数字提取 ASCII 码的高位提取十进制数检查 ASCII 码的高位是否是

0011如果不是数字,显示空白获得七段模式显示数字

包含七段模式的表

图 3-18 例 3.6 的 RISC 风格的程序

DIGIT EQU 0x800SEVEN EQU 0x4030

Move R2, DIGITMove R3, R2And R3, #0xF0And R2, #0x0FCompareByte R3, #0x30Branch 0 HIGH3Move R2, #0x0F

HIGH3: MoveByte SEVEN, TABLE(R2)

ORIGIN 0x1000TABLE: DATABYTE 0x7E,0x30,0x6D,0x79

DATABYTE 0x33,0x5B,0x5F,0x70DATABYTE 0x7F,0x7B,0x00,0x00DATABYTE 0x00,0x00,0x00,0x00

ASCII 编码数字的位置七段显示器的地址载入 ASCII 编码的数字

提取 ASCII 码的高位提取十进制数检查 ASCII 码的高位是否是 0011

如果不是数字,显示空白显示数字

包含七段模式的表

图 3-19 例 3.6 的 CISC 风格的程序

习题

[E] 3.1 一旦输入数据寄存器被读取,接口电路中的输入状态位就会被清空。为什么要这么做?

[E] 3.2 写一个程序,在显示设备的一行上以 16 进制形式显示主存中 10 个字节的内容。这 10 个字节从

存储器的 LOC 单元开始,每个字节含有两个 16 进制字符。显示时,连续的字节用空格隔开。

[E] 3.3 子程序与中断服务程序的区别是什么?

123

~

125

Page 22: Computer Organization and Embedded Systems, Sixth Edition ...images.china-pub.com/ebook3765001-3770000/3768724/ch03.pdf第3 章 Computer Organization and Embedded Systems, Sixth Edition

84  ·  第 3 章 基本输入 / 输出

[E] 3.4 在图 3-4 中的第一条 And 指令中,在检查 KIN 标识的时候使用了立即值 2,但在图 3-5 中的第一

条 TestBit 指令中,检查 KIN 标识时却使用了立即值 1。解释两者的区别。

[D] 3.5 有一台计算机,要求它从 20 台终端的键盘输入端接收字符。指针 PNTRn 指向用于存储每一台终

端的数据的主存区域,n 从 1 到 20。当另一个程序 PROG 正在执行时,终端的输入数据必须被

收集起来。这可以由如下两种方法实现:

(a) 每 T 秒钟程序 PROG 调用一个轮询子程序 POOL。这个子程序按顺序查询所有 20 台终端的

状态并将所有输入字符传送到存储器中,然后返回到 PROG。

(b) 当任何终端的接口缓冲区中有就绪的字符时,产生一个中断请求,然后中断服务程序

INTERRUPT 被执行。INTERRUPT 查询状态寄存器以找出第一个就绪的字符,传送该字符,

然后返回到 PROG。

编写程序 POOL 和 INTERRUPT。假设所有终端的最大字符输入速率为每秒 c 个字符,平均速率

等于 rc,其中 r ≤ 1。在方法(a)中,能够保证不丢失输入字符的 T 的最大值是多少?在方法

(b)中,等价的 T 值又是多少?估计一下,在 c=100,r 分别为 0.01、0.1、0.5 和 1 时,方法(a)和(b)中服务终端的平均时间百分比是多少。假设 POLL 花费 800 纳秒去查询所有 20 台设备,

处理设备的中断需要 200 纳秒。

[E] 3.6 在图 3-9 中,主程序的 START 段最后才设置 PS 中的中断允许位,这是为什么?该顺序对

START 中之前的操作是否有影响?为什么?

[E] 3.7 即使有多个中断请求等待处理,图 3-9 中每次进入 ILOC 时仍只能处理一个请求。以上说法是

正确还是错误?说明理由。

[E] 3.8 一个用户程序可以在每次除法操作前立刻检查除数是否为 0,然后采取适当的动作而不去调用操

作系统。给出理由说明为什么在用户程序中除数为 0 的实际情况下,允许产生一个异常中断是 /不是最好的。

[M] 3.9 假设一个存储单元 BINARY 包含一个 16 位的模式。要求在具有图 3-3 所示接口的显示设备上把

这些位显示为 0 和 1 组成的字符串。写一个 RISC 风格的程序完成 这个任务。

[M] 3.10 写一个 CISC 风格的程序完成习题 3.9 中的任务。

[E] 3.11 如果 TABLE 的地址是 0x10100,修改图 3-18 中的程序。

[E] 3.12 如果 TABLE 的地址是 0x10100,修改图 3-19 中的程序。

[M] 3.13 使用图 3-17 中的七段显示器以及图 3-14 中的定时器接口寄存器,写一个 RISC 风格的程序,显

示十进制数字的重复序列 0、1、2、…、9、0、…,每一个数字显示一秒钟。假设定时器电路

中的计数器是由 100MHz 的时钟驱动的。

[M] 3.14 写一个 CISC 风格的程序完成习题 3.13 中的任务。

[D] 3.15 使用两个图 3-17 所示的七段显示器以及图 3-14 中的定时器接口寄存器,写一个 RISC 风格的程

序,显示十进制数的重复序列 0、1、2、…、98、99、0、…,每个数显示一秒钟。假设定时器

电路中的计数器是由 100MHz 的时钟驱动的。

[D] 3.16 写一个 CISC 风格的程序完成习题 3.15 中的任务。

[D] 3.17 写一个 RISC 风格的程序,计算挂钟时间并以小时(0 到 23)和分钟(0 到 59)的形式显示时

间。显示器包括 4 个图 3-17 所示的七段显示器。还有一个具有图 3-14 所示接口寄存器的定时

器电路,其计数器是由 100MHz 的时钟驱动的。

[D] 3.18 写一个 CISC 风格的程序完成习题 3.17 中的任务。

[M] 3.19 写一个 RISC 风格的程序,倒序显示用户的名字。该程序应能显示一个提示符,要求在键盘上

输入用户名的字符,并以回车符(CR)结束。该程序还应该能接受字符序列并将它们保存在主

存中。然后它应显示一条消息,来指示该用户的名字将被倒序显示,紧接着就以相反的顺序显

示用户名的字符。

[M] 3.20 写一个 CISC 风格的程序完成习题 3.19 中的任务。

[M] 3.21 写一个 RISC 风格的程序,确定用户在键盘上输入的单词是否是回文。回文是指其字符以正常

126

Page 23: Computer Organization and Embedded Systems, Sixth Edition ...images.china-pub.com/ebook3765001-3770000/3768724/ch03.pdf第3 章 Computer Organization and Embedded Systems, Sixth Edition

第 3 章 基本输入 / 输出  ·  85

顺序或者相反顺序写出时都相同的单词。该程序应能显示一个提示符,要求用户在键盘上输入

任意一个单词的字符,并以回车符(CR)结束。该程序还应该能读取这些字符并将它们保存在

主存中。然后分析该单词以确定它是否是一个回文。最后,该程序应显示一条消息,以说明分

析的结果。

[M] 3.22 写一个 CISC 风格的程序完成习题 3.21 中的任务。

[D] 3.23 写一个 RISC 风格的程序,在一个标准的 80 个字符的行上水平居中显示一个字符串,并将其封

闭在一个盒子中,如下所示。

+-------------+| sample text |+-------------+

该字符串存储在以地址 STRING 开始的主存中。字符串的末尾有一个 NUL 控制字符(值为 0)。如果该字符串含有 78 个以上的字符(包括空格),则程序应将显示的字符串截断为 78 个字符。

可以将例 2.1 中确定字符串长度的程序改写为本问题中的程序所使用的一个子程序。假设显示

设备具有图 3-3 所示的接口。

[D] 3.24 写一个 CISC 风格的程序完成习题 3.23 中的任务。

[D] 3.25 写一个 RISC 风格的程序,显示一个 ASCII 字符编码的文本长序列,为了适应每行 80 个字符,

该文本序列应能自动换行。在显示下一个单词前,该程序必须确定本行剩下的空间是否足以显

示这个单词。如果不够,该单词应该在下一行的开头显示。当到达要显示的字符序列末端的

NUL 控制字符(值为 0)时,显示过程结束。假设该字符序列不使用除了末端的 NUL 字符之

外的控制字符,因此单词间仅用一个空格字符隔开。假设显示设备具有图 3-3 所示的接口。

[D] 3.26 写一个 CISC 风格的程序完成习题 3.25 中的任务。

127

128