第 3 章 8086
一. 基本数据类型
1. 字、双字的对齐
数据保存在内存时一个单元存放一个字节
数据保存时低字节(0~7位)占用内存中的低地址,此地址就是操作数的地址
在进行数据保存时,字和双字在内存中尽量做到对齐自然边界
对于不对齐的存储访问,处理器要求做两次存储访问操作;而对于对齐的访问,只要做一次存储访问操作。
2. 数字数据类型
2.1. 无符号整数
2.2. 带符号整数
3. 指针数据类型
3.1. 近指针
16 位,分段存储模式中用于同一段内的存储器引用
3.2. 远指针
32 位,分段存储模式中的跨段存储引用
4. 串数据类型
串是位、字节、字或双字的连续序列
二. 8086 的指令格式
[<标号>: ] | <指令助记符> | [<操作数>] | [; <注释>] |
---|---|---|---|
LOADREG: | MOV | AX, BX | ; AX <- AX + BX |
8086机器指令包含零个或多个操作数。某些操作数是显式规定的,有的是指令中隐含的(eg. 偏移地址)。操作数能定位在 立即数
寄存器
存储单元
I/O 端口
中
指令中并不直接给出操作数的数值,而给出操作数存放的地址、寄存器的地址或存储单元的地址。操作数的地址也不直接给出,给出计算方法。
三. 8086 指令的操作数寻址方式
1. 立即数
大部分算术指令均允许源操作数是立即数,但 DIV
和 IDIV
等不允许源操作数是立即数
2. 寄存器寻址
操作数在寄存器中,寄存器的内容就是操作数的数值,操作数用寄存器的符号来表示
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. 位移量
位移量代表操作数的直接(不计算)偏移。因为位移量是编码在指令中的,地址的这种形式称为绝对或静态地址。
3.2.2. 基地址
单独一个基地址表示操作数的间接偏移量,因为在基地址寄存器(BX/BP)中的值能够改变,它能用于变量和数据结构的动态存储。
3.2.3. 基地址 + 位移量
以基址寄存器 BX 或 BP 的内容为基准地址,指令再给出一个地址位移量 D(D8或D16),它们组合而得存储器操作数的有效地址。
当使用 BP 作基址寻址时,若无指定段替换,则内定在堆栈段内寻址。
可以作为数组的索引,位移量作为到数组开始处的静态偏移,基地址寄存器来确定到数组中规定的元素的偏移。
可以用来访问记录中的一个字段,其中基地址寄存器保持记录的开始地址,而位移量是字段的静态偏移。
3.2.4. 索引(变址)+ 位移量
当数组的元素是 2、4 或 8 字节时,这种地址方式为索引进入静态数组提供了有效的方法。位移量定位数组的开始,索引寄存器(即变址寄存器 SI/DI)保持所希望的数组元素的下标
3.2.5. 基地址 + 索引(变址)
用两个寄存器一起提供访问的存储单元的有效地址,即操作数的有效地址用一个基址寄存器(BX/BP)和一个变址寄存器(SI/DI)的内容之和表示。
在不使用段超越前缀的情况下,规定如果有效地址中含有 BP,则缺省的段寄存器为 SS;否则,缺省的段寄存器为 DS。
3.2.6. 基地址 + 索引 + 位移量
用两个寄存器和位移量一起提供访问的存储单元的有效地址,即操作数的有效地址用一个基址寄存器(BX/BP)中的内容和一个变址寄存器(SI/DI)中的内容,以及一个位移量的和表示。
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 地址空间
四. 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 | |
^^ | SAHF | AH 值送标志寄存器低字节 | |
^^ | PUSHF | 标志寄存器内容进栈 | |
^^ | POPF | 标志寄存器内容出栈 | |
I/O 指令 | IN | 输入字节或字 | IN AX, <端口地址/DX> |
^^ | OUT | 输出字节或字 | OUT <端口地址/DX>, AX |
2. 算术运算指令
助记符 | 功能 | 备注 | |
---|---|---|---|
加法指令 | ADD | 加法 | dest <- dest + src |
^^ | ADC | 带进位的加法 | dest <- dest + src + CF |
^^ | INC | 增量 1 | src <- src + 1 |
^^ | AAA | 加法的 ASCII 修正 | |
^^ | DAA | 加法的十进制修正 | |
减法指令 | SUB | 减法 | dest <- dest - src |
^^ | SBB | 带借位的减法 | dest <- dest - src - CF |
^^ | DEC | 减量 1 | src <- 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. 逻辑运算和移位指令
助记符 | 功能 | 备注 | |
---|---|---|---|
逻辑运算指令 | AND | 与 | dest <- dest & src |
^^ | OR | 或 | dest <- dest 丨 src |
^^ | NOT | 非 | src <- ~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/JNBE | Jump above | 无符号 |
^^ | JAE/JNB | Jump above equal | ^^ |
^^ | JB/JNAE | Jump below | ^^ |
^^ | JBE/JNA | Jump below equal | ^^ |
^^ | JC | Jump CF == 1 | |
^^ | JE/JZ | Jump equal/zero | |
^^ | JG/JNLE | Jump greater | 带符号 |
^^ | JGE/JNL | Jump greater equal | ^^ |
^^ | JL/JNGE | Jump less | ^^ |
^^ | JLE/JNG | Jump less equal | ^^ |
^^ | JNC | Jump CF == 0 | |
^^ | JNE/JNZ | Jump not equal/zero | |
^^ | JNO | Jump not overflow | |
^^ | JNP/JPO | Jump PF == 0 | |
^^ | JNS | Jump SF == 0 | |
^^ | JO | Jump overflow | |
^^ | JP/JPE | Jump PF == 1 | |
^^ | JS | Jump SF == 1 | |
^^ | JCXZ | Jump 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
则每次操作后 SI
和 DI
自减;如 DF==0
则 SI
和 DI
自增。
助记符 | 功能 | 备注 | |
---|---|---|---|
串操作指令 | 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 个操作数的传送
利用循环
利用重复前缀
^repeat-op
6. 处理器控制指令
助记符 | 功能 | |
---|---|---|
标志操作 | STC | CF = 1 |
^^ | CLC | CF = 0 |
^^ | CMC | CF = ~CF |
^^ | STD | DF = 1 |
^^ | CLD | DF = 0 |
^^ | STI | IF = 1 |
^^ | CLI | IF = 0 |
外同步 | HLT | 暂停直至中断或复位 |
^^ | WAIT | 等待 TEST 信号有效 |
^^ | ESC | 交权给外部处理机 |
^^ | LOCK | 在下一条指令期间封锁总线 |
空操作 | NOP | 空操作 |