实验17 编写包含多个功能子程序的中断例程
逻辑扇区的编号方法如下:
物理扇区号 逻辑扇区号
0面0道1扇区 0
0面0道2扇区 1
0面0道3扇区 2
0面0道4扇区 3
...
0面0道18扇区 17
0面1道1扇区 18
0面1道2扇区 19
0面1道3扇区 20
0面1道4扇区 21
...
0面1道18扇区 35
0面2道1扇区 36
0面2道2扇区 37
0面2道3扇区 38
0面2道4扇区 39
...
0面79道18扇区 1439
1面0道1扇区 1440
1面0道2扇区 1441
1面0道3扇区 1442
1面0道4扇区 1443
可以看出,逻辑扇区号和物理扇区号的关系如下:
逻辑扇区号=(面号*80+磁道号)*18+扇区号-1
面号=int(逻辑扇区号/1440)
磁道号=int(rem(逻辑扇区号/1440)/18)
扇区号=rem(rem(逻辑扇区号/1440)/18)+1
要求:安装一个新的int 7ch中断例程,实现通过逻辑扇区号对软盘进行读写。
参数说明:
(1)用ah寄存器传递功能号:0表示读,1表示写;
(2)用dx寄存器传递要读写的扇区的逻辑扇区号;
(3)用es:bx指向存储读出数据或写入数据的内存区。
(4)用al传送读取或写入的扇区数
分析:
根据前面的知识,可用int 13h的2号和3号功能对软盘的物理磁道进行读写。
思路:
搭建程序框架如下:
assume cs:code
code segment
;中断例程
;根据入口参数调用不同的功能子程序
;功能子程序A
;功能子程序B
start:
;安装
;写入偏移地址段地址
;初始化参数
;调用中断例程
;返回
code ends
end start
代码如下:
assume cs:code
stack segment
db 128 dup (0)
stack ends
code segment
;=======================================
;int7ch功能子程序
; 名称:int7ch
; 功能:通过逻辑扇区号对软盘进行读写
; 入口:(ah)=功能号:0表示读,1表示写;
; (al)=读出或写入的扇区数
; (dx)=要读写的扇区的逻辑扇区号;
; es:bx指向存储读出数据或写入数据的内存区。
; 返回:操作成功:(ah)=0,(al)=写入或读入的扇区数
; 操作失败:(ah)=出错代码
;=======================================
int7ch: jmp short int7chstart
table dw int7ch0,int7ch1
place db 0,0,0,0,0
int7chstart:push ax
push bx
push cx
push dx
push si
push ds
cmp ah,1
ja int7chno ;长度限制不能直接ja int7chret
jmp short int7chok
int7chno:jmp int7chret
int7chok:mov place[0],al ;读出或写入的扇区数
mov place[1],0 ;驱动器号
mov al,0
mov al,ah
mov ah,0
mov si,ax
add si,si ;对应的功能子程序的偏移地址
push si
mov ax,dx
mov dx,0
mov cx,05A0h ;1440
call divdw
mov ah,0
mov place[2],al ;面号=int(逻辑扇区号/1440)
mov ax,cx
mov dx,0
mov cx,012h ;18
call divdw
mov ah,0
mov place[3],al ;磁道号=int(rem(逻辑扇区号/1440)/18)
add cl,1
mov place[4],cl ;扇区号=rem(rem(逻辑扇区号/1440)/18)+1
mov al,place[0] ;读出的扇区数
mov dl,place[1] ;驱动器号
mov dh,place[2] ;磁头号(面)
mov ch,place[3] ;磁道数
mov cl,place[4] ;扇区号
pop si
jmp word ptr table[si]
int7ch0:mov ah,2 ;功能号
int 13h
jmp int7chret
int7ch1:mov ah,3 ;功能号
int 13h
jmp int7chret
;======================================
;名称:divdw
;功能:进行不会产生溢出的除法运算,被除数为dword型,除数为word型,结果为dword型。
;参数:(ax)=dword型数据的低16位
; (dx)=dword型数据的高16位
; (cx)=除数
;返回:(dx)=结果的高16位,(ax)=结果的低16位,(cx)=余数
;======================================
divdw:
push bx
push ax
mov ax,dx ;被除数高位
mov dx,0
div cx ;int(H/N)*65536,进行的16位除法,商返回给ax,余数返回给dx
mov bx,ax ;bx存放商int(H/N)
push dx ;dx为rem(H/N)
pop dx ;dx传送[rem(H/N)*65536+L]/N的高位,
pop ax ;存放[rem(H/N)*65536+L]/N的L
div cx ;是16位除法,商返回给ax,余数返回给dx
mov cx,dx ;返回结果余数
mov dx,bx ;返回结果高位到dx,返回结果低位到ax,
;int(H/N)*65536(dx存高位)+[rem(H/N)65536+L]/N(ax存低位,cx存余数)
pop bx
ret
int7chret:pop ds
pop si
pop dx
pop cx
pop bx
pop ax
iret
int7chend:nop
start: ;安装中断程序到一个安全的地方0:200,实现通过逻辑扇区号对软盘进行读写
mov ax,stack
mov ss,ax
mov sp,128
mov ax,cs
mov ds,ax
mov ax,0
mov es,ax
mov si,offset int7ch
mov di,200h
mov cx,offset int7chend-offset int7ch
cld
rep movsb
cli
;将中断程序的段地址偏移地址写入中断向量表
mov ax,0
mov es,ax
mov word ptr es:[7ch*4],0h ;!!!
mov word ptr es:[7ch*4+2],20h
;初始化参数,测试代码从此处修改
mov ax,cs
mov ds,ax
mov ax,0b800h
mov es,ax
sub ax,ax
mov dx,1443 ;要读写的扇区的逻辑扇区号
mov bx,0 ;es:bx指向存储读出数据或写入数据的内存区
mov ah,0 ;ah寄存器传递功能号:0表示读,1表示写
mov al,8 ;读出或写入的扇区数
sti
;调用中断例程
int 7ch
;返回
mov ax,4c00h
int 21h
code ends
end start
这道题的关键是搞清楚程序的入口
- [游客] 楼主写的挺好的,刚好解决我一个问题,谢谢了 07/08 23:57
- [keyia] 重新作了修改,可以正确显示10进制了;不过又发现新的问题:在重新打开cmd后,运行连接生成的.exe 06/01 03:30
- [tomato] 方法可以参考汇编语言课设一中对于类似12666这种十进制数据的显示算法。 05/31 21:14
- [keyia] 显示的十六进制数也不正确 05/31 20:02
- [keyia] 因为十进制显示目前我还没想到好的方法,先把16进制显示的作出来,只是实现了功能,还有很多问题,恳请大 05/31 19:31
- [keyia] 受教了,感谢。经你这样一说,就可以明显看出书中的问题具有极强的引导作用,可惜我的理解没转到上面来。思 05/31 19:12
- [tomato] 你的十进制数据只能显示两位的是吗?而且显示的十六进制数也不正确吧,因为数字和字符的ASCII码不是连 05/31 18:15
- [tomato] 具体的理解是正确的,但是有些问题没有说到点子上。比如,“思考:showchar函数是如何知道要显示多 05/31 17:14
- [q470393267] 这研究够有深度的,佩服佩服~还有楼主的精神确实很值得佩服! 05/28 12:57
- [keyia] 我正是被这里卡住了... 05/22 17:46