@
目录- 第二讲 内存与寄存器
- 第五讲 循环程序与多段程序
- 第六讲 寻址方式
- 第七讲 寻址方式的应用
- 第八讲 指令的转移和应用
- 第九讲 模块化程序设计
- 第十讲 标志寄存器及其应用
- 第十一讲 直接定址表
- 第十二讲 内中断及其处理
第二讲 内存与寄存器
1.2 机器语言到汇编语言
1.3 计算机的组成
- 总线
1.4 内存的读写与地址空间
第五讲 循环程序与多段程序
5.1 段前缀的使用
-
引入段前缀原因
mov al,[0] //将【0】当作常熟0 引用
对策:段前缀 ds:[bx] -
访问连续单元8位累加
解决mov al, ds:[addr] mov ah,0 add dx,ax
-
es 扩展段寄存器
5.2 在代码段中使用数据
- 程序中直接写地址 危险!
在段中存放数据
dw 字型数据 db字节型数据 - 例:编程计算以下8个数的和,结果放入ax中
assume cs:code
code segment
dw 0123H,0456H,0789H,0abcH,0defH,0fedH //dw 字型数据 db字节型数据
start: mov bx,0 //程序入口
mov ax,0
mov cx,6
s: add ax,cs:[bx]
add bx,2
loop s
mov ax,4c00h
int 21h
code ends
end start
5.2 在代码段中使用栈
- 栈的使用
- 逆序存放数据
assume cs:code
code segment
dw 0123H,0456H,0789H,0abcH,0defH,0fedH //dw 自行数据 db字节型数据
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
start: mov ax,cs
mov ss,ax //栈底指针
mov sp,30h //栈指针
mov bx,0
mov cx,6
s: push cs:[bx]
add bx,2
loop s
mov bx,0
mov cx,6
ss: pop cs:[bx]
add bx,2
loop ss
mov ax,4c00h
int 21h
code ends
end start
5.3把数据、代码、栈、放入不同段
assume cs:code, ds:data, ss:stack
data segment
dw 0123H,0456H,0789H,0abcH,0defH,0fedH //dw 自行数据 db字节型数据
data ends
stack segment
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
stack ends
code segment
start: mov ax,stack //初始化各寄存器
mov ss,ax //栈底指针
mov sp,30h //栈指针
mov ax,data
mov ds,ax
mov bx,0
mov cx,6
s: push [bx] //入栈
add bx,2
loop s
mov bx,0
mov cx,6
s: pop [bx] //出栈
add bx,2
loop s
mov ax,4c00h
int 21h
code ends
end start
第六讲 寻址方式
6.1 处理字符问题
- 用 ' ' 的方式指明数据以字符方式给出,编译器将他们转化为相应的ACSCII码。
- 大小写转换
ASCII值 小写 比 大写 大 20H(10 0000) - 小写转大写:
and al,11011111B
大写转小写:
or al,00100000B
6.2 [bx+idata]寻址
- [bx+idata]的含义
(1)mov ax,[bx+200] / mov ax,[200+bx]
(ds)*16+200+bx
(2)其他写法
mov ax,[200+bx]
mov ax,200[bx]
mov ax,[bx].200 - 用[bx+idata]进行数组处理
对两个段进行同步操作
6.3 SI和DI寄存器
- 变址寄存器
SI(原变址寄存器)和DI(目标变址寄存器)与BX功能相近
SI和DI与BX不同处:不可分成两个8位寄存器 - 应用SI和DI
将welcome to masm 复制到后边数据区
assume cs:code ,ds:data
data segment
db 'welcome to masm'
db '...............'
data ends
code segment
start:mov ax,data
mov ds,ax
mov si,0
mov di,16
mov cx,8
S:mov ax,[si]
mov [di],ax
add si,2
add di,2
loop s
mov ax,4c00h
int 21h
code ends
end start
end
6.4 [bx+si]和[bx+di]方式指定地址
- [bx+si]表示一个内存单元
mov ax,[bs+si]
表示:(ax)=((ds)*16+(bx)+(si))
mov ax,[bx][si] - [bx+si+idata]
6.5 寻址方式的灵活应用
2. 二重循环
(1)将外层循环暂时保存在一个通用寄存器中
(2)用固定的内存空间保存数据 ds:[40H]
(3) 用栈保护数据 将外层循环cx压栈,结束后都栈顶弹出cx值
第七讲 寻址方式的应用
7.1 用于内存寻址的寄存器
- 通用寄存器:AX BXCX DX
变址寄存器:SI DI
指针寄存器:SP BP
指令寄存器:IP
段寄存器: CS SS DS ES
标志寄存器:PSW - [BX] [SI] [DI] [BP]可单独使用
BX/BP作为基址
SI/DI作为变址 - BX默认指ds段
BP默认指ss段
指定:mov ax,ds:[bp]
默认:mov ax,[bp]
7.2 数据位置与大小
- 数据位置的表达
立即数 | 寄存器 | 内存:段地址和偏移地址 |
---|---|---|
直接包含在机器指令中的数据 | 指令要处理的数据在寄存器中,汇编指令中给出相应的寄存器名 | 指令要处理的数据在内存中,由SA:EA确定内存单元 |
mov ax,1 | mov ax,bx | mov ax,bp[si] |
- 数据长度
字操作 | 字节操作 | 用word ptr或byte ptr 指明 |
---|---|---|
mov ax,1 // mov ax,bx | mov al,1 // mov al,bl | mov word ptr ds:[0],1 inc byte word ptr [bx] |
在没有寄存器参与时,用word ptr 或byte ptr 显性指明大小
7.3 寻址方式的综合应用
- 问题
- 解决方案
mov ax,seg
mov ds,ax
mov bx,60h
mov word ptr [bx+10h+si],'h'
inc si
mov byte ptr [bx+10h+si],'o'
inc si
mov byte ptr [bx+10h+si],'u'
7.4 div指令实现除法
- div除法指令
被除数默认放在AX或DX和AX中
除数8位或者16位在寄存器或内存单元中 - 格式
div 寄存器
div内存单元
被除数 | AX | DX和AX |
---|---|---|
除数 | 8位内存或寄存器 | 16位内存或寄存器 |
商 | AL | AX |
余数 | AH | DX |
-
div bl
被除数:(ax)
除数: (bl)
商: (al)
余数: (ah)div bx
被除数:(dx)*10000h+(ax)
除数: (bx)
商: (ax)
余数:(dx) -
示例
100001/100
100001 = 186A1H
需要十六位除法
用DX(高位)和AX(低位)联合存放186A1
BX存放100D = 64H
mov dx,1h
mov ax,86a1h
mov bx,64h
div bx
7.5 dup功能和用法
- db 重复的次数 dup (重复的数据)
db 3 dup(0) | 定义三个字节,值都为0 | db 0,0,0 |
---|---|---|
db 3 dup(1.2.3) | 定义九个字节 | db 1,2,3,1,2,3,1,2,3 |
第八讲 指令的转移和应用
8.1 ‘转移’综述
- 转移指令
可以控制cpu执行内存某处的指令
可以修改IP,或同时及修改CS和IP - 段内转移
只修改IP,如jmp ax - 段间转移
同时修改CS和IP,如jmp 1000:0 - 段内短转移:ip修改范围-128~127
- 段内近转移:ip修改范围-32768~32767
- 无条件转移: jmp
- 条件转移 jcxz
- 循环指令 loop
- 过程
- 中断
8.2 offset 指令
- offset取得标号的偏移地址
- offset 标号
3.在程序运行时把s处的指令复制到s0处
s: mov ax,bx
mov si,offset s
mov di,offset s0
mov ax,cs:[si]
mov cs:[di],ax
s0: nop
nop
8.3 jmp 指令
- 无条件转移
(1)转移的目的地址
(2)转移的距离
a.段间的转移 jmp 2000:1000(远转移)
b.段内短转移 jmp short标号;8位位移
c.段内近转移 jmp near ptr 标号;16位位移 - jmp:根据位移进行转移
- 两种段内转移
(1)短转移
jmp short 标号
(ip)=(ip)+八位位移
八位位移=‘标号’地址-jmp指令后的第一个字节地址
8位位移范围为-128~127,补码表示
(2)近转移
jmp near ptr 标号
(ip)=(ip)+16位位移
八位位移=‘标号’地址-jmp指令后的第一个字节地址
8位位移范围为-32769~32767,补码表示 - 远转移
远转移jmp far ptr 标号 | 近转移jmp near ptr 标号 |
---|---|
段间转移 | 段内转移 |
far ptr 指明了跳转的目的地址 | near ptr 指明了相对当前ip的转移位移 |
- 转移地址在寄存器中jmp
jmp 16寄存器(位移)
6.转移地址在内存中的jmp
jmp word ptr 内存单元地址 | jmp dword ptr 内存单元地址 |
---|---|
段内转移 | 段间转移 |
从内存单原处存放一个字,是转移的目的偏移地址 | 从内存单元处存放两个字,高地址处的字是转移的目的段地址,低地址处是偏移地址 |
jmp word ptr ds[0] | mov ds:[0],ax-----mov word ptr ds:[2],0-----jmp dword ptr ds:[0] |
8.4 其他转移指令
- jcxz 有条件转移
如果(CX) =0,则转移到标号处
如果(CX)!=0,则继续向下执行 - 所有有条件转移都是短转移
- 机器码中包含转移的位移
第九讲 模块化程序设计
9.1 call指令和ret指令
- 调用子程序call
返回 ret - 执行call两步操作
将当前ip或cs+ip压栈
转移到标号处执行 - call far ptr
相当于:
push cs
push ip
jmp far ptr 标号 - 寄存器call
call 16位寄存器 - 内存地址的call
call word ptr
相当于:
push ip
jmp word ptr
mov sp,10h
mov ax,0123h
mov ds:[0],ax
call word ptr ds:[0]
ret | retf |
---|---|
用栈中的数据,修改ip内容,从而实现近转移 | 用栈中的数据修改cs和ip的内容,从而实现远转移 |
pop ip | pop ip ,pop cs |
902 call指令和ret指令配合
- 计算2的n次方
n由cx提供
assume cs:code ss:stack
stack segment
db 8 dup(0)
db 8 dup(0)
code segment
start :mov ax,stack
mov ss,ax
mov sp,16
mov ax,1
mov cx,3
call s
mov bx,ax
mov ax,4c22h
int 21h
s:add ax,ax
loop s
ret
code ends
end start
903 乘法指令mul
- mul寄存器
8位乘法 | 16位乘法 | |
---|---|---|
被乘数 | AL | AX |
乘数 | 8位寄存器或内存单元 | 16位寄存器或内存字单元 |
结果 | AX | DX(高位)和AX(低位) |
例 | mul bl / mul byte ptr ds:[0] | mul word ptr [bx+si+8] |
- 计算100*10
mov al,100
mov bl,10
mul bl
904 模块化设计
- 计算data段中的数据的3次方,保存在后一组dword中
asuume cs:code
data segment
dw 1,2,3,4,5,6,7,8
dd 0,0,0,0,0,0,0,0
data ends
code segment
start:mov ax,data
mov ds,ax
mov si,0
mov di,16
mov cx,8
s:mov bx,[si]
call cube
mov [di],ax
mov [di+2],dx
add di,4
add si,2
loop s
cube: mov ax,bx
mul bx
mul bx
ret
mov ax,4c00h
int 21h
code ends
end start
2.用内存单元批量传递数据
2. 用栈传递参数
将需要传递的参数 入栈
905 寄存器冲突问题
第十讲 标志寄存器及其应用
1001 标志寄存器
- flag寄存器按位起作用,每一位都有特定含义
- 8086 cpu1,3,5, 12 -15无意义
- 标志寄存器作用
(1)存储相关指令的执行结果
(2)为cpu执行指令提供依据
(3)控制cpu相关工作方式
- 直接访问标志寄存器
pushf:压栈 popf:出栈 - ZF-零标志(指示相关计算结果是否为零)
ZF=1 结果为0 ZF=0结果不为0 - PF - 奇偶标志位
执行指令结果二进制结果中1的个数
1的个数为偶数:PF=1
1的个数为奇数:PF=0 - SF - 符号标志
将结果视为符号数
结果为负:SF=1
结果非负:SF=0
无符号数时无意义 - CF - 进位标志
进行无符号运算时,CF记录了运算结果的最高有效位向更高位进值。
有进位或者借位:CF=1
无进位或者借位:CF=0 - OF - 溢出标志
进行有符号运算,超过机器表示范围称为溢出
有溢出:OF=1
无溢出:OF=0
1002 带进位的加减法
- adc--带进位的加法
adc ax,bx=(ax)+(bx)+CF - adc指令:大数相加
- 128位数相加
结果存放在第一段中
code segment
start:
mov ax,data
mov ds,ax
mov di,16
mov si,0
mov cx,8
call add128
mov ax,4c00H
int 21H
add128:
push ax
push cx
push si
push di
sub ax,ax
s:mov ax,ds:[si]
adc ax,ds:[di]
mov ds:[si],ax
inc si
inc si
inc di
inc di
loop s
pop di
pop si
pop cx
pop ax
ret
code ends
end start
(1)不可以,清除掉进位或者借位,将CF清零
(2)不可以,inc不会影响进位,add可能产生进位,避免改变CF的值
- sbb指令--带借位的减法
abb ax,bx
(ax)=(ax)-(bx)-CF
1003cmp指令
- cmp是比较指令,相当于减法指令,但不保存结果
- 相关指令通过识别被影响的标志寄存器得知比较结果
cmp ax,ax | mov ax,8 / mov bx,3 / cmp ax,bx |
---|---|
做(ax)-(bx)运算,结果为0,但不在ax保存,仅影响flag各位 | (ax)= 8,(bx)=3 |
ZF=1 PF=1 SF=0 CF=0 OF=0 | ZF=0 PF=1 SF=0 CF=0 OF=0 |
- 无符号数比较与标志位取值
(1)无符号数
(2)有符号数比较
- 条件转移指令
- 条件转移指令的使用
cmp ah,bh
je s
add ah,bh
jmp short ok
s:add ah,ah
ok:ret
add ax,0 改变标志寄存器
如果ax=0,则ZF=0
1004 条件转移指令的应用
- 双分支结构
code segment
start:mov ax,data
mov ds,ax
mov cx,8
mov ax,0
mov bx,0
s:cmp byte ptr [bx],8
jne next
inc ax
next:inc bx
loop s
mov ax,4c00h
int 21h
code ends
end start
1005 DF指令和串传送指令
-
DF—方向标志位
-
串传送指令
es与di配合,为目标段 -
例
code segment
start:mov ax,data
mov ds,ax
mov es,ax
mov si,0
mov di,16
cld
mov cx,16
s:movsb
loop s
...
4.例二
第十一讲 直接定址表
1401 移位指令
左移一位*2,右移一位 /2
1402操作显存数据
- 显示原理
有128K
B8000~BFFFF 32K空间 80*25彩色字符空间
- 例
code segment
start:
mov ax,data
mov ds,ax
mov ax,0B8000H
mov es,ax
mov si,0
mov di,160*12+8-16
mov cx,16
s:mov al,[si]
mov es:[di],al
inc di
mov al,71
mov es:[di],al
inc si
inc di
loop s
...
1602 描述内存单元标号
- 标号
- 去了冒号的数据标号
1603 数据的直接定址表
- 映射关系
- 最简解决方式
assume cs:code
code segment
start:mov al,2bh
call showbyte
mov ax,4c00h
int 21h
showbyte:
jmp short show
table db '0123456789ABCDEF'
show: push bx
push es
push cx
mov cl,4 ;高低四位进行分离
mov ah,al
shr ah,cl
and al,00001111b
;高四位字符偏移地址
mov bl,ah
mov bh,0
mov ah,table[bx]
mov bx,0b800h
mov es,bx
mov es:[160*12+40*2],ah
mov al,71h
mov es:[160*12+40*2+1],al
;低四位字符偏移地址
mov bl,al
mov bh,0
mov al,table[bx]
mov es:[160*12+40*2+2],al
mov al,71h
mov es:[160*12+40*2+3],al
pop cx
pop es
pop bx
ret
code ends
end start
- 例
assume cs:code
code segment
start:mov al,60
call showsin
mov ax,4c00h
int 21h
showsin:
jmp short show
table dw ag0,ag30,ag60,ag90 //emu8086报错!!!!!!!!
ag0 db'0',0 //在debug中可以正常运行
ag30 db'0.5',0
ag60 db'0.866',0
ag90 db'1',0
show: push bx
push es
push si
mov bx,0b800h
mov es,bx
mov ah,0
mov bl,30
div bl
mov bl,al
mov bh,0
add bx,bx ;当60时候,找ag60,因为是字,乘二
mov bx,table[bx]
mov si,160*12+40*2
shows: mov ah,cs:[bx]
cmp ah,0
je showret
mov es:[si],ah
inc si
mov al,71h
mov es:[si],al
inc bx
inc si
jmp shows
showret:
pop si
pop es
pop bx
ret
code ends
end start
1604 代码直接定址表
- 实例
- 各功能的实现
assume cs:code
code segment
start:mov ah,0 ;功能号
mov al,2
call setfunction
mov ax,4c00h
int 21h
setfunction:
jmp short set
table dw fun1,fun2,fun3,fun4
set:push bx
cmp ah,3
ja sret
mov bl,ah
mov bh,0
add bx,bx
call word ptr table[bx]
sret:pop bx
ret
fun1:push bx
push es
push cx
mov bx,0b800h
mov es,bx
mov cx,2000
mov bx,0
lop1:mov byte ptr es:[bx],' '
add bx,2
loop lop1
pop cx
pop es
pop bx
ret
fun2: push bx
push es
push cx
mov bx,0b800h
mov es,bx
mov cx,2000
mov bx,1
lop2:and byte ptr es:[bx],11111000b
or es:[bx],al
add bx,2
loop lop2
pop cx
pop es
pop bx
ret
fun3: push bx
push es
push cx
mov cl,4
shl al,cl
mov bx,0b800h
mov es,bx
mov cx,2000
mov bx,1
lop3:and byte ptr es:[bx],10001111b
or es:[bx],al
add bx,2
loop lop3
pop cx
pop es
pop bx
ret
fun4:push cx
push si
push di
push es
push ds
mov si,0b800h
mov es,si
mov ds,si
mov si,160 ;n+1行
mov di,0
cld ;在字串操作中使变址寄存器SI或DI的地址指针自动增加
mov cx,24
lop4:push cx
mov cx,160
rep movsb ;rep重复执行后面的指令 movsb:源地址是DS:SI,目的地址是ES:DI ,传送一个字节,之后SI和DI(或者ESI和EDI)加/减1
pop cx
loop lop4
mov cx,80
mov si,0
lop4s:mov byte ptr es:[160*24+si],' '
add si,2
loop lop4s
pop ds
pop es
pop di
pop si
pop cx
ret
code ends
end start
第十二讲 内中断及其处理
1201 中断及其处理
- 内中断(CPU内部事件)
(1)除法错误:0
(2)单步执行:1
(3)执行into指令:4
(4)执行int指令: n - cpu接到中断处理信息
执行中断程序
中断处理程序在哪里
中断信息和其处理程序的入口地址之间有某种联系,cpu根据中断信息可以找到要执行的处理程序
中断向量表
IP = N*4 , CS = IP+2
3. 中断过程
1202 编制中断处理程序
- do0子程序放在哪
放在内存确定的位置
- 程序框架
do0:显示 overflow
(1)安装程序:将do0送入内存0000:0200处
(2)将do0中断处理程序的入口地址0000:0200存储在中断向量表0号表项 - 写安装程序
assume cs:code
code segment
start: ;安装中断向量表
mov ax,cs
mov ds,ax
mov si,offset do0
mov ax,0
mov es,ax
mov di,200h
mov cx,offset do0end-offset do0 ;do0部分代码长度
cld
rep movsb
;设置中断向量表
mov ax,0
mov es,ax
mov word ptr es:[0*4],200h
mov word ptr es:[0*4+2],0h
do0: jmp short show ; 显示字符串overflow
table db "over flow"
show:mov ax,cs
mov ds,ax
mov si,202h
mov ax,0b800h
mov es,ax
mov di,12*160+36*2
mov cx,10
s:mov al,[si]
mov es:[di],al
inc si
add di,2
loop s
mov ax,4c00h
int 21h
do0end:nop
code ends
end start
1203 单步中断
- debug提供了单步中断功能 -t
使用单步中断程序时,debug将TF标志位设为1,使cpu在单步模式运行 - 与终端相关的标志位
TF - 陷阱标志位:(第八位)
IF - 中断标志:(第九位)
TF IF设置为0原因:
例如:设置栈
原因:SS-SP 联合指向栈顶,应该连续完成
1301由int指令引发的中断
- 执行n号中断
- 中断例程:7ch的中断例程编写和安装
(1)求一个word型数据的平方
ax=要计算的参数
dx,ax存放高低16位返回值
(2)安装程序
(3)设置中断向量表,将入口地址保存在7ch表项中
assume cs:code
code segment
start:
mov ax,cs
mov ds,ax
mov si,offset sqr
mov ax,0
mov es,ax
mov di,200h
mov cx,offset sqrend - offset sqr
cld
rep movsb
mov ax,0
mov es,ax
mov word ptr es[7ch*4],200h
mov word ptr es[7ch*4+2],0
mov ax,4c00h
int 21h
sqr:mul ax
iret
sqrend:nop