第 5 章教学重点在掌握基本的汇编语言程序设计方法之后,进一步学习如何提高编程效率的各种实用方法:
高级语言特性
宏结构
模块化第 5 章 5.1 高级语言特性
MASM 6.0引入高级语言的程序设计特性
条件控制伪指令
.IF,ELSE,ENDIF
循环控制伪指令
.WHILE,ENDW,REPEAT,UNTIL
过程声明和过程调用伪指令
.PROTO,INVOKE
第 5 章 5.1.1 条件控制伪指令
类 似 高 级 语 言 中 IF,THEN,ELSE 和
ENDIF的相应功能
在汇编时要展开,自动生成相应的比较和条件转移指令序列,实现程序分支
.IF 条件表达式 ;条件为真 ( 值为非 0)
分支体 ;执行分支体
[,ELSE ;前面 IF条件为假分支体 ;执行分支体 ]
.ENDIF ;分支结束 条件;单分支结构
.IF AX < 0
neg ax
.ENDIF
mov result,ax;双分支结构
.IF ax==5
mov bx,ax
mov ax,0
.ELSE
dec ax
.ENDIF;双分支结构
.IF ax==5
* cmp ax,05h
* jne @C0001
mov bx,ax
mov ax,0
.ELSE
* jmp @C0003
*@C0001:
dec ax
.ENDIF
*@C0003:
例 题
.data
_a sbyte?
_b sbyte?
_c sbyte?
tag byte?
.code
.startup
mov al,_b
imul al
mov bx,ax ;bx中为 b2
mov al,_a
imul _c
mov cx,4
imul cx ;ax中为 4ac
例 5.1- 1/2
.if sword ptr bx >= ax ;比较二者大小
mov tag,1;第一分支体:条件满足,tag←1
.else
mov tag,0;第二分支体:条件不满足,tag←0
.endif
.exit 0
例 5.1- 2/2
第 5 章 5.1.2 循环控制伪指令
WHILE结构 的循环控制伪指令
.WHILE 条件表达式 ;条件为真循环体 ;执行循环体
.ENDW ;循环体结束
UNTIL结构 的循环控制伪指令
.REPEAT ;重复执行循环体循环体
.UNTIL 条件表达式 ;直到条件为 真;WHILE结构
xor ax,ax
mov cx,100
.while cx!=0
add ax,cx
dec cx
.endw
mov sum,ax
求 1~ 100之和;UNTIL结构
xor ax,ax
mov cx,100
.repeat
add ax,cx
dec cx
.until cx==0
mov sum,ax
mov cx,100
xor ax,ax
lea bx,array
.repeat
.if sword ptr [bx] >= 0
add ax,[bx]
.else
.break
.endif
inc bx
inc bx
.untilcxz
mov result,ax
例 5.2
第 5 章
要调用带参数过程定义的过程,不应采用
CALL指令,因为比较烦琐
应该采用过程调用伪指令 INVOKE
使用 INVOKE 伪指令的前提是需要用
PROTO伪指令对过程进行声明
5.1.3 过程声明和过程调用伪指令过程名 PROC 调用距离 语言类型 作用范围 <起始参数 >
USES 寄存器列表,参数,类型
LOCAL 参数表
… ;汇编语言语句过程名 ENDP
过程声明伪指令,用于事先声明过程的结构过程名 PROTO 调用距离 语言类型,参数,类型
过程调用伪指令
INVOKE 过程名,参数,...
如何调用;汇编语言程序,lt503.asm
.model small
checksumd PROTO c,:word,:word ;声明过程
.stack
.data
array db 12h,25h,0f0h,0a3h,3
db 68h,71h,0cah,0ffh,90h
count equ $-array ; 数 组 的 元 素 个 数
result db? ;校验和
.code
.startup
INVOKE checksumd,count,offset array;调用过程
mov result,al ;保存校验和
.exit 0
例 5.3- 1/2
列表文件
checksumd PROC c USES bx cx,\
countp:word,arrayp:word
mov bx,arrayp ;BX←数组的偏移地址
mov cx,countp ;CX←数组的元素个数
xor al,al
sumd,add al,[bx] ;求和,AL←AL+DS:[BX]
inc bx
loop sumd
ret
checksumd endp
end
例 5.3- 2/2
列表文件第 5 章 5.2 宏结构程序设计宏汇编重复汇编条件汇编
—— 统称宏结构宏( Macro)是汇编语言的一个特点,它是与子程序类似又独具特色的另一种简化源程序的方法第 5 章宏 —— 具有宏名的一段汇编语句序列
—— 宏定义 时书写宏指令 —— 这段汇编语句序列的缩写
—— 宏调用 时书写宏展开 —— 宏指令处用这段宏代替的过程
—— 宏汇编 时实现宏的参数 功能强大,颇具特色配合宏,还有 宏操作符 和有关伪指令
5.2.1 宏汇编宏定义 宏名 macro [形参表 ]
宏定义体
endm
mainbegin MACRO ;;定义名为 mainbegin的宏,无参数
mov ax,@data ;;宏定义体
mov ds,ax
ENDM ;;宏定义结束
mainend MACRO retnum ;;带有形参 retnum
mov al,retnum ;;宏定义中使用参数
mov ah,4ch
int 21h
ENDM
宏注释符宏调用 宏名 [实参表 ]
start,mainbegin ;宏调用,建立 DS内容
dispmsg string ;宏调用,显示字符串
mainend 0 ;宏调用,返回 DOS
end start
宏调用的实质是在汇编过程中进行宏展开
宏展开的具体过程是:当汇编程序扫描源程序遇到已有定义的宏调用时,即用相应的宏定义体取代源程序的宏指令,同时用位置匹配的实参对形参进行取代宏展开 宏展开 —— 在汇编时,用宏定义体的代码序列替代宏指令的过程 。
start,mainbegin ;宏指令
1 mov ax,@data ;宏展开
1 mov ds,ax
mainend 0 ;宏指令
1 mov al,0 ;宏展开
1 mov ah,4ch
1 int 21h
宏的参数 宏的参数使用非常灵活宏定义时,
可以 无参数,例如 5.4a的 mainbegin
可以带有 一个参数,例如 5.4a的 mainend
也可以具有 多个参数 ;例如 5.5a的 shlext
参数可以是 常数,变量,存储单元,指令 ( 操作码 ) 或它们的一部分,也可以是 表达式 ;例如
5.5b的 shift和 shrot
宏定义体可以是任何合法的汇编语句,既可以是 硬指令序列,又可以是 伪指令序列 ;例如 5.6的
dstring;宏定义
shlext macro shloprand,shlnum
push cx
mov cl,shlnum
shl shloprand,cl
pop cx
endm;宏指令
shlext ax,6;宏展开
1 push cx
1 mov cl,06
1 shl ax,cl
1 pop cx
例 5.5a;统一 4条移位指令的宏指令
shift macro soprand,snum,sopcode
push cx
mov cl,snum
s&sopcode& soprand,cl
pop cx
endm;统一移位和循环移位 8条指令的宏指令
shrot macro sroprand,srnum,sropcode
push cx
mov cl,srnum
sropcode sroprand,cl
pop cx
endm
例 5.5b
替换操作符;宏定义
dstring macro string
db ’&string&’,0dh,0ah,’$’
endm;宏调用
dstring < This is a example,>
dstring < 0 !< Number !< 10 >;宏展开
1 db ’This is a example.’,0dh,0ah,’$’
1 db ’0 < Number < 10’,0dh,0ah,’$’
例 5.6
转义注释符传递注释符第 5 章 与宏有关的伪指令
局部标号伪指令
LOCAL 标号列表宏定义体采用了标号,应使用 LOCAL加以说明它必须是宏定义 MACRO语句之后的第一条语句
宏定义删除伪指令
PURGE 宏名表不需要某个宏定义时,可以把它删除
宏定义退出伪指令
EXITM
伪指令 EXITM表示结束当前宏调用的展开;宏定义
absol macro oprd
local next
cmp oprd,0
jge next
neg oprd
next:
endm
例 5.7 ;宏调用
absol word ptr [bx]
absol bx;宏展开
1 cmp word ptr [bx],0
1 jge0000
1 neg word ptr [bx]
10000:
1 cmp bx,0
1 jge0001
1 neg bx
10001:
单独占一行比较
仅是 源程序级 的 简化,
宏调用 在汇编时 进行程序语句的展开,不需要返回;不减小目标程序,执行速度没有改变
通过形参,实参结合实现参数传递,简捷直观,灵活多变
还是 目标程序级 的 简化,子程序调用 在执行时 由 CALL指令转向,
RET指令返回;形成的目标代码较短,执行速度减慢
需要利用寄存器,存储单元或堆栈等传递参数宏 子程序
宏与子程序具有各自的特点,程序员应该根据具体问题选择使用那种方法
通常,当程序段较短或要求较快执行时,
应选用宏;当程序段较长或为减小目标代码时,要选用子程序比较结论宏 子程序第 5 章 5.2.2 重复汇编
重复汇编 指在汇编过程中,重复展开一段 ( 基本 ) 相同的语句
重复汇编没有名字,不能被调用
重复汇编常用在宏定义体中,也可以在一般汇编语句中使用
重复汇编伪指令有三个:
REPEAT—— 按参数值重复
FOR—— 按参数个数重复
FORC—— 按参数的字符个数重复
最后,用 ENDM结束按参数值重复 REPEAT 重复次数重复体
ENDM
char = 'A'
REPEAT 26
db char
char = char +1
ENDM
1 db char ;等效于 db 'A'
1 char = char +1
1 db char ;等效于 db 'B'
1 char = char +1
...
1 db char ;等效于 db 'Z'
1 char = char +1
按参数个数重复 FOR 形参,〈 实参表 〉
重复体
ENDM
FOR regad,<ax,bx,cx,dx>
push regad
ENDM
1 push ax
1 push bx
1 push cx
1 push dx
按参数字符个数重复 FORC 形参,字符串重复体
ENDM
FORC regad,dcba
pop &regad&x
ENDM
1 pop dx
1 pop cx
1 pop bx
1 pop ax
第 5 章 5.2.3 条件汇编
条件汇编伪指令在汇编过程中,根据条件决定汇编的语句
IFxx 表达式 ;满足,汇编分支语句体 1
分支语句体 1
[ ELSE ;不满足,汇编分支语句体 2
分支语句体 2 ]
ENDIF ;条件汇编结束
pdata macro num
IF num lt 100 ;;如果 num < 100,则汇编如下语句
db num dup (?)
ELSE ;;否则,汇编如下语句
db 100 dup (?)
ENDIF
endm
pdata 12 ;宏调用 ①
db 12 dup(?) ;宏汇编结果 ①
pdata 102 ;宏调用 ②
db 100 dup(?) ;宏汇编结果 ②
例 5.10
宏结构的作用宏汇编,重复汇编和条件汇编为源程序的编写提供了很多方便,
灵活运用它们可以编写出非常良好的源程序来汇编系统中有些以圆点起始的伪指令 ( 如,startup,.exit等 )
实际上是一种宏结构
dstring MACRO string ;;定义字符串
db '&string&',0dh,0ah,'$'
ENDM
mainbegin MACRO dsseg ;;设置数据段地址
mov ax,dsseg
mov ds,ax
ENDM
dispmsg MACRO message
mov dx,offset message
mov ah,09h
int 21h
ENDM
例题 5.4- 1/3
mainend MACRO retnum ;;返回 DOS,可不带参数
ifb <retnum>
mov ah,4ch ;;没有参数
else
mov ax,4c00h+(retnum AND 0ffh);; 有参数
endif
int 21h
ENDM
例题 5.4- 2/3
.model small
.stack 256
.data
msg1 equ this byte
dstring <Hello,Everybody !!>
msg2 equ this byte
dstring <You see,I made it.>
.code
start,mainbegin @data ;建立 DS内容
dispmsg msg1 ;显示 msg1字符串
dispmsg msg2 ;显示 msg2字符串
mainend ;返回 DOS
end start
例题 5.4- 3/3
将程序分段,采用子程序或宏结构都是进行模块化程序设计介绍开发大型程序时采用的方法:
源程序文件的包含目标模块连接子程序库
5.3 模块化程序设计例题 5.12
将键盘输入的数据按升序输出把源程序分放在几个文本文件中,在汇编时通过包含伪指令 INCLUDE结合成一体
INCLUDE 文件名
可将常用的子程序形成,ASM汇编语言源文件
可将常用的宏定义存放在,MAC宏库文件中
可将常量定义,声明语句组织在,INC包含文件中例 5.12a
① 宏库文件 lt512a.mac
② 主程序文件 lt512a.asm
③ 子程序文件 sub512a.asm
5.3.1 源程序文件的包含
1
dispchar macro char ;显示 char字符
mov dl,char
mov ah,2
int 21h
endm
dispmsg macro message ;显示 message字符串
mov dx,offset message
mov ah,9
int 21h
endm
Lt512a.mac
include lt512a.mac
...
dispmsg msg1 ;提示输入数据
mov bx,offset buf
call input ;数据输入
cmp cx,0
je start4 ;没有输入数据则退出
mov count,cx
..,;显示输入的数据
..,;数据排序
..,;显示经排序后的数据
start4,.exit 0
include sub512a.asm
end
Lt512a.as
m
子程序源文件有 3个子程序
ALdisp ;显示 2位 16进制数子程序 ( 例 4.10)
sorting ;排序子程序 ( 例 4.8)
input ;键盘输入子程序还包含一个宏
convert ;;将 DX两位 ASCII码转换为两位 16进制数
sub512a.as
m
让我们重点分析键盘输入子程序 input;键盘输入子程序;入口参数,ds:bx=存放数据的缓冲区;出口参数,cx=数据个数
input proc
push ax
push dx
xor cx,cx ;数据个数清 0
input01,xor dx,dx ;输入字符清 0
input02,mov ah,1 ;键盘输入一个字符
int 21h
input之一继续,input之二
input10,cmp al,0dh
je input30;是 回车,结束整个数据的输入
cmp al,’ ’
je input20;是 空格和逗号,确认输入了一个数据
cmp al,’,’
je input20
cmp al,08h
je input17;是 退格,丢弃本次输入的数据,出错
input之二继续,input之三
cmp al,’0’ ;有效数字判断 ( 图 5.2b)
jb input17 ;小于 ’ 0’,不是有效数字,出错
cmp al,’f’
ja input17 ;大于 ’ f’,不是有效数字
cmp al,’a’
jb input11
sub al,20h ;’a’ ~ ’ f’ 转 换 成 大写 ’ A’~ ’ F’
jmp input12
input11,cmp al,’F’
ja input17 ;字符小于 ’ a’,大于 ’ F’,出错
cmp al,’A’
jae input12 ;是 ’ A’~ ’ F’,有效字符
cmp al,’9’
ja input17 ;是 ’ 0’~ ’ 9’,有效字符
input之三继续,input之四
input12,cmp dl,0 ;有效字符的处理
jne input13
mov dl,al;dl=0,输入了一个数据的低位,则 dl←al
jmp input02 ;转到字符输入
input13,cmp dh,0
jne input17;dl≠ 0,dh≠ 0输入 3位数据,出错
mov dh,dl;dl≠ 0,dh= 0输入了一个数据的高位
mov dl,al ;dh←dl,dl←al
jmp input02 ;转到字符输入
input之四继续,input之五
input17,mov dl,7 ;输入错误处理
mov ah,2
int 21h
mov dl,'?'
mov ah,2
int 21h
jmp input01 ;转到输入一个数据
input之五继续,input之六;转换正确的输入数据 ( 图 5.2c)
input20,convert
jmp input01 ;转到输入一个数据
input30,convert
pop dx
pop ax
ret ;返回,出口参数已设定
input endp
input之六继续,convert之一;;将 DX两位 ASCII码转换为两位 16进制数 ( 图 5.2c)
convert macro
local input21,input22
local input24,input25
cmp dl,0;;dl=0,没有要转换的数据,退出
je input25
convert之一继续,convert之二
cmp dl,'9'
jbe input21
sub dl,7 ;;字符 A~ F,则减 7
input21,and dl,0fh ;;转换低位
cmp dh,0 ;;dh=0,没有高位数据
je input24
cmp dh,'9'
jbe input22
sub dh,7
input22,shl dh,1
shl dh,1
shl dh,1
shl dh,1 ;;转换高位
or dl,dh ;;合并高,低位
convert之二继续,convert之三源文件包含的操作步骤:
① 分别编辑生成各个文件
② 汇编,连接主程序文件
input24,mov [bx],dl ;;存入缓冲区
inc bx
inc cx ;;数据加 1
input25:
endm
convert之三把常用子程序写成独立的源程序文件,单独汇编,形成子程序的目标文件,OBJ
主程序也经过独立汇编之后形成目标文件连接程序将所有目标文件连接起来,最终产生可执行文件需要遵循的原则:
① 声明共用的变量,过程等
② 实现正确的段组合
③ 处理好参数传递问题
5.3.2 目标代码文件的连接
2
第 5 章 声明共用的变量、过程
各个模块间共用的变量,过程等要说明
PUBLIC 标识符 [,标识符,..];定义标识符的模块使用
EXTERN 标识符,类型 [,标识符,类型,..];调用标识符的模块使用
标识符是变量名,过程名等
类型是 byte / word / dword( 变量 ) 或 near /
far( 过程 )
在一个源程序中,public/extern语句可以有多条
各模块间的 public/extern伪指令要互相配对,
并且指明的类型互相一致第 5 章 实现正确的段组合
子程序文件必须定义在代码段中,也可以具有局部的数据变量
采用简化段定义格式,只要采用相同的存储模式,
容易实现正确的近或远调用
完整段定义格式中,为了实现模块间的段内近调用
( near类型 ),各自定义的段名,类别必须相同,
组合类型都是 public。 实际的程序开发中,各个模块往往由不同的程序员完成,不易实现段同名或类别相同,所以索性定义成远调用 ( far类型 )
定义数据段时,同样也要注意这个问题 。 当各个模块的数据段不同时,要正确设置数据段 DS寄存器的段基地址第 5 章 处理好参数传递问题
少量参数可用寄存器或堆栈直接传送数据本身
大量数据可以安排在缓冲区,用寄存器或堆栈传送数据的存储地址
还可利用变量传递参数,但是要采用
public/extern声明为公共 ( 全局 ) 变量
这些也是子程序间的参数传递方法
另外,第 7章混合编程介绍了更好的堆栈传递参数方法,可以采用例 5.12b
主程序 lt512b.asm并入宏定义
子程序文件 sub512b.asm,要加上段定义语句,声明语句等,
但不需要起始点和结束点模块连接的操作步骤:
① 分别编辑生成各个文件
② 分别汇编各个文件
③ 连接各个目标文件,形成可执行文件把常用子程序写成独立的源文件,单独汇编形成 OBJ文件后,存入 子程序库主程序也单独汇编形成 OBJ文件主程序连接时,调入子程序库中的子程序模块,产生最终的可执行文件例 5.12c
① 主程序文件 lt512c.asm
② 子程序文件 sub512c1.asm
③ 子程序文件 sub512c2.asm
④ 子程序文件 sub512c3.asm
5.3.3 子程序库的调入
3
..,;宏定义
.code
extern ALdisp:near,sorting:near,input:near;声明其他模块中的子程序
.startup
...
.exit 0
end
Lt512c.as
m
.model small
.code
public aldisp
Aldisp proc
...
Aldisp endp
end
sub512c1.asm
.model small
.code
public sorting
sorting proc
...
sorting endp
end
sub512c2.as
m
.model small
.code
public input
input proc
...
input endp
end
sub512c3.asm
库文件调入的操作步骤:
① 分别编辑生成各个文件
② 分别汇编各个文件
③ 用库管理文件,将子程序模块添加到库文件 (,LIB) 中
④ 连接主程序,提供库文件,
形成可执行文件第 5 章 补充例题
将子程序应用的例题 4.13~ 4.15的子程序编写成模块,供主程序调用
实现功能:从键盘输入有符号十进制数,求它们的平均值,然后输出
源程序文件进行简单修改
主程序文件
子程序文件
利用目标代码文件的连接形成可执行文件第 5 章 5.4 输入输出程序设计
输入指令 IN从外设读取数据
输出 OUT指令向外设提供数据
处理器通过 I/O接口控制外设参考 I/O指令第 2.1.5节建议结合硬件相关课程学习第 5 章 5.4.1 程序直接控制输入输出
程序执行 IN或 OUT指令实现数据传送
.model tiny ;形成 com格式的程序
.code
.startup
call speaker_on ;打开扬声器声音
mov ah,1 ;等待按键
int 21h
call speaker_off ;关闭扬声器声音
.exit 0
例 5.13:主程序
speaker_on proc ;扬声器开子程序
push ax
in al,61h ;读取原来控制信息
or al,03h ;D1D0=PB1PB0=11b
out 61h,al ;直接控制发声
pop ax
ret
speaker_on endp
例 5.13:子程序扬声器关;扬声器关子程序 speaker_off
and al,0fch ;D1D0=PB1PB0=00b
第 5 章 5.4.2 程序查询输入输出
程序需要查询外设状态,然后进行数据交换
实际的输入输出程序可以规定一个超时参数
打印机查询输出的控制:
要打印的字符首先提供给数据端口
然后查询状态端口,确定打印机是否可以接受
如果打印机还没有准备好接受数据,则继续检测一个固定时间
如果打印机能够接受数据,处理器利用控制端口将数据提供给打印机
mov cx,(sizeof okmsg)-1
mov si,offset okmsg
prnbegin,mov dx,378h ;打印机基地址
mov bx,100 ;超时参数
mov al,[si] ;打印字符
call printchar ;调用打印子程序
jc prnerr ;CF=1,不能打印
inc si ;CF=0,打印正常
loop prnbegin ;继续
mov dx,offset okmsg ;显示正确
jmp prnok
prnerr,mov dx,offset errmsg ;显示错误
prnok,mov ah,9
int 21h
例 5.14:主程序
printchar proc
push cx
out dx,al ;向数据端口输出打印字符
inc dx ;基地址加 1成为状态端口
print0,sub cx,cx
print1,in al,dx ;查询状态端口
test al,80h ;最高位 D7反映打印机状态
jnz print2 ;D7=1,可以接收打印数据
loop print1 ;D7=0,不能接收打印数据
dec bl ;超时参数减 1
jnz print0 ;循环检测
stc ;规定时间内没有准备好
jmp print3 ;退出打印例 5.14:打印子程序 1/2
print2,inc dx ;基地址再加 1成为控制端口
mov al,0dh ;使最低位 D0=1
out dx,al
nop ;延时
mov al,0ch ;使最低位 D0=0
out dx,al;产生选通脉冲,将打印字符送入打印机
clc ;设置正常标志 CF=0
print3,pop cx
ret ;返回
printchar endp
例 5.14:打印子程序 2/2
第 5 章 5.4.3 中断服务程序
需要交换数据的外设,采用中断请求向处理器提出要求
处理器执行事先设计好的中断服务程序,在中断服务程序当中实现数据交换
8086可以处理 256种中断,分为内部,外部两种类型
外部可屏蔽中断用于与外设进行数据交换第 5 章 1,内部中断服务程序
主程序通过中断调用指令 INT n执行内部中断服务程序,其实质相当于子程序调用
编写内部中断服务程序与编写子程序雷同
利用过程定义伪指令 PROC / ENDP
但通常要执行 STI指令开放可屏蔽中断
最后执行 IRET指令返回调用程序
内部中断服务程序常用寄存器传递参数
设置中断向量,AH= 25H( INT 21H)
获取中断向量,AH= 35H( INT 21H)
.data
intoff dw? ;保存原偏移地址
intseg dw? ;保存原段地址
.code
mov ax,3580h ;获取中断 80H的中断向量
int 21h
mov intoff,bx ;保存偏移地址
mov intseg,es ;保存段基地址例 5.15a,1/5
获取 中断向量,AH= 35H( INT 21H)
入口参数,AL=中断向量号出口参数,ES:BX=中断服务程序的入口地址
( 段基地址:偏移地址 )
push ds
mov dx,offset newint80h
mov ax,seg newint80h
mov ds,ax
mov ax,2580h ;设置中断 80H的入口地址
int 21h
pop ds
例 5.15a,2/5
设置中断向量,AH= 25H( INT 21H)
入口参数,AL=中断向量号
ES:BX=中断服务程序的段基地址:偏移地址
int 80h;调用中断 80h的服务程序,显示信息
mov dx,intoff ;恢复中断 80H的入口地址
mov ax,intseg
mov ds,ax
mov ax,2580h
int 21h
.exit 0 ;返回 DOS
例 5.15a,3/5
设置中断向量,AH= 25H( INT 21H)
入口参数,AL=中断向量号
ES:BX=中断服务程序的段基地址:偏移地址
newint80h proc ;内部中断服务程序
sti ;开中断
push ax ;保护现场
push bx
push cx
push si
mov si,offset intmsg;获取显示字符串首地址
mov cx,sizeof intmsg;获取显示字符串个数例 5.15a,4/5
disp,mov al,cs:[si] ;获取显示字符
mov bx,0 ;显示一个字符
mov ah,0eh
int 10h
inc si
loop disp
pop si ;恢复现场
pop cx
pop bx
pop ax
iret ;中断返回
intmsg db 'I am Great !',0dh,0ah ;显示信息
newint80h endp
例 5.15a,5/5
第 5 章 2,驻留中断服务程序
驻留 TSR程序:程序执行结束,但保留在系统主存中,可以让其他程序使用
方法:利用 DOS功能 31h代替 4ch终止程序程序 驻留返回,AH= 25H( INT 21H)
入口参数,AL=返回代码
DX=程序驻留的容量 ( 节,1节 =16个字节 )
.model tiny
.code
.startup ;等价于 org 100h
jmp start ;跳转到本程序的开始位置
newint80h proc ;驻留的中断服务程序
..,;同例题 5.15a过程
newint80h endp ;中断服务程序结束
start,mov ax,cs ;主程序开始位置
mov ds,ax
mov dx,offset newint80h
mov ax,2580h
int 21h ;设置 80h的中断向量
int 80h ;调用一下看看例 5.15b,1/2
mov dx,offset istmsg ;显示驻留成功
mov ah,9
int 21h
mov dx,(offset start)+15;计算驻留程序的长度 (需多加 15个字节 )
mov cl,4
shr dx,cl ;除以 16转换成,节,
mov ax,3100h;中断服务程序驻留后,主程序返回 DOS系统
int 21h
istmsg db 'INT 80H is installed!',0dh,0ah,'$'
end
例 5.15b,2/2
第 5 章 3,外部可屏蔽中断服务程序
编写可屏蔽中断服务程序,还要注意:
发送中断结束命令
不能采用寄存器传递参数
不要使用 DOS系统功能调用 INT 21H
中断服务程序尽量短小
主程序除需要修改中断向量外,还要注意:
控制 CPU的中断允许标志 IF
设置中断屏蔽寄存器 IMR
例 5.16 键盘中断服务程序
.code
mov ax,3509h
int 21h
push es
push bx ;保存原中断向量内容
cli ;关中断
push ds ;设置新中断向量内容
mov ax,2509h
mov dx,seg scancode
mov ds,dx
mov dx,offset scancode
int 21h
pop ds
例 5.16,1/
in al,21h ;读出 IMR
push ax ;保存原 IMR内容
and al,0fdh ;允许键盘中断 ( D1)
out 21h,al ;设置新 IMR内容
mov byte ptr esccode,0
sti ;开中断
waiting,cmp byte ptr esccode,81h;循环等待按下并释放 ESC键
jne waiting;中断服务程序设置 esccode单元内容
..,;恢复,返回例 5.16,2/
scancode proc
sti ;键盘中断服务程序
push ax
push bx
in al,60h ;读取扫描码
push ax
in al,61h ;通过 PB7应答键盘
or al,80h
out 61h,al ;使 PB7=1
and al,7fh
out 61h,al ;使 PB7=0
pop ax
cmp al,81h
jne scan1 ;不是 ESC键断开扫描码,显示例 5.16,3/
push ds;是 ESC键断开扫描码,则设置 esccode单元
mov bx,@data ;设置数据段地址
mov ds,bx
mov esccode,al ;设置 esccode单元为其扫描码
pop ds
scan1,push ax ;显示扫描代码
shr al,1 ;先显示高 4位
shr al,1
shr al,1
shr al,1
cmp al,0ah
jb scan2
add al,7
scan2,add al,30h ;转换成 ASCII码例 5.16,4/
mov bx,0
mov ah,0eh
int 10h
pop ax ;后显示低 4位
and al,0fh
cmp al,0ah
jb scan3
add al,7
scan3,add al,30h ;转换成 ASCII码
mov ah,0eh
int 10h
例 5.16,5/
mov ax,0e20h ;显示两个空格
int 10h
mov ax,0e20h
int 10h
mov al,20h ;发送 EOI命令
out 20h,al
pop bx
pop ax
iret ;中断返回
scancode endp
例 5.16,6/
第 5章 教学要求
1,理解条件控制和循环控制伪指令,熟悉带参数的过程定义和过程声明,过程调用伪指令
2,了解宏操作符,宏汇编,条件汇编和重复汇编,
源程序包含,代码连接和子程序库等程序设计方法
3,了解程序直接控制,查询和中断的输入输出程序设计
4,掌握伪指令,PROTO / INVOKE,MACRO/ENDM、
LOCAL,INCLUDE/ PUBLIC/ EXTERN