8086CPU寄存器
8086:16位,4.77MHz~10MHz,16根数据线,20根地址线
AX/AL:乘除法指令中用作累加器,IO指令中用作数据寄存器,可显式或隐含调用
AH:在LAHF用作目的寄存器,隐含调用。
AL:在BCD码用做累加器,隐含调用。
BX:在存储器寻址用作地址/基址寄存器,显式调用。在XALT用作基址寄存器,隐含调用
CX:循环计数器,隐含
CL:在移位、循环移位中用作移位次数,显式
DX:在I/O指令用作地址寄存器,显式调用。在乘除法用作辅助累加器,隐含调用
BP:堆栈段基址寄存器,显式。
SP:堆栈指针,隐含
SI:字符串操作源地址寄存器,隐含。存储器寻址用作地址寄存器,显式。
DI:字符串操作目的变址寄存器,隐含。存储器寻址用作地址寄存器,显式。
CS:代码段寄存器。
SS:堆栈段
DS:数据段
ES:附加段
IP:即将执行的指令的偏移地址,不能读/显式设定
PSW:
15~12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
OF | DF | IF | TF | SF | ZF | AF | PF | CF | ||||
overflow | 指针方向 | 中断 | 单步 | sign | zero | 辅助进位 | 最低位字节“1“个数 | carry | ||||
IF=1,允许中断 | TF=1,单步 | 低4位对高四位进位 | 为偶数时PF=1 |
CLI/STI:执行CLI,IF=0。执行STI,IF=1。
存储空间:按字节编址,
2
20
2^{20}
220=1MB寻址空间,00000H~FFFFFH,小端存储(低位低字节,高位高字节)。段:0000H~FFFFH(64KB),每个逻辑段最大64KB。
物理地址:物理地址=段地址:偏移地址。物理地址=段地址*16+偏移地址,各段可能重叠
段:CS:IP为即将执行的指令,SS:SP为栈顶,DS:EA为数据段,ES:EA为附加段。
8086的控制与时序
引脚:
M
N
/
M
X
‾
MN/\overline{MX}
MN/MX为工作模式,接+5V为最小模式。最大模式可接8087/8089等协处理器。控制由总线控制器8288提供。接地为最大模式,不含协处理器。
RST:复位,高有效
Ready:就绪,输入,高有效。
AD15~AD0:地址/数据复用信号,地址三态输出,数据三态双向。
M
/
I
O
‾
M/\overline{IO}
M/IO:三态,选内存/外设。
R
D
‾
\overline{RD}
RD:三态,低有效,读
W
R
‾
\overline{WR}
WR:三态,低有效,写
ALE:输出,地址锁存允许,正脉冲下降沿锁存地址。
D
T
/
R
‾
DT/\overline{R}
DT/R:三态输出,=1时发送数据,=0时接收数据。
D
E
N
‾
\overline{DEN}
DEN:三态低有效,表明AD15~AD0在传数据。
**
B
H
E
‾
/
S
7
\overline{BHE}/S_7
BHE/S7:三态输出,分时复用,为0时,
D
15
D_{15}
D15~
D
8
D_8
D8位有效
S6S5:S6=0,S5=IF
A
19
A_{19}
A19~
A
16
A_{16}
A16/
S
6
S_6
S6~
S
3
S_3
S3:地址状态复用
S
4
S
3
S_4S_3
S4S3:段。00ES,01SS,10CS,11DS
D
15
D_{15}
D15~
D
8
D_8
D8连奇体,
D
7
D_7
D7~
D
0
D_0
D0连偶体。从奇地址读一个字,需要2个总线周期。
B H E ‾ \overline{BHE} BHE | A 0 A_0 A0 | |
---|---|---|
0 | 0 | 从偶读字, A D 15 AD_{15} AD15~ A 0 A_0 A0 |
0 | 1 | 从奇读字节, A D 15 AD_{15} AD15~ D 8 D_8 D8 |
1 | 0 | 从偶读字节, A D 7 AD_{7} AD7~ D 0 D_0 D0 |
1 | 1 | 高阻 |
总线形成:8284时钟、3个8282地址锁存,2个8286数据收发,直接提供控制。
INTR输出高有效,IF=1时相应中断请求。
I
N
T
A
‾
\overline{INTA}
INTA输出,中断响应
NMI输入,上升沿有效,不可屏蔽中断请求。
输出:
A
D
15
AD_{15}
AD15~
A
D
0
AD_0
AD0,
A
19
/
S
6
A_{19}/S_6
A19/S6~
A
16
/
S
3
A_{16}/S_3
A16/S3时,20位地址被3片8282锁存,并锁存
B
H
E
‾
\overline{BHE}
BHE.
8286T与
D
T
/
R
‾
DT/\overline{R}
DT/R相连,
O
E
‾
\overline{OE}
OE与
D
E
N
‾
\overline{DEN}
DEN相连,允许数据通过。
三种周期:时钟周期、总线周期、指令周期(多个总线)
总线读周期
执行MOV AX,[BX]
T
1
T_1
T1:
M
/
I
O
‾
M/\overline{IO}
M/IO变高,对内存操作。
A
19
A_{19}
A19~
A
0
A_0
A0地址信号,
B
H
E
‾
/
S
7
\overline{BHE}/S_7
BHE/S7变低)(数据高8位有效),ALE正脉冲,
D
T
/
R
‾
DT/\overline{R}
DT/R变低(数据收发器接收)
T
2
T_2
T2:
A
19
A_{19}
A19~
A
16
A_{16}
A16状态信号,
A
D
15
AD_{15}
AD15~
A
D
0
AD_0
AD0高阻,
R
D
RD
RD低(读内存),
D
E
N
‾
\overline{DEN}
DEN低(允许收发器传送)
T
3
T_3
T3:
A
D
15
AD_{15}
AD15~
A
D
0
AD_0
AD0出现数据
T
4
T_4
T4:
R
D
‾
\overline{RD}
RD高,CPU读。
D
E
N
‾
\overline{DEN}
DEN高,收发器与总线断开。
总线写周期
执行MOV[DI],BL(写8位而不是16位)
T
1
T_1
T1:
D
T
/
R
‾
DT/\overline R
DT/R变高,数据收发器发,
B
H
E
‾
/
S
7
\overline{BHE}/S_7
BHE/S7高,高8位无效(与网上找的图有区别,注意具体问题具体分析)
T
2
T_2
T2:
W
R
‾
\overline{WR}
WR低,CPU将写。
A
D
15
AD_{15}
AD15~
A
D
8
AD_8
AD8变高阻,
D
E
N
‾
\overline{DEN}
DEN低(
T
2
T_2
T2已经发数据
D
7
D_7
D7~
D
0
D_0
D0),读时
T
3
T_3
T3才有数据区别。
T
3
T_3
T3:维持不变
等待状态
T
w
T_w
Tw:1.在
T
3
T_3
T3前沿检测Ready是否有效。2.若Ready无效,在
T
3
T_3
T3和
T
4
T_4
T4之间插入
T
w
T_w
Tw,转1。3.若Ready有效,进入
T
4
T_4
T4
T
4
T_4
T4:\overline{WR}高,CPU写
其余类似
模板与变量
调试流程:编辑(.asm),汇编(.obj),连接(.exe),执行。
调试debug模式下所有数据16进制。
伪指令:参数是常量、变量名,参数间用逗号分隔
模板:
.model small
.stack 100
.data
;//数据区
.code
start:
mov ax,@data
mov ds,ax
;//逻辑代码
mov ax,4c00h
int 21h
end start
字符量值为ASCII码
‘0’=30H,‘A’=41H,‘Z’=5AH,‘a’=61H,‘z’=7AH
八进制后缀Q,
符号名 EQU 数值表达式
在汇编前就被计算
变量:DB 字,DW 字节,DD 双字,DQ 8byte,DT 10byte
重复次数 dup (重复内容)
指令
寻址
指令格式:op dst src
立即寻址:操作数在指令中
寄存器寻址:用作dst,src
,除了IP、PSW,都可以寄存器寻址。CS不能为dst
存储器寻址:dst和src不能同为存储器寻址
直接寻址:EA=8/16位位移量,例如:MOV AX,[2000H]
寄存器间接寻址:EA=BX/BP/SI/DI。例如:MOV AX,[BX]
寄存器相对寻址:EA=BX/BP/SI/DI+8/16位。例如:MOV AX,06H[SI]
基址变址寻址:EA=BX/BP+SI/DI。例如:MOV AX,[BP][SI]
相对基址变址寻址:EA=BX/BP+SI/DI+8/16位移量
使用BP时,隐含段位SS。其余隐含段为DS。允许段超越。
EA可为数值,可为变量名(符号地址)
(CS,IP)不为目的操作数。数据类型要一致。
例如,MOV [BX][SI],1
错误,类型不明确。
XCHG OPR
1
_1
1 OPR
2
_2
2交换数值(不能同为mem,不能用seg、ip、imm)
XLAT
:AL
←
\leftarrow
←[(BX)+(AL)]
堆栈从较大地址分配使用,向上生长。
PUSH src
:SP
←
\leftarrow
←SP-2
,((SP)+1,(SP))
←
\leftarrow
←src
(不能同为imm),必须16位
POP dst
:dst
←
\leftarrow
←((SP)+1,(SP))
,SP
←
\leftarrow
←SP+2
,CS不能为dst
LEA reg,src
,reg不为seg,src必须为mem(lea传送地址,mov传送内容)
LDS
:reg
←
\leftarrow
←src
,dst
←
\leftarrow
←src+2
。src:reg,mem,imm。dst:mem,reg
pushf/popf:保存/恢复主程序flag
运算
CBW
:AL
→
\rightarrow
→AX
,CBW
:AX
→
\rightarrow
→DX,AX
加减法:OP dst,src
,src和dst不能同为reg/为seg
INC
不影响CF。
求补:NEG opr
(opr
←
\leftarrow
← 0-opr)
乘法:无符号数为MUL src
,有符号数为IMUL src
,src为reg/mem。为mem时,明确类型用ptr。
MUL:
{
C
F
,
O
F
=
00
高
位
为
0
11
否
则
\begin{cases}CF,OF=00&高位为0\\11&否则\end{cases}
{CF,OF=0011高位为0否则
IMUL:
{
C
F
,
O
F
=
00
高
位
为
低
一
半
符
号
扩
展
11
否
则
\begin{cases}CF,OF=00&高位为低一半符号扩展\\11&否则\end{cases}
{CF,OF=0011高位为低一半符号扩展否则
无符号除:DIV src
。有符号除:IDIV src
NOT不影响flag。其余逻辑运算清零CF/OF,但SF/PF/ZF根据结果设置。
移位:OP dst,src
其中src为1或CL。dst为mem且应当指明类型。左移为*2,右移为/2。带进位循环移位可实现高精度。
##
转移
转移:直接寻址(标号)、间接寻址(reg、mem)
JMP short
8位,
JMP 标号
:IP
←
\leftarrow
←IP+label
相对于当前IP偏移,CS不变
JMP NEAR PTR 标号
:16位范围,不包含byte/dword,为word
JMP FAR PTR 标号
:IP
←
\leftarrow
←offset next
,CS
←
\leftarrow
←seg next
无符号数:JB/JC/JNAE
低于,JNB/JAE/JNC
高于等于,JBE/JNA
低于等于,JNBE/JA
高于
有符号数:JL/JNGE
小于,JNL/JGE
大于等于,JLE/JNG
小于等于,JNLE/JG
大于
JCXZ
CX=0则转移,JE
相等,JNE
不相等,JP
PF=1则转移(1的个数为偶数)
LOOP
:只短转移
LOOP opr
:CX
≠
\ne
= 0
LOOPZ opr
(ZF=1且CX
≠
\ne
= 0)
LOOPNZ opr
(ZF=0且CX
≠
\ne
= 0)
LOOP
相当于:
DEC CX
JNZ 标号
子程序
CALL
子程序名(段内直接调用):SP
←
\leftarrow
←SP-2
,(SS:IP)
←
\leftarrow
←IP
,IP
←
\leftarrow
←子程序
RET
:(IP)
←
\leftarrow
←(SS:IP)
,(SP)
←
\leftarrow
←(SP)+2
RET n
:(IP)
←
\leftarrow
←(SS:IP)
,(SP)
←
\leftarrow
←SP+2+n
段间调用
call
子程序名
(SP)
←
\leftarrow
←(SP-2)
(SS:SP)
←
\leftarrow
←(CS)
(IP)
←
\leftarrow
←子程序入口
(CS)
←
\leftarrow
←子程序段
(先压段后压偏移)
段间返回
ret
(IP)
←
\leftarrow
←(SS:SP)
(SP)
←
\leftarrow
←(SP)+2
(CS)
←
\leftarrow
←(SS:SP)
(SP)
←
\leftarrow
←(SP)+2
先取偏移后取段
ret n
:在csn出栈还会(SP)
←
\leftarrow
←(SP)+n
I/O中断
物理地址=类型码*4
中断类型码/中断向量号 0~255
每个中断向量4byte,高字CS,低字IP
int:将flag入栈,清除TF、IF。CS入栈,IP入栈,最后跳转
into:检测OF。若溢出,中断类型码为4
iret:IP出栈、CS出栈,恢复flags
控制:hlt(停止) nop(空操作) wait(等到test=0)
I/O调用:参数装入指定reg,功能号装入AH
子功能装入AL,调用,返回。
int 21H:
AH | 功能 | 参数 | 返回 |
---|---|---|---|
1 | 输入字符,回显 | 无 | AL=字符 |
6 | 读字符,回显 | DL=0FFH | AL=字符,ZF=0。若无字符,AL=0,ZF=1 |
7 | 输入字符,不回显 | 无 | AL=字符 |
A | 输入字符到缓冲区 | DS:DX=缓冲区首地址 | |
2 | 显示字符一个(检验ctrl-break) | DL=字符ASCII | |
9 | 显示字符串 | DS:DS=串首地址,以$结束 |
0DH:回车(光标回到本行第一个字符)
0AH:换行
输出文字
lea bx,string
mov cx,7;7为长度
one:mov dl,cs:[bx]
mov ah,2
int 21H
inc bx
loop one
string db "hello"
end start
输出串
lea dx,string
mov ah,9
int 21h
string db 0DH,0AH,"hello",0DH,0AH,'$'
输入5个数
mov cx,5
mov sum,0
one:mov ah,1
int 21h
and al,0fh
add sum,al
loop one
从键盘输入至多5个数
lea dx,buffer
mov ah,0ah
int 21H
mov sum,0
mov cl,buffer+1
mov ch,0
lea bx,buffer+2
one:
mov al,[bx]
and al,0fh
add sum,al
inc bx
loop one
程序逻辑语句
双分支结构一定要跳过另一个分支体。
大小写字母ASCII码差值20H,仅
D
5
D_5
D5位不同。
用地址表实现多分支转移。数据段:addtbl dw f1,f2,f3
程序段:jmp addtbl[bx]
循环:
do-while型初始化、工作、修改、控制。
while型循环:初始化、控制、跳出、工作、修改、跳回控制。
无符号字数组以-1为结束,求平均值
lea bx,array
one:cmp word ptr[bx],-1
je done;//数组结束
add ax,[bx]
adc dx,0;保留进位
inc cx;//数组元素个数
add bx,2
jmp one
done:jcxz null
div cx
mov avg,ax
jmp exit
null:mov avg,-1
用 N 2 = 1 + 3 + . . . + ( 2 N − 1 ) N^2=1+3+...+(2N-1) N2=1+3+...+(2N−1)求平方根
square proc near
push cx
push bx
mov bx,ax;要求的数
mov al,0
mov cx,1
next:sub bx,cx
jb done
inc al
add cx,2
jmp next
done:
pop bx
pop cx
ret
square endp
可以自带数据区,在ret后、endp前,用cs段超越
表达式计算:
Z
=
100
(
X
/
Y
+
W
)
+
R
Z=100(X/Y+W)+R
Z=100(X/Y+W)+R
mov ax,x
cwd
idiv y
add ax,w
mov bx,100
imul bx
mov cx,ax
mov bx,dx
mov ax,r
cwd
add ax,cx
adc dx,bx
mov z,ax
mov z+2,dx
中断服务程序示例
point dw 0
temp db 500 dup(?)
intproc proc far
push ds
push ax
sti
mov ax,seg temp
mov ds,ax
mov bx,point
in al,60H
mov temp[bx],al
int pont
cli
mov al,20H
out 20H,al
pop ax
pop ds
iret
intproc endp