下载第 19章 两种典型的微处理器微处理器 — 集成计算机中央处理器( C P U)的所有组件在一个硅芯片上 — 诞生于 1 9 7 1
年。它的产生有一个很好的开端:第一个微处理器是 Intel 4004,其中有 2 3 0 0个晶体管。今天,
差不多 3 0年过去了,为家用计算机所制造的微处理器中将近有 10 000 000个晶体管。
微处理器实际的作用基本上保持不变。现在的芯片上附加的上百万个晶体管可以做许多有趣的事情,但在微处理器最初的探索过程中,这些事情更多的是分散我们的注意力而不是给我们以启迪。为了对微处理器的工作情况获得更清晰的认识,让我们先看一下最初的微处理器。
这些微处理器出现在 1 9 7 4年。在该年度,I n t e l公司在 4月推出了 8 0 8 0,M o t o r o l a(摩托罗拉) — 从 2 0世纪 5 0年代开始生产半导体和晶体管产品的公司 — 在 8月份推出了 6 8 0 0。它们并非是那年仅有的微处理器。同样是在 1 9 7 4年,德克萨斯仪器公司推出了 4位的 TMS 1000,用在许多计算器、玩具和设备上; National Semiconductor(国家半导体公司)推出了 PA C E,它是第一个 1 6位的微处理器。然而,回想起来,8 0 8 0和 6 8 0 0是两个最具有重大历史意义的芯片。
I n t e l设定 8 0 8 0最初价格为 $ 360,这是对 IBM System/360的一个讽刺。 IBM System/360是一个大型机系统,由许多大公司使用,要花费几百万美元。 (今天,你只花 $ 1,9 5就可以买到一个 8 0 8 0芯片。 )这并不是说 8 0 8 0可以与 S y s t e m / 3 6 0相提并论,但不用几年,I B M公司也将会正视这些很小的计算机。
8 0 8 0是一个 8位的微处理器,有 6 0 0 0个晶体管,时钟频率为 2 M H z,可寻址 6 4 K B的存储空间。 6 8 0 0(今天也只卖 $ 1,9 5)有大约 4 0 0 0个晶体管,也可寻址 6 4 K B的存储空间。第 1代 6 8 0 0
的时钟频率为 1 MHz,但到 1 9 7 7年 M o t o r o l a公司发布新款的 6 8 0 0时,其时钟频率已为 1,5 M H z
和 2 MHz。
这些芯片称作“单芯片微处理器”,不太准确的名称为“一个芯片上的计算机” 。处理器只是整个计算机的一部分。此外,计算机至少还需要一些随机访问存储器( R A M),供人们输入信息到计算机的方法(输入设备),供人们从计算机获取信息的方法(输出设备),以及其他可把所有这些东西连接在一起的芯片。这些组件将在第 2 1章详细介绍。
从现在起,我们只考察微处理器。描述微处理器时,通常是用框图来画微处理器的内部组件及它们是如何连接的。但在第 1 7章已有够多的图了,现在,我们将通过观察处理器与外界的相互作用来了解它的内部 。换句话说,为了弄清楚它的作用,可以把微处理器看成是一个黑盒子,它的内部操作不需要做详细研究。我们可以通过测试芯片的输入和输出信号,特别是芯片的指令集来掌握微处理器的功能。
8 0 8 0和 6 8 0 0都是 4 0管脚的集成电路。这些芯片最普通的 I C封装大约是 2英寸长,半英寸宽,
1 / 8英寸厚:
第 19章 两种典型的微处理器 189下载当然,你看到的只是外包装。位于其内部的硅晶片非常小,就拿早期的 8位微处理器来说,
其硅晶片小于 1 / 4平方英寸。外包装保护硅晶片并通过管脚提供对芯片的输入和输出点的访问。
下图显示了 8 0 8 0的 4 0个管脚的功能:
本书的所有电气或电子设备都需要某种电源供电。 8 0 8 0的一个特别之处在于它需要三种电源电压:管脚 2 0必须连到 5伏电源上,管脚 11连到 - 5伏电源上,管脚 2 8连到 1 2伏电源上;管脚 2接地( 1 9 7 6年,I n t e l发布了 8 0 8 5芯片,简化了这些电源需求) 。
其余管脚都画有箭头。从芯片中出来的箭头表示输出信号,这是由微处理器控制的信号,
计算机中其余芯片对此作出响应。指向芯片的箭头表示输入信号,这是来自于其他芯片的信号,8 0 8 0对它们做出响应。有些管脚既是输入又是输出。
第 1 7章的处理器需要振荡器使它工作。 8 0 8 0需要两个不同的 2 MHz同步时钟输入,在 2 2
和 1 5管脚上分别标记为?1和?2。这些信号可以很方便地由 I n t e l公司生产的 8 2 2 4时钟信号发生器提供。给这个芯片连上一个 18 MHz的石英晶体,剩下的工作它基本上可以完成。
一个微处理器通常有多个输出信号来寻址存储空间,这种信号的数目与微处理器可寻址的存储器空间的大小直接相关。 8 0 8 0有 1 6个地址信号,标为 A 0? A 1 5,具有寻址 21 6即 65 536
字节的存储空间的能力。
8 0 8 0是一个 8位微处理器,一次可从存储器中读出、写入 8位数据。它包括 8个数据信号
D0~ D7,这些信号是在此芯片中仅有的几个既作为输入又作为输出的信号。当微处理器从存储器读数据时,这些管脚作为输入;当微处理器向存储器写数据时,这些管脚作为输出。
微处理器的另外 1 0个管脚是控制信号。例如,R E S E T输入用来复位微处理器。输出信号-
W R 表示微处理器要向 R A M中写数据。 ( -W R信号对应于 R A M阵列的写入输入。 )另外,当芯片读取指令时,其他控制信号会在某个时候出现在 D0~ D7管脚。由 8 0 8 0构成的计算机系统通常使用 8 2 2 8系统控制芯片来锁存这些附加的控制信号。后面将会讲述一些控制信号。由于 8 0 8 0
的控制信号非常复杂,因此,除非你想基于 8 0 8 0芯片来实际设计计算机,否则最好不要用这些控制信号来折磨自己。
190 编码的奥秘 下载假定 8 0 8 0微处理器连接了 6 4 K B的存储器,这样可以不通过微处理器来读写数据。
8 0 8 0芯片复位后,它从存储器的地址 0 0 0 0 h处读取该字节,送到微处理器中。这可以通过在地址信号端 A0? A1 5输出 1 6个 0来实现。它读取的字节必须是 8 0 8 0指令,这种读取字节的过程叫作取指令。
在第 1 7章构造的计算机里,所有指令(除了停止指令 H LT)都是 3个字节长,包括一个操作码和两个字节的地址。在 8 0 8 0中,指令长度可以是 1个字节,2个字节或 3个字节。有些指令可使 8 0 8 0从存储器的某一位置处读出一个字节送到微处理器中;有些指令可使 8 0 8 0从微处理器中把数据写入存储器的某一位置处;其他指令可使 8 0 8 0不使用 R A M而在内部执行。第一条指令执行完后,8 0 8 0访问存储器中的第二条指令,依此类推。这些指令组合在一起构成一个计算机程序,用来完成一些自己感兴趣的事情。
当 8 0 8 0运行在最高速度即 2 MHz时,每个时钟周期为 5 0 0纳秒( 1除以 2 000 000周等于
0,0 0 0 0 0 0 5 0 0秒) 。第 1 7章中的每条指令都需要 4个时钟周期,8 0 8 0的每条指令则需要 4? 1 8个时钟周期,这意味着每条指令的执行时间为 2? 9微秒(即百万分之一秒) 。
了解微处理器功能的最好方法可能是在系统方式下测试其完整的指令集。
第 1 7章最后出现的计算机仅有 1 2条指令。一个 8位微处理器很容易就有 2 5 6条指令,每个操作码对应于某个 8位值。 (如果一些指令有 2个字节的操作码,则实际会有更多的指令) 。 8 0 8 0虽没有那么多,但它也有 2 4 4条操作码。这看起来似乎很多,但总的来说,却又不比第 1 7章中的计算机功能多多少。例如,如果想用 8 0 8 0做乘法或除法,仍然需要写一段小程序来实现。
第 1 7章中讲过,处理器指令集的每个操作码都和某个助记符相联系,有些助记符之后可能还有操作数。但这些助记符仅用来方便地表示操作码。处理器只读取字节,它并不懂组成这些助记符的字符的含义。
第 1 7章中的计算机有两条很重要的指令,称作装载( L o a d)和保存( S t o r e)指令。这些指令都占用三个字节的存储空间。装载指令的第一个字节是操作码,操作码后的两个字节表示 1 6位地址。处理器把在此地址中的字节送到累加器。同样,保存指令把累加器中的内容存储到指令指定的地址处。
下面,我们用助记符来简写这两个操作:
LOD A,[aaaa]
STO [aaaa],A
在此,A表示累加器(装载指令的目的操作数,保存指令的源操作数),a a a a表示一个 1 6
位的存储器地址,通常用 4位十六进制数来表示。
8 0 8 0中的 8位累加器称作 A,就像第 1 7章中的累加器。正如第 1 7章中的计算机一样,8 0 8 0
也有两条与装载和保存指令功能一样的指令。 8 0 8 0中这两条指令的操作码为 3 2 h和 3 A h,每个操作码后有一个 1 6位地址。 8 0 8 0的助记符为 S TA(代表存储累加器的内容)和 L D A(代表装载到累加器),
操作码 指令
3 2 S TA [aaaa],A
3 A LDA A,[aaaa]
除了累加器,8 0 8 0微处理器内部还包括 6个寄存器( r e g i s t e r),每个寄存器可以保存 8位的值。这些寄存器和累加器非常相似,事实上,累加器被看作是一种特殊的寄存器。和累加器一样,这 6个寄存器也是锁存器。处理器可以把数据从存储器传送到寄存器,也可以把数据从寄存器送回到存储器。然而,这些寄存器没有累加器的功能强大。例如,当两数相加时,其结果通常送往累加器而非其中一个寄存器。
在 8 0 8 0中,除累加器外的 6个寄存器的名字分别为 B,C,D,E,H和 L。人们通常问的第一个问题是“用 F和 G干什么?”,第二个问题是“用 I,J和 K又要做什么?”,答案是使用寄存器 H和 L具有某种特殊的含义。 H代表高( H i g h),L代表低 ( L o w )。通常把 H和 L的 8位合起来记作 H L来表示一个 1 6位寄存器对,H作为高位字节,L作为低位字节。这个 1 6位值通常用来寻址存储器。后面我们将看到它的简单用法。
所有这些寄存器都是必需的吗?为什么不在第 1 7章中的计算机中用到它们呢?从理论上说,它们并非必需,但是使用它们会很方便。许多计算机程序在同一时刻要用到几个数据,
如果所有这些数据都存储在微处理器的寄存器中而非存储器中,执行程序将会更快,因为程序访问存储器的次数越少,那么它的运行速度也就越快。
8 0 8 8指令中,有一个至少 6 3个指令码供一条 8 0 8 0指令使用的指令,它就是 M O V指令,即
M o v e的简写。该条指令只有一个字节,用于把一个寄存器中的内容传送到另一个寄存器中
(或同一个寄存器中) 。使用大量 M O V指令是设计带有 7个寄存器(包括累加器)的微处理器的正常结果。
下面是前 3 2条 M O V指令。记住目的操作数在左边,源操作数在右边:
操作码 指令 操作码 指令
4 0 MOV B,B 5 0 MOV D,B
4 1 MOV B,C 5 1 MOV D,C
4 2 MOV B,D 5 2 MOV D,D
4 3 MOV B,E 5 3 MOV D,E
4 4 MOV B,H 5 4 MOV D,H
4 5 MOV B,L 5 5 MOV D,L
4 6 MOV B,[ H L ] 5 6 MOV D,[ H L ]
4 7 MOV B,A 5 7 MOV D,A
4 8 MOV C,B 5 8 MOV E,B
4 9 MOV C,C 5 9 MOV E,C
4 A MOV C,D 5 A MOV E,D
4 B MOV C,E 5 B MOV E,E
4 C MOV C,H 5 C MOV E,H
4 D MOV C,L 5 D MOV E,L
4 E MOV C,[ H L ] 5 E MOV E,[ H L ]
4 F MOV C,A 5 F MOV E,A
这些都是很方便的指令。当一个寄存器中有值时,可以把它传送到其他寄存器中。注意,
上述指令中有四条指令用到 H L寄存器对,如:
MOV B,[HL]
前面列出的 L D A指令把一个字节从存储器中传送到累加器中,这个字节的 1 6位地址直接跟在 L D A操作码的后面。这里的 M O V指令把一个字节从存储器中传送到寄存器 B中,但被装载到寄存器中的字节的地址是保存在寄存器对 H L中。 H L寄存器是怎样得到 1 6位存储器地址的呢?它可以通过多种方法来实现,或许是通过某种方法计算出来的。
第 19章 两种典型的微处理器 191下载总之,这两条指令
LDA A,[aaaa]
MOV B,[HL]
都把一个字节从存储器中装载到微处理器中,但它们用两种不同的方法来寻址存储器地址。第一种方法叫作直接寻址方式,第二种方法叫作间接寻址方式。
第二批 3 2条 M O V指令表明用 H L寻址的存储器地址也可以作为目的操作数:
操作码 指令 操作码 指令
6 0 MOV H,B 7 0 MOV [HL],B
6 1 MOV H,C 7 1 MOV [HL],C
6 2 MOV H,D 7 2 MOV [HL],D
6 3 MOV H,E 7 3 MOV [HL],E
6 4 MOV H,H 7 4 MOV [HL],H
6 5 MOV H,L 75 MOV [HL],L
6 6 MOV H,[ H L ] 7 6 H LT
6 7 MOV H,A 7 7 MOV [HL],A
6 8 MOV L,B 7 8 MOV A,B
6 9 MOV L,C 7 9 MOV A,C
6 A MOV L,D 7 A MOV A,D
6 B MOV L,E 7 B MOV A,E
6 C MOV L,H 7 C MOV A,H
6 D MOV L,L 7 D MOV A,L
6 E MOV L,[ H L ] 7 E MOV A,[ H L ]
6 F MOV L,A 7 F MOV A,A
其中一些指令如:
MOV A,A
做的是无用的事,而像:
MOV [HL],[HL]
这样的指令是不存在的。和这条指令相对应的操作码实际上是停止指令。
观察这些 M O V操作码更明显的方法是考察它的位模式,M O V操作码由 8位组成:
01dddsss
其中字母 ddd 代表指代目的操作数的 3位代码,s s s代表指代源操作数的 3位代码。这 3位代码是:
000= 寄存器 B
001= 寄存器 C
010= 寄存器 D
0 11= 寄存器 E
100= 寄存器 H
101= 寄存器 L
110= HL中保存的存储器地址中的内容
111= 累加器 A
例如,指令:
MOV L,E
相应的操作码表示为 0 11 0 1 0 11,或 6 B h。可以通过检查前面的表来验证。
192 编码的奥秘 下载第 19章 两种典型的微处理器 193下载因此可能在 8 0 8 0内部某个地方,标有 s s s的 3位标识用在 8 - 1数据选择器中,标有 d d d的 3位标识用于控制 3 - 8译码器,此译码器用来决定哪一个寄存器锁存了一个值。
也可能使用寄存器 B和 C来构成一个 1 6位寄存器对 B C,用寄存器 D和 E来构成一个 1 6位寄存器对 D E。如果每一个寄存器对都包含用于装载或保存一个字节的存储器地址,则可以使用下述指令:
操作码 指令 操作码 指令
0 2 S TAX [BC],A 0 A LDAX A,[ B C ]
1 2 S TAX [DE],A 1 A LDAX A,[ D E ]
另一种类型的传送指令叫做传送立即数,指定的助记符为 M V I。传送立即数指令占两个字节,第一个是操作码,第二个是 1个字节的数据。此字节从存储器中传送到一个寄存器中或由 H L寻址的存储单元中。
操作码 指令
06 MVI B,x x
0 E MVI C,x x
16 MVI D,x x
1 E MVI E,x x
26 MVI H,x x
2 E MVI L,x x
3 6 MVI [HL],x x
3 E MVI A,x x
例如,当指令:
MVI E,37h
执行后,寄存器 E中包含有字节 3 7 h。这就是第三种寻址方式,即立即数寻址方式。
3 2个操作码的集合完成四种基本算术运算,那是在第 1 7章开发处理器时我们就已熟悉的运算,即加法( A D D),进位加法( A D C),减法( S U B)和借位减法( S B B) 。所有情况中,
累加器是两个操作数之一,也是结果的目的地址。
操作码 指令 操作码 指令
8 0 ADD A,B 9 0 SUB A,B
8 1 ADD A,C 9 1 SUB A,C
8 2 ADD A,D 9 2 SUB A,D
8 3 ADD A,E 9 3 SUB A,E
8 4 ADD A,H 9 4 SUB A,H
8 5 ADD A,L 9 5 SUB A,L
8 6 ADD A,[ H L ] 9 6 SUB A,[ H L ]
8 7 ADD A,A 9 7 SUB A,A
8 8 ADC A,B 9 8 SBB A,B
8 9 ADC A,C 9 9 SBB A,C
8 A ADC A,D 9 A SBB A,D
8 B ADC A,E 9 B SBB A,E
8 C ADC A,H 9 C SBB A,H
8 D ADC A,L 9 D SBB A,L
8 E ADC A,[ H L ] 9 E SBB A,[ H L ]
8 F ADC A,A 9 F SBB A,A
194 编码的奥秘 下载假设 A中是 3 5 h,寄存器 B中是 2 2 h,当指令:
SUB A,B
执行后,累加器中的结果为 1 3 h。
若 A中的值为 3 5 h,寄存器 H中的值为 1 0 h,L中的值为 7 C h,存储器地址 1 0 7 C h中的值为 4 A
h,则指令:
ADD A,[HL]
把累加器中的内容( 3 5 h)和通过寄存器对 H L寻址得到的值( 4 A h)相加,并把结果
( 7 F h)保存到累加器中。
A D C和 S B B指令允许 8 0 8 0加 /减 1 6位,2 4位,3 2位和更多位的数。例如,假设寄存器对 B C
和 D E都包含 1 6位数,你想把它们相加,并把结果存到 B C中。下面是具体做法:
MOV A,C ;低位字节
ADD A,E
MOV C,A
MOV A,B ;高位字节
ADC A,D
MOV B,A
其中有两条加法指令,A D D指令用于低位字节相加,A D C指令用于高位字节相加。第一条加法指令的进位位包含在第二条加法指令中。因为只能利用累加器进行加法运算,所以在这么短的代码中也需要至少 4条 M O V指令。许多 M O V指令常常出现在 8 0 8 0代码中。
该是谈论 8 0 8 0标志位的时候了。在第 1 7章的处理器中,已有进位标志位 C F和零标志位 Z F。
8 0 8 0还有 3个标志位,即符号标志位 S F、奇偶标志位 P F和辅助进位标志位 A F。所有标志位都保存在另一个叫作程序状态字( P S W,program status word)的 8位寄存器中。像 L D A,S TA
和 M O V这样的指令不影响标志位,而 A D D,S U B,A D C和 S B B指令却要影响标志位,影响的方式如下:
当运算结果最高位为 1时,符号标志位 S F为 1,表示结果为负。
当结果为 0时,零标志位 Z F为 1。
当运算结果中,1”的个数为偶数时,奇偶标志位 P F = 1;当运算结果中,1”的个数为奇数时,奇偶标志位 P F = 0。 P F有时用来粗略地检测错误,此标志位在 8 0 8 0程序中不常用。
当 A D D或 A D C运算产生进位或 S U B与 S B B运算不发生借位时,进位标志位 C F = 1。 (这点不同于第 1 7章中的计算机进位标志的实现。 )
当操作结果的低 4位向高 4位有进位时,辅助进位标志位 A F = 1。此标志位只用在 D A A
(十进制调整累加器)指令中。
有两条指令直接影响进位标志位 C F:
操作码 指令 含义
3 7 S T C 置 C F为 1
3 F C M C C F取反第 1 7章中的计算机可执行 A D D,A D C,S U B和 S B B指令(尽管没什么灵活性),但 8 0 8 0还可以进行逻辑运算 A N D(与),O R(或)和 X O R(异或) 。算术运算和逻辑运算都可通过处理器的算术逻辑单元( A L U)来执行:
第 19章 两种典型的微处理器 195下载操作码 指令 操作码 指令
A 0 AND A,B B 0 OR A,B
A 1 AND A,C B 1 OR A,C
A 2 AND A,D B 2 OR A,D
A 3 AND A,E B 3 OR A,E
A 4 AND A,H B 4 OR A,H
A 5 AND A,L B 5 OR A,L
A 6 AND A,[ H L ] B 6 OR A,[ H L ]
A 7 AND A,A B 7 OR A,A
A 8 XOR A,B B 8 CMP A,B
A 9 XOR A,C B 9 CMP A,C
A A XOR A,D B A CMP A,D
A B XOR A,E B B CMP A,E
A C XOR A,H B C CMP A,H
A D XOR A,L B D CMP A,L
A E XOR A,[ H L ] B E CMP A,[ H L ]
A F XOR A,A B F CMP A,A
A N D,X O R和 O R指令按位运算,即逻辑操作只是单独地在对应位之间进行。例如:
MVI A,0Fh
MVI B,55h
AND A,Bh
累加器中的结果将为 0 5 h。如果第三条指令为 O R运算,则结果为 5 F h;如果第三条指令为
X O R运算,则结果为 5 A h。
C M P(比较)指令与 S U B指令基本上一样,除了结果不保存在累加器中。换句话说,
C M P执行减法操作再把结果扔掉。这是为什么?是因为标志位。根据标志位的状态可知道所比较的两数之间的关系。例如,当如下指令:
MVI B,25h
CMP A,B
执行完时,A中的内容没有改变。然而,若 A中的值为 2 5 h,则 Z F标志置位;若 A中的值小于 2 5 h,则 CF = 1。
这 8个算术逻辑运算也可以对立即数进行操作:
操作码 指令 操作码 指令
C 6 ADI A,x x E 6 ANI A,x x
C E ACI A,x x E E XRI A,x x
D 6 SUI A,x x F 6 ORI A,x x
D E SBI A,x x F E CPI A,x x
例如,上面列出的两条指令也可以用下面的指令来替换:
CPI A,25h
下面是其他两条 8 0 8 0指令:
操作码 指令
2 7 D A A
2 F C M A
C M A即 complement accumulator,它对累加器中的值进行取反操作。每个 0变为 1,每个 1
196 编码的奥秘 下载变为 0。如果累加器中的值为 0 11 0 0 1 0 1,C M A指令使它变为 1 0 0 11 0 1 0。也可以用下述指令来使累加器按位取反:
XRI A,FFh,
D A A即 Decimal Adjust Accumulator,如前所述,它可能是 8 0 8 0中最复杂的一条指令。微处理器中有一个完整的小部件专门用于执行这条指令。
D A A指令帮助程序员用 B C D码表示的数来进行十进制算术运算。在 B C D码中,每一小块数据的范围在 0 0 0 0? 1 0 0 1之间,对应于十进制的 0? 9。利用 B C D码格式,每 8位字节可存储两个十进制数字。
假设累加器中的值为 B C D码的 2 7 h。由于是 B C D码,则它实际上指的是十进制的 2 7。 (十六进制的 2 7 h等于十进制的 3 9。 )再假定寄存器 B中的值为 B C D码的 9 4 h。如果执行指令:
MOV A,27 h
MOV B,94 h
ADD A,B
累加器中的值将为 BB h,当然,它不是 B C D码,因为 B C D码中的每一块不能超过 9。但是,
现在执行指令:
DAA
则累加器中的值为 2 1 h,且 CF = 1,这是因为 2 7和 9 4的十进制和为 1 2 1。如果想进行 B C D
码的算术运算,这样做是相当方便的。
经常需要对一个数进行加 1或减 1操作。在第 1 7章的乘法程序中,我们需要对一个数减 1,
使用的方法是加上 FFh,它是 - 1的 2的补码。 8 0 8 0中包含特殊的用于寄存器或存储单元的加 1
指令(称作增量)和减 1指令(称作减量),
操作码 指令 操作码 指令
0 4 INR B 0 5 DCR B
0 C INR C 0 D DCR C
1 4 INR D 1 5 DCR D
1 C INR E 1 D DCR E
2 4 INR H 2 5 DCR H
2 C INR L 2 D DCR L
3 4 INR [HL] 3 5 DCR [HL]
3 C INR A 3 D DCR A
单字节指令 I N R和 D C R可影响除 C F外的所有标志位。
8 0 8 0也包含 4个循环移位指令,这些指令可使累加器中的内容左移或右移 1位:
操作码 指令 含义
0 7 R L C 累加器循环左移
0 F R R C 累加器循环右移
1 7 R A L 累加器带进位循环左移
1 F R A R 累加器带进位循环右移这些指令只影响 C F。
假定累加器中的值为 A 7 h,即二进制的 1 0 1 0 0 111。 R L C指令使 A中的内容向左移位,最高位(移出顶端)成为最低位(移进底端),同时决定进位标志位 C F的状态。其结果为 0 1 0 0 1111
且 CF = 1。 R R C指令用同样的方法向右移位。开始为 1 0 1 0 0 111,执行 R R C指令后,其结果为第 19章 两种典型的微处理器 197下载
11 0 1 0 0 11且 CF = 1。
R A L和 R A R指令有些不同。当向左移位时,R A L指令把 C F移入累加器的最低位,而把最高位移入 C F中。例如,如果累加器的内容为 1 0 1 0 0 111,CF = 0,R A L指令执行的结果是累加器的内容变为 0 1 0 0 111 0,且 CF = 1。同样,在相同的初始条件下,R A R指令使累加器的内容变为 0 1 0 1 0 0 11,CF = 1。
对于乘 2(左移 1位)和除 2(右移一位)操作,移位指令非常方便。
把微处理器寻址的存储器叫作随机访问存储器( R A M)是有原因的:微处理器可以简单地根据提供的地址访问某一存储位置。 R A M就像一本书一样,我们可以打开它的任何一页。
它并不像做在微缩胶片上的一个星期的报纸,要找到周六版,需扫过大半周。同样,它也不同于磁带,要播放磁带上的最后一首歌需快进整个一面。微缩胶片和磁带的存储不是随机访问的,而是顺序访问的。
R A M确实效果不错,对于微处理器来说更是如此。但在使用存储器时有所差别是有好处的,下面就是一种既非随机又非顺序访问的存储方式:假定你在一个办公室里,人们到你桌前给你分配工作,每个工作都需要某种文件夹。通常你会发现你在继续某项工作之前,必须使用另外一个文件夹先做一些相关的工作。因此你把第一个文件夹放在桌子上,又拿出第二个文件夹放在它上面进行工作。现在又有一个人来让你做一个优先权高于前面工作的工作,
你拿来一个新文件夹放在那两个上面继续工作。而此项工作又需要另外一个文件夹,这样在你的桌子上很快就摆了一堆文件夹了。
注意,这个堆非常明确地、有序地保存了你正在做的工作的轨迹。最上面的文件夹总是最高优先权的工作,去掉这个以后,下一个肯定是你就要做的,如此类推。当你最终去掉了桌子上的最后一个文件夹后(你开始的第 1项工作),你就可以回家了。
以这种方式工作的存储器技术叫做作堆栈( s t a c k) 。从底向上压入堆栈,从顶向下弹出堆栈,因此这也叫后进先出存储器,或 L I F O。最后放入堆栈中的数据最先被取出,最先放入堆栈中的数据最后被取出。
计算机中也可以使用堆栈,不是用来保存工作而是用来存储数据,且已被证明使用起来非常方便。向堆栈中放入数据叫作 p u s h(压入),从堆栈中取走数据叫作 p o p(弹出) 。
假定你正在用汇编语言设计程序,程序中使用了寄存器 A,B和 C。但在编程过程中,你发现此程序需要去做另一件事 — 一个小的计算,其中也要使用寄存器 A,,B,C。而你最终要回到先前的程序,并使用 A,B,C中原有的值。
当然,你能做的工作只是简单地把寄存器 A,B,C中的值保存到存储器中的不同位置,
以后再把这些位置的值装载到寄存器中,但这样做需要保存值被保存的位置。一个显然的方法是把寄存器压入堆栈:
PUSH A
PUSH B
PUSH C
一会儿再解释这些指令的作用。现在,我们只需要知道它们以某种方式把寄存器的内容保存在一个后进先出的存储器中。一旦这些语句执行了,你的程序就可以毫无顾虑地利用这些寄存器来做其他工作。为了得到原来的值,只需简单地按与压入堆栈相反的顺序把它们从堆栈中弹出即可,如下所示:
198 编码的奥秘 下载
POP C
POP B
POP A
记住是后进先出。如果用错了 P O P语句的顺序,就会引起错误。
堆栈机制的一个好处在于一个程序的不同部分都可以使用堆栈而不会出现问题。例如,
在把 A,B,C压入堆栈中后,程序的其他部分还可能需要把寄存器 C,D,E的内容压入堆栈:
PUSH C
PUSH D
PUSH E
接着,这一部分程序所要做的就是在第一部分弹出 C,B和 A之前,用下述方法恢复寄存器的值:
POP E
POP D
POP C
堆栈是怎样实现的呢?首先,堆栈只是不被别的东西使用的正常的 R A M的一部分。 8 0 8 0
微处理器包含一个特殊的 1 6位寄存器来对这一部分存储器进行寻址,这个 1 6位寄存器叫作堆栈指针。
这里举的压入和弹出寄存器的例子对于 8 0 8 0来说不太准确。 8 0 8 0的 P U S H指令实际上是存储 1 6位的值到堆栈,P O P指令用来恢复它们。因此 8 0 8 0不用像 PUSH C和 POP C这样的指令,
它有下述 8条指令:
操作码 指令 操作码 指令
C 5 PUSH BC C 1 POP BC
D 5 PUSH DE D 1 POP DE
E 5 PUSH HL E 1 POP HL
F 5 PUSH PSW F 1 POP PSW
PUSH BC指令把寄存器 B和 C的内容保存到堆栈中,POP BC指令恢复它们。最后一行的缩写 P S W指的是程序状态字,前面讲过,它是包含有标志位的 8位寄存器。最后一行的两条指令实际上是把累加器和 P S W都压入和弹出堆栈。如果你想保存所有寄存器和标志位的内容,
可以使用:
PUSH PSW
PUSH BC
PUSH DE
PUSH HL
当以后想恢复这些寄存器的内容时,按相反的顺序使用 P O P指令:
POP HL
POP DE
POP BC
POP PSW
堆栈是怎样工作的呢?假设堆栈指针为 8 0 0 0 h,PUSH BC指令将引起下面这些情况发生:
堆栈指针减 1至 7 F F F H
寄存器 B的内容保存在堆栈指针所指的地址处,即 7 F F F h处第 19章 两种典型的微处理器 199下载
堆栈指针减 1至 7 F F E H
寄存器 C的内容保存在堆栈指针所指的地址处,即 7 F F E h处当堆栈指针仍然为 7 F F E h时,POP BC指令执行,用来反向执行每一步:
从堆栈指针所指的地址(即 7 F F E h)处装载数据到寄存器 C中
堆栈指针增 1至 7 F F F h
从堆栈指针所指的地址(即 7 F F F h)处装载数据到寄存器 B中
堆栈指针增 1至 8 0 0 0 h
对每个 P U S H指令,堆栈都会增加 2个字节,这可能导致程序出现小毛病 — 堆栈可能会变得很大以致会覆盖掉程序所需的一些代码和数据。这就是堆栈上溢问题。同样,过多的
P O P指令会过早用光堆栈内容,这就是堆栈下溢问题。
如果 8 0 8 0同一个 6 4 K B的存储器连接,你可能想把初始堆栈指针置为 0 0 0 0 h。第一条 P U S H
指令使地址减 1变为 F F F F h,这时堆栈占用了存储器的最高地址。如果你的程序放在从 0 0 0 0 h
处开始的存储器区域,则它和堆栈离的就太远了。
对堆栈寄存器进行赋值的指令是 L X I,即 load extended immediate(装载扩展的立即数) 。
下面这些操作码后的指令也是把两个字节装载到 1 6位寄存器:
操作码 指令
0 1 LXI BC,x x x x
11 LXI DE,x x x x
2 1 LXI HL,x x x x
3 1 LXI SP,x x x x
指令:
LXI BC,527Ah
等价于
MVI B,52
MVI C,7A h
L X I指令保存一个字节。另外,上表中最后一条 L X I指令用来对堆栈指针赋值。微处理器复位后,这条指令并不常用来作为首先执行的指令之一:
0000 h,LXI SP,0000 h
也可以对寄存器对和堆栈指针执行加 1和减 1操作,就好像它们是 1 6位寄存器一样:
操作码 指令 操作码 指令
0 3 INX BC 0 B DCX BC
1 3 INX DE 1 B DCX DE
2 3 INX HL 2 B DCX HL
3 3 INX SP 3 B DCX SP
即然是在讨论 1 6位指令,可以看看更多一些这样的指令。下面的指令是把 1 6位寄存器对的内容加到寄存器对 H L中:
操作码 指令
0 9 DAD HL,B C
1 9 DAD HL,D E
2 9 DAD HL,H L
3 9 DAD HL,S P
200 编码的奥秘 下载上面这些指令可节约几个字节。例如,第一条指令正常需要 6个字节:
MOV A,L
ADD A,C
MOV L,A
MOV A,H
ADC A,B
MOV H,A
D A D指令通常用于计算存储器地址,这条指令只影响 C F。
下一步让我们看以下各种指令。下面的两个操作码后都紧跟着一个 2字节地址,分别保存和装载寄存器对 H L的内容:
操作码 指令 含义
2 h SHLD [aaaa],H L 直接保存 H L
2 A h LHLD HL,[ a a a a ] 直接装载 H L
寄存器 L的内容保存在地址 a a a a处,寄存器 H的内容保存在地址 a a a a + 1处。
下面两条指令用来从寄存器对 H L中装载程序计数器 P C或堆栈指针 S P:
操作码 指令 含义
E 9 h PCHL PC,H L 把 H L中的内容装载到 P C
F 9 h SPHL SP,H L 把 H L中的内容装载到 S P
P C H L指令实际上是一种转移指令,8 0 8 0执行的下一条指令保存在 H L寄存器对中的地址所对应的存储单元中。 S P H L是另外一个设置 S P的方法。
下面两条指令中,第一条指令使 H L的内容与堆栈中最上面的两个字节进行交换,第二条指令使 H L的内容与寄存器对 D E的内容进行交换:
操作码 指令 含义
E 3 h XTHL HL,[ S P ] H L与堆栈顶端的内容交换
E B h XCHG HL,D E DE 和 H L交换除了 P C H L外,还没有讲过 8 0 8 0的转移指令。前面第 1 7章中讲过,处理器中有一个叫作程序计数器 P C的寄存器,P C中包含处理器取回并执行的指令的存储器地址。通常 P C使处理器顺序执行存储器中的指令,但有些指令 — 通常命名为 J u m p(转移),B r a n c h(分支)或 g o t o
(跳转) — 能使处理器偏离这个固定的过程。这些指令使得 P C装载另外的值,处理器所取的下一条指令将在存储器的其他位置。
尽管简单、普通的转移指令很有用,但条件转移指令更有用。这些指令可使处理器根据某些标志,如 C F或 Z F,来转移到另外的地址处。条件转移指令的存在使得第 1 7章中的自动加法机成为一般意义上的数字计算机。
8 0 8 0有 5个标志位,其中 4个对条件转移指令有用处。 8 0 8 0支持 9种不同的转移指令,包括无条件转移指令和基于 Z F,C F,P F,S F是 1还是 0的条件转移指令。
在介绍这些指令之前,先介绍一下与此相关的另外两种指令。第一个是 C a l l(调用)指令。
C a l l指令与 J u m p指令的不同之处在于:前者把一个新值装入到程序计数器 P C中,处理器保存
P C中原来的地址,保存在哪里?当然,在堆栈中。
这种策略意味着 C a l l指令可有效地保存“程序从哪里跳转”的标记。处理器最终可利用此第 19章 两种典型的微处理器 201下载地址返回到原来的位置。这个返回指令叫 R e t u r n。 R e t u r n指令从堆栈中弹出两个字节,并把该值装载到 P C中。
C a l l和 R e t u r n指令是任何处理器中都很重要的功能。它们允许程序员编写子程序,子程序是程序中经常用到的代码段。 (,经常”一般意味着“不止一次” 。 )子程序是汇编语言中的基本组成部分。
让我们看一个例子。假设你正在编写一个汇编语言程序,并且需要使两个数相乘,因此你可以写出一段代码来做这项工作,然后继续往下编写程序,现在又需要使两个数相乘。因为你已知道如何进行两数相乘,因此你只需简单地重复使用同样的指令来完成它。但只是简单地两次把这些指令输入到存储器吗?希望不是,这是对时间和存储空间的浪费,更好的方法是转送到原来的代码处。由于无法返回到程序的当前位置,所以一般的 J u m p指令不能用。
但使用 C a l l和 R e t u r n指令可以让你完成所需的功能。
进行两数相乘的一组指令可以作为一个子程序。下面就是这样的子程序。在第 1 7章中,
被乘数(和结果)存放在存储器的某一地址中;而在 8 0 8 0子程序中,寄存器 B的值和寄存器 C
中的值相乘,然后把 1 6位乘积装入寄存器 H L中:
Multiply,PUSH PSW ;保存要改变的寄存器
PUSH BC
SUB H,H ;设置 HL(结果)为 0000h
SUB L,L
MOV A,B ;乘数送到 A
CPI A,00h ;如果为 0,结束
JZ AllDone
MVI B,00h ; BC的高字节置 0
Multloop,DAD HL,BC ; BC 加到 HL
DEC A ;乘数减 1
JNZ Multloop ;不为 0,转移
AllDone,POP BC ;恢复保存的寄存器
POP PSW
RET ;返回注意,上述子程序的第 1行开始有一个标号 M u l t i p l y。当然,这个标号对应于子程序所在的存储器地址。子程序开始用了两个 P U S H指令,通常在子程序开始处应先保存(以后恢复)
它需要使用的寄存器。
然后该子程序把 H和 L寄存器置为 0。虽然可以使用 M V I指令而不用 S U B指令,但那需要使用 4个字节的指令而不是 2个字节的指令。子程序执行完后,寄存器对 H L中保存有相乘的结果。
下一步该子程序把寄存器 B的内容(乘数)移入 A中,并且检查它是否为 0。如果它为 0,
乘法子程序到此结束,因为结果为 0。由于寄存器 H和 L已经为 0,因而子程序可以只使用 J Z指令跳转到末端的两个 P O P指令处。
否则,子程序把寄存器 B置为 0。现在,寄存器对 B C中包含一个 1 6位的被乘数,A中为乘数。 D A D指令把 B C(被乘数)加到 H L(结果)中。 A中的乘数减 1,且只要它不为 0,J N Z指令就又使 B C加到 H L中。此小循环继续下去,直到 B C加到 H L中的次数等于乘数。 (可以用
8 0 8 0的移位指令编写一个更有效的乘法子程序。 )
202 编码的奥秘 下载利用这个子程序完成 2 5 h与 1 2 h相乘的程序用下面的代码:
MOV B,25h
MOV C,12h
CALL Multiply
C a l l指令把 P C的值保存在堆栈中,该值是 C a l l指令的下一条指令的地址。然后,C a l l指令使程序转移到标号 M u l t i p l y所标识的指令,即子程序的开始。当子程序计算完结果后,执行
R E T(返回)指令,即从堆栈中弹出程序计数器的值,程序继续执行 C a l l指令后面的语句。
8 0 8 0指令集中包括条件 C A L L指令和条件 R e t u r n指令,但它们远不如条件转移指令用得多。
下表中完整地列出了这些指令:
你可能知道,存储器并不是唯一连接在微处理器上的设备。一个计算机系统通常需要输入输出设备以便于实现人机通信。输入输出设备通常包括键盘和显示器。
微处理器是怎样与外围设备 (对于连接到微处理器而不是存储器的东西的称呼 )进行通信的呢?外围设备具有与存储器相似的接口,微处理器可通过对应于外设的具体地址来对外设进行读写。在有些微处理器中,外围设备实际上占用了通常用来寻址存储器的地址,这种配置叫作 内存映像 I / O。然而在 8 0 8 0中,在 65 536个正常地址外还有 2 5 6个附加地址专门为输入输出设备预留,这些就是 I / O端口 ( I/O Port) 。 I / O地址信号为 A0? A7,但 I / O访问与存储器访问不同,由 8 2 2 8系统控制芯片锁存的信号来区分。
O U T指令用于把累加器中的数据写到紧跟该指令的字节所寻址的 I / O端口中。 I N指令把端口的数据读入到累加器中。
操作码 指令
D 3 OUT PP
D B IN PP
外围设备有时需要引起微处理器的注意。例如,当你在键盘上按键时,如果微处理器能马上知道这件事通常是有帮助的。这由称作 中断 ( i n t e r r u p t)的机制来完成,这是连接至条件 操作码 操作码操作码 指令 指令 指令
8 0 8 0 I N T输入端的,由外设产生的信号。
然而,当 8 0 8 0复位时,它不能对中断产生响应。程序必须通过执行 E I( Enable interrupts)
指令来允许中断,通过执行 D I( Disable Interrupts)指令来禁止中断。
操作码 指令
F 3 D I
F B E I
8 0 8 0的 I N T E输出端信号表明允许中断。当外设需要中断微处理器当前工作时,它把 8 0 8 0
的 I N T输入端设置为 1。 8 0 8 0通过从存储器中取出指令对它作出响应,但控制信号表明有中断发生。外设通常通过提供下述指令之一来响应 8 0 8 0:
操作码 指令 操作码 指令
C 7 RST 0 E 7 RST 4
C F RST 1 E F RST 5
C 7 RST 2 E 7 RST 6
D F RST 3 F F RST 7
以上称作 R e s t a r t指令,它们与 C A L L指令相似,也需要把当前程序计数器的值压入堆栈。
但 R e s t a r t指令随后转移到一个特定的位置,RST 0转移到地址 0000h 处,RST 1转移到地址
0 0 0 8 h处等等,直到 RST 7转移到地址 0 0 3 8 h处。位于这些地址中的代码段来处理中断。例如,
来自键盘的中断引起 RST 4指令执行,地址 0 0 2 0 h处的一些代码从键盘读取数据(这将在第 2 1
章做全面介绍) 。
到此为止,已讲述了 2 4 3个操作码。下述 1 2个字节与任何操作码无关,0 8 h,1 0 h,1 8 h、
2 0 h,2 8 h,3 0 h,3 8 h,C B h,D 9 h,D D h,E D h和 F D h。这样总共有 2 5 5个操作码。下面还要提到一个操作码:
操作码 指令
0 0 N O P
N O P代表 no op,即 no operation (无操作) 。 N O P指令使微处理器什么都不做。这有什么作用吗?用于填空。 8 0 8 0通常可以执行一批 N O P指令而不会有任何坏情况发生。
以下不打算再详细讨论 Motorola 6800,因为它的设计与功能与 8 0 8 0非常相似。下面是
6 8 0 0的 4 0个管脚:
第 19章 两种典型的微处理器 203下载
VS S代表接地,VC C是 5 V电源。与 8 0 8 0相似,6 8 0 0有 1 6个地址输出信号和既可作为输入又可作为输出的 8个数据信号。它有 R E S E T信号和 R /- W信号。 - I R Q信号代表 中断请求 。 6 8 0 0的时钟信号比 8 0 8 0的更加简单。 6 8 0 0没有 I / O端口的概念,所有输入输出设备都必须是 6 8 0 0存储器地址空间的一部分。
6 8 0 0有一个 1 6位程序计数器 P C、一个 1 6位堆栈指针 S P、一个 8位状态寄存器(作为标志)
以及两个 8位累加器 A和 B。它们都被看成是累加器( B不是只作为一个寄存器)是因为没有能用 A来做而不能用 B来做的事。 6 8 0 0没有附加的 8位寄存器。
6 8 0 0中有一个 1 6位索引寄存器( index register),可用来保存一个 1 6位地址,很像 8 0 8 0中的寄存器对 H L。对于许多指令来说,它们的地址都可以由索引寄存器和紧跟在操作码后的地址之和得到。
虽然 6 8 0 0和 8 0 8 0所实现的操作相同 — 装载、保存、加法、减法、移位、转移、调用,
但很明显的区别是:它们的操作码和助记符完全不同。例如,下面是 6 8 0 0的分支转移指令:
操作码 指令 含义
2 0 h B R A 转移
2 2 h B H I 大于则转移
2 3 h B L S 小于或相同则转移
2 4 h B C C 进位为 0则转移
2 5 h B C S 进位置 1则转移
2 6 h B N E 不等则转移
2 7 h B E Q 相等则转移
2 8 h B V C 溢出为 0则转移
2 9 h B V S 溢出置 1则转移
2 A h B P L 为正则转移
2 B h B M I 为负则转移
2 C h B G E 大于或等于 0则转移
2 D h B LT 小于 0则转移
2 E h B G T 大于 0则转移
2 F h B L E 小于或等于 0则转移
6 8 0 0没有像 8 0 8 0中那样的奇偶标志位 P F,但它有一个 8 0 8 0中没有的标志位 — 溢出标志位( overflow flag) 。上述转移指令中有些依赖于标志位的组合。
当然 8 0 8 0和 6 8 0 0指令集是不同的,这两个芯片是同一时间由不同的两个公司的两组不同的工程师设计的。这种不兼容性意味着每一种芯片不能执行对方的机器代码,为一种芯片开发的汇编语言程序也不能翻译成可在另一种芯片上执行的操作码。编写可在多于一种处理器上执行的计算机程序是第 2 4章的主题。
8 0 8 0和 6 8 0 0还有一个有趣的不同点:在两种微处理器中,L D A指令都是从一个特定的地址处装载到累加器。例如,在 8 0 8 0中,下列字节序列:
204 编码的奥秘 下载
8080LDA指令将把存储在地址 3 4 7 B h处的字节装载到累加器。现在把上述指令与 6 8 0 0的 L D A指令相比较,后者采用称作 6 8 0 0的扩展地址模式:
该字节序列把存储在地址 7B34h 处的字节装载到累加器 A中。
这种不同点是很微妙的。当然,你也可能认为它们的操作码不同:对 8 0 8 0来说是 3 A h,对
6 8 0 0来说是 B 6 h。但主要是这两种微处理器处理紧随操作码后的地址是不同的,8 0 8 0认为低位在前,高位在后; 6 8 0 0则认为高位在前,低位在后。
这种 I n t e l和 M o t o r o l a微处理器保存多字节数时的根本不同从没有得到解决。直到现在,
I n t e l微处理器在保存多字节数时,仍是最低有效字节在前(即在最低存储地址处);而
M o t o r o l a微处理器在保存多字节数时,仍是最高有效字节在前。
这两种方法分别叫作 l i t t l e - e n d i a n ( I n t e l方式 )和 big-endian (Motorola方式 )。辩论这两种方式的优劣可能是很有趣的,不过在此之前,要知道术语 b i g - e n d i a n来自于 Jonathan Swift的
,G u l l i v e r’s Tr a v e l s》,指的是 Lilliput 和 B l e f u s c u在每次吃鸡蛋前都要互相碰一下。这种辩论可能是无目的的。先不说哪种方法在本质上说是不是正确的,但这种差别的确当在基于 l i t t l e -
endian 和 b i g - e n d i a n机器的系统之间共享信息时会带来附加的兼容性问题。
这两种微处理器后来怎样了呢? 8 0 8 0用在一些人所谓的第一台个人计算机上,不过可能更准确的说法是第一台家用计算机上。下图是 Altair 8800,出现在 1 9 7 5年 1月份的,P o p u l a r
E l e c t r o n i c s》杂志的封面上。
当你看到 Altair 8800时,前面面板上的灯泡和开关看起来似乎很熟悉。这和第 1 6章为
64KB RAM阵列建议的初始“控制面板”的界面是同一类型的。
8 0 8 0之后出现了 Intel 8085,更具意义的是出现了 Z i l o g制造的 Z - 8 0芯片。 Z i l o g是 Intel 公司的竞争对手,是由 I n t e l公司的前雇员,也曾在 4 0 0 4芯片上做出重要贡献的 Federico Faggin
第 19章 两种典型的微处理器 205下载
6800LDA指令建立的。 Z - 8 0与 8 0 8 0完全兼容,且增加了许多很有用的指令。 1 9 7 7年,Z - 8 0用于 Radio Shack
TRS-80 Model1上。
也是在 1 9 7 7年,由 Steven Jobs 和 Stephen Wo z n i a k建立的苹果计算机公司推出了 APPLE II。
APPLE II 既不用 8 0 8 0也不用 6 8 0 0,而是使用了采用 M O S技术的更便宜的 6 5 0 2芯片,它是对
6 8 0 0的增强。
1 9 7 8年 6月,I n t e l公司推出了 8 0 8 6,一个 1 6位微处理器,它可访问的存储空间达到 1 M B。
8 0 8 6的操作码与 8 0 8 0不兼容,但它包含乘法和除法指令。一年后,I n t e l公司又推出了 8 0 8 8,
其内部结构与 8 0 8 6相同,但其外部按字节访问存储器,因此该微处理器可使用较流行的为
8 0 8 0设计的 8位支持芯片。 I B M在其 5 1 5 0个人计算机 — 通常叫作 IBM PC— 上使用了 8 0 8 8芯片,这种个人计算机在 1 9 8 1年秋季推出。
I B M进军 P C市场产生了巨大影响,许多公司都发布了与 P C兼容的机器(兼容的含义在随后各章里将要详细讨论) 。多年来,,IBM PC兼容机”也暗指,Intel inside”,特指所谓 x 8 6家族的 I n t e l微处理器。 Intel x86家族继续发展,1 9 8 5年出现了 3 2位的 3 8 6芯片,1 9 8 9年出现了 4 8 6
芯片。 1 9 9 3年初,出现了 Intel Pentium微处理器,普遍地用在 P C兼容机上。虽然这些 I n t e l微处理器都不断增加了指令的指令集,但它们仍然支持从 8 0 8 6开始的所有以前处理器的操作码。
苹果公司的 Macintosh 首次发布于 1 9 8 4年,它使用了 Motorola 68000— 一个 1 6位的微处理器,也即 6 8 0 0的下一代处理器。 6 8 0 0 0和它的后代(常称为 6 8 K系列)是制造出的最受欢迎的一类微处理器。
从 1 9 9 4年开始,M a c i n t o s h计算机开始使用 Power PC,一种由 M o t o r o l a,I B M和 A p p l e公司联合开发的微处理器。 P o w e r P C是由一种称作 R I S C(精简指令集计算机)的微处理器体系结构来设计的,它试图通过简化某些方面以提高处理器的速度。在 R I S C计算机中,每条指令通常长度相同,(在 P o w e r P C中为 3 2位),存储器访问只限于装载和保存指令,且指令做简单操作而不是复杂操作。 RISC 处理器通常有大量的寄存器以避免频繁访问存储器。
因为 P o w e r P C具有完全不同的指令集,所以它不能执行 6 8 K的代码。但现在用于 A P P L E
M a c i n t o s h的 PowerPC 微处理器可仿真 6 8 K。运行于 PowerPC 上的仿真程序逐个检验 6 8 K程序的每一个操作码,并执行适当的操作。仿真程序不如 P o w e r P C自身代码那样快,但可以工作。
按照摩尔定律,微处理器中的晶体管数量应该每 1 8个月翻一番。这些多增加的晶体管有什么用处呢?
有些晶体管用于增加处理器的数据宽度,从 4位到 8位到 1 6位再到 3 2位;另外一些增加的晶体管用于处理新的指令。现在大多数微处理器都有用于浮点算术运算的指令(这将在第 2 3章解释);还有一些新增加的指令用来进行一些重复计算,以便在计算机屏幕上显示图片和电影。
现代处理器使用了一些技术用来提高速度,其中之一是流水线技术,处理器在执行一条指令的同时读取下一条指令。由于转移指令会改变执行流程,实际上这样达不到预期效果。
现在的处理器还包含一个 Cache( 高速缓冲存储器 ),它是做在处理器内部的快速 R A M阵列,
用于保存最近执行的指令。因为计算机程序经常执行一些小的指令循环,因而 C a c h e可以避免这些指令重复装载。所有这些速度提升措施都需要在处理器中有更多的逻辑器件和晶体管。
如前所述,微处理器只是完整的计算机系统的一部分(尽管是最重要的部分) 。我们将在第 2 1章构造这样一个系统,但首先必须学习怎样编码存在存储器中的除了操作码和数字外的其他东西。我们必须返回到小学一年级,再学习一下怎样读写文本。
206 编码的奥秘 下载下载
年。它的产生有一个很好的开端:第一个微处理器是 Intel 4004,其中有 2 3 0 0个晶体管。今天,
差不多 3 0年过去了,为家用计算机所制造的微处理器中将近有 10 000 000个晶体管。
微处理器实际的作用基本上保持不变。现在的芯片上附加的上百万个晶体管可以做许多有趣的事情,但在微处理器最初的探索过程中,这些事情更多的是分散我们的注意力而不是给我们以启迪。为了对微处理器的工作情况获得更清晰的认识,让我们先看一下最初的微处理器。
这些微处理器出现在 1 9 7 4年。在该年度,I n t e l公司在 4月推出了 8 0 8 0,M o t o r o l a(摩托罗拉) — 从 2 0世纪 5 0年代开始生产半导体和晶体管产品的公司 — 在 8月份推出了 6 8 0 0。它们并非是那年仅有的微处理器。同样是在 1 9 7 4年,德克萨斯仪器公司推出了 4位的 TMS 1000,用在许多计算器、玩具和设备上; National Semiconductor(国家半导体公司)推出了 PA C E,它是第一个 1 6位的微处理器。然而,回想起来,8 0 8 0和 6 8 0 0是两个最具有重大历史意义的芯片。
I n t e l设定 8 0 8 0最初价格为 $ 360,这是对 IBM System/360的一个讽刺。 IBM System/360是一个大型机系统,由许多大公司使用,要花费几百万美元。 (今天,你只花 $ 1,9 5就可以买到一个 8 0 8 0芯片。 )这并不是说 8 0 8 0可以与 S y s t e m / 3 6 0相提并论,但不用几年,I B M公司也将会正视这些很小的计算机。
8 0 8 0是一个 8位的微处理器,有 6 0 0 0个晶体管,时钟频率为 2 M H z,可寻址 6 4 K B的存储空间。 6 8 0 0(今天也只卖 $ 1,9 5)有大约 4 0 0 0个晶体管,也可寻址 6 4 K B的存储空间。第 1代 6 8 0 0
的时钟频率为 1 MHz,但到 1 9 7 7年 M o t o r o l a公司发布新款的 6 8 0 0时,其时钟频率已为 1,5 M H z
和 2 MHz。
这些芯片称作“单芯片微处理器”,不太准确的名称为“一个芯片上的计算机” 。处理器只是整个计算机的一部分。此外,计算机至少还需要一些随机访问存储器( R A M),供人们输入信息到计算机的方法(输入设备),供人们从计算机获取信息的方法(输出设备),以及其他可把所有这些东西连接在一起的芯片。这些组件将在第 2 1章详细介绍。
从现在起,我们只考察微处理器。描述微处理器时,通常是用框图来画微处理器的内部组件及它们是如何连接的。但在第 1 7章已有够多的图了,现在,我们将通过观察处理器与外界的相互作用来了解它的内部 。换句话说,为了弄清楚它的作用,可以把微处理器看成是一个黑盒子,它的内部操作不需要做详细研究。我们可以通过测试芯片的输入和输出信号,特别是芯片的指令集来掌握微处理器的功能。
8 0 8 0和 6 8 0 0都是 4 0管脚的集成电路。这些芯片最普通的 I C封装大约是 2英寸长,半英寸宽,
1 / 8英寸厚:
第 19章 两种典型的微处理器 189下载当然,你看到的只是外包装。位于其内部的硅晶片非常小,就拿早期的 8位微处理器来说,
其硅晶片小于 1 / 4平方英寸。外包装保护硅晶片并通过管脚提供对芯片的输入和输出点的访问。
下图显示了 8 0 8 0的 4 0个管脚的功能:
本书的所有电气或电子设备都需要某种电源供电。 8 0 8 0的一个特别之处在于它需要三种电源电压:管脚 2 0必须连到 5伏电源上,管脚 11连到 - 5伏电源上,管脚 2 8连到 1 2伏电源上;管脚 2接地( 1 9 7 6年,I n t e l发布了 8 0 8 5芯片,简化了这些电源需求) 。
其余管脚都画有箭头。从芯片中出来的箭头表示输出信号,这是由微处理器控制的信号,
计算机中其余芯片对此作出响应。指向芯片的箭头表示输入信号,这是来自于其他芯片的信号,8 0 8 0对它们做出响应。有些管脚既是输入又是输出。
第 1 7章的处理器需要振荡器使它工作。 8 0 8 0需要两个不同的 2 MHz同步时钟输入,在 2 2
和 1 5管脚上分别标记为?1和?2。这些信号可以很方便地由 I n t e l公司生产的 8 2 2 4时钟信号发生器提供。给这个芯片连上一个 18 MHz的石英晶体,剩下的工作它基本上可以完成。
一个微处理器通常有多个输出信号来寻址存储空间,这种信号的数目与微处理器可寻址的存储器空间的大小直接相关。 8 0 8 0有 1 6个地址信号,标为 A 0? A 1 5,具有寻址 21 6即 65 536
字节的存储空间的能力。
8 0 8 0是一个 8位微处理器,一次可从存储器中读出、写入 8位数据。它包括 8个数据信号
D0~ D7,这些信号是在此芯片中仅有的几个既作为输入又作为输出的信号。当微处理器从存储器读数据时,这些管脚作为输入;当微处理器向存储器写数据时,这些管脚作为输出。
微处理器的另外 1 0个管脚是控制信号。例如,R E S E T输入用来复位微处理器。输出信号-
W R 表示微处理器要向 R A M中写数据。 ( -W R信号对应于 R A M阵列的写入输入。 )另外,当芯片读取指令时,其他控制信号会在某个时候出现在 D0~ D7管脚。由 8 0 8 0构成的计算机系统通常使用 8 2 2 8系统控制芯片来锁存这些附加的控制信号。后面将会讲述一些控制信号。由于 8 0 8 0
的控制信号非常复杂,因此,除非你想基于 8 0 8 0芯片来实际设计计算机,否则最好不要用这些控制信号来折磨自己。
190 编码的奥秘 下载假定 8 0 8 0微处理器连接了 6 4 K B的存储器,这样可以不通过微处理器来读写数据。
8 0 8 0芯片复位后,它从存储器的地址 0 0 0 0 h处读取该字节,送到微处理器中。这可以通过在地址信号端 A0? A1 5输出 1 6个 0来实现。它读取的字节必须是 8 0 8 0指令,这种读取字节的过程叫作取指令。
在第 1 7章构造的计算机里,所有指令(除了停止指令 H LT)都是 3个字节长,包括一个操作码和两个字节的地址。在 8 0 8 0中,指令长度可以是 1个字节,2个字节或 3个字节。有些指令可使 8 0 8 0从存储器的某一位置处读出一个字节送到微处理器中;有些指令可使 8 0 8 0从微处理器中把数据写入存储器的某一位置处;其他指令可使 8 0 8 0不使用 R A M而在内部执行。第一条指令执行完后,8 0 8 0访问存储器中的第二条指令,依此类推。这些指令组合在一起构成一个计算机程序,用来完成一些自己感兴趣的事情。
当 8 0 8 0运行在最高速度即 2 MHz时,每个时钟周期为 5 0 0纳秒( 1除以 2 000 000周等于
0,0 0 0 0 0 0 5 0 0秒) 。第 1 7章中的每条指令都需要 4个时钟周期,8 0 8 0的每条指令则需要 4? 1 8个时钟周期,这意味着每条指令的执行时间为 2? 9微秒(即百万分之一秒) 。
了解微处理器功能的最好方法可能是在系统方式下测试其完整的指令集。
第 1 7章最后出现的计算机仅有 1 2条指令。一个 8位微处理器很容易就有 2 5 6条指令,每个操作码对应于某个 8位值。 (如果一些指令有 2个字节的操作码,则实际会有更多的指令) 。 8 0 8 0虽没有那么多,但它也有 2 4 4条操作码。这看起来似乎很多,但总的来说,却又不比第 1 7章中的计算机功能多多少。例如,如果想用 8 0 8 0做乘法或除法,仍然需要写一段小程序来实现。
第 1 7章中讲过,处理器指令集的每个操作码都和某个助记符相联系,有些助记符之后可能还有操作数。但这些助记符仅用来方便地表示操作码。处理器只读取字节,它并不懂组成这些助记符的字符的含义。
第 1 7章中的计算机有两条很重要的指令,称作装载( L o a d)和保存( S t o r e)指令。这些指令都占用三个字节的存储空间。装载指令的第一个字节是操作码,操作码后的两个字节表示 1 6位地址。处理器把在此地址中的字节送到累加器。同样,保存指令把累加器中的内容存储到指令指定的地址处。
下面,我们用助记符来简写这两个操作:
LOD A,[aaaa]
STO [aaaa],A
在此,A表示累加器(装载指令的目的操作数,保存指令的源操作数),a a a a表示一个 1 6
位的存储器地址,通常用 4位十六进制数来表示。
8 0 8 0中的 8位累加器称作 A,就像第 1 7章中的累加器。正如第 1 7章中的计算机一样,8 0 8 0
也有两条与装载和保存指令功能一样的指令。 8 0 8 0中这两条指令的操作码为 3 2 h和 3 A h,每个操作码后有一个 1 6位地址。 8 0 8 0的助记符为 S TA(代表存储累加器的内容)和 L D A(代表装载到累加器),
操作码 指令
3 2 S TA [aaaa],A
3 A LDA A,[aaaa]
除了累加器,8 0 8 0微处理器内部还包括 6个寄存器( r e g i s t e r),每个寄存器可以保存 8位的值。这些寄存器和累加器非常相似,事实上,累加器被看作是一种特殊的寄存器。和累加器一样,这 6个寄存器也是锁存器。处理器可以把数据从存储器传送到寄存器,也可以把数据从寄存器送回到存储器。然而,这些寄存器没有累加器的功能强大。例如,当两数相加时,其结果通常送往累加器而非其中一个寄存器。
在 8 0 8 0中,除累加器外的 6个寄存器的名字分别为 B,C,D,E,H和 L。人们通常问的第一个问题是“用 F和 G干什么?”,第二个问题是“用 I,J和 K又要做什么?”,答案是使用寄存器 H和 L具有某种特殊的含义。 H代表高( H i g h),L代表低 ( L o w )。通常把 H和 L的 8位合起来记作 H L来表示一个 1 6位寄存器对,H作为高位字节,L作为低位字节。这个 1 6位值通常用来寻址存储器。后面我们将看到它的简单用法。
所有这些寄存器都是必需的吗?为什么不在第 1 7章中的计算机中用到它们呢?从理论上说,它们并非必需,但是使用它们会很方便。许多计算机程序在同一时刻要用到几个数据,
如果所有这些数据都存储在微处理器的寄存器中而非存储器中,执行程序将会更快,因为程序访问存储器的次数越少,那么它的运行速度也就越快。
8 0 8 8指令中,有一个至少 6 3个指令码供一条 8 0 8 0指令使用的指令,它就是 M O V指令,即
M o v e的简写。该条指令只有一个字节,用于把一个寄存器中的内容传送到另一个寄存器中
(或同一个寄存器中) 。使用大量 M O V指令是设计带有 7个寄存器(包括累加器)的微处理器的正常结果。
下面是前 3 2条 M O V指令。记住目的操作数在左边,源操作数在右边:
操作码 指令 操作码 指令
4 0 MOV B,B 5 0 MOV D,B
4 1 MOV B,C 5 1 MOV D,C
4 2 MOV B,D 5 2 MOV D,D
4 3 MOV B,E 5 3 MOV D,E
4 4 MOV B,H 5 4 MOV D,H
4 5 MOV B,L 5 5 MOV D,L
4 6 MOV B,[ H L ] 5 6 MOV D,[ H L ]
4 7 MOV B,A 5 7 MOV D,A
4 8 MOV C,B 5 8 MOV E,B
4 9 MOV C,C 5 9 MOV E,C
4 A MOV C,D 5 A MOV E,D
4 B MOV C,E 5 B MOV E,E
4 C MOV C,H 5 C MOV E,H
4 D MOV C,L 5 D MOV E,L
4 E MOV C,[ H L ] 5 E MOV E,[ H L ]
4 F MOV C,A 5 F MOV E,A
这些都是很方便的指令。当一个寄存器中有值时,可以把它传送到其他寄存器中。注意,
上述指令中有四条指令用到 H L寄存器对,如:
MOV B,[HL]
前面列出的 L D A指令把一个字节从存储器中传送到累加器中,这个字节的 1 6位地址直接跟在 L D A操作码的后面。这里的 M O V指令把一个字节从存储器中传送到寄存器 B中,但被装载到寄存器中的字节的地址是保存在寄存器对 H L中。 H L寄存器是怎样得到 1 6位存储器地址的呢?它可以通过多种方法来实现,或许是通过某种方法计算出来的。
第 19章 两种典型的微处理器 191下载总之,这两条指令
LDA A,[aaaa]
MOV B,[HL]
都把一个字节从存储器中装载到微处理器中,但它们用两种不同的方法来寻址存储器地址。第一种方法叫作直接寻址方式,第二种方法叫作间接寻址方式。
第二批 3 2条 M O V指令表明用 H L寻址的存储器地址也可以作为目的操作数:
操作码 指令 操作码 指令
6 0 MOV H,B 7 0 MOV [HL],B
6 1 MOV H,C 7 1 MOV [HL],C
6 2 MOV H,D 7 2 MOV [HL],D
6 3 MOV H,E 7 3 MOV [HL],E
6 4 MOV H,H 7 4 MOV [HL],H
6 5 MOV H,L 75 MOV [HL],L
6 6 MOV H,[ H L ] 7 6 H LT
6 7 MOV H,A 7 7 MOV [HL],A
6 8 MOV L,B 7 8 MOV A,B
6 9 MOV L,C 7 9 MOV A,C
6 A MOV L,D 7 A MOV A,D
6 B MOV L,E 7 B MOV A,E
6 C MOV L,H 7 C MOV A,H
6 D MOV L,L 7 D MOV A,L
6 E MOV L,[ H L ] 7 E MOV A,[ H L ]
6 F MOV L,A 7 F MOV A,A
其中一些指令如:
MOV A,A
做的是无用的事,而像:
MOV [HL],[HL]
这样的指令是不存在的。和这条指令相对应的操作码实际上是停止指令。
观察这些 M O V操作码更明显的方法是考察它的位模式,M O V操作码由 8位组成:
01dddsss
其中字母 ddd 代表指代目的操作数的 3位代码,s s s代表指代源操作数的 3位代码。这 3位代码是:
000= 寄存器 B
001= 寄存器 C
010= 寄存器 D
0 11= 寄存器 E
100= 寄存器 H
101= 寄存器 L
110= HL中保存的存储器地址中的内容
111= 累加器 A
例如,指令:
MOV L,E
相应的操作码表示为 0 11 0 1 0 11,或 6 B h。可以通过检查前面的表来验证。
192 编码的奥秘 下载第 19章 两种典型的微处理器 193下载因此可能在 8 0 8 0内部某个地方,标有 s s s的 3位标识用在 8 - 1数据选择器中,标有 d d d的 3位标识用于控制 3 - 8译码器,此译码器用来决定哪一个寄存器锁存了一个值。
也可能使用寄存器 B和 C来构成一个 1 6位寄存器对 B C,用寄存器 D和 E来构成一个 1 6位寄存器对 D E。如果每一个寄存器对都包含用于装载或保存一个字节的存储器地址,则可以使用下述指令:
操作码 指令 操作码 指令
0 2 S TAX [BC],A 0 A LDAX A,[ B C ]
1 2 S TAX [DE],A 1 A LDAX A,[ D E ]
另一种类型的传送指令叫做传送立即数,指定的助记符为 M V I。传送立即数指令占两个字节,第一个是操作码,第二个是 1个字节的数据。此字节从存储器中传送到一个寄存器中或由 H L寻址的存储单元中。
操作码 指令
06 MVI B,x x
0 E MVI C,x x
16 MVI D,x x
1 E MVI E,x x
26 MVI H,x x
2 E MVI L,x x
3 6 MVI [HL],x x
3 E MVI A,x x
例如,当指令:
MVI E,37h
执行后,寄存器 E中包含有字节 3 7 h。这就是第三种寻址方式,即立即数寻址方式。
3 2个操作码的集合完成四种基本算术运算,那是在第 1 7章开发处理器时我们就已熟悉的运算,即加法( A D D),进位加法( A D C),减法( S U B)和借位减法( S B B) 。所有情况中,
累加器是两个操作数之一,也是结果的目的地址。
操作码 指令 操作码 指令
8 0 ADD A,B 9 0 SUB A,B
8 1 ADD A,C 9 1 SUB A,C
8 2 ADD A,D 9 2 SUB A,D
8 3 ADD A,E 9 3 SUB A,E
8 4 ADD A,H 9 4 SUB A,H
8 5 ADD A,L 9 5 SUB A,L
8 6 ADD A,[ H L ] 9 6 SUB A,[ H L ]
8 7 ADD A,A 9 7 SUB A,A
8 8 ADC A,B 9 8 SBB A,B
8 9 ADC A,C 9 9 SBB A,C
8 A ADC A,D 9 A SBB A,D
8 B ADC A,E 9 B SBB A,E
8 C ADC A,H 9 C SBB A,H
8 D ADC A,L 9 D SBB A,L
8 E ADC A,[ H L ] 9 E SBB A,[ H L ]
8 F ADC A,A 9 F SBB A,A
194 编码的奥秘 下载假设 A中是 3 5 h,寄存器 B中是 2 2 h,当指令:
SUB A,B
执行后,累加器中的结果为 1 3 h。
若 A中的值为 3 5 h,寄存器 H中的值为 1 0 h,L中的值为 7 C h,存储器地址 1 0 7 C h中的值为 4 A
h,则指令:
ADD A,[HL]
把累加器中的内容( 3 5 h)和通过寄存器对 H L寻址得到的值( 4 A h)相加,并把结果
( 7 F h)保存到累加器中。
A D C和 S B B指令允许 8 0 8 0加 /减 1 6位,2 4位,3 2位和更多位的数。例如,假设寄存器对 B C
和 D E都包含 1 6位数,你想把它们相加,并把结果存到 B C中。下面是具体做法:
MOV A,C ;低位字节
ADD A,E
MOV C,A
MOV A,B ;高位字节
ADC A,D
MOV B,A
其中有两条加法指令,A D D指令用于低位字节相加,A D C指令用于高位字节相加。第一条加法指令的进位位包含在第二条加法指令中。因为只能利用累加器进行加法运算,所以在这么短的代码中也需要至少 4条 M O V指令。许多 M O V指令常常出现在 8 0 8 0代码中。
该是谈论 8 0 8 0标志位的时候了。在第 1 7章的处理器中,已有进位标志位 C F和零标志位 Z F。
8 0 8 0还有 3个标志位,即符号标志位 S F、奇偶标志位 P F和辅助进位标志位 A F。所有标志位都保存在另一个叫作程序状态字( P S W,program status word)的 8位寄存器中。像 L D A,S TA
和 M O V这样的指令不影响标志位,而 A D D,S U B,A D C和 S B B指令却要影响标志位,影响的方式如下:
当运算结果最高位为 1时,符号标志位 S F为 1,表示结果为负。
当结果为 0时,零标志位 Z F为 1。
当运算结果中,1”的个数为偶数时,奇偶标志位 P F = 1;当运算结果中,1”的个数为奇数时,奇偶标志位 P F = 0。 P F有时用来粗略地检测错误,此标志位在 8 0 8 0程序中不常用。
当 A D D或 A D C运算产生进位或 S U B与 S B B运算不发生借位时,进位标志位 C F = 1。 (这点不同于第 1 7章中的计算机进位标志的实现。 )
当操作结果的低 4位向高 4位有进位时,辅助进位标志位 A F = 1。此标志位只用在 D A A
(十进制调整累加器)指令中。
有两条指令直接影响进位标志位 C F:
操作码 指令 含义
3 7 S T C 置 C F为 1
3 F C M C C F取反第 1 7章中的计算机可执行 A D D,A D C,S U B和 S B B指令(尽管没什么灵活性),但 8 0 8 0还可以进行逻辑运算 A N D(与),O R(或)和 X O R(异或) 。算术运算和逻辑运算都可通过处理器的算术逻辑单元( A L U)来执行:
第 19章 两种典型的微处理器 195下载操作码 指令 操作码 指令
A 0 AND A,B B 0 OR A,B
A 1 AND A,C B 1 OR A,C
A 2 AND A,D B 2 OR A,D
A 3 AND A,E B 3 OR A,E
A 4 AND A,H B 4 OR A,H
A 5 AND A,L B 5 OR A,L
A 6 AND A,[ H L ] B 6 OR A,[ H L ]
A 7 AND A,A B 7 OR A,A
A 8 XOR A,B B 8 CMP A,B
A 9 XOR A,C B 9 CMP A,C
A A XOR A,D B A CMP A,D
A B XOR A,E B B CMP A,E
A C XOR A,H B C CMP A,H
A D XOR A,L B D CMP A,L
A E XOR A,[ H L ] B E CMP A,[ H L ]
A F XOR A,A B F CMP A,A
A N D,X O R和 O R指令按位运算,即逻辑操作只是单独地在对应位之间进行。例如:
MVI A,0Fh
MVI B,55h
AND A,Bh
累加器中的结果将为 0 5 h。如果第三条指令为 O R运算,则结果为 5 F h;如果第三条指令为
X O R运算,则结果为 5 A h。
C M P(比较)指令与 S U B指令基本上一样,除了结果不保存在累加器中。换句话说,
C M P执行减法操作再把结果扔掉。这是为什么?是因为标志位。根据标志位的状态可知道所比较的两数之间的关系。例如,当如下指令:
MVI B,25h
CMP A,B
执行完时,A中的内容没有改变。然而,若 A中的值为 2 5 h,则 Z F标志置位;若 A中的值小于 2 5 h,则 CF = 1。
这 8个算术逻辑运算也可以对立即数进行操作:
操作码 指令 操作码 指令
C 6 ADI A,x x E 6 ANI A,x x
C E ACI A,x x E E XRI A,x x
D 6 SUI A,x x F 6 ORI A,x x
D E SBI A,x x F E CPI A,x x
例如,上面列出的两条指令也可以用下面的指令来替换:
CPI A,25h
下面是其他两条 8 0 8 0指令:
操作码 指令
2 7 D A A
2 F C M A
C M A即 complement accumulator,它对累加器中的值进行取反操作。每个 0变为 1,每个 1
196 编码的奥秘 下载变为 0。如果累加器中的值为 0 11 0 0 1 0 1,C M A指令使它变为 1 0 0 11 0 1 0。也可以用下述指令来使累加器按位取反:
XRI A,FFh,
D A A即 Decimal Adjust Accumulator,如前所述,它可能是 8 0 8 0中最复杂的一条指令。微处理器中有一个完整的小部件专门用于执行这条指令。
D A A指令帮助程序员用 B C D码表示的数来进行十进制算术运算。在 B C D码中,每一小块数据的范围在 0 0 0 0? 1 0 0 1之间,对应于十进制的 0? 9。利用 B C D码格式,每 8位字节可存储两个十进制数字。
假设累加器中的值为 B C D码的 2 7 h。由于是 B C D码,则它实际上指的是十进制的 2 7。 (十六进制的 2 7 h等于十进制的 3 9。 )再假定寄存器 B中的值为 B C D码的 9 4 h。如果执行指令:
MOV A,27 h
MOV B,94 h
ADD A,B
累加器中的值将为 BB h,当然,它不是 B C D码,因为 B C D码中的每一块不能超过 9。但是,
现在执行指令:
DAA
则累加器中的值为 2 1 h,且 CF = 1,这是因为 2 7和 9 4的十进制和为 1 2 1。如果想进行 B C D
码的算术运算,这样做是相当方便的。
经常需要对一个数进行加 1或减 1操作。在第 1 7章的乘法程序中,我们需要对一个数减 1,
使用的方法是加上 FFh,它是 - 1的 2的补码。 8 0 8 0中包含特殊的用于寄存器或存储单元的加 1
指令(称作增量)和减 1指令(称作减量),
操作码 指令 操作码 指令
0 4 INR B 0 5 DCR B
0 C INR C 0 D DCR C
1 4 INR D 1 5 DCR D
1 C INR E 1 D DCR E
2 4 INR H 2 5 DCR H
2 C INR L 2 D DCR L
3 4 INR [HL] 3 5 DCR [HL]
3 C INR A 3 D DCR A
单字节指令 I N R和 D C R可影响除 C F外的所有标志位。
8 0 8 0也包含 4个循环移位指令,这些指令可使累加器中的内容左移或右移 1位:
操作码 指令 含义
0 7 R L C 累加器循环左移
0 F R R C 累加器循环右移
1 7 R A L 累加器带进位循环左移
1 F R A R 累加器带进位循环右移这些指令只影响 C F。
假定累加器中的值为 A 7 h,即二进制的 1 0 1 0 0 111。 R L C指令使 A中的内容向左移位,最高位(移出顶端)成为最低位(移进底端),同时决定进位标志位 C F的状态。其结果为 0 1 0 0 1111
且 CF = 1。 R R C指令用同样的方法向右移位。开始为 1 0 1 0 0 111,执行 R R C指令后,其结果为第 19章 两种典型的微处理器 197下载
11 0 1 0 0 11且 CF = 1。
R A L和 R A R指令有些不同。当向左移位时,R A L指令把 C F移入累加器的最低位,而把最高位移入 C F中。例如,如果累加器的内容为 1 0 1 0 0 111,CF = 0,R A L指令执行的结果是累加器的内容变为 0 1 0 0 111 0,且 CF = 1。同样,在相同的初始条件下,R A R指令使累加器的内容变为 0 1 0 1 0 0 11,CF = 1。
对于乘 2(左移 1位)和除 2(右移一位)操作,移位指令非常方便。
把微处理器寻址的存储器叫作随机访问存储器( R A M)是有原因的:微处理器可以简单地根据提供的地址访问某一存储位置。 R A M就像一本书一样,我们可以打开它的任何一页。
它并不像做在微缩胶片上的一个星期的报纸,要找到周六版,需扫过大半周。同样,它也不同于磁带,要播放磁带上的最后一首歌需快进整个一面。微缩胶片和磁带的存储不是随机访问的,而是顺序访问的。
R A M确实效果不错,对于微处理器来说更是如此。但在使用存储器时有所差别是有好处的,下面就是一种既非随机又非顺序访问的存储方式:假定你在一个办公室里,人们到你桌前给你分配工作,每个工作都需要某种文件夹。通常你会发现你在继续某项工作之前,必须使用另外一个文件夹先做一些相关的工作。因此你把第一个文件夹放在桌子上,又拿出第二个文件夹放在它上面进行工作。现在又有一个人来让你做一个优先权高于前面工作的工作,
你拿来一个新文件夹放在那两个上面继续工作。而此项工作又需要另外一个文件夹,这样在你的桌子上很快就摆了一堆文件夹了。
注意,这个堆非常明确地、有序地保存了你正在做的工作的轨迹。最上面的文件夹总是最高优先权的工作,去掉这个以后,下一个肯定是你就要做的,如此类推。当你最终去掉了桌子上的最后一个文件夹后(你开始的第 1项工作),你就可以回家了。
以这种方式工作的存储器技术叫做作堆栈( s t a c k) 。从底向上压入堆栈,从顶向下弹出堆栈,因此这也叫后进先出存储器,或 L I F O。最后放入堆栈中的数据最先被取出,最先放入堆栈中的数据最后被取出。
计算机中也可以使用堆栈,不是用来保存工作而是用来存储数据,且已被证明使用起来非常方便。向堆栈中放入数据叫作 p u s h(压入),从堆栈中取走数据叫作 p o p(弹出) 。
假定你正在用汇编语言设计程序,程序中使用了寄存器 A,B和 C。但在编程过程中,你发现此程序需要去做另一件事 — 一个小的计算,其中也要使用寄存器 A,,B,C。而你最终要回到先前的程序,并使用 A,B,C中原有的值。
当然,你能做的工作只是简单地把寄存器 A,B,C中的值保存到存储器中的不同位置,
以后再把这些位置的值装载到寄存器中,但这样做需要保存值被保存的位置。一个显然的方法是把寄存器压入堆栈:
PUSH A
PUSH B
PUSH C
一会儿再解释这些指令的作用。现在,我们只需要知道它们以某种方式把寄存器的内容保存在一个后进先出的存储器中。一旦这些语句执行了,你的程序就可以毫无顾虑地利用这些寄存器来做其他工作。为了得到原来的值,只需简单地按与压入堆栈相反的顺序把它们从堆栈中弹出即可,如下所示:
198 编码的奥秘 下载
POP C
POP B
POP A
记住是后进先出。如果用错了 P O P语句的顺序,就会引起错误。
堆栈机制的一个好处在于一个程序的不同部分都可以使用堆栈而不会出现问题。例如,
在把 A,B,C压入堆栈中后,程序的其他部分还可能需要把寄存器 C,D,E的内容压入堆栈:
PUSH C
PUSH D
PUSH E
接着,这一部分程序所要做的就是在第一部分弹出 C,B和 A之前,用下述方法恢复寄存器的值:
POP E
POP D
POP C
堆栈是怎样实现的呢?首先,堆栈只是不被别的东西使用的正常的 R A M的一部分。 8 0 8 0
微处理器包含一个特殊的 1 6位寄存器来对这一部分存储器进行寻址,这个 1 6位寄存器叫作堆栈指针。
这里举的压入和弹出寄存器的例子对于 8 0 8 0来说不太准确。 8 0 8 0的 P U S H指令实际上是存储 1 6位的值到堆栈,P O P指令用来恢复它们。因此 8 0 8 0不用像 PUSH C和 POP C这样的指令,
它有下述 8条指令:
操作码 指令 操作码 指令
C 5 PUSH BC C 1 POP BC
D 5 PUSH DE D 1 POP DE
E 5 PUSH HL E 1 POP HL
F 5 PUSH PSW F 1 POP PSW
PUSH BC指令把寄存器 B和 C的内容保存到堆栈中,POP BC指令恢复它们。最后一行的缩写 P S W指的是程序状态字,前面讲过,它是包含有标志位的 8位寄存器。最后一行的两条指令实际上是把累加器和 P S W都压入和弹出堆栈。如果你想保存所有寄存器和标志位的内容,
可以使用:
PUSH PSW
PUSH BC
PUSH DE
PUSH HL
当以后想恢复这些寄存器的内容时,按相反的顺序使用 P O P指令:
POP HL
POP DE
POP BC
POP PSW
堆栈是怎样工作的呢?假设堆栈指针为 8 0 0 0 h,PUSH BC指令将引起下面这些情况发生:
堆栈指针减 1至 7 F F F H
寄存器 B的内容保存在堆栈指针所指的地址处,即 7 F F F h处第 19章 两种典型的微处理器 199下载
堆栈指针减 1至 7 F F E H
寄存器 C的内容保存在堆栈指针所指的地址处,即 7 F F E h处当堆栈指针仍然为 7 F F E h时,POP BC指令执行,用来反向执行每一步:
从堆栈指针所指的地址(即 7 F F E h)处装载数据到寄存器 C中
堆栈指针增 1至 7 F F F h
从堆栈指针所指的地址(即 7 F F F h)处装载数据到寄存器 B中
堆栈指针增 1至 8 0 0 0 h
对每个 P U S H指令,堆栈都会增加 2个字节,这可能导致程序出现小毛病 — 堆栈可能会变得很大以致会覆盖掉程序所需的一些代码和数据。这就是堆栈上溢问题。同样,过多的
P O P指令会过早用光堆栈内容,这就是堆栈下溢问题。
如果 8 0 8 0同一个 6 4 K B的存储器连接,你可能想把初始堆栈指针置为 0 0 0 0 h。第一条 P U S H
指令使地址减 1变为 F F F F h,这时堆栈占用了存储器的最高地址。如果你的程序放在从 0 0 0 0 h
处开始的存储器区域,则它和堆栈离的就太远了。
对堆栈寄存器进行赋值的指令是 L X I,即 load extended immediate(装载扩展的立即数) 。
下面这些操作码后的指令也是把两个字节装载到 1 6位寄存器:
操作码 指令
0 1 LXI BC,x x x x
11 LXI DE,x x x x
2 1 LXI HL,x x x x
3 1 LXI SP,x x x x
指令:
LXI BC,527Ah
等价于
MVI B,52
MVI C,7A h
L X I指令保存一个字节。另外,上表中最后一条 L X I指令用来对堆栈指针赋值。微处理器复位后,这条指令并不常用来作为首先执行的指令之一:
0000 h,LXI SP,0000 h
也可以对寄存器对和堆栈指针执行加 1和减 1操作,就好像它们是 1 6位寄存器一样:
操作码 指令 操作码 指令
0 3 INX BC 0 B DCX BC
1 3 INX DE 1 B DCX DE
2 3 INX HL 2 B DCX HL
3 3 INX SP 3 B DCX SP
即然是在讨论 1 6位指令,可以看看更多一些这样的指令。下面的指令是把 1 6位寄存器对的内容加到寄存器对 H L中:
操作码 指令
0 9 DAD HL,B C
1 9 DAD HL,D E
2 9 DAD HL,H L
3 9 DAD HL,S P
200 编码的奥秘 下载上面这些指令可节约几个字节。例如,第一条指令正常需要 6个字节:
MOV A,L
ADD A,C
MOV L,A
MOV A,H
ADC A,B
MOV H,A
D A D指令通常用于计算存储器地址,这条指令只影响 C F。
下一步让我们看以下各种指令。下面的两个操作码后都紧跟着一个 2字节地址,分别保存和装载寄存器对 H L的内容:
操作码 指令 含义
2 h SHLD [aaaa],H L 直接保存 H L
2 A h LHLD HL,[ a a a a ] 直接装载 H L
寄存器 L的内容保存在地址 a a a a处,寄存器 H的内容保存在地址 a a a a + 1处。
下面两条指令用来从寄存器对 H L中装载程序计数器 P C或堆栈指针 S P:
操作码 指令 含义
E 9 h PCHL PC,H L 把 H L中的内容装载到 P C
F 9 h SPHL SP,H L 把 H L中的内容装载到 S P
P C H L指令实际上是一种转移指令,8 0 8 0执行的下一条指令保存在 H L寄存器对中的地址所对应的存储单元中。 S P H L是另外一个设置 S P的方法。
下面两条指令中,第一条指令使 H L的内容与堆栈中最上面的两个字节进行交换,第二条指令使 H L的内容与寄存器对 D E的内容进行交换:
操作码 指令 含义
E 3 h XTHL HL,[ S P ] H L与堆栈顶端的内容交换
E B h XCHG HL,D E DE 和 H L交换除了 P C H L外,还没有讲过 8 0 8 0的转移指令。前面第 1 7章中讲过,处理器中有一个叫作程序计数器 P C的寄存器,P C中包含处理器取回并执行的指令的存储器地址。通常 P C使处理器顺序执行存储器中的指令,但有些指令 — 通常命名为 J u m p(转移),B r a n c h(分支)或 g o t o
(跳转) — 能使处理器偏离这个固定的过程。这些指令使得 P C装载另外的值,处理器所取的下一条指令将在存储器的其他位置。
尽管简单、普通的转移指令很有用,但条件转移指令更有用。这些指令可使处理器根据某些标志,如 C F或 Z F,来转移到另外的地址处。条件转移指令的存在使得第 1 7章中的自动加法机成为一般意义上的数字计算机。
8 0 8 0有 5个标志位,其中 4个对条件转移指令有用处。 8 0 8 0支持 9种不同的转移指令,包括无条件转移指令和基于 Z F,C F,P F,S F是 1还是 0的条件转移指令。
在介绍这些指令之前,先介绍一下与此相关的另外两种指令。第一个是 C a l l(调用)指令。
C a l l指令与 J u m p指令的不同之处在于:前者把一个新值装入到程序计数器 P C中,处理器保存
P C中原来的地址,保存在哪里?当然,在堆栈中。
这种策略意味着 C a l l指令可有效地保存“程序从哪里跳转”的标记。处理器最终可利用此第 19章 两种典型的微处理器 201下载地址返回到原来的位置。这个返回指令叫 R e t u r n。 R e t u r n指令从堆栈中弹出两个字节,并把该值装载到 P C中。
C a l l和 R e t u r n指令是任何处理器中都很重要的功能。它们允许程序员编写子程序,子程序是程序中经常用到的代码段。 (,经常”一般意味着“不止一次” 。 )子程序是汇编语言中的基本组成部分。
让我们看一个例子。假设你正在编写一个汇编语言程序,并且需要使两个数相乘,因此你可以写出一段代码来做这项工作,然后继续往下编写程序,现在又需要使两个数相乘。因为你已知道如何进行两数相乘,因此你只需简单地重复使用同样的指令来完成它。但只是简单地两次把这些指令输入到存储器吗?希望不是,这是对时间和存储空间的浪费,更好的方法是转送到原来的代码处。由于无法返回到程序的当前位置,所以一般的 J u m p指令不能用。
但使用 C a l l和 R e t u r n指令可以让你完成所需的功能。
进行两数相乘的一组指令可以作为一个子程序。下面就是这样的子程序。在第 1 7章中,
被乘数(和结果)存放在存储器的某一地址中;而在 8 0 8 0子程序中,寄存器 B的值和寄存器 C
中的值相乘,然后把 1 6位乘积装入寄存器 H L中:
Multiply,PUSH PSW ;保存要改变的寄存器
PUSH BC
SUB H,H ;设置 HL(结果)为 0000h
SUB L,L
MOV A,B ;乘数送到 A
CPI A,00h ;如果为 0,结束
JZ AllDone
MVI B,00h ; BC的高字节置 0
Multloop,DAD HL,BC ; BC 加到 HL
DEC A ;乘数减 1
JNZ Multloop ;不为 0,转移
AllDone,POP BC ;恢复保存的寄存器
POP PSW
RET ;返回注意,上述子程序的第 1行开始有一个标号 M u l t i p l y。当然,这个标号对应于子程序所在的存储器地址。子程序开始用了两个 P U S H指令,通常在子程序开始处应先保存(以后恢复)
它需要使用的寄存器。
然后该子程序把 H和 L寄存器置为 0。虽然可以使用 M V I指令而不用 S U B指令,但那需要使用 4个字节的指令而不是 2个字节的指令。子程序执行完后,寄存器对 H L中保存有相乘的结果。
下一步该子程序把寄存器 B的内容(乘数)移入 A中,并且检查它是否为 0。如果它为 0,
乘法子程序到此结束,因为结果为 0。由于寄存器 H和 L已经为 0,因而子程序可以只使用 J Z指令跳转到末端的两个 P O P指令处。
否则,子程序把寄存器 B置为 0。现在,寄存器对 B C中包含一个 1 6位的被乘数,A中为乘数。 D A D指令把 B C(被乘数)加到 H L(结果)中。 A中的乘数减 1,且只要它不为 0,J N Z指令就又使 B C加到 H L中。此小循环继续下去,直到 B C加到 H L中的次数等于乘数。 (可以用
8 0 8 0的移位指令编写一个更有效的乘法子程序。 )
202 编码的奥秘 下载利用这个子程序完成 2 5 h与 1 2 h相乘的程序用下面的代码:
MOV B,25h
MOV C,12h
CALL Multiply
C a l l指令把 P C的值保存在堆栈中,该值是 C a l l指令的下一条指令的地址。然后,C a l l指令使程序转移到标号 M u l t i p l y所标识的指令,即子程序的开始。当子程序计算完结果后,执行
R E T(返回)指令,即从堆栈中弹出程序计数器的值,程序继续执行 C a l l指令后面的语句。
8 0 8 0指令集中包括条件 C A L L指令和条件 R e t u r n指令,但它们远不如条件转移指令用得多。
下表中完整地列出了这些指令:
你可能知道,存储器并不是唯一连接在微处理器上的设备。一个计算机系统通常需要输入输出设备以便于实现人机通信。输入输出设备通常包括键盘和显示器。
微处理器是怎样与外围设备 (对于连接到微处理器而不是存储器的东西的称呼 )进行通信的呢?外围设备具有与存储器相似的接口,微处理器可通过对应于外设的具体地址来对外设进行读写。在有些微处理器中,外围设备实际上占用了通常用来寻址存储器的地址,这种配置叫作 内存映像 I / O。然而在 8 0 8 0中,在 65 536个正常地址外还有 2 5 6个附加地址专门为输入输出设备预留,这些就是 I / O端口 ( I/O Port) 。 I / O地址信号为 A0? A7,但 I / O访问与存储器访问不同,由 8 2 2 8系统控制芯片锁存的信号来区分。
O U T指令用于把累加器中的数据写到紧跟该指令的字节所寻址的 I / O端口中。 I N指令把端口的数据读入到累加器中。
操作码 指令
D 3 OUT PP
D B IN PP
外围设备有时需要引起微处理器的注意。例如,当你在键盘上按键时,如果微处理器能马上知道这件事通常是有帮助的。这由称作 中断 ( i n t e r r u p t)的机制来完成,这是连接至条件 操作码 操作码操作码 指令 指令 指令
8 0 8 0 I N T输入端的,由外设产生的信号。
然而,当 8 0 8 0复位时,它不能对中断产生响应。程序必须通过执行 E I( Enable interrupts)
指令来允许中断,通过执行 D I( Disable Interrupts)指令来禁止中断。
操作码 指令
F 3 D I
F B E I
8 0 8 0的 I N T E输出端信号表明允许中断。当外设需要中断微处理器当前工作时,它把 8 0 8 0
的 I N T输入端设置为 1。 8 0 8 0通过从存储器中取出指令对它作出响应,但控制信号表明有中断发生。外设通常通过提供下述指令之一来响应 8 0 8 0:
操作码 指令 操作码 指令
C 7 RST 0 E 7 RST 4
C F RST 1 E F RST 5
C 7 RST 2 E 7 RST 6
D F RST 3 F F RST 7
以上称作 R e s t a r t指令,它们与 C A L L指令相似,也需要把当前程序计数器的值压入堆栈。
但 R e s t a r t指令随后转移到一个特定的位置,RST 0转移到地址 0000h 处,RST 1转移到地址
0 0 0 8 h处等等,直到 RST 7转移到地址 0 0 3 8 h处。位于这些地址中的代码段来处理中断。例如,
来自键盘的中断引起 RST 4指令执行,地址 0 0 2 0 h处的一些代码从键盘读取数据(这将在第 2 1
章做全面介绍) 。
到此为止,已讲述了 2 4 3个操作码。下述 1 2个字节与任何操作码无关,0 8 h,1 0 h,1 8 h、
2 0 h,2 8 h,3 0 h,3 8 h,C B h,D 9 h,D D h,E D h和 F D h。这样总共有 2 5 5个操作码。下面还要提到一个操作码:
操作码 指令
0 0 N O P
N O P代表 no op,即 no operation (无操作) 。 N O P指令使微处理器什么都不做。这有什么作用吗?用于填空。 8 0 8 0通常可以执行一批 N O P指令而不会有任何坏情况发生。
以下不打算再详细讨论 Motorola 6800,因为它的设计与功能与 8 0 8 0非常相似。下面是
6 8 0 0的 4 0个管脚:
第 19章 两种典型的微处理器 203下载
VS S代表接地,VC C是 5 V电源。与 8 0 8 0相似,6 8 0 0有 1 6个地址输出信号和既可作为输入又可作为输出的 8个数据信号。它有 R E S E T信号和 R /- W信号。 - I R Q信号代表 中断请求 。 6 8 0 0的时钟信号比 8 0 8 0的更加简单。 6 8 0 0没有 I / O端口的概念,所有输入输出设备都必须是 6 8 0 0存储器地址空间的一部分。
6 8 0 0有一个 1 6位程序计数器 P C、一个 1 6位堆栈指针 S P、一个 8位状态寄存器(作为标志)
以及两个 8位累加器 A和 B。它们都被看成是累加器( B不是只作为一个寄存器)是因为没有能用 A来做而不能用 B来做的事。 6 8 0 0没有附加的 8位寄存器。
6 8 0 0中有一个 1 6位索引寄存器( index register),可用来保存一个 1 6位地址,很像 8 0 8 0中的寄存器对 H L。对于许多指令来说,它们的地址都可以由索引寄存器和紧跟在操作码后的地址之和得到。
虽然 6 8 0 0和 8 0 8 0所实现的操作相同 — 装载、保存、加法、减法、移位、转移、调用,
但很明显的区别是:它们的操作码和助记符完全不同。例如,下面是 6 8 0 0的分支转移指令:
操作码 指令 含义
2 0 h B R A 转移
2 2 h B H I 大于则转移
2 3 h B L S 小于或相同则转移
2 4 h B C C 进位为 0则转移
2 5 h B C S 进位置 1则转移
2 6 h B N E 不等则转移
2 7 h B E Q 相等则转移
2 8 h B V C 溢出为 0则转移
2 9 h B V S 溢出置 1则转移
2 A h B P L 为正则转移
2 B h B M I 为负则转移
2 C h B G E 大于或等于 0则转移
2 D h B LT 小于 0则转移
2 E h B G T 大于 0则转移
2 F h B L E 小于或等于 0则转移
6 8 0 0没有像 8 0 8 0中那样的奇偶标志位 P F,但它有一个 8 0 8 0中没有的标志位 — 溢出标志位( overflow flag) 。上述转移指令中有些依赖于标志位的组合。
当然 8 0 8 0和 6 8 0 0指令集是不同的,这两个芯片是同一时间由不同的两个公司的两组不同的工程师设计的。这种不兼容性意味着每一种芯片不能执行对方的机器代码,为一种芯片开发的汇编语言程序也不能翻译成可在另一种芯片上执行的操作码。编写可在多于一种处理器上执行的计算机程序是第 2 4章的主题。
8 0 8 0和 6 8 0 0还有一个有趣的不同点:在两种微处理器中,L D A指令都是从一个特定的地址处装载到累加器。例如,在 8 0 8 0中,下列字节序列:
204 编码的奥秘 下载
8080LDA指令将把存储在地址 3 4 7 B h处的字节装载到累加器。现在把上述指令与 6 8 0 0的 L D A指令相比较,后者采用称作 6 8 0 0的扩展地址模式:
该字节序列把存储在地址 7B34h 处的字节装载到累加器 A中。
这种不同点是很微妙的。当然,你也可能认为它们的操作码不同:对 8 0 8 0来说是 3 A h,对
6 8 0 0来说是 B 6 h。但主要是这两种微处理器处理紧随操作码后的地址是不同的,8 0 8 0认为低位在前,高位在后; 6 8 0 0则认为高位在前,低位在后。
这种 I n t e l和 M o t o r o l a微处理器保存多字节数时的根本不同从没有得到解决。直到现在,
I n t e l微处理器在保存多字节数时,仍是最低有效字节在前(即在最低存储地址处);而
M o t o r o l a微处理器在保存多字节数时,仍是最高有效字节在前。
这两种方法分别叫作 l i t t l e - e n d i a n ( I n t e l方式 )和 big-endian (Motorola方式 )。辩论这两种方式的优劣可能是很有趣的,不过在此之前,要知道术语 b i g - e n d i a n来自于 Jonathan Swift的
,G u l l i v e r’s Tr a v e l s》,指的是 Lilliput 和 B l e f u s c u在每次吃鸡蛋前都要互相碰一下。这种辩论可能是无目的的。先不说哪种方法在本质上说是不是正确的,但这种差别的确当在基于 l i t t l e -
endian 和 b i g - e n d i a n机器的系统之间共享信息时会带来附加的兼容性问题。
这两种微处理器后来怎样了呢? 8 0 8 0用在一些人所谓的第一台个人计算机上,不过可能更准确的说法是第一台家用计算机上。下图是 Altair 8800,出现在 1 9 7 5年 1月份的,P o p u l a r
E l e c t r o n i c s》杂志的封面上。
当你看到 Altair 8800时,前面面板上的灯泡和开关看起来似乎很熟悉。这和第 1 6章为
64KB RAM阵列建议的初始“控制面板”的界面是同一类型的。
8 0 8 0之后出现了 Intel 8085,更具意义的是出现了 Z i l o g制造的 Z - 8 0芯片。 Z i l o g是 Intel 公司的竞争对手,是由 I n t e l公司的前雇员,也曾在 4 0 0 4芯片上做出重要贡献的 Federico Faggin
第 19章 两种典型的微处理器 205下载
6800LDA指令建立的。 Z - 8 0与 8 0 8 0完全兼容,且增加了许多很有用的指令。 1 9 7 7年,Z - 8 0用于 Radio Shack
TRS-80 Model1上。
也是在 1 9 7 7年,由 Steven Jobs 和 Stephen Wo z n i a k建立的苹果计算机公司推出了 APPLE II。
APPLE II 既不用 8 0 8 0也不用 6 8 0 0,而是使用了采用 M O S技术的更便宜的 6 5 0 2芯片,它是对
6 8 0 0的增强。
1 9 7 8年 6月,I n t e l公司推出了 8 0 8 6,一个 1 6位微处理器,它可访问的存储空间达到 1 M B。
8 0 8 6的操作码与 8 0 8 0不兼容,但它包含乘法和除法指令。一年后,I n t e l公司又推出了 8 0 8 8,
其内部结构与 8 0 8 6相同,但其外部按字节访问存储器,因此该微处理器可使用较流行的为
8 0 8 0设计的 8位支持芯片。 I B M在其 5 1 5 0个人计算机 — 通常叫作 IBM PC— 上使用了 8 0 8 8芯片,这种个人计算机在 1 9 8 1年秋季推出。
I B M进军 P C市场产生了巨大影响,许多公司都发布了与 P C兼容的机器(兼容的含义在随后各章里将要详细讨论) 。多年来,,IBM PC兼容机”也暗指,Intel inside”,特指所谓 x 8 6家族的 I n t e l微处理器。 Intel x86家族继续发展,1 9 8 5年出现了 3 2位的 3 8 6芯片,1 9 8 9年出现了 4 8 6
芯片。 1 9 9 3年初,出现了 Intel Pentium微处理器,普遍地用在 P C兼容机上。虽然这些 I n t e l微处理器都不断增加了指令的指令集,但它们仍然支持从 8 0 8 6开始的所有以前处理器的操作码。
苹果公司的 Macintosh 首次发布于 1 9 8 4年,它使用了 Motorola 68000— 一个 1 6位的微处理器,也即 6 8 0 0的下一代处理器。 6 8 0 0 0和它的后代(常称为 6 8 K系列)是制造出的最受欢迎的一类微处理器。
从 1 9 9 4年开始,M a c i n t o s h计算机开始使用 Power PC,一种由 M o t o r o l a,I B M和 A p p l e公司联合开发的微处理器。 P o w e r P C是由一种称作 R I S C(精简指令集计算机)的微处理器体系结构来设计的,它试图通过简化某些方面以提高处理器的速度。在 R I S C计算机中,每条指令通常长度相同,(在 P o w e r P C中为 3 2位),存储器访问只限于装载和保存指令,且指令做简单操作而不是复杂操作。 RISC 处理器通常有大量的寄存器以避免频繁访问存储器。
因为 P o w e r P C具有完全不同的指令集,所以它不能执行 6 8 K的代码。但现在用于 A P P L E
M a c i n t o s h的 PowerPC 微处理器可仿真 6 8 K。运行于 PowerPC 上的仿真程序逐个检验 6 8 K程序的每一个操作码,并执行适当的操作。仿真程序不如 P o w e r P C自身代码那样快,但可以工作。
按照摩尔定律,微处理器中的晶体管数量应该每 1 8个月翻一番。这些多增加的晶体管有什么用处呢?
有些晶体管用于增加处理器的数据宽度,从 4位到 8位到 1 6位再到 3 2位;另外一些增加的晶体管用于处理新的指令。现在大多数微处理器都有用于浮点算术运算的指令(这将在第 2 3章解释);还有一些新增加的指令用来进行一些重复计算,以便在计算机屏幕上显示图片和电影。
现代处理器使用了一些技术用来提高速度,其中之一是流水线技术,处理器在执行一条指令的同时读取下一条指令。由于转移指令会改变执行流程,实际上这样达不到预期效果。
现在的处理器还包含一个 Cache( 高速缓冲存储器 ),它是做在处理器内部的快速 R A M阵列,
用于保存最近执行的指令。因为计算机程序经常执行一些小的指令循环,因而 C a c h e可以避免这些指令重复装载。所有这些速度提升措施都需要在处理器中有更多的逻辑器件和晶体管。
如前所述,微处理器只是完整的计算机系统的一部分(尽管是最重要的部分) 。我们将在第 2 1章构造这样一个系统,但首先必须学习怎样编码存在存储器中的除了操作码和数字外的其他东西。我们必须返回到小学一年级,再学习一下怎样读写文本。
206 编码的奥秘 下载下载