计算机硬件技术基础
第三章 微处理器的指令系统
3.1 8086/8088的寻址方式
3.1.1 数据寻址方式
-
立即寻址
- 将立即数传送到目标寄存器或存储器
- 操作数就在指令中(CPU直接从紧跟着指令代码的后续地址单元中取得该立即数)
- 不必执行总线周期
-
寄存器寻址
- 操作数放在CPU的寄存器中
- 对16位操作数,寄存器为8个16位通用寄存器(
AX、BX、CX、DX、SP、BP、SI、DI
) - 对8位操作数,寄存器只能为
AH、AL、BH、BL、CH、CL、DH、DL
- 操作数在CPU内部,不必执行总线周期
- CS不能用MOV改变
MOV AX,‘AB’ 把ASCII码BA(4241H)传送到AX
MOV WORD PTR [SI],6180H 把立即数6180H传送到数据段由SI和SI+1所指的两储存单元
-
存储器寻址
-
E A = 基 址 指 ( B X 或 B P ) + 变 址 值 ( S I 或 D I ) + 位 移 量 D I S P EA=基址指(BX或BP)+变址值(SI或DI)+位移量DISP EA=基址指(BX或BP)+变址值(SI或DI)+位移量DISP
-
EU先计算操作数地址的偏移地址(EA),然后送往BIU与左移四位的段寄存器相加,形成20位的物理地址
-
-
直接寻址
-
E A = D I S P EA=DISP EA=DISP
-
用于存储单元与AL、AX之间的MOV指令
-
指令长为3B
MOV AX,[1680H]* 把数据段存储器1680H和1681H两单元的字内容复制到AX中
-
-
位移寻址
- 适合几乎所有将数据从存储单元传送寄存器的指令
- 指令长为4B
- 涉及CL、ES等除AX、AL寄存器的指令为位移寻址
- 直接寻址和位移寻址为直接数据寻址的两种基本形式
-
寄存器间接寻址
- 操作数一定在存储器中
- EA由BX、BP、DI、SI保存,书写时要带[],表示间接寻址(意思是由[]内的寻址找到的存储单元)
- 不允许存储器与存储器之间传送数据
MOV AL,[SI]是正确的,因为汇编程序能根据AL判断[SI]为字节传送类型
MOV [SI],6AH是错误的,因为汇编程序不能通过立即数确定存储器数据类型的长度,可写为MOV BYTE PYR [SI],6AH,即可确定为字节
-
基址加变址寻址
- E A = 基 址 指 ( B X 或 B P ) + 变 址 值 ( S I 或 D I ) EA=基址指(BX或BP)+变址值(SI或DI) EA=基址指(BX或BP)+变址值(SI或DI)
MOV DX,[BP+SI] BP=2000H SI=0300H SS=1000H 则执行该指令时将12300H单元的字数据传送给DX寄存器
-
寄存器相对寻址
- E A = 变 址 值 ( S I 或 D I ) + 位 移 量 D I S P EA=变址值(SI或DI)+位移量DISP EA=变址值(SI或DI)+位移量DISP
MOV ARRAY[DI],BL 把BL中的字内容存入以ARRAY+DI作为有效地址的数据段存储单元
-
相对基址加变址寻址
-
E A = 基 址 指 ( B X 或 B P ) + 变 址 值 ( S I 或 D I ) + 位 移 量 D I S P EA=基址指(BX或BP)+变址值(SI或DI)+位移量DISP EA=基址指(BX或BP)+变址值(SI或DI)+位移量DISP
-
通常用来寻址存储器的二维数组数据
-
3.2 数据传送类指令
3.2.1 通用数据传送指令
-
MOV d,s;d<-s
- des不能为立即数
- des,src不能同时为存储器
- des不能为CS
-
PUSH s/POP d
- 按字操作,s/d 可以是16位寄存器或存储器两相邻单元
- 通过SS*16+SP确定栈顶,
-
XCHG d,s
- 将源操作数与目标操作数相互对应交换位置
- 不能在两个存储单元之间进行交换
- 段寄存器(CS、DS、SS、ES),IP不能作为s和d
-
XLAT
- 字节翻译指令
- 执行操作:AL<-[BX+AL]
MOV BX,0030H
MOV AL,5
XLAT
这段指令的意思是:
显示码表存放在偏移地址位0030H开始的内存中
通过给AL赋值5,可以取到距离开始地址5个存储单元的码
3.2.2 目标地址传送指令
-
LEA d,s
- 取有效地址(偏移地址)指令
- 把用于指定源操作数的16位偏移地址传送到指定的16位通用寄存器中
LEA BX,[SI] 是将SI指示的偏移地址(SI的内容)装入BX
MOV BX,[SI] 是将SI寻址的存储单元中的数据装入BX
-
LDS d,s
- 取某变量32位地址指针的指令
- 从指令的源s所指定的存储单元开始,取出4字节,将前两字节(偏移地址)传送到s,将后两字节(段地址)传送到DS
-
LES d,s
- 与LDS的区别只在于把由源操作数所指定的某变量的地址指针中的后两个字节的地址传送到ES段寄存器
LEA是将16位有效地址装入任何一个16位通用寄存器,而LDS和LES是将32位地址装入任何16位通用寄存器和DS,ES
3.2.3 标志位传送指令
-
LAHF
-
将标志寄存器FLSAGS的低字节(5个状态标志位)传送到AH寄存器中
-
一一对应,AD的D5、D3、D1三位没有意义
-
-
SAHF
- 将AH寄存器中的内容传送到标志寄存器FLAGS的低字节(功能与LAHF相反)
-
PUSHF
- 将16位标志寄存器FLAGS内容入栈保护
-
POPF
- 将当前栈顶和次栈顶的数据字弹出送回到FLAGS中
- 以上两个指令常成对出现,,用于保护标志寄存器内容
3.2.4 I/O数据传送指令
-
IN 累加器,端口
- 端口号可以用8位立即数直接给出;或将端口号事先安排在DX寄存器中
- 将指定端口中的内容输入到累加器AL/AX
IN AL,PORT
IN AL,DX
IN AX,DX
-
OUT 端口号,累加器
- 端口号可以用8位立即数直接给出;或将端口号事先安排在DX寄存器中
- 将累加器AL/AX中的内容输出到指定端口
3.3 算术运算类指令
3.3.1 加法指令
-
ADD d,s
- 将源操作数与目标操作数相加,结果保留在目标中,并根据结果置标值位
- d,s要求同MOV
注意数组加法
-
ADC d,s;d<-d+s+CF
- CF的原状态也一起参与加法运算
- 运算结束后,CF将重新根据结果置成新的状态
ADC AX,BX ;AX = AX+BX+C(进位位)
-
INC d;d<-d+1
- 将目标操作数当作无符号数,完成加1操作后,结果保留在目标中
- 只影响OF、SF、ZF、AF、PF,而不影响进位标志CF
3.3.2 减法指令
-
SUB d,s;d<-d-s
- 根据运算结果置标志位
-
SBB d,s;d<-d-s-CF
- 完成减法运算时还要再减去进位标志CF的原状态
- 运算结束后,CF将重新根据结果置成新的状态
-
DEC d;d<-d-1
- 自减一
-
NEG d;d<-d#+1
- 求补指令
- 将目标操作数取负后送回目标
- 需要注意正负数存储都是补码
- CF通常被置为1;只有当操作数为0时,CF置为0
-
CMP d,s;d-s
- 将目标操作数与源操作数相减但不送回结果
- 根据结果置标志位
- 对于两个无符号数的比较,只需要依据CF判断(ZF=0,d=s;CF=0,d>=s;CF=1,d<s)
- 两有符号数的比较:OF ⊕ \oplus ⊕SF=0,d>=s;OF ⊕ \oplus ⊕SF=1,d<s
3.3.3 乘法指令
-
MUL s
- 无符号乘法指令
- 被乘数隐含在AL/AX中
- 8位二进制乘法,高8位存在AH,低8位存在AL
- 16位二进制乘法,高16位存在DX,低16位存在AX
- 若AH!=0或DX!=0(高位有效),则CF=1,OF=1;否则,CF=OF=0
- 其余标志位为任意状态,不可预测
-
IMUL s
- 有符号乘法指令
- 若高位是低位的符号扩展(高位无有效数字),OF=CF=0;否则,为1
- 对其他标志位没有定义
3.3.4 除法指令
-
DIV s
- 不带符号的二进制数相除
- 被除数隐含在AX(字节除)或DX、AX(字除)
- 字节除法,所得商存于AL,余数存于AH
- 字除法,所得的商存于AX,余数存于DX
- 余数的符号应与被除数符号一致
-
IDIV s
- 带符号数的二进制相除
- 符号位为各自的最高位
-
CBW与CWD
- 专门为IDIV设置的符号扩展指令
- CBW:将AL的最高有效位D7扩展到AH,若AL最高有效位为0,则AH=00H;若AL最高有效位为1,则AH=FFH
- CWD:将AX最高有效位D15扩展到DX,若AX最高有效位为0,则DX=0000H;若AX最高有效位为1,则DX=FFFFH
3.4 逻辑运算和移位循环类指令
3.4.1 逻辑运算
3.4.2 移位指令与循环移位指令
用0补空位
用0补空位
算术右移补的是符号位,正数补0,负数补1
移位指令若移位位数为1,移位结果使符号位改变,则OF=1;若移多位,OF无效
- RCR
CF标志总是保持移出的最后一位的状态
移位指令若移位位数为1,移位结果使符号位改变,则OF=1;若移多位,OF无效
3.6 程序控制类指令
3.6.1 无条件转移指令
-
JMP 目标标号
① 段内直接转移
- 目标标号偏移地址=(IP)+ 指令中位移量
- 分为段内段转移(2B,-128~+127)和段间转移(3B,±32KB),影响IP指向下一指令加的字节数
② 段内间接转移
- 间接寻址方式(通过寄存器或存储器)
- 将段内的目标地址先存放在某通用寄存器或存储器的某两个
连续地址中,然后赋给IP
JMP SHORT ABC
JMP NEAR PTR ABC
JMP BX
③ 段间直接转移(远转移)
- 段间指由当前代码段转移到其他代码段,转移范围超过±32KB
- 执行时,将目标标号的段内偏移地址送入IP,目标标号所在段的段地址送入CS
JMP FAR PTR ADDR2
④ 段间间接转移
- 间接寻址方式
JMP DWORD PTR[BX + ADDR3]
设当前 CS = 1000H,IP = 026AH,DS = 2000H,BX = 1400H,ADDR3 = 020AH,(2160AH)= 0EH,(2160BH)= 32H,(2160CH)= 00H,
(2160DH)= 40H。
则执行指令时,目标地址的偏移地址320EH送入IP,而其段地址4000H送入CS。于是,指令执行后,CPU将转到另一代码段物理地址为4320EH的单元中去执行后续程序。
-
CALL Process
① CALL N_PROC
- 第一步,先将Process的返回地址(CALL指令的下一条指令的地址)压入堆栈中,以便返回
- 第二步,转移到Process的入口地址去继续执行
② CALL BX
- 间接寻址
- 事先将Process入口的偏移地址置入BX寄存器中
③ CALL F_PROC
- 其他代码段,需要将CS、IP一起入栈
④ RET
- 放在Process的出口
- 功能是从堆栈顶部弹出由CALL指令压入的断点地址值(近过程为2字节的偏移量,远过程为2字节的偏移地址和2字节的段地址)
- 有时还要弹出值n(n个字节偶数的内容,0~FFFFH范围内的任何一个偶数):取决于是否传参3.6.2 条件转移指令
3.6.2 条件转移指令
- 根据CPU执行上一条指令时,某一个或某几个标志位的状态而决定是否控制程序转移
- 条件转移指令都为段转移(段内直接寻址),-128~127
3.6.3 循环控制指令
-
LOOP target
- 先将循环次数送入CX寄存器
- CX自减一,直到CX=0,结束循环
-
LOOPNZ/LOOPNE target
- 若ZF = 0且CX != 0,继续循环
-
JCXZ target
- 若CX = 0,跳转到target