- ;----------------------------------------------------------------------------
- ; 函数名: ReadSector
- ;----------------------------------------------------------------------------
- ; 作用:
- ; 从第 ax 个 Sector 开始, 将 cl 个 Sector 读入 es:bx 中
- ReadSector:
- ; -----------------------------------------------------------------------
- ; 怎样由扇区号求扇区在磁盘中的位置 (扇区号 -> 柱面号, 起始扇区, 磁头号)
- ; -----------------------------------------------------------------------
- ; 设扇区号为 x
- ; ┌ 柱面号 = y >> 1
- ; x ┌ 商 y ┤
- ; -------------- => ┤ └ 磁头号 = y & 1
- ; 每磁道扇区数 |
- ; └ 余 z => 起始扇区号 = z + 1
-
- push bp
- mov bp, sp
- sub esp, 2 ; 辟出两个字节的堆栈区域保存要读的扇区数: byte [bp-2]
-
- mov byte [bp-2], cl
- push bx ; 保存 bx
- mov bl, [BPB_SecPerTrk] ; bl: 除数
- div bl ; y 在 al 中, z 在 ah 中
- inc ah ; z ++
- mov cl, ah ; cl <- 起始扇区号
- mov dh, al ; dh <- y
- shr al, 1 ; y >> 1 (其实是 y/BPB_NumHeads, 这里BPB_NumHeads=2)
- mov ch, al ; ch <- 柱面号
- and dh, 1 ; dh & 1 = 磁头号
- pop bx ; 恢复 bx
- ; 至此, "柱面号, 起始扇区, 磁头号" 全部得到 ^^^^^^^^^^^^^
- mov dl, [BS_DrvNum] ; 驱动器号 (0 表示 A 盘)
- .GoOnReading:
- mov ah, 2 ; 读
- mov al, byte [bp-2] ; 读 al 个扇区
- int 13h
- jc .GoOnReading ; 如果读取错误 CF 会被置为 1, 这时就不停地读, 直到正确为止
-
- add esp, 2
- pop bp
-
- ret
于渊 关于软盘结构的这段笔墨惜得不是地方 ,其实很多看这种入门级书的读者对于软盘(磁盘)的结构认识大多都是不到位的。我在阅读这段代码时也费了不少周折,最后发现其实是我对软盘结构认识不足,补上这一课,这段代码就好读多了。
3.5寸1.44M软盘结构
1、 结构:2面、80道/面、18扇区/道、512字节/扇区
扇区总数 = 2面 * 80道/面 * 18扇区/道 = 2880扇区
存储容量 = 512字节/扇区 * 2880扇区 = 1440 KB
2、 2 面: 编号0----1;
80道: 编号0----79 ;
18扇区:编号1----18 ;
这个很多书都有介绍,恕不细表。下面来看看软盘中磁道的安排,这会使我们感到很诧异——原来软盘结构安排会是这样。
3、相对扇区号:共2880个扇区,相对扇区号范围为 0----2879
编号顺序:
扇区物理号 相对扇区号
0面,0道,1扇区 0
0面,0道,2扇区 1
0面,0道,3扇区 2
…………………… ... 0面,0道
0面,0道,18扇区 17
1面,0道,1扇区 18
…………………… ... 1面,0道
1面,0道,18扇区 35
0面,1道,1扇区 36
…………………… ... 0面,1道
0面,1道,18扇区 53
1面,1道,1扇区 54
…………………… 1面,1道
注意下红色字,它表明软盘的排列并不是按照我们所想象的"把0面先排完了再开始排1面,而是交替排列的"
4、物理扇区号(A,B,C)与相对扇区号(S)相互转换公式:
头/面(0--1) 道(0-79) 扇区 (1--18)
A B C
例如:A=1面 B= 15道 C=7扇区 这就是它的物理扇区号,现在进入关键问题——如何计算相对扇区呢?
计算相对扇区时,参照上面的软盘结构排列表。例如:如果我们要计算1面15道第7扇区的相对扇区号,我们应该清楚在15道之前,即0~14道里面,每道都有有18个扇区,而又因为软盘磁道的交替排列方式,0、1两面都有磁道,故而在0~14道有(0道----14道)*2面*18, 在计算第15道时,注意下我们要计算的15道是在1面,而1面之前的0面15道,有18个扇区,而在1面的15道磁道中,有7个扇区。一共有0面的第15道18个扇区+1面第15道7个扇区-1,所以上述例子中的相对扇区号是(0道----14道)*2面*18+0面的第15道18个扇区+1面第15道7个扇区-1
有了上面的叙述,源代码中除以18求出来商就是磁道数,而余数即是扇区数目,由于除以了18,那么前面的结构表就可以如下表示:
0面,0道
1面,0道
0面,1道
1面,1道
0面,2道
1面,2道
.......
0面,12道
1面,12道
磁道除以2表示当前物理磁道号(因为是交替排列的!注意看上表的结构),而余数就可以表示磁头号。
于渊代码中间很多都是直接在寄存器中反复玩弄汇编技巧,这段程序让我看得相当郁闷~ 自己改写了一个,里面用内存保留计算结果,这样清晰很多:
- dbTrackNum db 0 ;磁道数
- dbSectorNum db 0 ;扇区数
- dbdriverNum db 0 ;驱动器号
- dbResistiveNum db 0 ;磁头数
-
- ReadSector:
- push dx
- push bx
-
- mov bl,[BPB_SecPerTrk]
- div bl
- inc ah
- mov byte [dbSectorNum],ah
- mov ah,al
- shr al,1
- mov byte [dbTrackNum],al
- and ah,1b
- mov byte [dbResistiveNum],ah
- mov ah,2h
- mov al,cl
- mov dl,[dbdriverNum]
- mov dh,[dbResistiveNum]
- mov ch,[dbTrackNum]
- mov cl,[dbSectorNum]
- pop bx
- .Reading:
- int 13h
- jc .Reading
- pop dx
- ret
- ;----------------------------------------------------------------------------
- ; 函数名: ReadSector
- ;----------------------------------------------------------------------------
- ; 作用:
- ; 从第 ax 个 Sector 开始, 将 cl 个 Sector 读入 es:bx 中
- ReadSector:
- ; -----------------------------------------------------------------------
- ; 怎样由扇区号求扇区在磁盘中的位置 (扇区号 -> 柱面号, 起始扇区, 磁头号)
- ; -----------------------------------------------------------------------
- ; 设扇区号为 x
- ; ┌ 柱面号 = y >> 1
- ; x ┌ 商 y ┤
- ; -------------- => ┤ └ 磁头号 = y & 1
- ; 每磁道扇区数 |
- ; └ 余 z => 起始扇区号 = z + 1
-
- push bp
- mov bp, sp
- sub esp, 2 ; 辟出两个字节的堆栈区域保存要读的扇区数: byte [bp-2]
-
- mov byte [bp-2], cl
- push bx ; 保存 bx
- mov bl, [BPB_SecPerTrk] ; bl: 除数
- div bl ; y 在 al 中, z 在 ah 中
- inc ah ; z ++
- mov cl, ah ; cl <- 起始扇区号
- mov dh, al ; dh <- y
- shr al, 1 ; y >> 1 (其实是 y/BPB_NumHeads, 这里BPB_NumHeads=2)
- mov ch, al ; ch <- 柱面号
- and dh, 1 ; dh & 1 = 磁头号
- pop bx ; 恢复 bx
- ; 至此, "柱面号, 起始扇区, 磁头号" 全部得到 ^^^^^^^^^^^^^
- mov dl, [BS_DrvNum] ; 驱动器号 (0 表示 A 盘)
- .GoOnReading:
- mov ah, 2 ; 读
- mov al, byte [bp-2] ; 读 al 个扇区
- int 13h
- jc .GoOnReading ; 如果读取错误 CF 会被置为 1, 这时就不停地读, 直到正确为止
-
- add esp, 2
- pop bp
-
- ret
于渊 关于软盘结构的这段笔墨惜得不是地方 ,其实很多看这种入门级书的读者对于软盘(磁盘)的结构认识大多都是不到位的。我在阅读这段代码时也费了不少周折,最后发现其实是我对软盘结构认识不足,补上这一课,这段代码就好读多了。
3.5寸1.44M软盘结构
1、 结构:2面、80道/面、18扇区/道、512字节/扇区
扇区总数 = 2面 * 80道/面 * 18扇区/道 = 2880扇区
存储容量 = 512字节/扇区 * 2880扇区 = 1440 KB
2、 2 面: 编号0----1;
80道: 编号0----79 ;
18扇区:编号1----18 ;
这个很多书都有介绍,恕不细表。下面来看看软盘中磁道的安排,这会使我们感到很诧异——原来软盘结构安排会是这样。
3、相对扇区号:共2880个扇区,相对扇区号范围为 0----2879
编号顺序:
扇区物理号 相对扇区号
0面,0道,1扇区 0
0面,0道,2扇区 1
0面,0道,3扇区 2
…………………… ... 0面,0道
0面,0道,18扇区 17
1面,0道,1扇区 18
…………………… ... 1面,0道
1面,0道,18扇区 35
0面,1道,1扇区 36
…………………… ... 0面,1道
0面,1道,18扇区 53
1面,1道,1扇区 54
…………………… 1面,1道
注意下红色字,它表明软盘的排列并不是按照我们所想象的"把0面先排完了再开始排1面,而是交替排列的"
4、物理扇区号(A,B,C)与相对扇区号(S)相互转换公式:
头/面(0--1) 道(0-79) 扇区 (1--18)
A B C
例如:A=1面 B= 15道 C=7扇区 这就是它的物理扇区号,现在进入关键问题——如何计算相对扇区呢?
计算相对扇区时,参照上面的软盘结构排列表。例如:如果我们要计算1面15道第7扇区的相对扇区号,我们应该清楚在15道之前,即0~14道里面,每道都有有18个扇区,而又因为软盘磁道的交替排列方式,0、1两面都有磁道,故而在0~14道有(0道----14道)*2面*18, 在计算第15道时,注意下我们要计算的15道是在1面,而1面之前的0面15道,有18个扇区,而在1面的15道磁道中,有7个扇区。一共有0面的第15道18个扇区+1面第15道7个扇区-1,所以上述例子中的相对扇区号是(0道----14道)*2面*18+0面的第15道18个扇区+1面第15道7个扇区-1
有了上面的叙述,源代码中除以18求出来商就是磁道数,而余数即是扇区数目,由于除以了18,那么前面的结构表就可以如下表示:
0面,0道
1面,0道
0面,1道
1面,1道
0面,2道
1面,2道
.......
0面,12道
1面,12道
磁道除以2表示当前物理磁道号(因为是交替排列的!注意看上表的结构),而余数就可以表示磁头号。
于渊代码中间很多都是直接在寄存器中反复玩弄汇编技巧,这段程序让我看得相当郁闷~ 自己改写了一个,里面用内存保留计算结果,这样清晰很多:
- dbTrackNum db 0 ;磁道数
- dbSectorNum db 0 ;扇区数
- dbdriverNum db 0 ;驱动器号
- dbResistiveNum db 0 ;磁头数
-
- ReadSector:
- push dx
- push bx
-
- mov bl,[BPB_SecPerTrk]
- div bl
- inc ah
- mov byte [dbSectorNum],ah
- mov ah,al
- shr al,1
- mov byte [dbTrackNum],al
- and ah,1b
- mov byte [dbResistiveNum],ah
- mov ah,2h
- mov al,cl
- mov dl,[dbdriverNum]
- mov dh,[dbResistiveNum]
- mov ch,[dbTrackNum]
- mov cl,[dbSectorNum]
- pop bx
- .Reading:
- int 13h
- jc .Reading
- pop dx
- ret