第三天 能读取软盘了!

第三天 能读取软盘了!

先介绍一个BOIS磁盘服务中断:INT 13H。因为我们只需要读软盘数据,所以只重点介绍2号读扇区子功能。

参数:

AH 功能号=02H

AL 需要读取的扇区数

CH 起始磁道数

CL 起始扇区数

DH 盘面号

DL 驱动器号

ES:BX 目标地址,读取出数据保存到内存的地址。

返回值:当CF=0时,操作成功。AH=0,AL为已读取的扇区数。操作失败时AH为错误码。

每个软盘都有正反两面,所以盘面号只能为0或1,每一面又分为80个磁道,就像80个同心圆一样,每个磁道又分为18个扇区。如图所示!

2(盘面)* 80(磁道)* 18(扇区)* 512(每扇区字节数)=1474560 Byte ≈1.44M Byte

这就是为什么总叫1.44M软盘的原因。

[课外知识]

软盘映像文件的数据就是对应软盘的实际位置。

数据组织顺序为:512字节→ 扇区,18扇区→ 盘面,2盘面→ 1磁道。

 

即理解为:每512个字节组成一个扇区,每个磁道有2个盘面,1个磁道每个盘面上有18个扇区,一个软盘共有80个磁道。有一点大家要注意,在映像文件中,每个磁道数据是以36个扇区数据来组织的,并不是一般理解的一个盘面的数据完了后再是另一个盘面的数据,而是每个磁道都以正反的扇区数据在一起。

读取软盘上的文件数据流程如下:

1、 计算目录区所在扇区号;

2、 读取目录区的一个扇区数据,如果已经到目录区尽头则跳转至10;

3、 在读取的数据中查找是否有目标文件名,如果没有则返回流程2;

4、 保存目标文件名的开始簇号,并计算数据区的开始扇区号;

5、 转换簇号为总扇区号;

6、 读取该扇区数据到指定内存,读取错误则跳转至10;

7、 读取FAT区的二个扇区数据,如果已经到FAT区尽头则跳转至10;

8、 取下一簇号,如果没有结束则跳转至5;

9、 结束;

10、 打印错误信息并结束;

因为我们要经常用到读取某个扇区的数据到指定内存,所以先写一个读取软盘扇区数据的子程序,以方便我们调用。

;##########################################################################

; 函数名: ReadSector

; 参数 : ax 需读取开始位置的总扇区号,这时的参数的总扇区号从0开始编号,以便统一。

; cl 需读取的扇区数

; es:bx 读取取的数据保存位置

; 返回值: 无

; 可能改变的寄存器有: AX , BX , CX , DX

; 用到的变量: [BPB_SecPerTrk] 每磁道扇区数,

; [BS_DrvNum] 当前驱动器号

;----------------------------------------------------------------------------

; 作用: 从第 ax 个扇区开始, 读取 cl 个扇区数据到内存 es:bx

;----------------------------------------------------------------------------

; -----------------------------------------------------------------------

; 怎样由扇区号求扇区在磁盘中的位置 (扇区号 -> 磁道号, 起始扇区, 盘面号)

; -----------------------------------------------------------------------

; 设总扇区号为 x

;                                   ┌ 磁道号 = y >> 1

;                      x ┌ 商 y ┤

; -------------- => ┤ └ 盘面号 = y & 1

;     每磁道扇区数 │

;                         └ 余 z => 起始扇区号 = z + 1

; -----------------------------------------------------------------------

ReadSector:

push bp ; 保存指针

mov bp, sp ;

sub sp, 2 ; 辟出两个字节的堆栈区域保存要读的扇区数: byte [bp-2],即为局部变量。

mov byte [bp-2], cl ; 保存需读取的扇区数,后面计算时需要用到CL寄存器。

;-------------------------------

push bx ; 保存 bx,下面的计算会占用BX寄存号。

mov bl, [BPB_SecPerTrk] ; bl: 除数 , 每磁道扇区数

div bl ; y 在 al 中, z 在 ah 中

; 此时AX为开始的扇区号,bl为每磁道扇区数,除出来的结果商:al 余数:ah

inc ah ; z++, 余数加1 ,得到在磁道中的开始扇区号,因为中断扇区号是从1开始编号。

mov cl, ah ; cl <- 起始扇区号, 将在磁道中开始扇区号保存到 cl 中

; 下面计算磁道号与盘面号

mov dh, al ; dh <- y 将余数存入 dh .

shr al, 1 ; y >> 1 (其实是 y/BPB_NumHeads, 这里BPB_NumHeads=2) 右移一位,等于除以2

mov ch, al ; ch <- 磁道号

and dh, 1 ; dh & 1 = 盘面号

pop bx ; 恢复 bx

;-------------------------------

; 至此, "磁道号, 起始扇区, 盘面号" 全部得到 - 磁道号: ch 盘面号: dh 开始扇区号: cl

mov dl, [BS_DrvNum] ; 取出启动的驱动器号,(0 表示 A 盘)

.GoOnReading:

mov ah, 2 ; 读取功能

mov al, byte [bp-2] ; 读 al 个扇区

int 13h ; 调用中断,进行磁盘扇区读取.

jc .GoOnReading ; 如果读取错误 CF 会被置为 1, 这时就不停地读, 直到正确为止

;--------------------------------------------------------------------

add sp, 2 ; 释放局部变量

pop bp ; 恢复环境并退出

ret

;==================================================================

上面这段子程序的参数要比服务中断的参数少,而且更好理解了。

代码中BPB_SecPerTrk、BS_DrvNum均在FAT头数据中有定义,BPB_SecPerTrk、BS_DrvNum为数据标号,标号加方括号为引号该标号所代码的内存中储存的数据。

子程序先保存必须数据,然后计算开始扇区号、磁道与盘面号,再调用中断,最后恢复环境数据并退出。

参数总扇区号(从0开始编号)除以每磁道扇区数(一般为18)所得余数为该磁道的偏移扇区数;

偏移扇区数加一得到中断所需的开始扇区号;

除出来的商再除以2所得商为磁道号,余数为盘面号。

提示: .GoOnReading:——为子标号,在标号前加小数点,代表该标号为上一个正常标号的子标号,一般用于子程序中的标号,方便局部引用,各子程序之间的子标号可以重复。关于更多的相关知识请查看NASM使用文档。

今天能把上面这段代码看懂就可以了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值