3 读到18扇区

我们趁着现在这劲头,再往后多读几个扇区吧。下面来看看projects/03_day下的harib00c。

本次添加的部分

  1. ;读磁盘
  2. MOV AX,0x0820
  3. MOV ES,AX
  4. MOV CH,0 ; 柱面0
  5. MOV DH,0 ; 磁头0
  6. MOV CL,2 ; 扇区2
  7. readloop:
  8. MOV SI,0 ; 记录失败次数的寄存器
  9. retry:
  10. MOV AH,0x02 ; AH=0x02 :读入磁盘
  11. MOV AL,1 ; 1个扇区
  12. MOV BX,0
  13. MOV DL,0x00 ; A驱动器
  14. INT 0x13 ; 调用磁盘BIOS
  15. JNC next ; 没出错时跳转到next
  16. ADD SI,1 ; SI1
  17. CMP SI,5 ; 比较SI5
  18. JAE error ; SI >= 5时,跳转到error
  19. MOV AH,0x00
  20. MOV DL,0x00 ; A驱动器
  21. INT 0x13 ; 重置驱动器
  22. JMP retry
  23. next:
  24. MOV AX,ES ; 把内存地址后移0x200
  25. ADD AX,0x0020
  26. MOV ES,AX ; 因为没有ADD ES,0x020指令,所以这里稍微绕个弯
  27. ADD CL,1 ; CL里加1
  28. CMP CL,18 ; 比较CL18
  29. 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处。