3 读到18扇区
我们趁着现在这劲头,再往后多读几个扇区吧。下面来看看projects/03_day下的harib00c。
本次添加的部分
;读磁盘
MOV AX,0x0820
MOV ES,AX
MOV CH,0 ; 柱面0
MOV DH,0 ; 磁头0
MOV CL,2 ; 扇区2
readloop:
MOV SI,0 ; 记录失败次数的寄存器
retry:
MOV AH,0x02 ; AH=0x02 :读入磁盘
MOV AL,1 ; 1个扇区
MOV BX,0
MOV DL,0x00 ; A驱动器
INT 0x13 ; 调用磁盘BIOS
JNC next ; 没出错时跳转到next
ADD SI,1 ; 往SI加1
CMP SI,5 ; 比较SI与5
JAE error ; SI >= 5时,跳转到error
MOV AH,0x00
MOV DL,0x00 ; A驱动器
INT 0x13 ; 重置驱动器
JMP retry
next:
MOV AX,ES ; 把内存地址后移0x200
ADD AX,0x0020
MOV ES,AX ; 因为没有ADD ES,0x020指令,所以这里稍微绕个弯
ADD CL,1 ; 往CL里加1
CMP CL,18 ; 比较CL与18
JBE readloop ; 如果CL <= 18 跳转至readloop
新出现的指令是JBE。这也是个条件跳转指令,是“jump if below or equal”的缩写,意思是小于等于则跳转。
程序做的事情很简单,只要读一读程序大家马上会明白。要读下一个扇区,只需给CL加1,给ES加上0x20就行了。CL是扇区号,ES指定读入地址。0x20是十六进制下512除以16的结果,如果写成“ADD AX,512/16”或许更好懂。(笔者在写的时候,直接在头脑中换算成了0x20,当然写成512/16也一样。)可能有人会说:往BX里加上512不是更简单吗?说来也是。不过这次我们想练习一下往ES里做加法的方法,所以这段程序就留在这儿吧。
可能有人会想,这里为什么要用循环呢?这个问题很好。的确,这里不是非要用循环才行,在调用读盘函数的INT 0x13的地方,只要将AL的值设置成17就行了。这样,程序一下子就能将扇区2~18共17个扇区的数据完整地读进来。之所以将这部分做成循环是因为笔者注意到了磁盘BIOS读盘函数说明的“补充说明”部分。这个部分内容摘要如下:
- 指定处理的扇区数,范围在0x01~0xff(指定0x02以上的数值时,要特别注意能够连续处理多个扇区的条件。如果是FD的话,似乎不能跨越多个磁道,也不能超过64KB的界限。)
这些内容看起来很复杂。因为很难一两句话说清楚,这里暂不详细解释,就结果而言,这些注意事项目前跟我们还没有关系,就是写成AL=17结果也是完全一样的。但这样的方式在下一次的程序中,就会成为问题,因此为了能够循序渐进,这里特意用循环来一个扇区一个扇区地读盘。
虽然显示的画面没什么变化,但我们已经把磁盘上C0-H0-S2到C0-H0-S18的512×17=8 704字节的内容,装载到了内存的0x8200~0xa3ff处。