本章目标
2.1 存储单元和地址
访问寄存器和存储器操作数的寻址方式
●
用于表示机器指令、数据和程序的汇编语言
●
堆栈和子程序
●
这一章我们从机器指令集的角度来考虑程序在计算机中的执行方法。第1 章已经介绍了 存储在存储器中的程序指令和数据操作数的一般概念,在本章中我们将讨论指令是如何组成 的,学习指令序列从存储器传递到处理器并完成给定任务的方法,还将介绍用来访问存储单元 和处理器寄存器中操作数的常用寻址方式。
这里强调的是基本概念。我们用一种通用的方式来描述机器指令和商用处理器中典型的 操作数寻址方式。本章将介绍足够的指令和寻址方式,以便于能够给出一个针对简单任务的完 整且真实的程序。这些通用程序用汇编语言进行了说明,其中机器指令和操作数寻址信息用符 号名来表示。包括操作数寻址方式在内的完整的指令集通常被称为处理器的指令集体系结构
(instruction set architecture,ISA)。在本章中我们对基本概念进行讨论,不需要定义完整的指 令集,我们也不会去尝试这样做,而是给出足够的例子来说明一种典型指令集的功能。
在本章和第3 章介绍的概念涉及输入 / 输出技术,这些概念对于理解计算机的功能是非常 必要的。我们选择了一种通用的表示方式使得内容易于阅读和理解。同时,这种方式允许进行 一般性的讨论而不受特定处理器特性的限制。
这些概念是怎样在真实的计算机上实现的呢?这很有趣而且非常重要,因此在第2 章和 第3 章中,我们会提供四个流行的商用处理器的例子。这些处理器在附录 B 到 E 中进行介绍。
附录B 讨论 Altera 公司的 Nios Ⅱ处理器。附录 C 介绍 Freescale 半导体公司的 ColdFire 处理 器。附录D 讨论 ARM 公司的 ARM 处理器。附录 E 介绍 Intel 公司的处理器基本体系结构。
在第2 章和第 3 章出现的通用程序在每一个附录中都会用具体的指令集表示出来。
读者可以选择一种处理器来学习相应附录中的内容,以了解商用的ISA 设计。但是,这 些附录中的知识对于本书主体内容的理解来说不是必要的。
大多数的程序是用高级语言编写的,比如用C、C++ 或 Java。为了在处理器上执行高级语 言程序,这个程序必须首先被翻译成该处理器上的机器语言,这由编译程序完成。汇编语言是 机器语言的一种易读的符号表示形式。在本书里我们会大量使用汇编语言,因为这是描述计算 机工作方式的最好方法。
本章中,我们将首先讨论指令和数据是如何存储在存储器中的以及如何访问它们以进行 处理。
2.1 存储单元和地址
我们首先来考虑计算机的存储器是如何构成的。存储器是由几百万个存储单元(cell)构 成的,其中每个单元可以存储一位(bit)具有 0 值或 1 值的信息。由于单独的一位只表示信 27
息中一个非常小的量,所以很少单独对位进行处理。常用的方法是按固定大小的组对位进行处 理。为此,存储器被组织成适合在一个基本操
作中对 n 位一组的信息进行存储或检索的形式。
每一个 n 位组称为一个字(word),n 称为字长
(word length)。计算机的存储器可以用图表方 式表示成字的集合,如图2-1 所示。
现代计算机的字长范围一般是从16 位到 64 位。如果一台计算机的字长是 32 位,那么 如图2-2 所示,一个单独的字就能够存储一个 32 位的有符号数或是四个各占 8 位的 ASCII 编 码 字 符。 一 个8 位 的 单 元 叫 做 一 个 字 节
(byte)。机器指令可能需要用一个或多个字来 表示。在描述了汇编语言级的指令后,在后面 一节中我们将讨论机器指令是如何被编码到存 储器的字中的。
为了存储或检索一个信息项需要访问存储 器,该信息项无论是一个字或是一个字节,对 于每一项的位置都要有具体的名字或是地址
(address)。习惯上我们用从 0 到 2k - 1 (k 取某个
适当的值)的数字作为存储器连续单元的地址。因此存储器可以有高达2k个可寻址单元。2k 个地址构成了计算机的地址空间(address space)。例如,一个 24 位的地址生成一个具有 224 (16 777 216) 个存储单元的地址空间。这个数通常写成 16M,这里 1M 表示数 220 (1 048 576) 。 一个32 位的地址创建出具有 232或者4G 个存储单元的地址空间,这里 1G 表示的是 230。其他 的惯用表示法就是用K 来表示数 210 (1 024) ,用 T 表示数 240。
b31 b30 b1 b0
ASCII 字符
a)一个有符号整数
b)四个字符 32 位
符号位:b31=0 代表正数 b31=1 代表负数
8 位 8 位 8 位 8 位
ASCII 字符 ASCII 字符 ASCII 字符
图2-2 一个 32 位字中编码信息的例子
2.1.1 按字节寻址能力
现在有三种基本的信息处理量:位、字节和字。一个字节通常为8 位,但字长通常的范围 是从16 位到 64 位。为存储器中的每一位分配不同的地址是不切实际的做法。实际上大部分的 分配方法是将连续的地址对应于存储器中连续的字节单元。这是大多数现代计算机中使用的分
28
29 第1 个字
第2 个字 n 位
第 i 个字
最后一个字
图2-1 存储器中的字
配方法。按字节寻址存储器(byte-addressable memory)就使用了这种分配方法。字节单元具 有地址0,1,2,…,这样,如果机器的字长为 32 位,那么连续的字被分配到地址 0,4,8,…
中,其中每个字包含四个字节。
2.1.2 大端和小端分配
如图2-3 所示,有两种在字中分配字节地址的方法。当低字节地址作为一个字中的最高有 效字节(最左边字节)时采用大端(big-endian)方法。而小端(little-endian)方法用于相反 的次序中,其中低字节地址作为一个字中的最低有效字节(最右边字节)。“最高有效”和“最 低有效”是指当这个字表示一个数时它们在分配位中所占的权重(以2 为权)。小端和大端两种 分配法都在商业计算机中使用。在这两种情况中,都将字节地址0,4,8,… 作为 32 位字长计 算机的存储器中连续字的地址。这些地址也可以用作访问存储器以存储或检索一个字时的地址。
2k–4 2k–3 2k–2 2k–1 2k–4 2k–4
0 1 2 3
4 5 6 7
0 0
4
2k–1 2k–2 2k–3 2k–4
3 2 1 0
7 6 5 4
4 字节地址
a)大端分配 b)小端分配
字地址 字节地址
图2-3 字节和字的寻址
在一个字中除了指明字节地址排序外,还需要说明每一位在一个字节或一个字中的标记。
最常用的也是我们在本书中采用的方法在图2-2a 中给出,它是数字型数据编码最常用的排序 方法。这种排序法也可以用于在字节中标记位,即从左到右为 b7,b6,…,b0。
2.1.3 字的对齐
在32 位字长的情况下,如图 2-3 所示,自然字的边界发生在地址 0,4,8,…上。如果 字位置的开始处在一个字节地址上,这个地址又是一个字中字节数的整数倍,那么我们说这些 字的位置具有对齐(aligned)地址。因为实际中会涉及二进制码地址的操作,一个字的字节数 是2 的幂次方,因此,如果字长是 16 位(2 个字节),对齐字从字节地址 0,2,4,… 开始,
而如果字长是64 位(23个字节),对齐字从字节地址0,8,16,… 开始。
没有一个基本原则性的约定规定字不能从任意一个字节地址开始。如果一个字可以从任 意的字节地址开始,这些字就是不对齐(unaligned)地址。但是,在大多数情况下使用的是对 齐的地址,我们将会在第8 章中看到,这会使得存储器操作数的访问操作更加高效。
2.1.4 访问数和字符
一个数通常占用一个字,在存储器中可以通过指明字的地址对其进行访问。同样,对于 30
31
单个字符也可以通过它们的字节地址进行访问。
为了编程方便,用不同的方法在程序指令中指定地址是非常有益的。我们将会在2.4 节中 讨论这个主题。