8086/8088指令系统
关于8086/8088 CPU的结构知识
补充内容:标志寄存器FLAG
- 6个状态标志位
CF:进位标志位
PF:奇偶标志位
AF:辅助进位标志位
ZF:零标志位
SF:符号标志位
OF:溢出标志位
- 3个控制标志位
TF:跟踪(陷阱)标志位,如果为1,则CPU处于单步工作方式。
IF:中断允许标志位,如果为1,屏蔽中断的控制标志位。
DF:方向标志位,如果为1,则操作的地址自动递减,否则递增。
1. 8086/8088指令寻址方式
1.1操作数的种类
- 数据操作数
1. 数据操作数是与数据有关的操作数,即指令操作的**对象是数据**。
2. 对于数据操作数,有的指令有两个操作数,一个称为源操作数,在操作过程中,其值不发生改变;另一个称为目的操作数,操作后一般被操作结果所代替。
(1)立即数操作数:要操作的数据包含在指令中。
(2)寄存器操作数:要操作的数据存放在指定的寄存器中。
(3)存储器操作数:要操作的数据存放在存储单元中。
(4)I/O操作数:要操作的数据来自或送到I/O端口。
- 地址操作数
1. 地址操作数是与程序转移地址有关的操作数,即指令中的操作对象不是数据,而是**要转移的目标地址**。它也分为**立即数操作数**、**寄存器操作数**和**存储器操作数**,即要转移的目标地址包含在**指令中**,或者**寄存器**,或者**存储单元**中。
2. 对于地址操作数,指令只有**一个目的操作数**,它是一个提供程序转移的**目标地址**。
1.2 寻址方式
所谓寻址方式,就是指令中给出的寻找操作数的方法。8086/8088的寻址方式分为两类:数据寻址方式和地址寻址方式。
1.2.1立即数寻址方式
立即数寻址方式又分为立即数寻址方式、寄存器寻址方式、存储器寻址方式和IO端口寻址方式四种类型。
1. 立即数寻址方式(immediate addressing)
MOV BL,80H
MOV AX,1090H
2. 寄存器寻址方式(register addressing)
MOV CL,DL
MOV AX,BX
3. 存储器寻址方式(memory addressing)
(1) 直接寻址方式:MOV AL,[1064H],数据段寄存器(DS)= 2000H,物理存储单元地址:2000H × 10H + 1064H = 21064H,将该地址内的数据存放到AL寄存器中。
(2)寄存器间接寻址方式:MOV AX,[SI],根据物理存储地址,将其值赋值为AX寄存器。
(3)寄存器相对寻址方式:MOV AL,[BP + TABLE],TABLE是一个8位或16位的位移量。
(4)基址变址寻址方式:MOV AH,[BP][SI],根据基址寄存器BP、变址寄存器SI运算的和,将其内容赋值到AH寄存器中。
(5)基址变址相对寻址方式:MOV AX,[BX + SI + COUNT],COUNT表示8位或16位常量。
4. IO端口寻址方式
(1)IO端口直接寻址方式:IN AL,21H。从地址为21H的端口读取数据送到AL中。
(2)IO端口间接寻址方式:OUT DX,AX。将AX的内容送到由DX寄存器内容所指定的端口号中。
(7)
1.2.2 地址寻址方式
- 段内直接寻址方式
- 段内间接寻址方式
- 段间直接寻址方式
- 段间间接寻址方式
2. 8086/8088指令系统
8086/8088的指令系统可以分为六种类型
- 数据传送指令;
- 算术运算指令;
- 位操作指令;
- 串操作指令;
- 程序控制指令;
- 处理器控制指令;
2.1 数据传送指令
2.1.1通用数据传送指令
- 数据传送指令MOV
MOV dst, src //dst表示目的操作数,src表示源操作数
- 堆栈操作指令PUSH、POP
PUSH src //压栈指令,先将堆栈指针SP-2,再将src压入栈中
POP dst //出栈指令,先将SP指向的栈顶值弹出栈顶,在将堆栈指针SP+2
- 数据交换指令XCHG
XCHG dst, src //将源操作数和目的操作数进行交换
- 字节转换操作XLAT
XLAT src_table //根据表中的元素的序号,查出表中相应元素的内容
2.1.2输入输出指令
- 输入指令IN
IN acc, port //从指定端口port中读入一个字节或一个字送AL或AX中
//端口地址小于0FFH
- 间接寻址的输入指令
IN acc, DX //由DX寄存器来指定端口号,将其端口号的8/16位数据送如AL/AX中
- 输出指令OUT
OUT port, acc //将AL或AX的8位/16位数据输出到指定的I/O端口,端口地址不大于FFH
- 间接寻址的输出指令
OUT DX, acc //由DX寄存器指定端口号,将AL或AX的8位/16位数据输出到该端口号中
2.1.3目的地址传送指令
目的地址传送指令常常用于串操作时建立初始的地址指针。
- 取有效地址指令LEA(load effective address)
LEA reg16, mem //将一个近地址指针写入指定的寄存器中。目的操作数必须为16位通用寄存器
LEA BX, BUFFER
MOV BX, BUFFER
//LEA是将BUFFER的偏移地址赋值给BX,而MOV是将BUFFER的值赋值给BX,LEA等同于下面的操作
MOV BX, OFFSET BUFFER //OFFSET BUFFER表示存储器地址的偏移地址
- 地址指针装入DS指令LDS(load pointer into DS)
LDS reg16, mem32 //LDS用于传送一个32位的远地址指针,包括一个偏移地址和一个段地址。偏移地址送入reg16的目的寄存器,段地址送入数据段寄存器DS。
- 地址指针装入ES指令(load pointer into ES)
LES reg16, mem32 //LES与LDS类似,不过段地址送入附加段寄存器ES
2.1.4标志传送指令
8086/8088 CPU有一标志寄存器FLAG,其中6个状态标志位和3个控制位。
- 取标志指令LAHF(load AH from Flags)
LAHF //LAHF指令将标志寄存器FLAG中的5个状态标志位SF,ZF,AF,PF,以及CF分别取出传送到累加器AH的对应位。LAHF 对状态标志没有影响。
- 置标志指令SAHF(store AH into Flags)
SAHF //SAHF指令与LAHF相反,将AH的对应位传送到标志寄存器的对应位。SAHF对部分状态标志位有影响。
- 标志压入堆栈指令PUSHF(PUSH Flags onto stack)
PUSHF //指令将SP-2,然后将标志寄存器FLAG的内容(16位)压入堆栈。不影响状态标志位。
- 标志弹出堆栈指令POPF(POP Flags off stack)
POPF //POPF指令操作与PUSHF相反,它将SP指向栈顶的内容弹出到寄存器,然后SP+2
2.2 算术运算指令
2.2.1二进制数运算指令
- 加法指令
- 不带进位加法指令
ADD dst, src //将源操作数和目的操作数相加然后赋值给dst目的操作数
- 带进位加法指令ADC
ADC dst, src //将源操作数和目的操作数相加,再加上进位标志CF的内容,赋值给目的操作数。
- 加1指令
INC dst //将目的操作数+1赋值给目的操作数。
- 减法指令
- 不带借位减法指令
SUB dst, src //将目的操作数减源操作数,结果赋值给目的操作数。
- 带借位的减法指令
SBB dst, src //将目的操作数减源操作数,然后在减进位标志CF,结果赋值给目的操作数。
- 减1指令
DEC dst //将目的操作数减1,然后赋值给操作数。
- 求补指令
NEG dst //用“0” - dst,结果赋值给目的操作数。
- 比较指令CMP
CMP dst, src //用dst减src,结果影响标志位,不影响dst和src。
- 乘法指令
- 无符号乘法
MUL src //MUL指令的另一个操作数在累加器(8位AL,16位AX)中,是隐含的。
- 带符号的乘法指令IMUL
IMUL src //IMUL操作与MUL操作类似,只是src表示的范围是带符号的。
- 除法指令
- 无符号数除法指令DIV
DIV src //字节除法中,AX除以src,被除数16位,除数8位,商在AL,余数在AH中。字除法,DX:AX除以src,被除数32位,除数为16位。商在AX,余数在DX中。
- 带符号除法指令IDIV
IDIV src //如果除数为0,会发生类型为0的终端。
- 符号扩展指令
字节扩展指令CBW:将一个字节(8位)按其符号扩展为字(16位)。它隐含的操作数为寄存器AL和AH。
字扩展指令CWD:将一个字(16位)按其符号位扩展为双字(32位)。它隐含的操作数为寄存器AX和DX。
2.3 位操作指令
2.3.1 逻辑运算指令
- 逻辑与指令AND
AND dst, src //将目的操作数和源操作数按位进行逻辑与运算,并将结果赋值给目的操作数。
- 测试指令TEST
TEST dst, src //TEST指令操作根AND指令相似,只是,不将操作结果赋值给目的操作数,只将结果反应在状态标志位上。TEST指令和CMP指令作用相似,一个比较位,一个比较字或字节。
- 逻辑或指令OR
OR dst, src //将目的操作数和源操作数进行按位逻辑或运算,结果赋值给目的操作数。
OR指令和AND指令:如果将一个寄存器和本身进行运算,不改变寄存器的值,只影响状态标志位。
经常用寄存器与自身按位与AND或者按位或OR,根据状态标志位来判断数据是否为0,用CMP指令虽然能达到同样的效果,但是指令字节较多,执行速度慢。
- 逻辑异或运算指令XOR
XOR dst, src //将dst和src进行按位异或运算,结果赋值给dst。
XOR指令的一个用途是:将寄存器或存储器某些特定的位”求反“,使其余位不变。**求反的位与”1“异或,不变的位与”0“异或。
- 逻辑非运算NOT
NOT dst //操作数不能为一个立即数。
2.3.2 移位指令
- 逻辑左移/算术左移指令SHL/SAL
SHL dst, 1/CL //将dst逻辑左移1位或CL位
SAL dst, 1/CL //将dst算术左移1位或CL位
SHL和SAL操作完全相同,左移一次可以实现dst乘以2操作。
- 逻辑右移指令SHR
SHR dst, 1/CL //将dst向右移1位或CL寄存器指定的位数,最高位补0。右移一次可以实现除以2操作。
- 算术右移指令SAR
SAR dst, 1/CL //将dst向右移1位或CL寄存器指定的位数,最高位保持不变。
2.3.3 循环移位指令
- 循环左移指令ROL
ROL dst, 1/CL //将dst向左循环移动1位或者CL寄存器指定的位数。
- 循环右移指令ROR
ROR dst, 1/CL //将dst向右循环移动1位或者CL寄存器指定的位数。
- 带进位循环左移指令RCL
RCL dst, 1/CL //将dst与进位标志CF一起向左循环1位或者CL寄存器指定的位数。
- 带进位循环右移指令RCR
RCR dst, 1/CL //将dst与进位标志CF一起向右循环1位或者CL寄存器指定的位数。
2.4 串操作指令
- 串传送指令
MOVS dst_string, src_string //将一个字节或字从存储器的某个区域传送到另一个区域。
MOVSB //B代表字节串传送,有B这个标志,指令后不能出现操作数。
MOVSW //W代表字传送,有W这个标志,指令后不能出现操作数。
例子: SI和DI分贝是源变址寄存器和目的变址寄存器
LEA SI, BUFFER1 ;源串首地址指针
LEA DI, BUFFER2 ;目的串首地址指针
MOV CX, 200 ;字符串长度
CLD ;清除方向标志DF
REP MOVSB ;传送200字节 REP是重复前缀
HLT ;停止
- 串装入指令LODS
LODS src_string //将一个字符串中的字节或字逐个装入累加器AL或AX中。
LODSB
LODSW
- 串送存指令STOS
STOS dst_string //将累加器AL或AX的值送存到内存缓冲区某个位置。
STOSB
STOSW
例子:将字符”#“装入以AREA为首地址的100个字节中
LEA DI, AREA
MOV AX, '##'
MOV CX, 50
CLD
REP STOSW
HTL
- 串比较指令SCAS
SCAS dst_string //SCAS指令在一个字符串中搜索特定的关键字。字符串的起始地址只能放在(ES:DI)中,不能段超越,待搜索的关键字必须放在累加器AL或AX中。
SCASB
SCASW
2.5 控制转移指令
2.5.1 转移指令
将一种程序控制从一处改换到另一处的最直接的方法。在CPU的内部,转移是通过将目标地址传送给CS和IP(段间转移)或IP(段内转移)来实现的。
- 无条件转移指令JMP
- 段内直接转移
JMP near_label //代码段寄存器CS的内容不变,JMP指令计算出下一条指令的地址到目标地址之间的16位相对位移量disp,disp可正可负。范围-32768 - 32767
- 段内直接短转移
JMP short_label //相对位移量disp的范围为-128 - 127,属于短标号。
- 段内间接转移
JMP reg16/mem16 //用指定的寄存器或存储器的内容取代当前IP的值,以实现程序的转移。
- 段间直接转移
JMP far_label //操作数是一个远标号,该标号在另一个代码段内。IP和CS内容会被该代码段标号信息取代。
- 段间间接转移
JMP mem32 //将存储器的前两个字节赋值给IP,后两个字节赋值给CS。
- 条件转移指令
Jcc short_babel //”cc“表示条件,首先测试规定条件,如果满足则跳转到目标地址,否则,继续执行。条件可以是无符号位的高 | 低(Above | Below),带符号数的大 | 小(Great | Less)等等。
2.5.2 循环控制指令
- LOOP
LOOP short_label //LOOP要求使用CX做寄存器的内容减一,结果不为零,则转到指令指定的短标号处。
LOOPE short_label //"E" 是相等equal
LOOPZ short_label //"Z" 是等于零zero
LOOPNE short_label //”NE“是不相等
LOOPNE short_label //”NZ“是不为零
2.5.3 过程调用与返回指令
- 过程调用指令CALL
- 段内直接调用
CALL near_proc //操作数是一个近过程,过程在本段内。
- 段内间接调用
CALL reg16/mem16 //操作数是一个16位的寄存器或存储器,先将IP入栈,再讲操作数内容赋值给IP。
- 段间直接调用
CALL far_proc //操作数是一个远过程,在另外的代码段。会先将CS和IP入栈,在更新其值为该代码段的信息。
- 段间间接调用
CALL mem32 //操作数是一个32位的存储器,先将CS和IP入栈,再见操作数的后两个字节给CS,前两个字节给IP。
- 过程返回指令RET
一般将堆栈之前保存的断点值弹出,程序返回原来调用的地方。RET允许带一个弹出只(pop_value),范围是0 - 64K大小,表示返回时从堆栈舍弃的字节数大小。
2.6 处理器控制指令
- 标志位操作指令
CLC:清进位标志
STC:置进位标志
CMC:对进位标志求反
CLD:清方向标志
STD:置方向标志
CLI:清中断允许位标志
STI:置中断允许标志
- 外部同步指令
- HLT //使CPU进入暂停状态
- WAIT //使CPU进入等待状态
- ESC //ESC ext_op, src 使其他处理器使用8086的寻址方式,并取得指令。
- LOCK //使CPU总线锁定低电平有效,直到执行完下一条指令。
- 空操作指令NOP
NOP指令不进行任何操作,但是会占用3个时钟周期。