Skip to content

第 3 章 8086

一. 基本数据类型

1. 字、双字的对齐

数据保存在内存时一个单元存放一个字节

数据保存时低字节(0~7位)占用内存中的低地址,此地址就是操作数的地址

在进行数据保存时,字和双字在内存中尽量做到对齐自然边界

对于不对齐的存储访问,处理器要求做两次存储访问操作;而对于对齐的访问,只要做一次存储访问操作。

2. 数字数据类型

2.1. 无符号整数

2.2. 带符号整数

3. 指针数据类型

3.1. 近指针

16 位,分段存储模式中用于同一段内的存储器引用

3.2. 远指针

32 位,分段存储模式中的跨段存储引用

4. 串数据类型

串是位、字节、字或双字的连续序列

二. 8086 的指令格式

[<标号>: ]<指令助记符>[<操作数>][; <注释>]
LOADREG:MOVAX, BX; AX <- AX + BX

8086机器指令包含零个或多个操作数。某些操作数是显式规定的,有的是指令中隐含的(eg. 偏移地址)。操作数能定位在 立即数 寄存器 存储单元 I/O 端口

指令中并不直接给出操作数的数值,而给出操作数存放的地址寄存器的地址存储单元的地址。操作数的地址也不直接给出,给出计算方法。

三. 8086 指令的操作数寻址方式

1. 立即数

大部分算术指令均允许源操作数是立即数,但 DIVIDIV 等不允许源操作数是立即数

ADD AX, 14

2. 寄存器寻址

操作数在寄存器中,寄存器的内容就是操作数的数值,操作数用寄存器的符号来表示

INC AX

3. 存储器寻址

操作数在存储器中,出入微处理器都需经过总线

当 EU 读写一个存储器操作数时,须将一个偏移地址传送给 BIU,BIU 经过地址运算后产生一个 20 位物理地址,然后执行存取该操作数所需的总线周期

EU 为一个存储器操作数而计算出来的偏移量称为操作数的有效地址 EA,这是一个 16 位无符号数,表示该操作数所在存储单元与所在段起始地址的距离(以字节为单位)

内存操作数地址 = (段地址 << 4) + 偏移地址

3.1. 规定段地址

[[undergraduate/Intel8086/c2-IA32-8086#^memory-organization]]

3.2. 规定偏移量

内存地址的偏移量部分或者直接作为一个静态值(称为位移量)规定或者由以下一个或多个成员通过计算得到地址:

  • 位移量:一个 8 位或 16 位值
  • 基地址:在通用寄存器中的值
  • 索引:在通用寄存器中的值

作为基地址或索引的通用寄存器限制如下:

  • SP 寄存器不能用作索引寄存器
  • SP 或 BP 寄存器用作为基地址,SS 段是默认的段
  • 在其他情况下 DS 段是默认段
3.2.1. 位移量

位移量代表操作数的直接(不计算)偏移。因为位移量是编码在指令中的,地址的这种形式称为绝对或静态地址。

EA = (DS << 4) + MASK
AX = [EA]
3.2.2. 基地址

单独一个基地址表示操作数的间接偏移量,因为在基地址寄存器(BX/BP)中的值能够改变,它能用于变量和数据结构的动态存储。

EA = (SS << 4) + BP
3.2.3. 基地址 + 位移量

以基址寄存器 BX 或 BP 的内容为基准地址,指令再给出一个地址位移量 D(D8或D16),它们组合而得存储器操作数的有效地址。

当使用 BP 作基址寻址时,若无指定段替换,则内定在堆栈段内寻址。

可以作为数组的索引,位移量作为到数组开始处的静态偏移,基地址寄存器来确定到数组中规定的元素的偏移。

可以用来访问记录中的一个字段,其中基地址寄存器保持记录的开始地址,而位移量是字段的静态偏移。

EA = (DS << 4) + SI + COUNT
3.2.4. 索引(变址)+ 位移量

当数组的元素是 2、4 或 8 字节时,这种地址方式为索引进入静态数组提供了有效的方法。位移量定位数组的开始,索引寄存器(即变址寄存器 SI/DI)保持所希望的数组元素的下标

EA = MASK + SI
3.2.5. 基地址 + 索引(变址)

用两个寄存器一起提供访问的存储单元的有效地址,即操作数的有效地址用一个基址寄存器(BX/BP)和一个变址寄存器(SI/DI)的内容之和表示。

在不使用段超越前缀的情况下,规定如果有效地址中含有 BP,则缺省的段寄存器为 SS;否则,缺省的段寄存器为 DS

EA = (SS << 4) + BP + SI
EA = (DS << 4) + BX + SI
3.2.6. 基地址 + 索引 + 位移量

两个寄存器和位移量一起提供访问的存储单元的有效地址,即操作数的有效地址用一个基址寄存器(BX/BP)中的内容和一个变址寄存器(SI/DI)中的内容,以及一个位移量的和表示。

EA = (DS << 4) + SI + BX + MASK

4. I/O 端口寻址

X86 支持 8 位 I/O 端口地址空间,I/O 接口的端口地址为 0000H ~FFFFH,共计 65536 个 I/O 端口。在 I/O 地址空间中也可以定义 16 位和 32位 的端口。

若端口地址为 00H~FFH,可以用立即数直接寻址;超出字节范围的端口地址必须存放在 DX 寄存器中,间接寻址。

  • I/O 端口用立即数寻址,只能用 8 位立即数,可寻址 I/O 地址空间的前 256 个端口
  • I/O 端口用 DX 寄存器间接寻址,可寻址全部 I/O 地址空间
IN AL, <端口地址/DX>
OUT <端口地址/DX>, AL

四. 8086 的通用指令

  • 指令
    • 一条指令对应一条基本操作。
    • 指令由操作码(OP)和操作数(OD)组成。
    • 操作码(OP)是指令操作功能,操作数(OD)是指令的操作数据。
  • 指令系统
    • 全部指令的集合。
    • 指令系统是计算机硬件实现软件编程的基础。
  • 字节/字
    • B : 字节 8 bit
    • W : 字 16 bit

1. 数据传送指令

助记符功能备注
通用数据传送指令MOV传送字节或字
^^PUSH字入栈SP <- SP - 2
^^POP字出栈SP <- SP + 2
^^XCHG交换字或字节
^^XLAT字节转换
地址目标传送指令LEA装入有效地址
^^LDS将指针变量装入寄存器及 DS
^^LES将指针变量装入寄存器及 ES
标志传送指令LAHF标志寄存器低字节送 AH
^^SAHFAH 值送标志寄存器低字节
^^PUSHF标志寄存器内容进栈
^^POPF标志寄存器内容出栈
I/O 指令IN输入字节或字IN AX, <端口地址/DX>
^^OUT输出字节或字OUT <端口地址/DX>, AX

2. 算术运算指令

助记符功能备注
加法指令ADD加法dest <- dest + src
^^ADC带进位的加法dest <- dest + src + CF
^^INC增量 1src <- src + 1
^^AAA加法的 ASCII 修正
^^DAA加法的十进制修正
减法指令SUB减法dest <- dest - src
^^SBB带借位的减法dest <- dest - src - CF
^^DEC减量 1src <- src - 1
^^NEG求补(变负)
^^CMP比较置位 AF CF OF PF SF ZF
^^AAS减法的 ASCII 修正
^^DAS减法的十进制修正
乘法指令MUL无符号乘法B : AX <- AX * src
^^IMUL整数乘法^^ W : DX:AX <- AX * src
^^AAM乘法的 ASCII 修正
除法指令DIV无符号除法B : AL <- AX / src, AH=余数
^^IDIV整数除法^^ W : AX <- DX:AX / src, DX=余数
^^AAD除法的 ASCII 修正
^^CBW字节转换为字
^^CWD字转换为字节

3. 逻辑运算和移位指令

助记符功能备注
逻辑运算指令ANDdest <- dest & src
^^ORdest <- dest 丨 src
^^NOTsrc <- ~src
^^XOR异或dest <- dest ^ src
^^TEST测试(与)仅改变标志位
移位指令SHL逻辑左移dest <- dest << src 移出位放入 CF
^^SAL算数左移dest <- dest << src 移出位放入 CF
^^SHR逻辑右移左侧补 0 移出位放 CF
^^SAR算术右移左侧补符号位 移出位放 CF
循环移位指令ROL循环左移直接将移出放入移入
^^ROR循环右移^^ 并将移出的位放入 CF
^^RCL通过 CF 循环左移将移出放入 CF
^^RCR通过 CF 循环右移^^ 并将 CF 放进移入

4. 控制转移指令

助记符功能备注
无条件跳转指令CALL调用过程(子过程)
^^RET从过程(子程序)返回
^^JMP无条件转移
条件跳转指令JA/JNBEJump above无符号
^^JAE/JNBJump above equal^^
^^JB/JNAEJump below^^
^^JBE/JNAJump below equal^^
^^JCJump CF == 1
^^JE/JZJump equal/zero
^^JG/JNLEJump greater带符号
^^JGE/JNLJump greater equal^^
^^JL/JNGEJump less^^
^^JLE/JNGJump less equal^^
^^JNCJump CF == 0
^^JNE/JNZJump not equal/zero
^^JNOJump not overflow
^^JNP/JPOJump PF == 0
^^JNSJump SF == 0
^^JOJump overflow
^^JP/JPEJump PF == 1
^^JSJump SF == 1
^^JCXZJump CX == 0
重复控制指令LOOP循环CX != 0 循环,CX--
^^LOOPE/LOOPZ等于/为零循环CF != 0 && ZF == 1
^^LOOPNE/LOOPNZ不等于/不为零循环CF != 0 && ZF == 0
中断指令INT中断
^^INT3断点中断
^^INTO溢出中断
^^IRET中断返回

5. 串操作指令

串指令对字节串、字串操作,允许它们移至存储器或从存储器传送;

基本串操作指令采用寄存器 SI 寻址源操作数,且假定是在现行的数据段区域中(段地址保存在段寄存器 DS 中);

采用寄存器 DI 寻址目的操作数,且假定是在现行的附加段区域中(段地址保存在段寄存器 ES 中);

[[undergraduate/Intel8086/c2-IA32-8086#^memory-organization]]

串操作时,地址指针会自动修改,具体由标志位 DF 控制。如 DF==1 则每次操作后 SIDI 自减;如 DF==0SIDI 自增。

助记符功能备注
串操作指令MOVS(MOVSB/MOVSW)串传送[ES:DI] <- [DS:SI]
^^CMPS(CMPSB/CMPSW)串比较FLAGS <- [DS:SI] - [ES:DI]
^^STOS(STOSB/STOSW)存入串FLAGS <- AX - [ES:DI]
^^LODS(LODSB/LODSW)取出串AX <- [DS:SI], SI=SI.next
^^SCAS(SCASB/SCASW)扫描串[ES:DI] <- AX, DI=DI.next
^^INS(INSB/INSW)输入串[ES:DI] <- [DX]
^^OUTS(OUTSB/OUTSW)输出串[DX] <- [DS:SI]
重复前缀REP重复操作
^^REPE/REPZ等于/为零重复
^^REPNE/REPNZ不等于/不为零重复
实现 100 个操作数的传送

利用循环

MOV SI, OFFSET SOURCE
MOV DI, OFFSET DEST ; 获取操作数开始地址
MOV CX, 100 ; 计数器设置
AGAIN: MOVS DEST, SOURCE ; 数据传送
DEC CX ; 计数器设置
JNZ AGAIN ; 非零则继续循环

利用重复前缀

MOV SI, OFFSET SOURCE
MOV DI, OFFSET DEST ; 获取操作数开始地址
MOV CX, 100 ; 计数器设置
REP MOVS DEST, SOURCE ; 采用REP重复前缀

^repeat-op

6. 处理器控制指令

助记符功能
标志操作STCCF = 1
^^CLCCF = 0
^^CMCCF = ~CF
^^STDDF = 1
^^CLDDF = 0
^^STIIF = 1
^^CLIIF = 0
外同步HLT暂停直至中断或复位
^^WAIT等待 TEST 信号有效
^^ESC交权给外部处理机
^^LOCK在下一条指令期间封锁总线
空操作NOP空操作