DOS程序员手册(一)

时间:2022-12-10 18:23:06

当今MS-Windows横扫大江南北,让我们这就来研究一下它的祖宗——MS-DOS!

这本书很难得,希望读者好好学习!

DOS程序员手册(一)

DOS教程

(以下内容全部为原作者的阐述,照样保留)

这个电子书只是很简单地把txt做成了chm,文本格式方面可能会让人看得有点恼火,呵,不好意思了,将就一下,因为我本身写网页是手工的,如果全部进行整理会花上几天时间。希望您看的时候不会边看边骂

(京)新登字158号

DOS Programmer's Reference,4th Edition

Terrv Dettmann

Authorized translation from the English language edition published by Que  Corporation.

Copyright 1993 by Que Corporation

All rights reserved. No part of this book maybe reproduced or transmitted in any form or by any means,electronic

or mechanical, including photocopying,recording or by any information storage retrieval system,without permis-

sion in writing from the Publisher.

Chinese language edition published by Tsinghua University Press.

本书英文版Que Corporation于1993年出版,版权为Que所有。本书中文版由Que Corporation授予清华大学出

版社出版。未经出版科书面允许,不得以任何方式复制或抄袭本书内容。

*国家版权局著作权合同登记章图字:01-95-330。

版权所有,翻印必究。

本书封面贴有清华大学出版社激光防伪标签,无标签者不得销售。

图书在版编目(CIP)数据

DOS程序员参考手册/(美)Detmann著;熊桂喜等译.-北京:清华大学出版社,1995

ISBN 7-302-001984-3

微型计算机磁盘操作系统手册IV.  TP316- 62

中国版本图书馆CIP数据核字(95)第17042号

出版者:清华大学出版社(北京清华大学校内,邮编100084)

印刷者:北京人民文学印刷厂

发行者:新华书店总店北京科技发行所

开本: 787*1092 1/16 印张: 54.75 字数: 1299千字

版次: 1996年1月第1版1996年1月第1次印刷

书号: ISBN 7-302-01984-3/TP·915

印数: 0001-5000

定价: 89.00元

a3页

内容简介

本书是介绍MS-DOS编程的技术书籍,是一本多年来的权威性畅销著作。内容非常

全面,覆盖了DOS的各个方面。

·包括了MS-DOS  6.xx的全部内容,并覆盖了DOS的各个版本(1.0-6.22)。书中

包括全部的DOS功能调用及数据结构,包括一些未公开的功能和保留的功能。

·介绍了PC编程时所需的BIOS、鼠标、EMS、XMS、DPMI、任务切换等的功能调

用。

.分专题介绍了DOS编程的各个方面:输入/输出设备;内存、文件、目录、设备管

理;TSR及设备驱动程序;DOS出错处理等等。

·介绍了如何在汇编语言、BASIC C/C++及Pascal中使用DOS及BIOS的技术。

·丰富而实用的大量实例源代码。

本书的读者对象为对PC编程有兴趣的专业技术人员、大专院校学生及计算机爱好

者。

a4页

目      录

译者序……………………………………………………………………………………………………… 1

引言…………………………………………………………………………………………………   2

第一部分DOS概述

第1章DOS简介………………………………………………………………………………………3

1.1什么是DOS………………………………………………………………………………………3

1.2DOS的历史………………………………………………………………………………………4

1.2.1 1.0版…………………………………………………·………………………………6

1.2.2 1.1版……………………………………………………………………………………6

1.2.3 1.25版…………………………………………………………………………………6

1.2.4 2.0版……………………………………………………………………………………6

1.2.5 2.1版…………………………………………………………………………………7

1.2.6 3.0版……………………………………………………………………………………7

1.2.7 3.1版……………………………………………………………………………………7

1.2.8 3.2版……………………………………………………………………………………7

1.2.9 3.3版……………………………………………………………………………………8

1.2.10 4.0版…………………………………………………………………………………8

1.2.11 5.0版…………………………………………………………………………………8

1.2.12 6.0版…………………………………………………………………………………8

1.2.13未来展望……………………………………………………………………………9

1.3DOS的结构……………………………………………………………………………………9

1.4 DOS的程序员接口……………………………………………………………………………10

1.5小结………………………………………………………………………………………………11

第2章     DOS系统结构………………………………………………………………………………12

2.1“虚机”概念………………………………………………………………………………………12

2.2物理机器…………………………………………………………………………………………13

2.3处理器……………………………………………………………………………………………13

2.3.1 8086内存寻址…………………………………………………………………………14

2.3.2 8086寄存器集…………………………………………………………………………16

2.3.3 80286及其更高档的处理器…………………………………………………………19

a5页

2.3.4CPU芯片的识别…………………………………………………………………… 20

2.3.5数学协处理器…………………………………………………………………………22

2.3.6数学协处理器的识别…………………………………………………………………22

2.4内存………………………………………………………………………………………………24

2.5 I/O通道……………………………………………………………………………………… 25

2.5.1键盘……………………………………………………………………………………25

2.5.2显示器屏幕……………………………………………………………………………26

2.5.3打印机…………………………………………………………………………………28

2.5.4串行口…………………………………………………………………………………28

2.5.5鼠标………………………………-……………………………………………… 29

2.6存储设备…………………………………………………………………………………………29

2.6.1物理磁盘结构…………………………………………………………………………29

2.6.2逻辑磁盘结构…………………………………………………………………………30

2.7软件………………………………………………………………………………………………31

2.7.1 BIOS……………………………………………………………………………………31

2.7.2 DOS核心………………………………………………………………………………32

2.7.3命令处理器………………………………………………………………………… 32

2.7.4设备驱动程序…………………………………………………………………………33

2.8小 结………………………………………………………………………………………………34

第3章动态的DOS…………………………………………………………………………………35

3.1 DOS启动顺序…………………………………………………………………………………35

3.2命令处理…………………………………………………………………………………………38

3.3 DOS下的程序…………………………………………………………………………………39

3.3.1 CoM程序………………………………………………………………………………39

3.3.2 EXE程序………………………………………………………………………………41

3.4一些高级语言的例子……………………………………………………………………………45

3.4.1一个Turbo Pascal程序………………………………………………………………45

3.4.2一个编译的C程序…………………………………………………………………46

3.4.3比较不同版本的程序…………………………………………………………………46

3.5中断………………………………………………………………………………………………48

3.5.1内部中断………………………………………………………………………………49

3.5.24非屏蔽中断……………………………………………………………………………49

3.5.3硬件(可屏蔽)中断……………………………………………………………………50

3.5.4软件中断………………………………………………………………………………50

3.6内存分配与管理…………………………………………………………………………………52

3.7小结………………………………………………………………………………………………55

第4章DOS和BIOS接口 ………………………………………………………………………56

4.1从程序中访问DOS和BIOS…………………………………………………………………56

4.1.1一个对Dos的简单调用………………………………………………………………57

a6页

4.1.2传递字符串地址给DOS………………………………………………………………58

4.2高级语言资源……………………………………………………………………………………59

4.2.1C语言………………………………………………………………………………60

4.2. 2 Turbo Pascal…………………………………………………………………………68

4.2.3 Quick BASIC…………………………………………………………………………72

4.3小结………………………………………………………………………………………………76

第二部分    输入输出设备

第5章输出设备………………………………………………………………………………………79

5.1基本的字符设备…………………………………………………………………………………79

5.2看看显示系统的工作方式…………………………………………………………………… 80

5.2.1存储和显示视频数据…………………………………………………………………81

5.2.2视频显示格式…………………………………………………………………………83

5.2.3识别视频显示适配卡…………………………………………………………………87

5.3视频功能…………………………………………………………………………………………99

5.3.1利用DOS和BIOS视频功能编程……………………………………………………99

5.3.2使用多个显示页………………………………………………………………………104

5.4打印机功能……………………………………………………………………………………106

5.5小结……………………………………………………………………………………………108

第6章输入设备……………………………………………………………………………………109

6.1键盘……………………………………………………………………………………………109

6.1.1了解键盘的工作方式…………………………………………………………………109

6.1.2用BASIC读键盘……………………………………………………………………113

6.1.3使用Int 16h来访问键盘……………………………………………………………114

6.1.4使用Int 21h来访问键盘……………………………………………………………118

6.1.5识别键盘支持的水平…………………………………………………………………124

6.2鼠标……………………………………………………………………………………………125

6.2.1了解鼠标的工作方式…………………………………………………………………125

6.2.2初始化鼠标驱动程序…………………………………………………………………125

6.2.3鼠标位于何处…………………………………………………………………………126

6.3小 结……………………………………………………………………………………………130

第7章串行设备……………………………………………………………………………………131

7.1串行接口………………………………………………………………………………………132

7.2 串行转换:UART……………………-…………………………………………………… 134

7.2.1发送保持寄存器(THR)………………………………………………………………135

7.2.2接收数据寄存器(RDR)………………………………………………………………135

7.2. 3波特率除数(BRD)……………………………………………………………………135

7.2.4中断允许寄存器(IER)………………………………………………………………136

a7页

7.2.5中断识别寄存器(IIR)………………………………………………………………136

7.2.6FIFO控制寄存器(FCR)……………………………………………………………137

7.2.7线控制寄存器(LCR)…………………………………………………………………137

7.2.8调制解调器控制寄存器(MCR)……………………………………………………138

7.2.9线状态寄存器(LSR)…………………………………………………………………138

7.2.10调制解调器状态寄存器(MSR)…………………………………………………139

7.3将通信端口初始化……………………………………………………………………………140

7.4调制解调器……………………………………………………………………………………142

7.5编写一个终端程序……………………………………………………………………………143

7.5.1双工考虑………………………………………………………………………………143

7.5.2控制程序Term.c……………………………………………………………………144

7.5.3支持函数………………………………………………………………………………144

7.6使用term.c……………………………………………………………………………………151

7.7直接访问UART………………………………………………………………………………151

7.7.1汇编语言………………………………………………………………………………152

7.7.2C语言…………………………………………………………………………………152

7.7.3BASIC语言……………………………………………………………………………152

7.7.4Pascal语言……………………………………………………………………………152

7.8修改Term.c…………………………………………………………………………………152

7.9回送检测…………………………………………………………………………………… 154

7.10评价串行I/O设备……………………………………………………………………………155

7.11小结……………………………………………………………………………………………155

第三部分    磁盘、目录和文件

第8章磁盘…………………………………………………………………………………………159

8.1磁盘的内部结构…………………………………………………………………………… 159

8.1.1分区表………………………………………………………………………………160

8.1.2引导记录………………………………………………………………………………163

8.1.3文件分配表(FAT)……………………………………………………………………166

8.2利用磁盘功能…………………………………………………………………………………172

8.2.1驱动器信息……………………………………………………………………………172

8.2.2格式化磁盘……………………………………………………………………………177

8.3小结……………………………………………………………………………………………183

第9章目录和文件…………………………………………………………………………………184

9.1磁盘目录……………………………………………………………………………………184

9.1.1根目录……………………………………………………………………………… 185

9.1.2目录项…………………………………………………………………………………186

9.1.3子目录…………………………………………………………………………………190

9.1.4卷标………………………………………………………………………………… 190

a8页

9.2什么是文件……………………………………………………………………………………191

9.3 DOS处理文件的方式…………………………………………………………………………191

9.3.1标准文件控制块………………………………………………………………………192

9.3.2扩展的文件控制………………………………………………………………………192

9.3.3基本的FCB文件处理……………………………………………………………193

9.3.4什么时候使用FCB功能…………………………-………………………………193

9.3.5句柄功能………………………………………………………………………………194

9.3.6基本的句柄文件处理技术……………………………………………………………194

9.3.7何时使用句柄功能……………………………………………………………………195

9.3.8练习:目录搜索………………………………………………………………………195

9.4小结……………………………………………………………………………………………199

第四部分内存管理及其它

第10章程序和内存管理…………………………………………………………………………203

10.1内存的工作方式………………………………………………………………………………204

10.2内存管理………………………………………………………………………………………207

10.2.1压缩程序内存………………………………………………………………………209

10.2.2获得更多的内存……………………………………………………………………210

10.3扩充内存………………………………………………………………………………………211

10.3.1确定扩充内存的有效性………………………………………………………… 211

10.3.2使用扩充内存………………………………………………………………………213

10.4扩展内存…………………………………………………………………………………… 217

10.4.1确定扩展内存的有效性……………………………………………………………217

10.4.2使用扩展内存………………………………………………………………………218

10.5程序执行………………………………………………………………………………………245

10.5.1 EXEC功能…………………………………………………………………………245

10.5.2程序退出…………………………………………………………………………··-249

10.5.3潜在的EXEC问题…………………………………………………………………249

10.5.4往DOS中输入命令………………………………………………………………250

10.5.5替换DOS的内部命令……………………………………………………………251

10.5.6为什么有些EXE文件不能被转换成COM文件………………………………252

10.5.7程序段前缀(PSP)…………………………………………………………………252

10.6内存常驻软件的编程…………………………………………………………………………254

10.7小结……………………………………………………………………………………………256

第11章中断处理程序……………………………………………………………………………257

11.1什么是中断……………………………………………………………………………………257

11.2中断的工作方式………………………………………………………………………………259

11.3 Intel 8086系列的中断类型…………………………………………………………………259

11.3.1内部硬件中断…………………………………………………………………… 260

a9页

11.3.2外部硬件中断……………………………………………………………………260

11.3.3软件中断……………………………………………………………………………261

11.4中断向量……………………………………………………………………………………262

11.5获取和设置中断向量…………………………………………………………………………262

11.6 什么时候必须写一个中断处理程序?………………………………………………………263

11.7编写Ctrl-C处理程序………………………………………………………………………264

11.8编写一个关键出错处理程序…………………………………………………………………270

11.9 TSR综述……………………………………………………………………………………294

11.10TSR的中断基础……………………………………………………………………………296

11.10.1键盘中断…………………………………………………………………………296

11.10.2 InDOS标志、DOSOK中断和定时器中断………………………………………296

11.11小结…………………………………………………………………………………………302

第12章设备驱动程序………………………………………………………………………… 304

12.1驱动程序的类型………………………………………………………………………………305

12.1.1字符设备驱动程序…………………………………………………………………305

12.1.2块设备驱动程序……………………………………………………………………305

12.2设备驱动程序的工作方式……………………………………………………………………306

12.3设备驱动程序的结构…………………………………………………………………………308

12.3.1设备头………………………………………………………………………………309

12.3.2策略例程………………………………………………………………………… 312

12.3.3中断例程……………………………………………………………………………314

12.4完整的驱动程序………………………………………………………………………………328

12.4.1汇编驱动程序………………………………………………………………………331

12.4.2安装驱动程序………………………………………………………………………332

12.4.3调试驱动程序………………………………………………………………………332

12.5编一个实用的驱动程序………………………………………………………………………333

12.6使用设备驱动程序……………………………………………………………………………334

12.7小结……………………………………………………………………………………………334

第13章其它杂项功能……………………………………………………………………………336

13.1DOS版本信息………………………………………………………………………………336

13.2设备信息………………………………………………………………………………………339

13.3日期和时间功能………………………………………………………………………………341

13.4扩展的出错处理………………………………………………………………………………345

13.5未公开的功能…………………………………………………………………………………349

13.6小结…………………………………………………………………………………………350

第五部分参考手册

第14章参考手册概述……………………………………………………………………………353

a10页

14.1怎样介绍各个服务……………………………………………………………………………353

14.1.1中断号…………………………………………………………………………… 353

14.1.2功能号………………………………………………………………………………354

14.1.3子功能号……………………………………………………………………………354

14.1.4版本的有效性………………………………………………………………………355

14.1.5用途……………………………………………………………………………… 355

14.1.6描述…………………………………………………………………………………355

14.1.7调用寄存器…………………………………………………………………………355

14.1.8返回寄存器…………………………………………………………………………355

14.1.9注释…………………………………………………………………………………355

14.2详细的功能总结………………………………………………………………………………355

第15章BIOS参考手册……………………………………………………………………………371

第16章DOS参考手册……………………………………………………………………………470

16.1怎样调用DOS服务…………………………………………………………………………470

16.2可重入性………………………………………………………………………………………470

16.3保留的功能……………………………………………………………………………………471

16.4未公开的功能…………………………………………………………………………………472

16.5 DOS服务……………………………………………………………………………………472

第17章鼠标参考手册……………………………………………………………………………649

17.1鼠标的功能…………………………………………………………………………………649

17.2鼠标驱动程序的EGA寄存器接口…………………………………………………………677

第18章EMS参考手册……………………………………………………………………………682

第19章XMS参考手册……………………………………………………………………………721

第20章DPMI参考手册…………………………………………………………………………731

第21章任务切换参考手册………………………………………………………………………780

21.1数据结构………………………………………………………………………………………780

21.2通报功能………………………………………………………………………………………784

21.3服务功能………………………………………………………………………………………789

第22章DoubleSpace参考手册…………………………………………………………………794

22.1CVF结构……………………………………………………………………………………794

22.2API功能………………………………………………………………………………………795

附录A ASCII字符集………………………………………………………………………………799

a11页

附录B 选中的内存位置……………………………………………………………………………806

B.1中断表…………………………………………………………………………………………806

B.2 BIOS数据区……………………………………………………………………………………808

附录C 一种标准的TSR标识技术………………………………………………………………811

C.1用户参数块………………………………………………………………………………… 812

C.2功能00h(检查安装)…………………………………………………………………………813

C.3功能01h(返回用户参数指针)………………………………………………………………814

C.4其它TesseRact功能…………………………………………………………………………815

附录D 保留的DOS功能…………………………………………………………………………816

D.1未公开的DOS功能的种类……………………………………………………………………816

D.2覆盖范围……………………………………………………………………………………817

D.3使用功能52h—表中表……………………………………………………………………818

D.4小结……………………………………………………………………………………………855

附录E 支持资源清单………………………………………………………………………………856

E.1硬件……………………………………………………………………………………………856

E.2 MS-DOS和BIOS编程………………………………………………………………………856

E.3编程语言…………………………………………………………………………………… 857

E.4一般编程技术……………………………………………………………………………… 858

      《DOS程序员参考手册》第四版;英文原名为“DOS Programmer's Reference, 4th
Edition”,作者是美国的Terry Dettman及AllenL.Wyatt, Sr. 。本书是Que的保留书
目,内容完整,解释清楚,在介绍DOS编程技术的书籍中,本书是多年来最有影响、最受欢
迎的书籍之一。
      DOS是整个PC机的技术基础,即使是到今天,在Windows 3.1广为流行,乃至Win- 
dows 95(或Chicago)即将问世时仍是如此。因为无论是Windows、OS/2、NetWare还是
Windows NT,都离不开DOS的基础性、概念性支持。虽然DOS是一个单用户的操作系
统,但所有上述的多任务操作系统都是从DOS上发展起来的,并且尽可能地与DOS保持
兼容,才能被用户接受。用户使用计算机,必须先从DOS学习起,具备了DOS的初步知识
才能进入Windows、OS/2乃至NetWare及Windows NT的网络世界。学习PC编程的
人,无论是学生或计算机爱好者,都得从DOS开始,更不要说是开始学习C 、BASIC、Pas- 
cal,特别是学习汇编语言编程的人们。即使是PC编程高手,首先也必须具备完整而深入
·的DOS知识。
      正是在这样的背景下,我们在清华大学出版社的全力支持下,组织翻译了这本《DOS
程序员参考手册》。原书已到第四版,但在国内却是首次介绍。与Microsoft公司为DOS
软件而准备的《程序员技术参考手册》相比,这本书内容更丰富、完整、更易于使用。
      全书共分五个部分及五个附录。第一至四部分是以技术专题方式对DOS编程的各个
方面进行了论述,并以大量的C/C++、Pascal、BASIC及汇编语言实例,使读者不仅可以
从理论上学习DOS编程的知识,而且可通过实例,立即构造出自己的实用程序。其中,第
一部分可以说是一些预备性的知识,介绍了DOS的历史、DOS的结构、DOS所运行的硬
件技术基础,以及提供给程序员的DOS和BIOS编程接口。本部分通过实例说明,要用好
DOS,使编出的程序效率更高,必须选择好适当的编程及层次;在C/C++、Pascal、BA-
SIC中,都可以充分地利用DOS和BIOS提供的资源。
      第二部分介绍DOS的外部设备编程技术。其中输入设备有键盘和鼠标;输出设备有
字符设备、显示器、打印机等。另外还重点介绍了串行设备。作者在这一部分里所介绍的
知识很有特色,且不局限于DOS范围,而是从编程者的需要出发,从各个层次上对输入
输出设备进行编程,且理论与实践并举。
      第三部分介绍了DOS的磁盘、文件及目录管理和程序员对其编程时所应具备的技术
及知识。这一部分是DOS的重点,也是DOS程序员最常使用的功能。本书的这一部分,
内容详尽,实例也很有针对性。
 
2页
      第四部分介绍了DOS编程技术的三个较难的专题:内存管理、中断处理程序及设备
处理程序。 Microsoft技术手册在这几个技术专题的介绍上过于简单,而本书则尽可能地
将所涉及的知识(无论是已公开的还是未公开的)介绍给读者,并给出了一些很有价值的
实例。但从译者角度看,所讲内容仍不够全面,有关这几个专题的内容,读者不妨参看清华
大学出版社出版的Addsion- Wesley的书籍《未公开的DOS核心技术》。
      第五部分是本书最具特色的内容,也是它区别于其它DOS程序员参考书籍的地方。
这一部分的篇幅较大,比Microsoft的参考手册所提供的知识要丰富得多。在内容上,它
介绍了BIOS、DOS、EMS、XMS、DPMI、DoubleSpace及任务切换等方面的功能调用。在
每个功能调用的介绍内容中,尽可能地把所涉及的知识、禁止及注意事项介绍给了读者。
它的注释部分确实是独一无二的。
      本书的内容都是最新的。本书的所有功能调用都已更新到了MS- DOS 6。不仅如此,
本书对每一个功能调用,都作了版本上的说明及在各个版本下的使用注意事项。因此,本
书完全可以作为任何一个DOS版本的技术参考手册。而且由于有了第五部分的内容,读
者在进行PC编程时,所涉及的技术,都可以在这里找到。像这样把BIOS、DOS、EMS、
XMS及DPMI都融于一体的书籍,确实给读者提供了方便。因为其中有些内容,一般程序
员是很难找到的。
      就像书名所表达的那样,本书是为DOS程序员准备的。但是由于PC机的特点,由于
DOS是PC机上各种软件的基础,因此本书为所有在PC上进行编程的计算机专业人员、
大专院校学生及计算机爱好者都能提供方便。
      这是一本在翻译上有较大难度的书籍,因为本书所涉及的知识非常丰富。由于工作量
关系,虽经我们做了巨大努力,书中仍难免有误,欢迎读者指正。
      参加本书的翻译及审校工作的有熊桂喜、陆益民、黎军英、田子钧、蒋华、陈石、陈清
等。此外还有其它同志为本书的翻译工作提供过宝贵的意见。在此一并致谢。
                                            译者
                            1994年12月于北京航空航天大学计算机系
3页
         引        言
      欢迎使用《DOS程序员参考手册》第四版。编写本书的目的有两个。首先,我们想向人
们解释清楚:在DOS级上的程序如何使用DOS、BIOS以及其它能帮助编程的相关功能。
其次,我们也想鼓励使用高级语言的程序员使用DOS功能来扩展他们对PC系统的控
制。                    
      大多数谈及DOS和BIOS编程的书籍,都把重点放在汇编语言上。虽然也有少量的
书籍讨论了从高级语言中使用DOS功能的内容,但大多数也只涉及皮毛,实际上是很难
作为参考手册来使用的。《DOS程序员参考手册》第四版一书,通过大量的实例,希望能帮
助读者在程序中充分地发掘出使用DOS或BIOS功能的潜力。我们的目的就是,当读者
进行编程工作时,本书能实实在在地摆在计算机旁,助你一臂之力,而不仅仅是放在书架
上的摆设。
      为了使本书能对读者发挥出最大的作用,我们充分地考虑到了谈及内容的深度和广
度,做到了读者能任意从某个具体的编程主题开始。本来,整本那可由介绍众多编程主题
和技巧的内容组成,但是,本书并没有对每个专题都穷追不舍,而是给出一个开始点,然后
给出足够的参考信息,让读者自己一步步地深入下去。书中的内容提供了各种所需的基础
知识,利用这些知识,读者自己就能进一步地编写出功能强大而富有活力的程序。
      本书讨论了BIOS和DOS功能可应用到的各个主要领域。书中的讨论和实例,能有
助于初学者了解到如何使用这些功能;对于高级程序员,则提供了更进一步的方法,让他
们去组织所了解的内容。只要可能,任何时候我们都强调搞清楚为什么要这么用的道理。
      像本书这样题材的书籍,只有提供了尽可能详尽的参考资料,才能对程序员真正有
用。本书的最后一大部分,一个功能一个功能地详细列出了所有的DOS和BIOS功能(包
括许多未曾公开的功能)。对每个功能,都对它提供了信息进行总结,并提供了对寄存器要
求的详细信息。在本手册中这一部分所列出的信息,对任何DOS程序员都是很有用的,无
论他工作时使用的是汇编语言,还是BASIC、C或Pascal。
      本书另一个有意义之处就是其中的内容都是最新的。书中所列功能的版本已覆盖了
MS-DOS6,还包括了有关扩展内存驱动程序、扩充内存驱动程序以及鼠标驱动程序的内
容。其中还有一些与硬件有关的章节,介绍了如何识别所使用的CPU芯片的类型,有什
么样的协处理器、系统当前使用的是何种显示卡等。
      本书在第四版中增加了一些以往版本所不具备的内容。除了对使用功能按照最新信
息进行了更新外,整个参考手册部分中的内容更加充实和完善,能够让读者尽快地获得所
需的内容。我们相信,仅仅通过这部分所增加的内容,就会让读者受益匪浅。
 
4页
   有时,有关未公开功能的内容是不完整或不准确的,但我们在本书中仍介绍了这方面
    的内容,因为程序员在编程时需要全面地了解DOS和BIOS的知识,而仅靠已公开的内
    容尚不能完全做到这一点。但使用这些未公开的特性是有风险的,因为它们未公开,因而
不能担保在所有的DOS版本下都能正常地工作。其中有些特性甚至有可能在某些版本中
    不存在。
    编写本书的目的
      编写本书的目的和指导思想,就是向读者显示如何在相应的层次上对DOS系统进行
    编程。我们讨论了各种可用的功能,但并不是在任何地方都必须用汇编语言来使用这些功
    能。而某些编程任务又必须用汇编语言才能有效地完成。(事实上,有些任务甚至必须通
    过直接进入硬件层才能完成,即使DOS和BIOS服务有时也不能令人满意)。但是,尽可
    能地在最高层上工作,肯定是有好处的。书中已提供了决定使用何种层次来编程的知识。
      书中给出的例子,其方向是在高级语言中如何与DOS和BIOS例程打交道。尽管使
    用汇编语言最简练,但我们不推荐这么做。通过强调在C/C++、Pascal、BASIC中也能有
    效地使用这些例程,我们希望能使这些技术获得广泛的应用。
    本书的读者对象
      如果你是一个对在DOS上工作感兴趣的程序员,并且希望提高程序的效率,那么本
    书一定适合于你。本书涉及DOS编程的各个层次,从高级编程语言服务到BIOS中断。
      本书的读者应该是熟悉C/C++、Pascal、BASIC的程序员,对汇编语言也应有一定
    了解。我们假定你至少熟悉一种编程语言,对其它语言也有兴趣,并且熟悉MS-DOS以及
    它的变种一DOS的IBM版本。
      我们还假定你希望提高自己的程序的速度,或想访问编程语言中不能提供的一些功
    能,而通过DOS和BIOS功能便能得到这些功能。本书给出了许多高级程序技巧,除了汇
    编语言外,在高级语言中也能随意地使用各类技巧。
      尽管某些特定技术只能在特定编程语言中才能说明,但是,我们真正感兴趣的是技
    术,而不是语言。在掌握了如何使用某项技术后,无论是在C/C++、Pascal、BASIC或汇
    编语言中,都能使用它,事实上,任何编程语言都能访问DOS或BIOS中断。
    阅读本书应具备的知识
      本书是为C/C++、Pascal、BASIC程序员编写的。书中也给出了一点使用汇编语言
    来编程的知识,但没有作深入的解释。如果读者想深入地了解汇编语言,可以参见Que出
    版的“Using Assembly Language”<<使用汇编语言>>一书,也可以参看附录E中所列出的
    其它书籍。
      书中的例子是用汇编语言、C/C++、Pascal和BASIC写成的,并推荐尽量使用C/
    C++。我们尽可能地把例子讲述清楚,而不要求读者具备很强的背景知识。所给出的程
    序清单有助于读者实际使用好DOS和BIOS功能。
5页
   如何阅读本书
        本书分成五个部分。对了解DOS的基础编程知识感兴趣的读者可从第一部分开始。
    而对各个专门方面的编程知识感兴趣的读者,则可以参看第二、三和四部分。而对许多高
    级程序员来说,只需要一个快速的参考手册,这部分内容位于第五部分。
        在第一部分“DOS简介”的四章内容中,对DOS的基本内容作了简要介绍。第一部分
    首先对DOS系统的历史和DOS的工作方式,无论是静态的还是动态的,都简单地浏览了
    一遍。接下来,介绍了在DOS级编程的基本原则,并介绍了在工作时可以使用的编程语言
    资源。最后,本部分还探讨了在DOS级编程的“细节”知识。
        第二部分,“字符设备和串行设备”中,第5章和第6章讨论了输出设备(显示器和打印
    机)及输入设备(键盘和鼠标)。第7章介绍了串行输入和输出设备;同时还讨论了
      8250UART。
        第三部分“磁盘、目录和文件”含有两章内容。第8章讨论了磁盘分区表、引导记录和
    文件分配表(FAT),还讨论了DOS的磁盘功能。第9章则讨论了根目录、目录项、子目录
    和卷标等内容。第9章还解释了通过DOS来处理文件的方式,在讨论中同时涉及了所使
    用的文件控制块(FCB)和句柄功能。
        第四部分“内存管理和杂项主题”讨论了程序内存管理(第10章)、中断处理程序(第
    11章)和设备驱动程序(第12章)。第13章“杂项功能”则介绍了设备信息和扩展的错误
      处理等内容。
        第二、三、四部分的各章在阐述各个专题时,还给出了一些实际例子,读者可以使用这
      些例子来构成自己的库函数。
        第五部分是一个完整的参考手册集。在本部分里,我们在编排上作了精心安排,以便
    给读者在使用查阅时提供方便。 DOS及BIOS服务都按功能号的数字顺序给出。每一功
    能都以标准的参考手册格式列出,并在各个功能的注释中给出了注意事项和使用限制。除
    了BIOS和标准的DOS功能外,第五部分还包括有鼠标功能(DOS Int 33h)、扩充内存
    (DOS Int 67h)、XMS、DPMI、任务切换程序以及DoubleSpace等技术规范的说明。
        在本书的最后给出了五个附录,提供了一些其它信息。附录A包含有ASCII字符集;
    附录B给出了一个选择的内存位置表;附录C给出了一个TSR接口的标准;附录D讨论
    了各种未公开的DOS功能,其中包括两个探讨性的实例程序;附录E是一个其它书籍的
      资源列表。
      本书中的代码
        如果你已做了很长时间的编程工作,就会明白:仅仅将程序代码敲入计算机并保证它
    无错误,也会消耗大量的时间。这样的经验同样适用于本书中的程序代码。尽管读者可以
    将书中所包含的程序全部敲入机器中,但完成此工作也得耗费几天的时光。而要改正敲入
      的错误,则又会花费更长的时间。如果读者时间富裕,那就没什么好说的;否则,可考虑购
    买本书所配的程序附盘,寄出所需费用,或与Discovery Computing公司联系。其地址和
      电话在下一节中给出。
6页
请与作者联系
      为本书作过贡献的人们,心中只有一个目标:让本书成为一本最好的DOS程序员
参考手册。在本书出版后,书中错误仍在所难免。如果发现了任何错误和疏漏之处,可用
各种方式告知我们,以便在下一个版本中更正过来,使之更完善。既可以直接给Que公司
写信,也可以与本书的作者直接联系,地址如下:
              Allen L.  Wyatt
              Discovery Cottiputing Inc. 
                    2323State Route 585
                    P. O. Box 738
                    Sundance,WY82729
                    800-628-8280
                307-283-2714(传真)
                72561,2207(CompuServe)
 
3页
第一部分DOS概述
             第1章DOS简介
      在进一步阅读本书之前,首先要清楚什么是DOS。本章首先扼要地介绍DOS操作系
统,再简短地介绍操作系统的历史,以说明DOS产生的历史渊源。本章的内容还将涉及
DOS结构及接口。因为这是一个非常粗略的介绍,所以不要关注一些尚不清楚的术语,因
为在本章之后的其它各章还会对其进行更详细的解释。
                    1.1  什么是DOS
      DOS由四个基本模块组成:
      ·引导记录(The boot record)此记录起始于每个磁盘的0道、0扇区、第1面上,
        是由DOS FORMAT命令格式化磁盘时放入的。对于硬盘,引导记录位于DOS分
        区的第一个扇区内。这个需要一个扇区空间的记录,标识了该磁盘,并含有用于引
        导该磁盘的初始化程序。
        · BIOS 基本输入/输出系统(BIOS)是存放在ROM中的。这个面向物理设备的
        低层接口,使得各种软件可以透明地使用各种变幻莫测的硬件设备。对于DOS它
        也通过从磁盘中调入I/O来扩展其功能。
      · DOS程序    DOS是通过两个程序来实现的。一个是O/I系统,它是从磁盘中调
        入的接口模块,用来扩展ROM BIOS的功能,并包含有标准的设备驱动程序集。
        另一个文件是磁盘操作系统(DOS),它是一个所有运行在计算机上的程序的高层
        接口,而不管该程序是否使用磁盘。
      ·命令处理程序(The command processor)大多数人认为该模块即是DOS。命令
        处理程序是人们工作在该系统下运行DOS服务的标准界面,它产生命令提示符
        (C>),接收命令,并执行用户向系统请求执行的各项任务。
      各个模块将在第2章“DOS系统结构”和第3章“动态的DOS” 中详细介绍。然而我们
在这里还是作些基本的介绍。
      BIOS提供了一系列功能,程序员可以利用这些功能来完成各种操作而不必关心底层
硬件的细节。在本书中,我们将利用BIOS来执行各种实例程序里的必需操作。在本书第
五部分“参考手册”中,按顺序详细介绍了BIOS中每个功能的作用。
      虽然BIOS功能非常强,但它离完整性还差得很远。建立在BIOS基础上的DOS平
台,为编程者提供了很多必要的服务。在通用的操作系统(如DOS)成为现实之前的早期
 
4页
 个人计算机上,程序员所写的程序中,常常包含有与DOS功能等同的内容。因此,跟踪应
用程序的过程,也是非常复杂和可怕的。
      由于DOS功能的编程已由Microsoft(和其它厂商)完成,DOS已成为读者在程序开
发中的伙伴。虽然不能认为DOS中的一切都工作得非常正确而不会出错,但可以假定
DOS是坚实的(除非有其它已证实的理由)。第五部分则包含了各种DOS功能的一项一
项详细介绍。
                      1.2 DOS的历史
      多少年以来,DOS一直被当作微型计算机的最原始的操作系统。今天的DOS,所拥有
的用户数比任何其它操作系统要多得多。它已变得非常复杂,是一个带有各种工具和应用
程序来满足各种需要的操作环境。
      DOS富有远见卓识之处就在于,它能处理各种复杂的微处理器的复杂特性,如80386
和80486等。将来的DOS版本,甚至可以处理多任务,支持多用户,尽管Microsoft公司还
没有明确地提供这方面的信息。一些人可能会对此心存疑问,特别是出现了新一代操作系
统—Windows和Windows NT之后。
      DOS首先是由Seattle Computer Products公司为其计算机将86—DOS第一次注册的。
DOS的最原始程序是由Tim Paterson编写的。它开始于1980年8月,第一个产品诞生于
该年的8月。那时,Digited Research的CP/M操作系统在微机操作系统领域有着广泛的
应用。86-DOS的一个特殊设计是CP/M的应用程序很容易转换过来,它保留了同样的文
件控制块结构和功能,因此,可以自动地将CP/M的程序转换到86—DOS上。
      因为86-DOS只能工作在1980年刚上市的8086/8088 CPU芯片上,所以很少有人知
道它的存在。但那些已经从8位的8088/Z80标准和CP/M系统升级到s-100系统的人
们,已经出现了86-DOS的用途,同时,Seattle Computer Products公司也已建立了拥有几
个多客户的市场基础,其中至少还包括一两个硬件制造广商,与此同时,Microsoft公司也
在与SCP公司接触,要他们为一个未知的公司研制一个新的版本。而在当时,没有人(除
Microsoft公司外)知道,IBM也在寻找一种操作系统。在1981年1月,Paterson知道了那
个客户的名字,并且Microsoft公司已经将从86-DOS分离出的版本注册在他们自己的名
下,那年4月,Paterson离开了Seattle Computer Products公司,加盟到了Microsoft,以后
几个月,他按照IBM的需要,进一步裁剪了该系统。
      在1981年7月,Microsoft从Seattle Computer Products公司那里,以相当低的价钱
(少于10万美元)购买了86-DOS的全部版权。以后,SCP公司对此交易提出过起诉,最后
法院判决Microsoft支付了数百万美元的补偿。其结果是Microsoft公司毫无异议地永远
拥有了最流行的操作系统的版权。
      当1981年8月10日IBM发布PC时,Microsoft同时准备了MS-DOS 1.0(对于IBM
机器为Personal Computer DOS,并非PC DOS,IBM从来不接受PC DOS这个大众化的术
语,以后IBM版本也都简称为DOS。)
      Paterson在1982年结束了直接参与DOS工作的生涯,但他仍活跃在PC舞台上,最
 
5页
  近他作为各种派生的BIOS的专家,在Phoenix Technologies公司担任顾问。
      在PC原始版本发布后,DOS在一些市场中还没有成为主流。 IBM还选择了CP/M-
86和Softech的P-system作为PC的可选系统。然而,卖主很少代理这些产品,也很少有
可以在这些操作系统上使用的开发语言。此时,Microsoft已经在编程语言方面也获得了
良好声誉。IBM用DOS发布自己的软件,开发者就迅速捡起这个从未停止过转动的球,开
发出了新的功能。 CP/M-86和P-system也从来没有脱离PC市场,它也一直在参与着市
场的竞争。
      DOS已经正式修改过很多次(并且一直还有许多版本并非是为通用系统而设计的),
尽管每次发展总包含一些改进和错误纠正,但实际上每次版本都对应着一些硬件的改变
—其中的一种就是磁盘格式和容量的改变。
      表1.1列出了正式公布的主要DOS版本(按日期)和主要的改进。本表中还未包含那
些非主流的版本。
                                      表1.1 DOS的各种版本
版本       日期                 硬件或操作系统上的更新
86-DOS    1980.8      Seattle Computer Products的版本(1980年4月开始设计,
                          作者Tim Paterson)。
1.0       1981.8        原始PC机,单面磁盘
1.1      1982.3        双面磁盘,日期时间印记
1.25     1982.3        第一个OEM版本(ZDOS),增加了VERIFY。
2.0       1983.3      PCXT,包括硬盘。
2.1      1983.10     IBM PCjr和便携式PC。
3.0      1984.8      PC AT,包括高密度磁盘。
3.1       1985.3        网络。
3.2      1985.12      扩充支持新的介质。
3.3      1987.4        支持PS/2。
4.0      1988.6        支持大于32M的硬盘驱动器。 EMS内存性能的集成支持。
5.0      1991.6        支持XMS,高位内存块(UMB)和HMA。
6.0      1993.3        支持磁盘的压缩,碎片去除,改进的CONFIG.SYS结构,
                          防病毒产品。
      综合表1.1可以看出,每个新DOS版本的性能提高和其所需的内存量总是相对应
的。DOSV1.0可存在于16K内存之下,原始的IBMPC只允许使用64K内存。版本2至
少需要24K内存(如果安装设备驱动程序的话,还需要更多的内存)。任何可用的程序至
少需要128K的最小内存。作为版本3,DOS需要36K内存(如果安装设备驱动程序和文
件外壳的话,所需更多),机器如果少于512K内存几乎不能使用了。对于版本4, 512K变
成必需的内存,并且640K以上内存(扩展内存和扩充内存,详见第2章)利用变成了现
实。因为内存紧张,DOS5.0提供了将DOS调入高位内存的方法,这样,它看上去便比
DOS 4少用了传统的常规内存,但它使用了更多的高内存区。最后,DOS6是一个最强大
的DOS版本,但它提供了一个改进的内存管理方法,使得已经安装的内存能发挥出最大
 
6页
 的效益。
      让我们了解一下每个DOS版本所包含的改变之处。在这本书中,我们有一些约定,如
V1,表示的是版本1,但也包括V1的子版本;而v1.n表示v1版本的子版本n。
1.2.1 1.0版             ·
      DOS V1.0是支持PC的最原始系统。它支持基本的单面、8个扇区(8-sector磁盘格
式,并且提供了所有基本的磁盘服务。主要的改变(相对cp/M而言)是,它包括了支持磁
盘目录结构、管理文件属性及文件大小的功能。版本1.0还加入了比原始86-DOS改进的
磁盘分配和管理功能,更好的操作系统服务程序以及启动初始化时执行AUTOEXEC
.BAT批处理文件的功能。IBM只是向生产厂家发放此版本。有趣的是,这个DOS版本没
有包括文件的日期和时间印记,这也是它和以后DOS版本的一个主要区别。
1.2.2 1.1版
      在版本V1.1(最后一个只属于IBM的版本),加入了日期、时间印记,并且加入了支
持双面磁盘的驱动程序,还有一些错误更正。它发布于1982年3月。
1.2.3 1.25版
    · V1.25是第一个非IBM的而由原始设备制造厂商(OEM)发布的版本。(版本号从
1.1跳到1.25对应了IBM版本号和Tim Paterson个人修订控制系统版本的不同,IBM
V1.1就是众所周知的版本V1.24)。在这个版本中加入了VERIFY功能,即加入00h作为
目录结束标志字节(IBM的版本到2.0才出现了该功能)。
      V1离统一的标准还差得很远;Microsoft不直接向最终用户销售该产品,而是授权给
OEM厂商,由它们任意修改,甚至可以更名(例如Heath-Zenith公司在1982年3月,将它
改为ZDOS,成为第一个非IBM使用的DOS)。
1.2.4  2.0版
      在DOS V2.0中,增加了支持双面和单面9扇区格式的软盘、硬盘和在pcjr下使用
磁带的功能。 DOS的服务程序也大大改善了。这个版本还加入了类似UNIX的分层式结
构的文件系统。下面列出了DOS V2.0中的一些主要改进之处:
        ·文件句柄
        ·I/O重定向
        ·管道
        ·筛选程序(或称为滤符程序)
        ·假脱机打印
        ·磁盘卷标
        ·扩充的文件属性
        ·系统配置文件
        ·程序环境块维护
 
7页
        ·ANSI显示驱动程序
        ·程序内存的动态控制
        ·支持用户自定义的命令处理程序
        ·国际化支持
      和V1一样,V2也授权给做了改变的OEM厂商。在这个时候,大多数OEM厂商知
道为了市场因素,要接近或全部和IBM的机器兼容,因此,改变就很小。一些公司像
Tandy公司的2000型号(它是第一个使用MS-DOS V2.0的机器),是到目前为止修改
DOS最多的厂家,在其BIOS中提供双重的向量来和IBM BIOS保持兼容。
      在版本2中,版本相同,但来自不同的OEM厂商的不同版本还可以发现一些不同之
处。几乎所有V2版本都存在这种情况。
1.2.5 2.1版
      在2.1版中,只增加了对时钟的改变,以便更加适合于IBM的PC杠和便携式PC机
的需要。 MS-DOS的这一版本,如已知的2.11版,现仅在少量机器上出现过,如东芝的
便携式组合设备,就已经将V2.11固化于ROM中。
1.2.6 3.0版
      DOS V3.0是为IBM个人计算机(Personal Computer)AT(PC/AT)提供的早期版本。
这个版本增加了支持高密度(1.2M)软盘和附加的硬盘格式,增加了支持网络磁盘功能的
技术基础,下面列出了主要的新特性:
.应用程序控制的假脱机打印
        .扩展的错误报告
        .建议的错误恢复码
        .文件的记录锁定支持
      尽管IBM和Microsoft版本到今天还有些不同,但V3的公布标志着OEM厂商*
更改DOS结构的结束。例如,对于IBM,它提供的支持实用程序都作为COM文件,而Mi- 
crosoft则是以EXE格式来支持,而在众多的编码中,则很少有明显的区别。
      然而,对网络操作支持,就非常有必要在DOS结构上,特别是在内部数据格式上执行
严格的统一标准,OEM合同也按照这个要求进行了修改。从这个时候开始,DOS的关键
部分基本上稳定了下来,这使得以前没有支持的开发者,现在有了技术上的支持,开发就
变得容易了。
1.2.7 3.1版
      DOS 3.1增加了网络磁盘,包括支持文件共享,并修正了一些错误。这个版本在一段
时间内,已经成为销售商的标准。
1.2.8  3.2版
      3.2版增加了支持3.5英寸软盘的功能。它还将格式化控制集成到外围设备驱动程
 
8页
 序中。3.2版是Microsoft以其自己的名字出售给最终用户的第一个版本。
1.2.9 3.3版
      在DOS3.3中,增加了两个新的用户命令(ULSFUNC和FASTOPEN)和两个新的
功能,升级了很多其它服务程序,设备支持也覆盖到了IBM PS/2系列。该版本有影响的
地方是,DOS的管理和开发工作,从Microsoft转到了IBM,以解放Microsoft,使之专心致
致地开发iBM的OS/2源程序(作为交易的一部分,IBM把自己的OS/2开发权转让给了
Microsoft)。两个公司都继续公布和支持其特有的产品版本。
1.2.10 4.0版
      在DOS 4.0版本中,扩充了很多用户命令,增加了许多功能,并且指出了图形用户外
壳程序。然而,最主要的改变是增加了支持超过32M容量的硬盘驱动器,并且将扩充内存
(expanded memory)驱动程序作为DOS的一个标准部分。(这些特性在那时已被作为附加
的可选部分。)
      两个月以后,IBM发布了升级的版本4.0—在磁盘卷标上标识为V4.01—该版
本更正了一些错误,而VER命令仍然标识该版本为4.0,只有通过查看两个隐含文件和
SHARE.EXE文件的日期和时间区分这两个版本。4.01版所标明的日期为08/03/88或
更晚,而4.0版的日期06/17/88。 Microsoft延迟一段时间后,也发布了它自己的4.0版,
其4.0版等效于IBM的4.01版。过了不久,Microsoft又发布了进一步修正其错误的4.01
版本。
1.2.11 5.0版
      在DOS5.0版中,增加了支持扩展内存(extended memory)的功能,改进了很多用户
命令,增加了一些新的用户命令,主要的有UNDELETE、UNFORMAT、MIRROR以及鼠
标响应,全屏幕文本编辑器等,增加了在外壳程序中支持的任务切换器API(应用程序接
口)。 DOS核心已重新构造,第一次使得DOS减少了空间。另外,DOS现在可以运行在
ROM中。只有使用SHARE命令才能安全地支持超过32M DOS分区的要求,也已不再是
必要的了。
      从DOS 3.3以后,DOS V5.0是第一个真正由Microsoft更改的DOS版本。Microsoft
支持的V4.0版是IBM DOSV4.0逆向工程的结果。
1.2.12 6.0版
      DOS 6.0版在1993年3月发布。主要改变在于为操作系统增加了很多实用程序。例
如,新增加了如下几个很有用的实用程序:
        · Anti- Virus Protection(防病毒保护)这个实用程序可运行在DOS和Windows
      下,保护系统免受已知病毒的侵犯。 Anti-Virus也可增加新病毒的有关信息。
        · Deleted file recovery(删除文件恢复)这个实用程序可以恢复被误删除的文
      件。与第三方产品不同的是,UNDELETE为用户提供了三个层次的安全服务。
 
9页
  · Disk doubling(磁盘压缩)这个实用程序调用DBLSPaCE来压缩磁盘文件,
      在使用压缩过的文件时,又对其解压缩。
      · File backup(文件备份)  该实用程序是经过改进的Backup,由菜单驱动,该实
      用程序可将硬盘数据拷到软盘做备份工作。在DOS和Windows下都可以运行。
      ·改进的内存管理  MEMMAKER是通过修改CONFIG.SYS和AUTOEXEC
      .BAT文件来优化使用内存的实用程序。
      另外,其它一些DOS实用程序也做了改进。CONFIG.SYS文件结构也被改成可以有
多个启动序列。例如,可以有一个特殊的配置用于支持使用CD-ROM,另一个配置用于支
持磁带驱动程序。 DOS在每次启动时便会询问用户选择哪一个启动序列。
1.2.13未来展望
      对程序员来说,DOS继续发展,将使新的服务和选项成为可能。像Microsoft Windows
和DESQview这样的窗口环境的出现,已经为还在DOS层次编程的程序员提供了新的更
复杂的服务功能。每增加一个新的服务,就可能使更多的机器硬件代码从程序中隐去,同
时又为用户创造了新的功能。这种不断增加的新功能,会导致牺牲程序的运行速度和响应
速度,而造成了太高的代价。但是,随着处理器速度的加快,对低层次进行的编程需求在不
断地减少。应用程序将主要使用DOS的服务和它的类似物。只有系统级的程序员才需要
工作在DOS内部,Windows或DESQView将不必担心去直接访问机器和它的服务。这就
是未来技术发展的趋势。
                      1.3 DOS的结构
      因为本书的目的是深入地探讨DOS和PC系统,因此,应注意到系统的分层功能。图
1.1将有助于你理解这种层次的结构。
                                      图1.1系统层次图
    设计整个DOS/PC系统的基本思想是一种“系统套系统”的设计途径。在系统的底
层,是从电子电路开始的。例如,正是带有一定功能和特点的电路(称为计算机)实现了
 
10页
    设备。
      BIOS又用严格定义的功能和特性与此电路层组合成一体,形成了一个新的,“计算机
系统”。BIOS层是通过具备了标准属性的设备来描述其特性的。不管使用的是何种显示
器,也不管购买了何种键盘,BIOS都认为它们的响应是相同的。总之,所有BIOS的这些
特性,使得它有能力支持一个编程环境。在这个环境中,人们开发出了DOS。为使DOS和
各种厂家标准的BIOS之间的接口标准化,DOS设计者引入了一个缓冲层,使用者通过它
来调用I/O系统。它经常被认为是BIOS的一部分。然而,由于此I/O系统层是从磁盘装
入的,它是DOS系统的一部分(并且会在需要时进行修改,以满足DOS的要求),技术上,
应将它看作是DOS整体的组成部分,因为它们之间的关系比它与BIOS之间的关系更密
    切。
      DOS环境仍定义的是一个计算机系统,但它是在一个更高层次上。可以管理文件和
文件系统的语言在这个层次上被引入,语言就像是基于此设备一样。在这个层次,DOS在
标准化的环境中集成了用户所需要操作的特性。例如,不管使用的是Toshiba的还是
Maxtor的磁盘,系统都将同样地对待它们。对在DOS上工作的程序,详细的低层情况就
    不重要了。
      在下个层次(命令处理器)上,是另一个以与设备无关,但能与设备交互为标志的计算
机系统,在这个层次上,可以将设备和文件按相同的方式处理,尽管DOS是按顺序执行
的,但在命令处理器层,可以将结果直接输出到文件(正常情况下,是输出到屏幕)。在这里
    不必考虑各设备速度的差异和各设备之间的不同之处。
      再上一层是由应用程序定义的计算机系统。因为这个系统是面向用户而不是面向程
    序员的,所以这个接口更加简单。现在的“计算机语言”是由菜单选择和窗口组成的。这一
层,和其它层一样,也是建立在下一层次之上的。
      当阅读本书或按个人的爱好,跳过这些层次工作时,要留意跳过部分系统层次的得和
失。因为DOS是建立在BIOS程序之上的,因此程序越过DOS 环境而直接到BIOS,能影
响到DOS工作的方式。例如,你可以在BIOS层用磁盘读和写功能来写一个自己的文件
处理程序。但如果这样做,也许得花整年的时间来做和DOS一样的工作。反之,你也可以
只停留在顶层,但更低的层次却可以让你的程序提高运行速度。这是一个复杂性与速度的
交替过程,如何选择,全在于程序员自己。
                  1.4 DOS的程序员接口
      在高级语言工作的程序员,习惯于工作在预定义的功能上。在BASIC中,所有功能
(PRINT和INPUT)都是在语言中定义的,Pascal同样也定义了可以使用的各种标准功
能函数。C和c++编译器带来了一个标准的库函数集合。对大多数人来说,这些功能便
代表了此语言的功能。事实上,在BASIC、c/c++和Pascal中提供的功能是基于更低层
次的DOS和BIOS功能的。语言的功能以标准的方式被写成对该服务所需的处理过程。
在一些情况下,语言的功能被定义成和国家或国际标准兼容的功能。然而,要完成该功能,
必须将其直接对应于DOS、BIOS或硬件设备。
 
11页
  通常,在高级语言功能层之下的功能领域是受保护的。因为高级语言功能是为很多不
能让“编程方式脱离纸袋”的人们通常使用而设计的。这些功能必须提供错误检测和综合
情况的控制。综合是一个缓慢的过程,因此就不得不牺牲速度。如果花时间学习的话,DOS
和BIOS服务程序可以在任何语言中被直接调用。
    软件中断是使用DOS和BIOS服务程序的一种手段。(第11章“中断处理”将讨论中
断。)在前文中,软件中断被作为高级语言的子程序来调用。要设置所有参数并可得到结
果。但是如果没有纯熟的使用高级语言功能的方法,就很可能陷入困境。
      如果进入上述的高级语言功能,则得到的不光是它的错误检测,控制能力和标准库的
可靠性,还可以得到的另一个优越之处,是它的可移植性。用标准的Microsoft C或Turbo
C所编写的C程序经常只需要经过一些小改动,就可直接用在UNIX系统中。 DOS和
BIOS功能就不行,但是可以建立自己所需的错误检测和控制,而不需要像Microsoft或
Borland公司程序员要考虑的那样,要适合整个市场的要求。
走进DOS和BIOS层,将得到控制的深度和程序的速度,代价(一些很小的额外的编
程量)是很小的。要想达到可能的最高速度,就需要直接存取硬件设备。这样的操作常用
在像屏幕显示器和串行口这样的设备上,而很少或不用在象磁盘这样的设备上。
      通常,对一个运行可靠、但速度较慢的程序,可以通过进行在低层次重新编写关键模
块或通过改变程序算法来加快程序的运行。在这本书中,将提供在各个编程层次的工作的
正反两方面的内容。由使用者来决定哪个更合适于自己的应用。但是,按照一般规则,总
是先工作在尽可能高的层次上。当运行程序时,就很容易发现错误。如果进入低层,很多
细微的错误就很难发现。
                        1.5小    结
      IBM兼容系列计算机已经构造好了强大的BIOS和DOS功能。 BIOS向外部世界提
供了低层接口;DOS提供高层次的服务功能来增强计算机程序的能力。和世界上大多数
操作系统一样,每一个成功的DOS版本都为计算机应用建立了一个稳固的基础。
      怎样开发程序,使用什么语言,使用BIOS或DOS服务程序等等之类的选择,主要是
由编程的需要来决定的。对所做的编程方式的选择,一定要综合地权衡各种方式的得与
失。根据所考虑的选择方式和采取的各种策略,便能找出最适合于使用者的计算机系统工
作的方式(而不是让它碍手碍脚)。本书的写作宗旨就是基于这样的想法:积累使用者的编
程经验,使它能充分地发挥出计算机的威力。
      在第2章里,我们将讨论DOS的结构,更贴近地探究一下这个DOS建立于其上的软
件基础,并看看它与所开发程序之间的关系。我们还将讨论到,作为一个程序员,如何在
DOS环境下,利用各种工具、资源和构件,构造出灵活舒适的软件大厦。
 
12页
  第2章DOS系统结构
    DOS结构涉及硬件之上的整个机器。它不只是操作系统,并且包括整个计算机。如果
想要对使用什么功能或怎样使用它们作出最好的决定,就必须了解DOS的结构。
                    2.1“虚机”概念
    认识DOS的一个有用的方法是,将它看成是分布在子系统中的一种体系结构。该体
系中每层都提供了一个完整地定义的服务程序集合,以使更高一层可以使用它。因此,每
个层次都成了一个虚拟的机器,它便构成下一个更高层次的计算机。图2.1说明了这个关
于DOS系统的概念。
                            图2.1虚拟机器的层次结构
    物理的机器或硬件,是该体系的最底层。系统之间的很多区别就在于这一层。
    围绕着机器,常见的主要组成包括以下几个部分:
      ·来自Intel 8086家族的处理器:8086、8088、80186、80286、80386和80486
      ·在系统中相似的物理设备映象(换句话说,相似的指定中断和地址)。
      ·一个有限数量的总线设计。
 
13页
DOS的一个主要目的就是隐藏各机器之间的差异,以便在编程和用户层都以标准的
方法来使用计算机提供的各种性能。DOS成功地在各种IBM兼容计算机所选择的操作系
统上实现了一致。
                    2.2物理机器
    机器之间最大的差异就在硬件层,在这个层次一般会发现其“兼容性”是否真的兼容。
当有重大的硬件差异时,在这个层次操作的程序就不能工作了。
    物理的计算机系统(见图2.2)可以分为几个主要部分:
      ·*处理器(CPU),完成计算机系统的操作。
      ·ROM和RAM,保留程序和数据。
      ·输入通道,为计算机输送信息。
      ·输出通道,将信息送给用户。
      ·存储设备(软盘和硬盘),临时地或永久地保留数据。
                                图2.2基本计算机的框图
    理解计算机系统的所有这些部分,对成功地开发出高质量的软件是很有必要的,特别
是使用DOS和BIOS尤为重要。下面将讨论这些部分。
                      2.3处理器
    在PC或兼容机上使用的*处理器(CPU)是Intel公司8086系列处理器芯片的成
员。在使用的计算机中经常看到8086、8088、80186、80286、80386或80486芯片。Intel新
近已经发布的芯片,主要版本有80386sx、80386DX、80486SX、80486DX、80486DX2等。
在Intel系列中的每个芯片,不仅有区别于已有芯片的特有功能,而且也和早期版本保持
了兼容性。例如,80386(SX或DX)就可以完成80286或8088可以完成的所有工作,并加
上了它自己特有的功能。
    本书不详细研究芯片之间的特殊差异,但要知道DOS的主要版本是基于8086和
8088芯片的能力而设计的。在讨论DOS、BIOS和编程时,所有例子都是运行在8086或
8088上的(没有包括新芯片扩充的特有性能)。在本书中,所有的引用都是针对8086的,
但都适用于整个intel处理器系列。对DOS的一些新的附加和扩充,需要不同CPU芯片
 
14页
知识,我们在例子中将清楚地注明所需知识的类型。
    CPU是完成最简单操作的基本处理器。因为必须了解一些这个基本处理器的知识,
所以这节提供了一个8086家族处理器的概述。如果读者已熟悉这个题目,可以跳过此节。
如果要详细了解8086家族的编程,请看本书最后的参考书目。
    在本节的后面,将讨论作为一个程序员可以存取的CPU寄存器。然而,因为内存寻址
是在DOS层完成很多程序操作的基础,所以首先必须了解8086怎样对内存寻址。让我们
先看以下部分的内容。
2.3.1 8086内存寻址
    一些程序员批评8086的分段内存寻址方式。内存分段限制着数据项的大小,并且指
针结构也很复杂。然而,分段式内存对于DOS程序员来说至今仍还存在。它对解决8086
的固有设计问题是一个明智的方法,也是用8086的16位寄存器来表示乡8086的20位地
址值的最好的查找方式。 8086有20根地址线,它允许在一个内存区域内有2的20次方(即
1048576或1M)字节的寻址能力,但它的寄存器只有16位宽(寄存器的使用将在本章后
面“8086寄存器集”一节中讨论)。
    解决这个问题的方法就是将整个内存地址分成可以在16位寄存器中被独立存储的
“片”。因此,需要用两个寄存器来表示一个地址:一个寄存器存储基地址(或称作段地址),
另一个存储相对于基地址的偏移量。该方法理论上可以寻址2的32次方(大于40亿字节)的连续
地址。但要实现这个寻址区间,微处理器需要32条地址线,因此它大大地超过了8086的
能力。下面我们用例子说明该寻址区域是非常有用的。
    图2.3示出了包含100000000h(4294967296)或2的32次方个单元的4千兆内存空间区域。每
一行是一个区或段(segment),包含10000h(65,536或2的16次方)个单元。在选定的每个段内的
地址时,可以用相对于该段开始单元的偏移量表示,第一个单元的偏移量为0。书写时,采
用段:偏移量(segment : offset)的形式来表示地址,而且各地址值均采用十六进制形式。
    第一段的最后一个字节(位于0000: FFFFh)后面,紧跟的是下一段的第一个字节
(位于(0001 : 0000h)。每个内存单元的绝对地址——即它的本来位置,应从内存区的第
一个字节算起。它的计算公式如下:
                  实际地址=(段地址*段间隔)+偏移量
    图2.3显示了这一计算过程。当段间隔等于10000h(64K)时,段号便形成了8位绝对
地址的最高4位值。类似地,偏移地址则可以当作绝对地址的最低4位值。
    实际上,基地址和绝对地址之间的关系并不像图2.3所显示的那样简单。采用了先进
技术的硬件设备可以快速地处理地址转换,以取代人们从段和偏移量计算出绝对地址的
工作。
    尽管通过这个例子对理解是有帮助的,但它还留下了一个疑问:8086使用的是20位
(而非32位)地址。因此,这个例子必须修改成实际的工作方式。Intel开发的寻址方式是
将段寄存器的内容当成是整个地址的高16位,低4位指定为零。换句话说,段寄存器包含
了20位绝对地址的高4位16进制数,并且最低位(最右边一位)为零。再加上要计算的地
 
15页
                      围2.3间隔值为10000h字节的各内存段
                          (图中所有数字都为十六进制,除了后缀为“d” 的外,它表示该数为十进制。)
址偏移量寄存器中的地址值,就可得到所要的绝对地址了。图2.4显示了Intel寻址方式
中怎样从段—偏移量地址得到绝对地址。
                              图2.4如何计算一个绝对地址
      现在,我们已有了基于8086内存寻址概念,下面让我们再来讨论8086的寄存器集。
      8086用段。偏移量来寻址内存会导致一个反常现象;实际使用中的绝对地址可以以
多个组合方式来寻址。例如,下面所有的段。偏移量对表示的地址都对应的是同一个绝对
内存地址。
               0101:FFF0                   1000:1000
                03F1:D0F0                    1001:0FF0
               0900:8000                    1002:0FE0
                0CB7:4490                    1003:0FD0
               0FFF:1010                 1100:0000
 
16页
  所有这些分段式的地址都对应于同一个绝对地址:011000h。注意,每增加或减少此
地址的一个段位置,会对应地增加或减少偏移量中的10h位置。正如所看到的那样,内存
段可以用很多方式来覆盖。
2.3.2 8086寄存器集
      8086系列使用了14个独立的16位可组合的寄存器,按用途分组,可分为四类:
        ·通用寄存器
        ·段寄存器
        ·偏移量寄存器
        ·标志寄存器
      表2.1列出了各个寄存器和它们的分类。
                                    表2.1 8086寄存器集
寄存器        类别      用途
AX              通用
BX              通用
CX              通用
DX              通用
CS              段          代码段
DS              段          数据段
ES              段          附加段
SS              段          堆栈段
SP              偏移量      堆栈指针
BP              偏移量      基地址指针
SI              偏移量      源索引地址
DI              偏移量      目的索引地址
IP              偏移量      指令指针
Flags           标志        状态标志
      当面对各个寄存器时,你就明白了在硬件层是如何直接对CPU进行操作的。要注意
的是,这些操作尽管都由汇编语言来完成,但像BASIC、C和Pascal这样的高级语言也有
自己的方法来调用这些寄存器。(有关这方面的技术将在第4章“DOS和BIOS接口”中讨
论)。
      正如上面所提到的,8086寄存器集可以按照使用目的,分成四类,让我们对此分别介
绍。
      通用寄存器
      通用寄存器,正如其名字所提示的,用于存储最新结果或其它临时需要的通用目的。
当使用DOS或BIOS功能时,就需要用所需的值装入这些寄存器来完成各种功能。总要
在某个寄存器中包含一个值来对应指定的功能,并按所需附加一些其它参数。当从DOS
或BIOS功能返回时,程序中要使用的返回值也包含在寄存器中。
      通用寄存器是AX、BX、CX和DX。为了方便地使用8位或16位值,每个16位的寄存
器可以作为一对8位寄存器来寻址。寄存器命名为AL、AH、BL、BH等,分别用来寻址低
8位或高8位(L和H分别指示低和高)。图2.5表示了各个寄存器之间的关系。
      这些寄存器的使用非常广泛。无论是使用汇编语言,还是使用高级语言,只要调用访
问DOS或BIOS的例程,都常用到它们。
 
17页
                  图2.5 16位的寄存器可以当作一对8位寄存器来寻址
        段寄存器
      段寄存器在8086的内存寻址方式中起着很重要的作用。它存储了16位代表64K内
存段的基地址的值。读者可能回忆起来:这些值对应于20位基地址的高16位;低4位被
指定为零。 8086的内存寻址硬件将这些基地址和存储在CPU偏移量寄存器中的值进行
组合,得到实际应访问的地址。
      下面列出了所使用的各个段寄存器:
      ·CS(代码段)寄存器
      ·DS(数据段)寄存器
      ·ES(扩充段)寄存器
        ·SS(堆栈段)寄存器
      每个段寄存器指示不同的段。作为程序员,可以用所选的任何方法在一定范围内使用
这些段寄存器。在第3章“动态的DOS” 中,读者将看到怎样编程以及怎样使用段寄存器。
段寄存器是为用于以下工作场合而设计的:
      · CS保存包含正在运行程序代码段的基地址。
      · DS保存包含程序数据段的基地址。
      · ES是对DS寄存器的补充,用于保存“扩充”段的基地址,经常用于数据。
      ·SS保存程序堆栈的基地址,用来临时存放数据。
      前面提到的使用段寄存器的限制包括对使用CS和SS寄存器的限制。为了便于操
作,8086期望CS寄存器永远指向正在运行程序的代码段,同样SS寄存器永远指向当前
的堆栈段(对8086操作是必须的)。
      堆栈
      8086系列的处理器用一个名叫堆栈的结构来跟踪函数调用和其它操作中产生的信
息。每当一个子程序被调用时,处理器将各寄存器推入堆栈(PUSH操作),当从子程序返
回时,又将它们弹出(POP操作)。每次PUSH应将堆栈指针指向前一个低地址;POP则恢
复这个“移动的”指针。这些在SP上的操作是86芯片系列内置的操作,并且不能被改变;
事实上,正如编程所希望的,SP总是被初始化为指向堆栈存储空间的栈顶而不是栈底。
      程序员使用堆栈来存放计算的中间结果,或者向子程序传送参数值。各种编程语言为
 
18页
  同样的目的而广泛地使用了堆栈。
      堆栈的工作很像自助餐馆的盘子堆,当一个项目加入到(PUSH进)堆上时,堆会变
大。当东西拿走时(POP出),最后一个加入堆的项目被第一个弹出。这个结构被称为是后
进先出(LIFO)结构。
      偏移量寄存器
      偏移量寄存器,正如其名字所表示的那样,一般用来作为内存地址的偏移量部分。地
址的段部分一般存在段寄存器中。
      因为地址被分成段寄存器和偏移量寄存器两部分,所以每个偏移量寄存器被隐含地
和指定的包含地址“其它”部分的段寄存器配对。这种配对是自动的,除非用特定的命令取
消这种默认的配对。
      在以下列表中,给出了5个偏移量寄存器和隐含的段寄存器之间的配对关系:
      ·SP(堆栈指针)寄存器(和SS配对)
      ·BN(基础指针)寄存器(和SS配对)
      ·SI(源索引)寄存器(和DS配对)
      ·DI(目的索引)寄存器(和DS配对)
      ·IP(指令指针)寄存器(和CS配对)
      根据这组寄存器在一般情况下所起的作用,可以将它们分成两类:指针寄存器和索引
寄存器。
      指针寄存器
      指针寄存器提供了一个在段中读取数值的常规方法。 SP永远指向当前堆栈的顶部,
并且自动地被各种汇编语言指令修改。其它指针寄存器,特别是BP,常在索引操作中用来
作为基本的(或参考)指针。例如,一些程序用BP指向堆栈中的一个固定位置。这个位置
以后可作为恢复子程序调用前放在堆栈中的变量的参考指针。在高级语言编译器中,BP
寄存器的使用便具备了存取参数的标准含意。
      指令指针(IP)保留下一条将被CPU执行的指令的地址偏移量。当IP和代码段(CS)
寄存器结合时,它们指向指令的绝对地址(CS : IP寄存器对永远用于这个用途)。IP的值
在每个指令从当前的代码段取出后,由CPU自动地增加。
      索引寄存器
     索引寄存器SI和DI,是特定的偏移量寄存器。特别是当SI和DI与DS和ES段寄存-
器合用时。例如,在字符串操作时,将使用DS:SI指向源串的地址,ES:DI指向目的串。
在非串操作中,程序员通常用SI和DI作为源操作数和目的数据的索引(偏移量),正象其
名字表示的那样。
      标志寄存器
      8086标志寄存器使用16位中的9位作为标志,表示处理器的状态或控制处理器的
操作方式。这些标志被分为两类:状态标志和控制标志。列出如下:
 
19页
        状态标志:
        ·CF(进位标志)
        ·PF(奇偶标志)
        ·AF(辅助进位标志)
        ·ZF(零标志)
        .OF(溢出标志) 
          ·SF(符号标志)
        这些标志报告最后一个被运行的指令的状态。例如,如果最后一条指令产生的值是
    零,则零标志就被设置。状态标志的设置和清除是自动的,但程序也可以设置和清除标志。
    很多DOS和BIOS程序就使用进位标志来指示错误。
        控制标志是:
        ·DF(方向标志) 
        ·TF(跟踪标志) 
        ·IF(中断标志)
        方向标志控制着8086的指令在内存拷贝的区域内指定方向。跟踪标志将CPU置成
    “单步”方式(调试器用来控制程序的执行)。中断标志允许或禁止硬件中断响应。
    2.3.3 80286及其更高档的处理器
      从80286开始,使打破由8088/8086分段式结构设置的1M内存的限制成为可能。
    CPU可以在实地址方式下运行,即运行与8086和8088的能力一样的程序。程序员可以
    在实地址方式下编程,也可以在保护模式下编程。
      在保护模式下,建立了一个描述符表。这些表包括以前段寄存器信息——段的基地
    址。同时加上一些信息,如,是否可以被写入这个段的信息。段寄器则是现在的段选择符,
    它是描述符表的索引。
        在80286保护模式中,一个描述符表项包含有24位基地址。当80286在保护模式下
    运行时,它可以存取多达16M的内存。
        80386和80486继续扩充了内存寻址能力。像80286一样,它们可以在保护模式下编
    程;然而,现在的描述表项有32位基地址,它允许寻址多达40亿字节(46字节)的内存。
    为适应这个寻址能力的跳跃,通用、偏移量和标志寄存器现在也有了32位版本:EAX、
    EBX、ECX、EDX、ESP、EBP、ESI、EIP和EFLAGS。老的16位寄存器(例如AX和BX)仍
    然存在,只是作为32位寄存器的低16位。
        不仅CPU可以存取4G字节的内存,一个段也可以扩充到全部4G内存中。事实上现
    在32位结构可以和16位结构一样容易处理,在DOS环境中的80386-/80486- 特定软件
    已经形成了市场,其中包括两个相互竞争的保护模式环境。 DOS保护模式接口(DPMI)和
    虚拟控制程序接口(VCPI)。
        另外,还有一个DOS扩充程序,该程序允许专门针对80386-/80486的软件,在允许
    存取实地址模式下DOS和BIOS功能的同时,在保护模式下进行操作。 DOS扩充程序允
 
20页
    许应用程序在使用CPU的32位扩充能力的同时,仍能使用DOS和BIOS提供的服务。这
类程序常常比用等同的16位并且对DOS内存没有强制限制开发出的程序运行得要快。
2.3.4 CPU芯片的识别
    要使用80286、80386和80486 CPU的扩充功能,软件必须知道它运行在其中一个芯
片上,并且要知道在什么芯片上运行。有三种解决确定当前芯片问题的方法。第一种解决
方法是基于80386和80486在加电时用DH寄存器的10(标志)字节(3或4)来区分,它是
什么芯片。第二种方法是询问用户,他使用的是哪种芯片。第三种方法是从已知的芯片之
间的差异来推断出所使用的芯片是哪一种。
    第一种方法必须包含有已重编程的BIOS芯片,它超出了大多数程序员的能力,对用
户而言则更是苛刻。它也不能区分80286到8086之间的芯片。第二种方法假设用户知道
其机器是什么CPU;在很多情况下,这种假设是无效的。第三种方法需要做的工作比第二
种多,但比第一种少,并且是可靠的。
    列表2.1中的编码演示了怎样确定当前的CPU。它首先测试8088、8086和80286及
其之上芯片的不同之处。在8088中,一个值被推进堆栈后,堆栈指针在写入堆栈之前减
少。从80286开始,则是先写值,然后堆栈指针再减少。通过压入堆栈指针,可以检查写入
堆栈的值,来确定堆栈指针是在值写入之前还是在之后减少。如果要确定当前使用的是
80286、80386或80486,可以尝试设置80286没有使用的标志寄存器位、80286不允许使
用这些位,但80386和80486却允许。如果可以改变这些位的值,则是80386或80486。同
样的方法也可用来区别80386和80486。注意,使用66h大小的覆盖前缀去强制32位标
志寄存器被压入和弹出。这个方法是完全安全的,因为在这时,已经知道它至少是个
80386芯片。
    列表2.1
page 6o,132
;checkcpu.asm
; Determines whether the CPU in use is an 8088/8086, an 80286,  an
;80386, or an 80486.Print the CPU and return an errorlevel Of 0,
;2, 3,or4  for 8088/8086, 80286,80386,or 80486, respectively.
           .model small
            .Stack
            . data
say86      db        "8088 or 8086$" 
say286 db              " 80286$" 
say386 db              "80386$" 
say486 db              "80486$" 
            .code
            .startup
checkcpu proc
; The first step is to determine whether the chip is an 8088/8086. 
;The key difference is based-on what the CPU does when it executes
;the PUSH instruction.The 8088/8086 decrements the stack
21页
; pointer first and then writes the saved value to the stack. The 
; 80286, 80386, and 80486 write the value to the stack and then
; decrement the stack pointer. Thus, when SP is pushed and the
; pushed value is popped off, the value popped off equals the
; current stack pointer, unless the chip is an 8088 or 8086.
push   sp
pop ax 
cmp ax,sp  ; if values are not the same,
jne is_86 , it is 8088/8086
; The second step is to detecmine whether the chip is an 80286.
; The key diffecence is the IOPL bits in the flags cegister;
; the 80386 and 80486 have them, and the 80286 does not. The
; 80286 does not let them be Set; the 80386 and 80486 do.
pushf
pop ax ; get flags in ax .
or ax,03000h ; set IOPL bits
push ax  ; stuff them back
popf , pop flags--this is where the 80286
; will put them back the way they were
pushf 
pop ax ; get flags in ax
test ax,03000h ; if the IOPL bits are reset, the chip
jz iS_286 ; is an 80286
; The third Step is to determine Whether the chip iS an 80386.
; The key difference iS the alignment check bit in the flags
; register; the 80486 has one, and the 80386 does not. The 80386
; does not let you set that bit, but the 80486 does.
db 66h ; (32 bit instruction)
pushf 
pop ax ; read low word of flags
and ax,00FFFh ; clear IOPL bits- -level zero
pop dx , read high word
or dx,00004h ; set alignment check bit
push dx ; push flags back
push ax
db 66h ; (32-bit instruction)
popf ; pop flags register- -this is where
; the 80386 undoes your work
db 66h ; (32-bit instruction)
pushf ; push flags back
pop ax ; read what you did
pop dx ; find out if the CPU reset the
test dx,4 ; alignment check bit
jz iS_386 ; if it did, the chip iS an 80386
is_486:
mov   dx,offset say486
mov al,4 ; errorlevel 4
jmp sayso
is_386:
mov dx, offset say386
mov al,3 ; errorlevel 3
jmp sayso
iS_286:
mov dx,offset say286
mov al,2 , errorlevel 2
22页
                      jmp     saySo
              is_86:
                  mov        dx ,offset say86
            mov        al,0           ;  errorlevel 0
              sayso:
                          push      ax        ;save errorlevel
                  mov        ah,9          ;call DOS wPite string function
                          int        21h
                          pop         ax                        ;retrieve  errorlevel
                    mov      ah , 04Ch         ;  terminate process with return code
                        int         21h
              checkcpu endp
                          end
2.3.5数学协处理器
      Intel 80x86系列的处理器,从8088到80386只能处理整数运算。对很多应用程序,有
整数运算就已足够。对于需要浮点运算的应用计算必须由已编好的特定的程序来处理。对
大多数应用程序来说,用户不需留意软件计算处理的开销。然而,对于浮点运算较多的数
学应用,开销变成了一个问题,这时的数学协处理器也变成必不可少的了;一些应用系统
甚至没有协处理器就不能运行。
      数学协处理器可以像处理器计算整数那样容易地计算浮点数。不仅如此,它还能和处
理器并行地处理所进行的计算工作。只有当数据被调入协处理器或从协处理器中读出数
据时,或者激活协处理器期间,才会需要处理器的配合,而在协处理器完成其功能期间,处
理器可以去做另外的属于它自己的工作。
2.3.6数学协处理器的识别
      Intel公司共有三种可以和主处理器一起工作的协处理器:8087、80287和80387,但
没有80187。因为8087也可以和80186和80188一起工作。也没有80487,因为在80486
内有内置的80387的等价物。要识别数学协处理器并不简单。表面上不匹配的处理器和
协处理器可以结合。事实上,8086 CPU和80287就可以组合在一起工作。
      与识别不同CPU的方法相比,识别协处理器的技术要利用不同代的协处理器之间的
细微差别。分辨系统中使用的是何种芯片,会由于在系统中根本未使用协处理器而复杂化
(数学协处理器决没有那么便宜——需要使用协处理器的应用也不普遍——使得卖方会
自动地将它们放入系统。另一方面,很少有卖方想把它们的产品放在失去和应用程序确定
的协处理器百分之一百兼容的地位上。折衷的方法是,在主板上放了一个协处理器的插
座,由用户选择是否要安装一个协处理器。)
      要确定当前协处理芯片是哪一种,可将一个位模式写进内存,试图初始化协处理器芯
片。然后数学协处理芯片运行一个将协处理器状态字写入内存的指令。如果拥有该芯片,
则有一个新值写入内存,如果没有该芯片,则写入的是位模式,而不是有效的协处理器状
    态字。
      当知道有协处理芯片存在后,可以用通过区别协处理器中断和读控制的方式来区分
 
23页
 8087和80287以及80387。这个过程对8087有效,但对80287或80387无效。要区别
80287和80387,可以创建出一个正的无穷大的值(正1除以0),再创建一个负的无穷大
的值,然后用协处理器来比较这两个值,因为80387在两个值之间有区别,而80287则没
有区别。
  在列表2.2中的过程可以被调用来确定当前使用的是哪个协处理器,如果它确实存
在的话。
    列表2.2
        page 60, 132
       ;CheCktpu. asm
        ;Determine the type Of math coprocessor(fpu)installed. 
                  .model small
                  .stack
                  .data
        ScratCh dW          (?)            ;have the math chip  store data here
        Saynone db        " NO math coprocessor$" 
        say87      db      "  8087$" 
        say287   db       " 80287$" 
        Say387 db         " 80387$" 
                  .Code
                  .startup
      ·checkfpu proc
                  fninit                       ; initialize the fpu
                  mov      scratch ,  055AAh;the fpu will not write this
                  fnstsw Scratch               ;  have the fpu write its status word
                  cmp      byte ptr scratch,0;check lSb--it shbuld be 0
                  jne      no math             ; if not, retyrn
                  fnstcw scratch               ; now have the fpu write its  control word
                  mov      ax , Sccatch       ;  read the value
                  and      ax ,0103Fh         ;mask expected bits
                  cmp    ax ,0003Fh          ;  this is what you should see
                  jne     no_math              ; if different ,  no math chip
        ;Now that you know that you have an fpu ,  which one is it?
                  and      Scratch    0FF7Fh ;  clear interrupt bit
                  fldcw    scratch             ;  load the control word
                  fdisi                        ;  disable interrupts
                  fstcw    Scratch             ;  write the control word back
                  test     Sccatch , 00080h ; any effect on the word?
                  jnz   found_8087          ;  if so , it is an 8087
        ;The chip is not an 8087 , so it is an 80287 or 80387. 
                  finit                       ;reinitialize the chip
                  fld1                         ;  push +1.0 onto the chip's stack
                  fldz                         ; push 0.0 onto the chip's stack
                  fdiv                        ; produce positive infinity
                  fld      st                  ;  produce negative infinity
                  fcompp                    ;compare
                  fstsw   scratch            ;write the status word
                  mov     ax , scratch
 
24页
        sahf                     ; copy AH into the flags register
            je       found_ 80287     ;  if Z bit set (equal)  ,  the
                                    ;   coprocessor found positive and
                                   ;   negative infinity to be equal
    ;The chip is an 80387
            mov      dx ,  offset say387
            mnv      al,3         ; errorlevel 3
                jmp      sayso
    no_math:
                mov       dX,offset saynone
                mov        al,0                  ; errorlevel 0
                jmp      sayso
      found_8087:
                mov          dx,offset  say87
            mov        al,1          ; errorlevel 1
            jmp    sayso
      found_80287:
                mov          dx,offset say287
            mov      al,2             ;  errorlevel 2
    sayso :
            push     ax                ;  save errorlevel
            mov     ah,9              ;  call DOS write string function
                int        21h
                pop         ax                       ;  retrieve errorlevel
            mov     ah , 04Ch         ; terminate Process with return code
                int         21h
    checkfpu endp
                end
                      2.4内      存
      PC及其兼容机中有四种类型的内存:
      ·ROM(只读内存)是安装在计算机中的永久内存,它通常保留特定的机器的
        BIOS部分。
      · RAM(随机存取内存)非永久地保留程序代码和数据。
      ·扩展内存(extended memory)(超过1M的内存)可以被80286处理器在保护模
        式下存取。
      ·扩充内存(expanded memory)加入到系统但不是直接被处理器映射的内存部
        分。这部分内存通过特定的扩充内存驱动系统来存取。
      读者可能已经听说过多种ROM,如PROM(可编程只读存储器)或EPROM(可擦写
可编程只读存储器),所有这些都属于ROM类型。尽管有人反对这样归类,但从DOS系
统程序的标准来看,PROM和其它一系列ROM都表示永久存储器。
      图2.6显示了在基本系统内存中内存的映射图。
      在第10章“程序和内存管理”中,将要详细讨论内存的分配和使用方法,并学习在程
序中怎样控制内存以及怎样使用内存。
 
25页
                        图2.6带有1兆内存机器的内存图
                        2.5I/O通道
      PC及其兼容机上的标准输入/输出(I/O)设备是键盘、视频监视器和打印机(见第5
章“输出设备”和第6章“输入设备”)。除了这些标准设备以外,计算机还常配有鼠标以及
一个或多个串行接口(见第6章和第7章“串行设备”)。
      可以增加诸如触觉感应屏幕(触摸屏)以及各种类型的传感器等一类的用户设备到
PC系统中。尽管讨论这些特殊设备已经超出了本书的范围,但在第12章“设备驱动程序”
中,将针对特定的设备,介绍怎样编写自己的驱动程序。
2.5.1键盘
      PC键盘从不知道从键盘上键入的内容。键盘不解释所击的键,只是直接告诉计算机
特定的键被按下或松开。键盘并不指定每个键的含意。但它指定每个键有一个唯一的数
值(扫描码)。这个扫描码被BIOS传送到计算机去解释。图2.7介绍了原始84键版本的
 
26页
键盘的扫描码。后来的键盘增加了更多的键,它将在第6章里介绍。
                                      图2.7键盘扫描码
      当使用者按下某一个键时,键盘通知计算机(通过Int 09h)那个键已被按下或松开。
当处理器执行Int 09h时,BIOS取得计算机瞬时的控制权,读取该键的扫描码。BIOS首先
检查像Shift和NumLock这样的双态键。如果双态键被按下或松开,BIOS修改在内存地
址0417h-0418h上的键盘状态位。接着,BIOS检查一些特定的组合键(如Ctrl-Alt-Del),
如果需要,就运行它们对应的特定的处理程序。
      如果扫描码还没有当作特殊用途的键(像NumLock,Ctrl-Alt-Del,Shift或者Ctrl等)
被“清除”的话,BIOS将它转换成等值的ASCII码。如果对该键没有正确的ASCII字符相
对应,它就给出值为零的ASCII码。然后,该ASCII字符,加上它的初始扫描码,就被保存
到键盘缓冲区中。这个缓冲区足以存放15个字符和它们的扫描码。如果缓冲区已满的话,
BIOS就会发出蜂鸣声(以表示键盘缓冲区满)并且去掉此键的扫描码的值。
      在字符到达键盘缓冲区后,就允许运行着的程序(包括DOS)使用它了。因为计算机
通常在几分之一秒中就响应,所以填满键盘缓冲区的机会是很小的,除非计算机忙于处理
其它任务。
      这里只能对键盘进行粗略的介绍,更详细的讨论键盘的编程请阅读第6章“输入设
备”。
2.5.2显示器屏幕
      PC支持多个视频接口卡的型号,并且每个显示卡都可工作在多个文本或图形模式
下,然而,编写一个适应各种显示的程序并没有想象的那么困难,因为DOS提供了确定显
示卡的种类以及当前工作模式的工具。
      第6章将详细讨论这些内容,这一节只介绍一些典型的显示卡类型。
      显示卡的类型
      对于大多数编程人员来说,至少应熟悉6种类型的显示卡。当然也有其它类型的显示
卡,但通常只用在一些特定的应用中。
      初始的“标准”显示器是单色显示卡(MDA)。这个系统以其明快的、清晰的字符以及
专业化的外观在计算机的商业应用中得到了很高的评价。其它视频卡(CGA、EGA、HGA、
 
27页
MCGA和VGA)也开始在不同的显示场合能被用户使用。表2.2列出了这些显示卡以及
它们开始使用的年代。
                                  表2.2显示卡和使用的年代
显示卡              推出的年份
MDA                       1981
CGA                       1982
    HGA                   1982
    EGA                     1984
    MCGA                    1987
    VGA                     1987
      在对单色显示卡的扩展中,彩色显示卡(CGA)使显示彩色成为可能,这一点是非常
重要的。CGA显示卡可以显示彩色和图形,但是显示字符不如MDA的清晰。这个不同的
原因在于产生每个字符的点阵象素数。 MDA使用9*14的字符框产生字符,而CGA使
用8*8的框。因为密度的不同,CGA的字符看起来要比MDA的字符“蠢”。
      大力神(Hercules)图形显示卡(HGA),结合单色屏幕的清晰的字符以及彩色图形卡
显示的图形产生了高分辨率的单色显示效果,因此它很快成为结合文本和图形的标准。
HGA不能产生彩色,但这个不足对它并不是特别不利。
      随着增强图形卡(EGA)彩色图形系统的推出,人们(和商业市场)开始发现,彩色使
他们的工作更加丰富多彩,更加有高度了。仅高亮度不足以在屏幕上显示各种变化,但可
以用彩色来强调很多事情。
      虽然只是少量的改进,使用也不广,但随着IBM PS/2型号25和30的多彩色图形阵
列(MCGA)和IBM PS/2型号50、60、80的视频图型阵列(VGA)的推出,显示的标准再一
次被重新确定。 MCGA类似于CGA,但它的分辨率更高。 MCGA分辨率是320*400;
CGA的分辨率是320*200。 VGA的分辨率(640*480)是EGA(640*350)适当扩充。两
种显示器中主要的改进则是所有的显示都使用的是模拟的而非数字的监视器。在模拟信
号下工作,新的视频系统可以显示256色的调色板(允许产生多达262144种颜色)。
      内存映射与显示卡
      在IBM系列中的视频显示卡都使用内存映射。换句话说,即将屏幕上所见的内容直
接映象到被显示卡控制的内存区域中。字符的实现很简单,它被直接写入显示内存,然后
显示卡从显示内存中读出该字符并将它显示到屏幕上。在图形模式下,显示卡将视频内存
的数据当作一个在屏幕上控制点的分离着的位的阵列。内存区域的使用按照显示模式以
及不同的显示卡有着很大的区别。表2.3详细列出了每个显示卡的视频缓存的起始位置
和长度。
                                  表2.3各显示卡的内存配置
显示器类型        显示模式          缓冲区段地址        缓冲区长度    显示页数
    MDA             文本              B000h                    4K          1
    CGA             文本              B800h                     16K         4/8
      图形              B800h                      16K         1
    HGA           图形                B000h                   64K           1
28页
                                                                  (续)
显示器类型      显示模式          缓冲区段地址      缓冲区长度      显示页数
    EGA           单色            B000h                 可变        可变
                  文本           B800h                可变        可变
                  图形            A000h                 可变        可变
    MCGA          文本            B800h                 32K         8
                  图形            A000h                  64K         1
    VGA           单色            B000h                 可变        可变
                  文本            B800h                 可变        可变
                  图形            A000h                 可变        可变
    尽管本节给出了显示卡功能的概述,但如果要了解更详细的信息,还是请参阅第5章
“输出设备”。第5章提供了一些关于显示卡怎样解释视频内存以及怎样用BIOS和DOS
功能去显示信息的内容。
2.5.3打印机
    在这本书中,名词打印机一般指连接在并行打印机上的打印机,而不指连在串行口上
的打印机(串行口将在下一节和第7章“串行设备”中讨论)。通过并行打印机接口,可以向
打印机传送一个初始信息,并且查询打印机当前状态,例如,打印纸是否用完等。这里特指
的是在DOS层用打印机可以做些什么。而打印机的使用则超出了本书的范围。
    在第5章“输出设备”中,读者将学到怎样编写一个程序,用BIOS和DOS功能直接访
问打印机。可以同时访问多个打印机(例如:LPT1和LPT2),并且可以解释返回码,来确
定打印机的状态。
2.5.4串行口
    当与一台并行打印机连接时,只能得到对并行打印机口的有限的控制。现在硬件已经
设计成几乎可以处理每个任务。你可以随意买一台打印机,并能保证在插上它之后,就能
正确地工作。然而,串行口则不同。
    当今大多数的计算机至少装备了一个串行口。它主要用来驱动串行打印机、鼠标或者
调制解调器,串行口还有些特殊的问题。连接双方必须设定它们的参数;如果参数设置不
对,就连接不通。这些参数包括波特率、奇偶校验、起始位、结束位以及数据长度。尽管大
多数(但不是全部)设备的物理连接都遵守一个标准,但参数还没有标准化。即使完成了正
确的物理连接,还必须完成正确的逻辑连接。
    目前还没有一个快速和简单的连接方法。串行口的参数指定了在信息传递时每秒传
送的位数;组成字符的位数;是否有奇偶校验位,如果有,校验的方式是什么;以及用来标
识字符结束的终止位的数目。可以用软件的控制流覆盖线路的设置,例如XON/XOFF或
ETX/ACK;或者用特定的线路协议,例如Xmodem或Kermit。因此,不熟练的人很难在第
一次将计算机和电话线连接就获得成功也就不足为奇了。
    第7章将专门解决串行通信的难点,以及怎样对它们编程。还将讨论所有串行口参数
 
29页
    的含义,以及怎样将这些信息最恰当地与所编的程序相结合。
    2.5.5鼠标
      当设计原始的PC时,鼠标并不是所考虑的重要设备。在BIOS中的程序允许程序员
    控制很多流行的控制杆和光笔。但是,时至今日,只有鼠标才被大量使用。
      一般情况下,鼠标或者通过和用户装在PC内总线上的控制板连接,或者通过串行口
    连接。鼠标的软件驱动程序确定鼠标的位置,并且处理连接到板上的接口。
        鼠标的工作机制
      在一般的形式中,鼠标是在底部安装了一个小球的设备。当在平面上移动鼠标时,传
    感器测量设备在X和Y方向的移动量。鼠标将位置的变化标志的信号传送给计算机系
    统。光电鼠标不使用小球,但它跟踪反射光和移动量,使用什么型号的鼠标并没有关系,计
    算机通过在屏幕上可视的指针来反映鼠标位置的移动。所有这些动作都在驱动程序层处
    理。
      除了移动传感器之外,鼠标通常安装一个、两个或三个开关(称为按钮),可以用它们
    来测试和控制程序的动作。
      当使用标准的鼠标驱动软件时,DOS的Int 33h将控制鼠标。这个中断提供了鼠标及
其移动的信息,并且提交这个数据的控制。即使鼠标是外接到DOS系统上的,也可以通过
    第6章“输入设备”来学习有关它的更多东西。

(未完待续哦)