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

我的博客

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

[2023-09-04 11:23] 第 17 章 实验 17  编写包含多个功能子程序的中断例程

(一)程序说明:本程序必须在纯 DOS 环境运行,因为 int 13h 中断例程只能在纯 DOS 环境运行。

(二)安装程序的代码
1. 参数说明:
(1) 用 AH 寄存器传递功能号:0 表示读,1 表示写。
由于要调用 BIOS 的 int 13h 中断例程,而 int 13h 中断例程的 AH 寄存器参数为:(ah)=2 或 (ah)=3。所以需要执行“add ah,2”指令,以转换 AH 寄存器存储的数据来适应 int 13h 中断例程的调用:
add ah,2  ; (ah)=0 或 (ah)=1,调用 BIOS 的 int 13h 中断时,(ah)=2 或 (ah)=3
(2) 用 DX 寄存器传递要读写的扇区的逻辑扇区号。
转换物理扇区的面号、磁道号、扇区号用到的除法运算方法,参见《课程设计 1》 的 divdw 子程序代码。
(3) 用 es:bx 指向存储读出数据或写入数据的内存区。
2. int 7Ch 中断例程说明:
(1) 读功能:将指定软盘位置所存储的字符串数据读入指定的内存区域。
(2) 写功能:将指定内存区域中的字符串数据写入软盘的某个存储位置。
注意,所需要显示的字符串数据由测试 int 7Ch 中断的程序提供。

assume cs:code

code segment

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

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

        mov ax,4c00h
        int 21h

; int 7Ch 中断例程
; begin int 7Ch
; 参数说明:
; (al)=1
; 由于字符串数据占用的存储空间不会超过 512 字节(即 512 个字符),所以只需 1 个扇区来存储。
; (al) 参数由测试程序提供,因为需要读取或写入的字符串数据也是由测试程序提供,所以在测试程序中才可以确定需要读取或写入字符串数据的大小。
; (ah)=0 读        (ah)=1 写
; 需用“add ah,2”指令转换为 int 13h 中断例程的参数:(ah)=2 读        (ah)=3 写
; (dx)=逻辑扇区号
; 转换成 int 13h 中断例程的参数:(dh)=面号 (dl)=驱动器号 (ch)=磁道号 (cl)=扇区号
; 转换方法:通过调用 divdw 除法运算子程序(参见《课程设计 1》)来实现转换
; es:bx 指向存储着读取字符串数据或写入字符串数据的内存区域
rwd:        push bx
        push ax

        mov cx,1440  ; 除数
        mov ax,dx  ; 逻辑扇区号值的低 16 位
        mov dx,0  ; 逻辑扇区号值的高 16 位
        call divdw  ; 调用 divdw 子程序,执行“逻辑扇区号 ÷ 1440”运算
        mov bx,ax  ; 将“逻辑扇区号 ÷ 1440”所得的磁盘面号(商)转存入 BX 寄存器
        mov ax,cx  ; 将“逻辑扇区号 ÷ 1440”所得余数转存入 AX 寄存器,以备后面使用
        mov cx,18  ; 除数
        call divdw  ; 调用 divdw 子程序,执行“rem(逻辑扇区号 ÷ 1440)÷18”运算
        mov ch,al  ; 将磁道号存入 CH 寄存器
        inc cl  ; CL 寄存器存储扇区号
        mov dh,bl  ; 将面号存入 DH 寄存器
        mov dl,0  ; DL 寄存器存储驱动器号
        pop ax
        pop bx
        add ah,2  ; 将 (ah) 参数转换成 int 13h 中断例程的功能号
        int 13h  ; 调用 int 13h 中断例程
rwdrep:        iret

; divdw 子程序的代码取自《课程设计 1》
; begin divdw
; 执行 divdw 子程序前已预先设置参数:
; (ax) = 被除数的低 16 位  (dx) = 被除数的高 16 位                (cx) = 除数
; 执行 divdw 子程序后返回的情况(指执行返回前的系列 pop 指令和 ret 指令之前):
; (ax) = 商数的低 16 位  (dx) = 商数的高 16 位   (cx) = 余数
divdw:        push bx
        ; 执行高 16 位被除数与原 16 位除数之间的除法运算
        mov bx,ax  ; 将被除数的低 16 位暂存到 BX 寄存器
        mov ax,dx  ; 将被除数的高 16 位转存到 AX 寄存器
        mov dx,0  ; 设置原被除数高 16 位进行的除法运算所需要使用的高 16 位被除数
        div cx  ; 执行高 16 位除法运算,计算结果的余数默认存储于 DX 寄存器
        mov bp,ax  ; 将高 16 位除法运算所得的商数转存到 BP 寄存器
        mov ax,bx  ; 将被除数的低 16 位传送回 AX 寄存器
        div cx  ; 执行低 16 位除法运算,计算结果的商数默认存储于 AX 寄存器
        mov cx,dx  ; 将低 16 位除法运算所得的余数(也是最终除法运算的余数)转存到 CX 寄存器
        mov dx,bp  ; 将高 16 位除法运算所得的商数转存到 DX 寄存器
        ; 经 divdw 子程序上述操作后,AX、DX 和 CX 寄存器分别存储着商数的低 16 位、高 16 位和余数

        pop bx
        ret
; end divdw

rwdend:        nop
; end int 7Ch

code ends

end start

(三)测试程序的代码
本程序用于测试本实验
1. 参数说明:
(1) 用 AH 寄存器传递功能号:0 表示读,1 表示写。
(2) 用 DX 寄存器传递要读写的扇区的逻辑扇区号。
(3) 用 es:bx 指向存储读出数据或写入数据的内存区。
2. 程序执行结果:
测试执行的 int 13h 中断例程,将软盘 A 中的数据写入指定的 dat2 段内存区域的操作,其返回 (ah)=0 说明该操作是成功的,且经 Debug 单步执行查看该段位置数据,正是预期的字符串数据。但若将其写入显存,则虽然 (ah)=0 说明操作成功,但屏幕显示却并非预期字符串数据;Debug 单步执行查看,该显存位置的数据也与预期字符串数据不一致 —— 参看下面的方法二的代码。

方法一

assume cs:code

; 操作对象:字符串数据
dat1 segment
  db 'Welcome to Masm!',496 dup (0)
dat1 ends

dat2 segment
  db 512 dup (0)
dat2 ends

code segment

; 将 dat1 段字符串数据写入到软盘 A 的 0 面、0 道、1 扇区
start:        mov ax,dat1
        mov es,ax
        mov al,1  ; 读取或写入字符串的扇区数为 1 个扇区
        mov ah,1  ; 先将字符串数据写入指定软盘的逻辑扇区
        mov bx,0  ; 令 es:bx 指向 dat1 段字符串首地址
        mov dx,0  ; 读、写的软盘逻辑扇区为 0,即软盘 A 的 0 面、0 道、1 扇区
        int 7Ch

        ; 读取软盘 A 的逻辑扇区 0 处的字符串数据到 dat2 段 512 个内存区域
        mov ax,dat2
        mov es,ax
        mov bx,0                                        ; 令 es:bx 指向 dat2 段内存区域
        mov al,1                                        ; 读取或写入字符串的扇区数为 1 个扇区
        mov ah,0                                        ; 读取软盘的逻辑扇区字符串数据到 dat2 段
        mov dx,0                                        ; 读、写的软盘逻辑扇区为 0,即软盘 A 的 0 面、0 道、1 扇区
        int 7Ch

        ; 将从软盘扇区中读到 dat2 段内存单元的字符串数据显示在屏幕上,以验证程序操作是否成功
        mov ax,0B800h
        mov ds,ax
        mov si,8*160+29*2  ; 8 行 30 列
        mov di,0
        mov ah,2  ; 显存属性:绿色字体
show:        cmp byte ptr es:[di],0
        je shend
        mov al,es:[di]
        mov [si],ax
        inc di
        add si,2
        jmp show
shend:        nop

        mov ax,4C00h
        int 21h

code ends

end start

方法二

assume cs:code

; 操作对象:字符串数据
data segment
  db 'Welcome to Masm!',496 dup (0)
data ends

code segment

; 将 data 段字符串数据写入到软盘 A 的 0 面、0 道、1 扇区
start:        mov ax,data
        mov es,ax
        mov al,1  ; 读取或写入字符串的扇区数为 1 个扇区
        mov ah,1  ; 先将字符串数据写入指定软盘的逻辑扇区
        mov bx,0  ; 令 es:bx 指向 data 段字符串首地址
        mov dx,0  ; 读、写的软盘逻辑扇区为 0,即软盘 A 的 0 面、0 道、1 扇区
        int 7Ch

        ; 读取软盘 A 的逻辑扇区 0 处的字符串数据到显示缓冲区 0 页 8 行 30 列
        mov ax,0B800h
        mov es,ax
        mov bx,7*160+29*2  ; 令 es:bx 指向显示缓冲区 0 页 8 行 30 列
        mov al,1  ; 读取或写入字符串的扇区数为 1 个扇区
        mov ah,0                                        ; 读取软盘的逻辑扇区字符串数据到屏幕上
        mov dx,0                                        ; 读、写的软盘逻辑扇区为 0,即软盘 A 的 0 面、0 道、1 扇区
        int 7Ch

        mov ax,4C00h
        int 21h

code ends

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