【分析解答】
第 3 版 · OCR 辅助 · 原书检索 · 文字用于定位,公式与图表请回原页核验 · 本次导入快照
## 【分析解答】
浮点运算结果是否溢出,并不以尾数溢出来判断,而主要看阶码是否溢出。尾数溢出时,可通过右规操作进行纠正。因为在进行规格化、尾数舍入和浮点数的乘/除运算过程中,都需要对阶码进行加、减运算,因此,在这些操作过程中,可能会发生阶码上溢或阶码下溢。阶码上溢时,说明结果的数值太大,无法表示,是真正的溢出;阶码下溢时,说明结果数值太小,可以把结果近似为 0。
16. 假设浮点数格式是:阶码为 4 位移码,偏置常数为 8,尾数为 6 位补码(采用双符号位)。用浮点运算规则分别计算在不采用任何附加位和采用 2 位附加位(保护位、舍入位)的情况下以下各式的值(假定对阶和右规时采用就近舍入到偶数方式)。
(1)$(15/16) \times 2^2 + (2/16) \times 2^5$。
(2)$(15/16) \times 2^2 - (2/16) \times 2^5$。
<!-- page: 75 -->
(3) $(15 / 16) \times 2^{5} + (2 / 16) \times 2^{7}$。
(4) $(15 / 16) \times 2^{5} - (2 / 16) \times 2^{7}$。
## 【分析解答】
将上述各式中的数据用相应的变量 $A, B, C, D$ 代替。
$$
\begin{array}{l}
A = (15 / 16) \times 2^{7} = 0.1111B \times 2^{7}, [A]_{\text{序}} = 00.1111, 1111. \\
B = (2 / 16) \times 2^{5} = 0.0010B \times 2^{5} = 0.1000B \times 2^{3}, [B]_{\text{序}} = 00.1000, 1011. \\
C = (15 / 16) \times 2^{5} = 0.1111B \times 2^{5}, [C]_{\text{序}} = 00.1111, 1101. \\
D = (2 / 16) \times 2^{7} = 0.0010B \times 2^{7} = 0.1000B \times 2^{5}, [D]_{\text{序}} = 00.1000, 1101.
\end{array}
$$
不采用任何附加位时的计算结果如下。
(1) 计算 $A + B: [\Delta E]_{\psi} = [E_A]_{\psi} + [-[E_B]_{\psi}]_{\psi} = 1111 + 0101 = 0100 \pmod{2^4}$,因此 $\Delta E = 4$,故需对 $B$ 进行对阶,因为采用就近舍入到偶数方式,所以,$B$ 的尾数右移 4 位后直接舍去 1000,又因为“1000”是中间值,因此尾数取偶数 00.0000,故对阶后结果为 $[B]_{\text{序}} = 00.0000, 1111$。由于 $B$ 的尾数为 0,因此,$[A + B]_{\text{序}} = [A]_{\text{序}} = 00.1111, 1111$。故 $A + B = A = (15/16) \times 2^7$。
(2) 计算 $A - B$,对阶结果与(1)相同,故 $[A - B]_{\text{序}} = [A]_{\text{序}} = 00.1111, 1111$。故 $A - B = A = (15/16) \times 2^7$。
(3) 计算 $C + D: [\Delta E]_{\psi} = [E_C]_{\psi} + [-[E_D]_{\psi}]_{\psi} = 1101 + 0011 = 0000 \pmod{2^4}$,因此 $\Delta E = 0$,故无需对阶。尾数直接加:$[M_C]_{\psi} + [M_D]_{\psi} = 00.1111 + 00.1000 = 01.0111$,因为补码的两个符号位不同,所以尾数溢出,需要右规。右规时需对尾数进行舍入,阶码加 1。舍入最后一位的“1”是中间值,因此尾数取偶数 00.1100,阶码 1101 加 1 后为 1110,所以,$[C + D]_{\text{序}} = 00.1100, 1110$。故 $C + D = (12/16) \times 2^4$。
(4) 计算 $C - D$,对阶结果与(3)相同。尾数直接减:$[M_C]_{\psi} + [-M_D]_{\psi} = 00.1111 + 11.1000 = 00.0111$。显然,尾数需左规。左规时,尾数左移一位,阶码减 1。因此,最终尾数为 00.1110,阶码 1101 减 1 后为 1100。因此,$[C - D]_{\text{序}} = 00.1110, 1100$,故 $C - D = (14/16) \times 2^4$。
采用两位附加位时的计算结果如下。
(1) 计算 $A + B: [\Delta E]_{\psi} = [E_A]_{\psi} + [-[E_B]_{\psi}]_{\psi} = 1111 + 0101 = 0100 \pmod{2^4}$,因此 $\Delta E = 4$,故需对 $B$ 进行对阶,对阶后结果为 $[B]_{\text{序}} = 00.0000, 10, 1111$。尾数相加结果为:$[M_A]_{\psi} + [M_B]_{\psi} = 00.1111, 00 + 00.0000, 10 = 00.1111, 10$,因此,$[A + B]_{\text{序}} = 00.1111, 10, 1111$。最后对尾数附加位 10 进行舍入,因为舍入的是中间值,所以尾数结果强迫为偶数,即尾数末位加 1,得尾数为 01.0000,因此,尾数需右规为 00.1000,同时,阶码 1111 加 1,产生阶码上溢,因而导致结果溢出。因此,$A + B$ 的结果溢出。
(2) 计算 $A - B$,对阶结果与(1)相同,尾数相减结果为:$[M_A]_{\psi} + [-M_B]_{\psi} = 00.1111, 00 + 11.1111, 10 = 00.1110, 10$,因此,$[A - B]_{\text{序}} = 00.1110, 10, 1111$。最后对尾数附加位 10 进行舍入,因为舍入的是中间值,所以尾数结果强迫为偶数,得尾数为 00.1110,因此,$[A - B]_{\text{序}} = 00.1110, 1111$。故 $A - B = (14/16) \times 2^7$。
(3) 计算 $C + D: [\Delta E]_{\psi} = [E_C]_{\psi} + [-[E_D]_{\psi}]_{\psi} = 1101 + 0011 = 0000 \pmod{2^4}$,因此 $\Delta E = 0$,故无需对阶。尾数直接加:$[M_C]_{\psi} + [M_D]_{\psi} = 00.1111, 00 + 00.1000, 00 = 01.0111, 00$,因为补码的两个符号位不同,所以尾数溢出,需要右规。右规时需对尾数进行舍入,阶码加 1。舍入的“100”是中间值,因此尾数取偶数 00.1100,阶码 1101 加 1 后为 1110,
<!-- page: 76 -->
所以,$[C + D]_{\mathrm{浮}} = 00.1100, 1110$。故 $C + D = (12 / 16) \times 2^{6}$。
(4) 计算 $C - D$:对阶结果与(3)相同,尾数直接减:$[M_C]_{\mathrm{扑}} + [-M_D]_{\mathrm{卸}} = 00.111100 + 11.100000 = 00.011100$。显然,尾数需左规。左规时,尾数左移一位,阶码减1。因此,最终尾数为00.1110,阶码1101减1后为1100。因此,$[C - D]_{\mathrm{浮}} = 00.1110, 1100$,故 $C - D = (14 / 16) \times 2^4$。
17. 采用 IEEE 754 单精度浮点数格式计算下列表达式的值。
(1) $0.75 + (-65.25)$。
(2) $0.75 - (-65.25)$。
【分析解答】
$x = 0.75 = 0.11\mathrm{B} = (1.10\dots 0)_2\times 2^{-1},y = -65.25 = -1000001.01\mathrm{B} = (-1.00000101\dots 0)_2\times 2^6$。用IEEE 754标准单精度格式表示为 $[x]_{\mathrm{浮}} = 00111111010\dots 0, [y]_{\mathrm{浮}} = 110000101000001010\dots 0$。假定用 $E_{x}\backslash E_{y}$ 分别表示 $[x]_{\mathrm{浮}}$ 和 $[y]_{\mathrm{浮}}$ 中的阶码,$M_x\backslash M_y$ 分别表示 $[x]_{\mathrm{浮}}$ 和 $[y]_{\mathrm{浮}}$ 中的尾数,即 $E_{x} = 01111110, M_{x} = 0(1).10\dots 0, E_{y} = 10000101, M_{x} = 1(1).000001010\dots 0$。尾数 $M_{x}$ 和 $M_{y}$ 的小数点前面有两位,第一位为数符,第二位加了括号,是隐藏位“1”。以下是机器中浮点数加/减运算过程(假定保留2位附加位;保护位和舍入位)。
(1) $0.75 + (-65.25)$。
① 对阶。$[\Delta E]_{\mathrm{卸}} = E_x + [-E_y]_{\mathrm{卸}} = 01111110 + 01111011 = 11111001 \pmod{2^8}$,$\Delta E = -7$,故需对 $x$ 进行对阶,结果为 $E_{x} = E_{y} = 10000101, M_{x} = 00.000000110\dots 000$,即将 $x$ 的尾数 $M_{x}$ 右移7位,符号不变,数值高位补0,隐藏位右移到小数点后面,最后移出的2位保留。
② 尾数相加。$M_{h} = M_{x} + M_{y} = 00.000000110\dots 000 + 11.000001010\dots 000$(注意小数点在隐藏位后)。根据原码加/减法运算规则,得 $00.000000110\dots 000 + 11.000001010\dots 000 = 11.000000100\dots 000$。上式尾数中最左边第一位是符号位,其余都是数值部分,尾数后面两位是附加位(加粗)。
③ 规格化。根据所得尾数的形式,数值部分最高位为1,所以不需要进行规格化。
④ 舍入。将结果的尾数 $M_{h}$ 中最后两位附加位舍入,从本例来看,不管采用什么舍入法,结果都一样,都是把最后两个0去掉,得 $M_{h} = 11.000000100\dots 0$。
⑤ 溢出判断。在上述阶码计算和调整过程中,没有发生“阶码上溢”和“阶码下溢”的问题。最终结果为 $E_{h} = 10000101, M_{h} = 1(1).00000010\dots 0$,即 $(-1.0000001)_{2} \times 2^{6} = -64.5$。
(2) $0.75 - (-65.25)$。
① 对阶。同上述(1)中对阶过程一样。
② 尾数相减。$M_{h} = M_{x} - M_{y} = 00.000000110\dots 000 - 11.000001010\dots 000$,根据原码加/减法运算规则,得 $00.000000110\dots 000 - 11.000001010\dots 000 = 01.000010000\dots 000$。上式尾数中最左边第一位是符号位,其余都是数值部分,尾数后面两位是附加位(加粗)。
③ 规格化。根据所得尾数的形式,数值部分最高位为1,不需要进行规格化。
④ 舍入。把结果的尾数 $M_{h}$ 中最后两位附加位舍入掉,得 $M_{h} = 01.000010000\dots 0$。
⑤ 溢出判断。在上述阶码计算和调整过程中,没有发生“阶码上溢”和“阶码下溢”的问题。最后结果为 $E_{h} = 10000101, M_{h} = 0(1).000010000\dots 0$,即 $(+1.00001)_{2} \times 2^{6} = +66$。
<!-- page: 77 -->
# 第4章 指令系统
## 4.1 教学目标和内容安排
主要教学目标:了解高级语言与汇编语言之间、汇编语言与机器语言之间的对应关系;掌握指令系统设计中有关指令格式、操作数类型、寻址方式、操作类型等内容;了解高级语言源程序转换为机器级代码的过程;并深刻理解CISC和RISC之间的差别。
### 基本学习要求:
(1) 理解引入高级语言、汇编语言和机器语言的目的。
(2) 了解“存储程序”工作方式的内涵。
(3) 了解指令的基本格式及其设计原则。
(4) 理解定长操作码指令的特点。
(5) 理解扩展操作码指令格式的设计方法。
(6) 理解指令寻址和有效地址的概念。
(7) 理解各种常见寻址方式的含义和应用场景。
(8) 理解指令中地址码的位数与主存容量、最小寻址单位之间的关系。
(9) 理解数据寻址和指令寻址的差别。
(10) 理解累加器型指令的特点。
(11) 理解线型指令的特点。
(12) 理解装入/存储型指令的特点。
(13) 理解通用寄存器型指令的特点。
(14) 理解各种指令类型的功能和操作过程。
(15) 理解分支指令、跳转指令、调用指令和返回指令的特点和相互间的区别。
(16) 理解CISC和RISC的区别和各自的特点。
(17) 了解汇编语言和机器语言(指令代码)之间的对应关系。
(18) 了解高级语言源程序和机器语言(指令代码)之间的对应关系。
(19) 了解从高级语言源程序到可执行文件的转换过程。
高级语言源程序最终必须转换成机器指令代码才能在机器上运行,所以,指令系统最根本的设计需求来自高级语言,因而,要能够很好地理解指令系统设计涉及的各类问题,最好能够站在高级语言程序员的角度去思考。例如,对于操作数类型,因为在高级语言中有各种
<!-- page: 78 -->
不同长度的无符号整数、带符号整数等数据类型,所以,底层指令系统中也需要提供相应的不同长度和不同类型数据的支持;对于操作类型,因为高级语言中存在各种运算表达式,以及循环和选择等各类程序结构,所以,指令系统就必须能够提供不同的运算类指令和不同的程序控制类指令;对于数据的寻址方式,因为高级语言中有简单/复合类型变量、静态/动态变量、全局/局部变量等各种属性数据的存在,使得数据所存放的位置具有多样性,例如,部分简单变量被分配在寄存器中存放,复合类型变量分配在存储器中存放,全局静态变量被分配在存储器的静态数据区,动态变量在存储器的堆区存放,局部变量被分配在存储器的栈区存放等,因此,在指令中需要能够存取在不同地方存放的数据,因而就涉及寻址方式问题。寻址方式的多样性是由数据存放位置的多样性决定的。
此外,指令系统的设计需求还有一部分来自操作系统。操作系统直接和硬件打交道,它通过对CPU和I/O接口中各种控制和状态寄存器,以及内存中专门的存储区进行直接的访问来实现对硬件资源的管理,因此,指令系统中还必须提供这些用来对硬件资源直接进行控制和管理的指令,专门供操作系统内核程序所用。
因此,在本章内容的教学过程中,应该适当地结合高级程序设计语言、编译器和操作系统的一些相关内容来讲解。尽量使学生能够在知其然的同时,也知其所以然。
在课时有限的情况下,指令系统实例和程序的机器级表示可以作为课外阅读材料,这部分内容基本上是具体的指令系统。在学习了前面基本原理的基础上,学生通过阅读与具体的指令系统相关的资料,可以起到巩固所学,加深理解的作用。
为了方便对指令功能进行形式化描述,通常使用寄存器传送级语言(Register Transfer Language, RTL),本书所用的RTL表示约定为: $R[a]$ 表示寄存器 $a$ 的内容, $M[a]$ 表示内存单元 $a$ 的内容,PC的内容直接用PC表示(参照主教材5.1.1节最后一段的说明)。
## 4.2 主要内容提要
### 1. 指令格式设计
指令中必须明显或隐含地给出以下信息:操作码、操作数或操作数的地址、结果存放的地址,以及下条指令的地址,通常下条指令地址隐含地由程序计数器PC给出。按照指令长度是否固定划分,可分为定长指令字格式和变长指令字格式。按照操作码长度是否固定划分,也可分为定长操作码指令格式和变长操作码指令格式。采用定长指令字和定长操作码方式,可以简化指令地址计算以及取指和译码操作;采用变长指令字和变长操作码方式,则指令更紧凑,使得程序占用空间更少。
### 2. 操作类型
根据操作类型的不同,可以将指令分成6类指令:①数据传送指令:数据在寄存器、主存单元、栈顶之间进行传送;②运算指令:各种算术运算和逻辑运算;③字符串处理类:字符串查找、扫描、转换等;④I/O指令:用于CPU中的寄存器与外设接口中的寄存器之间进行数据、状态和命令信息的交换;⑤程序流控制指令:如条件转移、无条件转移、调用、返回等指令;⑥系统控制指令:控制机器的启动和停止,进行自愿访管或自陷以及空操作等。
<!-- page: 79 -->
## 3. 操作数类型
为了支持高级语言中对不同类型数据的操作,必须提供对不同数据类型进行操作的指令,而且操作数宽度也有多种,以对应高级语言中各种类型的数据长度,如8位、16位、32位、64位等。下面以IA-32为例,提供的数据类型有以下5类。①序数或指针:用8位、16位或32位无符号整数表示;②带符号整数:用8位、16位、32位或64位补码表示;③实数:用IEEE 754浮点数格式表示;④十进制整数:用18位BCD码(80个二进位,其中符号占1字节)表示;⑤字符串:以字节为单位的字符序列,用ASCII码表示。
## 4. 寻址方式
编译器通常将高级语言程序中定义的各类常量和变量所需的空间分配在不同的寄存器或存储区中,例如,简单变量可能分配在通用寄存器中,静态全局数组变量分配在存储空间的静态数据区,动态变量分配在存储空间的动态数据区(堆区),局部变量分配在栈区,而且对于数组等复合变量,通常在程序中需要对每个基本元素进行访问和操作。因此,指令系统中必须提供一套行之有效的寻址方式,以方便CPU在执行指令时能快速地定位操作数所在位置并取得操作数。通常将操作数所在的存储单元的地址称为有效地址。指令中提供的寻址方式有以下7种。①立即寻址:指令中直接给出操作数本身;②直接寻址:指令的地址码给出操作数所在的存储单元地址;③间接寻址:指令的地址码给出操作数所在的存储单元地址所在的存储单元地址;④寄存器寻址:指令的地址码给出操作数所在的寄存器的编号;⑤寄存器间接寻址:指令的地址码给出操作数所在的存储单元地址所在的寄存器的编号;⑥栈寻址:操作数约定在栈中,总是在栈顶取数或存数;⑦偏移寻址:用寄存器内容加形式地址得到操作数所在的存储单元地址,包括变址寻址、相对寻址和基址寻址三种寻址方式。
变址寻址方式下,地址码给出一个形式地址,并且隐式或显式地指定一个寄存器作为变址寄存器,变址寄存器的内容(称为变址值)和形式地址相加,得到操作数的有效地址,通常用于循环体中对数组元素的访问。
相对寻址方式下,指令中的形式地址给出一个位移量 $D$,而基准地址由程序计器PC提供。即有效地址 $\mathrm{EA} = (\mathrm{PC}) + D$,通常用于转移指令中转移目标或公共子程序中的操作数的寻址。
基址寻址方式下,地址码给出的形式地址作为位移量,和基址寄存器的内容相加,得到有效地址。基址寄存器可以在指令中显式指定由某个通用寄存器充当,也可以用一个专门的基址寄存器。
## 5. 条件码(状态标志)的生成
对应高级语言程序中的选择结构和循环结构,相应的机器代码中需要有条件转移指令,它们根据不同的状态标志来改变程序的执行顺序。通常的状态标志有CF(进/借位标志)、ZF(零标志)、OF(溢出标志)、SF(符号标志)等。
## 6. 指令系统风格
按地址码指定风格来分,可以分成累加器型、栈型、通用寄存器型和装入/存储型指令系统。累加器型指令系统中,其中一个操作数和运算结果都隐含存放在累加器中,因而指令长度短,但程序的指令条数较多,并需要频繁访问存储器;栈型指令系统中,操作数和结果都隐含在栈中,因而指令中不需要指定地址码,指令长度短,但需要频繁访问栈,并且对指令序列
<!-- page: 80 -->
的顺序要求严格;通用寄存器型指令系统中,操作数明显地指定在通用寄存器中,使用大量通用寄存器,既缩短了指令长度,又减少了访问存储器的次数,所以现代计算机大多采用这种指令设计风格;装入/存储型指令系统中,只有装入(Load)指令和存储(Store)指令才能访问内存,而运算类指令的操作数只能在寄存器中,这种类型指令系统本身是通用寄存器型指令系统。
按指令系统的复杂度来分,可分成CISC(复杂指令系统计算机)和RISC(精简指令系统计算机)两类指令系统。CISC指令系统大多采用变长指令字和扩展操作码编码方式,指令格式多,指令条数多,寻址方式多而复杂,因而,指令的译码实现复杂,大多用微程序控制器实现;RISC指令系统大多采用定长指令字和定长操作码,指令格式少,指令系统中仅含有一些常用指令,因而指令条数少,寻址方式少且简单,指令的译码实现简单,可用硬连线路控制器实现。RISC处理器中设置大量的通用寄存器,可大大减少存储器访问次数,并且采用装入/存储型指令设计风格,因而,大部分指令的执行步骤一致、规整,指令的执行适合于采用流水线方式。