第 三 章 指 令 集 结 构
description
Transcript of 第 三 章 指 令 集 结 构
第 三 章
指 令 集 结 构
指令集结构( instruction set architecture ) ,即 ISA ,是微处理器的接口,包含了与该微处理器进行交互所需要的信息,但并不涉及微处理器自身如何设计和实现的细节。
什么是指令集结构?
ISA 包括:微处理器的指令集、程序员可直接访问的寄存器的细节、访问内存所需的信息、微处理器如何响应中断。
1. 程序设计语言的级别2. 汇编语言指令 3. 指令集结构设计4. 两种微处理器 ( 相对简单 CPU 和 8085 微处理 器 ) 的指令集结构
主要内容:
3.1 程序设计语言的级别 3.1.1 语言种类
高级语言( high-level languages )
汇编语言( assembly language ) 向下兼容( backward compatible )
平台无关( platform-independent )
机器语言
3.1.2 编译和汇编程序 1. 编译、汇编2. 编译器 源程序、源代码、目标代码 连接器、装载器3. 编译过程 同一高级语言源代码可以经过编译在不 同的微处理器和操作系统或者计算平台上运行。
图 3.1 高级程序的编译过程 装载器包含在计算平台中
4. 汇编器和汇编过程
图 3.2 汇编语言程序的汇编过程
每一种汇编语言对应一种微
处理器,不需要针对不同平
台的汇编器
。
3.2 汇编语言指令 3.2.1 指令类型
3.2.1.1 数据传送指令
将数据从一个地方移到另一个地方(实际是“拷贝”),包括:内存取数据到微处理器、微处理器中的数据存到内存、微处理器内移动数据、输入数据到微处理器、从微处理器输出数据。
3.2.1.2 数据运算指令 包括算术运算指令、逻辑运算指令 、移位指令。
3.2.1.3 程序控制指令
控制程序流程的指令,包括:跳转指令(条件或无条件)或分支指令、子程序调用和子程序返回指令、“软中断”指令、停机指令。
3.2.2 数据类型
数值数据 无符号整型数、有符号整型数、浮点数据
布尔类型 数据值常以 0表示 FALSE,以非 0表示 TRUE
字符数据 字符编码标准( ASCII、 EBCDIC、 UNICODE、或别的)
3.2.3 寻址方式
寻址方式( addressing modes ):确定操作数地址的方法。
3.2.3.1 直接寻址 在该寻址方式中,指令包含有要访问单元的内存地址。
例如: LDAC 5 从内存单元 5读取数据并且把数据存储在 CPU的累加器中。
3.2.3.2 间接寻址指令中指定的是含有操作数地址的内存单元的地址。
OP … 5IR
10 操作数 35
操作数的地址 105
…
例如: LDAC @5 或 LDAC ( 5 )
要进行两次内存访问。
例如:假设寄存器 R 中存储了数值 5 ,则: LDAC R ;把数值 5从寄存器 R中拷贝到 CPU的累加器中 LDAC (R) 或 LDAC @R ;相当于 LDAC 5 ,从寄存器 R 中获取地址
3.2.3.4 立即值寻址 指定的操作数不是一个地址,而是确实要用到的数据。
例如: LDAC #5 ;把数据值 5移到累加器中
3.2.3.3 寄存器直接寻址和寄存器间接寻址 与直接和间接寻址方式相似,但指定的寄存器,而不是内存单元。
3.2.3.5 隐含寻址 并不明确地指出操作数,因为总是用到特定的寄存器。
例如: CLAC ;清空 CPU中的累加器,即将其值置为 0
常用于用堆栈存储数据的 CPU中。指令中不需要指定操作数,因为它暗示操作数一定来自堆栈。
3.2.3.6 相对寻址
该方式中,操作数不直接提供地址,而是提供一个偏移量。它与 CPU中程序计数器的内容相加生成所需的地址。 程序计数器存有当前正在执行指令的地址。
例如: LDAC $5 ;若该指令定位于内存单元 10,且它占用两个内存单元, ;则下一条指令会位于单元 12,指令从单元( 12+ 5=17 ) ;读取 17 号单元中的数据并且把它存于累加器中。 该寻址方式对于短跳转和可重定位代码很有用。
3.2.3.7 变址寻址方式和基址寻址 变址寻址方式与相对寻址方式类似,但它是将指令提供的地址与变址寄存器 中而不是程序计数器中的内容相加。
例如: LDAC 5(X) ;变址寄存器 X :数值 10 ,则 5+ 10= 15 ;读取 15 号单元中的数据并且把它存储在累加器中。
除了用基址寄存器替换变址寄存器外,基址寻址方式和变址寻址方式完全一样。
3.2.4 指令格式
指令代码( instruction code ):汇编语言指令转换成对应的机器代码,以二进制数值的形式表现。
操作码 地址码
指令的基本格式为:
考虑一个简单的例子: A = B + C 一个操作: 加法 三个操作数: 两个源操作数—— B 、 C 一个目的操作数—— A 假定微处理器可以执行 16 种不同的操作。 需要 4 位来代表其中的操作(因为 24 = 16 ) (假设位模式 1010 → 加法) 假定仅有 4 种可能的操作数—— A , B , C 和 D 。 用两位来表示每一种操作数: 00→A , 01→B , 10→C , 11→D
图 3.4 采用 (a) 三操作数, (b) 二操作数, (c) 单操作数, (d)0 操作数的指令格式和计算 A= B+ C的汇编语言程序以及机器代码。
微处理器可以设计成能运行具有
3
、2
、1
或0
个操作数的指令。
查看图 3.4 的代码,我们能发现较少的操作数通常转化为较多的指令来完成同样的任务。
本例子简单地说明了三,二,一和零操作数指令的不同。实际上,这些指令需要比本例更多的位数。一个操作数字段可以指定一个任意的内存地址,而不只是四个寄存器中的一个。每个操作数可能需要 16、32甚至更多的位数。另外还需要一些位用于指定每个操作数的寻址方式。
3.3 指令集结构设计
完整性问题:该指令集是否有足够的指令可以让程序完成它必须的任务? 正交性问题:如果指令不重叠或者不执行同样的操作,那么它们就是正交的。在最小的指令集中为程序员提供必需的操作。 设计者可以优化 ISA 的另一个地方 就是寄存器组。
本小节:分析设计一套指令集结构时应考虑哪些问题?
要考虑的其它问题:
。处理器必须向下兼容其它的微处理器吗?。微处理器将处理何种类型和 大小的数据? 。需要中断吗? 。需要条件指令吗?
3.4 相对简单的指令集结构存储器模型 :该微处理器可以访问 64K(= 216)
字节的存储器(每字节 8位)或者 64K×8的存储器。从外部设备输入数据和输出数据到外部设备,都可以被看作是访问内存。
有三个寄存器:累加器( AC )、寄存器 R 、 1 位零标志Z。
包含 16 条指令,每一条都是 8位指令码,见表 3.1
Instruction
Instructi on Code
Operati on
NOP 0000 0000 No operati on LDAC 0000 0001 Г AC=M[Г ] STAC 0000 0010 Г M[Г ]=AC MVAC 0000 0011 R=AC MOVR 0000 0100 AC=R J UMP 0000 0101 Г GOTO Г J MPZ 0000 0110 Г I F(Z=1)THEN GOTO Г J PNZ 0000 0111 Г I F(Z=0)THEN GOTO Г ADD 0000 1000 AC=AC+R,I f(AC+R=0)Then Z=1 El se Z=0 SUB 0000 1001 AC=AC-R,I f(AC-R=0)Then Z=1 El se Z=0 I NAC 0000 1010 AC=AC+1,I f(AC+1=0)Then Z=1 El se Z=0 CLAC 0000 1011 AC=0,Z=1 AND 0000 1101 AC=AC∧ R,I f(AC∧ R=0)Then Z=1 El se Z=0 OR 0000 1101 AC=AC∨ R,I f(AC∨ R=0)Then Z=1 El se Z=0 XOR 0000 1110 AC=AC⊕ R,I f(AC⊕ R=0)Then Z=1 El se Z=0 NOT 0000 1111 AC=AC’,I f(AC’=0)Then Z=1 El se Z=0
表 3.1 相对简单 CPU 的指令集
LDAC 、 STAC 、 JUMP 、 JMPZ和 JPNZ指令都需要 16 位的存储地址。这些指令在存储器中每个 都需要 3字节。第一个 字节包含指令的操作码,另外两字节对应地址。
3 字节格式 1 字节格式
相对简单 CPU 的指令格式。
例如: 25 : JUMP 1234H该指令以如下形式存储在存储器中: 25 : 0000 0101 ( JUMP ) 26 : 0011 0100 ( 34H) 27 : 0001 0010 ( 12H)
注意:第二字节低 8位,第三字节高 8位
指令集结构的用法举例: 用相对简单 CPU 编程计算 1 + 2 +……+ n ,或者 。 则其高级语言的代码 片断如下:
n
i
i1
可以把数值 n 存储在标明为 n 的存储单元中,结果存在标明为 total的内存单元处,内存单元 i 用于存储求和的次数。确定运算步骤如下:
total = 0 ; FOR i = 1 TO n DO {total = total + i} ;
1 : total= 0 , i = 0 2 : i = i + 1 3 : total= total+ i 4 : IF i≠n THEN GOTO 2
实现这一算法的相对简单 CPU 的代码如下: CLAC STAC total STAC i
Loop: LDAC i INAC STAC i
MVAC LDAC total ADD STAC total
MVAC LDAC n SUB JPNZ Loop
total = 0 , i = 0
i = i + 1
total = total + i
IF i≠n THEN GOTO Loop
指令 1st Loop 2nd Loop 3rd Loop 4th Loop 5th Loop CLAC AC=0 STAC total total =0 STAC i i =0 LDAC i AC=0 AC=1 AC=2 AC=3 AC=4 I NAC AC=1 AC=2 AC=3 AC=4 AC=5 STAC i i =1 i =2 i =3 i =4 i =5 MVAC R=1 R=2 R=3 R=4 R=5 LDAC total AC=0 AC=1 AC=3 AC=6 AC=10 ADD AC=1 AC=3 AC=6 AC=10 AC=15 STAC total total =1 total =3 total =6 total =10 total =15 LDAC n AC=5 AC=5 AC=5 AC=5 AC=5 SUB AC=4,
Z=0 AC=3, Z=0
AC=2, Z=0
AC=1, Z=0
AC=0, Z=0
J PNZ Loop J UMP J UMP J UMP J UMP NO J UMP
下表显示了当 n = 5时代码的运行过程:表 3.2 循环求和程序的执行步骤
怎样看待这个指令集结构? 它满足了以教学为目的的设计目标。当我们在第 6和 7章中设计这种 CPU时我们就会看到,其复杂度足以阐明很多 CPU 的设计原则,却又没有掉进自身复杂度的陷阱中。 对于简单的应用程序来 说,指令集完整。如果一个应用程序需要使用浮点型数据,它就不是十分完整。对于通用计算 机(例如个人计算机),该指令集显然是不够的。 该指令集是相当正交的。只是多了 OR 指令,但有时 CPU 的指令集不是完全正交更好一些。 寄存器组是它最大的弱点。寄存器的缺乏导致执行任务较慢,并且降低了性能。
3.5 实例: 8085 微处理器指令集结构
3.5.1 8085 微处理器的寄存器组 通用数据寄存器: 累加寄存器 A - 总是接收一个 8位的算术或逻辑
指令的结果;也为所有采用二操作数的指令提供一个操作数。
六个通用寄存器 - 命名为 B , C , D , E , H和L ,可成对访问 : B 和 C , D 和 E , H和L 。寄存器对 HL 常用来指向内存单元。
16 位的堆栈指针寄存器 SP :包含堆栈顶部的地址。
5 个标志,共同称为标志寄存器:● 符号标志 S :表明算术或逻辑指令计算出的结果的符号。
其中,值 1 表示负数;值 0 表示正数(或零)。● 零标志 Z :如果算术或逻辑运算指令产生的结果为 0 ,
则将 Z 置为 1 ;否则 Z为 0 。 ● 奇偶标志 P :如果算术或逻辑运算结果中有偶数个 1 ,
则将 P置为 1 ;否则 P 为 0 。 ● 进位标志 CY :当算术运算产生进位时才去设置它。 例如,加法 1111 0000 + 1000 0000 = 1 0111 0000 ,
对两个 8位值相加但产生了 9位结果。最左边的 1被存储在 CY中;如果加法不产生进位 1 ,则 CY中会存储 0 。
● 辅助进位标志 AC :与进位标志类似。它不指明进位值,但指出从结果的低四位向高四位传递了进位。
例如,加法 0000 1111 + 0000 1000 = 0001 0111
中断标志寄存器 IM:用于允许和禁止中断而且检查待处理的中断。程序员可以读取并且设置该寄存器中的值来处理中断。
3.5.2 8085 微处理器指令集 8085 指令集总共包含了 74 条指令。 可分为三个部分:数据传送指令、数据运算指令和程序控制指令。 采用如下记号描述: ● r, r1, r2 :表示任何一个 8位寄存器 A, B, C, D, E,H,或者 L。
● M :表示内存单元。M[HL]表明该内存单元的地址存在寄存器对 HL中。
● rp :表示寄存器对 BC, DE, HL,或者堆栈指针 SP。 ● Г :一个 16位地址或者数据。● n :是一个存储在内存中且紧跟操作码后的 8位地址或者数据值。● cond :条件指令的一个条件。值为: NZ、 Z、 P 、 N 、 PO 、
PE 、 NC 、 C 。
除了 POP PSW指令外,其它指令都不会修改标志的值。 ( PSW :处理器状态字(保存累加器和标志器中的内容 ))
指令 操作 NOP No operati on MOV r1,r2 r1=r2 MOV r,M r=M[HL] MOV M,r M[HL]=r MVI r,n r=n MVI M,n M[HL]=n LXI rp Г, rp Г= LDA Г A=M[Г ] STA Г M[Г ]=A LHLD Г HL=M[Г ],M[Г +1] SHDL Г M[Г ],M[Г +1]=HL
指令 操作 LDAX rp A=M[rp](rp=BC,DE) STAX rp M[rp]=A(rp=BC,DE) XCHC DE← → HL PUSH rp Stack=rp(rp≠ SP) PUSH PSW Stack=A,fl ag regi ster POP rp Rp=Stack(rp≠ SP) POP PSW A,fl ag regi ster=Stack XTHL HL← → Stack SPHL SP=HL I N n A=i nput port n OUT n output port n=A
表 3.3 8085 微处理器的数据传送指令
(立即寻址)
( 直接寻址 )
指令的通用格式。一些指令有指定寄存器的字段,而另一些指令这些部分却是固定的。
图 3.6 8085的指令格式
一字节 二字节
三字节
指令 操作 标 志位
ADD r A=A+r ALL ADD M A=A+M[HL] ALL ADI n A=A+n ALL ADC r A=A+r+CY ALL ADC M A=A+M[HL]+CY ALL ACI n A=A+n+CY ALL SUB r A=A-r ALL SUB M A=A-M[HL] ALL SUI n A=A-n ALL SBB r A=A-r-CY ALL SBB M A=A-M[HL]-CY ALL SBI n A=A-n-CY ALL I NR r r=r+1 Not CY I NR M M[HL]=M[HL]+1 Not CY DCR n r=r-1 Not CY DCR M M[HL]=M[HL]-1 Not CY I NX rp rp=rp+1 None DCX rp rp=rp-1 None DAD rp HL=HL+rp CY DAA Deci mal adj ust ALL
指令 操作 标 志位
ANA r A=A∧ r ALL ANA M A=A∧ M[HL] ALL ANI n A=A∧ n ALL ORA r A=A∨ r ALL ORA M A=A∨ M[HL] ALL ORI n A=A∨ n ALL XRA r A=A⊕ r ALL XRA M A=A⊕ M[HL] ALL XRI n A=A⊕ n ALL CMP r Compare A and r ALL CMP M Compare A and M[HL] ALL CPI n Compare A and n ALL RLC CY=A7,A=A6-0,A7 ALL RRC CY=A0,A=A0,A7-1 ALL RAL CY,A=A,CY CY RAR A,CY=CY,A CY CMA A=A’ NONE CMC CY=CY’ CY STC CY=1 CY
数据运算指令大多数会影响表中的标志。
表 3.4 8085微处理器的数据运算指令
13 条程序控制指令。 DI , EI , RIM和 SIM包含在此因为它们可以处理中断,而中断最终又会影响程序控制。这些指令都不修改标志。
Instruction Operati on J UMP Г GOTO Г J cond Г I f condi t i on i s true then GOTO Г PCHL GOTO address i n HL CALL Г Cal l subrouti ne at Г Ccond Г I f condi t i on i s true then cal l subrouti ne at Г RET Return f rom subrouti ne Rcond I f condi t i on i s true the return f rom subrouti ne RSTn Cal l subrouti ne at 8*n(n=5. 5,6. 5,7. 5) RI M A=I M SI M I M=A DI Di sabl e i nterrupts EI Enabl e i nterrupts HLT Hal t the CPU
表 3.5 8085 微处理器的程序控制指令
3.5.3 一个简单的 8085 程序 计算和 1 + 2 +……+ n ,并且把结果存储于内存单元 total中 。 n 值最初存于标志为 n 的内存单元中。 当设计此程序时,我们计算如 n +( n- 1 )+……+ 1形式的总和。 算法如下:
与相对简单 CPU 中的程序不同, 8085 程序把它的运行值存储在 CPU 寄存器中。寄存器 B 包含数值i ,总和存储在寄存器 A 中。
1: i = n , sum = 0 2 : sum = sum + i , i = i- 1 3 : IF i≠0 THEN GOTO 2 4 : total= sum
执行该算法的 8085 代码如下: LDA n MOV B,A XRA A } sum = A♁A = 0 Loop: ADD B } sum = sum + i DCR B } i = i- 1 JNZ Loop } IF i≠0 THEN GOTO Loop STA total } total= sum
i = n
运行值存储在 CPU 寄存器,减少了内存访问次数,程序更短、运行速度更快
该程序仅需要七条指令,而对于相对简单 CPU 的程序则需要 13 条指令。它的循环段(执行了 n次)仅需要三条指令;而对于相对简单 CPU 同样的 循环则需要 10 条指令。
当 n = 5时,它的运算过程。
Instruction 1st Loop 2nd Loop 3rd Loop 4th Loop 5th Loop LDA n MOV B,A
B=5
XRA A A=0 ADD B A=5 A=9 A=12 A=14 A=15 DCR B B=4,
Z=0 B=3, Z=0
B=2, Z=0
B=1, Z=0
B=0, Z=0
J NZ Loop J UMP J UMP J UMP J UMP NO J UMP STA total total =15
表 3.6 8085 循环求和程序执行步骤
3.5.4 分析 8085 指令集结构 完备性: 8085 微处理器的指令集要比相对简单 CPU 的更完备,而且适合于像微波炉控制器这样的应用。但是,对于 像个人计算机这样更复杂的应用,它就不能够满足需要了。
与相对简单 CPU相比, 8085微处理器一个最明显的优势就是它的调用子程序的能力。还结合了中断。但不能很容易地处理浮点数据。
正交性:指令集也是相当正交的。 例如它没有清空累加器指令,而使用 XRA A 将累加器与自身作异或运算,使 A值始终置为 0 。
寄存器组: 8085 的寄存器组比较充足,有更多的标志位。
3.6 总结 在设计微处理器的过程中,确定指令集结构是第一步也算是最重要的一步。 ISA规定了微处理器能为人所看到的外部特性,包括:指令集,用户可访问的寄存器,以及如何与内存交互。 高级语言程序被编译和连接后形成机器语言程序。汇编语言程序 经汇编 后生成机器语言程序。微处理器实际执行这些机器语言程序 。 设计 ISA 的目标包括:完备性,即指令集应该包括编程所需的指令;正交性,即指令尽量最小重叠;还应该包含足够的寄存器以提高处理器的性能。 ISA 不但规定指令集,也规定指令所能处理的数据类型,及每条指令所 采用的寻址方式和指令格式。