汇编网首页登录博客注册
unixandlinux的学习博客
博客首页博客互动【做检测题】论坛求助

我的博客

个人首页 |  我的文章 |  我的相册 |  我的好友 |  最新访客 |  文章收藏 |  论坛提问 |  友情链接 |  给我留言  
图片载入中
学习动态
最新评论
最新留言
好友圈
友情链接

[2023-08-12 20:31] 第 13 章 实验 13  编写、应用中断例程

实验 13 编写、应用中断例程

一、编写并安装“int 7ch”指令所引发中断的中断例程,功能为显示一个用 0 结束的字符串,中断例程安装在内存地址 0:200 处。
参数:(dh)=行号,(di)=列号,(cl)=颜色,ds:si 指向字符串首地址。
以上中断例程安装成功后,对下面的程序进行单步跟踪,尤其注意观察 int、iret 指令执行前后 CS、IP 和栈的状态。
注意,“ds:si 指向字符串首地址”是作为参数向“int 7ch”指令所引发中断的中断例程提供的,可见该字符串并不在该中断例程程序代码之中,而是位于主调程序内。

assume cs:code

data segment
  db "welcome to masm!",0
data ends

code segment

start:  mov dh,10
        mov dl,10
        mov cl,2
        mov ax,data
        mov ds,ax
        mov si,0
        int 7ch

        mov ax,4c00h
        int 21h

code ends

end start

    具体代码如下:

1. 将要显示的字符和字符属性信息存储在 CX 寄存器中,再传递到显示缓冲区进行显示输出。

本程序与下一个程序的主要区别在于 dis 部分所使用的寄存器不同:本程序用 CX 寄存器,而下一个程序用 AX 寄存器。

assume cs:code

code segment

start:  mov ax,cs
        mov ds,ax
        mov si,offset show
        mov ax,0
        mov es,ax
        mov di,200h
        mov cx,offset showend-offset show
        cld
        rep movsb

        mov word ptr es:[7ch*4],200h
        mov word ptr es:[7ch*4+2],0

        mov ax,4c00h
        int 21h

show:  mov ax,0B800h
        mov es,ax
        dec dh
        mov al,80*2
        mul dh
        mov di,ax
        dec dl
        mov al,2
        mul dl
        add di,ax
        mov ch,cl

dis:  mov cl,[si]
        cmp cl,0
        je showrep
        mov es:[di],cx
        inc si
        add di,2
        jmp short dis
showrep:  iret
showend:  nop

code ends

end start

2. 将要显示的字符和字符属性信息存储在 AX 寄存器中,再传递到显示缓冲区进行显示输出。

本程序与上一个程序的主要区别在于 dis 部分所使用的寄存器不同:上一个程序用 CX 寄存器,而本程序
用 AX 寄存器。

assume cs:code

code segment

start:  mov ax,cs
        mov ds,ax
        mov si,offset show
        mov ax,0
        mov es,ax
        mov di,200h
        mov cx,offset showend-offset show
        cld
        rep movsb

        mov word ptr es:[7ch*4],200h
        mov word ptr es:[7ch*4+2],0

        mov ax,4c00h
        int 21h

show:  mov ax,0B800h
        mov es,ax
        dec dh
        mov al,80*2
        mul dh
        mov di,ax
        dec dl
        mov al,2
        mul dl
        add di,ax

dis:  mov al,[si]
        cmp al,0
        je showrep
        mov ah,cl
        mov es:[di],ax
        inc si
        add di,2
        jmp short dis
showrep:  iret
showend:  nop

code ends

end start

3. 通过调用 BIOS 的 int 10h 指令中断例程的 2 号和 9 号子程序来显示字符串。

assume cs:code

code segment

start:  mov ax,cs
        mov ds,ax
        mov si,offset show
        mov ax,0
        mov es,ax
        mov di,200h
        mov cx,offset showend-offset show
        cld
        rep movsb

        mov word ptr es:[7ch*4],200h
        mov word ptr es:[7ch*4+2],0

        mov ax,4c00h
        int 21h

show:  push cx  ; 由于下面要用到 CX 寄存器,所以需将 CL 寄存器存储的字符属性信息数据入栈
        mov bp,sp  ; 为下面调用原 CL 寄存器存储的字符属性数据而作的准备,这时 ss:[bp]=(cl)

        ; 设置 BIOS 的 int 10h 指令中断例程的 2 号子程序参数;注意,行、列数据已经作为参数存储在 DX 寄存器中
dis:        mov ah,2  ; 设置 BIOS 的 int 10h 指令中断例程子程序为 2 号:设置光标位置
        mov bh,0  ; 设置显示缓冲区的第 0 页
        int 10h  ; 调用 BIOS 的 int 10h 指令以引发其中断,从而调用其中断例程的 2 号子程序

        ; 设置 BIOS 的 int 10h 指令中断例程的 9 号子程序参数
        mov al,[si]  ; 将要显示的字符传送到 AL 寄存器
        cmp al,0  ; 验证 AL 寄存器所存储的字符 ASCII 码是否为 0 —— 是否到达字符串的结束位置
        je showrep  ; 执行判断字符码
        mov ah,9  ; 设置 BIOS 的 int 10h 指令中断例程的子程序为 9 号:在光标位置显示字符
        mov bl,[bp]  ; 读取字符属性信息到 BL 寄存器
        mov cx,1  ; 字符显示的重复次数为 1 次
        int 10h  ; 调用 BIOS 的 int 10h 指令以引发其中断,从而其中断例程的 9 号子程序

        inc si  ; 将 ds:[si] 指向要显示字符串的下一个字符
        inc dl  ; 增加列号,以便让下一个字符显示在屏幕的下一列位置
        jmp short dis

showrep:  pop cx
          iret
showend:  nop

code ends

end start

4. 通过结合调用 BIOS 的 int 10h 指令中断例程的 2 号子程序和 DOS 的 int 21h 指令中断例程的 9 号子程序来显示字符串。

assume cs:code

code segment

start:  mov ax,cs
        mov ds,ax
        mov si,offset show
        mov ax,0
        mov es,ax
        mov di,200h
        mov cx,offset showend-offset show
        cld
        rep movsb

        mov word ptr es:[7ch*4],200h
        mov word ptr es:[7ch*4+2],0

        mov ax,4c00h
        int 21h

show:  cmp byte ptr [si],0  ; 将字符串结束符由 0 值改为字符 '$',以适应 DOS 的 int 21h 指令中断例程的 9 号子程序的要求
        je ok
        inc si
        jmp short show
ok:  mov byte ptr [si],'$'

        ; 设置 BIOS 的 int 10h 指令中断例程的 2 号子程序参数;注意,行、列数据已经作为参数存储在 DX 寄存器中
        mov ah,2  ; 设置 BIOS 的 int 10h 指令中断例程子程序为 2 号:设置光标位置
        mov bh,0  ; 设置显示缓冲区的第 0 页
        int 10h  ; 调用 BIOS 的 int 10h 指令以引发其中断,从而调用其中断例程的 2 号子程序

        ; 设置 DOS 的 int 21h 指令中断例程的 9 号子程序参数
        mov dx,0  ; 设置 ds:dx 指向字符串首地址。注意,DS 段寄存器存储的值已经以参数形式提供
        mov ah,9  ; 设置 DOS 的 int 21h 指令中断例程子程序为 9 号:在光标位置显示字符串
        int 21h  ; 调用 DOS 的 int 21h 指令以引发其中断,从而调用其中断例程的 9 号子程序

        iret

showend:  nop

code ends

end start


二、编写并安装“int 7ch”指令所引发中断的中断例程,功能为完成 loop 指令的功能。
参数:(cx)=循环次数,(bx)=位移。
以上中断例程安装成功后,对下面的程序进行单步跟踪,尤其注意观察 int、iret 指令执行前后 CS、IP 和栈的状态。
在屏幕中间显示 80 个“!”字符。

assume cs:code

code segment

start:  mov ax,0B800h
        mov es,ax
        mov di,160*12
        mov bx,offset s-offset se  ; 设置从标号 se 到标号 s 的转移位移
        mov cx,80
s:  mov byte ptr es:[di],'!'
        add di,2
        int 7ch                                                ; 如果 (cx)≠0,转移到标号 s 处
se:  nop

        mov ax,4c00h
        int 21h

code ends

end start

        具体代码如下:

assume cs:code

code segment

start:  mov ax,cs
        mov ds,ax
        mov si,offset lp
        mov ax,0
        mov es,ax
        mov di,200h
        mov cx,offset lpend-offset lp
        cld
        rep movsb

        mov word ptr es:[7ch*4],200h
        mov word ptr es:[7ch*4+2],0

        mov ax,4c00h
        int 21h

lp:  push bp
        mov bp,sp
        dec cx
        jcxz lpret
        add [bp+2],bx
lpret:        pop bp
        iret
lpend:        nop

code ends

end start

三、下面的程序,分别在屏幕的第 2、4、6、8 行显示 4 句英文诗,补全程序。

assume cs:code

code segment

s1:  db 'Good,better,best,','$'
s2:  db 'Never let it rest,','$'
s3:  db 'Till good is better,','$'
s4:  db 'And better,best.','$'
s:  dw offset s1,offset s2,offset s3,offset s4
row:  db 2,4,6,8

start:  mov ax,cs
        mov ds,ax
        mov bx,offset s
        mov si,offset row
        mov cx,4
ok:  mov bh,0
        mov dh,___________
        mov dl,0
        mov ah,2
        int 10h

        mov dx,___________
        mov ah,9
        int 21h
        ______________
        ______________
        loop ok

        mov ax,4c00h
        int 21h

code ends

end start

完成后编译运行,体会其中的编程思想。

补全程序后的完整代码如下(其中注释中含下划线的行即是需补全的代码行):

1. 功能:分别在屏幕的第 2、4、6、8 行显示 4 句英文诗。
2. 说明:通过结合调用 BIOS 的 int 10h 指令中断例程的 2 号子程序和 DOS 的 int 21h 指令中断例程的 9 号子程序来显示指定的字符串。

assume cs:code

code segment

s1:  db 'Good,better,best,','$'
s2:  db 'Never let it rest,','$'
s3:  db 'Till good is better,','$'
s4:  db 'And better,best.','$'
s:  dw offset s1,offset s2,offset s3,offset s4
row:  db 2,4,6,8

start:  mov ax,cs
        mov ds,ax
        mov bx,offset s  ; BX 寄存器存储着 s 标号的偏移地址,因此 [bx]=offset s1,[bx+2]=offset s2,[bx+3]=offset s3,[bx+4]=offset s4
        mov si,offset row  ; SI 寄存器存储着 row 标号的偏移地址,因此 [si]=2,[si+1]=4,[si+2]=6,[si+3]=8
        mov cx,4  ; 设置 loop ok 的循环次数:因为要输出 4 个字符串,所以设置 (cx)=4

; 调用 BIOS 的 int 10h 指令中断例程的 2 号子程序,以定位光标位置
ok:        mov bh,0  ; 设置光标位置位于显示缓冲区的第 0 页
        mov dh,[si]  ; _____设置光标位置的行号
        mov dl,0  ; 设置光标位置位于第 0 列
        mov ah,2  ; 设置 BIOS 的 int 10h 指令中断例程子程序号参数:调用 2 号子程序
        int 10h

; 调用 DOS 的 int 21h 指令中断例程的 9 号子程序,以输出字符串
        mov dx,[bx]  ; _____设置 ds:dx 指向的字符串首地址
        mov ah,9; 设置 DOS 的 int 21h 指令中断例程子程序号参数:调用 9 号子程序
        int 21h
        inc si  ;______
        add bx,2  ;______
        loop ok

        mov ax,4c00h
        int 21h

code ends

end start
评论次数(0)  |  浏览次数(149)  |  类型(课程实验) |  收藏此文  | 
 
 请输入验证码  (提示:点击验证码输入框,以获取验证码