通用寄存器
8086 CPU的所有寄存器都是16位的,可以存放2个字节。
AX、BX、CX、DX这4个寄存器通常用来存放一般性的数据,被称为通用寄存器
处于对兼容性的考虑,8086 CPU可以一次性处理一下两者尺寸的数据
- 字节:记为byte,一个字节由8个bit组成,可以存储在8位寄存器中。
- 字:记为word,一个字由两个字节组成,这两个字节分别称为这个字的高位字节和低位字节。
段寄存器
CS和IP
CS是代码段寄存器,IP是指令指针寄存器。CS:IP只想的内容当做指令执行
jmp指令可以修改CS IP的值,格式为 "jmp 短地址:偏移地址"
如: jmp 2AE3:3,执行后:CS=2AE3H,IP=0003H,CPU将从2AE33H出读取指令。
如果仅修改IP的内容,可以用"jmp 某一合法寄存器"的指令完成,其功能为:用寄存器中的值修改IP
如:
jmp ax,指令执行前:ax=1000H,CS=2000H,IP=0003H
指令执行后:ax=1000H,CS=2000H,IP=1000H
jmp bx,指令执行前:bx=0B16H,CS=2000H,IP=0003H
指令执行后:ax=0B16H,CS=2000H,IP=0B16H
DS和[address]
mov bx, 1000H // 把1000H放到寄存器bx中
mov ds, bx // 把bx的值放到ds中,也就是1000H
mov al, [0] // [...]表示一个内存单元,中括号中的值表示偏移地址,那么基地址(段地址)在哪里呢,8086 CPU会自动取ds中数据作为内存单元的段地址
// 所以这段汇编指令最终就是将 1000:0 中数据读入al中,为什么不直接把1000H放入ds呢?8086 CPU不支持 mov ds,1000H,所以需要一个寄存器中转
mov、add、sub指令
mov指令有一些集中形式
mov 寄存器, 数据 // mov ax, 8
mov 寄存器, 寄存器 // mov ax, bx
mov 寄存器, 内存单元 // mov ax, [0]
mov 内存单元, 寄存器 // mov [0], ax
mov 段寄存器, 寄存器 // mov ds, ax
mov 寄存器, 段寄存器 // mov ax, ds
mov 内存单元, 段寄存器
mov 段寄存器, 内存单元
add指令有一些集中形式
add 寄存器, 数据 // add ax, 8
add 寄存器, 寄存器 // add ax, bx
add 寄存器, 内存单元 // add ax, [0]
add 内存单元, 寄存器 // add [0], ax
sub指令有一些集中形式
sub 寄存器, 数据 // sub ax, 8
sub 寄存器, 寄存器 // sub ax, bx
sub 寄存器, 内存单元 // sub ax, [0]
sub 内存单元, 寄存器 // sub [0], ax
栈
8086 CUP提供入栈和出栈指令,最基本的两个第PUSH和POP,如push ax表示将寄存器ax中的数据送入栈中,pop ax表示从栈顶取出数据送入ax中,8086CUP的入栈和出栈操作都是以字为单位进行的。栈顶的段地址存放在SS中,偏移地址存放在SP中,任意时刻,SS:SP 指向栈顶元素 ,push指令和pop指令执行时,CUP从SS和SP中得到栈顶地址。
注意栈超界问题,8086CPU不会检查栈边界,push和pop都可能超界,需要编程人员自己注意不要超界
push和pop的一些格式
push 寄存器 // 将一个寄存器中的数据入栈
pop 寄存器 // 将栈顶元素放入寄存器中
push 段寄存器
pop 段寄存器
push 内存单元 // 将一个内存字单元出的字入栈(注意:栈操作都是以字为单位)
pop 内存单元
描述性的符号 "()"
使用描述性符号"( )"表示一个寄存器或内存单元中的内容
如:(ax)表示ax中的内容,(20000H)表示内存20000H单元的内容。
((ds)16+(bx))表示 ds中的内容16+bx中的内容。
"( )"中的元素可以有3中类型:1、寄存器名 2、段寄存器名 3、内存单元的物理地址(一个20位数据)
约定符号 idata 表示常量
[bx]
mov ax, [bx]
功能:bx中存放的数据作为一个偏移地址EA,段地址SA默认在ds中,
将SA:EA处的数据送入ax中,即:(ax)=((ds)*16+(bx))
Loop指令
loop指令的格式是:loop 标号,CUP执行loop指令的时候,要进行两步操作,1、(cx)=(cx)-1; 2、判断cx中的值,不为0则专指标号处执行程序,如果为0则向下执行。cx中通常存放循环次数
例:计算2^12
assume cs:code
code segment
mov ax, 2
mov cx, 11 // 循环次数,除了第一次执行外,还要循环11次,共12次
s: add ax, ax // 标号
loop s // loop
mov ax, 4c00h
int 21h
code ends
end
CPU在执行 loop s的时候,要进行两步操作:
1、(cx)=(cx)-1
2、判断 cx 中的值,不为 0 则专指标号s锁标识的地址出执行,如果为0则执行下一条指令
[bx+idata]
[bx+idata] 表示一个内存单元,它的偏移地址为(bx)+idata
mov ax, [bx+200]
表示将一个内存单元的内容送入ax,这个内存单元的的长度为2个字节(字单元),存放一个字,偏移地址为bx中的数值加上200,段地址在ds中。
数学化描述为:(ax)=((ds)*16+(bx)+200)
SI和DI
si和di是8086cpu中和bx功能相近的寄存器,si和di不能够分成两个8位寄存器来使用。
[bx+si]和[bx+di]
mov ax, [bx+si]
将一个内存单元的内容送入ax,这个内存单元的长度为2字节(字单元),存放一个字,偏移地址为bx中的数值加上si中的数值,段地址在ds中。
数学化描述为:(ax)=((ds)*16+(bx)+(si))
该指令也可以写成如下格式(常用):
mov ax, [bx][si]
[bx+si+idata]和[bx+di+idata]
mov ax, [bx+si+idata]
将一个内存单元的内容送入ax,这个内存单元的的长度为2字节(字单元),存放一个字,偏移地址为bx中的数值加上si中的数值再加上idata,段地址在ds中。
数学化描述为:(ax)=((ds)*16+(bx)+(si)+idata)
该指令也可以写成如下格式(常用):
mov ax, [bx+200+si]
mov ax, [200+bx+si]
mov ax, 200 [bx] [si]
mov ax, [bx] .200 [si]
mov ax, [bx] [si] .200
不同寻址方式的灵活运用
###寻址方式 当数据存放在内存中的时候,我们可以用多种方式来给定这个内存单元的偏移地址,这种定位内存单元的方法一般被称为寻址方式。
指令要处理的数据有多长
- 通过寄存器名指明要处理的数据的尺寸
- 在没有寄存器名存在的情况下,用操作符 X ptr 指明内存单元的长度,X在汇编指令中可以为word或byte
- 其他方法
div指令
div是处方指令,使用div做除法的时候应注意以下问题。
伪指令dd
db用来定义字节型数据
dw用来定义字型数据
dd用来定义dword(double word,双字)型数据
dup
dup是一个操作符,在汇编语言中同db、dw、dd等一样,也是有编译器识别处理的符号。和db、dw、dd等数据定义伪指令配合使用,用来进行数据的重复
如:db 3 dup (0)
定义了三个字节,它们的值都是0,相当于 db 0,0,0
db 3 dup (0,1,2)
定义了9个字节,它们是0,1,2,0,1,2,0,1,2,相当于 db 0,1,2,0,1,2,0,1,2